CoS for RE sourced traffic

Many of you will have deployed CoS extensively on your networks. One area of a Junos CoS deployment that I am often asked about by friends is how to manipulate traffic that is sourced from the routing-engine. There are multiple catches and caveats in dealing with this traffic, and different ways to manipulate this.

At a 10,000 foot level, whenever we deploy CoS we generally want to be able to manipulate route-engine sourced traffic such as ISIS, BGP, OSPF, BFD, RSVP, etc to have various different DSCP, EXP, and 802.1p markings. Firstly, we can set a policy as to the marking used for traffic sourced from the route-engine;

set class-of-service host-outbound-traffic dscp-code-point 111000
set class-of-service host-outbound-traffic ieee-802.1 default 111

You can also specify the forwarding-class that is used for processing traffic sourced from the route-engine;

set class-of-service host-outbound-traffic forwarding-class hoffs-odd-class

It’s important to note that your rewrite rules will not take effect with this traffic (by default). Even if you have specified a forwarding-class, the “host-outbound-traffic” markings will be applied outbound for this route-engine sourced traffic.

However as of Junos 12.3, Juniper have implemented a new option for “host-outbound-traffic” on the MX, which causes the router to use the rewrite-rule for each unit to put markings onto traffic from the RE (based on the forwarding-class it is assigned). This is particularly helpful where you might have multiple fibre providers providing access to your customers, each with a different markings scheme that you are required to use. Note that this is only available for the 802.1p markings (not DSCP) This is done as follows;

set class-of-service host-outbound-traffic ieee-802.1 rewrite-rules

Of course a rewrite-rule must be configured on the outbound unit for this to have effect. So if we have a rewrite-rule to map “hoffs-odd-class” traffic to a marking of 010, the traffic will be now marked as 010 on egress.

This of course does not help us for DSCP markings (it only applies to 802.1p markings). Often we will want to manipulate these. Also how would we approach this problem if we were to wanted to assign different forwarding-classes to different types of traffic being sourced from the RE? A great example of this is that while we might want to ensure that BGP is prioritised, we probably don’t need prioritisation of http traffic sourced from the RE!

The solution for this is quite clever. Most of you will know that you can firewall off all traffic to the RE (regardless of the IP it is destined to – even if that IP is on a physical interface) by applying an inbound firewall filter to the loopback. The clever thing is that you can also apply a firewall filter to all traffic leaving the RE by applying an outbound firewall filter to the loopback. If we want to ensure that all http/https traffic is put into the best-effort forwarding-class, we could do the following;

set interfaces lo0 unit 0 family inet filter output RE-QOS
set firewall family inet filter RE-QOS term web from protocol tcp
set firewall family inet filter RE-QOS term web from port http
set firewall family inet filter RE-QOS term web from port https
set firewall family inet filter RE-QOS term web then dscp be
set firewall family inet filter RE-QOS term web then forwarding-class best-effort
set firewall family inet filter RE-QOS term web then accept
set firewall family inet filter RE-QOS term catchall then accept

This is a pretty handy tool and allows us to do a fairly fine-grained manipulation of how each traffic-type being sourced by the RE is treated. Obviously you could customise this in any way to suit your needs. However it’s worth noting that to my understanding you cannot manipulate the 802.1p markings with a firewall filter – hence why the “rewrite-rules” option becomes so important for host-oubound-traffic.

If you thought that this is all there is to marking/classifying traffic sourced from the RE, you would be wrong! On a MX router, the processing of certain control traffic is delegated to the individual line-cards (such as BFD). I have learned the hard way that the markings on this traffic are not modified by any configuration you apply to normal RE-sourced traffic.

The news is not all bad though, as there is an easy workaround for this, and not many protocols are distributed to the line cards. For this traffic, you can apply an outbound firewall filter to the interface you are doing this traffic on. As an example, here is how to ensure that BFD traffic which has been distributed to the line card is placed into the correct forwarding class and marked appropriately;

set interfaces ge-1/2/3 unit 0 family inet filter output cos-bfd-link
set firewall family inet filter cos-bfd-link term 1 from protocol udp
set firewall family inet filter cos-bfd-link term 1 from port 3784
set firewall family inet filter cos-bfd-link term 1 from port 3785
set firewall family inet filter cos-bfd-link term 1 then loss-priority low
set firewall family inet filter cos-bfd-link term 1 then forwarding-class network-control
set firewall family inet filter cos-bfd-link term 1 then dscp 111000
set firewall family inet filter cos-bfd-link term 2 then accept

Hope this helps!

LSP mappings based on route/traffic attributes

