]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[linux.git] / drivers / net / ethernet / mellanox / mlxsw / spectrum_router.c
index 902e766a8ed33eabbe0b11075284878ba3fb3ad4..64498c9f55abfc42fcad714984d6b1bd51974f66 100644 (file)
@@ -2371,7 +2371,7 @@ static enum mlxsw_reg_rauht_op mlxsw_sp_rauht_op(bool adding)
                        MLXSW_REG_RAUHT_OP_WRITE_DELETE;
 }
 
-static void
+static int
 mlxsw_sp_router_neigh_entry_op4(struct mlxsw_sp *mlxsw_sp,
                                struct mlxsw_sp_neigh_entry *neigh_entry,
                                enum mlxsw_reg_rauht_op op)
@@ -2385,10 +2385,10 @@ mlxsw_sp_router_neigh_entry_op4(struct mlxsw_sp *mlxsw_sp,
        if (neigh_entry->counter_valid)
                mlxsw_reg_rauht_pack_counter(rauht_pl,
                                             neigh_entry->counter_index);
-       mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rauht), rauht_pl);
+       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rauht), rauht_pl);
 }
 
-static void
+static int
 mlxsw_sp_router_neigh_entry_op6(struct mlxsw_sp *mlxsw_sp,
                                struct mlxsw_sp_neigh_entry *neigh_entry,
                                enum mlxsw_reg_rauht_op op)
@@ -2402,7 +2402,7 @@ mlxsw_sp_router_neigh_entry_op6(struct mlxsw_sp *mlxsw_sp,
        if (neigh_entry->counter_valid)
                mlxsw_reg_rauht_pack_counter(rauht_pl,
                                             neigh_entry->counter_index);
-       mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rauht), rauht_pl);
+       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rauht), rauht_pl);
 }
 
 bool mlxsw_sp_neigh_ipv6_ignore(struct mlxsw_sp_neigh_entry *neigh_entry)
@@ -2424,20 +2424,33 @@ mlxsw_sp_neigh_entry_update(struct mlxsw_sp *mlxsw_sp,
                            struct mlxsw_sp_neigh_entry *neigh_entry,
                            bool adding)
 {
+       enum mlxsw_reg_rauht_op op = mlxsw_sp_rauht_op(adding);
+       int err;
+
        if (!adding && !neigh_entry->connected)
                return;
        neigh_entry->connected = adding;
        if (neigh_entry->key.n->tbl->family == AF_INET) {
-               mlxsw_sp_router_neigh_entry_op4(mlxsw_sp, neigh_entry,
-                                               mlxsw_sp_rauht_op(adding));
+               err = mlxsw_sp_router_neigh_entry_op4(mlxsw_sp, neigh_entry,
+                                                     op);
+               if (err)
+                       return;
        } else if (neigh_entry->key.n->tbl->family == AF_INET6) {
                if (mlxsw_sp_neigh_ipv6_ignore(neigh_entry))
                        return;
-               mlxsw_sp_router_neigh_entry_op6(mlxsw_sp, neigh_entry,
-                                               mlxsw_sp_rauht_op(adding));
+               err = mlxsw_sp_router_neigh_entry_op6(mlxsw_sp, neigh_entry,
+                                                     op);
+               if (err)
+                       return;
        } else {
                WARN_ON_ONCE(1);
+               return;
        }
+
+       if (adding)
+               neigh_entry->key.n->flags |= NTF_OFFLOADED;
+       else
+               neigh_entry->key.n->flags &= ~NTF_OFFLOADED;
 }
 
 void
