Skip to content

Commit

Permalink
Merge pull request openshift#255 from redhat-nfvpe/dev/macvlan42a
Browse files Browse the repository at this point in the history
SimpleMacvlan support
  • Loading branch information
openshift-merge-robot committed Jul 19, 2019
2 parents e2285aa + b79d258 commit bd5dc53
Show file tree
Hide file tree
Showing 38 changed files with 4,547 additions and 41 deletions.
9 changes: 9 additions & 0 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Gopkg.toml
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,7 @@ required = [
[[constraint]]
name = "github.com/gophercloud/gophercloud"
revision="17584a22adf89c48eb1f2518e71326b3b01ba573"

[[constraint]]
name = "github.com/containernetworking/cni"
version = "0.7.1"
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
apiVersion: "k8s.cni.cncf.io/v1"
kind: NetworkAttachmentDefinition
metadata:
name: {{.AdditionalNetworkName}}
namespace: default
spec:
config: '{
"cniVersion": "0.3.0",
"type": "macvlan",
{{if (index . "Master") }}
"master": "{{.Master}}",
{{end}}{{if (index . "Mode") }}
"mode": "{{.Mode}}",
{{end}}{{if (index . "MTU") }}
"mtu": {{.MTU}},
{{end}}
"ipam": {{.IPAMConfig | indent 6}}
}'
50 changes: 49 additions & 1 deletion manifests/0000_70_cluster-network-operator_01_crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ spec:
type: array
items:
type: object
required: ["type", "name", "rawCNIConfig"]
required: ["type", "name"]
properties:
type:
type: string
Expand All @@ -86,6 +86,54 @@ spec:
type: string
rawCNIConfig:
type: string
simpleMacvlanConfig:
type: object
properties:
master:
type: string
ipamConfig:
type: object
properties:
type:
type: string
staticIPAMConfig:
type: object
properties:
addresses:
type: array
items:
type: object
properties:
address:
type: string
gateway:
type: string
routes:
type: array
items:
type: object
properties:
destination:
type: string
gateway:
type: string
dns:
type: object
properties:
nameservers:
type: array
items:
type: string
domain:
type: string
search:
type: array
items:
type: string
mode:
type: string
mtu:
type: integer
disableMultiNetwork:
type: boolean
deployKubeProxy:
Expand Down
167 changes: 167 additions & 0 deletions pkg/network/additional_networks.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ package network

