refactor(networkd): Switch from rtnetlink to rtnl
Gives a better abstraction on rtnetlink interaction Signed-off-by: Brad Beam <brad.beam@talos-systems.com>
This commit is contained in:
parent
313c118ad0
commit
cdc989ddda
160
.drone.yml
160
.drone.yml
@ -223,22 +223,22 @@ steps:
|
||||
depends_on:
|
||||
- rootfs
|
||||
|
||||
#- name: lint
|
||||
# image: autonomy/build-container:latest
|
||||
# commands:
|
||||
# - make lint
|
||||
# environment:
|
||||
# BINDIR: /usr/local/bin
|
||||
# BUILDKIT_HOST: ${BUILDKIT_HOST=tcp://buildkitd.ci.svc:1234}
|
||||
# volumes:
|
||||
# - name: dockersock
|
||||
# path: /var/run
|
||||
# - name: dev
|
||||
# path: /dev
|
||||
# - name: tmp
|
||||
# path: /tmp
|
||||
# depends_on:
|
||||
# - clone
|
||||
- name: lint
|
||||
image: autonomy/build-container:latest
|
||||
commands:
|
||||
- make lint
|
||||
environment:
|
||||
BINDIR: /usr/local/bin
|
||||
BUILDKIT_HOST: ${BUILDKIT_HOST=tcp://buildkitd.ci.svc:1234}
|
||||
volumes:
|
||||
- name: dockersock
|
||||
path: /var/run
|
||||
- name: dev
|
||||
path: /dev
|
||||
- name: tmp
|
||||
path: /tmp
|
||||
depends_on:
|
||||
- clone
|
||||
|
||||
- name: markdownlint
|
||||
image: autonomy/build-container:latest
|
||||
@ -614,22 +614,22 @@ steps:
|
||||
depends_on:
|
||||
- rootfs
|
||||
|
||||
#- name: lint
|
||||
# image: autonomy/build-container:latest
|
||||
# commands:
|
||||
# - make lint
|
||||
# environment:
|
||||
# BINDIR: /usr/local/bin
|
||||
# BUILDKIT_HOST: ${BUILDKIT_HOST=tcp://buildkitd.ci.svc:1234}
|
||||
# volumes:
|
||||
# - name: dockersock
|
||||
# path: /var/run
|
||||
# - name: dev
|
||||
# path: /dev
|
||||
# - name: tmp
|
||||
# path: /tmp
|
||||
# depends_on:
|
||||
# - clone
|
||||
- name: lint
|
||||
image: autonomy/build-container:latest
|
||||
commands:
|
||||
- make lint
|
||||
environment:
|
||||
BINDIR: /usr/local/bin
|
||||
BUILDKIT_HOST: ${BUILDKIT_HOST=tcp://buildkitd.ci.svc:1234}
|
||||
volumes:
|
||||
- name: dockersock
|
||||
path: /var/run
|
||||
- name: dev
|
||||
path: /dev
|
||||
- name: tmp
|
||||
path: /tmp
|
||||
depends_on:
|
||||
- clone
|
||||
|
||||
- name: markdownlint
|
||||
image: autonomy/build-container:latest
|
||||
@ -1141,22 +1141,22 @@ steps:
|
||||
depends_on:
|
||||
- rootfs
|
||||
|
||||
#- name: lint
|
||||
# image: autonomy/build-container:latest
|
||||
# commands:
|
||||
# - make lint
|
||||
# environment:
|
||||
# BINDIR: /usr/local/bin
|
||||
# BUILDKIT_HOST: ${BUILDKIT_HOST=tcp://buildkitd.ci.svc:1234}
|
||||
# volumes:
|
||||
# - name: dockersock
|
||||
# path: /var/run
|
||||
# - name: dev
|
||||
# path: /dev
|
||||
# - name: tmp
|
||||
# path: /tmp
|
||||
# depends_on:
|
||||
# - clone
|
||||
- name: lint
|
||||
image: autonomy/build-container:latest
|
||||
commands:
|
||||
- make lint
|
||||
environment:
|
||||
BINDIR: /usr/local/bin
|
||||
BUILDKIT_HOST: ${BUILDKIT_HOST=tcp://buildkitd.ci.svc:1234}
|
||||
volumes:
|
||||
- name: dockersock
|
||||
path: /var/run
|
||||
- name: dev
|
||||
path: /dev
|
||||
- name: tmp
|
||||
path: /tmp
|
||||
depends_on:
|
||||
- clone
|
||||
|
||||
- name: markdownlint
|
||||
image: autonomy/build-container:latest
|
||||
@ -1670,22 +1670,22 @@ steps:
|
||||
depends_on:
|
||||
- rootfs
|
||||
|
||||
#- name: lint
|
||||
# image: autonomy/build-container:latest
|
||||
# commands:
|
||||
# - make lint
|
||||
# environment:
|
||||
# BINDIR: /usr/local/bin
|
||||
# BUILDKIT_HOST: ${BUILDKIT_HOST=tcp://buildkitd.ci.svc:1234}
|
||||
# volumes:
|
||||
# - name: dockersock
|
||||
# path: /var/run
|
||||
# - name: dev
|
||||
# path: /dev
|
||||
# - name: tmp
|
||||
# path: /tmp
|
||||
# depends_on:
|
||||
# - clone
|
||||
- name: lint
|
||||
image: autonomy/build-container:latest
|
||||
commands:
|
||||
- make lint
|
||||
environment:
|
||||
BINDIR: /usr/local/bin
|
||||
BUILDKIT_HOST: ${BUILDKIT_HOST=tcp://buildkitd.ci.svc:1234}
|
||||
volumes:
|
||||
- name: dockersock
|
||||
path: /var/run
|
||||
- name: dev
|
||||
path: /dev
|
||||
- name: tmp
|
||||
path: /tmp
|
||||
depends_on:
|
||||
- clone
|
||||
|
||||
- name: markdownlint
|
||||
image: autonomy/build-container:latest
|
||||
@ -2199,22 +2199,22 @@ steps:
|
||||
depends_on:
|
||||
- rootfs
|
||||
|
||||
#- name: lint
|
||||
# image: autonomy/build-container:latest
|
||||
# commands:
|
||||
# - make lint
|
||||
# environment:
|
||||
# BINDIR: /usr/local/bin
|
||||
# BUILDKIT_HOST: ${BUILDKIT_HOST=tcp://buildkitd.ci.svc:1234}
|
||||
# volumes:
|
||||
# - name: dockersock
|
||||
# path: /var/run
|
||||
# - name: dev
|
||||
# path: /dev
|
||||
# - name: tmp
|
||||
# path: /tmp
|
||||
# depends_on:
|
||||
# - clone
|
||||
- name: lint
|
||||
image: autonomy/build-container:latest
|
||||
commands:
|
||||
- make lint
|
||||
environment:
|
||||
BINDIR: /usr/local/bin
|
||||
BUILDKIT_HOST: ${BUILDKIT_HOST=tcp://buildkitd.ci.svc:1234}
|
||||
volumes:
|
||||
- name: dockersock
|
||||
path: /var/run
|
||||
- name: dev
|
||||
path: /dev
|
||||
- name: tmp
|
||||
path: /tmp
|
||||
depends_on:
|
||||
- clone
|
||||
|
||||
- name: markdownlint
|
||||
image: autonomy/build-container:latest
|
||||
|
2
go.mod
2
go.mod
@ -2,6 +2,8 @@ module github.com/talos-systems/talos
|
||||
|
||||
go 1.12
|
||||
|
||||
replace github.com/jsimonetti/rtnetlink => github.com/bradbeam/rtnetlink v0.0.0-20190820045831-7b9ca088b93d
|
||||
|
||||
require (
|
||||
code.cloudfoundry.org/bytefmt v0.0.0-20180906201452-2aa6f33b730c
|
||||
github.com/beevik/ntp v0.2.0
|
||||
|
4
go.sum
4
go.sum
@ -42,6 +42,8 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce
|
||||
github.com/bifurcation/mint v0.0.0-20180715133206-93c51c6ce115/go.mod h1:zVt7zX3K/aDCk9Tj+VM7YymsX66ERvzCJzw8rFCX2JU=
|
||||
github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
|
||||
github.com/bradbeam/rtnetlink v0.0.0-20190820045831-7b9ca088b93d h1:w82c4zYkkMi98stDhWV5EB/+Pt6q8eyMzmtnzwy1HSs=
|
||||
github.com/bradbeam/rtnetlink v0.0.0-20190820045831-7b9ca088b93d/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
|
||||
github.com/caddyserver/caddy v1.0.1/go.mod h1:G+ouvOY32gENkJC+jhgl62TyhvqEsFaDiZ4uw0RzP1E=
|
||||
github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
||||
github.com/cespare/prettybench v0.0.0-20150116022406-03b8cfe5406c/go.mod h1:Xe6ZsFhtM8HrDku0pxJ3/Lr51rwykrzgFwpmTzleatY=
|
||||
@ -271,8 +273,6 @@ github.com/jimstudt/http-authentication v0.0.0-20140401203705-3eca13d6893a/go.mo
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a h1:84IpUNXj4mCR9CuCEvSiCArMbzr/TMbuPIadKDwypkI=
|
||||
github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
|
||||
github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
|
@ -44,7 +44,7 @@ func (task *UserDefinedNetwork) runtime(platform platform.Platform, data *userda
|
||||
}
|
||||
|
||||
// Convert links to nic
|
||||
log.Println("Discovering local network interfaces")
|
||||
log.Println("discovering local network interfaces")
|
||||
netconf, err := nwd.Discover()
|
||||
if err != nil {
|
||||
return err
|
||||
@ -53,9 +53,8 @@ func (task *UserDefinedNetwork) runtime(platform platform.Platform, data *userda
|
||||
// Configure specified interface
|
||||
netIfaces := make([]*nic.NetworkInterface, 0, len(netconf))
|
||||
var iface *nic.NetworkInterface
|
||||
for name, opts := range netconf {
|
||||
log.Printf("Creating interface %s", name)
|
||||
iface, err = nic.Create(opts...)
|
||||
for link, opts := range netconf {
|
||||
iface, err = nic.Create(link, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -65,7 +64,6 @@ func (task *UserDefinedNetwork) runtime(platform platform.Platform, data *userda
|
||||
|
||||
// kick off the addressing mechanism
|
||||
// Add any necessary routes
|
||||
log.Println("Configuring interface addressing")
|
||||
if err = nwd.Configure(netIfaces...); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -76,6 +74,7 @@ func (task *UserDefinedNetwork) runtime(platform platform.Platform, data *userda
|
||||
// 2. Kernel Arg
|
||||
// 3. DHCP response
|
||||
// 4. failsafe - talos-<ip addr>
|
||||
// default specified in etc.Hosts()
|
||||
var hostname string
|
||||
kernelHostname := kernel.ProcCmdline().Get(constants.KernelParamHostname).First()
|
||||
switch {
|
||||
@ -83,10 +82,8 @@ func (task *UserDefinedNetwork) runtime(platform platform.Platform, data *userda
|
||||
hostname = data.Networking.OS.Hostname
|
||||
case kernelHostname != nil:
|
||||
hostname = *kernelHostname
|
||||
case nwd.Hostname() != "":
|
||||
case nwd.Hostname(netIfaces...) != "":
|
||||
hostname = nwd.Hostname(netIfaces...)
|
||||
default:
|
||||
// will default in Hosts()
|
||||
}
|
||||
|
||||
return etc.Hosts(hostname)
|
||||
|
@ -40,9 +40,9 @@ func (task *Services) startSystemServices(data *userdata.UserData, mode runtime.
|
||||
// Start the services common to all nodes.
|
||||
svcs.Load(
|
||||
&services.MachinedAPI{},
|
||||
&services.Networkd{},
|
||||
&services.SystemContainerd{},
|
||||
&services.Containerd{},
|
||||
&services.Networkd{},
|
||||
&services.Udevd{},
|
||||
&services.OSD{},
|
||||
&services.NTPd{},
|
||||
|
@ -31,7 +31,8 @@ func (n *Networkd) ID(data *userdata.UserData) string {
|
||||
|
||||
// PreFunc implements the Service interface.
|
||||
func (n *Networkd) PreFunc(ctx context.Context, data *userdata.UserData) error {
|
||||
return containerd.Import(constants.SystemContainerdNamespace, &containerd.ImportRequest{
|
||||
importer := containerd.NewImporter(constants.SystemContainerdNamespace, containerd.WithContainerdAddress(constants.SystemContainerdAddress))
|
||||
return importer.Import(&containerd.ImportRequest{
|
||||
Path: "/usr/images/networkd.tar",
|
||||
Options: []containerdapi.ImportOpt{
|
||||
containerdapi.WithIndexName("talos/networkd"),
|
||||
@ -51,7 +52,7 @@ func (n *Networkd) Condition(data *userdata.UserData) conditions.Condition {
|
||||
|
||||
// DependsOn implements the Service interface.
|
||||
func (n *Networkd) DependsOn(data *userdata.UserData) []string {
|
||||
return []string{"containerd"}
|
||||
return []string{"system-containerd"}
|
||||
}
|
||||
|
||||
func (n *Networkd) Runner(data *userdata.UserData) (runner.Runner, error) {
|
||||
@ -65,6 +66,7 @@ func (n *Networkd) Runner(data *userdata.UserData) (runner.Runner, error) {
|
||||
mounts := []specs.Mount{
|
||||
{Type: "bind", Destination: constants.UserDataPath, Source: constants.UserDataPath, Options: []string{"rbind", "ro"}},
|
||||
{Type: "bind", Destination: "/etc/resolv.conf", Source: "/etc/resolv.conf", Options: []string{"rbind", "rw"}},
|
||||
{Type: "bind", Destination: "/etc/hosts", Source: "/etc/hosts", Options: []string{"rbind", "rw"}},
|
||||
}
|
||||
|
||||
env := []string{}
|
||||
@ -75,9 +77,11 @@ func (n *Networkd) Runner(data *userdata.UserData) (runner.Runner, error) {
|
||||
return restart.New(containerd.NewRunner(
|
||||
data,
|
||||
&args,
|
||||
runner.WithContainerdAddress(constants.SystemContainerdAddress),
|
||||
runner.WithContainerImage(image),
|
||||
runner.WithEnv(env),
|
||||
runner.WithOCISpecOpts(
|
||||
containerd.WithMemoryLimit(int64(1000000*32)),
|
||||
oci.WithMounts(mounts),
|
||||
),
|
||||
),
|
||||
|
@ -27,12 +27,8 @@ func main() {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Is there any value in returning the low level link or
|
||||
// should the translation to nic be handled here?
|
||||
// links := nwd.Discover()
|
||||
|
||||
// Convert links to nic
|
||||
log.Println("Discovering local network interfaces")
|
||||
log.Println("discovering local network interfaces")
|
||||
netconf, err = nwd.Discover()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
@ -44,7 +40,7 @@ func main() {
|
||||
log.Printf("failed to read userdata %s, using defaults: %+v", "/var/userdata.yaml", err)
|
||||
}
|
||||
|
||||
log.Println("Overlaying userdata network configuration")
|
||||
log.Println("overlaying userdata network configuration")
|
||||
// Update nic with userdata specified options
|
||||
if err = netconf.OverlayUserData(ud); err != nil {
|
||||
log.Fatal(err)
|
||||
@ -52,10 +48,10 @@ func main() {
|
||||
|
||||
// Configure specified interface
|
||||
netIfaces := make([]*nic.NetworkInterface, 0, len(netconf))
|
||||
for name, opts := range netconf {
|
||||
for link, opts := range netconf {
|
||||
var iface *nic.NetworkInterface
|
||||
log.Printf("Creating interface %s", name)
|
||||
iface, err = nic.Create(opts...)
|
||||
log.Printf("creating interface %s", link.Name)
|
||||
iface, err = nic.Create(link, opts...)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@ -65,11 +61,15 @@ func main() {
|
||||
|
||||
// kick off the addressing mechanism
|
||||
// Add any necessary routes
|
||||
log.Println("Configuring interface addressing")
|
||||
log.Println("configuring interface addressing")
|
||||
if err = nwd.Configure(netIfaces...); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Println("interface configuration")
|
||||
nwd.PrintState()
|
||||
|
||||
log.Println("starting renewal watcher")
|
||||
// handle dhcp renewal
|
||||
nwd.Renew(netIfaces...)
|
||||
}
|
||||
|
@ -6,14 +6,10 @@ package address
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"net"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/insomniacslk/dhcp/dhcpv4"
|
||||
"github.com/jsimonetti/rtnetlink"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// Addressing provides an interface for abstracting the underlying network
|
||||
@ -21,128 +17,18 @@ import (
|
||||
// supported.
|
||||
type Addressing interface {
|
||||
Name() string
|
||||
Discover(context.Context, string) error
|
||||
Address() net.IP
|
||||
Discover(context.Context) error
|
||||
Address() *net.IPNet
|
||||
Mask() net.IPMask
|
||||
MTU() uint32
|
||||
TTL() time.Duration
|
||||
Family() uint8
|
||||
Family() int
|
||||
Scope() uint8
|
||||
Routes() []*Route
|
||||
Resolvers() []net.IP
|
||||
Hostname() string
|
||||
Link() *net.Interface
|
||||
}
|
||||
|
||||
// Route is a representation of a network route
|
||||
type Route = dhcpv4.Route
|
||||
|
||||
// AddressMessage generates a rtnetlink.AddressMessage from the underlying
|
||||
// Addressing implementation. This message will be used to set the network
|
||||
// interface address.
|
||||
// nolint: golint
|
||||
func AddressMessage(method Addressing, idx uint32) *rtnetlink.AddressMessage {
|
||||
attrs := rtnetlink.AddressAttributes{
|
||||
Address: method.Address(),
|
||||
}
|
||||
|
||||
// AF_INET / ipv4 requires some additional configuration ( broadcast addr )
|
||||
if method.Family() == unix.AF_INET {
|
||||
brd := make(net.IP, len(method.Address()))
|
||||
binary.BigEndian.PutUint32(brd, binary.BigEndian.Uint32(method.Address())|^binary.BigEndian.Uint32(method.Mask()))
|
||||
|
||||
attrs.Broadcast = brd
|
||||
attrs.Local = method.Address()
|
||||
}
|
||||
|
||||
ones, _ := method.Mask().Size()
|
||||
|
||||
// TODO: look at setting dynamic/permanent flag on address
|
||||
// TODO: look at setting valid lifetime and preferred lifetime
|
||||
// Ref for scope configuration
|
||||
// https://elixir.bootlin.com/linux/latest/source/net/ipv4/fib_semantics.c#L919
|
||||
// https://unix.stackexchange.com/questions/123084/what-is-the-interface-scope-global-vs-link-used-for
|
||||
msg := &rtnetlink.AddressMessage{
|
||||
Family: method.Family(),
|
||||
PrefixLength: uint8(ones),
|
||||
Scope: method.Scope(),
|
||||
Index: idx,
|
||||
Attributes: attrs,
|
||||
}
|
||||
|
||||
return msg
|
||||
}
|
||||
|
||||
// RouteMessage generates a slice of rtnetlink.RouteMessages from the
|
||||
// underlying Addressing implementation. These messages will be used to set
|
||||
// up the routing table.
|
||||
func RouteMessage(method Addressing, idx uint32) []*rtnetlink.RouteMessage {
|
||||
routes := make([]*rtnetlink.RouteMessage, 0, len(method.Routes()))
|
||||
|
||||
var protocol uint8
|
||||
switch method.(type) {
|
||||
case *DHCP:
|
||||
protocol = unix.RTPROT_DHCP
|
||||
case *Static:
|
||||
protocol = unix.RTPROT_STATIC
|
||||
}
|
||||
|
||||
for _, route := range method.Routes() {
|
||||
attr := rtnetlink.RouteAttributes{
|
||||
OutIface: idx,
|
||||
Table: unix.RT_TABLE_MAIN,
|
||||
}
|
||||
|
||||
// Default to scope_link
|
||||
var scope uint8
|
||||
switch {
|
||||
case route.Dest == nil:
|
||||
// If no dest set, assume gateway
|
||||
scope = unix.RT_SCOPE_UNIVERSE
|
||||
case route.Dest.IP.Equal(net.IPv4zero):
|
||||
scope = unix.RT_SCOPE_UNIVERSE
|
||||
default:
|
||||
scope = unix.RT_SCOPE_LINK
|
||||
}
|
||||
|
||||
routeMsg := &rtnetlink.RouteMessage{
|
||||
Family: method.Family(),
|
||||
Table: unix.RT_TABLE_MAIN,
|
||||
Protocol: protocol,
|
||||
Scope: scope,
|
||||
Type: unix.RTN_UNICAST,
|
||||
}
|
||||
|
||||
if route.Dest != nil {
|
||||
attr.Dst = route.Dest.IP
|
||||
dstLength, _ := route.Dest.Mask.Size()
|
||||
routeMsg.DstLength = uint8(dstLength)
|
||||
}
|
||||
|
||||
if route.Router != nil {
|
||||
attr.Gateway = route.Router
|
||||
}
|
||||
|
||||
// TODO figure out if Src is actually needed
|
||||
/*
|
||||
if r.Src != nil {
|
||||
attr.Src = r.Src.IP
|
||||
ones, _ := r.Src.Net.Mask.Size()
|
||||
routeMsg.SrcLength = uint8(ones)
|
||||
}
|
||||
*/
|
||||
|
||||
routeMsg.Attributes = attr
|
||||
|
||||
routes = append(routes, routeMsg)
|
||||
}
|
||||
|
||||
// Return a sorted list of routes by scope
|
||||
// This should allow us to set up link level routes
|
||||
// before universal routes. This should help prevent
|
||||
// any network unreachable errors
|
||||
sort.Slice(routes, func(i, j int) bool {
|
||||
return routes[i].Scope > routes[j].Scope
|
||||
})
|
||||
|
||||
return routes
|
||||
}
|
||||
|
@ -20,7 +20,8 @@ import (
|
||||
|
||||
// DHCP implements the Addressing interface
|
||||
type DHCP struct {
|
||||
Ack *dhcpv4.DHCPv4
|
||||
Ack *dhcpv4.DHCPv4
|
||||
NetIf *net.Interface
|
||||
}
|
||||
|
||||
// Name returns back the name of the address method.
|
||||
@ -28,17 +29,26 @@ func (d *DHCP) Name() string {
|
||||
return "dhcp"
|
||||
}
|
||||
|
||||
// Link returns the underlying net.Interface that this address
|
||||
// method is configured for
|
||||
func (d *DHCP) Link() *net.Interface {
|
||||
return d.NetIf
|
||||
}
|
||||
|
||||
// Discover handles the DHCP client exchange stores the DHCP Ack.
|
||||
func (d *DHCP) Discover(ctx context.Context, name string) error {
|
||||
func (d *DHCP) Discover(ctx context.Context) error {
|
||||
// TODO do something with context
|
||||
ack, err := discover(name)
|
||||
ack, err := d.discover()
|
||||
d.Ack = ack
|
||||
return err
|
||||
}
|
||||
|
||||
// Address returns back the IP address from the received DHCP offer.
|
||||
func (d *DHCP) Address() net.IP {
|
||||
return d.Ack.YourIPAddr
|
||||
func (d *DHCP) Address() *net.IPNet {
|
||||
return &net.IPNet{
|
||||
IP: d.Ack.YourIPAddr,
|
||||
Mask: d.Mask(),
|
||||
}
|
||||
}
|
||||
|
||||
// Mask returns the netmask from the DHCP offer.
|
||||
@ -51,7 +61,7 @@ func (d *DHCP) MTU() uint32 {
|
||||
// TODO do we need to implement dhcpv4.GetUint32 upstream?
|
||||
mtu, err := dhcpv4.GetUint16(dhcpv4.OptionInterfaceMTU, d.Ack.Options)
|
||||
if err != nil {
|
||||
return 1500
|
||||
return uint32(d.NetIf.MTU)
|
||||
}
|
||||
return uint32(mtu)
|
||||
}
|
||||
@ -65,7 +75,7 @@ func (d *DHCP) TTL() time.Duration {
|
||||
}
|
||||
|
||||
// Family qualifies the address as ipv4 or ipv6
|
||||
func (d *DHCP) Family() uint8 {
|
||||
func (d *DHCP) Family() int {
|
||||
if d.Ack.YourIPAddr.To4() != nil {
|
||||
return unix.AF_INET
|
||||
}
|
||||
@ -79,13 +89,23 @@ func (d *DHCP) Scope() uint8 {
|
||||
|
||||
// Routes aggregates all Routers and ClasslessStaticRoutes retrieved from
|
||||
// the DHCP offer.
|
||||
// rfc3442:
|
||||
// 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) {
|
||||
for _, router := range d.Ack.Router() {
|
||||
// Note, we don't set a Dest on routes generated from Router()
|
||||
// since these all should be gateways ( listed in order of preference )
|
||||
routes = append(routes, &Route{Router: router})
|
||||
if len(d.Ack.ClasslessStaticRoute()) > 0 {
|
||||
return d.Ack.ClasslessStaticRoute()
|
||||
}
|
||||
routes = append(routes, d.Ack.ClasslessStaticRoute()...)
|
||||
|
||||
defRoute := &net.IPNet{
|
||||
IP: net.IPv4zero,
|
||||
Mask: net.IPv4Mask(0, 0, 0, 0),
|
||||
}
|
||||
|
||||
for _, router := range d.Ack.Router() {
|
||||
routes = append(routes, &Route{Router: router, Dest: defRoute})
|
||||
}
|
||||
|
||||
return routes
|
||||
}
|
||||
|
||||
@ -102,7 +122,7 @@ func (d *DHCP) Hostname() string {
|
||||
}
|
||||
|
||||
// discover handles the actual DHCP conversation.
|
||||
func discover(name string) (*dhcpv4.DHCPv4, error) {
|
||||
func (d *DHCP) discover() (*dhcpv4.DHCPv4, error) {
|
||||
opts := []dhcpv4.OptionCode{
|
||||
dhcpv4.OptionClasslessStaticRoute,
|
||||
dhcpv4.OptionDomainNameServer,
|
||||
@ -124,11 +144,10 @@ func discover(name string) (*dhcpv4.DHCPv4, error) {
|
||||
|
||||
mods := []dhcpv4.Modifier{dhcpv4.WithRequestedOptions(opts...)}
|
||||
|
||||
// TODO expose this with some debug logging option
|
||||
cli, err := nclient4.New(name, nclient4.WithTimeout(10*time.Second), nclient4.WithDebugLogger())
|
||||
//cli, err := nclient4.New(name, nclient4.WithTimeout(2*time.Second))
|
||||
// TODO expose this ( nclient4.WithDebugLogger() ) with some
|
||||
// debug logging option
|
||||
cli, err := nclient4.New(d.NetIf.Name, nclient4.WithTimeout(2*time.Second))
|
||||
if err != nil {
|
||||
log.Println("failed nclient4.new")
|
||||
return nil, err
|
||||
}
|
||||
// nolint: errcheck
|
||||
|
@ -16,11 +16,12 @@ import (
|
||||
// Static implements the Addressing interface
|
||||
type Static struct {
|
||||
Device *userdata.Device
|
||||
NetIf *net.Interface
|
||||
}
|
||||
|
||||
// Discover doesnt do anything in the static configuration since all
|
||||
// the necessary configuration data is supplied via userdata.
|
||||
func (s *Static) Discover(ctx context.Context, name string) error {
|
||||
func (s *Static) Discover(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -30,13 +31,11 @@ func (s *Static) Name() string {
|
||||
}
|
||||
|
||||
// Address returns the IP address
|
||||
func (s *Static) Address() net.IP {
|
||||
func (s *Static) Address() *net.IPNet {
|
||||
// nolint: errcheck
|
||||
ip, _, _ := net.ParseCIDR(s.Device.CIDR)
|
||||
if to4 := ip.To4(); to4 != nil {
|
||||
return to4
|
||||
}
|
||||
return ip
|
||||
ip, ipn, _ := net.ParseCIDR(s.Device.CIDR)
|
||||
ipn.IP = ip
|
||||
return ipn
|
||||
}
|
||||
|
||||
// Mask returns the netmask.
|
||||
@ -50,7 +49,7 @@ func (s *Static) Mask() net.IPMask {
|
||||
func (s *Static) MTU() uint32 {
|
||||
mtu := uint32(s.Device.MTU)
|
||||
if mtu == 0 {
|
||||
mtu = 1500
|
||||
mtu = uint32(s.NetIf.MTU)
|
||||
}
|
||||
return mtu
|
||||
}
|
||||
@ -62,8 +61,8 @@ func (s *Static) TTL() time.Duration {
|
||||
}
|
||||
|
||||
// Family qualifies the address as ipv4 or ipv6
|
||||
func (s *Static) Family() uint8 {
|
||||
if s.Address().To4() != nil {
|
||||
func (s *Static) Family() int {
|
||||
if s.Address().IP.To4() != nil {
|
||||
return unix.AF_INET
|
||||
}
|
||||
return unix.AF_INET6
|
||||
@ -97,3 +96,9 @@ func (s *Static) Resolvers() []net.IP {
|
||||
func (s *Static) Hostname() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Link returns the underlying net.Interface that this address
|
||||
// method is configured for
|
||||
func (s Static) Link() *net.Interface {
|
||||
return s.NetIf
|
||||
}
|
||||
|
@ -11,7 +11,6 @@ import (
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/jsimonetti/rtnetlink"
|
||||
"github.com/talos-systems/talos/internal/app/networkd/pkg/address"
|
||||
"github.com/talos-systems/talos/internal/app/networkd/pkg/nic"
|
||||
"github.com/talos-systems/talos/pkg/userdata"
|
||||
@ -19,16 +18,14 @@ import (
|
||||
|
||||
// filterInterfaceByName filters network links by name so we only mange links
|
||||
// we need to
|
||||
func filterInterfaceByName(links []rtnetlink.LinkMessage) (filteredLinks []rtnetlink.LinkMessage) {
|
||||
func filterInterfaceByName(links []*net.Interface) (filteredLinks []*net.Interface) {
|
||||
for _, link := range links {
|
||||
switch {
|
||||
case strings.HasPrefix(link.Attributes.Name, "en"):
|
||||
case strings.HasPrefix(link.Name, "en"):
|
||||
filteredLinks = append(filteredLinks, link)
|
||||
case strings.HasPrefix(link.Attributes.Name, "eth"):
|
||||
case strings.HasPrefix(link.Name, "eth"):
|
||||
filteredLinks = append(filteredLinks, link)
|
||||
// TODO Add bond support
|
||||
// case strings.HasPrefix(netif.Name, "bond"):
|
||||
case strings.HasPrefix(link.Attributes.Name, "lo"):
|
||||
case strings.HasPrefix(link.Name, "lo"):
|
||||
filteredLinks = append(filteredLinks, link)
|
||||
}
|
||||
}
|
||||
@ -37,23 +34,24 @@ func filterInterfaceByName(links []rtnetlink.LinkMessage) (filteredLinks []rtnet
|
||||
}
|
||||
|
||||
// parseLinkMessage creates the base set of attributes for nic creation
|
||||
func parseLinkMessage(link rtnetlink.LinkMessage) []nic.Option {
|
||||
func parseLinkMessage(link *net.Interface) []nic.Option {
|
||||
opts := []nic.Option{}
|
||||
|
||||
opts = append(opts, nic.WithName(link.Attributes.Name))
|
||||
opts = append(opts, nic.WithMTU(link.Attributes.MTU))
|
||||
opts = append(opts, nic.WithIndex(link.Index))
|
||||
opts = append(opts, nic.WithName(link.Name))
|
||||
opts = append(opts, nic.WithMTU(uint32(link.MTU)))
|
||||
opts = append(opts, nic.WithIndex(uint32(link.Index)))
|
||||
|
||||
// Ensure lo has proper loopback address
|
||||
// Ensure MTU for loopback is 64k
|
||||
// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=0cf833aefaa85bbfce3ff70485e5534e09254773
|
||||
if strings.HasPrefix(link.Attributes.Name, "lo") {
|
||||
if strings.HasPrefix(link.Name, "lo") {
|
||||
opts = append(opts, nic.WithAddressing(
|
||||
&address.Static{
|
||||
Device: &userdata.Device{
|
||||
CIDR: "127.0.0.1/8",
|
||||
MTU: 65536,
|
||||
},
|
||||
NetIf: link,
|
||||
},
|
||||
))
|
||||
}
|
||||
@ -76,7 +74,7 @@ func writeResolvConf(resolvers []net.IP) error {
|
||||
break
|
||||
}
|
||||
if _, err = resolvconf.WriteString(fmt.Sprintf("nameserver %s\n", resolver)); err != nil {
|
||||
log.Println("failde to add some resolver to resolvconf")
|
||||
log.Println("failed to add some resolver to resolvconf")
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -5,38 +5,47 @@
|
||||
package networkd
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/talos-systems/talos/internal/app/networkd/pkg/address"
|
||||
"github.com/talos-systems/talos/internal/app/networkd/pkg/nic"
|
||||
"github.com/talos-systems/talos/pkg/userdata"
|
||||
)
|
||||
|
||||
// NetConf provides a mapping between an interface name and the functional
|
||||
// NetConf provides a mapping between an interface link and the functional
|
||||
// options needed to configure the interface
|
||||
type NetConf map[string][]nic.Option
|
||||
type NetConf map[*net.Interface][]nic.Option
|
||||
|
||||
// OverlayUserData translates the supplied userdata to functional options
|
||||
func (n *NetConf) OverlayUserData(data *userdata.UserData) error {
|
||||
if !validNetworkUserData(data) {
|
||||
if !validateNetworkUserData(data) {
|
||||
return nil
|
||||
}
|
||||
|
||||
for name, opts := range *n {
|
||||
for link, opts := range *n {
|
||||
for _, device := range data.Networking.OS.Devices {
|
||||
|
||||
device := device
|
||||
if name != device.Interface {
|
||||
if link.Name != device.Interface {
|
||||
continue
|
||||
}
|
||||
|
||||
if device.CIDR != "" {
|
||||
s := &address.Static{Device: &device}
|
||||
// Configure Addressing
|
||||
if device.DHCP {
|
||||
d := &address.DHCP{NetIf: link}
|
||||
(*n)[link] = append(opts, nic.WithAddressing(d))
|
||||
}
|
||||
|
||||
(*n)[name] = append(opts, nic.WithAddressing(s))
|
||||
if device.CIDR != "" {
|
||||
s := &address.Static{Device: &device, NetIf: link}
|
||||
(*n)[link] = append(opts, nic.WithAddressing(s))
|
||||
}
|
||||
|
||||
// Configure MTU
|
||||
if device.MTU != 0 {
|
||||
(*n)[name] = append(opts, nic.WithMTU(uint32(device.MTU)))
|
||||
(*n)[link] = append(opts, nic.WithMTU(uint32(device.MTU)))
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -44,7 +53,7 @@ func (n *NetConf) OverlayUserData(data *userdata.UserData) error {
|
||||
}
|
||||
|
||||
// validateNetworkUserData ensures that we have actual data to do our lookups
|
||||
func validNetworkUserData(data *userdata.UserData) bool {
|
||||
func validateNetworkUserData(data *userdata.UserData) bool {
|
||||
if data == nil {
|
||||
return false
|
||||
}
|
||||
|
@ -6,57 +6,22 @@ package networkd
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
"github.com/jsimonetti/rtnetlink"
|
||||
"github.com/mdlayher/netlink"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// ifup sets the link state to up
|
||||
func (n *Networkd) ifup(idx uint32) error {
|
||||
msg, err := n.Conn.Link.Get(idx)
|
||||
if err != nil {
|
||||
log.Printf("failed to get link %d\n", idx)
|
||||
return err
|
||||
}
|
||||
|
||||
// Only bring the link up if needed
|
||||
switch msg.Attributes.OperationalState {
|
||||
case rtnetlink.OperStateUp:
|
||||
case rtnetlink.OperStateUnknown:
|
||||
default:
|
||||
err = n.Conn.Link.Set(&rtnetlink.LinkMessage{
|
||||
Family: msg.Family,
|
||||
Type: msg.Type,
|
||||
Index: idx,
|
||||
Flags: unix.IFF_UP,
|
||||
Change: unix.IFF_UP,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Println("failed ifup")
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// setMTU sets the link MTU
|
||||
func (n *Networkd) setMTU(idx, mtu uint32) error {
|
||||
msg, err := n.Conn.Link.Get(idx)
|
||||
func (n *Networkd) setMTU(idx int, mtu uint32) error {
|
||||
msg, err := n.nlConn.Link.Get(uint32(idx))
|
||||
if err != nil {
|
||||
log.Printf("failed to get link %d\n", idx)
|
||||
return err
|
||||
}
|
||||
|
||||
err = n.Conn.Link.Set(&rtnetlink.LinkMessage{
|
||||
err = n.nlConn.Link.Set(&rtnetlink.LinkMessage{
|
||||
Family: msg.Family,
|
||||
Type: msg.Type,
|
||||
Index: idx,
|
||||
Index: uint32(idx),
|
||||
Flags: msg.Flags,
|
||||
Change: 0,
|
||||
Attributes: &rtnetlink.LinkAttributes{
|
||||
@ -66,131 +31,3 @@ func (n *Networkd) setMTU(idx, mtu uint32) error {
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// AddressAdd attempts to configure an address on an interface specified by
|
||||
// the rtnetlink.AddressMessage. If the address is already configured on the
|
||||
// interface, no action is taken.
|
||||
func (n *Networkd) AddressAdd(msg *rtnetlink.AddressMessage) error {
|
||||
exists, err := n.addressExists(msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if exists {
|
||||
return err
|
||||
}
|
||||
|
||||
return n.Conn.Address.New(msg)
|
||||
}
|
||||
|
||||
func (n *Networkd) addressExists(msg *rtnetlink.AddressMessage) (bool, error) {
|
||||
al, err := n.Conn.Address.List()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// See if the address is already configured
|
||||
for _, addr := range al {
|
||||
if addr.Index == msg.Index {
|
||||
if !msg.Attributes.Address.Equal(addr.Attributes.Address) {
|
||||
continue
|
||||
}
|
||||
if msg.PrefixLength != addr.PrefixLength {
|
||||
continue
|
||||
}
|
||||
return true, err
|
||||
}
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
|
||||
// RouteAdd attempts to configure a route specified by the
|
||||
// rtnetlink.RouteMessage. If the route is already configured in the
|
||||
// routing table, no action is taken.
|
||||
func (n *Networkd) RouteAdd(msg *rtnetlink.RouteMessage) error {
|
||||
exists, err := n.routeExists(msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if exists {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = n.Conn.Route.Add(msg); err != nil {
|
||||
// nolint: gocritic
|
||||
switch err := err.(type) {
|
||||
case *netlink.OpError:
|
||||
// ignore the error if it's -EEXIST or -ESRCH
|
||||
if !os.IsExist(err.Err) && err.Err != syscall.ESRCH {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *Networkd) routeExists(msg *rtnetlink.RouteMessage) (bool, error) {
|
||||
rl, err := n.Conn.Route.List()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
for _, route := range rl {
|
||||
if msg.Attributes.OutIface != route.Attributes.OutIface {
|
||||
continue
|
||||
}
|
||||
|
||||
// This feels super ugly
|
||||
// Only compare against what was given
|
||||
if msg.Attributes.Dst != nil {
|
||||
if !compareNets(msg.Attributes.Dst, route.Attributes.Dst) {
|
||||
continue
|
||||
}
|
||||
if msg.DstLength != route.DstLength {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if msg.Attributes.Gateway != nil {
|
||||
if !compareNets(msg.Attributes.Gateway, route.Attributes.Gateway) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
// Unsure what to do if scope doesnt match
|
||||
// feels like it should require a delete + add
|
||||
|
||||
// TODO figure out if Src is actually needed
|
||||
/*
|
||||
if msg.Attributes.Src != nil {
|
||||
if !compareNets(msg.Attributes.Src, route.Attributes.Src) {
|
||||
continue
|
||||
}
|
||||
if msg.SrcLength != route.SrcLength {
|
||||
continue
|
||||
}
|
||||
}
|
||||
*/
|
||||
return true, err
|
||||
|
||||
}
|
||||
|
||||
return false, err
|
||||
}
|
||||
|
||||
// compareNets is a simple utility function to see if address `a` is
|
||||
// equal to `b`
|
||||
func compareNets(a, b net.IP) bool {
|
||||
if a == nil && b == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
if a != nil && a.Equal(b) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
@ -6,14 +6,19 @@ package networkd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"sync"
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/jsimonetti/rtnetlink"
|
||||
"github.com/jsimonetti/rtnetlink/rtnl"
|
||||
"github.com/mdlayher/netlink"
|
||||
"github.com/talos-systems/talos/internal/app/networkd/pkg/address"
|
||||
"github.com/talos-systems/talos/internal/app/networkd/pkg/nic"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// Set up default nameservers
|
||||
@ -23,28 +28,36 @@ const (
|
||||
)
|
||||
|
||||
// Networkd provides the high level interaction to configure network interfaces
|
||||
// on a host system. This currently support addressing configuration via dhcp
|
||||
// on a host system. This currently supports addressing configuration via dhcp
|
||||
// and/or a specified configuration file.
|
||||
type Networkd struct {
|
||||
Conn *rtnetlink.Conn
|
||||
Conn *rtnl.Conn
|
||||
nlConn *rtnetlink.Conn
|
||||
}
|
||||
|
||||
// New instantiates a new rtnetlink connection that is used for all subsequent
|
||||
// actions
|
||||
func New() (*Networkd, error) {
|
||||
// Handle netlink connection
|
||||
conn, err := rtnetlink.Dial(nil)
|
||||
conn, err := rtnl.Dial(nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Networkd{Conn: conn}, err
|
||||
// Need rtnetlink for MTU setting
|
||||
// TODO: possible rtnl enhancement
|
||||
nlConn, err := rtnetlink.Dial(nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Networkd{Conn: conn, nlConn: nlConn}, err
|
||||
}
|
||||
|
||||
// Discover enumerates a list of network links on the host and creates a
|
||||
// base set of interface configuration options
|
||||
func (n *Networkd) Discover() (NetConf, error) {
|
||||
links, err := n.Conn.Link.List()
|
||||
links, err := n.Conn.Links()
|
||||
if err != nil {
|
||||
return NetConf{}, err
|
||||
}
|
||||
@ -52,7 +65,7 @@ func (n *Networkd) Discover() (NetConf, error) {
|
||||
linkmap := NetConf{}
|
||||
|
||||
for _, link := range filterInterfaceByName(links) {
|
||||
linkmap[link.Attributes.Name] = parseLinkMessage(link)
|
||||
linkmap[link] = parseLinkMessage(link)
|
||||
}
|
||||
|
||||
return linkmap, nil
|
||||
@ -68,15 +81,9 @@ func (n *Networkd) Configure(ifaces ...*nic.NetworkInterface) error {
|
||||
)
|
||||
|
||||
for _, iface := range ifaces {
|
||||
log.Printf("configuring %+v\n", iface)
|
||||
// Attempt dhcp against all unconfigured interfaces
|
||||
if len(iface.AddressMethod) == 0 {
|
||||
iface.AddressMethod = append(iface.AddressMethod, &address.DHCP{})
|
||||
}
|
||||
|
||||
// Bring up the interface
|
||||
if err = n.ifup(iface.Index); err != nil {
|
||||
log.Printf("Failed to bring up %s: %v", iface.Name, err)
|
||||
if err = n.Conn.LinkUp(&net.Interface{Index: int(iface.Index)}); err != nil {
|
||||
log.Printf("failed to bring up %s: %v", iface.Name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
@ -84,7 +91,8 @@ func (n *Networkd) Configure(ifaces ...*nic.NetworkInterface) error {
|
||||
// the interface
|
||||
for _, method := range iface.AddressMethod {
|
||||
log.Printf("configuring %s addressing for %s\n", method.Name(), iface.Name)
|
||||
if err = n.configureInterface(method, iface.Name, iface.Index); err != nil {
|
||||
|
||||
if err = n.configureInterface(method); err != nil {
|
||||
// Treat as non fatal error when failing to configure an interface
|
||||
log.Println(err)
|
||||
continue
|
||||
@ -107,35 +115,31 @@ func (n *Networkd) Configure(ifaces ...*nic.NetworkInterface) error {
|
||||
// addressing configuration. Currently this only applies to interfaces
|
||||
// configured by DHCP.
|
||||
func (n *Networkd) Renew(ifaces ...*nic.NetworkInterface) {
|
||||
var wg sync.WaitGroup
|
||||
for _, iface := range ifaces {
|
||||
for _, method := range iface.AddressMethod {
|
||||
if method.TTL() == 0 {
|
||||
continue
|
||||
}
|
||||
wg.Add(1)
|
||||
|
||||
go n.renew(method, iface.Name, iface.Index)
|
||||
go n.renew(method)
|
||||
}
|
||||
}
|
||||
|
||||
// We dont ever wg.Done
|
||||
// because this should run forever
|
||||
// Probably a better way to do this
|
||||
wg.Wait()
|
||||
// TODO switch this out with context when that gets added
|
||||
select {}
|
||||
}
|
||||
|
||||
// renew sets up the looping to ensure we keep the addressing information
|
||||
// up to date. We attempt to do our first reconfiguration halfway through
|
||||
// address TTL. If that fails, we'll continue to attempt to retry every
|
||||
// halflife.
|
||||
func (n *Networkd) renew(method address.Addressing, name string, index uint32) {
|
||||
func (n *Networkd) renew(method address.Addressing) {
|
||||
renewDuration := method.TTL() / 2
|
||||
for {
|
||||
<-time.After(renewDuration)
|
||||
|
||||
if err := n.configureInterface(method, name, index); err != nil {
|
||||
log.Printf("failed to renew interface address for %s: %v\n", name, err)
|
||||
if err := n.configureInterface(method); err != nil {
|
||||
log.Printf("failed to renew interface address for %s: %v\n", method.Link().Name, err)
|
||||
renewDuration = (renewDuration / 2)
|
||||
} else {
|
||||
renewDuration = method.TTL() / 2
|
||||
@ -145,43 +149,70 @@ func (n *Networkd) renew(method address.Addressing, name string, index uint32) {
|
||||
|
||||
// configureInterface handles the actual address discovery mechanism and
|
||||
// netlink interaction to configure the interface
|
||||
func (n *Networkd) configureInterface(method address.Addressing, name string, index uint32) error {
|
||||
// nolint: gocyclo
|
||||
func (n *Networkd) configureInterface(method address.Addressing) error {
|
||||
// TODO s/Discover/Something else/
|
||||
// TODO make context more relevant
|
||||
var err error
|
||||
if err = method.Discover(context.Background(), name); err != nil {
|
||||
if err = method.Discover(context.Background()); err != nil {
|
||||
// Right now this would only happen during dhcp discovery failure
|
||||
log.Printf("Failed to prep %s: %v", name, err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Netlink message generation
|
||||
msg := address.AddressMessage(method, index)
|
||||
|
||||
// Add address if not exist
|
||||
if err = n.AddressAdd(msg); err != nil {
|
||||
// TODO how do we want to handle failures in addressing?
|
||||
log.Printf("Failed to add address %+v to %s: %v", msg, name, err)
|
||||
log.Printf("failed to prep %s: %v", method.Link().Name, err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Set link MTU if we got a response
|
||||
if err = n.setMTU(index, method.MTU()); err != nil {
|
||||
log.Printf("Failed to set mtu %d for %s: %v", method.MTU(), name, err)
|
||||
if err = n.setMTU(method.Link().Index, method.MTU()); err != nil {
|
||||
log.Printf("failed to set mtu %d for %s: %v", method.MTU(), method.Link().Name, err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Add any routes
|
||||
rMsgs := address.RouteMessage(method, index)
|
||||
for _, r := range rMsgs {
|
||||
if err = n.RouteAdd(r); err != nil {
|
||||
// TODO how do we want to handle failures in routing?
|
||||
log.Printf("Failed to add route %+v for %s: %v", r, name, err)
|
||||
continue
|
||||
// Check to see if we need to configure the address
|
||||
addrs, err := n.Conn.Addrs(method.Link(), method.Family())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
addressExists := false
|
||||
for _, addr := range addrs {
|
||||
if method.Address().String() == addr.String() {
|
||||
addressExists = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
if !addressExists {
|
||||
if err = n.Conn.AddrAdd(method.Link(), method.Address()); err != nil {
|
||||
switch err := err.(type) {
|
||||
case *netlink.OpError:
|
||||
// ignore the error if it's -EEXIST or -ESRCH
|
||||
if !os.IsExist(err.Err) && err.Err != syscall.ESRCH {
|
||||
log.Printf("failed to add address %+v to %s: %v", method.Address(), method.Link().Name, err)
|
||||
return err
|
||||
}
|
||||
default:
|
||||
log.Printf("failed to add address (already exists) %+v to %s: %v", method.Address(), method.Link().Name, err)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Add any routes
|
||||
for _, r := range method.Routes() {
|
||||
if err = n.Conn.RouteAddSrc(method.Link(), *r.Dest, method.Address(), r.Router); err != nil {
|
||||
switch err := err.(type) {
|
||||
case *netlink.OpError:
|
||||
// ignore the error if it's -EEXIST or -ESRCH
|
||||
if !os.IsExist(err.Err) && err.Err != syscall.ESRCH {
|
||||
log.Printf("failed to add route %+v for %s: %v", r, method.Link().Name, err)
|
||||
continue
|
||||
}
|
||||
default:
|
||||
log.Printf("failed to add route (already exists) %+v for %s: %v", r, method.Link().Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Hostname returns the first hostname found from the addressing methods.
|
||||
@ -197,10 +228,10 @@ func (n *Networkd) Hostname(ifaces ...*nic.NetworkInterface) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
/*
|
||||
// TODO add this in with some debug level of loggin
|
||||
func (n *Networkd) printState() {
|
||||
rl, err := n.Conn.Route.List()
|
||||
// PrintState displays the current links, addresses, and routing table.
|
||||
// nolint: gocyclo
|
||||
func (n *Networkd) PrintState() {
|
||||
rl, err := n.nlConn.Route.List()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
@ -209,21 +240,30 @@ func (n *Networkd) printState() {
|
||||
log.Printf("%+v", r)
|
||||
}
|
||||
|
||||
links, err := n.Conn.Link.List()
|
||||
links, err := n.Conn.Links()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
for _, link := range links {
|
||||
log.Printf("%+v", link)
|
||||
log.Printf("%+v", link.Attributes)
|
||||
for _, fam := range []int{unix.AF_INET, unix.AF_INET6} {
|
||||
var addrs []*net.IPNet
|
||||
addrs, err = n.Conn.Addrs(link, fam)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
for _, addr := range addrs {
|
||||
log.Printf("%+v", addr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
b, err := ioutil.ReadFile("/etc/resolv.conf")
|
||||
var b []byte
|
||||
b, err = ioutil.ReadFile("/etc/resolv.conf")
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
log.Printf("resolv.conf: %s", string(b))
|
||||
}
|
||||
*/
|
||||
|
@ -6,6 +6,7 @@ package nic
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/talos-systems/talos/internal/app/networkd/pkg/address"
|
||||
@ -35,7 +36,7 @@ type NetworkInterface struct {
|
||||
|
||||
// Create returns a NetworkInterface with all of the given setter options
|
||||
// applied
|
||||
func Create(setters ...Option) (*NetworkInterface, error) {
|
||||
func Create(link *net.Interface, setters ...Option) (*NetworkInterface, error) {
|
||||
|
||||
// Default interface setup
|
||||
iface := defaultOptions()
|
||||
@ -56,7 +57,7 @@ func Create(setters ...Option) (*NetworkInterface, error) {
|
||||
// TODO: do we want this behavior or to be explicit with userdata
|
||||
// so we dont configure every interface be default?
|
||||
if len(iface.AddressMethod) == 0 {
|
||||
iface.AddressMethod = append(iface.AddressMethod, &address.DHCP{})
|
||||
iface.AddressMethod = append(iface.AddressMethod, &address.DHCP{NetIf: link})
|
||||
}
|
||||
|
||||
return iface, result.ErrorOrNil()
|
||||
|
Loading…
x
Reference in New Issue
Block a user