Wednesday 3 August 2016

ERSPAN on a Nexus 7010 (updated 2017-10-19)

We needed to determine the cause of some faults on our server network which is based on Nexus 7010 equipment.  The ERSPAN ("Encapsulated Remote Source Port ANalyzer") feature proved excellent for this for a number of reasons:
  • We didn't need to physically go to the data centre to do the monitoring.  The monitoring is directed across an IP tunnel to the capture device, which can be anywhere else on an IP network.
  • ERSPAN (and SPAN in general) on the Nexus platform has very good filtering capability so we can select just the traffic we want and monitor it on a machine with significantly less bandwidth than the capture device (in my case, my office machine monitoring 8x 10Gbit/s links looking for odd packets!).
  • Related to the above, actually just physically connecting the 10Gbit/s ports to my laptop would be challenge, ignoring whether it can keep up with the traffic on them!

Setting up ERSPAN

In the Admin VDC (regardless of which VDC traffic is to be monitored in), the following global command needs to be set to define the source IP address for the packets.  This address does not have to available to the particular VDC where the monitoring is done:

  monitor erspan origin ip-address 192.84.5.248 global


The actual mirroring can then be set up as follows:

CommandMeaning
monitor session 1 type erspan-sourceCreate an ERSPAN session number 1
  erspan-id 18ID number transmitted in the ERSPAN packet to identify this particular SPAN
  vrf defaultVRF into which ERSPAN traffic is to be transmitted to the destination (not the VRF being monitored)
  destination ip 192.0.2.1IP address of destination (collector of ERSPAN traffic)
  source interface port-channel789 bothInterface to be monitored
  filter vlan 61,62VLANs to be selected from the above interface (to monitor a whole VLAN, use 'source vlan ...' instead).  Filters can also reference access lists and other criteria.
  filter access-group FILTER-VLANACCMAPVLAN access-map to use to filter traffic (see below).
  no shutEnable the monitor

Filtering using an ACL

If you want to filter traffic matching things like source IP addresses, port numbers, etc. you can use an access-list to match it.  The Cisco documentation isn't clear on this, and contradicts how it's done, but a good reference is here.

In short, you must create an access-list, then a vlan access-map and apply that to the ERSPAN session.  For example:

  ip access-list ERSPAN-TRAFFIC-ACL4
   permit udp host 192.0.2.6 any eq 53
  !
  vlan access-map ERSPAN-TRAFFIC-VLAM 10
   match ip address ERSPAN-TRAFFIC-ACL4
  !
  monitor session 1 type erspan-source
   filter access-group ERSPAN-TRAFFIC-VLAM

Note that, despite the command "filter access-group ..." you MUST use a VLAN access-map (at least on 7.3.1 and above).

Capturing the traffic

Once enabled, the router will send the monitored traffic to the target host.  This will arrive as GRE traffic with protocol type 0x88be (ERSPAN).  Following the GRE header will be the ERSPAN header, which contains things like the VLAN ID and ERSPAN ID, then the entire L2 frame.

Wireshark recognises the packets as ERSPAN packets without any configuration, and will correctly decode them to show the encapsulated packet directly, allowing you to watch things in real time from the comfort of your desk!

Saturday 9 January 2016

VRF Source Select in NX-OS (Cisco Nexus)

We've never used IOS's VRF Source Select feature before, so I've never had to look into it.  It's useful when you have clients in multiple VRFs on a single interface and wish to select between them based on their IP address.  However, we have a use for it on our VPN service...

We offer a standard "University VPN Service" which gives all users an address from a single pool, but institutions can pay to have a "Managed VPN Service" which is limited to a subset of users of their own choice (typically the ones in their institution) and has a dedicated pool of client addresses.  The institution can then permit this range access through firewalls and into servers.  The addresses are all routed to the VPN across a single routed link in our server network.

We provide some institutions with a private internal network using MPLS L3 VPN.  However, the VPN server itself doesn't have VRFs (and we don't really want to configure and would like to be able to use the source select feature to put their pool of addresses into the VPN.

The server router is a Nexus 7010 with NX-OS 7.2(1)D1(1).  We're running 7.2 to get use MPLS Inter-AS Option B routing working, but I don't think this is needed for the source select feature.

A bit of Googling and searching Cisco's website didn't show up a VRF source select equivalent directly, but you can roll your own very simply with inter-VRF routes and some Policy Based Routing (PBR).  Cisco's website documents this but doesn't give a complete example.

The VPN server

In real life, our VPN server is a Linux box running StrongSWAN and acting as a router (with a link subnet and the client addresses routed to it over that).  However, I'm simulating it using another VDC on the same Nexus 7010.

Here's the uplink subnet (to router R1) and the default route:

interface Ethernet2/5
  description to-r1
  ip address 1.19.0.9/24

  no shutdown
!
ip route 0.0.0.0/0 Ethernet2/5 1.19.0.1

We simulate client addresses in the global and customer VRFs with a pair of loopback interfaces:

interface loopback19
  description global
  ip address 1.0.9.1/24
!
interface loopback109
  description cust
  ip address 100.0.9.1/24

Link and default VRF on the router

The upstream router has a link to the VPN server with the client address range in the default VRF routed across it:

interface Ethernet2/6
  description to-v1
  ip address 1.19.0.1/24
  no shutdown
!
ip route 1.0.9.0/24 Ethernet2/6 1.19.0.9

Clients in the the default VRF are now reachable across the network (assuming static routes are redistributed appropriately).

The VPN client address in the default VRF can now be pinged:

route-dcr-r1# ping 1.0.9.1
PING 1.0.9.1 (1.0.9.1): 56 data bytes
64 bytes from 1.0.9.1: icmp_seq=0 ttl=254 time=1.506 ms
64 bytes from 1.0.9.1: icmp_seq=1 ttl=254 time=1.36 ms
64 bytes from 1.0.9.1: icmp_seq=2 ttl=254 time=1.339 ms
64 bytes from 1.0.9.1: icmp_seq=3 ttl=254 time=1.325 ms
64 bytes from 1.0.9.1: icmp_seq=4 ttl=254 time=1.371 ms

--- 1.0.9.1 ping statistics ---
5 packets transmitted, 5 packets received, 0.00% packet loss
round-trip min/avg/max = 1.325/1.38/1.506 ms

Routing traffic out from the VRF

To route traffic from inside the VRF to the VPN server in the default VRF, an inter-VRF static route can easily be created:

vrf context cust
  ip route 100.0.9.0/24 Ethernet2/6 1.19.0.9 vrf default

... this says that 100.0.9.0/24 is to be routed via 1.19.0.9 (the VPN server) in VRF default on Ethernet2/6.

The route needs to be redistributed as per any normal route in the VRF.  In our case, this is redistributed as a static route (not as part of an aggregate), along with the direct (NX-OS parlance for "connected") route used on the link subnet:

route-map permit_rtmap permit 10
!
router bgp 1
  vrf cust
    address-family ipv4 unicast
      redistribute direct route-map permit_rtmap
      redistribute static route-map permit_rtmap

Selecting VRF based on source IP address

Before we can use Policy Based Routing (PBR), we need to enable it as a feature:

feature pbr

First, we create an access list to match the traffic to jump into a different VRF:

ip access-list vpn-cust-addrs
  10 permit ip 100.0.9.0/24 any 

Then we create a route-map to change the VRF:

route-map vpn-in_rtmap permit 10
  match ip address vpn-cust-addrs 
  set vrf cust

... the set statement changes the VRF of the received traffic: the next hop and output interface are derived by looking at the routing table in the cust VRF.

Next, we apply the policy routing to the interface linking to the VPN server:

interface Ethernet2/6
  ip policy route-map vpn-in_rtmap

A ping to the client addresses from inside the VRF now works from R1:

route-dcr-r1# ping 100.0.9.1 vrf cust
PING 100.0.9.1 (100.0.9.1): 56 data bytes
64 bytes from 100.0.9.1: icmp_seq=0 ttl=254 time=1.552 ms
64 bytes from 100.0.9.1: icmp_seq=1 ttl=254 time=1.291 ms
64 bytes from 100.0.9.1: icmp_seq=2 ttl=254 time=1.3 ms
64 bytes from 100.0.9.1: icmp_seq=3 ttl=254 time=1.444 ms
64 bytes from 100.0.9.1: icmp_seq=4 ttl=254 time=1.307 ms

--- 100.0.9.1 ping statistics ---
5 packets transmitted, 5 packets received, 0.00% packet loss
round-trip min/avg/max = 1.291/1.378/1.552 ms

Friday 1 January 2016

Overriding a video mode for a specific monitor with a Raspberry Pi

I have a Raspberry Pi I use for fiddling about.  It has an odd little 10.4" Lilliput monitor with an 800x600 native resolution and a variety of inputs, including both HDMI and DVI:

  • If I use the DVI input, it reports a DMT (Display Monitor Timings - computer monitor type) with 800x600
  • If I use the HDMI input, it reports a CEA (Consumer Electronics Association - TV type) with a preferred resolution of 1280x720

I prefer to use the HDMI input as the cable is thinner and easier to connect (especially important with something as light as the Pi).  However, when I do, the Pi picks a rather blurry 1280x720.

I can force this in /boot/config.txt with the following lines:
# set DMT mode
hdmi_group=2
# set 800x600 @ 60Hz
hdmi_mode=9
However, this is annoying if I plug the Pi into a different screen.  It is possible to force a specific mode only when a particular monitor is connected.

First, find out the display ID:
pi@mincepi ~ $ tvservice -n
device_name=LLP-32V3H-H6A
Then edit config.txt to add a section in square brackets to override it:
[EDID=LLP-32V3H-H6A]
hdmi_group=2
hdmi_mode=9 
[all]
The trailing [all] is to specify that the following lines apply to all monitor types and is just a safe thing to put in case some additional directives are applied below it.