import (
"encoding/json"
"net"
"path/filepath"
"strings"

cnitypes "github.com/containernetworking/cni/pkg/types"

operv1 "github.com/openshift/api/operator/v1"
"github.com/openshift/cluster-network-operator/pkg/render"
Expand Down Expand Up @@ -58,3 +62,166 @@ func validateRaw(conf *operv1.AdditionalNetworkDefinition) []error {

return out
}

// staticIPAMConfig for json generation for static IPAM
type staticIPAMConfig struct {
Type string `json:"type"`
Routes []*cnitypes.Route `json:"routes"`
Addresses []staticIPAMAddress `json:"addresses,omitempty"`
DNS cnitypes.DNS `json:"dns"`
}

// staticIPAMAddress for json generation for static IPAM
type staticIPAMAddress struct {
AddressStr string `json:"address"`
Gateway net.IP `json:"gateway,omitempty"`
}

// getStaticIPAMConfigJSON generates static CNI json config
func getStaticIPAMConfigJSON(conf *operv1.StaticIPAMConfig) (string, error) {
staticIPAMConfig := staticIPAMConfig{}
staticIPAMConfig.Type = "static"
for _, address := range conf.Addresses {
staticIPAMConfig.Addresses = append(staticIPAMConfig.Addresses, staticIPAMAddress{AddressStr: address.Address, Gateway: net.ParseIP(address.Gateway)})
}
for _, route := range conf.Routes {
_, dest, err := net.ParseCIDR(route.Destination)
if err != nil {
return "", errors.Wrap(err, "failed to parse macvlan route")
}
staticIPAMConfig.Routes = append(staticIPAMConfig.Routes, &cnitypes.Route{Dst: *dest, GW: net.ParseIP(route.Gateway)})
}

if conf.DNS != nil {
staticIPAMConfig.DNS.Nameservers = append(staticIPAMConfig.DNS.Nameservers, conf.DNS.Nameservers...)
staticIPAMConfig.DNS.Domain = conf.DNS.Domain
staticIPAMConfig.DNS.Search = append(staticIPAMConfig.DNS.Search, conf.DNS.Search...)
}

jsonByte, err := json.Marshal(staticIPAMConfig)
if err != nil {
return "", errors.Wrap(err, "failed to create static ipam config")
}

return string(jsonByte), nil
}

// getIPAMConfigJSON generates IPAM CNI json config
func getIPAMConfigJSON(conf *operv1.IPAMConfig) (string, error) {

if conf == nil || conf.Type == operv1.IPAMTypeDHCP {
// DHCP does not have additional config
return `{ "type": "dhcp" }`, nil
} else if conf.Type == operv1.IPAMTypeStatic {
staticIPAMConfig, err := getStaticIPAMConfigJSON(conf.StaticIPAMConfig)
return staticIPAMConfig, err
}

return "", errors.Errorf("failed to render IPAM JSON")
}

// renderSimpleMacvlanConfig returns the SimpleMacvlanConfig manifests
func renderSimpleMacvlanConfig(conf *operv1.AdditionalNetworkDefinition, manifestDir string) ([]*uns.Unstructured, error) {
var err error
objs := []*uns.Unstructured{}

// render SimpleMacvlanConfig manifests
data := render.MakeRenderData()
data.Data["AdditionalNetworkName"] = conf.Name

if conf.SimpleMacvlanConfig == nil {
// no additional config, just fill default IPAM
data.Data["IPAMConfig"], err = getIPAMConfigJSON(nil)
} else {
macvlanConfig := conf.SimpleMacvlanConfig
data.Data["Master"] = macvlanConfig.Master

data.Data["IPAMConfig"], err = getIPAMConfigJSON(macvlanConfig.IPAMConfig)
if err != nil {
return nil, errors.Wrap(err, "failed to render ipam config")
}

if macvlanConfig.Mode != "" {
// macvlan CNI only accepts mode in lowercase
data.Data["Mode"] = strings.ToLower(string(macvlanConfig.Mode))
}

if macvlanConfig.MTU != 0 {
data.Data["MTU"] = macvlanConfig.MTU
}
}

objs, err = render.RenderDir(filepath.Join(manifestDir, "network/additional-networks/simplemacvlan"), &data)
if err != nil {
return nil, errors.Wrap(err, "failed to render simplemacvlan additional network")
}
return objs, nil
}

// validateStaticIPAMConfig checks its IPAMConfig.
func validateStaticIPAMConfig(conf *operv1.StaticIPAMConfig) []error {
out := []error{}
for _, addr := range conf.Addresses {
_, _, err := net.ParseCIDR(addr.Address)
if err != nil {
out = append(out, errors.Errorf("invalid static address: %v", err))
}
if addr.Gateway != "" && net.ParseIP(addr.Gateway) == nil {
out = append(out, errors.Errorf("invalid gateway: %s", addr.Gateway))
}
}
for _, route := range conf.Routes {
_, _, err := net.ParseCIDR(route.Destination)
if err != nil {
out = append(out, errors.Errorf("invalid route destination: %v", err))
}
if route.Gateway != "" && net.ParseIP(route.Gateway) == nil {
out = append(out, errors.Errorf("invalid gateway: %s", route.Gateway))
}
}
return out
}

// validateIPAMConfig checks its IPAMConfig.
func validateIPAMConfig(conf *operv1.IPAMConfig) []error {
out := []error{}

switch conf.Type {
case operv1.IPAMTypeStatic:
outStatic := validateStaticIPAMConfig(conf.StaticIPAMConfig)
out = append(out, outStatic...)
case operv1.IPAMTypeDHCP:
default:
out = append(out, errors.Errorf("invalid IPAM type: %s", conf.Type))
}

return out
}

// validateSimpleMacvlanConfig checks its name and SimpleMacvlanConfig.
func validateSimpleMacvlanConfig(conf *operv1.AdditionalNetworkDefinition) []error {
out := []error{}

if conf.Name == "" {
out = append(out, errors.Errorf("Additional Network Name cannot be nil"))
}

if conf.SimpleMacvlanConfig != nil {
macvlanConfig := conf.SimpleMacvlanConfig
outIPAM := validateIPAMConfig(macvlanConfig.IPAMConfig)
out = append(out, outIPAM...)

if conf.SimpleMacvlanConfig.Mode != "" {
switch conf.SimpleMacvlanConfig.Mode {
case operv1.MacvlanModeBridge:
case operv1.MacvlanModePrivate:
case operv1.MacvlanModeVEPA:
case operv1.MacvlanModePassthru:
default:
out = append(out, errors.Errorf("invalid Macvlan mode: %s", conf.SimpleMacvlanConfig.Mode))
}
}
}

return out
}

0 comments on commit bd5dc53

Please sign in to comment.