OSDN Git Service

net/ipv6: separate handling of FIB entries from dst based routes
[uclinux-h8/linux.git] / net / ipv6 / addrconf.c
index e1846b9..e533a44 100644 (file)
 #include <linux/seq_file.h>
 #include <linux/export.h>
 
-/* Set to 3 to get tracing... */
-#define ACONF_DEBUG 2
-
-#if ACONF_DEBUG >= 3
-#define ADBG(fmt, ...) printk(fmt, ##__VA_ARGS__)
-#else
-#define ADBG(fmt, ...) do { if (0) printk(fmt, ##__VA_ARGS__); } while (0)
-#endif
-
 #define        INFINITY_LIFE_TIME      0xFFFFFFFF
 
 #define IPV6_MAX_STRLEN \
@@ -409,9 +400,8 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
        dev_hold(dev);
 
        if (snmp6_alloc_dev(ndev) < 0) {
-               ADBG(KERN_WARNING
-                       "%s: cannot allocate memory for statistics; dev=%s.\n",
-                       __func__, dev->name);
+               netdev_dbg(dev, "%s: cannot allocate memory for statistics\n",
+                          __func__);
                neigh_parms_release(&nd_tbl, ndev->nd_parms);
                dev_put(dev);
                kfree(ndev);
@@ -419,9 +409,8 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
        }
 
        if (snmp6_register_dev(ndev) < 0) {
-               ADBG(KERN_WARNING
-                       "%s: cannot create /proc/net/dev_snmp6/%s\n",
-                       __func__, dev->name);
+               netdev_dbg(dev, "%s: cannot create /proc/net/dev_snmp6/%s\n",
+                          __func__, dev->name);
                goto err_release;
        }
 
@@ -927,7 +916,6 @@ void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp)
                pr_warn("Freeing alive inet6 address %p\n", ifp);
                return;
        }
-       ip6_rt_put(ifp->rt);
 
        kfree_rcu(ifp, rcu);
 }
