func cmdDel(args *skel.CmdArgs) error { conf := NetConf{} if err := json.Unmarshal(args.StdinData, &conf); err != nil { return fmt.Errorf("failed to load netconf: %v", err) } var ipn *net.IPNet err := ns.WithNetNSPath(args.Netns, false, func(hostNS *os.File) error { var err error ipn, err = ip.DelLinkByNameAddr(args.IfName, netlink.FAMILY_V4) return err }) if err != nil { return err } if conf.IPMasq { h := sha512.Sum512([]byte(args.ContainerID)) chain := fmt.Sprintf("CNI-%s-%x", conf.Name, h[:8]) if err = ip.TeardownIPMasq(ipn, chain); err != nil { return err } } return ipam.ExecDel(conf.IPAM.Type, args.StdinData) }
func cmdAdd(args *skel.CmdArgs) error { n, err := loadNetConf(args.StdinData) if err != nil { return err } br, err := setupBridge(n) if err != nil { return err } if err = setupVeth(args.Netns, br, args.IfName, n.MTU); err != nil { return err } // run the IPAM plugin and get back the config to apply result, err := ipam.ExecAdd(n.IPAM.Type, args.StdinData) if err != nil { return err } if result.IP4 == nil { return errors.New("IPAM plugin returned missing IPv4 config") } if result.IP4.Gateway == nil && n.IsGW { result.IP4.Gateway = calcGatewayIP(&result.IP4.IP) } err = ns.WithNetNSPath(args.Netns, false, func(hostNS *os.File) error { return ipam.ConfigureIface(args.IfName, result) }) if err != nil { return err } if n.IsGW { gwn := &net.IPNet{ IP: result.IP4.Gateway, Mask: result.IP4.IP.Mask, } if err = ensureBridgeAddr(br, gwn); err != nil { return err } if err := ip.EnableIP4Forward(); err != nil { return fmt.Errorf("failed to enable forwarding: %v", err) } } if n.IPMasq { chain := "CNI-" + n.Name if err = ip.SetupIPMasq(ip.Network(&result.IP4.IP), chain); err != nil { return err } } return result.Print() }
func setupVeth(netns string, br *netlink.Bridge, ifName string, mtu int) error { var hostVethName string err := ns.WithNetNSPath(netns, false, func(hostNS *os.File) error { // create the veth pair in the container and move host end into host netns hostVeth, _, err := ip.SetupVeth(ifName, mtu, hostNS) if err != nil { return err } hostVethName = hostVeth.Attrs().Name return nil }) if err != nil { return err } // need to lookup hostVeth again as its index has changed during ns move hostVeth, err := netlink.LinkByName(hostVethName) if err != nil { return fmt.Errorf("failed to lookup %q: %v", hostVethName, err) } // connect host veth end to the bridge if err = netlink.LinkSetMaster(hostVeth, br); err != nil { return fmt.Errorf("failed to connect %q to bridge %v: %v", hostVethName, br.Attrs().Name, err) } return nil }
func cmdDel(args *skel.CmdArgs) error { n, err := loadConf(args.StdinData) if err != nil { return err } err = ipam.ExecDel(n.IPAM.Type, args.StdinData) if err != nil { return err } return ns.WithNetNSPath(args.Netns, false, func(hostNS *os.File) error { return ip.DelLinkByName(args.IfName) }) }
// AcquireLease gets an DHCP lease and then maintains it in the background // by periodically renewing it. The acquired lease can be released by // calling DHCPLease.Stop() func AcquireLease(clientID, netns, ifName string) (*DHCPLease, error) { errCh := make(chan error, 1) l := &DHCPLease{ clientID: clientID, stop: make(chan struct{}), } log.Printf("%v: acquiring lease", clientID) l.wg.Add(1) go func() { errCh <- ns.WithNetNSPath(netns, true, func(_ *os.File) error { defer l.wg.Done() link, err := netlink.LinkByName(ifName) if err != nil { return fmt.Errorf("error looking up %q: %v", ifName, err) } l.link = link if err = l.acquire(); err != nil { return err } log.Printf("%v: lease acquired, expiration is %v", l.clientID, l.expireTime) errCh <- nil l.maintain() return nil }) }() if err := <-errCh; err != nil { return nil, err } return l, nil }
func setupContainerVeth(netns, ifName string, mtu int, pr *types.Result) (string, error) { // The IPAM result will be something like IP=192.168.3.5/24, GW=192.168.3.1. // What we want is really a point-to-point link but veth does not support IFF_POINTOPONT. // Next best thing would be to let it ARP but set interface to 192.168.3.5/32 and // add a route like "192.168.3.0/24 via 192.168.3.1 dev $ifName". // Unfortunately that won't work as the GW will be outside the interface's subnet. // Our solution is to configure the interface with 192.168.3.5/24, then delete the // "192.168.3.0/24 dev $ifName" route that was automatically added. Then we add // "192.168.3.1/32 dev $ifName" and "192.168.3.0/24 via 192.168.3.1 dev $ifName". // In other words we force all traffic to ARP via the gateway except for GW itself. var hostVethName string err := ns.WithNetNSPath(netns, false, func(hostNS *os.File) error { hostVeth, _, err := ip.SetupVeth(ifName, mtu, hostNS) if err != nil { return err } if err = ipam.ConfigureIface(ifName, pr); err != nil { return err } contVeth, err := netlink.LinkByName(ifName) if err != nil { return err } // Delete the route that was automatically added route := netlink.Route{ LinkIndex: contVeth.Attrs().Index, Dst: &net.IPNet{ IP: pr.IP4.IP.IP.Mask(pr.IP4.IP.Mask), Mask: pr.IP4.IP.Mask, }, Scope: netlink.SCOPE_LINK, Src: pr.IP4.IP.IP, } if err := netlink.RouteDel(&route); err != nil { return err } for _, r := range []netlink.Route{ netlink.Route{ LinkIndex: contVeth.Attrs().Index, Dst: &net.IPNet{ IP: pr.IP4.Gateway, Mask: net.CIDRMask(32, 32), }, Scope: netlink.SCOPE_LINK, Src: pr.IP4.IP.IP, }, netlink.Route{ LinkIndex: contVeth.Attrs().Index, Dst: &net.IPNet{ IP: pr.IP4.IP.IP.Mask(pr.IP4.IP.Mask), Mask: pr.IP4.IP.Mask, }, Scope: netlink.SCOPE_UNIVERSE, Gw: pr.IP4.Gateway, Src: pr.IP4.IP.IP, }, } { if err := netlink.RouteAdd(&r); err != nil { return err } } hostVethName = hostVeth.Attrs().Name return nil }) return hostVethName, err }