]> git.proxmox.com Git - mirror_frr.git/blobdiff - pimd/pim_igmpv2.c
zebra: Allow ns delete to happen after under/over flow checks
[mirror_frr.git] / pimd / pim_igmpv2.c
index d4b3010d3c15472e16fd13d9a68820b2606e90c5..19c37688130c523f4468dc7c488d5712668cfdf2 100644 (file)
 #include "pim_util.h"
 
 
-static void
-on_trace (const char *label,
-          struct interface *ifp, struct in_addr from)
+static void on_trace(const char *label, struct interface *ifp,
+                    struct in_addr from)
 {
-  if (PIM_DEBUG_IGMP_TRACE) {
-    char from_str[INET_ADDRSTRLEN];
-    pim_inet4_dump("<from?>", from, from_str, sizeof(from_str));
-    zlog_debug("%s: from %s on %s",
-               label, from_str, ifp->name);
-  }
+       if (PIM_DEBUG_IGMP_TRACE) {
+               char from_str[INET_ADDRSTRLEN];
+               pim_inet4_dump("<from?>", from, from_str, sizeof(from_str));
+               zlog_debug("%s: from %s on %s", label, from_str, ifp->name);
+       }
 }
 
-void
-igmp_v2_send_query (struct igmp_group *group,
-                    int fd,
-                    const char *ifname,
-                    char *query_buf,
-                    struct in_addr dst_addr,
-                    struct in_addr group_addr,
-                    int query_max_response_time_dsec)
+void igmp_v2_send_query(struct igmp_group *group, int fd, const char *ifname,
+                       char *query_buf, struct in_addr dst_addr,
+                       struct in_addr group_addr,
+                       int query_max_response_time_dsec)
 {
-  ssize_t             msg_size = 8;
-  uint8_t             max_resp_code;
-  ssize_t             sent;
-  struct sockaddr_in  to;
-  socklen_t           tolen;
-  uint16_t            checksum;
-
-  /* max_resp_code must be non-zero else this will look like an IGMP v1 query */
-  max_resp_code = igmp_msg_encode16to8(query_max_response_time_dsec);
-  zassert(max_resp_code > 0);
-
-  query_buf[0] = PIM_IGMP_MEMBERSHIP_QUERY;
-  query_buf[1] = max_resp_code;
-  *(uint16_t *)(query_buf + IGMP_CHECKSUM_OFFSET)   = 0; /* for computing checksum */
-  memcpy(query_buf+4, &group_addr, sizeof(struct in_addr));
-
-  checksum = in_cksum(query_buf, msg_size);
-  *(uint16_t *)(query_buf + IGMP_CHECKSUM_OFFSET) = checksum;
-
-  if (PIM_DEBUG_IGMP_PACKETS) {
-    char dst_str[INET_ADDRSTRLEN];
-    char group_str[INET_ADDRSTRLEN];
-    pim_inet4_dump("<dst?>", dst_addr, dst_str, sizeof(dst_str));
-    pim_inet4_dump("<group?>", group_addr, group_str, sizeof(group_str));
-    zlog_debug("Send IGMPv2 QUERY to %s on %s for group %s",
-              dst_str, ifname, group_str);
-  }
-
-  memset(&to, 0, sizeof(to));
-  to.sin_family = AF_INET;
-  to.sin_addr = dst_addr;
-  tolen = sizeof(to);
-
-  sent = sendto(fd, query_buf, msg_size, MSG_DONTWAIT,
-                (struct sockaddr *)&to, tolen);
-  if (sent != (ssize_t) msg_size) {
-    char dst_str[INET_ADDRSTRLEN];
-    char group_str[INET_ADDRSTRLEN];
-    pim_inet4_dump("<dst?>", dst_addr, dst_str, sizeof(dst_str));
-    pim_inet4_dump("<group?>", group_addr, group_str, sizeof(group_str));
-    if (sent < 0) {
-      zlog_warn("Send IGMPv2 QUERY failed due to %s on %s: group=%s msg_size=%zd: errno=%d: %s",
-               dst_str, ifname, group_str, msg_size, errno, safe_strerror(errno));
-    }
-    else {
-      zlog_warn("Send IGMPv2 QUERY failed due to %s on %s: group=%s msg_size=%zd: sent=%zd",
-               dst_str, ifname, group_str, msg_size, sent);
-    }
-    return;
-  }
+       ssize_t msg_size = 8;
+       uint8_t max_resp_code;
+       ssize_t sent;
+       struct sockaddr_in to;
+       socklen_t tolen;
+       uint16_t checksum;
+
+       /* max_resp_code must be non-zero else this will look like an IGMP v1
+        * query */
+       max_resp_code = igmp_msg_encode16to8(query_max_response_time_dsec);
+       zassert(max_resp_code > 0);
+
+       query_buf[0] = PIM_IGMP_MEMBERSHIP_QUERY;
+       query_buf[1] = max_resp_code;
+       *(uint16_t *)(query_buf + IGMP_CHECKSUM_OFFSET) =
+               0; /* for computing checksum */
+       memcpy(query_buf + 4, &group_addr, sizeof(struct in_addr));
+
+       checksum = in_cksum(query_buf, msg_size);
+       *(uint16_t *)(query_buf + IGMP_CHECKSUM_OFFSET) = checksum;
+
+       if (PIM_DEBUG_IGMP_PACKETS) {
+               char dst_str[INET_ADDRSTRLEN];
+               char group_str[INET_ADDRSTRLEN];
+               pim_inet4_dump("<dst?>", dst_addr, dst_str, sizeof(dst_str));
+               pim_inet4_dump("<group?>", group_addr, group_str,
+                              sizeof(group_str));
+               zlog_debug("Send IGMPv2 QUERY to %s on %s for group %s",
+                          dst_str, ifname, group_str);
+       }
+
+       memset(&to, 0, sizeof(to));
+       to.sin_family = AF_INET;
+       to.sin_addr = dst_addr;
+       tolen = sizeof(to);
+
+       sent = sendto(fd, query_buf, msg_size, MSG_DONTWAIT,
+                     (struct sockaddr *)&to, tolen);
+       if (sent != (ssize_t)msg_size) {
+               char dst_str[INET_ADDRSTRLEN];
+               char group_str[INET_ADDRSTRLEN];
+               pim_inet4_dump("<dst?>", dst_addr, dst_str, sizeof(dst_str));
+               pim_inet4_dump("<group?>", group_addr, group_str,
+                              sizeof(group_str));
+               if (sent < 0) {
+                       zlog_warn(
+                               "Send IGMPv2 QUERY failed due to %s on %s: group=%s msg_size=%zd: errno=%d: %s",
+                               dst_str, ifname, group_str, msg_size, errno,
+                               safe_strerror(errno));
+               } else {
+                       zlog_warn(
+                               "Send IGMPv2 QUERY failed due to %s on %s: group=%s msg_size=%zd: sent=%zd",
+                               dst_str, ifname, group_str, msg_size, sent);
+               }
+               return;
+       }
 }
 
