Skip to content

Commit

Permalink
Add configurable IPv6 prefix length to address pools (Implements #901)
Browse files Browse the repository at this point in the history
  • Loading branch information
ipspace committed Oct 16, 2023
1 parent 1692c8a commit 4a6fd95
Show file tree
Hide file tree
Showing 9 changed files with 455 additions and 12 deletions.
6 changes: 4 additions & 2 deletions docs/addressing.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ You can override or augment them in topology **addressing** element. You can als

## Dual-Stack Support

Every address pool could have an IPv4 and an IPv6 prefix, supporting IPv4-only, dual-stack or IPv6-only deployments. Pool address space is specified in **ipv4** or **ipv6** CIDR prefix. Size of individual IPv4 address allocations is specified with the **prefix** parameter, IPv6 prefixes are currently fixed (/64).
Every address pool could have an IPv4 and an IPv6 prefix, supporting IPv4-only, dual-stack or IPv6-only deployments. Pool address space is specified in **ipv4** or **ipv6** CIDR prefix. Size of individual IPv4 address allocations is specified with the **prefix** parameter. *netlab* uses /64 IPv6 prefixes unless you change the prefix size with **prefix6** attribute.

(address-pool-specs)=
## Specifying Address Pools
Expand All @@ -65,13 +65,15 @@ Each address pool specification is a dictionary of address pools. Individual add
* **ipv4** -- IPv4 CIDR prefix or **true** for unnumbered IPv4 links
* **ipv6** -- IPv6 CIDR prefix or **true** for LLA-only IPv6 links.
* **unnumbered** -- unnumbered address pool. Interfaces attached to nodes based on this address pool will have IPv4 and/or IPv6 enabled based on the protocols enabled on node's loopback interface.
* **prefix** -- IPv4 subnet allocation size. IPv6 subnets use /64 prefixes that cannot be changed.
* **prefix** -- IPv4 subnet allocation size.
* **prefix6** -- Optional IPv6 subnet allocation size. *netlab* creates /64 IPv6 subnets when the **prefix6** address pool parameter is not specified.
* **start** -- first subnet or first IP address offset. Used primarily with **loopback** pools to ensure the first address assignment gets the x.x.x.1/32 IP address, and with **mgmt** pool to specify the first management IP address.
* **allocation** -- [address allocation policy](addressing-tutorial-lan-links) (`id_based`, `sequential`, `p2p` or `loopback`).

**Notes:**

* Default IPv4 subnet allocation size is 32 for `loopback` pool, 24 for `lan` pool and 30 for `p2p` pool. All other pools must specify the **prefix** parameter whenever the **ipv4** parameter is specified.
* Default IPv6 subnet allocation is /64. You can change this behavior with the **prefix6** pool parameter.
* IPv4 loopback pool starts at .1 (**start** parameter is assumed to be 1)
* IPv6 loopback pool starts at the second subnet to make loopback IPv6 address similar to its IPv4 counterpart.

Expand Down
2 changes: 1 addition & 1 deletion docs/example/addr-builtin.txt
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ Point to point links get their prefixes from the **p2p** pool -- unless you chan

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 .2 address to the second node. You can force *netlab* to use this allocation method by setting **allocation: p2p** in a [pool](address-pool-specs) or a **prefix**.

The same process is used for IPv6 addresses even though you get a /64 prefix assigned to every P2P link. You know the reason: it was easier to do consistent address allocation across address families.
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:

Expand Down
2 changes: 1 addition & 1 deletion docs/example/addr-ipv6.txt
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ nodes:
```

```{tip}
The IPAM logic creates /64 IPv6 prefixes from address pools. You cannot specify target IPv6 prefix size like you could with IPv4. To build a network with non-/64 IPv6 prefixes you'll have to use [static link prefixes](#static-link-prefixes).
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
Expand Down
4 changes: 0 additions & 4 deletions docs/example/addr-static.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,6 @@ links:
ipv6: 2001:db8:0:42:0:1::/96
```

```{tip}
Static link **prefix** is the only way to create IPv6 subnets with non-/64 subnet mask. We're a bit opinionated about the right way of running IPv6.
```

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):

```
Expand Down
7 changes: 4 additions & 3 deletions netsim/augment/addressing.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@
* _prefix_ length - prefix length of individual subnets in the pool
IPv6 component of an addressing pool is defined with an _ipv6_ prefix,
prefix length of individual subnets is assumed to be /64.
prefix length of individual subnets is assumed to be /64 unless the
pool has _prefix6_ attribute.
Legacy setup migration
----------------------
Expand Down Expand Up @@ -219,9 +220,9 @@ def create_pool_generators(addrs: Box, no_copy_list: list) -> Box:
for key,data in pfx.items():
if "_pfx" in key:
af = key.replace('_pfx','')
plen = pfx['prefix'] if af == 'ipv4' else 64
plen = pfx['prefix'] if af == 'ipv4' else pfx.get('prefix6',64)
gen[pool][af] = data.subnet(plen)
if (af == 'ipv4' and plen == 32) or (pool == 'loopback'):
if (af == 'ipv4' and plen == 32) or (af == 'ipv6' and plen >= 127) or (pool == 'loopback'):
next(gen[pool][af])
elif not key in no_copy_list:
gen[pool][key] = data
Expand Down
5 changes: 4 additions & 1 deletion netsim/augment/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,10 @@ def transform(topology: Box, defaults: Box, pools: Box) -> None:
log.fatal( f"Loopback addresses must be valid IP prefixes, not 'True': {prefix_list}" )
elif not n.loopback[af]:
if af == 'ipv6':
n.loopback[af] = addressing.get_addr_mask(prefix_list[af],1)
if prefix_list[af].prefixlen == 128:
n.loopback[af] = str(prefix_list[af])
else:
n.loopback[af] = addressing.get_addr_mask(prefix_list[af],1)
else:
n.loopback[af] = str(prefix_list[af])
n.af[af] = True
Expand Down
1 change: 1 addition & 0 deletions netsim/defaults/attributes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ pool:
ipv6: { type: ipv6, use: prefix }
start: { type: int, min_value: 1 }
prefix: { type: int, min_value: 1, max_value: 32 }
prefix6: { type: int, min_value: 1, max_value: 128 }
allocation: { type: str, valid_values: [ p2p, sequential, id_based ] }
mac: mac
unnumbered: bool
Expand Down
Loading

0 comments on commit 4a6fd95

Please sign in to comment.