Skip to content

Commit

Permalink
Add NetworkAttachmentDefinition support to netwatcher
Browse files Browse the repository at this point in the history
In an effort to expand the existing netwatcher to be a more generic "Network Management Operator", this commit enhances it to be able to "speak" NAD, besides the 3 DANM APIs.
The idea is pretty simple: the Controller components can interpret the CNI config inside NAD.Spec.Config same way as the CNI config in Spec.Options inside any DANM network, then call the existing VLAN, and VxLAN management functionalities regardless which API triggered the Operator.
As a result, MACVLAN and IPVLAN type NADs can also enjoy the dynamic VLAN, and VxLAN host interface management functionalities previously exclusive to DANM API users.
Netwatcher also takes care of patching the name of the parent interface in Spec.Config, so the upstream CNIs connect the Pods to the right host interface.
  • Loading branch information
Levovar committed Mar 10, 2021
1 parent e5e8b7f commit 9244591
Show file tree
Hide file tree
Showing 36 changed files with 2,094 additions and 38 deletions.
2 changes: 1 addition & 1 deletion cmd/netwatcher/netwatcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func main() {
return
}
log.SetOutput(os.Stdout)
log.Println("Starting DANM Watcher...")
log.Println("Starting DANM NetWatcher...")
kubeConfig := flag.String("kubeconf", "", "Path to a kube config. Only required if out-of-cluster.")
flag.Parse()
config, err := getClientConfig(kubeConfig)
Expand Down
5 changes: 5 additions & 0 deletions crd/apis/k8s.cni.cncf.io/register.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package k8scnicncfio

const (
GroupName = "k8s.cni.cncf.io"
)
6 changes: 6 additions & 0 deletions crd/apis/k8s.cni.cncf.io/v1/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
//go:generate bash -c "cg(){ go list -m -f {{.Dir}} k8s.io/code-generator;}; crd(){ cat<<<'github.com/nokia/danm/crd';}; GOFLAGS='' bash $(cg)/generate-groups.sh all $(crd)/client/nad $(crd)/apis k8s.cni.cncf.io:v1 --go-header-file $(cg)/hack/boilerplate.go.txt"
// +k8s:deepcopy-gen=package
// +groupName=k8s.cni.cncf.io
// +groupGoName=K8sCniCncfIo

package v1
41 changes: 41 additions & 0 deletions crd/apis/k8s.cni.cncf.io/v1/register.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package v1

import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"

k8scnicncfio "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io"
)

// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: k8scnicncfio.GroupName, Version: "v1"}

// Resource takes an unqualified resource and returns a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}

var (
// localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes.
SchemeBuilder runtime.SchemeBuilder
localSchemeBuilder = &SchemeBuilder
AddToScheme = localSchemeBuilder.AddToScheme
)

func init() {
// We only register manually written functions here. The registration of the
// generated functions takes place in the generated files. The separation
// makes the code compile even when the generated files are missing.
localSchemeBuilder.Register(addKnownTypes)
}

// Adds the list of known types to api.Scheme.
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&NetworkAttachmentDefinition{},
&NetworkAttachmentDefinitionList{},
)
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
return nil
}
179 changes: 179 additions & 0 deletions crd/apis/k8s.cni.cncf.io/v1/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
package v1

import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"net"
)

// +genclient
// +genclient:noStatus
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +resourceName=network-attachment-definitions

type NetworkAttachmentDefinition struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

Spec NetworkAttachmentDefinitionSpec `json:"spec"`
}

type NetworkAttachmentDefinitionSpec struct {
Config string `json:"config"`
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type NetworkAttachmentDefinitionList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata"`

Items []NetworkAttachmentDefinition `json:"items"`
}

// DNS contains values interesting for DNS resolvers
// +k8s:deepcopy-gen=false
type DNS struct {
Nameservers []string `json:"nameservers,omitempty"`
Domain string `json:"domain,omitempty"`
Search []string `json:"search,omitempty"`
Options []string `json:"options,omitempty"`
}

const (
DeviceInfoTypePCI = "pci"
DeviceInfoTypeVHostUser = "vhost-user"
DeviceInfoTypeMemif = "memif"
DeviceInfoTypeVDPA = "vdpa"
DeviceInfoVersion = "1.0.0"
)

// DeviceInfo contains the information of the device associated
// with this network (if any)
type DeviceInfo struct {
Type string `json:"type,omitempty"`
Version string `json:"version,omitempty"`
Pci *PciDevice `json:"pci,omitempty"`
Vdpa *VdpaDevice `json:"vdpa,omitempty"`
VhostUser *VhostDevice `json:"vhost-user,omitempty"`
Memif *MemifDevice `json:"memif,omitempty"`
}

