.. | .. |
---|
13 | 13 | #include <linux/socket.h> |
---|
14 | 14 | #include <linux/route.h> |
---|
15 | 15 | #include <linux/gcd.h> |
---|
16 | | -#include <linux/random.h> |
---|
17 | 16 | #include <linux/if_macvlan.h> |
---|
| 17 | +#include <linux/refcount.h> |
---|
| 18 | +#include <linux/jhash.h> |
---|
| 19 | +#include <linux/net_namespace.h> |
---|
| 20 | +#include <linux/mutex.h> |
---|
18 | 21 | #include <net/netevent.h> |
---|
19 | 22 | #include <net/neighbour.h> |
---|
20 | 23 | #include <net/arp.h> |
---|
21 | 24 | #include <net/ip_fib.h> |
---|
22 | 25 | #include <net/ip6_fib.h> |
---|
| 26 | +#include <net/nexthop.h> |
---|
23 | 27 | #include <net/fib_rules.h> |
---|
24 | 28 | #include <net/ip_tunnels.h> |
---|
25 | 29 | #include <net/l3mdev.h> |
---|
.. | .. |
---|
45 | 49 | struct mlxsw_sp_lpm_tree; |
---|
46 | 50 | struct mlxsw_sp_rif_ops; |
---|
47 | 51 | |
---|
48 | | -struct mlxsw_sp_router { |
---|
49 | | - struct mlxsw_sp *mlxsw_sp; |
---|
50 | | - struct mlxsw_sp_rif **rifs; |
---|
51 | | - struct mlxsw_sp_vr *vrs; |
---|
52 | | - struct rhashtable neigh_ht; |
---|
53 | | - struct rhashtable nexthop_group_ht; |
---|
54 | | - struct rhashtable nexthop_ht; |
---|
55 | | - struct list_head nexthop_list; |
---|
56 | | - struct { |
---|
57 | | - /* One tree for each protocol: IPv4 and IPv6 */ |
---|
58 | | - struct mlxsw_sp_lpm_tree *proto_trees[2]; |
---|
59 | | - struct mlxsw_sp_lpm_tree *trees; |
---|
60 | | - unsigned int tree_count; |
---|
61 | | - } lpm; |
---|
62 | | - struct { |
---|
63 | | - struct delayed_work dw; |
---|
64 | | - unsigned long interval; /* ms */ |
---|
65 | | - } neighs_update; |
---|
66 | | - struct delayed_work nexthop_probe_dw; |
---|
67 | | -#define MLXSW_SP_UNRESOLVED_NH_PROBE_INTERVAL 5000 /* ms */ |
---|
68 | | - struct list_head nexthop_neighs_list; |
---|
69 | | - struct list_head ipip_list; |
---|
70 | | - bool aborted; |
---|
71 | | - struct notifier_block fib_nb; |
---|
72 | | - struct notifier_block netevent_nb; |
---|
73 | | - const struct mlxsw_sp_rif_ops **rif_ops_arr; |
---|
74 | | - const struct mlxsw_sp_ipip_ops **ipip_ops_arr; |
---|
75 | | -}; |
---|
76 | | - |
---|
77 | 52 | struct mlxsw_sp_rif { |
---|
78 | 53 | struct list_head nexthop_list; |
---|
79 | 54 | struct list_head neigh_list; |
---|
80 | | - struct net_device *dev; |
---|
| 55 | + struct net_device *dev; /* NULL for underlay RIF */ |
---|
81 | 56 | struct mlxsw_sp_fid *fid; |
---|
82 | 57 | unsigned char addr[ETH_ALEN]; |
---|
83 | 58 | int mtu; |
---|
.. | .. |
---|
104 | 79 | |
---|
105 | 80 | struct mlxsw_sp_rif_subport { |
---|
106 | 81 | struct mlxsw_sp_rif common; |
---|
| 82 | + refcount_t ref_count; |
---|
107 | 83 | union { |
---|
108 | 84 | u16 system_port; |
---|
109 | 85 | u16 lag_id; |
---|
.. | .. |
---|
116 | 92 | struct mlxsw_sp_rif common; |
---|
117 | 93 | struct mlxsw_sp_rif_ipip_lb_config lb_config; |
---|
118 | 94 | u16 ul_vr_id; /* Reserved for Spectrum-2. */ |
---|
| 95 | + u16 ul_rif_id; /* Reserved for Spectrum. */ |
---|
119 | 96 | }; |
---|
120 | 97 | |
---|
121 | 98 | struct mlxsw_sp_rif_params_ipip_lb { |
---|
.. | .. |
---|
136 | 113 | void (*fdb_del)(struct mlxsw_sp_rif *rif, const char *mac); |
---|
137 | 114 | }; |
---|
138 | 115 | |
---|
| 116 | +static struct mlxsw_sp_rif * |
---|
| 117 | +mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp *mlxsw_sp, |
---|
| 118 | + const struct net_device *dev); |
---|
| 119 | +static void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif); |
---|
139 | 120 | static void mlxsw_sp_lpm_tree_hold(struct mlxsw_sp_lpm_tree *lpm_tree); |
---|
140 | 121 | static void mlxsw_sp_lpm_tree_put(struct mlxsw_sp *mlxsw_sp, |
---|
141 | 122 | struct mlxsw_sp_lpm_tree *lpm_tree); |
---|
.. | .. |
---|
358 | 339 | MLXSW_SP_FIB_ENTRY_TYPE_REMOTE, |
---|
359 | 340 | MLXSW_SP_FIB_ENTRY_TYPE_LOCAL, |
---|
360 | 341 | MLXSW_SP_FIB_ENTRY_TYPE_TRAP, |
---|
| 342 | + MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE, |
---|
| 343 | + MLXSW_SP_FIB_ENTRY_TYPE_UNREACHABLE, |
---|
361 | 344 | |
---|
362 | 345 | /* This is a special case of local delivery, where a packet should be |
---|
363 | 346 | * decapsulated on reception. Note that there is no corresponding ENCAP, |
---|
.. | .. |
---|
366 | 349 | * encapsulating entries.) |
---|
367 | 350 | */ |
---|
368 | 351 | MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP, |
---|
| 352 | + MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP, |
---|
369 | 353 | }; |
---|
370 | 354 | |
---|
371 | 355 | struct mlxsw_sp_nexthop_group; |
---|
| 356 | +struct mlxsw_sp_fib_entry; |
---|
372 | 357 | |
---|
373 | 358 | struct mlxsw_sp_fib_node { |
---|
374 | | - struct list_head entry_list; |
---|
| 359 | + struct mlxsw_sp_fib_entry *fib_entry; |
---|
375 | 360 | struct list_head list; |
---|
376 | 361 | struct rhash_head ht_node; |
---|
377 | 362 | struct mlxsw_sp_fib *fib; |
---|
.. | .. |
---|
384 | 369 | }; |
---|
385 | 370 | |
---|
386 | 371 | struct mlxsw_sp_fib_entry { |
---|
387 | | - struct list_head list; |
---|
388 | 372 | struct mlxsw_sp_fib_node *fib_node; |
---|
389 | 373 | enum mlxsw_sp_fib_entry_type type; |
---|
390 | 374 | struct list_head nexthop_group_node; |
---|
.. | .. |
---|
434 | 418 | struct mlxsw_sp_fib *fib4; |
---|
435 | 419 | struct mlxsw_sp_fib *fib6; |
---|
436 | 420 | struct mlxsw_sp_mr_table *mr_table[MLXSW_SP_L3_PROTO_MAX]; |
---|
| 421 | + struct mlxsw_sp_rif *ul_rif; |
---|
| 422 | + refcount_t ul_rif_refcnt; |
---|
437 | 423 | }; |
---|
438 | 424 | |
---|
439 | 425 | static const struct rhashtable_params mlxsw_sp_fib_ht_params; |
---|
.. | .. |
---|
741 | 727 | return NULL; |
---|
742 | 728 | } |
---|
743 | 729 | |
---|
| 730 | +int mlxsw_sp_router_tb_id_vr_id(struct mlxsw_sp *mlxsw_sp, u32 tb_id, |
---|
| 731 | + u16 *vr_id) |
---|
| 732 | +{ |
---|
| 733 | + struct mlxsw_sp_vr *vr; |
---|
| 734 | + int err = 0; |
---|
| 735 | + |
---|
| 736 | + mutex_lock(&mlxsw_sp->router->lock); |
---|
| 737 | + vr = mlxsw_sp_vr_find(mlxsw_sp, tb_id); |
---|
| 738 | + if (!vr) { |
---|
| 739 | + err = -ESRCH; |
---|
| 740 | + goto out; |
---|
| 741 | + } |
---|
| 742 | + *vr_id = vr->id; |
---|
| 743 | +out: |
---|
| 744 | + mutex_unlock(&mlxsw_sp->router->lock); |
---|
| 745 | + return err; |
---|
| 746 | +} |
---|
| 747 | + |
---|
744 | 748 | static struct mlxsw_sp_fib *mlxsw_sp_vr_fib(const struct mlxsw_sp_vr *vr, |
---|
745 | 749 | enum mlxsw_sp_l3proto proto) |
---|
746 | 750 | { |
---|
.. | .. |
---|
960 | 964 | struct ip_tunnel *tun = netdev_priv(ol_dev); |
---|
961 | 965 | struct net *net = dev_net(ol_dev); |
---|
962 | 966 | |
---|
963 | | - return __dev_get_by_index(net, tun->parms.link); |
---|
| 967 | + return dev_get_by_index_rcu(net, tun->parms.link); |
---|
964 | 968 | } |
---|
965 | 969 | |
---|
966 | 970 | u32 mlxsw_sp_ipip_dev_ul_tb_id(const struct net_device *ol_dev) |
---|
967 | 971 | { |
---|
968 | | - struct net_device *d = __mlxsw_sp_ipip_netdev_ul_dev_get(ol_dev); |
---|
| 972 | + struct net_device *d; |
---|
| 973 | + u32 tb_id; |
---|
969 | 974 | |
---|
| 975 | + rcu_read_lock(); |
---|
| 976 | + d = __mlxsw_sp_ipip_netdev_ul_dev_get(ol_dev); |
---|
970 | 977 | if (d) |
---|
971 | | - return l3mdev_fib_table(d) ? : RT_TABLE_MAIN; |
---|
| 978 | + tb_id = l3mdev_fib_table(d) ? : RT_TABLE_MAIN; |
---|
972 | 979 | else |
---|
973 | | - return RT_TABLE_MAIN; |
---|
| 980 | + tb_id = RT_TABLE_MAIN; |
---|
| 981 | + rcu_read_unlock(); |
---|
| 982 | + |
---|
| 983 | + return tb_id; |
---|
974 | 984 | } |
---|
975 | 985 | |
---|
976 | 986 | static struct mlxsw_sp_rif * |
---|
.. | .. |
---|
1128 | 1138 | mlxsw_sp_ipip_entry_demote_decap(mlxsw_sp, ipip_entry); |
---|
1129 | 1139 | } |
---|
1130 | 1140 | |
---|
| 1141 | +static struct mlxsw_sp_fib_entry * |
---|
| 1142 | +mlxsw_sp_router_ip2me_fib_entry_find(struct mlxsw_sp *mlxsw_sp, u32 tb_id, |
---|
| 1143 | + enum mlxsw_sp_l3proto proto, |
---|
| 1144 | + const union mlxsw_sp_l3addr *addr, |
---|
| 1145 | + enum mlxsw_sp_fib_entry_type type) |
---|
| 1146 | +{ |
---|
| 1147 | + struct mlxsw_sp_fib_node *fib_node; |
---|
| 1148 | + unsigned char addr_prefix_len; |
---|
| 1149 | + struct mlxsw_sp_fib *fib; |
---|
| 1150 | + struct mlxsw_sp_vr *vr; |
---|
| 1151 | + const void *addrp; |
---|
| 1152 | + size_t addr_len; |
---|
| 1153 | + u32 addr4; |
---|
| 1154 | + |
---|
| 1155 | + vr = mlxsw_sp_vr_find(mlxsw_sp, tb_id); |
---|
| 1156 | + if (!vr) |
---|
| 1157 | + return NULL; |
---|
| 1158 | + fib = mlxsw_sp_vr_fib(vr, proto); |
---|
| 1159 | + |
---|
| 1160 | + switch (proto) { |
---|
| 1161 | + case MLXSW_SP_L3_PROTO_IPV4: |
---|
| 1162 | + addr4 = be32_to_cpu(addr->addr4); |
---|
| 1163 | + addrp = &addr4; |
---|
| 1164 | + addr_len = 4; |
---|
| 1165 | + addr_prefix_len = 32; |
---|
| 1166 | + break; |
---|
| 1167 | + case MLXSW_SP_L3_PROTO_IPV6: |
---|
| 1168 | + default: |
---|
| 1169 | + WARN_ON(1); |
---|
| 1170 | + return NULL; |
---|
| 1171 | + } |
---|
| 1172 | + |
---|
| 1173 | + fib_node = mlxsw_sp_fib_node_lookup(fib, addrp, addr_len, |
---|
| 1174 | + addr_prefix_len); |
---|
| 1175 | + if (!fib_node || fib_node->fib_entry->type != type) |
---|
| 1176 | + return NULL; |
---|
| 1177 | + |
---|
| 1178 | + return fib_node->fib_entry; |
---|
| 1179 | +} |
---|
| 1180 | + |
---|
1131 | 1181 | /* Given an IPIP entry, find the corresponding decap route. */ |
---|
1132 | 1182 | static struct mlxsw_sp_fib_entry * |
---|
1133 | 1183 | mlxsw_sp_ipip_entry_find_decap(struct mlxsw_sp *mlxsw_sp, |
---|
.. | .. |
---|
1135 | 1185 | { |
---|
1136 | 1186 | static struct mlxsw_sp_fib_node *fib_node; |
---|
1137 | 1187 | const struct mlxsw_sp_ipip_ops *ipip_ops; |
---|
1138 | | - struct mlxsw_sp_fib_entry *fib_entry; |
---|
1139 | 1188 | unsigned char saddr_prefix_len; |
---|
1140 | 1189 | union mlxsw_sp_l3addr saddr; |
---|
1141 | 1190 | struct mlxsw_sp_fib *ul_fib; |
---|
.. | .. |
---|
1163 | 1212 | saddr_len = 4; |
---|
1164 | 1213 | saddr_prefix_len = 32; |
---|
1165 | 1214 | break; |
---|
1166 | | - case MLXSW_SP_L3_PROTO_IPV6: |
---|
| 1215 | + default: |
---|
1167 | 1216 | WARN_ON(1); |
---|
1168 | 1217 | return NULL; |
---|
1169 | 1218 | } |
---|
1170 | 1219 | |
---|
1171 | 1220 | fib_node = mlxsw_sp_fib_node_lookup(ul_fib, saddrp, saddr_len, |
---|
1172 | 1221 | saddr_prefix_len); |
---|
1173 | | - if (!fib_node || list_empty(&fib_node->entry_list)) |
---|
| 1222 | + if (!fib_node || |
---|
| 1223 | + fib_node->fib_entry->type != MLXSW_SP_FIB_ENTRY_TYPE_TRAP) |
---|
1174 | 1224 | return NULL; |
---|
1175 | 1225 | |
---|
1176 | | - fib_entry = list_first_entry(&fib_node->entry_list, |
---|
1177 | | - struct mlxsw_sp_fib_entry, list); |
---|
1178 | | - if (fib_entry->type != MLXSW_SP_FIB_ENTRY_TYPE_TRAP) |
---|
1179 | | - return NULL; |
---|
1180 | | - |
---|
1181 | | - return fib_entry; |
---|
| 1226 | + return fib_node->fib_entry; |
---|
1182 | 1227 | } |
---|
1183 | 1228 | |
---|
1184 | 1229 | static struct mlxsw_sp_ipip_entry * |
---|
.. | .. |
---|
1292 | 1337 | ipip_list_node); |
---|
1293 | 1338 | list_for_each_entry_continue(ipip_entry, &mlxsw_sp->router->ipip_list, |
---|
1294 | 1339 | ipip_list_node) { |
---|
1295 | | - struct net_device *ipip_ul_dev = |
---|
1296 | | - __mlxsw_sp_ipip_netdev_ul_dev_get(ipip_entry->ol_dev); |
---|
| 1340 | + struct net_device *ol_dev = ipip_entry->ol_dev; |
---|
| 1341 | + struct net_device *ipip_ul_dev; |
---|
| 1342 | + |
---|
| 1343 | + rcu_read_lock(); |
---|
| 1344 | + ipip_ul_dev = __mlxsw_sp_ipip_netdev_ul_dev_get(ol_dev); |
---|
| 1345 | + rcu_read_unlock(); |
---|
1297 | 1346 | |
---|
1298 | 1347 | if (ipip_ul_dev == ul_dev) |
---|
1299 | 1348 | return ipip_entry; |
---|
.. | .. |
---|
1302 | 1351 | return NULL; |
---|
1303 | 1352 | } |
---|
1304 | 1353 | |
---|
1305 | | -bool mlxsw_sp_netdev_is_ipip_ul(const struct mlxsw_sp *mlxsw_sp, |
---|
| 1354 | +bool mlxsw_sp_netdev_is_ipip_ul(struct mlxsw_sp *mlxsw_sp, |
---|
1306 | 1355 | const struct net_device *dev) |
---|
1307 | 1356 | { |
---|
1308 | | - return mlxsw_sp_ipip_entry_find_by_ul_dev(mlxsw_sp, dev, NULL); |
---|
| 1357 | + bool is_ipip_ul; |
---|
| 1358 | + |
---|
| 1359 | + mutex_lock(&mlxsw_sp->router->lock); |
---|
| 1360 | + is_ipip_ul = mlxsw_sp_ipip_entry_find_by_ul_dev(mlxsw_sp, dev, NULL); |
---|
| 1361 | + mutex_unlock(&mlxsw_sp->router->lock); |
---|
| 1362 | + |
---|
| 1363 | + return is_ipip_ul; |
---|
1309 | 1364 | } |
---|
1310 | 1365 | |
---|
1311 | 1366 | static bool mlxsw_sp_netdevice_ipip_can_offload(struct mlxsw_sp *mlxsw_sp, |
---|
.. | .. |
---|
1325 | 1380 | static int mlxsw_sp_netdevice_ipip_ol_reg_event(struct mlxsw_sp *mlxsw_sp, |
---|
1326 | 1381 | struct net_device *ol_dev) |
---|
1327 | 1382 | { |
---|
| 1383 | + enum mlxsw_sp_ipip_type ipipt = MLXSW_SP_IPIP_TYPE_MAX; |
---|
1328 | 1384 | struct mlxsw_sp_ipip_entry *ipip_entry; |
---|
1329 | 1385 | enum mlxsw_sp_l3proto ul_proto; |
---|
1330 | | - enum mlxsw_sp_ipip_type ipipt; |
---|
1331 | 1386 | union mlxsw_sp_l3addr saddr; |
---|
1332 | 1387 | u32 ul_tb_id; |
---|
1333 | 1388 | |
---|
.. | .. |
---|
1372 | 1427 | } |
---|
1373 | 1428 | |
---|
1374 | 1429 | static int |
---|
1375 | | -mlxsw_sp_rif_ipip_lb_op(struct mlxsw_sp_rif_ipip_lb *lb_rif, |
---|
1376 | | - struct mlxsw_sp_vr *ul_vr, bool enable) |
---|
| 1430 | +mlxsw_sp_rif_ipip_lb_op(struct mlxsw_sp_rif_ipip_lb *lb_rif, u16 ul_vr_id, |
---|
| 1431 | + u16 ul_rif_id, bool enable) |
---|
1377 | 1432 | { |
---|
1378 | 1433 | struct mlxsw_sp_rif_ipip_lb_config lb_cf = lb_rif->lb_config; |
---|
1379 | 1434 | struct mlxsw_sp_rif *rif = &lb_rif->common; |
---|
.. | .. |
---|
1388 | 1443 | rif->rif_index, rif->vr_id, rif->dev->mtu); |
---|
1389 | 1444 | mlxsw_reg_ritr_loopback_ipip4_pack(ritr_pl, lb_cf.lb_ipipt, |
---|
1390 | 1445 | MLXSW_REG_RITR_LOOPBACK_IPIP_OPTIONS_GRE_KEY_PRESET, |
---|
1391 | | - ul_vr->id, saddr4, lb_cf.okey); |
---|
| 1446 | + ul_vr_id, ul_rif_id, saddr4, lb_cf.okey); |
---|
1392 | 1447 | break; |
---|
1393 | 1448 | |
---|
1394 | 1449 | case MLXSW_SP_L3_PROTO_IPV6: |
---|
.. | .. |
---|
1403 | 1458 | { |
---|
1404 | 1459 | struct mlxsw_sp_ipip_entry *ipip_entry; |
---|
1405 | 1460 | struct mlxsw_sp_rif_ipip_lb *lb_rif; |
---|
1406 | | - struct mlxsw_sp_vr *ul_vr; |
---|
1407 | 1461 | int err = 0; |
---|
1408 | 1462 | |
---|
1409 | 1463 | ipip_entry = mlxsw_sp_ipip_entry_find_by_ol_dev(mlxsw_sp, ol_dev); |
---|
1410 | 1464 | if (ipip_entry) { |
---|
1411 | 1465 | lb_rif = ipip_entry->ol_lb; |
---|
1412 | | - ul_vr = &mlxsw_sp->router->vrs[lb_rif->ul_vr_id]; |
---|
1413 | | - err = mlxsw_sp_rif_ipip_lb_op(lb_rif, ul_vr, true); |
---|
| 1466 | + err = mlxsw_sp_rif_ipip_lb_op(lb_rif, lb_rif->ul_vr_id, |
---|
| 1467 | + lb_rif->ul_rif_id, true); |
---|
1414 | 1468 | if (err) |
---|
1415 | 1469 | goto out; |
---|
1416 | 1470 | lb_rif->common.mtu = ol_dev->mtu; |
---|
.. | .. |
---|
1481 | 1535 | struct mlxsw_sp_rif *rif); |
---|
1482 | 1536 | |
---|
1483 | 1537 | /** |
---|
1484 | | - * Update the offload related to an IPIP entry. This always updates decap, and |
---|
1485 | | - * in addition to that it also: |
---|
1486 | | - * @recreate_loopback: recreates the associated loopback RIF |
---|
1487 | | - * @keep_encap: updates next hops that use the tunnel netdevice. This is only |
---|
| 1538 | + * __mlxsw_sp_ipip_entry_update_tunnel - Update offload related to IPIP entry. |
---|
| 1539 | + * @mlxsw_sp: mlxsw_sp. |
---|
| 1540 | + * @ipip_entry: IPIP entry. |
---|
| 1541 | + * @recreate_loopback: Recreates the associated loopback RIF. |
---|
| 1542 | + * @keep_encap: Updates next hops that use the tunnel netdevice. This is only |
---|
1488 | 1543 | * relevant when recreate_loopback is true. |
---|
1489 | | - * @update_nexthops: updates next hops, keeping the current loopback RIF. This |
---|
| 1544 | + * @update_nexthops: Updates next hops, keeping the current loopback RIF. This |
---|
1490 | 1545 | * is only relevant when recreate_loopback is false. |
---|
| 1546 | + * @extack: extack. |
---|
| 1547 | + * |
---|
| 1548 | + * Return: Non-zero value on failure. |
---|
1491 | 1549 | */ |
---|
1492 | 1550 | int __mlxsw_sp_ipip_entry_update_tunnel(struct mlxsw_sp *mlxsw_sp, |
---|
1493 | 1551 | struct mlxsw_sp_ipip_entry *ipip_entry, |
---|
.. | .. |
---|
1541 | 1599 | mlxsw_sp_netdevice_ipip_ul_vrf_event(struct mlxsw_sp *mlxsw_sp, |
---|
1542 | 1600 | struct mlxsw_sp_ipip_entry *ipip_entry, |
---|
1543 | 1601 | struct net_device *ul_dev, |
---|
| 1602 | + bool *demote_this, |
---|
1544 | 1603 | struct netlink_ext_ack *extack) |
---|
1545 | 1604 | { |
---|
| 1605 | + u32 ul_tb_id = l3mdev_fib_table(ul_dev) ? : RT_TABLE_MAIN; |
---|
| 1606 | + enum mlxsw_sp_l3proto ul_proto; |
---|
| 1607 | + union mlxsw_sp_l3addr saddr; |
---|
| 1608 | + |
---|
| 1609 | + /* Moving underlay to a different VRF might cause local address |
---|
| 1610 | + * conflict, and the conflicting tunnels need to be demoted. |
---|
| 1611 | + */ |
---|
| 1612 | + ul_proto = mlxsw_sp->router->ipip_ops_arr[ipip_entry->ipipt]->ul_proto; |
---|
| 1613 | + saddr = mlxsw_sp_ipip_netdev_saddr(ul_proto, ipip_entry->ol_dev); |
---|
| 1614 | + if (mlxsw_sp_ipip_demote_tunnel_by_saddr(mlxsw_sp, ul_proto, |
---|
| 1615 | + saddr, ul_tb_id, |
---|
| 1616 | + ipip_entry)) { |
---|
| 1617 | + *demote_this = true; |
---|
| 1618 | + return 0; |
---|
| 1619 | + } |
---|
| 1620 | + |
---|
1546 | 1621 | return __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp, ipip_entry, |
---|
1547 | 1622 | true, true, false, extack); |
---|
1548 | 1623 | } |
---|
.. | .. |
---|
1643 | 1718 | |
---|
1644 | 1719 | list_for_each_entry_safe(ipip_entry, tmp, &mlxsw_sp->router->ipip_list, |
---|
1645 | 1720 | ipip_list_node) { |
---|
1646 | | - struct net_device *ipip_ul_dev = |
---|
1647 | | - __mlxsw_sp_ipip_netdev_ul_dev_get(ipip_entry->ol_dev); |
---|
| 1721 | + struct net_device *ol_dev = ipip_entry->ol_dev; |
---|
| 1722 | + struct net_device *ipip_ul_dev; |
---|
1648 | 1723 | |
---|
| 1724 | + rcu_read_lock(); |
---|
| 1725 | + ipip_ul_dev = __mlxsw_sp_ipip_netdev_ul_dev_get(ol_dev); |
---|
| 1726 | + rcu_read_unlock(); |
---|
1649 | 1727 | if (ipip_ul_dev == ul_dev) |
---|
1650 | 1728 | mlxsw_sp_ipip_entry_demote_tunnel(mlxsw_sp, ipip_entry); |
---|
1651 | 1729 | } |
---|
.. | .. |
---|
1658 | 1736 | { |
---|
1659 | 1737 | struct netdev_notifier_changeupper_info *chup; |
---|
1660 | 1738 | struct netlink_ext_ack *extack; |
---|
| 1739 | + int err = 0; |
---|
1661 | 1740 | |
---|
| 1741 | + mutex_lock(&mlxsw_sp->router->lock); |
---|
1662 | 1742 | switch (event) { |
---|
1663 | 1743 | case NETDEV_REGISTER: |
---|
1664 | | - return mlxsw_sp_netdevice_ipip_ol_reg_event(mlxsw_sp, ol_dev); |
---|
| 1744 | + err = mlxsw_sp_netdevice_ipip_ol_reg_event(mlxsw_sp, ol_dev); |
---|
| 1745 | + break; |
---|
1665 | 1746 | case NETDEV_UNREGISTER: |
---|
1666 | 1747 | mlxsw_sp_netdevice_ipip_ol_unreg_event(mlxsw_sp, ol_dev); |
---|
1667 | | - return 0; |
---|
| 1748 | + break; |
---|
1668 | 1749 | case NETDEV_UP: |
---|
1669 | 1750 | mlxsw_sp_netdevice_ipip_ol_up_event(mlxsw_sp, ol_dev); |
---|
1670 | | - return 0; |
---|
| 1751 | + break; |
---|
1671 | 1752 | case NETDEV_DOWN: |
---|
1672 | 1753 | mlxsw_sp_netdevice_ipip_ol_down_event(mlxsw_sp, ol_dev); |
---|
1673 | | - return 0; |
---|
| 1754 | + break; |
---|
1674 | 1755 | case NETDEV_CHANGEUPPER: |
---|
1675 | 1756 | chup = container_of(info, typeof(*chup), info); |
---|
1676 | 1757 | extack = info->extack; |
---|
1677 | 1758 | if (netif_is_l3_master(chup->upper_dev)) |
---|
1678 | | - return mlxsw_sp_netdevice_ipip_ol_vrf_event(mlxsw_sp, |
---|
1679 | | - ol_dev, |
---|
1680 | | - extack); |
---|
1681 | | - return 0; |
---|
| 1759 | + err = mlxsw_sp_netdevice_ipip_ol_vrf_event(mlxsw_sp, |
---|
| 1760 | + ol_dev, |
---|
| 1761 | + extack); |
---|
| 1762 | + break; |
---|
1682 | 1763 | case NETDEV_CHANGE: |
---|
1683 | 1764 | extack = info->extack; |
---|
1684 | | - return mlxsw_sp_netdevice_ipip_ol_change_event(mlxsw_sp, |
---|
1685 | | - ol_dev, extack); |
---|
| 1765 | + err = mlxsw_sp_netdevice_ipip_ol_change_event(mlxsw_sp, |
---|
| 1766 | + ol_dev, extack); |
---|
| 1767 | + break; |
---|
1686 | 1768 | case NETDEV_CHANGEMTU: |
---|
1687 | | - return mlxsw_sp_netdevice_ipip_ol_update_mtu(mlxsw_sp, ol_dev); |
---|
| 1769 | + err = mlxsw_sp_netdevice_ipip_ol_update_mtu(mlxsw_sp, ol_dev); |
---|
| 1770 | + break; |
---|
1688 | 1771 | } |
---|
1689 | | - return 0; |
---|
| 1772 | + mutex_unlock(&mlxsw_sp->router->lock); |
---|
| 1773 | + return err; |
---|
1690 | 1774 | } |
---|
1691 | 1775 | |
---|
1692 | 1776 | static int |
---|
1693 | 1777 | __mlxsw_sp_netdevice_ipip_ul_event(struct mlxsw_sp *mlxsw_sp, |
---|
1694 | 1778 | struct mlxsw_sp_ipip_entry *ipip_entry, |
---|
1695 | 1779 | struct net_device *ul_dev, |
---|
| 1780 | + bool *demote_this, |
---|
1696 | 1781 | unsigned long event, |
---|
1697 | 1782 | struct netdev_notifier_info *info) |
---|
1698 | 1783 | { |
---|
.. | .. |
---|
1707 | 1792 | return mlxsw_sp_netdevice_ipip_ul_vrf_event(mlxsw_sp, |
---|
1708 | 1793 | ipip_entry, |
---|
1709 | 1794 | ul_dev, |
---|
| 1795 | + demote_this, |
---|
1710 | 1796 | extack); |
---|
1711 | 1797 | break; |
---|
1712 | 1798 | |
---|
.. | .. |
---|
1728 | 1814 | struct netdev_notifier_info *info) |
---|
1729 | 1815 | { |
---|
1730 | 1816 | struct mlxsw_sp_ipip_entry *ipip_entry = NULL; |
---|
1731 | | - int err; |
---|
| 1817 | + int err = 0; |
---|
1732 | 1818 | |
---|
| 1819 | + mutex_lock(&mlxsw_sp->router->lock); |
---|
1733 | 1820 | while ((ipip_entry = mlxsw_sp_ipip_entry_find_by_ul_dev(mlxsw_sp, |
---|
1734 | 1821 | ul_dev, |
---|
1735 | 1822 | ipip_entry))) { |
---|
| 1823 | + struct mlxsw_sp_ipip_entry *prev; |
---|
| 1824 | + bool demote_this = false; |
---|
| 1825 | + |
---|
1736 | 1826 | err = __mlxsw_sp_netdevice_ipip_ul_event(mlxsw_sp, ipip_entry, |
---|
1737 | | - ul_dev, event, info); |
---|
| 1827 | + ul_dev, &demote_this, |
---|
| 1828 | + event, info); |
---|
1738 | 1829 | if (err) { |
---|
1739 | 1830 | mlxsw_sp_ipip_demote_tunnel_by_ul_netdev(mlxsw_sp, |
---|
1740 | 1831 | ul_dev); |
---|
1741 | | - return err; |
---|
| 1832 | + break; |
---|
| 1833 | + } |
---|
| 1834 | + |
---|
| 1835 | + if (demote_this) { |
---|
| 1836 | + if (list_is_first(&ipip_entry->ipip_list_node, |
---|
| 1837 | + &mlxsw_sp->router->ipip_list)) |
---|
| 1838 | + prev = NULL; |
---|
| 1839 | + else |
---|
| 1840 | + /* This can't be cached from previous iteration, |
---|
| 1841 | + * because that entry could be gone now. |
---|
| 1842 | + */ |
---|
| 1843 | + prev = list_prev_entry(ipip_entry, |
---|
| 1844 | + ipip_list_node); |
---|
| 1845 | + mlxsw_sp_ipip_entry_demote_tunnel(mlxsw_sp, ipip_entry); |
---|
| 1846 | + ipip_entry = prev; |
---|
1742 | 1847 | } |
---|
1743 | 1848 | } |
---|
| 1849 | + mutex_unlock(&mlxsw_sp->router->lock); |
---|
1744 | 1850 | |
---|
1745 | | - return 0; |
---|
| 1851 | + return err; |
---|
| 1852 | +} |
---|
| 1853 | + |
---|
| 1854 | +int mlxsw_sp_router_nve_promote_decap(struct mlxsw_sp *mlxsw_sp, u32 ul_tb_id, |
---|
| 1855 | + enum mlxsw_sp_l3proto ul_proto, |
---|
| 1856 | + const union mlxsw_sp_l3addr *ul_sip, |
---|
| 1857 | + u32 tunnel_index) |
---|
| 1858 | +{ |
---|
| 1859 | + enum mlxsw_sp_fib_entry_type type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP; |
---|
| 1860 | + struct mlxsw_sp_router *router = mlxsw_sp->router; |
---|
| 1861 | + struct mlxsw_sp_fib_entry *fib_entry; |
---|
| 1862 | + int err = 0; |
---|
| 1863 | + |
---|
| 1864 | + mutex_lock(&mlxsw_sp->router->lock); |
---|
| 1865 | + |
---|
| 1866 | + if (WARN_ON_ONCE(router->nve_decap_config.valid)) { |
---|
| 1867 | + err = -EINVAL; |
---|
| 1868 | + goto out; |
---|
| 1869 | + } |
---|
| 1870 | + |
---|
| 1871 | + router->nve_decap_config.ul_tb_id = ul_tb_id; |
---|
| 1872 | + router->nve_decap_config.tunnel_index = tunnel_index; |
---|
| 1873 | + router->nve_decap_config.ul_proto = ul_proto; |
---|
| 1874 | + router->nve_decap_config.ul_sip = *ul_sip; |
---|
| 1875 | + router->nve_decap_config.valid = true; |
---|
| 1876 | + |
---|
| 1877 | + /* It is valid to create a tunnel with a local IP and only later |
---|
| 1878 | + * assign this IP address to a local interface |
---|
| 1879 | + */ |
---|
| 1880 | + fib_entry = mlxsw_sp_router_ip2me_fib_entry_find(mlxsw_sp, ul_tb_id, |
---|
| 1881 | + ul_proto, ul_sip, |
---|
| 1882 | + type); |
---|
| 1883 | + if (!fib_entry) |
---|
| 1884 | + goto out; |
---|
| 1885 | + |
---|
| 1886 | + fib_entry->decap.tunnel_index = tunnel_index; |
---|
| 1887 | + fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP; |
---|
| 1888 | + |
---|
| 1889 | + err = mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry); |
---|
| 1890 | + if (err) |
---|
| 1891 | + goto err_fib_entry_update; |
---|
| 1892 | + |
---|
| 1893 | + goto out; |
---|
| 1894 | + |
---|
| 1895 | +err_fib_entry_update: |
---|
| 1896 | + fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP; |
---|
| 1897 | + mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry); |
---|
| 1898 | +out: |
---|
| 1899 | + mutex_unlock(&mlxsw_sp->router->lock); |
---|
| 1900 | + return err; |
---|
| 1901 | +} |
---|
| 1902 | + |
---|
| 1903 | +void mlxsw_sp_router_nve_demote_decap(struct mlxsw_sp *mlxsw_sp, u32 ul_tb_id, |
---|
| 1904 | + enum mlxsw_sp_l3proto ul_proto, |
---|
| 1905 | + const union mlxsw_sp_l3addr *ul_sip) |
---|
| 1906 | +{ |
---|
| 1907 | + enum mlxsw_sp_fib_entry_type type = MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP; |
---|
| 1908 | + struct mlxsw_sp_router *router = mlxsw_sp->router; |
---|
| 1909 | + struct mlxsw_sp_fib_entry *fib_entry; |
---|
| 1910 | + |
---|
| 1911 | + mutex_lock(&mlxsw_sp->router->lock); |
---|
| 1912 | + |
---|
| 1913 | + if (WARN_ON_ONCE(!router->nve_decap_config.valid)) |
---|
| 1914 | + goto out; |
---|
| 1915 | + |
---|
| 1916 | + router->nve_decap_config.valid = false; |
---|
| 1917 | + |
---|
| 1918 | + fib_entry = mlxsw_sp_router_ip2me_fib_entry_find(mlxsw_sp, ul_tb_id, |
---|
| 1919 | + ul_proto, ul_sip, |
---|
| 1920 | + type); |
---|
| 1921 | + if (!fib_entry) |
---|
| 1922 | + goto out; |
---|
| 1923 | + |
---|
| 1924 | + fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP; |
---|
| 1925 | + mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry); |
---|
| 1926 | +out: |
---|
| 1927 | + mutex_unlock(&mlxsw_sp->router->lock); |
---|
| 1928 | +} |
---|
| 1929 | + |
---|
| 1930 | +static bool mlxsw_sp_router_nve_is_decap(struct mlxsw_sp *mlxsw_sp, |
---|
| 1931 | + u32 ul_tb_id, |
---|
| 1932 | + enum mlxsw_sp_l3proto ul_proto, |
---|
| 1933 | + const union mlxsw_sp_l3addr *ul_sip) |
---|
| 1934 | +{ |
---|
| 1935 | + struct mlxsw_sp_router *router = mlxsw_sp->router; |
---|
| 1936 | + |
---|
| 1937 | + return router->nve_decap_config.valid && |
---|
| 1938 | + router->nve_decap_config.ul_tb_id == ul_tb_id && |
---|
| 1939 | + router->nve_decap_config.ul_proto == ul_proto && |
---|
| 1940 | + !memcmp(&router->nve_decap_config.ul_sip, ul_sip, |
---|
| 1941 | + sizeof(*ul_sip)); |
---|
1746 | 1942 | } |
---|
1747 | 1943 | |
---|
1748 | 1944 | struct mlxsw_sp_neigh_key { |
---|
.. | .. |
---|
1981 | 2177 | char *rauhtd_pl, |
---|
1982 | 2178 | int ent_index) |
---|
1983 | 2179 | { |
---|
| 2180 | + u64 max_rifs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); |
---|
1984 | 2181 | struct net_device *dev; |
---|
1985 | 2182 | struct neighbour *n; |
---|
1986 | 2183 | __be32 dipn; |
---|
.. | .. |
---|
1989 | 2186 | |
---|
1990 | 2187 | mlxsw_reg_rauhtd_ent_ipv4_unpack(rauhtd_pl, ent_index, &rif, &dip); |
---|
1991 | 2188 | |
---|
| 2189 | + if (WARN_ON_ONCE(rif >= max_rifs)) |
---|
| 2190 | + return; |
---|
1992 | 2191 | if (!mlxsw_sp->router->rifs[rif]) { |
---|
1993 | 2192 | dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Incorrect RIF in neighbour entry\n"); |
---|
1994 | 2193 | return; |
---|
.. | .. |
---|
2115 | 2314 | int i, num_rec; |
---|
2116 | 2315 | int err; |
---|
2117 | 2316 | |
---|
2118 | | - /* Make sure the neighbour's netdev isn't removed in the |
---|
2119 | | - * process. |
---|
2120 | | - */ |
---|
2121 | | - rtnl_lock(); |
---|
| 2317 | + /* Ensure the RIF we read from the device does not change mid-dump. */ |
---|
| 2318 | + mutex_lock(&mlxsw_sp->router->lock); |
---|
2122 | 2319 | do { |
---|
2123 | 2320 | mlxsw_reg_rauhtd_pack(rauhtd_pl, type); |
---|
2124 | 2321 | err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(rauhtd), |
---|
.. | .. |
---|
2132 | 2329 | mlxsw_sp_router_neigh_rec_process(mlxsw_sp, rauhtd_pl, |
---|
2133 | 2330 | i); |
---|
2134 | 2331 | } while (mlxsw_sp_router_rauhtd_is_full(rauhtd_pl)); |
---|
2135 | | - rtnl_unlock(); |
---|
| 2332 | + mutex_unlock(&mlxsw_sp->router->lock); |
---|
2136 | 2333 | |
---|
2137 | 2334 | return err; |
---|
2138 | 2335 | } |
---|
.. | .. |
---|
2163 | 2360 | { |
---|
2164 | 2361 | struct mlxsw_sp_neigh_entry *neigh_entry; |
---|
2165 | 2362 | |
---|
2166 | | - /* Take RTNL mutex here to prevent lists from changes */ |
---|
2167 | | - rtnl_lock(); |
---|
| 2363 | + mutex_lock(&mlxsw_sp->router->lock); |
---|
2168 | 2364 | list_for_each_entry(neigh_entry, &mlxsw_sp->router->nexthop_neighs_list, |
---|
2169 | 2365 | nexthop_neighs_list_node) |
---|
2170 | 2366 | /* If this neigh have nexthops, make the kernel think this neigh |
---|
2171 | 2367 | * is active regardless of the traffic. |
---|
2172 | 2368 | */ |
---|
2173 | 2369 | neigh_event_send(neigh_entry->key.n, NULL); |
---|
2174 | | - rtnl_unlock(); |
---|
| 2370 | + mutex_unlock(&mlxsw_sp->router->lock); |
---|
2175 | 2371 | } |
---|
2176 | 2372 | |
---|
2177 | 2373 | static void |
---|
.. | .. |
---|
2211 | 2407 | * the nexthop wouldn't get offloaded until the neighbor is resolved |
---|
2212 | 2408 | * but it wouldn't get resolved ever in case traffic is flowing in HW |
---|
2213 | 2409 | * using different nexthop. |
---|
2214 | | - * |
---|
2215 | | - * Take RTNL mutex here to prevent lists from changes. |
---|
2216 | 2410 | */ |
---|
2217 | | - rtnl_lock(); |
---|
| 2411 | + mutex_lock(&router->lock); |
---|
2218 | 2412 | list_for_each_entry(neigh_entry, &router->nexthop_neighs_list, |
---|
2219 | 2413 | nexthop_neighs_list_node) |
---|
2220 | 2414 | if (!neigh_entry->connected) |
---|
2221 | 2415 | neigh_event_send(neigh_entry->key.n, NULL); |
---|
2222 | | - rtnl_unlock(); |
---|
| 2416 | + mutex_unlock(&router->lock); |
---|
2223 | 2417 | |
---|
2224 | 2418 | mlxsw_core_schedule_dw(&router->nexthop_probe_dw, |
---|
2225 | 2419 | MLXSW_SP_UNRESOLVED_NH_PROBE_INTERVAL); |
---|
.. | .. |
---|
2236 | 2430 | MLXSW_REG_RAUHT_OP_WRITE_DELETE; |
---|
2237 | 2431 | } |
---|
2238 | 2432 | |
---|
2239 | | -static void |
---|
| 2433 | +static int |
---|
2240 | 2434 | mlxsw_sp_router_neigh_entry_op4(struct mlxsw_sp *mlxsw_sp, |
---|
2241 | 2435 | struct mlxsw_sp_neigh_entry *neigh_entry, |
---|
2242 | 2436 | enum mlxsw_reg_rauht_op op) |
---|
.. | .. |
---|
2250 | 2444 | if (neigh_entry->counter_valid) |
---|
2251 | 2445 | mlxsw_reg_rauht_pack_counter(rauht_pl, |
---|
2252 | 2446 | neigh_entry->counter_index); |
---|
2253 | | - mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rauht), rauht_pl); |
---|
| 2447 | + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rauht), rauht_pl); |
---|
2254 | 2448 | } |
---|
2255 | 2449 | |
---|
2256 | | -static void |
---|
| 2450 | +static int |
---|
2257 | 2451 | mlxsw_sp_router_neigh_entry_op6(struct mlxsw_sp *mlxsw_sp, |
---|
2258 | 2452 | struct mlxsw_sp_neigh_entry *neigh_entry, |
---|
2259 | 2453 | enum mlxsw_reg_rauht_op op) |
---|
.. | .. |
---|
2267 | 2461 | if (neigh_entry->counter_valid) |
---|
2268 | 2462 | mlxsw_reg_rauht_pack_counter(rauht_pl, |
---|
2269 | 2463 | neigh_entry->counter_index); |
---|
2270 | | - mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rauht), rauht_pl); |
---|
| 2464 | + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rauht), rauht_pl); |
---|
2271 | 2465 | } |
---|
2272 | 2466 | |
---|
2273 | 2467 | bool mlxsw_sp_neigh_ipv6_ignore(struct mlxsw_sp_neigh_entry *neigh_entry) |
---|
.. | .. |
---|
2289 | 2483 | struct mlxsw_sp_neigh_entry *neigh_entry, |
---|
2290 | 2484 | bool adding) |
---|
2291 | 2485 | { |
---|
| 2486 | + enum mlxsw_reg_rauht_op op = mlxsw_sp_rauht_op(adding); |
---|
| 2487 | + int err; |
---|
| 2488 | + |
---|
2292 | 2489 | if (!adding && !neigh_entry->connected) |
---|
2293 | 2490 | return; |
---|
2294 | 2491 | neigh_entry->connected = adding; |
---|
2295 | 2492 | if (neigh_entry->key.n->tbl->family == AF_INET) { |
---|
2296 | | - mlxsw_sp_router_neigh_entry_op4(mlxsw_sp, neigh_entry, |
---|
2297 | | - mlxsw_sp_rauht_op(adding)); |
---|
| 2493 | + err = mlxsw_sp_router_neigh_entry_op4(mlxsw_sp, neigh_entry, |
---|
| 2494 | + op); |
---|
| 2495 | + if (err) |
---|
| 2496 | + return; |
---|
2298 | 2497 | } else if (neigh_entry->key.n->tbl->family == AF_INET6) { |
---|
2299 | 2498 | if (mlxsw_sp_neigh_ipv6_ignore(neigh_entry)) |
---|
2300 | 2499 | return; |
---|
2301 | | - mlxsw_sp_router_neigh_entry_op6(mlxsw_sp, neigh_entry, |
---|
2302 | | - mlxsw_sp_rauht_op(adding)); |
---|
| 2500 | + err = mlxsw_sp_router_neigh_entry_op6(mlxsw_sp, neigh_entry, |
---|
| 2501 | + op); |
---|
| 2502 | + if (err) |
---|
| 2503 | + return; |
---|
2303 | 2504 | } else { |
---|
2304 | 2505 | WARN_ON_ONCE(1); |
---|
| 2506 | + return; |
---|
2305 | 2507 | } |
---|
| 2508 | + |
---|
| 2509 | + if (adding) |
---|
| 2510 | + neigh_entry->key.n->flags |= NTF_OFFLOADED; |
---|
| 2511 | + else |
---|
| 2512 | + neigh_entry->key.n->flags &= ~NTF_OFFLOADED; |
---|
2306 | 2513 | } |
---|
2307 | 2514 | |
---|
2308 | 2515 | void |
---|
.. | .. |
---|
2344 | 2551 | dead = n->dead; |
---|
2345 | 2552 | read_unlock_bh(&n->lock); |
---|
2346 | 2553 | |
---|
2347 | | - rtnl_lock(); |
---|
| 2554 | + mutex_lock(&mlxsw_sp->router->lock); |
---|
2348 | 2555 | mlxsw_sp_span_respin(mlxsw_sp); |
---|
2349 | 2556 | |
---|
2350 | 2557 | entry_connected = nud_state & NUD_VALID && !dead; |
---|
.. | .. |
---|
2366 | 2573 | mlxsw_sp_neigh_entry_destroy(mlxsw_sp, neigh_entry); |
---|
2367 | 2574 | |
---|
2368 | 2575 | out: |
---|
2369 | | - rtnl_unlock(); |
---|
| 2576 | + mutex_unlock(&mlxsw_sp->router->lock); |
---|
2370 | 2577 | neigh_release(n); |
---|
2371 | 2578 | kfree(net_work); |
---|
2372 | 2579 | } |
---|
.. | .. |
---|
2402 | 2609 | struct mlxsw_sp_netevent_work *net_work; |
---|
2403 | 2610 | struct mlxsw_sp_router *router; |
---|
2404 | 2611 | |
---|
2405 | | - if (!net_eq(net, &init_net)) |
---|
| 2612 | + router = container_of(nb, struct mlxsw_sp_router, netevent_nb); |
---|
| 2613 | + if (!net_eq(net, mlxsw_sp_net(router->mlxsw_sp))) |
---|
2406 | 2614 | return NOTIFY_DONE; |
---|
2407 | 2615 | |
---|
2408 | 2616 | net_work = kzalloc(sizeof(*net_work), GFP_ATOMIC); |
---|
2409 | 2617 | if (!net_work) |
---|
2410 | 2618 | return NOTIFY_BAD; |
---|
2411 | 2619 | |
---|
2412 | | - router = container_of(nb, struct mlxsw_sp_router, netevent_nb); |
---|
2413 | 2620 | INIT_WORK(&net_work->work, cb); |
---|
2414 | 2621 | net_work->mlxsw_sp = router->mlxsw_sp; |
---|
2415 | 2622 | mlxsw_core_schedule_work(&net_work->work); |
---|
.. | .. |
---|
2739 | 2946 | return false; |
---|
2740 | 2947 | |
---|
2741 | 2948 | list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list) { |
---|
| 2949 | + struct fib6_nh *fib6_nh = mlxsw_sp_rt6->rt->fib6_nh; |
---|
2742 | 2950 | struct in6_addr *gw; |
---|
2743 | 2951 | int ifindex, weight; |
---|
2744 | 2952 | |
---|
2745 | | - ifindex = mlxsw_sp_rt6->rt->fib6_nh.nh_dev->ifindex; |
---|
2746 | | - weight = mlxsw_sp_rt6->rt->fib6_nh.nh_weight; |
---|
2747 | | - gw = &mlxsw_sp_rt6->rt->fib6_nh.nh_gw; |
---|
| 2953 | + ifindex = fib6_nh->fib_nh_dev->ifindex; |
---|
| 2954 | + weight = fib6_nh->fib_nh_weight; |
---|
| 2955 | + gw = &fib6_nh->fib_nh_gw6; |
---|
2748 | 2956 | if (!mlxsw_sp_nexthop6_group_has_nexthop(nh_grp, gw, ifindex, |
---|
2749 | 2957 | weight)) |
---|
2750 | 2958 | return false; |
---|
.. | .. |
---|
2793 | 3001 | val = nh_grp->count; |
---|
2794 | 3002 | for (i = 0; i < nh_grp->count; i++) { |
---|
2795 | 3003 | nh = &nh_grp->nexthops[i]; |
---|
2796 | | - val ^= nh->ifindex; |
---|
| 3004 | + val ^= jhash(&nh->ifindex, sizeof(nh->ifindex), seed); |
---|
| 3005 | + val ^= jhash(&nh->gw_addr, sizeof(nh->gw_addr), seed); |
---|
2797 | 3006 | } |
---|
2798 | 3007 | return jhash(&val, sizeof(val), seed); |
---|
2799 | 3008 | default: |
---|
.. | .. |
---|
2807 | 3016 | { |
---|
2808 | 3017 | unsigned int val = fib6_entry->nrt6; |
---|
2809 | 3018 | struct mlxsw_sp_rt6 *mlxsw_sp_rt6; |
---|
2810 | | - struct net_device *dev; |
---|
2811 | 3019 | |
---|
2812 | 3020 | list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list) { |
---|
2813 | | - dev = mlxsw_sp_rt6->rt->fib6_nh.nh_dev; |
---|
2814 | | - val ^= dev->ifindex; |
---|
| 3021 | + struct fib6_nh *fib6_nh = mlxsw_sp_rt6->rt->fib6_nh; |
---|
| 3022 | + struct net_device *dev = fib6_nh->fib_nh_dev; |
---|
| 3023 | + struct in6_addr *gw = &fib6_nh->fib_nh_gw6; |
---|
| 3024 | + |
---|
| 3025 | + val ^= jhash(&dev->ifindex, sizeof(dev->ifindex), seed); |
---|
| 3026 | + val ^= jhash(gw, sizeof(*gw), seed); |
---|
2815 | 3027 | } |
---|
2816 | 3028 | |
---|
2817 | 3029 | return jhash(&val, sizeof(val), seed); |
---|
.. | .. |
---|
3026 | 3238 | u32 adj_index = nh_grp->adj_index; /* base */ |
---|
3027 | 3239 | struct mlxsw_sp_nexthop *nh; |
---|
3028 | 3240 | int i; |
---|
3029 | | - int err; |
---|
3030 | 3241 | |
---|
3031 | 3242 | for (i = 0; i < nh_grp->count; i++) { |
---|
3032 | 3243 | nh = &nh_grp->nexthops[i]; |
---|
.. | .. |
---|
3037 | 3248 | } |
---|
3038 | 3249 | |
---|
3039 | 3250 | if (nh->update || reallocate) { |
---|
| 3251 | + int err = 0; |
---|
| 3252 | + |
---|
3040 | 3253 | switch (nh->type) { |
---|
3041 | 3254 | case MLXSW_SP_NEXTHOP_TYPE_ETH: |
---|
3042 | 3255 | err = mlxsw_sp_nexthop_update |
---|
.. | .. |
---|
3057 | 3270 | return 0; |
---|
3058 | 3271 | } |
---|
3059 | 3272 | |
---|
3060 | | -static bool |
---|
3061 | | -mlxsw_sp_fib_node_entry_is_first(const struct mlxsw_sp_fib_node *fib_node, |
---|
3062 | | - const struct mlxsw_sp_fib_entry *fib_entry); |
---|
3063 | | - |
---|
3064 | 3273 | static int |
---|
3065 | 3274 | mlxsw_sp_nexthop_fib_entries_update(struct mlxsw_sp *mlxsw_sp, |
---|
3066 | 3275 | struct mlxsw_sp_nexthop_group *nh_grp) |
---|
.. | .. |
---|
3069 | 3278 | int err; |
---|
3070 | 3279 | |
---|
3071 | 3280 | list_for_each_entry(fib_entry, &nh_grp->fib_list, nexthop_group_node) { |
---|
3072 | | - if (!mlxsw_sp_fib_node_entry_is_first(fib_entry->fib_node, |
---|
3073 | | - fib_entry)) |
---|
3074 | | - continue; |
---|
3075 | 3281 | err = mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry); |
---|
3076 | 3282 | if (err) |
---|
3077 | 3283 | return err; |
---|
3078 | 3284 | } |
---|
3079 | 3285 | return 0; |
---|
3080 | | -} |
---|
3081 | | - |
---|
3082 | | -static void |
---|
3083 | | -mlxsw_sp_fib_entry_offload_refresh(struct mlxsw_sp_fib_entry *fib_entry, |
---|
3084 | | - enum mlxsw_reg_ralue_op op, int err); |
---|
3085 | | - |
---|
3086 | | -static void |
---|
3087 | | -mlxsw_sp_nexthop_fib_entries_refresh(struct mlxsw_sp_nexthop_group *nh_grp) |
---|
3088 | | -{ |
---|
3089 | | - enum mlxsw_reg_ralue_op op = MLXSW_REG_RALUE_OP_WRITE_WRITE; |
---|
3090 | | - struct mlxsw_sp_fib_entry *fib_entry; |
---|
3091 | | - |
---|
3092 | | - list_for_each_entry(fib_entry, &nh_grp->fib_list, nexthop_group_node) { |
---|
3093 | | - if (!mlxsw_sp_fib_node_entry_is_first(fib_entry->fib_node, |
---|
3094 | | - fib_entry)) |
---|
3095 | | - continue; |
---|
3096 | | - mlxsw_sp_fib_entry_offload_refresh(fib_entry, op, 0); |
---|
3097 | | - } |
---|
3098 | 3286 | } |
---|
3099 | 3287 | |
---|
3100 | 3288 | static void mlxsw_sp_adj_grp_size_round_up(u16 *p_adj_grp_size) |
---|
.. | .. |
---|
3200 | 3388 | } |
---|
3201 | 3389 | } |
---|
3202 | 3390 | |
---|
| 3391 | +static struct mlxsw_sp_nexthop * |
---|
| 3392 | +mlxsw_sp_rt6_nexthop(struct mlxsw_sp_nexthop_group *nh_grp, |
---|
| 3393 | + const struct mlxsw_sp_rt6 *mlxsw_sp_rt6); |
---|
| 3394 | + |
---|
| 3395 | +static void |
---|
| 3396 | +mlxsw_sp_nexthop4_group_offload_refresh(struct mlxsw_sp *mlxsw_sp, |
---|
| 3397 | + struct mlxsw_sp_nexthop_group *nh_grp) |
---|
| 3398 | +{ |
---|
| 3399 | + int i; |
---|
| 3400 | + |
---|
| 3401 | + for (i = 0; i < nh_grp->count; i++) { |
---|
| 3402 | + struct mlxsw_sp_nexthop *nh = &nh_grp->nexthops[i]; |
---|
| 3403 | + |
---|
| 3404 | + if (nh->offloaded) |
---|
| 3405 | + nh->key.fib_nh->fib_nh_flags |= RTNH_F_OFFLOAD; |
---|
| 3406 | + else |
---|
| 3407 | + nh->key.fib_nh->fib_nh_flags &= ~RTNH_F_OFFLOAD; |
---|
| 3408 | + } |
---|
| 3409 | +} |
---|
| 3410 | + |
---|
| 3411 | +static void |
---|
| 3412 | +__mlxsw_sp_nexthop6_group_offload_refresh(struct mlxsw_sp_nexthop_group *nh_grp, |
---|
| 3413 | + struct mlxsw_sp_fib6_entry *fib6_entry) |
---|
| 3414 | +{ |
---|
| 3415 | + struct mlxsw_sp_rt6 *mlxsw_sp_rt6; |
---|
| 3416 | + |
---|
| 3417 | + list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list) { |
---|
| 3418 | + struct fib6_nh *fib6_nh = mlxsw_sp_rt6->rt->fib6_nh; |
---|
| 3419 | + struct mlxsw_sp_nexthop *nh; |
---|
| 3420 | + |
---|
| 3421 | + nh = mlxsw_sp_rt6_nexthop(nh_grp, mlxsw_sp_rt6); |
---|
| 3422 | + if (nh && nh->offloaded) |
---|
| 3423 | + fib6_nh->fib_nh_flags |= RTNH_F_OFFLOAD; |
---|
| 3424 | + else |
---|
| 3425 | + fib6_nh->fib_nh_flags &= ~RTNH_F_OFFLOAD; |
---|
| 3426 | + } |
---|
| 3427 | +} |
---|
| 3428 | + |
---|
| 3429 | +static void |
---|
| 3430 | +mlxsw_sp_nexthop6_group_offload_refresh(struct mlxsw_sp *mlxsw_sp, |
---|
| 3431 | + struct mlxsw_sp_nexthop_group *nh_grp) |
---|
| 3432 | +{ |
---|
| 3433 | + struct mlxsw_sp_fib6_entry *fib6_entry; |
---|
| 3434 | + |
---|
| 3435 | + /* Unfortunately, in IPv6 the route and the nexthop are described by |
---|
| 3436 | + * the same struct, so we need to iterate over all the routes using the |
---|
| 3437 | + * nexthop group and set / clear the offload indication for them. |
---|
| 3438 | + */ |
---|
| 3439 | + list_for_each_entry(fib6_entry, &nh_grp->fib_list, |
---|
| 3440 | + common.nexthop_group_node) |
---|
| 3441 | + __mlxsw_sp_nexthop6_group_offload_refresh(nh_grp, fib6_entry); |
---|
| 3442 | +} |
---|
| 3443 | + |
---|
| 3444 | +static void |
---|
| 3445 | +mlxsw_sp_nexthop_group_offload_refresh(struct mlxsw_sp *mlxsw_sp, |
---|
| 3446 | + struct mlxsw_sp_nexthop_group *nh_grp) |
---|
| 3447 | +{ |
---|
| 3448 | + switch (mlxsw_sp_nexthop_group_type(nh_grp)) { |
---|
| 3449 | + case AF_INET: |
---|
| 3450 | + mlxsw_sp_nexthop4_group_offload_refresh(mlxsw_sp, nh_grp); |
---|
| 3451 | + break; |
---|
| 3452 | + case AF_INET6: |
---|
| 3453 | + mlxsw_sp_nexthop6_group_offload_refresh(mlxsw_sp, nh_grp); |
---|
| 3454 | + break; |
---|
| 3455 | + } |
---|
| 3456 | +} |
---|
| 3457 | + |
---|
3203 | 3458 | static void |
---|
3204 | 3459 | mlxsw_sp_nexthop_group_refresh(struct mlxsw_sp *mlxsw_sp, |
---|
3205 | 3460 | struct mlxsw_sp_nexthop_group *nh_grp) |
---|
.. | .. |
---|
3273 | 3528 | goto set_trap; |
---|
3274 | 3529 | } |
---|
3275 | 3530 | |
---|
| 3531 | + mlxsw_sp_nexthop_group_offload_refresh(mlxsw_sp, nh_grp); |
---|
| 3532 | + |
---|
3276 | 3533 | if (!old_adj_index_valid) { |
---|
3277 | 3534 | /* The trap was set for fib entries, so we have to call |
---|
3278 | 3535 | * fib entry update to unset it and use adjacency index. |
---|
.. | .. |
---|
3294 | 3551 | goto set_trap; |
---|
3295 | 3552 | } |
---|
3296 | 3553 | |
---|
3297 | | - /* Offload state within the group changed, so update the flags. */ |
---|
3298 | | - mlxsw_sp_nexthop_fib_entries_refresh(nh_grp); |
---|
3299 | | - |
---|
3300 | 3554 | return; |
---|
3301 | 3555 | |
---|
3302 | 3556 | set_trap: |
---|
.. | .. |
---|
3309 | 3563 | err = mlxsw_sp_nexthop_fib_entries_update(mlxsw_sp, nh_grp); |
---|
3310 | 3564 | if (err) |
---|
3311 | 3565 | dev_warn(mlxsw_sp->bus_info->dev, "Failed to set traps for fib entries.\n"); |
---|
| 3566 | + mlxsw_sp_nexthop_group_offload_refresh(mlxsw_sp, nh_grp); |
---|
3312 | 3567 | if (old_adj_index_valid) |
---|
3313 | 3568 | mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, |
---|
3314 | 3569 | nh_grp->ecmp_size, nh_grp->adj_index); |
---|
.. | .. |
---|
3506 | 3761 | |
---|
3507 | 3762 | static bool mlxsw_sp_ipip_netdev_ul_up(struct net_device *ol_dev) |
---|
3508 | 3763 | { |
---|
3509 | | - struct net_device *ul_dev = __mlxsw_sp_ipip_netdev_ul_dev_get(ol_dev); |
---|
| 3764 | + struct net_device *ul_dev; |
---|
| 3765 | + bool is_up; |
---|
3510 | 3766 | |
---|
3511 | | - return ul_dev ? (ul_dev->flags & IFF_UP) : true; |
---|
| 3767 | + rcu_read_lock(); |
---|
| 3768 | + ul_dev = __mlxsw_sp_ipip_netdev_ul_dev_get(ol_dev); |
---|
| 3769 | + is_up = ul_dev ? (ul_dev->flags & IFF_UP) : true; |
---|
| 3770 | + rcu_read_unlock(); |
---|
| 3771 | + |
---|
| 3772 | + return is_up; |
---|
3512 | 3773 | } |
---|
3513 | 3774 | |
---|
3514 | 3775 | static void mlxsw_sp_nexthop_ipip_init(struct mlxsw_sp *mlxsw_sp, |
---|
.. | .. |
---|
3542 | 3803 | const struct fib_nh *fib_nh, |
---|
3543 | 3804 | enum mlxsw_sp_ipip_type *p_ipipt) |
---|
3544 | 3805 | { |
---|
3545 | | - struct net_device *dev = fib_nh->nh_dev; |
---|
| 3806 | + struct net_device *dev = fib_nh->fib_nh_dev; |
---|
3546 | 3807 | |
---|
3547 | 3808 | return dev && |
---|
3548 | 3809 | fib_nh->nh_parent->fib_type == RTN_UNICAST && |
---|
.. | .. |
---|
3569 | 3830 | struct fib_nh *fib_nh) |
---|
3570 | 3831 | { |
---|
3571 | 3832 | const struct mlxsw_sp_ipip_ops *ipip_ops; |
---|
3572 | | - struct net_device *dev = fib_nh->nh_dev; |
---|
| 3833 | + struct net_device *dev = fib_nh->fib_nh_dev; |
---|
3573 | 3834 | struct mlxsw_sp_ipip_entry *ipip_entry; |
---|
3574 | 3835 | struct mlxsw_sp_rif *rif; |
---|
3575 | 3836 | int err; |
---|
.. | .. |
---|
3613 | 3874 | struct mlxsw_sp_nexthop *nh, |
---|
3614 | 3875 | struct fib_nh *fib_nh) |
---|
3615 | 3876 | { |
---|
3616 | | - struct net_device *dev = fib_nh->nh_dev; |
---|
| 3877 | + struct net_device *dev = fib_nh->fib_nh_dev; |
---|
3617 | 3878 | struct in_device *in_dev; |
---|
3618 | 3879 | int err; |
---|
3619 | 3880 | |
---|
3620 | 3881 | nh->nh_grp = nh_grp; |
---|
3621 | 3882 | nh->key.fib_nh = fib_nh; |
---|
3622 | 3883 | #ifdef CONFIG_IP_ROUTE_MULTIPATH |
---|
3623 | | - nh->nh_weight = fib_nh->nh_weight; |
---|
| 3884 | + nh->nh_weight = fib_nh->fib_nh_weight; |
---|
3624 | 3885 | #else |
---|
3625 | 3886 | nh->nh_weight = 1; |
---|
3626 | 3887 | #endif |
---|
3627 | | - memcpy(&nh->gw_addr, &fib_nh->nh_gw, sizeof(fib_nh->nh_gw)); |
---|
| 3888 | + memcpy(&nh->gw_addr, &fib_nh->fib_nh_gw4, sizeof(fib_nh->fib_nh_gw4)); |
---|
3628 | 3889 | err = mlxsw_sp_nexthop_insert(mlxsw_sp, nh); |
---|
3629 | 3890 | if (err) |
---|
3630 | 3891 | return err; |
---|
.. | .. |
---|
3635 | 3896 | if (!dev) |
---|
3636 | 3897 | return 0; |
---|
3637 | 3898 | |
---|
3638 | | - in_dev = __in_dev_get_rtnl(dev); |
---|
| 3899 | + rcu_read_lock(); |
---|
| 3900 | + in_dev = __in_dev_get_rcu(dev); |
---|
3639 | 3901 | if (in_dev && IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN(in_dev) && |
---|
3640 | | - fib_nh->nh_flags & RTNH_F_LINKDOWN) |
---|
| 3902 | + fib_nh->fib_nh_flags & RTNH_F_LINKDOWN) { |
---|
| 3903 | + rcu_read_unlock(); |
---|
3641 | 3904 | return 0; |
---|
| 3905 | + } |
---|
| 3906 | + rcu_read_unlock(); |
---|
3642 | 3907 | |
---|
3643 | 3908 | err = mlxsw_sp_nexthop4_type_init(mlxsw_sp, nh, fib_nh); |
---|
3644 | 3909 | if (err) |
---|
.. | .. |
---|
3671 | 3936 | |
---|
3672 | 3937 | key.fib_nh = fib_nh; |
---|
3673 | 3938 | nh = mlxsw_sp_nexthop_lookup(mlxsw_sp, key); |
---|
3674 | | - if (WARN_ON_ONCE(!nh)) |
---|
| 3939 | + if (!nh) |
---|
3675 | 3940 | return; |
---|
3676 | 3941 | |
---|
3677 | 3942 | switch (event) { |
---|
.. | .. |
---|
3734 | 3999 | } |
---|
3735 | 4000 | |
---|
3736 | 4001 | static bool mlxsw_sp_fi_is_gateway(const struct mlxsw_sp *mlxsw_sp, |
---|
3737 | | - const struct fib_info *fi) |
---|
| 4002 | + struct fib_info *fi) |
---|
3738 | 4003 | { |
---|
3739 | | - return fi->fib_nh->nh_scope == RT_SCOPE_LINK || |
---|
3740 | | - mlxsw_sp_nexthop4_ipip_type(mlxsw_sp, fi->fib_nh, NULL); |
---|
| 4004 | + const struct fib_nh *nh = fib_info_nh(fi, 0); |
---|
| 4005 | + |
---|
| 4006 | + return nh->fib_nh_gw_family || |
---|
| 4007 | + mlxsw_sp_nexthop4_ipip_type(mlxsw_sp, nh, NULL); |
---|
3741 | 4008 | } |
---|
3742 | 4009 | |
---|
3743 | 4010 | static struct mlxsw_sp_nexthop_group * |
---|
3744 | 4011 | mlxsw_sp_nexthop4_group_create(struct mlxsw_sp *mlxsw_sp, struct fib_info *fi) |
---|
3745 | 4012 | { |
---|
| 4013 | + unsigned int nhs = fib_info_num_path(fi); |
---|
3746 | 4014 | struct mlxsw_sp_nexthop_group *nh_grp; |
---|
3747 | 4015 | struct mlxsw_sp_nexthop *nh; |
---|
3748 | 4016 | struct fib_nh *fib_nh; |
---|
3749 | | - size_t alloc_size; |
---|
3750 | 4017 | int i; |
---|
3751 | 4018 | int err; |
---|
3752 | 4019 | |
---|
3753 | | - alloc_size = sizeof(*nh_grp) + |
---|
3754 | | - fi->fib_nhs * sizeof(struct mlxsw_sp_nexthop); |
---|
3755 | | - nh_grp = kzalloc(alloc_size, GFP_KERNEL); |
---|
| 4020 | + nh_grp = kzalloc(struct_size(nh_grp, nexthops, nhs), GFP_KERNEL); |
---|
3756 | 4021 | if (!nh_grp) |
---|
3757 | 4022 | return ERR_PTR(-ENOMEM); |
---|
3758 | 4023 | nh_grp->priv = fi; |
---|
.. | .. |
---|
3760 | 4025 | nh_grp->neigh_tbl = &arp_tbl; |
---|
3761 | 4026 | |
---|
3762 | 4027 | nh_grp->gateway = mlxsw_sp_fi_is_gateway(mlxsw_sp, fi); |
---|
3763 | | - nh_grp->count = fi->fib_nhs; |
---|
| 4028 | + nh_grp->count = nhs; |
---|
3764 | 4029 | fib_info_hold(fi); |
---|
3765 | 4030 | for (i = 0; i < nh_grp->count; i++) { |
---|
3766 | 4031 | nh = &nh_grp->nexthops[i]; |
---|
3767 | | - fib_nh = &fi->fib_nh[i]; |
---|
| 4032 | + fib_nh = fib_info_nh(fi, i); |
---|
3768 | 4033 | err = mlxsw_sp_nexthop4_init(mlxsw_sp, nh_grp, nh, fib_nh); |
---|
3769 | 4034 | if (err) |
---|
3770 | 4035 | goto err_nexthop4_init; |
---|
.. | .. |
---|
3861 | 4126 | return !!nh_group->adj_index_valid; |
---|
3862 | 4127 | case MLXSW_SP_FIB_ENTRY_TYPE_LOCAL: |
---|
3863 | 4128 | return !!nh_group->nh_rif; |
---|
| 4129 | + case MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE: |
---|
3864 | 4130 | case MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP: |
---|
| 4131 | + case MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP: |
---|
3865 | 4132 | return true; |
---|
3866 | 4133 | default: |
---|
3867 | 4134 | return false; |
---|
.. | .. |
---|
3878 | 4145 | struct mlxsw_sp_nexthop *nh = &nh_grp->nexthops[i]; |
---|
3879 | 4146 | struct fib6_info *rt = mlxsw_sp_rt6->rt; |
---|
3880 | 4147 | |
---|
3881 | | - if (nh->rif && nh->rif->dev == rt->fib6_nh.nh_dev && |
---|
| 4148 | + if (nh->rif && nh->rif->dev == rt->fib6_nh->fib_nh_dev && |
---|
3882 | 4149 | ipv6_addr_equal((const struct in6_addr *) &nh->gw_addr, |
---|
3883 | | - &rt->fib6_nh.nh_gw)) |
---|
| 4150 | + &rt->fib6_nh->fib_nh_gw6)) |
---|
3884 | 4151 | return nh; |
---|
3885 | 4152 | continue; |
---|
3886 | 4153 | } |
---|
.. | .. |
---|
3889 | 4156 | } |
---|
3890 | 4157 | |
---|
3891 | 4158 | static void |
---|
3892 | | -mlxsw_sp_fib4_entry_offload_set(struct mlxsw_sp_fib_entry *fib_entry) |
---|
| 4159 | +mlxsw_sp_fib4_entry_hw_flags_set(struct mlxsw_sp *mlxsw_sp, |
---|
| 4160 | + struct mlxsw_sp_fib_entry *fib_entry) |
---|
3893 | 4161 | { |
---|
3894 | | - struct mlxsw_sp_nexthop_group *nh_grp = fib_entry->nh_group; |
---|
3895 | | - int i; |
---|
| 4162 | + struct fib_info *fi = mlxsw_sp_nexthop4_group_fi(fib_entry->nh_group); |
---|
| 4163 | + u32 *p_dst = (u32 *) fib_entry->fib_node->key.addr; |
---|
| 4164 | + int dst_len = fib_entry->fib_node->key.prefix_len; |
---|
| 4165 | + struct mlxsw_sp_fib4_entry *fib4_entry; |
---|
| 4166 | + struct fib_rt_info fri; |
---|
| 4167 | + bool should_offload; |
---|
3896 | 4168 | |
---|
3897 | | - if (fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_LOCAL || |
---|
3898 | | - fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP) { |
---|
3899 | | - nh_grp->nexthops->key.fib_nh->nh_flags |= RTNH_F_OFFLOAD; |
---|
3900 | | - return; |
---|
3901 | | - } |
---|
3902 | | - |
---|
3903 | | - for (i = 0; i < nh_grp->count; i++) { |
---|
3904 | | - struct mlxsw_sp_nexthop *nh = &nh_grp->nexthops[i]; |
---|
3905 | | - |
---|
3906 | | - if (nh->offloaded) |
---|
3907 | | - nh->key.fib_nh->nh_flags |= RTNH_F_OFFLOAD; |
---|
3908 | | - else |
---|
3909 | | - nh->key.fib_nh->nh_flags &= ~RTNH_F_OFFLOAD; |
---|
3910 | | - } |
---|
| 4169 | + should_offload = mlxsw_sp_fib_entry_should_offload(fib_entry); |
---|
| 4170 | + fib4_entry = container_of(fib_entry, struct mlxsw_sp_fib4_entry, |
---|
| 4171 | + common); |
---|
| 4172 | + fri.fi = fi; |
---|
| 4173 | + fri.tb_id = fib4_entry->tb_id; |
---|
| 4174 | + fri.dst = cpu_to_be32(*p_dst); |
---|
| 4175 | + fri.dst_len = dst_len; |
---|
| 4176 | + fri.tos = fib4_entry->tos; |
---|
| 4177 | + fri.type = fib4_entry->type; |
---|
| 4178 | + fri.offload = should_offload; |
---|
| 4179 | + fri.trap = !should_offload; |
---|
| 4180 | + fib_alias_hw_flags_set(mlxsw_sp_net(mlxsw_sp), &fri); |
---|
3911 | 4181 | } |
---|
3912 | 4182 | |
---|
3913 | 4183 | static void |
---|
3914 | | -mlxsw_sp_fib4_entry_offload_unset(struct mlxsw_sp_fib_entry *fib_entry) |
---|
| 4184 | +mlxsw_sp_fib4_entry_hw_flags_clear(struct mlxsw_sp *mlxsw_sp, |
---|
| 4185 | + struct mlxsw_sp_fib_entry *fib_entry) |
---|
3915 | 4186 | { |
---|
3916 | | - struct mlxsw_sp_nexthop_group *nh_grp = fib_entry->nh_group; |
---|
3917 | | - int i; |
---|
| 4187 | + struct fib_info *fi = mlxsw_sp_nexthop4_group_fi(fib_entry->nh_group); |
---|
| 4188 | + u32 *p_dst = (u32 *) fib_entry->fib_node->key.addr; |
---|
| 4189 | + int dst_len = fib_entry->fib_node->key.prefix_len; |
---|
| 4190 | + struct mlxsw_sp_fib4_entry *fib4_entry; |
---|
| 4191 | + struct fib_rt_info fri; |
---|
3918 | 4192 | |
---|
3919 | | - if (!list_is_singular(&nh_grp->fib_list)) |
---|
3920 | | - return; |
---|
3921 | | - |
---|
3922 | | - for (i = 0; i < nh_grp->count; i++) { |
---|
3923 | | - struct mlxsw_sp_nexthop *nh = &nh_grp->nexthops[i]; |
---|
3924 | | - |
---|
3925 | | - nh->key.fib_nh->nh_flags &= ~RTNH_F_OFFLOAD; |
---|
3926 | | - } |
---|
| 4193 | + fib4_entry = container_of(fib_entry, struct mlxsw_sp_fib4_entry, |
---|
| 4194 | + common); |
---|
| 4195 | + fri.fi = fi; |
---|
| 4196 | + fri.tb_id = fib4_entry->tb_id; |
---|
| 4197 | + fri.dst = cpu_to_be32(*p_dst); |
---|
| 4198 | + fri.dst_len = dst_len; |
---|
| 4199 | + fri.tos = fib4_entry->tos; |
---|
| 4200 | + fri.type = fib4_entry->type; |
---|
| 4201 | + fri.offload = false; |
---|
| 4202 | + fri.trap = false; |
---|
| 4203 | + fib_alias_hw_flags_set(mlxsw_sp_net(mlxsw_sp), &fri); |
---|
3927 | 4204 | } |
---|
3928 | 4205 | |
---|
3929 | 4206 | static void |
---|
3930 | | -mlxsw_sp_fib6_entry_offload_set(struct mlxsw_sp_fib_entry *fib_entry) |
---|
| 4207 | +mlxsw_sp_fib6_entry_hw_flags_set(struct mlxsw_sp *mlxsw_sp, |
---|
| 4208 | + struct mlxsw_sp_fib_entry *fib_entry) |
---|
| 4209 | +{ |
---|
| 4210 | + struct mlxsw_sp_fib6_entry *fib6_entry; |
---|
| 4211 | + struct mlxsw_sp_rt6 *mlxsw_sp_rt6; |
---|
| 4212 | + bool should_offload; |
---|
| 4213 | + |
---|
| 4214 | + should_offload = mlxsw_sp_fib_entry_should_offload(fib_entry); |
---|
| 4215 | + |
---|
| 4216 | + /* In IPv6 a multipath route is represented using multiple routes, so |
---|
| 4217 | + * we need to set the flags on all of them. |
---|
| 4218 | + */ |
---|
| 4219 | + fib6_entry = container_of(fib_entry, struct mlxsw_sp_fib6_entry, |
---|
| 4220 | + common); |
---|
| 4221 | + list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list) |
---|
| 4222 | + fib6_info_hw_flags_set(mlxsw_sp_rt6->rt, should_offload, |
---|
| 4223 | + !should_offload); |
---|
| 4224 | +} |
---|
| 4225 | + |
---|
| 4226 | +static void |
---|
| 4227 | +mlxsw_sp_fib6_entry_hw_flags_clear(struct mlxsw_sp *mlxsw_sp, |
---|
| 4228 | + struct mlxsw_sp_fib_entry *fib_entry) |
---|
3931 | 4229 | { |
---|
3932 | 4230 | struct mlxsw_sp_fib6_entry *fib6_entry; |
---|
3933 | 4231 | struct mlxsw_sp_rt6 *mlxsw_sp_rt6; |
---|
3934 | 4232 | |
---|
3935 | 4233 | fib6_entry = container_of(fib_entry, struct mlxsw_sp_fib6_entry, |
---|
3936 | 4234 | common); |
---|
3937 | | - |
---|
3938 | | - if (fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_LOCAL) { |
---|
3939 | | - list_first_entry(&fib6_entry->rt6_list, struct mlxsw_sp_rt6, |
---|
3940 | | - list)->rt->fib6_nh.nh_flags |= RTNH_F_OFFLOAD; |
---|
3941 | | - return; |
---|
3942 | | - } |
---|
3943 | | - |
---|
3944 | | - list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list) { |
---|
3945 | | - struct mlxsw_sp_nexthop_group *nh_grp = fib_entry->nh_group; |
---|
3946 | | - struct mlxsw_sp_nexthop *nh; |
---|
3947 | | - |
---|
3948 | | - nh = mlxsw_sp_rt6_nexthop(nh_grp, mlxsw_sp_rt6); |
---|
3949 | | - if (nh && nh->offloaded) |
---|
3950 | | - mlxsw_sp_rt6->rt->fib6_nh.nh_flags |= RTNH_F_OFFLOAD; |
---|
3951 | | - else |
---|
3952 | | - mlxsw_sp_rt6->rt->fib6_nh.nh_flags &= ~RTNH_F_OFFLOAD; |
---|
3953 | | - } |
---|
| 4235 | + list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list) |
---|
| 4236 | + fib6_info_hw_flags_set(mlxsw_sp_rt6->rt, false, false); |
---|
3954 | 4237 | } |
---|
3955 | 4238 | |
---|
3956 | 4239 | static void |
---|
3957 | | -mlxsw_sp_fib6_entry_offload_unset(struct mlxsw_sp_fib_entry *fib_entry) |
---|
3958 | | -{ |
---|
3959 | | - struct mlxsw_sp_fib6_entry *fib6_entry; |
---|
3960 | | - struct mlxsw_sp_rt6 *mlxsw_sp_rt6; |
---|
3961 | | - |
---|
3962 | | - fib6_entry = container_of(fib_entry, struct mlxsw_sp_fib6_entry, |
---|
3963 | | - common); |
---|
3964 | | - list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list) { |
---|
3965 | | - struct fib6_info *rt = mlxsw_sp_rt6->rt; |
---|
3966 | | - |
---|
3967 | | - rt->fib6_nh.nh_flags &= ~RTNH_F_OFFLOAD; |
---|
3968 | | - } |
---|
3969 | | -} |
---|
3970 | | - |
---|
3971 | | -static void mlxsw_sp_fib_entry_offload_set(struct mlxsw_sp_fib_entry *fib_entry) |
---|
| 4240 | +mlxsw_sp_fib_entry_hw_flags_set(struct mlxsw_sp *mlxsw_sp, |
---|
| 4241 | + struct mlxsw_sp_fib_entry *fib_entry) |
---|
3972 | 4242 | { |
---|
3973 | 4243 | switch (fib_entry->fib_node->fib->proto) { |
---|
3974 | 4244 | case MLXSW_SP_L3_PROTO_IPV4: |
---|
3975 | | - mlxsw_sp_fib4_entry_offload_set(fib_entry); |
---|
| 4245 | + mlxsw_sp_fib4_entry_hw_flags_set(mlxsw_sp, fib_entry); |
---|
3976 | 4246 | break; |
---|
3977 | 4247 | case MLXSW_SP_L3_PROTO_IPV6: |
---|
3978 | | - mlxsw_sp_fib6_entry_offload_set(fib_entry); |
---|
| 4248 | + mlxsw_sp_fib6_entry_hw_flags_set(mlxsw_sp, fib_entry); |
---|
3979 | 4249 | break; |
---|
3980 | 4250 | } |
---|
3981 | 4251 | } |
---|
3982 | 4252 | |
---|
3983 | 4253 | static void |
---|
3984 | | -mlxsw_sp_fib_entry_offload_unset(struct mlxsw_sp_fib_entry *fib_entry) |
---|
| 4254 | +mlxsw_sp_fib_entry_hw_flags_clear(struct mlxsw_sp *mlxsw_sp, |
---|
| 4255 | + struct mlxsw_sp_fib_entry *fib_entry) |
---|
3985 | 4256 | { |
---|
3986 | 4257 | switch (fib_entry->fib_node->fib->proto) { |
---|
3987 | 4258 | case MLXSW_SP_L3_PROTO_IPV4: |
---|
3988 | | - mlxsw_sp_fib4_entry_offload_unset(fib_entry); |
---|
| 4259 | + mlxsw_sp_fib4_entry_hw_flags_clear(mlxsw_sp, fib_entry); |
---|
3989 | 4260 | break; |
---|
3990 | 4261 | case MLXSW_SP_L3_PROTO_IPV6: |
---|
3991 | | - mlxsw_sp_fib6_entry_offload_unset(fib_entry); |
---|
| 4262 | + mlxsw_sp_fib6_entry_hw_flags_clear(mlxsw_sp, fib_entry); |
---|
3992 | 4263 | break; |
---|
3993 | 4264 | } |
---|
3994 | 4265 | } |
---|
3995 | 4266 | |
---|
3996 | 4267 | static void |
---|
3997 | | -mlxsw_sp_fib_entry_offload_refresh(struct mlxsw_sp_fib_entry *fib_entry, |
---|
3998 | | - enum mlxsw_reg_ralue_op op, int err) |
---|
| 4268 | +mlxsw_sp_fib_entry_hw_flags_refresh(struct mlxsw_sp *mlxsw_sp, |
---|
| 4269 | + struct mlxsw_sp_fib_entry *fib_entry, |
---|
| 4270 | + enum mlxsw_reg_ralue_op op) |
---|
3999 | 4271 | { |
---|
4000 | 4272 | switch (op) { |
---|
4001 | | - case MLXSW_REG_RALUE_OP_WRITE_DELETE: |
---|
4002 | | - return mlxsw_sp_fib_entry_offload_unset(fib_entry); |
---|
4003 | 4273 | case MLXSW_REG_RALUE_OP_WRITE_WRITE: |
---|
4004 | | - if (err) |
---|
4005 | | - return; |
---|
4006 | | - if (mlxsw_sp_fib_entry_should_offload(fib_entry)) |
---|
4007 | | - mlxsw_sp_fib_entry_offload_set(fib_entry); |
---|
4008 | | - else |
---|
4009 | | - mlxsw_sp_fib_entry_offload_unset(fib_entry); |
---|
4010 | | - return; |
---|
| 4274 | + mlxsw_sp_fib_entry_hw_flags_set(mlxsw_sp, fib_entry); |
---|
| 4275 | + break; |
---|
| 4276 | + case MLXSW_REG_RALUE_OP_WRITE_DELETE: |
---|
| 4277 | + mlxsw_sp_fib_entry_hw_flags_clear(mlxsw_sp, fib_entry); |
---|
| 4278 | + break; |
---|
4011 | 4279 | default: |
---|
4012 | | - return; |
---|
| 4280 | + break; |
---|
4013 | 4281 | } |
---|
4014 | 4282 | } |
---|
4015 | 4283 | |
---|
.. | .. |
---|
4039 | 4307 | } |
---|
4040 | 4308 | } |
---|
4041 | 4309 | |
---|
| 4310 | +static int mlxsw_sp_adj_discard_write(struct mlxsw_sp *mlxsw_sp, u16 rif_index) |
---|
| 4311 | +{ |
---|
| 4312 | + enum mlxsw_reg_ratr_trap_action trap_action; |
---|
| 4313 | + char ratr_pl[MLXSW_REG_RATR_LEN]; |
---|
| 4314 | + int err; |
---|
| 4315 | + |
---|
| 4316 | + if (mlxsw_sp->router->adj_discard_index_valid) |
---|
| 4317 | + return 0; |
---|
| 4318 | + |
---|
| 4319 | + err = mlxsw_sp_kvdl_alloc(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1, |
---|
| 4320 | + &mlxsw_sp->router->adj_discard_index); |
---|
| 4321 | + if (err) |
---|
| 4322 | + return err; |
---|
| 4323 | + |
---|
| 4324 | + trap_action = MLXSW_REG_RATR_TRAP_ACTION_DISCARD_ERRORS; |
---|
| 4325 | + mlxsw_reg_ratr_pack(ratr_pl, MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY, true, |
---|
| 4326 | + MLXSW_REG_RATR_TYPE_ETHERNET, |
---|
| 4327 | + mlxsw_sp->router->adj_discard_index, rif_index); |
---|
| 4328 | + mlxsw_reg_ratr_trap_action_set(ratr_pl, trap_action); |
---|
| 4329 | + err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ratr), ratr_pl); |
---|
| 4330 | + if (err) |
---|
| 4331 | + goto err_ratr_write; |
---|
| 4332 | + |
---|
| 4333 | + mlxsw_sp->router->adj_discard_index_valid = true; |
---|
| 4334 | + |
---|
| 4335 | + return 0; |
---|
| 4336 | + |
---|
| 4337 | +err_ratr_write: |
---|
| 4338 | + mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1, |
---|
| 4339 | + mlxsw_sp->router->adj_discard_index); |
---|
| 4340 | + return err; |
---|
| 4341 | +} |
---|
| 4342 | + |
---|
4042 | 4343 | static int mlxsw_sp_fib_entry_op_remote(struct mlxsw_sp *mlxsw_sp, |
---|
4043 | 4344 | struct mlxsw_sp_fib_entry *fib_entry, |
---|
4044 | 4345 | enum mlxsw_reg_ralue_op op) |
---|
4045 | 4346 | { |
---|
| 4347 | + struct mlxsw_sp_nexthop_group *nh_group = fib_entry->nh_group; |
---|
4046 | 4348 | char ralue_pl[MLXSW_REG_RALUE_LEN]; |
---|
4047 | 4349 | enum mlxsw_reg_ralue_trap_action trap_action; |
---|
4048 | 4350 | u16 trap_id = 0; |
---|
4049 | 4351 | u32 adjacency_index = 0; |
---|
4050 | 4352 | u16 ecmp_size = 0; |
---|
| 4353 | + int err; |
---|
4051 | 4354 | |
---|
4052 | 4355 | /* In case the nexthop group adjacency index is valid, use it |
---|
4053 | 4356 | * with provided ECMP size. Otherwise, setup trap and pass |
---|
.. | .. |
---|
4057 | 4360 | trap_action = MLXSW_REG_RALUE_TRAP_ACTION_NOP; |
---|
4058 | 4361 | adjacency_index = fib_entry->nh_group->adj_index; |
---|
4059 | 4362 | ecmp_size = fib_entry->nh_group->ecmp_size; |
---|
| 4363 | + } else if (!nh_group->adj_index_valid && nh_group->count && |
---|
| 4364 | + nh_group->nh_rif) { |
---|
| 4365 | + err = mlxsw_sp_adj_discard_write(mlxsw_sp, |
---|
| 4366 | + nh_group->nh_rif->rif_index); |
---|
| 4367 | + if (err) |
---|
| 4368 | + return err; |
---|
| 4369 | + trap_action = MLXSW_REG_RALUE_TRAP_ACTION_NOP; |
---|
| 4370 | + adjacency_index = mlxsw_sp->router->adj_discard_index; |
---|
| 4371 | + ecmp_size = 1; |
---|
4060 | 4372 | } else { |
---|
4061 | 4373 | trap_action = MLXSW_REG_RALUE_TRAP_ACTION_TRAP; |
---|
4062 | 4374 | trap_id = MLXSW_TRAP_ID_RTR_INGRESS0; |
---|
.. | .. |
---|
4103 | 4415 | return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl); |
---|
4104 | 4416 | } |
---|
4105 | 4417 | |
---|
| 4418 | +static int mlxsw_sp_fib_entry_op_blackhole(struct mlxsw_sp *mlxsw_sp, |
---|
| 4419 | + struct mlxsw_sp_fib_entry *fib_entry, |
---|
| 4420 | + enum mlxsw_reg_ralue_op op) |
---|
| 4421 | +{ |
---|
| 4422 | + enum mlxsw_reg_ralue_trap_action trap_action; |
---|
| 4423 | + char ralue_pl[MLXSW_REG_RALUE_LEN]; |
---|
| 4424 | + |
---|
| 4425 | + trap_action = MLXSW_REG_RALUE_TRAP_ACTION_DISCARD_ERROR; |
---|
| 4426 | + mlxsw_sp_fib_entry_ralue_pack(ralue_pl, fib_entry, op); |
---|
| 4427 | + mlxsw_reg_ralue_act_local_pack(ralue_pl, trap_action, 0, 0); |
---|
| 4428 | + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl); |
---|
| 4429 | +} |
---|
| 4430 | + |
---|
| 4431 | +static int |
---|
| 4432 | +mlxsw_sp_fib_entry_op_unreachable(struct mlxsw_sp *mlxsw_sp, |
---|
| 4433 | + struct mlxsw_sp_fib_entry *fib_entry, |
---|
| 4434 | + enum mlxsw_reg_ralue_op op) |
---|
| 4435 | +{ |
---|
| 4436 | + enum mlxsw_reg_ralue_trap_action trap_action; |
---|
| 4437 | + char ralue_pl[MLXSW_REG_RALUE_LEN]; |
---|
| 4438 | + u16 trap_id; |
---|
| 4439 | + |
---|
| 4440 | + trap_action = MLXSW_REG_RALUE_TRAP_ACTION_TRAP; |
---|
| 4441 | + trap_id = MLXSW_TRAP_ID_RTR_INGRESS1; |
---|
| 4442 | + |
---|
| 4443 | + mlxsw_sp_fib_entry_ralue_pack(ralue_pl, fib_entry, op); |
---|
| 4444 | + mlxsw_reg_ralue_act_local_pack(ralue_pl, trap_action, trap_id, 0); |
---|
| 4445 | + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl); |
---|
| 4446 | +} |
---|
| 4447 | + |
---|
4106 | 4448 | static int |
---|
4107 | 4449 | mlxsw_sp_fib_entry_op_ipip_decap(struct mlxsw_sp *mlxsw_sp, |
---|
4108 | 4450 | struct mlxsw_sp_fib_entry *fib_entry, |
---|
.. | .. |
---|
4119 | 4461 | fib_entry->decap.tunnel_index); |
---|
4120 | 4462 | } |
---|
4121 | 4463 | |
---|
| 4464 | +static int mlxsw_sp_fib_entry_op_nve_decap(struct mlxsw_sp *mlxsw_sp, |
---|
| 4465 | + struct mlxsw_sp_fib_entry *fib_entry, |
---|
| 4466 | + enum mlxsw_reg_ralue_op op) |
---|
| 4467 | +{ |
---|
| 4468 | + char ralue_pl[MLXSW_REG_RALUE_LEN]; |
---|
| 4469 | + |
---|
| 4470 | + mlxsw_sp_fib_entry_ralue_pack(ralue_pl, fib_entry, op); |
---|
| 4471 | + mlxsw_reg_ralue_act_ip2me_tun_pack(ralue_pl, |
---|
| 4472 | + fib_entry->decap.tunnel_index); |
---|
| 4473 | + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl); |
---|
| 4474 | +} |
---|
| 4475 | + |
---|
4122 | 4476 | static int __mlxsw_sp_fib_entry_op(struct mlxsw_sp *mlxsw_sp, |
---|
4123 | 4477 | struct mlxsw_sp_fib_entry *fib_entry, |
---|
4124 | 4478 | enum mlxsw_reg_ralue_op op) |
---|
.. | .. |
---|
4130 | 4484 | return mlxsw_sp_fib_entry_op_local(mlxsw_sp, fib_entry, op); |
---|
4131 | 4485 | case MLXSW_SP_FIB_ENTRY_TYPE_TRAP: |
---|
4132 | 4486 | return mlxsw_sp_fib_entry_op_trap(mlxsw_sp, fib_entry, op); |
---|
| 4487 | + case MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE: |
---|
| 4488 | + return mlxsw_sp_fib_entry_op_blackhole(mlxsw_sp, fib_entry, op); |
---|
| 4489 | + case MLXSW_SP_FIB_ENTRY_TYPE_UNREACHABLE: |
---|
| 4490 | + return mlxsw_sp_fib_entry_op_unreachable(mlxsw_sp, fib_entry, |
---|
| 4491 | + op); |
---|
4133 | 4492 | case MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP: |
---|
4134 | 4493 | return mlxsw_sp_fib_entry_op_ipip_decap(mlxsw_sp, |
---|
4135 | 4494 | fib_entry, op); |
---|
| 4495 | + case MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP: |
---|
| 4496 | + return mlxsw_sp_fib_entry_op_nve_decap(mlxsw_sp, fib_entry, op); |
---|
4136 | 4497 | } |
---|
4137 | 4498 | return -EINVAL; |
---|
4138 | 4499 | } |
---|
.. | .. |
---|
4143 | 4504 | { |
---|
4144 | 4505 | int err = __mlxsw_sp_fib_entry_op(mlxsw_sp, fib_entry, op); |
---|
4145 | 4506 | |
---|
4146 | | - mlxsw_sp_fib_entry_offload_refresh(fib_entry, op, err); |
---|
| 4507 | + if (err) |
---|
| 4508 | + return err; |
---|
| 4509 | + |
---|
| 4510 | + mlxsw_sp_fib_entry_hw_flags_refresh(mlxsw_sp, fib_entry, op); |
---|
4147 | 4511 | |
---|
4148 | 4512 | return err; |
---|
4149 | 4513 | } |
---|
.. | .. |
---|
4167 | 4531 | const struct fib_entry_notifier_info *fen_info, |
---|
4168 | 4532 | struct mlxsw_sp_fib_entry *fib_entry) |
---|
4169 | 4533 | { |
---|
| 4534 | + struct net_device *dev = fib_info_nh(fen_info->fi, 0)->fib_nh_dev; |
---|
4170 | 4535 | union mlxsw_sp_l3addr dip = { .addr4 = htonl(fen_info->dst) }; |
---|
4171 | | - struct net_device *dev = fen_info->fi->fib_dev; |
---|
| 4536 | + struct mlxsw_sp_router *router = mlxsw_sp->router; |
---|
| 4537 | + u32 tb_id = mlxsw_sp_fix_tb_id(fen_info->tb_id); |
---|
4172 | 4538 | struct mlxsw_sp_ipip_entry *ipip_entry; |
---|
4173 | 4539 | struct fib_info *fi = fen_info->fi; |
---|
4174 | 4540 | |
---|
.. | .. |
---|
4182 | 4548 | fib_entry, |
---|
4183 | 4549 | ipip_entry); |
---|
4184 | 4550 | } |
---|
4185 | | - /* fall through */ |
---|
| 4551 | + if (mlxsw_sp_router_nve_is_decap(mlxsw_sp, tb_id, |
---|
| 4552 | + MLXSW_SP_L3_PROTO_IPV4, |
---|
| 4553 | + &dip)) { |
---|
| 4554 | + u32 tunnel_index; |
---|
| 4555 | + |
---|
| 4556 | + tunnel_index = router->nve_decap_config.tunnel_index; |
---|
| 4557 | + fib_entry->decap.tunnel_index = tunnel_index; |
---|
| 4558 | + fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP; |
---|
| 4559 | + return 0; |
---|
| 4560 | + } |
---|
| 4561 | + fallthrough; |
---|
4186 | 4562 | case RTN_BROADCAST: |
---|
4187 | 4563 | fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP; |
---|
4188 | 4564 | return 0; |
---|
4189 | | - case RTN_UNREACHABLE: /* fall through */ |
---|
4190 | | - case RTN_BLACKHOLE: /* fall through */ |
---|
| 4565 | + case RTN_BLACKHOLE: |
---|
| 4566 | + fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE; |
---|
| 4567 | + return 0; |
---|
| 4568 | + case RTN_UNREACHABLE: |
---|
4191 | 4569 | case RTN_PROHIBIT: |
---|
4192 | 4570 | /* Packets hitting these routes need to be trapped, but |
---|
4193 | 4571 | * can do so with a lower priority than packets directed |
---|
4194 | 4572 | * at the host, so use action type local instead of trap. |
---|
4195 | 4573 | */ |
---|
4196 | | - fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_LOCAL; |
---|
| 4574 | + fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_UNREACHABLE; |
---|
4197 | 4575 | return 0; |
---|
4198 | 4576 | case RTN_UNICAST: |
---|
4199 | 4577 | if (mlxsw_sp_fi_is_gateway(mlxsw_sp, fi)) |
---|
.. | .. |
---|
4203 | 4581 | return 0; |
---|
4204 | 4582 | default: |
---|
4205 | 4583 | return -EINVAL; |
---|
| 4584 | + } |
---|
| 4585 | +} |
---|
| 4586 | + |
---|
| 4587 | +static void |
---|
| 4588 | +mlxsw_sp_fib4_entry_type_unset(struct mlxsw_sp *mlxsw_sp, |
---|
| 4589 | + struct mlxsw_sp_fib_entry *fib_entry) |
---|
| 4590 | +{ |
---|
| 4591 | + switch (fib_entry->type) { |
---|
| 4592 | + case MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP: |
---|
| 4593 | + mlxsw_sp_fib_entry_decap_fini(mlxsw_sp, fib_entry); |
---|
| 4594 | + break; |
---|
| 4595 | + default: |
---|
| 4596 | + break; |
---|
4206 | 4597 | } |
---|
4207 | 4598 | } |
---|
4208 | 4599 | |
---|
.. | .. |
---|
4238 | 4629 | return fib4_entry; |
---|
4239 | 4630 | |
---|
4240 | 4631 | err_nexthop4_group_get: |
---|
| 4632 | + mlxsw_sp_fib4_entry_type_unset(mlxsw_sp, fib_entry); |
---|
4241 | 4633 | err_fib4_entry_type_set: |
---|
4242 | 4634 | kfree(fib4_entry); |
---|
4243 | 4635 | return ERR_PTR(err); |
---|
.. | .. |
---|
4247 | 4639 | struct mlxsw_sp_fib4_entry *fib4_entry) |
---|
4248 | 4640 | { |
---|
4249 | 4641 | mlxsw_sp_nexthop4_group_put(mlxsw_sp, &fib4_entry->common); |
---|
| 4642 | + mlxsw_sp_fib4_entry_type_unset(mlxsw_sp, &fib4_entry->common); |
---|
4250 | 4643 | kfree(fib4_entry); |
---|
4251 | 4644 | } |
---|
4252 | 4645 | |
---|
.. | .. |
---|
4270 | 4663 | if (!fib_node) |
---|
4271 | 4664 | return NULL; |
---|
4272 | 4665 | |
---|
4273 | | - list_for_each_entry(fib4_entry, &fib_node->entry_list, common.list) { |
---|
4274 | | - if (fib4_entry->tb_id == fen_info->tb_id && |
---|
4275 | | - fib4_entry->tos == fen_info->tos && |
---|
4276 | | - fib4_entry->type == fen_info->type && |
---|
4277 | | - mlxsw_sp_nexthop4_group_fi(fib4_entry->common.nh_group) == |
---|
4278 | | - fen_info->fi) { |
---|
4279 | | - return fib4_entry; |
---|
4280 | | - } |
---|
4281 | | - } |
---|
| 4666 | + fib4_entry = container_of(fib_node->fib_entry, |
---|
| 4667 | + struct mlxsw_sp_fib4_entry, common); |
---|
| 4668 | + if (fib4_entry->tb_id == fen_info->tb_id && |
---|
| 4669 | + fib4_entry->tos == fen_info->tos && |
---|
| 4670 | + fib4_entry->type == fen_info->type && |
---|
| 4671 | + mlxsw_sp_nexthop4_group_fi(fib4_entry->common.nh_group) == |
---|
| 4672 | + fen_info->fi) |
---|
| 4673 | + return fib4_entry; |
---|
4282 | 4674 | |
---|
4283 | 4675 | return NULL; |
---|
4284 | 4676 | } |
---|
.. | .. |
---|
4326 | 4718 | if (!fib_node) |
---|
4327 | 4719 | return NULL; |
---|
4328 | 4720 | |
---|
4329 | | - INIT_LIST_HEAD(&fib_node->entry_list); |
---|
4330 | 4721 | list_add(&fib_node->list, &fib->node_list); |
---|
4331 | 4722 | memcpy(fib_node->key.addr, addr, addr_len); |
---|
4332 | 4723 | fib_node->key.prefix_len = prefix_len; |
---|
.. | .. |
---|
4337 | 4728 | static void mlxsw_sp_fib_node_destroy(struct mlxsw_sp_fib_node *fib_node) |
---|
4338 | 4729 | { |
---|
4339 | 4730 | list_del(&fib_node->list); |
---|
4340 | | - WARN_ON(!list_empty(&fib_node->entry_list)); |
---|
4341 | 4731 | kfree(fib_node); |
---|
4342 | | -} |
---|
4343 | | - |
---|
4344 | | -static bool |
---|
4345 | | -mlxsw_sp_fib_node_entry_is_first(const struct mlxsw_sp_fib_node *fib_node, |
---|
4346 | | - const struct mlxsw_sp_fib_entry *fib_entry) |
---|
4347 | | -{ |
---|
4348 | | - return list_first_entry(&fib_node->entry_list, |
---|
4349 | | - struct mlxsw_sp_fib_entry, list) == fib_entry; |
---|
4350 | 4732 | } |
---|
4351 | 4733 | |
---|
4352 | 4734 | static int mlxsw_sp_fib_lpm_tree_link(struct mlxsw_sp *mlxsw_sp, |
---|
.. | .. |
---|
4488 | 4870 | { |
---|
4489 | 4871 | struct mlxsw_sp_vr *vr = fib_node->fib->vr; |
---|
4490 | 4872 | |
---|
4491 | | - if (!list_empty(&fib_node->entry_list)) |
---|
| 4873 | + if (fib_node->fib_entry) |
---|
4492 | 4874 | return; |
---|
4493 | 4875 | mlxsw_sp_fib_node_fini(mlxsw_sp, fib_node); |
---|
4494 | 4876 | mlxsw_sp_fib_node_destroy(fib_node); |
---|
4495 | 4877 | mlxsw_sp_vr_put(mlxsw_sp, vr); |
---|
4496 | 4878 | } |
---|
4497 | 4879 | |
---|
4498 | | -static struct mlxsw_sp_fib4_entry * |
---|
4499 | | -mlxsw_sp_fib4_node_entry_find(const struct mlxsw_sp_fib_node *fib_node, |
---|
4500 | | - const struct mlxsw_sp_fib4_entry *new4_entry) |
---|
4501 | | -{ |
---|
4502 | | - struct mlxsw_sp_fib4_entry *fib4_entry; |
---|
4503 | | - |
---|
4504 | | - list_for_each_entry(fib4_entry, &fib_node->entry_list, common.list) { |
---|
4505 | | - if (fib4_entry->tb_id > new4_entry->tb_id) |
---|
4506 | | - continue; |
---|
4507 | | - if (fib4_entry->tb_id != new4_entry->tb_id) |
---|
4508 | | - break; |
---|
4509 | | - if (fib4_entry->tos > new4_entry->tos) |
---|
4510 | | - continue; |
---|
4511 | | - if (fib4_entry->prio >= new4_entry->prio || |
---|
4512 | | - fib4_entry->tos < new4_entry->tos) |
---|
4513 | | - return fib4_entry; |
---|
4514 | | - } |
---|
4515 | | - |
---|
4516 | | - return NULL; |
---|
4517 | | -} |
---|
4518 | | - |
---|
4519 | | -static int |
---|
4520 | | -mlxsw_sp_fib4_node_list_append(struct mlxsw_sp_fib4_entry *fib4_entry, |
---|
4521 | | - struct mlxsw_sp_fib4_entry *new4_entry) |
---|
4522 | | -{ |
---|
4523 | | - struct mlxsw_sp_fib_node *fib_node; |
---|
4524 | | - |
---|
4525 | | - if (WARN_ON(!fib4_entry)) |
---|
4526 | | - return -EINVAL; |
---|
4527 | | - |
---|
4528 | | - fib_node = fib4_entry->common.fib_node; |
---|
4529 | | - list_for_each_entry_from(fib4_entry, &fib_node->entry_list, |
---|
4530 | | - common.list) { |
---|
4531 | | - if (fib4_entry->tb_id != new4_entry->tb_id || |
---|
4532 | | - fib4_entry->tos != new4_entry->tos || |
---|
4533 | | - fib4_entry->prio != new4_entry->prio) |
---|
4534 | | - break; |
---|
4535 | | - } |
---|
4536 | | - |
---|
4537 | | - list_add_tail(&new4_entry->common.list, &fib4_entry->common.list); |
---|
4538 | | - return 0; |
---|
4539 | | -} |
---|
4540 | | - |
---|
4541 | | -static int |
---|
4542 | | -mlxsw_sp_fib4_node_list_insert(struct mlxsw_sp_fib4_entry *new4_entry, |
---|
4543 | | - bool replace, bool append) |
---|
4544 | | -{ |
---|
4545 | | - struct mlxsw_sp_fib_node *fib_node = new4_entry->common.fib_node; |
---|
4546 | | - struct mlxsw_sp_fib4_entry *fib4_entry; |
---|
4547 | | - |
---|
4548 | | - fib4_entry = mlxsw_sp_fib4_node_entry_find(fib_node, new4_entry); |
---|
4549 | | - |
---|
4550 | | - if (append) |
---|
4551 | | - return mlxsw_sp_fib4_node_list_append(fib4_entry, new4_entry); |
---|
4552 | | - if (replace && WARN_ON(!fib4_entry)) |
---|
4553 | | - return -EINVAL; |
---|
4554 | | - |
---|
4555 | | - /* Insert new entry before replaced one, so that we can later |
---|
4556 | | - * remove the second. |
---|
4557 | | - */ |
---|
4558 | | - if (fib4_entry) { |
---|
4559 | | - list_add_tail(&new4_entry->common.list, |
---|
4560 | | - &fib4_entry->common.list); |
---|
4561 | | - } else { |
---|
4562 | | - struct mlxsw_sp_fib4_entry *last; |
---|
4563 | | - |
---|
4564 | | - list_for_each_entry(last, &fib_node->entry_list, common.list) { |
---|
4565 | | - if (new4_entry->tb_id > last->tb_id) |
---|
4566 | | - break; |
---|
4567 | | - fib4_entry = last; |
---|
4568 | | - } |
---|
4569 | | - |
---|
4570 | | - if (fib4_entry) |
---|
4571 | | - list_add(&new4_entry->common.list, |
---|
4572 | | - &fib4_entry->common.list); |
---|
4573 | | - else |
---|
4574 | | - list_add(&new4_entry->common.list, |
---|
4575 | | - &fib_node->entry_list); |
---|
4576 | | - } |
---|
4577 | | - |
---|
4578 | | - return 0; |
---|
4579 | | -} |
---|
4580 | | - |
---|
4581 | | -static void |
---|
4582 | | -mlxsw_sp_fib4_node_list_remove(struct mlxsw_sp_fib4_entry *fib4_entry) |
---|
4583 | | -{ |
---|
4584 | | - list_del(&fib4_entry->common.list); |
---|
4585 | | -} |
---|
4586 | | - |
---|
4587 | | -static int mlxsw_sp_fib_node_entry_add(struct mlxsw_sp *mlxsw_sp, |
---|
4588 | | - struct mlxsw_sp_fib_entry *fib_entry) |
---|
4589 | | -{ |
---|
4590 | | - struct mlxsw_sp_fib_node *fib_node = fib_entry->fib_node; |
---|
4591 | | - |
---|
4592 | | - if (!mlxsw_sp_fib_node_entry_is_first(fib_node, fib_entry)) |
---|
4593 | | - return 0; |
---|
4594 | | - |
---|
4595 | | - /* To prevent packet loss, overwrite the previously offloaded |
---|
4596 | | - * entry. |
---|
4597 | | - */ |
---|
4598 | | - if (!list_is_singular(&fib_node->entry_list)) { |
---|
4599 | | - enum mlxsw_reg_ralue_op op = MLXSW_REG_RALUE_OP_WRITE_DELETE; |
---|
4600 | | - struct mlxsw_sp_fib_entry *n = list_next_entry(fib_entry, list); |
---|
4601 | | - |
---|
4602 | | - mlxsw_sp_fib_entry_offload_refresh(n, op, 0); |
---|
4603 | | - } |
---|
4604 | | - |
---|
4605 | | - return mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry); |
---|
4606 | | -} |
---|
4607 | | - |
---|
4608 | | -static void mlxsw_sp_fib_node_entry_del(struct mlxsw_sp *mlxsw_sp, |
---|
| 4880 | +static int mlxsw_sp_fib_node_entry_link(struct mlxsw_sp *mlxsw_sp, |
---|
4609 | 4881 | struct mlxsw_sp_fib_entry *fib_entry) |
---|
4610 | 4882 | { |
---|
4611 | 4883 | struct mlxsw_sp_fib_node *fib_node = fib_entry->fib_node; |
---|
4612 | | - |
---|
4613 | | - if (!mlxsw_sp_fib_node_entry_is_first(fib_node, fib_entry)) |
---|
4614 | | - return; |
---|
4615 | | - |
---|
4616 | | - /* Promote the next entry by overwriting the deleted entry */ |
---|
4617 | | - if (!list_is_singular(&fib_node->entry_list)) { |
---|
4618 | | - struct mlxsw_sp_fib_entry *n = list_next_entry(fib_entry, list); |
---|
4619 | | - enum mlxsw_reg_ralue_op op = MLXSW_REG_RALUE_OP_WRITE_DELETE; |
---|
4620 | | - |
---|
4621 | | - mlxsw_sp_fib_entry_update(mlxsw_sp, n); |
---|
4622 | | - mlxsw_sp_fib_entry_offload_refresh(fib_entry, op, 0); |
---|
4623 | | - return; |
---|
4624 | | - } |
---|
4625 | | - |
---|
4626 | | - mlxsw_sp_fib_entry_del(mlxsw_sp, fib_entry); |
---|
4627 | | -} |
---|
4628 | | - |
---|
4629 | | -static int mlxsw_sp_fib4_node_entry_link(struct mlxsw_sp *mlxsw_sp, |
---|
4630 | | - struct mlxsw_sp_fib4_entry *fib4_entry, |
---|
4631 | | - bool replace, bool append) |
---|
4632 | | -{ |
---|
4633 | 4884 | int err; |
---|
4634 | 4885 | |
---|
4635 | | - err = mlxsw_sp_fib4_node_list_insert(fib4_entry, replace, append); |
---|
4636 | | - if (err) |
---|
4637 | | - return err; |
---|
| 4886 | + fib_node->fib_entry = fib_entry; |
---|
4638 | 4887 | |
---|
4639 | | - err = mlxsw_sp_fib_node_entry_add(mlxsw_sp, &fib4_entry->common); |
---|
| 4888 | + err = mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry); |
---|
4640 | 4889 | if (err) |
---|
4641 | | - goto err_fib_node_entry_add; |
---|
| 4890 | + goto err_fib_entry_update; |
---|
4642 | 4891 | |
---|
4643 | 4892 | return 0; |
---|
4644 | 4893 | |
---|
4645 | | -err_fib_node_entry_add: |
---|
4646 | | - mlxsw_sp_fib4_node_list_remove(fib4_entry); |
---|
| 4894 | +err_fib_entry_update: |
---|
| 4895 | + fib_node->fib_entry = NULL; |
---|
4647 | 4896 | return err; |
---|
4648 | 4897 | } |
---|
4649 | 4898 | |
---|
4650 | 4899 | static void |
---|
4651 | | -mlxsw_sp_fib4_node_entry_unlink(struct mlxsw_sp *mlxsw_sp, |
---|
4652 | | - struct mlxsw_sp_fib4_entry *fib4_entry) |
---|
| 4900 | +mlxsw_sp_fib_node_entry_unlink(struct mlxsw_sp *mlxsw_sp, |
---|
| 4901 | + struct mlxsw_sp_fib_entry *fib_entry) |
---|
4653 | 4902 | { |
---|
4654 | | - mlxsw_sp_fib_node_entry_del(mlxsw_sp, &fib4_entry->common); |
---|
4655 | | - mlxsw_sp_fib4_node_list_remove(fib4_entry); |
---|
| 4903 | + struct mlxsw_sp_fib_node *fib_node = fib_entry->fib_node; |
---|
4656 | 4904 | |
---|
4657 | | - if (fib4_entry->common.type == MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP) |
---|
4658 | | - mlxsw_sp_fib_entry_decap_fini(mlxsw_sp, &fib4_entry->common); |
---|
| 4905 | + mlxsw_sp_fib_entry_del(mlxsw_sp, fib_entry); |
---|
| 4906 | + fib_node->fib_entry = NULL; |
---|
4659 | 4907 | } |
---|
4660 | 4908 | |
---|
4661 | | -static void mlxsw_sp_fib4_entry_replace(struct mlxsw_sp *mlxsw_sp, |
---|
4662 | | - struct mlxsw_sp_fib4_entry *fib4_entry, |
---|
4663 | | - bool replace) |
---|
| 4909 | +static bool mlxsw_sp_fib4_allow_replace(struct mlxsw_sp_fib4_entry *fib4_entry) |
---|
4664 | 4910 | { |
---|
4665 | 4911 | struct mlxsw_sp_fib_node *fib_node = fib4_entry->common.fib_node; |
---|
4666 | | - struct mlxsw_sp_fib4_entry *replaced; |
---|
| 4912 | + struct mlxsw_sp_fib4_entry *fib4_replaced; |
---|
4667 | 4913 | |
---|
4668 | | - if (!replace) |
---|
4669 | | - return; |
---|
| 4914 | + if (!fib_node->fib_entry) |
---|
| 4915 | + return true; |
---|
4670 | 4916 | |
---|
4671 | | - /* We inserted the new entry before replaced one */ |
---|
4672 | | - replaced = list_next_entry(fib4_entry, common.list); |
---|
| 4917 | + fib4_replaced = container_of(fib_node->fib_entry, |
---|
| 4918 | + struct mlxsw_sp_fib4_entry, common); |
---|
| 4919 | + if (fib4_entry->tb_id == RT_TABLE_MAIN && |
---|
| 4920 | + fib4_replaced->tb_id == RT_TABLE_LOCAL) |
---|
| 4921 | + return false; |
---|
4673 | 4922 | |
---|
4674 | | - mlxsw_sp_fib4_node_entry_unlink(mlxsw_sp, replaced); |
---|
4675 | | - mlxsw_sp_fib4_entry_destroy(mlxsw_sp, replaced); |
---|
4676 | | - mlxsw_sp_fib_node_put(mlxsw_sp, fib_node); |
---|
| 4923 | + return true; |
---|
4677 | 4924 | } |
---|
4678 | 4925 | |
---|
4679 | 4926 | static int |
---|
4680 | | -mlxsw_sp_router_fib4_add(struct mlxsw_sp *mlxsw_sp, |
---|
4681 | | - const struct fib_entry_notifier_info *fen_info, |
---|
4682 | | - bool replace, bool append) |
---|
| 4927 | +mlxsw_sp_router_fib4_replace(struct mlxsw_sp *mlxsw_sp, |
---|
| 4928 | + const struct fib_entry_notifier_info *fen_info) |
---|
4683 | 4929 | { |
---|
4684 | | - struct mlxsw_sp_fib4_entry *fib4_entry; |
---|
| 4930 | + struct mlxsw_sp_fib4_entry *fib4_entry, *fib4_replaced; |
---|
| 4931 | + struct mlxsw_sp_fib_entry *replaced; |
---|
4685 | 4932 | struct mlxsw_sp_fib_node *fib_node; |
---|
4686 | 4933 | int err; |
---|
4687 | 4934 | |
---|
.. | .. |
---|
4704 | 4951 | goto err_fib4_entry_create; |
---|
4705 | 4952 | } |
---|
4706 | 4953 | |
---|
4707 | | - err = mlxsw_sp_fib4_node_entry_link(mlxsw_sp, fib4_entry, replace, |
---|
4708 | | - append); |
---|
4709 | | - if (err) { |
---|
4710 | | - dev_warn(mlxsw_sp->bus_info->dev, "Failed to link FIB entry to node\n"); |
---|
4711 | | - goto err_fib4_node_entry_link; |
---|
| 4954 | + if (!mlxsw_sp_fib4_allow_replace(fib4_entry)) { |
---|
| 4955 | + mlxsw_sp_fib4_entry_destroy(mlxsw_sp, fib4_entry); |
---|
| 4956 | + mlxsw_sp_fib_node_put(mlxsw_sp, fib_node); |
---|
| 4957 | + return 0; |
---|
4712 | 4958 | } |
---|
4713 | 4959 | |
---|
4714 | | - mlxsw_sp_fib4_entry_replace(mlxsw_sp, fib4_entry, replace); |
---|
| 4960 | + replaced = fib_node->fib_entry; |
---|
| 4961 | + err = mlxsw_sp_fib_node_entry_link(mlxsw_sp, &fib4_entry->common); |
---|
| 4962 | + if (err) { |
---|
| 4963 | + dev_warn(mlxsw_sp->bus_info->dev, "Failed to link FIB entry to node\n"); |
---|
| 4964 | + goto err_fib_node_entry_link; |
---|
| 4965 | + } |
---|
| 4966 | + |
---|
| 4967 | + /* Nothing to replace */ |
---|
| 4968 | + if (!replaced) |
---|
| 4969 | + return 0; |
---|
| 4970 | + |
---|
| 4971 | + mlxsw_sp_fib_entry_hw_flags_clear(mlxsw_sp, replaced); |
---|
| 4972 | + fib4_replaced = container_of(replaced, struct mlxsw_sp_fib4_entry, |
---|
| 4973 | + common); |
---|
| 4974 | + mlxsw_sp_fib4_entry_destroy(mlxsw_sp, fib4_replaced); |
---|
4715 | 4975 | |
---|
4716 | 4976 | return 0; |
---|
4717 | 4977 | |
---|
4718 | | -err_fib4_node_entry_link: |
---|
| 4978 | +err_fib_node_entry_link: |
---|
| 4979 | + fib_node->fib_entry = replaced; |
---|
4719 | 4980 | mlxsw_sp_fib4_entry_destroy(mlxsw_sp, fib4_entry); |
---|
4720 | 4981 | err_fib4_entry_create: |
---|
4721 | 4982 | mlxsw_sp_fib_node_put(mlxsw_sp, fib_node); |
---|
.. | .. |
---|
4732 | 4993 | return; |
---|
4733 | 4994 | |
---|
4734 | 4995 | fib4_entry = mlxsw_sp_fib4_entry_lookup(mlxsw_sp, fen_info); |
---|
4735 | | - if (WARN_ON(!fib4_entry)) |
---|
| 4996 | + if (!fib4_entry) |
---|
4736 | 4997 | return; |
---|
4737 | 4998 | fib_node = fib4_entry->common.fib_node; |
---|
4738 | 4999 | |
---|
4739 | | - mlxsw_sp_fib4_node_entry_unlink(mlxsw_sp, fib4_entry); |
---|
| 5000 | + mlxsw_sp_fib_node_entry_unlink(mlxsw_sp, &fib4_entry->common); |
---|
4740 | 5001 | mlxsw_sp_fib4_entry_destroy(mlxsw_sp, fib4_entry); |
---|
4741 | 5002 | mlxsw_sp_fib_node_put(mlxsw_sp, fib_node); |
---|
4742 | 5003 | } |
---|
4743 | 5004 | |
---|
4744 | 5005 | static bool mlxsw_sp_fib6_rt_should_ignore(const struct fib6_info *rt) |
---|
4745 | 5006 | { |
---|
4746 | | - /* Packets with link-local destination IP arriving to the router |
---|
4747 | | - * are trapped to the CPU, so no need to program specific routes |
---|
4748 | | - * for them. |
---|
4749 | | - */ |
---|
4750 | | - if (ipv6_addr_type(&rt->fib6_dst.addr) & IPV6_ADDR_LINKLOCAL) |
---|
4751 | | - return true; |
---|
4752 | | - |
---|
4753 | 5007 | /* Multicast routes aren't supported, so ignore them. Neighbour |
---|
4754 | 5008 | * Discovery packets are specifically trapped. |
---|
4755 | 5009 | */ |
---|
.. | .. |
---|
4794 | 5048 | |
---|
4795 | 5049 | static void mlxsw_sp_rt6_destroy(struct mlxsw_sp_rt6 *mlxsw_sp_rt6) |
---|
4796 | 5050 | { |
---|
| 5051 | + struct fib6_nh *fib6_nh = mlxsw_sp_rt6->rt->fib6_nh; |
---|
| 5052 | + |
---|
| 5053 | + fib6_nh->fib_nh_flags &= ~RTNH_F_OFFLOAD; |
---|
4797 | 5054 | mlxsw_sp_rt6_release(mlxsw_sp_rt6->rt); |
---|
4798 | 5055 | kfree(mlxsw_sp_rt6); |
---|
4799 | | -} |
---|
4800 | | - |
---|
4801 | | -static bool mlxsw_sp_fib6_rt_can_mp(const struct fib6_info *rt) |
---|
4802 | | -{ |
---|
4803 | | - /* RTF_CACHE routes are ignored */ |
---|
4804 | | - return (rt->fib6_flags & (RTF_GATEWAY | RTF_ADDRCONF)) == RTF_GATEWAY; |
---|
4805 | 5056 | } |
---|
4806 | 5057 | |
---|
4807 | 5058 | static struct fib6_info * |
---|
.. | .. |
---|
4809 | 5060 | { |
---|
4810 | 5061 | return list_first_entry(&fib6_entry->rt6_list, struct mlxsw_sp_rt6, |
---|
4811 | 5062 | list)->rt; |
---|
4812 | | -} |
---|
4813 | | - |
---|
4814 | | -static struct mlxsw_sp_fib6_entry * |
---|
4815 | | -mlxsw_sp_fib6_node_mp_entry_find(const struct mlxsw_sp_fib_node *fib_node, |
---|
4816 | | - const struct fib6_info *nrt, bool replace) |
---|
4817 | | -{ |
---|
4818 | | - struct mlxsw_sp_fib6_entry *fib6_entry; |
---|
4819 | | - |
---|
4820 | | - if (!mlxsw_sp_fib6_rt_can_mp(nrt) || replace) |
---|
4821 | | - return NULL; |
---|
4822 | | - |
---|
4823 | | - list_for_each_entry(fib6_entry, &fib_node->entry_list, common.list) { |
---|
4824 | | - struct fib6_info *rt = mlxsw_sp_fib6_entry_rt(fib6_entry); |
---|
4825 | | - |
---|
4826 | | - /* RT6_TABLE_LOCAL and RT6_TABLE_MAIN share the same |
---|
4827 | | - * virtual router. |
---|
4828 | | - */ |
---|
4829 | | - if (rt->fib6_table->tb6_id > nrt->fib6_table->tb6_id) |
---|
4830 | | - continue; |
---|
4831 | | - if (rt->fib6_table->tb6_id != nrt->fib6_table->tb6_id) |
---|
4832 | | - break; |
---|
4833 | | - if (rt->fib6_metric < nrt->fib6_metric) |
---|
4834 | | - continue; |
---|
4835 | | - if (rt->fib6_metric == nrt->fib6_metric && |
---|
4836 | | - mlxsw_sp_fib6_rt_can_mp(rt)) |
---|
4837 | | - return fib6_entry; |
---|
4838 | | - if (rt->fib6_metric > nrt->fib6_metric) |
---|
4839 | | - break; |
---|
4840 | | - } |
---|
4841 | | - |
---|
4842 | | - return NULL; |
---|
4843 | 5063 | } |
---|
4844 | 5064 | |
---|
4845 | 5065 | static struct mlxsw_sp_rt6 * |
---|
.. | .. |
---|
4860 | 5080 | const struct fib6_info *rt, |
---|
4861 | 5081 | enum mlxsw_sp_ipip_type *ret) |
---|
4862 | 5082 | { |
---|
4863 | | - return rt->fib6_nh.nh_dev && |
---|
4864 | | - mlxsw_sp_netdev_ipip_type(mlxsw_sp, rt->fib6_nh.nh_dev, ret); |
---|
| 5083 | + return rt->fib6_nh->fib_nh_dev && |
---|
| 5084 | + mlxsw_sp_netdev_ipip_type(mlxsw_sp, rt->fib6_nh->fib_nh_dev, ret); |
---|
4865 | 5085 | } |
---|
4866 | 5086 | |
---|
4867 | 5087 | static int mlxsw_sp_nexthop6_type_init(struct mlxsw_sp *mlxsw_sp, |
---|
.. | .. |
---|
4871 | 5091 | { |
---|
4872 | 5092 | const struct mlxsw_sp_ipip_ops *ipip_ops; |
---|
4873 | 5093 | struct mlxsw_sp_ipip_entry *ipip_entry; |
---|
4874 | | - struct net_device *dev = rt->fib6_nh.nh_dev; |
---|
| 5094 | + struct net_device *dev = rt->fib6_nh->fib_nh_dev; |
---|
4875 | 5095 | struct mlxsw_sp_rif *rif; |
---|
4876 | 5096 | int err; |
---|
4877 | 5097 | |
---|
.. | .. |
---|
4914 | 5134 | struct mlxsw_sp_nexthop *nh, |
---|
4915 | 5135 | const struct fib6_info *rt) |
---|
4916 | 5136 | { |
---|
4917 | | - struct net_device *dev = rt->fib6_nh.nh_dev; |
---|
| 5137 | + struct net_device *dev = rt->fib6_nh->fib_nh_dev; |
---|
4918 | 5138 | |
---|
4919 | 5139 | nh->nh_grp = nh_grp; |
---|
4920 | | - nh->nh_weight = rt->fib6_nh.nh_weight; |
---|
4921 | | - memcpy(&nh->gw_addr, &rt->fib6_nh.nh_gw, sizeof(nh->gw_addr)); |
---|
| 5140 | + nh->nh_weight = rt->fib6_nh->fib_nh_weight; |
---|
| 5141 | + memcpy(&nh->gw_addr, &rt->fib6_nh->fib_nh_gw6, sizeof(nh->gw_addr)); |
---|
4922 | 5142 | mlxsw_sp_nexthop_counter_alloc(mlxsw_sp, nh); |
---|
4923 | 5143 | |
---|
4924 | 5144 | list_add_tail(&nh->router_list_node, &mlxsw_sp->router->nexthop_list); |
---|
.. | .. |
---|
4941 | 5161 | static bool mlxsw_sp_rt6_is_gateway(const struct mlxsw_sp *mlxsw_sp, |
---|
4942 | 5162 | const struct fib6_info *rt) |
---|
4943 | 5163 | { |
---|
4944 | | - return rt->fib6_flags & RTF_GATEWAY || |
---|
| 5164 | + return rt->fib6_nh->fib_nh_gw_family || |
---|
4945 | 5165 | mlxsw_sp_nexthop6_ipip_type(mlxsw_sp, rt, NULL); |
---|
4946 | 5166 | } |
---|
4947 | 5167 | |
---|
.. | .. |
---|
4952 | 5172 | struct mlxsw_sp_nexthop_group *nh_grp; |
---|
4953 | 5173 | struct mlxsw_sp_rt6 *mlxsw_sp_rt6; |
---|
4954 | 5174 | struct mlxsw_sp_nexthop *nh; |
---|
4955 | | - size_t alloc_size; |
---|
4956 | 5175 | int i = 0; |
---|
4957 | 5176 | int err; |
---|
4958 | 5177 | |
---|
4959 | | - alloc_size = sizeof(*nh_grp) + |
---|
4960 | | - fib6_entry->nrt6 * sizeof(struct mlxsw_sp_nexthop); |
---|
4961 | | - nh_grp = kzalloc(alloc_size, GFP_KERNEL); |
---|
| 5178 | + nh_grp = kzalloc(struct_size(nh_grp, nexthops, fib6_entry->nrt6), |
---|
| 5179 | + GFP_KERNEL); |
---|
4962 | 5180 | if (!nh_grp) |
---|
4963 | 5181 | return ERR_PTR(-ENOMEM); |
---|
4964 | 5182 | INIT_LIST_HEAD(&nh_grp->fib_list); |
---|
.. | .. |
---|
5029 | 5247 | &nh_grp->fib_list); |
---|
5030 | 5248 | fib6_entry->common.nh_group = nh_grp; |
---|
5031 | 5249 | |
---|
| 5250 | + /* The route and the nexthop are described by the same struct, so we |
---|
| 5251 | + * need to the update the nexthop offload indication for the new route. |
---|
| 5252 | + */ |
---|
| 5253 | + __mlxsw_sp_nexthop6_group_offload_refresh(nh_grp, fib6_entry); |
---|
| 5254 | + |
---|
5032 | 5255 | return 0; |
---|
5033 | 5256 | } |
---|
5034 | 5257 | |
---|
.. | .. |
---|
5061 | 5284 | * currently associated with it in the device's table is that |
---|
5062 | 5285 | * of the old group. Start using the new one instead. |
---|
5063 | 5286 | */ |
---|
5064 | | - err = mlxsw_sp_fib_node_entry_add(mlxsw_sp, &fib6_entry->common); |
---|
| 5287 | + err = mlxsw_sp_fib_entry_update(mlxsw_sp, &fib6_entry->common); |
---|
5065 | 5288 | if (err) |
---|
5066 | | - goto err_fib_node_entry_add; |
---|
| 5289 | + goto err_fib_entry_update; |
---|
5067 | 5290 | |
---|
5068 | 5291 | if (list_empty(&old_nh_grp->fib_list)) |
---|
5069 | 5292 | mlxsw_sp_nexthop6_group_destroy(mlxsw_sp, old_nh_grp); |
---|
5070 | 5293 | |
---|
5071 | 5294 | return 0; |
---|
5072 | 5295 | |
---|
5073 | | -err_fib_node_entry_add: |
---|
| 5296 | +err_fib_entry_update: |
---|
5074 | 5297 | mlxsw_sp_nexthop6_group_put(mlxsw_sp, &fib6_entry->common); |
---|
5075 | 5298 | err_nexthop6_group_get: |
---|
5076 | 5299 | list_add_tail(&fib6_entry->common.nexthop_group_node, |
---|
.. | .. |
---|
5082 | 5305 | static int |
---|
5083 | 5306 | mlxsw_sp_fib6_entry_nexthop_add(struct mlxsw_sp *mlxsw_sp, |
---|
5084 | 5307 | struct mlxsw_sp_fib6_entry *fib6_entry, |
---|
5085 | | - struct fib6_info *rt) |
---|
| 5308 | + struct fib6_info **rt_arr, unsigned int nrt6) |
---|
5086 | 5309 | { |
---|
5087 | 5310 | struct mlxsw_sp_rt6 *mlxsw_sp_rt6; |
---|
5088 | | - int err; |
---|
| 5311 | + int err, i; |
---|
5089 | 5312 | |
---|
5090 | | - mlxsw_sp_rt6 = mlxsw_sp_rt6_create(rt); |
---|
5091 | | - if (IS_ERR(mlxsw_sp_rt6)) |
---|
5092 | | - return PTR_ERR(mlxsw_sp_rt6); |
---|
| 5313 | + for (i = 0; i < nrt6; i++) { |
---|
| 5314 | + mlxsw_sp_rt6 = mlxsw_sp_rt6_create(rt_arr[i]); |
---|
| 5315 | + if (IS_ERR(mlxsw_sp_rt6)) { |
---|
| 5316 | + err = PTR_ERR(mlxsw_sp_rt6); |
---|
| 5317 | + goto err_rt6_create; |
---|
| 5318 | + } |
---|
5093 | 5319 | |
---|
5094 | | - list_add_tail(&mlxsw_sp_rt6->list, &fib6_entry->rt6_list); |
---|
5095 | | - fib6_entry->nrt6++; |
---|
| 5320 | + list_add_tail(&mlxsw_sp_rt6->list, &fib6_entry->rt6_list); |
---|
| 5321 | + fib6_entry->nrt6++; |
---|
| 5322 | + } |
---|
5096 | 5323 | |
---|
5097 | 5324 | err = mlxsw_sp_nexthop6_group_update(mlxsw_sp, fib6_entry); |
---|
5098 | 5325 | if (err) |
---|
.. | .. |
---|
5101 | 5328 | return 0; |
---|
5102 | 5329 | |
---|
5103 | 5330 | err_nexthop6_group_update: |
---|
5104 | | - fib6_entry->nrt6--; |
---|
5105 | | - list_del(&mlxsw_sp_rt6->list); |
---|
5106 | | - mlxsw_sp_rt6_destroy(mlxsw_sp_rt6); |
---|
| 5331 | + i = nrt6; |
---|
| 5332 | +err_rt6_create: |
---|
| 5333 | + for (i--; i >= 0; i--) { |
---|
| 5334 | + fib6_entry->nrt6--; |
---|
| 5335 | + mlxsw_sp_rt6 = list_last_entry(&fib6_entry->rt6_list, |
---|
| 5336 | + struct mlxsw_sp_rt6, list); |
---|
| 5337 | + list_del(&mlxsw_sp_rt6->list); |
---|
| 5338 | + mlxsw_sp_rt6_destroy(mlxsw_sp_rt6); |
---|
| 5339 | + } |
---|
5107 | 5340 | return err; |
---|
5108 | 5341 | } |
---|
5109 | 5342 | |
---|
5110 | 5343 | static void |
---|
5111 | 5344 | mlxsw_sp_fib6_entry_nexthop_del(struct mlxsw_sp *mlxsw_sp, |
---|
5112 | 5345 | struct mlxsw_sp_fib6_entry *fib6_entry, |
---|
5113 | | - struct fib6_info *rt) |
---|
| 5346 | + struct fib6_info **rt_arr, unsigned int nrt6) |
---|
5114 | 5347 | { |
---|
5115 | 5348 | struct mlxsw_sp_rt6 *mlxsw_sp_rt6; |
---|
| 5349 | + int i; |
---|
5116 | 5350 | |
---|
5117 | | - mlxsw_sp_rt6 = mlxsw_sp_fib6_entry_rt_find(fib6_entry, rt); |
---|
5118 | | - if (WARN_ON(!mlxsw_sp_rt6)) |
---|
5119 | | - return; |
---|
| 5351 | + for (i = 0; i < nrt6; i++) { |
---|
| 5352 | + mlxsw_sp_rt6 = mlxsw_sp_fib6_entry_rt_find(fib6_entry, |
---|
| 5353 | + rt_arr[i]); |
---|
| 5354 | + if (WARN_ON_ONCE(!mlxsw_sp_rt6)) |
---|
| 5355 | + continue; |
---|
5120 | 5356 | |
---|
5121 | | - fib6_entry->nrt6--; |
---|
5122 | | - list_del(&mlxsw_sp_rt6->list); |
---|
| 5357 | + fib6_entry->nrt6--; |
---|
| 5358 | + list_del(&mlxsw_sp_rt6->list); |
---|
| 5359 | + mlxsw_sp_rt6_destroy(mlxsw_sp_rt6); |
---|
| 5360 | + } |
---|
| 5361 | + |
---|
5123 | 5362 | mlxsw_sp_nexthop6_group_update(mlxsw_sp, fib6_entry); |
---|
5124 | | - mlxsw_sp_rt6_destroy(mlxsw_sp_rt6); |
---|
5125 | 5363 | } |
---|
5126 | 5364 | |
---|
5127 | 5365 | static void mlxsw_sp_fib6_entry_type_set(struct mlxsw_sp *mlxsw_sp, |
---|
.. | .. |
---|
5136 | 5374 | */ |
---|
5137 | 5375 | if (rt->fib6_flags & (RTF_LOCAL | RTF_ANYCAST)) |
---|
5138 | 5376 | fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP; |
---|
| 5377 | + else if (rt->fib6_type == RTN_BLACKHOLE) |
---|
| 5378 | + fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE; |
---|
5139 | 5379 | else if (rt->fib6_flags & RTF_REJECT) |
---|
5140 | | - fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_LOCAL; |
---|
| 5380 | + fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_UNREACHABLE; |
---|
5141 | 5381 | else if (mlxsw_sp_rt6_is_gateway(mlxsw_sp, rt)) |
---|
5142 | 5382 | fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_REMOTE; |
---|
5143 | 5383 | else |
---|
.. | .. |
---|
5160 | 5400 | static struct mlxsw_sp_fib6_entry * |
---|
5161 | 5401 | mlxsw_sp_fib6_entry_create(struct mlxsw_sp *mlxsw_sp, |
---|
5162 | 5402 | struct mlxsw_sp_fib_node *fib_node, |
---|
5163 | | - struct fib6_info *rt) |
---|
| 5403 | + struct fib6_info **rt_arr, unsigned int nrt6) |
---|
5164 | 5404 | { |
---|
5165 | 5405 | struct mlxsw_sp_fib6_entry *fib6_entry; |
---|
5166 | 5406 | struct mlxsw_sp_fib_entry *fib_entry; |
---|
5167 | 5407 | struct mlxsw_sp_rt6 *mlxsw_sp_rt6; |
---|
5168 | | - int err; |
---|
| 5408 | + int err, i; |
---|
5169 | 5409 | |
---|
5170 | 5410 | fib6_entry = kzalloc(sizeof(*fib6_entry), GFP_KERNEL); |
---|
5171 | 5411 | if (!fib6_entry) |
---|
5172 | 5412 | return ERR_PTR(-ENOMEM); |
---|
5173 | 5413 | fib_entry = &fib6_entry->common; |
---|
5174 | 5414 | |
---|
5175 | | - mlxsw_sp_rt6 = mlxsw_sp_rt6_create(rt); |
---|
5176 | | - if (IS_ERR(mlxsw_sp_rt6)) { |
---|
5177 | | - err = PTR_ERR(mlxsw_sp_rt6); |
---|
5178 | | - goto err_rt6_create; |
---|
| 5415 | + INIT_LIST_HEAD(&fib6_entry->rt6_list); |
---|
| 5416 | + |
---|
| 5417 | + for (i = 0; i < nrt6; i++) { |
---|
| 5418 | + mlxsw_sp_rt6 = mlxsw_sp_rt6_create(rt_arr[i]); |
---|
| 5419 | + if (IS_ERR(mlxsw_sp_rt6)) { |
---|
| 5420 | + err = PTR_ERR(mlxsw_sp_rt6); |
---|
| 5421 | + goto err_rt6_create; |
---|
| 5422 | + } |
---|
| 5423 | + list_add_tail(&mlxsw_sp_rt6->list, &fib6_entry->rt6_list); |
---|
| 5424 | + fib6_entry->nrt6++; |
---|
5179 | 5425 | } |
---|
5180 | 5426 | |
---|
5181 | | - mlxsw_sp_fib6_entry_type_set(mlxsw_sp, fib_entry, mlxsw_sp_rt6->rt); |
---|
| 5427 | + mlxsw_sp_fib6_entry_type_set(mlxsw_sp, fib_entry, rt_arr[0]); |
---|
5182 | 5428 | |
---|
5183 | | - INIT_LIST_HEAD(&fib6_entry->rt6_list); |
---|
5184 | | - list_add_tail(&mlxsw_sp_rt6->list, &fib6_entry->rt6_list); |
---|
5185 | | - fib6_entry->nrt6 = 1; |
---|
5186 | 5429 | err = mlxsw_sp_nexthop6_group_get(mlxsw_sp, fib6_entry); |
---|
5187 | 5430 | if (err) |
---|
5188 | 5431 | goto err_nexthop6_group_get; |
---|
.. | .. |
---|
5192 | 5435 | return fib6_entry; |
---|
5193 | 5436 | |
---|
5194 | 5437 | err_nexthop6_group_get: |
---|
5195 | | - list_del(&mlxsw_sp_rt6->list); |
---|
5196 | | - mlxsw_sp_rt6_destroy(mlxsw_sp_rt6); |
---|
| 5438 | + i = nrt6; |
---|
5197 | 5439 | err_rt6_create: |
---|
| 5440 | + for (i--; i >= 0; i--) { |
---|
| 5441 | + fib6_entry->nrt6--; |
---|
| 5442 | + mlxsw_sp_rt6 = list_last_entry(&fib6_entry->rt6_list, |
---|
| 5443 | + struct mlxsw_sp_rt6, list); |
---|
| 5444 | + list_del(&mlxsw_sp_rt6->list); |
---|
| 5445 | + mlxsw_sp_rt6_destroy(mlxsw_sp_rt6); |
---|
| 5446 | + } |
---|
5198 | 5447 | kfree(fib6_entry); |
---|
5199 | 5448 | return ERR_PTR(err); |
---|
5200 | 5449 | } |
---|
.. | .. |
---|
5209 | 5458 | } |
---|
5210 | 5459 | |
---|
5211 | 5460 | static struct mlxsw_sp_fib6_entry * |
---|
5212 | | -mlxsw_sp_fib6_node_entry_find(const struct mlxsw_sp_fib_node *fib_node, |
---|
5213 | | - const struct fib6_info *nrt, bool replace) |
---|
5214 | | -{ |
---|
5215 | | - struct mlxsw_sp_fib6_entry *fib6_entry, *fallback = NULL; |
---|
5216 | | - |
---|
5217 | | - list_for_each_entry(fib6_entry, &fib_node->entry_list, common.list) { |
---|
5218 | | - struct fib6_info *rt = mlxsw_sp_fib6_entry_rt(fib6_entry); |
---|
5219 | | - |
---|
5220 | | - if (rt->fib6_table->tb6_id > nrt->fib6_table->tb6_id) |
---|
5221 | | - continue; |
---|
5222 | | - if (rt->fib6_table->tb6_id != nrt->fib6_table->tb6_id) |
---|
5223 | | - break; |
---|
5224 | | - if (replace && rt->fib6_metric == nrt->fib6_metric) { |
---|
5225 | | - if (mlxsw_sp_fib6_rt_can_mp(rt) == |
---|
5226 | | - mlxsw_sp_fib6_rt_can_mp(nrt)) |
---|
5227 | | - return fib6_entry; |
---|
5228 | | - if (mlxsw_sp_fib6_rt_can_mp(nrt)) |
---|
5229 | | - fallback = fallback ?: fib6_entry; |
---|
5230 | | - } |
---|
5231 | | - if (rt->fib6_metric > nrt->fib6_metric) |
---|
5232 | | - return fallback ?: fib6_entry; |
---|
5233 | | - } |
---|
5234 | | - |
---|
5235 | | - return fallback; |
---|
5236 | | -} |
---|
5237 | | - |
---|
5238 | | -static int |
---|
5239 | | -mlxsw_sp_fib6_node_list_insert(struct mlxsw_sp_fib6_entry *new6_entry, |
---|
5240 | | - bool replace) |
---|
5241 | | -{ |
---|
5242 | | - struct mlxsw_sp_fib_node *fib_node = new6_entry->common.fib_node; |
---|
5243 | | - struct fib6_info *nrt = mlxsw_sp_fib6_entry_rt(new6_entry); |
---|
5244 | | - struct mlxsw_sp_fib6_entry *fib6_entry; |
---|
5245 | | - |
---|
5246 | | - fib6_entry = mlxsw_sp_fib6_node_entry_find(fib_node, nrt, replace); |
---|
5247 | | - |
---|
5248 | | - if (replace && WARN_ON(!fib6_entry)) |
---|
5249 | | - return -EINVAL; |
---|
5250 | | - |
---|
5251 | | - if (fib6_entry) { |
---|
5252 | | - list_add_tail(&new6_entry->common.list, |
---|
5253 | | - &fib6_entry->common.list); |
---|
5254 | | - } else { |
---|
5255 | | - struct mlxsw_sp_fib6_entry *last; |
---|
5256 | | - |
---|
5257 | | - list_for_each_entry(last, &fib_node->entry_list, common.list) { |
---|
5258 | | - struct fib6_info *rt = mlxsw_sp_fib6_entry_rt(last); |
---|
5259 | | - |
---|
5260 | | - if (nrt->fib6_table->tb6_id > rt->fib6_table->tb6_id) |
---|
5261 | | - break; |
---|
5262 | | - fib6_entry = last; |
---|
5263 | | - } |
---|
5264 | | - |
---|
5265 | | - if (fib6_entry) |
---|
5266 | | - list_add(&new6_entry->common.list, |
---|
5267 | | - &fib6_entry->common.list); |
---|
5268 | | - else |
---|
5269 | | - list_add(&new6_entry->common.list, |
---|
5270 | | - &fib_node->entry_list); |
---|
5271 | | - } |
---|
5272 | | - |
---|
5273 | | - return 0; |
---|
5274 | | -} |
---|
5275 | | - |
---|
5276 | | -static void |
---|
5277 | | -mlxsw_sp_fib6_node_list_remove(struct mlxsw_sp_fib6_entry *fib6_entry) |
---|
5278 | | -{ |
---|
5279 | | - list_del(&fib6_entry->common.list); |
---|
5280 | | -} |
---|
5281 | | - |
---|
5282 | | -static int mlxsw_sp_fib6_node_entry_link(struct mlxsw_sp *mlxsw_sp, |
---|
5283 | | - struct mlxsw_sp_fib6_entry *fib6_entry, |
---|
5284 | | - bool replace) |
---|
5285 | | -{ |
---|
5286 | | - int err; |
---|
5287 | | - |
---|
5288 | | - err = mlxsw_sp_fib6_node_list_insert(fib6_entry, replace); |
---|
5289 | | - if (err) |
---|
5290 | | - return err; |
---|
5291 | | - |
---|
5292 | | - err = mlxsw_sp_fib_node_entry_add(mlxsw_sp, &fib6_entry->common); |
---|
5293 | | - if (err) |
---|
5294 | | - goto err_fib_node_entry_add; |
---|
5295 | | - |
---|
5296 | | - return 0; |
---|
5297 | | - |
---|
5298 | | -err_fib_node_entry_add: |
---|
5299 | | - mlxsw_sp_fib6_node_list_remove(fib6_entry); |
---|
5300 | | - return err; |
---|
5301 | | -} |
---|
5302 | | - |
---|
5303 | | -static void |
---|
5304 | | -mlxsw_sp_fib6_node_entry_unlink(struct mlxsw_sp *mlxsw_sp, |
---|
5305 | | - struct mlxsw_sp_fib6_entry *fib6_entry) |
---|
5306 | | -{ |
---|
5307 | | - mlxsw_sp_fib_node_entry_del(mlxsw_sp, &fib6_entry->common); |
---|
5308 | | - mlxsw_sp_fib6_node_list_remove(fib6_entry); |
---|
5309 | | -} |
---|
5310 | | - |
---|
5311 | | -static struct mlxsw_sp_fib6_entry * |
---|
5312 | 5461 | mlxsw_sp_fib6_entry_lookup(struct mlxsw_sp *mlxsw_sp, |
---|
5313 | 5462 | const struct fib6_info *rt) |
---|
5314 | 5463 | { |
---|
5315 | 5464 | struct mlxsw_sp_fib6_entry *fib6_entry; |
---|
5316 | 5465 | struct mlxsw_sp_fib_node *fib_node; |
---|
5317 | 5466 | struct mlxsw_sp_fib *fib; |
---|
| 5467 | + struct fib6_info *cmp_rt; |
---|
5318 | 5468 | struct mlxsw_sp_vr *vr; |
---|
5319 | 5469 | |
---|
5320 | 5470 | vr = mlxsw_sp_vr_find(mlxsw_sp, rt->fib6_table->tb6_id); |
---|
.. | .. |
---|
5328 | 5478 | if (!fib_node) |
---|
5329 | 5479 | return NULL; |
---|
5330 | 5480 | |
---|
5331 | | - list_for_each_entry(fib6_entry, &fib_node->entry_list, common.list) { |
---|
5332 | | - struct fib6_info *iter_rt = mlxsw_sp_fib6_entry_rt(fib6_entry); |
---|
5333 | | - |
---|
5334 | | - if (rt->fib6_table->tb6_id == iter_rt->fib6_table->tb6_id && |
---|
5335 | | - rt->fib6_metric == iter_rt->fib6_metric && |
---|
5336 | | - mlxsw_sp_fib6_entry_rt_find(fib6_entry, rt)) |
---|
5337 | | - return fib6_entry; |
---|
5338 | | - } |
---|
| 5481 | + fib6_entry = container_of(fib_node->fib_entry, |
---|
| 5482 | + struct mlxsw_sp_fib6_entry, common); |
---|
| 5483 | + cmp_rt = mlxsw_sp_fib6_entry_rt(fib6_entry); |
---|
| 5484 | + if (rt->fib6_table->tb6_id == cmp_rt->fib6_table->tb6_id && |
---|
| 5485 | + rt->fib6_metric == cmp_rt->fib6_metric && |
---|
| 5486 | + mlxsw_sp_fib6_entry_rt_find(fib6_entry, rt)) |
---|
| 5487 | + return fib6_entry; |
---|
5339 | 5488 | |
---|
5340 | 5489 | return NULL; |
---|
5341 | 5490 | } |
---|
5342 | 5491 | |
---|
5343 | | -static void mlxsw_sp_fib6_entry_replace(struct mlxsw_sp *mlxsw_sp, |
---|
5344 | | - struct mlxsw_sp_fib6_entry *fib6_entry, |
---|
5345 | | - bool replace) |
---|
| 5492 | +static bool mlxsw_sp_fib6_allow_replace(struct mlxsw_sp_fib6_entry *fib6_entry) |
---|
5346 | 5493 | { |
---|
5347 | 5494 | struct mlxsw_sp_fib_node *fib_node = fib6_entry->common.fib_node; |
---|
5348 | | - struct mlxsw_sp_fib6_entry *replaced; |
---|
| 5495 | + struct mlxsw_sp_fib6_entry *fib6_replaced; |
---|
| 5496 | + struct fib6_info *rt, *rt_replaced; |
---|
5349 | 5497 | |
---|
5350 | | - if (!replace) |
---|
5351 | | - return; |
---|
| 5498 | + if (!fib_node->fib_entry) |
---|
| 5499 | + return true; |
---|
5352 | 5500 | |
---|
5353 | | - replaced = list_next_entry(fib6_entry, common.list); |
---|
| 5501 | + fib6_replaced = container_of(fib_node->fib_entry, |
---|
| 5502 | + struct mlxsw_sp_fib6_entry, |
---|
| 5503 | + common); |
---|
| 5504 | + rt = mlxsw_sp_fib6_entry_rt(fib6_entry); |
---|
| 5505 | + rt_replaced = mlxsw_sp_fib6_entry_rt(fib6_replaced); |
---|
| 5506 | + if (rt->fib6_table->tb6_id == RT_TABLE_MAIN && |
---|
| 5507 | + rt_replaced->fib6_table->tb6_id == RT_TABLE_LOCAL) |
---|
| 5508 | + return false; |
---|
5354 | 5509 | |
---|
5355 | | - mlxsw_sp_fib6_node_entry_unlink(mlxsw_sp, replaced); |
---|
5356 | | - mlxsw_sp_fib6_entry_destroy(mlxsw_sp, replaced); |
---|
5357 | | - mlxsw_sp_fib_node_put(mlxsw_sp, fib_node); |
---|
| 5510 | + return true; |
---|
5358 | 5511 | } |
---|
5359 | 5512 | |
---|
5360 | | -static int mlxsw_sp_router_fib6_add(struct mlxsw_sp *mlxsw_sp, |
---|
5361 | | - struct fib6_info *rt, bool replace) |
---|
| 5513 | +static int mlxsw_sp_router_fib6_replace(struct mlxsw_sp *mlxsw_sp, |
---|
| 5514 | + struct fib6_info **rt_arr, |
---|
| 5515 | + unsigned int nrt6) |
---|
5362 | 5516 | { |
---|
5363 | | - struct mlxsw_sp_fib6_entry *fib6_entry; |
---|
| 5517 | + struct mlxsw_sp_fib6_entry *fib6_entry, *fib6_replaced; |
---|
| 5518 | + struct mlxsw_sp_fib_entry *replaced; |
---|
5364 | 5519 | struct mlxsw_sp_fib_node *fib_node; |
---|
| 5520 | + struct fib6_info *rt = rt_arr[0]; |
---|
5365 | 5521 | int err; |
---|
5366 | 5522 | |
---|
5367 | 5523 | if (mlxsw_sp->router->aborted) |
---|
.. | .. |
---|
5381 | 5537 | if (IS_ERR(fib_node)) |
---|
5382 | 5538 | return PTR_ERR(fib_node); |
---|
5383 | 5539 | |
---|
5384 | | - /* Before creating a new entry, try to append route to an existing |
---|
5385 | | - * multipath entry. |
---|
5386 | | - */ |
---|
5387 | | - fib6_entry = mlxsw_sp_fib6_node_mp_entry_find(fib_node, rt, replace); |
---|
5388 | | - if (fib6_entry) { |
---|
5389 | | - err = mlxsw_sp_fib6_entry_nexthop_add(mlxsw_sp, fib6_entry, rt); |
---|
5390 | | - if (err) |
---|
5391 | | - goto err_fib6_entry_nexthop_add; |
---|
5392 | | - return 0; |
---|
5393 | | - } |
---|
5394 | | - |
---|
5395 | | - fib6_entry = mlxsw_sp_fib6_entry_create(mlxsw_sp, fib_node, rt); |
---|
| 5540 | + fib6_entry = mlxsw_sp_fib6_entry_create(mlxsw_sp, fib_node, rt_arr, |
---|
| 5541 | + nrt6); |
---|
5396 | 5542 | if (IS_ERR(fib6_entry)) { |
---|
5397 | 5543 | err = PTR_ERR(fib6_entry); |
---|
5398 | 5544 | goto err_fib6_entry_create; |
---|
5399 | 5545 | } |
---|
5400 | 5546 | |
---|
5401 | | - err = mlxsw_sp_fib6_node_entry_link(mlxsw_sp, fib6_entry, replace); |
---|
5402 | | - if (err) |
---|
5403 | | - goto err_fib6_node_entry_link; |
---|
| 5547 | + if (!mlxsw_sp_fib6_allow_replace(fib6_entry)) { |
---|
| 5548 | + mlxsw_sp_fib6_entry_destroy(mlxsw_sp, fib6_entry); |
---|
| 5549 | + mlxsw_sp_fib_node_put(mlxsw_sp, fib_node); |
---|
| 5550 | + return 0; |
---|
| 5551 | + } |
---|
5404 | 5552 | |
---|
5405 | | - mlxsw_sp_fib6_entry_replace(mlxsw_sp, fib6_entry, replace); |
---|
| 5553 | + replaced = fib_node->fib_entry; |
---|
| 5554 | + err = mlxsw_sp_fib_node_entry_link(mlxsw_sp, &fib6_entry->common); |
---|
| 5555 | + if (err) |
---|
| 5556 | + goto err_fib_node_entry_link; |
---|
| 5557 | + |
---|
| 5558 | + /* Nothing to replace */ |
---|
| 5559 | + if (!replaced) |
---|
| 5560 | + return 0; |
---|
| 5561 | + |
---|
| 5562 | + mlxsw_sp_fib_entry_hw_flags_clear(mlxsw_sp, replaced); |
---|
| 5563 | + fib6_replaced = container_of(replaced, struct mlxsw_sp_fib6_entry, |
---|
| 5564 | + common); |
---|
| 5565 | + mlxsw_sp_fib6_entry_destroy(mlxsw_sp, fib6_replaced); |
---|
5406 | 5566 | |
---|
5407 | 5567 | return 0; |
---|
5408 | 5568 | |
---|
5409 | | -err_fib6_node_entry_link: |
---|
| 5569 | +err_fib_node_entry_link: |
---|
| 5570 | + fib_node->fib_entry = replaced; |
---|
5410 | 5571 | mlxsw_sp_fib6_entry_destroy(mlxsw_sp, fib6_entry); |
---|
5411 | 5572 | err_fib6_entry_create: |
---|
| 5573 | + mlxsw_sp_fib_node_put(mlxsw_sp, fib_node); |
---|
| 5574 | + return err; |
---|
| 5575 | +} |
---|
| 5576 | + |
---|
| 5577 | +static int mlxsw_sp_router_fib6_append(struct mlxsw_sp *mlxsw_sp, |
---|
| 5578 | + struct fib6_info **rt_arr, |
---|
| 5579 | + unsigned int nrt6) |
---|
| 5580 | +{ |
---|
| 5581 | + struct mlxsw_sp_fib6_entry *fib6_entry; |
---|
| 5582 | + struct mlxsw_sp_fib_node *fib_node; |
---|
| 5583 | + struct fib6_info *rt = rt_arr[0]; |
---|
| 5584 | + int err; |
---|
| 5585 | + |
---|
| 5586 | + if (mlxsw_sp->router->aborted) |
---|
| 5587 | + return 0; |
---|
| 5588 | + |
---|
| 5589 | + if (rt->fib6_src.plen) |
---|
| 5590 | + return -EINVAL; |
---|
| 5591 | + |
---|
| 5592 | + if (mlxsw_sp_fib6_rt_should_ignore(rt)) |
---|
| 5593 | + return 0; |
---|
| 5594 | + |
---|
| 5595 | + fib_node = mlxsw_sp_fib_node_get(mlxsw_sp, rt->fib6_table->tb6_id, |
---|
| 5596 | + &rt->fib6_dst.addr, |
---|
| 5597 | + sizeof(rt->fib6_dst.addr), |
---|
| 5598 | + rt->fib6_dst.plen, |
---|
| 5599 | + MLXSW_SP_L3_PROTO_IPV6); |
---|
| 5600 | + if (IS_ERR(fib_node)) |
---|
| 5601 | + return PTR_ERR(fib_node); |
---|
| 5602 | + |
---|
| 5603 | + if (WARN_ON_ONCE(!fib_node->fib_entry)) { |
---|
| 5604 | + mlxsw_sp_fib_node_put(mlxsw_sp, fib_node); |
---|
| 5605 | + return -EINVAL; |
---|
| 5606 | + } |
---|
| 5607 | + |
---|
| 5608 | + fib6_entry = container_of(fib_node->fib_entry, |
---|
| 5609 | + struct mlxsw_sp_fib6_entry, common); |
---|
| 5610 | + err = mlxsw_sp_fib6_entry_nexthop_add(mlxsw_sp, fib6_entry, rt_arr, |
---|
| 5611 | + nrt6); |
---|
| 5612 | + if (err) |
---|
| 5613 | + goto err_fib6_entry_nexthop_add; |
---|
| 5614 | + |
---|
| 5615 | + return 0; |
---|
| 5616 | + |
---|
5412 | 5617 | err_fib6_entry_nexthop_add: |
---|
5413 | 5618 | mlxsw_sp_fib_node_put(mlxsw_sp, fib_node); |
---|
5414 | 5619 | return err; |
---|
5415 | 5620 | } |
---|
5416 | 5621 | |
---|
5417 | 5622 | static void mlxsw_sp_router_fib6_del(struct mlxsw_sp *mlxsw_sp, |
---|
5418 | | - struct fib6_info *rt) |
---|
| 5623 | + struct fib6_info **rt_arr, |
---|
| 5624 | + unsigned int nrt6) |
---|
5419 | 5625 | { |
---|
5420 | 5626 | struct mlxsw_sp_fib6_entry *fib6_entry; |
---|
5421 | 5627 | struct mlxsw_sp_fib_node *fib_node; |
---|
| 5628 | + struct fib6_info *rt = rt_arr[0]; |
---|
5422 | 5629 | |
---|
5423 | 5630 | if (mlxsw_sp->router->aborted) |
---|
5424 | 5631 | return; |
---|
.. | .. |
---|
5426 | 5633 | if (mlxsw_sp_fib6_rt_should_ignore(rt)) |
---|
5427 | 5634 | return; |
---|
5428 | 5635 | |
---|
| 5636 | + /* Multipath routes are first added to the FIB trie and only then |
---|
| 5637 | + * notified. If we vetoed the addition, we will get a delete |
---|
| 5638 | + * notification for a route we do not have. Therefore, do not warn if |
---|
| 5639 | + * route was not found. |
---|
| 5640 | + */ |
---|
5429 | 5641 | fib6_entry = mlxsw_sp_fib6_entry_lookup(mlxsw_sp, rt); |
---|
5430 | | - if (WARN_ON(!fib6_entry)) |
---|
| 5642 | + if (!fib6_entry) |
---|
5431 | 5643 | return; |
---|
5432 | 5644 | |
---|
5433 | | - /* If route is part of a multipath entry, but not the last one |
---|
5434 | | - * removed, then only reduce its nexthop group. |
---|
| 5645 | + /* If not all the nexthops are deleted, then only reduce the nexthop |
---|
| 5646 | + * group. |
---|
5435 | 5647 | */ |
---|
5436 | | - if (!list_is_singular(&fib6_entry->rt6_list)) { |
---|
5437 | | - mlxsw_sp_fib6_entry_nexthop_del(mlxsw_sp, fib6_entry, rt); |
---|
| 5648 | + if (nrt6 != fib6_entry->nrt6) { |
---|
| 5649 | + mlxsw_sp_fib6_entry_nexthop_del(mlxsw_sp, fib6_entry, rt_arr, |
---|
| 5650 | + nrt6); |
---|
5438 | 5651 | return; |
---|
5439 | 5652 | } |
---|
5440 | 5653 | |
---|
5441 | 5654 | fib_node = fib6_entry->common.fib_node; |
---|
5442 | 5655 | |
---|
5443 | | - mlxsw_sp_fib6_node_entry_unlink(mlxsw_sp, fib6_entry); |
---|
| 5656 | + mlxsw_sp_fib_node_entry_unlink(mlxsw_sp, &fib6_entry->common); |
---|
5444 | 5657 | mlxsw_sp_fib6_entry_destroy(mlxsw_sp, fib6_entry); |
---|
5445 | 5658 | mlxsw_sp_fib_node_put(mlxsw_sp, fib_node); |
---|
5446 | 5659 | } |
---|
.. | .. |
---|
5594 | 5807 | static void mlxsw_sp_fib4_node_flush(struct mlxsw_sp *mlxsw_sp, |
---|
5595 | 5808 | struct mlxsw_sp_fib_node *fib_node) |
---|
5596 | 5809 | { |
---|
5597 | | - struct mlxsw_sp_fib4_entry *fib4_entry, *tmp; |
---|
| 5810 | + struct mlxsw_sp_fib4_entry *fib4_entry; |
---|
5598 | 5811 | |
---|
5599 | | - list_for_each_entry_safe(fib4_entry, tmp, &fib_node->entry_list, |
---|
5600 | | - common.list) { |
---|
5601 | | - bool do_break = &tmp->common.list == &fib_node->entry_list; |
---|
5602 | | - |
---|
5603 | | - mlxsw_sp_fib4_node_entry_unlink(mlxsw_sp, fib4_entry); |
---|
5604 | | - mlxsw_sp_fib4_entry_destroy(mlxsw_sp, fib4_entry); |
---|
5605 | | - mlxsw_sp_fib_node_put(mlxsw_sp, fib_node); |
---|
5606 | | - /* Break when entry list is empty and node was freed. |
---|
5607 | | - * Otherwise, we'll access freed memory in the next |
---|
5608 | | - * iteration. |
---|
5609 | | - */ |
---|
5610 | | - if (do_break) |
---|
5611 | | - break; |
---|
5612 | | - } |
---|
| 5812 | + fib4_entry = container_of(fib_node->fib_entry, |
---|
| 5813 | + struct mlxsw_sp_fib4_entry, common); |
---|
| 5814 | + mlxsw_sp_fib_node_entry_unlink(mlxsw_sp, fib_node->fib_entry); |
---|
| 5815 | + mlxsw_sp_fib4_entry_destroy(mlxsw_sp, fib4_entry); |
---|
| 5816 | + mlxsw_sp_fib_node_put(mlxsw_sp, fib_node); |
---|
5613 | 5817 | } |
---|
5614 | 5818 | |
---|
5615 | 5819 | static void mlxsw_sp_fib6_node_flush(struct mlxsw_sp *mlxsw_sp, |
---|
5616 | 5820 | struct mlxsw_sp_fib_node *fib_node) |
---|
5617 | 5821 | { |
---|
5618 | | - struct mlxsw_sp_fib6_entry *fib6_entry, *tmp; |
---|
| 5822 | + struct mlxsw_sp_fib6_entry *fib6_entry; |
---|
5619 | 5823 | |
---|
5620 | | - list_for_each_entry_safe(fib6_entry, tmp, &fib_node->entry_list, |
---|
5621 | | - common.list) { |
---|
5622 | | - bool do_break = &tmp->common.list == &fib_node->entry_list; |
---|
5623 | | - |
---|
5624 | | - mlxsw_sp_fib6_node_entry_unlink(mlxsw_sp, fib6_entry); |
---|
5625 | | - mlxsw_sp_fib6_entry_destroy(mlxsw_sp, fib6_entry); |
---|
5626 | | - mlxsw_sp_fib_node_put(mlxsw_sp, fib_node); |
---|
5627 | | - if (do_break) |
---|
5628 | | - break; |
---|
5629 | | - } |
---|
| 5824 | + fib6_entry = container_of(fib_node->fib_entry, |
---|
| 5825 | + struct mlxsw_sp_fib6_entry, common); |
---|
| 5826 | + mlxsw_sp_fib_node_entry_unlink(mlxsw_sp, fib_node->fib_entry); |
---|
| 5827 | + mlxsw_sp_fib6_entry_destroy(mlxsw_sp, fib6_entry); |
---|
| 5828 | + mlxsw_sp_fib_node_put(mlxsw_sp, fib_node); |
---|
5630 | 5829 | } |
---|
5631 | 5830 | |
---|
5632 | 5831 | static void mlxsw_sp_fib_node_flush(struct mlxsw_sp *mlxsw_sp, |
---|
.. | .. |
---|
5679 | 5878 | continue; |
---|
5680 | 5879 | mlxsw_sp_vr_fib_flush(mlxsw_sp, vr, MLXSW_SP_L3_PROTO_IPV6); |
---|
5681 | 5880 | } |
---|
| 5881 | + |
---|
| 5882 | + /* After flushing all the routes, it is not possible anyone is still |
---|
| 5883 | + * using the adjacency index that is discarding packets, so free it in |
---|
| 5884 | + * case it was allocated. |
---|
| 5885 | + */ |
---|
| 5886 | + if (!mlxsw_sp->router->adj_discard_index_valid) |
---|
| 5887 | + return; |
---|
| 5888 | + mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1, |
---|
| 5889 | + mlxsw_sp->router->adj_discard_index); |
---|
| 5890 | + mlxsw_sp->router->adj_discard_index_valid = false; |
---|
5682 | 5891 | } |
---|
5683 | 5892 | |
---|
5684 | 5893 | static void mlxsw_sp_router_fib_abort(struct mlxsw_sp *mlxsw_sp) |
---|
.. | .. |
---|
5695 | 5904 | dev_warn(mlxsw_sp->bus_info->dev, "Failed to set abort trap.\n"); |
---|
5696 | 5905 | } |
---|
5697 | 5906 | |
---|
| 5907 | +struct mlxsw_sp_fib6_event_work { |
---|
| 5908 | + struct fib6_info **rt_arr; |
---|
| 5909 | + unsigned int nrt6; |
---|
| 5910 | +}; |
---|
| 5911 | + |
---|
5698 | 5912 | struct mlxsw_sp_fib_event_work { |
---|
5699 | 5913 | struct work_struct work; |
---|
5700 | 5914 | union { |
---|
5701 | | - struct fib6_entry_notifier_info fen6_info; |
---|
| 5915 | + struct mlxsw_sp_fib6_event_work fib6_work; |
---|
5702 | 5916 | struct fib_entry_notifier_info fen_info; |
---|
5703 | 5917 | struct fib_rule_notifier_info fr_info; |
---|
5704 | 5918 | struct fib_nh_notifier_info fnh_info; |
---|
.. | .. |
---|
5709 | 5923 | unsigned long event; |
---|
5710 | 5924 | }; |
---|
5711 | 5925 | |
---|
| 5926 | +static int |
---|
| 5927 | +mlxsw_sp_router_fib6_work_init(struct mlxsw_sp_fib6_event_work *fib6_work, |
---|
| 5928 | + struct fib6_entry_notifier_info *fen6_info) |
---|
| 5929 | +{ |
---|
| 5930 | + struct fib6_info *rt = fen6_info->rt; |
---|
| 5931 | + struct fib6_info **rt_arr; |
---|
| 5932 | + struct fib6_info *iter; |
---|
| 5933 | + unsigned int nrt6; |
---|
| 5934 | + int i = 0; |
---|
| 5935 | + |
---|
| 5936 | + nrt6 = fen6_info->nsiblings + 1; |
---|
| 5937 | + |
---|
| 5938 | + rt_arr = kcalloc(nrt6, sizeof(struct fib6_info *), GFP_ATOMIC); |
---|
| 5939 | + if (!rt_arr) |
---|
| 5940 | + return -ENOMEM; |
---|
| 5941 | + |
---|
| 5942 | + fib6_work->rt_arr = rt_arr; |
---|
| 5943 | + fib6_work->nrt6 = nrt6; |
---|
| 5944 | + |
---|
| 5945 | + rt_arr[0] = rt; |
---|
| 5946 | + fib6_info_hold(rt); |
---|
| 5947 | + |
---|
| 5948 | + if (!fen6_info->nsiblings) |
---|
| 5949 | + return 0; |
---|
| 5950 | + |
---|
| 5951 | + list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings) { |
---|
| 5952 | + if (i == fen6_info->nsiblings) |
---|
| 5953 | + break; |
---|
| 5954 | + |
---|
| 5955 | + rt_arr[i + 1] = iter; |
---|
| 5956 | + fib6_info_hold(iter); |
---|
| 5957 | + i++; |
---|
| 5958 | + } |
---|
| 5959 | + WARN_ON_ONCE(i != fen6_info->nsiblings); |
---|
| 5960 | + |
---|
| 5961 | + return 0; |
---|
| 5962 | +} |
---|
| 5963 | + |
---|
| 5964 | +static void |
---|
| 5965 | +mlxsw_sp_router_fib6_work_fini(struct mlxsw_sp_fib6_event_work *fib6_work) |
---|
| 5966 | +{ |
---|
| 5967 | + int i; |
---|
| 5968 | + |
---|
| 5969 | + for (i = 0; i < fib6_work->nrt6; i++) |
---|
| 5970 | + mlxsw_sp_rt6_release(fib6_work->rt_arr[i]); |
---|
| 5971 | + kfree(fib6_work->rt_arr); |
---|
| 5972 | +} |
---|
| 5973 | + |
---|
5712 | 5974 | static void mlxsw_sp_router_fib4_event_work(struct work_struct *work) |
---|
5713 | 5975 | { |
---|
5714 | 5976 | struct mlxsw_sp_fib_event_work *fib_work = |
---|
5715 | 5977 | container_of(work, struct mlxsw_sp_fib_event_work, work); |
---|
5716 | 5978 | struct mlxsw_sp *mlxsw_sp = fib_work->mlxsw_sp; |
---|
5717 | | - bool replace, append; |
---|
5718 | 5979 | int err; |
---|
5719 | 5980 | |
---|
5720 | | - /* Protect internal structures from changes */ |
---|
5721 | | - rtnl_lock(); |
---|
| 5981 | + mutex_lock(&mlxsw_sp->router->lock); |
---|
5722 | 5982 | mlxsw_sp_span_respin(mlxsw_sp); |
---|
5723 | 5983 | |
---|
5724 | 5984 | switch (fib_work->event) { |
---|
5725 | | - case FIB_EVENT_ENTRY_REPLACE: /* fall through */ |
---|
5726 | | - case FIB_EVENT_ENTRY_APPEND: /* fall through */ |
---|
5727 | | - case FIB_EVENT_ENTRY_ADD: |
---|
5728 | | - replace = fib_work->event == FIB_EVENT_ENTRY_REPLACE; |
---|
5729 | | - append = fib_work->event == FIB_EVENT_ENTRY_APPEND; |
---|
5730 | | - err = mlxsw_sp_router_fib4_add(mlxsw_sp, &fib_work->fen_info, |
---|
5731 | | - replace, append); |
---|
| 5985 | + case FIB_EVENT_ENTRY_REPLACE: |
---|
| 5986 | + err = mlxsw_sp_router_fib4_replace(mlxsw_sp, |
---|
| 5987 | + &fib_work->fen_info); |
---|
5732 | 5988 | if (err) |
---|
5733 | 5989 | mlxsw_sp_router_fib_abort(mlxsw_sp); |
---|
5734 | 5990 | fib_info_put(fib_work->fen_info.fi); |
---|
.. | .. |
---|
5737 | 5993 | mlxsw_sp_router_fib4_del(mlxsw_sp, &fib_work->fen_info); |
---|
5738 | 5994 | fib_info_put(fib_work->fen_info.fi); |
---|
5739 | 5995 | break; |
---|
5740 | | - case FIB_EVENT_RULE_ADD: |
---|
5741 | | - /* if we get here, a rule was added that we do not support. |
---|
5742 | | - * just do the fib_abort |
---|
5743 | | - */ |
---|
5744 | | - mlxsw_sp_router_fib_abort(mlxsw_sp); |
---|
5745 | | - break; |
---|
5746 | | - case FIB_EVENT_NH_ADD: /* fall through */ |
---|
| 5996 | + case FIB_EVENT_NH_ADD: |
---|
5747 | 5997 | case FIB_EVENT_NH_DEL: |
---|
5748 | 5998 | mlxsw_sp_nexthop4_event(mlxsw_sp, fib_work->event, |
---|
5749 | 5999 | fib_work->fnh_info.fib_nh); |
---|
5750 | 6000 | fib_info_put(fib_work->fnh_info.fib_nh->nh_parent); |
---|
5751 | 6001 | break; |
---|
5752 | 6002 | } |
---|
5753 | | - rtnl_unlock(); |
---|
| 6003 | + mutex_unlock(&mlxsw_sp->router->lock); |
---|
5754 | 6004 | kfree(fib_work); |
---|
5755 | 6005 | } |
---|
5756 | 6006 | |
---|
.. | .. |
---|
5759 | 6009 | struct mlxsw_sp_fib_event_work *fib_work = |
---|
5760 | 6010 | container_of(work, struct mlxsw_sp_fib_event_work, work); |
---|
5761 | 6011 | struct mlxsw_sp *mlxsw_sp = fib_work->mlxsw_sp; |
---|
5762 | | - bool replace; |
---|
5763 | 6012 | int err; |
---|
5764 | 6013 | |
---|
5765 | | - rtnl_lock(); |
---|
| 6014 | + mutex_lock(&mlxsw_sp->router->lock); |
---|
5766 | 6015 | mlxsw_sp_span_respin(mlxsw_sp); |
---|
5767 | 6016 | |
---|
5768 | 6017 | switch (fib_work->event) { |
---|
5769 | | - case FIB_EVENT_ENTRY_REPLACE: /* fall through */ |
---|
5770 | | - case FIB_EVENT_ENTRY_APPEND: /* fall through */ |
---|
5771 | | - case FIB_EVENT_ENTRY_ADD: |
---|
5772 | | - replace = fib_work->event == FIB_EVENT_ENTRY_REPLACE; |
---|
5773 | | - err = mlxsw_sp_router_fib6_add(mlxsw_sp, |
---|
5774 | | - fib_work->fen6_info.rt, replace); |
---|
| 6018 | + case FIB_EVENT_ENTRY_REPLACE: |
---|
| 6019 | + err = mlxsw_sp_router_fib6_replace(mlxsw_sp, |
---|
| 6020 | + fib_work->fib6_work.rt_arr, |
---|
| 6021 | + fib_work->fib6_work.nrt6); |
---|
5775 | 6022 | if (err) |
---|
5776 | 6023 | mlxsw_sp_router_fib_abort(mlxsw_sp); |
---|
5777 | | - mlxsw_sp_rt6_release(fib_work->fen6_info.rt); |
---|
| 6024 | + mlxsw_sp_router_fib6_work_fini(&fib_work->fib6_work); |
---|
| 6025 | + break; |
---|
| 6026 | + case FIB_EVENT_ENTRY_APPEND: |
---|
| 6027 | + err = mlxsw_sp_router_fib6_append(mlxsw_sp, |
---|
| 6028 | + fib_work->fib6_work.rt_arr, |
---|
| 6029 | + fib_work->fib6_work.nrt6); |
---|
| 6030 | + if (err) |
---|
| 6031 | + mlxsw_sp_router_fib_abort(mlxsw_sp); |
---|
| 6032 | + mlxsw_sp_router_fib6_work_fini(&fib_work->fib6_work); |
---|
5778 | 6033 | break; |
---|
5779 | 6034 | case FIB_EVENT_ENTRY_DEL: |
---|
5780 | | - mlxsw_sp_router_fib6_del(mlxsw_sp, fib_work->fen6_info.rt); |
---|
5781 | | - mlxsw_sp_rt6_release(fib_work->fen6_info.rt); |
---|
5782 | | - break; |
---|
5783 | | - case FIB_EVENT_RULE_ADD: |
---|
5784 | | - /* if we get here, a rule was added that we do not support. |
---|
5785 | | - * just do the fib_abort |
---|
5786 | | - */ |
---|
5787 | | - mlxsw_sp_router_fib_abort(mlxsw_sp); |
---|
| 6035 | + mlxsw_sp_router_fib6_del(mlxsw_sp, |
---|
| 6036 | + fib_work->fib6_work.rt_arr, |
---|
| 6037 | + fib_work->fib6_work.nrt6); |
---|
| 6038 | + mlxsw_sp_router_fib6_work_fini(&fib_work->fib6_work); |
---|
5788 | 6039 | break; |
---|
5789 | 6040 | } |
---|
5790 | | - rtnl_unlock(); |
---|
| 6041 | + mutex_unlock(&mlxsw_sp->router->lock); |
---|
5791 | 6042 | kfree(fib_work); |
---|
5792 | 6043 | } |
---|
5793 | 6044 | |
---|
.. | .. |
---|
5800 | 6051 | int err; |
---|
5801 | 6052 | |
---|
5802 | 6053 | rtnl_lock(); |
---|
| 6054 | + mutex_lock(&mlxsw_sp->router->lock); |
---|
5803 | 6055 | switch (fib_work->event) { |
---|
5804 | | - case FIB_EVENT_ENTRY_REPLACE: /* fall through */ |
---|
| 6056 | + case FIB_EVENT_ENTRY_REPLACE: |
---|
5805 | 6057 | case FIB_EVENT_ENTRY_ADD: |
---|
5806 | 6058 | replace = fib_work->event == FIB_EVENT_ENTRY_REPLACE; |
---|
5807 | 6059 | |
---|
.. | .. |
---|
5827 | 6079 | &fib_work->ven_info); |
---|
5828 | 6080 | dev_put(fib_work->ven_info.dev); |
---|
5829 | 6081 | break; |
---|
5830 | | - case FIB_EVENT_RULE_ADD: |
---|
5831 | | - /* if we get here, a rule was added that we do not support. |
---|
5832 | | - * just do the fib_abort |
---|
5833 | | - */ |
---|
5834 | | - mlxsw_sp_router_fib_abort(mlxsw_sp); |
---|
5835 | | - break; |
---|
5836 | 6082 | } |
---|
| 6083 | + mutex_unlock(&mlxsw_sp->router->lock); |
---|
5837 | 6084 | rtnl_unlock(); |
---|
5838 | 6085 | kfree(fib_work); |
---|
5839 | 6086 | } |
---|
.. | .. |
---|
5845 | 6092 | struct fib_nh_notifier_info *fnh_info; |
---|
5846 | 6093 | |
---|
5847 | 6094 | switch (fib_work->event) { |
---|
5848 | | - case FIB_EVENT_ENTRY_REPLACE: /* fall through */ |
---|
5849 | | - case FIB_EVENT_ENTRY_APPEND: /* fall through */ |
---|
5850 | | - case FIB_EVENT_ENTRY_ADD: /* fall through */ |
---|
| 6095 | + case FIB_EVENT_ENTRY_REPLACE: |
---|
5851 | 6096 | case FIB_EVENT_ENTRY_DEL: |
---|
5852 | 6097 | fen_info = container_of(info, struct fib_entry_notifier_info, |
---|
5853 | 6098 | info); |
---|
.. | .. |
---|
5857 | 6102 | */ |
---|
5858 | 6103 | fib_info_hold(fib_work->fen_info.fi); |
---|
5859 | 6104 | break; |
---|
5860 | | - case FIB_EVENT_NH_ADD: /* fall through */ |
---|
| 6105 | + case FIB_EVENT_NH_ADD: |
---|
5861 | 6106 | case FIB_EVENT_NH_DEL: |
---|
5862 | 6107 | fnh_info = container_of(info, struct fib_nh_notifier_info, |
---|
5863 | 6108 | info); |
---|
.. | .. |
---|
5867 | 6112 | } |
---|
5868 | 6113 | } |
---|
5869 | 6114 | |
---|
5870 | | -static void mlxsw_sp_router_fib6_event(struct mlxsw_sp_fib_event_work *fib_work, |
---|
5871 | | - struct fib_notifier_info *info) |
---|
| 6115 | +static int mlxsw_sp_router_fib6_event(struct mlxsw_sp_fib_event_work *fib_work, |
---|
| 6116 | + struct fib_notifier_info *info) |
---|
5872 | 6117 | { |
---|
5873 | 6118 | struct fib6_entry_notifier_info *fen6_info; |
---|
| 6119 | + int err; |
---|
5874 | 6120 | |
---|
5875 | 6121 | switch (fib_work->event) { |
---|
5876 | | - case FIB_EVENT_ENTRY_REPLACE: /* fall through */ |
---|
5877 | | - case FIB_EVENT_ENTRY_APPEND: /* fall through */ |
---|
5878 | | - case FIB_EVENT_ENTRY_ADD: /* fall through */ |
---|
| 6122 | + case FIB_EVENT_ENTRY_REPLACE: |
---|
| 6123 | + case FIB_EVENT_ENTRY_APPEND: |
---|
5879 | 6124 | case FIB_EVENT_ENTRY_DEL: |
---|
5880 | 6125 | fen6_info = container_of(info, struct fib6_entry_notifier_info, |
---|
5881 | 6126 | info); |
---|
5882 | | - fib_work->fen6_info = *fen6_info; |
---|
5883 | | - fib6_info_hold(fib_work->fen6_info.rt); |
---|
| 6127 | + err = mlxsw_sp_router_fib6_work_init(&fib_work->fib6_work, |
---|
| 6128 | + fen6_info); |
---|
| 6129 | + if (err) |
---|
| 6130 | + return err; |
---|
5884 | 6131 | break; |
---|
5885 | 6132 | } |
---|
| 6133 | + |
---|
| 6134 | + return 0; |
---|
5886 | 6135 | } |
---|
5887 | 6136 | |
---|
5888 | 6137 | static void |
---|
.. | .. |
---|
5890 | 6139 | struct fib_notifier_info *info) |
---|
5891 | 6140 | { |
---|
5892 | 6141 | switch (fib_work->event) { |
---|
5893 | | - case FIB_EVENT_ENTRY_REPLACE: /* fall through */ |
---|
5894 | | - case FIB_EVENT_ENTRY_ADD: /* fall through */ |
---|
| 6142 | + case FIB_EVENT_ENTRY_REPLACE: |
---|
| 6143 | + case FIB_EVENT_ENTRY_ADD: |
---|
5895 | 6144 | case FIB_EVENT_ENTRY_DEL: |
---|
5896 | 6145 | memcpy(&fib_work->men_info, info, sizeof(fib_work->men_info)); |
---|
5897 | 6146 | mr_cache_hold(fib_work->men_info.mfc); |
---|
5898 | 6147 | break; |
---|
5899 | | - case FIB_EVENT_VIF_ADD: /* fall through */ |
---|
| 6148 | + case FIB_EVENT_VIF_ADD: |
---|
5900 | 6149 | case FIB_EVENT_VIF_DEL: |
---|
5901 | 6150 | memcpy(&fib_work->ven_info, info, sizeof(fib_work->ven_info)); |
---|
5902 | 6151 | dev_hold(fib_work->ven_info.dev); |
---|
.. | .. |
---|
5922 | 6171 | |
---|
5923 | 6172 | fr_info = container_of(info, struct fib_rule_notifier_info, info); |
---|
5924 | 6173 | rule = fr_info->rule; |
---|
| 6174 | + |
---|
| 6175 | + /* Rule only affects locally generated traffic */ |
---|
| 6176 | + if (rule->iifindex == mlxsw_sp_net(mlxsw_sp)->loopback_dev->ifindex) |
---|
| 6177 | + return 0; |
---|
5925 | 6178 | |
---|
5926 | 6179 | switch (info->family) { |
---|
5927 | 6180 | case AF_INET: |
---|
.. | .. |
---|
5957 | 6210 | struct mlxsw_sp_router *router; |
---|
5958 | 6211 | int err; |
---|
5959 | 6212 | |
---|
5960 | | - if (!net_eq(info->net, &init_net) || |
---|
5961 | | - (info->family != AF_INET && info->family != AF_INET6 && |
---|
| 6213 | + if ((info->family != AF_INET && info->family != AF_INET6 && |
---|
5962 | 6214 | info->family != RTNL_FAMILY_IPMR && |
---|
5963 | 6215 | info->family != RTNL_FAMILY_IP6MR)) |
---|
5964 | 6216 | return NOTIFY_DONE; |
---|
.. | .. |
---|
5966 | 6218 | router = container_of(nb, struct mlxsw_sp_router, fib_nb); |
---|
5967 | 6219 | |
---|
5968 | 6220 | switch (event) { |
---|
5969 | | - case FIB_EVENT_RULE_ADD: /* fall through */ |
---|
| 6221 | + case FIB_EVENT_RULE_ADD: |
---|
5970 | 6222 | case FIB_EVENT_RULE_DEL: |
---|
5971 | 6223 | err = mlxsw_sp_router_fib_rule_event(event, info, |
---|
5972 | 6224 | router->mlxsw_sp); |
---|
5973 | | - if (!err || info->extack) |
---|
5974 | | - return notifier_from_errno(err); |
---|
5975 | | - break; |
---|
| 6225 | + return notifier_from_errno(err); |
---|
5976 | 6226 | case FIB_EVENT_ENTRY_ADD: |
---|
| 6227 | + case FIB_EVENT_ENTRY_REPLACE: |
---|
| 6228 | + case FIB_EVENT_ENTRY_APPEND: |
---|
5977 | 6229 | if (router->aborted) { |
---|
5978 | 6230 | NL_SET_ERR_MSG_MOD(info->extack, "FIB offload was aborted. Not configuring route"); |
---|
5979 | 6231 | return notifier_from_errno(-EINVAL); |
---|
| 6232 | + } |
---|
| 6233 | + if (info->family == AF_INET) { |
---|
| 6234 | + struct fib_entry_notifier_info *fen_info = ptr; |
---|
| 6235 | + |
---|
| 6236 | + if (fen_info->fi->fib_nh_is_v6) { |
---|
| 6237 | + NL_SET_ERR_MSG_MOD(info->extack, "IPv6 gateway with IPv4 route is not supported"); |
---|
| 6238 | + return notifier_from_errno(-EINVAL); |
---|
| 6239 | + } |
---|
| 6240 | + if (fen_info->fi->nh) { |
---|
| 6241 | + NL_SET_ERR_MSG_MOD(info->extack, "IPv4 route with nexthop objects is not supported"); |
---|
| 6242 | + return notifier_from_errno(-EINVAL); |
---|
| 6243 | + } |
---|
| 6244 | + } else if (info->family == AF_INET6) { |
---|
| 6245 | + struct fib6_entry_notifier_info *fen6_info; |
---|
| 6246 | + |
---|
| 6247 | + fen6_info = container_of(info, |
---|
| 6248 | + struct fib6_entry_notifier_info, |
---|
| 6249 | + info); |
---|
| 6250 | + if (fen6_info->rt->nh) { |
---|
| 6251 | + NL_SET_ERR_MSG_MOD(info->extack, "IPv6 route with nexthop objects is not supported"); |
---|
| 6252 | + return notifier_from_errno(-EINVAL); |
---|
| 6253 | + } |
---|
5980 | 6254 | } |
---|
5981 | 6255 | break; |
---|
5982 | 6256 | } |
---|
.. | .. |
---|
5995 | 6269 | break; |
---|
5996 | 6270 | case AF_INET6: |
---|
5997 | 6271 | INIT_WORK(&fib_work->work, mlxsw_sp_router_fib6_event_work); |
---|
5998 | | - mlxsw_sp_router_fib6_event(fib_work, info); |
---|
| 6272 | + err = mlxsw_sp_router_fib6_event(fib_work, info); |
---|
| 6273 | + if (err) |
---|
| 6274 | + goto err_fib_event; |
---|
5999 | 6275 | break; |
---|
6000 | 6276 | case RTNL_FAMILY_IP6MR: |
---|
6001 | 6277 | case RTNL_FAMILY_IPMR: |
---|
.. | .. |
---|
6007 | 6283 | mlxsw_core_schedule_work(&fib_work->work); |
---|
6008 | 6284 | |
---|
6009 | 6285 | return NOTIFY_DONE; |
---|
| 6286 | + |
---|
| 6287 | +err_fib_event: |
---|
| 6288 | + kfree(fib_work); |
---|
| 6289 | + return NOTIFY_BAD; |
---|
6010 | 6290 | } |
---|
6011 | 6291 | |
---|
6012 | | -struct mlxsw_sp_rif * |
---|
| 6292 | +static struct mlxsw_sp_rif * |
---|
6013 | 6293 | mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp *mlxsw_sp, |
---|
6014 | 6294 | const struct net_device *dev) |
---|
6015 | 6295 | { |
---|
.. | .. |
---|
6023 | 6303 | return NULL; |
---|
6024 | 6304 | } |
---|
6025 | 6305 | |
---|
| 6306 | +bool mlxsw_sp_rif_exists(struct mlxsw_sp *mlxsw_sp, |
---|
| 6307 | + const struct net_device *dev) |
---|
| 6308 | +{ |
---|
| 6309 | + struct mlxsw_sp_rif *rif; |
---|
| 6310 | + |
---|
| 6311 | + mutex_lock(&mlxsw_sp->router->lock); |
---|
| 6312 | + rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev); |
---|
| 6313 | + mutex_unlock(&mlxsw_sp->router->lock); |
---|
| 6314 | + |
---|
| 6315 | + return rif; |
---|
| 6316 | +} |
---|
| 6317 | + |
---|
| 6318 | +u16 mlxsw_sp_rif_vid(struct mlxsw_sp *mlxsw_sp, const struct net_device *dev) |
---|
| 6319 | +{ |
---|
| 6320 | + struct mlxsw_sp_rif *rif; |
---|
| 6321 | + u16 vid = 0; |
---|
| 6322 | + |
---|
| 6323 | + mutex_lock(&mlxsw_sp->router->lock); |
---|
| 6324 | + rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev); |
---|
| 6325 | + if (!rif) |
---|
| 6326 | + goto out; |
---|
| 6327 | + |
---|
| 6328 | + /* We only return the VID for VLAN RIFs. Otherwise we return an |
---|
| 6329 | + * invalid value (0). |
---|
| 6330 | + */ |
---|
| 6331 | + if (rif->ops->type != MLXSW_SP_RIF_TYPE_VLAN) |
---|
| 6332 | + goto out; |
---|
| 6333 | + |
---|
| 6334 | + vid = mlxsw_sp_fid_8021q_vid(rif->fid); |
---|
| 6335 | + |
---|
| 6336 | +out: |
---|
| 6337 | + mutex_unlock(&mlxsw_sp->router->lock); |
---|
| 6338 | + return vid; |
---|
| 6339 | +} |
---|
| 6340 | + |
---|
6026 | 6341 | static int mlxsw_sp_router_rif_disable(struct mlxsw_sp *mlxsw_sp, u16 rif) |
---|
6027 | 6342 | { |
---|
6028 | 6343 | char ritr_pl[MLXSW_REG_RITR_LEN]; |
---|
.. | .. |
---|
6030 | 6345 | |
---|
6031 | 6346 | mlxsw_reg_ritr_rif_pack(ritr_pl, rif); |
---|
6032 | 6347 | err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl); |
---|
6033 | | - if (WARN_ON_ONCE(err)) |
---|
| 6348 | + if (err) |
---|
6034 | 6349 | return err; |
---|
6035 | 6350 | |
---|
6036 | 6351 | mlxsw_reg_ritr_enable_set(ritr_pl, false); |
---|
.. | .. |
---|
6057 | 6372 | case NETDEV_UP: |
---|
6058 | 6373 | return rif == NULL; |
---|
6059 | 6374 | case NETDEV_DOWN: |
---|
6060 | | - idev = __in_dev_get_rtnl(dev); |
---|
| 6375 | + rcu_read_lock(); |
---|
| 6376 | + idev = __in_dev_get_rcu(dev); |
---|
6061 | 6377 | if (idev && idev->ifa_list) |
---|
6062 | 6378 | addr_list_empty = false; |
---|
6063 | 6379 | |
---|
.. | .. |
---|
6065 | 6381 | if (addr_list_empty && inet6_dev && |
---|
6066 | 6382 | !list_empty(&inet6_dev->addr_list)) |
---|
6067 | 6383 | addr_list_empty = false; |
---|
| 6384 | + rcu_read_unlock(); |
---|
6068 | 6385 | |
---|
6069 | 6386 | /* macvlans do not have a RIF, but rather piggy back on the |
---|
6070 | 6387 | * RIF of their lower device. |
---|
.. | .. |
---|
6133 | 6450 | |
---|
6134 | 6451 | INIT_LIST_HEAD(&rif->nexthop_list); |
---|
6135 | 6452 | INIT_LIST_HEAD(&rif->neigh_list); |
---|
6136 | | - ether_addr_copy(rif->addr, l3_dev->dev_addr); |
---|
6137 | | - rif->mtu = l3_dev->mtu; |
---|
| 6453 | + if (l3_dev) { |
---|
| 6454 | + ether_addr_copy(rif->addr, l3_dev->dev_addr); |
---|
| 6455 | + rif->mtu = l3_dev->mtu; |
---|
| 6456 | + rif->dev = l3_dev; |
---|
| 6457 | + } |
---|
6138 | 6458 | rif->vr_id = vr_id; |
---|
6139 | | - rif->dev = l3_dev; |
---|
6140 | 6459 | rif->rif_index = rif_index; |
---|
6141 | 6460 | |
---|
6142 | 6461 | return rif; |
---|
.. | .. |
---|
6160 | 6479 | |
---|
6161 | 6480 | u16 mlxsw_sp_ipip_lb_ul_vr_id(const struct mlxsw_sp_rif_ipip_lb *lb_rif) |
---|
6162 | 6481 | { |
---|
6163 | | - return lb_rif->ul_vr_id; |
---|
| 6482 | + u32 ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(lb_rif->common.dev); |
---|
| 6483 | + struct mlxsw_sp_vr *ul_vr; |
---|
| 6484 | + |
---|
| 6485 | + ul_vr = mlxsw_sp_vr_get(lb_rif->common.mlxsw_sp, ul_tb_id, NULL); |
---|
| 6486 | + if (WARN_ON(IS_ERR(ul_vr))) |
---|
| 6487 | + return 0; |
---|
| 6488 | + |
---|
| 6489 | + return ul_vr->id; |
---|
| 6490 | +} |
---|
| 6491 | + |
---|
| 6492 | +u16 mlxsw_sp_ipip_lb_ul_rif_id(const struct mlxsw_sp_rif_ipip_lb *lb_rif) |
---|
| 6493 | +{ |
---|
| 6494 | + return lb_rif->ul_rif_id; |
---|
6164 | 6495 | } |
---|
6165 | 6496 | |
---|
6166 | 6497 | int mlxsw_sp_rif_dev_ifindex(const struct mlxsw_sp_rif *rif) |
---|
.. | .. |
---|
6171 | 6502 | const struct net_device *mlxsw_sp_rif_dev(const struct mlxsw_sp_rif *rif) |
---|
6172 | 6503 | { |
---|
6173 | 6504 | return rif->dev; |
---|
6174 | | -} |
---|
6175 | | - |
---|
6176 | | -struct mlxsw_sp_fid *mlxsw_sp_rif_fid(const struct mlxsw_sp_rif *rif) |
---|
6177 | | -{ |
---|
6178 | | - return rif->fid; |
---|
6179 | 6505 | } |
---|
6180 | 6506 | |
---|
6181 | 6507 | static struct mlxsw_sp_rif * |
---|
.. | .. |
---|
6193 | 6519 | int i, err; |
---|
6194 | 6520 | |
---|
6195 | 6521 | type = mlxsw_sp_dev_rif_type(mlxsw_sp, params->dev); |
---|
6196 | | - ops = mlxsw_sp->router->rif_ops_arr[type]; |
---|
| 6522 | + ops = mlxsw_sp->rif_ops_arr[type]; |
---|
6197 | 6523 | |
---|
6198 | 6524 | vr = mlxsw_sp_vr_get(mlxsw_sp, tb_id ? : RT_TABLE_MAIN, extack); |
---|
6199 | 6525 | if (IS_ERR(vr)) |
---|
.. | .. |
---|
6211 | 6537 | err = -ENOMEM; |
---|
6212 | 6538 | goto err_rif_alloc; |
---|
6213 | 6539 | } |
---|
| 6540 | + dev_hold(rif->dev); |
---|
| 6541 | + mlxsw_sp->router->rifs[rif_index] = rif; |
---|
6214 | 6542 | rif->mlxsw_sp = mlxsw_sp; |
---|
6215 | 6543 | rif->ops = ops; |
---|
6216 | 6544 | |
---|
.. | .. |
---|
6237 | 6565 | } |
---|
6238 | 6566 | |
---|
6239 | 6567 | mlxsw_sp_rif_counters_alloc(rif); |
---|
6240 | | - mlxsw_sp->router->rifs[rif_index] = rif; |
---|
6241 | 6568 | |
---|
6242 | 6569 | return rif; |
---|
6243 | 6570 | |
---|
.. | .. |
---|
6249 | 6576 | if (fid) |
---|
6250 | 6577 | mlxsw_sp_fid_put(fid); |
---|
6251 | 6578 | err_fid_get: |
---|
| 6579 | + mlxsw_sp->router->rifs[rif_index] = NULL; |
---|
| 6580 | + dev_put(rif->dev); |
---|
6252 | 6581 | kfree(rif); |
---|
6253 | 6582 | err_rif_alloc: |
---|
6254 | 6583 | err_rif_index_alloc: |
---|
.. | .. |
---|
6257 | 6586 | return ERR_PTR(err); |
---|
6258 | 6587 | } |
---|
6259 | 6588 | |
---|
6260 | | -void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif) |
---|
| 6589 | +static void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif) |
---|
6261 | 6590 | { |
---|
6262 | 6591 | const struct mlxsw_sp_rif_ops *ops = rif->ops; |
---|
6263 | 6592 | struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp; |
---|
.. | .. |
---|
6268 | 6597 | mlxsw_sp_router_rif_gone_sync(mlxsw_sp, rif); |
---|
6269 | 6598 | vr = &mlxsw_sp->router->vrs[rif->vr_id]; |
---|
6270 | 6599 | |
---|
6271 | | - mlxsw_sp->router->rifs[rif->rif_index] = NULL; |
---|
6272 | 6600 | mlxsw_sp_rif_counters_free(rif); |
---|
6273 | 6601 | for (i = 0; i < MLXSW_SP_L3_PROTO_MAX; i++) |
---|
6274 | 6602 | mlxsw_sp_mr_rif_del(vr->mr_table[i], rif); |
---|
.. | .. |
---|
6276 | 6604 | if (fid) |
---|
6277 | 6605 | /* Loopback RIFs are not associated with a FID. */ |
---|
6278 | 6606 | mlxsw_sp_fid_put(fid); |
---|
| 6607 | + mlxsw_sp->router->rifs[rif->rif_index] = NULL; |
---|
| 6608 | + dev_put(rif->dev); |
---|
6279 | 6609 | kfree(rif); |
---|
6280 | 6610 | vr->rif_count--; |
---|
6281 | 6611 | mlxsw_sp_vr_put(mlxsw_sp, vr); |
---|
.. | .. |
---|
6286 | 6616 | { |
---|
6287 | 6617 | struct mlxsw_sp_rif *rif; |
---|
6288 | 6618 | |
---|
| 6619 | + mutex_lock(&mlxsw_sp->router->lock); |
---|
6289 | 6620 | rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev); |
---|
6290 | 6621 | if (!rif) |
---|
6291 | | - return; |
---|
| 6622 | + goto out; |
---|
6292 | 6623 | mlxsw_sp_rif_destroy(rif); |
---|
| 6624 | +out: |
---|
| 6625 | + mutex_unlock(&mlxsw_sp->router->lock); |
---|
6293 | 6626 | } |
---|
6294 | 6627 | |
---|
6295 | 6628 | static void |
---|
.. | .. |
---|
6306 | 6639 | params->system_port = mlxsw_sp_port->local_port; |
---|
6307 | 6640 | } |
---|
6308 | 6641 | |
---|
| 6642 | +static struct mlxsw_sp_rif_subport * |
---|
| 6643 | +mlxsw_sp_rif_subport_rif(const struct mlxsw_sp_rif *rif) |
---|
| 6644 | +{ |
---|
| 6645 | + return container_of(rif, struct mlxsw_sp_rif_subport, common); |
---|
| 6646 | +} |
---|
| 6647 | + |
---|
| 6648 | +static struct mlxsw_sp_rif * |
---|
| 6649 | +mlxsw_sp_rif_subport_get(struct mlxsw_sp *mlxsw_sp, |
---|
| 6650 | + const struct mlxsw_sp_rif_params *params, |
---|
| 6651 | + struct netlink_ext_ack *extack) |
---|
| 6652 | +{ |
---|
| 6653 | + struct mlxsw_sp_rif_subport *rif_subport; |
---|
| 6654 | + struct mlxsw_sp_rif *rif; |
---|
| 6655 | + |
---|
| 6656 | + rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, params->dev); |
---|
| 6657 | + if (!rif) |
---|
| 6658 | + return mlxsw_sp_rif_create(mlxsw_sp, params, extack); |
---|
| 6659 | + |
---|
| 6660 | + rif_subport = mlxsw_sp_rif_subport_rif(rif); |
---|
| 6661 | + refcount_inc(&rif_subport->ref_count); |
---|
| 6662 | + return rif; |
---|
| 6663 | +} |
---|
| 6664 | + |
---|
| 6665 | +static void mlxsw_sp_rif_subport_put(struct mlxsw_sp_rif *rif) |
---|
| 6666 | +{ |
---|
| 6667 | + struct mlxsw_sp_rif_subport *rif_subport; |
---|
| 6668 | + |
---|
| 6669 | + rif_subport = mlxsw_sp_rif_subport_rif(rif); |
---|
| 6670 | + if (!refcount_dec_and_test(&rif_subport->ref_count)) |
---|
| 6671 | + return; |
---|
| 6672 | + |
---|
| 6673 | + mlxsw_sp_rif_destroy(rif); |
---|
| 6674 | +} |
---|
| 6675 | + |
---|
6309 | 6676 | static int |
---|
6310 | 6677 | mlxsw_sp_port_vlan_router_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, |
---|
6311 | 6678 | struct net_device *l3_dev, |
---|
.. | .. |
---|
6313 | 6680 | { |
---|
6314 | 6681 | struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; |
---|
6315 | 6682 | struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; |
---|
| 6683 | + struct mlxsw_sp_rif_params params = { |
---|
| 6684 | + .dev = l3_dev, |
---|
| 6685 | + }; |
---|
6316 | 6686 | u16 vid = mlxsw_sp_port_vlan->vid; |
---|
6317 | 6687 | struct mlxsw_sp_rif *rif; |
---|
6318 | 6688 | struct mlxsw_sp_fid *fid; |
---|
6319 | 6689 | int err; |
---|
6320 | 6690 | |
---|
6321 | | - rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev); |
---|
6322 | | - if (!rif) { |
---|
6323 | | - struct mlxsw_sp_rif_params params = { |
---|
6324 | | - .dev = l3_dev, |
---|
6325 | | - }; |
---|
6326 | | - |
---|
6327 | | - mlxsw_sp_rif_subport_params_init(¶ms, mlxsw_sp_port_vlan); |
---|
6328 | | - rif = mlxsw_sp_rif_create(mlxsw_sp, ¶ms, extack); |
---|
6329 | | - if (IS_ERR(rif)) |
---|
6330 | | - return PTR_ERR(rif); |
---|
6331 | | - } |
---|
| 6691 | + mlxsw_sp_rif_subport_params_init(¶ms, mlxsw_sp_port_vlan); |
---|
| 6692 | + rif = mlxsw_sp_rif_subport_get(mlxsw_sp, ¶ms, extack); |
---|
| 6693 | + if (IS_ERR(rif)) |
---|
| 6694 | + return PTR_ERR(rif); |
---|
6332 | 6695 | |
---|
6333 | 6696 | /* FID was already created, just take a reference */ |
---|
6334 | 6697 | fid = rif->ops->fid_get(rif, extack); |
---|
.. | .. |
---|
6355 | 6718 | mlxsw_sp_fid_port_vid_unmap(fid, mlxsw_sp_port, vid); |
---|
6356 | 6719 | err_fid_port_vid_map: |
---|
6357 | 6720 | mlxsw_sp_fid_put(fid); |
---|
| 6721 | + mlxsw_sp_rif_subport_put(rif); |
---|
6358 | 6722 | return err; |
---|
6359 | 6723 | } |
---|
6360 | 6724 | |
---|
6361 | | -void |
---|
6362 | | -mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) |
---|
| 6725 | +static void |
---|
| 6726 | +__mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) |
---|
6363 | 6727 | { |
---|
6364 | 6728 | struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; |
---|
6365 | 6729 | struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; |
---|
| 6730 | + struct mlxsw_sp_rif *rif = mlxsw_sp_fid_rif(fid); |
---|
6366 | 6731 | u16 vid = mlxsw_sp_port_vlan->vid; |
---|
6367 | 6732 | |
---|
6368 | 6733 | if (WARN_ON(mlxsw_sp_fid_type(fid) != MLXSW_SP_FID_TYPE_RFID)) |
---|
.. | .. |
---|
6372 | 6737 | mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid, BR_STATE_BLOCKING); |
---|
6373 | 6738 | mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, true); |
---|
6374 | 6739 | mlxsw_sp_fid_port_vid_unmap(fid, mlxsw_sp_port, vid); |
---|
6375 | | - /* If router port holds the last reference on the rFID, then the |
---|
6376 | | - * associated Sub-port RIF will be destroyed. |
---|
6377 | | - */ |
---|
6378 | 6740 | mlxsw_sp_fid_put(fid); |
---|
| 6741 | + mlxsw_sp_rif_subport_put(rif); |
---|
| 6742 | +} |
---|
| 6743 | + |
---|
| 6744 | +void |
---|
| 6745 | +mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) |
---|
| 6746 | +{ |
---|
| 6747 | + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port_vlan->mlxsw_sp_port->mlxsw_sp; |
---|
| 6748 | + |
---|
| 6749 | + mutex_lock(&mlxsw_sp->router->lock); |
---|
| 6750 | + __mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan); |
---|
| 6751 | + mutex_unlock(&mlxsw_sp->router->lock); |
---|
6379 | 6752 | } |
---|
6380 | 6753 | |
---|
6381 | 6754 | static int mlxsw_sp_inetaddr_port_vlan_event(struct net_device *l3_dev, |
---|
.. | .. |
---|
6395 | 6768 | return mlxsw_sp_port_vlan_router_join(mlxsw_sp_port_vlan, |
---|
6396 | 6769 | l3_dev, extack); |
---|
6397 | 6770 | case NETDEV_DOWN: |
---|
6398 | | - mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan); |
---|
| 6771 | + __mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan); |
---|
6399 | 6772 | break; |
---|
6400 | 6773 | } |
---|
6401 | 6774 | |
---|
.. | .. |
---|
6411 | 6784 | netif_is_ovs_port(port_dev)) |
---|
6412 | 6785 | return 0; |
---|
6413 | 6786 | |
---|
6414 | | - return mlxsw_sp_inetaddr_port_vlan_event(port_dev, port_dev, event, 1, |
---|
6415 | | - extack); |
---|
| 6787 | + return mlxsw_sp_inetaddr_port_vlan_event(port_dev, port_dev, event, |
---|
| 6788 | + MLXSW_SP_DEFAULT_VID, extack); |
---|
6416 | 6789 | } |
---|
6417 | 6790 | |
---|
6418 | 6791 | static int __mlxsw_sp_inetaddr_lag_event(struct net_device *l3_dev, |
---|
.. | .. |
---|
6445 | 6818 | if (netif_is_bridge_port(lag_dev)) |
---|
6446 | 6819 | return 0; |
---|
6447 | 6820 | |
---|
6448 | | - return __mlxsw_sp_inetaddr_lag_event(lag_dev, lag_dev, event, 1, |
---|
6449 | | - extack); |
---|
| 6821 | + return __mlxsw_sp_inetaddr_lag_event(lag_dev, lag_dev, event, |
---|
| 6822 | + MLXSW_SP_DEFAULT_VID, extack); |
---|
6450 | 6823 | } |
---|
6451 | 6824 | |
---|
6452 | | -static int mlxsw_sp_inetaddr_bridge_event(struct net_device *l3_dev, |
---|
| 6825 | +static int mlxsw_sp_inetaddr_bridge_event(struct mlxsw_sp *mlxsw_sp, |
---|
| 6826 | + struct net_device *l3_dev, |
---|
6453 | 6827 | unsigned long event, |
---|
6454 | 6828 | struct netlink_ext_ack *extack) |
---|
6455 | 6829 | { |
---|
6456 | | - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(l3_dev); |
---|
6457 | 6830 | struct mlxsw_sp_rif_params params = { |
---|
6458 | 6831 | .dev = l3_dev, |
---|
6459 | 6832 | }; |
---|
.. | .. |
---|
6474 | 6847 | return 0; |
---|
6475 | 6848 | } |
---|
6476 | 6849 | |
---|
6477 | | -static int mlxsw_sp_inetaddr_vlan_event(struct net_device *vlan_dev, |
---|
| 6850 | +static int mlxsw_sp_inetaddr_vlan_event(struct mlxsw_sp *mlxsw_sp, |
---|
| 6851 | + struct net_device *vlan_dev, |
---|
6478 | 6852 | unsigned long event, |
---|
6479 | 6853 | struct netlink_ext_ack *extack) |
---|
6480 | 6854 | { |
---|
.. | .. |
---|
6491 | 6865 | return __mlxsw_sp_inetaddr_lag_event(vlan_dev, real_dev, event, |
---|
6492 | 6866 | vid, extack); |
---|
6493 | 6867 | else if (netif_is_bridge_master(real_dev) && br_vlan_enabled(real_dev)) |
---|
6494 | | - return mlxsw_sp_inetaddr_bridge_event(vlan_dev, event, extack); |
---|
| 6868 | + return mlxsw_sp_inetaddr_bridge_event(mlxsw_sp, vlan_dev, event, |
---|
| 6869 | + extack); |
---|
6495 | 6870 | |
---|
6496 | 6871 | return 0; |
---|
6497 | 6872 | } |
---|
.. | .. |
---|
6574 | 6949 | return err; |
---|
6575 | 6950 | } |
---|
6576 | 6951 | |
---|
6577 | | -void mlxsw_sp_rif_macvlan_del(struct mlxsw_sp *mlxsw_sp, |
---|
6578 | | - const struct net_device *macvlan_dev) |
---|
| 6952 | +static void __mlxsw_sp_rif_macvlan_del(struct mlxsw_sp *mlxsw_sp, |
---|
| 6953 | + const struct net_device *macvlan_dev) |
---|
6579 | 6954 | { |
---|
6580 | 6955 | struct macvlan_dev *vlan = netdev_priv(macvlan_dev); |
---|
6581 | 6956 | struct mlxsw_sp_rif *rif; |
---|
.. | .. |
---|
6592 | 6967 | mlxsw_sp_fid_index(rif->fid), false); |
---|
6593 | 6968 | } |
---|
6594 | 6969 | |
---|
6595 | | -static int mlxsw_sp_inetaddr_macvlan_event(struct net_device *macvlan_dev, |
---|
| 6970 | +void mlxsw_sp_rif_macvlan_del(struct mlxsw_sp *mlxsw_sp, |
---|
| 6971 | + const struct net_device *macvlan_dev) |
---|
| 6972 | +{ |
---|
| 6973 | + mutex_lock(&mlxsw_sp->router->lock); |
---|
| 6974 | + __mlxsw_sp_rif_macvlan_del(mlxsw_sp, macvlan_dev); |
---|
| 6975 | + mutex_unlock(&mlxsw_sp->router->lock); |
---|
| 6976 | +} |
---|
| 6977 | + |
---|
| 6978 | +static int mlxsw_sp_inetaddr_macvlan_event(struct mlxsw_sp *mlxsw_sp, |
---|
| 6979 | + struct net_device *macvlan_dev, |
---|
6596 | 6980 | unsigned long event, |
---|
6597 | 6981 | struct netlink_ext_ack *extack) |
---|
6598 | 6982 | { |
---|
6599 | | - struct mlxsw_sp *mlxsw_sp; |
---|
6600 | | - |
---|
6601 | | - mlxsw_sp = mlxsw_sp_lower_get(macvlan_dev); |
---|
6602 | | - if (!mlxsw_sp) |
---|
6603 | | - return 0; |
---|
6604 | | - |
---|
6605 | 6983 | switch (event) { |
---|
6606 | 6984 | case NETDEV_UP: |
---|
6607 | 6985 | return mlxsw_sp_rif_macvlan_add(mlxsw_sp, macvlan_dev, extack); |
---|
6608 | 6986 | case NETDEV_DOWN: |
---|
6609 | | - mlxsw_sp_rif_macvlan_del(mlxsw_sp, macvlan_dev); |
---|
| 6987 | + __mlxsw_sp_rif_macvlan_del(mlxsw_sp, macvlan_dev); |
---|
6610 | 6988 | break; |
---|
6611 | 6989 | } |
---|
6612 | 6990 | |
---|
6613 | 6991 | return 0; |
---|
6614 | 6992 | } |
---|
6615 | 6993 | |
---|
6616 | | -static int __mlxsw_sp_inetaddr_event(struct net_device *dev, |
---|
| 6994 | +static int mlxsw_sp_router_port_check_rif_addr(struct mlxsw_sp *mlxsw_sp, |
---|
| 6995 | + struct net_device *dev, |
---|
| 6996 | + const unsigned char *dev_addr, |
---|
| 6997 | + struct netlink_ext_ack *extack) |
---|
| 6998 | +{ |
---|
| 6999 | + struct mlxsw_sp_rif *rif; |
---|
| 7000 | + int i; |
---|
| 7001 | + |
---|
| 7002 | + /* A RIF is not created for macvlan netdevs. Their MAC is used to |
---|
| 7003 | + * populate the FDB |
---|
| 7004 | + */ |
---|
| 7005 | + if (netif_is_macvlan(dev) || netif_is_l3_master(dev)) |
---|
| 7006 | + return 0; |
---|
| 7007 | + |
---|
| 7008 | + for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) { |
---|
| 7009 | + rif = mlxsw_sp->router->rifs[i]; |
---|
| 7010 | + if (rif && rif->ops && |
---|
| 7011 | + rif->ops->type == MLXSW_SP_RIF_TYPE_IPIP_LB) |
---|
| 7012 | + continue; |
---|
| 7013 | + if (rif && rif->dev && rif->dev != dev && |
---|
| 7014 | + !ether_addr_equal_masked(rif->dev->dev_addr, dev_addr, |
---|
| 7015 | + mlxsw_sp->mac_mask)) { |
---|
| 7016 | + NL_SET_ERR_MSG_MOD(extack, "All router interface MAC addresses must have the same prefix"); |
---|
| 7017 | + return -EINVAL; |
---|
| 7018 | + } |
---|
| 7019 | + } |
---|
| 7020 | + |
---|
| 7021 | + return 0; |
---|
| 7022 | +} |
---|
| 7023 | + |
---|
| 7024 | +static int __mlxsw_sp_inetaddr_event(struct mlxsw_sp *mlxsw_sp, |
---|
| 7025 | + struct net_device *dev, |
---|
6617 | 7026 | unsigned long event, |
---|
6618 | 7027 | struct netlink_ext_ack *extack) |
---|
6619 | 7028 | { |
---|
.. | .. |
---|
6622 | 7031 | else if (netif_is_lag_master(dev)) |
---|
6623 | 7032 | return mlxsw_sp_inetaddr_lag_event(dev, event, extack); |
---|
6624 | 7033 | else if (netif_is_bridge_master(dev)) |
---|
6625 | | - return mlxsw_sp_inetaddr_bridge_event(dev, event, extack); |
---|
| 7034 | + return mlxsw_sp_inetaddr_bridge_event(mlxsw_sp, dev, event, |
---|
| 7035 | + extack); |
---|
6626 | 7036 | else if (is_vlan_dev(dev)) |
---|
6627 | | - return mlxsw_sp_inetaddr_vlan_event(dev, event, extack); |
---|
| 7037 | + return mlxsw_sp_inetaddr_vlan_event(mlxsw_sp, dev, event, |
---|
| 7038 | + extack); |
---|
6628 | 7039 | else if (netif_is_macvlan(dev)) |
---|
6629 | | - return mlxsw_sp_inetaddr_macvlan_event(dev, event, extack); |
---|
| 7040 | + return mlxsw_sp_inetaddr_macvlan_event(mlxsw_sp, dev, event, |
---|
| 7041 | + extack); |
---|
6630 | 7042 | else |
---|
6631 | 7043 | return 0; |
---|
6632 | 7044 | } |
---|
6633 | 7045 | |
---|
6634 | | -int mlxsw_sp_inetaddr_event(struct notifier_block *unused, |
---|
6635 | | - unsigned long event, void *ptr) |
---|
| 7046 | +static int mlxsw_sp_inetaddr_event(struct notifier_block *nb, |
---|
| 7047 | + unsigned long event, void *ptr) |
---|
6636 | 7048 | { |
---|
6637 | 7049 | struct in_ifaddr *ifa = (struct in_ifaddr *) ptr; |
---|
6638 | 7050 | struct net_device *dev = ifa->ifa_dev->dev; |
---|
6639 | | - struct mlxsw_sp *mlxsw_sp; |
---|
| 7051 | + struct mlxsw_sp_router *router; |
---|
6640 | 7052 | struct mlxsw_sp_rif *rif; |
---|
6641 | 7053 | int err = 0; |
---|
6642 | 7054 | |
---|
6643 | 7055 | /* NETDEV_UP event is handled by mlxsw_sp_inetaddr_valid_event */ |
---|
6644 | 7056 | if (event == NETDEV_UP) |
---|
6645 | | - goto out; |
---|
| 7057 | + return NOTIFY_DONE; |
---|
6646 | 7058 | |
---|
6647 | | - mlxsw_sp = mlxsw_sp_lower_get(dev); |
---|
6648 | | - if (!mlxsw_sp) |
---|
6649 | | - goto out; |
---|
6650 | | - |
---|
6651 | | - rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev); |
---|
| 7059 | + router = container_of(nb, struct mlxsw_sp_router, inetaddr_nb); |
---|
| 7060 | + mutex_lock(&router->lock); |
---|
| 7061 | + rif = mlxsw_sp_rif_find_by_dev(router->mlxsw_sp, dev); |
---|
6652 | 7062 | if (!mlxsw_sp_rif_should_config(rif, dev, event)) |
---|
6653 | 7063 | goto out; |
---|
6654 | 7064 | |
---|
6655 | | - err = __mlxsw_sp_inetaddr_event(dev, event, NULL); |
---|
| 7065 | + err = __mlxsw_sp_inetaddr_event(router->mlxsw_sp, dev, event, NULL); |
---|
6656 | 7066 | out: |
---|
| 7067 | + mutex_unlock(&router->lock); |
---|
6657 | 7068 | return notifier_from_errno(err); |
---|
6658 | 7069 | } |
---|
6659 | 7070 | |
---|
.. | .. |
---|
6668 | 7079 | |
---|
6669 | 7080 | mlxsw_sp = mlxsw_sp_lower_get(dev); |
---|
6670 | 7081 | if (!mlxsw_sp) |
---|
6671 | | - goto out; |
---|
| 7082 | + return NOTIFY_DONE; |
---|
6672 | 7083 | |
---|
| 7084 | + mutex_lock(&mlxsw_sp->router->lock); |
---|
6673 | 7085 | rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev); |
---|
6674 | 7086 | if (!mlxsw_sp_rif_should_config(rif, dev, event)) |
---|
6675 | 7087 | goto out; |
---|
6676 | 7088 | |
---|
6677 | | - err = __mlxsw_sp_inetaddr_event(dev, event, ivi->extack); |
---|
| 7089 | + err = mlxsw_sp_router_port_check_rif_addr(mlxsw_sp, dev, dev->dev_addr, |
---|
| 7090 | + ivi->extack); |
---|
| 7091 | + if (err) |
---|
| 7092 | + goto out; |
---|
| 7093 | + |
---|
| 7094 | + err = __mlxsw_sp_inetaddr_event(mlxsw_sp, dev, event, ivi->extack); |
---|
6678 | 7095 | out: |
---|
| 7096 | + mutex_unlock(&mlxsw_sp->router->lock); |
---|
6679 | 7097 | return notifier_from_errno(err); |
---|
6680 | 7098 | } |
---|
6681 | 7099 | |
---|
6682 | 7100 | struct mlxsw_sp_inet6addr_event_work { |
---|
6683 | 7101 | struct work_struct work; |
---|
| 7102 | + struct mlxsw_sp *mlxsw_sp; |
---|
6684 | 7103 | struct net_device *dev; |
---|
6685 | 7104 | unsigned long event; |
---|
6686 | 7105 | }; |
---|
.. | .. |
---|
6689 | 7108 | { |
---|
6690 | 7109 | struct mlxsw_sp_inet6addr_event_work *inet6addr_work = |
---|
6691 | 7110 | container_of(work, struct mlxsw_sp_inet6addr_event_work, work); |
---|
| 7111 | + struct mlxsw_sp *mlxsw_sp = inet6addr_work->mlxsw_sp; |
---|
6692 | 7112 | struct net_device *dev = inet6addr_work->dev; |
---|
6693 | 7113 | unsigned long event = inet6addr_work->event; |
---|
6694 | | - struct mlxsw_sp *mlxsw_sp; |
---|
6695 | 7114 | struct mlxsw_sp_rif *rif; |
---|
6696 | 7115 | |
---|
6697 | 7116 | rtnl_lock(); |
---|
6698 | | - mlxsw_sp = mlxsw_sp_lower_get(dev); |
---|
6699 | | - if (!mlxsw_sp) |
---|
6700 | | - goto out; |
---|
| 7117 | + mutex_lock(&mlxsw_sp->router->lock); |
---|
6701 | 7118 | |
---|
6702 | 7119 | rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev); |
---|
6703 | 7120 | if (!mlxsw_sp_rif_should_config(rif, dev, event)) |
---|
6704 | 7121 | goto out; |
---|
6705 | 7122 | |
---|
6706 | | - __mlxsw_sp_inetaddr_event(dev, event, NULL); |
---|
| 7123 | + __mlxsw_sp_inetaddr_event(mlxsw_sp, dev, event, NULL); |
---|
6707 | 7124 | out: |
---|
| 7125 | + mutex_unlock(&mlxsw_sp->router->lock); |
---|
6708 | 7126 | rtnl_unlock(); |
---|
6709 | 7127 | dev_put(dev); |
---|
6710 | 7128 | kfree(inet6addr_work); |
---|
6711 | 7129 | } |
---|
6712 | 7130 | |
---|
6713 | 7131 | /* Called with rcu_read_lock() */ |
---|
6714 | | -int mlxsw_sp_inet6addr_event(struct notifier_block *unused, |
---|
6715 | | - unsigned long event, void *ptr) |
---|
| 7132 | +static int mlxsw_sp_inet6addr_event(struct notifier_block *nb, |
---|
| 7133 | + unsigned long event, void *ptr) |
---|
6716 | 7134 | { |
---|
6717 | 7135 | struct inet6_ifaddr *if6 = (struct inet6_ifaddr *) ptr; |
---|
6718 | 7136 | struct mlxsw_sp_inet6addr_event_work *inet6addr_work; |
---|
6719 | 7137 | struct net_device *dev = if6->idev->dev; |
---|
| 7138 | + struct mlxsw_sp_router *router; |
---|
6720 | 7139 | |
---|
6721 | 7140 | /* NETDEV_UP event is handled by mlxsw_sp_inet6addr_valid_event */ |
---|
6722 | 7141 | if (event == NETDEV_UP) |
---|
6723 | | - return NOTIFY_DONE; |
---|
6724 | | - |
---|
6725 | | - if (!mlxsw_sp_port_dev_lower_find_rcu(dev)) |
---|
6726 | 7142 | return NOTIFY_DONE; |
---|
6727 | 7143 | |
---|
6728 | 7144 | inet6addr_work = kzalloc(sizeof(*inet6addr_work), GFP_ATOMIC); |
---|
6729 | 7145 | if (!inet6addr_work) |
---|
6730 | 7146 | return NOTIFY_BAD; |
---|
6731 | 7147 | |
---|
| 7148 | + router = container_of(nb, struct mlxsw_sp_router, inet6addr_nb); |
---|
6732 | 7149 | INIT_WORK(&inet6addr_work->work, mlxsw_sp_inet6addr_event_work); |
---|
| 7150 | + inet6addr_work->mlxsw_sp = router->mlxsw_sp; |
---|
6733 | 7151 | inet6addr_work->dev = dev; |
---|
6734 | 7152 | inet6addr_work->event = event; |
---|
6735 | 7153 | dev_hold(dev); |
---|
.. | .. |
---|
6749 | 7167 | |
---|
6750 | 7168 | mlxsw_sp = mlxsw_sp_lower_get(dev); |
---|
6751 | 7169 | if (!mlxsw_sp) |
---|
6752 | | - goto out; |
---|
| 7170 | + return NOTIFY_DONE; |
---|
6753 | 7171 | |
---|
| 7172 | + mutex_lock(&mlxsw_sp->router->lock); |
---|
6754 | 7173 | rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev); |
---|
6755 | 7174 | if (!mlxsw_sp_rif_should_config(rif, dev, event)) |
---|
6756 | 7175 | goto out; |
---|
6757 | 7176 | |
---|
6758 | | - err = __mlxsw_sp_inetaddr_event(dev, event, i6vi->extack); |
---|
| 7177 | + err = mlxsw_sp_router_port_check_rif_addr(mlxsw_sp, dev, dev->dev_addr, |
---|
| 7178 | + i6vi->extack); |
---|
| 7179 | + if (err) |
---|
| 7180 | + goto out; |
---|
| 7181 | + |
---|
| 7182 | + err = __mlxsw_sp_inetaddr_event(mlxsw_sp, dev, event, i6vi->extack); |
---|
6759 | 7183 | out: |
---|
| 7184 | + mutex_unlock(&mlxsw_sp->router->lock); |
---|
6760 | 7185 | return notifier_from_errno(err); |
---|
6761 | 7186 | } |
---|
6762 | 7187 | |
---|
.. | .. |
---|
6777 | 7202 | return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl); |
---|
6778 | 7203 | } |
---|
6779 | 7204 | |
---|
6780 | | -int mlxsw_sp_netdevice_router_port_event(struct net_device *dev) |
---|
| 7205 | +static int |
---|
| 7206 | +mlxsw_sp_router_port_change_event(struct mlxsw_sp *mlxsw_sp, |
---|
| 7207 | + struct mlxsw_sp_rif *rif) |
---|
6781 | 7208 | { |
---|
6782 | | - struct mlxsw_sp *mlxsw_sp; |
---|
6783 | | - struct mlxsw_sp_rif *rif; |
---|
| 7209 | + struct net_device *dev = rif->dev; |
---|
6784 | 7210 | u16 fid_index; |
---|
6785 | 7211 | int err; |
---|
6786 | 7212 | |
---|
6787 | | - mlxsw_sp = mlxsw_sp_lower_get(dev); |
---|
6788 | | - if (!mlxsw_sp) |
---|
6789 | | - return 0; |
---|
6790 | | - |
---|
6791 | | - rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev); |
---|
6792 | | - if (!rif) |
---|
6793 | | - return 0; |
---|
6794 | 7213 | fid_index = mlxsw_sp_fid_index(rif->fid); |
---|
6795 | 7214 | |
---|
6796 | 7215 | err = mlxsw_sp_rif_fdb_op(mlxsw_sp, rif->addr, fid_index, false); |
---|
.. | .. |
---|
6834 | 7253 | return err; |
---|
6835 | 7254 | } |
---|
6836 | 7255 | |
---|
| 7256 | +static int mlxsw_sp_router_port_pre_changeaddr_event(struct mlxsw_sp_rif *rif, |
---|
| 7257 | + struct netdev_notifier_pre_changeaddr_info *info) |
---|
| 7258 | +{ |
---|
| 7259 | + struct netlink_ext_ack *extack; |
---|
| 7260 | + |
---|
| 7261 | + extack = netdev_notifier_info_to_extack(&info->info); |
---|
| 7262 | + return mlxsw_sp_router_port_check_rif_addr(rif->mlxsw_sp, rif->dev, |
---|
| 7263 | + info->dev_addr, extack); |
---|
| 7264 | +} |
---|
| 7265 | + |
---|
| 7266 | +int mlxsw_sp_netdevice_router_port_event(struct net_device *dev, |
---|
| 7267 | + unsigned long event, void *ptr) |
---|
| 7268 | +{ |
---|
| 7269 | + struct mlxsw_sp *mlxsw_sp; |
---|
| 7270 | + struct mlxsw_sp_rif *rif; |
---|
| 7271 | + int err = 0; |
---|
| 7272 | + |
---|
| 7273 | + mlxsw_sp = mlxsw_sp_lower_get(dev); |
---|
| 7274 | + if (!mlxsw_sp) |
---|
| 7275 | + return 0; |
---|
| 7276 | + |
---|
| 7277 | + mutex_lock(&mlxsw_sp->router->lock); |
---|
| 7278 | + rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev); |
---|
| 7279 | + if (!rif) |
---|
| 7280 | + goto out; |
---|
| 7281 | + |
---|
| 7282 | + switch (event) { |
---|
| 7283 | + case NETDEV_CHANGEMTU: |
---|
| 7284 | + case NETDEV_CHANGEADDR: |
---|
| 7285 | + err = mlxsw_sp_router_port_change_event(mlxsw_sp, rif); |
---|
| 7286 | + break; |
---|
| 7287 | + case NETDEV_PRE_CHANGEADDR: |
---|
| 7288 | + err = mlxsw_sp_router_port_pre_changeaddr_event(rif, ptr); |
---|
| 7289 | + break; |
---|
| 7290 | + } |
---|
| 7291 | + |
---|
| 7292 | +out: |
---|
| 7293 | + mutex_unlock(&mlxsw_sp->router->lock); |
---|
| 7294 | + return err; |
---|
| 7295 | +} |
---|
| 7296 | + |
---|
6837 | 7297 | static int mlxsw_sp_port_vrf_join(struct mlxsw_sp *mlxsw_sp, |
---|
6838 | 7298 | struct net_device *l3_dev, |
---|
6839 | 7299 | struct netlink_ext_ack *extack) |
---|
.. | .. |
---|
6845 | 7305 | */ |
---|
6846 | 7306 | rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev); |
---|
6847 | 7307 | if (rif) |
---|
6848 | | - __mlxsw_sp_inetaddr_event(l3_dev, NETDEV_DOWN, extack); |
---|
| 7308 | + __mlxsw_sp_inetaddr_event(mlxsw_sp, l3_dev, NETDEV_DOWN, |
---|
| 7309 | + extack); |
---|
6849 | 7310 | |
---|
6850 | | - return __mlxsw_sp_inetaddr_event(l3_dev, NETDEV_UP, extack); |
---|
| 7311 | + return __mlxsw_sp_inetaddr_event(mlxsw_sp, l3_dev, NETDEV_UP, extack); |
---|
6851 | 7312 | } |
---|
6852 | 7313 | |
---|
6853 | 7314 | static void mlxsw_sp_port_vrf_leave(struct mlxsw_sp *mlxsw_sp, |
---|
.. | .. |
---|
6858 | 7319 | rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev); |
---|
6859 | 7320 | if (!rif) |
---|
6860 | 7321 | return; |
---|
6861 | | - __mlxsw_sp_inetaddr_event(l3_dev, NETDEV_DOWN, NULL); |
---|
| 7322 | + __mlxsw_sp_inetaddr_event(mlxsw_sp, l3_dev, NETDEV_DOWN, NULL); |
---|
6862 | 7323 | } |
---|
6863 | 7324 | |
---|
6864 | 7325 | int mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event, |
---|
.. | .. |
---|
6873 | 7334 | if (!mlxsw_sp || netif_is_macvlan(l3_dev)) |
---|
6874 | 7335 | return 0; |
---|
6875 | 7336 | |
---|
| 7337 | + mutex_lock(&mlxsw_sp->router->lock); |
---|
6876 | 7338 | switch (event) { |
---|
6877 | 7339 | case NETDEV_PRECHANGEUPPER: |
---|
6878 | | - return 0; |
---|
| 7340 | + break; |
---|
6879 | 7341 | case NETDEV_CHANGEUPPER: |
---|
6880 | 7342 | if (info->linking) { |
---|
6881 | 7343 | struct netlink_ext_ack *extack; |
---|
.. | .. |
---|
6887 | 7349 | } |
---|
6888 | 7350 | break; |
---|
6889 | 7351 | } |
---|
| 7352 | + mutex_unlock(&mlxsw_sp->router->lock); |
---|
6890 | 7353 | |
---|
6891 | 7354 | return err; |
---|
6892 | 7355 | } |
---|
6893 | 7356 | |
---|
6894 | | -static int __mlxsw_sp_rif_macvlan_flush(struct net_device *dev, void *data) |
---|
| 7357 | +static int __mlxsw_sp_rif_macvlan_flush(struct net_device *dev, |
---|
| 7358 | + struct netdev_nested_priv *priv) |
---|
6895 | 7359 | { |
---|
6896 | | - struct mlxsw_sp_rif *rif = data; |
---|
| 7360 | + struct mlxsw_sp_rif *rif = (struct mlxsw_sp_rif *)priv->data; |
---|
6897 | 7361 | |
---|
6898 | 7362 | if (!netif_is_macvlan(dev)) |
---|
6899 | 7363 | return 0; |
---|
.. | .. |
---|
6904 | 7368 | |
---|
6905 | 7369 | static int mlxsw_sp_rif_macvlan_flush(struct mlxsw_sp_rif *rif) |
---|
6906 | 7370 | { |
---|
| 7371 | + struct netdev_nested_priv priv = { |
---|
| 7372 | + .data = (void *)rif, |
---|
| 7373 | + }; |
---|
| 7374 | + |
---|
6907 | 7375 | if (!netif_is_macvlan_port(rif->dev)) |
---|
6908 | 7376 | return 0; |
---|
6909 | 7377 | |
---|
6910 | 7378 | netdev_warn(rif->dev, "Router interface is deleted. Upper macvlans will not work\n"); |
---|
6911 | 7379 | return netdev_walk_all_upper_dev_rcu(rif->dev, |
---|
6912 | | - __mlxsw_sp_rif_macvlan_flush, rif); |
---|
6913 | | -} |
---|
6914 | | - |
---|
6915 | | -static struct mlxsw_sp_rif_subport * |
---|
6916 | | -mlxsw_sp_rif_subport_rif(const struct mlxsw_sp_rif *rif) |
---|
6917 | | -{ |
---|
6918 | | - return container_of(rif, struct mlxsw_sp_rif_subport, common); |
---|
| 7380 | + __mlxsw_sp_rif_macvlan_flush, &priv); |
---|
6919 | 7381 | } |
---|
6920 | 7382 | |
---|
6921 | 7383 | static void mlxsw_sp_rif_subport_setup(struct mlxsw_sp_rif *rif, |
---|
.. | .. |
---|
6924 | 7386 | struct mlxsw_sp_rif_subport *rif_subport; |
---|
6925 | 7387 | |
---|
6926 | 7388 | rif_subport = mlxsw_sp_rif_subport_rif(rif); |
---|
| 7389 | + refcount_set(&rif_subport->ref_count, 1); |
---|
6927 | 7390 | rif_subport->vid = params->vid; |
---|
6928 | 7391 | rif_subport->lag = params->lag; |
---|
6929 | 7392 | if (params->lag) |
---|
.. | .. |
---|
7018 | 7481 | return mlxsw_core_max_ports(mlxsw_sp->core) + 1; |
---|
7019 | 7482 | } |
---|
7020 | 7483 | |
---|
7021 | | -static int mlxsw_sp_rif_vlan_configure(struct mlxsw_sp_rif *rif) |
---|
7022 | | -{ |
---|
7023 | | - struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp; |
---|
7024 | | - u16 vid = mlxsw_sp_fid_8021q_vid(rif->fid); |
---|
7025 | | - int err; |
---|
7026 | | - |
---|
7027 | | - err = mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_VLAN_IF, vid, true); |
---|
7028 | | - if (err) |
---|
7029 | | - return err; |
---|
7030 | | - |
---|
7031 | | - err = mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_MC, |
---|
7032 | | - mlxsw_sp_router_port(mlxsw_sp), true); |
---|
7033 | | - if (err) |
---|
7034 | | - goto err_fid_mc_flood_set; |
---|
7035 | | - |
---|
7036 | | - err = mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC, |
---|
7037 | | - mlxsw_sp_router_port(mlxsw_sp), true); |
---|
7038 | | - if (err) |
---|
7039 | | - goto err_fid_bc_flood_set; |
---|
7040 | | - |
---|
7041 | | - err = mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, rif->dev->dev_addr, |
---|
7042 | | - mlxsw_sp_fid_index(rif->fid), true); |
---|
7043 | | - if (err) |
---|
7044 | | - goto err_rif_fdb_op; |
---|
7045 | | - |
---|
7046 | | - mlxsw_sp_fid_rif_set(rif->fid, rif); |
---|
7047 | | - return 0; |
---|
7048 | | - |
---|
7049 | | -err_rif_fdb_op: |
---|
7050 | | - mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC, |
---|
7051 | | - mlxsw_sp_router_port(mlxsw_sp), false); |
---|
7052 | | -err_fid_bc_flood_set: |
---|
7053 | | - mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_MC, |
---|
7054 | | - mlxsw_sp_router_port(mlxsw_sp), false); |
---|
7055 | | -err_fid_mc_flood_set: |
---|
7056 | | - mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_VLAN_IF, vid, false); |
---|
7057 | | - return err; |
---|
7058 | | -} |
---|
7059 | | - |
---|
7060 | | -static void mlxsw_sp_rif_vlan_deconfigure(struct mlxsw_sp_rif *rif) |
---|
7061 | | -{ |
---|
7062 | | - u16 vid = mlxsw_sp_fid_8021q_vid(rif->fid); |
---|
7063 | | - struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp; |
---|
7064 | | - struct mlxsw_sp_fid *fid = rif->fid; |
---|
7065 | | - |
---|
7066 | | - mlxsw_sp_fid_rif_set(fid, NULL); |
---|
7067 | | - mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, rif->dev->dev_addr, |
---|
7068 | | - mlxsw_sp_fid_index(fid), false); |
---|
7069 | | - mlxsw_sp_rif_macvlan_flush(rif); |
---|
7070 | | - mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC, |
---|
7071 | | - mlxsw_sp_router_port(mlxsw_sp), false); |
---|
7072 | | - mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_MC, |
---|
7073 | | - mlxsw_sp_router_port(mlxsw_sp), false); |
---|
7074 | | - mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_VLAN_IF, vid, false); |
---|
7075 | | -} |
---|
7076 | | - |
---|
7077 | | -static struct mlxsw_sp_fid * |
---|
7078 | | -mlxsw_sp_rif_vlan_fid_get(struct mlxsw_sp_rif *rif, |
---|
7079 | | - struct netlink_ext_ack *extack) |
---|
7080 | | -{ |
---|
7081 | | - u16 vid; |
---|
7082 | | - int err; |
---|
7083 | | - |
---|
7084 | | - if (is_vlan_dev(rif->dev)) { |
---|
7085 | | - vid = vlan_dev_vlan_id(rif->dev); |
---|
7086 | | - } else { |
---|
7087 | | - err = br_vlan_get_pvid(rif->dev, &vid); |
---|
7088 | | - if (err < 0 || !vid) { |
---|
7089 | | - NL_SET_ERR_MSG_MOD(extack, "Couldn't determine bridge PVID"); |
---|
7090 | | - return ERR_PTR(-EINVAL); |
---|
7091 | | - } |
---|
7092 | | - } |
---|
7093 | | - |
---|
7094 | | - return mlxsw_sp_fid_8021q_get(rif->mlxsw_sp, vid); |
---|
7095 | | -} |
---|
7096 | | - |
---|
7097 | | -static void mlxsw_sp_rif_vlan_fdb_del(struct mlxsw_sp_rif *rif, const char *mac) |
---|
7098 | | -{ |
---|
7099 | | - u16 vid = mlxsw_sp_fid_8021q_vid(rif->fid); |
---|
7100 | | - struct switchdev_notifier_fdb_info info; |
---|
7101 | | - struct net_device *br_dev; |
---|
7102 | | - struct net_device *dev; |
---|
7103 | | - |
---|
7104 | | - br_dev = is_vlan_dev(rif->dev) ? vlan_dev_real_dev(rif->dev) : rif->dev; |
---|
7105 | | - dev = br_fdb_find_port(br_dev, mac, vid); |
---|
7106 | | - if (!dev) |
---|
7107 | | - return; |
---|
7108 | | - |
---|
7109 | | - info.addr = mac; |
---|
7110 | | - info.vid = vid; |
---|
7111 | | - call_switchdev_notifiers(SWITCHDEV_FDB_DEL_TO_BRIDGE, dev, &info.info); |
---|
7112 | | -} |
---|
7113 | | - |
---|
7114 | | -static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_vlan_ops = { |
---|
7115 | | - .type = MLXSW_SP_RIF_TYPE_VLAN, |
---|
7116 | | - .rif_size = sizeof(struct mlxsw_sp_rif), |
---|
7117 | | - .configure = mlxsw_sp_rif_vlan_configure, |
---|
7118 | | - .deconfigure = mlxsw_sp_rif_vlan_deconfigure, |
---|
7119 | | - .fid_get = mlxsw_sp_rif_vlan_fid_get, |
---|
7120 | | - .fdb_del = mlxsw_sp_rif_vlan_fdb_del, |
---|
7121 | | -}; |
---|
7122 | | - |
---|
7123 | 7484 | static int mlxsw_sp_rif_fid_configure(struct mlxsw_sp_rif *rif) |
---|
7124 | 7485 | { |
---|
7125 | 7486 | struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp; |
---|
.. | .. |
---|
7195 | 7556 | |
---|
7196 | 7557 | info.addr = mac; |
---|
7197 | 7558 | info.vid = 0; |
---|
7198 | | - call_switchdev_notifiers(SWITCHDEV_FDB_DEL_TO_BRIDGE, dev, &info.info); |
---|
| 7559 | + call_switchdev_notifiers(SWITCHDEV_FDB_DEL_TO_BRIDGE, dev, &info.info, |
---|
| 7560 | + NULL); |
---|
7199 | 7561 | } |
---|
7200 | 7562 | |
---|
7201 | 7563 | static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_fid_ops = { |
---|
.. | .. |
---|
7205 | 7567 | .deconfigure = mlxsw_sp_rif_fid_deconfigure, |
---|
7206 | 7568 | .fid_get = mlxsw_sp_rif_fid_fid_get, |
---|
7207 | 7569 | .fdb_del = mlxsw_sp_rif_fid_fdb_del, |
---|
| 7570 | +}; |
---|
| 7571 | + |
---|
| 7572 | +static struct mlxsw_sp_fid * |
---|
| 7573 | +mlxsw_sp_rif_vlan_fid_get(struct mlxsw_sp_rif *rif, |
---|
| 7574 | + struct netlink_ext_ack *extack) |
---|
| 7575 | +{ |
---|
| 7576 | + struct net_device *br_dev; |
---|
| 7577 | + u16 vid; |
---|
| 7578 | + int err; |
---|
| 7579 | + |
---|
| 7580 | + if (is_vlan_dev(rif->dev)) { |
---|
| 7581 | + vid = vlan_dev_vlan_id(rif->dev); |
---|
| 7582 | + br_dev = vlan_dev_real_dev(rif->dev); |
---|
| 7583 | + if (WARN_ON(!netif_is_bridge_master(br_dev))) |
---|
| 7584 | + return ERR_PTR(-EINVAL); |
---|
| 7585 | + } else { |
---|
| 7586 | + err = br_vlan_get_pvid(rif->dev, &vid); |
---|
| 7587 | + if (err < 0 || !vid) { |
---|
| 7588 | + NL_SET_ERR_MSG_MOD(extack, "Couldn't determine bridge PVID"); |
---|
| 7589 | + return ERR_PTR(-EINVAL); |
---|
| 7590 | + } |
---|
| 7591 | + } |
---|
| 7592 | + |
---|
| 7593 | + return mlxsw_sp_fid_8021q_get(rif->mlxsw_sp, vid); |
---|
| 7594 | +} |
---|
| 7595 | + |
---|
| 7596 | +static void mlxsw_sp_rif_vlan_fdb_del(struct mlxsw_sp_rif *rif, const char *mac) |
---|
| 7597 | +{ |
---|
| 7598 | + u16 vid = mlxsw_sp_fid_8021q_vid(rif->fid); |
---|
| 7599 | + struct switchdev_notifier_fdb_info info; |
---|
| 7600 | + struct net_device *br_dev; |
---|
| 7601 | + struct net_device *dev; |
---|
| 7602 | + |
---|
| 7603 | + br_dev = is_vlan_dev(rif->dev) ? vlan_dev_real_dev(rif->dev) : rif->dev; |
---|
| 7604 | + dev = br_fdb_find_port(br_dev, mac, vid); |
---|
| 7605 | + if (!dev) |
---|
| 7606 | + return; |
---|
| 7607 | + |
---|
| 7608 | + info.addr = mac; |
---|
| 7609 | + info.vid = vid; |
---|
| 7610 | + call_switchdev_notifiers(SWITCHDEV_FDB_DEL_TO_BRIDGE, dev, &info.info, |
---|
| 7611 | + NULL); |
---|
| 7612 | +} |
---|
| 7613 | + |
---|
| 7614 | +static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_vlan_emu_ops = { |
---|
| 7615 | + .type = MLXSW_SP_RIF_TYPE_VLAN, |
---|
| 7616 | + .rif_size = sizeof(struct mlxsw_sp_rif), |
---|
| 7617 | + .configure = mlxsw_sp_rif_fid_configure, |
---|
| 7618 | + .deconfigure = mlxsw_sp_rif_fid_deconfigure, |
---|
| 7619 | + .fid_get = mlxsw_sp_rif_vlan_fid_get, |
---|
| 7620 | + .fdb_del = mlxsw_sp_rif_vlan_fdb_del, |
---|
7208 | 7621 | }; |
---|
7209 | 7622 | |
---|
7210 | 7623 | static struct mlxsw_sp_rif_ipip_lb * |
---|
.. | .. |
---|
7227 | 7640 | } |
---|
7228 | 7641 | |
---|
7229 | 7642 | static int |
---|
7230 | | -mlxsw_sp_rif_ipip_lb_configure(struct mlxsw_sp_rif *rif) |
---|
| 7643 | +mlxsw_sp1_rif_ipip_lb_configure(struct mlxsw_sp_rif *rif) |
---|
7231 | 7644 | { |
---|
7232 | 7645 | struct mlxsw_sp_rif_ipip_lb *lb_rif = mlxsw_sp_rif_ipip_lb_rif(rif); |
---|
7233 | 7646 | u32 ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(rif->dev); |
---|
.. | .. |
---|
7239 | 7652 | if (IS_ERR(ul_vr)) |
---|
7240 | 7653 | return PTR_ERR(ul_vr); |
---|
7241 | 7654 | |
---|
7242 | | - err = mlxsw_sp_rif_ipip_lb_op(lb_rif, ul_vr, true); |
---|
| 7655 | + err = mlxsw_sp_rif_ipip_lb_op(lb_rif, ul_vr->id, 0, true); |
---|
7243 | 7656 | if (err) |
---|
7244 | 7657 | goto err_loopback_op; |
---|
7245 | 7658 | |
---|
7246 | 7659 | lb_rif->ul_vr_id = ul_vr->id; |
---|
| 7660 | + lb_rif->ul_rif_id = 0; |
---|
7247 | 7661 | ++ul_vr->rif_count; |
---|
7248 | 7662 | return 0; |
---|
7249 | 7663 | |
---|
.. | .. |
---|
7252 | 7666 | return err; |
---|
7253 | 7667 | } |
---|
7254 | 7668 | |
---|
7255 | | -static void mlxsw_sp_rif_ipip_lb_deconfigure(struct mlxsw_sp_rif *rif) |
---|
| 7669 | +static void mlxsw_sp1_rif_ipip_lb_deconfigure(struct mlxsw_sp_rif *rif) |
---|
7256 | 7670 | { |
---|
7257 | 7671 | struct mlxsw_sp_rif_ipip_lb *lb_rif = mlxsw_sp_rif_ipip_lb_rif(rif); |
---|
7258 | 7672 | struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp; |
---|
7259 | 7673 | struct mlxsw_sp_vr *ul_vr; |
---|
7260 | 7674 | |
---|
7261 | 7675 | ul_vr = &mlxsw_sp->router->vrs[lb_rif->ul_vr_id]; |
---|
7262 | | - mlxsw_sp_rif_ipip_lb_op(lb_rif, ul_vr, false); |
---|
| 7676 | + mlxsw_sp_rif_ipip_lb_op(lb_rif, ul_vr->id, 0, false); |
---|
7263 | 7677 | |
---|
7264 | 7678 | --ul_vr->rif_count; |
---|
7265 | 7679 | mlxsw_sp_vr_put(mlxsw_sp, ul_vr); |
---|
7266 | 7680 | } |
---|
7267 | 7681 | |
---|
7268 | | -static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_ipip_lb_ops = { |
---|
| 7682 | +static const struct mlxsw_sp_rif_ops mlxsw_sp1_rif_ipip_lb_ops = { |
---|
7269 | 7683 | .type = MLXSW_SP_RIF_TYPE_IPIP_LB, |
---|
7270 | 7684 | .rif_size = sizeof(struct mlxsw_sp_rif_ipip_lb), |
---|
7271 | 7685 | .setup = mlxsw_sp_rif_ipip_lb_setup, |
---|
7272 | | - .configure = mlxsw_sp_rif_ipip_lb_configure, |
---|
7273 | | - .deconfigure = mlxsw_sp_rif_ipip_lb_deconfigure, |
---|
| 7686 | + .configure = mlxsw_sp1_rif_ipip_lb_configure, |
---|
| 7687 | + .deconfigure = mlxsw_sp1_rif_ipip_lb_deconfigure, |
---|
7274 | 7688 | }; |
---|
7275 | 7689 | |
---|
7276 | | -static const struct mlxsw_sp_rif_ops *mlxsw_sp_rif_ops_arr[] = { |
---|
| 7690 | +const struct mlxsw_sp_rif_ops *mlxsw_sp1_rif_ops_arr[] = { |
---|
7277 | 7691 | [MLXSW_SP_RIF_TYPE_SUBPORT] = &mlxsw_sp_rif_subport_ops, |
---|
7278 | | - [MLXSW_SP_RIF_TYPE_VLAN] = &mlxsw_sp_rif_vlan_ops, |
---|
| 7692 | + [MLXSW_SP_RIF_TYPE_VLAN] = &mlxsw_sp_rif_vlan_emu_ops, |
---|
7279 | 7693 | [MLXSW_SP_RIF_TYPE_FID] = &mlxsw_sp_rif_fid_ops, |
---|
7280 | | - [MLXSW_SP_RIF_TYPE_IPIP_LB] = &mlxsw_sp_rif_ipip_lb_ops, |
---|
| 7694 | + [MLXSW_SP_RIF_TYPE_IPIP_LB] = &mlxsw_sp1_rif_ipip_lb_ops, |
---|
| 7695 | +}; |
---|
| 7696 | + |
---|
| 7697 | +static int |
---|
| 7698 | +mlxsw_sp_rif_ipip_lb_ul_rif_op(struct mlxsw_sp_rif *ul_rif, bool enable) |
---|
| 7699 | +{ |
---|
| 7700 | + struct mlxsw_sp *mlxsw_sp = ul_rif->mlxsw_sp; |
---|
| 7701 | + char ritr_pl[MLXSW_REG_RITR_LEN]; |
---|
| 7702 | + |
---|
| 7703 | + mlxsw_reg_ritr_pack(ritr_pl, enable, MLXSW_REG_RITR_LOOPBACK_IF, |
---|
| 7704 | + ul_rif->rif_index, ul_rif->vr_id, IP_MAX_MTU); |
---|
| 7705 | + mlxsw_reg_ritr_loopback_protocol_set(ritr_pl, |
---|
| 7706 | + MLXSW_REG_RITR_LOOPBACK_GENERIC); |
---|
| 7707 | + |
---|
| 7708 | + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl); |
---|
| 7709 | +} |
---|
| 7710 | + |
---|
| 7711 | +static struct mlxsw_sp_rif * |
---|
| 7712 | +mlxsw_sp_ul_rif_create(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_vr *vr, |
---|
| 7713 | + struct netlink_ext_ack *extack) |
---|
| 7714 | +{ |
---|
| 7715 | + struct mlxsw_sp_rif *ul_rif; |
---|
| 7716 | + u16 rif_index; |
---|
| 7717 | + int err; |
---|
| 7718 | + |
---|
| 7719 | + err = mlxsw_sp_rif_index_alloc(mlxsw_sp, &rif_index); |
---|
| 7720 | + if (err) { |
---|
| 7721 | + NL_SET_ERR_MSG_MOD(extack, "Exceeded number of supported router interfaces"); |
---|
| 7722 | + return ERR_PTR(err); |
---|
| 7723 | + } |
---|
| 7724 | + |
---|
| 7725 | + ul_rif = mlxsw_sp_rif_alloc(sizeof(*ul_rif), rif_index, vr->id, NULL); |
---|
| 7726 | + if (!ul_rif) |
---|
| 7727 | + return ERR_PTR(-ENOMEM); |
---|
| 7728 | + |
---|
| 7729 | + mlxsw_sp->router->rifs[rif_index] = ul_rif; |
---|
| 7730 | + ul_rif->mlxsw_sp = mlxsw_sp; |
---|
| 7731 | + err = mlxsw_sp_rif_ipip_lb_ul_rif_op(ul_rif, true); |
---|
| 7732 | + if (err) |
---|
| 7733 | + goto ul_rif_op_err; |
---|
| 7734 | + |
---|
| 7735 | + return ul_rif; |
---|
| 7736 | + |
---|
| 7737 | +ul_rif_op_err: |
---|
| 7738 | + mlxsw_sp->router->rifs[rif_index] = NULL; |
---|
| 7739 | + kfree(ul_rif); |
---|
| 7740 | + return ERR_PTR(err); |
---|
| 7741 | +} |
---|
| 7742 | + |
---|
| 7743 | +static void mlxsw_sp_ul_rif_destroy(struct mlxsw_sp_rif *ul_rif) |
---|
| 7744 | +{ |
---|
| 7745 | + struct mlxsw_sp *mlxsw_sp = ul_rif->mlxsw_sp; |
---|
| 7746 | + |
---|
| 7747 | + mlxsw_sp_rif_ipip_lb_ul_rif_op(ul_rif, false); |
---|
| 7748 | + mlxsw_sp->router->rifs[ul_rif->rif_index] = NULL; |
---|
| 7749 | + kfree(ul_rif); |
---|
| 7750 | +} |
---|
| 7751 | + |
---|
| 7752 | +static struct mlxsw_sp_rif * |
---|
| 7753 | +mlxsw_sp_ul_rif_get(struct mlxsw_sp *mlxsw_sp, u32 tb_id, |
---|
| 7754 | + struct netlink_ext_ack *extack) |
---|
| 7755 | +{ |
---|
| 7756 | + struct mlxsw_sp_vr *vr; |
---|
| 7757 | + int err; |
---|
| 7758 | + |
---|
| 7759 | + vr = mlxsw_sp_vr_get(mlxsw_sp, tb_id, extack); |
---|
| 7760 | + if (IS_ERR(vr)) |
---|
| 7761 | + return ERR_CAST(vr); |
---|
| 7762 | + |
---|
| 7763 | + if (refcount_inc_not_zero(&vr->ul_rif_refcnt)) |
---|
| 7764 | + return vr->ul_rif; |
---|
| 7765 | + |
---|
| 7766 | + vr->ul_rif = mlxsw_sp_ul_rif_create(mlxsw_sp, vr, extack); |
---|
| 7767 | + if (IS_ERR(vr->ul_rif)) { |
---|
| 7768 | + err = PTR_ERR(vr->ul_rif); |
---|
| 7769 | + goto err_ul_rif_create; |
---|
| 7770 | + } |
---|
| 7771 | + |
---|
| 7772 | + vr->rif_count++; |
---|
| 7773 | + refcount_set(&vr->ul_rif_refcnt, 1); |
---|
| 7774 | + |
---|
| 7775 | + return vr->ul_rif; |
---|
| 7776 | + |
---|
| 7777 | +err_ul_rif_create: |
---|
| 7778 | + mlxsw_sp_vr_put(mlxsw_sp, vr); |
---|
| 7779 | + return ERR_PTR(err); |
---|
| 7780 | +} |
---|
| 7781 | + |
---|
| 7782 | +static void mlxsw_sp_ul_rif_put(struct mlxsw_sp_rif *ul_rif) |
---|
| 7783 | +{ |
---|
| 7784 | + struct mlxsw_sp *mlxsw_sp = ul_rif->mlxsw_sp; |
---|
| 7785 | + struct mlxsw_sp_vr *vr; |
---|
| 7786 | + |
---|
| 7787 | + vr = &mlxsw_sp->router->vrs[ul_rif->vr_id]; |
---|
| 7788 | + |
---|
| 7789 | + if (!refcount_dec_and_test(&vr->ul_rif_refcnt)) |
---|
| 7790 | + return; |
---|
| 7791 | + |
---|
| 7792 | + vr->rif_count--; |
---|
| 7793 | + mlxsw_sp_ul_rif_destroy(ul_rif); |
---|
| 7794 | + mlxsw_sp_vr_put(mlxsw_sp, vr); |
---|
| 7795 | +} |
---|
| 7796 | + |
---|
| 7797 | +int mlxsw_sp_router_ul_rif_get(struct mlxsw_sp *mlxsw_sp, u32 ul_tb_id, |
---|
| 7798 | + u16 *ul_rif_index) |
---|
| 7799 | +{ |
---|
| 7800 | + struct mlxsw_sp_rif *ul_rif; |
---|
| 7801 | + int err = 0; |
---|
| 7802 | + |
---|
| 7803 | + mutex_lock(&mlxsw_sp->router->lock); |
---|
| 7804 | + ul_rif = mlxsw_sp_ul_rif_get(mlxsw_sp, ul_tb_id, NULL); |
---|
| 7805 | + if (IS_ERR(ul_rif)) { |
---|
| 7806 | + err = PTR_ERR(ul_rif); |
---|
| 7807 | + goto out; |
---|
| 7808 | + } |
---|
| 7809 | + *ul_rif_index = ul_rif->rif_index; |
---|
| 7810 | +out: |
---|
| 7811 | + mutex_unlock(&mlxsw_sp->router->lock); |
---|
| 7812 | + return err; |
---|
| 7813 | +} |
---|
| 7814 | + |
---|
| 7815 | +void mlxsw_sp_router_ul_rif_put(struct mlxsw_sp *mlxsw_sp, u16 ul_rif_index) |
---|
| 7816 | +{ |
---|
| 7817 | + struct mlxsw_sp_rif *ul_rif; |
---|
| 7818 | + |
---|
| 7819 | + mutex_lock(&mlxsw_sp->router->lock); |
---|
| 7820 | + ul_rif = mlxsw_sp->router->rifs[ul_rif_index]; |
---|
| 7821 | + if (WARN_ON(!ul_rif)) |
---|
| 7822 | + goto out; |
---|
| 7823 | + |
---|
| 7824 | + mlxsw_sp_ul_rif_put(ul_rif); |
---|
| 7825 | +out: |
---|
| 7826 | + mutex_unlock(&mlxsw_sp->router->lock); |
---|
| 7827 | +} |
---|
| 7828 | + |
---|
| 7829 | +static int |
---|
| 7830 | +mlxsw_sp2_rif_ipip_lb_configure(struct mlxsw_sp_rif *rif) |
---|
| 7831 | +{ |
---|
| 7832 | + struct mlxsw_sp_rif_ipip_lb *lb_rif = mlxsw_sp_rif_ipip_lb_rif(rif); |
---|
| 7833 | + u32 ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(rif->dev); |
---|
| 7834 | + struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp; |
---|
| 7835 | + struct mlxsw_sp_rif *ul_rif; |
---|
| 7836 | + int err; |
---|
| 7837 | + |
---|
| 7838 | + ul_rif = mlxsw_sp_ul_rif_get(mlxsw_sp, ul_tb_id, NULL); |
---|
| 7839 | + if (IS_ERR(ul_rif)) |
---|
| 7840 | + return PTR_ERR(ul_rif); |
---|
| 7841 | + |
---|
| 7842 | + err = mlxsw_sp_rif_ipip_lb_op(lb_rif, 0, ul_rif->rif_index, true); |
---|
| 7843 | + if (err) |
---|
| 7844 | + goto err_loopback_op; |
---|
| 7845 | + |
---|
| 7846 | + lb_rif->ul_vr_id = 0; |
---|
| 7847 | + lb_rif->ul_rif_id = ul_rif->rif_index; |
---|
| 7848 | + |
---|
| 7849 | + return 0; |
---|
| 7850 | + |
---|
| 7851 | +err_loopback_op: |
---|
| 7852 | + mlxsw_sp_ul_rif_put(ul_rif); |
---|
| 7853 | + return err; |
---|
| 7854 | +} |
---|
| 7855 | + |
---|
| 7856 | +static void mlxsw_sp2_rif_ipip_lb_deconfigure(struct mlxsw_sp_rif *rif) |
---|
| 7857 | +{ |
---|
| 7858 | + struct mlxsw_sp_rif_ipip_lb *lb_rif = mlxsw_sp_rif_ipip_lb_rif(rif); |
---|
| 7859 | + struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp; |
---|
| 7860 | + struct mlxsw_sp_rif *ul_rif; |
---|
| 7861 | + |
---|
| 7862 | + ul_rif = mlxsw_sp_rif_by_index(mlxsw_sp, lb_rif->ul_rif_id); |
---|
| 7863 | + mlxsw_sp_rif_ipip_lb_op(lb_rif, 0, lb_rif->ul_rif_id, false); |
---|
| 7864 | + mlxsw_sp_ul_rif_put(ul_rif); |
---|
| 7865 | +} |
---|
| 7866 | + |
---|
| 7867 | +static const struct mlxsw_sp_rif_ops mlxsw_sp2_rif_ipip_lb_ops = { |
---|
| 7868 | + .type = MLXSW_SP_RIF_TYPE_IPIP_LB, |
---|
| 7869 | + .rif_size = sizeof(struct mlxsw_sp_rif_ipip_lb), |
---|
| 7870 | + .setup = mlxsw_sp_rif_ipip_lb_setup, |
---|
| 7871 | + .configure = mlxsw_sp2_rif_ipip_lb_configure, |
---|
| 7872 | + .deconfigure = mlxsw_sp2_rif_ipip_lb_deconfigure, |
---|
| 7873 | +}; |
---|
| 7874 | + |
---|
| 7875 | +const struct mlxsw_sp_rif_ops *mlxsw_sp2_rif_ops_arr[] = { |
---|
| 7876 | + [MLXSW_SP_RIF_TYPE_SUBPORT] = &mlxsw_sp_rif_subport_ops, |
---|
| 7877 | + [MLXSW_SP_RIF_TYPE_VLAN] = &mlxsw_sp_rif_vlan_emu_ops, |
---|
| 7878 | + [MLXSW_SP_RIF_TYPE_FID] = &mlxsw_sp_rif_fid_ops, |
---|
| 7879 | + [MLXSW_SP_RIF_TYPE_IPIP_LB] = &mlxsw_sp2_rif_ipip_lb_ops, |
---|
7281 | 7880 | }; |
---|
7282 | 7881 | |
---|
7283 | 7882 | static int mlxsw_sp_rifs_init(struct mlxsw_sp *mlxsw_sp) |
---|
.. | .. |
---|
7289 | 7888 | GFP_KERNEL); |
---|
7290 | 7889 | if (!mlxsw_sp->router->rifs) |
---|
7291 | 7890 | return -ENOMEM; |
---|
7292 | | - |
---|
7293 | | - mlxsw_sp->router->rif_ops_arr = mlxsw_sp_rif_ops_arr; |
---|
7294 | 7891 | |
---|
7295 | 7892 | return 0; |
---|
7296 | 7893 | } |
---|
.. | .. |
---|
7316 | 7913 | |
---|
7317 | 7914 | static int mlxsw_sp_ipips_init(struct mlxsw_sp *mlxsw_sp) |
---|
7318 | 7915 | { |
---|
| 7916 | + int err; |
---|
| 7917 | + |
---|
7319 | 7918 | mlxsw_sp->router->ipip_ops_arr = mlxsw_sp_ipip_ops_arr; |
---|
7320 | 7919 | INIT_LIST_HEAD(&mlxsw_sp->router->ipip_list); |
---|
| 7920 | + |
---|
| 7921 | + err = mlxsw_sp_ipip_ecn_encap_init(mlxsw_sp); |
---|
| 7922 | + if (err) |
---|
| 7923 | + return err; |
---|
| 7924 | + err = mlxsw_sp_ipip_ecn_decap_init(mlxsw_sp); |
---|
| 7925 | + if (err) |
---|
| 7926 | + return err; |
---|
| 7927 | + |
---|
7321 | 7928 | return mlxsw_sp_ipip_config_tigcr(mlxsw_sp); |
---|
7322 | 7929 | } |
---|
7323 | 7930 | |
---|
.. | .. |
---|
7350 | 7957 | mlxsw_reg_recr2_outer_header_fields_enable_set(recr2_pl, field, true); |
---|
7351 | 7958 | } |
---|
7352 | 7959 | |
---|
7353 | | -static void mlxsw_sp_mp4_hash_init(char *recr2_pl) |
---|
| 7960 | +static void mlxsw_sp_mp4_hash_init(struct mlxsw_sp *mlxsw_sp, char *recr2_pl) |
---|
7354 | 7961 | { |
---|
7355 | | - bool only_l3 = !init_net.ipv4.sysctl_fib_multipath_hash_policy; |
---|
| 7962 | + struct net *net = mlxsw_sp_net(mlxsw_sp); |
---|
| 7963 | + bool only_l3 = !net->ipv4.sysctl_fib_multipath_hash_policy; |
---|
7356 | 7964 | |
---|
7357 | 7965 | mlxsw_sp_mp_hash_header_set(recr2_pl, |
---|
7358 | 7966 | MLXSW_REG_RECR2_IPV4_EN_NOT_TCP_NOT_UDP); |
---|
.. | .. |
---|
7367 | 7975 | mlxsw_sp_mp_hash_field_set(recr2_pl, MLXSW_REG_RECR2_TCP_UDP_DPORT); |
---|
7368 | 7976 | } |
---|
7369 | 7977 | |
---|
7370 | | -static void mlxsw_sp_mp6_hash_init(char *recr2_pl) |
---|
| 7978 | +static void mlxsw_sp_mp6_hash_init(struct mlxsw_sp *mlxsw_sp, char *recr2_pl) |
---|
7371 | 7979 | { |
---|
7372 | | - bool only_l3 = !ip6_multipath_hash_policy(&init_net); |
---|
| 7980 | + bool only_l3 = !ip6_multipath_hash_policy(mlxsw_sp_net(mlxsw_sp)); |
---|
7373 | 7981 | |
---|
7374 | 7982 | mlxsw_sp_mp_hash_header_set(recr2_pl, |
---|
7375 | 7983 | MLXSW_REG_RECR2_IPV6_EN_NOT_TCP_NOT_UDP); |
---|
.. | .. |
---|
7395 | 8003 | char recr2_pl[MLXSW_REG_RECR2_LEN]; |
---|
7396 | 8004 | u32 seed; |
---|
7397 | 8005 | |
---|
7398 | | - get_random_bytes(&seed, sizeof(seed)); |
---|
| 8006 | + seed = jhash(mlxsw_sp->base_mac, sizeof(mlxsw_sp->base_mac), 0); |
---|
7399 | 8007 | mlxsw_reg_recr2_pack(recr2_pl, seed); |
---|
7400 | | - mlxsw_sp_mp4_hash_init(recr2_pl); |
---|
7401 | | - mlxsw_sp_mp6_hash_init(recr2_pl); |
---|
| 8008 | + mlxsw_sp_mp4_hash_init(mlxsw_sp, recr2_pl); |
---|
| 8009 | + mlxsw_sp_mp6_hash_init(mlxsw_sp, recr2_pl); |
---|
7402 | 8010 | |
---|
7403 | 8011 | return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(recr2), recr2_pl); |
---|
7404 | 8012 | } |
---|
.. | .. |
---|
7429 | 8037 | |
---|
7430 | 8038 | static int __mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp) |
---|
7431 | 8039 | { |
---|
7432 | | - bool usp = init_net.ipv4.sysctl_ip_fwd_update_priority; |
---|
| 8040 | + struct net *net = mlxsw_sp_net(mlxsw_sp); |
---|
7433 | 8041 | char rgcr_pl[MLXSW_REG_RGCR_LEN]; |
---|
7434 | 8042 | u64 max_rifs; |
---|
7435 | | - int err; |
---|
| 8043 | + bool usp; |
---|
7436 | 8044 | |
---|
7437 | 8045 | if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_RIFS)) |
---|
7438 | 8046 | return -EIO; |
---|
7439 | 8047 | max_rifs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); |
---|
| 8048 | + usp = READ_ONCE(net->ipv4.sysctl_ip_fwd_update_priority); |
---|
7440 | 8049 | |
---|
7441 | 8050 | mlxsw_reg_rgcr_pack(rgcr_pl, true, true); |
---|
7442 | 8051 | mlxsw_reg_rgcr_max_router_interfaces_set(rgcr_pl, max_rifs); |
---|
7443 | 8052 | mlxsw_reg_rgcr_usp_set(rgcr_pl, usp); |
---|
7444 | | - err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rgcr), rgcr_pl); |
---|
7445 | | - if (err) |
---|
7446 | | - return err; |
---|
7447 | | - return 0; |
---|
| 8053 | + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rgcr), rgcr_pl); |
---|
7448 | 8054 | } |
---|
7449 | 8055 | |
---|
7450 | 8056 | static void __mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp) |
---|
.. | .. |
---|
7455 | 8061 | mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rgcr), rgcr_pl); |
---|
7456 | 8062 | } |
---|
7457 | 8063 | |
---|
7458 | | -int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp) |
---|
| 8064 | +int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp, |
---|
| 8065 | + struct netlink_ext_ack *extack) |
---|
7459 | 8066 | { |
---|
7460 | 8067 | struct mlxsw_sp_router *router; |
---|
7461 | 8068 | int err; |
---|
.. | .. |
---|
7463 | 8070 | router = kzalloc(sizeof(*mlxsw_sp->router), GFP_KERNEL); |
---|
7464 | 8071 | if (!router) |
---|
7465 | 8072 | return -ENOMEM; |
---|
| 8073 | + mutex_init(&router->lock); |
---|
7466 | 8074 | mlxsw_sp->router = router; |
---|
7467 | 8075 | router->mlxsw_sp = mlxsw_sp; |
---|
7468 | 8076 | |
---|
.. | .. |
---|
7506 | 8114 | if (err) |
---|
7507 | 8115 | goto err_neigh_init; |
---|
7508 | 8116 | |
---|
7509 | | - mlxsw_sp->router->netevent_nb.notifier_call = |
---|
7510 | | - mlxsw_sp_router_netevent_event; |
---|
7511 | | - err = register_netevent_notifier(&mlxsw_sp->router->netevent_nb); |
---|
7512 | | - if (err) |
---|
7513 | | - goto err_register_netevent_notifier; |
---|
7514 | | - |
---|
7515 | 8117 | err = mlxsw_sp_mp_hash_init(mlxsw_sp); |
---|
7516 | 8118 | if (err) |
---|
7517 | 8119 | goto err_mp_hash_init; |
---|
.. | .. |
---|
7520 | 8122 | if (err) |
---|
7521 | 8123 | goto err_dscp_init; |
---|
7522 | 8124 | |
---|
| 8125 | + router->inetaddr_nb.notifier_call = mlxsw_sp_inetaddr_event; |
---|
| 8126 | + err = register_inetaddr_notifier(&router->inetaddr_nb); |
---|
| 8127 | + if (err) |
---|
| 8128 | + goto err_register_inetaddr_notifier; |
---|
| 8129 | + |
---|
| 8130 | + router->inet6addr_nb.notifier_call = mlxsw_sp_inet6addr_event; |
---|
| 8131 | + err = register_inet6addr_notifier(&router->inet6addr_nb); |
---|
| 8132 | + if (err) |
---|
| 8133 | + goto err_register_inet6addr_notifier; |
---|
| 8134 | + |
---|
| 8135 | + mlxsw_sp->router->netevent_nb.notifier_call = |
---|
| 8136 | + mlxsw_sp_router_netevent_event; |
---|
| 8137 | + err = register_netevent_notifier(&mlxsw_sp->router->netevent_nb); |
---|
| 8138 | + if (err) |
---|
| 8139 | + goto err_register_netevent_notifier; |
---|
| 8140 | + |
---|
7523 | 8141 | mlxsw_sp->router->fib_nb.notifier_call = mlxsw_sp_router_fib_event; |
---|
7524 | | - err = register_fib_notifier(&mlxsw_sp->router->fib_nb, |
---|
7525 | | - mlxsw_sp_router_fib_dump_flush); |
---|
| 8142 | + err = register_fib_notifier(mlxsw_sp_net(mlxsw_sp), |
---|
| 8143 | + &mlxsw_sp->router->fib_nb, |
---|
| 8144 | + mlxsw_sp_router_fib_dump_flush, extack); |
---|
7526 | 8145 | if (err) |
---|
7527 | 8146 | goto err_register_fib_notifier; |
---|
7528 | 8147 | |
---|
7529 | 8148 | return 0; |
---|
7530 | 8149 | |
---|
7531 | 8150 | err_register_fib_notifier: |
---|
7532 | | -err_dscp_init: |
---|
7533 | | -err_mp_hash_init: |
---|
7534 | 8151 | unregister_netevent_notifier(&mlxsw_sp->router->netevent_nb); |
---|
7535 | 8152 | err_register_netevent_notifier: |
---|
| 8153 | + unregister_inet6addr_notifier(&router->inet6addr_nb); |
---|
| 8154 | +err_register_inet6addr_notifier: |
---|
| 8155 | + unregister_inetaddr_notifier(&router->inetaddr_nb); |
---|
| 8156 | +err_register_inetaddr_notifier: |
---|
| 8157 | + mlxsw_core_flush_owq(); |
---|
| 8158 | +err_dscp_init: |
---|
| 8159 | +err_mp_hash_init: |
---|
7536 | 8160 | mlxsw_sp_neigh_fini(mlxsw_sp); |
---|
7537 | 8161 | err_neigh_init: |
---|
7538 | 8162 | mlxsw_sp_vrs_fini(mlxsw_sp); |
---|
.. | .. |
---|
7551 | 8175 | err_rifs_init: |
---|
7552 | 8176 | __mlxsw_sp_router_fini(mlxsw_sp); |
---|
7553 | 8177 | err_router_init: |
---|
| 8178 | + mutex_destroy(&mlxsw_sp->router->lock); |
---|
7554 | 8179 | kfree(mlxsw_sp->router); |
---|
7555 | 8180 | return err; |
---|
7556 | 8181 | } |
---|
7557 | 8182 | |
---|
7558 | 8183 | void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp) |
---|
7559 | 8184 | { |
---|
7560 | | - unregister_fib_notifier(&mlxsw_sp->router->fib_nb); |
---|
| 8185 | + unregister_fib_notifier(mlxsw_sp_net(mlxsw_sp), |
---|
| 8186 | + &mlxsw_sp->router->fib_nb); |
---|
7561 | 8187 | unregister_netevent_notifier(&mlxsw_sp->router->netevent_nb); |
---|
| 8188 | + unregister_inet6addr_notifier(&mlxsw_sp->router->inet6addr_nb); |
---|
| 8189 | + unregister_inetaddr_notifier(&mlxsw_sp->router->inetaddr_nb); |
---|
| 8190 | + mlxsw_core_flush_owq(); |
---|
7562 | 8191 | mlxsw_sp_neigh_fini(mlxsw_sp); |
---|
7563 | 8192 | mlxsw_sp_vrs_fini(mlxsw_sp); |
---|
7564 | 8193 | mlxsw_sp_mr_fini(mlxsw_sp); |
---|
.. | .. |
---|
7568 | 8197 | mlxsw_sp_ipips_fini(mlxsw_sp); |
---|
7569 | 8198 | mlxsw_sp_rifs_fini(mlxsw_sp); |
---|
7570 | 8199 | __mlxsw_sp_router_fini(mlxsw_sp); |
---|
| 8200 | + mutex_destroy(&mlxsw_sp->router->lock); |
---|
7571 | 8201 | kfree(mlxsw_sp->router); |
---|
7572 | 8202 | } |
---|