diff options
author | Wataru Ishida <ishida.wataru@lab.ntt.co.jp> | 2016-11-11 16:23:55 +0000 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2016-11-12 21:21:49 -0800 |
commit | 6d52e8c1e5d4de4dfea37656b50c71579343b5f7 (patch) | |
tree | c5f1b0201dc1017405b19325fd349aa33f34b54e | |
parent | c463e12538943aab758fba793e1af24b18856e06 (diff) |
ops: drop open switch support
Signed-off-by: Wataru Ishida <ishida.wataru@lab.ntt.co.jp>
-rw-r--r-- | docs/sources/openswitch.md | 96 | ||||
-rw-r--r-- | gobgpd/main.go | 12 | ||||
-rw-r--r-- | openswitch/openswitch.go | 692 |
3 files changed, 1 insertions, 799 deletions
diff --git a/docs/sources/openswitch.md b/docs/sources/openswitch.md deleted file mode 100644 index d69f3686..00000000 --- a/docs/sources/openswitch.md +++ /dev/null @@ -1,96 +0,0 @@ -# Coordination with OpenSwitch - -GoBGP will be able to coordination with [OpenSwitch](http://www.openswitch.net) -by connecting to ovsdb using unixsocket(use [ovsdb library of golang](https://github.com/osrg/libovsdb)). -And GoBGP will behaves as BGP agent of OpenSwitch because GoBGP can share configuration -and routing information in coordination with OpenSwitch. - -This page explains how to coordination to OpenSwitch. -And this example have step that share configuration and routing information between OpenSwitch and Gobgp in [docker container](https://hub.docker.com/r/openswitch/genericx86-64/). - - -## Prerequisites - -- Install the docker environment referring to the [here](https://docs.docker.com/engine/installation/ubuntulinux/) -- Install the gobgp refarring to the [here](https://github.com/osrg/gobgp/blob/master/docs/sources/getting-started.md) - -## Getting and Running OpenSwitch container -- Getting image - - Thera are two ways, to get OpenSwitch docker image. - First way, get image from DockerHub using the **docker pull** command. - Second way, build the iamge refarring to the [Step-by-Step Guide](http://www.openswitch.net/documents/dev/step-by-step-guide) of OpenSwitch. - - - In the case of **docker pull** - ```bash - $ sudo docker pull openswitch/genericx86-64 - $ sudo docker images - REPOSITORY TAG IMAGE ID CREATED SIZE - openswitch/genericx86-64 latest 69682b4baeba 4 months ago 321.3 MB 1.278 GB - ``` - -- Running container - - Share the GoBGP binary when you execute docker run command. - ```bash - sudo docker run --privileged -v /tmp:/tmp -v /dev/log:/dev/log -v /sys/fs/cgroup:/sys/fs/cgroup -v $GOPATH/bin:/home/root/bin -h ops --name ops openswitch/genericx86-64 /sbin/init & - $ sudo docker ps -a - CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES - 4eebc0f25f9c openswitch/genericx86-64 "/sbin/init" 3 seconds ago Up 3 seconds ops - ``` - -## Starting Coordination with OpenSwitch -- Enter the OpenSwitch container - ```bash - % sudo docker exec -it ops bash - ``` - -- Setting OpenSwitch - ```bash - bash-4.3# vtysh - switch# show running-config - Current configuration: - ! - ! - ! - switch# configure terminal - switch(config)# router bgp 65001 - switch(config-router)# bgp router-id 10.0.255.1 - switch(config-router)# neighbor 10.0.255.2 remote-as 65002 - switch(config-router)# do show running-config - Current configuration: - ! - ! - ! - router bgp 65001 - bgp router-id 10.0.255.1 - neighbor 10.0.255.2 remote-as 65002 - ! - ``` - -- Starting GoBGP - ```bash - bash-4.3# cd /home/root/bin - bash-4.3# gobgpd --openswitch -p - INFO[0000] gobgpd started - INFO[0000] Coordination with OpenSwitch - INFO[0000] Peer 10.0.255.2 is added - INFO[0015] Peer Up - ``` - - If GoBGP has routes in Global Rib, routes relayed to the OpenSwitch as follows: - ```bash - bash-4.3# vtysh - switch# show ip bgp - Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, - i internal, S Stale, R Removed - Origin codes: i - IGP, e - EGP, ? - incomplete - - Local router-id 10.0.255.1 - Network Next Hop Metric LocPrf Weight Path - * 10.10.10.0/24 10.0.255.2 0 0 32768 65002 i - * 10.10.11.0/24 10.0.255.2 0 0 32768 65002 i - * 10.10.12.0/24 10.0.255.2 0 0 32768 65002 i - Total number of entries 3 - ``` - diff --git a/gobgpd/main.go b/gobgpd/main.go index a92c837e..8ecc8877 100644 --- a/gobgpd/main.go +++ b/gobgpd/main.go @@ -22,7 +22,6 @@ import ( p "github.com/kr/pretty" api "github.com/osrg/gobgp/api" "github.com/osrg/gobgp/config" - ops "github.com/osrg/gobgp/openswitch" "github.com/osrg/gobgp/packet/bgp" "github.com/osrg/gobgp/server" "io/ioutil" @@ -50,7 +49,6 @@ func main() { Facility string `long:"syslog-facility" description:"specify syslog facility"` DisableStdlog bool `long:"disable-stdlog" description:"disable standard logging"` CPUs int `long:"cpus" description:"specify the number of CPUs to be used"` - Ops bool `long:"openswitch" description:"openswitch mode"` GrpcHosts string `long:"api-hosts" description:"specify the hosts that gobgpd listens on" default:":50051"` GracefulRestart bool `short:"r" long:"graceful-restart" description:"flag restart-state in graceful-restart capability"` Dry bool `short:"d" long:"dry-run" description:"check configuration"` @@ -187,15 +185,7 @@ func main() { } }() - if opts.Ops { - m, err := ops.NewOpsManager(opts.GrpcHosts) - if err != nil { - log.Errorf("Failed to start ops config manager: %s", err) - os.Exit(1) - } - log.Info("Coordination with OpenSwitch") - m.Serve() - } else if opts.ConfigFile != "" { + if opts.ConfigFile != "" { go config.ReadConfigfileServe(opts.ConfigFile, opts.ConfigType, configCh) } diff --git a/openswitch/openswitch.go b/openswitch/openswitch.go deleted file mode 100644 index 7641a9b2..00000000 --- a/openswitch/openswitch.go +++ /dev/null @@ -1,692 +0,0 @@ -// Copyright (C) 2015 Nippon Telegraph and Telephone Corporation. -// -// 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 openswitch - -import ( - "fmt" - "net" - "reflect" - "strconv" - "time" - - log "github.com/Sirupsen/logrus" - api "github.com/osrg/gobgp/api" - "github.com/osrg/gobgp/packet/bgp" - "github.com/osrg/gobgp/table" - "github.com/satori/go.uuid" - ovsdb "github.com/socketplane/libovsdb" - "golang.org/x/net/context" - "google.golang.org/grpc" -) - -const ( - TARGET_TABLE = "OpenSwitch" -) - -const ( - NEXTHOP_TRANSACT_NUUID = "nexthop" - ROUTE_TRANSACT_NUUID = "route" -) - -type Notifier struct { - updateCh chan *ovsdb.TableUpdates -} - -func (n Notifier) Update(context interface{}, tableUpdates ovsdb.TableUpdates) { - n.updateCh <- &tableUpdates -} -func (n Notifier) Locked([]interface{}) { -} -func (n Notifier) Stolen([]interface{}) { -} -func (n Notifier) Echo([]interface{}) { -} -func (n Notifier) Disconnected(client *ovsdb.OvsdbClient) { -} - -func NewNotifier(ch chan *ovsdb.TableUpdates) *Notifier { - return &Notifier{ - updateCh: ch, - } -} - -func (m *OpsManager) populateCache(updates ovsdb.TableUpdates) { - for table, tableUpdate := range updates.Updates { - if _, ok := m.cache[table]; !ok { - m.cache[table] = make(map[string]ovsdb.Row) - - } - for uuid, row := range tableUpdate.Rows { - empty := ovsdb.Row{} - if !reflect.DeepEqual(row.New, empty) { - m.cache[table][uuid] = row.New - } else { - delete(m.cache[table], uuid) - } - } - } -} - -func extractUUID(v interface{}) uuid.UUID { - vv, ok := v.([]interface{}) - if !ok { - return uuid.Nil - } - if len(vv) != 2 || vv[0].(string) != "uuid" { - return uuid.Nil - } - return uuid.FromStringOrNil(vv[1].(string)) -} - -func (m *OpsManager) getRootUUID() (uuid.UUID, error) { - for k, _ := range m.cache[TARGET_TABLE] { - return uuid.FromStringOrNil(k), nil - } - return uuid.Nil, fmt.Errorf("OpenSwitch table not found") -} - -func (m *OpsManager) getVrfUUID() (uuid.UUID, error) { - vrfs, ok := m.cache["VRF"] - if !ok { - return uuid.Nil, fmt.Errorf("VRF table not found") - } - for k, _ := range vrfs { - return uuid.FromStringOrNil(k), nil - } - return uuid.Nil, fmt.Errorf("uuid not found in VRF table") -} - -func (m *OpsManager) getBGPRouterUUID() (uint32, uuid.UUID, error) { - var asn uint32 - vrfs, ok := m.cache["VRF"] - if !ok { - return asn, uuid.Nil, fmt.Errorf("VRF table not found") - } - for _, v := range vrfs { - if v.Fields["name"] == "vrf_default" { - routers := v.Fields["bgp_routers"].(ovsdb.OvsMap).GoMap - if len(routers) < 1 { - return asn, uuid.Nil, fmt.Errorf("no bgp router configured") - } - if len(routers) > 1 { - return asn, uuid.Nil, fmt.Errorf("default vrf has multiple bgp router setting") - } - for k, v := range routers { - asn = uint32(k.(float64)) - id := extractUUID(v) - if id == uuid.Nil { - return asn, uuid.Nil, fmt.Errorf("invalid bgp router schema") - } - return asn, id, nil - } - } - } - return asn, uuid.Nil, fmt.Errorf("row not found in vrf table") -} - -func parseRouteToGobgp(route ovsdb.RowUpdate, nexthops map[string]ovsdb.Row) (*api.Path, bool, bool, error) { - var nlri bgp.AddrPrefixInterface - path := &api.Path{ - IsFromExternal: true, - Pattrs: make([][]byte, 0), - } - isWithdraw := false - isFromGobgp := false - prefix := route.New.Fields["prefix"].(string) - safi := route.New.Fields["sub_address_family"].(string) - afi := route.New.Fields["address_family"].(string) - m := route.New.Fields["metric"].(float64) - attrs := route.New.Fields["path_attributes"].(ovsdb.OvsMap).GoMap - - if attrs["IsFromGobgp"] == "true" { - isFromGobgp = true - } - - nh := make([]interface{}, 0) - nhId, ok := route.New.Fields["bgp_nexthops"].(ovsdb.UUID) - if ok { - for id, n := range nexthops { - if id == nhId.GoUUID { - nh = append(nh, n.Fields["ip_address"]) - } - } - } - - nexthop := "0.0.0.0" - if afi == "ipv6" { - nexthop = "::" - } - if len(nh) == 0 { - log.WithFields(log.Fields{ - "Topic": "openswitch", - }).Debug("nexthop address does not exist") - } else if len(nh) == 1 { - if net.ParseIP(nh[0].(string)) == nil { - return nil, isWithdraw, isFromGobgp, fmt.Errorf("invalid nexthop address") - } else { - nexthop = nh[0].(string) - } - } else { - return nil, isWithdraw, isFromGobgp, fmt.Errorf("route has multiple nexthop address") - } - - med, _ := bgp.NewPathAttributeMultiExitDisc(uint32(m)).Serialize() - path.Pattrs = append(path.Pattrs, med) - - lpref, err := strconv.Atoi(attrs["BGP_loc_pref"].(string)) - if err != nil { - return nil, isWithdraw, isFromGobgp, err - } - localPref, _ := bgp.NewPathAttributeLocalPref(uint32(lpref)).Serialize() - path.Pattrs = append(path.Pattrs, localPref) - - var origin_t int - switch attrs["BGP_origin"].(string) { - case "i": - origin_t = bgp.BGP_ORIGIN_ATTR_TYPE_IGP - case "e": - origin_t = bgp.BGP_ORIGIN_ATTR_TYPE_EGP - case "?": - origin_t = bgp.BGP_ORIGIN_ATTR_TYPE_INCOMPLETE - default: - return nil, isWithdraw, isFromGobgp, fmt.Errorf("invalid origin") - } - origin, _ := bgp.NewPathAttributeOrigin(uint8(origin_t)).Serialize() - path.Pattrs = append(path.Pattrs, origin) - - switch afi { - case "ipv4", "ipv6": - ip, net, err := net.ParseCIDR(prefix) - if err != nil { - return nil, isWithdraw, isFromGobgp, err - } - ones, _ := net.Mask.Size() - if afi == "ipv4" { - if ip.To4() == nil { - return nil, isWithdraw, isFromGobgp, fmt.Errorf("invalid ipv4 prefix") - } - nlri = bgp.NewIPAddrPrefix(uint8(ones), ip.String()) - } else { - if ip.To16() == nil { - return nil, isWithdraw, isFromGobgp, fmt.Errorf("invalid ipv6 prefix") - } - nlri = bgp.NewIPv6AddrPrefix(uint8(ones), ip.String()) - } - default: - return nil, isWithdraw, isFromGobgp, fmt.Errorf("unsupported address family: %s", afi) - } - - if afi == "ipv4" && safi == "unicast" { - path.Nlri, _ = nlri.Serialize() - n, _ := bgp.NewPathAttributeNextHop(nexthop).Serialize() - path.Pattrs = append(path.Pattrs, n) - } else { - mpreach, _ := bgp.NewPathAttributeMpReachNLRI(nexthop, []bgp.AddrPrefixInterface{nlri}).Serialize() - path.Pattrs = append(path.Pattrs, mpreach) - } - if attrs["BGP_flags"].(string) == "512" { - isWithdraw = true - } - - return path, isWithdraw, isFromGobgp, nil -} - -func (m *OpsManager) getBGPNeighborUUIDs(id uuid.UUID) ([]net.IP, []uuid.UUID, error) { - global, ok := m.cache["BGP_Router"] - if !ok { - return nil, nil, fmt.Errorf("BGP_Router table not found") - } - for k, v := range global { - if uuid.Equal(id, uuid.FromStringOrNil(k)) { - neighbors := v.Fields["bgp_neighbors"].(ovsdb.OvsMap).GoMap - if len(neighbors) < 1 { - return nil, nil, fmt.Errorf("no bgp neighbor configured") - } - addrs := make([]net.IP, 0, len(neighbors)) - ids := make([]uuid.UUID, 0, len(neighbors)) - for k, v := range neighbors { - addrs = append(addrs, net.ParseIP(k.(string))) - id := extractUUID(v) - if id == uuid.Nil { - return nil, nil, fmt.Errorf("invalid uuid schema") - } - ids = append(ids, id) - } - return addrs, ids, nil - } - } - return nil, nil, fmt.Errorf("neighbor not found") -} - -func (m *OpsManager) handleVrfUpdate(cli api.GobgpApiClient, update ovsdb.TableUpdate) { - for _, v := range update.Rows { - if len(v.Old.Fields) == 0 { - log.WithFields(log.Fields{ - "Topic": "openswitch", - }).Debug("new vrf") - } else if _, ok := v.Old.Fields["bgp_routers"]; ok { - if _, _, err := m.getBGPRouterUUID(); err != nil { - cli.StopServer(context.Background(), &api.StopServerRequest{}) - return - } - } - } -} - -func (m *OpsManager) handleBgpRouterUpdate(cli api.GobgpApiClient, update ovsdb.TableUpdate) { - asn, id, err := m.getBGPRouterUUID() - if err != nil { - log.WithFields(log.Fields{ - "Topic": "openswitch", - "Error": err, - }).Debug("Could not get BGP Router UUID") - return - } - for k, v := range update.Rows { - if uuid.Equal(id, uuid.FromStringOrNil(k)) { - initial := false - if len(v.Old.Fields) == 0 { - log.WithFields(log.Fields{ - "Topic": "openswitch", - }).Debug("new bgp router") - initial = true - } - if _, ok := v.Old.Fields["router_id"]; initial || ok { - r, ok := v.New.Fields["router_id"].(string) - if !ok { - log.WithFields(log.Fields{ - "Topic": "openswitch", - }).Debug("router-id is not configured yet") - return - } - cli.StartServer(context.Background(), &api.StartServerRequest{ - Global: &api.Global{ - As: asn, - RouterId: r, - }, - }) - } - if o, ok := v.Old.Fields["bgp_neighbors"]; ok { - oldNeighMap := o.(ovsdb.OvsMap).GoMap - newNeighMap := v.New.Fields["bgp_neighbors"].(ovsdb.OvsMap).GoMap - for k, _ := range oldNeighMap { - if _, ok := newNeighMap[k]; !ok { - cli.DeleteNeighbor(context.Background(), &api.DeleteNeighborRequest{ - Peer: &api.Peer{ - Conf: &api.PeerConf{ - NeighborAddress: k.(string), - }, - }, - }) - } - } - } - } - } -} - -func (m *OpsManager) handleNeighborUpdate(cli api.GobgpApiClient, update ovsdb.TableUpdate) { - _, id, _ := m.getBGPRouterUUID() - addrs, ids, err := m.getBGPNeighborUUIDs(id) - if err != nil { - return - } - for k, v := range update.Rows { - for idx, id := range ids { - if uuid.Equal(id, uuid.FromStringOrNil(k)) { - asn, ok := v.New.Fields["remote_as"].(float64) - if !ok { - log.WithFields(log.Fields{ - "Topic": "openswitch", - }).Debug("remote-as is not configured yet") - continue - } - cli.AddNeighbor(context.Background(), &api.AddNeighborRequest{ - Peer: &api.Peer{ - Conf: &api.PeerConf{ - NeighborAddress: addrs[idx].String(), - PeerAs: uint32(asn), - }, - }, - }) - } - } - } -} - -func (m *OpsManager) handleRouteUpdate(cli api.GobgpApiClient, update ovsdb.TableUpdate) { - id, _ := m.getVrfUUID() - for _, v := range update.Rows { - vrf := v.New.Fields["vrf"] - if vrf == nil { - continue - } - idx := vrf.(ovsdb.UUID).GoUUID - if uuid.Equal(id, uuid.FromStringOrNil(idx)) { - path, isWithdraw, isFromGobgp, err := parseRouteToGobgp(v, m.cache["BGP_Nexthop"]) - if err != nil { - log.WithFields(log.Fields{ - "Topic": "openswitch", - "Path": path, - "Error": err, - }).Debug("failed to parse path") - return - } - if isWithdraw { - cli.DeletePath(context.Background(), &api.DeletePathRequest{ - Resource: api.Resource_GLOBAL, - Path: path, - }) - } else { - if isFromGobgp { - return - } - cli.AddPath(context.Background(), &api.AddPathRequest{ - Resource: api.Resource_GLOBAL, - Path: path, - }) - } - } - } -} - -func parseRouteToOps(p *table.Path) (map[string]interface{}, bool, error) { - route := map[string]interface{}{"metric": 0, "peer": "Remote announcement"} - IsWithdraw := false - var nexthop string - pathAttr := map[string]string{"BGP_iBGP": "false", - "BGP_flags": "16", - "BGP_internal": "false", - "BGP_loc_pref": "0", - "IsFromGobgp": "true", - } - for _, a := range p.GetPathAttrs() { - switch a.GetType() { - case bgp.BGP_ATTR_TYPE_NEXT_HOP: - nexthop = a.(*bgp.PathAttributeNextHop).Value.String() - case bgp.BGP_ATTR_TYPE_MP_REACH_NLRI: - n := a.(*bgp.PathAttributeMpReachNLRI).Nexthop - if n != nil { - nexthop = n.String() - } else { - nexthop = "" - } - case bgp.BGP_ATTR_TYPE_AS_PATH: - pathAttr["BGP_AS_path"] = a.(*bgp.PathAttributeAsPath).String() - case bgp.BGP_ATTR_TYPE_ORIGIN: - origin := "-" - switch a.(*bgp.PathAttributeOrigin).Value[0] { - case bgp.BGP_ORIGIN_ATTR_TYPE_IGP: - origin = "i" - case bgp.BGP_ORIGIN_ATTR_TYPE_EGP: - origin = "e" - case bgp.BGP_ORIGIN_ATTR_TYPE_INCOMPLETE: - origin = "?" - } - pathAttr["BGP_origin"] = origin - case bgp.BGP_ATTR_TYPE_LOCAL_PREF: - pathAttr["BGP_loc_pref"] = fmt.Sprintf("%v", a.(*bgp.PathAttributeLocalPref).Value) - case bgp.BGP_ATTR_TYPE_MULTI_EXIT_DISC: - route["metric"] = a.(*bgp.PathAttributeMultiExitDisc).Value - default: - continue - } - } - IsWithdraw = p.IsWithdraw - afi := "ipv4" - if p.GetNlri().AFI() != bgp.AFI_IP { - afi = "ipv6" - } - safi := "unicast" - - route["prefix"] = p.GetNlri().String() - route["address_family"] = afi - route["sub_address_family"] = safi - route["bgp_nexthops"] = nexthop - route["path_attributes"] = pathAttr - - return route, IsWithdraw, nil -} - -func insertNextHop(opsRoute map[string]interface{}) ovsdb.Operation { - nexthop := make(map[string]interface{}) - nexthop["ip_address"] = opsRoute["bgp_nexthops"] - nexthop["type"] = opsRoute["sub_address_family"] - insNextHopOp := ovsdb.Operation{ - Op: "insert", - Table: "BGP_Nexthop", - Row: nexthop, - UUIDName: NEXTHOP_TRANSACT_NUUID, - } - return insNextHopOp -} - -func insertRoute(vrfId uuid.UUID, opsRoute map[string]interface{}) (ovsdb.Operation, error) { - v := []ovsdb.UUID{ovsdb.UUID{vrfId.String()}} - vrfSet, _ := ovsdb.NewOvsSet(v) - opsRoute["vrf"] = vrfSet - - nexthop := []ovsdb.UUID{ovsdb.UUID{NEXTHOP_TRANSACT_NUUID}} - nexthopSet, _ := ovsdb.NewOvsSet(nexthop) - opsRoute["bgp_nexthops"] = nexthopSet - - attrMap, err := ovsdb.NewOvsMap(opsRoute["path_attributes"]) - if err != nil { - return ovsdb.Operation{}, err - } - - opsRoute["path_attributes"] = attrMap - - insRouteOp := ovsdb.Operation{ - Op: "insert", - Table: "BGP_Route", - Row: opsRoute, - UUIDName: ROUTE_TRANSACT_NUUID, - } - return insRouteOp, nil -} - -func deleteRoute(opsRoute map[string]interface{}) ovsdb.Operation { - condition := ovsdb.NewCondition("prefix", "==", opsRoute["prefix"]) - deleteOp := ovsdb.Operation{ - Op: "delete", - Table: "BGP_Route", - Where: []interface{}{condition}, - } - return deleteOp -} - -func (m *OpsManager) TransactPreparation(p *table.Path) (*OpsOperation, error) { - v, err := m.getVrfUUID() - if err != nil { - return nil, err - } - opsRoute, isWithdraw, err := parseRouteToOps(p) - if err != nil { - return nil, err - } - - var o []ovsdb.Operation - if !isWithdraw { - insNextHopOp := insertNextHop(opsRoute) - insRouteOp, err := insertRoute(v, opsRoute) - if err != nil { - return nil, err - } - o = []ovsdb.Operation{insNextHopOp, insRouteOp} - } else { - delRouteOp := deleteRoute(opsRoute) - o = []ovsdb.Operation{delRouteOp} - } - oOperation := &OpsOperation{ - operations: o, - } - return oOperation, nil -} - -func (m *OpsManager) Transact(operations []ovsdb.Operation) error { - ops := m.ops - reply, err := ops.Transact(TARGET_TABLE, operations...) - if err != nil { - return err - } - if len(reply) < len(operations) { - return fmt.Errorf("number of replies should be atleast equal to number of Operations") - } - var repErr error - for i, o := range reply { - if o.Error != "" && i < len(operations) { - repErr = fmt.Errorf("transaction failed due to an error :", o.Error, " details:", o.Details, " in ", operations[i]) - } else if o.Error != "" { - repErr = fmt.Errorf("transaction failed due to an error :", o.Error) - } - } - if repErr != nil { - return repErr - } - return nil -} - -func (m *OpsManager) GobgpMonitor(target string) { - time.Sleep(time.Duration(time.Second * 2)) - - conn, err := grpc.Dial(target, grpc.WithTimeout(time.Second), grpc.WithBlock(), grpc.WithInsecure()) - if err != nil { - log.Fatal(err) - } - cli := api.NewGobgpApiClient(conn) - rsp, err := cli.GetServer(context.Background(), &api.GetServerRequest{}) - if err != nil { - log.Fatal(err) - } - nativeOption := api.ToNativeOption{ - LocalAS: uint32(rsp.Global.As), - LocalID: net.ParseIP(rsp.Global.RouterId), - } - stream, err := cli.MonitorRib(context.Background(), &api.Table{ - Type: api.Resource_GLOBAL, - Family: uint32(bgp.RF_IPv4_UC), - }) - if err != nil { - log.Fatal(err) - } - for { - d, err := stream.Recv() - if err != nil { - log.Fatal(err) - } - dst, err := d.ToNativeDestination(nativeOption) - if err != nil { - log.WithFields(log.Fields{ - "Topic": "openswitch", - }).Error(err) - continue - } - path := dst.GetAllKnownPathList()[0] - if path.IsLocal() && !path.IsWithdraw { - continue - } - o, err := m.TransactPreparation(path) - if err != nil { - log.WithFields(log.Fields{ - "Topic": "openswitch", - "Type": "Monitor", - "Error": err, - }).Error("failed transact preparation of ops") - } - m.opsCh <- o - } -} - -func (m *OpsManager) OpsServe(target string) error { - initial, err := m.ops.MonitorAll(TARGET_TABLE, "") - if err != nil { - return err - } - go func() { - m.opsUpdateCh <- initial - }() - conn, err := grpc.Dial(target, grpc.WithTimeout(time.Second), grpc.WithBlock(), grpc.WithInsecure()) - if err != nil { - log.Fatal(err) - } - cli := api.NewGobgpApiClient(conn) - for { - select { - case updates := <-m.opsUpdateCh: - m.populateCache(*updates) - if t, ok := updates.Updates["VRF"]; ok { - m.handleVrfUpdate(cli, t) - } - if t, ok := updates.Updates["BGP_Router"]; ok { - m.handleBgpRouterUpdate(cli, t) - } - if t, ok := updates.Updates["BGP_Neighbor"]; ok { - m.handleNeighborUpdate(cli, t) - } - if t, ok := updates.Updates["BGP_Route"]; ok { - m.handleRouteUpdate(cli, t) - } - case r := <-m.opsCh: - if err := m.Transact(r.operations); err != nil { - } - } - } - return nil -} - -func (m *OpsManager) Serve() error { - go m.OpsServe(m.target) - go m.GobgpMonitor(m.target) - return nil -} - -type OpsOperation struct { - operations []ovsdb.Operation -} - -type OpsChs struct { - opsCh chan *OpsOperation - opsUpdateCh chan *ovsdb.TableUpdates -} - -type OpsManager struct { - ops *ovsdb.OvsdbClient - opsCh chan *OpsOperation - opsUpdateCh chan *ovsdb.TableUpdates - bgpReady bool - cache map[string]map[string]ovsdb.Row - target string -} - -func NewOpsManager(target string) (*OpsManager, error) { - ops, err := ovsdb.Connect("", 0) - if err != nil { - return nil, err - } - opsUpdateCh := make(chan *ovsdb.TableUpdates) - n := NewNotifier(opsUpdateCh) - ops.Register(n) - - return &OpsManager{ - ops: ops, - opsCh: make(chan *OpsOperation, 1024), - opsUpdateCh: opsUpdateCh, - bgpReady: false, - cache: make(map[string]map[string]ovsdb.Row), - target: target, - }, nil -} |