Skip to content

Instantly share code, notes, and snippets.

@abhi
Created January 21, 2016 03:56
Show Gist options
  • Save abhi/25babd9d158ed24f2910 to your computer and use it in GitHub Desktop.
Save abhi/25babd9d158ed24f2910 to your computer and use it in GitHub Desktop.
l3 bgp integration for contiv
diff --git a/ofctrl/fgraphTable.go b/ofctrl/fgraphTable.go
old mode 100644
new mode 100755
index 9cc8592..96daacb
--- a/ofctrl/fgraphTable.go
+++ b/ofctrl/fgraphTable.go
@@ -17,29 +17,28 @@ package ofctrl
// This file implements the forwarding graph API for the table
import (
- "errors"
+ "errors"
- "github.com/shaleman/libOpenflow/openflow13"
+ "github.com/shaleman/libOpenflow/openflow13"
- log "github.com/Sirupsen/logrus"
+ log "github.com/Sirupsen/logrus"
)
// Fgraph table element
type Table struct {
- Switch *OFSwitch
- TableId uint8
- flowDb map[string]*Flow // database of flow entries
+ Switch *OFSwitch
+ TableId uint8
+ flowDb map[string]*Flow // database of flow entries
}
-
// Fgraph element type for table
func (self *Table) Type() string {
- return "table"
+ return "table"
}
// instruction set for table element
func (self *Table) GetFlowInstr() openflow13.Instruction {
- return openflow13.NewInstrGotoTable(self.TableId)
+ return openflow13.NewInstrGotoTable(self.TableId)
}
// FIXME: global unique flow cookie
@@ -47,44 +46,46 @@ var globalFlowId uint64 = 1
// Create a new flow on the table
func (self *Table) NewFlow(match FlowMatch) (*Flow, error) {
- flow := new(Flow)
- flow.Table = self
- flow.Match = match
- flow.isInstalled = false
- flow.flowId = globalFlowId // FIXME: need a better id allocation
- globalFlowId += 1
- flow.flowActions = make([]*FlowAction, 0)
-
- log.Infof("Creating new flow for match: %+v", match)
-
- // See if the flow already exists
- flowKey := flow.flowKey()
- if (self.flowDb[flowKey] != nil) {
- log.Errorf("Flow %s already exists", flowKey)
- return nil, errors.New("Flow already exists")
- }
-
- log.Infof("Added flow: %s", flowKey)
-
- // Save it in DB. We dont install the flow till its next graph elem is set
- self.flowDb[flowKey] = flow
-
- return flow, nil
+ flow := new(Flow)
+ flow.Table = self
+ flow.Match = match
+ flow.isInstalled = false
+ flow.flowId = globalFlowId // FIXME: need a better id allocation
+ globalFlowId += 1
+ flow.flowActions = make([]*FlowAction, 0)
+
+ log.Infof("Creating new flow for match: %+v", match)
+
+ // See if the flow already exists
+ flowKey := flow.flowKey()
+ log.Infof(" new flow key for match: %+v", flowKey)
+
+ if self.flowDb[flowKey] != nil {
+ log.Errorf("Flow %s already exists", flowKey)
+ return nil, errors.New("Flow already exists")
+ }
+
+ log.Infof("Added flow: %s", flowKey)
+
+ // Save it in DB. We dont install the flow till its next graph elem is set
+ self.flowDb[flowKey] = flow
+
+ return flow, nil
}
// Delete a flow from the table
func (self *Table) DeleteFlow(flowKey string) error {
- // first empty it and then delete it.
- self.flowDb[flowKey] = nil
- delete(self.flowDb, flowKey)
+ // first empty it and then delete it.
+ self.flowDb[flowKey] = nil
+ delete(self.flowDb, flowKey)
- log.Infof("Deleted flow: %s", flowKey)
+ log.Infof("Deleted flow: %s", flowKey)
- return nil
+ return nil
}
// Delete the table
func (self *Table) Delete() error {
- // FIXME: Delete the table
- return nil
+ // FIXME: Delete the table
+ return nil
}
diff --git a/ofnet.go b/ofnet.go
old mode 100644
new mode 100755
index 362311d..4a2bfab
--- a/ofnet.go
+++ b/ofnet.go
@@ -61,11 +61,40 @@ type OfnetDatapath interface {
// Remove a vlan
RemoveVlan(vlanId uint16, vni uint32) error
+
+ //Add uplink port
+ AddUplink(portNo uint32) error
+
+ //Delete uplink port
+ RemoveUplink(portNo uint32) error
+}
+
+// Interface implemented by each control protocol.
+type OfnetProto interface {
+
+ //Create a protocol server
+ StartProtoServer(routerInfo OfnetProtoRouterInfo) error
+
+ //Add a Protocol Neighbor
+ AddProtoNeighbor(neighborInfo *OfnetProtoNeighborInfo) error
+
+ //Delete a Protocol Neighbor
+ DeleteProtoNeighbor() error
+
+ //Get Protocol router info
+ GetRouterInfo() *OfnetProtoRouterInfo
+
+ //Add Local Route
+ AddLocalProtoRoute(path *OfnetProtoRouteInfo) error
+
+ //Delete Local Route
+ DeleteLocalProtoRoute(path *OfnetProtoRouteInfo) error
}
// Default port numbers
const OFNET_MASTER_PORT = 9001
-const OFNET_AGENT_PORT = 9002
+const OFNET_AGENT_VXLAN_PORT = 9002
+const OFNET_AGENT_VLAN_PORT = 9010
// Information about each node
type OfnetNode struct {
@@ -79,6 +108,7 @@ type OfnetEndpoint struct {
EndpointType string // Type of the endpoint "internal", "external" or "externalRoute"
EndpointGroup int // Endpoint group identifier for policies.
IpAddr net.IP // IP address of the end point
+ IpMask net.IP // IP mask for the end point
VrfId uint16 // IP address namespace
MacAddrStr string // Mac address of the end point(in string format)
Vlan uint16 // Vlan Id for the endpoint
@@ -102,3 +132,21 @@ type OfnetPolicyRule struct {
TcpFlags string // TCP flags to match: syn || syn,ack || ack || syn,!ack || !syn,ack;
Action string // rule action: 'accept' or 'deny'
}
+
+type OfnetProtoNeighborInfo struct {
+ ProtocolType string // type of protocol
+ NeighborIP string // ip address of the neighbor
+ As string // As of neighbor if applicable
+}
+
+type OfnetProtoRouterInfo struct {
+ ProtocolType string // type of protocol
+ RouterIP string // ip address of the neighbor
+ VlanIntf string // uplink L2 intf
+}
+
+type OfnetProtoRouteInfo struct {
+ ProtocolType string // type of protocol
+ localEpIP string
+ nextHopIP string
+}
diff --git a/ofnetAgent.go b/ofnetAgent.go
old mode 100644
new mode 100755
index 4be071d..491aa3e
--- a/ofnetAgent.go
+++ b/ofnetAgent.go
@@ -26,14 +26,13 @@ package ofnet
import (
"errors"
"fmt"
+ log "github.com/Sirupsen/logrus"
+ "github.com/contiv/ofnet/ofctrl"
+ "github.com/contiv/ofnet/ovsdbDriver"
+ "github.com/contiv/ofnet/rpcHub"
"net"
"net/rpc"
"time"
-
- "github.com/contiv/ofnet/ofctrl"
- "github.com/contiv/ofnet/rpcHub"
-
- log "github.com/Sirupsen/logrus"
)
// OfnetAgent state
@@ -44,10 +43,10 @@ type OfnetAgent struct {
MyPort uint16 // Port where the agent's RPC server is listening
MyAddr string // RPC server addr. same as localIp. different in testing environments
isConnected bool // Is the switch connected
-
- rpcServ *rpc.Server // jsonrpc server
- rpcListener net.Listener // Listener
- datapath OfnetDatapath // Configured datapath
+ rpcServ *rpc.Server // jsonrpc server
+ rpcListener net.Listener // Listener
+ datapath OfnetDatapath // Configured datapath
+ protopath OfnetProto // Configured protopath
masterDb map[string]*OfnetNode // list of Masters
@@ -62,6 +61,8 @@ type OfnetAgent struct {
// Endpoint database
endpointDb map[string]*OfnetEndpoint // all known endpoints
localEndpointDb map[uint32]*OfnetEndpoint // local port to endpoint map
+
+ ovsDriver *ovsdbDriver.OvsDriver
}
// local End point information
@@ -71,6 +72,7 @@ type EndpointInfo struct {
MacAddr net.HardwareAddr
Vlan uint16
IpAddr net.IP
+ VrfId uint16
}
const FLOW_MATCH_PRIORITY = 100 // Priority for all match flows
@@ -85,7 +87,11 @@ const IP_TBL_ID = 4
const MAC_DEST_TBL_ID = 5
// Create a new Ofnet agent and initialize it
-func NewOfnetAgent(dpName string, localIp net.IP, rpcPort uint16, ovsPort uint16) (*OfnetAgent, error) {
+/*routerInfo[0] - > IP of the router intf
+ routerInfo[1] -> Uplink nexthop interface
+*/
+func NewOfnetAgent(dpName string, localIp net.IP, rpcPort uint16,
+ ovsPort uint16, routerInfo ...string) (*OfnetAgent, error) {
agent := new(OfnetAgent)
// Init params
@@ -128,6 +134,11 @@ func NewOfnetAgent(dpName string, localIp net.IP, rpcPort uint16, ovsPort uint16
agent.datapath = NewVxlan(agent, rpcServ)
case "vlan":
agent.datapath = NewVlanBridge(agent, rpcServ)
+ case "vlrouter":
+ agent.datapath = NewVlrouter(agent, rpcServ)
+ agent.ovsDriver = ovsdbDriver.NewOvsDriver("contivVlanBridge")
+ agent.protopath = NewOfnetBgp(agent, routerInfo)
+
default:
log.Fatalf("Unknown Datapath %s", dpName)
}
@@ -280,7 +291,7 @@ func (self *OfnetAgent) RemoveMaster(masterInfo *OfnetNode) error {
}
// Add a local endpoint.
-// This takes ofp port number, mac address, vlan and IP address of the port.
+// This takes ofp port number, mac address, vlan , VrfId and IP address of the port.
func (self *OfnetAgent) AddLocalEndpoint(endpoint EndpointInfo) error {
// Add port vlan mapping
self.portVlanMap[endpoint.PortNo] = &endpoint.Vlan
@@ -300,7 +311,8 @@ func (self *OfnetAgent) AddLocalEndpoint(endpoint EndpointInfo) error {
EndpointType: "internal",
EndpointGroup: endpoint.EndpointGroup,
IpAddr: endpoint.IpAddr,
- VrfId: 0, // FIXME set VRF correctly
+ IpMask: net.ParseIP("255.255.255.255"),
+ VrfId: endpoint.Vlan, //This has to be changed to vrfId when there is multi network per vrf support
MacAddrStr: endpoint.MacAddr.String(),
Vlan: endpoint.Vlan,
Vni: *vni,
@@ -415,19 +427,33 @@ func (self *OfnetAgent) RemoveVtepPort(portNo uint32, remoteIp net.IP) error {
return self.datapath.RemoveVtepPort(portNo, remoteIp)
}
-// Add a vlan.
-// This is mainly used for mapping vlan id to Vxlan VNI
-func (self *OfnetAgent) AddVlan(vlanId uint16, vni uint32) error {
+// Add a Network.
+// This is mainly used for mapping vlan id to Vxlan VNI and add gateway for network
+func (self *OfnetAgent) AddNetwork(vlanId uint16, vni uint32, Gw string) error {
// store it in DB
self.vlanVniMap[vlanId] = &vni
self.vniVlanMap[vni] = &vlanId
+ if Gw != "" {
+ // Call the datapath
+ epreg := &OfnetEndpoint{
+ EndpointID: Gw,
+ EndpointType: "internal",
+ IpAddr: net.ParseIP(Gw),
+ IpMask: net.ParseIP("255.255.255.255"),
+ VrfId: 0, // FIXME set VRF correctly
+ Vlan: 1,
+ PortNo: 0,
+ Timestamp: time.Now(),
+ }
+ self.endpointDb[Gw] = epreg
+ return self.datapath.AddVlan(vlanId, vni)
+ }
+ return nil
- // Call the datapath
- return self.datapath.AddVlan(vlanId, vni)
}
// Remove a vlan from datapath
-func (self *OfnetAgent) RemoveVlan(vlanId uint16, vni uint32) error {
+func (self *OfnetAgent) RemoveNetwork(vlanId uint16, vni uint32, Gw string) error {
// Clear the database
delete(self.vlanVniMap, vlanId)
delete(self.vniVlanMap, vni)
@@ -438,6 +464,7 @@ func (self *OfnetAgent) RemoveVlan(vlanId uint16, vni uint32) error {
log.Fatalf("Vlan %d still has routes. Route: %+v", vlanId, endpoint)
}
}
+ delete(self.endpointDb, Gw)
// Call the datapath
return self.datapath.RemoveVlan(vlanId, vni)
@@ -517,3 +544,42 @@ func (self *OfnetAgent) DummyRpc(arg *string, ret *bool) error {
log.Infof("Received dummy route RPC call")
return nil
}
+
+//AddBgpNeighbors add bgp neighbor
+func (self *OfnetAgent) AddBgpNeighbors(As string, peer string) error {
+
+ neighborInfo := &OfnetProtoNeighborInfo{
+ ProtocolType: "bgp",
+ NeighborIP: peer,
+ As: As,
+ }
+ return self.protopath.AddProtoNeighbor(neighborInfo)
+}
+
+func (self *OfnetAgent) DeleteBgpNeighbors() error {
+ return self.protopath.DeleteProtoNeighbor()
+}
+
+func (self *OfnetAgent) GetRouterInfo() *OfnetProtoRouterInfo {
+ return self.protopath.GetRouterInfo()
+}
+
+func (self *OfnetAgent) AddLocalProtoRoute(path *OfnetProtoRouteInfo) {
+ if self.protopath != nil {
+ self.protopath.AddLocalProtoRoute(path)
+ }
+}
+
+func (self *OfnetAgent) DeleteLocalProtoRoute(path *OfnetProtoRouteInfo) {
+ if self.protopath != nil {
+ self.protopath.DeleteLocalProtoRoute(path)
+ }
+}
+
+func (self *OfnetAgent) AddUplink(portNo uint32) error {
+ return self.datapath.AddUplink(portNo)
+}
+
+func (self *OfnetAgent) RemoveUplink(portNo uint32) error {
+ return self.datapath.RemoveUplink(portNo)
+}
diff --git a/ofnetBgp.go b/ofnetBgp.go
new file mode 100755
index 0000000..2eccf90
--- /dev/null
+++ b/ofnetBgp.go
@@ -0,0 +1,682 @@
+/***
+Copyright 2014 Cisco Systems Inc. All rights reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+package ofnet
+
+import (
+ "errors"
+ "fmt"
+ "io"
+ "net"
+ "os/exec"
+ "strconv"
+ "time"
+
+ "container/list"
+ log "github.com/Sirupsen/logrus"
+
+ api "github.com/osrg/gobgp/api"
+ bgpconf "github.com/osrg/gobgp/config"
+ "github.com/osrg/gobgp/packet"
+ bgpserver "github.com/osrg/gobgp/server"
+ "github.com/vishvananda/netlink"
+ "golang.org/x/net/context"
+
+ "google.golang.org/grpc"
+)
+
+type OfnetBgp struct {
+ routerIP string // virtual interface ip for bgp
+ vlanIntf string // uplink port name
+ agent *OfnetAgent // Pointer back to ofnet agent that owns this
+
+ //bgp resources
+ modRibCh chan *api.Path //channel for route change notif
+ advPathCh chan *api.Path
+ bgpServer *bgpserver.BgpServer // bgp server instance
+ grpcServer *bgpserver.Server // grpc server to talk to gobgp
+
+ myRouterMac net.HardwareAddr //Router mac used for external proxy
+ myBgpPeer string // bgp neighbor
+ unresolvedEPs *list.List // unresolved endpoint list
+ cc *grpc.ClientConn //grpc client connection
+
+}
+
+// Create a new vlrouter instance
+func NewOfnetBgp(agent *OfnetAgent, routerInfo []string) *OfnetBgp {
+
+ //Sanity checks
+ if agent == nil || agent.datapath == nil {
+ log.Errorf("Invilid OfnetAgent")
+ return nil
+ }
+
+ ofnetBgp := new(OfnetBgp)
+ // Keep a reference to the agent
+ ofnetBgp.agent = agent
+
+ if len(routerInfo) > 1 {
+ //Ensuring routerInfo is in ip format
+ if ok := net.ParseIP(routerInfo[0]); ok != nil {
+ ofnetBgp.routerIP = routerInfo[0]
+ } else {
+ log.Errorf("Error creating ofnetBgp")
+ return nil
+ }
+ ofnetBgp.vlanIntf = routerInfo[1]
+ }
+
+ ofnetBgp.bgpServer, ofnetBgp.grpcServer = createBgpServer()
+
+ if ofnetBgp.bgpServer == nil || ofnetBgp.grpcServer == nil {
+ log.Errorf("Error instantiating Bgp server")
+ return nil
+ }
+ //go routine to start gobgp server
+ go func() {
+ rInfo := OfnetProtoRouterInfo{ProtocolType: "bgp", RouterIP: ofnetBgp.routerIP}
+ err := ofnetBgp.StartProtoServer(rInfo)
+ if err != nil {
+ log.Errorf("protocol server finished with err: %s", err)
+ }
+ }()
+ return ofnetBgp
+}
+
+/*
+Bgp serve routine does the following:
+1) Creates inb01 router port
+2) Add MyBgp endpoint
+3) Kicks off routines to monitor route updates and peer state
+*/
+func (self *OfnetBgp) StartProtoServer(routerInfo OfnetProtoRouterInfo) error {
+ time.Sleep(5 * time.Second)
+ self.agent.WaitForSwitchConnection()
+
+ self.modRibCh = make(chan *api.Path, 16)
+ self.advPathCh = make(chan *api.Path, 16)
+
+ timeout := grpc.WithTimeout(time.Second)
+ conn, err := grpc.Dial("127.0.0.1:8080", timeout, grpc.WithBlock(), grpc.WithInsecure())
+ if err != nil {
+ log.Fatal(err)
+ }
+ self.cc = conn
+ defer self.cc.Close()
+
+ client := api.NewGobgpApiClient(self.cc)
+ if client == nil {
+ log.Errorf("Invalid Gobgpapi client")
+ return errors.New("Error creating Gobgpapiclient")
+ }
+ path := &api.Path{
+ Pattrs: make([][]byte, 0),
+ }
+
+ if len(routerInfo.RouterIP) == 0 {
+ log.Errorf("Invalid router IP. Bgp service aborted")
+ return errors.New("Invalid router IP")
+ }
+ path.Nlri, _ = bgp.NewIPAddrPrefix(uint8(32), routerInfo.RouterIP).Serialize()
+ n, _ := bgp.NewPathAttributeNextHop("0.0.0.0").Serialize()
+ path.Pattrs = append(path.Pattrs, n)
+ origin, _ := bgp.NewPathAttributeOrigin(bgp.BGP_ORIGIN_ATTR_TYPE_INCOMPLETE).Serialize()
+ path.Pattrs = append(path.Pattrs, origin)
+
+ err = self.agent.ovsDriver.CreatePort("inb01", "internal", 1)
+ if err != nil {
+ log.Errorf("Error creating the port", err)
+ return err
+ }
+
+ cmd := exec.Command("ifconfig", "inb01", routerInfo.RouterIP+"/24")
+ cmd.Run()
+
+ intf, _ := net.InterfaceByName("inb01")
+ ofPortno, _ := self.agent.ovsDriver.GetOfpPortNo("inb01")
+
+ if intf == nil || ofPortno == 0 {
+ log.Errorf("Error fetching inb01 information", intf, ofPortno)
+ return errors.New("Unable to fetch inb01 info")
+ }
+
+ epreg := &OfnetEndpoint{
+ EndpointID: routerInfo.RouterIP,
+ EndpointType: "internal-bgp",
+ IpAddr: net.ParseIP(routerInfo.RouterIP),
+ IpMask: net.ParseIP("255.255.255.255"),
+ VrfId: 0, // FIXME set VRF correctly
+ MacAddrStr: intf.HardwareAddr.String(), //link.Attrs().HardwareAddr.String(),
+ Vlan: 1,
+ PortNo: ofPortno,
+ Timestamp: time.Now(),
+ }
+ // Add the endpoint to local routing table
+ self.agent.endpointDb[routerInfo.RouterIP] = epreg
+ self.agent.localEndpointDb[epreg.PortNo] = epreg
+ fmt.Println(epreg)
+ err = self.agent.datapath.AddLocalEndpoint(*epreg)
+
+ uplink, _ := self.agent.ovsDriver.GetOfpPortNo(self.vlanIntf)
+ self.agent.AddUplink(uplink)
+
+ //Add bgp router id as well
+ bgpGlobalCfg := &bgpconf.Global{}
+ setDefaultGlobalConfigValues(bgpGlobalCfg)
+ bgpGlobalCfg.GlobalConfig.RouterId = net.ParseIP(routerInfo.RouterIP)
+ bgpGlobalCfg.GlobalConfig.As = 65002
+ self.bgpServer.SetGlobalType(*bgpGlobalCfg)
+
+ self.advPathCh <- path
+
+ //monitor route updates from peer
+ go self.monitorBest()
+ //monitor peer state
+ go self.monitorPeer()
+
+ for {
+ select {
+ case p := <-self.modRibCh:
+ err = self.modRib(p)
+ if err != nil {
+ log.Error("failed to mod rib: ", err)
+ }
+ }
+ }
+}
+
+//DeleteProtoNeighbor deletes bgp neighbor for the host
+func (self *OfnetBgp) DeleteProtoNeighbor() error {
+
+ /*As a part of delete bgp neighbors
+ 1) Search for BGP peer and remove from Bgp.
+ 2) Delete endpoint info for peer
+ 3) Finally delete all routes learnt on the nexthop bgp port.
+ 4) Mark the routes learn via json rpc as unresolved
+ */
+ log.Infof("Received DeleteProtoNeighbor to delete bgp neighbor %v", self.myBgpPeer)
+ client := api.NewGobgpApiClient(self.cc)
+ if client == nil {
+ log.Errorf("Invalid Gobgpapi client")
+ return errors.New("Error creating Gobgpapiclient")
+ }
+ arg := &api.Arguments{Name: self.myBgpPeer}
+
+ peer, err := client.GetNeighbor(context.Background(), arg)
+ if err != nil {
+ log.Errorf("GetNeighbor failed ", err)
+ return err
+ }
+ log.Infof("Deleteing Bgp peer from Bgp server")
+ p := bgpconf.Neighbor{}
+ setNeighborConfigValues(&p)
+
+ p.NeighborAddress = net.ParseIP(peer.Conf.NeighborAddress)
+ p.NeighborConfig.NeighborAddress = net.ParseIP(peer.Conf.NeighborAddress)
+ p.NeighborConfig.PeerAs = uint32(peer.Conf.PeerAs)
+ //FIX ME set ipv6 depending on peerip (for v6 BGP)
+ p.AfiSafis.AfiSafiList = []bgpconf.AfiSafi{
+ bgpconf.AfiSafi{AfiSafiName: "ipv4-unicast"}}
+ self.bgpServer.SetBmpConfig(bgpconf.BmpServers{
+ BmpServerList: []bgpconf.BmpServer{},
+ })
+
+ self.bgpServer.PeerDelete(p)
+
+ bgpEndpoint := self.agent.getEndpointByIp(net.ParseIP(self.myBgpPeer))
+ self.agent.datapath.RemoveEndpoint(bgpEndpoint)
+ delete(self.agent.endpointDb, self.myBgpPeer)
+
+ uplink, _ := self.agent.ovsDriver.GetOfpPortNo(self.vlanIntf)
+
+ for _, endpoint := range self.agent.endpointDb {
+ if endpoint.PortNo == uplink {
+ self.agent.datapath.RemoveEndpoint(endpoint)
+ if endpoint.EndpointType == "internal" {
+ endpoint.PortNo = 0
+ self.agent.endpointDb[endpoint.EndpointID] = endpoint
+ //We readd unresolved endpoints that were learnt via
+ //etcd
+ self.agent.datapath.AddEndpoint(endpoint)
+ } else if endpoint.EndpointType == "external" {
+ delete(self.agent.endpointDb, endpoint.EndpointID)
+ }
+ }
+ }
+ return nil
+}
+
+//AddProtoNeighbor adds bgp neighbor
+func (self *OfnetBgp) AddProtoNeighbor(neighborInfo *OfnetProtoNeighborInfo) error {
+
+ log.Infof("Received AddProtoNeighbor to Add bgp neighbor %v", neighborInfo.NeighborIP)
+
+ var policyConfig bgpconf.RoutingPolicy
+
+ peerAs, _ := strconv.Atoi(neighborInfo.As)
+ p := &bgpconf.Neighbor{}
+ setNeighborConfigValues(p)
+ p.NeighborAddress = net.ParseIP(neighborInfo.NeighborIP)
+ p.NeighborConfig.NeighborAddress = net.ParseIP(neighborInfo.NeighborIP)
+ p.NeighborConfig.PeerAs = uint32(peerAs)
+ //FIX ME set ipv6 depending on peerip (for v6 BGP)
+ p.AfiSafis.AfiSafiList = []bgpconf.AfiSafi{
+ bgpconf.AfiSafi{AfiSafiName: "ipv4-unicast"}}
+ self.bgpServer.SetBmpConfig(bgpconf.BmpServers{
+ BmpServerList: []bgpconf.BmpServer{},
+ })
+
+ self.bgpServer.PeerAdd(*p)
+ // if policyConfig == nil {
+ //policyConfig = &newConfig.Policy
+ self.bgpServer.SetPolicy(policyConfig)
+ // } else {
+ //if bgpconf.CheckPolicyDifference(policyConfig, &newConfig.Policy) {
+ // log.Info("Policy config is updated")
+ // bgpServer.UpdatePolicy(newConfig.Policy)
+ //}
+ // }
+
+ log.Infof("Peer %v is added", p.NeighborConfig.NeighborAddress)
+
+ epreg := &OfnetEndpoint{
+ EndpointID: neighborInfo.NeighborIP,
+ EndpointType: "external-bgp",
+ IpAddr: net.ParseIP(neighborInfo.NeighborIP),
+ IpMask: net.ParseIP("255.255.255.255"),
+ VrfId: 0, // FIXME set VRF correctly
+ Vlan: 1,
+ Timestamp: time.Now(),
+ }
+
+ // Install the endpoint in datapath
+ // First, add the endpoint to local routing table
+ self.agent.endpointDb[epreg.EndpointID] = epreg
+ err := self.agent.datapath.AddEndpoint(epreg)
+
+ if err != nil {
+ log.Errorf("Error adding endpoint: {%+v}. Err: %v", epreg, err)
+ return err
+ }
+ self.myBgpPeer = neighborInfo.NeighborIP
+
+ return nil
+}
+
+//GetRouterInfo returns the configured RouterInfo
+func (self *OfnetBgp) GetRouterInfo() *OfnetProtoRouterInfo {
+ routerInfo := &OfnetProtoRouterInfo{
+ ProtocolType: "bgp",
+ RouterIP: self.routerIP,
+ VlanIntf: self.vlanIntf,
+ }
+ return routerInfo
+}
+
+//AddLocalProtoRoute is used to add local endpoint to the protocol RIB
+func (self *OfnetBgp) AddLocalProtoRoute(pathInfo *OfnetProtoRouteInfo) error {
+
+ log.Infof("Received AddLocalProtoRoute to add local endpoint to protocol RIB: %v", pathInfo)
+
+ path := &api.Path{
+ Pattrs: make([][]byte, 0),
+ }
+
+ // form the path structure with appropriate path attributes
+ nlri := bgp.NewIPAddrPrefix(32, pathInfo.localEpIP)
+ path.Nlri, _ = nlri.Serialize()
+ origin, _ := bgp.NewPathAttributeOrigin(bgp.BGP_ORIGIN_ATTR_TYPE_EGP).Serialize()
+ path.Pattrs = append(path.Pattrs, origin)
+ aspathParam := []bgp.AsPathParamInterface{bgp.NewAs4PathParam(2, []uint32{65002})}
+ aspath, _ := bgp.NewPathAttributeAsPath(aspathParam).Serialize()
+ path.Pattrs = append(path.Pattrs, aspath)
+ n, _ := bgp.NewPathAttributeNextHop(pathInfo.nextHopIP).Serialize()
+ path.Pattrs = append(path.Pattrs, n)
+
+ name := ""
+
+ arg := &api.ModPathArguments{
+ Resource: api.Resource_GLOBAL,
+ Name: name,
+ Paths: []*api.Path{path},
+ }
+
+ //send arguement stream
+ client := api.NewGobgpApiClient(self.cc)
+ if client == nil {
+ log.Errorf("Gobgpapi stream invalid")
+ return nil
+ }
+
+ stream, err := client.ModPath(context.Background())
+ if err != nil {
+ log.Errorf("Fail to enforce Modpathi", err)
+ return err
+ }
+
+ err = stream.Send(arg)
+ if err != nil {
+ log.Errorf("Failed to send strean", err)
+ return err
+ }
+ stream.CloseSend()
+ res, e := stream.CloseAndRecv()
+ if e != nil {
+ log.Errorf("Falied toclose stream ")
+ return e
+ }
+ if res.Code != api.Error_SUCCESS {
+ return fmt.Errorf("error: code: %d, msg: %s", res.Code, res.Msg)
+ }
+ return nil
+}
+
+//DeleteLocalProtoRoute withdraws local endpoints from protocol RIB
+func (self *OfnetBgp) DeleteLocalProtoRoute(pathInfo *OfnetProtoRouteInfo) error {
+
+ log.Infof("Received DeleteLocalProtoRoute to withdraw local endpoint to protocol RIB: %v", pathInfo)
+
+ path := &api.Path{
+ Pattrs: make([][]byte, 0),
+ }
+
+ //form appropraite path attributes for path to be withdrawn
+ nlri := bgp.NewIPAddrPrefix(32, pathInfo.localEpIP)
+ path.Nlri, _ = nlri.Serialize()
+ origin, _ := bgp.NewPathAttributeOrigin(bgp.BGP_ORIGIN_ATTR_TYPE_EGP).Serialize()
+ path.Pattrs = append(path.Pattrs, origin)
+ aspathParam := []bgp.AsPathParamInterface{bgp.NewAs4PathParam(2, []uint32{65002})}
+ aspath, _ := bgp.NewPathAttributeAsPath(aspathParam).Serialize()
+ path.Pattrs = append(path.Pattrs, aspath)
+ n, _ := bgp.NewPathAttributeNextHop(pathInfo.nextHopIP).Serialize()
+ path.Pattrs = append(path.Pattrs, n)
+ path.IsWithdraw = true
+ name := ""
+
+ arg := &api.ModPathArguments{
+ Resource: api.Resource_GLOBAL,
+ Name: name,
+ Paths: []*api.Path{path},
+ }
+
+ //send arguement stream
+ client := api.NewGobgpApiClient(self.cc)
+ if client == nil {
+ log.Errorf("Gobgpapi stream invalid")
+ return nil
+ }
+
+ stream, err := client.ModPath(context.Background())
+ log.Infof("The stream is ", stream)
+ if err != nil {
+ log.Errorf("Fail to enforce Modpathi", err)
+ return err
+ }
+ err = stream.Send(arg)
+ if err != nil {
+ log.Errorf("Failed to send strean", err)
+ return err
+ }
+ stream.CloseSend()
+ res, e := stream.CloseAndRecv()
+ if e != nil {
+ log.Errorf("Falied toclose stream ")
+ return e
+ }
+ if res.Code != api.Error_SUCCESS {
+ return fmt.Errorf("error: code: %d, msg: %s", res.Code, res.Msg)
+ }
+ return nil
+}
+
+//monitorBest monitors for route updates/changes form peer
+func (self *OfnetBgp) monitorBest() error {
+
+ client := api.NewGobgpApiClient(self.cc)
+ if client == nil {
+ log.Errorf("Invalid Gobgpapi client")
+ return errors.New("Error creating Gobgpapiclient")
+ }
+ arg := &api.Arguments{
+ Resource: api.Resource_GLOBAL,
+ Rf: uint32(bgp.RF_IPv4_UC),
+ }
+
+ stream, err := client.MonitorBestChanged(context.Background(), arg)
+ if err != nil {
+ return err
+ }
+
+ for {
+ dst, err := stream.Recv()
+ if err == io.EOF {
+ break
+ } else if err != nil {
+ return err
+ }
+
+ self.modRibCh <- dst.Paths[0]
+ }
+ return nil
+}
+
+// monitorPeer is used to monitor the bgp peer state
+func (self *OfnetBgp) monitorPeer() error {
+
+ var oldAdminState, oldState string
+
+ client := api.NewGobgpApiClient(self.cc)
+ if client == nil {
+ log.Errorf("Invalid Gobgpapi client")
+ return errors.New("Error creating Gobgpapiclient")
+ }
+ arg := &api.Arguments{}
+
+ stream, err := client.MonitorPeerState(context.Background(), arg)
+ if err != nil {
+ log.Errorf("MonitorPeerState failed ", err)
+ return err
+ }
+ for {
+ s, err := stream.Recv()
+ if err == io.EOF {
+ break
+ } else if err != nil {
+ log.Errorf("MonitorPeerState stream failed :", err)
+ break
+ }
+ fmt.Printf("[NEIGH] %s fsm: %s admin: %s\n", s.Conf.NeighborAddress,
+ s.Info.BgpState, s.Info.AdminState)
+ if oldState == "BGP_FSM_ESTABLISHED" && oldAdminState == "ADMIN_STATE_UP" {
+ uplink, _ := self.agent.ovsDriver.GetOfpPortNo(self.vlanIntf)
+ /*If the state changed from being established to idle or active:
+ 1) delete all endpoints learnt via bgp Peer
+ 2) mark routes pointing to the bgp nexthop as unresolved
+ 3) mark the bgp peer reachbility as unresolved
+ */
+ for _, endpoint := range self.agent.endpointDb {
+ if endpoint.PortNo == uplink {
+ self.agent.datapath.RemoveEndpoint(endpoint)
+ if endpoint.EndpointType == "internal" {
+ endpoint.PortNo = 0
+ self.agent.endpointDb[endpoint.EndpointID] = endpoint
+ //We readd unresolved endpoints that were learnt via
+ //json rpc
+ self.agent.datapath.AddEndpoint(endpoint)
+ } else if endpoint.EndpointType == "external" {
+ delete(self.agent.endpointDb, endpoint.EndpointID)
+ } else if endpoint.EndpointType == "external-bgp" {
+ // bgp peer endpoint
+ endpoint.PortNo = 0
+ self.agent.endpointDb[endpoint.EndpointID] = endpoint
+ self.agent.datapath.AddEndpoint(endpoint)
+ }
+ }
+ }
+ }
+ oldState = s.Info.BgpState
+ oldAdminState = s.Info.AdminState
+ }
+ return nil
+}
+
+//modrib receives route updates from BGP server and adds the endpoint
+func (self *OfnetBgp) modRib(path *api.Path) error {
+ var nlri bgp.AddrPrefixInterface
+ var nextHop string
+ var macAddrStr string
+ var portNo uint32
+ if len(path.Nlri) > 0 {
+ nlri = &bgp.IPAddrPrefix{}
+ err := nlri.DecodeFromBytes(path.Nlri)
+ if err != nil {
+ return err
+ }
+ }
+
+ for _, attr := range path.Pattrs {
+ p, err := bgp.GetPathAttribute(attr)
+ if err != nil {
+ return err
+ }
+
+ err = p.DecodeFromBytes(attr)
+ if err != nil {
+ return err
+ }
+
+ if p.GetType() == bgp.BGP_ATTR_TYPE_NEXT_HOP {
+ nextHop = p.(*bgp.PathAttributeNextHop).Value.String()
+ break
+ }
+ }
+ if nextHop == "0.0.0.0" {
+ return nil
+ }
+
+ if nlri == nil {
+ return fmt.Errorf("no nlri")
+ }
+
+ endpointIPNet, _ := netlink.ParseIPNet(nlri.String())
+ log.Infof("Bgp Rib Received endpoint update for %v , with nexthop %v",
+ endpointIPNet, nextHop)
+
+ //check if bgp published a route local to the host
+ epid := endpointIPNet.IP.Mask(endpointIPNet.Mask).String()
+
+ //Check if the route is local
+ if nextHop == self.routerIP {
+ log.Info("This is a local route skipping endpoint create! ")
+ return nil
+ }
+
+ if self.agent.endpointDb[nextHop] == nil {
+ //the nexthop is not the directly connected eBgp peer
+ macAddrStr = ""
+ portNo = 0
+ } else {
+ macAddrStr = self.agent.endpointDb[nextHop].MacAddrStr
+ portNo = self.agent.endpointDb[nextHop].PortNo
+ }
+
+ ipmask := net.ParseIP("255.255.255.255").Mask(endpointIPNet.Mask)
+
+ if path.IsWithdraw != true {
+ epreg := &OfnetEndpoint{
+ EndpointID: epid,
+ EndpointType: "external",
+ IpAddr: endpointIPNet.IP,
+ IpMask: ipmask,
+ VrfId: 0, // FIXME set VRF correctly
+ MacAddrStr: macAddrStr,
+ Vlan: 1,
+ OriginatorIp: self.agent.localIp,
+ PortNo: portNo,
+ Timestamp: time.Now(),
+ }
+
+ // Install the endpoint in datapath
+ // First, add the endpoint to local routing table
+ self.agent.endpointDb[epreg.EndpointID] = epreg
+ err := self.agent.datapath.AddEndpoint(epreg)
+ if err != nil {
+ log.Errorf("Error adding endpoint: {%+v}. Err: %v", epreg, err)
+ return err
+ }
+ } else {
+ log.Info("Received route withdraw from BGP for ", endpointIPNet)
+ endpoint := self.agent.getEndpointByIp(endpointIPNet.IP)
+ self.agent.datapath.RemoveEndpoint(endpoint)
+ delete(self.agent.endpointDb, endpoint.EndpointID)
+ }
+ return nil
+}
+
+//createBgpServer creates and starts a bgp server and correspoinding grpc server
+func createBgpServer() (bgpServer *bgpserver.BgpServer, grpcServer *bgpserver.Server) {
+ bgpServer = bgpserver.NewBgpServer(bgp.BGP_PORT)
+ if bgpServer == nil {
+ log.Errorf("Error creating bgp server")
+ return
+ } else {
+ go bgpServer.Serve()
+ }
+ // start grpc Server
+ grpcServer = bgpserver.NewGrpcServer(bgpserver.GRPC_PORT, bgpServer.GrpcReqCh)
+ if grpcServer == nil {
+ log.Errorf("Error creating bgp server")
+ return
+ } else {
+ go grpcServer.Serve()
+ }
+ return
+}
+
+//setDefaultGlobalConfigValues sets the default global configs for bgp
+func setDefaultGlobalConfigValues(bt *bgpconf.Global) error {
+
+ bt.AfiSafis.AfiSafiList = []bgpconf.AfiSafi{
+ bgpconf.AfiSafi{AfiSafiName: "ipv4-unicast"},
+ bgpconf.AfiSafi{AfiSafiName: "ipv6-unicast"},
+ bgpconf.AfiSafi{AfiSafiName: "l3vpn-ipv4-unicast"},
+ bgpconf.AfiSafi{AfiSafiName: "l3vpn-ipv6-unicast"},
+ bgpconf.AfiSafi{AfiSafiName: "l2vpn-evpn"},
+ bgpconf.AfiSafi{AfiSafiName: "encap"},
+ bgpconf.AfiSafi{AfiSafiName: "rtc"},
+ bgpconf.AfiSafi{AfiSafiName: "ipv4-flowspec"},
+ bgpconf.AfiSafi{AfiSafiName: "l3vpn-ipv4-flowspec"},
+ bgpconf.AfiSafi{AfiSafiName: "ipv6-flowspec"},
+ bgpconf.AfiSafi{AfiSafiName: "l3vpn-ipv6-flowspec"},
+ }
+ bt.MplsLabelRange.MinLabel = bgpconf.DEFAULT_MPLS_LABEL_MIN
+ bt.MplsLabelRange.MaxLabel = bgpconf.DEFAULT_MPLS_LABEL_MAX
+
+ return nil
+}
+
+//setNeighborConfigValues sets the default neighbor configs for bgp
+func setNeighborConfigValues(neighbor *bgpconf.Neighbor) error {
+
+ neighbor.Timers.TimersConfig.ConnectRetry = float64(bgpconf.DEFAULT_CONNECT_RETRY)
+ neighbor.Timers.TimersConfig.HoldTime = float64(bgpconf.DEFAULT_HOLDTIME)
+ neighbor.Timers.TimersConfig.KeepaliveInterval = float64(bgpconf.DEFAULT_HOLDTIME / 3)
+ neighbor.Timers.TimersConfig.IdleHoldTimeAfterReset =
+ float64(bgpconf.DEFAULT_IDLE_HOLDTIME_AFTER_RESET)
+ //FIX ME need to check with global peer to set internal or external
+ neighbor.NeighborConfig.PeerType = bgpconf.PEER_TYPE_EXTERNAL
+ neighbor.Transport.TransportConfig.PassiveMode = false
+ return nil
+}
diff --git a/ofnetMaster.go b/ofnetMaster.go
old mode 100644
new mode 100755
index a54f9b8..d61018b
--- a/ofnetMaster.go
+++ b/ofnetMaster.go
@@ -126,6 +126,8 @@ func (self *OfnetMaster) RegisterNode(hostInfo *OfnetNode, ret *bool) error {
// Add an Endpoint
func (self *OfnetMaster) EndpointAdd(ep *OfnetEndpoint, ret *bool) error {
+
+ log.Infof("Received Endpoint CReate from Remote netplugin")
// Check if we have the endpoint already and which is more recent
oldEp := self.endpointDb[ep.EndpointID]
if oldEp != nil {
diff --git a/ofnetPolicy_test.go b/ofnetPolicy_test.go
old mode 100644
new mode 100755
index 78b8e30..60228a1
--- a/ofnetPolicy_test.go
+++ b/ofnetPolicy_test.go
@@ -68,7 +68,7 @@ func TestPolicyAddDelete(t *testing.T) {
ofnetAgent.WaitForSwitchConnection()
// Create a vlan for the endpoint
- ofnetAgent.AddVlan(1, 1)
+ ofnetAgent.AddNetwork(1, 1, "")
macAddr, _ := net.ParseMAC("00:01:02:03:04:05")
endpoint := EndpointInfo{
diff --git a/ofnet_test.go b/ofnet_test.go
old mode 100644
new mode 100755
index 7a26af9..8d13795
--- a/ofnet_test.go
+++ b/ofnet_test.go
@@ -14,6 +14,10 @@ import (
"github.com/contiv/ofnet/ovsdbDriver"
log "github.com/Sirupsen/logrus"
+ api "github.com/osrg/gobgp/api"
+ "github.com/osrg/gobgp/packet"
+ "golang.org/x/net/context"
+ "google.golang.org/grpc"
)
const NUM_MASTER = 2
@@ -24,7 +28,9 @@ var vrtrMasters [NUM_MASTER]*OfnetMaster
var vxlanMasters [NUM_MASTER]*OfnetMaster
var vrtrAgents [NUM_AGENT]*OfnetAgent
var vxlanAgents [NUM_AGENT]*OfnetAgent
-var ovsDrivers [NUM_AGENT * 2]*ovsdbDriver.OvsDriver
+var ovsDrivers [NUM_AGENT * 3]*ovsdbDriver.OvsDriver
+var vlrtrAgent *OfnetAgent
+var vlrtrMaster *OfnetMaster
//var localIpList []string = []string{"10.10.10.1", "10.10.10.2", "10.10.10.3", "10.10.10.4"}
var localIpList []string
@@ -52,8 +58,15 @@ func TestMain(m *testing.M) {
}
log.Infof("Created Master: %v", vxlanMasters[i])
+
+ }
+ vlrtrMaster = NewOfnetMaster(uint16(9501))
+ if vlrtrMaster == nil {
+ log.Fatalf("Error creating ofnet master")
}
+ log.Infof("Created Master: %v", vlrtrMaster)
+
// Wait a second for masters to be up
time.Sleep(1 * time.Second)
@@ -89,15 +102,30 @@ func TestMain(m *testing.M) {
log.Infof("Created vxlan ofnet agent: %v", vxlanAgents[i])
}
+ // Create agent
+ rpcPort := uint16(9551)
+ ovsPort := uint16(9561)
+ lclIp := net.ParseIP(localIpList[0])
+ vlrtrAgent, err = NewOfnetAgent("vlrouter", lclIp, rpcPort, ovsPort, "50.1.1.1", "inb01")
+ if err != nil {
+ log.Fatalf("Error creating ofnet agent. Err: %v", err)
+ }
+
+ // Override MyAddr to local host
+ vlrtrAgent.MyAddr = "127.0.0.1"
+
+ log.Infof("Created vlrouter ofnet agent: %v", vlrtrAgent)
+
+ masterInfo := OfnetNode{
+ HostAddr: "127.0.0.1",
+ }
+ var resp bool
+
// Add master node to each agent
for i := 0; i < NUM_AGENT; i++ {
// add the two master nodes
for j := 0; j < NUM_MASTER; j++ {
- var resp bool
- masterInfo := OfnetNode{
- HostAddr: "127.0.0.1",
- HostPort: uint16(9301 + j),
- }
+ masterInfo.HostPort = uint16(9301 + j)
// connect vrtr agent to vrtr master
err := vrtrAgents[i].AddMaster(&masterInfo, &resp)
if err != nil {
@@ -113,6 +141,13 @@ func TestMain(m *testing.M) {
}
}
+ // connect vrtr agent to vrtr master
+
+ masterInfo.HostPort = uint16(9501)
+ err = vlrtrAgent.AddMaster(&masterInfo, &resp)
+ if err != nil {
+ log.Fatalf("Error adding master %+v to vlrtr node. Err: %v", masterInfo, err)
+ }
log.Infof("Ofnet masters and agents are setup..")
@@ -129,6 +164,11 @@ func TestMain(m *testing.M) {
return
}
}
+ err = vlrtrMaster.MakeDummyRpcCall()
+ if err != nil {
+ log.Fatalf("Error making dummy rpc call. Err: %v", err)
+ return
+ }
log.Infof("Made dummy rpc call to all agents")
@@ -154,8 +194,25 @@ func TestMain(m *testing.M) {
}
}
- // Wait for 10sec for switch to connect to controller
- time.Sleep(10 * time.Second)
+ brName := "contivVlanBridge"
+ ovsPort = uint16(9561)
+ ovsDrivers[2*NUM_AGENT] = ovsdbDriver.NewOvsDriver(brName)
+ err = ovsDrivers[2*NUM_AGENT].AddController("127.0.0.1", ovsPort)
+ if err != nil {
+ log.Fatalf("Error adding controller to ovs: %s", brName)
+ }
+
+ // Wait for 20sec for switch to connect to controller
+ time.Sleep(20 * time.Second)
+
+ err = SetupVlans()
+ if err != nil {
+ log.Fatalf("Error setting up Vlans")
+ }
+ err = SetupVteps()
+ if err != nil {
+ log.Fatalf("Error setting up vteps")
+ }
// run the test
exitCode := m.Run()
@@ -164,41 +221,54 @@ func TestMain(m *testing.M) {
}
// test adding vlan
-func TestOfnetSetupVlan(t *testing.T) {
+func SetupVlans() error {
for i := 0; i < NUM_AGENT; i++ {
- for j := 1; j < 10; j++ {
- log.Infof("Adding Vlan %d on %s", j, localIpList[i])
- err := vrtrAgents[i].AddVlan(uint16(j), uint32(j))
+ log.Info("Infex %d \n", i)
+ for j := 1; j < 5; j++ {
+ log.Info("Infex %d \n", j)
+ //log.Infof("Adding Vlan %d on %s", j, localIpList[i])
+ err := vrtrAgents[i].AddNetwork(uint16(j), uint32(j), "")
if err != nil {
- t.Errorf("Error adding vlan %d. Err: %v", j, err)
+ log.Errorf("Error adding vlan %d. Err: %v", j, err)
+ return err
}
- err = vxlanAgents[i].AddVlan(uint16(j), uint32(j))
+ err = vxlanAgents[i].AddNetwork(uint16(j), uint32(j), "")
if err != nil {
- t.Errorf("Error adding vlan %d. Err: %v", j, err)
+ log.Errorf("Error adding vlan %d. Err: %v", j, err)
+ return err
}
}
}
+ err := vlrtrAgent.AddNetwork(uint16(1), uint32(1),
+ fmt.Sprintf("10.10.%d.%d", 1, 1))
+ if err != nil {
+ log.Errorf("Error adding vlan 1. Err: %v", err)
+ return err
+ }
+ return nil
}
// test adding full mesh vtep ports
-func TestOfnetSetupVtep(t *testing.T) {
+func SetupVteps() error {
for i := 0; i < NUM_AGENT; i++ {
for j := 0; j < NUM_AGENT; j++ {
if i != j {
log.Infof("Adding VTEP on %s for remoteIp: %s", localIpList[i], localIpList[j])
err := vrtrAgents[i].AddVtepPort(uint32(j+1), net.ParseIP(localIpList[j]))
if err != nil {
- t.Errorf("Error adding VTEP port. Err: %v", err)
+ log.Errorf("Error adding VTEP port. Err: %v", err)
+ return err
}
err = vxlanAgents[i].AddVtepPort(uint32(j+1), net.ParseIP(localIpList[j]))
if err != nil {
- t.Errorf("Error adding VTEP port. Err: %v", err)
+ log.Errorf("Error adding VTEP port. Err: %v", err)
+ return err
}
}
}
}
-
log.Infof("Finished setting up VTEP ports..")
+ return nil
}
// Test adding/deleting Vrouter routes
@@ -419,6 +489,12 @@ func TestWaitAndCleanup(t *testing.T) {
t.Errorf("Error deleting the bridge. Err: %v", err)
}
}
+ brName := "contivVlanBridge"
+ log.Infof("Deleting OVS bridge: %s", brName)
+ err := ovsDrivers[2*NUM_AGENT].DeleteBridge(brName)
+ if err != nil {
+ t.Errorf("Error deleting the bridge. Err: %v", err)
+ }
}
// Run an ovs-ofctl command
@@ -475,3 +551,194 @@ func ofctlFlowMatch(flowList []string, tableId int, matchStr string) bool {
return false
}
+
+// Test adding/deleting Vlrouter routes
+func TestOfnetVlrouteAddDelete(t *testing.T) {
+
+ macAddr, _ := net.ParseMAC("02:02:01:06:06:06")
+ ipAddr := net.ParseIP("20.20.20.20")
+ endpoint := EndpointInfo{
+ PortNo: uint32(NUM_AGENT + 3),
+ MacAddr: macAddr,
+ Vlan: 1,
+ IpAddr: ipAddr,
+ }
+
+ log.Infof("Installing local vlrouter endpoint: %+v", endpoint)
+ err := vlrtrAgent.AddNetwork(uint16(1), uint32(1), "20.20.20.254")
+ if err != nil {
+ t.Errorf("Error adding vlan 1 . Err: %v", err)
+ }
+
+ // Install the local endpoint
+ err = vlrtrAgent.AddLocalEndpoint(endpoint)
+ if err != nil {
+ t.Fatalf("Error installing endpoint: %+v. Err: %v", endpoint, err)
+ return
+ }
+
+ log.Infof("Finished adding local vlrouter endpoint")
+
+ // verify all ovs switches have this route
+ brName := "contivVlanBridge"
+ flowList, err := ofctlFlowDump(brName)
+ if err != nil {
+ t.Errorf("Error getting flow entries. Err: %v", err)
+ return
+ }
+
+ // verify flow entry exists
+ ipFlowMatch := fmt.Sprintf("priority=100,ip,nw_dst=20.20.20.20")
+ ipTableId := IP_TBL_ID
+ if !ofctlFlowMatch(flowList, ipTableId, ipFlowMatch) {
+ t.Errorf("Could not find the route %s on ovs %s", ipFlowMatch, brName)
+ return
+ }
+
+ log.Infof("Found ipflow %s on ovs %s", ipFlowMatch, brName)
+
+ log.Infof("Adding Vlrouter endpoint successful.\n Testing Delete")
+
+ macAddr, _ = net.ParseMAC("02:02:01:06:06:06")
+ ipAddr = net.ParseIP("20.20.20.20")
+ endpoint = EndpointInfo{
+ PortNo: uint32(NUM_AGENT + 3),
+ MacAddr: macAddr,
+ Vlan: 1,
+ IpAddr: ipAddr,
+ }
+
+ log.Infof("Deleting local vlrouter endpoint: %+v", endpoint)
+
+ // Install the local endpoint
+ err = vlrtrAgent.RemoveLocalEndpoint(uint32(NUM_AGENT + 3))
+ if err != nil {
+ t.Fatalf("Error deleting endpoint: %+v. Err: %v", endpoint, err)
+ return
+ }
+
+ log.Infof("Deleted endpoints. Verifying they are gone")
+
+ // verify flows are deleted
+ brName = "contivVlanBridge"
+
+ flowList, err = ofctlFlowDump(brName)
+ if err != nil {
+ t.Errorf("Error getting flow entries. Err: %v", err)
+ }
+
+ // verify flow entry exists
+ ipFlowMatch = fmt.Sprintf("priority=100,ip,nw_dst=20.20.20.20")
+ ipTableId = IP_TBL_ID
+ if ofctlFlowMatch(flowList, ipTableId, ipFlowMatch) {
+ t.Errorf("Still found the flow %s on ovs %s", ipFlowMatch, brName)
+ }
+
+ log.Infof("Verified all flows are deleted")
+}
+
+// Test adding/deleting Vlrouter routes
+func TestOfnetBgpVlrouteAddDelete(t *testing.T) {
+
+ path := &api.Path{
+ Pattrs: make([][]byte, 0),
+ }
+ nlri := bgp.NewIPAddrPrefix(32, "20.20.20.20")
+ path.Nlri, _ = nlri.Serialize()
+ origin, _ := bgp.NewPathAttributeOrigin(bgp.BGP_ORIGIN_ATTR_TYPE_EGP).Serialize()
+ path.Pattrs = append(path.Pattrs, origin)
+ aspathParam := []bgp.AsPathParamInterface{bgp.NewAs4PathParam(2, []uint32{65002})}
+ aspath, _ := bgp.NewPathAttributeAsPath(aspathParam).Serialize()
+ path.Pattrs = append(path.Pattrs, aspath)
+ n, _ := bgp.NewPathAttributeNextHop("50.1.1.2").Serialize()
+ path.Pattrs = append(path.Pattrs, n)
+ vlrtrAgent.modRibCh <- path
+ log.Infof("Adding path to the Bgp Rib")
+ time.Sleep(2 * time.Second)
+
+ // verify flow entry exists
+ brName := "contivVlanBridge"
+
+ flowList, err := ofctlFlowDump(brName)
+ if err != nil {
+ t.Errorf("Error getting flow entries. Err: %v", err)
+ }
+
+ ipFlowMatch := fmt.Sprintf("priority=100,ip,nw_dst=20.20.20.20")
+ ipTableId := IP_TBL_ID
+ if !ofctlFlowMatch(flowList, ipTableId, ipFlowMatch) {
+ t.Errorf("Could not find the route %s on ovs %s", ipFlowMatch, brName)
+ return
+ }
+ log.Infof("Found ipflow %s on ovs %s", ipFlowMatch, brName)
+
+ // withdraw the route
+ path.IsWithdraw = true
+ vlrtrAgent.modRibCh <- path
+ log.Infof("Withdrawing route from BGP rib")
+
+ // verify flow entry exists
+ brName = "contivVlanBridge"
+
+ flowList, err = ofctlFlowDump(brName)
+ if err != nil {
+ t.Errorf("Error getting flow entries. Err: %v", err)
+ }
+
+ ipFlowMatch = fmt.Sprintf("priority=100,ip,nw_dst=20.20.20.20")
+ ipTableId = IP_TBL_ID
+ if ofctlFlowMatch(flowList, ipTableId, ipFlowMatch) {
+ t.Errorf("Found the route %s on ovs %s which was withdrawn", ipFlowMatch, brName)
+ return
+ }
+ log.Infof("ipflow %s on ovs %s has been deleted from OVS", ipFlowMatch, brName)
+
+}
+
+func TestOfnetBgpPeerAddDelete(t *testing.T) {
+
+ as := "500"
+ peer := "50.1.1.2"
+
+ //Add Bgp neighbor and check if it is successful
+
+ err := vlrtrAgent.AddBgpNeighbors(as, peer)
+ if err != nil {
+ t.Errorf("Error adding Bgp Neighbor", err)
+ return
+ }
+
+ timeout := grpc.WithTimeout(time.Second)
+ conn, err := grpc.Dial("127.0.0.1:8080", timeout, grpc.WithBlock(), grpc.WithInsecure())
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer conn.Close()
+ client := api.NewGobgpApiClient(conn)
+ if client == nil {
+ t.Errorf("GoBgpApiclient is invalid")
+ }
+ arg := &api.Arguments{Name: vlrtrAgent.myBgpPeer}
+
+ //Check if neighbor is added to bgp server
+ bgpPeer, err := client.GetNeighbor(context.Background(), arg)
+ if err != nil {
+ t.Errorf("GetNeighbor failed ", err)
+ return
+ }
+
+ //Delete BGP neighbor
+ err = vlrtrAgent.DeleteBgpNeighbors()
+ if err != nil {
+ t.Errorf("Error Deleting Bgp Neighbor", err)
+ return
+ }
+
+ //Check if neighbor is added to bgp server
+ bgpPeer, err = client.GetNeighbor(context.Background(), arg)
+ if bgpPeer != nil {
+ t.Errorf("Neighbor is not deleted ", err)
+ return
+ }
+
+}
diff --git a/vlanBridge.go b/vlanBridge.go
old mode 100644
new mode 100755
index 90da06c..035b02a
--- a/vlanBridge.go
+++ b/vlanBridge.go
@@ -121,3 +121,13 @@ func (self *VlanBridge) RemoveEndpoint(endpoint *OfnetEndpoint) error {
return nil
}
+
+// AddUplink adds an uplink to the switch
+func (self *VlanBridge) AddUplink(portNo uint32) error {
+ return nil
+}
+
+// RemoveUplink remove an uplink to the switch
+func (self *VlanBridge) RemoveUplink(portNo uint32) error {
+ return nil
+}
diff --git a/vlrouter.go b/vlrouter.go
new file mode 100755
index 0000000..2c7c848
--- /dev/null
+++ b/vlrouter.go
@@ -0,0 +1,570 @@
+/***
+Copyright 2014 Cisco Systems Inc. All rights reserved.
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+package ofnet
+
+// This file implements the virtual router functionality using Vxlan overlay
+
+// VXLAN tables are structured as follows
+//
+// +-------+ +-------------------+
+// | Valid +---------------------------------------->| ARP to Controller |
+// | Pkts +-->+-------+ +-------------------+
+// +-------+ | Vlan | +---------+
+// | Table +------->| IP Dst | +--------------+
+// +-------+ | Lookup +--------->| Ucast Output |
+// +---------- +--------------+
+//
+//
+
+import (
+ //"fmt"
+ "errors"
+ "net"
+ "net/rpc"
+
+ "container/list"
+ log "github.com/Sirupsen/logrus"
+ "github.com/contiv/ofnet/ofctrl"
+ "github.com/shaleman/libOpenflow/openflow13"
+ "github.com/shaleman/libOpenflow/protocol"
+)
+
+// Vlrouter state.
+// One Vlrouter instance exists on each host
+type Vlrouter struct {
+ agent *OfnetAgent // Pointer back to ofnet agent that owns this
+ ofSwitch *ofctrl.OFSwitch // openflow switch we are talking to
+ policyAgent *PolicyAgent // Policy agent
+
+ // Fgraph tables
+ inputTable *ofctrl.Table // Packet lookup starts here
+ vlanTable *ofctrl.Table // Vlan Table. map port or VNI to vlan
+ ipTable *ofctrl.Table // IP lookup table
+
+ // Flow Database
+ flowDb map[string]*ofctrl.Flow // Database of flow entries
+ portVlanFlowDb map[uint32]*ofctrl.Flow // Database of flow entries
+
+ myRouterMac net.HardwareAddr //Router mac used for external proxy
+ MyBgpPeer string // bgp neighbor
+ unresolvedEPs *list.List // unresolved endpoint list
+
+}
+
+// Create a new vlrouter instance
+func NewVlrouter(agent *OfnetAgent, rpcServ *rpc.Server) *Vlrouter {
+ vlrouter := new(Vlrouter)
+
+ // Keep a reference to the agent
+ vlrouter.agent = agent
+
+ // Create policy agent
+ vlrouter.policyAgent = NewPolicyAgent(agent, rpcServ)
+
+ // Create a flow dbs and my router mac
+ vlrouter.flowDb = make(map[string]*ofctrl.Flow)
+ vlrouter.portVlanFlowDb = make(map[uint32]*ofctrl.Flow)
+ vlrouter.myRouterMac, _ = net.ParseMAC("00:00:11:11:11:11")
+ vlrouter.unresolvedEPs = list.New()
+
+ return vlrouter
+}
+
+// Handle new master added event
+func (self *Vlrouter) MasterAdded(master *OfnetNode) error {
+
+ return nil
+}
+
+// Handle switch connected notification
+func (self *Vlrouter) SwitchConnected(sw *ofctrl.OFSwitch) {
+ // Keep a reference to the switch
+ self.ofSwitch = sw
+
+ log.Infof("Switch connected(vlrouter). installing flows")
+
+ // Tell the policy agent about the switch
+ self.policyAgent.SwitchConnected(sw)
+
+ // Init the Fgraph
+ self.initFgraph()
+}
+
+// Handle switch disconnected notification
+func (self *Vlrouter) SwitchDisconnected(sw *ofctrl.OFSwitch) {
+ // FIXME
+}
+
+// Handle incoming packet
+func (self *Vlrouter) PacketRcvd(sw *ofctrl.OFSwitch, pkt *ofctrl.PacketIn) {
+ switch pkt.Data.Ethertype {
+ case 0x0806:
+ if (pkt.Match.Type == openflow13.MatchType_OXM) &&
+ (pkt.Match.Fields[0].Class == openflow13.OXM_CLASS_OPENFLOW_BASIC) &&
+ (pkt.Match.Fields[0].Field == openflow13.OXM_FIELD_IN_PORT) {
+ // Get the input port number
+ switch t := pkt.Match.Fields[0].Value.(type) {
+ case *openflow13.InPortField:
+ var inPortFld openflow13.InPortField
+ inPortFld = *t
+
+ self.processArp(pkt.Data, inPortFld.InPort)
+ }
+ }
+
+ case 0x0800:
+ // FIXME: We dont expect IP packets. Use this for statefull policies.
+ default:
+ log.Errorf("Received unknown ethertype: %x", pkt.Data.Ethertype)
+ }
+}
+
+/*AddLocalEndpoint does the following:
+1) Adds endpoint to the OVS and the associated flows
+2) Populates BGP RIB with local route to be propogated to neighbor
+*/
+
+func (self *Vlrouter) AddLocalEndpoint(endpoint OfnetEndpoint) error {
+ // Install a flow entry for vlan mapping and point it to IP table
+ if self.agent.ctrler == nil {
+ return nil
+ }
+
+ portVlanFlow, err := self.vlanTable.NewFlow(ofctrl.FlowMatch{
+ Priority: FLOW_MATCH_PRIORITY,
+ InputPort: endpoint.PortNo,
+ })
+ if err != nil {
+ log.Errorf("Error creating portvlan entry. Err: %v", err)
+ return err
+ }
+ err = portVlanFlow.Next(self.ipTable)
+ if err != nil {
+ log.Errorf("Error installing portvlan entry. Err: %v", err)
+ return err
+ }
+
+ // save the flow entry
+ self.portVlanFlowDb[endpoint.PortNo] = portVlanFlow
+
+ // Set the vlan and install it
+ // FIXME: Dont set the vlan till multi-vrf support. We cant pop vlan unless flow matches on vlan
+ // portVlanFlow.SetVlan(endpoint.Vlan)
+ outPort, err := self.ofSwitch.OutputPort(endpoint.PortNo)
+ if err != nil {
+ log.Errorf("Error creating output port %d. Err: %v", endpoint.PortNo, err)
+ return err
+ }
+
+ // Install the IP address
+ ipFlow, err := self.ipTable.NewFlow(ofctrl.FlowMatch{
+ Priority: FLOW_MATCH_PRIORITY,
+ Ethertype: 0x0800,
+ IpDa: &endpoint.IpAddr,
+ })
+
+ if err != nil {
+ log.Errorf("Error creating flow for endpoint: %+v. Err: %v", endpoint, err)
+ return err
+ }
+
+ destMacAddr, _ := net.ParseMAC(endpoint.MacAddrStr)
+
+ // Set Mac addresses
+ ipFlow.SetMacDa(destMacAddr)
+ ipFlow.SetMacSa(self.myRouterMac)
+
+ // Point the route at output port
+ err = ipFlow.Next(outPort)
+ if err != nil {
+ log.Errorf("Error installing flow for endpoint: %+v. Err: %v", endpoint, err)
+ return err
+ }
+
+ // Store the flow
+ self.flowDb[endpoint.IpAddr.String()] = ipFlow
+
+ if endpoint.EndpointType == "internal-bgp" {
+ return nil
+ }
+
+ path := &OfnetProtoRouteInfo{
+ ProtocolType: "bgp",
+ localEpIP: endpoint.IpAddr.String(),
+ nextHopIP: self.agent.GetRouterInfo().RouterIP,
+ }
+ log.Infof("ADDING LOCAL ROUTE AND PASSING TO BGP")
+ self.agent.AddLocalProtoRoute(path)
+
+ return nil
+}
+
+/* RemoveLocalEndpoint does the following
+1) Removes the local endpoint and associated flows from OVS
+2) Withdraws the route from BGP RIB
+*/
+func (self *Vlrouter) RemoveLocalEndpoint(endpoint OfnetEndpoint) error {
+
+ // Remove the port vlan flow.
+ portVlanFlow := self.portVlanFlowDb[endpoint.PortNo]
+ if portVlanFlow != nil {
+ err := portVlanFlow.Delete()
+ if err != nil {
+ log.Errorf("Error deleting portvlan flow. Err: %v", err)
+ }
+ }
+
+ // Find the flow entry
+ ipFlow := self.flowDb[endpoint.IpAddr.String()]
+ if ipFlow == nil {
+ log.Errorf("Error finding the flow for endpoint: %+v", endpoint)
+ return errors.New("Flow not found")
+ }
+
+ // Delete the Fgraph entry
+ err := ipFlow.Delete()
+ if err != nil {
+ log.Errorf("Error deleting the endpoint: %+v. Err: %v", endpoint, err)
+ }
+
+ path := &OfnetProtoRouteInfo{
+ ProtocolType: "bgp",
+ localEpIP: endpoint.IpAddr.String(),
+ nextHopIP: self.agent.GetRouterInfo().RouterIP,
+ }
+
+ self.agent.DeleteLocalProtoRoute(path)
+
+ return nil
+}
+
+// Add a vlan.
+// This is mainly used for mapping vlan id to Vxlan VNI
+func (self *Vlrouter) AddVlan(vlanId uint16, vni uint32) error {
+ // FIXME: Add this for multiple VRF support
+ return nil
+}
+
+// Remove a vlan
+func (self *Vlrouter) RemoveVlan(vlanId uint16, vni uint32) error {
+ // FIXME: Add this for multiple VRF support
+ return nil
+}
+
+/* AddEndpoint does the following :
+1)Adds a remote endpoint and associated flows to OVS
+2)The remotes routes can be 3 endpoint types :
+ a) internal - json rpc based learning from peer netplugins/ofnetagents in the cluster
+ b) external - remote endpoint learn via BGP
+ c) external-bgp - endpoint of BGP peer
+*/
+func (self *Vlrouter) AddEndpoint(endpoint *OfnetEndpoint) error {
+
+ nexthopEp := self.agent.getEndpointByIp(net.ParseIP(self.MyBgpPeer))
+ if nexthopEp != nil && nexthopEp.PortNo != 0 {
+ endpoint.MacAddrStr = nexthopEp.MacAddrStr
+ endpoint.PortNo = nexthopEp.PortNo
+ } else {
+ endpoint.PortNo = 0
+ endpoint.MacAddrStr = " "
+ if endpoint.EndpointType != "external-bgp" {
+ //for the remote endpoints maintain a cache of
+ //routes that need to be resolved to next hop.
+ // bgp peer resolution happens via ARP and hence not
+ //maintainer in cache.
+ log.Info("Putting in endpoint info to cache")
+ self.unresolvedEPs.PushBack(endpoint.EndpointID)
+ log.Info(self.unresolvedEPs)
+ }
+ }
+ if endpoint.EndpointType == "external-bgp" {
+ self.MyBgpPeer = endpoint.IpAddr.String()
+ }
+ log.Infof("AddEndpoint call for endpoint: %+v", endpoint)
+
+ outPort, err := self.ofSwitch.OutputPort(endpoint.PortNo)
+ if err != nil {
+ log.Errorf("Error creating output port %d. Err: %v", endpoint.PortNo, err)
+ return err
+ }
+
+ // Install the IP address
+ ipFlow, err := self.ipTable.NewFlow(ofctrl.FlowMatch{
+ Priority: FLOW_MATCH_PRIORITY,
+ Ethertype: 0x0800,
+ IpDa: &endpoint.IpAddr,
+ IpDaMask: &endpoint.IpMask,
+ })
+ if err != nil {
+ log.Errorf("Error creating flow for endpoint: %+v. Err: %v", endpoint, err)
+ return err
+ }
+
+ // Set Mac addresses
+ DAMac, _ := net.ParseMAC(endpoint.MacAddrStr)
+ ipFlow.SetMacDa(DAMac)
+ ipFlow.SetMacSa(self.myRouterMac)
+
+ // Set VNI
+ // FIXME: hardcode VNI for default VRF.
+ // FIXME: We need to use fabric VNI per VRF
+ // FIXME: Cant pop vlan tag till the flow matches on vlan.
+
+ // Point it to output port
+ err = ipFlow.Next(outPort)
+ if err != nil {
+ log.Errorf("Error installing flow for endpoint: %+v. Err: %v", endpoint, err)
+ return err
+ }
+
+ // Store it in flow db
+ self.flowDb[endpoint.IpAddr.String()] = ipFlow
+
+ return nil
+}
+
+// RemoveEndpoint removes an endpoint from the datapath
+func (self *Vlrouter) RemoveEndpoint(endpoint *OfnetEndpoint) error {
+ // Find the flow entry
+ ipFlow := self.flowDb[endpoint.IpAddr.String()]
+ if ipFlow == nil {
+ log.Errorf("Error finding the flow for endpoint: %+v", endpoint)
+ return errors.New("Flow not found")
+ }
+
+ // Delete the Fgraph entry
+ err := ipFlow.Delete()
+ if err != nil {
+ log.Errorf("Error deleting the endpoint: %+v. Err: %v", endpoint, err)
+ }
+
+ // Remove the endpoint from policy tables
+ // err = self.policyAgent.DelEndpoint(endpoint)
+ // if err != nil {
+ // log.Errorf("Error deleting endpoint to policy agent{%+v}. Err: %v", endpoint, err)
+ // return err
+ // }
+
+ return nil
+}
+
+// initialize Fgraph on the switch
+func (self *Vlrouter) initFgraph() error {
+ sw := self.ofSwitch
+
+ // Create all tables
+ self.inputTable = sw.DefaultTable()
+ self.vlanTable, _ = sw.NewTable(VLAN_TBL_ID)
+ self.ipTable, _ = sw.NewTable(IP_TBL_ID)
+
+ //Create all drop entries
+ // Drop mcast source mac
+ bcastMac, _ := net.ParseMAC("01:00:00:00:00:00")
+ bcastSrcFlow, _ := self.inputTable.NewFlow(ofctrl.FlowMatch{
+ Priority: FLOW_MATCH_PRIORITY,
+ MacSa: &bcastMac,
+ MacSaMask: &bcastMac,
+ })
+ bcastSrcFlow.Next(sw.DropAction())
+
+ // Redirect ARP packets to controller
+ arpFlow, _ := self.inputTable.NewFlow(ofctrl.FlowMatch{
+ Priority: FLOW_MATCH_PRIORITY,
+ Ethertype: 0x0806,
+ })
+ arpFlow.Next(sw.SendToController())
+
+ //All ARP replies will need IP table lookup
+ Mac, _ := net.ParseMAC("00:00:11:11:11:11")
+ arpFlow, _ = self.inputTable.NewFlow(ofctrl.FlowMatch{
+ Priority: 300,
+ Ethertype: 0x0806,
+ MacSa: &Mac,
+ })
+ arpFlow.Next(self.ipTable)
+
+ // Send all valid packets to vlan table
+ // This is installed at lower priority so that all packets that miss above
+ // flows will match entry
+ validPktFlow, _ := self.inputTable.NewFlow(ofctrl.FlowMatch{
+ Priority: FLOW_MISS_PRIORITY,
+ })
+ validPktFlow.Next(self.vlanTable)
+
+ // Drop all packets that miss Vlan lookup
+ vlanMissFlow, _ := self.vlanTable.NewFlow(ofctrl.FlowMatch{
+ Priority: FLOW_MISS_PRIORITY,
+ })
+ vlanMissFlow.Next(sw.DropAction())
+
+ // Drop all packets that miss IP lookup
+ ipMissFlow, _ := self.ipTable.NewFlow(ofctrl.FlowMatch{
+ Priority: FLOW_MISS_PRIORITY,
+ })
+ ipMissFlow.Next(sw.DropAction())
+
+ return nil
+}
+
+/*processArp does the following :
+1) Process incoming ARP packets
+2) Proxy with Router mac if arp request is from local internal endpoint
+3) Proxy with interface mac is arp request is from remote endpoint
+4) Learn MAC,Port of the source if its not learnt and it is bgp peer endpoint
+*/
+func (self *Vlrouter) processArp(pkt protocol.Ethernet, inPort uint32) {
+ log.Debugf("processing ARP packet on port %d", inPort)
+ switch t := pkt.Data.(type) {
+ case *protocol.ARP:
+ log.Debugf("ARP packet: %+v", *t)
+ var arpHdr protocol.ARP = *t
+ var srcMac net.HardwareAddr
+ var intf *net.Interface
+
+ switch arpHdr.Operation {
+ case protocol.Type_Request:
+ // Lookup the Dest IP in the endpoint table
+ endpoint := self.agent.getEndpointByIp(arpHdr.IPDst)
+ if endpoint == nil {
+ //If we dont know the IP address, dont send an ARP response
+ log.Infof("Received ARP request for unknown IP: %v ", arpHdr.IPDst)
+ return
+ } else {
+ if endpoint.EndpointType == "internal" || endpoint.EndpointType == "internal-bgp" {
+ //srcMac, _ = net.ParseMAC(endpoint.MacAddrStr)
+ intf, _ = net.InterfaceByName(self.agent.GetRouterInfo().VlanIntf)
+ srcMac = intf.HardwareAddr
+ } else if endpoint.EndpointType == "external" || endpoint.EndpointType == "external-bgp" {
+ endpoint = self.agent.getEndpointByIp(arpHdr.IPSrc)
+ if endpoint != nil {
+ if endpoint.EndpointType == "internal" || endpoint.EndpointType == "internal-bgp" {
+ srcMac = self.myRouterMac
+ } else {
+ return
+ }
+
+ } else {
+ return
+ }
+
+ }
+ }
+
+ //Check if source endpoint is learnt.
+ endpoint = self.agent.getEndpointByIp(arpHdr.IPSrc)
+ if endpoint != nil && endpoint.EndpointType == "external-bgp" {
+ //endpoint exists from where the arp is received.
+ if endpoint.PortNo == 0 {
+ log.Infof("Received ARP from BGP Peer on %s: Mac: %s", endpoint.PortNo, endpoint.MacAddrStr)
+ //learn the mac address and portno for the endpoint
+ self.RemoveEndpoint(endpoint)
+ endpoint.PortNo = inPort
+ endpoint.MacAddrStr = arpHdr.HWSrc.String()
+ self.agent.endpointDb[endpoint.EndpointID] = endpoint
+ self.AddEndpoint(endpoint)
+ self.resolveUnresolvedEPs(endpoint.MacAddrStr, inPort)
+
+ }
+ }
+
+ // Form an ARP response
+ arpResp, _ := protocol.NewARP(protocol.Type_Reply)
+ arpResp.HWSrc = srcMac
+ arpResp.IPSrc = arpHdr.IPDst
+ arpResp.HWDst = arpHdr.HWSrc
+ arpResp.IPDst = arpHdr.IPSrc
+
+ log.Infof("Sending ARP response: %+v", arpResp)
+
+ // build the ethernet packet
+ ethPkt := protocol.NewEthernet()
+ ethPkt.HWDst = arpResp.HWDst
+ ethPkt.HWSrc = arpResp.HWSrc
+ ethPkt.Ethertype = 0x0806
+ ethPkt.Data = arpResp
+
+ log.Infof("Sending ARP response Ethernet: %+v", ethPkt)
+
+ // Packet out
+ pktOut := openflow13.NewPacketOut()
+ pktOut.Data = ethPkt
+ pktOut.AddAction(openflow13.NewActionOutput(inPort))
+
+ log.Infof("Sending ARP response packet: %+v", pktOut)
+
+ // Send it out
+ self.ofSwitch.Send(pktOut)
+ default:
+ log.Infof("Dropping ARP response packet from port %d", inPort)
+ }
+ }
+}
+func (self *Vlrouter) AddVtepPort(portNo uint32, remoteIp net.IP) error {
+ return nil
+}
+
+// Remove a VTEP port
+func (self *Vlrouter) RemoveVtepPort(portNo uint32, remoteIp net.IP) error {
+ return nil
+}
+
+/*resolveUnresolvedEPs walks through the unresolved endpoint list and resolves
+over given mac and port*/
+
+func (self *Vlrouter) resolveUnresolvedEPs(MacAddrStr string, portNo uint32) {
+
+ for self.unresolvedEPs.Len() > 0 {
+ Element := self.unresolvedEPs.Front()
+ if endpointID, ok := Element.Value.(string); ok {
+ endpoint := self.agent.endpointDb[endpointID]
+ self.RemoveEndpoint(endpoint)
+ endpoint.PortNo = portNo
+ endpoint.MacAddrStr = MacAddrStr
+ self.agent.endpointDb[endpoint.EndpointID] = endpoint
+ self.AddEndpoint(endpoint)
+ self.unresolvedEPs.Remove(Element)
+ }
+ }
+}
+
+// AddUplink adds an uplink to the switch
+func (self *Vlrouter) AddUplink(portNo uint32) error {
+ log.Infof("Adding uplink port: %+v", portNo)
+
+ // Install a flow entry for vlan mapping and point it to Mac table
+ portVlanFlow, err := self.vlanTable.NewFlow(ofctrl.FlowMatch{
+ Priority: FLOW_MATCH_PRIORITY,
+ InputPort: portNo,
+ })
+ if err != nil {
+ log.Errorf("Error creating portvlan entry. Err: %v", err)
+ return err
+ }
+
+ // Packets coming from uplink go thru policy and iptable lookup
+ //FIXME: Change next to Policy table
+ err = portVlanFlow.Next(self.ipTable)
+ if err != nil {
+ log.Errorf("Error installing portvlan entry. Err: %v", err)
+ return err
+ }
+
+ // save the flow entry
+ self.portVlanFlowDb[portNo] = portVlanFlow
+
+ return nil
+}
+
+func (self *Vlrouter) RemoveUplink(portNo uint32) error {
+ return nil
+}
diff --git a/vrouter.go b/vrouter.go
old mode 100644
new mode 100755
index ad8b53f..e9225f0
--- a/vrouter.go
+++ b/vrouter.go
@@ -1,11 +1,9 @@
/***
Copyright 2014 Cisco Systems Inc. All rights reserved.
-
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
-
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -378,6 +376,18 @@ func (self *Vrouter) RemoveEndpoint(endpoint *OfnetEndpoint) error {
return nil
}
+// AddUplink adds an uplink to the switch
+func (vr *Vrouter) AddUplink(portNo uint32) error {
+ // Nothing to do
+ return nil
+}
+
+// RemoveUplink remove an uplink to the switch
+func (vr *Vrouter) RemoveUplink(portNo uint32) error {
+ // Nothing to do
+ return nil
+}
+
// initialize Fgraph on the switch
func (self *Vrouter) initFgraph() error {
sw := self.ofSwitch
diff --git a/vxlanBridge.go b/vxlanBridge.go
old mode 100644
new mode 100755
index 4d159f7..001bc28
--- a/vxlanBridge.go
+++ b/vxlanBridge.go
@@ -532,6 +532,16 @@ func (self *Vxlan) RemoveEndpoint(endpoint *OfnetEndpoint) error {
return nil
}
+// AddUplink adds an uplink to the switch
+func (vx *Vxlan) AddUplink(portNo uint32) error {
+ return nil
+}
+
+// RemoveUplink remove an uplink to the switch
+func (vx *Vxlan) RemoveUplink(portNo uint32) error {
+ return nil
+}
+
// initialize Fgraph on the switch
func (self *Vxlan) initFgraph() error {
sw := self.ofSwitch
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment