bgpd: fix prefix-sid crash bug and add topotest (step4)

This commit fix bgpd's prefix-sid type4,5 feature which has
miss implementation from https://github.com/FRRouting/frr/pull/5653
was merged. Due to some nessesary lines are not presented.

When bgpd receives multi update message with same service-sid on
prefix-sid type-5 attribute, bgpd will crash arround path-attribute's
values object reference count.

And also, this commit add a topotest to check that feature work fine.

Signed-off-by: Hiroki Shirokura <slank.dev@gmail.com>
This commit is contained in:
Hiroki Shirokura 2020-12-24 04:07:39 +00:00 committed by Mark Stapp
parent 4df9d8592b
commit b83127e156
8 changed files with 360 additions and 0 deletions

View File

@ -676,6 +676,10 @@ unsigned int attrhash_key_make(const void *p)
MIX(transit_hash_key_make(bgp_attr_get_transit(attr)));
if (attr->encap_subtlvs)
MIX(encap_hash_key_make(attr->encap_subtlvs));
if (attr->srv6_l3vpn)
MIX(srv6_l3vpn_hash_key_make(attr->srv6_l3vpn));
if (attr->srv6_vpn)
MIX(srv6_vpn_hash_key_make(attr->srv6_vpn));
#ifdef ENABLE_BGP_VNC
struct bgp_attr_encap_subtlv *vnc_subtlvs =
bgp_attr_get_vnc_subtlvs(attr);
@ -1141,6 +1145,16 @@ void bgp_attr_undup(struct attr *new, struct attr *old)
if (new->lcommunity != old->lcommunity)
lcommunity_free(&new->lcommunity);
if (new->srv6_l3vpn != old->srv6_l3vpn) {
srv6_l3vpn_free(new->srv6_l3vpn);
new->srv6_l3vpn = NULL;
}
if (new->srv6_vpn != old->srv6_vpn) {
srv6_vpn_free(new->srv6_vpn);
new->srv6_vpn = NULL;
}
}
/* Free bgp attribute and aspath. */
@ -1202,6 +1216,14 @@ void bgp_attr_flush(struct attr *attr)
encap_free(attr->encap_subtlvs);
attr->encap_subtlvs = NULL;
}
if (attr->srv6_l3vpn && !attr->srv6_l3vpn->refcnt) {
srv6_l3vpn_free(attr->srv6_l3vpn);
attr->srv6_l3vpn = NULL;
}
if (attr->srv6_vpn && !attr->srv6_vpn->refcnt) {
srv6_vpn_free(attr->srv6_vpn);
attr->srv6_vpn = NULL;
}
#ifdef ENABLE_BGP_VNC
struct bgp_attr_encap_subtlv *vnc_subtlvs =
bgp_attr_get_vnc_subtlvs(attr);
@ -2676,6 +2698,7 @@ static bgp_attr_parse_ret_t bgp_attr_psid_sub(uint8_t type, uint16_t length,
sizeof(struct bgp_attr_srv6_vpn));
attr->srv6_vpn->sid_flags = sid_flags;
sid_copy(&attr->srv6_vpn->sid, &ipv6_sid);
attr->srv6_vpn = srv6_vpn_intern(attr->srv6_vpn);
}
/* Placeholder code for the SRv6 L3 Service type */
@ -2718,6 +2741,7 @@ static bgp_attr_parse_ret_t bgp_attr_psid_sub(uint8_t type, uint16_t length,
attr->srv6_l3vpn->sid_flags = sid_flags;
attr->srv6_l3vpn->endpoint_behavior = endpoint_behavior;
sid_copy(&attr->srv6_l3vpn->sid, &ipv6_sid);
attr->srv6_l3vpn = srv6_l3vpn_intern(attr->srv6_l3vpn);
}
/* Placeholder code for Unsupported TLV */

View File

@ -0,0 +1,29 @@
group controller {
neighbor 10.0.0.1 {
router-id 10.0.0.101;
local-address 10.0.0.101;
local-as 2;
peer-as 1;
family {
ipv6 mpls-vpn;
}
static {
route 2001:1::/64 {
rd 2:10;
next-hop 2001::2;
extended-community [ target:2:10 ];
label 3;
attribute [0x28 0xc0 0x0500150020010db800010001000000000000000100ffff00 ];
}
route 2001:2::/64 {
rd 2:10;
next-hop 2001::2;
extended-community [ target:2:10 ];
label 3;
attribute [0x28 0xc0 0x0500150020010db800010001000000000000000100ffff00 ];
}
}
}
}

View File

@ -0,0 +1,53 @@
[exabgp.api]
encoder = text
highres = false
respawn = false
socket = ''
[exabgp.bgp]
openwait = 60
[exabgp.cache]
attributes = true
nexthops = true
[exabgp.daemon]
daemonize = true
pid = '/var/run/exabgp/exabgp.pid'
user = 'exabgp'
[exabgp.log]
all = false
configuration = true
daemon = true
destination = '/var/log/exabgp.log'
enable = true
level = INFO
message = false
network = true
packets = false
parser = false
processes = true
reactor = true
rib = false
routes = false
short = false
timers = false
[exabgp.pdb]
enable = false
[exabgp.profile]
enable = false
file = ''
[exabgp.reactor]
speed = 1.0
[exabgp.tcp]
acl = false
bind = ''
delay = 0
once = false
port = 179

View File

