12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2e420114eSJiri Pirko /*
3e420114eSJiri Pirko * drivers/net/ethernet/rocker/rocker_ofdpa.c - Rocker switch OF-DPA-like
4e420114eSJiri Pirko * implementation
5e420114eSJiri Pirko * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com>
6e420114eSJiri Pirko * Copyright (c) 2014-2016 Jiri Pirko <jiri@mellanox.com>
7e420114eSJiri Pirko */
8e420114eSJiri Pirko
9e420114eSJiri Pirko #include <linux/kernel.h>
103fbcdbf3SJiri Pirko #include <linux/types.h>
113fbcdbf3SJiri Pirko #include <linux/spinlock.h>
123fbcdbf3SJiri Pirko #include <linux/hashtable.h>
133fbcdbf3SJiri Pirko #include <linux/crc32.h>
143fbcdbf3SJiri Pirko #include <linux/netdevice.h>
153fbcdbf3SJiri Pirko #include <linux/inetdevice.h>
163fbcdbf3SJiri Pirko #include <linux/if_vlan.h>
173fbcdbf3SJiri Pirko #include <linux/if_bridge.h>
183fbcdbf3SJiri Pirko #include <net/neighbour.h>
193fbcdbf3SJiri Pirko #include <net/switchdev.h>
203fbcdbf3SJiri Pirko #include <net/ip_fib.h>
215481d73fSDavid Ahern #include <net/nexthop.h>
223fbcdbf3SJiri Pirko #include <net/arp.h>
233fbcdbf3SJiri Pirko
24e420114eSJiri Pirko #include "rocker.h"
253fbcdbf3SJiri Pirko #include "rocker_tlv.h"
263fbcdbf3SJiri Pirko
273fbcdbf3SJiri Pirko struct ofdpa_flow_tbl_key {
283fbcdbf3SJiri Pirko u32 priority;
293fbcdbf3SJiri Pirko enum rocker_of_dpa_table_id tbl_id;
303fbcdbf3SJiri Pirko union {
313fbcdbf3SJiri Pirko struct {
323fbcdbf3SJiri Pirko u32 in_pport;
333fbcdbf3SJiri Pirko u32 in_pport_mask;
343fbcdbf3SJiri Pirko enum rocker_of_dpa_table_id goto_tbl;
353fbcdbf3SJiri Pirko } ig_port;
363fbcdbf3SJiri Pirko struct {
373fbcdbf3SJiri Pirko u32 in_pport;
383fbcdbf3SJiri Pirko __be16 vlan_id;
393fbcdbf3SJiri Pirko __be16 vlan_id_mask;
403fbcdbf3SJiri Pirko enum rocker_of_dpa_table_id goto_tbl;
413fbcdbf3SJiri Pirko bool untagged;
423fbcdbf3SJiri Pirko __be16 new_vlan_id;
433fbcdbf3SJiri Pirko } vlan;
443fbcdbf3SJiri Pirko struct {
453fbcdbf3SJiri Pirko u32 in_pport;
463fbcdbf3SJiri Pirko u32 in_pport_mask;
473fbcdbf3SJiri Pirko __be16 eth_type;
483fbcdbf3SJiri Pirko u8 eth_dst[ETH_ALEN];
493fbcdbf3SJiri Pirko u8 eth_dst_mask[ETH_ALEN];
503fbcdbf3SJiri Pirko __be16 vlan_id;
513fbcdbf3SJiri Pirko __be16 vlan_id_mask;
523fbcdbf3SJiri Pirko enum rocker_of_dpa_table_id goto_tbl;
533fbcdbf3SJiri Pirko bool copy_to_cpu;
543fbcdbf3SJiri Pirko } term_mac;
553fbcdbf3SJiri Pirko struct {
563fbcdbf3SJiri Pirko __be16 eth_type;
573fbcdbf3SJiri Pirko __be32 dst4;
583fbcdbf3SJiri Pirko __be32 dst4_mask;
593fbcdbf3SJiri Pirko enum rocker_of_dpa_table_id goto_tbl;
603fbcdbf3SJiri Pirko u32 group_id;
613fbcdbf3SJiri Pirko } ucast_routing;
623fbcdbf3SJiri Pirko struct {
633fbcdbf3SJiri Pirko u8 eth_dst[ETH_ALEN];
643fbcdbf3SJiri Pirko u8 eth_dst_mask[ETH_ALEN];
653fbcdbf3SJiri Pirko int has_eth_dst;
663fbcdbf3SJiri Pirko int has_eth_dst_mask;
673fbcdbf3SJiri Pirko __be16 vlan_id;
683fbcdbf3SJiri Pirko u32 tunnel_id;
693fbcdbf3SJiri Pirko enum rocker_of_dpa_table_id goto_tbl;
703fbcdbf3SJiri Pirko u32 group_id;
713fbcdbf3SJiri Pirko bool copy_to_cpu;
723fbcdbf3SJiri Pirko } bridge;
733fbcdbf3SJiri Pirko struct {
743fbcdbf3SJiri Pirko u32 in_pport;
753fbcdbf3SJiri Pirko u32 in_pport_mask;
763fbcdbf3SJiri Pirko u8 eth_src[ETH_ALEN];
773fbcdbf3SJiri Pirko u8 eth_src_mask[ETH_ALEN];
783fbcdbf3SJiri Pirko u8 eth_dst[ETH_ALEN];
793fbcdbf3SJiri Pirko u8 eth_dst_mask[ETH_ALEN];
803fbcdbf3SJiri Pirko __be16 eth_type;
813fbcdbf3SJiri Pirko __be16 vlan_id;
823fbcdbf3SJiri Pirko __be16 vlan_id_mask;
833fbcdbf3SJiri Pirko u8 ip_proto;
843fbcdbf3SJiri Pirko u8 ip_proto_mask;
853fbcdbf3SJiri Pirko u8 ip_tos;
863fbcdbf3SJiri Pirko u8 ip_tos_mask;
873fbcdbf3SJiri Pirko u32 group_id;
883fbcdbf3SJiri Pirko } acl;
893fbcdbf3SJiri Pirko };
903fbcdbf3SJiri Pirko };
913fbcdbf3SJiri Pirko
923fbcdbf3SJiri Pirko struct ofdpa_flow_tbl_entry {
933fbcdbf3SJiri Pirko struct hlist_node entry;
943fbcdbf3SJiri Pirko u32 cmd;
953fbcdbf3SJiri Pirko u64 cookie;
963fbcdbf3SJiri Pirko struct ofdpa_flow_tbl_key key;
973fbcdbf3SJiri Pirko size_t key_len;
983fbcdbf3SJiri Pirko u32 key_crc32; /* key */
99936bd486SJiri Pirko struct fib_info *fi;
1003fbcdbf3SJiri Pirko };
1013fbcdbf3SJiri Pirko
1023fbcdbf3SJiri Pirko struct ofdpa_group_tbl_entry {
1033fbcdbf3SJiri Pirko struct hlist_node entry;
1043fbcdbf3SJiri Pirko u32 cmd;
1053fbcdbf3SJiri Pirko u32 group_id; /* key */
1063fbcdbf3SJiri Pirko u16 group_count;
1073fbcdbf3SJiri Pirko u32 *group_ids;
1083fbcdbf3SJiri Pirko union {
1093fbcdbf3SJiri Pirko struct {
1103fbcdbf3SJiri Pirko u8 pop_vlan;
1113fbcdbf3SJiri Pirko } l2_interface;
1123fbcdbf3SJiri Pirko struct {
1133fbcdbf3SJiri Pirko u8 eth_src[ETH_ALEN];
1143fbcdbf3SJiri Pirko u8 eth_dst[ETH_ALEN];
1153fbcdbf3SJiri Pirko __be16 vlan_id;
1163fbcdbf3SJiri Pirko u32 group_id;
1173fbcdbf3SJiri Pirko } l2_rewrite;
1183fbcdbf3SJiri Pirko struct {
1193fbcdbf3SJiri Pirko u8 eth_src[ETH_ALEN];
1203fbcdbf3SJiri Pirko u8 eth_dst[ETH_ALEN];
1213fbcdbf3SJiri Pirko __be16 vlan_id;
1223fbcdbf3SJiri Pirko bool ttl_check;
1233fbcdbf3SJiri Pirko u32 group_id;
1243fbcdbf3SJiri Pirko } l3_unicast;
1253fbcdbf3SJiri Pirko };
1263fbcdbf3SJiri Pirko };
1273fbcdbf3SJiri Pirko
1283fbcdbf3SJiri Pirko struct ofdpa_fdb_tbl_entry {
1293fbcdbf3SJiri Pirko struct hlist_node entry;
1303fbcdbf3SJiri Pirko u32 key_crc32; /* key */
1313fbcdbf3SJiri Pirko bool learned;
1323fbcdbf3SJiri Pirko unsigned long touched;
1333fbcdbf3SJiri Pirko struct ofdpa_fdb_tbl_key {
1343fbcdbf3SJiri Pirko struct ofdpa_port *ofdpa_port;
1353fbcdbf3SJiri Pirko u8 addr[ETH_ALEN];
1363fbcdbf3SJiri Pirko __be16 vlan_id;
1373fbcdbf3SJiri Pirko } key;
1383fbcdbf3SJiri Pirko };
1393fbcdbf3SJiri Pirko
1403fbcdbf3SJiri Pirko struct ofdpa_internal_vlan_tbl_entry {
1413fbcdbf3SJiri Pirko struct hlist_node entry;
1423fbcdbf3SJiri Pirko int ifindex; /* key */
1433fbcdbf3SJiri Pirko u32 ref_count;
1443fbcdbf3SJiri Pirko __be16 vlan_id;
1453fbcdbf3SJiri Pirko };
1463fbcdbf3SJiri Pirko
1473fbcdbf3SJiri Pirko struct ofdpa_neigh_tbl_entry {
1483fbcdbf3SJiri Pirko struct hlist_node entry;
1493fbcdbf3SJiri Pirko __be32 ip_addr; /* key */
1503fbcdbf3SJiri Pirko struct net_device *dev;
1513fbcdbf3SJiri Pirko u32 ref_count;
1523fbcdbf3SJiri Pirko u32 index;
1533fbcdbf3SJiri Pirko u8 eth_dst[ETH_ALEN];
1543fbcdbf3SJiri Pirko bool ttl_check;
1553fbcdbf3SJiri Pirko };
1563fbcdbf3SJiri Pirko
1573fbcdbf3SJiri Pirko enum {
1583fbcdbf3SJiri Pirko OFDPA_CTRL_LINK_LOCAL_MCAST,
1593fbcdbf3SJiri Pirko OFDPA_CTRL_LOCAL_ARP,
1603fbcdbf3SJiri Pirko OFDPA_CTRL_IPV4_MCAST,
1613fbcdbf3SJiri Pirko OFDPA_CTRL_IPV6_MCAST,
1623fbcdbf3SJiri Pirko OFDPA_CTRL_DFLT_BRIDGING,
1633fbcdbf3SJiri Pirko OFDPA_CTRL_DFLT_OVS,
1643fbcdbf3SJiri Pirko OFDPA_CTRL_MAX,
1653fbcdbf3SJiri Pirko };
1663fbcdbf3SJiri Pirko
1673fbcdbf3SJiri Pirko #define OFDPA_INTERNAL_VLAN_ID_BASE 0x0f00
1683fbcdbf3SJiri Pirko #define OFDPA_N_INTERNAL_VLANS 255
1693fbcdbf3SJiri Pirko #define OFDPA_VLAN_BITMAP_LEN BITS_TO_LONGS(VLAN_N_VID)
1703fbcdbf3SJiri Pirko #define OFDPA_INTERNAL_VLAN_BITMAP_LEN BITS_TO_LONGS(OFDPA_N_INTERNAL_VLANS)
1713fbcdbf3SJiri Pirko #define OFDPA_UNTAGGED_VID 0
172e420114eSJiri Pirko
173e420114eSJiri Pirko struct ofdpa {
1743fbcdbf3SJiri Pirko struct rocker *rocker;
1753fbcdbf3SJiri Pirko DECLARE_HASHTABLE(flow_tbl, 16);
1763fbcdbf3SJiri Pirko spinlock_t flow_tbl_lock; /* for flow tbl accesses */
1773fbcdbf3SJiri Pirko u64 flow_tbl_next_cookie;
1783fbcdbf3SJiri Pirko DECLARE_HASHTABLE(group_tbl, 16);
1793fbcdbf3SJiri Pirko spinlock_t group_tbl_lock; /* for group tbl accesses */
1803fbcdbf3SJiri Pirko struct timer_list fdb_cleanup_timer;
1813fbcdbf3SJiri Pirko DECLARE_HASHTABLE(fdb_tbl, 16);
1823fbcdbf3SJiri Pirko spinlock_t fdb_tbl_lock; /* for fdb tbl accesses */
1833fbcdbf3SJiri Pirko unsigned long internal_vlan_bitmap[OFDPA_INTERNAL_VLAN_BITMAP_LEN];
1843fbcdbf3SJiri Pirko DECLARE_HASHTABLE(internal_vlan_tbl, 8);
1853fbcdbf3SJiri Pirko spinlock_t internal_vlan_tbl_lock; /* for vlan tbl accesses */
1863fbcdbf3SJiri Pirko DECLARE_HASHTABLE(neigh_tbl, 16);
1873fbcdbf3SJiri Pirko spinlock_t neigh_tbl_lock; /* for neigh tbl accesses */
1883fbcdbf3SJiri Pirko u32 neigh_tbl_next_index;
1893a8befcdSJiri Pirko unsigned long ageing_time;
190936bd486SJiri Pirko bool fib_aborted;
191e420114eSJiri Pirko };
192e420114eSJiri Pirko
193e420114eSJiri Pirko struct ofdpa_port {
1943fbcdbf3SJiri Pirko struct ofdpa *ofdpa;
1953fbcdbf3SJiri Pirko struct rocker_port *rocker_port;
1963fbcdbf3SJiri Pirko struct net_device *dev;
1973fbcdbf3SJiri Pirko u32 pport;
1983fbcdbf3SJiri Pirko struct net_device *bridge_dev;
1993fbcdbf3SJiri Pirko __be16 internal_vlan_id;
2003fbcdbf3SJiri Pirko int stp_state;
2013fbcdbf3SJiri Pirko u32 brport_flags;
2023fbcdbf3SJiri Pirko unsigned long ageing_time;
2033fbcdbf3SJiri Pirko bool ctrls[OFDPA_CTRL_MAX];
2043fbcdbf3SJiri Pirko unsigned long vlan_bitmap[OFDPA_VLAN_BITMAP_LEN];
205e420114eSJiri Pirko };
206e420114eSJiri Pirko
2073fbcdbf3SJiri Pirko static const u8 zero_mac[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
2083fbcdbf3SJiri Pirko static const u8 ff_mac[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
2093fbcdbf3SJiri Pirko static const u8 ll_mac[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
2103fbcdbf3SJiri Pirko static const u8 ll_mask[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0 };
2113fbcdbf3SJiri Pirko static const u8 mcast_mac[ETH_ALEN] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 };
2123fbcdbf3SJiri Pirko static const u8 ipv4_mcast[ETH_ALEN] = { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 };
2133fbcdbf3SJiri Pirko static const u8 ipv4_mask[ETH_ALEN] = { 0xff, 0xff, 0xff, 0x80, 0x00, 0x00 };
2143fbcdbf3SJiri Pirko static const u8 ipv6_mcast[ETH_ALEN] = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x00 };
2153fbcdbf3SJiri Pirko static const u8 ipv6_mask[ETH_ALEN] = { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 };
2163fbcdbf3SJiri Pirko
2173fbcdbf3SJiri Pirko /* Rocker priority levels for flow table entries. Higher
2183fbcdbf3SJiri Pirko * priority match takes precedence over lower priority match.
2193fbcdbf3SJiri Pirko */
2203fbcdbf3SJiri Pirko
2213fbcdbf3SJiri Pirko enum {
2223fbcdbf3SJiri Pirko OFDPA_PRIORITY_UNKNOWN = 0,
2233fbcdbf3SJiri Pirko OFDPA_PRIORITY_IG_PORT = 1,
2243fbcdbf3SJiri Pirko OFDPA_PRIORITY_VLAN = 1,
2253fbcdbf3SJiri Pirko OFDPA_PRIORITY_TERM_MAC_UCAST = 0,
2263fbcdbf3SJiri Pirko OFDPA_PRIORITY_TERM_MAC_MCAST = 1,
2273fbcdbf3SJiri Pirko OFDPA_PRIORITY_BRIDGING_VLAN_DFLT_EXACT = 1,
2283fbcdbf3SJiri Pirko OFDPA_PRIORITY_BRIDGING_VLAN_DFLT_WILD = 2,
2293fbcdbf3SJiri Pirko OFDPA_PRIORITY_BRIDGING_VLAN = 3,
2303fbcdbf3SJiri Pirko OFDPA_PRIORITY_BRIDGING_TENANT_DFLT_EXACT = 1,
2313fbcdbf3SJiri Pirko OFDPA_PRIORITY_BRIDGING_TENANT_DFLT_WILD = 2,
2323fbcdbf3SJiri Pirko OFDPA_PRIORITY_BRIDGING_TENANT = 3,
2333fbcdbf3SJiri Pirko OFDPA_PRIORITY_ACL_CTRL = 3,
2343fbcdbf3SJiri Pirko OFDPA_PRIORITY_ACL_NORMAL = 2,
2353fbcdbf3SJiri Pirko OFDPA_PRIORITY_ACL_DFLT = 1,
2363fbcdbf3SJiri Pirko };
2373fbcdbf3SJiri Pirko
ofdpa_vlan_id_is_internal(__be16 vlan_id)2383fbcdbf3SJiri Pirko static bool ofdpa_vlan_id_is_internal(__be16 vlan_id)
2393fbcdbf3SJiri Pirko {
2403fbcdbf3SJiri Pirko u16 start = OFDPA_INTERNAL_VLAN_ID_BASE;
2413fbcdbf3SJiri Pirko u16 end = 0xffe;
2423fbcdbf3SJiri Pirko u16 _vlan_id = ntohs(vlan_id);
2433fbcdbf3SJiri Pirko
2443fbcdbf3SJiri Pirko return (_vlan_id >= start && _vlan_id <= end);
2453fbcdbf3SJiri Pirko }
2463fbcdbf3SJiri Pirko
ofdpa_port_vid_to_vlan(const struct ofdpa_port * ofdpa_port,u16 vid,bool * pop_vlan)2473fbcdbf3SJiri Pirko static __be16 ofdpa_port_vid_to_vlan(const struct ofdpa_port *ofdpa_port,
2483fbcdbf3SJiri Pirko u16 vid, bool *pop_vlan)
2493fbcdbf3SJiri Pirko {
2503fbcdbf3SJiri Pirko __be16 vlan_id;
2513fbcdbf3SJiri Pirko
2523fbcdbf3SJiri Pirko if (pop_vlan)
2533fbcdbf3SJiri Pirko *pop_vlan = false;
2543fbcdbf3SJiri Pirko vlan_id = htons(vid);
2553fbcdbf3SJiri Pirko if (!vlan_id) {
2563fbcdbf3SJiri Pirko vlan_id = ofdpa_port->internal_vlan_id;
2573fbcdbf3SJiri Pirko if (pop_vlan)
2583fbcdbf3SJiri Pirko *pop_vlan = true;
2593fbcdbf3SJiri Pirko }
2603fbcdbf3SJiri Pirko
2613fbcdbf3SJiri Pirko return vlan_id;
2623fbcdbf3SJiri Pirko }
2633fbcdbf3SJiri Pirko
ofdpa_port_vlan_to_vid(const struct ofdpa_port * ofdpa_port,__be16 vlan_id)2643fbcdbf3SJiri Pirko static u16 ofdpa_port_vlan_to_vid(const struct ofdpa_port *ofdpa_port,
2653fbcdbf3SJiri Pirko __be16 vlan_id)
2663fbcdbf3SJiri Pirko {
2673fbcdbf3SJiri Pirko if (ofdpa_vlan_id_is_internal(vlan_id))
2683fbcdbf3SJiri Pirko return 0;
2693fbcdbf3SJiri Pirko
2703fbcdbf3SJiri Pirko return ntohs(vlan_id);
2713fbcdbf3SJiri Pirko }
2723fbcdbf3SJiri Pirko
ofdpa_port_is_slave(const struct ofdpa_port * ofdpa_port,const char * kind)2733fbcdbf3SJiri Pirko static bool ofdpa_port_is_slave(const struct ofdpa_port *ofdpa_port,
2743fbcdbf3SJiri Pirko const char *kind)
2753fbcdbf3SJiri Pirko {
2763fbcdbf3SJiri Pirko return ofdpa_port->bridge_dev &&
2773fbcdbf3SJiri Pirko !strcmp(ofdpa_port->bridge_dev->rtnl_link_ops->kind, kind);
2783fbcdbf3SJiri Pirko }
2793fbcdbf3SJiri Pirko
ofdpa_port_is_bridged(const struct ofdpa_port * ofdpa_port)2803fbcdbf3SJiri Pirko static bool ofdpa_port_is_bridged(const struct ofdpa_port *ofdpa_port)
2813fbcdbf3SJiri Pirko {
2823fbcdbf3SJiri Pirko return ofdpa_port_is_slave(ofdpa_port, "bridge");
2833fbcdbf3SJiri Pirko }
2843fbcdbf3SJiri Pirko
ofdpa_port_is_ovsed(const struct ofdpa_port * ofdpa_port)2853fbcdbf3SJiri Pirko static bool ofdpa_port_is_ovsed(const struct ofdpa_port *ofdpa_port)
2863fbcdbf3SJiri Pirko {
2873fbcdbf3SJiri Pirko return ofdpa_port_is_slave(ofdpa_port, "openvswitch");
2883fbcdbf3SJiri Pirko }
2893fbcdbf3SJiri Pirko
2903fbcdbf3SJiri Pirko #define OFDPA_OP_FLAG_REMOVE BIT(0)
2913fbcdbf3SJiri Pirko #define OFDPA_OP_FLAG_NOWAIT BIT(1)
2923fbcdbf3SJiri Pirko #define OFDPA_OP_FLAG_LEARNED BIT(2)
2933fbcdbf3SJiri Pirko #define OFDPA_OP_FLAG_REFRESH BIT(3)
2943fbcdbf3SJiri Pirko
ofdpa_flags_nowait(int flags)2953fbcdbf3SJiri Pirko static bool ofdpa_flags_nowait(int flags)
2963fbcdbf3SJiri Pirko {
2973fbcdbf3SJiri Pirko return flags & OFDPA_OP_FLAG_NOWAIT;
2983fbcdbf3SJiri Pirko }
2993fbcdbf3SJiri Pirko
3003fbcdbf3SJiri Pirko /*************************************************************
3013fbcdbf3SJiri Pirko * Flow, group, FDB, internal VLAN and neigh command prepares
3023fbcdbf3SJiri Pirko *************************************************************/
3033fbcdbf3SJiri Pirko
3043fbcdbf3SJiri Pirko static int
ofdpa_cmd_flow_tbl_add_ig_port(struct rocker_desc_info * desc_info,const struct ofdpa_flow_tbl_entry * entry)3053fbcdbf3SJiri Pirko ofdpa_cmd_flow_tbl_add_ig_port(struct rocker_desc_info *desc_info,
3063fbcdbf3SJiri Pirko const struct ofdpa_flow_tbl_entry *entry)
3073fbcdbf3SJiri Pirko {
3083fbcdbf3SJiri Pirko if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_IN_PPORT,
3093fbcdbf3SJiri Pirko entry->key.ig_port.in_pport))
3103fbcdbf3SJiri Pirko return -EMSGSIZE;
3113fbcdbf3SJiri Pirko if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_IN_PPORT_MASK,
3123fbcdbf3SJiri Pirko entry->key.ig_port.in_pport_mask))
3133fbcdbf3SJiri Pirko return -EMSGSIZE;
3143fbcdbf3SJiri Pirko if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_GOTO_TABLE_ID,
3153fbcdbf3SJiri Pirko entry->key.ig_port.goto_tbl))
3163fbcdbf3SJiri Pirko return -EMSGSIZE;
3173fbcdbf3SJiri Pirko
3183fbcdbf3SJiri Pirko return 0;
3193fbcdbf3SJiri Pirko }
3203fbcdbf3SJiri Pirko
3213fbcdbf3SJiri Pirko static int
ofdpa_cmd_flow_tbl_add_vlan(struct rocker_desc_info * desc_info,const struct ofdpa_flow_tbl_entry * entry)3223fbcdbf3SJiri Pirko ofdpa_cmd_flow_tbl_add_vlan(struct rocker_desc_info *desc_info,
3233fbcdbf3SJiri Pirko const struct ofdpa_flow_tbl_entry *entry)
3243fbcdbf3SJiri Pirko {
3253fbcdbf3SJiri Pirko if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_IN_PPORT,
3263fbcdbf3SJiri Pirko entry->key.vlan.in_pport))
3273fbcdbf3SJiri Pirko return -EMSGSIZE;
3283fbcdbf3SJiri Pirko if (rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID,
3293fbcdbf3SJiri Pirko entry->key.vlan.vlan_id))
3303fbcdbf3SJiri Pirko return -EMSGSIZE;
3313fbcdbf3SJiri Pirko if (rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID_MASK,
3323fbcdbf3SJiri Pirko entry->key.vlan.vlan_id_mask))
3333fbcdbf3SJiri Pirko return -EMSGSIZE;
3343fbcdbf3SJiri Pirko if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_GOTO_TABLE_ID,
3353fbcdbf3SJiri Pirko entry->key.vlan.goto_tbl))
3363fbcdbf3SJiri Pirko return -EMSGSIZE;
3373fbcdbf3SJiri Pirko if (entry->key.vlan.untagged &&
3383fbcdbf3SJiri Pirko rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_NEW_VLAN_ID,
3393fbcdbf3SJiri Pirko entry->key.vlan.new_vlan_id))
3403fbcdbf3SJiri Pirko return -EMSGSIZE;
3413fbcdbf3SJiri Pirko
3423fbcdbf3SJiri Pirko return 0;
3433fbcdbf3SJiri Pirko }
3443fbcdbf3SJiri Pirko
3453fbcdbf3SJiri Pirko static int
ofdpa_cmd_flow_tbl_add_term_mac(struct rocker_desc_info * desc_info,const struct ofdpa_flow_tbl_entry * entry)3463fbcdbf3SJiri Pirko ofdpa_cmd_flow_tbl_add_term_mac(struct rocker_desc_info *desc_info,
3473fbcdbf3SJiri Pirko const struct ofdpa_flow_tbl_entry *entry)
3483fbcdbf3SJiri Pirko {
3493fbcdbf3SJiri Pirko if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_IN_PPORT,
3503fbcdbf3SJiri Pirko entry->key.term_mac.in_pport))
3513fbcdbf3SJiri Pirko return -EMSGSIZE;
3523fbcdbf3SJiri Pirko if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_IN_PPORT_MASK,
3533fbcdbf3SJiri Pirko entry->key.term_mac.in_pport_mask))
3543fbcdbf3SJiri Pirko return -EMSGSIZE;
3553fbcdbf3SJiri Pirko if (rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_ETHERTYPE,
3563fbcdbf3SJiri Pirko entry->key.term_mac.eth_type))
3573fbcdbf3SJiri Pirko return -EMSGSIZE;
3583fbcdbf3SJiri Pirko if (rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC,
3593fbcdbf3SJiri Pirko ETH_ALEN, entry->key.term_mac.eth_dst))
3603fbcdbf3SJiri Pirko return -EMSGSIZE;
3613fbcdbf3SJiri Pirko if (rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC_MASK,
3623fbcdbf3SJiri Pirko ETH_ALEN, entry->key.term_mac.eth_dst_mask))
3633fbcdbf3SJiri Pirko return -EMSGSIZE;
3643fbcdbf3SJiri Pirko if (rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID,
3653fbcdbf3SJiri Pirko entry->key.term_mac.vlan_id))
3663fbcdbf3SJiri Pirko return -EMSGSIZE;
3673fbcdbf3SJiri Pirko if (rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID_MASK,
3683fbcdbf3SJiri Pirko entry->key.term_mac.vlan_id_mask))
3693fbcdbf3SJiri Pirko return -EMSGSIZE;
3703fbcdbf3SJiri Pirko if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_GOTO_TABLE_ID,
3713fbcdbf3SJiri Pirko entry->key.term_mac.goto_tbl))
3723fbcdbf3SJiri Pirko return -EMSGSIZE;
3733fbcdbf3SJiri Pirko if (entry->key.term_mac.copy_to_cpu &&
3743fbcdbf3SJiri Pirko rocker_tlv_put_u8(desc_info, ROCKER_TLV_OF_DPA_COPY_CPU_ACTION,
3753fbcdbf3SJiri Pirko entry->key.term_mac.copy_to_cpu))
3763fbcdbf3SJiri Pirko return -EMSGSIZE;
3773fbcdbf3SJiri Pirko
3783fbcdbf3SJiri Pirko return 0;
3793fbcdbf3SJiri Pirko }
3803fbcdbf3SJiri Pirko
3813fbcdbf3SJiri Pirko static int
ofdpa_cmd_flow_tbl_add_ucast_routing(struct rocker_desc_info * desc_info,const struct ofdpa_flow_tbl_entry * entry)3823fbcdbf3SJiri Pirko ofdpa_cmd_flow_tbl_add_ucast_routing(struct rocker_desc_info *desc_info,
3833fbcdbf3SJiri Pirko const struct ofdpa_flow_tbl_entry *entry)
3843fbcdbf3SJiri Pirko {
3853fbcdbf3SJiri Pirko if (rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_ETHERTYPE,
3863fbcdbf3SJiri Pirko entry->key.ucast_routing.eth_type))
3873fbcdbf3SJiri Pirko return -EMSGSIZE;
3883fbcdbf3SJiri Pirko if (rocker_tlv_put_be32(desc_info, ROCKER_TLV_OF_DPA_DST_IP,
3893fbcdbf3SJiri Pirko entry->key.ucast_routing.dst4))
3903fbcdbf3SJiri Pirko return -EMSGSIZE;
3913fbcdbf3SJiri Pirko if (rocker_tlv_put_be32(desc_info, ROCKER_TLV_OF_DPA_DST_IP_MASK,
3923fbcdbf3SJiri Pirko entry->key.ucast_routing.dst4_mask))
3933fbcdbf3SJiri Pirko return -EMSGSIZE;
3943fbcdbf3SJiri Pirko if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_GOTO_TABLE_ID,
3953fbcdbf3SJiri Pirko entry->key.ucast_routing.goto_tbl))
3963fbcdbf3SJiri Pirko return -EMSGSIZE;
3973fbcdbf3SJiri Pirko if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_GROUP_ID,
3983fbcdbf3SJiri Pirko entry->key.ucast_routing.group_id))
3993fbcdbf3SJiri Pirko return -EMSGSIZE;
4003fbcdbf3SJiri Pirko
4013fbcdbf3SJiri Pirko return 0;
4023fbcdbf3SJiri Pirko }
4033fbcdbf3SJiri Pirko
4043fbcdbf3SJiri Pirko static int
ofdpa_cmd_flow_tbl_add_bridge(struct rocker_desc_info * desc_info,const struct ofdpa_flow_tbl_entry * entry)4053fbcdbf3SJiri Pirko ofdpa_cmd_flow_tbl_add_bridge(struct rocker_desc_info *desc_info,
4063fbcdbf3SJiri Pirko const struct ofdpa_flow_tbl_entry *entry)
4073fbcdbf3SJiri Pirko {
4083fbcdbf3SJiri Pirko if (entry->key.bridge.has_eth_dst &&
4093fbcdbf3SJiri Pirko rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC,
4103fbcdbf3SJiri Pirko ETH_ALEN, entry->key.bridge.eth_dst))
4113fbcdbf3SJiri Pirko return -EMSGSIZE;
4123fbcdbf3SJiri Pirko if (entry->key.bridge.has_eth_dst_mask &&
4133fbcdbf3SJiri Pirko rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC_MASK,
4143fbcdbf3SJiri Pirko ETH_ALEN, entry->key.bridge.eth_dst_mask))
4153fbcdbf3SJiri Pirko return -EMSGSIZE;
4163fbcdbf3SJiri Pirko if (entry->key.bridge.vlan_id &&
4173fbcdbf3SJiri Pirko rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID,
4183fbcdbf3SJiri Pirko entry->key.bridge.vlan_id))
4193fbcdbf3SJiri Pirko return -EMSGSIZE;
4203fbcdbf3SJiri Pirko if (entry->key.bridge.tunnel_id &&
4213fbcdbf3SJiri Pirko rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_TUNNEL_ID,
4223fbcdbf3SJiri Pirko entry->key.bridge.tunnel_id))
4233fbcdbf3SJiri Pirko return -EMSGSIZE;
4243fbcdbf3SJiri Pirko if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_GOTO_TABLE_ID,
4253fbcdbf3SJiri Pirko entry->key.bridge.goto_tbl))
4263fbcdbf3SJiri Pirko return -EMSGSIZE;
4273fbcdbf3SJiri Pirko if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_GROUP_ID,
4283fbcdbf3SJiri Pirko entry->key.bridge.group_id))
4293fbcdbf3SJiri Pirko return -EMSGSIZE;
4303fbcdbf3SJiri Pirko if (entry->key.bridge.copy_to_cpu &&
4313fbcdbf3SJiri Pirko rocker_tlv_put_u8(desc_info, ROCKER_TLV_OF_DPA_COPY_CPU_ACTION,
4323fbcdbf3SJiri Pirko entry->key.bridge.copy_to_cpu))
4333fbcdbf3SJiri Pirko return -EMSGSIZE;
4343fbcdbf3SJiri Pirko
4353fbcdbf3SJiri Pirko return 0;
4363fbcdbf3SJiri Pirko }
4373fbcdbf3SJiri Pirko
4383fbcdbf3SJiri Pirko static int
ofdpa_cmd_flow_tbl_add_acl(struct rocker_desc_info * desc_info,const struct ofdpa_flow_tbl_entry * entry)4393fbcdbf3SJiri Pirko ofdpa_cmd_flow_tbl_add_acl(struct rocker_desc_info *desc_info,
4403fbcdbf3SJiri Pirko const struct ofdpa_flow_tbl_entry *entry)
4413fbcdbf3SJiri Pirko {
4423fbcdbf3SJiri Pirko if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_IN_PPORT,
4433fbcdbf3SJiri Pirko entry->key.acl.in_pport))
4443fbcdbf3SJiri Pirko return -EMSGSIZE;
4453fbcdbf3SJiri Pirko if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_IN_PPORT_MASK,
4463fbcdbf3SJiri Pirko entry->key.acl.in_pport_mask))
4473fbcdbf3SJiri Pirko return -EMSGSIZE;
4483fbcdbf3SJiri Pirko if (rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_SRC_MAC,
4493fbcdbf3SJiri Pirko ETH_ALEN, entry->key.acl.eth_src))
4503fbcdbf3SJiri Pirko return -EMSGSIZE;
4513fbcdbf3SJiri Pirko if (rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_SRC_MAC_MASK,
4523fbcdbf3SJiri Pirko ETH_ALEN, entry->key.acl.eth_src_mask))
4533fbcdbf3SJiri Pirko return -EMSGSIZE;
4543fbcdbf3SJiri Pirko if (rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC,
4553fbcdbf3SJiri Pirko ETH_ALEN, entry->key.acl.eth_dst))
4563fbcdbf3SJiri Pirko return -EMSGSIZE;
4573fbcdbf3SJiri Pirko if (rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC_MASK,
4583fbcdbf3SJiri Pirko ETH_ALEN, entry->key.acl.eth_dst_mask))
4593fbcdbf3SJiri Pirko return -EMSGSIZE;
4603fbcdbf3SJiri Pirko if (rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_ETHERTYPE,
4613fbcdbf3SJiri Pirko entry->key.acl.eth_type))
4623fbcdbf3SJiri Pirko return -EMSGSIZE;
4633fbcdbf3SJiri Pirko if (rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID,
4643fbcdbf3SJiri Pirko entry->key.acl.vlan_id))
4653fbcdbf3SJiri Pirko return -EMSGSIZE;
4663fbcdbf3SJiri Pirko if (rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID_MASK,
4673fbcdbf3SJiri Pirko entry->key.acl.vlan_id_mask))
4683fbcdbf3SJiri Pirko return -EMSGSIZE;
4693fbcdbf3SJiri Pirko
4703fbcdbf3SJiri Pirko switch (ntohs(entry->key.acl.eth_type)) {
4713fbcdbf3SJiri Pirko case ETH_P_IP:
4723fbcdbf3SJiri Pirko case ETH_P_IPV6:
4733fbcdbf3SJiri Pirko if (rocker_tlv_put_u8(desc_info, ROCKER_TLV_OF_DPA_IP_PROTO,
4743fbcdbf3SJiri Pirko entry->key.acl.ip_proto))
4753fbcdbf3SJiri Pirko return -EMSGSIZE;
4763fbcdbf3SJiri Pirko if (rocker_tlv_put_u8(desc_info,
4773fbcdbf3SJiri Pirko ROCKER_TLV_OF_DPA_IP_PROTO_MASK,
4783fbcdbf3SJiri Pirko entry->key.acl.ip_proto_mask))
4793fbcdbf3SJiri Pirko return -EMSGSIZE;
4803fbcdbf3SJiri Pirko if (rocker_tlv_put_u8(desc_info, ROCKER_TLV_OF_DPA_IP_DSCP,
4813fbcdbf3SJiri Pirko entry->key.acl.ip_tos & 0x3f))
4823fbcdbf3SJiri Pirko return -EMSGSIZE;
4833fbcdbf3SJiri Pirko if (rocker_tlv_put_u8(desc_info,
4843fbcdbf3SJiri Pirko ROCKER_TLV_OF_DPA_IP_DSCP_MASK,
4853fbcdbf3SJiri Pirko entry->key.acl.ip_tos_mask & 0x3f))
4863fbcdbf3SJiri Pirko return -EMSGSIZE;
4873fbcdbf3SJiri Pirko if (rocker_tlv_put_u8(desc_info, ROCKER_TLV_OF_DPA_IP_ECN,
4883fbcdbf3SJiri Pirko (entry->key.acl.ip_tos & 0xc0) >> 6))
4893fbcdbf3SJiri Pirko return -EMSGSIZE;
4903fbcdbf3SJiri Pirko if (rocker_tlv_put_u8(desc_info,
4913fbcdbf3SJiri Pirko ROCKER_TLV_OF_DPA_IP_ECN_MASK,
4923fbcdbf3SJiri Pirko (entry->key.acl.ip_tos_mask & 0xc0) >> 6))
4933fbcdbf3SJiri Pirko return -EMSGSIZE;
4943fbcdbf3SJiri Pirko break;
4953fbcdbf3SJiri Pirko }
4963fbcdbf3SJiri Pirko
4973fbcdbf3SJiri Pirko if (entry->key.acl.group_id != ROCKER_GROUP_NONE &&
4983fbcdbf3SJiri Pirko rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_GROUP_ID,
4993fbcdbf3SJiri Pirko entry->key.acl.group_id))
5003fbcdbf3SJiri Pirko return -EMSGSIZE;
5013fbcdbf3SJiri Pirko
5023fbcdbf3SJiri Pirko return 0;
5033fbcdbf3SJiri Pirko }
5043fbcdbf3SJiri Pirko
ofdpa_cmd_flow_tbl_add(const struct rocker_port * rocker_port,struct rocker_desc_info * desc_info,void * priv)5053fbcdbf3SJiri Pirko static int ofdpa_cmd_flow_tbl_add(const struct rocker_port *rocker_port,
5063fbcdbf3SJiri Pirko struct rocker_desc_info *desc_info,
5073fbcdbf3SJiri Pirko void *priv)
5083fbcdbf3SJiri Pirko {
5093fbcdbf3SJiri Pirko const struct ofdpa_flow_tbl_entry *entry = priv;
5103fbcdbf3SJiri Pirko struct rocker_tlv *cmd_info;
5113fbcdbf3SJiri Pirko int err = 0;
5123fbcdbf3SJiri Pirko
5133fbcdbf3SJiri Pirko if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE, entry->cmd))
5143fbcdbf3SJiri Pirko return -EMSGSIZE;
5153fbcdbf3SJiri Pirko cmd_info = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);
5163fbcdbf3SJiri Pirko if (!cmd_info)
5173fbcdbf3SJiri Pirko return -EMSGSIZE;
5183fbcdbf3SJiri Pirko if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_TABLE_ID,
5193fbcdbf3SJiri Pirko entry->key.tbl_id))
5203fbcdbf3SJiri Pirko return -EMSGSIZE;
5213fbcdbf3SJiri Pirko if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_PRIORITY,
5223fbcdbf3SJiri Pirko entry->key.priority))
5233fbcdbf3SJiri Pirko return -EMSGSIZE;
5243fbcdbf3SJiri Pirko if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_HARDTIME, 0))
5253fbcdbf3SJiri Pirko return -EMSGSIZE;
5263fbcdbf3SJiri Pirko if (rocker_tlv_put_u64(desc_info, ROCKER_TLV_OF_DPA_COOKIE,
5273fbcdbf3SJiri Pirko entry->cookie))
5283fbcdbf3SJiri Pirko return -EMSGSIZE;
5293fbcdbf3SJiri Pirko
5303fbcdbf3SJiri Pirko switch (entry->key.tbl_id) {
5313fbcdbf3SJiri Pirko case ROCKER_OF_DPA_TABLE_ID_INGRESS_PORT:
5323fbcdbf3SJiri Pirko err = ofdpa_cmd_flow_tbl_add_ig_port(desc_info, entry);
5333fbcdbf3SJiri Pirko break;
5343fbcdbf3SJiri Pirko case ROCKER_OF_DPA_TABLE_ID_VLAN:
5353fbcdbf3SJiri Pirko err = ofdpa_cmd_flow_tbl_add_vlan(desc_info, entry);
5363fbcdbf3SJiri Pirko break;
5373fbcdbf3SJiri Pirko case ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC:
5383fbcdbf3SJiri Pirko err = ofdpa_cmd_flow_tbl_add_term_mac(desc_info, entry);
5393fbcdbf3SJiri Pirko break;
5403fbcdbf3SJiri Pirko case ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING:
5413fbcdbf3SJiri Pirko err = ofdpa_cmd_flow_tbl_add_ucast_routing(desc_info, entry);
5423fbcdbf3SJiri Pirko break;
5433fbcdbf3SJiri Pirko case ROCKER_OF_DPA_TABLE_ID_BRIDGING:
5443fbcdbf3SJiri Pirko err = ofdpa_cmd_flow_tbl_add_bridge(desc_info, entry);
5453fbcdbf3SJiri Pirko break;
5463fbcdbf3SJiri Pirko case ROCKER_OF_DPA_TABLE_ID_ACL_POLICY:
5473fbcdbf3SJiri Pirko err = ofdpa_cmd_flow_tbl_add_acl(desc_info, entry);
5483fbcdbf3SJiri Pirko break;
5493fbcdbf3SJiri Pirko default:
5503fbcdbf3SJiri Pirko err = -ENOTSUPP;
5513fbcdbf3SJiri Pirko break;
5523fbcdbf3SJiri Pirko }
5533fbcdbf3SJiri Pirko
5543fbcdbf3SJiri Pirko if (err)
5553fbcdbf3SJiri Pirko return err;
5563fbcdbf3SJiri Pirko
5573fbcdbf3SJiri Pirko rocker_tlv_nest_end(desc_info, cmd_info);
5583fbcdbf3SJiri Pirko
5593fbcdbf3SJiri Pirko return 0;
5603fbcdbf3SJiri Pirko }
5613fbcdbf3SJiri Pirko
ofdpa_cmd_flow_tbl_del(const struct rocker_port * rocker_port,struct rocker_desc_info * desc_info,void * priv)5623fbcdbf3SJiri Pirko static int ofdpa_cmd_flow_tbl_del(const struct rocker_port *rocker_port,
5633fbcdbf3SJiri Pirko struct rocker_desc_info *desc_info,
5643fbcdbf3SJiri Pirko void *priv)
5653fbcdbf3SJiri Pirko {
5663fbcdbf3SJiri Pirko const struct ofdpa_flow_tbl_entry *entry = priv;
5673fbcdbf3SJiri Pirko struct rocker_tlv *cmd_info;
5683fbcdbf3SJiri Pirko
5693fbcdbf3SJiri Pirko if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE, entry->cmd))
5703fbcdbf3SJiri Pirko return -EMSGSIZE;
5713fbcdbf3SJiri Pirko cmd_info = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);
5723fbcdbf3SJiri Pirko if (!cmd_info)
5733fbcdbf3SJiri Pirko return -EMSGSIZE;
5743fbcdbf3SJiri Pirko if (rocker_tlv_put_u64(desc_info, ROCKER_TLV_OF_DPA_COOKIE,
5753fbcdbf3SJiri Pirko entry->cookie))
5763fbcdbf3SJiri Pirko return -EMSGSIZE;
5773fbcdbf3SJiri Pirko rocker_tlv_nest_end(desc_info, cmd_info);
5783fbcdbf3SJiri Pirko
5793fbcdbf3SJiri Pirko return 0;
5803fbcdbf3SJiri Pirko }
5813fbcdbf3SJiri Pirko
5823fbcdbf3SJiri Pirko static int
ofdpa_cmd_group_tbl_add_l2_interface(struct rocker_desc_info * desc_info,struct ofdpa_group_tbl_entry * entry)5833fbcdbf3SJiri Pirko ofdpa_cmd_group_tbl_add_l2_interface(struct rocker_desc_info *desc_info,
5843fbcdbf3SJiri Pirko struct ofdpa_group_tbl_entry *entry)
5853fbcdbf3SJiri Pirko {
5863fbcdbf3SJiri Pirko if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_OUT_PPORT,
5873fbcdbf3SJiri Pirko ROCKER_GROUP_PORT_GET(entry->group_id)))
5883fbcdbf3SJiri Pirko return -EMSGSIZE;
5893fbcdbf3SJiri Pirko if (rocker_tlv_put_u8(desc_info, ROCKER_TLV_OF_DPA_POP_VLAN,
5903fbcdbf3SJiri Pirko entry->l2_interface.pop_vlan))
5913fbcdbf3SJiri Pirko return -EMSGSIZE;
5923fbcdbf3SJiri Pirko
5933fbcdbf3SJiri Pirko return 0;
5943fbcdbf3SJiri Pirko }
5953fbcdbf3SJiri Pirko
5963fbcdbf3SJiri Pirko static int
ofdpa_cmd_group_tbl_add_l2_rewrite(struct rocker_desc_info * desc_info,const struct ofdpa_group_tbl_entry * entry)5973fbcdbf3SJiri Pirko ofdpa_cmd_group_tbl_add_l2_rewrite(struct rocker_desc_info *desc_info,
5983fbcdbf3SJiri Pirko const struct ofdpa_group_tbl_entry *entry)
5993fbcdbf3SJiri Pirko {
6003fbcdbf3SJiri Pirko if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_GROUP_ID_LOWER,
6013fbcdbf3SJiri Pirko entry->l2_rewrite.group_id))
6023fbcdbf3SJiri Pirko return -EMSGSIZE;
6033fbcdbf3SJiri Pirko if (!is_zero_ether_addr(entry->l2_rewrite.eth_src) &&
6043fbcdbf3SJiri Pirko rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_SRC_MAC,
6053fbcdbf3SJiri Pirko ETH_ALEN, entry->l2_rewrite.eth_src))
6063fbcdbf3SJiri Pirko return -EMSGSIZE;
6073fbcdbf3SJiri Pirko if (!is_zero_ether_addr(entry->l2_rewrite.eth_dst) &&
6083fbcdbf3SJiri Pirko rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC,
6093fbcdbf3SJiri Pirko ETH_ALEN, entry->l2_rewrite.eth_dst))
6103fbcdbf3SJiri Pirko return -EMSGSIZE;
6113fbcdbf3SJiri Pirko if (entry->l2_rewrite.vlan_id &&
6123fbcdbf3SJiri Pirko rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID,
6133fbcdbf3SJiri Pirko entry->l2_rewrite.vlan_id))
6143fbcdbf3SJiri Pirko return -EMSGSIZE;
6153fbcdbf3SJiri Pirko
6163fbcdbf3SJiri Pirko return 0;
6173fbcdbf3SJiri Pirko }
6183fbcdbf3SJiri Pirko
6193fbcdbf3SJiri Pirko static int
ofdpa_cmd_group_tbl_add_group_ids(struct rocker_desc_info * desc_info,const struct ofdpa_group_tbl_entry * entry)6203fbcdbf3SJiri Pirko ofdpa_cmd_group_tbl_add_group_ids(struct rocker_desc_info *desc_info,
6213fbcdbf3SJiri Pirko const struct ofdpa_group_tbl_entry *entry)
6223fbcdbf3SJiri Pirko {
6233fbcdbf3SJiri Pirko int i;
6243fbcdbf3SJiri Pirko struct rocker_tlv *group_ids;
6253fbcdbf3SJiri Pirko
6263fbcdbf3SJiri Pirko if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_GROUP_COUNT,
6273fbcdbf3SJiri Pirko entry->group_count))
6283fbcdbf3SJiri Pirko return -EMSGSIZE;
6293fbcdbf3SJiri Pirko
6303fbcdbf3SJiri Pirko group_ids = rocker_tlv_nest_start(desc_info,
6313fbcdbf3SJiri Pirko ROCKER_TLV_OF_DPA_GROUP_IDS);
6323fbcdbf3SJiri Pirko if (!group_ids)
6333fbcdbf3SJiri Pirko return -EMSGSIZE;
6343fbcdbf3SJiri Pirko
6353fbcdbf3SJiri Pirko for (i = 0; i < entry->group_count; i++)
6363fbcdbf3SJiri Pirko /* Note TLV array is 1-based */
6373fbcdbf3SJiri Pirko if (rocker_tlv_put_u32(desc_info, i + 1, entry->group_ids[i]))
6383fbcdbf3SJiri Pirko return -EMSGSIZE;
6393fbcdbf3SJiri Pirko
6403fbcdbf3SJiri Pirko rocker_tlv_nest_end(desc_info, group_ids);
6413fbcdbf3SJiri Pirko
6423fbcdbf3SJiri Pirko return 0;
6433fbcdbf3SJiri Pirko }
6443fbcdbf3SJiri Pirko
6453fbcdbf3SJiri Pirko static int
ofdpa_cmd_group_tbl_add_l3_unicast(struct rocker_desc_info * desc_info,const struct ofdpa_group_tbl_entry * entry)6463fbcdbf3SJiri Pirko ofdpa_cmd_group_tbl_add_l3_unicast(struct rocker_desc_info *desc_info,
6473fbcdbf3SJiri Pirko const struct ofdpa_group_tbl_entry *entry)
6483fbcdbf3SJiri Pirko {
6493fbcdbf3SJiri Pirko if (!is_zero_ether_addr(entry->l3_unicast.eth_src) &&
6503fbcdbf3SJiri Pirko rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_SRC_MAC,
6513fbcdbf3SJiri Pirko ETH_ALEN, entry->l3_unicast.eth_src))
6523fbcdbf3SJiri Pirko return -EMSGSIZE;
6533fbcdbf3SJiri Pirko if (!is_zero_ether_addr(entry->l3_unicast.eth_dst) &&
6543fbcdbf3SJiri Pirko rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC,
6553fbcdbf3SJiri Pirko ETH_ALEN, entry->l3_unicast.eth_dst))
6563fbcdbf3SJiri Pirko return -EMSGSIZE;
6573fbcdbf3SJiri Pirko if (entry->l3_unicast.vlan_id &&
6583fbcdbf3SJiri Pirko rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID,
6593fbcdbf3SJiri Pirko entry->l3_unicast.vlan_id))
6603fbcdbf3SJiri Pirko return -EMSGSIZE;
6613fbcdbf3SJiri Pirko if (rocker_tlv_put_u8(desc_info, ROCKER_TLV_OF_DPA_TTL_CHECK,
6623fbcdbf3SJiri Pirko entry->l3_unicast.ttl_check))
6633fbcdbf3SJiri Pirko return -EMSGSIZE;
6643fbcdbf3SJiri Pirko if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_GROUP_ID_LOWER,
6653fbcdbf3SJiri Pirko entry->l3_unicast.group_id))
6663fbcdbf3SJiri Pirko return -EMSGSIZE;
6673fbcdbf3SJiri Pirko
6683fbcdbf3SJiri Pirko return 0;
6693fbcdbf3SJiri Pirko }
6703fbcdbf3SJiri Pirko
ofdpa_cmd_group_tbl_add(const struct rocker_port * rocker_port,struct rocker_desc_info * desc_info,void * priv)6713fbcdbf3SJiri Pirko static int ofdpa_cmd_group_tbl_add(const struct rocker_port *rocker_port,
6723fbcdbf3SJiri Pirko struct rocker_desc_info *desc_info,
6733fbcdbf3SJiri Pirko void *priv)
6743fbcdbf3SJiri Pirko {
6753fbcdbf3SJiri Pirko struct ofdpa_group_tbl_entry *entry = priv;
6763fbcdbf3SJiri Pirko struct rocker_tlv *cmd_info;
6773fbcdbf3SJiri Pirko int err = 0;
6783fbcdbf3SJiri Pirko
6793fbcdbf3SJiri Pirko if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE, entry->cmd))
6803fbcdbf3SJiri Pirko return -EMSGSIZE;
6813fbcdbf3SJiri Pirko cmd_info = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);
6823fbcdbf3SJiri Pirko if (!cmd_info)
6833fbcdbf3SJiri Pirko return -EMSGSIZE;
6843fbcdbf3SJiri Pirko
6853fbcdbf3SJiri Pirko if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_GROUP_ID,
6863fbcdbf3SJiri Pirko entry->group_id))
6873fbcdbf3SJiri Pirko return -EMSGSIZE;
6883fbcdbf3SJiri Pirko
6893fbcdbf3SJiri Pirko switch (ROCKER_GROUP_TYPE_GET(entry->group_id)) {
6903fbcdbf3SJiri Pirko case ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE:
6913fbcdbf3SJiri Pirko err = ofdpa_cmd_group_tbl_add_l2_interface(desc_info, entry);
6923fbcdbf3SJiri Pirko break;
6933fbcdbf3SJiri Pirko case ROCKER_OF_DPA_GROUP_TYPE_L2_REWRITE:
6943fbcdbf3SJiri Pirko err = ofdpa_cmd_group_tbl_add_l2_rewrite(desc_info, entry);
6953fbcdbf3SJiri Pirko break;
6963fbcdbf3SJiri Pirko case ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD:
6973fbcdbf3SJiri Pirko case ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST:
6983fbcdbf3SJiri Pirko err = ofdpa_cmd_group_tbl_add_group_ids(desc_info, entry);
6993fbcdbf3SJiri Pirko break;
7003fbcdbf3SJiri Pirko case ROCKER_OF_DPA_GROUP_TYPE_L3_UCAST:
7013fbcdbf3SJiri Pirko err = ofdpa_cmd_group_tbl_add_l3_unicast(desc_info, entry);
7023fbcdbf3SJiri Pirko break;
7033fbcdbf3SJiri Pirko default:
7043fbcdbf3SJiri Pirko err = -ENOTSUPP;
7053fbcdbf3SJiri Pirko break;
7063fbcdbf3SJiri Pirko }
7073fbcdbf3SJiri Pirko
7083fbcdbf3SJiri Pirko if (err)
7093fbcdbf3SJiri Pirko return err;
7103fbcdbf3SJiri Pirko
7113fbcdbf3SJiri Pirko rocker_tlv_nest_end(desc_info, cmd_info);
7123fbcdbf3SJiri Pirko
7133fbcdbf3SJiri Pirko return 0;
7143fbcdbf3SJiri Pirko }
7153fbcdbf3SJiri Pirko
ofdpa_cmd_group_tbl_del(const struct rocker_port * rocker_port,struct rocker_desc_info * desc_info,void * priv)7163fbcdbf3SJiri Pirko static int ofdpa_cmd_group_tbl_del(const struct rocker_port *rocker_port,
7173fbcdbf3SJiri Pirko struct rocker_desc_info *desc_info,
7183fbcdbf3SJiri Pirko void *priv)
7193fbcdbf3SJiri Pirko {
7203fbcdbf3SJiri Pirko const struct ofdpa_group_tbl_entry *entry = priv;
7213fbcdbf3SJiri Pirko struct rocker_tlv *cmd_info;
7223fbcdbf3SJiri Pirko
7233fbcdbf3SJiri Pirko if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE, entry->cmd))
7243fbcdbf3SJiri Pirko return -EMSGSIZE;
7253fbcdbf3SJiri Pirko cmd_info = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);
7263fbcdbf3SJiri Pirko if (!cmd_info)
7273fbcdbf3SJiri Pirko return -EMSGSIZE;
7283fbcdbf3SJiri Pirko if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_GROUP_ID,
7293fbcdbf3SJiri Pirko entry->group_id))
7303fbcdbf3SJiri Pirko return -EMSGSIZE;
7313fbcdbf3SJiri Pirko rocker_tlv_nest_end(desc_info, cmd_info);
7323fbcdbf3SJiri Pirko
7333fbcdbf3SJiri Pirko return 0;
7343fbcdbf3SJiri Pirko }
7353fbcdbf3SJiri Pirko
7363fbcdbf3SJiri Pirko /***************************************************
7373fbcdbf3SJiri Pirko * Flow, group, FDB, internal VLAN and neigh tables
7383fbcdbf3SJiri Pirko ***************************************************/
7393fbcdbf3SJiri Pirko
7403fbcdbf3SJiri Pirko static struct ofdpa_flow_tbl_entry *
ofdpa_flow_tbl_find(const struct ofdpa * ofdpa,const struct ofdpa_flow_tbl_entry * match)7413fbcdbf3SJiri Pirko ofdpa_flow_tbl_find(const struct ofdpa *ofdpa,
7423fbcdbf3SJiri Pirko const struct ofdpa_flow_tbl_entry *match)
7433fbcdbf3SJiri Pirko {
7443fbcdbf3SJiri Pirko struct ofdpa_flow_tbl_entry *found;
7453fbcdbf3SJiri Pirko size_t key_len = match->key_len ? match->key_len : sizeof(found->key);
7463fbcdbf3SJiri Pirko
7473fbcdbf3SJiri Pirko hash_for_each_possible(ofdpa->flow_tbl, found,
7483fbcdbf3SJiri Pirko entry, match->key_crc32) {
7493fbcdbf3SJiri Pirko if (memcmp(&found->key, &match->key, key_len) == 0)
7503fbcdbf3SJiri Pirko return found;
7513fbcdbf3SJiri Pirko }
7523fbcdbf3SJiri Pirko
7533fbcdbf3SJiri Pirko return NULL;
7543fbcdbf3SJiri Pirko }
7553fbcdbf3SJiri Pirko
ofdpa_flow_tbl_add(struct ofdpa_port * ofdpa_port,int flags,struct ofdpa_flow_tbl_entry * match)7563fbcdbf3SJiri Pirko static int ofdpa_flow_tbl_add(struct ofdpa_port *ofdpa_port,
75700fc0c51SArkadi Sharshevsky int flags, struct ofdpa_flow_tbl_entry *match)
7583fbcdbf3SJiri Pirko {
7593fbcdbf3SJiri Pirko struct ofdpa *ofdpa = ofdpa_port->ofdpa;
7603fbcdbf3SJiri Pirko struct ofdpa_flow_tbl_entry *found;
7613fbcdbf3SJiri Pirko size_t key_len = match->key_len ? match->key_len : sizeof(found->key);
7623fbcdbf3SJiri Pirko unsigned long lock_flags;
7633fbcdbf3SJiri Pirko
7643fbcdbf3SJiri Pirko match->key_crc32 = crc32(~0, &match->key, key_len);
7653fbcdbf3SJiri Pirko
7663fbcdbf3SJiri Pirko spin_lock_irqsave(&ofdpa->flow_tbl_lock, lock_flags);
7673fbcdbf3SJiri Pirko
7683fbcdbf3SJiri Pirko found = ofdpa_flow_tbl_find(ofdpa, match);
7693fbcdbf3SJiri Pirko
7703fbcdbf3SJiri Pirko if (found) {
7713fbcdbf3SJiri Pirko match->cookie = found->cookie;
7723fbcdbf3SJiri Pirko hash_del(&found->entry);
77300fc0c51SArkadi Sharshevsky kfree(found);
7743fbcdbf3SJiri Pirko found = match;
7753fbcdbf3SJiri Pirko found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_MOD;
7763fbcdbf3SJiri Pirko } else {
7773fbcdbf3SJiri Pirko found = match;
7783fbcdbf3SJiri Pirko found->cookie = ofdpa->flow_tbl_next_cookie++;
7793fbcdbf3SJiri Pirko found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_ADD;
7803fbcdbf3SJiri Pirko }
7813fbcdbf3SJiri Pirko
7823fbcdbf3SJiri Pirko hash_add(ofdpa->flow_tbl, &found->entry, found->key_crc32);
7833fbcdbf3SJiri Pirko spin_unlock_irqrestore(&ofdpa->flow_tbl_lock, lock_flags);
7843fbcdbf3SJiri Pirko
7853fbcdbf3SJiri Pirko return rocker_cmd_exec(ofdpa_port->rocker_port,
7863fbcdbf3SJiri Pirko ofdpa_flags_nowait(flags),
7873fbcdbf3SJiri Pirko ofdpa_cmd_flow_tbl_add,
7883fbcdbf3SJiri Pirko found, NULL, NULL);
7893fbcdbf3SJiri Pirko }
7903fbcdbf3SJiri Pirko
ofdpa_flow_tbl_del(struct ofdpa_port * ofdpa_port,int flags,struct ofdpa_flow_tbl_entry * match)7913fbcdbf3SJiri Pirko static int ofdpa_flow_tbl_del(struct ofdpa_port *ofdpa_port,
79200fc0c51SArkadi Sharshevsky int flags, struct ofdpa_flow_tbl_entry *match)
7933fbcdbf3SJiri Pirko {
7943fbcdbf3SJiri Pirko struct ofdpa *ofdpa = ofdpa_port->ofdpa;
7953fbcdbf3SJiri Pirko struct ofdpa_flow_tbl_entry *found;
7963fbcdbf3SJiri Pirko size_t key_len = match->key_len ? match->key_len : sizeof(found->key);
7973fbcdbf3SJiri Pirko unsigned long lock_flags;
7983fbcdbf3SJiri Pirko int err = 0;
7993fbcdbf3SJiri Pirko
8003fbcdbf3SJiri Pirko match->key_crc32 = crc32(~0, &match->key, key_len);
8013fbcdbf3SJiri Pirko
8023fbcdbf3SJiri Pirko spin_lock_irqsave(&ofdpa->flow_tbl_lock, lock_flags);
8033fbcdbf3SJiri Pirko
8043fbcdbf3SJiri Pirko found = ofdpa_flow_tbl_find(ofdpa, match);
8053fbcdbf3SJiri Pirko
8063fbcdbf3SJiri Pirko if (found) {
8073fbcdbf3SJiri Pirko hash_del(&found->entry);
8083fbcdbf3SJiri Pirko found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_DEL;
8093fbcdbf3SJiri Pirko }
8103fbcdbf3SJiri Pirko
8113fbcdbf3SJiri Pirko spin_unlock_irqrestore(&ofdpa->flow_tbl_lock, lock_flags);
8123fbcdbf3SJiri Pirko
81300fc0c51SArkadi Sharshevsky kfree(match);
8143fbcdbf3SJiri Pirko
8153fbcdbf3SJiri Pirko if (found) {
8163fbcdbf3SJiri Pirko err = rocker_cmd_exec(ofdpa_port->rocker_port,
8173fbcdbf3SJiri Pirko ofdpa_flags_nowait(flags),
8183fbcdbf3SJiri Pirko ofdpa_cmd_flow_tbl_del,
8193fbcdbf3SJiri Pirko found, NULL, NULL);
82000fc0c51SArkadi Sharshevsky kfree(found);
8213fbcdbf3SJiri Pirko }
8223fbcdbf3SJiri Pirko
8233fbcdbf3SJiri Pirko return err;
8243fbcdbf3SJiri Pirko }
8253fbcdbf3SJiri Pirko
ofdpa_flow_tbl_do(struct ofdpa_port * ofdpa_port,int flags,struct ofdpa_flow_tbl_entry * entry)82600fc0c51SArkadi Sharshevsky static int ofdpa_flow_tbl_do(struct ofdpa_port *ofdpa_port, int flags,
8273fbcdbf3SJiri Pirko struct ofdpa_flow_tbl_entry *entry)
8283fbcdbf3SJiri Pirko {
8293fbcdbf3SJiri Pirko if (flags & OFDPA_OP_FLAG_REMOVE)
83000fc0c51SArkadi Sharshevsky return ofdpa_flow_tbl_del(ofdpa_port, flags, entry);
8313fbcdbf3SJiri Pirko else
83200fc0c51SArkadi Sharshevsky return ofdpa_flow_tbl_add(ofdpa_port, flags, entry);
8333fbcdbf3SJiri Pirko }
8343fbcdbf3SJiri Pirko
ofdpa_flow_tbl_ig_port(struct ofdpa_port * ofdpa_port,int flags,u32 in_pport,u32 in_pport_mask,enum rocker_of_dpa_table_id goto_tbl)83500fc0c51SArkadi Sharshevsky static int ofdpa_flow_tbl_ig_port(struct ofdpa_port *ofdpa_port, int flags,
8363fbcdbf3SJiri Pirko u32 in_pport, u32 in_pport_mask,
8373fbcdbf3SJiri Pirko enum rocker_of_dpa_table_id goto_tbl)
8383fbcdbf3SJiri Pirko {
8393fbcdbf3SJiri Pirko struct ofdpa_flow_tbl_entry *entry;
8403fbcdbf3SJiri Pirko
84100fc0c51SArkadi Sharshevsky entry = kzalloc(sizeof(*entry), GFP_KERNEL);
8423fbcdbf3SJiri Pirko if (!entry)
8433fbcdbf3SJiri Pirko return -ENOMEM;
8443fbcdbf3SJiri Pirko
8453fbcdbf3SJiri Pirko entry->key.priority = OFDPA_PRIORITY_IG_PORT;
8463fbcdbf3SJiri Pirko entry->key.tbl_id = ROCKER_OF_DPA_TABLE_ID_INGRESS_PORT;
8473fbcdbf3SJiri Pirko entry->key.ig_port.in_pport = in_pport;
8483fbcdbf3SJiri Pirko entry->key.ig_port.in_pport_mask = in_pport_mask;
8493fbcdbf3SJiri Pirko entry->key.ig_port.goto_tbl = goto_tbl;
8503fbcdbf3SJiri Pirko
85100fc0c51SArkadi Sharshevsky return ofdpa_flow_tbl_do(ofdpa_port, flags, entry);
8523fbcdbf3SJiri Pirko }
8533fbcdbf3SJiri Pirko
ofdpa_flow_tbl_vlan(struct ofdpa_port * ofdpa_port,int flags,u32 in_pport,__be16 vlan_id,__be16 vlan_id_mask,enum rocker_of_dpa_table_id goto_tbl,bool untagged,__be16 new_vlan_id)8543fbcdbf3SJiri Pirko static int ofdpa_flow_tbl_vlan(struct ofdpa_port *ofdpa_port,
85500fc0c51SArkadi Sharshevsky int flags,
8563fbcdbf3SJiri Pirko u32 in_pport, __be16 vlan_id,
8573fbcdbf3SJiri Pirko __be16 vlan_id_mask,
8583fbcdbf3SJiri Pirko enum rocker_of_dpa_table_id goto_tbl,
8593fbcdbf3SJiri Pirko bool untagged, __be16 new_vlan_id)
8603fbcdbf3SJiri Pirko {
8613fbcdbf3SJiri Pirko struct ofdpa_flow_tbl_entry *entry;
8623fbcdbf3SJiri Pirko
86300fc0c51SArkadi Sharshevsky entry = kzalloc(sizeof(*entry), GFP_KERNEL);
8643fbcdbf3SJiri Pirko if (!entry)
8653fbcdbf3SJiri Pirko return -ENOMEM;
8663fbcdbf3SJiri Pirko
8673fbcdbf3SJiri Pirko entry->key.priority = OFDPA_PRIORITY_VLAN;
8683fbcdbf3SJiri Pirko entry->key.tbl_id = ROCKER_OF_DPA_TABLE_ID_VLAN;
8693fbcdbf3SJiri Pirko entry->key.vlan.in_pport = in_pport;
8703fbcdbf3SJiri Pirko entry->key.vlan.vlan_id = vlan_id;
8713fbcdbf3SJiri Pirko entry->key.vlan.vlan_id_mask = vlan_id_mask;
8723fbcdbf3SJiri Pirko entry->key.vlan.goto_tbl = goto_tbl;
8733fbcdbf3SJiri Pirko
8743fbcdbf3SJiri Pirko entry->key.vlan.untagged = untagged;
8753fbcdbf3SJiri Pirko entry->key.vlan.new_vlan_id = new_vlan_id;
8763fbcdbf3SJiri Pirko
87700fc0c51SArkadi Sharshevsky return ofdpa_flow_tbl_do(ofdpa_port, flags, entry);
8783fbcdbf3SJiri Pirko }
8793fbcdbf3SJiri Pirko
ofdpa_flow_tbl_term_mac(struct ofdpa_port * ofdpa_port,u32 in_pport,u32 in_pport_mask,__be16 eth_type,const u8 * eth_dst,const u8 * eth_dst_mask,__be16 vlan_id,__be16 vlan_id_mask,bool copy_to_cpu,int flags)8803fbcdbf3SJiri Pirko static int ofdpa_flow_tbl_term_mac(struct ofdpa_port *ofdpa_port,
8813fbcdbf3SJiri Pirko u32 in_pport, u32 in_pport_mask,
8823fbcdbf3SJiri Pirko __be16 eth_type, const u8 *eth_dst,
8833fbcdbf3SJiri Pirko const u8 *eth_dst_mask, __be16 vlan_id,
8843fbcdbf3SJiri Pirko __be16 vlan_id_mask, bool copy_to_cpu,
8853fbcdbf3SJiri Pirko int flags)
8863fbcdbf3SJiri Pirko {
8873fbcdbf3SJiri Pirko struct ofdpa_flow_tbl_entry *entry;
8883fbcdbf3SJiri Pirko
88900fc0c51SArkadi Sharshevsky entry = kzalloc(sizeof(*entry), GFP_KERNEL);
8903fbcdbf3SJiri Pirko if (!entry)
8913fbcdbf3SJiri Pirko return -ENOMEM;
8923fbcdbf3SJiri Pirko
8933fbcdbf3SJiri Pirko if (is_multicast_ether_addr(eth_dst)) {
8943fbcdbf3SJiri Pirko entry->key.priority = OFDPA_PRIORITY_TERM_MAC_MCAST;
8953fbcdbf3SJiri Pirko entry->key.term_mac.goto_tbl =
8963fbcdbf3SJiri Pirko ROCKER_OF_DPA_TABLE_ID_MULTICAST_ROUTING;
8973fbcdbf3SJiri Pirko } else {
8983fbcdbf3SJiri Pirko entry->key.priority = OFDPA_PRIORITY_TERM_MAC_UCAST;
8993fbcdbf3SJiri Pirko entry->key.term_mac.goto_tbl =
9003fbcdbf3SJiri Pirko ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING;
9013fbcdbf3SJiri Pirko }
9023fbcdbf3SJiri Pirko
9033fbcdbf3SJiri Pirko entry->key.tbl_id = ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC;
9043fbcdbf3SJiri Pirko entry->key.term_mac.in_pport = in_pport;
9053fbcdbf3SJiri Pirko entry->key.term_mac.in_pport_mask = in_pport_mask;
9063fbcdbf3SJiri Pirko entry->key.term_mac.eth_type = eth_type;
9073fbcdbf3SJiri Pirko ether_addr_copy(entry->key.term_mac.eth_dst, eth_dst);
9083fbcdbf3SJiri Pirko ether_addr_copy(entry->key.term_mac.eth_dst_mask, eth_dst_mask);
9093fbcdbf3SJiri Pirko entry->key.term_mac.vlan_id = vlan_id;
9103fbcdbf3SJiri Pirko entry->key.term_mac.vlan_id_mask = vlan_id_mask;
9113fbcdbf3SJiri Pirko entry->key.term_mac.copy_to_cpu = copy_to_cpu;
9123fbcdbf3SJiri Pirko
91300fc0c51SArkadi Sharshevsky return ofdpa_flow_tbl_do(ofdpa_port, flags, entry);
9143fbcdbf3SJiri Pirko }
9153fbcdbf3SJiri Pirko
ofdpa_flow_tbl_bridge(struct ofdpa_port * ofdpa_port,int flags,const u8 * eth_dst,const u8 * eth_dst_mask,__be16 vlan_id,u32 tunnel_id,enum rocker_of_dpa_table_id goto_tbl,u32 group_id,bool copy_to_cpu)9163fbcdbf3SJiri Pirko static int ofdpa_flow_tbl_bridge(struct ofdpa_port *ofdpa_port,
91700fc0c51SArkadi Sharshevsky int flags, const u8 *eth_dst,
91800fc0c51SArkadi Sharshevsky const u8 *eth_dst_mask, __be16 vlan_id,
91900fc0c51SArkadi Sharshevsky u32 tunnel_id,
9203fbcdbf3SJiri Pirko enum rocker_of_dpa_table_id goto_tbl,
9213fbcdbf3SJiri Pirko u32 group_id, bool copy_to_cpu)
9223fbcdbf3SJiri Pirko {
9233fbcdbf3SJiri Pirko struct ofdpa_flow_tbl_entry *entry;
9243fbcdbf3SJiri Pirko u32 priority;
9253fbcdbf3SJiri Pirko bool vlan_bridging = !!vlan_id;
9261d96006dSJiapeng Zhong bool dflt = !eth_dst || eth_dst_mask;
9273fbcdbf3SJiri Pirko bool wild = false;
9283fbcdbf3SJiri Pirko
92900fc0c51SArkadi Sharshevsky entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
9303fbcdbf3SJiri Pirko if (!entry)
9313fbcdbf3SJiri Pirko return -ENOMEM;
9323fbcdbf3SJiri Pirko
9333fbcdbf3SJiri Pirko entry->key.tbl_id = ROCKER_OF_DPA_TABLE_ID_BRIDGING;
9343fbcdbf3SJiri Pirko
9353fbcdbf3SJiri Pirko if (eth_dst) {
9363fbcdbf3SJiri Pirko entry->key.bridge.has_eth_dst = 1;
9373fbcdbf3SJiri Pirko ether_addr_copy(entry->key.bridge.eth_dst, eth_dst);
9383fbcdbf3SJiri Pirko }
9393fbcdbf3SJiri Pirko if (eth_dst_mask) {
9403fbcdbf3SJiri Pirko entry->key.bridge.has_eth_dst_mask = 1;
9413fbcdbf3SJiri Pirko ether_addr_copy(entry->key.bridge.eth_dst_mask, eth_dst_mask);
9423fbcdbf3SJiri Pirko if (!ether_addr_equal(eth_dst_mask, ff_mac))
9433fbcdbf3SJiri Pirko wild = true;
9443fbcdbf3SJiri Pirko }
9453fbcdbf3SJiri Pirko
9463fbcdbf3SJiri Pirko priority = OFDPA_PRIORITY_UNKNOWN;
9473fbcdbf3SJiri Pirko if (vlan_bridging && dflt && wild)
9483fbcdbf3SJiri Pirko priority = OFDPA_PRIORITY_BRIDGING_VLAN_DFLT_WILD;
9493fbcdbf3SJiri Pirko else if (vlan_bridging && dflt && !wild)
9503fbcdbf3SJiri Pirko priority = OFDPA_PRIORITY_BRIDGING_VLAN_DFLT_EXACT;
9513fbcdbf3SJiri Pirko else if (vlan_bridging && !dflt)
9523fbcdbf3SJiri Pirko priority = OFDPA_PRIORITY_BRIDGING_VLAN;
9533fbcdbf3SJiri Pirko else if (!vlan_bridging && dflt && wild)
9543fbcdbf3SJiri Pirko priority = OFDPA_PRIORITY_BRIDGING_TENANT_DFLT_WILD;
9553fbcdbf3SJiri Pirko else if (!vlan_bridging && dflt && !wild)
9563fbcdbf3SJiri Pirko priority = OFDPA_PRIORITY_BRIDGING_TENANT_DFLT_EXACT;
9573fbcdbf3SJiri Pirko else if (!vlan_bridging && !dflt)
9583fbcdbf3SJiri Pirko priority = OFDPA_PRIORITY_BRIDGING_TENANT;
9593fbcdbf3SJiri Pirko
9603fbcdbf3SJiri Pirko entry->key.priority = priority;
9613fbcdbf3SJiri Pirko entry->key.bridge.vlan_id = vlan_id;
9623fbcdbf3SJiri Pirko entry->key.bridge.tunnel_id = tunnel_id;
9633fbcdbf3SJiri Pirko entry->key.bridge.goto_tbl = goto_tbl;
9643fbcdbf3SJiri Pirko entry->key.bridge.group_id = group_id;
9653fbcdbf3SJiri Pirko entry->key.bridge.copy_to_cpu = copy_to_cpu;
9663fbcdbf3SJiri Pirko
96700fc0c51SArkadi Sharshevsky return ofdpa_flow_tbl_do(ofdpa_port, flags, entry);
9683fbcdbf3SJiri Pirko }
9693fbcdbf3SJiri Pirko
ofdpa_flow_tbl_ucast4_routing(struct ofdpa_port * ofdpa_port,__be16 eth_type,__be32 dst,__be32 dst_mask,u32 priority,enum rocker_of_dpa_table_id goto_tbl,u32 group_id,struct fib_info * fi,int flags)9703fbcdbf3SJiri Pirko static int ofdpa_flow_tbl_ucast4_routing(struct ofdpa_port *ofdpa_port,
9713fbcdbf3SJiri Pirko __be16 eth_type, __be32 dst,
9723fbcdbf3SJiri Pirko __be32 dst_mask, u32 priority,
9733fbcdbf3SJiri Pirko enum rocker_of_dpa_table_id goto_tbl,
974936bd486SJiri Pirko u32 group_id, struct fib_info *fi,
975936bd486SJiri Pirko int flags)
9763fbcdbf3SJiri Pirko {
9773fbcdbf3SJiri Pirko struct ofdpa_flow_tbl_entry *entry;
9783fbcdbf3SJiri Pirko
97900fc0c51SArkadi Sharshevsky entry = kzalloc(sizeof(*entry), GFP_KERNEL);
9803fbcdbf3SJiri Pirko if (!entry)
9813fbcdbf3SJiri Pirko return -ENOMEM;
9823fbcdbf3SJiri Pirko
9833fbcdbf3SJiri Pirko entry->key.tbl_id = ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING;
9843fbcdbf3SJiri Pirko entry->key.priority = priority;
9853fbcdbf3SJiri Pirko entry->key.ucast_routing.eth_type = eth_type;
9863fbcdbf3SJiri Pirko entry->key.ucast_routing.dst4 = dst;
9873fbcdbf3SJiri Pirko entry->key.ucast_routing.dst4_mask = dst_mask;
9883fbcdbf3SJiri Pirko entry->key.ucast_routing.goto_tbl = goto_tbl;
9893fbcdbf3SJiri Pirko entry->key.ucast_routing.group_id = group_id;
9903fbcdbf3SJiri Pirko entry->key_len = offsetof(struct ofdpa_flow_tbl_key,
9913fbcdbf3SJiri Pirko ucast_routing.group_id);
992936bd486SJiri Pirko entry->fi = fi;
9933fbcdbf3SJiri Pirko
99400fc0c51SArkadi Sharshevsky return ofdpa_flow_tbl_do(ofdpa_port, flags, entry);
9953fbcdbf3SJiri Pirko }
9963fbcdbf3SJiri Pirko
ofdpa_flow_tbl_acl(struct ofdpa_port * ofdpa_port,int flags,u32 in_pport,u32 in_pport_mask,const u8 * eth_src,const u8 * eth_src_mask,const u8 * eth_dst,const u8 * eth_dst_mask,__be16 eth_type,__be16 vlan_id,__be16 vlan_id_mask,u8 ip_proto,u8 ip_proto_mask,u8 ip_tos,u8 ip_tos_mask,u32 group_id)99700fc0c51SArkadi Sharshevsky static int ofdpa_flow_tbl_acl(struct ofdpa_port *ofdpa_port, int flags,
9983fbcdbf3SJiri Pirko u32 in_pport, u32 in_pport_mask,
9993fbcdbf3SJiri Pirko const u8 *eth_src, const u8 *eth_src_mask,
10003fbcdbf3SJiri Pirko const u8 *eth_dst, const u8 *eth_dst_mask,
10013fbcdbf3SJiri Pirko __be16 eth_type, __be16 vlan_id,
10023fbcdbf3SJiri Pirko __be16 vlan_id_mask, u8 ip_proto,
10033fbcdbf3SJiri Pirko u8 ip_proto_mask, u8 ip_tos, u8 ip_tos_mask,
10043fbcdbf3SJiri Pirko u32 group_id)
10053fbcdbf3SJiri Pirko {
10063fbcdbf3SJiri Pirko u32 priority;
10073fbcdbf3SJiri Pirko struct ofdpa_flow_tbl_entry *entry;
10083fbcdbf3SJiri Pirko
100900fc0c51SArkadi Sharshevsky entry = kzalloc(sizeof(*entry), GFP_KERNEL);
10103fbcdbf3SJiri Pirko if (!entry)
10113fbcdbf3SJiri Pirko return -ENOMEM;
10123fbcdbf3SJiri Pirko
10133fbcdbf3SJiri Pirko priority = OFDPA_PRIORITY_ACL_NORMAL;
10143fbcdbf3SJiri Pirko if (eth_dst && eth_dst_mask) {
10153fbcdbf3SJiri Pirko if (ether_addr_equal(eth_dst_mask, mcast_mac))
10163fbcdbf3SJiri Pirko priority = OFDPA_PRIORITY_ACL_DFLT;
10173fbcdbf3SJiri Pirko else if (is_link_local_ether_addr(eth_dst))
10183fbcdbf3SJiri Pirko priority = OFDPA_PRIORITY_ACL_CTRL;
10193fbcdbf3SJiri Pirko }
10203fbcdbf3SJiri Pirko
10213fbcdbf3SJiri Pirko entry->key.priority = priority;
10223fbcdbf3SJiri Pirko entry->key.tbl_id = ROCKER_OF_DPA_TABLE_ID_ACL_POLICY;
10233fbcdbf3SJiri Pirko entry->key.acl.in_pport = in_pport;
10243fbcdbf3SJiri Pirko entry->key.acl.in_pport_mask = in_pport_mask;
10253fbcdbf3SJiri Pirko
10263fbcdbf3SJiri Pirko if (eth_src)
10273fbcdbf3SJiri Pirko ether_addr_copy(entry->key.acl.eth_src, eth_src);
10283fbcdbf3SJiri Pirko if (eth_src_mask)
10293fbcdbf3SJiri Pirko ether_addr_copy(entry->key.acl.eth_src_mask, eth_src_mask);
10303fbcdbf3SJiri Pirko if (eth_dst)
10313fbcdbf3SJiri Pirko ether_addr_copy(entry->key.acl.eth_dst, eth_dst);
10323fbcdbf3SJiri Pirko if (eth_dst_mask)
10333fbcdbf3SJiri Pirko ether_addr_copy(entry->key.acl.eth_dst_mask, eth_dst_mask);
10343fbcdbf3SJiri Pirko
10353fbcdbf3SJiri Pirko entry->key.acl.eth_type = eth_type;
10363fbcdbf3SJiri Pirko entry->key.acl.vlan_id = vlan_id;
10373fbcdbf3SJiri Pirko entry->key.acl.vlan_id_mask = vlan_id_mask;
10383fbcdbf3SJiri Pirko entry->key.acl.ip_proto = ip_proto;
10393fbcdbf3SJiri Pirko entry->key.acl.ip_proto_mask = ip_proto_mask;
10403fbcdbf3SJiri Pirko entry->key.acl.ip_tos = ip_tos;
10413fbcdbf3SJiri Pirko entry->key.acl.ip_tos_mask = ip_tos_mask;
10423fbcdbf3SJiri Pirko entry->key.acl.group_id = group_id;
10433fbcdbf3SJiri Pirko
104400fc0c51SArkadi Sharshevsky return ofdpa_flow_tbl_do(ofdpa_port, flags, entry);
10453fbcdbf3SJiri Pirko }
10463fbcdbf3SJiri Pirko
10473fbcdbf3SJiri Pirko static struct ofdpa_group_tbl_entry *
ofdpa_group_tbl_find(const struct ofdpa * ofdpa,const struct ofdpa_group_tbl_entry * match)10483fbcdbf3SJiri Pirko ofdpa_group_tbl_find(const struct ofdpa *ofdpa,
10493fbcdbf3SJiri Pirko const struct ofdpa_group_tbl_entry *match)
10503fbcdbf3SJiri Pirko {
10513fbcdbf3SJiri Pirko struct ofdpa_group_tbl_entry *found;
10523fbcdbf3SJiri Pirko
10533fbcdbf3SJiri Pirko hash_for_each_possible(ofdpa->group_tbl, found,
10543fbcdbf3SJiri Pirko entry, match->group_id) {
10553fbcdbf3SJiri Pirko if (found->group_id == match->group_id)
10563fbcdbf3SJiri Pirko return found;
10573fbcdbf3SJiri Pirko }
10583fbcdbf3SJiri Pirko
10593fbcdbf3SJiri Pirko return NULL;
10603fbcdbf3SJiri Pirko }
10613fbcdbf3SJiri Pirko
ofdpa_group_tbl_entry_free(struct ofdpa_group_tbl_entry * entry)106200fc0c51SArkadi Sharshevsky static void ofdpa_group_tbl_entry_free(struct ofdpa_group_tbl_entry *entry)
10633fbcdbf3SJiri Pirko {
10643fbcdbf3SJiri Pirko switch (ROCKER_GROUP_TYPE_GET(entry->group_id)) {
10653fbcdbf3SJiri Pirko case ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD:
10663fbcdbf3SJiri Pirko case ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST:
106700fc0c51SArkadi Sharshevsky kfree(entry->group_ids);
10683fbcdbf3SJiri Pirko break;
10693fbcdbf3SJiri Pirko default:
10703fbcdbf3SJiri Pirko break;
10713fbcdbf3SJiri Pirko }
107200fc0c51SArkadi Sharshevsky kfree(entry);
10733fbcdbf3SJiri Pirko }
10743fbcdbf3SJiri Pirko
ofdpa_group_tbl_add(struct ofdpa_port * ofdpa_port,int flags,struct ofdpa_group_tbl_entry * match)107500fc0c51SArkadi Sharshevsky static int ofdpa_group_tbl_add(struct ofdpa_port *ofdpa_port, int flags,
10763fbcdbf3SJiri Pirko struct ofdpa_group_tbl_entry *match)
10773fbcdbf3SJiri Pirko {
10783fbcdbf3SJiri Pirko struct ofdpa *ofdpa = ofdpa_port->ofdpa;
10793fbcdbf3SJiri Pirko struct ofdpa_group_tbl_entry *found;
10803fbcdbf3SJiri Pirko unsigned long lock_flags;
10813fbcdbf3SJiri Pirko
10823fbcdbf3SJiri Pirko spin_lock_irqsave(&ofdpa->group_tbl_lock, lock_flags);
10833fbcdbf3SJiri Pirko
10843fbcdbf3SJiri Pirko found = ofdpa_group_tbl_find(ofdpa, match);
10853fbcdbf3SJiri Pirko
10863fbcdbf3SJiri Pirko if (found) {
10873fbcdbf3SJiri Pirko hash_del(&found->entry);
108800fc0c51SArkadi Sharshevsky ofdpa_group_tbl_entry_free(found);
10893fbcdbf3SJiri Pirko found = match;
10903fbcdbf3SJiri Pirko found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_MOD;
10913fbcdbf3SJiri Pirko } else {
10923fbcdbf3SJiri Pirko found = match;
10933fbcdbf3SJiri Pirko found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_ADD;
10943fbcdbf3SJiri Pirko }
10953fbcdbf3SJiri Pirko
10963fbcdbf3SJiri Pirko hash_add(ofdpa->group_tbl, &found->entry, found->group_id);
10973fbcdbf3SJiri Pirko
10983fbcdbf3SJiri Pirko spin_unlock_irqrestore(&ofdpa->group_tbl_lock, lock_flags);
10993fbcdbf3SJiri Pirko
11003fbcdbf3SJiri Pirko return rocker_cmd_exec(ofdpa_port->rocker_port,
11013fbcdbf3SJiri Pirko ofdpa_flags_nowait(flags),
11023fbcdbf3SJiri Pirko ofdpa_cmd_group_tbl_add,
11033fbcdbf3SJiri Pirko found, NULL, NULL);
11043fbcdbf3SJiri Pirko }
11053fbcdbf3SJiri Pirko
ofdpa_group_tbl_del(struct ofdpa_port * ofdpa_port,int flags,struct ofdpa_group_tbl_entry * match)110600fc0c51SArkadi Sharshevsky static int ofdpa_group_tbl_del(struct ofdpa_port *ofdpa_port, int flags,
11073fbcdbf3SJiri Pirko struct ofdpa_group_tbl_entry *match)
11083fbcdbf3SJiri Pirko {
11093fbcdbf3SJiri Pirko struct ofdpa *ofdpa = ofdpa_port->ofdpa;
11103fbcdbf3SJiri Pirko struct ofdpa_group_tbl_entry *found;
11113fbcdbf3SJiri Pirko unsigned long lock_flags;
11123fbcdbf3SJiri Pirko int err = 0;
11133fbcdbf3SJiri Pirko
11143fbcdbf3SJiri Pirko spin_lock_irqsave(&ofdpa->group_tbl_lock, lock_flags);
11153fbcdbf3SJiri Pirko
11163fbcdbf3SJiri Pirko found = ofdpa_group_tbl_find(ofdpa, match);
11173fbcdbf3SJiri Pirko
11183fbcdbf3SJiri Pirko if (found) {
11193fbcdbf3SJiri Pirko hash_del(&found->entry);
11203fbcdbf3SJiri Pirko found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_DEL;
11213fbcdbf3SJiri Pirko }
11223fbcdbf3SJiri Pirko
11233fbcdbf3SJiri Pirko spin_unlock_irqrestore(&ofdpa->group_tbl_lock, lock_flags);
11243fbcdbf3SJiri Pirko
112500fc0c51SArkadi Sharshevsky ofdpa_group_tbl_entry_free(match);
11263fbcdbf3SJiri Pirko
11273fbcdbf3SJiri Pirko if (found) {
11283fbcdbf3SJiri Pirko err = rocker_cmd_exec(ofdpa_port->rocker_port,
11293fbcdbf3SJiri Pirko ofdpa_flags_nowait(flags),
11303fbcdbf3SJiri Pirko ofdpa_cmd_group_tbl_del,
11313fbcdbf3SJiri Pirko found, NULL, NULL);
113200fc0c51SArkadi Sharshevsky ofdpa_group_tbl_entry_free(found);
11333fbcdbf3SJiri Pirko }
11343fbcdbf3SJiri Pirko
11353fbcdbf3SJiri Pirko return err;
11363fbcdbf3SJiri Pirko }
11373fbcdbf3SJiri Pirko
ofdpa_group_tbl_do(struct ofdpa_port * ofdpa_port,int flags,struct ofdpa_group_tbl_entry * entry)113800fc0c51SArkadi Sharshevsky static int ofdpa_group_tbl_do(struct ofdpa_port *ofdpa_port, int flags,
11393fbcdbf3SJiri Pirko struct ofdpa_group_tbl_entry *entry)
11403fbcdbf3SJiri Pirko {
11413fbcdbf3SJiri Pirko if (flags & OFDPA_OP_FLAG_REMOVE)
114200fc0c51SArkadi Sharshevsky return ofdpa_group_tbl_del(ofdpa_port, flags, entry);
11433fbcdbf3SJiri Pirko else
114400fc0c51SArkadi Sharshevsky return ofdpa_group_tbl_add(ofdpa_port, flags, entry);
11453fbcdbf3SJiri Pirko }
11463fbcdbf3SJiri Pirko
ofdpa_group_l2_interface(struct ofdpa_port * ofdpa_port,int flags,__be16 vlan_id,u32 out_pport,int pop_vlan)11473fbcdbf3SJiri Pirko static int ofdpa_group_l2_interface(struct ofdpa_port *ofdpa_port,
114800fc0c51SArkadi Sharshevsky int flags, __be16 vlan_id,
114900fc0c51SArkadi Sharshevsky u32 out_pport, int pop_vlan)
11503fbcdbf3SJiri Pirko {
11513fbcdbf3SJiri Pirko struct ofdpa_group_tbl_entry *entry;
11523fbcdbf3SJiri Pirko
115300fc0c51SArkadi Sharshevsky entry = kzalloc(sizeof(*entry), GFP_KERNEL);
11543fbcdbf3SJiri Pirko if (!entry)
11553fbcdbf3SJiri Pirko return -ENOMEM;
11563fbcdbf3SJiri Pirko
11573fbcdbf3SJiri Pirko entry->group_id = ROCKER_GROUP_L2_INTERFACE(vlan_id, out_pport);
11583fbcdbf3SJiri Pirko entry->l2_interface.pop_vlan = pop_vlan;
11593fbcdbf3SJiri Pirko
116000fc0c51SArkadi Sharshevsky return ofdpa_group_tbl_do(ofdpa_port, flags, entry);
11613fbcdbf3SJiri Pirko }
11623fbcdbf3SJiri Pirko
ofdpa_group_l2_fan_out(struct ofdpa_port * ofdpa_port,int flags,u8 group_count,const u32 * group_ids,u32 group_id)11633fbcdbf3SJiri Pirko static int ofdpa_group_l2_fan_out(struct ofdpa_port *ofdpa_port,
11643fbcdbf3SJiri Pirko int flags, u8 group_count,
11653fbcdbf3SJiri Pirko const u32 *group_ids, u32 group_id)
11663fbcdbf3SJiri Pirko {
11673fbcdbf3SJiri Pirko struct ofdpa_group_tbl_entry *entry;
11683fbcdbf3SJiri Pirko
116900fc0c51SArkadi Sharshevsky entry = kzalloc(sizeof(*entry), GFP_KERNEL);
11703fbcdbf3SJiri Pirko if (!entry)
11713fbcdbf3SJiri Pirko return -ENOMEM;
11723fbcdbf3SJiri Pirko
11733fbcdbf3SJiri Pirko entry->group_id = group_id;
11743fbcdbf3SJiri Pirko entry->group_count = group_count;
11753fbcdbf3SJiri Pirko
1176b1357cfbSZahari Doychev entry->group_ids = kcalloc(group_count, sizeof(u32), GFP_KERNEL);
11773fbcdbf3SJiri Pirko if (!entry->group_ids) {
117800fc0c51SArkadi Sharshevsky kfree(entry);
11793fbcdbf3SJiri Pirko return -ENOMEM;
11803fbcdbf3SJiri Pirko }
11813fbcdbf3SJiri Pirko memcpy(entry->group_ids, group_ids, group_count * sizeof(u32));
11823fbcdbf3SJiri Pirko
118300fc0c51SArkadi Sharshevsky return ofdpa_group_tbl_do(ofdpa_port, flags, entry);
11843fbcdbf3SJiri Pirko }
11853fbcdbf3SJiri Pirko
ofdpa_group_l2_flood(struct ofdpa_port * ofdpa_port,int flags,__be16 vlan_id,u8 group_count,const u32 * group_ids,u32 group_id)11863fbcdbf3SJiri Pirko static int ofdpa_group_l2_flood(struct ofdpa_port *ofdpa_port,
118700fc0c51SArkadi Sharshevsky int flags, __be16 vlan_id,
118800fc0c51SArkadi Sharshevsky u8 group_count, const u32 *group_ids,
118900fc0c51SArkadi Sharshevsky u32 group_id)
11903fbcdbf3SJiri Pirko {
119100fc0c51SArkadi Sharshevsky return ofdpa_group_l2_fan_out(ofdpa_port, flags,
11923fbcdbf3SJiri Pirko group_count, group_ids,
11933fbcdbf3SJiri Pirko group_id);
11943fbcdbf3SJiri Pirko }
11953fbcdbf3SJiri Pirko
ofdpa_group_l3_unicast(struct ofdpa_port * ofdpa_port,int flags,u32 index,const u8 * src_mac,const u8 * dst_mac,__be16 vlan_id,bool ttl_check,u32 pport)119600fc0c51SArkadi Sharshevsky static int ofdpa_group_l3_unicast(struct ofdpa_port *ofdpa_port, int flags,
11973fbcdbf3SJiri Pirko u32 index, const u8 *src_mac, const u8 *dst_mac,
11983fbcdbf3SJiri Pirko __be16 vlan_id, bool ttl_check, u32 pport)
11993fbcdbf3SJiri Pirko {
12003fbcdbf3SJiri Pirko struct ofdpa_group_tbl_entry *entry;
12013fbcdbf3SJiri Pirko
120200fc0c51SArkadi Sharshevsky entry = kzalloc(sizeof(*entry), GFP_KERNEL);
12033fbcdbf3SJiri Pirko if (!entry)
12043fbcdbf3SJiri Pirko return -ENOMEM;
12053fbcdbf3SJiri Pirko
12063fbcdbf3SJiri Pirko entry->group_id = ROCKER_GROUP_L3_UNICAST(index);
12073fbcdbf3SJiri Pirko if (src_mac)
12083fbcdbf3SJiri Pirko ether_addr_copy(entry->l3_unicast.eth_src, src_mac);
12093fbcdbf3SJiri Pirko if (dst_mac)
12103fbcdbf3SJiri Pirko ether_addr_copy(entry->l3_unicast.eth_dst, dst_mac);
12113fbcdbf3SJiri Pirko entry->l3_unicast.vlan_id = vlan_id;
12123fbcdbf3SJiri Pirko entry->l3_unicast.ttl_check = ttl_check;
12133fbcdbf3SJiri Pirko entry->l3_unicast.group_id = ROCKER_GROUP_L2_INTERFACE(vlan_id, pport);
12143fbcdbf3SJiri Pirko
121500fc0c51SArkadi Sharshevsky return ofdpa_group_tbl_do(ofdpa_port, flags, entry);
12163fbcdbf3SJiri Pirko }
12173fbcdbf3SJiri Pirko
12183fbcdbf3SJiri Pirko static struct ofdpa_neigh_tbl_entry *
ofdpa_neigh_tbl_find(const struct ofdpa * ofdpa,__be32 ip_addr)12193fbcdbf3SJiri Pirko ofdpa_neigh_tbl_find(const struct ofdpa *ofdpa, __be32 ip_addr)
12203fbcdbf3SJiri Pirko {
12213fbcdbf3SJiri Pirko struct ofdpa_neigh_tbl_entry *found;
12223fbcdbf3SJiri Pirko
12233fbcdbf3SJiri Pirko hash_for_each_possible(ofdpa->neigh_tbl, found,
12243fbcdbf3SJiri Pirko entry, be32_to_cpu(ip_addr))
12253fbcdbf3SJiri Pirko if (found->ip_addr == ip_addr)
12263fbcdbf3SJiri Pirko return found;
12273fbcdbf3SJiri Pirko
12283fbcdbf3SJiri Pirko return NULL;
12293fbcdbf3SJiri Pirko }
12303fbcdbf3SJiri Pirko
ofdpa_neigh_add(struct ofdpa * ofdpa,struct ofdpa_neigh_tbl_entry * entry)12313fbcdbf3SJiri Pirko static void ofdpa_neigh_add(struct ofdpa *ofdpa,
12323fbcdbf3SJiri Pirko struct ofdpa_neigh_tbl_entry *entry)
12333fbcdbf3SJiri Pirko {
12343fbcdbf3SJiri Pirko entry->index = ofdpa->neigh_tbl_next_index++;
12353fbcdbf3SJiri Pirko entry->ref_count++;
12363fbcdbf3SJiri Pirko hash_add(ofdpa->neigh_tbl, &entry->entry,
12373fbcdbf3SJiri Pirko be32_to_cpu(entry->ip_addr));
12383fbcdbf3SJiri Pirko }
12393fbcdbf3SJiri Pirko
ofdpa_neigh_del(struct ofdpa_neigh_tbl_entry * entry)124000fc0c51SArkadi Sharshevsky static void ofdpa_neigh_del(struct ofdpa_neigh_tbl_entry *entry)
12413fbcdbf3SJiri Pirko {
12423fbcdbf3SJiri Pirko if (--entry->ref_count == 0) {
12433fbcdbf3SJiri Pirko hash_del(&entry->entry);
124400fc0c51SArkadi Sharshevsky kfree(entry);
12453fbcdbf3SJiri Pirko }
12463fbcdbf3SJiri Pirko }
12473fbcdbf3SJiri Pirko
ofdpa_neigh_update(struct ofdpa_neigh_tbl_entry * entry,const u8 * eth_dst,bool ttl_check)12483fbcdbf3SJiri Pirko static void ofdpa_neigh_update(struct ofdpa_neigh_tbl_entry *entry,
12493fbcdbf3SJiri Pirko const u8 *eth_dst, bool ttl_check)
12503fbcdbf3SJiri Pirko {
12513fbcdbf3SJiri Pirko if (eth_dst) {
12523fbcdbf3SJiri Pirko ether_addr_copy(entry->eth_dst, eth_dst);
12533fbcdbf3SJiri Pirko entry->ttl_check = ttl_check;
125400fc0c51SArkadi Sharshevsky } else {
12553fbcdbf3SJiri Pirko entry->ref_count++;
12563fbcdbf3SJiri Pirko }
12573fbcdbf3SJiri Pirko }
12583fbcdbf3SJiri Pirko
ofdpa_port_ipv4_neigh(struct ofdpa_port * ofdpa_port,int flags,__be32 ip_addr,const u8 * eth_dst)12593fbcdbf3SJiri Pirko static int ofdpa_port_ipv4_neigh(struct ofdpa_port *ofdpa_port,
12603fbcdbf3SJiri Pirko int flags, __be32 ip_addr, const u8 *eth_dst)
12613fbcdbf3SJiri Pirko {
12623fbcdbf3SJiri Pirko struct ofdpa *ofdpa = ofdpa_port->ofdpa;
12633fbcdbf3SJiri Pirko struct ofdpa_neigh_tbl_entry *entry;
12643fbcdbf3SJiri Pirko struct ofdpa_neigh_tbl_entry *found;
12653fbcdbf3SJiri Pirko unsigned long lock_flags;
12663fbcdbf3SJiri Pirko __be16 eth_type = htons(ETH_P_IP);
12673fbcdbf3SJiri Pirko enum rocker_of_dpa_table_id goto_tbl =
12683fbcdbf3SJiri Pirko ROCKER_OF_DPA_TABLE_ID_ACL_POLICY;
12693fbcdbf3SJiri Pirko u32 group_id;
12703fbcdbf3SJiri Pirko u32 priority = 0;
12713fbcdbf3SJiri Pirko bool adding = !(flags & OFDPA_OP_FLAG_REMOVE);
12723fbcdbf3SJiri Pirko bool updating;
12733fbcdbf3SJiri Pirko bool removing;
12743fbcdbf3SJiri Pirko int err = 0;
12753fbcdbf3SJiri Pirko
1276c0955bf9SDuoming Zhou entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
12773fbcdbf3SJiri Pirko if (!entry)
12783fbcdbf3SJiri Pirko return -ENOMEM;
12793fbcdbf3SJiri Pirko
12803fbcdbf3SJiri Pirko spin_lock_irqsave(&ofdpa->neigh_tbl_lock, lock_flags);
12813fbcdbf3SJiri Pirko
12823fbcdbf3SJiri Pirko found = ofdpa_neigh_tbl_find(ofdpa, ip_addr);
12833fbcdbf3SJiri Pirko
12843fbcdbf3SJiri Pirko updating = found && adding;
12853fbcdbf3SJiri Pirko removing = found && !adding;
12863fbcdbf3SJiri Pirko adding = !found && adding;
12873fbcdbf3SJiri Pirko
12883fbcdbf3SJiri Pirko if (adding) {
12893fbcdbf3SJiri Pirko entry->ip_addr = ip_addr;
12903fbcdbf3SJiri Pirko entry->dev = ofdpa_port->dev;
12913fbcdbf3SJiri Pirko ether_addr_copy(entry->eth_dst, eth_dst);
12923fbcdbf3SJiri Pirko entry->ttl_check = true;
129300fc0c51SArkadi Sharshevsky ofdpa_neigh_add(ofdpa, entry);
12943fbcdbf3SJiri Pirko } else if (removing) {
12953fbcdbf3SJiri Pirko memcpy(entry, found, sizeof(*entry));
129600fc0c51SArkadi Sharshevsky ofdpa_neigh_del(found);
12973fbcdbf3SJiri Pirko } else if (updating) {
129800fc0c51SArkadi Sharshevsky ofdpa_neigh_update(found, eth_dst, true);
12993fbcdbf3SJiri Pirko memcpy(entry, found, sizeof(*entry));
13003fbcdbf3SJiri Pirko } else {
13013fbcdbf3SJiri Pirko err = -ENOENT;
13023fbcdbf3SJiri Pirko }
13033fbcdbf3SJiri Pirko
13043fbcdbf3SJiri Pirko spin_unlock_irqrestore(&ofdpa->neigh_tbl_lock, lock_flags);
13053fbcdbf3SJiri Pirko
13063fbcdbf3SJiri Pirko if (err)
13073fbcdbf3SJiri Pirko goto err_out;
13083fbcdbf3SJiri Pirko
13093fbcdbf3SJiri Pirko /* For each active neighbor, we have an L3 unicast group and
13103fbcdbf3SJiri Pirko * a /32 route to the neighbor, which uses the L3 unicast
13113fbcdbf3SJiri Pirko * group. The L3 unicast group can also be referred to by
13123fbcdbf3SJiri Pirko * other routes' nexthops.
13133fbcdbf3SJiri Pirko */
13143fbcdbf3SJiri Pirko
131500fc0c51SArkadi Sharshevsky err = ofdpa_group_l3_unicast(ofdpa_port, flags,
13163fbcdbf3SJiri Pirko entry->index,
13173fbcdbf3SJiri Pirko ofdpa_port->dev->dev_addr,
13183fbcdbf3SJiri Pirko entry->eth_dst,
13193fbcdbf3SJiri Pirko ofdpa_port->internal_vlan_id,
13203fbcdbf3SJiri Pirko entry->ttl_check,
13213fbcdbf3SJiri Pirko ofdpa_port->pport);
13223fbcdbf3SJiri Pirko if (err) {
13233fbcdbf3SJiri Pirko netdev_err(ofdpa_port->dev, "Error (%d) L3 unicast group index %d\n",
13243fbcdbf3SJiri Pirko err, entry->index);
13253fbcdbf3SJiri Pirko goto err_out;
13263fbcdbf3SJiri Pirko }
13273fbcdbf3SJiri Pirko
13283fbcdbf3SJiri Pirko if (adding || removing) {
13293fbcdbf3SJiri Pirko group_id = ROCKER_GROUP_L3_UNICAST(entry->index);
133000fc0c51SArkadi Sharshevsky err = ofdpa_flow_tbl_ucast4_routing(ofdpa_port,
13313fbcdbf3SJiri Pirko eth_type, ip_addr,
13323fbcdbf3SJiri Pirko inet_make_mask(32),
13333fbcdbf3SJiri Pirko priority, goto_tbl,
1334936bd486SJiri Pirko group_id, NULL, flags);
13353fbcdbf3SJiri Pirko
13363fbcdbf3SJiri Pirko if (err)
13373fbcdbf3SJiri Pirko netdev_err(ofdpa_port->dev, "Error (%d) /32 unicast route %pI4 group 0x%08x\n",
13383fbcdbf3SJiri Pirko err, &entry->ip_addr, group_id);
13393fbcdbf3SJiri Pirko }
13403fbcdbf3SJiri Pirko
13413fbcdbf3SJiri Pirko err_out:
13423fbcdbf3SJiri Pirko if (!adding)
134300fc0c51SArkadi Sharshevsky kfree(entry);
13443fbcdbf3SJiri Pirko
13453fbcdbf3SJiri Pirko return err;
13463fbcdbf3SJiri Pirko }
13473fbcdbf3SJiri Pirko
ofdpa_port_ipv4_resolve(struct ofdpa_port * ofdpa_port,__be32 ip_addr)13483fbcdbf3SJiri Pirko static int ofdpa_port_ipv4_resolve(struct ofdpa_port *ofdpa_port,
13493fbcdbf3SJiri Pirko __be32 ip_addr)
13503fbcdbf3SJiri Pirko {
13513fbcdbf3SJiri Pirko struct net_device *dev = ofdpa_port->dev;
13523fbcdbf3SJiri Pirko struct neighbour *n = __ipv4_neigh_lookup(dev, (__force u32)ip_addr);
13533fbcdbf3SJiri Pirko int err = 0;
13543fbcdbf3SJiri Pirko
13553fbcdbf3SJiri Pirko if (!n) {
13563fbcdbf3SJiri Pirko n = neigh_create(&arp_tbl, &ip_addr, dev);
13573fbcdbf3SJiri Pirko if (IS_ERR(n))
1358f73e0c24SDan Carpenter return PTR_ERR(n);
13593fbcdbf3SJiri Pirko }
13603fbcdbf3SJiri Pirko
13613fbcdbf3SJiri Pirko /* If the neigh is already resolved, then go ahead and
13623fbcdbf3SJiri Pirko * install the entry, otherwise start the ARP process to
13633fbcdbf3SJiri Pirko * resolve the neigh.
13643fbcdbf3SJiri Pirko */
13653fbcdbf3SJiri Pirko
13663fbcdbf3SJiri Pirko if (n->nud_state & NUD_VALID)
136700fc0c51SArkadi Sharshevsky err = ofdpa_port_ipv4_neigh(ofdpa_port, 0,
13683fbcdbf3SJiri Pirko ip_addr, n->ha);
13693fbcdbf3SJiri Pirko else
13703fbcdbf3SJiri Pirko neigh_event_send(n, NULL);
13713fbcdbf3SJiri Pirko
13723fbcdbf3SJiri Pirko neigh_release(n);
13733fbcdbf3SJiri Pirko return err;
13743fbcdbf3SJiri Pirko }
13753fbcdbf3SJiri Pirko
ofdpa_port_ipv4_nh(struct ofdpa_port * ofdpa_port,int flags,__be32 ip_addr,u32 * index)13763fbcdbf3SJiri Pirko static int ofdpa_port_ipv4_nh(struct ofdpa_port *ofdpa_port,
137700fc0c51SArkadi Sharshevsky int flags, __be32 ip_addr, u32 *index)
13783fbcdbf3SJiri Pirko {
13793fbcdbf3SJiri Pirko struct ofdpa *ofdpa = ofdpa_port->ofdpa;
13803fbcdbf3SJiri Pirko struct ofdpa_neigh_tbl_entry *entry;
13813fbcdbf3SJiri Pirko struct ofdpa_neigh_tbl_entry *found;
13823fbcdbf3SJiri Pirko unsigned long lock_flags;
13833fbcdbf3SJiri Pirko bool adding = !(flags & OFDPA_OP_FLAG_REMOVE);
13843fbcdbf3SJiri Pirko bool updating;
13853fbcdbf3SJiri Pirko bool removing;
13863fbcdbf3SJiri Pirko bool resolved = true;
13873fbcdbf3SJiri Pirko int err = 0;
13883fbcdbf3SJiri Pirko
138900fc0c51SArkadi Sharshevsky entry = kzalloc(sizeof(*entry), GFP_KERNEL);
13903fbcdbf3SJiri Pirko if (!entry)
13913fbcdbf3SJiri Pirko return -ENOMEM;
13923fbcdbf3SJiri Pirko
13933fbcdbf3SJiri Pirko spin_lock_irqsave(&ofdpa->neigh_tbl_lock, lock_flags);
13943fbcdbf3SJiri Pirko
13953fbcdbf3SJiri Pirko found = ofdpa_neigh_tbl_find(ofdpa, ip_addr);
13963fbcdbf3SJiri Pirko
13973fbcdbf3SJiri Pirko updating = found && adding;
13983fbcdbf3SJiri Pirko removing = found && !adding;
13993fbcdbf3SJiri Pirko adding = !found && adding;
14003fbcdbf3SJiri Pirko
14013fbcdbf3SJiri Pirko if (adding) {
14023fbcdbf3SJiri Pirko entry->ip_addr = ip_addr;
14033fbcdbf3SJiri Pirko entry->dev = ofdpa_port->dev;
140400fc0c51SArkadi Sharshevsky ofdpa_neigh_add(ofdpa, entry);
14053fbcdbf3SJiri Pirko *index = entry->index;
14063fbcdbf3SJiri Pirko resolved = false;
14073fbcdbf3SJiri Pirko } else if (removing) {
1408ecf244f7SArnd Bergmann *index = found->index;
1409b0791159SDavid S. Miller ofdpa_neigh_del(found);
14103fbcdbf3SJiri Pirko } else if (updating) {
141100fc0c51SArkadi Sharshevsky ofdpa_neigh_update(found, NULL, false);
14123fbcdbf3SJiri Pirko resolved = !is_zero_ether_addr(found->eth_dst);
1413ecf244f7SArnd Bergmann *index = found->index;
14143fbcdbf3SJiri Pirko } else {
14153fbcdbf3SJiri Pirko err = -ENOENT;
14163fbcdbf3SJiri Pirko }
14173fbcdbf3SJiri Pirko
14183fbcdbf3SJiri Pirko spin_unlock_irqrestore(&ofdpa->neigh_tbl_lock, lock_flags);
14193fbcdbf3SJiri Pirko
14203fbcdbf3SJiri Pirko if (!adding)
142100fc0c51SArkadi Sharshevsky kfree(entry);
14223fbcdbf3SJiri Pirko
14233fbcdbf3SJiri Pirko if (err)
14243fbcdbf3SJiri Pirko return err;
14253fbcdbf3SJiri Pirko
14263fbcdbf3SJiri Pirko /* Resolved means neigh ip_addr is resolved to neigh mac. */
14273fbcdbf3SJiri Pirko
14283fbcdbf3SJiri Pirko if (!resolved)
142900fc0c51SArkadi Sharshevsky err = ofdpa_port_ipv4_resolve(ofdpa_port, ip_addr);
14303fbcdbf3SJiri Pirko
14313fbcdbf3SJiri Pirko return err;
14323fbcdbf3SJiri Pirko }
14333fbcdbf3SJiri Pirko
ofdpa_port_get(const struct ofdpa * ofdpa,int port_index)14343fbcdbf3SJiri Pirko static struct ofdpa_port *ofdpa_port_get(const struct ofdpa *ofdpa,
14353fbcdbf3SJiri Pirko int port_index)
14363fbcdbf3SJiri Pirko {
14373fbcdbf3SJiri Pirko struct rocker_port *rocker_port;
14383fbcdbf3SJiri Pirko
14393fbcdbf3SJiri Pirko rocker_port = ofdpa->rocker->ports[port_index];
14403fbcdbf3SJiri Pirko return rocker_port ? rocker_port->wpriv : NULL;
14413fbcdbf3SJiri Pirko }
14423fbcdbf3SJiri Pirko
ofdpa_port_vlan_flood_group(struct ofdpa_port * ofdpa_port,int flags,__be16 vlan_id)14433fbcdbf3SJiri Pirko static int ofdpa_port_vlan_flood_group(struct ofdpa_port *ofdpa_port,
14443fbcdbf3SJiri Pirko int flags, __be16 vlan_id)
14453fbcdbf3SJiri Pirko {
14463fbcdbf3SJiri Pirko struct ofdpa_port *p;
14473fbcdbf3SJiri Pirko const struct ofdpa *ofdpa = ofdpa_port->ofdpa;
14483fbcdbf3SJiri Pirko unsigned int port_count = ofdpa->rocker->port_count;
14493fbcdbf3SJiri Pirko u32 group_id = ROCKER_GROUP_L2_FLOOD(vlan_id, 0);
14503fbcdbf3SJiri Pirko u32 *group_ids;
14513fbcdbf3SJiri Pirko u8 group_count = 0;
14523fbcdbf3SJiri Pirko int err = 0;
14533fbcdbf3SJiri Pirko int i;
14543fbcdbf3SJiri Pirko
1455b1357cfbSZahari Doychev group_ids = kcalloc(port_count, sizeof(u32), GFP_KERNEL);
14563fbcdbf3SJiri Pirko if (!group_ids)
14573fbcdbf3SJiri Pirko return -ENOMEM;
14583fbcdbf3SJiri Pirko
14593fbcdbf3SJiri Pirko /* Adjust the flood group for this VLAN. The flood group
14603fbcdbf3SJiri Pirko * references an L2 interface group for each port in this
14613fbcdbf3SJiri Pirko * VLAN.
14623fbcdbf3SJiri Pirko */
14633fbcdbf3SJiri Pirko
14643fbcdbf3SJiri Pirko for (i = 0; i < port_count; i++) {
14653fbcdbf3SJiri Pirko p = ofdpa_port_get(ofdpa, i);
14663fbcdbf3SJiri Pirko if (!p)
14673fbcdbf3SJiri Pirko continue;
14683fbcdbf3SJiri Pirko if (!ofdpa_port_is_bridged(p))
14693fbcdbf3SJiri Pirko continue;
14703fbcdbf3SJiri Pirko if (test_bit(ntohs(vlan_id), p->vlan_bitmap)) {
14713fbcdbf3SJiri Pirko group_ids[group_count++] =
14723fbcdbf3SJiri Pirko ROCKER_GROUP_L2_INTERFACE(vlan_id, p->pport);
14733fbcdbf3SJiri Pirko }
14743fbcdbf3SJiri Pirko }
14753fbcdbf3SJiri Pirko
14763fbcdbf3SJiri Pirko /* If there are no bridged ports in this VLAN, we're done */
14773fbcdbf3SJiri Pirko if (group_count == 0)
14783fbcdbf3SJiri Pirko goto no_ports_in_vlan;
14793fbcdbf3SJiri Pirko
148000fc0c51SArkadi Sharshevsky err = ofdpa_group_l2_flood(ofdpa_port, flags, vlan_id,
14813fbcdbf3SJiri Pirko group_count, group_ids, group_id);
14823fbcdbf3SJiri Pirko if (err)
14833fbcdbf3SJiri Pirko netdev_err(ofdpa_port->dev, "Error (%d) port VLAN l2 flood group\n", err);
14843fbcdbf3SJiri Pirko
14853fbcdbf3SJiri Pirko no_ports_in_vlan:
148600fc0c51SArkadi Sharshevsky kfree(group_ids);
14873fbcdbf3SJiri Pirko return err;
14883fbcdbf3SJiri Pirko }
14893fbcdbf3SJiri Pirko
ofdpa_port_vlan_l2_groups(struct ofdpa_port * ofdpa_port,int flags,__be16 vlan_id,bool pop_vlan)149000fc0c51SArkadi Sharshevsky static int ofdpa_port_vlan_l2_groups(struct ofdpa_port *ofdpa_port, int flags,
14913fbcdbf3SJiri Pirko __be16 vlan_id, bool pop_vlan)
14923fbcdbf3SJiri Pirko {
14933fbcdbf3SJiri Pirko const struct ofdpa *ofdpa = ofdpa_port->ofdpa;
14943fbcdbf3SJiri Pirko unsigned int port_count = ofdpa->rocker->port_count;
14953fbcdbf3SJiri Pirko struct ofdpa_port *p;
14963fbcdbf3SJiri Pirko bool adding = !(flags & OFDPA_OP_FLAG_REMOVE);
14973fbcdbf3SJiri Pirko u32 out_pport;
14983fbcdbf3SJiri Pirko int ref = 0;
14993fbcdbf3SJiri Pirko int err;
15003fbcdbf3SJiri Pirko int i;
15013fbcdbf3SJiri Pirko
15023fbcdbf3SJiri Pirko /* An L2 interface group for this port in this VLAN, but
15033fbcdbf3SJiri Pirko * only when port STP state is LEARNING|FORWARDING.
15043fbcdbf3SJiri Pirko */
15053fbcdbf3SJiri Pirko
15063fbcdbf3SJiri Pirko if (ofdpa_port->stp_state == BR_STATE_LEARNING ||
15073fbcdbf3SJiri Pirko ofdpa_port->stp_state == BR_STATE_FORWARDING) {
15083fbcdbf3SJiri Pirko out_pport = ofdpa_port->pport;
150900fc0c51SArkadi Sharshevsky err = ofdpa_group_l2_interface(ofdpa_port, flags,
15103fbcdbf3SJiri Pirko vlan_id, out_pport, pop_vlan);
15113fbcdbf3SJiri Pirko if (err) {
15123fbcdbf3SJiri Pirko netdev_err(ofdpa_port->dev, "Error (%d) port VLAN l2 group for pport %d\n",
15133fbcdbf3SJiri Pirko err, out_pport);
15143fbcdbf3SJiri Pirko return err;
15153fbcdbf3SJiri Pirko }
15163fbcdbf3SJiri Pirko }
15173fbcdbf3SJiri Pirko
15183fbcdbf3SJiri Pirko /* An L2 interface group for this VLAN to CPU port.
15193fbcdbf3SJiri Pirko * Add when first port joins this VLAN and destroy when
15203fbcdbf3SJiri Pirko * last port leaves this VLAN.
15213fbcdbf3SJiri Pirko */
15223fbcdbf3SJiri Pirko
15233fbcdbf3SJiri Pirko for (i = 0; i < port_count; i++) {
15243fbcdbf3SJiri Pirko p = ofdpa_port_get(ofdpa, i);
15253fbcdbf3SJiri Pirko if (p && test_bit(ntohs(vlan_id), p->vlan_bitmap))
15263fbcdbf3SJiri Pirko ref++;
15273fbcdbf3SJiri Pirko }
15283fbcdbf3SJiri Pirko
15293fbcdbf3SJiri Pirko if ((!adding || ref != 1) && (adding || ref != 0))
15303fbcdbf3SJiri Pirko return 0;
15313fbcdbf3SJiri Pirko
15323fbcdbf3SJiri Pirko out_pport = 0;
153300fc0c51SArkadi Sharshevsky err = ofdpa_group_l2_interface(ofdpa_port, flags,
15343fbcdbf3SJiri Pirko vlan_id, out_pport, pop_vlan);
15353fbcdbf3SJiri Pirko if (err) {
15363fbcdbf3SJiri Pirko netdev_err(ofdpa_port->dev, "Error (%d) port VLAN l2 group for CPU port\n", err);
15373fbcdbf3SJiri Pirko return err;
15383fbcdbf3SJiri Pirko }
15393fbcdbf3SJiri Pirko
15403fbcdbf3SJiri Pirko return 0;
15413fbcdbf3SJiri Pirko }
15423fbcdbf3SJiri Pirko
15433fbcdbf3SJiri Pirko static struct ofdpa_ctrl {
15443fbcdbf3SJiri Pirko const u8 *eth_dst;
15453fbcdbf3SJiri Pirko const u8 *eth_dst_mask;
15463fbcdbf3SJiri Pirko __be16 eth_type;
15473fbcdbf3SJiri Pirko bool acl;
15483fbcdbf3SJiri Pirko bool bridge;
15493fbcdbf3SJiri Pirko bool term;
15503fbcdbf3SJiri Pirko bool copy_to_cpu;
15513fbcdbf3SJiri Pirko } ofdpa_ctrls[] = {
15523fbcdbf3SJiri Pirko [OFDPA_CTRL_LINK_LOCAL_MCAST] = {
15533fbcdbf3SJiri Pirko /* pass link local multicast pkts up to CPU for filtering */
15543fbcdbf3SJiri Pirko .eth_dst = ll_mac,
15553fbcdbf3SJiri Pirko .eth_dst_mask = ll_mask,
15563fbcdbf3SJiri Pirko .acl = true,
15573fbcdbf3SJiri Pirko },
15583fbcdbf3SJiri Pirko [OFDPA_CTRL_LOCAL_ARP] = {
15593fbcdbf3SJiri Pirko /* pass local ARP pkts up to CPU */
15603fbcdbf3SJiri Pirko .eth_dst = zero_mac,
15613fbcdbf3SJiri Pirko .eth_dst_mask = zero_mac,
15623fbcdbf3SJiri Pirko .eth_type = htons(ETH_P_ARP),
15633fbcdbf3SJiri Pirko .acl = true,
15643fbcdbf3SJiri Pirko },
15653fbcdbf3SJiri Pirko [OFDPA_CTRL_IPV4_MCAST] = {
15663fbcdbf3SJiri Pirko /* pass IPv4 mcast pkts up to CPU, RFC 1112 */
15673fbcdbf3SJiri Pirko .eth_dst = ipv4_mcast,
15683fbcdbf3SJiri Pirko .eth_dst_mask = ipv4_mask,
15693fbcdbf3SJiri Pirko .eth_type = htons(ETH_P_IP),
15703fbcdbf3SJiri Pirko .term = true,
15713fbcdbf3SJiri Pirko .copy_to_cpu = true,
15723fbcdbf3SJiri Pirko },
15733fbcdbf3SJiri Pirko [OFDPA_CTRL_IPV6_MCAST] = {
15743fbcdbf3SJiri Pirko /* pass IPv6 mcast pkts up to CPU, RFC 2464 */
15753fbcdbf3SJiri Pirko .eth_dst = ipv6_mcast,
15763fbcdbf3SJiri Pirko .eth_dst_mask = ipv6_mask,
15773fbcdbf3SJiri Pirko .eth_type = htons(ETH_P_IPV6),
15783fbcdbf3SJiri Pirko .term = true,
15793fbcdbf3SJiri Pirko .copy_to_cpu = true,
15803fbcdbf3SJiri Pirko },
15813fbcdbf3SJiri Pirko [OFDPA_CTRL_DFLT_BRIDGING] = {
15823fbcdbf3SJiri Pirko /* flood any pkts on vlan */
15833fbcdbf3SJiri Pirko .bridge = true,
15843fbcdbf3SJiri Pirko .copy_to_cpu = true,
15853fbcdbf3SJiri Pirko },
15863fbcdbf3SJiri Pirko [OFDPA_CTRL_DFLT_OVS] = {
15873fbcdbf3SJiri Pirko /* pass all pkts up to CPU */
15883fbcdbf3SJiri Pirko .eth_dst = zero_mac,
15893fbcdbf3SJiri Pirko .eth_dst_mask = zero_mac,
15903fbcdbf3SJiri Pirko .acl = true,
15913fbcdbf3SJiri Pirko },
15923fbcdbf3SJiri Pirko };
15933fbcdbf3SJiri Pirko
ofdpa_port_ctrl_vlan_acl(struct ofdpa_port * ofdpa_port,int flags,const struct ofdpa_ctrl * ctrl,__be16 vlan_id)159400fc0c51SArkadi Sharshevsky static int ofdpa_port_ctrl_vlan_acl(struct ofdpa_port *ofdpa_port, int flags,
15953fbcdbf3SJiri Pirko const struct ofdpa_ctrl *ctrl, __be16 vlan_id)
15963fbcdbf3SJiri Pirko {
15973fbcdbf3SJiri Pirko u32 in_pport = ofdpa_port->pport;
15983fbcdbf3SJiri Pirko u32 in_pport_mask = 0xffffffff;
15993fbcdbf3SJiri Pirko u32 out_pport = 0;
16003fbcdbf3SJiri Pirko const u8 *eth_src = NULL;
16013fbcdbf3SJiri Pirko const u8 *eth_src_mask = NULL;
16023fbcdbf3SJiri Pirko __be16 vlan_id_mask = htons(0xffff);
16033fbcdbf3SJiri Pirko u8 ip_proto = 0;
16043fbcdbf3SJiri Pirko u8 ip_proto_mask = 0;
16053fbcdbf3SJiri Pirko u8 ip_tos = 0;
16063fbcdbf3SJiri Pirko u8 ip_tos_mask = 0;
16073fbcdbf3SJiri Pirko u32 group_id = ROCKER_GROUP_L2_INTERFACE(vlan_id, out_pport);
16083fbcdbf3SJiri Pirko int err;
16093fbcdbf3SJiri Pirko
161000fc0c51SArkadi Sharshevsky err = ofdpa_flow_tbl_acl(ofdpa_port, flags,
16113fbcdbf3SJiri Pirko in_pport, in_pport_mask,
16123fbcdbf3SJiri Pirko eth_src, eth_src_mask,
16133fbcdbf3SJiri Pirko ctrl->eth_dst, ctrl->eth_dst_mask,
16143fbcdbf3SJiri Pirko ctrl->eth_type,
16153fbcdbf3SJiri Pirko vlan_id, vlan_id_mask,
16163fbcdbf3SJiri Pirko ip_proto, ip_proto_mask,
16173fbcdbf3SJiri Pirko ip_tos, ip_tos_mask,
16183fbcdbf3SJiri Pirko group_id);
16193fbcdbf3SJiri Pirko
16203fbcdbf3SJiri Pirko if (err)
16213fbcdbf3SJiri Pirko netdev_err(ofdpa_port->dev, "Error (%d) ctrl ACL\n", err);
16223fbcdbf3SJiri Pirko
16233fbcdbf3SJiri Pirko return err;
16243fbcdbf3SJiri Pirko }
16253fbcdbf3SJiri Pirko
ofdpa_port_ctrl_vlan_bridge(struct ofdpa_port * ofdpa_port,int flags,const struct ofdpa_ctrl * ctrl,__be16 vlan_id)16263fbcdbf3SJiri Pirko static int ofdpa_port_ctrl_vlan_bridge(struct ofdpa_port *ofdpa_port,
162700fc0c51SArkadi Sharshevsky int flags, const struct ofdpa_ctrl *ctrl,
16283fbcdbf3SJiri Pirko __be16 vlan_id)
16293fbcdbf3SJiri Pirko {
16303fbcdbf3SJiri Pirko enum rocker_of_dpa_table_id goto_tbl =
16313fbcdbf3SJiri Pirko ROCKER_OF_DPA_TABLE_ID_ACL_POLICY;
16323fbcdbf3SJiri Pirko u32 group_id = ROCKER_GROUP_L2_FLOOD(vlan_id, 0);
16333fbcdbf3SJiri Pirko u32 tunnel_id = 0;
16343fbcdbf3SJiri Pirko int err;
16353fbcdbf3SJiri Pirko
16363fbcdbf3SJiri Pirko if (!ofdpa_port_is_bridged(ofdpa_port))
16373fbcdbf3SJiri Pirko return 0;
16383fbcdbf3SJiri Pirko
163900fc0c51SArkadi Sharshevsky err = ofdpa_flow_tbl_bridge(ofdpa_port, flags,
16403fbcdbf3SJiri Pirko ctrl->eth_dst, ctrl->eth_dst_mask,
16413fbcdbf3SJiri Pirko vlan_id, tunnel_id,
16423fbcdbf3SJiri Pirko goto_tbl, group_id, ctrl->copy_to_cpu);
16433fbcdbf3SJiri Pirko
16443fbcdbf3SJiri Pirko if (err)
16453fbcdbf3SJiri Pirko netdev_err(ofdpa_port->dev, "Error (%d) ctrl FLOOD\n", err);
16463fbcdbf3SJiri Pirko
16473fbcdbf3SJiri Pirko return err;
16483fbcdbf3SJiri Pirko }
16493fbcdbf3SJiri Pirko
ofdpa_port_ctrl_vlan_term(struct ofdpa_port * ofdpa_port,int flags,const struct ofdpa_ctrl * ctrl,__be16 vlan_id)165000fc0c51SArkadi Sharshevsky static int ofdpa_port_ctrl_vlan_term(struct ofdpa_port *ofdpa_port, int flags,
16513fbcdbf3SJiri Pirko const struct ofdpa_ctrl *ctrl, __be16 vlan_id)
16523fbcdbf3SJiri Pirko {
16533fbcdbf3SJiri Pirko u32 in_pport_mask = 0xffffffff;
16543fbcdbf3SJiri Pirko __be16 vlan_id_mask = htons(0xffff);
16553fbcdbf3SJiri Pirko int err;
16563fbcdbf3SJiri Pirko
16573fbcdbf3SJiri Pirko if (ntohs(vlan_id) == 0)
16583fbcdbf3SJiri Pirko vlan_id = ofdpa_port->internal_vlan_id;
16593fbcdbf3SJiri Pirko
166000fc0c51SArkadi Sharshevsky err = ofdpa_flow_tbl_term_mac(ofdpa_port, ofdpa_port->pport, in_pport_mask,
16613fbcdbf3SJiri Pirko ctrl->eth_type, ctrl->eth_dst,
16623fbcdbf3SJiri Pirko ctrl->eth_dst_mask, vlan_id,
16633fbcdbf3SJiri Pirko vlan_id_mask, ctrl->copy_to_cpu,
16643fbcdbf3SJiri Pirko flags);
16653fbcdbf3SJiri Pirko
16663fbcdbf3SJiri Pirko if (err)
16673fbcdbf3SJiri Pirko netdev_err(ofdpa_port->dev, "Error (%d) ctrl term\n", err);
16683fbcdbf3SJiri Pirko
16693fbcdbf3SJiri Pirko return err;
16703fbcdbf3SJiri Pirko }
16713fbcdbf3SJiri Pirko
ofdpa_port_ctrl_vlan(struct ofdpa_port * ofdpa_port,int flags,const struct ofdpa_ctrl * ctrl,__be16 vlan_id)167200fc0c51SArkadi Sharshevsky static int ofdpa_port_ctrl_vlan(struct ofdpa_port *ofdpa_port, int flags,
16733fbcdbf3SJiri Pirko const struct ofdpa_ctrl *ctrl, __be16 vlan_id)
16743fbcdbf3SJiri Pirko {
16753fbcdbf3SJiri Pirko if (ctrl->acl)
167600fc0c51SArkadi Sharshevsky return ofdpa_port_ctrl_vlan_acl(ofdpa_port, flags,
16773fbcdbf3SJiri Pirko ctrl, vlan_id);
16783fbcdbf3SJiri Pirko if (ctrl->bridge)
167900fc0c51SArkadi Sharshevsky return ofdpa_port_ctrl_vlan_bridge(ofdpa_port, flags,
16803fbcdbf3SJiri Pirko ctrl, vlan_id);
16813fbcdbf3SJiri Pirko
16823fbcdbf3SJiri Pirko if (ctrl->term)
168300fc0c51SArkadi Sharshevsky return ofdpa_port_ctrl_vlan_term(ofdpa_port, flags,
16843fbcdbf3SJiri Pirko ctrl, vlan_id);
16853fbcdbf3SJiri Pirko
16863fbcdbf3SJiri Pirko return -EOPNOTSUPP;
16873fbcdbf3SJiri Pirko }
16883fbcdbf3SJiri Pirko
ofdpa_port_ctrl_vlan_add(struct ofdpa_port * ofdpa_port,int flags,__be16 vlan_id)168900fc0c51SArkadi Sharshevsky static int ofdpa_port_ctrl_vlan_add(struct ofdpa_port *ofdpa_port, int flags,
16903fbcdbf3SJiri Pirko __be16 vlan_id)
16913fbcdbf3SJiri Pirko {
16923fbcdbf3SJiri Pirko int err = 0;
16933fbcdbf3SJiri Pirko int i;
16943fbcdbf3SJiri Pirko
16953fbcdbf3SJiri Pirko for (i = 0; i < OFDPA_CTRL_MAX; i++) {
16963fbcdbf3SJiri Pirko if (ofdpa_port->ctrls[i]) {
169700fc0c51SArkadi Sharshevsky err = ofdpa_port_ctrl_vlan(ofdpa_port, flags,
16983fbcdbf3SJiri Pirko &ofdpa_ctrls[i], vlan_id);
16993fbcdbf3SJiri Pirko if (err)
17003fbcdbf3SJiri Pirko return err;
17013fbcdbf3SJiri Pirko }
17023fbcdbf3SJiri Pirko }
17033fbcdbf3SJiri Pirko
17043fbcdbf3SJiri Pirko return err;
17053fbcdbf3SJiri Pirko }
17063fbcdbf3SJiri Pirko
ofdpa_port_ctrl(struct ofdpa_port * ofdpa_port,int flags,const struct ofdpa_ctrl * ctrl)170700fc0c51SArkadi Sharshevsky static int ofdpa_port_ctrl(struct ofdpa_port *ofdpa_port, int flags,
17083fbcdbf3SJiri Pirko const struct ofdpa_ctrl *ctrl)
17093fbcdbf3SJiri Pirko {
17103fbcdbf3SJiri Pirko u16 vid;
17113fbcdbf3SJiri Pirko int err = 0;
17123fbcdbf3SJiri Pirko
17133fbcdbf3SJiri Pirko for (vid = 1; vid < VLAN_N_VID; vid++) {
17143fbcdbf3SJiri Pirko if (!test_bit(vid, ofdpa_port->vlan_bitmap))
17153fbcdbf3SJiri Pirko continue;
171600fc0c51SArkadi Sharshevsky err = ofdpa_port_ctrl_vlan(ofdpa_port, flags,
17173fbcdbf3SJiri Pirko ctrl, htons(vid));
17183fbcdbf3SJiri Pirko if (err)
17193fbcdbf3SJiri Pirko break;
17203fbcdbf3SJiri Pirko }
17213fbcdbf3SJiri Pirko
17223fbcdbf3SJiri Pirko return err;
17233fbcdbf3SJiri Pirko }
17243fbcdbf3SJiri Pirko
ofdpa_port_vlan(struct ofdpa_port * ofdpa_port,int flags,u16 vid)172500fc0c51SArkadi Sharshevsky static int ofdpa_port_vlan(struct ofdpa_port *ofdpa_port, int flags,
172600fc0c51SArkadi Sharshevsky u16 vid)
17273fbcdbf3SJiri Pirko {
17283fbcdbf3SJiri Pirko enum rocker_of_dpa_table_id goto_tbl =
17293fbcdbf3SJiri Pirko ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC;
17303fbcdbf3SJiri Pirko u32 in_pport = ofdpa_port->pport;
17313fbcdbf3SJiri Pirko __be16 vlan_id = htons(vid);
17323fbcdbf3SJiri Pirko __be16 vlan_id_mask = htons(0xffff);
17333fbcdbf3SJiri Pirko __be16 internal_vlan_id;
17343fbcdbf3SJiri Pirko bool untagged;
17353fbcdbf3SJiri Pirko bool adding = !(flags & OFDPA_OP_FLAG_REMOVE);
17363fbcdbf3SJiri Pirko int err;
17373fbcdbf3SJiri Pirko
17383fbcdbf3SJiri Pirko internal_vlan_id = ofdpa_port_vid_to_vlan(ofdpa_port, vid, &untagged);
17393fbcdbf3SJiri Pirko
17403fbcdbf3SJiri Pirko if (adding &&
17413fbcdbf3SJiri Pirko test_bit(ntohs(internal_vlan_id), ofdpa_port->vlan_bitmap))
17423fbcdbf3SJiri Pirko return 0; /* already added */
17433fbcdbf3SJiri Pirko else if (!adding &&
17443fbcdbf3SJiri Pirko !test_bit(ntohs(internal_vlan_id), ofdpa_port->vlan_bitmap))
17453fbcdbf3SJiri Pirko return 0; /* already removed */
17463fbcdbf3SJiri Pirko
17473fbcdbf3SJiri Pirko change_bit(ntohs(internal_vlan_id), ofdpa_port->vlan_bitmap);
17483fbcdbf3SJiri Pirko
17493fbcdbf3SJiri Pirko if (adding) {
175000fc0c51SArkadi Sharshevsky err = ofdpa_port_ctrl_vlan_add(ofdpa_port, flags,
17513fbcdbf3SJiri Pirko internal_vlan_id);
17523fbcdbf3SJiri Pirko if (err) {
17533fbcdbf3SJiri Pirko netdev_err(ofdpa_port->dev, "Error (%d) port ctrl vlan add\n", err);
175400fc0c51SArkadi Sharshevsky goto err_vlan_add;
17553fbcdbf3SJiri Pirko }
17563fbcdbf3SJiri Pirko }
17573fbcdbf3SJiri Pirko
175800fc0c51SArkadi Sharshevsky err = ofdpa_port_vlan_l2_groups(ofdpa_port, flags,
17593fbcdbf3SJiri Pirko internal_vlan_id, untagged);
17603fbcdbf3SJiri Pirko if (err) {
17613fbcdbf3SJiri Pirko netdev_err(ofdpa_port->dev, "Error (%d) port VLAN l2 groups\n", err);
176200fc0c51SArkadi Sharshevsky goto err_vlan_l2_groups;
17633fbcdbf3SJiri Pirko }
17643fbcdbf3SJiri Pirko
176500fc0c51SArkadi Sharshevsky err = ofdpa_port_vlan_flood_group(ofdpa_port, flags,
17663fbcdbf3SJiri Pirko internal_vlan_id);
17673fbcdbf3SJiri Pirko if (err) {
17683fbcdbf3SJiri Pirko netdev_err(ofdpa_port->dev, "Error (%d) port VLAN l2 flood group\n", err);
176900fc0c51SArkadi Sharshevsky goto err_flood_group;
17703fbcdbf3SJiri Pirko }
17713fbcdbf3SJiri Pirko
177200fc0c51SArkadi Sharshevsky err = ofdpa_flow_tbl_vlan(ofdpa_port, flags,
17733fbcdbf3SJiri Pirko in_pport, vlan_id, vlan_id_mask,
17743fbcdbf3SJiri Pirko goto_tbl, untagged, internal_vlan_id);
17753fbcdbf3SJiri Pirko if (err)
17763fbcdbf3SJiri Pirko netdev_err(ofdpa_port->dev, "Error (%d) port VLAN table\n", err);
17773fbcdbf3SJiri Pirko
177800fc0c51SArkadi Sharshevsky return 0;
17793fbcdbf3SJiri Pirko
178000fc0c51SArkadi Sharshevsky err_vlan_add:
178100fc0c51SArkadi Sharshevsky err_vlan_l2_groups:
178200fc0c51SArkadi Sharshevsky err_flood_group:
178300fc0c51SArkadi Sharshevsky change_bit(ntohs(internal_vlan_id), ofdpa_port->vlan_bitmap);
17843fbcdbf3SJiri Pirko return err;
17853fbcdbf3SJiri Pirko }
17863fbcdbf3SJiri Pirko
ofdpa_port_ig_tbl(struct ofdpa_port * ofdpa_port,int flags)178700fc0c51SArkadi Sharshevsky static int ofdpa_port_ig_tbl(struct ofdpa_port *ofdpa_port, int flags)
17883fbcdbf3SJiri Pirko {
17893fbcdbf3SJiri Pirko enum rocker_of_dpa_table_id goto_tbl;
17903fbcdbf3SJiri Pirko u32 in_pport;
17913fbcdbf3SJiri Pirko u32 in_pport_mask;
17923fbcdbf3SJiri Pirko int err;
17933fbcdbf3SJiri Pirko
17943fbcdbf3SJiri Pirko /* Normal Ethernet Frames. Matches pkts from any local physical
17953fbcdbf3SJiri Pirko * ports. Goto VLAN tbl.
17963fbcdbf3SJiri Pirko */
17973fbcdbf3SJiri Pirko
17983fbcdbf3SJiri Pirko in_pport = 0;
17993fbcdbf3SJiri Pirko in_pport_mask = 0xffff0000;
18003fbcdbf3SJiri Pirko goto_tbl = ROCKER_OF_DPA_TABLE_ID_VLAN;
18013fbcdbf3SJiri Pirko
180200fc0c51SArkadi Sharshevsky err = ofdpa_flow_tbl_ig_port(ofdpa_port, flags,
18033fbcdbf3SJiri Pirko in_pport, in_pport_mask,
18043fbcdbf3SJiri Pirko goto_tbl);
18053fbcdbf3SJiri Pirko if (err)
18063fbcdbf3SJiri Pirko netdev_err(ofdpa_port->dev, "Error (%d) ingress port table entry\n", err);
18073fbcdbf3SJiri Pirko
18083fbcdbf3SJiri Pirko return err;
18093fbcdbf3SJiri Pirko }
18103fbcdbf3SJiri Pirko
18113fbcdbf3SJiri Pirko struct ofdpa_fdb_learn_work {
18123fbcdbf3SJiri Pirko struct work_struct work;
18133fbcdbf3SJiri Pirko struct ofdpa_port *ofdpa_port;
18143fbcdbf3SJiri Pirko int flags;
18153fbcdbf3SJiri Pirko u8 addr[ETH_ALEN];
18163fbcdbf3SJiri Pirko u16 vid;
18173fbcdbf3SJiri Pirko };
18183fbcdbf3SJiri Pirko
ofdpa_port_fdb_learn_work(struct work_struct * work)18193fbcdbf3SJiri Pirko static void ofdpa_port_fdb_learn_work(struct work_struct *work)
18203fbcdbf3SJiri Pirko {
18213fbcdbf3SJiri Pirko const struct ofdpa_fdb_learn_work *lw =
18223fbcdbf3SJiri Pirko container_of(work, struct ofdpa_fdb_learn_work, work);
18233fbcdbf3SJiri Pirko bool removing = (lw->flags & OFDPA_OP_FLAG_REMOVE);
1824c35b57ceSVladimir Oltean struct switchdev_notifier_fdb_info info = {};
182542e51de9SIdo Schimmel enum switchdev_notifier_type event;
18263fbcdbf3SJiri Pirko
18273fbcdbf3SJiri Pirko info.addr = lw->addr;
18283fbcdbf3SJiri Pirko info.vid = lw->vid;
1829*386b4174SIdo Schimmel info.offloaded = !removing;
183042e51de9SIdo Schimmel event = removing ? SWITCHDEV_FDB_DEL_TO_BRIDGE :
183142e51de9SIdo Schimmel SWITCHDEV_FDB_ADD_TO_BRIDGE;
18323fbcdbf3SJiri Pirko
18333fbcdbf3SJiri Pirko rtnl_lock();
183442e51de9SIdo Schimmel call_switchdev_notifiers(event, lw->ofdpa_port->dev, &info.info, NULL);
18353fbcdbf3SJiri Pirko rtnl_unlock();
18363fbcdbf3SJiri Pirko
183700fc0c51SArkadi Sharshevsky kfree(work);
18383fbcdbf3SJiri Pirko }
18393fbcdbf3SJiri Pirko
ofdpa_port_fdb_learn(struct ofdpa_port * ofdpa_port,int flags,const u8 * addr,__be16 vlan_id)18403fbcdbf3SJiri Pirko static int ofdpa_port_fdb_learn(struct ofdpa_port *ofdpa_port,
184100fc0c51SArkadi Sharshevsky int flags, const u8 *addr, __be16 vlan_id)
18423fbcdbf3SJiri Pirko {
18433fbcdbf3SJiri Pirko struct ofdpa_fdb_learn_work *lw;
18443fbcdbf3SJiri Pirko enum rocker_of_dpa_table_id goto_tbl =
18453fbcdbf3SJiri Pirko ROCKER_OF_DPA_TABLE_ID_ACL_POLICY;
18463fbcdbf3SJiri Pirko u32 out_pport = ofdpa_port->pport;
18473fbcdbf3SJiri Pirko u32 tunnel_id = 0;
18483fbcdbf3SJiri Pirko u32 group_id = ROCKER_GROUP_NONE;
18493fbcdbf3SJiri Pirko bool copy_to_cpu = false;
18503fbcdbf3SJiri Pirko int err;
18513fbcdbf3SJiri Pirko
18523fbcdbf3SJiri Pirko if (ofdpa_port_is_bridged(ofdpa_port))
18533fbcdbf3SJiri Pirko group_id = ROCKER_GROUP_L2_INTERFACE(vlan_id, out_pport);
18543fbcdbf3SJiri Pirko
18553fbcdbf3SJiri Pirko if (!(flags & OFDPA_OP_FLAG_REFRESH)) {
185600fc0c51SArkadi Sharshevsky err = ofdpa_flow_tbl_bridge(ofdpa_port, flags, addr,
18573fbcdbf3SJiri Pirko NULL, vlan_id, tunnel_id, goto_tbl,
18583fbcdbf3SJiri Pirko group_id, copy_to_cpu);
18593fbcdbf3SJiri Pirko if (err)
18603fbcdbf3SJiri Pirko return err;
18613fbcdbf3SJiri Pirko }
18623fbcdbf3SJiri Pirko
18633fbcdbf3SJiri Pirko if (!ofdpa_port_is_bridged(ofdpa_port))
18643fbcdbf3SJiri Pirko return 0;
18653fbcdbf3SJiri Pirko
186642e51de9SIdo Schimmel if (!(flags & OFDPA_OP_FLAG_LEARNED))
186742e51de9SIdo Schimmel return 0;
186842e51de9SIdo Schimmel
186900fc0c51SArkadi Sharshevsky lw = kzalloc(sizeof(*lw), GFP_ATOMIC);
18703fbcdbf3SJiri Pirko if (!lw)
18713fbcdbf3SJiri Pirko return -ENOMEM;
18723fbcdbf3SJiri Pirko
18733fbcdbf3SJiri Pirko INIT_WORK(&lw->work, ofdpa_port_fdb_learn_work);
18743fbcdbf3SJiri Pirko
18753fbcdbf3SJiri Pirko lw->ofdpa_port = ofdpa_port;
18763fbcdbf3SJiri Pirko lw->flags = flags;
18773fbcdbf3SJiri Pirko ether_addr_copy(lw->addr, addr);
18783fbcdbf3SJiri Pirko lw->vid = ofdpa_port_vlan_to_vid(ofdpa_port, vlan_id);
18793fbcdbf3SJiri Pirko
18803fbcdbf3SJiri Pirko schedule_work(&lw->work);
18813fbcdbf3SJiri Pirko return 0;
18823fbcdbf3SJiri Pirko }
18833fbcdbf3SJiri Pirko
18843fbcdbf3SJiri Pirko static struct ofdpa_fdb_tbl_entry *
ofdpa_fdb_tbl_find(const struct ofdpa * ofdpa,const struct ofdpa_fdb_tbl_entry * match)18853fbcdbf3SJiri Pirko ofdpa_fdb_tbl_find(const struct ofdpa *ofdpa,
18863fbcdbf3SJiri Pirko const struct ofdpa_fdb_tbl_entry *match)
18873fbcdbf3SJiri Pirko {
18883fbcdbf3SJiri Pirko struct ofdpa_fdb_tbl_entry *found;
18893fbcdbf3SJiri Pirko
18903fbcdbf3SJiri Pirko hash_for_each_possible(ofdpa->fdb_tbl, found, entry, match->key_crc32)
18913fbcdbf3SJiri Pirko if (memcmp(&found->key, &match->key, sizeof(found->key)) == 0)
18923fbcdbf3SJiri Pirko return found;
18933fbcdbf3SJiri Pirko
18943fbcdbf3SJiri Pirko return NULL;
18953fbcdbf3SJiri Pirko }
18963fbcdbf3SJiri Pirko
ofdpa_port_fdb(struct ofdpa_port * ofdpa_port,const unsigned char * addr,__be16 vlan_id,int flags)18973fbcdbf3SJiri Pirko static int ofdpa_port_fdb(struct ofdpa_port *ofdpa_port,
18983fbcdbf3SJiri Pirko const unsigned char *addr,
18993fbcdbf3SJiri Pirko __be16 vlan_id, int flags)
19003fbcdbf3SJiri Pirko {
19013fbcdbf3SJiri Pirko struct ofdpa *ofdpa = ofdpa_port->ofdpa;
19023fbcdbf3SJiri Pirko struct ofdpa_fdb_tbl_entry *fdb;
19033fbcdbf3SJiri Pirko struct ofdpa_fdb_tbl_entry *found;
19043fbcdbf3SJiri Pirko bool removing = (flags & OFDPA_OP_FLAG_REMOVE);
19053fbcdbf3SJiri Pirko unsigned long lock_flags;
19063fbcdbf3SJiri Pirko
190700fc0c51SArkadi Sharshevsky fdb = kzalloc(sizeof(*fdb), GFP_KERNEL);
19083fbcdbf3SJiri Pirko if (!fdb)
19093fbcdbf3SJiri Pirko return -ENOMEM;
19103fbcdbf3SJiri Pirko
19113fbcdbf3SJiri Pirko fdb->learned = (flags & OFDPA_OP_FLAG_LEARNED);
19123fbcdbf3SJiri Pirko fdb->touched = jiffies;
19133fbcdbf3SJiri Pirko fdb->key.ofdpa_port = ofdpa_port;
19143fbcdbf3SJiri Pirko ether_addr_copy(fdb->key.addr, addr);
19153fbcdbf3SJiri Pirko fdb->key.vlan_id = vlan_id;
19163fbcdbf3SJiri Pirko fdb->key_crc32 = crc32(~0, &fdb->key, sizeof(fdb->key));
19173fbcdbf3SJiri Pirko
19183fbcdbf3SJiri Pirko spin_lock_irqsave(&ofdpa->fdb_tbl_lock, lock_flags);
19193fbcdbf3SJiri Pirko
19203fbcdbf3SJiri Pirko found = ofdpa_fdb_tbl_find(ofdpa, fdb);
19213fbcdbf3SJiri Pirko
19223fbcdbf3SJiri Pirko if (found) {
19233fbcdbf3SJiri Pirko found->touched = jiffies;
19243fbcdbf3SJiri Pirko if (removing) {
192500fc0c51SArkadi Sharshevsky kfree(fdb);
19263fbcdbf3SJiri Pirko hash_del(&found->entry);
19273fbcdbf3SJiri Pirko }
19283fbcdbf3SJiri Pirko } else if (!removing) {
19293fbcdbf3SJiri Pirko hash_add(ofdpa->fdb_tbl, &fdb->entry,
19303fbcdbf3SJiri Pirko fdb->key_crc32);
19313fbcdbf3SJiri Pirko }
19323fbcdbf3SJiri Pirko
19333fbcdbf3SJiri Pirko spin_unlock_irqrestore(&ofdpa->fdb_tbl_lock, lock_flags);
19343fbcdbf3SJiri Pirko
19353fbcdbf3SJiri Pirko /* Check if adding and already exists, or removing and can't find */
19363fbcdbf3SJiri Pirko if (!found != !removing) {
193700fc0c51SArkadi Sharshevsky kfree(fdb);
19383fbcdbf3SJiri Pirko if (!found && removing)
19393fbcdbf3SJiri Pirko return 0;
19403fbcdbf3SJiri Pirko /* Refreshing existing to update aging timers */
19413fbcdbf3SJiri Pirko flags |= OFDPA_OP_FLAG_REFRESH;
19423fbcdbf3SJiri Pirko }
19433fbcdbf3SJiri Pirko
194400fc0c51SArkadi Sharshevsky return ofdpa_port_fdb_learn(ofdpa_port, flags, addr, vlan_id);
19453fbcdbf3SJiri Pirko }
19463fbcdbf3SJiri Pirko
ofdpa_port_fdb_flush(struct ofdpa_port * ofdpa_port,int flags)194700fc0c51SArkadi Sharshevsky static int ofdpa_port_fdb_flush(struct ofdpa_port *ofdpa_port, int flags)
19483fbcdbf3SJiri Pirko {
19493fbcdbf3SJiri Pirko struct ofdpa *ofdpa = ofdpa_port->ofdpa;
19503fbcdbf3SJiri Pirko struct ofdpa_fdb_tbl_entry *found;
19513fbcdbf3SJiri Pirko unsigned long lock_flags;
19523fbcdbf3SJiri Pirko struct hlist_node *tmp;
19533fbcdbf3SJiri Pirko int bkt;
19543fbcdbf3SJiri Pirko int err = 0;
19553fbcdbf3SJiri Pirko
19563fbcdbf3SJiri Pirko if (ofdpa_port->stp_state == BR_STATE_LEARNING ||
19573fbcdbf3SJiri Pirko ofdpa_port->stp_state == BR_STATE_FORWARDING)
19583fbcdbf3SJiri Pirko return 0;
19593fbcdbf3SJiri Pirko
19603fbcdbf3SJiri Pirko flags |= OFDPA_OP_FLAG_NOWAIT | OFDPA_OP_FLAG_REMOVE;
19613fbcdbf3SJiri Pirko
19623fbcdbf3SJiri Pirko spin_lock_irqsave(&ofdpa->fdb_tbl_lock, lock_flags);
19633fbcdbf3SJiri Pirko
19643fbcdbf3SJiri Pirko hash_for_each_safe(ofdpa->fdb_tbl, bkt, tmp, found, entry) {
19653fbcdbf3SJiri Pirko if (found->key.ofdpa_port != ofdpa_port)
19663fbcdbf3SJiri Pirko continue;
19673fbcdbf3SJiri Pirko if (!found->learned)
19683fbcdbf3SJiri Pirko continue;
196900fc0c51SArkadi Sharshevsky err = ofdpa_port_fdb_learn(ofdpa_port, flags,
19703fbcdbf3SJiri Pirko found->key.addr,
19713fbcdbf3SJiri Pirko found->key.vlan_id);
19723fbcdbf3SJiri Pirko if (err)
19733fbcdbf3SJiri Pirko goto err_out;
19743fbcdbf3SJiri Pirko hash_del(&found->entry);
19753fbcdbf3SJiri Pirko }
19763fbcdbf3SJiri Pirko
19773fbcdbf3SJiri Pirko err_out:
19783fbcdbf3SJiri Pirko spin_unlock_irqrestore(&ofdpa->fdb_tbl_lock, lock_flags);
19793fbcdbf3SJiri Pirko
19803fbcdbf3SJiri Pirko return err;
19813fbcdbf3SJiri Pirko }
19823fbcdbf3SJiri Pirko
ofdpa_fdb_cleanup(struct timer_list * t)1983e99e88a9SKees Cook static void ofdpa_fdb_cleanup(struct timer_list *t)
19843fbcdbf3SJiri Pirko {
1985e99e88a9SKees Cook struct ofdpa *ofdpa = from_timer(ofdpa, t, fdb_cleanup_timer);
19863fbcdbf3SJiri Pirko struct ofdpa_port *ofdpa_port;
19873fbcdbf3SJiri Pirko struct ofdpa_fdb_tbl_entry *entry;
19883fbcdbf3SJiri Pirko struct hlist_node *tmp;
19893a8befcdSJiri Pirko unsigned long next_timer = jiffies + ofdpa->ageing_time;
19903fbcdbf3SJiri Pirko unsigned long expires;
19913fbcdbf3SJiri Pirko unsigned long lock_flags;
19923fbcdbf3SJiri Pirko int flags = OFDPA_OP_FLAG_NOWAIT | OFDPA_OP_FLAG_REMOVE |
19933fbcdbf3SJiri Pirko OFDPA_OP_FLAG_LEARNED;
19943fbcdbf3SJiri Pirko int bkt;
19953fbcdbf3SJiri Pirko
19963fbcdbf3SJiri Pirko spin_lock_irqsave(&ofdpa->fdb_tbl_lock, lock_flags);
19973fbcdbf3SJiri Pirko
19983fbcdbf3SJiri Pirko hash_for_each_safe(ofdpa->fdb_tbl, bkt, tmp, entry, entry) {
19993fbcdbf3SJiri Pirko if (!entry->learned)
20003fbcdbf3SJiri Pirko continue;
20013fbcdbf3SJiri Pirko ofdpa_port = entry->key.ofdpa_port;
20023fbcdbf3SJiri Pirko expires = entry->touched + ofdpa_port->ageing_time;
20033fbcdbf3SJiri Pirko if (time_before_eq(expires, jiffies)) {
200400fc0c51SArkadi Sharshevsky ofdpa_port_fdb_learn(ofdpa_port, flags,
200500fc0c51SArkadi Sharshevsky entry->key.addr,
20063fbcdbf3SJiri Pirko entry->key.vlan_id);
20073fbcdbf3SJiri Pirko hash_del(&entry->entry);
20083fbcdbf3SJiri Pirko } else if (time_before(expires, next_timer)) {
20093fbcdbf3SJiri Pirko next_timer = expires;
20103fbcdbf3SJiri Pirko }
20113fbcdbf3SJiri Pirko }
20123fbcdbf3SJiri Pirko
20133fbcdbf3SJiri Pirko spin_unlock_irqrestore(&ofdpa->fdb_tbl_lock, lock_flags);
20143fbcdbf3SJiri Pirko
20153fbcdbf3SJiri Pirko mod_timer(&ofdpa->fdb_cleanup_timer, round_jiffies_up(next_timer));
20163fbcdbf3SJiri Pirko }
20173fbcdbf3SJiri Pirko
ofdpa_port_router_mac(struct ofdpa_port * ofdpa_port,int flags,__be16 vlan_id)20183fbcdbf3SJiri Pirko static int ofdpa_port_router_mac(struct ofdpa_port *ofdpa_port,
201900fc0c51SArkadi Sharshevsky int flags, __be16 vlan_id)
20203fbcdbf3SJiri Pirko {
20213fbcdbf3SJiri Pirko u32 in_pport_mask = 0xffffffff;
20223fbcdbf3SJiri Pirko __be16 eth_type;
20233fbcdbf3SJiri Pirko const u8 *dst_mac_mask = ff_mac;
20243fbcdbf3SJiri Pirko __be16 vlan_id_mask = htons(0xffff);
20253fbcdbf3SJiri Pirko bool copy_to_cpu = false;
20263fbcdbf3SJiri Pirko int err;
20273fbcdbf3SJiri Pirko
20283fbcdbf3SJiri Pirko if (ntohs(vlan_id) == 0)
20293fbcdbf3SJiri Pirko vlan_id = ofdpa_port->internal_vlan_id;
20303fbcdbf3SJiri Pirko
20313fbcdbf3SJiri Pirko eth_type = htons(ETH_P_IP);
203200fc0c51SArkadi Sharshevsky err = ofdpa_flow_tbl_term_mac(ofdpa_port, ofdpa_port->pport,
203300fc0c51SArkadi Sharshevsky in_pport_mask, eth_type,
203400fc0c51SArkadi Sharshevsky ofdpa_port->dev->dev_addr,
20353fbcdbf3SJiri Pirko dst_mac_mask, vlan_id, vlan_id_mask,
20363fbcdbf3SJiri Pirko copy_to_cpu, flags);
20373fbcdbf3SJiri Pirko if (err)
20383fbcdbf3SJiri Pirko return err;
20393fbcdbf3SJiri Pirko
20403fbcdbf3SJiri Pirko eth_type = htons(ETH_P_IPV6);
204100fc0c51SArkadi Sharshevsky err = ofdpa_flow_tbl_term_mac(ofdpa_port, ofdpa_port->pport,
204200fc0c51SArkadi Sharshevsky in_pport_mask, eth_type,
204300fc0c51SArkadi Sharshevsky ofdpa_port->dev->dev_addr,
20443fbcdbf3SJiri Pirko dst_mac_mask, vlan_id, vlan_id_mask,
20453fbcdbf3SJiri Pirko copy_to_cpu, flags);
20463fbcdbf3SJiri Pirko
20473fbcdbf3SJiri Pirko return err;
20483fbcdbf3SJiri Pirko }
20493fbcdbf3SJiri Pirko
ofdpa_port_fwding(struct ofdpa_port * ofdpa_port,int flags)205000fc0c51SArkadi Sharshevsky static int ofdpa_port_fwding(struct ofdpa_port *ofdpa_port, int flags)
20513fbcdbf3SJiri Pirko {
20523fbcdbf3SJiri Pirko bool pop_vlan;
20533fbcdbf3SJiri Pirko u32 out_pport;
20543fbcdbf3SJiri Pirko __be16 vlan_id;
20553fbcdbf3SJiri Pirko u16 vid;
20563fbcdbf3SJiri Pirko int err;
20573fbcdbf3SJiri Pirko
20583fbcdbf3SJiri Pirko /* Port will be forwarding-enabled if its STP state is LEARNING
20593fbcdbf3SJiri Pirko * or FORWARDING. Traffic from CPU can still egress, regardless of
20603fbcdbf3SJiri Pirko * port STP state. Use L2 interface group on port VLANs as a way
20613fbcdbf3SJiri Pirko * to toggle port forwarding: if forwarding is disabled, L2
20623fbcdbf3SJiri Pirko * interface group will not exist.
20633fbcdbf3SJiri Pirko */
20643fbcdbf3SJiri Pirko
20653fbcdbf3SJiri Pirko if (ofdpa_port->stp_state != BR_STATE_LEARNING &&
20663fbcdbf3SJiri Pirko ofdpa_port->stp_state != BR_STATE_FORWARDING)
20673fbcdbf3SJiri Pirko flags |= OFDPA_OP_FLAG_REMOVE;
20683fbcdbf3SJiri Pirko
20693fbcdbf3SJiri Pirko out_pport = ofdpa_port->pport;
20703fbcdbf3SJiri Pirko for (vid = 1; vid < VLAN_N_VID; vid++) {
20713fbcdbf3SJiri Pirko if (!test_bit(vid, ofdpa_port->vlan_bitmap))
20723fbcdbf3SJiri Pirko continue;
20733fbcdbf3SJiri Pirko vlan_id = htons(vid);
20743fbcdbf3SJiri Pirko pop_vlan = ofdpa_vlan_id_is_internal(vlan_id);
207500fc0c51SArkadi Sharshevsky err = ofdpa_group_l2_interface(ofdpa_port, flags,
20763fbcdbf3SJiri Pirko vlan_id, out_pport, pop_vlan);
20773fbcdbf3SJiri Pirko if (err) {
20783fbcdbf3SJiri Pirko netdev_err(ofdpa_port->dev, "Error (%d) port VLAN l2 group for pport %d\n",
20793fbcdbf3SJiri Pirko err, out_pport);
20803fbcdbf3SJiri Pirko return err;
20813fbcdbf3SJiri Pirko }
20823fbcdbf3SJiri Pirko }
20833fbcdbf3SJiri Pirko
20843fbcdbf3SJiri Pirko return 0;
20853fbcdbf3SJiri Pirko }
20863fbcdbf3SJiri Pirko
ofdpa_port_stp_update(struct ofdpa_port * ofdpa_port,int flags,u8 state)20873fbcdbf3SJiri Pirko static int ofdpa_port_stp_update(struct ofdpa_port *ofdpa_port,
20883fbcdbf3SJiri Pirko int flags, u8 state)
20893fbcdbf3SJiri Pirko {
20903fbcdbf3SJiri Pirko bool want[OFDPA_CTRL_MAX] = { 0, };
20913fbcdbf3SJiri Pirko bool prev_ctrls[OFDPA_CTRL_MAX];
209216b8b6deSArnd Bergmann u8 prev_state;
20933fbcdbf3SJiri Pirko int err;
20943fbcdbf3SJiri Pirko int i;
20953fbcdbf3SJiri Pirko
209600fc0c51SArkadi Sharshevsky memcpy(prev_ctrls, ofdpa_port->ctrls, sizeof(prev_ctrls));
20973fbcdbf3SJiri Pirko prev_state = ofdpa_port->stp_state;
209800fc0c51SArkadi Sharshevsky
209900fc0c51SArkadi Sharshevsky if (ofdpa_port->stp_state == state)
21003fbcdbf3SJiri Pirko return 0;
21013fbcdbf3SJiri Pirko
21023fbcdbf3SJiri Pirko ofdpa_port->stp_state = state;
21033fbcdbf3SJiri Pirko
21043fbcdbf3SJiri Pirko switch (state) {
21053fbcdbf3SJiri Pirko case BR_STATE_DISABLED:
21063fbcdbf3SJiri Pirko /* port is completely disabled */
21073fbcdbf3SJiri Pirko break;
21083fbcdbf3SJiri Pirko case BR_STATE_LISTENING:
21093fbcdbf3SJiri Pirko case BR_STATE_BLOCKING:
21103fbcdbf3SJiri Pirko want[OFDPA_CTRL_LINK_LOCAL_MCAST] = true;
21113fbcdbf3SJiri Pirko break;
21123fbcdbf3SJiri Pirko case BR_STATE_LEARNING:
21133fbcdbf3SJiri Pirko case BR_STATE_FORWARDING:
21143fbcdbf3SJiri Pirko if (!ofdpa_port_is_ovsed(ofdpa_port))
21153fbcdbf3SJiri Pirko want[OFDPA_CTRL_LINK_LOCAL_MCAST] = true;
21163fbcdbf3SJiri Pirko want[OFDPA_CTRL_IPV4_MCAST] = true;
21173fbcdbf3SJiri Pirko want[OFDPA_CTRL_IPV6_MCAST] = true;
21183fbcdbf3SJiri Pirko if (ofdpa_port_is_bridged(ofdpa_port))
21193fbcdbf3SJiri Pirko want[OFDPA_CTRL_DFLT_BRIDGING] = true;
21203fbcdbf3SJiri Pirko else if (ofdpa_port_is_ovsed(ofdpa_port))
21213fbcdbf3SJiri Pirko want[OFDPA_CTRL_DFLT_OVS] = true;
21223fbcdbf3SJiri Pirko else
21233fbcdbf3SJiri Pirko want[OFDPA_CTRL_LOCAL_ARP] = true;
21243fbcdbf3SJiri Pirko break;
21253fbcdbf3SJiri Pirko }
21263fbcdbf3SJiri Pirko
21273fbcdbf3SJiri Pirko for (i = 0; i < OFDPA_CTRL_MAX; i++) {
21283fbcdbf3SJiri Pirko if (want[i] != ofdpa_port->ctrls[i]) {
21293fbcdbf3SJiri Pirko int ctrl_flags = flags |
21303fbcdbf3SJiri Pirko (want[i] ? 0 : OFDPA_OP_FLAG_REMOVE);
213100fc0c51SArkadi Sharshevsky err = ofdpa_port_ctrl(ofdpa_port, ctrl_flags,
21323fbcdbf3SJiri Pirko &ofdpa_ctrls[i]);
21333fbcdbf3SJiri Pirko if (err)
213400fc0c51SArkadi Sharshevsky goto err_port_ctrl;
21353fbcdbf3SJiri Pirko ofdpa_port->ctrls[i] = want[i];
21363fbcdbf3SJiri Pirko }
21373fbcdbf3SJiri Pirko }
21383fbcdbf3SJiri Pirko
213900fc0c51SArkadi Sharshevsky err = ofdpa_port_fdb_flush(ofdpa_port, flags);
21403fbcdbf3SJiri Pirko if (err)
214100fc0c51SArkadi Sharshevsky goto err_fdb_flush;
21423fbcdbf3SJiri Pirko
214300fc0c51SArkadi Sharshevsky err = ofdpa_port_fwding(ofdpa_port, flags);
214400fc0c51SArkadi Sharshevsky if (err)
214500fc0c51SArkadi Sharshevsky goto err_port_fwding;
21463fbcdbf3SJiri Pirko
214700fc0c51SArkadi Sharshevsky return 0;
214800fc0c51SArkadi Sharshevsky
214900fc0c51SArkadi Sharshevsky err_port_ctrl:
215000fc0c51SArkadi Sharshevsky err_fdb_flush:
215100fc0c51SArkadi Sharshevsky err_port_fwding:
21523fbcdbf3SJiri Pirko memcpy(ofdpa_port->ctrls, prev_ctrls, sizeof(prev_ctrls));
21533fbcdbf3SJiri Pirko ofdpa_port->stp_state = prev_state;
21543fbcdbf3SJiri Pirko return err;
21553fbcdbf3SJiri Pirko }
21563fbcdbf3SJiri Pirko
ofdpa_port_fwd_enable(struct ofdpa_port * ofdpa_port,int flags)21573fbcdbf3SJiri Pirko static int ofdpa_port_fwd_enable(struct ofdpa_port *ofdpa_port, int flags)
21583fbcdbf3SJiri Pirko {
21593fbcdbf3SJiri Pirko if (ofdpa_port_is_bridged(ofdpa_port))
21603fbcdbf3SJiri Pirko /* bridge STP will enable port */
21613fbcdbf3SJiri Pirko return 0;
21623fbcdbf3SJiri Pirko
21633fbcdbf3SJiri Pirko /* port is not bridged, so simulate going to FORWARDING state */
216400fc0c51SArkadi Sharshevsky return ofdpa_port_stp_update(ofdpa_port, flags,
21653fbcdbf3SJiri Pirko BR_STATE_FORWARDING);
21663fbcdbf3SJiri Pirko }
21673fbcdbf3SJiri Pirko
ofdpa_port_fwd_disable(struct ofdpa_port * ofdpa_port,int flags)21683fbcdbf3SJiri Pirko static int ofdpa_port_fwd_disable(struct ofdpa_port *ofdpa_port, int flags)
21693fbcdbf3SJiri Pirko {
21703fbcdbf3SJiri Pirko if (ofdpa_port_is_bridged(ofdpa_port))
21713fbcdbf3SJiri Pirko /* bridge STP will disable port */
21723fbcdbf3SJiri Pirko return 0;
21733fbcdbf3SJiri Pirko
21743fbcdbf3SJiri Pirko /* port is not bridged, so simulate going to DISABLED state */
217500fc0c51SArkadi Sharshevsky return ofdpa_port_stp_update(ofdpa_port, flags,
21763fbcdbf3SJiri Pirko BR_STATE_DISABLED);
21773fbcdbf3SJiri Pirko }
21783fbcdbf3SJiri Pirko
ofdpa_port_vlan_add(struct ofdpa_port * ofdpa_port,u16 vid,u16 flags)21793fbcdbf3SJiri Pirko static int ofdpa_port_vlan_add(struct ofdpa_port *ofdpa_port,
21803fbcdbf3SJiri Pirko u16 vid, u16 flags)
21813fbcdbf3SJiri Pirko {
21823fbcdbf3SJiri Pirko int err;
21833fbcdbf3SJiri Pirko
21843fbcdbf3SJiri Pirko /* XXX deal with flags for PVID and untagged */
21853fbcdbf3SJiri Pirko
218600fc0c51SArkadi Sharshevsky err = ofdpa_port_vlan(ofdpa_port, 0, vid);
21873fbcdbf3SJiri Pirko if (err)
21883fbcdbf3SJiri Pirko return err;
21893fbcdbf3SJiri Pirko
219000fc0c51SArkadi Sharshevsky err = ofdpa_port_router_mac(ofdpa_port, 0, htons(vid));
21913fbcdbf3SJiri Pirko if (err)
219200fc0c51SArkadi Sharshevsky ofdpa_port_vlan(ofdpa_port,
21933fbcdbf3SJiri Pirko OFDPA_OP_FLAG_REMOVE, vid);
21943fbcdbf3SJiri Pirko
21953fbcdbf3SJiri Pirko return err;
21963fbcdbf3SJiri Pirko }
21973fbcdbf3SJiri Pirko
ofdpa_port_vlan_del(struct ofdpa_port * ofdpa_port,u16 vid,u16 flags)21983fbcdbf3SJiri Pirko static int ofdpa_port_vlan_del(struct ofdpa_port *ofdpa_port,
21993fbcdbf3SJiri Pirko u16 vid, u16 flags)
22003fbcdbf3SJiri Pirko {
22013fbcdbf3SJiri Pirko int err;
22023fbcdbf3SJiri Pirko
220300fc0c51SArkadi Sharshevsky err = ofdpa_port_router_mac(ofdpa_port, OFDPA_OP_FLAG_REMOVE,
220400fc0c51SArkadi Sharshevsky htons(vid));
22053fbcdbf3SJiri Pirko if (err)
22063fbcdbf3SJiri Pirko return err;
22073fbcdbf3SJiri Pirko
220800fc0c51SArkadi Sharshevsky return ofdpa_port_vlan(ofdpa_port, OFDPA_OP_FLAG_REMOVE,
220900fc0c51SArkadi Sharshevsky vid);
22103fbcdbf3SJiri Pirko }
22113fbcdbf3SJiri Pirko
22123fbcdbf3SJiri Pirko static struct ofdpa_internal_vlan_tbl_entry *
ofdpa_internal_vlan_tbl_find(const struct ofdpa * ofdpa,int ifindex)22133fbcdbf3SJiri Pirko ofdpa_internal_vlan_tbl_find(const struct ofdpa *ofdpa, int ifindex)
22143fbcdbf3SJiri Pirko {
22153fbcdbf3SJiri Pirko struct ofdpa_internal_vlan_tbl_entry *found;
22163fbcdbf3SJiri Pirko
22173fbcdbf3SJiri Pirko hash_for_each_possible(ofdpa->internal_vlan_tbl, found,
22183fbcdbf3SJiri Pirko entry, ifindex) {
22193fbcdbf3SJiri Pirko if (found->ifindex == ifindex)
22203fbcdbf3SJiri Pirko return found;
22213fbcdbf3SJiri Pirko }
22223fbcdbf3SJiri Pirko
22233fbcdbf3SJiri Pirko return NULL;
22243fbcdbf3SJiri Pirko }
22253fbcdbf3SJiri Pirko
ofdpa_port_internal_vlan_id_get(struct ofdpa_port * ofdpa_port,int ifindex)22263fbcdbf3SJiri Pirko static __be16 ofdpa_port_internal_vlan_id_get(struct ofdpa_port *ofdpa_port,
22273fbcdbf3SJiri Pirko int ifindex)
22283fbcdbf3SJiri Pirko {
22293fbcdbf3SJiri Pirko struct ofdpa *ofdpa = ofdpa_port->ofdpa;
22303fbcdbf3SJiri Pirko struct ofdpa_internal_vlan_tbl_entry *entry;
22313fbcdbf3SJiri Pirko struct ofdpa_internal_vlan_tbl_entry *found;
22323fbcdbf3SJiri Pirko unsigned long lock_flags;
22333fbcdbf3SJiri Pirko int i;
22343fbcdbf3SJiri Pirko
22353fbcdbf3SJiri Pirko entry = kzalloc(sizeof(*entry), GFP_KERNEL);
22363fbcdbf3SJiri Pirko if (!entry)
22373fbcdbf3SJiri Pirko return 0;
22383fbcdbf3SJiri Pirko
22393fbcdbf3SJiri Pirko entry->ifindex = ifindex;
22403fbcdbf3SJiri Pirko
22413fbcdbf3SJiri Pirko spin_lock_irqsave(&ofdpa->internal_vlan_tbl_lock, lock_flags);
22423fbcdbf3SJiri Pirko
22433fbcdbf3SJiri Pirko found = ofdpa_internal_vlan_tbl_find(ofdpa, ifindex);
22443fbcdbf3SJiri Pirko if (found) {
22453fbcdbf3SJiri Pirko kfree(entry);
22463fbcdbf3SJiri Pirko goto found;
22473fbcdbf3SJiri Pirko }
22483fbcdbf3SJiri Pirko
22493fbcdbf3SJiri Pirko found = entry;
22503fbcdbf3SJiri Pirko hash_add(ofdpa->internal_vlan_tbl, &found->entry, found->ifindex);
22513fbcdbf3SJiri Pirko
22523fbcdbf3SJiri Pirko for (i = 0; i < OFDPA_N_INTERNAL_VLANS; i++) {
22533fbcdbf3SJiri Pirko if (test_and_set_bit(i, ofdpa->internal_vlan_bitmap))
22543fbcdbf3SJiri Pirko continue;
22553fbcdbf3SJiri Pirko found->vlan_id = htons(OFDPA_INTERNAL_VLAN_ID_BASE + i);
22563fbcdbf3SJiri Pirko goto found;
22573fbcdbf3SJiri Pirko }
22583fbcdbf3SJiri Pirko
22593fbcdbf3SJiri Pirko netdev_err(ofdpa_port->dev, "Out of internal VLAN IDs\n");
22603fbcdbf3SJiri Pirko
22613fbcdbf3SJiri Pirko found:
22623fbcdbf3SJiri Pirko found->ref_count++;
22633fbcdbf3SJiri Pirko spin_unlock_irqrestore(&ofdpa->internal_vlan_tbl_lock, lock_flags);
22643fbcdbf3SJiri Pirko
22653fbcdbf3SJiri Pirko return found->vlan_id;
22663fbcdbf3SJiri Pirko }
22673fbcdbf3SJiri Pirko
ofdpa_port_fib_ipv4(struct ofdpa_port * ofdpa_port,__be32 dst,int dst_len,struct fib_info * fi,u32 tb_id,int flags)226800fc0c51SArkadi Sharshevsky static int ofdpa_port_fib_ipv4(struct ofdpa_port *ofdpa_port, __be32 dst,
226900fc0c51SArkadi Sharshevsky int dst_len, struct fib_info *fi, u32 tb_id,
227000fc0c51SArkadi Sharshevsky int flags)
22713fbcdbf3SJiri Pirko {
22723fbcdbf3SJiri Pirko const struct fib_nh *nh;
22733fbcdbf3SJiri Pirko __be16 eth_type = htons(ETH_P_IP);
22743fbcdbf3SJiri Pirko __be32 dst_mask = inet_make_mask(dst_len);
22753fbcdbf3SJiri Pirko __be16 internal_vlan_id = ofdpa_port->internal_vlan_id;
22763fbcdbf3SJiri Pirko u32 priority = fi->fib_priority;
22773fbcdbf3SJiri Pirko enum rocker_of_dpa_table_id goto_tbl =
22783fbcdbf3SJiri Pirko ROCKER_OF_DPA_TABLE_ID_ACL_POLICY;
22793fbcdbf3SJiri Pirko u32 group_id;
22803fbcdbf3SJiri Pirko bool nh_on_port;
22813fbcdbf3SJiri Pirko bool has_gw;
22823fbcdbf3SJiri Pirko u32 index;
22833fbcdbf3SJiri Pirko int err;
22843fbcdbf3SJiri Pirko
22853fbcdbf3SJiri Pirko /* XXX support ECMP */
22863fbcdbf3SJiri Pirko
22875481d73fSDavid Ahern nh = fib_info_nh(fi, 0);
22885481d73fSDavid Ahern nh_on_port = (nh->fib_nh_dev == ofdpa_port->dev);
2289b75ed8b1SDavid Ahern has_gw = !!nh->fib_nh_gw4;
22903fbcdbf3SJiri Pirko
22913fbcdbf3SJiri Pirko if (has_gw && nh_on_port) {
229200fc0c51SArkadi Sharshevsky err = ofdpa_port_ipv4_nh(ofdpa_port, flags,
2293b75ed8b1SDavid Ahern nh->fib_nh_gw4, &index);
22943fbcdbf3SJiri Pirko if (err)
22953fbcdbf3SJiri Pirko return err;
22963fbcdbf3SJiri Pirko
22973fbcdbf3SJiri Pirko group_id = ROCKER_GROUP_L3_UNICAST(index);
22983fbcdbf3SJiri Pirko } else {
22993fbcdbf3SJiri Pirko /* Send to CPU for processing */
23003fbcdbf3SJiri Pirko group_id = ROCKER_GROUP_L2_INTERFACE(internal_vlan_id, 0);
23013fbcdbf3SJiri Pirko }
23023fbcdbf3SJiri Pirko
230300fc0c51SArkadi Sharshevsky err = ofdpa_flow_tbl_ucast4_routing(ofdpa_port, eth_type, dst,
23043fbcdbf3SJiri Pirko dst_mask, priority, goto_tbl,
2305936bd486SJiri Pirko group_id, fi, flags);
23063fbcdbf3SJiri Pirko if (err)
23073fbcdbf3SJiri Pirko netdev_err(ofdpa_port->dev, "Error (%d) IPv4 route %pI4\n",
23083fbcdbf3SJiri Pirko err, &dst);
23093fbcdbf3SJiri Pirko
23103fbcdbf3SJiri Pirko return err;
23113fbcdbf3SJiri Pirko }
23123fbcdbf3SJiri Pirko
23133fbcdbf3SJiri Pirko static void
ofdpa_port_internal_vlan_id_put(const struct ofdpa_port * ofdpa_port,int ifindex)23143fbcdbf3SJiri Pirko ofdpa_port_internal_vlan_id_put(const struct ofdpa_port *ofdpa_port,
23153fbcdbf3SJiri Pirko int ifindex)
23163fbcdbf3SJiri Pirko {
23173fbcdbf3SJiri Pirko struct ofdpa *ofdpa = ofdpa_port->ofdpa;
23183fbcdbf3SJiri Pirko struct ofdpa_internal_vlan_tbl_entry *found;
23193fbcdbf3SJiri Pirko unsigned long lock_flags;
23203fbcdbf3SJiri Pirko unsigned long bit;
23213fbcdbf3SJiri Pirko
23223fbcdbf3SJiri Pirko spin_lock_irqsave(&ofdpa->internal_vlan_tbl_lock, lock_flags);
23233fbcdbf3SJiri Pirko
23243fbcdbf3SJiri Pirko found = ofdpa_internal_vlan_tbl_find(ofdpa, ifindex);
23253fbcdbf3SJiri Pirko if (!found) {
23263fbcdbf3SJiri Pirko netdev_err(ofdpa_port->dev,
23273fbcdbf3SJiri Pirko "ifindex (%d) not found in internal VLAN tbl\n",
23283fbcdbf3SJiri Pirko ifindex);
23293fbcdbf3SJiri Pirko goto not_found;
23303fbcdbf3SJiri Pirko }
23313fbcdbf3SJiri Pirko
23323fbcdbf3SJiri Pirko if (--found->ref_count <= 0) {
23333fbcdbf3SJiri Pirko bit = ntohs(found->vlan_id) - OFDPA_INTERNAL_VLAN_ID_BASE;
23343fbcdbf3SJiri Pirko clear_bit(bit, ofdpa->internal_vlan_bitmap);
23353fbcdbf3SJiri Pirko hash_del(&found->entry);
23363fbcdbf3SJiri Pirko kfree(found);
23373fbcdbf3SJiri Pirko }
23383fbcdbf3SJiri Pirko
23393fbcdbf3SJiri Pirko not_found:
23403fbcdbf3SJiri Pirko spin_unlock_irqrestore(&ofdpa->internal_vlan_tbl_lock, lock_flags);
23413fbcdbf3SJiri Pirko }
23423fbcdbf3SJiri Pirko
23433fbcdbf3SJiri Pirko /**********************************
23443fbcdbf3SJiri Pirko * Rocker world ops implementation
23453fbcdbf3SJiri Pirko **********************************/
23463fbcdbf3SJiri Pirko
ofdpa_init(struct rocker * rocker)23473fbcdbf3SJiri Pirko static int ofdpa_init(struct rocker *rocker)
23483fbcdbf3SJiri Pirko {
23493fbcdbf3SJiri Pirko struct ofdpa *ofdpa = rocker->wpriv;
23503fbcdbf3SJiri Pirko
23513fbcdbf3SJiri Pirko ofdpa->rocker = rocker;
23523fbcdbf3SJiri Pirko
23533fbcdbf3SJiri Pirko hash_init(ofdpa->flow_tbl);
23543fbcdbf3SJiri Pirko spin_lock_init(&ofdpa->flow_tbl_lock);
23553fbcdbf3SJiri Pirko
23563fbcdbf3SJiri Pirko hash_init(ofdpa->group_tbl);
23573fbcdbf3SJiri Pirko spin_lock_init(&ofdpa->group_tbl_lock);
23583fbcdbf3SJiri Pirko
23593fbcdbf3SJiri Pirko hash_init(ofdpa->fdb_tbl);
23603fbcdbf3SJiri Pirko spin_lock_init(&ofdpa->fdb_tbl_lock);
23613fbcdbf3SJiri Pirko
23623fbcdbf3SJiri Pirko hash_init(ofdpa->internal_vlan_tbl);
23633fbcdbf3SJiri Pirko spin_lock_init(&ofdpa->internal_vlan_tbl_lock);
23643fbcdbf3SJiri Pirko
23653fbcdbf3SJiri Pirko hash_init(ofdpa->neigh_tbl);
23663fbcdbf3SJiri Pirko spin_lock_init(&ofdpa->neigh_tbl_lock);
23673fbcdbf3SJiri Pirko
2368e99e88a9SKees Cook timer_setup(&ofdpa->fdb_cleanup_timer, ofdpa_fdb_cleanup, 0);
23693fbcdbf3SJiri Pirko mod_timer(&ofdpa->fdb_cleanup_timer, jiffies);
23703fbcdbf3SJiri Pirko
23713a8befcdSJiri Pirko ofdpa->ageing_time = BR_DEFAULT_AGEING_TIME;
23723a8befcdSJiri Pirko
23733fbcdbf3SJiri Pirko return 0;
23743fbcdbf3SJiri Pirko }
23753fbcdbf3SJiri Pirko
ofdpa_fini(struct rocker * rocker)23763fbcdbf3SJiri Pirko static void ofdpa_fini(struct rocker *rocker)
23773fbcdbf3SJiri Pirko {
23783fbcdbf3SJiri Pirko struct ofdpa *ofdpa = rocker->wpriv;
23793fbcdbf3SJiri Pirko
23803fbcdbf3SJiri Pirko unsigned long flags;
23813fbcdbf3SJiri Pirko struct ofdpa_flow_tbl_entry *flow_entry;
23823fbcdbf3SJiri Pirko struct ofdpa_group_tbl_entry *group_entry;
23833fbcdbf3SJiri Pirko struct ofdpa_fdb_tbl_entry *fdb_entry;
23843fbcdbf3SJiri Pirko struct ofdpa_internal_vlan_tbl_entry *internal_vlan_entry;
23853fbcdbf3SJiri Pirko struct ofdpa_neigh_tbl_entry *neigh_entry;
23863fbcdbf3SJiri Pirko struct hlist_node *tmp;
23873fbcdbf3SJiri Pirko int bkt;
23883fbcdbf3SJiri Pirko
23893fbcdbf3SJiri Pirko del_timer_sync(&ofdpa->fdb_cleanup_timer);
2390db701955SIdo Schimmel flush_workqueue(rocker->rocker_owq);
23913fbcdbf3SJiri Pirko
23923fbcdbf3SJiri Pirko spin_lock_irqsave(&ofdpa->flow_tbl_lock, flags);
23933fbcdbf3SJiri Pirko hash_for_each_safe(ofdpa->flow_tbl, bkt, tmp, flow_entry, entry)
23943fbcdbf3SJiri Pirko hash_del(&flow_entry->entry);
23953fbcdbf3SJiri Pirko spin_unlock_irqrestore(&ofdpa->flow_tbl_lock, flags);
23963fbcdbf3SJiri Pirko
23973fbcdbf3SJiri Pirko spin_lock_irqsave(&ofdpa->group_tbl_lock, flags);
23983fbcdbf3SJiri Pirko hash_for_each_safe(ofdpa->group_tbl, bkt, tmp, group_entry, entry)
23993fbcdbf3SJiri Pirko hash_del(&group_entry->entry);
24003fbcdbf3SJiri Pirko spin_unlock_irqrestore(&ofdpa->group_tbl_lock, flags);
24013fbcdbf3SJiri Pirko
24023fbcdbf3SJiri Pirko spin_lock_irqsave(&ofdpa->fdb_tbl_lock, flags);
24033fbcdbf3SJiri Pirko hash_for_each_safe(ofdpa->fdb_tbl, bkt, tmp, fdb_entry, entry)
24043fbcdbf3SJiri Pirko hash_del(&fdb_entry->entry);
24053fbcdbf3SJiri Pirko spin_unlock_irqrestore(&ofdpa->fdb_tbl_lock, flags);
24063fbcdbf3SJiri Pirko
24073fbcdbf3SJiri Pirko spin_lock_irqsave(&ofdpa->internal_vlan_tbl_lock, flags);
24083fbcdbf3SJiri Pirko hash_for_each_safe(ofdpa->internal_vlan_tbl, bkt,
24093fbcdbf3SJiri Pirko tmp, internal_vlan_entry, entry)
24103fbcdbf3SJiri Pirko hash_del(&internal_vlan_entry->entry);
24113fbcdbf3SJiri Pirko spin_unlock_irqrestore(&ofdpa->internal_vlan_tbl_lock, flags);
24123fbcdbf3SJiri Pirko
24133fbcdbf3SJiri Pirko spin_lock_irqsave(&ofdpa->neigh_tbl_lock, flags);
24143fbcdbf3SJiri Pirko hash_for_each_safe(ofdpa->neigh_tbl, bkt, tmp, neigh_entry, entry)
24153fbcdbf3SJiri Pirko hash_del(&neigh_entry->entry);
24163fbcdbf3SJiri Pirko spin_unlock_irqrestore(&ofdpa->neigh_tbl_lock, flags);
24173fbcdbf3SJiri Pirko }
24183fbcdbf3SJiri Pirko
ofdpa_port_pre_init(struct rocker_port * rocker_port)24193fbcdbf3SJiri Pirko static int ofdpa_port_pre_init(struct rocker_port *rocker_port)
24203fbcdbf3SJiri Pirko {
24213fbcdbf3SJiri Pirko struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
24223fbcdbf3SJiri Pirko
24233fbcdbf3SJiri Pirko ofdpa_port->ofdpa = rocker_port->rocker->wpriv;
24243fbcdbf3SJiri Pirko ofdpa_port->rocker_port = rocker_port;
24253fbcdbf3SJiri Pirko ofdpa_port->dev = rocker_port->dev;
24263fbcdbf3SJiri Pirko ofdpa_port->pport = rocker_port->pport;
24278cc186a4SArkadi Sharshevsky ofdpa_port->brport_flags = BR_LEARNING;
24283fbcdbf3SJiri Pirko ofdpa_port->ageing_time = BR_DEFAULT_AGEING_TIME;
24293fbcdbf3SJiri Pirko return 0;
24303fbcdbf3SJiri Pirko }
24313fbcdbf3SJiri Pirko
ofdpa_port_init(struct rocker_port * rocker_port)24323fbcdbf3SJiri Pirko static int ofdpa_port_init(struct rocker_port *rocker_port)
24333fbcdbf3SJiri Pirko {
24343fbcdbf3SJiri Pirko struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
24353fbcdbf3SJiri Pirko int err;
24363fbcdbf3SJiri Pirko
24373fbcdbf3SJiri Pirko rocker_port_set_learning(rocker_port,
24383fbcdbf3SJiri Pirko !!(ofdpa_port->brport_flags & BR_LEARNING));
24393fbcdbf3SJiri Pirko
244000fc0c51SArkadi Sharshevsky err = ofdpa_port_ig_tbl(ofdpa_port, 0);
24413fbcdbf3SJiri Pirko if (err) {
24423fbcdbf3SJiri Pirko netdev_err(ofdpa_port->dev, "install ig port table failed\n");
24433fbcdbf3SJiri Pirko return err;
24443fbcdbf3SJiri Pirko }
24453fbcdbf3SJiri Pirko
24463fbcdbf3SJiri Pirko ofdpa_port->internal_vlan_id =
24473fbcdbf3SJiri Pirko ofdpa_port_internal_vlan_id_get(ofdpa_port,
24483fbcdbf3SJiri Pirko ofdpa_port->dev->ifindex);
24493fbcdbf3SJiri Pirko
245000fc0c51SArkadi Sharshevsky err = ofdpa_port_vlan_add(ofdpa_port, OFDPA_UNTAGGED_VID, 0);
24513fbcdbf3SJiri Pirko if (err) {
24523fbcdbf3SJiri Pirko netdev_err(ofdpa_port->dev, "install untagged VLAN failed\n");
24533fbcdbf3SJiri Pirko goto err_untagged_vlan;
24543fbcdbf3SJiri Pirko }
24553fbcdbf3SJiri Pirko return 0;
24563fbcdbf3SJiri Pirko
24573fbcdbf3SJiri Pirko err_untagged_vlan:
245800fc0c51SArkadi Sharshevsky ofdpa_port_ig_tbl(ofdpa_port, OFDPA_OP_FLAG_REMOVE);
24593fbcdbf3SJiri Pirko return err;
24603fbcdbf3SJiri Pirko }
24613fbcdbf3SJiri Pirko
ofdpa_port_fini(struct rocker_port * rocker_port)24623fbcdbf3SJiri Pirko static void ofdpa_port_fini(struct rocker_port *rocker_port)
24633fbcdbf3SJiri Pirko {
24643fbcdbf3SJiri Pirko struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
24653fbcdbf3SJiri Pirko
246600fc0c51SArkadi Sharshevsky ofdpa_port_ig_tbl(ofdpa_port, OFDPA_OP_FLAG_REMOVE);
24673fbcdbf3SJiri Pirko }
24683fbcdbf3SJiri Pirko
ofdpa_port_open(struct rocker_port * rocker_port)24693fbcdbf3SJiri Pirko static int ofdpa_port_open(struct rocker_port *rocker_port)
24703fbcdbf3SJiri Pirko {
24713fbcdbf3SJiri Pirko struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
24723fbcdbf3SJiri Pirko
24733fbcdbf3SJiri Pirko return ofdpa_port_fwd_enable(ofdpa_port, 0);
24743fbcdbf3SJiri Pirko }
24753fbcdbf3SJiri Pirko
ofdpa_port_stop(struct rocker_port * rocker_port)24763fbcdbf3SJiri Pirko static void ofdpa_port_stop(struct rocker_port *rocker_port)
24773fbcdbf3SJiri Pirko {
24783fbcdbf3SJiri Pirko struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
24793fbcdbf3SJiri Pirko
24803fbcdbf3SJiri Pirko ofdpa_port_fwd_disable(ofdpa_port, OFDPA_OP_FLAG_NOWAIT);
24813fbcdbf3SJiri Pirko }
24823fbcdbf3SJiri Pirko
ofdpa_port_attr_stp_state_set(struct rocker_port * rocker_port,u8 state)24833fbcdbf3SJiri Pirko static int ofdpa_port_attr_stp_state_set(struct rocker_port *rocker_port,
248400fc0c51SArkadi Sharshevsky u8 state)
24853fbcdbf3SJiri Pirko {
24863fbcdbf3SJiri Pirko struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
24873fbcdbf3SJiri Pirko
248800fc0c51SArkadi Sharshevsky return ofdpa_port_stp_update(ofdpa_port, 0, state);
24893fbcdbf3SJiri Pirko }
24903fbcdbf3SJiri Pirko
ofdpa_port_attr_bridge_flags_set(struct rocker_port * rocker_port,unsigned long brport_flags)24913fbcdbf3SJiri Pirko static int ofdpa_port_attr_bridge_flags_set(struct rocker_port *rocker_port,
2492bae33f2bSVladimir Oltean unsigned long brport_flags)
24933fbcdbf3SJiri Pirko {
24943fbcdbf3SJiri Pirko struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
24953fbcdbf3SJiri Pirko unsigned long orig_flags;
24963fbcdbf3SJiri Pirko int err = 0;
24973fbcdbf3SJiri Pirko
24983fbcdbf3SJiri Pirko orig_flags = ofdpa_port->brport_flags;
24993fbcdbf3SJiri Pirko ofdpa_port->brport_flags = brport_flags;
2500bae33f2bSVladimir Oltean
2501bae33f2bSVladimir Oltean if ((orig_flags ^ ofdpa_port->brport_flags) & BR_LEARNING)
25023fbcdbf3SJiri Pirko err = rocker_port_set_learning(ofdpa_port->rocker_port,
25033fbcdbf3SJiri Pirko !!(ofdpa_port->brport_flags & BR_LEARNING));
25043fbcdbf3SJiri Pirko
25053fbcdbf3SJiri Pirko return err;
25063fbcdbf3SJiri Pirko }
25073fbcdbf3SJiri Pirko
25083fbcdbf3SJiri Pirko static int
ofdpa_port_attr_bridge_flags_support_get(const struct rocker_port * rocker_port,unsigned long * p_brport_flags_support)250996673a30SArkadi Sharshevsky ofdpa_port_attr_bridge_flags_support_get(const struct rocker_port *
251096673a30SArkadi Sharshevsky rocker_port,
251196673a30SArkadi Sharshevsky unsigned long *
251296673a30SArkadi Sharshevsky p_brport_flags_support)
251396673a30SArkadi Sharshevsky {
251496673a30SArkadi Sharshevsky *p_brport_flags_support = BR_LEARNING;
251596673a30SArkadi Sharshevsky return 0;
251696673a30SArkadi Sharshevsky }
251796673a30SArkadi Sharshevsky
251896673a30SArkadi Sharshevsky static int
ofdpa_port_attr_bridge_ageing_time_set(struct rocker_port * rocker_port,u32 ageing_time)25193fbcdbf3SJiri Pirko ofdpa_port_attr_bridge_ageing_time_set(struct rocker_port *rocker_port,
2520bae33f2bSVladimir Oltean u32 ageing_time)
25213fbcdbf3SJiri Pirko {
25223fbcdbf3SJiri Pirko struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
25233a8befcdSJiri Pirko struct ofdpa *ofdpa = ofdpa_port->ofdpa;
25243fbcdbf3SJiri Pirko
25253fbcdbf3SJiri Pirko ofdpa_port->ageing_time = clock_t_to_jiffies(ageing_time);
25263a8befcdSJiri Pirko if (ofdpa_port->ageing_time < ofdpa->ageing_time)
25273a8befcdSJiri Pirko ofdpa->ageing_time = ofdpa_port->ageing_time;
25283fbcdbf3SJiri Pirko mod_timer(&ofdpa_port->ofdpa->fdb_cleanup_timer, jiffies);
25293fbcdbf3SJiri Pirko
25303fbcdbf3SJiri Pirko return 0;
25313fbcdbf3SJiri Pirko }
25323fbcdbf3SJiri Pirko
ofdpa_port_obj_vlan_add(struct rocker_port * rocker_port,const struct switchdev_obj_port_vlan * vlan)25333fbcdbf3SJiri Pirko static int ofdpa_port_obj_vlan_add(struct rocker_port *rocker_port,
253400fc0c51SArkadi Sharshevsky const struct switchdev_obj_port_vlan *vlan)
25353fbcdbf3SJiri Pirko {
25363fbcdbf3SJiri Pirko struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
25373fbcdbf3SJiri Pirko
2538b7a9e0daSVladimir Oltean return ofdpa_port_vlan_add(ofdpa_port, vlan->vid, vlan->flags);
25393fbcdbf3SJiri Pirko }
25403fbcdbf3SJiri Pirko
ofdpa_port_obj_vlan_del(struct rocker_port * rocker_port,const struct switchdev_obj_port_vlan * vlan)25413fbcdbf3SJiri Pirko static int ofdpa_port_obj_vlan_del(struct rocker_port *rocker_port,
25423fbcdbf3SJiri Pirko const struct switchdev_obj_port_vlan *vlan)
25433fbcdbf3SJiri Pirko {
25443fbcdbf3SJiri Pirko struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
25453fbcdbf3SJiri Pirko
2546b7a9e0daSVladimir Oltean return ofdpa_port_vlan_del(ofdpa_port, vlan->vid, vlan->flags);
25473fbcdbf3SJiri Pirko }
25483fbcdbf3SJiri Pirko
ofdpa_port_obj_fdb_add(struct rocker_port * rocker_port,u16 vid,const unsigned char * addr)25493fbcdbf3SJiri Pirko static int ofdpa_port_obj_fdb_add(struct rocker_port *rocker_port,
255000fc0c51SArkadi Sharshevsky u16 vid, const unsigned char *addr)
25513fbcdbf3SJiri Pirko {
25523fbcdbf3SJiri Pirko struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
255300fc0c51SArkadi Sharshevsky __be16 vlan_id = ofdpa_port_vid_to_vlan(ofdpa_port, vid, NULL);
25543fbcdbf3SJiri Pirko
25553fbcdbf3SJiri Pirko if (!ofdpa_port_is_bridged(ofdpa_port))
25563fbcdbf3SJiri Pirko return -EINVAL;
25573fbcdbf3SJiri Pirko
255800fc0c51SArkadi Sharshevsky return ofdpa_port_fdb(ofdpa_port, addr, vlan_id, 0);
25593fbcdbf3SJiri Pirko }
25603fbcdbf3SJiri Pirko
ofdpa_port_obj_fdb_del(struct rocker_port * rocker_port,u16 vid,const unsigned char * addr)25613fbcdbf3SJiri Pirko static int ofdpa_port_obj_fdb_del(struct rocker_port *rocker_port,
256200fc0c51SArkadi Sharshevsky u16 vid, const unsigned char *addr)
25633fbcdbf3SJiri Pirko {
25643fbcdbf3SJiri Pirko struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
256500fc0c51SArkadi Sharshevsky __be16 vlan_id = ofdpa_port_vid_to_vlan(ofdpa_port, vid, NULL);
25663fbcdbf3SJiri Pirko int flags = OFDPA_OP_FLAG_REMOVE;
25673fbcdbf3SJiri Pirko
25683fbcdbf3SJiri Pirko if (!ofdpa_port_is_bridged(ofdpa_port))
25693fbcdbf3SJiri Pirko return -EINVAL;
25703fbcdbf3SJiri Pirko
257100fc0c51SArkadi Sharshevsky return ofdpa_port_fdb(ofdpa_port, addr, vlan_id, flags);
25723fbcdbf3SJiri Pirko }
25733fbcdbf3SJiri Pirko
ofdpa_port_bridge_join(struct ofdpa_port * ofdpa_port,struct net_device * bridge,struct netlink_ext_ack * extack)25743fbcdbf3SJiri Pirko static int ofdpa_port_bridge_join(struct ofdpa_port *ofdpa_port,
25752f5dc00fSVladimir Oltean struct net_device *bridge,
25762f5dc00fSVladimir Oltean struct netlink_ext_ack *extack)
25773fbcdbf3SJiri Pirko {
25782f5dc00fSVladimir Oltean struct net_device *dev = ofdpa_port->dev;
25793fbcdbf3SJiri Pirko int err;
25803fbcdbf3SJiri Pirko
25813fbcdbf3SJiri Pirko /* Port is joining bridge, so the internal VLAN for the
25823fbcdbf3SJiri Pirko * port is going to change to the bridge internal VLAN.
25833fbcdbf3SJiri Pirko * Let's remove untagged VLAN (vid=0) from port and
25843fbcdbf3SJiri Pirko * re-add once internal VLAN has changed.
25853fbcdbf3SJiri Pirko */
25863fbcdbf3SJiri Pirko
25873fbcdbf3SJiri Pirko err = ofdpa_port_vlan_del(ofdpa_port, OFDPA_UNTAGGED_VID, 0);
25883fbcdbf3SJiri Pirko if (err)
25893fbcdbf3SJiri Pirko return err;
25903fbcdbf3SJiri Pirko
25913fbcdbf3SJiri Pirko ofdpa_port_internal_vlan_id_put(ofdpa_port,
25923fbcdbf3SJiri Pirko ofdpa_port->dev->ifindex);
25933fbcdbf3SJiri Pirko ofdpa_port->internal_vlan_id =
25943fbcdbf3SJiri Pirko ofdpa_port_internal_vlan_id_get(ofdpa_port, bridge->ifindex);
25953fbcdbf3SJiri Pirko
25963fbcdbf3SJiri Pirko ofdpa_port->bridge_dev = bridge;
25973fbcdbf3SJiri Pirko
25982f5dc00fSVladimir Oltean err = ofdpa_port_vlan_add(ofdpa_port, OFDPA_UNTAGGED_VID, 0);
25992f5dc00fSVladimir Oltean if (err)
26002f5dc00fSVladimir Oltean return err;
26012f5dc00fSVladimir Oltean
26024e51bf44SVladimir Oltean return switchdev_bridge_port_offload(dev, dev, NULL, NULL, NULL,
260347211192STobias Waldekranz false, extack);
26043fbcdbf3SJiri Pirko }
26053fbcdbf3SJiri Pirko
ofdpa_port_bridge_leave(struct ofdpa_port * ofdpa_port)26063fbcdbf3SJiri Pirko static int ofdpa_port_bridge_leave(struct ofdpa_port *ofdpa_port)
26073fbcdbf3SJiri Pirko {
26082f5dc00fSVladimir Oltean struct net_device *dev = ofdpa_port->dev;
26093fbcdbf3SJiri Pirko int err;
26103fbcdbf3SJiri Pirko
26114e51bf44SVladimir Oltean switchdev_bridge_port_unoffload(dev, NULL, NULL, NULL);
26122f5dc00fSVladimir Oltean
26133fbcdbf3SJiri Pirko err = ofdpa_port_vlan_del(ofdpa_port, OFDPA_UNTAGGED_VID, 0);
26143fbcdbf3SJiri Pirko if (err)
26153fbcdbf3SJiri Pirko return err;
26163fbcdbf3SJiri Pirko
26173fbcdbf3SJiri Pirko ofdpa_port_internal_vlan_id_put(ofdpa_port,
26183fbcdbf3SJiri Pirko ofdpa_port->bridge_dev->ifindex);
26193fbcdbf3SJiri Pirko ofdpa_port->internal_vlan_id =
26203fbcdbf3SJiri Pirko ofdpa_port_internal_vlan_id_get(ofdpa_port,
26213fbcdbf3SJiri Pirko ofdpa_port->dev->ifindex);
26223fbcdbf3SJiri Pirko
26233fbcdbf3SJiri Pirko ofdpa_port->bridge_dev = NULL;
26243fbcdbf3SJiri Pirko
262500fc0c51SArkadi Sharshevsky err = ofdpa_port_vlan_add(ofdpa_port, OFDPA_UNTAGGED_VID, 0);
26263fbcdbf3SJiri Pirko if (err)
26273fbcdbf3SJiri Pirko return err;
26283fbcdbf3SJiri Pirko
26293fbcdbf3SJiri Pirko if (ofdpa_port->dev->flags & IFF_UP)
26303fbcdbf3SJiri Pirko err = ofdpa_port_fwd_enable(ofdpa_port, 0);
26313fbcdbf3SJiri Pirko
26323fbcdbf3SJiri Pirko return err;
26333fbcdbf3SJiri Pirko }
26343fbcdbf3SJiri Pirko
ofdpa_port_ovs_changed(struct ofdpa_port * ofdpa_port,struct net_device * master)26353fbcdbf3SJiri Pirko static int ofdpa_port_ovs_changed(struct ofdpa_port *ofdpa_port,
26363fbcdbf3SJiri Pirko struct net_device *master)
26373fbcdbf3SJiri Pirko {
26383fbcdbf3SJiri Pirko int err;
26393fbcdbf3SJiri Pirko
26403fbcdbf3SJiri Pirko ofdpa_port->bridge_dev = master;
26413fbcdbf3SJiri Pirko
26423fbcdbf3SJiri Pirko err = ofdpa_port_fwd_disable(ofdpa_port, 0);
26433fbcdbf3SJiri Pirko if (err)
26443fbcdbf3SJiri Pirko return err;
26453fbcdbf3SJiri Pirko err = ofdpa_port_fwd_enable(ofdpa_port, 0);
26463fbcdbf3SJiri Pirko
26473fbcdbf3SJiri Pirko return err;
26483fbcdbf3SJiri Pirko }
26493fbcdbf3SJiri Pirko
ofdpa_port_master_linked(struct rocker_port * rocker_port,struct net_device * master,struct netlink_ext_ack * extack)26503fbcdbf3SJiri Pirko static int ofdpa_port_master_linked(struct rocker_port *rocker_port,
26512f5dc00fSVladimir Oltean struct net_device *master,
26522f5dc00fSVladimir Oltean struct netlink_ext_ack *extack)
26533fbcdbf3SJiri Pirko {
26543fbcdbf3SJiri Pirko struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
26553fbcdbf3SJiri Pirko int err = 0;
26563fbcdbf3SJiri Pirko
26573fbcdbf3SJiri Pirko if (netif_is_bridge_master(master))
26582f5dc00fSVladimir Oltean err = ofdpa_port_bridge_join(ofdpa_port, master, extack);
26593fbcdbf3SJiri Pirko else if (netif_is_ovs_master(master))
26603fbcdbf3SJiri Pirko err = ofdpa_port_ovs_changed(ofdpa_port, master);
26613fbcdbf3SJiri Pirko return err;
26623fbcdbf3SJiri Pirko }
26633fbcdbf3SJiri Pirko
ofdpa_port_master_unlinked(struct rocker_port * rocker_port,struct net_device * master)26643fbcdbf3SJiri Pirko static int ofdpa_port_master_unlinked(struct rocker_port *rocker_port,
26653fbcdbf3SJiri Pirko struct net_device *master)
26663fbcdbf3SJiri Pirko {
26673fbcdbf3SJiri Pirko struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
26683fbcdbf3SJiri Pirko int err = 0;
26693fbcdbf3SJiri Pirko
26703fbcdbf3SJiri Pirko if (ofdpa_port_is_bridged(ofdpa_port))
26713fbcdbf3SJiri Pirko err = ofdpa_port_bridge_leave(ofdpa_port);
26723fbcdbf3SJiri Pirko else if (ofdpa_port_is_ovsed(ofdpa_port))
26733fbcdbf3SJiri Pirko err = ofdpa_port_ovs_changed(ofdpa_port, NULL);
26743fbcdbf3SJiri Pirko return err;
26753fbcdbf3SJiri Pirko }
26763fbcdbf3SJiri Pirko
ofdpa_port_neigh_update(struct rocker_port * rocker_port,struct neighbour * n)26773fbcdbf3SJiri Pirko static int ofdpa_port_neigh_update(struct rocker_port *rocker_port,
26783fbcdbf3SJiri Pirko struct neighbour *n)
26793fbcdbf3SJiri Pirko {
26803fbcdbf3SJiri Pirko struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
26813fbcdbf3SJiri Pirko int flags = (n->nud_state & NUD_VALID ? 0 : OFDPA_OP_FLAG_REMOVE) |
26823fbcdbf3SJiri Pirko OFDPA_OP_FLAG_NOWAIT;
26833fbcdbf3SJiri Pirko __be32 ip_addr = *(__be32 *) n->primary_key;
26843fbcdbf3SJiri Pirko
268500fc0c51SArkadi Sharshevsky return ofdpa_port_ipv4_neigh(ofdpa_port, flags, ip_addr, n->ha);
26863fbcdbf3SJiri Pirko }
26873fbcdbf3SJiri Pirko
ofdpa_port_neigh_destroy(struct rocker_port * rocker_port,struct neighbour * n)26883fbcdbf3SJiri Pirko static int ofdpa_port_neigh_destroy(struct rocker_port *rocker_port,
26893fbcdbf3SJiri Pirko struct neighbour *n)
26903fbcdbf3SJiri Pirko {
26913fbcdbf3SJiri Pirko struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
26923fbcdbf3SJiri Pirko int flags = OFDPA_OP_FLAG_REMOVE | OFDPA_OP_FLAG_NOWAIT;
26933fbcdbf3SJiri Pirko __be32 ip_addr = *(__be32 *) n->primary_key;
26943fbcdbf3SJiri Pirko
269500fc0c51SArkadi Sharshevsky return ofdpa_port_ipv4_neigh(ofdpa_port, flags, ip_addr, n->ha);
26963fbcdbf3SJiri Pirko }
26973fbcdbf3SJiri Pirko
ofdpa_port_ev_mac_vlan_seen(struct rocker_port * rocker_port,const unsigned char * addr,__be16 vlan_id)26983fbcdbf3SJiri Pirko static int ofdpa_port_ev_mac_vlan_seen(struct rocker_port *rocker_port,
26993fbcdbf3SJiri Pirko const unsigned char *addr,
27003fbcdbf3SJiri Pirko __be16 vlan_id)
27013fbcdbf3SJiri Pirko {
27023fbcdbf3SJiri Pirko struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
27033fbcdbf3SJiri Pirko int flags = OFDPA_OP_FLAG_NOWAIT | OFDPA_OP_FLAG_LEARNED;
27043fbcdbf3SJiri Pirko
27053fbcdbf3SJiri Pirko if (ofdpa_port->stp_state != BR_STATE_LEARNING &&
27063fbcdbf3SJiri Pirko ofdpa_port->stp_state != BR_STATE_FORWARDING)
27073fbcdbf3SJiri Pirko return 0;
27083fbcdbf3SJiri Pirko
270900fc0c51SArkadi Sharshevsky return ofdpa_port_fdb(ofdpa_port, addr, vlan_id, flags);
27103fbcdbf3SJiri Pirko }
27113fbcdbf3SJiri Pirko
ofdpa_port_dev_lower_find(struct net_device * dev,struct rocker * rocker)2712936bd486SJiri Pirko static struct ofdpa_port *ofdpa_port_dev_lower_find(struct net_device *dev,
2713936bd486SJiri Pirko struct rocker *rocker)
2714936bd486SJiri Pirko {
2715936bd486SJiri Pirko struct rocker_port *rocker_port;
2716936bd486SJiri Pirko
2717936bd486SJiri Pirko rocker_port = rocker_port_dev_lower_find(dev, rocker);
2718936bd486SJiri Pirko return rocker_port ? rocker_port->wpriv : NULL;
2719936bd486SJiri Pirko }
2720936bd486SJiri Pirko
ofdpa_fib4_add(struct rocker * rocker,const struct fib_entry_notifier_info * fen_info)2721936bd486SJiri Pirko static int ofdpa_fib4_add(struct rocker *rocker,
2722936bd486SJiri Pirko const struct fib_entry_notifier_info *fen_info)
2723936bd486SJiri Pirko {
2724936bd486SJiri Pirko struct ofdpa *ofdpa = rocker->wpriv;
2725936bd486SJiri Pirko struct ofdpa_port *ofdpa_port;
27265481d73fSDavid Ahern struct fib_nh *nh;
2727936bd486SJiri Pirko int err;
2728936bd486SJiri Pirko
2729936bd486SJiri Pirko if (ofdpa->fib_aborted)
2730936bd486SJiri Pirko return 0;
27315481d73fSDavid Ahern nh = fib_info_nh(fen_info->fi, 0);
27325481d73fSDavid Ahern ofdpa_port = ofdpa_port_dev_lower_find(nh->fib_nh_dev, rocker);
2733936bd486SJiri Pirko if (!ofdpa_port)
2734936bd486SJiri Pirko return 0;
273500fc0c51SArkadi Sharshevsky err = ofdpa_port_fib_ipv4(ofdpa_port, htonl(fen_info->dst),
2736936bd486SJiri Pirko fen_info->dst_len, fen_info->fi,
2737936bd486SJiri Pirko fen_info->tb_id, 0);
2738936bd486SJiri Pirko if (err)
2739936bd486SJiri Pirko return err;
27405481d73fSDavid Ahern nh->fib_nh_flags |= RTNH_F_OFFLOAD;
2741936bd486SJiri Pirko return 0;
2742936bd486SJiri Pirko }
2743936bd486SJiri Pirko
ofdpa_fib4_del(struct rocker * rocker,const struct fib_entry_notifier_info * fen_info)2744936bd486SJiri Pirko static int ofdpa_fib4_del(struct rocker *rocker,
2745936bd486SJiri Pirko const struct fib_entry_notifier_info *fen_info)
2746936bd486SJiri Pirko {
2747936bd486SJiri Pirko struct ofdpa *ofdpa = rocker->wpriv;
2748936bd486SJiri Pirko struct ofdpa_port *ofdpa_port;
27495481d73fSDavid Ahern struct fib_nh *nh;
2750936bd486SJiri Pirko
2751936bd486SJiri Pirko if (ofdpa->fib_aborted)
2752936bd486SJiri Pirko return 0;
27535481d73fSDavid Ahern nh = fib_info_nh(fen_info->fi, 0);
27545481d73fSDavid Ahern ofdpa_port = ofdpa_port_dev_lower_find(nh->fib_nh_dev, rocker);
2755936bd486SJiri Pirko if (!ofdpa_port)
2756936bd486SJiri Pirko return 0;
27575481d73fSDavid Ahern nh->fib_nh_flags &= ~RTNH_F_OFFLOAD;
275800fc0c51SArkadi Sharshevsky return ofdpa_port_fib_ipv4(ofdpa_port, htonl(fen_info->dst),
2759936bd486SJiri Pirko fen_info->dst_len, fen_info->fi,
2760936bd486SJiri Pirko fen_info->tb_id, OFDPA_OP_FLAG_REMOVE);
2761936bd486SJiri Pirko }
2762936bd486SJiri Pirko
ofdpa_fib4_abort(struct rocker * rocker)2763936bd486SJiri Pirko static void ofdpa_fib4_abort(struct rocker *rocker)
2764936bd486SJiri Pirko {
2765936bd486SJiri Pirko struct ofdpa *ofdpa = rocker->wpriv;
2766936bd486SJiri Pirko struct ofdpa_port *ofdpa_port;
2767936bd486SJiri Pirko struct ofdpa_flow_tbl_entry *flow_entry;
2768936bd486SJiri Pirko struct hlist_node *tmp;
2769936bd486SJiri Pirko unsigned long flags;
2770936bd486SJiri Pirko int bkt;
2771936bd486SJiri Pirko
2772936bd486SJiri Pirko if (ofdpa->fib_aborted)
2773936bd486SJiri Pirko return;
2774936bd486SJiri Pirko
2775936bd486SJiri Pirko spin_lock_irqsave(&ofdpa->flow_tbl_lock, flags);
2776936bd486SJiri Pirko hash_for_each_safe(ofdpa->flow_tbl, bkt, tmp, flow_entry, entry) {
27775481d73fSDavid Ahern struct fib_nh *nh;
27785481d73fSDavid Ahern
2779936bd486SJiri Pirko if (flow_entry->key.tbl_id !=
2780936bd486SJiri Pirko ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING)
2781936bd486SJiri Pirko continue;
27825481d73fSDavid Ahern nh = fib_info_nh(flow_entry->fi, 0);
27835481d73fSDavid Ahern ofdpa_port = ofdpa_port_dev_lower_find(nh->fib_nh_dev, rocker);
2784936bd486SJiri Pirko if (!ofdpa_port)
2785936bd486SJiri Pirko continue;
27865481d73fSDavid Ahern nh->fib_nh_flags &= ~RTNH_F_OFFLOAD;
278743d01212SDan Carpenter ofdpa_flow_tbl_del(ofdpa_port,
278843d01212SDan Carpenter OFDPA_OP_FLAG_REMOVE | OFDPA_OP_FLAG_NOWAIT,
2789936bd486SJiri Pirko flow_entry);
2790936bd486SJiri Pirko }
2791936bd486SJiri Pirko spin_unlock_irqrestore(&ofdpa->flow_tbl_lock, flags);
2792936bd486SJiri Pirko ofdpa->fib_aborted = true;
2793936bd486SJiri Pirko }
2794936bd486SJiri Pirko
2795e420114eSJiri Pirko struct rocker_world_ops rocker_ofdpa_ops = {
2796e420114eSJiri Pirko .kind = "ofdpa",
2797e420114eSJiri Pirko .priv_size = sizeof(struct ofdpa),
2798e420114eSJiri Pirko .port_priv_size = sizeof(struct ofdpa_port),
2799e420114eSJiri Pirko .mode = ROCKER_PORT_MODE_OF_DPA,
28003fbcdbf3SJiri Pirko .init = ofdpa_init,
28013fbcdbf3SJiri Pirko .fini = ofdpa_fini,
28023fbcdbf3SJiri Pirko .port_pre_init = ofdpa_port_pre_init,
28033fbcdbf3SJiri Pirko .port_init = ofdpa_port_init,
28043fbcdbf3SJiri Pirko .port_fini = ofdpa_port_fini,
28053fbcdbf3SJiri Pirko .port_open = ofdpa_port_open,
28063fbcdbf3SJiri Pirko .port_stop = ofdpa_port_stop,
28073fbcdbf3SJiri Pirko .port_attr_stp_state_set = ofdpa_port_attr_stp_state_set,
28083fbcdbf3SJiri Pirko .port_attr_bridge_flags_set = ofdpa_port_attr_bridge_flags_set,
280996673a30SArkadi Sharshevsky .port_attr_bridge_flags_support_get = ofdpa_port_attr_bridge_flags_support_get,
28103fbcdbf3SJiri Pirko .port_attr_bridge_ageing_time_set = ofdpa_port_attr_bridge_ageing_time_set,
28113fbcdbf3SJiri Pirko .port_obj_vlan_add = ofdpa_port_obj_vlan_add,
28123fbcdbf3SJiri Pirko .port_obj_vlan_del = ofdpa_port_obj_vlan_del,
28133fbcdbf3SJiri Pirko .port_obj_fdb_add = ofdpa_port_obj_fdb_add,
28143fbcdbf3SJiri Pirko .port_obj_fdb_del = ofdpa_port_obj_fdb_del,
28153fbcdbf3SJiri Pirko .port_master_linked = ofdpa_port_master_linked,
28163fbcdbf3SJiri Pirko .port_master_unlinked = ofdpa_port_master_unlinked,
28173fbcdbf3SJiri Pirko .port_neigh_update = ofdpa_port_neigh_update,
28183fbcdbf3SJiri Pirko .port_neigh_destroy = ofdpa_port_neigh_destroy,
28193fbcdbf3SJiri Pirko .port_ev_mac_vlan_seen = ofdpa_port_ev_mac_vlan_seen,
2820936bd486SJiri Pirko .fib4_add = ofdpa_fib4_add,
2821936bd486SJiri Pirko .fib4_del = ofdpa_fib4_del,
2822936bd486SJiri Pirko .fib4_abort = ofdpa_fib4_abort,
2823e420114eSJiri Pirko };
2824