L2

Manage L2 (MAC) addresses

L2

Manage the L2 (MAC address, FDB) table. l2 also manages two related tables: the L2 cache, which holds masked MAC entries such as BPDU and reserved-multicast traps, and the L2 station table, which lists the MAC addresses the switch terminates for routing.

Sub-command words are case-insensitive but must be typed in full: station works, sta does not. Synonyms: + for add, - for del, -d for show, clr for clear, -h for hash, -i for info and c for cache. Options are Key=<value> pairs. The upper-case letters of a key are the shortest accepted abbreviation, so MACaddress can be written mac= and Vlanid can be written v=. VLAN IDs are decimal unless written with 0x. When an option is left out, the VLAN defaults to 1 and the MAC to 00:00:00:00:00:01.

A sub-command that takes options, run with no options at all, prints Current settings: and the defaults and changes nothing. So l2 add or l2 clear on their own are harmless. l2 cache clear is the exception.

Warning

add, replace, del, clear, and the cache and station changes write the switch’s L2 tables directly. On SONiC, orchagent and syncd own these tables and are not told. The next FDB flush or ageing event can undo the change, or leave SONiC’s view out of step with the hardware. Removing station entries stops routing.

show, count, check, conflict, hash, info, cache show and station show only read.

l2 show

List every L2 entry, one line per entry in the same form as the l2 add echo, without the ADD: prefix. An empty table prints nothing. The built-in help shows l2 show [PortBitMap=<pbmp>], but the option is ignored. The whole table is always listed. Read-only.

On a SONiC switch with no hosts learned, the table holds a single static entry: the switch’s own MAC on VLAN 1, pointing at cpu0. Learned MACs appear as further lines with the front-panel port (or trunk) they were learned on.

SONiC’s generate_dump collects this command (scripts/generate_dump (show techsupport collector)).

Hardware-validated

drivshell> l2 show
mac=e0:39:d7:88:3b:00 vlan=1 GPORT=0x0 modid=0 port=0/cpu0 Static CPU
l2 add [PortBitMap=<pbmp> | Port=<port>] [MACaddress=<mac>] [Vlanid=<id>] [Module=<modid>] [Trunk=<bool>] [TrunkGroupID=<id>] [STatic=<bool>] [HIT=<bool>] [Replace=<bool>] [SourceCosPriority=<bool>] [DiscardSource=<bool>] [DiscardDest=<bool>] [L3=<bool>] [CPUmirror=<bool>] [MIRror=<bool>] [ReplacePriority=<bool>] [MacBlockPortBitMap=<pbmp>] [Group=<group>] [PENDing=<bool>] [LearnLimitExempt=<bool>] [Mesh=<bool>]

Add an L2 entry. It is echoed as, for example, ADD: mac=76:c0:f8:4b:c8:04 vlan=4095 GPORT=0x0 modid=0 port=0/cpu0 Static CPU. With PortBitMap, one entry is added per port and the MAC address goes up by one for each port. With Port, one entry is added. ReplacePriority defaults to true. The built-in help also lists RemoteLookup; the shell rejects it as an unknown option. Module, PENDing and LearnLimitExempt work but are not in the help. Changes the L2 table.

Hardware-validated — Direct a router MAC to the CPU

drivshell> l2 add mac=76:c0:f8:4b:c8:04 port=cpu0 Static=true ReplacePriority=false vlan=4095
ADD: mac=76:c0:f8:4b:c8:04 vlan=4095 GPORT=0x0 modid=0 port=0/cpu0 Static CPU
l2 replace [Module=<n>] [Port=<port>] [MACaddress=<mac>] [Vlanid=<id>] [Trunk=<bool>] [TrunkGroupID=<id>] [STatic=<bool>] [PENDing=<bool>] [IgnorePENDing=<bool>] [NewModule=<n>] [NewPort=<port>] [NewTrunkGroupID=<id>] [Mesh=<bool>]

Move matching L2 entries to a new port, module or trunk. Entries are matched on whichever of MAC, VLAN, port and trunk you give. The built-in help shows this as l2_replace; the shell actually accepts l2 replace. Changes the L2 table.

Unvalidated

