Skip to content

Commit

Permalink
EBGP underlay_as enhancements (#362)
Browse files Browse the repository at this point in the history
  • Loading branch information
jbemmel authored and ipspace committed Sep 8, 2022
1 parent 79b61cf commit 9d81f03
Show file tree
Hide file tree
Showing 9 changed files with 136 additions and 15 deletions.
1 change: 0 additions & 1 deletion netsim/ansible/templates/bgp/srlinux.j2
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,4 @@ updates:
accept: {}

{% from "srlinux.macro.j2" import bgp_config with context %}
{% set _add_interfaces = bgp.update( { 'interfaces': interfaces } ) %}
{{ bgp_config('default',bgp.as,bgp.router_id,bgp,{}) }}
31 changes: 23 additions & 8 deletions netsim/ansible/templates/bgp/srlinux.macro.j2
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@
{# {{ bgp_network(af,loopback[af]) }} #}
{% endif %}

{% for l in vrf_bgp.interfaces|default([]) if l.bgp.advertise|default("") and l[af] is defined and not 'vrf' in l %}
{% for l in interfaces|default([]) if l.bgp.advertise|default("") and l[af] is defined and not 'vrf' in l %}
{# {{ bgp_network(af,l[af]) }} #}
{% endfor %}
{% for pfx in bgp.originate|default([]) if af == 'ipv4' %}
Expand Down Expand Up @@ -155,25 +155,40 @@
{% endif %}
{% elif n[af]==True and af=='ipv6' %}
{# BGP unnumbered for IPv6 LLA #}
{% set peer_group = "ebgp-unnumbered" + (('-' + n.local_as|string()) if n.local_as is defined else '') %}

- path: network-instance[name={{vrf}}]/ip-forwarding
val:
receive-ipv4-check: false
_annotate_receive-ipv4-check: "Allow IPv4 on IPv6 unnumbered interfaces"

{% set ns = namespace(l=false) %}
{% for i in vrf_bgp.interfaces|default([]) if i.ifindex == n.ifindex %}
{% set ns.l = i %}
{% endfor %}
{% if ns.l %}
{% set if_name_index = ns.l.ifname.split('.') %}
{% for i in interfaces|default([]) if i.ifindex == n.ifindex %}
{% set if_name_index = i.ifname.split('.') %}
{% set if_name = if_name_index[0] %}
{% set if_index = if_name_index[1] if if_name_index|length > 1 else '0' %}
- path: network-instance[name={{vrf}}]/protocols/bgp/dynamic-neighbors/interface[interface-name={{if_name}}.{{if_index}}]
val:
peer-group: "ebgp-unnumbered"
peer-group: "{{ peer_group }}"
allowed-peer-as: [ {{ n.as }}..{{ n.as }} ]

{% if peer_group != "ebgp-unnumbered" %}
- path: network-instance[name={{vrf}}]/protocols/bgp/group[group-name={{peer_group}}]
val:
admin-state: enable
import-policy: accept_all
export-policy: accept_all
timers:
connect-retry: 10
_annotate_connect-retry: "Reduce default 120s to 10s"
minimum-advertisement-interval: 1
local-as:
- as-number: {{ n.local_as }}
prepend-global-as: false
ipv4-unicast:
advertise-ipv6-next-hops: true
receive-ipv6-next-hops: true
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
{% endfor %}
Expand Down
11 changes: 10 additions & 1 deletion netsim/augment/links.py
Original file line number Diff line number Diff line change
Expand Up @@ -335,10 +335,15 @@ def augment_lan_link(link: Box, addr_pools: Box, ndict: dict, defaults: Box) ->
node_if['data'].neighbors = []
for remote_if in interfaces:
if remote_if['node'] != node_if['node'] or remote_if['data'].ifindex != node_if['data'].ifindex:
ngh_data = { 'ifname': remote_if['data'].ifname, 'node': remote_if['node'] }
ngh_data = Box({ 'ifname': remote_if['data'].ifname, 'node': remote_if['node'] })
for af in ('ipv4','ipv6'):
if af in remote_if['data']:
ngh_data[af] = remote_if['data'][af]

# List enabled modules that have interface level attributes; copy those attributes too
mods_with_ifattr = Box({ m : True for m in ndict[remote_if['node']].get('module',[]) if defaults[m].attributes.get('interface',None) })
ifaddr_add_module(ngh_data,remote_if['data'],mods_with_ifattr)

node_if['data'].neighbors.append(ngh_data)

if common.DEBUG: # pragma: no cover (debugging)
Expand Down Expand Up @@ -418,6 +423,10 @@ def augment_p2p_link(link: Box, addr_pools: Box, ndict: dict, defaults: Box) ->
if af in interfaces[i]:
link[end_names[i]][af] = interfaces[i][af]

# JvB: copy module specific link attributes like bgp.local_as
mods_with_ifattr = Box({ m : True for m in ndict[remote].get('module',[]) if defaults[m].attributes.get('interface',None) })
ifaddr_add_module(interfaces[i]['neighbors'][0],interfaces[1-i],mods_with_ifattr)

return link

def check_link_attributes(data: Box, nodes: dict, valid: set) -> bool:
Expand Down
13 changes: 9 additions & 4 deletions netsim/extra/ebgp-local_as.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,12 @@ def ebgp_neighbor(n: Box, asn: int, intf: Box, extra_data: dict) -> Box:
different underlay AS
"""
def build_ebgp_sessions(node: Box, topology: Box) -> None:

#
# eBGP sessions - iterate over all links, find adjacent nodes
# in different AS numbers, and create eBGP neighbors; set 'local_as'
ibgp_as = topology.bgp['as']
for l in [ l for l in node.get("interfaces",[]) if l.type == 'p2p' ]:
node_as = l.bgp.underlay_as if "bgp" in l and "underlay_as" in l.bgp else node.bgp.underlay_as
node_as = l.bgp.underlay_as if "bgp" in l and "underlay_as" in l.bgp else node.bgp.get('underlay_as',None)

for ngb_ifdata in l.get("neighbors",[]):
ngb_name = ngb_ifdata.node
Expand All @@ -80,9 +79,15 @@ def build_ebgp_sessions(node: Box, topology: Box) -> None:
extra_data.local_if = l.ifname
if common.DEBUG:
print(f'ebgp-local_as: adding neighbor for node {node.name} peer {neighbor.name} peer_as={peer_as}')
node.bgp.neighbors.append( ebgp_neighbor(neighbor,peer_as,ngb_ifdata,extra_data) )
ebgp_data = ebgp_neighbor(neighbor,peer_as,ngb_ifdata,extra_data)
if 'vrf' in l: # VRF neighbor
if not node.vrfs[l.vrf].bgp.neighbors:
node.vrfs[l.vrf].bgp.neighbors = []
node.vrfs[l.vrf].bgp.neighbors.append(ebgp_data)
else:
node.bgp.neighbors.append(ebgp_data)

def post_transform(topology: Box) -> None:
for node in topology.nodes.values():
if "bgp" in node and "underlay_as" in node.bgp:
if "bgp" in node: # and "underlay_as" in node.bgp: Can also be at link level
build_ebgp_sessions(node,topology)
82 changes: 82 additions & 0 deletions tests/integration/vlan/vlan-vrf-route-leaking.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#
# VRF lite implementation with VLAN trunks, including ebgp peering between vrfs locally
#
# * h1 and h2 should be able to ping each other, as well as h3 and h4
# * h3 and h4 should be able to ping each other, as well as h1 and h2
#
# A device has to support the following features to pass this test case:
#
# * Routed VLAN interfaces
# * VRFs
# * OSPF in VRFs
# * BGP unnumbered using ipv6 lla
#
# Please note it might take a while for the lab to work due to
# STP and OSPF setup phase
#
groups:
routers:
members: [ r1,r2,r3 ]
module: [ vlan,vrf,ospf ]
hosts:
device: linux
members: [ h1,h2,h3,h4 ]

plugin: [ ebgp-local_as ]

vrfs:
red:
blue:

vlans:
red:
mode: route
vrf: red
blue:
mode: route
vrf: blue

nodes:
r1:
r2:
module: [ vlan,vrf,ospf,bgp ]
bgp.as: 65000
r3:
h1:
h2:
h3:
h4:

links:
- r1:
r2:
vlan.trunk: [ red, blue ]
- r2:
r3:
vlan.trunk: [ red, blue ]
- interfaces: # VRF route leaking between red and blue on r2, using eBGP peering
- node: r2
vrf: red
ipv6: True
ipv4: False
bgp.underlay_as: 65001
# vlan.access: vrf-leak
- node: r2
vrf: blue
ipv6: True
ipv4: False
bgp.underlay_as: 65002
# vlan.access: vrf-leak
role: external
- h1:
r1:
vlan.access: red
- h3:
r1:
vlan.access: blue
- h2:
r3:
vlan.access: red
- h4:
r3:
vlan.access: blue
4 changes: 3 additions & 1 deletion tests/topology/expected/bgp-community.yml
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,9 @@ nodes:
linkindex: 2
name: r3 -> r2
neighbors:
- ifname: GigabitEthernet0/1
- bgp:
local_as: 65002
ifname: GigabitEthernet0/1
ipv4: 10.1.0.5/30
node: r2
ospf:
Expand Down
5 changes: 5 additions & 0 deletions tests/topology/expected/vlan-vrf-lite.yml
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ nodes:
- ifname: Ethernet2
ipv4: 172.16.2.1/24
node: r1
vrf: red
role: stub
type: lan
mgmt:
Expand Down Expand Up @@ -242,6 +243,7 @@ nodes:
- ifname: Ethernet3
ipv4: 172.16.4.2/24
node: r2
vrf: red
role: stub
type: lan
mgmt:
Expand Down Expand Up @@ -269,6 +271,7 @@ nodes:
- ifname: Ethernet3
ipv4: 172.16.3.1/24
node: r1
vrf: blue
role: stub
type: lan
mgmt:
Expand Down Expand Up @@ -296,6 +299,7 @@ nodes:
- ifname: Ethernet4
ipv4: 172.16.5.2/24
node: r2
vrf: blue
role: stub
type: lan
mgmt:
Expand All @@ -320,6 +324,7 @@ nodes:
- ifname: Ethernet4
ipv4: 10.1.0.2/30
node: r1
vrf: red
type: p2p
loopback:
ipv4: 10.0.0.8/32
Expand Down
2 changes: 2 additions & 0 deletions tests/topology/expected/vrf-igp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,7 @@ nodes:
- ifname: Ethernet2
ipv4: 10.1.0.5/30
node: pe1
vrf: red
role: external
type: p2p
loopback:
Expand Down Expand Up @@ -420,6 +421,7 @@ nodes:
- ifname: Ethernet2
ipv4: 10.1.0.9/30
node: pe2
vrf: blue
ospf:
area: 0.0.0.0
network_type: point-to-point
Expand Down
2 changes: 2 additions & 0 deletions tests/topology/expected/vrf.yml
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ nodes:
- ifname: Ethernet1
ipv4: 10.1.0.1/30
node: r1
vrf: red
role: external
type: p2p
- bgp:
Expand Down Expand Up @@ -365,6 +366,7 @@ nodes:
- ifname: Ethernet2
ipv4: 10.1.0.5/30
node: r1
vrf: blue
ospf:
area: 0.0.0.0
network_type: point-to-point
Expand Down

0 comments on commit 9d81f03

Please sign in to comment.