bfd: remove source IP check from session add
[vpp.git] / src / vnet / bfd / bfd_udp.c
index d8fd4a1..e835eac 100644 (file)
@@ -35,6 +35,7 @@
 #include <vnet/dpo/receive_dpo.h>
 #include <vnet/fib/fib_entry.h>
 #include <vnet/fib/fib_table.h>
+#include <vlib/stats/stats.h>
 #include <vnet/bfd/bfd_debug.h>
 #include <vnet/bfd/bfd_udp.h>
 #include <vnet/bfd/bfd_main.h>
@@ -68,8 +69,10 @@ typedef struct
   vlib_log_class_t log_class;
   /* number of active udp4 sessions */
   u32 udp4_sessions_count;
+  u32 udp4_sessions_count_stat_seg_entry;
   /* number of active udp6 sessions */
   u32 udp6_sessions_count;
+  u32 udp6_sessions_count_stat_seg_entry;
 } bfd_udp_main_t;
 
 static vlib_node_registration_t bfd_udp4_input_node;
@@ -79,6 +82,14 @@ static vlib_node_registration_t bfd_udp_echo6_input_node;
 
 bfd_udp_main_t bfd_udp_main;
 
+void
+bfd_udp_update_stat_segment_entry (u32 entry, u64 value)
+{
+  vlib_stats_segment_lock ();
+  vlib_stats_set_gauge (entry, value);
+  vlib_stats_segment_unlock ();
+}
+
 vnet_api_error_t
 bfd_udp_set_echo_source (u32 sw_if_index)
 {
@@ -94,7 +105,7 @@ bfd_udp_set_echo_source (u32 sw_if_index)
 }
 
 vnet_api_error_t
-bfd_udp_del_echo_source (u32 sw_if_index)
+bfd_udp_del_echo_source ()
 {
   bfd_udp_main.echo_source_sw_if_index = ~0;
   bfd_udp_main.echo_source_is_set = 0;
@@ -372,13 +383,18 @@ bfd_add_udp6_transport (vlib_main_t * vm, u32 bi, const bfd_session_t * bs,
 }
 
 static void
-bfd_create_frame_to_next_node (vlib_main_t * vm, u32 bi, u32 next_node)
+bfd_create_frame_to_next_node (vlib_main_t *vm, bfd_main_t *bm,
+                              const bfd_session_t *bs, u32 bi, u32 next_node,
+                              vlib_combined_counter_main_t *tx_counter)
 {
   vlib_frame_t *f = vlib_get_frame_to_node (vm, next_node);
   u32 *to_next = vlib_frame_vector_args (f);
   to_next[0] = bi;
   f->n_vectors = 1;
   vlib_put_frame_to_node (vm, next_node, f);
+  vlib_buffer_t *b = vlib_get_buffer (vm, bi);
+  vlib_increment_combined_counter (tx_counter, vm->thread_index, bs->bs_idx, 1,
+                                  vlib_buffer_length_in_chain (vm, b));
 }
 
 int
@@ -435,25 +451,33 @@ bfd_udp_calc_next_node (const struct bfd_session_s *bs, u32 * next_node)
 }
 
 int
-bfd_transport_udp4 (vlib_main_t * vm, u32 bi, const struct bfd_session_s *bs)
+bfd_transport_udp4 (vlib_main_t *vm, u32 bi, const struct bfd_session_s *bs,
+                   int is_echo)
 {
   u32 next_node;
   int rv = bfd_udp_calc_next_node (bs, &next_node);
+  bfd_main_t *bm = bfd_udp_main.bfd_main;
   if (rv)
     {
-      bfd_create_frame_to_next_node (vm, bi, next_node);
+      bfd_create_frame_to_next_node (vm, bm, bs, bi, next_node,
+                                    is_echo ? &bm->tx_echo_counter :
+                                              &bm->tx_counter);
     }
   return rv;
 }
 
 int