drivshell> l2 replace Vlanid=100 Port=xe1 NewPort=xe2
l2 del [MACaddress=<mac>] [Vlanid=<id>] [Count=<n>]

Delete Count entries (default 1), starting at MACaddress on Vlanid and adding one to the MAC each time. It stops with L2: ERROR: Entry not found at the first address that is not in the table, as in the example, where none of the addresses exist. Changes the L2 table.

Hardware-validated

drivshell> l2 del mac=00:00:00:00:00:01 vlan=100 count=4
L2: ERROR: Entry not found

Failed to execute the diagnostic command. Error: Operation failed.
l2 clear [Module=<n>] [Port=<port>] [Vlanid=<id>] [TrunkGroupID=<id>] [MACaddress=<mac>] [STatic=<bool>] [PENDing=<bool>]

Delete L2 entries in bulk. The options you give decide what is deleted:

  • Port (with or without Module): every entry on that port

  • Vlanid: every entry in that VLAN

  • TrunkGroupID: every entry on that trunk

  • MACaddress: that MAC in every VLAN

  • MACaddress and Vlanid: that one entry

  • MACaddress and Port: that MAC on that port

  • Vlanid and Port: that VLAN on that port

  • Vlanid and TrunkGroupID: that VLAN on that trunk

Any other combination prints Unknown argument combination. Static entries are deleted too, unless you add STatic=false. The shell prints what it deletes, for example L2: Deleting non-static addresses by VLAN, and nothing else, even when no entry matched. Changes the L2 table, including entries that SONiC installed as static.

Hardware-validated

drivshell> l2 clear Vlanid=100 STatic=false
L2: Deleting non-static addresses by VLAN
l2 count

Print L2 entry counts per table memory. This only works on chips with the older split L2 table. On Trident 3 it prints ERROR: L2 count not implemented on this unit and L2: Command not implemented. Use l2 info instead. Read-only.

Hardware-validated

drivshell> l2 count
ERROR: L2 count not implemented on this unit
L2: Command not implemented

Failed to execute the diagnostic command. Error: Operation failed.
l2 check

Read the whole hardware L2 table and dump every valid entry. A dot is printed for every 100 indexes. The built-in help shows l2 check [hit, valid, static]; the shell actually rejects any argument with Subcommands not supported. Read-only, but slow on a large table.

Unvalidated

drivshell> l2 check
l2 watch [start | stop]

With no argument, print L2 watch is running. or L2 watch is not running.. start prints every learn and age event on the console until stop. This does not change the table, but on a busy switch it can flood the shell.

Unvalidated

drivshell> l2 watch
l2 conflict [MACaddress=<mac>] [Vlanid=<id>]

List the entries that share a hash bucket with the given MAC and VLAN, each prefixed conflict:. Use it to see why a MAC could not be learned. When no entry shares the bucket it prints nothing. Read-only.

Hardware-validated

drivshell> l2 conflict mac=00:11:22:33:44:55 vlan=100
l2 hash [MACaddress=<mac>] [Vlanid=<id>] [Hash=<hash_type>]

Print the hash bucket and index that a MAC and VLAN map to under hash type Hash. Read-only.

On Trident 3 it fails with L2: ERROR: Invalid parameter, as below. Use l2 conflict to see what shares a bucket with an address.

Hardware-validated

drivshell> l2 hash mac=00:11:22:33:44:55 vlan=100
L2: ERROR: Invalid parameter

Failed to execute the diagnostic command. Error: Operation failed.
l2 info

Print how many MAC entries are in use and the maximum, as mac entries      :  <used> / <max>. Read-only. Trident 3 has room for 32768 MAC entries; a SONiC switch with no hosts learned shows 1 (its own MAC).

Hardware-validated

drivshell> l2 info
mac entries      :      1 /  32768
l2 cache add [CacheIndex=<index>] [MACaddress=<mac>] [MACaddressMask=<mac>] [Vlanid=<id>] [VlanidMask=<mask>] [LookupClass=<class>] [SourcePort=<port>] [SourcePortMask=<mask>] [Module=<modid>] [Port=<port>] [Trunk=<bool>] [TrunkGroupID=<id>] [SetPriority=<bool>] [PRIOrity=<prio>] [DiscardDest=<bool>] [L3=<bool>] [CPUmirror=<bool>] [MIRror=<bool>] [BPDU=<bool>] [ReplacePriority=<bool>] [LearnDisable=<bool>] [PROTocolPacKeT=<bool>]

