| .. | .. |
|---|
| 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 | } |
|---|