//AddLocalProtoRoute is used to add local endpoint to the protocol RIB func (self *OfnetBgp) AddLocalProtoRoute(pathInfo []*OfnetProtoRouteInfo) error { if self.routerIP == "" { //ignoring populating to the bgp rib because //Bgp is not configured. return nil } log.Infof("Received AddLocalProtoRoute to add local endpoint to protocol RIB: %+v", pathInfo) // add routes attrs := []bgp.PathAttributeInterface{ bgp.NewPathAttributeOrigin(1), bgp.NewPathAttributeNextHop(pathInfo[0].nextHopIP), bgp.NewPathAttributeAsPath([]bgp.AsPathParamInterface{bgp.NewAs4PathParam(bgp.BGP_ASPATH_ATTR_TYPE_SEQ, []uint32{self.myBgpAs})}), } paths := []*table.Path{} for _, path := range pathInfo { paths = append(paths, table.NewPath(nil, bgp.NewIPAddrPrefix(32, path.localEpIP), false, attrs, time.Now(), false)) } _, err := self.bgpServer.AddPath("", paths) if err != nil { return err } return nil }
func createPathFromIPRouteMessage(m *zebra.Message) *table.Path { header := m.Header body := m.Body.(*zebra.IPRouteBody) family := bgp.RF_IPv6_UC if header.Command == zebra.IPV4_ROUTE_ADD || header.Command == zebra.IPV4_ROUTE_DELETE { family = bgp.RF_IPv4_UC } var nlri bgp.AddrPrefixInterface pattr := make([]bgp.PathAttributeInterface, 0) var mpnlri *bgp.PathAttributeMpReachNLRI var isWithdraw bool = header.Command == zebra.IPV4_ROUTE_DELETE || header.Command == zebra.IPV6_ROUTE_DELETE origin := bgp.NewPathAttributeOrigin(bgp.BGP_ORIGIN_ATTR_TYPE_IGP) pattr = append(pattr, origin) log.WithFields(log.Fields{ "Topic": "Zebra", "RouteType": body.Type.String(), "Flag": body.Flags.String(), "Message": body.Message, "Prefix": body.Prefix, "PrefixLength": body.PrefixLength, "Nexthop": body.Nexthops, "IfIndex": body.Ifindexs, "Metric": body.Metric, "Distance": body.Distance, "api": header.Command.String(), }).Debugf("create path from ip route message.") switch family { case bgp.RF_IPv4_UC: nlri = bgp.NewIPAddrPrefix(body.PrefixLength, body.Prefix.String()) nexthop := bgp.NewPathAttributeNextHop(body.Nexthops[0].String()) pattr = append(pattr, nexthop) case bgp.RF_IPv6_UC: nlri = bgp.NewIPv6AddrPrefix(body.PrefixLength, body.Prefix.String()) mpnlri = bgp.NewPathAttributeMpReachNLRI(body.Nexthops[0].String(), []bgp.AddrPrefixInterface{nlri}) pattr = append(pattr, mpnlri) default: log.WithFields(log.Fields{ "Topic": "Zebra", }).Errorf("unsupport address family: %s", family) return nil } med := bgp.NewPathAttributeMultiExitDisc(body.Metric) pattr = append(pattr, med) path := table.NewPath(nil, nlri, isWithdraw, pattr, time.Now(), false) path.SetIsFromExternal(true) return path }
func (bs *BgpService) DelPath(route string) error { attrs := []bgp.PathAttributeInterface{ bgp.NewPathAttributeNextHop("0.0.0.0"), } if err := bs.bgp.DeletePath([]byte{}, bgp.RF_IPv4_UC, "", []*table.Path{table.NewPath(nil, bgp.NewIPAddrPrefix(32, route), true, attrs, time.Now(), false)}); err != nil { return fmt.Errorf("[bgp] Error deleting bgp path. %v", err) } return nil }
func (bs *BgpService) AddPath(route string) error { attrs := []bgp.PathAttributeInterface{ bgp.NewPathAttributeOrigin(0), bgp.NewPathAttributeNextHop("0.0.0.0"), } if _, err := bs.bgp.AddPath("", []*table.Path{table.NewPath(nil, bgp.NewIPAddrPrefix(32, route), false, attrs, time.Now(), false)}); err != nil { return fmt.Errorf("[bgp] Error adding bgp path. %v", err) } return nil }
func createPathFromIPRouteMessage(m *zebra.Message, peerInfo *table.PeerInfo) *table.Path { header := m.Header body := m.Body.(*zebra.IPRouteBody) isV4 := header.Command == zebra.IPV4_ROUTE_ADD || header.Command == zebra.IPV4_ROUTE_DELETE var nlri bgp.AddrPrefixInterface pattr := make([]bgp.PathAttributeInterface, 0) var mpnlri *bgp.PathAttributeMpReachNLRI var isWithdraw bool = header.Command == zebra.IPV4_ROUTE_DELETE || header.Command == zebra.IPV6_ROUTE_DELETE origin := bgp.NewPathAttributeOrigin(bgp.BGP_ORIGIN_ATTR_TYPE_IGP) pattr = append(pattr, origin) log.WithFields(log.Fields{ "Topic": "Zebra", "RouteType": body.Type.String(), "Flag": body.Flags.String(), "Message": body.Message, "Prefix": body.Prefix, "PrefixLength": body.PrefixLength, "Nexthop": body.Nexthops, "IfIndex": body.Ifindexs, "Metric": body.Metric, "Distance": body.Distance, "api": header.Command.String(), }).Debugf("create path from ip route message.") if isV4 { nlri = bgp.NewIPAddrPrefix(body.PrefixLength, body.Prefix.String()) nexthop := bgp.NewPathAttributeNextHop(body.Nexthops[0].String()) pattr = append(pattr, nexthop) } else { nlri = bgp.NewIPv6AddrPrefix(body.PrefixLength, body.Prefix.String()) mpnlri = bgp.NewPathAttributeMpReachNLRI(body.Nexthops[0].String(), []bgp.AddrPrefixInterface{nlri}) pattr = append(pattr, mpnlri) } med := bgp.NewPathAttributeMultiExitDisc(body.Metric) pattr = append(pattr, med) p := table.NewPath(peerInfo, nlri, isWithdraw, pattr, false, time.Now(), false) p.IsFromZebra = true return p }
//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) attrs := []bgp.PathAttributeInterface{ bgp.NewPathAttributeOrigin(1), bgp.NewPathAttributeNextHop(pathInfo[0].nextHopIP), bgp.NewPathAttributeAsPath([]bgp.AsPathParamInterface{bgp.NewAs4PathParam(bgp.BGP_ASPATH_ATTR_TYPE_SEQ, []uint32{self.myBgpAs})}), } paths := []*table.Path{} for _, path := range pathInfo { paths = append(paths, table.NewPath(nil, bgp.NewIPAddrPrefix(32, path.localEpIP), true, attrs, time.Now(), false)) } if err := self.bgpServer.DeletePath(nil, bgp.RF_IPv4_UC, "", paths); err != nil { return err } return nil }
func (p *Path) ToNativePath(option ...ToNativeOption) (*table.Path, error) { info := &table.PeerInfo{ AS: p.SourceAsn, ID: net.ParseIP(p.SourceId), Address: net.ParseIP(p.NeighborIp), } var nlri bgp.AddrPrefixInterface for _, o := range option { info.LocalAS = o.LocalAS info.LocalID = o.LocalID info.RouteReflectorClient = o.RouteReflectorClient info.RouteReflectorClusterID = o.RouteReflectorClusterID nlri = o.NLRI } if nlri == nil { var err error nlri, err = getNLRI(bgp.RouteFamily(p.Family), p.Nlri) if err != nil { return nil, err } } pattr := make([]bgp.PathAttributeInterface, 0, len(p.Pattrs)) for _, attr := range p.Pattrs { p, err := bgp.GetPathAttribute(attr) if err != nil { return nil, err } err = p.DecodeFromBytes(attr) if err != nil { return nil, err } pattr = append(pattr, p) } t := time.Unix(p.Age, 0) path := table.NewPath(info, nlri, p.IsWithdraw, pattr, t, false) path.SetValidation(config.IntToRpkiValidationResultTypeMap[int(p.Validation)]) path.MarkStale(p.Stale) if p.Filtered { path.Filter("", table.POLICY_DIRECTION_IN) } return path, nil }
func injectMrt(r string, filename string, count int, skip int, onlyBest bool) error { var resource api.Resource switch r { case CMD_GLOBAL: resource = api.Resource_GLOBAL default: return fmt.Errorf("unknown resource type: %s", r) } file, err := os.Open(filename) if err != nil { return fmt.Errorf("failed to open file: %s", err) } idx := 0 ch := make(chan *api.InjectMrtRequest, 1<<20) go func() { var peers []*mrt.Peer for { buf := make([]byte, mrt.MRT_COMMON_HEADER_LEN) _, err := file.Read(buf) if err == io.EOF { break } else if err != nil { exitWithError(fmt.Errorf("failed to read: %s", err)) } h := &mrt.MRTHeader{} err = h.DecodeFromBytes(buf) if err != nil { exitWithError(fmt.Errorf("failed to parse")) } buf = make([]byte, h.Len) _, err = file.Read(buf) if err != nil { exitWithError(fmt.Errorf("failed to read")) } msg, err := mrt.ParseMRTBody(h, buf) if err != nil { printError(fmt.Errorf("failed to parse: %s", err)) continue } if globalOpts.Debug { fmt.Println(msg) } if msg.Header.Type == mrt.TABLE_DUMPv2 { subType := mrt.MRTSubTypeTableDumpv2(msg.Header.SubType) var rf bgp.RouteFamily switch subType { case mrt.PEER_INDEX_TABLE: peers = msg.Body.(*mrt.PeerIndexTable).Peers continue case mrt.RIB_IPV4_UNICAST: rf = bgp.RF_IPv4_UC case mrt.RIB_IPV6_UNICAST: rf = bgp.RF_IPv6_UC default: exitWithError(fmt.Errorf("unsupported subType: %s", subType)) } if peers == nil { exitWithError(fmt.Errorf("not found PEER_INDEX_TABLE")) } rib := msg.Body.(*mrt.Rib) nlri := rib.Prefix paths := make([]*api.Path, 0, len(rib.Entries)) for _, e := range rib.Entries { if len(peers) < int(e.PeerIndex) { exitWithError(fmt.Errorf("invalid peer index: %d (PEER_INDEX_TABLE has only %d peers)\n", e.PeerIndex, len(peers))) } if !onlyBest { path := &api.Path{ Pattrs: make([][]byte, 0), NoImplicitWithdraw: true, SourceAsn: peers[e.PeerIndex].AS, SourceId: peers[e.PeerIndex].BgpId.String(), } if rf == bgp.RF_IPv4_UC { path.Nlri, _ = nlri.Serialize() } for _, p := range e.PathAttributes { b, err := p.Serialize() if err != nil { continue } path.Pattrs = append(path.Pattrs, b) } paths = append(paths, path) } } if onlyBest { paths = func() []*api.Path { dst := table.NewDestination(nlri) pathList := make([]*table.Path, 0, len(rib.Entries)) for _, e := range rib.Entries { p := table.NewPath(&table.PeerInfo{AS: peers[e.PeerIndex].AS, ID: peers[e.PeerIndex].BgpId}, nlri, false, e.PathAttributes, time.Unix(int64(e.OriginatedTime), 0), false) dst.AddNewPath(p) pathList = append(pathList, p) } best, _, _ := dst.Calculate([]string{table.GLOBAL_RIB_NAME}) for _, p := range pathList { if p == best[table.GLOBAL_RIB_NAME] { nb, _ := nlri.Serialize() return []*api.Path{&api.Path{ Nlri: nb, NoImplicitWithdraw: true, SourceAsn: p.GetSource().AS, SourceId: p.GetSource().ID.String(), Pattrs: func() [][]byte { attrs := make([][]byte, 0) for _, a := range p.GetPathAttrs() { if b, e := a.Serialize(); e == nil { attrs = append(attrs, b) } } return attrs }(), }} } } exitWithError(fmt.Errorf("Can't find the best %v", nlri)) return []*api.Path{} }() } if idx >= skip { ch <- &api.InjectMrtRequest{ Resource: resource, Paths: paths, } } idx += 1 if idx == count+skip { break } } } close(ch) }() stream, err := client.InjectMrt(context.Background()) if err != nil { return fmt.Errorf("failed to modpath: %s", err) } for arg := range ch { err = stream.Send(arg) if err != nil { return fmt.Errorf("failed to send: %s", err) } } _, err = stream.CloseAndRecv() if err != nil { return fmt.Errorf("failed to send: %s", err) } return nil }
func injectMrt(filename string, count int, skip int, onlyBest bool) error { file, err := os.Open(filename) if err != nil { return fmt.Errorf("failed to open file: %s", err) } idx := 0 ch := make(chan []*table.Path, 1<<20) go func() { var peers []*mrt.Peer for { buf := make([]byte, mrt.MRT_COMMON_HEADER_LEN) _, err := file.Read(buf) if err == io.EOF { break } else if err != nil { exitWithError(fmt.Errorf("failed to read: %s", err)) } h := &mrt.MRTHeader{} err = h.DecodeFromBytes(buf) if err != nil { exitWithError(fmt.Errorf("failed to parse")) } buf = make([]byte, h.Len) _, err = file.Read(buf) if err != nil { exitWithError(fmt.Errorf("failed to read")) } msg, err := mrt.ParseMRTBody(h, buf) if err != nil { printError(fmt.Errorf("failed to parse: %s", err)) continue } if globalOpts.Debug { fmt.Println(msg) } if msg.Header.Type == mrt.TABLE_DUMPv2 { subType := mrt.MRTSubTypeTableDumpv2(msg.Header.SubType) switch subType { case mrt.PEER_INDEX_TABLE: peers = msg.Body.(*mrt.PeerIndexTable).Peers continue default: exitWithError(fmt.Errorf("unsupported subType: %v", subType)) } if peers == nil { exitWithError(fmt.Errorf("not found PEER_INDEX_TABLE")) } rib := msg.Body.(*mrt.Rib) nlri := rib.Prefix paths := make([]*table.Path, 0, len(rib.Entries)) for _, e := range rib.Entries { if len(peers) < int(e.PeerIndex) { exitWithError(fmt.Errorf("invalid peer index: %d (PEER_INDEX_TABLE has only %d peers)\n", e.PeerIndex, len(peers))) } source := &table.PeerInfo{ AS: peers[e.PeerIndex].AS, ID: peers[e.PeerIndex].BgpId, } t := time.Unix(int64(e.OriginatedTime), 0) paths = append(paths, table.NewPath(source, nlri, false, e.PathAttributes, t, false)) } if onlyBest { dst := table.NewDestination(nlri) for _, p := range paths { dst.AddNewPath(p) } best, _, _ := dst.Calculate([]string{table.GLOBAL_RIB_NAME}) if best[table.GLOBAL_RIB_NAME] == nil { exitWithError(fmt.Errorf("Can't find the best %v", nlri)) } paths = []*table.Path{best[table.GLOBAL_RIB_NAME]} } if idx >= skip { ch <- paths } idx += 1 if idx == count+skip { break } } } close(ch) }() stream, err := client.AddPathByStream() if err != nil { return fmt.Errorf("failed to modpath: %s", err) } for paths := range ch { err = stream.Send(paths...) if err != nil { return fmt.Errorf("failed to send: %s", err) } } if err := stream.Close(); err != nil { return fmt.Errorf("failed to send: %s", err) } return nil }
func TestMonitor(test *testing.T) { assert := assert.New(test) s := NewBgpServer() go s.Serve() s.Start(&config.Global{ Config: config.GlobalConfig{ As: 1, RouterId: "1.1.1.1", Port: 10179, }, }) n := &config.Neighbor{ Config: config.NeighborConfig{ NeighborAddress: "127.0.0.1", PeerAs: 2, }, Transport: config.Transport{ Config: config.TransportConfig{ PassiveMode: true, }, }, } if err := s.AddNeighbor(n); err != nil { log.Fatal(err) } t := NewBgpServer() go t.Serve() t.Start(&config.Global{ Config: config.GlobalConfig{ As: 2, RouterId: "2.2.2.2", Port: -1, }, }) m := &config.Neighbor{ Config: config.NeighborConfig{ NeighborAddress: "127.0.0.1", PeerAs: 1, }, Transport: config.Transport{ Config: config.TransportConfig{ RemotePort: 10179, }, }, } if err := t.AddNeighbor(m); err != nil { log.Fatal(err) } for { time.Sleep(time.Second) if t.GetNeighbor(false)[0].State.SessionState == config.SESSION_STATE_ESTABLISHED { break } } w := s.Watch(WatchBestPath()) attrs := []bgp.PathAttributeInterface{ bgp.NewPathAttributeOrigin(0), bgp.NewPathAttributeNextHop("10.0.0.1"), } if _, err := t.AddPath("", []*table.Path{table.NewPath(nil, bgp.NewIPAddrPrefix(24, "10.0.0.0"), false, attrs, time.Now(), false)}); err != nil { log.Fatal(err) } ev := <-w.Event() b := ev.(*WatchEventBestPath) assert.Equal(len(b.PathList), 1) assert.Equal(b.PathList[0].GetNlri().String(), "10.0.0.0/24") assert.Equal(b.PathList[0].IsWithdraw, false) if _, err := t.AddPath("", []*table.Path{table.NewPath(nil, bgp.NewIPAddrPrefix(24, "10.0.0.0"), true, attrs, time.Now(), false)}); err != nil { log.Fatal(err) } ev = <-w.Event() b = ev.(*WatchEventBestPath) assert.Equal(len(b.PathList), 1) assert.Equal(b.PathList[0].GetNlri().String(), "10.0.0.0/24") assert.Equal(b.PathList[0].IsWithdraw, true) }
func (s *Server) api2PathList(resource Resource, ApiPathList []*Path) ([]*table.Path, error) { var nlri bgp.AddrPrefixInterface var nexthop string var pi *table.PeerInfo pathList := make([]*table.Path, 0, len(ApiPathList)) for _, path := range ApiPathList { seen := make(map[bgp.BGPAttrType]bool) pattr := make([]bgp.PathAttributeInterface, 0) extcomms := make([]bgp.ExtendedCommunityInterface, 0) if path.SourceAsn != 0 { pi = &table.PeerInfo{ AS: path.SourceAsn, LocalID: net.ParseIP(path.SourceId), } } if len(path.Nlri) > 0 { nlri = &bgp.IPAddrPrefix{} err := nlri.DecodeFromBytes(path.Nlri) if err != nil { return nil, err } } for _, attr := range path.Pattrs { p, err := bgp.GetPathAttribute(attr) if err != nil { return nil, err } err = p.DecodeFromBytes(attr) if err != nil { return nil, err } if _, ok := seen[p.GetType()]; !ok { seen[p.GetType()] = true } else { return nil, fmt.Errorf("the path attribute apears twice. Type : " + strconv.Itoa(int(p.GetType()))) } switch p.GetType() { case bgp.BGP_ATTR_TYPE_NEXT_HOP: nexthop = p.(*bgp.PathAttributeNextHop).Value.String() case bgp.BGP_ATTR_TYPE_EXTENDED_COMMUNITIES: value := p.(*bgp.PathAttributeExtendedCommunities).Value if len(value) > 0 { extcomms = append(extcomms, value...) } case bgp.BGP_ATTR_TYPE_MP_REACH_NLRI: mpreach := p.(*bgp.PathAttributeMpReachNLRI) if len(mpreach.Value) != 1 { return nil, fmt.Errorf("include only one route in mp_reach_nlri") } nlri = mpreach.Value[0] nexthop = mpreach.Nexthop.String() default: pattr = append(pattr, p) } } if nlri == nil || nexthop == "" { return nil, fmt.Errorf("not found nlri or nexthop") } rf := bgp.AfiSafiToRouteFamily(nlri.AFI(), nlri.SAFI()) if resource != Resource_VRF && rf == bgp.RF_IPv4_UC { pattr = append(pattr, bgp.NewPathAttributeNextHop(nexthop)) } else { pattr = append(pattr, bgp.NewPathAttributeMpReachNLRI(nexthop, []bgp.AddrPrefixInterface{nlri})) } if len(extcomms) > 0 { pattr = append(pattr, bgp.NewPathAttributeExtendedCommunities(extcomms)) } newPath := table.NewPath(pi, nlri, path.IsWithdraw, pattr, time.Now(), path.NoImplicitWithdraw) newPath.SetIsFromExternal(path.IsFromExternal) pathList = append(pathList, newPath) } return pathList, nil }
func ParsePath(rf bgp.RouteFamily, args []string) (*table.Path, error) { var nlri bgp.AddrPrefixInterface var rd bgp.RouteDistinguisherInterface var extcomms []string var err error attrs := table.PathAttrs(make([]bgp.PathAttributeInterface, 0, 1)) fns := []func([]string) ([]string, bgp.PathAttributeInterface, error){ extractOrigin, extractMed, extractLocalPref, extractCommunity, extractAigp, extractAggregator, extractLargeCommunity, } for _, fn := range fns { var a bgp.PathAttributeInterface args, a, err = fn(args) if err != nil { return nil, err } if a != nil { attrs = append(attrs, a) } } args, nexthop, err := extractNexthop(rf, args) if err != nil { return nil, err } switch rf { case bgp.RF_IPv4_UC, bgp.RF_IPv6_UC: if len(args) < 1 { return nil, fmt.Errorf("invalid format") } ip, net, err := net.ParseCIDR(args[0]) if err != nil { return nil, err } ones, _ := net.Mask.Size() if rf == bgp.RF_IPv4_UC { if ip.To4() == nil { return nil, fmt.Errorf("invalid ipv4 prefix") } nlri = bgp.NewIPAddrPrefix(uint8(ones), ip.String()) } else { if ip.To16() == nil { return nil, fmt.Errorf("invalid ipv6 prefix") } nlri = bgp.NewIPv6AddrPrefix(uint8(ones), ip.String()) } extcomms = args[1:] case bgp.RF_IPv4_VPN, bgp.RF_IPv6_VPN: if len(args) < 5 || args[1] != "label" || args[3] != "rd" { return nil, fmt.Errorf("invalid format") } ip, net, _ := net.ParseCIDR(args[0]) ones, _ := net.Mask.Size() label := 0 if label, err = strconv.Atoi(args[2]); err != nil { return nil, fmt.Errorf("invalid format") } mpls := bgp.NewMPLSLabelStack(uint32(label)) rd, err = bgp.ParseRouteDistinguisher(args[4]) if err != nil { return nil, err } extcomms = args[5:] if rf == bgp.RF_IPv4_VPN { if ip.To4() == nil { return nil, fmt.Errorf("invalid ipv4 prefix") } nlri = bgp.NewLabeledVPNIPAddrPrefix(uint8(ones), ip.String(), *mpls, rd) } else { if ip.To16() == nil { return nil, fmt.Errorf("invalid ipv6 prefix") } nlri = bgp.NewLabeledVPNIPv6AddrPrefix(uint8(ones), ip.String(), *mpls, rd) } case bgp.RF_IPv4_MPLS, bgp.RF_IPv6_MPLS: if len(args) < 2 { return nil, fmt.Errorf("invalid format") } ip, net, _ := net.ParseCIDR(args[0]) ones, _ := net.Mask.Size() mpls, err := bgp.ParseMPLSLabelStack(args[1]) if err != nil { return nil, err } extcomms = args[2:] if rf == bgp.RF_IPv4_MPLS { if ip.To4() == nil { return nil, fmt.Errorf("invalid ipv4 prefix") } nlri = bgp.NewLabeledIPAddrPrefix(uint8(ones), ip.String(), *mpls) } else { if ip.To4() != nil { return nil, fmt.Errorf("invalid ipv6 prefix") } nlri = bgp.NewLabeledIPv6AddrPrefix(uint8(ones), ip.String(), *mpls) } case bgp.RF_EVPN: nlri, extcomms, err = ParseEvpnArgs(args) case bgp.RF_FS_IPv4_VPN, bgp.RF_FS_IPv6_VPN, bgp.RF_FS_L2_VPN: args, rd, err = extractRouteDistinguisher(args) if err != nil { return nil, err } fallthrough case bgp.RF_FS_IPv4_UC, bgp.RF_FS_IPv6_UC: nlri, extcomms, err = ParseFlowSpecArgs(rf, args, rd) case bgp.RF_OPAQUE: m := extractReserved(args, []string{"key", "value"}) if len(m["key"]) != 1 { return nil, fmt.Errorf("opaque nlri key missing") } if len(m["value"]) > 0 { nlri = bgp.NewOpaqueNLRI([]byte(m["key"][0]), []byte(m["value"][0])) } else { nlri = bgp.NewOpaqueNLRI([]byte(m["key"][0]), nil) } default: return nil, fmt.Errorf("Unsupported route family: %s", rf) } if err != nil { return nil, err } if rf == bgp.RF_IPv4_UC { attrs = append(attrs, bgp.NewPathAttributeNextHop(nexthop)) } else { mpreach := bgp.NewPathAttributeMpReachNLRI(nexthop, []bgp.AddrPrefixInterface{nlri}) attrs = append(attrs, mpreach) } if extcomms != nil && len(extcomms) > 0 { extcomms, err := ParseExtendedCommunities(strings.Join(extcomms, " ")) if err != nil { return nil, err } p := bgp.NewPathAttributeExtendedCommunities(extcomms) attrs = append(attrs, p) } sort.Sort(attrs) return table.NewPath(nil, nlri, false, attrs, time.Now(), false), nil }
func Test_createRequestFromIPRouteMessage(t *testing.T) { assert := assert.New(t) m := &zebra.Message{} h := &zebra.Header{ Len: zebra.HEADER_SIZE, Marker: zebra.HEADER_MARKER, Version: zebra.VERSION, Command: zebra.IPV4_ROUTE_ADD, } b := &zebra.IPRouteBody{ Type: zebra.ROUTE_TYPE(zebra.ROUTE_STATIC), Flags: zebra.FLAG(zebra.FLAG_SELECTED), Message: zebra.MESSAGE_NEXTHOP | zebra.MESSAGE_DISTANCE | zebra.MESSAGE_METRIC, SAFI: zebra.SAFI(zebra.SAFI_UNICAST), Prefix: net.ParseIP("192.168.100.0"), PrefixLength: uint8(24), Nexthops: []net.IP{net.ParseIP("0.0.0.0")}, Ifindexs: []uint32{1}, Distance: uint8(0), Metric: uint32(100), Api: zebra.API_TYPE(zebra.IPV4_ROUTE_ADD), } m.Header = *h m.Body = b p := createRequestFromIPRouteMessage(m) assert.NotNil(p) paths, err := cmd.ApiStruct2Path(p.Path) assert.Nil(err) assert.Equal(len(paths), 1) path := paths[0] pp := table.NewPath(nil, path.Nlri, path.IsWithdraw, path.PathAttrs, time.Now(), false) pp.SetIsFromExternal(p.Path.IsFromExternal) assert.Equal("0.0.0.0", pp.GetNexthop().String()) assert.Equal("192.168.100.0/24", pp.GetNlri().String()) assert.True(pp.IsFromExternal()) assert.False(pp.IsWithdraw) // withdraw h.Command = zebra.IPV4_ROUTE_DELETE m.Header = *h p = createRequestFromIPRouteMessage(m) assert.NotNil(p) paths, err = cmd.ApiStruct2Path(p.Path) assert.Nil(err) assert.Equal(len(paths), 1) path = paths[0] pp = table.NewPath(nil, path.Nlri, path.IsWithdraw, path.PathAttrs, time.Now(), false) pp.SetIsFromExternal(p.Path.IsFromExternal) assert.Equal("0.0.0.0", pp.GetNexthop().String()) assert.Equal("192.168.100.0/24", pp.GetNlri().String()) med, _ := pp.GetMed() assert.Equal(uint32(100), med) assert.True(pp.IsFromExternal()) assert.True(pp.IsWithdraw) // IPv6 h.Command = zebra.IPV6_ROUTE_ADD b.Prefix = net.ParseIP("2001:db8:0:f101::") b.PrefixLength = uint8(64) b.Nexthops = []net.IP{net.ParseIP("::")} m.Header = *h m.Body = b p = createRequestFromIPRouteMessage(m) assert.NotNil(p) paths, err = cmd.ApiStruct2Path(p.Path) assert.Nil(err) assert.Equal(len(paths), 1) path = paths[0] pp = table.NewPath(nil, path.Nlri, path.IsWithdraw, path.PathAttrs, time.Now(), false) pp.SetIsFromExternal(p.Path.IsFromExternal) assert.Equal("::", pp.GetNexthop().String()) assert.Equal("2001:db8:0:f101::/64", pp.GetNlri().String()) med, _ = pp.GetMed() assert.Equal(uint32(100), med) assert.True(pp.IsFromExternal()) assert.False(pp.IsWithdraw) // withdraw h.Command = zebra.IPV6_ROUTE_DELETE m.Header = *h p = createRequestFromIPRouteMessage(m) assert.NotNil(p) paths, err = cmd.ApiStruct2Path(p.Path) assert.Nil(err) assert.Equal(len(paths), 1) path = paths[0] pp = table.NewPath(nil, path.Nlri, path.IsWithdraw, path.PathAttrs, time.Now(), false) pp.SetIsFromExternal(p.Path.IsFromExternal) assert.Equal("::", pp.GetNexthop().String()) assert.Equal("2001:db8:0:f101::/64", pp.GetNlri().String()) assert.True(pp.IsFromExternal()) assert.True(pp.IsWithdraw) }
// Test adding/deleting Vlrouter routes func TestOfnetBgpVlrouteAddDelete(t *testing.T) { neighborAs := "500" peer := "50.1.1.3" routerIP := "50.1.1.2/24" as := "65002" //Add Bgp neighbor and check if it is successful for i := 0; i < NUM_VLRTR_AGENT; i++ { err := vlrtrAgents[i].AddBgp(routerIP, as, neighborAs, peer) time.Sleep(5 * time.Second) if err != nil { t.Errorf("Error adding Bgp Neighbor: %v", err) return } attrs := []bgp.PathAttributeInterface{ bgp.NewPathAttributeOrigin(1), bgp.NewPathAttributeNextHop("50.1.1.3"), bgp.NewPathAttributeAsPath([]bgp.AsPathParamInterface{bgp.NewAs4PathParam(bgp.BGP_ASPATH_ATTR_TYPE_SEQ, []uint32{65002})}), } path := table.NewPath(nil, bgp.NewIPAddrPrefix(32, "20.20.20.20"), false, attrs, time.Now(), false) vlrtrAgents[i].protopath.ModifyProtoRib(path) log.Infof("Adding path to the Bgp Rib") time.Sleep(2 * time.Second) // verify flow entry exists brName := "vlrtrBridge" + fmt.Sprintf("%d", i) 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 vlrtrAgents[i].protopath.ModifyProtoRib(path) log.Infof("Withdrawing route from BGP rib") // verify flow entry exists brName = "vlrtrBridge" + fmt.Sprintf("%d", i) 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) } }