diff --git a/k8sclient/k8sclient.go b/k8sclient/k8sclient.go index 81549bef7..e445239fb 100644 --- a/k8sclient/k8sclient.go +++ b/k8sclient/k8sclient.go @@ -112,6 +112,20 @@ func SetNetworkStatus(client KubeClient, k8sArgs *types.K8sArgs, netStatus []*ty if netStatus != nil { var networkStatus []string for _, status := range netStatus { + // Clean each empty gateway + // Otherwise we wind up with JSON that's a "default-route": [""] + cleargateway := true + for _, eachgateway := range status.Gateway { + if eachgateway != nil { + cleargateway = false + } + } + + if cleargateway { + status.Gateway = nil + } + + // Now we can sanely marshal the JSON output data, err := json.MarshalIndent(status, "", " ") if err != nil { return logging.Errorf("SetNetworkStatus: error with Marshal Indent: %v", err) diff --git a/multus/multus.go b/multus/multus.go index 2cbd172b2..64b403110 100644 --- a/multus/multus.go +++ b/multus/multus.go @@ -251,7 +251,7 @@ func delegateAdd(exec invoke.Exec, ifName string, delegate *types.DelegateNetCon cniArgs = fmt.Sprintf("%s;MAC=%s", cniArgs, delegate.MacRequest) logging.Debugf("delegateAdd: set MAC address %q to %q", delegate.MacRequest, ifName) - rt.Args = append(rt.Args, [2]string{ "MAC", delegate.MacRequest }) + rt.Args = append(rt.Args, [2]string{"MAC", delegate.MacRequest}) } if delegate.IPRequest != nil { @@ -270,7 +270,7 @@ func delegateAdd(exec invoke.Exec, ifName string, delegate *types.DelegateNetCon ips := strings.Join(delegate.IPRequest, ",") cniArgs = fmt.Sprintf("%s;IP=%s", cniArgs, ips) logging.Debugf("delegateAdd: set IP address %q to %q", ips, ifName) - rt.Args = append(rt.Args, [2]string{ "IP", ips }) + rt.Args = append(rt.Args, [2]string{"IP", ips}) } } @@ -421,13 +421,35 @@ func cmdAdd(args *skel.CmdArgs, exec invoke.Exec, kubeClient k8s.KubeClient) (cn } // Remove gateway from routing table if the gateway is not used + deletegateway := false + adddefaultgateway := false if delegate.IsFilterGateway { + deletegateway = true + logging.Debugf("Marked interface %v for gateway deletion", ifName) + } else { + // Otherwise, determine if this interface now gets our default route. + if delegate.GatewayRequest != nil { + deletegateway = true + adddefaultgateway = true + logging.Debugf("Detected gateway override on interface %v to %v", ifName, delegate.GatewayRequest) + } + } + + if deletegateway { tmpResult, err = netutils.DeleteDefaultGW(args, ifName, &tmpResult) if err != nil { return nil, logging.Errorf("Multus: Err in deleting gateway: %v", err) } } + // Here we'll set the default gateway + if adddefaultgateway { + tmpResult, err = netutils.SetDefaultGW(args, ifName, delegate.GatewayRequest, &tmpResult) + if err != nil { + return nil, logging.Errorf("Multus: Err in setting default gateway: %v", err) + } + } + // Master plugin result is always used if present if delegate.MasterPlugin || result == nil { result = tmpResult diff --git a/netutils/netutils.go b/netutils/netutils.go index a42eb3efe..759ac14f0 100644 --- a/netutils/netutils.go +++ b/netutils/netutils.go @@ -20,23 +20,21 @@ import ( cnitypes "github.com/containernetworking/cni/pkg/types" "github.com/containernetworking/cni/pkg/types/current" "github.com/containernetworking/plugins/pkg/ns" - "github.com/intel/multus-cni/logging" - "github.com/vishvananda/netlink" + "net" ) // DeleteDefaultGW removes the default gateway from marked interfaces. func DeleteDefaultGW(args *skel.CmdArgs, ifName string, res *cnitypes.Result) (*current.Result, error) { - logging.Debugf("XXX: DeleteDefaultGW: %s", args.Netns) result, err := current.NewResultFromResult(*res) if err != nil { - return nil, logging.Errorf("XXX: %v", err) + return nil, logging.Errorf("DeleteDefaultGW: Error creating new from current CNI result: %v", err) } netns, err := ns.GetNS(args.Netns) if err != nil { - return nil, logging.Errorf("XXX: %v", err) + return nil, logging.Errorf("DeleteDefaultGW: Error getting namespace %v", err) } defer netns.Close() @@ -60,3 +58,61 @@ func DeleteDefaultGW(args *skel.CmdArgs, ifName string, res *cnitypes.Result) (* result.Routes = newRoutes return result, err } + +// SetDefaultGW adds a default gateway on a specific interface +func SetDefaultGW(args *skel.CmdArgs, ifName string, gateways []net.IP, res *cnitypes.Result) (*current.Result, error) { + + // Use the current CNI result... + result, err := current.NewResultFromResult(*res) + if err != nil { + return nil, logging.Errorf("SetDefaultGW: Error creating new CNI result from current: %v", err) + } + + // This ensures we're acting within the net namespace for the pod. + netns, err := ns.GetNS(args.Netns) + if err != nil { + return nil, logging.Errorf("SetDefaultGW: Error getting namespace %v", err) + } + defer netns.Close() + + var newResultDefaultRoutes []*cnitypes.Route + + // Do this within the net namespace. + err = netns.Do(func(_ ns.NetNS) error { + var err error + + // Pick up the link info as we need the index. + link, _ := netlink.LinkByName(ifName) + + // Cycle through all the desired gateways. + for _, gw := range gateways { + + // Create a new route (note: dst is nil by default) + logging.Debugf("SetDefaultGW: Adding default route on %v (index: %v) to %v", ifName, link.Attrs().Index, gw) + newDefaultRoute := netlink.Route{ + LinkIndex: link.Attrs().Index, + Gw: gw, + } + + // Build a new element for the results route + + // Set a correct CIDR depending on IP type + _, dstipnet, _ := net.ParseCIDR("::0/0") + if gw.To4 != nil { + _, dstipnet, _ = net.ParseCIDR("0.0.0.0/0") + } + newResultDefaultRoutes = append(newResultDefaultRoutes, &cnitypes.Route{Dst: *dstipnet, GW: gw}) + + // Perform the creation of the default route.... + err = netlink.RouteAdd(&newDefaultRoute) + if err != nil { + logging.Errorf("SetDefaultGW: Error adding route: %v", err) + } + } + return err + }) + + result.Routes = newResultDefaultRoutes + return result, err + +} diff --git a/types/conf.go b/types/conf.go index 35174631f..8b90a8a19 100644 --- a/types/conf.go +++ b/types/conf.go @@ -204,7 +204,6 @@ func LoadNetworkStatus(r types.Result, netName string, defaultNet bool) (*Networ logging.Debugf("LoadNetworkStatus: %v, %s, %t", r, netName, defaultNet) netstatus := &NetworkStatus{} netstatus.Name = netName - netstatus.Default = defaultNet // Convert whatever the IPAM result was into the current Result type result, err := current.NewResultFromResult(r) diff --git a/types/types.go b/types/types.go index c5370099d..e00003f24 100644 --- a/types/types.go +++ b/types/types.go @@ -86,7 +86,6 @@ type NetworkStatus struct { Interface string `json:"interface,omitempty"` IPs []string `json:"ips,omitempty"` Mac string `json:"mac,omitempty"` - Default bool `json:"default,omitempty"` DNS types.DNS `json:"dns,omitempty"` Gateway []net.IP `json:"default-route,omitempty"` }