1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2018 Mellanox Technologies. All rights reserved */
4 #include <linux/if_bridge.h>
5 #include <linux/list.h>
10 #include <net/ip6_tunnel.h>
13 #include "spectrum_ipip.h"
14 #include "spectrum_span.h"
15 #include "spectrum_switchdev.h"
17 int mlxsw_sp_span_init(struct mlxsw_sp
*mlxsw_sp
)
21 if (!MLXSW_CORE_RES_VALID(mlxsw_sp
->core
, MAX_SPAN
))
24 mlxsw_sp
->span
.entries_count
= MLXSW_CORE_RES_GET(mlxsw_sp
->core
,
26 mlxsw_sp
->span
.entries
= kcalloc(mlxsw_sp
->span
.entries_count
,
27 sizeof(struct mlxsw_sp_span_entry
),
29 if (!mlxsw_sp
->span
.entries
)
32 for (i
= 0; i
< mlxsw_sp
->span
.entries_count
; i
++) {
33 struct mlxsw_sp_span_entry
*curr
= &mlxsw_sp
->span
.entries
[i
];
35 INIT_LIST_HEAD(&curr
->bound_ports_list
);
42 void mlxsw_sp_span_fini(struct mlxsw_sp
*mlxsw_sp
)
46 for (i
= 0; i
< mlxsw_sp
->span
.entries_count
; i
++) {
47 struct mlxsw_sp_span_entry
*curr
= &mlxsw_sp
->span
.entries
[i
];
49 WARN_ON_ONCE(!list_empty(&curr
->bound_ports_list
));
51 kfree(mlxsw_sp
->span
.entries
);
55 mlxsw_sp_span_entry_phys_parms(const struct net_device
*to_dev
,
56 struct mlxsw_sp_span_parms
*sparmsp
)
58 sparmsp
->dest_port
= netdev_priv(to_dev
);
63 mlxsw_sp_span_entry_phys_configure(struct mlxsw_sp_span_entry
*span_entry
,
64 struct mlxsw_sp_span_parms sparms
)
66 struct mlxsw_sp_port
*dest_port
= sparms
.dest_port
;
67 struct mlxsw_sp
*mlxsw_sp
= dest_port
->mlxsw_sp
;
68 u8 local_port
= dest_port
->local_port
;
69 char mpat_pl
[MLXSW_REG_MPAT_LEN
];
70 int pa_id
= span_entry
->id
;
72 /* Create a new port analayzer entry for local_port. */
73 mlxsw_reg_mpat_pack(mpat_pl
, pa_id
, local_port
, true,
74 MLXSW_REG_MPAT_SPAN_TYPE_LOCAL_ETH
);
76 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(mpat
), mpat_pl
);
80 mlxsw_sp_span_entry_deconfigure_common(struct mlxsw_sp_span_entry
*span_entry
,
81 enum mlxsw_reg_mpat_span_type span_type
)
83 struct mlxsw_sp_port
*dest_port
= span_entry
->parms
.dest_port
;
84 struct mlxsw_sp
*mlxsw_sp
= dest_port
->mlxsw_sp
;
85 u8 local_port
= dest_port
->local_port
;
86 char mpat_pl
[MLXSW_REG_MPAT_LEN
];
87 int pa_id
= span_entry
->id
;
89 mlxsw_reg_mpat_pack(mpat_pl
, pa_id
, local_port
, false, span_type
);
90 mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(mpat
), mpat_pl
);
94 mlxsw_sp_span_entry_phys_deconfigure(struct mlxsw_sp_span_entry
*span_entry
)
96 mlxsw_sp_span_entry_deconfigure_common(span_entry
,
97 MLXSW_REG_MPAT_SPAN_TYPE_LOCAL_ETH
);
101 struct mlxsw_sp_span_entry_ops mlxsw_sp_span_entry_ops_phys
= {
102 .can_handle
= mlxsw_sp_port_dev_check
,
103 .parms
= mlxsw_sp_span_entry_phys_parms
,
104 .configure
= mlxsw_sp_span_entry_phys_configure
,
105 .deconfigure
= mlxsw_sp_span_entry_phys_deconfigure
,
108 static int mlxsw_sp_span_dmac(struct neigh_table
*tbl
,
110 struct net_device
*dev
,
111 unsigned char dmac
[ETH_ALEN
])
113 struct neighbour
*neigh
= neigh_lookup(tbl
, pkey
, dev
);
117 neigh
= neigh_create(tbl
, pkey
, dev
);
119 return PTR_ERR(neigh
);
122 neigh_event_send(neigh
, NULL
);
124 read_lock_bh(&neigh
->lock
);
125 if ((neigh
->nud_state
& NUD_VALID
) && !neigh
->dead
)
126 memcpy(dmac
, neigh
->ha
, ETH_ALEN
);
129 read_unlock_bh(&neigh
->lock
);
131 neigh_release(neigh
);
136 mlxsw_sp_span_entry_unoffloadable(struct mlxsw_sp_span_parms
*sparmsp
)
138 sparmsp
->dest_port
= NULL
;
142 static struct net_device
*
143 mlxsw_sp_span_entry_bridge_8021q(const struct net_device
*br_dev
,
147 struct bridge_vlan_info vinfo
;
148 struct net_device
*edev
;
151 if (!vid
&& WARN_ON(br_vlan_get_pvid(br_dev
, &vid
)))
154 br_vlan_get_info(br_dev
, vid
, &vinfo
) ||
155 !(vinfo
.flags
& BRIDGE_VLAN_INFO_BRENTRY
))
158 edev
= br_fdb_find_port(br_dev
, dmac
, vid
);
162 if (br_vlan_get_info(edev
, vid
, &vinfo
))
164 if (vinfo
.flags
& BRIDGE_VLAN_INFO_UNTAGGED
)
171 static struct net_device
*
172 mlxsw_sp_span_entry_bridge_8021d(const struct net_device
*br_dev
,
175 return br_fdb_find_port(br_dev
, dmac
, 0);
178 static struct net_device
*
179 mlxsw_sp_span_entry_bridge(const struct net_device
*br_dev
,
180 unsigned char dmac
[ETH_ALEN
],
183 struct mlxsw_sp_bridge_port
*bridge_port
;
184 enum mlxsw_reg_spms_state spms_state
;
185 struct net_device
*dev
= NULL
;
186 struct mlxsw_sp_port
*port
;
189 if (br_vlan_enabled(br_dev
))
190 dev
= mlxsw_sp_span_entry_bridge_8021q(br_dev
, dmac
, p_vid
);
192 dev
= mlxsw_sp_span_entry_bridge_8021d(br_dev
, dmac
);
196 port
= mlxsw_sp_port_dev_lower_find(dev
);
200 bridge_port
= mlxsw_sp_bridge_port_find(port
->mlxsw_sp
->bridge
, dev
);
204 stp_state
= mlxsw_sp_bridge_port_stp_state(bridge_port
);
205 spms_state
= mlxsw_sp_stp_spms_state(stp_state
);
206 if (spms_state
!= MLXSW_REG_SPMS_STATE_FORWARDING
)
212 static struct net_device
*
213 mlxsw_sp_span_entry_vlan(const struct net_device
*vlan_dev
,
216 *p_vid
= vlan_dev_vlan_id(vlan_dev
);
217 return vlan_dev_real_dev(vlan_dev
);
220 static struct net_device
*
221 mlxsw_sp_span_entry_lag(struct net_device
*lag_dev
)
223 struct net_device
*dev
;
224 struct list_head
*iter
;
226 netdev_for_each_lower_dev(lag_dev
, dev
, iter
)
227 if (netif_carrier_ok(dev
) &&
228 net_lag_port_dev_txable(dev
) &&
229 mlxsw_sp_port_dev_check(dev
))
235 static __maybe_unused
int
236 mlxsw_sp_span_entry_tunnel_parms_common(struct net_device
*edev
,
237 union mlxsw_sp_l3addr saddr
,
238 union mlxsw_sp_l3addr daddr
,
239 union mlxsw_sp_l3addr gw
,
241 struct neigh_table
*tbl
,
242 struct mlxsw_sp_span_parms
*sparmsp
)
244 unsigned char dmac
[ETH_ALEN
];
247 if (mlxsw_sp_l3addr_is_zero(gw
))
250 if (!edev
|| mlxsw_sp_span_dmac(tbl
, &gw
, edev
, dmac
))
253 if (is_vlan_dev(edev
))
254 edev
= mlxsw_sp_span_entry_vlan(edev
, &vid
);
256 if (netif_is_bridge_master(edev
)) {
257 edev
= mlxsw_sp_span_entry_bridge(edev
, dmac
, &vid
);
262 if (is_vlan_dev(edev
)) {
263 if (vid
|| !(edev
->flags
& IFF_UP
))
265 edev
= mlxsw_sp_span_entry_vlan(edev
, &vid
);
268 if (netif_is_lag_master(edev
)) {
269 if (!(edev
->flags
& IFF_UP
))
271 edev
= mlxsw_sp_span_entry_lag(edev
);
276 if (!mlxsw_sp_port_dev_check(edev
))
279 sparmsp
->dest_port
= netdev_priv(edev
);
281 memcpy(sparmsp
->dmac
, dmac
, ETH_ALEN
);
282 memcpy(sparmsp
->smac
, edev
->dev_addr
, ETH_ALEN
);
283 sparmsp
->saddr
= saddr
;
284 sparmsp
->daddr
= daddr
;
289 return mlxsw_sp_span_entry_unoffloadable(sparmsp
);
292 #if IS_ENABLED(CONFIG_NET_IPGRE)
293 static struct net_device
*
294 mlxsw_sp_span_gretap4_route(const struct net_device
*to_dev
,
295 __be32
*saddrp
, __be32
*daddrp
)
297 struct ip_tunnel
*tun
= netdev_priv(to_dev
);
298 struct net_device
*dev
= NULL
;
299 struct ip_tunnel_parm parms
;
300 struct rtable
*rt
= NULL
;
303 /* We assume "dev" stays valid after rt is put. */
306 parms
= mlxsw_sp_ipip_netdev_parms4(to_dev
);
307 ip_tunnel_init_flow(&fl4
, parms
.iph
.protocol
, *daddrp
, *saddrp
,
308 0, 0, parms
.link
, tun
->fwmark
, 0);
310 rt
= ip_route_output_key(tun
->net
, &fl4
);
314 if (rt
->rt_type
!= RTN_UNICAST
)
319 if (rt
->rt_gw_family
== AF_INET
)
320 *daddrp
= rt
->rt_gw4
;
321 /* can not offload if route has an IPv6 gateway */
322 else if (rt
->rt_gw_family
== AF_INET6
)
331 mlxsw_sp_span_entry_gretap4_parms(const struct net_device
*to_dev
,
332 struct mlxsw_sp_span_parms
*sparmsp
)
334 struct ip_tunnel_parm tparm
= mlxsw_sp_ipip_netdev_parms4(to_dev
);
335 union mlxsw_sp_l3addr saddr
= { .addr4
= tparm
.iph
.saddr
};
336 union mlxsw_sp_l3addr daddr
= { .addr4
= tparm
.iph
.daddr
};
337 bool inherit_tos
= tparm
.iph
.tos
& 0x1;
338 bool inherit_ttl
= !tparm
.iph
.ttl
;
339 union mlxsw_sp_l3addr gw
= daddr
;
340 struct net_device
*l3edev
;
342 if (!(to_dev
->flags
& IFF_UP
) ||
343 /* Reject tunnels with GRE keys, checksums, etc. */
344 tparm
.i_flags
|| tparm
.o_flags
||
345 /* Require a fixed TTL and a TOS copied from the mirrored packet. */
346 inherit_ttl
|| !inherit_tos
||
347 /* A destination address may not be "any". */
348 mlxsw_sp_l3addr_is_zero(daddr
))
349 return mlxsw_sp_span_entry_unoffloadable(sparmsp
);
351 l3edev
= mlxsw_sp_span_gretap4_route(to_dev
, &saddr
.addr4
, &gw
.addr4
);
352 return mlxsw_sp_span_entry_tunnel_parms_common(l3edev
, saddr
, daddr
, gw
,
358 mlxsw_sp_span_entry_gretap4_configure(struct mlxsw_sp_span_entry
*span_entry
,
359 struct mlxsw_sp_span_parms sparms
)
361 struct mlxsw_sp_port
*dest_port
= sparms
.dest_port
;
362 struct mlxsw_sp
*mlxsw_sp
= dest_port
->mlxsw_sp
;
363 u8 local_port
= dest_port
->local_port
;
364 char mpat_pl
[MLXSW_REG_MPAT_LEN
];
365 int pa_id
= span_entry
->id
;
367 /* Create a new port analayzer entry for local_port. */
368 mlxsw_reg_mpat_pack(mpat_pl
, pa_id
, local_port
, true,
369 MLXSW_REG_MPAT_SPAN_TYPE_REMOTE_ETH_L3
);
370 mlxsw_reg_mpat_eth_rspan_pack(mpat_pl
, sparms
.vid
);
371 mlxsw_reg_mpat_eth_rspan_l2_pack(mpat_pl
,
372 MLXSW_REG_MPAT_ETH_RSPAN_VERSION_NO_HEADER
,
373 sparms
.dmac
, !!sparms
.vid
);
374 mlxsw_reg_mpat_eth_rspan_l3_ipv4_pack(mpat_pl
,
375 sparms
.ttl
, sparms
.smac
,
376 be32_to_cpu(sparms
.saddr
.addr4
),
377 be32_to_cpu(sparms
.daddr
.addr4
));
379 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(mpat
), mpat_pl
);
383 mlxsw_sp_span_entry_gretap4_deconfigure(struct mlxsw_sp_span_entry
*span_entry
)
385 mlxsw_sp_span_entry_deconfigure_common(span_entry
,
386 MLXSW_REG_MPAT_SPAN_TYPE_REMOTE_ETH_L3
);
389 static const struct mlxsw_sp_span_entry_ops mlxsw_sp_span_entry_ops_gretap4
= {
390 .can_handle
= netif_is_gretap
,
391 .parms
= mlxsw_sp_span_entry_gretap4_parms
,
392 .configure
= mlxsw_sp_span_entry_gretap4_configure
,
393 .deconfigure
= mlxsw_sp_span_entry_gretap4_deconfigure
,
397 #if IS_ENABLED(CONFIG_IPV6_GRE)
398 static struct net_device
*
399 mlxsw_sp_span_gretap6_route(const struct net_device
*to_dev
,
400 struct in6_addr
*saddrp
,
401 struct in6_addr
*daddrp
)
403 struct ip6_tnl
*t
= netdev_priv(to_dev
);
404 struct flowi6 fl6
= t
->fl
.u
.ip6
;
405 struct net_device
*dev
= NULL
;
406 struct dst_entry
*dst
;
407 struct rt6_info
*rt6
;
409 /* We assume "dev" stays valid after dst is released. */
412 fl6
.flowi6_mark
= t
->parms
.fwmark
;
413 if (!ip6_tnl_xmit_ctl(t
, &fl6
.saddr
, &fl6
.daddr
))
416 dst
= ip6_route_output(t
->net
, NULL
, &fl6
);
417 if (!dst
|| dst
->error
)
420 rt6
= container_of(dst
, struct rt6_info
, dst
);
424 *daddrp
= rt6
->rt6i_gateway
;
432 mlxsw_sp_span_entry_gretap6_parms(const struct net_device
*to_dev
,
433 struct mlxsw_sp_span_parms
*sparmsp
)
435 struct __ip6_tnl_parm tparm
= mlxsw_sp_ipip_netdev_parms6(to_dev
);
436 bool inherit_tos
= tparm
.flags
& IP6_TNL_F_USE_ORIG_TCLASS
;
437 union mlxsw_sp_l3addr saddr
= { .addr6
= tparm
.laddr
};
438 union mlxsw_sp_l3addr daddr
= { .addr6
= tparm
.raddr
};
439 bool inherit_ttl
= !tparm
.hop_limit
;
440 union mlxsw_sp_l3addr gw
= daddr
;
441 struct net_device
*l3edev
;
443 if (!(to_dev
->flags
& IFF_UP
) ||
444 /* Reject tunnels with GRE keys, checksums, etc. */
445 tparm
.i_flags
|| tparm
.o_flags
||
446 /* Require a fixed TTL and a TOS copied from the mirrored packet. */
447 inherit_ttl
|| !inherit_tos
||
448 /* A destination address may not be "any". */
449 mlxsw_sp_l3addr_is_zero(daddr
))
450 return mlxsw_sp_span_entry_unoffloadable(sparmsp
);
452 l3edev
= mlxsw_sp_span_gretap6_route(to_dev
, &saddr
.addr6
, &gw
.addr6
);
453 return mlxsw_sp_span_entry_tunnel_parms_common(l3edev
, saddr
, daddr
, gw
,
459 mlxsw_sp_span_entry_gretap6_configure(struct mlxsw_sp_span_entry
*span_entry
,
460 struct mlxsw_sp_span_parms sparms
)
462 struct mlxsw_sp_port
*dest_port
= sparms
.dest_port
;
463 struct mlxsw_sp
*mlxsw_sp
= dest_port
->mlxsw_sp
;
464 u8 local_port
= dest_port
->local_port
;
465 char mpat_pl
[MLXSW_REG_MPAT_LEN
];
466 int pa_id
= span_entry
->id
;
468 /* Create a new port analayzer entry for local_port. */
469 mlxsw_reg_mpat_pack(mpat_pl
, pa_id
, local_port
, true,
470 MLXSW_REG_MPAT_SPAN_TYPE_REMOTE_ETH_L3
);
471 mlxsw_reg_mpat_eth_rspan_pack(mpat_pl
, sparms
.vid
);
472 mlxsw_reg_mpat_eth_rspan_l2_pack(mpat_pl
,
473 MLXSW_REG_MPAT_ETH_RSPAN_VERSION_NO_HEADER
,
474 sparms
.dmac
, !!sparms
.vid
);
475 mlxsw_reg_mpat_eth_rspan_l3_ipv6_pack(mpat_pl
, sparms
.ttl
, sparms
.smac
,
479 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(mpat
), mpat_pl
);
483 mlxsw_sp_span_entry_gretap6_deconfigure(struct mlxsw_sp_span_entry
*span_entry
)
485 mlxsw_sp_span_entry_deconfigure_common(span_entry
,
486 MLXSW_REG_MPAT_SPAN_TYPE_REMOTE_ETH_L3
);
490 struct mlxsw_sp_span_entry_ops mlxsw_sp_span_entry_ops_gretap6
= {
491 .can_handle
= netif_is_ip6gretap
,
492 .parms
= mlxsw_sp_span_entry_gretap6_parms
,
493 .configure
= mlxsw_sp_span_entry_gretap6_configure
,
494 .deconfigure
= mlxsw_sp_span_entry_gretap6_deconfigure
,
499 mlxsw_sp_span_vlan_can_handle(const struct net_device
*dev
)
501 return is_vlan_dev(dev
) &&
502 mlxsw_sp_port_dev_check(vlan_dev_real_dev(dev
));
506 mlxsw_sp_span_entry_vlan_parms(const struct net_device
*to_dev
,
507 struct mlxsw_sp_span_parms
*sparmsp
)
509 struct net_device
*real_dev
;
512 if (!(to_dev
->flags
& IFF_UP
))
513 return mlxsw_sp_span_entry_unoffloadable(sparmsp
);
515 real_dev
= mlxsw_sp_span_entry_vlan(to_dev
, &vid
);
516 sparmsp
->dest_port
= netdev_priv(real_dev
);
522 mlxsw_sp_span_entry_vlan_configure(struct mlxsw_sp_span_entry
*span_entry
,
523 struct mlxsw_sp_span_parms sparms
)
525 struct mlxsw_sp_port
*dest_port
= sparms
.dest_port
;
526 struct mlxsw_sp
*mlxsw_sp
= dest_port
->mlxsw_sp
;
527 u8 local_port
= dest_port
->local_port
;
528 char mpat_pl
[MLXSW_REG_MPAT_LEN
];
529 int pa_id
= span_entry
->id
;
531 mlxsw_reg_mpat_pack(mpat_pl
, pa_id
, local_port
, true,
532 MLXSW_REG_MPAT_SPAN_TYPE_REMOTE_ETH
);
533 mlxsw_reg_mpat_eth_rspan_pack(mpat_pl
, sparms
.vid
);
535 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(mpat
), mpat_pl
);
539 mlxsw_sp_span_entry_vlan_deconfigure(struct mlxsw_sp_span_entry
*span_entry
)
541 mlxsw_sp_span_entry_deconfigure_common(span_entry
,
542 MLXSW_REG_MPAT_SPAN_TYPE_REMOTE_ETH
);
546 struct mlxsw_sp_span_entry_ops mlxsw_sp_span_entry_ops_vlan
= {
547 .can_handle
= mlxsw_sp_span_vlan_can_handle
,
548 .parms
= mlxsw_sp_span_entry_vlan_parms
,
549 .configure
= mlxsw_sp_span_entry_vlan_configure
,
550 .deconfigure
= mlxsw_sp_span_entry_vlan_deconfigure
,
554 struct mlxsw_sp_span_entry_ops
*const mlxsw_sp_span_entry_types
[] = {
555 &mlxsw_sp_span_entry_ops_phys
,
556 #if IS_ENABLED(CONFIG_NET_IPGRE)
557 &mlxsw_sp_span_entry_ops_gretap4
,
559 #if IS_ENABLED(CONFIG_IPV6_GRE)
560 &mlxsw_sp_span_entry_ops_gretap6
,
562 &mlxsw_sp_span_entry_ops_vlan
,
566 mlxsw_sp_span_entry_nop_parms(const struct net_device
*to_dev
,
567 struct mlxsw_sp_span_parms
*sparmsp
)
569 return mlxsw_sp_span_entry_unoffloadable(sparmsp
);
573 mlxsw_sp_span_entry_nop_configure(struct mlxsw_sp_span_entry
*span_entry
,
574 struct mlxsw_sp_span_parms sparms
)
580 mlxsw_sp_span_entry_nop_deconfigure(struct mlxsw_sp_span_entry
*span_entry
)
584 static const struct mlxsw_sp_span_entry_ops mlxsw_sp_span_entry_ops_nop
= {
585 .parms
= mlxsw_sp_span_entry_nop_parms
,
586 .configure
= mlxsw_sp_span_entry_nop_configure
,
587 .deconfigure
= mlxsw_sp_span_entry_nop_deconfigure
,
591 mlxsw_sp_span_entry_configure(struct mlxsw_sp
*mlxsw_sp
,
592 struct mlxsw_sp_span_entry
*span_entry
,
593 struct mlxsw_sp_span_parms sparms
)
595 if (sparms
.dest_port
) {
596 if (sparms
.dest_port
->mlxsw_sp
!= mlxsw_sp
) {
597 netdev_err(span_entry
->to_dev
, "Cannot mirror to %s, which belongs to a different mlxsw instance",
598 sparms
.dest_port
->dev
->name
);
599 sparms
.dest_port
= NULL
;
600 } else if (span_entry
->ops
->configure(span_entry
, sparms
)) {
601 netdev_err(span_entry
->to_dev
, "Failed to offload mirror to %s",
602 sparms
.dest_port
->dev
->name
);
603 sparms
.dest_port
= NULL
;
607 span_entry
->parms
= sparms
;
611 mlxsw_sp_span_entry_deconfigure(struct mlxsw_sp_span_entry
*span_entry
)
613 if (span_entry
->parms
.dest_port
)
614 span_entry
->ops
->deconfigure(span_entry
);
617 static struct mlxsw_sp_span_entry
*
618 mlxsw_sp_span_entry_create(struct mlxsw_sp
*mlxsw_sp
,
619 const struct net_device
*to_dev
,
620 const struct mlxsw_sp_span_entry_ops
*ops
,
621 struct mlxsw_sp_span_parms sparms
)
623 struct mlxsw_sp_span_entry
*span_entry
= NULL
;
626 /* find a free entry to use */
627 for (i
= 0; i
< mlxsw_sp
->span
.entries_count
; i
++) {
628 if (!mlxsw_sp
->span
.entries
[i
].ref_count
) {
629 span_entry
= &mlxsw_sp
->span
.entries
[i
];
636 span_entry
->ops
= ops
;
637 span_entry
->ref_count
= 1;
638 span_entry
->to_dev
= to_dev
;
639 mlxsw_sp_span_entry_configure(mlxsw_sp
, span_entry
, sparms
);
644 static void mlxsw_sp_span_entry_destroy(struct mlxsw_sp_span_entry
*span_entry
)
646 mlxsw_sp_span_entry_deconfigure(span_entry
);
649 struct mlxsw_sp_span_entry
*
650 mlxsw_sp_span_entry_find_by_port(struct mlxsw_sp
*mlxsw_sp
,
651 const struct net_device
*to_dev
)
655 for (i
= 0; i
< mlxsw_sp
->span
.entries_count
; i
++) {
656 struct mlxsw_sp_span_entry
*curr
= &mlxsw_sp
->span
.entries
[i
];
658 if (curr
->ref_count
&& curr
->to_dev
== to_dev
)
664 void mlxsw_sp_span_entry_invalidate(struct mlxsw_sp
*mlxsw_sp
,
665 struct mlxsw_sp_span_entry
*span_entry
)
667 mlxsw_sp_span_entry_deconfigure(span_entry
);
668 span_entry
->ops
= &mlxsw_sp_span_entry_ops_nop
;
671 static struct mlxsw_sp_span_entry
*
672 mlxsw_sp_span_entry_find_by_id(struct mlxsw_sp
*mlxsw_sp
, int span_id
)
676 for (i
= 0; i
< mlxsw_sp
->span
.entries_count
; i
++) {
677 struct mlxsw_sp_span_entry
*curr
= &mlxsw_sp
->span
.entries
[i
];
679 if (curr
->ref_count
&& curr
->id
== span_id
)
685 static struct mlxsw_sp_span_entry
*
686 mlxsw_sp_span_entry_get(struct mlxsw_sp
*mlxsw_sp
,
687 const struct net_device
*to_dev
,
688 const struct mlxsw_sp_span_entry_ops
*ops
,
689 struct mlxsw_sp_span_parms sparms
)
691 struct mlxsw_sp_span_entry
*span_entry
;
693 span_entry
= mlxsw_sp_span_entry_find_by_port(mlxsw_sp
, to_dev
);
695 /* Already exists, just take a reference */
696 span_entry
->ref_count
++;
700 return mlxsw_sp_span_entry_create(mlxsw_sp
, to_dev
, ops
, sparms
);
703 static int mlxsw_sp_span_entry_put(struct mlxsw_sp
*mlxsw_sp
,
704 struct mlxsw_sp_span_entry
*span_entry
)
706 WARN_ON(!span_entry
->ref_count
);
707 if (--span_entry
->ref_count
== 0)
708 mlxsw_sp_span_entry_destroy(span_entry
);
712 static bool mlxsw_sp_span_is_egress_mirror(struct mlxsw_sp_port
*port
)
714 struct mlxsw_sp
*mlxsw_sp
= port
->mlxsw_sp
;
715 struct mlxsw_sp_span_inspected_port
*p
;
718 for (i
= 0; i
< mlxsw_sp
->span
.entries_count
; i
++) {
719 struct mlxsw_sp_span_entry
*curr
= &mlxsw_sp
->span
.entries
[i
];
721 list_for_each_entry(p
, &curr
->bound_ports_list
, list
)
722 if (p
->local_port
== port
->local_port
&&
723 p
->type
== MLXSW_SP_SPAN_EGRESS
)
730 static int mlxsw_sp_span_mtu_to_buffsize(const struct mlxsw_sp
*mlxsw_sp
,
733 return mlxsw_sp_bytes_cells(mlxsw_sp
, mtu
* 5 / 2) + 1;
736 int mlxsw_sp_span_port_mtu_update(struct mlxsw_sp_port
*port
, u16 mtu
)
738 struct mlxsw_sp
*mlxsw_sp
= port
->mlxsw_sp
;
739 char sbib_pl
[MLXSW_REG_SBIB_LEN
];
742 /* If port is egress mirrored, the shared buffer size should be
743 * updated according to the mtu value
745 if (mlxsw_sp_span_is_egress_mirror(port
)) {
746 u32 buffsize
= mlxsw_sp_span_mtu_to_buffsize(mlxsw_sp
, mtu
);
748 mlxsw_reg_sbib_pack(sbib_pl
, port
->local_port
, buffsize
);
749 err
= mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(sbib
), sbib_pl
);
751 netdev_err(port
->dev
, "Could not update shared buffer for mirroring\n");
759 static struct mlxsw_sp_span_inspected_port
*
760 mlxsw_sp_span_entry_bound_port_find(struct mlxsw_sp_span_entry
*span_entry
,
761 enum mlxsw_sp_span_type type
,
762 struct mlxsw_sp_port
*port
,
765 struct mlxsw_sp_span_inspected_port
*p
;
767 list_for_each_entry(p
, &span_entry
->bound_ports_list
, list
)
768 if (type
== p
->type
&&
769 port
->local_port
== p
->local_port
&&
776 mlxsw_sp_span_inspected_port_bind(struct mlxsw_sp_port
*port
,
777 struct mlxsw_sp_span_entry
*span_entry
,
778 enum mlxsw_sp_span_type type
,
781 struct mlxsw_sp
*mlxsw_sp
= port
->mlxsw_sp
;
782 char mpar_pl
[MLXSW_REG_MPAR_LEN
];
783 int pa_id
= span_entry
->id
;
785 /* bind the port to the SPAN entry */
786 mlxsw_reg_mpar_pack(mpar_pl
, port
->local_port
,
787 (enum mlxsw_reg_mpar_i_e
)type
, bind
, pa_id
);
788 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(mpar
), mpar_pl
);
792 mlxsw_sp_span_inspected_port_add(struct mlxsw_sp_port
*port
,
793 struct mlxsw_sp_span_entry
*span_entry
,
794 enum mlxsw_sp_span_type type
,
797 struct mlxsw_sp_span_inspected_port
*inspected_port
;
798 struct mlxsw_sp
*mlxsw_sp
= port
->mlxsw_sp
;
799 char sbib_pl
[MLXSW_REG_SBIB_LEN
];
803 /* A given (source port, direction) can only be bound to one analyzer,
804 * so if a binding is requested, check for conflicts.
807 for (i
= 0; i
< mlxsw_sp
->span
.entries_count
; i
++) {
808 struct mlxsw_sp_span_entry
*curr
=
809 &mlxsw_sp
->span
.entries
[i
];
811 if (mlxsw_sp_span_entry_bound_port_find(curr
, type
,
816 /* if it is an egress SPAN, bind a shared buffer to it */
817 if (type
== MLXSW_SP_SPAN_EGRESS
) {
818 u32 buffsize
= mlxsw_sp_span_mtu_to_buffsize(mlxsw_sp
,
821 mlxsw_reg_sbib_pack(sbib_pl
, port
->local_port
, buffsize
);
822 err
= mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(sbib
), sbib_pl
);
824 netdev_err(port
->dev
, "Could not create shared buffer for mirroring\n");
830 err
= mlxsw_sp_span_inspected_port_bind(port
, span_entry
, type
,
836 inspected_port
= kzalloc(sizeof(*inspected_port
), GFP_KERNEL
);
837 if (!inspected_port
) {
839 goto err_inspected_port_alloc
;
841 inspected_port
->local_port
= port
->local_port
;
842 inspected_port
->type
= type
;
843 inspected_port
->bound
= bind
;
844 list_add_tail(&inspected_port
->list
, &span_entry
->bound_ports_list
);
848 err_inspected_port_alloc
:
850 mlxsw_sp_span_inspected_port_bind(port
, span_entry
, type
,
853 if (type
== MLXSW_SP_SPAN_EGRESS
) {
854 mlxsw_reg_sbib_pack(sbib_pl
, port
->local_port
, 0);
855 mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(sbib
), sbib_pl
);
861 mlxsw_sp_span_inspected_port_del(struct mlxsw_sp_port
*port
,
862 struct mlxsw_sp_span_entry
*span_entry
,
863 enum mlxsw_sp_span_type type
,
866 struct mlxsw_sp_span_inspected_port
*inspected_port
;
867 struct mlxsw_sp
*mlxsw_sp
= port
->mlxsw_sp
;
868 char sbib_pl
[MLXSW_REG_SBIB_LEN
];
870 inspected_port
= mlxsw_sp_span_entry_bound_port_find(span_entry
, type
,
876 mlxsw_sp_span_inspected_port_bind(port
, span_entry
, type
,
878 /* remove the SBIB buffer if it was egress SPAN */
879 if (type
== MLXSW_SP_SPAN_EGRESS
) {
880 mlxsw_reg_sbib_pack(sbib_pl
, port
->local_port
, 0);
881 mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(sbib
), sbib_pl
);
884 mlxsw_sp_span_entry_put(mlxsw_sp
, span_entry
);
886 list_del(&inspected_port
->list
);
887 kfree(inspected_port
);
890 static const struct mlxsw_sp_span_entry_ops
*
891 mlxsw_sp_span_entry_ops(struct mlxsw_sp
*mlxsw_sp
,
892 const struct net_device
*to_dev
)
896 for (i
= 0; i
< ARRAY_SIZE(mlxsw_sp_span_entry_types
); ++i
)
897 if (mlxsw_sp_span_entry_types
[i
]->can_handle(to_dev
))
898 return mlxsw_sp_span_entry_types
[i
];
903 int mlxsw_sp_span_mirror_add(struct mlxsw_sp_port
*from
,
904 const struct net_device
*to_dev
,
905 enum mlxsw_sp_span_type type
, bool bind
,
908 struct mlxsw_sp
*mlxsw_sp
= from
->mlxsw_sp
;
909 const struct mlxsw_sp_span_entry_ops
*ops
;
910 struct mlxsw_sp_span_parms sparms
= {NULL
};
911 struct mlxsw_sp_span_entry
*span_entry
;
914 ops
= mlxsw_sp_span_entry_ops(mlxsw_sp
, to_dev
);
916 netdev_err(to_dev
, "Cannot mirror to %s", to_dev
->name
);
920 err
= ops
->parms(to_dev
, &sparms
);
924 span_entry
= mlxsw_sp_span_entry_get(mlxsw_sp
, to_dev
, ops
, sparms
);
928 netdev_dbg(from
->dev
, "Adding inspected port to SPAN entry %d\n",
931 err
= mlxsw_sp_span_inspected_port_add(from
, span_entry
, type
, bind
);
935 *p_span_id
= span_entry
->id
;
939 mlxsw_sp_span_entry_put(mlxsw_sp
, span_entry
);
943 void mlxsw_sp_span_mirror_del(struct mlxsw_sp_port
*from
, int span_id
,
944 enum mlxsw_sp_span_type type
, bool bind
)
946 struct mlxsw_sp_span_entry
*span_entry
;
948 span_entry
= mlxsw_sp_span_entry_find_by_id(from
->mlxsw_sp
, span_id
);
950 netdev_err(from
->dev
, "no span entry found\n");
954 netdev_dbg(from
->dev
, "removing inspected port from SPAN entry %d\n",
956 mlxsw_sp_span_inspected_port_del(from
, span_entry
, type
, bind
);
959 void mlxsw_sp_span_respin(struct mlxsw_sp
*mlxsw_sp
)
965 for (i
= 0; i
< mlxsw_sp
->span
.entries_count
; i
++) {
966 struct mlxsw_sp_span_entry
*curr
= &mlxsw_sp
->span
.entries
[i
];
967 struct mlxsw_sp_span_parms sparms
= {NULL
};
969 if (!curr
->ref_count
)
972 err
= curr
->ops
->parms(curr
->to_dev
, &sparms
);
976 if (memcmp(&sparms
, &curr
->parms
, sizeof(sparms
))) {
977 mlxsw_sp_span_entry_deconfigure(curr
);
978 mlxsw_sp_span_entry_configure(mlxsw_sp
, curr
, sparms
);