aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/plugins/mactime/FEATURE.yaml11
-rw-r--r--src/plugins/mactime/mactime.api20
-rw-r--r--src/plugins/mactime/mactime.c75
-rw-r--r--src/plugins/mactime/mactime.h2
-rw-r--r--src/plugins/mactime/mactime_test.c10
-rw-r--r--src/plugins/mactime/node.c68
6 files changed, 161 insertions, 25 deletions
diff --git a/src/plugins/mactime/FEATURE.yaml b/src/plugins/mactime/FEATURE.yaml
new file mode 100644
index 00000000000..fbc0a6cccdd
--- /dev/null
+++ b/src/plugins/mactime/FEATURE.yaml
@@ -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]
diff --git a/src/plugins/mactime/mactime.api b/src/plugins/mactime/mactime.api
index 7cad7828fe4..d9049d8dbd1 100644
--- a/src/plugins/mactime/mactime.api
+++ b/src/plugins/mactime/mactime.api
@@ -14,15 +14,15 @@
*/
/** \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];
};
/*
diff --git a/src/plugins/mactime/mactime.c b/src/plugins/mactime/mactime.c
index 1b053faa2e8..d84151ed29e 100644
--- a/src/plugins/mactime/mactime.c
+++ b/src/plugins/mactime/mactime.c
@@ -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++)
{
diff --git a/src/plugins/mactime/mactime.h b/src/plugins/mactime/mactime.h
index 8d4165212a4..928d7e940b6 100644
--- a/src/plugins/mactime/mactime.h
+++ b/src/plugins/mactime/mactime.h
@@ -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
{
diff --git a/src/plugins/mactime/mactime_test.c b/src/plugins/mactime/mactime_test.c
index 351493daf24..36ee063135d 100644
--- a/src/plugins/mactime/mactime_test.c
+++ b/src/plugins/mactime/mactime_test.c
@@ -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));
diff --git a/src/plugins/mactime/node.c b/src/plugins/mactime/node.c
index 4d45dd54ef3..e4d12f80db4 100644
--- a/src/plugins/mactime/node.c
+++ b/src/plugins/mactime/node.c
@@ -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
{
@@ -266,8 +312,6 @@ mactime_node_inline (vlib_main_t * vm,
}
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;
}