Val:~$ whoami

I am Val Glinskiy, network engineer specializing in data center networks. TIME magazine selected me as Person of the Year in 2006.

Search This Blog

Showing posts with label Linux. Show all posts
Showing posts with label Linux. Show all posts

Tuesday, March 13, 2018

DIY routing to the host

   Cumulus Networks promotes routing to the host via Host Pack software package as a way to provide host network redundancy without using proprietary MLAG or mostly incompatible EVPN ESI multihoming solutions from switch vendors. While Host Pack seems to be geared towards hosts running Linux containers, it got me thinking how can I do routing to bare metal host. The routing protocol of choice is BGP. Now I need an IP address on the interface that never goes down and make sure that my server and client applications use that IP. That same IP will be advertised via BGP from the host. Loopback interface is obvious choice for this kind of interface.
   srv1 and srv2 are Vagrant minimal/xenial64 boxes. srv1, tor1, tor2 and tor3 run BGP, srv2 is connected to 172.16.99.0/24 network hosted on tor3. Let's configure "always-up" IP address on srv1:
sudo ip addr add 100.100.100.100/32 dev lo:100
    While binding server application like Apache to specific IP address or interface is pretty straightforward task, selecting source address for outgoing connection is a bit more complicated. Here is how Linux selects source IP address:
The application can request a particular IP [20], the kernel will use the src hint from the chosen route path [21], or, lacking this hint, the kernel will choose the first address configured on the interface which falls in the same network as the destination address or the nexthop router.
I want it to be transparent for the applications and left on its own, Linux most likely will select IP address of one of the physical interfaces. The only option left is to make sure that route to 172.16.99.0/24 on srv1 is programmed with src 100.100.100.100.
In this lab I am using BIRD 1.6 to run BGP on srv1, but Free Rang Routing will work too.

router id 100.100.100.100;

filter my_vip
{
        if net = 100.100.100.100/32 then accept;
        reject;
}
filter remote_site
{
        if net ~ [ 172.16.99.0/24 ] then
        {
           krt_prefsrc = 100.100.100.100; #set src
           accept;
        }
        reject;
}

protocol kernel {
        scan time 60;
        import none;
        export filter remote_site;
        persist;     # routes stay even if bird is down
        merge paths on;  # ECMP
}

protocol device {
        scan time 60;
}

protocol direct {
        interface "enp0s[8|9]", "lo*";
}
protocol bgp host_2rtr1 {
        local as 65499;
        neighbor 192.168.11.3 as 64900;
        export filter my_vip;
        import filter remote_site;
}
protocol bgp host_2rtr2 {
        local as 65499;
        neighbor 192.168.22.3 as 64920;
        export filter my_vip;
        import filter remote_site;
}

Let's see BGP routes we get from tor1 and tor2:
bird> show route 172.16.99.0/24
172.16.99.0/24     via 192.168.11.3 on enp0s8 [host_2rtr1 16:15:49] * (100) [AS65000i]
                   via 192.168.22.3 on enp0s9 [host_2rtr2 16:15:49] (100) [AS65000i]

Only one route is marked as primary, I could not find "bestpath as-path multipath-relax" equivalent in BIRD. It's required because tor1 and tor2 have different AS numbers. But no worries, "merge path on" under "protocol kernel" will take care of this. Indeed:
vagrant@srv1:~$ ip route show 172.16.99.0/24         
172.16.99.0/24  proto bird  src 100.100.100.100       
        nexthop via 192.168.11.3  dev enp0s8 weight 1 
        nexthop via 192.168.22.3  dev enp0s9 weight 1
both routes are installed and claim to use 100.100.100.100 as a source IP address to reach srv2 network.
Let's verify. I start pinging srv2 from srv1 and run tcpdump on srv2 side.



vagrant@srv1:~$ ping 172.16.99.200
Here is tcpdump output on srv2:
02:22:09.753864 IP 100.100.100.100 > 172.16.99.200: ICMP echo request, id 5024, seq 1, length 64
02:22:09.753906 IP 172.16.99.200 > 100.100.100.100: ICMP echo reply, id 5024, seq 1, length 64
02:22:10.750884 IP 100.100.100.100 > 172.16.99.200: ICMP echo request, id 5024, seq 2, length 64
02:22:10.750920 IP 172.16.99.200 > 100.100.100.100: ICMP echo reply, id 5024, seq 2, length 64


As you can see, packets are coming from 100.100.100.100, even though I did not specify source IP address for the ping.
Similar test with ssh
vagrant@srv1:~$ ssh 172.16.99.200

