diff options
-rw-r--r-- | src/plugins/mactime/FEATURE.yaml | 11 | ||||
-rw-r--r-- | src/plugins/mactime/mactime.api | 20 | ||||
-rw-r--r-- | src/plugins/mactime/mactime.c | 75 | ||||
-rw-r--r-- | src/plugins/mactime/mactime.h | 2 | ||||
-rw-r--r-- | src/plugins/mactime/mactime_test.c | 10 | ||||
-rw-r--r-- | src/plugins/mactime/node.c | 68 |
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; } |