Showing posts with label junos. Show all posts
Showing posts with label junos. Show all posts

Sunday, June 2, 2013

Brocade and Juniper Interop - OSPF, MPLS, VLL/VPLS, and VRF interconnects

From the start

We run a mix of Brocade MLX and Juniper MX80's at work, and I've spent the last week trying to make them talk to each other properly. You'd think that by 2013, a multi-vendor network would work fine using standardised protocols, but it's still quite time consuming finding which ways work and which ways most certainly don't. Oddly enough, I'm not the only person who's been working on this recently - Nick Buraglio has done a bit in the last couple of weeks too (thanks for the help on this)

As SDN starts to take over, this will become much less of a problem, but until then, here's how to do the following with Juniper MX-series routers and Brocade MLX/XMR chassis:
  • Jumbo frames
  • OSPF
  • MPLS
  • VPLS
  • VLL/l2circuit
  • Tagging VPLS/VLL/l2circuit into a VRF on Juniper
Disclaimer - the MX80 chassis has lots of stuff built in, including a tunnel services PIC - we need this for some of the stuff below, not sure how it works with bigger chassis.

Jumbo frames

This should be easy, but there's a couple of things that will trip you up if you aren't careful. The maximum frame size you can have on the Brocades is 9216 bytes, and on the Junipers it's 9192 bytes. I tried to set the frame size on the Brocades down to 9192 bytes and found a weird quirk - I could send 9146 byte pings from the Juniper, but the Brocade would only respond to 9142 byte pings - it appears the Brocades include the FCS in their count of frame size.

