Add IFA_FLAGS for IPv6 temporary addresses back (rhbz 1064430)
This commit is contained in:
parent
18e89ed90e
commit
451ae94d0c
|
@ -0,0 +1,45 @@
|
|||
Bugzilla: 1056711
|
||||
Upstream-status: Submitted for 3.15
|
||||
|
||||
This fixes the issue described here:
|
||||
https://bugzilla.redhat.com/show_bug.cgi?id=1056711#c5
|
||||
|
||||
net-next commit 971a351ccbbd2b6eef136a2221da0b80aca50906
|
||||
Author: Jiri Pirko <jiri@resnulli.us>
|
||||
Date: Tue Dec 10 13:56:29 2013 +0100
|
||||
|
||||
ipv6 addrconf: revert /proc/net/if_inet6 ifa_flag format
|
||||
|
||||
Turned out that applications like ifconfig do not handle the change.
|
||||
So revert ifa_flag format back to 2-letter hex value.
|
||||
|
||||
Introduced by:
|
||||
commit 479840ffdbe4242e8a25349218c8e0859223aa35
|
||||
"ipv6 addrconf: extend ifa_flags to u32"
|
||||
|
||||
Signed-off-by: Jiri Pirko <jpirko@redhat.com>
|
||||
|
||||
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
|
||||
index be4dbbd..3c3425e 100644
|
||||
--- a/net/ipv6/addrconf.c
|
||||
+++ b/net/ipv6/addrconf.c
|
||||
@@ -3367,12 +3367,12 @@ static void if6_seq_stop(struct seq_file *seq, void *v)
|
||||
static int if6_seq_show(struct seq_file *seq, void *v)
|
||||
{
|
||||
struct inet6_ifaddr *ifp = (struct inet6_ifaddr *)v;
|
||||
- seq_printf(seq, "%pi6 %02x %02x %02x %03x %8s\n",
|
||||
+ seq_printf(seq, "%pi6 %02x %02x %02x %02x %8s\n",
|
||||
&ifp->addr,
|
||||
ifp->idev->dev->ifindex,
|
||||
ifp->prefix_len,
|
||||
ifp->scope,
|
||||
- ifp->flags,
|
||||
+ (u8) ifp->flags,
|
||||
ifp->idev->dev->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
_______________________________________________
|
||||
kernel mailing list
|
||||
kernel@lists.fedoraproject.org
|
||||
https://admin.fedoraproject.org/mailman/listinfo/kernel
|
|
@ -0,0 +1,753 @@
|
|||
This patch is made against 3.13 kernel. So it's suitable for F21 and for F20
|
||||
later on when F20 is rebased to 3.13.
|
||||
|
||||
https://bugzilla.redhat.com/show_bug.cgi?id=1056711
|
||||
|
||||
NetworkManager depends on IFA_F_NOPREFIXROUTE IFA_F_MANAGETEMPADDR
|
||||
in order to do SLAAC in userspace correctly.
|
||||
|
||||
Split patches available here:
|
||||
|
||||
http://people.redhat.com/jpirko/f21_backport_of_IFA_F_NOPREFIXROUTE_and_IFA_F_MANAGETEMPADDR/
|
||||
|
||||
Jiri Pirko (2):
|
||||
ipv6 addrconf: extend ifa_flags to u32
|
||||
ipv6 addrconf: introduce IFA_F_MANAGETEMPADDR to tell kernel to manage
|
||||
temporary addresses
|
||||
|
||||
Li RongQing (1):
|
||||
ipv6: unneccessary to get address prefix in addrconf_get_prefix_route
|
||||
|
||||
Thomas Haller (2):
|
||||
ipv6 addrconf: add IFA_F_NOPREFIXROUTE flag to suppress creation of
|
||||
IP6 routes
|
||||
ipv6 addrconf: don't cleanup prefix route for IFA_F_NOPREFIXROUTE
|
||||
|
||||
stephen hemminger (1):
|
||||
ipv6: addrconf spelling fixes
|
||||
|
||||
include/net/addrconf.h | 4 +-
|
||||
include/net/if_inet6.h | 2 +-
|
||||
include/uapi/linux/if_addr.h | 6 +
|
||||
net/ipv6/addrconf.c | 409 +++++++++++++++++++++++++------------------
|
||||
4 files changed, 250 insertions(+), 171 deletions(-)
|
||||
|
||||
Signed-off-by: Jiri Pirko <jpirko@redhat.com>
|
||||
|
||||
diff --git a/include/net/addrconf.h b/include/net/addrconf.h
|
||||
index 86505bf..e70278e 100644
|
||||
--- a/include/net/addrconf.h
|
||||
+++ b/include/net/addrconf.h
|
||||
@@ -81,9 +81,9 @@ int ipv6_dev_get_saddr(struct net *net, const struct net_device *dev,
|
||||
const struct in6_addr *daddr, unsigned int srcprefs,
|
||||
struct in6_addr *saddr);
|
||||
int __ipv6_get_lladdr(struct inet6_dev *idev, struct in6_addr *addr,
|
||||
- unsigned char banned_flags);
|
||||
+ u32 banned_flags);
|
||||
int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr,
|
||||
- unsigned char banned_flags);
|
||||
+ u32 banned_flags);
|
||||
int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2);
|
||||
void addrconf_join_solict(struct net_device *dev, const struct in6_addr *addr);
|
||||
void addrconf_leave_solict(struct inet6_dev *idev, const struct in6_addr *addr);
|
||||
diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h
|
||||
index 65bb130..9650a3f 100644
|
||||
--- a/include/net/if_inet6.h
|
||||
+++ b/include/net/if_inet6.h
|
||||
@@ -50,8 +50,8 @@ struct inet6_ifaddr {
|
||||
|
||||
int state;
|
||||
|
||||
+ __u32 flags;
|
||||
__u8 dad_probes;
|
||||
- __u8 flags;
|
||||
|
||||
__u16 scope;
|
||||
|
||||
diff --git a/include/uapi/linux/if_addr.h b/include/uapi/linux/if_addr.h
|
||||
index 23357ab..dea10a8 100644
|
||||
--- a/include/uapi/linux/if_addr.h
|
||||
+++ b/include/uapi/linux/if_addr.h
|
||||
@@ -18,6 +18,9 @@ struct ifaddrmsg {
|
||||
* It makes no difference for normally configured broadcast interfaces,
|
||||
* but for point-to-point IFA_ADDRESS is DESTINATION address,
|
||||
* local address is supplied in IFA_LOCAL attribute.
|
||||
+ *
|
||||
+ * IFA_FLAGS is a u32 attribute that extends the u8 field ifa_flags.
|
||||
+ * If present, the value from struct ifaddrmsg will be ignored.
|
||||
*/
|
||||
enum {
|
||||
IFA_UNSPEC,
|
||||
@@ -28,6 +31,7 @@ enum {
|
||||
IFA_ANYCAST,
|
||||
IFA_CACHEINFO,
|
||||
IFA_MULTICAST,
|
||||
+ IFA_FLAGS,
|
||||
__IFA_MAX,
|
||||
};
|
||||
|
||||
@@ -44,6 +48,8 @@ enum {
|
||||
#define IFA_F_DEPRECATED 0x20
|
||||
#define IFA_F_TENTATIVE 0x40
|
||||
#define IFA_F_PERMANENT 0x80
|
||||
+#define IFA_F_MANAGETEMPADDR 0x100
|
||||
+#define IFA_F_NOPREFIXROUTE 0x200
|
||||
|
||||
struct ifa_cacheinfo {
|
||||
__u32 ifa_prefered;
|
||||
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
|
||||
index 4b6b720..3c4e25d 100644
|
||||
--- a/net/ipv6/addrconf.c
|
||||
+++ b/net/ipv6/addrconf.c
|
||||
@@ -891,15 +891,95 @@ out:
|
||||
goto out2;
|
||||
}
|
||||
|
||||
+enum cleanup_prefix_rt_t {
|
||||
+ CLEANUP_PREFIX_RT_NOP, /* no cleanup action for prefix route */
|
||||
+ CLEANUP_PREFIX_RT_DEL, /* delete the prefix route */
|
||||
+ CLEANUP_PREFIX_RT_EXPIRE, /* update the lifetime of the prefix route */
|
||||
+};
|
||||
+
|
||||
+/*
|
||||
+ * Check, whether the prefix for ifp would still need a prefix route
|
||||
+ * after deleting ifp. The function returns one of the CLEANUP_PREFIX_RT_*
|
||||
+ * constants.
|
||||
+ *
|
||||
+ * 1) we don't purge prefix if address was not permanent.
|
||||
+ * prefix is managed by its own lifetime.
|
||||
+ * 2) we also don't purge, if the address was IFA_F_NOPREFIXROUTE.
|
||||
+ * 3) if there are no addresses, delete prefix.
|
||||
+ * 4) if there are still other permanent address(es),
|
||||
+ * corresponding prefix is still permanent.
|
||||
+ * 5) if there are still other addresses with IFA_F_NOPREFIXROUTE,
|
||||
+ * don't purge the prefix, assume user space is managing it.
|
||||
+ * 6) otherwise, update prefix lifetime to the
|
||||
+ * longest valid lifetime among the corresponding
|
||||
+ * addresses on the device.
|
||||
+ * Note: subsequent RA will update lifetime.
|
||||
+ **/
|
||||
+static enum cleanup_prefix_rt_t
|
||||
+check_cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long *expires)
|
||||
+{
|
||||
+ struct inet6_ifaddr *ifa;
|
||||
+ struct inet6_dev *idev = ifp->idev;
|
||||
+ unsigned long lifetime;
|
||||
+ enum cleanup_prefix_rt_t action = CLEANUP_PREFIX_RT_DEL;
|
||||
+
|
||||
+ *expires = jiffies;
|
||||
+
|
||||
+ list_for_each_entry(ifa, &idev->addr_list, if_list) {
|
||||
+ if (ifa == ifp)
|
||||
+ continue;
|
||||
+ if (!ipv6_prefix_equal(&ifa->addr, &ifp->addr,
|
||||
+ ifp->prefix_len))
|
||||
+ continue;
|
||||
+ if (ifa->flags & (IFA_F_PERMANENT | IFA_F_NOPREFIXROUTE))
|
||||
+ return CLEANUP_PREFIX_RT_NOP;
|
||||
+
|
||||
+ action = CLEANUP_PREFIX_RT_EXPIRE;
|
||||
+
|
||||
+ spin_lock(&ifa->lock);
|
||||
+
|
||||
+ lifetime = addrconf_timeout_fixup(ifa->valid_lft, HZ);
|
||||
+ /*
|
||||
+ * Note: Because this address is
|
||||
+ * not permanent, lifetime <
|
||||
+ * LONG_MAX / HZ here.
|
||||
+ */
|
||||
+ if (time_before(*expires, ifa->tstamp + lifetime * HZ))
|
||||
+ *expires = ifa->tstamp + lifetime * HZ;
|
||||
+ spin_unlock(&ifa->lock);
|
||||
+ }
|
||||
+
|
||||
+ return action;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long expires, bool del_rt)
|
||||
+{
|
||||
+ struct rt6_info *rt;
|
||||
+
|
||||
+ rt = addrconf_get_prefix_route(&ifp->addr,
|
||||
+ ifp->prefix_len,
|
||||
+ ifp->idev->dev,
|
||||
+ 0, RTF_GATEWAY | RTF_DEFAULT);
|
||||
+ if (rt) {
|
||||
+ if (del_rt)
|
||||
+ ip6_del_rt(rt);
|
||||
+ else {
|
||||
+ if (!(rt->rt6i_flags & RTF_EXPIRES))
|
||||
+ rt6_set_expires(rt, expires);
|
||||
+ ip6_rt_put(rt);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+
|
||||
/* This function wants to get referenced ifp and releases it before return */
|
||||
|
||||
static void ipv6_del_addr(struct inet6_ifaddr *ifp)
|
||||
{
|
||||
- struct inet6_ifaddr *ifa, *ifn;
|
||||
- struct inet6_dev *idev = ifp->idev;
|
||||
int state;
|
||||
- int deleted = 0, onlink = 0;
|
||||
- unsigned long expires = jiffies;
|
||||
+ enum cleanup_prefix_rt_t action = CLEANUP_PREFIX_RT_NOP;
|
||||
+ unsigned long expires;
|
||||
|
||||
spin_lock_bh(&ifp->state_lock);
|
||||
state = ifp->state;
|
||||
@@ -913,7 +993,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
|
||||
hlist_del_init_rcu(&ifp->addr_lst);
|
||||
spin_unlock_bh(&addrconf_hash_lock);
|
||||
|
||||
- write_lock_bh(&idev->lock);
|
||||
+ write_lock_bh(&ifp->idev->lock);
|
||||
|
||||
if (ifp->flags&IFA_F_TEMPORARY) {
|
||||
list_del(&ifp->tmp_list);
|
||||
@@ -924,45 +1004,13 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
|
||||
__in6_ifa_put(ifp);
|
||||
}
|
||||
|
||||
- list_for_each_entry_safe(ifa, ifn, &idev->addr_list, if_list) {
|
||||
- if (ifa == ifp) {
|
||||
- list_del_init(&ifp->if_list);
|
||||
- __in6_ifa_put(ifp);
|
||||
+ if (ifp->flags & IFA_F_PERMANENT && !(ifp->flags & IFA_F_NOPREFIXROUTE))
|
||||
+ action = check_cleanup_prefix_route(ifp, &expires);
|
||||
|
||||
- if (!(ifp->flags & IFA_F_PERMANENT) || onlink > 0)
|
||||
- break;
|
||||
- deleted = 1;
|
||||
- continue;
|
||||
- } else if (ifp->flags & IFA_F_PERMANENT) {
|
||||
- if (ipv6_prefix_equal(&ifa->addr, &ifp->addr,
|
||||
- ifp->prefix_len)) {
|
||||
- if (ifa->flags & IFA_F_PERMANENT) {
|
||||
- onlink = 1;
|
||||
- if (deleted)
|
||||
- break;
|
||||
- } else {
|
||||
- unsigned long lifetime;
|
||||
-
|
||||
- if (!onlink)
|
||||
- onlink = -1;
|
||||
-
|
||||
- spin_lock(&ifa->lock);
|
||||
-
|
||||
- lifetime = addrconf_timeout_fixup(ifa->valid_lft, HZ);
|
||||
- /*
|
||||
- * Note: Because this address is
|
||||
- * not permanent, lifetime <
|
||||
- * LONG_MAX / HZ here.
|
||||
- */
|
||||
- if (time_before(expires,
|
||||
- ifa->tstamp + lifetime * HZ))
|
||||
- expires = ifa->tstamp + lifetime * HZ;
|
||||
- spin_unlock(&ifa->lock);
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
- write_unlock_bh(&idev->lock);
|
||||
+ list_del_init(&ifp->if_list);
|
||||
+ __in6_ifa_put(ifp);
|
||||
+
|
||||
+ write_unlock_bh(&ifp->idev->lock);
|
||||
|
||||
addrconf_del_dad_timer(ifp);
|
||||
|
||||
@@ -970,41 +1018,9 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
|
||||
|
||||
inet6addr_notifier_call_chain(NETDEV_DOWN, ifp);
|
||||
|
||||
- /*
|
||||
- * Purge or update corresponding prefix
|
||||
- *
|
||||
- * 1) we don't purge prefix here if address was not permanent.
|
||||
- * prefix is managed by its own lifetime.
|
||||
- * 2) if there're no addresses, delete prefix.
|
||||
- * 3) if there're still other permanent address(es),
|
||||
- * corresponding prefix is still permanent.
|
||||
- * 4) otherwise, update prefix lifetime to the
|
||||
- * longest valid lifetime among the corresponding
|
||||
- * addresses on the device.
|
||||
- * Note: subsequent RA will update lifetime.
|
||||
- *
|
||||
- * --yoshfuji
|
||||
- */
|
||||
- if ((ifp->flags & IFA_F_PERMANENT) && onlink < 1) {
|
||||
- struct in6_addr prefix;
|
||||
- struct rt6_info *rt;
|
||||
-
|
||||
- ipv6_addr_prefix(&prefix, &ifp->addr, ifp->prefix_len);
|
||||
-
|
||||
- rt = addrconf_get_prefix_route(&prefix,
|
||||
- ifp->prefix_len,
|
||||
- ifp->idev->dev,
|
||||
- 0, RTF_GATEWAY | RTF_DEFAULT);
|
||||
-
|
||||
- if (rt) {
|
||||
- if (onlink == 0) {
|
||||
- ip6_del_rt(rt);
|
||||
- rt = NULL;
|
||||
- } else if (!(rt->rt6i_flags & RTF_EXPIRES)) {
|
||||
- rt6_set_expires(rt, expires);
|
||||
- }
|
||||
- }
|
||||
- ip6_rt_put(rt);
|
||||
+ if (action != CLEANUP_PREFIX_RT_NOP) {
|
||||
+ cleanup_prefix_route(ifp, expires,
|
||||
+ action == CLEANUP_PREFIX_RT_DEL);
|
||||
}
|
||||
|
||||
/* clean up prefsrc entries */
|
||||
@@ -1024,7 +1040,7 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *i
|
||||
u32 addr_flags;
|
||||
unsigned long now = jiffies;
|
||||
|
||||
- write_lock(&idev->lock);
|
||||
+ write_lock_bh(&idev->lock);
|
||||
if (ift) {
|
||||
spin_lock_bh(&ift->lock);
|
||||
memcpy(&addr.s6_addr[8], &ift->addr.s6_addr[8], 8);
|
||||
@@ -1036,7 +1052,7 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *i
|
||||
retry:
|
||||
in6_dev_hold(idev);
|
||||
if (idev->cnf.use_tempaddr <= 0) {
|
||||
- write_unlock(&idev->lock);
|
||||
+ write_unlock_bh(&idev->lock);
|
||||
pr_info("%s: use_tempaddr is disabled\n", __func__);
|
||||
in6_dev_put(idev);
|
||||
ret = -1;
|
||||
@@ -1046,7 +1062,7 @@ retry:
|
||||
if (ifp->regen_count++ >= idev->cnf.regen_max_retry) {
|
||||
idev->cnf.use_tempaddr = -1; /*XXX*/
|
||||
spin_unlock_bh(&ifp->lock);
|
||||
- write_unlock(&idev->lock);
|
||||
+ write_unlock_bh(&idev->lock);
|
||||
pr_warn("%s: regeneration time exceeded - disabled temporary address support\n",
|
||||
__func__);
|
||||
in6_dev_put(idev);
|
||||
@@ -1072,7 +1088,7 @@ retry:
|
||||
regen_advance = idev->cnf.regen_max_retry *
|
||||
idev->cnf.dad_transmits *
|
||||
idev->nd_parms->retrans_time / HZ;
|
||||
- write_unlock(&idev->lock);
|
||||
+ write_unlock_bh(&idev->lock);
|
||||
|
||||
/* A temporary address is created only if this calculated Preferred
|
||||
* Lifetime is greater than REGEN_ADVANCE time units. In particular,
|
||||
@@ -1099,7 +1115,7 @@ retry:
|
||||
in6_dev_put(idev);
|
||||
pr_info("%s: retry temporary address regeneration\n", __func__);
|
||||
tmpaddr = &addr;
|
||||
- write_lock(&idev->lock);
|
||||
+ write_lock_bh(&idev->lock);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
@@ -1200,7 +1216,7 @@ static int ipv6_get_saddr_eval(struct net *net,
|
||||
* | d is scope of the destination.
|
||||
* B-d | \
|
||||
* | \ <- smaller scope is better if
|
||||
- * B-15 | \ if scope is enough for destinaion.
|
||||
+ * B-15 | \ if scope is enough for destination.
|
||||
* | ret = B - scope (-1 <= scope >= d <= 15).
|
||||
* d-C-1 | /
|
||||
* |/ <- greater is better
|
||||
@@ -1407,7 +1423,7 @@ try_nextdev:
|
||||
EXPORT_SYMBOL(ipv6_dev_get_saddr);
|
||||
|
||||
int __ipv6_get_lladdr(struct inet6_dev *idev, struct in6_addr *addr,
|
||||
- unsigned char banned_flags)
|
||||
+ u32 banned_flags)
|
||||
{
|
||||
struct inet6_ifaddr *ifp;
|
||||
int err = -EADDRNOTAVAIL;
|
||||
@@ -1424,7 +1440,7 @@ int __ipv6_get_lladdr(struct inet6_dev *idev, struct in6_addr *addr,
|
||||
}
|
||||
|
||||
int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr,
|
||||
- unsigned char banned_flags)
|
||||
+ u32 banned_flags)
|
||||
{
|
||||
struct inet6_dev *idev;
|
||||
int err = -EADDRNOTAVAIL;
|
||||
@@ -2016,6 +2032,73 @@ static struct inet6_dev *addrconf_add_dev(struct net_device *dev)
|
||||
return idev;
|
||||
}
|
||||
|
||||
+static void manage_tempaddrs(struct inet6_dev *idev,
|
||||
+ struct inet6_ifaddr *ifp,
|
||||
+ __u32 valid_lft, __u32 prefered_lft,
|
||||
+ bool create, unsigned long now)
|
||||
+{
|
||||
+ u32 flags;
|
||||
+ struct inet6_ifaddr *ift;
|
||||
+
|
||||
+ read_lock_bh(&idev->lock);
|
||||
+ /* update all temporary addresses in the list */
|
||||
+ list_for_each_entry(ift, &idev->tempaddr_list, tmp_list) {
|
||||
+ int age, max_valid, max_prefered;
|
||||
+
|
||||
+ if (ifp != ift->ifpub)
|
||||
+ continue;
|
||||
+
|
||||
+ /* RFC 4941 section 3.3:
|
||||
+ * If a received option will extend the lifetime of a public
|
||||
+ * address, the lifetimes of temporary addresses should
|
||||
+ * be extended, subject to the overall constraint that no
|
||||
+ * temporary addresses should ever remain "valid" or "preferred"
|
||||
+ * for a time longer than (TEMP_VALID_LIFETIME) or
|
||||
+ * (TEMP_PREFERRED_LIFETIME - DESYNC_FACTOR), respectively.
|
||||
+ */
|
||||
+ age = (now - ift->cstamp) / HZ;
|
||||
+ max_valid = idev->cnf.temp_valid_lft - age;
|
||||
+ if (max_valid < 0)
|
||||
+ max_valid = 0;
|
||||
+
|
||||
+ max_prefered = idev->cnf.temp_prefered_lft -
|
||||
+ idev->cnf.max_desync_factor - age;
|
||||
+ if (max_prefered < 0)
|
||||
+ max_prefered = 0;
|
||||
+
|
||||
+ if (valid_lft > max_valid)
|
||||
+ valid_lft = max_valid;
|
||||
+
|
||||
+ if (prefered_lft > max_prefered)
|
||||
+ prefered_lft = max_prefered;
|
||||
+
|
||||
+ spin_lock(&ift->lock);
|
||||
+ flags = ift->flags;
|
||||
+ ift->valid_lft = valid_lft;
|
||||
+ ift->prefered_lft = prefered_lft;
|
||||
+ ift->tstamp = now;
|
||||
+ if (prefered_lft > 0)
|
||||
+ ift->flags &= ~IFA_F_DEPRECATED;
|
||||
+
|
||||
+ spin_unlock(&ift->lock);
|
||||
+ if (!(flags&IFA_F_TENTATIVE))
|
||||
+ ipv6_ifa_notify(0, ift);
|
||||
+ }
|
||||
+
|
||||
+ if ((create || list_empty(&idev->tempaddr_list)) &&
|
||||
+ idev->cnf.use_tempaddr > 0) {
|
||||
+ /* When a new public address is created as described
|
||||
+ * in [ADDRCONF], also create a new temporary address.
|
||||
+ * Also create a temporary address if it's enabled but
|
||||
+ * no temporary address currently exists.
|
||||
+ */
|
||||
+ read_unlock_bh(&idev->lock);
|
||||
+ ipv6_create_tempaddr(ifp, NULL);
|
||||
+ } else {
|
||||
+ read_unlock_bh(&idev->lock);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)
|
||||
{
|
||||
struct prefix_info *pinfo;
|
||||
@@ -2170,6 +2253,7 @@ ok:
|
||||
return;
|
||||
}
|
||||
|
||||
+ ifp->flags |= IFA_F_MANAGETEMPADDR;
|
||||
update_lft = 0;
|
||||
create = 1;
|
||||
ifp->cstamp = jiffies;
|
||||
@@ -2178,9 +2262,8 @@ ok:
|
||||
}
|
||||
|
||||
if (ifp) {
|
||||
- int flags;
|
||||
+ u32 flags;
|
||||
unsigned long now;
|
||||
- struct inet6_ifaddr *ift;
|
||||
u32 stored_lft;
|
||||
|
||||
/* update lifetime (RFC2462 5.5.3 e) */
|
||||
@@ -2221,70 +2304,8 @@ ok:
|
||||
} else
|
||||
spin_unlock(&ifp->lock);
|
||||
|
||||
- read_lock_bh(&in6_dev->lock);
|
||||
- /* update all temporary addresses in the list */
|
||||
- list_for_each_entry(ift, &in6_dev->tempaddr_list,
|
||||
- tmp_list) {
|
||||
- int age, max_valid, max_prefered;
|
||||
-
|
||||
- if (ifp != ift->ifpub)
|
||||
- continue;
|
||||
-
|
||||
- /*
|
||||
- * RFC 4941 section 3.3:
|
||||
- * If a received option will extend the lifetime
|
||||
- * of a public address, the lifetimes of
|
||||
- * temporary addresses should be extended,
|
||||
- * subject to the overall constraint that no
|
||||
- * temporary addresses should ever remain
|
||||
- * "valid" or "preferred" for a time longer than
|
||||
- * (TEMP_VALID_LIFETIME) or
|
||||
- * (TEMP_PREFERRED_LIFETIME - DESYNC_FACTOR),
|
||||
- * respectively.
|
||||
- */
|
||||
- age = (now - ift->cstamp) / HZ;
|
||||
- max_valid = in6_dev->cnf.temp_valid_lft - age;
|
||||
- if (max_valid < 0)
|
||||
- max_valid = 0;
|
||||
-
|
||||
- max_prefered = in6_dev->cnf.temp_prefered_lft -
|
||||
- in6_dev->cnf.max_desync_factor -
|
||||
- age;
|
||||
- if (max_prefered < 0)
|
||||
- max_prefered = 0;
|
||||
-
|
||||
- if (valid_lft > max_valid)
|
||||
- valid_lft = max_valid;
|
||||
-
|
||||
- if (prefered_lft > max_prefered)
|
||||
- prefered_lft = max_prefered;
|
||||
-
|
||||
- spin_lock(&ift->lock);
|
||||
- flags = ift->flags;
|
||||
- ift->valid_lft = valid_lft;
|
||||
- ift->prefered_lft = prefered_lft;
|
||||
- ift->tstamp = now;
|
||||
- if (prefered_lft > 0)
|
||||
- ift->flags &= ~IFA_F_DEPRECATED;
|
||||
-
|
||||
- spin_unlock(&ift->lock);
|
||||
- if (!(flags&IFA_F_TENTATIVE))
|
||||
- ipv6_ifa_notify(0, ift);
|
||||
- }
|
||||
-
|
||||
- if ((create || list_empty(&in6_dev->tempaddr_list)) && in6_dev->cnf.use_tempaddr > 0) {
|
||||
- /*
|
||||
- * When a new public address is created as
|
||||
- * described in [ADDRCONF], also create a new
|
||||
- * temporary address. Also create a temporary
|
||||
- * address if it's enabled but no temporary
|
||||
- * address currently exists.
|
||||
- */
|
||||
- read_unlock_bh(&in6_dev->lock);
|
||||
- ipv6_create_tempaddr(ifp, NULL);
|
||||
- } else {
|
||||
- read_unlock_bh(&in6_dev->lock);
|
||||
- }
|
||||
+ manage_tempaddrs(in6_dev, ifp, valid_lft, prefered_lft,
|
||||
+ create, now);
|
||||
|
||||
in6_ifa_put(ifp);
|
||||
addrconf_verify(0);
|
||||
@@ -2363,10 +2384,11 @@ err_exit:
|
||||
/*
|
||||
* Manual configuration of address on an interface
|
||||
*/
|
||||
-static int inet6_addr_add(struct net *net, int ifindex, const struct in6_addr *pfx,
|
||||
+static int inet6_addr_add(struct net *net, int ifindex,
|
||||
+ const struct in6_addr *pfx,
|
||||
const struct in6_addr *peer_pfx,
|
||||
- unsigned int plen, __u8 ifa_flags, __u32 prefered_lft,
|
||||
- __u32 valid_lft)
|
||||
+ unsigned int plen, __u32 ifa_flags,
|
||||
+ __u32 prefered_lft, __u32 valid_lft)
|
||||
{
|
||||
struct inet6_ifaddr *ifp;
|
||||
struct inet6_dev *idev;
|
||||
@@ -2385,6 +2407,9 @@ static int inet6_addr_add(struct net *net, int ifindex, const struct in6_addr *p
|
||||
if (!valid_lft || prefered_lft > valid_lft)
|
||||
return -EINVAL;
|
||||
|
||||
+ if (ifa_flags & IFA_F_MANAGETEMPADDR && plen != 64)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
dev = __dev_get_by_index(net, ifindex);
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
@@ -2417,14 +2442,20 @@ static int inet6_addr_add(struct net *net, int ifindex, const struct in6_addr *p
|
||||
valid_lft, prefered_lft);
|
||||
|
||||
if (!IS_ERR(ifp)) {
|
||||
- addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev,
|
||||
- expires, flags);
|
||||
+ if (!(ifa_flags & IFA_F_NOPREFIXROUTE)) {
|
||||
+ addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev,
|
||||
+ expires, flags);
|
||||
+ }
|
||||
+
|
||||
/*
|
||||
* Note that section 3.1 of RFC 4429 indicates
|
||||
* that the Optimistic flag should not be set for
|
||||
* manually configured addresses
|
||||
*/
|
||||
addrconf_dad_start(ifp);
|
||||
+ if (ifa_flags & IFA_F_MANAGETEMPADDR)
|
||||
+ manage_tempaddrs(idev, ifp, valid_lft, prefered_lft,
|
||||
+ true, jiffies);
|
||||
in6_ifa_put(ifp);
|
||||
addrconf_verify(0);
|
||||
return 0;
|
||||
@@ -2857,7 +2888,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
|
||||
}
|
||||
|
||||
/*
|
||||
- * MTU falled under IPV6_MIN_MTU.
|
||||
+ * if MTU under IPV6_MIN_MTU.
|
||||
* Stop IPv6 on this interface.
|
||||
*/
|
||||
|
||||
@@ -3366,7 +3397,7 @@ static void if6_seq_stop(struct seq_file *seq, void *v)
|
||||
static int if6_seq_show(struct seq_file *seq, void *v)
|
||||
{
|
||||
struct inet6_ifaddr *ifp = (struct inet6_ifaddr *)v;
|
||||
- seq_printf(seq, "%pi6 %02x %02x %02x %02x %8s\n",
|
||||
+ seq_printf(seq, "%pi6 %02x %02x %02x %03x %8s\n",
|
||||
&ifp->addr,
|
||||
ifp->idev->dev->ifindex,
|
||||
ifp->prefix_len,
|
||||
@@ -3593,6 +3624,7 @@ static const struct nla_policy ifa_ipv6_policy[IFA_MAX+1] = {
|
||||
[IFA_ADDRESS] = { .len = sizeof(struct in6_addr) },
|
||||
[IFA_LOCAL] = { .len = sizeof(struct in6_addr) },
|
||||
[IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) },
|
||||
+ [IFA_FLAGS] = { .len = sizeof(u32) },
|
||||
};
|
||||
|
||||
static int
|
||||
@@ -3616,16 +3648,22 @@ inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||
return inet6_addr_del(net, ifm->ifa_index, pfx, ifm->ifa_prefixlen);
|
||||
}
|
||||
|
||||
-static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags,
|
||||
+static int inet6_addr_modify(struct inet6_ifaddr *ifp, u32 ifa_flags,
|
||||
u32 prefered_lft, u32 valid_lft)
|
||||
{
|
||||
u32 flags;
|
||||
clock_t expires;
|
||||
unsigned long timeout;
|
||||
+ bool was_managetempaddr;
|
||||
+ bool had_prefixroute;
|
||||
|
||||
if (!valid_lft || (prefered_lft > valid_lft))
|
||||
return -EINVAL;
|
||||
|
||||
+ if (ifa_flags & IFA_F_MANAGETEMPADDR &&
|
||||
+ (ifp->flags & IFA_F_TEMPORARY || ifp->prefix_len != 64))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
timeout = addrconf_timeout_fixup(valid_lft, HZ);
|
||||
if (addrconf_finite_timeout(timeout)) {
|
||||
expires = jiffies_to_clock_t(timeout * HZ);
|
||||
@@ -3645,7 +3683,13 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags,
|
||||
}
|
||||
|
||||
spin_lock_bh(&ifp->lock);
|
||||
- ifp->flags = (ifp->flags & ~(IFA_F_DEPRECATED | IFA_F_PERMANENT | IFA_F_NODAD | IFA_F_HOMEADDRESS)) | ifa_flags;
|
||||
+ was_managetempaddr = ifp->flags & IFA_F_MANAGETEMPADDR;
|
||||
+ had_prefixroute = ifp->flags & IFA_F_PERMANENT &&
|
||||
+ !(ifp->flags & IFA_F_NOPREFIXROUTE);
|
||||
+ ifp->flags &= ~(IFA_F_DEPRECATED | IFA_F_PERMANENT | IFA_F_NODAD |
|
||||
+ IFA_F_HOMEADDRESS | IFA_F_MANAGETEMPADDR |
|
||||
+ IFA_F_NOPREFIXROUTE);
|
||||
+ ifp->flags |= ifa_flags;
|
||||
ifp->tstamp = jiffies;
|
||||
ifp->valid_lft = valid_lft;
|
||||
ifp->prefered_lft = prefered_lft;
|
||||
@@ -3654,8 +3698,30 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags,
|
||||
if (!(ifp->flags&IFA_F_TENTATIVE))
|
||||
ipv6_ifa_notify(0, ifp);
|
||||
|
||||
- addrconf_prefix_route(&ifp->addr, ifp->prefix_len, ifp->idev->dev,
|
||||
- expires, flags);
|
||||
+ if (!(ifa_flags & IFA_F_NOPREFIXROUTE)) {
|
||||
+ addrconf_prefix_route(&ifp->addr, ifp->prefix_len, ifp->idev->dev,
|
||||
+ expires, flags);
|
||||
+ } else if (had_prefixroute) {
|
||||
+ enum cleanup_prefix_rt_t action;
|
||||
+ unsigned long rt_expires;
|
||||
+
|
||||
+ write_lock_bh(&ifp->idev->lock);
|
||||
+ action = check_cleanup_prefix_route(ifp, &rt_expires);
|
||||
+ write_unlock_bh(&ifp->idev->lock);
|
||||
+
|
||||
+ if (action != CLEANUP_PREFIX_RT_NOP) {
|
||||
+ cleanup_prefix_route(ifp, rt_expires,
|
||||
+ action == CLEANUP_PREFIX_RT_DEL);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (was_managetempaddr || ifp->flags & IFA_F_MANAGETEMPADDR) {
|
||||
+ if (was_managetempaddr && !(ifp->flags & IFA_F_MANAGETEMPADDR))
|
||||
+ valid_lft = prefered_lft = 0;
|
||||
+ manage_tempaddrs(ifp->idev, ifp, valid_lft, prefered_lft,
|
||||
+ !was_managetempaddr, jiffies);
|
||||
+ }
|
||||
+
|
||||
addrconf_verify(0);
|
||||
|
||||
return 0;
|
||||
@@ -3671,7 +3737,7 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||
struct inet6_ifaddr *ifa;
|
||||
struct net_device *dev;
|
||||
u32 valid_lft = INFINITY_LIFE_TIME, preferred_lft = INFINITY_LIFE_TIME;
|
||||
- u8 ifa_flags;
|
||||
+ u32 ifa_flags;
|
||||
int err;
|
||||
|
||||
err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy);
|
||||
@@ -3698,14 +3764,17 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||
if (dev == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
+ ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) : ifm->ifa_flags;
|
||||
+
|
||||
/* We ignore other flags so far. */
|
||||
- ifa_flags = ifm->ifa_flags & (IFA_F_NODAD | IFA_F_HOMEADDRESS);
|
||||
+ ifa_flags &= IFA_F_NODAD | IFA_F_HOMEADDRESS | IFA_F_MANAGETEMPADDR |
|
||||
+ IFA_F_NOPREFIXROUTE;
|
||||
|
||||
ifa = ipv6_get_ifaddr(net, pfx, dev, 1);
|
||||
if (ifa == NULL) {
|
||||
/*
|
||||
* It would be best to check for !NLM_F_CREATE here but
|
||||
- * userspace alreay relies on not having to provide this.
|
||||
+ * userspace already relies on not having to provide this.
|
||||
*/
|
||||
return inet6_addr_add(net, ifm->ifa_index, pfx, peer_pfx,
|
||||
ifm->ifa_prefixlen, ifa_flags,
|
||||
@@ -3723,7 +3792,7 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||
return err;
|
||||
}
|
||||
|
||||
-static void put_ifaddrmsg(struct nlmsghdr *nlh, u8 prefixlen, u8 flags,
|
||||
+static void put_ifaddrmsg(struct nlmsghdr *nlh, u8 prefixlen, u32 flags,
|
||||
u8 scope, int ifindex)
|
||||
{
|
||||
struct ifaddrmsg *ifm;
|
||||
@@ -3766,7 +3835,8 @@ static inline int inet6_ifaddr_msgsize(void)
|
||||
return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
|
||||
+ nla_total_size(16) /* IFA_LOCAL */
|
||||
+ nla_total_size(16) /* IFA_ADDRESS */
|
||||
- + nla_total_size(sizeof(struct ifa_cacheinfo));
|
||||
+ + nla_total_size(sizeof(struct ifa_cacheinfo))
|
||||
+ + nla_total_size(4) /* IFA_FLAGS */;
|
||||
}
|
||||
|
||||
static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa,
|
||||
@@ -3815,6 +3885,9 @@ static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa,
|
||||
if (put_cacheinfo(skb, ifa->cstamp, ifa->tstamp, preferred, valid) < 0)
|
||||
goto error;
|
||||
|
||||
+ if (nla_put_u32(skb, IFA_FLAGS, ifa->flags) < 0)
|
||||
+ goto error;
|
||||
+
|
||||
return nlmsg_end(skb, nlh);
|
||||
|
||||
error:
|
||||
_______________________________________________
|
||||
kernel mailing list
|
||||
kernel@lists.fedoraproject.org
|
||||
https://admin.fedoraproject.org/mailman/listinfo/kernel
|
10
kernel.spec
10
kernel.spec
|
@ -759,6 +759,10 @@ Patch25189: tick-Clear-broadcast-pending-bit-when-switching-to-oneshot.patch
|
|||
#rhbz 1045755
|
||||
Patch25195: cgroup-fixes.patch
|
||||
|
||||
#rhbz 1064430 1056711
|
||||
Patch25196: ipv6-introduce-IFA_F_NOPREFIXROUTE-and-IFA_F_MANAGETEMPADDR-flags.patch
|
||||
Patch25197: ipv6-addrconf-revert-if_inet6ifa_flag-format.patch
|
||||
|
||||
# END OF PATCH DEFINITIONS
|
||||
|
||||
%endif
|
||||
|
@ -1474,6 +1478,11 @@ ApplyPatch tick-Clear-broadcast-pending-bit-when-switching-to-oneshot.patch
|
|||
#rhbz 1045755
|
||||
ApplyPatch cgroup-fixes.patch
|
||||
|
||||
#rhbz 1064430 1056711
|
||||
ApplyPatch ipv6-introduce-IFA_F_NOPREFIXROUTE-and-IFA_F_MANAGETEMPADDR-flags.patch
|
||||
ApplyPatch ipv6-addrconf-revert-if_inet6ifa_flag-format.patch
|
||||
|
||||
|
||||
# END OF PATCH APPLICATIONS
|
||||
|
||||
%endif
|
||||
|
@ -2286,6 +2295,7 @@ fi
|
|||
# || ||
|
||||
%changelog
|
||||
* Wed Feb 12 2014 Josh Boyer <jwboyer@fedoraproject.org>
|
||||
- Add IFA_FLAGS for IPv6 temporary addresses back (rhbz 1064430)
|
||||
- Fix cgroup destroy oops (rhbz 1045755)
|
||||
- Fix backtrace in amd_e400_idle (rhbz 1031296)
|
||||
- CVE-2014-1874 SELinux: local denial of service (rhbz 1062356 1062507)
|
||||
|
|
Loading…
Reference in New Issue