@@ -2873,12 +2886,13 @@ mlxsw_sp_nexthop6_group_cmp(const struct mlxsw_sp_nexthop_group *nh_grp,
                return false;
 
        list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list) {
+               struct fib6_nh *fib6_nh = &mlxsw_sp_rt6->rt->fib6_nh;
                struct in6_addr *gw;
                int ifindex, weight;
 
-               ifindex = mlxsw_sp_rt6->rt->fib6_nh.nh_dev->ifindex;
-               weight = mlxsw_sp_rt6->rt->fib6_nh.nh_weight;
-               gw = &mlxsw_sp_rt6->rt->fib6_nh.nh_gw;
+               ifindex = fib6_nh->fib_nh_dev->ifindex;
+               weight = fib6_nh->fib_nh_weight;
+               gw = &fib6_nh->fib_nh_gw6;
                if (!mlxsw_sp_nexthop6_group_has_nexthop(nh_grp, gw, ifindex,
                                                         weight))
                        return false;
@@ -2944,7 +2958,7 @@ mlxsw_sp_nexthop6_group_hash(struct mlxsw_sp_fib6_entry *fib6_entry, u32 seed)
        struct net_device *dev;
 
        list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list) {
-               dev = mlxsw_sp_rt6->rt->fib6_nh.nh_dev;
+               dev = mlxsw_sp_rt6->rt->fib6_nh.fib_nh_dev;
                val ^= dev->ifindex;
        }
 
@@ -3610,7 +3624,7 @@ static bool mlxsw_sp_nexthop4_ipip_type(const struct mlxsw_sp *mlxsw_sp,
                                        const struct fib_nh *fib_nh,
                                        enum mlxsw_sp_ipip_type *p_ipipt)
 {
-       struct net_device *dev = fib_nh->nh_dev;
+       struct net_device *dev = fib_nh->fib_nh_dev;
 
        return dev &&
               fib_nh->nh_parent->fib_type == RTN_UNICAST &&
@@ -3637,7 +3651,7 @@ static int mlxsw_sp_nexthop4_type_init(struct mlxsw_sp *mlxsw_sp,
                                       struct fib_nh *fib_nh)
 {
        const struct mlxsw_sp_ipip_ops *ipip_ops;
-       struct net_device *dev = fib_nh->nh_dev;
+       struct net_device *dev = fib_nh->fib_nh_dev;
        struct mlxsw_sp_ipip_entry *ipip_entry;
        struct mlxsw_sp_rif *rif;
        int err;
@@ -3681,18 +3695,18 @@ static int mlxsw_sp_nexthop4_init(struct mlxsw_sp *mlxsw_sp,
                                  struct mlxsw_sp_nexthop *nh,
                                  struct fib_nh *fib_nh)
 {
-       struct net_device *dev = fib_nh->nh_dev;
+       struct net_device *dev = fib_nh->fib_nh_dev;
        struct in_device *in_dev;
        int err;
 
        nh->nh_grp = nh_grp;
        nh->key.fib_nh = fib_nh;
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
-       nh->nh_weight = fib_nh->nh_weight;
+       nh->nh_weight = fib_nh->fib_nh_weight;
 #else
        nh->nh_weight = 1;
 #endif
-       memcpy(&nh->gw_addr, &fib_nh->nh_gw, sizeof(fib_nh->nh_gw));
+       memcpy(&nh->gw_addr, &fib_nh->fib_nh_gw4, sizeof(fib_nh->fib_nh_gw4));
        err = mlxsw_sp_nexthop_insert(mlxsw_sp, nh);
        if (err)
                return err;
@@ -3705,7 +3719,7 @@ static int mlxsw_sp_nexthop4_init(struct mlxsw_sp *mlxsw_sp,
 
        in_dev = __in_dev_get_rtnl(dev);
        if (in_dev && IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN(in_dev) &&
-           fib_nh->nh_flags & RTNH_F_LINKDOWN)
+           fib_nh->fib_nh_flags & RTNH_F_LINKDOWN)
                return 0;
 
        err = mlxsw_sp_nexthop4_type_init(mlxsw_sp, nh, fib_nh);
@@ -3804,7 +3818,7 @@ static void mlxsw_sp_nexthop_rif_gone_sync(struct mlxsw_sp *mlxsw_sp,
 static bool mlxsw_sp_fi_is_gateway(const struct mlxsw_sp *mlxsw_sp,
                                   const struct fib_info *fi)
 {
-       return fi->fib_nh->nh_scope == RT_SCOPE_LINK ||
+       return fi->fib_nh->fib_nh_scope == RT_SCOPE_LINK ||
               mlxsw_sp_nexthop4_ipip_type(mlxsw_sp, fi->fib_nh, NULL);
 }
 
@@ -3946,9 +3960,9 @@ mlxsw_sp_rt6_nexthop(struct mlxsw_sp_nexthop_group *nh_grp,
                struct mlxsw_sp_nexthop *nh = &nh_grp->nexthops[i];
                struct fib6_info *rt = mlxsw_sp_rt6->rt;
 
-               if (nh->rif && nh->rif->dev == rt->fib6_nh.nh_dev &&
+               if (nh->rif && nh->rif->dev == rt->fib6_nh.fib_nh_dev &&
                    ipv6_addr_equal((const struct in6_addr *) &nh->gw_addr,
-                                   &rt->fib6_nh.nh_gw))
+                                   &rt->fib6_nh.fib_nh_gw6))
                        return nh;
                continue;
        }
@@ -3966,7 +3980,7 @@ mlxsw_sp_fib4_entry_offload_set(struct mlxsw_sp_fib_entry *fib_entry)
            fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE ||
            fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP ||
            fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP) {
-               nh_grp->nexthops->key.fib_nh->nh_flags |= RTNH_F_OFFLOAD;
+               nh_grp->nexthops->key.fib_nh->fib_nh_flags |= RTNH_F_OFFLOAD;
                return;
        }
 
@@ -3974,9 +3988,9 @@ mlxsw_sp_fib4_entry_offload_set(struct mlxsw_sp_fib_entry *fib_entry)
                struct mlxsw_sp_nexthop *nh = &nh_grp->nexthops[i];
 
                if (nh->offloaded)
-                       nh->key.fib_nh->nh_flags |= RTNH_F_OFFLOAD;
+                       nh->key.fib_nh->fib_nh_flags |= RTNH_F_OFFLOAD;
                else
-                       nh->key.fib_nh->nh_flags &= ~RTNH_F_OFFLOAD;
+                       nh->key.fib_nh->fib_nh_flags &= ~RTNH_F_OFFLOAD;
        }
 }
 
