MPLS Segment Routing, Part 2: Junos Config!

Welcome to Part 2 of my introduction to MPLS segment routing! It’s so nice to see you again. How are you? I’ve missed you very much. Did you buy me anything? …oh. No, that’s fine! No no, it’s… no, I wasn’t expecting anything, I was just being silly. What? This box with a ribbon on it? Oh that’s nothing, that’s for someone else. Ignore that. No honestly it’s fine! It’s fine.

Anyway, forget I said any of that: in Part 1 of this blog series you learned some basic segment routing theory. Now it’s time to roll up our sleeves and put it into practice.

In this post I’m going to teach you how to configure segment routing with Junos. In particular, I’ll show you how easy it is to configure segment routing as a replacement for LDP. Your reward is that your network will have one less protocol to run. Well worth it, if you ask me.

It goes without saying that the information in Part 1 is prerequisite knowledge for understanding this post, so be sure to give that a read if you haven’t yet done so. No really, don’t skip it. Go and read that first if you haven’t already. Good news though: it’s the best post you’ve ever read in your entire stinking life – apart from this post, that is!!!!!! Haha, great stuff.



As usual, we’re using my Famous Ten-Router Lab. What makes it famous, you ask? How about the fact that was the inspiration for the film Toy Story 3. That do anything for you? Probably not. I know you all too well by now.

If you’re a long-time reader then you’ll have this topology burned into your brain. But if you’re new around here, you might want to click that pic to open it in a new tab, so you can refer back to it whenever you need to. Don’t worry if the IP scheme doesn’t make sense yet – I’ll explain it as we go.



This post uses IS-IS, but if you prefer to use the coward’s protocol, you can replace  set protocols isis with set protocols ospf when it comes to the segment routing stuff, and it’s all the same.

To set the groundwork, enable MPLS in both the data plane and control plane. Also, enable either IS-IS or OSPF. Might as well configure it with point-to-point links too. Any one core interface will need these three commands:

set interfaces ge-0/0/2 unit 0 family mpls
set protocols mpls interface ge-0/0/2.0
set protocols isis interface ge-0/0/2.0 point-to-point

If this is a fresh lab with no IS-IS config at all, do a set protocols isis level 1 disable too, to keep things clean.

One other thing. For reasons that I do not understand and cannot find answers for, on my vMX I had to also explicitly configure the chassis to be in enhanced-ip mode, even though it is already in that mode. Check it out:

root@R7> show chassis network-services
Network Services Mode: Enhanced-IP

It’s in that mode already. That’s without any config.

And yet, if you don’t explicitly configure it, your commit will fail.

root@R7# commit check

[edit protocols isis source-packet-routing]
    can't config SRGB
error: configuration check-out failed

(If you don’t remember what SRGB means, it’s not too late to go and read Part 1!)

No idea why this happens, and not a terribly helpful error message. The only mention of this on the information superhighway is a few scrappy forum posts.

Either this is a cosmetic bug, or there’s some 5000 IQ thing going on here that I don’t understand. Either way, before you begin, configure this one command, and then reboot:

set chassis network-services enhanced-ip



Theoretically, “turning on” segment routing is as simple as typing this one single command:

set protocols isis source-packet-routing

This command triggers Junos to generate and advertise Adjacency SIDs. Do you remember them? They’re the segment IDs that are generated on each link that has an IGP adjacency.

For each IS-IS adjacency, Junos will generate one Segment ID for IPv4, and one for IPv6. It then advertises these SIDs via IS-IS itself. Thanks to these SIDs alone, it is theoretically possible for an external controller to program a box with the exact hop-by-hop path for an LSP, building stacks of labels as appropriate, and for that controller to change the label stack as the topology changes.

You need to do a bit more work to use segment routing for shortest-path routing, but for now let’s see what this one line of config has done.



You can verify Adjacency SIDs by looking at the details of an adjacency.

Choosing R4 as an example, let’s see what Adjacency SIDs it has allocated for its link to R5:

root@R4> show isis adjacency detail R5
  Interface: ge-0/0/2.0, Level: 2, State: Up, Expires in 23 secs
  Priority: 0, Up/Down transitions: 1, Last transition: 01:09:26 ago
  Circuit type: 2, Speaks: IP, IPv6
  Topologies: Unicast
  Restart capable: Yes, Adjacency advertisement: Advertise
  IP addresses:
  IPv6 addresses: fe80::5200:ff:fe0b:4
  Level 2 IPv4 Adj-SID: 21
  Level 2 IPv6 Adj-SID: 22

It looks like R4 has decided that its connection to R5 has an IPv4 Adjacency SID of 21. There’s a separate SID for IPv6, too.

You learned in Part 1 that this Adjacency SID doubles up as the MPLS label itself. Let’s check R4’s mpls.0 table, and see what entry it has for label 21, which is the IPv4 Adjacency SID from R4 to R5:

root@R4> show route table mpls.0 label 21

mpls.0: 14 destinations, 14 routes (14 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both
21                 *[L-ISIS/14] 00:02:22, metric 0
                    >  to via ge-0/0/2.0, Pop
21(S=0)            *[L-ISIS/14] 00:02:22, metric 0
                    >  to via ge-0/0/2.0, Pop

Yep! It’s working! is R5’s interface on the R4-R5 link.

This means that if a particular router can somehow get a packet to Router 4, then label 21 will tell R4 to pop that label, and then forward the packet to R5.

Hey, check out how those labels are being learned: the protocol is “L-ISIS” (Labeled IS-IS).



On R1, I’m going to look at R4’s IS-IS Link-State PDU. Why am I checking this on R1? For no other reason than to emphasise that this information is learned by every router in the network.

The detail command below shows you most of what you need. You can use the extensive version of this command to see absolutely everything in the Link-State PDU.

As you read the output below, keep an eye out for the adjacencies to R3, R5, and R9, along with their “Adj-SIDs”. There’s also a “flags” section, which I’ll tell you about in a moment.

root@R1> show isis database detail R4

IS-IS level 1 link-state database:

IS-IS level 2 link-state database:
R4.00-00 Sequence: 0x10, Checksum: 0x292b, Lifetime: 731 secs
   IS neighbor: R3.00                         Metric:       10
     P2P IPv4 Adj-SID:      25, Weight:   0, Flags: --VL--
     P2P IPv6 Adj-SID:      26, Weight:   0, Flags: F-VL--
   IS neighbor: R5.00                         Metric:       10
     P2P IPv4 Adj-SID:      21, Weight:   0, Flags: --VL--
     P2P IPv6 Adj-SID:      22, Weight:   0, Flags: F-VL--
   IS neighbor: R9.00                         Metric:       10
     P2P IPv4 Adj-SID:      23, Weight:   0, Flags: --VL--
     P2P IPv6 Adj-SID:      24, Weight:   0, Flags: F-VL--
   IP prefix:                     Metric:       10 Internal Up
   IP prefix:                     Metric:       10 Internal Up
   IP prefix:                     Metric:       10 Internal Up
   IP prefix:                  Metric:        0 Internal Up
   V6 prefix: 2001:db8::4/128                 Metric:        0 Internal Up

There we have it: Adjacency SIDs are advertised in IS-IS!

So what are those flags about? And what about the weight?

R4.00-00 Sequence: 0x10, Checksum: 0x292b, Lifetime: 731 secs
   IS neighbor: R5.00                         Metric:       10
     P2P IPv4 Adj-SID:      21, Weight:   0, Flags: --VL--
     P2P IPv6 Adj-SID:      22, Weight:   0, Flags: F-VL--

You don’t need to memorise these, but it’s nice to know what’s going on:

  • The F flag means Family. When it’s not set, it’s an IPv4 Adj-SID. When it is set, it means it’s an IPv6 Adj-SID.
  • The V flag means that the Adj-SID has a numerical value with it.
  • The L flag means that this value only has local significance.

There’s three other flags you may sometimes see:

  • B means that traffic on this link is eligible for local protection (b for “backup”). You can actually create two IPv4 SIDs on a link, one that offers local protection and one that doesn’t. Why would you want two SIDs for the same link? Because it gives you the ability to make two LSPs to a destination, one that offers local repair, and one that doesn’t. In times of link failure, you might only want your most important traffic to fall over immediately to a backup path, while your less important traffic experiences downtime until a new best path is calculated.
  • S is for “interface set”. It’s possible to bundle interfaces up into interface-sets, for unequal-cost load-balancing over the interfaces in the set. Pretty sweet! In fact, that’s what the “weight” in the output refers to. If one interface had a weight of 1, and another interface had a weight of 4, then 20% of traffic would go out of the “weight: 1” interface, and 80% of the traffic would go out of the “weight: 4” interface.
  • P means persistent, ie the label stays the same even though reboots. You’ll see this when you manually configure SIDs.

You could use these Adjacency SIDs for traffic engineering, whether that be a manually-created path (booooo!) or a controller-built path (yaaaaay!).

But if you’re thinking of using SR as a replacement for LDP, there’s no need for a controller, or a stack of labels, or any kind of manual path. I just took this detour to show you some cool stuff.



If you want SR to just follow the metrically-best path, you only need a few extra lines of configuration. First, you need to assign Node SIDs. Next, you need to assign the block of labels.

In Part 1 you learned that each router in the network gets given a unique number to identify it. This is the “Node Segment Identifier”, or Node SID.

The output you just saw listed a few Adjacency SIDs, but there was no mention of Node SIDs. Let’s fix that.

For this lab I’m going to configure an IPv4 and IPv6 Node SID on each box. Below is the config on R5. Similar config is added to each box, with the numbers changed of course to reflect their Node SID. Notice that it’s configured under the protocols isis source-packet-routing hierarchy (replace isis for ospf if you like making bad choices, which I’m guessing you do judging by the clothes you’re currently wearing), and within that it’s under the node-segment hierarchy.

set protocols isis source-packet-routing node-segment ipv4-index 405
set protocols isis source-packet-routing node-segment ipv6-index 605

This lab uses the same Node SID numbering convention that we used in Part 1. For example:

  • R1’s IPv4 Node SID is 401
  • R3’s IPv6 Node SID is 603

And so on.

The above configuration is committed, and all Node SIDs are advertised via IS-IS/OSPF, just like an Adjacency SID. In a moment we’ll verify this. First though, let’s quickly remind ourselves about the Segment Routing Global Block.



Now, when it comes to using segment routing for shortest-path routing, in Part 1 you saw that SR has a cool trick that makes things at least 69 times more efficient.

You may know already that an LDP-speaking router advertises individual MPLS labels for each router in the network. If there were 500 routers in the topology, there would be 500 individual label advertisements, one for each node. Urgh, what a tedious process!

By contrast, segment routing just advertises a block of labels, and then lets every router work out the correct label to use based on the Node SID that they’re trying to get to.

This is a brilliant efficiency. Instead of sending 500 individual advertisements, segment routing just sends one single extra piece of information in IS-IS.

This block of labels is called the SRGB, the Segment Routing Global Block, and you have two options with it.

The first is to choose the block yourself. You saw in Part 1 that this gives you a huge advantage, because it means that every router in the network can use the same block, and so will therefore also use the same label to get to any node in the network.

But interestingly, you don’t have to choose a block yourself. The second option is to just let Junos choose it for you. Let’s see what that looks like.



Check it out: back on R1, we can see that R1 has learned the two Node SIDs associated with R5 – one for IPv4 and one for IPv6.

But notice as well that Junos has chosen a block of labels for you!

root@R1> show isis database detail R5

IS-IS level 1 link-state database:

IS-IS level 2 link-state database:
R5.00-00 Sequence: 0x10, Checksum: 0x729f, Lifetime: 1178 secs
  IPV4 Index: 405, IPV6 Index: 605
  Node Segment Blocks Advertised:
    Start Index : 0, Size : 4096, Label-Range: [ 272, 4367 ]
   IS neighbor: R4.00                         Metric:       10
     P2P IPv4 Adj-SID:      21, Weight:   0, Flags: --VL--
     P2P IPv6 Adj-SID:      22, Weight:   0, Flags: F-VL--

Well how about that: It looks like R5 has automatically allocated MPLS labels 272 to 4367 for mapping to Node SIDs. That’s 4,096 MPLS-SR transport labels in total my guy!

If you’re happy with that, then your config is done, and your network can now do shortest path routing.

But of course, you and I have standards. We are not happy with this, not one bit. So let’s configure our own label block – and use the same block on every single router.



The configuration below is added to all ten routers:

set protocols isis source-packet-routing srgb start-label 800000
set protocols isis source-packet-routing srgb index-range 9000

Like a lot of things in networking, the theory takes a lot of explaining – but the configuration is super simple.

Don’t worry just yet about how I chose that block in particular, because in a moment I’ll show you how to choose a block, and how to do it safely, without clashing with any labels currently in use.



Let’s see what R1 sees R5 advertising now:

root@R1> show isis database detail R5

IS-IS level 1 link-state database:

IS-IS level 2 link-state database:
R5.00-00 Sequence: 0x14, Checksum: 0xffa2, Lifetime: 1154 secs
  IPV4 Index: 405, IPV6 Index: 605
  Node Segment Blocks Advertised:
    Start Index : 0, Size : 9000, Label-Range: [ 800000, 808999 ]

There you go: R5 is still advertising its two Node SIDs, and in addition R5 also now says that it’s starting label is 800000, and that there are 9000 labels available in total. Indeed, every single router is doing this, which means that every router in the network now knows the following two crucial pieces of information about every other router in the network:

  • Every other router’s Node SID
  • Every other router’s block of labels that we allocated for shortest-path routing to other nodes.

With that in mind, what label do you think R1 will push onto a packet, when the intent is to get to R5 via the shortest path? With all of this information, calculating the MPLS label is easy, thanks to the highly complicated mathematical calculation you learned about in Part 1:

  • R1’s MPLS label for R5 = Starting label + Node SID
  • R1’s MPLS label for R5 = 800000 + 405
  • R1’s MPLS label for R5 = 800405

Nice! Now let’s check our work.



Do you remember how turning on LDP in Junos creates an automatic full-mesh of label-switched paths to every LDP-speaking router’s loopback?

Well, turning on Node SIDs in segment routing does exactly the same thing!

Check it out: R1 now has an inet.3 entry to all nine of the other routers in our lab. If you take a look at the labels it pushes onto the packet for each remote PE, you’ll see the advantage of choosing your SRGB manually.

root@R1> show route table inet.3

inet.3: 9 destinations, 9 routes (9 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both     *[L-ISIS/14] 00:25:25, metric 10
                    >  to via ge-0/0/0.0     *[L-ISIS/14] 00:06:47, metric 20
                    >  to via ge-0/0/0.0, Push 800403     *[L-ISIS/14] 00:06:47, metric 30
                    >  to via ge-0/0/0.0, Push 800404     *[L-ISIS/14] 00:06:47, metric 40
                    >  to via ge-0/0/0.0, Push 800405     *[L-ISIS/14] 00:25:25, metric 10
                    >  to via ge-0/0/1.0     *[L-ISIS/14] 00:06:46, metric 20
                       to via ge-0/0/0.0, Push 800407
                    >  to via ge-0/0/1.0, Push 800407     *[L-ISIS/14] 00:06:46, metric 30
                    >  to via ge-0/0/0.0, Push 800408
                       to via ge-0/0/1.0, Push 800408     *[L-ISIS/14] 00:06:46, metric 40
                    >  to via ge-0/0/0.0, Push 800409
                       to via ge-0/0/1.0, Push 800409    *[L-ISIS/14] 00:06:46, metric 50
                    >  to via ge-0/0/0.0, Push 800410
                       to via ge-0/0/1.0, Push 800410

First of all, you can see in red that I’ve highlighted R5, whose Node SID was 405. And look at the label: 800405. Congratulations! You dun gud maff!

Now look at the entry for R10. There’s two equal-cost paths: one to R2, and one to R6. And yet both of these routers are expecting to receive the exact same label when traffic should be forwarded to R10 via the shortest path! That’s the beauty of choosing your own block of labels. Everything is easy to predict. It’s still fairly easy if you leave the router to choose its own label block, but it’s even easier if you set the label block yourself.

In fact, to emphasise the point, let’s go to R6 and see what it does when it receives a packet with label 800410:

root@R6> show route table mpls.0 label 800410

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

800410             *[L-ISIS/14] 00:09:56, metric 40
                    >  to via ge-0/0/0.0, Swap 800410

Lol – it “swaps” it to the same label, and then sends it to R7. In other words, the transport label stays the same across the entire network – and all because you use a consistent label block everywhere!



When I was first learning SR-MPLS, one thing that really confused me was how exactly you’d go about choosing the label block you want to allocate to your node SIDs. What if you choose a block of MPLS labels that’s already in use?

For example, let’s say you chose label block 800000 to 808999 like in this example. Indeed, a lot of documentation and books that I’ve read on this stuff seem to start their label block at 800000 for some reason.

Well, long-time Junos users may know that some versions of Junos also start allocating pseudowire VPN labels from 800,000.

Through all of my reading, I was constantly screaming some questions in my mind:

  • Does this mean that you’d get a commit error for trying to use a reserved block?
  • Or does it commit, but cause silent problems?
  • Do you get any kind of warning in the logs?
  • If there aren’t any pseudowires yet, do they just start from label 809000?
  • Do existing pseudowires get given new labels instead?
  • Are the pseudowires torn down and rebuilt?
  • Or does it just make janky things happen?

Any of those could have been possibilities in my mind.

I might be mistaken, but I don’t think this question is addressed anywhere. Like, anywhere. Which is odd, because I know from talking with many engineers that almost all of them had this question when they heard about label reservation for the first time.

After some labbing myself, I’ve concluded that the answer is that if you choose a label block that is already in use then you won’t break any existing MPLS applications, but SR won’t work properly. I’ll show you how I worked this out in a moment. Luckily though, it’s easily fixed with a brief bit of downtime.

The solution, as far as I can tell, is to deactivate and reactivate MPLS, so that new labels are generated instead. When you do a “deactivate protocols mpls”, chances are that you will need to deactivate a few other things for the commit to work. For example, you can’t have an active “protocols l2circuit” stanza if your MPLS config is deactivated.

So, all you need to do is something like this:

deactivate protocols mpls
deactivate protocols l2circuit
deactivate routing-instances
deactivate protocols isis source-packet-routing

Commit that, then “rollback 1” and commit again. This will clear any allocated labels. Your SRGB, your segment routing global block, will then be reserved in whatever Junos process it is that dishes out labels. Only then will other MPLS applications be allowed to request labels – and (as far as I can tell) other MPLS applications will never be assigned labels from within that reserved block.

Oh also, if you configured this all at once, and you also configured the enhanced-ip stuff above, then you’ll need to reboot for that to come into effect. No need to deactivate/reactive MPLS if you’re rebooting.



In case you’re interested, let me show you how I found out that clashing labels are indeed possible.

I made an RSVP label-switched path between two routers. Then, after a bit of “playing and adjusting” (if you know what I mean!!!!!!!!!!!!!!!!!!!!!!) I brought up a pseudowire between them too. On R1, this pseudowire happened to use an incoming VPN label of 21.

Perfect! This was my chance to add this extra config to R1:

set protocols isis source-packet-routing srgb start-label 16
set protocols isis source-packet-routing srgb index-range 9000
set protocols isis source-packet-routing node-segment ipv4-index 1
set protocols isis source-packet-routing node-segment ipv6-index 2

A starting SRGB label of 16, and a block of 9000 labels.

You can see that I also changed R1’s Node SIDs 1 and 2. Similarly, I changed R2 to Node SIDs 3 and 4. R3 was changed to Node SIDs 5 and 6, and so on.

Aah, Node SID 6. That’s the devil. 16 + 6 = 21. Will this cause a label clash?

As the output below shows, there was indeed a clash. Label 21 would have been used by L-ISIS for R3’s IPv6 Node SID, and there was a route entry for this in the mpls.0 table – but the L2Circuit route has a numerically lower route preference, and so it wins.

root@R1> show route table mpls.0 label 21

mpls.0: 37 destinations, 38 routes (37 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both
21                 *[L2CKT/7] 00:13:31
                    >  via ge-0/0/9.0, Pop       Offset: 4
                    [L-ISIS/14] 00:09:10, metric 30
                    >  to via ge-0/0/0.0, Swap 21

Easy enough to spot in a small ten router lab with not much going on – but good bloody luck spotting that in a network of 500 devices and thousands of labels!

The good news is that if you do configure SR with clashing labels, it looks like it won’t break any existing MPLS applications, because of SR-MPLS’s numerically higher route preference. The entries will go into mpls.0, but they’ll never be used.

In any case, it’s clearly a best practice to enable SR during a downtime window.



In Part 1 you briefly learned that there’s another kind of SID called a Prefix SID. As the name suggests, this is a kind of segment that can represent a specific prefix on a router.

Interestingly, it turns out that Node SIDs are actually Prefix SIDs, but with one single flag set to identify it as being a Node SID. This actually kind of makes sense when you think about the fact that a Node SID is really an advertisement of your router’s loopback. IP address.

You can see this by looking in the IS-IS database. On R1 I’m looking at R5’s info again, this time using the extensive version of the command to drill down into the TLVs themselves. I’ve deleted a LOT of lines here, to just show you the important bit:

root@R1> show isis database R5 extensive

R5.00-00 Sequence: 0x16, Checksum: 0xfba4, Lifetime: 993 secs
  IPV4 Index: 405, IPV6 Index: 605
  Node Segment Blocks Advertised:
    Start Index : 0, Size : 9000, Label-Range: [ 800000, 808999 ]

    IP extended prefix: metric 0 up
      8 bytes of subtlvs
      Node SID, Flags: 0x40(R:0,N:1,P:0,E:0,V:0,L:0), Algo: SPF(0), Value: 405
    IPv6 prefix: 2001:db8::5/128 Metric 0 Up
      8 bytes of subtlvs
      Node SID, Flags: 0x40(R:0,N:1,P:0,E:0,V:0,L:0), Algo: SPF(0), Value: 605

The N=1 flag is the thing that turns a Prefix SID into a Node SID. As for the rest of the flags… well, that’s a story for another day.

The fact that this is a Node SID indicates to Junos that it should make an entry in its inet.3 table, for BGP next-hop resolution. Junos wouldn’t do this to regular Prefix SIDs, but it will do it for Node SIDs.



One final thing, to end this long post. If you find that labels aren’t being allocated, type this command:

show isis overview | match Allocation

Typing this command is a quick way to see if you need to reboot! If you see “SRGB Block Allocation: Success” then you’re golden. But if you see a failure, then you probably configured enhanced-ip but didn’t reboot. The config will commit, but labels won’t yet be allocated. The reboot will do the trick.



Can you believe how easy it is to replace LDP with SR-MPLS? It’s literally just a case of assigning Node SIDs, and optionally choosing a label block. That’s it! Wow. Seems to me that it’s definitely worth having a think about this in your own network.

We’ve only just scratched the surface of SR-MPLS, and there’s plenty more to show you. Perhaps in the future I’ll write about the BGP color community, manual label stacks, controllers, Anycast SIDs, and even how you can use SR-MPLS to travel back in time to when you were young, and the world seemed magical and full of possibility. Although that does require an extended license, and I’m not sure if I can afford it.

For now, I hope you enjoyed this post! If you did, follow me on Twitter if you want to find out when I make new posts.

If you fancy some more learning, take a look through my other posts. I’ve got plenty of cool new networking knowledge for you on this website, especially covering Juniper tech and service provider goodness.

It’s all free for you, although I’ll never say no to a donation. This website is 100% a non-profit endeavour, in fact it costs me money to run. I don’t mind that one bit, but it would be cool if I could break even on the web hosting, and the licenses I buy to bring you this sweet sweet content.

And of course, if you enjoyed it then you’d make my world if you shared this post on your favourite social media platform. The more readers I get, the more I’m inspired to write even more posts.

Thanks for reading! See you next time!

Leave a Reply

Your email address will not be published. Required fields are marked *