02:31:37.652419 IP 100.100.100.100.54634 > 172.16.99.200.ssh: Flags [S], seq 3479345726, win 29200, options [mss 1460,sackOK,TS val 2387063 ecr 0,nop,wscale 7], length 0
02:31:37.652473 IP 172.16.99.200.ssh > 100.100.100.100.54634: Flags [S.], seq 2929355359, ack 3479345727, win 28960, options [mss 1460,sackOK,TS val 2404414 ecr 2387063,nop,wscale 7], length 0
02:31:37.665081 IP 100.100.100.100.54634 > 172.16.99.200.ssh: Flags [.], ack 1, win 229, options [nop,nop,TS val 2387066 ecr 2404414], length 0
02:31:37.666605 IP 100.100.100.100.54634 > 172.16.99.200.ssh: Flags [P.], seq 1:42, ack 1, win 229, options [nop,nop,TS val 2387066 ecr 2404414], length 41
02:31:37.666621 IP 172.16.99.200.ssh > 100.100.100.100.54634: Flags [.], ack 42, win 227, options [nop,nop,TS val 2404418 ecr 2387066], length 0




And last test - failover. Since my lab setup is entirely virtual, the goal was to test if failover works at all and not how fast it does. You need real hardware to check the speed of failover.

vagrant@srv1:~$ iperf -s -B 100.100.100.100

vagrant@srv2:~$ iperf  -M 1000 -b 80K -i 1 -c 100.100.100.100 -t 120

In my case traffic took srv2 -> tor3 -> tor1 -> srv1 path. While iperf was running, I shutdown BGP session between tor1 and srv1. Here are the results from iperf:
[  3] 46.0-47.0 sec   384 KBytes  3.15 Mbits/sec
[  3] 47.0-48.0 sec   512 KBytes  4.19 Mbits/sec
[  3] 48.0-49.0 sec   384 KBytes  3.15 Mbits/sec
[  3] 49.0-50.0 sec  0.00 Bytes  0.00 bits/sec
[  3] 50.0-51.0 sec  0.00 Bytes  0.00 bits/sec
[  3] 51.0-52.0 sec  0.00 Bytes  0.00 bits/sec
[  3] 52.0-53.0 sec   256 KBytes  2.10 Mbits/sec
[  3] 53.0-54.0 sec   512 KBytes  4.19 Mbits/sec


That 3-second interval of 0.00bits/sec is failover time. Again, since it's virtual environment, your mileage may vary.

Monday, March 22, 2010

Debian 5.0.4 on Dell 1950

Normally, installing Debian on Dell servers is piece of cake. This particular 1950 came with Broadcom NICs and PERC5 controller. Debian 5.0.4 does not include driver for Broadcom drivers due to some copyright restrictions. However, the driver is available as deb package. Download it and copy to FAT or FAT32 formatted USB drive. When prompted for NIC driver during the installation process, insert USB drive into USB port. As soon as server loads the driver and moves to the next screen in installation process, remove the drive. If you do not remove the USB drive before installation process gets to partitioning, your drive sequence will we out of whack. You'll have to boot from CD and edit /etc/fstab.
Since this server has hardware I wanted to use instead of configuring software RAID in Linux. The question is how to monitor RAID state from Debian. There is no deb package or source code, but LSI provides RPM. I downloaded "MegaCLI - Linux" from "Miscellaneous" section, unpacked it, installed "alien" on Debian (sudo apt-get install aliean) and then "sudo alien -i  MegaCli-1.01-0.i386.rpm". It install MegaCli under /opt/MegaRAID/MegaCli.  Moritz Mertinkat has great emergency cheat sheet for MegaCli usage.

Wednesday, October 14, 2009

How to generate lots of BGP routes

I needed to test in the lab whether my Cisco router can handle more than 300K routes - size of current full BGP table. Now, Cisco router can only accept 200 network statements under router bgp configuration, so I would need 1500 routers. Even if I had that many routers to my disposal, it would have taken days to configure all of them. As always, open source software can help. Quagga lets you run OSPF, BGP, RIP, RIPng on Linux and Solaris. If you go with all default options, it is very easy to install. Download and unpack. Go to quagga directory, in my case it was quagga-0.98.6, type
./configure
make
sudo make install
That's it. By default, it went into /usr/local/. I have Debian 4 (Etch) with 2.6.8 kernel and a lot of development packages installed. The only thing I had to do was to add /usr/local/lib to /etc/ld.so.conf file and run /sbin/ldconfig.
Here is the setup


Now I need a valid configuration file for Quagga BGP. Adding 300000 network statements manually is not something system administrators do on Linux. Hence, here is the script
#!/usr/bin/perl

