A brief break…

As many of you will have already read, my JNCIE-ENT lab exam is scheduled for Friday 21 Feb 2014 – which is getting quite close now! For more info on what this involves, check out my blog post here; JNCIE-ENT beta exam booked.

I’m going to be travelling over to be in the San Francisco Bay Area from Monday 17 Feb – Saturday 22 Feb in order that I can catch up with various people in that time and recover from the jet lag in time for the exam (which is a tiring experience at the best of times).

As much as the JNCIE-ENT lab exam is a massive undertaking, I am feeling as prepared as I could be at this point – I’ve put in 270 hours of study so far, and will be aiming to put in a minimum of 40 hours per week from this point forward.

I’m also looking forward to attending the NZNOG (New Zealand Network Operators Group) conference in a couple of weeks – this is always a great opportunity to catch up with others in the industry and exchange ideas and thoughts.

Over this time, I doubt I will have sufficient time to post many (if any) blog posts (though I may try to fit a couple of new ones in). I will be attempting to rewrite/reword a couple of my earlier posts that I am not yet 100% happy with yet, plus just keeping my head down and focusing on study! Please forgive me for the lack of new content in these coming few weeks!

Thanks to all of those of you who have taken the time to read the various articles I have posted over the short time I have been blogging – particularly those of you who have been kind enough to provide feedback / encouragement / comments relating to these articles and/or my JNCIE-ENT study :).

Cheers,
–Hoff

A quick hack to find busy interfaces on a MX!

Today at work we were attempting to locate one unit out of around 4,000 to find where a large amount of traffic on our network was headed. The monitoring tools pointed at this device were… shall we say… less than awesome for these tasks ;). So, my co-worker Tim Woolford (@insertbird on twitter), came up with this useful bash script to find any queues that were dropping more than X packets per second (in this case, we have configured the limit to 1pps – see the limit variable if you want to change this). We figure that this is something that others may find useful, so here’s the script. It’s quick and dirty, but does the trick. Here’s some sample output from it (note that the “Customer ABC” is the configured description on the unit);

[email protected]:~$ ./ddos-mx.sh 1.2.3.4
1.2.3.4 - xe-1/3/1.10046 dropping 14 pps in forwarding queue 1 - Customer ABC

This utilises the ‘JUNIPER-COS-MIB’ SNMP functionality and also the IF-MIB to resolve interfaces. Hopefully this is of use to others who want a quick way to find that one busy interface on a box etc.

#!/bin/sh
host=$1
community="COMMUNITY_NAME_GOES_HERE"
limit=1

snmpwalk -v 2c -c $community $host .1.3.6.1.4.1.2636.3.15.4.1.12 |grep -v 0$ | while read line
do
	ifIndex=`echo $line | sed -e 's/^.*3.15.4.1.12.//'|cut -d '.' -f 1`
	pps=`echo $line | sed -e 's/^.*Counter64: //'`
	class=`echo $line |sed -e 's/^.*3.15.4.1.12.[0-9]\{1,5\}.//' -e 's/ = Counter64.*$//'`
	ifName=`snmpwalk -v 2c -c $community $host .1.3.6.1.2.1.2.2.1.2.$ifIndex |sed -e 's/^.*STRING: //'`
	echo $ifName | grep \\. > /dev/null
	if [ $? = 0 ]; then
		if [ $pps -gt $limit ]; then
			desc="`snmpwalk -v 2c -c $community $host .1.3.6.1.2.1.31.1.1.1.18.$ifIndex |sed -e 's/^.*STRING: //'`"
			echo $host - $ifName dropping $pps pps in forwarding queue $class - $desc
		fi
	fi
done

Of course this touches a fraction of what we could achieve with Juniper SNMP and scripts polling this, but as a simple hack, this goes a long way! You will need snmpwalk whichever box you are running this from in order to use this. All credit for this post goes to Tim Woolford (@insertbird).

BGP local-as – as-path manipulation options

BGP local-as is a handy feature which allows you to pretend to be a member of a different ASN for the purposes of peering with another ASN. This is pretty handy for migration purposes – i.e. if ISP A buys ISP B and wants to migrate all of ISP B’s customers to peer with ISP A without having to get them to change their peering configuration. This feature is very simple to configure, and most who have worked for any length of time in a service provider will be familiar with it, however many will be googling if they have to implement any of the as-path manipulation features offered within it! In this blog post, I’m going to go through each of these as-path manipulation options in some detail.

