]> git.proxmox.com Git - mirror_frr.git/blobdiff - pimd/pim_register.c
lib: enforce vrf_name_to_id by returning default_vrf when name is null
[mirror_frr.git] / pimd / pim_register.c
index 7844bd339946f05f7939f1fed82ea6bfbf7e50a6..b9908ae22be4ea5bbabee4b65f08624c170b82e1 100644 (file)
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
- * 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
+ * You should have received a copy of the GNU General Public License 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>
@@ -24,6 +23,9 @@
 #include "log.h"
 #include "if.h"
 #include "thread.h"
+#include "prefix.h"
+#include "vty.h"
+#include "plist.h"
 
 #include "pimd.h"
 #include "pim_mroute.h"
 #include "pim_oil.h"
 #include "pim_zebra.h"
 #include "pim_join.h"
+#include "pim_util.h"
+#include "pim_ssm.h"
 
 struct thread *send_test_packet_timer = NULL;
 
-/*
- * This seems stupidly expensive.  A list lookup.  Why is this
- * not a hash?
- */
-static int
-pim_check_is_my_ip_address (struct in_addr dest_addr)
+void pim_register_join(struct pim_upstream *up)
+{
+       struct pim_instance *pim = up->channel_oil->pim;
+
+       if (pim_is_grp_ssm(pim, up->sg.grp)) {
+               if (PIM_DEBUG_PIM_EVENTS)
+                       zlog_debug("%s register setup skipped as group is SSM",
+                                  up->sg_str);
+               return;
+       }
+
+       pim_channel_add_oif(up->channel_oil, pim->regiface,
+                           PIM_OIF_FLAG_PROTO_PIM);
+       up->reg_state = PIM_REG_JOIN;
+}
+
+void pim_register_stop_send(struct interface *ifp, struct prefix_sg *sg,
+                           struct in_addr src, struct in_addr originator)
 {
-  /*
-   * See if we can short-cut some?
-   * This might not make sense if we ever leave a static RP
-   * type of configuration.
-   * Note - Premature optimization might bite our patooeys' here.
-   */
-  if (I_am_RP(dest_addr) && (dest_addr.s_addr == qpim_rp.rpf_addr.s_addr))
-    return 1;
-
-  if (if_lookup_exact_address (&dest_addr, AF_INET))
-    return 1;
-
-  return 0;
+       struct pim_interface *pinfo;
+       unsigned char buffer[10000];
+       unsigned int b1length = 0;
+       unsigned int length;
+       uint8_t *b1;
+       struct prefix p;
+
+       if (PIM_DEBUG_PIM_REG) {
+               zlog_debug("Sending Register stop for %s to %s on %s",
+                          pim_str_sg_dump(sg), inet_ntoa(originator),
+                          ifp->name);
+       }
+
+       memset(buffer, 0, 10000);
+       b1 = (uint8_t *)buffer + PIM_MSG_REGISTER_STOP_LEN;
+
+       length = pim_encode_addr_group(b1, AFI_IP, 0, 0, sg->grp);
+       b1length += length;
+       b1 += length;
+
+       p.family = AF_INET;
+       p.u.prefix4 = sg->src;
+       p.prefixlen = 32;
+       length = pim_encode_addr_ucast(b1, &p);
+       b1length += length;
+
+       pim_msg_build_header(buffer, b1length + PIM_MSG_REGISTER_STOP_LEN,
+                            PIM_MSG_TYPE_REG_STOP);
+
+       pinfo = (struct pim_interface *)ifp->info;
+       if (!pinfo) {
+               if (PIM_DEBUG_PIM_TRACE)
+                       zlog_debug("%s: No pinfo!\n", __PRETTY_FUNCTION__);
+               return;
+       }
+       if (pim_msg_send(pinfo->pim_sock_fd, src, originator, buffer,
+                        b1length + PIM_MSG_REGISTER_STOP_LEN, ifp->name)) {
+               if (PIM_DEBUG_PIM_TRACE) {
+                       zlog_debug(
+                               "%s: could not send PIM register stop message on interface %s",
+                               __PRETTY_FUNCTION__, ifp->name);
+               }
+       }
+       ++pinfo->pim_ifstat_reg_stop_send;
 }
 
