Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RTC: Enable to advertise Default Route Target #1716

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions config/bgp_configs.go
Original file line number Diff line number Diff line change
Expand Up @@ -3334,12 +3334,22 @@ func (lhs *LongLivedGracefulRestart) Equal(rhs *LongLivedGracefulRestart) bool {
type RouteTargetMembershipState struct {
// original -> gobgp:deferral-time
DeferralTime uint16 `mapstructure:"deferral-time" json:"deferral-time,omitempty"`
// original -> gobgp:advertise-default
// gobgp:advertise-default's original type is boolean.
// Configure whether advertise the default route target or not. This can
// be used only when the given neighbor is a route reflector client.
AdvertiseDefault bool `mapstructure:"advertise-default" json:"advertise-default,omitempty"`
}

// struct for container gobgp:config.
type RouteTargetMembershipConfig struct {
// original -> gobgp:deferral-time
DeferralTime uint16 `mapstructure:"deferral-time" json:"deferral-time,omitempty"`
// original -> gobgp:advertise-default
// gobgp:advertise-default's original type is boolean.
// Configure whether advertise the default route target or not. This can
// be used only when the given neighbor is a route reflector client.
AdvertiseDefault bool `mapstructure:"advertise-default" json:"advertise-default,omitempty"`
}

func (lhs *RouteTargetMembershipConfig) Equal(rhs *RouteTargetMembershipConfig) bool {
Expand All @@ -3349,6 +3359,9 @@ func (lhs *RouteTargetMembershipConfig) Equal(rhs *RouteTargetMembershipConfig)
if lhs.DeferralTime != rhs.DeferralTime {
return false
}
if lhs.AdvertiseDefault != rhs.AdvertiseDefault {
return false
}
return true
}

Expand Down
3 changes: 3 additions & 0 deletions config/default.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,9 @@ func setDefaultNeighborConfigValuesWithViper(v *viper.Viper, n *Neighbor, g *Glo
n.AfiSafis[i].AddPaths.Config.SendMax = n.AddPaths.Config.SendMax
}
n.AfiSafis[i].AddPaths.State.SendMax = n.AfiSafis[i].AddPaths.Config.SendMax
if !n.RouteReflector.Config.RouteReflectorClient && n.AfiSafis[i].RouteTargetMembership.Config.AdvertiseDefault {
return fmt.Errorf("advertise-default can be enabled for only route reflector client")
}
}
}

Expand Down
76 changes: 76 additions & 0 deletions server/peer.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,15 @@ func (peer *Peer) isDynamicNeighbor() bool {
return peer.fsm.pConf.Config.NeighborAddress == "" && peer.fsm.pConf.Config.NeighborInterface == ""
}

func (peer *Peer) isAdvertiseDefaultRTEnabled() bool {
for _, afiSafi := range peer.fsm.pConf.AfiSafis {
if afiSafi.State.Family == bgp.RF_RTC_UC && afiSafi.RouteTargetMembership.Config.AdvertiseDefault {
return true
}
}
return false
}

