diff options
Diffstat (limited to 'pimd/pim_iface.c')
| -rw-r--r-- | pimd/pim_iface.c | 295 |
1 files changed, 204 insertions, 91 deletions
diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index 8b27809c7c..98fa4c4882 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -50,10 +50,12 @@ #include "pim_igmp_join.h" #include "pim_vxlan.h" +#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) { @@ -83,6 +85,7 @@ static void pim_sec_addr_free(struct pim_secondary_addr *sec_addr) XFREE(MTYPE_PIM_SEC_ADDR, sec_addr); } +__attribute__((unused)) static int pim_sec_addr_comp(const void *p1, const void *p2) { const struct pim_secondary_addr *sec1 = p1; @@ -149,10 +152,12 @@ struct pim_interface *pim_if_new(struct interface *ifp, bool igmp, bool pim, 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; @@ -182,7 +187,9 @@ struct pim_interface *pim_if_new(struct interface *ifp, bool igmp, bool pim, ifp->info = pim_ifp; +#if PIM_IPV == 4 pim_sock_reset(ifp); +#endif pim_if_add_vif(ifp, ispimreg, is_vxlan_term); pim_ifp->pim->mcast_if_count++; @@ -193,23 +200,26 @@ struct pim_interface *pim_if_new(struct interface *ifp, bool igmp, bool pim, void pim_if_delete(struct interface *ifp) { struct pim_interface *pim_ifp; - struct pim_ifchannel *ch; assert(ifp); pim_ifp = ifp->info; 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); } +#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"); pim_if_del_vif(ifp); - pim_ifp->pim->mcast_if_count--; pim_igmp_if_fini(pim_ifp); @@ -218,13 +228,6 @@ void pim_if_delete(struct interface *ifp) list_delete(&pim_ifp->sec_addr_list); XFREE(MTYPE_PIM_INTERFACE, pim_ifp->boundary_oil_plist); - - while (!RB_EMPTY(pim_ifchannel_rb, &pim_ifp->ifchannel_rb)) { - ch = RB_ROOT(pim_ifchannel_rb, &pim_ifp->ifchannel_rb); - - pim_ifchannel_delete(ch); - } - XFREE(MTYPE_PIM_INTERFACE, pim_ifp); ifp->info = NULL; @@ -299,27 +302,20 @@ static int detect_primary_address_change(struct interface *ifp, const char *caller) { struct pim_interface *pim_ifp = ifp->info; - struct in_addr new_prim_addr; + pim_addr new_prim_addr; int changed; if (force_prim_as_any) - new_prim_addr.s_addr = INADDR_ANY; + new_prim_addr = PIMADDR_ANY; else new_prim_addr = pim_find_primary_addr(ifp); - changed = new_prim_addr.s_addr != pim_ifp->primary_address.s_addr; + changed = pim_addr_cmp(new_prim_addr, pim_ifp->primary_address); - if (PIM_DEBUG_ZEBRA) { - char new_prim_str[INET_ADDRSTRLEN]; - char old_prim_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<new?>", new_prim_addr, new_prim_str, - sizeof(new_prim_str)); - pim_inet4_dump("<old?>", pim_ifp->primary_address, old_prim_str, - sizeof(old_prim_str)); - zlog_debug("%s: old=%s new=%s on interface %s: %s", __func__, - old_prim_str, new_prim_str, ifp->name, - changed ? "changed" : "unchanged"); - } + if (PIM_DEBUG_ZEBRA) + zlog_debug("%s: old=%pPA new=%pPA on interface %s: %s", + __func__, &pim_ifp->primary_address, &new_prim_addr, + ifp->name, changed ? "changed" : "unchanged"); if (changed) { /* Before updating pim_ifp send Hello time with 0 hold time */ @@ -401,19 +397,18 @@ static int pim_sec_addr_update(struct interface *ifp) } for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { - struct prefix *p = ifc->address; + pim_addr addr = pim_addr_from_prefix(ifc->address); - if (PIM_INADDR_IS_ANY(p->u.prefix4)) { + if (pim_addr_is_any(addr)) continue; - } - if (pim_ifp->primary_address.s_addr == p->u.prefix4.s_addr) { + if (!pim_addr_cmp(addr, pim_ifp->primary_address)) { /* don't add the primary address into the secondary * address list */ continue; } - if (pim_sec_addr_add(pim_ifp, p)) { + if (pim_sec_addr_add(pim_ifp, ifc->address)) { changed = 1; } } @@ -480,7 +475,7 @@ static void detect_address_change(struct interface *ifp, int force_prim_as_any, * address change on all of them when the lo address changes */ } -int pim_update_source_set(struct interface *ifp, struct in_addr source) +int pim_update_source_set(struct interface *ifp, pim_addr source) { struct pim_interface *pim_ifp = ifp->info; @@ -488,7 +483,7 @@ int pim_update_source_set(struct interface *ifp, struct in_addr source) return PIM_IFACE_NOT_FOUND; } - if (pim_ifp->update_source.s_addr == source.s_addr) { + if (!pim_addr_cmp(pim_ifp->update_source, source)) { return PIM_UPDATE_SOURCE_DUP; } @@ -502,7 +497,6 @@ void pim_if_addr_add(struct connected *ifc) { struct pim_interface *pim_ifp; struct interface *ifp; - struct in_addr ifaddr; bool vxlan_term; assert(ifc); @@ -522,14 +516,35 @@ void pim_if_addr_add(struct connected *ifc) CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ? "secondary" : "primary"); - - ifaddr = ifc->address->u.prefix4; +#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__); // if (ifc->address->family != AF_INET) // return; +#if PIM_IPV == 4 + struct in_addr ifaddr = ifc->address->u.prefix4; + if (PIM_IF_TEST_IGMP(pim_ifp->options)) { struct gm_sock *igmp; @@ -561,7 +576,7 @@ void pim_if_addr_add(struct connected *ifc) 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]; @@ -595,10 +610,11 @@ void pim_if_addr_add(struct connected *ifc) true); } } /* igmp mtrace only */ +#endif if (PIM_IF_TEST_PIM(pim_ifp->options)) { - if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) { + if (!pim_addr_is_any(pim_ifp->primary_address)) { /* Interface has a valid socket ? */ if (pim_ifp->pim_sock_fd < 0) { @@ -646,6 +662,7 @@ void pim_if_addr_add(struct connected *ifc) static void pim_if_addr_del_igmp(struct connected *ifc) { +#if PIM_IPV == 4 struct pim_interface *pim_ifp = ifc->ifp->info; struct gm_sock *igmp; struct in_addr ifaddr; @@ -668,6 +685,7 @@ static void pim_if_addr_del_igmp(struct connected *ifc) /* if addr found, del IGMP socket */ igmp_sock_delete(igmp); } +#endif } static void pim_if_addr_del_pim(struct connected *ifc) @@ -684,7 +702,7 @@ static void pim_if_addr_del_pim(struct connected *ifc) return; } - if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) { + if (!pim_addr_is_any(pim_ifp->primary_address)) { /* Interface keeps a valid primary address */ return; } @@ -717,6 +735,43 @@ void pim_if_addr_del(struct connected *ifc, int force_prim_as_any) ? "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); @@ -752,7 +807,7 @@ void pim_if_addr_add_all(struct interface *ifp) if (PIM_IF_TEST_PIM(pim_ifp->options)) { /* Interface has a valid primary address ? */ - if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) { + if (!pim_addr_is_any(pim_ifp->primary_address)) { /* Interface has a valid socket ? */ if (pim_ifp->pim_sock_fd < 0) { @@ -827,40 +882,58 @@ void pim_if_addr_del_all_igmp(struct interface *ifp) } } -struct in_addr pim_find_primary_addr(struct interface *ifp) +pim_addr pim_find_primary_addr(struct interface *ifp) { struct connected *ifc; struct listnode *node; - struct in_addr addr = {0}; - int v4_addrs = 0; - int v6_addrs = 0; struct pim_interface *pim_ifp = ifp->info; - if (pim_ifp && PIM_INADDR_ISNOT_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)) { - struct prefix *p = ifc->address; + pim_addr addr; - if (p->family != AF_INET) { - v6_addrs++; + if (ifc->address->family != AF_INET6) continue; - } - if (PIM_INADDR_IS_ANY(p->u.prefix4)) { - zlog_warn( - "%s: null IPv4 address connected to interface %s", - __func__, ifp->name); + 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; + } - v4_addrs++; + 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++; + break; + case AF_INET6: + v6_addrs++; + break; + default: + continue; + } if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY)) continue; - return p->u.prefix4; + if (ifc->address->family != PIM_AF) + continue; + + return pim_addr_from_prefix(ifc->address); } /* @@ -882,10 +955,8 @@ struct in_addr pim_find_primary_addr(struct interface *ifp) if (lo_ifp && (lo_ifp != ifp)) return pim_find_primary_addr(lo_ifp); } - - addr.s_addr = PIM_NET_INADDR_ANY; - - return addr; + return PIMADDR_ANY; +#endif } static int pim_iface_next_vif_index(struct interface *ifp) @@ -916,7 +987,7 @@ static int pim_iface_next_vif_index(struct interface *ifp) int pim_if_add_vif(struct interface *ifp, bool ispimreg, bool is_vxlan_term) { struct pim_interface *pim_ifp = ifp->info; - struct in_addr ifaddr; + pim_addr ifaddr; unsigned char flags = 0; assert(pim_ifp); @@ -935,7 +1006,7 @@ int pim_if_add_vif(struct interface *ifp, bool ispimreg, bool is_vxlan_term) } ifaddr = pim_ifp->primary_address; - if (!ispimreg && !is_vxlan_term && PIM_INADDR_IS_ANY(ifaddr)) { + if (!ispimreg && !is_vxlan_term && pim_addr_is_any(ifaddr)) { zlog_warn( "%s: could not get address for interface %s ifindex=%d", __func__, ifp->name, ifp->ifindex); @@ -1094,8 +1165,7 @@ uint16_t pim_if_jp_override_interval_msec(struct interface *ifp) router (Section 4.3.4). The primary IP address of a neighbor is the address that it uses as the source of its PIM Hello messages. */ -struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp, - struct in_addr addr) +struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp, pim_addr addr) { struct listnode *neighnode; struct pim_neighbor *neigh; @@ -1111,15 +1181,13 @@ struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp, return 0; } - p.family = AF_INET; - p.u.prefix4 = addr; - p.prefixlen = IPV4_MAX_BITLEN; + pim_addr_to_prefix(&p, addr); for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode, neigh)) { /* primary address ? */ - if (neigh->source_addr.s_addr == addr.s_addr) + if (!pim_addr_cmp(neigh->source_addr, addr)) return neigh; /* secondary address ? */ @@ -1127,13 +1195,10 @@ struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp, return neigh; } - if (PIM_DEBUG_PIM_TRACE) { - char addr_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); + if (PIM_DEBUG_PIM_TRACE) zlog_debug( - "%s: neighbor not found for address %s on interface %s", - __func__, addr_str, ifp->name); - } + "%s: neighbor not found for address %pPA on interface %s", + __func__, &addr, ifp->name); return NULL; } @@ -1158,6 +1223,7 @@ long pim_if_t_suppressed_msec(struct interface *ifp) return t_suppressed_msec; } +#if PIM_IPV == 4 static void igmp_join_free(struct gm_join *ij) { XFREE(MTYPE_PIM_IGMP_JOIN, ij); @@ -1182,12 +1248,16 @@ static struct gm_join *igmp_join_find(struct list *join_list, } 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; } @@ -1203,6 +1273,8 @@ static int igmp_join_sock(const char *ifname, ifindex_t ifindex, __func__, join_fd, group_str, source_str, ifindex, ifname, errno, safe_strerror(errno)); + pim_ifp->igmp_ifstat_joins_failed++; + close(join_fd); return -2; } @@ -1222,7 +1294,7 @@ static struct gm_join *igmp_join_new(struct interface *ifp, 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]; @@ -1348,6 +1420,7 @@ int pim_if_igmp_join_del(struct interface *ifp, struct in_addr group_addr, return 0; } +__attribute__((unused)) static void pim_if_igmp_join_del_all(struct interface *ifp) { struct pim_interface *pim_ifp; @@ -1368,6 +1441,19 @@ 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_igmp_join_del(ifp, ij->group_addr, ij->source_addr); } +#else /* PIM_IPV != 4 */ +ferr_r pim_if_igmp_join_add(struct interface *ifp, struct in_addr group_addr, + struct in_addr source_addr) +{ + return ferr_ok(); +} + +int pim_if_igmp_join_del(struct interface *ifp, struct in_addr group_addr, + struct in_addr source_addr) +{ + return 0; +} +#endif /* PIM_IPV != 4 */ /* RFC 4601 @@ -1383,8 +1469,7 @@ static void pim_if_igmp_join_del_all(struct interface *ifp) gone down (and may have come back up), and so we must assume it no longer knows it was the winner. */ -void pim_if_assert_on_neighbor_down(struct interface *ifp, - struct in_addr neigh_addr) +void pim_if_assert_on_neighbor_down(struct interface *ifp, pim_addr neigh_addr) { struct pim_interface *pim_ifp; struct pim_ifchannel *ch; @@ -1397,7 +1482,7 @@ void pim_if_assert_on_neighbor_down(struct interface *ifp, if (ch->ifassert_state != PIM_IFASSERT_I_AM_LOSER) continue; /* Dead neighbor was winner ? */ - if (ch->ifassert_winner.s_addr != neigh_addr.s_addr) + if (pim_addr_cmp(ch->ifassert_winner, neigh_addr)) continue; assert_action_a5(ch); @@ -1473,7 +1558,7 @@ void pim_if_create_pimreg(struct pim_instance *pim) } } -struct prefix *pim_if_connected_to_source(struct interface *ifp, struct in_addr src) +struct prefix *pim_if_connected_to_source(struct interface *ifp, pim_addr src) { struct listnode *cnode; struct connected *c; @@ -1482,12 +1567,10 @@ struct prefix *pim_if_connected_to_source(struct interface *ifp, struct in_addr if (!ifp) return NULL; - p.family = AF_INET; - p.u.prefix4 = src; - p.prefixlen = IPV4_MAX_BITLEN; + pim_addr_to_prefix(&p, src); for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) { - if (c->address->family != AF_INET) + if (c->address->family != PIM_AF) continue; if (prefix_match(c->address, &p)) return c->address; @@ -1521,7 +1604,7 @@ int pim_if_ifchannel_count(struct pim_interface *pim_ifp) return count; } -int pim_ifp_create(struct interface *ifp) +static int pim_ifp_create(struct interface *ifp) { struct pim_instance *pim; @@ -1558,6 +1641,7 @@ int pim_ifp_create(struct interface *ifp) pim_if_create_pimreg(pim); } +#if PIM_IPV == 4 /* * If we are a vrf device that is up, open up the pim_socket for * listening @@ -1585,15 +1669,16 @@ int pim_ifp_create(struct interface *ifp) "%s: Cannot enable pim on %s. MAXVIFS(%d) reached. Deleting and readding the vxlan termimation device after unconfiguring pim from other interfaces may succeed.", __func__, ifp->name, MAXVIFS); } +#endif return 0; } -int pim_ifp_up(struct interface *ifp) +static int pim_ifp_up(struct interface *ifp) { + uint32_t table_id; struct pim_interface *pim_ifp; struct pim_instance *pim; - uint32_t table_id; if (PIM_DEBUG_ZEBRA) { zlog_debug( @@ -1645,7 +1730,7 @@ int pim_ifp_up(struct interface *ifp) return 0; } -int pim_ifp_down(struct interface *ifp) +static int pim_ifp_down(struct interface *ifp) { if (PIM_DEBUG_ZEBRA) { zlog_debug( @@ -1663,6 +1748,7 @@ int pim_ifp_down(struct interface *ifp) */ pim_if_addr_del_all(ifp); +#if PIM_IPV == 4 /* pim_sock_delete() closes the socket, stops read and timer threads, @@ -1671,20 +1757,21 @@ int pim_ifp_down(struct interface *ifp) 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; } -int pim_ifp_destroy(struct interface *ifp) +static int pim_ifp_destroy(struct interface *ifp) { - struct pim_instance *pim; - if (PIM_DEBUG_ZEBRA) { zlog_debug( "%s: %s index %d vrf %s(%u) flags %ld metric %d mtu %d operative %d", @@ -1696,9 +1783,35 @@ int pim_ifp_destroy(struct interface *ifp) 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); +#endif + + return 0; +} + +static int pim_if_new_hook(struct interface *ifp) +{ + return 0; +} + +static int pim_if_delete_hook(struct interface *ifp) +{ + if (ifp->info) + pim_if_delete(ifp); return 0; } + +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); +} |
