#if PIM_IPV == 4
static void pim_if_igmp_join_del_all(struct interface *ifp);
static int igmp_join_sock(const char *ifname, ifindex_t ifindex,
- struct in_addr group_addr,
- struct in_addr source_addr);
+ struct in_addr group_addr, struct in_addr source_addr,
+ struct pim_interface *pim_ifp);
#endif
void pim_if_init(struct pim_instance *pim)
pim_ifp->pim = ifp->vrf->info;
pim_ifp->mroute_vif_index = -1;
-#if PIM_IPV == 4
pim_ifp->igmp_version = IGMP_DEFAULT_VERSION;
pim_ifp->gm_default_robustness_variable =
IGMP_DEFAULT_ROBUSTNESS_VARIABLE;
if (pim)
PIM_IF_DO_PIM(pim_ifp->options);
+#if PIM_IPV == 4
if (igmp)
PIM_IF_DO_IGMP(pim_ifp->options);
PIM_IF_DO_IGMP_LISTEN_ALLROUTERS(pim_ifp->options);
+#endif
pim_ifp->gm_join_list = NULL;
pim_ifp->pim_neighbor_list = NULL;
ifp->info = pim_ifp;
+#if PIM_IPV == 4
pim_sock_reset(ifp);
+#endif
pim_if_add_vif(ifp, ispimreg, is_vxlan_term);
-#endif
pim_ifp->pim->mcast_if_count++;
return pim_ifp;
if (pim_ifp->gm_join_list) {
pim_if_igmp_join_del_all(ifp);
}
+#endif
pim_ifchannel_delete_all(ifp);
+#if PIM_IPV == 4
igmp_sock_delete_all(ifp);
+#endif
pim_neighbor_delete_all(ifp, "Interface removed from configuration");
XFREE(MTYPE_PIM_INTERFACE, pim_ifp->boundary_oil_plist);
XFREE(MTYPE_PIM_INTERFACE, pim_ifp);
-#endif
ifp->info = NULL;
}
CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY)
? "secondary"
: "primary");
+#if PIM_IPV != 4
+ if (IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6) ||
+ IN6_IS_ADDR_LOOPBACK(&ifc->address->u.prefix6)) {
+ if (IN6_IS_ADDR_UNSPECIFIED(&pim_ifp->ll_lowest))
+ pim_ifp->ll_lowest = ifc->address->u.prefix6;
+ else if (IPV6_ADDR_CMP(&ifc->address->u.prefix6,
+ &pim_ifp->ll_lowest) < 0)
+ pim_ifp->ll_lowest = ifc->address->u.prefix6;
+
+ if (IPV6_ADDR_CMP(&ifc->address->u.prefix6,
+ &pim_ifp->ll_highest) > 0)
+ pim_ifp->ll_highest = ifc->address->u.prefix6;
+
+ if (PIM_DEBUG_ZEBRA)
+ zlog_debug(
+ "%s: new link-local %pI6, lowest now %pI6, highest %pI6",
+ ifc->ifp->name, &ifc->address->u.prefix6,
+ &pim_ifp->ll_lowest, &pim_ifp->ll_highest);
+ }
+#endif
detect_address_change(ifp, 0, __func__);
close(ij->sock_fd);
join_fd = igmp_join_sock(
ifp->name, ifp->ifindex, ij->group_addr,
- ij->source_addr);
+ ij->source_addr, pim_ifp);
if (join_fd < 0) {
char group_str[INET_ADDRSTRLEN];
char source_str[INET_ADDRSTRLEN];
? "secondary"
: "primary");
+#if PIM_IPV == 6
+ struct pim_interface *pim_ifp = ifc->ifp->info;
+
+ if (pim_ifp &&
+ (!IPV6_ADDR_CMP(&ifc->address->u.prefix6, &pim_ifp->ll_lowest) ||
+ !IPV6_ADDR_CMP(&ifc->address->u.prefix6, &pim_ifp->ll_highest))) {
+ struct listnode *cnode;
+ struct connected *cc;
+
+ memset(&pim_ifp->ll_lowest, 0xff, sizeof(pim_ifp->ll_lowest));
+ memset(&pim_ifp->ll_highest, 0, sizeof(pim_ifp->ll_highest));
+
+ for (ALL_LIST_ELEMENTS_RO(ifc->ifp->connected, cnode, cc)) {
+ if (!IN6_IS_ADDR_LINKLOCAL(&cc->address->u.prefix6) &&
+ !IN6_IS_ADDR_LOOPBACK(&cc->address->u.prefix6))
+ continue;
+
+ if (IPV6_ADDR_CMP(&cc->address->u.prefix6,
+ &pim_ifp->ll_lowest) < 0)
+ pim_ifp->ll_lowest = cc->address->u.prefix6;
+ if (IPV6_ADDR_CMP(&cc->address->u.prefix6,
+ &pim_ifp->ll_highest) > 0)
+ pim_ifp->ll_highest = cc->address->u.prefix6;
+ }
+
+ if (pim_ifp->ll_lowest.s6_addr[0] == 0xff)
+ memset(&pim_ifp->ll_lowest, 0,
+ sizeof(pim_ifp->ll_lowest));
+
+ if (PIM_DEBUG_ZEBRA)
+ zlog_debug(
+ "%s: removed link-local %pI6, lowest now %pI6, highest %pI6",
+ ifc->ifp->name, &ifc->address->u.prefix6,
+ &pim_ifp->ll_lowest, &pim_ifp->ll_highest);
+ }
+#endif
+
detect_address_change(ifp, force_prim_as_any, __func__);
pim_if_addr_del_igmp(ifc);
{
struct connected *ifc;
struct listnode *node;
- int v4_addrs = 0;
- int v6_addrs = 0;
struct pim_interface *pim_ifp = ifp->info;
- if (pim_ifp && !pim_addr_is_any(pim_ifp->update_source)) {
+ if (pim_ifp && !pim_addr_is_any(pim_ifp->update_source))
return pim_ifp->update_source;
- }
+
+#if PIM_IPV == 6
+ if (pim_ifp)
+ return pim_ifp->ll_highest;
+
+ pim_addr best_addr = PIMADDR_ANY;
for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
pim_addr addr;
+ if (ifc->address->family != AF_INET6)
+ continue;
+
+ addr = pim_addr_from_prefix(ifc->address);
+ if (!IN6_IS_ADDR_LINKLOCAL(&addr))
+ continue;
+ if (pim_addr_cmp(addr, best_addr) > 0)
+ best_addr = addr;
+ }
+
+ return best_addr;
+#else
+ int v4_addrs = 0;
+ int v6_addrs = 0;
+
+ for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
switch (ifc->address->family) {
case AF_INET:
v4_addrs++;
if (ifc->address->family != PIM_AF)
continue;
- addr = pim_addr_from_prefix(ifc->address);
-
-#if PIM_IPV == 6
- if (!IN6_IS_ADDR_LINKLOCAL(&addr))
- continue;
-#endif
- return addr;
+ return pim_addr_from_prefix(ifc->address);
}
-#if PIM_IPV == 4
/*
* If we have no v4_addrs and v6 is configured
* We probably are using unnumbered
if (lo_ifp && (lo_ifp != ifp))
return pim_find_primary_addr(lo_ifp);
}
-#endif
return PIMADDR_ANY;
+#endif
}
static int pim_iface_next_vif_index(struct interface *ifp)
}
static int igmp_join_sock(const char *ifname, ifindex_t ifindex,
- struct in_addr group_addr, struct in_addr source_addr)
+ struct in_addr group_addr, struct in_addr source_addr,
+ struct pim_interface *pim_ifp)
{
int join_fd;
+ pim_ifp->igmp_ifstat_joins_sent++;
+
join_fd = pim_socket_raw(IPPROTO_IGMP);
if (join_fd < 0) {
+ pim_ifp->igmp_ifstat_joins_failed++;
return -1;
}
__func__, join_fd, group_str, source_str, ifindex,
ifname, errno, safe_strerror(errno));
+ pim_ifp->igmp_ifstat_joins_failed++;
+
close(join_fd);
return -2;
}
assert(pim_ifp);
join_fd = igmp_join_sock(ifp->name, ifp->ifindex, group_addr,
- source_addr);
+ source_addr, pim_ifp);
if (join_fd < 0) {
char group_str[INET_ADDRSTRLEN];
char source_str[INET_ADDRSTRLEN];
*/
if (pim_ifp)
pim_ifp->pim = pim;
-#if PIM_IPV == 4
pim_if_addr_add_all(ifp);
/*
* this is a no-op if it's already been done.
*/
pim_if_create_pimreg(pim);
-#endif
}
#if PIM_IPV == 4
static int pim_ifp_up(struct interface *ifp)
{
+ uint32_t table_id;
struct pim_interface *pim_ifp;
struct pim_instance *pim;
if (pim_ifp)
pim_ifp->pim = pim;
-#if PIM_IPV == 4
- uint32_t table_id;
-
/*
pim_if_addr_add_all() suffices for bringing up both IGMP and
PIM
}
}
}
-#endif
return 0;
}
ifp->mtu, if_is_operative(ifp));
}
-#if PIM_IPV == 4
if (!if_is_operative(ifp)) {
pim_ifchannel_delete_all(ifp);
/*
*/
pim_if_addr_del_all(ifp);
+#if PIM_IPV == 4
/*
pim_sock_delete() closes the socket, stops read and timer
threads,
if (ifp->info) {
pim_sock_delete(ifp, "link down");
}
+#endif
}
if (ifp->info) {
pim_if_del_vif(ifp);
+#if PIM_IPV == 4
pim_ifstat_reset(ifp);
- }
#endif
+ }
return 0;
}
ifp->mtu, if_is_operative(ifp));
}
-#if PIM_IPV == 4
- struct pim_instance *pim;
-
if (!if_is_operative(ifp))
pim_if_addr_del_all(ifp);
+#if PIM_IPV == 4
+ struct pim_instance *pim;
+
pim = ifp->vrf->info;
if (pim && pim->vxlan.term_if == ifp)
pim_vxlan_del_term_dev(pim);