Skip to content

Commit 8b23abf

Browse files
authored
Merge pull request #16300 from donaldsharp/local_connected
Local connected
2 parents 8e4389d + 37dd518 commit 8b23abf

File tree

7 files changed

+196
-19
lines changed

7 files changed

+196
-19
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"192.168.44.0/24":[
3+
{
4+
"prefix":"192.168.44.0/24",
5+
"prefixLen":24,
6+
"protocol":"connected",
7+
"vrfName":"default",
8+
"selected":true,
9+
"destSelected":true,
10+
"distance":0,
11+
"metric":0,
12+
"installed":true,
13+
"table":254,
14+
"nexthops":[
15+
{
16+
"fib":true,
17+
"directlyConnected":true,
18+
"interfaceName":"r1-eth1",
19+
"active":true
20+
}
21+
]
22+
}
23+
]
24+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"4.5.6.7/32":[
3+
{
4+
"prefix":"4.5.6.7/32",
5+
"prefixLen":32,
6+
"protocol":"kernel",
7+
"vrfName":"default",
8+
"selected":true,
9+
"destSelected":true,
10+
"distance":0,
11+
"metric":0,
12+
"installed":true,
13+
"table":254,
14+
"nexthops":[
15+
{
16+
"fib":true,
17+
"directlyConnected":true,
18+
"interfaceName":"r1-eth1",
19+
"active":true
20+
}
21+
]
22+
}
23+
]
24+
}

tests/topotests/zebra_multiple_connected/test_zebra_multiple_connected.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
import pytest
2020
import json
2121
from functools import partial
22+
from lib.topolog import logger
23+
24+
pytestmark = pytest.mark.random_order(disabled=True)
2225

2326
# Save the Current Working Directory to find configuration files.
2427
CWD = os.path.dirname(os.path.realpath(__file__))
@@ -159,6 +162,46 @@ def test_zebra_noprefix_connected():
159162
assert result, "Connected Route should not have been added"
160163

161164

165+
def test_zebra_noprefix_connected_add():
166+
"Test that a noprefixroute created with a manual route works as expected, this is for NetworkManager"
167+
168+
tgen = get_topogen()
169+
if tgen.routers_have_failure():
170+
pytest.skip(tgen.errors)
171+
172+
router = tgen.gears["r1"]
173+
router.run("ip route add 192.168.44.0/24 dev r1-eth1")
174+
175+
connected = "{}/{}/ip_route_connected.json".format(CWD, router.name)
176+
expected = json.loads(open(connected).read())
177+
178+
test_func = partial(
179+
topotest.router_json_cmp, router, "show ip route 192.168.44.0/24 json", expected
180+
)
181+
result, _ = topotest.run_and_expect(test_func, None, count=20, wait=1)
182+
assert result, "Connected Route should have been added\n{}".format(_)
183+
184+
185+
def test_zebra_kernel_route_add():
186+
"Test that a random kernel route is properly handled as expected"
187+
188+
tgen = get_topogen()
189+
if tgen.routers_have_failure():
190+
pytest.skip(tgen.errors)
191+
192+
router = tgen.gears["r1"]
193+
router.run("ip route add 4.5.6.7/32 dev r1-eth1")
194+
195+
kernel = "{}/{}/ip_route_kernel.json".format(CWD, router.name)
196+
expected = json.loads(open(kernel).read())
197+
198+
test_func = partial(
199+
topotest.router_json_cmp, router, "show ip route 4.5.6.7/32 json", expected
200+
)
201+
result, _ = topotest.run_and_expect(test_func, None, count=20, wait=1)
202+
assert result, "Connected Route should have been added\n{}".format(_)
203+
204+
162205
if __name__ == "__main__":
163206
args = ["-s"] + sys.argv[1:]
164207
sys.exit(pytest.main(args))

zebra/interface.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1058,6 +1058,8 @@ void if_down(struct interface *ifp)
10581058

10591059
/* Delete all neighbor addresses learnt through IPv6 RA */
10601060
if_down_del_nbr_connected(ifp);
1061+
1062+
rib_update_handle_vrf_all(RIB_UPDATE_INTERFACE_DOWN, ZEBRA_ROUTE_KERNEL);
10611063
}
10621064

10631065
void if_refresh(struct interface *ifp)

