From 451ae94d0c814b9cb86b9ef7c8ccb2b7656f585c Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Feb 12 2014 18:43:32 +0000 Subject: Add IFA_FLAGS for IPv6 temporary addresses back (rhbz 1064430) --- diff --git a/ipv6-addrconf-revert-if_inet6ifa_flag-format.patch b/ipv6-addrconf-revert-if_inet6ifa_flag-format.patch new file mode 100644 index 0000000..1282667 --- /dev/null +++ b/ipv6-addrconf-revert-if_inet6ifa_flag-format.patch @@ -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 +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 + +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 diff --git a/ipv6-introduce-IFA_F_NOPREFIXROUTE-and-IFA_F_MANAGETEMPADDR-flags.patch b/ipv6-introduce-IFA_F_NOPREFIXROUTE-and-IFA_F_MANAGETEMPADDR-flags.patch new file mode 100644 index 0000000..54d1e91 --- /dev/null +++ b/ipv6-introduce-IFA_F_NOPREFIXROUTE-and-IFA_F_MANAGETEMPADDR-flags.patch @@ -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 + +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 \ No newline at end of file diff --git a/kernel.spec b/kernel.spec index 49ddb8a..e990b0a 100644 --- a/kernel.spec +++ b/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 +- 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)