]> Pileus Git - ~andy/linux/blobdiff - net/ipv6/addrconf.c
Merge tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost
[~andy/linux] / net / ipv6 / addrconf.c
index cf88df82e2c21ca21da8184f0370096b094dffba..0ba0866230c99367db4f3706b15cb2ed0ff91dbf 100644 (file)
@@ -630,13 +630,13 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
                goto out;
        }
 
-       rt = addrconf_dst_alloc(idev, addr, 0);
+       rt = addrconf_dst_alloc(idev, addr, false);
        if (IS_ERR(rt)) {
                err = PTR_ERR(rt);
                goto out;
        }
 
-       ipv6_addr_copy(&ifa->addr, addr);
+       ifa->addr = *addr;
 
        spin_lock_init(&ifa->lock);
        spin_lock_init(&ifa->state_lock);
@@ -650,16 +650,6 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
 
        ifa->rt = rt;
 
-       /*
-        * part one of RFC 4429, section 3.3
-        * We should not configure an address as
-        * optimistic if we do not yet know the link
-        * layer address of our nexhop router
-        */
-
-       if (dst_get_neighbour_raw(&rt->dst) == NULL)
-               ifa->flags &= ~IFA_F_OPTIMISTIC;
-
        ifa->idev = idev;
        in6_dev_hold(idev);
        /* For caller */
@@ -807,7 +797,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
                                ip6_del_rt(rt);
                                rt = NULL;
                        } else if (!(rt->rt6i_flags & RTF_EXPIRES)) {
-                               rt->rt6i_expires = expires;
+                               rt->dst.expires = expires;
                                rt->rt6i_flags |= RTF_EXPIRES;
                        }
                }
@@ -1228,7 +1218,7 @@ try_nextdev:
        if (!hiscore->ifa)
                return -EADDRNOTAVAIL;
 
-       ipv6_addr_copy(saddr, &hiscore->ifa->addr);
+       *saddr = hiscore->ifa->addr;
        in6_ifa_put(hiscore->ifa);
        return 0;
 }
@@ -1249,7 +1239,7 @@ int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr,
                list_for_each_entry(ifp, &idev->addr_list, if_list) {
                        if (ifp->scope == IFA_LINK &&
                            !(ifp->flags & banned_flags)) {
-                               ipv6_addr_copy(addr, &ifp->addr);
+                               *addr = ifp->addr;
                                err = 0;
                                break;
                        }
@@ -1700,7 +1690,7 @@ addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev,
                .fc_protocol = RTPROT_KERNEL,
        };
 
-       ipv6_addr_copy(&cfg.fc_dst, pfx);
+       cfg.fc_dst = *pfx;
 
        /* Prevent useless cloning on PtP SIT.
           This thing is done here expecting that the whole
@@ -1733,7 +1723,7 @@ static struct rt6_info *addrconf_get_prefix_route(const struct in6_addr *pfx,
        if (!fn)
                goto out;
        for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
-               if (rt->rt6i_dev->ifindex != dev->ifindex)
+               if (rt->dst.dev->ifindex != dev->ifindex)
                        continue;
                if ((rt->rt6i_flags & flags) != flags)
                        continue;
@@ -1805,14 +1795,15 @@ static struct inet6_dev *addrconf_add_dev(struct net_device *dev)
                return ERR_PTR(-EACCES);
 
        /* Add default multicast route */
-       addrconf_add_mroute(dev);
+       if (!(dev->flags & IFF_LOOPBACK))
+               addrconf_add_mroute(dev);
 
        /* Add link local route */
        addrconf_add_lroute(dev);
        return idev;
 }
 
