Skip to content

Commit

Permalink
bgpd: Allow overriding default distance if set to 0
Browse files Browse the repository at this point in the history
`set distance` with route-maps allow setting it to zero. Relax zebra to
use distance as 0 as well.

Or imagine a case when you have a static kernel route with distance 0, but
you need to override it from BGP with 0 distance as well.

Signed-off-by: Donatas Abraitis <donatas@opensourcerouting.org>
  • Loading branch information
ton31337 committed Mar 20, 2023
1 parent 3bf4d3b commit 6acf5c8
Show file tree
Hide file tree
Showing 11 changed files with 173 additions and 36 deletions.
63 changes: 38 additions & 25 deletions bgpd/bgp_route.c
Original file line number Diff line number Diff line change
Expand Up @@ -15115,8 +15115,9 @@ static int bgp_distance_unset(struct vty *vty, const char *distance_str,
}

/* Apply BGP information to distance method. */
uint8_t bgp_distance_apply(const struct prefix *p, struct bgp_path_info *pinfo,
afi_t afi, safi_t safi, struct bgp *bgp)
bool bgp_distance_apply(const struct prefix *p, struct bgp_path_info *pinfo,
afi_t afi, safi_t safi, struct bgp *bgp,
uint8_t *distance)
{
struct bgp_dest *dest;
struct prefix q = {0};
Expand All @@ -15127,12 +15128,15 @@ uint8_t bgp_distance_apply(const struct prefix *p, struct bgp_path_info *pinfo,
struct bgp_path_info *bpi_ultimate;

if (!bgp)
return 0;
return false;

peer = pinfo->peer;
if (pinfo->attr->distance != ZEBRA_EBGP_DISTANCE_DEFAULT ||
pinfo->attr->distance != ZEBRA_IBGP_DISTANCE_DEFAULT) {
*distance = pinfo->attr->distance;
return true;
}

if (pinfo->attr->distance)
return pinfo->attr->distance;
peer = pinfo->peer;

/* get peer origin to calculate appropriate distance */
if (pinfo->sub_type == BGP_ROUTE_IMPORTED) {
Expand All @@ -15145,7 +15149,7 @@ uint8_t bgp_distance_apply(const struct prefix *p, struct bgp_path_info *pinfo,
*/
if (pinfo->sub_type != BGP_ROUTE_AGGREGATE
&& !sockunion2hostprefix(&peer->su, &q))
return 0;
return false;

dest = bgp_node_match(bgp_distance_table[afi][safi], &q);
if (dest) {
Expand All @@ -15154,11 +15158,15 @@ uint8_t bgp_distance_apply(const struct prefix *p, struct bgp_path_info *pinfo,

if (bdistance->access_list) {
alist = access_list_lookup(afi, bdistance->access_list);
if (alist
&& access_list_apply(alist, p) == FILTER_PERMIT)
return bdistance->distance;
} else
return bdistance->distance;
if (alist &&
access_list_apply(alist, p) == FILTER_PERMIT) {
*distance = bdistance->distance;
return true;
}
} else {
*distance = bdistance->distance;
return true;
}
}

/* Backdoor check. */
Expand All @@ -15168,26 +15176,31 @@ uint8_t bgp_distance_apply(const struct prefix *p, struct bgp_path_info *pinfo,
bgp_dest_unlock_node(dest);

if (bgp_static->backdoor) {
if (bgp->distance_local[afi][safi])
return bgp->distance_local[afi][safi];
else
return ZEBRA_IBGP_DISTANCE_DEFAULT;
*distance = (bgp->distance_local[afi][safi])
? bgp->distance_local[afi][safi]
: ZEBRA_IBGP_DISTANCE_DEFAULT;
return true;
}
}

if (peer->sort == BGP_PEER_EBGP) {
if (bgp->distance_ebgp[afi][safi])
return bgp->distance_ebgp[afi][safi];
return ZEBRA_EBGP_DISTANCE_DEFAULT;
*distance = (bgp->distance_ebgp[afi][safi])
? bgp->distance_ebgp[afi][safi]
: ZEBRA_EBGP_DISTANCE_DEFAULT;
return true;
} else if (peer->sort == BGP_PEER_IBGP) {
if (bgp->distance_ibgp[afi][safi])
return bgp->distance_ibgp[afi][safi];
return ZEBRA_IBGP_DISTANCE_DEFAULT;
*distance = (bgp->distance_ibgp[afi][safi])
? bgp->distance_ibgp[afi][safi]
: ZEBRA_IBGP_DISTANCE_DEFAULT;
return true;
} else {
if (bgp->distance_local[afi][safi])
return bgp->distance_local[afi][safi];
return ZEBRA_IBGP_DISTANCE_DEFAULT;
*distance = (bgp->distance_local[afi][safi])
? bgp->distance_local[afi][safi]
: ZEBRA_IBGP_DISTANCE_DEFAULT;
return true;
}

return false;
}

/* If we enter `distance bgp (1-255) (1-255) (1-255)`,
Expand Down
6 changes: 3 additions & 3 deletions bgpd/bgp_route.h
Original file line number Diff line number Diff line change
Expand Up @@ -776,9 +776,9 @@ extern void bgp_aggregate_decrement(struct bgp *bgp, const struct prefix *p,
struct bgp_path_info *path, afi_t afi,
safi_t safi);

extern uint8_t bgp_distance_apply(const struct prefix *p,
struct bgp_path_info *path, afi_t afi,
safi_t safi, struct bgp *bgp);
extern bool bgp_distance_apply(const struct prefix *p,
struct bgp_path_info *path, afi_t afi,
safi_t safi, struct bgp *bgp, uint8_t *distance);

extern afi_t bgp_node_afi(struct vty *);
extern safi_t bgp_node_safi(struct vty *);
Expand Down
13 changes: 8 additions & 5 deletions bgpd/bgp_zebra.c
Original file line number Diff line number Diff line change
Expand Up @@ -1286,7 +1286,7 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
int nh_family;
unsigned int valid_nh_count = 0;
bool allow_recursion = false;
uint8_t distance;
uint8_t distance = ZEBRA_EBGP_DISTANCE_DEFAULT;
struct peer *peer;
struct bgp_path_info *mpinfo;
struct bgp *bgp_orig;
Expand Down Expand Up @@ -1613,9 +1613,11 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
api.tag = tag;
}

distance = bgp_distance_apply(p, info, afi, safi, bgp);
if (distance) {
if (bgp_distance_apply(p, info, afi, safi, bgp, &distance)) {
SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE);
if (!distance)
SET_FLAG(api.flags,
ZEBRA_FLAG_DEFAULT_DISTANCE_OVERRIDE);
api.distance = distance;
}

Expand All @@ -1630,9 +1632,10 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,

zlog_debug(
"Tx route %s VRF %u %pFX metric %u tag %" ROUTE_TAG_PRI
" count %d nhg %d",
" count %d nhg %d distance %u",
is_add ? "add" : "delete", bgp->vrf_id, &api.prefix,
api.metric, api.tag, api.nexthop_num, nhg_id);
api.metric, api.tag, api.nexthop_num, nhg_id,
api.distance);
for (i = 0; i < api.nexthop_num; i++) {
api_nh = &api.nexthops[i];

Expand Down
7 changes: 6 additions & 1 deletion lib/zclient.h
Original file line number Diff line number Diff line change
Expand Up @@ -533,13 +533,18 @@ struct zapi_route {
* offload situation.
*/
#define ZEBRA_FLAG_OFFLOAD_FAILED 0x200

/*
* This flag lets us know that we think the route entry
* received has caused us to be out of sync with the
* kernel (NLM_F_APPEND at the very least )
*/
#define ZEBRA_FLAG_OUTOFSYNC 0x400
/*
* This flag tells to override a default distance for
* the routes that has distance set to 0. For example,
* via route-maps `set distance 0`.
*/
#define ZEBRA_FLAG_DEFAULT_DISTANCE_OVERRIDE 0x800

/* The older XXX_MESSAGE flags live here */
uint32_t message;
Expand Down
Empty file.
9 changes: 9 additions & 0 deletions tests/topotests/bgp_distance_zero/r1/bgpd.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
!
router bgp 65001
no bgp ebgp-requires-policy
no bgp network import-check
neighbor 192.168.1.2 remote-as external
address-family ipv4 unicast
network 10.10.10.1/32
exit-address-family
!
4 changes: 4 additions & 0 deletions tests/topotests/bgp_distance_zero/r1/zebra.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
!
int r1-eth0
ip address 192.168.1.1/24
!
10 changes: 10 additions & 0 deletions tests/topotests/bgp_distance_zero/r2/bgpd.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
!
router bgp 65002
neighbor 192.168.1.1 remote-as external
address-family ipv4 unicast
neighbor 192.168.1.1 route-map r1 in
exit-address-family
!
route-map r1 permit 10
set distance 0
exit
4 changes: 4 additions & 0 deletions tests/topotests/bgp_distance_zero/r2/zebra.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
!
int r2-eth0
ip address 192.168.1.2/24
!
86 changes: 86 additions & 0 deletions tests/topotests/bgp_distance_zero/test_bgp_distance_zero.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#!/usr/bin/env python
# SPDX-License-Identifier: ISC

# Copyright (c) 2023 by
# Donatas Abraitis <donatas@opensourcerouting.org>
#

"""
Test if distance can be set to zero via route-maps.
"""

import os
import sys
import json
import pytest
import functools

pytestmark = pytest.mark.bgpd

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

pytestmark = [pytest.mark.bgpd]


def setup_module(mod):
topodef = {"s1": ("r1", "r2")}
tgen = Topogen(topodef, mod.__name__)
tgen.start_topology()

router_list = tgen.routers()

for i, (rname, router) in enumerate(router_list.items(), 1):
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
router.load_config(
TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
)

tgen.start_router()


def teardown_module(mod):
tgen = get_topogen()
tgen.stop_topology()


def test_bgp_distance_zero():
tgen = get_topogen()

if tgen.routers_have_failure():
pytest.skip(tgen.errors)

r2 = tgen.gears["r2"]

def _bgp_converge_table():
output = json.loads(r2.vtysh_cmd("show bgp ipv4 unicast 10.10.10.1/32 json"))
expected = {"paths": [{"valid": True}]}
return topotest.json_cmp(output, expected)

test_func = functools.partial(_bgp_converge_table)
_, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
assert result is None, "Can't see distance 0 in BGP table"

def _bgp_converge_rib():
output = json.loads(r2.vtysh_cmd("show ip route 10.10.10.1/32 json"))
expected = {
"10.10.10.1/32": [
{"protocol": "bgp", "distance": 0, "selected": True, "installed": True}
]
}
return topotest.json_cmp(output, expected)

test_func = functools.partial(_bgp_converge_rib)
_, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
assert result is None, "Can't see distance 0 in RIB"


if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))
7 changes: 5 additions & 2 deletions zebra/zebra_rib.c
Original file line number Diff line number Diff line change
Expand Up @@ -2781,8 +2781,11 @@ static void process_subq_early_route_add(struct zebra_early_route *ere)
if (re->distance == 0) {
if (same && !zebra_router_notify_on_ack())
re->distance = same->distance;
else
re->distance = route_distance(re->type);
else {
if (!CHECK_FLAG(re->flags,
ZEBRA_FLAG_DEFAULT_DISTANCE_OVERRIDE))
re->distance = route_distance(re->type);
}
}

if (re->metric == ROUTE_INSTALLATION_METRIC &&
Expand Down

0 comments on commit 6acf5c8

Please sign in to comment.