1*4882a593Smuzhiyun // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2*4882a593Smuzhiyun /* Copyright (c) 2015-2018 Mellanox Technologies. All rights reserved */
3*4882a593Smuzhiyun
4*4882a593Smuzhiyun #include <linux/kernel.h>
5*4882a593Smuzhiyun #include <linux/types.h>
6*4882a593Smuzhiyun #include <linux/netdevice.h>
7*4882a593Smuzhiyun #include <linux/etherdevice.h>
8*4882a593Smuzhiyun #include <linux/slab.h>
9*4882a593Smuzhiyun #include <linux/device.h>
10*4882a593Smuzhiyun #include <linux/skbuff.h>
11*4882a593Smuzhiyun #include <linux/if_vlan.h>
12*4882a593Smuzhiyun #include <linux/if_bridge.h>
13*4882a593Smuzhiyun #include <linux/workqueue.h>
14*4882a593Smuzhiyun #include <linux/jiffies.h>
15*4882a593Smuzhiyun #include <linux/rtnetlink.h>
16*4882a593Smuzhiyun #include <linux/netlink.h>
17*4882a593Smuzhiyun #include <net/switchdev.h>
18*4882a593Smuzhiyun #include <net/vxlan.h>
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #include "spectrum_span.h"
21*4882a593Smuzhiyun #include "spectrum_switchdev.h"
22*4882a593Smuzhiyun #include "spectrum.h"
23*4882a593Smuzhiyun #include "core.h"
24*4882a593Smuzhiyun #include "reg.h"
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun struct mlxsw_sp_bridge_ops;
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun struct mlxsw_sp_bridge {
29*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp;
30*4882a593Smuzhiyun struct {
31*4882a593Smuzhiyun struct delayed_work dw;
32*4882a593Smuzhiyun #define MLXSW_SP_DEFAULT_LEARNING_INTERVAL 100
33*4882a593Smuzhiyun unsigned int interval; /* ms */
34*4882a593Smuzhiyun } fdb_notify;
35*4882a593Smuzhiyun #define MLXSW_SP_MIN_AGEING_TIME 10
36*4882a593Smuzhiyun #define MLXSW_SP_MAX_AGEING_TIME 1000000
37*4882a593Smuzhiyun #define MLXSW_SP_DEFAULT_AGEING_TIME 300
38*4882a593Smuzhiyun u32 ageing_time;
39*4882a593Smuzhiyun bool vlan_enabled_exists;
40*4882a593Smuzhiyun struct list_head bridges_list;
41*4882a593Smuzhiyun DECLARE_BITMAP(mids_bitmap, MLXSW_SP_MID_MAX);
42*4882a593Smuzhiyun const struct mlxsw_sp_bridge_ops *bridge_8021q_ops;
43*4882a593Smuzhiyun const struct mlxsw_sp_bridge_ops *bridge_8021d_ops;
44*4882a593Smuzhiyun };
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun struct mlxsw_sp_bridge_device {
47*4882a593Smuzhiyun struct net_device *dev;
48*4882a593Smuzhiyun struct list_head list;
49*4882a593Smuzhiyun struct list_head ports_list;
50*4882a593Smuzhiyun struct list_head mids_list;
51*4882a593Smuzhiyun u8 vlan_enabled:1,
52*4882a593Smuzhiyun multicast_enabled:1,
53*4882a593Smuzhiyun mrouter:1;
54*4882a593Smuzhiyun const struct mlxsw_sp_bridge_ops *ops;
55*4882a593Smuzhiyun };
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun struct mlxsw_sp_bridge_port {
58*4882a593Smuzhiyun struct net_device *dev;
59*4882a593Smuzhiyun struct mlxsw_sp_bridge_device *bridge_device;
60*4882a593Smuzhiyun struct list_head list;
61*4882a593Smuzhiyun struct list_head vlans_list;
62*4882a593Smuzhiyun unsigned int ref_count;
63*4882a593Smuzhiyun u8 stp_state;
64*4882a593Smuzhiyun unsigned long flags;
65*4882a593Smuzhiyun bool mrouter;
66*4882a593Smuzhiyun bool lagged;
67*4882a593Smuzhiyun union {
68*4882a593Smuzhiyun u16 lag_id;
69*4882a593Smuzhiyun u16 system_port;
70*4882a593Smuzhiyun };
71*4882a593Smuzhiyun };
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun struct mlxsw_sp_bridge_vlan {
74*4882a593Smuzhiyun struct list_head list;
75*4882a593Smuzhiyun struct list_head port_vlan_list;
76*4882a593Smuzhiyun u16 vid;
77*4882a593Smuzhiyun };
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun struct mlxsw_sp_bridge_ops {
80*4882a593Smuzhiyun int (*port_join)(struct mlxsw_sp_bridge_device *bridge_device,
81*4882a593Smuzhiyun struct mlxsw_sp_bridge_port *bridge_port,
82*4882a593Smuzhiyun struct mlxsw_sp_port *mlxsw_sp_port,
83*4882a593Smuzhiyun struct netlink_ext_ack *extack);
84*4882a593Smuzhiyun void (*port_leave)(struct mlxsw_sp_bridge_device *bridge_device,
85*4882a593Smuzhiyun struct mlxsw_sp_bridge_port *bridge_port,
86*4882a593Smuzhiyun struct mlxsw_sp_port *mlxsw_sp_port);
87*4882a593Smuzhiyun int (*vxlan_join)(struct mlxsw_sp_bridge_device *bridge_device,
88*4882a593Smuzhiyun const struct net_device *vxlan_dev, u16 vid,
89*4882a593Smuzhiyun struct netlink_ext_ack *extack);
90*4882a593Smuzhiyun struct mlxsw_sp_fid *
91*4882a593Smuzhiyun (*fid_get)(struct mlxsw_sp_bridge_device *bridge_device,
92*4882a593Smuzhiyun u16 vid, struct netlink_ext_ack *extack);
93*4882a593Smuzhiyun struct mlxsw_sp_fid *
94*4882a593Smuzhiyun (*fid_lookup)(struct mlxsw_sp_bridge_device *bridge_device,
95*4882a593Smuzhiyun u16 vid);
96*4882a593Smuzhiyun u16 (*fid_vid)(struct mlxsw_sp_bridge_device *bridge_device,
97*4882a593Smuzhiyun const struct mlxsw_sp_fid *fid);
98*4882a593Smuzhiyun };
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun static int
101*4882a593Smuzhiyun mlxsw_sp_bridge_port_fdb_flush(struct mlxsw_sp *mlxsw_sp,
102*4882a593Smuzhiyun struct mlxsw_sp_bridge_port *bridge_port,
103*4882a593Smuzhiyun u16 fid_index);
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun static void
106*4882a593Smuzhiyun mlxsw_sp_bridge_port_mdb_flush(struct mlxsw_sp_port *mlxsw_sp_port,
107*4882a593Smuzhiyun struct mlxsw_sp_bridge_port *bridge_port);
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun static void
110*4882a593Smuzhiyun mlxsw_sp_bridge_mdb_mc_enable_sync(struct mlxsw_sp_port *mlxsw_sp_port,
111*4882a593Smuzhiyun struct mlxsw_sp_bridge_device
112*4882a593Smuzhiyun *bridge_device);
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun static void
115*4882a593Smuzhiyun mlxsw_sp_port_mrouter_update_mdb(struct mlxsw_sp_port *mlxsw_sp_port,
116*4882a593Smuzhiyun struct mlxsw_sp_bridge_port *bridge_port,
117*4882a593Smuzhiyun bool add);
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun static struct mlxsw_sp_bridge_device *
mlxsw_sp_bridge_device_find(const struct mlxsw_sp_bridge * bridge,const struct net_device * br_dev)120*4882a593Smuzhiyun mlxsw_sp_bridge_device_find(const struct mlxsw_sp_bridge *bridge,
121*4882a593Smuzhiyun const struct net_device *br_dev)
122*4882a593Smuzhiyun {
123*4882a593Smuzhiyun struct mlxsw_sp_bridge_device *bridge_device;
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun list_for_each_entry(bridge_device, &bridge->bridges_list, list)
126*4882a593Smuzhiyun if (bridge_device->dev == br_dev)
127*4882a593Smuzhiyun return bridge_device;
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun return NULL;
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun
mlxsw_sp_bridge_device_is_offloaded(const struct mlxsw_sp * mlxsw_sp,const struct net_device * br_dev)132*4882a593Smuzhiyun bool mlxsw_sp_bridge_device_is_offloaded(const struct mlxsw_sp *mlxsw_sp,
133*4882a593Smuzhiyun const struct net_device *br_dev)
134*4882a593Smuzhiyun {
135*4882a593Smuzhiyun return !!mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, br_dev);
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun
mlxsw_sp_bridge_device_upper_rif_destroy(struct net_device * dev,struct netdev_nested_priv * priv)138*4882a593Smuzhiyun static int mlxsw_sp_bridge_device_upper_rif_destroy(struct net_device *dev,
139*4882a593Smuzhiyun struct netdev_nested_priv *priv)
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = priv->data;
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun mlxsw_sp_rif_destroy_by_dev(mlxsw_sp, dev);
144*4882a593Smuzhiyun return 0;
145*4882a593Smuzhiyun }
146*4882a593Smuzhiyun
mlxsw_sp_bridge_device_rifs_destroy(struct mlxsw_sp * mlxsw_sp,struct net_device * dev)147*4882a593Smuzhiyun static void mlxsw_sp_bridge_device_rifs_destroy(struct mlxsw_sp *mlxsw_sp,
148*4882a593Smuzhiyun struct net_device *dev)
149*4882a593Smuzhiyun {
150*4882a593Smuzhiyun struct netdev_nested_priv priv = {
151*4882a593Smuzhiyun .data = (void *)mlxsw_sp,
152*4882a593Smuzhiyun };
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun mlxsw_sp_rif_destroy_by_dev(mlxsw_sp, dev);
155*4882a593Smuzhiyun netdev_walk_all_upper_dev_rcu(dev,
156*4882a593Smuzhiyun mlxsw_sp_bridge_device_upper_rif_destroy,
157*4882a593Smuzhiyun &priv);
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun
mlxsw_sp_bridge_device_vxlan_init(struct mlxsw_sp_bridge * bridge,struct net_device * br_dev,struct netlink_ext_ack * extack)160*4882a593Smuzhiyun static int mlxsw_sp_bridge_device_vxlan_init(struct mlxsw_sp_bridge *bridge,
161*4882a593Smuzhiyun struct net_device *br_dev,
162*4882a593Smuzhiyun struct netlink_ext_ack *extack)
163*4882a593Smuzhiyun {
164*4882a593Smuzhiyun struct net_device *dev, *stop_dev;
165*4882a593Smuzhiyun struct list_head *iter;
166*4882a593Smuzhiyun int err;
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun netdev_for_each_lower_dev(br_dev, dev, iter) {
169*4882a593Smuzhiyun if (netif_is_vxlan(dev) && netif_running(dev)) {
170*4882a593Smuzhiyun err = mlxsw_sp_bridge_vxlan_join(bridge->mlxsw_sp,
171*4882a593Smuzhiyun br_dev, dev, 0,
172*4882a593Smuzhiyun extack);
173*4882a593Smuzhiyun if (err) {
174*4882a593Smuzhiyun stop_dev = dev;
175*4882a593Smuzhiyun goto err_vxlan_join;
176*4882a593Smuzhiyun }
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun return 0;
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun err_vxlan_join:
183*4882a593Smuzhiyun netdev_for_each_lower_dev(br_dev, dev, iter) {
184*4882a593Smuzhiyun if (netif_is_vxlan(dev) && netif_running(dev)) {
185*4882a593Smuzhiyun if (stop_dev == dev)
186*4882a593Smuzhiyun break;
187*4882a593Smuzhiyun mlxsw_sp_bridge_vxlan_leave(bridge->mlxsw_sp, dev);
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun }
190*4882a593Smuzhiyun return err;
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun
mlxsw_sp_bridge_device_vxlan_fini(struct mlxsw_sp_bridge * bridge,struct net_device * br_dev)193*4882a593Smuzhiyun static void mlxsw_sp_bridge_device_vxlan_fini(struct mlxsw_sp_bridge *bridge,
194*4882a593Smuzhiyun struct net_device *br_dev)
195*4882a593Smuzhiyun {
196*4882a593Smuzhiyun struct net_device *dev;
197*4882a593Smuzhiyun struct list_head *iter;
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun netdev_for_each_lower_dev(br_dev, dev, iter) {
200*4882a593Smuzhiyun if (netif_is_vxlan(dev) && netif_running(dev))
201*4882a593Smuzhiyun mlxsw_sp_bridge_vxlan_leave(bridge->mlxsw_sp, dev);
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun static struct mlxsw_sp_bridge_device *
mlxsw_sp_bridge_device_create(struct mlxsw_sp_bridge * bridge,struct net_device * br_dev,struct netlink_ext_ack * extack)206*4882a593Smuzhiyun mlxsw_sp_bridge_device_create(struct mlxsw_sp_bridge *bridge,
207*4882a593Smuzhiyun struct net_device *br_dev,
208*4882a593Smuzhiyun struct netlink_ext_ack *extack)
209*4882a593Smuzhiyun {
210*4882a593Smuzhiyun struct device *dev = bridge->mlxsw_sp->bus_info->dev;
211*4882a593Smuzhiyun struct mlxsw_sp_bridge_device *bridge_device;
212*4882a593Smuzhiyun bool vlan_enabled = br_vlan_enabled(br_dev);
213*4882a593Smuzhiyun int err;
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun if (vlan_enabled && bridge->vlan_enabled_exists) {
216*4882a593Smuzhiyun dev_err(dev, "Only one VLAN-aware bridge is supported\n");
217*4882a593Smuzhiyun NL_SET_ERR_MSG_MOD(extack, "Only one VLAN-aware bridge is supported");
218*4882a593Smuzhiyun return ERR_PTR(-EINVAL);
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun bridge_device = kzalloc(sizeof(*bridge_device), GFP_KERNEL);
222*4882a593Smuzhiyun if (!bridge_device)
223*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun bridge_device->dev = br_dev;
226*4882a593Smuzhiyun bridge_device->vlan_enabled = vlan_enabled;
227*4882a593Smuzhiyun bridge_device->multicast_enabled = br_multicast_enabled(br_dev);
228*4882a593Smuzhiyun bridge_device->mrouter = br_multicast_router(br_dev);
229*4882a593Smuzhiyun INIT_LIST_HEAD(&bridge_device->ports_list);
230*4882a593Smuzhiyun if (vlan_enabled) {
231*4882a593Smuzhiyun bridge->vlan_enabled_exists = true;
232*4882a593Smuzhiyun bridge_device->ops = bridge->bridge_8021q_ops;
233*4882a593Smuzhiyun } else {
234*4882a593Smuzhiyun bridge_device->ops = bridge->bridge_8021d_ops;
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun INIT_LIST_HEAD(&bridge_device->mids_list);
237*4882a593Smuzhiyun list_add(&bridge_device->list, &bridge->bridges_list);
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun /* It is possible we already have VXLAN devices enslaved to the bridge.
240*4882a593Smuzhiyun * In which case, we need to replay their configuration as if they were
241*4882a593Smuzhiyun * just now enslaved to the bridge.
242*4882a593Smuzhiyun */
243*4882a593Smuzhiyun err = mlxsw_sp_bridge_device_vxlan_init(bridge, br_dev, extack);
244*4882a593Smuzhiyun if (err)
245*4882a593Smuzhiyun goto err_vxlan_init;
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun return bridge_device;
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun err_vxlan_init:
250*4882a593Smuzhiyun list_del(&bridge_device->list);
251*4882a593Smuzhiyun if (bridge_device->vlan_enabled)
252*4882a593Smuzhiyun bridge->vlan_enabled_exists = false;
253*4882a593Smuzhiyun kfree(bridge_device);
254*4882a593Smuzhiyun return ERR_PTR(err);
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun static void
mlxsw_sp_bridge_device_destroy(struct mlxsw_sp_bridge * bridge,struct mlxsw_sp_bridge_device * bridge_device)258*4882a593Smuzhiyun mlxsw_sp_bridge_device_destroy(struct mlxsw_sp_bridge *bridge,
259*4882a593Smuzhiyun struct mlxsw_sp_bridge_device *bridge_device)
260*4882a593Smuzhiyun {
261*4882a593Smuzhiyun mlxsw_sp_bridge_device_vxlan_fini(bridge, bridge_device->dev);
262*4882a593Smuzhiyun mlxsw_sp_bridge_device_rifs_destroy(bridge->mlxsw_sp,
263*4882a593Smuzhiyun bridge_device->dev);
264*4882a593Smuzhiyun list_del(&bridge_device->list);
265*4882a593Smuzhiyun if (bridge_device->vlan_enabled)
266*4882a593Smuzhiyun bridge->vlan_enabled_exists = false;
267*4882a593Smuzhiyun WARN_ON(!list_empty(&bridge_device->ports_list));
268*4882a593Smuzhiyun WARN_ON(!list_empty(&bridge_device->mids_list));
269*4882a593Smuzhiyun kfree(bridge_device);
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun static struct mlxsw_sp_bridge_device *
mlxsw_sp_bridge_device_get(struct mlxsw_sp_bridge * bridge,struct net_device * br_dev,struct netlink_ext_ack * extack)273*4882a593Smuzhiyun mlxsw_sp_bridge_device_get(struct mlxsw_sp_bridge *bridge,
274*4882a593Smuzhiyun struct net_device *br_dev,
275*4882a593Smuzhiyun struct netlink_ext_ack *extack)
276*4882a593Smuzhiyun {
277*4882a593Smuzhiyun struct mlxsw_sp_bridge_device *bridge_device;
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun bridge_device = mlxsw_sp_bridge_device_find(bridge, br_dev);
280*4882a593Smuzhiyun if (bridge_device)
281*4882a593Smuzhiyun return bridge_device;
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun return mlxsw_sp_bridge_device_create(bridge, br_dev, extack);
284*4882a593Smuzhiyun }
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun static void
mlxsw_sp_bridge_device_put(struct mlxsw_sp_bridge * bridge,struct mlxsw_sp_bridge_device * bridge_device)287*4882a593Smuzhiyun mlxsw_sp_bridge_device_put(struct mlxsw_sp_bridge *bridge,
288*4882a593Smuzhiyun struct mlxsw_sp_bridge_device *bridge_device)
289*4882a593Smuzhiyun {
290*4882a593Smuzhiyun if (list_empty(&bridge_device->ports_list))
291*4882a593Smuzhiyun mlxsw_sp_bridge_device_destroy(bridge, bridge_device);
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun static struct mlxsw_sp_bridge_port *
__mlxsw_sp_bridge_port_find(const struct mlxsw_sp_bridge_device * bridge_device,const struct net_device * brport_dev)295*4882a593Smuzhiyun __mlxsw_sp_bridge_port_find(const struct mlxsw_sp_bridge_device *bridge_device,
296*4882a593Smuzhiyun const struct net_device *brport_dev)
297*4882a593Smuzhiyun {
298*4882a593Smuzhiyun struct mlxsw_sp_bridge_port *bridge_port;
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun list_for_each_entry(bridge_port, &bridge_device->ports_list, list) {
301*4882a593Smuzhiyun if (bridge_port->dev == brport_dev)
302*4882a593Smuzhiyun return bridge_port;
303*4882a593Smuzhiyun }
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun return NULL;
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun struct mlxsw_sp_bridge_port *
mlxsw_sp_bridge_port_find(struct mlxsw_sp_bridge * bridge,struct net_device * brport_dev)309*4882a593Smuzhiyun mlxsw_sp_bridge_port_find(struct mlxsw_sp_bridge *bridge,
310*4882a593Smuzhiyun struct net_device *brport_dev)
311*4882a593Smuzhiyun {
312*4882a593Smuzhiyun struct net_device *br_dev = netdev_master_upper_dev_get(brport_dev);
313*4882a593Smuzhiyun struct mlxsw_sp_bridge_device *bridge_device;
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun if (!br_dev)
316*4882a593Smuzhiyun return NULL;
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun bridge_device = mlxsw_sp_bridge_device_find(bridge, br_dev);
319*4882a593Smuzhiyun if (!bridge_device)
320*4882a593Smuzhiyun return NULL;
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun return __mlxsw_sp_bridge_port_find(bridge_device, brport_dev);
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun static struct mlxsw_sp_bridge_port *
mlxsw_sp_bridge_port_create(struct mlxsw_sp_bridge_device * bridge_device,struct net_device * brport_dev)326*4882a593Smuzhiyun mlxsw_sp_bridge_port_create(struct mlxsw_sp_bridge_device *bridge_device,
327*4882a593Smuzhiyun struct net_device *brport_dev)
328*4882a593Smuzhiyun {
329*4882a593Smuzhiyun struct mlxsw_sp_bridge_port *bridge_port;
330*4882a593Smuzhiyun struct mlxsw_sp_port *mlxsw_sp_port;
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun bridge_port = kzalloc(sizeof(*bridge_port), GFP_KERNEL);
333*4882a593Smuzhiyun if (!bridge_port)
334*4882a593Smuzhiyun return NULL;
335*4882a593Smuzhiyun
336*4882a593Smuzhiyun mlxsw_sp_port = mlxsw_sp_port_dev_lower_find(brport_dev);
337*4882a593Smuzhiyun bridge_port->lagged = mlxsw_sp_port->lagged;
338*4882a593Smuzhiyun if (bridge_port->lagged)
339*4882a593Smuzhiyun bridge_port->lag_id = mlxsw_sp_port->lag_id;
340*4882a593Smuzhiyun else
341*4882a593Smuzhiyun bridge_port->system_port = mlxsw_sp_port->local_port;
342*4882a593Smuzhiyun bridge_port->dev = brport_dev;
343*4882a593Smuzhiyun bridge_port->bridge_device = bridge_device;
344*4882a593Smuzhiyun bridge_port->stp_state = BR_STATE_DISABLED;
345*4882a593Smuzhiyun bridge_port->flags = BR_LEARNING | BR_FLOOD | BR_LEARNING_SYNC |
346*4882a593Smuzhiyun BR_MCAST_FLOOD;
347*4882a593Smuzhiyun INIT_LIST_HEAD(&bridge_port->vlans_list);
348*4882a593Smuzhiyun list_add(&bridge_port->list, &bridge_device->ports_list);
349*4882a593Smuzhiyun bridge_port->ref_count = 1;
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun return bridge_port;
352*4882a593Smuzhiyun }
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun static void
mlxsw_sp_bridge_port_destroy(struct mlxsw_sp_bridge_port * bridge_port)355*4882a593Smuzhiyun mlxsw_sp_bridge_port_destroy(struct mlxsw_sp_bridge_port *bridge_port)
356*4882a593Smuzhiyun {
357*4882a593Smuzhiyun list_del(&bridge_port->list);
358*4882a593Smuzhiyun WARN_ON(!list_empty(&bridge_port->vlans_list));
359*4882a593Smuzhiyun kfree(bridge_port);
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun static struct mlxsw_sp_bridge_port *
mlxsw_sp_bridge_port_get(struct mlxsw_sp_bridge * bridge,struct net_device * brport_dev,struct netlink_ext_ack * extack)363*4882a593Smuzhiyun mlxsw_sp_bridge_port_get(struct mlxsw_sp_bridge *bridge,
364*4882a593Smuzhiyun struct net_device *brport_dev,
365*4882a593Smuzhiyun struct netlink_ext_ack *extack)
366*4882a593Smuzhiyun {
367*4882a593Smuzhiyun struct net_device *br_dev = netdev_master_upper_dev_get(brport_dev);
368*4882a593Smuzhiyun struct mlxsw_sp_bridge_device *bridge_device;
369*4882a593Smuzhiyun struct mlxsw_sp_bridge_port *bridge_port;
370*4882a593Smuzhiyun int err;
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun bridge_port = mlxsw_sp_bridge_port_find(bridge, brport_dev);
373*4882a593Smuzhiyun if (bridge_port) {
374*4882a593Smuzhiyun bridge_port->ref_count++;
375*4882a593Smuzhiyun return bridge_port;
376*4882a593Smuzhiyun }
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun bridge_device = mlxsw_sp_bridge_device_get(bridge, br_dev, extack);
379*4882a593Smuzhiyun if (IS_ERR(bridge_device))
380*4882a593Smuzhiyun return ERR_CAST(bridge_device);
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun bridge_port = mlxsw_sp_bridge_port_create(bridge_device, brport_dev);
383*4882a593Smuzhiyun if (!bridge_port) {
384*4882a593Smuzhiyun err = -ENOMEM;
385*4882a593Smuzhiyun goto err_bridge_port_create;
386*4882a593Smuzhiyun }
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun return bridge_port;
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun err_bridge_port_create:
391*4882a593Smuzhiyun mlxsw_sp_bridge_device_put(bridge, bridge_device);
392*4882a593Smuzhiyun return ERR_PTR(err);
393*4882a593Smuzhiyun }
394*4882a593Smuzhiyun
mlxsw_sp_bridge_port_put(struct mlxsw_sp_bridge * bridge,struct mlxsw_sp_bridge_port * bridge_port)395*4882a593Smuzhiyun static void mlxsw_sp_bridge_port_put(struct mlxsw_sp_bridge *bridge,
396*4882a593Smuzhiyun struct mlxsw_sp_bridge_port *bridge_port)
397*4882a593Smuzhiyun {
398*4882a593Smuzhiyun struct mlxsw_sp_bridge_device *bridge_device;
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun if (--bridge_port->ref_count != 0)
401*4882a593Smuzhiyun return;
402*4882a593Smuzhiyun bridge_device = bridge_port->bridge_device;
403*4882a593Smuzhiyun mlxsw_sp_bridge_port_destroy(bridge_port);
404*4882a593Smuzhiyun mlxsw_sp_bridge_device_put(bridge, bridge_device);
405*4882a593Smuzhiyun }
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun static struct mlxsw_sp_port_vlan *
mlxsw_sp_port_vlan_find_by_bridge(struct mlxsw_sp_port * mlxsw_sp_port,const struct mlxsw_sp_bridge_device * bridge_device,u16 vid)408*4882a593Smuzhiyun mlxsw_sp_port_vlan_find_by_bridge(struct mlxsw_sp_port *mlxsw_sp_port,
409*4882a593Smuzhiyun const struct mlxsw_sp_bridge_device *
410*4882a593Smuzhiyun bridge_device,
411*4882a593Smuzhiyun u16 vid)
412*4882a593Smuzhiyun {
413*4882a593Smuzhiyun struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list,
416*4882a593Smuzhiyun list) {
417*4882a593Smuzhiyun if (!mlxsw_sp_port_vlan->bridge_port)
418*4882a593Smuzhiyun continue;
419*4882a593Smuzhiyun if (mlxsw_sp_port_vlan->bridge_port->bridge_device !=
420*4882a593Smuzhiyun bridge_device)
421*4882a593Smuzhiyun continue;
422*4882a593Smuzhiyun if (bridge_device->vlan_enabled &&
423*4882a593Smuzhiyun mlxsw_sp_port_vlan->vid != vid)
424*4882a593Smuzhiyun continue;
425*4882a593Smuzhiyun return mlxsw_sp_port_vlan;
426*4882a593Smuzhiyun }
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun return NULL;
429*4882a593Smuzhiyun }
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun static struct mlxsw_sp_port_vlan*
mlxsw_sp_port_vlan_find_by_fid(struct mlxsw_sp_port * mlxsw_sp_port,u16 fid_index)432*4882a593Smuzhiyun mlxsw_sp_port_vlan_find_by_fid(struct mlxsw_sp_port *mlxsw_sp_port,
433*4882a593Smuzhiyun u16 fid_index)
434*4882a593Smuzhiyun {
435*4882a593Smuzhiyun struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list,
438*4882a593Smuzhiyun list) {
439*4882a593Smuzhiyun struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun if (fid && mlxsw_sp_fid_index(fid) == fid_index)
442*4882a593Smuzhiyun return mlxsw_sp_port_vlan;
443*4882a593Smuzhiyun }
444*4882a593Smuzhiyun
445*4882a593Smuzhiyun return NULL;
446*4882a593Smuzhiyun }
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun static struct mlxsw_sp_bridge_vlan *
mlxsw_sp_bridge_vlan_find(const struct mlxsw_sp_bridge_port * bridge_port,u16 vid)449*4882a593Smuzhiyun mlxsw_sp_bridge_vlan_find(const struct mlxsw_sp_bridge_port *bridge_port,
450*4882a593Smuzhiyun u16 vid)
451*4882a593Smuzhiyun {
452*4882a593Smuzhiyun struct mlxsw_sp_bridge_vlan *bridge_vlan;
453*4882a593Smuzhiyun
454*4882a593Smuzhiyun list_for_each_entry(bridge_vlan, &bridge_port->vlans_list, list) {
455*4882a593Smuzhiyun if (bridge_vlan->vid == vid)
456*4882a593Smuzhiyun return bridge_vlan;
457*4882a593Smuzhiyun }
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun return NULL;
460*4882a593Smuzhiyun }
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun static struct mlxsw_sp_bridge_vlan *
mlxsw_sp_bridge_vlan_create(struct mlxsw_sp_bridge_port * bridge_port,u16 vid)463*4882a593Smuzhiyun mlxsw_sp_bridge_vlan_create(struct mlxsw_sp_bridge_port *bridge_port, u16 vid)
464*4882a593Smuzhiyun {
465*4882a593Smuzhiyun struct mlxsw_sp_bridge_vlan *bridge_vlan;
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun bridge_vlan = kzalloc(sizeof(*bridge_vlan), GFP_KERNEL);
468*4882a593Smuzhiyun if (!bridge_vlan)
469*4882a593Smuzhiyun return NULL;
470*4882a593Smuzhiyun
471*4882a593Smuzhiyun INIT_LIST_HEAD(&bridge_vlan->port_vlan_list);
472*4882a593Smuzhiyun bridge_vlan->vid = vid;
473*4882a593Smuzhiyun list_add(&bridge_vlan->list, &bridge_port->vlans_list);
474*4882a593Smuzhiyun
475*4882a593Smuzhiyun return bridge_vlan;
476*4882a593Smuzhiyun }
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun static void
mlxsw_sp_bridge_vlan_destroy(struct mlxsw_sp_bridge_vlan * bridge_vlan)479*4882a593Smuzhiyun mlxsw_sp_bridge_vlan_destroy(struct mlxsw_sp_bridge_vlan *bridge_vlan)
480*4882a593Smuzhiyun {
481*4882a593Smuzhiyun list_del(&bridge_vlan->list);
482*4882a593Smuzhiyun WARN_ON(!list_empty(&bridge_vlan->port_vlan_list));
483*4882a593Smuzhiyun kfree(bridge_vlan);
484*4882a593Smuzhiyun }
485*4882a593Smuzhiyun
486*4882a593Smuzhiyun static struct mlxsw_sp_bridge_vlan *
mlxsw_sp_bridge_vlan_get(struct mlxsw_sp_bridge_port * bridge_port,u16 vid)487*4882a593Smuzhiyun mlxsw_sp_bridge_vlan_get(struct mlxsw_sp_bridge_port *bridge_port, u16 vid)
488*4882a593Smuzhiyun {
489*4882a593Smuzhiyun struct mlxsw_sp_bridge_vlan *bridge_vlan;
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun bridge_vlan = mlxsw_sp_bridge_vlan_find(bridge_port, vid);
492*4882a593Smuzhiyun if (bridge_vlan)
493*4882a593Smuzhiyun return bridge_vlan;
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun return mlxsw_sp_bridge_vlan_create(bridge_port, vid);
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun
mlxsw_sp_bridge_vlan_put(struct mlxsw_sp_bridge_vlan * bridge_vlan)498*4882a593Smuzhiyun static void mlxsw_sp_bridge_vlan_put(struct mlxsw_sp_bridge_vlan *bridge_vlan)
499*4882a593Smuzhiyun {
500*4882a593Smuzhiyun if (list_empty(&bridge_vlan->port_vlan_list))
501*4882a593Smuzhiyun mlxsw_sp_bridge_vlan_destroy(bridge_vlan);
502*4882a593Smuzhiyun }
503*4882a593Smuzhiyun
504*4882a593Smuzhiyun static int
mlxsw_sp_port_bridge_vlan_stp_set(struct mlxsw_sp_port * mlxsw_sp_port,struct mlxsw_sp_bridge_vlan * bridge_vlan,u8 state)505*4882a593Smuzhiyun mlxsw_sp_port_bridge_vlan_stp_set(struct mlxsw_sp_port *mlxsw_sp_port,
506*4882a593Smuzhiyun struct mlxsw_sp_bridge_vlan *bridge_vlan,
507*4882a593Smuzhiyun u8 state)
508*4882a593Smuzhiyun {
509*4882a593Smuzhiyun struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
510*4882a593Smuzhiyun
511*4882a593Smuzhiyun list_for_each_entry(mlxsw_sp_port_vlan, &bridge_vlan->port_vlan_list,
512*4882a593Smuzhiyun bridge_vlan_node) {
513*4882a593Smuzhiyun if (mlxsw_sp_port_vlan->mlxsw_sp_port != mlxsw_sp_port)
514*4882a593Smuzhiyun continue;
515*4882a593Smuzhiyun return mlxsw_sp_port_vid_stp_set(mlxsw_sp_port,
516*4882a593Smuzhiyun bridge_vlan->vid, state);
517*4882a593Smuzhiyun }
518*4882a593Smuzhiyun
519*4882a593Smuzhiyun return 0;
520*4882a593Smuzhiyun }
521*4882a593Smuzhiyun
mlxsw_sp_port_attr_stp_state_set(struct mlxsw_sp_port * mlxsw_sp_port,struct switchdev_trans * trans,struct net_device * orig_dev,u8 state)522*4882a593Smuzhiyun static int mlxsw_sp_port_attr_stp_state_set(struct mlxsw_sp_port *mlxsw_sp_port,
523*4882a593Smuzhiyun struct switchdev_trans *trans,
524*4882a593Smuzhiyun struct net_device *orig_dev,
525*4882a593Smuzhiyun u8 state)
526*4882a593Smuzhiyun {
527*4882a593Smuzhiyun struct mlxsw_sp_bridge_port *bridge_port;
528*4882a593Smuzhiyun struct mlxsw_sp_bridge_vlan *bridge_vlan;
529*4882a593Smuzhiyun int err;
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun if (switchdev_trans_ph_prepare(trans))
532*4882a593Smuzhiyun return 0;
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun /* It's possible we failed to enslave the port, yet this
535*4882a593Smuzhiyun * operation is executed due to it being deferred.
536*4882a593Smuzhiyun */
537*4882a593Smuzhiyun bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp_port->mlxsw_sp->bridge,
538*4882a593Smuzhiyun orig_dev);
539*4882a593Smuzhiyun if (!bridge_port)
540*4882a593Smuzhiyun return 0;
541*4882a593Smuzhiyun
542*4882a593Smuzhiyun list_for_each_entry(bridge_vlan, &bridge_port->vlans_list, list) {
543*4882a593Smuzhiyun err = mlxsw_sp_port_bridge_vlan_stp_set(mlxsw_sp_port,
544*4882a593Smuzhiyun bridge_vlan, state);
545*4882a593Smuzhiyun if (err)
546*4882a593Smuzhiyun goto err_port_bridge_vlan_stp_set;
547*4882a593Smuzhiyun }
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun bridge_port->stp_state = state;
550*4882a593Smuzhiyun
551*4882a593Smuzhiyun return 0;
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun err_port_bridge_vlan_stp_set:
554*4882a593Smuzhiyun list_for_each_entry_continue_reverse(bridge_vlan,
555*4882a593Smuzhiyun &bridge_port->vlans_list, list)
556*4882a593Smuzhiyun mlxsw_sp_port_bridge_vlan_stp_set(mlxsw_sp_port, bridge_vlan,
557*4882a593Smuzhiyun bridge_port->stp_state);
558*4882a593Smuzhiyun return err;
559*4882a593Smuzhiyun }
560*4882a593Smuzhiyun
561*4882a593Smuzhiyun static int
mlxsw_sp_port_bridge_vlan_flood_set(struct mlxsw_sp_port * mlxsw_sp_port,struct mlxsw_sp_bridge_vlan * bridge_vlan,enum mlxsw_sp_flood_type packet_type,bool member)562*4882a593Smuzhiyun mlxsw_sp_port_bridge_vlan_flood_set(struct mlxsw_sp_port *mlxsw_sp_port,
563*4882a593Smuzhiyun struct mlxsw_sp_bridge_vlan *bridge_vlan,
564*4882a593Smuzhiyun enum mlxsw_sp_flood_type packet_type,
565*4882a593Smuzhiyun bool member)
566*4882a593Smuzhiyun {
567*4882a593Smuzhiyun struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
568*4882a593Smuzhiyun
569*4882a593Smuzhiyun list_for_each_entry(mlxsw_sp_port_vlan, &bridge_vlan->port_vlan_list,
570*4882a593Smuzhiyun bridge_vlan_node) {
571*4882a593Smuzhiyun if (mlxsw_sp_port_vlan->mlxsw_sp_port != mlxsw_sp_port)
572*4882a593Smuzhiyun continue;
573*4882a593Smuzhiyun return mlxsw_sp_fid_flood_set(mlxsw_sp_port_vlan->fid,
574*4882a593Smuzhiyun packet_type,
575*4882a593Smuzhiyun mlxsw_sp_port->local_port,
576*4882a593Smuzhiyun member);
577*4882a593Smuzhiyun }
578*4882a593Smuzhiyun
579*4882a593Smuzhiyun return 0;
580*4882a593Smuzhiyun }
581*4882a593Smuzhiyun
582*4882a593Smuzhiyun static int
mlxsw_sp_bridge_port_flood_table_set(struct mlxsw_sp_port * mlxsw_sp_port,struct mlxsw_sp_bridge_port * bridge_port,enum mlxsw_sp_flood_type packet_type,bool member)583*4882a593Smuzhiyun mlxsw_sp_bridge_port_flood_table_set(struct mlxsw_sp_port *mlxsw_sp_port,
584*4882a593Smuzhiyun struct mlxsw_sp_bridge_port *bridge_port,
585*4882a593Smuzhiyun enum mlxsw_sp_flood_type packet_type,
586*4882a593Smuzhiyun bool member)
587*4882a593Smuzhiyun {
588*4882a593Smuzhiyun struct mlxsw_sp_bridge_vlan *bridge_vlan;
589*4882a593Smuzhiyun int err;
590*4882a593Smuzhiyun
591*4882a593Smuzhiyun list_for_each_entry(bridge_vlan, &bridge_port->vlans_list, list) {
592*4882a593Smuzhiyun err = mlxsw_sp_port_bridge_vlan_flood_set(mlxsw_sp_port,
593*4882a593Smuzhiyun bridge_vlan,
594*4882a593Smuzhiyun packet_type,
595*4882a593Smuzhiyun member);
596*4882a593Smuzhiyun if (err)
597*4882a593Smuzhiyun goto err_port_bridge_vlan_flood_set;
598*4882a593Smuzhiyun }
599*4882a593Smuzhiyun
600*4882a593Smuzhiyun return 0;
601*4882a593Smuzhiyun
602*4882a593Smuzhiyun err_port_bridge_vlan_flood_set:
603*4882a593Smuzhiyun list_for_each_entry_continue_reverse(bridge_vlan,
604*4882a593Smuzhiyun &bridge_port->vlans_list, list)
605*4882a593Smuzhiyun mlxsw_sp_port_bridge_vlan_flood_set(mlxsw_sp_port, bridge_vlan,
606*4882a593Smuzhiyun packet_type, !member);
607*4882a593Smuzhiyun return err;
608*4882a593Smuzhiyun }
609*4882a593Smuzhiyun
610*4882a593Smuzhiyun static int
mlxsw_sp_port_bridge_vlan_learning_set(struct mlxsw_sp_port * mlxsw_sp_port,struct mlxsw_sp_bridge_vlan * bridge_vlan,bool set)611*4882a593Smuzhiyun mlxsw_sp_port_bridge_vlan_learning_set(struct mlxsw_sp_port *mlxsw_sp_port,
612*4882a593Smuzhiyun struct mlxsw_sp_bridge_vlan *bridge_vlan,
613*4882a593Smuzhiyun bool set)
614*4882a593Smuzhiyun {
615*4882a593Smuzhiyun struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
616*4882a593Smuzhiyun u16 vid = bridge_vlan->vid;
617*4882a593Smuzhiyun
618*4882a593Smuzhiyun list_for_each_entry(mlxsw_sp_port_vlan, &bridge_vlan->port_vlan_list,
619*4882a593Smuzhiyun bridge_vlan_node) {
620*4882a593Smuzhiyun if (mlxsw_sp_port_vlan->mlxsw_sp_port != mlxsw_sp_port)
621*4882a593Smuzhiyun continue;
622*4882a593Smuzhiyun return mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, set);
623*4882a593Smuzhiyun }
624*4882a593Smuzhiyun
625*4882a593Smuzhiyun return 0;
626*4882a593Smuzhiyun }
627*4882a593Smuzhiyun
628*4882a593Smuzhiyun static int
mlxsw_sp_bridge_port_learning_set(struct mlxsw_sp_port * mlxsw_sp_port,struct mlxsw_sp_bridge_port * bridge_port,bool set)629*4882a593Smuzhiyun mlxsw_sp_bridge_port_learning_set(struct mlxsw_sp_port *mlxsw_sp_port,
630*4882a593Smuzhiyun struct mlxsw_sp_bridge_port *bridge_port,
631*4882a593Smuzhiyun bool set)
632*4882a593Smuzhiyun {
633*4882a593Smuzhiyun struct mlxsw_sp_bridge_vlan *bridge_vlan;
634*4882a593Smuzhiyun int err;
635*4882a593Smuzhiyun
636*4882a593Smuzhiyun list_for_each_entry(bridge_vlan, &bridge_port->vlans_list, list) {
637*4882a593Smuzhiyun err = mlxsw_sp_port_bridge_vlan_learning_set(mlxsw_sp_port,
638*4882a593Smuzhiyun bridge_vlan, set);
639*4882a593Smuzhiyun if (err)
640*4882a593Smuzhiyun goto err_port_bridge_vlan_learning_set;
641*4882a593Smuzhiyun }
642*4882a593Smuzhiyun
643*4882a593Smuzhiyun return 0;
644*4882a593Smuzhiyun
645*4882a593Smuzhiyun err_port_bridge_vlan_learning_set:
646*4882a593Smuzhiyun list_for_each_entry_continue_reverse(bridge_vlan,
647*4882a593Smuzhiyun &bridge_port->vlans_list, list)
648*4882a593Smuzhiyun mlxsw_sp_port_bridge_vlan_learning_set(mlxsw_sp_port,
649*4882a593Smuzhiyun bridge_vlan, !set);
650*4882a593Smuzhiyun return err;
651*4882a593Smuzhiyun }
652*4882a593Smuzhiyun
mlxsw_sp_port_attr_br_pre_flags_set(struct mlxsw_sp_port * mlxsw_sp_port,struct switchdev_trans * trans,unsigned long brport_flags)653*4882a593Smuzhiyun static int mlxsw_sp_port_attr_br_pre_flags_set(struct mlxsw_sp_port
654*4882a593Smuzhiyun *mlxsw_sp_port,
655*4882a593Smuzhiyun struct switchdev_trans *trans,
656*4882a593Smuzhiyun unsigned long brport_flags)
657*4882a593Smuzhiyun {
658*4882a593Smuzhiyun if (brport_flags & ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD))
659*4882a593Smuzhiyun return -EINVAL;
660*4882a593Smuzhiyun
661*4882a593Smuzhiyun return 0;
662*4882a593Smuzhiyun }
663*4882a593Smuzhiyun
mlxsw_sp_port_attr_br_flags_set(struct mlxsw_sp_port * mlxsw_sp_port,struct switchdev_trans * trans,struct net_device * orig_dev,unsigned long brport_flags)664*4882a593Smuzhiyun static int mlxsw_sp_port_attr_br_flags_set(struct mlxsw_sp_port *mlxsw_sp_port,
665*4882a593Smuzhiyun struct switchdev_trans *trans,
666*4882a593Smuzhiyun struct net_device *orig_dev,
667*4882a593Smuzhiyun unsigned long brport_flags)
668*4882a593Smuzhiyun {
669*4882a593Smuzhiyun struct mlxsw_sp_bridge_port *bridge_port;
670*4882a593Smuzhiyun int err;
671*4882a593Smuzhiyun
672*4882a593Smuzhiyun if (switchdev_trans_ph_prepare(trans))
673*4882a593Smuzhiyun return 0;
674*4882a593Smuzhiyun
675*4882a593Smuzhiyun bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp_port->mlxsw_sp->bridge,
676*4882a593Smuzhiyun orig_dev);
677*4882a593Smuzhiyun if (!bridge_port)
678*4882a593Smuzhiyun return 0;
679*4882a593Smuzhiyun
680*4882a593Smuzhiyun err = mlxsw_sp_bridge_port_flood_table_set(mlxsw_sp_port, bridge_port,
681*4882a593Smuzhiyun MLXSW_SP_FLOOD_TYPE_UC,
682*4882a593Smuzhiyun brport_flags & BR_FLOOD);
683*4882a593Smuzhiyun if (err)
684*4882a593Smuzhiyun return err;
685*4882a593Smuzhiyun
686*4882a593Smuzhiyun err = mlxsw_sp_bridge_port_learning_set(mlxsw_sp_port, bridge_port,
687*4882a593Smuzhiyun brport_flags & BR_LEARNING);
688*4882a593Smuzhiyun if (err)
689*4882a593Smuzhiyun return err;
690*4882a593Smuzhiyun
691*4882a593Smuzhiyun if (bridge_port->bridge_device->multicast_enabled)
692*4882a593Smuzhiyun goto out;
693*4882a593Smuzhiyun
694*4882a593Smuzhiyun err = mlxsw_sp_bridge_port_flood_table_set(mlxsw_sp_port, bridge_port,
695*4882a593Smuzhiyun MLXSW_SP_FLOOD_TYPE_MC,
696*4882a593Smuzhiyun brport_flags &
697*4882a593Smuzhiyun BR_MCAST_FLOOD);
698*4882a593Smuzhiyun if (err)
699*4882a593Smuzhiyun return err;
700*4882a593Smuzhiyun
701*4882a593Smuzhiyun out:
702*4882a593Smuzhiyun memcpy(&bridge_port->flags, &brport_flags, sizeof(brport_flags));
703*4882a593Smuzhiyun return 0;
704*4882a593Smuzhiyun }
705*4882a593Smuzhiyun
mlxsw_sp_ageing_set(struct mlxsw_sp * mlxsw_sp,u32 ageing_time)706*4882a593Smuzhiyun static int mlxsw_sp_ageing_set(struct mlxsw_sp *mlxsw_sp, u32 ageing_time)
707*4882a593Smuzhiyun {
708*4882a593Smuzhiyun char sfdat_pl[MLXSW_REG_SFDAT_LEN];
709*4882a593Smuzhiyun int err;
710*4882a593Smuzhiyun
711*4882a593Smuzhiyun mlxsw_reg_sfdat_pack(sfdat_pl, ageing_time);
712*4882a593Smuzhiyun err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfdat), sfdat_pl);
713*4882a593Smuzhiyun if (err)
714*4882a593Smuzhiyun return err;
715*4882a593Smuzhiyun mlxsw_sp->bridge->ageing_time = ageing_time;
716*4882a593Smuzhiyun return 0;
717*4882a593Smuzhiyun }
718*4882a593Smuzhiyun
mlxsw_sp_port_attr_br_ageing_set(struct mlxsw_sp_port * mlxsw_sp_port,struct switchdev_trans * trans,unsigned long ageing_clock_t)719*4882a593Smuzhiyun static int mlxsw_sp_port_attr_br_ageing_set(struct mlxsw_sp_port *mlxsw_sp_port,
720*4882a593Smuzhiyun struct switchdev_trans *trans,
721*4882a593Smuzhiyun unsigned long ageing_clock_t)
722*4882a593Smuzhiyun {
723*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
724*4882a593Smuzhiyun unsigned long ageing_jiffies = clock_t_to_jiffies(ageing_clock_t);
725*4882a593Smuzhiyun u32 ageing_time = jiffies_to_msecs(ageing_jiffies) / 1000;
726*4882a593Smuzhiyun
727*4882a593Smuzhiyun if (switchdev_trans_ph_prepare(trans)) {
728*4882a593Smuzhiyun if (ageing_time < MLXSW_SP_MIN_AGEING_TIME ||
729*4882a593Smuzhiyun ageing_time > MLXSW_SP_MAX_AGEING_TIME)
730*4882a593Smuzhiyun return -ERANGE;
731*4882a593Smuzhiyun else
732*4882a593Smuzhiyun return 0;
733*4882a593Smuzhiyun }
734*4882a593Smuzhiyun
735*4882a593Smuzhiyun return mlxsw_sp_ageing_set(mlxsw_sp, ageing_time);
736*4882a593Smuzhiyun }
737*4882a593Smuzhiyun
mlxsw_sp_port_attr_br_vlan_set(struct mlxsw_sp_port * mlxsw_sp_port,struct switchdev_trans * trans,struct net_device * orig_dev,bool vlan_enabled)738*4882a593Smuzhiyun static int mlxsw_sp_port_attr_br_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port,
739*4882a593Smuzhiyun struct switchdev_trans *trans,
740*4882a593Smuzhiyun struct net_device *orig_dev,
741*4882a593Smuzhiyun bool vlan_enabled)
742*4882a593Smuzhiyun {
743*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
744*4882a593Smuzhiyun struct mlxsw_sp_bridge_device *bridge_device;
745*4882a593Smuzhiyun
746*4882a593Smuzhiyun if (!switchdev_trans_ph_prepare(trans))
747*4882a593Smuzhiyun return 0;
748*4882a593Smuzhiyun
749*4882a593Smuzhiyun bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, orig_dev);
750*4882a593Smuzhiyun if (WARN_ON(!bridge_device))
751*4882a593Smuzhiyun return -EINVAL;
752*4882a593Smuzhiyun
753*4882a593Smuzhiyun if (bridge_device->vlan_enabled == vlan_enabled)
754*4882a593Smuzhiyun return 0;
755*4882a593Smuzhiyun
756*4882a593Smuzhiyun netdev_err(bridge_device->dev, "VLAN filtering can't be changed for existing bridge\n");
757*4882a593Smuzhiyun return -EINVAL;
758*4882a593Smuzhiyun }
759*4882a593Smuzhiyun
mlxsw_sp_port_attr_mrouter_set(struct mlxsw_sp_port * mlxsw_sp_port,struct switchdev_trans * trans,struct net_device * orig_dev,bool is_port_mrouter)760*4882a593Smuzhiyun static int mlxsw_sp_port_attr_mrouter_set(struct mlxsw_sp_port *mlxsw_sp_port,
761*4882a593Smuzhiyun struct switchdev_trans *trans,
762*4882a593Smuzhiyun struct net_device *orig_dev,
763*4882a593Smuzhiyun bool is_port_mrouter)
764*4882a593Smuzhiyun {
765*4882a593Smuzhiyun struct mlxsw_sp_bridge_port *bridge_port;
766*4882a593Smuzhiyun int err;
767*4882a593Smuzhiyun
768*4882a593Smuzhiyun if (switchdev_trans_ph_prepare(trans))
769*4882a593Smuzhiyun return 0;
770*4882a593Smuzhiyun
771*4882a593Smuzhiyun bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp_port->mlxsw_sp->bridge,
772*4882a593Smuzhiyun orig_dev);
773*4882a593Smuzhiyun if (!bridge_port)
774*4882a593Smuzhiyun return 0;
775*4882a593Smuzhiyun
776*4882a593Smuzhiyun if (!bridge_port->bridge_device->multicast_enabled)
777*4882a593Smuzhiyun goto out;
778*4882a593Smuzhiyun
779*4882a593Smuzhiyun err = mlxsw_sp_bridge_port_flood_table_set(mlxsw_sp_port, bridge_port,
780*4882a593Smuzhiyun MLXSW_SP_FLOOD_TYPE_MC,
781*4882a593Smuzhiyun is_port_mrouter);
782*4882a593Smuzhiyun if (err)
783*4882a593Smuzhiyun return err;
784*4882a593Smuzhiyun
785*4882a593Smuzhiyun mlxsw_sp_port_mrouter_update_mdb(mlxsw_sp_port, bridge_port,
786*4882a593Smuzhiyun is_port_mrouter);
787*4882a593Smuzhiyun out:
788*4882a593Smuzhiyun bridge_port->mrouter = is_port_mrouter;
789*4882a593Smuzhiyun return 0;
790*4882a593Smuzhiyun }
791*4882a593Smuzhiyun
mlxsw_sp_mc_flood(const struct mlxsw_sp_bridge_port * bridge_port)792*4882a593Smuzhiyun static bool mlxsw_sp_mc_flood(const struct mlxsw_sp_bridge_port *bridge_port)
793*4882a593Smuzhiyun {
794*4882a593Smuzhiyun const struct mlxsw_sp_bridge_device *bridge_device;
795*4882a593Smuzhiyun
796*4882a593Smuzhiyun bridge_device = bridge_port->bridge_device;
797*4882a593Smuzhiyun return bridge_device->multicast_enabled ? bridge_port->mrouter :
798*4882a593Smuzhiyun bridge_port->flags & BR_MCAST_FLOOD;
799*4882a593Smuzhiyun }
800*4882a593Smuzhiyun
mlxsw_sp_port_mc_disabled_set(struct mlxsw_sp_port * mlxsw_sp_port,struct switchdev_trans * trans,struct net_device * orig_dev,bool mc_disabled)801*4882a593Smuzhiyun static int mlxsw_sp_port_mc_disabled_set(struct mlxsw_sp_port *mlxsw_sp_port,
802*4882a593Smuzhiyun struct switchdev_trans *trans,
803*4882a593Smuzhiyun struct net_device *orig_dev,
804*4882a593Smuzhiyun bool mc_disabled)
805*4882a593Smuzhiyun {
806*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
807*4882a593Smuzhiyun struct mlxsw_sp_bridge_device *bridge_device;
808*4882a593Smuzhiyun struct mlxsw_sp_bridge_port *bridge_port;
809*4882a593Smuzhiyun int err;
810*4882a593Smuzhiyun
811*4882a593Smuzhiyun if (switchdev_trans_ph_prepare(trans))
812*4882a593Smuzhiyun return 0;
813*4882a593Smuzhiyun
814*4882a593Smuzhiyun /* It's possible we failed to enslave the port, yet this
815*4882a593Smuzhiyun * operation is executed due to it being deferred.
816*4882a593Smuzhiyun */
817*4882a593Smuzhiyun bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, orig_dev);
818*4882a593Smuzhiyun if (!bridge_device)
819*4882a593Smuzhiyun return 0;
820*4882a593Smuzhiyun
821*4882a593Smuzhiyun if (bridge_device->multicast_enabled != !mc_disabled) {
822*4882a593Smuzhiyun bridge_device->multicast_enabled = !mc_disabled;
823*4882a593Smuzhiyun mlxsw_sp_bridge_mdb_mc_enable_sync(mlxsw_sp_port,
824*4882a593Smuzhiyun bridge_device);
825*4882a593Smuzhiyun }
826*4882a593Smuzhiyun
827*4882a593Smuzhiyun list_for_each_entry(bridge_port, &bridge_device->ports_list, list) {
828*4882a593Smuzhiyun enum mlxsw_sp_flood_type packet_type = MLXSW_SP_FLOOD_TYPE_MC;
829*4882a593Smuzhiyun bool member = mlxsw_sp_mc_flood(bridge_port);
830*4882a593Smuzhiyun
831*4882a593Smuzhiyun err = mlxsw_sp_bridge_port_flood_table_set(mlxsw_sp_port,
832*4882a593Smuzhiyun bridge_port,
833*4882a593Smuzhiyun packet_type, member);
834*4882a593Smuzhiyun if (err)
835*4882a593Smuzhiyun return err;
836*4882a593Smuzhiyun }
837*4882a593Smuzhiyun
838*4882a593Smuzhiyun bridge_device->multicast_enabled = !mc_disabled;
839*4882a593Smuzhiyun
840*4882a593Smuzhiyun return 0;
841*4882a593Smuzhiyun }
842*4882a593Smuzhiyun
mlxsw_sp_smid_router_port_set(struct mlxsw_sp * mlxsw_sp,u16 mid_idx,bool add)843*4882a593Smuzhiyun static int mlxsw_sp_smid_router_port_set(struct mlxsw_sp *mlxsw_sp,
844*4882a593Smuzhiyun u16 mid_idx, bool add)
845*4882a593Smuzhiyun {
846*4882a593Smuzhiyun char *smid_pl;
847*4882a593Smuzhiyun int err;
848*4882a593Smuzhiyun
849*4882a593Smuzhiyun smid_pl = kmalloc(MLXSW_REG_SMID_LEN, GFP_KERNEL);
850*4882a593Smuzhiyun if (!smid_pl)
851*4882a593Smuzhiyun return -ENOMEM;
852*4882a593Smuzhiyun
853*4882a593Smuzhiyun mlxsw_reg_smid_pack(smid_pl, mid_idx,
854*4882a593Smuzhiyun mlxsw_sp_router_port(mlxsw_sp), add);
855*4882a593Smuzhiyun err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(smid), smid_pl);
856*4882a593Smuzhiyun kfree(smid_pl);
857*4882a593Smuzhiyun return err;
858*4882a593Smuzhiyun }
859*4882a593Smuzhiyun
860*4882a593Smuzhiyun static void
mlxsw_sp_bridge_mrouter_update_mdb(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_bridge_device * bridge_device,bool add)861*4882a593Smuzhiyun mlxsw_sp_bridge_mrouter_update_mdb(struct mlxsw_sp *mlxsw_sp,
862*4882a593Smuzhiyun struct mlxsw_sp_bridge_device *bridge_device,
863*4882a593Smuzhiyun bool add)
864*4882a593Smuzhiyun {
865*4882a593Smuzhiyun struct mlxsw_sp_mid *mid;
866*4882a593Smuzhiyun
867*4882a593Smuzhiyun list_for_each_entry(mid, &bridge_device->mids_list, list)
868*4882a593Smuzhiyun mlxsw_sp_smid_router_port_set(mlxsw_sp, mid->mid, add);
869*4882a593Smuzhiyun }
870*4882a593Smuzhiyun
871*4882a593Smuzhiyun static int
mlxsw_sp_port_attr_br_mrouter_set(struct mlxsw_sp_port * mlxsw_sp_port,struct switchdev_trans * trans,struct net_device * orig_dev,bool is_mrouter)872*4882a593Smuzhiyun mlxsw_sp_port_attr_br_mrouter_set(struct mlxsw_sp_port *mlxsw_sp_port,
873*4882a593Smuzhiyun struct switchdev_trans *trans,
874*4882a593Smuzhiyun struct net_device *orig_dev,
875*4882a593Smuzhiyun bool is_mrouter)
876*4882a593Smuzhiyun {
877*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
878*4882a593Smuzhiyun struct mlxsw_sp_bridge_device *bridge_device;
879*4882a593Smuzhiyun
880*4882a593Smuzhiyun if (switchdev_trans_ph_prepare(trans))
881*4882a593Smuzhiyun return 0;
882*4882a593Smuzhiyun
883*4882a593Smuzhiyun /* It's possible we failed to enslave the port, yet this
884*4882a593Smuzhiyun * operation is executed due to it being deferred.
885*4882a593Smuzhiyun */
886*4882a593Smuzhiyun bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, orig_dev);
887*4882a593Smuzhiyun if (!bridge_device)
888*4882a593Smuzhiyun return 0;
889*4882a593Smuzhiyun
890*4882a593Smuzhiyun if (bridge_device->mrouter != is_mrouter)
891*4882a593Smuzhiyun mlxsw_sp_bridge_mrouter_update_mdb(mlxsw_sp, bridge_device,
892*4882a593Smuzhiyun is_mrouter);
893*4882a593Smuzhiyun bridge_device->mrouter = is_mrouter;
894*4882a593Smuzhiyun return 0;
895*4882a593Smuzhiyun }
896*4882a593Smuzhiyun
mlxsw_sp_port_attr_set(struct net_device * dev,const struct switchdev_attr * attr,struct switchdev_trans * trans)897*4882a593Smuzhiyun static int mlxsw_sp_port_attr_set(struct net_device *dev,
898*4882a593Smuzhiyun const struct switchdev_attr *attr,
899*4882a593Smuzhiyun struct switchdev_trans *trans)
900*4882a593Smuzhiyun {
901*4882a593Smuzhiyun struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
902*4882a593Smuzhiyun int err;
903*4882a593Smuzhiyun
904*4882a593Smuzhiyun switch (attr->id) {
905*4882a593Smuzhiyun case SWITCHDEV_ATTR_ID_PORT_STP_STATE:
906*4882a593Smuzhiyun err = mlxsw_sp_port_attr_stp_state_set(mlxsw_sp_port, trans,
907*4882a593Smuzhiyun attr->orig_dev,
908*4882a593Smuzhiyun attr->u.stp_state);
909*4882a593Smuzhiyun break;
910*4882a593Smuzhiyun case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS:
911*4882a593Smuzhiyun err = mlxsw_sp_port_attr_br_pre_flags_set(mlxsw_sp_port,
912*4882a593Smuzhiyun trans,
913*4882a593Smuzhiyun attr->u.brport_flags);
914*4882a593Smuzhiyun break;
915*4882a593Smuzhiyun case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
916*4882a593Smuzhiyun err = mlxsw_sp_port_attr_br_flags_set(mlxsw_sp_port, trans,
917*4882a593Smuzhiyun attr->orig_dev,
918*4882a593Smuzhiyun attr->u.brport_flags);
919*4882a593Smuzhiyun break;
920*4882a593Smuzhiyun case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME:
921*4882a593Smuzhiyun err = mlxsw_sp_port_attr_br_ageing_set(mlxsw_sp_port, trans,
922*4882a593Smuzhiyun attr->u.ageing_time);
923*4882a593Smuzhiyun break;
924*4882a593Smuzhiyun case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING:
925*4882a593Smuzhiyun err = mlxsw_sp_port_attr_br_vlan_set(mlxsw_sp_port, trans,
926*4882a593Smuzhiyun attr->orig_dev,
927*4882a593Smuzhiyun attr->u.vlan_filtering);
928*4882a593Smuzhiyun break;
929*4882a593Smuzhiyun case SWITCHDEV_ATTR_ID_PORT_MROUTER:
930*4882a593Smuzhiyun err = mlxsw_sp_port_attr_mrouter_set(mlxsw_sp_port, trans,
931*4882a593Smuzhiyun attr->orig_dev,
932*4882a593Smuzhiyun attr->u.mrouter);
933*4882a593Smuzhiyun break;
934*4882a593Smuzhiyun case SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED:
935*4882a593Smuzhiyun err = mlxsw_sp_port_mc_disabled_set(mlxsw_sp_port, trans,
936*4882a593Smuzhiyun attr->orig_dev,
937*4882a593Smuzhiyun attr->u.mc_disabled);
938*4882a593Smuzhiyun break;
939*4882a593Smuzhiyun case SWITCHDEV_ATTR_ID_BRIDGE_MROUTER:
940*4882a593Smuzhiyun err = mlxsw_sp_port_attr_br_mrouter_set(mlxsw_sp_port, trans,
941*4882a593Smuzhiyun attr->orig_dev,
942*4882a593Smuzhiyun attr->u.mrouter);
943*4882a593Smuzhiyun break;
944*4882a593Smuzhiyun default:
945*4882a593Smuzhiyun err = -EOPNOTSUPP;
946*4882a593Smuzhiyun break;
947*4882a593Smuzhiyun }
948*4882a593Smuzhiyun
949*4882a593Smuzhiyun if (switchdev_trans_ph_commit(trans))
950*4882a593Smuzhiyun mlxsw_sp_span_respin(mlxsw_sp_port->mlxsw_sp);
951*4882a593Smuzhiyun
952*4882a593Smuzhiyun return err;
953*4882a593Smuzhiyun }
954*4882a593Smuzhiyun
955*4882a593Smuzhiyun static int
mlxsw_sp_port_vlan_fid_join(struct mlxsw_sp_port_vlan * mlxsw_sp_port_vlan,struct mlxsw_sp_bridge_port * bridge_port,struct netlink_ext_ack * extack)956*4882a593Smuzhiyun mlxsw_sp_port_vlan_fid_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
957*4882a593Smuzhiyun struct mlxsw_sp_bridge_port *bridge_port,
958*4882a593Smuzhiyun struct netlink_ext_ack *extack)
959*4882a593Smuzhiyun {
960*4882a593Smuzhiyun struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
961*4882a593Smuzhiyun struct mlxsw_sp_bridge_device *bridge_device;
962*4882a593Smuzhiyun u8 local_port = mlxsw_sp_port->local_port;
963*4882a593Smuzhiyun u16 vid = mlxsw_sp_port_vlan->vid;
964*4882a593Smuzhiyun struct mlxsw_sp_fid *fid;
965*4882a593Smuzhiyun int err;
966*4882a593Smuzhiyun
967*4882a593Smuzhiyun bridge_device = bridge_port->bridge_device;
968*4882a593Smuzhiyun fid = bridge_device->ops->fid_get(bridge_device, vid, extack);
969*4882a593Smuzhiyun if (IS_ERR(fid))
970*4882a593Smuzhiyun return PTR_ERR(fid);
971*4882a593Smuzhiyun
972*4882a593Smuzhiyun err = mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_UC, local_port,
973*4882a593Smuzhiyun bridge_port->flags & BR_FLOOD);
974*4882a593Smuzhiyun if (err)
975*4882a593Smuzhiyun goto err_fid_uc_flood_set;
976*4882a593Smuzhiyun
977*4882a593Smuzhiyun err = mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_MC, local_port,
978*4882a593Smuzhiyun mlxsw_sp_mc_flood(bridge_port));
979*4882a593Smuzhiyun if (err)
980*4882a593Smuzhiyun goto err_fid_mc_flood_set;
981*4882a593Smuzhiyun
982*4882a593Smuzhiyun err = mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_BC, local_port,
983*4882a593Smuzhiyun true);
984*4882a593Smuzhiyun if (err)
985*4882a593Smuzhiyun goto err_fid_bc_flood_set;
986*4882a593Smuzhiyun
987*4882a593Smuzhiyun err = mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port, vid);
988*4882a593Smuzhiyun if (err)
989*4882a593Smuzhiyun goto err_fid_port_vid_map;
990*4882a593Smuzhiyun
991*4882a593Smuzhiyun mlxsw_sp_port_vlan->fid = fid;
992*4882a593Smuzhiyun
993*4882a593Smuzhiyun return 0;
994*4882a593Smuzhiyun
995*4882a593Smuzhiyun err_fid_port_vid_map:
996*4882a593Smuzhiyun mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_BC, local_port, false);
997*4882a593Smuzhiyun err_fid_bc_flood_set:
998*4882a593Smuzhiyun mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_MC, local_port, false);
999*4882a593Smuzhiyun err_fid_mc_flood_set:
1000*4882a593Smuzhiyun mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_UC, local_port, false);
1001*4882a593Smuzhiyun err_fid_uc_flood_set:
1002*4882a593Smuzhiyun mlxsw_sp_fid_put(fid);
1003*4882a593Smuzhiyun return err;
1004*4882a593Smuzhiyun }
1005*4882a593Smuzhiyun
1006*4882a593Smuzhiyun static void
mlxsw_sp_port_vlan_fid_leave(struct mlxsw_sp_port_vlan * mlxsw_sp_port_vlan)1007*4882a593Smuzhiyun mlxsw_sp_port_vlan_fid_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
1008*4882a593Smuzhiyun {
1009*4882a593Smuzhiyun struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
1010*4882a593Smuzhiyun struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
1011*4882a593Smuzhiyun u8 local_port = mlxsw_sp_port->local_port;
1012*4882a593Smuzhiyun u16 vid = mlxsw_sp_port_vlan->vid;
1013*4882a593Smuzhiyun
1014*4882a593Smuzhiyun mlxsw_sp_port_vlan->fid = NULL;
1015*4882a593Smuzhiyun mlxsw_sp_fid_port_vid_unmap(fid, mlxsw_sp_port, vid);
1016*4882a593Smuzhiyun mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_BC, local_port, false);
1017*4882a593Smuzhiyun mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_MC, local_port, false);
1018*4882a593Smuzhiyun mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_UC, local_port, false);
1019*4882a593Smuzhiyun mlxsw_sp_fid_put(fid);
1020*4882a593Smuzhiyun }
1021*4882a593Smuzhiyun
1022*4882a593Smuzhiyun static u16
mlxsw_sp_port_pvid_determine(const struct mlxsw_sp_port * mlxsw_sp_port,u16 vid,bool is_pvid)1023*4882a593Smuzhiyun mlxsw_sp_port_pvid_determine(const struct mlxsw_sp_port *mlxsw_sp_port,
1024*4882a593Smuzhiyun u16 vid, bool is_pvid)
1025*4882a593Smuzhiyun {
1026*4882a593Smuzhiyun if (is_pvid)
1027*4882a593Smuzhiyun return vid;
1028*4882a593Smuzhiyun else if (mlxsw_sp_port->pvid == vid)
1029*4882a593Smuzhiyun return 0; /* Dis-allow untagged packets */
1030*4882a593Smuzhiyun else
1031*4882a593Smuzhiyun return mlxsw_sp_port->pvid;
1032*4882a593Smuzhiyun }
1033*4882a593Smuzhiyun
1034*4882a593Smuzhiyun static int
mlxsw_sp_port_vlan_bridge_join(struct mlxsw_sp_port_vlan * mlxsw_sp_port_vlan,struct mlxsw_sp_bridge_port * bridge_port,struct netlink_ext_ack * extack)1035*4882a593Smuzhiyun mlxsw_sp_port_vlan_bridge_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
1036*4882a593Smuzhiyun struct mlxsw_sp_bridge_port *bridge_port,
1037*4882a593Smuzhiyun struct netlink_ext_ack *extack)
1038*4882a593Smuzhiyun {
1039*4882a593Smuzhiyun struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
1040*4882a593Smuzhiyun struct mlxsw_sp_bridge_vlan *bridge_vlan;
1041*4882a593Smuzhiyun u16 vid = mlxsw_sp_port_vlan->vid;
1042*4882a593Smuzhiyun int err;
1043*4882a593Smuzhiyun
1044*4882a593Smuzhiyun /* No need to continue if only VLAN flags were changed */
1045*4882a593Smuzhiyun if (mlxsw_sp_port_vlan->bridge_port)
1046*4882a593Smuzhiyun return 0;
1047*4882a593Smuzhiyun
1048*4882a593Smuzhiyun err = mlxsw_sp_port_vlan_fid_join(mlxsw_sp_port_vlan, bridge_port,
1049*4882a593Smuzhiyun extack);
1050*4882a593Smuzhiyun if (err)
1051*4882a593Smuzhiyun return err;
1052*4882a593Smuzhiyun
1053*4882a593Smuzhiyun err = mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid,
1054*4882a593Smuzhiyun bridge_port->flags & BR_LEARNING);
1055*4882a593Smuzhiyun if (err)
1056*4882a593Smuzhiyun goto err_port_vid_learning_set;
1057*4882a593Smuzhiyun
1058*4882a593Smuzhiyun err = mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid,
1059*4882a593Smuzhiyun bridge_port->stp_state);
1060*4882a593Smuzhiyun if (err)
1061*4882a593Smuzhiyun goto err_port_vid_stp_set;
1062*4882a593Smuzhiyun
1063*4882a593Smuzhiyun bridge_vlan = mlxsw_sp_bridge_vlan_get(bridge_port, vid);
1064*4882a593Smuzhiyun if (!bridge_vlan) {
1065*4882a593Smuzhiyun err = -ENOMEM;
1066*4882a593Smuzhiyun goto err_bridge_vlan_get;
1067*4882a593Smuzhiyun }
1068*4882a593Smuzhiyun
1069*4882a593Smuzhiyun list_add(&mlxsw_sp_port_vlan->bridge_vlan_node,
1070*4882a593Smuzhiyun &bridge_vlan->port_vlan_list);
1071*4882a593Smuzhiyun
1072*4882a593Smuzhiyun mlxsw_sp_bridge_port_get(mlxsw_sp_port->mlxsw_sp->bridge,
1073*4882a593Smuzhiyun bridge_port->dev, extack);
1074*4882a593Smuzhiyun mlxsw_sp_port_vlan->bridge_port = bridge_port;
1075*4882a593Smuzhiyun
1076*4882a593Smuzhiyun return 0;
1077*4882a593Smuzhiyun
1078*4882a593Smuzhiyun err_bridge_vlan_get:
1079*4882a593Smuzhiyun mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid, BR_STATE_DISABLED);
1080*4882a593Smuzhiyun err_port_vid_stp_set:
1081*4882a593Smuzhiyun mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, false);
1082*4882a593Smuzhiyun err_port_vid_learning_set:
1083*4882a593Smuzhiyun mlxsw_sp_port_vlan_fid_leave(mlxsw_sp_port_vlan);
1084*4882a593Smuzhiyun return err;
1085*4882a593Smuzhiyun }
1086*4882a593Smuzhiyun
1087*4882a593Smuzhiyun void
mlxsw_sp_port_vlan_bridge_leave(struct mlxsw_sp_port_vlan * mlxsw_sp_port_vlan)1088*4882a593Smuzhiyun mlxsw_sp_port_vlan_bridge_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
1089*4882a593Smuzhiyun {
1090*4882a593Smuzhiyun struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
1091*4882a593Smuzhiyun struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
1092*4882a593Smuzhiyun struct mlxsw_sp_bridge_vlan *bridge_vlan;
1093*4882a593Smuzhiyun struct mlxsw_sp_bridge_port *bridge_port;
1094*4882a593Smuzhiyun u16 vid = mlxsw_sp_port_vlan->vid;
1095*4882a593Smuzhiyun bool last_port, last_vlan;
1096*4882a593Smuzhiyun
1097*4882a593Smuzhiyun if (WARN_ON(mlxsw_sp_fid_type(fid) != MLXSW_SP_FID_TYPE_8021Q &&
1098*4882a593Smuzhiyun mlxsw_sp_fid_type(fid) != MLXSW_SP_FID_TYPE_8021D))
1099*4882a593Smuzhiyun return;
1100*4882a593Smuzhiyun
1101*4882a593Smuzhiyun bridge_port = mlxsw_sp_port_vlan->bridge_port;
1102*4882a593Smuzhiyun last_vlan = list_is_singular(&bridge_port->vlans_list);
1103*4882a593Smuzhiyun bridge_vlan = mlxsw_sp_bridge_vlan_find(bridge_port, vid);
1104*4882a593Smuzhiyun last_port = list_is_singular(&bridge_vlan->port_vlan_list);
1105*4882a593Smuzhiyun
1106*4882a593Smuzhiyun list_del(&mlxsw_sp_port_vlan->bridge_vlan_node);
1107*4882a593Smuzhiyun mlxsw_sp_bridge_vlan_put(bridge_vlan);
1108*4882a593Smuzhiyun mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid, BR_STATE_DISABLED);
1109*4882a593Smuzhiyun mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, false);
1110*4882a593Smuzhiyun if (last_port)
1111*4882a593Smuzhiyun mlxsw_sp_bridge_port_fdb_flush(mlxsw_sp_port->mlxsw_sp,
1112*4882a593Smuzhiyun bridge_port,
1113*4882a593Smuzhiyun mlxsw_sp_fid_index(fid));
1114*4882a593Smuzhiyun if (last_vlan)
1115*4882a593Smuzhiyun mlxsw_sp_bridge_port_mdb_flush(mlxsw_sp_port, bridge_port);
1116*4882a593Smuzhiyun
1117*4882a593Smuzhiyun mlxsw_sp_port_vlan_fid_leave(mlxsw_sp_port_vlan);
1118*4882a593Smuzhiyun
1119*4882a593Smuzhiyun mlxsw_sp_bridge_port_put(mlxsw_sp_port->mlxsw_sp->bridge, bridge_port);
1120*4882a593Smuzhiyun mlxsw_sp_port_vlan->bridge_port = NULL;
1121*4882a593Smuzhiyun }
1122*4882a593Smuzhiyun
1123*4882a593Smuzhiyun static int
mlxsw_sp_bridge_port_vlan_add(struct mlxsw_sp_port * mlxsw_sp_port,struct mlxsw_sp_bridge_port * bridge_port,u16 vid,bool is_untagged,bool is_pvid,struct netlink_ext_ack * extack)1124*4882a593Smuzhiyun mlxsw_sp_bridge_port_vlan_add(struct mlxsw_sp_port *mlxsw_sp_port,
1125*4882a593Smuzhiyun struct mlxsw_sp_bridge_port *bridge_port,
1126*4882a593Smuzhiyun u16 vid, bool is_untagged, bool is_pvid,
1127*4882a593Smuzhiyun struct netlink_ext_ack *extack)
1128*4882a593Smuzhiyun {
1129*4882a593Smuzhiyun u16 pvid = mlxsw_sp_port_pvid_determine(mlxsw_sp_port, vid, is_pvid);
1130*4882a593Smuzhiyun struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
1131*4882a593Smuzhiyun u16 old_pvid = mlxsw_sp_port->pvid;
1132*4882a593Smuzhiyun int err;
1133*4882a593Smuzhiyun
1134*4882a593Smuzhiyun /* The only valid scenario in which a port-vlan already exists, is if
1135*4882a593Smuzhiyun * the VLAN flags were changed and the port-vlan is associated with the
1136*4882a593Smuzhiyun * correct bridge port
1137*4882a593Smuzhiyun */
1138*4882a593Smuzhiyun mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid);
1139*4882a593Smuzhiyun if (mlxsw_sp_port_vlan &&
1140*4882a593Smuzhiyun mlxsw_sp_port_vlan->bridge_port != bridge_port)
1141*4882a593Smuzhiyun return -EEXIST;
1142*4882a593Smuzhiyun
1143*4882a593Smuzhiyun if (!mlxsw_sp_port_vlan) {
1144*4882a593Smuzhiyun mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_create(mlxsw_sp_port,
1145*4882a593Smuzhiyun vid);
1146*4882a593Smuzhiyun if (IS_ERR(mlxsw_sp_port_vlan))
1147*4882a593Smuzhiyun return PTR_ERR(mlxsw_sp_port_vlan);
1148*4882a593Smuzhiyun }
1149*4882a593Smuzhiyun
1150*4882a593Smuzhiyun err = mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, true,
1151*4882a593Smuzhiyun is_untagged);
1152*4882a593Smuzhiyun if (err)
1153*4882a593Smuzhiyun goto err_port_vlan_set;
1154*4882a593Smuzhiyun
1155*4882a593Smuzhiyun err = mlxsw_sp_port_pvid_set(mlxsw_sp_port, pvid);
1156*4882a593Smuzhiyun if (err)
1157*4882a593Smuzhiyun goto err_port_pvid_set;
1158*4882a593Smuzhiyun
1159*4882a593Smuzhiyun err = mlxsw_sp_port_vlan_bridge_join(mlxsw_sp_port_vlan, bridge_port,
1160*4882a593Smuzhiyun extack);
1161*4882a593Smuzhiyun if (err)
1162*4882a593Smuzhiyun goto err_port_vlan_bridge_join;
1163*4882a593Smuzhiyun
1164*4882a593Smuzhiyun return 0;
1165*4882a593Smuzhiyun
1166*4882a593Smuzhiyun err_port_vlan_bridge_join:
1167*4882a593Smuzhiyun mlxsw_sp_port_pvid_set(mlxsw_sp_port, old_pvid);
1168*4882a593Smuzhiyun err_port_pvid_set:
1169*4882a593Smuzhiyun mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, false, false);
1170*4882a593Smuzhiyun err_port_vlan_set:
1171*4882a593Smuzhiyun mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan);
1172*4882a593Smuzhiyun return err;
1173*4882a593Smuzhiyun }
1174*4882a593Smuzhiyun
1175*4882a593Smuzhiyun static int
mlxsw_sp_br_ban_rif_pvid_change(struct mlxsw_sp * mlxsw_sp,const struct net_device * br_dev,const struct switchdev_obj_port_vlan * vlan)1176*4882a593Smuzhiyun mlxsw_sp_br_ban_rif_pvid_change(struct mlxsw_sp *mlxsw_sp,
1177*4882a593Smuzhiyun const struct net_device *br_dev,
1178*4882a593Smuzhiyun const struct switchdev_obj_port_vlan *vlan)
1179*4882a593Smuzhiyun {
1180*4882a593Smuzhiyun u16 pvid;
1181*4882a593Smuzhiyun u16 vid;
1182*4882a593Smuzhiyun
1183*4882a593Smuzhiyun pvid = mlxsw_sp_rif_vid(mlxsw_sp, br_dev);
1184*4882a593Smuzhiyun if (!pvid)
1185*4882a593Smuzhiyun return 0;
1186*4882a593Smuzhiyun
1187*4882a593Smuzhiyun for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
1188*4882a593Smuzhiyun if (vlan->flags & BRIDGE_VLAN_INFO_PVID) {
1189*4882a593Smuzhiyun if (vid != pvid) {
1190*4882a593Smuzhiyun netdev_err(br_dev, "Can't change PVID, it's used by router interface\n");
1191*4882a593Smuzhiyun return -EBUSY;
1192*4882a593Smuzhiyun }
1193*4882a593Smuzhiyun } else {
1194*4882a593Smuzhiyun if (vid == pvid) {
1195*4882a593Smuzhiyun netdev_err(br_dev, "Can't remove PVID, it's used by router interface\n");
1196*4882a593Smuzhiyun return -EBUSY;
1197*4882a593Smuzhiyun }
1198*4882a593Smuzhiyun }
1199*4882a593Smuzhiyun }
1200*4882a593Smuzhiyun
1201*4882a593Smuzhiyun return 0;
1202*4882a593Smuzhiyun }
1203*4882a593Smuzhiyun
mlxsw_sp_port_vlans_add(struct mlxsw_sp_port * mlxsw_sp_port,const struct switchdev_obj_port_vlan * vlan,struct switchdev_trans * trans,struct netlink_ext_ack * extack)1204*4882a593Smuzhiyun static int mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port,
1205*4882a593Smuzhiyun const struct switchdev_obj_port_vlan *vlan,
1206*4882a593Smuzhiyun struct switchdev_trans *trans,
1207*4882a593Smuzhiyun struct netlink_ext_ack *extack)
1208*4882a593Smuzhiyun {
1209*4882a593Smuzhiyun bool flag_untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
1210*4882a593Smuzhiyun bool flag_pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
1211*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1212*4882a593Smuzhiyun struct net_device *orig_dev = vlan->obj.orig_dev;
1213*4882a593Smuzhiyun struct mlxsw_sp_bridge_port *bridge_port;
1214*4882a593Smuzhiyun u16 vid;
1215*4882a593Smuzhiyun
1216*4882a593Smuzhiyun if (netif_is_bridge_master(orig_dev)) {
1217*4882a593Smuzhiyun int err = 0;
1218*4882a593Smuzhiyun
1219*4882a593Smuzhiyun if ((vlan->flags & BRIDGE_VLAN_INFO_BRENTRY) &&
1220*4882a593Smuzhiyun br_vlan_enabled(orig_dev) &&
1221*4882a593Smuzhiyun switchdev_trans_ph_prepare(trans))
1222*4882a593Smuzhiyun err = mlxsw_sp_br_ban_rif_pvid_change(mlxsw_sp,
1223*4882a593Smuzhiyun orig_dev, vlan);
1224*4882a593Smuzhiyun if (!err)
1225*4882a593Smuzhiyun err = -EOPNOTSUPP;
1226*4882a593Smuzhiyun return err;
1227*4882a593Smuzhiyun }
1228*4882a593Smuzhiyun
1229*4882a593Smuzhiyun if (switchdev_trans_ph_commit(trans))
1230*4882a593Smuzhiyun return 0;
1231*4882a593Smuzhiyun
1232*4882a593Smuzhiyun bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev);
1233*4882a593Smuzhiyun if (WARN_ON(!bridge_port))
1234*4882a593Smuzhiyun return -EINVAL;
1235*4882a593Smuzhiyun
1236*4882a593Smuzhiyun if (!bridge_port->bridge_device->vlan_enabled)
1237*4882a593Smuzhiyun return 0;
1238*4882a593Smuzhiyun
1239*4882a593Smuzhiyun for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) {
1240*4882a593Smuzhiyun int err;
1241*4882a593Smuzhiyun
1242*4882a593Smuzhiyun err = mlxsw_sp_bridge_port_vlan_add(mlxsw_sp_port, bridge_port,
1243*4882a593Smuzhiyun vid, flag_untagged,
1244*4882a593Smuzhiyun flag_pvid, extack);
1245*4882a593Smuzhiyun if (err)
1246*4882a593Smuzhiyun return err;
1247*4882a593Smuzhiyun }
1248*4882a593Smuzhiyun
1249*4882a593Smuzhiyun return 0;
1250*4882a593Smuzhiyun }
1251*4882a593Smuzhiyun
mlxsw_sp_fdb_flush_type(bool lagged)1252*4882a593Smuzhiyun static enum mlxsw_reg_sfdf_flush_type mlxsw_sp_fdb_flush_type(bool lagged)
1253*4882a593Smuzhiyun {
1254*4882a593Smuzhiyun return lagged ? MLXSW_REG_SFDF_FLUSH_PER_LAG_AND_FID :
1255*4882a593Smuzhiyun MLXSW_REG_SFDF_FLUSH_PER_PORT_AND_FID;
1256*4882a593Smuzhiyun }
1257*4882a593Smuzhiyun
1258*4882a593Smuzhiyun static int
mlxsw_sp_bridge_port_fdb_flush(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_bridge_port * bridge_port,u16 fid_index)1259*4882a593Smuzhiyun mlxsw_sp_bridge_port_fdb_flush(struct mlxsw_sp *mlxsw_sp,
1260*4882a593Smuzhiyun struct mlxsw_sp_bridge_port *bridge_port,
1261*4882a593Smuzhiyun u16 fid_index)
1262*4882a593Smuzhiyun {
1263*4882a593Smuzhiyun bool lagged = bridge_port->lagged;
1264*4882a593Smuzhiyun char sfdf_pl[MLXSW_REG_SFDF_LEN];
1265*4882a593Smuzhiyun u16 system_port;
1266*4882a593Smuzhiyun
1267*4882a593Smuzhiyun system_port = lagged ? bridge_port->lag_id : bridge_port->system_port;
1268*4882a593Smuzhiyun mlxsw_reg_sfdf_pack(sfdf_pl, mlxsw_sp_fdb_flush_type(lagged));
1269*4882a593Smuzhiyun mlxsw_reg_sfdf_fid_set(sfdf_pl, fid_index);
1270*4882a593Smuzhiyun mlxsw_reg_sfdf_port_fid_system_port_set(sfdf_pl, system_port);
1271*4882a593Smuzhiyun
1272*4882a593Smuzhiyun return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfdf), sfdf_pl);
1273*4882a593Smuzhiyun }
1274*4882a593Smuzhiyun
mlxsw_sp_sfd_rec_policy(bool dynamic)1275*4882a593Smuzhiyun static enum mlxsw_reg_sfd_rec_policy mlxsw_sp_sfd_rec_policy(bool dynamic)
1276*4882a593Smuzhiyun {
1277*4882a593Smuzhiyun return dynamic ? MLXSW_REG_SFD_REC_POLICY_DYNAMIC_ENTRY_INGRESS :
1278*4882a593Smuzhiyun MLXSW_REG_SFD_REC_POLICY_DYNAMIC_ENTRY_MLAG;
1279*4882a593Smuzhiyun }
1280*4882a593Smuzhiyun
mlxsw_sp_sfd_op(bool adding)1281*4882a593Smuzhiyun static enum mlxsw_reg_sfd_op mlxsw_sp_sfd_op(bool adding)
1282*4882a593Smuzhiyun {
1283*4882a593Smuzhiyun return adding ? MLXSW_REG_SFD_OP_WRITE_EDIT :
1284*4882a593Smuzhiyun MLXSW_REG_SFD_OP_WRITE_REMOVE;
1285*4882a593Smuzhiyun }
1286*4882a593Smuzhiyun
mlxsw_sp_port_fdb_tunnel_uc_op(struct mlxsw_sp * mlxsw_sp,const char * mac,u16 fid,enum mlxsw_sp_l3proto proto,const union mlxsw_sp_l3addr * addr,bool adding,bool dynamic)1287*4882a593Smuzhiyun static int mlxsw_sp_port_fdb_tunnel_uc_op(struct mlxsw_sp *mlxsw_sp,
1288*4882a593Smuzhiyun const char *mac, u16 fid,
1289*4882a593Smuzhiyun enum mlxsw_sp_l3proto proto,
1290*4882a593Smuzhiyun const union mlxsw_sp_l3addr *addr,
1291*4882a593Smuzhiyun bool adding, bool dynamic)
1292*4882a593Smuzhiyun {
1293*4882a593Smuzhiyun enum mlxsw_reg_sfd_uc_tunnel_protocol sfd_proto;
1294*4882a593Smuzhiyun char *sfd_pl;
1295*4882a593Smuzhiyun u8 num_rec;
1296*4882a593Smuzhiyun u32 uip;
1297*4882a593Smuzhiyun int err;
1298*4882a593Smuzhiyun
1299*4882a593Smuzhiyun switch (proto) {
1300*4882a593Smuzhiyun case MLXSW_SP_L3_PROTO_IPV4:
1301*4882a593Smuzhiyun uip = be32_to_cpu(addr->addr4);
1302*4882a593Smuzhiyun sfd_proto = MLXSW_REG_SFD_UC_TUNNEL_PROTOCOL_IPV4;
1303*4882a593Smuzhiyun break;
1304*4882a593Smuzhiyun case MLXSW_SP_L3_PROTO_IPV6:
1305*4882a593Smuzhiyun default:
1306*4882a593Smuzhiyun WARN_ON(1);
1307*4882a593Smuzhiyun return -EOPNOTSUPP;
1308*4882a593Smuzhiyun }
1309*4882a593Smuzhiyun
1310*4882a593Smuzhiyun sfd_pl = kmalloc(MLXSW_REG_SFD_LEN, GFP_KERNEL);
1311*4882a593Smuzhiyun if (!sfd_pl)
1312*4882a593Smuzhiyun return -ENOMEM;
1313*4882a593Smuzhiyun
1314*4882a593Smuzhiyun mlxsw_reg_sfd_pack(sfd_pl, mlxsw_sp_sfd_op(adding), 0);
1315*4882a593Smuzhiyun mlxsw_reg_sfd_uc_tunnel_pack(sfd_pl, 0,
1316*4882a593Smuzhiyun mlxsw_sp_sfd_rec_policy(dynamic), mac, fid,
1317*4882a593Smuzhiyun MLXSW_REG_SFD_REC_ACTION_NOP, uip,
1318*4882a593Smuzhiyun sfd_proto);
1319*4882a593Smuzhiyun num_rec = mlxsw_reg_sfd_num_rec_get(sfd_pl);
1320*4882a593Smuzhiyun err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl);
1321*4882a593Smuzhiyun if (err)
1322*4882a593Smuzhiyun goto out;
1323*4882a593Smuzhiyun
1324*4882a593Smuzhiyun if (num_rec != mlxsw_reg_sfd_num_rec_get(sfd_pl))
1325*4882a593Smuzhiyun err = -EBUSY;
1326*4882a593Smuzhiyun
1327*4882a593Smuzhiyun out:
1328*4882a593Smuzhiyun kfree(sfd_pl);
1329*4882a593Smuzhiyun return err;
1330*4882a593Smuzhiyun }
1331*4882a593Smuzhiyun
__mlxsw_sp_port_fdb_uc_op(struct mlxsw_sp * mlxsw_sp,u8 local_port,const char * mac,u16 fid,bool adding,enum mlxsw_reg_sfd_rec_action action,enum mlxsw_reg_sfd_rec_policy policy)1332*4882a593Smuzhiyun static int __mlxsw_sp_port_fdb_uc_op(struct mlxsw_sp *mlxsw_sp, u8 local_port,
1333*4882a593Smuzhiyun const char *mac, u16 fid, bool adding,
1334*4882a593Smuzhiyun enum mlxsw_reg_sfd_rec_action action,
1335*4882a593Smuzhiyun enum mlxsw_reg_sfd_rec_policy policy)
1336*4882a593Smuzhiyun {
1337*4882a593Smuzhiyun char *sfd_pl;
1338*4882a593Smuzhiyun u8 num_rec;
1339*4882a593Smuzhiyun int err;
1340*4882a593Smuzhiyun
1341*4882a593Smuzhiyun sfd_pl = kmalloc(MLXSW_REG_SFD_LEN, GFP_KERNEL);
1342*4882a593Smuzhiyun if (!sfd_pl)
1343*4882a593Smuzhiyun return -ENOMEM;
1344*4882a593Smuzhiyun
1345*4882a593Smuzhiyun mlxsw_reg_sfd_pack(sfd_pl, mlxsw_sp_sfd_op(adding), 0);
1346*4882a593Smuzhiyun mlxsw_reg_sfd_uc_pack(sfd_pl, 0, policy, mac, fid, action, local_port);
1347*4882a593Smuzhiyun num_rec = mlxsw_reg_sfd_num_rec_get(sfd_pl);
1348*4882a593Smuzhiyun err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl);
1349*4882a593Smuzhiyun if (err)
1350*4882a593Smuzhiyun goto out;
1351*4882a593Smuzhiyun
1352*4882a593Smuzhiyun if (num_rec != mlxsw_reg_sfd_num_rec_get(sfd_pl))
1353*4882a593Smuzhiyun err = -EBUSY;
1354*4882a593Smuzhiyun
1355*4882a593Smuzhiyun out:
1356*4882a593Smuzhiyun kfree(sfd_pl);
1357*4882a593Smuzhiyun return err;
1358*4882a593Smuzhiyun }
1359*4882a593Smuzhiyun
mlxsw_sp_port_fdb_uc_op(struct mlxsw_sp * mlxsw_sp,u8 local_port,const char * mac,u16 fid,bool adding,bool dynamic)1360*4882a593Smuzhiyun static int mlxsw_sp_port_fdb_uc_op(struct mlxsw_sp *mlxsw_sp, u8 local_port,
1361*4882a593Smuzhiyun const char *mac, u16 fid, bool adding,
1362*4882a593Smuzhiyun bool dynamic)
1363*4882a593Smuzhiyun {
1364*4882a593Smuzhiyun return __mlxsw_sp_port_fdb_uc_op(mlxsw_sp, local_port, mac, fid, adding,
1365*4882a593Smuzhiyun MLXSW_REG_SFD_REC_ACTION_NOP,
1366*4882a593Smuzhiyun mlxsw_sp_sfd_rec_policy(dynamic));
1367*4882a593Smuzhiyun }
1368*4882a593Smuzhiyun
mlxsw_sp_rif_fdb_op(struct mlxsw_sp * mlxsw_sp,const char * mac,u16 fid,bool adding)1369*4882a593Smuzhiyun int mlxsw_sp_rif_fdb_op(struct mlxsw_sp *mlxsw_sp, const char *mac, u16 fid,
1370*4882a593Smuzhiyun bool adding)
1371*4882a593Smuzhiyun {
1372*4882a593Smuzhiyun return __mlxsw_sp_port_fdb_uc_op(mlxsw_sp, 0, mac, fid, adding,
1373*4882a593Smuzhiyun MLXSW_REG_SFD_REC_ACTION_FORWARD_IP_ROUTER,
1374*4882a593Smuzhiyun MLXSW_REG_SFD_REC_POLICY_STATIC_ENTRY);
1375*4882a593Smuzhiyun }
1376*4882a593Smuzhiyun
mlxsw_sp_port_fdb_uc_lag_op(struct mlxsw_sp * mlxsw_sp,u16 lag_id,const char * mac,u16 fid,u16 lag_vid,bool adding,bool dynamic)1377*4882a593Smuzhiyun static int mlxsw_sp_port_fdb_uc_lag_op(struct mlxsw_sp *mlxsw_sp, u16 lag_id,
1378*4882a593Smuzhiyun const char *mac, u16 fid, u16 lag_vid,
1379*4882a593Smuzhiyun bool adding, bool dynamic)
1380*4882a593Smuzhiyun {
1381*4882a593Smuzhiyun char *sfd_pl;
1382*4882a593Smuzhiyun u8 num_rec;
1383*4882a593Smuzhiyun int err;
1384*4882a593Smuzhiyun
1385*4882a593Smuzhiyun sfd_pl = kmalloc(MLXSW_REG_SFD_LEN, GFP_KERNEL);
1386*4882a593Smuzhiyun if (!sfd_pl)
1387*4882a593Smuzhiyun return -ENOMEM;
1388*4882a593Smuzhiyun
1389*4882a593Smuzhiyun mlxsw_reg_sfd_pack(sfd_pl, mlxsw_sp_sfd_op(adding), 0);
1390*4882a593Smuzhiyun mlxsw_reg_sfd_uc_lag_pack(sfd_pl, 0, mlxsw_sp_sfd_rec_policy(dynamic),
1391*4882a593Smuzhiyun mac, fid, MLXSW_REG_SFD_REC_ACTION_NOP,
1392*4882a593Smuzhiyun lag_vid, lag_id);
1393*4882a593Smuzhiyun num_rec = mlxsw_reg_sfd_num_rec_get(sfd_pl);
1394*4882a593Smuzhiyun err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl);
1395*4882a593Smuzhiyun if (err)
1396*4882a593Smuzhiyun goto out;
1397*4882a593Smuzhiyun
1398*4882a593Smuzhiyun if (num_rec != mlxsw_reg_sfd_num_rec_get(sfd_pl))
1399*4882a593Smuzhiyun err = -EBUSY;
1400*4882a593Smuzhiyun
1401*4882a593Smuzhiyun out:
1402*4882a593Smuzhiyun kfree(sfd_pl);
1403*4882a593Smuzhiyun return err;
1404*4882a593Smuzhiyun }
1405*4882a593Smuzhiyun
1406*4882a593Smuzhiyun static int
mlxsw_sp_port_fdb_set(struct mlxsw_sp_port * mlxsw_sp_port,struct switchdev_notifier_fdb_info * fdb_info,bool adding)1407*4882a593Smuzhiyun mlxsw_sp_port_fdb_set(struct mlxsw_sp_port *mlxsw_sp_port,
1408*4882a593Smuzhiyun struct switchdev_notifier_fdb_info *fdb_info, bool adding)
1409*4882a593Smuzhiyun {
1410*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1411*4882a593Smuzhiyun struct net_device *orig_dev = fdb_info->info.dev;
1412*4882a593Smuzhiyun struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
1413*4882a593Smuzhiyun struct mlxsw_sp_bridge_device *bridge_device;
1414*4882a593Smuzhiyun struct mlxsw_sp_bridge_port *bridge_port;
1415*4882a593Smuzhiyun u16 fid_index, vid;
1416*4882a593Smuzhiyun
1417*4882a593Smuzhiyun bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev);
1418*4882a593Smuzhiyun if (!bridge_port)
1419*4882a593Smuzhiyun return -EINVAL;
1420*4882a593Smuzhiyun
1421*4882a593Smuzhiyun bridge_device = bridge_port->bridge_device;
1422*4882a593Smuzhiyun mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_bridge(mlxsw_sp_port,
1423*4882a593Smuzhiyun bridge_device,
1424*4882a593Smuzhiyun fdb_info->vid);
1425*4882a593Smuzhiyun if (!mlxsw_sp_port_vlan)
1426*4882a593Smuzhiyun return 0;
1427*4882a593Smuzhiyun
1428*4882a593Smuzhiyun fid_index = mlxsw_sp_fid_index(mlxsw_sp_port_vlan->fid);
1429*4882a593Smuzhiyun vid = mlxsw_sp_port_vlan->vid;
1430*4882a593Smuzhiyun
1431*4882a593Smuzhiyun if (!bridge_port->lagged)
1432*4882a593Smuzhiyun return mlxsw_sp_port_fdb_uc_op(mlxsw_sp,
1433*4882a593Smuzhiyun bridge_port->system_port,
1434*4882a593Smuzhiyun fdb_info->addr, fid_index,
1435*4882a593Smuzhiyun adding, false);
1436*4882a593Smuzhiyun else
1437*4882a593Smuzhiyun return mlxsw_sp_port_fdb_uc_lag_op(mlxsw_sp,
1438*4882a593Smuzhiyun bridge_port->lag_id,
1439*4882a593Smuzhiyun fdb_info->addr, fid_index,
1440*4882a593Smuzhiyun vid, adding, false);
1441*4882a593Smuzhiyun }
1442*4882a593Smuzhiyun
mlxsw_sp_port_mdb_op(struct mlxsw_sp * mlxsw_sp,const char * addr,u16 fid,u16 mid_idx,bool adding)1443*4882a593Smuzhiyun static int mlxsw_sp_port_mdb_op(struct mlxsw_sp *mlxsw_sp, const char *addr,
1444*4882a593Smuzhiyun u16 fid, u16 mid_idx, bool adding)
1445*4882a593Smuzhiyun {
1446*4882a593Smuzhiyun char *sfd_pl;
1447*4882a593Smuzhiyun u8 num_rec;
1448*4882a593Smuzhiyun int err;
1449*4882a593Smuzhiyun
1450*4882a593Smuzhiyun sfd_pl = kmalloc(MLXSW_REG_SFD_LEN, GFP_KERNEL);
1451*4882a593Smuzhiyun if (!sfd_pl)
1452*4882a593Smuzhiyun return -ENOMEM;
1453*4882a593Smuzhiyun
1454*4882a593Smuzhiyun mlxsw_reg_sfd_pack(sfd_pl, mlxsw_sp_sfd_op(adding), 0);
1455*4882a593Smuzhiyun mlxsw_reg_sfd_mc_pack(sfd_pl, 0, addr, fid,
1456*4882a593Smuzhiyun MLXSW_REG_SFD_REC_ACTION_NOP, mid_idx);
1457*4882a593Smuzhiyun num_rec = mlxsw_reg_sfd_num_rec_get(sfd_pl);
1458*4882a593Smuzhiyun err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl);
1459*4882a593Smuzhiyun if (err)
1460*4882a593Smuzhiyun goto out;
1461*4882a593Smuzhiyun
1462*4882a593Smuzhiyun if (num_rec != mlxsw_reg_sfd_num_rec_get(sfd_pl))
1463*4882a593Smuzhiyun err = -EBUSY;
1464*4882a593Smuzhiyun
1465*4882a593Smuzhiyun out:
1466*4882a593Smuzhiyun kfree(sfd_pl);
1467*4882a593Smuzhiyun return err;
1468*4882a593Smuzhiyun }
1469*4882a593Smuzhiyun
mlxsw_sp_port_smid_full_entry(struct mlxsw_sp * mlxsw_sp,u16 mid_idx,long * ports_bitmap,bool set_router_port)1470*4882a593Smuzhiyun static int mlxsw_sp_port_smid_full_entry(struct mlxsw_sp *mlxsw_sp, u16 mid_idx,
1471*4882a593Smuzhiyun long *ports_bitmap,
1472*4882a593Smuzhiyun bool set_router_port)
1473*4882a593Smuzhiyun {
1474*4882a593Smuzhiyun char *smid_pl;
1475*4882a593Smuzhiyun int err, i;
1476*4882a593Smuzhiyun
1477*4882a593Smuzhiyun smid_pl = kmalloc(MLXSW_REG_SMID_LEN, GFP_KERNEL);
1478*4882a593Smuzhiyun if (!smid_pl)
1479*4882a593Smuzhiyun return -ENOMEM;
1480*4882a593Smuzhiyun
1481*4882a593Smuzhiyun mlxsw_reg_smid_pack(smid_pl, mid_idx, 0, false);
1482*4882a593Smuzhiyun for (i = 1; i < mlxsw_core_max_ports(mlxsw_sp->core); i++) {
1483*4882a593Smuzhiyun if (mlxsw_sp->ports[i])
1484*4882a593Smuzhiyun mlxsw_reg_smid_port_mask_set(smid_pl, i, 1);
1485*4882a593Smuzhiyun }
1486*4882a593Smuzhiyun
1487*4882a593Smuzhiyun mlxsw_reg_smid_port_mask_set(smid_pl,
1488*4882a593Smuzhiyun mlxsw_sp_router_port(mlxsw_sp), 1);
1489*4882a593Smuzhiyun
1490*4882a593Smuzhiyun for_each_set_bit(i, ports_bitmap, mlxsw_core_max_ports(mlxsw_sp->core))
1491*4882a593Smuzhiyun mlxsw_reg_smid_port_set(smid_pl, i, 1);
1492*4882a593Smuzhiyun
1493*4882a593Smuzhiyun mlxsw_reg_smid_port_set(smid_pl, mlxsw_sp_router_port(mlxsw_sp),
1494*4882a593Smuzhiyun set_router_port);
1495*4882a593Smuzhiyun
1496*4882a593Smuzhiyun err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(smid), smid_pl);
1497*4882a593Smuzhiyun kfree(smid_pl);
1498*4882a593Smuzhiyun return err;
1499*4882a593Smuzhiyun }
1500*4882a593Smuzhiyun
mlxsw_sp_port_smid_set(struct mlxsw_sp_port * mlxsw_sp_port,u16 mid_idx,bool add)1501*4882a593Smuzhiyun static int mlxsw_sp_port_smid_set(struct mlxsw_sp_port *mlxsw_sp_port,
1502*4882a593Smuzhiyun u16 mid_idx, bool add)
1503*4882a593Smuzhiyun {
1504*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1505*4882a593Smuzhiyun char *smid_pl;
1506*4882a593Smuzhiyun int err;
1507*4882a593Smuzhiyun
1508*4882a593Smuzhiyun smid_pl = kmalloc(MLXSW_REG_SMID_LEN, GFP_KERNEL);
1509*4882a593Smuzhiyun if (!smid_pl)
1510*4882a593Smuzhiyun return -ENOMEM;
1511*4882a593Smuzhiyun
1512*4882a593Smuzhiyun mlxsw_reg_smid_pack(smid_pl, mid_idx, mlxsw_sp_port->local_port, add);
1513*4882a593Smuzhiyun err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(smid), smid_pl);
1514*4882a593Smuzhiyun kfree(smid_pl);
1515*4882a593Smuzhiyun return err;
1516*4882a593Smuzhiyun }
1517*4882a593Smuzhiyun
1518*4882a593Smuzhiyun static struct
__mlxsw_sp_mc_get(struct mlxsw_sp_bridge_device * bridge_device,const unsigned char * addr,u16 fid)1519*4882a593Smuzhiyun mlxsw_sp_mid *__mlxsw_sp_mc_get(struct mlxsw_sp_bridge_device *bridge_device,
1520*4882a593Smuzhiyun const unsigned char *addr,
1521*4882a593Smuzhiyun u16 fid)
1522*4882a593Smuzhiyun {
1523*4882a593Smuzhiyun struct mlxsw_sp_mid *mid;
1524*4882a593Smuzhiyun
1525*4882a593Smuzhiyun list_for_each_entry(mid, &bridge_device->mids_list, list) {
1526*4882a593Smuzhiyun if (ether_addr_equal(mid->addr, addr) && mid->fid == fid)
1527*4882a593Smuzhiyun return mid;
1528*4882a593Smuzhiyun }
1529*4882a593Smuzhiyun return NULL;
1530*4882a593Smuzhiyun }
1531*4882a593Smuzhiyun
1532*4882a593Smuzhiyun static void
mlxsw_sp_bridge_port_get_ports_bitmap(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_bridge_port * bridge_port,unsigned long * ports_bitmap)1533*4882a593Smuzhiyun mlxsw_sp_bridge_port_get_ports_bitmap(struct mlxsw_sp *mlxsw_sp,
1534*4882a593Smuzhiyun struct mlxsw_sp_bridge_port *bridge_port,
1535*4882a593Smuzhiyun unsigned long *ports_bitmap)
1536*4882a593Smuzhiyun {
1537*4882a593Smuzhiyun struct mlxsw_sp_port *mlxsw_sp_port;
1538*4882a593Smuzhiyun u64 max_lag_members, i;
1539*4882a593Smuzhiyun int lag_id;
1540*4882a593Smuzhiyun
1541*4882a593Smuzhiyun if (!bridge_port->lagged) {
1542*4882a593Smuzhiyun set_bit(bridge_port->system_port, ports_bitmap);
1543*4882a593Smuzhiyun } else {
1544*4882a593Smuzhiyun max_lag_members = MLXSW_CORE_RES_GET(mlxsw_sp->core,
1545*4882a593Smuzhiyun MAX_LAG_MEMBERS);
1546*4882a593Smuzhiyun lag_id = bridge_port->lag_id;
1547*4882a593Smuzhiyun for (i = 0; i < max_lag_members; i++) {
1548*4882a593Smuzhiyun mlxsw_sp_port = mlxsw_sp_port_lagged_get(mlxsw_sp,
1549*4882a593Smuzhiyun lag_id, i);
1550*4882a593Smuzhiyun if (mlxsw_sp_port)
1551*4882a593Smuzhiyun set_bit(mlxsw_sp_port->local_port,
1552*4882a593Smuzhiyun ports_bitmap);
1553*4882a593Smuzhiyun }
1554*4882a593Smuzhiyun }
1555*4882a593Smuzhiyun }
1556*4882a593Smuzhiyun
1557*4882a593Smuzhiyun static void
mlxsw_sp_mc_get_mrouters_bitmap(unsigned long * flood_bitmap,struct mlxsw_sp_bridge_device * bridge_device,struct mlxsw_sp * mlxsw_sp)1558*4882a593Smuzhiyun mlxsw_sp_mc_get_mrouters_bitmap(unsigned long *flood_bitmap,
1559*4882a593Smuzhiyun struct mlxsw_sp_bridge_device *bridge_device,
1560*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp)
1561*4882a593Smuzhiyun {
1562*4882a593Smuzhiyun struct mlxsw_sp_bridge_port *bridge_port;
1563*4882a593Smuzhiyun
1564*4882a593Smuzhiyun list_for_each_entry(bridge_port, &bridge_device->ports_list, list) {
1565*4882a593Smuzhiyun if (bridge_port->mrouter) {
1566*4882a593Smuzhiyun mlxsw_sp_bridge_port_get_ports_bitmap(mlxsw_sp,
1567*4882a593Smuzhiyun bridge_port,
1568*4882a593Smuzhiyun flood_bitmap);
1569*4882a593Smuzhiyun }
1570*4882a593Smuzhiyun }
1571*4882a593Smuzhiyun }
1572*4882a593Smuzhiyun
1573*4882a593Smuzhiyun static bool
mlxsw_sp_mc_write_mdb_entry(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_mid * mid,struct mlxsw_sp_bridge_device * bridge_device)1574*4882a593Smuzhiyun mlxsw_sp_mc_write_mdb_entry(struct mlxsw_sp *mlxsw_sp,
1575*4882a593Smuzhiyun struct mlxsw_sp_mid *mid,
1576*4882a593Smuzhiyun struct mlxsw_sp_bridge_device *bridge_device)
1577*4882a593Smuzhiyun {
1578*4882a593Smuzhiyun long *flood_bitmap;
1579*4882a593Smuzhiyun int num_of_ports;
1580*4882a593Smuzhiyun int alloc_size;
1581*4882a593Smuzhiyun u16 mid_idx;
1582*4882a593Smuzhiyun int err;
1583*4882a593Smuzhiyun
1584*4882a593Smuzhiyun mid_idx = find_first_zero_bit(mlxsw_sp->bridge->mids_bitmap,
1585*4882a593Smuzhiyun MLXSW_SP_MID_MAX);
1586*4882a593Smuzhiyun if (mid_idx == MLXSW_SP_MID_MAX)
1587*4882a593Smuzhiyun return false;
1588*4882a593Smuzhiyun
1589*4882a593Smuzhiyun num_of_ports = mlxsw_core_max_ports(mlxsw_sp->core);
1590*4882a593Smuzhiyun alloc_size = sizeof(long) * BITS_TO_LONGS(num_of_ports);
1591*4882a593Smuzhiyun flood_bitmap = kzalloc(alloc_size, GFP_KERNEL);
1592*4882a593Smuzhiyun if (!flood_bitmap)
1593*4882a593Smuzhiyun return false;
1594*4882a593Smuzhiyun
1595*4882a593Smuzhiyun bitmap_copy(flood_bitmap, mid->ports_in_mid, num_of_ports);
1596*4882a593Smuzhiyun mlxsw_sp_mc_get_mrouters_bitmap(flood_bitmap, bridge_device, mlxsw_sp);
1597*4882a593Smuzhiyun
1598*4882a593Smuzhiyun mid->mid = mid_idx;
1599*4882a593Smuzhiyun err = mlxsw_sp_port_smid_full_entry(mlxsw_sp, mid_idx, flood_bitmap,
1600*4882a593Smuzhiyun bridge_device->mrouter);
1601*4882a593Smuzhiyun kfree(flood_bitmap);
1602*4882a593Smuzhiyun if (err)
1603*4882a593Smuzhiyun return false;
1604*4882a593Smuzhiyun
1605*4882a593Smuzhiyun err = mlxsw_sp_port_mdb_op(mlxsw_sp, mid->addr, mid->fid, mid_idx,
1606*4882a593Smuzhiyun true);
1607*4882a593Smuzhiyun if (err)
1608*4882a593Smuzhiyun return false;
1609*4882a593Smuzhiyun
1610*4882a593Smuzhiyun set_bit(mid_idx, mlxsw_sp->bridge->mids_bitmap);
1611*4882a593Smuzhiyun mid->in_hw = true;
1612*4882a593Smuzhiyun return true;
1613*4882a593Smuzhiyun }
1614*4882a593Smuzhiyun
mlxsw_sp_mc_remove_mdb_entry(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_mid * mid)1615*4882a593Smuzhiyun static int mlxsw_sp_mc_remove_mdb_entry(struct mlxsw_sp *mlxsw_sp,
1616*4882a593Smuzhiyun struct mlxsw_sp_mid *mid)
1617*4882a593Smuzhiyun {
1618*4882a593Smuzhiyun if (!mid->in_hw)
1619*4882a593Smuzhiyun return 0;
1620*4882a593Smuzhiyun
1621*4882a593Smuzhiyun clear_bit(mid->mid, mlxsw_sp->bridge->mids_bitmap);
1622*4882a593Smuzhiyun mid->in_hw = false;
1623*4882a593Smuzhiyun return mlxsw_sp_port_mdb_op(mlxsw_sp, mid->addr, mid->fid, mid->mid,
1624*4882a593Smuzhiyun false);
1625*4882a593Smuzhiyun }
1626*4882a593Smuzhiyun
1627*4882a593Smuzhiyun static struct
__mlxsw_sp_mc_alloc(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_bridge_device * bridge_device,const unsigned char * addr,u16 fid)1628*4882a593Smuzhiyun mlxsw_sp_mid *__mlxsw_sp_mc_alloc(struct mlxsw_sp *mlxsw_sp,
1629*4882a593Smuzhiyun struct mlxsw_sp_bridge_device *bridge_device,
1630*4882a593Smuzhiyun const unsigned char *addr,
1631*4882a593Smuzhiyun u16 fid)
1632*4882a593Smuzhiyun {
1633*4882a593Smuzhiyun struct mlxsw_sp_mid *mid;
1634*4882a593Smuzhiyun size_t alloc_size;
1635*4882a593Smuzhiyun
1636*4882a593Smuzhiyun mid = kzalloc(sizeof(*mid), GFP_KERNEL);
1637*4882a593Smuzhiyun if (!mid)
1638*4882a593Smuzhiyun return NULL;
1639*4882a593Smuzhiyun
1640*4882a593Smuzhiyun alloc_size = sizeof(unsigned long) *
1641*4882a593Smuzhiyun BITS_TO_LONGS(mlxsw_core_max_ports(mlxsw_sp->core));
1642*4882a593Smuzhiyun
1643*4882a593Smuzhiyun mid->ports_in_mid = kzalloc(alloc_size, GFP_KERNEL);
1644*4882a593Smuzhiyun if (!mid->ports_in_mid)
1645*4882a593Smuzhiyun goto err_ports_in_mid_alloc;
1646*4882a593Smuzhiyun
1647*4882a593Smuzhiyun ether_addr_copy(mid->addr, addr);
1648*4882a593Smuzhiyun mid->fid = fid;
1649*4882a593Smuzhiyun mid->in_hw = false;
1650*4882a593Smuzhiyun
1651*4882a593Smuzhiyun if (!bridge_device->multicast_enabled)
1652*4882a593Smuzhiyun goto out;
1653*4882a593Smuzhiyun
1654*4882a593Smuzhiyun if (!mlxsw_sp_mc_write_mdb_entry(mlxsw_sp, mid, bridge_device))
1655*4882a593Smuzhiyun goto err_write_mdb_entry;
1656*4882a593Smuzhiyun
1657*4882a593Smuzhiyun out:
1658*4882a593Smuzhiyun list_add_tail(&mid->list, &bridge_device->mids_list);
1659*4882a593Smuzhiyun return mid;
1660*4882a593Smuzhiyun
1661*4882a593Smuzhiyun err_write_mdb_entry:
1662*4882a593Smuzhiyun kfree(mid->ports_in_mid);
1663*4882a593Smuzhiyun err_ports_in_mid_alloc:
1664*4882a593Smuzhiyun kfree(mid);
1665*4882a593Smuzhiyun return NULL;
1666*4882a593Smuzhiyun }
1667*4882a593Smuzhiyun
mlxsw_sp_port_remove_from_mid(struct mlxsw_sp_port * mlxsw_sp_port,struct mlxsw_sp_mid * mid)1668*4882a593Smuzhiyun static int mlxsw_sp_port_remove_from_mid(struct mlxsw_sp_port *mlxsw_sp_port,
1669*4882a593Smuzhiyun struct mlxsw_sp_mid *mid)
1670*4882a593Smuzhiyun {
1671*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1672*4882a593Smuzhiyun int err = 0;
1673*4882a593Smuzhiyun
1674*4882a593Smuzhiyun clear_bit(mlxsw_sp_port->local_port, mid->ports_in_mid);
1675*4882a593Smuzhiyun if (bitmap_empty(mid->ports_in_mid,
1676*4882a593Smuzhiyun mlxsw_core_max_ports(mlxsw_sp->core))) {
1677*4882a593Smuzhiyun err = mlxsw_sp_mc_remove_mdb_entry(mlxsw_sp, mid);
1678*4882a593Smuzhiyun list_del(&mid->list);
1679*4882a593Smuzhiyun kfree(mid->ports_in_mid);
1680*4882a593Smuzhiyun kfree(mid);
1681*4882a593Smuzhiyun }
1682*4882a593Smuzhiyun return err;
1683*4882a593Smuzhiyun }
1684*4882a593Smuzhiyun
mlxsw_sp_port_mdb_add(struct mlxsw_sp_port * mlxsw_sp_port,const struct switchdev_obj_port_mdb * mdb,struct switchdev_trans * trans)1685*4882a593Smuzhiyun static int mlxsw_sp_port_mdb_add(struct mlxsw_sp_port *mlxsw_sp_port,
1686*4882a593Smuzhiyun const struct switchdev_obj_port_mdb *mdb,
1687*4882a593Smuzhiyun struct switchdev_trans *trans)
1688*4882a593Smuzhiyun {
1689*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1690*4882a593Smuzhiyun struct net_device *orig_dev = mdb->obj.orig_dev;
1691*4882a593Smuzhiyun struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
1692*4882a593Smuzhiyun struct net_device *dev = mlxsw_sp_port->dev;
1693*4882a593Smuzhiyun struct mlxsw_sp_bridge_device *bridge_device;
1694*4882a593Smuzhiyun struct mlxsw_sp_bridge_port *bridge_port;
1695*4882a593Smuzhiyun struct mlxsw_sp_mid *mid;
1696*4882a593Smuzhiyun u16 fid_index;
1697*4882a593Smuzhiyun int err = 0;
1698*4882a593Smuzhiyun
1699*4882a593Smuzhiyun if (switchdev_trans_ph_commit(trans))
1700*4882a593Smuzhiyun return 0;
1701*4882a593Smuzhiyun
1702*4882a593Smuzhiyun bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev);
1703*4882a593Smuzhiyun if (!bridge_port)
1704*4882a593Smuzhiyun return 0;
1705*4882a593Smuzhiyun
1706*4882a593Smuzhiyun bridge_device = bridge_port->bridge_device;
1707*4882a593Smuzhiyun mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_bridge(mlxsw_sp_port,
1708*4882a593Smuzhiyun bridge_device,
1709*4882a593Smuzhiyun mdb->vid);
1710*4882a593Smuzhiyun if (!mlxsw_sp_port_vlan)
1711*4882a593Smuzhiyun return 0;
1712*4882a593Smuzhiyun
1713*4882a593Smuzhiyun fid_index = mlxsw_sp_fid_index(mlxsw_sp_port_vlan->fid);
1714*4882a593Smuzhiyun
1715*4882a593Smuzhiyun mid = __mlxsw_sp_mc_get(bridge_device, mdb->addr, fid_index);
1716*4882a593Smuzhiyun if (!mid) {
1717*4882a593Smuzhiyun mid = __mlxsw_sp_mc_alloc(mlxsw_sp, bridge_device, mdb->addr,
1718*4882a593Smuzhiyun fid_index);
1719*4882a593Smuzhiyun if (!mid) {
1720*4882a593Smuzhiyun netdev_err(dev, "Unable to allocate MC group\n");
1721*4882a593Smuzhiyun return -ENOMEM;
1722*4882a593Smuzhiyun }
1723*4882a593Smuzhiyun }
1724*4882a593Smuzhiyun set_bit(mlxsw_sp_port->local_port, mid->ports_in_mid);
1725*4882a593Smuzhiyun
1726*4882a593Smuzhiyun if (!bridge_device->multicast_enabled)
1727*4882a593Smuzhiyun return 0;
1728*4882a593Smuzhiyun
1729*4882a593Smuzhiyun if (bridge_port->mrouter)
1730*4882a593Smuzhiyun return 0;
1731*4882a593Smuzhiyun
1732*4882a593Smuzhiyun err = mlxsw_sp_port_smid_set(mlxsw_sp_port, mid->mid, true);
1733*4882a593Smuzhiyun if (err) {
1734*4882a593Smuzhiyun netdev_err(dev, "Unable to set SMID\n");
1735*4882a593Smuzhiyun goto err_out;
1736*4882a593Smuzhiyun }
1737*4882a593Smuzhiyun
1738*4882a593Smuzhiyun return 0;
1739*4882a593Smuzhiyun
1740*4882a593Smuzhiyun err_out:
1741*4882a593Smuzhiyun mlxsw_sp_port_remove_from_mid(mlxsw_sp_port, mid);
1742*4882a593Smuzhiyun return err;
1743*4882a593Smuzhiyun }
1744*4882a593Smuzhiyun
1745*4882a593Smuzhiyun static void
mlxsw_sp_bridge_mdb_mc_enable_sync(struct mlxsw_sp_port * mlxsw_sp_port,struct mlxsw_sp_bridge_device * bridge_device)1746*4882a593Smuzhiyun mlxsw_sp_bridge_mdb_mc_enable_sync(struct mlxsw_sp_port *mlxsw_sp_port,
1747*4882a593Smuzhiyun struct mlxsw_sp_bridge_device
1748*4882a593Smuzhiyun *bridge_device)
1749*4882a593Smuzhiyun {
1750*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1751*4882a593Smuzhiyun struct mlxsw_sp_mid *mid;
1752*4882a593Smuzhiyun bool mc_enabled;
1753*4882a593Smuzhiyun
1754*4882a593Smuzhiyun mc_enabled = bridge_device->multicast_enabled;
1755*4882a593Smuzhiyun
1756*4882a593Smuzhiyun list_for_each_entry(mid, &bridge_device->mids_list, list) {
1757*4882a593Smuzhiyun if (mc_enabled)
1758*4882a593Smuzhiyun mlxsw_sp_mc_write_mdb_entry(mlxsw_sp, mid,
1759*4882a593Smuzhiyun bridge_device);
1760*4882a593Smuzhiyun else
1761*4882a593Smuzhiyun mlxsw_sp_mc_remove_mdb_entry(mlxsw_sp, mid);
1762*4882a593Smuzhiyun }
1763*4882a593Smuzhiyun }
1764*4882a593Smuzhiyun
1765*4882a593Smuzhiyun static void
mlxsw_sp_port_mrouter_update_mdb(struct mlxsw_sp_port * mlxsw_sp_port,struct mlxsw_sp_bridge_port * bridge_port,bool add)1766*4882a593Smuzhiyun mlxsw_sp_port_mrouter_update_mdb(struct mlxsw_sp_port *mlxsw_sp_port,
1767*4882a593Smuzhiyun struct mlxsw_sp_bridge_port *bridge_port,
1768*4882a593Smuzhiyun bool add)
1769*4882a593Smuzhiyun {
1770*4882a593Smuzhiyun struct mlxsw_sp_bridge_device *bridge_device;
1771*4882a593Smuzhiyun struct mlxsw_sp_mid *mid;
1772*4882a593Smuzhiyun
1773*4882a593Smuzhiyun bridge_device = bridge_port->bridge_device;
1774*4882a593Smuzhiyun
1775*4882a593Smuzhiyun list_for_each_entry(mid, &bridge_device->mids_list, list) {
1776*4882a593Smuzhiyun if (!test_bit(mlxsw_sp_port->local_port, mid->ports_in_mid))
1777*4882a593Smuzhiyun mlxsw_sp_port_smid_set(mlxsw_sp_port, mid->mid, add);
1778*4882a593Smuzhiyun }
1779*4882a593Smuzhiyun }
1780*4882a593Smuzhiyun
mlxsw_sp_port_obj_add(struct net_device * dev,const struct switchdev_obj * obj,struct switchdev_trans * trans,struct netlink_ext_ack * extack)1781*4882a593Smuzhiyun static int mlxsw_sp_port_obj_add(struct net_device *dev,
1782*4882a593Smuzhiyun const struct switchdev_obj *obj,
1783*4882a593Smuzhiyun struct switchdev_trans *trans,
1784*4882a593Smuzhiyun struct netlink_ext_ack *extack)
1785*4882a593Smuzhiyun {
1786*4882a593Smuzhiyun struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
1787*4882a593Smuzhiyun const struct switchdev_obj_port_vlan *vlan;
1788*4882a593Smuzhiyun int err = 0;
1789*4882a593Smuzhiyun
1790*4882a593Smuzhiyun switch (obj->id) {
1791*4882a593Smuzhiyun case SWITCHDEV_OBJ_ID_PORT_VLAN:
1792*4882a593Smuzhiyun vlan = SWITCHDEV_OBJ_PORT_VLAN(obj);
1793*4882a593Smuzhiyun err = mlxsw_sp_port_vlans_add(mlxsw_sp_port, vlan, trans,
1794*4882a593Smuzhiyun extack);
1795*4882a593Smuzhiyun
1796*4882a593Smuzhiyun if (switchdev_trans_ph_prepare(trans)) {
1797*4882a593Smuzhiyun /* The event is emitted before the changes are actually
1798*4882a593Smuzhiyun * applied to the bridge. Therefore schedule the respin
1799*4882a593Smuzhiyun * call for later, so that the respin logic sees the
1800*4882a593Smuzhiyun * updated bridge state.
1801*4882a593Smuzhiyun */
1802*4882a593Smuzhiyun mlxsw_sp_span_respin(mlxsw_sp_port->mlxsw_sp);
1803*4882a593Smuzhiyun }
1804*4882a593Smuzhiyun break;
1805*4882a593Smuzhiyun case SWITCHDEV_OBJ_ID_PORT_MDB:
1806*4882a593Smuzhiyun err = mlxsw_sp_port_mdb_add(mlxsw_sp_port,
1807*4882a593Smuzhiyun SWITCHDEV_OBJ_PORT_MDB(obj),
1808*4882a593Smuzhiyun trans);
1809*4882a593Smuzhiyun break;
1810*4882a593Smuzhiyun default:
1811*4882a593Smuzhiyun err = -EOPNOTSUPP;
1812*4882a593Smuzhiyun break;
1813*4882a593Smuzhiyun }
1814*4882a593Smuzhiyun
1815*4882a593Smuzhiyun return err;
1816*4882a593Smuzhiyun }
1817*4882a593Smuzhiyun
1818*4882a593Smuzhiyun static void
mlxsw_sp_bridge_port_vlan_del(struct mlxsw_sp_port * mlxsw_sp_port,struct mlxsw_sp_bridge_port * bridge_port,u16 vid)1819*4882a593Smuzhiyun mlxsw_sp_bridge_port_vlan_del(struct mlxsw_sp_port *mlxsw_sp_port,
1820*4882a593Smuzhiyun struct mlxsw_sp_bridge_port *bridge_port, u16 vid)
1821*4882a593Smuzhiyun {
1822*4882a593Smuzhiyun u16 pvid = mlxsw_sp_port->pvid == vid ? 0 : mlxsw_sp_port->pvid;
1823*4882a593Smuzhiyun struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
1824*4882a593Smuzhiyun
1825*4882a593Smuzhiyun mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid);
1826*4882a593Smuzhiyun if (WARN_ON(!mlxsw_sp_port_vlan))
1827*4882a593Smuzhiyun return;
1828*4882a593Smuzhiyun
1829*4882a593Smuzhiyun mlxsw_sp_port_vlan_bridge_leave(mlxsw_sp_port_vlan);
1830*4882a593Smuzhiyun mlxsw_sp_port_pvid_set(mlxsw_sp_port, pvid);
1831*4882a593Smuzhiyun mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, false, false);
1832*4882a593Smuzhiyun mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan);
1833*4882a593Smuzhiyun }
1834*4882a593Smuzhiyun
mlxsw_sp_port_vlans_del(struct mlxsw_sp_port * mlxsw_sp_port,const struct switchdev_obj_port_vlan * vlan)1835*4882a593Smuzhiyun static int mlxsw_sp_port_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port,
1836*4882a593Smuzhiyun const struct switchdev_obj_port_vlan *vlan)
1837*4882a593Smuzhiyun {
1838*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1839*4882a593Smuzhiyun struct net_device *orig_dev = vlan->obj.orig_dev;
1840*4882a593Smuzhiyun struct mlxsw_sp_bridge_port *bridge_port;
1841*4882a593Smuzhiyun u16 vid;
1842*4882a593Smuzhiyun
1843*4882a593Smuzhiyun if (netif_is_bridge_master(orig_dev))
1844*4882a593Smuzhiyun return -EOPNOTSUPP;
1845*4882a593Smuzhiyun
1846*4882a593Smuzhiyun bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev);
1847*4882a593Smuzhiyun if (WARN_ON(!bridge_port))
1848*4882a593Smuzhiyun return -EINVAL;
1849*4882a593Smuzhiyun
1850*4882a593Smuzhiyun if (!bridge_port->bridge_device->vlan_enabled)
1851*4882a593Smuzhiyun return 0;
1852*4882a593Smuzhiyun
1853*4882a593Smuzhiyun for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++)
1854*4882a593Smuzhiyun mlxsw_sp_bridge_port_vlan_del(mlxsw_sp_port, bridge_port, vid);
1855*4882a593Smuzhiyun
1856*4882a593Smuzhiyun return 0;
1857*4882a593Smuzhiyun }
1858*4882a593Smuzhiyun
1859*4882a593Smuzhiyun static int
__mlxsw_sp_port_mdb_del(struct mlxsw_sp_port * mlxsw_sp_port,struct mlxsw_sp_bridge_port * bridge_port,struct mlxsw_sp_mid * mid)1860*4882a593Smuzhiyun __mlxsw_sp_port_mdb_del(struct mlxsw_sp_port *mlxsw_sp_port,
1861*4882a593Smuzhiyun struct mlxsw_sp_bridge_port *bridge_port,
1862*4882a593Smuzhiyun struct mlxsw_sp_mid *mid)
1863*4882a593Smuzhiyun {
1864*4882a593Smuzhiyun struct net_device *dev = mlxsw_sp_port->dev;
1865*4882a593Smuzhiyun int err;
1866*4882a593Smuzhiyun
1867*4882a593Smuzhiyun if (bridge_port->bridge_device->multicast_enabled &&
1868*4882a593Smuzhiyun !bridge_port->mrouter) {
1869*4882a593Smuzhiyun err = mlxsw_sp_port_smid_set(mlxsw_sp_port, mid->mid, false);
1870*4882a593Smuzhiyun if (err)
1871*4882a593Smuzhiyun netdev_err(dev, "Unable to remove port from SMID\n");
1872*4882a593Smuzhiyun }
1873*4882a593Smuzhiyun
1874*4882a593Smuzhiyun err = mlxsw_sp_port_remove_from_mid(mlxsw_sp_port, mid);
1875*4882a593Smuzhiyun if (err)
1876*4882a593Smuzhiyun netdev_err(dev, "Unable to remove MC SFD\n");
1877*4882a593Smuzhiyun
1878*4882a593Smuzhiyun return err;
1879*4882a593Smuzhiyun }
1880*4882a593Smuzhiyun
mlxsw_sp_port_mdb_del(struct mlxsw_sp_port * mlxsw_sp_port,const struct switchdev_obj_port_mdb * mdb)1881*4882a593Smuzhiyun static int mlxsw_sp_port_mdb_del(struct mlxsw_sp_port *mlxsw_sp_port,
1882*4882a593Smuzhiyun const struct switchdev_obj_port_mdb *mdb)
1883*4882a593Smuzhiyun {
1884*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1885*4882a593Smuzhiyun struct net_device *orig_dev = mdb->obj.orig_dev;
1886*4882a593Smuzhiyun struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
1887*4882a593Smuzhiyun struct mlxsw_sp_bridge_device *bridge_device;
1888*4882a593Smuzhiyun struct net_device *dev = mlxsw_sp_port->dev;
1889*4882a593Smuzhiyun struct mlxsw_sp_bridge_port *bridge_port;
1890*4882a593Smuzhiyun struct mlxsw_sp_mid *mid;
1891*4882a593Smuzhiyun u16 fid_index;
1892*4882a593Smuzhiyun
1893*4882a593Smuzhiyun bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev);
1894*4882a593Smuzhiyun if (!bridge_port)
1895*4882a593Smuzhiyun return 0;
1896*4882a593Smuzhiyun
1897*4882a593Smuzhiyun bridge_device = bridge_port->bridge_device;
1898*4882a593Smuzhiyun mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_bridge(mlxsw_sp_port,
1899*4882a593Smuzhiyun bridge_device,
1900*4882a593Smuzhiyun mdb->vid);
1901*4882a593Smuzhiyun if (!mlxsw_sp_port_vlan)
1902*4882a593Smuzhiyun return 0;
1903*4882a593Smuzhiyun
1904*4882a593Smuzhiyun fid_index = mlxsw_sp_fid_index(mlxsw_sp_port_vlan->fid);
1905*4882a593Smuzhiyun
1906*4882a593Smuzhiyun mid = __mlxsw_sp_mc_get(bridge_device, mdb->addr, fid_index);
1907*4882a593Smuzhiyun if (!mid) {
1908*4882a593Smuzhiyun netdev_err(dev, "Unable to remove port from MC DB\n");
1909*4882a593Smuzhiyun return -EINVAL;
1910*4882a593Smuzhiyun }
1911*4882a593Smuzhiyun
1912*4882a593Smuzhiyun return __mlxsw_sp_port_mdb_del(mlxsw_sp_port, bridge_port, mid);
1913*4882a593Smuzhiyun }
1914*4882a593Smuzhiyun
1915*4882a593Smuzhiyun static void
mlxsw_sp_bridge_port_mdb_flush(struct mlxsw_sp_port * mlxsw_sp_port,struct mlxsw_sp_bridge_port * bridge_port)1916*4882a593Smuzhiyun mlxsw_sp_bridge_port_mdb_flush(struct mlxsw_sp_port *mlxsw_sp_port,
1917*4882a593Smuzhiyun struct mlxsw_sp_bridge_port *bridge_port)
1918*4882a593Smuzhiyun {
1919*4882a593Smuzhiyun struct mlxsw_sp_bridge_device *bridge_device;
1920*4882a593Smuzhiyun struct mlxsw_sp_mid *mid, *tmp;
1921*4882a593Smuzhiyun
1922*4882a593Smuzhiyun bridge_device = bridge_port->bridge_device;
1923*4882a593Smuzhiyun
1924*4882a593Smuzhiyun list_for_each_entry_safe(mid, tmp, &bridge_device->mids_list, list) {
1925*4882a593Smuzhiyun if (test_bit(mlxsw_sp_port->local_port, mid->ports_in_mid)) {
1926*4882a593Smuzhiyun __mlxsw_sp_port_mdb_del(mlxsw_sp_port, bridge_port,
1927*4882a593Smuzhiyun mid);
1928*4882a593Smuzhiyun } else if (bridge_device->multicast_enabled &&
1929*4882a593Smuzhiyun bridge_port->mrouter) {
1930*4882a593Smuzhiyun mlxsw_sp_port_smid_set(mlxsw_sp_port, mid->mid, false);
1931*4882a593Smuzhiyun }
1932*4882a593Smuzhiyun }
1933*4882a593Smuzhiyun }
1934*4882a593Smuzhiyun
mlxsw_sp_port_obj_del(struct net_device * dev,const struct switchdev_obj * obj)1935*4882a593Smuzhiyun static int mlxsw_sp_port_obj_del(struct net_device *dev,
1936*4882a593Smuzhiyun const struct switchdev_obj *obj)
1937*4882a593Smuzhiyun {
1938*4882a593Smuzhiyun struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
1939*4882a593Smuzhiyun int err = 0;
1940*4882a593Smuzhiyun
1941*4882a593Smuzhiyun switch (obj->id) {
1942*4882a593Smuzhiyun case SWITCHDEV_OBJ_ID_PORT_VLAN:
1943*4882a593Smuzhiyun err = mlxsw_sp_port_vlans_del(mlxsw_sp_port,
1944*4882a593Smuzhiyun SWITCHDEV_OBJ_PORT_VLAN(obj));
1945*4882a593Smuzhiyun break;
1946*4882a593Smuzhiyun case SWITCHDEV_OBJ_ID_PORT_MDB:
1947*4882a593Smuzhiyun err = mlxsw_sp_port_mdb_del(mlxsw_sp_port,
1948*4882a593Smuzhiyun SWITCHDEV_OBJ_PORT_MDB(obj));
1949*4882a593Smuzhiyun break;
1950*4882a593Smuzhiyun default:
1951*4882a593Smuzhiyun err = -EOPNOTSUPP;
1952*4882a593Smuzhiyun break;
1953*4882a593Smuzhiyun }
1954*4882a593Smuzhiyun
1955*4882a593Smuzhiyun mlxsw_sp_span_respin(mlxsw_sp_port->mlxsw_sp);
1956*4882a593Smuzhiyun
1957*4882a593Smuzhiyun return err;
1958*4882a593Smuzhiyun }
1959*4882a593Smuzhiyun
mlxsw_sp_lag_rep_port(struct mlxsw_sp * mlxsw_sp,u16 lag_id)1960*4882a593Smuzhiyun static struct mlxsw_sp_port *mlxsw_sp_lag_rep_port(struct mlxsw_sp *mlxsw_sp,
1961*4882a593Smuzhiyun u16 lag_id)
1962*4882a593Smuzhiyun {
1963*4882a593Smuzhiyun struct mlxsw_sp_port *mlxsw_sp_port;
1964*4882a593Smuzhiyun u64 max_lag_members;
1965*4882a593Smuzhiyun int i;
1966*4882a593Smuzhiyun
1967*4882a593Smuzhiyun max_lag_members = MLXSW_CORE_RES_GET(mlxsw_sp->core,
1968*4882a593Smuzhiyun MAX_LAG_MEMBERS);
1969*4882a593Smuzhiyun for (i = 0; i < max_lag_members; i++) {
1970*4882a593Smuzhiyun mlxsw_sp_port = mlxsw_sp_port_lagged_get(mlxsw_sp, lag_id, i);
1971*4882a593Smuzhiyun if (mlxsw_sp_port)
1972*4882a593Smuzhiyun return mlxsw_sp_port;
1973*4882a593Smuzhiyun }
1974*4882a593Smuzhiyun return NULL;
1975*4882a593Smuzhiyun }
1976*4882a593Smuzhiyun
1977*4882a593Smuzhiyun static int
mlxsw_sp_bridge_8021q_port_join(struct mlxsw_sp_bridge_device * bridge_device,struct mlxsw_sp_bridge_port * bridge_port,struct mlxsw_sp_port * mlxsw_sp_port,struct netlink_ext_ack * extack)1978*4882a593Smuzhiyun mlxsw_sp_bridge_8021q_port_join(struct mlxsw_sp_bridge_device *bridge_device,
1979*4882a593Smuzhiyun struct mlxsw_sp_bridge_port *bridge_port,
1980*4882a593Smuzhiyun struct mlxsw_sp_port *mlxsw_sp_port,
1981*4882a593Smuzhiyun struct netlink_ext_ack *extack)
1982*4882a593Smuzhiyun {
1983*4882a593Smuzhiyun if (is_vlan_dev(bridge_port->dev)) {
1984*4882a593Smuzhiyun NL_SET_ERR_MSG_MOD(extack, "Can not enslave a VLAN device to a VLAN-aware bridge");
1985*4882a593Smuzhiyun return -EINVAL;
1986*4882a593Smuzhiyun }
1987*4882a593Smuzhiyun
1988*4882a593Smuzhiyun /* Port is no longer usable as a router interface */
1989*4882a593Smuzhiyun if (mlxsw_sp_port->default_vlan->fid)
1990*4882a593Smuzhiyun mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port->default_vlan);
1991*4882a593Smuzhiyun
1992*4882a593Smuzhiyun return 0;
1993*4882a593Smuzhiyun }
1994*4882a593Smuzhiyun
1995*4882a593Smuzhiyun static void
mlxsw_sp_bridge_8021q_port_leave(struct mlxsw_sp_bridge_device * bridge_device,struct mlxsw_sp_bridge_port * bridge_port,struct mlxsw_sp_port * mlxsw_sp_port)1996*4882a593Smuzhiyun mlxsw_sp_bridge_8021q_port_leave(struct mlxsw_sp_bridge_device *bridge_device,
1997*4882a593Smuzhiyun struct mlxsw_sp_bridge_port *bridge_port,
1998*4882a593Smuzhiyun struct mlxsw_sp_port *mlxsw_sp_port)
1999*4882a593Smuzhiyun {
2000*4882a593Smuzhiyun /* Make sure untagged frames are allowed to ingress */
2001*4882a593Smuzhiyun mlxsw_sp_port_pvid_set(mlxsw_sp_port, MLXSW_SP_DEFAULT_VID);
2002*4882a593Smuzhiyun }
2003*4882a593Smuzhiyun
2004*4882a593Smuzhiyun static int
mlxsw_sp_bridge_8021q_vxlan_join(struct mlxsw_sp_bridge_device * bridge_device,const struct net_device * vxlan_dev,u16 vid,struct netlink_ext_ack * extack)2005*4882a593Smuzhiyun mlxsw_sp_bridge_8021q_vxlan_join(struct mlxsw_sp_bridge_device *bridge_device,
2006*4882a593Smuzhiyun const struct net_device *vxlan_dev, u16 vid,
2007*4882a593Smuzhiyun struct netlink_ext_ack *extack)
2008*4882a593Smuzhiyun {
2009*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_device->dev);
2010*4882a593Smuzhiyun struct vxlan_dev *vxlan = netdev_priv(vxlan_dev);
2011*4882a593Smuzhiyun struct mlxsw_sp_nve_params params = {
2012*4882a593Smuzhiyun .type = MLXSW_SP_NVE_TYPE_VXLAN,
2013*4882a593Smuzhiyun .vni = vxlan->cfg.vni,
2014*4882a593Smuzhiyun .dev = vxlan_dev,
2015*4882a593Smuzhiyun };
2016*4882a593Smuzhiyun struct mlxsw_sp_fid *fid;
2017*4882a593Smuzhiyun int err;
2018*4882a593Smuzhiyun
2019*4882a593Smuzhiyun /* If the VLAN is 0, we need to find the VLAN that is configured as
2020*4882a593Smuzhiyun * PVID and egress untagged on the bridge port of the VxLAN device.
2021*4882a593Smuzhiyun * It is possible no such VLAN exists
2022*4882a593Smuzhiyun */
2023*4882a593Smuzhiyun if (!vid) {
2024*4882a593Smuzhiyun err = mlxsw_sp_vxlan_mapped_vid(vxlan_dev, &vid);
2025*4882a593Smuzhiyun if (err || !vid)
2026*4882a593Smuzhiyun return err;
2027*4882a593Smuzhiyun }
2028*4882a593Smuzhiyun
2029*4882a593Smuzhiyun fid = mlxsw_sp_fid_8021q_get(mlxsw_sp, vid);
2030*4882a593Smuzhiyun if (IS_ERR(fid)) {
2031*4882a593Smuzhiyun NL_SET_ERR_MSG_MOD(extack, "Failed to create 802.1Q FID");
2032*4882a593Smuzhiyun return PTR_ERR(fid);
2033*4882a593Smuzhiyun }
2034*4882a593Smuzhiyun
2035*4882a593Smuzhiyun if (mlxsw_sp_fid_vni_is_set(fid)) {
2036*4882a593Smuzhiyun NL_SET_ERR_MSG_MOD(extack, "VNI is already set on FID");
2037*4882a593Smuzhiyun err = -EINVAL;
2038*4882a593Smuzhiyun goto err_vni_exists;
2039*4882a593Smuzhiyun }
2040*4882a593Smuzhiyun
2041*4882a593Smuzhiyun err = mlxsw_sp_nve_fid_enable(mlxsw_sp, fid, ¶ms, extack);
2042*4882a593Smuzhiyun if (err)
2043*4882a593Smuzhiyun goto err_nve_fid_enable;
2044*4882a593Smuzhiyun
2045*4882a593Smuzhiyun return 0;
2046*4882a593Smuzhiyun
2047*4882a593Smuzhiyun err_nve_fid_enable:
2048*4882a593Smuzhiyun err_vni_exists:
2049*4882a593Smuzhiyun mlxsw_sp_fid_put(fid);
2050*4882a593Smuzhiyun return err;
2051*4882a593Smuzhiyun }
2052*4882a593Smuzhiyun
2053*4882a593Smuzhiyun static struct net_device *
mlxsw_sp_bridge_8021q_vxlan_dev_find(struct net_device * br_dev,u16 vid)2054*4882a593Smuzhiyun mlxsw_sp_bridge_8021q_vxlan_dev_find(struct net_device *br_dev, u16 vid)
2055*4882a593Smuzhiyun {
2056*4882a593Smuzhiyun struct net_device *dev;
2057*4882a593Smuzhiyun struct list_head *iter;
2058*4882a593Smuzhiyun
2059*4882a593Smuzhiyun netdev_for_each_lower_dev(br_dev, dev, iter) {
2060*4882a593Smuzhiyun u16 pvid;
2061*4882a593Smuzhiyun int err;
2062*4882a593Smuzhiyun
2063*4882a593Smuzhiyun if (!netif_is_vxlan(dev))
2064*4882a593Smuzhiyun continue;
2065*4882a593Smuzhiyun
2066*4882a593Smuzhiyun err = mlxsw_sp_vxlan_mapped_vid(dev, &pvid);
2067*4882a593Smuzhiyun if (err || pvid != vid)
2068*4882a593Smuzhiyun continue;
2069*4882a593Smuzhiyun
2070*4882a593Smuzhiyun return dev;
2071*4882a593Smuzhiyun }
2072*4882a593Smuzhiyun
2073*4882a593Smuzhiyun return NULL;
2074*4882a593Smuzhiyun }
2075*4882a593Smuzhiyun
2076*4882a593Smuzhiyun static struct mlxsw_sp_fid *
mlxsw_sp_bridge_8021q_fid_get(struct mlxsw_sp_bridge_device * bridge_device,u16 vid,struct netlink_ext_ack * extack)2077*4882a593Smuzhiyun mlxsw_sp_bridge_8021q_fid_get(struct mlxsw_sp_bridge_device *bridge_device,
2078*4882a593Smuzhiyun u16 vid, struct netlink_ext_ack *extack)
2079*4882a593Smuzhiyun {
2080*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_device->dev);
2081*4882a593Smuzhiyun
2082*4882a593Smuzhiyun return mlxsw_sp_fid_8021q_get(mlxsw_sp, vid);
2083*4882a593Smuzhiyun }
2084*4882a593Smuzhiyun
2085*4882a593Smuzhiyun static struct mlxsw_sp_fid *
mlxsw_sp_bridge_8021q_fid_lookup(struct mlxsw_sp_bridge_device * bridge_device,u16 vid)2086*4882a593Smuzhiyun mlxsw_sp_bridge_8021q_fid_lookup(struct mlxsw_sp_bridge_device *bridge_device,
2087*4882a593Smuzhiyun u16 vid)
2088*4882a593Smuzhiyun {
2089*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_device->dev);
2090*4882a593Smuzhiyun
2091*4882a593Smuzhiyun return mlxsw_sp_fid_8021q_lookup(mlxsw_sp, vid);
2092*4882a593Smuzhiyun }
2093*4882a593Smuzhiyun
2094*4882a593Smuzhiyun static u16
mlxsw_sp_bridge_8021q_fid_vid(struct mlxsw_sp_bridge_device * bridge_device,const struct mlxsw_sp_fid * fid)2095*4882a593Smuzhiyun mlxsw_sp_bridge_8021q_fid_vid(struct mlxsw_sp_bridge_device *bridge_device,
2096*4882a593Smuzhiyun const struct mlxsw_sp_fid *fid)
2097*4882a593Smuzhiyun {
2098*4882a593Smuzhiyun return mlxsw_sp_fid_8021q_vid(fid);
2099*4882a593Smuzhiyun }
2100*4882a593Smuzhiyun
2101*4882a593Smuzhiyun static const struct mlxsw_sp_bridge_ops mlxsw_sp_bridge_8021q_ops = {
2102*4882a593Smuzhiyun .port_join = mlxsw_sp_bridge_8021q_port_join,
2103*4882a593Smuzhiyun .port_leave = mlxsw_sp_bridge_8021q_port_leave,
2104*4882a593Smuzhiyun .vxlan_join = mlxsw_sp_bridge_8021q_vxlan_join,
2105*4882a593Smuzhiyun .fid_get = mlxsw_sp_bridge_8021q_fid_get,
2106*4882a593Smuzhiyun .fid_lookup = mlxsw_sp_bridge_8021q_fid_lookup,
2107*4882a593Smuzhiyun .fid_vid = mlxsw_sp_bridge_8021q_fid_vid,
2108*4882a593Smuzhiyun };
2109*4882a593Smuzhiyun
2110*4882a593Smuzhiyun static bool
mlxsw_sp_port_is_br_member(const struct mlxsw_sp_port * mlxsw_sp_port,const struct net_device * br_dev)2111*4882a593Smuzhiyun mlxsw_sp_port_is_br_member(const struct mlxsw_sp_port *mlxsw_sp_port,
2112*4882a593Smuzhiyun const struct net_device *br_dev)
2113*4882a593Smuzhiyun {
2114*4882a593Smuzhiyun struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
2115*4882a593Smuzhiyun
2116*4882a593Smuzhiyun list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list,
2117*4882a593Smuzhiyun list) {
2118*4882a593Smuzhiyun if (mlxsw_sp_port_vlan->bridge_port &&
2119*4882a593Smuzhiyun mlxsw_sp_port_vlan->bridge_port->bridge_device->dev ==
2120*4882a593Smuzhiyun br_dev)
2121*4882a593Smuzhiyun return true;
2122*4882a593Smuzhiyun }
2123*4882a593Smuzhiyun
2124*4882a593Smuzhiyun return false;
2125*4882a593Smuzhiyun }
2126*4882a593Smuzhiyun
2127*4882a593Smuzhiyun static int
mlxsw_sp_bridge_8021d_port_join(struct mlxsw_sp_bridge_device * bridge_device,struct mlxsw_sp_bridge_port * bridge_port,struct mlxsw_sp_port * mlxsw_sp_port,struct netlink_ext_ack * extack)2128*4882a593Smuzhiyun mlxsw_sp_bridge_8021d_port_join(struct mlxsw_sp_bridge_device *bridge_device,
2129*4882a593Smuzhiyun struct mlxsw_sp_bridge_port *bridge_port,
2130*4882a593Smuzhiyun struct mlxsw_sp_port *mlxsw_sp_port,
2131*4882a593Smuzhiyun struct netlink_ext_ack *extack)
2132*4882a593Smuzhiyun {
2133*4882a593Smuzhiyun struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
2134*4882a593Smuzhiyun struct net_device *dev = bridge_port->dev;
2135*4882a593Smuzhiyun u16 vid;
2136*4882a593Smuzhiyun
2137*4882a593Smuzhiyun vid = is_vlan_dev(dev) ? vlan_dev_vlan_id(dev) : MLXSW_SP_DEFAULT_VID;
2138*4882a593Smuzhiyun mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid);
2139*4882a593Smuzhiyun if (WARN_ON(!mlxsw_sp_port_vlan))
2140*4882a593Smuzhiyun return -EINVAL;
2141*4882a593Smuzhiyun
2142*4882a593Smuzhiyun if (mlxsw_sp_port_is_br_member(mlxsw_sp_port, bridge_device->dev)) {
2143*4882a593Smuzhiyun NL_SET_ERR_MSG_MOD(extack, "Can not bridge VLAN uppers of the same port");
2144*4882a593Smuzhiyun return -EINVAL;
2145*4882a593Smuzhiyun }
2146*4882a593Smuzhiyun
2147*4882a593Smuzhiyun /* Port is no longer usable as a router interface */
2148*4882a593Smuzhiyun if (mlxsw_sp_port_vlan->fid)
2149*4882a593Smuzhiyun mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan);
2150*4882a593Smuzhiyun
2151*4882a593Smuzhiyun return mlxsw_sp_port_vlan_bridge_join(mlxsw_sp_port_vlan, bridge_port,
2152*4882a593Smuzhiyun extack);
2153*4882a593Smuzhiyun }
2154*4882a593Smuzhiyun
2155*4882a593Smuzhiyun static void
mlxsw_sp_bridge_8021d_port_leave(struct mlxsw_sp_bridge_device * bridge_device,struct mlxsw_sp_bridge_port * bridge_port,struct mlxsw_sp_port * mlxsw_sp_port)2156*4882a593Smuzhiyun mlxsw_sp_bridge_8021d_port_leave(struct mlxsw_sp_bridge_device *bridge_device,
2157*4882a593Smuzhiyun struct mlxsw_sp_bridge_port *bridge_port,
2158*4882a593Smuzhiyun struct mlxsw_sp_port *mlxsw_sp_port)
2159*4882a593Smuzhiyun {
2160*4882a593Smuzhiyun struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
2161*4882a593Smuzhiyun struct net_device *dev = bridge_port->dev;
2162*4882a593Smuzhiyun u16 vid;
2163*4882a593Smuzhiyun
2164*4882a593Smuzhiyun vid = is_vlan_dev(dev) ? vlan_dev_vlan_id(dev) : MLXSW_SP_DEFAULT_VID;
2165*4882a593Smuzhiyun mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid);
2166*4882a593Smuzhiyun if (!mlxsw_sp_port_vlan || !mlxsw_sp_port_vlan->bridge_port)
2167*4882a593Smuzhiyun return;
2168*4882a593Smuzhiyun
2169*4882a593Smuzhiyun mlxsw_sp_port_vlan_bridge_leave(mlxsw_sp_port_vlan);
2170*4882a593Smuzhiyun }
2171*4882a593Smuzhiyun
2172*4882a593Smuzhiyun static int
mlxsw_sp_bridge_8021d_vxlan_join(struct mlxsw_sp_bridge_device * bridge_device,const struct net_device * vxlan_dev,u16 vid,struct netlink_ext_ack * extack)2173*4882a593Smuzhiyun mlxsw_sp_bridge_8021d_vxlan_join(struct mlxsw_sp_bridge_device *bridge_device,
2174*4882a593Smuzhiyun const struct net_device *vxlan_dev, u16 vid,
2175*4882a593Smuzhiyun struct netlink_ext_ack *extack)
2176*4882a593Smuzhiyun {
2177*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_device->dev);
2178*4882a593Smuzhiyun struct vxlan_dev *vxlan = netdev_priv(vxlan_dev);
2179*4882a593Smuzhiyun struct mlxsw_sp_nve_params params = {
2180*4882a593Smuzhiyun .type = MLXSW_SP_NVE_TYPE_VXLAN,
2181*4882a593Smuzhiyun .vni = vxlan->cfg.vni,
2182*4882a593Smuzhiyun .dev = vxlan_dev,
2183*4882a593Smuzhiyun };
2184*4882a593Smuzhiyun struct mlxsw_sp_fid *fid;
2185*4882a593Smuzhiyun int err;
2186*4882a593Smuzhiyun
2187*4882a593Smuzhiyun fid = mlxsw_sp_fid_8021d_get(mlxsw_sp, bridge_device->dev->ifindex);
2188*4882a593Smuzhiyun if (IS_ERR(fid)) {
2189*4882a593Smuzhiyun NL_SET_ERR_MSG_MOD(extack, "Failed to create 802.1D FID");
2190*4882a593Smuzhiyun return -EINVAL;
2191*4882a593Smuzhiyun }
2192*4882a593Smuzhiyun
2193*4882a593Smuzhiyun if (mlxsw_sp_fid_vni_is_set(fid)) {
2194*4882a593Smuzhiyun NL_SET_ERR_MSG_MOD(extack, "VNI is already set on FID");
2195*4882a593Smuzhiyun err = -EINVAL;
2196*4882a593Smuzhiyun goto err_vni_exists;
2197*4882a593Smuzhiyun }
2198*4882a593Smuzhiyun
2199*4882a593Smuzhiyun err = mlxsw_sp_nve_fid_enable(mlxsw_sp, fid, ¶ms, extack);
2200*4882a593Smuzhiyun if (err)
2201*4882a593Smuzhiyun goto err_nve_fid_enable;
2202*4882a593Smuzhiyun
2203*4882a593Smuzhiyun return 0;
2204*4882a593Smuzhiyun
2205*4882a593Smuzhiyun err_nve_fid_enable:
2206*4882a593Smuzhiyun err_vni_exists:
2207*4882a593Smuzhiyun mlxsw_sp_fid_put(fid);
2208*4882a593Smuzhiyun return err;
2209*4882a593Smuzhiyun }
2210*4882a593Smuzhiyun
2211*4882a593Smuzhiyun static struct mlxsw_sp_fid *
mlxsw_sp_bridge_8021d_fid_get(struct mlxsw_sp_bridge_device * bridge_device,u16 vid,struct netlink_ext_ack * extack)2212*4882a593Smuzhiyun mlxsw_sp_bridge_8021d_fid_get(struct mlxsw_sp_bridge_device *bridge_device,
2213*4882a593Smuzhiyun u16 vid, struct netlink_ext_ack *extack)
2214*4882a593Smuzhiyun {
2215*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_device->dev);
2216*4882a593Smuzhiyun
2217*4882a593Smuzhiyun return mlxsw_sp_fid_8021d_get(mlxsw_sp, bridge_device->dev->ifindex);
2218*4882a593Smuzhiyun }
2219*4882a593Smuzhiyun
2220*4882a593Smuzhiyun static struct mlxsw_sp_fid *
mlxsw_sp_bridge_8021d_fid_lookup(struct mlxsw_sp_bridge_device * bridge_device,u16 vid)2221*4882a593Smuzhiyun mlxsw_sp_bridge_8021d_fid_lookup(struct mlxsw_sp_bridge_device *bridge_device,
2222*4882a593Smuzhiyun u16 vid)
2223*4882a593Smuzhiyun {
2224*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_device->dev);
2225*4882a593Smuzhiyun
2226*4882a593Smuzhiyun /* The only valid VLAN for a VLAN-unaware bridge is 0 */
2227*4882a593Smuzhiyun if (vid)
2228*4882a593Smuzhiyun return NULL;
2229*4882a593Smuzhiyun
2230*4882a593Smuzhiyun return mlxsw_sp_fid_8021d_lookup(mlxsw_sp, bridge_device->dev->ifindex);
2231*4882a593Smuzhiyun }
2232*4882a593Smuzhiyun
2233*4882a593Smuzhiyun static u16
mlxsw_sp_bridge_8021d_fid_vid(struct mlxsw_sp_bridge_device * bridge_device,const struct mlxsw_sp_fid * fid)2234*4882a593Smuzhiyun mlxsw_sp_bridge_8021d_fid_vid(struct mlxsw_sp_bridge_device *bridge_device,
2235*4882a593Smuzhiyun const struct mlxsw_sp_fid *fid)
2236*4882a593Smuzhiyun {
2237*4882a593Smuzhiyun return 0;
2238*4882a593Smuzhiyun }
2239*4882a593Smuzhiyun
2240*4882a593Smuzhiyun static const struct mlxsw_sp_bridge_ops mlxsw_sp_bridge_8021d_ops = {
2241*4882a593Smuzhiyun .port_join = mlxsw_sp_bridge_8021d_port_join,
2242*4882a593Smuzhiyun .port_leave = mlxsw_sp_bridge_8021d_port_leave,
2243*4882a593Smuzhiyun .vxlan_join = mlxsw_sp_bridge_8021d_vxlan_join,
2244*4882a593Smuzhiyun .fid_get = mlxsw_sp_bridge_8021d_fid_get,
2245*4882a593Smuzhiyun .fid_lookup = mlxsw_sp_bridge_8021d_fid_lookup,
2246*4882a593Smuzhiyun .fid_vid = mlxsw_sp_bridge_8021d_fid_vid,
2247*4882a593Smuzhiyun };
2248*4882a593Smuzhiyun
mlxsw_sp_port_bridge_join(struct mlxsw_sp_port * mlxsw_sp_port,struct net_device * brport_dev,struct net_device * br_dev,struct netlink_ext_ack * extack)2249*4882a593Smuzhiyun int mlxsw_sp_port_bridge_join(struct mlxsw_sp_port *mlxsw_sp_port,
2250*4882a593Smuzhiyun struct net_device *brport_dev,
2251*4882a593Smuzhiyun struct net_device *br_dev,
2252*4882a593Smuzhiyun struct netlink_ext_ack *extack)
2253*4882a593Smuzhiyun {
2254*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
2255*4882a593Smuzhiyun struct mlxsw_sp_bridge_device *bridge_device;
2256*4882a593Smuzhiyun struct mlxsw_sp_bridge_port *bridge_port;
2257*4882a593Smuzhiyun int err;
2258*4882a593Smuzhiyun
2259*4882a593Smuzhiyun bridge_port = mlxsw_sp_bridge_port_get(mlxsw_sp->bridge, brport_dev,
2260*4882a593Smuzhiyun extack);
2261*4882a593Smuzhiyun if (IS_ERR(bridge_port))
2262*4882a593Smuzhiyun return PTR_ERR(bridge_port);
2263*4882a593Smuzhiyun bridge_device = bridge_port->bridge_device;
2264*4882a593Smuzhiyun
2265*4882a593Smuzhiyun err = bridge_device->ops->port_join(bridge_device, bridge_port,
2266*4882a593Smuzhiyun mlxsw_sp_port, extack);
2267*4882a593Smuzhiyun if (err)
2268*4882a593Smuzhiyun goto err_port_join;
2269*4882a593Smuzhiyun
2270*4882a593Smuzhiyun return 0;
2271*4882a593Smuzhiyun
2272*4882a593Smuzhiyun err_port_join:
2273*4882a593Smuzhiyun mlxsw_sp_bridge_port_put(mlxsw_sp->bridge, bridge_port);
2274*4882a593Smuzhiyun return err;
2275*4882a593Smuzhiyun }
2276*4882a593Smuzhiyun
mlxsw_sp_port_bridge_leave(struct mlxsw_sp_port * mlxsw_sp_port,struct net_device * brport_dev,struct net_device * br_dev)2277*4882a593Smuzhiyun void mlxsw_sp_port_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_port,
2278*4882a593Smuzhiyun struct net_device *brport_dev,
2279*4882a593Smuzhiyun struct net_device *br_dev)
2280*4882a593Smuzhiyun {
2281*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
2282*4882a593Smuzhiyun struct mlxsw_sp_bridge_device *bridge_device;
2283*4882a593Smuzhiyun struct mlxsw_sp_bridge_port *bridge_port;
2284*4882a593Smuzhiyun
2285*4882a593Smuzhiyun bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, br_dev);
2286*4882a593Smuzhiyun if (!bridge_device)
2287*4882a593Smuzhiyun return;
2288*4882a593Smuzhiyun bridge_port = __mlxsw_sp_bridge_port_find(bridge_device, brport_dev);
2289*4882a593Smuzhiyun if (!bridge_port)
2290*4882a593Smuzhiyun return;
2291*4882a593Smuzhiyun
2292*4882a593Smuzhiyun bridge_device->ops->port_leave(bridge_device, bridge_port,
2293*4882a593Smuzhiyun mlxsw_sp_port);
2294*4882a593Smuzhiyun mlxsw_sp_bridge_port_put(mlxsw_sp->bridge, bridge_port);
2295*4882a593Smuzhiyun }
2296*4882a593Smuzhiyun
mlxsw_sp_bridge_vxlan_join(struct mlxsw_sp * mlxsw_sp,const struct net_device * br_dev,const struct net_device * vxlan_dev,u16 vid,struct netlink_ext_ack * extack)2297*4882a593Smuzhiyun int mlxsw_sp_bridge_vxlan_join(struct mlxsw_sp *mlxsw_sp,
2298*4882a593Smuzhiyun const struct net_device *br_dev,
2299*4882a593Smuzhiyun const struct net_device *vxlan_dev, u16 vid,
2300*4882a593Smuzhiyun struct netlink_ext_ack *extack)
2301*4882a593Smuzhiyun {
2302*4882a593Smuzhiyun struct mlxsw_sp_bridge_device *bridge_device;
2303*4882a593Smuzhiyun
2304*4882a593Smuzhiyun bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, br_dev);
2305*4882a593Smuzhiyun if (WARN_ON(!bridge_device))
2306*4882a593Smuzhiyun return -EINVAL;
2307*4882a593Smuzhiyun
2308*4882a593Smuzhiyun return bridge_device->ops->vxlan_join(bridge_device, vxlan_dev, vid,
2309*4882a593Smuzhiyun extack);
2310*4882a593Smuzhiyun }
2311*4882a593Smuzhiyun
mlxsw_sp_bridge_vxlan_leave(struct mlxsw_sp * mlxsw_sp,const struct net_device * vxlan_dev)2312*4882a593Smuzhiyun void mlxsw_sp_bridge_vxlan_leave(struct mlxsw_sp *mlxsw_sp,
2313*4882a593Smuzhiyun const struct net_device *vxlan_dev)
2314*4882a593Smuzhiyun {
2315*4882a593Smuzhiyun struct vxlan_dev *vxlan = netdev_priv(vxlan_dev);
2316*4882a593Smuzhiyun struct mlxsw_sp_fid *fid;
2317*4882a593Smuzhiyun
2318*4882a593Smuzhiyun /* If the VxLAN device is down, then the FID does not have a VNI */
2319*4882a593Smuzhiyun fid = mlxsw_sp_fid_lookup_by_vni(mlxsw_sp, vxlan->cfg.vni);
2320*4882a593Smuzhiyun if (!fid)
2321*4882a593Smuzhiyun return;
2322*4882a593Smuzhiyun
2323*4882a593Smuzhiyun mlxsw_sp_nve_fid_disable(mlxsw_sp, fid);
2324*4882a593Smuzhiyun /* Drop both the reference we just took during lookup and the reference
2325*4882a593Smuzhiyun * the VXLAN device took.
2326*4882a593Smuzhiyun */
2327*4882a593Smuzhiyun mlxsw_sp_fid_put(fid);
2328*4882a593Smuzhiyun mlxsw_sp_fid_put(fid);
2329*4882a593Smuzhiyun }
2330*4882a593Smuzhiyun
2331*4882a593Smuzhiyun static void
mlxsw_sp_switchdev_vxlan_addr_convert(const union vxlan_addr * vxlan_addr,enum mlxsw_sp_l3proto * proto,union mlxsw_sp_l3addr * addr)2332*4882a593Smuzhiyun mlxsw_sp_switchdev_vxlan_addr_convert(const union vxlan_addr *vxlan_addr,
2333*4882a593Smuzhiyun enum mlxsw_sp_l3proto *proto,
2334*4882a593Smuzhiyun union mlxsw_sp_l3addr *addr)
2335*4882a593Smuzhiyun {
2336*4882a593Smuzhiyun if (vxlan_addr->sa.sa_family == AF_INET) {
2337*4882a593Smuzhiyun addr->addr4 = vxlan_addr->sin.sin_addr.s_addr;
2338*4882a593Smuzhiyun *proto = MLXSW_SP_L3_PROTO_IPV4;
2339*4882a593Smuzhiyun } else {
2340*4882a593Smuzhiyun addr->addr6 = vxlan_addr->sin6.sin6_addr;
2341*4882a593Smuzhiyun *proto = MLXSW_SP_L3_PROTO_IPV6;
2342*4882a593Smuzhiyun }
2343*4882a593Smuzhiyun }
2344*4882a593Smuzhiyun
2345*4882a593Smuzhiyun static void
mlxsw_sp_switchdev_addr_vxlan_convert(enum mlxsw_sp_l3proto proto,const union mlxsw_sp_l3addr * addr,union vxlan_addr * vxlan_addr)2346*4882a593Smuzhiyun mlxsw_sp_switchdev_addr_vxlan_convert(enum mlxsw_sp_l3proto proto,
2347*4882a593Smuzhiyun const union mlxsw_sp_l3addr *addr,
2348*4882a593Smuzhiyun union vxlan_addr *vxlan_addr)
2349*4882a593Smuzhiyun {
2350*4882a593Smuzhiyun switch (proto) {
2351*4882a593Smuzhiyun case MLXSW_SP_L3_PROTO_IPV4:
2352*4882a593Smuzhiyun vxlan_addr->sa.sa_family = AF_INET;
2353*4882a593Smuzhiyun vxlan_addr->sin.sin_addr.s_addr = addr->addr4;
2354*4882a593Smuzhiyun break;
2355*4882a593Smuzhiyun case MLXSW_SP_L3_PROTO_IPV6:
2356*4882a593Smuzhiyun vxlan_addr->sa.sa_family = AF_INET6;
2357*4882a593Smuzhiyun vxlan_addr->sin6.sin6_addr = addr->addr6;
2358*4882a593Smuzhiyun break;
2359*4882a593Smuzhiyun }
2360*4882a593Smuzhiyun }
2361*4882a593Smuzhiyun
mlxsw_sp_fdb_vxlan_call_notifiers(struct net_device * dev,const char * mac,enum mlxsw_sp_l3proto proto,union mlxsw_sp_l3addr * addr,__be32 vni,bool adding)2362*4882a593Smuzhiyun static void mlxsw_sp_fdb_vxlan_call_notifiers(struct net_device *dev,
2363*4882a593Smuzhiyun const char *mac,
2364*4882a593Smuzhiyun enum mlxsw_sp_l3proto proto,
2365*4882a593Smuzhiyun union mlxsw_sp_l3addr *addr,
2366*4882a593Smuzhiyun __be32 vni, bool adding)
2367*4882a593Smuzhiyun {
2368*4882a593Smuzhiyun struct switchdev_notifier_vxlan_fdb_info info;
2369*4882a593Smuzhiyun struct vxlan_dev *vxlan = netdev_priv(dev);
2370*4882a593Smuzhiyun enum switchdev_notifier_type type;
2371*4882a593Smuzhiyun
2372*4882a593Smuzhiyun type = adding ? SWITCHDEV_VXLAN_FDB_ADD_TO_BRIDGE :
2373*4882a593Smuzhiyun SWITCHDEV_VXLAN_FDB_DEL_TO_BRIDGE;
2374*4882a593Smuzhiyun mlxsw_sp_switchdev_addr_vxlan_convert(proto, addr, &info.remote_ip);
2375*4882a593Smuzhiyun info.remote_port = vxlan->cfg.dst_port;
2376*4882a593Smuzhiyun info.remote_vni = vni;
2377*4882a593Smuzhiyun info.remote_ifindex = 0;
2378*4882a593Smuzhiyun ether_addr_copy(info.eth_addr, mac);
2379*4882a593Smuzhiyun info.vni = vni;
2380*4882a593Smuzhiyun info.offloaded = adding;
2381*4882a593Smuzhiyun call_switchdev_notifiers(type, dev, &info.info, NULL);
2382*4882a593Smuzhiyun }
2383*4882a593Smuzhiyun
mlxsw_sp_fdb_nve_call_notifiers(struct net_device * dev,const char * mac,enum mlxsw_sp_l3proto proto,union mlxsw_sp_l3addr * addr,__be32 vni,bool adding)2384*4882a593Smuzhiyun static void mlxsw_sp_fdb_nve_call_notifiers(struct net_device *dev,
2385*4882a593Smuzhiyun const char *mac,
2386*4882a593Smuzhiyun enum mlxsw_sp_l3proto proto,
2387*4882a593Smuzhiyun union mlxsw_sp_l3addr *addr,
2388*4882a593Smuzhiyun __be32 vni,
2389*4882a593Smuzhiyun bool adding)
2390*4882a593Smuzhiyun {
2391*4882a593Smuzhiyun if (netif_is_vxlan(dev))
2392*4882a593Smuzhiyun mlxsw_sp_fdb_vxlan_call_notifiers(dev, mac, proto, addr, vni,
2393*4882a593Smuzhiyun adding);
2394*4882a593Smuzhiyun }
2395*4882a593Smuzhiyun
2396*4882a593Smuzhiyun static void
mlxsw_sp_fdb_call_notifiers(enum switchdev_notifier_type type,const char * mac,u16 vid,struct net_device * dev,bool offloaded)2397*4882a593Smuzhiyun mlxsw_sp_fdb_call_notifiers(enum switchdev_notifier_type type,
2398*4882a593Smuzhiyun const char *mac, u16 vid,
2399*4882a593Smuzhiyun struct net_device *dev, bool offloaded)
2400*4882a593Smuzhiyun {
2401*4882a593Smuzhiyun struct switchdev_notifier_fdb_info info;
2402*4882a593Smuzhiyun
2403*4882a593Smuzhiyun info.addr = mac;
2404*4882a593Smuzhiyun info.vid = vid;
2405*4882a593Smuzhiyun info.offloaded = offloaded;
2406*4882a593Smuzhiyun call_switchdev_notifiers(type, dev, &info.info, NULL);
2407*4882a593Smuzhiyun }
2408*4882a593Smuzhiyun
mlxsw_sp_fdb_notify_mac_process(struct mlxsw_sp * mlxsw_sp,char * sfn_pl,int rec_index,bool adding)2409*4882a593Smuzhiyun static void mlxsw_sp_fdb_notify_mac_process(struct mlxsw_sp *mlxsw_sp,
2410*4882a593Smuzhiyun char *sfn_pl, int rec_index,
2411*4882a593Smuzhiyun bool adding)
2412*4882a593Smuzhiyun {
2413*4882a593Smuzhiyun unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core);
2414*4882a593Smuzhiyun struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
2415*4882a593Smuzhiyun struct mlxsw_sp_bridge_device *bridge_device;
2416*4882a593Smuzhiyun struct mlxsw_sp_bridge_port *bridge_port;
2417*4882a593Smuzhiyun struct mlxsw_sp_port *mlxsw_sp_port;
2418*4882a593Smuzhiyun enum switchdev_notifier_type type;
2419*4882a593Smuzhiyun char mac[ETH_ALEN];
2420*4882a593Smuzhiyun u8 local_port;
2421*4882a593Smuzhiyun u16 vid, fid;
2422*4882a593Smuzhiyun bool do_notification = true;
2423*4882a593Smuzhiyun int err;
2424*4882a593Smuzhiyun
2425*4882a593Smuzhiyun mlxsw_reg_sfn_mac_unpack(sfn_pl, rec_index, mac, &fid, &local_port);
2426*4882a593Smuzhiyun
2427*4882a593Smuzhiyun if (WARN_ON_ONCE(local_port >= max_ports))
2428*4882a593Smuzhiyun return;
2429*4882a593Smuzhiyun mlxsw_sp_port = mlxsw_sp->ports[local_port];
2430*4882a593Smuzhiyun if (!mlxsw_sp_port) {
2431*4882a593Smuzhiyun dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Incorrect local port in FDB notification\n");
2432*4882a593Smuzhiyun goto just_remove;
2433*4882a593Smuzhiyun }
2434*4882a593Smuzhiyun
2435*4882a593Smuzhiyun if (mlxsw_sp_fid_is_dummy(mlxsw_sp, fid))
2436*4882a593Smuzhiyun goto just_remove;
2437*4882a593Smuzhiyun
2438*4882a593Smuzhiyun mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_fid(mlxsw_sp_port, fid);
2439*4882a593Smuzhiyun if (!mlxsw_sp_port_vlan) {
2440*4882a593Smuzhiyun netdev_err(mlxsw_sp_port->dev, "Failed to find a matching {Port, VID} following FDB notification\n");
2441*4882a593Smuzhiyun goto just_remove;
2442*4882a593Smuzhiyun }
2443*4882a593Smuzhiyun
2444*4882a593Smuzhiyun bridge_port = mlxsw_sp_port_vlan->bridge_port;
2445*4882a593Smuzhiyun if (!bridge_port) {
2446*4882a593Smuzhiyun netdev_err(mlxsw_sp_port->dev, "{Port, VID} not associated with a bridge\n");
2447*4882a593Smuzhiyun goto just_remove;
2448*4882a593Smuzhiyun }
2449*4882a593Smuzhiyun
2450*4882a593Smuzhiyun bridge_device = bridge_port->bridge_device;
2451*4882a593Smuzhiyun vid = bridge_device->vlan_enabled ? mlxsw_sp_port_vlan->vid : 0;
2452*4882a593Smuzhiyun
2453*4882a593Smuzhiyun do_fdb_op:
2454*4882a593Smuzhiyun err = mlxsw_sp_port_fdb_uc_op(mlxsw_sp, local_port, mac, fid,
2455*4882a593Smuzhiyun adding, true);
2456*4882a593Smuzhiyun if (err) {
2457*4882a593Smuzhiyun dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to set FDB entry\n");
2458*4882a593Smuzhiyun return;
2459*4882a593Smuzhiyun }
2460*4882a593Smuzhiyun
2461*4882a593Smuzhiyun if (!do_notification)
2462*4882a593Smuzhiyun return;
2463*4882a593Smuzhiyun type = adding ? SWITCHDEV_FDB_ADD_TO_BRIDGE : SWITCHDEV_FDB_DEL_TO_BRIDGE;
2464*4882a593Smuzhiyun mlxsw_sp_fdb_call_notifiers(type, mac, vid, bridge_port->dev, adding);
2465*4882a593Smuzhiyun
2466*4882a593Smuzhiyun return;
2467*4882a593Smuzhiyun
2468*4882a593Smuzhiyun just_remove:
2469*4882a593Smuzhiyun adding = false;
2470*4882a593Smuzhiyun do_notification = false;
2471*4882a593Smuzhiyun goto do_fdb_op;
2472*4882a593Smuzhiyun }
2473*4882a593Smuzhiyun
mlxsw_sp_fdb_notify_mac_lag_process(struct mlxsw_sp * mlxsw_sp,char * sfn_pl,int rec_index,bool adding)2474*4882a593Smuzhiyun static void mlxsw_sp_fdb_notify_mac_lag_process(struct mlxsw_sp *mlxsw_sp,
2475*4882a593Smuzhiyun char *sfn_pl, int rec_index,
2476*4882a593Smuzhiyun bool adding)
2477*4882a593Smuzhiyun {
2478*4882a593Smuzhiyun struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
2479*4882a593Smuzhiyun struct mlxsw_sp_bridge_device *bridge_device;
2480*4882a593Smuzhiyun struct mlxsw_sp_bridge_port *bridge_port;
2481*4882a593Smuzhiyun struct mlxsw_sp_port *mlxsw_sp_port;
2482*4882a593Smuzhiyun enum switchdev_notifier_type type;
2483*4882a593Smuzhiyun char mac[ETH_ALEN];
2484*4882a593Smuzhiyun u16 lag_vid = 0;
2485*4882a593Smuzhiyun u16 lag_id;
2486*4882a593Smuzhiyun u16 vid, fid;
2487*4882a593Smuzhiyun bool do_notification = true;
2488*4882a593Smuzhiyun int err;
2489*4882a593Smuzhiyun
2490*4882a593Smuzhiyun mlxsw_reg_sfn_mac_lag_unpack(sfn_pl, rec_index, mac, &fid, &lag_id);
2491*4882a593Smuzhiyun mlxsw_sp_port = mlxsw_sp_lag_rep_port(mlxsw_sp, lag_id);
2492*4882a593Smuzhiyun if (!mlxsw_sp_port) {
2493*4882a593Smuzhiyun dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Cannot find port representor for LAG\n");
2494*4882a593Smuzhiyun goto just_remove;
2495*4882a593Smuzhiyun }
2496*4882a593Smuzhiyun
2497*4882a593Smuzhiyun if (mlxsw_sp_fid_is_dummy(mlxsw_sp, fid))
2498*4882a593Smuzhiyun goto just_remove;
2499*4882a593Smuzhiyun
2500*4882a593Smuzhiyun mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_fid(mlxsw_sp_port, fid);
2501*4882a593Smuzhiyun if (!mlxsw_sp_port_vlan) {
2502*4882a593Smuzhiyun netdev_err(mlxsw_sp_port->dev, "Failed to find a matching {Port, VID} following FDB notification\n");
2503*4882a593Smuzhiyun goto just_remove;
2504*4882a593Smuzhiyun }
2505*4882a593Smuzhiyun
2506*4882a593Smuzhiyun bridge_port = mlxsw_sp_port_vlan->bridge_port;
2507*4882a593Smuzhiyun if (!bridge_port) {
2508*4882a593Smuzhiyun netdev_err(mlxsw_sp_port->dev, "{Port, VID} not associated with a bridge\n");
2509*4882a593Smuzhiyun goto just_remove;
2510*4882a593Smuzhiyun }
2511*4882a593Smuzhiyun
2512*4882a593Smuzhiyun bridge_device = bridge_port->bridge_device;
2513*4882a593Smuzhiyun vid = bridge_device->vlan_enabled ? mlxsw_sp_port_vlan->vid : 0;
2514*4882a593Smuzhiyun lag_vid = mlxsw_sp_fid_lag_vid_valid(mlxsw_sp_port_vlan->fid) ?
2515*4882a593Smuzhiyun mlxsw_sp_port_vlan->vid : 0;
2516*4882a593Smuzhiyun
2517*4882a593Smuzhiyun do_fdb_op:
2518*4882a593Smuzhiyun err = mlxsw_sp_port_fdb_uc_lag_op(mlxsw_sp, lag_id, mac, fid, lag_vid,
2519*4882a593Smuzhiyun adding, true);
2520*4882a593Smuzhiyun if (err) {
2521*4882a593Smuzhiyun dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to set FDB entry\n");
2522*4882a593Smuzhiyun return;
2523*4882a593Smuzhiyun }
2524*4882a593Smuzhiyun
2525*4882a593Smuzhiyun if (!do_notification)
2526*4882a593Smuzhiyun return;
2527*4882a593Smuzhiyun type = adding ? SWITCHDEV_FDB_ADD_TO_BRIDGE : SWITCHDEV_FDB_DEL_TO_BRIDGE;
2528*4882a593Smuzhiyun mlxsw_sp_fdb_call_notifiers(type, mac, vid, bridge_port->dev, adding);
2529*4882a593Smuzhiyun
2530*4882a593Smuzhiyun return;
2531*4882a593Smuzhiyun
2532*4882a593Smuzhiyun just_remove:
2533*4882a593Smuzhiyun adding = false;
2534*4882a593Smuzhiyun do_notification = false;
2535*4882a593Smuzhiyun goto do_fdb_op;
2536*4882a593Smuzhiyun }
2537*4882a593Smuzhiyun
2538*4882a593Smuzhiyun static int
__mlxsw_sp_fdb_notify_mac_uc_tunnel_process(struct mlxsw_sp * mlxsw_sp,const struct mlxsw_sp_fid * fid,bool adding,struct net_device ** nve_dev,u16 * p_vid,__be32 * p_vni)2539*4882a593Smuzhiyun __mlxsw_sp_fdb_notify_mac_uc_tunnel_process(struct mlxsw_sp *mlxsw_sp,
2540*4882a593Smuzhiyun const struct mlxsw_sp_fid *fid,
2541*4882a593Smuzhiyun bool adding,
2542*4882a593Smuzhiyun struct net_device **nve_dev,
2543*4882a593Smuzhiyun u16 *p_vid, __be32 *p_vni)
2544*4882a593Smuzhiyun {
2545*4882a593Smuzhiyun struct mlxsw_sp_bridge_device *bridge_device;
2546*4882a593Smuzhiyun struct net_device *br_dev, *dev;
2547*4882a593Smuzhiyun int nve_ifindex;
2548*4882a593Smuzhiyun int err;
2549*4882a593Smuzhiyun
2550*4882a593Smuzhiyun err = mlxsw_sp_fid_nve_ifindex(fid, &nve_ifindex);
2551*4882a593Smuzhiyun if (err)
2552*4882a593Smuzhiyun return err;
2553*4882a593Smuzhiyun
2554*4882a593Smuzhiyun err = mlxsw_sp_fid_vni(fid, p_vni);
2555*4882a593Smuzhiyun if (err)
2556*4882a593Smuzhiyun return err;
2557*4882a593Smuzhiyun
2558*4882a593Smuzhiyun dev = __dev_get_by_index(mlxsw_sp_net(mlxsw_sp), nve_ifindex);
2559*4882a593Smuzhiyun if (!dev)
2560*4882a593Smuzhiyun return -EINVAL;
2561*4882a593Smuzhiyun *nve_dev = dev;
2562*4882a593Smuzhiyun
2563*4882a593Smuzhiyun if (!netif_running(dev))
2564*4882a593Smuzhiyun return -EINVAL;
2565*4882a593Smuzhiyun
2566*4882a593Smuzhiyun if (adding && !br_port_flag_is_set(dev, BR_LEARNING))
2567*4882a593Smuzhiyun return -EINVAL;
2568*4882a593Smuzhiyun
2569*4882a593Smuzhiyun if (adding && netif_is_vxlan(dev)) {
2570*4882a593Smuzhiyun struct vxlan_dev *vxlan = netdev_priv(dev);
2571*4882a593Smuzhiyun
2572*4882a593Smuzhiyun if (!(vxlan->cfg.flags & VXLAN_F_LEARN))
2573*4882a593Smuzhiyun return -EINVAL;
2574*4882a593Smuzhiyun }
2575*4882a593Smuzhiyun
2576*4882a593Smuzhiyun br_dev = netdev_master_upper_dev_get(dev);
2577*4882a593Smuzhiyun if (!br_dev)
2578*4882a593Smuzhiyun return -EINVAL;
2579*4882a593Smuzhiyun
2580*4882a593Smuzhiyun bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, br_dev);
2581*4882a593Smuzhiyun if (!bridge_device)
2582*4882a593Smuzhiyun return -EINVAL;
2583*4882a593Smuzhiyun
2584*4882a593Smuzhiyun *p_vid = bridge_device->ops->fid_vid(bridge_device, fid);
2585*4882a593Smuzhiyun
2586*4882a593Smuzhiyun return 0;
2587*4882a593Smuzhiyun }
2588*4882a593Smuzhiyun
mlxsw_sp_fdb_notify_mac_uc_tunnel_process(struct mlxsw_sp * mlxsw_sp,char * sfn_pl,int rec_index,bool adding)2589*4882a593Smuzhiyun static void mlxsw_sp_fdb_notify_mac_uc_tunnel_process(struct mlxsw_sp *mlxsw_sp,
2590*4882a593Smuzhiyun char *sfn_pl,
2591*4882a593Smuzhiyun int rec_index,
2592*4882a593Smuzhiyun bool adding)
2593*4882a593Smuzhiyun {
2594*4882a593Smuzhiyun enum mlxsw_reg_sfn_uc_tunnel_protocol sfn_proto;
2595*4882a593Smuzhiyun enum switchdev_notifier_type type;
2596*4882a593Smuzhiyun struct net_device *nve_dev;
2597*4882a593Smuzhiyun union mlxsw_sp_l3addr addr;
2598*4882a593Smuzhiyun struct mlxsw_sp_fid *fid;
2599*4882a593Smuzhiyun char mac[ETH_ALEN];
2600*4882a593Smuzhiyun u16 fid_index, vid;
2601*4882a593Smuzhiyun __be32 vni;
2602*4882a593Smuzhiyun u32 uip;
2603*4882a593Smuzhiyun int err;
2604*4882a593Smuzhiyun
2605*4882a593Smuzhiyun mlxsw_reg_sfn_uc_tunnel_unpack(sfn_pl, rec_index, mac, &fid_index,
2606*4882a593Smuzhiyun &uip, &sfn_proto);
2607*4882a593Smuzhiyun
2608*4882a593Smuzhiyun fid = mlxsw_sp_fid_lookup_by_index(mlxsw_sp, fid_index);
2609*4882a593Smuzhiyun if (!fid)
2610*4882a593Smuzhiyun goto err_fid_lookup;
2611*4882a593Smuzhiyun
2612*4882a593Smuzhiyun err = mlxsw_sp_nve_learned_ip_resolve(mlxsw_sp, uip,
2613*4882a593Smuzhiyun (enum mlxsw_sp_l3proto) sfn_proto,
2614*4882a593Smuzhiyun &addr);
2615*4882a593Smuzhiyun if (err)
2616*4882a593Smuzhiyun goto err_ip_resolve;
2617*4882a593Smuzhiyun
2618*4882a593Smuzhiyun err = __mlxsw_sp_fdb_notify_mac_uc_tunnel_process(mlxsw_sp, fid, adding,
2619*4882a593Smuzhiyun &nve_dev, &vid, &vni);
2620*4882a593Smuzhiyun if (err)
2621*4882a593Smuzhiyun goto err_fdb_process;
2622*4882a593Smuzhiyun
2623*4882a593Smuzhiyun err = mlxsw_sp_port_fdb_tunnel_uc_op(mlxsw_sp, mac, fid_index,
2624*4882a593Smuzhiyun (enum mlxsw_sp_l3proto) sfn_proto,
2625*4882a593Smuzhiyun &addr, adding, true);
2626*4882a593Smuzhiyun if (err)
2627*4882a593Smuzhiyun goto err_fdb_op;
2628*4882a593Smuzhiyun
2629*4882a593Smuzhiyun mlxsw_sp_fdb_nve_call_notifiers(nve_dev, mac,
2630*4882a593Smuzhiyun (enum mlxsw_sp_l3proto) sfn_proto,
2631*4882a593Smuzhiyun &addr, vni, adding);
2632*4882a593Smuzhiyun
2633*4882a593Smuzhiyun type = adding ? SWITCHDEV_FDB_ADD_TO_BRIDGE :
2634*4882a593Smuzhiyun SWITCHDEV_FDB_DEL_TO_BRIDGE;
2635*4882a593Smuzhiyun mlxsw_sp_fdb_call_notifiers(type, mac, vid, nve_dev, adding);
2636*4882a593Smuzhiyun
2637*4882a593Smuzhiyun mlxsw_sp_fid_put(fid);
2638*4882a593Smuzhiyun
2639*4882a593Smuzhiyun return;
2640*4882a593Smuzhiyun
2641*4882a593Smuzhiyun err_fdb_op:
2642*4882a593Smuzhiyun err_fdb_process:
2643*4882a593Smuzhiyun err_ip_resolve:
2644*4882a593Smuzhiyun mlxsw_sp_fid_put(fid);
2645*4882a593Smuzhiyun err_fid_lookup:
2646*4882a593Smuzhiyun /* Remove an FDB entry in case we cannot process it. Otherwise the
2647*4882a593Smuzhiyun * device will keep sending the same notification over and over again.
2648*4882a593Smuzhiyun */
2649*4882a593Smuzhiyun mlxsw_sp_port_fdb_tunnel_uc_op(mlxsw_sp, mac, fid_index,
2650*4882a593Smuzhiyun (enum mlxsw_sp_l3proto) sfn_proto, &addr,
2651*4882a593Smuzhiyun false, true);
2652*4882a593Smuzhiyun }
2653*4882a593Smuzhiyun
mlxsw_sp_fdb_notify_rec_process(struct mlxsw_sp * mlxsw_sp,char * sfn_pl,int rec_index)2654*4882a593Smuzhiyun static void mlxsw_sp_fdb_notify_rec_process(struct mlxsw_sp *mlxsw_sp,
2655*4882a593Smuzhiyun char *sfn_pl, int rec_index)
2656*4882a593Smuzhiyun {
2657*4882a593Smuzhiyun switch (mlxsw_reg_sfn_rec_type_get(sfn_pl, rec_index)) {
2658*4882a593Smuzhiyun case MLXSW_REG_SFN_REC_TYPE_LEARNED_MAC:
2659*4882a593Smuzhiyun mlxsw_sp_fdb_notify_mac_process(mlxsw_sp, sfn_pl,
2660*4882a593Smuzhiyun rec_index, true);
2661*4882a593Smuzhiyun break;
2662*4882a593Smuzhiyun case MLXSW_REG_SFN_REC_TYPE_AGED_OUT_MAC:
2663*4882a593Smuzhiyun mlxsw_sp_fdb_notify_mac_process(mlxsw_sp, sfn_pl,
2664*4882a593Smuzhiyun rec_index, false);
2665*4882a593Smuzhiyun break;
2666*4882a593Smuzhiyun case MLXSW_REG_SFN_REC_TYPE_LEARNED_MAC_LAG:
2667*4882a593Smuzhiyun mlxsw_sp_fdb_notify_mac_lag_process(mlxsw_sp, sfn_pl,
2668*4882a593Smuzhiyun rec_index, true);
2669*4882a593Smuzhiyun break;
2670*4882a593Smuzhiyun case MLXSW_REG_SFN_REC_TYPE_AGED_OUT_MAC_LAG:
2671*4882a593Smuzhiyun mlxsw_sp_fdb_notify_mac_lag_process(mlxsw_sp, sfn_pl,
2672*4882a593Smuzhiyun rec_index, false);
2673*4882a593Smuzhiyun break;
2674*4882a593Smuzhiyun case MLXSW_REG_SFN_REC_TYPE_LEARNED_UNICAST_TUNNEL:
2675*4882a593Smuzhiyun mlxsw_sp_fdb_notify_mac_uc_tunnel_process(mlxsw_sp, sfn_pl,
2676*4882a593Smuzhiyun rec_index, true);
2677*4882a593Smuzhiyun break;
2678*4882a593Smuzhiyun case MLXSW_REG_SFN_REC_TYPE_AGED_OUT_UNICAST_TUNNEL:
2679*4882a593Smuzhiyun mlxsw_sp_fdb_notify_mac_uc_tunnel_process(mlxsw_sp, sfn_pl,
2680*4882a593Smuzhiyun rec_index, false);
2681*4882a593Smuzhiyun break;
2682*4882a593Smuzhiyun }
2683*4882a593Smuzhiyun }
2684*4882a593Smuzhiyun
mlxsw_sp_fdb_notify_work_schedule(struct mlxsw_sp * mlxsw_sp,bool no_delay)2685*4882a593Smuzhiyun static void mlxsw_sp_fdb_notify_work_schedule(struct mlxsw_sp *mlxsw_sp,
2686*4882a593Smuzhiyun bool no_delay)
2687*4882a593Smuzhiyun {
2688*4882a593Smuzhiyun struct mlxsw_sp_bridge *bridge = mlxsw_sp->bridge;
2689*4882a593Smuzhiyun unsigned int interval = no_delay ? 0 : bridge->fdb_notify.interval;
2690*4882a593Smuzhiyun
2691*4882a593Smuzhiyun mlxsw_core_schedule_dw(&bridge->fdb_notify.dw,
2692*4882a593Smuzhiyun msecs_to_jiffies(interval));
2693*4882a593Smuzhiyun }
2694*4882a593Smuzhiyun
2695*4882a593Smuzhiyun #define MLXSW_SP_FDB_SFN_QUERIES_PER_SESSION 10
2696*4882a593Smuzhiyun
mlxsw_sp_fdb_notify_work(struct work_struct * work)2697*4882a593Smuzhiyun static void mlxsw_sp_fdb_notify_work(struct work_struct *work)
2698*4882a593Smuzhiyun {
2699*4882a593Smuzhiyun struct mlxsw_sp_bridge *bridge;
2700*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp;
2701*4882a593Smuzhiyun char *sfn_pl;
2702*4882a593Smuzhiyun int queries;
2703*4882a593Smuzhiyun u8 num_rec;
2704*4882a593Smuzhiyun int i;
2705*4882a593Smuzhiyun int err;
2706*4882a593Smuzhiyun
2707*4882a593Smuzhiyun sfn_pl = kmalloc(MLXSW_REG_SFN_LEN, GFP_KERNEL);
2708*4882a593Smuzhiyun if (!sfn_pl)
2709*4882a593Smuzhiyun return;
2710*4882a593Smuzhiyun
2711*4882a593Smuzhiyun bridge = container_of(work, struct mlxsw_sp_bridge, fdb_notify.dw.work);
2712*4882a593Smuzhiyun mlxsw_sp = bridge->mlxsw_sp;
2713*4882a593Smuzhiyun
2714*4882a593Smuzhiyun rtnl_lock();
2715*4882a593Smuzhiyun queries = MLXSW_SP_FDB_SFN_QUERIES_PER_SESSION;
2716*4882a593Smuzhiyun while (queries > 0) {
2717*4882a593Smuzhiyun mlxsw_reg_sfn_pack(sfn_pl);
2718*4882a593Smuzhiyun err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(sfn), sfn_pl);
2719*4882a593Smuzhiyun if (err) {
2720*4882a593Smuzhiyun dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to get FDB notifications\n");
2721*4882a593Smuzhiyun goto out;
2722*4882a593Smuzhiyun }
2723*4882a593Smuzhiyun num_rec = mlxsw_reg_sfn_num_rec_get(sfn_pl);
2724*4882a593Smuzhiyun for (i = 0; i < num_rec; i++)
2725*4882a593Smuzhiyun mlxsw_sp_fdb_notify_rec_process(mlxsw_sp, sfn_pl, i);
2726*4882a593Smuzhiyun if (num_rec != MLXSW_REG_SFN_REC_MAX_COUNT)
2727*4882a593Smuzhiyun goto out;
2728*4882a593Smuzhiyun queries--;
2729*4882a593Smuzhiyun }
2730*4882a593Smuzhiyun
2731*4882a593Smuzhiyun out:
2732*4882a593Smuzhiyun rtnl_unlock();
2733*4882a593Smuzhiyun kfree(sfn_pl);
2734*4882a593Smuzhiyun mlxsw_sp_fdb_notify_work_schedule(mlxsw_sp, !queries);
2735*4882a593Smuzhiyun }
2736*4882a593Smuzhiyun
2737*4882a593Smuzhiyun struct mlxsw_sp_switchdev_event_work {
2738*4882a593Smuzhiyun struct work_struct work;
2739*4882a593Smuzhiyun union {
2740*4882a593Smuzhiyun struct switchdev_notifier_fdb_info fdb_info;
2741*4882a593Smuzhiyun struct switchdev_notifier_vxlan_fdb_info vxlan_fdb_info;
2742*4882a593Smuzhiyun };
2743*4882a593Smuzhiyun struct net_device *dev;
2744*4882a593Smuzhiyun unsigned long event;
2745*4882a593Smuzhiyun };
2746*4882a593Smuzhiyun
2747*4882a593Smuzhiyun static void
mlxsw_sp_switchdev_bridge_vxlan_fdb_event(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_switchdev_event_work * switchdev_work,struct mlxsw_sp_fid * fid,__be32 vni)2748*4882a593Smuzhiyun mlxsw_sp_switchdev_bridge_vxlan_fdb_event(struct mlxsw_sp *mlxsw_sp,
2749*4882a593Smuzhiyun struct mlxsw_sp_switchdev_event_work *
2750*4882a593Smuzhiyun switchdev_work,
2751*4882a593Smuzhiyun struct mlxsw_sp_fid *fid, __be32 vni)
2752*4882a593Smuzhiyun {
2753*4882a593Smuzhiyun struct switchdev_notifier_vxlan_fdb_info vxlan_fdb_info;
2754*4882a593Smuzhiyun struct switchdev_notifier_fdb_info *fdb_info;
2755*4882a593Smuzhiyun struct net_device *dev = switchdev_work->dev;
2756*4882a593Smuzhiyun enum mlxsw_sp_l3proto proto;
2757*4882a593Smuzhiyun union mlxsw_sp_l3addr addr;
2758*4882a593Smuzhiyun int err;
2759*4882a593Smuzhiyun
2760*4882a593Smuzhiyun fdb_info = &switchdev_work->fdb_info;
2761*4882a593Smuzhiyun err = vxlan_fdb_find_uc(dev, fdb_info->addr, vni, &vxlan_fdb_info);
2762*4882a593Smuzhiyun if (err)
2763*4882a593Smuzhiyun return;
2764*4882a593Smuzhiyun
2765*4882a593Smuzhiyun mlxsw_sp_switchdev_vxlan_addr_convert(&vxlan_fdb_info.remote_ip,
2766*4882a593Smuzhiyun &proto, &addr);
2767*4882a593Smuzhiyun
2768*4882a593Smuzhiyun switch (switchdev_work->event) {
2769*4882a593Smuzhiyun case SWITCHDEV_FDB_ADD_TO_DEVICE:
2770*4882a593Smuzhiyun err = mlxsw_sp_port_fdb_tunnel_uc_op(mlxsw_sp,
2771*4882a593Smuzhiyun vxlan_fdb_info.eth_addr,
2772*4882a593Smuzhiyun mlxsw_sp_fid_index(fid),
2773*4882a593Smuzhiyun proto, &addr, true, false);
2774*4882a593Smuzhiyun if (err)
2775*4882a593Smuzhiyun return;
2776*4882a593Smuzhiyun vxlan_fdb_info.offloaded = true;
2777*4882a593Smuzhiyun call_switchdev_notifiers(SWITCHDEV_VXLAN_FDB_OFFLOADED, dev,
2778*4882a593Smuzhiyun &vxlan_fdb_info.info, NULL);
2779*4882a593Smuzhiyun mlxsw_sp_fdb_call_notifiers(SWITCHDEV_FDB_OFFLOADED,
2780*4882a593Smuzhiyun vxlan_fdb_info.eth_addr,
2781*4882a593Smuzhiyun fdb_info->vid, dev, true);
2782*4882a593Smuzhiyun break;
2783*4882a593Smuzhiyun case SWITCHDEV_FDB_DEL_TO_DEVICE:
2784*4882a593Smuzhiyun err = mlxsw_sp_port_fdb_tunnel_uc_op(mlxsw_sp,
2785*4882a593Smuzhiyun vxlan_fdb_info.eth_addr,
2786*4882a593Smuzhiyun mlxsw_sp_fid_index(fid),
2787*4882a593Smuzhiyun proto, &addr, false,
2788*4882a593Smuzhiyun false);
2789*4882a593Smuzhiyun vxlan_fdb_info.offloaded = false;
2790*4882a593Smuzhiyun call_switchdev_notifiers(SWITCHDEV_VXLAN_FDB_OFFLOADED, dev,
2791*4882a593Smuzhiyun &vxlan_fdb_info.info, NULL);
2792*4882a593Smuzhiyun break;
2793*4882a593Smuzhiyun }
2794*4882a593Smuzhiyun }
2795*4882a593Smuzhiyun
2796*4882a593Smuzhiyun static void
mlxsw_sp_switchdev_bridge_nve_fdb_event(struct mlxsw_sp_switchdev_event_work * switchdev_work)2797*4882a593Smuzhiyun mlxsw_sp_switchdev_bridge_nve_fdb_event(struct mlxsw_sp_switchdev_event_work *
2798*4882a593Smuzhiyun switchdev_work)
2799*4882a593Smuzhiyun {
2800*4882a593Smuzhiyun struct mlxsw_sp_bridge_device *bridge_device;
2801*4882a593Smuzhiyun struct net_device *dev = switchdev_work->dev;
2802*4882a593Smuzhiyun struct net_device *br_dev;
2803*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp;
2804*4882a593Smuzhiyun struct mlxsw_sp_fid *fid;
2805*4882a593Smuzhiyun __be32 vni;
2806*4882a593Smuzhiyun int err;
2807*4882a593Smuzhiyun
2808*4882a593Smuzhiyun if (switchdev_work->event != SWITCHDEV_FDB_ADD_TO_DEVICE &&
2809*4882a593Smuzhiyun switchdev_work->event != SWITCHDEV_FDB_DEL_TO_DEVICE)
2810*4882a593Smuzhiyun return;
2811*4882a593Smuzhiyun
2812*4882a593Smuzhiyun if (switchdev_work->event == SWITCHDEV_FDB_ADD_TO_DEVICE &&
2813*4882a593Smuzhiyun !switchdev_work->fdb_info.added_by_user)
2814*4882a593Smuzhiyun return;
2815*4882a593Smuzhiyun
2816*4882a593Smuzhiyun if (!netif_running(dev))
2817*4882a593Smuzhiyun return;
2818*4882a593Smuzhiyun br_dev = netdev_master_upper_dev_get(dev);
2819*4882a593Smuzhiyun if (!br_dev)
2820*4882a593Smuzhiyun return;
2821*4882a593Smuzhiyun if (!netif_is_bridge_master(br_dev))
2822*4882a593Smuzhiyun return;
2823*4882a593Smuzhiyun mlxsw_sp = mlxsw_sp_lower_get(br_dev);
2824*4882a593Smuzhiyun if (!mlxsw_sp)
2825*4882a593Smuzhiyun return;
2826*4882a593Smuzhiyun bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, br_dev);
2827*4882a593Smuzhiyun if (!bridge_device)
2828*4882a593Smuzhiyun return;
2829*4882a593Smuzhiyun
2830*4882a593Smuzhiyun fid = bridge_device->ops->fid_lookup(bridge_device,
2831*4882a593Smuzhiyun switchdev_work->fdb_info.vid);
2832*4882a593Smuzhiyun if (!fid)
2833*4882a593Smuzhiyun return;
2834*4882a593Smuzhiyun
2835*4882a593Smuzhiyun err = mlxsw_sp_fid_vni(fid, &vni);
2836*4882a593Smuzhiyun if (err)
2837*4882a593Smuzhiyun goto out;
2838*4882a593Smuzhiyun
2839*4882a593Smuzhiyun mlxsw_sp_switchdev_bridge_vxlan_fdb_event(mlxsw_sp, switchdev_work, fid,
2840*4882a593Smuzhiyun vni);
2841*4882a593Smuzhiyun
2842*4882a593Smuzhiyun out:
2843*4882a593Smuzhiyun mlxsw_sp_fid_put(fid);
2844*4882a593Smuzhiyun }
2845*4882a593Smuzhiyun
mlxsw_sp_switchdev_bridge_fdb_event_work(struct work_struct * work)2846*4882a593Smuzhiyun static void mlxsw_sp_switchdev_bridge_fdb_event_work(struct work_struct *work)
2847*4882a593Smuzhiyun {
2848*4882a593Smuzhiyun struct mlxsw_sp_switchdev_event_work *switchdev_work =
2849*4882a593Smuzhiyun container_of(work, struct mlxsw_sp_switchdev_event_work, work);
2850*4882a593Smuzhiyun struct net_device *dev = switchdev_work->dev;
2851*4882a593Smuzhiyun struct switchdev_notifier_fdb_info *fdb_info;
2852*4882a593Smuzhiyun struct mlxsw_sp_port *mlxsw_sp_port;
2853*4882a593Smuzhiyun int err;
2854*4882a593Smuzhiyun
2855*4882a593Smuzhiyun rtnl_lock();
2856*4882a593Smuzhiyun if (netif_is_vxlan(dev)) {
2857*4882a593Smuzhiyun mlxsw_sp_switchdev_bridge_nve_fdb_event(switchdev_work);
2858*4882a593Smuzhiyun goto out;
2859*4882a593Smuzhiyun }
2860*4882a593Smuzhiyun
2861*4882a593Smuzhiyun mlxsw_sp_port = mlxsw_sp_port_dev_lower_find(dev);
2862*4882a593Smuzhiyun if (!mlxsw_sp_port)
2863*4882a593Smuzhiyun goto out;
2864*4882a593Smuzhiyun
2865*4882a593Smuzhiyun switch (switchdev_work->event) {
2866*4882a593Smuzhiyun case SWITCHDEV_FDB_ADD_TO_DEVICE:
2867*4882a593Smuzhiyun fdb_info = &switchdev_work->fdb_info;
2868*4882a593Smuzhiyun if (!fdb_info->added_by_user)
2869*4882a593Smuzhiyun break;
2870*4882a593Smuzhiyun err = mlxsw_sp_port_fdb_set(mlxsw_sp_port, fdb_info, true);
2871*4882a593Smuzhiyun if (err)
2872*4882a593Smuzhiyun break;
2873*4882a593Smuzhiyun mlxsw_sp_fdb_call_notifiers(SWITCHDEV_FDB_OFFLOADED,
2874*4882a593Smuzhiyun fdb_info->addr,
2875*4882a593Smuzhiyun fdb_info->vid, dev, true);
2876*4882a593Smuzhiyun break;
2877*4882a593Smuzhiyun case SWITCHDEV_FDB_DEL_TO_DEVICE:
2878*4882a593Smuzhiyun fdb_info = &switchdev_work->fdb_info;
2879*4882a593Smuzhiyun mlxsw_sp_port_fdb_set(mlxsw_sp_port, fdb_info, false);
2880*4882a593Smuzhiyun break;
2881*4882a593Smuzhiyun case SWITCHDEV_FDB_ADD_TO_BRIDGE:
2882*4882a593Smuzhiyun case SWITCHDEV_FDB_DEL_TO_BRIDGE:
2883*4882a593Smuzhiyun /* These events are only used to potentially update an existing
2884*4882a593Smuzhiyun * SPAN mirror.
2885*4882a593Smuzhiyun */
2886*4882a593Smuzhiyun break;
2887*4882a593Smuzhiyun }
2888*4882a593Smuzhiyun
2889*4882a593Smuzhiyun mlxsw_sp_span_respin(mlxsw_sp_port->mlxsw_sp);
2890*4882a593Smuzhiyun
2891*4882a593Smuzhiyun out:
2892*4882a593Smuzhiyun rtnl_unlock();
2893*4882a593Smuzhiyun kfree(switchdev_work->fdb_info.addr);
2894*4882a593Smuzhiyun kfree(switchdev_work);
2895*4882a593Smuzhiyun dev_put(dev);
2896*4882a593Smuzhiyun }
2897*4882a593Smuzhiyun
2898*4882a593Smuzhiyun static void
mlxsw_sp_switchdev_vxlan_fdb_add(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_switchdev_event_work * switchdev_work)2899*4882a593Smuzhiyun mlxsw_sp_switchdev_vxlan_fdb_add(struct mlxsw_sp *mlxsw_sp,
2900*4882a593Smuzhiyun struct mlxsw_sp_switchdev_event_work *
2901*4882a593Smuzhiyun switchdev_work)
2902*4882a593Smuzhiyun {
2903*4882a593Smuzhiyun struct switchdev_notifier_vxlan_fdb_info *vxlan_fdb_info;
2904*4882a593Smuzhiyun struct mlxsw_sp_bridge_device *bridge_device;
2905*4882a593Smuzhiyun struct net_device *dev = switchdev_work->dev;
2906*4882a593Smuzhiyun u8 all_zeros_mac[ETH_ALEN] = { 0 };
2907*4882a593Smuzhiyun enum mlxsw_sp_l3proto proto;
2908*4882a593Smuzhiyun union mlxsw_sp_l3addr addr;
2909*4882a593Smuzhiyun struct net_device *br_dev;
2910*4882a593Smuzhiyun struct mlxsw_sp_fid *fid;
2911*4882a593Smuzhiyun u16 vid;
2912*4882a593Smuzhiyun int err;
2913*4882a593Smuzhiyun
2914*4882a593Smuzhiyun vxlan_fdb_info = &switchdev_work->vxlan_fdb_info;
2915*4882a593Smuzhiyun br_dev = netdev_master_upper_dev_get(dev);
2916*4882a593Smuzhiyun
2917*4882a593Smuzhiyun bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, br_dev);
2918*4882a593Smuzhiyun if (!bridge_device)
2919*4882a593Smuzhiyun return;
2920*4882a593Smuzhiyun
2921*4882a593Smuzhiyun fid = mlxsw_sp_fid_lookup_by_vni(mlxsw_sp, vxlan_fdb_info->vni);
2922*4882a593Smuzhiyun if (!fid)
2923*4882a593Smuzhiyun return;
2924*4882a593Smuzhiyun
2925*4882a593Smuzhiyun mlxsw_sp_switchdev_vxlan_addr_convert(&vxlan_fdb_info->remote_ip,
2926*4882a593Smuzhiyun &proto, &addr);
2927*4882a593Smuzhiyun
2928*4882a593Smuzhiyun if (ether_addr_equal(vxlan_fdb_info->eth_addr, all_zeros_mac)) {
2929*4882a593Smuzhiyun err = mlxsw_sp_nve_flood_ip_add(mlxsw_sp, fid, proto, &addr);
2930*4882a593Smuzhiyun if (err) {
2931*4882a593Smuzhiyun mlxsw_sp_fid_put(fid);
2932*4882a593Smuzhiyun return;
2933*4882a593Smuzhiyun }
2934*4882a593Smuzhiyun vxlan_fdb_info->offloaded = true;
2935*4882a593Smuzhiyun call_switchdev_notifiers(SWITCHDEV_VXLAN_FDB_OFFLOADED, dev,
2936*4882a593Smuzhiyun &vxlan_fdb_info->info, NULL);
2937*4882a593Smuzhiyun mlxsw_sp_fid_put(fid);
2938*4882a593Smuzhiyun return;
2939*4882a593Smuzhiyun }
2940*4882a593Smuzhiyun
2941*4882a593Smuzhiyun /* The device has a single FDB table, whereas Linux has two - one
2942*4882a593Smuzhiyun * in the bridge driver and another in the VxLAN driver. We only
2943*4882a593Smuzhiyun * program an entry to the device if the MAC points to the VxLAN
2944*4882a593Smuzhiyun * device in the bridge's FDB table
2945*4882a593Smuzhiyun */
2946*4882a593Smuzhiyun vid = bridge_device->ops->fid_vid(bridge_device, fid);
2947*4882a593Smuzhiyun if (br_fdb_find_port(br_dev, vxlan_fdb_info->eth_addr, vid) != dev)
2948*4882a593Smuzhiyun goto err_br_fdb_find;
2949*4882a593Smuzhiyun
2950*4882a593Smuzhiyun err = mlxsw_sp_port_fdb_tunnel_uc_op(mlxsw_sp, vxlan_fdb_info->eth_addr,
2951*4882a593Smuzhiyun mlxsw_sp_fid_index(fid), proto,
2952*4882a593Smuzhiyun &addr, true, false);
2953*4882a593Smuzhiyun if (err)
2954*4882a593Smuzhiyun goto err_fdb_tunnel_uc_op;
2955*4882a593Smuzhiyun vxlan_fdb_info->offloaded = true;
2956*4882a593Smuzhiyun call_switchdev_notifiers(SWITCHDEV_VXLAN_FDB_OFFLOADED, dev,
2957*4882a593Smuzhiyun &vxlan_fdb_info->info, NULL);
2958*4882a593Smuzhiyun mlxsw_sp_fdb_call_notifiers(SWITCHDEV_FDB_OFFLOADED,
2959*4882a593Smuzhiyun vxlan_fdb_info->eth_addr, vid, dev, true);
2960*4882a593Smuzhiyun
2961*4882a593Smuzhiyun mlxsw_sp_fid_put(fid);
2962*4882a593Smuzhiyun
2963*4882a593Smuzhiyun return;
2964*4882a593Smuzhiyun
2965*4882a593Smuzhiyun err_fdb_tunnel_uc_op:
2966*4882a593Smuzhiyun err_br_fdb_find:
2967*4882a593Smuzhiyun mlxsw_sp_fid_put(fid);
2968*4882a593Smuzhiyun }
2969*4882a593Smuzhiyun
2970*4882a593Smuzhiyun static void
mlxsw_sp_switchdev_vxlan_fdb_del(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_switchdev_event_work * switchdev_work)2971*4882a593Smuzhiyun mlxsw_sp_switchdev_vxlan_fdb_del(struct mlxsw_sp *mlxsw_sp,
2972*4882a593Smuzhiyun struct mlxsw_sp_switchdev_event_work *
2973*4882a593Smuzhiyun switchdev_work)
2974*4882a593Smuzhiyun {
2975*4882a593Smuzhiyun struct switchdev_notifier_vxlan_fdb_info *vxlan_fdb_info;
2976*4882a593Smuzhiyun struct mlxsw_sp_bridge_device *bridge_device;
2977*4882a593Smuzhiyun struct net_device *dev = switchdev_work->dev;
2978*4882a593Smuzhiyun struct net_device *br_dev = netdev_master_upper_dev_get(dev);
2979*4882a593Smuzhiyun u8 all_zeros_mac[ETH_ALEN] = { 0 };
2980*4882a593Smuzhiyun enum mlxsw_sp_l3proto proto;
2981*4882a593Smuzhiyun union mlxsw_sp_l3addr addr;
2982*4882a593Smuzhiyun struct mlxsw_sp_fid *fid;
2983*4882a593Smuzhiyun u16 vid;
2984*4882a593Smuzhiyun
2985*4882a593Smuzhiyun vxlan_fdb_info = &switchdev_work->vxlan_fdb_info;
2986*4882a593Smuzhiyun
2987*4882a593Smuzhiyun bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, br_dev);
2988*4882a593Smuzhiyun if (!bridge_device)
2989*4882a593Smuzhiyun return;
2990*4882a593Smuzhiyun
2991*4882a593Smuzhiyun fid = mlxsw_sp_fid_lookup_by_vni(mlxsw_sp, vxlan_fdb_info->vni);
2992*4882a593Smuzhiyun if (!fid)
2993*4882a593Smuzhiyun return;
2994*4882a593Smuzhiyun
2995*4882a593Smuzhiyun mlxsw_sp_switchdev_vxlan_addr_convert(&vxlan_fdb_info->remote_ip,
2996*4882a593Smuzhiyun &proto, &addr);
2997*4882a593Smuzhiyun
2998*4882a593Smuzhiyun if (ether_addr_equal(vxlan_fdb_info->eth_addr, all_zeros_mac)) {
2999*4882a593Smuzhiyun mlxsw_sp_nve_flood_ip_del(mlxsw_sp, fid, proto, &addr);
3000*4882a593Smuzhiyun mlxsw_sp_fid_put(fid);
3001*4882a593Smuzhiyun return;
3002*4882a593Smuzhiyun }
3003*4882a593Smuzhiyun
3004*4882a593Smuzhiyun mlxsw_sp_port_fdb_tunnel_uc_op(mlxsw_sp, vxlan_fdb_info->eth_addr,
3005*4882a593Smuzhiyun mlxsw_sp_fid_index(fid), proto, &addr,
3006*4882a593Smuzhiyun false, false);
3007*4882a593Smuzhiyun vid = bridge_device->ops->fid_vid(bridge_device, fid);
3008*4882a593Smuzhiyun mlxsw_sp_fdb_call_notifiers(SWITCHDEV_FDB_OFFLOADED,
3009*4882a593Smuzhiyun vxlan_fdb_info->eth_addr, vid, dev, false);
3010*4882a593Smuzhiyun
3011*4882a593Smuzhiyun mlxsw_sp_fid_put(fid);
3012*4882a593Smuzhiyun }
3013*4882a593Smuzhiyun
mlxsw_sp_switchdev_vxlan_fdb_event_work(struct work_struct * work)3014*4882a593Smuzhiyun static void mlxsw_sp_switchdev_vxlan_fdb_event_work(struct work_struct *work)
3015*4882a593Smuzhiyun {
3016*4882a593Smuzhiyun struct mlxsw_sp_switchdev_event_work *switchdev_work =
3017*4882a593Smuzhiyun container_of(work, struct mlxsw_sp_switchdev_event_work, work);
3018*4882a593Smuzhiyun struct net_device *dev = switchdev_work->dev;
3019*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp;
3020*4882a593Smuzhiyun struct net_device *br_dev;
3021*4882a593Smuzhiyun
3022*4882a593Smuzhiyun rtnl_lock();
3023*4882a593Smuzhiyun
3024*4882a593Smuzhiyun if (!netif_running(dev))
3025*4882a593Smuzhiyun goto out;
3026*4882a593Smuzhiyun br_dev = netdev_master_upper_dev_get(dev);
3027*4882a593Smuzhiyun if (!br_dev)
3028*4882a593Smuzhiyun goto out;
3029*4882a593Smuzhiyun if (!netif_is_bridge_master(br_dev))
3030*4882a593Smuzhiyun goto out;
3031*4882a593Smuzhiyun mlxsw_sp = mlxsw_sp_lower_get(br_dev);
3032*4882a593Smuzhiyun if (!mlxsw_sp)
3033*4882a593Smuzhiyun goto out;
3034*4882a593Smuzhiyun
3035*4882a593Smuzhiyun switch (switchdev_work->event) {
3036*4882a593Smuzhiyun case SWITCHDEV_VXLAN_FDB_ADD_TO_DEVICE:
3037*4882a593Smuzhiyun mlxsw_sp_switchdev_vxlan_fdb_add(mlxsw_sp, switchdev_work);
3038*4882a593Smuzhiyun break;
3039*4882a593Smuzhiyun case SWITCHDEV_VXLAN_FDB_DEL_TO_DEVICE:
3040*4882a593Smuzhiyun mlxsw_sp_switchdev_vxlan_fdb_del(mlxsw_sp, switchdev_work);
3041*4882a593Smuzhiyun break;
3042*4882a593Smuzhiyun }
3043*4882a593Smuzhiyun
3044*4882a593Smuzhiyun out:
3045*4882a593Smuzhiyun rtnl_unlock();
3046*4882a593Smuzhiyun kfree(switchdev_work);
3047*4882a593Smuzhiyun dev_put(dev);
3048*4882a593Smuzhiyun }
3049*4882a593Smuzhiyun
3050*4882a593Smuzhiyun static int
mlxsw_sp_switchdev_vxlan_work_prepare(struct mlxsw_sp_switchdev_event_work * switchdev_work,struct switchdev_notifier_info * info)3051*4882a593Smuzhiyun mlxsw_sp_switchdev_vxlan_work_prepare(struct mlxsw_sp_switchdev_event_work *
3052*4882a593Smuzhiyun switchdev_work,
3053*4882a593Smuzhiyun struct switchdev_notifier_info *info)
3054*4882a593Smuzhiyun {
3055*4882a593Smuzhiyun struct vxlan_dev *vxlan = netdev_priv(switchdev_work->dev);
3056*4882a593Smuzhiyun struct switchdev_notifier_vxlan_fdb_info *vxlan_fdb_info;
3057*4882a593Smuzhiyun struct vxlan_config *cfg = &vxlan->cfg;
3058*4882a593Smuzhiyun struct netlink_ext_ack *extack;
3059*4882a593Smuzhiyun
3060*4882a593Smuzhiyun extack = switchdev_notifier_info_to_extack(info);
3061*4882a593Smuzhiyun vxlan_fdb_info = container_of(info,
3062*4882a593Smuzhiyun struct switchdev_notifier_vxlan_fdb_info,
3063*4882a593Smuzhiyun info);
3064*4882a593Smuzhiyun
3065*4882a593Smuzhiyun if (vxlan_fdb_info->remote_port != cfg->dst_port) {
3066*4882a593Smuzhiyun NL_SET_ERR_MSG_MOD(extack, "VxLAN: FDB: Non-default remote port is not supported");
3067*4882a593Smuzhiyun return -EOPNOTSUPP;
3068*4882a593Smuzhiyun }
3069*4882a593Smuzhiyun if (vxlan_fdb_info->remote_vni != cfg->vni ||
3070*4882a593Smuzhiyun vxlan_fdb_info->vni != cfg->vni) {
3071*4882a593Smuzhiyun NL_SET_ERR_MSG_MOD(extack, "VxLAN: FDB: Non-default VNI is not supported");
3072*4882a593Smuzhiyun return -EOPNOTSUPP;
3073*4882a593Smuzhiyun }
3074*4882a593Smuzhiyun if (vxlan_fdb_info->remote_ifindex) {
3075*4882a593Smuzhiyun NL_SET_ERR_MSG_MOD(extack, "VxLAN: FDB: Local interface is not supported");
3076*4882a593Smuzhiyun return -EOPNOTSUPP;
3077*4882a593Smuzhiyun }
3078*4882a593Smuzhiyun if (is_multicast_ether_addr(vxlan_fdb_info->eth_addr)) {
3079*4882a593Smuzhiyun NL_SET_ERR_MSG_MOD(extack, "VxLAN: FDB: Multicast MAC addresses not supported");
3080*4882a593Smuzhiyun return -EOPNOTSUPP;
3081*4882a593Smuzhiyun }
3082*4882a593Smuzhiyun if (vxlan_addr_multicast(&vxlan_fdb_info->remote_ip)) {
3083*4882a593Smuzhiyun NL_SET_ERR_MSG_MOD(extack, "VxLAN: FDB: Multicast destination IP is not supported");
3084*4882a593Smuzhiyun return -EOPNOTSUPP;
3085*4882a593Smuzhiyun }
3086*4882a593Smuzhiyun
3087*4882a593Smuzhiyun switchdev_work->vxlan_fdb_info = *vxlan_fdb_info;
3088*4882a593Smuzhiyun
3089*4882a593Smuzhiyun return 0;
3090*4882a593Smuzhiyun }
3091*4882a593Smuzhiyun
3092*4882a593Smuzhiyun /* Called under rcu_read_lock() */
mlxsw_sp_switchdev_event(struct notifier_block * unused,unsigned long event,void * ptr)3093*4882a593Smuzhiyun static int mlxsw_sp_switchdev_event(struct notifier_block *unused,
3094*4882a593Smuzhiyun unsigned long event, void *ptr)
3095*4882a593Smuzhiyun {
3096*4882a593Smuzhiyun struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
3097*4882a593Smuzhiyun struct mlxsw_sp_switchdev_event_work *switchdev_work;
3098*4882a593Smuzhiyun struct switchdev_notifier_fdb_info *fdb_info;
3099*4882a593Smuzhiyun struct switchdev_notifier_info *info = ptr;
3100*4882a593Smuzhiyun struct net_device *br_dev;
3101*4882a593Smuzhiyun int err;
3102*4882a593Smuzhiyun
3103*4882a593Smuzhiyun if (event == SWITCHDEV_PORT_ATTR_SET) {
3104*4882a593Smuzhiyun err = switchdev_handle_port_attr_set(dev, ptr,
3105*4882a593Smuzhiyun mlxsw_sp_port_dev_check,
3106*4882a593Smuzhiyun mlxsw_sp_port_attr_set);
3107*4882a593Smuzhiyun return notifier_from_errno(err);
3108*4882a593Smuzhiyun }
3109*4882a593Smuzhiyun
3110*4882a593Smuzhiyun /* Tunnel devices are not our uppers, so check their master instead */
3111*4882a593Smuzhiyun br_dev = netdev_master_upper_dev_get_rcu(dev);
3112*4882a593Smuzhiyun if (!br_dev)
3113*4882a593Smuzhiyun return NOTIFY_DONE;
3114*4882a593Smuzhiyun if (!netif_is_bridge_master(br_dev))
3115*4882a593Smuzhiyun return NOTIFY_DONE;
3116*4882a593Smuzhiyun if (!mlxsw_sp_port_dev_lower_find_rcu(br_dev))
3117*4882a593Smuzhiyun return NOTIFY_DONE;
3118*4882a593Smuzhiyun
3119*4882a593Smuzhiyun switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC);
3120*4882a593Smuzhiyun if (!switchdev_work)
3121*4882a593Smuzhiyun return NOTIFY_BAD;
3122*4882a593Smuzhiyun
3123*4882a593Smuzhiyun switchdev_work->dev = dev;
3124*4882a593Smuzhiyun switchdev_work->event = event;
3125*4882a593Smuzhiyun
3126*4882a593Smuzhiyun switch (event) {
3127*4882a593Smuzhiyun case SWITCHDEV_FDB_ADD_TO_DEVICE:
3128*4882a593Smuzhiyun case SWITCHDEV_FDB_DEL_TO_DEVICE:
3129*4882a593Smuzhiyun case SWITCHDEV_FDB_ADD_TO_BRIDGE:
3130*4882a593Smuzhiyun case SWITCHDEV_FDB_DEL_TO_BRIDGE:
3131*4882a593Smuzhiyun fdb_info = container_of(info,
3132*4882a593Smuzhiyun struct switchdev_notifier_fdb_info,
3133*4882a593Smuzhiyun info);
3134*4882a593Smuzhiyun INIT_WORK(&switchdev_work->work,
3135*4882a593Smuzhiyun mlxsw_sp_switchdev_bridge_fdb_event_work);
3136*4882a593Smuzhiyun memcpy(&switchdev_work->fdb_info, ptr,
3137*4882a593Smuzhiyun sizeof(switchdev_work->fdb_info));
3138*4882a593Smuzhiyun switchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC);
3139*4882a593Smuzhiyun if (!switchdev_work->fdb_info.addr)
3140*4882a593Smuzhiyun goto err_addr_alloc;
3141*4882a593Smuzhiyun ether_addr_copy((u8 *)switchdev_work->fdb_info.addr,
3142*4882a593Smuzhiyun fdb_info->addr);
3143*4882a593Smuzhiyun /* Take a reference on the device. This can be either
3144*4882a593Smuzhiyun * upper device containig mlxsw_sp_port or just a
3145*4882a593Smuzhiyun * mlxsw_sp_port
3146*4882a593Smuzhiyun */
3147*4882a593Smuzhiyun dev_hold(dev);
3148*4882a593Smuzhiyun break;
3149*4882a593Smuzhiyun case SWITCHDEV_VXLAN_FDB_ADD_TO_DEVICE:
3150*4882a593Smuzhiyun case SWITCHDEV_VXLAN_FDB_DEL_TO_DEVICE:
3151*4882a593Smuzhiyun INIT_WORK(&switchdev_work->work,
3152*4882a593Smuzhiyun mlxsw_sp_switchdev_vxlan_fdb_event_work);
3153*4882a593Smuzhiyun err = mlxsw_sp_switchdev_vxlan_work_prepare(switchdev_work,
3154*4882a593Smuzhiyun info);
3155*4882a593Smuzhiyun if (err)
3156*4882a593Smuzhiyun goto err_vxlan_work_prepare;
3157*4882a593Smuzhiyun dev_hold(dev);
3158*4882a593Smuzhiyun break;
3159*4882a593Smuzhiyun default:
3160*4882a593Smuzhiyun kfree(switchdev_work);
3161*4882a593Smuzhiyun return NOTIFY_DONE;
3162*4882a593Smuzhiyun }
3163*4882a593Smuzhiyun
3164*4882a593Smuzhiyun mlxsw_core_schedule_work(&switchdev_work->work);
3165*4882a593Smuzhiyun
3166*4882a593Smuzhiyun return NOTIFY_DONE;
3167*4882a593Smuzhiyun
3168*4882a593Smuzhiyun err_vxlan_work_prepare:
3169*4882a593Smuzhiyun err_addr_alloc:
3170*4882a593Smuzhiyun kfree(switchdev_work);
3171*4882a593Smuzhiyun return NOTIFY_BAD;
3172*4882a593Smuzhiyun }
3173*4882a593Smuzhiyun
3174*4882a593Smuzhiyun struct notifier_block mlxsw_sp_switchdev_notifier = {
3175*4882a593Smuzhiyun .notifier_call = mlxsw_sp_switchdev_event,
3176*4882a593Smuzhiyun };
3177*4882a593Smuzhiyun
3178*4882a593Smuzhiyun static int
mlxsw_sp_switchdev_vxlan_vlan_add(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_bridge_device * bridge_device,const struct net_device * vxlan_dev,u16 vid,bool flag_untagged,bool flag_pvid,struct netlink_ext_ack * extack)3179*4882a593Smuzhiyun mlxsw_sp_switchdev_vxlan_vlan_add(struct mlxsw_sp *mlxsw_sp,
3180*4882a593Smuzhiyun struct mlxsw_sp_bridge_device *bridge_device,
3181*4882a593Smuzhiyun const struct net_device *vxlan_dev, u16 vid,
3182*4882a593Smuzhiyun bool flag_untagged, bool flag_pvid,
3183*4882a593Smuzhiyun struct netlink_ext_ack *extack)
3184*4882a593Smuzhiyun {
3185*4882a593Smuzhiyun struct vxlan_dev *vxlan = netdev_priv(vxlan_dev);
3186*4882a593Smuzhiyun __be32 vni = vxlan->cfg.vni;
3187*4882a593Smuzhiyun struct mlxsw_sp_fid *fid;
3188*4882a593Smuzhiyun u16 old_vid;
3189*4882a593Smuzhiyun int err;
3190*4882a593Smuzhiyun
3191*4882a593Smuzhiyun /* We cannot have the same VLAN as PVID and egress untagged on multiple
3192*4882a593Smuzhiyun * VxLAN devices. Note that we get this notification before the VLAN is
3193*4882a593Smuzhiyun * actually added to the bridge's database, so it is not possible for
3194*4882a593Smuzhiyun * the lookup function to return 'vxlan_dev'
3195*4882a593Smuzhiyun */
3196*4882a593Smuzhiyun if (flag_untagged && flag_pvid &&
3197*4882a593Smuzhiyun mlxsw_sp_bridge_8021q_vxlan_dev_find(bridge_device->dev, vid)) {
3198*4882a593Smuzhiyun NL_SET_ERR_MSG_MOD(extack, "VLAN already mapped to a different VNI");
3199*4882a593Smuzhiyun return -EINVAL;
3200*4882a593Smuzhiyun }
3201*4882a593Smuzhiyun
3202*4882a593Smuzhiyun if (!netif_running(vxlan_dev))
3203*4882a593Smuzhiyun return 0;
3204*4882a593Smuzhiyun
3205*4882a593Smuzhiyun /* First case: FID is not associated with this VNI, but the new VLAN
3206*4882a593Smuzhiyun * is both PVID and egress untagged. Need to enable NVE on the FID, if
3207*4882a593Smuzhiyun * it exists
3208*4882a593Smuzhiyun */
3209*4882a593Smuzhiyun fid = mlxsw_sp_fid_lookup_by_vni(mlxsw_sp, vni);
3210*4882a593Smuzhiyun if (!fid) {
3211*4882a593Smuzhiyun if (!flag_untagged || !flag_pvid)
3212*4882a593Smuzhiyun return 0;
3213*4882a593Smuzhiyun return mlxsw_sp_bridge_8021q_vxlan_join(bridge_device,
3214*4882a593Smuzhiyun vxlan_dev, vid, extack);
3215*4882a593Smuzhiyun }
3216*4882a593Smuzhiyun
3217*4882a593Smuzhiyun /* Second case: FID is associated with the VNI and the VLAN associated
3218*4882a593Smuzhiyun * with the FID is the same as the notified VLAN. This means the flags
3219*4882a593Smuzhiyun * (PVID / egress untagged) were toggled and that NVE should be
3220*4882a593Smuzhiyun * disabled on the FID
3221*4882a593Smuzhiyun */
3222*4882a593Smuzhiyun old_vid = mlxsw_sp_fid_8021q_vid(fid);
3223*4882a593Smuzhiyun if (vid == old_vid) {
3224*4882a593Smuzhiyun if (WARN_ON(flag_untagged && flag_pvid)) {
3225*4882a593Smuzhiyun mlxsw_sp_fid_put(fid);
3226*4882a593Smuzhiyun return -EINVAL;
3227*4882a593Smuzhiyun }
3228*4882a593Smuzhiyun mlxsw_sp_bridge_vxlan_leave(mlxsw_sp, vxlan_dev);
3229*4882a593Smuzhiyun mlxsw_sp_fid_put(fid);
3230*4882a593Smuzhiyun return 0;
3231*4882a593Smuzhiyun }
3232*4882a593Smuzhiyun
3233*4882a593Smuzhiyun /* Third case: A new VLAN was configured on the VxLAN device, but this
3234*4882a593Smuzhiyun * VLAN is not PVID, so there is nothing to do.
3235*4882a593Smuzhiyun */
3236*4882a593Smuzhiyun if (!flag_pvid) {
3237*4882a593Smuzhiyun mlxsw_sp_fid_put(fid);
3238*4882a593Smuzhiyun return 0;
3239*4882a593Smuzhiyun }
3240*4882a593Smuzhiyun
3241*4882a593Smuzhiyun /* Fourth case: Thew new VLAN is PVID, which means the VLAN currently
3242*4882a593Smuzhiyun * mapped to the VNI should be unmapped
3243*4882a593Smuzhiyun */
3244*4882a593Smuzhiyun mlxsw_sp_bridge_vxlan_leave(mlxsw_sp, vxlan_dev);
3245*4882a593Smuzhiyun mlxsw_sp_fid_put(fid);
3246*4882a593Smuzhiyun
3247*4882a593Smuzhiyun /* Fifth case: The new VLAN is also egress untagged, which means the
3248*4882a593Smuzhiyun * VLAN needs to be mapped to the VNI
3249*4882a593Smuzhiyun */
3250*4882a593Smuzhiyun if (!flag_untagged)
3251*4882a593Smuzhiyun return 0;
3252*4882a593Smuzhiyun
3253*4882a593Smuzhiyun err = mlxsw_sp_bridge_8021q_vxlan_join(bridge_device, vxlan_dev, vid,
3254*4882a593Smuzhiyun extack);
3255*4882a593Smuzhiyun if (err)
3256*4882a593Smuzhiyun goto err_vxlan_join;
3257*4882a593Smuzhiyun
3258*4882a593Smuzhiyun return 0;
3259*4882a593Smuzhiyun
3260*4882a593Smuzhiyun err_vxlan_join:
3261*4882a593Smuzhiyun mlxsw_sp_bridge_8021q_vxlan_join(bridge_device, vxlan_dev, old_vid,
3262*4882a593Smuzhiyun NULL);
3263*4882a593Smuzhiyun return err;
3264*4882a593Smuzhiyun }
3265*4882a593Smuzhiyun
3266*4882a593Smuzhiyun static void
mlxsw_sp_switchdev_vxlan_vlan_del(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_bridge_device * bridge_device,const struct net_device * vxlan_dev,u16 vid)3267*4882a593Smuzhiyun mlxsw_sp_switchdev_vxlan_vlan_del(struct mlxsw_sp *mlxsw_sp,
3268*4882a593Smuzhiyun struct mlxsw_sp_bridge_device *bridge_device,
3269*4882a593Smuzhiyun const struct net_device *vxlan_dev, u16 vid)
3270*4882a593Smuzhiyun {
3271*4882a593Smuzhiyun struct vxlan_dev *vxlan = netdev_priv(vxlan_dev);
3272*4882a593Smuzhiyun __be32 vni = vxlan->cfg.vni;
3273*4882a593Smuzhiyun struct mlxsw_sp_fid *fid;
3274*4882a593Smuzhiyun
3275*4882a593Smuzhiyun if (!netif_running(vxlan_dev))
3276*4882a593Smuzhiyun return;
3277*4882a593Smuzhiyun
3278*4882a593Smuzhiyun fid = mlxsw_sp_fid_lookup_by_vni(mlxsw_sp, vni);
3279*4882a593Smuzhiyun if (!fid)
3280*4882a593Smuzhiyun return;
3281*4882a593Smuzhiyun
3282*4882a593Smuzhiyun /* A different VLAN than the one mapped to the VNI is deleted */
3283*4882a593Smuzhiyun if (mlxsw_sp_fid_8021q_vid(fid) != vid)
3284*4882a593Smuzhiyun goto out;
3285*4882a593Smuzhiyun
3286*4882a593Smuzhiyun mlxsw_sp_bridge_vxlan_leave(mlxsw_sp, vxlan_dev);
3287*4882a593Smuzhiyun
3288*4882a593Smuzhiyun out:
3289*4882a593Smuzhiyun mlxsw_sp_fid_put(fid);
3290*4882a593Smuzhiyun }
3291*4882a593Smuzhiyun
3292*4882a593Smuzhiyun static int
mlxsw_sp_switchdev_vxlan_vlans_add(struct net_device * vxlan_dev,struct switchdev_notifier_port_obj_info * port_obj_info)3293*4882a593Smuzhiyun mlxsw_sp_switchdev_vxlan_vlans_add(struct net_device *vxlan_dev,
3294*4882a593Smuzhiyun struct switchdev_notifier_port_obj_info *
3295*4882a593Smuzhiyun port_obj_info)
3296*4882a593Smuzhiyun {
3297*4882a593Smuzhiyun struct switchdev_obj_port_vlan *vlan =
3298*4882a593Smuzhiyun SWITCHDEV_OBJ_PORT_VLAN(port_obj_info->obj);
3299*4882a593Smuzhiyun bool flag_untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
3300*4882a593Smuzhiyun bool flag_pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
3301*4882a593Smuzhiyun struct switchdev_trans *trans = port_obj_info->trans;
3302*4882a593Smuzhiyun struct mlxsw_sp_bridge_device *bridge_device;
3303*4882a593Smuzhiyun struct netlink_ext_ack *extack;
3304*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp;
3305*4882a593Smuzhiyun struct net_device *br_dev;
3306*4882a593Smuzhiyun u16 vid;
3307*4882a593Smuzhiyun
3308*4882a593Smuzhiyun extack = switchdev_notifier_info_to_extack(&port_obj_info->info);
3309*4882a593Smuzhiyun br_dev = netdev_master_upper_dev_get(vxlan_dev);
3310*4882a593Smuzhiyun if (!br_dev)
3311*4882a593Smuzhiyun return 0;
3312*4882a593Smuzhiyun
3313*4882a593Smuzhiyun mlxsw_sp = mlxsw_sp_lower_get(br_dev);
3314*4882a593Smuzhiyun if (!mlxsw_sp)
3315*4882a593Smuzhiyun return 0;
3316*4882a593Smuzhiyun
3317*4882a593Smuzhiyun port_obj_info->handled = true;
3318*4882a593Smuzhiyun
3319*4882a593Smuzhiyun if (switchdev_trans_ph_commit(trans))
3320*4882a593Smuzhiyun return 0;
3321*4882a593Smuzhiyun
3322*4882a593Smuzhiyun bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, br_dev);
3323*4882a593Smuzhiyun if (!bridge_device)
3324*4882a593Smuzhiyun return -EINVAL;
3325*4882a593Smuzhiyun
3326*4882a593Smuzhiyun if (!bridge_device->vlan_enabled)
3327*4882a593Smuzhiyun return 0;
3328*4882a593Smuzhiyun
3329*4882a593Smuzhiyun for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) {
3330*4882a593Smuzhiyun int err;
3331*4882a593Smuzhiyun
3332*4882a593Smuzhiyun err = mlxsw_sp_switchdev_vxlan_vlan_add(mlxsw_sp, bridge_device,
3333*4882a593Smuzhiyun vxlan_dev, vid,
3334*4882a593Smuzhiyun flag_untagged,
3335*4882a593Smuzhiyun flag_pvid, extack);
3336*4882a593Smuzhiyun if (err)
3337*4882a593Smuzhiyun return err;
3338*4882a593Smuzhiyun }
3339*4882a593Smuzhiyun
3340*4882a593Smuzhiyun return 0;
3341*4882a593Smuzhiyun }
3342*4882a593Smuzhiyun
3343*4882a593Smuzhiyun static void
mlxsw_sp_switchdev_vxlan_vlans_del(struct net_device * vxlan_dev,struct switchdev_notifier_port_obj_info * port_obj_info)3344*4882a593Smuzhiyun mlxsw_sp_switchdev_vxlan_vlans_del(struct net_device *vxlan_dev,
3345*4882a593Smuzhiyun struct switchdev_notifier_port_obj_info *
3346*4882a593Smuzhiyun port_obj_info)
3347*4882a593Smuzhiyun {
3348*4882a593Smuzhiyun struct switchdev_obj_port_vlan *vlan =
3349*4882a593Smuzhiyun SWITCHDEV_OBJ_PORT_VLAN(port_obj_info->obj);
3350*4882a593Smuzhiyun struct mlxsw_sp_bridge_device *bridge_device;
3351*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp;
3352*4882a593Smuzhiyun struct net_device *br_dev;
3353*4882a593Smuzhiyun u16 vid;
3354*4882a593Smuzhiyun
3355*4882a593Smuzhiyun br_dev = netdev_master_upper_dev_get(vxlan_dev);
3356*4882a593Smuzhiyun if (!br_dev)
3357*4882a593Smuzhiyun return;
3358*4882a593Smuzhiyun
3359*4882a593Smuzhiyun mlxsw_sp = mlxsw_sp_lower_get(br_dev);
3360*4882a593Smuzhiyun if (!mlxsw_sp)
3361*4882a593Smuzhiyun return;
3362*4882a593Smuzhiyun
3363*4882a593Smuzhiyun port_obj_info->handled = true;
3364*4882a593Smuzhiyun
3365*4882a593Smuzhiyun bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, br_dev);
3366*4882a593Smuzhiyun if (!bridge_device)
3367*4882a593Smuzhiyun return;
3368*4882a593Smuzhiyun
3369*4882a593Smuzhiyun if (!bridge_device->vlan_enabled)
3370*4882a593Smuzhiyun return;
3371*4882a593Smuzhiyun
3372*4882a593Smuzhiyun for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++)
3373*4882a593Smuzhiyun mlxsw_sp_switchdev_vxlan_vlan_del(mlxsw_sp, bridge_device,
3374*4882a593Smuzhiyun vxlan_dev, vid);
3375*4882a593Smuzhiyun }
3376*4882a593Smuzhiyun
3377*4882a593Smuzhiyun static int
mlxsw_sp_switchdev_handle_vxlan_obj_add(struct net_device * vxlan_dev,struct switchdev_notifier_port_obj_info * port_obj_info)3378*4882a593Smuzhiyun mlxsw_sp_switchdev_handle_vxlan_obj_add(struct net_device *vxlan_dev,
3379*4882a593Smuzhiyun struct switchdev_notifier_port_obj_info *
3380*4882a593Smuzhiyun port_obj_info)
3381*4882a593Smuzhiyun {
3382*4882a593Smuzhiyun int err = 0;
3383*4882a593Smuzhiyun
3384*4882a593Smuzhiyun switch (port_obj_info->obj->id) {
3385*4882a593Smuzhiyun case SWITCHDEV_OBJ_ID_PORT_VLAN:
3386*4882a593Smuzhiyun err = mlxsw_sp_switchdev_vxlan_vlans_add(vxlan_dev,
3387*4882a593Smuzhiyun port_obj_info);
3388*4882a593Smuzhiyun break;
3389*4882a593Smuzhiyun default:
3390*4882a593Smuzhiyun break;
3391*4882a593Smuzhiyun }
3392*4882a593Smuzhiyun
3393*4882a593Smuzhiyun return err;
3394*4882a593Smuzhiyun }
3395*4882a593Smuzhiyun
3396*4882a593Smuzhiyun static void
mlxsw_sp_switchdev_handle_vxlan_obj_del(struct net_device * vxlan_dev,struct switchdev_notifier_port_obj_info * port_obj_info)3397*4882a593Smuzhiyun mlxsw_sp_switchdev_handle_vxlan_obj_del(struct net_device *vxlan_dev,
3398*4882a593Smuzhiyun struct switchdev_notifier_port_obj_info *
3399*4882a593Smuzhiyun port_obj_info)
3400*4882a593Smuzhiyun {
3401*4882a593Smuzhiyun switch (port_obj_info->obj->id) {
3402*4882a593Smuzhiyun case SWITCHDEV_OBJ_ID_PORT_VLAN:
3403*4882a593Smuzhiyun mlxsw_sp_switchdev_vxlan_vlans_del(vxlan_dev, port_obj_info);
3404*4882a593Smuzhiyun break;
3405*4882a593Smuzhiyun default:
3406*4882a593Smuzhiyun break;
3407*4882a593Smuzhiyun }
3408*4882a593Smuzhiyun }
3409*4882a593Smuzhiyun
mlxsw_sp_switchdev_blocking_event(struct notifier_block * unused,unsigned long event,void * ptr)3410*4882a593Smuzhiyun static int mlxsw_sp_switchdev_blocking_event(struct notifier_block *unused,
3411*4882a593Smuzhiyun unsigned long event, void *ptr)
3412*4882a593Smuzhiyun {
3413*4882a593Smuzhiyun struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
3414*4882a593Smuzhiyun int err = 0;
3415*4882a593Smuzhiyun
3416*4882a593Smuzhiyun switch (event) {
3417*4882a593Smuzhiyun case SWITCHDEV_PORT_OBJ_ADD:
3418*4882a593Smuzhiyun if (netif_is_vxlan(dev))
3419*4882a593Smuzhiyun err = mlxsw_sp_switchdev_handle_vxlan_obj_add(dev, ptr);
3420*4882a593Smuzhiyun else
3421*4882a593Smuzhiyun err = switchdev_handle_port_obj_add(dev, ptr,
3422*4882a593Smuzhiyun mlxsw_sp_port_dev_check,
3423*4882a593Smuzhiyun mlxsw_sp_port_obj_add);
3424*4882a593Smuzhiyun return notifier_from_errno(err);
3425*4882a593Smuzhiyun case SWITCHDEV_PORT_OBJ_DEL:
3426*4882a593Smuzhiyun if (netif_is_vxlan(dev))
3427*4882a593Smuzhiyun mlxsw_sp_switchdev_handle_vxlan_obj_del(dev, ptr);
3428*4882a593Smuzhiyun else
3429*4882a593Smuzhiyun err = switchdev_handle_port_obj_del(dev, ptr,
3430*4882a593Smuzhiyun mlxsw_sp_port_dev_check,
3431*4882a593Smuzhiyun mlxsw_sp_port_obj_del);
3432*4882a593Smuzhiyun return notifier_from_errno(err);
3433*4882a593Smuzhiyun case SWITCHDEV_PORT_ATTR_SET:
3434*4882a593Smuzhiyun err = switchdev_handle_port_attr_set(dev, ptr,
3435*4882a593Smuzhiyun mlxsw_sp_port_dev_check,
3436*4882a593Smuzhiyun mlxsw_sp_port_attr_set);
3437*4882a593Smuzhiyun return notifier_from_errno(err);
3438*4882a593Smuzhiyun }
3439*4882a593Smuzhiyun
3440*4882a593Smuzhiyun return NOTIFY_DONE;
3441*4882a593Smuzhiyun }
3442*4882a593Smuzhiyun
3443*4882a593Smuzhiyun static struct notifier_block mlxsw_sp_switchdev_blocking_notifier = {
3444*4882a593Smuzhiyun .notifier_call = mlxsw_sp_switchdev_blocking_event,
3445*4882a593Smuzhiyun };
3446*4882a593Smuzhiyun
3447*4882a593Smuzhiyun u8
mlxsw_sp_bridge_port_stp_state(struct mlxsw_sp_bridge_port * bridge_port)3448*4882a593Smuzhiyun mlxsw_sp_bridge_port_stp_state(struct mlxsw_sp_bridge_port *bridge_port)
3449*4882a593Smuzhiyun {
3450*4882a593Smuzhiyun return bridge_port->stp_state;
3451*4882a593Smuzhiyun }
3452*4882a593Smuzhiyun
mlxsw_sp_fdb_init(struct mlxsw_sp * mlxsw_sp)3453*4882a593Smuzhiyun static int mlxsw_sp_fdb_init(struct mlxsw_sp *mlxsw_sp)
3454*4882a593Smuzhiyun {
3455*4882a593Smuzhiyun struct mlxsw_sp_bridge *bridge = mlxsw_sp->bridge;
3456*4882a593Smuzhiyun struct notifier_block *nb;
3457*4882a593Smuzhiyun int err;
3458*4882a593Smuzhiyun
3459*4882a593Smuzhiyun err = mlxsw_sp_ageing_set(mlxsw_sp, MLXSW_SP_DEFAULT_AGEING_TIME);
3460*4882a593Smuzhiyun if (err) {
3461*4882a593Smuzhiyun dev_err(mlxsw_sp->bus_info->dev, "Failed to set default ageing time\n");
3462*4882a593Smuzhiyun return err;
3463*4882a593Smuzhiyun }
3464*4882a593Smuzhiyun
3465*4882a593Smuzhiyun err = register_switchdev_notifier(&mlxsw_sp_switchdev_notifier);
3466*4882a593Smuzhiyun if (err) {
3467*4882a593Smuzhiyun dev_err(mlxsw_sp->bus_info->dev, "Failed to register switchdev notifier\n");
3468*4882a593Smuzhiyun return err;
3469*4882a593Smuzhiyun }
3470*4882a593Smuzhiyun
3471*4882a593Smuzhiyun nb = &mlxsw_sp_switchdev_blocking_notifier;
3472*4882a593Smuzhiyun err = register_switchdev_blocking_notifier(nb);
3473*4882a593Smuzhiyun if (err) {
3474*4882a593Smuzhiyun dev_err(mlxsw_sp->bus_info->dev, "Failed to register switchdev blocking notifier\n");
3475*4882a593Smuzhiyun goto err_register_switchdev_blocking_notifier;
3476*4882a593Smuzhiyun }
3477*4882a593Smuzhiyun
3478*4882a593Smuzhiyun INIT_DELAYED_WORK(&bridge->fdb_notify.dw, mlxsw_sp_fdb_notify_work);
3479*4882a593Smuzhiyun bridge->fdb_notify.interval = MLXSW_SP_DEFAULT_LEARNING_INTERVAL;
3480*4882a593Smuzhiyun mlxsw_sp_fdb_notify_work_schedule(mlxsw_sp, false);
3481*4882a593Smuzhiyun return 0;
3482*4882a593Smuzhiyun
3483*4882a593Smuzhiyun err_register_switchdev_blocking_notifier:
3484*4882a593Smuzhiyun unregister_switchdev_notifier(&mlxsw_sp_switchdev_notifier);
3485*4882a593Smuzhiyun return err;
3486*4882a593Smuzhiyun }
3487*4882a593Smuzhiyun
mlxsw_sp_fdb_fini(struct mlxsw_sp * mlxsw_sp)3488*4882a593Smuzhiyun static void mlxsw_sp_fdb_fini(struct mlxsw_sp *mlxsw_sp)
3489*4882a593Smuzhiyun {
3490*4882a593Smuzhiyun struct notifier_block *nb;
3491*4882a593Smuzhiyun
3492*4882a593Smuzhiyun cancel_delayed_work_sync(&mlxsw_sp->bridge->fdb_notify.dw);
3493*4882a593Smuzhiyun
3494*4882a593Smuzhiyun nb = &mlxsw_sp_switchdev_blocking_notifier;
3495*4882a593Smuzhiyun unregister_switchdev_blocking_notifier(nb);
3496*4882a593Smuzhiyun
3497*4882a593Smuzhiyun unregister_switchdev_notifier(&mlxsw_sp_switchdev_notifier);
3498*4882a593Smuzhiyun }
3499*4882a593Smuzhiyun
mlxsw_sp_switchdev_init(struct mlxsw_sp * mlxsw_sp)3500*4882a593Smuzhiyun int mlxsw_sp_switchdev_init(struct mlxsw_sp *mlxsw_sp)
3501*4882a593Smuzhiyun {
3502*4882a593Smuzhiyun struct mlxsw_sp_bridge *bridge;
3503*4882a593Smuzhiyun
3504*4882a593Smuzhiyun bridge = kzalloc(sizeof(*mlxsw_sp->bridge), GFP_KERNEL);
3505*4882a593Smuzhiyun if (!bridge)
3506*4882a593Smuzhiyun return -ENOMEM;
3507*4882a593Smuzhiyun mlxsw_sp->bridge = bridge;
3508*4882a593Smuzhiyun bridge->mlxsw_sp = mlxsw_sp;
3509*4882a593Smuzhiyun
3510*4882a593Smuzhiyun INIT_LIST_HEAD(&mlxsw_sp->bridge->bridges_list);
3511*4882a593Smuzhiyun
3512*4882a593Smuzhiyun bridge->bridge_8021q_ops = &mlxsw_sp_bridge_8021q_ops;
3513*4882a593Smuzhiyun bridge->bridge_8021d_ops = &mlxsw_sp_bridge_8021d_ops;
3514*4882a593Smuzhiyun
3515*4882a593Smuzhiyun return mlxsw_sp_fdb_init(mlxsw_sp);
3516*4882a593Smuzhiyun }
3517*4882a593Smuzhiyun
mlxsw_sp_switchdev_fini(struct mlxsw_sp * mlxsw_sp)3518*4882a593Smuzhiyun void mlxsw_sp_switchdev_fini(struct mlxsw_sp *mlxsw_sp)
3519*4882a593Smuzhiyun {
3520*4882a593Smuzhiyun mlxsw_sp_fdb_fini(mlxsw_sp);
3521*4882a593Smuzhiyun WARN_ON(!list_empty(&mlxsw_sp->bridge->bridges_list));
3522*4882a593Smuzhiyun kfree(mlxsw_sp->bridge);
3523*4882a593Smuzhiyun }
3524*4882a593Smuzhiyun
3525