"fmt"
"net"
"os/exec"
- "regexp"
+ "strconv"
"strings"
"github.com/sirupsen/logrus"
return nil
}
-func setupInterface(netns ns.NetNS, containerID, ifName, macAddress, ipAddress, gatewayIP, defaultGateway string, mtu int) (*current.Interface, *current.Interface, error) {
+func setupInterface(netns ns.NetNS, containerID, ifName, macAddress, ipAddress, gatewayIP, defaultGateway string, idx, mtu int) (*current.Interface, *current.Interface, error) {
hostIface := ¤t.Interface{}
contIface := ¤t.Interface{}
}
// rename the host end of veth pair
- re := regexp.MustCompile("(\\d+)\\D*\\z")
- index := re.FindAllString(ifName, -1)
- hostIface.Name = containerID[:14] + index[0]
+ hostIface.Name = containerID[:14] + strconv.Itoa(idx)
if err := renameLink(oldHostVethName, hostIface.Name); err != nil {
return nil, nil, fmt.Errorf("failed to rename %s to %s: %v", oldHostVethName, hostIface.Name, err)
}
}
// ConfigureInterface sets up the container interface
-var ConfigureInterface = func(args *skel.CmdArgs, namespace, podName, macAddress, ipAddress, gatewayIP, interfaceName, defaultGateway string, mtu int) ([]*current.Interface, error) {
+var ConfigureInterface = func(args *skel.CmdArgs, namespace, podName, macAddress, ipAddress, gatewayIP, interfaceName, defaultGateway string, idx, mtu int) ([]*current.Interface, error) {
netns, err := ns.GetNS(args.Netns)
if err != nil {
return nil, fmt.Errorf("failed to open netns %q: %v", args.Netns, err)
}
defer netns.Close()
- hostIface, contIface, err := setupInterface(netns, args.ContainerID, interfaceName, macAddress, ipAddress, gatewayIP, defaultGateway, mtu)
- if err != nil {
- return nil, err
- }
+
var ifaceID string
- if interfaceName != "" {
+ if interfaceName != "*" {
ifaceID = fmt.Sprintf("%s_%s_%s", namespace, podName, interfaceName)
} else {
ifaceID = fmt.Sprintf("%s_%s", namespace, podName)
+ interfaceName = args.IfName
+ defaultGateway = "true"
+ }
+ hostIface, contIface, err := setupInterface(netns, args.ContainerID, interfaceName, macAddress, ipAddress, gatewayIP, defaultGateway, idx, mtu)
+ if err != nil {
+ return nil, err
}
ovsArgs := []string{
logrus.Errorf("addMultipleInterfaces: interface can't be null")
return nil
}
- logrus.Debugf("addMultipleInterfaces: ipAddress %v %v", ipAddress, interfaceName)
- interfacesArray, err = app.ConfigureInterface(args, namespace, podName, macAddress, ipAddress, gatewayIP, interfaceName, defaultGateway, config.Default.MTU)
+ interfacesArray, err = app.ConfigureInterface(args, namespace, podName, macAddress, ipAddress, gatewayIP, interfaceName, defaultGateway, index, config.Default.MTU)
if err != nil {
logrus.Errorf("Failed to configure interface in pod: %v", err)
return nil
}
func main() {
- logrus.Infof("ovn4nfvk8s-cni CNI Invoked by Multus")
+ logrus.Infof("ovn4nfvk8s-cni invoked")
c := cli.NewApp()
c.Name = "ovn4nfvk8s-cni"
c.Usage = "a CNI plugin to set up or tear down a additional interfaces with OVN"
+++ /dev/null
-// +build linux
-
-package main
-
-import (
- "encoding/json"
-
- "github.com/containernetworking/cni/pkg/skel"
- "github.com/containernetworking/cni/pkg/types"
- "github.com/containernetworking/cni/pkg/types/current"
- "net"
- "ovn4nfv-k8s-plugin/cmd/ovn4nfvk8s-cni/app"
- "reflect"
- "testing"
-)
-
-func TestAddMultipleInterfaces(t *testing.T) {
- oldConfigureInterface := app.ConfigureInterface
- // as we are exiting, revert ConfigureInterface back at end of function
- defer func() { app.ConfigureInterface = oldConfigureInterface }()
- app.ConfigureInterface = func(args *skel.CmdArgs, namespace, podName, macAddress, ipAddress, gatewayIP, interfaceName, defaultGateway string, mtu int) ([]*current.Interface, error) {
- return []*current.Interface{
- {
- Name: "pod",
- Mac: "0a:00:00:00:00:0c",
- Sandbox: "102103104",
- }}, nil
- }
- oldConfigureRoute := app.ConfigureRoute
- defer func() { app.ConfigureRoute = oldConfigureRoute }()
- app.ConfigureRoute = func(args *skel.CmdArgs, dst, gw, dev string) error {
- return nil
- }
-
- args := &skel.CmdArgs{"102103104", "default", "eth0", "", "", nil}
- ovnAnnotation := "[{\"ip_address\":\"172.16.24.2/24\", \"mac_address\":\"0a:00:00:00:00:0c\", \"gateway_ip\": \"172.16.24.1\",\"interface\":\"net0\"}] "
- result := addMultipleInterfaces(args, ovnAnnotation, "default", "pod")
- if result == nil {
- t.Errorf("Failed addMultipleInterfaces %+v", ovnAnnotation)
- }
- resultSave := result
- ovnAnnotation = "[{\"ip_address\":\"172.16.24.2/24\", \"mac_address\":\"0a:00:00:00:00:0c\", \"gateway_ip\": \"172.16.24.1\",\"defaultGateway\":\"true\",\"interface\":\"net0\"}] "
- result = addMultipleInterfaces(args, ovnAnnotation, "default", "pod")
- if result == nil {
- t.Errorf("Failed addMultipleInterfaces %+v", ovnAnnotation)
- }
- ovnAnnotation = "[{\"ip_address\":\"172.16.24.2/24\", \"mac_address\":\"0a:00:00:00:00:0c\", \"gateway_ip\": \"172.16.24.1\"}] "
- result = addMultipleInterfaces(args, ovnAnnotation, "default", "pod")
- if result != nil {
- t.Errorf("Failed addMultipleInterfaces %+v", ovnAnnotation)
- }
- ovnAnnotation = "[{\"mac_address\":\"0a:00:00:00:00:0c\", \"gateway_ip\": \"172.16.24.1\",\"interface\":\"net0\"}] "
- result = addMultipleInterfaces(args, ovnAnnotation, "default", "pod")
- if result != nil {
- t.Errorf("Failed addMultipleInterfaces %+v", ovnAnnotation)
- }
- ovnAnnotation = "[{\"ip_address\":\"172.16.24.2/24\", \"mac_address\":\"0a:00:00:00:00:0c\", \"gateway_ip\": \"172.16.24.1\",\"interface\":\"net0\"}, {\"ip_address\":\"172.16.25.2/24\", \"mac_address\":\"0a:00:00:00:00:0d\", \"gateway_ip\": \"172.16.25.1\",\"interface\":\"net1\"}]"
- result = addMultipleInterfaces(args, ovnAnnotation, "default", "pod")
- if result == nil {
- t.Errorf("Failed addMultipleInterfaces %+v", ovnAnnotation)
- }
- ovnAnnotation = "[{\"ip_address\":\"172.16.24.2/24\", \"mac_address\":\"0a:00:00:00:00:0c\", \"gateway_ip\": \"172.16.24.1\",\"interface\":\"net0\", \"defaultGateway\":\"true\"}, {\"ip_address\":\"172.16.25.2/24\", \"mac_address\":\"0a:00:00:00:00:0d\", \"gateway_ip\": \"172.16.25.1\",\"interface\":\"net1\"}]"
- result = addMultipleInterfaces(args, ovnAnnotation, "default", "pod")
- if result == nil {
- t.Errorf("Failed addMultipleInterfaces %+v", ovnAnnotation)
- }
- // Test add route feature
- ovnRoutesAnnotation := "[{ \"dst\": \"172.16.29.0/24\", \"gw\": \"172.16.24.1\", \"dev\": \"eth0\" }]"
- result = addRoutes(args, ovnRoutesAnnotation, resultSave)
- if result == nil {
- t.Errorf("Failed addRoutes %+v", ovnRoutesAnnotation)
- }
-
- ovnRoutesAnnotation = "[{ \"dst\": \"172.16.30.0/24\", \"gw\": \"172.16.25.1\", \"dev\": \"eth0\"}, { \"dst\": \"172.16.31.0/24\", \"gw\": \"172.16.26.1\", \"dev\": \"eth1\" }]"
- result = addRoutes(args, ovnRoutesAnnotation, resultSave)
- if result == nil {
- t.Errorf("Failed addRoutes %+v", ovnRoutesAnnotation)
- }
- newResult, err := current.NewResultFromResult(result)
- if err != nil {
- t.Errorf("Failed addMultipleInterfaces %+v", newResult)
- }
- addr1, addrNet1, _ := net.ParseCIDR("172.16.24.2/24")
- addr2, addrNet2, _ := net.ParseCIDR("172.16.29.0/24")
- addr3, addrNet3, _ := net.ParseCIDR("172.16.30.0/24")
- addr4, addrNet4, _ := net.ParseCIDR("172.16.31.0/24")
- expectedResult := ¤t.Result{
- CNIVersion: "0.3.1",
- Interfaces: []*current.Interface{
- {
- Name: "pod",
- Mac: "0a:00:00:00:00:0c",
- Sandbox: "102103104",
- },
- },
- IPs: []*current.IPConfig{
- {
- Version: "4",
- Interface: current.Int(1),
- Address: net.IPNet{IP: addr1, Mask: addrNet1.Mask},
- Gateway: net.ParseIP("172.16.24.1"),
- },
- },
- Routes: []*types.Route{
- {
- Dst: net.IPNet{IP: addr2, Mask: addrNet2.Mask},
- GW: net.ParseIP("172.16.24.1"),
- },
- {
- Dst: net.IPNet{IP: addr3, Mask: addrNet3.Mask},
- GW: net.ParseIP("172.16.25.1"),
- },
- {
- Dst: net.IPNet{IP: addr4, Mask: addrNet4.Mask},
- GW: net.ParseIP("172.16.26.1"),
- },
- },
- DNS: types.DNS{},
- }
- jsonBytes1, err := json.Marshal(newResult.Routes)
- jsonBytes2, err := json.Marshal(expectedResult.Routes)
- if !reflect.DeepEqual(jsonBytes1, jsonBytes2) {
- t.Errorf("Routes are not correct")
- }
-
-}
--- /dev/null
+
+---
+
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+ name: networks.k8s.plugin.opnfv.org
+spec:
+ group: k8s.plugin.opnfv.org
+ names:
+ kind: Network
+ listKind: NetworkList
+ plural: networks
+ singular: network
+ scope: Namespaced
+ subresources:
+ status: {}
+ validation:
+ openAPIV3Schema:
+ properties:
+ apiVersion:
+ description: 'APIVersion defines the versioned schema of this representation
+ of an object. Servers should convert recognized schemas to the latest
+ internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources'
+ type: string
+ kind:
+ description: 'Kind is a string value representing the REST resource this
+ object represents. Servers may infer this from the endpoint the client
+ submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds'
+ type: string
+ metadata:
+ type: object
+ spec:
+ properties:
+ cniType:
+ description: 'INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
+ Important: Run "operator-sdk generate k8s" to regenerate code after
+ modifying this file Add custom validation using kubebuilder tags:
+ https://book-v1.book.kubebuilder.io/beyond_basics/generating_crd.html'
+ type: string
+ dns:
+ properties:
+ domain:
+ type: string
+ nameservers:
+ items:
+ type: string
+ type: array
+ options:
+ items:
+ type: string
+ type: array
+ search:
+ items:
+ type: string
+ type: array
+ type: object
+ ipv4Subnets:
+ items:
+ properties:
+ excludeIps:
+ type: string
+ gateway:
+ type: string
+ name:
+ type: string
+ subnet:
+ type: string
+ required:
+ - name
+ - subnet
+ type: object
+ type: array
+ ipv6Subnets:
+ items:
+ properties:
+ excludeIps:
+ type: string
+ gateway:
+ type: string
+ name:
+ type: string
+ subnet:
+ type: string
+ required:
+ - name
+ - subnet
+ type: object
+ type: array
+ routes:
+ items:
+ properties:
+ dst:
+ type: string
+ gw:
+ type: string
+ required:
+ - dst
+ type: object
+ type: array
+ required:
+ - cniType
+ - ipv4Subnets
+ type: object
+ status:
+ properties:
+ state:
+ description: 'INSERT ADDITIONAL STATUS FIELD - define observed state
+ of cluster Important: Run "operator-sdk generate k8s" to regenerate
+ code after modifying this file Add custom validation using kubebuilder
+ tags: https://book-v1.book.kubebuilder.io/beyond_basics/generating_crd.html'
+ type: string
+ required:
+ - state
+ type: object
+ version: v1alpha1
+ versions:
+ - name: v1alpha1
+ served: true
+ storage: true
+
+
+---
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+ name: providernetworks.k8s.plugin.opnfv.org
+spec:
+ group: k8s.plugin.opnfv.org
+ names:
+ kind: ProviderNetwork
+ listKind: ProviderNetworkList
+ plural: providernetworks
+ singular: providernetwork
+ scope: Namespaced
+ subresources:
+ status: {}
+ validation:
+ openAPIV3Schema:
+ description: ProviderNetwork is the Schema for the providernetworks API
+ properties:
+ apiVersion:
+ description: 'APIVersion defines the versioned schema of this representation
+ of an object. Servers should convert recognized schemas to the latest
+ internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+ type: string
+ kind:
+ description: 'Kind is a string value representing the REST resource this
+ object represents. Servers may infer this from the endpoint the client
+ submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+ type: string
+ metadata:
+ type: object
+ spec:
+ description: ProviderNetworkSpec defines the desired state of ProviderNetwork
+ properties:
+ cniType:
+ description: 'INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
+ Important: Run "operator-sdk generate k8s" to regenerate code after
+ modifying this file Add custom validation using kubebuilder tags:
+ https://book-v1.book.kubebuilder.io/beyond_basics/generating_crd.html'
+ type: string
+ direct:
+ properties:
+ directNodeSelector:
+ type: string
+ nodeLabelList:
+ items:
+ type: string
+ type: array
+ providerInterfaceName:
+ type: string
+ required:
+ - directNodeSelector
+ - providerInterfaceName
+ type: object
+ dns:
+ properties:
+ domain:
+ type: string
+ nameservers:
+ items:
+ type: string
+ type: array
+ options:
+ items:
+ type: string
+ type: array
+ search:
+ items:
+ type: string
+ type: array
+ type: object
+ ipv4Subnets:
+ items:
+ properties:
+ excludeIps:
+ type: string
+ gateway:
+ type: string
+ name:
+ type: string
+ subnet:
+ type: string
+ required:
+ - name
+ - subnet
+ type: object
+ type: array
+ ipv6Subnets:
+ items:
+ properties:
+ excludeIps:
+ type: string
+ gateway:
+ type: string
+ name:
+ type: string
+ subnet:
+ type: string
+ required:
+ - name
+ - subnet
+ type: object
+ type: array
+ providerNetType:
+ type: string
+ routes:
+ items:
+ properties:
+ dst:
+ type: string
+ gw:
+ type: string
+ required:
+ - dst
+ type: object
+ type: array
+ vlan:
+ properties:
+ logicalInterfaceName:
+ type: string
+ nodeLabelList:
+ items:
+ type: string
+ type: array
+ providerInterfaceName:
+ type: string
+ vlanId:
+ type: string
+ vlanNodeSelector:
+ type: string
+ required:
+ - providerInterfaceName
+ - vlanId
+ - vlanNodeSelector
+ type: object
+ required:
+ - cniType
+ - ipv4Subnets
+ - providerNetType
+ type: object
+ status:
+ description: ProviderNetworkStatus defines the observed state of ProviderNetwork
+ properties:
+ state:
+ description: 'INSERT ADDITIONAL STATUS FIELD - define observed state
+ of cluster Important: Run "operator-sdk generate k8s" to regenerate
+ code after modifying this file Add custom validation using kubebuilder
+ tags: https://book-v1.book.kubebuilder.io/beyond_basics/generating_crd.html'
+ type: string
+ required:
+ - state
+ type: object
+ type: object
+ version: v1alpha1
+ versions:
+ - name: v1alpha1
+ served: true
+ storage: true
+---
+
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: k8s-nfn-sa
+ namespace: operator
+
+---
+
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+ creationTimestamp: null
+ name: k8s-nfn-cr
+rules:
+- apiGroups:
+ - ""
+ resources:
+ - pods
+ - services
+ - endpoints
+ - persistentvolumeclaims
+ - events
+ - configmaps
+ - secrets
+ - nodes
+ verbs:
+ - '*'
+- apiGroups:
+ - apps
+ resources:
+ - deployments
+ - daemonsets
+ - replicasets
+ - statefulsets
+ verbs:
+ - '*'
+- apiGroups:
+ - monitoring.coreos.com
+ resources:
+ - servicemonitors
+ verbs:
+ - get
+ - create
+- apiGroups:
+ - apps
+ resourceNames:
+ - nfn-operator
+ resources:
+ - deployments/finalizers
+ verbs:
+ - update
+- apiGroups:
+ - k8s.plugin.opnfv.org
+ resources:
+ - '*'
+ - providernetworks
+ verbs:
+ - '*'
+
+---
+
+kind: ClusterRoleBinding
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+ name: k8s-nfn-crb
+subjects:
+- kind: Group
+ name: system:serviceaccounts
+ apiGroup: rbac.authorization.k8s.io
+roleRef:
+ kind: ClusterRole
+ name: k8s-nfn-cr
+ apiGroup: rbac.authorization.k8s.io
+
+
+---
+
+apiVersion: v1
+kind: Service
+metadata:
+ name: nfn-operator
+ namespace: operator
+spec:
+ type: NodePort
+ ports:
+ - port: 50000
+ protocol: TCP
+ targetPort: 50000
+ selector:
+ name: nfn-operator
+
+
+---
+
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: ovn-controller-network
+ namespace: operator
+data:
+ OVN_SUBNET: "10.244.64.0/18"
+ OVN_GATEWAYIP: "10.244.64.20/18"
+ OVN_EXCLUDEIPS: "10.244.64.0..10.244.64.16"
+
+
+---
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: nfn-operator
+ namespace: operator
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ name: nfn-operator
+ template:
+ metadata:
+ labels:
+ name: nfn-operator
+ spec:
+ hostNetwork: true
+ affinity:
+ nodeAffinity:
+ requiredDuringSchedulingIgnoredDuringExecution:
+ nodeSelectorTerms:
+ - matchExpressions:
+ - key: nfnType
+ operator: In
+ values:
+ - operator
+ tolerations:
+ - key: "node-role.kubernetes.io/master"
+ effect: "NoSchedule"
+ operator: "Exists"
+ serviceAccountName: k8s-nfn-sa
+ containers:
+ - name: nfn-operator
+ image: integratedcloudnative/ovn4nfv-k8s-plugin:master
+ command: ["/usr/local/bin/entrypoint", "operator"]
+ imagePullPolicy: IfNotPresent
+ envFrom:
+ - configMapRef:
+ name: ovn-controller-network
+ ports:
+ - containerPort: 50000
+ protocol: TCP
+ env:
+ - name: HOST_IP
+ valueFrom:
+ fieldRef:
+ fieldPath: status.hostIP
+ - name: POD_NAME
+ valueFrom:
+ fieldRef:
+ fieldPath: metadata.name
+ - name: OPERATOR_NAME
+ value: "nfn-operator"
+
+---
+kind: ConfigMap
+apiVersion: v1
+metadata:
+ name: ovn4nfv-cni-config
+ namespace: operator
+ labels:
+ app: ovn4nfv
+data:
+ ovn4nfv_k8s.conf: |
+ [logging]
+ loglevel=5
+ logfile=/var/log/openvswitch/ovn4k8s.log
+
+ [cni]
+ conf-dir=/etc/cni/net.d
+ plugin=ovn4nfvk8s-cni
+
+ [kubernetes]
+ kubeconfig=/etc/kubernetes/admin.conf
+
+---
+apiVersion: extensions/v1beta1
+kind: DaemonSet
+metadata:
+ name: ovn4nfv-cni
+ namespace: operator
+ labels:
+ app: ovn4nfv
+spec:
+ updateStrategy:
+ type: RollingUpdate
+ template:
+ metadata:
+ labels:
+ app: ovn4nfv
+ spec:
+ hostNetwork: true
+ nodeSelector:
+ beta.kubernetes.io/arch: amd64
+ tolerations:
+ - operator: Exists
+ effect: NoSchedule
+ containers:
+ - name: ovn4nfv
+ image: integratedcloudnative/ovn4nfv-k8s-plugin:master
+ command: ["/usr/local/bin/entrypoint", "cni"]
+ resources:
+ requests:
+ cpu: "100m"
+ memory: "50Mi"
+ limits:
+ cpu: "100m"
+ memory: "50Mi"
+ securityContext:
+ privileged: true
+ volumeMounts:
+ - name: cnibin
+ mountPath: /host/opt/cni/bin
+ - name: cniconf
+ mountPath: /host/etc/openvswitch
+ - name: ovn4nfv-cfg
+ mountPath: /tmp/ovn4nfv-conf
+ volumes:
+ - name: cnibin
+ hostPath:
+ path: /opt/cni/bin
+ - name: cniconf
+ hostPath:
+ path: /etc/openvswitch
+ - name: ovn4nfv-cfg
+ configMap:
+ name: ovn4nfv-cni-config
+ items:
+ - key: ovn4nfv_k8s.conf
+ path: ovn4nfv_k8s.conf
+
+---
+apiVersion: extensions/v1beta1
+kind: DaemonSet
+metadata:
+ name: nfn-agent
+ namespace: operator
+ labels:
+ app: nfn-agent
+spec:
+ updateStrategy:
+ type: RollingUpdate
+ template:
+ metadata:
+ labels:
+ app: nfn-agent
+ spec:
+ hostNetwork: true
+ nodeSelector:
+ beta.kubernetes.io/arch: amd64
+ tolerations:
+ - operator: Exists
+ effect: NoSchedule
+ containers:
+ - name: nfn-agent
+ image: integratedcloudnative/ovn4nfv-k8s-plugin:master
+ command: ["/usr/local/bin/entrypoint", "agent"]
+ resources:
+ requests:
+ cpu: "100m"
+ memory: "50Mi"
+ limits:
+ cpu: "100m"
+ memory: "50Mi"
+ env:
+ - name: NFN_NODE_NAME
+ valueFrom:
+ fieldRef:
+ fieldPath: spec.nodeName
+ securityContext:
+ privileged: true
+ volumeMounts:
+ - mountPath: /run/openvswitch
+ name: host-run-ovs
+ - mountPath: /var/run/openvswitch
+ name: host-var-run-ovs
+ volumes:
+ - name: host-run-ovs
+ hostPath:
+ path: /run/openvswitch
+ - name: host-var-run-ovs
+ hostPath:
+ path: /var/run/openvswitch
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-gomodules.xyz/jsonpatch/v2 v2.0.0 h1:OyHbl+7IOECpPKfVK42oFr6N7+Y2dR+Jsb/IiDV3hOo=
+gomodules.xyz/jsonpatch/v2 v2.0.0 h1:lHNQverf0+Gm1TbSbVIDWVXOhZ2FpZopxRqpr2uIjs4=
gomodules.xyz/jsonpatch/v2 v2.0.0/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU=
gomodules.xyz/jsonpatch/v2 v2.0.1 h1:xyiBuvkD2g5n7cYzx6u2sxQvsAy4QJsZFCzGVdzOXZ0=
gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU=
return nil
}
+// CreateNetwork in OVN controller
+func createOvnLS(name, subnet, gatewayIP, excludeIps string) (gatewayIPMask string, err error) {
+ var stdout, stderr string
+
+ output, stderr, err := RunOVNNbctl("--data=bare", "--no-heading",
+ "--columns=name", "find", "logical_switch", "name="+name)
+ if err != nil {
+ log.Error(err, "Error in reading logical switch", "stderr", stderr)
+ return
+ }
+
+ if strings.Compare(name, output) == 0 {
+ log.V(1).Info("Logical Switch already exists, delete first to update/recreate", "name", name)
+ return "", fmt.Errorf("LS exists")
+ }
+
+ _, cidr, err := net.ParseCIDR(subnet)
+ if err != nil {
+ log.Error(err, "ovnNetwork '%s' invalid subnet CIDR", "name", name)
+ return
+
+ }
+ firstIP := NextIP(cidr.IP)
+ n, _ := cidr.Mask.Size()
+
+ var gwIP net.IP
+ if gatewayIP != "" {
+ gwIP, _, err = net.ParseCIDR(gatewayIP)
+ if err != nil {
+ // Check if this is a valid IP address
+ gwIP = net.ParseIP(gatewayIP)
+ }
+ }
+ // If no valid Gateway use the first IP address for GatewayIP
+ if gwIP == nil {
+ gatewayIPMask = fmt.Sprintf("%s/%d", firstIP.String(), n)
+ } else {
+ gatewayIPMask = fmt.Sprintf("%s/%d", gwIP.String(), n)
+ }
+
+ // Create a logical switch and set its subnet.
+ if excludeIps != "" {
+ stdout, stderr, err = RunOVNNbctl("--wait=hv", "--", "--may-exist", "ls-add", name, "--", "set", "logical_switch", name, "other-config:subnet="+subnet, "external-ids:gateway_ip="+gatewayIPMask, "other-config:exclude_ips="+excludeIps)
+ } else {
+ stdout, stderr, err = RunOVNNbctl("--wait=hv", "--", "--may-exist", "ls-add", name, "--", "set", "logical_switch", name, "other-config:subnet="+subnet, "external-ids:gateway_ip="+gatewayIPMask)
+ }
+ if err != nil {
+ log.Error(err, "Failed to create a logical switch", "name", name, "stdout", stdout, "stderr", stderr)
+ return
+ }
+ return
+}
+
// generateMac generates mac address.
func generateMac() string {
prefix := "00:00:00"
kapi "k8s.io/api/core/v1"
kexec "k8s.io/utils/exec"
"math/rand"
- "net"
+ "os"
k8sv1alpha1 "ovn4nfv-k8s-plugin/pkg/apis/k8s/v1alpha1"
"strings"
"time"
gatewayCache map[string]string
}
+type OVNNetworkConf struct {
+ Subnet string
+ GatewayIP string
+ ExcludeIPs string
+}
+
const (
ovn4nfvRouterName = "ovn4nfv-master"
// Ovn4nfvAnnotationTag tag on already processed Pods
Ovn4nfvAnnotationTag = "k8s.plugin.opnfv.org/ovnInterfaces"
+ // OVN Default Network name
+ Ovn4nfvDefaultNw = "ovn4nfvk8s-default-nw"
)
+var ovnConf *OVNNetworkConf
+
+func GetOvnNetConf() error {
+ ovnConf = &OVNNetworkConf{}
+
+ ovnConf.Subnet = os.Getenv("OVN_SUBNET")
+ if ovnConf.Subnet == "" {
+ fmt.Errorf("OVN subnet is not set in nfn-operator configmap env")
+ }
+
+ ovnConf.GatewayIP = os.Getenv("OVN_GATEWAYIP")
+ if ovnConf.GatewayIP == "" {
+ fmt.Errorf("OVN gatewayIP is not set in nfn-operator configmap env")
+ }
+
+ ovnConf.ExcludeIPs = os.Getenv("OVN_EXCLUDEIPS")
+ if ovnConf.ExcludeIPs == "" {
+ fmt.Errorf("OVN excludeIPs is not set in nfn-operator configmap env")
+ }
+
+ return nil
+}
+
type netInterface struct {
Name string
Interface string
log.Error(err, "Failed to initialize exec helper")
return nil, err
}
+
+ if err := GetOvnNetConf(); err != nil {
+ log.Error(err, "nfn-operator OVN Network configmap is not set")
+ return nil, err
+ }
if err := SetupOvnUtils(); err != nil {
log.Error(err, "Failed to initialize OVN State")
return nil, err
}
+
ovnCtl = &Controller{
gatewayCache: make(map[string]string),
}
// AddLogicalPorts adds ports to the Pod
func (oc *Controller) AddLogicalPorts(pod *kapi.Pod, ovnNetObjs []map[string]interface{}) (key, value string) {
- if ovnNetObjs == nil {
- return
- }
-
if pod.Spec.HostNetwork {
return
}
}
var ovnString, outStr string
+ var defaultInterface bool
+
ovnString = "["
var ns netInterface
for _, net := range ovnNetObjs {
-
err := mapstructure.Decode(net, &ns)
if err != nil {
log.Error(err, "mapstruct error", "network", net)
return
}
-
if !oc.FindLogicalSwitch(ns.Name) {
log.Info("Logical Switch not found")
return
}
- if ns.Interface == "" {
+ if ns.Name == Ovn4nfvDefaultNw {
+ defaultInterface = true
+ }
+ if ns.Interface == "" && ns.Name != Ovn4nfvDefaultNw {
log.Info("Interface name must be provided")
return
}
if ns.DefaultGateway == "" {
ns.DefaultGateway = "false"
}
- outStr = oc.addLogicalPortWithSwitch(pod, ns.Name, ns.IPAddress, ns.MacAddress, ns.Interface, ns.NetType)
+ var portName string
+ if ns.Interface != "" {
+ portName = fmt.Sprintf("%s_%s_%s", pod.Namespace, pod.Name, ns.Interface)
+ } else {
+ portName = fmt.Sprintf("%s_%s", pod.Namespace, pod.Name)
+ ns.Interface = "*"
+ }
+ outStr = oc.addLogicalPortWithSwitch(pod, ns.Name, ns.IPAddress, ns.MacAddress, portName)
if outStr == "" {
return
}
ovnString += tmpString
ovnString += ","
}
- last := len(ovnString) - 1
+ var last int
+ if defaultInterface == false {
+ // Add Default interface
+ portName := fmt.Sprintf("%s_%s", pod.Namespace, pod.Name)
+ outStr = oc.addLogicalPortWithSwitch(pod, Ovn4nfvDefaultNw, "", "", portName)
+ if outStr == "" {
+ return
+ }
+ last := len(outStr) - 1
+ tmpString := outStr[:last]
+ tmpString += "," + "\\\"interface\\\":" + "\\\"" + "*" + "\\\"}"
+ ovnString += tmpString
+ ovnString += ","
+ }
+ last = len(ovnString) - 1
ovnString = ovnString[:last]
ovnString += "]"
key = Ovn4nfvAnnotationTag
// DeleteLogicalPorts deletes the OVN ports for the pod
func (oc *Controller) DeleteLogicalPorts(name, namespace string) {
+ log.Info("DeleteLogicalPorts")
logicalPort := fmt.Sprintf("%s_%s", namespace, name)
// get the list of logical ports from OVN
for _, existingPort := range existingLogicalPorts {
if strings.Contains(existingPort, logicalPort) {
// found, delete this logical port
- log.V(1).Info("Deleting", "Port", existingPort)
+ log.Info("Deleting", "Port", existingPort)
stdout, stderr, err := RunOVNNbctl("--if-exists", "lsp-del",
existingPort)
if err != nil {
return
}
-// CreateNetwork in OVN controller
-func (oc *Controller) createOvnLS(name, subnet, gatewayIP, excludeIps string) (gatewayIPMask string, err error) {
- var stdout, stderr string
-
- output, stderr, err := RunOVNNbctl("--data=bare", "--no-heading",
- "--columns=name", "find", "logical_switch", "name="+name)
- if err != nil {
- log.Error(err, "Error in reading logical switch", "stderr", stderr)
- return
- }
-
- if strings.Compare(name, output) == 0 {
- log.V(1).Info("Logical Switch already exists, delete first to update/recreate", "name", name)
- return "", fmt.Errorf("LS exists")
- }
-
- _, cidr, err := net.ParseCIDR(subnet)
- if err != nil {
- log.Error(err, "ovnNetwork '%s' invalid subnet CIDR", "name", name)
- return
-
- }
- firstIP := NextIP(cidr.IP)
- n, _ := cidr.Mask.Size()
-
- var gwIP net.IP
- if gatewayIP != "" {
- gwIP, _, err = net.ParseCIDR(gatewayIP)
- if err != nil {
- // Check if this is a valid IP address
- gwIP = net.ParseIP(gatewayIP)
- }
- }
- // If no valid Gateway use the first IP address for GatewayIP
- if gwIP == nil {
- gatewayIPMask = fmt.Sprintf("%s/%d", firstIP.String(), n)
- } else {
- gatewayIPMask = fmt.Sprintf("%s/%d", gwIP.String(), n)
- }
-
- // Create a logical switch and set its subnet.
- if excludeIps != "" {
- stdout, stderr, err = RunOVNNbctl("--wait=hv", "--", "--may-exist", "ls-add", name, "--", "set", "logical_switch", name, "other-config:subnet="+subnet, "external-ids:gateway_ip="+gatewayIPMask, "other-config:exclude_ips="+excludeIps)
- } else {
- stdout, stderr, err = RunOVNNbctl("--wait=hv", "--", "--may-exist", "ls-add", name, "--", "set", "logical_switch", name, "other-config:subnet="+subnet, "external-ids:gateway_ip="+gatewayIPMask)
- }
- if err != nil {
- log.Error(err, "Failed to create a logical switch", "name", name, "stdout", stdout, "stderr", stderr)
- return
- }
- return
-}
-
// CreateNetwork in OVN controller
func (oc *Controller) CreateNetwork(cr *k8sv1alpha1.Network) error {
var stdout, stderr string
gatewayIP := cr.Spec.Ipv4Subnets[0].Gateway
excludeIps := cr.Spec.Ipv4Subnets[0].ExcludeIps
- gatewayIPMask, err := oc.createOvnLS(name, subnet, gatewayIP, excludeIps)
+ gatewayIPMask, err := createOvnLS(name, subnet, gatewayIP, excludeIps)
if err != nil {
return err
}
subnet := cr.Spec.Ipv4Subnets[0].Subnet
gatewayIP := cr.Spec.Ipv4Subnets[0].Gateway
excludeIps := cr.Spec.Ipv4Subnets[0].ExcludeIps
- _, err := oc.createOvnLS(name, subnet, gatewayIP, excludeIps)
+ _, err := createOvnLS(name, subnet, gatewayIP, excludeIps)
if err != nil {
return err
}
return gatewayIP, mask, nil
}
-func (oc *Controller) addLogicalPortWithSwitch(pod *kapi.Pod, logicalSwitch, ipAddress, macAddress, interfaceName, netType string) (annotation string) {
+func (oc *Controller) addLogicalPortWithSwitch(pod *kapi.Pod, logicalSwitch, ipAddress, macAddress, portName string) (annotation string) {
var out, stderr string
var err error
var isStaticIP bool
return
}
- var portName string
- if interfaceName != "" {
- portName = fmt.Sprintf("%s_%s_%s", pod.Namespace, pod.Name, interfaceName)
- } else {
- return
- }
-
log.V(1).Info("Creating logical port for on switch", "portName", portName, "logicalSwitch", logicalSwitch)
if ipAddress != "" && macAddress != "" {
+++ /dev/null
-package ovn
-
-import (
- "fmt"
- "testing"
-
- "github.com/urfave/cli"
- fakeexec "k8s.io/utils/exec/testing"
-
- "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "ovn4nfv-k8s-plugin/internal/pkg/config"
- ovntest "ovn4nfv-k8s-plugin/internal/pkg/testing"
-
- . "github.com/onsi/ginkgo"
- . "github.com/onsi/gomega"
-)
-
-func TestOvn(t *testing.T) {
- RegisterFailHandler(Fail)
- RunSpecs(t, "OVN/Pod Test Suite")
-}
-
-var _ = AfterSuite(func() {
-})
-
-var _ = Describe("Add logical Port", func() {
- var app *cli.App
-
- BeforeEach(func() {
- app = cli.NewApp()
- app.Name = "test"
- app.Flags = config.Flags
-
- })
-
- It("tests Pod", func() {
- app.Action = func(ctx *cli.Context) error {
- const (
- gwIP string = "10.1.1.1"
- gwCIDR string = gwIP + "/24"
- netName string = "ovn-prot-net"
- portName string = "_ok_net0"
- macIPAddress string = "0a:00:00:00:00:01 192.168.1.3"
- )
- fakeCmds := ovntest.AddFakeCmd(nil, &ovntest.ExpectedCmd{
- Cmd: "ovn-nbctl --timeout=15 --data=bare --no-heading --columns=name find logical_switch " + "name=" + netName,
- Output: netName,
- })
- fakeCmds = ovntest.AddFakeCmdsNoOutputNoError(fakeCmds, []string{
- "ovn-nbctl --timeout=15 --wait=sb -- --may-exist lsp-add " + netName + " " + portName + " -- lsp-set-addresses " + portName + " dynamic -- set logical_switch_port " + portName + " external-ids:namespace= external-ids:logical_switch=" + netName + " external-ids:pod=true",
- })
-
- fakeCmds = ovntest.AddFakeCmd(fakeCmds, &ovntest.ExpectedCmd{
- Cmd: "ovn-nbctl --timeout=15 get logical_switch_port " + portName + " dynamic_addresses",
- Output: macIPAddress,
- })
- fakeCmds = ovntest.AddFakeCmd(fakeCmds, &ovntest.ExpectedCmd{
- Cmd: "ovn-nbctl --timeout=15 --if-exists get logical_switch " + netName + " external_ids:gateway_ip",
- Output: gwCIDR,
- })
-
- fexec := &fakeexec.FakeExec{
- CommandScript: fakeCmds,
- LookPathFunc: func(file string) (string, error) {
- return fmt.Sprintf("/fake-bin/%s", file), nil
- },
- }
- oldSetupOvnUtils := SetupOvnUtils
- // as we are exiting, revert ConfigureInterface back at end of function
- defer func() { SetupOvnUtils = oldSetupOvnUtils }()
- SetupOvnUtils = func() error {
- return nil
- }
- ovnController, err := NewOvnController(fexec)
- Expect(err).NotTo(HaveOccurred())
-
- var (
- okPod = v1.Pod{
- TypeMeta: metav1.TypeMeta{
- Kind: "Pod",
- APIVersion: "v1",
- },
- ObjectMeta: metav1.ObjectMeta{
- Name: "ok",
- },
- Spec: v1.PodSpec{
- Containers: []v1.Container{
- {
- Name: "by-name",
- },
- {},
- },
- },
- }
- )
- a := []map[string]interface{}{{"name": "ovn-prot-net", "interface": "net0"}}
- ovnController.AddLogicalPorts(&okPod, a)
- Expect(fexec.CommandCalls).To(Equal(len(fakeCmds)))
-
- return nil
- }
-
- err := app.Run([]string{app.Name})
- Expect(err).NotTo(HaveOccurred())
- })
-
- It("tests Pod provider", func() {
- app.Action = func(ctx *cli.Context) error {
- const (
- gwIP string = "10.1.1.1"
- gwCIDR string = gwIP + "/24"
- netName string = "ovn-prot-net"
- portName string = "_ok_net0"
- macIPAddress string = "0a:00:00:00:00:01 192.168.1.3/24"
- )
- fakeCmds := ovntest.AddFakeCmd(nil, &ovntest.ExpectedCmd{
- Cmd: "ovn-nbctl --timeout=15 --data=bare --no-heading --columns=name find logical_switch " + "name=" + netName,
- Output: netName,
- })
-
- fakeCmds = ovntest.AddFakeCmdsNoOutputNoError(fakeCmds, []string{
- "ovn-nbctl --timeout=15 --may-exist lsp-add " + netName + " " + portName + " -- lsp-set-addresses " + portName + " " + macIPAddress + " -- --if-exists clear logical_switch_port " + portName + " dynamic_addresses" + " -- set logical_switch_port " + portName + " external-ids:namespace= external-ids:logical_switch=" + netName + " external-ids:pod=true",
- })
-
- fakeCmds = ovntest.AddFakeCmd(fakeCmds, &ovntest.ExpectedCmd{
- Cmd: "ovn-nbctl --timeout=15 get logical_switch_port " + portName + " addresses",
- Output: macIPAddress,
- })
-
- fakeCmds = ovntest.AddFakeCmd(fakeCmds, &ovntest.ExpectedCmd{
- Cmd: "ovn-nbctl --timeout=15 --if-exists get logical_switch " + netName + " external_ids:gateway_ip",
- Output: gwCIDR,
- })
-
- fexec := &fakeexec.FakeExec{
- CommandScript: fakeCmds,
- LookPathFunc: func(file string) (string, error) {
- return fmt.Sprintf("/fake-bin/%s", file), nil
- },
- }
- oldSetupOvnUtils := SetupOvnUtils
- // as we are exiting, revert ConfigureInterface back at end of function
- defer func() { SetupOvnUtils = oldSetupOvnUtils }()
- SetupOvnUtils = func() error {
- return nil
- }
- ovnController, err := NewOvnController(fexec)
- Expect(err).NotTo(HaveOccurred())
- var (
- okPod = v1.Pod{
- TypeMeta: metav1.TypeMeta{
- Kind: "Pod",
- APIVersion: "v1",
- },
- ObjectMeta: metav1.ObjectMeta{
- Name: "ok",
- },
- Spec: v1.PodSpec{
- Containers: []v1.Container{
- {
- Name: "by-name",
- },
- {},
- },
- },
- }
- )
- a := []map[string]interface{}{{"name": "ovn-prot-net", "interface": "net0", "netType": "provider", "ipAddress": "192.168.1.3/24", "macAddress": "0a:00:00:00:00:01"}}
- ovnController.AddLogicalPorts(&okPod, a)
- Expect(fexec.CommandCalls).To(Equal(len(fakeCmds)))
-
- return nil
- }
-
- err := app.Run([]string{app.Name})
- Expect(err).NotTo(HaveOccurred())
- })
-
-})
"fmt"
kexec "k8s.io/utils/exec"
"os"
+ "reflect"
"strings"
"time"
)
log.Error(err, "Failed to initialize OVN Distributed Router")
return err
}
+
+ log.Info("OVN Network", "OVN Default NW", Ovn4nfvDefaultNw, "OVN Subnet", ovnConf.Subnet, "OVN Gateway IP", ovnConf.GatewayIP, "OVN ExcludeIPs", ovnConf.ExcludeIPs)
+ _, err = createOvnLS(Ovn4nfvDefaultNw, ovnConf.Subnet, ovnConf.GatewayIP, ovnConf.ExcludeIPs)
+ if err != nil && !reflect.DeepEqual(err, fmt.Errorf("LS exists")) {
+ log.Error(err, "Failed to create ovn4nfvk8s default nw")
+ return err
+ }
return nil
}
Interface []map[string]interface{} "json:\"interface\""
}
+var enableOvnDefaultIntf bool = true
// Add creates a new Pod Controller and adds it to the Manager. The Manager will set fields on the Controller
// and Start it when the Manager is Started.
func Add(mgr manager.Manager) error {
CreateFunc: func(e event.CreateEvent) bool {
// The object doesn't contain annotation ,nfnNetworkAnnotation so the event will be
// ignored.
- annotaion := e.Meta.GetAnnotations()
+ /*annotaion := e.Meta.GetAnnotations()
if _, ok := annotaion[nfnNetworkAnnotation]; !ok {
return false
- }
+ }*/
return true
},
DeleteFunc: func(e event.DeleteEvent) bool {
// The object doesn't contain annotation ,nfnNetworkAnnotation so the event will be
// ignored.
- annotaion := e.Meta.GetAnnotations()
+ /*annotaion := e.Meta.GetAnnotations()
if _, ok := annotaion[nfnNetworkAnnotation]; !ok {
return false
- }
+ }*/
return true
},
}
// Request object not found, could have been deleted after reconcile request.
// Owned objects are automatically garbage collected. For additional cleanup logic use finalizers.
// Return and don't requeue
- if instance.Name == "" || instance.Namespace == "" {
- return reconcile.Result{}, nil
- }
+ reqLogger.Info("Delete Pod", "request", request)
r.deleteLogicalPorts(request.Name, request.Namespace)
+ reqLogger.Info("Exit Reconciling Pod")
return reconcile.Result{}, nil
}
// Error reading the object - requeue the request.
if instance.Name == "" || instance.Namespace == "" {
return reconcile.Result{}, nil
}
+ if instance.Spec.HostNetwork {
+ return reconcile.Result{}, nil
+ }
+
err = r.addLogicalPorts(instance)
if err != nil && err.Error() == "Failed to add ports" {
// Requeue the object
nfn, err := r.readPodAnnotation(pod)
if err != nil {
- return err
+ // No annotation for multiple interfaces
+ nfn = &nfnNetwork {Interface: nil}
+ if enableOvnDefaultIntf == true {
+ nfn.Type = "ovn4nfv"
+ } else {
+ return err
+ }
}
-
+
switch {
case nfn.Type == "ovn4nfv":
ovnCtl, err := ovn.GetOvnController()
if err != nil {
return err
}
- if _, ok := pod.Annotations[ovn.Ovn4nfvAnnotationTag]; ok {
+ if _, ok := pod.Annotations[ovn.Ovn4nfvAnnotationTag]; ok {
return fmt.Errorf("Pod annotation found")
}
key, value := ovnCtl.AddLogicalPorts(pod, nfn.Interface)
if err != nil {
return err
}
+ log.Info("Calling DeleteLogicalPorts")
ovnCtl.DeleteLogicalPorts(name, namesapce)
return nil
// Add other types here