]> git.proxmox.com Git - mirror_frr.git/blobdiff - pimd/pim_msg.c
Merge pull request #423 from opensourcerouting/feature/isis-mt
[mirror_frr.git] / pimd / pim_msg.c
index 61fc480bf9a8458fc3ac75303aad191088343a6c..e19893f5dab4253f7de1970b64b4b77bbb270b98 100644 (file)
   along with this program; see the file COPYING; if not, write to the
   Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
   MA 02110-1301 USA
-  
 */
 
 #include <zebra.h>
 
 #include "if.h"
 #include "log.h"
+#include "prefix.h"
+#include "vty.h"
+#include "plist.h"
 
 #include "pimd.h"
+#include "pim_vty.h"
 #include "pim_pim.h"
 #include "pim_msg.h"
 #include "pim_util.h"
 #include "pim_str.h"
+#include "pim_iface.h"
+#include "pim_rp.h"
+#include "pim_rpf.h"
+#include "pim_register.h"
+#include "pim_jp_agg.h"
 
-void pim_msg_build_header(uint8_t *pim_msg, int pim_msg_size,
-                         uint8_t pim_msg_type)
+void pim_msg_build_header(uint8_t *pim_msg, size_t pim_msg_size, uint8_t pim_msg_type)
 {
-  uint16_t checksum;
-
-  zassert(pim_msg_size >= PIM_PIM_MIN_LEN);
+  struct pim_msg_header *header = (struct pim_msg_header *)pim_msg;
 
   /*
    * Write header
    */
+  header->ver = PIM_PROTO_VERSION;
+  header->type = pim_msg_type;
+  header->reserved = 0;
 
-  *(uint8_t *) PIM_MSG_HDR_OFFSET_VERSION(pim_msg) = (PIM_PROTO_VERSION << 4) | pim_msg_type;
-  *(uint8_t *) PIM_MSG_HDR_OFFSET_RESERVED(pim_msg) = 0;
 
+  header->checksum = 0;
   /*
-   * Compute checksum
+   * The checksum for Registers is done only on the first 8 bytes of the packet,
+   * including the PIM header and the next 4 bytes, excluding the data packet portion
    */
-
-  *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg) = 0;
-  checksum = in_cksum(pim_msg, pim_msg_size);
-  *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg) = checksum;
+  if (pim_msg_type == PIM_MSG_TYPE_REGISTER)
+    header->checksum = in_cksum (pim_msg, PIM_MSG_REGISTER_LEN);
+  else
+    header->checksum = in_cksum (pim_msg, pim_msg_size);
 }
 
-uint8_t *pim_msg_addr_encode_ipv4_ucast(uint8_t *buf,
-                                       int buf_size,
-                                       struct in_addr addr)
+uint8_t *pim_msg_addr_encode_ipv4_ucast(uint8_t *buf, struct in_addr addr)
 {
-  const int ENCODED_IPV4_UCAST_SIZE = 6;
-
-  if (buf_size < ENCODED_IPV4_UCAST_SIZE) {
-    return 0;
-  }
-
   buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV4; /* addr family */
   buf[1] = '\0';    /* native encoding */
   memcpy(buf+2, &addr, sizeof(struct in_addr));
 
-  return buf + ENCODED_IPV4_UCAST_SIZE;
+  return buf + PIM_ENCODED_IPV4_UCAST_SIZE;
 }
 
-uint8_t *pim_msg_addr_encode_ipv4_group(uint8_t *buf,
-                                       int buf_size,
-                                       struct in_addr addr)
+uint8_t *pim_msg_addr_encode_ipv4_group(uint8_t *buf, struct in_addr addr)
 {
-  const int ENCODED_IPV4_GROUP_SIZE = 8;
-
-  if (buf_size < ENCODED_IPV4_GROUP_SIZE) {
-    return 0;
-  }
-
   buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV4; /* addr family */
   buf[1] = '\0';    /* native encoding */
   buf[2] = '\0';    /* reserved */
   buf[3] = 32;      /* mask len */
   memcpy(buf+4, &addr, sizeof(struct in_addr));
 
-  return buf + ENCODED_IPV4_GROUP_SIZE;
+  return buf + PIM_ENCODED_IPV4_GROUP_SIZE;
 }
 
 uint8_t *
-pim_msg_addr_encode_ipv4_source(uint8_t *buf, int buf_size,
-                               struct in_addr addr, uint8_t bits)
+pim_msg_addr_encode_ipv4_source(uint8_t *buf,
+                                struct in_addr addr, uint8_t bits)
 {
-  const int ENCODED_IPV4_SOURCE_SIZE = 8;
-
-  if (buf_size < ENCODED_IPV4_SOURCE_SIZE) {
-    return 0;
-  }
-
   buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV4; /* addr family */
   buf[1] = '\0';    /* native encoding */
   buf[2] = bits;
   buf[3] = 32;      /* mask len */
   memcpy(buf+4, &addr, sizeof(struct in_addr));
 
-  return buf + ENCODED_IPV4_SOURCE_SIZE;
+  return buf + PIM_ENCODED_IPV4_SOURCE_SIZE;
 }
 
