feat: support MTU and route changes for DHCP

This PR updates the behavior of our machine configs with respect to
DHCP-enabled interfaces. Now, if MTU is specified by the user, that
value will take precedence over any setting provided by the DHCP server.

Additionally, any routes specified will be appended to routes specified
by the DHCP server.

Signed-off-by: Spencer Smith <robertspencersmith@gmail.com>
This commit is contained in:
Spencer Smith
2020-10-16 15:28:41 -04:00
committed by talos-bot
parent af6388c755
commit 4c47fa259c
4 changed files with 36 additions and 10 deletions

View File

@ -1288,6 +1288,8 @@ Type: `string`
#### routes
A list of routes associated with the interface.
If used in combination with DHCP, these routes will be appended to routes returned by DHCP server.
Type: `array`
#### bond
@ -1303,6 +1305,8 @@ Type: `array`
#### mtu
The interface's MTU.
If used in combination with DHCP, this will override any MTU settings returned from DHCP server.
Type: `int`
#### dhcp

View File

@ -27,6 +27,8 @@ type DHCP struct {
Ack *dhcpv4.DHCPv4
NetIf *net.Interface
DHCPOptions config.DHCPOptions
Mtu int
RouteList []config.Route
}
// Name returns back the name of the address method.
@ -65,13 +67,20 @@ func (d *DHCP) Mask() net.IPMask {
// MTU returs the MTU size from the DHCP offer.
func (d *DHCP) MTU() uint32 {
mtuReturn := uint32(d.NetIf.MTU)
// TODO do we need to implement dhcpv4.GetUint32 upstream?
mtu, err := dhcpv4.GetUint16(dhcpv4.OptionInterfaceMTU, d.Ack.Options)
if err != nil {
return uint32(d.NetIf.MTU)
if err == nil {
mtuReturn = uint32(mtu)
}
return uint32(mtu)
// override with any non-zero Mtu value passed into the dhcp object
if uint32(d.Mtu) > 0 {
mtuReturn = uint32(d.Mtu)
}
return mtuReturn
}
// TTL denotes how long a DHCP offer is valid for.
@ -108,10 +117,6 @@ func (d *DHCP) Valid() bool {
// If the DHCP server returns both a Classless Static Routes option and
// a Router option, the DHCP client MUST ignore the Router option.
func (d *DHCP) Routes() (routes []*Route) {
if len(d.Ack.ClasslessStaticRoute()) > 0 {
return d.Ack.ClasslessStaticRoute()
}
defRoute := &net.IPNet{
IP: net.IPv4zero,
Mask: net.IPv4Mask(0, 0, 0, 0),
@ -121,6 +126,19 @@ func (d *DHCP) Routes() (routes []*Route) {
routes = append(routes, &Route{Router: router, Dest: defRoute})
}
// overwrite router option if classless routes were provided.
if len(d.Ack.ClasslessStaticRoute()) > 0 {
routes = d.Ack.ClasslessStaticRoute()
}
// append any routes that were provided in config
for _, route := range d.RouteList {
// nolint: errcheck
_, ipnet, _ := net.ParseCIDR(route.Network())
routes = append(routes, &Route{Dest: ipnet, Router: net.ParseIP(route.Gateway())})
}
return routes
}

View File

@ -46,7 +46,7 @@ func buildOptions(device config.Device, hostname string) (name string, opts []ni
opts = append(opts, nic.WithAddressing(s))
case device.DHCP():
d := &address.DHCP{DHCPOptions: device.DHCPOptions()}
d := &address.DHCP{DHCPOptions: device.DHCPOptions(), RouteList: device.Routes(), Mtu: device.MTU()}
opts = append(opts, nic.WithAddressing(d))
default:
// Allow master interface without any addressing if VLANs exist

View File

@ -818,13 +818,17 @@ type Device struct {
DeviceInterface string `yaml:"interface"`
// description: The CIDR to use.
DeviceCIDR string `yaml:"cidr"`
// description: A list of routes associated with the interface.
// description: |
// A list of routes associated with the interface.
// If used in combination with DHCP, these routes will be appended to routes returned by DHCP server.
DeviceRoutes []*Route `yaml:"routes"`
// description: Bond specific options.
DeviceBond *Bond `yaml:"bond"`
// description: VLAN specific options.
DeviceVlans []*Vlan `yaml:"vlans"`
// description: The interface's MTU.
// description: |
// The interface's MTU.
// If used in combination with DHCP, this will override any MTU settings returned from DHCP server.
DeviceMTU int `yaml:"mtu"`
// description: Indicates if DHCP should be used.
DeviceDHCP bool `yaml:"dhcp"`