my $host="quagga-host";         #quagga router name
my $logpass="zebra";            #login password
my $enable="zebra";             #enable password
my $myasn="65099";              #local AS number
my $router_id="172.31.2.2";     #bgp router-id
my $remote_as="65001";          #remote-as number
my $remote_ip="172.31.2.1";     #BGP neighbor ip address
my $route_count=0;
my $max_routes=300000;              #max number of routers to generate

open (BGPCONF,'>bgpd.conf')|| die "Can not open bgpd.conf for writing";
print BGPCONF "hostname $host\npassword $logpass\nenable password $enable\nline vty \n";
print BGPCONF "router bgp $myasn\n  bgp router-id $router_id\n  neighbor $remote_ip remote-as $remote_as\n";
MAXR: while ($route_count <= $max_routes ) { 
$octet1=int(rand(223))+1; #generate 1st octet randomly in 1-223 range, 224 and up is multicust and class E  
if ($octet1 ==127) {next;} #need to make sure that 127.X.X.0/24 is excluded 
$octet2=0;  
while ( $octet2 <= 255 ){
$octet3=0;
while ( $octet3 <= 255 ) {
print BGPCONF "  network $octet1\.$octet2\.$octet3\.0/24\n";
$octet3++;
$route_count++;
if ($route_count == $max_routes) {last MAXR;}
}
$octet2++;
}
}
close BGPCONF;
this script will generate bgpd.conf for Quagga. Since it is lab environment not connected to any real network, I do not really care about zebra configuration or restricting access to Quagga BGP console. Copy bgpd.conf file into /usr/local/etc and run /usr/local/sbin/bgpd -d -f /usr/local/etc/bgpd.conf -u root -g root Again, this is not production environment. Do not run Quagga as root in production. Here is relevant configuration from Cisco router:
interface GigabitEthernet0/0
ip address 172.31.2.1 255.255.255.0
network 172.31.2.0 mask 255.255.255.0
media-type rj45
negotiation auto
!
router bgp 65001
no synchronization
bgp log-neighbor-changes
neighbor 172.31.2.2 remote-as 65099
no auto-summary
!
Let's see if it works. On Linux host:
sh-2.05b$ telnet localhost 2605
Trying 127.0.0.1...
Connected to localhost.localdomain.
Escape character is '^]'.

Hello, this is Quagga (version 0.98.6).
Copyright 1996-2005 Kunihiro Ishiguro, et al.


User Access Verification

Password:
quagga-host> sho ip bgp summ
BGP router identifier 172.31.2.2, local AS number 65099
2 BGP AS-PATH entries
0 BGP community entries

Neighbor        V    AS MsgRcvd MsgSent   TblVer  InQ OutQ Up/Down  State/PfxRcd
172.31.2.1      4 65001     283     606        0    0    0 03:41:55        1

Total number of neighbors 1
quagga-host>
on Cisco:
R1#sho ip bgp sum
BGP router identifier 192.0.2.2, local AS number 65001
BGP table version is 330002, main routing table version 330002
310001 network entries using 40920132 bytes of memory
310001 path entries using 16120052 bytes of memory
3/2 BGP path/bestpath attribute entries using 444 bytes of memory
1 BGP AS-PATH entries using 24 bytes of memory
0 BGP route-map cache entries using 0 bytes of memory
0 BGP filter-list cache entries using 0 bytes of memory
Bitfield cache entries: current 1 (at peak 2) using 32 bytes of memory
BGP using 57040684 total bytes of memory
BGP activity 310001/0 prefixes, 320001/10000 paths, scan interval 60 secs

Neighbor        V    AS MsgRcvd MsgSent   TblVer  InQ OutQ Up/Down  State/PfxRcd
172.31.2.2      4 65099     602     322   330002    0    0 03:38:59   310000
Yep. It works.

Wednesday, February 04, 2009

Packetization Layer Path MTU Discovery

A lot of network administrators block all ICMP traffic on the network's edge. Although some ICMP packets can be used in DDoS, ICMP type 3 plays important role in Paht MTU discovery. If ICMP is completely blocked, sending side can not reliably determine MTU and that can lead to re-transmissions and slower data transfer. Sometimes, ICMP blocking network could be outside your control, so you can not change ACL or firewall rules. In this case Packetization Layer Path MTU Discovery can be used. It utilizes TCP for maximum packet size discovery (RFC4821). To enable PLPMTUD on Linux:
echo 2 > /proc/sys/net/ipv4/tcp_mtu_probing
or
in /etc/sysctl.conf net.ipv4.tcp_mtu_probing = 2