root/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mlxsw_sp_span_init
  2. mlxsw_sp_span_fini
  3. mlxsw_sp_span_entry_phys_parms
  4. mlxsw_sp_span_entry_phys_configure
  5. mlxsw_sp_span_entry_deconfigure_common
  6. mlxsw_sp_span_entry_phys_deconfigure
  7. mlxsw_sp_span_dmac
  8. mlxsw_sp_span_entry_unoffloadable
  9. mlxsw_sp_span_entry_bridge_8021q
  10. mlxsw_sp_span_entry_bridge_8021d
  11. mlxsw_sp_span_entry_bridge
  12. mlxsw_sp_span_entry_vlan
  13. mlxsw_sp_span_entry_lag
  14. mlxsw_sp_span_entry_tunnel_parms_common
  15. mlxsw_sp_span_gretap4_route
  16. mlxsw_sp_span_entry_gretap4_parms
  17. mlxsw_sp_span_entry_gretap4_configure
  18. mlxsw_sp_span_entry_gretap4_deconfigure
  19. mlxsw_sp_span_gretap6_route
  20. mlxsw_sp_span_entry_gretap6_parms
  21. mlxsw_sp_span_entry_gretap6_configure
  22. mlxsw_sp_span_entry_gretap6_deconfigure
  23. mlxsw_sp_span_vlan_can_handle
  24. mlxsw_sp_span_entry_vlan_parms
  25. mlxsw_sp_span_entry_vlan_configure
  26. mlxsw_sp_span_entry_vlan_deconfigure
  27. mlxsw_sp_span_entry_nop_parms
  28. mlxsw_sp_span_entry_nop_configure
  29. mlxsw_sp_span_entry_nop_deconfigure
  30. mlxsw_sp_span_entry_configure
  31. mlxsw_sp_span_entry_deconfigure
  32. mlxsw_sp_span_entry_create
  33. mlxsw_sp_span_entry_destroy
  34. mlxsw_sp_span_entry_find_by_port
  35. mlxsw_sp_span_entry_invalidate
  36. mlxsw_sp_span_entry_find_by_id
  37. mlxsw_sp_span_entry_get
  38. mlxsw_sp_span_entry_put
  39. mlxsw_sp_span_is_egress_mirror
  40. mlxsw_sp_span_mtu_to_buffsize
  41. mlxsw_sp_span_port_mtu_update
  42. mlxsw_sp_span_entry_bound_port_find
  43. mlxsw_sp_span_inspected_port_bind
  44. mlxsw_sp_span_inspected_port_add
  45. mlxsw_sp_span_inspected_port_del
  46. mlxsw_sp_span_entry_ops
  47. mlxsw_sp_span_mirror_add
  48. mlxsw_sp_span_mirror_del
  49. mlxsw_sp_span_respin

   1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2 /* Copyright (c) 2018 Mellanox Technologies. All rights reserved */
   3 
   4 #include <linux/if_bridge.h>
   5 #include <linux/list.h>
   6 #include <net/arp.h>
   7 #include <net/gre.h>
   8 #include <net/lag.h>
   9 #include <net/ndisc.h>
  10 #include <net/ip6_tunnel.h>
  11 
  12 #include "spectrum.h"
  13 #include "spectrum_ipip.h"
  14 #include "spectrum_span.h"
  15 #include "spectrum_switchdev.h"
  16 
  17 int mlxsw_sp_span_init(struct mlxsw_sp *mlxsw_sp)
  18 {
  19         int i;
  20 
  21         if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_SPAN))
  22                 return -EIO;
  23 
  24         mlxsw_sp->span.entries_count = MLXSW_CORE_RES_GET(mlxsw_sp->core,
  25                                                           MAX_SPAN);
  26         mlxsw_sp->span.entries = kcalloc(mlxsw_sp->span.entries_count,
  27                                          sizeof(struct mlxsw_sp_span_entry),
  28                                          GFP_KERNEL);
  29         if (!mlxsw_sp->span.entries)
  30                 return -ENOMEM;
  31 
  32         for (i = 0; i < mlxsw_sp->span.entries_count; i++) {
  33                 struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i];
  34 
  35                 INIT_LIST_HEAD(&curr->bound_ports_list);
  36                 curr->id = i;
  37         }
  38 
  39         return 0;
  40 }
  41 
  42 void mlxsw_sp_span_fini(struct mlxsw_sp *mlxsw_sp)
  43 {
  44         int i;
  45 
  46         for (i = 0; i < mlxsw_sp->span.entries_count; i++) {
  47                 struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i];
  48 
  49                 WARN_ON_ONCE(!list_empty(&curr->bound_ports_list));
  50         }
  51         kfree(mlxsw_sp->span.entries);
  52 }
  53 
  54 static int
  55 mlxsw_sp_span_entry_phys_parms(const struct net_device *to_dev,
  56                                struct mlxsw_sp_span_parms *sparmsp)
  57 {
  58         sparmsp->dest_port = netdev_priv(to_dev);
  59         return 0;
  60 }
  61 
  62 static int
  63 mlxsw_sp_span_entry_phys_configure(struct mlxsw_sp_span_entry *span_entry,
  64                                    struct mlxsw_sp_span_parms sparms)
  65 {
  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;
  71 
  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);
  75 
  76         return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpat), mpat_pl);
  77 }
  78 
  79 static void
  80 mlxsw_sp_span_entry_deconfigure_common(struct mlxsw_sp_span_entry *span_entry,
  81                                        enum mlxsw_reg_mpat_span_type span_type)
  82 {
  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;
  88 
  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);
  91 }
  92 
  93 static void
  94 mlxsw_sp_span_entry_phys_deconfigure(struct mlxsw_sp_span_entry *span_entry)
  95 {
  96         mlxsw_sp_span_entry_deconfigure_common(span_entry,
  97                                             MLXSW_REG_MPAT_SPAN_TYPE_LOCAL_ETH);
  98 }
  99 
 100 static const
 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,
 106 };
 107 
 108 static int mlxsw_sp_span_dmac(struct neigh_table *tbl,
 109                               const void *pkey,
 110                               struct net_device *dev,
 111                               unsigned char dmac[ETH_ALEN])
 112 {
 113         struct neighbour *neigh = neigh_lookup(tbl, pkey, dev);
 114         int err = 0;
 115 
 116         if (!neigh) {
 117                 neigh = neigh_create(tbl, pkey, dev);
 118                 if (IS_ERR(neigh))
 119                         return PTR_ERR(neigh);
 120         }
 121 
 122         neigh_event_send(neigh, NULL);
 123 
 124         read_lock_bh(&neigh->lock);
 125         if ((neigh->nud_state & NUD_VALID) && !neigh->dead)
 126                 memcpy(dmac, neigh->ha, ETH_ALEN);
 127         else
 128                 err = -ENOENT;
 129         read_unlock_bh(&neigh->lock);
 130 
 131         neigh_release(neigh);
 132         return err;
 133 }
 134 
 135 static int
 136 mlxsw_sp_span_entry_unoffloadable(struct mlxsw_sp_span_parms *sparmsp)
 137 {
 138         sparmsp->dest_port = NULL;
 139         return 0;
 140 }
 141 
 142 static struct net_device *
 143 mlxsw_sp_span_entry_bridge_8021q(const struct net_device *br_dev,
 144                                  unsigned char *dmac,
 145                                  u16 *p_vid)
 146 {
 147         struct bridge_vlan_info vinfo;
 148         struct net_device *edev;
 149         u16 vid = *p_vid;
 150 
 151         if (!vid && WARN_ON(br_vlan_get_pvid(br_dev, &vid)))
 152                 return NULL;
 153         if (!vid ||
 154             br_vlan_get_info(br_dev, vid, &vinfo) ||
 155             !(vinfo.flags & BRIDGE_VLAN_INFO_BRENTRY))
 156                 return NULL;
 157 
 158         edev = br_fdb_find_port(br_dev, dmac, vid);
 159         if (!edev)
 160                 return NULL;
 161 
 162         if (br_vlan_get_info(edev, vid, &vinfo))
 163                 return NULL;
 164         if (vinfo.flags & BRIDGE_VLAN_INFO_UNTAGGED)
 165                 *p_vid = 0;
 166         else
 167                 *p_vid = vid;
 168         return edev;
 169 }
 170 
 171 static struct net_device *
 172 mlxsw_sp_span_entry_bridge_8021d(const struct net_device *br_dev,
 173                                  unsigned char *dmac)
 174 {
 175         return br_fdb_find_port(br_dev, dmac, 0);
 176 }
 177 
 178 static struct net_device *
 179 mlxsw_sp_span_entry_bridge(const struct net_device *br_dev,
 180                            unsigned char dmac[ETH_ALEN],
 181                            u16 *p_vid)
 182 {
 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;
 187         u8 stp_state;
 188 
 189         if (br_vlan_enabled(br_dev))
 190                 dev = mlxsw_sp_span_entry_bridge_8021q(br_dev, dmac, p_vid);
 191         else if (!*p_vid)
 192                 dev = mlxsw_sp_span_entry_bridge_8021d(br_dev, dmac);
 193         if (!dev)
 194                 return NULL;
 195 
 196         port = mlxsw_sp_port_dev_lower_find(dev);
 197         if (!port)
 198                 return NULL;
 199 
 200         bridge_port = mlxsw_sp_bridge_port_find(port->mlxsw_sp->bridge, dev);
 201         if (!bridge_port)
 202                 return NULL;
 203 
 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)
 207                 return NULL;
 208 
 209         return dev;
 210 }
 211 
 212 static struct net_device *
 213 mlxsw_sp_span_entry_vlan(const struct net_device *vlan_dev,
 214                          u16 *p_vid)
 215 {
 216         *p_vid = vlan_dev_vlan_id(vlan_dev);
 217         return vlan_dev_real_dev(vlan_dev);
 218 }
 219 
 220 static struct net_device *
 221 mlxsw_sp_span_entry_lag(struct net_device *lag_dev)
 222 {
 223         struct net_device *dev;
 224         struct list_head *iter;
 225 
 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))
 230                         return dev;
 231 
 232         return NULL;
 233 }
 234 
 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,
 240                                         __u8 ttl,
 241                                         struct neigh_table *tbl,
 242                                         struct mlxsw_sp_span_parms *sparmsp)
 243 {
 244         unsigned char dmac[ETH_ALEN];
 245         u16 vid = 0;
 246 
 247         if (mlxsw_sp_l3addr_is_zero(gw))
 248                 gw = daddr;
 249 
 250         if (!edev || mlxsw_sp_span_dmac(tbl, &gw, edev, dmac))
 251                 goto unoffloadable;
 252 
 253         if (is_vlan_dev(edev))
 254                 edev = mlxsw_sp_span_entry_vlan(edev, &vid);
 255 
 256         if (netif_is_bridge_master(edev)) {
 257                 edev = mlxsw_sp_span_entry_bridge(edev, dmac, &vid);
 258                 if (!edev)
 259                         goto unoffloadable;
 260         }
 261 
 262         if (is_vlan_dev(edev)) {
 263                 if (vid || !(edev->flags & IFF_UP))
 264                         goto unoffloadable;
 265                 edev = mlxsw_sp_span_entry_vlan(edev, &vid);
 266         }
 267 
 268         if (netif_is_lag_master(edev)) {
 269                 if (!(edev->flags & IFF_UP))
 270                         goto unoffloadable;
 271                 edev = mlxsw_sp_span_entry_lag(edev);
 272                 if (!edev)
 273                         goto unoffloadable;
 274         }
 275 
 276         if (!mlxsw_sp_port_dev_check(edev))
 277                 goto unoffloadable;
 278 
 279         sparmsp->dest_port = netdev_priv(edev);
 280         sparmsp->ttl = ttl;
 281         memcpy(sparmsp->dmac, dmac, ETH_ALEN);
 282         memcpy(sparmsp->smac, edev->dev_addr, ETH_ALEN);
 283         sparmsp->saddr = saddr;
 284         sparmsp->daddr = daddr;
 285         sparmsp->vid = vid;
 286         return 0;
 287 
 288 unoffloadable:
 289         return mlxsw_sp_span_entry_unoffloadable(sparmsp);
 290 }
 291 
 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)
 296 {
 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;
 301         struct flowi4 fl4;
 302 
 303         /* We assume "dev" stays valid after rt is put. */
 304         ASSERT_RTNL();
 305 
 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);
 309 
 310         rt = ip_route_output_key(tun->net, &fl4);
 311         if (IS_ERR(rt))
 312                 return NULL;
 313 
 314         if (rt->rt_type != RTN_UNICAST)
 315                 goto out;
 316 
 317         dev = rt->dst.dev;
 318         *saddrp = fl4.saddr;
 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)
 323                 dev = NULL;
 324 
 325 out:
 326         ip_rt_put(rt);
 327         return dev;
 328 }
 329 
 330 static int
 331 mlxsw_sp_span_entry_gretap4_parms(const struct net_device *to_dev,
 332                                   struct mlxsw_sp_span_parms *sparmsp)
 333 {
 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;
 341 
 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);
 350 
 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,
 353                                                        tparm.iph.ttl,
 354                                                        &arp_tbl, sparmsp);
 355 }
 356 
 357 static int
 358 mlxsw_sp_span_entry_gretap4_configure(struct mlxsw_sp_span_entry *span_entry,
 359                                       struct mlxsw_sp_span_parms sparms)
 360 {
 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;
 366 
 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));
 378 
 379         return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpat), mpat_pl);
 380 }
 381 
 382 static void
 383 mlxsw_sp_span_entry_gretap4_deconfigure(struct mlxsw_sp_span_entry *span_entry)
 384 {
 385         mlxsw_sp_span_entry_deconfigure_common(span_entry,
 386                                         MLXSW_REG_MPAT_SPAN_TYPE_REMOTE_ETH_L3);
 387 }
 388 
 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,
 394 };
 395 #endif
 396 
 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)
 402 {
 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;
 408 
 409         /* We assume "dev" stays valid after dst is released. */
 410         ASSERT_RTNL();
 411 
 412         fl6.flowi6_mark = t->parms.fwmark;
 413         if (!ip6_tnl_xmit_ctl(t, &fl6.saddr, &fl6.daddr))
 414                 return NULL;
 415 
 416         dst = ip6_route_output(t->net, NULL, &fl6);
 417         if (!dst || dst->error)
 418                 goto out;
 419 
 420         rt6 = container_of(dst, struct rt6_info, dst);
 421 
 422         dev = dst->dev;
 423         *saddrp = fl6.saddr;
 424         *daddrp = rt6->rt6i_gateway;
 425 
 426 out:
 427         dst_release(dst);
 428         return dev;
 429 }
 430 
 431 static int
 432 mlxsw_sp_span_entry_gretap6_parms(const struct net_device *to_dev,
 433                                   struct mlxsw_sp_span_parms *sparmsp)
 434 {
 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;
 442 
 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);
 451 
 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,
 454                                                        tparm.hop_limit,
 455                                                        &nd_tbl, sparmsp);
 456 }
 457 
 458 static int
 459 mlxsw_sp_span_entry_gretap6_configure(struct mlxsw_sp_span_entry *span_entry,
 460                                       struct mlxsw_sp_span_parms sparms)
 461 {
 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;
 467 
 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,
 476                                               sparms.saddr.addr6,
 477                                               sparms.daddr.addr6);
 478 
 479         return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpat), mpat_pl);
 480 }
 481 
 482 static void
 483 mlxsw_sp_span_entry_gretap6_deconfigure(struct mlxsw_sp_span_entry *span_entry)
 484 {
 485         mlxsw_sp_span_entry_deconfigure_common(span_entry,
 486                                         MLXSW_REG_MPAT_SPAN_TYPE_REMOTE_ETH_L3);
 487 }
 488 
 489 static const
 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,
 495 };
 496 #endif
 497 
 498 static bool
 499 mlxsw_sp_span_vlan_can_handle(const struct net_device *dev)
 500 {
 501         return is_vlan_dev(dev) &&
 502                mlxsw_sp_port_dev_check(vlan_dev_real_dev(dev));
 503 }
 504 
 505 static int
 506 mlxsw_sp_span_entry_vlan_parms(const struct net_device *to_dev,
 507                                struct mlxsw_sp_span_parms *sparmsp)
 508 {
 509         struct net_device *real_dev;
 510         u16 vid;
 511 
 512         if (!(to_dev->flags & IFF_UP))
 513                 return mlxsw_sp_span_entry_unoffloadable(sparmsp);
 514 
 515         real_dev = mlxsw_sp_span_entry_vlan(to_dev, &vid);
 516         sparmsp->dest_port = netdev_priv(real_dev);
 517         sparmsp->vid = vid;
 518         return 0;
 519 }
 520 
 521 static int
 522 mlxsw_sp_span_entry_vlan_configure(struct mlxsw_sp_span_entry *span_entry,
 523                                    struct mlxsw_sp_span_parms sparms)
 524 {
 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;
 530 
 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);
 534 
 535         return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpat), mpat_pl);
 536 }
 537 
 538 static void
 539 mlxsw_sp_span_entry_vlan_deconfigure(struct mlxsw_sp_span_entry *span_entry)
 540 {
 541         mlxsw_sp_span_entry_deconfigure_common(span_entry,
 542                                         MLXSW_REG_MPAT_SPAN_TYPE_REMOTE_ETH);
 543 }
 544 
 545 static const
 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,
 551 };
 552 
 553 static const
 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,
 558 #endif
 559 #if IS_ENABLED(CONFIG_IPV6_GRE)
 560         &mlxsw_sp_span_entry_ops_gretap6,
 561 #endif
 562         &mlxsw_sp_span_entry_ops_vlan,
 563 };
 564 
 565 static int
 566 mlxsw_sp_span_entry_nop_parms(const struct net_device *to_dev,
 567                               struct mlxsw_sp_span_parms *sparmsp)
 568 {
 569         return mlxsw_sp_span_entry_unoffloadable(sparmsp);
 570 }
 571 
 572 static int
 573 mlxsw_sp_span_entry_nop_configure(struct mlxsw_sp_span_entry *span_entry,
 574                                   struct mlxsw_sp_span_parms sparms)
 575 {
 576         return 0;
 577 }
 578 
 579 static void
 580 mlxsw_sp_span_entry_nop_deconfigure(struct mlxsw_sp_span_entry *span_entry)
 581 {
 582 }
 583 
 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,
 588 };
 589 
 590 static void
 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)
 594 {
 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;
 604                 }
 605         }
 606 
 607         span_entry->parms = sparms;
 608 }
 609 
 610 static void
 611 mlxsw_sp_span_entry_deconfigure(struct mlxsw_sp_span_entry *span_entry)
 612 {
 613         if (span_entry->parms.dest_port)
 614                 span_entry->ops->deconfigure(span_entry);
 615 }
 616 
 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)
 622 {
 623         struct mlxsw_sp_span_entry *span_entry = NULL;
 624         int i;
 625 
 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];
 630                         break;
 631                 }
 632         }
 633         if (!span_entry)
 634                 return NULL;
 635 
 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);
 640 
 641         return span_entry;
 642 }
 643 
 644 static void mlxsw_sp_span_entry_destroy(struct mlxsw_sp_span_entry *span_entry)
 645 {
 646         mlxsw_sp_span_entry_deconfigure(span_entry);
 647 }
 648 
 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)
 652 {
 653         int i;
 654 
 655         for (i = 0; i < mlxsw_sp->span.entries_count; i++) {
 656                 struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i];
 657 
 658                 if (curr->ref_count && curr->to_dev == to_dev)
 659                         return curr;
 660         }
 661         return NULL;
 662 }
 663 
 664 void mlxsw_sp_span_entry_invalidate(struct mlxsw_sp *mlxsw_sp,
 665                                     struct mlxsw_sp_span_entry *span_entry)
 666 {
 667         mlxsw_sp_span_entry_deconfigure(span_entry);
 668         span_entry->ops = &mlxsw_sp_span_entry_ops_nop;
 669 }
 670 
 671 static struct mlxsw_sp_span_entry *
 672 mlxsw_sp_span_entry_find_by_id(struct mlxsw_sp *mlxsw_sp, int span_id)
 673 {
 674         int i;
 675 
 676         for (i = 0; i < mlxsw_sp->span.entries_count; i++) {
 677                 struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i];
 678 
 679                 if (curr->ref_count && curr->id == span_id)
 680                         return curr;
 681         }
 682         return NULL;
 683 }
 684 
 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)
 690 {
 691         struct mlxsw_sp_span_entry *span_entry;
 692 
 693         span_entry = mlxsw_sp_span_entry_find_by_port(mlxsw_sp, to_dev);
 694         if (span_entry) {
 695                 /* Already exists, just take a reference */
 696                 span_entry->ref_count++;
 697                 return span_entry;
 698         }
 699 
 700         return mlxsw_sp_span_entry_create(mlxsw_sp, to_dev, ops, sparms);
 701 }
 702 
 703 static int mlxsw_sp_span_entry_put(struct mlxsw_sp *mlxsw_sp,
 704                                    struct mlxsw_sp_span_entry *span_entry)
 705 {
 706         WARN_ON(!span_entry->ref_count);
 707         if (--span_entry->ref_count == 0)
 708                 mlxsw_sp_span_entry_destroy(span_entry);
 709         return 0;
 710 }
 711 
 712 static bool mlxsw_sp_span_is_egress_mirror(struct mlxsw_sp_port *port)
 713 {
 714         struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp;
 715         struct mlxsw_sp_span_inspected_port *p;
 716         int i;
 717 
 718         for (i = 0; i < mlxsw_sp->span.entries_count; i++) {
 719                 struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i];
 720 
 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)
 724                                 return true;
 725         }
 726 
 727         return false;
 728 }
 729 
 730 static int mlxsw_sp_span_mtu_to_buffsize(const struct mlxsw_sp *mlxsw_sp,
 731                                          int mtu)
 732 {
 733         return mlxsw_sp_bytes_cells(mlxsw_sp, mtu * 5 / 2) + 1;
 734 }
 735 
 736 int mlxsw_sp_span_port_mtu_update(struct mlxsw_sp_port *port, u16 mtu)
 737 {
 738         struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp;
 739         char sbib_pl[MLXSW_REG_SBIB_LEN];
 740         int err;
 741 
 742         /* If port is egress mirrored, the shared buffer size should be
 743          * updated according to the mtu value
 744          */
 745         if (mlxsw_sp_span_is_egress_mirror(port)) {
 746                 u32 buffsize = mlxsw_sp_span_mtu_to_buffsize(mlxsw_sp, mtu);
 747 
 748                 mlxsw_reg_sbib_pack(sbib_pl, port->local_port, buffsize);
 749                 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbib), sbib_pl);
 750                 if (err) {
 751                         netdev_err(port->dev, "Could not update shared buffer for mirroring\n");
 752                         return err;
 753                 }
 754         }
 755 
 756         return 0;
 757 }
 758 
 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,
 763                                     bool bind)
 764 {
 765         struct mlxsw_sp_span_inspected_port *p;
 766 
 767         list_for_each_entry(p, &span_entry->bound_ports_list, list)
 768                 if (type == p->type &&
 769                     port->local_port == p->local_port &&
 770                     bind == p->bound)
 771                         return p;
 772         return NULL;
 773 }
 774 
 775 static int
 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,
 779                                   bool bind)
 780 {
 781         struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp;
 782         char mpar_pl[MLXSW_REG_MPAR_LEN];
 783         int pa_id = span_entry->id;
 784 
 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);
 789 }
 790 
 791 static int
 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,
 795                                  bool bind)
 796 {
 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];
 800         int i;
 801         int err;
 802 
 803         /* A given (source port, direction) can only be bound to one analyzer,
 804          * so if a binding is requested, check for conflicts.
 805          */
 806         if (bind)
 807                 for (i = 0; i < mlxsw_sp->span.entries_count; i++) {
 808                         struct mlxsw_sp_span_entry *curr =
 809                                 &mlxsw_sp->span.entries[i];
 810 
 811                         if (mlxsw_sp_span_entry_bound_port_find(curr, type,
 812                                                                 port, bind))
 813                                 return -EEXIST;
 814                 }
 815 
 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,
 819                                                              port->dev->mtu);
 820 
 821                 mlxsw_reg_sbib_pack(sbib_pl, port->local_port, buffsize);
 822                 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbib), sbib_pl);
 823                 if (err) {
 824                         netdev_err(port->dev, "Could not create shared buffer for mirroring\n");
 825                         return err;
 826                 }
 827         }
 828 
 829         if (bind) {
 830                 err = mlxsw_sp_span_inspected_port_bind(port, span_entry, type,
 831                                                         true);
 832                 if (err)
 833                         goto err_port_bind;
 834         }
 835 
 836         inspected_port = kzalloc(sizeof(*inspected_port), GFP_KERNEL);
 837         if (!inspected_port) {
 838                 err = -ENOMEM;
 839                 goto err_inspected_port_alloc;
 840         }
 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);
 845 
 846         return 0;
 847 
 848 err_inspected_port_alloc:
 849         if (bind)
 850                 mlxsw_sp_span_inspected_port_bind(port, span_entry, type,
 851                                                   false);
 852 err_port_bind:
 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);
 856         }
 857         return err;
 858 }
 859 
 860 static void
 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,
 864                                  bool bind)
 865 {
 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];
 869 
 870         inspected_port = mlxsw_sp_span_entry_bound_port_find(span_entry, type,
 871                                                              port, bind);
 872         if (!inspected_port)
 873                 return;
 874 
 875         if (bind)
 876                 mlxsw_sp_span_inspected_port_bind(port, span_entry, type,
 877                                                   false);
 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);
 882         }
 883 
 884         mlxsw_sp_span_entry_put(mlxsw_sp, span_entry);
 885 
 886         list_del(&inspected_port->list);
 887         kfree(inspected_port);
 888 }
 889 
 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)
 893 {
 894         size_t i;
 895 
 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];
 899 
 900         return NULL;
 901 }
 902 
 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,
 906                              int *p_span_id)
 907 {
 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;
 912         int err;
 913 
 914         ops = mlxsw_sp_span_entry_ops(mlxsw_sp, to_dev);
 915         if (!ops) {
 916                 netdev_err(to_dev, "Cannot mirror to %s", to_dev->name);
 917                 return -EOPNOTSUPP;
 918         }
 919 
 920         err = ops->parms(to_dev, &sparms);
 921         if (err)
 922                 return err;
 923 
 924         span_entry = mlxsw_sp_span_entry_get(mlxsw_sp, to_dev, ops, sparms);
 925         if (!span_entry)
 926                 return -ENOBUFS;
 927 
 928         netdev_dbg(from->dev, "Adding inspected port to SPAN entry %d\n",
 929                    span_entry->id);
 930 
 931         err = mlxsw_sp_span_inspected_port_add(from, span_entry, type, bind);
 932         if (err)
 933                 goto err_port_bind;
 934 
 935         *p_span_id = span_entry->id;
 936         return 0;
 937 
 938 err_port_bind:
 939         mlxsw_sp_span_entry_put(mlxsw_sp, span_entry);
 940         return err;
 941 }
 942 
 943 void mlxsw_sp_span_mirror_del(struct mlxsw_sp_port *from, int span_id,
 944                               enum mlxsw_sp_span_type type, bool bind)
 945 {
 946         struct mlxsw_sp_span_entry *span_entry;
 947 
 948         span_entry = mlxsw_sp_span_entry_find_by_id(from->mlxsw_sp, span_id);
 949         if (!span_entry) {
 950                 netdev_err(from->dev, "no span entry found\n");
 951                 return;
 952         }
 953 
 954         netdev_dbg(from->dev, "removing inspected port from SPAN entry %d\n",
 955                    span_entry->id);
 956         mlxsw_sp_span_inspected_port_del(from, span_entry, type, bind);
 957 }
 958 
 959 void mlxsw_sp_span_respin(struct mlxsw_sp *mlxsw_sp)
 960 {
 961         int i;
 962         int err;
 963 
 964         ASSERT_RTNL();
 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};
 968 
 969                 if (!curr->ref_count)
 970                         continue;
 971 
 972                 err = curr->ops->parms(curr->to_dev, &sparms);
 973                 if (err)
 974                         continue;
 975 
 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);
 979                 }
 980         }
 981 }

/* [<][>][^][v][top][bottom][index][help] */