Skip to content

Commit 90ab725

Browse files
Merge branch 'FRRouting:master' into master
2 parents 0145e41 + ea41dc5 commit 90ab725

File tree

13 files changed

+407
-61
lines changed

13 files changed

+407
-61
lines changed

alpine/APKBUILD.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ makedepends="ncurses-dev net-snmp-dev gawk texinfo perl
1919
perl pkgconf python3 python3-dev readline readline-dev sqlite-libs pcre2-dev
2020
squashfs-tools sudo tar texinfo xorriso xz-libs py-pip rtrlib rtrlib-dev
2121
py3-sphinx elfutils elfutils-dev protobuf-c-compiler protobuf-c-dev
22-
lua5.3-dev lua5.3 gzip"
22+
lua5.3-dev lua5.3 gzip pytest"
2323
checkdepends="pytest py-setuptools"
2424
install="$pkgname.pre-install $pkgname.pre-deinstall $pkgname.post-deinstall"
2525
subpackages="$pkgname-dev $pkgname-doc $pkgname-dbg"

mgmtd/mgmt_be_adapter.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,9 @@ static void be_adapter_handle_subscribe(struct mgmt_msg_subscribe *msg, size_t m
501501
for (uint j = 0; j < msg->nrpc; j++)
502502
be_adapter_register_client_xpath(adapter->id, s[i++],
503503
MGMT_BE_XPATH_SUBSCR_TYPE_RPC);
504+
505+
zlog_notice("Backend daemon: %s registers with mgmtd (client-id: %u)", adapter->name,
506+
adapter->id);
504507
done:
505508
darr_free_free(s);
506509
}
@@ -727,7 +730,7 @@ static void be_adapter_conn_init(struct event *event)
727730
/* Deal with a disconnect happening */
728731
if (id >= darr_len(mgmt_be_adapters_by_id) || !mgmt_be_adapters_by_id[id])
729732
return;
730-
_log_err("Couldn't send initial config to adapter: %s", adapter->name);
733+
_log_warn("Couldn't send initial config to adapter: %s will retry", adapter->name);
731734
be_adapter_sched_init_event(adapter);
732735
}
733736
}

mgmtd/mgmt_ds.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -242,13 +242,13 @@ int mgmt_ds_lock(struct mgmt_ds_ctx *ds_ctx, uint64_t session_id)
242242
assert(ds_ctx);
243243

244244
if (ds_ctx->locked) {
245-
_log_err("LOCK already taken on DS:%s by session-id %Lu",
246-
mgmt_ds_id2name(ds_ctx->ds_id), ds_ctx->vty_session_id);
245+
_log_err("LOCK already taken on DS:%s by session-id %Lu (requesting session-id %Lu)",
246+
mgmt_ds_id2name(ds_ctx->ds_id), ds_ctx->vty_session_id, session_id);
247247
return -EBUSY;
248248
}
249249
if (ds_ctx->txn_locked) {
250-
_log_err("LOCK already taken on DS:%s by session-less txn-id %Lu",
251-
mgmt_ds_id2name(ds_ctx->ds_id), ds_ctx->txn_locked);
250+
_log_err("LOCK already taken on DS:%s by session-less txn-id %Lu (requesting session-id %Lu)",
251+
mgmt_ds_id2name(ds_ctx->ds_id), ds_ctx->txn_locked, session_id);
252252
return -EBUSY;
253253
}
254254
_dbg("LOCK on DS:%s for session-id %Lu", mgmt_ds_id2name(ds_ctx->ds_id), session_id);