This blog post is based on a lab of 4 routers (each in its own ASN) laid out in the following manner;
BGP local-as as-path lab

The base configuration of the lab we shall be working on can be found here; local-as-blog-lab.pdf

Before we get into this, it’s worth noting that i’m configuring all my BGP parameters in the “neighbor” hierarchy out of sheer force of habit – but I could equally be configuring the peer-as & local-as in the “group” hierarchy.

As noted in the diagram, 1.1.1.1/32 is advertised into BGP from R1, and 6.6.6.6/32 from R6. These are the only routes that are being advertised via BGP, and are there to show us what happens in each direction when we configure local-as with the various options offered to us within this feature.

Right, so first up, lets say that R2 thinks that R4’s ASN is actually AS9999. We’ll firstly configure this on R2;

[edit protocols bgp group R4 neighbor 192.168.3.2]
-     peer-as 4;
+     peer-as 9999;

Now we will find that this BGP session isn’t doing so well at coming up;
On R2;

[email protected]# run show bgp summary | match 9999           
192.168.3.2            9999          0          2       0       0          14 Active

Okay, so now we need to turn on local-as on R4 for the BGP session facing R2 in order that R4 pretends to be inside AS9999;

[edit protocols bgp group R2 neighbor 192.168.3.1]
+      local-as 9999;

And it’s now up and looking good – R4 is pretending for the sakes of the session to R2 that it is in AS9999;

[email protected]# run show bgp summary | match 9999    
192.168.3.2            9999          5          5       0       0          48 1/1/1/0              0/0/0/0

Okay, now we’ll have a look at how the routes look in either direction. Firstly lets examine 1.1.1.1/32 as received on R6;

[email protected]# run show route 1.1.1.1 