-void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
+void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)
 {
        struct prefix_info *pinfo;
        __u32 valid_lft;
@@ -1890,11 +1881,11 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
                                rt = NULL;
                        } else if (addrconf_finite_timeout(rt_expires)) {
                                /* not infinity */
-                               rt->rt6i_expires = jiffies + rt_expires;
+                               rt->dst.expires = jiffies + rt_expires;
                                rt->rt6i_flags |= RTF_EXPIRES;
                        } else {
                                rt->rt6i_flags &= ~RTF_EXPIRES;
-                               rt->rt6i_expires = 0;
+                               rt->dst.expires = 0;
                        }
                } else if (valid_lft) {
                        clock_t expires = 0;
@@ -1943,7 +1934,7 @@ ok:
 
 #ifdef CONFIG_IPV6_OPTIMISTIC_DAD
                        if (in6_dev->cnf.optimistic_dad &&
-                           !net->ipv6.devconf_all->forwarding)
+                           !net->ipv6.devconf_all->forwarding && sllao)
                                addr_flags = IFA_F_OPTIMISTIC;
 #endif
 
@@ -3077,20 +3068,39 @@ static void addrconf_dad_run(struct inet6_dev *idev)
 struct if6_iter_state {
        struct seq_net_private p;
        int bucket;
+       int offset;
 };
 
-static struct inet6_ifaddr *if6_get_first(struct seq_file *seq)
+static struct inet6_ifaddr *if6_get_first(struct seq_file *seq, loff_t pos)
 {
        struct inet6_ifaddr *ifa = NULL;
        struct if6_iter_state *state = seq->private;
        struct net *net = seq_file_net(seq);
+       int p = 0;
+
+       /* initial bucket if pos is 0 */
+       if (pos == 0) {
+               state->bucket = 0;
+               state->offset = 0;
+       }
 
-       for (state->bucket = 0; state->bucket < IN6_ADDR_HSIZE; ++state->bucket) {
+       for (; state->bucket < IN6_ADDR_HSIZE; ++state->bucket) {
                struct hlist_node *n;
                hlist_for_each_entry_rcu_bh(ifa, n, &inet6_addr_lst[state->bucket],
-                                        addr_lst)
+                                        addr_lst) {
+                       /* sync with offset */
+                       if (p < state->offset) {
+                               p++;
+                               continue;
+                       }
+                       state->offset++;
                        if (net_eq(dev_net(ifa->idev->dev), net))
                                return ifa;
+               }
+
+               /* prepare for next bucket */
+               state->offset = 0;
+               p = 0;
        }
        return NULL;
 }
@@ -3102,13 +3112,17 @@ static struct inet6_ifaddr *if6_get_next(struct seq_file *seq,
        struct net *net = seq_file_net(seq);
        struct hlist_node *n = &ifa->addr_lst;
 
-       hlist_for_each_entry_continue_rcu_bh(ifa, n, addr_lst)
+       hlist_for_each_entry_continue_rcu_bh(ifa, n, addr_lst) {
+               state->offset++;
                if (net_eq(dev_net(ifa->idev->dev), net))
                        return ifa;
+       }
 
        while (++state->bucket < IN6_ADDR_HSIZE) {
+               state->offset = 0;
                hlist_for_each_entry_rcu_bh(ifa, n,
                                     &inet6_addr_lst[state->bucket], addr_lst) {
+                       state->offset++;
                        if (net_eq(dev_net(ifa->idev->dev), net))
                                return ifa;
                }
@@ -3117,21 +3131,11 @@ static struct inet6_ifaddr *if6_get_next(struct seq_file *seq,
        return NULL;
 }
 
-static struct inet6_ifaddr *if6_get_idx(struct seq_file *seq, loff_t pos)
-{
-       struct inet6_ifaddr *ifa = if6_get_first(seq);
-
-       if (ifa)
-               while (pos && (ifa = if6_get_next(seq, ifa)) != NULL)
-                       --pos;
-       return pos ? NULL : ifa;
-}
-
 static void *if6_seq_start(struct seq_file *seq, loff_t *pos)
        __acquires(rcu_bh)
 {
        rcu_read_lock_bh();
-       return if6_get_idx(seq, *pos);
+       return if6_get_first(seq, *pos);
 }
 
 static void *if6_seq_next(struct seq_file *seq, void *v, loff_t *pos)