-int
-igmp_v2_recv_report (struct igmp_sock *igmp,
-                     struct in_addr from, const char *from_str,
-                     char *igmp_msg, int igmp_msg_len)
+int igmp_v2_recv_report(struct igmp_sock *igmp, struct in_addr from,
+                       const char *from_str, char *igmp_msg, int igmp_msg_len)
 {
-  struct interface *ifp = igmp->interface;
-  struct in_addr group_addr;
-  char group_str[INET_ADDRSTRLEN];
-
-  on_trace(__PRETTY_FUNCTION__, igmp->interface, from);
-
-  if (igmp_msg_len != IGMP_V12_MSG_SIZE) {
-    zlog_warn("Recv IGMPv2 REPORT from %s on %s: size=%d other than correct=%d",
-              from_str, ifp->name, igmp_msg_len, IGMP_V12_MSG_SIZE);
-    return -1;
-  }
-
-  memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr));
-
-  if (PIM_DEBUG_IGMP_PACKETS) {
-    pim_inet4_dump("<dst?>", group_addr, group_str, sizeof(group_str));
-    zlog_debug("Recv IGMPv2 REPORT from %s on %s for %s",
-               from_str, ifp->name, group_str);
-  }
-
-  /*
-   * RFC 3376
-   * 7.3.2. In the Presence of Older Version Group Members
-   *
-   * When Group Compatibility Mode is IGMPv2, a router internally
-   * translates the following IGMPv2 messages for that group to their
-   * IGMPv3 equivalents:
-   *
-   * IGMPv2 Message                IGMPv3 Equivalent
-   * --------------                -----------------
-   * Report                        IS_EX( {} )
-   * Leave                         TO_IN( {} )
-   */
-  igmpv3_report_isex (igmp, from, group_addr, 0, NULL, 1);
-
-  return 0;
+       struct interface *ifp = igmp->interface;
+       struct in_addr group_addr;
+       char group_str[INET_ADDRSTRLEN];
+
+       on_trace(__PRETTY_FUNCTION__, igmp->interface, from);
+
+       if (igmp->mtrace_only)
+               return 0;
+
+       if (igmp_msg_len != IGMP_V12_MSG_SIZE) {
+               zlog_warn(
+                       "Recv IGMPv2 REPORT from %s on %s: size=%d other than correct=%d",
+                       from_str, ifp->name, igmp_msg_len, IGMP_V12_MSG_SIZE);
+               return -1;
+       }
+
+       /* Collecting IGMP Rx stats */
+       igmp->rx_stats.report_v2++;
+
+       memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr));
+
+       if (PIM_DEBUG_IGMP_PACKETS) {
+               pim_inet4_dump("<dst?>", group_addr, group_str,
+                              sizeof(group_str));
+               zlog_debug("Recv IGMPv2 REPORT from %s on %s for %s", from_str,
+                          ifp->name, group_str);
+       }
+
+       /*
+        * RFC 3376
+        * 7.3.2. In the Presence of Older Version Group Members
+        *
+        * When Group Compatibility Mode is IGMPv2, a router internally
+        * translates the following IGMPv2 messages for that group to their
+        * IGMPv3 equivalents:
+        *
+        * IGMPv2 Message                IGMPv3 Equivalent
+        * --------------                -----------------
+        * Report                        IS_EX( {} )
+        * Leave                         TO_IN( {} )
+        */
+       igmpv3_report_isex(igmp, from, group_addr, 0, NULL, 1);
+
+       return 0;
 }
 