Add a masked L2 cache entry. These are the same entries that bpdu add writes. Without CacheIndex a free index is chosen and printed as => using index <n>. Changes switch state. The SAI may use L2 cache entries for its own traps, so only overwrite indexes you created. On a SONiC switch the L2 cache is empty, so any index is free.

Unvalidated

drivshell> l2 cache add mac=01:80:c2:00:00:0e port=cpu0 BPDU=true
l2 cache del CacheIndex=<index> [Count=<n>]

Delete Count L2 cache entries, starting at CacheIndex. Without an index it prints ERROR: no index specified. Changes switch state.

Unvalidated

drivshell> l2 cache del CacheIndex=10
l2 cache show

List the valid L2 cache entries with their indexes. Read-only. On a SONiC switch it prints nothing: SONiC traps control packets with field-processor rules, not with L2 cache entries.

Hardware-validated

drivshell> l2 cache show
l2 cache clear [ReInit=<bool>]

Delete every L2 cache entry. ReInit=true then puts back the SDK’s default entries.

Warning

Unlike the other l2 sub-commands, l2 cache clear with no option does not just print settings: it deletes everything, including entries the SAI installed.

Unvalidated

drivshell> l2 cache clear ReInit=true
l2 station add [ID=<sid>] [Priority=<val>] [MACaddress=<mac>] [MACaddressMask=<mask>] [Vlanid=<id>] [VlanidMask=<mask>] [SourcePort=<id>] [SourcePortMask=<mask>] [IPv4=<bool>] [IPv6=<bool>] [ArpRarp=<bool>] [MPLS=<bool>] [MiM=<bool>] [TRILL=<bool>] [FCoE=<bool>] [OAM=<bool>] [CPUmirror=<bool>] [Replace=<bool>] [Discard=<bool>]

Add an L2 station entry: a MAC (and optional VLAN or port) for which the switch terminates IPv4, IPv6, MPLS or other traffic. The new entry’s ID is printed as Created SID=0x<sid>. The SAI keeps the router MACs here, so a wrong entry can stop routing. Changes switch state.

Unvalidated

drivshell> l2 station add mac=76:c0:f8:4b:c8:04 MACaddressMask=ff:ff:ff:ff:ff:ff IPv4=true IPv6=true
l2 station delete ID=<sid>

Delete one station entry. l2 station clear deletes all of them, including the router MACs, which stops routing on a SONiC switch. Changes switch state.

Unvalidated

drivshell> l2 station delete ID=0x1
l2 station show ID=<sid>

Show one station entry: its ID and priority, then the MAC, MAC mask, VLAN, VLAN mask, source port, source-port mask and flags, one per line. There is no way to list all entries. Without ID= it only prints the defaults. Read-only.

On a SONiC switch station 1 is the router MAC (the switch’s own MAC, any VLAN, any port). The shell prints the MAC bytes without leading zeros, so e0:39:d7:88:3b:0 is e0:39:d7:88:3b:00.

Hardware-validated

drivshell> l2 station show ID=0x1
  SID=0x00000001, priority=0
  MAC=e0:39:d7:88:3b:0
  MAC MASK=ff:ff:ff:ff:ff:ff
  VLAN=0x0
  VLAN MASK=0x0
  SourcePort=0x0
  SourcePort MASK=0x0
  Flags=0x803c

Built-in help