@@ -3992,7 +4006,7 @@ mlxsw_sp_fib4_entry_offload_unset(struct mlxsw_sp_fib_entry *fib_entry)
        for (i = 0; i < nh_grp->count; i++) {
                struct mlxsw_sp_nexthop *nh = &nh_grp->nexthops[i];
 
-               nh->key.fib_nh->nh_flags &= ~RTNH_F_OFFLOAD;
+               nh->key.fib_nh->fib_nh_flags &= ~RTNH_F_OFFLOAD;
        }
 }
 
@@ -4008,19 +4022,20 @@ mlxsw_sp_fib6_entry_offload_set(struct mlxsw_sp_fib_entry *fib_entry)
        if (fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_LOCAL ||
            fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE) {
                list_first_entry(&fib6_entry->rt6_list, struct mlxsw_sp_rt6,
-                                list)->rt->fib6_nh.nh_flags |= RTNH_F_OFFLOAD;
+                                list)->rt->fib6_nh.fib_nh_flags |= RTNH_F_OFFLOAD;
                return;
        }
 
        list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list) {
                struct mlxsw_sp_nexthop_group *nh_grp = fib_entry->nh_group;
+               struct fib6_nh *fib6_nh = &mlxsw_sp_rt6->rt->fib6_nh;
                struct mlxsw_sp_nexthop *nh;
 
                nh = mlxsw_sp_rt6_nexthop(nh_grp, mlxsw_sp_rt6);
                if (nh && nh->offloaded)
-                       mlxsw_sp_rt6->rt->fib6_nh.nh_flags |= RTNH_F_OFFLOAD;
+                       fib6_nh->fib_nh_flags |= RTNH_F_OFFLOAD;
                else
-                       mlxsw_sp_rt6->rt->fib6_nh.nh_flags &= ~RTNH_F_OFFLOAD;
+                       fib6_nh->fib_nh_flags &= ~RTNH_F_OFFLOAD;
        }
 }
 
@@ -4035,7 +4050,7 @@ mlxsw_sp_fib6_entry_offload_unset(struct mlxsw_sp_fib_entry *fib_entry)
        list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list) {
                struct fib6_info *rt = mlxsw_sp_rt6->rt;
 
-               rt->fib6_nh.nh_flags &= ~RTNH_F_OFFLOAD;
+               rt->fib6_nh.fib_nh_flags &= ~RTNH_F_OFFLOAD;
        }
 }
 