A friend today asked me an interesting question (that is in fact a part of the JNCIE-SP syllabus) – “How can I ensure that certain traffic types take different paths in my MPLS network?”

This is applicable for many of us who run large backhaul networks with many paths in them – some higher latency, some higher capacity. In these cases it is important to be able to load balance traffic based on many different requirements, first the available capacity, but also at times based on the traffic type.

A good example of where these requirements might become important is found in New Zealand – we have a single cable system out of NZ, which connects in a ring between two points in each of NZ, Australia & the USA (see below diagram). What this results in is that between NZ and the USA there are two paths: one direct, and one that goes via AU (and is 30ms longer). Both links are unprotected in themselves, but if you have a path on each, you can assume that one out of the two paths will be up at any time. You therefore don’t want to have too much more traffic than a single link could cope with, but at times you’ll oversubscribe a tad. If you wanted to oversubscribe it would make sense to ensure that latency sensitive traffic is on the short path and best effort traffic is on the long path.

The friend with whom I was discussing this was wanting to ensure that UDP traffic destined to routes in a certain as-path was transited on the long path between the USA and NZ. In this blog post we will discuss how we would achieve this on a Juniper MX router, and walk through how to achieve this example in a step by step manner.

We can map traffic to LSPs based on a range of criteria including the CoS queue, designation prefix, destination prefix as-path, and a few other useful properties (basically any information about the destination route that you can match with policy or the QoS class the traffic is in).

The one catch is that the route-preference for all LSPs you are wanting to map traffic to must be both equal and the best possible route-preference to the destination. If this is not the case, traffic will simply be sent to the best preference LSP. Likewise – if one LSP is unable to stand up and is withdrawn from the routing table, traffic mapped to this LSP will just move to another LSP.

Below is a diagram showing an example network which illustrates the problem my friend had. I have illustrated the primary TE path of two LSPs – the RED LSP which takes a direct path from the USA to NZ, and the BLUE LSP which takes a longer path via AU to NZ. The goal will be to ensure that all UDP traffic from our US transit provider that is destined to as900 and its customers will take the long path, while all other traffic takes the short path. Criteria for sending via each link is also illustrated on the diagram.

Dagram of example network

Dagram of example network

Okay – got the requirements – tell me how we do this!!!!!

We’ll configure this in a few steps, breaking down what we are doing and why as we go.

1/ Classify UDP traffic so that we can match based on this later
The first thing we identify is that one of the requirements dictates that we peer inside the header of every packet to classify it as UDP or non-UDP. In order to do this we will need to use a firewall filter on ingress to our router. We will use this to classify the traffic into a CoS class (which we can then use to map to a different LSP when we match the destination we want).

The first thing we must do in this step is create our new CoS class. Let’s call this class the “udp-class” class, while we leave the “best-effort” and “network-control” classes we had already configured in place;

[email protected]# show | compare

[edit class-of-service forwarding-classes]
     queue 3 { ... }
+    queue 1 udp-class;

Now that we have this, we must build a firewall filter to match UDP traffic vs other traffic;

[email protected]# show | compare
[edit]
+  firewall {
+      family inet {
+          filter transit-in {
+              term udp {
+                  from {
+                      protocol udp;
+                  }
+                  then {
+                      forwarding-class udp-class;
+                      accept;
+                  }
+              }
+              term other-traffic {
+                  then accept;
+              }
+          }
+      }
+  }

Finally, we need to apply this filter to inbound traffic on the interface connecting to our US transit provider;

