Spreadsheets are not an adequate method to manage IP addressing
Different IP design strategies
IPv4
Bogons, and the basics
There are a number of valid and invalid prefixes for use internally within an enterprise. Here's a list of invalid prefixes in the global routing table; of those, the RFC 1918 prefixes are available for use:
Prefix | RFC | Usable Internally? |
---|---|---|
0.0.0.0 | 1122 | π€ͺ Everybody more or less agreed not to use it |
10.0.0.0/8 | 1918 | β Use this block for large prefix allocations |
100.64.0.0/10 | 6598 | π CG-NAT, can technically be used, but will break in random cloud applications |
127.0.0.0/8 | 1122 | β loopback |
169.254.0.0/16 | 3927 | β , but don't allocate it (APIPA) |
172.16.0.0/12 | 1918 | β Use this block for medium prefix allocations |
192.0.0.0/24 | 5736 | β IETF skunkworks |
192.0.2.0/24 | 5737 | β Carrier test networks |
192.88.99.0/24 | 3068 | β 6to4 relays |
192.168.0.0/16 | 1918 | β Avoid this block for enterprises, it'll collide with home networks when people use VPN |
198.18.0.0/15 | 2544 | β device benchmarking |
198.51.100.0/24 | 5737 | β Carrier test networks |
203.0.113.0/24 | 5737 | β Carrier test networks |
224.0.0.0/4 | 3171 | β multicast |
240.0.0.0/4 | 1122 | π€― madlad play, might work, might not. Linux seems to live in this space just fine |
All of these prefixes must be dropped at any network perimeter, e.g. firewalls, extranet routers, to prevent internal traffic or misconfigured NATs from leaking. It also prevents protocol abuse, which is a cheap and easy way to improve security.
In multi-site networks, dropping all of these prefixes would be wise - an ethernet loop + APIPA can turn a switching issue into a network-wide outage pretty easily. Longest Prefix Match can ensure that any allocated networks remain reachable.
Each of these prefixes should be created in Netbox, so you can use it as a reference later. I'd recommend tagging them with some form of hint to indicate usability, e.g.:
IP:Usable
IP:Unusable
As you get more familiar with the API/search, tag-based filters become incredibly handy.
IPv6
IPv6 is quite easy. All valid routable addresses fall under one allocated prefix:
2000::/3
This means that you can implement a "default route" that won't accidentally leak bogons like in IPv4, but with a much simpler approach. Instead of implementing ::0/0
for your default route, use 2000::/3
.
If you insist on using private addressing, I'd encourage a thorough review of why - but this is the prefix available:
fc00::/7
Link-local addressing, or addressing that is "always on" regardless of prefix allocation, is also allocated a specific prefix. This prevents the need of a bunch of little helper protocols that simply don't need to exist, or become standardized. Traffic like Router Advertisements(RA), Routing Protocols, First Hop Redundancy Protocols have a distinct source address that can be pinged even before a network is online.
It's also incredibly handy when bootstrapping new devices! All that's required is some form of helper on the default gateway to act as an SSH proxy and some neighbor discovery, and you suddenly have always-on remote management.
fe80::/10
Multicast also has its own prefix:
ff80::/8
This is much simpler, but where to get IPv6 addressing can be more complex. If it's in a lab environment and doesn't need internet access, fc00::/7
is just fine to use.
The recommended method for acquiring an IPv6 prefix is to request it with DHCP-PD or to request it through a tunnel broker.
There's one more "gotcha" to keep in mind with IPv6 - weird stuff breaks if you go with a longer prefix than /64. I'd strongly encourage avoiding cutesy CIDR block allocations like /120 or /65; that's an IPv4 solution to a problem IPv6 doesn't have. Just request enough IP addressing for your site instead.
Constructing an IP hierarchy
For the purposes of this post, we're going to use the following language to describe a network address:
1{{ prefix }}{{ subprefix }}{{ host bits }}/{{ prefix length }}
2 10.99. 100. 0 /24
The major first step here is to decide how to break down your addressing. There are two major paths to follow:
-
Location based addressing is used when prefix scale is a concern. If you need to summarize routes on routers due to RIB limits, this is the way to go. This can be for a few reasons:
- "I have a lot of routes / lot of sites and am worried about RIB capacity in my hardware"
- Most enterprise equipment can handle 16-64k routes; if this is not enough, follow this approach
- ISPs will follow this path
- Cloud providers will follow this path
-
Purpose based addressing is used when perimeter security is a concern. Easy summarization to a common prefix per "network role" allows for straightforward firewall policy creation, including a number of microsegmentation tools that may have laughably low table capacities.
- "I want to keep my workloads separated from each other"
- Financial services will follow this path
- Healthcare will follow this path
Committing to one or the other before allocating blocks will simplify your life later.
Note: With IPv6, only the largest of organizations (ones that need more than 2^8 or 2^16 networks per site) will need to allocate their own top-level prefix. It's easier to just run DHCP-PD and ask for a /56 or /48.
Guidance on prefix allocation
To assess the proper 1918/bogon prefix for use, first assess the number of prefixes you would need as a ceiling:
1num_sites*num_network_roles
Attempt to select a site that will fit this prefix count with a minumum of 80% buffer (leaving a reserve for point-to-point connects, etc.)
I would highly encourage not getting creative with CIDR prefix lengths in IPv4-land. If possible, try and stick to /24
for a subprefix. IPv6 does not support prefix lengths longer than /64
particularly well (with specific exceptions for point-to-point, /126
or /127
depending on hardware), and using prefixes like /65
for access segments will lead to trouble with end devices like Android.
It's much simpler to translate the /24
in question linearly to a /64
and using that calculation to estimate what IPv6 prefix size you want. It's also much simpler to troubleshoot and maintain if you don't build a pile of weird stuff, even if it makes you feel smart!
As a starting point, it's good to set up a set of standard t-shirt sizes for networks in `{{ IPv4 }}/{{ IPv6 }} format. Here's an example:
- Large Site/Role:
/16
//56
- Medium Site/Role:
/18
//60
- Small Site/Role:
/22
//62
- "Normal" subprefix:
/24
//64
- "Small" subprefix:
/26
//64
- Point-to-point:
/31
//127
Note: Service providers don't always support weird DHCP-PD sizes, so options may be limited to the above.
Note: Service providers are typically pretty generous with prefix allocations, and keep in mind a /56 is roughly equivalent to a /16. I'd recommend allocating a /56 per site in production or in the lab whenever permitted.
Automating it
Once you have sizes set, it's actually pretty easy to let go of your artisanal, hand-crafted prefixes and automate aggressively. With Netbox and Ansible, it's incredibly easy to leverage the netbox.netbox.netbox_prefix
module. The following example will grab a /24
from 10.99.0.0/16
:
`
1- name: "Example Ansible Playbook"
2 connection: local
3 hosts: localhost
4 gather_facts: False
5 tasks:
6 - name: "Get next available prefix"
7 netbox.netbox.netbox_prefix:
8 netbox_url: "{{ netbox_url }}"
9 netbox_token: "{{ netbox_token }}"
10 data:
11 parent: "10.99.0.0/16"
12 prefix_length: 24
13 state: present
14 first_available: yes
`
It's extremely rewarding to design, deploy, and automate an IP design in this manner - and you'll find that automation is considerably easier if what to automate is well-defined.
Top comments (0)