Usages:
      l2 add [PortBitMap=<pbmp> or Port=<port>] [MACaddress=<mac>] [Vlanid=<id>]
             [Trunk=true|false] [TrunkGroupId=<id>] [STatic=true|false]
             [SourceCosPriority=true|false] [DiscardSource=true|false]
             [DiscardDest]=true|false] [L3=true|false] [HIT=true|false]
             [Replace=true|false] [CPUmirror=true|false] [MIRror=true|false]
             [ReplacePriority=true|false] [RemoteLookup=true|false]
             [MacBlockPortBitMap=<pbmp>] [Group=<group>]
             [Mesh=true|false]
            - Add incrementing L2 addresses associated with port(s)
      l2_replace [Module=<n>] [Port=<port>] [MACaddress=<mac>]
                 [Vlanid=<id>] [Trunk=true|false] [TrunkGroupId=<id>]
                 [STatic=true|false] [Pending=true|false]
                 [NewModule=<n>] [NewPort=<port>] [NewTrunkGroupId=<id>]
                 [Mesh=true|false]
      l2 del [MACaddress=<mac>] [Count=<value>] [Vlanid=<id>]
            - Delete incrementing L2 address(s)
      l2 show [PortBitMap=<pbmp]
            - Show L2 addresses associated with port(s)
      l2 count
            - Show the L2 counts on different memories
      l2 check [hit, valid, static]
            - Check full L2 table for valid entries
      l2 clear [Module=<n>] [Port=<port>] [MACaddress=<mac>]
               [Vlanid=<id>] [TrunkGroupID=<id>] [Static=true|false]
            - Remove all L2 entries on the given module, module/port,
               VLAN, or trunk group ID
      l2 hash [MACaddress=<mac>] [Vlanid=<id>] [Hash=<hash_type>]
            - Calculate L2 hash index
      l2 conflict [MACaddress=<mac>] [Vlanid=<id>]
            - Dump all conflicting L2 entries (same hash bucket)
      l2 watch [start | stop]
            - Watch dynamic address insertions/deletions
      l2 info
            - Display the capacity and usage of the L2 resources.
      l2 cache add [CacheIndex=<index>]
             [MACaddress=<mac>] [MACaddressMask=<mac>]
             [Vlanid=<id>] [VlanidMask=<mask>] [LookupClass=<class>]
             [SourcePort=<id>] [SourcePortMask=<mask>]
             [Module=<modid>] [Port=<port>]
             [Trunk=true|false] [TrunkGroupId=<id>]
             [SetPriority=true|false] [PRIOrity=<prio>]
             [DiscardDest]=true|false] [CPUmirror=true|false]
             [MIRror=true|false] [BPDU=true|false] [L3=true|false]
             [ReplacePriority=true|false] [LearnDisable=true|false]
             [PROTocolPacKeT=true|false]
            - Add L2 cache entry
      l2 cache del CacheIndex=<index> [Count=<value>]
            - Delete L2 cache entry
      l2 cache show
            - Show L2 cache entries
      l2 cache clear [ReInit=true|false]
            - Delete all L2 cache entries
      l2 station add [Priority=<val>] [ID=<Sid>]
             [MACaddress=<mac>] [MACaddressMask=<mask>]
             [Vlanid=<id>] [VlanidMask=<mask>]
             [SourcePort=<id>] [SourcePortMask=<mask>]
             [IPv4=true|false] [IPv6=true|false] [ArpRarp=true|false]
             [MPLS=true|false] [MiM=true|false] [TRILL=true|false]
             [FCoE=true|false] [OAM=true|false] [CPUmirror=true|false]
             [Replace=true|false] [Discard=true|false]
            - Add L2 station entry
      l2 station delete ID=<sid>
            - Delete L2 station entry
      l2 station clear
            - Delete all L2 station entries
      l2 station show ID=<sid>
            - Show L2 station entry

Further reading

bcmsh.md (published as https://kamelnetworks.github.io/sonic/bcmsh.html), SDK-6.5.20 HSDK Getting Started Guide (GS-SDK6520-R), plus SDK-6.5.20/21/22 Release Notes (RN-SDK65xx-R), SDK-6.5.20..6.5.27 Resolved-Issues-Improvements.xlsx (7 files), scripts/generate_dump (show techsupport collector), ASIC-level Shell Access (Open NX-OS), Cisco Nexus 9000 Series NX-OS Troubleshooting Guide, Release 9.3(x) – Troubleshooting VLANs, FBOSS: BcmSwitch gatherSdkState/rcload, validated shell commands, diag shell stress test, vendor-diag-shell skill, debugging doc, BCM-SDK命令的使用.pdf, BCM_SDK命令, 交换芯片Helix4 L2 L3功能验证, How to check and change L2 fdb related information on BCM shell, Edgecore AS5610-52X reverse engineering: Cumulus 2.5 baseline captures.