package gobgp import ( "context" "fmt" "io" "log" "time" gobgpapi "github.com/osrg/gobgp/api" "github.com/osrg/gobgp/pkg/packet/bgp" "github.com/alice-lg/alice-lg/pkg/api" "github.com/alice-lg/alice-lg/pkg/sources/gobgp/apiutil" ) var families []gobgpapi.Family = []gobgpapi.Family{gobgpapi.Family{ Afi: gobgpapi.Family_AFI_IP, Safi: gobgpapi.Family_SAFI_UNICAST, }, gobgpapi.Family{ Afi: gobgpapi.Family_AFI_IP6, Safi: gobgpapi.Family_SAFI_UNICAST, }, } // NewRoutesResponse creates a new routes response func NewRoutesResponse() api.RoutesResponse { routes := api.RoutesResponse{} routes.Imported = make(api.Routes, 0) routes.Filtered = make(api.Routes, 0) routes.NotExported = make(api.Routes, 0) return routes } func (gobgp *GoBGP) lookupNeighbor(neighborID string) (*gobgpapi.Peer, error) { peers, err := gobgp.GetNeighbors() if err != nil { return nil, err } for _, peer := range peers { peerID := PeerHash(peer) if neighborID == "" || peerID == neighborID { return peer, nil } } return nil, fmt.Errorf("could not lookup neighbor") } // GetNeighbors retrievs all neighbors and returns // a list of peers. func (gobgp *GoBGP) GetNeighbors() ([]*gobgpapi.Peer, error) { ctx, cancel := context.WithTimeout( context.Background(), time.Second*time.Duration(gobgp.config.ProcessingTimeout)) defer cancel() peerStream, err := gobgp.client.ListPeer( ctx, &gobgpapi.ListPeerRequest{EnableAdvertised: true}) if err != nil { return nil, err } peers := make([]*gobgpapi.Peer, 0) for { peer, err := peerStream.Recv() if err == io.EOF { break } peers = append(peers, peer.Peer) } return peers, nil } func (gobgp *GoBGP) parsePathIntoRoute( path *gobgpapi.Path, prefix string, ) (*api.Route, error) { route := api.Route{} route.ID = fmt.Sprintf("%s_%s", path.SourceId, prefix) route.NeighborID = PeerHashWithASAndAddress(path.SourceAsn, path.NeighborIp) route.Network = prefix route.Interface = "Unknown" route.Age = time.Since(time.Unix(path.Age.GetSeconds(), int64(path.Age.GetNanos()))) route.Primary = path.Best attrs, err := apiutil.GetNativePathAttributes(path) if err != nil { return nil, err } route.BGP = &api.BGPInfo{} route.BGP.Communities = make(api.Communities, 0) route.BGP.LargeCommunities = make(api.Communities, 0) route.BGP.ExtCommunities = make(api.ExtCommunities, 0) for _, attr := range attrs { switch attr := attr.(type) { case *bgp.PathAttributeMultiExitDisc: route.BGP.Med = int(attr.Value) case *bgp.PathAttributeNextHop: route.Gateway = attr.Value.String() route.BGP.NextHop = attr.Value.String() case *bgp.PathAttributeLocalPref: route.BGP.LocalPref = int(attr.Value) case *bgp.PathAttributeOrigin: switch attr.Value { case bgp.BGP_ORIGIN_ATTR_TYPE_IGP: route.BGP.Origin = "IGP" case bgp.BGP_ORIGIN_ATTR_TYPE_EGP: route.BGP.Origin = "EGP" case bgp.BGP_ORIGIN_ATTR_TYPE_INCOMPLETE: route.BGP.Origin = "Incomplete" } case *bgp.PathAttributeAsPath: for _, aspth := range attr.Value { for _, as := range aspth.GetAS() { route.BGP.AsPath = append(route.BGP.AsPath, int(as)) } } case *bgp.PathAttributeCommunities: for _, community := range attr.Value { apiComm := api.Community{ int((0xffff0000 & community) >> 16), int(0xffff & community)} route.BGP.Communities = append(route.BGP.Communities, apiComm) } case *bgp.PathAttributeExtendedCommunities: for _, community := range attr.Value { if apiComm, ok := community.(*bgp.TwoOctetAsSpecificExtended); ok { route.BGP.ExtCommunities = append( route.BGP.ExtCommunities, api.ExtCommunity{ apiComm.AS, apiComm.LocalAdmin}) } } case *bgp.PathAttributeLargeCommunities: for _, community := range attr.Values { route.BGP.LargeCommunities = append( route.BGP.LargeCommunities, api.Community{ int(community.ASN), int(community.LocalData1), int(community.LocalData2)}) } } } route.Metric = (route.BGP.LocalPref + route.BGP.Med) return &route, nil } // GetRoutes retrieves all routes from a peer // for a table type. func (gobgp *GoBGP) GetRoutes( peer *gobgpapi.Peer, tableType gobgpapi.TableType, response *api.RoutesResponse, ) error { ctx, cancel := context.WithTimeout( context.Background(), time.Second*time.Duration(gobgp.config.ProcessingTimeout)) defer cancel() for _, family := range families { pathStream, err := gobgp.client.ListPath(ctx, &gobgpapi.ListPathRequest{ Name: peer.State.NeighborAddress, TableType: tableType, Family: &family, EnableFiltered: true, }) if err != nil { log.Print(err) continue } rib := make([]*gobgpapi.Destination, 0) for { _path, err := pathStream.Recv() if err == io.EOF { break } else if err != nil { log.Print(err) return err } rib = append(rib, _path.Destination) } for _, destination := range rib { for _, path := range destination.Paths { route, err := gobgp.parsePathIntoRoute(path, destination.Prefix) if err != nil { log.Println(err) continue } if path.Filtered { response.Filtered = append(response.Filtered, route) } else { response.Imported = append(response.Imported, route) } } } } return nil }