aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiri Pirko <jiri@mellanox.com>2016-09-26 06:52:31 -0400
committerDavid S. Miller <davem@davemloft.net>2016-09-28 04:48:00 -0400
commitb45f64d16d456fde027a220cc62d6b4cc315f97b (patch)
tree511588702e27d07674648f53af8a291be4fbc66f
parentc98501879b1b1af90c7325574f2672e9efca592c (diff)
mlxsw: spectrum_router: Use FIB notifications instead of switchdev calls
Until now, in order to offload a FIB entry to HW we use switchdev op. However that has limits. Mainly in case we need to make the HW aware of all route prefixes configured in kernel. HW needs to know those in order to properly trap appropriate packets and pass the to kernel to do the forwarding. Abort mechanism is now handled within the mlxsw driver. Signed-off-by: Jiri Pirko <jiri@mellanox.com> Reviewed-by: Ido Schimmel <idosch@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-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
3 files changed, 260 insertions, 195 deletions
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));