mirror of
https://github.com/k8snetworkplumbingwg/multus-cni.git
synced 2025-07-04 11:26:17 +00:00
Support gateway in NetworkSelectionElement
Changes config JSON from gateway to default-route, adds Readme, fixes lint Co-authored-by: dougbtv <dosmith@redhat.com>
This commit is contained in:
parent
84c348ce18
commit
165e23b72c
@ -469,6 +469,72 @@ $ kubectl exec -it pod-case-06 -- ip -d address
|
|||||||
| macvlan1 | macvlan interface (macvlan-conf-1) |
|
| macvlan1 | macvlan interface (macvlan-conf-1) |
|
||||||
| net2 | macvlan interface (macvlan-conf-2) |
|
| net2 | macvlan interface (macvlan-conf-2) |
|
||||||
|
|
||||||
|
## Specifying a default route for a specific attachment
|
||||||
|
|
||||||
|
Typically, the default route for a pod will route traffic over the `eth0` and therefore over the cluster-wide default network. You may wish to specify that a different network attachment will have the default route.
|
||||||
|
|
||||||
|
You can achieve this by using the JSON formatted annotation and specifying a `default-route` key.
|
||||||
|
|
||||||
|
*NOTE*: It's important that you consider that this may impact some functionality of getting traffic to route over the cluster-wide default network.
|
||||||
|
|
||||||
|
For example, we have a this configuration for macvlan:
|
||||||
|
|
||||||
|
```
|
||||||
|
cat <<EOF | kubectl create -f -
|
||||||
|
apiVersion: "k8s.cni.cncf.io/v1"
|
||||||
|
kind: NetworkAttachmentDefinition
|
||||||
|
metadata:
|
||||||
|
name: macvlan-conf
|
||||||
|
spec:
|
||||||
|
config: '{
|
||||||
|
"cniVersion": "0.3.0",
|
||||||
|
"type": "macvlan",
|
||||||
|
"master": "eth0",
|
||||||
|
"mode": "bridge",
|
||||||
|
"ipam": {
|
||||||
|
"type": "host-local",
|
||||||
|
"subnet": "192.168.2.0/24",
|
||||||
|
"rangeStart": "192.168.2.200",
|
||||||
|
"rangeEnd": "192.168.2.216",
|
||||||
|
"routes": [
|
||||||
|
{ "dst": "0.0.0.0/0" }
|
||||||
|
],
|
||||||
|
"gateway": "192.168.2.1"
|
||||||
|
}
|
||||||
|
}'
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
We can then create a pod which uses the `default-route` key in the JSON formatted `k8s.v1.cni.cncf.io/networks` annotation.
|
||||||
|
|
||||||
|
```
|
||||||
|
cat <<EOF | kubectl create -f -
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: samplepod
|
||||||
|
annotations:
|
||||||
|
k8s.v1.cni.cncf.io/networks: '[{
|
||||||
|
"name": "macvlan-conf",
|
||||||
|
"default-route": ["192.168.2.1"]
|
||||||
|
}]'
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: samplepod
|
||||||
|
command: ["/bin/bash", "-c", "trap : TERM INT; sleep infinity & wait"]
|
||||||
|
image: dougbtv/centos-network
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
This will set `192.168.2.1` as the default route over the `net1` interface, such as:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ kubectl exec -it samplepod -- ip route
|
||||||
|
default via 192.168.2.1 dev net1
|
||||||
|
10.244.0.0/24 dev eth0 proto kernel scope link src 10.244.0.169
|
||||||
|
10.244.0.0/16 via 10.244.0.1 dev eth0
|
||||||
|
```
|
||||||
|
|
||||||
## Entrypoint Parameters
|
## Entrypoint Parameters
|
||||||
|
|
||||||
Multus CNI, when installed using the daemonset-style installation uses an entrypoint script which copies the Multus binary into place, places CNI configurations. This entrypoint takes a variety of parameters for customization.
|
Multus CNI, when installed using the daemonset-style installation uses an entrypoint script which copies the Multus binary into place, places CNI configurations. This entrypoint takes a variety of parameters for customization.
|
||||||
|
@ -490,8 +490,24 @@ func TryLoadPodDelegates(k8sArgs *types.K8sArgs, conf *types.NetConf, kubeClient
|
|||||||
if err = conf.AddDelegates(delegates); err != nil {
|
if err = conf.AddDelegates(delegates); err != nil {
|
||||||
return 0, nil, err
|
return 0, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check gatewayRequest is configured in delegates
|
||||||
|
// and mark its config if gateway filter is required
|
||||||
|
isGatewayConfigured := false
|
||||||
|
for _, delegate := range conf.Delegates {
|
||||||
|
if delegate.GatewayRequest != nil {
|
||||||
|
isGatewayConfigured = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if isGatewayConfigured == true {
|
||||||
|
types.CheckGatewayConfig(conf.Delegates)
|
||||||
|
}
|
||||||
|
|
||||||
return len(delegates), clientInfo, nil
|
return len(delegates), clientInfo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0, clientInfo, nil
|
return 0, clientInfo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,6 +38,7 @@ import (
|
|||||||
"github.com/containernetworking/plugins/pkg/ns"
|
"github.com/containernetworking/plugins/pkg/ns"
|
||||||
k8s "github.com/intel/multus-cni/k8sclient"
|
k8s "github.com/intel/multus-cni/k8sclient"
|
||||||
"github.com/intel/multus-cni/logging"
|
"github.com/intel/multus-cni/logging"
|
||||||
|
"github.com/intel/multus-cni/netutils"
|
||||||
"github.com/intel/multus-cni/types"
|
"github.com/intel/multus-cni/types"
|
||||||
"github.com/vishvananda/netlink"
|
"github.com/vishvananda/netlink"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
@ -419,6 +420,14 @@ func cmdAdd(args *skel.CmdArgs, exec invoke.Exec, kubeClient k8s.KubeClient) (cn
|
|||||||
return nil, logging.Errorf("Multus: error adding pod to network %q: %v", netName, err)
|
return nil, logging.Errorf("Multus: error adding pod to network %q: %v", netName, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove gateway from routing table if the gateway is not used
|
||||||
|
if delegate.IsFilterGateway {
|
||||||
|
tmpResult, err = netutils.DeleteDefaultGW(args, ifName, &tmpResult)
|
||||||
|
if err != nil {
|
||||||
|
return nil, logging.Errorf("Multus: Err in deleting gateway: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Master plugin result is always used if present
|
// Master plugin result is always used if present
|
||||||
if delegate.MasterPlugin || result == nil {
|
if delegate.MasterPlugin || result == nil {
|
||||||
result = tmpResult
|
result = tmpResult
|
||||||
|
62
netutils/netutils.go
Normal file
62
netutils/netutils.go
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
// Copyright (c) 2019 Multus Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
package netutils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
|
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"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
netns, err := ns.GetNS(args.Netns)
|
||||||
|
if err != nil {
|
||||||
|
return nil, logging.Errorf("XXX: %v", err)
|
||||||
|
}
|
||||||
|
defer netns.Close()
|
||||||
|
|
||||||
|
err = netns.Do(func(_ ns.NetNS) error {
|
||||||
|
var err error
|
||||||
|
link, _ := netlink.LinkByName(ifName)
|
||||||
|
routes, _ := netlink.RouteList(link, netlink.FAMILY_ALL)
|
||||||
|
for _, nlroute := range routes {
|
||||||
|
if nlroute.Dst == nil {
|
||||||
|
err = netlink.RouteDel(&nlroute)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
var newRoutes []*cnitypes.Route
|
||||||
|
for _, route := range result.Routes {
|
||||||
|
if mask, _ := route.Dst.Mask.Size(); mask != 0 {
|
||||||
|
newRoutes = append(newRoutes, route)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.Routes = newRoutes
|
||||||
|
return result, err
|
||||||
|
}
|
@ -17,6 +17,7 @@ package types
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"net"
|
||||||
|
|
||||||
"github.com/containernetworking/cni/libcni"
|
"github.com/containernetworking/cni/libcni"
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
@ -111,6 +112,9 @@ func LoadDelegateNetConf(bytes []byte, net *NetworkSelectionElement, deviceID st
|
|||||||
if net.PortMappingsRequest != nil {
|
if net.PortMappingsRequest != nil {
|
||||||
delegateConf.PortMappingsRequest = net.PortMappingsRequest
|
delegateConf.PortMappingsRequest = net.PortMappingsRequest
|
||||||
}
|
}
|
||||||
|
if net.GatewayRequest != nil {
|
||||||
|
delegateConf.GatewayRequest = append(delegateConf.GatewayRequest, net.GatewayRequest...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delegateConf.Bytes = bytes
|
delegateConf.Bytes = bytes
|
||||||
@ -183,6 +187,18 @@ func CreateCNIRuntimeConf(args *skel.CmdArgs, k8sArgs *K8sArgs, ifName string, r
|
|||||||
return rt
|
return rt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetGatewayFromResult retrieves gateway IP addresses from CNI result
|
||||||
|
func GetGatewayFromResult(result *current.Result) []net.IP {
|
||||||
|
var gateways []net.IP
|
||||||
|
|
||||||
|
for _, route := range result.Routes {
|
||||||
|
if mask, _ := route.Dst.Mask.Size(); mask == 0 {
|
||||||
|
gateways = append(gateways, route.GW)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return gateways
|
||||||
|
}
|
||||||
|
|
||||||
// LoadNetworkStatus create network status from CNI result
|
// LoadNetworkStatus create network status from CNI result
|
||||||
func LoadNetworkStatus(r types.Result, netName string, defaultNet bool) (*NetworkStatus, error) {
|
func LoadNetworkStatus(r types.Result, netName string, defaultNet bool) (*NetworkStatus, error) {
|
||||||
logging.Debugf("LoadNetworkStatus: %v, %s, %t", r, netName, defaultNet)
|
logging.Debugf("LoadNetworkStatus: %v, %s, %t", r, netName, defaultNet)
|
||||||
@ -215,6 +231,7 @@ func LoadNetworkStatus(r types.Result, netName string, defaultNet bool) (*Networ
|
|||||||
}
|
}
|
||||||
|
|
||||||
netstatus.DNS = result.DNS
|
netstatus.DNS = result.DNS
|
||||||
|
netstatus.Gateway = GetGatewayFromResult(result)
|
||||||
|
|
||||||
return netstatus, nil
|
return netstatus, nil
|
||||||
|
|
||||||
@ -449,6 +466,17 @@ func addCNIArgsInConfList(inBytes []byte, cniArgs *map[string]interface{}) ([]by
|
|||||||
return configBytes, nil
|
return configBytes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CheckGatewayConfig check gatewayRequest and mark IsFilterGateway flag if
|
||||||
|
// gw filtering is required
|
||||||
|
func CheckGatewayConfig(delegates []*DelegateNetConf) {
|
||||||
|
// Check the Gateway
|
||||||
|
for i, delegate := range delegates {
|
||||||
|
if delegate.GatewayRequest == nil {
|
||||||
|
delegates[i].IsFilterGateway = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// CheckSystemNamespaces checks whether given namespace is in systemNamespaces or not.
|
// CheckSystemNamespaces checks whether given namespace is in systemNamespaces or not.
|
||||||
func CheckSystemNamespaces(namespace string, systemNamespaces []string) bool {
|
func CheckSystemNamespaces(namespace string, systemNamespaces []string) bool {
|
||||||
for _, nsname := range systemNamespaces {
|
for _, nsname := range systemNamespaces {
|
||||||
|
@ -88,6 +88,7 @@ type NetworkStatus struct {
|
|||||||
Mac string `json:"mac,omitempty"`
|
Mac string `json:"mac,omitempty"`
|
||||||
Default bool `json:"default,omitempty"`
|
Default bool `json:"default,omitempty"`
|
||||||
DNS types.DNS `json:"dns,omitempty"`
|
DNS types.DNS `json:"dns,omitempty"`
|
||||||
|
Gateway []net.IP `json:"default-route,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DelegateNetConf for net-attach-def for pod
|
// DelegateNetConf for net-attach-def for pod
|
||||||
@ -99,6 +100,8 @@ type DelegateNetConf struct {
|
|||||||
IPRequest []string `json:"ipRequest,omitempty"`
|
IPRequest []string `json:"ipRequest,omitempty"`
|
||||||
PortMappingsRequest []*PortMapEntry `json:"-"`
|
PortMappingsRequest []*PortMapEntry `json:"-"`
|
||||||
BandwidthRequest *BandwidthEntry `json:"-"`
|
BandwidthRequest *BandwidthEntry `json:"-"`
|
||||||
|
GatewayRequest []net.IP `json:"default-route,omitempty"`
|
||||||
|
IsFilterGateway bool
|
||||||
// MasterPlugin is only used internal housekeeping
|
// MasterPlugin is only used internal housekeeping
|
||||||
MasterPlugin bool `json:"-"`
|
MasterPlugin bool `json:"-"`
|
||||||
// Conflist plugin is only used internal housekeeping
|
// Conflist plugin is only used internal housekeeping
|
||||||
@ -137,6 +140,8 @@ type NetworkSelectionElement struct {
|
|||||||
BandwidthRequest *BandwidthEntry `json:"bandwidth,omitempty"`
|
BandwidthRequest *BandwidthEntry `json:"bandwidth,omitempty"`
|
||||||
// CNIArgs contains additional CNI arguments for the network interface
|
// CNIArgs contains additional CNI arguments for the network interface
|
||||||
CNIArgs *map[string]interface{} `json:"cni-args"`
|
CNIArgs *map[string]interface{} `json:"cni-args"`
|
||||||
|
// GatewayRequest contains default route IP address for the pod
|
||||||
|
GatewayRequest []net.IP `json:"default-route,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// K8sArgs is the valid CNI_ARGS used for Kubernetes
|
// K8sArgs is the valid CNI_ARGS used for Kubernetes
|
||||||
|
Loading…
Reference in New Issue
Block a user