Skip to content

Commit

Permalink
Add EOR type to Table's filter on Watch method
Browse files Browse the repository at this point in the history
New EOR filter provides opprtunity to watch eor messages from
different peers for any route family.

CLOUD-118121
  • Loading branch information
bayrinat committed Dec 21, 2022
1 parent f0b3ed1 commit 2e034b4
Show file tree
Hide file tree
Showing 6 changed files with 1,938 additions and 1,703 deletions.
3,402 changes: 1,703 additions & 1,699 deletions api/gobgp.pb.go

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion api/gobgp.proto
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ message WatchEventRequest {

message Table {
message Filter {
enum Type { BEST = 0; ADJIN = 1; POST_POLICY = 2; }
enum Type { BEST = 0; ADJIN = 1; POST_POLICY = 2; EOR = 3; }
Type type = 1;
bool init = 2;
}
Expand Down
21 changes: 20 additions & 1 deletion internal/pkg/table/path.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,12 +168,25 @@ func NewPath(source *PeerInfo, nlri bgp.AddrPrefixInterface, isWithdraw bool, pa
func NewEOR(family bgp.RouteFamily) *Path {
afi, safi := bgp.RouteFamilyToAfiSafi(family)
nlri, _ := bgp.NewPrefixFromRouteFamily(afi, safi)
return &Path{
p := &Path{
info: &originInfo{
nlri: nlri,
eor: true,
},
}
// Add attributes to eor path according RFC.
//
// RFC 4724 2. Marker for End-of-RIB
// For the IPv4 unicast address family, the End-of-RIB
// marker is an UPDATE message with the minimum length [BGP-4]. For any
// other address family, it is an UPDATE message that contains only the
// MP_UNREACH_NLRI attribute.
if family != bgp.RF_IPv4_UC {
p.pathAttrs = []bgp.PathAttributeInterface{
bgp.NewPathAttributeMpUnreachNLRI([]bgp.AddrPrefixInterface{nlri}),
}
}
return p
}

func (path *Path) IsEOR() bool {
Expand Down Expand Up @@ -1246,6 +1259,12 @@ func (p *Path) GetHash() uint32 {
return p.attrsHash
}

func (p *Path) SetSource(peerInfo *PeerInfo) {
if p.info != nil {
p.info.source = peerInfo
}
}

func nlriToIPNet(nlri bgp.AddrPrefixInterface) *net.IPNet {
switch T := nlri.(type) {
case *bgp.IPAddrPrefix:
Expand Down
12 changes: 10 additions & 2 deletions pkg/packet/bgp/bgp.go
Original file line number Diff line number Diff line change
Expand Up @@ -1973,11 +1973,19 @@ func (l *LabeledVPNIPAddrPrefix) SAFI() uint8 {
}

func (l *LabeledVPNIPAddrPrefix) IPPrefixLen() uint8 {
return l.Length - 8*uint8(l.Labels.Len()+l.RD.Len())
rdLen := 0
if l.RD != nil {
rdLen = l.RD.Len()
}
return l.Length - 8*uint8(l.Labels.Len()+rdLen)
}

func (l *LabeledVPNIPAddrPrefix) Len(options ...*MarshallingOption) int {
return 1 + l.Labels.Len() + l.RD.Len() + int((l.IPPrefixLen()+7)/8)
rdLen := 0
if l.RD != nil {
rdLen = l.RD.Len()
}
return 1 + l.Labels.Len() + rdLen + int((l.IPPrefixLen()+7)/8)
}

func (l *LabeledVPNIPAddrPrefix) String() string {
Expand Down
129 changes: 129 additions & 0 deletions pkg/server/grpc_server_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
package server

import (
"net"
"testing"
"time"

api "github.com/osrg/gobgp/v3/api"
"github.com/osrg/gobgp/v3/internal/pkg/table"
"github.com/osrg/gobgp/v3/pkg/apiutil"
"github.com/osrg/gobgp/v3/pkg/packet/bgp"
"github.com/stretchr/testify/assert"
"google.golang.org/protobuf/types/known/anypb"
)

func TestParseHost(t *testing.T) {
Expand Down Expand Up @@ -41,3 +48,125 @@ func TestParseHost(t *testing.T) {
})
}
}

func TestToPathApi(t *testing.T) {
type args struct {
path *table.Path
v *table.Validation
onlyBinary bool
nlriBinary bool
attributeBinary bool
}
tests := []struct {
name string
args args
want *api.Path
}{
{
name: "ipv4 path",
args: args{
path: table.NewPath(&table.PeerInfo{
ID: net.IP{10, 10, 10, 10},
LocalID: net.IP{10, 11, 11, 11},
Address: net.IP{10, 12, 12, 12},
LocalAddress: net.IP{10, 13, 13, 13},
},
bgp.NewIPAddrPrefix(8, "10.0.0.0"),
false,
[]bgp.PathAttributeInterface{bgp.NewPathAttributeOrigin(0)},
time.Time{},
false),
},
want: &api.Path{
Nlri: anyNlri(bgp.NewIPAddrPrefix(8, "10.0.0.0")),
Pattrs: anyAttrs([]bgp.PathAttributeInterface{bgp.NewPathAttributeOrigin(0)}),
Family: &api.Family{
Afi: api.Family_AFI_IP,
Safi: api.Family_SAFI_UNICAST,
},
Validation: &api.Validation{},
NeighborIp: "10.12.12.12",
SourceId: "10.10.10.10",
},
},
{
name: "eor ipv4 path",
args: args{
path: eor(bgp.RF_IPv4_UC),
},
want: &api.Path{
Nlri: anyEorNlri(bgp.AFI_IP, bgp.SAFI_UNICAST),
Family: &api.Family{
Afi: api.Family_AFI_IP,
Safi: api.Family_SAFI_UNICAST,
},
Pattrs: []*anypb.Any{},
Validation: &api.Validation{},
NeighborIp: "10.12.12.12",
SourceId: "10.10.10.10",
},
},
{
name: "eor vpn path",
args: args{
path: eor(bgp.RF_IPv4_VPN),
},
want: &api.Path{
Nlri: anyEorNlri(bgp.AFI_IP, bgp.SAFI_MPLS_VPN),
Family: &api.Family{
Afi: api.Family_AFI_IP,
Safi: api.Family_SAFI_MPLS_VPN,
},
Pattrs: anyAttrs(
[]bgp.PathAttributeInterface{
bgp.NewPathAttributeMpUnreachNLRI([]bgp.AddrPrefixInterface{
nlri(bgp.AFI_IP, bgp.SAFI_MPLS_VPN),
}),
}),
Validation: &api.Validation{},
NeighborIp: "10.12.12.12",
SourceId: "10.10.10.10",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
apiPath := toPathApi(tt.args.path, tt.args.v, tt.args.onlyBinary, tt.args.nlriBinary, tt.args.attributeBinary)
assert.Equal(t, tt.want.Nlri, apiPath.Nlri, "not equal nlri")
assert.Equal(t, tt.want.Pattrs, apiPath.Pattrs, "not equal attrs")
assert.Equal(t, tt.want.Family, apiPath.Family, "not equal family")
assert.Equal(t, tt.want.NeighborIp, apiPath.NeighborIp, "not equal neighbor")
})
}
}

func eor(f bgp.RouteFamily) *table.Path {
p := table.NewEOR(f)
p.SetSource(&table.PeerInfo{
ID: net.IP{10, 10, 10, 10},
LocalID: net.IP{10, 11, 11, 11},
Address: net.IP{10, 12, 12, 12},
LocalAddress: net.IP{10, 13, 13, 13},
})
return p
}

func anyEorNlri(afi uint16, safi uint8) *anypb.Any {
n, _ := bgp.NewPrefixFromRouteFamily(afi, safi)
return anyNlri(n)
}

func anyNlri(nlri bgp.AddrPrefixInterface) *anypb.Any {
anyNlri, _ := apiutil.MarshalNLRI(nlri)
return anyNlri
}

func anyAttrs(attrs []bgp.PathAttributeInterface) []*anypb.Any {
anyPattrs, _ := apiutil.MarshalPathAttributes(attrs)
return anyPattrs
}

func nlri(afi uint16, safi uint8) bgp.AddrPrefixInterface {
n, _ := bgp.NewPrefixFromRouteFamily(afi, safi)
return n
}
75 changes: 75 additions & 0 deletions pkg/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -1667,6 +1667,21 @@ func (s *BgpServer) handleFSMMessage(peer *peer, e *fsmMsg) {
if f == bgp.RF_RTC_UC {
rtc = true
}
peer.fsm.lock.RLock()
peerInfo := &table.PeerInfo{
AS: peer.fsm.peerInfo.AS,
ID: peer.fsm.peerInfo.ID,
LocalAS: peer.fsm.peerInfo.LocalAS,
LocalID: peer.fsm.peerInfo.LocalID,
Address: peer.fsm.peerInfo.Address,
LocalAddress: peer.fsm.peerInfo.LocalAddress,
}
peer.fsm.lock.RUnlock()
ev := &watchEventEor{
Family: f,
PeerInfo: peerInfo,
}
s.notifyWatcher(watchEventTypeEor, ev)
for i, a := range peerAfiSafis {
if a.State.Family == f {
peer.fsm.lock.Lock()
Expand Down Expand Up @@ -4015,6 +4030,8 @@ func (s *BgpServer) WatchEvent(ctx context.Context, r *api.WatchEventRequest, fn
opts = append(opts, watchUpdate(filter.Init, ""))
case api.WatchEventRequest_Table_Filter_POST_POLICY:
opts = append(opts, watchPostUpdate(filter.Init, ""))
case api.WatchEventRequest_Table_Filter_EOR:
opts = append(opts, watchEor(filter.Init))
}
}
}
Expand Down Expand Up @@ -4067,6 +4084,19 @@ func (s *BgpServer) WatchEvent(ctx context.Context, r *api.WatchEventRequest, fn
},
},
})
case *watchEventEor:
eor := table.NewEOR(msg.Family)
eor.SetSource(msg.PeerInfo)
path := toPathApi(eor, nil, false, false, false)

fn(&api.WatchEventResponse{
Event: &api.WatchEventResponse_Table{
Table: &api.WatchEventResponse_TableEvent{
Paths: []*api.Path{path},
},
},
})

case *watchEventPeer:
fn(&api.WatchEventResponse{
Event: &api.WatchEventResponse_Peer{
Expand Down Expand Up @@ -4137,6 +4167,7 @@ const (
watchEventTypePeerState watchEventType = "peerstate"
watchEventTypeTable watchEventType = "table"
watchEventTypeRecvMsg watchEventType = "receivedmessage"
watchEventTypeEor watchEventType = "eor"
)

type watchEvent interface {
Expand Down Expand Up @@ -4214,6 +4245,11 @@ type watchEventMessage struct {
IsSent bool
}

type watchEventEor struct {
Family bgp.RouteFamily
PeerInfo *table.PeerInfo
}

type watchOptions struct {
bestpath bool
preUpdate bool
Expand All @@ -4225,6 +4261,8 @@ type watchOptions struct {
tableName string
recvMessage bool
peerAddress string
initEor bool
eor bool
}

type watchOption func(*watchOptions)
Expand Down Expand Up @@ -4258,6 +4296,15 @@ func watchPostUpdate(current bool, peerAddress string) watchOption {
}
}

func watchEor(current bool) watchOption {
return func(o *watchOptions) {
o.eor = true
if current {
o.initEor = true
}
}
}

func watchPeer() watchOption {
return func(o *watchOptions) {
o.peerState = true
Expand Down Expand Up @@ -4412,6 +4459,9 @@ func (s *BgpServer) watch(opts ...watchOption) (w *watcher) {
if w.opts.postUpdate {
register(watchEventTypePostUpdate, w)
}
if w.opts.eor {
register(watchEventTypeEor, w)
}
if w.opts.peerState {
for _, p := range s.neighborMap {
w.notify(newWatchEventPeer(p, nil, p.fsm.state, PEER_EVENT_INIT))
Expand All @@ -4427,6 +4477,31 @@ func (s *BgpServer) watch(opts ...watchOption) (w *watcher) {
MultiPathList: s.globalRib.GetBestMultiPathList(table.GLOBAL_RIB_NAME, nil),
})
}
if w.opts.initEor && s.active() == nil {
for _, p := range s.neighborMap {
func() {
p.fsm.lock.RLock()
defer p.fsm.lock.RUnlock()
for _, a := range p.fsm.pConf.AfiSafis {
if s := a.MpGracefulRestart.State; s.Enabled && s.EndOfRibReceived {
family := a.State.Family
peerInfo := &table.PeerInfo{
AS: p.fsm.peerInfo.AS,
ID: p.fsm.peerInfo.ID,
LocalAS: p.fsm.peerInfo.LocalAS,
LocalID: p.fsm.peerInfo.LocalID,
Address: p.fsm.peerInfo.Address,
LocalAddress: p.fsm.peerInfo.LocalAddress,
}
w.notify(&watchEventEor{
Family: family,
PeerInfo: peerInfo,
})
}
}
}()
}
}
if w.opts.initUpdate {
for _, peer := range s.neighborMap {
peer.fsm.lock.RLock()
Expand Down

0 comments on commit 2e034b4

Please sign in to comment.