mactime: upstream new features 28/19928/2
authorDave Barach <dave@barachs.net>
Mon, 3 Jun 2019 14:23:30 +0000 (10:23 -0400)
committerDamjan Marion <dmarion@me.com>
Tue, 4 Jun 2019 07:47:24 +0000 (07:47 +0000)
Add per mac address data quotas (simple version)

Add mini-ACLs to turf "call home" traffic from a certain species of
security DVR.
Add FEATURE.yaml

Update the API version number

Type: feature
Feature-name: mactime

Change-Id: Ida6945f7791ab43909afa68dcf2f652b20c53afd
Signed-off-by: Dave Barach <dave@barachs.net>
src/plugins/mactime/FEATURE.yaml [new file with mode: 0644]
src/plugins/mactime/mactime.api
src/plugins/mactime/mactime.c
src/plugins/mactime/mactime.h
src/plugins/mactime/mactime_test.c
src/plugins/mactime/node.c

diff --git a/src/plugins/mactime/FEATURE.yaml b/src/plugins/mactime/FEATURE.yaml
new file mode 100644 (file)
index 0000000..fbc0a6c
--- /dev/null
@@ -0,0 +1,11 @@
+name: Time-range-based MAC-address filter (mactime)
+maintainer: Dave Barach <dave@barachs.net>
+features:
+  - Static / time-range / data quota based MAC address filter
+description: "Device-input/output arc driver level MAC filter.
+              Checks to see if traffic is allowed to/from the given
+              MAC address, and takes the appropriate action.
+              Intended for the home gateway use-case, where WAN traffic
+              is billed per bit."
+state: production
+properties: [API, CLI, MULTITHREAD]
index 7cad782..d9049d8 100644 (file)
  */
 
 /** \file
-    This file defines vpp mactime control-plane API messages 
+    This file defines vpp mactime control-plane API messages
 */
-option version = "1.0.0";
+option version = "1.1.0";
 
-/** \brief api to enable or disable the time-based src mac filter on 
+/** \brief api to enable or disable the time-based src mac filter on
     an interface
 */
 
-autoreply define mactime_enable_disable 
+autoreply define mactime_enable_disable
 {
   u32 client_index;             /**< client index, from api_main */
   u32 context;                  /**< application context */
@@ -31,14 +31,14 @@ autoreply define mactime_enable_disable
 };
 
 /** \brief a time range structure
- * times are in double-precision fp seconds since 1/1/1970, 
+ * times are in double-precision fp seconds since 1/1/1970,
  * which was a Thursday.
  */
 typeonly define time_range
 {
   f64 start;                    /**< start of the time range  */
   f64 end;                      /**< end of the time range */
-}; 
+};
 
 /** \brief configure per src-mac time ranges
  *
@@ -54,9 +54,9 @@ typeonly define time_range
  *   set count = number of ranges
  *   set each range start/end in seconds since Sunday began
  *   As in: start/end >= 0.0 && start/end < 7.0 *86400.0
- * 
+ *
  *  to create a (time-range-based) dynamic drop entry:
- *   Same procedure to create a dynamic allow entry, 
+ *   Same procedure to create a dynamic allow entry,
  *   set drop=1 instead of allow=1
  *
  *  to delete a per src-mac entry (of any kind)
@@ -74,11 +74,13 @@ autoreply define mactime_add_del_range
   u8 is_add;                    /**< add=1, del=0  */
   u8 drop;                      /**< drop flag */
   u8 allow;                     /**< allow flag */
+  u8 no_udp_10001;              /**< drop udp to port 10001 */
+  u64 data_quota;              /**< max bytes this device */
   u8 mac_address[6];            /**< src mac address */
   u8 device_name[64];           /**< device name */
   u32 count;                    /**< number of time ranges to follow */
   /** time ranges, in seconds since Sunday began */