inet.0: 6 destinations, 6 routes (6 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both

1.1.1.1/32         *[BGP/170] 00:02:29, localpref 100
                      AS path: 4 9999 2 1 I
                    > to 192.168.6.1 via ge-0/0/1.0

And now for 6.6.6.6/32 on R1;

[email protected]# run show route 6.6.6.6 

inet.0: 6 destinations, 6 routes (6 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both

6.6.6.6/32         *[BGP/170] 00:03:06, localpref 100
                      AS path: 2 9999 4 6 I
                    > to 192.168.1.2 via ge-0/0/1.0

We can see that as9999 now appears as an additional ASN in the as-path in both directions through the R2-R4 BGP peering. This is important to note – while we would expect it to be added as routes are learned by R2 from R4, R4 is also adding it to routes it learns to keep the as-path consistent in both directions.

Now lets have a look at the options available to us for the local-as feature;

[email protected]# set protocols bgp group R2 neighbor 192.168.3.1 local-as ?
Possible completions:
  <as_num>              Autonomous system number in plain number or 'higher 16bits'.'Lower 16 bits' (asdot notation) format
  alias                Treat this AS as an alias to the system AS
  loops                Maximum number of times this AS can be in an AS path (1..10)
  no-prepend-global-as  Do not prepend global autonomous-system number in advertised paths
  private              Hide this local AS in paths learned from this peering

Before we go any further, it’s worth noting that you cannot configure both the private and alias options on the same neighbor/group.

Loops is not going to be covered in in this post, but at a high level this is a way to influence allow X number of as-path loops in the as-path.

The private option instructs the router with local-as configured to stop adding the configured “local-as” to routes it learns from the peer with local-as configured against it.

Lets configure the private option on this on R4 now;

[edit protocols bgp group R2 neighbor 192.168.3.1 local-as]
+      private;

As expected, there is no change on the 6.6.6.6/32 route from R1, which R4 is learning from R2;

[email protected]# run show route 6.6.6.6    

inet.0: 6 destinations, 6 routes (6 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both

6.6.6.6/32         *[BGP/170] 00:00:02, localpref 100
                      AS path: 2 9999 4 6 I
                    > to 192.168.1.2 via ge-0/0/1.0

However, R6 now sees 1.1.1.1/32 without as9999 in the as-path – R4 is no longer adding this to the as-path as it receives the route from R2;

[email protected]# run show route 1.1.1.1 

inet.0: 6 destinations, 6 routes (6 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both

1.1.1.1/32         *[BGP/170] 00:02:29, localpref 100
                      AS path: 4 2 1 I
                    > to 192.168.6.1 via ge-0/0/1.0

We’ll now roll this back ready to move on to the next option;

[email protected]# show | compare 
[edit protocols bgp group R2 neighbor 192.168.3.1 local-as]
-      private;

The next option we will look at is the alias feature. This behaves the same way as private for routes learned from the peer that local-as is configured on – it does not add the local-as to the path, but as normal just adds the local system ASN as normal. However the difference is that when sending routes to the neighbor, the router with local-as configured will omit the local system ASN, placing just the configured local-as in the as-path (instead of the default behaviour which is to insert both the local system and configured local-as in the path).

Given that there is nothing like seeing it for yourself, we will now configure this option on R4 and take a peek;

[edit protocols bgp group R2 neighbor 192.168.3.1 local-as]
+      alias;

Firstly we inspect 1.1.1.1/32 (learned by R4 from R2 and viewed on R6) which we can see looks as if there was no local-as configured on R4 at all – the as-path is as normal. This is the same as in the private option;

[email protected]# run show route 1.1.1.1 

inet.0: 6 destinations, 6 routes (6 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both

1.1.1.1/32         *[BGP/170] 00:00:47, localpref 100
                      AS path: 4 2 1 I
                    > to 192.168.6.1 via ge-0/0/1.0

Next, we’ll have a look at 6.6.6.6/32 (sent by R4 to R2 and viewed on R1) which we can see has AS9999 but not AS4 in the path;

[email protected]# run show route 6.6.6.6    

inet.0: 6 destinations, 6 routes (6 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both

6.6.6.6/32         *[BGP/170] 00:00:56, localpref 100
                      AS path: 2 9999 6 I
                    > to 192.168.1.2 via ge-0/0/1.0

Before we move on, lets quickly remove the alias option so that we can see what happens when we configure the next feature;

[edit protocols bgp group R2 neighbor 192.168.3.1 local-as]
-      alias;

The final option available to us is one called no-prepend-global-as. While private and alias cannot be configured at the same time as each other (as alias is the functionality of private plus one further change to the as-path), no-prepend-global-as can be configured in conjunction with either of these other options. The no-prepend-global-as essentially implements only the function that is present in alias but not private – this is that when sending routes to the neighbor, the router with local-as configured will omit the local system ASN, placing just the configured local-as in the as-path (instead of the default behaviour which is to insert both the local system and configured local-as in the path).

We’ll now configure this;

edit protocols bgp group R2 neighbor 192.168.3.1 local-as]
+      no-prepend-global-as;

And then we’ll have a look. Like alias we can see that the configured local-as on R4 is in the as-path as seen by R1 (learned from R4 by R2), but not the R4 system AS;

[email protected]# run show route 6.6.6.6 

inet.0: 6 destinations, 6 routes (6 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both

6.6.6.6/32         *[BGP/170] 00:05:53, localpref 100
                      AS path: 2 9999 6 I
                    > to 192.168.1.2 via ge-0/0/1.0

However, we can see that unlike alias, it does not modify the default behaviour on routes learned from R2 by R4 (and we have both the R4 system ASN + the configured local-as;

[email protected]# run show route 1.1.1.1 

inet.0: 6 destinations, 6 routes (6 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both

1.1.1.1/32         *[BGP/170] 00:06:19, localpref 100
                      AS path: 4 9999 2 1 I
                    > to 192.168.6.1 via ge-0/0/1.0

Local-as is a really useful feature – generally for the purposes of migrations. Some of the as-path manipulation options can be invaluable in complex/odd peering scenarios where there is a requirement to disguise what is actually happening on the network – be it a superficial requirement or the prevention of a an apparent loop being signified in the as-path.

I hope this article helps clarify the various options for you!

A reading list of useful JNCIE-ENT articles

Here’s a (small) reading list of blog articles that I’ve found useful during my study for anyone wanting to get started on study towards their JNCIE-ENT certification.

Blueprint analysis;
http://data-in-motion.blogspot.co.nz/2012/12/jncip-ent-jncie-ent-preparation-part-2.html

OSPF;
http://3fives.com/jncie-tip-ospf-database-purge/
http://3fives.com/ospf3-ipv6-realm-cli-issues/

Summarisation tip;
http://www.shortestpathfirst.net/2011/06/21/jncie-tips-from-the-field-summarization-made-easy/

Load balancing;
http://www.junosandme.net/m/article-105738134.html
http://www.junosandme.net/m/article-109245295.html
http://www.junosandme.net/m/article-109382234.html

Ethernet OAM;
http://www.junosandme.net/article-oam-lfm-part-1-the-theory-100830412.html
http://www.junosandme.net/article-oam-lfm-part-2-junos-implementation-101155962.html

Exam experiences;
http://www.shortestpathfirst.net/2011/03/16/preparation-tips-for-the-jncie-er-exam/
http://3fives.com/the-jncie-ent-alpha-experience/
http://3fives.com/jncie-ent-lab-exam/
http://3fives.com/jncie-ent/
http://www.network-janitor.net/2012/05/juniper-lab-experiences-my-second-attempt-at-jncie-ent/
http://www.network-janitor.net/2013/05/eventully-my-jncie-ent-success/
http://forums.juniper.net/t5/My-Certification-Journey/My-Experience-of-JNCIE-ENT-Hard-prep-for-a-hard-exam/ba-p/149102
http://taildrop.net/2011/09/20/the-path-to-certification/#more-51

A tip for logging useful stuff;
http://www.junosandme.net/m/article-97603704.html

Hope this helps those of you working towards this certification!

Limiting web-managment access with captive-portal on the EX

A feature I’ve been playing around with on the EX4200s in my JNCIE-ENT study lab is captive portal. The EX can provide a local captive-portal, which on the surface would seem to be quite a nice feature for a switch to have, if it didn’t have one HUGE limitation.

A basic configuration for captive portal would look a little like this;

[email protected]# show 
## Last changed: 2013-09-24 09:13:13 UTC
version 12.3R4.6;
system {
    host-name EX4200-SWITCH;
    root-authentication { /* OMITTED */ };
    login { /* OMITTED */ };
    services {
        ssh {
            root-login allow;
        }
        web-management {
            http;
            https {
                system-generated-certificate;
            }
        }
    }
}
services {
    captive-portal {
        authentication-profile-name JNCIE;
        interface {
            ge-0/0/0.0;
        }
    }
}
interfaces {
    ge-0/0/0 {
        description "Hoff laptop";
        unit 0 {
            family ethernet-switching {
                port-mode access;
                vlan {
                    members DATA;
                }
            }
        }
    }
    me0 { /* OMITTED */ };
    vlan {
        unit 55 {
            family inet {
                address 192.168.55.1/24;
            }
        }
    }
}
routing-options { /* OMITTED */ };
access {
    radius-server {
        1.2.3.4 secret "$9$tnSt01Ex7dsY4HqTF"; ## SECRET-DATA
    }
    profile JNCIE {
        authentication-order radius;
        radius {
            authentication-server 1.2.3.4;
        }
    }
}
vlans { /* OMITTED */ };

We can see with this configuration that captive portal is doing its thing on ge-0/0/0;

[email protected]# run show captive-portal interface 
Captive Portal Information:
Interface      State           MAC address          User           Fallen back
ge-0/0/0.0     Initialize

At this point, I can authenticate through the web interface;

Captive portal login

Captive portal login

After entering some credentials in the login screen (shown above) we can see I am all authenticated;

[email protected]# run show captive-portal interface   
Captive Portal Information:
Interface      State           MAC address          User           Fallen back
ge-0/0/0.0     Authenticated   68:5b:35:7a:9a:2a    snap           No

What’s interesting about this though is that I had to enable the “web-management” (J-Web) service for this to work. If you configure captive-portal without enabling the web-management service a warning is thrown up (both in the configuration and when you do a commit check);

[email protected]# show 
version 12.3R4.6;
system { /* OMITTED */ };
services {
    captive-portal {
        authentication-profile-name JNCIE;
        interface {
            ##
            ## Warning: HTTP web service should be enabled
            ##
            ge-0/0/0.0;
        }
    }
}

{master:0}[edit]
[email protected]# commit check 
[edit services captive-portal interface]
  'ge-0/0/0.0'
    HTTP web service should be enabled
error: configuration check-out failed: (statements constraint check failed)

This raised some alarm bells – surely you must be able to do captive-portal without being forced into having the J-Web interface. Sadly not. Once you are authorised through the captive-portal interface you can jump straight onto the web-management interface of the switch (see below). This is really undesirable – generally you do NOT want users on a port you distrust enough to be falling back to captive portal anywhere near accessing the switch management login.

Web management interface accessible from captive-portal port

Web management interface accessible from captive-portal port

Upon discovering this, I had a crack at locking down the J-Web interface to just the out of band management port (me0). Firstly I tried specifying an interface that web-management should be limited to;

[email protected]# show | compare 
[edit system services web-management http]
+     interface me0.0;
[edit system services web-management https]
+     interface me0.0;

Before re-testing, I cleared my current session;

[email protected]# run clear captive-portal interface 
[email protected]# run show captive-portal interface     
Captive Portal Information:
Interface      State           MAC address          User           Fallen back
ge-0/0/0.0     Connecting

I then had another try at authenticating, but got a 401 error;
Denied due to web-mangement being configured for me0 only

Clearly if you limit the web-management to just one interface, it also limits the captive-portal access to just one interface.

I rolled this back then tried a number of other ways to allow http/https access to captive-portal but deny it to the J-Web interface, however all of these were unsuccessful. These included fiddling with port numbers, firewall filters, and a few other odd stabs in the dark. There doesn’t seem to be a heap of relevant documentation on this either.

This is really annoying – it seems that you just can’t separate the ability to get a login screen for J-Web from the ability to get a log-in screen for captive-portal! While having the ability to do captive-portal on the EX is really cool it just comes across a bit half-baked when you have issues like this!

I’ll be ensuring that if I ever do have to use this in anger I’m passing the captive-portal authentication to a separate device for this functionality – ensuring that I don’t expose J-Web (something I really really do not ever want to do). It’s disappointing not to be able to present to you all a cool way to work around this, but unfortunately this just seems to be a limitation of the EX…

A working way to force EX VoIP VLAN classification!

In my previous post “How does EX CoS interact with the VoIP VLAN feature?“, I proved in a lab environment that while the Juniper documentation implies that setting the set forwarding-class X parameter in the edit ethernet-switching-options voip interface ge-x/x/x hierarchy forces traffic into a forwarding-class, this is not the case. Instead this actually (assuming you have LLDP-MED on and a BA classifier on the interface) causes the EX to signal the phone via LLDP-MED to use a specific marking on all traffic to cause it to be classified into a certain forwarding class.

This leaves the question of what you would do if you truly wanted to force all traffic arriving on the VoIP VLAN to be forced into a certain forwarding class without making it possible for other traffic to be placed there based on a DSCP marking coming from the user’s computer. One possible way to do this would be with a firewall filter, which I’m going to explore in this post.

It would be worth reading the aforementioned post before going into this one, as in this post I’m skipping over a few valuable things mentioned in the previous post.

I’m going to use the same baseline configuration as I did in the last lab. Here is the configuration of the EX4200 acting as the switch;

[email protected]# show 
## Last changed: 2013-04-08 00:22:06 UTC
version 11.4R7.5;
system { /* OMITTED */ };
interfaces {
    ge-0/0/0 {
        description "Hoff laptop";
        unit 0 {
            family ethernet-switching {
                port-mode access;
                vlan {
                    members DATA;
                }
            }
        }
    }
    ge-0/0/1 {
        description "EX4200 acting as Router";
        unit 0 {
            family ethernet-switching {
                port-mode trunk;
                vlan {
                    members [ VOICE DATA ];
                }
            }
        }
    }
    me0 { /* OMITTED */ };
}
routing-options { /* OMITTED */ };
ethernet-switching-options {
    voip {
        interface ge-0/0/0.0 {
            vlan VOICE;
        }
    }
}
vlans {
    DATA {
        vlan-id 55;
    }
    VOICE {
        vlan-id 66;
    }
}

And here’s the configuration of the other EX4200 which has a couple of tagged routed interfaces that I can throw traffic at (to get it egressing an interface on the other EX4200 that we can measure);

[email protected]# show 
## Last changed: 2013-12-21 08:07:44 UTC
version 11.2R2.4;
system { /* OMITTED */ };
interfaces {
    ge-0/0/1 {
        description "EX4200 acting as Switch";
        vlan-tagging;
        unit 55 {
            description "DATA vlan";
            vlan-id 55;
            family inet {
                address 192.168.55.1/24;
            }
        }
        unit 66 {
            description "VOICE vlan";
            vlan-id 66;
            family inet {
                address 192.168.66.1/24;
            }
        }
    }
    me0 { /* OMITTED */ };
}
routing-options { /* OMITTED */ };

Okay, so we’ve already baselined this in the previous configuration to check that traffic does in fact by default go into the BE queue in this configuration, but I’ll quickly re-prove this. Let’s start with 30secs of a 100Mbit iperf from my laptop to 192.168.55.1  on the DATA VLAN;

Phoebe:~ tim$ iperf -c 192.168.55.1 -u -b 100m -t 30

And the result;

[email protected]# run show interfaces queue ge-0/0/1    
Physical interface: ge-0/0/1, Enabled, Physical link is Up
  Interface index: 130, SNMP ifIndex: 504
  Description: EX4200 acting as Router
Forwarding classes: 16 supported, 4 in use
Egress queues: 8 supported, 4 in use
Queue: 0, Forwarding classes: best-effort
  Queued:
  Transmitted:
    Packets              :                245623
    Bytes                :             372363016
    Tail-dropped packets :                     0
<some output omitted for brevity>

Looking good. We’ll now clear the interface stats then confirm the same behaviour for the VOICE VLAN;

[email protected]# run clear interfaces statistics ge-0/0/1
Phoebe:~ tim$ iperf -c 192.168.66.1 -u -b 100m -t 30

And the result for this one;

[email protected]# run show interfaces queue ge-0/0/1    
Physical interface: ge-0/0/1, Enabled, Physical link is Up
  Interface index: 130, SNMP ifIndex: 504
  Description: EX4200 acting as Router
Forwarding classes: 16 supported, 4 in use
Egress queues: 8 supported, 4 in use
Queue: 0, Forwarding classes: best-effort
  Queued:
  Transmitted:
    Packets              :                245811
    Bytes                :             373631264
    Tail-dropped packets :                     0
<some output omitted for brevity>

Okay cool. Now it’s time to implement the a firewall filter that classifies all traffic coming in on the VOICE VLAN into the EF forwarding-class and leaves the rest of the traffic in the default BE forwarding-class (note that when using the action then forwarding-class X in an ethernet-switching firewall filter you are required to set a then loss-priority X action to accompany it);

[edit interfaces ge-0/0/0 unit 0 family ethernet-switching]
+       filter {
+           input MF-VoiceVlan;
+       }
[edit]
+  firewall {
+      family ethernet-switching {
+          filter MF-VoiceVlan {
+              term VoiceVlan {
+                  from {
+                      vlan VOICE;
+                  }
+                  then {
+                      accept;
+                      forwarding-class expedited-forwarding;
+                      loss-priority low;
+                  }
+              }
+              term Catchall {
+                  then accept;
+              }
+          }
+      }
+  }

Let’s now clear the interface stats then check that the DATA VLAN is still doing its thing;

[email protected]# run clear interfaces statistics ge-0/0/1
Phoebe:~ tim$ iperf -c 192.168.55.1 -u -b 100m -t 30

And the results look the same as expected;

[email protected]# run show interfaces queue ge-0/0/1    
Physical interface: ge-0/0/1, Enabled, Physical link is Up
  Interface index: 130, SNMP ifIndex: 504
  Description: EX4200 acting as Router
Forwarding classes: 16 supported, 4 in use
Egress queues: 8 supported, 4 in use
Queue: 0, Forwarding classes: best-effort
  Queued:
  Transmitted:
    Packets              :                245395
    Bytes                :             372017368
    Tail-dropped packets :                     0
<some output omitted for brevity>

Now, for the moment of truth – to re-test the VOICE VLAN iperf and check that traffic is being classified into the EF forwarding-class! Firstly to clear the interface stats and run the iperf;

[email protected]# run clear interfaces statistics ge-0/0/1
Phoebe:~ tim$ iperf -c 192.168.66.1 -u -b 100m -t 30

And now to check the results;

[email protected]# run show interfaces queue ge-0/0/1    
Physical interface: ge-0/0/1, Enabled, Physical link is Up
  Interface index: 130, SNMP ifIndex: 504
  Description: EX4200 acting as Router
Forwarding classes: 16 supported, 4 in use
Egress queues: 8 supported, 4 in use
Queue: 0, Forwarding classes: best-effort
  Queued:
  Transmitted:
    Packets              :                     0
    Bytes                :                     0
    Tail-dropped packets :                     0
<some output omitted for brevity>
Queue: 5, Forwarding classes: expedited-forwarding
  Queued:
  Transmitted:
    Packets              :                245479
    Bytes                :             373126624
    Tail-dropped packets :                     0
<some output omitted for brevity>

It would appear this works exactly as expected!

While this method is not quite as elegant config-wise, it actually works as expected – which is always a good thing :). I expect that in most cases simply using the traditional method of telling the switch to signal a marking to the phone will be sufficient, but if you are ever in a situation where there is a requirement not to trust the phone to do the right thing but instead to absolutely force traffic from the VoIP VLAN into a certain queue this will do the trick nicely.

Hope this helps.

How does EX CoS interact with the VoIP VLAN feature?

One of the things I covered recently in my preparation for the JNCIE-ENT lab exam (which is now only a few weeks away) is the “VoIP VLAN” functionality implemented on the EX series switches. This is pretty standard stuff – the idea is that on an untagged access-port you configure an additional VLAN for which traffic is tagged to separate to a VoIP phone from traffic to a user’s PC which may be behind that VoIP phone. All the information required by the VoIP phone to use this (VLAN tag for voice traffic plus the fact that there is a separate VoIP VLAN) is advertised to the phone via LLDP-MED.

This would be typically implemented in the following manner;

set interfaces ge-0/0/5 description "Bob the sales person's desk"
set interfaces ge-0/0/5 unit 0 family ethernet-switching port-mode access
set interfaces ge-0/0/5 unit 0 family ethernet-switching vlan members SALES-LAN
set protocols lldp-med interface ge-0/0/5.0
set ethernet-switching-options voip interface ge-0/0/5.0 vlan VOIP-PHONES

The documentation (or some of it at least) also indicates that you can put traffic into a forwarding-class with an option under the same hierarchy with the following line of configuration;

set ethernet-switching-options voip interface ge-0/0/5.0 forwarding-class assured-forwarding

As with most of the things I’ve been studying, I tested this in the lab to make sure. I started with the following as a baseline (note that the VoIP forwarding-class is not specified in this configuration);

[email protected]# show 
## Last changed: 2013-04-08 00:22:06 UTC
version 11.4R7.5;
system { /* OMITTED */ };
interfaces {
    ge-0/0/0 {
        description "Hoff laptop";
        unit 0 {
            family ethernet-switching {
                port-mode access;
                vlan {
                    members DATA;
                }
            }
        }
    }
    ge-0/0/1 {
        description "EX4200 acting as Router";
        unit 0 {
            family ethernet-switching {
                port-mode trunk;
                vlan {
                    members [ VOICE DATA ];
                }
            }
        }
    }
    me0 { /* OMITTED */ };
}
routing-options { /* OMITTED */ };
ethernet-switching-options {
    voip {
        interface ge-0/0/0.0 {
            vlan VOICE;
        }
    }
}
vlans {
    DATA {
        vlan-id 55;
    }
    VOICE {
        vlan-id 66;
    }
}

We can see here that this configuration was doing what it was supposed to (for the presentation of the vlans to the interfaces at least);

[email protected]# run show ethernet-switching interfaces                           
Interface    State  VLAN members        Tag   Tagging  Blocking 
ge-0/0/0.0   down   DATA                55    untagged unblocked
                    VOICE               66    tagged   unblocked
ge-0/0/1.0   up     DATA                55    tagged   unblocked
                    VOICE               66    tagged   unblocked

My laptop took the place of a “phone” with a couple of tagged interfaces configured on it, and ge-0/0/1 on the 4200 was connected to another 4200 with a couple of tagged routed interfaces to in order that I had something to throw traffic at;

[email protected]# show 
## Last changed: 2013-12-21 08:07:44 UTC
version 11.2R2.4;
system { /* OMITTED */ };
interfaces {
    ge-0/0/1 {
        description "EX4200 acting as Switch";
        vlan-tagging;
        unit 55 {
            description "DATA vlan";
            vlan-id 55;
            family inet {
                address 192.168.55.1/24;
            }
        }
        unit 66 {
            description "VOICE vlan";
            vlan-id 66;
            family inet {
                address 192.168.66.1/24;
            }
        }
    }
    me0 { /* OMITTED */ };
}
routing-options { /* OMITTED */ };

Now that I had this all set up, I ran a 100Mbit UDP IPERF on the DATA VLAN (untagged on my laptop) with a destination of 192.168.55.1 as a bit of a benchmark. As expected when I had a look at which queue was being used as it egressed the switch-4200 to go to the router-4200 it was in the best-effort queue;

[email protected]# run show interfaces queue ge-0/0/1          
Physical interface: ge-0/0/1, Enabled, Physical link is Up
  Interface index: 130, SNMP ifIndex: 504
  Description: EX4200 acting as Router
Forwarding classes: 16 supported, 4 in use
Egress queues: 8 supported, 4 in use
Queue: 0, Forwarding classes: best-effort 
  Queued:
  Transmitted:
    Packets              :                639900
    Bytes                :             970048656
    Tail-dropped packets :                     0
<some output omitted for brevity>

I then cleared the interface stats to ensure that there was no confusion with the next step;

[email protected]# run clear interfaces statistics ge-0/0/1

Next, to continue with the baselining, I ran the same IPERF to 192.168.66.1 in the tagged VOICE VLAN 66 from my laptop

[email protected]# run show interfaces queue ge-0/0/1          
Physical interface: ge-0/0/1, Enabled, Physical link is Up
  Interface index: 130, SNMP ifIndex: 504
  Description: EX4200 acting as Router
Forwarding classes: 16 supported, 4 in use
Egress queues: 8 supported, 4 in use
Queue: 0, Forwarding classes: best-effort 
  Queued:
  Transmitted:
    Packets              :                640695
    Bytes                :             973825824
    Tail-dropped packets :                     0
<some output omitted for brevity>

As expected, this traffic was also in the BE queue.

After clearing the stats again I made the following change to the configuration to (as I thought at the time) classify traffic into the EF queue;

[email protected]# run clear interfaces statistics ge-0/0/1 
[email protected]# show | compare 
 [edit ethernet-switching-options voip interface ge-0/0/0.0]
+    forwarding-class expedited-forwarding;

Now at this point, it was time to run the test in the VOICE VLAN and prove that traffic was as expected pushed into the EF queue;

[email protected]# run show interfaces queue ge-0/0/1    
Physical interface: ge-0/0/1, Enabled, Physical link is Up
  Interface index: 130, SNMP ifIndex: 504
  Description: EX4200 acting as Router
Forwarding classes: 16 supported, 4 in use
Egress queues: 8 supported, 4 in use
Queue: 0, Forwarding classes: best-effort 
  Queued:
  Transmitted:
    Packets              :                636228
    Bytes                :             967047632
    Tail-dropped packets :                     0
Queue: 1, Forwarding classes: assured-forwarding 
  Queued:
  Transmitted:
    Packets              :                     0
    Bytes                :                     0
    Tail-dropped packets :                     0
Queue: 5, Forwarding classes: expedited-forwarding 
  Queued:
  Transmitted:
    Packets              :                     0
    Bytes                :                     0
    Tail-dropped packets :                     0
Queue: 7, Forwarding classes: network-control 
  Queued:
  Transmitted:
    Packets              :                     0
    Bytes                :                     0
    Tail-dropped packets :                     0

However, the above result certainly wasn’t what I was expecting! Just in case I’d hit a bug with 11 code, I upgraded the switch to JUNOS 12.3R4.6, but still got the same result.

Following this I did some reading around and found that there were two conflicting sets of documentation. Most of it indicated that this option acted in a manner similar to the set class-of-service interface ge-1/2/3 unit 0 forwarding-class expedited-forwarding configuration option and forced traffic into the desired queue when received on this particular VLAN, however I managed to find a couple of documentation entires which echoed what is noted in “Junos Enterprise Switching” by Marschke & Reynolds – the fact that all the forwarding-class option under the VoIP configuration for the interface does is to work out the desired forwarding-class to advertise for the phone to mark for. What actually happens here is that once you configure the forwarding-class (assuming you have a BA classifier & LLDP-MED on the interface in question) the switch might for example advertise the following to the phone for it to use for VoIP traffic;

Organization specific TLV (127), length 8: OUI ANSI/TIA (0x0012bb)
	Network policy Subtype (2)
		Application type [voice] (0x01), Flags [Tagged]
		Vlan id 66, L2 priority 4, DSCP value 46

However, the issue I had was that there was a heap of documentation out there for the EX series which was at best misleading, and at worst plain wrong.

To be sure that I wasn’t doing something absolutely stupid, I logged a JTAC case pointing out that what I had found bay testing this in the lab was a little different to what the bulk of the documentation on this feature implied. After battling through PTAC, I was finally informed that PR791041 had already been raised to fix this documentation. Hopefully they actually get it fixed soon though, as I can foresee others making the same mistake I did!

Hope this helps.

UPDATE – I’ve written up a way you could actually achieve the original goal of forcing all traffic arriving on the VoIP VLAN into a specific forwarding class (without relying on trusting the phone / user’s PC) here; “A working way to force EX VoIP VLAN classification!