-static void
-pim_register_stop_send (struct in_addr src)
+int pim_register_stop_recv(struct interface *ifp, uint8_t *buf, int buf_size)
 {
-  return;
+       struct pim_interface *pim_ifp = ifp->info;
+       struct pim_instance *pim = pim_ifp->pim;
+       struct pim_upstream *upstream = NULL;
+       struct prefix source;
+       struct prefix_sg sg;
+       int l;
+
+       memset(&sg, 0, sizeof(struct prefix_sg));
+       l = pim_parse_addr_group(&sg, buf, buf_size);
+       buf += l;
+       buf_size -= l;
+       pim_parse_addr_ucast(&source, buf, buf_size);
+       sg.src = source.u.prefix4;
+
+       upstream = pim_upstream_find(pim, &sg);
+       if (!upstream) {
+               return 0;
+       }
+
+       if (PIM_DEBUG_PIM_REG)
+               zlog_debug("Received Register stop for %s", upstream->sg_str);
+
+       switch (upstream->reg_state) {
+       case PIM_REG_NOINFO:
+       case PIM_REG_PRUNE:
+               return 0;
+               break;
+       case PIM_REG_JOIN:
+               upstream->reg_state = PIM_REG_PRUNE;
+               pim_channel_del_oif(upstream->channel_oil, pim->regiface,
+                                   PIM_OIF_FLAG_PROTO_PIM);
+               pim_upstream_start_register_stop_timer(upstream, 0);
+               break;
+       case PIM_REG_JOIN_PENDING:
+               upstream->reg_state = PIM_REG_PRUNE;
+               pim_upstream_start_register_stop_timer(upstream, 0);
+               return 0;
+               break;
+       }
+
+       return 0;
 }
 