[email protected]# show | compare 
[edit interfaces ge-0/0/3 unit 0 family inet]
+       filter {
+           input transit-in;

At this point, we have all UDP traffic from our transit provider mapped to our “udp-class” CoS queue, and we are now ready to create a policy to make forwarding decisions based on this.

2/ Create a policy to make next-hop decisions based on CoS queue

In this step, we will create a CBF (CoS Based Forwarding) policy, which will (when called upon by route policy) install a next-hop LSP based on the specified forwarding class.

This is done as follows;

[email protected]# show | compare 
[edit class-of-service]
+   forwarding-policy {
+       next-hop-map NZ-Traffic {
+           forwarding-class udp-class {
+               lsp-next-hop BLUE;
+           }
+           forwarding-class best-effort {
+               lsp-next-hop RED;
+           }
+           forwarding-class network-control {
+               lsp-next-hop RED;
+           }
+       }
+   }

It is worth re-noting that the LSPs must be equal route preference (see more detail above) – I’ve seen lots of people miss this and wonder why their CBF policy is not working.

Additionally, the astute reader will note that I have not actually created a policy for the assured-forwarding queue, which is created by default on the MX as queue 2. In this case we will assume that no traffic is passing in this queue, however if any traffic is passed in a queue that is not defined in a CBF policy, it is mapped in the same manner as queue 0 (in this case best-effort). If queue 0 is not defined, one of the defined queues is selected at random use for non-defined queues.

At this point we have our CBF policy all sorted and are ready to proceed to the next step.

3/ Find the destinations we want this policy applied to

We must now find the destinations we want this policy applied to. In our case, this is to be all prefixes destined to as900 and it’s customers. This is best described in a regular expression as “900+ .*” (one or more iterations of as900 followed by any number of other AS numbers).

We can verify that this will work with the following command (note that I only have the two prefixes shown in the diagram set up behind the NZ router in this lab);

[email protected]# run show route aspath-regex "900+ .*" 

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

200.0.0.0/24       *[BGP/170] 00:16:23, localpref 100, from 10.0.0.2
                      AS path: 900 800 700 I
                      to 10.1.0.3 via ge-0/0/1.0, label-switched-path BLUE
                    > to 10.1.1.2 via ge-0/0/2.0, label-switched-path RED

inet.3: 1 destinations, 1 routes (1 active, 0 holddown, 0 hidden)

mpls.0: 4 destinations, 4 routes (4 active, 0 holddown, 0 hidden)

We now configure this on our USA router;

[email protected]# show | compare
[edit policy-options]
+   as-path as900_and_customers "900+ .*";

Cool! We now have a way to match both parts of the criteria on which we wish to match traffic. All that is left to do is to put it all together.

4/ Putting it all together and writing some route policy

In previous steps we have created mechanisms to match the traffic type and destinations for which we want to send traffic via our “long path”. Now we need to create some policy based on this to make it all work!

We want this policy to match traffic destined prefixes for as900 and customers (defined above) that already has a next hop of the NZ router. For all traffic that is matched we need to then define the next-hop based on our CBF policy defined above (in order that only UDP traffic is sent via the long path (BLUE LSP)).

For all other traffic with a next hop of the NZ router, we want to map it to the short path (RED LSP).

The following policy will do the trick nicely;

[email protected]# show | compare 
[edit policy-options]
+   policy-statement map-nz-lsps {
+       term as900_and_customers {
+           from {
+               neighbor 10.0.0.2;
+               as-path as900_and_customers;
+           }
+           then {
+               cos-next-hop-map NZ-Traffic;
+               accept;
+           }
+       }
+       term other-nz {
+           from neighbor 10.0.0.2;
+           then {
+               install-nexthop lsp RED;
+               accept;
+           }
+       }
+   }

It’s worth noting again that LSPs must have an equal route preference (and there must be no better preferences route) for install-nexthop to work (as with CBF policy) – see more detail above.

Finally we need to apply this policy to all routes being exported from the route-engine to the forwarding-engine. This requires one further line of configuration, and is done as follows;

[email protected]# show | compare 
[edit routing-options]
+   forwarding-table {
+       export map-nz-lsps;
+   }

We now have a peek at a prefix which matches the criterion of each of the two terms, starting with 200.0.0.0/24;

[email protected]> show route forwarding-table matching 200/24 
Routing table: default.inet
Internet:
Destination        Type RtRef Next hop           Type Index NhRef Netif
200.0.0.0/24       user     0                    indr 262143     2
                                                 idxd   551     2
                   idx:1      10.1.0.3          Push 299920   572     2 ge-0/0/1.0
                   idx:3      10.1.1.2           ucst   573     4 ge-0/0/2.0
                   idx:xx     10.1.1.2           ucst   573     4 ge-0/0/2.0

We can see from the above output that it has created a per queue mapping for queues 1, 3 and a default mapping (matching queue 0’s configuration). So all working as expected.

And now for 100.0.0.0/24;

[email protected]# run show route forwarding-table matching 100/24    
Routing table: default.inet
Internet:
Destination        Type RtRef Next hop           Type Index NhRef Netif
100.0.0.0/24       user     0                    indr 262142     2
                              10.1.1.2           ucst   573     3 ge-0/0/2.0

We can see from the output that other traffic is being mapped to the RED LSP (i.e. the short path) – exactly what we wanted.

5/ Testing

We now want to verify this by generating some traffic from the “Transit provider in the USA” – which in this lab is represented with a CentOS box. We need to test three scenarios;

A/ Traffic destined for 100/24
In this test, I will generate some ICMP echo requests from the CentOS box representing the transit provider to 100/24. If our lab is working correctly, I would expect to see this take the RED LSP (the short path).

Let’s clear the LSP stats, run the ICMP echo requests, then re-examine the LSP stats;

[email protected]# run clear mpls lsp statistics
[[email protected] ~]# ping 100.0.0.1 -i 0.01 
PING 100.0.0.1 (100.0.0.1) 56(84) bytes of data.

--- 100.0.0.1 ping statistics ---
5241 packets transmitted, 0 received, 100% packet loss, time 52754ms
[email protected]# run show mpls lsp statistics ingress 
Ingress LSP: 2 sessions
To              From            State     Packets            Bytes LSPname
10.0.0.2        10.0.0.1        Up              0                0 BLUE
10.0.0.2        10.0.0.1        Up           4890           410760 RED
Total 2 displayed, Up 2, Down 0

Great! As expected, traffic is being sent via the RED (short path) LSP.

B/ non-UDP traffic destined for 200/24

In this test, I will generate some ICMP echo requests from the CentOS box representing the transit provider to 200/24. If our lab is working correctly, I would expect to see this take the RED LSP (the short path).

Let’s clear the LSP stats, run the ICMP echo requests, then re-examine the LSP stats;

[email protected]# run clear mpls lsp statistics
[[email protected] ~]# ping 200.0.0.1 -i 0.01 
PING 200.0.0.1 (200.0.0.1) 56(84) bytes of data.

--- 200.0.0.1 ping statistics ---
1447 packets transmitted, 0 received, 100% packet loss, time 14581ms
[email protected]# run show mpls lsp statistics ingress    
Ingress LSP: 2 sessions
To              From            State     Packets            Bytes LSPname
10.0.0.2        10.0.0.1        Up              0                0 BLUE
10.0.0.2        10.0.0.1        Up           1447           121548 RED
Total 2 displayed, Up 2, Down 0

Again traffic is transiting the RED (short path) LSP as expected.

C/ UDP traffic destined for 200/24

In this final test, I will generate some UDP iperf traffic from the CentOS box representing the transit provider to 200/24. If our lab is working correctly, I would expect to see this take the BLUE LSP (the long path).

Let’s clear the LSP stats, run the iperf, then re-examine the LSP stats;

[email protected]# run clear mpls lsp statistics
[[email protected] ~]# iperf -c 200.0.0.1 -u -b 10m -t 30
------------------------------------------------------------
Client connecting to 200.0.0.1, UDP port 5001
Sending 1470 byte datagrams
UDP buffer size:  107 KByte (default)
------------------------------------------------------------
[  3] local 10.1.99.99 port 46896 connected with 200.0.0.1 port 5001
[ ID] Interval       Transfer     Bandwidth
[  3]  0.0-30.0 sec  35.8 MBytes  10.0 Mbits/sec
[  3] Sent 25511 datagrams
[  3] WARNING: did not receive ack of last datagram after 10 tries.
[email protected]# run show mpls lsp statistics ingress    
Ingress LSP: 2 sessions
To              From            State     Packets            Bytes LSPname
10.0.0.2        10.0.0.1        Up          25521         38332542 BLUE
10.0.0.2        10.0.0.1        Up              0                0 RED
Total 2 displayed, Up 2, Down 0

This is taking the long path. All working as expected!

In this article I have attempted to describe how to select LSPs based on traffic and destination route properties. While I’ve used the criterion of UDP traffic aimed at a certain destination, you could of course implement this based on any combination of CoS queue, destination route attributes & traffic properties. This should be a really useful tool to have up your sleeve to meet TE requirements on your network – and something worth knowing for the JNCIE-SP exam.

One thing to note is that while in this article I quickly whipped up an extra CoS queue without any further configuration, beware of doing this in real life – you should to define buffer and transmit rates for schedulers on all interfaces for each queue. I will aim to do another blog post soon digging into this deeper – but for now just a warning (and have a look at the O’Reilly MX book if you want more detail on MX CoS)!

Thanks to Barry Murphy for coming up with this interesting scenario for me to write a post about. Hope this helps!

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!

Confirming IPv6 GRE ToS copy behaviour

One of the fairly simple topics in the JNCIE-ENT syllabus is GRE tunnelling. Or so you would think. When configuring GRE tunnels in JUNOS, there is a nifty little flag which you can enable which copies the contents of the payload’s IP ToS field to the outer header’s IP ToS field;

set interfaces gr-0/0/0 unit 0 copy-tos-to-outer-ip-header

However after doing a bit of googling I found some conflicting sets of documentation on weather this would work for IPv4 payload only or IPv4 & IPv6 payload. I quickly whipped up a lab to prove this out either way (using SRX240’s running 11.4R5.5). I’m documenting this here as I imagine this is a question others may have while preparing for this exam (or for production purposes).

First, it’s worth noting that this lab has been done using 3x SRX240 and 1x EX4200 (configurations for which can be found here). The “VR” devices are two virtual routers on one SRX240.

Image

The GRE tunnel interfaces are configured as below (example from the R2 end);

[edit interfaces gr-0/0/0]
[email protected]# show 
unit 0 {
    tunnel {
        source 192.168.10.1;
        destination 192.168.6.1;
    }
    family inet {
        address 10.0.12.2/24;
    }
    family inet6 {
        address 2001:face:12::2/64;
    }
    copy-tos-to-outer-ip-header;
}

Let’s then configure two firewalls on each of R2 & the EX and apply them inbound on ge-0/0/3.0 of R2 and ge-0/0/10.0 of the EX;

[edit firewall]
[email protected]# show 
family inet {
    filter tos-count {
        term 255 {
            from {
                dscp 63;
            }
            then {
                count 255;
                accept;
            }
        }
        term 0 {
            from {
                dscp 0;
            }
            then {
                count 0;
                accept;
            }
        }
    }
}
family inet6 {
    filter tos6-count {                 
        term 255 {
            from {
                traffic-class 63;
            }
            then {
                count 6-255;
                accept;
            }
        }
        term 0 {
            from {
                traffic-class 0;
            }
            then {
                count 6-0;
                accept;
            }
        }
    }
}

Now for the testing. First we’ll send 1x ICMPv4 and 1x ICMPv6 request with a ToS value of 0 to confirm that nothing too funky is happening;

[email protected]> ping 2001:face:1::2 source 2001:face:2::2 routing-instance VR2 tos 0 count 1
PING6(56=40+8+8 bytes) 2001:face:2::2 --> 2001:face:1::2
16 bytes from 2001:face:1::2, icmp_seq=0 hlim=62 time=4.625 ms

--- 2001:face:1::2 ping6 statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max/std-dev = 4.625/4.625/4.625/0.000 ms

[email protected]> ping 10.0.1.2 source 10.0.2.2 routing-instance VR2 tos 0 count 1                 
PING 10.0.1.2 (10.0.1.2): 56 data bytes
64 bytes from 10.0.1.2: icmp_seq=0 ttl=62 time=3.021 ms

--- 10.0.1.2 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max/stddev = 3.021/3.021/3.021/0.000 ms

Right, now let’s confirm what the devices along the way are seeing the outermost ToS value as in the encapsulated and unencapsulated versions of this traffic;

[email protected]> show firewall   

Filter: __default_bpdu_filter__                                

Filter: tos-count                                              
Counters:
Name                                                Bytes              Packets
0                                                      84                    1
255                                                     0                    0

Filter: tos6-count                                             
Counters:
Name                                                Bytes              Packets
6-0                                                   128                    2
6-255                                                   0                    0
[email protected]> show firewall 

Filter: tos-count                                              
Counters:
Name                                                Bytes              Packets
0                                                     224                    2
255                                                     0                    0

We can see that at both points IPv4 and IPv6 traffic is marked with a ToS value of 0 as expected. Now to set a ToS value of 255 (DSCP 63) and confirm what happens when we set the ToS to a non default value;

[email protected]> ping 2001:face:1::2 source 2001:face:2::2 routing-instance VR2 tos 255 count 1
PING6(56=40+8+8 bytes) 2001:face:2::2 --> 2001:face:1::2
16 bytes from 2001:face:1::2, icmp_seq=0 hlim=62 time=4.897 ms

--- 2001:face:1::2 ping6 statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max/std-dev = 4.897/4.897/4.897/0.000 ms

[email protected]> ping 10.0.1.2 source 10.0.2.2 routing-instance VR2 tos 255 count 1                 
PING 10.0.1.2 (10.0.1.2): 56 data bytes
64 bytes from 10.0.1.2: icmp_seq=0 ttl=62 time=2.466 ms

--- 10.0.1.2 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max/stddev = 2.466/2.466/2.466/0.000 ms

Now let’s have another look to see what ToS value these had at each point;

[email protected]> show firewall    

Filter: __default_bpdu_filter__                                

Filter: tos-count                                              
Counters:
Name                                                Bytes              Packets
0                                                      84                    1
255                                                    84                    1

Filter: tos6-count                                             
Counters:
Name                                                Bytes              Packets
6-0                                                    56                    1
6-255                                                  56                    1
[email protected]> show firewall         Filter: tos-count                                              
Counters:
Name                                                Bytes              Packets
0                                                     224                    2
255                                                   224                    2

And it would seem that the IPv6 traffic is indeed having the ToS values copied to the outer header (note that I didn’t clear this between the ToS 0 and ToS 255 ICMPs).

Hope this helps clear up any confusion!