diff options
Diffstat (limited to 'netboot/netconf.go')
-rw-r--r-- | netboot/netconf.go | 77 |
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) } } |