diff options
Diffstat (limited to 'pimd/pim_iface.c')
| -rw-r--r-- | pimd/pim_iface.c | 139 |
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); } |
