1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * drivers/net/ethernet/rocker/rocker_ofdpa.c - Rocker switch OF-DPA-like
4*4882a593Smuzhiyun * implementation
5*4882a593Smuzhiyun * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com>
6*4882a593Smuzhiyun * Copyright (c) 2014-2016 Jiri Pirko <jiri@mellanox.com>
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #include <linux/kernel.h>
10*4882a593Smuzhiyun #include <linux/types.h>
11*4882a593Smuzhiyun #include <linux/spinlock.h>
12*4882a593Smuzhiyun #include <linux/hashtable.h>
13*4882a593Smuzhiyun #include <linux/crc32.h>
14*4882a593Smuzhiyun #include <linux/netdevice.h>
15*4882a593Smuzhiyun #include <linux/inetdevice.h>
16*4882a593Smuzhiyun #include <linux/if_vlan.h>
17*4882a593Smuzhiyun #include <linux/if_bridge.h>
18*4882a593Smuzhiyun #include <net/neighbour.h>
19*4882a593Smuzhiyun #include <net/switchdev.h>
20*4882a593Smuzhiyun #include <net/ip_fib.h>
21*4882a593Smuzhiyun #include <net/nexthop.h>
22*4882a593Smuzhiyun #include <net/arp.h>
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun #include "rocker.h"
25*4882a593Smuzhiyun #include "rocker_tlv.h"
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun struct ofdpa_flow_tbl_key {
28*4882a593Smuzhiyun u32 priority;
29*4882a593Smuzhiyun enum rocker_of_dpa_table_id tbl_id;
30*4882a593Smuzhiyun union {
31*4882a593Smuzhiyun struct {
32*4882a593Smuzhiyun u32 in_pport;
33*4882a593Smuzhiyun u32 in_pport_mask;
34*4882a593Smuzhiyun enum rocker_of_dpa_table_id goto_tbl;
35*4882a593Smuzhiyun } ig_port;
36*4882a593Smuzhiyun struct {
37*4882a593Smuzhiyun u32 in_pport;
38*4882a593Smuzhiyun __be16 vlan_id;
39*4882a593Smuzhiyun __be16 vlan_id_mask;
40*4882a593Smuzhiyun enum rocker_of_dpa_table_id goto_tbl;
41*4882a593Smuzhiyun bool untagged;
42*4882a593Smuzhiyun __be16 new_vlan_id;
43*4882a593Smuzhiyun } vlan;
44*4882a593Smuzhiyun struct {
45*4882a593Smuzhiyun u32 in_pport;
46*4882a593Smuzhiyun u32 in_pport_mask;
47*4882a593Smuzhiyun __be16 eth_type;
48*4882a593Smuzhiyun u8 eth_dst[ETH_ALEN];
49*4882a593Smuzhiyun u8 eth_dst_mask[ETH_ALEN];
50*4882a593Smuzhiyun __be16 vlan_id;
51*4882a593Smuzhiyun __be16 vlan_id_mask;
52*4882a593Smuzhiyun enum rocker_of_dpa_table_id goto_tbl;
53*4882a593Smuzhiyun bool copy_to_cpu;
54*4882a593Smuzhiyun } term_mac;
55*4882a593Smuzhiyun struct {
56*4882a593Smuzhiyun __be16 eth_type;
57*4882a593Smuzhiyun __be32 dst4;
58*4882a593Smuzhiyun __be32 dst4_mask;
59*4882a593Smuzhiyun enum rocker_of_dpa_table_id goto_tbl;
60*4882a593Smuzhiyun u32 group_id;
61*4882a593Smuzhiyun } ucast_routing;
62*4882a593Smuzhiyun struct {
63*4882a593Smuzhiyun u8 eth_dst[ETH_ALEN];
64*4882a593Smuzhiyun u8 eth_dst_mask[ETH_ALEN];
65*4882a593Smuzhiyun int has_eth_dst;
66*4882a593Smuzhiyun int has_eth_dst_mask;
67*4882a593Smuzhiyun __be16 vlan_id;
68*4882a593Smuzhiyun u32 tunnel_id;
69*4882a593Smuzhiyun enum rocker_of_dpa_table_id goto_tbl;
70*4882a593Smuzhiyun u32 group_id;
71*4882a593Smuzhiyun bool copy_to_cpu;
72*4882a593Smuzhiyun } bridge;
73*4882a593Smuzhiyun struct {
74*4882a593Smuzhiyun u32 in_pport;
75*4882a593Smuzhiyun u32 in_pport_mask;
76*4882a593Smuzhiyun u8 eth_src[ETH_ALEN];
77*4882a593Smuzhiyun u8 eth_src_mask[ETH_ALEN];
78*4882a593Smuzhiyun u8 eth_dst[ETH_ALEN];
79*4882a593Smuzhiyun u8 eth_dst_mask[ETH_ALEN];
80*4882a593Smuzhiyun __be16 eth_type;
81*4882a593Smuzhiyun __be16 vlan_id;
82*4882a593Smuzhiyun __be16 vlan_id_mask;
83*4882a593Smuzhiyun u8 ip_proto;
84*4882a593Smuzhiyun u8 ip_proto_mask;
85*4882a593Smuzhiyun u8 ip_tos;
86*4882a593Smuzhiyun u8 ip_tos_mask;
87*4882a593Smuzhiyun u32 group_id;
88*4882a593Smuzhiyun } acl;
89*4882a593Smuzhiyun };
90*4882a593Smuzhiyun };
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun struct ofdpa_flow_tbl_entry {
93*4882a593Smuzhiyun struct hlist_node entry;
94*4882a593Smuzhiyun u32 cmd;
95*4882a593Smuzhiyun u64 cookie;
96*4882a593Smuzhiyun struct ofdpa_flow_tbl_key key;
97*4882a593Smuzhiyun size_t key_len;
98*4882a593Smuzhiyun u32 key_crc32; /* key */
99*4882a593Smuzhiyun struct fib_info *fi;
100*4882a593Smuzhiyun };
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun struct ofdpa_group_tbl_entry {
103*4882a593Smuzhiyun struct hlist_node entry;
104*4882a593Smuzhiyun u32 cmd;
105*4882a593Smuzhiyun u32 group_id; /* key */
106*4882a593Smuzhiyun u16 group_count;
107*4882a593Smuzhiyun u32 *group_ids;
108*4882a593Smuzhiyun union {
109*4882a593Smuzhiyun struct {
110*4882a593Smuzhiyun u8 pop_vlan;
111*4882a593Smuzhiyun } l2_interface;
112*4882a593Smuzhiyun struct {
113*4882a593Smuzhiyun u8 eth_src[ETH_ALEN];
114*4882a593Smuzhiyun u8 eth_dst[ETH_ALEN];
115*4882a593Smuzhiyun __be16 vlan_id;
116*4882a593Smuzhiyun u32 group_id;
117*4882a593Smuzhiyun } l2_rewrite;
118*4882a593Smuzhiyun struct {
119*4882a593Smuzhiyun u8 eth_src[ETH_ALEN];
120*4882a593Smuzhiyun u8 eth_dst[ETH_ALEN];
121*4882a593Smuzhiyun __be16 vlan_id;
122*4882a593Smuzhiyun bool ttl_check;
123*4882a593Smuzhiyun u32 group_id;
124*4882a593Smuzhiyun } l3_unicast;
125*4882a593Smuzhiyun };
126*4882a593Smuzhiyun };
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun struct ofdpa_fdb_tbl_entry {
129*4882a593Smuzhiyun struct hlist_node entry;
130*4882a593Smuzhiyun u32 key_crc32; /* key */
131*4882a593Smuzhiyun bool learned;
132*4882a593Smuzhiyun unsigned long touched;
133*4882a593Smuzhiyun struct ofdpa_fdb_tbl_key {
134*4882a593Smuzhiyun struct ofdpa_port *ofdpa_port;
135*4882a593Smuzhiyun u8 addr[ETH_ALEN];
136*4882a593Smuzhiyun __be16 vlan_id;
137*4882a593Smuzhiyun } key;
138*4882a593Smuzhiyun };
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun struct ofdpa_internal_vlan_tbl_entry {
141*4882a593Smuzhiyun struct hlist_node entry;
142*4882a593Smuzhiyun int ifindex; /* key */
143*4882a593Smuzhiyun u32 ref_count;
144*4882a593Smuzhiyun __be16 vlan_id;
145*4882a593Smuzhiyun };
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun struct ofdpa_neigh_tbl_entry {
148*4882a593Smuzhiyun struct hlist_node entry;
149*4882a593Smuzhiyun __be32 ip_addr; /* key */
150*4882a593Smuzhiyun struct net_device *dev;
151*4882a593Smuzhiyun u32 ref_count;
152*4882a593Smuzhiyun u32 index;
153*4882a593Smuzhiyun u8 eth_dst[ETH_ALEN];
154*4882a593Smuzhiyun bool ttl_check;
155*4882a593Smuzhiyun };
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun enum {
158*4882a593Smuzhiyun OFDPA_CTRL_LINK_LOCAL_MCAST,
159*4882a593Smuzhiyun OFDPA_CTRL_LOCAL_ARP,
160*4882a593Smuzhiyun OFDPA_CTRL_IPV4_MCAST,
161*4882a593Smuzhiyun OFDPA_CTRL_IPV6_MCAST,
162*4882a593Smuzhiyun OFDPA_CTRL_DFLT_BRIDGING,
163*4882a593Smuzhiyun OFDPA_CTRL_DFLT_OVS,
164*4882a593Smuzhiyun OFDPA_CTRL_MAX,
165*4882a593Smuzhiyun };
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun #define OFDPA_INTERNAL_VLAN_ID_BASE 0x0f00
168*4882a593Smuzhiyun #define OFDPA_N_INTERNAL_VLANS 255
169*4882a593Smuzhiyun #define OFDPA_VLAN_BITMAP_LEN BITS_TO_LONGS(VLAN_N_VID)
170*4882a593Smuzhiyun #define OFDPA_INTERNAL_VLAN_BITMAP_LEN BITS_TO_LONGS(OFDPA_N_INTERNAL_VLANS)
171*4882a593Smuzhiyun #define OFDPA_UNTAGGED_VID 0
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun struct ofdpa {
174*4882a593Smuzhiyun struct rocker *rocker;
175*4882a593Smuzhiyun DECLARE_HASHTABLE(flow_tbl, 16);
176*4882a593Smuzhiyun spinlock_t flow_tbl_lock; /* for flow tbl accesses */
177*4882a593Smuzhiyun u64 flow_tbl_next_cookie;
178*4882a593Smuzhiyun DECLARE_HASHTABLE(group_tbl, 16);
179*4882a593Smuzhiyun spinlock_t group_tbl_lock; /* for group tbl accesses */
180*4882a593Smuzhiyun struct timer_list fdb_cleanup_timer;
181*4882a593Smuzhiyun DECLARE_HASHTABLE(fdb_tbl, 16);
182*4882a593Smuzhiyun spinlock_t fdb_tbl_lock; /* for fdb tbl accesses */
183*4882a593Smuzhiyun unsigned long internal_vlan_bitmap[OFDPA_INTERNAL_VLAN_BITMAP_LEN];
184*4882a593Smuzhiyun DECLARE_HASHTABLE(internal_vlan_tbl, 8);
185*4882a593Smuzhiyun spinlock_t internal_vlan_tbl_lock; /* for vlan tbl accesses */
186*4882a593Smuzhiyun DECLARE_HASHTABLE(neigh_tbl, 16);
187*4882a593Smuzhiyun spinlock_t neigh_tbl_lock; /* for neigh tbl accesses */
188*4882a593Smuzhiyun u32 neigh_tbl_next_index;
189*4882a593Smuzhiyun unsigned long ageing_time;
190*4882a593Smuzhiyun bool fib_aborted;
191*4882a593Smuzhiyun };
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun struct ofdpa_port {
194*4882a593Smuzhiyun struct ofdpa *ofdpa;
195*4882a593Smuzhiyun struct rocker_port *rocker_port;
196*4882a593Smuzhiyun struct net_device *dev;
197*4882a593Smuzhiyun u32 pport;
198*4882a593Smuzhiyun struct net_device *bridge_dev;
199*4882a593Smuzhiyun __be16 internal_vlan_id;
200*4882a593Smuzhiyun int stp_state;
201*4882a593Smuzhiyun u32 brport_flags;
202*4882a593Smuzhiyun unsigned long ageing_time;
203*4882a593Smuzhiyun bool ctrls[OFDPA_CTRL_MAX];
204*4882a593Smuzhiyun unsigned long vlan_bitmap[OFDPA_VLAN_BITMAP_LEN];
205*4882a593Smuzhiyun };
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun static const u8 zero_mac[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
208*4882a593Smuzhiyun static const u8 ff_mac[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
209*4882a593Smuzhiyun static const u8 ll_mac[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
210*4882a593Smuzhiyun static const u8 ll_mask[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0 };
211*4882a593Smuzhiyun static const u8 mcast_mac[ETH_ALEN] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 };
212*4882a593Smuzhiyun static const u8 ipv4_mcast[ETH_ALEN] = { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 };
213*4882a593Smuzhiyun static const u8 ipv4_mask[ETH_ALEN] = { 0xff, 0xff, 0xff, 0x80, 0x00, 0x00 };
214*4882a593Smuzhiyun static const u8 ipv6_mcast[ETH_ALEN] = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x00 };
215*4882a593Smuzhiyun static const u8 ipv6_mask[ETH_ALEN] = { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 };
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun /* Rocker priority levels for flow table entries. Higher
218*4882a593Smuzhiyun * priority match takes precedence over lower priority match.
219*4882a593Smuzhiyun */
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun enum {
222*4882a593Smuzhiyun OFDPA_PRIORITY_UNKNOWN = 0,
223*4882a593Smuzhiyun OFDPA_PRIORITY_IG_PORT = 1,
224*4882a593Smuzhiyun OFDPA_PRIORITY_VLAN = 1,
225*4882a593Smuzhiyun OFDPA_PRIORITY_TERM_MAC_UCAST = 0,
226*4882a593Smuzhiyun OFDPA_PRIORITY_TERM_MAC_MCAST = 1,
227*4882a593Smuzhiyun OFDPA_PRIORITY_BRIDGING_VLAN_DFLT_EXACT = 1,
228*4882a593Smuzhiyun OFDPA_PRIORITY_BRIDGING_VLAN_DFLT_WILD = 2,
229*4882a593Smuzhiyun OFDPA_PRIORITY_BRIDGING_VLAN = 3,
230*4882a593Smuzhiyun OFDPA_PRIORITY_BRIDGING_TENANT_DFLT_EXACT = 1,
231*4882a593Smuzhiyun OFDPA_PRIORITY_BRIDGING_TENANT_DFLT_WILD = 2,
232*4882a593Smuzhiyun OFDPA_PRIORITY_BRIDGING_TENANT = 3,
233*4882a593Smuzhiyun OFDPA_PRIORITY_ACL_CTRL = 3,
234*4882a593Smuzhiyun OFDPA_PRIORITY_ACL_NORMAL = 2,
235*4882a593Smuzhiyun OFDPA_PRIORITY_ACL_DFLT = 1,
236*4882a593Smuzhiyun };
237*4882a593Smuzhiyun
ofdpa_vlan_id_is_internal(__be16 vlan_id)238*4882a593Smuzhiyun static bool ofdpa_vlan_id_is_internal(__be16 vlan_id)
239*4882a593Smuzhiyun {
240*4882a593Smuzhiyun u16 start = OFDPA_INTERNAL_VLAN_ID_BASE;
241*4882a593Smuzhiyun u16 end = 0xffe;
242*4882a593Smuzhiyun u16 _vlan_id = ntohs(vlan_id);
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun return (_vlan_id >= start && _vlan_id <= end);
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun
ofdpa_port_vid_to_vlan(const struct ofdpa_port * ofdpa_port,u16 vid,bool * pop_vlan)247*4882a593Smuzhiyun static __be16 ofdpa_port_vid_to_vlan(const struct ofdpa_port *ofdpa_port,
248*4882a593Smuzhiyun u16 vid, bool *pop_vlan)
249*4882a593Smuzhiyun {
250*4882a593Smuzhiyun __be16 vlan_id;
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun if (pop_vlan)
253*4882a593Smuzhiyun *pop_vlan = false;
254*4882a593Smuzhiyun vlan_id = htons(vid);
255*4882a593Smuzhiyun if (!vlan_id) {
256*4882a593Smuzhiyun vlan_id = ofdpa_port->internal_vlan_id;
257*4882a593Smuzhiyun if (pop_vlan)
258*4882a593Smuzhiyun *pop_vlan = true;
259*4882a593Smuzhiyun }
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun return vlan_id;
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun
ofdpa_port_vlan_to_vid(const struct ofdpa_port * ofdpa_port,__be16 vlan_id)264*4882a593Smuzhiyun static u16 ofdpa_port_vlan_to_vid(const struct ofdpa_port *ofdpa_port,
265*4882a593Smuzhiyun __be16 vlan_id)
266*4882a593Smuzhiyun {
267*4882a593Smuzhiyun if (ofdpa_vlan_id_is_internal(vlan_id))
268*4882a593Smuzhiyun return 0;
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun return ntohs(vlan_id);
271*4882a593Smuzhiyun }
272*4882a593Smuzhiyun
ofdpa_port_is_slave(const struct ofdpa_port * ofdpa_port,const char * kind)273*4882a593Smuzhiyun static bool ofdpa_port_is_slave(const struct ofdpa_port *ofdpa_port,
274*4882a593Smuzhiyun const char *kind)
275*4882a593Smuzhiyun {
276*4882a593Smuzhiyun return ofdpa_port->bridge_dev &&
277*4882a593Smuzhiyun !strcmp(ofdpa_port->bridge_dev->rtnl_link_ops->kind, kind);
278*4882a593Smuzhiyun }
279*4882a593Smuzhiyun
ofdpa_port_is_bridged(const struct ofdpa_port * ofdpa_port)280*4882a593Smuzhiyun static bool ofdpa_port_is_bridged(const struct ofdpa_port *ofdpa_port)
281*4882a593Smuzhiyun {
282*4882a593Smuzhiyun return ofdpa_port_is_slave(ofdpa_port, "bridge");
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun
ofdpa_port_is_ovsed(const struct ofdpa_port * ofdpa_port)285*4882a593Smuzhiyun static bool ofdpa_port_is_ovsed(const struct ofdpa_port *ofdpa_port)
286*4882a593Smuzhiyun {
287*4882a593Smuzhiyun return ofdpa_port_is_slave(ofdpa_port, "openvswitch");
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun #define OFDPA_OP_FLAG_REMOVE BIT(0)
291*4882a593Smuzhiyun #define OFDPA_OP_FLAG_NOWAIT BIT(1)
292*4882a593Smuzhiyun #define OFDPA_OP_FLAG_LEARNED BIT(2)
293*4882a593Smuzhiyun #define OFDPA_OP_FLAG_REFRESH BIT(3)
294*4882a593Smuzhiyun
ofdpa_flags_nowait(int flags)295*4882a593Smuzhiyun static bool ofdpa_flags_nowait(int flags)
296*4882a593Smuzhiyun {
297*4882a593Smuzhiyun return flags & OFDPA_OP_FLAG_NOWAIT;
298*4882a593Smuzhiyun }
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun /*************************************************************
301*4882a593Smuzhiyun * Flow, group, FDB, internal VLAN and neigh command prepares
302*4882a593Smuzhiyun *************************************************************/
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun static int
ofdpa_cmd_flow_tbl_add_ig_port(struct rocker_desc_info * desc_info,const struct ofdpa_flow_tbl_entry * entry)305*4882a593Smuzhiyun ofdpa_cmd_flow_tbl_add_ig_port(struct rocker_desc_info *desc_info,
306*4882a593Smuzhiyun const struct ofdpa_flow_tbl_entry *entry)
307*4882a593Smuzhiyun {
308*4882a593Smuzhiyun if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_IN_PPORT,
309*4882a593Smuzhiyun entry->key.ig_port.in_pport))
310*4882a593Smuzhiyun return -EMSGSIZE;
311*4882a593Smuzhiyun if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_IN_PPORT_MASK,
312*4882a593Smuzhiyun entry->key.ig_port.in_pport_mask))
313*4882a593Smuzhiyun return -EMSGSIZE;
314*4882a593Smuzhiyun if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_GOTO_TABLE_ID,
315*4882a593Smuzhiyun entry->key.ig_port.goto_tbl))
316*4882a593Smuzhiyun return -EMSGSIZE;
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun return 0;
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun static int
ofdpa_cmd_flow_tbl_add_vlan(struct rocker_desc_info * desc_info,const struct ofdpa_flow_tbl_entry * entry)322*4882a593Smuzhiyun ofdpa_cmd_flow_tbl_add_vlan(struct rocker_desc_info *desc_info,
323*4882a593Smuzhiyun const struct ofdpa_flow_tbl_entry *entry)
324*4882a593Smuzhiyun {
325*4882a593Smuzhiyun if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_IN_PPORT,
326*4882a593Smuzhiyun entry->key.vlan.in_pport))
327*4882a593Smuzhiyun return -EMSGSIZE;
328*4882a593Smuzhiyun if (rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID,
329*4882a593Smuzhiyun entry->key.vlan.vlan_id))
330*4882a593Smuzhiyun return -EMSGSIZE;
331*4882a593Smuzhiyun if (rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID_MASK,
332*4882a593Smuzhiyun entry->key.vlan.vlan_id_mask))
333*4882a593Smuzhiyun return -EMSGSIZE;
334*4882a593Smuzhiyun if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_GOTO_TABLE_ID,
335*4882a593Smuzhiyun entry->key.vlan.goto_tbl))
336*4882a593Smuzhiyun return -EMSGSIZE;
337*4882a593Smuzhiyun if (entry->key.vlan.untagged &&
338*4882a593Smuzhiyun rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_NEW_VLAN_ID,
339*4882a593Smuzhiyun entry->key.vlan.new_vlan_id))
340*4882a593Smuzhiyun return -EMSGSIZE;
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun return 0;
343*4882a593Smuzhiyun }
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun static int
ofdpa_cmd_flow_tbl_add_term_mac(struct rocker_desc_info * desc_info,const struct ofdpa_flow_tbl_entry * entry)346*4882a593Smuzhiyun ofdpa_cmd_flow_tbl_add_term_mac(struct rocker_desc_info *desc_info,
347*4882a593Smuzhiyun const struct ofdpa_flow_tbl_entry *entry)
348*4882a593Smuzhiyun {
349*4882a593Smuzhiyun if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_IN_PPORT,
350*4882a593Smuzhiyun entry->key.term_mac.in_pport))
351*4882a593Smuzhiyun return -EMSGSIZE;
352*4882a593Smuzhiyun if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_IN_PPORT_MASK,
353*4882a593Smuzhiyun entry->key.term_mac.in_pport_mask))
354*4882a593Smuzhiyun return -EMSGSIZE;
355*4882a593Smuzhiyun if (rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_ETHERTYPE,
356*4882a593Smuzhiyun entry->key.term_mac.eth_type))
357*4882a593Smuzhiyun return -EMSGSIZE;
358*4882a593Smuzhiyun if (rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC,
359*4882a593Smuzhiyun ETH_ALEN, entry->key.term_mac.eth_dst))
360*4882a593Smuzhiyun return -EMSGSIZE;
361*4882a593Smuzhiyun if (rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC_MASK,
362*4882a593Smuzhiyun ETH_ALEN, entry->key.term_mac.eth_dst_mask))
363*4882a593Smuzhiyun return -EMSGSIZE;
364*4882a593Smuzhiyun if (rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID,
365*4882a593Smuzhiyun entry->key.term_mac.vlan_id))
366*4882a593Smuzhiyun return -EMSGSIZE;
367*4882a593Smuzhiyun if (rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID_MASK,
368*4882a593Smuzhiyun entry->key.term_mac.vlan_id_mask))
369*4882a593Smuzhiyun return -EMSGSIZE;
370*4882a593Smuzhiyun if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_GOTO_TABLE_ID,
371*4882a593Smuzhiyun entry->key.term_mac.goto_tbl))
372*4882a593Smuzhiyun return -EMSGSIZE;
373*4882a593Smuzhiyun if (entry->key.term_mac.copy_to_cpu &&
374*4882a593Smuzhiyun rocker_tlv_put_u8(desc_info, ROCKER_TLV_OF_DPA_COPY_CPU_ACTION,
375*4882a593Smuzhiyun entry->key.term_mac.copy_to_cpu))
376*4882a593Smuzhiyun return -EMSGSIZE;
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun return 0;
379*4882a593Smuzhiyun }
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun static int
ofdpa_cmd_flow_tbl_add_ucast_routing(struct rocker_desc_info * desc_info,const struct ofdpa_flow_tbl_entry * entry)382*4882a593Smuzhiyun ofdpa_cmd_flow_tbl_add_ucast_routing(struct rocker_desc_info *desc_info,
383*4882a593Smuzhiyun const struct ofdpa_flow_tbl_entry *entry)
384*4882a593Smuzhiyun {
385*4882a593Smuzhiyun if (rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_ETHERTYPE,
386*4882a593Smuzhiyun entry->key.ucast_routing.eth_type))
387*4882a593Smuzhiyun return -EMSGSIZE;
388*4882a593Smuzhiyun if (rocker_tlv_put_be32(desc_info, ROCKER_TLV_OF_DPA_DST_IP,
389*4882a593Smuzhiyun entry->key.ucast_routing.dst4))
390*4882a593Smuzhiyun return -EMSGSIZE;
391*4882a593Smuzhiyun if (rocker_tlv_put_be32(desc_info, ROCKER_TLV_OF_DPA_DST_IP_MASK,
392*4882a593Smuzhiyun entry->key.ucast_routing.dst4_mask))
393*4882a593Smuzhiyun return -EMSGSIZE;
394*4882a593Smuzhiyun if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_GOTO_TABLE_ID,
395*4882a593Smuzhiyun entry->key.ucast_routing.goto_tbl))
396*4882a593Smuzhiyun return -EMSGSIZE;
397*4882a593Smuzhiyun if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_GROUP_ID,
398*4882a593Smuzhiyun entry->key.ucast_routing.group_id))
399*4882a593Smuzhiyun return -EMSGSIZE;
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun return 0;
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun static int
ofdpa_cmd_flow_tbl_add_bridge(struct rocker_desc_info * desc_info,const struct ofdpa_flow_tbl_entry * entry)405*4882a593Smuzhiyun ofdpa_cmd_flow_tbl_add_bridge(struct rocker_desc_info *desc_info,
406*4882a593Smuzhiyun const struct ofdpa_flow_tbl_entry *entry)
407*4882a593Smuzhiyun {
408*4882a593Smuzhiyun if (entry->key.bridge.has_eth_dst &&
409*4882a593Smuzhiyun rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC,
410*4882a593Smuzhiyun ETH_ALEN, entry->key.bridge.eth_dst))
411*4882a593Smuzhiyun return -EMSGSIZE;
412*4882a593Smuzhiyun if (entry->key.bridge.has_eth_dst_mask &&
413*4882a593Smuzhiyun rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC_MASK,
414*4882a593Smuzhiyun ETH_ALEN, entry->key.bridge.eth_dst_mask))
415*4882a593Smuzhiyun return -EMSGSIZE;
416*4882a593Smuzhiyun if (entry->key.bridge.vlan_id &&
417*4882a593Smuzhiyun rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID,
418*4882a593Smuzhiyun entry->key.bridge.vlan_id))
419*4882a593Smuzhiyun return -EMSGSIZE;
420*4882a593Smuzhiyun if (entry->key.bridge.tunnel_id &&
421*4882a593Smuzhiyun rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_TUNNEL_ID,
422*4882a593Smuzhiyun entry->key.bridge.tunnel_id))
423*4882a593Smuzhiyun return -EMSGSIZE;
424*4882a593Smuzhiyun if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_GOTO_TABLE_ID,
425*4882a593Smuzhiyun entry->key.bridge.goto_tbl))
426*4882a593Smuzhiyun return -EMSGSIZE;
427*4882a593Smuzhiyun if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_GROUP_ID,
428*4882a593Smuzhiyun entry->key.bridge.group_id))
429*4882a593Smuzhiyun return -EMSGSIZE;
430*4882a593Smuzhiyun if (entry->key.bridge.copy_to_cpu &&
431*4882a593Smuzhiyun rocker_tlv_put_u8(desc_info, ROCKER_TLV_OF_DPA_COPY_CPU_ACTION,
432*4882a593Smuzhiyun entry->key.bridge.copy_to_cpu))
433*4882a593Smuzhiyun return -EMSGSIZE;
434*4882a593Smuzhiyun
435*4882a593Smuzhiyun return 0;
436*4882a593Smuzhiyun }
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun static int
ofdpa_cmd_flow_tbl_add_acl(struct rocker_desc_info * desc_info,const struct ofdpa_flow_tbl_entry * entry)439*4882a593Smuzhiyun ofdpa_cmd_flow_tbl_add_acl(struct rocker_desc_info *desc_info,
440*4882a593Smuzhiyun const struct ofdpa_flow_tbl_entry *entry)
441*4882a593Smuzhiyun {
442*4882a593Smuzhiyun if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_IN_PPORT,
443*4882a593Smuzhiyun entry->key.acl.in_pport))
444*4882a593Smuzhiyun return -EMSGSIZE;
445*4882a593Smuzhiyun if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_IN_PPORT_MASK,
446*4882a593Smuzhiyun entry->key.acl.in_pport_mask))
447*4882a593Smuzhiyun return -EMSGSIZE;
448*4882a593Smuzhiyun if (rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_SRC_MAC,
449*4882a593Smuzhiyun ETH_ALEN, entry->key.acl.eth_src))
450*4882a593Smuzhiyun return -EMSGSIZE;
451*4882a593Smuzhiyun if (rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_SRC_MAC_MASK,
452*4882a593Smuzhiyun ETH_ALEN, entry->key.acl.eth_src_mask))
453*4882a593Smuzhiyun return -EMSGSIZE;
454*4882a593Smuzhiyun if (rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC,
455*4882a593Smuzhiyun ETH_ALEN, entry->key.acl.eth_dst))
456*4882a593Smuzhiyun return -EMSGSIZE;
457*4882a593Smuzhiyun if (rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC_MASK,
458*4882a593Smuzhiyun ETH_ALEN, entry->key.acl.eth_dst_mask))
459*4882a593Smuzhiyun return -EMSGSIZE;
460*4882a593Smuzhiyun if (rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_ETHERTYPE,
461*4882a593Smuzhiyun entry->key.acl.eth_type))
462*4882a593Smuzhiyun return -EMSGSIZE;
463*4882a593Smuzhiyun if (rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID,
464*4882a593Smuzhiyun entry->key.acl.vlan_id))
465*4882a593Smuzhiyun return -EMSGSIZE;
466*4882a593Smuzhiyun if (rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID_MASK,
467*4882a593Smuzhiyun entry->key.acl.vlan_id_mask))
468*4882a593Smuzhiyun return -EMSGSIZE;
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun switch (ntohs(entry->key.acl.eth_type)) {
471*4882a593Smuzhiyun case ETH_P_IP:
472*4882a593Smuzhiyun case ETH_P_IPV6:
473*4882a593Smuzhiyun if (rocker_tlv_put_u8(desc_info, ROCKER_TLV_OF_DPA_IP_PROTO,
474*4882a593Smuzhiyun entry->key.acl.ip_proto))
475*4882a593Smuzhiyun return -EMSGSIZE;
476*4882a593Smuzhiyun if (rocker_tlv_put_u8(desc_info,
477*4882a593Smuzhiyun ROCKER_TLV_OF_DPA_IP_PROTO_MASK,
478*4882a593Smuzhiyun entry->key.acl.ip_proto_mask))
479*4882a593Smuzhiyun return -EMSGSIZE;
480*4882a593Smuzhiyun if (rocker_tlv_put_u8(desc_info, ROCKER_TLV_OF_DPA_IP_DSCP,
481*4882a593Smuzhiyun entry->key.acl.ip_tos & 0x3f))
482*4882a593Smuzhiyun return -EMSGSIZE;
483*4882a593Smuzhiyun if (rocker_tlv_put_u8(desc_info,
484*4882a593Smuzhiyun ROCKER_TLV_OF_DPA_IP_DSCP_MASK,
485*4882a593Smuzhiyun entry->key.acl.ip_tos_mask & 0x3f))
486*4882a593Smuzhiyun return -EMSGSIZE;
487*4882a593Smuzhiyun if (rocker_tlv_put_u8(desc_info, ROCKER_TLV_OF_DPA_IP_ECN,
488*4882a593Smuzhiyun (entry->key.acl.ip_tos & 0xc0) >> 6))
489*4882a593Smuzhiyun return -EMSGSIZE;
490*4882a593Smuzhiyun if (rocker_tlv_put_u8(desc_info,
491*4882a593Smuzhiyun ROCKER_TLV_OF_DPA_IP_ECN_MASK,
492*4882a593Smuzhiyun (entry->key.acl.ip_tos_mask & 0xc0) >> 6))
493*4882a593Smuzhiyun return -EMSGSIZE;
494*4882a593Smuzhiyun break;
495*4882a593Smuzhiyun }
496*4882a593Smuzhiyun
497*4882a593Smuzhiyun if (entry->key.acl.group_id != ROCKER_GROUP_NONE &&
498*4882a593Smuzhiyun rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_GROUP_ID,
499*4882a593Smuzhiyun entry->key.acl.group_id))
500*4882a593Smuzhiyun return -EMSGSIZE;
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun return 0;
503*4882a593Smuzhiyun }
504*4882a593Smuzhiyun
ofdpa_cmd_flow_tbl_add(const struct rocker_port * rocker_port,struct rocker_desc_info * desc_info,void * priv)505*4882a593Smuzhiyun static int ofdpa_cmd_flow_tbl_add(const struct rocker_port *rocker_port,
506*4882a593Smuzhiyun struct rocker_desc_info *desc_info,
507*4882a593Smuzhiyun void *priv)
508*4882a593Smuzhiyun {
509*4882a593Smuzhiyun const struct ofdpa_flow_tbl_entry *entry = priv;
510*4882a593Smuzhiyun struct rocker_tlv *cmd_info;
511*4882a593Smuzhiyun int err = 0;
512*4882a593Smuzhiyun
513*4882a593Smuzhiyun if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE, entry->cmd))
514*4882a593Smuzhiyun return -EMSGSIZE;
515*4882a593Smuzhiyun cmd_info = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);
516*4882a593Smuzhiyun if (!cmd_info)
517*4882a593Smuzhiyun return -EMSGSIZE;
518*4882a593Smuzhiyun if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_TABLE_ID,
519*4882a593Smuzhiyun entry->key.tbl_id))
520*4882a593Smuzhiyun return -EMSGSIZE;
521*4882a593Smuzhiyun if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_PRIORITY,
522*4882a593Smuzhiyun entry->key.priority))
523*4882a593Smuzhiyun return -EMSGSIZE;
524*4882a593Smuzhiyun if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_HARDTIME, 0))
525*4882a593Smuzhiyun return -EMSGSIZE;
526*4882a593Smuzhiyun if (rocker_tlv_put_u64(desc_info, ROCKER_TLV_OF_DPA_COOKIE,
527*4882a593Smuzhiyun entry->cookie))
528*4882a593Smuzhiyun return -EMSGSIZE;
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun switch (entry->key.tbl_id) {
531*4882a593Smuzhiyun case ROCKER_OF_DPA_TABLE_ID_INGRESS_PORT:
532*4882a593Smuzhiyun err = ofdpa_cmd_flow_tbl_add_ig_port(desc_info, entry);
533*4882a593Smuzhiyun break;
534*4882a593Smuzhiyun case ROCKER_OF_DPA_TABLE_ID_VLAN:
535*4882a593Smuzhiyun err = ofdpa_cmd_flow_tbl_add_vlan(desc_info, entry);
536*4882a593Smuzhiyun break;
537*4882a593Smuzhiyun case ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC:
538*4882a593Smuzhiyun err = ofdpa_cmd_flow_tbl_add_term_mac(desc_info, entry);
539*4882a593Smuzhiyun break;
540*4882a593Smuzhiyun case ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING:
541*4882a593Smuzhiyun err = ofdpa_cmd_flow_tbl_add_ucast_routing(desc_info, entry);
542*4882a593Smuzhiyun break;
543*4882a593Smuzhiyun case ROCKER_OF_DPA_TABLE_ID_BRIDGING:
544*4882a593Smuzhiyun err = ofdpa_cmd_flow_tbl_add_bridge(desc_info, entry);
545*4882a593Smuzhiyun break;
546*4882a593Smuzhiyun case ROCKER_OF_DPA_TABLE_ID_ACL_POLICY:
547*4882a593Smuzhiyun err = ofdpa_cmd_flow_tbl_add_acl(desc_info, entry);
548*4882a593Smuzhiyun break;
549*4882a593Smuzhiyun default:
550*4882a593Smuzhiyun err = -ENOTSUPP;
551*4882a593Smuzhiyun break;
552*4882a593Smuzhiyun }
553*4882a593Smuzhiyun
554*4882a593Smuzhiyun if (err)
555*4882a593Smuzhiyun return err;
556*4882a593Smuzhiyun
557*4882a593Smuzhiyun rocker_tlv_nest_end(desc_info, cmd_info);
558*4882a593Smuzhiyun
559*4882a593Smuzhiyun return 0;
560*4882a593Smuzhiyun }
561*4882a593Smuzhiyun
ofdpa_cmd_flow_tbl_del(const struct rocker_port * rocker_port,struct rocker_desc_info * desc_info,void * priv)562*4882a593Smuzhiyun static int ofdpa_cmd_flow_tbl_del(const struct rocker_port *rocker_port,
563*4882a593Smuzhiyun struct rocker_desc_info *desc_info,
564*4882a593Smuzhiyun void *priv)
565*4882a593Smuzhiyun {
566*4882a593Smuzhiyun const struct ofdpa_flow_tbl_entry *entry = priv;
567*4882a593Smuzhiyun struct rocker_tlv *cmd_info;
568*4882a593Smuzhiyun
569*4882a593Smuzhiyun if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE, entry->cmd))
570*4882a593Smuzhiyun return -EMSGSIZE;
571*4882a593Smuzhiyun cmd_info = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);
572*4882a593Smuzhiyun if (!cmd_info)
573*4882a593Smuzhiyun return -EMSGSIZE;
574*4882a593Smuzhiyun if (rocker_tlv_put_u64(desc_info, ROCKER_TLV_OF_DPA_COOKIE,
575*4882a593Smuzhiyun entry->cookie))
576*4882a593Smuzhiyun return -EMSGSIZE;
577*4882a593Smuzhiyun rocker_tlv_nest_end(desc_info, cmd_info);
578*4882a593Smuzhiyun
579*4882a593Smuzhiyun return 0;
580*4882a593Smuzhiyun }
581*4882a593Smuzhiyun
582*4882a593Smuzhiyun static int
ofdpa_cmd_group_tbl_add_l2_interface(struct rocker_desc_info * desc_info,struct ofdpa_group_tbl_entry * entry)583*4882a593Smuzhiyun ofdpa_cmd_group_tbl_add_l2_interface(struct rocker_desc_info *desc_info,
584*4882a593Smuzhiyun struct ofdpa_group_tbl_entry *entry)
585*4882a593Smuzhiyun {
586*4882a593Smuzhiyun if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_OUT_PPORT,
587*4882a593Smuzhiyun ROCKER_GROUP_PORT_GET(entry->group_id)))
588*4882a593Smuzhiyun return -EMSGSIZE;
589*4882a593Smuzhiyun if (rocker_tlv_put_u8(desc_info, ROCKER_TLV_OF_DPA_POP_VLAN,
590*4882a593Smuzhiyun entry->l2_interface.pop_vlan))
591*4882a593Smuzhiyun return -EMSGSIZE;
592*4882a593Smuzhiyun
593*4882a593Smuzhiyun return 0;
594*4882a593Smuzhiyun }
595*4882a593Smuzhiyun
596*4882a593Smuzhiyun static int
ofdpa_cmd_group_tbl_add_l2_rewrite(struct rocker_desc_info * desc_info,const struct ofdpa_group_tbl_entry * entry)597*4882a593Smuzhiyun ofdpa_cmd_group_tbl_add_l2_rewrite(struct rocker_desc_info *desc_info,
598*4882a593Smuzhiyun const struct ofdpa_group_tbl_entry *entry)
599*4882a593Smuzhiyun {
600*4882a593Smuzhiyun if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_GROUP_ID_LOWER,
601*4882a593Smuzhiyun entry->l2_rewrite.group_id))
602*4882a593Smuzhiyun return -EMSGSIZE;
603*4882a593Smuzhiyun if (!is_zero_ether_addr(entry->l2_rewrite.eth_src) &&
604*4882a593Smuzhiyun rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_SRC_MAC,
605*4882a593Smuzhiyun ETH_ALEN, entry->l2_rewrite.eth_src))
606*4882a593Smuzhiyun return -EMSGSIZE;
607*4882a593Smuzhiyun if (!is_zero_ether_addr(entry->l2_rewrite.eth_dst) &&
608*4882a593Smuzhiyun rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC,
609*4882a593Smuzhiyun ETH_ALEN, entry->l2_rewrite.eth_dst))
610*4882a593Smuzhiyun return -EMSGSIZE;
611*4882a593Smuzhiyun if (entry->l2_rewrite.vlan_id &&
612*4882a593Smuzhiyun rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID,
613*4882a593Smuzhiyun entry->l2_rewrite.vlan_id))
614*4882a593Smuzhiyun return -EMSGSIZE;
615*4882a593Smuzhiyun
616*4882a593Smuzhiyun return 0;
617*4882a593Smuzhiyun }
618*4882a593Smuzhiyun
619*4882a593Smuzhiyun static int
ofdpa_cmd_group_tbl_add_group_ids(struct rocker_desc_info * desc_info,const struct ofdpa_group_tbl_entry * entry)620*4882a593Smuzhiyun ofdpa_cmd_group_tbl_add_group_ids(struct rocker_desc_info *desc_info,
621*4882a593Smuzhiyun const struct ofdpa_group_tbl_entry *entry)
622*4882a593Smuzhiyun {
623*4882a593Smuzhiyun int i;
624*4882a593Smuzhiyun struct rocker_tlv *group_ids;
625*4882a593Smuzhiyun
626*4882a593Smuzhiyun if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_GROUP_COUNT,
627*4882a593Smuzhiyun entry->group_count))
628*4882a593Smuzhiyun return -EMSGSIZE;
629*4882a593Smuzhiyun
630*4882a593Smuzhiyun group_ids = rocker_tlv_nest_start(desc_info,
631*4882a593Smuzhiyun ROCKER_TLV_OF_DPA_GROUP_IDS);
632*4882a593Smuzhiyun if (!group_ids)
633*4882a593Smuzhiyun return -EMSGSIZE;
634*4882a593Smuzhiyun
635*4882a593Smuzhiyun for (i = 0; i < entry->group_count; i++)
636*4882a593Smuzhiyun /* Note TLV array is 1-based */
637*4882a593Smuzhiyun if (rocker_tlv_put_u32(desc_info, i + 1, entry->group_ids[i]))
638*4882a593Smuzhiyun return -EMSGSIZE;
639*4882a593Smuzhiyun
640*4882a593Smuzhiyun rocker_tlv_nest_end(desc_info, group_ids);
641*4882a593Smuzhiyun
642*4882a593Smuzhiyun return 0;
643*4882a593Smuzhiyun }
644*4882a593Smuzhiyun
645*4882a593Smuzhiyun static int
ofdpa_cmd_group_tbl_add_l3_unicast(struct rocker_desc_info * desc_info,const struct ofdpa_group_tbl_entry * entry)646*4882a593Smuzhiyun ofdpa_cmd_group_tbl_add_l3_unicast(struct rocker_desc_info *desc_info,
647*4882a593Smuzhiyun const struct ofdpa_group_tbl_entry *entry)
648*4882a593Smuzhiyun {
649*4882a593Smuzhiyun if (!is_zero_ether_addr(entry->l3_unicast.eth_src) &&
650*4882a593Smuzhiyun rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_SRC_MAC,
651*4882a593Smuzhiyun ETH_ALEN, entry->l3_unicast.eth_src))
652*4882a593Smuzhiyun return -EMSGSIZE;
653*4882a593Smuzhiyun if (!is_zero_ether_addr(entry->l3_unicast.eth_dst) &&
654*4882a593Smuzhiyun rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC,
655*4882a593Smuzhiyun ETH_ALEN, entry->l3_unicast.eth_dst))
656*4882a593Smuzhiyun return -EMSGSIZE;
657*4882a593Smuzhiyun if (entry->l3_unicast.vlan_id &&
658*4882a593Smuzhiyun rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID,
659*4882a593Smuzhiyun entry->l3_unicast.vlan_id))
660*4882a593Smuzhiyun return -EMSGSIZE;
661*4882a593Smuzhiyun if (rocker_tlv_put_u8(desc_info, ROCKER_TLV_OF_DPA_TTL_CHECK,
662*4882a593Smuzhiyun entry->l3_unicast.ttl_check))
663*4882a593Smuzhiyun return -EMSGSIZE;
664*4882a593Smuzhiyun if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_GROUP_ID_LOWER,
665*4882a593Smuzhiyun entry->l3_unicast.group_id))
666*4882a593Smuzhiyun return -EMSGSIZE;
667*4882a593Smuzhiyun
668*4882a593Smuzhiyun return 0;
669*4882a593Smuzhiyun }
670*4882a593Smuzhiyun
ofdpa_cmd_group_tbl_add(const struct rocker_port * rocker_port,struct rocker_desc_info * desc_info,void * priv)671*4882a593Smuzhiyun static int ofdpa_cmd_group_tbl_add(const struct rocker_port *rocker_port,
672*4882a593Smuzhiyun struct rocker_desc_info *desc_info,
673*4882a593Smuzhiyun void *priv)
674*4882a593Smuzhiyun {
675*4882a593Smuzhiyun struct ofdpa_group_tbl_entry *entry = priv;
676*4882a593Smuzhiyun struct rocker_tlv *cmd_info;
677*4882a593Smuzhiyun int err = 0;
678*4882a593Smuzhiyun
679*4882a593Smuzhiyun if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE, entry->cmd))
680*4882a593Smuzhiyun return -EMSGSIZE;
681*4882a593Smuzhiyun cmd_info = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);
682*4882a593Smuzhiyun if (!cmd_info)
683*4882a593Smuzhiyun return -EMSGSIZE;
684*4882a593Smuzhiyun
685*4882a593Smuzhiyun if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_GROUP_ID,
686*4882a593Smuzhiyun entry->group_id))
687*4882a593Smuzhiyun return -EMSGSIZE;
688*4882a593Smuzhiyun
689*4882a593Smuzhiyun switch (ROCKER_GROUP_TYPE_GET(entry->group_id)) {
690*4882a593Smuzhiyun case ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE:
691*4882a593Smuzhiyun err = ofdpa_cmd_group_tbl_add_l2_interface(desc_info, entry);
692*4882a593Smuzhiyun break;
693*4882a593Smuzhiyun case ROCKER_OF_DPA_GROUP_TYPE_L2_REWRITE:
694*4882a593Smuzhiyun err = ofdpa_cmd_group_tbl_add_l2_rewrite(desc_info, entry);
695*4882a593Smuzhiyun break;
696*4882a593Smuzhiyun case ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD:
697*4882a593Smuzhiyun case ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST:
698*4882a593Smuzhiyun err = ofdpa_cmd_group_tbl_add_group_ids(desc_info, entry);
699*4882a593Smuzhiyun break;
700*4882a593Smuzhiyun case ROCKER_OF_DPA_GROUP_TYPE_L3_UCAST:
701*4882a593Smuzhiyun err = ofdpa_cmd_group_tbl_add_l3_unicast(desc_info, entry);
702*4882a593Smuzhiyun break;
703*4882a593Smuzhiyun default:
704*4882a593Smuzhiyun err = -ENOTSUPP;
705*4882a593Smuzhiyun break;
706*4882a593Smuzhiyun }
707*4882a593Smuzhiyun
708*4882a593Smuzhiyun if (err)
709*4882a593Smuzhiyun return err;
710*4882a593Smuzhiyun
711*4882a593Smuzhiyun rocker_tlv_nest_end(desc_info, cmd_info);
712*4882a593Smuzhiyun
713*4882a593Smuzhiyun return 0;
714*4882a593Smuzhiyun }
715*4882a593Smuzhiyun
ofdpa_cmd_group_tbl_del(const struct rocker_port * rocker_port,struct rocker_desc_info * desc_info,void * priv)716*4882a593Smuzhiyun static int ofdpa_cmd_group_tbl_del(const struct rocker_port *rocker_port,
717*4882a593Smuzhiyun struct rocker_desc_info *desc_info,
718*4882a593Smuzhiyun void *priv)
719*4882a593Smuzhiyun {
720*4882a593Smuzhiyun const struct ofdpa_group_tbl_entry *entry = priv;
721*4882a593Smuzhiyun struct rocker_tlv *cmd_info;
722*4882a593Smuzhiyun
723*4882a593Smuzhiyun if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE, entry->cmd))
724*4882a593Smuzhiyun return -EMSGSIZE;
725*4882a593Smuzhiyun cmd_info = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);
726*4882a593Smuzhiyun if (!cmd_info)
727*4882a593Smuzhiyun return -EMSGSIZE;
728*4882a593Smuzhiyun if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_GROUP_ID,
729*4882a593Smuzhiyun entry->group_id))
730*4882a593Smuzhiyun return -EMSGSIZE;
731*4882a593Smuzhiyun rocker_tlv_nest_end(desc_info, cmd_info);
732*4882a593Smuzhiyun
733*4882a593Smuzhiyun return 0;
734*4882a593Smuzhiyun }
735*4882a593Smuzhiyun
736*4882a593Smuzhiyun /***************************************************
737*4882a593Smuzhiyun * Flow, group, FDB, internal VLAN and neigh tables
738*4882a593Smuzhiyun ***************************************************/
739*4882a593Smuzhiyun
740*4882a593Smuzhiyun static struct ofdpa_flow_tbl_entry *
ofdpa_flow_tbl_find(const struct ofdpa * ofdpa,const struct ofdpa_flow_tbl_entry * match)741*4882a593Smuzhiyun ofdpa_flow_tbl_find(const struct ofdpa *ofdpa,
742*4882a593Smuzhiyun const struct ofdpa_flow_tbl_entry *match)
743*4882a593Smuzhiyun {
744*4882a593Smuzhiyun struct ofdpa_flow_tbl_entry *found;
745*4882a593Smuzhiyun size_t key_len = match->key_len ? match->key_len : sizeof(found->key);
746*4882a593Smuzhiyun
747*4882a593Smuzhiyun hash_for_each_possible(ofdpa->flow_tbl, found,
748*4882a593Smuzhiyun entry, match->key_crc32) {
749*4882a593Smuzhiyun if (memcmp(&found->key, &match->key, key_len) == 0)
750*4882a593Smuzhiyun return found;
751*4882a593Smuzhiyun }
752*4882a593Smuzhiyun
753*4882a593Smuzhiyun return NULL;
754*4882a593Smuzhiyun }
755*4882a593Smuzhiyun
ofdpa_flow_tbl_add(struct ofdpa_port * ofdpa_port,int flags,struct ofdpa_flow_tbl_entry * match)756*4882a593Smuzhiyun static int ofdpa_flow_tbl_add(struct ofdpa_port *ofdpa_port,
757*4882a593Smuzhiyun int flags, struct ofdpa_flow_tbl_entry *match)
758*4882a593Smuzhiyun {
759*4882a593Smuzhiyun struct ofdpa *ofdpa = ofdpa_port->ofdpa;
760*4882a593Smuzhiyun struct ofdpa_flow_tbl_entry *found;
761*4882a593Smuzhiyun size_t key_len = match->key_len ? match->key_len : sizeof(found->key);
762*4882a593Smuzhiyun unsigned long lock_flags;
763*4882a593Smuzhiyun
764*4882a593Smuzhiyun match->key_crc32 = crc32(~0, &match->key, key_len);
765*4882a593Smuzhiyun
766*4882a593Smuzhiyun spin_lock_irqsave(&ofdpa->flow_tbl_lock, lock_flags);
767*4882a593Smuzhiyun
768*4882a593Smuzhiyun found = ofdpa_flow_tbl_find(ofdpa, match);
769*4882a593Smuzhiyun
770*4882a593Smuzhiyun if (found) {
771*4882a593Smuzhiyun match->cookie = found->cookie;
772*4882a593Smuzhiyun hash_del(&found->entry);
773*4882a593Smuzhiyun kfree(found);
774*4882a593Smuzhiyun found = match;
775*4882a593Smuzhiyun found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_MOD;
776*4882a593Smuzhiyun } else {
777*4882a593Smuzhiyun found = match;
778*4882a593Smuzhiyun found->cookie = ofdpa->flow_tbl_next_cookie++;
779*4882a593Smuzhiyun found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_ADD;
780*4882a593Smuzhiyun }
781*4882a593Smuzhiyun
782*4882a593Smuzhiyun hash_add(ofdpa->flow_tbl, &found->entry, found->key_crc32);
783*4882a593Smuzhiyun spin_unlock_irqrestore(&ofdpa->flow_tbl_lock, lock_flags);
784*4882a593Smuzhiyun
785*4882a593Smuzhiyun return rocker_cmd_exec(ofdpa_port->rocker_port,
786*4882a593Smuzhiyun ofdpa_flags_nowait(flags),
787*4882a593Smuzhiyun ofdpa_cmd_flow_tbl_add,
788*4882a593Smuzhiyun found, NULL, NULL);
789*4882a593Smuzhiyun }
790*4882a593Smuzhiyun
ofdpa_flow_tbl_del(struct ofdpa_port * ofdpa_port,int flags,struct ofdpa_flow_tbl_entry * match)791*4882a593Smuzhiyun static int ofdpa_flow_tbl_del(struct ofdpa_port *ofdpa_port,
792*4882a593Smuzhiyun int flags, struct ofdpa_flow_tbl_entry *match)
793*4882a593Smuzhiyun {
794*4882a593Smuzhiyun struct ofdpa *ofdpa = ofdpa_port->ofdpa;
795*4882a593Smuzhiyun struct ofdpa_flow_tbl_entry *found;
796*4882a593Smuzhiyun size_t key_len = match->key_len ? match->key_len : sizeof(found->key);
797*4882a593Smuzhiyun unsigned long lock_flags;
798*4882a593Smuzhiyun int err = 0;
799*4882a593Smuzhiyun
800*4882a593Smuzhiyun match->key_crc32 = crc32(~0, &match->key, key_len);
801*4882a593Smuzhiyun
802*4882a593Smuzhiyun spin_lock_irqsave(&ofdpa->flow_tbl_lock, lock_flags);
803*4882a593Smuzhiyun
804*4882a593Smuzhiyun found = ofdpa_flow_tbl_find(ofdpa, match);
805*4882a593Smuzhiyun
806*4882a593Smuzhiyun if (found) {
807*4882a593Smuzhiyun hash_del(&found->entry);
808*4882a593Smuzhiyun found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_DEL;
809*4882a593Smuzhiyun }
810*4882a593Smuzhiyun
811*4882a593Smuzhiyun spin_unlock_irqrestore(&ofdpa->flow_tbl_lock, lock_flags);
812*4882a593Smuzhiyun
813*4882a593Smuzhiyun kfree(match);
814*4882a593Smuzhiyun
815*4882a593Smuzhiyun if (found) {
816*4882a593Smuzhiyun err = rocker_cmd_exec(ofdpa_port->rocker_port,
817*4882a593Smuzhiyun ofdpa_flags_nowait(flags),
818*4882a593Smuzhiyun ofdpa_cmd_flow_tbl_del,
819*4882a593Smuzhiyun found, NULL, NULL);
820*4882a593Smuzhiyun kfree(found);
821*4882a593Smuzhiyun }
822*4882a593Smuzhiyun
823*4882a593Smuzhiyun return err;
824*4882a593Smuzhiyun }
825*4882a593Smuzhiyun
ofdpa_flow_tbl_do(struct ofdpa_port * ofdpa_port,int flags,struct ofdpa_flow_tbl_entry * entry)826*4882a593Smuzhiyun static int ofdpa_flow_tbl_do(struct ofdpa_port *ofdpa_port, int flags,
827*4882a593Smuzhiyun struct ofdpa_flow_tbl_entry *entry)
828*4882a593Smuzhiyun {
829*4882a593Smuzhiyun if (flags & OFDPA_OP_FLAG_REMOVE)
830*4882a593Smuzhiyun return ofdpa_flow_tbl_del(ofdpa_port, flags, entry);
831*4882a593Smuzhiyun else
832*4882a593Smuzhiyun return ofdpa_flow_tbl_add(ofdpa_port, flags, entry);
833*4882a593Smuzhiyun }
834*4882a593Smuzhiyun
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)835*4882a593Smuzhiyun static int ofdpa_flow_tbl_ig_port(struct ofdpa_port *ofdpa_port, int flags,
836*4882a593Smuzhiyun u32 in_pport, u32 in_pport_mask,
837*4882a593Smuzhiyun enum rocker_of_dpa_table_id goto_tbl)
838*4882a593Smuzhiyun {
839*4882a593Smuzhiyun struct ofdpa_flow_tbl_entry *entry;
840*4882a593Smuzhiyun
841*4882a593Smuzhiyun entry = kzalloc(sizeof(*entry), GFP_KERNEL);
842*4882a593Smuzhiyun if (!entry)
843*4882a593Smuzhiyun return -ENOMEM;
844*4882a593Smuzhiyun
845*4882a593Smuzhiyun entry->key.priority = OFDPA_PRIORITY_IG_PORT;
846*4882a593Smuzhiyun entry->key.tbl_id = ROCKER_OF_DPA_TABLE_ID_INGRESS_PORT;
847*4882a593Smuzhiyun entry->key.ig_port.in_pport = in_pport;
848*4882a593Smuzhiyun entry->key.ig_port.in_pport_mask = in_pport_mask;
849*4882a593Smuzhiyun entry->key.ig_port.goto_tbl = goto_tbl;
850*4882a593Smuzhiyun
851*4882a593Smuzhiyun return ofdpa_flow_tbl_do(ofdpa_port, flags, entry);
852*4882a593Smuzhiyun }
853*4882a593Smuzhiyun
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)854*4882a593Smuzhiyun static int ofdpa_flow_tbl_vlan(struct ofdpa_port *ofdpa_port,
855*4882a593Smuzhiyun int flags,
856*4882a593Smuzhiyun u32 in_pport, __be16 vlan_id,
857*4882a593Smuzhiyun __be16 vlan_id_mask,
858*4882a593Smuzhiyun enum rocker_of_dpa_table_id goto_tbl,
859*4882a593Smuzhiyun bool untagged, __be16 new_vlan_id)
860*4882a593Smuzhiyun {
861*4882a593Smuzhiyun struct ofdpa_flow_tbl_entry *entry;
862*4882a593Smuzhiyun
863*4882a593Smuzhiyun entry = kzalloc(sizeof(*entry), GFP_KERNEL);
864*4882a593Smuzhiyun if (!entry)
865*4882a593Smuzhiyun return -ENOMEM;
866*4882a593Smuzhiyun
867*4882a593Smuzhiyun entry->key.priority = OFDPA_PRIORITY_VLAN;
868*4882a593Smuzhiyun entry->key.tbl_id = ROCKER_OF_DPA_TABLE_ID_VLAN;
869*4882a593Smuzhiyun entry->key.vlan.in_pport = in_pport;
870*4882a593Smuzhiyun entry->key.vlan.vlan_id = vlan_id;
871*4882a593Smuzhiyun entry->key.vlan.vlan_id_mask = vlan_id_mask;
872*4882a593Smuzhiyun entry->key.vlan.goto_tbl = goto_tbl;
873*4882a593Smuzhiyun
874*4882a593Smuzhiyun entry->key.vlan.untagged = untagged;
875*4882a593Smuzhiyun entry->key.vlan.new_vlan_id = new_vlan_id;
876*4882a593Smuzhiyun
877*4882a593Smuzhiyun return ofdpa_flow_tbl_do(ofdpa_port, flags, entry);
878*4882a593Smuzhiyun }
879*4882a593Smuzhiyun
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)880*4882a593Smuzhiyun static int ofdpa_flow_tbl_term_mac(struct ofdpa_port *ofdpa_port,
881*4882a593Smuzhiyun u32 in_pport, u32 in_pport_mask,
882*4882a593Smuzhiyun __be16 eth_type, const u8 *eth_dst,
883*4882a593Smuzhiyun const u8 *eth_dst_mask, __be16 vlan_id,
884*4882a593Smuzhiyun __be16 vlan_id_mask, bool copy_to_cpu,
885*4882a593Smuzhiyun int flags)
886*4882a593Smuzhiyun {
887*4882a593Smuzhiyun struct ofdpa_flow_tbl_entry *entry;
888*4882a593Smuzhiyun
889*4882a593Smuzhiyun entry = kzalloc(sizeof(*entry), GFP_KERNEL);
890*4882a593Smuzhiyun if (!entry)
891*4882a593Smuzhiyun return -ENOMEM;
892*4882a593Smuzhiyun
893*4882a593Smuzhiyun if (is_multicast_ether_addr(eth_dst)) {
894*4882a593Smuzhiyun entry->key.priority = OFDPA_PRIORITY_TERM_MAC_MCAST;
895*4882a593Smuzhiyun entry->key.term_mac.goto_tbl =
896*4882a593Smuzhiyun ROCKER_OF_DPA_TABLE_ID_MULTICAST_ROUTING;
897*4882a593Smuzhiyun } else {
898*4882a593Smuzhiyun entry->key.priority = OFDPA_PRIORITY_TERM_MAC_UCAST;
899*4882a593Smuzhiyun entry->key.term_mac.goto_tbl =
900*4882a593Smuzhiyun ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING;
901*4882a593Smuzhiyun }
902*4882a593Smuzhiyun
903*4882a593Smuzhiyun entry->key.tbl_id = ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC;
904*4882a593Smuzhiyun entry->key.term_mac.in_pport = in_pport;
905*4882a593Smuzhiyun entry->key.term_mac.in_pport_mask = in_pport_mask;
906*4882a593Smuzhiyun entry->key.term_mac.eth_type = eth_type;
907*4882a593Smuzhiyun ether_addr_copy(entry->key.term_mac.eth_dst, eth_dst);
908*4882a593Smuzhiyun ether_addr_copy(entry->key.term_mac.eth_dst_mask, eth_dst_mask);
909*4882a593Smuzhiyun entry->key.term_mac.vlan_id = vlan_id;
910*4882a593Smuzhiyun entry->key.term_mac.vlan_id_mask = vlan_id_mask;
911*4882a593Smuzhiyun entry->key.term_mac.copy_to_cpu = copy_to_cpu;
912*4882a593Smuzhiyun
913*4882a593Smuzhiyun return ofdpa_flow_tbl_do(ofdpa_port, flags, entry);
914*4882a593Smuzhiyun }
915*4882a593Smuzhiyun
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)916*4882a593Smuzhiyun static int ofdpa_flow_tbl_bridge(struct ofdpa_port *ofdpa_port,
917*4882a593Smuzhiyun int flags, const u8 *eth_dst,
918*4882a593Smuzhiyun const u8 *eth_dst_mask, __be16 vlan_id,
919*4882a593Smuzhiyun u32 tunnel_id,
920*4882a593Smuzhiyun enum rocker_of_dpa_table_id goto_tbl,
921*4882a593Smuzhiyun u32 group_id, bool copy_to_cpu)
922*4882a593Smuzhiyun {
923*4882a593Smuzhiyun struct ofdpa_flow_tbl_entry *entry;
924*4882a593Smuzhiyun u32 priority;
925*4882a593Smuzhiyun bool vlan_bridging = !!vlan_id;
926*4882a593Smuzhiyun bool dflt = !eth_dst || (eth_dst && eth_dst_mask);
927*4882a593Smuzhiyun bool wild = false;
928*4882a593Smuzhiyun
929*4882a593Smuzhiyun entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
930*4882a593Smuzhiyun if (!entry)
931*4882a593Smuzhiyun return -ENOMEM;
932*4882a593Smuzhiyun
933*4882a593Smuzhiyun entry->key.tbl_id = ROCKER_OF_DPA_TABLE_ID_BRIDGING;
934*4882a593Smuzhiyun
935*4882a593Smuzhiyun if (eth_dst) {
936*4882a593Smuzhiyun entry->key.bridge.has_eth_dst = 1;
937*4882a593Smuzhiyun ether_addr_copy(entry->key.bridge.eth_dst, eth_dst);
938*4882a593Smuzhiyun }
939*4882a593Smuzhiyun if (eth_dst_mask) {
940*4882a593Smuzhiyun entry->key.bridge.has_eth_dst_mask = 1;
941*4882a593Smuzhiyun ether_addr_copy(entry->key.bridge.eth_dst_mask, eth_dst_mask);
942*4882a593Smuzhiyun if (!ether_addr_equal(eth_dst_mask, ff_mac))
943*4882a593Smuzhiyun wild = true;
944*4882a593Smuzhiyun }
945*4882a593Smuzhiyun
946*4882a593Smuzhiyun priority = OFDPA_PRIORITY_UNKNOWN;
947*4882a593Smuzhiyun if (vlan_bridging && dflt && wild)
948*4882a593Smuzhiyun priority = OFDPA_PRIORITY_BRIDGING_VLAN_DFLT_WILD;
949*4882a593Smuzhiyun else if (vlan_bridging && dflt && !wild)
950*4882a593Smuzhiyun priority = OFDPA_PRIORITY_BRIDGING_VLAN_DFLT_EXACT;
951*4882a593Smuzhiyun else if (vlan_bridging && !dflt)
952*4882a593Smuzhiyun priority = OFDPA_PRIORITY_BRIDGING_VLAN;
953*4882a593Smuzhiyun else if (!vlan_bridging && dflt && wild)
954*4882a593Smuzhiyun priority = OFDPA_PRIORITY_BRIDGING_TENANT_DFLT_WILD;
955*4882a593Smuzhiyun else if (!vlan_bridging && dflt && !wild)
956*4882a593Smuzhiyun priority = OFDPA_PRIORITY_BRIDGING_TENANT_DFLT_EXACT;
957*4882a593Smuzhiyun else if (!vlan_bridging && !dflt)
958*4882a593Smuzhiyun priority = OFDPA_PRIORITY_BRIDGING_TENANT;
959*4882a593Smuzhiyun
960*4882a593Smuzhiyun entry->key.priority = priority;
961*4882a593Smuzhiyun entry->key.bridge.vlan_id = vlan_id;
962*4882a593Smuzhiyun entry->key.bridge.tunnel_id = tunnel_id;
963*4882a593Smuzhiyun entry->key.bridge.goto_tbl = goto_tbl;
964*4882a593Smuzhiyun entry->key.bridge.group_id = group_id;
965*4882a593Smuzhiyun entry->key.bridge.copy_to_cpu = copy_to_cpu;
966*4882a593Smuzhiyun
967*4882a593Smuzhiyun return ofdpa_flow_tbl_do(ofdpa_port, flags, entry);
968*4882a593Smuzhiyun }
969*4882a593Smuzhiyun
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)970*4882a593Smuzhiyun static int ofdpa_flow_tbl_ucast4_routing(struct ofdpa_port *ofdpa_port,
971*4882a593Smuzhiyun __be16 eth_type, __be32 dst,
972*4882a593Smuzhiyun __be32 dst_mask, u32 priority,
973*4882a593Smuzhiyun enum rocker_of_dpa_table_id goto_tbl,
974*4882a593Smuzhiyun u32 group_id, struct fib_info *fi,
975*4882a593Smuzhiyun int flags)
976*4882a593Smuzhiyun {
977*4882a593Smuzhiyun struct ofdpa_flow_tbl_entry *entry;
978*4882a593Smuzhiyun
979*4882a593Smuzhiyun entry = kzalloc(sizeof(*entry), GFP_KERNEL);
980*4882a593Smuzhiyun if (!entry)
981*4882a593Smuzhiyun return -ENOMEM;
982*4882a593Smuzhiyun
983*4882a593Smuzhiyun entry->key.tbl_id = ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING;
984*4882a593Smuzhiyun entry->key.priority = priority;
985*4882a593Smuzhiyun entry->key.ucast_routing.eth_type = eth_type;
986*4882a593Smuzhiyun entry->key.ucast_routing.dst4 = dst;
987*4882a593Smuzhiyun entry->key.ucast_routing.dst4_mask = dst_mask;
988*4882a593Smuzhiyun entry->key.ucast_routing.goto_tbl = goto_tbl;
989*4882a593Smuzhiyun entry->key.ucast_routing.group_id = group_id;
990*4882a593Smuzhiyun entry->key_len = offsetof(struct ofdpa_flow_tbl_key,
991*4882a593Smuzhiyun ucast_routing.group_id);
992*4882a593Smuzhiyun entry->fi = fi;
993*4882a593Smuzhiyun
994*4882a593Smuzhiyun return ofdpa_flow_tbl_do(ofdpa_port, flags, entry);
995*4882a593Smuzhiyun }
996*4882a593Smuzhiyun
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)997*4882a593Smuzhiyun static int ofdpa_flow_tbl_acl(struct ofdpa_port *ofdpa_port, int flags,
998*4882a593Smuzhiyun u32 in_pport, u32 in_pport_mask,
999*4882a593Smuzhiyun const u8 *eth_src, const u8 *eth_src_mask,
1000*4882a593Smuzhiyun const u8 *eth_dst, const u8 *eth_dst_mask,
1001*4882a593Smuzhiyun __be16 eth_type, __be16 vlan_id,
1002*4882a593Smuzhiyun __be16 vlan_id_mask, u8 ip_proto,
1003*4882a593Smuzhiyun u8 ip_proto_mask, u8 ip_tos, u8 ip_tos_mask,
1004*4882a593Smuzhiyun u32 group_id)
1005*4882a593Smuzhiyun {
1006*4882a593Smuzhiyun u32 priority;
1007*4882a593Smuzhiyun struct ofdpa_flow_tbl_entry *entry;
1008*4882a593Smuzhiyun
1009*4882a593Smuzhiyun entry = kzalloc(sizeof(*entry), GFP_KERNEL);
1010*4882a593Smuzhiyun if (!entry)
1011*4882a593Smuzhiyun return -ENOMEM;
1012*4882a593Smuzhiyun
1013*4882a593Smuzhiyun priority = OFDPA_PRIORITY_ACL_NORMAL;
1014*4882a593Smuzhiyun if (eth_dst && eth_dst_mask) {
1015*4882a593Smuzhiyun if (ether_addr_equal(eth_dst_mask, mcast_mac))
1016*4882a593Smuzhiyun priority = OFDPA_PRIORITY_ACL_DFLT;
1017*4882a593Smuzhiyun else if (is_link_local_ether_addr(eth_dst))
1018*4882a593Smuzhiyun priority = OFDPA_PRIORITY_ACL_CTRL;
1019*4882a593Smuzhiyun }
1020*4882a593Smuzhiyun
1021*4882a593Smuzhiyun entry->key.priority = priority;
1022*4882a593Smuzhiyun entry->key.tbl_id = ROCKER_OF_DPA_TABLE_ID_ACL_POLICY;
1023*4882a593Smuzhiyun entry->key.acl.in_pport = in_pport;
1024*4882a593Smuzhiyun entry->key.acl.in_pport_mask = in_pport_mask;
1025*4882a593Smuzhiyun
1026*4882a593Smuzhiyun if (eth_src)
1027*4882a593Smuzhiyun ether_addr_copy(entry->key.acl.eth_src, eth_src);
1028*4882a593Smuzhiyun if (eth_src_mask)
1029*4882a593Smuzhiyun ether_addr_copy(entry->key.acl.eth_src_mask, eth_src_mask);
1030*4882a593Smuzhiyun if (eth_dst)
1031*4882a593Smuzhiyun ether_addr_copy(entry->key.acl.eth_dst, eth_dst);
1032*4882a593Smuzhiyun if (eth_dst_mask)
1033*4882a593Smuzhiyun ether_addr_copy(entry->key.acl.eth_dst_mask, eth_dst_mask);
1034*4882a593Smuzhiyun
1035*4882a593Smuzhiyun entry->key.acl.eth_type = eth_type;
1036*4882a593Smuzhiyun entry->key.acl.vlan_id = vlan_id;
1037*4882a593Smuzhiyun entry->key.acl.vlan_id_mask = vlan_id_mask;
1038*4882a593Smuzhiyun entry->key.acl.ip_proto = ip_proto;
1039*4882a593Smuzhiyun entry->key.acl.ip_proto_mask = ip_proto_mask;
1040*4882a593Smuzhiyun entry->key.acl.ip_tos = ip_tos;
1041*4882a593Smuzhiyun entry->key.acl.ip_tos_mask = ip_tos_mask;
1042*4882a593Smuzhiyun entry->key.acl.group_id = group_id;
1043*4882a593Smuzhiyun
1044*4882a593Smuzhiyun return ofdpa_flow_tbl_do(ofdpa_port, flags, entry);
1045*4882a593Smuzhiyun }
1046*4882a593Smuzhiyun
1047*4882a593Smuzhiyun static struct ofdpa_group_tbl_entry *
ofdpa_group_tbl_find(const struct ofdpa * ofdpa,const struct ofdpa_group_tbl_entry * match)1048*4882a593Smuzhiyun ofdpa_group_tbl_find(const struct ofdpa *ofdpa,
1049*4882a593Smuzhiyun const struct ofdpa_group_tbl_entry *match)
1050*4882a593Smuzhiyun {
1051*4882a593Smuzhiyun struct ofdpa_group_tbl_entry *found;
1052*4882a593Smuzhiyun
1053*4882a593Smuzhiyun hash_for_each_possible(ofdpa->group_tbl, found,
1054*4882a593Smuzhiyun entry, match->group_id) {
1055*4882a593Smuzhiyun if (found->group_id == match->group_id)
1056*4882a593Smuzhiyun return found;
1057*4882a593Smuzhiyun }
1058*4882a593Smuzhiyun
1059*4882a593Smuzhiyun return NULL;
1060*4882a593Smuzhiyun }
1061*4882a593Smuzhiyun
ofdpa_group_tbl_entry_free(struct ofdpa_group_tbl_entry * entry)1062*4882a593Smuzhiyun static void ofdpa_group_tbl_entry_free(struct ofdpa_group_tbl_entry *entry)
1063*4882a593Smuzhiyun {
1064*4882a593Smuzhiyun switch (ROCKER_GROUP_TYPE_GET(entry->group_id)) {
1065*4882a593Smuzhiyun case ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD:
1066*4882a593Smuzhiyun case ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST:
1067*4882a593Smuzhiyun kfree(entry->group_ids);
1068*4882a593Smuzhiyun break;
1069*4882a593Smuzhiyun default:
1070*4882a593Smuzhiyun break;
1071*4882a593Smuzhiyun }
1072*4882a593Smuzhiyun kfree(entry);
1073*4882a593Smuzhiyun }
1074*4882a593Smuzhiyun
ofdpa_group_tbl_add(struct ofdpa_port * ofdpa_port,int flags,struct ofdpa_group_tbl_entry * match)1075*4882a593Smuzhiyun static int ofdpa_group_tbl_add(struct ofdpa_port *ofdpa_port, int flags,
1076*4882a593Smuzhiyun struct ofdpa_group_tbl_entry *match)
1077*4882a593Smuzhiyun {
1078*4882a593Smuzhiyun struct ofdpa *ofdpa = ofdpa_port->ofdpa;
1079*4882a593Smuzhiyun struct ofdpa_group_tbl_entry *found;
1080*4882a593Smuzhiyun unsigned long lock_flags;
1081*4882a593Smuzhiyun
1082*4882a593Smuzhiyun spin_lock_irqsave(&ofdpa->group_tbl_lock, lock_flags);
1083*4882a593Smuzhiyun
1084*4882a593Smuzhiyun found = ofdpa_group_tbl_find(ofdpa, match);
1085*4882a593Smuzhiyun
1086*4882a593Smuzhiyun if (found) {
1087*4882a593Smuzhiyun hash_del(&found->entry);
1088*4882a593Smuzhiyun ofdpa_group_tbl_entry_free(found);
1089*4882a593Smuzhiyun found = match;
1090*4882a593Smuzhiyun found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_MOD;
1091*4882a593Smuzhiyun } else {
1092*4882a593Smuzhiyun found = match;
1093*4882a593Smuzhiyun found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_ADD;
1094*4882a593Smuzhiyun }
1095*4882a593Smuzhiyun
1096*4882a593Smuzhiyun hash_add(ofdpa->group_tbl, &found->entry, found->group_id);
1097*4882a593Smuzhiyun
1098*4882a593Smuzhiyun spin_unlock_irqrestore(&ofdpa->group_tbl_lock, lock_flags);
1099*4882a593Smuzhiyun
1100*4882a593Smuzhiyun return rocker_cmd_exec(ofdpa_port->rocker_port,
1101*4882a593Smuzhiyun ofdpa_flags_nowait(flags),
1102*4882a593Smuzhiyun ofdpa_cmd_group_tbl_add,
1103*4882a593Smuzhiyun found, NULL, NULL);
1104*4882a593Smuzhiyun }
1105*4882a593Smuzhiyun
ofdpa_group_tbl_del(struct ofdpa_port * ofdpa_port,int flags,struct ofdpa_group_tbl_entry * match)1106*4882a593Smuzhiyun static int ofdpa_group_tbl_del(struct ofdpa_port *ofdpa_port, int flags,
1107*4882a593Smuzhiyun struct ofdpa_group_tbl_entry *match)
1108*4882a593Smuzhiyun {
1109*4882a593Smuzhiyun struct ofdpa *ofdpa = ofdpa_port->ofdpa;
1110*4882a593Smuzhiyun struct ofdpa_group_tbl_entry *found;
1111*4882a593Smuzhiyun unsigned long lock_flags;
1112*4882a593Smuzhiyun int err = 0;
1113*4882a593Smuzhiyun
1114*4882a593Smuzhiyun spin_lock_irqsave(&ofdpa->group_tbl_lock, lock_flags);
1115*4882a593Smuzhiyun
1116*4882a593Smuzhiyun found = ofdpa_group_tbl_find(ofdpa, match);
1117*4882a593Smuzhiyun
1118*4882a593Smuzhiyun if (found) {
1119*4882a593Smuzhiyun hash_del(&found->entry);
1120*4882a593Smuzhiyun found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_DEL;
1121*4882a593Smuzhiyun }
1122*4882a593Smuzhiyun
1123*4882a593Smuzhiyun spin_unlock_irqrestore(&ofdpa->group_tbl_lock, lock_flags);
1124*4882a593Smuzhiyun
1125*4882a593Smuzhiyun ofdpa_group_tbl_entry_free(match);
1126*4882a593Smuzhiyun
1127*4882a593Smuzhiyun if (found) {
1128*4882a593Smuzhiyun err = rocker_cmd_exec(ofdpa_port->rocker_port,
1129*4882a593Smuzhiyun ofdpa_flags_nowait(flags),
1130*4882a593Smuzhiyun ofdpa_cmd_group_tbl_del,
1131*4882a593Smuzhiyun found, NULL, NULL);
1132*4882a593Smuzhiyun ofdpa_group_tbl_entry_free(found);
1133*4882a593Smuzhiyun }
1134*4882a593Smuzhiyun
1135*4882a593Smuzhiyun return err;
1136*4882a593Smuzhiyun }
1137*4882a593Smuzhiyun
ofdpa_group_tbl_do(struct ofdpa_port * ofdpa_port,int flags,struct ofdpa_group_tbl_entry * entry)1138*4882a593Smuzhiyun static int ofdpa_group_tbl_do(struct ofdpa_port *ofdpa_port, int flags,
1139*4882a593Smuzhiyun struct ofdpa_group_tbl_entry *entry)
1140*4882a593Smuzhiyun {
1141*4882a593Smuzhiyun if (flags & OFDPA_OP_FLAG_REMOVE)
1142*4882a593Smuzhiyun return ofdpa_group_tbl_del(ofdpa_port, flags, entry);
1143*4882a593Smuzhiyun else
1144*4882a593Smuzhiyun return ofdpa_group_tbl_add(ofdpa_port, flags, entry);
1145*4882a593Smuzhiyun }
1146*4882a593Smuzhiyun
ofdpa_group_l2_interface(struct ofdpa_port * ofdpa_port,int flags,__be16 vlan_id,u32 out_pport,int pop_vlan)1147*4882a593Smuzhiyun static int ofdpa_group_l2_interface(struct ofdpa_port *ofdpa_port,
1148*4882a593Smuzhiyun int flags, __be16 vlan_id,
1149*4882a593Smuzhiyun u32 out_pport, int pop_vlan)
1150*4882a593Smuzhiyun {
1151*4882a593Smuzhiyun struct ofdpa_group_tbl_entry *entry;
1152*4882a593Smuzhiyun
1153*4882a593Smuzhiyun entry = kzalloc(sizeof(*entry), GFP_KERNEL);
1154*4882a593Smuzhiyun if (!entry)
1155*4882a593Smuzhiyun return -ENOMEM;
1156*4882a593Smuzhiyun
1157*4882a593Smuzhiyun entry->group_id = ROCKER_GROUP_L2_INTERFACE(vlan_id, out_pport);
1158*4882a593Smuzhiyun entry->l2_interface.pop_vlan = pop_vlan;
1159*4882a593Smuzhiyun
1160*4882a593Smuzhiyun return ofdpa_group_tbl_do(ofdpa_port, flags, entry);
1161*4882a593Smuzhiyun }
1162*4882a593Smuzhiyun
ofdpa_group_l2_fan_out(struct ofdpa_port * ofdpa_port,int flags,u8 group_count,const u32 * group_ids,u32 group_id)1163*4882a593Smuzhiyun static int ofdpa_group_l2_fan_out(struct ofdpa_port *ofdpa_port,
1164*4882a593Smuzhiyun int flags, u8 group_count,
1165*4882a593Smuzhiyun const u32 *group_ids, u32 group_id)
1166*4882a593Smuzhiyun {
1167*4882a593Smuzhiyun struct ofdpa_group_tbl_entry *entry;
1168*4882a593Smuzhiyun
1169*4882a593Smuzhiyun entry = kzalloc(sizeof(*entry), GFP_KERNEL);
1170*4882a593Smuzhiyun if (!entry)
1171*4882a593Smuzhiyun return -ENOMEM;
1172*4882a593Smuzhiyun
1173*4882a593Smuzhiyun entry->group_id = group_id;
1174*4882a593Smuzhiyun entry->group_count = group_count;
1175*4882a593Smuzhiyun
1176*4882a593Smuzhiyun entry->group_ids = kcalloc(group_count, sizeof(u32), GFP_KERNEL);
1177*4882a593Smuzhiyun if (!entry->group_ids) {
1178*4882a593Smuzhiyun kfree(entry);
1179*4882a593Smuzhiyun return -ENOMEM;
1180*4882a593Smuzhiyun }
1181*4882a593Smuzhiyun memcpy(entry->group_ids, group_ids, group_count * sizeof(u32));
1182*4882a593Smuzhiyun
1183*4882a593Smuzhiyun return ofdpa_group_tbl_do(ofdpa_port, flags, entry);
1184*4882a593Smuzhiyun }
1185*4882a593Smuzhiyun
ofdpa_group_l2_flood(struct ofdpa_port * ofdpa_port,int flags,__be16 vlan_id,u8 group_count,const u32 * group_ids,u32 group_id)1186*4882a593Smuzhiyun static int ofdpa_group_l2_flood(struct ofdpa_port *ofdpa_port,
1187*4882a593Smuzhiyun int flags, __be16 vlan_id,
1188*4882a593Smuzhiyun u8 group_count, const u32 *group_ids,
1189*4882a593Smuzhiyun u32 group_id)
1190*4882a593Smuzhiyun {
1191*4882a593Smuzhiyun return ofdpa_group_l2_fan_out(ofdpa_port, flags,
1192*4882a593Smuzhiyun group_count, group_ids,
1193*4882a593Smuzhiyun group_id);
1194*4882a593Smuzhiyun }
1195*4882a593Smuzhiyun
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)1196*4882a593Smuzhiyun static int ofdpa_group_l3_unicast(struct ofdpa_port *ofdpa_port, int flags,
1197*4882a593Smuzhiyun u32 index, const u8 *src_mac, const u8 *dst_mac,
1198*4882a593Smuzhiyun __be16 vlan_id, bool ttl_check, u32 pport)
1199*4882a593Smuzhiyun {
1200*4882a593Smuzhiyun struct ofdpa_group_tbl_entry *entry;
1201*4882a593Smuzhiyun
1202*4882a593Smuzhiyun entry = kzalloc(sizeof(*entry), GFP_KERNEL);
1203*4882a593Smuzhiyun if (!entry)
1204*4882a593Smuzhiyun return -ENOMEM;
1205*4882a593Smuzhiyun
1206*4882a593Smuzhiyun entry->group_id = ROCKER_GROUP_L3_UNICAST(index);
1207*4882a593Smuzhiyun if (src_mac)
1208*4882a593Smuzhiyun ether_addr_copy(entry->l3_unicast.eth_src, src_mac);
1209*4882a593Smuzhiyun if (dst_mac)
1210*4882a593Smuzhiyun ether_addr_copy(entry->l3_unicast.eth_dst, dst_mac);
1211*4882a593Smuzhiyun entry->l3_unicast.vlan_id = vlan_id;
1212*4882a593Smuzhiyun entry->l3_unicast.ttl_check = ttl_check;
1213*4882a593Smuzhiyun entry->l3_unicast.group_id = ROCKER_GROUP_L2_INTERFACE(vlan_id, pport);
1214*4882a593Smuzhiyun
1215*4882a593Smuzhiyun return ofdpa_group_tbl_do(ofdpa_port, flags, entry);
1216*4882a593Smuzhiyun }
1217*4882a593Smuzhiyun
1218*4882a593Smuzhiyun static struct ofdpa_neigh_tbl_entry *
ofdpa_neigh_tbl_find(const struct ofdpa * ofdpa,__be32 ip_addr)1219*4882a593Smuzhiyun ofdpa_neigh_tbl_find(const struct ofdpa *ofdpa, __be32 ip_addr)
1220*4882a593Smuzhiyun {
1221*4882a593Smuzhiyun struct ofdpa_neigh_tbl_entry *found;
1222*4882a593Smuzhiyun
1223*4882a593Smuzhiyun hash_for_each_possible(ofdpa->neigh_tbl, found,
1224*4882a593Smuzhiyun entry, be32_to_cpu(ip_addr))
1225*4882a593Smuzhiyun if (found->ip_addr == ip_addr)
1226*4882a593Smuzhiyun return found;
1227*4882a593Smuzhiyun
1228*4882a593Smuzhiyun return NULL;
1229*4882a593Smuzhiyun }
1230*4882a593Smuzhiyun
ofdpa_neigh_add(struct ofdpa * ofdpa,struct ofdpa_neigh_tbl_entry * entry)1231*4882a593Smuzhiyun static void ofdpa_neigh_add(struct ofdpa *ofdpa,
1232*4882a593Smuzhiyun struct ofdpa_neigh_tbl_entry *entry)
1233*4882a593Smuzhiyun {
1234*4882a593Smuzhiyun entry->index = ofdpa->neigh_tbl_next_index++;
1235*4882a593Smuzhiyun entry->ref_count++;
1236*4882a593Smuzhiyun hash_add(ofdpa->neigh_tbl, &entry->entry,
1237*4882a593Smuzhiyun be32_to_cpu(entry->ip_addr));
1238*4882a593Smuzhiyun }
1239*4882a593Smuzhiyun
ofdpa_neigh_del(struct ofdpa_neigh_tbl_entry * entry)1240*4882a593Smuzhiyun static void ofdpa_neigh_del(struct ofdpa_neigh_tbl_entry *entry)
1241*4882a593Smuzhiyun {
1242*4882a593Smuzhiyun if (--entry->ref_count == 0) {
1243*4882a593Smuzhiyun hash_del(&entry->entry);
1244*4882a593Smuzhiyun kfree(entry);
1245*4882a593Smuzhiyun }
1246*4882a593Smuzhiyun }
1247*4882a593Smuzhiyun
ofdpa_neigh_update(struct ofdpa_neigh_tbl_entry * entry,const u8 * eth_dst,bool ttl_check)1248*4882a593Smuzhiyun static void ofdpa_neigh_update(struct ofdpa_neigh_tbl_entry *entry,
1249*4882a593Smuzhiyun const u8 *eth_dst, bool ttl_check)
1250*4882a593Smuzhiyun {
1251*4882a593Smuzhiyun if (eth_dst) {
1252*4882a593Smuzhiyun ether_addr_copy(entry->eth_dst, eth_dst);
1253*4882a593Smuzhiyun entry->ttl_check = ttl_check;
1254*4882a593Smuzhiyun } else {
1255*4882a593Smuzhiyun entry->ref_count++;
1256*4882a593Smuzhiyun }
1257*4882a593Smuzhiyun }
1258*4882a593Smuzhiyun
ofdpa_port_ipv4_neigh(struct ofdpa_port * ofdpa_port,int flags,__be32 ip_addr,const u8 * eth_dst)1259*4882a593Smuzhiyun static int ofdpa_port_ipv4_neigh(struct ofdpa_port *ofdpa_port,
1260*4882a593Smuzhiyun int flags, __be32 ip_addr, const u8 *eth_dst)
1261*4882a593Smuzhiyun {
1262*4882a593Smuzhiyun struct ofdpa *ofdpa = ofdpa_port->ofdpa;
1263*4882a593Smuzhiyun struct ofdpa_neigh_tbl_entry *entry;
1264*4882a593Smuzhiyun struct ofdpa_neigh_tbl_entry *found;
1265*4882a593Smuzhiyun unsigned long lock_flags;
1266*4882a593Smuzhiyun __be16 eth_type = htons(ETH_P_IP);
1267*4882a593Smuzhiyun enum rocker_of_dpa_table_id goto_tbl =
1268*4882a593Smuzhiyun ROCKER_OF_DPA_TABLE_ID_ACL_POLICY;
1269*4882a593Smuzhiyun u32 group_id;
1270*4882a593Smuzhiyun u32 priority = 0;
1271*4882a593Smuzhiyun bool adding = !(flags & OFDPA_OP_FLAG_REMOVE);
1272*4882a593Smuzhiyun bool updating;
1273*4882a593Smuzhiyun bool removing;
1274*4882a593Smuzhiyun int err = 0;
1275*4882a593Smuzhiyun
1276*4882a593Smuzhiyun entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
1277*4882a593Smuzhiyun if (!entry)
1278*4882a593Smuzhiyun return -ENOMEM;
1279*4882a593Smuzhiyun
1280*4882a593Smuzhiyun spin_lock_irqsave(&ofdpa->neigh_tbl_lock, lock_flags);
1281*4882a593Smuzhiyun
1282*4882a593Smuzhiyun found = ofdpa_neigh_tbl_find(ofdpa, ip_addr);
1283*4882a593Smuzhiyun
1284*4882a593Smuzhiyun updating = found && adding;
1285*4882a593Smuzhiyun removing = found && !adding;
1286*4882a593Smuzhiyun adding = !found && adding;
1287*4882a593Smuzhiyun
1288*4882a593Smuzhiyun if (adding) {
1289*4882a593Smuzhiyun entry->ip_addr = ip_addr;
1290*4882a593Smuzhiyun entry->dev = ofdpa_port->dev;
1291*4882a593Smuzhiyun ether_addr_copy(entry->eth_dst, eth_dst);
1292*4882a593Smuzhiyun entry->ttl_check = true;
1293*4882a593Smuzhiyun ofdpa_neigh_add(ofdpa, entry);
1294*4882a593Smuzhiyun } else if (removing) {
1295*4882a593Smuzhiyun memcpy(entry, found, sizeof(*entry));
1296*4882a593Smuzhiyun ofdpa_neigh_del(found);
1297*4882a593Smuzhiyun } else if (updating) {
1298*4882a593Smuzhiyun ofdpa_neigh_update(found, eth_dst, true);
1299*4882a593Smuzhiyun memcpy(entry, found, sizeof(*entry));
1300*4882a593Smuzhiyun } else {
1301*4882a593Smuzhiyun err = -ENOENT;
1302*4882a593Smuzhiyun }
1303*4882a593Smuzhiyun
1304*4882a593Smuzhiyun spin_unlock_irqrestore(&ofdpa->neigh_tbl_lock, lock_flags);
1305*4882a593Smuzhiyun
1306*4882a593Smuzhiyun if (err)
1307*4882a593Smuzhiyun goto err_out;
1308*4882a593Smuzhiyun
1309*4882a593Smuzhiyun /* For each active neighbor, we have an L3 unicast group and
1310*4882a593Smuzhiyun * a /32 route to the neighbor, which uses the L3 unicast
1311*4882a593Smuzhiyun * group. The L3 unicast group can also be referred to by
1312*4882a593Smuzhiyun * other routes' nexthops.
1313*4882a593Smuzhiyun */
1314*4882a593Smuzhiyun
1315*4882a593Smuzhiyun err = ofdpa_group_l3_unicast(ofdpa_port, flags,
1316*4882a593Smuzhiyun entry->index,
1317*4882a593Smuzhiyun ofdpa_port->dev->dev_addr,
1318*4882a593Smuzhiyun entry->eth_dst,
1319*4882a593Smuzhiyun ofdpa_port->internal_vlan_id,
1320*4882a593Smuzhiyun entry->ttl_check,
1321*4882a593Smuzhiyun ofdpa_port->pport);
1322*4882a593Smuzhiyun if (err) {
1323*4882a593Smuzhiyun netdev_err(ofdpa_port->dev, "Error (%d) L3 unicast group index %d\n",
1324*4882a593Smuzhiyun err, entry->index);
1325*4882a593Smuzhiyun goto err_out;
1326*4882a593Smuzhiyun }
1327*4882a593Smuzhiyun
1328*4882a593Smuzhiyun if (adding || removing) {
1329*4882a593Smuzhiyun group_id = ROCKER_GROUP_L3_UNICAST(entry->index);
1330*4882a593Smuzhiyun err = ofdpa_flow_tbl_ucast4_routing(ofdpa_port,
1331*4882a593Smuzhiyun eth_type, ip_addr,
1332*4882a593Smuzhiyun inet_make_mask(32),
1333*4882a593Smuzhiyun priority, goto_tbl,
1334*4882a593Smuzhiyun group_id, NULL, flags);
1335*4882a593Smuzhiyun
1336*4882a593Smuzhiyun if (err)
1337*4882a593Smuzhiyun netdev_err(ofdpa_port->dev, "Error (%d) /32 unicast route %pI4 group 0x%08x\n",
1338*4882a593Smuzhiyun err, &entry->ip_addr, group_id);
1339*4882a593Smuzhiyun }
1340*4882a593Smuzhiyun
1341*4882a593Smuzhiyun err_out:
1342*4882a593Smuzhiyun if (!adding)
1343*4882a593Smuzhiyun kfree(entry);
1344*4882a593Smuzhiyun
1345*4882a593Smuzhiyun return err;
1346*4882a593Smuzhiyun }
1347*4882a593Smuzhiyun
ofdpa_port_ipv4_resolve(struct ofdpa_port * ofdpa_port,__be32 ip_addr)1348*4882a593Smuzhiyun static int ofdpa_port_ipv4_resolve(struct ofdpa_port *ofdpa_port,
1349*4882a593Smuzhiyun __be32 ip_addr)
1350*4882a593Smuzhiyun {
1351*4882a593Smuzhiyun struct net_device *dev = ofdpa_port->dev;
1352*4882a593Smuzhiyun struct neighbour *n = __ipv4_neigh_lookup(dev, (__force u32)ip_addr);
1353*4882a593Smuzhiyun int err = 0;
1354*4882a593Smuzhiyun
1355*4882a593Smuzhiyun if (!n) {
1356*4882a593Smuzhiyun n = neigh_create(&arp_tbl, &ip_addr, dev);
1357*4882a593Smuzhiyun if (IS_ERR(n))
1358*4882a593Smuzhiyun return PTR_ERR(n);
1359*4882a593Smuzhiyun }
1360*4882a593Smuzhiyun
1361*4882a593Smuzhiyun /* If the neigh is already resolved, then go ahead and
1362*4882a593Smuzhiyun * install the entry, otherwise start the ARP process to
1363*4882a593Smuzhiyun * resolve the neigh.
1364*4882a593Smuzhiyun */
1365*4882a593Smuzhiyun
1366*4882a593Smuzhiyun if (n->nud_state & NUD_VALID)
1367*4882a593Smuzhiyun err = ofdpa_port_ipv4_neigh(ofdpa_port, 0,
1368*4882a593Smuzhiyun ip_addr, n->ha);
1369*4882a593Smuzhiyun else
1370*4882a593Smuzhiyun neigh_event_send(n, NULL);
1371*4882a593Smuzhiyun
1372*4882a593Smuzhiyun neigh_release(n);
1373*4882a593Smuzhiyun return err;
1374*4882a593Smuzhiyun }
1375*4882a593Smuzhiyun
ofdpa_port_ipv4_nh(struct ofdpa_port * ofdpa_port,int flags,__be32 ip_addr,u32 * index)1376*4882a593Smuzhiyun static int ofdpa_port_ipv4_nh(struct ofdpa_port *ofdpa_port,
1377*4882a593Smuzhiyun int flags, __be32 ip_addr, u32 *index)
1378*4882a593Smuzhiyun {
1379*4882a593Smuzhiyun struct ofdpa *ofdpa = ofdpa_port->ofdpa;
1380*4882a593Smuzhiyun struct ofdpa_neigh_tbl_entry *entry;
1381*4882a593Smuzhiyun struct ofdpa_neigh_tbl_entry *found;
1382*4882a593Smuzhiyun unsigned long lock_flags;
1383*4882a593Smuzhiyun bool adding = !(flags & OFDPA_OP_FLAG_REMOVE);
1384*4882a593Smuzhiyun bool updating;
1385*4882a593Smuzhiyun bool removing;
1386*4882a593Smuzhiyun bool resolved = true;
1387*4882a593Smuzhiyun int err = 0;
1388*4882a593Smuzhiyun
1389*4882a593Smuzhiyun entry = kzalloc(sizeof(*entry), GFP_KERNEL);
1390*4882a593Smuzhiyun if (!entry)
1391*4882a593Smuzhiyun return -ENOMEM;
1392*4882a593Smuzhiyun
1393*4882a593Smuzhiyun spin_lock_irqsave(&ofdpa->neigh_tbl_lock, lock_flags);
1394*4882a593Smuzhiyun
1395*4882a593Smuzhiyun found = ofdpa_neigh_tbl_find(ofdpa, ip_addr);
1396*4882a593Smuzhiyun
1397*4882a593Smuzhiyun updating = found && adding;
1398*4882a593Smuzhiyun removing = found && !adding;
1399*4882a593Smuzhiyun adding = !found && adding;
1400*4882a593Smuzhiyun
1401*4882a593Smuzhiyun if (adding) {
1402*4882a593Smuzhiyun entry->ip_addr = ip_addr;
1403*4882a593Smuzhiyun entry->dev = ofdpa_port->dev;
1404*4882a593Smuzhiyun ofdpa_neigh_add(ofdpa, entry);
1405*4882a593Smuzhiyun *index = entry->index;
1406*4882a593Smuzhiyun resolved = false;
1407*4882a593Smuzhiyun } else if (removing) {
1408*4882a593Smuzhiyun *index = found->index;
1409*4882a593Smuzhiyun ofdpa_neigh_del(found);
1410*4882a593Smuzhiyun } else if (updating) {
1411*4882a593Smuzhiyun ofdpa_neigh_update(found, NULL, false);
1412*4882a593Smuzhiyun resolved = !is_zero_ether_addr(found->eth_dst);
1413*4882a593Smuzhiyun *index = found->index;
1414*4882a593Smuzhiyun } else {
1415*4882a593Smuzhiyun err = -ENOENT;
1416*4882a593Smuzhiyun }
1417*4882a593Smuzhiyun
1418*4882a593Smuzhiyun spin_unlock_irqrestore(&ofdpa->neigh_tbl_lock, lock_flags);
1419*4882a593Smuzhiyun
1420*4882a593Smuzhiyun if (!adding)
1421*4882a593Smuzhiyun kfree(entry);
1422*4882a593Smuzhiyun
1423*4882a593Smuzhiyun if (err)
1424*4882a593Smuzhiyun return err;
1425*4882a593Smuzhiyun
1426*4882a593Smuzhiyun /* Resolved means neigh ip_addr is resolved to neigh mac. */
1427*4882a593Smuzhiyun
1428*4882a593Smuzhiyun if (!resolved)
1429*4882a593Smuzhiyun err = ofdpa_port_ipv4_resolve(ofdpa_port, ip_addr);
1430*4882a593Smuzhiyun
1431*4882a593Smuzhiyun return err;
1432*4882a593Smuzhiyun }
1433*4882a593Smuzhiyun
ofdpa_port_get(const struct ofdpa * ofdpa,int port_index)1434*4882a593Smuzhiyun static struct ofdpa_port *ofdpa_port_get(const struct ofdpa *ofdpa,
1435*4882a593Smuzhiyun int port_index)
1436*4882a593Smuzhiyun {
1437*4882a593Smuzhiyun struct rocker_port *rocker_port;
1438*4882a593Smuzhiyun
1439*4882a593Smuzhiyun rocker_port = ofdpa->rocker->ports[port_index];
1440*4882a593Smuzhiyun return rocker_port ? rocker_port->wpriv : NULL;
1441*4882a593Smuzhiyun }
1442*4882a593Smuzhiyun
ofdpa_port_vlan_flood_group(struct ofdpa_port * ofdpa_port,int flags,__be16 vlan_id)1443*4882a593Smuzhiyun static int ofdpa_port_vlan_flood_group(struct ofdpa_port *ofdpa_port,
1444*4882a593Smuzhiyun int flags, __be16 vlan_id)
1445*4882a593Smuzhiyun {
1446*4882a593Smuzhiyun struct ofdpa_port *p;
1447*4882a593Smuzhiyun const struct ofdpa *ofdpa = ofdpa_port->ofdpa;
1448*4882a593Smuzhiyun unsigned int port_count = ofdpa->rocker->port_count;
1449*4882a593Smuzhiyun u32 group_id = ROCKER_GROUP_L2_FLOOD(vlan_id, 0);
1450*4882a593Smuzhiyun u32 *group_ids;
1451*4882a593Smuzhiyun u8 group_count = 0;
1452*4882a593Smuzhiyun int err = 0;
1453*4882a593Smuzhiyun int i;
1454*4882a593Smuzhiyun
1455*4882a593Smuzhiyun group_ids = kcalloc(port_count, sizeof(u32), GFP_KERNEL);
1456*4882a593Smuzhiyun if (!group_ids)
1457*4882a593Smuzhiyun return -ENOMEM;
1458*4882a593Smuzhiyun
1459*4882a593Smuzhiyun /* Adjust the flood group for this VLAN. The flood group
1460*4882a593Smuzhiyun * references an L2 interface group for each port in this
1461*4882a593Smuzhiyun * VLAN.
1462*4882a593Smuzhiyun */
1463*4882a593Smuzhiyun
1464*4882a593Smuzhiyun for (i = 0; i < port_count; i++) {
1465*4882a593Smuzhiyun p = ofdpa_port_get(ofdpa, i);
1466*4882a593Smuzhiyun if (!p)
1467*4882a593Smuzhiyun continue;
1468*4882a593Smuzhiyun if (!ofdpa_port_is_bridged(p))
1469*4882a593Smuzhiyun continue;
1470*4882a593Smuzhiyun if (test_bit(ntohs(vlan_id), p->vlan_bitmap)) {
1471*4882a593Smuzhiyun group_ids[group_count++] =
1472*4882a593Smuzhiyun ROCKER_GROUP_L2_INTERFACE(vlan_id, p->pport);
1473*4882a593Smuzhiyun }
1474*4882a593Smuzhiyun }
1475*4882a593Smuzhiyun
1476*4882a593Smuzhiyun /* If there are no bridged ports in this VLAN, we're done */
1477*4882a593Smuzhiyun if (group_count == 0)
1478*4882a593Smuzhiyun goto no_ports_in_vlan;
1479*4882a593Smuzhiyun
1480*4882a593Smuzhiyun err = ofdpa_group_l2_flood(ofdpa_port, flags, vlan_id,
1481*4882a593Smuzhiyun group_count, group_ids, group_id);
1482*4882a593Smuzhiyun if (err)
1483*4882a593Smuzhiyun netdev_err(ofdpa_port->dev, "Error (%d) port VLAN l2 flood group\n", err);
1484*4882a593Smuzhiyun
1485*4882a593Smuzhiyun no_ports_in_vlan:
1486*4882a593Smuzhiyun kfree(group_ids);
1487*4882a593Smuzhiyun return err;
1488*4882a593Smuzhiyun }
1489*4882a593Smuzhiyun
ofdpa_port_vlan_l2_groups(struct ofdpa_port * ofdpa_port,int flags,__be16 vlan_id,bool pop_vlan)1490*4882a593Smuzhiyun static int ofdpa_port_vlan_l2_groups(struct ofdpa_port *ofdpa_port, int flags,
1491*4882a593Smuzhiyun __be16 vlan_id, bool pop_vlan)
1492*4882a593Smuzhiyun {
1493*4882a593Smuzhiyun const struct ofdpa *ofdpa = ofdpa_port->ofdpa;
1494*4882a593Smuzhiyun unsigned int port_count = ofdpa->rocker->port_count;
1495*4882a593Smuzhiyun struct ofdpa_port *p;
1496*4882a593Smuzhiyun bool adding = !(flags & OFDPA_OP_FLAG_REMOVE);
1497*4882a593Smuzhiyun u32 out_pport;
1498*4882a593Smuzhiyun int ref = 0;
1499*4882a593Smuzhiyun int err;
1500*4882a593Smuzhiyun int i;
1501*4882a593Smuzhiyun
1502*4882a593Smuzhiyun /* An L2 interface group for this port in this VLAN, but
1503*4882a593Smuzhiyun * only when port STP state is LEARNING|FORWARDING.
1504*4882a593Smuzhiyun */
1505*4882a593Smuzhiyun
1506*4882a593Smuzhiyun if (ofdpa_port->stp_state == BR_STATE_LEARNING ||
1507*4882a593Smuzhiyun ofdpa_port->stp_state == BR_STATE_FORWARDING) {
1508*4882a593Smuzhiyun out_pport = ofdpa_port->pport;
1509*4882a593Smuzhiyun err = ofdpa_group_l2_interface(ofdpa_port, flags,
1510*4882a593Smuzhiyun vlan_id, out_pport, pop_vlan);
1511*4882a593Smuzhiyun if (err) {
1512*4882a593Smuzhiyun netdev_err(ofdpa_port->dev, "Error (%d) port VLAN l2 group for pport %d\n",
1513*4882a593Smuzhiyun err, out_pport);
1514*4882a593Smuzhiyun return err;
1515*4882a593Smuzhiyun }
1516*4882a593Smuzhiyun }
1517*4882a593Smuzhiyun
1518*4882a593Smuzhiyun /* An L2 interface group for this VLAN to CPU port.
1519*4882a593Smuzhiyun * Add when first port joins this VLAN and destroy when
1520*4882a593Smuzhiyun * last port leaves this VLAN.
1521*4882a593Smuzhiyun */
1522*4882a593Smuzhiyun
1523*4882a593Smuzhiyun for (i = 0; i < port_count; i++) {
1524*4882a593Smuzhiyun p = ofdpa_port_get(ofdpa, i);
1525*4882a593Smuzhiyun if (p && test_bit(ntohs(vlan_id), p->vlan_bitmap))
1526*4882a593Smuzhiyun ref++;
1527*4882a593Smuzhiyun }
1528*4882a593Smuzhiyun
1529*4882a593Smuzhiyun if ((!adding || ref != 1) && (adding || ref != 0))
1530*4882a593Smuzhiyun return 0;
1531*4882a593Smuzhiyun
1532*4882a593Smuzhiyun out_pport = 0;
1533*4882a593Smuzhiyun err = ofdpa_group_l2_interface(ofdpa_port, flags,
1534*4882a593Smuzhiyun vlan_id, out_pport, pop_vlan);
1535*4882a593Smuzhiyun if (err) {
1536*4882a593Smuzhiyun netdev_err(ofdpa_port->dev, "Error (%d) port VLAN l2 group for CPU port\n", err);
1537*4882a593Smuzhiyun return err;
1538*4882a593Smuzhiyun }
1539*4882a593Smuzhiyun
1540*4882a593Smuzhiyun return 0;
1541*4882a593Smuzhiyun }
1542*4882a593Smuzhiyun
1543*4882a593Smuzhiyun static struct ofdpa_ctrl {
1544*4882a593Smuzhiyun const u8 *eth_dst;
1545*4882a593Smuzhiyun const u8 *eth_dst_mask;
1546*4882a593Smuzhiyun __be16 eth_type;
1547*4882a593Smuzhiyun bool acl;
1548*4882a593Smuzhiyun bool bridge;
1549*4882a593Smuzhiyun bool term;
1550*4882a593Smuzhiyun bool copy_to_cpu;
1551*4882a593Smuzhiyun } ofdpa_ctrls[] = {
1552*4882a593Smuzhiyun [OFDPA_CTRL_LINK_LOCAL_MCAST] = {
1553*4882a593Smuzhiyun /* pass link local multicast pkts up to CPU for filtering */
1554*4882a593Smuzhiyun .eth_dst = ll_mac,
1555*4882a593Smuzhiyun .eth_dst_mask = ll_mask,
1556*4882a593Smuzhiyun .acl = true,
1557*4882a593Smuzhiyun },
1558*4882a593Smuzhiyun [OFDPA_CTRL_LOCAL_ARP] = {
1559*4882a593Smuzhiyun /* pass local ARP pkts up to CPU */
1560*4882a593Smuzhiyun .eth_dst = zero_mac,
1561*4882a593Smuzhiyun .eth_dst_mask = zero_mac,
1562*4882a593Smuzhiyun .eth_type = htons(ETH_P_ARP),
1563*4882a593Smuzhiyun .acl = true,
1564*4882a593Smuzhiyun },
1565*4882a593Smuzhiyun [OFDPA_CTRL_IPV4_MCAST] = {
1566*4882a593Smuzhiyun /* pass IPv4 mcast pkts up to CPU, RFC 1112 */
1567*4882a593Smuzhiyun .eth_dst = ipv4_mcast,
1568*4882a593Smuzhiyun .eth_dst_mask = ipv4_mask,
1569*4882a593Smuzhiyun .eth_type = htons(ETH_P_IP),
1570*4882a593Smuzhiyun .term = true,
1571*4882a593Smuzhiyun .copy_to_cpu = true,
1572*4882a593Smuzhiyun },
1573*4882a593Smuzhiyun [OFDPA_CTRL_IPV6_MCAST] = {
1574*4882a593Smuzhiyun /* pass IPv6 mcast pkts up to CPU, RFC 2464 */
1575*4882a593Smuzhiyun .eth_dst = ipv6_mcast,
1576*4882a593Smuzhiyun .eth_dst_mask = ipv6_mask,
1577*4882a593Smuzhiyun .eth_type = htons(ETH_P_IPV6),
1578*4882a593Smuzhiyun .term = true,
1579*4882a593Smuzhiyun .copy_to_cpu = true,
1580*4882a593Smuzhiyun },
1581*4882a593Smuzhiyun [OFDPA_CTRL_DFLT_BRIDGING] = {
1582*4882a593Smuzhiyun /* flood any pkts on vlan */
1583*4882a593Smuzhiyun .bridge = true,
1584*4882a593Smuzhiyun .copy_to_cpu = true,
1585*4882a593Smuzhiyun },
1586*4882a593Smuzhiyun [OFDPA_CTRL_DFLT_OVS] = {
1587*4882a593Smuzhiyun /* pass all pkts up to CPU */
1588*4882a593Smuzhiyun .eth_dst = zero_mac,
1589*4882a593Smuzhiyun .eth_dst_mask = zero_mac,
1590*4882a593Smuzhiyun .acl = true,
1591*4882a593Smuzhiyun },
1592*4882a593Smuzhiyun };
1593*4882a593Smuzhiyun
ofdpa_port_ctrl_vlan_acl(struct ofdpa_port * ofdpa_port,int flags,const struct ofdpa_ctrl * ctrl,__be16 vlan_id)1594*4882a593Smuzhiyun static int ofdpa_port_ctrl_vlan_acl(struct ofdpa_port *ofdpa_port, int flags,
1595*4882a593Smuzhiyun const struct ofdpa_ctrl *ctrl, __be16 vlan_id)
1596*4882a593Smuzhiyun {
1597*4882a593Smuzhiyun u32 in_pport = ofdpa_port->pport;
1598*4882a593Smuzhiyun u32 in_pport_mask = 0xffffffff;
1599*4882a593Smuzhiyun u32 out_pport = 0;
1600*4882a593Smuzhiyun const u8 *eth_src = NULL;
1601*4882a593Smuzhiyun const u8 *eth_src_mask = NULL;
1602*4882a593Smuzhiyun __be16 vlan_id_mask = htons(0xffff);
1603*4882a593Smuzhiyun u8 ip_proto = 0;
1604*4882a593Smuzhiyun u8 ip_proto_mask = 0;
1605*4882a593Smuzhiyun u8 ip_tos = 0;
1606*4882a593Smuzhiyun u8 ip_tos_mask = 0;
1607*4882a593Smuzhiyun u32 group_id = ROCKER_GROUP_L2_INTERFACE(vlan_id, out_pport);
1608*4882a593Smuzhiyun int err;
1609*4882a593Smuzhiyun
1610*4882a593Smuzhiyun err = ofdpa_flow_tbl_acl(ofdpa_port, flags,
1611*4882a593Smuzhiyun in_pport, in_pport_mask,
1612*4882a593Smuzhiyun eth_src, eth_src_mask,
1613*4882a593Smuzhiyun ctrl->eth_dst, ctrl->eth_dst_mask,
1614*4882a593Smuzhiyun ctrl->eth_type,
1615*4882a593Smuzhiyun vlan_id, vlan_id_mask,
1616*4882a593Smuzhiyun ip_proto, ip_proto_mask,
1617*4882a593Smuzhiyun ip_tos, ip_tos_mask,
1618*4882a593Smuzhiyun group_id);
1619*4882a593Smuzhiyun
1620*4882a593Smuzhiyun if (err)
1621*4882a593Smuzhiyun netdev_err(ofdpa_port->dev, "Error (%d) ctrl ACL\n", err);
1622*4882a593Smuzhiyun
1623*4882a593Smuzhiyun return err;
1624*4882a593Smuzhiyun }
1625*4882a593Smuzhiyun
ofdpa_port_ctrl_vlan_bridge(struct ofdpa_port * ofdpa_port,int flags,const struct ofdpa_ctrl * ctrl,__be16 vlan_id)1626*4882a593Smuzhiyun static int ofdpa_port_ctrl_vlan_bridge(struct ofdpa_port *ofdpa_port,
1627*4882a593Smuzhiyun int flags, const struct ofdpa_ctrl *ctrl,
1628*4882a593Smuzhiyun __be16 vlan_id)
1629*4882a593Smuzhiyun {
1630*4882a593Smuzhiyun enum rocker_of_dpa_table_id goto_tbl =
1631*4882a593Smuzhiyun ROCKER_OF_DPA_TABLE_ID_ACL_POLICY;
1632*4882a593Smuzhiyun u32 group_id = ROCKER_GROUP_L2_FLOOD(vlan_id, 0);
1633*4882a593Smuzhiyun u32 tunnel_id = 0;
1634*4882a593Smuzhiyun int err;
1635*4882a593Smuzhiyun
1636*4882a593Smuzhiyun if (!ofdpa_port_is_bridged(ofdpa_port))
1637*4882a593Smuzhiyun return 0;
1638*4882a593Smuzhiyun
1639*4882a593Smuzhiyun err = ofdpa_flow_tbl_bridge(ofdpa_port, flags,
1640*4882a593Smuzhiyun ctrl->eth_dst, ctrl->eth_dst_mask,
1641*4882a593Smuzhiyun vlan_id, tunnel_id,
1642*4882a593Smuzhiyun goto_tbl, group_id, ctrl->copy_to_cpu);
1643*4882a593Smuzhiyun
1644*4882a593Smuzhiyun if (err)
1645*4882a593Smuzhiyun netdev_err(ofdpa_port->dev, "Error (%d) ctrl FLOOD\n", err);
1646*4882a593Smuzhiyun
1647*4882a593Smuzhiyun return err;
1648*4882a593Smuzhiyun }
1649*4882a593Smuzhiyun
ofdpa_port_ctrl_vlan_term(struct ofdpa_port * ofdpa_port,int flags,const struct ofdpa_ctrl * ctrl,__be16 vlan_id)1650*4882a593Smuzhiyun static int ofdpa_port_ctrl_vlan_term(struct ofdpa_port *ofdpa_port, int flags,
1651*4882a593Smuzhiyun const struct ofdpa_ctrl *ctrl, __be16 vlan_id)
1652*4882a593Smuzhiyun {
1653*4882a593Smuzhiyun u32 in_pport_mask = 0xffffffff;
1654*4882a593Smuzhiyun __be16 vlan_id_mask = htons(0xffff);
1655*4882a593Smuzhiyun int err;
1656*4882a593Smuzhiyun
1657*4882a593Smuzhiyun if (ntohs(vlan_id) == 0)
1658*4882a593Smuzhiyun vlan_id = ofdpa_port->internal_vlan_id;
1659*4882a593Smuzhiyun
1660*4882a593Smuzhiyun err = ofdpa_flow_tbl_term_mac(ofdpa_port, ofdpa_port->pport, in_pport_mask,
1661*4882a593Smuzhiyun ctrl->eth_type, ctrl->eth_dst,
1662*4882a593Smuzhiyun ctrl->eth_dst_mask, vlan_id,
1663*4882a593Smuzhiyun vlan_id_mask, ctrl->copy_to_cpu,
1664*4882a593Smuzhiyun flags);
1665*4882a593Smuzhiyun
1666*4882a593Smuzhiyun if (err)
1667*4882a593Smuzhiyun netdev_err(ofdpa_port->dev, "Error (%d) ctrl term\n", err);
1668*4882a593Smuzhiyun
1669*4882a593Smuzhiyun return err;
1670*4882a593Smuzhiyun }
1671*4882a593Smuzhiyun
ofdpa_port_ctrl_vlan(struct ofdpa_port * ofdpa_port,int flags,const struct ofdpa_ctrl * ctrl,__be16 vlan_id)1672*4882a593Smuzhiyun static int ofdpa_port_ctrl_vlan(struct ofdpa_port *ofdpa_port, int flags,
1673*4882a593Smuzhiyun const struct ofdpa_ctrl *ctrl, __be16 vlan_id)
1674*4882a593Smuzhiyun {
1675*4882a593Smuzhiyun if (ctrl->acl)
1676*4882a593Smuzhiyun return ofdpa_port_ctrl_vlan_acl(ofdpa_port, flags,
1677*4882a593Smuzhiyun ctrl, vlan_id);
1678*4882a593Smuzhiyun if (ctrl->bridge)
1679*4882a593Smuzhiyun return ofdpa_port_ctrl_vlan_bridge(ofdpa_port, flags,
1680*4882a593Smuzhiyun ctrl, vlan_id);
1681*4882a593Smuzhiyun
1682*4882a593Smuzhiyun if (ctrl->term)
1683*4882a593Smuzhiyun return ofdpa_port_ctrl_vlan_term(ofdpa_port, flags,
1684*4882a593Smuzhiyun ctrl, vlan_id);
1685*4882a593Smuzhiyun
1686*4882a593Smuzhiyun return -EOPNOTSUPP;
1687*4882a593Smuzhiyun }
1688*4882a593Smuzhiyun
ofdpa_port_ctrl_vlan_add(struct ofdpa_port * ofdpa_port,int flags,__be16 vlan_id)1689*4882a593Smuzhiyun static int ofdpa_port_ctrl_vlan_add(struct ofdpa_port *ofdpa_port, int flags,
1690*4882a593Smuzhiyun __be16 vlan_id)
1691*4882a593Smuzhiyun {
1692*4882a593Smuzhiyun int err = 0;
1693*4882a593Smuzhiyun int i;
1694*4882a593Smuzhiyun
1695*4882a593Smuzhiyun for (i = 0; i < OFDPA_CTRL_MAX; i++) {
1696*4882a593Smuzhiyun if (ofdpa_port->ctrls[i]) {
1697*4882a593Smuzhiyun err = ofdpa_port_ctrl_vlan(ofdpa_port, flags,
1698*4882a593Smuzhiyun &ofdpa_ctrls[i], vlan_id);
1699*4882a593Smuzhiyun if (err)
1700*4882a593Smuzhiyun return err;
1701*4882a593Smuzhiyun }
1702*4882a593Smuzhiyun }
1703*4882a593Smuzhiyun
1704*4882a593Smuzhiyun return err;
1705*4882a593Smuzhiyun }
1706*4882a593Smuzhiyun
ofdpa_port_ctrl(struct ofdpa_port * ofdpa_port,int flags,const struct ofdpa_ctrl * ctrl)1707*4882a593Smuzhiyun static int ofdpa_port_ctrl(struct ofdpa_port *ofdpa_port, int flags,
1708*4882a593Smuzhiyun const struct ofdpa_ctrl *ctrl)
1709*4882a593Smuzhiyun {
1710*4882a593Smuzhiyun u16 vid;
1711*4882a593Smuzhiyun int err = 0;
1712*4882a593Smuzhiyun
1713*4882a593Smuzhiyun for (vid = 1; vid < VLAN_N_VID; vid++) {
1714*4882a593Smuzhiyun if (!test_bit(vid, ofdpa_port->vlan_bitmap))
1715*4882a593Smuzhiyun continue;
1716*4882a593Smuzhiyun err = ofdpa_port_ctrl_vlan(ofdpa_port, flags,
1717*4882a593Smuzhiyun ctrl, htons(vid));
1718*4882a593Smuzhiyun if (err)
1719*4882a593Smuzhiyun break;
1720*4882a593Smuzhiyun }
1721*4882a593Smuzhiyun
1722*4882a593Smuzhiyun return err;
1723*4882a593Smuzhiyun }
1724*4882a593Smuzhiyun
ofdpa_port_vlan(struct ofdpa_port * ofdpa_port,int flags,u16 vid)1725*4882a593Smuzhiyun static int ofdpa_port_vlan(struct ofdpa_port *ofdpa_port, int flags,
1726*4882a593Smuzhiyun u16 vid)
1727*4882a593Smuzhiyun {
1728*4882a593Smuzhiyun enum rocker_of_dpa_table_id goto_tbl =
1729*4882a593Smuzhiyun ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC;
1730*4882a593Smuzhiyun u32 in_pport = ofdpa_port->pport;
1731*4882a593Smuzhiyun __be16 vlan_id = htons(vid);
1732*4882a593Smuzhiyun __be16 vlan_id_mask = htons(0xffff);
1733*4882a593Smuzhiyun __be16 internal_vlan_id;
1734*4882a593Smuzhiyun bool untagged;
1735*4882a593Smuzhiyun bool adding = !(flags & OFDPA_OP_FLAG_REMOVE);
1736*4882a593Smuzhiyun int err;
1737*4882a593Smuzhiyun
1738*4882a593Smuzhiyun internal_vlan_id = ofdpa_port_vid_to_vlan(ofdpa_port, vid, &untagged);
1739*4882a593Smuzhiyun
1740*4882a593Smuzhiyun if (adding &&
1741*4882a593Smuzhiyun test_bit(ntohs(internal_vlan_id), ofdpa_port->vlan_bitmap))
1742*4882a593Smuzhiyun return 0; /* already added */
1743*4882a593Smuzhiyun else if (!adding &&
1744*4882a593Smuzhiyun !test_bit(ntohs(internal_vlan_id), ofdpa_port->vlan_bitmap))
1745*4882a593Smuzhiyun return 0; /* already removed */
1746*4882a593Smuzhiyun
1747*4882a593Smuzhiyun change_bit(ntohs(internal_vlan_id), ofdpa_port->vlan_bitmap);
1748*4882a593Smuzhiyun
1749*4882a593Smuzhiyun if (adding) {
1750*4882a593Smuzhiyun err = ofdpa_port_ctrl_vlan_add(ofdpa_port, flags,
1751*4882a593Smuzhiyun internal_vlan_id);
1752*4882a593Smuzhiyun if (err) {
1753*4882a593Smuzhiyun netdev_err(ofdpa_port->dev, "Error (%d) port ctrl vlan add\n", err);
1754*4882a593Smuzhiyun goto err_vlan_add;
1755*4882a593Smuzhiyun }
1756*4882a593Smuzhiyun }
1757*4882a593Smuzhiyun
1758*4882a593Smuzhiyun err = ofdpa_port_vlan_l2_groups(ofdpa_port, flags,
1759*4882a593Smuzhiyun internal_vlan_id, untagged);
1760*4882a593Smuzhiyun if (err) {
1761*4882a593Smuzhiyun netdev_err(ofdpa_port->dev, "Error (%d) port VLAN l2 groups\n", err);
1762*4882a593Smuzhiyun goto err_vlan_l2_groups;
1763*4882a593Smuzhiyun }
1764*4882a593Smuzhiyun
1765*4882a593Smuzhiyun err = ofdpa_port_vlan_flood_group(ofdpa_port, flags,
1766*4882a593Smuzhiyun internal_vlan_id);
1767*4882a593Smuzhiyun if (err) {
1768*4882a593Smuzhiyun netdev_err(ofdpa_port->dev, "Error (%d) port VLAN l2 flood group\n", err);
1769*4882a593Smuzhiyun goto err_flood_group;
1770*4882a593Smuzhiyun }
1771*4882a593Smuzhiyun
1772*4882a593Smuzhiyun err = ofdpa_flow_tbl_vlan(ofdpa_port, flags,
1773*4882a593Smuzhiyun in_pport, vlan_id, vlan_id_mask,
1774*4882a593Smuzhiyun goto_tbl, untagged, internal_vlan_id);
1775*4882a593Smuzhiyun if (err)
1776*4882a593Smuzhiyun netdev_err(ofdpa_port->dev, "Error (%d) port VLAN table\n", err);
1777*4882a593Smuzhiyun
1778*4882a593Smuzhiyun return 0;
1779*4882a593Smuzhiyun
1780*4882a593Smuzhiyun err_vlan_add:
1781*4882a593Smuzhiyun err_vlan_l2_groups:
1782*4882a593Smuzhiyun err_flood_group:
1783*4882a593Smuzhiyun change_bit(ntohs(internal_vlan_id), ofdpa_port->vlan_bitmap);
1784*4882a593Smuzhiyun return err;
1785*4882a593Smuzhiyun }
1786*4882a593Smuzhiyun
ofdpa_port_ig_tbl(struct ofdpa_port * ofdpa_port,int flags)1787*4882a593Smuzhiyun static int ofdpa_port_ig_tbl(struct ofdpa_port *ofdpa_port, int flags)
1788*4882a593Smuzhiyun {
1789*4882a593Smuzhiyun enum rocker_of_dpa_table_id goto_tbl;
1790*4882a593Smuzhiyun u32 in_pport;
1791*4882a593Smuzhiyun u32 in_pport_mask;
1792*4882a593Smuzhiyun int err;
1793*4882a593Smuzhiyun
1794*4882a593Smuzhiyun /* Normal Ethernet Frames. Matches pkts from any local physical
1795*4882a593Smuzhiyun * ports. Goto VLAN tbl.
1796*4882a593Smuzhiyun */
1797*4882a593Smuzhiyun
1798*4882a593Smuzhiyun in_pport = 0;
1799*4882a593Smuzhiyun in_pport_mask = 0xffff0000;
1800*4882a593Smuzhiyun goto_tbl = ROCKER_OF_DPA_TABLE_ID_VLAN;
1801*4882a593Smuzhiyun
1802*4882a593Smuzhiyun err = ofdpa_flow_tbl_ig_port(ofdpa_port, flags,
1803*4882a593Smuzhiyun in_pport, in_pport_mask,
1804*4882a593Smuzhiyun goto_tbl);
1805*4882a593Smuzhiyun if (err)
1806*4882a593Smuzhiyun netdev_err(ofdpa_port->dev, "Error (%d) ingress port table entry\n", err);
1807*4882a593Smuzhiyun
1808*4882a593Smuzhiyun return err;
1809*4882a593Smuzhiyun }
1810*4882a593Smuzhiyun
1811*4882a593Smuzhiyun struct ofdpa_fdb_learn_work {
1812*4882a593Smuzhiyun struct work_struct work;
1813*4882a593Smuzhiyun struct ofdpa_port *ofdpa_port;
1814*4882a593Smuzhiyun int flags;
1815*4882a593Smuzhiyun u8 addr[ETH_ALEN];
1816*4882a593Smuzhiyun u16 vid;
1817*4882a593Smuzhiyun };
1818*4882a593Smuzhiyun
ofdpa_port_fdb_learn_work(struct work_struct * work)1819*4882a593Smuzhiyun static void ofdpa_port_fdb_learn_work(struct work_struct *work)
1820*4882a593Smuzhiyun {
1821*4882a593Smuzhiyun const struct ofdpa_fdb_learn_work *lw =
1822*4882a593Smuzhiyun container_of(work, struct ofdpa_fdb_learn_work, work);
1823*4882a593Smuzhiyun bool removing = (lw->flags & OFDPA_OP_FLAG_REMOVE);
1824*4882a593Smuzhiyun bool learned = (lw->flags & OFDPA_OP_FLAG_LEARNED);
1825*4882a593Smuzhiyun struct switchdev_notifier_fdb_info info;
1826*4882a593Smuzhiyun
1827*4882a593Smuzhiyun info.addr = lw->addr;
1828*4882a593Smuzhiyun info.vid = lw->vid;
1829*4882a593Smuzhiyun
1830*4882a593Smuzhiyun rtnl_lock();
1831*4882a593Smuzhiyun if (learned && removing)
1832*4882a593Smuzhiyun call_switchdev_notifiers(SWITCHDEV_FDB_DEL_TO_BRIDGE,
1833*4882a593Smuzhiyun lw->ofdpa_port->dev, &info.info, NULL);
1834*4882a593Smuzhiyun else if (learned && !removing)
1835*4882a593Smuzhiyun call_switchdev_notifiers(SWITCHDEV_FDB_ADD_TO_BRIDGE,
1836*4882a593Smuzhiyun lw->ofdpa_port->dev, &info.info, NULL);
1837*4882a593Smuzhiyun rtnl_unlock();
1838*4882a593Smuzhiyun
1839*4882a593Smuzhiyun kfree(work);
1840*4882a593Smuzhiyun }
1841*4882a593Smuzhiyun
ofdpa_port_fdb_learn(struct ofdpa_port * ofdpa_port,int flags,const u8 * addr,__be16 vlan_id)1842*4882a593Smuzhiyun static int ofdpa_port_fdb_learn(struct ofdpa_port *ofdpa_port,
1843*4882a593Smuzhiyun int flags, const u8 *addr, __be16 vlan_id)
1844*4882a593Smuzhiyun {
1845*4882a593Smuzhiyun struct ofdpa_fdb_learn_work *lw;
1846*4882a593Smuzhiyun enum rocker_of_dpa_table_id goto_tbl =
1847*4882a593Smuzhiyun ROCKER_OF_DPA_TABLE_ID_ACL_POLICY;
1848*4882a593Smuzhiyun u32 out_pport = ofdpa_port->pport;
1849*4882a593Smuzhiyun u32 tunnel_id = 0;
1850*4882a593Smuzhiyun u32 group_id = ROCKER_GROUP_NONE;
1851*4882a593Smuzhiyun bool copy_to_cpu = false;
1852*4882a593Smuzhiyun int err;
1853*4882a593Smuzhiyun
1854*4882a593Smuzhiyun if (ofdpa_port_is_bridged(ofdpa_port))
1855*4882a593Smuzhiyun group_id = ROCKER_GROUP_L2_INTERFACE(vlan_id, out_pport);
1856*4882a593Smuzhiyun
1857*4882a593Smuzhiyun if (!(flags & OFDPA_OP_FLAG_REFRESH)) {
1858*4882a593Smuzhiyun err = ofdpa_flow_tbl_bridge(ofdpa_port, flags, addr,
1859*4882a593Smuzhiyun NULL, vlan_id, tunnel_id, goto_tbl,
1860*4882a593Smuzhiyun group_id, copy_to_cpu);
1861*4882a593Smuzhiyun if (err)
1862*4882a593Smuzhiyun return err;
1863*4882a593Smuzhiyun }
1864*4882a593Smuzhiyun
1865*4882a593Smuzhiyun if (!ofdpa_port_is_bridged(ofdpa_port))
1866*4882a593Smuzhiyun return 0;
1867*4882a593Smuzhiyun
1868*4882a593Smuzhiyun lw = kzalloc(sizeof(*lw), GFP_ATOMIC);
1869*4882a593Smuzhiyun if (!lw)
1870*4882a593Smuzhiyun return -ENOMEM;
1871*4882a593Smuzhiyun
1872*4882a593Smuzhiyun INIT_WORK(&lw->work, ofdpa_port_fdb_learn_work);
1873*4882a593Smuzhiyun
1874*4882a593Smuzhiyun lw->ofdpa_port = ofdpa_port;
1875*4882a593Smuzhiyun lw->flags = flags;
1876*4882a593Smuzhiyun ether_addr_copy(lw->addr, addr);
1877*4882a593Smuzhiyun lw->vid = ofdpa_port_vlan_to_vid(ofdpa_port, vlan_id);
1878*4882a593Smuzhiyun
1879*4882a593Smuzhiyun schedule_work(&lw->work);
1880*4882a593Smuzhiyun return 0;
1881*4882a593Smuzhiyun }
1882*4882a593Smuzhiyun
1883*4882a593Smuzhiyun static struct ofdpa_fdb_tbl_entry *
ofdpa_fdb_tbl_find(const struct ofdpa * ofdpa,const struct ofdpa_fdb_tbl_entry * match)1884*4882a593Smuzhiyun ofdpa_fdb_tbl_find(const struct ofdpa *ofdpa,
1885*4882a593Smuzhiyun const struct ofdpa_fdb_tbl_entry *match)
1886*4882a593Smuzhiyun {
1887*4882a593Smuzhiyun struct ofdpa_fdb_tbl_entry *found;
1888*4882a593Smuzhiyun
1889*4882a593Smuzhiyun hash_for_each_possible(ofdpa->fdb_tbl, found, entry, match->key_crc32)
1890*4882a593Smuzhiyun if (memcmp(&found->key, &match->key, sizeof(found->key)) == 0)
1891*4882a593Smuzhiyun return found;
1892*4882a593Smuzhiyun
1893*4882a593Smuzhiyun return NULL;
1894*4882a593Smuzhiyun }
1895*4882a593Smuzhiyun
ofdpa_port_fdb(struct ofdpa_port * ofdpa_port,const unsigned char * addr,__be16 vlan_id,int flags)1896*4882a593Smuzhiyun static int ofdpa_port_fdb(struct ofdpa_port *ofdpa_port,
1897*4882a593Smuzhiyun const unsigned char *addr,
1898*4882a593Smuzhiyun __be16 vlan_id, int flags)
1899*4882a593Smuzhiyun {
1900*4882a593Smuzhiyun struct ofdpa *ofdpa = ofdpa_port->ofdpa;
1901*4882a593Smuzhiyun struct ofdpa_fdb_tbl_entry *fdb;
1902*4882a593Smuzhiyun struct ofdpa_fdb_tbl_entry *found;
1903*4882a593Smuzhiyun bool removing = (flags & OFDPA_OP_FLAG_REMOVE);
1904*4882a593Smuzhiyun unsigned long lock_flags;
1905*4882a593Smuzhiyun
1906*4882a593Smuzhiyun fdb = kzalloc(sizeof(*fdb), GFP_KERNEL);
1907*4882a593Smuzhiyun if (!fdb)
1908*4882a593Smuzhiyun return -ENOMEM;
1909*4882a593Smuzhiyun
1910*4882a593Smuzhiyun fdb->learned = (flags & OFDPA_OP_FLAG_LEARNED);
1911*4882a593Smuzhiyun fdb->touched = jiffies;
1912*4882a593Smuzhiyun fdb->key.ofdpa_port = ofdpa_port;
1913*4882a593Smuzhiyun ether_addr_copy(fdb->key.addr, addr);
1914*4882a593Smuzhiyun fdb->key.vlan_id = vlan_id;
1915*4882a593Smuzhiyun fdb->key_crc32 = crc32(~0, &fdb->key, sizeof(fdb->key));
1916*4882a593Smuzhiyun
1917*4882a593Smuzhiyun spin_lock_irqsave(&ofdpa->fdb_tbl_lock, lock_flags);
1918*4882a593Smuzhiyun
1919*4882a593Smuzhiyun found = ofdpa_fdb_tbl_find(ofdpa, fdb);
1920*4882a593Smuzhiyun
1921*4882a593Smuzhiyun if (found) {
1922*4882a593Smuzhiyun found->touched = jiffies;
1923*4882a593Smuzhiyun if (removing) {
1924*4882a593Smuzhiyun kfree(fdb);
1925*4882a593Smuzhiyun hash_del(&found->entry);
1926*4882a593Smuzhiyun }
1927*4882a593Smuzhiyun } else if (!removing) {
1928*4882a593Smuzhiyun hash_add(ofdpa->fdb_tbl, &fdb->entry,
1929*4882a593Smuzhiyun fdb->key_crc32);
1930*4882a593Smuzhiyun }
1931*4882a593Smuzhiyun
1932*4882a593Smuzhiyun spin_unlock_irqrestore(&ofdpa->fdb_tbl_lock, lock_flags);
1933*4882a593Smuzhiyun
1934*4882a593Smuzhiyun /* Check if adding and already exists, or removing and can't find */
1935*4882a593Smuzhiyun if (!found != !removing) {
1936*4882a593Smuzhiyun kfree(fdb);
1937*4882a593Smuzhiyun if (!found && removing)
1938*4882a593Smuzhiyun return 0;
1939*4882a593Smuzhiyun /* Refreshing existing to update aging timers */
1940*4882a593Smuzhiyun flags |= OFDPA_OP_FLAG_REFRESH;
1941*4882a593Smuzhiyun }
1942*4882a593Smuzhiyun
1943*4882a593Smuzhiyun return ofdpa_port_fdb_learn(ofdpa_port, flags, addr, vlan_id);
1944*4882a593Smuzhiyun }
1945*4882a593Smuzhiyun
ofdpa_port_fdb_flush(struct ofdpa_port * ofdpa_port,int flags)1946*4882a593Smuzhiyun static int ofdpa_port_fdb_flush(struct ofdpa_port *ofdpa_port, int flags)
1947*4882a593Smuzhiyun {
1948*4882a593Smuzhiyun struct ofdpa *ofdpa = ofdpa_port->ofdpa;
1949*4882a593Smuzhiyun struct ofdpa_fdb_tbl_entry *found;
1950*4882a593Smuzhiyun unsigned long lock_flags;
1951*4882a593Smuzhiyun struct hlist_node *tmp;
1952*4882a593Smuzhiyun int bkt;
1953*4882a593Smuzhiyun int err = 0;
1954*4882a593Smuzhiyun
1955*4882a593Smuzhiyun if (ofdpa_port->stp_state == BR_STATE_LEARNING ||
1956*4882a593Smuzhiyun ofdpa_port->stp_state == BR_STATE_FORWARDING)
1957*4882a593Smuzhiyun return 0;
1958*4882a593Smuzhiyun
1959*4882a593Smuzhiyun flags |= OFDPA_OP_FLAG_NOWAIT | OFDPA_OP_FLAG_REMOVE;
1960*4882a593Smuzhiyun
1961*4882a593Smuzhiyun spin_lock_irqsave(&ofdpa->fdb_tbl_lock, lock_flags);
1962*4882a593Smuzhiyun
1963*4882a593Smuzhiyun hash_for_each_safe(ofdpa->fdb_tbl, bkt, tmp, found, entry) {
1964*4882a593Smuzhiyun if (found->key.ofdpa_port != ofdpa_port)
1965*4882a593Smuzhiyun continue;
1966*4882a593Smuzhiyun if (!found->learned)
1967*4882a593Smuzhiyun continue;
1968*4882a593Smuzhiyun err = ofdpa_port_fdb_learn(ofdpa_port, flags,
1969*4882a593Smuzhiyun found->key.addr,
1970*4882a593Smuzhiyun found->key.vlan_id);
1971*4882a593Smuzhiyun if (err)
1972*4882a593Smuzhiyun goto err_out;
1973*4882a593Smuzhiyun hash_del(&found->entry);
1974*4882a593Smuzhiyun }
1975*4882a593Smuzhiyun
1976*4882a593Smuzhiyun err_out:
1977*4882a593Smuzhiyun spin_unlock_irqrestore(&ofdpa->fdb_tbl_lock, lock_flags);
1978*4882a593Smuzhiyun
1979*4882a593Smuzhiyun return err;
1980*4882a593Smuzhiyun }
1981*4882a593Smuzhiyun
ofdpa_fdb_cleanup(struct timer_list * t)1982*4882a593Smuzhiyun static void ofdpa_fdb_cleanup(struct timer_list *t)
1983*4882a593Smuzhiyun {
1984*4882a593Smuzhiyun struct ofdpa *ofdpa = from_timer(ofdpa, t, fdb_cleanup_timer);
1985*4882a593Smuzhiyun struct ofdpa_port *ofdpa_port;
1986*4882a593Smuzhiyun struct ofdpa_fdb_tbl_entry *entry;
1987*4882a593Smuzhiyun struct hlist_node *tmp;
1988*4882a593Smuzhiyun unsigned long next_timer = jiffies + ofdpa->ageing_time;
1989*4882a593Smuzhiyun unsigned long expires;
1990*4882a593Smuzhiyun unsigned long lock_flags;
1991*4882a593Smuzhiyun int flags = OFDPA_OP_FLAG_NOWAIT | OFDPA_OP_FLAG_REMOVE |
1992*4882a593Smuzhiyun OFDPA_OP_FLAG_LEARNED;
1993*4882a593Smuzhiyun int bkt;
1994*4882a593Smuzhiyun
1995*4882a593Smuzhiyun spin_lock_irqsave(&ofdpa->fdb_tbl_lock, lock_flags);
1996*4882a593Smuzhiyun
1997*4882a593Smuzhiyun hash_for_each_safe(ofdpa->fdb_tbl, bkt, tmp, entry, entry) {
1998*4882a593Smuzhiyun if (!entry->learned)
1999*4882a593Smuzhiyun continue;
2000*4882a593Smuzhiyun ofdpa_port = entry->key.ofdpa_port;
2001*4882a593Smuzhiyun expires = entry->touched + ofdpa_port->ageing_time;
2002*4882a593Smuzhiyun if (time_before_eq(expires, jiffies)) {
2003*4882a593Smuzhiyun ofdpa_port_fdb_learn(ofdpa_port, flags,
2004*4882a593Smuzhiyun entry->key.addr,
2005*4882a593Smuzhiyun entry->key.vlan_id);
2006*4882a593Smuzhiyun hash_del(&entry->entry);
2007*4882a593Smuzhiyun } else if (time_before(expires, next_timer)) {
2008*4882a593Smuzhiyun next_timer = expires;
2009*4882a593Smuzhiyun }
2010*4882a593Smuzhiyun }
2011*4882a593Smuzhiyun
2012*4882a593Smuzhiyun spin_unlock_irqrestore(&ofdpa->fdb_tbl_lock, lock_flags);
2013*4882a593Smuzhiyun
2014*4882a593Smuzhiyun mod_timer(&ofdpa->fdb_cleanup_timer, round_jiffies_up(next_timer));
2015*4882a593Smuzhiyun }
2016*4882a593Smuzhiyun
ofdpa_port_router_mac(struct ofdpa_port * ofdpa_port,int flags,__be16 vlan_id)2017*4882a593Smuzhiyun static int ofdpa_port_router_mac(struct ofdpa_port *ofdpa_port,
2018*4882a593Smuzhiyun int flags, __be16 vlan_id)
2019*4882a593Smuzhiyun {
2020*4882a593Smuzhiyun u32 in_pport_mask = 0xffffffff;
2021*4882a593Smuzhiyun __be16 eth_type;
2022*4882a593Smuzhiyun const u8 *dst_mac_mask = ff_mac;
2023*4882a593Smuzhiyun __be16 vlan_id_mask = htons(0xffff);
2024*4882a593Smuzhiyun bool copy_to_cpu = false;
2025*4882a593Smuzhiyun int err;
2026*4882a593Smuzhiyun
2027*4882a593Smuzhiyun if (ntohs(vlan_id) == 0)
2028*4882a593Smuzhiyun vlan_id = ofdpa_port->internal_vlan_id;
2029*4882a593Smuzhiyun
2030*4882a593Smuzhiyun eth_type = htons(ETH_P_IP);
2031*4882a593Smuzhiyun err = ofdpa_flow_tbl_term_mac(ofdpa_port, ofdpa_port->pport,
2032*4882a593Smuzhiyun in_pport_mask, eth_type,
2033*4882a593Smuzhiyun ofdpa_port->dev->dev_addr,
2034*4882a593Smuzhiyun dst_mac_mask, vlan_id, vlan_id_mask,
2035*4882a593Smuzhiyun copy_to_cpu, flags);
2036*4882a593Smuzhiyun if (err)
2037*4882a593Smuzhiyun return err;
2038*4882a593Smuzhiyun
2039*4882a593Smuzhiyun eth_type = htons(ETH_P_IPV6);
2040*4882a593Smuzhiyun err = ofdpa_flow_tbl_term_mac(ofdpa_port, ofdpa_port->pport,
2041*4882a593Smuzhiyun in_pport_mask, eth_type,
2042*4882a593Smuzhiyun ofdpa_port->dev->dev_addr,
2043*4882a593Smuzhiyun dst_mac_mask, vlan_id, vlan_id_mask,
2044*4882a593Smuzhiyun copy_to_cpu, flags);
2045*4882a593Smuzhiyun
2046*4882a593Smuzhiyun return err;
2047*4882a593Smuzhiyun }
2048*4882a593Smuzhiyun
ofdpa_port_fwding(struct ofdpa_port * ofdpa_port,int flags)2049*4882a593Smuzhiyun static int ofdpa_port_fwding(struct ofdpa_port *ofdpa_port, int flags)
2050*4882a593Smuzhiyun {
2051*4882a593Smuzhiyun bool pop_vlan;
2052*4882a593Smuzhiyun u32 out_pport;
2053*4882a593Smuzhiyun __be16 vlan_id;
2054*4882a593Smuzhiyun u16 vid;
2055*4882a593Smuzhiyun int err;
2056*4882a593Smuzhiyun
2057*4882a593Smuzhiyun /* Port will be forwarding-enabled if its STP state is LEARNING
2058*4882a593Smuzhiyun * or FORWARDING. Traffic from CPU can still egress, regardless of
2059*4882a593Smuzhiyun * port STP state. Use L2 interface group on port VLANs as a way
2060*4882a593Smuzhiyun * to toggle port forwarding: if forwarding is disabled, L2
2061*4882a593Smuzhiyun * interface group will not exist.
2062*4882a593Smuzhiyun */
2063*4882a593Smuzhiyun
2064*4882a593Smuzhiyun if (ofdpa_port->stp_state != BR_STATE_LEARNING &&
2065*4882a593Smuzhiyun ofdpa_port->stp_state != BR_STATE_FORWARDING)
2066*4882a593Smuzhiyun flags |= OFDPA_OP_FLAG_REMOVE;
2067*4882a593Smuzhiyun
2068*4882a593Smuzhiyun out_pport = ofdpa_port->pport;
2069*4882a593Smuzhiyun for (vid = 1; vid < VLAN_N_VID; vid++) {
2070*4882a593Smuzhiyun if (!test_bit(vid, ofdpa_port->vlan_bitmap))
2071*4882a593Smuzhiyun continue;
2072*4882a593Smuzhiyun vlan_id = htons(vid);
2073*4882a593Smuzhiyun pop_vlan = ofdpa_vlan_id_is_internal(vlan_id);
2074*4882a593Smuzhiyun err = ofdpa_group_l2_interface(ofdpa_port, flags,
2075*4882a593Smuzhiyun vlan_id, out_pport, pop_vlan);
2076*4882a593Smuzhiyun if (err) {
2077*4882a593Smuzhiyun netdev_err(ofdpa_port->dev, "Error (%d) port VLAN l2 group for pport %d\n",
2078*4882a593Smuzhiyun err, out_pport);
2079*4882a593Smuzhiyun return err;
2080*4882a593Smuzhiyun }
2081*4882a593Smuzhiyun }
2082*4882a593Smuzhiyun
2083*4882a593Smuzhiyun return 0;
2084*4882a593Smuzhiyun }
2085*4882a593Smuzhiyun
ofdpa_port_stp_update(struct ofdpa_port * ofdpa_port,int flags,u8 state)2086*4882a593Smuzhiyun static int ofdpa_port_stp_update(struct ofdpa_port *ofdpa_port,
2087*4882a593Smuzhiyun int flags, u8 state)
2088*4882a593Smuzhiyun {
2089*4882a593Smuzhiyun bool want[OFDPA_CTRL_MAX] = { 0, };
2090*4882a593Smuzhiyun bool prev_ctrls[OFDPA_CTRL_MAX];
2091*4882a593Smuzhiyun u8 prev_state;
2092*4882a593Smuzhiyun int err;
2093*4882a593Smuzhiyun int i;
2094*4882a593Smuzhiyun
2095*4882a593Smuzhiyun memcpy(prev_ctrls, ofdpa_port->ctrls, sizeof(prev_ctrls));
2096*4882a593Smuzhiyun prev_state = ofdpa_port->stp_state;
2097*4882a593Smuzhiyun
2098*4882a593Smuzhiyun if (ofdpa_port->stp_state == state)
2099*4882a593Smuzhiyun return 0;
2100*4882a593Smuzhiyun
2101*4882a593Smuzhiyun ofdpa_port->stp_state = state;
2102*4882a593Smuzhiyun
2103*4882a593Smuzhiyun switch (state) {
2104*4882a593Smuzhiyun case BR_STATE_DISABLED:
2105*4882a593Smuzhiyun /* port is completely disabled */
2106*4882a593Smuzhiyun break;
2107*4882a593Smuzhiyun case BR_STATE_LISTENING:
2108*4882a593Smuzhiyun case BR_STATE_BLOCKING:
2109*4882a593Smuzhiyun want[OFDPA_CTRL_LINK_LOCAL_MCAST] = true;
2110*4882a593Smuzhiyun break;
2111*4882a593Smuzhiyun case BR_STATE_LEARNING:
2112*4882a593Smuzhiyun case BR_STATE_FORWARDING:
2113*4882a593Smuzhiyun if (!ofdpa_port_is_ovsed(ofdpa_port))
2114*4882a593Smuzhiyun want[OFDPA_CTRL_LINK_LOCAL_MCAST] = true;
2115*4882a593Smuzhiyun want[OFDPA_CTRL_IPV4_MCAST] = true;
2116*4882a593Smuzhiyun want[OFDPA_CTRL_IPV6_MCAST] = true;
2117*4882a593Smuzhiyun if (ofdpa_port_is_bridged(ofdpa_port))
2118*4882a593Smuzhiyun want[OFDPA_CTRL_DFLT_BRIDGING] = true;
2119*4882a593Smuzhiyun else if (ofdpa_port_is_ovsed(ofdpa_port))
2120*4882a593Smuzhiyun want[OFDPA_CTRL_DFLT_OVS] = true;
2121*4882a593Smuzhiyun else
2122*4882a593Smuzhiyun want[OFDPA_CTRL_LOCAL_ARP] = true;
2123*4882a593Smuzhiyun break;
2124*4882a593Smuzhiyun }
2125*4882a593Smuzhiyun
2126*4882a593Smuzhiyun for (i = 0; i < OFDPA_CTRL_MAX; i++) {
2127*4882a593Smuzhiyun if (want[i] != ofdpa_port->ctrls[i]) {
2128*4882a593Smuzhiyun int ctrl_flags = flags |
2129*4882a593Smuzhiyun (want[i] ? 0 : OFDPA_OP_FLAG_REMOVE);
2130*4882a593Smuzhiyun err = ofdpa_port_ctrl(ofdpa_port, ctrl_flags,
2131*4882a593Smuzhiyun &ofdpa_ctrls[i]);
2132*4882a593Smuzhiyun if (err)
2133*4882a593Smuzhiyun goto err_port_ctrl;
2134*4882a593Smuzhiyun ofdpa_port->ctrls[i] = want[i];
2135*4882a593Smuzhiyun }
2136*4882a593Smuzhiyun }
2137*4882a593Smuzhiyun
2138*4882a593Smuzhiyun err = ofdpa_port_fdb_flush(ofdpa_port, flags);
2139*4882a593Smuzhiyun if (err)
2140*4882a593Smuzhiyun goto err_fdb_flush;
2141*4882a593Smuzhiyun
2142*4882a593Smuzhiyun err = ofdpa_port_fwding(ofdpa_port, flags);
2143*4882a593Smuzhiyun if (err)
2144*4882a593Smuzhiyun goto err_port_fwding;
2145*4882a593Smuzhiyun
2146*4882a593Smuzhiyun return 0;
2147*4882a593Smuzhiyun
2148*4882a593Smuzhiyun err_port_ctrl:
2149*4882a593Smuzhiyun err_fdb_flush:
2150*4882a593Smuzhiyun err_port_fwding:
2151*4882a593Smuzhiyun memcpy(ofdpa_port->ctrls, prev_ctrls, sizeof(prev_ctrls));
2152*4882a593Smuzhiyun ofdpa_port->stp_state = prev_state;
2153*4882a593Smuzhiyun return err;
2154*4882a593Smuzhiyun }
2155*4882a593Smuzhiyun
ofdpa_port_fwd_enable(struct ofdpa_port * ofdpa_port,int flags)2156*4882a593Smuzhiyun static int ofdpa_port_fwd_enable(struct ofdpa_port *ofdpa_port, int flags)
2157*4882a593Smuzhiyun {
2158*4882a593Smuzhiyun if (ofdpa_port_is_bridged(ofdpa_port))
2159*4882a593Smuzhiyun /* bridge STP will enable port */
2160*4882a593Smuzhiyun return 0;
2161*4882a593Smuzhiyun
2162*4882a593Smuzhiyun /* port is not bridged, so simulate going to FORWARDING state */
2163*4882a593Smuzhiyun return ofdpa_port_stp_update(ofdpa_port, flags,
2164*4882a593Smuzhiyun BR_STATE_FORWARDING);
2165*4882a593Smuzhiyun }
2166*4882a593Smuzhiyun
ofdpa_port_fwd_disable(struct ofdpa_port * ofdpa_port,int flags)2167*4882a593Smuzhiyun static int ofdpa_port_fwd_disable(struct ofdpa_port *ofdpa_port, int flags)
2168*4882a593Smuzhiyun {
2169*4882a593Smuzhiyun if (ofdpa_port_is_bridged(ofdpa_port))
2170*4882a593Smuzhiyun /* bridge STP will disable port */
2171*4882a593Smuzhiyun return 0;
2172*4882a593Smuzhiyun
2173*4882a593Smuzhiyun /* port is not bridged, so simulate going to DISABLED state */
2174*4882a593Smuzhiyun return ofdpa_port_stp_update(ofdpa_port, flags,
2175*4882a593Smuzhiyun BR_STATE_DISABLED);
2176*4882a593Smuzhiyun }
2177*4882a593Smuzhiyun
ofdpa_port_vlan_add(struct ofdpa_port * ofdpa_port,u16 vid,u16 flags)2178*4882a593Smuzhiyun static int ofdpa_port_vlan_add(struct ofdpa_port *ofdpa_port,
2179*4882a593Smuzhiyun u16 vid, u16 flags)
2180*4882a593Smuzhiyun {
2181*4882a593Smuzhiyun int err;
2182*4882a593Smuzhiyun
2183*4882a593Smuzhiyun /* XXX deal with flags for PVID and untagged */
2184*4882a593Smuzhiyun
2185*4882a593Smuzhiyun err = ofdpa_port_vlan(ofdpa_port, 0, vid);
2186*4882a593Smuzhiyun if (err)
2187*4882a593Smuzhiyun return err;
2188*4882a593Smuzhiyun
2189*4882a593Smuzhiyun err = ofdpa_port_router_mac(ofdpa_port, 0, htons(vid));
2190*4882a593Smuzhiyun if (err)
2191*4882a593Smuzhiyun ofdpa_port_vlan(ofdpa_port,
2192*4882a593Smuzhiyun OFDPA_OP_FLAG_REMOVE, vid);
2193*4882a593Smuzhiyun
2194*4882a593Smuzhiyun return err;
2195*4882a593Smuzhiyun }
2196*4882a593Smuzhiyun
ofdpa_port_vlan_del(struct ofdpa_port * ofdpa_port,u16 vid,u16 flags)2197*4882a593Smuzhiyun static int ofdpa_port_vlan_del(struct ofdpa_port *ofdpa_port,
2198*4882a593Smuzhiyun u16 vid, u16 flags)
2199*4882a593Smuzhiyun {
2200*4882a593Smuzhiyun int err;
2201*4882a593Smuzhiyun
2202*4882a593Smuzhiyun err = ofdpa_port_router_mac(ofdpa_port, OFDPA_OP_FLAG_REMOVE,
2203*4882a593Smuzhiyun htons(vid));
2204*4882a593Smuzhiyun if (err)
2205*4882a593Smuzhiyun return err;
2206*4882a593Smuzhiyun
2207*4882a593Smuzhiyun return ofdpa_port_vlan(ofdpa_port, OFDPA_OP_FLAG_REMOVE,
2208*4882a593Smuzhiyun vid);
2209*4882a593Smuzhiyun }
2210*4882a593Smuzhiyun
2211*4882a593Smuzhiyun static struct ofdpa_internal_vlan_tbl_entry *
ofdpa_internal_vlan_tbl_find(const struct ofdpa * ofdpa,int ifindex)2212*4882a593Smuzhiyun ofdpa_internal_vlan_tbl_find(const struct ofdpa *ofdpa, int ifindex)
2213*4882a593Smuzhiyun {
2214*4882a593Smuzhiyun struct ofdpa_internal_vlan_tbl_entry *found;
2215*4882a593Smuzhiyun
2216*4882a593Smuzhiyun hash_for_each_possible(ofdpa->internal_vlan_tbl, found,
2217*4882a593Smuzhiyun entry, ifindex) {
2218*4882a593Smuzhiyun if (found->ifindex == ifindex)
2219*4882a593Smuzhiyun return found;
2220*4882a593Smuzhiyun }
2221*4882a593Smuzhiyun
2222*4882a593Smuzhiyun return NULL;
2223*4882a593Smuzhiyun }
2224*4882a593Smuzhiyun
ofdpa_port_internal_vlan_id_get(struct ofdpa_port * ofdpa_port,int ifindex)2225*4882a593Smuzhiyun static __be16 ofdpa_port_internal_vlan_id_get(struct ofdpa_port *ofdpa_port,
2226*4882a593Smuzhiyun int ifindex)
2227*4882a593Smuzhiyun {
2228*4882a593Smuzhiyun struct ofdpa *ofdpa = ofdpa_port->ofdpa;
2229*4882a593Smuzhiyun struct ofdpa_internal_vlan_tbl_entry *entry;
2230*4882a593Smuzhiyun struct ofdpa_internal_vlan_tbl_entry *found;
2231*4882a593Smuzhiyun unsigned long lock_flags;
2232*4882a593Smuzhiyun int i;
2233*4882a593Smuzhiyun
2234*4882a593Smuzhiyun entry = kzalloc(sizeof(*entry), GFP_KERNEL);
2235*4882a593Smuzhiyun if (!entry)
2236*4882a593Smuzhiyun return 0;
2237*4882a593Smuzhiyun
2238*4882a593Smuzhiyun entry->ifindex = ifindex;
2239*4882a593Smuzhiyun
2240*4882a593Smuzhiyun spin_lock_irqsave(&ofdpa->internal_vlan_tbl_lock, lock_flags);
2241*4882a593Smuzhiyun
2242*4882a593Smuzhiyun found = ofdpa_internal_vlan_tbl_find(ofdpa, ifindex);
2243*4882a593Smuzhiyun if (found) {
2244*4882a593Smuzhiyun kfree(entry);
2245*4882a593Smuzhiyun goto found;
2246*4882a593Smuzhiyun }
2247*4882a593Smuzhiyun
2248*4882a593Smuzhiyun found = entry;
2249*4882a593Smuzhiyun hash_add(ofdpa->internal_vlan_tbl, &found->entry, found->ifindex);
2250*4882a593Smuzhiyun
2251*4882a593Smuzhiyun for (i = 0; i < OFDPA_N_INTERNAL_VLANS; i++) {
2252*4882a593Smuzhiyun if (test_and_set_bit(i, ofdpa->internal_vlan_bitmap))
2253*4882a593Smuzhiyun continue;
2254*4882a593Smuzhiyun found->vlan_id = htons(OFDPA_INTERNAL_VLAN_ID_BASE + i);
2255*4882a593Smuzhiyun goto found;
2256*4882a593Smuzhiyun }
2257*4882a593Smuzhiyun
2258*4882a593Smuzhiyun netdev_err(ofdpa_port->dev, "Out of internal VLAN IDs\n");
2259*4882a593Smuzhiyun
2260*4882a593Smuzhiyun found:
2261*4882a593Smuzhiyun found->ref_count++;
2262*4882a593Smuzhiyun spin_unlock_irqrestore(&ofdpa->internal_vlan_tbl_lock, lock_flags);
2263*4882a593Smuzhiyun
2264*4882a593Smuzhiyun return found->vlan_id;
2265*4882a593Smuzhiyun }
2266*4882a593Smuzhiyun
ofdpa_port_fib_ipv4(struct ofdpa_port * ofdpa_port,__be32 dst,int dst_len,struct fib_info * fi,u32 tb_id,int flags)2267*4882a593Smuzhiyun static int ofdpa_port_fib_ipv4(struct ofdpa_port *ofdpa_port, __be32 dst,
2268*4882a593Smuzhiyun int dst_len, struct fib_info *fi, u32 tb_id,
2269*4882a593Smuzhiyun int flags)
2270*4882a593Smuzhiyun {
2271*4882a593Smuzhiyun const struct fib_nh *nh;
2272*4882a593Smuzhiyun __be16 eth_type = htons(ETH_P_IP);
2273*4882a593Smuzhiyun __be32 dst_mask = inet_make_mask(dst_len);
2274*4882a593Smuzhiyun __be16 internal_vlan_id = ofdpa_port->internal_vlan_id;
2275*4882a593Smuzhiyun u32 priority = fi->fib_priority;
2276*4882a593Smuzhiyun enum rocker_of_dpa_table_id goto_tbl =
2277*4882a593Smuzhiyun ROCKER_OF_DPA_TABLE_ID_ACL_POLICY;
2278*4882a593Smuzhiyun u32 group_id;
2279*4882a593Smuzhiyun bool nh_on_port;
2280*4882a593Smuzhiyun bool has_gw;
2281*4882a593Smuzhiyun u32 index;
2282*4882a593Smuzhiyun int err;
2283*4882a593Smuzhiyun
2284*4882a593Smuzhiyun /* XXX support ECMP */
2285*4882a593Smuzhiyun
2286*4882a593Smuzhiyun nh = fib_info_nh(fi, 0);
2287*4882a593Smuzhiyun nh_on_port = (nh->fib_nh_dev == ofdpa_port->dev);
2288*4882a593Smuzhiyun has_gw = !!nh->fib_nh_gw4;
2289*4882a593Smuzhiyun
2290*4882a593Smuzhiyun if (has_gw && nh_on_port) {
2291*4882a593Smuzhiyun err = ofdpa_port_ipv4_nh(ofdpa_port, flags,
2292*4882a593Smuzhiyun nh->fib_nh_gw4, &index);
2293*4882a593Smuzhiyun if (err)
2294*4882a593Smuzhiyun return err;
2295*4882a593Smuzhiyun
2296*4882a593Smuzhiyun group_id = ROCKER_GROUP_L3_UNICAST(index);
2297*4882a593Smuzhiyun } else {
2298*4882a593Smuzhiyun /* Send to CPU for processing */
2299*4882a593Smuzhiyun group_id = ROCKER_GROUP_L2_INTERFACE(internal_vlan_id, 0);
2300*4882a593Smuzhiyun }
2301*4882a593Smuzhiyun
2302*4882a593Smuzhiyun err = ofdpa_flow_tbl_ucast4_routing(ofdpa_port, eth_type, dst,
2303*4882a593Smuzhiyun dst_mask, priority, goto_tbl,
2304*4882a593Smuzhiyun group_id, fi, flags);
2305*4882a593Smuzhiyun if (err)
2306*4882a593Smuzhiyun netdev_err(ofdpa_port->dev, "Error (%d) IPv4 route %pI4\n",
2307*4882a593Smuzhiyun err, &dst);
2308*4882a593Smuzhiyun
2309*4882a593Smuzhiyun return err;
2310*4882a593Smuzhiyun }
2311*4882a593Smuzhiyun
2312*4882a593Smuzhiyun static void
ofdpa_port_internal_vlan_id_put(const struct ofdpa_port * ofdpa_port,int ifindex)2313*4882a593Smuzhiyun ofdpa_port_internal_vlan_id_put(const struct ofdpa_port *ofdpa_port,
2314*4882a593Smuzhiyun int ifindex)
2315*4882a593Smuzhiyun {
2316*4882a593Smuzhiyun struct ofdpa *ofdpa = ofdpa_port->ofdpa;
2317*4882a593Smuzhiyun struct ofdpa_internal_vlan_tbl_entry *found;
2318*4882a593Smuzhiyun unsigned long lock_flags;
2319*4882a593Smuzhiyun unsigned long bit;
2320*4882a593Smuzhiyun
2321*4882a593Smuzhiyun spin_lock_irqsave(&ofdpa->internal_vlan_tbl_lock, lock_flags);
2322*4882a593Smuzhiyun
2323*4882a593Smuzhiyun found = ofdpa_internal_vlan_tbl_find(ofdpa, ifindex);
2324*4882a593Smuzhiyun if (!found) {
2325*4882a593Smuzhiyun netdev_err(ofdpa_port->dev,
2326*4882a593Smuzhiyun "ifindex (%d) not found in internal VLAN tbl\n",
2327*4882a593Smuzhiyun ifindex);
2328*4882a593Smuzhiyun goto not_found;
2329*4882a593Smuzhiyun }
2330*4882a593Smuzhiyun
2331*4882a593Smuzhiyun if (--found->ref_count <= 0) {
2332*4882a593Smuzhiyun bit = ntohs(found->vlan_id) - OFDPA_INTERNAL_VLAN_ID_BASE;
2333*4882a593Smuzhiyun clear_bit(bit, ofdpa->internal_vlan_bitmap);
2334*4882a593Smuzhiyun hash_del(&found->entry);
2335*4882a593Smuzhiyun kfree(found);
2336*4882a593Smuzhiyun }
2337*4882a593Smuzhiyun
2338*4882a593Smuzhiyun not_found:
2339*4882a593Smuzhiyun spin_unlock_irqrestore(&ofdpa->internal_vlan_tbl_lock, lock_flags);
2340*4882a593Smuzhiyun }
2341*4882a593Smuzhiyun
2342*4882a593Smuzhiyun /**********************************
2343*4882a593Smuzhiyun * Rocker world ops implementation
2344*4882a593Smuzhiyun **********************************/
2345*4882a593Smuzhiyun
ofdpa_init(struct rocker * rocker)2346*4882a593Smuzhiyun static int ofdpa_init(struct rocker *rocker)
2347*4882a593Smuzhiyun {
2348*4882a593Smuzhiyun struct ofdpa *ofdpa = rocker->wpriv;
2349*4882a593Smuzhiyun
2350*4882a593Smuzhiyun ofdpa->rocker = rocker;
2351*4882a593Smuzhiyun
2352*4882a593Smuzhiyun hash_init(ofdpa->flow_tbl);
2353*4882a593Smuzhiyun spin_lock_init(&ofdpa->flow_tbl_lock);
2354*4882a593Smuzhiyun
2355*4882a593Smuzhiyun hash_init(ofdpa->group_tbl);
2356*4882a593Smuzhiyun spin_lock_init(&ofdpa->group_tbl_lock);
2357*4882a593Smuzhiyun
2358*4882a593Smuzhiyun hash_init(ofdpa->fdb_tbl);
2359*4882a593Smuzhiyun spin_lock_init(&ofdpa->fdb_tbl_lock);
2360*4882a593Smuzhiyun
2361*4882a593Smuzhiyun hash_init(ofdpa->internal_vlan_tbl);
2362*4882a593Smuzhiyun spin_lock_init(&ofdpa->internal_vlan_tbl_lock);
2363*4882a593Smuzhiyun
2364*4882a593Smuzhiyun hash_init(ofdpa->neigh_tbl);
2365*4882a593Smuzhiyun spin_lock_init(&ofdpa->neigh_tbl_lock);
2366*4882a593Smuzhiyun
2367*4882a593Smuzhiyun timer_setup(&ofdpa->fdb_cleanup_timer, ofdpa_fdb_cleanup, 0);
2368*4882a593Smuzhiyun mod_timer(&ofdpa->fdb_cleanup_timer, jiffies);
2369*4882a593Smuzhiyun
2370*4882a593Smuzhiyun ofdpa->ageing_time = BR_DEFAULT_AGEING_TIME;
2371*4882a593Smuzhiyun
2372*4882a593Smuzhiyun return 0;
2373*4882a593Smuzhiyun }
2374*4882a593Smuzhiyun
ofdpa_fini(struct rocker * rocker)2375*4882a593Smuzhiyun static void ofdpa_fini(struct rocker *rocker)
2376*4882a593Smuzhiyun {
2377*4882a593Smuzhiyun struct ofdpa *ofdpa = rocker->wpriv;
2378*4882a593Smuzhiyun
2379*4882a593Smuzhiyun unsigned long flags;
2380*4882a593Smuzhiyun struct ofdpa_flow_tbl_entry *flow_entry;
2381*4882a593Smuzhiyun struct ofdpa_group_tbl_entry *group_entry;
2382*4882a593Smuzhiyun struct ofdpa_fdb_tbl_entry *fdb_entry;
2383*4882a593Smuzhiyun struct ofdpa_internal_vlan_tbl_entry *internal_vlan_entry;
2384*4882a593Smuzhiyun struct ofdpa_neigh_tbl_entry *neigh_entry;
2385*4882a593Smuzhiyun struct hlist_node *tmp;
2386*4882a593Smuzhiyun int bkt;
2387*4882a593Smuzhiyun
2388*4882a593Smuzhiyun del_timer_sync(&ofdpa->fdb_cleanup_timer);
2389*4882a593Smuzhiyun flush_workqueue(rocker->rocker_owq);
2390*4882a593Smuzhiyun
2391*4882a593Smuzhiyun spin_lock_irqsave(&ofdpa->flow_tbl_lock, flags);
2392*4882a593Smuzhiyun hash_for_each_safe(ofdpa->flow_tbl, bkt, tmp, flow_entry, entry)
2393*4882a593Smuzhiyun hash_del(&flow_entry->entry);
2394*4882a593Smuzhiyun spin_unlock_irqrestore(&ofdpa->flow_tbl_lock, flags);
2395*4882a593Smuzhiyun
2396*4882a593Smuzhiyun spin_lock_irqsave(&ofdpa->group_tbl_lock, flags);
2397*4882a593Smuzhiyun hash_for_each_safe(ofdpa->group_tbl, bkt, tmp, group_entry, entry)
2398*4882a593Smuzhiyun hash_del(&group_entry->entry);
2399*4882a593Smuzhiyun spin_unlock_irqrestore(&ofdpa->group_tbl_lock, flags);
2400*4882a593Smuzhiyun
2401*4882a593Smuzhiyun spin_lock_irqsave(&ofdpa->fdb_tbl_lock, flags);
2402*4882a593Smuzhiyun hash_for_each_safe(ofdpa->fdb_tbl, bkt, tmp, fdb_entry, entry)
2403*4882a593Smuzhiyun hash_del(&fdb_entry->entry);
2404*4882a593Smuzhiyun spin_unlock_irqrestore(&ofdpa->fdb_tbl_lock, flags);
2405*4882a593Smuzhiyun
2406*4882a593Smuzhiyun spin_lock_irqsave(&ofdpa->internal_vlan_tbl_lock, flags);
2407*4882a593Smuzhiyun hash_for_each_safe(ofdpa->internal_vlan_tbl, bkt,
2408*4882a593Smuzhiyun tmp, internal_vlan_entry, entry)
2409*4882a593Smuzhiyun hash_del(&internal_vlan_entry->entry);
2410*4882a593Smuzhiyun spin_unlock_irqrestore(&ofdpa->internal_vlan_tbl_lock, flags);
2411*4882a593Smuzhiyun
2412*4882a593Smuzhiyun spin_lock_irqsave(&ofdpa->neigh_tbl_lock, flags);
2413*4882a593Smuzhiyun hash_for_each_safe(ofdpa->neigh_tbl, bkt, tmp, neigh_entry, entry)
2414*4882a593Smuzhiyun hash_del(&neigh_entry->entry);
2415*4882a593Smuzhiyun spin_unlock_irqrestore(&ofdpa->neigh_tbl_lock, flags);
2416*4882a593Smuzhiyun }
2417*4882a593Smuzhiyun
ofdpa_port_pre_init(struct rocker_port * rocker_port)2418*4882a593Smuzhiyun static int ofdpa_port_pre_init(struct rocker_port *rocker_port)
2419*4882a593Smuzhiyun {
2420*4882a593Smuzhiyun struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
2421*4882a593Smuzhiyun
2422*4882a593Smuzhiyun ofdpa_port->ofdpa = rocker_port->rocker->wpriv;
2423*4882a593Smuzhiyun ofdpa_port->rocker_port = rocker_port;
2424*4882a593Smuzhiyun ofdpa_port->dev = rocker_port->dev;
2425*4882a593Smuzhiyun ofdpa_port->pport = rocker_port->pport;
2426*4882a593Smuzhiyun ofdpa_port->brport_flags = BR_LEARNING;
2427*4882a593Smuzhiyun ofdpa_port->ageing_time = BR_DEFAULT_AGEING_TIME;
2428*4882a593Smuzhiyun return 0;
2429*4882a593Smuzhiyun }
2430*4882a593Smuzhiyun
ofdpa_port_init(struct rocker_port * rocker_port)2431*4882a593Smuzhiyun static int ofdpa_port_init(struct rocker_port *rocker_port)
2432*4882a593Smuzhiyun {
2433*4882a593Smuzhiyun struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
2434*4882a593Smuzhiyun int err;
2435*4882a593Smuzhiyun
2436*4882a593Smuzhiyun rocker_port_set_learning(rocker_port,
2437*4882a593Smuzhiyun !!(ofdpa_port->brport_flags & BR_LEARNING));
2438*4882a593Smuzhiyun
2439*4882a593Smuzhiyun err = ofdpa_port_ig_tbl(ofdpa_port, 0);
2440*4882a593Smuzhiyun if (err) {
2441*4882a593Smuzhiyun netdev_err(ofdpa_port->dev, "install ig port table failed\n");
2442*4882a593Smuzhiyun return err;
2443*4882a593Smuzhiyun }
2444*4882a593Smuzhiyun
2445*4882a593Smuzhiyun ofdpa_port->internal_vlan_id =
2446*4882a593Smuzhiyun ofdpa_port_internal_vlan_id_get(ofdpa_port,
2447*4882a593Smuzhiyun ofdpa_port->dev->ifindex);
2448*4882a593Smuzhiyun
2449*4882a593Smuzhiyun err = ofdpa_port_vlan_add(ofdpa_port, OFDPA_UNTAGGED_VID, 0);
2450*4882a593Smuzhiyun if (err) {
2451*4882a593Smuzhiyun netdev_err(ofdpa_port->dev, "install untagged VLAN failed\n");
2452*4882a593Smuzhiyun goto err_untagged_vlan;
2453*4882a593Smuzhiyun }
2454*4882a593Smuzhiyun return 0;
2455*4882a593Smuzhiyun
2456*4882a593Smuzhiyun err_untagged_vlan:
2457*4882a593Smuzhiyun ofdpa_port_ig_tbl(ofdpa_port, OFDPA_OP_FLAG_REMOVE);
2458*4882a593Smuzhiyun return err;
2459*4882a593Smuzhiyun }
2460*4882a593Smuzhiyun
ofdpa_port_fini(struct rocker_port * rocker_port)2461*4882a593Smuzhiyun static void ofdpa_port_fini(struct rocker_port *rocker_port)
2462*4882a593Smuzhiyun {
2463*4882a593Smuzhiyun struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
2464*4882a593Smuzhiyun
2465*4882a593Smuzhiyun ofdpa_port_ig_tbl(ofdpa_port, OFDPA_OP_FLAG_REMOVE);
2466*4882a593Smuzhiyun }
2467*4882a593Smuzhiyun
ofdpa_port_open(struct rocker_port * rocker_port)2468*4882a593Smuzhiyun static int ofdpa_port_open(struct rocker_port *rocker_port)
2469*4882a593Smuzhiyun {
2470*4882a593Smuzhiyun struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
2471*4882a593Smuzhiyun
2472*4882a593Smuzhiyun return ofdpa_port_fwd_enable(ofdpa_port, 0);
2473*4882a593Smuzhiyun }
2474*4882a593Smuzhiyun
ofdpa_port_stop(struct rocker_port * rocker_port)2475*4882a593Smuzhiyun static void ofdpa_port_stop(struct rocker_port *rocker_port)
2476*4882a593Smuzhiyun {
2477*4882a593Smuzhiyun struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
2478*4882a593Smuzhiyun
2479*4882a593Smuzhiyun ofdpa_port_fwd_disable(ofdpa_port, OFDPA_OP_FLAG_NOWAIT);
2480*4882a593Smuzhiyun }
2481*4882a593Smuzhiyun
ofdpa_port_attr_stp_state_set(struct rocker_port * rocker_port,u8 state)2482*4882a593Smuzhiyun static int ofdpa_port_attr_stp_state_set(struct rocker_port *rocker_port,
2483*4882a593Smuzhiyun u8 state)
2484*4882a593Smuzhiyun {
2485*4882a593Smuzhiyun struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
2486*4882a593Smuzhiyun
2487*4882a593Smuzhiyun return ofdpa_port_stp_update(ofdpa_port, 0, state);
2488*4882a593Smuzhiyun }
2489*4882a593Smuzhiyun
ofdpa_port_attr_bridge_flags_set(struct rocker_port * rocker_port,unsigned long brport_flags,struct switchdev_trans * trans)2490*4882a593Smuzhiyun static int ofdpa_port_attr_bridge_flags_set(struct rocker_port *rocker_port,
2491*4882a593Smuzhiyun unsigned long brport_flags,
2492*4882a593Smuzhiyun struct switchdev_trans *trans)
2493*4882a593Smuzhiyun {
2494*4882a593Smuzhiyun struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
2495*4882a593Smuzhiyun unsigned long orig_flags;
2496*4882a593Smuzhiyun int err = 0;
2497*4882a593Smuzhiyun
2498*4882a593Smuzhiyun orig_flags = ofdpa_port->brport_flags;
2499*4882a593Smuzhiyun ofdpa_port->brport_flags = brport_flags;
2500*4882a593Smuzhiyun if ((orig_flags ^ ofdpa_port->brport_flags) & BR_LEARNING &&
2501*4882a593Smuzhiyun !switchdev_trans_ph_prepare(trans))
2502*4882a593Smuzhiyun err = rocker_port_set_learning(ofdpa_port->rocker_port,
2503*4882a593Smuzhiyun !!(ofdpa_port->brport_flags & BR_LEARNING));
2504*4882a593Smuzhiyun
2505*4882a593Smuzhiyun if (switchdev_trans_ph_prepare(trans))
2506*4882a593Smuzhiyun ofdpa_port->brport_flags = orig_flags;
2507*4882a593Smuzhiyun
2508*4882a593Smuzhiyun return err;
2509*4882a593Smuzhiyun }
2510*4882a593Smuzhiyun
2511*4882a593Smuzhiyun static int
ofdpa_port_attr_bridge_flags_support_get(const struct rocker_port * rocker_port,unsigned long * p_brport_flags_support)2512*4882a593Smuzhiyun ofdpa_port_attr_bridge_flags_support_get(const struct rocker_port *
2513*4882a593Smuzhiyun rocker_port,
2514*4882a593Smuzhiyun unsigned long *
2515*4882a593Smuzhiyun p_brport_flags_support)
2516*4882a593Smuzhiyun {
2517*4882a593Smuzhiyun *p_brport_flags_support = BR_LEARNING;
2518*4882a593Smuzhiyun return 0;
2519*4882a593Smuzhiyun }
2520*4882a593Smuzhiyun
2521*4882a593Smuzhiyun static int
ofdpa_port_attr_bridge_ageing_time_set(struct rocker_port * rocker_port,u32 ageing_time,struct switchdev_trans * trans)2522*4882a593Smuzhiyun ofdpa_port_attr_bridge_ageing_time_set(struct rocker_port *rocker_port,
2523*4882a593Smuzhiyun u32 ageing_time,
2524*4882a593Smuzhiyun struct switchdev_trans *trans)
2525*4882a593Smuzhiyun {
2526*4882a593Smuzhiyun struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
2527*4882a593Smuzhiyun struct ofdpa *ofdpa = ofdpa_port->ofdpa;
2528*4882a593Smuzhiyun
2529*4882a593Smuzhiyun if (!switchdev_trans_ph_prepare(trans)) {
2530*4882a593Smuzhiyun ofdpa_port->ageing_time = clock_t_to_jiffies(ageing_time);
2531*4882a593Smuzhiyun if (ofdpa_port->ageing_time < ofdpa->ageing_time)
2532*4882a593Smuzhiyun ofdpa->ageing_time = ofdpa_port->ageing_time;
2533*4882a593Smuzhiyun mod_timer(&ofdpa_port->ofdpa->fdb_cleanup_timer, jiffies);
2534*4882a593Smuzhiyun }
2535*4882a593Smuzhiyun
2536*4882a593Smuzhiyun return 0;
2537*4882a593Smuzhiyun }
2538*4882a593Smuzhiyun
ofdpa_port_obj_vlan_add(struct rocker_port * rocker_port,const struct switchdev_obj_port_vlan * vlan)2539*4882a593Smuzhiyun static int ofdpa_port_obj_vlan_add(struct rocker_port *rocker_port,
2540*4882a593Smuzhiyun const struct switchdev_obj_port_vlan *vlan)
2541*4882a593Smuzhiyun {
2542*4882a593Smuzhiyun struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
2543*4882a593Smuzhiyun u16 vid;
2544*4882a593Smuzhiyun int err;
2545*4882a593Smuzhiyun
2546*4882a593Smuzhiyun for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) {
2547*4882a593Smuzhiyun err = ofdpa_port_vlan_add(ofdpa_port, vid, vlan->flags);
2548*4882a593Smuzhiyun if (err)
2549*4882a593Smuzhiyun return err;
2550*4882a593Smuzhiyun }
2551*4882a593Smuzhiyun
2552*4882a593Smuzhiyun return 0;
2553*4882a593Smuzhiyun }
2554*4882a593Smuzhiyun
ofdpa_port_obj_vlan_del(struct rocker_port * rocker_port,const struct switchdev_obj_port_vlan * vlan)2555*4882a593Smuzhiyun static int ofdpa_port_obj_vlan_del(struct rocker_port *rocker_port,
2556*4882a593Smuzhiyun const struct switchdev_obj_port_vlan *vlan)
2557*4882a593Smuzhiyun {
2558*4882a593Smuzhiyun struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
2559*4882a593Smuzhiyun u16 vid;
2560*4882a593Smuzhiyun int err;
2561*4882a593Smuzhiyun
2562*4882a593Smuzhiyun for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) {
2563*4882a593Smuzhiyun err = ofdpa_port_vlan_del(ofdpa_port, vid, vlan->flags);
2564*4882a593Smuzhiyun if (err)
2565*4882a593Smuzhiyun return err;
2566*4882a593Smuzhiyun }
2567*4882a593Smuzhiyun
2568*4882a593Smuzhiyun return 0;
2569*4882a593Smuzhiyun }
2570*4882a593Smuzhiyun
ofdpa_port_obj_fdb_add(struct rocker_port * rocker_port,u16 vid,const unsigned char * addr)2571*4882a593Smuzhiyun static int ofdpa_port_obj_fdb_add(struct rocker_port *rocker_port,
2572*4882a593Smuzhiyun u16 vid, const unsigned char *addr)
2573*4882a593Smuzhiyun {
2574*4882a593Smuzhiyun struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
2575*4882a593Smuzhiyun __be16 vlan_id = ofdpa_port_vid_to_vlan(ofdpa_port, vid, NULL);
2576*4882a593Smuzhiyun
2577*4882a593Smuzhiyun if (!ofdpa_port_is_bridged(ofdpa_port))
2578*4882a593Smuzhiyun return -EINVAL;
2579*4882a593Smuzhiyun
2580*4882a593Smuzhiyun return ofdpa_port_fdb(ofdpa_port, addr, vlan_id, 0);
2581*4882a593Smuzhiyun }
2582*4882a593Smuzhiyun
ofdpa_port_obj_fdb_del(struct rocker_port * rocker_port,u16 vid,const unsigned char * addr)2583*4882a593Smuzhiyun static int ofdpa_port_obj_fdb_del(struct rocker_port *rocker_port,
2584*4882a593Smuzhiyun u16 vid, const unsigned char *addr)
2585*4882a593Smuzhiyun {
2586*4882a593Smuzhiyun struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
2587*4882a593Smuzhiyun __be16 vlan_id = ofdpa_port_vid_to_vlan(ofdpa_port, vid, NULL);
2588*4882a593Smuzhiyun int flags = OFDPA_OP_FLAG_REMOVE;
2589*4882a593Smuzhiyun
2590*4882a593Smuzhiyun if (!ofdpa_port_is_bridged(ofdpa_port))
2591*4882a593Smuzhiyun return -EINVAL;
2592*4882a593Smuzhiyun
2593*4882a593Smuzhiyun return ofdpa_port_fdb(ofdpa_port, addr, vlan_id, flags);
2594*4882a593Smuzhiyun }
2595*4882a593Smuzhiyun
ofdpa_port_bridge_join(struct ofdpa_port * ofdpa_port,struct net_device * bridge)2596*4882a593Smuzhiyun static int ofdpa_port_bridge_join(struct ofdpa_port *ofdpa_port,
2597*4882a593Smuzhiyun struct net_device *bridge)
2598*4882a593Smuzhiyun {
2599*4882a593Smuzhiyun int err;
2600*4882a593Smuzhiyun
2601*4882a593Smuzhiyun /* Port is joining bridge, so the internal VLAN for the
2602*4882a593Smuzhiyun * port is going to change to the bridge internal VLAN.
2603*4882a593Smuzhiyun * Let's remove untagged VLAN (vid=0) from port and
2604*4882a593Smuzhiyun * re-add once internal VLAN has changed.
2605*4882a593Smuzhiyun */
2606*4882a593Smuzhiyun
2607*4882a593Smuzhiyun err = ofdpa_port_vlan_del(ofdpa_port, OFDPA_UNTAGGED_VID, 0);
2608*4882a593Smuzhiyun if (err)
2609*4882a593Smuzhiyun return err;
2610*4882a593Smuzhiyun
2611*4882a593Smuzhiyun ofdpa_port_internal_vlan_id_put(ofdpa_port,
2612*4882a593Smuzhiyun ofdpa_port->dev->ifindex);
2613*4882a593Smuzhiyun ofdpa_port->internal_vlan_id =
2614*4882a593Smuzhiyun ofdpa_port_internal_vlan_id_get(ofdpa_port, bridge->ifindex);
2615*4882a593Smuzhiyun
2616*4882a593Smuzhiyun ofdpa_port->bridge_dev = bridge;
2617*4882a593Smuzhiyun
2618*4882a593Smuzhiyun return ofdpa_port_vlan_add(ofdpa_port, OFDPA_UNTAGGED_VID, 0);
2619*4882a593Smuzhiyun }
2620*4882a593Smuzhiyun
ofdpa_port_bridge_leave(struct ofdpa_port * ofdpa_port)2621*4882a593Smuzhiyun static int ofdpa_port_bridge_leave(struct ofdpa_port *ofdpa_port)
2622*4882a593Smuzhiyun {
2623*4882a593Smuzhiyun int err;
2624*4882a593Smuzhiyun
2625*4882a593Smuzhiyun err = ofdpa_port_vlan_del(ofdpa_port, OFDPA_UNTAGGED_VID, 0);
2626*4882a593Smuzhiyun if (err)
2627*4882a593Smuzhiyun return err;
2628*4882a593Smuzhiyun
2629*4882a593Smuzhiyun ofdpa_port_internal_vlan_id_put(ofdpa_port,
2630*4882a593Smuzhiyun ofdpa_port->bridge_dev->ifindex);
2631*4882a593Smuzhiyun ofdpa_port->internal_vlan_id =
2632*4882a593Smuzhiyun ofdpa_port_internal_vlan_id_get(ofdpa_port,
2633*4882a593Smuzhiyun ofdpa_port->dev->ifindex);
2634*4882a593Smuzhiyun
2635*4882a593Smuzhiyun ofdpa_port->bridge_dev = NULL;
2636*4882a593Smuzhiyun
2637*4882a593Smuzhiyun err = ofdpa_port_vlan_add(ofdpa_port, OFDPA_UNTAGGED_VID, 0);
2638*4882a593Smuzhiyun if (err)
2639*4882a593Smuzhiyun return err;
2640*4882a593Smuzhiyun
2641*4882a593Smuzhiyun if (ofdpa_port->dev->flags & IFF_UP)
2642*4882a593Smuzhiyun err = ofdpa_port_fwd_enable(ofdpa_port, 0);
2643*4882a593Smuzhiyun
2644*4882a593Smuzhiyun return err;
2645*4882a593Smuzhiyun }
2646*4882a593Smuzhiyun
ofdpa_port_ovs_changed(struct ofdpa_port * ofdpa_port,struct net_device * master)2647*4882a593Smuzhiyun static int ofdpa_port_ovs_changed(struct ofdpa_port *ofdpa_port,
2648*4882a593Smuzhiyun struct net_device *master)
2649*4882a593Smuzhiyun {
2650*4882a593Smuzhiyun int err;
2651*4882a593Smuzhiyun
2652*4882a593Smuzhiyun ofdpa_port->bridge_dev = master;
2653*4882a593Smuzhiyun
2654*4882a593Smuzhiyun err = ofdpa_port_fwd_disable(ofdpa_port, 0);
2655*4882a593Smuzhiyun if (err)
2656*4882a593Smuzhiyun return err;
2657*4882a593Smuzhiyun err = ofdpa_port_fwd_enable(ofdpa_port, 0);
2658*4882a593Smuzhiyun
2659*4882a593Smuzhiyun return err;
2660*4882a593Smuzhiyun }
2661*4882a593Smuzhiyun
ofdpa_port_master_linked(struct rocker_port * rocker_port,struct net_device * master)2662*4882a593Smuzhiyun static int ofdpa_port_master_linked(struct rocker_port *rocker_port,
2663*4882a593Smuzhiyun struct net_device *master)
2664*4882a593Smuzhiyun {
2665*4882a593Smuzhiyun struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
2666*4882a593Smuzhiyun int err = 0;
2667*4882a593Smuzhiyun
2668*4882a593Smuzhiyun if (netif_is_bridge_master(master))
2669*4882a593Smuzhiyun err = ofdpa_port_bridge_join(ofdpa_port, master);
2670*4882a593Smuzhiyun else if (netif_is_ovs_master(master))
2671*4882a593Smuzhiyun err = ofdpa_port_ovs_changed(ofdpa_port, master);
2672*4882a593Smuzhiyun return err;
2673*4882a593Smuzhiyun }
2674*4882a593Smuzhiyun
ofdpa_port_master_unlinked(struct rocker_port * rocker_port,struct net_device * master)2675*4882a593Smuzhiyun static int ofdpa_port_master_unlinked(struct rocker_port *rocker_port,
2676*4882a593Smuzhiyun struct net_device *master)
2677*4882a593Smuzhiyun {
2678*4882a593Smuzhiyun struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
2679*4882a593Smuzhiyun int err = 0;
2680*4882a593Smuzhiyun
2681*4882a593Smuzhiyun if (ofdpa_port_is_bridged(ofdpa_port))
2682*4882a593Smuzhiyun err = ofdpa_port_bridge_leave(ofdpa_port);
2683*4882a593Smuzhiyun else if (ofdpa_port_is_ovsed(ofdpa_port))
2684*4882a593Smuzhiyun err = ofdpa_port_ovs_changed(ofdpa_port, NULL);
2685*4882a593Smuzhiyun return err;
2686*4882a593Smuzhiyun }
2687*4882a593Smuzhiyun
ofdpa_port_neigh_update(struct rocker_port * rocker_port,struct neighbour * n)2688*4882a593Smuzhiyun static int ofdpa_port_neigh_update(struct rocker_port *rocker_port,
2689*4882a593Smuzhiyun struct neighbour *n)
2690*4882a593Smuzhiyun {
2691*4882a593Smuzhiyun struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
2692*4882a593Smuzhiyun int flags = (n->nud_state & NUD_VALID ? 0 : OFDPA_OP_FLAG_REMOVE) |
2693*4882a593Smuzhiyun OFDPA_OP_FLAG_NOWAIT;
2694*4882a593Smuzhiyun __be32 ip_addr = *(__be32 *) n->primary_key;
2695*4882a593Smuzhiyun
2696*4882a593Smuzhiyun return ofdpa_port_ipv4_neigh(ofdpa_port, flags, ip_addr, n->ha);
2697*4882a593Smuzhiyun }
2698*4882a593Smuzhiyun
ofdpa_port_neigh_destroy(struct rocker_port * rocker_port,struct neighbour * n)2699*4882a593Smuzhiyun static int ofdpa_port_neigh_destroy(struct rocker_port *rocker_port,
2700*4882a593Smuzhiyun struct neighbour *n)
2701*4882a593Smuzhiyun {
2702*4882a593Smuzhiyun struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
2703*4882a593Smuzhiyun int flags = OFDPA_OP_FLAG_REMOVE | OFDPA_OP_FLAG_NOWAIT;
2704*4882a593Smuzhiyun __be32 ip_addr = *(__be32 *) n->primary_key;
2705*4882a593Smuzhiyun
2706*4882a593Smuzhiyun return ofdpa_port_ipv4_neigh(ofdpa_port, flags, ip_addr, n->ha);
2707*4882a593Smuzhiyun }
2708*4882a593Smuzhiyun
ofdpa_port_ev_mac_vlan_seen(struct rocker_port * rocker_port,const unsigned char * addr,__be16 vlan_id)2709*4882a593Smuzhiyun static int ofdpa_port_ev_mac_vlan_seen(struct rocker_port *rocker_port,
2710*4882a593Smuzhiyun const unsigned char *addr,
2711*4882a593Smuzhiyun __be16 vlan_id)
2712*4882a593Smuzhiyun {
2713*4882a593Smuzhiyun struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
2714*4882a593Smuzhiyun int flags = OFDPA_OP_FLAG_NOWAIT | OFDPA_OP_FLAG_LEARNED;
2715*4882a593Smuzhiyun
2716*4882a593Smuzhiyun if (ofdpa_port->stp_state != BR_STATE_LEARNING &&
2717*4882a593Smuzhiyun ofdpa_port->stp_state != BR_STATE_FORWARDING)
2718*4882a593Smuzhiyun return 0;
2719*4882a593Smuzhiyun
2720*4882a593Smuzhiyun return ofdpa_port_fdb(ofdpa_port, addr, vlan_id, flags);
2721*4882a593Smuzhiyun }
2722*4882a593Smuzhiyun
ofdpa_port_dev_lower_find(struct net_device * dev,struct rocker * rocker)2723*4882a593Smuzhiyun static struct ofdpa_port *ofdpa_port_dev_lower_find(struct net_device *dev,
2724*4882a593Smuzhiyun struct rocker *rocker)
2725*4882a593Smuzhiyun {
2726*4882a593Smuzhiyun struct rocker_port *rocker_port;
2727*4882a593Smuzhiyun
2728*4882a593Smuzhiyun rocker_port = rocker_port_dev_lower_find(dev, rocker);
2729*4882a593Smuzhiyun return rocker_port ? rocker_port->wpriv : NULL;
2730*4882a593Smuzhiyun }
2731*4882a593Smuzhiyun
ofdpa_fib4_add(struct rocker * rocker,const struct fib_entry_notifier_info * fen_info)2732*4882a593Smuzhiyun static int ofdpa_fib4_add(struct rocker *rocker,
2733*4882a593Smuzhiyun const struct fib_entry_notifier_info *fen_info)
2734*4882a593Smuzhiyun {
2735*4882a593Smuzhiyun struct ofdpa *ofdpa = rocker->wpriv;
2736*4882a593Smuzhiyun struct ofdpa_port *ofdpa_port;
2737*4882a593Smuzhiyun struct fib_nh *nh;
2738*4882a593Smuzhiyun int err;
2739*4882a593Smuzhiyun
2740*4882a593Smuzhiyun if (ofdpa->fib_aborted)
2741*4882a593Smuzhiyun return 0;
2742*4882a593Smuzhiyun nh = fib_info_nh(fen_info->fi, 0);
2743*4882a593Smuzhiyun ofdpa_port = ofdpa_port_dev_lower_find(nh->fib_nh_dev, rocker);
2744*4882a593Smuzhiyun if (!ofdpa_port)
2745*4882a593Smuzhiyun return 0;
2746*4882a593Smuzhiyun err = ofdpa_port_fib_ipv4(ofdpa_port, htonl(fen_info->dst),
2747*4882a593Smuzhiyun fen_info->dst_len, fen_info->fi,
2748*4882a593Smuzhiyun fen_info->tb_id, 0);
2749*4882a593Smuzhiyun if (err)
2750*4882a593Smuzhiyun return err;
2751*4882a593Smuzhiyun nh->fib_nh_flags |= RTNH_F_OFFLOAD;
2752*4882a593Smuzhiyun return 0;
2753*4882a593Smuzhiyun }
2754*4882a593Smuzhiyun
ofdpa_fib4_del(struct rocker * rocker,const struct fib_entry_notifier_info * fen_info)2755*4882a593Smuzhiyun static int ofdpa_fib4_del(struct rocker *rocker,
2756*4882a593Smuzhiyun const struct fib_entry_notifier_info *fen_info)
2757*4882a593Smuzhiyun {
2758*4882a593Smuzhiyun struct ofdpa *ofdpa = rocker->wpriv;
2759*4882a593Smuzhiyun struct ofdpa_port *ofdpa_port;
2760*4882a593Smuzhiyun struct fib_nh *nh;
2761*4882a593Smuzhiyun
2762*4882a593Smuzhiyun if (ofdpa->fib_aborted)
2763*4882a593Smuzhiyun return 0;
2764*4882a593Smuzhiyun nh = fib_info_nh(fen_info->fi, 0);
2765*4882a593Smuzhiyun ofdpa_port = ofdpa_port_dev_lower_find(nh->fib_nh_dev, rocker);
2766*4882a593Smuzhiyun if (!ofdpa_port)
2767*4882a593Smuzhiyun return 0;
2768*4882a593Smuzhiyun nh->fib_nh_flags &= ~RTNH_F_OFFLOAD;
2769*4882a593Smuzhiyun return ofdpa_port_fib_ipv4(ofdpa_port, htonl(fen_info->dst),
2770*4882a593Smuzhiyun fen_info->dst_len, fen_info->fi,
2771*4882a593Smuzhiyun fen_info->tb_id, OFDPA_OP_FLAG_REMOVE);
2772*4882a593Smuzhiyun }
2773*4882a593Smuzhiyun
ofdpa_fib4_abort(struct rocker * rocker)2774*4882a593Smuzhiyun static void ofdpa_fib4_abort(struct rocker *rocker)
2775*4882a593Smuzhiyun {
2776*4882a593Smuzhiyun struct ofdpa *ofdpa = rocker->wpriv;
2777*4882a593Smuzhiyun struct ofdpa_port *ofdpa_port;
2778*4882a593Smuzhiyun struct ofdpa_flow_tbl_entry *flow_entry;
2779*4882a593Smuzhiyun struct hlist_node *tmp;
2780*4882a593Smuzhiyun unsigned long flags;
2781*4882a593Smuzhiyun int bkt;
2782*4882a593Smuzhiyun
2783*4882a593Smuzhiyun if (ofdpa->fib_aborted)
2784*4882a593Smuzhiyun return;
2785*4882a593Smuzhiyun
2786*4882a593Smuzhiyun spin_lock_irqsave(&ofdpa->flow_tbl_lock, flags);
2787*4882a593Smuzhiyun hash_for_each_safe(ofdpa->flow_tbl, bkt, tmp, flow_entry, entry) {
2788*4882a593Smuzhiyun struct fib_nh *nh;
2789*4882a593Smuzhiyun
2790*4882a593Smuzhiyun if (flow_entry->key.tbl_id !=
2791*4882a593Smuzhiyun ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING)
2792*4882a593Smuzhiyun continue;
2793*4882a593Smuzhiyun nh = fib_info_nh(flow_entry->fi, 0);
2794*4882a593Smuzhiyun ofdpa_port = ofdpa_port_dev_lower_find(nh->fib_nh_dev, rocker);
2795*4882a593Smuzhiyun if (!ofdpa_port)
2796*4882a593Smuzhiyun continue;
2797*4882a593Smuzhiyun nh->fib_nh_flags &= ~RTNH_F_OFFLOAD;
2798*4882a593Smuzhiyun ofdpa_flow_tbl_del(ofdpa_port,
2799*4882a593Smuzhiyun OFDPA_OP_FLAG_REMOVE | OFDPA_OP_FLAG_NOWAIT,
2800*4882a593Smuzhiyun flow_entry);
2801*4882a593Smuzhiyun }
2802*4882a593Smuzhiyun spin_unlock_irqrestore(&ofdpa->flow_tbl_lock, flags);
2803*4882a593Smuzhiyun ofdpa->fib_aborted = true;
2804*4882a593Smuzhiyun }
2805*4882a593Smuzhiyun
2806*4882a593Smuzhiyun struct rocker_world_ops rocker_ofdpa_ops = {
2807*4882a593Smuzhiyun .kind = "ofdpa",
2808*4882a593Smuzhiyun .priv_size = sizeof(struct ofdpa),
2809*4882a593Smuzhiyun .port_priv_size = sizeof(struct ofdpa_port),
2810*4882a593Smuzhiyun .mode = ROCKER_PORT_MODE_OF_DPA,
2811*4882a593Smuzhiyun .init = ofdpa_init,
2812*4882a593Smuzhiyun .fini = ofdpa_fini,
2813*4882a593Smuzhiyun .port_pre_init = ofdpa_port_pre_init,
2814*4882a593Smuzhiyun .port_init = ofdpa_port_init,
2815*4882a593Smuzhiyun .port_fini = ofdpa_port_fini,
2816*4882a593Smuzhiyun .port_open = ofdpa_port_open,
2817*4882a593Smuzhiyun .port_stop = ofdpa_port_stop,
2818*4882a593Smuzhiyun .port_attr_stp_state_set = ofdpa_port_attr_stp_state_set,
2819*4882a593Smuzhiyun .port_attr_bridge_flags_set = ofdpa_port_attr_bridge_flags_set,
2820*4882a593Smuzhiyun .port_attr_bridge_flags_support_get = ofdpa_port_attr_bridge_flags_support_get,
2821*4882a593Smuzhiyun .port_attr_bridge_ageing_time_set = ofdpa_port_attr_bridge_ageing_time_set,
2822*4882a593Smuzhiyun .port_obj_vlan_add = ofdpa_port_obj_vlan_add,
2823*4882a593Smuzhiyun .port_obj_vlan_del = ofdpa_port_obj_vlan_del,
2824*4882a593Smuzhiyun .port_obj_fdb_add = ofdpa_port_obj_fdb_add,
2825*4882a593Smuzhiyun .port_obj_fdb_del = ofdpa_port_obj_fdb_del,
2826*4882a593Smuzhiyun .port_master_linked = ofdpa_port_master_linked,
2827*4882a593Smuzhiyun .port_master_unlinked = ofdpa_port_master_unlinked,
2828*4882a593Smuzhiyun .port_neigh_update = ofdpa_port_neigh_update,
2829*4882a593Smuzhiyun .port_neigh_destroy = ofdpa_port_neigh_destroy,
2830*4882a593Smuzhiyun .port_ev_mac_vlan_seen = ofdpa_port_ev_mac_vlan_seen,
2831*4882a593Smuzhiyun .fib4_add = ofdpa_fib4_add,
2832*4882a593Smuzhiyun .fib4_del = ofdpa_fib4_del,
2833*4882a593Smuzhiyun .fib4_abort = ofdpa_fib4_abort,
2834*4882a593Smuzhiyun };
2835