@@ -984,7 +972,7 @@ static int ipv6_add_addr_hash(struct net_device *dev, struct inet6_ifaddr *ifa)
 
        /* Ignore adding duplicate addresses on an interface */
        if (ipv6_chk_same_addr(dev_net(dev), &ifa->addr, dev, hash)) {
-               ADBG("ipv6_add_addr: already assigned\n");
+               netdev_dbg(dev, "ipv6_add_addr: already assigned\n");
                err = -EEXIST;
        } else {
                hlist_add_head_rcu(&ifa->addr_lst, &inet6_addr_lst[hash]);
@@ -1044,12 +1032,11 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr,
 
        ifa = kzalloc(sizeof(*ifa), gfp_flags);
        if (!ifa) {
-               ADBG("ipv6_add_addr: malloc failed\n");
                err = -ENOBUFS;
                goto out;
        }
 
-       rt = addrconf_dst_alloc(idev, addr, false);
+       rt = addrconf_dst_alloc(net, idev, addr, false, gfp_flags);
        if (IS_ERR(rt)) {
                err = PTR_ERR(rt);
                rt = NULL;
@@ -1058,7 +1045,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr,
 
        if (net->ipv6.devconf_all->disable_policy ||
            idev->cnf.disable_policy)
-               rt->dst.flags |= DST_NOPOLICY;
+               rt->dst_nopolicy = true;
 
        neigh_parms_data_state_setall(idev->nd_parms);
 
@@ -1114,8 +1101,8 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr,
        inet6addr_notifier_call_chain(NETDEV_UP, ifa);
 out:
        if (unlikely(err < 0)) {
-               if (rt)
-                       ip6_rt_put(rt);
+               fib6_info_release(rt);
+
                if (ifa) {
                        if (ifa->idev)
                                in6_dev_put(ifa->idev);
@@ -1199,11 +1186,11 @@ cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long expires, bool del_r
                                       0, RTF_GATEWAY | RTF_DEFAULT);
        if (rt) {
                if (del_rt)
-                       ip6_del_rt(rt);
+                       ip6_del_rt(dev_net(ifp->idev->dev), rt);
                else {
                        if (!(rt->rt6i_flags & RTF_EXPIRES))
-                               rt6_set_expires(rt, expires);
-                       ip6_rt_put(rt);
+                               fib6_set_expires(rt, expires);
+                       fib6_info_release(rt);
                }
        }
 }
@@ -1459,6 +1446,21 @@ static bool ipv6_use_optimistic_addr(struct net *net,
 #endif
 }
 
+static bool ipv6_allow_optimistic_dad(struct net *net,
+                                     struct inet6_dev *idev)
+{
+#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
+       if (!idev)
+               return false;
+       if (!net->ipv6.devconf_all->optimistic_dad && !idev->cnf.optimistic_dad)
+               return false;
+
+       return true;
+#else
+       return false;
+#endif
+}
+
 static int ipv6_get_saddr_eval(struct net *net,
                               struct ipv6_saddr_score *score,
                               struct ipv6_saddr_dst *dst,
@@ -1836,22 +1838,42 @@ static int ipv6_count_addresses(const struct inet6_dev *idev)
 int ipv6_chk_addr(struct net *net, const struct in6_addr *addr,
                  const struct net_device *dev, int strict)
 {
-       return ipv6_chk_addr_and_flags(net, addr, dev, strict, IFA_F_TENTATIVE);
+       return ipv6_chk_addr_and_flags(net, addr, dev, !dev,
+                                      strict, IFA_F_TENTATIVE);
 }
 EXPORT_SYMBOL(ipv6_chk_addr);
 
+/* device argument is used to find the L3 domain of interest. If
+ * skip_dev_check is set, then the ifp device is not checked against
+ * the passed in dev argument. So the 2 cases for addresses checks are:
+ *   1. does the address exist in the L3 domain that dev is part of
+ *      (skip_dev_check = true), or
+ *
+ *   2. does the address exist on the specific device
+ *      (skip_dev_check = false)
+ */
 int ipv6_chk_addr_and_flags(struct net *net, const struct in6_addr *addr,
-                           const struct net_device *dev, int strict,
-                           u32 banned_flags)
+                           const struct net_device *dev, bool skip_dev_check,
+                           int strict, u32 banned_flags)
 {
        unsigned int hash = inet6_addr_hash(net, addr);
+       const struct net_device *l3mdev;
        struct inet6_ifaddr *ifp;
        u32 ifp_flags;
 
        rcu_read_lock();
+
+       l3mdev = l3mdev_master_dev_rcu(dev);
+       if (skip_dev_check)
+               dev = NULL;
+
        hlist_for_each_entry_rcu(ifp, &inet6_addr_lst[hash], addr_lst) {
                if (!net_eq(dev_net(ifp->idev->dev), net))
                        continue;
+
+               if (l3mdev_master_dev_rcu(ifp->idev->dev) != l3mdev)
+                       continue;
+
                /* Decouple optimistic from tentative for evaluation here.
                 * Ban optimistic addresses explicitly, when required.
                 */
@@ -1968,6 +1990,8 @@ static void addrconf_dad_stop(struct inet6_ifaddr *ifp, int dad_failed)
                spin_lock_bh(&ifp->lock);
                addrconf_del_dad_work(ifp);
                ifp->flags |= IFA_F_TENTATIVE;
+               if (dad_failed)
+                       ifp->flags &= ~IFA_F_OPTIMISTIC;
                spin_unlock_bh(&ifp->lock);
                if (dad_failed)
                        ipv6_ifa_notify(0, ifp);
@@ -2295,7 +2319,7 @@ static void  ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpad
 
 static void
 addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev,
-                     unsigned long expires, u32 flags)
+                     unsigned long expires, u32 flags, gfp_t gfp_flags)
 {
        struct fib6_config cfg = {
                .fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_PREFIX,
@@ -2306,6 +2330,7 @@ addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev,
                .fc_flags = RTF_UP | flags,
                .fc_nlinfo.nl_net = dev_net(dev),
                .fc_protocol = RTPROT_KERNEL,
+               .fc_type = RTN_UNICAST,
        };
 
        cfg.fc_dst = *pfx;
@@ -2319,7 +2344,7 @@ addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev,
                cfg.fc_flags |= RTF_NONEXTHOP;
 #endif
 
-       ip6_route_add(&cfg, NULL);
+       ip6_route_add(&cfg, gfp_flags, NULL);
 }
 
 
@@ -2343,14 +2368,13 @@ static struct rt6_info *addrconf_get_prefix_route(const struct in6_addr *pfx,
                goto out;
 
        for_each_fib6_node_rt_rcu(fn) {
-               if (rt->dst.dev->ifindex != dev->ifindex)
+               if (rt->fib6_nh.nh_dev->ifindex != dev->ifindex)
                        continue;
                if ((rt->rt6i_flags & flags) != flags)
                        continue;
                if ((rt->rt6i_flags & noflags) != 0)
                        continue;
-               if (!dst_hold_safe(&rt->dst))
-                       rt = NULL;
+               fib6_info_hold(rt);
                break;
        }
 out:
@@ -2369,12 +2393,13 @@ static void addrconf_add_mroute(struct net_device *dev)
                .fc_ifindex = dev->ifindex,
                .fc_dst_len = 8,
                .fc_flags = RTF_UP,
+               .fc_type = RTN_UNICAST,
                .fc_nlinfo.nl_net = dev_net(dev),
        };
 
        ipv6_addr_set(&cfg.fc_dst, htonl(0xFF000000), 0, 0, 0);
 
-       ip6_route_add(&cfg, NULL);
+       ip6_route_add(&cfg, GFP_ATOMIC, NULL);
 }
 
 static struct inet6_dev *addrconf_add_dev(struct net_device *dev)
@@ -2504,7 +2529,6 @@ int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
                if (IS_ERR_OR_NULL(ifp))
                        return -1;
 
-               update_lft = 0;
                create = 1;
                spin_lock_bh(&ifp->lock);
                ifp->flags |= IFA_F_MANAGETEMPADDR;
@@ -2526,7 +2550,7 @@ int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
                        stored_lft = ifp->valid_lft - (now - ifp->tstamp) / HZ;
                else
                        stored_lft = 0;
-               if (!update_lft && !create && stored_lft) {
+               if (!create && stored_lft) {
                        const u32 minimum_lft = min_t(u32,
                                stored_lft, MIN_VALID_LIFETIME);
                        valid_lft = max(valid_lft, minimum_lft);
@@ -2581,7 +2605,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)
        pinfo = (struct prefix_info *) opt;
 
        if (len < sizeof(struct prefix_info)) {
-               ADBG("addrconf: prefix option too short\n");
+               netdev_dbg(dev, "addrconf: prefix option too short\n");
                return;
        }
 
@@ -2642,13 +2666,13 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)
                if (rt) {
                        /* Autoconf prefix route */
                        if (valid_lft == 0) {
-                               ip6_del_rt(rt);
+                               ip6_del_rt(net, rt);
                                rt = NULL;
                        } else if (addrconf_finite_timeout(rt_expires)) {
                                /* not infinity */
-                               rt6_set_expires(rt, jiffies + rt_expires);
+                               fib6_set_expires(rt, jiffies + rt_expires);
                        } else {
-                               rt6_clean_expires(rt);
+                               fib6_clean_expires(rt);
                        }
                } else if (valid_lft) {
                        clock_t expires = 0;
@@ -2659,9 +2683,9 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)
                                expires = jiffies_to_clock_t(rt_expires);
                        }
                        addrconf_prefix_route(&pinfo->prefix, pinfo->prefix_len,
-                                             dev, expires, flags);
+                                             dev, expires, flags, GFP_ATOMIC);
                }
