Tip

This is the documentation for the 25.06 version. Looking for the documentation of the latest version? Have a look here.

Routing IPv4 Traffic Through Unnumbered Interfaces

Unnumbered interfaces can process IPv4 packets without having an IPv4 address present on the interface. Unnumbered interfaces “borrow” the IPv4 address from another interface for routing purposes. Depending on the configuration style, the borrowed address may or may not be used directly as a routing destination.

Warning

The best practice for maximum stability is to borrow an IP address from a loopback interface. Loopback interfaces will always be up and able to process traffic, where other interfaces may be down and unable to process if they lose link, for example.

Unnumbered interfaces are useful on large and complex deployments where having to allocate, assign, and otherwise manage unique transit networks for every point-to-point interface can be a significant burden.

This technique is primarily used with point-to-point tunnel interfaces, such as GRE or IPIP. While this technique can work with Ethernet interfaces, doing so involves additional complications.

Note

Though this recipe covers GRE, IPIP, and Ethernet interfaces, the GRE example will contain additional explanations and context. Read the GRE example first before looking at the other examples.

Required Information

These tables contain general information about the two nodes involved in this unnumbered routing example.

Example Unnumbered Routing Configuration for R1

Item

Value

R1 WAN IP Address

203.0.113.2/24

R1 LAN Subnet

10.2.0.0/24

R1 LAN IP Address

10.2.0.1

R1 Loopback Instance

0 (loop0)

R1 Loopback Address

10.2.10.1/32

Example Unnumbered Routing Configuration for R2

Item

Value

R2 WAN IP Address

203.0.113.30/24

R2 LAN Subnet

10.30.0.0/24

R2 LAN IP Address

10.30.0.1

R2 Loopback Instance

0 (loop0)

R2 Loopback Address

10.30.10.1/32

GRE Example

This example demonstrates using a GRE tunnel between two hosts, R1 and R2, with the GRE interface being unnumbered.

Configure R1

First configure a loopback instance. This creates the loop0 interface where the local routing address will reside.

r1 tnsr(config)# interface loopback routing
r1 tnsr(config-loopback)# instance 0
r1 tnsr(config-loopback)# exit

Next, enable the loop0 and assign an IP address:

r1 tnsr(config)# interface loop0
r1 tnsr(config-interface)# ip address 10.2.10.1/32
r1 tnsr(config-interface)# enable
r1 tnsr(config-interface)# exit

Note

Even when repeating this example with multiple unnumbered tunnel interfaces, only this single loopback is necessary. Every unnumbered tunnel can borrow its address from this one loopback.

Create a GRE tunnel interface instance between R1 and R2:

r1 tnsr(config)# gre toremote
r1 tnsr(config-gre)# instance 0
r1 tnsr(config-gre)# source 203.0.113.2
r1 tnsr(config-gre)# destination 203.0.113.30
r1 tnsr(config-gre)# exit

See also

GRE Interfaces

Enable the GRE interface and configure it as unnumbered, borrowing from the loop0 interface:

r1 tnsr(config)# interface gre0
r1 tnsr(config-interface)# ip unnumbered loop0
r1 tnsr(config-interface)# enable
r1 tnsr(config-interface)# exit

This is an optional route to the remote loopback address. This can be used for diagnostic purposes, but is generally unnecessary.

r1 tnsr(config)# route table default
r1 tnsr(config-route-table)# route 10.30.10.1/32
r1 tnsr(config-rttbl4-next-hop)# next-hop 0 via 0.0.0.0 gre0
r1 tnsr(config-rttbl4-next-hop)# exit
r1 tnsr(config-route-table)# exit

Note

The via 0.0.0.0 indicates that the interface itself is the destination, in this case gre0. This tells the dataplane to send traffic for this destination through this interface without a specific destination address.

See also

Managing Routes

Finally, add a route to the remote LAN subnet at R2 using the same interface route method:

