]> git.proxmox.com Git - mirror_frr.git/blobdiff - pimd/pim_iface.c
Merge pull request #10366 from AbhishekNR/mld_cli
[mirror_frr.git] / pimd / pim_iface.c
index 168bf6ea6a9769217b6faf32d24d6bcd2ae9ef5f..8e0e418a9949ffec4a8ce646083df018930724e0 100644 (file)
@@ -53,8 +53,8 @@
 #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)
@@ -127,7 +127,6 @@ struct pim_interface *pim_if_new(struct interface *ifp, bool igmp, bool 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;
@@ -153,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;
@@ -186,10 +187,11 @@ 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);
-#endif
        pim_ifp->pim->mcast_if_count++;
 
        return pim_ifp;
@@ -208,9 +210,12 @@ void pim_if_delete(struct interface *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");
 
@@ -224,7 +229,6 @@ void pim_if_delete(struct interface *ifp)
 
        XFREE(MTYPE_PIM_INTERFACE, pim_ifp->boundary_oil_plist);
        XFREE(MTYPE_PIM_INTERFACE, pim_ifp);
-#endif
 
        ifp->info = NULL;
 }
@@ -512,6 +516,26 @@ void pim_if_addr_add(struct connected *ifc)
                           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__);
 
@@ -552,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];
@@ -711,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);
@@ -825,17 +886,36 @@ pim_addr pim_find_primary_addr(struct interface *ifp)
 {
        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++;
@@ -853,16 +933,9 @@ pim_addr pim_find_primary_addr(struct interface *ifp)
                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
@@ -882,8 +955,8 @@ pim_addr pim_find_primary_addr(struct interface *ifp)
                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)
@@ -1175,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;
        }
 
@@ -1196,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;
        }
@@ -1216,7 +1295,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];
@@ -1552,7 +1631,6 @@ static int pim_ifp_create(struct interface *ifp)
                 */
                if (pim_ifp)
                        pim_ifp->pim = pim;
-#if PIM_IPV == 4
                pim_if_addr_add_all(ifp);
 
                /*
@@ -1564,7 +1642,6 @@ static int pim_ifp_create(struct interface *ifp)
                 * this is a no-op if it's already been done.
                 */
                pim_if_create_pimreg(pim);
-#endif
        }
 
 #if PIM_IPV == 4
@@ -1602,6 +1679,7 @@ static int pim_ifp_create(struct interface *ifp)
 
 static int pim_ifp_up(struct interface *ifp)
 {
+       uint32_t table_id;
        struct pim_interface *pim_ifp;
        struct pim_instance *pim;
 
@@ -1624,9 +1702,6 @@ static int pim_ifp_up(struct interface *ifp)
        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
@@ -1655,7 +1730,6 @@ static int pim_ifp_up(struct interface *ifp)
                        }
                }
        }
-#endif
        return 0;
 }
 
@@ -1669,7 +1743,6 @@ static int pim_ifp_down(struct interface *ifp)
                        ifp->mtu, if_is_operative(ifp));
        }
 
-#if PIM_IPV == 4
        if (!if_is_operative(ifp)) {
                pim_ifchannel_delete_all(ifp);
                /*
@@ -1678,6 +1751,7 @@ static 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,
@@ -1686,13 +1760,15 @@ static 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;
 }
@@ -1707,12 +1783,12 @@ static int pim_ifp_destroy(struct interface *ifp)
                        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);