mirror of
https://github.com/siderolabs/talos.git
synced 2025-08-17 20:17:03 +02: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:
parent
a12eb76734
commit
7bc3fcf77d
@ -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,13 +18,15 @@ import (
|
||||
|
||||
"github.com/talos-systems/go-procfs/procfs"
|
||||
|
||||
"github.com/talos-systems/talos/pkg/machinery/config"
|
||||
"github.com/talos-systems/talos/pkg/machinery/constants"
|
||||
)
|
||||
|
||||
// DHCP implements the Addressing interface.
|
||||
type DHCP struct {
|
||||
Ack *dhcpv4.DHCPv4
|
||||
NetIf *net.Interface
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user