summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--api/grpc_server.go587
-rw-r--r--client/client.go900
-rw-r--r--config/util.go42
-rw-r--r--gobgp/cmd/neighbor.go19
-rw-r--r--table/policy.go298
-rw-r--r--test/lib/base.py6
6 files changed, 1615 insertions, 237 deletions
diff --git a/api/grpc_server.go b/api/grpc_server.go
index 3ccfa4cc..4d3da7ec 100644
--- a/api/grpc_server.go
+++ b/api/grpc_server.go
@@ -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),
- })
- }
+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: 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),
+ 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,
},
- State: &TimersState{
- KeepaliveInterval: uint64(timer.State.KeepaliveInterval),
- NegotiatedHoldTime: uint64(timer.State.NegotiatedHoldTime),
- Uptime: uint64(timer.State.Uptime),
- Downtime: uint64(timer.State.Downtime),
+ 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,
},
},
- RouteReflector: &RouteReflector{
- RouteReflectorClient: pconf.RouteReflector.Config.RouteReflectorClient,
- RouteReflectorClusterId: string(pconf.RouteReflector.Config.RouteReflectorClusterId),
+ 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),
},
- RouteServer: &RouteServer{
- RouteServerClient: pconf.RouteServer.Config.RouteServerClient,
+ 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
- }
- if a.Timers != nil && a.Timers.Config != nil {
+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
+ }
+
+ 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.RouteServer != nil {
- pconf.RouteServer.Config.RouteServerClient = a.RouteServer.RouteServerClient
+ 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.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.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.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.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.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.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.Transport != nil {
- pconf.Transport.Config.LocalAddress = a.Transport.LocalAddress
- pconf.Transport.Config.PassiveMode = a.Transport.PassiveMode
+ }
+ 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.EbgpMultihop != nil {
- pconf.EbgpMultihop.Config.Enabled = a.EbgpMultihop.Enabled
- pconf.EbgpMultihop.Config.MultihopTtl = uint8(a.EbgpMultihop.MultihopTtl)
+ }
+ 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
- }(arg.Peer)
+ }
+ 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 {
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
+}
diff --git a/config/util.go b/config/util.go
index d1696eb0..13f1fa77 100644
--- a/config/util.go
+++ b/config/util.go
@@ -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
+}
diff --git a/gobgp/cmd/neighbor.go b/gobgp/cmd/neighbor.go
index a238b562..fa6591f2 100644
--- a/gobgp/cmd/neighbor.go
+++ b/gobgp/cmd/neighbor.go
@@ -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)
}
}
diff --git a/table/policy.go b/table/policy.go
index 07b0f046..7ac8a6c3 100644
--- a/table/policy.go
+++ b/table/policy.go
@@ -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
+}
diff --git a/test/lib/base.py b/test/lib/base.py
index c37fe75d..10b50b46 100644
--- a/test/lib/base.py
+++ b/test/lib/base.py
@@ -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