mirror of
https://github.com/osrg/gobgp.git
synced 2024-05-11 05:55:10 +00:00
client: add golang client library
Signed-off-by: Wataru Ishida <[email protected]>
This commit is contained in:
+395
-202
@@ -17,13 +17,6 @@ package gobgpapi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"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"
|
||||
"io"
|
||||
"net"
|
||||
"reflect"
|
||||
@@ -32,6 +25,14 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"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 Server struct {
|
||||
@@ -87,108 +88,108 @@ func (s *Server) Serve() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) GetNeighbor(ctx context.Context, arg *GetNeighborRequest) (*GetNeighborResponse, error) {
|
||||
toApi := func(pconf *config.Neighbor) *Peer {
|
||||
prefixLimits := make([]*PrefixLimit, 0, len(pconf.AfiSafis))
|
||||
for _, family := range pconf.AfiSafis {
|
||||
if c := family.PrefixLimit.Config; c.MaxPrefixes > 0 {
|
||||
k, _ := bgp.GetRouteFamily(string(family.Config.AfiSafiName))
|
||||
prefixLimits = append(prefixLimits, &PrefixLimit{
|
||||
Family: uint32(k),
|
||||
MaxPrefixes: c.MaxPrefixes,
|
||||
ShutdownThresholdPct: uint32(c.ShutdownThresholdPct),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
timer := pconf.Timers
|
||||
s := pconf.State
|
||||
localAddress := pconf.Transport.Config.LocalAddress
|
||||
if pconf.Transport.State.LocalAddress != "" {
|
||||
localAddress = pconf.Transport.State.LocalAddress
|
||||
}
|
||||
var remoteCap, localCap [][]byte
|
||||
for _, cap := range pconf.State.RemoteCapabilityList {
|
||||
c, _ := cap.Serialize()
|
||||
remoteCap = append(remoteCap, c)
|
||||
}
|
||||
for _, cap := range pconf.State.LocalCapabilityList {
|
||||
c, _ := cap.Serialize()
|
||||
localCap = append(localCap, c)
|
||||
}
|
||||
return &Peer{
|
||||
Conf: &PeerConf{
|
||||
NeighborAddress: pconf.Config.NeighborAddress,
|
||||
Id: s.RemoteRouterId,
|
||||
PeerAs: pconf.Config.PeerAs,
|
||||
LocalAs: pconf.Config.LocalAs,
|
||||
PeerType: uint32(pconf.Config.PeerType.ToInt()),
|
||||
AuthPassword: pconf.Config.AuthPassword,
|
||||
RemovePrivateAs: uint32(pconf.Config.RemovePrivateAs.ToInt()),
|
||||
RouteFlapDamping: pconf.Config.RouteFlapDamping,
|
||||
SendCommunity: uint32(pconf.Config.SendCommunity.ToInt()),
|
||||
Description: pconf.Config.Description,
|
||||
PeerGroup: pconf.Config.PeerGroup,
|
||||
RemoteCap: remoteCap,
|
||||
LocalCap: localCap,
|
||||
PrefixLimits: prefixLimits,
|
||||
LocalAddress: localAddress,
|
||||
NeighborInterface: pconf.Config.NeighborInterface,
|
||||
Vrf: pconf.Config.Vrf,
|
||||
},
|
||||
Info: &PeerState{
|
||||
BgpState: bgp.FSMState(s.SessionState.ToInt()).String(),
|
||||
AdminState: s.AdminState,
|
||||
Messages: &Messages{
|
||||
Received: &Message{
|
||||
NOTIFICATION: s.Messages.Received.Notification,
|
||||
UPDATE: s.Messages.Received.Update,
|
||||
OPEN: s.Messages.Received.Open,
|
||||
KEEPALIVE: s.Messages.Received.Keepalive,
|
||||
REFRESH: s.Messages.Received.Refresh,
|
||||
DISCARDED: s.Messages.Received.Discarded,
|
||||
TOTAL: s.Messages.Received.Total,
|
||||
},
|
||||
Sent: &Message{
|
||||
NOTIFICATION: s.Messages.Sent.Notification,
|
||||
UPDATE: s.Messages.Sent.Update,
|
||||
OPEN: s.Messages.Sent.Open,
|
||||
KEEPALIVE: s.Messages.Sent.Keepalive,
|
||||
REFRESH: s.Messages.Sent.Refresh,
|
||||
DISCARDED: s.Messages.Sent.Discarded,
|
||||
TOTAL: s.Messages.Sent.Total,
|
||||
},
|
||||
},
|
||||
Received: s.AdjTable.Received,
|
||||
Accepted: s.AdjTable.Accepted,
|
||||
Advertised: s.AdjTable.Advertised,
|
||||
},
|
||||
Timers: &Timers{
|
||||
Config: &TimersConfig{
|
||||
ConnectRetry: uint64(timer.Config.ConnectRetry),
|
||||
HoldTime: uint64(timer.Config.HoldTime),
|
||||
KeepaliveInterval: uint64(timer.Config.KeepaliveInterval),
|
||||
},
|
||||
State: &TimersState{
|
||||
KeepaliveInterval: uint64(timer.State.KeepaliveInterval),
|
||||
NegotiatedHoldTime: uint64(timer.State.NegotiatedHoldTime),
|
||||
Uptime: uint64(timer.State.Uptime),
|
||||
Downtime: uint64(timer.State.Downtime),
|
||||
},
|
||||
},
|
||||
RouteReflector: &RouteReflector{
|
||||
RouteReflectorClient: pconf.RouteReflector.Config.RouteReflectorClient,
|
||||
RouteReflectorClusterId: string(pconf.RouteReflector.Config.RouteReflectorClusterId),
|
||||
},
|
||||
RouteServer: &RouteServer{
|
||||
RouteServerClient: pconf.RouteServer.Config.RouteServerClient,
|
||||
},
|
||||
func NewPeerFromConfigStruct(pconf *config.Neighbor) *Peer {
|
||||
prefixLimits := make([]*PrefixLimit, 0, len(pconf.AfiSafis))
|
||||
for _, family := range pconf.AfiSafis {
|
||||
if c := family.PrefixLimit.Config; c.MaxPrefixes > 0 {
|
||||
k, _ := bgp.GetRouteFamily(string(family.Config.AfiSafiName))
|
||||
prefixLimits = append(prefixLimits, &PrefixLimit{
|
||||
Family: uint32(k),
|
||||
MaxPrefixes: c.MaxPrefixes,
|
||||
ShutdownThresholdPct: uint32(c.ShutdownThresholdPct),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
timer := pconf.Timers
|
||||
s := pconf.State
|
||||
localAddress := pconf.Transport.Config.LocalAddress
|
||||
if pconf.Transport.State.LocalAddress != "" {
|
||||
localAddress = pconf.Transport.State.LocalAddress
|
||||
}
|
||||
var remoteCap, localCap [][]byte
|
||||
for _, cap := range pconf.State.RemoteCapabilityList {
|
||||
c, _ := cap.Serialize()
|
||||
remoteCap = append(remoteCap, c)
|
||||
}
|
||||
for _, cap := range pconf.State.LocalCapabilityList {
|
||||
c, _ := cap.Serialize()
|
||||
localCap = append(localCap, c)
|
||||
}
|
||||
return &Peer{
|
||||
Conf: &PeerConf{
|
||||
NeighborAddress: pconf.Config.NeighborAddress,
|
||||
Id: s.RemoteRouterId,
|
||||
PeerAs: pconf.Config.PeerAs,
|
||||
LocalAs: pconf.Config.LocalAs,
|
||||
PeerType: uint32(pconf.Config.PeerType.ToInt()),
|
||||
AuthPassword: pconf.Config.AuthPassword,
|
||||
RemovePrivateAs: uint32(pconf.Config.RemovePrivateAs.ToInt()),
|
||||
RouteFlapDamping: pconf.Config.RouteFlapDamping,
|
||||
SendCommunity: uint32(pconf.Config.SendCommunity.ToInt()),
|
||||
Description: pconf.Config.Description,
|
||||
PeerGroup: pconf.Config.PeerGroup,
|
||||
RemoteCap: remoteCap,
|
||||
LocalCap: localCap,
|
||||
PrefixLimits: prefixLimits,
|
||||
LocalAddress: localAddress,
|
||||
NeighborInterface: pconf.Config.NeighborInterface,
|
||||
Vrf: pconf.Config.Vrf,
|
||||
},
|
||||
Info: &PeerState{
|
||||
BgpState: string(s.SessionState),
|
||||
AdminState: s.AdminState,
|
||||
Messages: &Messages{
|
||||
Received: &Message{
|
||||
NOTIFICATION: s.Messages.Received.Notification,
|
||||
UPDATE: s.Messages.Received.Update,
|
||||
OPEN: s.Messages.Received.Open,
|
||||
KEEPALIVE: s.Messages.Received.Keepalive,
|
||||
REFRESH: s.Messages.Received.Refresh,
|
||||
DISCARDED: s.Messages.Received.Discarded,
|
||||
TOTAL: s.Messages.Received.Total,
|
||||
},
|
||||
Sent: &Message{
|
||||
NOTIFICATION: s.Messages.Sent.Notification,
|
||||
UPDATE: s.Messages.Sent.Update,
|
||||
OPEN: s.Messages.Sent.Open,
|
||||
KEEPALIVE: s.Messages.Sent.Keepalive,
|
||||
REFRESH: s.Messages.Sent.Refresh,
|
||||
DISCARDED: s.Messages.Sent.Discarded,
|
||||
TOTAL: s.Messages.Sent.Total,
|
||||
},
|
||||
},
|
||||
Received: s.AdjTable.Received,
|
||||
Accepted: s.AdjTable.Accepted,
|
||||
Advertised: s.AdjTable.Advertised,
|
||||
},
|
||||
Timers: &Timers{
|
||||
Config: &TimersConfig{
|
||||
ConnectRetry: uint64(timer.Config.ConnectRetry),
|
||||
HoldTime: uint64(timer.Config.HoldTime),
|
||||
KeepaliveInterval: uint64(timer.Config.KeepaliveInterval),
|
||||
},
|
||||
State: &TimersState{
|
||||
KeepaliveInterval: uint64(timer.State.KeepaliveInterval),
|
||||
NegotiatedHoldTime: uint64(timer.State.NegotiatedHoldTime),
|
||||
Uptime: uint64(timer.State.Uptime),
|
||||
Downtime: uint64(timer.State.Downtime),
|
||||
},
|
||||
},
|
||||
RouteReflector: &RouteReflector{
|
||||
RouteReflectorClient: pconf.RouteReflector.Config.RouteReflectorClient,
|
||||
RouteReflectorClusterId: string(pconf.RouteReflector.Config.RouteReflectorClusterId),
|
||||
},
|
||||
RouteServer: &RouteServer{
|
||||
RouteServerClient: pconf.RouteServer.Config.RouteServerClient,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) GetNeighbor(ctx context.Context, arg *GetNeighborRequest) (*GetNeighborResponse, error) {
|
||||
p := []*Peer{}
|
||||
for _, e := range s.bgpServer.GetNeighbor() {
|
||||
p = append(p, toApi(e))
|
||||
p = append(p, NewPeerFromConfigStruct(e))
|
||||
}
|
||||
return &GetNeighborResponse{Peers: p}, nil
|
||||
}
|
||||
@@ -205,20 +206,24 @@ func ToPathApi(path *table.Path) *Path {
|
||||
}
|
||||
return ret
|
||||
}(path.GetPathAttrs())
|
||||
return &Path{
|
||||
Nlri: n,
|
||||
Pattrs: pattrs,
|
||||
Age: path.GetTimestamp().Unix(),
|
||||
IsWithdraw: path.IsWithdraw,
|
||||
Validation: int32(path.Validation().ToInt()),
|
||||
Filtered: path.Filtered("") == table.POLICY_DIRECTION_IN,
|
||||
Family: family,
|
||||
SourceAsn: path.GetSource().AS,
|
||||
SourceId: path.GetSource().ID.String(),
|
||||
NeighborIp: path.GetSource().Address.String(),
|
||||
Stale: path.IsStale(),
|
||||
IsFromExternal: path.IsFromExternal(),
|
||||
p := &Path{
|
||||
Nlri: n,
|
||||
Pattrs: pattrs,
|
||||
Age: path.GetTimestamp().Unix(),
|
||||
IsWithdraw: path.IsWithdraw,
|
||||
Validation: int32(path.Validation().ToInt()),
|
||||
Filtered: path.Filtered("") == table.POLICY_DIRECTION_IN,
|
||||
Family: family,
|
||||
Stale: path.IsStale(),
|
||||
IsFromExternal: path.IsFromExternal(),
|
||||
NoImplicitWithdraw: path.NoImplicitWithdraw(),
|
||||
}
|
||||
if s := path.GetSource(); s != nil {
|
||||
p.SourceAsn = s.AS
|
||||
p.SourceId = s.ID.String()
|
||||
p.NeighborIp = s.Address.String()
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (s *Server) GetRib(ctx context.Context, arg *GetRibRequest) (*GetRibResponse, error) {
|
||||
@@ -776,80 +781,163 @@ func (s *Server) DeleteVrf(ctx context.Context, arg *DeleteVrfRequest) (*DeleteV
|
||||
return &DeleteVrfResponse{}, s.bgpServer.DeleteVrf(arg.Vrf.Name)
|
||||
}
|
||||
|
||||
func (s *Server) AddNeighbor(ctx context.Context, arg *AddNeighborRequest) (*AddNeighborResponse, error) {
|
||||
c, err := func(a *Peer) (*config.Neighbor, error) {
|
||||
pconf := &config.Neighbor{}
|
||||
if a.Conf != nil {
|
||||
pconf.Config.NeighborAddress = a.Conf.NeighborAddress
|
||||
pconf.Config.PeerAs = a.Conf.PeerAs
|
||||
pconf.Config.LocalAs = a.Conf.LocalAs
|
||||
pconf.Config.AuthPassword = a.Conf.AuthPassword
|
||||
pconf.Config.RemovePrivateAs = config.RemovePrivateAsOption(a.Conf.RemovePrivateAs)
|
||||
pconf.Config.RouteFlapDamping = a.Conf.RouteFlapDamping
|
||||
pconf.Config.SendCommunity = config.CommunityType(a.Conf.SendCommunity)
|
||||
pconf.Config.Description = a.Conf.Description
|
||||
pconf.Config.PeerGroup = a.Conf.PeerGroup
|
||||
pconf.Config.NeighborAddress = a.Conf.NeighborAddress
|
||||
pconf.Config.NeighborInterface = a.Conf.NeighborInterface
|
||||
pconf.Config.Vrf = a.Conf.Vrf
|
||||
func NewNeighborFromAPIStruct(a *Peer) (*config.Neighbor, error) {
|
||||
pconf := &config.Neighbor{}
|
||||
if a.Conf != nil {
|
||||
pconf.Config.NeighborAddress = a.Conf.NeighborAddress
|
||||
pconf.Config.PeerAs = a.Conf.PeerAs
|
||||
pconf.Config.LocalAs = a.Conf.LocalAs
|
||||
pconf.Config.AuthPassword = a.Conf.AuthPassword
|
||||
pconf.Config.RemovePrivateAs = config.RemovePrivateAsOption(a.Conf.RemovePrivateAs)
|
||||
pconf.Config.RouteFlapDamping = a.Conf.RouteFlapDamping
|
||||
pconf.Config.SendCommunity = config.CommunityType(a.Conf.SendCommunity)
|
||||
pconf.Config.Description = a.Conf.Description
|
||||
pconf.Config.PeerGroup = a.Conf.PeerGroup
|
||||
pconf.Config.NeighborAddress = a.Conf.NeighborAddress
|
||||
pconf.Config.NeighborInterface = a.Conf.NeighborInterface
|
||||
pconf.Config.Vrf = a.Conf.Vrf
|
||||
|
||||
f := func(bufs [][]byte) ([]bgp.ParameterCapabilityInterface, error) {
|
||||
var caps []bgp.ParameterCapabilityInterface
|
||||
for _, buf := range bufs {
|
||||
cap, err := bgp.DecodeCapability(buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
caps = append(caps, cap)
|
||||
}
|
||||
return caps, nil
|
||||
}
|
||||
if a.Timers != nil && a.Timers.Config != nil {
|
||||
|
||||
localCaps, err := f(a.Conf.LocalCap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
remoteCaps, err := f(a.Conf.RemoteCap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pconf.State.LocalCapabilityList = localCaps
|
||||
pconf.State.RemoteCapabilityList = remoteCaps
|
||||
|
||||
pconf.State.RemoteRouterId = a.Conf.Id
|
||||
|
||||
for _, f := range a.Families {
|
||||
family := bgp.RouteFamily(f)
|
||||
pconf.AfiSafis = append(pconf.AfiSafis, config.AfiSafi{
|
||||
Config: config.AfiSafiConfig{
|
||||
AfiSafiName: config.AfiSafiType(family.String()),
|
||||
Enabled: true,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
for _, pl := range a.Conf.PrefixLimits {
|
||||
for _, f := range pconf.AfiSafis {
|
||||
if f.Config.AfiSafiName == config.AfiSafiType(bgp.RouteFamily(pl.Family).String()) {
|
||||
f.PrefixLimit.Config.MaxPrefixes = pl.MaxPrefixes
|
||||
f.PrefixLimit.Config.ShutdownThresholdPct = config.Percentage(pl.ShutdownThresholdPct)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
if a.RouteReflector != nil {
|
||||
pconf.RouteReflector.Config.RouteReflectorClusterId = config.RrClusterIdType(a.RouteReflector.RouteReflectorClusterId)
|
||||
pconf.RouteReflector.Config.RouteReflectorClient = a.RouteReflector.RouteReflectorClient
|
||||
if a.Timers.State != nil {
|
||||
pconf.Timers.State.KeepaliveInterval = float64(a.Timers.State.KeepaliveInterval)
|
||||
pconf.Timers.State.NegotiatedHoldTime = float64(a.Timers.State.NegotiatedHoldTime)
|
||||
pconf.Timers.State.Uptime = int64(a.Timers.State.Uptime)
|
||||
pconf.Timers.State.Downtime = int64(a.Timers.State.Downtime)
|
||||
}
|
||||
if a.RouteServer != nil {
|
||||
pconf.RouteServer.Config.RouteServerClient = a.RouteServer.RouteServerClient
|
||||
}
|
||||
if a.ApplyPolicy != nil {
|
||||
if a.ApplyPolicy.ImportPolicy != nil {
|
||||
pconf.ApplyPolicy.Config.DefaultImportPolicy = config.DefaultPolicyType(a.ApplyPolicy.ImportPolicy.Default)
|
||||
for _, p := range a.ApplyPolicy.ImportPolicy.Policies {
|
||||
pconf.ApplyPolicy.Config.ImportPolicyList = append(pconf.ApplyPolicy.Config.ImportPolicyList, p.Name)
|
||||
}
|
||||
}
|
||||
if a.ApplyPolicy.ExportPolicy != nil {
|
||||
pconf.ApplyPolicy.Config.DefaultExportPolicy = config.DefaultPolicyType(a.ApplyPolicy.ExportPolicy.Default)
|
||||
for _, p := range a.ApplyPolicy.ExportPolicy.Policies {
|
||||
pconf.ApplyPolicy.Config.ExportPolicyList = append(pconf.ApplyPolicy.Config.ExportPolicyList, p.Name)
|
||||
}
|
||||
}
|
||||
if a.ApplyPolicy.InPolicy != nil {
|
||||
pconf.ApplyPolicy.Config.DefaultInPolicy = config.DefaultPolicyType(a.ApplyPolicy.InPolicy.Default)
|
||||
for _, p := range a.ApplyPolicy.InPolicy.Policies {
|
||||
pconf.ApplyPolicy.Config.InPolicyList = append(pconf.ApplyPolicy.Config.InPolicyList, p.Name)
|
||||
}
|
||||
}
|
||||
if a.RouteReflector != nil {
|
||||
pconf.RouteReflector.Config.RouteReflectorClusterId = config.RrClusterIdType(a.RouteReflector.RouteReflectorClusterId)
|
||||
pconf.RouteReflector.Config.RouteReflectorClient = a.RouteReflector.RouteReflectorClient
|
||||
}
|
||||
if a.RouteServer != nil {
|
||||
pconf.RouteServer.Config.RouteServerClient = a.RouteServer.RouteServerClient
|
||||
}
|
||||
if a.ApplyPolicy != nil {
|
||||
if a.ApplyPolicy.ImportPolicy != nil {
|
||||
pconf.ApplyPolicy.Config.DefaultImportPolicy = config.DefaultPolicyType(a.ApplyPolicy.ImportPolicy.Default)
|
||||
for _, p := range a.ApplyPolicy.ImportPolicy.Policies {
|
||||
pconf.ApplyPolicy.Config.ImportPolicyList = append(pconf.ApplyPolicy.Config.ImportPolicyList, p.Name)
|
||||
}
|
||||
}
|
||||
if a.Families != nil {
|
||||
for _, family := range a.Families {
|
||||
name, ok := bgp.AddressFamilyNameMap[bgp.RouteFamily(family)]
|
||||
if !ok {
|
||||
return pconf, fmt.Errorf("invalid address family: %d", family)
|
||||
}
|
||||
cAfiSafi := config.AfiSafi{
|
||||
Config: config.AfiSafiConfig{
|
||||
AfiSafiName: config.AfiSafiType(name),
|
||||
},
|
||||
}
|
||||
pconf.AfiSafis = append(pconf.AfiSafis, cAfiSafi)
|
||||
if a.ApplyPolicy.ExportPolicy != nil {
|
||||
pconf.ApplyPolicy.Config.DefaultExportPolicy = config.DefaultPolicyType(a.ApplyPolicy.ExportPolicy.Default)
|
||||
for _, p := range a.ApplyPolicy.ExportPolicy.Policies {
|
||||
pconf.ApplyPolicy.Config.ExportPolicyList = append(pconf.ApplyPolicy.Config.ExportPolicyList, p.Name)
|
||||
}
|
||||
}
|
||||
if a.Transport != nil {
|
||||
pconf.Transport.Config.LocalAddress = a.Transport.LocalAddress
|
||||
pconf.Transport.Config.PassiveMode = a.Transport.PassiveMode
|
||||
if a.ApplyPolicy.InPolicy != nil {
|
||||
pconf.ApplyPolicy.Config.DefaultInPolicy = config.DefaultPolicyType(a.ApplyPolicy.InPolicy.Default)
|
||||
for _, p := range a.ApplyPolicy.InPolicy.Policies {
|
||||
pconf.ApplyPolicy.Config.InPolicyList = append(pconf.ApplyPolicy.Config.InPolicyList, p.Name)
|
||||
}
|
||||
}
|
||||
if a.EbgpMultihop != nil {
|
||||
pconf.EbgpMultihop.Config.Enabled = a.EbgpMultihop.Enabled
|
||||
pconf.EbgpMultihop.Config.MultihopTtl = uint8(a.EbgpMultihop.MultihopTtl)
|
||||
}
|
||||
if a.Families != nil {
|
||||
for _, family := range a.Families {
|
||||
name, ok := bgp.AddressFamilyNameMap[bgp.RouteFamily(family)]
|
||||
if !ok {
|
||||
return pconf, fmt.Errorf("invalid address family: %d", family)
|
||||
}
|
||||
cAfiSafi := config.AfiSafi{
|
||||
Config: config.AfiSafiConfig{
|
||||
AfiSafiName: config.AfiSafiType(name),
|
||||
},
|
||||
}
|
||||
pconf.AfiSafis = append(pconf.AfiSafis, cAfiSafi)
|
||||
}
|
||||
return pconf, nil
|
||||
}(arg.Peer)
|
||||
}
|
||||
if a.Transport != nil {
|
||||
pconf.Transport.Config.LocalAddress = a.Transport.LocalAddress
|
||||
pconf.Transport.Config.PassiveMode = a.Transport.PassiveMode
|
||||
}
|
||||
if a.EbgpMultihop != nil {
|
||||
pconf.EbgpMultihop.Config.Enabled = a.EbgpMultihop.Enabled
|
||||
pconf.EbgpMultihop.Config.MultihopTtl = uint8(a.EbgpMultihop.MultihopTtl)
|
||||
}
|
||||
if a.Info != nil {
|
||||
pconf.State.SessionState = config.SessionState(a.Info.BgpState)
|
||||
pconf.State.AdminState = a.Info.AdminState
|
||||
|
||||
pconf.State.AdjTable.Received = a.Info.Received
|
||||
pconf.State.AdjTable.Accepted = a.Info.Accepted
|
||||
pconf.State.AdjTable.Advertised = a.Info.Advertised
|
||||
|
||||
if a.Info.Messages != nil {
|
||||
if a.Info.Messages.Sent != nil {
|
||||
pconf.State.Messages.Sent.Update = a.Info.Messages.Sent.UPDATE
|
||||
pconf.State.Messages.Sent.Notification = a.Info.Messages.Sent.NOTIFICATION
|
||||
pconf.State.Messages.Sent.Open = a.Info.Messages.Sent.OPEN
|
||||
pconf.State.Messages.Sent.Refresh = a.Info.Messages.Sent.REFRESH
|
||||
pconf.State.Messages.Sent.Keepalive = a.Info.Messages.Sent.KEEPALIVE
|
||||
pconf.State.Messages.Sent.Discarded = a.Info.Messages.Sent.DISCARDED
|
||||
pconf.State.Messages.Sent.Total = a.Info.Messages.Sent.TOTAL
|
||||
}
|
||||
if a.Info.Messages.Received != nil {
|
||||
pconf.State.Messages.Received.Update = a.Info.Messages.Received.UPDATE
|
||||
pconf.State.Messages.Received.Open = a.Info.Messages.Received.OPEN
|
||||
pconf.State.Messages.Received.Refresh = a.Info.Messages.Received.REFRESH
|
||||
pconf.State.Messages.Received.Keepalive = a.Info.Messages.Received.KEEPALIVE
|
||||
pconf.State.Messages.Received.Discarded = a.Info.Messages.Received.DISCARDED
|
||||
pconf.State.Messages.Received.Total = a.Info.Messages.Received.TOTAL
|
||||
}
|
||||
}
|
||||
}
|
||||
return pconf, nil
|
||||
}
|
||||
|
||||
func (s *Server) AddNeighbor(ctx context.Context, arg *AddNeighborRequest) (*AddNeighborResponse, error) {
|
||||
c, err := NewNeighborFromAPIStruct(arg.Peer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -880,6 +968,70 @@ func NewPrefixFromApiStruct(a *Prefix) (*table.Prefix, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func NewAPIPrefixFromConfigStruct(c config.Prefix) (*Prefix, error) {
|
||||
min, max, err := config.ParseMaskLength(c.IpPrefix, c.MasklengthRange)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Prefix{
|
||||
IpPrefix: c.IpPrefix,
|
||||
MaskLengthMin: uint32(min),
|
||||
MaskLengthMax: uint32(max),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func NewAPIDefinedSetFromTableStruct(t table.DefinedSet) (*DefinedSet, error) {
|
||||
a := &DefinedSet{
|
||||
Type: DefinedType(t.Type()),
|
||||
Name: t.Name(),
|
||||
}
|
||||
switch t.Type() {
|
||||
case table.DEFINED_TYPE_PREFIX:
|
||||
s := t.(*table.PrefixSet)
|
||||
c := s.ToConfig()
|
||||
for _, p := range c.PrefixList {
|
||||
ap, err := NewAPIPrefixFromConfigStruct(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
a.Prefixes = append(a.Prefixes, ap)
|
||||
}
|
||||
case table.DEFINED_TYPE_NEIGHBOR:
|
||||
s := t.(*table.NeighborSet)
|
||||
c := s.ToConfig()
|
||||
for _, n := range c.NeighborInfoList {
|
||||
a.List = append(a.List, n)
|
||||
}
|
||||
case table.DEFINED_TYPE_AS_PATH:
|
||||
s := t.(*table.AsPathSet)
|
||||
c := s.ToConfig()
|
||||
for _, n := range c.AsPathList {
|
||||
a.List = append(a.List, n)
|
||||
}
|
||||
case table.DEFINED_TYPE_COMMUNITY:
|
||||
s := t.(*table.CommunitySet)
|
||||
c := s.ToConfig()
|
||||
for _, n := range c.CommunityList {
|
||||
a.List = append(a.List, n)
|
||||
}
|
||||
case table.DEFINED_TYPE_EXT_COMMUNITY:
|
||||
s := t.(*table.ExtCommunitySet)
|
||||
c := s.ToConfig()
|
||||
for _, n := range c.ExtCommunityList {
|
||||
a.List = append(a.List, n)
|
||||
}
|
||||
case table.DEFINED_TYPE_LARGE_COMMUNITY:
|
||||
s := t.(*table.LargeCommunitySet)
|
||||
c := s.ToConfig()
|
||||
for _, n := range c.LargeCommunityList {
|
||||
a.List = append(a.List, n)
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid defined type")
|
||||
}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
func NewDefinedSetFromApiStruct(a *DefinedSet) (table.DefinedSet, error) {
|
||||
if a.Name == "" {
|
||||
return nil, fmt.Errorf("empty neighbor set name")
|
||||
@@ -1024,6 +1176,10 @@ func (s *Server) ReplaceDefinedSet(ctx context.Context, arg *ReplaceDefinedSetRe
|
||||
return &ReplaceDefinedSetResponse{}, s.bgpServer.ReplaceDefinedSet(set)
|
||||
}
|
||||
|
||||
func NewAPIStatementFromTableStruct(t *table.Statement) *Statement {
|
||||
return toStatementApi(t.ToConfig())
|
||||
}
|
||||
|
||||
func toStatementApi(s *config.Statement) *Statement {
|
||||
cs := &Conditions{}
|
||||
if s.Conditions.MatchPrefixSet.PrefixSet != "" {
|
||||
@@ -1076,8 +1232,7 @@ func toStatementApi(s *config.Statement) *Statement {
|
||||
RouteAction: func() RouteAction {
|
||||
if s.Actions.RouteDisposition.AcceptRoute {
|
||||
return RouteAction_ACCEPT
|
||||
}
|
||||
if s.Actions.RouteDisposition.RejectRoute {
|
||||
} else if s.Actions.RouteDisposition.RejectRoute {
|
||||
return RouteAction_REJECT
|
||||
}
|
||||
return RouteAction_NONE
|
||||
@@ -1536,6 +1691,10 @@ func (s *Server) ReplaceStatement(ctx context.Context, arg *ReplaceStatementRequ
|
||||
return &ReplaceStatementResponse{}, err
|
||||
}
|
||||
|
||||
func NewAPIPolicyFromTableStruct(p *table.Policy) *Policy {
|
||||
return toPolicyApi(p.ToConfig())
|
||||
}
|
||||
|
||||
func toPolicyApi(p *config.PolicyDefinition) *Policy {
|
||||
return &Policy{
|
||||
Name: p.Name,
|
||||
@@ -1549,6 +1708,46 @@ func toPolicyApi(p *config.PolicyDefinition) *Policy {
|
||||
}
|
||||
}
|
||||
|
||||
func NewAPIPolicyAssignmentFromTableStruct(t *table.PolicyAssignment) *PolicyAssignment {
|
||||
return &PolicyAssignment{
|
||||
Type: func() PolicyType {
|
||||
switch t.Type {
|
||||
case table.POLICY_DIRECTION_IN:
|
||||
return PolicyType_IN
|
||||
case table.POLICY_DIRECTION_IMPORT:
|
||||
return PolicyType_IMPORT
|
||||
case table.POLICY_DIRECTION_EXPORT:
|
||||
return PolicyType_EXPORT
|
||||
}
|
||||
log.Errorf("invalid policy-type: %s", t.Type)
|
||||
return PolicyType(-1)
|
||||
}(),
|
||||
Default: func() RouteAction {
|
||||
switch t.Default {
|
||||
case table.ROUTE_TYPE_ACCEPT:
|
||||
return RouteAction_ACCEPT
|
||||
case table.ROUTE_TYPE_REJECT:
|
||||
return RouteAction_REJECT
|
||||
}
|
||||
return RouteAction_NONE
|
||||
}(),
|
||||
Name: t.Name,
|
||||
Resource: func() Resource {
|
||||
if t.Name != "" {
|
||||
return Resource_LOCAL
|
||||
}
|
||||
return Resource_GLOBAL
|
||||
}(),
|
||||
Policies: func() []*Policy {
|
||||
l := make([]*Policy, 0)
|
||||
for _, p := range t.Policies {
|
||||
l = append(l, NewAPIPolicyFromTableStruct(p))
|
||||
}
|
||||
return l
|
||||
}(),
|
||||
}
|
||||
}
|
||||
|
||||
func NewPolicyFromApiStruct(a *Policy) (*table.Policy, error) {
|
||||
if a.Name == "" {
|
||||
return nil, fmt.Errorf("empty policy name")
|
||||
@@ -1635,31 +1834,25 @@ func (s *Server) GetPolicyAssignment(ctx context.Context, arg *GetPolicyAssignme
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
d, a, err := s.bgpServer.GetPolicyAssignment(name, dir)
|
||||
def, pols, err := s.bgpServer.GetPolicyAssignment(name, dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &GetPolicyAssignmentResponse{
|
||||
Assignment: &PolicyAssignment{
|
||||
Default: func() RouteAction {
|
||||
switch d {
|
||||
case table.ROUTE_TYPE_ACCEPT:
|
||||
return RouteAction_ACCEPT
|
||||
case table.ROUTE_TYPE_REJECT:
|
||||
return RouteAction_REJECT
|
||||
}
|
||||
return RouteAction_NONE
|
||||
|
||||
}(),
|
||||
Policies: func() []*Policy {
|
||||
l := make([]*Policy, 0)
|
||||
for _, p := range a {
|
||||
l = append(l, toPolicyApi(p))
|
||||
}
|
||||
return l
|
||||
}(),
|
||||
},
|
||||
}, err
|
||||
policies := make([]*table.Policy, 0, len(pols))
|
||||
for _, p := range pols {
|
||||
t, err := table.NewPolicy(*p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
policies = append(policies, t)
|
||||
}
|
||||
t := &table.PolicyAssignment{
|
||||
Name: name,
|
||||
Type: dir,
|
||||
Default: def,
|
||||
Policies: policies,
|
||||
}
|
||||
return &GetPolicyAssignmentResponse{NewAPIPolicyAssignmentFromTableStruct(t)}, err
|
||||
}
|
||||
|
||||
func defaultRouteType(d RouteAction) table.RouteType {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -17,6 +17,10 @@ package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"regexp"
|
||||
"strconv"
|
||||
|
||||
"github.com/osrg/gobgp/packet/bgp"
|
||||
)
|
||||
|
||||
@@ -82,3 +86,41 @@ func CheckAfiSafisChange(x, y []AfiSafi) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func ParseMaskLength(prefix, mask string) (int, int, error) {
|
||||
_, ipNet, err := net.ParseCIDR(prefix)
|
||||
if err != nil {
|
||||
return 0, 0, fmt.Errorf("invalid prefix: %s", prefix)
|
||||
}
|
||||
if mask == "" {
|
||||
l, _ := ipNet.Mask.Size()
|
||||
return l, l, nil
|
||||
}
|
||||
exp := regexp.MustCompile("(\\d+)\\.\\.(\\d+)")
|
||||
elems := exp.FindStringSubmatch(mask)
|
||||
if len(elems) != 3 {
|
||||
return 0, 0, fmt.Errorf("invalid mask length range: %s", mask)
|
||||
}
|
||||
// we've already checked the range is sane by regexp
|
||||
min, _ := strconv.Atoi(elems[1])
|
||||
max, _ := strconv.Atoi(elems[2])
|
||||
if min > max {
|
||||
return 0, 0, fmt.Errorf("invalid mask length range: %s", mask)
|
||||
}
|
||||
if ipv4 := ipNet.IP.To4(); ipv4 != nil {
|
||||
f := func(i int) bool {
|
||||
return i >= 0 && i <= 32
|
||||
}
|
||||
if !f(min) || !f(max) {
|
||||
return 0, 0, fmt.Errorf("ipv4 mask length range outside scope :%s", mask)
|
||||
}
|
||||
} else {
|
||||
f := func(i int) bool {
|
||||
return i >= 0 && i <= 128
|
||||
}
|
||||
if !f(min) || !f(max) {
|
||||
return 0, 0, fmt.Errorf("ipv6 mask length range outside scope :%s", mask)
|
||||
}
|
||||
}
|
||||
return min, max, nil
|
||||
}
|
||||
|
||||
+11
-8
@@ -109,7 +109,7 @@ func showNeighbors(vrf string) error {
|
||||
timeStr := "never"
|
||||
if p.Timers.State.Uptime != 0 {
|
||||
t := int64(p.Timers.State.Downtime)
|
||||
if p.Info.BgpState == "BGP_FSM_ESTABLISHED" {
|
||||
if p.Info.BgpState == string(config.SESSION_STATE_ESTABLISHED) {
|
||||
t = int64(p.Timers.State.Uptime)
|
||||
}
|
||||
timeStr = formatTimedelta(int64(now.Sub(time.Unix(int64(t), 0)).Seconds()))
|
||||
@@ -131,18 +131,21 @@ func showNeighbors(vrf string) error {
|
||||
return "Idle(PfxCt)"
|
||||
}
|
||||
|
||||
if fsm == "BGP_FSM_IDLE" {
|
||||
switch config.SessionState(fsm) {
|
||||
case config.SESSION_STATE_IDLE:
|
||||
return "Idle"
|
||||
} else if fsm == "BGP_FSM_CONNECT" {
|
||||
case config.SESSION_STATE_CONNECT:
|
||||
return "Connect"
|
||||
} else if fsm == "BGP_FSM_ACTIVE" {
|
||||
case config.SESSION_STATE_ACTIVE:
|
||||
return "Active"
|
||||
} else if fsm == "BGP_FSM_OPENSENT" {
|
||||
case config.SESSION_STATE_OPENSENT:
|
||||
return "Sent"
|
||||
} else if fsm == "BGP_FSM_OPENCONFIRM" {
|
||||
case config.SESSION_STATE_OPENCONFIRM:
|
||||
return "Confirm"
|
||||
} else {
|
||||
case config.SESSION_STATE_ESTABLISHED:
|
||||
return "Establ"
|
||||
default:
|
||||
return fsm
|
||||
}
|
||||
}
|
||||
|
||||
@@ -590,7 +593,7 @@ func showNeighborRib(r string, name string, args []string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if peer.Info.BgpState != "BGP_FSM_ESTABLISHED" {
|
||||
if peer.Info.BgpState != string(config.SESSION_STATE_ESTABLISHED) {
|
||||
return fmt.Errorf("Neighbor %v's BGP session is not established", name)
|
||||
}
|
||||
}
|
||||
|
||||
+269
-29
@@ -17,6 +17,7 @@ package table
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"reflect"
|
||||
@@ -178,6 +179,18 @@ const (
|
||||
ATTRIBUTE_LE
|
||||
)
|
||||
|
||||
func (c AttributeComparison) String() string {
|
||||
switch c {
|
||||
case ATTRIBUTE_EQ:
|
||||
return "="
|
||||
case ATTRIBUTE_GE:
|
||||
return ">="
|
||||
case ATTRIBUTE_LE:
|
||||
return "<="
|
||||
}
|
||||
return "?"
|
||||
}
|
||||
|
||||
const (
|
||||
ASPATH_REGEXP_MAGIC = "(^|[,{}() ]|$)"
|
||||
)
|
||||
@@ -188,10 +201,29 @@ type DefinedSet interface {
|
||||
Append(DefinedSet) error
|
||||
Remove(DefinedSet) error
|
||||
Replace(DefinedSet) error
|
||||
String() string
|
||||
List() []string
|
||||
}
|
||||
|
||||
type DefinedSetMap map[DefinedType]map[string]DefinedSet
|
||||
|
||||
type DefinedSetList []DefinedSet
|
||||
|
||||
func (l DefinedSetList) Len() int {
|
||||
return len(l)
|
||||
}
|
||||
|
||||
func (l DefinedSetList) Swap(i, j int) {
|
||||
l[i], l[j] = l[j], l[i]
|
||||
}
|
||||
|
||||
func (l DefinedSetList) Less(i, j int) bool {
|
||||
if l[i].Type() != l[j].Type() {
|
||||
return l[i].Type() < l[j].Type()
|
||||
}
|
||||
return l[i].Name() < l[j].Name()
|
||||
}
|
||||
|
||||
type Prefix struct {
|
||||
Prefix *net.IPNet
|
||||
AddressFamily bgp.RouteFamily
|
||||
@@ -347,6 +379,18 @@ func (lhs *PrefixSet) Replace(arg DefinedSet) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *PrefixSet) List() []string {
|
||||
var list []string
|
||||
s.tree.Walk(func(s string, v interface{}) bool {
|
||||
ps := v.([]*Prefix)
|
||||
for _, p := range ps {
|
||||
list = append(list, fmt.Sprintf("%s %d..%d", p.Prefix.String(), p.MasklengthRangeMin, p.MasklengthRangeMax))
|
||||
}
|
||||
return false
|
||||
})
|
||||
return list
|
||||
}
|
||||
|
||||
func (s *PrefixSet) ToConfig() *config.PrefixSet {
|
||||
list := make([]config.Prefix, 0, s.tree.Len())
|
||||
s.tree.Walk(func(s string, v interface{}) bool {
|
||||
@@ -362,6 +406,14 @@ func (s *PrefixSet) ToConfig() *config.PrefixSet {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *PrefixSet) String() string {
|
||||
return strings.Join(s.List(), "\n")
|
||||
}
|
||||
|
||||
func (s *PrefixSet) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(s.ToConfig())
|
||||
}
|
||||
|
||||
func NewPrefixSetFromApiStruct(name string, prefixes []*Prefix) (*PrefixSet, error) {
|
||||
if name == "" {
|
||||
return nil, fmt.Errorf("empty prefix set name")
|
||||
@@ -465,17 +517,29 @@ func (lhs *NeighborSet) Replace(arg DefinedSet) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *NeighborSet) ToConfig() *config.NeighborSet {
|
||||
func (s *NeighborSet) List() []string {
|
||||
list := make([]string, 0, len(s.list))
|
||||
for _, n := range s.list {
|
||||
list = append(list, n.String())
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func (s *NeighborSet) ToConfig() *config.NeighborSet {
|
||||
return &config.NeighborSet{
|
||||
NeighborSetName: s.name,
|
||||
NeighborInfoList: list,
|
||||
NeighborInfoList: s.List(),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *NeighborSet) String() string {
|
||||
return strings.Join(s.List(), "\n")
|
||||
}
|
||||
|
||||
func (s *NeighborSet) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(s.ToConfig())
|
||||
}
|
||||
|
||||
func NewNeighborSetFromApiStruct(name string, list []net.IP) (*NeighborSet, error) {
|
||||
return &NeighborSet{
|
||||
name: name,
|
||||
@@ -667,7 +731,7 @@ func (lhs *AsPathSet) Replace(arg DefinedSet) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *AsPathSet) ToConfig() *config.AsPathSet {
|
||||
func (s *AsPathSet) List() []string {
|
||||
list := make([]string, 0, len(s.list)+len(s.singleList))
|
||||
for _, exp := range s.singleList {
|
||||
list = append(list, exp.String())
|
||||
@@ -675,12 +739,24 @@ func (s *AsPathSet) ToConfig() *config.AsPathSet {
|
||||
for _, exp := range s.list {
|
||||
list = append(list, exp.String())
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func (s *AsPathSet) ToConfig() *config.AsPathSet {
|
||||
return &config.AsPathSet{
|
||||
AsPathSetName: s.name,
|
||||
AsPathList: list,
|
||||
AsPathList: s.List(),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *AsPathSet) String() string {
|
||||
return strings.Join(s.List(), "\n")
|
||||
}
|
||||
|
||||
func (s *AsPathSet) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(s.ToConfig())
|
||||
}
|
||||
|
||||
func NewAsPathSet(c config.AsPathSet) (*AsPathSet, error) {
|
||||
name := c.AsPathSetName
|
||||
if name == "" {
|
||||
@@ -797,17 +873,29 @@ type CommunitySet struct {
|
||||
regExpSet
|
||||
}
|
||||
|
||||
func (s *CommunitySet) ToConfig() *config.CommunitySet {
|
||||
func (s *CommunitySet) List() []string {
|
||||
list := make([]string, 0, len(s.list))
|
||||
for _, exp := range s.list {
|
||||
list = append(list, exp.String())
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func (s *CommunitySet) ToConfig() *config.CommunitySet {
|
||||
return &config.CommunitySet{
|
||||
CommunitySetName: s.name,
|
||||
CommunityList: list,
|
||||
CommunityList: s.List(),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *CommunitySet) String() string {
|
||||
return strings.Join(s.List(), "\n")
|
||||
}
|
||||
|
||||
func (s *CommunitySet) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(s.ToConfig())
|
||||
}
|
||||
|
||||
func ParseCommunity(arg string) (uint32, error) {
|
||||
i, err := strconv.ParseUint(arg, 10, 32)
|
||||
if err == nil {
|
||||
@@ -927,7 +1015,7 @@ type ExtCommunitySet struct {
|
||||
subtypeList []bgp.ExtendedCommunityAttrSubType
|
||||
}
|
||||
|
||||
func (s *ExtCommunitySet) ToConfig() *config.ExtCommunitySet {
|
||||
func (s *ExtCommunitySet) List() []string {
|
||||
list := make([]string, 0, len(s.list))
|
||||
f := func(idx int, arg string) string {
|
||||
switch s.subtypeList[idx] {
|
||||
@@ -944,12 +1032,24 @@ func (s *ExtCommunitySet) ToConfig() *config.ExtCommunitySet {
|
||||
for idx, exp := range s.list {
|
||||
list = append(list, f(idx, exp.String()))
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func (s *ExtCommunitySet) ToConfig() *config.ExtCommunitySet {
|
||||
return &config.ExtCommunitySet{
|
||||
ExtCommunitySetName: s.name,
|
||||
ExtCommunityList: list,
|
||||
ExtCommunityList: s.List(),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ExtCommunitySet) String() string {
|
||||
return strings.Join(s.List(), "\n")
|
||||
}
|
||||
|
||||
func (s *ExtCommunitySet) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(s.ToConfig())
|
||||
}
|
||||
|
||||
func NewExtCommunitySet(c config.ExtCommunitySet) (*ExtCommunitySet, error) {
|
||||
name := c.ExtCommunitySetName
|
||||
if name == "" {
|
||||
@@ -982,17 +1082,29 @@ type LargeCommunitySet struct {
|
||||
regExpSet
|
||||
}
|
||||
|
||||
func (s *LargeCommunitySet) ToConfig() *config.LargeCommunitySet {
|
||||
func (s *LargeCommunitySet) List() []string {
|
||||
list := make([]string, 0, len(s.list))
|
||||
for _, exp := range s.list {
|
||||
list = append(list, exp.String())
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func (s *LargeCommunitySet) ToConfig() *config.LargeCommunitySet {
|
||||
return &config.LargeCommunitySet{
|
||||
LargeCommunitySetName: s.name,
|
||||
LargeCommunityList: list,
|
||||
LargeCommunityList: s.List(),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *LargeCommunitySet) String() string {
|
||||
return strings.Join(s.List(), "\n")
|
||||
}
|
||||
|
||||
func (s *LargeCommunitySet) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(s.ToConfig())
|
||||
}
|
||||
|
||||
func ParseLargeCommunityRegexp(arg string) (*regexp.Regexp, error) {
|
||||
if regexp.MustCompile("\\d+:\\d+:\\d+").MatchString(arg) {
|
||||
return regexp.MustCompile(fmt.Sprintf("^%s$", arg)), nil
|
||||
@@ -1037,7 +1149,6 @@ type Condition interface {
|
||||
}
|
||||
|
||||
type PrefixCondition struct {
|
||||
name string
|
||||
set *PrefixSet
|
||||
option MatchOption
|
||||
}
|
||||
@@ -1096,7 +1207,7 @@ func (c *PrefixCondition) Evaluate(path *Path, _ *PolicyOptions) bool {
|
||||
return result
|
||||
}
|
||||
|
||||
func (c *PrefixCondition) Name() string { return c.name }
|
||||
func (c *PrefixCondition) Name() string { return c.set.name }
|
||||
|
||||
func NewPrefixCondition(c config.MatchPrefixSet) (*PrefixCondition, error) {
|
||||
if c.PrefixSet == "" {
|
||||
@@ -1107,13 +1218,14 @@ func NewPrefixCondition(c config.MatchPrefixSet) (*PrefixCondition, error) {
|
||||
return nil, err
|
||||
}
|
||||
return &PrefixCondition{
|
||||
name: c.PrefixSet,
|
||||
set: &PrefixSet{
|
||||
name: c.PrefixSet,
|
||||
},
|
||||
option: o,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type NeighborCondition struct {
|
||||
name string
|
||||
set *NeighborSet
|
||||
option MatchOption
|
||||
}
|
||||
@@ -1165,7 +1277,7 @@ func (c *NeighborCondition) Evaluate(path *Path, options *PolicyOptions) bool {
|
||||
return result
|
||||
}
|
||||
|
||||
func (c *NeighborCondition) Name() string { return c.name }
|
||||
func (c *NeighborCondition) Name() string { return c.set.name }
|
||||
|
||||
func NewNeighborCondition(c config.MatchNeighborSet) (*NeighborCondition, error) {
|
||||
if c.NeighborSet == "" {
|
||||
@@ -1176,13 +1288,14 @@ func NewNeighborCondition(c config.MatchNeighborSet) (*NeighborCondition, error)
|
||||
return nil, err
|
||||
}
|
||||
return &NeighborCondition{
|
||||
name: c.NeighborSet,
|
||||
set: &NeighborSet{
|
||||
name: c.NeighborSet,
|
||||
},
|
||||
option: o,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type AsPathCondition struct {
|
||||
name string
|
||||
set *AsPathSet
|
||||
option MatchOption
|
||||
}
|
||||
@@ -1236,7 +1349,7 @@ func (c *AsPathCondition) Evaluate(path *Path, _ *PolicyOptions) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *AsPathCondition) Name() string { return c.name }
|
||||
func (c *AsPathCondition) Name() string { return c.set.name }
|
||||
|
||||
func NewAsPathCondition(c config.MatchAsPathSet) (*AsPathCondition, error) {
|
||||
if c.AsPathSet == "" {
|
||||
@@ -1247,13 +1360,14 @@ func NewAsPathCondition(c config.MatchAsPathSet) (*AsPathCondition, error) {
|
||||
return nil, err
|
||||
}
|
||||
return &AsPathCondition{
|
||||
name: c.AsPathSet,
|
||||
set: &AsPathSet{
|
||||
name: c.AsPathSet,
|
||||
},
|
||||
option: o,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type CommunityCondition struct {
|
||||
name string
|
||||
set *CommunitySet
|
||||
option MatchOption
|
||||
}
|
||||
@@ -1294,7 +1408,7 @@ func (c *CommunityCondition) Evaluate(path *Path, _ *PolicyOptions) bool {
|
||||
return result
|
||||
}
|
||||
|
||||
func (c *CommunityCondition) Name() string { return c.name }
|
||||
func (c *CommunityCondition) Name() string { return c.set.name }
|
||||
|
||||
func NewCommunityCondition(c config.MatchCommunitySet) (*CommunityCondition, error) {
|
||||
if c.CommunitySet == "" {
|
||||
@@ -1305,13 +1419,16 @@ func NewCommunityCondition(c config.MatchCommunitySet) (*CommunityCondition, err
|
||||
return nil, err
|
||||
}
|
||||
return &CommunityCondition{
|
||||
name: c.CommunitySet,
|
||||
set: &CommunitySet{
|
||||
regExpSet: regExpSet{
|
||||
name: c.CommunitySet,
|
||||
},
|
||||
},
|
||||
option: o,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type ExtCommunityCondition struct {
|
||||
name string
|
||||
set *ExtCommunitySet
|
||||
option MatchOption
|
||||
}
|
||||
@@ -1357,7 +1474,7 @@ func (c *ExtCommunityCondition) Evaluate(path *Path, _ *PolicyOptions) bool {
|
||||
return result
|
||||
}
|
||||
|
||||
func (c *ExtCommunityCondition) Name() string { return c.name }
|
||||
func (c *ExtCommunityCondition) Name() string { return c.set.name }
|
||||
|
||||
func NewExtCommunityCondition(c config.MatchExtCommunitySet) (*ExtCommunityCondition, error) {
|
||||
if c.ExtCommunitySet == "" {
|
||||
@@ -1368,13 +1485,16 @@ func NewExtCommunityCondition(c config.MatchExtCommunitySet) (*ExtCommunityCondi
|
||||
return nil, err
|
||||
}
|
||||
return &ExtCommunityCondition{
|
||||
name: c.ExtCommunitySet,
|
||||
set: &ExtCommunitySet{
|
||||
regExpSet: regExpSet{
|
||||
name: c.ExtCommunitySet,
|
||||
},
|
||||
},
|
||||
option: o,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type LargeCommunityCondition struct {
|
||||
name string
|
||||
set *LargeCommunitySet
|
||||
option MatchOption
|
||||
}
|
||||
@@ -1415,7 +1535,7 @@ func (c *LargeCommunityCondition) Evaluate(path *Path, _ *PolicyOptions) bool {
|
||||
return result
|
||||
}
|
||||
|
||||
func (c *LargeCommunityCondition) Name() string { return c.name }
|
||||
func (c *LargeCommunityCondition) Name() string { return c.set.name }
|
||||
|
||||
func NewLargeCommunityCondition(c config.MatchLargeCommunitySet) (*LargeCommunityCondition, error) {
|
||||
if c.LargeCommunitySet == "" {
|
||||
@@ -1426,7 +1546,11 @@ func NewLargeCommunityCondition(c config.MatchLargeCommunitySet) (*LargeCommunit
|
||||
return nil, err
|
||||
}
|
||||
return &LargeCommunityCondition{
|
||||
name: c.LargeCommunitySet,
|
||||
set: &LargeCommunitySet{
|
||||
regExpSet: regExpSet{
|
||||
name: c.LargeCommunitySet,
|
||||
},
|
||||
},
|
||||
option: o,
|
||||
}, nil
|
||||
}
|
||||
@@ -1464,6 +1588,10 @@ func (c *AsPathLengthCondition) Set() DefinedSet {
|
||||
|
||||
func (c *AsPathLengthCondition) Name() string { return "" }
|
||||
|
||||
func (c *AsPathLengthCondition) String() string {
|
||||
return fmt.Sprintf("%s%d", c.operator, c.length)
|
||||
}
|
||||
|
||||
func NewAsPathLengthCondition(c config.AsPathLength) (*AsPathLengthCondition, error) {
|
||||
if c.Value == 0 && c.Operator == "" {
|
||||
return nil, nil
|
||||
@@ -1500,6 +1628,10 @@ func (c *RpkiValidationCondition) Set() DefinedSet {
|
||||
|
||||
func (c *RpkiValidationCondition) Name() string { return "" }
|
||||
|
||||
func (c *RpkiValidationCondition) String() string {
|
||||
return string(c.result)
|
||||
}
|
||||
|
||||
func NewRpkiValidationCondition(c config.RpkiValidationResultType) (*RpkiValidationCondition, error) {
|
||||
if c == config.RPKI_VALIDATION_RESULT_TYPE_NONE {
|
||||
return nil, nil
|
||||
@@ -1535,6 +1667,10 @@ func (c *RouteTypeCondition) Set() DefinedSet {
|
||||
|
||||
func (c *RouteTypeCondition) Name() string { return "" }
|
||||
|
||||
func (c *RouteTypeCondition) String() string {
|
||||
return string(c.typ)
|
||||
}
|
||||
|
||||
func NewRouteTypeCondition(c config.RouteType) (*RouteTypeCondition, error) {
|
||||
if string(c) == "" || c == config.ROUTE_TYPE_NONE {
|
||||
return nil, nil
|
||||
@@ -1550,6 +1686,7 @@ func NewRouteTypeCondition(c config.RouteType) (*RouteTypeCondition, error) {
|
||||
type Action interface {
|
||||
Type() ActionType
|
||||
Apply(*Path, *PolicyOptions) *Path
|
||||
String() string
|
||||
}
|
||||
|
||||
type RoutingAction struct {
|
||||
@@ -1567,6 +1704,14 @@ func (a *RoutingAction) Apply(path *Path, _ *PolicyOptions) *Path {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *RoutingAction) String() string {
|
||||
action := "reject"
|
||||
if a.AcceptRoute {
|
||||
action = "accept"
|
||||
}
|
||||
return action
|
||||
}
|
||||
|
||||
func NewRoutingAction(c config.RouteDisposition) (*RoutingAction, error) {
|
||||
if c.AcceptRoute == c.RejectRoute && c.AcceptRoute {
|
||||
return nil, fmt.Errorf("invalid route disposition")
|
||||
@@ -1680,6 +1825,17 @@ func (a *CommunityAction) ToConfig() *config.SetCommunity {
|
||||
}
|
||||
}
|
||||
|
||||
func (a *CommunityAction) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(a.ToConfig())
|
||||
}
|
||||
|
||||
func (a *CommunityAction) String() string {
|
||||
list := a.ToConfig().SetCommunityMethod.CommunitiesList
|
||||
exp := regexp.MustCompile("[\\^\\$]")
|
||||
l := exp.ReplaceAllString(strings.Join(list, ", "), "")
|
||||
return fmt.Sprintf("%s[%s]", a.action, l)
|
||||
}
|
||||
|
||||
func NewCommunityAction(c config.SetCommunity) (*CommunityAction, error) {
|
||||
a, ok := CommunityOptionValueMap[strings.ToLower(c.Options)]
|
||||
if !ok {
|
||||
@@ -1768,6 +1924,17 @@ func (a *ExtCommunityAction) ToConfig() *config.SetExtCommunity {
|
||||
}
|
||||
}
|
||||
|
||||
func (a *ExtCommunityAction) String() string {
|
||||
list := a.ToConfig().SetExtCommunityMethod.CommunitiesList
|
||||
exp := regexp.MustCompile("[\\^\\$]")
|
||||
l := exp.ReplaceAllString(strings.Join(list, ", "), "")
|
||||
return fmt.Sprintf("%s[%s]", a.action, l)
|
||||
}
|
||||
|
||||
func (a *ExtCommunityAction) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(a.ToConfig())
|
||||
}
|
||||
|
||||
func NewExtCommunityAction(c config.SetExtCommunity) (*ExtCommunityAction, error) {
|
||||
a, ok := CommunityOptionValueMap[strings.ToLower(c.Options)]
|
||||
if !ok {
|
||||
@@ -1846,6 +2013,17 @@ func (a *LargeCommunityAction) ToConfig() *config.SetLargeCommunity {
|
||||
}
|
||||
}
|
||||
|
||||
func (a *LargeCommunityAction) String() string {
|
||||
list := a.ToConfig().SetLargeCommunityMethod.CommunitiesList
|
||||
exp := regexp.MustCompile("[\\^\\$]")
|
||||
l := exp.ReplaceAllString(strings.Join(list, ", "), "")
|
||||
return fmt.Sprintf("%s[%s]", a.action, l)
|
||||
}
|
||||
|
||||
func (a *LargeCommunityAction) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(a.ToConfig())
|
||||
}
|
||||
|
||||
func NewLargeCommunityAction(c config.SetLargeCommunity) (*LargeCommunityAction, error) {
|
||||
a, ok := CommunityOptionValueMap[strings.ToLower(string(c.Options))]
|
||||
if !ok {
|
||||
@@ -1919,6 +2097,14 @@ func (a *MedAction) ToConfig() config.BgpSetMedType {
|
||||
return config.BgpSetMedType(fmt.Sprintf("%d", a.value))
|
||||
}
|
||||
|
||||
func (a *MedAction) String() string {
|
||||
return string(a.ToConfig())
|
||||
}
|
||||
|
||||
func (a *MedAction) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(a.ToConfig())
|
||||
}
|
||||
|
||||
func NewMedAction(c config.BgpSetMedType) (*MedAction, error) {
|
||||
if string(c) == "" {
|
||||
return nil, nil
|
||||
@@ -1961,6 +2147,14 @@ func (a *LocalPrefAction) ToConfig() uint32 {
|
||||
return a.value
|
||||
}
|
||||
|
||||
func (a *LocalPrefAction) String() string {
|
||||
return fmt.Sprintf("%d", a.value)
|
||||
}
|
||||
|
||||
func (a *LocalPrefAction) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(a.ToConfig())
|
||||
}
|
||||
|
||||
func NewLocalPrefAction(value uint32) (*LocalPrefAction, error) {
|
||||
if value == 0 {
|
||||
return nil, nil
|
||||
@@ -2020,6 +2214,15 @@ func (a *AsPathPrependAction) ToConfig() *config.SetAsPathPrepend {
|
||||
}
|
||||
}
|
||||
|
||||
func (a *AsPathPrependAction) String() string {
|
||||
c := a.ToConfig()
|
||||
return fmt.Sprintf("prepend %s %d times", c.As, c.RepeatN)
|
||||
}
|
||||
|
||||
func (a *AsPathPrependAction) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(a.ToConfig())
|
||||
}
|
||||
|
||||
// NewAsPathPrependAction creates AsPathPrependAction object.
|
||||
// If ASN cannot be parsed, nil will be returned.
|
||||
func NewAsPathPrependAction(action config.SetAsPathPrepend) (*AsPathPrependAction, error) {
|
||||
@@ -2071,8 +2274,16 @@ func (a *NexthopAction) ToConfig() config.BgpNextHopType {
|
||||
return config.BgpNextHopType(a.value.String())
|
||||
}
|
||||
|
||||
func (a *NexthopAction) String() string {
|
||||
return string(a.ToConfig())
|
||||
}
|
||||
|
||||
func (a *NexthopAction) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(a.ToConfig())
|
||||
}
|
||||
|
||||
func NewNexthopAction(c config.BgpNextHopType) (*NexthopAction, error) {
|
||||
switch string(c) {
|
||||
switch strings.ToLower(string(c)) {
|
||||
case "":
|
||||
return nil, nil
|
||||
case "self":
|
||||
@@ -2201,6 +2412,10 @@ func (s *Statement) ToConfig() *config.Statement {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Statement) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(s.ToConfig())
|
||||
}
|
||||
|
||||
type opType int
|
||||
|
||||
const (
|
||||
@@ -2483,6 +2698,10 @@ func (lhs *Policy) Replace(rhs *Policy) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Policy) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(p.ToConfig())
|
||||
}
|
||||
|
||||
func NewPolicy(c config.PolicyDefinition) (*Policy, error) {
|
||||
if c.Name == "" {
|
||||
return nil, fmt.Errorf("empty policy name")
|
||||
@@ -2508,6 +2727,20 @@ func NewPolicy(c config.PolicyDefinition) (*Policy, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
type Policies []*Policy
|
||||
|
||||
func (p Policies) Len() int {
|
||||
return len(p)
|
||||
}
|
||||
|
||||
func (p Policies) Swap(i, j int) {
|
||||
p[i], p[j] = p[j], p[i]
|
||||
}
|
||||
|
||||
func (p Policies) Less(i, j int) bool {
|
||||
return p[i].Name < p[j].Name
|
||||
}
|
||||
|
||||
type Assignment struct {
|
||||
inPolicies []*Policy
|
||||
defaultInPolicy RouteType
|
||||
@@ -3362,3 +3595,10 @@ func CanImportToVrf(v *Vrf, path *Path) bool {
|
||||
c.set = set
|
||||
return c.Evaluate(path, nil)
|
||||
}
|
||||
|
||||
type PolicyAssignment struct {
|
||||
Name string
|
||||
Type PolicyDirection
|
||||
Policies []*Policy
|
||||
Default RouteType
|
||||
}
|
||||
|
||||
+3
-3
@@ -29,9 +29,9 @@ DEFAULT_TEST_BASE_DIR = '/tmp/gobgp'
|
||||
TEST_PREFIX = DEFAULT_TEST_PREFIX
|
||||
TEST_BASE_DIR = DEFAULT_TEST_BASE_DIR
|
||||
|
||||
BGP_FSM_IDLE = 'BGP_FSM_IDLE'
|
||||
BGP_FSM_ACTIVE = 'BGP_FSM_ACTIVE'
|
||||
BGP_FSM_ESTABLISHED = 'BGP_FSM_ESTABLISHED'
|
||||
BGP_FSM_IDLE = 'idle'
|
||||
BGP_FSM_ACTIVE = 'active'
|
||||
BGP_FSM_ESTABLISHED = 'established'
|
||||
|
||||
BGP_ATTR_TYPE_ORIGIN = 1
|
||||
BGP_ATTR_TYPE_AS_PATH = 2
|
||||
|
||||
Reference in New Issue
Block a user