From e5d85eb0ebb77a2e5baab858268593e1a6c2c8b8 Mon Sep 17 00:00:00 2001 From: pkeerthana Date: Thu, 5 May 2016 02:42:13 +0530 Subject: [PATCH] infra nw support (#340) * revert and update only godeps * fix for unit-test failure * infra nw support * update comments, add system tests * fixed gofmt --- Godeps/Godeps.json | 14 +-- .../contiv/contivmodel/client/contivModel.js | 5 + .../contivmodel/client/contivModelClient.go | 75 ++++++++------- .../contiv/contivmodel/contivModel.go | 10 ++ .../contiv/contivmodel/network.json | 7 ++ .../src/github.com/contiv/ofnet/ofnetAgent.go | 22 ++++- core/core.go | 2 +- drivers/fakenetepdriver.go | 2 +- drivers/ovsSwitch.go | 47 +++++----- drivers/ovsdriver.go | 45 +++++++-- drivers/ovsdriver_test.go | 10 +- mgmtfn/k8splugin/kubeClient_test.go | 2 +- netctl/commands.go | 5 + netctl/netctl.go | 9 +- netmaster/intent/config.go | 1 + netmaster/master/endpoint.go | 39 ++++---- netmaster/master/network.go | 51 +++++----- netmaster/mastercfg/networkstate.go | 1 + netmaster/objApi/apiController.go | 1 + netmaster/objApi/objapi_test.go | 82 +++++++++------- netplugin/netd.go | 94 ++++++++++++++++++- netplugin/plugin/netplugin.go | 4 +- scripts/unittests | 8 +- systemtests/network_test.go | 62 ++++++++++++ systemtests/node_test.go | 13 +++ utils/netutils/netutils.go | 14 +++ 26 files changed, 456 insertions(+), 169 deletions(-) diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index afc973781..3bd0b78a1 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -49,11 +49,11 @@ }, { "ImportPath": "github.com/contiv/contivmodel", - "Rev": "12422da891c2ad18c1e3fb57ec541929d25fcff0" + "Rev": "1d248eda1a27121dce011656ecde3247827780dc" }, { "ImportPath": "github.com/contiv/contivmodel/client", - "Rev": "12422da891c2ad18c1e3fb57ec541929d25fcff0" + "Rev": "1d248eda1a27121dce011656ecde3247827780dc" }, { "ImportPath": "github.com/contiv/libovsdb", @@ -70,23 +70,23 @@ }, { "ImportPath": "github.com/contiv/ofnet", - "Rev": "5ec464bca5a171d1a8fbee1b147bd468c07649cc" + "Rev": "bc37eaef88c241864b9782f356a43305535cf3c0" }, { "ImportPath": "github.com/contiv/ofnet/ofctrl", - "Rev": "5ec464bca5a171d1a8fbee1b147bd468c07649cc" + "Rev": "bc37eaef88c241864b9782f356a43305535cf3c0" }, { "ImportPath": "github.com/contiv/ofnet/ovsdbDriver", - "Rev": "5ec464bca5a171d1a8fbee1b147bd468c07649cc" + "Rev": "bc37eaef88c241864b9782f356a43305535cf3c0" }, { "ImportPath": "github.com/contiv/ofnet/pqueue", - "Rev": "5ec464bca5a171d1a8fbee1b147bd468c07649cc" + "Rev": "bc37eaef88c241864b9782f356a43305535cf3c0" }, { "ImportPath": "github.com/contiv/ofnet/rpcHub", - "Rev": "5ec464bca5a171d1a8fbee1b147bd468c07649cc" + "Rev": "bc37eaef88c241864b9782f356a43305535cf3c0" }, { "ImportPath": "github.com/contiv/systemtests-utils", diff --git a/Godeps/_workspace/src/github.com/contiv/contivmodel/client/contivModel.js b/Godeps/_workspace/src/github.com/contiv/contivmodel/client/contivModel.js index 0e3cd3028..2ea3b6d29 100644 --- a/Godeps/_workspace/src/github.com/contiv/contivmodel/client/contivModel.js +++ b/Godeps/_workspace/src/github.com/contiv/contivmodel/client/contivModel.js @@ -282,6 +282,8 @@ var NetworkSummaryView = React.createClass({ { network.networkName } + { network.nwType } + { network.pktTag } { network.subnet } @@ -301,6 +303,7 @@ var NetworkSummaryView = React.createClass({ Encapsulation Gateway Network name + Network Type Vlan/Vxlan Tag Subnet @@ -328,6 +331,8 @@ var NetworkModalView = React.createClass({ + + diff --git a/Godeps/_workspace/src/github.com/contiv/contivmodel/client/contivModelClient.go b/Godeps/_workspace/src/github.com/contiv/contivmodel/client/contivModelClient.go index 29400a81a..73cf0a3f9 100644 --- a/Godeps/_workspace/src/github.com/contiv/contivmodel/client/contivModelClient.go +++ b/Godeps/_workspace/src/github.com/contiv/contivmodel/client/contivModelClient.go @@ -11,11 +11,15 @@ import ( "io/ioutil" "net/http" - "github.com/contiv/objdb/modeldb" - log "github.com/Sirupsen/logrus" ) +// Link is a one way relattion between two objects +type Link struct { + ObjType string `json:"type,omitempty"` + ObjKey string `json:"key,omitempty"` +} + func httpGet(url string, jdata interface{}) error { r, err := http.Get(url) @@ -157,12 +161,12 @@ type AppProfile struct { } type AppProfileLinkSets struct { - EndpointGroups map[string]modeldb.Link `json:"EndpointGroups,omitempty"` + EndpointGroups map[string]Link `json:"EndpointGroups,omitempty"` } type AppProfileLinks struct { - Network modeldb.Link `json:"Network,omitempty"` - Tenant modeldb.Link `json:"Tenant,omitempty"` + Network Link `json:"Network,omitempty"` + Tenant Link `json:"Tenant,omitempty"` } type EndpointGroup struct { @@ -181,14 +185,14 @@ type EndpointGroup struct { } type EndpointGroupLinkSets struct { - Policies map[string]modeldb.Link `json:"Policies,omitempty"` - Services map[string]modeldb.Link `json:"Services,omitempty"` + Policies map[string]Link `json:"Policies,omitempty"` + Services map[string]Link `json:"Services,omitempty"` } type EndpointGroupLinks struct { - AppProfile modeldb.Link `json:"AppProfile,omitempty"` - Network modeldb.Link `json:"Network,omitempty"` - Tenant modeldb.Link `json:"Tenant,omitempty"` + AppProfile Link `json:"AppProfile,omitempty"` + Network Link `json:"Network,omitempty"` + Tenant Link `json:"Tenant,omitempty"` } type Global struct { @@ -221,6 +225,7 @@ type Network struct { Encap string `json:"encap,omitempty"` // Encapsulation Gateway string `json:"gateway,omitempty"` // Gateway NetworkName string `json:"networkName,omitempty"` // Network name + NwType string `json:"nwType,omitempty"` // Network Type PktTag int `json:"pktTag,omitempty"` // Vlan/Vxlan Tag Subnet string `json:"subnet,omitempty"` // Subnet TenantName string `json:"tenantName,omitempty"` // Tenant Name @@ -231,13 +236,13 @@ type Network struct { } type NetworkLinkSets struct { - AppProfiles map[string]modeldb.Link `json:"AppProfiles,omitempty"` - EndpointGroups map[string]modeldb.Link `json:"EndpointGroups,omitempty"` - Services map[string]modeldb.Link `json:"Services,omitempty"` + AppProfiles map[string]Link `json:"AppProfiles,omitempty"` + EndpointGroups map[string]Link `json:"EndpointGroups,omitempty"` + Services map[string]Link `json:"Services,omitempty"` } type NetworkLinks struct { - Tenant modeldb.Link `json:"Tenant,omitempty"` + Tenant Link `json:"Tenant,omitempty"` } type Policy struct { @@ -253,12 +258,12 @@ type Policy struct { } type PolicyLinkSets struct { - EndpointGroups map[string]modeldb.Link `json:"EndpointGroups,omitempty"` - Rules map[string]modeldb.Link `json:"Rules,omitempty"` + EndpointGroups map[string]Link `json:"EndpointGroups,omitempty"` + Rules map[string]Link `json:"Rules,omitempty"` } type PolicyLinks struct { - Tenant modeldb.Link `json:"Tenant,omitempty"` + Tenant Link `json:"Tenant,omitempty"` } type Rule struct { @@ -285,7 +290,7 @@ type Rule struct { } type RuleLinkSets struct { - Policies map[string]modeldb.Link `json:"Policies,omitempty"` + Policies map[string]Link `json:"Policies,omitempty"` } type Service struct { @@ -311,14 +316,14 @@ type Service struct { } type ServiceLinkSets struct { - EndpointGroups map[string]modeldb.Link `json:"EndpointGroups,omitempty"` - Instances map[string]modeldb.Link `json:"Instances,omitempty"` - Networks map[string]modeldb.Link `json:"Networks,omitempty"` + EndpointGroups map[string]Link `json:"EndpointGroups,omitempty"` + Instances map[string]Link `json:"Instances,omitempty"` + Networks map[string]Link `json:"Networks,omitempty"` } type ServiceLinks struct { - App modeldb.Link `json:"App,omitempty"` - VolumeProfile modeldb.Link `json:"VolumeProfile,omitempty"` + App Link `json:"App,omitempty"` + VolumeProfile Link `json:"VolumeProfile,omitempty"` } type ServiceInstance struct { @@ -337,11 +342,11 @@ type ServiceInstance struct { } type ServiceInstanceLinkSets struct { - Volumes map[string]modeldb.Link `json:"Volumes,omitempty"` + Volumes map[string]Link `json:"Volumes,omitempty"` } type ServiceInstanceLinks struct { - Service modeldb.Link `json:"Service,omitempty"` + Service Link `json:"Service,omitempty"` } type Tenant struct { @@ -356,12 +361,12 @@ type Tenant struct { } type TenantLinkSets struct { - AppProfiles map[string]modeldb.Link `json:"AppProfiles,omitempty"` - EndpointGroups map[string]modeldb.Link `json:"EndpointGroups,omitempty"` - Networks map[string]modeldb.Link `json:"Networks,omitempty"` - Policies map[string]modeldb.Link `json:"Policies,omitempty"` - VolumeProfiles map[string]modeldb.Link `json:"VolumeProfiles,omitempty"` - Volumes map[string]modeldb.Link `json:"Volumes,omitempty"` + AppProfiles map[string]Link `json:"AppProfiles,omitempty"` + EndpointGroups map[string]Link `json:"EndpointGroups,omitempty"` + Networks map[string]Link `json:"Networks,omitempty"` + Policies map[string]Link `json:"Policies,omitempty"` + VolumeProfiles map[string]Link `json:"VolumeProfiles,omitempty"` + Volumes map[string]Link `json:"Volumes,omitempty"` } type Volume struct { @@ -381,11 +386,11 @@ type Volume struct { } type VolumeLinkSets struct { - ServiceInstances map[string]modeldb.Link `json:"ServiceInstances,omitempty"` + ServiceInstances map[string]Link `json:"ServiceInstances,omitempty"` } type VolumeLinks struct { - Tenant modeldb.Link `json:"Tenant,omitempty"` + Tenant Link `json:"Tenant,omitempty"` } type VolumeProfile struct { @@ -405,11 +410,11 @@ type VolumeProfile struct { } type VolumeProfileLinkSets struct { - Services map[string]modeldb.Link `json:"Services,omitempty"` + Services map[string]Link `json:"Services,omitempty"` } type VolumeProfileLinks struct { - Tenant modeldb.Link `json:"Tenant,omitempty"` + Tenant Link `json:"Tenant,omitempty"` } // AppProfilePost posts the appProfile object diff --git a/Godeps/_workspace/src/github.com/contiv/contivmodel/contivModel.go b/Godeps/_workspace/src/github.com/contiv/contivmodel/contivModel.go index 6bfc0255f..a9c430824 100644 --- a/Godeps/_workspace/src/github.com/contiv/contivmodel/contivModel.go +++ b/Godeps/_workspace/src/github.com/contiv/contivmodel/contivModel.go @@ -94,6 +94,7 @@ type Network struct { Encap string `json:"encap,omitempty"` // Encapsulation Gateway string `json:"gateway,omitempty"` // Gateway NetworkName string `json:"networkName,omitempty"` // Network name + NwType string `json:"nwType,omitempty"` // Network Type PktTag int `json:"pktTag,omitempty"` // Vlan/Vxlan Tag Subnet string `json:"subnet,omitempty"` // Subnet TenantName string `json:"tenantName,omitempty"` // Tenant Name @@ -1873,6 +1874,15 @@ func ValidateNetwork(obj *Network) error { return errors.New("networkName string too long") } + if obj.NwType == "" { + obj.NwType = "data" + } + + nwTypeMatch := regexp.MustCompile("^(infra|data)$") + if nwTypeMatch.MatchString(obj.NwType) == false { + return errors.New("nwType string invalid format") + } + subnetMatch := regexp.MustCompile("^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3})(\\-(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9]))?/(3[0-1]|2[0-9]|1[0-9]|[1-9])$") if subnetMatch.MatchString(obj.Subnet) == false { return errors.New("subnet string invalid format") diff --git a/Godeps/_workspace/src/github.com/contiv/contivmodel/network.json b/Godeps/_workspace/src/github.com/contiv/contivmodel/network.json index c76e3f837..2a062e24b 100644 --- a/Godeps/_workspace/src/github.com/contiv/contivmodel/network.json +++ b/Godeps/_workspace/src/github.com/contiv/contivmodel/network.json @@ -17,6 +17,13 @@ "title": "Tenant Name", "length": 64 }, + "nwType": { + "type": "string", + "format": "^(infra|data)$", + "default": "\"data\"", + "title": "Network Type", + "showSummary": true + }, "encap": { "type": "string", "format": "^(vlan|vxlan)$", diff --git a/Godeps/_workspace/src/github.com/contiv/ofnet/ofnetAgent.go b/Godeps/_workspace/src/github.com/contiv/ofnet/ofnetAgent.go index 881f17e9b..b24023993 100644 --- a/Godeps/_workspace/src/github.com/contiv/ofnet/ofnetAgent.go +++ b/Godeps/_workspace/src/github.com/contiv/ofnet/ofnetAgent.go @@ -569,16 +569,28 @@ func (self *OfnetAgent) RemoveNetwork(vlanId uint16, vni uint32, Gw string, Vrf delete(self.endpointDb, gwEpid) - // Clear the database - delete(self.vlanVniMap, vlanId) - delete(self.vniVlanMap, vni) - // make sure there are no endpoints still installed in this vlan for _, endpoint := range self.endpointDb { if (vni != 0) && (endpoint.Vni == vni) { - log.Fatalf("Vlan %d still has routes. Route: %+v", vlanId, endpoint) + if endpoint.OriginatorIp.String() == self.localIp.String() { + log.Fatalf("Vlan %d still has routes. Route: %+v", vlanId, endpoint) + } else { + // Network delete arrived before other hosts cleanup endpoint + var resp bool + log.Warnf("Vlan %d still has routes, cleaning up. Route: %+v", vlanId, endpoint) + err := self.EndpointDel(endpoint, &resp) + if err != nil { + log.Errorf("Error uninstalling endpoint %+v. Err: %v", endpoint, err) + } + + } } } + + // Clear the database + delete(self.vlanVniMap, vlanId) + delete(self.vniVlanMap, vni) + // Call the datapath return self.datapath.RemoveVlan(vlanId, vni, Vrf) } diff --git a/core/core.go b/core/core.go index 95ee4e3c5..a7a988324 100755 --- a/core/core.go +++ b/core/core.go @@ -106,7 +106,7 @@ type NetworkDriver interface { Init(instInfo *InstanceInfo) error Deinit() CreateNetwork(id string) error - DeleteNetwork(id, encap string, pktTag, extPktTag int, gateway string, tenant string) error + DeleteNetwork(id, nwType, encap string, pktTag, extPktTag int, gateway string, tenant string) error CreateEndpoint(id string) error DeleteEndpoint(id string) error AddPeerHost(node ServiceInfo) error diff --git a/drivers/fakenetepdriver.go b/drivers/fakenetepdriver.go index 5f70a4959..46cac511a 100755 --- a/drivers/fakenetepdriver.go +++ b/drivers/fakenetepdriver.go @@ -26,7 +26,7 @@ func (d *FakeNetEpDriver) CreateNetwork(id string) error { } // DeleteNetwork is not implemented. -func (d *FakeNetEpDriver) DeleteNetwork(id, encap string, pktTag, extPktTag int, gateway string, tenant string) error { +func (d *FakeNetEpDriver) DeleteNetwork(id, nwType, encap string, pktTag, extPktTag int, gateway string, tenant string) error { return core.Errorf("Not implemented") } diff --git a/drivers/ovsSwitch.go b/drivers/ovsSwitch.go index 007fe457c..a182946a0 100755 --- a/drivers/ovsSwitch.go +++ b/drivers/ovsSwitch.go @@ -222,11 +222,12 @@ func setLinkMtu(name string, mtu int) error { return netlink.LinkSetMTU(iface, mtu) } -// getOvsPostName returns OVS port name depending on if we use Veth pairs -func getOvsPostName(intfName string) string { +// getOvsPortName returns OVS port name depending on if we use Veth pairs +// For infra nw, dont use Veth pair +func getOvsPortName(intfName string, skipVethPair bool) string { var ovsPortName string - if useVethPair { + if useVethPair && !skipVethPair { ovsPortName = strings.Replace(intfName, "port", "vport", 1) } else { ovsPortName = intfName @@ -236,14 +237,14 @@ func getOvsPostName(intfName string) string { } // CreatePort creates a port in ovs switch -func (sw *OvsSwitch) CreatePort(intfName string, cfgEp *mastercfg.CfgEndpointState, pktTag, nwPktTag int) error { +func (sw *OvsSwitch) CreatePort(intfName string, cfgEp *mastercfg.CfgEndpointState, pktTag, nwPktTag int, skipVethPair bool) error { var ovsIntfType string // Get OVS port name - ovsPortName := getOvsPostName(intfName) + ovsPortName := getOvsPortName(intfName, skipVethPair) // Create Veth pairs if required - if useVethPair { + if useVethPair && !skipVethPair { ovsIntfType = "" // Create a Veth pair @@ -262,19 +263,10 @@ func (sw *OvsSwitch) CreatePort(intfName string, cfgEp *mastercfg.CfgEndpointSta } else { ovsPortName = intfName ovsIntfType = "internal" - - } - - // Set the link mtu to 1450 to allow for 50 bytes vxlan encap - // (inner eth header(14) + outer IP(20) outer UDP(8) + vxlan header(8)) - err := setLinkMtu(intfName, vxlanEndpointMtu) - if err != nil { - log.Errorf("Error setting link %s mtu. Err: %v", intfName, err) - return err } // Ask OVSDB driver to add the port - err = sw.ovsdbDriver.CreatePort(ovsPortName, ovsIntfType, cfgEp.ID, pktTag) + err := sw.ovsdbDriver.CreatePort(ovsPortName, ovsIntfType, cfgEp.ID, pktTag) if err != nil { return err } @@ -287,6 +279,14 @@ func (sw *OvsSwitch) CreatePort(intfName string, cfgEp *mastercfg.CfgEndpointSta // Wait a little for OVS to create the interface time.Sleep(300 * time.Millisecond) + // Set the link mtu to 1450 to allow for 50 bytes vxlan encap + // (inner eth header(14) + outer IP(20) outer UDP(8) + vxlan header(8)) + err = setLinkMtu(intfName, vxlanEndpointMtu) + if err != nil { + log.Errorf("Error setting link %s mtu. Err: %v", intfName, err) + return err + } + // Set the interface mac address err = netutils.SetInterfaceMac(intfName, cfgEp.MacAddress) if err != nil { @@ -318,6 +318,7 @@ func (sw *OvsSwitch) CreatePort(intfName string, cfgEp *mastercfg.CfgEndpointSta // Add the local port to ofnet err = sw.ofnetAgent.AddLocalEndpoint(endpoint) + if err != nil { log.Errorf("Error adding local port %s to ofnet. Err: %v", ovsPortName, err) return err @@ -326,9 +327,10 @@ func (sw *OvsSwitch) CreatePort(intfName string, cfgEp *mastercfg.CfgEndpointSta } // UpdatePort updates an OVS port without creating it -func (sw *OvsSwitch) UpdatePort(intfName string, cfgEp *mastercfg.CfgEndpointState, pktTag int) error { +func (sw *OvsSwitch) UpdatePort(intfName string, cfgEp *mastercfg.CfgEndpointState, pktTag int, skipVethPair bool) error { + // Get OVS port name - ovsPortName := getOvsPostName(intfName) + ovsPortName := getOvsPortName(intfName, skipVethPair) // Add the endpoint to ofnet // Get the openflow port number for the interface @@ -363,17 +365,14 @@ func (sw *OvsSwitch) UpdatePort(intfName string, cfgEp *mastercfg.CfgEndpointSta } // DeletePort removes a port from OVS -func (sw *OvsSwitch) DeletePort(epOper *OvsOperEndpointState) error { +func (sw *OvsSwitch) DeletePort(epOper *OvsOperEndpointState, skipVethPair bool) error { if epOper.VtepIP != "" { return nil } // Get the OVS port name - ovsPortName := getOvsPostName(epOper.PortName) - if !useVethPair { - ovsPortName = epOper.PortName - } + ovsPortName := getOvsPortName(epOper.PortName, skipVethPair) // Get the openflow port number for the interface ofpPort, err := sw.ovsdbDriver.GetOfpPortNo(ovsPortName) @@ -399,7 +398,7 @@ func (sw *OvsSwitch) DeletePort(epOper *OvsOperEndpointState) error { } // Delete the Veth pairs if required - if useVethPair { + if useVethPair && !skipVethPair { // Delete a Veth pair verr := deleteVethPair(ovsPortName, epOper.PortName) if verr != nil { diff --git a/drivers/ovsdriver.go b/drivers/ovsdriver.go index 014f325df..7c30cf671 100755 --- a/drivers/ovsdriver.go +++ b/drivers/ovsdriver.go @@ -19,6 +19,7 @@ import ( "encoding/json" "errors" "fmt" + "os" "strconv" "strings" @@ -193,8 +194,8 @@ func (d *OvsDriver) CreateNetwork(id string) error { } // DeleteNetwork deletes a network by named identifier -func (d *OvsDriver) DeleteNetwork(id, encap string, pktTag, extPktTag int, gateway string, tenant string) error { - log.Infof("delete net %s, encap %s, tags: %d/%d", id, encap, pktTag, extPktTag) +func (d *OvsDriver) DeleteNetwork(id, nwType, encap string, pktTag, extPktTag int, gateway string, tenant string) error { + log.Infof("delete net %s, nwType %s, encap %s, tags: %d/%d", id, nwType, encap, pktTag, extPktTag) // Find the switch based on network type var sw *OvsSwitch @@ -204,6 +205,23 @@ func (d *OvsDriver) DeleteNetwork(id, encap string, pktTag, extPktTag int, gatew sw = d.switchDb["vlan"] } + // Delete infra nw endpoint if present + if nwType == "infra" { + hostName, _ := os.Hostname() + epID := id + "-" + hostName + + epOper := OvsOperEndpointState{} + epOper.StateDriver = d.oper.StateDriver + err := epOper.Read(epID) + if err == nil { + err = sw.DeletePort(&epOper, true) + if err != nil { + log.Errorf("Error deleting endpoint: %+v. Err: %v", epOper, err) + } + epOper.Clear() + } + } + return sw.DeleteNetwork(uint16(pktTag), uint32(extPktTag), gateway, tenant) } @@ -251,6 +269,9 @@ func (d *OvsDriver) CreateEndpoint(id string) error { sw = d.switchDb["vlan"] } + // Skip Veth pair creation for infra nw endpoints + skipVethPair := (cfgNw.NwType == "infra") + operEp := &OvsOperEndpointState{} operEp.StateDriver = d.oper.StateDriver err = operEp.Read(id) @@ -263,7 +284,7 @@ func (d *OvsDriver) CreateEndpoint(id string) error { log.Printf("Found matching oper state for ep %s, noop", id) // Ask the switch to update the port - err = sw.UpdatePort(operEp.PortName, cfgEp, cfgEpGroup.PktTag) + err = sw.UpdatePort(operEp.PortName, cfgEp, cfgEpGroup.PktTag, skipVethPair) if err != nil { log.Errorf("Error creating port %s. Err: %v", intfName, err) return err @@ -276,14 +297,19 @@ func (d *OvsDriver) CreateEndpoint(id string) error { d.DeleteEndpoint(operEp.ID) } - // Get the interface name to use - intfName, err = d.getIntfName() - if err != nil { - return err + if cfgNw.NwType == "infra" { + // For infra nw, port name is network name + intfName = cfgNw.NetworkName + } else { + // Get the interface name to use + intfName, err = d.getIntfName() + if err != nil { + return err + } } // Ask the switch to create the port - err = sw.CreatePort(intfName, cfgEp, cfgEpGroup.PktTag, cfgNw.PktTag) + err = sw.CreatePort(intfName, cfgEp, cfgEpGroup.PktTag, cfgNw.PktTag, skipVethPair) if err != nil { log.Errorf("Error creating port %s. Err: %v", intfName, err) return err @@ -345,7 +371,8 @@ func (d *OvsDriver) DeleteEndpoint(id string) (err error) { sw = d.switchDb["vlan"] } - err = sw.DeletePort(&epOper) + skipVethPair := (cfgNw.NwType == "infra") + err = sw.DeletePort(&epOper, skipVethPair) if err != nil { log.Errorf("Error deleting endpoint: %+v. Err: %v", epOper, err) } diff --git a/drivers/ovsdriver_test.go b/drivers/ovsdriver_test.go index 172c294f1..ddc245dfc 100755 --- a/drivers/ovsdriver_test.go +++ b/drivers/ovsdriver_test.go @@ -286,7 +286,7 @@ func TestOvsDriverCreateEndpoint(t *testing.T) { if err != nil { t.Fatalf("network creation failed. Error: %s", err) } - defer func() { driver.DeleteNetwork(testOvsNwID, "", testPktTag, testExtPktTag, testGateway, testTenant) }() + defer func() { driver.DeleteNetwork(testOvsNwID, "", "", testPktTag, testExtPktTag, testGateway, testTenant) }() // create endpoint err = driver.CreateEndpoint(id) @@ -321,7 +321,7 @@ func TestOvsDriverCreateEndpointStateful(t *testing.T) { t.Fatalf("network creation failed. Error: %s", err) } defer func() { - driver.DeleteNetwork(testOvsNwIDStateful, "", testPktTagStateful, testExtPktTag, testGateway, testTenant) + driver.DeleteNetwork(testOvsNwIDStateful, "", "", testPktTagStateful, testExtPktTag, testGateway, testTenant) }() // Create endpoint @@ -361,7 +361,7 @@ func TestOvsDriverCreateEndpointStatefulStateMismatch(t *testing.T) { if err != nil { t.Fatalf("network creation failed. Error: %s", err) } - defer func() { driver.DeleteNetwork(testOvsNwID, "", testPktTag, testExtPktTag, testGateway, testTenant) }() + defer func() { driver.DeleteNetwork(testOvsNwID, "", "", testPktTag, testExtPktTag, testGateway, testTenant) }() // create second network err = driver.CreateNetwork(testOvsNwIDStateful) @@ -369,7 +369,7 @@ func TestOvsDriverCreateEndpointStatefulStateMismatch(t *testing.T) { t.Fatalf("network creation failed. Error: %s", err) } defer func() { - driver.DeleteNetwork(testOvsNwIDStateful, "", testPktTagStateful, testExtPktTag, testGateway, testTenant) + driver.DeleteNetwork(testOvsNwIDStateful, "", "", testPktTagStateful, testExtPktTag, testGateway, testTenant) }() // create endpoint @@ -422,7 +422,7 @@ func TestOvsDriverDeleteEndpoint(t *testing.T) { if err != nil { t.Fatalf("network creation failed. Error: %s", err) } - defer func() { driver.DeleteNetwork(testOvsNwID, "", testPktTag, testExtPktTag, testGateway, testTenant) }() + defer func() { driver.DeleteNetwork(testOvsNwID, "", "", testPktTag, testExtPktTag, testGateway, testTenant) }() // create endpoint err = driver.CreateEndpoint(id) diff --git a/mgmtfn/k8splugin/kubeClient_test.go b/mgmtfn/k8splugin/kubeClient_test.go index a051c6132..b77d365f8 100644 --- a/mgmtfn/k8splugin/kubeClient_test.go +++ b/mgmtfn/k8splugin/kubeClient_test.go @@ -91,7 +91,7 @@ func (d *KubeTestNetDrv) CreateNetwork(id string) error { } // DeleteNetwork is not implemented. -func (d *KubeTestNetDrv) DeleteNetwork(id, encap string, pktTag, extPktTag int, gateway string, tenant string) error { +func (d *KubeTestNetDrv) DeleteNetwork(id, nwType, encap string, pktTag, extPktTag int, gateway string, tenant string) error { return nil } diff --git a/netctl/commands.go b/netctl/commands.go index 7b50a3c25..2e966b9ab 100755 --- a/netctl/commands.go +++ b/netctl/commands.go @@ -103,6 +103,11 @@ var Commands = []cli.Command{ ArgsUsage: "[network]", Flags: []cli.Flag{ tenantFlag, + cli.StringFlag{ + Name: "nw-type, n", + Usage: "Network Type (infra or data)", + Value: "data", + }, cli.StringFlag{ Name: "encap, e", Usage: "Encap type (vlan or vxlan)", diff --git a/netctl/netctl.go b/netctl/netctl.go index e139bd2ea..75fd86e20 100755 --- a/netctl/netctl.go +++ b/netctl/netctl.go @@ -264,6 +264,7 @@ func createNetwork(ctx *cli.Context) { network := ctx.Args()[0] encap := ctx.String("encap") pktTag := ctx.Int("pkt-tag") + nwType := ctx.String("nw-type") errCheck(ctx, getClient(ctx).NetworkPost(&contivClient.Network{ TenantName: tenant, @@ -272,6 +273,7 @@ func createNetwork(ctx *cli.Context) { Subnet: subnet, Gateway: gateway, PktTag: pktTag, + NwType: nwType, })) } @@ -318,14 +320,15 @@ func listNetworks(ctx *cli.Context) { } else { writer := tabwriter.NewWriter(os.Stdout, 0, 2, 2, ' ', 0) defer writer.Flush() - writer.Write([]byte("Tenant\tNetwork\tEncap type\tPacket tag\tSubnet\tGateway\n")) - writer.Write([]byte("------\t-------\t----------\t----------\t-------\t------\n")) + writer.Write([]byte("Tenant\tNetwork\tNw Type\tEncap type\tPacket tag\tSubnet\tGateway\n")) + writer.Write([]byte("------\t-------\t-------\t----------\t----------\t-------\t------\n")) for _, net := range filtered { writer.Write( - []byte(fmt.Sprintf("%v\t%v\t%v\t%v\t%v\t%v\n", + []byte(fmt.Sprintf("%v\t%v\t%v\t%v\t%v\t%v\t%v\n", net.TenantName, net.NetworkName, + net.NwType, net.Encap, net.PktTag, net.Subnet, diff --git a/netmaster/intent/config.go b/netmaster/intent/config.go index 8cb7d225b..b718754d5 100755 --- a/netmaster/intent/config.go +++ b/netmaster/intent/config.go @@ -39,6 +39,7 @@ type ConfigNetwork struct { Name string // overrides for various functions when auto allocation is not desired + NwType string PktTagType string PktTag int SubnetCIDR string diff --git a/netmaster/master/endpoint.go b/netmaster/master/endpoint.go index 09472a49e..a23f6d5aa 100644 --- a/netmaster/master/endpoint.go +++ b/netmaster/master/endpoint.go @@ -103,10 +103,13 @@ func CreateEndpoint(stateDriver core.StateDriver, nwCfg *mastercfg.CfgNetworkSta } // Set endpoint group - epCfg.EndpointGroupID, err = getEndpointGroupID(ep.ServiceName, nwCfg.NetworkName, nwCfg.Tenant) - if err != nil { - log.Errorf("Error getting endpoint group for %s.%s. Err: %v", ep.ServiceName, nwCfg.ID, err) - return nil, err + // Skip for infra nw + if nwCfg.NwType != "infra" { + epCfg.EndpointGroupID, err = getEndpointGroupID(ep.ServiceName, nwCfg.NetworkName, nwCfg.Tenant) + if err != nil { + log.Errorf("Error getting endpoint group for %s.%s. Err: %v", ep.ServiceName, nwCfg.ID, err) + return nil, err + } } err = epCfg.Write() @@ -175,24 +178,26 @@ func DeleteEndpointID(stateDriver core.StateDriver, epID string) (*mastercfg.Cfg nwCfg := &mastercfg.CfgNetworkState{} nwCfg.StateDriver = stateDriver err = nwCfg.Read(epCfg.NetID) - if err != nil { - return nil, err - } - err = freeEndpointResources(epCfg, nwCfg) - if err != nil { - return nil, err - } + // Network may already be deleted if infra nw + // If network present, free up nw resources + if err == nil { + err = freeEndpointResources(epCfg, nwCfg) + if err != nil { + return nil, err + } - err = epCfg.Clear() - if err != nil { - log.Errorf("error writing nw config. Error: %s", err) - return nil, err + err = nwCfg.Write() + if err != nil { + log.Errorf("error writing nw config. Error: %s", err) + return nil, err + } } - err = nwCfg.Write() + // Even if network not present (already deleted), cleanup ep cfg + err = epCfg.Clear() if err != nil { - log.Errorf("error writing nw config. Error: %s", err) + log.Errorf("error writing ep config. Error: %s", err) return nil, err } diff --git a/netmaster/master/network.go b/netmaster/master/network.go index fc21cadb2..08dfc66e1 100755 --- a/netmaster/master/network.go +++ b/netmaster/master/network.go @@ -104,6 +104,7 @@ func CreateNetwork(network intent.ConfigNetwork, stateDriver core.StateDriver, t nwCfg = &mastercfg.CfgNetworkState{ Tenant: tenantName, NetworkName: network.Name, + NwType: network.NwType, PktTagType: network.PktTagType, SubnetIP: subnetIP, SubnetLen: subnetLen, @@ -154,6 +155,11 @@ func CreateNetwork(network intent.ConfigNetwork, stateDriver core.StateDriver, t return err } + // Skip docker and service container configs for infra nw + if network.NwType == "infra" { + return nil + } + if GetClusterMode() == "docker" { // Create the network in docker err = docknet.CreateDockNet(tenantName, network.Name, "", nwCfg) @@ -385,30 +391,33 @@ func DeleteNetworkID(stateDriver core.StateDriver, netID string) error { return err } - // Check if there are any active endpoints - if hasActiveEndpoints(nwCfg) { - return core.Errorf("Error: Network has active endpoints") - } + if nwCfg.NwType != "infra" { + // For Infra nw, endpoint delete initiated by netplugin + // Check if there are any active endpoints + if hasActiveEndpoints(nwCfg) { + return core.Errorf("Error: Network has active endpoints") + } - if IsDNSEnabled() { - // detach Dns container - err = detachServiceContainer(nwCfg.Tenant, nwCfg.NetworkName) - if err != nil { - log.Errorf("Error detaching service container. Err: %v", err) + if IsDNSEnabled() { + // detach Dns container + err = detachServiceContainer(nwCfg.Tenant, nwCfg.NetworkName) + if err != nil { + log.Errorf("Error detaching service container. Err: %v", err) + } } - } - if GetClusterMode() == "docker" { - // Delete the docker network - err = docknet.DeleteDockNet(nwCfg.Tenant, nwCfg.NetworkName, "") - if err != nil { - log.Errorf("Error deleting network %s. Err: %v", netID, err) - // DeleteDockNet will fail when network has active endpoints. - // No damage is done yet. It is safe to fail. - // We do not have to call attachServiceContainer here, - // as detachServiceContainer detaches only when there are no - // endpoints remaining. - return err + if GetClusterMode() == "docker" { + // Delete the docker network + err = docknet.DeleteDockNet(nwCfg.Tenant, nwCfg.NetworkName, "") + if err != nil { + log.Errorf("Error deleting network %s. Err: %v", netID, err) + // DeleteDockNet will fail when network has active endpoints. + // No damage is done yet. It is safe to fail. + // We do not have to call attachServiceContainer here, + // as detachServiceContainer detaches only when there are no + // endpoints remaining. + return err + } } } diff --git a/netmaster/mastercfg/networkstate.go b/netmaster/mastercfg/networkstate.go index 3b8547963..8a31bb37b 100644 --- a/netmaster/mastercfg/networkstate.go +++ b/netmaster/mastercfg/networkstate.go @@ -45,6 +45,7 @@ type CfgNetworkState struct { core.CommonState Tenant string `json:"tenant"` NetworkName string `json:"networkName"` + NwType string `json:"nwType"` PktTagType string `json:"pktTagType"` PktTag int `json:"pktTag"` ExtPktTag int `json:"extPktTag"` diff --git a/netmaster/objApi/apiController.go b/netmaster/objApi/apiController.go index 511432e0c..8265c50bb 100755 --- a/netmaster/objApi/apiController.go +++ b/netmaster/objApi/apiController.go @@ -570,6 +570,7 @@ func (ac *APIController) NetworkCreate(network *contivModel.Network) error { // Build networ config networkCfg := intent.ConfigNetwork{ Name: network.NetworkName, + NwType: network.NwType, PktTagType: network.Encap, PktTag: network.PktTag, SubnetCIDR: network.Subnet, diff --git a/netmaster/objApi/objapi_test.go b/netmaster/objApi/objapi_test.go index c67364b24..d9632943e 100644 --- a/netmaster/objApi/objapi_test.go +++ b/netmaster/objApi/objapi_test.go @@ -150,10 +150,11 @@ func checkError(t *testing.T, testStr string, err error) { } // checkCreateNetwork creates networks and checks for error -func checkCreateNetwork(t *testing.T, expError bool, tenant, network, encap, subnet, gw string, tag int) { +func checkCreateNetwork(t *testing.T, expError bool, tenant, network, nwType, encap, subnet, gw string, tag int) { net := client.Network{ TenantName: tenant, NetworkName: network, + NwType: nwType, Encap: encap, Subnet: subnet, Gateway: gw, @@ -174,7 +175,7 @@ func checkCreateNetwork(t *testing.T, expError bool, tenant, network, encap, sub } // verifyNetworkState verifies network state es as expected -func verifyNetworkState(t *testing.T, tenant, network, encap, subnet, gw string, subnetLen uint, pktTag, extTag int) { +func verifyNetworkState(t *testing.T, tenant, network, nwType, encap, subnet, gw string, subnetLen uint, pktTag, extTag int) { networkID := network + "." + tenant nwCfg := &mastercfg.CfgNetworkState{} nwCfg.StateDriver = stateStore @@ -184,7 +185,7 @@ func verifyNetworkState(t *testing.T, tenant, network, encap, subnet, gw string, } // verify network params - if nwCfg.Tenant != tenant || nwCfg.NetworkName != network || + if nwCfg.Tenant != tenant || nwCfg.NetworkName != network || nwCfg.NwType != nwType || nwCfg.PktTagType != encap || nwCfg.SubnetIP != netutils.GetSubnetAddr(subnet, subnetLen) || nwCfg.Gateway != gw { t.Fatalf("Network state {%+v} did not match expected state", nwCfg) } @@ -490,39 +491,52 @@ func TestTenantAddDelete(t *testing.T) { // TestNetworkAddDelete tests network create/delete REST api func TestNetworkAddDelete(t *testing.T) { // Basic vlan network - checkCreateNetwork(t, false, "default", "contiv", "vlan", "10.1.1.1/24", "10.1.1.254", 1) - verifyNetworkState(t, "default", "contiv", "vlan", "10.1.1.1", "10.1.1.254", 24, 1, 0) + checkCreateNetwork(t, false, "default", "contiv", "", "vlan", "10.1.1.1/24", "10.1.1.254", 1) + verifyNetworkState(t, "default", "contiv", "data", "vlan", "10.1.1.1", "10.1.1.254", 24, 1, 0) checkDeleteNetwork(t, false, "default", "contiv") // Basic Vxlan network - checkCreateNetwork(t, false, "default", "contiv", "vxlan", "10.1.1.1/16", "10.1.1.254", 1) - verifyNetworkState(t, "default", "contiv", "vxlan", "10.1.1.1", "10.1.1.254", 16, 1, 1) + checkCreateNetwork(t, false, "default", "contiv", "", "vxlan", "10.1.1.1/16", "10.1.1.254", 1) + verifyNetworkState(t, "default", "contiv", "data", "vxlan", "10.1.1.1", "10.1.1.254", 16, 1, 1) checkDeleteNetwork(t, false, "default", "contiv") + // Infra vlan network create and delete + checkCreateNetwork(t, false, "default", "infraNw", "infra", "vlan", "10.1.1.1/24", "10.1.1.254", 1) + time.Sleep(time.Second) + verifyNetworkState(t, "default", "infraNw", "infra", "vlan", "10.1.1.1", "10.1.1.254", 24, 1, 0) + checkDeleteNetwork(t, false, "default", "infraNw") + time.Sleep(time.Second) + + // Try creating network with invalid network type + checkCreateNetwork(t, true, "default", "infraNw", "infratest", "vlan", "10.1.1.1/24", "10.1.1.254", 1) + checkCreateNetwork(t, true, "default", "infraNw", "testinfra", "vlan", "10.1.1.1/24", "10.1.1.254", 1) + checkCreateNetwork(t, true, "default", "infraNw", "testdata", "vlan", "10.1.1.1/24", "10.1.1.254", 1) + checkCreateNetwork(t, true, "default", "infraNw", "datatest", "vlan", "10.1.1.1/24", "10.1.1.254", 1) + // Basic IP range network checks - checkCreateNetwork(t, false, "default", "contiv", "vxlan", "10.1.1.10-20/24", "10.1.1.254", 1) - verifyNetworkState(t, "default", "contiv", "vxlan", "10.1.1.10", "10.1.1.254", 24, 1, 1) + checkCreateNetwork(t, false, "default", "contiv", "data", "vxlan", "10.1.1.10-20/24", "10.1.1.254", 1) + verifyNetworkState(t, "default", "contiv", "data", "vxlan", "10.1.1.10", "10.1.1.254", 24, 1, 1) checkDeleteNetwork(t, false, "default", "contiv") // Try network create with invalid network range - checkCreateNetwork(t, true, "default", "contiv", "vxlan", "10.1.1.1-70/26", "10.1.1.63", 1) + checkCreateNetwork(t, true, "default", "contiv", "data", "vxlan", "10.1.1.1-70/26", "10.1.1.63", 1) // Try network create with invalid subnet length - checkCreateNetwork(t, true, "default", "contiv", "vxlan", "10.1.1.1/32", "10.1.1.1", 1) + checkCreateNetwork(t, true, "default", "contiv", "data", "vxlan", "10.1.1.1/32", "10.1.1.1", 1) // try creating network without tenant - checkCreateNetwork(t, true, "tenant1", "contiv", "vxlan", "10.1.1.1/24", "10.1.1.254", 1) + checkCreateNetwork(t, true, "tenant1", "contiv", "data", "vxlan", "10.1.1.1/24", "10.1.1.254", 1) // try invalid encap - checkCreateNetwork(t, true, "default", "contiv", "vvvv", "10.1.1.1/24", "10.1.1.254", 1) + checkCreateNetwork(t, true, "default", "contiv", "data", "vvvv", "10.1.1.1/24", "10.1.1.254", 1) // try invalid pkt tags - checkCreateNetwork(t, true, "default", "contiv", "vlan", "10.1.1.1/24", "10.1.1.254", 5000) - checkCreateNetwork(t, true, "default", "contiv", "vxlan", "10.1.1.1/24", "10.1.1.254", 20000) + checkCreateNetwork(t, true, "default", "contiv", "data", "vlan", "10.1.1.1/24", "10.1.1.254", 5000) + checkCreateNetwork(t, true, "default", "contiv", "data", "vxlan", "10.1.1.1/24", "10.1.1.254", 20000) // Try gateway outside the network - checkCreateNetwork(t, true, "default", "contiv", "vxlan", "10.1.1.1/24", "10.1.2.254", 1) - checkCreateNetwork(t, true, "default", "contiv", "vxlan", "10.1.1.65-70/26", "10.1.1.1", 2) + checkCreateNetwork(t, true, "default", "contiv", "data", "vxlan", "10.1.1.1/24", "10.1.2.254", 1) + checkCreateNetwork(t, true, "default", "contiv", "data", "vxlan", "10.1.1.65-70/26", "10.1.1.1", 2) // Try deleting a non-existing network checkDeleteNetwork(t, true, "default", "contiv") @@ -557,36 +571,36 @@ func TestGlobalSetting(t *testing.T) { // TestNetworkPktRanges tests pkt-tag ranges in network REST api func TestNetworkPktRanges(t *testing.T) { // verify auto allocation of vlans - checkCreateNetwork(t, false, "default", "contiv", "vlan", "10.1.1.1/24", "10.1.1.254", 0) - verifyNetworkState(t, "default", "contiv", "vlan", "10.1.1.1", "10.1.1.254", 24, 1, 0) + checkCreateNetwork(t, false, "default", "contiv", "data", "vlan", "10.1.1.1/24", "10.1.1.254", 0) + verifyNetworkState(t, "default", "contiv", "data", "vlan", "10.1.1.1", "10.1.1.254", 24, 1, 0) checkDeleteNetwork(t, false, "default", "contiv") // auto allocation of vxlan - checkCreateNetwork(t, false, "default", "contiv", "vxlan", "10.1.1.1/24", "10.1.1.254", 0) - verifyNetworkState(t, "default", "contiv", "vxlan", "10.1.1.1", "10.1.1.254", 24, 1, 1) - checkCreateNetwork(t, false, "default", "contiv2", "vxlan", "10.1.2.1/24", "10.1.2.254", 0) - verifyNetworkState(t, "default", "contiv2", "vxlan", "10.1.2.1", "10.1.2.254", 24, 2, 2) - checkCreateNetwork(t, false, "default", "contiv3", "vxlan", "10.1.3.1/24", "10.1.3.254", 1000) - verifyNetworkState(t, "default", "contiv3", "vxlan", "10.1.3.1", "10.1.3.254", 24, 3, 1000) + checkCreateNetwork(t, false, "default", "contiv", "data", "vxlan", "10.1.1.1/24", "10.1.1.254", 0) + verifyNetworkState(t, "default", "contiv", "data", "vxlan", "10.1.1.1", "10.1.1.254", 24, 1, 1) + checkCreateNetwork(t, false, "default", "contiv2", "data", "vxlan", "10.1.2.1/24", "10.1.2.254", 0) + verifyNetworkState(t, "default", "contiv2", "data", "vxlan", "10.1.2.1", "10.1.2.254", 24, 2, 2) + checkCreateNetwork(t, false, "default", "contiv3", "data", "vxlan", "10.1.3.1/24", "10.1.3.254", 1000) + verifyNetworkState(t, "default", "contiv3", "data", "vxlan", "10.1.3.1", "10.1.3.254", 24, 3, 1000) checkDeleteNetwork(t, false, "default", "contiv") checkDeleteNetwork(t, false, "default", "contiv2") checkDeleteNetwork(t, false, "default", "contiv3") // verify duplicate values fail - checkCreateNetwork(t, false, "default", "contiv1", "vlan", "10.1.1.1/24", "10.1.1.254", 1) - checkCreateNetwork(t, true, "default", "contiv2", "vlan", "10.1.1.1/24", "10.1.1.254", 1) + checkCreateNetwork(t, false, "default", "contiv1", "data", "vlan", "10.1.1.1/24", "10.1.1.254", 1) + checkCreateNetwork(t, true, "default", "contiv2", "data", "vlan", "10.1.1.1/24", "10.1.1.254", 1) checkDeleteNetwork(t, false, "default", "contiv1") - checkCreateNetwork(t, false, "default", "contiv1", "vxlan", "10.1.1.1/24", "10.1.1.254", 0) - checkCreateNetwork(t, true, "default", "contiv2", "vxlan", "10.1.1.1/24", "10.1.1.254", 1) + checkCreateNetwork(t, false, "default", "contiv1", "data", "vxlan", "10.1.1.1/24", "10.1.1.254", 0) + checkCreateNetwork(t, true, "default", "contiv2", "data", "vxlan", "10.1.1.1/24", "10.1.1.254", 1) checkDeleteNetwork(t, false, "default", "contiv1") // shrink ranges and try allocating checkGlobalSet(t, false, "default", "100-1000", "1001-2000") - checkCreateNetwork(t, true, "default", "contiv1", "vlan", "10.1.1.1/24", "10.1.1.254", 1001) - checkCreateNetwork(t, true, "default", "contiv1", "vlan", "10.1.1.1/24", "10.1.1.254", 99) - checkCreateNetwork(t, true, "default", "contiv2", "vxlan", "10.1.2.1/24", "10.1.2.254", 2001) - checkCreateNetwork(t, true, "default", "contiv2", "vxlan", "10.1.2.1/24", "10.1.2.254", 1000) + checkCreateNetwork(t, true, "default", "contiv1", "data", "vlan", "10.1.1.1/24", "10.1.1.254", 1001) + checkCreateNetwork(t, true, "default", "contiv1", "data", "vlan", "10.1.1.1/24", "10.1.1.254", 99) + checkCreateNetwork(t, true, "default", "contiv2", "data", "vxlan", "10.1.2.1/24", "10.1.2.254", 2001) + checkCreateNetwork(t, true, "default", "contiv2", "data", "vxlan", "10.1.2.1/24", "10.1.2.254", 1000) // reset back to default values checkGlobalSet(t, false, "default", "1-4094", "1-10000") @@ -657,7 +671,7 @@ func TestPolicyRules(t *testing.T) { // TestEpgPolicies tests attaching policy to EPG func TestEpgPolicies(t *testing.T) { // create network - checkCreateNetwork(t, false, "default", "contiv", "vxlan", "10.1.1.1/16", "10.1.1.254", 1) + checkCreateNetwork(t, false, "default", "contiv", "data", "vxlan", "10.1.1.1/16", "10.1.1.254", 1) // create policy checkCreatePolicy(t, false, "default", "policy1") diff --git a/netplugin/netd.go b/netplugin/netd.go index 28d756c0b..a90328426 100755 --- a/netplugin/netd.go +++ b/netplugin/netd.go @@ -28,10 +28,13 @@ import ( "github.com/contiv/netplugin/core" "github.com/contiv/netplugin/mgmtfn/dockplugin" "github.com/contiv/netplugin/mgmtfn/k8splugin" + "github.com/contiv/netplugin/netmaster/intent" + "github.com/contiv/netplugin/netmaster/master" "github.com/contiv/netplugin/netmaster/mastercfg" "github.com/contiv/netplugin/netplugin/cluster" "github.com/contiv/netplugin/netplugin/plugin" "github.com/contiv/netplugin/svcplugin" + "github.com/contiv/netplugin/utils/netutils" "github.com/contiv/netplugin/version" log "github.com/Sirupsen/logrus" @@ -70,6 +73,9 @@ func processCurrentState(netPlugin *plugin.NetPlugin, opts cliOpts) error { net := netCfg.(*mastercfg.CfgNetworkState) log.Debugf("read net key[%d] %s, populating state \n", idx, net.ID) processNetEvent(netPlugin, net, false) + if net.NwType == "infra" { + processInfraNwCreate(netPlugin, net, opts) + } } } @@ -98,6 +104,80 @@ func processCurrentState(netPlugin *plugin.NetPlugin, opts cliOpts) error { return nil } +// Process Infra Nw Create +// Auto allocate an endpoint for this node +func processInfraNwCreate(netPlugin *plugin.NetPlugin, nwCfg *mastercfg.CfgNetworkState, opts cliOpts) (err error) { + pluginHost := opts.hostLabel + + // Build endpoint request + mreq := master.CreateEndpointRequest{ + TenantName: nwCfg.Tenant, + NetworkName: nwCfg.NetworkName, + EndpointID: pluginHost, + ConfigEP: intent.ConfigEP{ + Container: pluginHost, + Host: pluginHost, + }, + } + + var mresp master.CreateEndpointResponse + err = cluster.MasterPostReq("/plugin/createEndpoint", &mreq, &mresp) + if err != nil { + log.Errorf("master failed to create endpoint %s", err) + return err + } + + log.Infof("Got endpoint create resp from master: %+v", mresp) + + // Take lock to ensure netPlugin processes only one cmd at a time + netPlugin.Lock() + defer func() { netPlugin.Unlock() }() + + // Ask netplugin to create the endpoint + netID := nwCfg.NetworkName + "." + nwCfg.Tenant + err = netPlugin.CreateEndpoint(netID + "-" + pluginHost) + if err != nil { + log.Errorf("Endpoint creation failed. Error: %s", err) + return err + } + + // Assign IP to interface + ipCIDR := fmt.Sprintf("%s/%d", mresp.EndpointConfig.IPAddress, nwCfg.SubnetLen) + err = netutils.SetInterfaceIP(nwCfg.NetworkName, ipCIDR) + if err != nil { + log.Errorf("Could not assign ip: %s", err) + return err + } + + return nil +} + +// Process Infra Nw Delete +// Delete the auto allocated endpoint +func processInfraNwDelete(netPlugin *plugin.NetPlugin, nwCfg *mastercfg.CfgNetworkState, opts cliOpts) (err error) { + pluginHost := opts.hostLabel + + // Build endpoint request + mreq := master.DeleteEndpointRequest{ + TenantName: nwCfg.Tenant, + NetworkName: nwCfg.NetworkName, + EndpointID: pluginHost, + } + + var mresp master.DeleteEndpointResponse + err = cluster.MasterPostReq("/plugin/deleteEndpoint", &mreq, &mresp) + if err != nil { + log.Errorf("master failed to delete endpoint %s", err) + return err + } + + log.Infof("Got endpoint create resp from master: %+v", mresp) + + // Network delete will take care of infra nw EP delete in plugin + + return +} + func processNetEvent(netPlugin *plugin.NetPlugin, nwCfg *mastercfg.CfgNetworkState, isDelete bool) (err error) { // take a lock to ensure we are programming one event at a time. @@ -109,7 +189,7 @@ func processNetEvent(netPlugin *plugin.NetPlugin, nwCfg *mastercfg.CfgNetworkSta operStr := "" if isDelete { - err = netPlugin.DeleteNetwork(nwCfg.ID, nwCfg.PktTagType, nwCfg.PktTag, nwCfg.ExtPktTag, + err = netPlugin.DeleteNetwork(nwCfg.ID, nwCfg.NwType, nwCfg.PktTagType, nwCfg.PktTag, nwCfg.ExtPktTag, nwCfg.Gateway, nwCfg.Tenant) operStr = "delete" } else { @@ -188,7 +268,17 @@ func processStateEvent(netPlugin *plugin.NetPlugin, opts cliOpts, rsps chan core } if nwCfg, ok := currentState.(*mastercfg.CfgNetworkState); ok { log.Infof("Received %q for network: %q", eventStr, nwCfg.ID) - processNetEvent(netPlugin, nwCfg, isDelete) + if isDelete != true { + processNetEvent(netPlugin, nwCfg, isDelete) + if nwCfg.NwType == "infra" { + processInfraNwCreate(netPlugin, nwCfg, opts) + } + } else { + if nwCfg.NwType == "infra" { + processInfraNwDelete(netPlugin, nwCfg, opts) + } + processNetEvent(netPlugin, nwCfg, isDelete) + } } if bgpCfg, ok := currentState.(*mastercfg.CfgBgpState); ok { log.Infof("Received %q for Bgp: %q", eventStr, bgpCfg.Hostname) diff --git a/netplugin/plugin/netplugin.go b/netplugin/plugin/netplugin.go index 5a57823a0..131bb1dbe 100755 --- a/netplugin/plugin/netplugin.go +++ b/netplugin/plugin/netplugin.go @@ -100,8 +100,8 @@ func (p *NetPlugin) CreateNetwork(id string) error { } // DeleteNetwork deletes a network provided by the ID. -func (p *NetPlugin) DeleteNetwork(id, encap string, pktTag, extPktTag int, Gw string, tenant string) error { - return p.NetworkDriver.DeleteNetwork(id, encap, pktTag, extPktTag, Gw, tenant) +func (p *NetPlugin) DeleteNetwork(id, nwType, encap string, pktTag, extPktTag int, Gw string, tenant string) error { + return p.NetworkDriver.DeleteNetwork(id, nwType, encap, pktTag, extPktTag, Gw, tenant) } // FetchNetwork retrieves a network's state given an ID. diff --git a/scripts/unittests b/scripts/unittests index 9a3b24013..d94564cb4 100755 --- a/scripts/unittests +++ b/scripts/unittests @@ -8,8 +8,6 @@ USAGE="${0} -vagrant" PATH=$PATH:/usr/local/go/bin -# time for vagrant folder sync -sleep 2 # copy certificates used for kubeclient UT cp -rf $GOSRC/github.com/contiv/netplugin/mgmtfn/k8splugin/certs /tmp run_in_vagrant=false @@ -58,6 +56,9 @@ if ${run_in_vagrant}; then exit 1 fi + # time for vagrant folder sync + sleep 2 + # XXX: running unit-tests require root permission due to dependence on ovs # utilities. Need to find a way without 'sudo'. (CONTIV_NODES=1 vagrant ssh netplugin-node1 -c 'sudo -E PATH=$PATH $GOSRC/github.com/contiv/netplugin/'${0}) @@ -76,6 +77,9 @@ if ${run_in_vagrant}; then exit 0 fi +cd $GOSRC/github.com/contiv/netplugin +find . -follow -type f -exec tail -1 {} \; >& /dev/null + for pkg in ${test_packages} do # running in the sand box diff --git a/systemtests/network_test.go b/systemtests/network_test.go index 3be8c2452..51f49fc97 100755 --- a/systemtests/network_test.go +++ b/systemtests/network_test.go @@ -10,6 +10,68 @@ import ( "time" ) +func (s *systemtestSuite) TestInfraNetworkAddDeleteVXLAN(c *C) { + s.testInfraNetworkAddDelete(c, "vxlan") +} + +func (s *systemtestSuite) TestInfraNetworkAddDeleteVLAN(c *C) { + s.testInfraNetworkAddDelete(c, "vlan") +} + +func (s *systemtestSuite) testInfraNetworkAddDelete(c *C, encap string) { + + if s.fwdMode == "routing" { + s.SetupBgp(c, false) + s.CheckBgpConnection(c) + } + + for i := 0; i < s.iterations; i++ { + var ( + netNames = []string{} + ) + + numInfraNw := 3 + for networkNum := 0; networkNum < numInfraNw; networkNum++ { + network := &client.Network{ + TenantName: "default", + NwType: "infra", + NetworkName: fmt.Sprintf("net%d", networkNum), + Subnet: fmt.Sprintf("10.1.%d.0/24", networkNum), + Gateway: fmt.Sprintf("10.1.%d.254", networkNum), + PktTag: 1001 + networkNum, + Encap: encap, + } + + c.Assert(s.cli.NetworkPost(network), IsNil) + + // TBD: Need to fix timing issue + // where endpoint create is received on non-master node + // before network create is received + time.Sleep(5 * time.Second) + + netNames = append(netNames, network.NetworkName) + } + + node1 := s.nodes[0] + + for networkNum := 0; networkNum < numInfraNw; networkNum++ { + // From first node, ping every node on this network + for nodeNum := 1; nodeNum <= len(s.nodes); nodeNum++ { + logrus.Infof("Running ping test for network %q node %d", netNames[networkNum], nodeNum) + ipaddr := fmt.Sprintf("10.1.%d.%d", networkNum, nodeNum) + c.Assert(node1.checkPing(ipaddr), IsNil) + + } + } + + for _, netName := range netNames { + c.Assert(s.cli.NetworkDelete("default", netName), IsNil) + } + + time.Sleep(5 * time.Second) + } +} + func (s *systemtestSuite) TestNetworkAddDeleteVXLAN(c *C) { s.testNetworkAddDelete(c, "vxlan") } diff --git a/systemtests/node_test.go b/systemtests/node_test.go index f911ab8cc..d777c85b0 100644 --- a/systemtests/node_test.go +++ b/systemtests/node_test.go @@ -203,3 +203,16 @@ func (n *node) runCommandUntilNoError(cmd string) error { _, err := utils.WaitForDone(runCmd, 10*time.Millisecond, 10*time.Second, timeoutMessage) return err } + +func (n *node) checkPing(ipaddr string) error { + logrus.Infof("Checking ping from %s to %s", n.Name(), ipaddr) + out, err := n.tbnode.RunCommandWithOutput("ping -c 1 " + ipaddr) + + if err != nil || strings.Contains(out, "0 received, 100% packet loss") { + logrus.Errorf("Ping from %s to %s FAILED: %q - %v", n.Name(), ipaddr, out, err) + return fmt.Errorf("Ping failed from %s to %s: %q - %v", n.Name(), ipaddr, out, err) + } + + logrus.Infof("Ping from %s to %s SUCCEEDED", n.Name(), ipaddr) + return nil +} diff --git a/utils/netutils/netutils.go b/utils/netutils/netutils.go index cdf9a8e3b..d448bf4f7 100644 --- a/utils/netutils/netutils.go +++ b/utils/netutils/netutils.go @@ -292,6 +292,20 @@ func GetInterfaceIP(linkName string) (string, error) { return localIPAddr, err } +// SetInterfaceIP : Set IP address of an interface +func SetInterfaceIP(name string, ipstr string) error { + iface, err := netlink.LinkByName(name) + if err != nil { + return err + } + ipaddr, err := netlink.ParseAddr(ipstr) + if err != nil { + return err + } + netlink.LinkSetUp(iface) + return netlink.AddrAdd(iface, ipaddr) +} + // SetInterfaceMac : Set mac address of an interface func SetInterfaceMac(name string, macaddr string) error { iface, err := netlink.LinkByName(name)