-void
-pim_register_send (const struct ip *ip_hdr, struct pim_rpf *rpg)
+void pim_register_send(const uint8_t *buf, int buf_size, struct in_addr src,
+                      struct pim_rpf *rpg, int null_register,
+                      struct pim_upstream *up)
 {
-  unsigned char buffer[3000];
-  unsigned char *b1;
-  struct pim_interface *pinfo;
-  struct interface *ifp;
-  uint32_t plen;
-
-  ifp = rpg->source_nexthop.interface;
-  pinfo = (struct pim_interface *)ifp->info;
-  if (!pinfo) {
-    zlog_debug("%s: No pinfo!\n", __PRETTY_FUNCTION__);
-    return;
-  }
-
-  memset(buffer, 0, 3000);
-  b1 = buffer + PIM_MSG_REGISTER_LEN;
-
-  plen = ntohs(ip_hdr->ip_len);
-  memcpy(b1, (const unsigned char *)ip_hdr, plen);
-
-  pim_msg_build_header(buffer, plen + PIM_MSG_REGISTER_LEN, PIM_MSG_TYPE_REGISTER);
-
-  if (pim_msg_send(pinfo->pim_sock_fd,
-                  rpg->rpf_addr,
-                  buffer,
-                  plen + PIM_MSG_REGISTER_LEN,
-                  ifp->name)) {
-    if (PIM_DEBUG_PIM_TRACE) {
-      zlog_debug("%s: could not send PIM register message on interface %s",
-                __PRETTY_FUNCTION__, ifp->name);
-    }
-    return;
-  }
+       unsigned char buffer[10000];
+       unsigned char *b1;
+       struct pim_interface *pinfo;
+       struct interface *ifp;
+
+       if (PIM_DEBUG_PIM_REG) {
+               zlog_debug("Sending %s %sRegister Packet to %s", up->sg_str,
+                          null_register ? "NULL " : "",
+                          inet_ntoa(rpg->rpf_addr.u.prefix4));
+       }
+
+       ifp = rpg->source_nexthop.interface;
+       if (!ifp) {
+               if (PIM_DEBUG_PIM_REG)
+                       zlog_debug("%s: No interface to transmit register on",
+                                  __PRETTY_FUNCTION__);
+               return;
+       }
+       pinfo = (struct pim_interface *)ifp->info;
+       if (!pinfo) {
+               if (PIM_DEBUG_PIM_REG)
+                       zlog_debug(
+                               "%s: Interface: %s not configured for pim to trasmit on!\n",
+                               __PRETTY_FUNCTION__, ifp->name);
+               return;
+       }
+
+       if (PIM_DEBUG_PIM_REG) {
+               char rp_str[INET_ADDRSTRLEN];
+               strncpy(rp_str, inet_ntoa(rpg->rpf_addr.u.prefix4),
+                       INET_ADDRSTRLEN - 1);
+               zlog_debug("%s: Sending %s %sRegister Packet to %s on %s",
+                          __PRETTY_FUNCTION__, up->sg_str,
+                          null_register ? "NULL " : "", rp_str, ifp->name);
+       }
+
+       memset(buffer, 0, 10000);
+       b1 = buffer + PIM_MSG_HEADER_LEN;
+       *b1 |= null_register << 6;
+       b1 = buffer + PIM_MSG_REGISTER_LEN;
+
+       memcpy(b1, (const unsigned char *)buf, buf_size);
+
+       pim_msg_build_header(buffer, buf_size + PIM_MSG_REGISTER_LEN,
+                            PIM_MSG_TYPE_REGISTER);
+
+       ++pinfo->pim_ifstat_reg_send;
+
+       if (pim_msg_send(pinfo->pim_sock_fd, src, rpg->rpf_addr.u.prefix4,
+                        buffer, buf_size + PIM_MSG_REGISTER_LEN, ifp->name)) {
+               if (PIM_DEBUG_PIM_TRACE) {
+                       zlog_debug(
+                               "%s: could not send PIM register message on interface %s",
+                               __PRETTY_FUNCTION__, ifp->name);
+               }
+               return;
+       }
 }
 
 /*
@@ -151,162 +263,189 @@ pim_register_send (const struct ip *ip_hdr, struct pim_rpf *rpg)
  *      }
  *  }
  */
