Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ryusuke...
[firefly-linux-kernel-4.4.55.git] / net / ipv4 / fib_semantics.c
index 622ac4c95026150a76d09e7df9a49aadf9e09420..33e2c35b74b770f526045776e355e01114477fd9 100644 (file)
@@ -141,18 +141,8 @@ const struct fib_prop fib_props[RTN_MAX + 1] = {
        },
 };
 
-
 /* Release a nexthop info record */
 
-static void free_fib_info_rcu(struct rcu_head *head)
-{
-       struct fib_info *fi = container_of(head, struct fib_info, rcu);
-
-       if (fi->fib_metrics != (u32 *) dst_default_metrics)
-               kfree(fi->fib_metrics);
-       kfree(fi);
-}
-
 void free_fib_info(struct fib_info *fi)
 {
        if (fi->fib_dead == 0) {
@@ -166,7 +156,7 @@ void free_fib_info(struct fib_info *fi)
        } endfor_nexthops(fi);
        fib_info_cnt--;
        release_net(fi->fib_net);
-       call_rcu(&fi->rcu, free_fib_info_rcu);
+       kfree_rcu(fi, rcu);
 }
 
 void fib_release_info(struct fib_info *fi)
@@ -222,7 +212,7 @@ static inline unsigned int fib_info_hashfn(const struct fib_info *fi)
        unsigned int mask = (fib_info_hash_size - 1);
        unsigned int val = fi->fib_nhs;
 
-       val ^= fi->fib_protocol;
+       val ^= (fi->fib_protocol << 8) | fi->fib_scope;
        val ^= (__force u32)fi->fib_prefsrc;
        val ^= fi->fib_priority;
        for_nexthops(fi) {
@@ -248,10 +238,11 @@ static struct fib_info *fib_find_info(const struct fib_info *nfi)
                if (fi->fib_nhs != nfi->fib_nhs)
                        continue;
                if (nfi->fib_protocol == fi->fib_protocol &&
+                   nfi->fib_scope == fi->fib_scope &&
                    nfi->fib_prefsrc == fi->fib_prefsrc &&
                    nfi->fib_priority == fi->fib_priority &&
                    memcmp(nfi->fib_metrics, fi->fib_metrics,
-                          sizeof(fi->fib_metrics)) == 0 &&
+                          sizeof(u32) * RTAX_MAX) == 0 &&
                    ((nfi->fib_flags ^ fi->fib_flags) & ~RTNH_F_DEAD) == 0 &&
                    (nfi->fib_nhs == 0 || nh_comp(fi, nfi) == 0))
                        return fi;
@@ -328,7 +319,7 @@ void rtmsg_fib(int event, __be32 key, struct fib_alias *fa,
                goto errout;
 
        err = fib_dump_info(skb, info->pid, seq, event, tb_id,
-                           fa->fa_type, fa->fa_scope, key, dst_len,
+                           fa->fa_type, key, dst_len,
                            fa->fa_tos, fa->fa_info, nlm_flags);
        if (err < 0) {
                /* -EMSGSIZE implies BUG in fib_nlmsg_size() */
@@ -695,6 +686,16 @@ static void fib_info_hash_move(struct hlist_head *new_info_hash,
        fib_info_hash_free(old_laddrhash, bytes);
 }
 
+__be32 fib_info_update_nh_saddr(struct net *net, struct fib_nh *nh)
+{
+       nh->nh_saddr = inet_select_addr(nh->nh_dev,
+                                       nh->nh_gw,
+                                       nh->nh_parent->fib_scope);
+       nh->nh_saddr_genid = atomic_read(&net->ipv4.dev_addr_genid);
+
+       return nh->nh_saddr;
+}
+
 struct fib_info *fib_create_info(struct fib_config *cfg)
 {
        int err;
@@ -753,6 +754,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
 
        fi->fib_net = hold_net(net);
        fi->fib_protocol = cfg->fc_protocol;
+       fi->fib_scope = cfg->fc_scope;
        fi->fib_flags = cfg->fc_flags;
        fi->fib_priority = cfg->fc_priority;
        fi->fib_prefsrc = cfg->fc_prefsrc;
@@ -854,10 +856,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
        }
 
        change_nexthops(fi) {
-               nexthop_nh->nh_cfg_scope = cfg->fc_scope;
-               nexthop_nh->nh_saddr = inet_select_addr(nexthop_nh->nh_dev,
-                                                       nexthop_nh->nh_gw,
-                                                       nexthop_nh->nh_cfg_scope);
+               fib_info_update_nh_saddr(net, nexthop_nh);
        } endfor_nexthops(fi)
 
 link_it:
@@ -906,7 +905,7 @@ failure:
 }
 
 int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
-                 u32 tb_id, u8 type, u8 scope, __be32 dst, int dst_len, u8 tos,
+                 u32 tb_id, u8 type, __be32 dst, int dst_len, u8 tos,
                  struct fib_info *fi, unsigned int flags)
 {
        struct nlmsghdr *nlh;
@@ -928,7 +927,7 @@ int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
        NLA_PUT_U32(skb, RTA_TABLE, tb_id);
        rtm->rtm_type = type;
        rtm->rtm_flags = fi->fib_flags;
-       rtm->rtm_scope = scope;
+       rtm->rtm_scope = fi->fib_scope;
        rtm->rtm_protocol = fi->fib_protocol;
 
        if (rtm->rtm_dst_len)
@@ -1084,7 +1083,7 @@ void fib_select_default(struct fib_result *res)
        list_for_each_entry_rcu(fa, fa_head, fa_list) {
                struct fib_info *next_fi = fa->fa_info;
 
-               if (fa->fa_scope != res->scope ||
+               if (next_fi->fib_scope != res->scope ||
                    fa->fa_type != RTN_UNICAST)
                        continue;
 
@@ -1128,24 +1127,6 @@ out:
        return;
 }
 
-void fib_update_nh_saddrs(struct net_device *dev)
-{
-       struct hlist_head *head;
-       struct hlist_node *node;
-       struct fib_nh *nh;
-       unsigned int hash;
-
-       hash = fib_devindex_hashfn(dev->ifindex);
-       head = &fib_info_devhash[hash];
-       hlist_for_each_entry(nh, node, head, nh_hash) {
-               if (nh->nh_dev != dev)
-                       continue;
-               nh->nh_saddr = inet_select_addr(nh->nh_dev,
-                                               nh->nh_gw,
-                                               nh->nh_cfg_scope);
-       }
-}
-
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
 
 /*