zebra/rib.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,7 @@ typedef struct rib_tables_iter_t_ {
326326

327327
/* Events/reasons triggering a RIB update. */
328328
enum rib_update_event {
329+
RIB_UPDATE_INTERFACE_DOWN,
329330
RIB_UPDATE_KERNEL,
330331
RIB_UPDATE_RMAP_CHANGE,
331332
RIB_UPDATE_OTHER,
@@ -395,7 +396,7 @@ extern int rib_add_multipath_nhe(afi_t afi, safi_t safi, struct prefix *p,
395396

396397
extern void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
397398
unsigned short instance, uint32_t flags,
398-
struct prefix *p, struct prefix_ipv6 *src_p,
399+
const struct prefix *p, const struct prefix_ipv6 *src_p,
399400
const struct nexthop *nh, uint32_t nhe_id,
400401
uint32_t table_id, uint32_t metric, uint8_t distance,
401402
bool fromkernel);
@@ -477,6 +478,8 @@ extern uint8_t route_distance(int type);
477478
extern void zebra_rib_evaluate_rn_nexthops(struct route_node *rn, uint32_t seq,
478479
bool rt_delete);
479480

481+
extern void rib_update_handle_vrf_all(enum rib_update_event event, int rtype);
482+
480483
/*
481484
* rib_find_rn_from_ctx
482485
*

zebra/rt_netlink.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -799,8 +799,6 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h,
799799
return 0;
800800
if (rtm->rtm_protocol == RTPROT_REDIRECT)
801801
return 0;
802-
if (rtm->rtm_protocol == RTPROT_KERNEL)
803-
return 0;
804802

805803
selfroute = is_selfroute(rtm->rtm_protocol);
806804

zebra/zebra_rib.c

Lines changed: 99 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1619,6 +1619,10 @@ static bool rib_compare_routes(const struct route_entry *re1,
16191619
* v6 link-locals, and we also support multiple addresses in the same
16201620
* subnet on a single interface.
16211621
*/
1622+
if (re1->type == ZEBRA_ROUTE_CONNECT &&
1623+
(re1->nhe->nhg.nexthop->ifindex == re2->nhe->nhg.nexthop->ifindex))
1624+
return true;
1625+
16221626
if (re1->type != ZEBRA_ROUTE_CONNECT && re1->type != ZEBRA_ROUTE_LOCAL)
16231627
return true;
16241628

@@ -2863,10 +2867,11 @@ static void process_subq_early_route_add(struct zebra_early_route *ere)
28632867

28642868
/* Link new re to node.*/
28652869
if (IS_ZEBRA_DEBUG_RIB) {
2866-
rnode_debug(
2867-
rn, re->vrf_id,
2868-
"Inserting route rn %p, re %p (%s) existing %p, same_count %d",
2869-
rn, re, zebra_route_string(re->type), same, same_count);
2870+
rnode_debug(rn, re->vrf_id,
2871+
"Inserting route rn %p, re %p (%s/%s/%s) existing %p, same_count %d",
2872+
rn, re, zebra_route_string(re->type),
2873+
afi2str(ere->afi), safi2str(ere->safi), same,
2874+
same_count);
28702875

28712876
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
28722877
route_entry_dump(
@@ -4370,8 +4375,10 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
43704375
return -1;
43714376

43724377
/* We either need nexthop(s) or an existing nexthop id */
4373-
if (ng == NULL && re->nhe_id == 0)
4378+
if (ng == NULL && re->nhe_id == 0) {
4379+
zebra_rib_route_entry_free(re);
43744380
return -1;
4381+
}
43754382

43764383
/*
43774384
* Use a temporary nhe to convey info to the common/main api.
@@ -4383,6 +4390,34 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
43834390
nhe.id = re->nhe_id;
43844391

43854392
n = zebra_nhe_copy(&nhe, 0);
4393+
4394+
if (re->type == ZEBRA_ROUTE_KERNEL) {
4395+
struct interface *ifp;
4396+
struct connected *connected;
4397+
4398+
if (p->family == AF_INET6 &&
4399+
IN6_IS_ADDR_LINKLOCAL(&p->u.prefix6)) {
4400+
zebra_nhg_free(n);
4401+
zebra_rib_route_entry_free(re);
4402+
return -1;
4403+
}
4404+
4405+
ifp = if_lookup_prefix(p, re->vrf_id);
4406+
if (ifp) {
4407+
connected = connected_lookup_prefix(ifp, p);
4408+
4409+
if (connected && !CHECK_FLAG(connected->flags,
4410+
ZEBRA_IFA_NOPREFIXROUTE)) {
4411+
zebra_nhg_free(n);
4412+
zebra_rib_route_entry_free(re);
4413+
return -1;
4414+
}
4415+
4416+
if (ifp->ifindex == ng->nexthop->ifindex)
4417+
re->type = ZEBRA_ROUTE_CONNECT;
4418+
}
4419+
}
4420+
43864421
ret = rib_add_multipath_nhe(afi, safi, p, src_p, re, n, startup);
43874422

43884423
/* In error cases, free the route also */
@@ -4393,8 +4428,8 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
43934428
}
43944429

43954430
void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
4396-
unsigned short instance, uint32_t flags, struct prefix *p,
4397-
struct prefix_ipv6 *src_p, const struct nexthop *nh,
4431+
unsigned short instance, uint32_t flags, const struct prefix *p,
4432+
const struct prefix_ipv6 *src_p, const struct nexthop *nh,
43984433
uint32_t nhe_id, uint32_t table_id, uint32_t metric,
43994434
uint8_t distance, bool fromkernel)
44004435
{
@@ -4458,6 +4493,9 @@ static const char *rib_update_event2str(enum rib_update_event event)
44584493
const char *ret = "UNKNOWN";
44594494

44604495
switch (event) {
4496+
case RIB_UPDATE_INTERFACE_DOWN:
4497+
ret = "RIB_UPDATE_INTERFACE_DOWN";
4498+
break;
44614499
case RIB_UPDATE_KERNEL:
44624500
ret = "RIB_UPDATE_KERNEL";
44634501
break;
@@ -4474,15 +4512,56 @@ static const char *rib_update_event2str(enum rib_update_event event)
44744512
return ret;
44754513
}
44764514

4515+
/*
4516+
* We now keep kernel routes, but we don't have any
4517+
* trigger events for them when they are implicitly
4518+
* deleted. Since we are already walking the
4519+
* entire table on a down event let's look at
4520+
* the few kernel routes we may have
4521+
*/
4522+
static void
4523+
rib_update_handle_kernel_route_down_possibility(struct route_node *rn,
4524+
struct route_entry *re)
4525+
{
4526+
struct nexthop *nexthop = NULL;
4527+
bool alive = false;
4528+
4529+
for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) {
4530+
struct interface *ifp = if_lookup_by_index(nexthop->ifindex,
4531+
nexthop->vrf_id);
4532+
4533+
if (ifp && if_is_up(ifp)) {
4534+
alive = true;
4535+
break;
4536+
}
4537+
}
4538+
4539+
if (!alive) {
4540+
struct rib_table_info *rib_table = srcdest_rnode_table_info(rn);
4541+
const struct prefix *p;
4542+
const struct prefix_ipv6 *src_p;
4543+
4544+
srcdest_rnode_prefixes(rn, &p, (const struct prefix **)&src_p);
4545+
4546+
rib_delete(rib_table->afi, rib_table->safi, re->vrf_id,
4547+
re->type, re->instance, re->flags, p, src_p, NULL, 0,
4548+
re->table, re->metric, re->distance, true);
4549+
}
4550+
}
4551+
44774552

44784553
/* Schedule route nodes to be processed if they match the type */
4479-
static void rib_update_route_node(struct route_node *rn, int type)
4554+
static void rib_update_route_node(struct route_node *rn, int type,
4555+
enum rib_update_event event)
44804556
{
44814557
struct route_entry *re, *next;
44824558
bool re_changed = false;
44834559

44844560
RNODE_FOREACH_RE_SAFE (rn, re, next) {
4485-
if (type == ZEBRA_ROUTE_ALL || type == re->type) {
4561+
if (event == RIB_UPDATE_INTERFACE_DOWN && type == re->type &&
4562+
type == ZEBRA_ROUTE_KERNEL)
4563+
rib_update_handle_kernel_route_down_possibility(rn, re);
4564+
else if (type == ZEBRA_ROUTE_ALL || type == re->type) {
44864565
SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
44874566
re_changed = true;
44884567
}
@@ -4522,28 +4601,32 @@ void rib_update_table(struct route_table *table, enum rib_update_event event,
45224601
/*
45234602
* If we are looking at a route node and the node
45244603
* has already been queued we don't
4525-
* need to queue it up again
4604+
* need to queue it up again, unless it is
4605+
* an interface down event as that we need
4606+
* to process this no matter what.
45264607
*/
4527-
if (rn->info
4528-
&& CHECK_FLAG(rib_dest_from_rnode(rn)->flags,
4529-
RIB_ROUTE_ANY_QUEUED))
4608+
if (rn->info &&
4609+
CHECK_FLAG(rib_dest_from_rnode(rn)->flags,
4610+
RIB_ROUTE_ANY_QUEUED) &&
4611+
event != RIB_UPDATE_INTERFACE_DOWN)
45304612
continue;
45314613

45324614
switch (event) {
4615+
case RIB_UPDATE_INTERFACE_DOWN:
45334616
case RIB_UPDATE_KERNEL:
4534-
rib_update_route_node(rn, ZEBRA_ROUTE_KERNEL);
4617+
rib_update_route_node(rn, ZEBRA_ROUTE_KERNEL, event);
45354618
break;
45364619
case RIB_UPDATE_RMAP_CHANGE:
45374620
case RIB_UPDATE_OTHER:
4538-
rib_update_route_node(rn, rtype);
4621+
rib_update_route_node(rn, rtype, event);
45394622
break;
45404623
case RIB_UPDATE_MAX:
45414624
break;
45424625
}
45434626
}
45444627
}
45454628

4546-
static void rib_update_handle_vrf_all(enum rib_update_event event, int rtype)
4629+
void rib_update_handle_vrf_all(enum rib_update_event event, int rtype)
45474630
{
45484631
struct zebra_router_table *zrt;
45494632

0 commit comments

Comments
 (0)