-  vl_api_time_range_t ranges[count]; 
+  vl_api_time_range_t ranges[count];
 };
 
 /*
index 1b053fa..d84151e 100644 (file)
@@ -220,10 +220,13 @@ static void vl_api_mactime_add_del_range_t_handler
   clib_bihash_kv_8_8_t kv;
   int found = 1;
   clib_bihash_8_8_t *lut = &mm->lookup_table;
+  u64 data_quota;
   int i, rv = 0;
 
   feature_init (mm);
 
+  data_quota = clib_net_to_host_u64 (mp->data_quota);
+
   clib_memset (&kv, 0, sizeof (kv));
   memcpy (&kv.key, mp->mac_address, sizeof (mp->mac_address));
 
@@ -272,14 +275,19 @@ static void vl_api_mactime_add_del_range_t_handler
              if (mp->allow)
                dp->flags = MACTIME_DEVICE_FLAG_STATIC_ALLOW;
            }
+         if (mp->no_udp_10001)
+           dp->flags |= MACTIME_DEVICE_FLAG_DROP_UDP_10001;
+
+         dp->data_quota = data_quota;
 
          /* Add the hash table entry */
          kv.value = dp - mm->devices;
          clib_bihash_add_del_8_8 (lut, &kv, 1 /* is_add */ );
        }
-      else                     /* add more ranges */
+      else                     /* add more ranges, flags, etc. */
        {
          dp = pool_elt_at_index (mm->devices, kv.value);
+
          for (i = 0; i < clib_net_to_host_u32 (mp->count); i++)
            {
              clib_timebase_range_t _r, *r = &_r;
@@ -287,6 +295,27 @@ static void vl_api_mactime_add_del_range_t_handler
              r->end = mp->ranges[i].end;
              vec_add1 (dp->ranges, r[0]);
            }
+
+         if (vec_len (dp->ranges))
+           {
+             /* Set allow/drop based on msg flags */
+             if (mp->drop)
+               dp->flags = MACTIME_DEVICE_FLAG_DYNAMIC_DROP;
+             if (mp->allow)
+               dp->flags = MACTIME_DEVICE_FLAG_DYNAMIC_ALLOW;
+           }
+         else
+           {
+             /* no ranges, it's a static allow/drop */
+             if (mp->drop)
+               dp->flags = MACTIME_DEVICE_FLAG_STATIC_DROP;
+             if (mp->allow)
+               dp->flags = MACTIME_DEVICE_FLAG_STATIC_ALLOW;
+           }
+         if (mp->no_udp_10001)
+           dp->flags |= MACTIME_DEVICE_FLAG_DROP_UDP_10001;
+
+         dp->data_quota = data_quota;
        }
     }
   else                         /* delete case */
@@ -424,6 +453,40 @@ VLIB_PLUGIN_REGISTER () =
 };
 /* *INDENT-ON* */
 
+u8 *
+format_bytes_with_width (u8 * s, va_list * va)
+{
+  uword nbytes = va_arg (*va, u64);
+  int width = va_arg (*va, int);
+  f64 nbytes_f64;
+  u8 *fmt;
+  char *suffix = "";
+
+  fmt = format (0, "%%%d.3f%%s%c", width, 0);
+
+  if (nbytes > (1024ULL * 1024ULL * 1024ULL))
+    {
+      nbytes_f64 = ((f64) nbytes) / (1024.0 * 1024.0 * 1024.0);
+      suffix = "G";
+    }
+  else if (nbytes > (1024ULL * 1024ULL))
+    {
+      nbytes_f64 = ((f64) nbytes) / (1024.0 * 1024.0);
+      suffix = "M";
+    }
+  else if (nbytes > 1024ULL)
+    {
+      nbytes_f64 = ((f64) nbytes) / (1024.0);
+      suffix = "K";
+    }
+  else
+    nbytes_f64 = (f64) nbytes;
+
+  s = format (s, (char *) fmt, nbytes_f64, suffix);
+  vec_free (fmt);
+  return s;
+}
+
 static clib_error_t *
 show_mactime_command_fn (vlib_main_t * vm,
                         unformat_input_t * input, vlib_cli_command_t * cmd)
@@ -471,7 +534,7 @@ show_mactime_command_fn (vlib_main_t * vm,
   }));
   /* *INDENT-ON* */
 