r1 tnsr(config)# route table default
r1 tnsr(config-route-table)# route 10.30.0.0/24
r1 tnsr(config-rttbl4-next-hop)# next-hop 0 via 0.0.0.0 gre0
r1 tnsr(config-rttbl4-next-hop)# exit
r1 tnsr(config-route-table)# exit

Configure R2

On the other router the procedure is the same, but substituting the relevant parameters along the way.

Create the R2 loopback instance:

r2 tnsr(config)# interface loopback routing
r2 tnsr(config-loopback)# instance 0
r2 tnsr(config-loopback)# exit

Enable and configure the R2 loopback interface:

r2 tnsr(config)# interface loop0
r2 tnsr(config-interface)# ip address 10.30.10.1/32
r2 tnsr(config-interface)# enable
r2 tnsr(config-interface)# exit

Create the GRE interface from R2 to R1:

r2 tnsr(config)# gre tohq
r2 tnsr(config-gre)# instance 0
r2 tnsr(config-gre)# source 203.0.113.30
r2 tnsr(config-gre)# destination 203.0.113.2
r2 tnsr(config-gre)# exit

Enable and configure the R2 GRE interface as unnumbered, borrowing from loop0:

r2 tnsr(config)# interface gre0
r2 tnsr(config-interface)# ip unnumbered loop0
r2 tnsr(config-interface)# enable
r2 tnsr(config-interface)# exit

Optionally add a route to the R1 loopback through gre0:

r2 tnsr(config)# route table default
r2 tnsr(config-route-table)# route 10.2.10.1/32
r2 tnsr(config-rttbl4-next-hop)# next-hop 0 via 0.0.0.0 gre0
r2 tnsr(config-rttbl4-next-hop)# exit
r2 tnsr(config-route-table)# exit

Add a route to the R1 LAN subnet through gre0:

r2 tnsr(config)# route table default
r2 tnsr(config-route-table)# route 10.2.0.0/24
r2 tnsr(config-rttbl4-next-hop)# next-hop 0 via 0.0.0.0 gre0
r2 tnsr(config-rttbl4-next-hop)# exit
r2 tnsr(config-route-table)# exit

Testing

With a GRE tunnel interface, testing can be performed from the TNSR CLI, a dataplane shell or VPP. The TNSR CLI is the easiest method.

First, from R1, try a ping from the R1 LAN IP address to the R2 LAN IP address:

r1 tnsr(config)# dataplane ping 10.30.0.1 source 10.2.0.1 count 3
PING 10.30.0.1 (10.30.0.1) from 10.2.0.1 : 56(84) bytes of data.
64 bytes from 10.30.0.1: icmp_seq=1 ttl=64 time=0.175 ms
64 bytes from 10.30.0.1: icmp_seq=2 ttl=64 time=0.125 ms
64 bytes from 10.30.0.1: icmp_seq=3 ttl=64 time=0.125 ms

--- 10.30.0.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2077ms
rtt min/avg/max/mdev = 0.125/0.141/0.175/0.023 ms

Then, from R2, try a ping from the R2 LAN IP address to the R1 LAN IP address:

r2 tnsr(config)# dataplane ping 10.2.0.1 source 10.30.0.1 count 3
PING 10.2.0.1 (10.2.0.1) from 10.30.0.1 : 56(84) bytes of data.
64 bytes from 10.2.0.1: icmp_seq=1 ttl=64 time=0.208 ms
64 bytes from 10.2.0.1: icmp_seq=2 ttl=64 time=0.120 ms
64 bytes from 10.2.0.1: icmp_seq=3 ttl=64 time=0.117 ms

--- 10.2.0.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2073ms
rtt min/avg/max/mdev = 0.117/0.148/0.208/0.042 ms

If both pings were successful, there is now two-way routing connectivity between the R1 LAN and R2 LAN. Add more routes as needed.

To add more routers, R1 only needs additional GRE tunnels and routes.

IPIP Example

