diff options
author | Wataru Ishida <ishida.wataru@lab.ntt.co.jp> | 2016-11-11 10:12:57 +0000 |
---|---|---|
committer | Wataru Ishida <ishida.wataru@lab.ntt.co.jp> | 2016-11-14 02:15:45 +0000 |
commit | 3f2dd34d37b5ca4874399d7eaff9bbb8b7975cd4 (patch) | |
tree | 50a37b0a7b09d9f11b6a83d5e701bc1e7ce31806 /client/client.go | |
parent | 480eb327831d56a795ea28d2c7293ab134d78a47 (diff) |
client: add golang client library
Signed-off-by: Wataru Ishida <ishida.wataru@lab.ntt.co.jp>
Diffstat (limited to 'client/client.go')
-rw-r--r-- | client/client.go | 900 |
1 files changed, 900 insertions, 0 deletions
diff --git a/client/client.go b/client/client.go new file mode 100644 index 00000000..53a822c5 --- /dev/null +++ b/client/client.go @@ -0,0 +1,900 @@ +// Copyright (C) 2016 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 client provides a wrapper for GoBGP's gRPC API +package client + +import ( + "fmt" + "net" + "strconv" + "time" + + api "github.com/osrg/gobgp/api" + "github.com/osrg/gobgp/config" + "github.com/osrg/gobgp/packet/bgp" + "github.com/osrg/gobgp/server" + "github.com/osrg/gobgp/table" + "golang.org/x/net/context" + "google.golang.org/grpc" +) + +type GoBGPClient struct { + conn *grpc.ClientConn + cli api.GobgpApiClient +} + +func defaultGRPCOptions() []grpc.DialOption { + return []grpc.DialOption{grpc.WithTimeout(time.Second), grpc.WithBlock(), grpc.WithInsecure()} +} + +func NewGoBGPClient(target string, opts ...grpc.DialOption) (*GoBGPClient, error) { + if target == "" { + target = ":50051" + } + if len(opts) == 0 { + opts = defaultGRPCOptions() + } + conn, err := grpc.Dial(target, opts...) + if err != nil { + return nil, err + } + cli := api.NewGobgpApiClient(conn) + return &GoBGPClient{conn: conn, cli: cli}, nil +} + +func (cli *GoBGPClient) Close() error { + return cli.conn.Close() +} + +func (cli *GoBGPClient) StartServer(c *config.Global) error { + _, err := cli.cli.StartServer(context.Background(), &api.StartServerRequest{ + Global: &api.Global{ + As: c.Config.As, + RouterId: c.Config.RouterId, + ListenPort: c.Config.Port, + ListenAddresses: c.Config.LocalAddressList, + UseMultiplePaths: c.UseMultiplePaths.Config.Enabled, + }, + }) + return err +} + +func (cli *GoBGPClient) StopServer() error { + _, err := cli.cli.StopServer(context.Background(), &api.StopServerRequest{}) + return err +} + +func (cli *GoBGPClient) GetServer() (*config.Global, error) { + ret, err := cli.cli.GetServer(context.Background(), &api.GetServerRequest{}) + if err != nil { + return nil, err + } + return &config.Global{ + Config: config.GlobalConfig{ + As: ret.Global.As, + RouterId: ret.Global.RouterId, + Port: ret.Global.ListenPort, + LocalAddressList: ret.Global.ListenAddresses, + }, + UseMultiplePaths: config.UseMultiplePaths{ + Config: config.UseMultiplePathsConfig{ + Enabled: ret.Global.UseMultiplePaths, + }, + }, + }, nil +} + +func (cli *GoBGPClient) GetNeighbor() ([]*config.Neighbor, error) { + ret, err := cli.cli.GetNeighbor(context.Background(), &api.GetNeighborRequest{}) + if err != nil { + return nil, err + } + + neighbors := make([]*config.Neighbor, 0, len(ret.Peers)) + + for _, p := range ret.Peers { + n, err := api.NewNeighborFromAPIStruct(p) + if err != nil { + return nil, err + } + neighbors = append(neighbors, n) + } + return neighbors, nil +} + +func (cli *GoBGPClient) AddNeighbor(c *config.Neighbor) error { + peer := api.NewPeerFromConfigStruct(c) + _, err := cli.cli.AddNeighbor(context.Background(), &api.AddNeighborRequest{peer}) + return err +} + +func (cli *GoBGPClient) DeleteNeighbor(c *config.Neighbor) error { + peer := api.NewPeerFromConfigStruct(c) + _, err := cli.cli.DeleteNeighbor(context.Background(), &api.DeleteNeighborRequest{peer}) + return err +} + +//func (cli *GoBGPClient) UpdateNeighbor(c *config.Neighbor) (bool, error) { +//} + +func (cli *GoBGPClient) ShutdownNeighbor(addr string) error { + _, err := cli.cli.ShutdownNeighbor(context.Background(), &api.ShutdownNeighborRequest{addr}) + return err +} + +func (cli *GoBGPClient) ResetNeighbor(addr string) error { + _, err := cli.cli.ResetNeighbor(context.Background(), &api.ResetNeighborRequest{addr}) + return err +} + +func (cli *GoBGPClient) EnableNeighbor(addr string) error { + _, err := cli.cli.EnableNeighbor(context.Background(), &api.EnableNeighborRequest{addr}) + return err +} + +func (cli *GoBGPClient) DisableNeighbor(addr string) error { + _, err := cli.cli.DisableNeighbor(context.Background(), &api.DisableNeighborRequest{addr}) + return err +} + +func (cli *GoBGPClient) softreset(addr string, family bgp.RouteFamily, dir api.SoftResetNeighborRequest_SoftResetDirection) error { + _, err := cli.cli.SoftResetNeighbor(context.Background(), &api.SoftResetNeighborRequest{ + Address: addr, + Direction: dir, + }) + return err +} + +func (cli *GoBGPClient) SoftResetIn(addr string, family bgp.RouteFamily) error { + return cli.softreset(addr, family, api.SoftResetNeighborRequest_IN) +} + +func (cli *GoBGPClient) SoftResetOut(addr string, family bgp.RouteFamily) error { + return cli.softreset(addr, family, api.SoftResetNeighborRequest_OUT) +} + +func (cli *GoBGPClient) SoftReset(addr string, family bgp.RouteFamily) error { + return cli.softreset(addr, family, api.SoftResetNeighborRequest_BOTH) +} + +func (cli *GoBGPClient) getRIB(resource api.Resource, name string, family bgp.RouteFamily, prefixes []*table.LookupPrefix) (*table.Table, error) { + dsts := make([]*api.Destination, 0, len(prefixes)) + for _, p := range prefixes { + longer := false + shorter := false + if p.LookupOption&table.LOOKUP_LONGER > 0 { + longer = true + } + if p.LookupOption&table.LOOKUP_SHORTER > 0 { + shorter = true + } + dsts = append(dsts, &api.Destination{ + Prefix: p.Prefix, + LongerPrefixes: longer, + ShorterPrefixes: shorter, + }) + } + res, err := cli.cli.GetRib(context.Background(), &api.GetRibRequest{ + Table: &api.Table{ + Type: resource, + Family: uint32(family), + Name: name, + Destinations: dsts, + }, + }) + if err != nil { + return nil, err + } + return res.Table.ToNativeTable() +} + +func (cli *GoBGPClient) GetRIB(family bgp.RouteFamily, prefixes []*table.LookupPrefix) (*table.Table, error) { + return cli.getRIB(api.Resource_GLOBAL, "", family, prefixes) +} + +func (cli *GoBGPClient) GetLocalRIB(name string, family bgp.RouteFamily, prefixes []*table.LookupPrefix) (*table.Table, error) { + return cli.getRIB(api.Resource_LOCAL, name, family, prefixes) +} + +func (cli *GoBGPClient) GetAdjRIBIn(name string, family bgp.RouteFamily, prefixes []*table.LookupPrefix) (*table.Table, error) { + return cli.getRIB(api.Resource_ADJ_IN, name, family, prefixes) +} + +func (cli *GoBGPClient) GetAdjRIBOut(name string, family bgp.RouteFamily, prefixes []*table.LookupPrefix) (*table.Table, error) { + return cli.getRIB(api.Resource_ADJ_OUT, name, family, prefixes) +} + +func (cli *GoBGPClient) GetVRFRIB(name string, family bgp.RouteFamily, prefixes []*table.LookupPrefix) (*table.Table, error) { + return cli.getRIB(api.Resource_VRF, name, family, prefixes) +} + +func (cli *GoBGPClient) getRIBInfo(resource api.Resource, name string, family bgp.RouteFamily) (*table.TableInfo, error) { + res, err := cli.cli.GetRibInfo(context.Background(), &api.GetRibInfoRequest{ + Info: &api.TableInfo{ + Type: resource, + Name: name, + Family: uint32(family), + }, + }) + if err != nil { + return nil, err + } + return &table.TableInfo{ + NumDestination: int(res.Info.NumDestination), + NumPath: int(res.Info.NumPath), + NumAccepted: int(res.Info.NumAccepted), + }, nil + +} + +func (cli *GoBGPClient) GetRIBInfo(family bgp.RouteFamily) (*table.TableInfo, error) { + return cli.getRIBInfo(api.Resource_GLOBAL, "", family) +} + +func (cli *GoBGPClient) GetLocalRIBInfo(name string, family bgp.RouteFamily) (*table.TableInfo, error) { + return cli.getRIBInfo(api.Resource_LOCAL, name, family) +} + +func (cli *GoBGPClient) GetAdjRIBInInfo(name string, family bgp.RouteFamily) (*table.TableInfo, error) { + return cli.getRIBInfo(api.Resource_ADJ_IN, name, family) +} + +func (cli *GoBGPClient) GetAdjRIBOutInfo(name string, family bgp.RouteFamily) (*table.TableInfo, error) { + return cli.getRIBInfo(api.Resource_ADJ_OUT, name, family) +} + +type AddPathByStreamClient struct { + stream api.GobgpApi_InjectMrtClient +} + +func (c *AddPathByStreamClient) Send(paths ...*table.Path) error { + ps := make([]*api.Path, 0, len(paths)) + for _, p := range paths { + ps = append(ps, api.ToPathApi(p)) + } + return c.stream.Send(&api.InjectMrtRequest{ + Resource: api.Resource_GLOBAL, + Paths: ps, + }) +} + +func (c *AddPathByStreamClient) Close() error { + _, err := c.stream.CloseAndRecv() + return err +} + +func (cli *GoBGPClient) AddPathByStream() (*AddPathByStreamClient, error) { + stream, err := cli.cli.InjectMrt(context.Background()) + if err != nil { + return nil, err + } + return &AddPathByStreamClient{stream}, nil +} + +func (cli *GoBGPClient) addPath(vrfID string, pathList []*table.Path) ([]byte, error) { + resource := api.Resource_GLOBAL + if vrfID != "" { + resource = api.Resource_VRF + } + var uuid []byte + for _, path := range pathList { + r, err := cli.cli.AddPath(context.Background(), &api.AddPathRequest{ + Resource: resource, + VrfId: vrfID, + Path: api.ToPathApi(path), + }) + if err != nil { + return nil, err + } + uuid = r.Uuid + } + return uuid, nil +} + +func (cli *GoBGPClient) AddPath(pathList []*table.Path) ([]byte, error) { + return cli.addPath("", pathList) +} + +func (cli *GoBGPClient) AddVRFPath(vrfID string, pathList []*table.Path) ([]byte, error) { + if vrfID == "" { + return nil, fmt.Errorf("VRF ID is empty") + } + return cli.addPath(vrfID, pathList) +} + +func (cli *GoBGPClient) deletePath(uuid []byte, f bgp.RouteFamily, vrfID string, pathList []*table.Path) error { + var reqs []*api.DeletePathRequest + + resource := api.Resource_GLOBAL + if vrfID != "" { + resource = api.Resource_VRF + } + switch { + case len(pathList) != 0: + for _, path := range pathList { + nlri := path.GetNlri() + n, err := nlri.Serialize() + if err != nil { + return err + } + p := &api.Path{ + Nlri: n, + Family: uint32(path.GetRouteFamily()), + } + reqs = append(reqs, &api.DeletePathRequest{ + Resource: resource, + VrfId: vrfID, + Path: p, + }) + } + default: + reqs = append(reqs, &api.DeletePathRequest{ + Resource: resource, + VrfId: vrfID, + Uuid: uuid, + Family: uint32(f), + }) + } + + for _, req := range reqs { + if _, err := cli.cli.DeletePath(context.Background(), req); err != nil { + return err + } + } + return nil +} + +func (cli *GoBGPClient) DeletePath(pathList []*table.Path) error { + return cli.deletePath(nil, bgp.RouteFamily(0), "", pathList) +} + +func (cli *GoBGPClient) DeleteVRFPath(vrfID string, pathList []*table.Path) error { + if vrfID == "" { + return fmt.Errorf("VRF ID is empty") + } + return cli.deletePath(nil, bgp.RouteFamily(0), vrfID, pathList) +} + +func (cli *GoBGPClient) DeletePathByUUID(uuid []byte) error { + return cli.deletePath(uuid, bgp.RouteFamily(0), "", nil) +} + +func (cli *GoBGPClient) DeletePathByFamily(family bgp.RouteFamily) error { + return cli.deletePath(nil, family, "", nil) +} + +func (cli *GoBGPClient) GetVRF() ([]*table.Vrf, error) { + ret, err := cli.cli.GetVrf(context.Background(), &api.GetVrfRequest{}) + if err != nil { + return nil, err + } + var vrfs []*table.Vrf + + 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 + } + + for _, vrf := range ret.Vrfs { + importRT, err := f(vrf.ImportRt) + if err != nil { + return nil, err + } + exportRT, err := f(vrf.ExportRt) + if err != nil { + return nil, err + } + vrfs = append(vrfs, &table.Vrf{ + Name: vrf.Name, + Id: vrf.Id, + Rd: bgp.GetRouteDistinguisher(vrf.Rd), + ImportRt: importRT, + ExportRt: exportRT, + }) + } + + return vrfs, nil +} + +func (cli *GoBGPClient) AddVRF(name string, id int, rd bgp.RouteDistinguisherInterface, im, ex []bgp.ExtendedCommunityInterface) error { + buf, err := rd.Serialize() + if err != nil { + return err + } + + f := func(comms []bgp.ExtendedCommunityInterface) ([][]byte, error) { + var bufs [][]byte + for _, c := range comms { + buf, err := c.Serialize() + if err != nil { + return nil, err + } + bufs = append(bufs, buf) + } + return bufs, err + } + + importRT, err := f(im) + if err != nil { + return err + } + exportRT, err := f(ex) + if err != nil { + return err + } + + arg := &api.AddVrfRequest{ + Vrf: &api.Vrf{ + Name: name, + Rd: buf, + Id: uint32(id), + ImportRt: importRT, + ExportRt: exportRT, + }, + } + _, err = cli.cli.AddVrf(context.Background(), arg) + return err +} + +func (cli *GoBGPClient) DeleteVRF(name string) error { + arg := &api.DeleteVrfRequest{ + Vrf: &api.Vrf{ + Name: name, + }, + } + _, err := cli.cli.DeleteVrf(context.Background(), arg) + return err +} + +func (cli *GoBGPClient) GetDefinedSet(typ table.DefinedType) ([]table.DefinedSet, error) { + ret, err := cli.cli.GetDefinedSet(context.Background(), &api.GetDefinedSetRequest{Type: api.DefinedType(typ)}) + if err != nil { + return nil, err + } + ds := make([]table.DefinedSet, 0, len(ret.Sets)) + for _, s := range ret.Sets { + d, err := api.NewDefinedSetFromApiStruct(s) + if err != nil { + return nil, err + } + ds = append(ds, d) + } + return ds, nil +} + +func (cli *GoBGPClient) AddDefinedSet(d table.DefinedSet) error { + a, err := api.NewAPIDefinedSetFromTableStruct(d) + if err != nil { + return err + } + _, err = cli.cli.AddDefinedSet(context.Background(), &api.AddDefinedSetRequest{ + Set: a, + }) + return err +} + +func (cli *GoBGPClient) DeleteDefinedSet(d table.DefinedSet, all bool) error { + a, err := api.NewAPIDefinedSetFromTableStruct(d) + if err != nil { + return err + } + _, err = cli.cli.DeleteDefinedSet(context.Background(), &api.DeleteDefinedSetRequest{ + Set: a, + All: all, + }) + return err +} + +func (cli *GoBGPClient) ReplaceDefinedSet(d table.DefinedSet) error { + a, err := api.NewAPIDefinedSetFromTableStruct(d) + if err != nil { + return err + } + _, err = cli.cli.ReplaceDefinedSet(context.Background(), &api.ReplaceDefinedSetRequest{ + Set: a, + }) + return err +} + +func (cli *GoBGPClient) GetStatement() ([]*table.Statement, error) { + ret, err := cli.cli.GetStatement(context.Background(), &api.GetStatementRequest{}) + if err != nil { + return nil, err + } + sts := make([]*table.Statement, 0, len(ret.Statements)) + for _, s := range ret.Statements { + st, err := api.NewStatementFromApiStruct(s) + if err != nil { + return nil, err + } + sts = append(sts, st) + } + return sts, nil +} + +func (cli *GoBGPClient) AddStatement(t *table.Statement) error { + a := api.NewAPIStatementFromTableStruct(t) + _, err := cli.cli.AddStatement(context.Background(), &api.AddStatementRequest{ + Statement: a, + }) + return err +} + +func (cli *GoBGPClient) DeleteStatement(t *table.Statement, all bool) error { + a := api.NewAPIStatementFromTableStruct(t) + _, err := cli.cli.DeleteStatement(context.Background(), &api.DeleteStatementRequest{ + Statement: a, + All: all, + }) + return err +} + +func (cli *GoBGPClient) ReplaceStatement(t *table.Statement) error { + a := api.NewAPIStatementFromTableStruct(t) + _, err := cli.cli.ReplaceStatement(context.Background(), &api.ReplaceStatementRequest{ + Statement: a, + }) + return err +} + +func (cli *GoBGPClient) GetPolicy() ([]*table.Policy, error) { + ret, err := cli.cli.GetPolicy(context.Background(), &api.GetPolicyRequest{}) + if err != nil { + return nil, err + } + pols := make([]*table.Policy, 0, len(ret.Policies)) + for _, p := range ret.Policies { + pol, err := api.NewPolicyFromApiStruct(p) + if err != nil { + return nil, err + } + pols = append(pols, pol) + } + return pols, nil +} + +func (cli *GoBGPClient) AddPolicy(t *table.Policy, refer bool) error { + a := api.NewAPIPolicyFromTableStruct(t) + _, err := cli.cli.AddPolicy(context.Background(), &api.AddPolicyRequest{ + Policy: a, + ReferExistingStatements: refer, + }) + return err +} + +func (cli *GoBGPClient) DeletePolicy(t *table.Policy, all, preserve bool) error { + a := api.NewAPIPolicyFromTableStruct(t) + _, err := cli.cli.DeletePolicy(context.Background(), &api.DeletePolicyRequest{ + Policy: a, + All: all, + PreserveStatements: preserve, + }) + return err +} + +func (cli *GoBGPClient) ReplacePolicy(t *table.Policy, refer, preserve bool) error { + a := api.NewAPIPolicyFromTableStruct(t) + _, err := cli.cli.ReplacePolicy(context.Background(), &api.ReplacePolicyRequest{ + Policy: a, + ReferExistingStatements: refer, + PreserveStatements: preserve, + }) + return err +} + +func (cli *GoBGPClient) getPolicyAssignment(name string, dir table.PolicyDirection) (*table.PolicyAssignment, error) { + var typ api.PolicyType + switch dir { + case table.POLICY_DIRECTION_IN: + typ = api.PolicyType_IN + case table.POLICY_DIRECTION_IMPORT: + typ = api.PolicyType_IMPORT + case table.POLICY_DIRECTION_EXPORT: + typ = api.PolicyType_EXPORT + } + resource := api.Resource_GLOBAL + if name != "" { + resource = api.Resource_LOCAL + } + + ret, err := cli.cli.GetPolicyAssignment(context.Background(), &api.GetPolicyAssignmentRequest{ + Assignment: &api.PolicyAssignment{ + Name: name, + Resource: resource, + Type: typ, + }, + }) + if err != nil { + return nil, err + } + + def := table.ROUTE_TYPE_ACCEPT + if ret.Assignment.Default == api.RouteAction_REJECT { + def = table.ROUTE_TYPE_REJECT + } + + pols := make([]*table.Policy, 0, len(ret.Assignment.Policies)) + for _, p := range ret.Assignment.Policies { + pol, err := api.NewPolicyFromApiStruct(p) + if err != nil { + return nil, err + } + pols = append(pols, pol) + } + return &table.PolicyAssignment{ + Name: name, + Type: dir, + Policies: pols, + Default: def, + }, nil +} + +func (cli *GoBGPClient) GetImportPolicy() (*table.PolicyAssignment, error) { + return cli.getPolicyAssignment("", table.POLICY_DIRECTION_IMPORT) +} + +func (cli *GoBGPClient) GetExportPolicy() (*table.PolicyAssignment, error) { + return cli.getPolicyAssignment("", table.POLICY_DIRECTION_EXPORT) +} + +func (cli *GoBGPClient) GetRouteServerInPolicy(name string) (*table.PolicyAssignment, error) { + return cli.getPolicyAssignment(name, table.POLICY_DIRECTION_IN) +} + +func (cli *GoBGPClient) GetRouteServerImportPolicy(name string) (*table.PolicyAssignment, error) { + return cli.getPolicyAssignment(name, table.POLICY_DIRECTION_IMPORT) +} + +func (cli *GoBGPClient) GetRouteServerExportPolicy(name string) (*table.PolicyAssignment, error) { + return cli.getPolicyAssignment(name, table.POLICY_DIRECTION_EXPORT) +} + +func (cli *GoBGPClient) AddPolicyAssignment(assignment *table.PolicyAssignment) error { + _, err := cli.cli.AddPolicyAssignment(context.Background(), &api.AddPolicyAssignmentRequest{ + api.NewAPIPolicyAssignmentFromTableStruct(assignment), + }) + return err +} + +func (cli *GoBGPClient) DeletePolicyAssignment(assignment *table.PolicyAssignment, all bool) error { + a := api.NewAPIPolicyAssignmentFromTableStruct(assignment) + _, err := cli.cli.DeletePolicyAssignment(context.Background(), &api.DeletePolicyAssignmentRequest{a, all}) + return err +} + +func (cli *GoBGPClient) ReplacePolicyAssignment(assignment *table.PolicyAssignment) error { + _, err := cli.cli.ReplacePolicyAssignment(context.Background(), &api.ReplacePolicyAssignmentRequest{ + api.NewAPIPolicyAssignmentFromTableStruct(assignment), + }) + return err +} + +//func (cli *GoBGPClient) EnableMrt(c *config.MrtConfig) error { +//} +// +//func (cli *GoBGPClient) DisableMrt(c *config.MrtConfig) error { +//} +// + +func (cli *GoBGPClient) GetRPKI() ([]*config.RpkiServer, error) { + rsp, err := cli.cli.GetRpki(context.Background(), &api.GetRpkiRequest{}) + if err != nil { + return nil, err + } + servers := make([]*config.RpkiServer, 0, len(rsp.Servers)) + for _, s := range rsp.Servers { + port, err := strconv.Atoi(s.Conf.RemotePort) + if err != nil { + return nil, err + } + server := &config.RpkiServer{ + Config: config.RpkiServerConfig{ + Address: s.Conf.Address, + Port: uint32(port), + }, + State: config.RpkiServerState{ + Up: s.State.Up, + SerialNumber: s.State.Serial, + RecordsV4: s.State.RecordIpv4, + RecordsV6: s.State.RecordIpv6, + PrefixesV4: s.State.PrefixIpv4, + PrefixesV6: s.State.PrefixIpv6, + Uptime: s.State.Uptime, + Downtime: s.State.Downtime, + RpkiMessages: config.RpkiMessages{ + RpkiReceived: config.RpkiReceived{ + SerialNotify: s.State.SerialNotify, + CacheReset: s.State.CacheReset, + CacheResponse: s.State.CacheResponse, + Ipv4Prefix: s.State.ReceivedIpv4, + Ipv6Prefix: s.State.ReceivedIpv6, + EndOfData: s.State.EndOfData, + Error: s.State.Error, + }, + RpkiSent: config.RpkiSent{ + SerialQuery: s.State.SerialQuery, + ResetQuery: s.State.ResetQuery, + }, + }, + }, + } + servers = append(servers, server) + } + return servers, nil +} + +func (cli *GoBGPClient) GetROA(family bgp.RouteFamily) ([]*server.ROA, error) { + rsp, err := cli.cli.GetRoa(context.Background(), &api.GetRoaRequest{ + Family: uint32(family), + }) + if err != nil { + return nil, err + } + roas := make([]*server.ROA, 0, len(rsp.Roas)) + for _, r := range rsp.Roas { + ip := net.ParseIP(r.Prefix) + if ip.To4() != nil { + ip = ip.To4() + } + afi, _ := bgp.RouteFamilyToAfiSafi(family) + roa := server.NewROA(int(afi), []byte(ip), uint8(r.Prefixlen), uint8(r.Maxlen), r.As, net.JoinHostPort(r.Conf.Address, r.Conf.RemotePort)) + roas = append(roas, roa) + } + return roas, nil +} + +func (cli *GoBGPClient) AddRPKIServer(address string, port, lifetime int) error { + _, err := cli.cli.AddRpki(context.Background(), &api.AddRpkiRequest{ + Address: address, + Port: uint32(port), + Lifetime: int64(lifetime), + }) + return err +} + +func (cli *GoBGPClient) DeleteRPKIServer(address string) error { + _, err := cli.cli.DeleteRpki(context.Background(), &api.DeleteRpkiRequest{ + Address: address, + }) + return err +} + +func (cli *GoBGPClient) EnableRPKIServer(address string) error { + _, err := cli.cli.EnableRpki(context.Background(), &api.EnableRpkiRequest{ + Address: address, + }) + return err +} + +func (cli *GoBGPClient) DisableRPKIServer(address string) error { + _, err := cli.cli.DisableRpki(context.Background(), &api.DisableRpkiRequest{ + Address: address, + }) + return err +} + +func (cli *GoBGPClient) ResetRPKIServer(address string) error { + _, err := cli.cli.ResetRpki(context.Background(), &api.ResetRpkiRequest{ + Address: address, + }) + return err +} + +func (cli *GoBGPClient) SoftResetRPKIServer(address string) error { + _, err := cli.cli.SoftResetRpki(context.Background(), &api.SoftResetRpkiRequest{ + Address: address, + }) + return err +} + +func (cli *GoBGPClient) ValidateRIBWithRPKI(prefixes ...string) error { + req := &api.ValidateRibRequest{} + if len(prefixes) > 1 { + return fmt.Errorf("too many prefixes: %d", len(prefixes)) + } else if len(prefixes) == 1 { + req.Prefix = prefixes[0] + } + _, err := cli.cli.ValidateRib(context.Background(), req) + return err +} + +func (cli *GoBGPClient) AddBMP(c *config.BmpServerConfig) error { + _, err := cli.cli.AddBmp(context.Background(), &api.AddBmpRequest{ + Address: c.Address, + Port: c.Port, + Type: api.AddBmpRequest_MonitoringPolicy(c.RouteMonitoringPolicy.ToInt()), + }) + return err +} + +func (cli *GoBGPClient) DeleteBMP(c *config.BmpServerConfig) error { + _, err := cli.cli.DeleteBmp(context.Background(), &api.DeleteBmpRequest{ + Address: c.Address, + Port: c.Port, + }) + return err +} + +type MonitorRIBClient struct { + stream api.GobgpApi_MonitorRibClient +} + +func (c *MonitorRIBClient) Recv() (*table.Destination, error) { + d, err := c.stream.Recv() + if err != nil { + return nil, err + } + return d.ToNativeDestination() +} + +func (cli *GoBGPClient) MonitorRIB(family bgp.RouteFamily) (*MonitorRIBClient, error) { + stream, err := cli.cli.MonitorRib(context.Background(), &api.Table{ + Type: api.Resource_GLOBAL, + Family: uint32(family), + }) + if err != nil { + return nil, err + } + return &MonitorRIBClient{stream}, nil +} + +func (cli *GoBGPClient) MonitorAdjRIBIn(name string, family bgp.RouteFamily) (*MonitorRIBClient, error) { + stream, err := cli.cli.MonitorRib(context.Background(), &api.Table{ + Type: api.Resource_ADJ_IN, + Name: name, + Family: uint32(family), + }) + if err != nil { + return nil, err + } + return &MonitorRIBClient{stream}, nil +} + +type MonitorNeighborStateClient struct { + stream api.GobgpApi_MonitorPeerStateClient +} + +func (c *MonitorNeighborStateClient) Recv() (*config.Neighbor, error) { + p, err := c.stream.Recv() + if err != nil { + return nil, err + } + return api.NewNeighborFromAPIStruct(p) +} + +func (cli *GoBGPClient) MonitorNeighborState(names ...string) (*MonitorNeighborStateClient, error) { + if len(names) > 1 { + return nil, fmt.Errorf("support one name at most: %d", len(names)) + } + name := "" + if len(names) > 0 { + name = names[0] + } + stream, err := cli.cli.MonitorPeerState(context.Background(), &api.Arguments{ + Name: name, + }) + if err != nil { + return nil, err + } + return &MonitorNeighborStateClient{stream}, nil +} |