-
Notifications
You must be signed in to change notification settings - Fork 105
Bird: add bgp/evpn support with vxlan and anycast gateway #3475
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
base: dev
Are you sure you want to change the base?
Changes from 18 commits
1bf6d25
17853b7
c855257
c62264e
209eb66
ce10613
f5345c2
c0b88e7
991a9b4
e1dff3a
e68e756
ebe51df
621c9f0
e3db717
9ca1373
62ba689
584641a
fe39d5b
ea25b48
7c1ac05
10502ae
ff02050
0706caf
d71130d
3f711e8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| #!/bin/sh | ||
| # | ||
| # Initial configuration for BIRD containers (docker exec / sh mode). | ||
| # Do not use the -clab suffix here: that convention is for netns execution on the host. | ||
| # | ||
| set -x | ||
| set -e | ||
| {% if 'vxlan' in module|default([]) %} | ||
|
jbemmel marked this conversation as resolved.
Outdated
|
||
| # | ||
| # containerlab interfaces might not be ready when netlab initial executes this | ||
| # script via docker exec | ||
| # | ||
| waited=0 | ||
| while [ "$waited" -lt "${NETLAB_INTERFACE_WAIT:-30}" ]; do | ||
| if [ -d /sys/class/net/eth1 ]; then | ||
| break | ||
| fi | ||
| sleep 1 | ||
| waited=$((waited + 1)) | ||
| done | ||
| if [ ! -d /sys/class/net/eth1 ]; then | ||
| echo "Timeout waiting for containerlab interfaces (eth1)" >&2 | ||
| exit 1 | ||
| fi | ||
| {% endif %} | ||
| {% include 'linux/vanilla.j2' +%} | ||
| # | ||
| {% if loopback.ipv6 is defined %} | ||
| set +e | ||
| ip addr add fe80::1/64 dev lo scope link | ||
| {% endif %} | ||
| exit 0 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,11 +1,14 @@ | ||
| --- | ||
| description: BIRD Internet Routing Daemon | ||
| parent: linux | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why exactly do you need this?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 'linux' is the implicit default so it's not strictly needed
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
So why did you add it? |
||
| role: router | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And why have you changed the default role?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See #3499 as to what triggered it - I agree it would be better to fix that specific test It could make sense that a "Routing Daemon" would have a default "router" role - but we can leave it out
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Although it's not defined (precisely) anywhere in the documentation, the daemon devices were designed to provide control-plane-only functionality (for example, BGP RR). That's also the most common BIRD use case (IXP BGP route server)
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
ok, so in my mind that is a "router" role more than a "host" role. Looking at the codebase, I now realize that Linux daemons are explicitly exempted from requiring a loopback interface - is that the more common way BIRD gets deployed? |
||
| group_vars: | ||
| netlab_import_map: | ||
| bgp: RTS_BGP | ||
| ospf: RTS_OSPF | ||
| connected: RTS_DEVICE | ||
| static: RTS_STATIC_DEVICE,RTS_STATIC | ||
| netlab_initial: always | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Isn't this relevant only with configuration reload?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I initially modeled the Bird config after |
||
| packages: | ||
| bird: bird | ||
| daemon_config: | ||
|
|
@@ -16,12 +19,16 @@ daemon_config: | |
| bgp@policy: /etc/bird/bgp.policy.conf | ||
| ospf@areas: /etc/bird/ospf.areas.conf | ||
| ospf: /etc/bird/ospf.mod.conf | ||
| vxlan: /etc/bird/vxlan.mod.conf | ||
| evpn: /etc/bird/evpn.mod.conf | ||
| routing: /etc/bird/routing.mod.conf | ||
| clab: | ||
| node_config: null # Do not inherit linux :ns scripts; use netlab_config_mode: sh | ||
|
jbemmel marked this conversation as resolved.
Outdated
|
||
| group_vars: | ||
| netlab_show_command: [ birdc, 'show $@' ] | ||
| docker_shell: bash -il | ||
| netlab_config_mode: sh | ||
| netlab_config_done: /var/run/netlab-config-done | ||
| image: netlab/bird:latest | ||
| build: True | ||
| sw_version: 2.19.1 | ||
|
|
@@ -69,6 +76,15 @@ features: | |
| areas: true | ||
| routing: | ||
| static.discard: true | ||
| evpn: | ||
| transport: [ vxlan ] | ||
| vxlan: | ||
| vtep6: true | ||
| vlan: | ||
| model: router | ||
| svi_interface_name: vlan{vlan} | ||
| gateway: | ||
| protocol: [ anycast ] | ||
| dhcp: false | ||
| initial: | ||
| ipv4: | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,5 @@ | ||
| {% set module = module|default([]) %} | ||
| log "/var/log/bird" all; | ||
| log stderr all; | ||
|
|
||
| {% include 'protocols.j2' %} | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| {% macro bird_ec(rt) %}(rt, {{ rt.split(':')[0] }}, {{ rt.split(':')[1] }}){% endmacro %} | ||
|
|
||
| {% if vxlan is defined and vxlan.flooding|default('') == 'evpn' %} | ||
| {% for vname in vxlan.vlans|default([]) if vlans[vname].vni is defined and 'evpn' in vlans[vname] %} | ||
| {% set vlan = vlans[vname] %} | ||
| protocol bridge bridge_{{ vname }} { | ||
| eth { table eth_{{ vname }}; export all; }; | ||
| bridge device "vlan{{ vlan.id }}"; | ||
| }; | ||
|
|
||
| protocol evpn evpn_{{ vname }} { | ||
| eth { table eth_{{ vname }}; }; | ||
| evpn { table evpntab; import all; export all; }; | ||
| rd {{ vlan.evpn.rd }}; | ||
| {% for rt in vlan.evpn.import|default([]) %} | ||
| import target {{ bird_ec(rt) }}; | ||
| {% endfor %} | ||
| {% for rt in vlan.evpn.export|default([]) %} | ||
| export target {{ bird_ec(rt) }}; | ||
| {% endfor %} | ||
| vni {{ vlan.vni }}; | ||
| vid {{ vlan.id }}; | ||
| encapsulation vxlan { | ||
| tunnel device "vxlan{{ vlan.vni }}"; | ||
| router address {{ vxlan.vtep }}; | ||
| }; | ||
| }; | ||
| {% endfor %} | ||
| {% endif %} | ||
|
|
||
| {% for vname,vdata in vrfs|default({})|dictsort %} | ||
| {% if 'evpn' in vdata and vdata.evpn.transit_vni is defined %} | ||
| eth table eth_vrf_{{ vname }}; | ||
|
|
||
| protocol evpn evpn_vrf_{{ vname }} { | ||
| eth { table eth_vrf_{{ vname }}; }; | ||
| evpn { table evpntab; import all; export all; }; | ||
| rd {{ vdata.rd }}; | ||
| {% for rt in vdata.import|default([]) %} | ||
| import target {{ bird_ec(rt) }}; | ||
| {% endfor %} | ||
| {% for rt in vdata.export|default([]) %} | ||
| export target {{ bird_ec(rt) }}; | ||
| {% endfor %} | ||
| vni {{ vdata.evpn.transit_vni }}; | ||
| encapsulation vxlan { | ||
| tunnel device "vxlan{{ vdata.evpn.transit_vni }}"; | ||
| router address {{ vxlan.vtep }}; | ||
| }; | ||
| }; | ||
| {% endif %} | ||
| {% endfor %} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| {% include 'gateway/frr.j2' +%} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| {% include 'vlan/frr.j2' +%} | ||
| {% if 'vxlan' in module|default([]) %} | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do you need this dirty hack???
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because daemons have 2 types of template files: Bash scripts and config file snippets
If we move the logic from |
||
| {% include 'vxlan/frr.j2' +%} | ||
| {% endif %} | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| {% if vxlan.flooding|default('') == 'evpn' %} | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If this thing generates content only when EVPN is enabled, don't you think it belongs to the EVPN config?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It does fit better in evpn.j2, which already has the check |
||
| {% for vname in vxlan.vlans|default([]) if vlans[vname].vni is defined and 'evpn' in vlans[vname] %} | ||
| eth table eth_{{ vname }}; | ||
| {% endfor %} | ||
| {% endif %} | ||
Uh oh!
There was an error while loading. Please reload this page.