@ -0,0 +1,26 @@
log stdout notifications
log monitor notifications
!log commands
!
!debug bgp zebra
!debug bgp neighbor-events
!debug bgp vnc verbose
!debug bgp update-groups
!debug bgp updates in
!debug bgp updates out
!debug bgp vpn label
!debug bgp vpn leak-from-vrf
!debug bgp vpn leak-to-vrf
!debug bgp vpn rmap-event
!
router bgp 1
bgp router-id 10.0.0.1
no bgp default ipv4-unicast
no bgp ebgp-requires-policy
neighbor 10.0.0.101 remote-as 2
neighbor 10.0.0.101 timers 3 10
!
address-family ipv6 vpn
neighbor 10.0.0.101 activate
exit-address-family
!

View File

@ -0,0 +1,50 @@
{
"2:10":{
"prefix":"2001:1::\/64",
"advertisedTo":{
"10.0.0.101":{
}
},
"paths":[
{
"aspath":{
"string":"2",
"segments":[
{
"type":"as-sequence",
"list":[
2
]
}
],
"length":1
},
"origin":"IGP",
"valid":true,
"bestpath":{
"overall":true
},
"extendedCommunity":{
"string":"RT:2:10"
},
"remoteLabel":3,
"remoteSid":"2001:db8:1:1::1",
"nexthops":[
{
"ip":"2001::2",
"afi":"ipv6",
"scope":"global",
"metric":0,
"accessible":true,
"used":true
}
],
"peer":{
"peerId":"10.0.0.101",
"routerId":"10.0.0.101",
"type":"external"
}
}
]
}
}

View File

@ -0,0 +1,50 @@
{
"2:10":{
"prefix":"2001:2::\/64",
"advertisedTo":{
"10.0.0.101":{
}
},
"paths":[
{
"aspath":{
"string":"2",
"segments":[
{
"type":"as-sequence",
"list":[
2
]
}
],
"length":1
},
"origin":"IGP",
"valid":true,
"bestpath":{
"overall":true
},
"extendedCommunity":{
"string":"RT:2:10"
},
"remoteLabel":3,
"remoteSid":"2001:db8:1:1::1",
"nexthops":[
{
"ip":"2001::2",
"afi":"ipv6",
"scope":"global",
"metric":0,
"accessible":true,
"used":true
}
],
"peer":{
"peerId":"10.0.0.101",
"routerId":"10.0.0.101",
"type":"external"
}
}
]
}
}

View File

@ -0,0 +1,7 @@
hostname r1
!
interface r1-eth0
ip address 10.0.0.1/24
no shutdown
!
line vty

View File

@ -0,0 +1,121 @@
#!/usr/bin/env python
#
# test_bgp_prefix_sid2.py
# Part of NetDEF Topology Tests
#
# Copyright (c) 2020 by LINE Corporation
# Copyright (c) 2020 by Hiroki Shirokura <slank.dev@gmail.com>
#
# Permission to use, copy, modify, and/or distribute this software
# for any purpose with or without fee is hereby granted, provided
# that the above copyright notice and this permission notice appear
# in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
# OF THIS SOFTWARE.
#
"""
test_bgp_prefix_sid2.py: Test BGP topology with EBGP on prefix-sid
"""
import json
import os
import sys
import functools
import pytest
CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, "../"))
# pylint: disable=C0413
from lib import topotest
from lib.topogen import Topogen, TopoRouter, get_topogen
from lib.topolog import logger
from mininet.topo import Topo
class TemplateTopo(Topo):
def build(self, **_opts):
tgen = get_topogen(self)
router = tgen.add_router("r1")
switch = tgen.add_switch("s1")
switch.add_link(router)
switch = tgen.gears["s1"]
peer1 = tgen.add_exabgp_peer(
"peer1", ip="10.0.0.101", defaultRoute="via 10.0.0.1"
)
switch.add_link(peer1)
def setup_module(module):
tgen = Topogen(TemplateTopo, module.__name__)
tgen.start_topology()
router = tgen.gears["r1"]
router.load_config(
TopoRouter.RD_ZEBRA,
os.path.join(CWD, "{}/zebra.conf".format("r1"))
)
router.load_config(
TopoRouter.RD_BGP,
os.path.join(CWD, "{}/bgpd.conf".format("r1"))
)
router.start()
logger.info("starting exaBGP")
peer_list = tgen.exabgp_peers()
for pname, peer in peer_list.items():
logger.info("starting exaBGP on {}".format(pname))
peer_dir = os.path.join(CWD, pname)
env_file = os.path.join(CWD, pname, "exabgp.env")
logger.info("Running ExaBGP peer on {}".format(pname))
peer.start(peer_dir, env_file)
logger.info(pname)
def teardown_module(module):
tgen = get_topogen()
tgen.stop_topology()
def open_json_file(filename):
try:
with open(filename, "r") as f:
return json.load(f)
except IOError:
assert False, "Could not read file {}".format(filename)
def test_r1_rib():
def _check(name, cmd, expected_file):
logger.info("polling")
tgen = get_topogen()
router = tgen.gears[name]
output = json.loads(router.vtysh_cmd(cmd))
expected = open_json_file("{}/{}".format(CWD, expected_file))
return topotest.json_cmp(output, expected)
def check(name, cmd, expected_file):
logger.info("[+] check {} \"{}\" {}".format(name, cmd, expected_file))
tgen = get_topogen()
func = functools.partial(_check, name, cmd, expected_file)
success, result = topotest.run_and_expect(func, None, count=10, wait=0.5)
assert result is None, 'Failed'
check("r1", "show bgp ipv6 vpn 2001:1::/64 json", "r1/vpnv6_rib_entry1.json")
check("r1", "show bgp ipv6 vpn 2001:2::/64 json", "r1/vpnv6_rib_entry2.json")
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
ret = pytest.main(args)
sys.exit(ret)