func configureIface(ifname string, ipn ip.IP4Net, mtu int) error { iface, err := netlink.LinkByName(ifname) if err != nil { return fmt.Errorf("failed to lookup interface %v", ifname) } err = netlink.AddrAdd(iface, &netlink.Addr{IPNet: ipn.ToIPNet(), Label: ""}) if err != nil { return fmt.Errorf("failed to add IP address %v to %v: %v", ipn.String(), ifname, err) } err = netlink.LinkSetMTU(iface, mtu) if err != nil { return fmt.Errorf("failed to set MTU for %v: %v", ifname, err) } err = netlink.LinkSetUp(iface) if err != nil { return fmt.Errorf("failed to set interface %v to UP state: %v", ifname, err) } // explicitly add a route since there might be a route for a subnet already // installed by Docker and then it won't get auto added err = netlink.RouteAdd(&netlink.Route{ LinkIndex: iface.Attrs().Index, Scope: netlink.SCOPE_UNIVERSE, Dst: ipn.Network().ToIPNet(), }) if err != nil && err != syscall.EEXIST { return fmt.Errorf("failed to add route (%v -> %v): %v", ipn.Network().String(), ifname, err) } return nil }
// Set the link mtu func setLinkMtu(name string, mtu int) error { iface, err := netlink.LinkByName(name) if err != nil { return err } return netlink.LinkSetMTU(iface, mtu) }
func applyNetConf(link netlink.Link, netConf config.InterfaceConfig) error { if netConf.DHCP { log.Infof("Running DHCP on %s", link.Attrs().Name) cmd := exec.Command("dhcpcd", "-A4", "-e", "force_hostname=true", link.Attrs().Name) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { log.Error(err) } } else if netConf.IPV4LL { if err := AssignLinkLocalIP(link); err != nil { log.Error("IPV4LL set failed") return err } } else if netConf.Address == "" { return nil } else { addr, err := netlink.ParseAddr(netConf.Address) if err != nil { return err } if err := netlink.AddrAdd(link, addr); err != nil { log.Error("addr add failed") return err } log.Infof("Set %s on %s", netConf.Address, link.Attrs().Name) } if netConf.MTU > 0 { if err := netlink.LinkSetMTU(link, netConf.MTU); err != nil { log.Error("set MTU Failed") return err } } if err := netlink.LinkSetUp(link); err != nil { log.Error("failed to setup link") return err } if netConf.Gateway != "" { gatewayIp := net.ParseIP(netConf.Gateway) if gatewayIp == nil { return errors.New("Invalid gateway address " + netConf.Gateway) } route := netlink.Route{ Scope: netlink.SCOPE_UNIVERSE, Gw: net.ParseIP(netConf.Gateway), } if err := netlink.RouteAdd(&route); err != nil { log.Error("gateway set failed") return err } log.Infof("Set default gateway %s", netConf.Gateway) } return nil }
// attach a container network interface to an external network func (v *veth) attach(n *configs.Network) (err error) { brl, err := netlink.LinkByName(n.Bridge) if err != nil { return err } br, ok := brl.(*netlink.Bridge) if !ok { return fmt.Errorf("Wrong device type %T", brl) } host, err := netlink.LinkByName(n.HostInterfaceName) if err != nil { return err } if err := netlink.LinkSetMaster(host, br); err != nil { return err } if err := netlink.LinkSetMTU(host, n.Mtu); err != nil { return err } if n.HairpinMode { if err := netlink.LinkSetHairpin(host, true); err != nil { return err } } if err := netlink.LinkSetUp(host); err != nil { return err } return nil }
func (driver *driver) joinEndpoint(w http.ResponseWriter, r *http.Request) { var j join if err := json.NewDecoder(r.Body).Decode(&j); err != nil { sendError(w, "Could not decode JSON encode payload", http.StatusBadRequest) return } log.Debugf("Join request: %+v", &j) endID := j.EndpointID // unique name while still on the common netns preMoveName := endID[:5] mode, err := setVlanMode(macvlanMode) if err != nil { log.Errorf("error parsing vlan mode [ %v ]: %s", mode, err) return } // Get the link for the master index (Example: the docker host eth iface) hostEth, err := netlink.LinkByName(macvlanEthIface) if err != nil { log.Warnf("Error looking up the parent iface [ %s ] mode: [ %s ] error: [ %s ]", macvlanEthIface, mode, err) } macvlan := &netlink.Macvlan{ LinkAttrs: netlink.LinkAttrs{ Name: preMoveName, ParentIndex: hostEth.Attrs().Index, }, Mode: mode, } if err := netlink.LinkAdd(macvlan); err != nil { log.Errorf("failed to create Macvlan: [ %v ] with the error: %s", macvlan, err) log.Error("Ensure there are no existing [ ipvlan ] type links and remove with 'ip link del <link_name>'," + " also check `/var/run/docker/netns/` for orphaned links to unmount and delete, then restart the plugin") return } log.Infof("Created Macvlan port: [ %s ] using the mode: [ %s ]", macvlan.Name, macvlanMode) // Set the netlink iface MTU, default is 1500 if err := netlink.LinkSetMTU(macvlan, defaultMTU); err != nil { log.Errorf("Error setting the MTU [ %d ] for link [ %s ]: %s", defaultMTU, macvlan.Name, err) } // Bring the netlink iface up if err := netlink.LinkSetUp(macvlan); err != nil { log.Warnf("failed to enable the [ macvlan ] netlink link: [ %v ]", macvlan, err) } // SrcName gets renamed to DstPrefix on the container iface ifname := &InterfaceName{ SrcName: macvlan.Name, DstPrefix: containerIfacePrefix, } res := &joinResponse{ InterfaceName: *ifname, Gateway: gatewayIP, } objectResponse(w, res) log.Debugf("Join endpoint %s:%s to %s", j.NetworkID, j.EndpointID, j.SandboxKey) }
func (Link) SetMTU(intf *net.Interface, mtu int) error { netlinkMu.Lock() defer netlinkMu.Unlock() link, err := netlink.LinkByName(intf.Name) if err != nil { return errF(err) } return errF(netlink.LinkSetMTU(link, mtu)) }
func (driver *driver) JoinEndpoint(j *netApi.JoinRequest) (*netApi.JoinResponse, error) { log.Debugf("Join endpoint request: %+v", j) log.Debugf("Joining endpoint %s:%s to %s", j.NetworkID, j.EndpointID, j.SandboxKey) tempName := j.EndpointID[:4] hostName := "vethr" + j.EndpointID[:4] veth := &netlink.Veth{ LinkAttrs: netlink.LinkAttrs{ Name: hostName, TxQLen: 0, }, PeerName: tempName, } log.Debugf("Adding link %+v", veth) if err := netlink.LinkAdd(veth); err != nil { log.Errorf("Unable to add link %+v:%+v", veth, err) return nil, err } if err := netlink.LinkSetMTU(veth, 1500); err != nil { log.Errorf("Error setting the MTU %s", err) } log.Debugf("Bringing link up %+v", veth) if err := netlink.LinkSetUp(veth); err != nil { log.Errorf("Unable to bring up %+v: %+v", veth, err) return nil, err } ep := driver.network.endpoints[j.EndpointID] ep.iface = hostName iface, _ := netlink.LinkByName(hostName) routeAdd(ep.ipv4Address, iface) for _, ipa := range ep.ipAliases { routeAdd(ipa, iface) } respIface := &netApi.InterfaceName{ SrcName: tempName, DstPrefix: "eth", } sandboxRoute := netApi.StaticRoute{ Destination: "0.0.0.0/0", RouteType: 1, // CONNECTED NextHop: "", } resp := &netApi.JoinResponse{ InterfaceName: respIface, DisableGatewayService: true, StaticRoutes: []netApi.StaticRoute{sandboxRoute}, } log.Infof("Join Request Response %+v", resp) return resp, nil }
func applyNetConf(link netlink.Link, netConf InterfaceConfig) error { if netConf.IPV4LL { if err := AssignLinkLocalIP(link); err != nil { log.Errorf("IPV4LL set failed: %v", err) return err } } else if netConf.Address == "" { return nil } else { addr, err := netlink.ParseAddr(netConf.Address) if err != nil { return err } if err := netlink.AddrAdd(link, addr); err != nil { //Ignore this error log.Errorf("addr add failed: %v", err) } else { log.Infof("Set %s on %s", netConf.Address, link.Attrs().Name) } } if netConf.MTU > 0 { if err := netlink.LinkSetMTU(link, netConf.MTU); err != nil { log.Errorf("set MTU Failed: %v", err) return err } } if err := netlink.LinkSetUp(link); err != nil { log.Errorf("failed to setup link: %v", err) return err } if netConf.Gateway != "" { gatewayIp := net.ParseIP(netConf.Gateway) if gatewayIp == nil { return errors.New("Invalid gateway address " + netConf.Gateway) } route := netlink.Route{ Scope: netlink.SCOPE_UNIVERSE, Gw: net.ParseIP(netConf.Gateway), } if err := netlink.RouteAdd(&route); err != nil { log.Errorf("gateway set failed: %v", err) return err } log.Infof("Set default gateway %s", netConf.Gateway) } return nil }
// SetupVeth sets up the net interface, the temporary interface and fills up some endpoint // fields such as LXCMAC, NodeMac, IfIndex and IfName. Returns a pointer for the created // veth, a pointer for the temporary link, the name of the temporary link and error if // something fails. func SetupVeth(id string, mtu int, ep *endpoint.Endpoint) (*netlink.Veth, *netlink.Link, string, error) { lxcIfName := Endpoint2IfName(id) tmpIfName := temporaryInterfacePrefix + id[:5] veth := &netlink.Veth{ LinkAttrs: netlink.LinkAttrs{Name: lxcIfName}, PeerName: tmpIfName, } if err := netlink.LinkAdd(veth); err != nil { return nil, nil, "", fmt.Errorf("unable to create veth pair: %s", err) } var err error defer func() { if err != nil { if err = netlink.LinkDel(veth); err != nil { log.Warningf("failed to clean up veth %q: %s", veth.Name, err) } } }() log.Debugf("Created veth pair %s <-> %s", lxcIfName, veth.PeerName) // Disable reverse path filter on the host side veth peer to allow // container addresses to be used as source address when the linux // stack performs routing. args := []string{"-w", "net.ipv4.conf." + lxcIfName + ".rp_filter=0"} _, err = exec.Command("sysctl", args...).CombinedOutput() if err != nil { return nil, nil, "", fmt.Errorf("unable to disable rp_filter on %s: %s", lxcIfName, err) } peer, err := netlink.LinkByName(tmpIfName) if err != nil { return nil, nil, "", fmt.Errorf("unable to lookup veth peer just created: %s", err) } if err = netlink.LinkSetMTU(peer, mtu); err != nil { return nil, nil, "", fmt.Errorf("unable to set MTU to %q: %s", tmpIfName, err) } hostVeth, err := netlink.LinkByName(lxcIfName) if err != nil { return nil, nil, "", fmt.Errorf("unable to lookup veth just created: %s", err) } if err = netlink.LinkSetMTU(hostVeth, mtu); err != nil { return nil, nil, "", fmt.Errorf("unable to set MTU to %q: %s", lxcIfName, err) } if err = netlink.LinkSetUp(veth); err != nil { return nil, nil, "", fmt.Errorf("unable to bring up veth pair: %s", err) } ep.LXCMAC = mac.MAC(peer.Attrs().HardwareAddr) ep.NodeMAC = mac.MAC(hostVeth.Attrs().HardwareAddr) ep.IfIndex = hostVeth.Attrs().Index ep.IfName = lxcIfName return veth, &peer, tmpIfName, nil }
// Join creates a MACVLAN interface to be moved to the container netns func (d *Driver) Join(r *sdk.JoinRequest) (*sdk.JoinResponse, error) { log.Debugf("Join request: %+v", &r) getID, err := d.getNetwork(r.NetworkID) if err != nil { // Init any existing libnetwork networks d.existingNetChecks() getID, err = d.getNetwork(r.NetworkID) if err != nil { return nil, fmt.Errorf("error getting network ID [ %s ]. Run 'docker network ls' or 'docker network create' Err: %v", r.NetworkID, err) } } endID := r.EndpointID // unique name while still on the common netns preMoveName := endID[:5] mode, err := setVlanMode("bridge") if err != nil { return nil, fmt.Errorf("error getting vlan mode [ %v ]: %s", mode, err) } if getID.ifaceOpt == "" { return nil, fmt.Errorf("Required macvlan parent interface is missing, please recreate the network specifying the -o host_iface=ethX") } // Get the link for the master index (Example: the docker host eth iface) hostEth, err := netlink.LinkByName(getID.ifaceOpt) if err != nil { log.Warnf("Error looking up the parent iface [ %s ] error: [ %s ]", getID.ifaceOpt, err) } mvlan := &netlink.Macvlan{ LinkAttrs: netlink.LinkAttrs{ Name: preMoveName, ParentIndex: hostEth.Attrs().Index, }, Mode: mode, } if err := netlink.LinkAdd(mvlan); err != nil { log.Warnf("Failed to create the netlink link: [ %v ] with the "+ "error: %s Note: a parent index cannot be link to both macvlan "+ "and macvlan simultaneously. A new parent index is required", mvlan, err) log.Warnf("Also check `/var/run/docker/netns/` for orphaned links to unmount and delete, then restart the plugin") log.Warnf("Run this to clean orphaned links 'umount /var/run/docker/netns/* && rm /var/run/docker/netns/*'") } // Set the netlink iface MTU, default is 1500 if err := netlink.LinkSetMTU(mvlan, defaultMTU); err != nil { log.Errorf("Error setting the MTU [ %d ] for link [ %s ]: %s", defaultMTU, mvlan.Name, err) } // Bring the netlink iface up if err := netlink.LinkSetUp(mvlan); err != nil { log.Warnf("failed to enable the macvlan netlink link: [ %v ]", mvlan, err) } // SrcName gets renamed to DstPrefix on the container iface ifname := &sdk.InterfaceName{ SrcName: mvlan.Name, DstPrefix: containerIfacePrefix, } res := &sdk.JoinResponse{ InterfaceName: *ifname, Gateway: getID.gateway, DisableGatewayService: true, } log.Debugf("Join response: %+v", res) log.Debugf("Join endpoint %s:%s to %s", r.NetworkID, r.EndpointID, r.SandboxKey) return res, nil }
// Join method is invoked when a Sandbox is attached to an endpoint. func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error { if err := validateID(nid, eid); err != nil { return err } n := d.network(nid) if n == nil { return fmt.Errorf("could not find network with id %s", nid) } ep := n.endpoint(eid) if ep == nil { return fmt.Errorf("could not find endpoint with id %s", eid) } s := n.getSubnetforIP(ep.addr) if s == nil { return fmt.Errorf("could not find subnet for endpoint %s", eid) } if err := n.obtainVxlanID(s); err != nil { return fmt.Errorf("couldn't get vxlan id for %q: %v", s.subnetIP.String(), err) } if err := n.joinSandbox(); err != nil { return fmt.Errorf("network sandbox join failed: %v", err) } if err := n.joinSubnetSandbox(s); err != nil { return fmt.Errorf("subnet sandbox join failed for %q: %v", s.subnetIP.String(), err) } // joinSubnetSandbox gets called when an endpoint comes up on a new subnet in the // overlay network. Hence the Endpoint count should be updated outside joinSubnetSandbox n.incEndpointCount() sbox := n.sandbox() name1, name2, err := createVethPair() if err != nil { return err } // Set the container interface and its peer MTU to 1450 to allow // for 50 bytes vxlan encap (inner eth header(14) + outer IP(20) + // outer UDP(8) + vxlan header(8)) veth, err := netlink.LinkByName(name1) if err != nil { return fmt.Errorf("cound not find link by name %s: %v", name1, err) } err = netlink.LinkSetMTU(veth, vxlanVethMTU) if err != nil { return err } if err := sbox.AddInterface(name1, "veth", sbox.InterfaceOptions().Master(s.brName)); err != nil { return fmt.Errorf("could not add veth pair inside the network sandbox: %v", err) } veth, err = netlink.LinkByName(name2) if err != nil { return fmt.Errorf("could not find link by name %s: %v", name2, err) } err = netlink.LinkSetMTU(veth, vxlanVethMTU) if err != nil { return err } if err := netlink.LinkSetHardwareAddr(veth, ep.mac); err != nil { return fmt.Errorf("could not set mac address (%v) to the container interface: %v", ep.mac, err) } for _, sub := range n.subnets { if sub == s { continue } if err := jinfo.AddStaticRoute(sub.subnetIP, types.NEXTHOP, s.gwIP.IP); err != nil { log.Errorf("Adding subnet %s static route in network %q failed\n", s.subnetIP, n.id) } } if iNames := jinfo.InterfaceName(); iNames != nil { err = iNames.SetNames(name2, "eth") if err != nil { return err } } d.peerDbAdd(nid, eid, ep.addr.IP, ep.addr.Mask, ep.mac, net.ParseIP(d.bindAddress), true) d.pushLocalEndpointEvent("join", nid, eid) return nil }
func (driver *driver) joinEndpoint(w http.ResponseWriter, r *http.Request) { var j join if err := json.NewDecoder(r.Body).Decode(&j); err != nil { sendError(w, "Could not decode JSON encode payload", http.StatusBadRequest) return } log.Debugf("Join request: %+v", &j) endID := j.EndpointID // unique name while still on the common netns preMoveName := endID[:5] mode, err := getIPVlanMode(ipVlanMode) if err != nil { log.Errorf("error getting vlan mode [ %v ]: %s", mode, err) return } // Get the link for the master index (Example: the docker host eth iface) hostEth, err := netlink.LinkByName(ipVlanEthIface) if err != nil { log.Warnf("Error looking up the parent iface [ %s ] error: [ %s ]", ipVlanEthIface, err) } ipvlan := &netlink.IPVlan{ LinkAttrs: netlink.LinkAttrs{ Name: preMoveName, ParentIndex: hostEth.Attrs().Index, TxQLen: TxQueueLen, }, Mode: mode, } if err := netlink.LinkAdd(ipvlan); err != nil { log.Warnf("Failed to create the netlink link: [ %v ] with the "+ "error: %s Note: a parent index cannot be link to both ipvlan "+ "and ipvlan simultaneously. A new parent index is required", ipvlan, err) log.Warnf("Also check `/var/run/docker/netns/` for orphaned links to unmount and delete, then restart the plugin") log.Warnf("Run this to clean orphaned links 'umount /var/run/docker/netns/* && rm /var/run/docker/netns/*'") } log.Infof("Created ipvlan link: [ %s ] with a mode: [ %s ]", ipvlan.Name, ipVlanMode) // Set the netlink iface MTU, default is 1500 if err := netlink.LinkSetMTU(ipvlan, defaultMTU); err != nil { log.Errorf("Error setting the MTU [ %d ] for link [ %s ]: %s", defaultMTU, ipvlan.Name, err) } // Bring the netlink iface up if err := netlink.LinkSetUp(ipvlan); err != nil { log.Warnf("failed to enable the ipvlan netlink link: [ %v ]", ipvlan, err) } // SrcName gets renamed to DstPrefix on the container iface ifname := &InterfaceName{ SrcName: ipvlan.Name, DstPrefix: containerEthPrefix, } res := &joinResponse{} // L2 ipvlan needs an explicit IP for a default GW in the container netns if ipVlanMode == ipVlanL2 { res = &joinResponse{ InterfaceName: *ifname, Gateway: driver.pluginConfig.gatewayIP.String(), } defer objectResponse(w, res) } // ipvlan L3 mode doesnt need an IP for a default GW, just an iface dex. if ipVlanMode == ipVlanL3 || ipVlanMode == ipVlanL3Routing { res = &joinResponse{ InterfaceName: *ifname, } // Add a default route of only the interface inside the container defaultRoute := &staticRoute{ Destination: defaultRoute, RouteType: types.CONNECTED, NextHop: "", } res.StaticRoutes = []*staticRoute{defaultRoute} } log.Debugf("Join response: %+v", res) // Send the response to libnetwork objectResponse(w, res) log.Debugf("Join endpoint %s:%s to %s", j.NetworkID, j.EndpointID, j.SandboxKey) }
func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error { defer osl.InitOSContext()() if ifInfo == nil { return errors.New("invalid interface info passed") } // Get the network handler and make sure it exists d.Lock() n, ok := d.networks[nid] dconfig := d.config d.Unlock() if !ok { return types.NotFoundErrorf("network %s does not exist", nid) } if n == nil { return driverapi.ErrNoNetwork(nid) } // Sanity check n.Lock() if n.id != nid { n.Unlock() return InvalidNetworkIDError(nid) } n.Unlock() // Check if endpoint id is good and retrieve correspondent endpoint ep, err := n.getEndpoint(eid) if err != nil { return err } // Endpoint with that id exists either on desired or other sandbox if ep != nil { return driverapi.ErrEndpointExists(eid) } // Try to convert the options to endpoint configuration epConfig, err := parseEndpointOptions(epOptions) if err != nil { return err } // Create and add the endpoint n.Lock() endpoint := &bridgeEndpoint{id: eid, config: epConfig} n.endpoints[eid] = endpoint n.Unlock() // On failure make sure to remove the endpoint defer func() { if err != nil { n.Lock() delete(n.endpoints, eid) n.Unlock() } }() // Generate a name for what will be the host side pipe interface hostIfName, err := netutils.GenerateIfaceName(vethPrefix, vethLen) if err != nil { return err } // Generate a name for what will be the sandbox side pipe interface containerIfName, err := netutils.GenerateIfaceName(vethPrefix, vethLen) if err != nil { return err } // Generate and add the interface pipe host <-> sandbox veth := &netlink.Veth{ LinkAttrs: netlink.LinkAttrs{Name: hostIfName, TxQLen: 0}, PeerName: containerIfName} if err = netlink.LinkAdd(veth); err != nil { return types.InternalErrorf("failed to add the host (%s) <=> sandbox (%s) pair interfaces: %v", hostIfName, containerIfName, err) } // Get the host side pipe interface handler host, err := netlink.LinkByName(hostIfName) if err != nil { return types.InternalErrorf("failed to find host side interface %s: %v", hostIfName, err) } defer func() { if err != nil { netlink.LinkDel(host) } }() // Get the sandbox side pipe interface handler sbox, err := netlink.LinkByName(containerIfName) if err != nil { return types.InternalErrorf("failed to find sandbox side interface %s: %v", containerIfName, err) } defer func() { if err != nil { netlink.LinkDel(sbox) } }() n.Lock() config := n.config n.Unlock() // Add bridge inherited attributes to pipe interfaces if config.Mtu != 0 { err = netlink.LinkSetMTU(host, config.Mtu) if err != nil { return types.InternalErrorf("failed to set MTU on host interface %s: %v", hostIfName, err) } err = netlink.LinkSetMTU(sbox, config.Mtu) if err != nil { return types.InternalErrorf("failed to set MTU on sandbox interface %s: %v", containerIfName, err) } } // Attach host side pipe interface into the bridge if err = addToBridge(hostIfName, config.BridgeName); err != nil { return fmt.Errorf("adding interface %s to bridge %s failed: %v", hostIfName, config.BridgeName, err) } if !dconfig.EnableUserlandProxy { err = setHairpinMode(host, true) if err != nil { return err } } // Store the sandbox side pipe interface parameters endpoint.srcName = containerIfName endpoint.macAddress = ifInfo.MacAddress() endpoint.addr = ifInfo.Address() endpoint.addrv6 = ifInfo.AddressIPv6() // Set the sbox's MAC if not provided. If specified, use the one configured by user, otherwise generate one based on IP. if endpoint.macAddress == nil { endpoint.macAddress = electMacAddress(epConfig, endpoint.addr.IP) if err = ifInfo.SetMacAddress(endpoint.macAddress); err != nil { return err } } // Up the host interface after finishing all netlink configuration if err = netlink.LinkSetUp(host); err != nil { return fmt.Errorf("could not set link up for host interface %s: %v", hostIfName, err) } if endpoint.addrv6 == nil && config.EnableIPv6 { var ip6 net.IP network := n.bridge.bridgeIPv6 if config.AddressIPv6 != nil { network = config.AddressIPv6 } ones, _ := network.Mask.Size() if ones > 80 { err = types.ForbiddenErrorf("Cannot self generate an IPv6 address on network %v: At least 48 host bits are needed.", network) return err } ip6 = make(net.IP, len(network.IP)) copy(ip6, network.IP) for i, h := range endpoint.macAddress { ip6[i+10] = h } endpoint.addrv6 = &net.IPNet{IP: ip6, Mask: network.Mask} if err = ifInfo.SetIPAddress(endpoint.addrv6); err != nil { return err } } return nil }
func (driver *driver) joinEndpoint(w http.ResponseWriter, r *http.Request) { var j join if err := json.NewDecoder(r.Body).Decode(&j); err != nil { sendError(w, "Could not decode JSON encode payload", http.StatusBadRequest) return } log.Debugf("Join request: %+v", &j) getID, err := driver.getNetwork(j.NetworkID) if err != nil { log.Errorf("error getting network ID mode [ %s ]: %v", j.NetworkID, err) } endID := j.EndpointID // unique name while still on the common netns preMoveName := endID[:5] res := &joinResponse{} mode, err := setVlanMode("bridge") if err != nil { log.Errorf("error getting vlan mode [ %v ]: %s", mode, err) return } if getID.ifaceOpt == "" { log.Error("Required macvlan parent interface is missing, please recreate the network specifying the host_iface") return } // Get the link for the master index (Example: the docker host eth iface) hostEth, err := netlink.LinkByName(getID.ifaceOpt) if err != nil { log.Warnf("Error looking up the parent iface [ %s ] error: [ %s ]", getID.ifaceOpt, err) } mvlan := &netlink.Macvlan{ LinkAttrs: netlink.LinkAttrs{ Name: preMoveName, ParentIndex: hostEth.Attrs().Index, }, Mode: mode, } if err := netlink.LinkAdd(mvlan); err != nil { log.Warnf("Failed to create the netlink link: [ %v ] with the "+ "error: %s Note: a parent index cannot be link to both macvlan "+ "and macvlan simultaneously. A new parent index is required", mvlan, err) log.Warnf("Also check `/var/run/docker/netns/` for orphaned links to unmount and delete, then restart the plugin") log.Warnf("Run this to clean orphaned links 'umount /var/run/docker/netns/* && rm /var/run/docker/netns/*'") } // Set the netlink iface MTU, default is 1500 if err := netlink.LinkSetMTU(mvlan, defaultMTU); err != nil { log.Errorf("Error setting the MTU [ %d ] for link [ %s ]: %s", defaultMTU, mvlan.Name, err) } // Bring the netlink iface up if err := netlink.LinkSetUp(mvlan); err != nil { log.Warnf("failed to enable the macvlan netlink link: [ %v ]", mvlan, err) } // SrcName gets renamed to DstPrefix on the container iface ifname := &InterfaceName{ SrcName: mvlan.Name, DstPrefix: containerIfacePrefix, } res = &joinResponse{ InterfaceName: *ifname, Gateway: getID.gateway, DisableGatewayService: true, } defer objectResponse(w, res) log.Debugf("Join response: %+v", res) // Send the response to libnetwork // objectResponse(w, res) log.Debugf("Join endpoint %s:%s to %s", j.NetworkID, j.EndpointID, j.SandboxKey) }
func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error { var ( ipv6Addr *net.IPNet err error ) if epInfo == nil { return errors.New("invalid endpoint info passed") } if len(epInfo.Interfaces()) != 0 { return errors.New("non empty interface list passed to bridge(local) driver") } // Get the network handler and make sure it exists d.Lock() n := d.network config := n.config d.Unlock() if n == nil { return driverapi.ErrNoNetwork(nid) } // Sanity check n.Lock() if n.id != nid { n.Unlock() return InvalidNetworkIDError(nid) } n.Unlock() // Check if endpoint id is good and retrieve correspondent endpoint ep, err := n.getEndpoint(eid) if err != nil { return err } // Endpoint with that id exists either on desired or other sandbox if ep != nil { return driverapi.ErrEndpointExists(eid) } // Try to convert the options to endpoint configuration epConfig, err := parseEndpointOptions(epOptions) if err != nil { return err } // Create and add the endpoint n.Lock() endpoint := &bridgeEndpoint{id: eid, config: epConfig} n.endpoints[eid] = endpoint n.Unlock() // On failure make sure to remove the endpoint defer func() { if err != nil { n.Lock() delete(n.endpoints, eid) n.Unlock() } }() // Generate a name for what will be the host side pipe interface name1, err := generateIfaceName() if err != nil { return err } // Generate a name for what will be the sandbox side pipe interface name2, err := generateIfaceName() if err != nil { return err } // Generate and add the interface pipe host <-> sandbox veth := &netlink.Veth{ LinkAttrs: netlink.LinkAttrs{Name: name1, TxQLen: 0}, PeerName: name2} if err = netlink.LinkAdd(veth); err != nil { return err } // Get the host side pipe interface handler host, err := netlink.LinkByName(name1) if err != nil { return err } defer func() { if err != nil { netlink.LinkDel(host) } }() // Get the sandbox side pipe interface handler sbox, err := netlink.LinkByName(name2) if err != nil { return err } defer func() { if err != nil { netlink.LinkDel(sbox) } }() // Add bridge inherited attributes to pipe interfaces if config.Mtu != 0 { err = netlink.LinkSetMTU(host, config.Mtu) if err != nil { return err } err = netlink.LinkSetMTU(sbox, config.Mtu) if err != nil { return err } } // Attach host side pipe interface into the bridge if err = netlink.LinkSetMaster(host, &netlink.Bridge{LinkAttrs: netlink.LinkAttrs{Name: config.BridgeName}}); err != nil { return err } if !config.EnableUserlandProxy { err = netlink.LinkSetHairpin(host, true) if err != nil { return err } } // v4 address for the sandbox side pipe interface ip4, err := ipAllocator.RequestIP(n.bridge.bridgeIPv4, nil) if err != nil { return err } ipv4Addr := &net.IPNet{IP: ip4, Mask: n.bridge.bridgeIPv4.Mask} // Set the sbox's MAC. If specified, use the one configured by user, otherwise generate one based on IP. mac := electMacAddress(epConfig, ip4) err = netlink.LinkSetHardwareAddr(sbox, mac) if err != nil { return err } endpoint.macAddress = mac // v6 address for the sandbox side pipe interface ipv6Addr = &net.IPNet{} if config.EnableIPv6 { var ip6 net.IP network := n.bridge.bridgeIPv6 if config.FixedCIDRv6 != nil { network = config.FixedCIDRv6 } ones, _ := network.Mask.Size() if ones <= 80 { ip6 = make(net.IP, len(network.IP)) copy(ip6, network.IP) for i, h := range mac { ip6[i+10] = h } } ip6, err := ipAllocator.RequestIP(network, ip6) if err != nil { return err } ipv6Addr = &net.IPNet{IP: ip6, Mask: network.Mask} } // Create the sandbox side pipe interface intf := &sandbox.Interface{} intf.SrcName = name2 intf.DstName = containerVethPrefix intf.Address = ipv4Addr if config.EnableIPv6 { intf.AddressIPv6 = ipv6Addr } // Store the interface in endpoint, this is needed for cleanup on DeleteEndpoint() endpoint.intf = intf err = epInfo.AddInterface(ifaceID, endpoint.macAddress, *ipv4Addr, *ipv6Addr) if err != nil { return err } // Program any required port mapping and store them in the endpoint endpoint.portMapping, err = allocatePorts(epConfig, intf, config.DefaultBindingIP, config.EnableUserlandProxy) if err != nil { return err } return nil }
func (v *veth) initialize(config *network) error { peer := config.TempVethPeerName if peer == "" { return fmt.Errorf("peer is not specified") } child, err := netlink.LinkByName(peer) if err != nil { return err } if err := netlink.LinkSetDown(child); err != nil { return err } if err := netlink.LinkSetName(child, config.Name); err != nil { return err } // get the interface again after we changed the name as the index also changes. if child, err = netlink.LinkByName(config.Name); err != nil { return err } if config.MacAddress != "" { mac, err := net.ParseMAC(config.MacAddress) if err != nil { return err } if err := netlink.LinkSetHardwareAddr(child, mac); err != nil { return err } } ip, err := netlink.ParseAddr(config.Address) if err != nil { return err } if err := netlink.AddrAdd(child, ip); err != nil { return err } if config.IPv6Address != "" { ip6, err := netlink.ParseAddr(config.IPv6Address) if err != nil { return err } if err := netlink.AddrAdd(child, ip6); err != nil { return err } } if err := netlink.LinkSetMTU(child, config.Mtu); err != nil { return err } if err := netlink.LinkSetUp(child); err != nil { return err } if config.Gateway != "" { gw := net.ParseIP(config.Gateway) if err := netlink.RouteAdd(&netlink.Route{ Scope: netlink.SCOPE_UNIVERSE, LinkIndex: child.Attrs().Index, Gw: gw, }); err != nil { return err } } if config.IPv6Gateway != "" { gw := net.ParseIP(config.IPv6Gateway) if err := netlink.RouteAdd(&netlink.Route{ Scope: netlink.SCOPE_UNIVERSE, LinkIndex: child.Attrs().Index, Gw: gw, }); err != nil { return err } } return nil }
func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error { defer osl.InitOSContext()() if ifInfo == nil { return errors.New("invalid interface info passed") } // Get the network handler and make sure it exists d.Lock() n, ok := d.networks[nid] dconfig := d.config d.Unlock() if !ok { return types.NotFoundErrorf("network %s does not exist", nid) } if n == nil { return driverapi.ErrNoNetwork(nid) } // Sanity check n.Lock() if n.id != nid { n.Unlock() return InvalidNetworkIDError(nid) } n.Unlock() // Check if endpoint id is good and retrieve correspondent endpoint ep, err := n.getEndpoint(eid) if err != nil { return err } // Endpoint with that id exists either on desired or other sandbox if ep != nil { return driverapi.ErrEndpointExists(eid) } // Try to convert the options to endpoint configuration epConfig, err := parseEndpointOptions(epOptions) if err != nil { return err } // Create and add the endpoint n.Lock() endpoint := &bridgeEndpoint{id: eid, config: epConfig} n.endpoints[eid] = endpoint n.Unlock() // On failure make sure to remove the endpoint defer func() { if err != nil { n.Lock() delete(n.endpoints, eid) n.Unlock() } }() // Generate a name for what will be the host side pipe interface hostIfName, err := netutils.GenerateIfaceName(vethPrefix, vethLen) if err != nil { return err } // Generate a name for what will be the sandbox side pipe interface containerIfName, err := netutils.GenerateIfaceName(vethPrefix, vethLen) if err != nil { return err } // Generate and add the interface pipe host <-> sandbox veth := &netlink.Veth{ LinkAttrs: netlink.LinkAttrs{Name: hostIfName, TxQLen: 0}, PeerName: containerIfName} if err = netlink.LinkAdd(veth); err != nil { return types.InternalErrorf("failed to add the host (%s) <=> sandbox (%s) pair interfaces: %v", hostIfName, containerIfName, err) } // Get the host side pipe interface handler host, err := netlink.LinkByName(hostIfName) if err != nil { return types.InternalErrorf("failed to find host side interface %s: %v", hostIfName, err) } defer func() { if err != nil { netlink.LinkDel(host) } }() // Get the sandbox side pipe interface handler sbox, err := netlink.LinkByName(containerIfName) if err != nil { return types.InternalErrorf("failed to find sandbox side interface %s: %v", containerIfName, err) } defer func() { if err != nil { netlink.LinkDel(sbox) } }() n.Lock() config := n.config n.Unlock() // Add bridge inherited attributes to pipe interfaces if config.Mtu != 0 { err = netlink.LinkSetMTU(host, config.Mtu) if err != nil { return types.InternalErrorf("failed to set MTU on host interface %s: %v", hostIfName, err) } err = netlink.LinkSetMTU(sbox, config.Mtu) if err != nil { return types.InternalErrorf("failed to set MTU on sandbox interface %s: %v", containerIfName, err) } } // Attach host side pipe interface into the bridge if err = addToBridge(hostIfName, config.BridgeName); err != nil { return fmt.Errorf("adding interface %s to bridge %s failed: %v", hostIfName, config.BridgeName, err) } if !dconfig.EnableUserlandProxy { err = setHairpinMode(host, true) if err != nil { return err } } // Create the sandbox side pipe interface endpoint.srcName = containerIfName endpoint.macAddress = ifInfo.MacAddress() endpoint.addr = ifInfo.Address() endpoint.addrv6 = ifInfo.AddressIPv6() // Down the interface before configuring mac address. if err = netlink.LinkSetDown(sbox); err != nil { return fmt.Errorf("could not set link down for container interface %s: %v", containerIfName, err) } // Set the sbox's MAC. If specified, use the one configured by user, otherwise generate one based on IP. if endpoint.macAddress == nil { endpoint.macAddress = electMacAddress(epConfig, endpoint.addr.IP) if err := ifInfo.SetMacAddress(endpoint.macAddress); err != nil { return err } } err = netlink.LinkSetHardwareAddr(sbox, endpoint.macAddress) if err != nil { return fmt.Errorf("could not set mac address for container interface %s: %v", containerIfName, err) } // Up the host interface after finishing all netlink configuration if err = netlink.LinkSetUp(host); err != nil { return fmt.Errorf("could not set link up for host interface %s: %v", hostIfName, err) } if endpoint.addrv6 == nil && config.EnableIPv6 { var ip6 net.IP network := n.bridge.bridgeIPv6 if config.AddressIPv6 != nil { network = config.AddressIPv6 } ones, _ := network.Mask.Size() if ones > 80 { err = types.ForbiddenErrorf("Cannot self generate an IPv6 address on network %v: At least 48 host bits are needed.", network) return err } ip6 = make(net.IP, len(network.IP)) copy(ip6, network.IP) for i, h := range endpoint.macAddress { ip6[i+10] = h } endpoint.addrv6 = &net.IPNet{IP: ip6, Mask: network.Mask} if err := ifInfo.SetIPAddress(endpoint.addrv6); err != nil { return err } } // Add a neighbor proxy if using NDP proxying if config.NDPProxyInterface != "" && config.EnableIPv6 { link, err := netlink.LinkByName(config.NDPProxyInterface) if err != nil { return err } neighbor := netlink.Neigh{ LinkIndex: link.Attrs().Index, Family: netlink.FAMILY_V6, State: netlink.NUD_PERMANENT, Type: netlink.NDA_UNSPEC, Flags: netlink.NTF_PROXY, IP: endpoint.addrv6.IP, HardwareAddr: endpoint.macAddress, } if err := netlink.NeighAdd(&neighbor); err != nil { logrus.Warnf("could not add the neighbor proxy: %v", err) return err } if endpoint.config != nil { for _, port := range endpoint.config.ExposedPorts { insert := []string{ string(iptables.Insert), DockerChain, "-p", port.Proto.String(), "-d", endpoint.addrv6.String(), "--dport", strconv.Itoa(int(port.Port)), "-j", "ACCEPT", } iptables.Raw(iptables.IP6Tables, insert...) } } } // Program any required port mapping and store them in the endpoint endpoint.portMapping, err = n.allocatePorts(epConfig, endpoint, config.DefaultBindingIP, d.config.EnableUserlandProxy) if err != nil { return err } return nil }
func applyInterfaceConfig(link netlink.Link, netConf InterfaceConfig) error { if netConf.Bond != "" { if err := netlink.LinkSetDown(link); err != nil { return err } b, err := Bond(netConf.Bond) if err != nil { return err } if err := b.AddSlave(link.Attrs().Name); err != nil { return err } return nil } if netConf.Bridge != "" && netConf.Bridge != "true" { b, err := NewBridge(netConf.Bridge) if err != nil { return err } if err := b.AddLink(link); err != nil { return err } return linkUp(link, netConf) } if netConf.IPV4LL { if err := AssignLinkLocalIP(link); err != nil { log.Errorf("IPV4LL set failed: %v", err) return err } } else { addresses := []string{} if netConf.Address != "" { addresses = append(addresses, netConf.Address) } if len(netConf.Addresses) > 0 { addresses = append(addresses, netConf.Addresses...) } for _, address := range addresses { err := applyAddress(address, link, netConf) if err != nil { log.Errorf("Failed to apply address %s to %s: %v", address, link.Attrs().Name, err) } } } if netConf.MTU > 0 { if err := netlink.LinkSetMTU(link, netConf.MTU); err != nil { log.Errorf("set MTU Failed: %v", err) return err } } runCmds(netConf.PreUp, link.Attrs().Name) if err := linkUp(link, netConf); err != nil { return err } if err := setGateway(netConf.Gateway); err != nil { log.Errorf("Fail to set gateway %s", netConf.Gateway) } if err := setGateway(netConf.GatewayIpv6); err != nil { log.Errorf("Fail to set gateway %s", netConf.GatewayIpv6) } runCmds(netConf.PostUp, link.Attrs().Name) return nil }
// configureInterface is used to configure an individual interface against a // matched configuration. It sets up the addresses, the MTU, and invokes DHCP if // necessary. func configureInterface(link netlink.Link, netconf *kurmaNetworkInterface) error { linkName := link.Attrs().Name addressConfigured := true // configure using DHCP if netconf.DHCP { cmd := exec.Command("udhcpc", "-i", linkName, "-t", "20", "-n") cmd.Stdin = nil cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { return fmt.Errorf("failed to configure %s with DHCP: %v", linkName, err) } addressConfigured = true } // single address if netconf.Address != "" { addr, err := netlink.ParseAddr(netconf.Address) if err != nil { return fmt.Errorf("failed to parse address %q on %s", netconf.Address, linkName) } if err := netlink.AddrAdd(link, addr); err != nil { return fmt.Errorf("failed to configure address %q on %s: %v", netconf.Address, linkName, err) } addressConfigured = true } // list of addresses for _, address := range netconf.Addresses { addr, err := netlink.ParseAddr(address) if err != nil { return fmt.Errorf("failed to parse address %q on %s", address, linkName) } if err := netlink.AddrAdd(link, addr); err != nil { return fmt.Errorf("failed to configure address %q on %s: %v", address, linkName, err) } addressConfigured = true } if !addressConfigured { return fmt.Errorf("no address configured to %s: unable to set link up", linkName) } if netconf.MTU > 0 { if err := netlink.LinkSetMTU(link, netconf.MTU); err != nil { return fmt.Errorf("failed to set mtu on %s: %v", linkName, err) } } // verify it is up at the end if link.Attrs().Flags&net.FlagUp == 0 { if err := netlink.LinkSetUp(link); err != nil { return fmt.Errorf("failed to set link %s up: %v", linkName, err) } } return nil }
func (e *endpoints) create(eid string, ifInfo *driverapi.EndpointInterface, niConfig networkConfig) (err error) { ep := endpoint{} // Generate a name for what will be the host side pipe interface hostIfName, err := netutils.GenerateIfaceName(vethPrefix, vethLen) if err != nil { return err } // Generate a name for what will be the sandbox side pipe interface containerIfName, err := netutils.GenerateIfaceName(vethPrefix, vethLen) if err != nil { return err } // Generate and add the interface pipe host <-> sandbox veth := &netlink.Veth{ LinkAttrs: netlink.LinkAttrs{Name: hostIfName, TxQLen: 0}, PeerName: containerIfName, } if err = netlink.LinkAdd(veth); err != nil { return types.InternalErrorf("failed to add the host (%s) <=> sandbox (%s) pair interfaces: %v", hostIfName, containerIfName, err) } // Get the host side pipe interface handler host, err := netlink.LinkByName(hostIfName) if err != nil { return types.InternalErrorf("failed to find host side interface %s: %v", hostIfName, err) } defer func() { if err != nil { netlink.LinkDel(host) } }() // Get the sandbox side pipe interface handler sbox, err := netlink.LinkByName(containerIfName) if err != nil { return types.InternalErrorf("failed to find sandbox side interface %s: %v", containerIfName, err) } defer func() { if err != nil { netlink.LinkDel(sbox) } }() // Add bridge inherited attributes to pipe interfaces if niConfig.Mtu != 0 { err = netlink.LinkSetMTU(host, niConfig.Mtu) if err != nil { return types.InternalErrorf("failed to set MTU on host interface %s: %v", hostIfName, err) } err = netlink.LinkSetMTU(sbox, niConfig.Mtu) if err != nil { return types.InternalErrorf("failed to set MTU on sandbox interface %s: %v", containerIfName, err) } } // Attach host side pipe interface into the bridge br, err := netlink.LinkByName(niConfig.BridgeName) if err != nil { return types.InternalErrorf("failed to find bridge by name %s: %v", niConfig.BridgeName, err) } if err = netlink.LinkSetMaster(host, br.(*netlink.Bridge)); err != nil { return fmt.Errorf("adding interface %s to bridge %s failed: %v", hostIfName, niConfig.BridgeName, err) } // Create the sandbox side pipe interface ep.ifname = containerIfName ep.addr, _, err = net.ParseCIDR(ifInfo.Address) if err != nil { return fmt.Errorf("ipv4 adress unparseable") } /* _, ep.addrv6, err = net.ParseCIDR(ifInfo.AddressIPv6) if err != nil { return fmt.Errorf("ipv6 adress unparseable") } */ if ifInfo.MacAddress != "" { ep.mac, err = net.ParseMAC(ifInfo.MacAddress) if err != nil { return fmt.Errorf("mac adress unparseable") } // Down the interface before configuring mac address. if err = netlink.LinkSetDown(sbox); err != nil { return fmt.Errorf("could not set link down for container interface %s: %v", containerIfName, err) } err = netlink.LinkSetHardwareAddr(sbox, ep.mac) if err != nil { return fmt.Errorf("could not set mac address for container interface %s: %v", containerIfName, err) } if err = netlink.LinkSetUp(sbox); err != nil { return fmt.Errorf("could not set link up for container interface %s: %v", containerIfName, err) } } else { // Get existing mac address from interface ep.mac = sbox.Attrs().HardwareAddr } // Up the host interface after finishing all netlink configuration if err = netlink.LinkSetUp(host); err != nil { return fmt.Errorf("could not set link up for host interface %s: %v", hostIfName, err) } if ep.addrv6 == nil && niConfig.EnableIPv6 { return fmt.Errorf("IPV6 is not supported. Go and code it yourself.") } e.add(eid, ep) Log.Debugf("ep data at join: ip: %v, mac: %v", ep.addr, ep.mac) broadcastChange(br, ep) return nil }
func (d *Driver) createVxLan(vxlanName string, net *dockertypes.NetworkResource) (*netlink.Vxlan, error) { vxlan := &netlink.Vxlan{ LinkAttrs: netlink.LinkAttrs{ Name: vxlanName, }, } // Parse interface options for k, v := range net.Options { if k == "vxlanMTU" { MTU, err := strconv.Atoi(v) if err != nil { log.Errorf("Error converting MTU to int: %v", err) return nil, err } vxlan.LinkAttrs.MTU = MTU } if k == "vxlanHardwareAddr" { HardwareAddr, err := gonet.ParseMAC(v) if err != nil { log.Errorf("Error parsing mac: %v", err) return nil, err } vxlan.LinkAttrs.HardwareAddr = HardwareAddr } if k == "vxlanTxQLen" { TxQLen, err := strconv.Atoi(v) if err != nil { log.Errorf("Error converting TxQLen to int: %v", err) return nil, err } vxlan.LinkAttrs.TxQLen = TxQLen } if k == "VxlanId" { log.Debugf("VxlanID: %+v", v) VxlanID, err := strconv.ParseInt(v, 0, 32) if err != nil { log.Errorf("Error converting VxlanId to int: %v", err) return nil, err } log.Debugf("VxlanID: %+v", VxlanID) log.Debugf("int(VxlanID): %+v", int(VxlanID)) vxlan.VxlanId = int(VxlanID) } if k == "VtepDev" { vtepDev, err := netlink.LinkByName(v) if err != nil { log.Errorf("Error getting VtepDev interface: %v", err) return nil, err } vxlan.VtepDevIndex = vtepDev.Attrs().Index } if k == "SrcAddr" { vxlan.SrcAddr = gonet.ParseIP(v) } if k == "Group" { vxlan.Group = gonet.ParseIP(v) } if k == "TTL" { TTL, err := strconv.Atoi(v) if err != nil { log.Errorf("Error converting TTL to int: %v", err) return nil, err } vxlan.TTL = TTL } if k == "TOS" { TOS, err := strconv.Atoi(v) if err != nil { log.Errorf("Error converting TOS to int: %v", err) return nil, err } vxlan.TOS = TOS } if k == "Learning" { Learning, err := strconv.ParseBool(v) if err != nil { log.Errorf("Error converting Learning to bool: %v", err) return nil, err } vxlan.Learning = Learning } if k == "Proxy" { Proxy, err := strconv.ParseBool(v) if err != nil { log.Errorf("Error converting Proxy to bool: %v", err) return nil, err } vxlan.Proxy = Proxy } if k == "RSC" { RSC, err := strconv.ParseBool(v) if err != nil { log.Errorf("Error converting RSC to bool: %v", err) return nil, err } vxlan.RSC = RSC } if k == "L2miss" { L2miss, err := strconv.ParseBool(v) if err != nil { log.Errorf("Error converting L2miss to bool: %v", err) return nil, err } vxlan.L2miss = L2miss } if k == "L3miss" { L3miss, err := strconv.ParseBool(v) if err != nil { log.Errorf("Error converting L3miss to bool: %v", err) return nil, err } vxlan.L3miss = L3miss } if k == "NoAge" { NoAge, err := strconv.ParseBool(v) if err != nil { log.Errorf("Error converting NoAge to bool: %v", err) return nil, err } vxlan.NoAge = NoAge } if k == "GBP" { GBP, err := strconv.ParseBool(v) if err != nil { log.Errorf("Error converting GBP to bool: %v", err) return nil, err } vxlan.GBP = GBP } if k == "Age" { Age, err := strconv.Atoi(v) if err != nil { log.Errorf("Error converting Age to int: %v", err) return nil, err } vxlan.Age = Age } if k == "Limit" { Limit, err := strconv.Atoi(v) if err != nil { log.Errorf("Error converting Limit to int: %v", err) return nil, err } vxlan.Limit = Limit } if k == "Port" { Port, err := strconv.Atoi(v) if err != nil { log.Errorf("Error converting Port to int: %v", err) return nil, err } vxlan.Port = Port } if k == "PortLow" { PortLow, err := strconv.Atoi(v) if err != nil { log.Errorf("Error converting PortLow to int: %v", err) return nil, err } vxlan.PortLow = PortLow } if k == "PortHigh" { PortHigh, err := strconv.Atoi(v) if err != nil { log.Errorf("Error converting PortHigh to int: %v", err) return nil, err } vxlan.PortHigh = PortHigh } } if d.vtepdev != "" { vtepDev, err := netlink.LinkByName(d.vtepdev) if err != nil { log.Errorf("Error getting vtepdev interface: %v", err) return nil, err } vxlan.VtepDevIndex = vtepDev.Attrs().Index } err := netlink.LinkAdd(vxlan) if err != nil { log.Errorf("Error adding vxlan interface: %v", err) return nil, err } // Parse interface options for k, v := range net.Options { if k == "vxlanHardwareAddr" { hardwareAddr, err := gonet.ParseMAC(v) if err != nil { log.Errorf("Error parsing mac address: %v", err) return nil, err } err = netlink.LinkSetHardwareAddr(vxlan, hardwareAddr) if err != nil { log.Errorf("Error setting mac address: %v", err) return nil, err } } if k == "vxlanMTU" { mtu, err := strconv.Atoi(v) if err != nil { log.Errorf("Error converting MTU to int: %v", err) return nil, err } err = netlink.LinkSetMTU(vxlan, mtu) if err != nil { log.Errorf("Error setting MTU: %v", err) return nil, err } } } // bring interfaces up err = netlink.LinkSetUp(vxlan) if err != nil { log.Errorf("Error bringing up vxlan: %v", err) return nil, err } return vxlan, nil }
// Join method is invoked when a Sandbox is attached to an endpoint. func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error { if err := validateID(nid, eid); err != nil { return err } n := d.network(nid) if n == nil { return fmt.Errorf("could not find network with id %s", nid) } ep := n.endpoint(eid) if ep == nil { return fmt.Errorf("could not find endpoint with id %s", eid) } if err := n.joinSandbox(); err != nil { return fmt.Errorf("network sandbox join failed: %v", err) } sbox := n.sandbox() name1, name2, err := createVethPair() if err != nil { return err } // Set the container interface and its peer MTU to 1450 to allow // for 50 bytes vxlan encap (inner eth header(14) + outer IP(20) + // outer UDP(8) + vxlan header(8)) veth, err := netlink.LinkByName(name1) if err != nil { return fmt.Errorf("cound not find link by name %s: %v", name1, err) } err = netlink.LinkSetMTU(veth, vxlanVethMTU) if err != nil { return err } if err := sbox.AddInterface(name1, "veth", sbox.InterfaceOptions().Master("bridge1")); err != nil { return fmt.Errorf("could not add veth pair inside the network sandbox: %v", err) } veth, err = netlink.LinkByName(name2) if err != nil { return fmt.Errorf("could not find link by name %s: %v", name2, err) } err = netlink.LinkSetMTU(veth, vxlanVethMTU) if err != nil { return err } if err := netlink.LinkSetHardwareAddr(veth, ep.mac); err != nil { return fmt.Errorf("could not set mac address to the container interface: %v", err) } if iNames := jinfo.InterfaceName(); iNames != nil { err = iNames.SetNames(name2, "eth") if err != nil { return err } } err = jinfo.SetGateway(bridgeIP.IP) if err != nil { return err } d.peerDbAdd(nid, eid, ep.addr.IP, ep.mac, d.serfInstance.LocalMember().Addr, true) d.notifyCh <- ovNotify{ action: "join", nid: nid, eid: eid, } return nil }
func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error { var ( ipv6Addr *net.IPNet err error ) defer sandbox.InitOSContext()() if epInfo == nil { return errors.New("invalid endpoint info passed") } if len(epInfo.Interfaces()) != 0 { return errors.New("non empty interface list passed to bridge(local) driver") } // Get the network handler and make sure it exists d.Lock() n, ok := d.networks[nid] d.Unlock() if !ok { return types.NotFoundErrorf("network %s does not exist", nid) } if n == nil { return driverapi.ErrNoNetwork(nid) } // Sanity check n.Lock() if n.id != nid { n.Unlock() return InvalidNetworkIDError(nid) } n.Unlock() // Check if endpoint id is good and retrieve correspondent endpoint ep, err := n.getEndpoint(eid) if err != nil { return err } // Endpoint with that id exists either on desired or other sandbox if ep != nil { return driverapi.ErrEndpointExists(eid) } // Try to convert the options to endpoint configuration epConfig, err := parseEndpointOptions(epOptions) if err != nil { return err } // Create and add the endpoint n.Lock() endpoint := &bridgeEndpoint{id: eid, config: epConfig} n.endpoints[eid] = endpoint n.Unlock() // On failure make sure to remove the endpoint defer func() { if err != nil { n.Lock() delete(n.endpoints, eid) n.Unlock() } }() // Generate a name for what will be the host side pipe interface hostIfName, err := netutils.GenerateIfaceName(vethPrefix, vethLen) if err != nil { return err } // Generate a name for what will be the sandbox side pipe interface containerIfName, err := netutils.GenerateIfaceName(vethPrefix, vethLen) if err != nil { return err } // Generate and add the interface pipe host <-> sandbox veth := &netlink.Veth{ LinkAttrs: netlink.LinkAttrs{Name: hostIfName, TxQLen: 0}, PeerName: containerIfName} if err = netlink.LinkAdd(veth); err != nil { return err } // Get the host side pipe interface handler host, err := netlink.LinkByName(hostIfName) if err != nil { return err } defer func() { if err != nil { netlink.LinkDel(host) } }() // Get the sandbox side pipe interface handler sbox, err := netlink.LinkByName(containerIfName) if err != nil { return err } defer func() { if err != nil { netlink.LinkDel(sbox) } }() n.Lock() config := n.config n.Unlock() // Add bridge inherited attributes to pipe interfaces if config.Mtu != 0 { err = netlink.LinkSetMTU(host, config.Mtu) if err != nil { return err } err = netlink.LinkSetMTU(sbox, config.Mtu) if err != nil { return err } } // Attach host side pipe interface into the bridge if err = addToBridge(hostIfName, config.BridgeName); err != nil { return fmt.Errorf("adding interface %s to bridge %s failed: %v", hostIfName, config.BridgeName, err) } if !config.EnableUserlandProxy { err = setHairpinMode(host, true) if err != nil { return err } } // v4 address for the sandbox side pipe interface ip4, err := ipAllocator.RequestIP(n.bridge.bridgeIPv4, nil) if err != nil { return err } ipv4Addr := &net.IPNet{IP: ip4, Mask: n.bridge.bridgeIPv4.Mask} // Down the interface before configuring mac address. if err = netlink.LinkSetDown(sbox); err != nil { return fmt.Errorf("could not set link down for container interface %s: %v", containerIfName, err) } // Set the sbox's MAC. If specified, use the one configured by user, otherwise generate one based on IP. mac := electMacAddress(epConfig, ip4) err = netlink.LinkSetHardwareAddr(sbox, mac) if err != nil { return fmt.Errorf("could not set mac address for container interface %s: %v", containerIfName, err) } endpoint.macAddress = mac // Up the host interface after finishing all netlink configuration if err = netlink.LinkSetUp(host); err != nil { return fmt.Errorf("could not set link up for host interface %s: %v", hostIfName, err) } // v6 address for the sandbox side pipe interface ipv6Addr = &net.IPNet{} if config.EnableIPv6 { var ip6 net.IP network := n.bridge.bridgeIPv6 if config.FixedCIDRv6 != nil { network = config.FixedCIDRv6 } ones, _ := network.Mask.Size() if ones <= 80 { ip6 = make(net.IP, len(network.IP)) copy(ip6, network.IP) for i, h := range mac { ip6[i+10] = h } } ip6, err := ipAllocator.RequestIP(network, ip6) if err != nil { return err } ipv6Addr = &net.IPNet{IP: ip6, Mask: network.Mask} } // Create the sandbox side pipe interface endpoint.srcName = containerIfName endpoint.addr = ipv4Addr if config.EnableIPv6 { endpoint.addrv6 = ipv6Addr } err = epInfo.AddInterface(ifaceID, endpoint.macAddress, *ipv4Addr, *ipv6Addr) if err != nil { return err } // Program any required port mapping and store them in the endpoint endpoint.portMapping, err = n.allocatePorts(epConfig, endpoint, config.DefaultBindingIP, config.EnableUserlandProxy) if err != nil { return err } return nil }
func applyNetConf(link netlink.Link, netConf InterfaceConfig) error { if netConf.Bond != "" { b := Bond(netConf.Bond) b.AddSlave(link.Attrs().Name) if b.Error() != nil { return b.Error() } return linkUp(link, netConf) } if netConf.IPV4LL { if err := AssignLinkLocalIP(link); err != nil { log.Errorf("IPV4LL set failed: %v", err) return err } } else if netConf.Address == "" && len(netConf.Addresses) == 0 { return nil } else { if netConf.Address != "" { err := applyAddress(netConf.Address, link, netConf) if err != nil { log.Errorf("Failed to apply address %s to %s: %v", netConf.Address, link.Attrs().Name, err) } } for _, address := range netConf.Addresses { err := applyAddress(address, link, netConf) if err != nil { log.Errorf("Failed to apply address %s to %s: %v", address, link.Attrs().Name, err) } } } if netConf.MTU > 0 { if err := netlink.LinkSetMTU(link, netConf.MTU); err != nil { log.Errorf("set MTU Failed: %v", err) return err } } if err := linkUp(link, netConf); err != nil { return err } if err := setGateway(netConf.Gateway); err != nil { log.Errorf("Fail to set gateway %s", netConf.Gateway) } if err := setGateway(netConf.GatewayIpv6); err != nil { log.Errorf("Fail to set gateway %s", netConf.Gateway) } for _, postUp := range netConf.PostUp { postUp = strings.TrimSpace(postUp) if postUp == "" { continue } args, err := shlex.Split(strings.Replace(postUp, "$iface", link.Attrs().Name, -1)) if err != nil { log.Errorf("Failed to parse command [%s]: %v", postUp, err) continue } cmd := exec.Command(args[0], args[1:]...) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { log.Errorf("Failed to run command [%s]: %v", postUp, err) continue } } return nil }