MACsec is an interesting alternative to existing tunneling solutions, that protects Layer 2 by performing integrity, origin authentication and, optionally, encryption. Normal use-case is to use MACsec between hosts and access switches, between two hosts or between two switches. This article is a leftover from MACsec on Linux that I first tested in 2016 when support for MACsec was just included in the kernel. I will describe how MACsec is used together with a Layer 2 GRE tunnel to protect the traffic between two remote sites, over WAN or Internet, like a site-to-site VPN at Layer 2.
Scenario Overview
Today, I am not going to present MACsec - you can read my previous post about MACsec implementation on Linux. Instead, this post presents a Layer 2 site-to-site VPN scenario using two Linux machines that perform MACsec inside a GRETAP tunnel - GRETAP is a Layer 2 tunnel. Here is a diagram with some high level notes:
- there are two remote sites, Site 1 and Site 2, connected over a private WAN or over the Internet
- both sites use same IP address space
- a Layer 2 Tunnel is connecting the sites - in our demo, we are using a GRETAP tunnel, but any other L2 tunneling protocols could also be used
For demo purposes, I am using network namespaces (netns
) and virtual ethernet interfaces (veth
) to simulate the entire scenario on a single Linux machine. Let's jump right into it (assuming your machine is a Linux box), clone my github repository and run the demo-setup-MACsecOverWAN.sh
bash script, as indicated below:
# preparation mkdir macsec-demo && cd macsec-demo# clone my demo repository from github git clone https://github.com/costiser/macsec-over-wan.git# run the setup script with "sudo" cd macsec-over-wansudo ./demo-setup-MACsecOverWAN.sh
MACsec over WAN Implementation
Demo Overview
NOTES
|
All commands in this demo must be executed with |
Running the sudo setup-MACsecOverWAN-layer2.sh
bash script will do the following:
- creates two network namespaces, host1 and host2, representing two host devices
- creates two network namespaces, nsra and nsrb, representing Linux Routers that are the tunnel endpoints
- creates a network namespace, wan, for the WAN or Internet cloud
Test the connectivity between the two hosts with ICMP pings - use ip netns exec <namespace> <command>
to execute commands inside the network namespaces:
sudo ip netns exec host1 ping 192.168.1.2 PING 192.168.1.2 (192.168.1.2) 56(84) bytes of data. 64 bytes from 192.168.1.2: icmp_seq=1 ttl=64 time=0.204 ms 64 bytes from 192.168.1.2: icmp_seq=2 ttl=64 time=0.129 ms 64 bytes from 192.168.1.2: icmp_seq=3 ttl=64 time=0.123 ms 64 bytes from 192.168.1.2: icmp_seq=4 ttl=64 time=0.120 ms ...
While ping is running, capture the traffic in the wan namespace in order to confirm the MACsec and GRETAP overlay:
sudo ip netns exec wan tcpdump -neli wan1 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on wan1, link-type EN10MB (Ethernet), capture size 262144 bytes 21:21:55.81476500:aa:aa:aa:aa:aa > 00:aa:aa:1f:1f:1f , ethertype IPv4 (0x0800), length 168:1.1.1.1 > 2.2.2.2: GREv0, proto TEB (0x6558) , length 134:00:00:00:00:00:01 > 00:00:00:00:00:02, ethertype Unknown (0x88e5) , length 130: 0x0000: 2c00 0000 0019 0000 0011 1111 0001 aafd ,............... 0x0010: 7858 40ec c447 2ab3 1463 6205 272b 85ef [email protected]*..cb.'+.. 0x0020: 6a7b 7419 c3ec 4300 d0ab 9922 797a cf72 j{t...C...."yz.r 0x0030: 33ec 07fe 6b6b 3095 0e63 5743 06b7 813b 3...kk0..cWC...; 0x0040: 5501 7c3c 529f 72ec 668d 24d4 c443 e9f9 U.|..e.}. 0x0070: 0bab fae3 .... 21:21:55.814832 00:aa:aa:1f:1f:1f > 00:aa:aa:aa:aa:aa , ethertype IPv4 (0x0800), length 168:2.2.2.2 > 1.1.1.1: GREv0, proto TEB (0x6558) , length 134:00:00:00:00:00:02 > 00:00:00:00:00:01, ethertype Unknown (0x88e5) , length 130: 0x0000: 2c00 0000 001a 0000 0022 2222 0001 1bd5 ,........""".... 0x0010: 10f4 a646 7057 7acb 690b 1841 b35d 606a ...FpWz.i..A.]`j 0x0020: 93f9 f78c 95fb 424f e92e 9828 7953 d99b ......BO...(yS.. 0x0030: e710 1a52 3218 4ed2 0854 e8aa 339b 4129 ...R2.N..T..3.A) 0x0040: 07d0 cce5 ff29 b398 ded1 8549 b83c d094 .....).....I.<.. 0x0050: 1480 434f ca8b 17e4 e5bd 9fcc 5d33 617a ..CO........]3az 0x0060: 9651 3e68 1a0b 4db1 dcc8 3444 8d2e 0579 .Q>h..M...4D...y 0x0070: 2392 8953 #..S
NOTES
|
The first EtherType in the output of the tcpdump is Transparent Ethernet bridging , meaning the GRETAP.The MAC security (IEEE 802.1AE) .
|
Solution Explained
In order to explain how all pieces come together, let's look at the nsra
and nsrb
Linux routers that provide IP routing connectivity between the sites. Since MACsec operates at Layer 2, we need to build a Layer 2 tunnel between the sites. For that, we use GRETAP but any other Layer 2 Tunneling protocol can be used instead.
Note that I am setting some easy-to-read MAC addresses on most of the interfaces.
# on site1's Linux router ( ip netns exec nsransra )ip link add gretap1 type gretap local 1.1.1.1 remote 2.2.2.2 ip netns exec nsraip link set gretap1 address 00:00:00:11:11:11 ip netns exec nsraip link set gretap1 up # on site2's Linux router ( ip netns exec nsrbnsrb )ip link add gretap1 type gretap local 2.2.2.2 remote 1.1.1.1 ip netns exec nsrbip link set gretap1 address 00:00:00:22:22:22 ip netns exec nsrbip link set gretap1 up
Now, we build the MACsec tunnel inside the GRETAP interface. The MACsec endpoint addresses are the ones of the parent gretap1
interface.
# on site1's Linux router ( ip netns exec nsransra )ip link add link gretap1 macsec1 type macsec encrypt on ip netns exec nsraip macsec add macsec1 tx sa 0 pn 1 on key 01 11111111111111111111111111111111 ip netns exec nsraip macsec add macsec1 rx address 00:00:00:22:22:22 port 1 ip netns exec nsraip macsec add macsec1 rx address 00:00:00:22:22:22 port 1 sa 0 pn 1 on key 02 22222222222222222222222222222222 ip netns exec nsraip link set macsec1 up # on site2's Linux router ( ip netns exec nsrbnsrb )ip link add link gretap1 macsec1 type macsec encrypt on ip netns exec nsrbip macsec add macsec1 tx sa 0 pn 1 on key 02 22222222222222222222222222222222 ip netns exec nsrbip macsec add macsec1 rx address 00:00:00:11:11:11 port 1 ip netns exec nsrbip macsec add macsec1 rx address 00:00:00:11:11:11 port 1 sa 0 pn 1 on key 01 11111111111111111111111111111111 ip netns exec nsrbip link set macsec1 up
Last piece of the puzzle is to "force" traffic into the macsec1
interface. For that, I'm using a simple Linux bridge, br0
, on each of the Linux routers that "bridges" the macsec1
interface with the internal LAN interface of the site.
Note that you could achieve the same also with an Open vSwitch (OVS) switch.
# on site1's Linux router ( ip netns exec nsransra )ip link add br0 type bridge ip netns exec nsraip link set veth11 master br0 ip netns exec nsraip link set macsec1 master br0 ip netns exec nsraip link set br0 up # on site2's Linux router ( ip netns exec nsrbnsrb )ip link add br0 type bridge ip netns exec nsrbip link set veth22 master br0 ip netns exec nsrbip link set macsec1 master br0 ip netns exec nsrbip link set br0 up
Packet Analysis
Let's have a quick look the traffic protected by MACsec. Perform a tcpdump
packet capture in the wan
network namespace, as if someone in the Internet is sniffing the traffic. Save the capture in a file named macsec.pcap
:
sudo ip netns exec wan tcpdump -i wan1 -w macsec.pcap
Generate some traffic from host1
. Note that I am also clearing the ARP cache since I want to capture also the broadcast ARP Requests:
# clear ARP cache for host2 sudo ip netns exec host1 arp -d 192.168.1.2# generate some traffic sudo ip netns exec host1 ping 192.168.1.2 PING 192.168.1.2 (192.168.1.2) 56(84) bytes of data. 64 bytes from 192.168.1.2: icmp_seq=1 ttl=64 time=0.300 ms 64 bytes from 192.168.1.2: icmp_seq=2 ttl=64 time=0.173 ms 64 bytes from 192.168.1.2: icmp_seq=3 ttl=64 time=0.136 ms ^C --- 192.168.1.2 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 31ms rtt min/avg/max/mdev = 0.136/0.203/0.300/0.070 ms# check the ARP cache sudo ip netns exec host1 arp -an ? (192.168.1.2) at 00:00:00:00:00:02 [ether] on veth1
Opening the macsec.pcap
with Wireshark would show multiple MACsec packets carrying both ARP and ICMP data. MACsec protects all Layer 2 traffic, including broadcasts. Some of the important things to note are included in the diagram below:
Taken the ARP Request broadcast frame as an example, we can see that MACsec inserts a Security Tag (16 Bytes) between the original Ethernet header and the Data, then appends an Integrity Check Value / ICV (16 Bytes) at the end:
MTU
Everytime tunneling is involved, you
- Original ETH: 14 bytes (since this is now transparently bridged over WAN)
- MACsec: 32 bytes
- GRETAP: 4 bytes
- IP: 20 bytes
- TOTAL: 70 bytes overhead
MTU : 1500 - 70 =1430
We can easily confirm the Path MTU by sending ICMP with DF-bit set from the testing host1
namespace. If the calculation is correct, then the maximum ICMP packet that we can send is: 1430 - 20 (IP header) - 8 (ICMP header) = 1402. Anything bigger than 1402 would be dropped:
# WORKING: Max size of ICMP packets: 1430(MTU)-8(ICMP)-20(IP)=1402 sudo ip netns exec host1 ping -M do -c2 192.168.1.2 -s 1402 PING 192.168.1.2 (192.168.1.2) 1402(1430 ) bytes of data. 1410 bytes from 192.168.1.2: icmp_seq=1 ttl=64 time=0.144 ms 1410 bytes from 192.168.1.2: icmp_seq=2 ttl=64 time=0.149 ms --- 192.168.1.2 ping statistics --- 2 packets transmitted, 2 received,0% packet loss , time 19ms rtt min/avg/max/mdev = 0.144/0.146/0.149/0.012 ms# NOT WORKING: size 1403 sudo ip netns exec host1 ping -M do -c2 192.168.1.2 -s 1403 PING 192.168.1.2 (192.168.1.2) 1403(1431 ) bytes of data. --- 192.168.1.2 ping statistics --- 2 packets transmitted, 0 received,100% packet loss , time 2ms
Of course, instead of decreasing the MTU on the clients side, another option would be to increase it on the WAN path. This would be possible if the WAN is a network under your control, but it would be impossible if you use the Internet.
Performance
It is well known that encryption drastically decreases the network throughput. MACsec is no exception to that. Vendors providing MACsec capabilities claim line-rate performance for it. In Linux, there are efforts to offload MACsec onto NICs, but as far as I know, such work is still in progress.
In my demo, I wanted to see how much does the network performance decreases when uses MACsec. For that, I first wanted to get a baseline when the two hosts are connected via WAN with plain GRE without any MACsec involved. I have another bash script that creates the plain GRE setup and then I'm running iperf, with default options, between the host clients.
# create the demo with plain GRE sudo ./demo-setup-GREplain.sh# start iperf server on host2 sudo ip netns exec host2 iperf -s# start iperf client on host1 # subsequent commands with "P" option tells iperf to use multiple parallel client threads sudo ip netns exec host1 iperf -c 192.168.1.2 sudo ip netns exec host1 iperf -c 192.168.1.2 -P 3 sudo ip netns exec host1 iperf -c 192.168.1.2 -P 5 sudo ip netns exec host1 iperf -c 192.168.1.2 -P 7
The reported baseline performance in my case was close to 27 Gbps for a single thread and up to 100 Gbps for -P 7
(seven client threads):
# output snippets from the iperf server [ ID] Interval Transfer Bandwidth [ 4] 0.0-10.0 sec 32.1 GBytes 27.6 Gbits/sec ... [SUM] 0.0-10.0 sec 81.2 GBytes 69.7 Gbits/sec ... [SUM] 0.0-10.0 sec 108 GBytes 92.5 Gbits/sec ... [SUM] 0.0-10.0 sec 117 GBytes 100 Gbits/sec
Now cleanup this plain GRE demo with sudo ./demo-cleanup-GREplain.sh
.
Then we start again the MACsec setup demo, we manually configure the proper MTU on clients (that is not part of the demo script), then perform the same iperf tests:
# create the demo with MACsec over GRETAP sudo ./demo-setup-MACsecOverWAN.sh# configure proper MTU on clients sudo ip netns exec host1 ip link set veth1 mtu 1430 sudo ip netns exec host2 ip link set veth2 mtu 1430 # start iperf server on host2 sudo ip netns exec host2 iperf -s# start iperf client on host1 # subsequent commands with "P" option tells iperf to use multiple parallel client threads sudo ip netns exec host1 iperf -c 192.168.1.2 sudo ip netns exec host1 iperf -c 192.168.1.2 -P 3 sudo ip netns exec host1 iperf -c 192.168.1.2 -P 5 sudo ip netns exec host1 iperf -c 192.168.1.2 -P 7
The results, in my case, were 2 Gbps for a single client thread and up to 3.5 Gbps for seven threads (-P 7
). Below is a snippet from the iperf -s
output:
# output snippets from the iperf server with MACsec over GRETAP [ ID] Interval Transfer Bandwidth [ 4] 0.0-10.0 sec 2.41 GBytes 2.07 Gbits/sec ... [SUM] 0.0-10.0 sec 3.01 GBytes 2.58 Gbits/sec ... [SUM] 0.0-10.0 sec 3.79 GBytes 3.25 Gbits/sec ... [SUM] 0.0-10.0 sec 4.17 GBytes 3.57 Gbits/sec
NOTES
|
Since everything runs in a single machine, simulated with network namespaces and veth interfaces, the iperf performance depends on how busy and how powerful your Linux machine is. |
You could try to tweak the Linux network stack as described in another post, but I did not spend any time on that.
To clear the entire setup, use sudo ./demo-cleanup-MACsecOverWAN.sh
script. This concludes an article that I'm happy to have done with a delay of three years from my original MACsec on Linux post.
As always, thank you for your interest and looking forward to your comments!
Comments
comments powered by Disqus