-  vlib_cli_output (vm, "%-15s %18s %14s %10s %10s %10s",
+  vlib_cli_output (vm, "%-15s %18s %14s %10s %11s %10s",
                   "Device Name", "Addresses", "Status",
                   "AllowPkt", "AllowByte", "DropPkt");
 
@@ -543,9 +606,13 @@ show_mactime_command_fn (vlib_main_t * vm,
       vlib_get_combined_counter (&mm->allow_counters, dp - mm->devices,
                                 &allow);
       vlib_get_combined_counter (&mm->drop_counters, dp - mm->devices, &drop);
-      vlib_cli_output (vm, "%-15s %18s %14s %10lld %10lld %10lld",
+      vlib_cli_output (vm, "%-15s %18s %14s %10lld %U %10lld",
                       dp->device_name, macstring, status_string,
-                      allow.packets, allow.bytes, drop.packets);
+                      allow.packets, format_bytes_with_width, allow.bytes,
+                      10, drop.packets);
+      if (dp->data_quota > 0)
+       vlib_cli_output (vm, "%-54s %s%U", " ", "Quota ",
+                        format_bytes_with_width, dp->data_quota, 10);
       /* This is really only good for small N... */
       for (j = 0; j < vec_len (mm->arp_cache_copy); j++)
        {
index 8d41652..928d7e9 100644 (file)
@@ -36,6 +36,7 @@ typedef struct
 {
   u8 *device_name;
   u8 mac_address[6];
+  u64 data_quota;
   u32 flags;
   clib_timebase_range_t *ranges;
 } mactime_device_t;
@@ -45,6 +46,7 @@ typedef struct
 #define MACTIME_DEVICE_FLAG_STATIC_ALLOW       (1<<1)
 #define MACTIME_DEVICE_FLAG_DYNAMIC_DROP       (1<<2)
 #define MACTIME_DEVICE_FLAG_DYNAMIC_ALLOW      (1<<3)
+#define MACTIME_DEVICE_FLAG_DROP_UDP_10001      (1<<4)
 
 typedef struct
 {
index 351493d..36ee063 100644 (file)
@@ -159,6 +159,8 @@ api_mactime_add_del_range (vat_main_t * vam)
   u8 is_add = 1;
   u8 allow = 0;
   u8 drop = 0;
+  u8 no_udp_10001 = 0;
+  u64 data_quota = 0;
   int ret;
   int ii;
 
@@ -180,10 +182,16 @@ api_mactime_add_del_range (vat_main_t * vam)
        allow = 1;
       else if (unformat (i, "drop-static"))
        drop = 1;
+      else if (unformat (i, "no-udp-10001"))
+       no_udp_10001 = 1;
       else if (unformat (i, "mac %U", my_unformat_mac_address, mac_address))
        mac_set = 1;
       else if (unformat (i, "del"))
        is_add = 0;
+      else if (unformat (i, "data-quota %lldM", &data_quota))
+       data_quota <<= 20;
+      else if (unformat (i, "data-quota %lldG", &data_quota))
+       data_quota <<= 30;
       else
        break;
     }
@@ -226,6 +234,8 @@ api_mactime_add_del_range (vat_main_t * vam)
   mp->is_add = is_add;
   mp->drop = drop;
   mp->allow = allow;
+  mp->no_udp_10001 = no_udp_10001;
+  mp->data_quota = clib_host_to_net_u64 (data_quota);
   memcpy (mp->mac_address, mac_address, sizeof (mp->mac_address));
   memcpy (mp->device_name, device_name, vec_len (device_name));
   mp->count = clib_host_to_net_u32 (vec_len (rp));
index 4d45dd5..e4d12f8 100644 (file)
@@ -19,6 +19,7 @@
 #include <vnet/pg/pg.h>
 #include <vppinfra/error.h>
 #include <mactime/mactime.h>
+#include <vnet/ip/ip4.h>
 
 typedef struct
 {
@@ -32,8 +33,11 @@ vlib_node_registration_t mactime_node;
 vlib_node_registration_t mactime_tx_node;
 
 #define foreach_mactime_error                   \
-_(DROP, "Dropped packets")                      \
-_(OK, "Permitted packets")
+_(OK, "Permitted packets")                     \
+_(STATIC_DROP, "Static drop packets")           \
+_(RANGE_DROP, "Range drop packets")             \
+_(QUOTA_DROP, "Data quota drop packets")       \
+_(DROP_10001, "Dropped UDP DST-port 10001")
 
 typedef enum
 {
@@ -82,7 +86,7 @@ mactime_node_inline (vlib_main_t * vm,
   mactime_device_t *dp;
   clib_bihash_kv_8_8_t kv;
   clib_bihash_8_8_t *lut = &mm->lookup_table;
-  u32 packets_ok = 0, packets_dropped = 0;
+  u32 packets_ok = 0;
   f64 now;
   u32 thread_index = vm->thread_index;
   vnet_main_t *vnm = vnet_get_main ();
@@ -164,6 +168,24 @@ mactime_node_inline (vlib_main_t * vm,
 
          dp = pool_elt_at_index (mm->devices, device_index0);
 
+         /* Known device, check for a traffic quota */
+         if (PREDICT_FALSE (dp->data_quota))
+           {
+             vlib_counter_t device_current_count;
+             vlib_get_combined_counter (&mm->allow_counters,
+                                        dp - mm->devices,
+                                        &device_current_count);
+             if (device_current_count.bytes >= dp->data_quota)
+               {
+                 next0 = MACTIME_NEXT_DROP;
+                 b0->error = node->errors[MACTIME_ERROR_QUOTA_DROP];
+                 vlib_increment_combined_counter
+                   (&mm->drop_counters, thread_index, dp - mm->devices, 1,
+                    len0);
+                 goto trace0;
+               }
+           }
+
          /* Static drop / allow? */
          if (PREDICT_FALSE
              (dp->flags &
@@ -173,17 +195,41 @@ mactime_node_inline (vlib_main_t * vm,
              if (dp->flags & MACTIME_DEVICE_FLAG_STATIC_DROP)
                {
                  next0 = MACTIME_NEXT_DROP;
+                 b0->error = node->errors[MACTIME_ERROR_STATIC_DROP];
                  vlib_increment_combined_counter
                    (&mm->drop_counters, thread_index, dp - mm->devices, 1,
                     len0);
-                 packets_dropped++;
                }
              else              /* note next0 set to allow */
                {
-                 vlib_increment_combined_counter
-                   (&mm->allow_counters, thread_index, dp - mm->devices, 1,
-                    len0);
-                 packets_ok++;
+                 /*
+                  * Special-case mini-ACL for a certain species of
+                  * home security DVR which likes to "call home."
+                  */
+                 if (PREDICT_FALSE
+                     (dp->flags & MACTIME_DEVICE_FLAG_DROP_UDP_10001))
+                   {
+                     ip4_header_t *ip = (void *) (((u8 *) en0) + 14);
+                     udp_header_t *udp = (udp_header_t *) (ip + 1);
+                     if (ip->protocol != IP_PROTOCOL_UDP)
+                       goto pass;
+                     if (clib_net_to_host_u16 (udp->dst_port) == 10001 ||
+                         clib_net_to_host_u16 (udp->dst_port) == 9603)
+                       {
+                         next0 = MACTIME_NEXT_DROP;
+                         b0->error = node->errors[MACTIME_ERROR_DROP_10001];
+                       }
+                     else
+                       goto pass;
+                   }
+                 else
+                   {
+                   pass:
+                     vlib_increment_combined_counter
+                       (&mm->allow_counters, thread_index, dp - mm->devices,
+                        1, len0);
+                     packets_ok++;
+                   }
                }
              goto trace0;
            }
@@ -205,8 +251,8 @@ mactime_node_inline (vlib_main_t * vm,
                      vlib_increment_combined_counter
                        (&mm->drop_counters, thread_index,
                         dp - mm->devices, 1, len0);
-                     packets_dropped++;
                      next0 = MACTIME_NEXT_DROP;
+                     b0->error = node->errors[MACTIME_ERROR_RANGE_DROP];
                    }
                  else          /* it's an allow range, allow it */
                    {
@@ -225,9 +271,9 @@ mactime_node_inline (vlib_main_t * vm,
          if (dp->flags & MACTIME_DEVICE_FLAG_DYNAMIC_ALLOW)
            {
              next0 = MACTIME_NEXT_DROP;
+             b0->error = node->errors[MACTIME_ERROR_STATIC_DROP];
              vlib_increment_combined_counter
                (&mm->drop_counters, thread_index, dp - mm->devices, 1, len0);
-             packets_dropped++;
            }
          else
            {
@@ -265,8 +311,6 @@ mactime_node_inline (vlib_main_t * vm,
       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     }
 
-  vlib_node_increment_counter (vm, node->node_index,
-                              MACTIME_ERROR_DROP, packets_dropped);
   vlib_node_increment_counter (vm, node->node_index,
                               MACTIME_ERROR_OK, packets_ok);
   return frame->n_vectors;