|
1 | 1 | /*
|
2 | 2 | * drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
|
3 |
| - * Copyright (c) 2016 Mellanox Technologies. All rights reserved. |
| 3 | + * Copyright (c) 2016-2017 Mellanox Technologies. All rights reserved. |
4 | 4 | * Copyright (c) 2016 Jiri Pirko <[email protected]>
|
5 | 5 | * Copyright (c) 2016 Ido Schimmel <[email protected]>
|
6 | 6 | * Copyright (c) 2016 Yotam Gigi <[email protected]>
|
| 7 | + * Copyright (c) 2017 Petr Machata <[email protected]> |
7 | 8 | *
|
8 | 9 | * Redistribution and use in source and binary forms, with or without
|
9 | 10 | * modification, are permitted provided that the following conditions are met:
|
|
51 | 52 | #include <net/ip_fib.h>
|
52 | 53 | #include <net/ip6_fib.h>
|
53 | 54 | #include <net/fib_rules.h>
|
| 55 | +#include <net/ip_tunnels.h> |
54 | 56 | #include <net/l3mdev.h>
|
55 | 57 | #include <net/addrconf.h>
|
56 | 58 | #include <net/ndisc.h>
|
@@ -131,6 +133,17 @@ struct mlxsw_sp_rif_subport {
|
131 | 133 | bool lag;
|
132 | 134 | };
|
133 | 135 |
|
| 136 | +struct mlxsw_sp_rif_ipip_lb { |
| 137 | + struct mlxsw_sp_rif common; |
| 138 | + struct mlxsw_sp_rif_ipip_lb_config lb_config; |
| 139 | + u16 ul_vr_id; /* Reserved for Spectrum-2. */ |
| 140 | +}; |
| 141 | + |
| 142 | +struct mlxsw_sp_rif_params_ipip_lb { |
| 143 | + struct mlxsw_sp_rif_params common; |
| 144 | + struct mlxsw_sp_rif_ipip_lb_config lb_config; |
| 145 | +}; |
| 146 | + |
134 | 147 | struct mlxsw_sp_rif_ops {
|
135 | 148 | enum mlxsw_sp_rif_type type;
|
136 | 149 | size_t rif_size;
|
@@ -883,6 +896,25 @@ static void mlxsw_sp_vrs_fini(struct mlxsw_sp *mlxsw_sp)
|
883 | 896 | kfree(mlxsw_sp->router->vrs);
|
884 | 897 | }
|
885 | 898 |
|
| 899 | +static struct net_device * |
| 900 | +__mlxsw_sp_ipip_netdev_ul_dev_get(const struct net_device *ol_dev) |
| 901 | +{ |
| 902 | + struct ip_tunnel *tun = netdev_priv(ol_dev); |
| 903 | + struct net *net = dev_net(ol_dev); |
| 904 | + |
| 905 | + return __dev_get_by_index(net, tun->parms.link); |
| 906 | +} |
| 907 | + |
| 908 | +static u32 mlxsw_sp_ipip_dev_ul_tb_id(const struct net_device *ol_dev) |
| 909 | +{ |
| 910 | + struct net_device *d = __mlxsw_sp_ipip_netdev_ul_dev_get(ol_dev); |
| 911 | + |
| 912 | + if (d) |
| 913 | + return l3mdev_fib_table(d) ? : RT_TABLE_MAIN; |
| 914 | + else |
| 915 | + return l3mdev_fib_table(ol_dev) ? : RT_TABLE_MAIN; |
| 916 | +} |
| 917 | + |
886 | 918 | struct mlxsw_sp_neigh_key {
|
887 | 919 | struct neighbour *n;
|
888 | 920 | };
|
@@ -2236,6 +2268,25 @@ static void mlxsw_sp_nexthop_neigh_fini(struct mlxsw_sp *mlxsw_sp,
|
2236 | 2268 | neigh_release(n);
|
2237 | 2269 | }
|
2238 | 2270 |
|
| 2271 | +static bool mlxsw_sp_netdev_ipip_type(const struct mlxsw_sp *mlxsw_sp, |
| 2272 | + const struct net_device *dev, |
| 2273 | + enum mlxsw_sp_ipip_type *p_type) |
| 2274 | +{ |
| 2275 | + struct mlxsw_sp_router *router = mlxsw_sp->router; |
| 2276 | + const struct mlxsw_sp_ipip_ops *ipip_ops; |
| 2277 | + enum mlxsw_sp_ipip_type ipipt; |
| 2278 | + |
| 2279 | + for (ipipt = 0; ipipt < MLXSW_SP_IPIP_TYPE_MAX; ++ipipt) { |
| 2280 | + ipip_ops = router->ipip_ops_arr[ipipt]; |
| 2281 | + if (dev->type == ipip_ops->dev_type) { |
| 2282 | + if (p_type) |
| 2283 | + *p_type = ipipt; |
| 2284 | + return true; |
| 2285 | + } |
| 2286 | + } |
| 2287 | + return false; |
| 2288 | +} |
| 2289 | + |
2239 | 2290 | static int mlxsw_sp_nexthop4_init(struct mlxsw_sp *mlxsw_sp,
|
2240 | 2291 | struct mlxsw_sp_nexthop_group *nh_grp,
|
2241 | 2292 | struct mlxsw_sp_nexthop *nh,
|
@@ -4374,7 +4425,10 @@ mlxsw_sp_dev_rif_type(const struct mlxsw_sp *mlxsw_sp,
|
4374 | 4425 | {
|
4375 | 4426 | enum mlxsw_sp_fid_type type;
|
4376 | 4427 |
|
4377 |
| - /* RIF type is derived from the type of the underlying FID */ |
| 4428 | + if (mlxsw_sp_netdev_ipip_type(mlxsw_sp, dev, NULL)) |
| 4429 | + return MLXSW_SP_RIF_TYPE_IPIP_LB; |
| 4430 | + |
| 4431 | + /* Otherwise RIF type is derived from the type of the underlying FID. */ |
4378 | 4432 | if (is_vlan_dev(dev) && netif_is_bridge_master(vlan_dev_real_dev(dev)))
|
4379 | 4433 | type = MLXSW_SP_FID_TYPE_8021Q;
|
4380 | 4434 | else if (netif_is_bridge_master(dev) && br_vlan_enabled(dev))
|
@@ -5164,10 +5218,104 @@ static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_fid_ops = {
|
5164 | 5218 | .fid_get = mlxsw_sp_rif_fid_fid_get,
|
5165 | 5219 | };
|
5166 | 5220 |
|
| 5221 | +static struct mlxsw_sp_rif_ipip_lb * |
| 5222 | +mlxsw_sp_rif_ipip_lb_rif(struct mlxsw_sp_rif *rif) |
| 5223 | +{ |
| 5224 | + return container_of(rif, struct mlxsw_sp_rif_ipip_lb, common); |
| 5225 | +} |
| 5226 | + |
| 5227 | +static void |
| 5228 | +mlxsw_sp_rif_ipip_lb_setup(struct mlxsw_sp_rif *rif, |
| 5229 | + const struct mlxsw_sp_rif_params *params) |
| 5230 | +{ |
| 5231 | + struct mlxsw_sp_rif_params_ipip_lb *params_lb; |
| 5232 | + struct mlxsw_sp_rif_ipip_lb *rif_lb; |
| 5233 | + |
| 5234 | + params_lb = container_of(params, struct mlxsw_sp_rif_params_ipip_lb, |
| 5235 | + common); |
| 5236 | + rif_lb = mlxsw_sp_rif_ipip_lb_rif(rif); |
| 5237 | + rif_lb->lb_config = params_lb->lb_config; |
| 5238 | +} |
| 5239 | + |
| 5240 | +static int |
| 5241 | +mlxsw_sp_rif_ipip_lb_op(struct mlxsw_sp_rif_ipip_lb *lb_rif, |
| 5242 | + struct mlxsw_sp_vr *ul_vr, bool enable) |
| 5243 | +{ |
| 5244 | + struct mlxsw_sp_rif_ipip_lb_config lb_cf = lb_rif->lb_config; |
| 5245 | + struct mlxsw_sp_rif *rif = &lb_rif->common; |
| 5246 | + struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp; |
| 5247 | + char ritr_pl[MLXSW_REG_RITR_LEN]; |
| 5248 | + u32 saddr4; |
| 5249 | + |
| 5250 | + switch (lb_cf.ul_protocol) { |
| 5251 | + case MLXSW_SP_L3_PROTO_IPV4: |
| 5252 | + saddr4 = be32_to_cpu(lb_cf.saddr.addr4); |
| 5253 | + mlxsw_reg_ritr_pack(ritr_pl, enable, MLXSW_REG_RITR_LOOPBACK_IF, |
| 5254 | + rif->rif_index, rif->vr_id, rif->dev->mtu); |
| 5255 | + mlxsw_reg_ritr_loopback_ipip4_pack(ritr_pl, lb_cf.lb_ipipt, |
| 5256 | + MLXSW_REG_RITR_LOOPBACK_IPIP_OPTIONS_GRE_KEY_PRESET, |
| 5257 | + ul_vr->id, saddr4, lb_cf.okey); |
| 5258 | + break; |
| 5259 | + |
| 5260 | + case MLXSW_SP_L3_PROTO_IPV6: |
| 5261 | + return -EAFNOSUPPORT; |
| 5262 | + } |
| 5263 | + |
| 5264 | + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl); |
| 5265 | +} |
| 5266 | + |
| 5267 | +static int |
| 5268 | +mlxsw_sp_rif_ipip_lb_configure(struct mlxsw_sp_rif *rif) |
| 5269 | +{ |
| 5270 | + struct mlxsw_sp_rif_ipip_lb *lb_rif = mlxsw_sp_rif_ipip_lb_rif(rif); |
| 5271 | + u32 ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(rif->dev); |
| 5272 | + struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp; |
| 5273 | + struct mlxsw_sp_vr *ul_vr; |
| 5274 | + int err; |
| 5275 | + |
| 5276 | + ul_vr = mlxsw_sp_vr_get(mlxsw_sp, ul_tb_id); |
| 5277 | + if (IS_ERR(ul_vr)) |
| 5278 | + return PTR_ERR(ul_vr); |
| 5279 | + |
| 5280 | + err = mlxsw_sp_rif_ipip_lb_op(lb_rif, ul_vr, true); |
| 5281 | + if (err) |
| 5282 | + goto err_loopback_op; |
| 5283 | + |
| 5284 | + lb_rif->ul_vr_id = ul_vr->id; |
| 5285 | + ++ul_vr->rif_count; |
| 5286 | + return 0; |
| 5287 | + |
| 5288 | +err_loopback_op: |
| 5289 | + mlxsw_sp_vr_put(ul_vr); |
| 5290 | + return err; |
| 5291 | +} |
| 5292 | + |
| 5293 | +static void mlxsw_sp_rif_ipip_lb_deconfigure(struct mlxsw_sp_rif *rif) |
| 5294 | +{ |
| 5295 | + struct mlxsw_sp_rif_ipip_lb *lb_rif = mlxsw_sp_rif_ipip_lb_rif(rif); |
| 5296 | + struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp; |
| 5297 | + struct mlxsw_sp_vr *ul_vr; |
| 5298 | + |
| 5299 | + ul_vr = &mlxsw_sp->router->vrs[lb_rif->ul_vr_id]; |
| 5300 | + mlxsw_sp_rif_ipip_lb_op(lb_rif, ul_vr, false); |
| 5301 | + |
| 5302 | + --ul_vr->rif_count; |
| 5303 | + mlxsw_sp_vr_put(ul_vr); |
| 5304 | +} |
| 5305 | + |
| 5306 | +static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_ipip_lb_ops = { |
| 5307 | + .type = MLXSW_SP_RIF_TYPE_IPIP_LB, |
| 5308 | + .rif_size = sizeof(struct mlxsw_sp_rif_ipip_lb), |
| 5309 | + .setup = mlxsw_sp_rif_ipip_lb_setup, |
| 5310 | + .configure = mlxsw_sp_rif_ipip_lb_configure, |
| 5311 | + .deconfigure = mlxsw_sp_rif_ipip_lb_deconfigure, |
| 5312 | +}; |
| 5313 | + |
5167 | 5314 | static const struct mlxsw_sp_rif_ops *mlxsw_sp_rif_ops_arr[] = {
|
5168 | 5315 | [MLXSW_SP_RIF_TYPE_SUBPORT] = &mlxsw_sp_rif_subport_ops,
|
5169 | 5316 | [MLXSW_SP_RIF_TYPE_VLAN] = &mlxsw_sp_rif_vlan_ops,
|
5170 | 5317 | [MLXSW_SP_RIF_TYPE_FID] = &mlxsw_sp_rif_fid_ops,
|
| 5318 | + [MLXSW_SP_RIF_TYPE_IPIP_LB] = &mlxsw_sp_rif_ipip_lb_ops, |
5171 | 5319 | };
|
5172 | 5320 |
|
5173 | 5321 | static int mlxsw_sp_rifs_init(struct mlxsw_sp *mlxsw_sp)
|
|
0 commit comments