Configuring the same style of setup with IPIP is nearly identical to the GRE example. Refer to that recipe for more detail on each step.

Configure R1

Create the R1 loopback instance:

r1 tnsr(config)# interface loopback routing
r1 tnsr(config-loopback)# instance 0
r1 tnsr(config-loopback)# exit

Enable and configure the R1 loopback interface IP address:

r1 tnsr(config)# interface loop0
r1 tnsr(config-interface)# ip address 10.2.10.1/32
r1 tnsr(config-interface)# enable
r1 tnsr(config-interface)# exit

Create a new IPIP tunnel interface between R1 and R2. This example creates ipip10:

r1 tnsr(config)# tunnel ipip 10
r1 tnsr(config-ipip)# source ipv4 address 203.0.113.2
r1 tnsr(config-ipip)# destination ipv4 address 203.0.113.30
r1 tnsr(config-ipip)# exit

Next enable the R1 ipip10 interface and configure it as unnumbered, borrowing its IP address from loop0:

r1 tnsr(config)# interface ipip10
r1 tnsr(config-interface)# ip unnumbered loop0
r1 tnsr(config-interface)# enable
r1 tnsr(config-interface)# exit

Create a route to the R2 LAN subnet using the ipip10 interface as the destination:

r1 tnsr(config)# route table default
r1 tnsr(config-route-table)# route 10.30.0.0/24
r1 tnsr(config-rttbl4-next-hop)# next-hop 0 via 0.0.0.0 ipip10
r1 tnsr(config-rttbl4-next-hop)# exit
r1 tnsr(config-route-table)# exit

Configure R2

Create the R2 loopback instance:

r2 tnsr(config)# interface loopback routing
r2 tnsr(config-loopback)# instance 0
r2 tnsr(config-loopback)# exit

Enable and configure the R2 loopback interface IP address:

r2 tnsr(config)# interface loop0
r2 tnsr(config-interface)# ip address 10.30.10.1/32
r2 tnsr(config-interface)# enable
r2 tnsr(config-interface)# exit

Create a new IPIP tunnel interface between R2 and R1. This example creates ipip10:

r2 tnsr(config)# tunnel ipip 10
r2 tnsr(config-ipip)# source ipv4 address 203.0.113.30
r2 tnsr(config-ipip)# destination ipv4 address 203.0.113.2
r2 tnsr(config-ipip)# exit

Next enable the R2 ipip10 interface and configure it as unnumbered, borrowing its IP address from loop0:

r2 tnsr(config)# interface ipip10
r2 tnsr(config-interface)# ip unnumbered loop0
r2 tnsr(config-interface)# enable
r2 tnsr(config-interface)# exit

Create a route to the R1 LAN subnet using the ipip10 interface as the destination:

r2 tnsr(config)# route table default
r2 tnsr(config-route-table)# route 10.2.0.0/24
r2 tnsr(config-rttbl4-next-hop)# next-hop 0 via 0.0.0.0 ipip10
r2 tnsr(config-rttbl4-next-hop)# exit
r2 tnsr(config-route-table)# exit

Testing

Testing the IPIP configuration works identically to testing in the GRE example. Try a ping from each router using the TNSR CLI. Refer to the GRE example testing section for more details.

Ethernet Example

Typically Ethernet interfaces are not point-to-point connections so there is ambiguity when determining how TNSR delivers packets to the peer. If the interface is cross-connected or only has one possible destination, it is still viable.

Using unnumbered Ethernet interfaces requires using routes with the dataplane-only property, which makes it harder to test. The ping command in TNSR relies on routes in the operating system which are not present with dataplane-only routes.

See also

While some aspects of this example are much different, refer to the GRE example for more details on the setup in general.

Configure R1

Create the R1 loopback instance:

r1 tnsr(config)# interface loopback routing
r1 tnsr(config-loopback)# instance 0
r1 tnsr(config-loopback)# exit

Enable and configure the R1 loopback interface IP address:

