vrrp: fix vrrp_garp_or_na_send()'s memory leak
[vpp.git] / src / plugins / vrrp / node.c
index 7ba18c4..d5594ae 100644 (file)
@@ -86,22 +86,16 @@ typedef enum
   VRRP_INPUT_N_NEXT,
 } vrrp_next_t;
 
-typedef struct vrrp_input_process_args
-{
-  u32 vr_index;
-  vrrp_header_t *pkt;
-} vrrp_input_process_args_t;
-
 /* Given a VR and a pointer to the VRRP header of an incoming packet,
  * compare the local src address to the peers. Return < 0 if the local
  * address < the peer address, 0 if they're equal, > 0 if
  * the local address > the peer address
  */
 static int
-vrrp_vr_addr_cmp (vrrp_vr_t * vr, vrrp_header_t * pkt)
+vrrp_vr_addr_cmp (vrrp_vr_t *vr, ip46_address_t *peer_addr)
 {
   vrrp_vr_config_t *vrc = &vr->config;
-  void *peer_addr, *local_addr;
+  void *peer_addr_bytes, *local_addr;
   ip46_address_t addr;
   int addr_size;
 
@@ -109,7 +103,7 @@ vrrp_vr_addr_cmp (vrrp_vr_t * vr, vrrp_header_t * pkt)
 
   if (vrrp_vr_is_ipv6 (vr))
     {
-      peer_addr = &(((ip6_header_t *) pkt) - 1)->src_address;
+      peer_addr_bytes = &peer_addr->ip6;
       local_addr = &addr.ip6;
       addr_size = 16;
       ip6_address_copy (local_addr,
@@ -117,25 +111,26 @@ vrrp_vr_addr_cmp (vrrp_vr_t * vr, vrrp_header_t * pkt)
     }
   else
     {
-      peer_addr = &(((ip4_header_t *) pkt) - 1)->src_address;
+      peer_addr_bytes = &peer_addr->ip4;
       local_addr = &addr.ip4;
       addr_size = 4;
       fib_sas4_get (vrc->sw_if_index, NULL, local_addr);
     }
 
-  return memcmp (local_addr, peer_addr, addr_size);
+  return memcmp (local_addr, peer_addr_bytes, addr_size);
 }
 
 static void
-vrrp_input_process_master (vrrp_vr_t * vr, vrrp_header_t * pkt)
+vrrp_input_process_master (vrrp_vr_t *vr, vrrp_input_process_args_t *args)
 {
   /* received priority 0, another VR is shutting down. send an adv and
    * remain in the master state
    */
-  if (pkt->priority == 0)
+  if (args->priority == 0)
     {
       clib_warning ("Received shutdown message from a peer on VR %U",
                    format_vrrp_vr_key, vr);
+      vrrp_incr_stat_counter (VRRP_STAT_COUNTER_PRIO0_RCVD, vr->stat_index);
       vrrp_adv_send (vr, 0);
       vrrp_vr_timer_set (vr, VRRP_VR_TIMER_ADV);
       return;
@@ -146,11 +141,11 @@ vrrp_input_process_master (vrrp_vr_t * vr, vrrp_header_t * pkt)
    * - received priority == adjusted priority and peer addr > local addr
    * allow the local VR to be preempted by the peer
    */
-  if ((pkt->priority > vrrp_vr_priority (vr)) ||
-      ((pkt->priority == vrrp_vr_priority (vr)) &&
-       (vrrp_vr_addr_cmp (vr, pkt) < 0)))
+  if ((args->priority > vrrp_vr_priority (vr)) ||
+      ((args->priority == vrrp_vr_priority (vr)) &&
+       (vrrp_vr_addr_cmp (vr, &args->src_addr) < 0)))
     {
-      vrrp_vr_transition (vr, VRRP_VR_STATE_BACKUP, pkt);
+      vrrp_vr_transition (vr, VRRP_VR_STATE_BACKUP, args);
 
       return;
     }
@@ -163,16 +158,17 @@ vrrp_input_process_master (vrrp_vr_t * vr, vrrp_header_t * pkt)
 
 /* RFC 5798 section 6.4.2 */
 static void
-vrrp_input_process_backup (vrrp_vr_t * vr, vrrp_header_t * pkt)
+vrrp_input_process_backup (vrrp_vr_t *vr, vrrp_input_process_args_t *args)
 {
   vrrp_vr_config_t *vrc = &vr->config;
   vrrp_vr_runtime_t *vrt = &vr->runtime;
 
   /* master shutting down, ready for election */
-  if (pkt->priority == 0)
+  if (args->priority == 0)
     {
       clib_warning ("Master for VR %U is shutting down", format_vrrp_vr_key,
                    vr);
+      vrrp_incr_stat_counter (VRRP_STAT_COUNTER_PRIO0_RCVD, vr->stat_index);
       vrt->master_down_int = vrt->skew;
       vrrp_vr_timer_set (vr, VRRP_VR_TIMER_MASTER_DOWN);
       return;
@@ -180,10 +176,9 @@ vrrp_input_process_backup (vrrp_vr_t * vr, vrrp_header_t * pkt)
 
   /* no preempt set or adv from a higher priority router, update timers */
   if (!(vrc->flags & VRRP_VR_PREEMPT) ||
-      (pkt->priority >= vrrp_vr_priority (vr)))
+      (args->priority >= vrrp_vr_priority (vr)))
     {
-      vrt->master_adv_int = clib_net_to_host_u16 (pkt->rsvd_and_max_adv_int);
-      vrt->master_adv_int &= ((u16) 0x0fff);   /* ignore rsvd bits */
+      vrt->master_adv_int = args->max_adv_int;
 
       vrrp_vr_skew_compute (vr);
       vrrp_vr_master_down_compute (vr);
@@ -208,19 +203,21 @@ vrrp_input_process (vrrp_input_process_args_t * args)
       return;
     }
 
+  vrrp_incr_stat_counter (VRRP_STAT_COUNTER_ADV_RCVD, vr->stat_index);
+
   switch (vr->runtime.state)
     {
     case VRRP_VR_STATE_INIT:
       return;
     case VRRP_VR_STATE_BACKUP:
       /* this is usually the only state an advertisement should be received */
-      vrrp_input_process_backup (vr, args->pkt);
+      vrrp_input_process_backup (vr, args);
       break;
     case VRRP_VR_STATE_MASTER:
       /* might be getting preempted. or have a misbehaving peer */
       clib_warning ("Received advertisement for master VR %U",
                    format_vrrp_vr_key, vr);
-      vrrp_input_process_master (vr, args->pkt);
+      vrrp_input_process_master (vr, args);
       break;
     default:
       clib_warning ("Received advertisement for VR %U in unknown state %d",
@@ -489,7 +486,6 @@ VLIB_NODE_FN (vrrp4_arp_input_node) (vlib_main_t * vm,
   return vrrp_arp_nd_input_inline (vm, node, frame, 0 /* is_ipv6 */ );
 }
 
-/* *INDENT-OFF* */
 VLIB_REGISTER_NODE (vrrp4_arp_input_node) =
 {
   .name = "vrrp4-arp-input",
@@ -522,7 +518,6 @@ VLIB_NODE_FN (vrrp6_nd_input_node) (vlib_main_t * vm,
   return vrrp_arp_nd_input_inline (vm, node, frame, 1 /* is_ipv6 */);
 }
 
-/* *INDENT-OFF* */
 VLIB_REGISTER_NODE (vrrp6_nd_input_node) =
 {
   .name = "vrrp6-nd-input",
@@ -586,6 +581,7 @@ vrrp_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
          addr_len = 16;
          payload_len0 = clib_net_to_host_u16 (ip6->payload_length);
          vlib_buffer_advance (b0, sizeof (*ip6));
+         clib_memcpy_fast (&args0.src_addr.ip6, &ip6->src_address, addr_len);
        }
       else
        {
@@ -596,6 +592,7 @@ vrrp_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
          addr_len = 4;
          payload_len0 = clib_net_to_host_u16 (ip4->length) - sizeof(*ip4);
          vlib_buffer_advance (b0, sizeof (*ip4));
+         clib_memcpy_fast (&args0.src_addr.ip4, &ip4->src_address, addr_len);
        }
 
       next0 = VRRP_INPUT_NEXT_DROP;
@@ -612,6 +609,7 @@ vrrp_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
       if (*ttl0 != 255)
        {
          error0 = VRRP_ERROR_BAD_TTL;
+         vrrp_incr_err_counter (VRRP_ERR_COUNTER_TTL);
          goto trace;
        }
 
@@ -619,6 +617,7 @@ vrrp_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
       if ((vrrp0->vrrp_version_and_type >> 4) != 3)
        {
          error0 = VRRP_ERROR_NOT_VERSION_3;
+         vrrp_incr_err_counter (VRRP_ERR_COUNTER_VERSION);
          goto trace;
        }
 
@@ -627,6 +626,7 @@ vrrp_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
           ((u32) vrrp0->n_addrs) * addr_len)
        {
          error0 = VRRP_ERROR_INCOMPLETE_PKT;
+         vrrp_incr_err_counter (VRRP_ERR_COUNTER_PKT_LEN);
          goto trace;
        }
 
@@ -634,6 +634,7 @@ vrrp_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
       if (rx_csum0 != vrrp_adv_csum (ip0, vrrp0, is_ipv6, payload_len0))
        {
          error0 = VRRP_ERROR_BAD_CHECKSUM;
+         vrrp_incr_err_counter (VRRP_ERR_COUNTER_CHKSUM);
          goto trace;
        }
 
@@ -643,6 +644,7 @@ vrrp_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
                              vrrp0->vr_id, is_ipv6)))
        {
          error0 = VRRP_ERROR_UNKNOWN_VR;
+         vrrp_incr_err_counter (VRRP_ERR_COUNTER_VRID);
          goto trace;
        }
 
@@ -651,12 +653,14 @@ vrrp_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
       if (vrrp0->n_addrs != vec_len (vr0->config.vr_addrs))
        {
          error0 = VRRP_ERROR_ADDR_MISMATCH;
+         vrrp_incr_err_counter (VRRP_ERR_COUNTER_ADDR_LIST);
          goto trace;
        }
 
       /* signal main thread to process contents of packet */
       args0.vr_index = vr0 - vmp->vrs;
-      args0.pkt = vrrp0;
+      args0.priority = vrrp0->priority;
+      args0.max_adv_int = vrrp_adv_int_from_packet (vrrp0);
 
       vl_api_rpc_call_main_thread (vrrp_input_process, (u8 *) &args0,
                                   sizeof (args0));
@@ -693,7 +697,6 @@ VLIB_NODE_FN (vrrp4_input_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
   return vrrp_input_inline (vm, node, frame, 0);
 }
 
-/* *INDENT-OFF* */
 VLIB_REGISTER_NODE (vrrp4_input_node) =
 {
   .name = "vrrp4-input",
@@ -1098,7 +1101,6 @@ vrrp_input_init (vlib_main_t *vm)
 
 VLIB_INIT_FUNCTION (vrrp_input_init);
 
-/* *INDENT-ON* */
 
 /*
  * fd.io coding-style-patch-verification: ON