type PciDevice struct {
PciAddress string `json:"pci-address,omitempty"`
Vhostnet string `json:"vhost-net,omitempty"`
RdmaDevice string `json:"rdma-device,omitempty"`
PfPciAddress string `json:"pf-pci-address,omitempty"`
}

type VdpaDevice struct {
ParentDevice string `json:"parent-device,omitempty"`
Driver string `json:"driver,omitempty"`
Path string `json:"path,omitempty"`
PciAddress string `json:"pci-address,omitempty"`
PfPciAddress string `json:"pf-pci-address,omitempty"`
}

const (
VhostDeviceModeClient = "client"
VhostDeviceModeServer = "server"
)

type VhostDevice struct {
Mode string `json:"mode,omitempty"`
Path string `json:"path,omitempty"`
}

const (
MemifDeviceRoleMaster = "master"
MemitDeviceRoleSlave = "slave"
MemifDeviceModeEthernet = "ethernet"
MemitDeviceModeIP = "ip"
MemitDeviceModePunt = "punt"
)

type MemifDevice struct {
Role string `json:"role,omitempty"`
Path string `json:"path,omitempty"`
Mode string `json:"mode,omitempty"`
}

// NetworkStatus is for network status annotation for pod
// +k8s:deepcopy-gen=false
type NetworkStatus struct {
Name string `json:"name"`
Interface string `json:"interface,omitempty"`
IPs []string `json:"ips,omitempty"`
Mac string `json:"mac,omitempty"`
Default bool `json:"default,omitempty"`
DNS DNS `json:"dns,omitempty"`
DeviceInfo *DeviceInfo `json:"device-info,omitempty"`
}

// PortMapEntry for CNI PortMapEntry
// +k8s:deepcopy-gen=false
type PortMapEntry struct {
HostPort int `json:"hostPort"`
ContainerPort int `json:"containerPort"`
Protocol string `json:"protocol,omitempty"`
HostIP string `json:"hostIP,omitempty"`
}

// BandwidthEntry for CNI BandwidthEntry
// +k8s:deepcopy-gen=false
type BandwidthEntry struct {
IngressRate int `json:"ingressRate"`
IngressBurst int `json:"ingressBurst"`

EgressRate int `json:"egressRate"`
EgressBurst int `json:"egressBurst"`
}

// NetworkSelectionElement represents one element of the JSON format
// Network Attachment Selection Annotation as described in section 4.1.2
// of the CRD specification.
// +k8s:deepcopy-gen=false
type NetworkSelectionElement struct {
// Name contains the name of the Network object this element selects
Name string `json:"name"`
// Namespace contains the optional namespace that the network referenced
// by Name exists in
Namespace string `json:"namespace,omitempty"`
// IPRequest contains an optional requested IP addresses for this network
// attachment
IPRequest []string `json:"ips,omitempty"`
// MacRequest contains an optional requested MAC address for this
// network attachment
MacRequest string `json:"mac,omitempty"`
// InfinibandGUIDRequest contains an optional requested Infiniband GUID
// address for this network attachment
InfinibandGUIDRequest string `json:"infiniband-guid,omitempty"`
// InterfaceRequest contains an optional requested name for the
// network interface this attachment will create in the container
InterfaceRequest string `json:"interface,omitempty"`
// PortMappingsRequest contains an optional requested port mapping
// for the network
PortMappingsRequest []*PortMapEntry `json:"portMappings,omitempty"`
// BandwidthRequest contains an optional requested bandwidth for
// the network
BandwidthRequest *BandwidthEntry `json:"bandwidth,omitempty"`
// CNIArgs contains additional CNI arguments for the network interface
CNIArgs *map[string]interface{} `json:"cni-args"`
// GatewayRequest contains default route IP address for the pod
GatewayRequest []net.IP `json:"default-route,omitempty"`
}

const (
// Pod annotation for network-attachment-definition
NetworkAttachmentAnnot = "k8s.v1.cni.cncf.io/networks"
// Pod annotation for network status
NetworkStatusAnnot = "k8s.v1.cni.cncf.io/network-status"
// Old Pod annotation for network status (which is used before but it will be obsolated)
OldNetworkStatusAnnot = "k8s.v1.cni.cncf.io/networks-status"
)

// NoK8sNetworkError indicates error, no network in kubernetes
// +k8s:deepcopy-gen=false
type NoK8sNetworkError struct {
Message string
}

func (e *NoK8sNetworkError) Error() string { return string(e.Message) }
Loading

0 comments on commit 9244591

Please sign in to comment.