Skip to content

Commit 10666fb

Browse files
authored
Merge pull request FRRouting#18451 from soumyar-roy/soumya/fastra
zebra: V6 RA not sent anymore after interface up-down-up
2 parents 19c540e + cc4fffa commit 10666fb

File tree

4 files changed

+154
-10
lines changed

4 files changed

+154
-10
lines changed

tests/topotests/high_ecmp/test_high_ecmp_unnumbered.py

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,139 @@ def teardown_module(_mod):
105105
tgen.stop_topology()
106106

107107

108+
def test_v6_rtadv():
109+
tgen = get_topogen()
110+
111+
# Get the initial interface state and RA interval before making any changes
112+
interface_output = tgen.gears["r1"].vtysh_cmd("show interface r1-eth200 json")
113+
interface_data = json.loads(interface_output)
114+
115+
# Check if the interface exists and get its current state
116+
interface_section = interface_data.get("r1-eth200", {})
117+
if not interface_section:
118+
logger.error("Interface r1-eth200 not found. Test cannot continue.")
119+
return
120+
121+
# Get the RA interval
122+
ra_interval = interface_section.get("ndRouterAdvertisementsIntervalSecs")
123+
if ra_interval is None:
124+
# If RA interval isn't found, log a message and exit the test
125+
logger.error(
126+
"Could not find RA interval (ndRouterAdvertisementsIntervalSecs) in interface configuration. Test cannot continue."
127+
)
128+
return
129+
130+
logger.info(f"Using RA interval of {ra_interval} seconds")
131+
132+
# Function to get current RA state - returns the router advertisement sent count
133+
def _get_ra_state():
134+
output = tgen.gears["r1"].vtysh_cmd("show interface r1-eth200 json")
135+
data = json.loads(output)
136+
return data.get("r1-eth200", {}).get("ndRouterAdvertisementsSent")
137+
138+
logger.info("Shutdown r1-eth200")
139+
tgen.gears["r1"].vtysh_cmd(
140+
"""
141+
configure terminal
142+
interface r1-eth200
143+
shutdown
144+
"""
145+
)
146+
147+
# Verify interface is down before proceeding
148+
def _check_interface_down():
149+
output = tgen.gears["r1"].vtysh_cmd("show interface r1-eth200 json")
150+
return True if '"administrativeStatus":"down"' in output else False
151+
152+
_, result = topotest.run_and_expect(_check_interface_down, True, count=10, wait=15)
153+
assert result is True, "Interface r1-eth200 did not go down after shutdown command"
154+
155+
# Take snapshots for RA status when interface is down
156+
ra_sent_count1 = _get_ra_state()
157+
158+
if ra_sent_count1 is None:
159+
logger.error("Could not get RA sent count. Test cannot continue.")
160+
return
161+
162+
# We need to wait for at least ra_interval + buffer time(1 sec) to avoid
163+
# situation where any event was delayed or due to any processing delay
164+
logger.info(f"Waiting another {ra_interval + 1} seconds for RA timer...")
165+
sleep(ra_interval + 1)
166+
ra_sent_count2 = _get_ra_state()
167+
168+
# Verify RA sent count didn't change when interface is down
169+
assert (
170+
ra_sent_count1 == ra_sent_count2
171+
), f"RA sent count should not have changed when interface is down: was {ra_sent_count1}, now {ra_sent_count2}"
172+
173+
logger.info("Do no shutdown for r1-eth200")
174+
tgen.gears["r1"].vtysh_cmd(
175+
"""
176+
configure terminal
177+
interface r1-eth200
178+
no shutdown
179+
"""
180+
)
181+
182+
# Verify interface is up before proceeding
183+
def _check_interface_up():
184+
output = tgen.gears["r1"].vtysh_cmd("show interface r1-eth200 json")
185+
return True if '"administrativeStatus":"up"' in output else False
186+
187+
_, result = topotest.run_and_expect(_check_interface_up, True, count=10, wait=15)
188+
assert result is True, "Interface r1-eth200 did not go up after no shutdown command"
189+
190+
# Take snapshots for RA status when interface is up
191+
ra_sent_count1 = _get_ra_state()
192+
193+
# We need to wait for at least ra_interval + buffer time(1 sec)
194+
logger.info(f"Waiting another {ra_interval + 1} seconds for RA timer...")
195+
sleep(ra_interval + 1)
196+
ra_sent_count2 = _get_ra_state()
197+
198+
# Verify RA sent count changed when interface is up (RAs should be sent)
199+
assert (
200+
ra_sent_count1 != ra_sent_count2
201+
), f"RA sent count should have changed when interface is up: was {ra_sent_count1}, still {ra_sent_count2}"
202+
203+
logger.info("Remove r1-eth200")
204+
existing_config = tgen.gears["r1"].vtysh_cmd("show interface r1-eth200")
205+
tgen.gears["r1"].cmd(
206+
"""
207+
sudo ip link set dev r1-eth200 down
208+
"""
209+
)
210+
211+
# Verify interface is down after ip link set down
212+
_, result = topotest.run_and_expect(_check_interface_down, True, count=10, wait=15)
213+
assert result is True, "Interface r1-eth200 did not go down after ip link set down"
214+
215+
# Get current RA sent count
216+
ra_sent_count1 = _get_ra_state()
217+
218+
# Wait for the RA interval
219+
logger.info(f"Waiting {ra_interval + 1} seconds for RA timer...")
220+
sleep(ra_interval + 1)
221+
222+
# Get second RA sent count
223+
ra_sent_count2 = _get_ra_state()
224+
225+
# Verify counts are the same when interface is down
226+
assert (
227+
ra_sent_count1 == ra_sent_count2
228+
), f"RA sent count changed from {ra_sent_count1} to {ra_sent_count2} within {ra_interval + 1} seconds while interface is down"
229+
230+
tgen.gears["r1"].cmd(
231+
"""
232+
sudo ip link set dev r1-eth200 up
233+
"""
234+
)
235+
236+
# Verify interface is up after ip link set up
237+
_, result = topotest.run_and_expect(_check_interface_up, True, count=10, wait=15)
238+
assert result is True, "Interface r1-eth200 did not go up after ip link set up"
239+
240+
108241
def test_bgp_route_cleanup():
109242
failures = 0
110243
net = get_topogen().net

