summaryrefslogtreecommitdiff
path: root/pimd/pim_iface.c
diff options
context:
space:
mode:
Diffstat (limited to 'pimd/pim_iface.c')
-rw-r--r--pimd/pim_iface.c139
1 files changed, 102 insertions, 37 deletions
diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c
index b053e422ec..dcb6116012 100644
--- a/pimd/pim_iface.c
+++ b/pimd/pim_iface.c
@@ -40,9 +40,8 @@
#include "pim6_mld.h"
-#if PIM_IPV == 4
-static void pim_if_igmp_join_del_all(struct interface *ifp);
-#endif
+static void pim_if_gm_join_del_all(struct interface *ifp);
+
static int gm_join_sock(const char *ifname, ifindex_t ifindex,
pim_addr group_addr, pim_addr source_addr,
struct pim_interface *pim_ifp);
@@ -189,11 +188,9 @@ void pim_if_delete(struct interface *ifp)
assert(pim_ifp);
pim_ifp->pim->mcast_if_count--;
-#if PIM_IPV == 4
if (pim_ifp->gm_join_list) {
- pim_if_igmp_join_del_all(ifp);
+ pim_if_gm_join_del_all(ifp);
}
-#endif
pim_ifchannel_delete_all(ifp);
#if PIM_IPV == 4
@@ -382,7 +379,7 @@ static int pim_sec_addr_update(struct interface *ifp)
sec_addr->flags |= PIM_SEC_ADDRF_STALE;
}
- for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
+ frr_each (if_connected, ifp->connected, ifc) {
pim_addr addr = pim_addr_from_prefix(ifc->address);
if (pim_addr_is_any(addr))
@@ -726,13 +723,12 @@ void pim_if_addr_del(struct connected *ifc, int force_prim_as_any)
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)) {
+ frr_each (if_connected, ifc->ifp->connected, cc) {
if (!IN6_IS_ADDR_LINKLOCAL(&cc->address->u.prefix6) &&
!IN6_IS_ADDR_LOOPBACK(&cc->address->u.prefix6))
continue;
@@ -768,8 +764,6 @@ void pim_if_addr_del(struct connected *ifc, int force_prim_as_any)
void pim_if_addr_add_all(struct interface *ifp)
{
struct connected *ifc;
- struct listnode *node;
- struct listnode *nextnode;
int v4_addrs = 0;
int v6_addrs = 0;
struct pim_interface *pim_ifp = ifp->info;
@@ -780,7 +774,7 @@ void pim_if_addr_add_all(struct interface *ifp)
if (!pim_ifp)
return;
- for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
+ frr_each (if_connected, ifp->connected, ifc) {
struct prefix *p = ifc->address;
if (p->family != AF_INET)
@@ -816,8 +810,6 @@ void pim_if_addr_add_all(struct interface *ifp)
void pim_if_addr_del_all(struct interface *ifp)
{
struct connected *ifc;
- struct listnode *node;
- struct listnode *nextnode;
struct pim_instance *pim;
pim = ifp->vrf->info;
@@ -828,7 +820,7 @@ void pim_if_addr_del_all(struct interface *ifp)
if (!ifp->info)
return;
- for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
+ frr_each_safe (if_connected, ifp->connected, ifc) {
struct prefix *p = ifc->address;
if (p->family != PIM_AF)
@@ -844,14 +836,12 @@ void pim_if_addr_del_all(struct interface *ifp)
void pim_if_addr_del_all_igmp(struct interface *ifp)
{
struct connected *ifc;
- struct listnode *node;
- struct listnode *nextnode;
/* PIM/IGMP enabled ? */
if (!ifp->info)
return;
- for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
+ frr_each_safe (if_connected, ifp->connected, ifc) {
struct prefix *p = ifc->address;
if (p->family != AF_INET)
@@ -864,7 +854,6 @@ void pim_if_addr_del_all_igmp(struct interface *ifp)
pim_addr pim_find_primary_addr(struct interface *ifp)
{
struct connected *ifc;
- struct listnode *node;
struct pim_interface *pim_ifp = ifp->info;
if (pim_ifp && !pim_addr_is_any(pim_ifp->update_source))
@@ -876,7 +865,7 @@ pim_addr pim_find_primary_addr(struct interface *ifp)
pim_addr best_addr = PIMADDR_ANY;
- for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
+ frr_each (if_connected, ifp->connected, ifc) {
pim_addr addr;
if (ifc->address->family != AF_INET6)
@@ -893,8 +882,9 @@ pim_addr pim_find_primary_addr(struct interface *ifp)
#else
int v4_addrs = 0;
int v6_addrs = 0;
+ struct connected *promote_ifc = NULL;
- for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
+ frr_each (if_connected, ifp->connected, ifc) {
switch (ifc->address->family) {
case AF_INET:
v4_addrs++;
@@ -906,15 +896,24 @@ pim_addr pim_find_primary_addr(struct interface *ifp)
continue;
}
- if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY))
+ if (ifc->address->family != PIM_AF)
continue;
- if (ifc->address->family != PIM_AF)
+ if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY)) {
+ promote_ifc = ifc;
continue;
+ }
return pim_addr_from_prefix(ifc->address);
}
+
+ /* Promote the new primary address. */
+ if (v4_addrs && promote_ifc) {
+ UNSET_FLAG(promote_ifc->flags, ZEBRA_IFA_SECONDARY);
+ return pim_addr_from_prefix(promote_ifc->address);
+ }
+
/*
* If we have no v4_addrs and v6 is configured
* We probably are using unnumbered
@@ -979,13 +978,13 @@ int pim_if_add_vif(struct interface *ifp, bool ispimreg, bool is_vxlan_term)
}
if (ifp->ifindex < 0) {
- zlog_warn("%s: ifindex=%d < 1 on interface %s", __func__,
+ zlog_warn("%s: ifindex=%d < 0 on interface %s", __func__,
ifp->ifindex, ifp->name);
return -2;
- } else if ((ifp->ifindex == 0) &&
+ } else if ((ifp->ifindex == PIM_OIF_PIM_REGISTER_VIF) &&
((strncmp(ifp->name, "pimreg", 6)) &&
(strncmp(ifp->name, "pim6reg", 7)))) {
- zlog_warn("%s: ifindex=%d == 0 on interface %s", __func__,
+ zlog_warn("%s: ifindex=%d on interface %s", __func__,
ifp->ifindex, ifp->name);
return -2;
}
@@ -1380,9 +1379,8 @@ int pim_if_gm_join_del(struct interface *ifp, pim_addr group_addr,
return 0;
}
-#if PIM_IPV == 4
__attribute__((unused))
-static void pim_if_igmp_join_del_all(struct interface *ifp)
+static void pim_if_gm_join_del_all(struct interface *ifp)
{
struct pim_interface *pim_ifp;
struct listnode *node;
@@ -1402,7 +1400,6 @@ static void pim_if_igmp_join_del_all(struct interface *ifp)
for (ALL_LIST_ELEMENTS(pim_ifp->gm_join_list, node, nextnode, ij))
pim_if_gm_join_del(ifp, ij->group_addr, ij->source_addr);
}
-#endif /* PIM_IPV == 4 */
/*
RFC 4601
@@ -1482,7 +1479,7 @@ void pim_if_update_assert_tracking_desired(struct interface *ifp)
*/
void pim_if_create_pimreg(struct pim_instance *pim)
{
- char pimreg_name[INTERFACE_NAMSIZ];
+ char pimreg_name[IFNAMSIZ];
if (!pim->regiface) {
if (pim->vrf->vrf_id == VRF_DEFAULT)
@@ -1495,9 +1492,16 @@ void pim_if_create_pimreg(struct pim_instance *pim)
pim->vrf->name);
pim->regiface->ifindex = PIM_OIF_PIM_REGISTER_VIF;
- if (!pim->regiface->info)
- pim_if_new(pim->regiface, false, false, true,
- false /*vxlan_term*/);
+ /*
+ * The pimreg interface might has been removed from
+ * kerenl with the VRF's deletion. It must be
+ * recreated, so delete the old one first.
+ */
+ if (pim->regiface->info)
+ pim_if_delete(pim->regiface);
+
+ pim_if_new(pim->regiface, false, false, true,
+ false /*vxlan_term*/);
/*
* On vrf moves we delete the interface if there
@@ -1511,7 +1515,6 @@ void pim_if_create_pimreg(struct pim_instance *pim)
struct prefix *pim_if_connected_to_source(struct interface *ifp, pim_addr src)
{
- struct listnode *cnode;
struct connected *c;
struct prefix p;
@@ -1520,7 +1523,7 @@ struct prefix *pim_if_connected_to_source(struct interface *ifp, pim_addr src)
pim_addr_to_prefix(&p, src);
- for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) {
+ frr_each (if_connected, ifp->connected, c) {
if (c->address->family != PIM_AF)
continue;
if (prefix_match(c->address, &p))
@@ -1674,7 +1677,9 @@ static int pim_ifp_up(struct interface *ifp)
__func__, vrf->name);
return 0;
}
+
pim_zebra_interface_set_master(master, ifp);
+ break;
}
}
}
@@ -1759,6 +1764,66 @@ void pim_iface_init(void)
hook_register_prio(if_add, 0, pim_if_new_hook);
hook_register_prio(if_del, 0, pim_if_delete_hook);
- if_zapi_callbacks(pim_ifp_create, pim_ifp_up, pim_ifp_down,
- pim_ifp_destroy);
+ hook_register_prio(if_real, 0, pim_ifp_create);
+ hook_register_prio(if_up, 0, pim_ifp_up);
+ hook_register_prio(if_down, 0, pim_ifp_down);
+ hook_register_prio(if_unreal, 0, pim_ifp_destroy);
+}
+
+static void pim_if_membership_clear(struct interface *ifp)
+{
+ struct pim_interface *pim_ifp;
+
+ pim_ifp = ifp->info;
+ assert(pim_ifp);
+
+ if (pim_ifp->pim_enable && pim_ifp->gm_enable)
+ return;
+
+ pim_ifchannel_membership_clear(ifp);
+}
+
+void pim_pim_interface_delete(struct interface *ifp)
+{
+ struct pim_interface *pim_ifp = ifp->info;
+
+ if (!pim_ifp)
+ return;
+
+ pim_ifp->pim_enable = false;
+
+ pim_if_membership_clear(ifp);
+
+ /*
+ * pim_sock_delete() removes all neighbors from
+ * pim_ifp->pim_neighbor_list.
+ */
+ pim_sock_delete(ifp, "pim unconfigured on interface");
+ pim_upstream_nh_if_update(pim_ifp->pim, ifp);
+
+ if (!pim_ifp->gm_enable) {
+ pim_if_addr_del_all(ifp);
+ pim_if_delete(ifp);
+ }
+}
+
+void pim_gm_interface_delete(struct interface *ifp)
+{
+ struct pim_interface *pim_ifp = ifp->info;
+
+ if (!pim_ifp)
+ return;
+
+ pim_ifp->gm_enable = false;
+
+ pim_if_membership_clear(ifp);
+
+#if PIM_IPV == 4
+ igmp_sock_delete_all(ifp);
+#else
+ gm_ifp_teardown(ifp);
+#endif
+
+ if (!pim_ifp->pim_enable)
+ pim_if_delete(ifp);
}