mirror of
				https://github.com/lingble/talos.git
				synced 2025-11-03 22:17:58 +00:00 
			
		
		
		
	feat: support metric values for DHCP
This PR adds a "DHCPOptions" field to the config. This field contains a single subfield currently, "RouteMetric". Setting this well ensure that any routes provided from the DHCP server are given this metric upon injection into the routing table. Signed-off-by: Spencer Smith <robertspencersmith@gmail.com>
This commit is contained in:
		@@ -1320,6 +1320,22 @@ Type: `bool`
 | 
			
		||||
Indicates if the interface is a dummy interface.
 | 
			
		||||
Type: `bool`
 | 
			
		||||
 | 
			
		||||
#### dhcpOptions
 | 
			
		||||
 | 
			
		||||
DHCP specific options.
 | 
			
		||||
DHCP *must* be set to true for these to take effect.
 | 
			
		||||
 | 
			
		||||
Type: `DHCPOptions`
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
### DHCPOptions
 | 
			
		||||
 | 
			
		||||
#### routeMetric
 | 
			
		||||
 | 
			
		||||
The priority of all routes received via DHCP
 | 
			
		||||
Type: `uint32`
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
### Bond
 | 
			
		||||
 
 | 
			
		||||
@@ -18,6 +18,7 @@ import (
 | 
			
		||||
 | 
			
		||||
	"github.com/talos-systems/go-procfs/procfs"
 | 
			
		||||
 | 
			
		||||
	"github.com/talos-systems/talos/pkg/machinery/config"
 | 
			
		||||
	"github.com/talos-systems/talos/pkg/machinery/constants"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -25,6 +26,7 @@ import (
 | 
			
		||||
type DHCP struct {
 | 
			
		||||
	Ack         *dhcpv4.DHCPv4
 | 
			
		||||
	NetIf       *net.Interface
 | 
			
		||||
	DHCPOptions config.DHCPOptions
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Name returns back the name of the address method.
 | 
			
		||||
 
 | 
			
		||||
@@ -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{}
 | 
			
		||||
		d := &address.DHCP{DHCPOptions: device.DHCPOptions()}
 | 
			
		||||
		opts = append(opts, nic.WithAddressing(d))
 | 
			
		||||
	default:
 | 
			
		||||
		// Allow master interface without any addressing if VLANs exist
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,7 @@ import (
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/hashicorp/go-multierror"
 | 
			
		||||
	"github.com/insomniacslk/dhcp/dhcpv4"
 | 
			
		||||
	"github.com/jsimonetti/rtnetlink"
 | 
			
		||||
	"github.com/jsimonetti/rtnetlink/rtnl"
 | 
			
		||||
	"github.com/mdlayher/netlink"
 | 
			
		||||
@@ -338,7 +339,9 @@ func (n *NetworkInterface) configureInterface(method address.Addressing, link *n
 | 
			
		||||
 | 
			
		||||
	if method.Address() != nil {
 | 
			
		||||
		// Check to see if we need to configure the address
 | 
			
		||||
		addrs, err := n.rtnlConn.Addrs(method.Link(), method.Family())
 | 
			
		||||
		var addrs []*net.IPNet
 | 
			
		||||
 | 
			
		||||
		addrs, err = n.rtnlConn.Addrs(method.Link(), method.Family())
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
@@ -368,20 +371,9 @@ func (n *NetworkInterface) configureInterface(method address.Addressing, link *n
 | 
			
		||||
 | 
			
		||||
	// Add any routes
 | 
			
		||||
	for _, r := range method.Routes() {
 | 
			
		||||
		// If gateway/router is 0.0.0.0 we'll set to nil so route scope decision will be correct
 | 
			
		||||
		gw := r.Router
 | 
			
		||||
		if net.IPv4zero.Equal(gw) {
 | 
			
		||||
			gw = nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		src := method.Address()
 | 
			
		||||
		// if destination is the ipv6 route,and gateway is LL do not pass a src address to set the default geteway
 | 
			
		||||
		if net.IPv6zero.Equal(r.Dest.IP) && gw.IsLinkLocalUnicast() {
 | 
			
		||||
			src = nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if err := n.rtnlConn.RouteAddSrc(method.Link(), *r.Dest, src, gw); err != nil {
 | 
			
		||||
			log.Println("failed to configure route: " + err.Error())
 | 
			
		||||
		err = n.addRoute(method, r)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -414,3 +406,89 @@ func (n *NetworkInterface) Reset() {
 | 
			
		||||
	// nolint: errcheck
 | 
			
		||||
	n.rtnlConn.LinkDown(link)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// addRoute is a function loosely copied from https://github.com/jsimonetti/rtnetlink/blob/154ecd417600f79d7847278a1e984056dc647acc/rtnl/route.go
 | 
			
		||||
// and merged with our logic on determining gw, src, dst, etc.
 | 
			
		||||
// we need this b/c we need to craft the route message ourselves to add attributes.
 | 
			
		||||
// nolint: gocyclo
 | 
			
		||||
func (n *NetworkInterface) addRoute(method address.Addressing, r *dhcpv4.Route) error {
 | 
			
		||||
	dst := *r.Dest
 | 
			
		||||
 | 
			
		||||
	// If gateway/router is 0.0.0.0 we'll set to nil so route scope decision will be correct
 | 
			
		||||
	gw := r.Router
 | 
			
		||||
	if net.IPv4zero.Equal(gw) {
 | 
			
		||||
		gw = nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	src := method.Address()
 | 
			
		||||
	// if destination is the ipv6 route,and gateway is LL do not pass a src address to set the default geteway
 | 
			
		||||
	if net.IPv6zero.Equal(r.Dest.IP) && gw.IsLinkLocalUnicast() {
 | 
			
		||||
		src = nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// determine if this is ipv4 or 6
 | 
			
		||||
	var af int
 | 
			
		||||
	if dst.IP.To4() != nil {
 | 
			
		||||
		af = unix.AF_INET
 | 
			
		||||
	} else if len(dst.IP) == net.IPv6len {
 | 
			
		||||
		af = unix.AF_INET6
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ifc := method.Link()
 | 
			
		||||
 | 
			
		||||
	// Determine scope
 | 
			
		||||
	var scope uint8
 | 
			
		||||
 | 
			
		||||
	switch {
 | 
			
		||||
	case gw != nil:
 | 
			
		||||
		scope = unix.RT_SCOPE_UNIVERSE
 | 
			
		||||
 | 
			
		||||
	case len(dst.IP) == net.IPv6len && dst.IP.To4() == nil:
 | 
			
		||||
		scope = unix.RT_SCOPE_UNIVERSE
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		// Set default scope to LINK
 | 
			
		||||
		scope = unix.RT_SCOPE_LINK
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	attr := rtnetlink.RouteAttributes{
 | 
			
		||||
		Dst:      dst.IP,
 | 
			
		||||
		OutIface: uint32(ifc.Index),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Set DHCP specific options
 | 
			
		||||
	if dhcpObj, ok := method.(*address.DHCP); ok {
 | 
			
		||||
		if dhcpObj.DHCPOptions != nil {
 | 
			
		||||
			attr.Priority = dhcpObj.DHCPOptions.RouteMetric()
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if attr.Priority == uint32(0) {
 | 
			
		||||
			attr.Priority = uint32(1024)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if gw != nil {
 | 
			
		||||
		attr.Gateway = gw
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var srclen int
 | 
			
		||||
	if src != nil {
 | 
			
		||||
		srclen, _ = src.Mask.Size()
 | 
			
		||||
		attr.Src = src.IP
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dstlen, _ := dst.Mask.Size()
 | 
			
		||||
 | 
			
		||||
	tx := &rtnetlink.RouteMessage{
 | 
			
		||||
		Family:     uint8(af),
 | 
			
		||||
		Table:      unix.RT_TABLE_MAIN,
 | 
			
		||||
		Protocol:   unix.RTPROT_BOOT,
 | 
			
		||||
		Type:       unix.RTN_UNICAST,
 | 
			
		||||
		Scope:      scope,
 | 
			
		||||
		DstLength:  uint8(dstlen),
 | 
			
		||||
		SrcLength:  uint8(srclen),
 | 
			
		||||
		Attributes: attr,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return n.rtnlConn.Conn.Route.Add(tx)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -115,6 +115,12 @@ type Device interface {
 | 
			
		||||
	DHCP() bool
 | 
			
		||||
	Ignore() bool
 | 
			
		||||
	Dummy() bool
 | 
			
		||||
	DHCPOptions() DHCPOptions
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DHCPOptions represents a set of DHCP options.
 | 
			
		||||
type DHCPOptions interface {
 | 
			
		||||
	RouteMetric() uint32
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Bond contains the various options for configuring a
 | 
			
		||||
 
 | 
			
		||||
@@ -749,6 +749,23 @@ func (d *Device) Dummy() bool {
 | 
			
		||||
	return d.DeviceDummy
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DHCPOptions implements the MachineNetwork interface.
 | 
			
		||||
func (d *Device) DHCPOptions() config.DHCPOptions {
 | 
			
		||||
	// Default route metric on systemd is 1024. This sets the same.
 | 
			
		||||
	if d.DeviceDHCPOptions == nil {
 | 
			
		||||
		return &DHCPOptions{
 | 
			
		||||
			DHCPRouteMetric: uint32(0),
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return d.DeviceDHCPOptions
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RouteMetric implements the MachineNetwork interface.
 | 
			
		||||
func (d *DHCPOptions) RouteMetric() uint32 {
 | 
			
		||||
	return d.DHCPRouteMetric
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Network implements the MachineNetwork interface.
 | 
			
		||||
func (r *Route) Network() string {
 | 
			
		||||
	return r.RouteNetwork
 | 
			
		||||
 
 | 
			
		||||
@@ -832,6 +832,16 @@ type Device struct {
 | 
			
		||||
	DeviceIgnore bool `yaml:"ignore"`
 | 
			
		||||
	//   description: Indicates if the interface is a dummy interface.
 | 
			
		||||
	DeviceDummy bool `yaml:"dummy"`
 | 
			
		||||
	//   description: |
 | 
			
		||||
	//     DHCP specific options.
 | 
			
		||||
	//     DHCP *must* be set to true for these to take effect.
 | 
			
		||||
	DeviceDHCPOptions *DHCPOptions `yaml:"dhcpOptions"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DHCPOptions contains options for configuring the DHCP settings for a given interface.
 | 
			
		||||
type DHCPOptions struct {
 | 
			
		||||
	//   description: The priority of all routes received via DHCP
 | 
			
		||||
	DHCPRouteMetric uint32 `yaml:"routeMetric"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Bond contains the various options for configuring a
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user