mgmtd/mgmt_txn.c

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -807,18 +807,17 @@ int mgmt_txn_handle_be_adapter_connect(struct mgmt_be_client_adapter *adapter, b
807807
struct mgmt_txn *txn, *next;
808808

809809
if (connect)
810-
txn_cfg_be_client_connect(adapter);
811-
else {
812-
/*
813-
* Check if any transaction is currently on-going that
814-
* involves this backend client. If so check if we can now
815-
* advance that configuration.
816-
*/
817-
TAILQ_FOREACH_SAFE (txn, &txn_txns, link, next) {
818-
/* XXX update to handle get-tree and RPC too! */
819-
if (txn->type == MGMTD_TXN_TYPE_CONFIG)
820-
txn_cfg_txn_be_client_disconnect(txn, adapter);
821-
}
810+
return txn_cfg_be_client_connect(adapter);
811+
812+
/*
813+
* Disconnecting: check if any transaction is currently on-going that
814+
* involves this backend client. If so check if we can now advance that
815+
* transaction.
816+
*/
817+
TAILQ_FOREACH_SAFE (txn, &txn_txns, link, next) {
818+
/* XXX update to handle get-tree and RPC too! */
819+
if (txn->type == MGMTD_TXN_TYPE_CONFIG)
820+
txn_cfg_txn_be_client_disconnect(txn, adapter);
822821
}
823822

824823
return 0;

mgmtd/mgmt_txn_cfg.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -845,8 +845,8 @@ int txn_cfg_be_client_connect(struct mgmt_be_client_adapter *adapter)
845845
*/
846846

847847
if (!txn_init_readers++ && mgmt_ds_lock(ds_ctx, 0) != 0) {
848-
_dbg("Failed to lock DS:%s for init of BE adapter '%s'",
849-
mgmt_ds_id2name(MGMTD_DS_RUNNING), adapter->name);
848+
_log_warn("Unable to lock DS:%s for init config of BE client '%s' will retry",
849+
mgmt_ds_id2name(MGMTD_DS_RUNNING), adapter->name);
850850
--txn_init_readers;
851851
return -1;
852852
}
@@ -865,8 +865,8 @@ int txn_cfg_be_client_connect(struct mgmt_be_client_adapter *adapter)
865865
*/
866866
txn = txn_create(MGMTD_TXN_TYPE_CONFIG);
867867
if (!txn) {
868-
_log_err("Failed to create CONFIG Transaction for downloading CONFIGs for client '%s'",
869-
adapter->name);
868+
_log_warn("Unable to create init config txn for BE client '%s' will retry",
869+
adapter->name);
870870
if (!--txn_init_readers)
871871
mgmt_ds_unlock(ds_ctx, 0);
872872
nb_config_diff_del_changes(&adapter_cfgs);

tests/topotests/bgp_vpnv4_gre/test_bgp_vpnv4_gre.py

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
import os
1717
import sys
1818
import json
19+
import re
20+
import time
1921
from functools import partial
2022
import pytest
2123

@@ -201,6 +203,136 @@ def test_protocols_convergence():
201203
assert success is True, "network 10.201.0.0/24 invalid for MPLS: not found on r2"
202204

203205

206+
def test_promiscuity_no_route_reset():
207+
"""
208+
Test that promiscuity changes don't cause route resets on GRE tunnel interfaces
209+
and that the PROMISC flag is correctly displayed.
210+
211+
This simulates running tcpdump on an interface which sets promiscuous mode.
212+
Without the fix, this would cause routes to reset their timers.
213+
"""
214+
tgen = get_topogen()
215+
if tgen.routers_have_failure():
216+
pytest.skip(tgen.errors)
217+
218+
logger.info(
219+
"Test that promiscuity changes (like tcpdump) don't reset routes on GRE interfaces"
220+
)
221+
router = tgen.gears["r1"]
222+
223+
# INTENTIONAL: Wait 3 seconds at the beginning for routes to age
224+
logger.info("Waiting 3 seconds for routes to age")
225+
time.sleep(3)
226+
227+
target_route = "10.201.0.0/24"
228+
logger.info("Getting route timer before promiscuity change")
229+
routes_before = router.vtysh_cmd("show ip route vrf vrf1 json")
230+
routes_json_before = json.loads(routes_before)
231+
232+
uptime_before_promisc = None
233+
if target_route in routes_json_before:
234+
routes_list = routes_json_before[target_route]
235+
if routes_list and isinstance(routes_list, list):
236+
uptime_before_promisc = routes_list[0].get("uptime", None)
237+
logger.info(
238+
"Route {} timer before promiscuity: {}".format(
239+
target_route, uptime_before_promisc
240+
)
241+
)
242+
243+
if not uptime_before_promisc:
244+
pytest.skip("Route {} not found in VRF vrf1".format(target_route))
245+
246+
# Toggle promiscuity on r1-eth1
247+
logger.info("Setting promiscuity on r1-eth1")
248+
router.run("ip link set r1-eth1 promisc on")
249+
250+
# Check that PROMISC flag is set on r1-eth1
251+
def _check_promisc_on():
252+
output = router.vtysh_cmd("show interface r1-eth1")
253+
if "PROMISC" in output:
254+
return None
255+
return "PROMISC flag not found in output"
256+
257+
_, result = topotest.run_and_expect(_check_promisc_on, None, count=20, wait=3)
258+
assert result is None, "PROMISC flag not set after enabling: {}".format(result)
259+
logger.info("PROMISC flag correctly set on r1-eth1")
260+
261+
# Turn off promiscuity on r1-eth1
262+
logger.info("Clearing promiscuity on r1-eth1")
263+
router.run("ip link set r1-eth1 promisc off")
264+
265+
# Check that PROMISC flag is cleared
266+
def _check_promisc_off():
267+
output = router.vtysh_cmd("show interface r1-eth1")
268+
flags_match = re.search(r"flags:\s*<([^>]+)>", output)
269+
if flags_match:
270+
flags = flags_match.group(1)
271+
if "PROMISC" not in flags:
272+
return None
273+
return "PROMISC flag still present: {}".format(flags)
274+
return "Could not find flags in output"
275+
276+
_, result = topotest.run_and_expect(_check_promisc_off, None, count=20, wait=3)
277+
assert result is None, "PROMISC flag not cleared: {}".format(result)
278+
logger.info("PROMISC flag correctly cleared on r1-eth1")
279+
280+
# INTENTIONAL: Wait 3 seconds at the beginning for routes to age
281+
logger.info("Waiting 3 seconds for routes to age")
282+
time.sleep(3)
283+
284+
# Get route timer after promiscuity changes and verify it didn't reset
285+
logger.info("Verifying route {} timer was not reset".format(target_route))
286+
routes_after = router.vtysh_cmd("show ip route vrf vrf1 json")
287+
routes_json_after = json.loads(routes_after)
288+
289+
uptime_after_promisc = None
290+
if target_route in routes_json_after:
291+
routes_list = routes_json_after[target_route]
292+
if routes_list and isinstance(routes_list, list):
293+
uptime_after_promisc = routes_list[0].get("uptime", None)
294+
295+
if not uptime_after_promisc:
296+
pytest.fail(
297+
"Route {} disappeared after promiscuity changes".format(target_route)
298+
)
299+
300+
logger.info(
301+
"Route {} timer after promiscuity: {}".format(
302+
target_route, uptime_after_promisc
303+
)
304+
)
305+
306+
def uptime_to_seconds(uptime_str):
307+
parts = uptime_str.split(":")
308+
if len(parts) == 3:
309+
return int(parts[0]) * 3600 + int(parts[1]) * 60 + int(parts[2])
310+
return 0
311+
312+
before_seconds = uptime_to_seconds(uptime_before_promisc)
313+
after_seconds = uptime_to_seconds(uptime_after_promisc)
314+
315+
logger.info(
316+
"Timer before: {}s, Timer after: {}s".format(before_seconds, after_seconds)
317+
)
318+
319+
assert (
320+
after_seconds >= before_seconds
321+
), "Route {} timer was reset! Before: {}s ({}), After: {}s ({})".format(
322+
target_route,
323+
before_seconds,
324+
uptime_before_promisc,
325+
after_seconds,
326+
uptime_after_promisc,
327+
)
328+
329+
logger.info(
330+
"Route {} remained stable - timer NOT reset by promiscuity changes".format(
331+
target_route
332+
)
333+
)
334+
335+
204336
def test_memory_leak():
205337
"Run the memory leak test and report results."
206338
tgen = get_topogen()

tools/etc/frr/support_bundle_commands.conf

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,13 @@ show ip rip
166166
show ip rip status
167167
CMD_LIST_END
168168

169+
# RIPNG Support Bundle Command List
170+
PROC_NAME:ripng
171+
CMD_LIST_START
172+
show ipv6 ripng
173+
show ipv6 ripng status
174+
CMD_LIST_END
175+
169176
# ISIS Support Bundle Command List
170177
PROC_NAME:isis
171178
CMD_LIST_START
@@ -331,12 +338,37 @@ show mgmt backend-adapter all
331338
show mgmt backend-yang-xpath-registry
332339
show mgmt commit-history
333340
show mgmt datastore all
341+
show mgmt transaction all
334342
show mgmt frontend-adapter all detail
343+
335344
show mgmt get-data /* datastore candidate only-config
336345
show mgmt get-data /* datastore running only-config
337346
show mgmt get-data /* datastore operational
338-
show mgmt transaction all
339-
show mgmt yang-xpath-subscription /
347+
348+
show configuration running json babeld
349+
show configuration running json bfdd
350+
show configuration running json bgpd
351+
show configuration running json eigrpd
352+
show configuration running json fabricd
353+
show configuration running json isisd
354+
show configuration running json ldpd
355+
show configuration running json nhrpd
356+
show configuration running json ospf6d
357+
show configuration running json ospfd
358+
show configuration running json pathd
359+
show configuration running json pbrd
360+
show configuration running json pim6d
361+
show configuration running json pimd
362+
show configuration running json ripd
363+
show configuration running json ripngd
364+
show configuration running json sharpd
365+
show configuration running json staticd
366+
show configuration running json vrrpd
367+
show configuration running json zebra
368+
369+
show configuration running xml mgmtd
370+
show configuration running xml with-defaults mgmtd
371+
show configuration running json mgmtd
340372
CMD_LIST_END
341373

342374
#NHRP Support Bundle Command List
@@ -355,3 +387,13 @@ show ipv6 nhrp nhs
355387
show ipv6 nhrp opennhrp
356388
show ipv6 route nhrp
357389
CMD_LIST_END
390+
391+
#System Support Bundle Command List
392+
PROC_NAME:system
393+
CMD_LIST_START
394+
show debugging
395+
show logging
396+
show memory
397+
show modules
398+
show watchfrr
399+
CMD_LIST_END

zebra/if_netlink.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1520,6 +1520,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
15201520
dplane_ctx_set_ifp_vrf_id(ctx, ns_id);
15211521

15221522
dplane_ctx_set_ifp_flags(ctx, ifi->ifi_flags & 0x0000fffff);
1523+
dplane_ctx_set_ifp_change_flags(ctx, ifi->ifi_change & 0x0000fffff);
15231524

15241525
if (tb[IFLA_PROTO_DOWN]) {
15251526
dplane_ctx_set_ifp_protodown_set(ctx, true);

zebra/interface.c

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2010,6 +2010,7 @@ static void zebra_if_dplane_ifp_handling(struct zebra_dplane_ctx *ctx)
20102010
uint8_t old_hw_addr[INTERFACE_HWADDR_MAX];
20112011
char *desc;
20122012
uint8_t family;
2013+
uint64_t change_flags;
20132014

20142015
/* If VRF, create or update the VRF structure itself. */
20152016
if (zif_type == ZEBRA_IF_VRF && !vrf_is_backend_netns())
@@ -2031,6 +2032,7 @@ static void zebra_if_dplane_ifp_handling(struct zebra_dplane_ctx *ctx)
20312032
startup = dplane_ctx_get_ifp_startup(ctx);
20322033
desc = dplane_ctx_get_ifp_desc(ctx);
20332034
family = dplane_ctx_get_ifp_family(ctx);
2035+
change_flags = dplane_ctx_get_ifp_change_flags(ctx);
20342036

20352037
#ifndef AF_BRIDGE
20362038
/*
@@ -2150,6 +2152,23 @@ static void zebra_if_dplane_ifp_handling(struct zebra_dplane_ctx *ctx)
21502152
frrtrace(8, frr_zebra, if_dplane_ifp_handling_new, name, ifindex, vrf_id,
21512153
zif_type, zif_slave_type, master_ifindex, flags, 1);
21522154

2155+
/* Update flags - all paths need this */
2156+
ifp->flags = flags;
2157+
2158+
/*
2159+
* Interface promiscuity changes trigger spurious routing updates on HBN
2160+
* uplink interfaces, causing route flushes and traffic disruption.
2161+
*
2162+
* Check if only promiscuity flag changed (from netlink change mask)
2163+
*/
2164+
if (change_flags == IFF_PROMISC) {
2165+
/* Flags already updated above, skip routing notifications */
2166+
if (IS_ZEBRA_DEBUG_KERNEL)
2167+
zlog_debug("%s: PROMISC-only update for %s(%u), no routing notification",
2168+
__func__, name, ifp->ifindex);
2169+
return;
2170+
}
2171+
21532172
set_ifindex(ifp, ifindex, zns);
21542173
if_update_state_mtu(ifp, mtu);
21552174
if_update_state_mtu6(ifp, mtu);
@@ -2180,8 +2199,6 @@ static void zebra_if_dplane_ifp_handling(struct zebra_dplane_ctx *ctx)
21802199
rc_bitfield);
21812200

21822201
if (if_is_no_ptm_operative(ifp)) {
2183-
2184-
ifp->flags = flags;
21852202
bool is_up = if_is_operative(ifp);
21862203

21872204
if (!if_is_no_ptm_operative(ifp) ||
@@ -2239,7 +2256,6 @@ static void zebra_if_dplane_ifp_handling(struct zebra_dplane_ctx *ctx)
22392256
}
22402257
}
22412258
} else {
2242-
ifp->flags = flags;
22432259
if (if_is_operative(ifp) &&
22442260
!CHECK_FLAG(zif->flags,
22452261
ZIF_FLAG_PROTODOWN)) {

0 commit comments

Comments
 (0)