In the end, the best solution was to just leave both routers at their maximum values, set VPLS/VLL MTUs to 9100 bytes (or some number with a bit of headroom over 9000), and IP MTUs to 9000 (except for OSPF interfaces, but we'll get to that soon).

The main thing to remember is that on the Junipers, you can set MTU on the physical interface, or inside a "family XXX" stanza, but not directly on a logical interface. If you want to set the IP MTU for a logical interface, it sits in "interface XXX -> unit Y -> family inet -> mtu 9000"

OSPF

You *can* stand up OSPF with Jumbo frames, but it's fine with 1500 byte frames. We're in the position of introducing Junipers into our Brocade OSPF cloud, and since the defaults for Brocade are already 1500 bytes, it's easier to step the Junipers down than bring the Brocades up. I've set up the Brocade-facing interface like this:

interfaces {
    ge-1/0/0 {
        vlan-tagging;
        mtu 9192;
        unit 1000 {
            vlan-id 1000;
            family inet {
                mtu 1500
                address 10.1.2.1/30;
            }
            family mpls;
        }
    }
}

The Brocade end looks like this:

interface ve 100
 bfd interval 100 min-rx 100 multiplier 3
 ip ospf area 0
 ip ospf cost 100
 ip ospf dead-interval 40
 ip ospf hello-interval 10
 ip address 10.2.3.2/30
 ip mtu 1500
!

The only tricky bit is making sure the IP MTU is the same for each end - if you get a huge route update going into an interface that can't take the whole packet then you'll end up blackholing routes. Junipers are supposed to not stand up OSPF when there's an IP MTU mismatch, but it doesn't always work - it pays to test with ping packets to confirm - you should be able to ping in either direction with a 1472 bytes of data (1500 - 20 byte IP header - 8 byte ICMP header).

MPLS

This is pretty straightforward - set up loopback interfaces on each end, and enable RSVP and LDP. We'll use RSVP for the outer tags, and LDP for the inner tags - no clever BGP signalling here.

Juniper:

protocols {
    rsvp {
        interface all {
            disable;
        }
        interface ge-1/0/0.1000;
        interface lo0.0;
    }
    mpls {                              
        label-switched-path 1-to-2 {
            from 10.0.0.1;
            to 10.0.0.2;
            fast-reroute;
        }
        label-switched-path 1-to-3 {
            from 10.0.0.1;
            to 10.0.0.3;
            fast-reroute;
        }
        interface all {
            disable;
        }
        interface ge-1/0/0.1000;
    }
    ospf {
        traffic-engineering;
        area 0.0.0.0 {
            interface all {
                disable;
            }
            interface ge-1/0/0.1000 {
                hello-interval 3;       
                dead-interval 12;
                bfd-liveness-detection {
                    minimum-interval 300;
                    multiplier 3;
                }
            }
            interface lo0.0 {
                passive;
            }
        }
    }
    ldp {
        interface all {
            disable;
        }
        interface lo0.0;
    }
}

Brocade:

router mpls
 policy
  traffic-eng ospf


 mpls-interface ve100


 path 3-to-1
  loose 10.0.0.1                                                  

 path 3-to-2
  loose 10.0.0.2

 path S3-to-1
  loose 10.0.0.1

 path S3-to-2
  loose 10.0.0.2


 lsp LSP-3-to-1
  to 10.0.0.1
  primary 3-to-1
  secondary S3-to-1
    standby
  frr
  revert-timer 30
  enable

 lsp LSP-3-to-2
  to 10.0.0.2
  primary 3-to-2                                                  
  secondary S3-to-2
    standby
  frr
  revert-timer 30
  enable

VPLS

This is where it gets interesting. In my opinion, Brocade does the right thing (packets come out of a VLAN-tagged "pipe", and then go into a VPLS "pipe"), whereas Juniper does it at a lower and less-abstract level (packets with headers that get altered) - it's more flexible, but it's harder to make it do the right thing.

Raw mode, tagged mode, and tags inside raw mode

VPLS has two modes - Raw mode creates a broadcast domain between all peers on the same VPLS, whereas tagged mode allows you to use inner tags within a VPLS circuit. The problem comes where Juniper sends 802.1q VLAN-tagged packets through a raw-mode VPLS. You end up left with a situation where traffic can go one way, but not the other, and it's all quite confusing.

Raw mode interop

Check out these configs:

On Juniper, we make a routing instance, and add interfaces into it. They can be VLAN-tagged or normal access ports, and there's a very important trick to make it all use raw mode properly - the line "vlan-id none". If you don't do this, packets on an untagged port go through fine, but packets from tagged ports come through with 802.1q VLAN tags on them. On Brocade, a VPLS get delivered to a mix of tagged and untagged ports, but all traffic is sent as normal untagged ethernet. The "vlan-id none" line makes the Junipers behave in the same way. The config below delivers VPLS 40 untagged at both ends, and VPLS 140 tagged as VLAN 140.

Don't worry too much about the MTUs - they need to match up, but they don't appear to be enforced. We picked 9100 as it's well under the 9192 byte hardware MTU, but well above the 9000 byte IP MTU - a bit of leeway in each direction.

Juniper:

routing-instances {
    vpls-40 {
        description vpls-40;
        instance-type vpls;
        vlan-id none;
        interface ge-1/1/9.40;           
        protocols {
            vpls {
                no-tunnel-services;
                vpls-id 40;
                mtu 9100;
                neighbor 10.0.0.2;
                neighbor 10.0.0.3;
            }
        }
    }
    vpls-140 {
        description vpls-140;
        instance-type vpls;
        vlan-id none;
        interface ge-1/1/9.140;           
        protocols {
            vpls {
                no-tunnel-services;
                vpls-id 140;
                mtu 9100;
                neighbor 10.0.0.2;
                neighbor 10.0.0.3;
            }
        }
    }
}
interfaces {
    ge-1/1/9 {
        flexible-vlan-tagging;
        native-vlan-id 40;
        mtu 9192;
        encapsulation flexible-ethernet-services;
        unit 40 {
            encapsulation vlan-vpls;
            vlan-id 40;
            family vpls;
        }
        unit 140 {
            encapsulation vlan-vpls;
            vlan-id 140;
            family vpls;
        }
    }
}

Brocade:

router mpls
 vpls vlan40 40 
  vpls-peer 10.0.0.1 10.0.0.2
  vpls-mtu 9100
  vlan 40
   untagged ethe 1/5 


 vpls vlan40 40 
  vpls-peer 10.0.0.1 10.0.0.2
  vpls-mtu 9100
  vlan 140
   tagged ethe 1/5 

If you're interested in the mechanics behind the Juniper implementation, the "show interface" command gives you a bit of insight - Juniper interprets the "vlan-id none" line in the routing instance and converts that to tag push/pop operations on the interface:

  Logical interface ge-1/1/9.40 (Index 332) (SNMP ifIndex 564) 
    Flags: SNMP-Traps 0x0
    VLAN-Tag [ 0x8100.40 ] Native-vlan-id: 40 In(pop) Out(push 0x8100.40) 
    Encapsulation: VLAN-VPLS
    Input packets : 9 
    Output packets: 7
    Protocol vpls, MTU: 9192            
      Flags: Is-Primary

  Logical interface ge-1/1/9.140 (Index 333) (SNMP ifIndex 597) 
    Flags: SNMP-Traps 0x0 VLAN-Tag [ 0x8100.140 ] In(pop) Out(push 0x8100.140) 
    Encapsulation: VLAN-VPLS
    Input packets : 149 
    Output packets: 92
    Protocol vpls, MTU: 9192
      Flags: Is-Primary

VLL/l2circuit

This is the fun one. Tagged-mode VLLs are the easiest to get up and running, but raw-mode should be doable too. There is one problem though - the only way I can make raw-mode work on the Junipers looks like a filthy hack, but it produces the same results that we see above in the "show interface" output for VPLS.

First off, configs for tagged mode

Brocade:

router mpls
 vll vlan42 42
  vll-mtu 9100
  vll-peer 10.0.0.1
  vlan 42
   tagged e 1/5

Juniper:

interfaces {
    ge-1/1/9 {
        flexible-vlan-tagging;
        mtu 9192;
        encapsulation flexible-ethernet-services;
        unit 42 {
            encapsulation vlan-ccc;
            vlan-id 42;                     
            family ccc;
        }
    }
}

protocols {
    l2circuit {
        neighbor 10.0.0.3 {
            interface ge-1/1/9.42 {
                virtual-circuit-id 42;
                mtu 9100;
                encapsulation-type ethernet-vlan;
            }
        }
    }
}

This is all pretty straightforward, and works out of the box. Here's what the raw mode config looks like

Brocade:

router mpls
 vll vlan41 41 raw-mode
  vll-mtu 9100
  vll-peer 10.0.0.1
  vlan 41                                                         
   tagged e 1/5

Juniper:

interfaces {
    ge-1/1/9 {
        flexible-vlan-tagging;
        mtu 9192;
        encapsulation flexible-ethernet-services;
        unit 41 {
            encapsulation vlan-ccc;
            vlan-id 41;
            input-vlan-map pop;
            output-vlan-map push;
            family ccc;
        }
    }
}
protocols {
    l2circuit {
        neighbor 10.0.0.3 {
            interface ge-1/1/9.41 {
                virtual-circuit-id 41;
                mtu 9100;
                encapsulation-type ethernet;
            }
        }
    }
}

As you can see, the default for Brocade is tagged mode, so we need to explicitly put it in raw mode. On the Juniper end, we set the encapsulation type on the VLL to ethernet instead of ethernet-vlan, but this only works with encapsulation ethernet-ccc on the physical interface. If we have VLAN tagging mode enabled, there doesn't seem to be any way to tell the MX80 about this. The way I've made this work is with the "input-vlan-map" and "output-vlan-map" statements - they seem to round everything out and make it all work. Given the default for both Juniper and Brocade is tagged mode, and we need a bit of mad hax to make raw mod work here, it might make sense to use tagged mode.

Tagging circuits to VRFs (Juniper only)

This was my favourite part. The way to do this seems to be lt- devices, which means you need to set up the tunnel services PIC (if you have one - the MX80's have one built in).

chassis {
    fpc 0 {
        pic 0 {
            tunnel-services {
                bandwidth 1g;
            }
        }
    }
}

This next part took a while to figure out, but it totally works - you just need to make sure you match up the encapsulations and it all works fine.

Here's some config:

routing-instances {
    vrf {
        instance-type vrf;
        interface lt-0/0/10.1;
        route-distinguisher 1:2;
        vrf-target target:1:2;
        vrf-table-label;
    }
    vrf-43 {
        instance-type vrf;
        interface lt-0/0/10.3;
        route-distinguisher 1:42;
        vrf-target target:1:42;
        vrf-table-label;
    }
    vpls-40 {
        description vpls-40;
        instance-type vpls;
        vlan-id none;
        interface lt-0/0/10.2;           
        protocols {
            vpls {
                no-tunnel-services;
                vpls-id 40;
                mtu 9100;
                neighbor 10.0.0.2;
                neighbor 10.0.0.3;
            }
        }
    }
}
protcols {
    l2circuit {
        neighbor 10.0.0.2 {
            interface lt-0/0/10.4 {
                virtual-circuit-id 43;
                mtu 9100;
                encapsulation ethernet-vlan;
            }
        }
    }
}
interfaces {
    lt-0/0/10 {
        mtu 9192;
        unit 1 {
            encapsulation ethernet;
            peer-unit 2;
            family inet {
                mtu 9000;
                address 192.168.0.13/24;
            }
        }
        unit 2 {
            encapsulation ethernet-vpls;
            peer-unit 1;
        }
        unit 3 {
            encapsulation ethernet;
            peer-unit 4;
            family inet {
                mtu 9000;
                address 192.168.43.13/24;
            }
        }
        unit 4 {
            encapsulation ethernet-ccc;
            peer-unit 3;
        }
    }
}

This took about a day to get working, but it's totally simple once it matches up. The lt- devices are instead of crossover cables hanging out the back of your router, and the key is to just set the encapsulation types correctly. You can cheat a little with irb interfaces in VPLS routing instances, but this alters the route table directly on the chassis. Doing it this way means it's locked down to a VRF, and everything is a bit nicer.

End

I hope you've enjoyed this - let me know if there's anything I've missed or got wrong. The moral of the story here is - Juniper and Brocade can do VPLS and VLLs fine between each other - just watch out for the little quirks that would trip you up.

Tuesday, February 12, 2013

OpenFlow 1.0 support on Juniper MX240 with JunOS 12.3

Juniper have added OpenFlow to JunOS 12.3

Do you have a spare MX240 lying around? Chuck a copy of JunOS 12.3 on it and you can get Openflow 1.0 up and running and have a play.

Details

  • Fairly full OF1.0 implementation. I don't have a spare MX240 to test, but it would appear that everything is handled in hardware (not sure how Junipers could do otherwise tbh)
  • Supports multiple VLANs - if these can be turned on and off from the controller then this would be awesome (let me know if you find this out)
  • Doesn't handle buffered packets - make sure your controller can handle OFPT_PACKET_IN messages that don't send a buffer ID (current version of POX doesn't do this?, but the betta branch does)
  • Doesn't handle TLS connectivity to the controller - not the end of the world, but I'm curious as to why this was done
  • Doesn't do anything related to STP... who cares?
  • Only supports MX240s...
This looks like a great start, well done Juniper! Here's my list of requests for the next iteration:
  • Support more than one device :) MX80's would be great, also looking to see what the EX series implementation looks like
  • Buffered packets! Everyone else does this, and it greatly speeds up the flows-per-second bottleneck between the switch and controller
That's pretty much all from me. OF1.1 support (or 1.3 as this is where everyone is going) would be awesome so we can drive MPLS, but other than that, this is fantastic news.

Update

It looks like it's not quite ready for RouteFlow - Joe Stringer pointed this out in the notes:

• If the controller pushes a flow with a set source MAC address action, the router cannot
   program the corresponding filter term. However, CLI show commands still display the
  flow with the associated action, and the device sends an OFPET_FLOW_MOD_FAILED
 error message with an OFPMFC_UNSUPPORTED code to the controller. [PR 838699]
• If the controller pushes a flow with a set destination MAC address action, the router
   cannot program the corresponding filter term. However, CLI show commands still
  display the flow with the associated action, and the device sends an
 OFPET_FLOW_MOD_FAILED error message with an OFPMFC_UNSUPPORTED code
to the controller. [PR 838709]
• If a flow contains a set IP source address action or a set IP destination address action,
   the device rejects the flow and sends an OFPET_FLOW_MOD_FAILED error m

In other words, no MAC/IP address rewrites = no routing :(

Disclaimer

I've been told that this info and the linked documents are public... If Juniper isn't happy with this, please get in touch and I'll fix it.

Tuesday, April 3, 2012

Creating an Olive with JunOS 12.1 on VirtualBox




First, download jinstall-12.1R1.9-domestic-signed.tgz from the Juniper website.





You’ll need to unpack it and play around with it a little. Unpack the tgz

sam@laptop:~/Downloads$ mkdir jinst-signed
sam@laptop:~/Downloads$ cd jinst-signed/
sam@laptop:~/Downloads/jinst-signed$ tar -xzf ../jinstall-12.1R1.9-domestic-signed.tgz
sam@laptop:~/Downloads/jinst-signed$ ls -l
razem 437104
-rw-r--r-- 1 sam sam      7153 2012-03-24 19:57 certs.pem
-rw-r--r-- 1 sam sam        50 2012-03-25 03:31 +COMMENT
-rw-r--r-- 1 sam sam      1154 2012-03-25 03:31 +CONTENTS
-rw-r--r-- 1 sam sam       195 2012-03-25 03:31 +DESC
-rw-r--r-- 1 sam sam     87216 2012-03-25 03:31 +INSTALL
-rw-r--r-- 1 sam sam      6267 2012-03-25 02:25 issu-indb.tgz
-rw-r--r-- 1 sam sam 447458263 2012-03-25 02:40 jinstall-12.1R1.9-domestic.tgz
-rw-r--r-- 1 sam sam        33 2012-03-25 03:19 jinstall-12.1R1.9-domestic.tgz.md5
-rw-r--r-- 1 sam sam        41 2012-03-25 03:19 jinstall-12.1R1.9-domestic.tgz.sha1
-rw-r--r-- 1 sam sam       525 2012-03-25 03:31 jinstall-12.1R1.9-domestic.tgz.sig



There are tons of of files in this archive, and lots of guides say to try and play with it and pack it back up, but it’s actually a lot easier to just use the unsigned archive jinstall-12.1R1.9-domestic.tgz


If we unpack this, we get the following files:



-rw-r--r-- 1 sam sam  11673600 2012-03-25 02:38 bootstrap-install-12.1R1.9.tar
-rw-r--r-- 1 sam sam        39 2012-03-25 02:39 +COMMENT
-rw-r--r-- 1 sam sam       702 2012-03-25 02:39 +CONTENTS
-rw-r--r-- 1 sam sam    106121 2012-03-25 02:39 +DEINSTALL
-rw-r--r-- 1 sam sam       244 2012-03-25 02:39 +DESC
-rw-r--r-- 1 sam sam    107634 2012-04-02 19:57 +INSTALL
-rw-r--r-- 1 sam sam 440390207 2012-03-25 02:26 jbundle-12.1R1.9-domestic.tgz
-rw-r--r-- 1 sam sam      5933 2012-04-02 19:56 pkgtools.tgz
-rw-r--r-- 1 sam sam    106669 2012-04-02 19:57 +REQUIRE



We need to do edit the +INSTALL and +REQUIRE files here. Do a search for "re_name" and you'll find the following line:



check_arch_compatibility()
{
    re_name=`/sbin/sysctl -n hw.re.name 2>/dev/null`
    if [ -z "$re_name" ]; then
        Error "hw.re.name sysctl not supported."
    fi

This will make the install fail, so we need to replace it with the following:

check_arch_compatibility() { #re_name=`/sbin/sysctl -n hw.re.name 2>/dev/null` re_name="olive" if [ -z "$re_name" ]; then Error "hw.re.name sysctl not supported." fi


Once you've updated both of these files, unpack the pkgtools.tgz into a new directory


sam@laptop:~/Downloads/jinst-signed/jinst$ mkdir pkgtools
sam@laptop:~/Downloads/jinst-signed/jinst$ cd pkgtools/
sam@laptop:~/Downloads/jinst-signed/jinst/pkgtools$ tar -xzf ../pkgtools.tgz
sam@laptop:~/Downloads/jinst-signed/jinst/pkgtools$ ls -l
razem 8
drwxrwxr-x 2 sam sam 4096 2012-04-02 18:52 bin
drwxrwxr-x 2 sam sam 4096 2012-04-02 18:52 pkg
sam@laptop:~/Downloads/jinst-signed/jinst/pkgtools$ ls -l bin/
razem 4
-rwxr-xr-x 1 sam sam 2980 2012-04-02 19:55 checkpic



The checkpic file needs to be replaced with the "true" program from FreeBSD, so now is a good time to install it on our virtual machine. I've used FreeBSD 7.3, because FreeBSD 8 and higher use gpart instead of bsdlabel for changing the boot partition, but if you're keen to play with it, look in the +INSTALL file for the line "bsdlabel -B -b /boot/boot $labeldrive"


Anyway, get the i386 ISO for FreeBSD (the NZ mirror is on Citylink, so if your ISP zero-rates traffic through WIX/APE then it won't add to your data cap), and make up a virtual machine. I've used VirtualBox, but it should work in any virtual machine software



I used 512MB at first, but it wasn't enough for JunOS 12.1 - bumping it up to 640MB for the install made it work though. As you'll see in the later screenshots, I did this on my netbook with 990MB of RAM, so I couldn't bump it up too much further.

 An 8GB virtual hard drive gives you lots of room for new versions of software in your /var/tmp directory

This part is important - when booting, you can only see the output from JunOS through the console port. The easiest way to get this set up is to install socat and screen, and use the following command:
socat UNIX-CONNECT:/tmp/olivecom1 PTY,link=olivescreen
This will hang (only works once the virtual machine is running and the pipe is created) - so in a second terminal use this command:
screen olivescreen


 Boot up the installer, and go for a Standard install.
At the partition screen, push C to create a new slice, and allocate all the disk space to it. Then press Q and go to the next screen
 Choose a Standard boot loader
 The next screen lets you create partitions. Create the first partition with 1024M, as a file system partition, and mount point /

 Once this is done, create a 1024M swap partition, then a 16sM file system partition mounted at /dummy (this makes the labels line up so the installer doesn't fail), a 1024M file system partition at /config, and the last partition (with all the left over space) on /var

 Looking good so far? If the drive labels don't match up (i.e. no partition ad0s1f) then the JunOS install will fail

 Do a minimum install, install from CD/DVD, say no to all the questions, and you're done!
 Now you can exit the installer and reboot (don't forget to eject the virtual DVD!)
 When it reboots, use "dhclient em0" to get an address (probably 10.0.2.15), and then copy the file /usr/bin/true to your computer. The command "scp /usr/bin/true name@10.0.2.2:~/" should work for some computers, but under lubuntu it fails, so I had to use my GuruPlug instead ;)

Let's leave that virtual machine cooking for a bit. Now you have this "true" file, copy it in place of checkpic in your pkgtools/bin directory, then pack it all up

sam@laptop:~/Downloads/jinst-signed/jinst/pkgtools$ tar -xzf ../pkgtools.tgz *


Delete the pkgtools directory, and pack this all up into another .tgz

sam@laptop:~/Downloads/jinst-signed/jinst$ tar -xzf ../jinstall-12.1R1.9-domestic-olive.tgz *


Then you're good to go. Use scp to copy this onto your virtual machine, and use the pkg_add command to install JunOS 12.1
 When it's all done, rebooot, and watch it all in your terminal
And here is your JunOS 12.1 Olive. Haven't tested mine yet, but will end up using it as a testbed for big changes at work. Make sure you use the "cli" command to get the JunOS commandline, then run it like normal - use "request system power-off" to shut it down before turning it off. Check my older posts for how to network them, and remember - ethernet multicast fails on these, but you can make it work over GRE or IP-IP tunnels (older posts cover this too).