diff --git a/plugins/main/bridge/bridge.go b/plugins/main/bridge/bridge.go index 4054f6176..67414b08c 100644 --- a/plugins/main/bridge/bridge.go +++ b/plugins/main/bridge/bridge.go @@ -18,6 +18,7 @@ import ( "encoding/json" "errors" "fmt" + "log" "net" "os" "runtime" @@ -42,6 +43,7 @@ import ( // For testcases to force an error after IPAM has been performed var debugPostIPAMError error +var logger = log.New(os.Stdout, "", log.Ldate|log.Ltime) const defaultBrName = "cni0" @@ -774,10 +776,6 @@ func cmdDel(args *skel.CmdArgs) error { return nil } - if args.Netns == "" { - return ipamDel() - } - // There is a netns so try to clean up. Delete can be called multiple times // so don't return an error if the device is already removed. // If the device isn't there then don't try to clean up IP masq either. @@ -791,28 +789,35 @@ func cmdDel(args *skel.CmdArgs) error { return err }) if err != nil { - // if NetNs is passed down by the Cloud Orchestration Engine, or if it called multiple times + // if NetNs is passed down by the Cloud Orchestration Engine, or if it called multiple times // so don't return an error if the device is already removed. // https://github.com/kubernetes/kubernetes/issues/43014#issuecomment-287164444 _, ok := err.(ns.NSPathNotExistErr) - if ok { - return ipamDel() + if !ok { + return err } - return err } - // call ipam.ExecDel after clean up device in netns - if err := ipamDel(); err != nil { - return err - } + if len(ipnets) == 0 { + // could not get ip address within netns, so try to get it from prevResult + prevResult, err := parsePrevResult(n) + if err != nil { + return err + } - if n.MacSpoofChk { - sc := link.NewSpoofChecker("", "", uniqueID(args.ContainerID, args.IfName)) - if err := sc.Teardown(); err != nil { - fmt.Fprintf(os.Stderr, "%v", err) + if prevResult != nil { + ipCfgs, err := getIPCfgs(args.IfName, prevResult) + if err != nil { + return err + } + + for _, ip := range ipCfgs { + ipnets = append(ipnets, &ip.Address) + } } } + // clean up IP masq first if isLayer3 && n.IPMasq { chain := utils.FormatChainName(n.Name, args.ContainerID) comment := utils.FormatComment(n.Name, args.ContainerID) @@ -823,6 +828,18 @@ func cmdDel(args *skel.CmdArgs) error { } } + // call ipam.ExecDel after clean up device in netns + if err := ipamDel(); err != nil { + return err + } + + if n.MacSpoofChk { + sc := link.NewSpoofChecker("", "", uniqueID(args.ContainerID, args.IfName)) + if err := sc.Teardown(); err != nil { + fmt.Fprintf(os.Stderr, "%v", err) + } + } + return err } @@ -1088,3 +1105,60 @@ func cmdCheck(args *skel.CmdArgs) error { func uniqueID(containerID, cniIface string) string { return containerID + "-" + cniIface } + +// parsePrevResult parse previous result +func parsePrevResult(conf *NetConf) (*current.Result, error) { + var prevResult *current.Result + if conf.RawPrevResult != nil { + resultBytes, err := json.Marshal(conf.RawPrevResult) + if err != nil { + return nil, fmt.Errorf("could not serialize prevResult: %#v", err) + } + res, err := version.NewResult(conf.CNIVersion, resultBytes) + if err != nil { + return nil, fmt.Errorf("could not parse prevResult: %v", err) + } + conf.RawPrevResult = nil + prevResult, err = current.NewResultFromResult(res) + if err != nil { + return nil, fmt.Errorf("could not convert result to current version: %v", err) + } + } + return prevResult, nil +} + +// getIPCfgs finds the IPs on the supplied interface, returning as IPConfig structures +func getIPCfgs(iface string, prevResult *current.Result) ([]*current.IPConfig, error) { + if len(prevResult.IPs) == 0 { + // No IP addresses; that makes no sense. Pack it in. + return nil, fmt.Errorf("No IP addresses supplied on interface: %s", iface) + } + + // We do a single interface name, stored in args.IfName + logger.Printf("Checking for relevant interface: %s", iface) + + // ips contains the IPConfig structures that were passed, filtered somewhat + ipCfgs := make([]*current.IPConfig, 0, len(prevResult.IPs)) + + for _, ipCfg := range prevResult.IPs { + // IPs have an interface that is an index into the interfaces array. + // We assume a match if this index is missing. + if ipCfg.Interface == nil { + logger.Printf("No interface for IP address %s", ipCfg.Address.IP) + ipCfgs = append(ipCfgs, ipCfg) + continue + } + + // Skip all IPs we know belong to an interface with the wrong name. + intIdx := *ipCfg.Interface + if intIdx >= 0 && intIdx < len(prevResult.Interfaces) && prevResult.Interfaces[intIdx].Name != iface { + logger.Printf("Incorrect interface for IP address %s", ipCfg.Address.IP) + continue + } + + logger.Printf("Found IP address %s", ipCfg.Address.IP.String()) + ipCfgs = append(ipCfgs, ipCfg) + } + + return ipCfgs, nil +}