zebra/interface.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -990,6 +990,7 @@ void if_down(struct interface *ifp)
990990
zif->down_count++;
991991
frr_timestamp(2, zif->down_last, sizeof(zif->down_last));
992992

993+
rtadv_stop_ra(ifp, true);
993994
if_down_nhg_dependents(ifp);
994995

995996
/* Handle interface down for specific types for EVPN. Non-VxLAN
@@ -3706,7 +3707,7 @@ int if_shutdown(struct interface *ifp)
37063707

37073708
if (ifp->ifindex != IFINDEX_INTERNAL) {
37083709
/* send RA lifetime of 0 before stopping. rfc4861/6.2.5 */
3709-
rtadv_stop_ra(ifp);
3710+
rtadv_stop_ra(ifp, false);
37103711
if (if_unset_flags(ifp, IFF_UP) < 0) {
37113712
zlog_debug("Can't shutdown interface %s", ifp->name);
37123713
return -1;

zebra/rtadv.c

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1400,8 +1400,11 @@ static void rtadv_start_interface_events(struct zebra_vrf *zvrf,
14001400
}
14011401

14021402
adv_if = adv_if_add(zvrf, zif->ifp->name);
1403-
if (adv_if != NULL)
1403+
if (adv_if != NULL) {
1404+
rtadv_send_packet(zvrf->rtadv.sock, zif->ifp, RA_ENABLE);
1405+
wheel_add_item(zrouter.ra_wheel, zif->ifp);
14041406
return; /* Already added */
1407+
}
14051408

14061409
if (if_join_all_router(zvrf->rtadv.sock, zif->ifp)) {
14071410
/*Failed to join on 1st attempt, wait random amount of time between 1 ms
@@ -1413,6 +1416,9 @@ static void rtadv_start_interface_events(struct zebra_vrf *zvrf,
14131416

14141417
if (adv_if_list_count(&zvrf->rtadv.adv_if) == 1)
14151418
rtadv_event(zvrf, RTADV_START, 0);
1419+
1420+
rtadv_send_packet(zvrf->rtadv.sock, zif->ifp, RA_ENABLE);
1421+
wheel_add_item(zrouter.ra_wheel, zif->ifp);
14161422
}
14171423

14181424
void ipv6_nd_suppress_ra_set(struct interface *ifp,
@@ -1461,7 +1467,6 @@ void ipv6_nd_suppress_ra_set(struct interface *ifp,
14611467
RTADV_NUM_FAST_REXMITS;
14621468
}
14631469

1464-
wheel_add_item(zrouter.ra_wheel, ifp);
14651470
rtadv_start_interface_events(zvrf, zif);
14661471
}
14671472
}
@@ -1581,20 +1586,25 @@ static void zebra_interface_radv_set(ZAPI_HANDLER_ARGS, int enable)
15811586
* ceasing to advertise and want to let our neighbors know.
15821587
* RFC 4861 secion 6.2.5
15831588
*/
1584-
void rtadv_stop_ra(struct interface *ifp)
1589+
void rtadv_stop_ra(struct interface *ifp, bool if_down_event)
15851590
{
15861591
struct zebra_if *zif;
15871592
struct zebra_vrf *zvrf;
15881593

1589-
zif = ifp->info;
1590-
zvrf = rtadv_interface_get_zvrf(ifp);
1591-
15921594
/*Try to delete from ra wheels */
15931595
wheel_remove_item(zrouter.ra_wheel, ifp);
15941596

1597+
zif = ifp->info;
1598+
zvrf = rtadv_interface_get_zvrf(ifp);
1599+
15951600
/*Turn off event for ICMPv6 join*/
15961601
event_cancel(&zif->icmpv6_join_timer);
15971602

1603+
if (if_down_event) {
1604+
/* Nothing to do more, return */
1605+
return;
1606+
}
1607+
15981608
if (zif->rtadv.AdvSendAdvertisements)
15991609
rtadv_send_packet(zvrf->rtadv.sock, ifp, RA_SUPPRESS);
16001610
}
@@ -1622,7 +1632,7 @@ void rtadv_stop_ra_all(void)
16221632
rprefix)
16231633
rtadv_prefix_reset(zif, rprefix, rprefix);
16241634

1625-
rtadv_stop_ra(ifp);
1635+
rtadv_stop_ra(ifp, false);
16261636
}
16271637
}
16281638

zebra/rtadv.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ enum ipv6_nd_suppress_ra_status {
404404

405405
extern void rtadv_vrf_init(struct zebra_vrf *zvrf);
406406
extern void rtadv_vrf_terminate(struct zebra_vrf *zvrf);
407-
extern void rtadv_stop_ra(struct interface *ifp);
407+
extern void rtadv_stop_ra(struct interface *ifp, bool if_down_event);
408408
extern void rtadv_stop_ra_all(void);
409409
extern void rtadv_cmd_init(void);
410410
extern void rtadv_if_init(struct zebra_if *zif);
@@ -494,7 +494,7 @@ static inline void rtadv_delete_prefix(struct zebra_if *zif,
494494
const struct prefix *p)
495495
{
496496
}
497-
static inline void rtadv_stop_ra(struct interface *ifp)
497+
static inline void rtadv_stop_ra(struct interface *ifp, bool if_down_event)
498498
{
499499
}
500500
static inline void rtadv_stop_ra_all(void)

0 commit comments

Comments
 (0)