func (peer *Peer) recvedAllEOR() bool {
for _, a := range peer.fsm.pConf.AfiSafis {
if s := a.MpGracefulRestart.State; s.Enabled && !s.EndOfRibReceived {
Expand Down Expand Up @@ -321,6 +330,73 @@ func (peer *Peer) getAccepted(rfList []bgp.RouteFamily) []*table.Path {
return peer.adjRibIn.PathList(rfList, true)
}

func (peer *Peer) filterRTCPath(path, old *table.Path) *table.Path {
if path == nil || path.GetRouteFamily() != bgp.RF_RTC_UC {
return path
}

rt := path.GetNlri().(*bgp.RouteTargetMembershipNLRI).RouteTarget
isAdvDefaultRT := peer.isAdvertiseDefaultRTEnabled()
if rt != nil && isAdvDefaultRT {
// If "advertise-default" is enabled, the default route tartget is
// already advertised to this peer, then there is no other path to be
// advertised.
return nil
} else if rt == nil && !isAdvDefaultRT {
// Avoid the default route target to be advertised to the peers which
// "advertise-default" is disabled.
return nil
}

if path.IsWithdraw {
return path
}

if path.IsLocal() && path == old {
// We assumes "path" was already sent before. This assumption avoids
// the infinite UPDATE loop between a Route Reflector and its clients.
log.WithFields(log.Fields{
"Topic": "Peer",
"Key": peer.fsm.pConf.State.NeighborAddress,
"Path": path,
}).Debug("given rtm nlri is already sent, skipping to advertise")
return nil
}

if old != nil && old.IsLocal() {
// We assumes VRF with the specific RT is deleted.
return old.Clone(true)
}

if peer.isRouteReflectorClient() {
// We need to send the path even if the peer is the originator of the
// given path in order to signal that the client should distribute
// route with the given RT.
return path
}

// We send a path even if it is not the best path. See comments in
// (*Destination) GetChanges().
dst := peer.localRib.GetDestination(path)
path = nil
for _, p := range dst.GetKnownPathList(peer.TableID(), peer.AS()) {
srcPeer := p.GetSource()
if peer.ID() != srcPeer.Address.String() {
if srcPeer.RouteReflectorClient {
// The path from a RR client is preferred than others for the
// case that RR and non RR client peering (e.g., peering of
// different RR clusters).
path = p
break
} else if path == nil {
path = p
}
}
}

return path
}

func (peer *Peer) filterPathFromSourcePeer(path, old *table.Path) *table.Path {
if peer.ID() != path.GetSource().Address.String() {
return path
Expand Down
56 changes: 15 additions & 41 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -465,46 +465,8 @@ func filterpath(peer *Peer, path, old *table.Path) *table.Path {

func (s *BgpServer) filterpath(peer *Peer, path, old *table.Path) *table.Path {
// Special handling for RTM NLRI.
if path != nil && path.GetRouteFamily() == bgp.RF_RTC_UC && !path.IsWithdraw {
// If the given "path" is locally generated and the same with "old", we
// assumes "path" was already sent before. This assumption avoids the
// infinite UPDATE loop between Route Reflector and its clients.
if path.IsLocal() && path == old {
log.WithFields(log.Fields{
"Topic": "Peer",
"Key": peer.fsm.pConf.State.NeighborAddress,
"Path": path,
}).Debug("given rtm nlri is already sent, skipping to advertise")
return nil
}

if old != nil && old.IsLocal() {
// We assumes VRF with the specific RT is deleted.
path = old.Clone(true)
} else if peer.isRouteReflectorClient() {
// We need to send the path even if the peer is originator of the
// path in order to signal that the client should distribute route
// with the given RT.
} else {
// We send a path even if it is not the best path. See comments in
// (*Destination) GetChanges().
dst := peer.localRib.GetDestination(path)
path = nil
for _, p := range dst.GetKnownPathList(peer.TableID(), peer.AS()) {
srcPeer := p.GetSource()
if peer.ID() != srcPeer.Address.String() {
if srcPeer.RouteReflectorClient {
// The path from a RR client is preferred than others
// for the case that RR and non RR client peering
// (e.g., peering of different RR clusters).
path = p
break
} else if path == nil {
path = p
}
}
}
}
if path = peer.filterRTCPath(path, old); path == nil {
return nil
}

// only allow vpnv4 and vpnv6 paths to be advertised to VRFed neighbors.
Expand Down Expand Up @@ -988,7 +950,9 @@ func (server *BgpServer) propagateUpdateToNeighbors(source *Peer, newPath *table
}
family := newPath.GetRouteFamily()
for _, targetPeer := range server.neighborMap {
if (source == nil && targetPeer.isRouteServerClient()) || (source != nil && source.isRouteServerClient() != targetPeer.isRouteServerClient()) {
if (source == nil && targetPeer.isRouteServerClient()) ||
(source != nil && source.isRouteServerClient() != targetPeer.isRouteServerClient()) ||
(family == bgp.RF_RTC_UC && targetPeer.isAdvertiseDefaultRTEnabled()) {
continue
}
f := func() bgp.RouteFamily {
Expand Down Expand Up @@ -1162,6 +1126,16 @@ func (server *BgpServer) handleFSMMessage(peer *Peer, e *FsmMsg) {
}, false)
}
}
if peer.isAdvertiseDefaultRTEnabled() {
// Insert a RTC path with the default route target.
pi := &table.PeerInfo{
AS: server.bgpConfig.Global.Config.As,
LocalID: net.ParseIP(server.bgpConfig.Global.Config.RouterId).To4(),
}
path := table.NewDefaultRouteTargetPath(pi)
server.globalRib.Update(path)
sendFsmOutgoingMsg(peer, []*table.Path{path}, nil, false)
}
if !peer.fsm.pConf.GracefulRestart.State.LocalRestarting {
// When graceful-restart cap (which means intention
// of sending EOR) and route-target address family are negotiated,
Expand Down
10 changes: 10 additions & 0 deletions table/path.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,16 @@ func NewEOR(family bgp.RouteFamily) *Path {
}
}

func NewDefaultRouteTargetPath(source *PeerInfo) *Path {
nlri := bgp.NewRouteTargetMembershipNLRI(0, nil)
attrs := []bgp.PathAttributeInterface{
bgp.NewPathAttributeOrigin(bgp.BGP_ORIGIN_ATTR_TYPE_INCOMPLETE),
bgp.NewPathAttributeAsPath(nil),
bgp.NewPathAttributeMpReachNLRI("0.0.0.0", []bgp.AddrPrefixInterface{nlri}),
}
return NewPath(source, nlri, false, attrs, time.Now(), false)
}

func (path *Path) IsEOR() bool {
if path.info != nil && path.info.eor {
return true
Expand Down
12 changes: 8 additions & 4 deletions table/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ import (
"unsafe"

"github.com/armon/go-radix"
"github.com/osrg/gobgp/packet/bgp"
log "github.com/sirupsen/logrus"

"github.com/osrg/gobgp/packet/bgp"
)

type LookupOption uint8
Expand Down Expand Up @@ -103,9 +104,12 @@ func (t *Table) deleteRTCPathsByVrf(vrf *Vrf, vrfs map[string]*Vrf) []*Path {
for _, target := range vrf.ImportRt {
lhs := target.String()
for _, dest := range t.destinations {
nlri := dest.GetNlri().(*bgp.RouteTargetMembershipNLRI)
rhs := nlri.RouteTarget.String()
if lhs == rhs && isLastTargetUser(vrfs, target) {
rhs := dest.GetNlri().(*bgp.RouteTargetMembershipNLRI).RouteTarget
if rhs == nil {
// Ignores the default route target.
continue
}
if lhs == rhs.String() && isLastTargetUser(vrfs, target) {
for _, p := range dest.knownPathList {
if p.IsLocal() {
pathList = append(pathList, p.Clone(true))
Expand Down
6 changes: 4 additions & 2 deletions test/lib/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,8 @@ def add_peer(self, peer, passwd=None, vpn=False, is_rs_client=False,
graceful_restart=None, local_as=None, prefix_limit=None,
v6=False, llgr=None, vrf='', interface='', allow_as_in=0,
remove_private_as=None, replace_peer_as=False, addpath=False,
treat_as_withdraw=False, remote_as=None):
treat_as_withdraw=False, remote_as=None,
advertise_default_rt=False):
neigh_addr = ''
local_addr = ''
it = itertools.product(self.ip_addrs, peer.ip_addrs)
Expand Down Expand Up @@ -431,7 +432,8 @@ def add_peer(self, peer, passwd=None, vpn=False, is_rs_client=False,
'replace_peer_as': replace_peer_as,
'addpath': addpath,
'treat_as_withdraw': treat_as_withdraw,
'remote_as': remote_as or peer.asn}
'remote_as': remote_as or peer.asn,
'advertise_default_rt': advertise_default_rt}
if self.is_running and reload_config:
self.create_config()
self.reload_config()
Expand Down
10 changes: 9 additions & 1 deletion test/lib/gobgp.py
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,15 @@ def _create_config_bgp(self):
afi_safi_list.append({'config': {'afi-safi-name': 'l3vpn-ipv4-unicast'}})
afi_safi_list.append({'config': {'afi-safi-name': 'l3vpn-ipv6-unicast'}})
afi_safi_list.append({'config': {'afi-safi-name': 'l2vpn-evpn'}})
afi_safi_list.append({'config': {'afi-safi-name': 'rtc'}, 'route-target-membership': {'config': {'deferral-time': 10}}})
if info['is_rr_client'] and info['advertise_default_rt']:
afi_safi_list.append(
{'config': {'afi-safi-name': 'rtc'},
'route-target-membership': {'config': {'deferral-time': 10,
'advertise-default': True}}})
else:
afi_safi_list.append(
{'config': {'afi-safi-name': 'rtc'},
'route-target-membership': {'config': {'deferral-time': 10}}})

if info['flowspec']:
afi_safi_list.append({'config': {'afi-safi-name': 'ipv4-flowspec'}})
Expand Down
Loading