-bfd_transport_udp6 (vlib_main_t * vm, u32 bi, const struct bfd_session_s *bs)
+bfd_transport_udp6 (vlib_main_t *vm, u32 bi, const struct bfd_session_s *bs,
+                   int is_echo)
 {
   u32 next_node;
   int rv = bfd_udp_calc_next_node (bs, &next_node);
+  bfd_main_t *bm = bfd_udp_main.bfd_main;
   if (rv)
     {
-      bfd_create_frame_to_next_node (vm, bi, next_node);
+      bfd_create_frame_to_next_node (
+       vm, bfd_udp_main.bfd_main, bs, bi, next_node,
+       is_echo ? &bm->tx_echo_counter : &bm->tx_counter);
     }
   return 1;
 }
@@ -503,6 +527,7 @@ bfd_udp_add_session_internal (vlib_main_t * vm, bfd_udp_main_t * bum,
     }
   bfd_udp_session_t *bus = &bs->udp;
   clib_memset (bus, 0, sizeof (*bus));
+  bus->adj_index = ADJ_INDEX_INVALID;
   bfd_udp_key_t *key = &bus->key;
   bfd_udp_key_init (key, sw_if_index, local_addr, peer_addr);
   const bfd_session_t *tmp = bfd_lookup_session (bum, key);
@@ -521,15 +546,21 @@ bfd_udp_add_session_internal (vlib_main_t * vm, bfd_udp_main_t * bum,
           &key->peer_addr, IP46_TYPE_ANY);
   vlib_log_info (bum->log_class, "create BFD session: %U",
                 format_bfd_session, bs);
+  const ip46_address_t *peer =
+    (vnet_sw_interface_is_p2p (vnet_get_main (), key->sw_if_index) ?
+       &zero_addr :
+       &key->peer_addr);
   if (BFD_TRANSPORT_UDP4 == t)
     {
       bus->adj_index = adj_nbr_add_or_lock (FIB_PROTOCOL_IP4, VNET_LINK_IP4,
-                                           &key->peer_addr,
-                                           key->sw_if_index);
+                                           peer, key->sw_if_index);
       BFD_DBG ("adj_nbr_add_or_lock(FIB_PROTOCOL_IP4, VNET_LINK_IP4, %U, %d) "
-              "returns %d", format_ip46_address, &key->peer_addr,
-              IP46_TYPE_ANY, key->sw_if_index, bus->adj_index);
+              "returns %d",
+              format_ip46_address, peer, IP46_TYPE_ANY, key->sw_if_index,
+              bus->adj_index);
       ++bum->udp4_sessions_count;
