#if defined(HAVE_RTADV)
-#ifndef VTYSH_EXTRACT_PL
#include "zebra/rtadv_clippy.c"
-#endif
DEFINE_MTYPE_STATIC(ZEBRA, RTADV_PREFIX, "Router Advertisement Prefix");
DEFINE_MTYPE_STATIC(ZEBRA, ADV_IF, "Advertised Interface");
#define ALLNODE "ff02::1"
#define ALLROUTER "ff02::2"
+/* 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);
+
+static int rtadv_prefix_cmp(const struct rtadv_prefix *a,
+ const struct rtadv_prefix *b)
+{
+ return prefix_cmp(&a->prefix, &b->prefix);
+}
+
+DECLARE_RBTREE_UNIQ(rtadv_prefixes, struct rtadv_prefix, item,
+ rtadv_prefix_cmp);
+
DEFINE_MTYPE_STATIC(ZEBRA, RTADV_RDNSS, "Router Advertisement RDNSS");
DEFINE_MTYPE_STATIC(ZEBRA, RTADV_DNSSL, "Router Advertisement DNSSL");
adata = calloc(1, CMSG_SPACE(sizeof(struct in6_pktinfo)));
if (adata == NULL) {
- zlog_debug(
- "rtadv_send_packet: can't malloc control data");
+ zlog_debug("%s: can't malloc control data", __func__);
exit(-1);
}
}
}
/* Fill in prefix. */
- for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvPrefixList, node, rprefix)) {
+ frr_each (rtadv_prefixes, zif->rtadv.prefixes, rprefix) {
struct nd_opt_prefix_info *pinfo;
pinfo = (struct nd_opt_prefix_info *)(buf + len);
zif->rtadv.lastadvcurhoplimit.tv_sec == 0)) {
flog_warn(
EC_ZEBRA_RA_PARAM_MISMATCH,
- "%s(%u): Rx RA - our AdvCurHopLimit doesn't agree with %s",
- ifp->name, ifp->ifindex, addr_str);
+ "%s(%u): Rx RA - our AdvCurHopLimit (%u) doesn't agree with %s (%u)",
+ ifp->name, ifp->ifindex, zif->rtadv.AdvCurHopLimit,
+ addr_str, radvert->nd_ra_curhoplimit);
monotime(&zif->rtadv.lastadvcurhoplimit);
}
zif->rtadv.lastadvmanagedflag.tv_sec == 0)) {
flog_warn(
EC_ZEBRA_RA_PARAM_MISMATCH,
- "%s(%u): Rx RA - our AdvManagedFlag doesn't agree with %s",
- ifp->name, ifp->ifindex, addr_str);
+ "%s(%u): Rx RA - our AdvManagedFlag (%u) doesn't agree with %s (%u)",
+ ifp->name, ifp->ifindex, zif->rtadv.AdvManagedFlag,
+ addr_str,
+ !!CHECK_FLAG(radvert->nd_ra_flags_reserved,
+ ND_RA_FLAG_MANAGED));
monotime(&zif->rtadv.lastadvmanagedflag);
}
zif->rtadv.lastadvotherconfigflag.tv_sec == 0)) {
flog_warn(
EC_ZEBRA_RA_PARAM_MISMATCH,
- "%s(%u): Rx RA - our AdvOtherConfigFlag doesn't agree with %s",
- ifp->name, ifp->ifindex, addr_str);
+ "%s(%u): Rx RA - our AdvOtherConfigFlag (%u) doesn't agree with %s (%u)",
+ ifp->name, ifp->ifindex, zif->rtadv.AdvOtherConfigFlag,
+ addr_str,
+ !!CHECK_FLAG(radvert->nd_ra_flags_reserved,
+ ND_RA_FLAG_OTHER));
monotime(&zif->rtadv.lastadvotherconfigflag);
}
zif->rtadv.lastadvreachabletime.tv_sec == 0)) {
flog_warn(
EC_ZEBRA_RA_PARAM_MISMATCH,
- "%s(%u): Rx RA - our AdvReachableTime doesn't agree with %s",
- ifp->name, ifp->ifindex, addr_str);
+ "%s(%u): Rx RA - our AdvReachableTime (%u) doesn't agree with %s (%u)",
+ ifp->name, ifp->ifindex, zif->rtadv.AdvReachableTime,
+ addr_str, ntohl(radvert->nd_ra_reachable));
monotime(&zif->rtadv.lastadvreachabletime);
}
- if ((ntohl(radvert->nd_ra_retransmit) !=
+ if ((radvert->nd_ra_retransmit && zif->rtadv.AdvRetransTimer) &&
+ (ntohl(radvert->nd_ra_retransmit) !=
(unsigned int)zif->rtadv.AdvRetransTimer) &&
(monotime_since(&zif->rtadv.lastadvretranstimer, NULL) >
SIXHOUR2USEC ||
zif->rtadv.lastadvretranstimer.tv_sec == 0)) {
flog_warn(
EC_ZEBRA_RA_PARAM_MISMATCH,
- "%s(%u): Rx RA - our AdvRetransTimer doesn't agree with %s",
- ifp->name, ifp->ifindex, addr_str);
+ "%s(%u): Rx RA - our AdvRetransTimer (%u) doesn't agree with %s (%u)",
+ ifp->name, ifp->ifindex, zif->rtadv.AdvRetransTimer,
+ addr_str, ntohl(radvert->nd_ra_retransmit));
monotime(&zif->rtadv.lastadvretranstimer);
}
int sock = -1;
int ret = 0;
struct icmp6_filter filter;
+ int error;
frr_with_privs(&zserv_privs) {
sock = ns_socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6, ns_id);
-
+ /*
+ * with privs might set errno too if it fails save
+ * to the side
+ */
+ error = errno;
}
if (sock < 0) {
+ zlog_warn("RTADV socket for ns: %u failure to create: %s(%u)",
+ ns_id, safe_strerror(error), error);
return -1;
}
ret = setsockopt_ipv6_pktinfo(sock, 1);
if (ret < 0) {
+ zlog_warn("RTADV failure to set Packet Information");
close(sock);
return ret;
}
ret = setsockopt_ipv6_multicast_loop(sock, 0);
if (ret < 0) {
+ zlog_warn("RTADV failure to set multicast Loop detection");
close(sock);
return ret;
}
ret = setsockopt_ipv6_unicast_hops(sock, 255);
if (ret < 0) {
+ zlog_warn("RTADV failure to set maximum unicast hops");
close(sock);
return ret;
}
ret = setsockopt_ipv6_multicast_hops(sock, 255);
if (ret < 0) {
+ zlog_warn("RTADV failure to set maximum multicast hops");
close(sock);
return ret;
}
ret = setsockopt_ipv6_hoplimit(sock, 1);
if (ret < 0) {
+ zlog_warn("RTADV failure to set maximum incoming hop limit");
close(sock);
return ret;
}
XFREE(MTYPE_RTADV_PREFIX, rtadv_prefix);
}
-static struct rtadv_prefix *rtadv_prefix_lookup(struct list *rplist,
- struct prefix_ipv6 *p)
-{
- struct listnode *node;
- struct rtadv_prefix *rprefix;
-
- for (ALL_LIST_ELEMENTS_RO(rplist, node, rprefix))
- if (prefix_same((struct prefix *)&rprefix->prefix,
- (struct prefix *)p))
- return rprefix;
- return NULL;
-}
-
-static struct rtadv_prefix *rtadv_prefix_get(struct list *rplist,
+static struct rtadv_prefix *rtadv_prefix_get(struct rtadv_prefixes_head *list,
struct prefix_ipv6 *p)
{
- struct rtadv_prefix *rprefix;
+ struct rtadv_prefix *rprefix, ref;
+
+ ref.prefix = *p;
- rprefix = rtadv_prefix_lookup(rplist, p);
+ rprefix = rtadv_prefixes_find(list, &ref);
if (rprefix)
return rprefix;
rprefix = rtadv_prefix_new();
memcpy(&rprefix->prefix, p, sizeof(struct prefix_ipv6));
- listnode_add(rplist, rprefix);
+ rtadv_prefixes_add(list, rprefix);
return rprefix;
}
{
struct rtadv_prefix *rprefix;
- rprefix = rtadv_prefix_get(zif->rtadv.AdvPrefixList, &rp->prefix);
+ rprefix = rtadv_prefix_get(zif->rtadv.prefixes, &rp->prefix);
/*
* Set parameters based on where the prefix is created.
{
struct rtadv_prefix *rprefix;
- rprefix = rtadv_prefix_lookup(zif->rtadv.AdvPrefixList, &rp->prefix);
+ rprefix = rtadv_prefixes_find(zif->rtadv.prefixes, rp);
if (rprefix != NULL) {
/*
}
}
- listnode_delete(zif->rtadv.AdvPrefixList, (void *)rprefix);
+ rtadv_prefixes_del(zif->rtadv.prefixes, rprefix);
rtadv_prefix_free(rprefix);
return 1;
} else
rtadv_prefix_reset(zif, &rp);
}
+static void rtadv_start_interface_events(struct zebra_vrf *zvrf,
+ struct zebra_if *zif)
+{
+ struct adv_if *adv_if = NULL;
+
+ if (zif->ifp->ifindex == IFINDEX_INTERNAL) {
+ if (IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug(
+ "%s(%s) has not configured an ifindex yet, delaying until we have one",
+ zif->ifp->name, zvrf->vrf->name);
+ return;
+ }
+
+ adv_if = adv_if_add(zvrf, zif->ifp->name);
+ if (adv_if != NULL)
+ return; /* Already added */
+
+ if_join_all_router(zvrf->rtadv.sock, zif->ifp);
+
+ if (adv_if_list_count(&zvrf->rtadv.adv_if) == 1)
+ rtadv_event(zvrf, RTADV_START, 0);
+}
+
static void ipv6_nd_suppress_ra_set(struct interface *ifp,
enum ipv6_nd_suppress_ra_status status)
{
RTADV_NUM_FAST_REXMITS;
}
- adv_if = adv_if_add(zvrf, ifp->name);
- if (adv_if != NULL)
- return; /* Alread added */
-
- if_join_all_router(zvrf->rtadv.sock, ifp);
-
- if (adv_if_list_count(&zvrf->rtadv.adv_if) == 1)
- rtadv_event(zvrf, RTADV_START, 0);
+ rtadv_start_interface_events(zvrf, zif);
}
}
}
{
struct vrf *vrf;
struct interface *ifp;
- struct listnode *node, *nnode;
struct zebra_if *zif;
struct rtadv_prefix *rprefix;
FOR_ALL_INTERFACES (vrf, ifp) {
zif = ifp->info;
- for (ALL_LIST_ELEMENTS(zif->rtadv.AdvPrefixList,
- node, nnode, rprefix))
+ frr_each_safe (rtadv_prefixes, zif->rtadv.prefixes,
+ rprefix)
rtadv_prefix_reset(zif, rprefix);
rtadv_stop_ra(ifp);
if (zif->rtadv.AdvLinkMTU)
vty_out(vty, " ipv6 nd mtu %d\n", zif->rtadv.AdvLinkMTU);
- for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvPrefixList, node, rprefix)) {
+ frr_each (rtadv_prefixes, zif->rtadv.prefixes, rprefix) {
if ((rprefix->AdvPrefixCreate == PREFIX_SRC_MANUAL)
|| (rprefix->AdvPrefixCreate == PREFIX_SRC_BOTH)) {
vty_out(vty, " ipv6 nd prefix %pFX", &rprefix->prefix);
return;
}
+void rtadv_if_up(struct zebra_if *zif)
+{
+ struct zebra_vrf *zvrf = rtadv_interface_get_zvrf(zif->ifp);
+
+ /* Enable fast tx of RA if enabled && RA interval is not in msecs */
+ if (zif->rtadv.AdvSendAdvertisements &&
+ (zif->rtadv.MaxRtrAdvInterval >= 1000) &&
+ zif->rtadv.UseFastRexmit) {
+ zif->rtadv.inFastRexmit = 1;
+ zif->rtadv.NumFastReXmitsRemain = RTADV_NUM_FAST_REXMITS;
+ }
+
+ /*
+ * startup the state machine, if it hasn't been already
+ * due to a delayed ifindex on startup ordering
+ */
+ if (zif->rtadv.AdvSendAdvertisements)
+ rtadv_start_interface_events(zvrf, zif);
+}
+
+void rtadv_if_init(struct zebra_if *zif)
+{
+ /* Set default router advertise values. */
+ struct rtadvconf *rtadv;
+
+ rtadv = &zif->rtadv;
+
+ rtadv->AdvSendAdvertisements = 0;
+ rtadv->MaxRtrAdvInterval = RTADV_MAX_RTR_ADV_INTERVAL;
+ rtadv->MinRtrAdvInterval = RTADV_MIN_RTR_ADV_INTERVAL;
+ rtadv->AdvIntervalTimer = 0;
+ rtadv->AdvManagedFlag = 0;
+ rtadv->AdvOtherConfigFlag = 0;
+ rtadv->AdvHomeAgentFlag = 0;
+ rtadv->AdvLinkMTU = 0;
+ rtadv->AdvReachableTime = 0;
+ rtadv->AdvRetransTimer = 0;
+ rtadv->AdvCurHopLimit = RTADV_DEFAULT_HOPLIMIT;
+ memset(&rtadv->lastadvcurhoplimit, 0,
+ sizeof(rtadv->lastadvcurhoplimit));
+ memset(&rtadv->lastadvmanagedflag, 0,
+ sizeof(rtadv->lastadvmanagedflag));
+ memset(&rtadv->lastadvotherconfigflag, 0,
+ sizeof(rtadv->lastadvotherconfigflag));
+ memset(&rtadv->lastadvreachabletime, 0,
+ sizeof(rtadv->lastadvreachabletime));
+ memset(&rtadv->lastadvretranstimer, 0,
+ sizeof(rtadv->lastadvretranstimer));
+ rtadv->AdvDefaultLifetime = -1; /* derive from MaxRtrAdvInterval */
+ rtadv->HomeAgentPreference = 0;
+ rtadv->HomeAgentLifetime = -1; /* derive from AdvDefaultLifetime */
+ rtadv->AdvIntervalOption = 0;
+ rtadv->UseFastRexmit = true;
+ rtadv->DefaultPreference = RTADV_PREF_MEDIUM;
+
+ rtadv_prefixes_init(rtadv->prefixes);
+
+ rtadv->AdvRDNSSList = list_new();
+ rtadv->AdvDNSSLList = list_new();
+}
+
+void rtadv_if_fini(struct zebra_if *zif)
+{
+ struct rtadvconf *rtadv;
+ struct rtadv_prefix *rp;
+
+ rtadv = &zif->rtadv;
+
+ while ((rp = rtadv_prefixes_pop(rtadv->prefixes)))
+ rtadv_prefix_free(rp);
+
+ list_delete(&rtadv->AdvRDNSSList);
+ list_delete(&rtadv->AdvDNSSLList);
+}
+
void rtadv_vrf_init(struct zebra_vrf *zvrf)
{
if (!vrf_is_backend_netns() && (zvrf_id(zvrf) != VRF_DEFAULT))
struct ipv6_mreq mreq;
- memset(&mreq, 0, sizeof(struct ipv6_mreq));
+ memset(&mreq, 0, sizeof(mreq));
inet_pton(AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr);
mreq.ipv6mr_interface = ifp->ifindex;
struct ipv6_mreq mreq;
- memset(&mreq, 0, sizeof(struct ipv6_mreq));
+ memset(&mreq, 0, sizeof(mreq));
inet_pton(AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr);
mreq.ipv6mr_interface = ifp->ifindex;
return true;
}
-#else
-void rtadv_vrf_init(struct zebra_vrf *zvrf)
-{
- /* Empty.*/;
-}
-
-void rtadv_cmd_init(void)
-{
- /* Empty.*/;
-}
-
-void rtadv_add_prefix(struct zebra_if *zif, const struct prefix_ipv6 *p)
-{
- /* Empty.*/;
-}
-
-void rtadv_delete_prefix(struct zebra_if *zif, const struct prefix *p)
-{
- /* Empty.*/;
-}
-
-void rtadv_stop_ra(struct interface *ifp)
-{
- /* Empty.*/;
-}
-
-void rtadv_stop_ra_all(void)
-{
- /* Empty.*/;
-}
-
+#else /* !HAVE_RTADV */
/*
* If the end user does not have RADV enabled we should
* handle this better