Files
wenovusandFUJITA Tomonori 7ef2f0bb82 Add CommunityCount BGP Policy Condition
This is intended to have the same behaviour as [these OpenConfig paths](https://openconfig.net/projects/models/schemadocs/yangdoc/openconfig-routing-policy.html#routing-policy-policy-definitions-policy-definition-statements-statement-conditions-bgp-conditions-community-count):
* /routing-policy/policy-definitions/policy-definition/statements/statement/conditions/bgp-conditions/community-count/config/operator
* /routing-policy/policy-definitions/policy-definition/statements/statement/conditions/bgp-conditions/community-count/config/value
2024-04-11 07:48:16 +09:00

1911 lines
60 KiB
Go

// Copyright (C) 2014-2021 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 server
import (
"bytes"
"context"
"fmt"
"io"
"math"
"net"
"reflect"
"regexp"
"strconv"
"strings"
"sync"
"time"
"github.com/dgryski/go-farm"
"google.golang.org/grpc"
apb "google.golang.org/protobuf/types/known/anypb"
"google.golang.org/protobuf/types/known/emptypb"
tspb "google.golang.org/protobuf/types/known/timestamppb"
api "github.com/osrg/gobgp/v3/api"
"github.com/osrg/gobgp/v3/internal/pkg/table"
"github.com/osrg/gobgp/v3/pkg/apiutil"
"github.com/osrg/gobgp/v3/pkg/config/oc"
"github.com/osrg/gobgp/v3/pkg/log"
"github.com/osrg/gobgp/v3/pkg/packet/bgp"
)
// Unlimited batch size by default
const defaultListPathBatchSize = math.MaxUint64
type server struct {
bgpServer *BgpServer
grpcServer *grpc.Server
hosts string
api.UnimplementedGobgpApiServer
}
func newAPIserver(b *BgpServer, g *grpc.Server, hosts string) *server {
grpc.EnableTracing = false
s := &server{
bgpServer: b,
grpcServer: g,
hosts: hosts,
}
api.RegisterGobgpApiServer(g, s)
return s
}
func (s *server) serve() error {
var wg sync.WaitGroup
l := []net.Listener{}
var err error
for _, host := range strings.Split(s.hosts, ",") {
network, address := parseHost(host)
var lis net.Listener
lis, err = net.Listen(network, address)
if err != nil {
s.bgpServer.logger.Warn("listen failed",
log.Fields{
"Topic": "grpc",
"Key": host,
"Error": err})
break
}
l = append(l, lis)
}
if err != nil {
for _, lis := range l {
lis.Close()
}
return err
}
wg.Add(len(l))
serve := func(lis net.Listener) {
defer wg.Done()
err := s.grpcServer.Serve(lis)
if err != nil {
s.bgpServer.logger.Warn("accept failed",
log.Fields{
"Topic": "grpc",
"Key": lis.Addr().String(),
"Error": err})
}
}
for _, lis := range l {
go serve(lis)
}
wg.Wait()
return nil
}
func (s *server) ListDynamicNeighbor(r *api.ListDynamicNeighborRequest, stream api.GobgpApi_ListDynamicNeighborServer) error {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
fn := func(dn *api.DynamicNeighbor) {
if err := stream.Send(&api.ListDynamicNeighborResponse{DynamicNeighbor: dn}); err != nil {
cancel()
return
}
}
return s.bgpServer.ListDynamicNeighbor(ctx, r, fn)
}
func (s *server) ListPeerGroup(r *api.ListPeerGroupRequest, stream api.GobgpApi_ListPeerGroupServer) error {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
fn := func(pg *api.PeerGroup) {
if err := stream.Send(&api.ListPeerGroupResponse{PeerGroup: pg}); err != nil {
cancel()
return
}
}
return s.bgpServer.ListPeerGroup(ctx, r, fn)
}
func parseHost(host string) (string, string) {
const unixScheme = "unix://"
if strings.HasPrefix(host, unixScheme) {
return "unix", host[len(unixScheme):]
}
return "tcp", host
}
func (s *server) ListPeer(r *api.ListPeerRequest, stream api.GobgpApi_ListPeerServer) error {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
fn := func(p *api.Peer) {
if err := stream.Send(&api.ListPeerResponse{Peer: p}); err != nil {
cancel()
return
}
}
return s.bgpServer.ListPeer(ctx, r, fn)
}
func newValidationFromTableStruct(v *table.Validation) *api.Validation {
if v == nil {
return &api.Validation{}
}
return &api.Validation{
State: api.Validation_State(v.Status.ToInt()),
Reason: api.Validation_Reason(v.Reason.ToInt()),
Matched: newRoaListFromTableStructList(v.Matched),
UnmatchedAsn: newRoaListFromTableStructList(v.UnmatchedAs),
UnmatchedLength: newRoaListFromTableStructList(v.UnmatchedLength),
}
}
func toPathAPI(binNlri []byte, binPattrs [][]byte, anyNlri *apb.Any, anyPattrs []*apb.Any, path *table.Path, v *table.Validation) *api.Path {
nlri := path.GetNlri()
p := &api.Path{
Nlri: anyNlri,
Pattrs: anyPattrs,
Age: tspb.New(path.GetTimestamp()),
IsWithdraw: path.IsWithdraw,
Validation: newValidationFromTableStruct(v),
Family: &api.Family{Afi: api.Family_Afi(nlri.AFI()), Safi: api.Family_Safi(nlri.SAFI())},
Stale: path.IsStale(),
IsFromExternal: path.IsFromExternal(),
NoImplicitWithdraw: path.NoImplicitWithdraw(),
IsNexthopInvalid: path.IsNexthopInvalid,
Identifier: nlri.PathIdentifier(),
LocalIdentifier: nlri.PathLocalIdentifier(),
NlriBinary: binNlri,
PattrsBinary: binPattrs,
}
if s := path.GetSource(); s != nil {
p.SourceAsn = s.AS
p.SourceId = s.ID.String()
p.NeighborIp = s.Address.String()
}
return p
}
func eorToPathAPI(path *table.Path) *api.Path {
nlri := path.GetNlri()
p := &api.Path{
Age: tspb.New(path.GetTimestamp()),
IsWithdraw: path.IsWithdraw,
Family: &api.Family{Afi: api.Family_Afi(nlri.AFI()), Safi: api.Family_Safi(nlri.SAFI())},
}
if s := path.GetSource(); s != nil {
p.SourceAsn = s.AS
p.SourceId = s.ID.String()
p.NeighborIp = s.Address.String()
}
return p
}
func toPathApi(path *table.Path, v *table.Validation, onlyBinary, nlriBinary, attributeBinary bool) *api.Path {
var (
anyNlri *apb.Any
anyPattrs []*apb.Any
)
nlri := path.GetNlri()
if !onlyBinary {
anyNlri, _ = apiutil.MarshalNLRI(nlri)
anyPattrs, _ = apiutil.MarshalPathAttributes(path.GetPathAttrs())
}
var binNlri []byte
if onlyBinary || nlriBinary {
binNlri, _ = nlri.Serialize()
}
var binPattrs [][]byte
if onlyBinary || attributeBinary {
pa := path.GetPathAttrs()
binPattrs = make([][]byte, 0, len(pa))
for _, a := range pa {
b, e := a.Serialize()
if e == nil {
binPattrs = append(binPattrs, b)
}
}
}
return toPathAPI(binNlri, binPattrs, anyNlri, anyPattrs, path, v)
}
func getValidation(v map[*table.Path]*table.Validation, p *table.Path) *table.Validation {
if v == nil {
return nil
} else {
return v[p]
}
}
func (s *server) ListPath(r *api.ListPathRequest, stream api.GobgpApi_ListPathServer) error {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
batchSize := r.BatchSize
if batchSize == 0 {
batchSize = defaultListPathBatchSize
}
l := make([]*api.Destination, 0)
send := func() error {
for _, d := range l {
if err := stream.Send(&api.ListPathResponse{Destination: d}); err != nil {
return err
}
}
return nil
}
var sendErr error
err := s.bgpServer.ListPath(ctx, r, func(d *api.Destination) {
if uint64(len(l)) < batchSize {
l = append(l, d)
return
}
if sendErr = send(); sendErr != nil {
cancel()
return
}
l = l[:0]
})
if sendErr != nil {
return sendErr
}
if err != nil {
return err
}
return send()
}
func (s *server) WatchEvent(r *api.WatchEventRequest, stream api.GobgpApi_WatchEventServer) error {
ctx, cancel := context.WithCancel(stream.Context())
s.bgpServer.WatchEvent(ctx, r, func(rsp *api.WatchEventResponse) {
if err := stream.Send(rsp); err != nil {
cancel()
return
}
})
<-ctx.Done()
return nil
}
func (s *server) ResetPeer(ctx context.Context, r *api.ResetPeerRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, s.bgpServer.ResetPeer(ctx, r)
}
func (s *server) ShutdownPeer(ctx context.Context, r *api.ShutdownPeerRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, s.bgpServer.ShutdownPeer(ctx, r)
}
func (s *server) EnablePeer(ctx context.Context, r *api.EnablePeerRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, s.bgpServer.EnablePeer(ctx, r)
}
func (s *server) DisablePeer(ctx context.Context, r *api.DisablePeerRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, s.bgpServer.DisablePeer(ctx, r)
}
func (s *server) SetPolicies(ctx context.Context, r *api.SetPoliciesRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, s.bgpServer.SetPolicies(ctx, r)
}
func newRoutingPolicyFromApiStruct(arg *api.SetPoliciesRequest) (*oc.RoutingPolicy, error) {
policyDefinitions := make([]oc.PolicyDefinition, 0, len(arg.Policies))
for _, p := range arg.Policies {
pd, err := newConfigPolicyFromApiStruct(p)
if err != nil {
return nil, err
}
policyDefinitions = append(policyDefinitions, *pd)
}
definedSets, err := newConfigDefinedSetsFromApiStruct(arg.DefinedSets)
if err != nil {
return nil, err
}
return &oc.RoutingPolicy{
DefinedSets: *definedSets,
PolicyDefinitions: policyDefinitions,
}, nil
}
func api2Path(resource api.TableType, path *api.Path, isWithdraw bool) (*table.Path, error) {
var pi *table.PeerInfo
var nlri bgp.AddrPrefixInterface
var nexthop string
if path.SourceAsn != 0 {
pi = &table.PeerInfo{
AS: path.SourceAsn,
ID: net.ParseIP(path.SourceId),
}
}
nlri, err := apiutil.GetNativeNlri(path)
if err != nil {
return nil, err
}
nlri.SetPathIdentifier(path.Identifier)
attrList, err := apiutil.GetNativePathAttributes(path)
if err != nil {
return nil, err
}
// TODO (sbezverk) At this poinnt nlri and path attributes are converted to native mode
// need to check if update with SR Policy nlri comes with mandatory route distinguisher
// extended community or NO_ADVERTISE community, with Tunnel Encapsulation Attribute 23
// and tunnel type 15. If it is not the case ignore update and log an error.
pattrs := make([]bgp.PathAttributeInterface, 0)
seen := make(map[bgp.BGPAttrType]struct{})
for _, attr := range attrList {
attrType := attr.GetType()
if _, ok := seen[attrType]; !ok {
seen[attrType] = struct{}{}
} else {
return nil, fmt.Errorf("duplicated path attribute type: %d", attrType)
}
switch a := attr.(type) {
case *bgp.PathAttributeNextHop:
nexthop = a.Value.String()
case *bgp.PathAttributeMpReachNLRI:
if len(a.Value) == 0 {
return nil, fmt.Errorf("invalid mp reach attribute")
}
nexthop = a.Nexthop.String()
default:
pattrs = append(pattrs, attr)
}
}
if nlri == nil {
return nil, fmt.Errorf("nlri not found")
} else if !path.IsWithdraw && nexthop == "" {
return nil, fmt.Errorf("nexthop not found")
}
rf := bgp.AfiSafiToRouteFamily(uint16(path.Family.Afi), uint8(path.Family.Safi))
if resource != api.TableType_VRF && rf == bgp.RF_IPv4_UC && net.ParseIP(nexthop).To4() != nil {
pattrs = append(pattrs, bgp.NewPathAttributeNextHop(nexthop))
} else {
pattrs = append(pattrs, bgp.NewPathAttributeMpReachNLRI(nexthop, []bgp.AddrPrefixInterface{nlri}))
}
doWithdraw := (isWithdraw || path.IsWithdraw)
newPath := table.NewPath(pi, nlri, doWithdraw, pattrs, time.Now(), path.NoImplicitWithdraw)
if !doWithdraw {
total := bytes.NewBuffer(make([]byte, 0))
for _, a := range newPath.GetPathAttrs() {
if a.GetType() == bgp.BGP_ATTR_TYPE_MP_REACH_NLRI {
continue
}
b, _ := a.Serialize()
total.Write(b)
}
newPath.SetHash(farm.Hash32(total.Bytes()))
}
newPath.SetIsFromExternal(path.IsFromExternal)
return newPath, nil
}
func (s *server) AddPath(ctx context.Context, r *api.AddPathRequest) (*api.AddPathResponse, error) {
return s.bgpServer.AddPath(ctx, r)
}
func (s *server) DeletePath(ctx context.Context, r *api.DeletePathRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, s.bgpServer.DeletePath(ctx, r)
}
func (s *server) EnableMrt(ctx context.Context, r *api.EnableMrtRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, s.bgpServer.EnableMrt(ctx, r)
}
func (s *server) DisableMrt(ctx context.Context, r *api.DisableMrtRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, s.bgpServer.DisableMrt(ctx, r)
}
func (s *server) AddPathStream(stream api.GobgpApi_AddPathStreamServer) error {
for {
arg, err := stream.Recv()
if err == io.EOF {
break
} else if err != nil {
return err
}
if arg.TableType != api.TableType_GLOBAL && arg.TableType != api.TableType_VRF {
return fmt.Errorf("unsupported resource: %s", arg.TableType)
}
pathList := make([]*table.Path, 0, len(arg.Paths))
for _, apiPath := range arg.Paths {
if path, err := api2Path(arg.TableType, apiPath, apiPath.IsWithdraw); err != nil {
return err
} else {
pathList = append(pathList, path)
}
}
err = s.bgpServer.addPathStream(arg.VrfId, pathList)
if err != nil {
return err
}
}
return stream.SendAndClose(&emptypb.Empty{})
}
func (s *server) AddBmp(ctx context.Context, r *api.AddBmpRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, s.bgpServer.AddBmp(ctx, r)
}
func (s *server) DeleteBmp(ctx context.Context, r *api.DeleteBmpRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, s.bgpServer.DeleteBmp(ctx, r)
}
func (s *server) ListBmp(r *api.ListBmpRequest, stream api.GobgpApi_ListBmpServer) error {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
fn := func(rsp *api.ListBmpResponse_BmpStation) {
if err := stream.Send(&api.ListBmpResponse{Station: rsp}); err != nil {
cancel()
}
}
return s.bgpServer.ListBmp(ctx, r, fn)
}
func (s *server) AddRpki(ctx context.Context, r *api.AddRpkiRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, s.bgpServer.AddRpki(ctx, r)
}
func (s *server) DeleteRpki(ctx context.Context, r *api.DeleteRpkiRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, s.bgpServer.DeleteRpki(ctx, r)
}
func (s *server) EnableRpki(ctx context.Context, r *api.EnableRpkiRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, s.bgpServer.EnableRpki(ctx, r)
}
func (s *server) DisableRpki(ctx context.Context, r *api.DisableRpkiRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, s.bgpServer.DisableRpki(ctx, r)
}
func (s *server) ResetRpki(ctx context.Context, r *api.ResetRpkiRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, s.bgpServer.ResetRpki(ctx, r)
}
func (s *server) ListRpki(r *api.ListRpkiRequest, stream api.GobgpApi_ListRpkiServer) error {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
fn := func(r *api.Rpki) {
if err := stream.Send(&api.ListRpkiResponse{Server: r}); err != nil {
cancel()
}
}
return s.bgpServer.ListRpki(ctx, r, fn)
}
func (s *server) ListRpkiTable(r *api.ListRpkiTableRequest, stream api.GobgpApi_ListRpkiTableServer) error {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
fn := func(r *api.Roa) {
if err := stream.Send(&api.ListRpkiTableResponse{Roa: r}); err != nil {
cancel()
}
}
return s.bgpServer.ListRpkiTable(ctx, r, fn)
}
func (s *server) EnableZebra(ctx context.Context, r *api.EnableZebraRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, s.bgpServer.EnableZebra(ctx, r)
}
func (s *server) ListVrf(r *api.ListVrfRequest, stream api.GobgpApi_ListVrfServer) error {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
fn := func(v *api.Vrf) {
if err := stream.Send(&api.ListVrfResponse{Vrf: v}); err != nil {
cancel()
}
}
return s.bgpServer.ListVrf(ctx, r, fn)
}
func (s *server) AddVrf(ctx context.Context, r *api.AddVrfRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, s.bgpServer.AddVrf(ctx, r)
}
func (s *server) DeleteVrf(ctx context.Context, r *api.DeleteVrfRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, s.bgpServer.DeleteVrf(ctx, r)
}
func readMpGracefulRestartFromAPIStruct(c *oc.MpGracefulRestart, a *api.MpGracefulRestart) {
if c == nil || a == nil {
return
}
if a.Config != nil {
c.Config.Enabled = a.Config.Enabled
}
}
func readAfiSafiConfigFromAPIStruct(c *oc.AfiSafiConfig, a *api.AfiSafiConfig) {
if c == nil || a == nil {
return
}
rf := bgp.AfiSafiToRouteFamily(uint16(a.Family.Afi), uint8(a.Family.Safi))
c.AfiSafiName = oc.AfiSafiType(rf.String())
c.Enabled = a.Enabled
}
func readAfiSafiStateFromAPIStruct(s *oc.AfiSafiState, a *api.AfiSafiConfig) {
if s == nil || a == nil {
return
}
// Store only address family value for the convenience
s.Family = bgp.AfiSafiToRouteFamily(uint16(a.Family.Afi), uint8(a.Family.Safi))
}
func readPrefixLimitFromAPIStruct(c *oc.PrefixLimit, a *api.PrefixLimit) {
if c == nil || a == nil {
return
}
c.Config.MaxPrefixes = a.MaxPrefixes
c.Config.ShutdownThresholdPct = oc.Percentage(a.ShutdownThresholdPct)
}
func readApplyPolicyFromAPIStruct(c *oc.ApplyPolicy, a *api.ApplyPolicy) {
if c == nil || a == nil {
return
}
f := func(a api.RouteAction) oc.DefaultPolicyType {
if a == api.RouteAction_ACCEPT {
return oc.DEFAULT_POLICY_TYPE_ACCEPT_ROUTE
} else if a == api.RouteAction_REJECT {
return oc.DEFAULT_POLICY_TYPE_REJECT_ROUTE
}
return ""
}
if a.ImportPolicy != nil {
c.Config.DefaultImportPolicy = f(a.ImportPolicy.DefaultAction)
for _, p := range a.ImportPolicy.Policies {
c.Config.ImportPolicyList = append(c.Config.ImportPolicyList, p.Name)
}
}
if a.ExportPolicy != nil {
c.Config.DefaultExportPolicy = f(a.ExportPolicy.DefaultAction)
for _, p := range a.ExportPolicy.Policies {
c.Config.ExportPolicyList = append(c.Config.ExportPolicyList, p.Name)
}
}
if a.InPolicy != nil {
c.Config.DefaultInPolicy = f(a.InPolicy.DefaultAction)
for _, p := range a.InPolicy.Policies {
c.Config.InPolicyList = append(c.Config.InPolicyList, p.Name)
}
}
}
func readRouteSelectionOptionsFromAPIStruct(c *oc.RouteSelectionOptions, a *api.RouteSelectionOptions) {
if c == nil || a == nil {
return
}
if a.Config != nil {
c.Config.AlwaysCompareMed = a.Config.AlwaysCompareMed
c.Config.IgnoreAsPathLength = a.Config.IgnoreAsPathLength
c.Config.ExternalCompareRouterId = a.Config.ExternalCompareRouterId
c.Config.AdvertiseInactiveRoutes = a.Config.AdvertiseInactiveRoutes
c.Config.EnableAigp = a.Config.EnableAigp
c.Config.IgnoreNextHopIgpMetric = a.Config.IgnoreNextHopIgpMetric
}
}
func readUseMultiplePathsFromAPIStruct(c *oc.UseMultiplePaths, a *api.UseMultiplePaths) {
if c == nil || a == nil {
return
}
if a.Config != nil {
c.Config.Enabled = a.Config.Enabled
}
if a.Ebgp != nil && a.Ebgp.Config != nil {
c.Ebgp = oc.Ebgp{
Config: oc.EbgpConfig{
AllowMultipleAs: a.Ebgp.Config.AllowMultipleAsn,
MaximumPaths: a.Ebgp.Config.MaximumPaths,
},
}
}
if a.Ibgp != nil && a.Ibgp.Config != nil {
c.Ibgp = oc.Ibgp{
Config: oc.IbgpConfig{
MaximumPaths: a.Ibgp.Config.MaximumPaths,
},
}
}
}
func readRouteTargetMembershipFromAPIStruct(c *oc.RouteTargetMembership, a *api.RouteTargetMembership) {
if c == nil || a == nil {
return
}
if a.Config != nil {
c.Config.DeferralTime = uint16(a.Config.DeferralTime)
}
}
func readLongLivedGracefulRestartFromAPIStruct(c *oc.LongLivedGracefulRestart, a *api.LongLivedGracefulRestart) {
if c == nil || a == nil {
return
}
if a.Config != nil {
c.Config.Enabled = a.Config.Enabled
c.Config.RestartTime = a.Config.RestartTime
}
}
func readAddPathsFromAPIStruct(c *oc.AddPaths, a *api.AddPaths) {
if c == nil || a == nil {
return
}
if a.Config != nil {
c.Config.Receive = a.Config.Receive
c.Config.SendMax = uint8(a.Config.SendMax)
}
}
func newNeighborFromAPIStruct(a *api.Peer) (*oc.Neighbor, error) {
pconf := &oc.Neighbor{}
if a.Conf != nil {
pconf.Config.PeerAs = a.Conf.PeerAsn
pconf.Config.LocalAs = a.Conf.LocalAsn
pconf.Config.AuthPassword = a.Conf.AuthPassword
pconf.Config.RouteFlapDamping = a.Conf.RouteFlapDamping
pconf.Config.Description = a.Conf.Description
pconf.Config.PeerGroup = a.Conf.PeerGroup
pconf.Config.PeerType = oc.IntToPeerTypeMap[int(a.Conf.Type)]
pconf.Config.NeighborAddress = a.Conf.NeighborAddress
pconf.Config.AdminDown = a.Conf.AdminDown
pconf.Config.NeighborInterface = a.Conf.NeighborInterface
pconf.Config.Vrf = a.Conf.Vrf
pconf.AsPathOptions.Config.AllowOwnAs = uint8(a.Conf.AllowOwnAsn)
pconf.AsPathOptions.Config.ReplacePeerAs = a.Conf.ReplacePeerAsn
pconf.Config.SendSoftwareVersion = a.Conf.SendSoftwareVersion
switch a.Conf.RemovePrivate {
case api.RemovePrivate_REMOVE_ALL:
pconf.Config.RemovePrivateAs = oc.REMOVE_PRIVATE_AS_OPTION_ALL
case api.RemovePrivate_REPLACE:
pconf.Config.RemovePrivateAs = oc.REMOVE_PRIVATE_AS_OPTION_REPLACE
}
if a.State != nil {
localCaps, err := apiutil.UnmarshalCapabilities(a.State.LocalCap)
if err != nil {
return nil, err
}
remoteCaps, err := apiutil.UnmarshalCapabilities(a.State.RemoteCap)
if err != nil {
return nil, err
}
pconf.State.LocalCapabilityList = localCaps
pconf.State.RemoteCapabilityList = remoteCaps
pconf.State.RemoteRouterId = a.State.RouterId
}
for _, af := range a.AfiSafis {
afiSafi := oc.AfiSafi{}
readMpGracefulRestartFromAPIStruct(&afiSafi.MpGracefulRestart, af.MpGracefulRestart)
readAfiSafiConfigFromAPIStruct(&afiSafi.Config, af.Config)
readAfiSafiStateFromAPIStruct(&afiSafi.State, af.Config)
readApplyPolicyFromAPIStruct(&afiSafi.ApplyPolicy, af.ApplyPolicy)
readRouteSelectionOptionsFromAPIStruct(&afiSafi.RouteSelectionOptions, af.RouteSelectionOptions)
readUseMultiplePathsFromAPIStruct(&afiSafi.UseMultiplePaths, af.UseMultiplePaths)
readPrefixLimitFromAPIStruct(&afiSafi.PrefixLimit, af.PrefixLimits)
readRouteTargetMembershipFromAPIStruct(&afiSafi.RouteTargetMembership, af.RouteTargetMembership)
readLongLivedGracefulRestartFromAPIStruct(&afiSafi.LongLivedGracefulRestart, af.LongLivedGracefulRestart)
readAddPathsFromAPIStruct(&afiSafi.AddPaths, af.AddPaths)
pconf.AfiSafis = append(pconf.AfiSafis, afiSafi)
}
}
if a.Timers != nil {
if a.Timers.Config != nil {
pconf.Timers.Config.ConnectRetry = float64(a.Timers.Config.ConnectRetry)
pconf.Timers.Config.HoldTime = float64(a.Timers.Config.HoldTime)
pconf.Timers.Config.KeepaliveInterval = float64(a.Timers.Config.KeepaliveInterval)
pconf.Timers.Config.MinimumAdvertisementInterval = float64(a.Timers.Config.MinimumAdvertisementInterval)
pconf.Timers.Config.IdleHoldTimeAfterReset = float64(a.Timers.Config.IdleHoldTimeAfterReset)
}
if a.Timers.State != nil {
pconf.Timers.State.KeepaliveInterval = float64(a.Timers.State.KeepaliveInterval)
pconf.Timers.State.NegotiatedHoldTime = float64(a.Timers.State.NegotiatedHoldTime)
}
}
if a.RouteReflector != nil {
pconf.RouteReflector.Config.RouteReflectorClusterId = oc.RrClusterIdType(a.RouteReflector.RouteReflectorClusterId)
pconf.RouteReflector.Config.RouteReflectorClient = a.RouteReflector.RouteReflectorClient
}
if a.RouteServer != nil {
pconf.RouteServer.Config.RouteServerClient = a.RouteServer.RouteServerClient
pconf.RouteServer.Config.SecondaryRoute = a.RouteServer.SecondaryRoute
}
if a.GracefulRestart != nil {
pconf.GracefulRestart.Config.Enabled = a.GracefulRestart.Enabled
pconf.GracefulRestart.Config.RestartTime = uint16(a.GracefulRestart.RestartTime)
pconf.GracefulRestart.Config.HelperOnly = a.GracefulRestart.HelperOnly
pconf.GracefulRestart.Config.DeferralTime = uint16(a.GracefulRestart.DeferralTime)
pconf.GracefulRestart.Config.NotificationEnabled = a.GracefulRestart.NotificationEnabled
pconf.GracefulRestart.Config.LongLivedEnabled = a.GracefulRestart.LonglivedEnabled
pconf.GracefulRestart.State.LocalRestarting = a.GracefulRestart.LocalRestarting
}
readApplyPolicyFromAPIStruct(&pconf.ApplyPolicy, a.ApplyPolicy)
if a.Transport != nil {
pconf.Transport.Config.LocalAddress = a.Transport.LocalAddress
pconf.Transport.Config.PassiveMode = a.Transport.PassiveMode
pconf.Transport.Config.RemotePort = uint16(a.Transport.RemotePort)
pconf.Transport.Config.LocalPort = uint16(a.Transport.LocalPort)
pconf.Transport.Config.BindInterface = a.Transport.BindInterface
pconf.Transport.Config.TcpMss = uint16(a.Transport.TcpMss)
}
if a.EbgpMultihop != nil {
pconf.EbgpMultihop.Config.Enabled = a.EbgpMultihop.Enabled
pconf.EbgpMultihop.Config.MultihopTtl = uint8(a.EbgpMultihop.MultihopTtl)
}
if a.TtlSecurity != nil {
pconf.TtlSecurity.Config.Enabled = a.TtlSecurity.Enabled
pconf.TtlSecurity.Config.TtlMin = uint8(a.TtlSecurity.TtlMin)
}
if a.State != nil {
pconf.State.SessionState = oc.SessionState(strings.ToUpper(string(a.State.SessionState)))
pconf.State.AdminState = oc.IntToAdminStateMap[int(a.State.AdminState)]
pconf.State.PeerAs = a.State.PeerAsn
pconf.State.PeerType = oc.IntToPeerTypeMap[int(a.State.Type)]
pconf.State.NeighborAddress = a.State.NeighborAddress
if a.State.Messages != nil {
if a.State.Messages.Sent != nil {
pconf.State.Messages.Sent.Update = a.State.Messages.Sent.Update
pconf.State.Messages.Sent.Notification = a.State.Messages.Sent.Notification
pconf.State.Messages.Sent.Open = a.State.Messages.Sent.Open
pconf.State.Messages.Sent.Refresh = a.State.Messages.Sent.Refresh
pconf.State.Messages.Sent.Keepalive = a.State.Messages.Sent.Keepalive
pconf.State.Messages.Sent.Discarded = a.State.Messages.Sent.Discarded
pconf.State.Messages.Sent.Total = a.State.Messages.Sent.Total
}
if a.State.Messages.Received != nil {
pconf.State.Messages.Received.Update = a.State.Messages.Received.Update
pconf.State.Messages.Received.Open = a.State.Messages.Received.Open
pconf.State.Messages.Received.Refresh = a.State.Messages.Received.Refresh
pconf.State.Messages.Received.Keepalive = a.State.Messages.Received.Keepalive
pconf.State.Messages.Received.Discarded = a.State.Messages.Received.Discarded
pconf.State.Messages.Received.Total = a.State.Messages.Received.Total
}
}
}
return pconf, nil
}
func newPeerGroupFromAPIStruct(a *api.PeerGroup) (*oc.PeerGroup, error) {
pconf := &oc.PeerGroup{}
if a.Conf != nil {
pconf.Config.PeerAs = a.Conf.PeerAsn
pconf.Config.LocalAs = a.Conf.LocalAsn
pconf.Config.AuthPassword = a.Conf.AuthPassword
pconf.Config.RouteFlapDamping = a.Conf.RouteFlapDamping
pconf.Config.Description = a.Conf.Description
pconf.Config.PeerGroupName = a.Conf.PeerGroupName
switch a.Conf.RemovePrivate {
case api.RemovePrivate_REMOVE_ALL:
pconf.Config.RemovePrivateAs = oc.REMOVE_PRIVATE_AS_OPTION_ALL
case api.RemovePrivate_REPLACE:
pconf.Config.RemovePrivateAs = oc.REMOVE_PRIVATE_AS_OPTION_REPLACE
}
for _, af := range a.AfiSafis {
afiSafi := oc.AfiSafi{}
readMpGracefulRestartFromAPIStruct(&afiSafi.MpGracefulRestart, af.MpGracefulRestart)
readAfiSafiConfigFromAPIStruct(&afiSafi.Config, af.Config)
readAfiSafiStateFromAPIStruct(&afiSafi.State, af.Config)
readApplyPolicyFromAPIStruct(&afiSafi.ApplyPolicy, af.ApplyPolicy)
readRouteSelectionOptionsFromAPIStruct(&afiSafi.RouteSelectionOptions, af.RouteSelectionOptions)
readUseMultiplePathsFromAPIStruct(&afiSafi.UseMultiplePaths, af.UseMultiplePaths)
readPrefixLimitFromAPIStruct(&afiSafi.PrefixLimit, af.PrefixLimits)
readRouteTargetMembershipFromAPIStruct(&afiSafi.RouteTargetMembership, af.RouteTargetMembership)
readLongLivedGracefulRestartFromAPIStruct(&afiSafi.LongLivedGracefulRestart, af.LongLivedGracefulRestart)
readAddPathsFromAPIStruct(&afiSafi.AddPaths, af.AddPaths)
pconf.AfiSafis = append(pconf.AfiSafis, afiSafi)
}
}
if a.Timers != nil {
if a.Timers.Config != nil {
pconf.Timers.Config.ConnectRetry = float64(a.Timers.Config.ConnectRetry)
pconf.Timers.Config.HoldTime = float64(a.Timers.Config.HoldTime)
pconf.Timers.Config.KeepaliveInterval = float64(a.Timers.Config.KeepaliveInterval)
pconf.Timers.Config.MinimumAdvertisementInterval = float64(a.Timers.Config.MinimumAdvertisementInterval)
pconf.Timers.Config.IdleHoldTimeAfterReset = float64(a.Timers.Config.IdleHoldTimeAfterReset)
}
if a.Timers.State != nil {
pconf.Timers.State.KeepaliveInterval = float64(a.Timers.State.KeepaliveInterval)
pconf.Timers.State.NegotiatedHoldTime = float64(a.Timers.State.NegotiatedHoldTime)
}
}
if a.RouteReflector != nil {
pconf.RouteReflector.Config.RouteReflectorClusterId = oc.RrClusterIdType(a.RouteReflector.RouteReflectorClusterId)
pconf.RouteReflector.Config.RouteReflectorClient = a.RouteReflector.RouteReflectorClient
}
if a.RouteServer != nil {
pconf.RouteServer.Config.RouteServerClient = a.RouteServer.RouteServerClient
pconf.RouteServer.Config.SecondaryRoute = a.RouteServer.SecondaryRoute
}
if a.GracefulRestart != nil {
pconf.GracefulRestart.Config.Enabled = a.GracefulRestart.Enabled
pconf.GracefulRestart.Config.RestartTime = uint16(a.GracefulRestart.RestartTime)
pconf.GracefulRestart.Config.HelperOnly = a.GracefulRestart.HelperOnly
pconf.GracefulRestart.Config.DeferralTime = uint16(a.GracefulRestart.DeferralTime)
pconf.GracefulRestart.Config.NotificationEnabled = a.GracefulRestart.NotificationEnabled
pconf.GracefulRestart.Config.LongLivedEnabled = a.GracefulRestart.LonglivedEnabled
pconf.GracefulRestart.State.LocalRestarting = a.GracefulRestart.LocalRestarting
}
readApplyPolicyFromAPIStruct(&pconf.ApplyPolicy, a.ApplyPolicy)
if a.Transport != nil {
pconf.Transport.Config.LocalAddress = a.Transport.LocalAddress
pconf.Transport.Config.PassiveMode = a.Transport.PassiveMode
pconf.Transport.Config.RemotePort = uint16(a.Transport.RemotePort)
pconf.Transport.Config.TcpMss = uint16(a.Transport.TcpMss)
}
if a.EbgpMultihop != nil {
pconf.EbgpMultihop.Config.Enabled = a.EbgpMultihop.Enabled
pconf.EbgpMultihop.Config.MultihopTtl = uint8(a.EbgpMultihop.MultihopTtl)
}
if a.TtlSecurity != nil {
pconf.TtlSecurity.Config.Enabled = a.TtlSecurity.Enabled
pconf.TtlSecurity.Config.TtlMin = uint8(a.TtlSecurity.TtlMin)
}
if a.Info != nil {
pconf.State.TotalPaths = a.Info.TotalPaths
pconf.State.TotalPrefixes = a.Info.TotalPrefixes
pconf.State.PeerAs = a.Info.PeerAsn
pconf.State.PeerType = oc.IntToPeerTypeMap[int(a.Info.Type)]
}
return pconf, nil
}
func (s *server) AddPeer(ctx context.Context, r *api.AddPeerRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, s.bgpServer.AddPeer(ctx, r)
}
func (s *server) DeletePeer(ctx context.Context, r *api.DeletePeerRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, s.bgpServer.DeletePeer(ctx, r)
}
func (s *server) UpdatePeer(ctx context.Context, r *api.UpdatePeerRequest) (*api.UpdatePeerResponse, error) {
return s.bgpServer.UpdatePeer(ctx, r)
}
func (s *server) AddPeerGroup(ctx context.Context, r *api.AddPeerGroupRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, s.bgpServer.AddPeerGroup(ctx, r)
}
func (s *server) DeletePeerGroup(ctx context.Context, r *api.DeletePeerGroupRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, s.bgpServer.DeletePeerGroup(ctx, r)
}
func (s *server) UpdatePeerGroup(ctx context.Context, r *api.UpdatePeerGroupRequest) (*api.UpdatePeerGroupResponse, error) {
return s.bgpServer.UpdatePeerGroup(ctx, r)
}
func (s *server) AddDynamicNeighbor(ctx context.Context, r *api.AddDynamicNeighborRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, s.bgpServer.AddDynamicNeighbor(ctx, r)
}
func (s *server) DeleteDynamicNeighbor(ctx context.Context, r *api.DeleteDynamicNeighborRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, s.bgpServer.DeleteDynamicNeighbor(ctx, r)
}
func newPrefixFromApiStruct(a *api.Prefix) (*table.Prefix, error) {
_, prefix, err := net.ParseCIDR(a.IpPrefix)
if err != nil {
return nil, err
}
rf := bgp.RF_IPv4_UC
if strings.Contains(a.IpPrefix, ":") {
rf = bgp.RF_IPv6_UC
}
return &table.Prefix{
Prefix: prefix,
AddressFamily: rf,
MasklengthRangeMin: uint8(a.MaskLengthMin),
MasklengthRangeMax: uint8(a.MaskLengthMax),
}, nil
}
func newConfigPrefixFromAPIStruct(a *api.Prefix) (*oc.Prefix, error) {
_, prefix, err := net.ParseCIDR(a.IpPrefix)
if err != nil {
return nil, err
}
return &oc.Prefix{
IpPrefix: prefix.String(),
MasklengthRange: fmt.Sprintf("%d..%d", a.MaskLengthMin, a.MaskLengthMax),
}, nil
}
func newConfigDefinedSetsFromApiStruct(a []*api.DefinedSet) (*oc.DefinedSets, error) {
ps := make([]oc.PrefixSet, 0)
ns := make([]oc.NeighborSet, 0)
as := make([]oc.AsPathSet, 0)
cs := make([]oc.CommunitySet, 0)
es := make([]oc.ExtCommunitySet, 0)
ls := make([]oc.LargeCommunitySet, 0)
for _, ds := range a {
if ds.Name == "" {
return nil, fmt.Errorf("empty neighbor set name")
}
switch table.DefinedType(ds.DefinedType) {
case table.DEFINED_TYPE_PREFIX:
prefixes := make([]oc.Prefix, 0, len(ds.Prefixes))
for _, p := range ds.Prefixes {
prefix, err := newConfigPrefixFromAPIStruct(p)
if err != nil {
return nil, err
}
prefixes = append(prefixes, *prefix)
}
ps = append(ps, oc.PrefixSet{
PrefixSetName: ds.Name,
PrefixList: prefixes,
})
case table.DEFINED_TYPE_NEIGHBOR:
ns = append(ns, oc.NeighborSet{
NeighborSetName: ds.Name,
NeighborInfoList: ds.List,
})
case table.DEFINED_TYPE_AS_PATH:
as = append(as, oc.AsPathSet{
AsPathSetName: ds.Name,
AsPathList: ds.List,
})
case table.DEFINED_TYPE_COMMUNITY:
cs = append(cs, oc.CommunitySet{
CommunitySetName: ds.Name,
CommunityList: ds.List,
})
case table.DEFINED_TYPE_EXT_COMMUNITY:
es = append(es, oc.ExtCommunitySet{
ExtCommunitySetName: ds.Name,
ExtCommunityList: ds.List,
})
case table.DEFINED_TYPE_LARGE_COMMUNITY:
ls = append(ls, oc.LargeCommunitySet{
LargeCommunitySetName: ds.Name,
LargeCommunityList: ds.List,
})
default:
return nil, fmt.Errorf("invalid defined type")
}
}
return &oc.DefinedSets{
PrefixSets: ps,
NeighborSets: ns,
BgpDefinedSets: oc.BgpDefinedSets{
AsPathSets: as,
CommunitySets: cs,
ExtCommunitySets: es,
LargeCommunitySets: ls,
},
}, nil
}
func newDefinedSetFromApiStruct(a *api.DefinedSet) (table.DefinedSet, error) {
if a.Name == "" {
return nil, fmt.Errorf("empty neighbor set name")
}
switch table.DefinedType(a.DefinedType) {
case table.DEFINED_TYPE_PREFIX:
prefixes := make([]*table.Prefix, 0, len(a.Prefixes))
for _, p := range a.Prefixes {
prefix, err := newPrefixFromApiStruct(p)
if err != nil {
return nil, err
}
prefixes = append(prefixes, prefix)
}
return table.NewPrefixSetFromApiStruct(a.Name, prefixes)
case table.DEFINED_TYPE_NEIGHBOR:
list := make([]net.IPNet, 0, len(a.List))
for _, x := range a.List {
_, addr, err := net.ParseCIDR(x)
if err != nil {
return nil, fmt.Errorf("invalid address or prefix: %s", x)
}
list = append(list, *addr)
}
return table.NewNeighborSetFromApiStruct(a.Name, list)
case table.DEFINED_TYPE_AS_PATH:
return table.NewAsPathSet(oc.AsPathSet{
AsPathSetName: a.Name,
AsPathList: a.List,
})
case table.DEFINED_TYPE_COMMUNITY:
return table.NewCommunitySet(oc.CommunitySet{
CommunitySetName: a.Name,
CommunityList: a.List,
})
case table.DEFINED_TYPE_EXT_COMMUNITY:
return table.NewExtCommunitySet(oc.ExtCommunitySet{
ExtCommunitySetName: a.Name,
ExtCommunityList: a.List,
})
case table.DEFINED_TYPE_LARGE_COMMUNITY:
return table.NewLargeCommunitySet(oc.LargeCommunitySet{
LargeCommunitySetName: a.Name,
LargeCommunityList: a.List,
})
default:
return nil, fmt.Errorf("invalid defined type")
}
}
var _regexpPrefixMaskLengthRange = regexp.MustCompile(`(\d+)\.\.(\d+)`)
func (s *server) ListDefinedSet(r *api.ListDefinedSetRequest, stream api.GobgpApi_ListDefinedSetServer) error {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
fn := func(d *api.DefinedSet) {
if err := stream.Send(&api.ListDefinedSetResponse{DefinedSet: d}); err != nil {
cancel()
}
}
return s.bgpServer.ListDefinedSet(ctx, r, fn)
}
func (s *server) AddDefinedSet(ctx context.Context, r *api.AddDefinedSetRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, s.bgpServer.AddDefinedSet(ctx, r)
}
func (s *server) DeleteDefinedSet(ctx context.Context, r *api.DeleteDefinedSetRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, s.bgpServer.DeleteDefinedSet(ctx, r)
}
var _regexpMedActionType = regexp.MustCompile(`([+-]?)(\d+)`)
func matchSetOptionsRestrictedTypeToAPI(t oc.MatchSetOptionsRestrictedType) api.MatchSet_Type {
t = t.DefaultAsNeeded()
switch t {
case oc.MATCH_SET_OPTIONS_RESTRICTED_TYPE_ANY:
return api.MatchSet_ANY
case oc.MATCH_SET_OPTIONS_RESTRICTED_TYPE_INVERT:
return api.MatchSet_INVERT
}
return api.MatchSet_ANY
}
func toStatementApi(s *oc.Statement) *api.Statement {
cs := &api.Conditions{}
if s.Conditions.MatchPrefixSet.PrefixSet != "" {
cs.PrefixSet = &api.MatchSet{
Type: matchSetOptionsRestrictedTypeToAPI(s.Conditions.MatchPrefixSet.MatchSetOptions),
Name: s.Conditions.MatchPrefixSet.PrefixSet,
}
}
if s.Conditions.MatchNeighborSet.NeighborSet != "" {
cs.NeighborSet = &api.MatchSet{
Type: matchSetOptionsRestrictedTypeToAPI(s.Conditions.MatchNeighborSet.MatchSetOptions),
Name: s.Conditions.MatchNeighborSet.NeighborSet,
}
}
if s.Conditions.BgpConditions.CommunityCount.Operator != "" {
cs.CommunityCount = &api.CommunityCount{
Count: s.Conditions.BgpConditions.CommunityCount.Value,
Type: api.CommunityCount_Type(s.Conditions.BgpConditions.CommunityCount.Operator.ToInt()),
}
}
if s.Conditions.BgpConditions.AsPathLength.Operator != "" {
cs.AsPathLength = &api.AsPathLength{
Length: s.Conditions.BgpConditions.AsPathLength.Value,
Type: api.AsPathLength_Type(s.Conditions.BgpConditions.AsPathLength.Operator.ToInt()),
}
}
if s.Conditions.BgpConditions.MatchAsPathSet.AsPathSet != "" {
cs.AsPathSet = &api.MatchSet{
Type: api.MatchSet_Type(s.Conditions.BgpConditions.MatchAsPathSet.MatchSetOptions.ToInt()),
Name: s.Conditions.BgpConditions.MatchAsPathSet.AsPathSet,
}
}
if s.Conditions.BgpConditions.MatchCommunitySet.CommunitySet != "" {
cs.CommunitySet = &api.MatchSet{
Type: api.MatchSet_Type(s.Conditions.BgpConditions.MatchCommunitySet.MatchSetOptions.ToInt()),
Name: s.Conditions.BgpConditions.MatchCommunitySet.CommunitySet,
}
}
if s.Conditions.BgpConditions.MatchExtCommunitySet.ExtCommunitySet != "" {
cs.ExtCommunitySet = &api.MatchSet{
Type: api.MatchSet_Type(s.Conditions.BgpConditions.MatchExtCommunitySet.MatchSetOptions.ToInt()),
Name: s.Conditions.BgpConditions.MatchExtCommunitySet.ExtCommunitySet,
}
}
if s.Conditions.BgpConditions.MatchLargeCommunitySet.LargeCommunitySet != "" {
cs.LargeCommunitySet = &api.MatchSet{
Type: api.MatchSet_Type(s.Conditions.BgpConditions.MatchLargeCommunitySet.MatchSetOptions.ToInt()),
Name: s.Conditions.BgpConditions.MatchLargeCommunitySet.LargeCommunitySet,
}
}
if s.Conditions.BgpConditions.RouteType != "" {
cs.RouteType = api.Conditions_RouteType(s.Conditions.BgpConditions.RouteType.ToInt())
}
if len(s.Conditions.BgpConditions.NextHopInList) > 0 {
cs.NextHopInList = s.Conditions.BgpConditions.NextHopInList
}
if s.Conditions.BgpConditions.AfiSafiInList != nil {
afiSafiIn := make([]*api.Family, 0)
for _, afiSafiType := range s.Conditions.BgpConditions.AfiSafiInList {
if mapped, ok := bgp.AddressFamilyValueMap[string(afiSafiType)]; ok {
afi, safi := bgp.RouteFamilyToAfiSafi(mapped)
afiSafiIn = append(afiSafiIn, &api.Family{Afi: api.Family_Afi(afi), Safi: api.Family_Safi(safi)})
}
}
cs.AfiSafiIn = afiSafiIn
}
cs.RpkiResult = int32(s.Conditions.BgpConditions.RpkiValidationResult.ToInt())
as := &api.Actions{
RouteAction: func() api.RouteAction {
switch s.Actions.RouteDisposition {
case oc.ROUTE_DISPOSITION_ACCEPT_ROUTE:
return api.RouteAction_ACCEPT
case oc.ROUTE_DISPOSITION_REJECT_ROUTE:
return api.RouteAction_REJECT
}
return api.RouteAction_NONE
}(),
Community: func() *api.CommunityAction {
if len(s.Actions.BgpActions.SetCommunity.SetCommunityMethod.CommunitiesList) == 0 {
return nil
}
return &api.CommunityAction{
Type: api.CommunityAction_Type(oc.BgpSetCommunityOptionTypeToIntMap[oc.BgpSetCommunityOptionType(s.Actions.BgpActions.SetCommunity.Options)]),
Communities: s.Actions.BgpActions.SetCommunity.SetCommunityMethod.CommunitiesList}
}(),
Med: func() *api.MedAction {
medStr := strings.TrimSpace(string(s.Actions.BgpActions.SetMed))
if len(medStr) == 0 {
return nil
}
matches := _regexpMedActionType.FindStringSubmatch(medStr)
if len(matches) == 0 {
return nil
}
action := api.MedAction_REPLACE
switch matches[1] {
case "+", "-":
action = api.MedAction_MOD
}
value, err := strconv.ParseInt(matches[1]+matches[2], 10, 64)
if err != nil {
return nil
}
return &api.MedAction{
Value: value,
Type: action,
}
}(),
AsPrepend: func() *api.AsPrependAction {
if len(s.Actions.BgpActions.SetAsPathPrepend.As) == 0 {
return nil
}
var asn uint64
useleft := false
if s.Actions.BgpActions.SetAsPathPrepend.As != "last-as" {
asn, _ = strconv.ParseUint(s.Actions.BgpActions.SetAsPathPrepend.As, 10, 32)
} else {
useleft = true
}
return &api.AsPrependAction{
Asn: uint32(asn),
Repeat: uint32(s.Actions.BgpActions.SetAsPathPrepend.RepeatN),
UseLeftMost: useleft,
}
}(),
ExtCommunity: func() *api.CommunityAction {
if len(s.Actions.BgpActions.SetExtCommunity.SetExtCommunityMethod.CommunitiesList) == 0 {
return nil
}
return &api.CommunityAction{
Type: api.CommunityAction_Type(oc.BgpSetCommunityOptionTypeToIntMap[oc.BgpSetCommunityOptionType(s.Actions.BgpActions.SetExtCommunity.Options)]),
Communities: s.Actions.BgpActions.SetExtCommunity.SetExtCommunityMethod.CommunitiesList,
}
}(),
LargeCommunity: func() *api.CommunityAction {
if len(s.Actions.BgpActions.SetLargeCommunity.SetLargeCommunityMethod.CommunitiesList) == 0 {
return nil
}
return &api.CommunityAction{
Type: api.CommunityAction_Type(oc.BgpSetCommunityOptionTypeToIntMap[oc.BgpSetCommunityOptionType(s.Actions.BgpActions.SetLargeCommunity.Options)]),
Communities: s.Actions.BgpActions.SetLargeCommunity.SetLargeCommunityMethod.CommunitiesList,
}
}(),
Nexthop: func() *api.NexthopAction {
if len(string(s.Actions.BgpActions.SetNextHop)) == 0 {
return nil
}
if string(s.Actions.BgpActions.SetNextHop) == "self" {
return &api.NexthopAction{
Self: true,
}
}
if string(s.Actions.BgpActions.SetNextHop) == "unchanged" {
return &api.NexthopAction{
Unchanged: true,
}
}
return &api.NexthopAction{
Address: string(s.Actions.BgpActions.SetNextHop),
}
}(),
LocalPref: func() *api.LocalPrefAction {
if s.Actions.BgpActions.SetLocalPref == 0 {
return nil
}
return &api.LocalPrefAction{Value: s.Actions.BgpActions.SetLocalPref}
}(),
}
return &api.Statement{
Name: s.Name,
Conditions: cs,
Actions: as,
}
}
func toConfigMatchSetOption(a api.MatchSet_Type) (oc.MatchSetOptionsType, error) {
var typ oc.MatchSetOptionsType
switch a {
case api.MatchSet_ANY:
typ = oc.MATCH_SET_OPTIONS_TYPE_ANY
case api.MatchSet_ALL:
typ = oc.MATCH_SET_OPTIONS_TYPE_ALL
case api.MatchSet_INVERT:
typ = oc.MATCH_SET_OPTIONS_TYPE_INVERT
default:
return typ, fmt.Errorf("invalid match type")
}
return typ, nil
}
func toConfigMatchSetOptionRestricted(a api.MatchSet_Type) (oc.MatchSetOptionsRestrictedType, error) {
var typ oc.MatchSetOptionsRestrictedType
switch a {
case api.MatchSet_ANY:
typ = oc.MATCH_SET_OPTIONS_RESTRICTED_TYPE_ANY
case api.MatchSet_INVERT:
typ = oc.MATCH_SET_OPTIONS_RESTRICTED_TYPE_INVERT
default:
return typ, fmt.Errorf("invalid match type")
}
return typ, nil
}
func newPrefixConditionFromApiStruct(a *api.MatchSet) (*table.PrefixCondition, error) {
if a == nil {
return nil, nil
}
typ, err := toConfigMatchSetOptionRestricted(a.Type)
if err != nil {
return nil, err
}
c := oc.MatchPrefixSet{
PrefixSet: a.Name,
MatchSetOptions: typ,
}
return table.NewPrefixCondition(c)
}
func newNeighborConditionFromApiStruct(a *api.MatchSet) (*table.NeighborCondition, error) {
if a == nil {
return nil, nil
}
typ, err := toConfigMatchSetOptionRestricted(a.Type)
if err != nil {
return nil, err
}
c := oc.MatchNeighborSet{
NeighborSet: a.Name,
MatchSetOptions: typ,
}
return table.NewNeighborCondition(c)
}
func newCommunityCountConditionFromApiStruct(a *api.CommunityCount) (*table.CommunityCountCondition, error) {
if a == nil {
return nil, nil
}
return table.NewCommunityCountCondition(oc.CommunityCount{
Operator: oc.IntToAttributeComparisonMap[int(a.Type)],
Value: a.Count,
})
}
func newAsPathLengthConditionFromApiStruct(a *api.AsPathLength) (*table.AsPathLengthCondition, error) {
if a == nil {
return nil, nil
}
return table.NewAsPathLengthCondition(oc.AsPathLength{
Operator: oc.IntToAttributeComparisonMap[int(a.Type)],
Value: a.Length,
})
}
func newAsPathConditionFromApiStruct(a *api.MatchSet) (*table.AsPathCondition, error) {
if a == nil {
return nil, nil
}
typ, err := toConfigMatchSetOption(a.Type)
if err != nil {
return nil, err
}
c := oc.MatchAsPathSet{
AsPathSet: a.Name,
MatchSetOptions: typ,
}
return table.NewAsPathCondition(c)
}
func newRpkiValidationConditionFromApiStruct(a int32) (*table.RpkiValidationCondition, error) {
if a < 1 {
return nil, nil
}
return table.NewRpkiValidationCondition(oc.IntToRpkiValidationResultTypeMap[int(a)])
}
func newRouteTypeConditionFromApiStruct(a api.Conditions_RouteType) (*table.RouteTypeCondition, error) {
if a == 0 {
return nil, nil
}
typ, ok := oc.IntToRouteTypeMap[int(a)]
if !ok {
return nil, fmt.Errorf("invalid route type: %d", a)
}
return table.NewRouteTypeCondition(typ)
}
func newCommunityConditionFromApiStruct(a *api.MatchSet) (*table.CommunityCondition, error) {
if a == nil {
return nil, nil
}
typ, err := toConfigMatchSetOption(a.Type)
if err != nil {
return nil, err
}
c := oc.MatchCommunitySet{
CommunitySet: a.Name,
MatchSetOptions: typ,
}
return table.NewCommunityCondition(c)
}
func newExtCommunityConditionFromApiStruct(a *api.MatchSet) (*table.ExtCommunityCondition, error) {
if a == nil {
return nil, nil
}
typ, err := toConfigMatchSetOption(a.Type)
if err != nil {
return nil, err
}
c := oc.MatchExtCommunitySet{
ExtCommunitySet: a.Name,
MatchSetOptions: typ,
}
return table.NewExtCommunityCondition(c)
}
func newLargeCommunityConditionFromApiStruct(a *api.MatchSet) (*table.LargeCommunityCondition, error) {
if a == nil {
return nil, nil
}
typ, err := toConfigMatchSetOption(a.Type)
if err != nil {
return nil, err
}
c := oc.MatchLargeCommunitySet{
LargeCommunitySet: a.Name,
MatchSetOptions: typ,
}
return table.NewLargeCommunityCondition(c)
}
func newNextHopConditionFromApiStruct(a []string) (*table.NextHopCondition, error) {
if a == nil {
return nil, nil
}
return table.NewNextHopCondition(a)
}
func newAfiSafiInConditionFromApiStruct(a []*api.Family) (*table.AfiSafiInCondition, error) {
if a == nil {
return nil, nil
}
afiSafiTypes := make([]oc.AfiSafiType, 0, len(a))
for _, aType := range a {
rf := bgp.AfiSafiToRouteFamily(uint16(aType.Afi), uint8(aType.Safi))
if configType, ok := bgp.AddressFamilyNameMap[bgp.RouteFamily(rf)]; ok {
afiSafiTypes = append(afiSafiTypes, oc.AfiSafiType(configType))
} else {
return nil, fmt.Errorf("unknown afi-safi-in type value: %v", aType)
}
}
return table.NewAfiSafiInCondition(afiSafiTypes)
}
func newRoutingActionFromApiStruct(a api.RouteAction) (*table.RoutingAction, error) {
if a == api.RouteAction_NONE {
return nil, nil
}
accept := false
if a == api.RouteAction_ACCEPT {
accept = true
}
return &table.RoutingAction{
AcceptRoute: accept,
}, nil
}
func newCommunityActionFromApiStruct(a *api.CommunityAction) (*table.CommunityAction, error) {
if a == nil {
return nil, nil
}
return table.NewCommunityAction(oc.SetCommunity{
Options: string(oc.IntToBgpSetCommunityOptionTypeMap[int(a.Type)]),
SetCommunityMethod: oc.SetCommunityMethod{
CommunitiesList: a.Communities,
},
})
}
func newExtCommunityActionFromApiStruct(a *api.CommunityAction) (*table.ExtCommunityAction, error) {
if a == nil {
return nil, nil
}
return table.NewExtCommunityAction(oc.SetExtCommunity{
Options: string(oc.IntToBgpSetCommunityOptionTypeMap[int(a.Type)]),
SetExtCommunityMethod: oc.SetExtCommunityMethod{
CommunitiesList: a.Communities,
},
})
}
func newLargeCommunityActionFromApiStruct(a *api.CommunityAction) (*table.LargeCommunityAction, error) {
if a == nil {
return nil, nil
}
return table.NewLargeCommunityAction(oc.SetLargeCommunity{
Options: oc.IntToBgpSetCommunityOptionTypeMap[int(a.Type)],
SetLargeCommunityMethod: oc.SetLargeCommunityMethod{
CommunitiesList: a.Communities,
},
})
}
func newMedActionFromApiStruct(a *api.MedAction) (*table.MedAction, error) {
if a == nil {
return nil, nil
}
return table.NewMedActionFromApiStruct(table.MedActionType(a.Type), a.Value), nil
}
func newLocalPrefActionFromApiStruct(a *api.LocalPrefAction) (*table.LocalPrefAction, error) {
if a == nil || a.Value == 0 {
return nil, nil
}
return table.NewLocalPrefAction(a.Value)
}
func newAsPathPrependActionFromApiStruct(a *api.AsPrependAction) (*table.AsPathPrependAction, error) {
if a == nil {
return nil, nil
}
return table.NewAsPathPrependAction(oc.SetAsPathPrepend{
RepeatN: uint8(a.Repeat),
As: func() string {
if a.UseLeftMost {
return "last-as"
}
return fmt.Sprintf("%d", a.Asn)
}(),
})
}
func newNexthopActionFromApiStruct(a *api.NexthopAction) (*table.NexthopAction, error) {
if a == nil {
return nil, nil
}
return table.NewNexthopAction(oc.BgpNextHopType(
func() string {
if a.Self {
return "self"
}
if a.Unchanged {
return "unchanged"
}
return a.Address
}(),
))
}
func newStatementFromApiStruct(a *api.Statement) (*table.Statement, error) {
if a.Name == "" {
return nil, fmt.Errorf("empty statement name")
}
var ra table.Action
var as []table.Action
var cs []table.Condition
var err error
if a.Conditions != nil {
cfs := []func() (table.Condition, error){
func() (table.Condition, error) {
return newPrefixConditionFromApiStruct(a.Conditions.PrefixSet)
},
func() (table.Condition, error) {
return newNeighborConditionFromApiStruct(a.Conditions.NeighborSet)
},
func() (table.Condition, error) {
return newCommunityCountConditionFromApiStruct(a.Conditions.CommunityCount)
},
func() (table.Condition, error) {
return newAsPathLengthConditionFromApiStruct(a.Conditions.AsPathLength)
},
func() (table.Condition, error) {
return newRpkiValidationConditionFromApiStruct(a.Conditions.RpkiResult)
},
func() (table.Condition, error) {
return newRouteTypeConditionFromApiStruct(a.Conditions.RouteType)
},
func() (table.Condition, error) {
return newAsPathConditionFromApiStruct(a.Conditions.AsPathSet)
},
func() (table.Condition, error) {
return newCommunityConditionFromApiStruct(a.Conditions.CommunitySet)
},
func() (table.Condition, error) {
return newExtCommunityConditionFromApiStruct(a.Conditions.ExtCommunitySet)
},
func() (table.Condition, error) {
return newLargeCommunityConditionFromApiStruct(a.Conditions.LargeCommunitySet)
},
func() (table.Condition, error) {
return newNextHopConditionFromApiStruct(a.Conditions.NextHopInList)
},
func() (table.Condition, error) {
return newAfiSafiInConditionFromApiStruct(a.Conditions.AfiSafiIn)
},
}
cs = make([]table.Condition, 0, len(cfs))
for _, f := range cfs {
c, err := f()
if err != nil {
return nil, err
}
if !reflect.ValueOf(c).IsNil() {
cs = append(cs, c)
}
}
}
if a.Actions != nil {
ra, err = newRoutingActionFromApiStruct(a.Actions.RouteAction)
if err != nil {
return nil, err
}
afs := []func() (table.Action, error){
func() (table.Action, error) {
return newCommunityActionFromApiStruct(a.Actions.Community)
},
func() (table.Action, error) {
return newExtCommunityActionFromApiStruct(a.Actions.ExtCommunity)
},
func() (table.Action, error) {
return newLargeCommunityActionFromApiStruct(a.Actions.LargeCommunity)
},
func() (table.Action, error) {
return newMedActionFromApiStruct(a.Actions.Med)
},
func() (table.Action, error) {
return newLocalPrefActionFromApiStruct(a.Actions.LocalPref)
},
func() (table.Action, error) {
return newAsPathPrependActionFromApiStruct(a.Actions.AsPrepend)
},
func() (table.Action, error) {
return newNexthopActionFromApiStruct(a.Actions.Nexthop)
},
}
as = make([]table.Action, 0, len(afs))
for _, f := range afs {
a, err := f()
if err != nil {
return nil, err
}
if !reflect.ValueOf(a).IsNil() {
as = append(as, a)
}
}
}
return &table.Statement{
Name: a.Name,
Conditions: cs,
RouteAction: ra,
ModActions: as,
}, nil
}
func (s *server) ListStatement(r *api.ListStatementRequest, stream api.GobgpApi_ListStatementServer) error {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
fn := func(s *api.Statement) {
if err := stream.Send(&api.ListStatementResponse{Statement: s}); err != nil {
cancel()
}
}
return s.bgpServer.ListStatement(ctx, r, fn)
}
func (s *server) AddStatement(ctx context.Context, r *api.AddStatementRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, s.bgpServer.AddStatement(ctx, r)
}
func (s *server) DeleteStatement(ctx context.Context, r *api.DeleteStatementRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, s.bgpServer.DeleteStatement(ctx, r)
}
func newConfigPolicyFromApiStruct(a *api.Policy) (*oc.PolicyDefinition, error) {
if a.Name == "" {
return nil, fmt.Errorf("empty policy name")
}
stmts := make([]oc.Statement, 0, len(a.Statements))
for idx, x := range a.Statements {
if x.Name == "" {
x.Name = fmt.Sprintf("%s_stmt%d", a.Name, idx)
}
y, err := newStatementFromApiStruct(x)
if err != nil {
return nil, err
}
stmt := y.ToConfig()
stmts = append(stmts, *stmt)
}
return &oc.PolicyDefinition{
Name: a.Name,
Statements: stmts,
}, nil
}
func newPolicyFromApiStruct(a *api.Policy) (*table.Policy, error) {
if a.Name == "" {
return nil, fmt.Errorf("empty policy name")
}
stmts := make([]*table.Statement, 0, len(a.Statements))
for idx, x := range a.Statements {
if x.Name == "" {
x.Name = fmt.Sprintf("%s_stmt%d", a.Name, idx)
}
y, err := newStatementFromApiStruct(x)
if err != nil {
return nil, err
}
stmts = append(stmts, y)
}
return &table.Policy{
Name: a.Name,
Statements: stmts,
}, nil
}
func newRoaListFromTableStructList(origin []*table.ROA) []*api.Roa {
l := make([]*api.Roa, 0)
for _, r := range origin {
host, portStr, _ := net.SplitHostPort(r.Src)
port, _ := strconv.ParseUint(portStr, 10, 32)
ones, _ := r.Network.Mask.Size()
l = append(l, &api.Roa{
Asn: r.AS,
Maxlen: uint32(r.MaxLen),
Prefixlen: uint32(ones),
Prefix: r.Network.IP.String(),
Conf: &api.RPKIConf{
Address: host,
RemotePort: uint32(port),
},
})
}
return l
}
func (s *server) ListPolicy(r *api.ListPolicyRequest, stream api.GobgpApi_ListPolicyServer) error {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
fn := func(p *api.Policy) {
if err := stream.Send(&api.ListPolicyResponse{Policy: p}); err != nil {
cancel()
}
}
return s.bgpServer.ListPolicy(ctx, r, fn)
}
func (s *server) AddPolicy(ctx context.Context, r *api.AddPolicyRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, s.bgpServer.AddPolicy(ctx, r)
}
func (s *server) DeletePolicy(ctx context.Context, r *api.DeletePolicyRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, s.bgpServer.DeletePolicy(ctx, r)
}
func (s *server) ListPolicyAssignment(r *api.ListPolicyAssignmentRequest, stream api.GobgpApi_ListPolicyAssignmentServer) error {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
fn := func(a *api.PolicyAssignment) {
if err := stream.Send(&api.ListPolicyAssignmentResponse{Assignment: a}); err != nil {
cancel()
}
}
return s.bgpServer.ListPolicyAssignment(ctx, r, fn)
}
func defaultRouteType(d api.RouteAction) table.RouteType {
switch d {
case api.RouteAction_ACCEPT:
return table.ROUTE_TYPE_ACCEPT
case api.RouteAction_REJECT:
return table.ROUTE_TYPE_REJECT
default:
return table.ROUTE_TYPE_NONE
}
}
func toPolicyDefinition(policies []*api.Policy) []*oc.PolicyDefinition {
l := make([]*oc.PolicyDefinition, 0, len(policies))
for _, p := range policies {
l = append(l, &oc.PolicyDefinition{Name: p.Name})
}
return l
}
func (s *server) AddPolicyAssignment(ctx context.Context, r *api.AddPolicyAssignmentRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, s.bgpServer.AddPolicyAssignment(ctx, r)
}
func (s *server) DeletePolicyAssignment(ctx context.Context, r *api.DeletePolicyAssignmentRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, s.bgpServer.DeletePolicyAssignment(ctx, r)
}
func (s *server) SetPolicyAssignment(ctx context.Context, r *api.SetPolicyAssignmentRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, s.bgpServer.SetPolicyAssignment(ctx, r)
}
func (s *server) GetBgp(ctx context.Context, r *api.GetBgpRequest) (*api.GetBgpResponse, error) {
return s.bgpServer.GetBgp(ctx, r)
}
func newGlobalFromAPIStruct(a *api.Global) *oc.Global {
families := make([]oc.AfiSafi, 0, len(a.Families))
for _, f := range a.Families {
name := oc.IntToAfiSafiTypeMap[int(f)]
rf, _ := bgp.GetRouteFamily(string(name))
families = append(families, oc.AfiSafi{
Config: oc.AfiSafiConfig{
AfiSafiName: name,
Enabled: true,
},
State: oc.AfiSafiState{
AfiSafiName: name,
Enabled: true,
Family: rf,
},
})
}
applyPolicy := &oc.ApplyPolicy{}
readApplyPolicyFromAPIStruct(applyPolicy, a.ApplyPolicy)
global := &oc.Global{
Config: oc.GlobalConfig{
As: a.Asn,
RouterId: a.RouterId,
Port: a.ListenPort,
LocalAddressList: a.ListenAddresses,
},
ApplyPolicy: *applyPolicy,
AfiSafis: families,
UseMultiplePaths: oc.UseMultiplePaths{
Config: oc.UseMultiplePathsConfig{
Enabled: a.UseMultiplePaths,
},
},
}
if a.RouteSelectionOptions != nil {
global.RouteSelectionOptions = oc.RouteSelectionOptions{
Config: oc.RouteSelectionOptionsConfig{
AlwaysCompareMed: a.RouteSelectionOptions.AlwaysCompareMed,
IgnoreAsPathLength: a.RouteSelectionOptions.IgnoreAsPathLength,
ExternalCompareRouterId: a.RouteSelectionOptions.ExternalCompareRouterId,
AdvertiseInactiveRoutes: a.RouteSelectionOptions.AdvertiseInactiveRoutes,
EnableAigp: a.RouteSelectionOptions.EnableAigp,
IgnoreNextHopIgpMetric: a.RouteSelectionOptions.IgnoreNextHopIgpMetric,
DisableBestPathSelection: a.RouteSelectionOptions.DisableBestPathSelection,
},
}
}
if a.DefaultRouteDistance != nil {
global.DefaultRouteDistance = oc.DefaultRouteDistance{
Config: oc.DefaultRouteDistanceConfig{
ExternalRouteDistance: uint8(a.DefaultRouteDistance.ExternalRouteDistance),
InternalRouteDistance: uint8(a.DefaultRouteDistance.InternalRouteDistance),
},
}
}
if a.Confederation != nil {
global.Confederation = oc.Confederation{
Config: oc.ConfederationConfig{
Enabled: a.Confederation.Enabled,
Identifier: a.Confederation.Identifier,
MemberAsList: a.Confederation.MemberAsList,
},
}
}
if a.GracefulRestart != nil {
global.GracefulRestart = oc.GracefulRestart{
Config: oc.GracefulRestartConfig{
Enabled: a.GracefulRestart.Enabled,
RestartTime: uint16(a.GracefulRestart.RestartTime),
StaleRoutesTime: float64(a.GracefulRestart.StaleRoutesTime),
HelperOnly: a.GracefulRestart.HelperOnly,
DeferralTime: uint16(a.GracefulRestart.DeferralTime),
NotificationEnabled: a.GracefulRestart.NotificationEnabled,
LongLivedEnabled: a.GracefulRestart.LonglivedEnabled,
},
}
}
return global
}
func (s *server) StartBgp(ctx context.Context, r *api.StartBgpRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, s.bgpServer.StartBgp(ctx, r)
}
func (s *server) StopBgp(ctx context.Context, r *api.StopBgpRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, s.bgpServer.StopBgp(ctx, r)
}
func (s *server) GetTable(ctx context.Context, r *api.GetTableRequest) (*api.GetTableResponse, error) {
return s.bgpServer.GetTable(ctx, r)
}
func (s *server) SetLogLevel(ctx context.Context, r *api.SetLogLevelRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, s.bgpServer.SetLogLevel(ctx, r)
}