mlxsw: spectrum_router: Only clear offload indication from valid IPv6 FIB info
[linux-2.6-microblaze.git] / drivers / net / ethernet / mellanox / mlxsw / spectrum_router.c
index ca9f7d0..645ec70 100644 (file)
@@ -1353,21 +1353,33 @@ mlxsw_sp_ipip_entry_matches_decap(struct mlxsw_sp *mlxsw_sp,
 
 /* Given decap parameters, find the corresponding IPIP entry. */
 static struct mlxsw_sp_ipip_entry *
-mlxsw_sp_ipip_entry_find_by_decap(struct mlxsw_sp *mlxsw_sp,
-                                 const struct net_device *ul_dev,
+mlxsw_sp_ipip_entry_find_by_decap(struct mlxsw_sp *mlxsw_sp, int ul_dev_ifindex,
                                  enum mlxsw_sp_l3proto ul_proto,
                                  union mlxsw_sp_l3addr ul_dip)
 {
-       struct mlxsw_sp_ipip_entry *ipip_entry;
+       struct mlxsw_sp_ipip_entry *ipip_entry = NULL;
+       struct net_device *ul_dev;
+
+       rcu_read_lock();
+
+       ul_dev = dev_get_by_index_rcu(mlxsw_sp_net(mlxsw_sp), ul_dev_ifindex);
+       if (!ul_dev)
+               goto out_unlock;
 
        list_for_each_entry(ipip_entry, &mlxsw_sp->router->ipip_list,
                            ipip_list_node)
                if (mlxsw_sp_ipip_entry_matches_decap(mlxsw_sp, ul_dev,
                                                      ul_proto, ul_dip,
                                                      ipip_entry))
-                       return ipip_entry;
+                       goto out_unlock;
+
+       rcu_read_unlock();
 
        return NULL;
+
+out_unlock:
+       rcu_read_unlock();
+       return ipip_entry;
 }
 
 static bool mlxsw_sp_netdev_ipip_type(const struct mlxsw_sp *mlxsw_sp,
@@ -3971,6 +3983,7 @@ static int mlxsw_sp_nexthop4_init(struct mlxsw_sp *mlxsw_sp,
 
        if (!dev)
                return 0;
+       nh->ifindex = dev->ifindex;
 
        rcu_read_lock();
        in_dev = __in_dev_get_rcu(dev);
@@ -4765,17 +4778,17 @@ mlxsw_sp_fib4_entry_type_set(struct mlxsw_sp *mlxsw_sp,
                             const struct fib_entry_notifier_info *fen_info,
                             struct mlxsw_sp_fib_entry *fib_entry)
 {
-       struct net_device *dev = fib_info_nh(fen_info->fi, 0)->fib_nh_dev;
+       struct mlxsw_sp_nexthop_group_info *nhgi = fib_entry->nh_group->nhgi;
        union mlxsw_sp_l3addr dip = { .addr4 = htonl(fen_info->dst) };
        struct mlxsw_sp_router *router = mlxsw_sp->router;
        u32 tb_id = mlxsw_sp_fix_tb_id(fen_info->tb_id);
+       int ifindex = nhgi->nexthops[0].ifindex;
        struct mlxsw_sp_ipip_entry *ipip_entry;
-       struct fib_info *fi = fen_info->fi;
 
        switch (fen_info->type) {
        case RTN_LOCAL:
-               ipip_entry = mlxsw_sp_ipip_entry_find_by_decap(mlxsw_sp, dev,
-                                                MLXSW_SP_L3_PROTO_IPV4, dip);
+               ipip_entry = mlxsw_sp_ipip_entry_find_by_decap(mlxsw_sp, ifindex,
+                                                              MLXSW_SP_L3_PROTO_IPV4, dip);
                if (ipip_entry && ipip_entry->ol_dev->flags & IFF_UP) {
                        fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP;
                        return mlxsw_sp_fib_entry_decap_init(mlxsw_sp,
@@ -4808,7 +4821,7 @@ mlxsw_sp_fib4_entry_type_set(struct mlxsw_sp *mlxsw_sp,
                fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_UNREACHABLE;
                return 0;
        case RTN_UNICAST:
-               if (mlxsw_sp_fi_is_gateway(mlxsw_sp, fi))
+               if (nhgi->gateway)
                        fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_REMOTE;
                else
                        fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_LOCAL;
@@ -4851,14 +4864,14 @@ mlxsw_sp_fib4_entry_create(struct mlxsw_sp *mlxsw_sp,
                goto err_fib_entry_priv_create;
        }
 
-       err = mlxsw_sp_fib4_entry_type_set(mlxsw_sp, fen_info, fib_entry);
-       if (err)
-               goto err_fib4_entry_type_set;
-
        err = mlxsw_sp_nexthop4_group_get(mlxsw_sp, fib_entry, fen_info->fi);
        if (err)
                goto err_nexthop4_group_get;
 
+       err = mlxsw_sp_fib4_entry_type_set(mlxsw_sp, fen_info, fib_entry);
+       if (err)
+               goto err_fib4_entry_type_set;
+
        fib4_entry->fi = fen_info->fi;
        fib_info_hold(fib4_entry->fi);
        fib4_entry->tb_id = fen_info->tb_id;
@@ -4869,9 +4882,9 @@ mlxsw_sp_fib4_entry_create(struct mlxsw_sp *mlxsw_sp,
 
        return fib4_entry;
 
-err_nexthop4_group_get:
-       mlxsw_sp_fib4_entry_type_unset(mlxsw_sp, fib_entry);
 err_fib4_entry_type_set:
+       mlxsw_sp_nexthop4_group_put(mlxsw_sp, &fib4_entry->common);
+err_nexthop4_group_get:
        mlxsw_sp_fib_entry_priv_put(fib_entry->priv);
 err_fib_entry_priv_create:
        kfree(fib4_entry);
@@ -4882,8 +4895,8 @@ static void mlxsw_sp_fib4_entry_destroy(struct mlxsw_sp *mlxsw_sp,
                                        struct mlxsw_sp_fib4_entry *fib4_entry)
 {
        fib_info_put(fib4_entry->fi);
-       mlxsw_sp_nexthop4_group_put(mlxsw_sp, &fib4_entry->common);
        mlxsw_sp_fib4_entry_type_unset(mlxsw_sp, &fib4_entry->common);
+       mlxsw_sp_nexthop4_group_put(mlxsw_sp, &fib4_entry->common);
        mlxsw_sp_fib_entry_priv_put(fib4_entry->common.priv);
        kfree(fib4_entry);
 }
@@ -5311,7 +5324,8 @@ static void mlxsw_sp_rt6_destroy(struct mlxsw_sp_rt6 *mlxsw_sp_rt6)
 {
        struct fib6_nh *fib6_nh = mlxsw_sp_rt6->rt->fib6_nh;
 
-       fib6_nh->fib_nh_flags &= ~RTNH_F_OFFLOAD;
+       if (!mlxsw_sp_rt6->rt->nh)
+               fib6_nh->fib_nh_flags &= ~RTNH_F_OFFLOAD;
        mlxsw_sp_rt6_release(mlxsw_sp_rt6->rt);
        kfree(mlxsw_sp_rt6);
 }
@@ -5423,7 +5437,7 @@ err_nexthop6_init:
                nh = &nhgi->nexthops[i];
                mlxsw_sp_nexthop6_fini(mlxsw_sp, nh);
        }
-       kfree(nh_grp);
+       kfree(nhgi);
        return err;
 }
 
@@ -5495,15 +5509,15 @@ static int mlxsw_sp_nexthop6_group_get(struct mlxsw_sp *mlxsw_sp,
                        return PTR_ERR(nh_grp);
        }
 
-       list_add_tail(&fib6_entry->common.nexthop_group_node,
-                     &nh_grp->fib_list);
-       fib6_entry->common.nh_group = nh_grp;
-
        /* The route and the nexthop are described by the same struct, so we
         * need to the update the nexthop offload indication for the new route.
         */
        __mlxsw_sp_nexthop6_group_offload_refresh(nh_grp, fib6_entry);
 
+       list_add_tail(&fib6_entry->common.nexthop_group_node,
+                     &nh_grp->fib_list);
+       fib6_entry->common.nh_group = nh_grp;
+
        return 0;
 }
 
@@ -5621,19 +5635,13 @@ static void mlxsw_sp_fib6_entry_type_set(struct mlxsw_sp *mlxsw_sp,
                                         struct mlxsw_sp_fib_entry *fib_entry,
                                         const struct fib6_info *rt)
 {
-       /* Packets hitting RTF_REJECT routes need to be discarded by the
-        * stack. We can rely on their destination device not having a
-        * RIF (it's the loopback device) and can thus use action type
-        * local, which will cause them to be trapped with a lower
-        * priority than packets that need to be locally received.
-        */
        if (rt->fib6_flags & (RTF_LOCAL | RTF_ANYCAST))
                fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP;
        else if (rt->fib6_type == RTN_BLACKHOLE)
                fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE;
        else if (rt->fib6_flags & RTF_REJECT)
                fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_UNREACHABLE;
-       else if (mlxsw_sp_rt6_is_gateway(mlxsw_sp, rt))
+       else if (fib_entry->nh_group->nhgi->gateway)
                fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_REMOTE;
        else
                fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_LOCAL;
@@ -5685,12 +5693,12 @@ mlxsw_sp_fib6_entry_create(struct mlxsw_sp *mlxsw_sp,
                fib6_entry->nrt6++;
        }
 
-       mlxsw_sp_fib6_entry_type_set(mlxsw_sp, fib_entry, rt_arr[0]);
-
        err = mlxsw_sp_nexthop6_group_get(mlxsw_sp, fib6_entry);
        if (err)
                goto err_nexthop6_group_get;
 
+       mlxsw_sp_fib6_entry_type_set(mlxsw_sp, fib_entry, rt_arr[0]);
+
        fib_entry->fib_node = fib_node;
 
        return fib6_entry;