aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2016-09-28 04:48:20 -0400
committerDavid S. Miller <davem@davemloft.net>2016-09-28 04:48:20 -0400
commit9c5982fe260a28e84d167e894123dc342e76c39f (patch)
treebdd2565cbf373e53c32a47ff30c11e4de0028ce7
parenteb523f42d77a43f80bb9c57a34fbdc8406c7b075 (diff)
parentfd41b0eaa06a8a0516f9e0b0a5889035bf423784 (diff)
Merge branch 'fib-offload-notifications'
Jiri Pirko says: ==================== fib offload: switch to notifier The goal of this patchset is to allow driver to propagate all prefixes configured in kernel down HW. This is necessary for routing to work as expected. If we don't do that HW might forward prefixes known to kernel incorrectly. Take an example when default route is set in switch HW and there is an IP address set on a management (non-switch) port. Currently, only FIB entries related to the switch port netdev are offloaded using switchdev ops. This model is not extendable so the first patch introduces a replacement: notifier to propagate FIB entry additions and removals to whoever is interested. The second patch introduces couple of helpers to deal with RTNH_F_OFFLOAD flags. Currently it is set in switchdev core. There the assumption is that only one offload device exists. But for FIB notifier, we assume multiple offload devices. So the patch introduces a per FIB entry reference counter and helpers use it in order to achieve this: 0 means RTNH_F_OFFLOAD is not set, no device offloads this entry n means RTNH_F_OFFLOAD is set and the entry is offloaded by n devices Patches 3 and 4 convert mlxsw and rocker to adopt this new way, registering one notifier block for each asic instance. Both of these patches also implement internal "abort" mechanism. Using switchdev ops, "abort" is called by switchdev core whenever there is an error during FIB entry add offload. This leads to removal of all offloaded entries on system by fib_trie code. Now the new notifier assumes the driver takes care of the abort action. Here's why: 1) The fact that one HW cannot offload an entry does not mean that the others can't do it. So let only one entity to abort and leave the rest to work happily. 2) The driver knows what to in order to properly abort. For example, currently abort is broken for mlxsw, as for Spectrum there is a need to set 0.0.0.0/0 trap in RALUE register. The fifth patch removes the old, no longer used FIB offload infrastructure. The last patch reflects the changes into switchdev documentation file. --- v2->v3: -patch 3/6 -fixed offload inc/dec to be done in fib4_entry_init/fini and only in case !trap as suggested by Ido v1->v2: -patch 3/6: -fixed lpm tree setup and binding for abort and pointed out by Ido -do nexthop checks as suggested by Ido -fix use after free during abort -patch 6/6: -fixed texts as suggested by Ido ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--Documentation/networking/switchdev.txt27
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum.h9
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c437
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c9
-rw-r--r--drivers/net/ethernet/rocker/rocker.h15
-rw-r--r--drivers/net/ethernet/rocker/rocker_main.c120
-rw-r--r--drivers/net/ethernet/rocker/rocker_ofdpa.c115
-rw-r--r--include/net/ip_fib.h49
-rw-r--r--include/net/switchdev.h40
-rw-r--r--net/ipv4/fib_frontend.c29
-rw-r--r--net/ipv4/fib_rules.c12
-rw-r--r--net/ipv4/fib_trie.c166
-rw-r--r--net/switchdev/switchdev.c181
13 files changed, 581 insertions, 628 deletions
diff --git a/Documentation/networking/switchdev.txt b/Documentation/networking/switchdev.txt
index 44235e83799b..2bbac05ab9e2 100644
--- a/Documentation/networking/switchdev.txt
+++ b/Documentation/networking/switchdev.txt
@@ -314,30 +314,29 @@ the kernel, with the device doing the FIB lookup and forwarding. The device
314does a longest prefix match (LPM) on FIB entries matching route prefix and 314does a longest prefix match (LPM) on FIB entries matching route prefix and
315forwards the packet to the matching FIB entry's nexthop(s) egress ports. 315forwards the packet to the matching FIB entry's nexthop(s) egress ports.
316 316
317To program the device, the driver implements support for 317To program the device, the driver has to register a FIB notifier handler
318SWITCHDEV_OBJ_IPV[4|6]_FIB object using switchdev_port_obj_xxx ops. 318using register_fib_notifier. The following events are available:
319switchdev_port_obj_add is used for both adding a new FIB entry to the device, 319FIB_EVENT_ENTRY_ADD: used for both adding a new FIB entry to the device,
320or modifying an existing entry on the device. 320 or modifying an existing entry on the device.
321FIB_EVENT_ENTRY_DEL: used for removing a FIB entry
322FIB_EVENT_RULE_ADD, FIB_EVENT_RULE_DEL: used to propagate FIB rule changes
321 323
322XXX: Currently, only SWITCHDEV_OBJ_ID_IPV4_FIB objects are supported. 324FIB_EVENT_ENTRY_ADD and FIB_EVENT_ENTRY_DEL events pass:
323 325
324SWITCHDEV_OBJ_ID_IPV4_FIB object passes: 326 struct fib_entry_notifier_info {
325 327 struct fib_notifier_info info; /* must be first */
326 struct switchdev_obj_ipv4_fib { /* IPV4_FIB */
327 u32 dst; 328 u32 dst;
328 int dst_len; 329 int dst_len;
329 struct fib_info *fi; 330 struct fib_info *fi;
330 u8 tos; 331 u8 tos;
331 u8 type; 332 u8 type;
332 u32 nlflags;
333 u32 tb_id; 333 u32 tb_id;
334 } ipv4_fib; 334 u32 nlflags;
335 };
335 336
336to add/modify/delete IPv4 dst/dest_len prefix on table tb_id. The *fi 337to add/modify/delete IPv4 dst/dest_len prefix on table tb_id. The *fi
337structure holds details on the route and route's nexthops. *dev is one of the 338structure holds details on the route and route's nexthops. *dev is one of the
338port netdevs mentioned in the routes next hop list. If the output port netdevs 339port netdevs mentioned in the route's next hop list.
339referenced in the route's nexthop list don't all have the same switch ID, the
340driver is not called to add/modify/delete the FIB entry.
341 340
342Routes offloaded to the device are labeled with "offload" in the ip route 341Routes offloaded to the device are labeled with "offload" in the ip route
343listing: 342listing:
@@ -355,6 +354,8 @@ listing:
355 12.0.0.4 via 11.0.0.9 dev sw1p2 proto zebra metric 20 offload 354 12.0.0.4 via 11.0.0.9 dev sw1p2 proto zebra metric 20 offload
356 192.168.0.0/24 dev eth0 proto kernel scope link src 192.168.0.15 355 192.168.0.0/24 dev eth0 proto kernel scope link src 192.168.0.15
357 356
357The "offload" flag is set in case at least one device offloads the FIB entry.
358
358XXX: add/mod/del IPv6 FIB API 359XXX: add/mod/del IPv6 FIB API
359 360
360Nexthop Resolution 361Nexthop Resolution
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
index 73cae211a5ce..9b22863a924b 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
@@ -45,7 +45,7 @@
45#include <linux/list.h> 45#include <linux/list.h>
46#include <linux/dcbnl.h> 46#include <linux/dcbnl.h>
47#include <linux/in6.h> 47#include <linux/in6.h>
48#include <net/switchdev.h> 48#include <linux/notifier.h>
49 49
50#include "port.h" 50#include "port.h"
51#include "core.h" 51#include "core.h"
@@ -257,6 +257,7 @@ struct mlxsw_sp_router {
257#define MLXSW_SP_UNRESOLVED_NH_PROBE_INTERVAL 5000 /* ms */ 257#define MLXSW_SP_UNRESOLVED_NH_PROBE_INTERVAL 5000 /* ms */
258 struct list_head nexthop_group_list; 258 struct list_head nexthop_group_list;
259 struct list_head nexthop_neighs_list; 259 struct list_head nexthop_neighs_list;
260 bool aborted;
260}; 261};
261 262
262struct mlxsw_sp { 263struct mlxsw_sp {
@@ -296,6 +297,7 @@ struct mlxsw_sp {
296 struct mlxsw_sp_span_entry *entries; 297 struct mlxsw_sp_span_entry *entries;
297 int entries_count; 298 int entries_count;
298 } span; 299 } span;
300 struct notifier_block fib_nb;
299}; 301};
300 302
301static inline struct mlxsw_sp_upper * 303static inline struct mlxsw_sp_upper *
@@ -584,11 +586,6 @@ static inline void mlxsw_sp_port_dcb_fini(struct mlxsw_sp_port *mlxsw_sp_port)
584 586
585int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp); 587int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp);
586void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp); 588void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp);
587int mlxsw_sp_router_fib4_add(struct mlxsw_sp_port *mlxsw_sp_port,
588 const struct switchdev_obj_ipv4_fib *fib4,
589 struct switchdev_trans *trans);
590int mlxsw_sp_router_fib4_del(struct mlxsw_sp_port *mlxsw_sp_port,
591 const struct switchdev_obj_ipv4_fib *fib4);
592int mlxsw_sp_router_neigh_construct(struct net_device *dev, 589int mlxsw_sp_router_neigh_construct(struct net_device *dev,
593 struct neighbour *n); 590 struct neighbour *n);
594void mlxsw_sp_router_neigh_destroy(struct net_device *dev, 591void mlxsw_sp_router_neigh_destroy(struct net_device *dev,
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
index cc653ac2d7d6..48d50efec5e2 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
@@ -43,6 +43,7 @@
43#include <net/netevent.h> 43#include <net/netevent.h>
44#include <net/neighbour.h> 44#include <net/neighbour.h>
45#include <net/arp.h> 45#include <net/arp.h>
46#include <net/ip_fib.h>
46 47
47#include "spectrum.h" 48#include "spectrum.h"
48#include "core.h" 49#include "core.h"
@@ -122,17 +123,20 @@ struct mlxsw_sp_nexthop_group;
122 123
123struct mlxsw_sp_fib_entry { 124struct mlxsw_sp_fib_entry {
124 struct rhash_head ht_node; 125 struct rhash_head ht_node;
126 struct list_head list;
125 struct mlxsw_sp_fib_key key; 127 struct mlxsw_sp_fib_key key;
126 enum mlxsw_sp_fib_entry_type type; 128 enum mlxsw_sp_fib_entry_type type;
127 unsigned int ref_count; 129 unsigned int ref_count;
128 u16 rif; /* used for action local */ 130 u16 rif; /* used for action local */
129 struct mlxsw_sp_vr *vr; 131 struct mlxsw_sp_vr *vr;
132 struct fib_info *fi;
130 struct list_head nexthop_group_node; 133 struct list_head nexthop_group_node;
131 struct mlxsw_sp_nexthop_group *nh_group; 134 struct mlxsw_sp_nexthop_group *nh_group;
132}; 135};
133 136
134struct mlxsw_sp_fib { 137struct mlxsw_sp_fib {
135 struct rhashtable ht; 138 struct rhashtable ht;
139 struct list_head entry_list;
136 unsigned long prefix_ref_count[MLXSW_SP_PREFIX_COUNT]; 140 unsigned long prefix_ref_count[MLXSW_SP_PREFIX_COUNT];
137 struct mlxsw_sp_prefix_usage prefix_usage; 141 struct mlxsw_sp_prefix_usage prefix_usage;
138}; 142};
@@ -154,6 +158,7 @@ static int mlxsw_sp_fib_entry_insert(struct mlxsw_sp_fib *fib,
154 mlxsw_sp_fib_ht_params); 158 mlxsw_sp_fib_ht_params);
155 if (err) 159 if (err)
156 return err; 160 return err;
161 list_add_tail(&fib_entry->list, &fib->entry_list);
157 if (fib->prefix_ref_count[prefix_len]++ == 0) 162 if (fib->prefix_ref_count[prefix_len]++ == 0)
158 mlxsw_sp_prefix_usage_set(&fib->prefix_usage, prefix_len); 163 mlxsw_sp_prefix_usage_set(&fib->prefix_usage, prefix_len);
159 return 0; 164 return 0;
@@ -166,6 +171,7 @@ static void mlxsw_sp_fib_entry_remove(struct mlxsw_sp_fib *fib,
166 171
167 if (--fib->prefix_ref_count[prefix_len] == 0) 172 if (--fib->prefix_ref_count[prefix_len] == 0)
168 mlxsw_sp_prefix_usage_clear(&fib->prefix_usage, prefix_len); 173 mlxsw_sp_prefix_usage_clear(&fib->prefix_usage, prefix_len);
174 list_del(&fib_entry->list);
169 rhashtable_remove_fast(&fib->ht, &fib_entry->ht_node, 175 rhashtable_remove_fast(&fib->ht, &fib_entry->ht_node,
170 mlxsw_sp_fib_ht_params); 176 mlxsw_sp_fib_ht_params);
171} 177}
@@ -216,6 +222,7 @@ static struct mlxsw_sp_fib *mlxsw_sp_fib_create(void)
216 err = rhashtable_init(&fib->ht, &mlxsw_sp_fib_ht_params); 222 err = rhashtable_init(&fib->ht, &mlxsw_sp_fib_ht_params);
217 if (err) 223 if (err)
218 goto err_rhashtable_init; 224 goto err_rhashtable_init;
225 INIT_LIST_HEAD(&fib->entry_list);
219 return fib; 226 return fib;
220 227
221err_rhashtable_init: 228err_rhashtable_init:
@@ -1520,85 +1527,6 @@ static void mlxsw_sp_nexthop_group_put(struct mlxsw_sp *mlxsw_sp,
1520 mlxsw_sp_nexthop_group_destroy(mlxsw_sp, nh_grp); 1527 mlxsw_sp_nexthop_group_destroy(mlxsw_sp, nh_grp);
1521} 1528}
1522 1529
1523static int __mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp)
1524{
1525 struct mlxsw_resources *resources;
1526 char rgcr_pl[MLXSW_REG_RGCR_LEN];
1527 int err;
1528
1529 resources = mlxsw_core_resources_get(mlxsw_sp->core);
1530 if (!resources->max_rif_valid)
1531 return -EIO;
1532
1533 mlxsw_sp->rifs = kcalloc(resources->max_rif,
1534 sizeof(struct mlxsw_sp_rif *), GFP_KERNEL);
1535 if (!mlxsw_sp->rifs)
1536 return -ENOMEM;
1537
1538 mlxsw_reg_rgcr_pack(rgcr_pl, true);
1539 mlxsw_reg_rgcr_max_router_interfaces_set(rgcr_pl, resources->max_rif);
1540 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rgcr), rgcr_pl);
1541 if (err)
1542 goto err_rgcr_fail;
1543
1544 return 0;
1545
1546err_rgcr_fail:
1547 kfree(mlxsw_sp->rifs);
1548 return err;
1549}
1550
1551static void __mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp)
1552{
1553 struct mlxsw_resources *resources;
1554 char rgcr_pl[MLXSW_REG_RGCR_LEN];
1555 int i;
1556
1557 mlxsw_reg_rgcr_pack(rgcr_pl, false);
1558 mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rgcr), rgcr_pl);
1559
1560 resources = mlxsw_core_resources_get(mlxsw_sp->core);
1561 for (i = 0; i < resources->max_rif; i++)
1562 WARN_ON_ONCE(mlxsw_sp->rifs[i]);
1563
1564 kfree(mlxsw_sp->rifs);
1565}
1566
1567int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp)
1568{
1569 int err;
1570
1571 INIT_LIST_HEAD(&mlxsw_sp->router.nexthop_neighs_list);
1572 INIT_LIST_HEAD(&mlxsw_sp->router.nexthop_group_list);
1573 err = __mlxsw_sp_router_init(mlxsw_sp);
1574 if (err)
1575 return err;
1576
1577 mlxsw_sp_lpm_init(mlxsw_sp);
1578 err = mlxsw_sp_vrs_init(mlxsw_sp);
1579 if (err)
1580 goto err_vrs_init;
1581
1582 err = mlxsw_sp_neigh_init(mlxsw_sp);
1583 if (err)
1584 goto err_neigh_init;
1585
1586 return 0;
1587
1588err_neigh_init:
1589 mlxsw_sp_vrs_fini(mlxsw_sp);
1590err_vrs_init:
1591 __mlxsw_sp_router_fini(mlxsw_sp);
1592 return err;
1593}
1594
1595void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp)
1596{
1597 mlxsw_sp_neigh_fini(mlxsw_sp);
1598 mlxsw_sp_vrs_fini(mlxsw_sp);
1599 __mlxsw_sp_router_fini(mlxsw_sp);
1600}
1601
1602static int mlxsw_sp_fib_entry_op4_remote(struct mlxsw_sp *mlxsw_sp, 1530static int mlxsw_sp_fib_entry_op4_remote(struct mlxsw_sp *mlxsw_sp,
1603 struct mlxsw_sp_fib_entry *fib_entry, 1531 struct mlxsw_sp_fib_entry *fib_entry,
1604 enum mlxsw_reg_ralue_op op) 1532 enum mlxsw_reg_ralue_op op)
@@ -1706,94 +1634,98 @@ static int mlxsw_sp_fib_entry_del(struct mlxsw_sp *mlxsw_sp,
1706 MLXSW_REG_RALUE_OP_WRITE_DELETE); 1634 MLXSW_REG_RALUE_OP_WRITE_DELETE);
1707} 1635}
1708 1636
1709struct mlxsw_sp_router_fib4_add_info {
1710 struct switchdev_trans_item tritem;
1711 struct mlxsw_sp *mlxsw_sp;
1712 struct mlxsw_sp_fib_entry *fib_entry;
1713};
1714
1715static void mlxsw_sp_router_fib4_add_info_destroy(void const *data)
1716{
1717 const struct mlxsw_sp_router_fib4_add_info *info = data;
1718 struct mlxsw_sp_fib_entry *fib_entry = info->fib_entry;
1719 struct mlxsw_sp *mlxsw_sp = info->mlxsw_sp;
1720 struct mlxsw_sp_vr *vr = fib_entry->vr;
1721
1722 mlxsw_sp_fib_entry_destroy(fib_entry);
1723 mlxsw_sp_vr_put(mlxsw_sp, vr);
1724 kfree(info);
1725}
1726
1727static int 1637static int
1728mlxsw_sp_router_fib4_entry_init(struct mlxsw_sp *mlxsw_sp, 1638mlxsw_sp_router_fib4_entry_init(struct mlxsw_sp *mlxsw_sp,
1729 const struct switchdev_obj_ipv4_fib *fib4, 1639 const struct fib_entry_notifier_info *fen_info,
1730 struct mlxsw_sp_fib_entry *fib_entry) 1640 struct mlxsw_sp_fib_entry *fib_entry)
1731{ 1641{
1732 struct fib_info *fi = fib4->fi; 1642 struct fib_info *fi = fen_info->fi;
1643 struct mlxsw_sp_rif *r;
1644 int nhsel;
1645 int err;
1733 1646
1734 if (fib4->type == RTN_LOCAL || fib4->type == RTN_BROADCAST) { 1647 if (fen_info->type == RTN_LOCAL || fen_info->type == RTN_BROADCAST) {
1735 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP; 1648 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP;
1736 return 0; 1649 return 0;
1737 } 1650 }
1738 if (fib4->type != RTN_UNICAST) 1651 if (fen_info->type != RTN_UNICAST)
1739 return -EINVAL; 1652 return -EINVAL;
1740 1653
1741 if (fi->fib_scope != RT_SCOPE_UNIVERSE) { 1654 for (nhsel = 0; nhsel < fi->fib_nhs; nhsel++) {
1742 struct mlxsw_sp_rif *r; 1655 const struct fib_nh *nh = &fi->fib_nh[nhsel];
1656
1657 if (!nh->nh_dev)
1658 continue;
1659 r = mlxsw_sp_rif_find_by_dev(mlxsw_sp, nh->nh_dev);
1660 if (!r) {
1661 /* In case router interface is not found for
1662 * at least one of the nexthops, that means
1663 * the nexthop points to some device unrelated
1664 * to us. Set trap and pass the packets for
1665 * this prefix to kernel.
1666 */
1667 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP;
1668 return 0;
1669 }
1670 }
1743 1671
1672 if (fi->fib_scope != RT_SCOPE_UNIVERSE) {
1744 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_LOCAL; 1673 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_LOCAL;
1745 r = mlxsw_sp_rif_find_by_dev(mlxsw_sp, fi->fib_dev);
1746 if (!r)
1747 return -EINVAL;
1748 fib_entry->rif = r->rif; 1674 fib_entry->rif = r->rif;
1749 return 0; 1675 } else {
1676 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_REMOTE;
1677 err = mlxsw_sp_nexthop_group_get(mlxsw_sp, fib_entry, fi);
1678 if (err)
1679 return err;
1750 } 1680 }
1751 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_REMOTE; 1681 fib_info_offload_inc(fen_info->fi);
1752 return mlxsw_sp_nexthop_group_get(mlxsw_sp, fib_entry, fi); 1682 return 0;
1753} 1683}
1754 1684
1755static void 1685static void
1756mlxsw_sp_router_fib4_entry_fini(struct mlxsw_sp *mlxsw_sp, 1686mlxsw_sp_router_fib4_entry_fini(struct mlxsw_sp *mlxsw_sp,
1757 struct mlxsw_sp_fib_entry *fib_entry) 1687 struct mlxsw_sp_fib_entry *fib_entry)
1758{ 1688{
1759 if (fib_entry->type != MLXSW_SP_FIB_ENTRY_TYPE_REMOTE) 1689 if (fib_entry->type != MLXSW_SP_FIB_ENTRY_TYPE_TRAP)
1760 return; 1690 fib_info_offload_dec(fib_entry->fi);
1761 mlxsw_sp_nexthop_group_put(mlxsw_sp, fib_entry); 1691 if (fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_REMOTE)
1692 mlxsw_sp_nexthop_group_put(mlxsw_sp, fib_entry);
1762} 1693}
1763 1694
1764static struct mlxsw_sp_fib_entry * 1695static struct mlxsw_sp_fib_entry *
1765mlxsw_sp_fib_entry_get(struct mlxsw_sp *mlxsw_sp, 1696mlxsw_sp_fib_entry_get(struct mlxsw_sp *mlxsw_sp,
1766 const struct switchdev_obj_ipv4_fib *fib4) 1697 const struct fib_entry_notifier_info *fen_info)
1767{ 1698{
1768 struct mlxsw_sp_fib_entry *fib_entry; 1699 struct mlxsw_sp_fib_entry *fib_entry;
1769 struct fib_info *fi = fib4->fi; 1700 struct fib_info *fi = fen_info->fi;
1770 struct mlxsw_sp_vr *vr; 1701 struct mlxsw_sp_vr *vr;
1771 int err; 1702 int err;
1772 1703
1773 vr = mlxsw_sp_vr_get(mlxsw_sp, fib4->dst_len, fib4->tb_id, 1704 vr = mlxsw_sp_vr_get(mlxsw_sp, fen_info->dst_len, fen_info->tb_id,
1774 MLXSW_SP_L3_PROTO_IPV4); 1705 MLXSW_SP_L3_PROTO_IPV4);
1775 if (IS_ERR(vr)) 1706 if (IS_ERR(vr))
1776 return ERR_CAST(vr); 1707 return ERR_CAST(vr);
1777 1708
1778 fib_entry = mlxsw_sp_fib_entry_lookup(vr->fib, &fib4->dst, 1709 fib_entry = mlxsw_sp_fib_entry_lookup(vr->fib, &fen_info->dst,
1779 sizeof(fib4->dst), 1710 sizeof(fen_info->dst),
1780 fib4->dst_len, fi->fib_dev); 1711 fen_info->dst_len, fi->fib_dev);
1781 if (fib_entry) { 1712 if (fib_entry) {
1782 /* Already exists, just take a reference */ 1713 /* Already exists, just take a reference */
1783 fib_entry->ref_count++; 1714 fib_entry->ref_count++;
1784 return fib_entry; 1715 return fib_entry;
1785 } 1716 }
1786 fib_entry = mlxsw_sp_fib_entry_create(vr->fib, &fib4->dst, 1717 fib_entry = mlxsw_sp_fib_entry_create(vr->fib, &fen_info->dst,
1787 sizeof(fib4->dst), 1718 sizeof(fen_info->dst),
1788 fib4->dst_len, fi->fib_dev); 1719 fen_info->dst_len, fi->fib_dev);
1789 if (!fib_entry) { 1720 if (!fib_entry) {
1790 err = -ENOMEM; 1721 err = -ENOMEM;
1791 goto err_fib_entry_create; 1722 goto err_fib_entry_create;
1792 } 1723 }
1793 fib_entry->vr = vr; 1724 fib_entry->vr = vr;
1725 fib_entry->fi = fi;
1794 fib_entry->ref_count = 1; 1726 fib_entry->ref_count = 1;
1795 1727
1796 err = mlxsw_sp_router_fib4_entry_init(mlxsw_sp, fib4, fib_entry); 1728 err = mlxsw_sp_router_fib4_entry_init(mlxsw_sp, fen_info, fib_entry);
1797 if (err) 1729 if (err)
1798 goto err_fib4_entry_init; 1730 goto err_fib4_entry_init;
1799 1731
@@ -1809,17 +1741,19 @@ err_fib_entry_create:
1809 1741
1810static struct mlxsw_sp_fib_entry * 1742static struct mlxsw_sp_fib_entry *
1811mlxsw_sp_fib_entry_find(struct mlxsw_sp *mlxsw_sp, 1743mlxsw_sp_fib_entry_find(struct mlxsw_sp *mlxsw_sp,
1812 const struct switchdev_obj_ipv4_fib *fib4) 1744 const struct fib_entry_notifier_info *fen_info)
1813{ 1745{
1814 struct mlxsw_sp_vr *vr; 1746 struct mlxsw_sp_vr *vr;
1815 1747
1816 vr = mlxsw_sp_vr_find(mlxsw_sp, fib4->tb_id, MLXSW_SP_L3_PROTO_IPV4); 1748 vr = mlxsw_sp_vr_find(mlxsw_sp, fen_info->tb_id,
1749 MLXSW_SP_L3_PROTO_IPV4);
1817 if (!vr) 1750 if (!vr)
1818 return NULL; 1751 return NULL;
1819 1752
1820 return mlxsw_sp_fib_entry_lookup(vr->fib, &fib4->dst, 1753 return mlxsw_sp_fib_entry_lookup(vr->fib, &fen_info->dst,
1821 sizeof(fib4->dst), fib4->dst_len, 1754 sizeof(fen_info->dst),
1822 fib4->fi->fib_dev); 1755 fen_info->dst_len,
1756 fen_info->fi->fib_dev);
1823} 1757}
1824 1758
1825static void mlxsw_sp_fib_entry_put(struct mlxsw_sp *mlxsw_sp, 1759static void mlxsw_sp_fib_entry_put(struct mlxsw_sp *mlxsw_sp,
@@ -1834,60 +1768,43 @@ static void mlxsw_sp_fib_entry_put(struct mlxsw_sp *mlxsw_sp,
1834 mlxsw_sp_vr_put(mlxsw_sp, vr); 1768 mlxsw_sp_vr_put(mlxsw_sp, vr);
1835} 1769}
1836 1770
1837static int 1771static void mlxsw_sp_fib_entry_put_all(struct mlxsw_sp *mlxsw_sp,
1838mlxsw_sp_router_fib4_add_prepare(struct mlxsw_sp_port *mlxsw_sp_port, 1772 struct mlxsw_sp_fib_entry *fib_entry)
1839 const struct switchdev_obj_ipv4_fib *fib4,
1840 struct switchdev_trans *trans)
1841{ 1773{
1842 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 1774 unsigned int last_ref_count;
1843 struct mlxsw_sp_router_fib4_add_info *info;
1844 struct mlxsw_sp_fib_entry *fib_entry;
1845 int err;
1846
1847 fib_entry = mlxsw_sp_fib_entry_get(mlxsw_sp, fib4);
1848 if (IS_ERR(fib_entry))
1849 return PTR_ERR(fib_entry);
1850 1775
1851 info = kmalloc(sizeof(*info), GFP_KERNEL); 1776 do {
1852 if (!info) { 1777 last_ref_count = fib_entry->ref_count;
1853 err = -ENOMEM; 1778 mlxsw_sp_fib_entry_put(mlxsw_sp, fib_entry);
1854 goto err_alloc_info; 1779 } while (last_ref_count != 1);
1855 }
1856 info->mlxsw_sp = mlxsw_sp;
1857 info->fib_entry = fib_entry;
1858 switchdev_trans_item_enqueue(trans, info,
1859 mlxsw_sp_router_fib4_add_info_destroy,
1860 &info->tritem);
1861 return 0;
1862
1863err_alloc_info:
1864 mlxsw_sp_fib_entry_put(mlxsw_sp, fib_entry);
1865 return err;
1866} 1780}
1867 1781
1868static int 1782static int mlxsw_sp_router_fib4_add(struct mlxsw_sp *mlxsw_sp,
1869mlxsw_sp_router_fib4_add_commit(struct mlxsw_sp_port *mlxsw_sp_port, 1783 struct fib_entry_notifier_info *fen_info)
1870 const struct switchdev_obj_ipv4_fib *fib4,
1871 struct switchdev_trans *trans)
1872{ 1784{
1873 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1874 struct mlxsw_sp_router_fib4_add_info *info;
1875 struct mlxsw_sp_fib_entry *fib_entry; 1785 struct mlxsw_sp_fib_entry *fib_entry;
1876 struct mlxsw_sp_vr *vr; 1786 struct mlxsw_sp_vr *vr;
1877 int err; 1787 int err;
1878 1788
1879 info = switchdev_trans_item_dequeue(trans); 1789 if (mlxsw_sp->router.aborted)
1880 fib_entry = info->fib_entry; 1790 return 0;
1881 kfree(info); 1791
1792 fib_entry = mlxsw_sp_fib_entry_get(mlxsw_sp, fen_info);
1793 if (IS_ERR(fib_entry)) {
1794 dev_warn(mlxsw_sp->bus_info->dev, "Failed to get FIB4 entry being added.\n");
1795 return PTR_ERR(fib_entry);
1796 }
1882 1797
1883 if (fib_entry->ref_count != 1) 1798 if (fib_entry->ref_count != 1)
1884 return 0; 1799 return 0;
1885 1800
1886 vr = fib_entry->vr; 1801 vr = fib_entry->vr;
1887 err = mlxsw_sp_fib_entry_insert(vr->fib, fib_entry); 1802 err = mlxsw_sp_fib_entry_insert(vr->fib, fib_entry);
1888 if (err) 1803 if (err) {
1804 dev_warn(mlxsw_sp->bus_info->dev, "Failed to insert FIB4 entry being added.\n");
1889 goto err_fib_entry_insert; 1805 goto err_fib_entry_insert;
1890 err = mlxsw_sp_fib_entry_update(mlxsw_sp_port->mlxsw_sp, fib_entry); 1806 }
1807 err = mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry);
1891 if (err) 1808 if (err)
1892 goto err_fib_entry_add; 1809 goto err_fib_entry_add;
1893 return 0; 1810 return 0;
@@ -1899,24 +1816,15 @@ err_fib_entry_insert:
1899 return err; 1816 return err;
1900} 1817}
1901 1818
1902int mlxsw_sp_router_fib4_add(struct mlxsw_sp_port *mlxsw_sp_port, 1819static int mlxsw_sp_router_fib4_del(struct mlxsw_sp *mlxsw_sp,
1903 const struct switchdev_obj_ipv4_fib *fib4, 1820 struct fib_entry_notifier_info *fen_info)
1904 struct switchdev_trans *trans)
1905{
1906 if (switchdev_trans_ph_prepare(trans))
1907 return mlxsw_sp_router_fib4_add_prepare(mlxsw_sp_port,
1908 fib4, trans);
1909 return mlxsw_sp_router_fib4_add_commit(mlxsw_sp_port,
1910 fib4, trans);
1911}
1912
1913int mlxsw_sp_router_fib4_del(struct mlxsw_sp_port *mlxsw_sp_port,
1914 const struct switchdev_obj_ipv4_fib *fib4)
1915{ 1821{
1916 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1917 struct mlxsw_sp_fib_entry *fib_entry; 1822 struct mlxsw_sp_fib_entry *fib_entry;
1918 1823
1919 fib_entry = mlxsw_sp_fib_entry_find(mlxsw_sp, fib4); 1824 if (mlxsw_sp->router.aborted)
1825 return 0;
1826
1827 fib_entry = mlxsw_sp_fib_entry_find(mlxsw_sp, fen_info);
1920 if (!fib_entry) { 1828 if (!fib_entry) {
1921 dev_warn(mlxsw_sp->bus_info->dev, "Failed to find FIB4 entry being removed.\n"); 1829 dev_warn(mlxsw_sp->bus_info->dev, "Failed to find FIB4 entry being removed.\n");
1922 return -ENOENT; 1830 return -ENOENT;
@@ -1930,3 +1838,172 @@ int mlxsw_sp_router_fib4_del(struct mlxsw_sp_port *mlxsw_sp_port,
1930 mlxsw_sp_fib_entry_put(mlxsw_sp, fib_entry); 1838 mlxsw_sp_fib_entry_put(mlxsw_sp, fib_entry);
1931 return 0; 1839 return 0;
1932} 1840}
1841
1842static int mlxsw_sp_router_set_abort_trap(struct mlxsw_sp *mlxsw_sp)
1843{
1844 char ralta_pl[MLXSW_REG_RALTA_LEN];
1845 char ralst_pl[MLXSW_REG_RALST_LEN];
1846 char raltb_pl[MLXSW_REG_RALTB_LEN];
1847 char ralue_pl[MLXSW_REG_RALUE_LEN];
1848 int err;
1849
1850 mlxsw_reg_ralta_pack(ralta_pl, true, MLXSW_REG_RALXX_PROTOCOL_IPV4,
1851 MLXSW_SP_LPM_TREE_MIN);
1852 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralta), ralta_pl);
1853 if (err)
1854 return err;
1855
1856 mlxsw_reg_ralst_pack(ralst_pl, 0xff, MLXSW_SP_LPM_TREE_MIN);
1857 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralst), ralst_pl);
1858 if (err)
1859 return err;
1860
1861 mlxsw_reg_raltb_pack(raltb_pl, 0, MLXSW_REG_RALXX_PROTOCOL_IPV4, 0);
1862 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(raltb), raltb_pl);
1863 if (err)
1864 return err;
1865
1866 mlxsw_reg_ralue_pack4(ralue_pl, MLXSW_SP_L3_PROTO_IPV4,
1867 MLXSW_REG_RALUE_OP_WRITE_WRITE, 0, 0, 0);
1868 mlxsw_reg_ralue_act_ip2me_pack(ralue_pl);
1869 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl);
1870}
1871
1872static void mlxsw_sp_router_fib4_abort(struct mlxsw_sp *mlxsw_sp)
1873{
1874 struct mlxsw_resources *resources;
1875 struct mlxsw_sp_fib_entry *fib_entry;
1876 struct mlxsw_sp_fib_entry *tmp;
1877 struct mlxsw_sp_vr *vr;
1878 int i;
1879 int err;
1880
1881 resources = mlxsw_core_resources_get(mlxsw_sp->core);
1882 for (i = 0; i < resources->max_virtual_routers; i++) {
1883 vr = &mlxsw_sp->router.vrs[i];
1884 if (!vr->used)
1885 continue;
1886
1887 list_for_each_entry_safe(fib_entry, tmp,
1888 &vr->fib->entry_list, list) {
1889 bool do_break = &tmp->list == &vr->fib->entry_list;
1890
1891 mlxsw_sp_fib_entry_del(mlxsw_sp, fib_entry);
1892 mlxsw_sp_fib_entry_remove(fib_entry->vr->fib,
1893 fib_entry);
1894 mlxsw_sp_fib_entry_put_all(mlxsw_sp, fib_entry);
1895 if (do_break)
1896 break;
1897 }
1898 }
1899 mlxsw_sp->router.aborted = true;
1900 err = mlxsw_sp_router_set_abort_trap(mlxsw_sp);
1901 if (err)
1902 dev_warn(mlxsw_sp->bus_info->dev, "Failed to set abort trap.\n");
1903}
1904
1905static int __mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp)
1906{
1907 struct mlxsw_resources *resources;
1908 char rgcr_pl[MLXSW_REG_RGCR_LEN];
1909 int err;
1910
1911 resources = mlxsw_core_resources_get(mlxsw_sp->core);
1912 if (!resources->max_rif_valid)
1913 return -EIO;
1914
1915 mlxsw_sp->rifs = kcalloc(resources->max_rif,
1916 sizeof(struct mlxsw_sp_rif *), GFP_KERNEL);
1917 if (!mlxsw_sp->rifs)
1918 return -ENOMEM;
1919
1920 mlxsw_reg_rgcr_pack(rgcr_pl, true);
1921 mlxsw_reg_rgcr_max_router_interfaces_set(rgcr_pl, resources->max_rif);
1922 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rgcr), rgcr_pl);
1923 if (err)
1924 goto err_rgcr_fail;
1925
1926 return 0;
1927
1928err_rgcr_fail:
1929 kfree(mlxsw_sp->rifs);
1930 return err;
1931}
1932
1933static void __mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp)
1934{
1935 struct mlxsw_resources *resources;
1936 char rgcr_pl[MLXSW_REG_RGCR_LEN];
1937 int i;
1938
1939 mlxsw_reg_rgcr_pack(rgcr_pl, false);
1940 mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rgcr), rgcr_pl);
1941
1942 resources = mlxsw_core_resources_get(mlxsw_sp->core);
1943 for (i = 0; i < resources->max_rif; i++)
1944 WARN_ON_ONCE(mlxsw_sp->rifs[i]);
1945
1946 kfree(mlxsw_sp->rifs);
1947}
1948
1949static int mlxsw_sp_router_fib_event(struct notifier_block *nb,
1950 unsigned long event, void *ptr)
1951{
1952 struct mlxsw_sp *mlxsw_sp = container_of(nb, struct mlxsw_sp, fib_nb);
1953 struct fib_entry_notifier_info *fen_info = ptr;
1954 int err;
1955
1956 switch (event) {
1957 case FIB_EVENT_ENTRY_ADD:
1958 err = mlxsw_sp_router_fib4_add(mlxsw_sp, fen_info);
1959 if (err)
1960 mlxsw_sp_router_fib4_abort(mlxsw_sp);
1961 break;
1962 case FIB_EVENT_ENTRY_DEL:
1963 mlxsw_sp_router_fib4_del(mlxsw_sp, fen_info);
1964 break;
1965 case FIB_EVENT_RULE_ADD: /* fall through */
1966 case FIB_EVENT_RULE_DEL:
1967 mlxsw_sp_router_fib4_abort(mlxsw_sp);
1968 break;
1969 }
1970 return NOTIFY_DONE;
1971}
1972
1973int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp)
1974{
1975 int err;
1976
1977 INIT_LIST_HEAD(&mlxsw_sp->router.nexthop_neighs_list);
1978 INIT_LIST_HEAD(&mlxsw_sp->router.nexthop_group_list);
1979 err = __mlxsw_sp_router_init(mlxsw_sp);
1980 if (err)
1981 return err;
1982
1983 mlxsw_sp_lpm_init(mlxsw_sp);
1984 err = mlxsw_sp_vrs_init(mlxsw_sp);
1985 if (err)
1986 goto err_vrs_init;
1987
1988 err = mlxsw_sp_neigh_init(mlxsw_sp);
1989 if (err)
1990 goto err_neigh_init;
1991
1992 mlxsw_sp->fib_nb.notifier_call = mlxsw_sp_router_fib_event;
1993 register_fib_notifier(&mlxsw_sp->fib_nb);
1994 return 0;
1995
1996err_neigh_init:
1997 mlxsw_sp_vrs_fini(mlxsw_sp);
1998err_vrs_init:
1999 __mlxsw_sp_router_fini(mlxsw_sp);
2000 return err;
2001}
2002
2003void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp)
2004{
2005 unregister_fib_notifier(&mlxsw_sp->fib_nb);
2006 mlxsw_sp_neigh_fini(mlxsw_sp);
2007 mlxsw_sp_vrs_fini(mlxsw_sp);
2008 __mlxsw_sp_router_fini(mlxsw_sp);
2009}
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
index 2b04b76b503e..5e00c79e8133 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
@@ -1044,11 +1044,6 @@ static int mlxsw_sp_port_obj_add(struct net_device *dev,
1044 SWITCHDEV_OBJ_PORT_VLAN(obj), 1044 SWITCHDEV_OBJ_PORT_VLAN(obj),
1045 trans); 1045 trans);
1046 break; 1046 break;
1047 case SWITCHDEV_OBJ_ID_IPV4_FIB:
1048 err = mlxsw_sp_router_fib4_add(mlxsw_sp_port,
1049 SWITCHDEV_OBJ_IPV4_FIB(obj),
1050 trans);
1051 break;
1052 case SWITCHDEV_OBJ_ID_PORT_FDB: 1047 case SWITCHDEV_OBJ_ID_PORT_FDB:
1053 err = mlxsw_sp_port_fdb_static_add(mlxsw_sp_port, 1048 err = mlxsw_sp_port_fdb_static_add(mlxsw_sp_port,
1054 SWITCHDEV_OBJ_PORT_FDB(obj), 1049 SWITCHDEV_OBJ_PORT_FDB(obj),
@@ -1181,10 +1176,6 @@ static int mlxsw_sp_port_obj_del(struct net_device *dev,
1181 err = mlxsw_sp_port_vlans_del(mlxsw_sp_port, 1176 err = mlxsw_sp_port_vlans_del(mlxsw_sp_port,
1182 SWITCHDEV_OBJ_PORT_VLAN(obj)); 1177 SWITCHDEV_OBJ_PORT_VLAN(obj));
1183 break; 1178 break;
1184 case SWITCHDEV_OBJ_ID_IPV4_FIB:
1185 err = mlxsw_sp_router_fib4_del(mlxsw_sp_port,
1186 SWITCHDEV_OBJ_IPV4_FIB(obj));
1187 break;
1188 case SWITCHDEV_OBJ_ID_PORT_FDB: 1179 case SWITCHDEV_OBJ_ID_PORT_FDB:
1189 err = mlxsw_sp_port_fdb_static_del(mlxsw_sp_port, 1180 err = mlxsw_sp_port_fdb_static_del(mlxsw_sp_port,
1190 SWITCHDEV_OBJ_PORT_FDB(obj)); 1181 SWITCHDEV_OBJ_PORT_FDB(obj));
diff --git a/drivers/net/ethernet/rocker/rocker.h b/drivers/net/ethernet/rocker/rocker.h
index 1ab995f7146b..2eb9b49569d5 100644
--- a/drivers/net/ethernet/rocker/rocker.h
+++ b/drivers/net/ethernet/rocker/rocker.h
@@ -15,6 +15,7 @@
15#include <linux/kernel.h> 15#include <linux/kernel.h>
16#include <linux/types.h> 16#include <linux/types.h>
17#include <linux/netdevice.h> 17#include <linux/netdevice.h>
18#include <linux/notifier.h>
18#include <net/neighbour.h> 19#include <net/neighbour.h>
19#include <net/switchdev.h> 20#include <net/switchdev.h>
20 21
@@ -52,6 +53,9 @@ struct rocker_port {
52 struct rocker_dma_ring_info rx_ring; 53 struct rocker_dma_ring_info rx_ring;
53}; 54};
54 55
56struct rocker_port *rocker_port_dev_lower_find(struct net_device *dev,
57 struct rocker *rocker);
58
55struct rocker_world_ops; 59struct rocker_world_ops;
56 60
57struct rocker { 61struct rocker {
@@ -66,6 +70,7 @@ struct rocker {
66 spinlock_t cmd_ring_lock; /* for cmd ring accesses */ 70 spinlock_t cmd_ring_lock; /* for cmd ring accesses */
67 struct rocker_dma_ring_info cmd_ring; 71 struct rocker_dma_ring_info cmd_ring;
68 struct rocker_dma_ring_info event_ring; 72 struct rocker_dma_ring_info event_ring;
73 struct notifier_block fib_nb;
69 struct rocker_world_ops *wops; 74 struct rocker_world_ops *wops;
70 void *wpriv; 75 void *wpriv;
71}; 76};
@@ -117,11 +122,6 @@ struct rocker_world_ops {
117 int (*port_obj_vlan_dump)(const struct rocker_port *rocker_port, 122 int (*port_obj_vlan_dump)(const struct rocker_port *rocker_port,
118 struct switchdev_obj_port_vlan *vlan, 123 struct switchdev_obj_port_vlan *vlan,
119 switchdev_obj_dump_cb_t *cb); 124 switchdev_obj_dump_cb_t *cb);
120 int (*port_obj_fib4_add)(struct rocker_port *rocker_port,
121 const struct switchdev_obj_ipv4_fib *fib4,
122 struct switchdev_trans *trans);
123 int (*port_obj_fib4_del)(struct rocker_port *rocker_port,
124 const struct switchdev_obj_ipv4_fib *fib4);
125 int (*port_obj_fdb_add)(struct rocker_port *rocker_port, 125 int (*port_obj_fdb_add)(struct rocker_port *rocker_port,
126 const struct switchdev_obj_port_fdb *fdb, 126 const struct switchdev_obj_port_fdb *fdb,
127 struct switchdev_trans *trans); 127 struct switchdev_trans *trans);
@@ -141,6 +141,11 @@ struct rocker_world_ops {
141 int (*port_ev_mac_vlan_seen)(struct rocker_port *rocker_port, 141 int (*port_ev_mac_vlan_seen)(struct rocker_port *rocker_port,
142 const unsigned char *addr, 142 const unsigned char *addr,
143 __be16 vlan_id); 143 __be16 vlan_id);
144 int (*fib4_add)(struct rocker *rocker,
145 const struct fib_entry_notifier_info *fen_info);
146 int (*fib4_del)(struct rocker *rocker,
147 const struct fib_entry_notifier_info *fen_info);
148 void (*fib4_abort)(struct rocker *rocker);
144}; 149};
145 150
146extern struct rocker_world_ops rocker_ofdpa_ops; 151extern struct rocker_world_ops rocker_ofdpa_ops;
diff --git a/drivers/net/ethernet/rocker/rocker_main.c b/drivers/net/ethernet/rocker/rocker_main.c
index 1f0c08602eba..5424fb341613 100644
--- a/drivers/net/ethernet/rocker/rocker_main.c
+++ b/drivers/net/ethernet/rocker/rocker_main.c
@@ -1625,29 +1625,6 @@ rocker_world_port_obj_vlan_dump(const struct rocker_port *rocker_port,
1625} 1625}
1626 1626
1627static int 1627static int
1628rocker_world_port_obj_fib4_add(struct rocker_port *rocker_port,
1629 const struct switchdev_obj_ipv4_fib *fib4,
1630 struct switchdev_trans *trans)
1631{
1632 struct rocker_world_ops *wops = rocker_port->rocker->wops;
1633
1634 if (!wops->port_obj_fib4_add)
1635 return -EOPNOTSUPP;
1636 return wops->port_obj_fib4_add(rocker_port, fib4, trans);
1637}
1638
1639static int
1640rocker_world_port_obj_fib4_del(struct rocker_port *rocker_port,
1641 const struct switchdev_obj_ipv4_fib *fib4)
1642{
1643 struct rocker_world_ops *wops = rocker_port->rocker->wops;
1644
1645 if (!wops->port_obj_fib4_del)
1646 return -EOPNOTSUPP;
1647 return wops->port_obj_fib4_del(rocker_port, fib4);
1648}
1649
1650static int
1651rocker_world_port_obj_fdb_add(struct rocker_port *rocker_port, 1628rocker_world_port_obj_fdb_add(struct rocker_port *rocker_port,
1652 const struct switchdev_obj_port_fdb *fdb, 1629 const struct switchdev_obj_port_fdb *fdb,
1653 struct switchdev_trans *trans) 1630 struct switchdev_trans *trans)
@@ -1733,6 +1710,34 @@ static int rocker_world_port_ev_mac_vlan_seen(struct rocker_port *rocker_port,
1733 return wops->port_ev_mac_vlan_seen(rocker_port, addr, vlan_id); 1710 return wops->port_ev_mac_vlan_seen(rocker_port, addr, vlan_id);
1734} 1711}
1735 1712
1713static int rocker_world_fib4_add(struct rocker *rocker,
1714 const struct fib_entry_notifier_info *fen_info)
1715{
1716 struct rocker_world_ops *wops = rocker->wops;
1717
1718 if (!wops->fib4_add)
1719 return 0;
1720 return wops->fib4_add(rocker, fen_info);
1721}
1722
1723static int rocker_world_fib4_del(struct rocker *rocker,
1724 const struct fib_entry_notifier_info *fen_info)
1725{
1726 struct rocker_world_ops *wops = rocker->wops;
1727
1728 if (!wops->fib4_del)
1729 return 0;
1730 return wops->fib4_del(rocker, fen_info);
1731}
1732
1733static void rocker_world_fib4_abort(struct rocker *rocker)
1734{
1735 struct rocker_world_ops *wops = rocker->wops;
1736
1737 if (wops->fib4_abort)
1738 wops->fib4_abort(rocker);
1739}
1740
1736/***************** 1741/*****************
1737 * Net device ops 1742 * Net device ops
1738 *****************/ 1743 *****************/
@@ -2096,11 +2101,6 @@ static int rocker_port_obj_add(struct net_device *dev,
2096 SWITCHDEV_OBJ_PORT_VLAN(obj), 2101 SWITCHDEV_OBJ_PORT_VLAN(obj),
2097 trans); 2102 trans);
2098 break; 2103 break;
2099 case SWITCHDEV_OBJ_ID_IPV4_FIB:
2100 err = rocker_world_port_obj_fib4_add(rocker_port,
2101 SWITCHDEV_OBJ_IPV4_FIB(obj),
2102 trans);
2103 break;
2104 case SWITCHDEV_OBJ_ID_PORT_FDB: 2104 case SWITCHDEV_OBJ_ID_PORT_FDB:
2105 err = rocker_world_port_obj_fdb_add(rocker_port, 2105 err = rocker_world_port_obj_fdb_add(rocker_port,
2106 SWITCHDEV_OBJ_PORT_FDB(obj), 2106 SWITCHDEV_OBJ_PORT_FDB(obj),
@@ -2125,10 +2125,6 @@ static int rocker_port_obj_del(struct net_device *dev,
2125 err = rocker_world_port_obj_vlan_del(rocker_port, 2125 err = rocker_world_port_obj_vlan_del(rocker_port,
2126 SWITCHDEV_OBJ_PORT_VLAN(obj)); 2126 SWITCHDEV_OBJ_PORT_VLAN(obj));
2127 break; 2127 break;
2128 case SWITCHDEV_OBJ_ID_IPV4_FIB:
2129 err = rocker_world_port_obj_fib4_del(rocker_port,
2130 SWITCHDEV_OBJ_IPV4_FIB(obj));
2131 break;
2132 case SWITCHDEV_OBJ_ID_PORT_FDB: 2128 case SWITCHDEV_OBJ_ID_PORT_FDB:
2133 err = rocker_world_port_obj_fdb_del(rocker_port, 2129 err = rocker_world_port_obj_fdb_del(rocker_port,
2134 SWITCHDEV_OBJ_PORT_FDB(obj)); 2130 SWITCHDEV_OBJ_PORT_FDB(obj));
@@ -2175,6 +2171,31 @@ static const struct switchdev_ops rocker_port_switchdev_ops = {
2175 .switchdev_port_obj_dump = rocker_port_obj_dump, 2171 .switchdev_port_obj_dump = rocker_port_obj_dump,
2176}; 2172};
2177 2173
2174static int rocker_router_fib_event(struct notifier_block *nb,
2175 unsigned long event, void *ptr)
2176{
2177 struct rocker *rocker = container_of(nb, struct rocker, fib_nb);
2178 struct fib_entry_notifier_info *fen_info = ptr;
2179 int err;
2180
2181 switch (event) {
2182 case FIB_EVENT_ENTRY_ADD:
2183 err = rocker_world_fib4_add(rocker, fen_info);
2184 if (err)
2185 rocker_world_fib4_abort(rocker);
2186 else
2187 break;
2188 case FIB_EVENT_ENTRY_DEL:
2189 rocker_world_fib4_del(rocker, fen_info);
2190 break;
2191 case FIB_EVENT_RULE_ADD: /* fall through */
2192 case FIB_EVENT_RULE_DEL:
2193 rocker_world_fib4_abort(rocker);
2194 break;
2195 }
2196 return NOTIFY_DONE;
2197}
2198
2178/******************** 2199/********************
2179 * ethtool interface 2200 * ethtool interface
2180 ********************/ 2201 ********************/
@@ -2740,6 +2761,9 @@ static int rocker_probe(struct pci_dev *pdev, const struct pci_device_id *id)
2740 goto err_probe_ports; 2761 goto err_probe_ports;
2741 } 2762 }
2742 2763
2764 rocker->fib_nb.notifier_call = rocker_router_fib_event;
2765 register_fib_notifier(&rocker->fib_nb);
2766
2743 dev_info(&pdev->dev, "Rocker switch with id %*phN\n", 2767 dev_info(&pdev->dev, "Rocker switch with id %*phN\n",
2744 (int)sizeof(rocker->hw.id), &rocker->hw.id); 2768 (int)sizeof(rocker->hw.id), &rocker->hw.id);
2745 2769
@@ -2771,6 +2795,7 @@ static void rocker_remove(struct pci_dev *pdev)
2771{ 2795{
2772 struct rocker *rocker = pci_get_drvdata(pdev); 2796 struct rocker *rocker = pci_get_drvdata(pdev);
2773 2797
2798 unregister_fib_notifier(&rocker->fib_nb);
2774 rocker_write32(rocker, CONTROL, ROCKER_CONTROL_RESET); 2799 rocker_write32(rocker, CONTROL, ROCKER_CONTROL_RESET);
2775 rocker_remove_ports(rocker); 2800 rocker_remove_ports(rocker);
2776 free_irq(rocker_msix_vector(rocker, ROCKER_MSIX_VEC_EVENT), rocker); 2801 free_irq(rocker_msix_vector(rocker, ROCKER_MSIX_VEC_EVENT), rocker);
@@ -2799,6 +2824,37 @@ static bool rocker_port_dev_check(const struct net_device *dev)
2799 return dev->netdev_ops == &rocker_port_netdev_ops; 2824 return dev->netdev_ops == &rocker_port_netdev_ops;
2800} 2825}
2801 2826
2827static bool rocker_port_dev_check_under(const struct net_device *dev,
2828 struct rocker *rocker)
2829{
2830 struct rocker_port *rocker_port;
2831
2832 if (!rocker_port_dev_check(dev))
2833 return false;
2834
2835 rocker_port = netdev_priv(dev);
2836 if (rocker_port->rocker != rocker)
2837 return false;
2838
2839 return true;
2840}
2841
2842struct rocker_port *rocker_port_dev_lower_find(struct net_device *dev,
2843 struct rocker *rocker)
2844{
2845 struct net_device *lower_dev;
2846 struct list_head *iter;
2847
2848 if (rocker_port_dev_check_under(dev, rocker))
2849 return netdev_priv(dev);
2850
2851 netdev_for_each_all_lower_dev(dev, lower_dev, iter) {
2852 if (rocker_port_dev_check_under(lower_dev, rocker))
2853 return netdev_priv(lower_dev);
2854 }
2855 return NULL;
2856}
2857
2802static int rocker_netdevice_event(struct notifier_block *unused, 2858static int rocker_netdevice_event(struct notifier_block *unused,
2803 unsigned long event, void *ptr) 2859 unsigned long event, void *ptr)
2804{ 2860{
diff --git a/drivers/net/ethernet/rocker/rocker_ofdpa.c b/drivers/net/ethernet/rocker/rocker_ofdpa.c
index fcad907baecf..431a60804272 100644
--- a/drivers/net/ethernet/rocker/rocker_ofdpa.c
+++ b/drivers/net/ethernet/rocker/rocker_ofdpa.c
@@ -99,6 +99,7 @@ struct ofdpa_flow_tbl_entry {
99 struct ofdpa_flow_tbl_key key; 99 struct ofdpa_flow_tbl_key key;
100 size_t key_len; 100 size_t key_len;
101 u32 key_crc32; /* key */ 101 u32 key_crc32; /* key */
102 struct fib_info *fi;
102}; 103};
103 104
104struct ofdpa_group_tbl_entry { 105struct ofdpa_group_tbl_entry {
@@ -189,6 +190,7 @@ struct ofdpa {
189 spinlock_t neigh_tbl_lock; /* for neigh tbl accesses */ 190 spinlock_t neigh_tbl_lock; /* for neigh tbl accesses */
190 u32 neigh_tbl_next_index; 191 u32 neigh_tbl_next_index;
191 unsigned long ageing_time; 192 unsigned long ageing_time;
193 bool fib_aborted;
192}; 194};
193 195
194struct ofdpa_port { 196struct ofdpa_port {
@@ -1043,7 +1045,8 @@ static int ofdpa_flow_tbl_ucast4_routing(struct ofdpa_port *ofdpa_port,
1043 __be16 eth_type, __be32 dst, 1045 __be16 eth_type, __be32 dst,
1044 __be32 dst_mask, u32 priority, 1046 __be32 dst_mask, u32 priority,
1045 enum rocker_of_dpa_table_id goto_tbl, 1047 enum rocker_of_dpa_table_id goto_tbl,
1046 u32 group_id, int flags) 1048 u32 group_id, struct fib_info *fi,
1049 int flags)
1047{ 1050{
1048 struct ofdpa_flow_tbl_entry *entry; 1051 struct ofdpa_flow_tbl_entry *entry;
1049 1052
@@ -1060,6 +1063,7 @@ static int ofdpa_flow_tbl_ucast4_routing(struct ofdpa_port *ofdpa_port,
1060 entry->key.ucast_routing.group_id = group_id; 1063 entry->key.ucast_routing.group_id = group_id;
1061 entry->key_len = offsetof(struct ofdpa_flow_tbl_key, 1064 entry->key_len = offsetof(struct ofdpa_flow_tbl_key,
1062 ucast_routing.group_id); 1065 ucast_routing.group_id);
1066 entry->fi = fi;
1063 1067
1064 return ofdpa_flow_tbl_do(ofdpa_port, trans, flags, entry); 1068 return ofdpa_flow_tbl_do(ofdpa_port, trans, flags, entry);
1065} 1069}
@@ -1425,7 +1429,7 @@ static int ofdpa_port_ipv4_neigh(struct ofdpa_port *ofdpa_port,
1425 eth_type, ip_addr, 1429 eth_type, ip_addr,
1426 inet_make_mask(32), 1430 inet_make_mask(32),
1427 priority, goto_tbl, 1431 priority, goto_tbl,
1428 group_id, flags); 1432 group_id, NULL, flags);
1429 1433
1430 if (err) 1434 if (err)
1431 netdev_err(ofdpa_port->dev, "Error (%d) /32 unicast route %pI4 group 0x%08x\n", 1435 netdev_err(ofdpa_port->dev, "Error (%d) /32 unicast route %pI4 group 0x%08x\n",
@@ -2390,7 +2394,7 @@ found:
2390 2394
2391static int ofdpa_port_fib_ipv4(struct ofdpa_port *ofdpa_port, 2395static int ofdpa_port_fib_ipv4(struct ofdpa_port *ofdpa_port,
2392 struct switchdev_trans *trans, __be32 dst, 2396 struct switchdev_trans *trans, __be32 dst,
2393 int dst_len, const struct fib_info *fi, 2397 int dst_len, struct fib_info *fi,
2394 u32 tb_id, int flags) 2398 u32 tb_id, int flags)
2395{ 2399{
2396 const struct fib_nh *nh; 2400 const struct fib_nh *nh;
@@ -2426,7 +2430,7 @@ static int ofdpa_port_fib_ipv4(struct ofdpa_port *ofdpa_port,
2426 2430
2427 err = ofdpa_flow_tbl_ucast4_routing(ofdpa_port, trans, eth_type, dst, 2431 err = ofdpa_flow_tbl_ucast4_routing(ofdpa_port, trans, eth_type, dst,
2428 dst_mask, priority, goto_tbl, 2432 dst_mask, priority, goto_tbl,
2429 group_id, flags); 2433 group_id, fi, flags);
2430 if (err) 2434 if (err)
2431 netdev_err(ofdpa_port->dev, "Error (%d) IPv4 route %pI4\n", 2435 netdev_err(ofdpa_port->dev, "Error (%d) IPv4 route %pI4\n",
2432 err, &dst); 2436 err, &dst);
@@ -2718,28 +2722,6 @@ static int ofdpa_port_obj_vlan_dump(const struct rocker_port *rocker_port,
2718 return err; 2722 return err;
2719} 2723}
2720 2724
2721static int ofdpa_port_obj_fib4_add(struct rocker_port *rocker_port,
2722 const struct switchdev_obj_ipv4_fib *fib4,
2723 struct switchdev_trans *trans)
2724{
2725 struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
2726
2727 return ofdpa_port_fib_ipv4(ofdpa_port, trans,
2728 htonl(fib4->dst), fib4->dst_len,
2729 fib4->fi, fib4->tb_id, 0);
2730}
2731
2732static int ofdpa_port_obj_fib4_del(struct rocker_port *rocker_port,
2733 const struct switchdev_obj_ipv4_fib *fib4)
2734{
2735 struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
2736
2737 return ofdpa_port_fib_ipv4(ofdpa_port, NULL,
2738 htonl(fib4->dst), fib4->dst_len,
2739 fib4->fi, fib4->tb_id,
2740 OFDPA_OP_FLAG_REMOVE);
2741}
2742
2743static int ofdpa_port_obj_fdb_add(struct rocker_port *rocker_port, 2725static int ofdpa_port_obj_fdb_add(struct rocker_port *rocker_port,
2744 const struct switchdev_obj_port_fdb *fdb, 2726 const struct switchdev_obj_port_fdb *fdb,
2745 struct switchdev_trans *trans) 2727 struct switchdev_trans *trans)
@@ -2922,6 +2904,82 @@ static int ofdpa_port_ev_mac_vlan_seen(struct rocker_port *rocker_port,
2922 return ofdpa_port_fdb(ofdpa_port, NULL, addr, vlan_id, flags); 2904 return ofdpa_port_fdb(ofdpa_port, NULL, addr, vlan_id, flags);
2923} 2905}
2924 2906
2907static struct ofdpa_port *ofdpa_port_dev_lower_find(struct net_device *dev,
2908 struct rocker *rocker)
2909{
2910 struct rocker_port *rocker_port;
2911
2912 rocker_port = rocker_port_dev_lower_find(dev, rocker);
2913 return rocker_port ? rocker_port->wpriv : NULL;
2914}
2915
2916static int ofdpa_fib4_add(struct rocker *rocker,
2917 const struct fib_entry_notifier_info *fen_info)
2918{
2919 struct ofdpa *ofdpa = rocker->wpriv;
2920 struct ofdpa_port *ofdpa_port;
2921 int err;
2922
2923 if (ofdpa->fib_aborted)
2924 return 0;
2925 ofdpa_port = ofdpa_port_dev_lower_find(fen_info->fi->fib_dev, rocker);
2926 if (!ofdpa_port)
2927 return 0;
2928 err = ofdpa_port_fib_ipv4(ofdpa_port, NULL, htonl(fen_info->dst),
2929 fen_info->dst_len, fen_info->fi,
2930 fen_info->tb_id, 0);
2931 if (err)
2932 return err;
2933 fib_info_offload_inc(fen_info->fi);
2934 return 0;
2935}
2936
2937static int ofdpa_fib4_del(struct rocker *rocker,
2938 const struct fib_entry_notifier_info *fen_info)
2939{
2940 struct ofdpa *ofdpa = rocker->wpriv;
2941 struct ofdpa_port *ofdpa_port;
2942
2943 if (ofdpa->fib_aborted)
2944 return 0;
2945 ofdpa_port = ofdpa_port_dev_lower_find(fen_info->fi->fib_dev, rocker);
2946 if (!ofdpa_port)
2947 return 0;
2948 fib_info_offload_dec(fen_info->fi);
2949 return ofdpa_port_fib_ipv4(ofdpa_port, NULL, htonl(fen_info->dst),
2950 fen_info->dst_len, fen_info->fi,
2951 fen_info->tb_id, OFDPA_OP_FLAG_REMOVE);
2952}
2953
2954static void ofdpa_fib4_abort(struct rocker *rocker)
2955{
2956 struct ofdpa *ofdpa = rocker->wpriv;
2957 struct ofdpa_port *ofdpa_port;
2958 struct ofdpa_flow_tbl_entry *flow_entry;
2959 struct hlist_node *tmp;
2960 unsigned long flags;
2961 int bkt;
2962
2963 if (ofdpa->fib_aborted)
2964 return;
2965
2966 spin_lock_irqsave(&ofdpa->flow_tbl_lock, flags);
2967 hash_for_each_safe(ofdpa->flow_tbl, bkt, tmp, flow_entry, entry) {
2968 if (flow_entry->key.tbl_id !=
2969 ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING)
2970 continue;
2971 ofdpa_port = ofdpa_port_dev_lower_find(flow_entry->fi->fib_dev,
2972 rocker);
2973 if (!ofdpa_port)
2974 continue;
2975 fib_info_offload_dec(flow_entry->fi);
2976 ofdpa_flow_tbl_del(ofdpa_port, NULL, OFDPA_OP_FLAG_REMOVE,
2977 flow_entry);
2978 }
2979 spin_unlock_irqrestore(&ofdpa->flow_tbl_lock, flags);
2980 ofdpa->fib_aborted = true;
2981}
2982
2925struct rocker_world_ops rocker_ofdpa_ops = { 2983struct rocker_world_ops rocker_ofdpa_ops = {
2926 .kind = "ofdpa", 2984 .kind = "ofdpa",
2927 .priv_size = sizeof(struct ofdpa), 2985 .priv_size = sizeof(struct ofdpa),
@@ -2941,8 +2999,6 @@ struct rocker_world_ops rocker_ofdpa_ops = {
2941 .port_obj_vlan_add = ofdpa_port_obj_vlan_add, 2999 .port_obj_vlan_add = ofdpa_port_obj_vlan_add,
2942 .port_obj_vlan_del = ofdpa_port_obj_vlan_del, 3000 .port_obj_vlan_del = ofdpa_port_obj_vlan_del,
2943 .port_obj_vlan_dump = ofdpa_port_obj_vlan_dump, 3001 .port_obj_vlan_dump = ofdpa_port_obj_vlan_dump,
2944 .port_obj_fib4_add = ofdpa_port_obj_fib4_add,
2945 .port_obj_fib4_del = ofdpa_port_obj_fib4_del,
2946 .port_obj_fdb_add = ofdpa_port_obj_fdb_add, 3002 .port_obj_fdb_add = ofdpa_port_obj_fdb_add,
2947 .port_obj_fdb_del = ofdpa_port_obj_fdb_del, 3003 .port_obj_fdb_del = ofdpa_port_obj_fdb_del,
2948 .port_obj_fdb_dump = ofdpa_port_obj_fdb_dump, 3004 .port_obj_fdb_dump = ofdpa_port_obj_fdb_dump,
@@ -2951,4 +3007,7 @@ struct rocker_world_ops rocker_ofdpa_ops = {
2951 .port_neigh_update = ofdpa_port_neigh_update, 3007 .port_neigh_update = ofdpa_port_neigh_update,
2952 .port_neigh_destroy = ofdpa_port_neigh_destroy, 3008 .port_neigh_destroy = ofdpa_port_neigh_destroy,
2953 .port_ev_mac_vlan_seen = ofdpa_port_ev_mac_vlan_seen, 3009 .port_ev_mac_vlan_seen = ofdpa_port_ev_mac_vlan_seen,
3010 .fib4_add = ofdpa_fib4_add,
3011 .fib4_del = ofdpa_fib4_del,
3012 .fib4_abort = ofdpa_fib4_abort,
2954}; 3013};
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index 7d4a72e75f33..b9314b48e39f 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -22,6 +22,7 @@
22#include <net/fib_rules.h> 22#include <net/fib_rules.h>
23#include <net/inetpeer.h> 23#include <net/inetpeer.h>
24#include <linux/percpu.h> 24#include <linux/percpu.h>
25#include <linux/notifier.h>
25 26
26struct fib_config { 27struct fib_config {
27 u8 fc_dst_len; 28 u8 fc_dst_len;
@@ -122,6 +123,7 @@ struct fib_info {
122#ifdef CONFIG_IP_ROUTE_MULTIPATH 123#ifdef CONFIG_IP_ROUTE_MULTIPATH
123 int fib_weight; 124 int fib_weight;
124#endif 125#endif
126 unsigned int fib_offload_cnt;
125 struct rcu_head rcu; 127 struct rcu_head rcu;
126 struct fib_nh fib_nh[0]; 128 struct fib_nh fib_nh[0];
127#define fib_dev fib_nh[0].nh_dev 129#define fib_dev fib_nh[0].nh_dev
@@ -173,6 +175,18 @@ struct fib_result_nl {
173 175
174__be32 fib_info_update_nh_saddr(struct net *net, struct fib_nh *nh); 176__be32 fib_info_update_nh_saddr(struct net *net, struct fib_nh *nh);
175 177
178static inline void fib_info_offload_inc(struct fib_info *fi)
179{
180 fi->fib_offload_cnt++;
181 fi->fib_flags |= RTNH_F_OFFLOAD;
182}
183
184static inline void fib_info_offload_dec(struct fib_info *fi)
185{
186 if (--fi->fib_offload_cnt == 0)
187 fi->fib_flags &= ~RTNH_F_OFFLOAD;
188}
189
176#define FIB_RES_SADDR(net, res) \ 190#define FIB_RES_SADDR(net, res) \
177 ((FIB_RES_NH(res).nh_saddr_genid == \ 191 ((FIB_RES_NH(res).nh_saddr_genid == \
178 atomic_read(&(net)->ipv4.dev_addr_genid)) ? \ 192 atomic_read(&(net)->ipv4.dev_addr_genid)) ? \
@@ -185,6 +199,33 @@ __be32 fib_info_update_nh_saddr(struct net *net, struct fib_nh *nh);
185#define FIB_RES_PREFSRC(net, res) ((res).fi->fib_prefsrc ? : \ 199#define FIB_RES_PREFSRC(net, res) ((res).fi->fib_prefsrc ? : \
186 FIB_RES_SADDR(net, res)) 200 FIB_RES_SADDR(net, res))
187 201
202struct fib_notifier_info {
203 struct net *net;
204};
205
206struct fib_entry_notifier_info {
207 struct fib_notifier_info info; /* must be first */
208 u32 dst;
209 int dst_len;
210 struct fib_info *fi;
211 u8 tos;
212 u8 type;
213 u32 tb_id;
214 u32 nlflags;
215};
216
217enum fib_event_type {
218 FIB_EVENT_ENTRY_ADD,
219 FIB_EVENT_ENTRY_DEL,
220 FIB_EVENT_RULE_ADD,
221 FIB_EVENT_RULE_DEL,
222};
223
224int register_fib_notifier(struct notifier_block *nb);
225int unregister_fib_notifier(struct notifier_block *nb);
226int call_fib_notifiers(struct net *net, enum fib_event_type event_type,
227 struct fib_notifier_info *info);
228
188struct fib_table { 229struct fib_table {
189 struct hlist_node tb_hlist; 230 struct hlist_node tb_hlist;
190 u32 tb_id; 231 u32 tb_id;
@@ -196,13 +237,12 @@ struct fib_table {
196 237
197int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp, 238int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp,
198 struct fib_result *res, int fib_flags); 239 struct fib_result *res, int fib_flags);
199int fib_table_insert(struct fib_table *, struct fib_config *); 240int fib_table_insert(struct net *, struct fib_table *, struct fib_config *);
200int fib_table_delete(struct fib_table *, struct fib_config *); 241int fib_table_delete(struct net *, struct fib_table *, struct fib_config *);
201int fib_table_dump(struct fib_table *table, struct sk_buff *skb, 242int fib_table_dump(struct fib_table *table, struct sk_buff *skb,
202 struct netlink_callback *cb); 243 struct netlink_callback *cb);
203int fib_table_flush(struct fib_table *table); 244int fib_table_flush(struct net *net, struct fib_table *table);
204struct fib_table *fib_trie_unmerge(struct fib_table *main_tb); 245struct fib_table *fib_trie_unmerge(struct fib_table *main_tb);
205void fib_table_flush_external(struct fib_table *table);
206void fib_free_table(struct fib_table *tb); 246void fib_free_table(struct fib_table *tb);
207 247
208#ifndef CONFIG_IP_MULTIPLE_TABLES 248#ifndef CONFIG_IP_MULTIPLE_TABLES
@@ -315,7 +355,6 @@ static inline int fib_num_tclassid_users(struct net *net)
315} 355}
316#endif 356#endif
317int fib_unmerge(struct net *net); 357int fib_unmerge(struct net *net);
318void fib_flush_external(struct net *net);
319 358
320/* Exported by fib_semantics.c */ 359/* Exported by fib_semantics.c */
321int ip_fib_check_default(__be32 gw, struct net_device *dev); 360int ip_fib_check_default(__be32 gw, struct net_device *dev);
diff --git a/include/net/switchdev.h b/include/net/switchdev.h
index 729fe1534160..eba80c4fc56f 100644
--- a/include/net/switchdev.h
+++ b/include/net/switchdev.h
@@ -68,7 +68,6 @@ struct switchdev_attr {
68enum switchdev_obj_id { 68enum switchdev_obj_id {
69 SWITCHDEV_OBJ_ID_UNDEFINED, 69 SWITCHDEV_OBJ_ID_UNDEFINED,
70 SWITCHDEV_OBJ_ID_PORT_VLAN, 70 SWITCHDEV_OBJ_ID_PORT_VLAN,
71 SWITCHDEV_OBJ_ID_IPV4_FIB,
72 SWITCHDEV_OBJ_ID_PORT_FDB, 71 SWITCHDEV_OBJ_ID_PORT_FDB,
73 SWITCHDEV_OBJ_ID_PORT_MDB, 72 SWITCHDEV_OBJ_ID_PORT_MDB,
74}; 73};
@@ -92,21 +91,6 @@ struct switchdev_obj_port_vlan {
92#define SWITCHDEV_OBJ_PORT_VLAN(obj) \ 91#define SWITCHDEV_OBJ_PORT_VLAN(obj) \
93 container_of(obj, struct switchdev_obj_port_vlan, obj) 92 container_of(obj, struct switchdev_obj_port_vlan, obj)
94 93
95/* SWITCHDEV_OBJ_ID_IPV4_FIB */
96struct switchdev_obj_ipv4_fib {
97 struct switchdev_obj obj;
98 u32 dst;
99 int dst_len;
100 struct fib_info *fi;
101 u8 tos;
102 u8 type;
103 u32 nlflags;
104 u32 tb_id;
105};
106
107#define SWITCHDEV_OBJ_IPV4_FIB(obj) \
108 container_of(obj, struct switchdev_obj_ipv4_fib, obj)
109
110/* SWITCHDEV_OBJ_ID_PORT_FDB */ 94/* SWITCHDEV_OBJ_ID_PORT_FDB */
111struct switchdev_obj_port_fdb { 95struct switchdev_obj_port_fdb {
112 struct switchdev_obj obj; 96 struct switchdev_obj obj;
@@ -209,11 +193,6 @@ int switchdev_port_bridge_setlink(struct net_device *dev,
209 struct nlmsghdr *nlh, u16 flags); 193 struct nlmsghdr *nlh, u16 flags);
210int switchdev_port_bridge_dellink(struct net_device *dev, 194int switchdev_port_bridge_dellink(struct net_device *dev,
211 struct nlmsghdr *nlh, u16 flags); 195 struct nlmsghdr *nlh, u16 flags);
212int switchdev_fib_ipv4_add(u32 dst, int dst_len, struct fib_info *fi,
213 u8 tos, u8 type, u32 nlflags, u32 tb_id);
214int switchdev_fib_ipv4_del(u32 dst, int dst_len, struct fib_info *fi,
215 u8 tos, u8 type, u32 tb_id);
216void switchdev_fib_ipv4_abort(struct fib_info *fi);
217int switchdev_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], 196int switchdev_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
218 struct net_device *dev, const unsigned char *addr, 197 struct net_device *dev, const unsigned char *addr,
219 u16 vid, u16 nlm_flags); 198 u16 vid, u16 nlm_flags);
@@ -304,25 +283,6 @@ static inline int switchdev_port_bridge_dellink(struct net_device *dev,
304 return -EOPNOTSUPP; 283 return -EOPNOTSUPP;
305} 284}
306 285
307static inline int switchdev_fib_ipv4_add(u32 dst, int dst_len,
308 struct fib_info *fi,
309 u8 tos, u8 type,
310 u32 nlflags, u32 tb_id)
311{
312 return 0;
313}
314
315static inline int switchdev_fib_ipv4_del(u32 dst, int dst_len,
316 struct fib_info *fi,
317 u8 tos, u8 type, u32 tb_id)
318{
319 return 0;
320}
321
322static inline void switchdev_fib_ipv4_abort(struct fib_info *fi)
323{
324}
325
326static inline int switchdev_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], 286static inline int switchdev_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
327 struct net_device *dev, 287 struct net_device *dev,
328 const unsigned char *addr, 288 const unsigned char *addr,
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 4e56a4c20a3c..c3b80478226e 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -182,26 +182,13 @@ static void fib_flush(struct net *net)
182 struct fib_table *tb; 182 struct fib_table *tb;
183 183
184 hlist_for_each_entry_safe(tb, tmp, head, tb_hlist) 184 hlist_for_each_entry_safe(tb, tmp, head, tb_hlist)
185 flushed += fib_table_flush(tb); 185 flushed += fib_table_flush(net, tb);
186 } 186 }
187 187
188 if (flushed) 188 if (flushed)
189 rt_cache_flush(net); 189 rt_cache_flush(net);
190} 190}
191 191
192void fib_flush_external(struct net *net)
193{
194 struct fib_table *tb;
195 struct hlist_head *head;
196 unsigned int h;
197
198 for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
199 head = &net->ipv4.fib_table_hash[h];
200 hlist_for_each_entry(tb, head, tb_hlist)
201 fib_table_flush_external(tb);
202 }
203}
204
205/* 192/*
206 * Find address type as if only "dev" was present in the system. If 193 * Find address type as if only "dev" was present in the system. If
207 * on_dev is NULL then all interfaces are taken into consideration. 194 * on_dev is NULL then all interfaces are taken into consideration.
@@ -590,13 +577,13 @@ int ip_rt_ioctl(struct net *net, unsigned int cmd, void __user *arg)
590 if (cmd == SIOCDELRT) { 577 if (cmd == SIOCDELRT) {
591 tb = fib_get_table(net, cfg.fc_table); 578 tb = fib_get_table(net, cfg.fc_table);
592 if (tb) 579 if (tb)
593 err = fib_table_delete(tb, &cfg); 580 err = fib_table_delete(net, tb, &cfg);
594 else 581 else
595 err = -ESRCH; 582 err = -ESRCH;
596 } else { 583 } else {
597 tb = fib_new_table(net, cfg.fc_table); 584 tb = fib_new_table(net, cfg.fc_table);
598 if (tb) 585 if (tb)
599 err = fib_table_insert(tb, &cfg); 586 err = fib_table_insert(net, tb, &cfg);
600 else 587 else
601 err = -ENOBUFS; 588 err = -ENOBUFS;
602 } 589 }
@@ -719,7 +706,7 @@ static int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh)
719 goto errout; 706 goto errout;
720 } 707 }
721 708
722 err = fib_table_delete(tb, &cfg); 709 err = fib_table_delete(net, tb, &cfg);
723errout: 710errout:
724 return err; 711 return err;
725} 712}
@@ -741,7 +728,7 @@ static int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh)
741 goto errout; 728 goto errout;
742 } 729 }
743 730
744 err = fib_table_insert(tb, &cfg); 731 err = fib_table_insert(net, tb, &cfg);
745errout: 732errout:
746 return err; 733 return err;
747} 734}
@@ -828,9 +815,9 @@ static void fib_magic(int cmd, int type, __be32 dst, int dst_len, struct in_ifad
828 cfg.fc_scope = RT_SCOPE_HOST; 815 cfg.fc_scope = RT_SCOPE_HOST;
829 816
830 if (cmd == RTM_NEWROUTE) 817 if (cmd == RTM_NEWROUTE)
831 fib_table_insert(tb, &cfg); 818 fib_table_insert(net, tb, &cfg);
832 else 819 else
833 fib_table_delete(tb, &cfg); 820 fib_table_delete(net, tb, &cfg);
834} 821}
835 822
836void fib_add_ifaddr(struct in_ifaddr *ifa) 823void fib_add_ifaddr(struct in_ifaddr *ifa)
@@ -1254,7 +1241,7 @@ static void ip_fib_net_exit(struct net *net)
1254 1241
1255 hlist_for_each_entry_safe(tb, tmp, head, tb_hlist) { 1242 hlist_for_each_entry_safe(tb, tmp, head, tb_hlist) {
1256 hlist_del(&tb->tb_hlist); 1243 hlist_del(&tb->tb_hlist);
1257 fib_table_flush(tb); 1244 fib_table_flush(net, tb);
1258 fib_free_table(tb); 1245 fib_free_table(tb);
1259 } 1246 }
1260 } 1247 }
diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c
index 770bebed6b28..2e50062f642d 100644
--- a/net/ipv4/fib_rules.c
+++ b/net/ipv4/fib_rules.c
@@ -164,6 +164,14 @@ static struct fib_table *fib_empty_table(struct net *net)
164 return NULL; 164 return NULL;
165} 165}
166 166
167static int call_fib_rule_notifiers(struct net *net,
168 enum fib_event_type event_type)
169{
170 struct fib_notifier_info info;
171
172 return call_fib_notifiers(net, event_type, &info);
173}
174
167static const struct nla_policy fib4_rule_policy[FRA_MAX+1] = { 175static const struct nla_policy fib4_rule_policy[FRA_MAX+1] = {
168 FRA_GENERIC_POLICY, 176 FRA_GENERIC_POLICY,
169 [FRA_FLOW] = { .type = NLA_U32 }, 177 [FRA_FLOW] = { .type = NLA_U32 },
@@ -220,7 +228,7 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
220 rule4->tos = frh->tos; 228 rule4->tos = frh->tos;
221 229
222 net->ipv4.fib_has_custom_rules = true; 230 net->ipv4.fib_has_custom_rules = true;
223 fib_flush_external(rule->fr_net); 231 call_fib_rule_notifiers(net, FIB_EVENT_RULE_ADD);
224 232
225 err = 0; 233 err = 0;
226errout: 234errout:
@@ -242,7 +250,7 @@ static int fib4_rule_delete(struct fib_rule *rule)
242 net->ipv4.fib_num_tclassid_users--; 250 net->ipv4.fib_num_tclassid_users--;
243#endif 251#endif
244 net->ipv4.fib_has_custom_rules = true; 252 net->ipv4.fib_has_custom_rules = true;
245 fib_flush_external(rule->fr_net); 253 call_fib_rule_notifiers(net, FIB_EVENT_RULE_DEL);
246errout: 254errout:
247 return err; 255 return err;
248} 256}
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index 241f27bbd7ad..31cef3602585 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -73,6 +73,7 @@
73#include <linux/slab.h> 73#include <linux/slab.h>
74#include <linux/export.h> 74#include <linux/export.h>
75#include <linux/vmalloc.h> 75#include <linux/vmalloc.h>
76#include <linux/notifier.h>
76#include <net/net_namespace.h> 77#include <net/net_namespace.h>
77#include <net/ip.h> 78#include <net/ip.h>
78#include <net/protocol.h> 79#include <net/protocol.h>
@@ -80,10 +81,47 @@
80#include <net/tcp.h> 81#include <net/tcp.h>
81#include <net/sock.h> 82#include <net/sock.h>
82#include <net/ip_fib.h> 83#include <net/ip_fib.h>
83#include <net/switchdev.h>
84#include <trace/events/fib.h> 84#include <trace/events/fib.h>
85#include "fib_lookup.h" 85#include "fib_lookup.h"
86 86
87static BLOCKING_NOTIFIER_HEAD(fib_chain);
88
89int register_fib_notifier(struct notifier_block *nb)
90{
91 return blocking_notifier_chain_register(&fib_chain, nb);
92}
93EXPORT_SYMBOL(register_fib_notifier);
94
95int unregister_fib_notifier(struct notifier_block *nb)
96{
97 return blocking_notifier_chain_unregister(&fib_chain, nb);
98}
99EXPORT_SYMBOL(unregister_fib_notifier);
100
101int call_fib_notifiers(struct net *net, enum fib_event_type event_type,
102 struct fib_notifier_info *info)
103{
104 info->net = net;
105 return blocking_notifier_call_chain(&fib_chain, event_type, info);
106}
107
108static int call_fib_entry_notifiers(struct net *net,
109 enum fib_event_type event_type, u32 dst,
110 int dst_len, struct fib_info *fi,
111 u8 tos, u8 type, u32 tb_id, u32 nlflags)
112{
113 struct fib_entry_notifier_info info = {
114 .dst = dst,
115 .dst_len = dst_len,
116 .fi = fi,
117 .tos = tos,
118 .type = type,
119 .tb_id = tb_id,
120 .nlflags = nlflags,
121 };
122 return call_fib_notifiers(net, event_type, &info.info);
123}
124
87#define MAX_STAT_DEPTH 32 125#define MAX_STAT_DEPTH 32
88 126
89#define KEYLENGTH (8*sizeof(t_key)) 127#define KEYLENGTH (8*sizeof(t_key))
@@ -1076,7 +1114,8 @@ static int fib_insert_alias(struct trie *t, struct key_vector *tp,
1076} 1114}
1077 1115
1078/* Caller must hold RTNL. */ 1116/* Caller must hold RTNL. */
1079int fib_table_insert(struct fib_table *tb, struct fib_config *cfg) 1117int fib_table_insert(struct net *net, struct fib_table *tb,
1118 struct fib_config *cfg)
1080{ 1119{
1081 struct trie *t = (struct trie *)tb->tb_data; 1120 struct trie *t = (struct trie *)tb->tb_data;
1082 struct fib_alias *fa, *new_fa; 1121 struct fib_alias *fa, *new_fa;
@@ -1175,17 +1214,6 @@ int fib_table_insert(struct fib_table *tb, struct fib_config *cfg)
1175 new_fa->tb_id = tb->tb_id; 1214 new_fa->tb_id = tb->tb_id;
1176 new_fa->fa_default = -1; 1215 new_fa->fa_default = -1;
1177 1216
1178 err = switchdev_fib_ipv4_add(key, plen, fi,
1179 new_fa->fa_tos,
1180 cfg->fc_type,
1181 cfg->fc_nlflags,
1182 tb->tb_id);
1183 if (err) {
1184 switchdev_fib_ipv4_abort(fi);
1185 kmem_cache_free(fn_alias_kmem, new_fa);
1186 goto out;
1187 }
1188
1189 hlist_replace_rcu(&fa->fa_list, &new_fa->fa_list); 1217 hlist_replace_rcu(&fa->fa_list, &new_fa->fa_list);
1190 1218
1191 alias_free_mem_rcu(fa); 1219 alias_free_mem_rcu(fa);
@@ -1193,6 +1221,11 @@ int fib_table_insert(struct fib_table *tb, struct fib_config *cfg)
1193 fib_release_info(fi_drop); 1221 fib_release_info(fi_drop);
1194 if (state & FA_S_ACCESSED) 1222 if (state & FA_S_ACCESSED)
1195 rt_cache_flush(cfg->fc_nlinfo.nl_net); 1223 rt_cache_flush(cfg->fc_nlinfo.nl_net);
1224
1225 call_fib_entry_notifiers(net, FIB_EVENT_ENTRY_ADD,
1226 key, plen, fi,
1227 new_fa->fa_tos, cfg->fc_type,
1228 tb->tb_id, cfg->fc_nlflags);
1196 rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, 1229 rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen,
1197 tb->tb_id, &cfg->fc_nlinfo, nlflags); 1230 tb->tb_id, &cfg->fc_nlinfo, nlflags);
1198 1231
@@ -1228,30 +1261,22 @@ int fib_table_insert(struct fib_table *tb, struct fib_config *cfg)
1228 new_fa->tb_id = tb->tb_id; 1261 new_fa->tb_id = tb->tb_id;
1229 new_fa->fa_default = -1; 1262 new_fa->fa_default = -1;
1230 1263
1231 /* (Optionally) offload fib entry to switch hardware. */
1232 err = switchdev_fib_ipv4_add(key, plen, fi, tos, cfg->fc_type,
1233 cfg->fc_nlflags, tb->tb_id);
1234 if (err) {
1235 switchdev_fib_ipv4_abort(fi);
1236 goto out_free_new_fa;
1237 }
1238
1239 /* Insert new entry to the list. */ 1264 /* Insert new entry to the list. */
1240 err = fib_insert_alias(t, tp, l, new_fa, fa, key); 1265 err = fib_insert_alias(t, tp, l, new_fa, fa, key);
1241 if (err) 1266 if (err)
1242 goto out_sw_fib_del; 1267 goto out_free_new_fa;
1243 1268
1244 if (!plen) 1269 if (!plen)
1245 tb->tb_num_default++; 1270 tb->tb_num_default++;
1246 1271
1247 rt_cache_flush(cfg->fc_nlinfo.nl_net); 1272 rt_cache_flush(cfg->fc_nlinfo.nl_net);
1273 call_fib_entry_notifiers(net, FIB_EVENT_ENTRY_ADD, key, plen, fi, tos,
1274 cfg->fc_type, tb->tb_id, cfg->fc_nlflags);
1248 rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, new_fa->tb_id, 1275 rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, new_fa->tb_id,
1249 &cfg->fc_nlinfo, nlflags); 1276 &cfg->fc_nlinfo, nlflags);
1250succeeded: 1277succeeded:
1251 return 0; 1278 return 0;
1252 1279
1253out_sw_fib_del:
1254 switchdev_fib_ipv4_del(key, plen, fi, tos, cfg->fc_type, tb->tb_id);
1255out_free_new_fa: 1280out_free_new_fa:
1256 kmem_cache_free(fn_alias_kmem, new_fa); 1281 kmem_cache_free(fn_alias_kmem, new_fa);
1257out: 1282out:
@@ -1490,7 +1515,8 @@ static void fib_remove_alias(struct trie *t, struct key_vector *tp,
1490} 1515}
1491 1516
1492/* Caller must hold RTNL. */ 1517/* Caller must hold RTNL. */
1493int fib_table_delete(struct fib_table *tb, struct fib_config *cfg) 1518int fib_table_delete(struct net *net, struct fib_table *tb,
1519 struct fib_config *cfg)
1494{ 1520{
1495 struct trie *t = (struct trie *) tb->tb_data; 1521 struct trie *t = (struct trie *) tb->tb_data;
1496 struct fib_alias *fa, *fa_to_delete; 1522 struct fib_alias *fa, *fa_to_delete;
@@ -1543,9 +1569,9 @@ int fib_table_delete(struct fib_table *tb, struct fib_config *cfg)
1543 if (!fa_to_delete) 1569 if (!fa_to_delete)
1544 return -ESRCH; 1570 return -ESRCH;
1545 1571
1546 switchdev_fib_ipv4_del(key, plen, fa_to_delete->fa_info, tos, 1572 call_fib_entry_notifiers(net, FIB_EVENT_ENTRY_DEL, key, plen,
1547 cfg->fc_type, tb->tb_id); 1573 fa_to_delete->fa_info, tos, cfg->fc_type,
1548 1574 tb->tb_id, 0);
1549 rtmsg_fib(RTM_DELROUTE, htonl(key), fa_to_delete, plen, tb->tb_id, 1575 rtmsg_fib(RTM_DELROUTE, htonl(key), fa_to_delete, plen, tb->tb_id,
1550 &cfg->fc_nlinfo, 0); 1576 &cfg->fc_nlinfo, 0);
1551 1577
@@ -1734,82 +1760,8 @@ out:
1734 return NULL; 1760 return NULL;
1735} 1761}
1736 1762
1737/* Caller must hold RTNL */
1738void fib_table_flush_external(struct fib_table *tb)
1739{
1740 struct trie *t = (struct trie *)tb->tb_data;
1741 struct key_vector *pn = t->kv;
1742 unsigned long cindex = 1;
1743 struct hlist_node *tmp;
1744 struct fib_alias *fa;
1745
1746 /* walk trie in reverse order */
1747 for (;;) {
1748 unsigned char slen = 0;
1749 struct key_vector *n;
1750
1751 if (!(cindex--)) {
1752 t_key pkey = pn->key;
1753
1754 /* cannot resize the trie vector */
1755 if (IS_TRIE(pn))
1756 break;
1757
1758 /* resize completed node */
1759 pn = resize(t, pn);
1760 cindex = get_index(pkey, pn);
1761
1762 continue;
1763 }
1764
1765 /* grab the next available node */
1766 n = get_child(pn, cindex);
1767 if (!n)
1768 continue;
1769
1770 if (IS_TNODE(n)) {
1771 /* record pn and cindex for leaf walking */
1772 pn = n;
1773 cindex = 1ul << n->bits;
1774
1775 continue;
1776 }
1777
1778 hlist_for_each_entry_safe(fa, tmp, &n->leaf, fa_list) {
1779 struct fib_info *fi = fa->fa_info;
1780
1781 /* if alias was cloned to local then we just
1782 * need to remove the local copy from main
1783 */
1784 if (tb->tb_id != fa->tb_id) {
1785 hlist_del_rcu(&fa->fa_list);
1786 alias_free_mem_rcu(fa);
1787 continue;
1788 }
1789
1790 /* record local slen */
1791 slen = fa->fa_slen;
1792
1793 if (!fi || !(fi->fib_flags & RTNH_F_OFFLOAD))
1794 continue;
1795
1796 switchdev_fib_ipv4_del(n->key, KEYLENGTH - fa->fa_slen,
1797 fi, fa->fa_tos, fa->fa_type,
1798 tb->tb_id);
1799 }
1800
1801 /* update leaf slen */
1802 n->slen = slen;
1803
1804 if (hlist_empty(&n->leaf)) {
1805 put_child_root(pn, n->key, NULL);
1806 node_free(n);
1807 }
1808 }
1809}
1810
1811/* Caller must hold RTNL. */ 1763/* Caller must hold RTNL. */
1812int fib_table_flush(struct fib_table *tb) 1764int fib_table_flush(struct net *net, struct fib_table *tb)
1813{ 1765{
1814 struct trie *t = (struct trie *)tb->tb_data; 1766 struct trie *t = (struct trie *)tb->tb_data;
1815 struct key_vector *pn = t->kv; 1767 struct key_vector *pn = t->kv;
@@ -1858,9 +1810,11 @@ int fib_table_flush(struct fib_table *tb)
1858 continue; 1810 continue;
1859 } 1811 }
1860 1812
1861 switchdev_fib_ipv4_del(n->key, KEYLENGTH - fa->fa_slen, 1813 call_fib_entry_notifiers(net, FIB_EVENT_ENTRY_DEL,
1862 fi, fa->fa_tos, fa->fa_type, 1814 n->key,
1863 tb->tb_id); 1815 KEYLENGTH - fa->fa_slen,
1816 fi, fa->fa_tos, fa->fa_type,
1817 tb->tb_id, 0);
1864 hlist_del_rcu(&fa->fa_list); 1818 hlist_del_rcu(&fa->fa_list);
1865 fib_release_info(fa->fa_info); 1819 fib_release_info(fa->fa_info);
1866 alias_free_mem_rcu(fa); 1820 alias_free_mem_rcu(fa);
diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c
index 10b819308439..02beb35f577f 100644
--- a/net/switchdev/switchdev.c
+++ b/net/switchdev/switchdev.c
@@ -21,7 +21,6 @@
21#include <linux/workqueue.h> 21#include <linux/workqueue.h>
22#include <linux/if_vlan.h> 22#include <linux/if_vlan.h>
23#include <linux/rtnetlink.h> 23#include <linux/rtnetlink.h>
24#include <net/ip_fib.h>
25#include <net/switchdev.h> 24#include <net/switchdev.h>
26 25
27/** 26/**
@@ -344,8 +343,6 @@ static size_t switchdev_obj_size(const struct switchdev_obj *obj)
344 switch (obj->id) { 343 switch (obj->id) {
345 case SWITCHDEV_OBJ_ID_PORT_VLAN: 344 case SWITCHDEV_OBJ_ID_PORT_VLAN:
346 return sizeof(struct switchdev_obj_port_vlan); 345 return sizeof(struct switchdev_obj_port_vlan);
347 case SWITCHDEV_OBJ_ID_IPV4_FIB:
348 return sizeof(struct switchdev_obj_ipv4_fib);
349 case SWITCHDEV_OBJ_ID_PORT_FDB: 346 case SWITCHDEV_OBJ_ID_PORT_FDB:
350 return sizeof(struct switchdev_obj_port_fdb); 347 return sizeof(struct switchdev_obj_port_fdb);
351 case SWITCHDEV_OBJ_ID_PORT_MDB: 348 case SWITCHDEV_OBJ_ID_PORT_MDB:
@@ -1108,184 +1105,6 @@ int switchdev_port_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb,
1108} 1105}
1109EXPORT_SYMBOL_GPL(switchdev_port_fdb_dump); 1106EXPORT_SYMBOL_GPL(switchdev_port_fdb_dump);
1110 1107
1111static struct net_device *switchdev_get_lowest_dev(struct net_device *dev)
1112{
1113 const struct switchdev_ops *ops = dev->switchdev_ops;
1114 struct net_device *lower_dev;
1115 struct net_device *port_dev;
1116 struct list_head *iter;
1117
1118 /* Recusively search down until we find a sw port dev.
1119 * (A sw port dev supports switchdev_port_attr_get).
1120 */
1121
1122 if (ops && ops->switchdev_port_attr_get)
1123 return dev;
1124
1125 netdev_for_each_lower_dev(dev, lower_dev, iter) {
1126 port_dev = switchdev_get_lowest_dev(lower_dev);
1127 if (port_dev)
1128 return port_dev;
1129 }
1130
1131 return NULL;
1132}
1133
1134static struct net_device *switchdev_get_dev_by_nhs(struct fib_info *fi)
1135{
1136 struct switchdev_attr attr = {
1137 .id = SWITCHDEV_ATTR_ID_PORT_PARENT_ID,
1138 };
1139 struct switchdev_attr prev_attr;
1140 struct net_device *dev = NULL;
1141 int nhsel;
1142
1143 ASSERT_RTNL();
1144
1145 /* For this route, all nexthop devs must be on the same switch. */
1146
1147 for (nhsel = 0; nhsel < fi->fib_nhs; nhsel++) {
1148 const struct fib_nh *nh = &fi->fib_nh[nhsel];
1149
1150 if (!nh->nh_dev)
1151 return NULL;
1152
1153 dev = switchdev_get_lowest_dev(nh->nh_dev);
1154 if (!dev)
1155 return NULL;
1156
1157 attr.orig_dev = dev;
1158 if (switchdev_port_attr_get(dev, &attr))
1159 return NULL;
1160
1161 if (nhsel > 0 &&
1162 !netdev_phys_item_id_same(&prev_attr.u.ppid, &attr.u.ppid))
1163 return NULL;
1164
1165 prev_attr = attr;
1166 }
1167
1168 return dev;
1169}
1170
1171/**
1172 * switchdev_fib_ipv4_add - Add/modify switch IPv4 route entry
1173 *
1174 * @dst: route's IPv4 destination address
1175 * @dst_len: destination address length (prefix length)
1176 * @fi: route FIB info structure
1177 * @tos: route TOS
1178 * @type: route type
1179 * @nlflags: netlink flags passed in (NLM_F_*)
1180 * @tb_id: route table ID
1181 *
1182 * Add/modify switch IPv4 route entry.
1183 */
1184int switchdev_fib_ipv4_add(u32 dst, int dst_len, struct fib_info *fi,
1185 u8 tos, u8 type, u32 nlflags, u32 tb_id)
1186{
1187 struct switchdev_obj_ipv4_fib ipv4_fib = {
1188 .obj.id = SWITCHDEV_OBJ_ID_IPV4_FIB,
1189 .dst = dst,
1190 .dst_len = dst_len,
1191 .fi = fi,
1192 .tos = tos,
1193 .type = type,
1194 .nlflags = nlflags,
1195 .tb_id = tb_id,
1196 };
1197 struct net_device *dev;
1198 int err = 0;
1199
1200 /* Don't offload route if using custom ip rules or if
1201 * IPv4 FIB offloading has been disabled completely.
1202 */
1203
1204#ifdef CONFIG_IP_MULTIPLE_TABLES
1205 if (fi->fib_net->ipv4.fib_has_custom_rules)
1206 return 0;
1207#endif
1208
1209 if (fi->fib_net->ipv4.fib_offload_disabled)
1210 return 0;
1211
1212 dev = switchdev_get_dev_by_nhs(fi);
1213 if (!dev)
1214 return 0;
1215
1216 ipv4_fib.obj.orig_dev = dev;
1217 err = switchdev_port_obj_add(dev, &ipv4_fib.obj);
1218 if (!err)
1219 fi->fib_flags |= RTNH_F_OFFLOAD;
1220
1221 return err == -EOPNOTSUPP ? 0 : err;
1222}
1223EXPORT_SYMBOL_GPL(switchdev_fib_ipv4_add);
1224
1225/**
1226 * switchdev_fib_ipv4_del - Delete IPv4 route entry from switch
1227 *
1228 * @dst: route's IPv4 destination address
1229 * @dst_len: destination address length (prefix length)
1230 * @fi: route FIB info structure
1231 * @tos: route TOS
1232 * @type: route type
1233 * @tb_id: route table ID
1234 *
1235 * Delete IPv4 route entry from switch device.
1236 */
1237int switchdev_fib_ipv4_del(u32 dst, int dst_len, struct fib_info *fi,
1238 u8 tos, u8 type, u32 tb_id)
1239{
1240 struct switchdev_obj_ipv4_fib ipv4_fib = {
1241 .obj.id = SWITCHDEV_OBJ_ID_IPV4_FIB,
1242 .dst = dst,
1243 .dst_len = dst_len,
1244 .fi = fi,
1245 .tos = tos,
1246 .type = type,
1247 .nlflags = 0,
1248 .tb_id = tb_id,
1249 };
1250 struct net_device *dev;
1251 int err = 0;
1252
1253 if (!(fi->fib_flags & RTNH_F_OFFLOAD))
1254 return 0;
1255
1256 dev = switchdev_get_dev_by_nhs(fi);
1257 if (!dev)
1258 return 0;
1259
1260 ipv4_fib.obj.orig_dev = dev;
1261 err = switchdev_port_obj_del(dev, &ipv4_fib.obj);
1262 if (!err)
1263 fi->fib_flags &= ~RTNH_F_OFFLOAD;
1264
1265 return err == -EOPNOTSUPP ? 0 : err;
1266}
1267EXPORT_SYMBOL_GPL(switchdev_fib_ipv4_del);
1268
1269/**
1270 * switchdev_fib_ipv4_abort - Abort an IPv4 FIB operation
1271 *
1272 * @fi: route FIB info structure
1273 */
1274void switchdev_fib_ipv4_abort(struct fib_info *fi)
1275{
1276 /* There was a problem installing this route to the offload
1277 * device. For now, until we come up with more refined
1278 * policy handling, abruptly end IPv4 fib offloading for
1279 * for entire net by flushing offload device(s) of all
1280 * IPv4 routes, and mark IPv4 fib offloading broken from
1281 * this point forward.
1282 */
1283
1284 fib_flush_external(fi->fib_net);
1285 fi->fib_net->ipv4.fib_offload_disabled = true;
1286}
1287EXPORT_SYMBOL_GPL(switchdev_fib_ipv4_abort);
1288
1289bool switchdev_port_same_parent_id(struct net_device *a, 1108bool switchdev_port_same_parent_id(struct net_device *a,
1290 struct net_device *b) 1109 struct net_device *b)
1291{ 1110{