-int
-pim_msg_join_prune_encode (uint8_t *buf, int buf_size, int is_join,
-                          struct in_addr source, struct in_addr group,
-                          struct in_addr upstream, int holdtime)
+/*
+ * For the given 'struct pim_jp_sources' list
+ * determine the size_t it would take up.
+ */
+size_t
+pim_msg_get_jp_group_size (struct list *sources)
 {
-  uint8_t *pim_msg = buf;
-  uint8_t *pim_msg_curr = buf + PIM_MSG_HEADER_LEN;
-  uint8_t *end = buf + buf_size;
+  struct pim_jp_sources *js;
+  size_t size = 0;
+
+  size += sizeof (struct pim_encoded_group_ipv4);
+  size += 4;  // Joined sources (2) + Pruned Sources (2)
+
+  size += sizeof (struct pim_encoded_source_ipv4) * sources->count;
+
+  js = listgetdata(listhead(sources));
+  if (js && js->up->sg.src.s_addr == INADDR_ANY)
+    {
+      struct pim_upstream *child, *up;
+      struct listnode *up_node;
+
+      up = js->up;
+      if (PIM_DEBUG_PIM_PACKETS)
+        zlog_debug ("%s: Considering (%s) children for (S,G,rpt) prune",
+                    __PRETTY_FUNCTION__, up->sg_str);
+
+      for (ALL_LIST_ELEMENTS_RO (up->sources, up_node, child))
+        {
+          if (child->sptbit == PIM_UPSTREAM_SPTBIT_TRUE)
+            {
+              if (!pim_rpf_is_same(&up->rpf, &child->rpf))
+                {
+                  size += sizeof (struct pim_encoded_source_ipv4);
+                  PIM_UPSTREAM_FLAG_SET_SEND_SG_RPT_PRUNE(child->flags);
+                  if (PIM_DEBUG_PIM_PACKETS)
+                    zlog_debug ("%s: SPT Bit and RPF'(%s) != RPF'(S,G): Add Prune (%s,rpt) to compound message",
+                                __PRETTY_FUNCTION__, up->sg_str, child->sg_str);
+                }
+              else
+                if (PIM_DEBUG_PIM_PACKETS)
+                  zlog_debug ("%s: SPT Bit and RPF'(%s) == RPF'(S,G): Not adding Prune for (%s,rpt)",
+                              __PRETTY_FUNCTION__, up->sg_str, child->sg_str);
+            }
+          else if (pim_upstream_is_sg_rpt (child))
+            {
+              if (pim_upstream_empty_inherited_olist (child))
+                {
+                  size += sizeof (struct pim_encoded_source_ipv4);
+                  PIM_UPSTREAM_FLAG_SET_SEND_SG_RPT_PRUNE(child->flags);
+                  if (PIM_DEBUG_PIM_PACKETS)
+                    zlog_debug ("%s: inherited_olist(%s,rpt) is NULL, Add Prune to compound message",
+                                __PRETTY_FUNCTION__, child->sg_str);
+                }
+              else if (!pim_rpf_is_same (&up->rpf, &child->rpf))
+                {
+                  size += sizeof (struct pim_encoded_source_ipv4);
+                  PIM_UPSTREAM_FLAG_SET_SEND_SG_RPT_PRUNE(child->flags);
+                  if (PIM_DEBUG_PIM_PACKETS)
+                    zlog_debug ("%s: RPF'(%s) != RPF'(%s,rpt), Add Prune to compound message",
+                                __PRETTY_FUNCTION__, up->sg_str, child->sg_str);
+                }
+              else
+                if (PIM_DEBUG_PIM_PACKETS)
+                  zlog_debug ("%s: RPF'(%s) == RPF'(%s,rpt), Do not add Prune to compound message",
+                              __PRETTY_FUNCTION__, up->sg_str, child->sg_str);
+            }
+          else
+            if (PIM_DEBUG_PIM_PACKETS)
+              zlog_debug ("%s: SPT bit is not set for (%s)",
+                          __PRETTY_FUNCTION__, child->sg_str);
+        }
+    }
+  return size;
+}
+
+size_t
+pim_msg_build_jp_groups (struct pim_jp_groups *grp, struct pim_jp_agg_group *sgs, size_t size)
+{
+  struct listnode *node, *nnode;
+  struct pim_jp_sources *source;
+  struct pim_upstream *up = NULL;
   struct in_addr stosend;
   uint8_t bits;
-  int remain;
-
-  remain = end - pim_msg_curr;
-  pim_msg_curr = pim_msg_addr_encode_ipv4_ucast (pim_msg_curr, buf_size - PIM_MSG_HEADER_LEN, upstream);
-  if (!pim_msg_curr) {
-    char dst_str[100];
-    pim_inet4_dump("<dst?>", upstream, dst_str, sizeof(dst_str));
-    zlog_warn("%s: failure encoding destination address %s: space left=%d",
-             __PRETTY_FUNCTION__, dst_str, remain);
-    return -3;
-  }
-
-  remain = end - pim_msg_curr;
-  if (remain < 4) {
-    zlog_warn("%s: group will not fit: space left=%d",
-           __PRETTY_FUNCTION__, remain);
-    return -4;
-  }
-
-  *pim_msg_curr = 0; /* reserved */
-  ++pim_msg_curr;
-  *pim_msg_curr = 1; /* number of groups */
-  ++pim_msg_curr;
-
-  *((uint16_t *) pim_msg_curr) = htons(holdtime);
-  ++pim_msg_curr;
-  ++pim_msg_curr;
-
-  remain = end - pim_msg_curr;
-  pim_msg_curr = pim_msg_addr_encode_ipv4_group (pim_msg_curr, remain,
-                                                 group);
-  if (!pim_msg_curr) {
-    char group_str[100];
-    pim_inet4_dump("<grp?>", group, group_str, sizeof(group_str));
-    zlog_warn("%s: failure encoding group address %s: space left=%d",
-             __PRETTY_FUNCTION__, group_str, remain);
-    return -5;
-  }
-
-  remain = end - pim_msg_curr;
-  if (remain < 4) {
-    zlog_warn("%s: sources will not fit: space left=%d",
-             __PRETTY_FUNCTION__, remain);
-    return -6;
-  }
-
-  /* number of joined sources */
-  *((uint16_t *) pim_msg_curr) = htons(is_join ? 1 : 0);
-  ++pim_msg_curr;
-  ++pim_msg_curr;
-
-  /* number of pruned sources */
-  *((uint16_t *) pim_msg_curr) = htons(is_join ? 0 : 1);
-  ++pim_msg_curr;
-  ++pim_msg_curr;
-
-  remain = end - pim_msg_curr;
-  if (source.s_addr == INADDR_ANY)
+  uint8_t tgroups = 0;
+
+  memset (grp, 0, size);
+  pim_msg_addr_encode_ipv4_group ((uint8_t *)&grp->g, sgs->group);
+
+  for (ALL_LIST_ELEMENTS(sgs->sources, node, nnode, source))
     {
-      bits = PIM_ENCODE_SPARSE_BIT | PIM_ENCODE_WC_BIT | PIM_ENCODE_RPT_BIT;
-      stosend = qpim_rp.rpf_addr;
+      /* number of joined/pruned sources */
+      if (source->is_join)
+        grp->joins++;
+      else
+        grp->prunes++;
+
+      if (source->up->sg.src.s_addr == INADDR_ANY)
+        {
+          struct pim_rpf *rpf = pim_rp_g (source->up->sg.grp);
+          bits = PIM_ENCODE_SPARSE_BIT | PIM_ENCODE_WC_BIT | PIM_ENCODE_RPT_BIT;
+          stosend = rpf->rpf_addr.u.prefix4;
+          up = source->up;
+        }
+      else
+        {
+          bits = PIM_ENCODE_SPARSE_BIT;
+          stosend = source->up->sg.src;
+        }
+
+      pim_msg_addr_encode_ipv4_source ((uint8_t *)&grp->s[tgroups], stosend, bits);
+      tgroups++;
     }
-  else
+
+  if (up)
     {
-      bits = PIM_ENCODE_SPARSE_BIT;
-      stosend = source;
+      struct pim_upstream *child;
+
+      for (ALL_LIST_ELEMENTS(up->sources, node, nnode, child))
+        {
+          if (PIM_UPSTREAM_FLAG_TEST_SEND_SG_RPT_PRUNE(child->flags))
+            {
+              pim_msg_addr_encode_ipv4_source ((uint8_t *)&grp->s[tgroups],
+                                               child->sg.src,
+                                               PIM_ENCODE_SPARSE_BIT | PIM_ENCODE_RPT_BIT);
+              tgroups++;
+              PIM_UPSTREAM_FLAG_UNSET_SEND_SG_RPT_PRUNE(child->flags);
+              grp->prunes++;
+            }
+        }
     }
-  pim_msg_curr = pim_msg_addr_encode_ipv4_source (pim_msg_curr, remain, stosend, bits);
-  if (!pim_msg_curr) {
-    char source_str[100];
-    pim_inet4_dump("<src?>", source, source_str, sizeof(source_str));
-    zlog_warn("%s: failure encoding source address %s: space left=%d",
-             __PRETTY_FUNCTION__, source_str, remain);
-    return -7;
-  }
-
-  remain = pim_msg_curr - pim_msg;
-  pim_msg_build_header (pim_msg, remain, PIM_MSG_TYPE_JOIN_PRUNE);
-
-  return remain;
+
+  grp->joins = htons(grp->joins);
+  grp->prunes = htons(grp->prunes);
+
+  return size;
 }