This is a post about the different ways, and reasons why, we might move prefixes between the inet.3 and inet.0 tables on a Juniper router. You know: like George Clooney does in his spare time. Probably. Don’t look that up.

If you’re not sure what the inet.3 table actually is, then give Part 1 of this post a read, where I explain how BGP uses it to resolve next-hops. Don’t worry: take your time reading it. I’ll wait. No rush: I’ve got a nice cup of hot chocolate to drink.

…aah, you’re back! So, now you’re curious: is there a way to make other traffic go down an LSP, besides BGP-learned routes? And are there any unintended consequences of manipulating this behaviour?

The answer to those questions is “yes”, and “oooooh yes”.

In this post, we’re going to take a deep dive into some of the different options available to us, for transferring prefixes between inet.3 and inet.0. We’ll see what happens when we put this into action, we’ll talk about the side-effects, and we’ll even talk about what we can do to get around the problems we might have caused.

But before we start, there’s something you absolutely have to understand: next Wednesday I plan to be fully nude for 24 hours, for charity. Please send me £100 to support my brave, generous action. All profit will go to an organisation that teaches dogs how to perform basic to intermediate level heart surgery.



Take a look at this beautiful topology. We actually used this in part 1. We have LDP everywhere, and in addition there’s an RSVP LSP from R1 straight to R3, and another on R3 back to R1. You can see that R3 has an eBGP peering to R6, from which it’s learning a prefix: Nice.

Let’s remind ourselves of what happens by default: R3 connects to R6 via a link with the IP address This means that when R3 receives the (nice) advertisement, and re-advertises it by iBGP to its best friends in network AS12345, R3 does NOT change the next-hop. The next-hop remains – the interface IP of Router 6.

Now, this may or may not be a problem. If all the routers in your AS know how to get to, it’s all good. But some ISPs might consider the connection between R3 and R6 to be considered “outside” of their own AS. And, as such, this link WON’T be a part of their OSPF or IS-IS, and it WON’T be redistributed in.

This is where our famous next-hop-self command comes in: before R3 advertises (nice) into AS12345, it changes the next hop to itself, ie Now, all the routers in our AS know how to resolve the next-hop. Plus, it means that we can use our RSVP LSP: R1 sees the next-hop of, sees that there’s an entry in inet.3 for this BGP next-hop, and then pushes the traffic down the label-switched-path.

Imagine this scenario though: what if all of the routers in AS12345 *did* know how to get to What if we actually were redistributing this into OSPF or IS-IS? In a way, our network would actually be simpler, because we wouldn’t have to remember to do the next-hop-self command everywhere.

But, there’s a downside. We’re not running LDP or RSVP between ourselves and this other internet provider, whose AS number is 69 (nice). That means there’s going to be no entry for in our inet.3 table. In other words, this would be what happens:

— Router 1 looks up this prefix
— Sees a protocol next-hop of
— Looks in inet.3 for this IP address
— Finds nothing
— So falls back to the normal inet.0 table
— Resolves this IP in there instead
— And sends the packet out as a normal, unlabelled packet

Which is probably the exact opposite of what you want to happen.

Remember: for traffic to go down an LSP, by default the BGP protocol next-hop *has* to be in inet.3 – and the interface IP address of R1’s iBGP neighbour’s eBGP neighbour – – certainly won’t be in there.

That is… unless we put it in there ourselves? Gosh, how naughty! Whatever will mother say? Don’t tell the police!!

The syntax is easy as pie: just use the install command to associate the next-hop IP with the LSP you’ve made!