+      bfd_udp_update_stat_segment_entry (
+       bum->udp4_sessions_count_stat_seg_entry, bum->udp4_sessions_count);
       if (1 == bum->udp4_sessions_count)
        {
          udp_register_dst_port (vm, UDP_DST_PORT_bfd4,
@@ -541,12 +572,14 @@ bfd_udp_add_session_internal (vlib_main_t * vm, bfd_udp_main_t * bum,
   else
     {
       bus->adj_index = adj_nbr_add_or_lock (FIB_PROTOCOL_IP6, VNET_LINK_IP6,
-                                           &key->peer_addr,
-                                           key->sw_if_index);
+                                           peer, key->sw_if_index);
       BFD_DBG ("adj_nbr_add_or_lock(FIB_PROTOCOL_IP6, VNET_LINK_IP6, %U, %d) "
-              "returns %d", format_ip46_address, &key->peer_addr,
-              IP46_TYPE_ANY, key->sw_if_index, bus->adj_index);
+              "returns %d",
+              format_ip46_address, peer, IP46_TYPE_ANY, key->sw_if_index,
+              bus->adj_index);
       ++bum->udp6_sessions_count;
+      bfd_udp_update_stat_segment_entry (
+       bum->udp6_sessions_count_stat_seg_entry, bum->udp6_sessions_count);
       if (1 == bum->udp6_sessions_count)
        {
          udp_register_dst_port (vm, UDP_DST_PORT_bfd6,
@@ -568,8 +601,6 @@ bfd_udp_validate_api_input (u32 sw_if_index,
   bfd_udp_main_t *bum = &bfd_udp_main;
   vnet_sw_interface_t *sw_if =
     vnet_get_sw_interface_or_null (bfd_udp_main.vnet_main, sw_if_index);
-  u8 local_ip_valid = 0;
-  ip_interface_address_t *ia = NULL;
   if (!sw_if)
     {
       vlib_log_err (bum->log_class,
@@ -585,21 +616,6 @@ bfd_udp_validate_api_input (u32 sw_if_index,
                        "IP family mismatch (local is ipv4, peer is ipv6)");
          return VNET_API_ERROR_INVALID_ARGUMENT;
        }
-      ip4_main_t *im = &ip4_main;
-
-      /* *INDENT-OFF* */
-      foreach_ip_interface_address (
-          &im->lookup_main, ia, sw_if_index, 0 /* honor unnumbered */, ({
-            ip4_address_t *x =
-                ip_interface_address_get_address (&im->lookup_main, ia);
-            if (x->as_u32 == local_addr->ip4.as_u32)
-              {
-                /* valid address for this interface */
-                local_ip_valid = 1;
-                break;
-              }
-          }));
-      /* *INDENT-ON* */
     }
   else
     {
@@ -609,44 +625,6 @@ bfd_udp_validate_api_input (u32 sw_if_index,
                        "IP family mismatch (local is ipv6, peer is ipv4)");
          return VNET_API_ERROR_INVALID_ARGUMENT;
        }
-
-      if (ip6_address_is_link_local_unicast (&local_addr->ip6))
-       {
-         const ip6_address_t *ll_addr;
-         ll_addr = ip6_get_link_local_address (sw_if_index);
-         if (ll_addr && ip6_address_is_equal (ll_addr, &local_addr->ip6))
-           {
-             /* valid address for this interface */
-             local_ip_valid = 1;
-           }
-       }
-      else
-       {
-         ip6_main_t *im = &ip6_main;
-         /* *INDENT-OFF* */
-         foreach_ip_interface_address (
-             &im->lookup_main, ia, sw_if_index, 0 /* honor unnumbered */, ({
-               ip6_address_t *x =
-                   ip_interface_address_get_address (&im->lookup_main, ia);
-               if (local_addr->ip6.as_u64[0] == x->as_u64[0] &&
-                   local_addr->ip6.as_u64[1] == x->as_u64[1])
-                 {
-                   /* valid address for this interface */
-                   local_ip_valid = 1;
-                   break;
-                 }
-             }));
-         /* *INDENT-ON* */
-       }
-    }
-
-  if (!local_ip_valid)
-    {
-      vlib_log_err (bum->log_class,
-                   "local address %U not found on interface with index %u",
-                   format_ip46_address, local_addr, IP46_TYPE_ANY,
-                   sw_if_index);
-      return VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
     }
 
   return 0;
@@ -713,12 +691,15 @@ bfd_udp_del_session_internal (vlib_main_t * vm, bfd_session_t * bs)
 {
   bfd_udp_main_t *bum = &bfd_udp_main;
   BFD_DBG ("free bfd-udp session, bs_idx=%d", bs->bs_idx);
+  bfd_session_stop (bum->bfd_main, bs);
   mhash_unset (&bum->bfd_session_idx_by_bfd_key, &bs->udp.key, NULL);
   adj_unlock (bs->udp.adj_index);
   switch (bs->transport)
     {
     case BFD_TRANSPORT_UDP4:
       --bum->udp4_sessions_count;
+      bfd_udp_update_stat_segment_entry (
+       bum->udp4_sessions_count_stat_seg_entry, bum->udp4_sessions_count);
       if (!bum->udp4_sessions_count)
        {
          udp_unregister_dst_port (vm, UDP_DST_PORT_bfd4, 1);
@@ -727,6 +708,8 @@ bfd_udp_del_session_internal (vlib_main_t * vm, bfd_session_t * bs)
       break;
     case BFD_TRANSPORT_UDP6:
       --bum->udp6_sessions_count;
+      bfd_udp_update_stat_segment_entry (
+       bum->udp6_sessions_count_stat_seg_entry, bum->udp6_sessions_count);
       if (!bum->udp6_sessions_count)
        {
          udp_unregister_dst_port (vm, UDP_DST_PORT_bfd6, 0);
@@ -1342,6 +1325,9 @@ bfd_udp_input (vlib_main_t * vm, vlib_node_runtime_t * rt,
       next0 = BFD_UDP_INPUT_NEXT_NORMAL;
       if (BFD_UDP_ERROR_NONE == error0)
        {
+         vlib_increment_combined_counter (
+           &bm->rx_counter, vm->thread_index, bs->bs_idx, 1,
+           vlib_buffer_length_in_chain (vm, b0));
          /*
           *  if everything went fine, check for poll bit, if present, re-use
           *  the buffer and based on (now updated) session parameters, send
@@ -1488,8 +1474,9 @@ bfd_udp_echo_input (vlib_main_t * vm, vlib_node_runtime_t * rt,
          clib_memcpy_fast (t0->data, vlib_buffer_get_current (b0), len);
        }
 
+      bfd_session_t *bs = NULL;
       bfd_lock (bm);
-      if (bfd_consume_echo_pkt (vm, bfd_udp_main.bfd_main, b0))
+      if ((bs = bfd_consume_echo_pkt (vm, bfd_udp_main.bfd_main, b0)))
        {
          b0->error = rt->errors[BFD_UDP_ERROR_NONE];
          next0 = BFD_UDP_ECHO_INPUT_NEXT_NORMAL;
@@ -1512,6 +1499,14 @@ bfd_udp_echo_input (vlib_main_t * vm, vlib_node_runtime_t * rt,
        }
 
       bfd_unlock (bm);
+
+      if (bs)
+       {
+         vlib_increment_combined_counter (
+           &bm->rx_echo_counter, vm->thread_index, bs->bs_idx, 1,
+           vlib_buffer_length_in_chain (vm, b0));
+       }
+
       vlib_set_next_frame_buffer (vm, rt, next0, bi0);
 
       from += 1;
@@ -1640,6 +1635,31 @@ bfd_udp_sw_if_add_del (CLIB_UNUSED (vnet_main_t *vnm), u32 sw_if_index,
 
 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (bfd_udp_sw_if_add_del);
 
+clib_error_t *
+bfd_udp_stats_init (bfd_udp_main_t *bum)
+{
+  const char *name4 = "/bfd/udp4/sessions";
+  bum->udp4_sessions_count_stat_seg_entry = vlib_stats_add_gauge ("%s", name4);
+
+  vlib_stats_set_gauge (bum->udp4_sessions_count_stat_seg_entry, 0);
+  if (~0 == bum->udp4_sessions_count_stat_seg_entry)
+    {
+      return clib_error_return (
+       0, "Could not create stat segment entry for %s", name4);
+    }
+  const char *name6 = "/bfd/udp6/sessions";
+  bum->udp6_sessions_count_stat_seg_entry = vlib_stats_add_gauge ("%s", name6);
+
+  vlib_stats_set_gauge (bum->udp6_sessions_count_stat_seg_entry, 0);
+  if (~0 == bum->udp6_sessions_count_stat_seg_entry)
+    {
+      return clib_error_return (
+       0, "Could not create stat segment entry for %s", name6);
+    }
+
+  return 0;
+}
+
 /*
  * setup function
  */
@@ -1671,6 +1691,8 @@ bfd_udp_init (vlib_main_t * vm)
   ASSERT (node);
   bfd_udp_main.ip6_midchain_idx = node->index;
 
+  bfd_udp_stats_init (&bfd_udp_main);
+
   bfd_udp_main.log_class = vlib_log_register_class ("bfd", "udp");
   vlib_log_debug (bfd_udp_main.log_class, "initialized");
   return 0;