-               ip6_rt_put(rt);
+               fib6_info_release(rt);
        }
 
        /* Try to figure out our local address for this prefix */
@@ -2874,9 +2898,14 @@ static int inet6_addr_add(struct net *net, int ifindex,
        if (!IS_ERR(ifp)) {
                if (!(ifa_flags & IFA_F_NOPREFIXROUTE)) {
                        addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev,
-                                             expires, flags);
+                                             expires, flags, GFP_KERNEL);
                }
 
+               /* Send a netlink notification if DAD is enabled and
+                * optimistic flag is not set
+                */
+               if (!(ifp->flags & (IFA_F_OPTIMISTIC | IFA_F_NODAD)))
+                       ipv6_ifa_notify(0, ifp);
                /*
                 * Note that section 3.1 of RFC 4429 indicates
                 * that the Optimistic flag should not be set for
@@ -3022,7 +3051,8 @@ static void sit_add_v4_addrs(struct inet6_dev *idev)
 
        if (addr.s6_addr32[3]) {
                add_addr(idev, &addr, plen, scope);
-               addrconf_prefix_route(&addr, plen, idev->dev, 0, pflags);
+               addrconf_prefix_route(&addr, plen, idev->dev, 0, pflags,
+                                     GFP_ATOMIC);
                return;
        }
 
@@ -3047,7 +3077,7 @@ static void sit_add_v4_addrs(struct inet6_dev *idev)
 
                                add_addr(idev, &addr, plen, flag);
                                addrconf_prefix_route(&addr, plen, idev->dev, 0,
-                                                     pflags);
+                                                     pflags, GFP_ATOMIC);
                        }
                }
        }
@@ -3087,7 +3117,8 @@ void addrconf_add_linklocal(struct inet6_dev *idev,
        ifp = ipv6_add_addr(idev, addr, NULL, 64, IFA_LINK, addr_flags,
                            INFINITY_LIFE_TIME, INFINITY_LIFE_TIME, true, NULL);
        if (!IS_ERR(ifp)) {
-               addrconf_prefix_route(&ifp->addr, ifp->prefix_len, idev->dev, 0, 0);
+               addrconf_prefix_route(&ifp->addr, ifp->prefix_len, idev->dev,
+                                     0, 0, GFP_ATOMIC);
                addrconf_dad_start(ifp);
                in6_ifa_put(ifp);
        }
@@ -3202,7 +3233,8 @@ static void addrconf_addr_gen(struct inet6_dev *idev, bool prefix_route)
                        addrconf_add_linklocal(idev, &addr,
                                               IFA_F_STABLE_PRIVACY);
                else if (prefix_route)
-                       addrconf_prefix_route(&addr, 64, idev->dev, 0, 0);
+                       addrconf_prefix_route(&addr, 64, idev->dev,
+                                             0, 0, GFP_KERNEL);
                break;
        case IN6_ADDR_GEN_MODE_EUI64:
                /* addrconf_add_linklocal also adds a prefix_route and we
@@ -3212,7 +3244,8 @@ static void addrconf_addr_gen(struct inet6_dev *idev, bool prefix_route)
                if (ipv6_generate_eui64(addr.s6_addr + 8, idev->dev) == 0)
                        addrconf_add_linklocal(idev, &addr, 0);
                else if (prefix_route)
-                       addrconf_prefix_route(&addr, 64, idev->dev, 0, 0);
+                       addrconf_prefix_route(&addr, 64, idev->dev,
+                                             0, 0, GFP_ATOMIC);
                break;
        case IN6_ADDR_GEN_MODE_NONE:
        default:
@@ -3304,7 +3337,8 @@ static void addrconf_gre_config(struct net_device *dev)
 }
 #endif
 
-static int fixup_permanent_addr(struct inet6_dev *idev,
+static int fixup_permanent_addr(struct net *net,
+                               struct inet6_dev *idev,
                                struct inet6_ifaddr *ifp)
 {
        /* !rt6i_node means the host route was removed from the
@@ -3314,7 +3348,8 @@ static int fixup_permanent_addr(struct inet6_dev *idev,
        if (!ifp->rt || !ifp->rt->rt6i_node) {
                struct rt6_info *rt, *prev;
 
-               rt = addrconf_dst_alloc(idev, &ifp->addr, false);
+               rt = addrconf_dst_alloc(net, idev, &ifp->addr, false,
+                                       GFP_ATOMIC);
                if (IS_ERR(rt))
                        return PTR_ERR(rt);
 
@@ -3324,12 +3359,12 @@ static int fixup_permanent_addr(struct inet6_dev *idev,
                ifp->rt = rt;
                spin_unlock(&ifp->lock);
 
-               ip6_rt_put(prev);
+               fib6_info_release(prev);
        }
 
        if (!(ifp->flags & IFA_F_NOPREFIXROUTE)) {
                addrconf_prefix_route(&ifp->addr, ifp->prefix_len,
-                                     idev->dev, 0, 0);
+                                     idev->dev, 0, 0, GFP_ATOMIC);
        }
 
        if (ifp->state == INET6_IFADDR_STATE_PREDAD)
@@ -3338,7 +3373,7 @@ static int fixup_permanent_addr(struct inet6_dev *idev,
        return 0;
 }
 
-static void addrconf_permanent_addr(struct net_device *dev)
+static void addrconf_permanent_addr(struct net *net, struct net_device *dev)
 {
        struct inet6_ifaddr *ifp, *tmp;
        struct inet6_dev *idev;
@@ -3351,7 +3386,7 @@ static void addrconf_permanent_addr(struct net_device *dev)
 
        list_for_each_entry_safe(ifp, tmp, &idev->addr_list, if_list) {
                if ((ifp->flags & IFA_F_PERMANENT) &&
-                   fixup_permanent_addr(idev, ifp) < 0) {
+                   fixup_permanent_addr(net, idev, ifp) < 0) {
                        write_unlock_bh(&idev->lock);
                        in6_ifa_hold(ifp);
                        ipv6_del_addr(ifp);
@@ -3420,7 +3455,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
 
                if (event == NETDEV_UP) {
                        /* restore routes for permanent addresses */
