summaryrefslogtreecommitdiffhomepage
path: root/netboot/netconf.go
diff options
context:
space:
mode:
Diffstat (limited to 'netboot/netconf.go')
-rw-r--r--netboot/netconf.go77
1 files changed, 42 insertions, 35 deletions
diff --git a/netboot/netconf.go b/netboot/netconf.go
index 0f40e26..2e11d38 100644
--- a/netboot/netconf.go
+++ b/netboot/netconf.go
@@ -7,11 +7,13 @@ import (
"net"
"os"
"strings"
+ "syscall"
"time"
"github.com/insomniacslk/dhcp/dhcpv4"
"github.com/insomniacslk/dhcp/dhcpv6"
- "github.com/vishvananda/netlink"
+ "github.com/jsimonetti/rtnetlink"
+ "github.com/mdlayher/netlink"
)
// AddrConf holds a single IP address configuration for a NIC
@@ -136,31 +138,36 @@ func GetNetConfFromPacketv4(d *dhcpv4.DHCPv4) (*NetConf, error) {
}
// IfUp brings up an interface by name, and waits for it to come up until a timeout expires
-func IfUp(ifname string, timeout time.Duration) (netlink.Link, error) {
+func IfUp(ifname string, timeout time.Duration) (*net.Interface, error) {
start := time.Now()
+ var rt RTNL
+ defer rt.Close()
for time.Since(start) < timeout {
- iface, err := netlink.LinkByName(ifname)
+ iface, err := net.InterfaceByName(ifname)
if err != nil {
- return nil, fmt.Errorf("cannot get interface %q by name: %v", ifname, err)
+ return nil, err
}
-
// If the interface is up, return. According to kernel documentation OperState may
// be either Up or Unknown:
// Interface is in RFC2863 operational state UP or UNKNOWN. This is for
// backward compatibility, routing daemons, dhcp clients can use this
// flag to determine whether they should use the interface.
// Source: https://www.kernel.org/doc/Documentation/networking/operstates.txt
- operState := iface.Attrs().OperState
- if operState == netlink.OperUp || operState == netlink.OperUnknown {
+ operState, err := rt.GetLinkState(iface.Index)
+ if err != nil {
+ return nil, err
+ }
+ if operState == rtnetlink.OperStateUp || operState == rtnetlink.OperStateUnknown {
// XXX despite the OperUp state, upon the first attempt I
- // consistently get a "cannot assign requested address" error. This
- // may be a bug in the netlink library. Need to investigate more.
+ // consistently get a "cannot assign requested address" error. Need
+ // to investigate more.
time.Sleep(time.Second)
return iface, nil
}
// otherwise try to bring it up
- if err := netlink.LinkSetUp(iface); err != nil {
- return nil, fmt.Errorf("interface %q: %v can't make it up: %v", ifname, iface, err)
+ err = rt.SetLinkState(iface.Index, true)
+ if err != nil {
+ return nil, fmt.Errorf("interface %q: %v can't bring it up: %v", ifname, iface, err)
}
time.Sleep(10 * time.Millisecond)
}
@@ -172,21 +179,16 @@ func IfUp(ifname string, timeout time.Duration) (netlink.Link, error) {
// ConfigureInterface configures a network interface with the configuration held by a
// NetConf structure
func ConfigureInterface(ifname string, netconf *NetConf) error {
- iface, err := netlink.LinkByName(ifname)
+ iface, err := net.InterfaceByName(ifname)
if err != nil {
- return fmt.Errorf("error getting interface information for %s: %v", ifname, err)
+ return err
}
+ var rt RTNL
+ defer rt.Close()
// configure interfaces
for _, addr := range netconf.Addresses {
- dest := &netlink.Addr{
- IPNet: &addr.IPNet,
- PreferedLft: addr.PreferredLifetime,
- ValidLft: addr.ValidLifetime,
- }
- if err := netlink.AddrReplace(iface, dest); err != nil {
- if os.IsExist(err) {
- return fmt.Errorf("cannot configure %s on %s,%d,%d: %v", ifname, addr.IPNet, addr.PreferredLifetime, addr.ValidLifetime, err)
- }
+ if err := rt.SetAddr(iface.Index, addr.IPNet); err != nil {
+ return fmt.Errorf("cannot configure %s on %s: %v", ifname, addr.IPNet, err)
}
}
// configure /etc/resolv.conf
@@ -201,32 +203,37 @@ func ConfigureInterface(ifname string, netconf *NetConf) error {
return fmt.Errorf("could not write resolv.conf file %v", err)
}
+ // FIXME wut? No IPv6 here?
// add default route information for v4 space. only one default route is allowed
// so ignore the others if there are multiple ones
if len(netconf.Routers) > 0 {
- iface, err = netlink.LinkByName(ifname)
- if err != nil {
- return fmt.Errorf("could not obtain interface when adding default route: %v", err)
- }
// if there is a default v4 route, remove it, as we want to add the one we just got during
// the dhcp transaction. if the route is not present, which is the final state we want,
// an error is returned so ignore it
- dst := &net.IPNet{
- IP: net.IPv4(0, 0, 0, 0),
+ dst := net.IPNet{
+ IP: net.IPv4zero,
Mask: net.CIDRMask(0, 32),
}
// Remove a possible default route (dst 0.0.0.0) to the L2 domain (gw: 0.0.0.0), which is what
// a client would want to add before initiating the DHCP transaction in order not to fail with
// ENETUNREACH. If this default route has a specific metric assigned, it doesn't get removed.
// The code doesn't remove any other default route (i.e. gw != 0.0.0.0).
- route := netlink.Route{LinkIndex: iface.Attrs().Index, Dst: dst, Src: net.IPv4(0, 0, 0, 0)}
- netlink.RouteDel(&route)
+ if err := rt.RouteDel(net.IPv4zero); 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 {
+ return fmt.Errorf("could not delete default route on interface %s: %v", ifname, err)
+ }
+ default:
+ return fmt.Errorf("could not delete default route on interface %s: %v", ifname, err)
+ }
+ }
- src := netconf.Addresses[0].IPNet.IP
- route = netlink.Route{LinkIndex: iface.Attrs().Index, Dst: dst, Src: src, Gw: netconf.Routers[0]}
- err = netlink.RouteAdd(&route)
- if err != nil {
- return fmt.Errorf("could not add default route (%+v) to interface %s: %v", route, iface.Attrs().Name, err)
+ src := netconf.Addresses[0].IPNet
+ // TODO handle the remaining Routers if more than one
+ if err := rt.RouteAdd(iface.Index, dst, src, netconf.Routers[0]); err != nil {
+ return fmt.Errorf("could not add gateway %s for src %s dst %s to interface %s: %v", netconf.Routers[0], src, dst, ifname, err)
}
}