@@ -4913,7 +4928,7 @@ static void mlxsw_sp_rt6_destroy(struct mlxsw_sp_rt6 *mlxsw_sp_rt6)
 static bool mlxsw_sp_fib6_rt_can_mp(const struct fib6_info *rt)
 {
        /* RTF_CACHE routes are ignored */
-       return (rt->fib6_flags & (RTF_GATEWAY | RTF_ADDRCONF)) == RTF_GATEWAY;
+       return !(rt->fib6_flags & RTF_ADDRCONF) && rt->fib6_nh.fib_nh_gw_family;
 }
 
 static struct fib6_info *
@@ -4972,8 +4987,8 @@ static bool mlxsw_sp_nexthop6_ipip_type(const struct mlxsw_sp *mlxsw_sp,
                                        const struct fib6_info *rt,
                                        enum mlxsw_sp_ipip_type *ret)
 {
-       return rt->fib6_nh.nh_dev &&
-              mlxsw_sp_netdev_ipip_type(mlxsw_sp, rt->fib6_nh.nh_dev, ret);
+       return rt->fib6_nh.fib_nh_dev &&
+              mlxsw_sp_netdev_ipip_type(mlxsw_sp, rt->fib6_nh.fib_nh_dev, ret);
 }
 
 static int mlxsw_sp_nexthop6_type_init(struct mlxsw_sp *mlxsw_sp,
@@ -4983,7 +4998,7 @@ static int mlxsw_sp_nexthop6_type_init(struct mlxsw_sp *mlxsw_sp,
 {
        const struct mlxsw_sp_ipip_ops *ipip_ops;
        struct mlxsw_sp_ipip_entry *ipip_entry;
-       struct net_device *dev = rt->fib6_nh.nh_dev;
+       struct net_device *dev = rt->fib6_nh.fib_nh_dev;
        struct mlxsw_sp_rif *rif;
        int err;
 
@@ -5026,11 +5041,11 @@ static int mlxsw_sp_nexthop6_init(struct mlxsw_sp *mlxsw_sp,
                                  struct mlxsw_sp_nexthop *nh,
                                  const struct fib6_info *rt)
 {
-       struct net_device *dev = rt->fib6_nh.nh_dev;
+       struct net_device *dev = rt->fib6_nh.fib_nh_dev;
 
        nh->nh_grp = nh_grp;
-       nh->nh_weight = rt->fib6_nh.nh_weight;
-       memcpy(&nh->gw_addr, &rt->fib6_nh.nh_gw, sizeof(nh->gw_addr));
+       nh->nh_weight = rt->fib6_nh.fib_nh_weight;
+       memcpy(&nh->gw_addr, &rt->fib6_nh.fib_nh_gw6, sizeof(nh->gw_addr));
        mlxsw_sp_nexthop_counter_alloc(mlxsw_sp, nh);
 
        list_add_tail(&nh->router_list_node, &mlxsw_sp->router->nexthop_list);
@@ -5053,7 +5068,7 @@ static void mlxsw_sp_nexthop6_fini(struct mlxsw_sp *mlxsw_sp,
 static bool mlxsw_sp_rt6_is_gateway(const struct mlxsw_sp *mlxsw_sp,
                                    const struct fib6_info *rt)
 {
-       return rt->fib6_flags & RTF_GATEWAY ||
+       return rt->fib6_nh.fib_nh_gw_family ||
               mlxsw_sp_nexthop6_ipip_type(mlxsw_sp, rt, NULL);
 }
 
@@ -6090,6 +6105,14 @@ static int mlxsw_sp_router_fib_event(struct notifier_block *nb,
                        NL_SET_ERR_MSG_MOD(info->extack, "FIB offload was aborted. Not configuring route");
                        return notifier_from_errno(-EINVAL);
                }
+               if (info->family == AF_INET) {
+                       struct fib_entry_notifier_info *fen_info = ptr;
+
+                       if (fen_info->fi->fib_nh_is_v6) {
+                               NL_SET_ERR_MSG_MOD(info->extack, "IPv6 gateway with IPv4 route is not supported");
+                               return notifier_from_errno(-EINVAL);
+                       }
+               }
                break;
        }