Addressing Tutorial
IP Address Management (IPAM) is one of the most interesting netlab features – it allows you to create full-blown fully configured networking labs without spending a millisecond on IP addressing scheme, assigning IP addresses to nodes and interfaces, or configuring them on network devices.
This document starts with an easy walk through simple addressing schemes, gets progressively more complex, and ends with crazy scenarios like stretched subnets.
Basics
netlab uses a two-step IP address allocation during the lab topology transformation process:
A prefix is assigned to every link in the lab topology
An IPv4/IPv6 address is assigned to every node attached to a link
Of course it’s a bit more complex than that:
A link prefix could could contain an IPv4 subnet, an IPv6 subnet, or both.
You can assign a static prefix to a link or let netlab get one from an address pool.
You can assign static IPv4 and/or IPv6 addresses to every interface connected to a link, or remove an address from a particular interface.
netlab also supports unnumbered IPv4 interface, LLA-only IPv6 interfaces, and links/interfaces without IPv4/IPv6 addresses (in case you want to test layer-2 functionality).
Don’t get scared by the plethora of options – getting started with built-in address pools is as easy as it can get.
Using Built-In Address Pools
netlab ships with seven built-in address pools:
l2only: {}
lan:
ipv4: 172.16.0.0/16
prefix: 24
loopback:
ipv4: 10.0.0.0/24
prefix: 32
mgmt:
ipv4: 192.168.121.0/24
mac: 08-4F-A9-00-00-00
prefix: 24
start: 100
p2p:
ipv4: 10.1.0.0/16
prefix: 30
router_id:
ipv4: 10.0.0.0/24
prefix: 32
vrf_loopback:
ipv4: 10.2.0.0/24
prefix: 32
loopback pool generates IP address for loopback interfaces
lan pool is used to assign prefixes to stub links[1] and multi-access links[2].
p2p pool is used to assign prefixes to point-to-point links[3]
mgmt pool contains management network addresses. It’s the only pool that uses mac addresses at the moment. Changing its definition is probably a bad idea.
l2only pool contains no addresses. You can use it on layer-2-only links – add pool: l2only attribute to the link.
router_id address pool is used to allocate BGP and OSPFv3 router IDs in IPv6-only networks.
vrf_loopback address pool is used for optional VRF loopback interfaces.
Loopback Addresses
Let’s start with the simplest possible process: assigning IP addresses to loopback interfaces. We’ll use the following lab topology to make it a bit more interesting:
nodes: [ r1, r2, r3, r4 ]
links:
- r1
- r1-r2
- r1-r3-r4
- r3:
r4:
type: lan
One of the first things netlab topology transformation code does is assign node identifiers to lab devices:
nodes:
r1:
id: 1
r2:
id: 2
r3:
id: 3
r4:
id: 4
The node identifiers are then used to generate loopback addresses from the loopback pool:
nodes:
r1:
id: 1
loopback:
ipv4: 10.0.0.1/32
r2:
id: 2
loopback:
ipv4: 10.0.0.2/32
r3:
id: 3
loopback:
ipv4: 10.0.0.3/32
r4:
id: 4
loopback:
ipv4: 10.0.0.4/32
Don’t like the automatic assignment of node identifiers? No problem, use id node attribute.
Imagine you want R1 to have ID 42. All you have to do is to specify the lab devices in the dictionary format (because you want to set node attributes) and set id on R1:
nodes:
r1:
id: 42
r2:
r3:
r4:
links:
- r1
- r1-r2
- r1-r3-r4
- r3:
r4:
type: lan
The loopback interfaces immediate reflect the new node IDs. Please note that the auto-assigned IDs still start at one; as we don’t need an ID for R1 (it already has it), r2.id becomes 1.
Warning
Don’t count on this behavior, it might change in the future – we might try to set node IDs based on their position in the nodes dictionary, or start at two instead of one or…
nodes:
r1:
id: 42
loopback:
ipv4: 10.0.0.42/32
r2:
id: 1
loopback:
ipv4: 10.0.0.1/32
r3:
id: 2
loopback:
ipv4: 10.0.0.2/32
r4:
id: 3
loopback:
ipv4: 10.0.0.3/32
Stub Links
Stub links[1] get their IP prefixes from the lan address pool[4]. To get an IP address for a node on a stub link, netlab combines link prefix with node ID (see also: lan links).
Imagine the simplest possible lab topology: one device and one link:
nodes:
r1:
links:
- r1
The resulting link data structure contains prefix assigned from the lan pool and a list of interfaces attached to the link. Each interface has a node name and IPv4/IPv6 addresses:
- bridge: X_1
interfaces:
- ipv4: 172.16.0.1/24
node: r1
linkindex: 1
node_count: 1
prefix:
ipv4: 172.16.0.0/24
type: stub
The interface data structure is copied into node data (we need it there to generate device configuration):
nodes:
r1:
id: 1
interfaces:
- bridge: X_1
ifindex: 1
ifname: eth1
ipv4: 172.16.0.1/24
linkindex: 1
neighbors: []
type: stub
Remember how we changed the node ID to change its loopback interface address? We can use the same trick here:
nodes:
r1:
id: 42
links:
- r1
Not surprisingly, the IP address assigned to R1 on the stub link changes to .42:
nodes:
r1:
id: 42
interfaces:
- bridge: X_1
ifindex: 1
ifname: eth1
ipv4: 172.16.0.42/24
linkindex: 1
neighbors: []
type: stub
You could argue that a network device should always have a .1 IP address on a stub link. You might be right, but this approach makes our life easier, and you can always use static interface-level node IDs, or set prefix allocation to sequential to assign the first IP address in the prefix to the node attached to the stub link.
Loopback Links
Loopback links are a special case of stub links, and use the same address allocation mechanisms. They are configured as loopback interfaces not as physical interfaces and thus don’t consume VM/container resources.
The only difference between loopback- and stub links is the support for host prefixes – you can configure a /32 IPv4 or a /128 IPv6 prefix on a loopback link, for example:
defaults.device: eos
nodes:
r1:
r2:
links:
- r1:
prefix: 10.1.0.2/32
type: loopback
- r2:
ipv4: 10.1.0.1/32
type: loopback
You can also assign addresses to loopback links from the vrf_loopback pool which generates /32 IPv4 prefixes:
defaults.device: eos
nodes:
r1:
links:
- r1:
pool: vrf_loopback
type: loopback
Point-to-Point Links
Point-to-point links get their prefixes from the p2p pool. Unless you change the default settings, every P2P link gets a /30 IPv4 prefix from 10.1.0.0/16 address space[5].
IP address assignment on a point-to-point link does not use node identifiers. Nodes attached to a P2P link are sorted alphabetically, then the .1 address is assigned to the first node and the .2 address to the second node. You can force netlab to use this allocation method by setting allocation: p2p in a pool or a link prefix.
The same process is used for IPv6 addresses even though you usually get a /64 prefix assigned to every P2P link unless you change the size of IPv6 prefixes allocated from the p2p pool with the prefix6 parameter.
How about a quick example: two nodes, one link:
nodes: [ r1, r2 ]
links:
- r1-r2
Here’s the resulting link data structure:
links:
- interfaces:
- ipv4: 10.1.0.1/30
node: r1
- ipv4: 10.1.0.2/30
node: r2
linkindex: 1
name: r1 - r2
node_count: 2
prefix:
ipv4: 10.1.0.0/30
type: p2p
The interface data structure in individual nodes has more attributes: it contains a list of neighbors (that might come useful in configuration templates or when generating EBGP sessions).
nodes:
r1:
box: none
device: none
id: 1
interfaces:
- ifindex: 1
ifname: eth1
ipv4: 10.1.0.1/30
linkindex: 1
name: r1 -> r2
neighbors:
- ifname: eth1
ipv4: 10.1.0.2/30
node: r2
type: p2p
LAN Links
Multi-access (LAN) links are exactly like stub links, but they have more non-host nodes attached to them. Prefixes are allocated from the lan pool or the pool specified in the pool attribute.
On LAN links with large enough prefixes to accommodate the highest id of all nodes attached to a link, netlab combines link prefix and node id to get the interface IP address. You can force netlab to use this allocation method by setting allocation: id_based in a pool or a link prefix.
If the LAN prefix is not large enough (for example, /29 prefix in a large lab), netlab allocates sequential IP addresses to interfaces attached to the link (based on their position in the link data structure). You can force netlab to use this allocation method by setting allocation: sequential in a pool or a link prefix.
Warning
Sequential IP address allocation does not work on VLAN prefixes. They must be large enough to accommodate the largest node ID in the topology. Do not set allocation attribute on pools used by VLANs.
The simplest possible lab topology to illustrate how LAN links work contains three nodes and a single link:
nodes: [ r1, r2,r3 ]
links:
- r1-r2-r3
Here’s the resulting link data structure…
links:
- bridge: X_1
interfaces:
- ipv4: 172.16.0.1/24
node: r1
- ipv4: 172.16.0.2/24
node: r2
- ipv4: 172.16.0.3/24
node: r3
linkindex: 1
node_count: 3
prefix:
ipv4: 172.16.0.0/24
type: lan
… and here’s the interface data structure on R1:
nodes:
r1:
box: none
device: none
id: 1
interfaces:
- bridge: X_1
ifindex: 1
ifname: eth1
ipv4: 172.16.0.1/24
linkindex: 1
name: r1 -> [r2,r3]
neighbors:
- ifname: eth1
ipv4: 172.16.0.2/24
node: r2
- ifname: eth1
ipv4: 172.16.0.3/24
node: r3
type: lan
If you read the loopback interfaces and stub links sections, you know you can change node IDs[6]. Let’s change the node IDs in our lab and use a small static prefix on the LAN link to see how sequential address allocation works:
nodes:
r1:
id: 42
r2:
id: 17
r3:
id: 1
links:
- r1:
r2:
r3:
prefix.ipv4: 10.42.0.0/27
Here’s the interface data structure on R1 created from the above topology. As you can see, netlab allocated sequential IP address to R1 and its neighbors (R2 and R3):
interfaces:
- bridge: X_1
ifindex: 1
ifname: GigabitEthernet0/1
ipv4: 10.42.0.1/27
linkindex: 1
name: r1 -> [r2,r3]
neighbors:
- ifname: GigabitEthernet0/1
ipv4: 10.42.0.2/27
node: r2
- ifname: GigabitEthernet0/1
ipv4: 10.42.0.3/27
node: r3
type: lan
Customize Address Pools
Don’t like the built-in addressing rules? It’s extremely easy to:
Change built-in address pools
Define your own pools
Use user-defined pools on individual links
Change Built-In Address Pools
All netlab address pools are defined in the addressing section of lab topology file. The default value of that section (taken from system defaults) is:
addressing:
l2only: {}
lan:
ipv4: 172.16.0.0/16
prefix: 24
loopback:
ipv4: 10.0.0.0/24
prefix: 32
mgmt:
ipv4: 192.168.121.0/24
mac: 08-4F-A9-00-00-00
prefix: 24
start: 100
p2p:
ipv4: 10.1.0.0/16
prefix: 30
vrf_loopback:
ipv4: 10.2.0.0/24
prefix: 32
Tip
To display address pools used by your lab topology, use netlab create -o yaml:addressing
command.
To change the system defaults, specify addressing section in your lab topology. System defaults are always deep-merged with topology file settings, allowing you to specify just the changes you want to make.
For example, to use default AWS CIDR block for LAN segments, specify addressing.lan.ipv4 parameter:
addressing.lan.ipv4: 172.31.0.0/16
Obviously you could use the more traditional dictionary hierarchy if you prefer longer YAML files:
addressing:
lan:
ipv4: 172.31.0.0/16
Likewise, it takes a single line to change the default IPv4 prefix size of point-to-point address pools to /28:
addressing.p2p.prefix: 28
Select an Address Pool for a Link
pool link attribute is all you need to override the default pool selection logic. For example, to create a point-to-point link that uses a prefix from the LAN pool, use the following link definition:
nodes: [ r1, r2 ]
links:
- r1:
r2:
pool: lan
The resulting link data structure is interesting:
It contains all attributes one would expect to see on a point-to-point link
The nodes connected to the link get the first and the second IP address from the link prefix (due to point-to-point address allocation rules)
The IP prefix and the subnet size belong to the LAN pool (due to pool attribute).
links:
- interfaces:
- ipv4: 172.16.0.1/24
node: r1
- ipv4: 172.16.0.2/24
node: r2
linkindex: 1
name: r1 - r2
node_count: 2
pool: lan
prefix:
ipv4: 172.16.0.0/24
type: p2p
Layer-2-Only Links Using l2only Address Pool
A more interesting case of selecting built-in address pools with pool attribute is layer-2-only links – when a link pool is set to l2only, the link gets no IP prefix and the interfaces attached to the link have no IP addresses.
You could build a simple bridged network with this lab topology:
nodes: [ r1, r2 ]
links:
- r1:
r2:
pool: l2only
The resulting link data structure contains no IP addresses:
links:
- interfaces:
- ifindex: 1
ifname: GigabitEthernet0/1
node: r1
- ifindex: 1
ifname: GigabitEthernet0/1
node: r2
linkindex: 1
node_count: 2
pool: l2only
type: p2p
Similarly, the node data for R1 (what you’d find in Ansible inventory host_vars for R1) has no IP addresses apart from loopback and management ones:
af:
ipv4: true
box: cisco/iosv
device: iosv
id: 1
interfaces:
- ifindex: 1
ifname: GigabitEthernet0/1
linkindex: 1
name: r1 -> r2
neighbors:
- ifname: GigabitEthernet0/1
node: r2
pool: l2only
type: p2p
loopback:
ipv4: 10.0.0.1/32
mgmt:
ifname: GigabitEthernet0/0
ipv4: 192.168.121.101
mac: 08-4F-A9-00-00-01
name: r1
Custom Address Pools
To specify custom address pools, add keys to addressing dictionary, for example:
addressing:
core:
ipv4: 10.2.0.0/16
prefix: 28
To use the core address pool, set link pool to core, for example:
nodes: [ r1, r2 ]
links:
- r1:
r2:
pool: core
You’ll find more details in Topology Address Pools document.
Static Addresses
Don’t like the built-in IPAM rules? Take the matters in your hands and use static IP addresses. We’re also assuming you’re ready to dive deeper into the netlab bowels and will use commands like netlab create -o yaml:links
or netlab create -o yaml:nodes
(or explore Ansible inventory created with netlab create
) to inspect the results of your experiments.
Static Link Prefixes
In the Basics part of this document I mentioned you can assign a static prefix to a link:
Add prefix link attribute
Its value could be a string (IPv4 prefix) or a dictionary that can have ipv4 and ipv6 keys.
Example: Use 10.42.42.0/24 as the link prefix:
nodes: [ r1, r2 ]
links:
- r1:
r2:
prefix: 10.42.42.0/24
Another example: Assign a static IPv4 and IPv6 prefix to the link:
nodes: [ r1, r2 ]
links:
- r1:
r2:
prefix:
ipv4: 10.42.42.0/24
ipv6: 2001:db8:0:42:0:1::/96
Finally, you can set the link prefix to False to create a link without IP addresses (you could also use pool: l2only, but we’re talking about static prefixes here):
nodes: [ r1, r2 ]
links:
- r1:
r2:
prefix: False
Static Node Addressing
Sometimes you want to have even more control over interface IP addresses. Sure, why not: use ipv4 and/or ipv6 interface attributes to set the IP addresses of individual interfaces.
We’ll give you as much rope as you need (to make your troubleshooting miserable): you can specify IP addresses outside of link prefix, use different subnet masks, have IPv4 addresses on some nodes and IPv6 addresses on other nodes connected to the same link…
Let’s say you want to experiment with Proxy ARP, so you need different subnet masks on end hosts than on intermediate routers. No big deal:
nodes: [ h1, h2, r ]
links:
- h1:
ipv4: 10.0.1.3/24
r:
ipv4: 10.0.1.1/28
- h2:
ipv4: 10.0.1.67/24
r:
ipv4: 10.0.1.65/28
You could make the example a bit more convoluted by combining host IP addresses (with too-large subnet masks) with link prefixes:
nodes:
r:
id: 1 # Just to make sure it gets .1 address in every subnet
h1:
h2:
links:
- h1:
ipv4: 10.0.1.3/24
r:
prefix:
ipv4: 10.0.1.0/28
- h2:
ipv4: 10.0.1.67/24
r:
prefix:
ipv4: 10.0.1.64/28
Static ID-Based Interface Addresses
Looking for something less drastic like setting the router’s IP address to be the first IP address in the link subnet? We got you covered: use a number (instead of an IPv4/IPv6 address) in ipv4 or ipv6 interface attribute.
Remember the stub link example where I mentioned the router might not get the first IP address on the link? Let’s fix that:
nodes:
r1:
id: 42
links:
- r1:
ipv4: 1
Regardless of what prefix gets assigned to the link, R1 will always get the first IP address in that prefix, even though its device ID is 42. Here’s what you get as a result of the above topology file:
links:
- bridge: X_1
interfaces:
- ifindex: 1
ifname: eth1
ipv4: 172.16.0.1/24
node: r1
linkindex: 1
node_count: 1
prefix:
ipv4: 172.16.0.0/24
type: stub
nodes:
r1:
af:
ipv4: true
id: 42
interfaces:
- bridge: X_1
ifindex: 1
ifname: eth1
ipv4: 172.16.0.1/24
linkindex: 1
name: r1 -> stub
neighbors: []
type: stub
loopback:
ipv4: 10.0.0.42/32
IPv6 Support
netlab tries to be an equal-opportunity transformation tool: IPv4 and IPv6 are treated in exactly the same way[7]… it’s just that the system defaults are IPv4-only, but even that’s easy to fix.
Adding IPv6 Prefixes to Default Pools
Want to build a dual-stack lab? All you have to do is to add IPv6 prefixes to default address pools, for example:
addressing:
loopback:
ipv6: 2001:db8:0::/48
lan:
ipv6: 2001:db8:1::/48
p2p:
ipv6: 2001:db8:2::/48
nodes: [ r1 ]
The final address pools are a combination of system defaults (IPv4 prefixes) and IPv6 prefixes you specified in the topology file.
addressing:
l2only: {}
lan:
ipv4: 172.16.0.0/16
ipv6: 2001:db8:1::/48
prefix: 24
loopback:
ipv4: 10.0.0.0/24
ipv6: 2001:db8:0::/48
prefix: 32
mgmt:
ipv4: 192.168.121.0/24
mac: 08-4F-A9-00-00-00
prefix: 24
start: 100
p2p:
ipv4: 10.1.0.0/16
ipv6: 2001:db8:2::/48
prefix: 30
Every single address allocation feature described so far works as expected. For example, the loopback interface on R1 gets an IPv4 and an IPv6 address:
nodes:
r1:
box: none
device: none
id: 1
loopback:
ipv4: 10.0.0.1/32
ipv6: 2001:db8:0:1::1/64
mgmt:
ifname: eth0
ipv4: 192.168.121.101
mac: 08-4F-A9-00-00-01
Tip
The IPAM logic creates /64 IPv6 prefixes from address pools. To change the target IPv6 prefix size, use the prefix6 pool attribute. For example, you could set prefix6: 128 on the loopback pool to have /128 loopback IPv6 addresses.
IPv6-Only Networks
If you want to build an IPv6-only network, you have to remove IPv4 prefixes from the default pools – use ipv4: key without a value, for example:
addressing:
loopback:
ipv4:
ipv6: 2001:db8:0::/48
lan:
ipv4:
ipv6: 2001:db8:1::/48
p2p:
ipv4:
ipv6: 2001:db8:2::/48
nodes: [ r1 ]
The resulting address pools have no IPv4 prefixes (don’t worry about the prefix attribute, it’s not used without the ipv4 attribute):
addressing:
l2only: {}
lan:
ipv6: 2001:db8:1::/48
prefix: 24
loopback:
ipv6: 2001:db8:0::/48
prefix: 32
mgmt:
ipv4: 192.168.121.0/24
mac: 08-4F-A9-00-00-00
prefix: 24
start: 100
p2p:
ipv6: 2001:db8:2::/48
prefix: 30
Static Link and Node Addresses
You can use ipv6 attribute in link prefix to configure a static IPv6 prefix on a link, for example:
nodes: [ r1, r2 ]
links:
- r1:
r2:
prefix:
ipv6: 2001:db8:0:42:0:1::/96
Tip
You cannot specify a subnet for one address family in the link prefix attribute and hope to have the other address family prefix allocated from an address pool. Link prefix is an all-or-nothing attribute.
Likewise, you can use ipv6 attribute in node interface data to assign a static IPv6 address to an interface.
Link-Local Addresses
Use ipv6: True instead of ipv6: prefix to use link-local-only addressing on a link or in an address pool.
Example: you might want to use LLA-only addressing on point-to-point links in your network because you’re running IS-IS as your IGP and it doesn’t need GUA IPv6 addresses. Add ipv6: True to p2p pool and you’re good to go:
addressing:
loopback:
ipv6: 2001:db8:0::/48
lan:
ipv6: 2001:db8:1::/48
p2p:
ipv6: True
nodes: [ r1 ]
You can use the same approach on link- or even interface addresses. For example, to enable IPv6 LLA on a single link in your lab while allocating IPv4 prefixes from the standard address pools, use ipv6: True on individual interfaces:
nodes: [ r1, r2, r3 ]
links:
- name: IPv4-only link
r1:
r2:
- name: IPv4 + IPv6 LLA
r1:
ipv6: True
r2:
ipv6: True
For more examples, check out the addressing test cases.
Complex Addressing Scenarios
In the IPv6 section we described how to enable IPv6 on an interface without assigning a static address to it. netlab provides similar functionality for IPv4 – when setting ipv4 attribute to True, the device configuration modules try to configure unnumbered IPv4 Ethernet interfaces[8].
Now that you’ve seen that you can set ipv4 or ipv6 attribute to True you might wonder what happens if you set it to False. Should you do that, the affected interface (or link) gets no IPv4/IPv6 address.
Now let’s see how you can use these features in real-life scenarios.
Unnumbered Links
To create an unnumbered IPv4 link, set the ipv4 attribute of a link prefix to True. For example:
nodes: [ r1, r2 ]
links:
- r1:
r2:
prefix:
ipv4: True
Unnumbered point-to-point links (when supported) usually work reasonably well with OSPF and IS-IS. Some devices go a step further: you can use multi-access unnumbered links with IS-IS, for example:
module: [ isis ]
nodes: [ r1, r2, r3 ]
links:
- r1:
r2:
r3:
prefix:
ipv4: True
ipv6: True
Tip
You can use a somewhat-deprecated unnumbered link attribute to create an unnumbered link. That attribute is converted into ipv4: True and/or ipv6: True depending on the address families configured on the loopback interface.
You also can define unnumbered address pools – the above topology could be rewritten into this one:
addressing:
core:
ipv4: True
ipv6: True
module: [ isis ]
nodes: [ r1, r2, r3 ]
links:
- r1:
r2:
r3:
pool: core
Tip
It makes more sense to use link prefix when you’re testing device behavior over a single link. Unnumbered address pool makes your life easier in large-scale scenarios; it also allows you to quickly evaluate a migration from numbered to unnumbered links (or vice versa).
Devices Without IP Addresses
Several ways of building layer-2 only networks have been described in this document (address pools, static prefixes), but what if you want to connect a segment of IP hosts to a bridge (with no IP address)? Remove the IP addresses from the bridge interface with ipv4: False and/or ipv6: False[9].
Imagine a network with four hosts and a bridge connecting two parts of the same subnet. You could describe the network with the following lab topology:
nodes: [ h1, h2, h3, h4, b ]
links:
- prefix: 10.42.42.0/24
h1:
h2:
b:
ipv4: False
- prefix: 10.42.42.0/24
h3:
h4:
b:
ipv4: False
Notes:
The bridge B connects two parts of the same subnet. Such a topology is not supported by netlab IP address pools unless you use VLAN configuration module; you have to use the same static prefix on both links.
Hosts will get IP addresses assigned from the link prefix based on their node ID (h1: 10.42.42.1/24 through h4: 10.42.42.4/24)
Bridge B would get the same IP address (10.42.42.5/24) assigned to both interface. Most network operating systems wouldn’t agree with such an approach.
To make the topology work, remove the IPv4 address from bridge interfaces with ipv4: False interface attribute.