forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
kernel/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
....@@ -13,13 +13,17 @@
1313 #include <linux/socket.h>
1414 #include <linux/route.h>
1515 #include <linux/gcd.h>
16
-#include <linux/random.h>
1716 #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>
1821 #include <net/netevent.h>
1922 #include <net/neighbour.h>
2023 #include <net/arp.h>
2124 #include <net/ip_fib.h>
2225 #include <net/ip6_fib.h>
26
+#include <net/nexthop.h>
2327 #include <net/fib_rules.h>
2428 #include <net/ip_tunnels.h>
2529 #include <net/l3mdev.h>
....@@ -45,39 +49,10 @@
4549 struct mlxsw_sp_lpm_tree;
4650 struct mlxsw_sp_rif_ops;
4751
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
-
7752 struct mlxsw_sp_rif {
7853 struct list_head nexthop_list;
7954 struct list_head neigh_list;
80
- struct net_device *dev;
55
+ struct net_device *dev; /* NULL for underlay RIF */
8156 struct mlxsw_sp_fid *fid;
8257 unsigned char addr[ETH_ALEN];
8358 int mtu;
....@@ -104,6 +79,7 @@
10479
10580 struct mlxsw_sp_rif_subport {
10681 struct mlxsw_sp_rif common;
82
+ refcount_t ref_count;
10783 union {
10884 u16 system_port;
10985 u16 lag_id;
....@@ -116,6 +92,7 @@
11692 struct mlxsw_sp_rif common;
11793 struct mlxsw_sp_rif_ipip_lb_config lb_config;
11894 u16 ul_vr_id; /* Reserved for Spectrum-2. */
95
+ u16 ul_rif_id; /* Reserved for Spectrum. */
11996 };
12097
12198 struct mlxsw_sp_rif_params_ipip_lb {
....@@ -136,6 +113,10 @@
136113 void (*fdb_del)(struct mlxsw_sp_rif *rif, const char *mac);
137114 };
138115
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);
139120 static void mlxsw_sp_lpm_tree_hold(struct mlxsw_sp_lpm_tree *lpm_tree);
140121 static void mlxsw_sp_lpm_tree_put(struct mlxsw_sp *mlxsw_sp,
141122 struct mlxsw_sp_lpm_tree *lpm_tree);
....@@ -358,6 +339,8 @@
358339 MLXSW_SP_FIB_ENTRY_TYPE_REMOTE,
359340 MLXSW_SP_FIB_ENTRY_TYPE_LOCAL,
360341 MLXSW_SP_FIB_ENTRY_TYPE_TRAP,
342
+ MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE,
343
+ MLXSW_SP_FIB_ENTRY_TYPE_UNREACHABLE,
361344
362345 /* This is a special case of local delivery, where a packet should be
363346 * decapsulated on reception. Note that there is no corresponding ENCAP,
....@@ -366,12 +349,14 @@
366349 * encapsulating entries.)
367350 */
368351 MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP,
352
+ MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP,
369353 };
370354
371355 struct mlxsw_sp_nexthop_group;
356
+struct mlxsw_sp_fib_entry;
372357
373358 struct mlxsw_sp_fib_node {
374
- struct list_head entry_list;
359
+ struct mlxsw_sp_fib_entry *fib_entry;
375360 struct list_head list;
376361 struct rhash_head ht_node;
377362 struct mlxsw_sp_fib *fib;
....@@ -384,7 +369,6 @@
384369 };
385370
386371 struct mlxsw_sp_fib_entry {
387
- struct list_head list;
388372 struct mlxsw_sp_fib_node *fib_node;
389373 enum mlxsw_sp_fib_entry_type type;
390374 struct list_head nexthop_group_node;
....@@ -434,6 +418,8 @@
434418 struct mlxsw_sp_fib *fib4;
435419 struct mlxsw_sp_fib *fib6;
436420 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;
437423 };
438424
439425 static const struct rhashtable_params mlxsw_sp_fib_ht_params;
....@@ -741,6 +727,24 @@
741727 return NULL;
742728 }
743729
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
+
744748 static struct mlxsw_sp_fib *mlxsw_sp_vr_fib(const struct mlxsw_sp_vr *vr,
745749 enum mlxsw_sp_l3proto proto)
746750 {
....@@ -960,17 +964,23 @@
960964 struct ip_tunnel *tun = netdev_priv(ol_dev);
961965 struct net *net = dev_net(ol_dev);
962966
963
- return __dev_get_by_index(net, tun->parms.link);
967
+ return dev_get_by_index_rcu(net, tun->parms.link);
964968 }
965969
966970 u32 mlxsw_sp_ipip_dev_ul_tb_id(const struct net_device *ol_dev)
967971 {
968
- struct net_device *d = __mlxsw_sp_ipip_netdev_ul_dev_get(ol_dev);
972
+ struct net_device *d;
973
+ u32 tb_id;
969974
975
+ rcu_read_lock();
976
+ d = __mlxsw_sp_ipip_netdev_ul_dev_get(ol_dev);
970977 if (d)
971
- return l3mdev_fib_table(d) ? : RT_TABLE_MAIN;
978
+ tb_id = l3mdev_fib_table(d) ? : RT_TABLE_MAIN;
972979 else
973
- return RT_TABLE_MAIN;
980
+ tb_id = RT_TABLE_MAIN;
981
+ rcu_read_unlock();
982
+
983
+ return tb_id;
974984 }
975985
976986 static struct mlxsw_sp_rif *
....@@ -1128,6 +1138,46 @@
11281138 mlxsw_sp_ipip_entry_demote_decap(mlxsw_sp, ipip_entry);
11291139 }
11301140
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
+
11311181 /* Given an IPIP entry, find the corresponding decap route. */
11321182 static struct mlxsw_sp_fib_entry *
11331183 mlxsw_sp_ipip_entry_find_decap(struct mlxsw_sp *mlxsw_sp,
....@@ -1135,7 +1185,6 @@
11351185 {
11361186 static struct mlxsw_sp_fib_node *fib_node;
11371187 const struct mlxsw_sp_ipip_ops *ipip_ops;
1138
- struct mlxsw_sp_fib_entry *fib_entry;
11391188 unsigned char saddr_prefix_len;
11401189 union mlxsw_sp_l3addr saddr;
11411190 struct mlxsw_sp_fib *ul_fib;
....@@ -1163,22 +1212,18 @@
11631212 saddr_len = 4;
11641213 saddr_prefix_len = 32;
11651214 break;
1166
- case MLXSW_SP_L3_PROTO_IPV6:
1215
+ default:
11671216 WARN_ON(1);
11681217 return NULL;
11691218 }
11701219
11711220 fib_node = mlxsw_sp_fib_node_lookup(ul_fib, saddrp, saddr_len,
11721221 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)
11741224 return NULL;
11751225
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;
11821227 }
11831228
11841229 static struct mlxsw_sp_ipip_entry *
....@@ -1292,8 +1337,12 @@
12921337 ipip_list_node);
12931338 list_for_each_entry_continue(ipip_entry, &mlxsw_sp->router->ipip_list,
12941339 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();
12971346
12981347 if (ipip_ul_dev == ul_dev)
12991348 return ipip_entry;
....@@ -1302,10 +1351,16 @@
13021351 return NULL;
13031352 }
13041353
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,
13061355 const struct net_device *dev)
13071356 {
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;
13091364 }
13101365
13111366 static bool mlxsw_sp_netdevice_ipip_can_offload(struct mlxsw_sp *mlxsw_sp,
....@@ -1325,9 +1380,9 @@
13251380 static int mlxsw_sp_netdevice_ipip_ol_reg_event(struct mlxsw_sp *mlxsw_sp,
13261381 struct net_device *ol_dev)
13271382 {
1383
+ enum mlxsw_sp_ipip_type ipipt = MLXSW_SP_IPIP_TYPE_MAX;
13281384 struct mlxsw_sp_ipip_entry *ipip_entry;
13291385 enum mlxsw_sp_l3proto ul_proto;
1330
- enum mlxsw_sp_ipip_type ipipt;
13311386 union mlxsw_sp_l3addr saddr;
13321387 u32 ul_tb_id;
13331388
....@@ -1372,8 +1427,8 @@
13721427 }
13731428
13741429 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)
13771432 {
13781433 struct mlxsw_sp_rif_ipip_lb_config lb_cf = lb_rif->lb_config;
13791434 struct mlxsw_sp_rif *rif = &lb_rif->common;
....@@ -1388,7 +1443,7 @@
13881443 rif->rif_index, rif->vr_id, rif->dev->mtu);
13891444 mlxsw_reg_ritr_loopback_ipip4_pack(ritr_pl, lb_cf.lb_ipipt,
13901445 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);
13921447 break;
13931448
13941449 case MLXSW_SP_L3_PROTO_IPV6:
....@@ -1403,14 +1458,13 @@
14031458 {
14041459 struct mlxsw_sp_ipip_entry *ipip_entry;
14051460 struct mlxsw_sp_rif_ipip_lb *lb_rif;
1406
- struct mlxsw_sp_vr *ul_vr;
14071461 int err = 0;
14081462
14091463 ipip_entry = mlxsw_sp_ipip_entry_find_by_ol_dev(mlxsw_sp, ol_dev);
14101464 if (ipip_entry) {
14111465 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);
14141468 if (err)
14151469 goto out;
14161470 lb_rif->common.mtu = ol_dev->mtu;
....@@ -1481,13 +1535,17 @@
14811535 struct mlxsw_sp_rif *rif);
14821536
14831537 /**
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
14881543 * 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
14901545 * is only relevant when recreate_loopback is false.
1546
+ * @extack: extack.
1547
+ *
1548
+ * Return: Non-zero value on failure.
14911549 */
14921550 int __mlxsw_sp_ipip_entry_update_tunnel(struct mlxsw_sp *mlxsw_sp,
14931551 struct mlxsw_sp_ipip_entry *ipip_entry,
....@@ -1541,8 +1599,25 @@
15411599 mlxsw_sp_netdevice_ipip_ul_vrf_event(struct mlxsw_sp *mlxsw_sp,
15421600 struct mlxsw_sp_ipip_entry *ipip_entry,
15431601 struct net_device *ul_dev,
1602
+ bool *demote_this,
15441603 struct netlink_ext_ack *extack)
15451604 {
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
+
15461621 return __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp, ipip_entry,
15471622 true, true, false, extack);
15481623 }
....@@ -1643,9 +1718,12 @@
16431718
16441719 list_for_each_entry_safe(ipip_entry, tmp, &mlxsw_sp->router->ipip_list,
16451720 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;
16481723
1724
+ rcu_read_lock();
1725
+ ipip_ul_dev = __mlxsw_sp_ipip_netdev_ul_dev_get(ol_dev);
1726
+ rcu_read_unlock();
16491727 if (ipip_ul_dev == ul_dev)
16501728 mlxsw_sp_ipip_entry_demote_tunnel(mlxsw_sp, ipip_entry);
16511729 }
....@@ -1658,41 +1736,48 @@
16581736 {
16591737 struct netdev_notifier_changeupper_info *chup;
16601738 struct netlink_ext_ack *extack;
1739
+ int err = 0;
16611740
1741
+ mutex_lock(&mlxsw_sp->router->lock);
16621742 switch (event) {
16631743 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;
16651746 case NETDEV_UNREGISTER:
16661747 mlxsw_sp_netdevice_ipip_ol_unreg_event(mlxsw_sp, ol_dev);
1667
- return 0;
1748
+ break;
16681749 case NETDEV_UP:
16691750 mlxsw_sp_netdevice_ipip_ol_up_event(mlxsw_sp, ol_dev);
1670
- return 0;
1751
+ break;
16711752 case NETDEV_DOWN:
16721753 mlxsw_sp_netdevice_ipip_ol_down_event(mlxsw_sp, ol_dev);
1673
- return 0;
1754
+ break;
16741755 case NETDEV_CHANGEUPPER:
16751756 chup = container_of(info, typeof(*chup), info);
16761757 extack = info->extack;
16771758 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;
16821763 case NETDEV_CHANGE:
16831764 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;
16861768 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;
16881771 }
1689
- return 0;
1772
+ mutex_unlock(&mlxsw_sp->router->lock);
1773
+ return err;
16901774 }
16911775
16921776 static int
16931777 __mlxsw_sp_netdevice_ipip_ul_event(struct mlxsw_sp *mlxsw_sp,
16941778 struct mlxsw_sp_ipip_entry *ipip_entry,
16951779 struct net_device *ul_dev,
1780
+ bool *demote_this,
16961781 unsigned long event,
16971782 struct netdev_notifier_info *info)
16981783 {
....@@ -1707,6 +1792,7 @@
17071792 return mlxsw_sp_netdevice_ipip_ul_vrf_event(mlxsw_sp,
17081793 ipip_entry,
17091794 ul_dev,
1795
+ demote_this,
17101796 extack);
17111797 break;
17121798
....@@ -1728,21 +1814,131 @@
17281814 struct netdev_notifier_info *info)
17291815 {
17301816 struct mlxsw_sp_ipip_entry *ipip_entry = NULL;
1731
- int err;
1817
+ int err = 0;
17321818
1819
+ mutex_lock(&mlxsw_sp->router->lock);
17331820 while ((ipip_entry = mlxsw_sp_ipip_entry_find_by_ul_dev(mlxsw_sp,
17341821 ul_dev,
17351822 ipip_entry))) {
1823
+ struct mlxsw_sp_ipip_entry *prev;
1824
+ bool demote_this = false;
1825
+
17361826 err = __mlxsw_sp_netdevice_ipip_ul_event(mlxsw_sp, ipip_entry,
1737
- ul_dev, event, info);
1827
+ ul_dev, &demote_this,
1828
+ event, info);
17381829 if (err) {
17391830 mlxsw_sp_ipip_demote_tunnel_by_ul_netdev(mlxsw_sp,
17401831 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;
17421847 }
17431848 }
1849
+ mutex_unlock(&mlxsw_sp->router->lock);
17441850
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));
17461942 }
17471943
17481944 struct mlxsw_sp_neigh_key {
....@@ -1981,6 +2177,7 @@
19812177 char *rauhtd_pl,
19822178 int ent_index)
19832179 {
2180
+ u64 max_rifs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
19842181 struct net_device *dev;
19852182 struct neighbour *n;
19862183 __be32 dipn;
....@@ -1989,6 +2186,8 @@
19892186
19902187 mlxsw_reg_rauhtd_ent_ipv4_unpack(rauhtd_pl, ent_index, &rif, &dip);
19912188
2189
+ if (WARN_ON_ONCE(rif >= max_rifs))
2190
+ return;
19922191 if (!mlxsw_sp->router->rifs[rif]) {
19932192 dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Incorrect RIF in neighbour entry\n");
19942193 return;
....@@ -2115,10 +2314,8 @@
21152314 int i, num_rec;
21162315 int err;
21172316
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);
21222319 do {
21232320 mlxsw_reg_rauhtd_pack(rauhtd_pl, type);
21242321 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(rauhtd),
....@@ -2132,7 +2329,7 @@
21322329 mlxsw_sp_router_neigh_rec_process(mlxsw_sp, rauhtd_pl,
21332330 i);
21342331 } while (mlxsw_sp_router_rauhtd_is_full(rauhtd_pl));
2135
- rtnl_unlock();
2332
+ mutex_unlock(&mlxsw_sp->router->lock);
21362333
21372334 return err;
21382335 }
....@@ -2163,15 +2360,14 @@
21632360 {
21642361 struct mlxsw_sp_neigh_entry *neigh_entry;
21652362
2166
- /* Take RTNL mutex here to prevent lists from changes */
2167
- rtnl_lock();
2363
+ mutex_lock(&mlxsw_sp->router->lock);
21682364 list_for_each_entry(neigh_entry, &mlxsw_sp->router->nexthop_neighs_list,
21692365 nexthop_neighs_list_node)
21702366 /* If this neigh have nexthops, make the kernel think this neigh
21712367 * is active regardless of the traffic.
21722368 */
21732369 neigh_event_send(neigh_entry->key.n, NULL);
2174
- rtnl_unlock();
2370
+ mutex_unlock(&mlxsw_sp->router->lock);
21752371 }
21762372
21772373 static void
....@@ -2211,15 +2407,13 @@
22112407 * the nexthop wouldn't get offloaded until the neighbor is resolved
22122408 * but it wouldn't get resolved ever in case traffic is flowing in HW
22132409 * using different nexthop.
2214
- *
2215
- * Take RTNL mutex here to prevent lists from changes.
22162410 */
2217
- rtnl_lock();
2411
+ mutex_lock(&router->lock);
22182412 list_for_each_entry(neigh_entry, &router->nexthop_neighs_list,
22192413 nexthop_neighs_list_node)
22202414 if (!neigh_entry->connected)
22212415 neigh_event_send(neigh_entry->key.n, NULL);
2222
- rtnl_unlock();
2416
+ mutex_unlock(&router->lock);
22232417
22242418 mlxsw_core_schedule_dw(&router->nexthop_probe_dw,
22252419 MLXSW_SP_UNRESOLVED_NH_PROBE_INTERVAL);
....@@ -2236,7 +2430,7 @@
22362430 MLXSW_REG_RAUHT_OP_WRITE_DELETE;
22372431 }
22382432
2239
-static void
2433
+static int
22402434 mlxsw_sp_router_neigh_entry_op4(struct mlxsw_sp *mlxsw_sp,
22412435 struct mlxsw_sp_neigh_entry *neigh_entry,
22422436 enum mlxsw_reg_rauht_op op)
....@@ -2250,10 +2444,10 @@
22502444 if (neigh_entry->counter_valid)
22512445 mlxsw_reg_rauht_pack_counter(rauht_pl,
22522446 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);
22542448 }
22552449
2256
-static void
2450
+static int
22572451 mlxsw_sp_router_neigh_entry_op6(struct mlxsw_sp *mlxsw_sp,
22582452 struct mlxsw_sp_neigh_entry *neigh_entry,
22592453 enum mlxsw_reg_rauht_op op)
....@@ -2267,7 +2461,7 @@
22672461 if (neigh_entry->counter_valid)
22682462 mlxsw_reg_rauht_pack_counter(rauht_pl,
22692463 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);
22712465 }
22722466
22732467 bool mlxsw_sp_neigh_ipv6_ignore(struct mlxsw_sp_neigh_entry *neigh_entry)
....@@ -2289,20 +2483,33 @@
22892483 struct mlxsw_sp_neigh_entry *neigh_entry,
22902484 bool adding)
22912485 {
2486
+ enum mlxsw_reg_rauht_op op = mlxsw_sp_rauht_op(adding);
2487
+ int err;
2488
+
22922489 if (!adding && !neigh_entry->connected)
22932490 return;
22942491 neigh_entry->connected = adding;
22952492 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;
22982497 } else if (neigh_entry->key.n->tbl->family == AF_INET6) {
22992498 if (mlxsw_sp_neigh_ipv6_ignore(neigh_entry))
23002499 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;
23032504 } else {
23042505 WARN_ON_ONCE(1);
2506
+ return;
23052507 }
2508
+
2509
+ if (adding)
2510
+ neigh_entry->key.n->flags |= NTF_OFFLOADED;
2511
+ else
2512
+ neigh_entry->key.n->flags &= ~NTF_OFFLOADED;
23062513 }
23072514
23082515 void
....@@ -2344,7 +2551,7 @@
23442551 dead = n->dead;
23452552 read_unlock_bh(&n->lock);
23462553
2347
- rtnl_lock();
2554
+ mutex_lock(&mlxsw_sp->router->lock);
23482555 mlxsw_sp_span_respin(mlxsw_sp);
23492556
23502557 entry_connected = nud_state & NUD_VALID && !dead;
....@@ -2366,7 +2573,7 @@
23662573 mlxsw_sp_neigh_entry_destroy(mlxsw_sp, neigh_entry);
23672574
23682575 out:
2369
- rtnl_unlock();
2576
+ mutex_unlock(&mlxsw_sp->router->lock);
23702577 neigh_release(n);
23712578 kfree(net_work);
23722579 }
....@@ -2402,14 +2609,14 @@
24022609 struct mlxsw_sp_netevent_work *net_work;
24032610 struct mlxsw_sp_router *router;
24042611
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)))
24062614 return NOTIFY_DONE;
24072615
24082616 net_work = kzalloc(sizeof(*net_work), GFP_ATOMIC);
24092617 if (!net_work)
24102618 return NOTIFY_BAD;
24112619
2412
- router = container_of(nb, struct mlxsw_sp_router, netevent_nb);
24132620 INIT_WORK(&net_work->work, cb);
24142621 net_work->mlxsw_sp = router->mlxsw_sp;
24152622 mlxsw_core_schedule_work(&net_work->work);
....@@ -2739,12 +2946,13 @@
27392946 return false;
27402947
27412948 list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list) {
2949
+ struct fib6_nh *fib6_nh = mlxsw_sp_rt6->rt->fib6_nh;
27422950 struct in6_addr *gw;
27432951 int ifindex, weight;
27442952
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;
27482956 if (!mlxsw_sp_nexthop6_group_has_nexthop(nh_grp, gw, ifindex,
27492957 weight))
27502958 return false;
....@@ -2793,7 +3001,8 @@
27933001 val = nh_grp->count;
27943002 for (i = 0; i < nh_grp->count; i++) {
27953003 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);
27973006 }
27983007 return jhash(&val, sizeof(val), seed);
27993008 default:
....@@ -2807,11 +3016,14 @@
28073016 {
28083017 unsigned int val = fib6_entry->nrt6;
28093018 struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
2810
- struct net_device *dev;
28113019
28123020 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);
28153027 }
28163028
28173029 return jhash(&val, sizeof(val), seed);
....@@ -3026,7 +3238,6 @@
30263238 u32 adj_index = nh_grp->adj_index; /* base */
30273239 struct mlxsw_sp_nexthop *nh;
30283240 int i;
3029
- int err;
30303241
30313242 for (i = 0; i < nh_grp->count; i++) {
30323243 nh = &nh_grp->nexthops[i];
....@@ -3037,6 +3248,8 @@
30373248 }
30383249
30393250 if (nh->update || reallocate) {
3251
+ int err = 0;
3252
+
30403253 switch (nh->type) {
30413254 case MLXSW_SP_NEXTHOP_TYPE_ETH:
30423255 err = mlxsw_sp_nexthop_update
....@@ -3057,10 +3270,6 @@
30573270 return 0;
30583271 }
30593272
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
-
30643273 static int
30653274 mlxsw_sp_nexthop_fib_entries_update(struct mlxsw_sp *mlxsw_sp,
30663275 struct mlxsw_sp_nexthop_group *nh_grp)
....@@ -3069,32 +3278,11 @@
30693278 int err;
30703279
30713280 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;
30753281 err = mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry);
30763282 if (err)
30773283 return err;
30783284 }
30793285 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
- }
30983286 }
30993287
31003288 static void mlxsw_sp_adj_grp_size_round_up(u16 *p_adj_grp_size)
....@@ -3200,6 +3388,73 @@
32003388 }
32013389 }
32023390
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
+
32033458 static void
32043459 mlxsw_sp_nexthop_group_refresh(struct mlxsw_sp *mlxsw_sp,
32053460 struct mlxsw_sp_nexthop_group *nh_grp)
....@@ -3273,6 +3528,8 @@
32733528 goto set_trap;
32743529 }
32753530
3531
+ mlxsw_sp_nexthop_group_offload_refresh(mlxsw_sp, nh_grp);
3532
+
32763533 if (!old_adj_index_valid) {
32773534 /* The trap was set for fib entries, so we have to call
32783535 * fib entry update to unset it and use adjacency index.
....@@ -3294,9 +3551,6 @@
32943551 goto set_trap;
32953552 }
32963553
3297
- /* Offload state within the group changed, so update the flags. */
3298
- mlxsw_sp_nexthop_fib_entries_refresh(nh_grp);
3299
-
33003554 return;
33013555
33023556 set_trap:
....@@ -3309,6 +3563,7 @@
33093563 err = mlxsw_sp_nexthop_fib_entries_update(mlxsw_sp, nh_grp);
33103564 if (err)
33113565 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);
33123567 if (old_adj_index_valid)
33133568 mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ,
33143569 nh_grp->ecmp_size, nh_grp->adj_index);
....@@ -3506,9 +3761,15 @@
35063761
35073762 static bool mlxsw_sp_ipip_netdev_ul_up(struct net_device *ol_dev)
35083763 {
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;
35103766
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;
35123773 }
35133774
35143775 static void mlxsw_sp_nexthop_ipip_init(struct mlxsw_sp *mlxsw_sp,
....@@ -3542,7 +3803,7 @@
35423803 const struct fib_nh *fib_nh,
35433804 enum mlxsw_sp_ipip_type *p_ipipt)
35443805 {
3545
- struct net_device *dev = fib_nh->nh_dev;
3806
+ struct net_device *dev = fib_nh->fib_nh_dev;
35463807
35473808 return dev &&
35483809 fib_nh->nh_parent->fib_type == RTN_UNICAST &&
....@@ -3569,7 +3830,7 @@
35693830 struct fib_nh *fib_nh)
35703831 {
35713832 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;
35733834 struct mlxsw_sp_ipip_entry *ipip_entry;
35743835 struct mlxsw_sp_rif *rif;
35753836 int err;
....@@ -3613,18 +3874,18 @@
36133874 struct mlxsw_sp_nexthop *nh,
36143875 struct fib_nh *fib_nh)
36153876 {
3616
- struct net_device *dev = fib_nh->nh_dev;
3877
+ struct net_device *dev = fib_nh->fib_nh_dev;
36173878 struct in_device *in_dev;
36183879 int err;
36193880
36203881 nh->nh_grp = nh_grp;
36213882 nh->key.fib_nh = fib_nh;
36223883 #ifdef CONFIG_IP_ROUTE_MULTIPATH
3623
- nh->nh_weight = fib_nh->nh_weight;
3884
+ nh->nh_weight = fib_nh->fib_nh_weight;
36243885 #else
36253886 nh->nh_weight = 1;
36263887 #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));
36283889 err = mlxsw_sp_nexthop_insert(mlxsw_sp, nh);
36293890 if (err)
36303891 return err;
....@@ -3635,10 +3896,14 @@
36353896 if (!dev)
36363897 return 0;
36373898
3638
- in_dev = __in_dev_get_rtnl(dev);
3899
+ rcu_read_lock();
3900
+ in_dev = __in_dev_get_rcu(dev);
36393901 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();
36413904 return 0;
3905
+ }
3906
+ rcu_read_unlock();
36423907
36433908 err = mlxsw_sp_nexthop4_type_init(mlxsw_sp, nh, fib_nh);
36443909 if (err)
....@@ -3671,7 +3936,7 @@
36713936
36723937 key.fib_nh = fib_nh;
36733938 nh = mlxsw_sp_nexthop_lookup(mlxsw_sp, key);
3674
- if (WARN_ON_ONCE(!nh))
3939
+ if (!nh)
36753940 return;
36763941
36773942 switch (event) {
....@@ -3734,25 +3999,25 @@
37343999 }
37354000
37364001 static bool mlxsw_sp_fi_is_gateway(const struct mlxsw_sp *mlxsw_sp,
3737
- const struct fib_info *fi)
4002
+ struct fib_info *fi)
37384003 {
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);
37414008 }
37424009
37434010 static struct mlxsw_sp_nexthop_group *
37444011 mlxsw_sp_nexthop4_group_create(struct mlxsw_sp *mlxsw_sp, struct fib_info *fi)
37454012 {
4013
+ unsigned int nhs = fib_info_num_path(fi);
37464014 struct mlxsw_sp_nexthop_group *nh_grp;
37474015 struct mlxsw_sp_nexthop *nh;
37484016 struct fib_nh *fib_nh;
3749
- size_t alloc_size;
37504017 int i;
37514018 int err;
37524019
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);
37564021 if (!nh_grp)
37574022 return ERR_PTR(-ENOMEM);
37584023 nh_grp->priv = fi;
....@@ -3760,11 +4025,11 @@
37604025 nh_grp->neigh_tbl = &arp_tbl;
37614026
37624027 nh_grp->gateway = mlxsw_sp_fi_is_gateway(mlxsw_sp, fi);
3763
- nh_grp->count = fi->fib_nhs;
4028
+ nh_grp->count = nhs;
37644029 fib_info_hold(fi);
37654030 for (i = 0; i < nh_grp->count; i++) {
37664031 nh = &nh_grp->nexthops[i];
3767
- fib_nh = &fi->fib_nh[i];
4032
+ fib_nh = fib_info_nh(fi, i);
37684033 err = mlxsw_sp_nexthop4_init(mlxsw_sp, nh_grp, nh, fib_nh);
37694034 if (err)
37704035 goto err_nexthop4_init;
....@@ -3861,7 +4126,9 @@
38614126 return !!nh_group->adj_index_valid;
38624127 case MLXSW_SP_FIB_ENTRY_TYPE_LOCAL:
38634128 return !!nh_group->nh_rif;
4129
+ case MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE:
38644130 case MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP:
4131
+ case MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP:
38654132 return true;
38664133 default:
38674134 return false;
....@@ -3878,9 +4145,9 @@
38784145 struct mlxsw_sp_nexthop *nh = &nh_grp->nexthops[i];
38794146 struct fib6_info *rt = mlxsw_sp_rt6->rt;
38804147
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 &&
38824149 ipv6_addr_equal((const struct in6_addr *) &nh->gw_addr,
3883
- &rt->fib6_nh.nh_gw))
4150
+ &rt->fib6_nh->fib_nh_gw6))
38844151 return nh;
38854152 continue;
38864153 }
....@@ -3889,127 +4156,128 @@
38894156 }
38904157
38914158 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)
38934161 {
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;
38964168
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);
39114181 }
39124182
39134183 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)
39154186 {
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;
39184192
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);
39274204 }
39284205
39294206 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)
39314229 {
39324230 struct mlxsw_sp_fib6_entry *fib6_entry;
39334231 struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
39344232
39354233 fib6_entry = container_of(fib_entry, struct mlxsw_sp_fib6_entry,
39364234 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);
39544237 }
39554238
39564239 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)
39724242 {
39734243 switch (fib_entry->fib_node->fib->proto) {
39744244 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);
39764246 break;
39774247 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);
39794249 break;
39804250 }
39814251 }
39824252
39834253 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)
39854256 {
39864257 switch (fib_entry->fib_node->fib->proto) {
39874258 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);
39894260 break;
39904261 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);
39924263 break;
39934264 }
39944265 }
39954266
39964267 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)
39994271 {
40004272 switch (op) {
4001
- case MLXSW_REG_RALUE_OP_WRITE_DELETE:
4002
- return mlxsw_sp_fib_entry_offload_unset(fib_entry);
40034273 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;
40114279 default:
4012
- return;
4280
+ break;
40134281 }
40144282 }
40154283
....@@ -4039,15 +4307,50 @@
40394307 }
40404308 }
40414309
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
+
40424343 static int mlxsw_sp_fib_entry_op_remote(struct mlxsw_sp *mlxsw_sp,
40434344 struct mlxsw_sp_fib_entry *fib_entry,
40444345 enum mlxsw_reg_ralue_op op)
40454346 {
4347
+ struct mlxsw_sp_nexthop_group *nh_group = fib_entry->nh_group;
40464348 char ralue_pl[MLXSW_REG_RALUE_LEN];
40474349 enum mlxsw_reg_ralue_trap_action trap_action;
40484350 u16 trap_id = 0;
40494351 u32 adjacency_index = 0;
40504352 u16 ecmp_size = 0;
4353
+ int err;
40514354
40524355 /* In case the nexthop group adjacency index is valid, use it
40534356 * with provided ECMP size. Otherwise, setup trap and pass
....@@ -4057,6 +4360,15 @@
40574360 trap_action = MLXSW_REG_RALUE_TRAP_ACTION_NOP;
40584361 adjacency_index = fib_entry->nh_group->adj_index;
40594362 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;
40604372 } else {
40614373 trap_action = MLXSW_REG_RALUE_TRAP_ACTION_TRAP;
40624374 trap_id = MLXSW_TRAP_ID_RTR_INGRESS0;
....@@ -4103,6 +4415,36 @@
41034415 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl);
41044416 }
41054417
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
+
41064448 static int
41074449 mlxsw_sp_fib_entry_op_ipip_decap(struct mlxsw_sp *mlxsw_sp,
41084450 struct mlxsw_sp_fib_entry *fib_entry,
....@@ -4119,6 +4461,18 @@
41194461 fib_entry->decap.tunnel_index);
41204462 }
41214463
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
+
41224476 static int __mlxsw_sp_fib_entry_op(struct mlxsw_sp *mlxsw_sp,
41234477 struct mlxsw_sp_fib_entry *fib_entry,
41244478 enum mlxsw_reg_ralue_op op)
....@@ -4130,9 +4484,16 @@
41304484 return mlxsw_sp_fib_entry_op_local(mlxsw_sp, fib_entry, op);
41314485 case MLXSW_SP_FIB_ENTRY_TYPE_TRAP:
41324486 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);
41334492 case MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP:
41344493 return mlxsw_sp_fib_entry_op_ipip_decap(mlxsw_sp,
41354494 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);
41364497 }
41374498 return -EINVAL;
41384499 }
....@@ -4143,7 +4504,10 @@
41434504 {
41444505 int err = __mlxsw_sp_fib_entry_op(mlxsw_sp, fib_entry, op);
41454506
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);
41474511
41484512 return err;
41494513 }
....@@ -4167,8 +4531,10 @@
41674531 const struct fib_entry_notifier_info *fen_info,
41684532 struct mlxsw_sp_fib_entry *fib_entry)
41694533 {
4534
+ struct net_device *dev = fib_info_nh(fen_info->fi, 0)->fib_nh_dev;
41704535 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);
41724538 struct mlxsw_sp_ipip_entry *ipip_entry;
41734539 struct fib_info *fi = fen_info->fi;
41744540
....@@ -4182,18 +4548,30 @@
41824548 fib_entry,
41834549 ipip_entry);
41844550 }
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;
41864562 case RTN_BROADCAST:
41874563 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP;
41884564 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:
41914569 case RTN_PROHIBIT:
41924570 /* Packets hitting these routes need to be trapped, but
41934571 * can do so with a lower priority than packets directed
41944572 * at the host, so use action type local instead of trap.
41954573 */
4196
- fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_LOCAL;
4574
+ fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_UNREACHABLE;
41974575 return 0;
41984576 case RTN_UNICAST:
41994577 if (mlxsw_sp_fi_is_gateway(mlxsw_sp, fi))
....@@ -4203,6 +4581,19 @@
42034581 return 0;
42044582 default:
42054583 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;
42064597 }
42074598 }
42084599
....@@ -4238,6 +4629,7 @@
42384629 return fib4_entry;
42394630
42404631 err_nexthop4_group_get:
4632
+ mlxsw_sp_fib4_entry_type_unset(mlxsw_sp, fib_entry);
42414633 err_fib4_entry_type_set:
42424634 kfree(fib4_entry);
42434635 return ERR_PTR(err);
....@@ -4247,6 +4639,7 @@
42474639 struct mlxsw_sp_fib4_entry *fib4_entry)
42484640 {
42494641 mlxsw_sp_nexthop4_group_put(mlxsw_sp, &fib4_entry->common);
4642
+ mlxsw_sp_fib4_entry_type_unset(mlxsw_sp, &fib4_entry->common);
42504643 kfree(fib4_entry);
42514644 }
42524645
....@@ -4270,15 +4663,14 @@
42704663 if (!fib_node)
42714664 return NULL;
42724665
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;
42824674
42834675 return NULL;
42844676 }
....@@ -4326,7 +4718,6 @@
43264718 if (!fib_node)
43274719 return NULL;
43284720
4329
- INIT_LIST_HEAD(&fib_node->entry_list);
43304721 list_add(&fib_node->list, &fib->node_list);
43314722 memcpy(fib_node->key.addr, addr, addr_len);
43324723 fib_node->key.prefix_len = prefix_len;
....@@ -4337,16 +4728,7 @@
43374728 static void mlxsw_sp_fib_node_destroy(struct mlxsw_sp_fib_node *fib_node)
43384729 {
43394730 list_del(&fib_node->list);
4340
- WARN_ON(!list_empty(&fib_node->entry_list));
43414731 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;
43504732 }
43514733
43524734 static int mlxsw_sp_fib_lpm_tree_link(struct mlxsw_sp *mlxsw_sp,
....@@ -4488,200 +4870,65 @@
44884870 {
44894871 struct mlxsw_sp_vr *vr = fib_node->fib->vr;
44904872
4491
- if (!list_empty(&fib_node->entry_list))
4873
+ if (fib_node->fib_entry)
44924874 return;
44934875 mlxsw_sp_fib_node_fini(mlxsw_sp, fib_node);
44944876 mlxsw_sp_fib_node_destroy(fib_node);
44954877 mlxsw_sp_vr_put(mlxsw_sp, vr);
44964878 }
44974879
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,
46094881 struct mlxsw_sp_fib_entry *fib_entry)
46104882 {
46114883 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
-{
46334884 int err;
46344885
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;
46384887
4639
- err = mlxsw_sp_fib_node_entry_add(mlxsw_sp, &fib4_entry->common);
4888
+ err = mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry);
46404889 if (err)
4641
- goto err_fib_node_entry_add;
4890
+ goto err_fib_entry_update;
46424891
46434892 return 0;
46444893
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;
46474896 return err;
46484897 }
46494898
46504899 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)
46534902 {
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;
46564904
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;
46594907 }
46604908
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)
46644910 {
46654911 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;
46674913
4668
- if (!replace)
4669
- return;
4914
+ if (!fib_node->fib_entry)
4915
+ return true;
46704916
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;
46734922
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;
46774924 }
46784925
46794926 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)
46834929 {
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;
46854932 struct mlxsw_sp_fib_node *fib_node;
46864933 int err;
46874934
....@@ -4704,18 +4951,32 @@
47044951 goto err_fib4_entry_create;
47054952 }
47064953
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;
47124958 }
47134959
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);
47154975
47164976 return 0;
47174977
4718
-err_fib4_node_entry_link:
4978
+err_fib_node_entry_link:
4979
+ fib_node->fib_entry = replaced;
47194980 mlxsw_sp_fib4_entry_destroy(mlxsw_sp, fib4_entry);
47204981 err_fib4_entry_create:
47214982 mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
....@@ -4732,24 +4993,17 @@
47324993 return;
47334994
47344995 fib4_entry = mlxsw_sp_fib4_entry_lookup(mlxsw_sp, fen_info);
4735
- if (WARN_ON(!fib4_entry))
4996
+ if (!fib4_entry)
47364997 return;
47374998 fib_node = fib4_entry->common.fib_node;
47384999
4739
- mlxsw_sp_fib4_node_entry_unlink(mlxsw_sp, fib4_entry);
5000
+ mlxsw_sp_fib_node_entry_unlink(mlxsw_sp, &fib4_entry->common);
47405001 mlxsw_sp_fib4_entry_destroy(mlxsw_sp, fib4_entry);
47415002 mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
47425003 }
47435004
47445005 static bool mlxsw_sp_fib6_rt_should_ignore(const struct fib6_info *rt)
47455006 {
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
-
47535007 /* Multicast routes aren't supported, so ignore them. Neighbour
47545008 * Discovery packets are specifically trapped.
47555009 */
....@@ -4794,14 +5048,11 @@
47945048
47955049 static void mlxsw_sp_rt6_destroy(struct mlxsw_sp_rt6 *mlxsw_sp_rt6)
47965050 {
5051
+ struct fib6_nh *fib6_nh = mlxsw_sp_rt6->rt->fib6_nh;
5052
+
5053
+ fib6_nh->fib_nh_flags &= ~RTNH_F_OFFLOAD;
47975054 mlxsw_sp_rt6_release(mlxsw_sp_rt6->rt);
47985055 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;
48055056 }
48065057
48075058 static struct fib6_info *
....@@ -4809,37 +5060,6 @@
48095060 {
48105061 return list_first_entry(&fib6_entry->rt6_list, struct mlxsw_sp_rt6,
48115062 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;
48435063 }
48445064
48455065 static struct mlxsw_sp_rt6 *
....@@ -4860,8 +5080,8 @@
48605080 const struct fib6_info *rt,
48615081 enum mlxsw_sp_ipip_type *ret)
48625082 {
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);
48655085 }
48665086
48675087 static int mlxsw_sp_nexthop6_type_init(struct mlxsw_sp *mlxsw_sp,
....@@ -4871,7 +5091,7 @@
48715091 {
48725092 const struct mlxsw_sp_ipip_ops *ipip_ops;
48735093 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;
48755095 struct mlxsw_sp_rif *rif;
48765096 int err;
48775097
....@@ -4914,11 +5134,11 @@
49145134 struct mlxsw_sp_nexthop *nh,
49155135 const struct fib6_info *rt)
49165136 {
4917
- struct net_device *dev = rt->fib6_nh.nh_dev;
5137
+ struct net_device *dev = rt->fib6_nh->fib_nh_dev;
49185138
49195139 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));
49225142 mlxsw_sp_nexthop_counter_alloc(mlxsw_sp, nh);
49235143
49245144 list_add_tail(&nh->router_list_node, &mlxsw_sp->router->nexthop_list);
....@@ -4941,7 +5161,7 @@
49415161 static bool mlxsw_sp_rt6_is_gateway(const struct mlxsw_sp *mlxsw_sp,
49425162 const struct fib6_info *rt)
49435163 {
4944
- return rt->fib6_flags & RTF_GATEWAY ||
5164
+ return rt->fib6_nh->fib_nh_gw_family ||
49455165 mlxsw_sp_nexthop6_ipip_type(mlxsw_sp, rt, NULL);
49465166 }
49475167
....@@ -4952,13 +5172,11 @@
49525172 struct mlxsw_sp_nexthop_group *nh_grp;
49535173 struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
49545174 struct mlxsw_sp_nexthop *nh;
4955
- size_t alloc_size;
49565175 int i = 0;
49575176 int err;
49585177
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);
49625180 if (!nh_grp)
49635181 return ERR_PTR(-ENOMEM);
49645182 INIT_LIST_HEAD(&nh_grp->fib_list);
....@@ -5029,6 +5247,11 @@
50295247 &nh_grp->fib_list);
50305248 fib6_entry->common.nh_group = nh_grp;
50315249
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
+
50325255 return 0;
50335256 }
50345257
....@@ -5061,16 +5284,16 @@
50615284 * currently associated with it in the device's table is that
50625285 * of the old group. Start using the new one instead.
50635286 */
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);
50655288 if (err)
5066
- goto err_fib_node_entry_add;
5289
+ goto err_fib_entry_update;
50675290
50685291 if (list_empty(&old_nh_grp->fib_list))
50695292 mlxsw_sp_nexthop6_group_destroy(mlxsw_sp, old_nh_grp);
50705293
50715294 return 0;
50725295
5073
-err_fib_node_entry_add:
5296
+err_fib_entry_update:
50745297 mlxsw_sp_nexthop6_group_put(mlxsw_sp, &fib6_entry->common);
50755298 err_nexthop6_group_get:
50765299 list_add_tail(&fib6_entry->common.nexthop_group_node,
....@@ -5082,17 +5305,21 @@
50825305 static int
50835306 mlxsw_sp_fib6_entry_nexthop_add(struct mlxsw_sp *mlxsw_sp,
50845307 struct mlxsw_sp_fib6_entry *fib6_entry,
5085
- struct fib6_info *rt)
5308
+ struct fib6_info **rt_arr, unsigned int nrt6)
50865309 {
50875310 struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
5088
- int err;
5311
+ int err, i;
50895312
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
+ }
50935319
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
+ }
50965323
50975324 err = mlxsw_sp_nexthop6_group_update(mlxsw_sp, fib6_entry);
50985325 if (err)
....@@ -5101,27 +5328,38 @@
51015328 return 0;
51025329
51035330 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
+ }
51075340 return err;
51085341 }
51095342
51105343 static void
51115344 mlxsw_sp_fib6_entry_nexthop_del(struct mlxsw_sp *mlxsw_sp,
51125345 struct mlxsw_sp_fib6_entry *fib6_entry,
5113
- struct fib6_info *rt)
5346
+ struct fib6_info **rt_arr, unsigned int nrt6)
51145347 {
51155348 struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
5349
+ int i;
51165350
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;
51205356
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
+
51235362 mlxsw_sp_nexthop6_group_update(mlxsw_sp, fib6_entry);
5124
- mlxsw_sp_rt6_destroy(mlxsw_sp_rt6);
51255363 }
51265364
51275365 static void mlxsw_sp_fib6_entry_type_set(struct mlxsw_sp *mlxsw_sp,
....@@ -5136,8 +5374,10 @@
51365374 */
51375375 if (rt->fib6_flags & (RTF_LOCAL | RTF_ANYCAST))
51385376 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;
51395379 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;
51415381 else if (mlxsw_sp_rt6_is_gateway(mlxsw_sp, rt))
51425382 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_REMOTE;
51435383 else
....@@ -5160,29 +5400,32 @@
51605400 static struct mlxsw_sp_fib6_entry *
51615401 mlxsw_sp_fib6_entry_create(struct mlxsw_sp *mlxsw_sp,
51625402 struct mlxsw_sp_fib_node *fib_node,
5163
- struct fib6_info *rt)
5403
+ struct fib6_info **rt_arr, unsigned int nrt6)
51645404 {
51655405 struct mlxsw_sp_fib6_entry *fib6_entry;
51665406 struct mlxsw_sp_fib_entry *fib_entry;
51675407 struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
5168
- int err;
5408
+ int err, i;
51695409
51705410 fib6_entry = kzalloc(sizeof(*fib6_entry), GFP_KERNEL);
51715411 if (!fib6_entry)
51725412 return ERR_PTR(-ENOMEM);
51735413 fib_entry = &fib6_entry->common;
51745414
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++;
51795425 }
51805426
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]);
51825428
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;
51865429 err = mlxsw_sp_nexthop6_group_get(mlxsw_sp, fib6_entry);
51875430 if (err)
51885431 goto err_nexthop6_group_get;
....@@ -5192,9 +5435,15 @@
51925435 return fib6_entry;
51935436
51945437 err_nexthop6_group_get:
5195
- list_del(&mlxsw_sp_rt6->list);
5196
- mlxsw_sp_rt6_destroy(mlxsw_sp_rt6);
5438
+ i = nrt6;
51975439 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
+ }
51985447 kfree(fib6_entry);
51995448 return ERR_PTR(err);
52005449 }
....@@ -5209,112 +5458,13 @@
52095458 }
52105459
52115460 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 *
53125461 mlxsw_sp_fib6_entry_lookup(struct mlxsw_sp *mlxsw_sp,
53135462 const struct fib6_info *rt)
53145463 {
53155464 struct mlxsw_sp_fib6_entry *fib6_entry;
53165465 struct mlxsw_sp_fib_node *fib_node;
53175466 struct mlxsw_sp_fib *fib;
5467
+ struct fib6_info *cmp_rt;
53185468 struct mlxsw_sp_vr *vr;
53195469
53205470 vr = mlxsw_sp_vr_find(mlxsw_sp, rt->fib6_table->tb6_id);
....@@ -5328,40 +5478,46 @@
53285478 if (!fib_node)
53295479 return NULL;
53305480
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;
53395488
53405489 return NULL;
53415490 }
53425491
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)
53465493 {
53475494 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;
53495497
5350
- if (!replace)
5351
- return;
5498
+ if (!fib_node->fib_entry)
5499
+ return true;
53525500
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;
53545509
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;
53585511 }
53595512
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)
53625516 {
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;
53645519 struct mlxsw_sp_fib_node *fib_node;
5520
+ struct fib6_info *rt = rt_arr[0];
53655521 int err;
53665522
53675523 if (mlxsw_sp->router->aborted)
....@@ -5381,44 +5537,95 @@
53815537 if (IS_ERR(fib_node))
53825538 return PTR_ERR(fib_node);
53835539
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);
53965542 if (IS_ERR(fib6_entry)) {
53975543 err = PTR_ERR(fib6_entry);
53985544 goto err_fib6_entry_create;
53995545 }
54005546
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
+ }
54045552
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);
54065566
54075567 return 0;
54085568
5409
-err_fib6_node_entry_link:
5569
+err_fib_node_entry_link:
5570
+ fib_node->fib_entry = replaced;
54105571 mlxsw_sp_fib6_entry_destroy(mlxsw_sp, fib6_entry);
54115572 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
+
54125617 err_fib6_entry_nexthop_add:
54135618 mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
54145619 return err;
54155620 }
54165621
54175622 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)
54195625 {
54205626 struct mlxsw_sp_fib6_entry *fib6_entry;
54215627 struct mlxsw_sp_fib_node *fib_node;
5628
+ struct fib6_info *rt = rt_arr[0];
54225629
54235630 if (mlxsw_sp->router->aborted)
54245631 return;
....@@ -5426,21 +5633,27 @@
54265633 if (mlxsw_sp_fib6_rt_should_ignore(rt))
54275634 return;
54285635
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
+ */
54295641 fib6_entry = mlxsw_sp_fib6_entry_lookup(mlxsw_sp, rt);
5430
- if (WARN_ON(!fib6_entry))
5642
+ if (!fib6_entry)
54315643 return;
54325644
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.
54355647 */
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);
54385651 return;
54395652 }
54405653
54415654 fib_node = fib6_entry->common.fib_node;
54425655
5443
- mlxsw_sp_fib6_node_entry_unlink(mlxsw_sp, fib6_entry);
5656
+ mlxsw_sp_fib_node_entry_unlink(mlxsw_sp, &fib6_entry->common);
54445657 mlxsw_sp_fib6_entry_destroy(mlxsw_sp, fib6_entry);
54455658 mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
54465659 }
....@@ -5594,39 +5807,25 @@
55945807 static void mlxsw_sp_fib4_node_flush(struct mlxsw_sp *mlxsw_sp,
55955808 struct mlxsw_sp_fib_node *fib_node)
55965809 {
5597
- struct mlxsw_sp_fib4_entry *fib4_entry, *tmp;
5810
+ struct mlxsw_sp_fib4_entry *fib4_entry;
55985811
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);
56135817 }
56145818
56155819 static void mlxsw_sp_fib6_node_flush(struct mlxsw_sp *mlxsw_sp,
56165820 struct mlxsw_sp_fib_node *fib_node)
56175821 {
5618
- struct mlxsw_sp_fib6_entry *fib6_entry, *tmp;
5822
+ struct mlxsw_sp_fib6_entry *fib6_entry;
56195823
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);
56305829 }
56315830
56325831 static void mlxsw_sp_fib_node_flush(struct mlxsw_sp *mlxsw_sp,
....@@ -5679,6 +5878,16 @@
56795878 continue;
56805879 mlxsw_sp_vr_fib_flush(mlxsw_sp, vr, MLXSW_SP_L3_PROTO_IPV6);
56815880 }
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;
56825891 }
56835892
56845893 static void mlxsw_sp_router_fib_abort(struct mlxsw_sp *mlxsw_sp)
....@@ -5695,10 +5904,15 @@
56955904 dev_warn(mlxsw_sp->bus_info->dev, "Failed to set abort trap.\n");
56965905 }
56975906
5907
+struct mlxsw_sp_fib6_event_work {
5908
+ struct fib6_info **rt_arr;
5909
+ unsigned int nrt6;
5910
+};
5911
+
56985912 struct mlxsw_sp_fib_event_work {
56995913 struct work_struct work;
57005914 union {
5701
- struct fib6_entry_notifier_info fen6_info;
5915
+ struct mlxsw_sp_fib6_event_work fib6_work;
57025916 struct fib_entry_notifier_info fen_info;
57035917 struct fib_rule_notifier_info fr_info;
57045918 struct fib_nh_notifier_info fnh_info;
....@@ -5709,26 +5923,68 @@
57095923 unsigned long event;
57105924 };
57115925
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
+
57125974 static void mlxsw_sp_router_fib4_event_work(struct work_struct *work)
57135975 {
57145976 struct mlxsw_sp_fib_event_work *fib_work =
57155977 container_of(work, struct mlxsw_sp_fib_event_work, work);
57165978 struct mlxsw_sp *mlxsw_sp = fib_work->mlxsw_sp;
5717
- bool replace, append;
57185979 int err;
57195980
5720
- /* Protect internal structures from changes */
5721
- rtnl_lock();
5981
+ mutex_lock(&mlxsw_sp->router->lock);
57225982 mlxsw_sp_span_respin(mlxsw_sp);
57235983
57245984 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);
57325988 if (err)
57335989 mlxsw_sp_router_fib_abort(mlxsw_sp);
57345990 fib_info_put(fib_work->fen_info.fi);
....@@ -5737,20 +5993,14 @@
57375993 mlxsw_sp_router_fib4_del(mlxsw_sp, &fib_work->fen_info);
57385994 fib_info_put(fib_work->fen_info.fi);
57395995 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:
57475997 case FIB_EVENT_NH_DEL:
57485998 mlxsw_sp_nexthop4_event(mlxsw_sp, fib_work->event,
57495999 fib_work->fnh_info.fib_nh);
57506000 fib_info_put(fib_work->fnh_info.fib_nh->nh_parent);
57516001 break;
57526002 }
5753
- rtnl_unlock();
6003
+ mutex_unlock(&mlxsw_sp->router->lock);
57546004 kfree(fib_work);
57556005 }
57566006
....@@ -5759,35 +6009,36 @@
57596009 struct mlxsw_sp_fib_event_work *fib_work =
57606010 container_of(work, struct mlxsw_sp_fib_event_work, work);
57616011 struct mlxsw_sp *mlxsw_sp = fib_work->mlxsw_sp;
5762
- bool replace;
57636012 int err;
57646013
5765
- rtnl_lock();
6014
+ mutex_lock(&mlxsw_sp->router->lock);
57666015 mlxsw_sp_span_respin(mlxsw_sp);
57676016
57686017 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);
57756022 if (err)
57766023 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);
57786033 break;
57796034 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);
57886039 break;
57896040 }
5790
- rtnl_unlock();
6041
+ mutex_unlock(&mlxsw_sp->router->lock);
57916042 kfree(fib_work);
57926043 }
57936044
....@@ -5800,8 +6051,9 @@
58006051 int err;
58016052
58026053 rtnl_lock();
6054
+ mutex_lock(&mlxsw_sp->router->lock);
58036055 switch (fib_work->event) {
5804
- case FIB_EVENT_ENTRY_REPLACE: /* fall through */
6056
+ case FIB_EVENT_ENTRY_REPLACE:
58056057 case FIB_EVENT_ENTRY_ADD:
58066058 replace = fib_work->event == FIB_EVENT_ENTRY_REPLACE;
58076059
....@@ -5827,13 +6079,8 @@
58276079 &fib_work->ven_info);
58286080 dev_put(fib_work->ven_info.dev);
58296081 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;
58366082 }
6083
+ mutex_unlock(&mlxsw_sp->router->lock);
58376084 rtnl_unlock();
58386085 kfree(fib_work);
58396086 }
....@@ -5845,9 +6092,7 @@
58456092 struct fib_nh_notifier_info *fnh_info;
58466093
58476094 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:
58516096 case FIB_EVENT_ENTRY_DEL:
58526097 fen_info = container_of(info, struct fib_entry_notifier_info,
58536098 info);
....@@ -5857,7 +6102,7 @@
58576102 */
58586103 fib_info_hold(fib_work->fen_info.fi);
58596104 break;
5860
- case FIB_EVENT_NH_ADD: /* fall through */
6105
+ case FIB_EVENT_NH_ADD:
58616106 case FIB_EVENT_NH_DEL:
58626107 fnh_info = container_of(info, struct fib_nh_notifier_info,
58636108 info);
....@@ -5867,22 +6112,26 @@
58676112 }
58686113 }
58696114
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)
58726117 {
58736118 struct fib6_entry_notifier_info *fen6_info;
6119
+ int err;
58746120
58756121 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:
58796124 case FIB_EVENT_ENTRY_DEL:
58806125 fen6_info = container_of(info, struct fib6_entry_notifier_info,
58816126 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;
58846131 break;
58856132 }
6133
+
6134
+ return 0;
58866135 }
58876136
58886137 static void
....@@ -5890,13 +6139,13 @@
58906139 struct fib_notifier_info *info)
58916140 {
58926141 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:
58956144 case FIB_EVENT_ENTRY_DEL:
58966145 memcpy(&fib_work->men_info, info, sizeof(fib_work->men_info));
58976146 mr_cache_hold(fib_work->men_info.mfc);
58986147 break;
5899
- case FIB_EVENT_VIF_ADD: /* fall through */
6148
+ case FIB_EVENT_VIF_ADD:
59006149 case FIB_EVENT_VIF_DEL:
59016150 memcpy(&fib_work->ven_info, info, sizeof(fib_work->ven_info));
59026151 dev_hold(fib_work->ven_info.dev);
....@@ -5922,6 +6171,10 @@
59226171
59236172 fr_info = container_of(info, struct fib_rule_notifier_info, info);
59246173 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;
59256178
59266179 switch (info->family) {
59276180 case AF_INET:
....@@ -5957,8 +6210,7 @@
59576210 struct mlxsw_sp_router *router;
59586211 int err;
59596212
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 &&
59626214 info->family != RTNL_FAMILY_IPMR &&
59636215 info->family != RTNL_FAMILY_IP6MR))
59646216 return NOTIFY_DONE;
....@@ -5966,17 +6218,39 @@
59666218 router = container_of(nb, struct mlxsw_sp_router, fib_nb);
59676219
59686220 switch (event) {
5969
- case FIB_EVENT_RULE_ADD: /* fall through */
6221
+ case FIB_EVENT_RULE_ADD:
59706222 case FIB_EVENT_RULE_DEL:
59716223 err = mlxsw_sp_router_fib_rule_event(event, info,
59726224 router->mlxsw_sp);
5973
- if (!err || info->extack)
5974
- return notifier_from_errno(err);
5975
- break;
6225
+ return notifier_from_errno(err);
59766226 case FIB_EVENT_ENTRY_ADD:
6227
+ case FIB_EVENT_ENTRY_REPLACE:
6228
+ case FIB_EVENT_ENTRY_APPEND:
59776229 if (router->aborted) {
59786230 NL_SET_ERR_MSG_MOD(info->extack, "FIB offload was aborted. Not configuring route");
59796231 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
+ }
59806254 }
59816255 break;
59826256 }
....@@ -5995,7 +6269,9 @@
59956269 break;
59966270 case AF_INET6:
59976271 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;
59996275 break;
60006276 case RTNL_FAMILY_IP6MR:
60016277 case RTNL_FAMILY_IPMR:
....@@ -6007,9 +6283,13 @@
60076283 mlxsw_core_schedule_work(&fib_work->work);
60086284
60096285 return NOTIFY_DONE;
6286
+
6287
+err_fib_event:
6288
+ kfree(fib_work);
6289
+ return NOTIFY_BAD;
60106290 }
60116291
6012
-struct mlxsw_sp_rif *
6292
+static struct mlxsw_sp_rif *
60136293 mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp *mlxsw_sp,
60146294 const struct net_device *dev)
60156295 {
....@@ -6023,6 +6303,41 @@
60236303 return NULL;
60246304 }
60256305
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
+
60266341 static int mlxsw_sp_router_rif_disable(struct mlxsw_sp *mlxsw_sp, u16 rif)
60276342 {
60286343 char ritr_pl[MLXSW_REG_RITR_LEN];
....@@ -6030,7 +6345,7 @@
60306345
60316346 mlxsw_reg_ritr_rif_pack(ritr_pl, rif);
60326347 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
6033
- if (WARN_ON_ONCE(err))
6348
+ if (err)
60346349 return err;
60356350
60366351 mlxsw_reg_ritr_enable_set(ritr_pl, false);
....@@ -6057,7 +6372,8 @@
60576372 case NETDEV_UP:
60586373 return rif == NULL;
60596374 case NETDEV_DOWN:
6060
- idev = __in_dev_get_rtnl(dev);
6375
+ rcu_read_lock();
6376
+ idev = __in_dev_get_rcu(dev);
60616377 if (idev && idev->ifa_list)
60626378 addr_list_empty = false;
60636379
....@@ -6065,6 +6381,7 @@
60656381 if (addr_list_empty && inet6_dev &&
60666382 !list_empty(&inet6_dev->addr_list))
60676383 addr_list_empty = false;
6384
+ rcu_read_unlock();
60686385
60696386 /* macvlans do not have a RIF, but rather piggy back on the
60706387 * RIF of their lower device.
....@@ -6133,10 +6450,12 @@
61336450
61346451 INIT_LIST_HEAD(&rif->nexthop_list);
61356452 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
+ }
61386458 rif->vr_id = vr_id;
6139
- rif->dev = l3_dev;
61406459 rif->rif_index = rif_index;
61416460
61426461 return rif;
....@@ -6160,7 +6479,19 @@
61606479
61616480 u16 mlxsw_sp_ipip_lb_ul_vr_id(const struct mlxsw_sp_rif_ipip_lb *lb_rif)
61626481 {
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;
61646495 }
61656496
61666497 int mlxsw_sp_rif_dev_ifindex(const struct mlxsw_sp_rif *rif)
....@@ -6171,11 +6502,6 @@
61716502 const struct net_device *mlxsw_sp_rif_dev(const struct mlxsw_sp_rif *rif)
61726503 {
61736504 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;
61796505 }
61806506
61816507 static struct mlxsw_sp_rif *
....@@ -6193,7 +6519,7 @@
61936519 int i, err;
61946520
61956521 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];
61976523
61986524 vr = mlxsw_sp_vr_get(mlxsw_sp, tb_id ? : RT_TABLE_MAIN, extack);
61996525 if (IS_ERR(vr))
....@@ -6211,6 +6537,8 @@
62116537 err = -ENOMEM;
62126538 goto err_rif_alloc;
62136539 }
6540
+ dev_hold(rif->dev);
6541
+ mlxsw_sp->router->rifs[rif_index] = rif;
62146542 rif->mlxsw_sp = mlxsw_sp;
62156543 rif->ops = ops;
62166544
....@@ -6237,7 +6565,6 @@
62376565 }
62386566
62396567 mlxsw_sp_rif_counters_alloc(rif);
6240
- mlxsw_sp->router->rifs[rif_index] = rif;
62416568
62426569 return rif;
62436570
....@@ -6249,6 +6576,8 @@
62496576 if (fid)
62506577 mlxsw_sp_fid_put(fid);
62516578 err_fid_get:
6579
+ mlxsw_sp->router->rifs[rif_index] = NULL;
6580
+ dev_put(rif->dev);
62526581 kfree(rif);
62536582 err_rif_alloc:
62546583 err_rif_index_alloc:
....@@ -6257,7 +6586,7 @@
62576586 return ERR_PTR(err);
62586587 }
62596588
6260
-void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif)
6589
+static void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif)
62616590 {
62626591 const struct mlxsw_sp_rif_ops *ops = rif->ops;
62636592 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
....@@ -6268,7 +6597,6 @@
62686597 mlxsw_sp_router_rif_gone_sync(mlxsw_sp, rif);
62696598 vr = &mlxsw_sp->router->vrs[rif->vr_id];
62706599
6271
- mlxsw_sp->router->rifs[rif->rif_index] = NULL;
62726600 mlxsw_sp_rif_counters_free(rif);
62736601 for (i = 0; i < MLXSW_SP_L3_PROTO_MAX; i++)
62746602 mlxsw_sp_mr_rif_del(vr->mr_table[i], rif);
....@@ -6276,6 +6604,8 @@
62766604 if (fid)
62776605 /* Loopback RIFs are not associated with a FID. */
62786606 mlxsw_sp_fid_put(fid);
6607
+ mlxsw_sp->router->rifs[rif->rif_index] = NULL;
6608
+ dev_put(rif->dev);
62796609 kfree(rif);
62806610 vr->rif_count--;
62816611 mlxsw_sp_vr_put(mlxsw_sp, vr);
....@@ -6286,10 +6616,13 @@
62866616 {
62876617 struct mlxsw_sp_rif *rif;
62886618
6619
+ mutex_lock(&mlxsw_sp->router->lock);
62896620 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
62906621 if (!rif)
6291
- return;
6622
+ goto out;
62926623 mlxsw_sp_rif_destroy(rif);
6624
+out:
6625
+ mutex_unlock(&mlxsw_sp->router->lock);
62936626 }
62946627
62956628 static void
....@@ -6306,6 +6639,40 @@
63066639 params->system_port = mlxsw_sp_port->local_port;
63076640 }
63086641
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
+
63096676 static int
63106677 mlxsw_sp_port_vlan_router_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
63116678 struct net_device *l3_dev,
....@@ -6313,22 +6680,18 @@
63136680 {
63146681 struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
63156682 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
6683
+ struct mlxsw_sp_rif_params params = {
6684
+ .dev = l3_dev,
6685
+ };
63166686 u16 vid = mlxsw_sp_port_vlan->vid;
63176687 struct mlxsw_sp_rif *rif;
63186688 struct mlxsw_sp_fid *fid;
63196689 int err;
63206690
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(&params, mlxsw_sp_port_vlan);
6328
- rif = mlxsw_sp_rif_create(mlxsw_sp, &params, extack);
6329
- if (IS_ERR(rif))
6330
- return PTR_ERR(rif);
6331
- }
6691
+ mlxsw_sp_rif_subport_params_init(&params, mlxsw_sp_port_vlan);
6692
+ rif = mlxsw_sp_rif_subport_get(mlxsw_sp, &params, extack);
6693
+ if (IS_ERR(rif))
6694
+ return PTR_ERR(rif);
63326695
63336696 /* FID was already created, just take a reference */
63346697 fid = rif->ops->fid_get(rif, extack);
....@@ -6355,14 +6718,16 @@
63556718 mlxsw_sp_fid_port_vid_unmap(fid, mlxsw_sp_port, vid);
63566719 err_fid_port_vid_map:
63576720 mlxsw_sp_fid_put(fid);
6721
+ mlxsw_sp_rif_subport_put(rif);
63586722 return err;
63596723 }
63606724
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)
63636727 {
63646728 struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
63656729 struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
6730
+ struct mlxsw_sp_rif *rif = mlxsw_sp_fid_rif(fid);
63666731 u16 vid = mlxsw_sp_port_vlan->vid;
63676732
63686733 if (WARN_ON(mlxsw_sp_fid_type(fid) != MLXSW_SP_FID_TYPE_RFID))
....@@ -6372,10 +6737,18 @@
63726737 mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid, BR_STATE_BLOCKING);
63736738 mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, true);
63746739 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
- */
63786740 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);
63796752 }
63806753
63816754 static int mlxsw_sp_inetaddr_port_vlan_event(struct net_device *l3_dev,
....@@ -6395,7 +6768,7 @@
63956768 return mlxsw_sp_port_vlan_router_join(mlxsw_sp_port_vlan,
63966769 l3_dev, extack);
63976770 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);
63996772 break;
64006773 }
64016774
....@@ -6411,8 +6784,8 @@
64116784 netif_is_ovs_port(port_dev))
64126785 return 0;
64136786
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);
64166789 }
64176790
64186791 static int __mlxsw_sp_inetaddr_lag_event(struct net_device *l3_dev,
....@@ -6445,15 +6818,15 @@
64456818 if (netif_is_bridge_port(lag_dev))
64466819 return 0;
64476820
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);
64506823 }
64516824
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,
64536827 unsigned long event,
64546828 struct netlink_ext_ack *extack)
64556829 {
6456
- struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(l3_dev);
64576830 struct mlxsw_sp_rif_params params = {
64586831 .dev = l3_dev,
64596832 };
....@@ -6474,7 +6847,8 @@
64746847 return 0;
64756848 }
64766849
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,
64786852 unsigned long event,
64796853 struct netlink_ext_ack *extack)
64806854 {
....@@ -6491,7 +6865,8 @@
64916865 return __mlxsw_sp_inetaddr_lag_event(vlan_dev, real_dev, event,
64926866 vid, extack);
64936867 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);
64956870
64966871 return 0;
64976872 }
....@@ -6574,8 +6949,8 @@
65746949 return err;
65756950 }
65766951
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)
65796954 {
65806955 struct macvlan_dev *vlan = netdev_priv(macvlan_dev);
65816956 struct mlxsw_sp_rif *rif;
....@@ -6592,28 +6967,62 @@
65926967 mlxsw_sp_fid_index(rif->fid), false);
65936968 }
65946969
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,
65966980 unsigned long event,
65976981 struct netlink_ext_ack *extack)
65986982 {
6599
- struct mlxsw_sp *mlxsw_sp;
6600
-
6601
- mlxsw_sp = mlxsw_sp_lower_get(macvlan_dev);
6602
- if (!mlxsw_sp)
6603
- return 0;
6604
-
66056983 switch (event) {
66066984 case NETDEV_UP:
66076985 return mlxsw_sp_rif_macvlan_add(mlxsw_sp, macvlan_dev, extack);
66086986 case NETDEV_DOWN:
6609
- mlxsw_sp_rif_macvlan_del(mlxsw_sp, macvlan_dev);
6987
+ __mlxsw_sp_rif_macvlan_del(mlxsw_sp, macvlan_dev);
66106988 break;
66116989 }
66126990
66136991 return 0;
66146992 }
66156993
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,
66177026 unsigned long event,
66187027 struct netlink_ext_ack *extack)
66197028 {
....@@ -6622,38 +7031,40 @@
66227031 else if (netif_is_lag_master(dev))
66237032 return mlxsw_sp_inetaddr_lag_event(dev, event, extack);
66247033 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);
66267036 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);
66287039 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);
66307042 else
66317043 return 0;
66327044 }
66337045
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)
66367048 {
66377049 struct in_ifaddr *ifa = (struct in_ifaddr *) ptr;
66387050 struct net_device *dev = ifa->ifa_dev->dev;
6639
- struct mlxsw_sp *mlxsw_sp;
7051
+ struct mlxsw_sp_router *router;
66407052 struct mlxsw_sp_rif *rif;
66417053 int err = 0;
66427054
66437055 /* NETDEV_UP event is handled by mlxsw_sp_inetaddr_valid_event */
66447056 if (event == NETDEV_UP)
6645
- goto out;
7057
+ return NOTIFY_DONE;
66467058
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);
66527062 if (!mlxsw_sp_rif_should_config(rif, dev, event))
66537063 goto out;
66547064
6655
- err = __mlxsw_sp_inetaddr_event(dev, event, NULL);
7065
+ err = __mlxsw_sp_inetaddr_event(router->mlxsw_sp, dev, event, NULL);
66567066 out:
7067
+ mutex_unlock(&router->lock);
66577068 return notifier_from_errno(err);
66587069 }
66597070
....@@ -6668,19 +7079,27 @@
66687079
66697080 mlxsw_sp = mlxsw_sp_lower_get(dev);
66707081 if (!mlxsw_sp)
6671
- goto out;
7082
+ return NOTIFY_DONE;
66727083
7084
+ mutex_lock(&mlxsw_sp->router->lock);
66737085 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
66747086 if (!mlxsw_sp_rif_should_config(rif, dev, event))
66757087 goto out;
66767088
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);
66787095 out:
7096
+ mutex_unlock(&mlxsw_sp->router->lock);
66797097 return notifier_from_errno(err);
66807098 }
66817099
66827100 struct mlxsw_sp_inet6addr_event_work {
66837101 struct work_struct work;
7102
+ struct mlxsw_sp *mlxsw_sp;
66847103 struct net_device *dev;
66857104 unsigned long event;
66867105 };
....@@ -6689,47 +7108,46 @@
66897108 {
66907109 struct mlxsw_sp_inet6addr_event_work *inet6addr_work =
66917110 container_of(work, struct mlxsw_sp_inet6addr_event_work, work);
7111
+ struct mlxsw_sp *mlxsw_sp = inet6addr_work->mlxsw_sp;
66927112 struct net_device *dev = inet6addr_work->dev;
66937113 unsigned long event = inet6addr_work->event;
6694
- struct mlxsw_sp *mlxsw_sp;
66957114 struct mlxsw_sp_rif *rif;
66967115
66977116 rtnl_lock();
6698
- mlxsw_sp = mlxsw_sp_lower_get(dev);
6699
- if (!mlxsw_sp)
6700
- goto out;
7117
+ mutex_lock(&mlxsw_sp->router->lock);
67017118
67027119 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
67037120 if (!mlxsw_sp_rif_should_config(rif, dev, event))
67047121 goto out;
67057122
6706
- __mlxsw_sp_inetaddr_event(dev, event, NULL);
7123
+ __mlxsw_sp_inetaddr_event(mlxsw_sp, dev, event, NULL);
67077124 out:
7125
+ mutex_unlock(&mlxsw_sp->router->lock);
67087126 rtnl_unlock();
67097127 dev_put(dev);
67107128 kfree(inet6addr_work);
67117129 }
67127130
67137131 /* 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)
67167134 {
67177135 struct inet6_ifaddr *if6 = (struct inet6_ifaddr *) ptr;
67187136 struct mlxsw_sp_inet6addr_event_work *inet6addr_work;
67197137 struct net_device *dev = if6->idev->dev;
7138
+ struct mlxsw_sp_router *router;
67207139
67217140 /* NETDEV_UP event is handled by mlxsw_sp_inet6addr_valid_event */
67227141 if (event == NETDEV_UP)
6723
- return NOTIFY_DONE;
6724
-
6725
- if (!mlxsw_sp_port_dev_lower_find_rcu(dev))
67267142 return NOTIFY_DONE;
67277143
67287144 inet6addr_work = kzalloc(sizeof(*inet6addr_work), GFP_ATOMIC);
67297145 if (!inet6addr_work)
67307146 return NOTIFY_BAD;
67317147
7148
+ router = container_of(nb, struct mlxsw_sp_router, inet6addr_nb);
67327149 INIT_WORK(&inet6addr_work->work, mlxsw_sp_inet6addr_event_work);
7150
+ inet6addr_work->mlxsw_sp = router->mlxsw_sp;
67337151 inet6addr_work->dev = dev;
67347152 inet6addr_work->event = event;
67357153 dev_hold(dev);
....@@ -6749,14 +7167,21 @@
67497167
67507168 mlxsw_sp = mlxsw_sp_lower_get(dev);
67517169 if (!mlxsw_sp)
6752
- goto out;
7170
+ return NOTIFY_DONE;
67537171
7172
+ mutex_lock(&mlxsw_sp->router->lock);
67547173 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
67557174 if (!mlxsw_sp_rif_should_config(rif, dev, event))
67567175 goto out;
67577176
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);
67597183 out:
7184
+ mutex_unlock(&mlxsw_sp->router->lock);
67607185 return notifier_from_errno(err);
67617186 }
67627187
....@@ -6777,20 +7202,14 @@
67777202 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
67787203 }
67797204
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)
67817208 {
6782
- struct mlxsw_sp *mlxsw_sp;
6783
- struct mlxsw_sp_rif *rif;
7209
+ struct net_device *dev = rif->dev;
67847210 u16 fid_index;
67857211 int err;
67867212
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;
67947213 fid_index = mlxsw_sp_fid_index(rif->fid);
67957214
67967215 err = mlxsw_sp_rif_fdb_op(mlxsw_sp, rif->addr, fid_index, false);
....@@ -6834,6 +7253,47 @@
68347253 return err;
68357254 }
68367255
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
+
68377297 static int mlxsw_sp_port_vrf_join(struct mlxsw_sp *mlxsw_sp,
68387298 struct net_device *l3_dev,
68397299 struct netlink_ext_ack *extack)
....@@ -6845,9 +7305,10 @@
68457305 */
68467306 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev);
68477307 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);
68497310
6850
- return __mlxsw_sp_inetaddr_event(l3_dev, NETDEV_UP, extack);
7311
+ return __mlxsw_sp_inetaddr_event(mlxsw_sp, l3_dev, NETDEV_UP, extack);
68517312 }
68527313
68537314 static void mlxsw_sp_port_vrf_leave(struct mlxsw_sp *mlxsw_sp,
....@@ -6858,7 +7319,7 @@
68587319 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev);
68597320 if (!rif)
68607321 return;
6861
- __mlxsw_sp_inetaddr_event(l3_dev, NETDEV_DOWN, NULL);
7322
+ __mlxsw_sp_inetaddr_event(mlxsw_sp, l3_dev, NETDEV_DOWN, NULL);
68627323 }
68637324
68647325 int mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event,
....@@ -6873,9 +7334,10 @@
68737334 if (!mlxsw_sp || netif_is_macvlan(l3_dev))
68747335 return 0;
68757336
7337
+ mutex_lock(&mlxsw_sp->router->lock);
68767338 switch (event) {
68777339 case NETDEV_PRECHANGEUPPER:
6878
- return 0;
7340
+ break;
68797341 case NETDEV_CHANGEUPPER:
68807342 if (info->linking) {
68817343 struct netlink_ext_ack *extack;
....@@ -6887,13 +7349,15 @@
68877349 }
68887350 break;
68897351 }
7352
+ mutex_unlock(&mlxsw_sp->router->lock);
68907353
68917354 return err;
68927355 }
68937356
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)
68957359 {
6896
- struct mlxsw_sp_rif *rif = data;
7360
+ struct mlxsw_sp_rif *rif = (struct mlxsw_sp_rif *)priv->data;
68977361
68987362 if (!netif_is_macvlan(dev))
68997363 return 0;
....@@ -6904,18 +7368,16 @@
69047368
69057369 static int mlxsw_sp_rif_macvlan_flush(struct mlxsw_sp_rif *rif)
69067370 {
7371
+ struct netdev_nested_priv priv = {
7372
+ .data = (void *)rif,
7373
+ };
7374
+
69077375 if (!netif_is_macvlan_port(rif->dev))
69087376 return 0;
69097377
69107378 netdev_warn(rif->dev, "Router interface is deleted. Upper macvlans will not work\n");
69117379 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);
69197381 }
69207382
69217383 static void mlxsw_sp_rif_subport_setup(struct mlxsw_sp_rif *rif,
....@@ -6924,6 +7386,7 @@
69247386 struct mlxsw_sp_rif_subport *rif_subport;
69257387
69267388 rif_subport = mlxsw_sp_rif_subport_rif(rif);
7389
+ refcount_set(&rif_subport->ref_count, 1);
69277390 rif_subport->vid = params->vid;
69287391 rif_subport->lag = params->lag;
69297392 if (params->lag)
....@@ -7018,108 +7481,6 @@
70187481 return mlxsw_core_max_ports(mlxsw_sp->core) + 1;
70197482 }
70207483
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
-
71237484 static int mlxsw_sp_rif_fid_configure(struct mlxsw_sp_rif *rif)
71247485 {
71257486 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
....@@ -7195,7 +7556,8 @@
71957556
71967557 info.addr = mac;
71977558 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);
71997561 }
72007562
72017563 static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_fid_ops = {
....@@ -7205,6 +7567,57 @@
72057567 .deconfigure = mlxsw_sp_rif_fid_deconfigure,
72067568 .fid_get = mlxsw_sp_rif_fid_fid_get,
72077569 .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,
72087621 };
72097622
72107623 static struct mlxsw_sp_rif_ipip_lb *
....@@ -7227,7 +7640,7 @@
72277640 }
72287641
72297642 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)
72317644 {
72327645 struct mlxsw_sp_rif_ipip_lb *lb_rif = mlxsw_sp_rif_ipip_lb_rif(rif);
72337646 u32 ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(rif->dev);
....@@ -7239,11 +7652,12 @@
72397652 if (IS_ERR(ul_vr))
72407653 return PTR_ERR(ul_vr);
72417654
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);
72437656 if (err)
72447657 goto err_loopback_op;
72457658
72467659 lb_rif->ul_vr_id = ul_vr->id;
7660
+ lb_rif->ul_rif_id = 0;
72477661 ++ul_vr->rif_count;
72487662 return 0;
72497663
....@@ -7252,32 +7666,217 @@
72527666 return err;
72537667 }
72547668
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)
72567670 {
72577671 struct mlxsw_sp_rif_ipip_lb *lb_rif = mlxsw_sp_rif_ipip_lb_rif(rif);
72587672 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
72597673 struct mlxsw_sp_vr *ul_vr;
72607674
72617675 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);
72637677
72647678 --ul_vr->rif_count;
72657679 mlxsw_sp_vr_put(mlxsw_sp, ul_vr);
72667680 }
72677681
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 = {
72697683 .type = MLXSW_SP_RIF_TYPE_IPIP_LB,
72707684 .rif_size = sizeof(struct mlxsw_sp_rif_ipip_lb),
72717685 .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,
72747688 };
72757689
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[] = {
72777691 [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,
72797693 [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,
72817880 };
72827881
72837882 static int mlxsw_sp_rifs_init(struct mlxsw_sp *mlxsw_sp)
....@@ -7289,8 +7888,6 @@
72897888 GFP_KERNEL);
72907889 if (!mlxsw_sp->router->rifs)
72917890 return -ENOMEM;
7292
-
7293
- mlxsw_sp->router->rif_ops_arr = mlxsw_sp_rif_ops_arr;
72947891
72957892 return 0;
72967893 }
....@@ -7316,8 +7913,18 @@
73167913
73177914 static int mlxsw_sp_ipips_init(struct mlxsw_sp *mlxsw_sp)
73187915 {
7916
+ int err;
7917
+
73197918 mlxsw_sp->router->ipip_ops_arr = mlxsw_sp_ipip_ops_arr;
73207919 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
+
73217928 return mlxsw_sp_ipip_config_tigcr(mlxsw_sp);
73227929 }
73237930
....@@ -7350,9 +7957,10 @@
73507957 mlxsw_reg_recr2_outer_header_fields_enable_set(recr2_pl, field, true);
73517958 }
73527959
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)
73547961 {
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;
73567964
73577965 mlxsw_sp_mp_hash_header_set(recr2_pl,
73587966 MLXSW_REG_RECR2_IPV4_EN_NOT_TCP_NOT_UDP);
....@@ -7367,9 +7975,9 @@
73677975 mlxsw_sp_mp_hash_field_set(recr2_pl, MLXSW_REG_RECR2_TCP_UDP_DPORT);
73687976 }
73697977
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)
73717979 {
7372
- bool only_l3 = !ip6_multipath_hash_policy(&init_net);
7980
+ bool only_l3 = !ip6_multipath_hash_policy(mlxsw_sp_net(mlxsw_sp));
73737981
73747982 mlxsw_sp_mp_hash_header_set(recr2_pl,
73757983 MLXSW_REG_RECR2_IPV6_EN_NOT_TCP_NOT_UDP);
....@@ -7395,10 +8003,10 @@
73958003 char recr2_pl[MLXSW_REG_RECR2_LEN];
73968004 u32 seed;
73978005
7398
- get_random_bytes(&seed, sizeof(seed));
8006
+ seed = jhash(mlxsw_sp->base_mac, sizeof(mlxsw_sp->base_mac), 0);
73998007 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);
74028010
74038011 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(recr2), recr2_pl);
74048012 }
....@@ -7429,22 +8037,20 @@
74298037
74308038 static int __mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp)
74318039 {
7432
- bool usp = init_net.ipv4.sysctl_ip_fwd_update_priority;
8040
+ struct net *net = mlxsw_sp_net(mlxsw_sp);
74338041 char rgcr_pl[MLXSW_REG_RGCR_LEN];
74348042 u64 max_rifs;
7435
- int err;
8043
+ bool usp;
74368044
74378045 if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_RIFS))
74388046 return -EIO;
74398047 max_rifs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
8048
+ usp = READ_ONCE(net->ipv4.sysctl_ip_fwd_update_priority);
74408049
74418050 mlxsw_reg_rgcr_pack(rgcr_pl, true, true);
74428051 mlxsw_reg_rgcr_max_router_interfaces_set(rgcr_pl, max_rifs);
74438052 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);
74488054 }
74498055
74508056 static void __mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp)
....@@ -7455,7 +8061,8 @@
74558061 mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rgcr), rgcr_pl);
74568062 }
74578063
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)
74598066 {
74608067 struct mlxsw_sp_router *router;
74618068 int err;
....@@ -7463,6 +8070,7 @@
74638070 router = kzalloc(sizeof(*mlxsw_sp->router), GFP_KERNEL);
74648071 if (!router)
74658072 return -ENOMEM;
8073
+ mutex_init(&router->lock);
74668074 mlxsw_sp->router = router;
74678075 router->mlxsw_sp = mlxsw_sp;
74688076
....@@ -7506,12 +8114,6 @@
75068114 if (err)
75078115 goto err_neigh_init;
75088116
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
-
75158117 err = mlxsw_sp_mp_hash_init(mlxsw_sp);
75168118 if (err)
75178119 goto err_mp_hash_init;
....@@ -7520,19 +8122,41 @@
75208122 if (err)
75218123 goto err_dscp_init;
75228124
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
+
75238141 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);
75268145 if (err)
75278146 goto err_register_fib_notifier;
75288147
75298148 return 0;
75308149
75318150 err_register_fib_notifier:
7532
-err_dscp_init:
7533
-err_mp_hash_init:
75348151 unregister_netevent_notifier(&mlxsw_sp->router->netevent_nb);
75358152 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:
75368160 mlxsw_sp_neigh_fini(mlxsw_sp);
75378161 err_neigh_init:
75388162 mlxsw_sp_vrs_fini(mlxsw_sp);
....@@ -7551,14 +8175,19 @@
75518175 err_rifs_init:
75528176 __mlxsw_sp_router_fini(mlxsw_sp);
75538177 err_router_init:
8178
+ mutex_destroy(&mlxsw_sp->router->lock);
75548179 kfree(mlxsw_sp->router);
75558180 return err;
75568181 }
75578182
75588183 void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp)
75598184 {
7560
- unregister_fib_notifier(&mlxsw_sp->router->fib_nb);
8185
+ unregister_fib_notifier(mlxsw_sp_net(mlxsw_sp),
8186
+ &mlxsw_sp->router->fib_nb);
75618187 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();
75628191 mlxsw_sp_neigh_fini(mlxsw_sp);
75638192 mlxsw_sp_vrs_fini(mlxsw_sp);
75648193 mlxsw_sp_mr_fini(mlxsw_sp);
....@@ -7568,5 +8197,6 @@
75688197 mlxsw_sp_ipips_fini(mlxsw_sp);
75698198 mlxsw_sp_rifs_fini(mlxsw_sp);
75708199 __mlxsw_sp_router_fini(mlxsw_sp);
8200
+ mutex_destroy(&mlxsw_sp->router->lock);
75718201 kfree(mlxsw_sp->router);
75728202 }