/* Order is intentional. Matches RFC4191. This array is also used for
command matching, so only modify with care. */
-const char *rtadv_pref_strs[] = {"medium", "high", "INVALID", "low", 0};
+static const char *const rtadv_pref_strs[] = {
+ "medium", "high", "INVALID", "low", 0
+};
enum rtadv_event {
RTADV_START,
#define RTADV_MSG_SIZE 4096
/* Send router advertisement packet. */
-static void rtadv_send_packet(int sock, struct interface *ifp)
+static void rtadv_send_packet(int sock, struct interface *ifp,
+ ipv6_nd_suppress_ra_status stop)
{
struct msghdr msg;
struct iovec iov;
zif->rtadv.AdvDefaultLifetime != -1
? zif->rtadv.AdvDefaultLifetime
: MAX(1, 0.003 * zif->rtadv.MaxRtrAdvInterval);
- rtadv->nd_ra_router_lifetime = htons(pkt_RouterLifetime);
+
+ /* send RA lifetime of 0 before stopping. rfc4861/6.2.5 */
+ rtadv->nd_ra_router_lifetime =
+ (stop == RA_SUPPRESS) ? htons(0) : htons(pkt_RouterLifetime);
rtadv->nd_ra_reachable = htonl(zif->rtadv.AdvReachableTime);
rtadv->nd_ra_retransmit = htonl(0);
ifp->name);
rtadv_send_packet(rtadv_get_socket(zvrf),
- ifp);
+ ifp, RA_ENABLE);
} else {
zif->rtadv.AdvIntervalTimer -= period;
if (zif->rtadv.AdvIntervalTimer <= 0) {
.MaxRtrAdvInterval;
rtadv_send_packet(
rtadv_get_socket(zvrf),
- ifp);
+ ifp, RA_ENABLE);
}
}
}
if ((zif->rtadv.UseFastRexmit)
|| (zif->rtadv.AdvIntervalTimer <=
(zif->rtadv.MaxRtrAdvInterval - MIN_DELAY_BETWEEN_RAS))) {
- rtadv_send_packet(rtadv_get_socket(zvrf), ifp);
+ rtadv_send_packet(rtadv_get_socket(zvrf), ifp, RA_ENABLE);
zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
} else
zif->rtadv.AdvIntervalTimer = MIN_DELAY_BETWEEN_RAS;
if (status == RA_SUPPRESS) {
/* RA is currently enabled */
if (zif->rtadv.AdvSendAdvertisements) {
+ rtadv_send_packet(rtadv_get_socket(zvrf), ifp,
+ RA_SUPPRESS);
zif->rtadv.AdvSendAdvertisements = 0;
zif->rtadv.AdvIntervalTimer = 0;
zvrf->rtadv.adv_if_count--;
ifindex_t ifindex;
struct interface *ifp;
struct zebra_if *zif;
- int ra_interval;
+ int ra_interval_rxd;
s = msg;
/* Get interface index and RA interval. */
STREAM_GETL(s, ifindex);
- STREAM_GETL(s, ra_interval);
+ STREAM_GETL(s, ra_interval_rxd);
+
+ if (ra_interval_rxd < 0) {
+ zlog_warn(
+ "Requested RA interval %d is garbage; ignoring request",
+ ra_interval_rxd);
+ return;
+ }
+
+ unsigned int ra_interval = ra_interval_rxd;
if (IS_ZEBRA_DEBUG_EVENT)
- zlog_debug("%u: IF %u RA %s from client %s, interval %ds",
+ zlog_debug("%u: IF %u RA %s from client %s, interval %ums",
zvrf_id(zvrf), ifindex,
enable ? "enable" : "disable",
zebra_route_string(client->proto), ra_interval);
SET_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED);
ipv6_nd_suppress_ra_set(ifp, RA_ENABLE);
if (ra_interval
- && (ra_interval * 1000) < zif->rtadv.MaxRtrAdvInterval
+ && (ra_interval * 1000) < (unsigned int) zif->rtadv.MaxRtrAdvInterval
&& !CHECK_FLAG(zif->rtadv.ra_configured,
VTY_RA_INTERVAL_CONFIGURED))
zif->rtadv.MaxRtrAdvInterval = ra_interval * 1000;
return;
}
+/*
+ * send router lifetime value of zero in RAs on this interface since we're
+ * ceasing to advertise and want to let our neighbors know.
+ * RFC 4861 secion 6.2.5
+ */
+void rtadv_stop_ra(struct interface *ifp)
+{
+ struct zebra_if *zif;
+ struct zebra_vrf *zvrf;
+
+ zif = ifp->info;
+ zvrf = vrf_info_lookup(ifp->vrf_id);
+
+ if (zif->rtadv.AdvSendAdvertisements)
+ rtadv_send_packet(rtadv_get_socket(zvrf), ifp, RA_SUPPRESS);
+}
+
+/*
+ * send router lifetime value of zero in RAs on all interfaces since we're
+ * ceasing to advertise globally and want to let all of our neighbors know
+ * RFC 4861 secion 6.2.5
+ */
+void rtadv_stop_ra_all(void)
+{
+ struct vrf *vrf;
+ struct interface *ifp;
+
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name)
+ FOR_ALL_INTERFACES (vrf, ifp)
+ rtadv_stop_ra(ifp);
+}
+
void zebra_interface_radv_disable(ZAPI_HANDLER_ARGS)
{
zebra_interface_radv_set(client, hdr, msg, zvrf, 0);