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.
|
Indicates if the interface is a dummy interface.
|
||||||
Type: `bool`
|
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
|
### Bond
|
||||||
|
@ -18,13 +18,15 @@ import (
|
|||||||
|
|
||||||
"github.com/talos-systems/go-procfs/procfs"
|
"github.com/talos-systems/go-procfs/procfs"
|
||||||
|
|
||||||
|
"github.com/talos-systems/talos/pkg/machinery/config"
|
||||||
"github.com/talos-systems/talos/pkg/machinery/constants"
|
"github.com/talos-systems/talos/pkg/machinery/constants"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DHCP implements the Addressing interface.
|
// DHCP implements the Addressing interface.
|
||||||
type DHCP struct {
|
type DHCP struct {
|
||||||
Ack *dhcpv4.DHCPv4
|
Ack *dhcpv4.DHCPv4
|
||||||
NetIf *net.Interface
|
NetIf *net.Interface
|
||||||
|
DHCPOptions config.DHCPOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name returns back the name of the address method.
|
// 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))
|
opts = append(opts, nic.WithAddressing(s))
|
||||||
case device.DHCP():
|
case device.DHCP():
|
||||||
d := &address.DHCP{}
|
d := &address.DHCP{DHCPOptions: device.DHCPOptions()}
|
||||||
opts = append(opts, nic.WithAddressing(d))
|
opts = append(opts, nic.WithAddressing(d))
|
||||||
default:
|
default:
|
||||||
// Allow master interface without any addressing if VLANs exist
|
// Allow master interface without any addressing if VLANs exist
|
||||||
|
@ -17,6 +17,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/hashicorp/go-multierror"
|
"github.com/hashicorp/go-multierror"
|
||||||
|
"github.com/insomniacslk/dhcp/dhcpv4"
|
||||||
"github.com/jsimonetti/rtnetlink"
|
"github.com/jsimonetti/rtnetlink"
|
||||||
"github.com/jsimonetti/rtnetlink/rtnl"
|
"github.com/jsimonetti/rtnetlink/rtnl"
|
||||||
"github.com/mdlayher/netlink"
|
"github.com/mdlayher/netlink"
|
||||||
@ -338,7 +339,9 @@ func (n *NetworkInterface) configureInterface(method address.Addressing, link *n
|
|||||||
|
|
||||||
if method.Address() != nil {
|
if method.Address() != nil {
|
||||||
// Check to see if we need to configure the address
|
// 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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -368,20 +371,9 @@ func (n *NetworkInterface) configureInterface(method address.Addressing, link *n
|
|||||||
|
|
||||||
// Add any routes
|
// Add any routes
|
||||||
for _, r := range method.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
|
err = n.addRoute(method, r)
|
||||||
gw := r.Router
|
if err != nil {
|
||||||
if net.IPv4zero.Equal(gw) {
|
return err
|
||||||
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())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -414,3 +406,89 @@ func (n *NetworkInterface) Reset() {
|
|||||||
// nolint: errcheck
|
// nolint: errcheck
|
||||||
n.rtnlConn.LinkDown(link)
|
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
|
DHCP() bool
|
||||||
Ignore() bool
|
Ignore() bool
|
||||||
Dummy() 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
|
// Bond contains the various options for configuring a
|
||||||
|
@ -749,6 +749,23 @@ func (d *Device) Dummy() bool {
|
|||||||
return d.DeviceDummy
|
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.
|
// Network implements the MachineNetwork interface.
|
||||||
func (r *Route) Network() string {
|
func (r *Route) Network() string {
|
||||||
return r.RouteNetwork
|
return r.RouteNetwork
|
||||||
|
@ -832,6 +832,16 @@ type Device struct {
|
|||||||
DeviceIgnore bool `yaml:"ignore"`
|
DeviceIgnore bool `yaml:"ignore"`
|
||||||
// description: Indicates if the interface is a dummy interface.
|
// description: Indicates if the interface is a dummy interface.
|
||||||
DeviceDummy bool `yaml:"dummy"`
|
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
|
// Bond contains the various options for configuring a
|
||||||
|
Loading…
Reference in New Issue
Block a user