r1 tnsr(config)# interface loop0
r1 tnsr(config-interface)# ip address 10.2.10.1/32
r1 tnsr(config-interface)# enable
r1 tnsr(config-interface)# exit

Enable the directly connected link interface and configure it as unnumbered, borrowing its address from loop0:

r1 tnsr(config)# interface CCLINK
r1 tnsr(config-interface)# ip unnumbered loop0
r1 tnsr(config-interface)# enable
r1 tnsr(config-interface)# exit

Create a route to the R2 LAN subnet using the dataplane-only property and using both the R2 loopback IP address and the directly connected link interface as the destination:

r1 tnsr(config)# route table default
r1 tnsr(config-route-table)# route 10.30.0.0/24
r1 tnsr(config-rttbl4-next-hop)# dataplane-only
r1 tnsr(config-rttbl4-next-hop)# next-hop 0 via 10.30.10.1 CCLINK
r1 tnsr(config-rttbl4-next-hop)# exit
r1 tnsr(config-route-table)# exit

See also

Managing Routes

Configure R2

Create the R2 loopback instance:

r2 tnsr(config)# interface loopback routing
r2 tnsr(config-loopback)# instance 0
r2 tnsr(config-loopback)# exit

Enable and configure the R2 loopback interface IP address:

r2 tnsr(config)# interface loop0
r2 tnsr(config-interface)# ip address 10.30.10.1/32
r2 tnsr(config-interface)# enable
r2 tnsr(config-interface)# exit

Enable the directly connected link interface and configure it as unnumbered, borrowing its address from loop0:

r2 tnsr(config)# interface CCLINK
r2 tnsr(config-interface)# ip unnumbered loop0
r2 tnsr(config-interface)# enable
r2 tnsr(config-interface)# exit

Create a route to the R1 LAN subnet using the dataplane-only property and using both the R1 loopback IP address and the directly connected link interface as the destination:

r2 tnsr(config)# route table default
r2 tnsr(config-route-table)# route 10.2.0.0/24
r2 tnsr(config-rttbl4-next-hop)# next-hop 0 via 10.2.10.1 CCLINK
r2 tnsr(config-rttbl4-next-hop)# dataplane-only
r2 tnsr(config-rttbl4-next-hop)# exit
r2 tnsr(config-route-table)# exit

Testing

This type of routing will not work from the TNSR OS even using the dataplane namespace. As such, it cannot work with ping from the shell or even the TNSR CLI.

To test this type of routing, use the dataplane itself (VPP) to send a ping (sudo vppctl ping x.x.x.x source LAN) or ping from host to host within the target networks.

Test from R1 using the dataplane:

r1 tnsr(config)# dataplane shell sudo vppctl ping 10.30.0.1 source LAN
116 bytes from 10.30.0.1: icmp_seq=1 ttl=64 time=.1013 ms
116 bytes from 10.30.0.1: icmp_seq=2 ttl=64 time=.0776 ms
116 bytes from 10.30.0.1: icmp_seq=3 ttl=64 time=.0782 ms
116 bytes from 10.30.0.1: icmp_seq=4 ttl=64 time=.0772 ms
116 bytes from 10.30.0.1: icmp_seq=5 ttl=64 time=.0779 ms

Test from R2 using the dataplane:

r2 tnsr(config)# dataplane shell sudo vppctl ping 10.2.0.1 source LAN
116 bytes from 10.2.0.1: icmp_seq=1 ttl=64 time=.0964 ms
116 bytes from 10.2.0.1: icmp_seq=2 ttl=64 time=.0782 ms
116 bytes from 10.2.0.1: icmp_seq=3 ttl=64 time=.0779 ms
116 bytes from 10.2.0.1: icmp_seq=4 ttl=64 time=.0782 ms
116 bytes from 10.2.0.1: icmp_seq=5 ttl=64 time=.0782 ms

Statistics: 5 sent, 5 received, 0% packet loss