diff options
author | ISHIDA Wataru <ishida.wataru@lab.ntt.co.jp> | 2015-07-31 18:51:05 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2015-08-08 20:56:46 +0900 |
commit | bf9e135ba85cad641c3812abace9221cbf5a2615 (patch) | |
tree | 435728bd72e93ddfea7a3c02d78cfb1a9c65f16f /server | |
parent | ecd079e318e1c5d5aa2d2f1348a4ad1a37daec37 (diff) |
server: support vrf
to add/delete vrf
$ gobgp vrf [add|del] <vrf-name> rd <rd> rt [import|export|both] <rt>...
show vrf
$ gobgp vrf
to add/delete a path to a specific vrf
$ gobgp vrf <vrf-name> rib [add|del] <prefix> -a <address-family>
show paths contained in a specific vrf
$ gobgp vrf <vrf-name> rib -a <address-family>
Signed-off-by: ISHIDA Wataru <ishida.wataru@lab.ntt.co.jp>
Diffstat (limited to 'server')
-rw-r--r-- | server/grpc_server.go | 63 | ||||
-rw-r--r-- | server/server.go | 209 |
2 files changed, 237 insertions, 35 deletions
diff --git a/server/grpc_server.go b/server/grpc_server.go index 17fb6c87..041f0659 100644 --- a/server/grpc_server.go +++ b/server/grpc_server.go @@ -48,8 +48,6 @@ const ( REQ_NEIGHBOR_POLICY_DEL_EXPORT REQ_NEIGHBOR_POLICY_DEL_DISTRIBUTE REQ_GLOBAL_RIB - REQ_GLOBAL_ADD - REQ_GLOBAL_DELETE REQ_POLICY_PREFIX REQ_POLICY_PREFIXES REQ_POLICY_PREFIX_ADD @@ -85,6 +83,10 @@ const ( REQ_MRT_GLOBAL_RIB REQ_MRT_LOCAL_RIB REQ_RPKI + REQ_VRF + REQ_VRFS + REQ_VRF_MOD + REQ_MOD_PATH ) const GRPC_PORT = 8080 @@ -329,16 +331,11 @@ func (s *Server) ModPath(stream api.Grpc_ModPathServer) error { return err } - if arg.Resource != api.Resource_GLOBAL { + if arg.Resource != api.Resource_GLOBAL && arg.Resource != api.Resource_VRF { return fmt.Errorf("unsupported resource: %s", arg.Resource) } - reqType := REQ_GLOBAL_ADD - if arg.IsWithdraw { - reqType = REQ_GLOBAL_DELETE - } - - req := NewGrpcRequest(reqType, "", bgp.RouteFamily(0), arg) + req := NewGrpcRequest(REQ_MOD_PATH, arg.Name, bgp.RouteFamily(0), arg) s.bgpServerCh <- req res := <-req.ResponseCh @@ -641,6 +638,54 @@ func (s *Server) GetRPKI(arg *api.Arguments, stream api.Grpc_GetRPKIServer) erro return nil } +func (s *Server) GetVrf(arg *api.Arguments, stream api.Grpc_GetVrfServer) error { + rf, err := convertAf2Rf(arg.Af) + if err != nil { + return err + } + req := NewGrpcRequest(REQ_VRF, "", rf, arg) + s.bgpServerCh <- req + + for res := range req.ResponseCh { + if err := res.Err(); err != nil { + log.Debug(err.Error()) + return err + } + if err := stream.Send(res.Data.(*api.Path)); err != nil { + return err + } + } + return nil +} + +func (s *Server) GetVrfs(arg *api.Arguments, stream api.Grpc_GetVrfsServer) error { + req := NewGrpcRequest(REQ_VRFS, "", bgp.RouteFamily(0), nil) + s.bgpServerCh <- req + + for res := range req.ResponseCh { + if err := res.Err(); err != nil { + log.Debug(err.Error()) + return err + } + if err := stream.Send(res.Data.(*api.Vrf)); err != nil { + return err + } + } + return nil +} + +func (s *Server) ModVrf(ctx context.Context, arg *api.ModVrfArguments) (*api.Error, error) { + none := &api.Error{} + req := NewGrpcRequest(REQ_VRF_MOD, "", bgp.RouteFamily(0), arg) + s.bgpServerCh <- req + + res := <-req.ResponseCh + if err := res.Err(); err != nil { + return none, err + } + return none, nil +} + type GrpcRequest struct { RequestType int RemoteAddr string diff --git a/server/server.go b/server/server.go index 4cabc7b9..56ef8c68 100644 --- a/server/server.go +++ b/server/server.go @@ -831,33 +831,31 @@ func getMacMobilityExtendedCommunity(etag uint32, mac net.HardwareAddr, evpnPath return nil } -func (server *BgpServer) handleGlobalRibRequest(grpcReq *GrpcRequest, peerInfo *table.PeerInfo) []*table.Path { - var isWithdraw bool +func (server *BgpServer) handleModPathRequest(grpcReq *GrpcRequest, peerInfo *table.PeerInfo) []*table.Path { var nlri bgp.AddrPrefixInterface result := &GrpcResponse{} pattr := make([]bgp.PathAttributeInterface, 0) extcomms := make([]bgp.ExtendedCommunityInterface, 0) + var nexthop string + var rf bgp.RouteFamily - args, ok := grpcReq.Data.(*api.ModPathArguments) + arg, ok := grpcReq.Data.(*api.ModPathArguments) if !ok { result.ResponseErr = fmt.Errorf("type assertion failed") goto ERR } - if grpcReq.RequestType == REQ_GLOBAL_DELETE { - isWithdraw = true - } - if len(args.RawNlri) > 0 { + if len(arg.RawNlri) > 0 { nlri = &bgp.NLRInfo{} - err := nlri.DecodeFromBytes(args.RawNlri) + err := nlri.DecodeFromBytes(arg.RawNlri) if err != nil { result.ResponseErr = err goto ERR } } - for _, attr := range args.RawPattrs { + for _, attr := range arg.RawPattrs { p, err := bgp.GetPathAttribute(attr) if err != nil { result.ResponseErr = err @@ -871,30 +869,70 @@ func (server *BgpServer) handleGlobalRibRequest(grpcReq *GrpcRequest, peerInfo * } 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: - value := p.(*bgp.PathAttributeMpReachNLRI).Value - if len(value) != 1 { + mpreach := p.(*bgp.PathAttributeMpReachNLRI) + if len(mpreach.Value) != 1 { result.ResponseErr = fmt.Errorf("include only one route in mp_reach_nlri") goto ERR } - nlri = p.(*bgp.PathAttributeMpReachNLRI).Value[0] - fallthrough + nlri = mpreach.Value[0] + nexthop = mpreach.Nexthop.String() default: pattr = append(pattr, p) } } - if nlri == nil { - result.ResponseErr = fmt.Errorf("no nlri included") + if nlri == nil || nexthop == "" { + result.ResponseErr = fmt.Errorf("not found nlri or nexthop") goto ERR } - if bgp.AfiSafiToRouteFamily(nlri.AFI(), nlri.SAFI()) == bgp.RF_EVPN { + rf = bgp.AfiSafiToRouteFamily(nlri.AFI(), nlri.SAFI()) + + if arg.Resource == api.Resource_VRF { + vrfs := server.localRibMap[GLOBAL_RIB_NAME].rib.Vrfs + if _, ok := vrfs[arg.Name]; !ok { + result.ResponseErr = fmt.Errorf("vrf %s not found", arg.Name) + goto ERR + } + vrf := vrfs[arg.Name] + + switch rf { + case bgp.RF_IPv4_UC: + n := nlri.(*bgp.NLRInfo) + nlri = bgp.NewLabeledVPNIPAddrPrefix(n.Length, n.Prefix.String(), *bgp.NewMPLSLabelStack(), vrf.Rd) + case bgp.RF_IPv6_UC: + n := nlri.(*bgp.IPv6AddrPrefix) + nlri = bgp.NewLabeledVPNIPv6AddrPrefix(n.Length, n.Prefix.String(), *bgp.NewMPLSLabelStack(), vrf.Rd) + case bgp.RF_EVPN: + n := nlri.(*bgp.EVPNNLRI) + switch n.RouteType { + case bgp.EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT: + n.RouteTypeData.(*bgp.EVPNMacIPAdvertisementRoute).RD = vrf.Rd + case bgp.EVPN_INCLUSIVE_MULTICAST_ETHERNET_TAG: + n.RouteTypeData.(*bgp.EVPNMulticastEthernetTagRoute).RD = vrf.Rd + } + default: + result.ResponseErr = fmt.Errorf("unsupported route family for vrf: %s", rf) + goto ERR + } + extcomms = append(extcomms, vrf.ExportRt...) + } + + if arg.Resource != api.Resource_VRF && rf == bgp.RF_IPv4_UC { + pattr = append(pattr, bgp.NewPathAttributeNextHop(nexthop)) + } else { + pattr = append(pattr, bgp.NewPathAttributeMpReachNLRI(nexthop, []bgp.AddrPrefixInterface{nlri})) + } + + if rf == bgp.RF_EVPN { evpnNlri := nlri.(*bgp.EVPNNLRI) if evpnNlri.RouteType == bgp.EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT { macIpAdv := evpnNlri.RouteTypeData.(*bgp.EVPNMacIPAdvertisementRoute) @@ -911,7 +949,7 @@ func (server *BgpServer) handleGlobalRibRequest(grpcReq *GrpcRequest, peerInfo * pattr = append(pattr, bgp.NewPathAttributeExtendedCommunities(extcomms)) } - return []*table.Path{table.NewPath(peerInfo, nlri, isWithdraw, pattr, false, time.Now(), args.NoImplicitWithdraw)} + return []*table.Path{table.NewPath(peerInfo, nlri, arg.IsWithdraw, pattr, false, time.Now(), arg.NoImplicitWithdraw)} ERR: grpcReq.ResponseCh <- result close(grpcReq.ResponseCh) @@ -919,8 +957,123 @@ ERR: } +func (server *BgpServer) handleVrfMod(arg *api.ModVrfArguments) error { + vrfs := server.localRibMap[GLOBAL_RIB_NAME].rib.Vrfs + switch arg.Operation { + case api.Operation_ADD: + if _, ok := vrfs[arg.Vrf.Name]; ok { + return fmt.Errorf("vrf %s already exists", arg.Vrf.Name) + } + rd := bgp.GetRouteDistinguisher(arg.Vrf.Rd) + f := func(bufs [][]byte) ([]bgp.ExtendedCommunityInterface, error) { + ret := make([]bgp.ExtendedCommunityInterface, 0, len(bufs)) + for _, rt := range bufs { + r, err := bgp.ParseExtended(rt) + if err != nil { + return nil, err + } + ret = append(ret, r) + } + return ret, nil + } + importRt, err := f(arg.Vrf.ImportRt) + if err != nil { + return err + } + exportRt, err := f(arg.Vrf.ImportRt) + if err != nil { + return err + } + log.WithFields(log.Fields{ + "Topic": "Vrf", + "Key": arg.Vrf.Name, + "Rd": rd, + "ImportRt": importRt, + "ExportRt": exportRt, + }).Debugf("add vrf") + vrfs[arg.Vrf.Name] = &table.Vrf{ + Name: arg.Vrf.Name, + Rd: rd, + ImportRt: importRt, + ExportRt: exportRt, + } + case api.Operation_DEL: + if _, ok := vrfs[arg.Vrf.Name]; !ok { + return fmt.Errorf("vrf %s not found", arg.Vrf.Name) + } + vrf := vrfs[arg.Vrf.Name] + log.WithFields(log.Fields{ + "Topic": "Vrf", + "Key": vrf.Name, + "Rd": vrf.Rd, + "ImportRt": vrf.ImportRt, + "ExportRt": vrf.ExportRt, + }).Debugf("delete vrf") + delete(vrfs, arg.Vrf.Name) + default: + return fmt.Errorf("unknown operation:", arg.Operation) + } + return nil +} + +func (server *BgpServer) handleVrfRequest(req *GrpcRequest) []*table.Path { + var msgs []*table.Path + result := &GrpcResponse{} + + switch req.RequestType { + case REQ_VRF: + arg := req.Data.(*api.Arguments) + rib := server.localRibMap[GLOBAL_RIB_NAME].rib + vrfs := rib.Vrfs + if _, ok := vrfs[arg.Name]; !ok { + result.ResponseErr = fmt.Errorf("vrf %s not found", arg.Name) + break + } + var rf bgp.RouteFamily + switch req.RouteFamily { + 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", req.RouteFamily) + break + } + for _, path := range rib.GetPathList(rf) { + ok := policy.CanImportToVrf(vrfs[arg.Name], path) + if !ok { + continue + } + req.ResponseCh <- &GrpcResponse{ + Data: path.ToApiStruct(), + } + } + goto END + case REQ_VRFS: + vrfs := server.localRibMap[GLOBAL_RIB_NAME].rib.Vrfs + for _, vrf := range vrfs { + req.ResponseCh <- &GrpcResponse{ + Data: vrf.ToApiStruct(), + } + } + goto END + case REQ_VRF_MOD: + arg := req.Data.(*api.ModVrfArguments) + result.ResponseErr = server.handleVrfMod(arg) + default: + result.ResponseErr = fmt.Errorf("unknown request type:", req.RequestType) + } + + req.ResponseCh <- result +END: + close(req.ResponseCh) + return msgs +} + func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg { - msgs := make([]*SenderMsg, 0) + var msgs []*SenderMsg switch grpcReq.RequestType { case REQ_GLOBAL_RIB: @@ -933,14 +1086,14 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg { } close(grpcReq.ResponseCh) - case REQ_GLOBAL_ADD, REQ_GLOBAL_DELETE: + case REQ_MOD_PATH: pi := &table.PeerInfo{ AS: server.bgpConfig.Global.GlobalConfig.As, LocalID: server.bgpConfig.Global.GlobalConfig.RouterId, } - pathList := server.handleGlobalRibRequest(grpcReq, pi) + pathList := server.handleModPathRequest(grpcReq, pi) if len(pathList) > 0 { - msgs = append(msgs, server.propagateUpdate("", false, pathList)...) + msgs = server.propagateUpdate("", false, pathList) grpcReq.ResponseCh <- &GrpcResponse{} close(grpcReq.ResponseCh) } @@ -1011,7 +1164,7 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg { break } m := bgp.NewBGPNotificationMessage(bgp.BGP_ERROR_CEASE, bgp.BGP_ERROR_SUB_ADMINISTRATIVE_SHUTDOWN, nil) - msgs = append(msgs, newSenderMsg(peer, []*bgp.BGPMessage{m})) + msgs = []*SenderMsg{newSenderMsg(peer, []*bgp.BGPMessage{m})} grpcReq.ResponseCh <- &GrpcResponse{} close(grpcReq.ResponseCh) @@ -1022,7 +1175,7 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg { } peer.fsm.idleHoldTime = peer.conf.Timers.TimersConfig.IdleHoldTimeAfterReset m := bgp.NewBGPNotificationMessage(bgp.BGP_ERROR_CEASE, bgp.BGP_ERROR_SUB_ADMINISTRATIVE_RESET, nil) - msgs = append(msgs, newSenderMsg(peer, []*bgp.BGPMessage{m})) + msgs = []*SenderMsg{newSenderMsg(peer, []*bgp.BGPMessage{m})} grpcReq.ResponseCh <- &GrpcResponse{} close(grpcReq.ResponseCh) @@ -1032,8 +1185,7 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg { break } pathList := peer.adjRib.GetInPathList(grpcReq.RouteFamily) - msgs = append(msgs, server.propagateUpdate(peer.conf.NeighborConfig.NeighborAddress.String(), - peer.isRouteServerClient(), pathList)...) + msgs = server.propagateUpdate(peer.conf.NeighborConfig.NeighborAddress.String(), peer.isRouteServerClient(), pathList) if grpcReq.RequestType == REQ_NEIGHBOR_SOFT_RESET_IN { grpcReq.ResponseCh <- &GrpcResponse{} @@ -1048,7 +1200,7 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg { } pathList := peer.adjRib.GetOutPathList(grpcReq.RouteFamily) msgList := table.CreateUpdateMsgFromPaths(pathList) - msgs = append(msgs, newSenderMsg(peer, msgList)) + msgs = []*SenderMsg{newSenderMsg(peer, msgList)} grpcReq.ResponseCh <- &GrpcResponse{} close(grpcReq.ResponseCh) @@ -1239,6 +1391,11 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg { server.handleMrt(grpcReq) case REQ_RPKI: server.roaClient.handleGRPC(grpcReq) + case REQ_VRF, REQ_VRFS, REQ_VRF_MOD: + pathList := server.handleVrfRequest(grpcReq) + if len(pathList) > 0 { + msgs = server.propagateUpdate("", false, pathList) + } default: errmsg := fmt.Errorf("Unknown request type: %v", grpcReq.RequestType) result := &GrpcResponse{ |