-                       addrconf_permanent_addr(dev);
+                       addrconf_permanent_addr(net, dev);
 
                        if (!addrconf_link_ready(dev)) {
                                /* device is not ready yet. */
@@ -3706,7 +3741,7 @@ restart:
                spin_unlock_bh(&ifa->lock);
 
                if (rt)
-                       ip6_del_rt(rt);
+                       ip6_del_rt(net, rt);
 
                if (state != INET6_IFADDR_STATE_DEAD) {
                        __ipv6_ifa_notify(RTM_DELADDR, ifa);
@@ -3824,6 +3859,7 @@ static void addrconf_dad_begin(struct inet6_ifaddr *ifp)
        struct inet6_dev *idev = ifp->idev;
        struct net_device *dev = idev->dev;
        bool bump_id, notify = false;
+       struct net *net;
 
        addrconf_join_solict(dev, &ifp->addr);
 
@@ -3834,8 +3870,9 @@ static void addrconf_dad_begin(struct inet6_ifaddr *ifp)
        if (ifp->state == INET6_IFADDR_STATE_DEAD)
                goto out;
 
+       net = dev_net(dev);
        if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) ||
-           (dev_net(dev)->ipv6.devconf_all->accept_dad < 1 &&
+           (net->ipv6.devconf_all->accept_dad < 1 &&
             idev->cnf.accept_dad < 1) ||
            !(ifp->flags&IFA_F_TENTATIVE) ||
            ifp->flags & IFA_F_NODAD) {
@@ -3871,8 +3908,8 @@ static void addrconf_dad_begin(struct inet6_ifaddr *ifp)
         * Frames right away
         */
        if (ifp->flags & IFA_F_OPTIMISTIC) {
-               ip6_ins_rt(ifp->rt);
-               if (ipv6_use_optimistic_addr(dev_net(dev), idev)) {
+               ip6_ins_rt(net, ifp->rt);
+               if (ipv6_use_optimistic_addr(net, idev)) {
                        /* Because optimistic nodes can use this address,
                         * notify listeners. If DAD fails, RTM_DELADDR is sent.
                         */
@@ -4244,7 +4281,7 @@ static const struct file_operations if6_fops = {
 
 static int __net_init if6_proc_net_init(struct net *net)
 {
-       if (!proc_create("if_inet6", S_IRUGO, net->proc_net, &if6_fops))
+       if (!proc_create("if_inet6", 0444, net->proc_net, &if6_fops))
                return -ENOMEM;
        return 0;
 }
@@ -4408,8 +4445,8 @@ restart:
        if (time_before(next_sched, jiffies + ADDRCONF_TIMER_FUZZ_MAX))
                next_sched = jiffies + ADDRCONF_TIMER_FUZZ_MAX;
 
-       ADBG(KERN_DEBUG "now = %lu, schedule = %lu, rounded schedule = %lu => %lu\n",
-             now, next, next_sec, next_sched);
+       pr_debug("now = %lu, schedule = %lu, rounded schedule = %lu => %lu\n",
+                now, next, next_sec, next_sched);
        mod_delayed_work(addrconf_wq, &addr_chk_work, next_sched - now);
        rcu_read_unlock_bh();
 }
@@ -4500,6 +4537,9 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u32 ifa_flags,
            (ifp->flags & IFA_F_TEMPORARY || ifp->prefix_len != 64))
                return -EINVAL;
 
+       if (!(ifp->flags & IFA_F_TENTATIVE) || ifp->flags & IFA_F_DADFAILED)
+               ifa_flags &= ~IFA_F_OPTIMISTIC;
+
        timeout = addrconf_timeout_fixup(valid_lft, HZ);
        if (addrconf_finite_timeout(timeout)) {
                expires = jiffies_to_clock_t(timeout * HZ);
@@ -4535,8 +4575,9 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u32 ifa_flags,
                ipv6_ifa_notify(0, ifp);
 
        if (!(ifa_flags & IFA_F_NOPREFIXROUTE)) {
-               addrconf_prefix_route(&ifp->addr, ifp->prefix_len, ifp->idev->dev,
-                                     expires, flags);
+               addrconf_prefix_route(&ifp->addr, ifp->prefix_len,
+                                     ifp->idev->dev, expires, flags,
+                                     GFP_KERNEL);
        } else if (had_prefixroute) {
                enum cleanup_prefix_rt_t action;
                unsigned long rt_expires;
@@ -4573,6 +4614,7 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh,
        struct in6_addr *pfx, *peer_pfx;
        struct inet6_ifaddr *ifa;
        struct net_device *dev;
+       struct inet6_dev *idev;
        u32 valid_lft = INFINITY_LIFE_TIME, preferred_lft = INFINITY_LIFE_TIME;
        u32 ifa_flags;
        int err;
@@ -4606,7 +4648,19 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh,
 
        /* We ignore other flags so far. */
        ifa_flags &= IFA_F_NODAD | IFA_F_HOMEADDRESS | IFA_F_MANAGETEMPADDR |
-                    IFA_F_NOPREFIXROUTE | IFA_F_MCAUTOJOIN;
+                    IFA_F_NOPREFIXROUTE | IFA_F_MCAUTOJOIN | IFA_F_OPTIMISTIC;
+
+       idev = ipv6_find_idev(dev);
+       if (IS_ERR(idev))
+               return PTR_ERR(idev);
+
+       if (!ipv6_allow_optimistic_dad(net, idev))
+               ifa_flags &= ~IFA_F_OPTIMISTIC;
+
+       if (ifa_flags & IFA_F_NODAD && ifa_flags & IFA_F_OPTIMISTIC) {
+               NL_SET_ERR_MSG(extack, "IFA_F_NODAD and IFA_F_OPTIMISTIC are mutually exclusive");
+               return -EINVAL;
+       }
 
        ifa = ipv6_get_ifaddr(net, pfx, dev, 1);
        if (!ifa) {
@@ -4988,14 +5042,6 @@ static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa)
        struct net *net = dev_net(ifa->idev->dev);
        int err = -ENOBUFS;
 
-       /* Don't send DELADDR notification for TENTATIVE address,
-        * since NEWADDR notification is sent only after removing
-        * TENTATIVE flag, if DAD has not failed.
-        */
-       if (ifa->flags & IFA_F_TENTATIVE && !(ifa->flags & IFA_F_DADFAILED) &&
-           event == RTM_DELADDR)
-               return;
-
        skb = nlmsg_new(inet6_ifaddr_msgsize(), GFP_ATOMIC);
        if (!skb)
                goto errout;
@@ -5567,12 +5613,13 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
                 * to do it again
                 */
                if (!rcu_access_pointer(ifp->rt->rt6i_node))
-                       ip6_ins_rt(ifp->rt);
+                       ip6_ins_rt(net, ifp->rt);
                if (ifp->idev->cnf.forwarding)
                        addrconf_join_anycast(ifp);
                if (!ipv6_addr_any(&ifp->peer_addr))
                        addrconf_prefix_route(&ifp->peer_addr, 128,
-                                             ifp->idev->dev, 0, 0);
+                                             ifp->idev->dev, 0, 0,
+                                             GFP_KERNEL);
                break;
        case RTM_DELADDR:
                if (ifp->idev->cnf.forwarding)
@@ -5584,11 +5631,11 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
                        rt = addrconf_get_prefix_route(&ifp->peer_addr, 128,
                                                       ifp->idev->dev, 0, 0);
                        if (rt)
-                               ip6_del_rt(rt);
+                               ip6_del_rt(net, rt);
                }
                if (ifp->rt) {
-                       if (dst_hold_safe(&ifp->rt->dst))
-                               ip6_del_rt(ifp->rt);
+                       ip6_del_rt(net, ifp->rt);
+                       ifp->rt = NULL;
                }
                rt_genid_bump_ipv6(net);
                break;
@@ -5939,7 +5986,7 @@ void addrconf_disable_policy_idev(struct inet6_dev *idev, int val)
                        int cpu;
 
                        rcu_read_lock();
-                       addrconf_set_nopolicy(ifa->rt, val);
+                       ifa->rt->dst_nopolicy = val ? true : false;
                        if (rt->rt6i_pcpu) {
                                for_each_possible_cpu(cpu) {
                                        struct rt6_info **rtp;