Mulitple Span on 4112F-ON with OpenSwitch
In this test case I am testing to see if we can configure a Dell 4112F-ON with OpenSwitch to create a one to many port configuration using SPAN.
Helpful Links
ONIE Network Install Process Overview
OPX Install Instructions for Dell EMC Equipment
My Configuration
General Configuration
- ONIE host is running RHEL 8
- I am using a Dell S4112F-ON for testing
- OpenSwitch version PKGS_OPX-3.2.0-installer-x86_64
- PFSense running DNS and DHCP as services
RHEL Release Info
NAME="Red Hat Enterprise Linux"
VERSION="8.0 (Ootpa)"
ID="rhel"
ID_LIKE="fedora"
VERSION_ID="8.0"
PLATFORM_ID="platform:el8"
PRETTY_NAME="Red Hat Enterprise Linux 8.0 (Ootpa)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:redhat:enterprise_linux:8.0:GA"
HOME_URL="https://www.redhat.com/"
BUG_REPORT_URL="https://bugzilla.redhat.com/"
REDHAT_BUGZILLA_PRODUCT="Red Hat Enterprise Linux 8"
REDHAT_BUGZILLA_PRODUCT_VERSION=8.0
REDHAT_SUPPORT_PRODUCT="Red Hat Enterprise Linux"
REDHAT_SUPPORT_PRODUCT_VERSION="8.0"
Red Hat Enterprise Linux release 8.0 (Ootpa)
Red Hat Enterprise Linux release 8.0 (Ootpa)
OPX Version
OS_NAME="OPX"
OS_VERSION="unstable"
PLATFORM="S4112F-ON"
ARCHITECTURE="x86_64"
INTERNAL_BUILD_ID="OpenSwitch blueprint for Dell 1.0.0"
BUILD_VERSION="unstable.0-stretch"
BUILD_DATE="2019-06-21T19:04:22+0000"
INSTALL_DATE="2019-10-23T23:16:10+00:00"
SYSTEM_UPTIME= 1 day, 5 minutes
SYSTEM_STATE= running
UPGRADED_PACKAGES=no
ALTERED_PACKAGES=yes
Wasn't sure why I got the unstable version after installation. It didn't cause any problems for testing so I just left it as is.
Setup ONIE Prerequisites
See ONIE Install Setup for instructions.
Configure Device as TAP
Physical Configuration
For this configuration to work, we will use the management interface as the input interface for the tap. See image below. You will need to move your network cable over from your usual network to your traffic generator.
Configure Management Interface (Optional)
Update: After I got it working I ended up using this as an ingress interface so this step is more or less optional. You won't be able to SSH into this interface in the end config (at least not easily).
- Start by running
sudo -i
to move to privileged mode. Warning: I noticed the OPX command line tools won't behave correctly unless you are privileged. Ex:opx-show-interface
won't list any interfaces. - I added vim to my box before continuing with
sudo apt-get install -y vim
- The management interface is configured like a typicaly Debian interface with
vim /etc/network/interface.d/eth0
-
Use the following configuration modified to your needs:
auto eth0 allow-hotplug eth0 iface eth0 inet static address 192.168.1.20 netmask 255.255.255.0 gateway 192.168.1.1
-
When you are finished with your configuration run
systemctl restart networking
to apply the changes. - Confirm the changes were applied with
ip address show dev eth0
. If you see two IP addresses because you picked one up from DHCP you can delete the other withip address del [IP ADDRESS] dev eth0
and then runsystemctl restart networking
At this juncture your management interface should be up and running and you should be able to SSH to it. I went ahead and swapped to SSH so as not to deal with the oddities that come with running in the console port.
Bridge/tc Configuration
After attempt 3 I started thinking about other ways to connect things. Realized I could just pump everything to a bridge and let that do the replication. That worked!
Do the following to get it up and running:
tc
is a feature of modern Linux kernels designed for mirroring traffic. I found
this article
helpful. This Mellanox article was also
useful.
WARNING: You must use your management interface for the ingress port or this solution will not work! I noticed the other ports do not behave like normal Linux ports. More investigation required to figure out the difference.
- Create a bridge interface with
brctl addbr br0
- Attach all interfaces you want as part of the port mirroring to the bridge with
brctl addif br0 < INTERFACE >
1.Make sure all interfaces in use are enabled withip link set < INTERFACE > up
- Disable MAC address learning on the bridge with
brctl setageing br0 0
- Set the device's management interface to promiscuous mode with
ip link set < MGMT_INTERFACE > promisc on
- The first thing I did was create an ingress queue on my input interface with
tc qdisc add dev < MGMT_INTERFACE > handle ffff: ingress
1.If you need to delete a qdisc you can do it withtc qdisc del dev < MGMT_INTERFACE > [ root | ingress ]
- Double check your queue with handle ffff was created with
tc -s qdisc ls dev < MGMT_INTERFACE >
- Next we want to mirror all traffic from the ingress port to an output port with
tc filter add dev < MGMT_INTERFACE > parent ffff: protocol all u32 match u32 0 0 action mirred egress mirror dev br0
- Check that your port mirror appeared in the config with
tc -s -p filter ls dev < MGMT_INTERFACE > parent ffff:
1.If you need to delete the filters you can do so withtc filter del dev < MGMT_INTERFACE > parent ffff:
- Set queue to not shape traffic with
tc qdisc add dev < MGMT_INTERFACE > handle 1: root prio
Things I Tried
- I added 7 interfaces to my bridge to make sure there weren't any strange limitations
- I moved the SFPs around to multiple different ports to make sure the traffic was mirroing on all of them
- I double checked the traffic I was capturing belonged to the PCAP in question. Easy enough to see because it has IP addresses the hosts in question wouldn't ever otherwise see. Screenshots for confirmation below.
Host 1
Host 2
- I checked that pure L3 traffic was passed correctly using ICMP.
Noted Problem
The only major issue I noticed is that pure layer 2 traffic didn't get passed. Haven't figured out how to fix that yet.
Failed Ideas
Attempt 1 - Mirror Ports
My first go is to try using OpenSwitch's built in mirroring capability.
Physical Configuration
I didn't have enough target hosts to try outputting from one port to all ports so I simulated it. The purple cable in the image is the input port from the traffic generator (tcpreplay) and the white and yellow cables go out to the hosts listed as host 1 and host 2 in the test results section. The ports with the white and yellow cables were configured as the mirror's target ports.
Mirror Configuration
For each port you want to mirror to run opx-config-mirror create --src_intf e101-001-0 --dest_intf e101-005-0 --direction ingress --type span
. Substitute your source and destination ports appropriately.
Results
Mirror Port Failure After 4
I was only able to get this to work on up to 4 ports. After that I received errors. See output below:
root@OPX:~# opx-config-mirror create --src_intf e101-001-0 --dest_intf e101-005-0 --direction ingress --type span
root@OPX:~# ip link set e101-009-0 up
root@OPX:~# opx-config-mirror create --src_intf e101-001-0 --dest_intf e101-009-0 --direction ingress --type span
root@OPX:~# opx-config-mirror create --src_intf e101-001-0 --dest_intf e101-002-0 --direction ingress --type span
root@OPX:~# opx-config-mirror create --src_intf e101-001-0 --dest_intf e101-003-0 --direction ingress --type span
root@OPX:~# opx-config-mirror create --src_intf e101-001-0 --dest_intf e101-004-0 --direction ingress --type span
{'data': {'base-mirror/entry/dst-intf': bytearray(b'\x0f\x00\x00\x00'), 'base-mirror/entry/type': bytearray(b'\x01\x00\x00\x00'), 'base-mirror/entry/intf': {'0': {'base-mirror/entry/intf/src': bytearray(b'\x0c\x00\x00\x00'), 'base-mirror/entry/intf/direction': bytearray(b'\x01\x00\x00\x00')}}}, 'key': '1.27.1769488.1769473.'}
opx-config-mirror: Commit failed
root@OPX:~# opx-config-mirror create --src_intf e101-001-0 --dest_intf e101-006-0 --direction ingress --type span
{'data': {'base-mirror/entry/dst-intf': bytearray(b'\x11\x00\x00\x00'), 'base-mirror/entry/type': bytearray(b'\x01\x00\x00\x00'), 'base-mirror/entry/intf': {'0': {'base-mirror/entry/intf/src': bytearray(b'\x0c\x00\x00\x00'), 'base-mirror/entry/intf/direction': bytearray(b'\x01\x00\x00\x00')}}}, 'key': '1.27.1769488.1769473.'}
opx-config-mirror: Commit failed
root@OPX:~# opx-config-mirror create --src_intf e101-001-0 --dest_intf e101-007-0 --direction ingress --type span
{'data': {'base-mirror/entry/dst-intf': bytearray(b'\x12\x00\x00\x00'), 'base-mirror/entry/type': bytearray(b'\x01\x00\x00\x00'), 'base-mirror/entry/intf': {'0': {'base-mirror/entry/intf/src': bytearray(b'\x0c\x00\x00\x00'), 'base-mirror/entry/intf/direction': bytearray(b'\x01\x00\x00\x00')}}}, 'key': '1.27.1769488.1769473.'}
opx-config-mirror: Commit failed
Pretty printed version for ease of reading:
{
'data': {
'base-mirror/entry/dst-intf': bytearray(b '\x12\x00\x00\x00'),
'base-mirror/entry/type': bytearray(b '\x01\x00\x00\x00'),
'base-mirror/entry/intf': {
'0': {
'base-mirror/entry/intf/src': bytearray(b '\x0c\x00\x00\x00'),
'base-mirror/entry/intf/direction': bytearray(b '\x01\x00\x00\x00')
}
}
},
'key': '1.27.1769488.1769473.'
}
Functioning Mirror Ports
Before I caught the error, I did test the first two mirror ports I made and they worked as expected. See the below.
I used tcpreplay with some traffic I captured on my desktop to test the idea. I
just uploaded the PCAP and replayed it with tcpreplay -i ens224 ./test_pcap.pcap --loop 500
I then confirmed that all target ports received traffic. See screenshots below:
Host 1
Host 2
The host I collected the traffic on was 192.168.1.6 and as you can see from the images both hosts were able to see traffic from the tcpreplay session.
Attempt 2 - tc
Configuration
tc
is a feature of modern Linux kernels designed for mirroring traffic. I found
this article
helpful. This Mellanox article was also
useful.
- The first thing I did was create an ingress queue on my input interface with
tc qdisc add dev e101-001-0 handle ffff: ingress
1.If you need to delete a qdisc you can do it withtc qdisc del dev e101-001-0 [ root | ingress ]
- Double check your queue with handle ffff was created with
tc -s qdisc ls dev e101-001-0
- Next we want to mirror all traffic from the ingress port to an output port with
tc filter add dev e101-001-0 parent ffff: protocol all u32 match u32 0 0 action mirred egress mirror dev e101-005-0
- Check that your port mirror appeared in the config with
tc -s -p filter ls dev e101-001-0 parent ffff:
1.If you need to delete the filters you can do so withtc filter del dev e101-001-0 parent ffff:
- Set queue to not shape traffic with
tc qdisc add dev e101-001-0 handle 1: root prio
Alternate Configuration
I tried instead running:
tc qdisc add dev e101-001-0 clsact
tc filter add dev e101-001-0 ingress matchall skip_sw action mirred egress mirror dev e101-005-0
Other Things Tried
Haven't been able to figure out why just yet, but only Layer 2 traffic is making it through the port mirror. Everything above gets dropped.
I thought maybe it was MAC address learning, but the problem persisted when I ran opx-config-global-switch --mac-age-time 0
I also thought that it was the port not being set to promiscuous mode so I gave it ifconfig e101-001-0 promisc
.
That didn't work either.
Conclusions
I'm pretty confident that because this is a network OS for switching something funky is going on. Ex: When you run a port mirror, all the traffic passes correctly, but you won't see any of that traffic on a tcpdump session. Need to study up on the architecture. I'm pretty sure there's a way to make this particular tactic work, but for time's sake I'm going to try something else.
Attempt 3 - tc on Management Interface
I realized something is going on with the forwarding tables on the switch at a low level that was intercepting our traffic in attempt 2. That said, I noticed that the management interface for the switch effectively works like a standard Linux interface. I did the same thing I did in attempt 2 except I used the managament interface instead of one of the other interfaces.
Results
The switch accepts the config. However, the traffic only goes out to one port at a time.