-int
-igmp_v2_recv_leave (struct igmp_sock *igmp,
-                    struct in_addr from, const char *from_str,
-                    char *igmp_msg, int igmp_msg_len)
+int igmp_v2_recv_leave(struct igmp_sock *igmp, struct in_addr from,
+                      const char *from_str, char *igmp_msg, int igmp_msg_len)
 {
-  struct interface *ifp = igmp->interface;
-  struct in_addr group_addr;
-  char group_str[INET_ADDRSTRLEN];
-
-  on_trace(__PRETTY_FUNCTION__, igmp->interface, from);
-
-  if (igmp_msg_len != IGMP_V12_MSG_SIZE) {
-    zlog_warn("Recv IGMPv2 LEAVE from %s on %s: size=%d other than correct=%d",
-              from_str, ifp->name, igmp_msg_len, IGMP_V12_MSG_SIZE);
-    return -1;
-  }
-
-  memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr));
-
-  if (PIM_DEBUG_IGMP_PACKETS) {
-    pim_inet4_dump("<dst?>", group_addr, group_str, sizeof(group_str));
-    zlog_debug("Recv IGMPv2 LEAVE from %s on %s for %s",
-               from_str, ifp->name, group_str);
-  }
-
-  /*
-   * RFC 3376
-   * 7.3.2. In the Presence of Older Version Group Members
-   *
-   * When Group Compatibility Mode is IGMPv2, a router internally
-   * translates the following IGMPv2 messages for that group to their
-   * IGMPv3 equivalents:
-   *
-   * IGMPv2 Message                IGMPv3 Equivalent
-   * --------------                -----------------
-   * Report                        IS_EX( {} )
-   * Leave                         TO_IN( {} )
-   */
-  igmpv3_report_toin (igmp, from, group_addr, 0, NULL);
-
-  return 0;
+       struct interface *ifp = igmp->interface;
+       struct in_addr group_addr;
+       char group_str[INET_ADDRSTRLEN];
+
+       on_trace(__PRETTY_FUNCTION__, igmp->interface, from);
+
+       if (igmp->mtrace_only)
+               return 0;
+
+       if (igmp_msg_len != IGMP_V12_MSG_SIZE) {
+               zlog_warn(
+                       "Recv IGMPv2 LEAVE from %s on %s: size=%d other than correct=%d",
+                       from_str, ifp->name, igmp_msg_len, IGMP_V12_MSG_SIZE);
+               return -1;
+       }
+
+       /* Collecting IGMP Rx stats */
+       igmp->rx_stats.leave_v2++;
+
+       memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr));
+
+       if (PIM_DEBUG_IGMP_PACKETS) {
+               pim_inet4_dump("<dst?>", group_addr, group_str,
+                              sizeof(group_str));
+               zlog_debug("Recv IGMPv2 LEAVE from %s on %s for %s", from_str,
+                          ifp->name, group_str);
+       }
+
+       /*
+        * RFC 3376
+        * 7.3.2. In the Presence of Older Version Group Members
+        *
+        * When Group Compatibility Mode is IGMPv2, a router internally
+        * translates the following IGMPv2 messages for that group to their
+        * IGMPv3 equivalents:
+        *
+        * IGMPv2 Message                IGMPv3 Equivalent
+        * --------------                -----------------
+        * Report                        IS_EX( {} )
+        * Leave                         TO_IN( {} )
+        */
+       igmpv3_report_toin(igmp, from, group_addr, 0, NULL);
+
+       return 0;
 }