diff options
-rw-r--r-- | drivers/net/ethernet/rocker/rocker.h | 15 | ||||
-rw-r--r-- | drivers/net/ethernet/rocker/rocker_main.c | 120 | ||||
-rw-r--r-- | drivers/net/ethernet/rocker/rocker_ofdpa.c | 115 |
3 files changed, 185 insertions, 65 deletions
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 | ||
56 | struct rocker_port *rocker_port_dev_lower_find(struct net_device *dev, | ||
57 | struct rocker *rocker); | ||
58 | |||
55 | struct rocker_world_ops; | 59 | struct rocker_world_ops; |
56 | 60 | ||
57 | struct rocker { | 61 | struct 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 | ||
146 | extern struct rocker_world_ops rocker_ofdpa_ops; | 151 | extern 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 | ||
1627 | static int | 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 | rocker_world_port_obj_fdb_add(struct rocker_port *rocker_port, | 1628 | rocker_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 | ||
1713 | static 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 | |||
1723 | static 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 | |||
1733 | static 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 | ||
2174 | static 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 | ||
2827 | static 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 | |||
2842 | struct 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 | |||
2802 | static int rocker_netdevice_event(struct notifier_block *unused, | 2858 | static 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 | ||
104 | struct ofdpa_group_tbl_entry { | 105 | struct 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 | ||
194 | struct ofdpa_port { | 196 | struct 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 | ||
2391 | static int ofdpa_port_fib_ipv4(struct ofdpa_port *ofdpa_port, | 2395 | static 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 | ||
2721 | static 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 | |||
2732 | static 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 | |||
2743 | static int ofdpa_port_obj_fdb_add(struct rocker_port *rocker_port, | 2725 | static 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 | ||
2907 | static 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 | |||
2916 | static 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 | |||
2937 | static 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 | |||
2954 | static 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 | |||
2925 | struct rocker_world_ops rocker_ofdpa_ops = { | 2983 | struct 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 | }; |