func getDynamicIP(t Netlink, link netlink.Link, dc client.Client) (*dhcp.Packet, error) { var ack *dhcp.Packet var err error // use dhcp to acquire address id, err := client.NewID(link.Attrs().Index, link.Attrs().HardwareAddr) if err != nil { return nil, err } ack, err = dc.Request(id) if err != nil { log.Errorf("error sending dhcp request: %s", err) return nil, err } if ack.YourIP() == nil || ack.SubnetMask() == nil { err = fmt.Errorf("dhcp assigned nil ip or subnet mask") log.Error(err) return nil, err } log.Infof("DHCP response: IP=%s, SubnetMask=%s, Gateway=%s, DNS=%s, Lease Time=%s", ack.YourIP(), ack.SubnetMask(), ack.Gateway(), ack.DNS(), ack.LeaseTime()) defer func() { if err != nil && ack != nil { dc.Release(ack) } }() return ack, nil }
func apply(nl Netlink, t *BaseOperations, endpoint *NetworkEndpoint) error { // Locate interface slot, err := strconv.Atoi(endpoint.ID) if err != nil { detail := fmt.Sprintf("endpoint ID must be a base10 numeric pci slot identifier: %s", err) return errors.New(detail) } link, err := nl.LinkBySlot(int32(slot)) if err != nil { detail := fmt.Sprintf("unable to acquire reference to link %s: %s", endpoint.ID, err) return errors.New(detail) } // rename the link if needed link, err = renameLink(nl, link, int32(slot), endpoint) if err != nil { detail := fmt.Sprintf("unable to reacquire link %s after rename pass: %s", endpoint.ID, err) return errors.New(detail) } var ack *dhcp.Packet defer func() { if err != nil && ack != nil { t.dhcpClient.Release(ack) } }() var newIP *net.IPNet if endpoint.IsDynamic() && endpoint.DHCP == nil { if e, ok := t.dynEndpoints[endpoint.ID]; ok { // endpoint shares NIC, copy over DHCP endpoint.DHCP = e[0].DHCP } } log.Debugf("%+v", endpoint) if endpoint.IsDynamic() { if endpoint.DHCP == nil { ack, err = getDynamicIP(nl, link, t.dhcpClient) if err != nil { return err } endpoint.DHCP = &DHCPInfo{ Assigned: net.IPNet{IP: ack.YourIP(), Mask: ack.SubnetMask()}, Nameservers: ack.DNS(), Gateway: net.IPNet{IP: ack.Gateway(), Mask: ack.SubnetMask()}, } } newIP = &endpoint.DHCP.Assigned } else { newIP = endpoint.Static if newIP.IP.IsUnspecified() { // managed externally return nil } } var old *net.IPNet if !ip.IsUnspecifiedIP(endpoint.Assigned.IP) { old = &endpoint.Assigned } if err = linkAddrUpdate(old, newIP, nl, link); err != nil { return err } updateEndpoint(newIP, endpoint) if err = updateDefaultRoute(nl, link, endpoint); err != nil { return err } if err = t.updateHosts(endpoint); err != nil { return err } t.resolvConf.RemoveNameservers(endpoint.Network.Nameservers...) if err = t.updateNameservers(endpoint); err != nil { return err } if endpoint.IsDynamic() { eps := t.dynEndpoints[endpoint.ID] found := false for _, e := range eps { if e == endpoint { found = true break } } if !found { eps = append(eps, endpoint) t.dynEndpoints[endpoint.ID] = eps } } // add renew/release loop if necessary if ack != nil { if _, ok := t.dhcpLoops[endpoint.ID]; !ok { stop := make(chan bool) id, err := client.NewID(link.Attrs().Index, link.Attrs().HardwareAddr) if err != nil { log.Errorf("could not make DHCP client id for link %s: %s", link.Attrs().Name, err) } else { go t.dhcpLoop(stop, endpoint, ack, id) t.dhcpLoops[endpoint.ID] = stop } } } return nil }