Shared network shapes: worked examples
A shared network tells luna that two or more of its networks occupy the same link. That one fact drives everything on this page: how the DHCP server is told to pick a subnet, which pool a client is allowed to draw from, and how a node reserved in one network is still found when the request arrives looking like it belongs to another.
This page walks the shapes in the order they get harder — in-band BMC, a relayed network, two networks behind one relay, link-selection, and the combination — and shows what each renders to. For the settings themselves see DHCP addressing and DHCP relay on shared networks.
Availability
The Kea rendering described here — a shared group as oneshared-networks block,
the anchor joining that block, and IGNORE_LINK_SELECTION — is from Luna
2.2 and higher. Earlier releases render a shared group as separate
top-level subnets.
Note
Every example below uses the Kea DHCP server, which is the default. The ISC dhcpd backend expresses the same shapes withshared-network blocks and allow/deny members
of pools; the luna settings are identical either way, and only link-selection is Kea-only.
What a shared group renders to
A group is a carrier network plus every network whose shared names it:
luna network change ipmi --shared cluster
That makes cluster the carrier and ipmi a member. Luna renders the whole group as one
shared-networks block, with each network as a subnet inside it:
"shared-networks": [ {
"name": "cluster-ipmi",
"subnet4": [
{ "subnet": "10.141.0.0/16", ... },
{ "subnet": "10.148.0.0/16", ... }
]
} ]
The block is what makes the group a group. A DHCP server picks exactly one subnet for a request, and may only move to a sibling when that subnet is inside a shared network. Two networks rendered as separate, top-level subnets are not a group: the server picks one of them and a host reservation in the other is never found.
Shape 1 — in-band BMC on the host network
The commonest case, and the one with no relay in it. A node's host interface and its BMC sit on
the same wire, but they are two luna networks: cluster for the hosts, ipmi for the BMCs.
luna network change ipmi --shared cluster
Both subnets land in one block, and each pool carries the class that decides who may draw from it:
"shared-networks": [ {
"name": "cluster-ipmi",
"subnet4": [
{ "subnet": "10.141.0.0/16",
"pools": [ { "pool": "10.141.10.1-10.141.10.254",
"client-class": "cluster-ipmi-carrier-class" } ] },
{ "subnet": "10.148.0.0/16",
"pools": [ { "pool": "10.148.10.1-10.148.10.254",
"client-class": "ipmi-class" } ] }
]
} ]
ipmi-class matches the udhcp vendor-class identifier — the in-band client a BMC or a
netbooting node presents. The carrier's class is its mirror image: everything that is in none of
the member classes. So a BMC is served from the ipmi pool, everything else from cluster, and
both from the same wire.
Note
The classes are named after the group and its members and are generated for you. You never set them, and their names are not a stable interface — read the pool'sclient-class if you need to know which one applies.
Shape 2 — a network behind a relay
A remote subnet reaches the controller through a relay (IP helper). The server has to be told which relay source address belongs to which subnet:
luna network change remote --shared cluster
luna network change remote --dhcp_relay 10.150.0.1,10.150.0.2
The member subnet gains a relay block naming those sources:
{ "subnet": "10.150.0.0/16",
"relay": { "ip-addresses": [ "10.150.0.1", "10.150.0.2" ] },
"pools": [ { "pool": "10.150.10.1-10.150.10.254",
"client-class": "remote-class" } ] }
A request arriving with one of those addresses as its giaddr is matched to this subnet.
Shape 3 — two networks behind the same relay
Nothing new to set: it is shape 2 twice, with the same relay addresses on both networks. This is where the shared block earns its keep.
The relay cannot tell the server which of the two networks the client belongs to — both list the same giaddr — so the server picks one and then looks for the client's reservation across every subnet in the block. A node reserved in the second network is found and served its own address, even though selection landed on the first.
Outside a shared block the same two networks resolve by configuration order, and the reservation in the other one is invisible: the client is offered an address from the wrong network's pool, with the wrong gateway. If nodes behind a relay are booting with an address from a neighbouring network, this is the shape to check.
Shape 4 — selecting by link (option 82.5, RFC 3527)
Some relays do not identify the link by their own address. RFC 3527 defines option 82, sub-option 5 (link-selection): the relay adds the client's real link prefix, and the server selects the subnet from that instead of from the giaddr.
Luna needs a subnet covering that prefix or selection lands nowhere it controls.
dhcp_link_subnet provides it:
luna network change edge --dhcp_relay 10.160.0.1
luna network change edge --dhcp_link_subnet 10.170.35.0/24
That renders a small, pool-less anchor subnet on the link prefix, at the head of the group's block:
"shared-networks": [ {
"name": "cluster-edge",
"subnet4": [
{ "subnet": "10.170.35.0/24", "authoritative": false, "pools": [ ] },
{ "subnet": "10.141.0.0/16", "pools": [ { ... "client-class": "cluster-edge-cluster-pool-class" } ] },
{ "subnet": "10.160.0.0/16", "relay": { ... },
"pools": [ { ... "client-class": "cluster-edge-edge-pool-class" } ] }
]
} ]
Three things are worth understanding about the anchor:
- It has no pool. Its whole job is to be selectable, so that the server then moves to a real subnet in the same block. Nothing is ever served from it.
- The link prefix does not have to be a luna network.
dhcp_link_subnetis a prefix, not a reference: luna needs no network object for the link, and defining one changes nothing. Devices on that link that are not part of the cluster stay entirely outside luna's configuration. - The anchor belongs to the link, so it joins the group's block — not a block of its own. A group sibling left outside it would be unreachable from the anchor, which is the whole point of putting it there.
Because a foreign device on that link can also reach the server this way, every pool in a block that carries an anchor is fenced: a request that arrives with a link-selection sub-option and is not a netboot client is not served. Cluster nodes are unaffected; the neighbours on that link get nothing.
Shape 5 — one cluster, everything at once
The shapes above rarely arrive one at a time. A real cluster has local nodes and BMCs on the controller's own subnet, a plain relayed network, and a relay that rewrites selection with option 82.5 — all served from one configuration:
luna network change ipmi --shared cluster
luna network change remote --shared cluster
luna network change remote --dhcp_relay 10.150.0.1
luna network change edge --shared cluster
luna network change edge --dhcp_relay 10.160.0.1
luna network change edge --dhcp_link_subnet 10.170.35.0/24
All four networks are shared onto cluster, and that renders as two blocks, not one:
"shared-networks": [
{ "name": "cluster-ipmi-remote", "subnet4": [
{ "subnet": "10.141.0.0/16", "pools": [ { ... "client-class": "…-carrier-class" } ] },
{ "subnet": "10.148.0.0/16", "pools": [ { ... "client-class": "ipmi-class" } ] },
{ "subnet": "10.150.0.0/16", "relay": { "ip-addresses": [ "10.150.0.1" ] },
"pools": [ { "pool": "10.150.10.1-10.150.10.254" } ] } ] },
{ "name": "edge-linksel", "subnet4": [
{ "subnet": "10.170.35.0/24", "authoritative": false, "pools": [ ] },
{ "subnet": "10.160.0.0/16", "relay": { "ip-addresses": [ "10.160.0.1" ] },
"pools": [ { ... "client-class": "edge-boot-class" } ] } ] }
]
A block is a link, not a luna group. shared says "the same wire" for a host and its BMC, and
for a relayed network it is only the precondition dhcp_relay insists on — so one group can hold
relayed networks that are quite separate links. The anchor joins only the networks reached through
the same relay as the network carrying it. Merged with the rest it would be reachable from every
relayed member in the block, and an option-82.5 client would be served whichever the render
happened to put first.
Three details in that render are each one of the earlier shapes, doing its own job:
clusterandipmicarry pool classes — the wire case, shape 1. The class is what tells a host from a BMC when both arrive on the same segment.remote's pool carries none — shape 2. It is picked out by its relay, and a class there would refuse its own network's PXE clients, which would then fall through to the carrier's pool and boot on the wrong subnet.edge's pool is fenced, and its block is headed by a pool-less anchor — shape 4. The fence is what keeps the non-cluster devices on that link out of a cluster pool.
Measured on this configuration, with real relayed DHCPDISCOVER packets:
| client | served from |
|---|---|
| unknown node on the controller's subnet, PXE | cluster pool — 10.141.10.1 |
| BMC on the controller's subnet, udhcp | ipmi pool — 10.148.10.1 |
| unknown node over the plain relay | remote pool — 10.150.10.1 |
| unknown node over the 82.5 relay | edge pool — 10.160.10.1 |
| non-netboot device on the link prefix | nothing |
Set the anchor on one network. It applies to the block, and the same prefix may be rendered only once.
Anchor, or ignore the sub-option?
There is a second answer to a relay that sets option 82.5, and which one fits depends on the link.
anchor (dhcp_link_subnet) |
IGNORE_LINK_SELECTION |
|
|---|---|---|
| the sub-option is | honoured | ignored; the giaddr is used |
| needs a prefix in the config | yes, one pool-less subnet | no, nothing foreign at all |
| fences foreign devices out of your pools | yes | no |
| one relay fronting several links | works | breaks — the links become indistinguishable |
IGNORE_LINK_SELECTION is a server-wide setting in luna.ini, off by default:
[DHCP]
IGNORE_LINK_SELECTION = yes
followed by systemctl restart luna2-daemon. Turn it on where the relay reports a prefix you do
not want in the configuration and each link has its own giaddr and there is nothing on
those links to fence out. Leave it off otherwise — and it is ignored anyway wherever any network
declares an anchor, since an anchor says the sub-option carries information worth having.
Rules and limits
- An anchor requires a relay.
dhcp_link_subnetonly means something on a relayed path; setting it withoutdhcp_relayis refused, and clearing the relay clears the anchor with it. - An anchor must not be the network's own subnet. It would render the same prefix twice inside one block, which the DHCP server refuses.
- A link prefix may be used once. Setting the same
dhcp_link_subneton a network in a different group is refused, for the same reason: two blocks cannot both carry it. dhcp_relayrequires a shared network. Setting it on a network that is not shared is rejected.- Link-selection is Kea only. On ISC dhcpd,
dhcp_link_subnetis not rendered.
Checking the result
Luna regenerates the DHCP configuration whenever one of these settings changes, validates it with the server's own syntax check, and installs it only if both address families pass. An invalid render is logged and the previous configuration is left in place, so a live configuration is always one the server accepts.
kea-dhcp4 -t /etc/kea/kea-dhcp4.conf
Two things to look at in the rendered file:
- the networks you expect to be grouped are in one
shared-networksblock, and not also in the top-levelsubnet4; - every pool in a block that carries an anchor has a
client-class.
If a change does not appear, the reason is in the daemon log — by default
/var/log/luna/luna2-daemon.log, and set by LOGFILE in the [LOGGER] section of luna.ini:
grep -iE "dhcp|kea" /var/log/luna/luna2-daemon.log | tail -30