root@Router1> show configuration protocols mpls
label-switched-path TO_ROUTER_3 {

Now, is in our inet.3 table, so any prefixes that we learn by BGP, with a next-hop of, will go down our LSP!

And hey: if you actually want traffic destined *to* to go down the LSP as well, all you have to do is add the word “active” to the end of the install command. In other words, “install active“. This will actually put the prefix in inet.0, with a next-hop of the LSP. The prefix will no longer be in inet.3 – but that’s okay, because Junos can use both inet.3 AND inet.0 to resolve BGP next-hops. It just prefers inet.3 if there’s a tie-break.

ADVANTAGE: Gives you the most precision over what goes where.

DISADVANTAGE: This is basically a static route, so it’s not very scalable.



If we like, we can make OSPF or IS-IS believe that our LSP is an actual link, directly connecting the two routers at either end. All you have to do is make LSPs in both directions, then add the LSPs into your IGP, with a metric of your choice. The syntax couldn’t be simpler:

set protocols isis label-switched-path TO_ROUTER_3 level 2 metric 1


set protocols ospf area label-switched-path TO_ROUTER_3 metric 1

That’s it! You’ll now see the router at the other end of the LSP in your adjacencies:

root@Router1> show isis adjacency
Interface            System     L State   Hold (secs)  SNPA
TO_ROUTER_3          Router3    2   Up    0
em0.0                Router2    2   Up    19           8:0:27:51:a:7a
em1.0                Router4    2   Up    19           8:0:27:8a:2f:26

You’ll see the LSP being used in SPF calculations:

root@Router1> show isis spf brief
 IS-IS level 1 SPF results:
  0 nodes

 IS-IS level 2 SPF results:
Node          Metric    Interface   NH     Via            SNPA
Router4.02    20        em1.0       IPV4   Router4        8:0:27:8a:2f:26
Router5.00    11        em0.0       LSP    TO_ROUTER_3
Router5.02    11        em0.0       LSP    TO_ROUTER_3
Router2.02    11        em0.0       LSP    TO_ROUTER_3
Router4.00    10        em1.0       IPV4   Router4        8:0:27:8a:2f:26
Router2.00    10        em0.0       IPV4   Router2        8:0:27:51:a:7a
Router1.03    10
Router1.02    10
Router3.00    1         em0.0       LSP TO_ROUTER_3
Router1.00    0
10 nodes

And we can see from our routing table that IS-IS treats the LSP just like an available link. I gave this “link” a metric of 1, which gives us a total metric of 11. You can see that this is preferred over the non-labelled R1-R2-R3 path, which itself has a metric of 20.

root@Router1> show route

inet.0: 15 destinations, 15 routes (15 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both         *[IS-IS/18] 00:16:36, metric 11
                    > to via em0.0, label-switched-path TO_ROUTER_3

ADVANTAGE: Gives you even more control over link cost than you had without it.

DISADVANTAGE: Potential for inefficient paths to be preferred over shorter paths, depending on how the LSP is being formed.



R1 has an LSP to R3. As we know, this means that traffic with a BGP next-hop of will go down the LSP. But what if you also want all network traffic destined to itself to go down the LSP? Is there such a command to do that? Well, in fact, there’s a few different ways, starting with this:

set protocols mpls traffic-engineering bgp-igp

This one command moves – not copies, but moves – the contents of inet.3 into inet.0. LSPs will still be used to resolve BGP next-hops – remember, BGP can use both tables, it just prefers inet.3. But now, all your other traffic gets to use the LSP as well!

First, notice that that our inet.3 table is now empty:

root@Router1> show route table inet.3


Next, notice that everything is in inet.0 – and because RSVP and LDP have lower route preferences than IS-IS, our router is choosing these routes over our IGP.

root@Router1> show route table inet.0

inet.0: 15 destinations, 20 routes (15 active, 1 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both         *[Direct/0] 14:21:28
                    > via lo0.0         *[LDP/9] 00:00:09, metric 1
                    > to via em0.0
                    [IS-IS/18] 00:00:10, metric 10
                    > to via em0.0         *[RSVP/7/1] 00:00:10, metric 20
                    > to via em0.0, label-switched-path TO_ROUTER_3
                    [LDP/9] 00:00:10, metric 1
                    > to via em0.0, Push 299952
                    [IS-IS/18] 00:00:10, metric 20
                    > to via em0.0

This is pretty cool stuff. But you might be wondering: if this is so cool, why isn’t this the default? Why is it that only BGP traffic gets to use the LSP by default? A good question, with a simple answer: moving everything out of inet.3 breaks your ability to run MPLS VPNs.

Don’t worry though, there’s a way to fix it. Keep reading!

ADVANTAGE: Only one command to give every non-VRF prefix access to the LSP.

DISAVANTAGE: Breaks your ability to do MPLS VPNs.

PLEASE NOTE: My grandfather taught me this command back in the year 1875. He made me promise on my life I’d never tell anyone. Well, we all know that promises only have a lifetime of 140 years, so now I’m prepared to tell you everything.



This command does the same as the one above, but instead of moving the contents of inet.3 to inet.0, it copies it over:

set protocols mpls traffic-engineering bgp-igp-both-ribs

This means that your normal prefixes can use the LSP, and also you can still run MPLS VPNs!

If we do a lookup in Router 1’s routing tables for Router 2’s loopback, we see an LDP entry in both inet.0 and inet.3:

root@Router1> show route

inet.0: 15 destinations, 20 routes (15 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both         *[LDP/9] 00:00:18, metric 1
                    > to via em0.0
                    [IS-IS/18] 00:03:01, metric 10
                    > to via em0.0

inet.3: 4 destinations, 5 routes (4 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both         *[LDP/9] 00:00:18, metric 1
                    > to via em0.0

Okay, so again you might be wondering: why isn’t *this* the default? This seems like the best of both worlds. Well, as with all of these solutions, there’s a downside.

When you activate this command, and you make an LSP the preferred route in your inet.0 table, this can seriously break your IGP. In short, your IGP routes are no longer the “active” route, because now our LSP is the best route instead – and if our “normal” routes are no longer the best, this might stop them from being distributed properly. Luckily though, there’s a fix for that too.

ADVANTAGE: Gives you loads of functionality, including MPLS VPNs.

DISADVANTAGE: Can screw up your routing policies.

PLEASE NOTE: My grandfather’s grandfather told me about this command, and he made me swear to tell absolutely every single person I met about it. Up until now I’ve disobeyed him, because – and here’s the twist – my grandfather’s grandfather was Vlad the Impaler, the 15th century villain and archetypal rotter. No way was I honouring his requests! But I guess it’s okay to tell you about it this one time.



What if I told you there was a command that copied LSPs into inet.0 for forwarding, but didn’t use these LSPs when it came to making routing protocol decisions – and that this command also kept the IP in inet.3 as well, for VPN use? Well, consider today a birthday and Christmas combined, with this final command:

set protocols mpls traffic-engineering mpls-forwarding

This command allows your router to choose LSPs for forwarding traffic, but ignore them when it comes to the way the router advertises prefixes into your IGP. Take a look at this output, and notice a few new symbols in the legend, like the @ and # signs. This shows us that traffic will be forwarded down the LSP, but IS-IS still uses its own “best” path for a consistent IS-IS topology.

root@Router1> show route

inet.0: 15 destinations, 20 routes (15 active, 1 holddown, 0 hidden)
@ = Routing Use Only, # = Forwarding Use Only
+ = Active Route, - = Last Active, * = Both        @[IS-IS/18] 00:09:20, metric 20
                   > to via em1.0
                  #[LDP/9] 00:05:47, metric 1
                   > to via em1.0, Push 300016

inet.3: 4 destinations, 5 routes (4 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both        *[LDP/9] 00:05:47, metric 1
                   > to via em1.0, Push 300016

So, yet again, you might be wondering: okay, this really does sound perfect. Why isn’t THIS the default? Well, it sure is good, but the problem is that it’s an all-or-nothing approach. This command copies everything into inet.0, which doesn’t give you much control over precisely what goes in. If you do want everything to go in, great! But in an ISP-sized network, you possibly don’t. When you think of it like that, it’s a little easier to see why this isn’t the default behaviour – no matter how “romantically attractive” it might seem.

ADVANTAGE: Lets you copy inet.3 to inet.0 without it affecting your IGP’s routing decisions.

DISADVANTAGE: Doesn’t give you much granularity on choosing exactly what traffic should take your LSP.

PLEASE NOTE: I am famous for being a traditionally handsome Hollywood hunk.



There’s a related but different problem that you might be interested in.

Imagine that you’ve got a route reflector that isn’t in the forwarding path of your traffic, and you’re advertising MPLS VPN prefixes to this route reflector. And, imagine that you’re not running MPLS on this router. After all, why burden a route reflector with the need to distribute labels, when the router isn’t actually forwarding any traffic?

But, we have a problem: if we’re not running MPLS on the route reflector, then its inet.3 table will be empty. And if our route reflector can’t resolve the next-hop of the MPLS VPN prefixes in the inet.3 table, it won’t reflect our prefixes.

This is so easy to forget: route reflectors don’t just automatically reflect everything they learn. If a route reflector receives a prefix that it doesn’t consider valid – because, for example, it can’t resolve the next-hop – it won’t reflect the prefix.

There’s a variety of solutions to this, many of which involve telling your Juniper router which routing table to use to resolve these prefixes. For example, using a rib-group, or using the command “resolution rib”, you can manipulate the router into either using a different table to resolve the prefixes, or tell it to copy just a small number of next-hop IPs from inet.0 to inet.3.

Now, think of the consequences of doing this. Normally, when we look up a next-hop in inet.3, this next-hop will come with some kind of label. So if we’re copying next-hops from inet.0 to inet.3, what label is being used? Well, in fact, there isn’t any label! If our route reflector was actually forwarding traffic, this solution wouldn’t work.

But, our route reflector isn’t forwarding traffic. In effect, we’ve kind of tricked our router into thinking it can “resolve” the next-hop, when it actually can’t. But it doesn’t matter: the next-hop is in inet.3, and that’s good enough for our gullible route reflector to reflect the route on to a router that actually can forward this traffic. Sssssh, don’t tell the route reflector! It’ll feel embarrassed if it finds out the truth!

The commands are cool and funky, and luckily the awesome folks over at inetzero have written a brilliant deep-dive on exactly this, with five different solutions to this problem. Click here to give it a read, and to see a whole heap of examples, and take your inet.3 knowledge to the next level.

So, that’s it! I hope you learned a thing or two from this post, or maybe remembered some things you’d forgotten.

If you’re on Mastodon, follow me to find out when I make new posts. (2024 edit: I’m also on BlueSky nowadays too. I was once on Twitter, but I’ve given up on it, on account of… well, I don’t need to finish that sentence, do I.)

You’d make my day/week/year if you shared this post on your social media of choice, so more people will see it and read it. And 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.


  • April 10, 2019 at 12:53 am

    Hello Chris,

    Just started following you on Twitter. Wondering what you use to lab MPLS Juniper networks? I use GNS3 but have found that the forwarding plane craps out on me. I get as far as having my VRFs exchanging routes but cannot manage to ping using mpls so that I can actually see the labels.

    Thoughts, suggestions, ideas?

    • May 12, 2019 at 5:27 pm

      Hi Diego!

      Oh that’s strange, I’ve personally never found a problem like that in GNS3. If your VRFs are exchanging routes then they should be exchanging labels too. What happens when you look in the inet.3 or mpls.0 table? Do you see anything in there?

      For what it’s worth, my friend James has recently made a post on how to install EVE-NG and run Junos on it. I use EVE now, and it’s so much nicer! Very pretty, very nice network diagrams, all done through a web browser.

  • August 8, 2019 at 3:57 am

    Very nice post Chris. It cleared some doubts about inet3. BTW I am a big fan of EVE as well now and have used it to simulate some networks and even integrated with physical networks for hardware not virtually feasible.


    • August 11, 2019 at 12:07 pm

      Good work! And thank you for the kind words, I’m really glad you found it helpful 🙂

  • June 5, 2022 at 5:08 pm

    Fantastic post!
    Sadly, the article in the inetzero site is not longer there or was moved.
    Thanks for sharing!


Leave a Reply

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