-int
-pim_register_recv (struct interface *ifp,
-                  struct in_addr dest_addr,
-                  struct in_addr src_addr,
-                  uint8_t *tlv_buf, int tlv_buf_size)
-{
-  int sentRegisterStop = 0;
-  struct ip *ip_hdr;
-  //size_t hlen;
-  struct in_addr group;
-  struct in_addr source;
-  //uint8_t *msg;
-  uint32_t *bits;
-
-  if (!pim_check_is_my_ip_address (dest_addr)) {
-    if (PIM_DEBUG_PIM_PACKETS) {
-      char dest[100];
-
-      pim_inet4_dump ("<dst?>", dest_addr, dest, sizeof(dest));
-      zlog_debug ("%s: Received Register message for %s that I do not own", __func__,
-                 dest);
-    }
-    return 0;
-  }
-
-#define inherited_olist(S,G) NULL
-  /*
-   * Please note this is not drawn to get the correct bit/data size
-   *
-   * The entirety of the REGISTER packet looks like this:
-   * -------------------------------------------------------------
-   * | Ver  | Type | Reserved     |       Checksum               |
-   * |-----------------------------------------------------------|
-   * |B|N|     Reserved 2                                        |
-   * |-----------------------------------------------------------|
-   * | Encap  |                IP HDR                            |
-   * | Mcast  |                                                  |
-   * | Packet |--------------------------------------------------|
-   * |        |               Mcast Data                         |
-   * |        |                                                  |
-   * ...
-   *
-   * tlv_buf when received from the caller points at the B bit
-   * We need to know the inner source and dest
-   */
-  bits = (uint32_t *)tlv_buf;
-
-  /*
-   * tlv_buf points to the start of the |B|N|... Reserved
-   * Line above.  So we need to add 4 bytes to get to the
-   * start of the actual Encapsulated data.
-   */
-#define PIM_MSG_REGISTER_BIT_RESERVED_LEN 4
-  ip_hdr = (struct ip *)(tlv_buf + PIM_MSG_REGISTER_BIT_RESERVED_LEN);
-  //hlen = (ip_hdr->ip_hl << 2) | PIM_MSG_REGISTER_LEN;
-  //msg = (uint8_t *)tlv_buf + hlen;
-  source = ip_hdr->ip_src;
-  group = ip_hdr->ip_dst;
-
-  if (I_am_RP (group) && (dest_addr.s_addr == ((RP (group))->rpf_addr.s_addr))) {
-    sentRegisterStop = 0;
-
-    if (*bits & PIM_REGISTER_BORDER_BIT) {
-      struct in_addr pimbr = pim_br_get_pmbr (source, group);
-      if (PIM_DEBUG_PIM_PACKETS)
-       zlog_debug("%s: Received Register message with Border bit set", __func__);
-
-      if (pimbr.s_addr == pim_br_unknown.s_addr)
-       pim_br_set_pmbr(source, group, src_addr);
-      else if (src_addr.s_addr != pimbr.s_addr) {
-       pim_register_stop_send(src_addr);
-       if (PIM_DEBUG_PIM_PACKETS)
-         zlog_debug("%s: Sending register-Stop to %s and dropping mr. packet",
-           __func__, "Sender");
-       /* Drop Packet Silently */
-       return 1;
-      }
-    }
-
-    struct pim_upstream *upstream = pim_upstream_find (source, group);
-    /*
-     * If we don't have a place to send ignore the packet
-     */
-    if (!upstream)
-      return 1;
-
-    if ((upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) ||
-       ((SwitchToSptDesired(source, group)) &&
-        (inherited_olist(source, group) == NULL))) {
-      pim_register_stop_send(src_addr);
-      sentRegisterStop = 1;
-    }
-
-    if ((upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) ||
-       (SwitchToSptDesired(source, group))) {
-      if (sentRegisterStop) {
-       pim_upstream_keep_alive_timer_start (upstream, PIM_RP_KEEPALIVE_PERIOD);
-      } else {
-       pim_upstream_keep_alive_timer_start (upstream, PIM_KEEPALIVE_PERIOD);
-      }
-    }
-
-    if (!(upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) &&
-       !(*bits & PIM_REGISTER_NR_BIT))
-      {
-       pim_rp_set_upstream_addr (&upstream->upstream_addr, source);
-       pim_nexthop_lookup (&upstream->rpf.source_nexthop,
-                           upstream->upstream_addr, NULL);
-       upstream->rpf.source_nexthop.interface = ifp;
-       upstream->source_addr.s_addr = source.s_addr;
-       upstream->rpf.rpf_addr.s_addr = source.s_addr;
-       upstream->channel_oil->oil.mfcc_origin = source;
-       pim_scan_individual_oil (upstream->channel_oil);
-       pim_joinprune_send(upstream->rpf.source_nexthop.interface,
-                          upstream->rpf.source_nexthop.mrib_nexthop_addr,
-                          upstream->source_addr,
-                          upstream->group_addr,
-                          1);
-
-       //decapsulate and forward the iner packet to
-       //inherited_olist(S,G,rpt)
-      }
-  } else {
-    pim_register_stop_send(src_addr);
-  }
-
-  return 1;
-}
-
-
-static int
-pim_register_send_test_packet (struct thread *t)
-{
-  uint8_t *packet;
-
-  packet = THREAD_ARG(t);
-
-  *packet = 4;
-
-  return 1;
-}
-
-/*
- * pim_register_send_test_packet
- *
- * Send a test packet to the RP from source, in group and pps packets per second
- */
-void
-pim_register_send_test_packet_start (struct in_addr source,
-                                    struct in_addr group,
-                                    uint32_t pps)
+int pim_register_recv(struct interface *ifp, struct in_addr dest_addr,
+                     struct in_addr src_addr, uint8_t *tlv_buf,
+                     int tlv_buf_size)
 {
-  uint8_t *packet = NULL;
+       int sentRegisterStop = 0;
+       struct ip *ip_hdr;
+       struct prefix_sg sg;
+       uint32_t *bits;
+       int i_am_rp = 0;
+       struct pim_interface *pim_ifp = NULL;
 
-  THREAD_TIMER_MSEC_ON(master, send_test_packet_timer,
-                      pim_register_send_test_packet, packet, 1000/pps);
+       pim_ifp = ifp->info;
 
-  return;
+#define PIM_MSG_REGISTER_BIT_RESERVED_LEN 4
+       ip_hdr = (struct ip *)(tlv_buf + PIM_MSG_REGISTER_BIT_RESERVED_LEN);
+
+       if (!pim_rp_check_is_my_ip_address(pim_ifp->pim, ip_hdr->ip_dst,
+                                          dest_addr)) {
+               if (PIM_DEBUG_PIM_REG) {
+                       char dest[INET_ADDRSTRLEN];
+
+                       pim_inet4_dump("<dst?>", dest_addr, dest, sizeof(dest));
+                       zlog_debug(
+                               "%s: Received Register message for %s that I do not own",
+                               __func__, dest);
+               }
+               return 0;
+       }
+
+       ++pim_ifp->pim_ifstat_reg_recv;
+
+       /*
+        * Please note this is not drawn to get the correct bit/data size
+        *
+        * The entirety of the REGISTER packet looks like this:
+        * -------------------------------------------------------------
+        * | Ver  | Type | Reserved     |       Checksum               |
+        * |-----------------------------------------------------------|
+        * |B|N|     Reserved 2                                        |
+        * |-----------------------------------------------------------|
+        * | Encap  |                IP HDR                            |
+        * | Mcast  |                                                  |
+        * | Packet |--------------------------------------------------|
+        * |        |               Mcast Data                         |
+        * |        |                                                  |
+        * ...
+        *
+        * tlv_buf when received from the caller points at the B bit
+        * We need to know the inner source and dest
+        */
+       bits = (uint32_t *)tlv_buf;
+
+       /*
+        * tlv_buf points to the start of the |B|N|... Reserved
+        * Line above.  So we need to add 4 bytes to get to the
+        * start of the actual Encapsulated data.
+        */
+       memset(&sg, 0, sizeof(struct prefix_sg));
+       sg.src = ip_hdr->ip_src;
+       sg.grp = ip_hdr->ip_dst;
+
+       i_am_rp = I_am_RP(pim_ifp->pim, sg.grp);
+
+       if (PIM_DEBUG_PIM_REG) {
+               char src_str[INET_ADDRSTRLEN];
+
+               pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
+               zlog_debug(
+                       "Received Register message(%s) from %s on %s, rp: %d",
+                       pim_str_sg_dump(&sg), src_str, ifp->name, i_am_rp);
+       }
+
+       if (i_am_rp
+           && (dest_addr.s_addr
+               == ((RP(pim_ifp->pim, sg.grp))->rpf_addr.u.prefix4.s_addr))) {
+               sentRegisterStop = 0;
+
+               if (*bits & PIM_REGISTER_BORDER_BIT) {
+                       struct in_addr pimbr = pim_br_get_pmbr(&sg);
+                       if (PIM_DEBUG_PIM_PACKETS)
+                               zlog_debug(
+                                       "%s: Received Register message with Border bit set",
+                                       __func__);
+
+                       if (pimbr.s_addr == pim_br_unknown.s_addr)
+                               pim_br_set_pmbr(&sg, src_addr);
+                       else if (src_addr.s_addr != pimbr.s_addr) {
+                               pim_register_stop_send(ifp, &sg, dest_addr,
+                                                      src_addr);
+                               if (PIM_DEBUG_PIM_PACKETS)
+                                       zlog_debug(
+                                               "%s: Sending register-Stop to %s and dropping mr. packet",
+                                               __func__, "Sender");
+                               /* Drop Packet Silently */
+                               return 0;
+                       }
+               }
+
+               struct pim_upstream *upstream =
+                       pim_upstream_find(pim_ifp->pim, &sg);
+               /*
+                * If we don't have a place to send ignore the packet
+                */
+               if (!upstream) {
+                       upstream = pim_upstream_add(
+                               pim_ifp->pim, &sg, ifp,
+                               PIM_UPSTREAM_FLAG_MASK_SRC_STREAM,
+                               __PRETTY_FUNCTION__, NULL);
+                       if (!upstream) {
+                               zlog_warn("Failure to create upstream state");
+                               return 1;
+                       }
+
+                       upstream->upstream_register = src_addr;
+               } else {
+                       /*
+                        * If the FHR has set a very very fast register timer
+                        * there exists a possibility that the incoming NULL
+                        * register
+                        * is happening before we set the spt bit.  If so
+                        * Do a quick check to update the counters and
+                        * then set the spt bit as appropriate
+                        */
+                       if (upstream->sptbit != PIM_UPSTREAM_SPTBIT_TRUE) {
+                               pim_mroute_update_counters(
+                                       upstream->channel_oil);
+                               /*
+                                * Have we seen packets?
+                                */
+                               if (upstream->channel_oil->cc.oldpktcnt
+                                   < upstream->channel_oil->cc.pktcnt)
+                                       pim_upstream_set_sptbit(
+                                               upstream,
+                                               upstream->rpf.source_nexthop
+                                                       .interface);
+                       }
+               }
+
+               if ((upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE)
+                   || ((SwitchToSptDesired(pim_ifp->pim, &sg))
+                       && pim_upstream_inherited_olist(pim_ifp->pim, upstream)
+                                  == 0)) {
+                       // pim_scan_individual_oil (upstream->channel_oil);
+                       pim_register_stop_send(ifp, &sg, dest_addr, src_addr);
+                       sentRegisterStop = 1;
+               } else {
+                       if (PIM_DEBUG_PIM_REG)
+                               zlog_debug("(%s) sptbit: %d", upstream->sg_str,
+                                          upstream->sptbit);
+               }
+               if ((upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE)
+                   || (SwitchToSptDesired(pim_ifp->pim, &sg))) {
+                       if (sentRegisterStop) {
+                               pim_upstream_keep_alive_timer_start(
+                                       upstream,
+                                       pim_ifp->pim->rp_keep_alive_time);
+                       } else {
+                               pim_upstream_keep_alive_timer_start(
+                                       upstream,
+                                       pim_ifp->pim->keep_alive_time);
+                       }
+               }
+
+               if (!(upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE)
+                   && !(*bits & PIM_REGISTER_NR_BIT)) {
+                       // decapsulate and forward the iner packet to
+                       // inherited_olist(S,G,rpt)
+                       // This is taken care of by the kernel for us
+               }
+               pim_upstream_msdp_reg_timer_start(upstream);
+       } else {
+               if (PIM_DEBUG_PIM_REG) {
+                       if (!i_am_rp)
+                               zlog_debug(
+                                       "Received Register packet for %s, Rejecting packet because I am not the RP configured for group",
+                                       pim_str_sg_dump(&sg));
+                       else
+                               zlog_debug(
+                                       "Received Register packet for %s, Rejecting packet because the dst ip address is not the actual RP",
+                                       pim_str_sg_dump(&sg));
+               }
+               pim_register_stop_send(ifp, &sg, dest_addr, src_addr);
+       }
+
+       return 0;
 }