Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+583 -630
+14 -13
Documentation/networking/switchdev.txt
··· 314 314 does a longest prefix match (LPM) on FIB entries matching route prefix and 315 315 forwards the packet to the matching FIB entry's nexthop(s) egress ports. 316 316 317 - To program the device, the driver implements support for 318 - SWITCHDEV_OBJ_IPV[4|6]_FIB object using switchdev_port_obj_xxx ops. 319 - switchdev_port_obj_add is used for both adding a new FIB entry to the device, 320 - or modifying an existing entry on the device. 317 + To program the device, the driver has to register a FIB notifier handler 318 + using register_fib_notifier. The following events are available: 319 + FIB_EVENT_ENTRY_ADD: used for both adding a new FIB entry to the device, 320 + or modifying an existing entry on the device. 321 + FIB_EVENT_ENTRY_DEL: used for removing a FIB entry 322 + FIB_EVENT_RULE_ADD, FIB_EVENT_RULE_DEL: used to propagate FIB rule changes 321 323 322 - XXX: Currently, only SWITCHDEV_OBJ_ID_IPV4_FIB objects are supported. 324 + FIB_EVENT_ENTRY_ADD and FIB_EVENT_ENTRY_DEL events pass: 323 325 324 - SWITCHDEV_OBJ_ID_IPV4_FIB object passes: 325 - 326 - struct switchdev_obj_ipv4_fib { /* IPV4_FIB */ 326 + struct fib_entry_notifier_info { 327 + struct fib_notifier_info info; /* must be first */ 327 328 u32 dst; 328 329 int dst_len; 329 330 struct fib_info *fi; 330 331 u8 tos; 331 332 u8 type; 332 - u32 nlflags; 333 333 u32 tb_id; 334 - } ipv4_fib; 334 + u32 nlflags; 335 + }; 335 336 336 337 to add/modify/delete IPv4 dst/dest_len prefix on table tb_id. The *fi 337 338 structure holds details on the route and route's nexthops. *dev is one of the 338 - port netdevs mentioned in the routes next hop list. If the output port netdevs 339 - referenced in the route's nexthop list don't all have the same switch ID, the 340 - driver is not called to add/modify/delete the FIB entry. 339 + port netdevs mentioned in the route's next hop list. 341 340 342 341 Routes offloaded to the device are labeled with "offload" in the ip route 343 342 listing: ··· 353 354 12.0.0.3 via 11.0.0.1 dev sw1p1 proto zebra metric 20 offload 354 355 12.0.0.4 via 11.0.0.9 dev sw1p2 proto zebra metric 20 offload 355 356 192.168.0.0/24 dev eth0 proto kernel scope link src 192.168.0.15 357 + 358 + The "offload" flag is set in case at least one device offloads the FIB entry. 356 359 357 360 XXX: add/mod/del IPv6 FIB API 358 361
+3 -6
drivers/net/ethernet/mellanox/mlxsw/spectrum.h
··· 45 45 #include <linux/list.h> 46 46 #include <linux/dcbnl.h> 47 47 #include <linux/in6.h> 48 - #include <net/switchdev.h> 48 + #include <linux/notifier.h> 49 49 50 50 #include "port.h" 51 51 #include "core.h" ··· 257 257 #define MLXSW_SP_UNRESOLVED_NH_PROBE_INTERVAL 5000 /* ms */ 258 258 struct list_head nexthop_group_list; 259 259 struct list_head nexthop_neighs_list; 260 + bool aborted; 260 261 }; 261 262 262 263 struct mlxsw_sp { ··· 297 296 struct mlxsw_sp_span_entry *entries; 298 297 int entries_count; 299 298 } span; 299 + struct notifier_block fib_nb; 300 300 }; 301 301 302 302 static inline struct mlxsw_sp_upper * ··· 586 584 587 585 int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp); 588 586 void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp); 589 - int mlxsw_sp_router_fib4_add(struct mlxsw_sp_port *mlxsw_sp_port, 590 - const struct switchdev_obj_ipv4_fib *fib4, 591 - struct switchdev_trans *trans); 592 - int mlxsw_sp_router_fib4_del(struct mlxsw_sp_port *mlxsw_sp_port, 593 - const struct switchdev_obj_ipv4_fib *fib4); 594 587 int mlxsw_sp_router_neigh_construct(struct net_device *dev, 595 588 struct neighbour *n); 596 589 void mlxsw_sp_router_neigh_destroy(struct net_device *dev,
+259 -182
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
··· 43 43 #include <net/netevent.h> 44 44 #include <net/neighbour.h> 45 45 #include <net/arp.h> 46 + #include <net/ip_fib.h> 46 47 47 48 #include "spectrum.h" 48 49 #include "core.h" ··· 123 122 124 123 struct mlxsw_sp_fib_entry { 125 124 struct rhash_head ht_node; 125 + struct list_head list; 126 126 struct mlxsw_sp_fib_key key; 127 127 enum mlxsw_sp_fib_entry_type type; 128 128 unsigned int ref_count; 129 129 u16 rif; /* used for action local */ 130 130 struct mlxsw_sp_vr *vr; 131 + struct fib_info *fi; 131 132 struct list_head nexthop_group_node; 132 133 struct mlxsw_sp_nexthop_group *nh_group; 133 134 }; 134 135 135 136 struct mlxsw_sp_fib { 136 137 struct rhashtable ht; 138 + struct list_head entry_list; 137 139 unsigned long prefix_ref_count[MLXSW_SP_PREFIX_COUNT]; 138 140 struct mlxsw_sp_prefix_usage prefix_usage; 139 141 }; ··· 158 154 mlxsw_sp_fib_ht_params); 159 155 if (err) 160 156 return err; 157 + list_add_tail(&fib_entry->list, &fib->entry_list); 161 158 if (fib->prefix_ref_count[prefix_len]++ == 0) 162 159 mlxsw_sp_prefix_usage_set(&fib->prefix_usage, prefix_len); 163 160 return 0; ··· 171 166 172 167 if (--fib->prefix_ref_count[prefix_len] == 0) 173 168 mlxsw_sp_prefix_usage_clear(&fib->prefix_usage, prefix_len); 169 + list_del(&fib_entry->list); 174 170 rhashtable_remove_fast(&fib->ht, &fib_entry->ht_node, 175 171 mlxsw_sp_fib_ht_params); 176 172 } ··· 222 216 err = rhashtable_init(&fib->ht, &mlxsw_sp_fib_ht_params); 223 217 if (err) 224 218 goto err_rhashtable_init; 219 + INIT_LIST_HEAD(&fib->entry_list); 225 220 return fib; 226 221 227 222 err_rhashtable_init: ··· 1527 1520 mlxsw_sp_nexthop_group_destroy(mlxsw_sp, nh_grp); 1528 1521 } 1529 1522 1530 - static int __mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp) 1531 - { 1532 - struct mlxsw_resources *resources; 1533 - char rgcr_pl[MLXSW_REG_RGCR_LEN]; 1534 - int err; 1535 - 1536 - resources = mlxsw_core_resources_get(mlxsw_sp->core); 1537 - if (!resources->max_rif_valid) 1538 - return -EIO; 1539 - 1540 - mlxsw_sp->rifs = kcalloc(resources->max_rif, 1541 - sizeof(struct mlxsw_sp_rif *), GFP_KERNEL); 1542 - if (!mlxsw_sp->rifs) 1543 - return -ENOMEM; 1544 - 1545 - mlxsw_reg_rgcr_pack(rgcr_pl, true); 1546 - mlxsw_reg_rgcr_max_router_interfaces_set(rgcr_pl, resources->max_rif); 1547 - err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rgcr), rgcr_pl); 1548 - if (err) 1549 - goto err_rgcr_fail; 1550 - 1551 - return 0; 1552 - 1553 - err_rgcr_fail: 1554 - kfree(mlxsw_sp->rifs); 1555 - return err; 1556 - } 1557 - 1558 - static void __mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp) 1559 - { 1560 - struct mlxsw_resources *resources; 1561 - char rgcr_pl[MLXSW_REG_RGCR_LEN]; 1562 - int i; 1563 - 1564 - mlxsw_reg_rgcr_pack(rgcr_pl, false); 1565 - mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rgcr), rgcr_pl); 1566 - 1567 - resources = mlxsw_core_resources_get(mlxsw_sp->core); 1568 - for (i = 0; i < resources->max_rif; i++) 1569 - WARN_ON_ONCE(mlxsw_sp->rifs[i]); 1570 - 1571 - kfree(mlxsw_sp->rifs); 1572 - } 1573 - 1574 - int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp) 1575 - { 1576 - int err; 1577 - 1578 - INIT_LIST_HEAD(&mlxsw_sp->router.nexthop_neighs_list); 1579 - INIT_LIST_HEAD(&mlxsw_sp->router.nexthop_group_list); 1580 - err = __mlxsw_sp_router_init(mlxsw_sp); 1581 - if (err) 1582 - return err; 1583 - 1584 - mlxsw_sp_lpm_init(mlxsw_sp); 1585 - err = mlxsw_sp_vrs_init(mlxsw_sp); 1586 - if (err) 1587 - goto err_vrs_init; 1588 - 1589 - err = mlxsw_sp_neigh_init(mlxsw_sp); 1590 - if (err) 1591 - goto err_neigh_init; 1592 - 1593 - return 0; 1594 - 1595 - err_neigh_init: 1596 - mlxsw_sp_vrs_fini(mlxsw_sp); 1597 - err_vrs_init: 1598 - __mlxsw_sp_router_fini(mlxsw_sp); 1599 - return err; 1600 - } 1601 - 1602 - void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp) 1603 - { 1604 - mlxsw_sp_neigh_fini(mlxsw_sp); 1605 - mlxsw_sp_vrs_fini(mlxsw_sp); 1606 - __mlxsw_sp_router_fini(mlxsw_sp); 1607 - } 1608 - 1609 1523 static int mlxsw_sp_fib_entry_op4_remote(struct mlxsw_sp *mlxsw_sp, 1610 1524 struct mlxsw_sp_fib_entry *fib_entry, 1611 1525 enum mlxsw_reg_ralue_op op) ··· 1634 1706 MLXSW_REG_RALUE_OP_WRITE_DELETE); 1635 1707 } 1636 1708 1637 - struct mlxsw_sp_router_fib4_add_info { 1638 - struct switchdev_trans_item tritem; 1639 - struct mlxsw_sp *mlxsw_sp; 1640 - struct mlxsw_sp_fib_entry *fib_entry; 1641 - }; 1642 - 1643 - static void mlxsw_sp_router_fib4_add_info_destroy(void const *data) 1644 - { 1645 - const struct mlxsw_sp_router_fib4_add_info *info = data; 1646 - struct mlxsw_sp_fib_entry *fib_entry = info->fib_entry; 1647 - struct mlxsw_sp *mlxsw_sp = info->mlxsw_sp; 1648 - struct mlxsw_sp_vr *vr = fib_entry->vr; 1649 - 1650 - mlxsw_sp_fib_entry_destroy(fib_entry); 1651 - mlxsw_sp_vr_put(mlxsw_sp, vr); 1652 - kfree(info); 1653 - } 1654 - 1655 1709 static int 1656 1710 mlxsw_sp_router_fib4_entry_init(struct mlxsw_sp *mlxsw_sp, 1657 - const struct switchdev_obj_ipv4_fib *fib4, 1711 + const struct fib_entry_notifier_info *fen_info, 1658 1712 struct mlxsw_sp_fib_entry *fib_entry) 1659 1713 { 1660 - struct fib_info *fi = fib4->fi; 1714 + struct fib_info *fi = fen_info->fi; 1715 + struct mlxsw_sp_rif *r; 1716 + int nhsel; 1717 + int err; 1661 1718 1662 - if (fib4->type == RTN_LOCAL || fib4->type == RTN_BROADCAST) { 1719 + if (fen_info->type == RTN_LOCAL || fen_info->type == RTN_BROADCAST) { 1663 1720 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP; 1664 1721 return 0; 1665 1722 } 1666 - if (fib4->type != RTN_UNICAST) 1723 + if (fen_info->type != RTN_UNICAST) 1667 1724 return -EINVAL; 1668 1725 1669 - if (fi->fib_scope != RT_SCOPE_UNIVERSE) { 1670 - struct mlxsw_sp_rif *r; 1726 + for (nhsel = 0; nhsel < fi->fib_nhs; nhsel++) { 1727 + const struct fib_nh *nh = &fi->fib_nh[nhsel]; 1671 1728 1672 - fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_LOCAL; 1673 - r = mlxsw_sp_rif_find_by_dev(mlxsw_sp, fi->fib_dev); 1674 - if (!r) 1675 - return -EINVAL; 1676 - fib_entry->rif = r->rif; 1677 - return 0; 1729 + if (!nh->nh_dev) 1730 + continue; 1731 + r = mlxsw_sp_rif_find_by_dev(mlxsw_sp, nh->nh_dev); 1732 + if (!r) { 1733 + /* In case router interface is not found for 1734 + * at least one of the nexthops, that means 1735 + * the nexthop points to some device unrelated 1736 + * to us. Set trap and pass the packets for 1737 + * this prefix to kernel. 1738 + */ 1739 + fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP; 1740 + return 0; 1741 + } 1678 1742 } 1679 - fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_REMOTE; 1680 - return mlxsw_sp_nexthop_group_get(mlxsw_sp, fib_entry, fi); 1743 + 1744 + if (fi->fib_scope != RT_SCOPE_UNIVERSE) { 1745 + fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_LOCAL; 1746 + fib_entry->rif = r->rif; 1747 + } else { 1748 + fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_REMOTE; 1749 + err = mlxsw_sp_nexthop_group_get(mlxsw_sp, fib_entry, fi); 1750 + if (err) 1751 + return err; 1752 + } 1753 + fib_info_offload_inc(fen_info->fi); 1754 + return 0; 1681 1755 } 1682 1756 1683 1757 static void 1684 1758 mlxsw_sp_router_fib4_entry_fini(struct mlxsw_sp *mlxsw_sp, 1685 1759 struct mlxsw_sp_fib_entry *fib_entry) 1686 1760 { 1687 - if (fib_entry->type != MLXSW_SP_FIB_ENTRY_TYPE_REMOTE) 1688 - return; 1689 - mlxsw_sp_nexthop_group_put(mlxsw_sp, fib_entry); 1761 + if (fib_entry->type != MLXSW_SP_FIB_ENTRY_TYPE_TRAP) 1762 + fib_info_offload_dec(fib_entry->fi); 1763 + if (fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_REMOTE) 1764 + mlxsw_sp_nexthop_group_put(mlxsw_sp, fib_entry); 1690 1765 } 1691 1766 1692 1767 static struct mlxsw_sp_fib_entry * 1693 1768 mlxsw_sp_fib_entry_get(struct mlxsw_sp *mlxsw_sp, 1694 - const struct switchdev_obj_ipv4_fib *fib4) 1769 + const struct fib_entry_notifier_info *fen_info) 1695 1770 { 1696 1771 struct mlxsw_sp_fib_entry *fib_entry; 1697 - struct fib_info *fi = fib4->fi; 1772 + struct fib_info *fi = fen_info->fi; 1698 1773 struct mlxsw_sp_vr *vr; 1699 1774 int err; 1700 1775 1701 - vr = mlxsw_sp_vr_get(mlxsw_sp, fib4->dst_len, fib4->tb_id, 1776 + vr = mlxsw_sp_vr_get(mlxsw_sp, fen_info->dst_len, fen_info->tb_id, 1702 1777 MLXSW_SP_L3_PROTO_IPV4); 1703 1778 if (IS_ERR(vr)) 1704 1779 return ERR_CAST(vr); 1705 1780 1706 - fib_entry = mlxsw_sp_fib_entry_lookup(vr->fib, &fib4->dst, 1707 - sizeof(fib4->dst), 1708 - fib4->dst_len, fi->fib_dev); 1781 + fib_entry = mlxsw_sp_fib_entry_lookup(vr->fib, &fen_info->dst, 1782 + sizeof(fen_info->dst), 1783 + fen_info->dst_len, fi->fib_dev); 1709 1784 if (fib_entry) { 1710 1785 /* Already exists, just take a reference */ 1711 1786 fib_entry->ref_count++; 1712 1787 return fib_entry; 1713 1788 } 1714 - fib_entry = mlxsw_sp_fib_entry_create(vr->fib, &fib4->dst, 1715 - sizeof(fib4->dst), 1716 - fib4->dst_len, fi->fib_dev); 1789 + fib_entry = mlxsw_sp_fib_entry_create(vr->fib, &fen_info->dst, 1790 + sizeof(fen_info->dst), 1791 + fen_info->dst_len, fi->fib_dev); 1717 1792 if (!fib_entry) { 1718 1793 err = -ENOMEM; 1719 1794 goto err_fib_entry_create; 1720 1795 } 1721 1796 fib_entry->vr = vr; 1797 + fib_entry->fi = fi; 1722 1798 fib_entry->ref_count = 1; 1723 1799 1724 - err = mlxsw_sp_router_fib4_entry_init(mlxsw_sp, fib4, fib_entry); 1800 + err = mlxsw_sp_router_fib4_entry_init(mlxsw_sp, fen_info, fib_entry); 1725 1801 if (err) 1726 1802 goto err_fib4_entry_init; 1727 1803 ··· 1741 1809 1742 1810 static struct mlxsw_sp_fib_entry * 1743 1811 mlxsw_sp_fib_entry_find(struct mlxsw_sp *mlxsw_sp, 1744 - const struct switchdev_obj_ipv4_fib *fib4) 1812 + const struct fib_entry_notifier_info *fen_info) 1745 1813 { 1746 1814 struct mlxsw_sp_vr *vr; 1747 1815 1748 - vr = mlxsw_sp_vr_find(mlxsw_sp, fib4->tb_id, MLXSW_SP_L3_PROTO_IPV4); 1816 + vr = mlxsw_sp_vr_find(mlxsw_sp, fen_info->tb_id, 1817 + MLXSW_SP_L3_PROTO_IPV4); 1749 1818 if (!vr) 1750 1819 return NULL; 1751 1820 1752 - return mlxsw_sp_fib_entry_lookup(vr->fib, &fib4->dst, 1753 - sizeof(fib4->dst), fib4->dst_len, 1754 - fib4->fi->fib_dev); 1821 + return mlxsw_sp_fib_entry_lookup(vr->fib, &fen_info->dst, 1822 + sizeof(fen_info->dst), 1823 + fen_info->dst_len, 1824 + fen_info->fi->fib_dev); 1755 1825 } 1756 1826 1757 1827 static void mlxsw_sp_fib_entry_put(struct mlxsw_sp *mlxsw_sp, ··· 1768 1834 mlxsw_sp_vr_put(mlxsw_sp, vr); 1769 1835 } 1770 1836 1771 - static int 1772 - mlxsw_sp_router_fib4_add_prepare(struct mlxsw_sp_port *mlxsw_sp_port, 1773 - const struct switchdev_obj_ipv4_fib *fib4, 1774 - struct switchdev_trans *trans) 1837 + static void mlxsw_sp_fib_entry_put_all(struct mlxsw_sp *mlxsw_sp, 1838 + struct mlxsw_sp_fib_entry *fib_entry) 1775 1839 { 1776 - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 1777 - struct mlxsw_sp_router_fib4_add_info *info; 1778 - struct mlxsw_sp_fib_entry *fib_entry; 1779 - int err; 1840 + unsigned int last_ref_count; 1780 1841 1781 - fib_entry = mlxsw_sp_fib_entry_get(mlxsw_sp, fib4); 1782 - if (IS_ERR(fib_entry)) 1783 - return PTR_ERR(fib_entry); 1784 - 1785 - info = kmalloc(sizeof(*info), GFP_KERNEL); 1786 - if (!info) { 1787 - err = -ENOMEM; 1788 - goto err_alloc_info; 1789 - } 1790 - info->mlxsw_sp = mlxsw_sp; 1791 - info->fib_entry = fib_entry; 1792 - switchdev_trans_item_enqueue(trans, info, 1793 - mlxsw_sp_router_fib4_add_info_destroy, 1794 - &info->tritem); 1795 - return 0; 1796 - 1797 - err_alloc_info: 1798 - mlxsw_sp_fib_entry_put(mlxsw_sp, fib_entry); 1799 - return err; 1842 + do { 1843 + last_ref_count = fib_entry->ref_count; 1844 + mlxsw_sp_fib_entry_put(mlxsw_sp, fib_entry); 1845 + } while (last_ref_count != 1); 1800 1846 } 1801 1847 1802 - static int 1803 - mlxsw_sp_router_fib4_add_commit(struct mlxsw_sp_port *mlxsw_sp_port, 1804 - const struct switchdev_obj_ipv4_fib *fib4, 1805 - struct switchdev_trans *trans) 1848 + static int mlxsw_sp_router_fib4_add(struct mlxsw_sp *mlxsw_sp, 1849 + struct fib_entry_notifier_info *fen_info) 1806 1850 { 1807 - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 1808 - struct mlxsw_sp_router_fib4_add_info *info; 1809 1851 struct mlxsw_sp_fib_entry *fib_entry; 1810 1852 struct mlxsw_sp_vr *vr; 1811 1853 int err; 1812 1854 1813 - info = switchdev_trans_item_dequeue(trans); 1814 - fib_entry = info->fib_entry; 1815 - kfree(info); 1855 + if (mlxsw_sp->router.aborted) 1856 + return 0; 1857 + 1858 + fib_entry = mlxsw_sp_fib_entry_get(mlxsw_sp, fen_info); 1859 + if (IS_ERR(fib_entry)) { 1860 + dev_warn(mlxsw_sp->bus_info->dev, "Failed to get FIB4 entry being added.\n"); 1861 + return PTR_ERR(fib_entry); 1862 + } 1816 1863 1817 1864 if (fib_entry->ref_count != 1) 1818 1865 return 0; 1819 1866 1820 1867 vr = fib_entry->vr; 1821 1868 err = mlxsw_sp_fib_entry_insert(vr->fib, fib_entry); 1822 - if (err) 1869 + if (err) { 1870 + dev_warn(mlxsw_sp->bus_info->dev, "Failed to insert FIB4 entry being added.\n"); 1823 1871 goto err_fib_entry_insert; 1824 - err = mlxsw_sp_fib_entry_update(mlxsw_sp_port->mlxsw_sp, fib_entry); 1872 + } 1873 + err = mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry); 1825 1874 if (err) 1826 1875 goto err_fib_entry_add; 1827 1876 return 0; ··· 1816 1899 return err; 1817 1900 } 1818 1901 1819 - int mlxsw_sp_router_fib4_add(struct mlxsw_sp_port *mlxsw_sp_port, 1820 - const struct switchdev_obj_ipv4_fib *fib4, 1821 - struct switchdev_trans *trans) 1902 + static int mlxsw_sp_router_fib4_del(struct mlxsw_sp *mlxsw_sp, 1903 + struct fib_entry_notifier_info *fen_info) 1822 1904 { 1823 - if (switchdev_trans_ph_prepare(trans)) 1824 - return mlxsw_sp_router_fib4_add_prepare(mlxsw_sp_port, 1825 - fib4, trans); 1826 - return mlxsw_sp_router_fib4_add_commit(mlxsw_sp_port, 1827 - fib4, trans); 1828 - } 1829 - 1830 - int mlxsw_sp_router_fib4_del(struct mlxsw_sp_port *mlxsw_sp_port, 1831 - const struct switchdev_obj_ipv4_fib *fib4) 1832 - { 1833 - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 1834 1905 struct mlxsw_sp_fib_entry *fib_entry; 1835 1906 1836 - fib_entry = mlxsw_sp_fib_entry_find(mlxsw_sp, fib4); 1907 + if (mlxsw_sp->router.aborted) 1908 + return 0; 1909 + 1910 + fib_entry = mlxsw_sp_fib_entry_find(mlxsw_sp, fen_info); 1837 1911 if (!fib_entry) { 1838 1912 dev_warn(mlxsw_sp->bus_info->dev, "Failed to find FIB4 entry being removed.\n"); 1839 1913 return -ENOENT; ··· 1837 1929 1838 1930 mlxsw_sp_fib_entry_put(mlxsw_sp, fib_entry); 1839 1931 return 0; 1932 + } 1933 + 1934 + static int mlxsw_sp_router_set_abort_trap(struct mlxsw_sp *mlxsw_sp) 1935 + { 1936 + char ralta_pl[MLXSW_REG_RALTA_LEN]; 1937 + char ralst_pl[MLXSW_REG_RALST_LEN]; 1938 + char raltb_pl[MLXSW_REG_RALTB_LEN]; 1939 + char ralue_pl[MLXSW_REG_RALUE_LEN]; 1940 + int err; 1941 + 1942 + mlxsw_reg_ralta_pack(ralta_pl, true, MLXSW_REG_RALXX_PROTOCOL_IPV4, 1943 + MLXSW_SP_LPM_TREE_MIN); 1944 + err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralta), ralta_pl); 1945 + if (err) 1946 + return err; 1947 + 1948 + mlxsw_reg_ralst_pack(ralst_pl, 0xff, MLXSW_SP_LPM_TREE_MIN); 1949 + err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralst), ralst_pl); 1950 + if (err) 1951 + return err; 1952 + 1953 + mlxsw_reg_raltb_pack(raltb_pl, 0, MLXSW_REG_RALXX_PROTOCOL_IPV4, 0); 1954 + err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(raltb), raltb_pl); 1955 + if (err) 1956 + return err; 1957 + 1958 + mlxsw_reg_ralue_pack4(ralue_pl, MLXSW_SP_L3_PROTO_IPV4, 1959 + MLXSW_REG_RALUE_OP_WRITE_WRITE, 0, 0, 0); 1960 + mlxsw_reg_ralue_act_ip2me_pack(ralue_pl); 1961 + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl); 1962 + } 1963 + 1964 + static void mlxsw_sp_router_fib4_abort(struct mlxsw_sp *mlxsw_sp) 1965 + { 1966 + struct mlxsw_resources *resources; 1967 + struct mlxsw_sp_fib_entry *fib_entry; 1968 + struct mlxsw_sp_fib_entry *tmp; 1969 + struct mlxsw_sp_vr *vr; 1970 + int i; 1971 + int err; 1972 + 1973 + resources = mlxsw_core_resources_get(mlxsw_sp->core); 1974 + for (i = 0; i < resources->max_virtual_routers; i++) { 1975 + vr = &mlxsw_sp->router.vrs[i]; 1976 + if (!vr->used) 1977 + continue; 1978 + 1979 + list_for_each_entry_safe(fib_entry, tmp, 1980 + &vr->fib->entry_list, list) { 1981 + bool do_break = &tmp->list == &vr->fib->entry_list; 1982 + 1983 + mlxsw_sp_fib_entry_del(mlxsw_sp, fib_entry); 1984 + mlxsw_sp_fib_entry_remove(fib_entry->vr->fib, 1985 + fib_entry); 1986 + mlxsw_sp_fib_entry_put_all(mlxsw_sp, fib_entry); 1987 + if (do_break) 1988 + break; 1989 + } 1990 + } 1991 + mlxsw_sp->router.aborted = true; 1992 + err = mlxsw_sp_router_set_abort_trap(mlxsw_sp); 1993 + if (err) 1994 + dev_warn(mlxsw_sp->bus_info->dev, "Failed to set abort trap.\n"); 1995 + } 1996 + 1997 + static int __mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp) 1998 + { 1999 + struct mlxsw_resources *resources; 2000 + char rgcr_pl[MLXSW_REG_RGCR_LEN]; 2001 + int err; 2002 + 2003 + resources = mlxsw_core_resources_get(mlxsw_sp->core); 2004 + if (!resources->max_rif_valid) 2005 + return -EIO; 2006 + 2007 + mlxsw_sp->rifs = kcalloc(resources->max_rif, 2008 + sizeof(struct mlxsw_sp_rif *), GFP_KERNEL); 2009 + if (!mlxsw_sp->rifs) 2010 + return -ENOMEM; 2011 + 2012 + mlxsw_reg_rgcr_pack(rgcr_pl, true); 2013 + mlxsw_reg_rgcr_max_router_interfaces_set(rgcr_pl, resources->max_rif); 2014 + err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rgcr), rgcr_pl); 2015 + if (err) 2016 + goto err_rgcr_fail; 2017 + 2018 + return 0; 2019 + 2020 + err_rgcr_fail: 2021 + kfree(mlxsw_sp->rifs); 2022 + return err; 2023 + } 2024 + 2025 + static void __mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp) 2026 + { 2027 + struct mlxsw_resources *resources; 2028 + char rgcr_pl[MLXSW_REG_RGCR_LEN]; 2029 + int i; 2030 + 2031 + mlxsw_reg_rgcr_pack(rgcr_pl, false); 2032 + mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rgcr), rgcr_pl); 2033 + 2034 + resources = mlxsw_core_resources_get(mlxsw_sp->core); 2035 + for (i = 0; i < resources->max_rif; i++) 2036 + WARN_ON_ONCE(mlxsw_sp->rifs[i]); 2037 + 2038 + kfree(mlxsw_sp->rifs); 2039 + } 2040 + 2041 + static int mlxsw_sp_router_fib_event(struct notifier_block *nb, 2042 + unsigned long event, void *ptr) 2043 + { 2044 + struct mlxsw_sp *mlxsw_sp = container_of(nb, struct mlxsw_sp, fib_nb); 2045 + struct fib_entry_notifier_info *fen_info = ptr; 2046 + int err; 2047 + 2048 + switch (event) { 2049 + case FIB_EVENT_ENTRY_ADD: 2050 + err = mlxsw_sp_router_fib4_add(mlxsw_sp, fen_info); 2051 + if (err) 2052 + mlxsw_sp_router_fib4_abort(mlxsw_sp); 2053 + break; 2054 + case FIB_EVENT_ENTRY_DEL: 2055 + mlxsw_sp_router_fib4_del(mlxsw_sp, fen_info); 2056 + break; 2057 + case FIB_EVENT_RULE_ADD: /* fall through */ 2058 + case FIB_EVENT_RULE_DEL: 2059 + mlxsw_sp_router_fib4_abort(mlxsw_sp); 2060 + break; 2061 + } 2062 + return NOTIFY_DONE; 2063 + } 2064 + 2065 + int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp) 2066 + { 2067 + int err; 2068 + 2069 + INIT_LIST_HEAD(&mlxsw_sp->router.nexthop_neighs_list); 2070 + INIT_LIST_HEAD(&mlxsw_sp->router.nexthop_group_list); 2071 + err = __mlxsw_sp_router_init(mlxsw_sp); 2072 + if (err) 2073 + return err; 2074 + 2075 + mlxsw_sp_lpm_init(mlxsw_sp); 2076 + err = mlxsw_sp_vrs_init(mlxsw_sp); 2077 + if (err) 2078 + goto err_vrs_init; 2079 + 2080 + err = mlxsw_sp_neigh_init(mlxsw_sp); 2081 + if (err) 2082 + goto err_neigh_init; 2083 + 2084 + mlxsw_sp->fib_nb.notifier_call = mlxsw_sp_router_fib_event; 2085 + register_fib_notifier(&mlxsw_sp->fib_nb); 2086 + return 0; 2087 + 2088 + err_neigh_init: 2089 + mlxsw_sp_vrs_fini(mlxsw_sp); 2090 + err_vrs_init: 2091 + __mlxsw_sp_router_fini(mlxsw_sp); 2092 + return err; 2093 + } 2094 + 2095 + void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp) 2096 + { 2097 + unregister_fib_notifier(&mlxsw_sp->fib_nb); 2098 + mlxsw_sp_neigh_fini(mlxsw_sp); 2099 + mlxsw_sp_vrs_fini(mlxsw_sp); 2100 + __mlxsw_sp_router_fini(mlxsw_sp); 1840 2101 }
-9
drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
··· 1044 1044 SWITCHDEV_OBJ_PORT_VLAN(obj), 1045 1045 trans); 1046 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 1047 case SWITCHDEV_OBJ_ID_PORT_FDB: 1053 1048 err = mlxsw_sp_port_fdb_static_add(mlxsw_sp_port, 1054 1049 SWITCHDEV_OBJ_PORT_FDB(obj), ··· 1175 1180 1176 1181 err = mlxsw_sp_port_vlans_del(mlxsw_sp_port, 1177 1182 SWITCHDEV_OBJ_PORT_VLAN(obj)); 1178 - break; 1179 - case SWITCHDEV_OBJ_ID_IPV4_FIB: 1180 - err = mlxsw_sp_router_fib4_del(mlxsw_sp_port, 1181 - SWITCHDEV_OBJ_IPV4_FIB(obj)); 1182 1183 break; 1183 1184 case SWITCHDEV_OBJ_ID_PORT_FDB: 1184 1185 err = mlxsw_sp_port_fdb_static_del(mlxsw_sp_port,
+10 -5
drivers/net/ethernet/rocker/rocker.h
··· 15 15 #include <linux/kernel.h> 16 16 #include <linux/types.h> 17 17 #include <linux/netdevice.h> 18 + #include <linux/notifier.h> 18 19 #include <net/neighbour.h> 19 20 #include <net/switchdev.h> 20 21 ··· 53 52 struct rocker_dma_ring_info rx_ring; 54 53 }; 55 54 55 + struct rocker_port *rocker_port_dev_lower_find(struct net_device *dev, 56 + struct rocker *rocker); 57 + 56 58 struct rocker_world_ops; 57 59 58 60 struct rocker { ··· 70 66 spinlock_t cmd_ring_lock; /* for cmd ring accesses */ 71 67 struct rocker_dma_ring_info cmd_ring; 72 68 struct rocker_dma_ring_info event_ring; 69 + struct notifier_block fib_nb; 73 70 struct rocker_world_ops *wops; 74 71 void *wpriv; 75 72 }; ··· 122 117 int (*port_obj_vlan_dump)(const struct rocker_port *rocker_port, 123 118 struct switchdev_obj_port_vlan *vlan, 124 119 switchdev_obj_dump_cb_t *cb); 125 - int (*port_obj_fib4_add)(struct rocker_port *rocker_port, 126 - const struct switchdev_obj_ipv4_fib *fib4, 127 - struct switchdev_trans *trans); 128 - int (*port_obj_fib4_del)(struct rocker_port *rocker_port, 129 - const struct switchdev_obj_ipv4_fib *fib4); 130 120 int (*port_obj_fdb_add)(struct rocker_port *rocker_port, 131 121 const struct switchdev_obj_port_fdb *fdb, 132 122 struct switchdev_trans *trans); ··· 141 141 int (*port_ev_mac_vlan_seen)(struct rocker_port *rocker_port, 142 142 const unsigned char *addr, 143 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 146 151 extern struct rocker_world_ops rocker_ofdpa_ops;
+88 -32
drivers/net/ethernet/rocker/rocker_main.c
··· 1625 1625 } 1626 1626 1627 1627 static int 1628 - rocker_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 - 1639 - static int 1640 - rocker_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 - 1650 - static int 1651 1628 rocker_world_port_obj_fdb_add(struct rocker_port *rocker_port, 1652 1629 const struct switchdev_obj_port_fdb *fdb, 1653 1630 struct switchdev_trans *trans) ··· 1708 1731 if (!wops->port_ev_mac_vlan_seen) 1709 1732 return -EOPNOTSUPP; 1710 1733 return wops->port_ev_mac_vlan_seen(rocker_port, addr, vlan_id); 1734 + } 1735 + 1736 + static int rocker_world_fib4_add(struct rocker *rocker, 1737 + const struct fib_entry_notifier_info *fen_info) 1738 + { 1739 + struct rocker_world_ops *wops = rocker->wops; 1740 + 1741 + if (!wops->fib4_add) 1742 + return 0; 1743 + return wops->fib4_add(rocker, fen_info); 1744 + } 1745 + 1746 + static int rocker_world_fib4_del(struct rocker *rocker, 1747 + const struct fib_entry_notifier_info *fen_info) 1748 + { 1749 + struct rocker_world_ops *wops = rocker->wops; 1750 + 1751 + if (!wops->fib4_del) 1752 + return 0; 1753 + return wops->fib4_del(rocker, fen_info); 1754 + } 1755 + 1756 + static void rocker_world_fib4_abort(struct rocker *rocker) 1757 + { 1758 + struct rocker_world_ops *wops = rocker->wops; 1759 + 1760 + if (wops->fib4_abort) 1761 + wops->fib4_abort(rocker); 1711 1762 } 1712 1763 1713 1764 /***************** ··· 2101 2096 SWITCHDEV_OBJ_PORT_VLAN(obj), 2102 2097 trans); 2103 2098 break; 2104 - case SWITCHDEV_OBJ_ID_IPV4_FIB: 2105 - err = rocker_world_port_obj_fib4_add(rocker_port, 2106 - SWITCHDEV_OBJ_IPV4_FIB(obj), 2107 - trans); 2108 - break; 2109 2099 case SWITCHDEV_OBJ_ID_PORT_FDB: 2110 2100 err = rocker_world_port_obj_fdb_add(rocker_port, 2111 2101 SWITCHDEV_OBJ_PORT_FDB(obj), ··· 2124 2124 case SWITCHDEV_OBJ_ID_PORT_VLAN: 2125 2125 err = rocker_world_port_obj_vlan_del(rocker_port, 2126 2126 SWITCHDEV_OBJ_PORT_VLAN(obj)); 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 2127 break; 2132 2128 case SWITCHDEV_OBJ_ID_PORT_FDB: 2133 2129 err = rocker_world_port_obj_fdb_del(rocker_port, ··· 2170 2174 .switchdev_port_obj_del = rocker_port_obj_del, 2171 2175 .switchdev_port_obj_dump = rocker_port_obj_dump, 2172 2176 }; 2177 + 2178 + static int rocker_router_fib_event(struct notifier_block *nb, 2179 + unsigned long event, void *ptr) 2180 + { 2181 + struct rocker *rocker = container_of(nb, struct rocker, fib_nb); 2182 + struct fib_entry_notifier_info *fen_info = ptr; 2183 + int err; 2184 + 2185 + switch (event) { 2186 + case FIB_EVENT_ENTRY_ADD: 2187 + err = rocker_world_fib4_add(rocker, fen_info); 2188 + if (err) 2189 + rocker_world_fib4_abort(rocker); 2190 + else 2191 + break; 2192 + case FIB_EVENT_ENTRY_DEL: 2193 + rocker_world_fib4_del(rocker, fen_info); 2194 + break; 2195 + case FIB_EVENT_RULE_ADD: /* fall through */ 2196 + case FIB_EVENT_RULE_DEL: 2197 + rocker_world_fib4_abort(rocker); 2198 + break; 2199 + } 2200 + return NOTIFY_DONE; 2201 + } 2173 2202 2174 2203 /******************** 2175 2204 * ethtool interface ··· 2761 2740 goto err_probe_ports; 2762 2741 } 2763 2742 2743 + rocker->fib_nb.notifier_call = rocker_router_fib_event; 2744 + register_fib_notifier(&rocker->fib_nb); 2745 + 2764 2746 dev_info(&pdev->dev, "Rocker switch with id %*phN\n", 2765 2747 (int)sizeof(rocker->hw.id), &rocker->hw.id); 2766 2748 ··· 2795 2771 { 2796 2772 struct rocker *rocker = pci_get_drvdata(pdev); 2797 2773 2774 + unregister_fib_notifier(&rocker->fib_nb); 2798 2775 rocker_write32(rocker, CONTROL, ROCKER_CONTROL_RESET); 2799 2776 rocker_remove_ports(rocker); 2800 2777 free_irq(rocker_msix_vector(rocker, ROCKER_MSIX_VEC_EVENT), rocker); ··· 2822 2797 static bool rocker_port_dev_check(const struct net_device *dev) 2823 2798 { 2824 2799 return dev->netdev_ops == &rocker_port_netdev_ops; 2800 + } 2801 + 2802 + static bool rocker_port_dev_check_under(const struct net_device *dev, 2803 + struct rocker *rocker) 2804 + { 2805 + struct rocker_port *rocker_port; 2806 + 2807 + if (!rocker_port_dev_check(dev)) 2808 + return false; 2809 + 2810 + rocker_port = netdev_priv(dev); 2811 + if (rocker_port->rocker != rocker) 2812 + return false; 2813 + 2814 + return true; 2815 + } 2816 + 2817 + struct rocker_port *rocker_port_dev_lower_find(struct net_device *dev, 2818 + struct rocker *rocker) 2819 + { 2820 + struct net_device *lower_dev; 2821 + struct list_head *iter; 2822 + 2823 + if (rocker_port_dev_check_under(dev, rocker)) 2824 + return netdev_priv(dev); 2825 + 2826 + netdev_for_each_all_lower_dev(dev, lower_dev, iter) { 2827 + if (rocker_port_dev_check_under(lower_dev, rocker)) 2828 + return netdev_priv(lower_dev); 2829 + } 2830 + return NULL; 2825 2831 } 2826 2832 2827 2833 static int rocker_netdevice_event(struct notifier_block *unused,
+87 -28
drivers/net/ethernet/rocker/rocker_ofdpa.c
··· 99 99 struct ofdpa_flow_tbl_key key; 100 100 size_t key_len; 101 101 u32 key_crc32; /* key */ 102 + struct fib_info *fi; 102 103 }; 103 104 104 105 struct ofdpa_group_tbl_entry { ··· 190 189 spinlock_t neigh_tbl_lock; /* for neigh tbl accesses */ 191 190 u32 neigh_tbl_next_index; 192 191 unsigned long ageing_time; 192 + bool fib_aborted; 193 193 }; 194 194 195 195 struct ofdpa_port { ··· 1045 1043 __be16 eth_type, __be32 dst, 1046 1044 __be32 dst_mask, u32 priority, 1047 1045 enum rocker_of_dpa_table_id goto_tbl, 1048 - u32 group_id, int flags) 1046 + u32 group_id, struct fib_info *fi, 1047 + int flags) 1049 1048 { 1050 1049 struct ofdpa_flow_tbl_entry *entry; 1051 1050 ··· 1063 1060 entry->key.ucast_routing.group_id = group_id; 1064 1061 entry->key_len = offsetof(struct ofdpa_flow_tbl_key, 1065 1062 ucast_routing.group_id); 1063 + entry->fi = fi; 1066 1064 1067 1065 return ofdpa_flow_tbl_do(ofdpa_port, trans, flags, entry); 1068 1066 } ··· 1429 1425 eth_type, ip_addr, 1430 1426 inet_make_mask(32), 1431 1427 priority, goto_tbl, 1432 - group_id, flags); 1428 + group_id, NULL, flags); 1433 1429 1434 1430 if (err) 1435 1431 netdev_err(ofdpa_port->dev, "Error (%d) /32 unicast route %pI4 group 0x%08x\n", ··· 2394 2390 2395 2391 static int ofdpa_port_fib_ipv4(struct ofdpa_port *ofdpa_port, 2396 2392 struct switchdev_trans *trans, __be32 dst, 2397 - int dst_len, const struct fib_info *fi, 2393 + int dst_len, struct fib_info *fi, 2398 2394 u32 tb_id, int flags) 2399 2395 { 2400 2396 const struct fib_nh *nh; ··· 2430 2426 2431 2427 err = ofdpa_flow_tbl_ucast4_routing(ofdpa_port, trans, eth_type, dst, 2432 2428 dst_mask, priority, goto_tbl, 2433 - group_id, flags); 2429 + group_id, fi, flags); 2434 2430 if (err) 2435 2431 netdev_err(ofdpa_port->dev, "Error (%d) IPv4 route %pI4\n", 2436 2432 err, &dst); ··· 2722 2718 return err; 2723 2719 } 2724 2720 2725 - static int ofdpa_port_obj_fib4_add(struct rocker_port *rocker_port, 2726 - const struct switchdev_obj_ipv4_fib *fib4, 2727 - struct switchdev_trans *trans) 2728 - { 2729 - struct ofdpa_port *ofdpa_port = rocker_port->wpriv; 2730 - 2731 - return ofdpa_port_fib_ipv4(ofdpa_port, trans, 2732 - htonl(fib4->dst), fib4->dst_len, 2733 - fib4->fi, fib4->tb_id, 0); 2734 - } 2735 - 2736 - static int ofdpa_port_obj_fib4_del(struct rocker_port *rocker_port, 2737 - const struct switchdev_obj_ipv4_fib *fib4) 2738 - { 2739 - struct ofdpa_port *ofdpa_port = rocker_port->wpriv; 2740 - 2741 - return ofdpa_port_fib_ipv4(ofdpa_port, NULL, 2742 - htonl(fib4->dst), fib4->dst_len, 2743 - fib4->fi, fib4->tb_id, 2744 - OFDPA_OP_FLAG_REMOVE); 2745 - } 2746 - 2747 2721 static int ofdpa_port_obj_fdb_add(struct rocker_port *rocker_port, 2748 2722 const struct switchdev_obj_port_fdb *fdb, 2749 2723 struct switchdev_trans *trans) ··· 2904 2922 return ofdpa_port_fdb(ofdpa_port, NULL, addr, vlan_id, flags); 2905 2923 } 2906 2924 2925 + static struct ofdpa_port *ofdpa_port_dev_lower_find(struct net_device *dev, 2926 + struct rocker *rocker) 2927 + { 2928 + struct rocker_port *rocker_port; 2929 + 2930 + rocker_port = rocker_port_dev_lower_find(dev, rocker); 2931 + return rocker_port ? rocker_port->wpriv : NULL; 2932 + } 2933 + 2934 + static int ofdpa_fib4_add(struct rocker *rocker, 2935 + const struct fib_entry_notifier_info *fen_info) 2936 + { 2937 + struct ofdpa *ofdpa = rocker->wpriv; 2938 + struct ofdpa_port *ofdpa_port; 2939 + int err; 2940 + 2941 + if (ofdpa->fib_aborted) 2942 + return 0; 2943 + ofdpa_port = ofdpa_port_dev_lower_find(fen_info->fi->fib_dev, rocker); 2944 + if (!ofdpa_port) 2945 + return 0; 2946 + err = ofdpa_port_fib_ipv4(ofdpa_port, NULL, htonl(fen_info->dst), 2947 + fen_info->dst_len, fen_info->fi, 2948 + fen_info->tb_id, 0); 2949 + if (err) 2950 + return err; 2951 + fib_info_offload_inc(fen_info->fi); 2952 + return 0; 2953 + } 2954 + 2955 + static int ofdpa_fib4_del(struct rocker *rocker, 2956 + const struct fib_entry_notifier_info *fen_info) 2957 + { 2958 + struct ofdpa *ofdpa = rocker->wpriv; 2959 + struct ofdpa_port *ofdpa_port; 2960 + 2961 + if (ofdpa->fib_aborted) 2962 + return 0; 2963 + ofdpa_port = ofdpa_port_dev_lower_find(fen_info->fi->fib_dev, rocker); 2964 + if (!ofdpa_port) 2965 + return 0; 2966 + fib_info_offload_dec(fen_info->fi); 2967 + return ofdpa_port_fib_ipv4(ofdpa_port, NULL, htonl(fen_info->dst), 2968 + fen_info->dst_len, fen_info->fi, 2969 + fen_info->tb_id, OFDPA_OP_FLAG_REMOVE); 2970 + } 2971 + 2972 + static void ofdpa_fib4_abort(struct rocker *rocker) 2973 + { 2974 + struct ofdpa *ofdpa = rocker->wpriv; 2975 + struct ofdpa_port *ofdpa_port; 2976 + struct ofdpa_flow_tbl_entry *flow_entry; 2977 + struct hlist_node *tmp; 2978 + unsigned long flags; 2979 + int bkt; 2980 + 2981 + if (ofdpa->fib_aborted) 2982 + return; 2983 + 2984 + spin_lock_irqsave(&ofdpa->flow_tbl_lock, flags); 2985 + hash_for_each_safe(ofdpa->flow_tbl, bkt, tmp, flow_entry, entry) { 2986 + if (flow_entry->key.tbl_id != 2987 + ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING) 2988 + continue; 2989 + ofdpa_port = ofdpa_port_dev_lower_find(flow_entry->fi->fib_dev, 2990 + rocker); 2991 + if (!ofdpa_port) 2992 + continue; 2993 + fib_info_offload_dec(flow_entry->fi); 2994 + ofdpa_flow_tbl_del(ofdpa_port, NULL, OFDPA_OP_FLAG_REMOVE, 2995 + flow_entry); 2996 + } 2997 + spin_unlock_irqrestore(&ofdpa->flow_tbl_lock, flags); 2998 + ofdpa->fib_aborted = true; 2999 + } 3000 + 2907 3001 struct rocker_world_ops rocker_ofdpa_ops = { 2908 3002 .kind = "ofdpa", 2909 3003 .priv_size = sizeof(struct ofdpa), ··· 2999 2941 .port_obj_vlan_add = ofdpa_port_obj_vlan_add, 3000 2942 .port_obj_vlan_del = ofdpa_port_obj_vlan_del, 3001 2943 .port_obj_vlan_dump = ofdpa_port_obj_vlan_dump, 3002 - .port_obj_fib4_add = ofdpa_port_obj_fib4_add, 3003 - .port_obj_fib4_del = ofdpa_port_obj_fib4_del, 3004 2944 .port_obj_fdb_add = ofdpa_port_obj_fdb_add, 3005 2945 .port_obj_fdb_del = ofdpa_port_obj_fdb_del, 3006 2946 .port_obj_fdb_dump = ofdpa_port_obj_fdb_dump, ··· 3007 2951 .port_neigh_update = ofdpa_port_neigh_update, 3008 2952 .port_neigh_destroy = ofdpa_port_neigh_destroy, 3009 2953 .port_ev_mac_vlan_seen = ofdpa_port_ev_mac_vlan_seen, 2954 + .fib4_add = ofdpa_fib4_add, 2955 + .fib4_del = ofdpa_fib4_del, 2956 + .fib4_abort = ofdpa_fib4_abort, 3010 2957 };
+44 -5
include/net/ip_fib.h
··· 22 22 #include <net/fib_rules.h> 23 23 #include <net/inetpeer.h> 24 24 #include <linux/percpu.h> 25 + #include <linux/notifier.h> 25 26 26 27 struct fib_config { 27 28 u8 fc_dst_len; ··· 123 122 #ifdef CONFIG_IP_ROUTE_MULTIPATH 124 123 int fib_weight; 125 124 #endif 125 + unsigned int fib_offload_cnt; 126 126 struct rcu_head rcu; 127 127 struct fib_nh fib_nh[0]; 128 128 #define fib_dev fib_nh[0].nh_dev ··· 175 173 176 174 __be32 fib_info_update_nh_saddr(struct net *net, struct fib_nh *nh); 177 175 176 + static inline void fib_info_offload_inc(struct fib_info *fi) 177 + { 178 + fi->fib_offload_cnt++; 179 + fi->fib_flags |= RTNH_F_OFFLOAD; 180 + } 181 + 182 + static inline void fib_info_offload_dec(struct fib_info *fi) 183 + { 184 + if (--fi->fib_offload_cnt == 0) 185 + fi->fib_flags &= ~RTNH_F_OFFLOAD; 186 + } 187 + 178 188 #define FIB_RES_SADDR(net, res) \ 179 189 ((FIB_RES_NH(res).nh_saddr_genid == \ 180 190 atomic_read(&(net)->ipv4.dev_addr_genid)) ? \ ··· 199 185 #define FIB_RES_PREFSRC(net, res) ((res).fi->fib_prefsrc ? : \ 200 186 FIB_RES_SADDR(net, res)) 201 187 188 + struct fib_notifier_info { 189 + struct net *net; 190 + }; 191 + 192 + struct fib_entry_notifier_info { 193 + struct fib_notifier_info info; /* must be first */ 194 + u32 dst; 195 + int dst_len; 196 + struct fib_info *fi; 197 + u8 tos; 198 + u8 type; 199 + u32 tb_id; 200 + u32 nlflags; 201 + }; 202 + 203 + enum fib_event_type { 204 + FIB_EVENT_ENTRY_ADD, 205 + FIB_EVENT_ENTRY_DEL, 206 + FIB_EVENT_RULE_ADD, 207 + FIB_EVENT_RULE_DEL, 208 + }; 209 + 210 + int register_fib_notifier(struct notifier_block *nb); 211 + int unregister_fib_notifier(struct notifier_block *nb); 212 + int call_fib_notifiers(struct net *net, enum fib_event_type event_type, 213 + struct fib_notifier_info *info); 214 + 202 215 struct fib_table { 203 216 struct hlist_node tb_hlist; 204 217 u32 tb_id; ··· 237 196 238 197 int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp, 239 198 struct fib_result *res, int fib_flags); 240 - int fib_table_insert(struct fib_table *, struct fib_config *); 241 - int fib_table_delete(struct fib_table *, struct fib_config *); 199 + int fib_table_insert(struct net *, struct fib_table *, struct fib_config *); 200 + int fib_table_delete(struct net *, struct fib_table *, struct fib_config *); 242 201 int fib_table_dump(struct fib_table *table, struct sk_buff *skb, 243 202 struct netlink_callback *cb); 244 - int fib_table_flush(struct fib_table *table); 203 + int fib_table_flush(struct net *net, struct fib_table *table); 245 204 struct fib_table *fib_trie_unmerge(struct fib_table *main_tb); 246 - void fib_table_flush_external(struct fib_table *table); 247 205 void fib_free_table(struct fib_table *tb); 248 206 249 207 #ifndef CONFIG_IP_MULTIPLE_TABLES ··· 355 315 } 356 316 #endif 357 317 int fib_unmerge(struct net *net); 358 - void fib_flush_external(struct net *net); 359 318 360 319 /* Exported by fib_semantics.c */ 361 320 int ip_fib_check_default(__be32 gw, struct net_device *dev);
-40
include/net/switchdev.h
··· 68 68 enum switchdev_obj_id { 69 69 SWITCHDEV_OBJ_ID_UNDEFINED, 70 70 SWITCHDEV_OBJ_ID_PORT_VLAN, 71 - SWITCHDEV_OBJ_ID_IPV4_FIB, 72 71 SWITCHDEV_OBJ_ID_PORT_FDB, 73 72 SWITCHDEV_OBJ_ID_PORT_MDB, 74 73 }; ··· 90 91 91 92 #define SWITCHDEV_OBJ_PORT_VLAN(obj) \ 92 93 container_of(obj, struct switchdev_obj_port_vlan, obj) 93 - 94 - /* SWITCHDEV_OBJ_ID_IPV4_FIB */ 95 - struct switchdev_obj_ipv4_fib { 96 - struct switchdev_obj obj; 97 - u32 dst; 98 - int dst_len; 99 - struct fib_info *fi; 100 - u8 tos; 101 - u8 type; 102 - u32 nlflags; 103 - u32 tb_id; 104 - }; 105 - 106 - #define SWITCHDEV_OBJ_IPV4_FIB(obj) \ 107 - container_of(obj, struct switchdev_obj_ipv4_fib, obj) 108 94 109 95 /* SWITCHDEV_OBJ_ID_PORT_FDB */ 110 96 struct switchdev_obj_port_fdb { ··· 193 209 struct nlmsghdr *nlh, u16 flags); 194 210 int switchdev_port_bridge_dellink(struct net_device *dev, 195 211 struct nlmsghdr *nlh, u16 flags); 196 - int switchdev_fib_ipv4_add(u32 dst, int dst_len, struct fib_info *fi, 197 - u8 tos, u8 type, u32 nlflags, u32 tb_id); 198 - int switchdev_fib_ipv4_del(u32 dst, int dst_len, struct fib_info *fi, 199 - u8 tos, u8 type, u32 tb_id); 200 - void switchdev_fib_ipv4_abort(struct fib_info *fi); 201 212 int switchdev_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], 202 213 struct net_device *dev, const unsigned char *addr, 203 214 u16 vid, u16 nlm_flags); ··· 281 302 u16 flags) 282 303 { 283 304 return -EOPNOTSUPP; 284 - } 285 - 286 - static inline int switchdev_fib_ipv4_add(u32 dst, int dst_len, 287 - struct fib_info *fi, 288 - u8 tos, u8 type, 289 - u32 nlflags, u32 tb_id) 290 - { 291 - return 0; 292 - } 293 - 294 - static inline int switchdev_fib_ipv4_del(u32 dst, int dst_len, 295 - struct fib_info *fi, 296 - u8 tos, u8 type, u32 tb_id) 297 - { 298 - return 0; 299 - } 300 - 301 - static inline void switchdev_fib_ipv4_abort(struct fib_info *fi) 302 - { 303 305 } 304 306 305 307 static inline int switchdev_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
+8 -21
net/ipv4/fib_frontend.c
··· 182 182 struct fib_table *tb; 183 183 184 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 188 if (flushed) 189 189 rt_cache_flush(net); 190 - } 191 - 192 - void 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 190 } 204 191 205 192 /* ··· 577 590 if (cmd == SIOCDELRT) { 578 591 tb = fib_get_table(net, cfg.fc_table); 579 592 if (tb) 580 - err = fib_table_delete(tb, &cfg); 593 + err = fib_table_delete(net, tb, &cfg); 581 594 else 582 595 err = -ESRCH; 583 596 } else { 584 597 tb = fib_new_table(net, cfg.fc_table); 585 598 if (tb) 586 - err = fib_table_insert(tb, &cfg); 599 + err = fib_table_insert(net, tb, &cfg); 587 600 else 588 601 err = -ENOBUFS; 589 602 } ··· 706 719 goto errout; 707 720 } 708 721 709 - err = fib_table_delete(tb, &cfg); 722 + err = fib_table_delete(net, tb, &cfg); 710 723 errout: 711 724 return err; 712 725 } ··· 728 741 goto errout; 729 742 } 730 743 731 - err = fib_table_insert(tb, &cfg); 744 + err = fib_table_insert(net, tb, &cfg); 732 745 errout: 733 746 return err; 734 747 } ··· 815 828 cfg.fc_scope = RT_SCOPE_HOST; 816 829 817 830 if (cmd == RTM_NEWROUTE) 818 - fib_table_insert(tb, &cfg); 831 + fib_table_insert(net, tb, &cfg); 819 832 else 820 - fib_table_delete(tb, &cfg); 833 + fib_table_delete(net, tb, &cfg); 821 834 } 822 835 823 836 void fib_add_ifaddr(struct in_ifaddr *ifa) ··· 1241 1254 1242 1255 hlist_for_each_entry_safe(tb, tmp, head, tb_hlist) { 1243 1256 hlist_del(&tb->tb_hlist); 1244 - fib_table_flush(tb); 1257 + fib_table_flush(net, tb); 1245 1258 fib_free_table(tb); 1246 1259 } 1247 1260 }
+10 -2
net/ipv4/fib_rules.c
··· 164 164 return NULL; 165 165 } 166 166 167 + static 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 + 167 175 static const struct nla_policy fib4_rule_policy[FRA_MAX+1] = { 168 176 FRA_GENERIC_POLICY, 169 177 [FRA_FLOW] = { .type = NLA_U32 }, ··· 228 220 rule4->tos = frh->tos; 229 221 230 222 net->ipv4.fib_has_custom_rules = true; 231 - fib_flush_external(rule->fr_net); 223 + call_fib_rule_notifiers(net, FIB_EVENT_RULE_ADD); 232 224 233 225 err = 0; 234 226 errout: ··· 250 242 net->ipv4.fib_num_tclassid_users--; 251 243 #endif 252 244 net->ipv4.fib_has_custom_rules = true; 253 - fib_flush_external(rule->fr_net); 245 + call_fib_rule_notifiers(net, FIB_EVENT_RULE_DEL); 254 246 errout: 255 247 return err; 256 248 }
+60 -106
net/ipv4/fib_trie.c
··· 73 73 #include <linux/slab.h> 74 74 #include <linux/export.h> 75 75 #include <linux/vmalloc.h> 76 + #include <linux/notifier.h> 76 77 #include <net/net_namespace.h> 77 78 #include <net/ip.h> 78 79 #include <net/protocol.h> ··· 81 80 #include <net/tcp.h> 82 81 #include <net/sock.h> 83 82 #include <net/ip_fib.h> 84 - #include <net/switchdev.h> 85 83 #include <trace/events/fib.h> 86 84 #include "fib_lookup.h" 85 + 86 + static BLOCKING_NOTIFIER_HEAD(fib_chain); 87 + 88 + int register_fib_notifier(struct notifier_block *nb) 89 + { 90 + return blocking_notifier_chain_register(&fib_chain, nb); 91 + } 92 + EXPORT_SYMBOL(register_fib_notifier); 93 + 94 + int unregister_fib_notifier(struct notifier_block *nb) 95 + { 96 + return blocking_notifier_chain_unregister(&fib_chain, nb); 97 + } 98 + EXPORT_SYMBOL(unregister_fib_notifier); 99 + 100 + int call_fib_notifiers(struct net *net, enum fib_event_type event_type, 101 + struct fib_notifier_info *info) 102 + { 103 + info->net = net; 104 + return blocking_notifier_call_chain(&fib_chain, event_type, info); 105 + } 106 + 107 + static int call_fib_entry_notifiers(struct net *net, 108 + enum fib_event_type event_type, u32 dst, 109 + int dst_len, struct fib_info *fi, 110 + u8 tos, u8 type, u32 tb_id, u32 nlflags) 111 + { 112 + struct fib_entry_notifier_info info = { 113 + .dst = dst, 114 + .dst_len = dst_len, 115 + .fi = fi, 116 + .tos = tos, 117 + .type = type, 118 + .tb_id = tb_id, 119 + .nlflags = nlflags, 120 + }; 121 + return call_fib_notifiers(net, event_type, &info.info); 122 + } 87 123 88 124 #define MAX_STAT_DEPTH 32 89 125 ··· 1114 1076 } 1115 1077 1116 1078 /* Caller must hold RTNL. */ 1117 - int fib_table_insert(struct fib_table *tb, struct fib_config *cfg) 1079 + int fib_table_insert(struct net *net, struct fib_table *tb, 1080 + struct fib_config *cfg) 1118 1081 { 1119 1082 struct trie *t = (struct trie *)tb->tb_data; 1120 1083 struct fib_alias *fa, *new_fa; ··· 1214 1175 new_fa->tb_id = tb->tb_id; 1215 1176 new_fa->fa_default = -1; 1216 1177 1217 - err = switchdev_fib_ipv4_add(key, plen, fi, 1218 - new_fa->fa_tos, 1219 - cfg->fc_type, 1220 - cfg->fc_nlflags, 1221 - tb->tb_id); 1222 - if (err) { 1223 - switchdev_fib_ipv4_abort(fi); 1224 - kmem_cache_free(fn_alias_kmem, new_fa); 1225 - goto out; 1226 - } 1227 - 1228 1178 hlist_replace_rcu(&fa->fa_list, &new_fa->fa_list); 1229 1179 1230 1180 alias_free_mem_rcu(fa); ··· 1221 1193 fib_release_info(fi_drop); 1222 1194 if (state & FA_S_ACCESSED) 1223 1195 rt_cache_flush(cfg->fc_nlinfo.nl_net); 1196 + 1197 + call_fib_entry_notifiers(net, FIB_EVENT_ENTRY_ADD, 1198 + key, plen, fi, 1199 + new_fa->fa_tos, cfg->fc_type, 1200 + tb->tb_id, cfg->fc_nlflags); 1224 1201 rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, 1225 1202 tb->tb_id, &cfg->fc_nlinfo, nlflags); 1226 1203 ··· 1261 1228 new_fa->tb_id = tb->tb_id; 1262 1229 new_fa->fa_default = -1; 1263 1230 1264 - /* (Optionally) offload fib entry to switch hardware. */ 1265 - err = switchdev_fib_ipv4_add(key, plen, fi, tos, cfg->fc_type, 1266 - cfg->fc_nlflags, tb->tb_id); 1267 - if (err) { 1268 - switchdev_fib_ipv4_abort(fi); 1269 - goto out_free_new_fa; 1270 - } 1271 - 1272 1231 /* Insert new entry to the list. */ 1273 1232 err = fib_insert_alias(t, tp, l, new_fa, fa, key); 1274 1233 if (err) 1275 - goto out_sw_fib_del; 1234 + goto out_free_new_fa; 1276 1235 1277 1236 if (!plen) 1278 1237 tb->tb_num_default++; 1279 1238 1280 1239 rt_cache_flush(cfg->fc_nlinfo.nl_net); 1240 + call_fib_entry_notifiers(net, FIB_EVENT_ENTRY_ADD, key, plen, fi, tos, 1241 + cfg->fc_type, tb->tb_id, cfg->fc_nlflags); 1281 1242 rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, new_fa->tb_id, 1282 1243 &cfg->fc_nlinfo, nlflags); 1283 1244 succeeded: 1284 1245 return 0; 1285 1246 1286 - out_sw_fib_del: 1287 - switchdev_fib_ipv4_del(key, plen, fi, tos, cfg->fc_type, tb->tb_id); 1288 1247 out_free_new_fa: 1289 1248 kmem_cache_free(fn_alias_kmem, new_fa); 1290 1249 out: ··· 1515 1490 } 1516 1491 1517 1492 /* Caller must hold RTNL. */ 1518 - int fib_table_delete(struct fib_table *tb, struct fib_config *cfg) 1493 + int fib_table_delete(struct net *net, struct fib_table *tb, 1494 + struct fib_config *cfg) 1519 1495 { 1520 1496 struct trie *t = (struct trie *) tb->tb_data; 1521 1497 struct fib_alias *fa, *fa_to_delete; ··· 1569 1543 if (!fa_to_delete) 1570 1544 return -ESRCH; 1571 1545 1572 - switchdev_fib_ipv4_del(key, plen, fa_to_delete->fa_info, tos, 1573 - cfg->fc_type, tb->tb_id); 1574 - 1546 + call_fib_entry_notifiers(net, FIB_EVENT_ENTRY_DEL, key, plen, 1547 + fa_to_delete->fa_info, tos, cfg->fc_type, 1548 + tb->tb_id, 0); 1575 1549 rtmsg_fib(RTM_DELROUTE, htonl(key), fa_to_delete, plen, tb->tb_id, 1576 1550 &cfg->fc_nlinfo, 0); 1577 1551 ··· 1760 1734 return NULL; 1761 1735 } 1762 1736 1763 - /* Caller must hold RTNL */ 1764 - void fib_table_flush_external(struct fib_table *tb) 1765 - { 1766 - struct trie *t = (struct trie *)tb->tb_data; 1767 - struct key_vector *pn = t->kv; 1768 - unsigned long cindex = 1; 1769 - struct hlist_node *tmp; 1770 - struct fib_alias *fa; 1771 - 1772 - /* walk trie in reverse order */ 1773 - for (;;) { 1774 - unsigned char slen = 0; 1775 - struct key_vector *n; 1776 - 1777 - if (!(cindex--)) { 1778 - t_key pkey = pn->key; 1779 - 1780 - /* cannot resize the trie vector */ 1781 - if (IS_TRIE(pn)) 1782 - break; 1783 - 1784 - /* resize completed node */ 1785 - pn = resize(t, pn); 1786 - cindex = get_index(pkey, pn); 1787 - 1788 - continue; 1789 - } 1790 - 1791 - /* grab the next available node */ 1792 - n = get_child(pn, cindex); 1793 - if (!n) 1794 - continue; 1795 - 1796 - if (IS_TNODE(n)) { 1797 - /* record pn and cindex for leaf walking */ 1798 - pn = n; 1799 - cindex = 1ul << n->bits; 1800 - 1801 - continue; 1802 - } 1803 - 1804 - hlist_for_each_entry_safe(fa, tmp, &n->leaf, fa_list) { 1805 - struct fib_info *fi = fa->fa_info; 1806 - 1807 - /* if alias was cloned to local then we just 1808 - * need to remove the local copy from main 1809 - */ 1810 - if (tb->tb_id != fa->tb_id) { 1811 - hlist_del_rcu(&fa->fa_list); 1812 - alias_free_mem_rcu(fa); 1813 - continue; 1814 - } 1815 - 1816 - /* record local slen */ 1817 - slen = fa->fa_slen; 1818 - 1819 - if (!fi || !(fi->fib_flags & RTNH_F_OFFLOAD)) 1820 - continue; 1821 - 1822 - switchdev_fib_ipv4_del(n->key, KEYLENGTH - fa->fa_slen, 1823 - fi, fa->fa_tos, fa->fa_type, 1824 - tb->tb_id); 1825 - } 1826 - 1827 - /* update leaf slen */ 1828 - n->slen = slen; 1829 - 1830 - if (hlist_empty(&n->leaf)) { 1831 - put_child_root(pn, n->key, NULL); 1832 - node_free(n); 1833 - } 1834 - } 1835 - } 1836 - 1837 1737 /* Caller must hold RTNL. */ 1838 - int fib_table_flush(struct fib_table *tb) 1738 + int fib_table_flush(struct net *net, struct fib_table *tb) 1839 1739 { 1840 1740 struct trie *t = (struct trie *)tb->tb_data; 1841 1741 struct key_vector *pn = t->kv; ··· 1810 1858 continue; 1811 1859 } 1812 1860 1813 - switchdev_fib_ipv4_del(n->key, KEYLENGTH - fa->fa_slen, 1814 - fi, fa->fa_tos, fa->fa_type, 1815 - tb->tb_id); 1861 + call_fib_entry_notifiers(net, FIB_EVENT_ENTRY_DEL, 1862 + n->key, 1863 + KEYLENGTH - fa->fa_slen, 1864 + fi, fa->fa_tos, fa->fa_type, 1865 + tb->tb_id, 0); 1816 1866 hlist_del_rcu(&fa->fa_list); 1817 1867 fib_release_info(fa->fa_info); 1818 1868 alias_free_mem_rcu(fa);
-181
net/switchdev/switchdev.c
··· 21 21 #include <linux/workqueue.h> 22 22 #include <linux/if_vlan.h> 23 23 #include <linux/rtnetlink.h> 24 - #include <net/ip_fib.h> 25 24 #include <net/switchdev.h> 26 25 27 26 /** ··· 343 344 switch (obj->id) { 344 345 case SWITCHDEV_OBJ_ID_PORT_VLAN: 345 346 return sizeof(struct switchdev_obj_port_vlan); 346 - case SWITCHDEV_OBJ_ID_IPV4_FIB: 347 - return sizeof(struct switchdev_obj_ipv4_fib); 348 347 case SWITCHDEV_OBJ_ID_PORT_FDB: 349 348 return sizeof(struct switchdev_obj_port_fdb); 350 349 case SWITCHDEV_OBJ_ID_PORT_MDB: ··· 1104 1107 return err; 1105 1108 } 1106 1109 EXPORT_SYMBOL_GPL(switchdev_port_fdb_dump); 1107 - 1108 - static struct net_device *switchdev_get_lowest_dev(struct net_device *dev) 1109 - { 1110 - const struct switchdev_ops *ops = dev->switchdev_ops; 1111 - struct net_device *lower_dev; 1112 - struct net_device *port_dev; 1113 - struct list_head *iter; 1114 - 1115 - /* Recusively search down until we find a sw port dev. 1116 - * (A sw port dev supports switchdev_port_attr_get). 1117 - */ 1118 - 1119 - if (ops && ops->switchdev_port_attr_get) 1120 - return dev; 1121 - 1122 - netdev_for_each_lower_dev(dev, lower_dev, iter) { 1123 - port_dev = switchdev_get_lowest_dev(lower_dev); 1124 - if (port_dev) 1125 - return port_dev; 1126 - } 1127 - 1128 - return NULL; 1129 - } 1130 - 1131 - static struct net_device *switchdev_get_dev_by_nhs(struct fib_info *fi) 1132 - { 1133 - struct switchdev_attr attr = { 1134 - .id = SWITCHDEV_ATTR_ID_PORT_PARENT_ID, 1135 - }; 1136 - struct switchdev_attr prev_attr; 1137 - struct net_device *dev = NULL; 1138 - int nhsel; 1139 - 1140 - ASSERT_RTNL(); 1141 - 1142 - /* For this route, all nexthop devs must be on the same switch. */ 1143 - 1144 - for (nhsel = 0; nhsel < fi->fib_nhs; nhsel++) { 1145 - const struct fib_nh *nh = &fi->fib_nh[nhsel]; 1146 - 1147 - if (!nh->nh_dev) 1148 - return NULL; 1149 - 1150 - dev = switchdev_get_lowest_dev(nh->nh_dev); 1151 - if (!dev) 1152 - return NULL; 1153 - 1154 - attr.orig_dev = dev; 1155 - if (switchdev_port_attr_get(dev, &attr)) 1156 - return NULL; 1157 - 1158 - if (nhsel > 0 && 1159 - !netdev_phys_item_id_same(&prev_attr.u.ppid, &attr.u.ppid)) 1160 - return NULL; 1161 - 1162 - prev_attr = attr; 1163 - } 1164 - 1165 - return dev; 1166 - } 1167 - 1168 - /** 1169 - * switchdev_fib_ipv4_add - Add/modify switch IPv4 route entry 1170 - * 1171 - * @dst: route's IPv4 destination address 1172 - * @dst_len: destination address length (prefix length) 1173 - * @fi: route FIB info structure 1174 - * @tos: route TOS 1175 - * @type: route type 1176 - * @nlflags: netlink flags passed in (NLM_F_*) 1177 - * @tb_id: route table ID 1178 - * 1179 - * Add/modify switch IPv4 route entry. 1180 - */ 1181 - int switchdev_fib_ipv4_add(u32 dst, int dst_len, struct fib_info *fi, 1182 - u8 tos, u8 type, u32 nlflags, u32 tb_id) 1183 - { 1184 - struct switchdev_obj_ipv4_fib ipv4_fib = { 1185 - .obj.id = SWITCHDEV_OBJ_ID_IPV4_FIB, 1186 - .dst = dst, 1187 - .dst_len = dst_len, 1188 - .fi = fi, 1189 - .tos = tos, 1190 - .type = type, 1191 - .nlflags = nlflags, 1192 - .tb_id = tb_id, 1193 - }; 1194 - struct net_device *dev; 1195 - int err = 0; 1196 - 1197 - /* Don't offload route if using custom ip rules or if 1198 - * IPv4 FIB offloading has been disabled completely. 1199 - */ 1200 - 1201 - #ifdef CONFIG_IP_MULTIPLE_TABLES 1202 - if (fi->fib_net->ipv4.fib_has_custom_rules) 1203 - return 0; 1204 - #endif 1205 - 1206 - if (fi->fib_net->ipv4.fib_offload_disabled) 1207 - return 0; 1208 - 1209 - dev = switchdev_get_dev_by_nhs(fi); 1210 - if (!dev) 1211 - return 0; 1212 - 1213 - ipv4_fib.obj.orig_dev = dev; 1214 - err = switchdev_port_obj_add(dev, &ipv4_fib.obj); 1215 - if (!err) 1216 - fi->fib_flags |= RTNH_F_OFFLOAD; 1217 - 1218 - return err == -EOPNOTSUPP ? 0 : err; 1219 - } 1220 - EXPORT_SYMBOL_GPL(switchdev_fib_ipv4_add); 1221 - 1222 - /** 1223 - * switchdev_fib_ipv4_del - Delete IPv4 route entry from switch 1224 - * 1225 - * @dst: route's IPv4 destination address 1226 - * @dst_len: destination address length (prefix length) 1227 - * @fi: route FIB info structure 1228 - * @tos: route TOS 1229 - * @type: route type 1230 - * @tb_id: route table ID 1231 - * 1232 - * Delete IPv4 route entry from switch device. 1233 - */ 1234 - int switchdev_fib_ipv4_del(u32 dst, int dst_len, struct fib_info *fi, 1235 - u8 tos, u8 type, u32 tb_id) 1236 - { 1237 - struct switchdev_obj_ipv4_fib ipv4_fib = { 1238 - .obj.id = SWITCHDEV_OBJ_ID_IPV4_FIB, 1239 - .dst = dst, 1240 - .dst_len = dst_len, 1241 - .fi = fi, 1242 - .tos = tos, 1243 - .type = type, 1244 - .nlflags = 0, 1245 - .tb_id = tb_id, 1246 - }; 1247 - struct net_device *dev; 1248 - int err = 0; 1249 - 1250 - if (!(fi->fib_flags & RTNH_F_OFFLOAD)) 1251 - return 0; 1252 - 1253 - dev = switchdev_get_dev_by_nhs(fi); 1254 - if (!dev) 1255 - return 0; 1256 - 1257 - ipv4_fib.obj.orig_dev = dev; 1258 - err = switchdev_port_obj_del(dev, &ipv4_fib.obj); 1259 - if (!err) 1260 - fi->fib_flags &= ~RTNH_F_OFFLOAD; 1261 - 1262 - return err == -EOPNOTSUPP ? 0 : err; 1263 - } 1264 - EXPORT_SYMBOL_GPL(switchdev_fib_ipv4_del); 1265 - 1266 - /** 1267 - * switchdev_fib_ipv4_abort - Abort an IPv4 FIB operation 1268 - * 1269 - * @fi: route FIB info structure 1270 - */ 1271 - void switchdev_fib_ipv4_abort(struct fib_info *fi) 1272 - { 1273 - /* There was a problem installing this route to the offload 1274 - * device. For now, until we come up with more refined 1275 - * policy handling, abruptly end IPv4 fib offloading for 1276 - * for entire net by flushing offload device(s) of all 1277 - * IPv4 routes, and mark IPv4 fib offloading broken from 1278 - * this point forward. 1279 - */ 1280 - 1281 - fib_flush_external(fi->fib_net); 1282 - fi->fib_net->ipv4.fib_offload_disabled = true; 1283 - } 1284 - EXPORT_SYMBOL_GPL(switchdev_fib_ipv4_abort); 1285 1110 1286 1111 bool switchdev_port_same_parent_id(struct net_device *a, 1287 1112 struct net_device *b)