diff options
Diffstat (limited to 'server')
-rw-r--r-- | server/grpc_server.go | 93 | ||||
-rw-r--r-- | server/server.go | 413 |
2 files changed, 255 insertions, 251 deletions
diff --git a/server/grpc_server.go b/server/grpc_server.go index fef1a21a..d67d85cc 100644 --- a/server/grpc_server.go +++ b/server/grpc_server.go @@ -256,38 +256,58 @@ func toPathApi(id string, path *table.Path) *api.Path { } func (s *Server) GetRib(ctx context.Context, arg *api.GetRibRequest) (*api.GetRibResponse, error) { - var reqType int + f := func() []*LookupPrefix { + l := make([]*LookupPrefix, 0, len(arg.Table.Destinations)) + for _, p := range arg.Table.Destinations { + l = append(l, &LookupPrefix{ + Prefix: p.Prefix, + LookupOption: func() LookupOption { + if p.LongerPrefixes { + return LOOKUP_LONGER + } else if p.ShorterPrefixes { + return LOOKUP_SHORTER + } + return LOOKUP_EXACT + }(), + }) + } + return l + } + + var in bool + var err error + var id string + var r map[string][]*table.Path + + family := bgp.RouteFamily(arg.Table.Family) switch arg.Table.Type { - case api.Resource_LOCAL: - reqType = REQ_LOCAL_RIB - case api.Resource_GLOBAL: - reqType = REQ_GLOBAL_RIB + case api.Resource_LOCAL, api.Resource_GLOBAL: + id, r, err = s.bgpServer.GetRib(arg.Table.Name, family, f()) case api.Resource_ADJ_IN: - reqType = REQ_ADJ_RIB_IN + in = true + fallthrough case api.Resource_ADJ_OUT: - reqType = REQ_ADJ_RIB_OUT + id, r, err = s.bgpServer.GetAdjRib(arg.Table.Name, family, in, f()) case api.Resource_VRF: - reqType = REQ_VRF + id, r, err = s.bgpServer.GetVrfRib(arg.Table.Name, family, []*LookupPrefix{}) default: return nil, fmt.Errorf("unsupported resource type: %v", arg.Table.Type) } - d, err := s.get(reqType, arg) - if err != nil { - return nil, err - } - switch reqType { - case REQ_LOCAL_RIB, REQ_GLOBAL_RIB: - dsts := make([]*api.Destination, 0, len(d.(map[string][]*table.Path))) - for k, v := range d.(map[string][]*table.Path) { + dsts := make([]*api.Destination, 0, len(r)) + if err == nil { + for k, v := range r { dsts = append(dsts, &api.Destination{ Prefix: k, Paths: func(paths []*table.Path) []*api.Path { l := make([]*api.Path, 0, len(v)) for i, p := range paths { - pp := toPathApi("", p) - if i == 0 { - pp.Best = true + pp := toPathApi(id, p) + switch arg.Table.Type { + case api.Resource_LOCAL, api.Resource_GLOBAL: + if i == 0 { + pp.Best = true + } } l = append(l, pp) } @@ -295,37 +315,12 @@ func (s *Server) GetRib(ctx context.Context, arg *api.GetRibRequest) (*api.GetRi }(v), }) } - d := &api.Table{ - Type: arg.Table.Type, - Family: arg.Table.Family, - Destinations: dsts, - } - return &api.GetRibResponse{Table: d}, nil - case REQ_ADJ_RIB_IN, REQ_ADJ_RIB_OUT, REQ_VRF: - dsts := make([]*api.Destination, 0, len(d.([]*table.Path))) - var prefix string - var dst *api.Destination - for _, path := range d.([]*table.Path) { - if path.GetNlri().String() != prefix { - prefix = path.GetNlri().String() - dst = &api.Destination{ - Prefix: prefix, - Paths: []*api.Path{toPathApi(arg.Table.Name, path)}, - } - } else { - dst.Paths = append(dst.Paths, toPathApi(arg.Table.Name, path)) - } - dsts = append(dsts, dst) - } - return &api.GetRibResponse{ - Table: &api.Table{ - Type: arg.Table.Type, - Family: arg.Table.Family, - Destinations: dsts, - }, - }, nil } - return d.(*api.GetRibResponse), nil + return &api.GetRibResponse{Table: &api.Table{ + Type: arg.Table.Type, + Family: arg.Table.Family, + Destinations: dsts}, + }, err } func (s *Server) MonitorRib(arg *api.Table, stream api.GobgpApi_MonitorRibServer) error { diff --git a/server/server.go b/server/server.go index e7d15d94..bad4c760 100644 --- a/server/server.go +++ b/server/server.go @@ -1162,55 +1162,6 @@ func (s *BgpServer) DeletePath(uuid []byte, f bgp.RouteFamily, vrfId string, pat return err } -func (server *BgpServer) handleVrfRequest(req *GrpcRequest) []*table.Path { - var msgs []*table.Path - result := &GrpcResponse{} - - switch req.RequestType { - case REQ_VRF: - arg := req.Data.(*api.GetRibRequest) - name := arg.Table.Name - rib := server.globalRib - vrfs := rib.Vrfs - if _, ok := vrfs[name]; !ok { - result.ResponseErr = fmt.Errorf("vrf %s not found", name) - break - } - var rf bgp.RouteFamily - switch bgp.RouteFamily(arg.Table.Family) { - case bgp.RF_IPv4_UC: - rf = bgp.RF_IPv4_VPN - case bgp.RF_IPv6_UC: - rf = bgp.RF_IPv6_VPN - case bgp.RF_EVPN: - rf = bgp.RF_EVPN - default: - result.ResponseErr = fmt.Errorf("unsupported route family: %s", bgp.RouteFamily(arg.Table.Family)) - break - } - l := rib.GetPathList(table.GLOBAL_RIB_NAME, []bgp.RouteFamily{rf}) - paths := make([]*table.Path, 0, len(l)) - for _, path := range l { - ok := table.CanImportToVrf(vrfs[name], path) - if !ok { - continue - } - paths = append(paths, path) - } - req.ResponseCh <- &GrpcResponse{ - Data: paths, - } - goto END - default: - result.ResponseErr = fmt.Errorf("unknown request type: %d", req.RequestType) - } - - req.ResponseCh <- result -END: - close(req.ResponseCh) - return msgs -} - func (s *BgpServer) Start(c *config.Global) (err error) { ch := make(chan struct{}) defer func() { <-ch }() @@ -1355,154 +1306,6 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) { var err error switch grpcReq.RequestType { - case REQ_GLOBAL_RIB, REQ_LOCAL_RIB: - arg := grpcReq.Data.(*api.GetRibRequest) - rib := server.globalRib - id := table.GLOBAL_RIB_NAME - if grpcReq.RequestType == REQ_LOCAL_RIB { - peer, ok := server.neighborMap[arg.Table.Name] - if !ok { - err = fmt.Errorf("Neighbor that has %v doesn't exist.", arg.Table.Name) - goto ERROR - } - if !peer.isRouteServerClient() { - err = fmt.Errorf("Neighbor %v doesn't have local rib", arg.Table.Name) - goto ERROR - } - id = peer.ID() - } - af := bgp.RouteFamily(arg.Table.Family) - if _, ok := rib.Tables[af]; !ok { - err = fmt.Errorf("address family: %s not supported", af) - goto ERROR - } - - clone := func(pathList []*table.Path) []*table.Path { - l := make([]*table.Path, 0, len(pathList)) - for _, p := range pathList { - l = append(l, p.Clone(false)) - } - return l - } - - dsts := make(map[string][]*table.Path) - if (af == bgp.RF_IPv4_UC || af == bgp.RF_IPv6_UC) && len(arg.Table.Destinations) > 0 { - f := func(id, cidr string) (bool, error) { - _, prefix, err := net.ParseCIDR(cidr) - if err != nil { - return false, err - } - if dst := rib.Tables[af].GetDestination(prefix.String()); dst != nil { - if paths := dst.GetKnownPathList(id); len(paths) > 0 { - dsts[dst.GetNlri().String()] = clone(paths) - } - return true, nil - } else { - return false, nil - } - } - for _, dst := range arg.Table.Destinations { - key := dst.Prefix - if dst.LongerPrefixes { - _, prefix, _ := net.ParseCIDR(key) - for _, dst := range rib.Tables[af].GetLongerPrefixDestinations(prefix.String()) { - if paths := dst.GetKnownPathList(id); len(paths) > 0 { - dsts[dst.GetNlri().String()] = clone(paths) - } - } - } else if dst.ShorterPrefixes { - _, prefix, _ := net.ParseCIDR(key) - ones, bits := prefix.Mask.Size() - for i := ones; i > 0; i-- { - prefix.Mask = net.CIDRMask(i, bits) - f(id, prefix.String()) - } - } else if _, err := f(id, key); err != nil { - if host := net.ParseIP(key); host != nil { - masklen := 32 - if af == bgp.RF_IPv6_UC { - masklen = 128 - } - for i := masklen; i > 0; i-- { - if y, _ := f(id, fmt.Sprintf("%s/%d", key, i)); y { - break - } - } - } - } - } - } else { - for _, dst := range rib.Tables[af].GetSortedDestinations() { - if paths := dst.GetKnownPathList(id); len(paths) > 0 { - dsts[dst.GetNlri().String()] = clone(paths) - } - } - } - grpcReq.ResponseCh <- &GrpcResponse{ - Data: dsts, - } - close(grpcReq.ResponseCh) - case REQ_ADJ_RIB_IN, REQ_ADJ_RIB_OUT: - arg := grpcReq.Data.(*api.GetRibRequest) - - peer, ok := server.neighborMap[arg.Table.Name] - if !ok { - err = fmt.Errorf("Neighbor that has %v doesn't exist.", arg.Table.Name) - goto ERROR - } - // FIXME: temporary hack - arg.Table.Name = peer.TableID() - - rf := bgp.RouteFamily(arg.Table.Family) - var paths []*table.Path - if grpcReq.RequestType == REQ_ADJ_RIB_IN { - paths = peer.adjRibIn.PathList([]bgp.RouteFamily{rf}, false) - log.Debugf("RouteFamily=%v adj-rib-in found : %d", rf.String(), len(paths)) - } else { - paths = peer.adjRibOut.PathList([]bgp.RouteFamily{rf}, false) - log.Debugf("RouteFamily=%v adj-rib-out found : %d", rf.String(), len(paths)) - } - - for i, p := range paths { - id := peer.TableID() - paths[i] = p.Clone(false) - paths[i].Filter(id, p.Filtered(id)) - } - switch rf { - case bgp.RF_IPv4_UC, bgp.RF_IPv6_UC: - r := radix.New() - for _, p := range paths { - key := p.GetNlri().String() - found := true - for _, dst := range arg.Table.Destinations { - found = false - if dst.Prefix == key { - found = true - break - } - } - - if found { - b, _ := r.Get(table.CidrToRadixkey(key)) - if b == nil { - r.Insert(table.CidrToRadixkey(key), []*table.Path{p}) - } else { - l := b.([]*table.Path) - l = append(l, p) - } - } - } - l := make([]*table.Path, 0, len(paths)) - r.Walk(func(s string, v interface{}) bool { - l = append(l, v.([]*table.Path)...) - return false - }) - paths = l - } - grpcReq.ResponseCh <- &GrpcResponse{ - Data: paths, - } - close(grpcReq.ResponseCh) case REQ_NEIGHBOR_SOFT_RESET, REQ_NEIGHBOR_SOFT_RESET_IN: peers, err := reqToPeers(grpcReq) if err != nil { @@ -1621,11 +1424,6 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) { rsp := server.roaManager.handleGRPC(grpcReq) grpcReq.ResponseCh <- rsp close(grpcReq.ResponseCh) - case REQ_VRF: - pathList := server.handleVrfRequest(grpcReq) - if len(pathList) > 0 { - server.propagateUpdate(nil, pathList) - } default: err = fmt.Errorf("Unknown request type: %v", grpcReq.RequestType) goto ERROR @@ -1639,6 +1437,217 @@ ERROR: return } +type LookupOption uint8 + +const ( + LOOKUP_EXACT LookupOption = iota + LOOKUP_LONGER + LOOKUP_SHORTER +) + +type LookupPrefix struct { + Prefix string + LookupOption +} + +func (s *BgpServer) GetRib(addr string, family bgp.RouteFamily, prefixes []*LookupPrefix) (id string, dsts map[string][]*table.Path, err error) { + ch := make(chan struct{}) + defer func() { <-ch }() + + s.mgmtCh <- func() { + defer close(ch) + + rib := s.globalRib + id = table.GLOBAL_RIB_NAME + if len(addr) > 0 { + peer, ok := s.neighborMap[addr] + if !ok { + err = fmt.Errorf("Neighbor that has %v doesn't exist.", addr) + return + } + if !peer.isRouteServerClient() { + err = fmt.Errorf("Neighbor %v doesn't have local rib", addr) + return + } + id = peer.ID() + } + af := bgp.RouteFamily(family) + if _, ok := rib.Tables[af]; !ok { + err = fmt.Errorf("address family: %s not supported", af) + return + } + + dsts = make(map[string][]*table.Path) + if (af == bgp.RF_IPv4_UC || af == bgp.RF_IPv6_UC) && len(prefixes) > 0 { + f := func(id, cidr string) (bool, error) { + _, prefix, err := net.ParseCIDR(cidr) + if err != nil { + return false, err + } + if dst := rib.Tables[af].GetDestination(prefix.String()); dst != nil { + if paths := dst.GetKnownPathList(id); len(paths) > 0 { + dsts[dst.GetNlri().String()] = clonePathList(paths) + } + return true, nil + } else { + return false, nil + } + } + for _, p := range prefixes { + key := p.Prefix + switch p.LookupOption { + case LOOKUP_LONGER: + _, prefix, _ := net.ParseCIDR(key) + for _, dst := range rib.Tables[af].GetLongerPrefixDestinations(prefix.String()) { + if paths := dst.GetKnownPathList(id); len(paths) > 0 { + dsts[dst.GetNlri().String()] = clonePathList(paths) + } + } + + case LOOKUP_SHORTER: + _, prefix, _ := net.ParseCIDR(key) + ones, bits := prefix.Mask.Size() + for i := ones; i > 0; i-- { + prefix.Mask = net.CIDRMask(i, bits) + f(id, prefix.String()) + } + default: + if _, err := f(id, key); err != nil { + if host := net.ParseIP(key); host != nil { + masklen := 32 + if af == bgp.RF_IPv6_UC { + masklen = 128 + } + for i := masklen; i > 0; i-- { + if y, _ := f(id, fmt.Sprintf("%s/%d", key, i)); y { + break + } + } + } + } + } + } + } else { + for _, dst := range rib.Tables[af].GetSortedDestinations() { + if paths := dst.GetKnownPathList(id); len(paths) > 0 { + dsts[dst.GetNlri().String()] = clonePathList(paths) + } + } + } + } + return id, dsts, err +} + +func (s *BgpServer) GetVrfRib(name string, family bgp.RouteFamily, prefixes []*LookupPrefix) (id string, dsts map[string][]*table.Path, err error) { + ch := make(chan struct{}) + defer func() { <-ch }() + + s.mgmtCh <- func() { + defer close(ch) + + rib := s.globalRib + vrfs := rib.Vrfs + if _, ok := vrfs[name]; !ok { + err = fmt.Errorf("vrf %s not found", name) + return + } + var rf bgp.RouteFamily + switch family { + case bgp.RF_IPv4_UC: + rf = bgp.RF_IPv4_VPN + case bgp.RF_IPv6_UC: + rf = bgp.RF_IPv6_VPN + case bgp.RF_EVPN: + rf = bgp.RF_EVPN + default: + err = fmt.Errorf("unsupported route family: %s", family) + return + } + + dsts = make(map[string][]*table.Path) + for _, path := range rib.GetPathList(table.GLOBAL_RIB_NAME, []bgp.RouteFamily{rf}) { + if ok := table.CanImportToVrf(vrfs[name], path); ok { + if d, y := dsts[path.GetNlri().String()]; y { + d = append(d, path.Clone(false)) + } else { + dsts[path.GetNlri().String()] = []*table.Path{path.Clone(false)} + } + } + } + } + return table.GLOBAL_RIB_NAME, dsts, err +} + +func (s *BgpServer) GetAdjRib(addr string, family bgp.RouteFamily, in bool, prefixes []*LookupPrefix) (id string, dsts map[string][]*table.Path, err error) { + ch := make(chan struct{}) + defer func() { <-ch }() + + s.mgmtCh <- func() { + defer close(ch) + + peer, ok := s.neighborMap[addr] + if !ok { + err = fmt.Errorf("Neighbor that has %v doesn't exist.", addr) + return + } + id = peer.TableID() + + var paths []*table.Path + if in { + paths = peer.adjRibIn.PathList([]bgp.RouteFamily{family}, false) + log.Debugf("RouteFamily=%v adj-rib-in found : %d", family.String(), len(paths)) + } else { + paths = peer.adjRibOut.PathList([]bgp.RouteFamily{family}, false) + log.Debugf("RouteFamily=%v adj-rib-out found : %d", family.String(), len(paths)) + } + + for i, p := range paths { + paths[i] = p.Clone(false) + paths[i].Filter(id, p.Filtered(id)) + } + + dsts = make(map[string][]*table.Path) + switch family { + case bgp.RF_IPv4_UC, bgp.RF_IPv6_UC: + r := radix.New() + for _, p := range paths { + key := p.GetNlri().String() + found := true + for _, p := range prefixes { + found = false + if p.Prefix == key { + found = true + break + } + } + + if found { + b, _ := r.Get(table.CidrToRadixkey(key)) + if b == nil { + r.Insert(table.CidrToRadixkey(key), []*table.Path{p}) + } else { + l := b.([]*table.Path) + l = append(l, p) + } + } + } + r.Walk(func(s string, v interface{}) bool { + dsts[s] = v.([]*table.Path) + return false + }) + default: + for _, p := range paths { + if d, y := dsts[p.GetNlri().String()]; y { + d = append(d, p) + } else { + dsts[p.GetNlri().String()] = []*table.Path{p} + } + } + } + } + return id, dsts, err +} + func (s *BgpServer) GetServer() (c *config.Global) { ch := make(chan struct{}) defer func() { <-ch }() |