diff --git a/zebra/main.c b/zebra/main.c index e36af51005..bded50149f 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -186,7 +186,6 @@ static void sigint(void) work_queue_free_and_null(&zrouter.lsp_process_q); vrf_terminate(); - rtadv_terminate(); ns_walk_func(zebra_ns_early_shutdown, NULL, NULL); zebra_ns_notify_close(); diff --git a/zebra/rib.h b/zebra/rib.h index 75d7ae1b67..d72bb672c6 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -288,16 +288,30 @@ DECLARE_LIST(re_list, struct route_entry, next); #define RNODE_NEXT_RE(rn, re) RE_DEST_NEXT_ROUTE(rib_dest_from_rnode(rn), re) #if defined(HAVE_RTADV) +PREDECL_SORTLIST_UNIQ(adv_if_list); /* Structure which hold status of router advertisement. */ struct rtadv { int sock; - int adv_if_count; - int adv_msec_if_count; + struct adv_if_list_head adv_if; + struct adv_if_list_head adv_msec_if; struct thread *ra_read; struct thread *ra_timer; }; + +/* adv list node */ +struct adv_if { + char name[INTERFACE_NAMSIZ]; + struct adv_if_list_item list_item; +}; + +static int adv_if_cmp(const struct adv_if *a, const struct adv_if *b) +{ + return if_cmp_name_func(a->name, b->name); +} + +DECLARE_SORTLIST_UNIQ(adv_if_list, struct adv_if, list_item, adv_if_cmp); #endif /* HAVE_RTADV */ /* diff --git a/zebra/rtadv.c b/zebra/rtadv.c index 1e06b3e0e9..8d57ab6a7c 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -54,6 +54,7 @@ extern struct zebra_privs_t zserv_privs; #endif DEFINE_MTYPE_STATIC(ZEBRA, RTADV_PREFIX, "Router Advertisement Prefix"); +DEFINE_MTYPE_STATIC(ZEBRA, ADV_IF, "Advertised Interface"); #ifdef OPEN_BSD #include @@ -92,11 +93,13 @@ static void rtadv_event(struct zebra_vrf *, enum rtadv_event, int); static int if_join_all_router(int, struct interface *); static int if_leave_all_router(int, struct interface *); -static int rtadv_get_socket(struct zebra_vrf *zvrf) +static struct zebra_vrf *rtadv_interface_get_zvrf(const struct interface *ifp) { - if (zvrf->rtadv.sock > 0) - return zvrf->rtadv.sock; - return zrouter.rtadv_sock; + /* We use the default vrf for rtadv handling except in netns */ + if (!vrf_is_backend_netns()) + return vrf_info_lookup(VRF_DEFAULT); + + return vrf_info_lookup(ifp->vrf_id); } static int rtadv_increment_received(struct zebra_vrf *zvrf, ifindex_t *ifindex) @@ -480,7 +483,7 @@ static int rtadv_timer(struct thread *thread) int period; zvrf->rtadv.ra_timer = NULL; - if (zvrf->rtadv.adv_msec_if_count == 0) { + if (adv_if_list_count(&zvrf->rtadv.adv_msec_if) == 0) { period = 1000; /* 1 s */ rtadv_event(zvrf, RTADV_TIMER, 1 /* 1 s */); } else { @@ -520,8 +523,8 @@ static int rtadv_timer(struct thread *thread) ifp->ifindex); } - rtadv_send_packet(rtadv_get_socket(zvrf), - ifp, RA_ENABLE); + rtadv_send_packet(zvrf->rtadv.sock, ifp, + RA_ENABLE); } else { zif->rtadv.AdvIntervalTimer -= period; if (zif->rtadv.AdvIntervalTimer <= 0) { @@ -534,8 +537,8 @@ static int rtadv_timer(struct thread *thread) zif->rtadv .MaxRtrAdvInterval; rtadv_send_packet( - rtadv_get_socket(zvrf), - ifp, RA_ENABLE); + zvrf->rtadv.sock, ifp, + RA_ENABLE); } } } @@ -546,9 +549,10 @@ static int rtadv_timer(struct thread *thread) static void rtadv_process_solicit(struct interface *ifp) { - struct zebra_vrf *zvrf = vrf_info_lookup(ifp->vrf_id); + struct zebra_vrf *zvrf; struct zebra_if *zif; + zvrf = rtadv_interface_get_zvrf(ifp); assert(zvrf); zif = ifp->info; @@ -565,7 +569,7 @@ static void rtadv_process_solicit(struct interface *ifp) if ((zif->rtadv.UseFastRexmit) || (zif->rtadv.AdvIntervalTimer <= (zif->rtadv.MaxRtrAdvInterval - MIN_DELAY_BETWEEN_RAS))) { - rtadv_send_packet(rtadv_get_socket(zvrf), ifp, RA_ENABLE); + rtadv_send_packet(zvrf->rtadv.sock, ifp, RA_ENABLE); zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval; } else zif->rtadv.AdvIntervalTimer = MIN_DELAY_BETWEEN_RAS; @@ -788,7 +792,7 @@ static int rtadv_read(struct thread *thread) zvrf->rtadv.ra_read = NULL; /* Register myself. */ - rtadv_event(zvrf, RTADV_READ, sock); + rtadv_event(zvrf, RTADV_READ, 0); len = rtadv_recv_packet(zvrf, sock, buf, sizeof(buf), &from, &ifindex, &hoplimit); @@ -862,6 +866,201 @@ static int rtadv_make_socket(ns_id_t ns_id) return sock; } +static struct adv_if *adv_if_new(const char *name) +{ + struct adv_if *new; + + new = XCALLOC(MTYPE_ADV_IF, sizeof(struct adv_if)); + + strlcpy(new->name, name, sizeof(new->name)); + + return new; +} + +static void adv_if_free(struct adv_if *adv_if) +{ + XFREE(MTYPE_ADV_IF, adv_if); +} + +static bool adv_if_is_empty_internal(struct adv_if_list_head *adv_if_head) +{ + return adv_if_list_count(adv_if_head) ? false : true; +} + +static struct adv_if *adv_if_add_internal(struct adv_if_list_head *adv_if_head, + const char *name) +{ + struct adv_if adv_if_lookup = {}; + struct adv_if *adv_if = NULL; + + strlcpy(adv_if_lookup.name, name, sizeof(adv_if_lookup.name)); + adv_if = adv_if_list_find(adv_if_head, &adv_if_lookup); + + if (adv_if != NULL) + return adv_if; + + adv_if = adv_if_new(adv_if_lookup.name); + adv_if_list_add(adv_if_head, adv_if); + + return NULL; +} + +static struct adv_if *adv_if_del_internal(struct adv_if_list_head *adv_if_head, + const char *name) +{ + struct adv_if adv_if_lookup = {}; + struct adv_if *adv_if = NULL; + + strlcpy(adv_if_lookup.name, name, sizeof(adv_if_lookup.name)); + adv_if = adv_if_list_find(adv_if_head, &adv_if_lookup); + + if (adv_if == NULL) + return NULL; + + adv_if_list_del(adv_if_head, adv_if); + + return adv_if; +} + +static void adv_if_clean_internal(struct adv_if_list_head *adv_if_head) +{ + struct adv_if *node = NULL; + + if (!adv_if_is_empty_internal(adv_if_head)) { + frr_each_safe (adv_if_list, adv_if_head, node) { + adv_if_list_del(adv_if_head, node); + adv_if_free(node); + } + } + + adv_if_list_fini(adv_if_head); +} + + +/* + * Add to list. On Success, return NULL, otherwise return already existing + * adv_if. + */ +static struct adv_if *adv_if_add(struct zebra_vrf *zvrf, const char *name) +{ + struct adv_if *adv_if = NULL; + + adv_if = adv_if_add_internal(&zvrf->rtadv.adv_if, name); + + if (adv_if != NULL) + return adv_if; + + if (IS_ZEBRA_DEBUG_EVENT) { + struct vrf *vrf = zvrf->vrf; + + zlog_debug("%s: %s:%u IF %s count: %lu", __func__, + VRF_LOGNAME(vrf), zvrf_id(zvrf), name, + adv_if_list_count(&zvrf->rtadv.adv_if)); + } + + return NULL; +} + +/* + * Del from list. On Success, return the adv_if, otherwise return NULL. Caller + * frees. + */ +static struct adv_if *adv_if_del(struct zebra_vrf *zvrf, const char *name) +{ + struct adv_if *adv_if = NULL; + + adv_if = adv_if_del_internal(&zvrf->rtadv.adv_if, name); + + if (adv_if == NULL) + return NULL; + + if (IS_ZEBRA_DEBUG_EVENT) { + struct vrf *vrf = zvrf->vrf; + + zlog_debug("%s: %s:%u IF %s count: %lu", __func__, + VRF_LOGNAME(vrf), zvrf_id(zvrf), name, + adv_if_list_count(&zvrf->rtadv.adv_if)); + } + + return adv_if; +} + +/* + * Add to list. On Success, return NULL, otherwise return already existing + * adv_if. + */ +static struct adv_if *adv_msec_if_add(struct zebra_vrf *zvrf, const char *name) +{ + struct adv_if *adv_if = NULL; + + adv_if = adv_if_add_internal(&zvrf->rtadv.adv_msec_if, name); + + if (adv_if != NULL) + return adv_if; + + if (IS_ZEBRA_DEBUG_EVENT) { + struct vrf *vrf = zvrf->vrf; + + zlog_debug("%s: %s:%u IF %s count: %lu", __func__, + VRF_LOGNAME(vrf), zvrf_id(zvrf), name, + adv_if_list_count(&zvrf->rtadv.adv_msec_if)); + } + + return NULL; +} + +/* + * Del from list. On Success, return the adv_if, otherwise return NULL. Caller + * frees. + */ +static struct adv_if *adv_msec_if_del(struct zebra_vrf *zvrf, const char *name) +{ + struct adv_if *adv_if = NULL; + + adv_if = adv_if_del_internal(&zvrf->rtadv.adv_msec_if, name); + + if (adv_if == NULL) + return NULL; + + if (IS_ZEBRA_DEBUG_EVENT) { + struct vrf *vrf = zvrf->vrf; + + zlog_debug("%s: %s:%u IF %s count: %lu", __func__, + VRF_LOGNAME(vrf), zvrf_id(zvrf), name, + adv_if_list_count(&zvrf->rtadv.adv_msec_if)); + } + + return adv_if; +} + +/* Clean adv_if list, called on vrf terminate */ +static void adv_if_clean(struct zebra_vrf *zvrf) +{ + if (IS_ZEBRA_DEBUG_EVENT) { + struct vrf *vrf = zvrf->vrf; + + zlog_debug("%s: %s:%u count: %lu -> 0", __func__, + VRF_LOGNAME(vrf), zvrf_id(zvrf), + adv_if_list_count(&zvrf->rtadv.adv_if)); + } + + adv_if_clean_internal(&zvrf->rtadv.adv_if); +} + +/* Clean adv_msec_if list, called on vrf terminate */ +static void adv_msec_if_clean(struct zebra_vrf *zvrf) +{ + if (IS_ZEBRA_DEBUG_EVENT) { + struct vrf *vrf = zvrf->vrf; + + zlog_debug("%s: %s:%u count: %lu -> 0", __func__, + VRF_LOGNAME(vrf), zvrf_id(zvrf), + adv_if_list_count(&zvrf->rtadv.adv_msec_if)); + } + + adv_if_clean_internal(&zvrf->rtadv.adv_msec_if); +} + static struct rtadv_prefix *rtadv_prefix_new(void) { return XCALLOC(MTYPE_RTADV_PREFIX, sizeof(struct rtadv_prefix)); @@ -1006,30 +1205,34 @@ static void ipv6_nd_suppress_ra_set(struct interface *ifp, { struct zebra_if *zif; struct zebra_vrf *zvrf; + struct adv_if *adv_if = NULL; zif = ifp->info; - zvrf = vrf_info_lookup(ifp->vrf_id); + + zvrf = rtadv_interface_get_zvrf(ifp); if (status == RA_SUPPRESS) { /* RA is currently enabled */ if (zif->rtadv.AdvSendAdvertisements) { - rtadv_send_packet(rtadv_get_socket(zvrf), ifp, - RA_SUPPRESS); + rtadv_send_packet(zvrf->rtadv.sock, ifp, RA_SUPPRESS); zif->rtadv.AdvSendAdvertisements = 0; zif->rtadv.AdvIntervalTimer = 0; - zvrf->rtadv.adv_if_count--; - if_leave_all_router(rtadv_get_socket(zvrf), ifp); + adv_if = adv_if_del(zvrf, ifp->name); + if (adv_if == NULL) + return; /* Nothing to delete */ - if (zvrf->rtadv.adv_if_count == 0) + adv_if_free(adv_if); + + if_leave_all_router(zvrf->rtadv.sock, ifp); + + if (adv_if_list_count(&zvrf->rtadv.adv_if) == 0) rtadv_event(zvrf, RTADV_STOP, 0); } } else { if (!zif->rtadv.AdvSendAdvertisements) { zif->rtadv.AdvSendAdvertisements = 1; zif->rtadv.AdvIntervalTimer = 0; - zvrf->rtadv.adv_if_count++; - if ((zif->rtadv.MaxRtrAdvInterval >= 1000) && zif->rtadv.UseFastRexmit) { /* @@ -1041,11 +1244,14 @@ static void ipv6_nd_suppress_ra_set(struct interface *ifp, RTADV_NUM_FAST_REXMITS; } - if_join_all_router(rtadv_get_socket(zvrf), ifp); + adv_if = adv_if_add(zvrf, ifp->name); + if (adv_if != NULL) + return; /* Alread added */ - if (zvrf->rtadv.adv_if_count == 1) - rtadv_event(zvrf, RTADV_START, - rtadv_get_socket(zvrf)); + if_join_all_router(zvrf->rtadv.sock, ifp); + + if (adv_if_list_count(&zvrf->rtadv.adv_if) == 1) + rtadv_event(zvrf, RTADV_START, 0); } } } @@ -1092,7 +1298,7 @@ static void zebra_interface_radv_set(ZAPI_HANDLER_ARGS, int enable) zebra_route_string(client->proto)); return; } - if (ifp->vrf_id != zvrf_id(zvrf)) { + if (vrf_is_backend_netns() && ifp->vrf_id != zvrf_id(zvrf)) { struct vrf *vrf = zvrf->vrf; zlog_debug( @@ -1136,10 +1342,10 @@ void rtadv_stop_ra(struct interface *ifp) struct zebra_vrf *zvrf; zif = ifp->info; - zvrf = vrf_info_lookup(ifp->vrf_id); + zvrf = rtadv_interface_get_zvrf(ifp); if (zif->rtadv.AdvSendAdvertisements) - rtadv_send_packet(rtadv_get_socket(zvrf), ifp, RA_SUPPRESS); + rtadv_send_packet(zvrf->rtadv.sock, ifp, RA_SUPPRESS); } /* @@ -1379,8 +1585,9 @@ DEFUN (ipv6_nd_ra_interval_msec, unsigned interval; struct zebra_if *zif = ifp->info; struct zebra_vrf *zvrf; + struct adv_if *adv_if; - zvrf = vrf_info_lookup(ifp->vrf_id); + zvrf = rtadv_interface_get_zvrf(ifp); interval = strtoul(argv[idx_number]->arg, NULL, 10); if ((zif->rtadv.AdvDefaultLifetime != -1 @@ -1390,11 +1597,14 @@ DEFUN (ipv6_nd_ra_interval_msec, return CMD_WARNING_CONFIG_FAILED; } - if (zif->rtadv.MaxRtrAdvInterval % 1000) - zvrf->rtadv.adv_msec_if_count--; + if (zif->rtadv.MaxRtrAdvInterval % 1000) { + adv_if = adv_msec_if_del(zvrf, ifp->name); + if (adv_if != NULL) + adv_if_free(adv_if); + } if (interval % 1000) - zvrf->rtadv.adv_msec_if_count++; + (void)adv_msec_if_add(zvrf, ifp->name); SET_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED); zif->rtadv.MaxRtrAdvInterval = interval; @@ -1417,8 +1627,9 @@ DEFUN (ipv6_nd_ra_interval, unsigned interval; struct zebra_if *zif = ifp->info; struct zebra_vrf *zvrf; + struct adv_if *adv_if; - zvrf = vrf_info_lookup(ifp->vrf_id); + zvrf = rtadv_interface_get_zvrf(ifp); interval = strtoul(argv[idx_number]->arg, NULL, 10); if ((zif->rtadv.AdvDefaultLifetime != -1 @@ -1428,8 +1639,11 @@ DEFUN (ipv6_nd_ra_interval, return CMD_WARNING_CONFIG_FAILED; } - if (zif->rtadv.MaxRtrAdvInterval % 1000) - zvrf->rtadv.adv_msec_if_count--; + if (zif->rtadv.MaxRtrAdvInterval % 1000) { + adv_if = adv_msec_if_del(zvrf, ifp->name); + if (adv_if != NULL) + adv_if_free(adv_if); + } /* convert to milliseconds */ interval = interval * 1000; @@ -1456,11 +1670,15 @@ DEFUN (no_ipv6_nd_ra_interval, VTY_DECLVAR_CONTEXT(interface, ifp); struct zebra_if *zif = ifp->info; struct zebra_vrf *zvrf = NULL; + struct adv_if *adv_if; - zvrf = vrf_info_lookup(ifp->vrf_id); + zvrf = rtadv_interface_get_zvrf(ifp); - if (zif->rtadv.MaxRtrAdvInterval % 1000) - zvrf->rtadv.adv_msec_if_count--; + if (zif->rtadv.MaxRtrAdvInterval % 1000) { + adv_if = adv_msec_if_del(zvrf, ifp->name); + if (adv_if != NULL) + adv_if_free(adv_if); + } UNSET_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED); @@ -2451,7 +2669,7 @@ static int rtadv_config_write(struct vty *vty, struct interface *ifp) static void rtadv_event(struct zebra_vrf *zvrf, enum rtadv_event event, int val) { - struct rtadv *rtadv = &zvrf->rtadv; + struct rtadv *rtadv; if (IS_ZEBRA_DEBUG_EVENT) { struct vrf *vrf = zvrf->vrf; @@ -2460,9 +2678,11 @@ static void rtadv_event(struct zebra_vrf *zvrf, enum rtadv_event event, int val) VRF_LOGNAME(vrf), event, val); } + rtadv = &zvrf->rtadv; + switch (event) { case RTADV_START: - thread_add_read(zrouter.master, rtadv_read, zvrf, val, + thread_add_read(zrouter.master, rtadv_read, zvrf, rtadv->sock, &rtadv->ra_read); thread_add_event(zrouter.master, rtadv_timer, zvrf, 0, &rtadv->ra_timer); @@ -2480,7 +2700,7 @@ static void rtadv_event(struct zebra_vrf *zvrf, enum rtadv_event event, int val) &rtadv->ra_timer); break; case RTADV_READ: - thread_add_read(zrouter.master, rtadv_read, zvrf, val, + thread_add_read(zrouter.master, rtadv_read, zvrf, rtadv->sock, &rtadv->ra_read); break; default: @@ -2489,37 +2709,27 @@ static void rtadv_event(struct zebra_vrf *zvrf, enum rtadv_event event, int val) return; } -void rtadv_init(struct zebra_vrf *zvrf) +void rtadv_vrf_init(struct zebra_vrf *zvrf) { - if (vrf_is_backend_netns()) { - zvrf->rtadv.sock = rtadv_make_socket(zvrf->zns->ns_id); - zrouter.rtadv_sock = -1; - } else { - zvrf->rtadv.sock = -1; - if (zrouter.rtadv_sock < 0) - zrouter.rtadv_sock = - rtadv_make_socket(zvrf->zns->ns_id); - } + if (!vrf_is_backend_netns() && (zvrf_id(zvrf) != VRF_DEFAULT)) + return; + + zvrf->rtadv.sock = rtadv_make_socket(zvrf->zns->ns_id); } void rtadv_vrf_terminate(struct zebra_vrf *zvrf) { + if (!vrf_is_backend_netns() && (zvrf_id(zvrf) != VRF_DEFAULT)) + return; + rtadv_event(zvrf, RTADV_STOP, 0); if (zvrf->rtadv.sock >= 0) { close(zvrf->rtadv.sock); zvrf->rtadv.sock = -1; } - zvrf->rtadv.adv_if_count = 0; - zvrf->rtadv.adv_msec_if_count = 0; -} - -void rtadv_terminate(void) -{ - if (zrouter.rtadv_sock >= 0) { - close(zrouter.rtadv_sock); - zrouter.rtadv_sock = -1; - } + adv_if_clean(zvrf); + adv_msec_if_clean(zvrf); } void rtadv_cmd_init(void) @@ -2629,14 +2839,11 @@ static int if_leave_all_router(int sock, struct interface *ifp) } #else -void rtadv_init(struct zebra_vrf *zvrf) -{ - /* Empty.*/; -} -void rtadv_terminate(void) +void rtadv_vrf_init(struct zebra_vrf *zvrf) { /* Empty.*/; } + void rtadv_cmd_init(void) { /* Empty.*/; diff --git a/zebra/rtadv.h b/zebra/rtadv.h index d7a1ccfb29..7b71ee45a2 100644 --- a/zebra/rtadv.h +++ b/zebra/rtadv.h @@ -152,9 +152,8 @@ enum ipv6_nd_suppress_ra_status { RA_SUPPRESS, }; -extern void rtadv_init(struct zebra_vrf *zvrf); +extern void rtadv_vrf_init(struct zebra_vrf *zvrf); extern void rtadv_vrf_terminate(struct zebra_vrf *zvrf); -extern void rtadv_terminate(void); extern void rtadv_stop_ra(struct interface *ifp); extern void rtadv_stop_ra_all(void); extern void rtadv_cmd_init(void); diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c index 5a00f3155d..d930f59866 100644 --- a/zebra/zebra_router.c +++ b/zebra/zebra_router.c @@ -268,8 +268,6 @@ void zebra_router_init(bool asic_offload, bool notify_on_ack) zrouter.packets_to_process = ZEBRA_ZAPI_PACKETS_TO_PROCESS; - zrouter.rtadv_sock = -1; - zebra_vxlan_init(); zebra_mlag_init(); diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h index 08c5fcaf8d..408f9cbee5 100644 --- a/zebra/zebra_router.h +++ b/zebra/zebra_router.h @@ -162,9 +162,6 @@ struct zebra_router { struct hash *iptable_hash; - /* used if vrf backend is not network namespace */ - int rtadv_sock; - /* A sequence number used for tracking routes */ _Atomic uint32_t sequence_num; diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index a0c63e4202..2430b51989 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -131,7 +131,7 @@ static int zebra_vrf_enable(struct vrf *vrf) else zvrf->zns = zebra_ns_lookup(NS_DEFAULT); #if defined(HAVE_RTADV) - rtadv_init(zvrf); + rtadv_vrf_init(zvrf); #endif /* Inform clients that the VRF is now active. This is an