mactime: add a "top" command to watch device stats

Include a binary API change NOT suitable for cherry-picking into 19.08

Type: feature

Signed-off-by: Dave Barach <dave@barachs.net>
Change-Id: Id369514a3085f5e4bcee34819c55c4636df9b518
This commit is contained in:
Dave Barach
2019-10-07 12:04:31 -04:00
committed by Florin Coras
parent 0eb75d0e9c
commit 2c41a61d5f
8 changed files with 941 additions and 26 deletions

View File

@ -22,3 +22,21 @@ add_vpp_plugin(mactime
API_TEST_SOURCES API_TEST_SOURCES
mactime_test.c mactime_test.c
) )
option(VPP_BUILD_MACTIME_TOP "Build mactime plugin 'top' tool" OFF)
if(VPP_BUILD_MACTIME_TOP)
add_vpp_executable(mactime_top ENABLE_EXPORTS
SOURCES
mactime_top.c
DEPENDS api_headers
LINK_LIBRARIES
vlibmemoryclient
vppapiclient
svm
vppinfra
Threads::Threads
rt m dl crypto
)
endif()

View File

@ -13,12 +13,12 @@
* limitations under the License. * limitations under the License.
*/ */
/** \file /** @file
This file defines vpp mactime control-plane API messages This file defines vpp mactime control-plane API messages
*/ */
option version = "1.1.1"; option version = "1.2.1";
/** \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 an interface
*/ */
@ -31,7 +31,7 @@ autoreply define mactime_enable_disable
option vat_help = "<intfc> [disable]"; option vat_help = "<intfc> [disable]";
}; };
/** \brief a time range structure /** @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. * which was a Thursday.
*/ */
@ -41,7 +41,7 @@ typedef time_range
f64 end; /**< end of the time range */ f64 end; /**< end of the time range */
}; };
/** \brief configure per src-mac time ranges /** @brief configure per src-mac time ranges
* *
* Usage: * Usage:
* to create a static allow entry: * to create a static allow entry:
@ -56,6 +56,10 @@ typedef time_range
* set each range start/end in seconds since Sunday began * set each range start/end in seconds since Sunday began
* As in: start/end >= 0.0 && start/end < 7.0 *86400.0 * As in: start/end >= 0.0 && start/end < 7.0 *86400.0
* *
* to create a (time-range-based) dynamic allow entry with quota:
* Outside of stated time ranges, such entries revert to allow with no quota.
* previous setup, s/allow=1/allow_quota=1/
*
* to create a (time-range-based) dynamic drop entry: * 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 * set drop=1 instead of allow=1
@ -86,6 +90,58 @@ autoreply define mactime_add_del_range
option vat_help = "name <devname> mac <mac-addr> allow drop allow-range Mon - Fri 9:00 - 17:00"; option vat_help = "name <devname> mac <mac-addr> allow drop allow-range Mon - Fri 9:00 - 17:00";
}; };
/** @brief a time range, in fp seconds since Sunday midnight
*/
typedef mactime_time_range
{
f64 start;
f64 end;
};
/** @brief dump mactime table
*
* Request a mactime client pool dump
* Sequence:
* client send vl_api_mactime_dump to vpp
* vpp replies with zero or more vl_api_mactime_entry_t's
* vpp replies with a vl_api_mactime_dump_reply_t
* @param my_table_epoch dump table only if update needed, 0 => full dump
*/
define mactime_dump
{
u32 client_index; /**< client index, from api_main */
u32 context; /**< application context */
u32 my_table_epoch; /**< to suppress dump if no changes */
};
/** @brief mactime table entry details
*/
define mactime_details
{
u32 context;
u32 pool_index;
u8 mac_address[6];
u64 data_quota;
u64 data_used_in_range;
u32 flags;
u8 device_name[64];
u32 nranges;
vl_api_mactime_time_range_t ranges[nranges];
};
/** @brief dump mactime table reply
* Includes the vpp table epoch, needed to optimize API traffic
*/
define mactime_dump_reply
{
u32 context;
i32 retval;
u32 table_epoch;
};
/* /*
* Local Variables: * Local Variables:
* eval: (c-set-style "gnu") * eval: (c-set-style "gnu")

View File

@ -158,6 +158,77 @@ static void vl_api_mactime_enable_disable_t_handler
REPLY_MACRO (VL_API_MACTIME_ENABLE_DISABLE_REPLY); REPLY_MACRO (VL_API_MACTIME_ENABLE_DISABLE_REPLY);
} }
static void
vl_api_mactime_dump_t_handler (vl_api_mactime_dump_t * mp)
{
vl_api_mactime_details_t *ep;
vl_api_mactime_dump_reply_t *rmp;
mactime_device_t *dev;
mactime_main_t *mm = &mactime_main;
vl_api_registration_t *rp;
int rv = 0, i;
u32 his_table_epoch = clib_net_to_host_u32 (mp->my_table_epoch);
u32 message_size;
u32 name_len;
u32 nranges;
rp = vl_api_client_index_to_registration (mp->client_index);
if (rp == 0)
return;
if (his_table_epoch == mm->device_table_epoch)
{
rv = VNET_API_ERROR_NO_CHANGE;
goto send_reply;
}
/* *INDENT-OFF* */
pool_foreach (dev, mm->devices,
({
message_size = sizeof(*ep) + vec_len(dev->device_name) +
vec_len(dev->ranges) * sizeof(ep->ranges[0]);
ep = vl_msg_api_alloc (message_size);
memset (ep, 0, message_size);
ep->_vl_msg_id = clib_host_to_net_u16 (VL_API_MACTIME_DETAILS
+ mm->msg_id_base);
/* Index is the key for the stats segment combined counters */
ep->pool_index = clib_host_to_net_u32 (dev - mm->devices);
clib_memcpy_fast (ep->mac_address, dev->mac_address,
sizeof (ep->mac_address));
ep->data_quota = clib_host_to_net_u64 (dev->data_quota);
ep->data_used_in_range = clib_host_to_net_u64 (dev->data_used_in_range);
ep->flags = clib_host_to_net_u32 (dev->flags);
nranges = vec_len (dev->ranges);
ep->nranges = clib_host_to_net_u32 (nranges);
for (i = 0; i < vec_len (dev->ranges); i++)
{
ep->ranges[i].start = dev->ranges[i].start;
ep->ranges[i].end = dev->ranges[i].end;
}
name_len = vec_len (dev->device_name);
name_len = (name_len < ARRAY_LEN(ep->device_name)) ?
name_len : ARRAY_LEN(ep->device_name) - 1;
clib_memcpy_fast (ep->device_name, dev->device_name,
name_len);
ep->device_name [ARRAY_LEN(ep->device_name) -1] = 0;
vl_api_send_msg (rp, (u8 *)ep);
}));
/* *INDENT-OFF* */
send_reply:
/* *INDENT-OFF* */
REPLY_MACRO2 (VL_API_MACTIME_DUMP_REPLY,
({
rmp->table_epoch = clib_host_to_net_u32 (mm->device_table_epoch);
}));
/* *INDENT-ON* */
}
/** Create a lookup table entry for the indicated mac address /** Create a lookup table entry for the indicated mac address
*/ */
void void
@ -201,6 +272,14 @@ static void vl_api_mactime_add_del_range_t_handler
feature_init (mm); feature_init (mm);
/*
* Change the table epoch. Skip 0 so clients can code my_table_epoch = 0
* to receive a full dump.
*/
mm->device_table_epoch++;
if (PREDICT_FALSE (mm->device_table_epoch == 0))
mm->device_table_epoch++;
data_quota = clib_net_to_host_u64 (mp->data_quota); data_quota = clib_net_to_host_u64 (mp->data_quota);
clib_memset (&kv, 0, sizeof (kv)); clib_memset (&kv, 0, sizeof (kv));

View File

@ -29,26 +29,7 @@
#include <vppinfra/time_range.h> #include <vppinfra/time_range.h>
#include <vppinfra/bihash_8_8.h> #include <vppinfra/bihash_8_8.h>
#define MACTIME_RANGE_TYPE_DROP 0 #include <mactime/mactime_device.h>
#define MACTIME_RANGE_TYPE_ALLOW 1
typedef struct
{
u8 *device_name;
u8 mac_address[6];
u64 data_quota;
u64 data_used_in_range;
u32 flags;
clib_timebase_range_t *ranges;
} mactime_device_t;
/** Always drop packets from this device */
#define MACTIME_DEVICE_FLAG_STATIC_DROP (1<<0)
#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_DYNAMIC_ALLOW_QUOTA (1<<4)
#define MACTIME_DEVICE_FLAG_DROP_UDP_10001 (1<<5)
typedef struct typedef struct
{ {
@ -75,6 +56,7 @@ typedef struct
/* Device table */ /* Device table */
mactime_device_t *devices; mactime_device_t *devices;
u32 device_table_epoch;
/* Counters */ /* Counters */
vlib_combined_counter_main_t allow_counters; vlib_combined_counter_main_t allow_counters;

View File

@ -0,0 +1,53 @@
/*
* mactime_device.h - device table entry
*
* Copyright (c) 2018 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef included_mactime_device_h
#define included_mactime_device_h
#include <vppinfra/time_range.h>
#define MACTIME_RANGE_TYPE_DROP 0
#define MACTIME_RANGE_TYPE_ALLOW 1
typedef struct
{
u8 *device_name;
u8 mac_address[6];
u64 data_quota;
u64 data_used_in_range;
u32 flags;
u32 pool_index;
f64 last_seen;
clib_timebase_range_t *ranges;
} mactime_device_t;
/** Always drop packets from this device */
#define MACTIME_DEVICE_FLAG_STATIC_DROP (1<<0)
#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_DYNAMIC_ALLOW_QUOTA (1<<4)
#define MACTIME_DEVICE_FLAG_DROP_UDP_10001 (1<<5)
#endif /* included_mactime_device_h */
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/

View File

@ -20,6 +20,8 @@
#include <vppinfra/error.h> #include <vppinfra/error.h>
#include <vppinfra/time_range.h> #include <vppinfra/time_range.h>
#include <vnet/ethernet/ethernet.h> #include <vnet/ethernet/ethernet.h>
#include <mactime/mactime_device.h>
#include <vpp-api/client/stat_client.h>
/* Declare message IDs */ /* Declare message IDs */
#include <mactime/mactime.api_enum.h> #include <mactime/mactime.api_enum.h>
@ -27,6 +29,16 @@
typedef struct typedef struct
{ {
/* device table */
mactime_device_t *devices;
uword *device_by_device_name;
u32 vpp_table_epoch;
/* time range setup */
f64 sunday_midnight;
clib_timebase_t timebase;
f64 timezone_offset;
/* API message ID base */ /* API message ID base */
u16 msg_id_base; u16 msg_id_base;
vat_main_t *vat_main; vat_main_t *vat_main;
@ -78,6 +90,206 @@ api_mactime_enable_disable (vat_main_t * vam)
return ret; return ret;
} }
#if VPP_API_TEST_BUILTIN
extern u8 *format_bytes_with_width (u8 * s, va_list * va);
#else
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 = "";
if (width > 0)
fmt = format (0, "%%%d.3f%%s%c", width, 0);
else
fmt = format (0, "%%.3f%%s%c", 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;
suffix = "B";
}
s = format (s, (char *) fmt, nbytes_f64, suffix);
vec_free (fmt);
return s;
}
#endif
static u8 *
format_device (u8 * s, va_list * args)
{
mactime_device_t *dp = va_arg (*args, mactime_device_t *);
mactime_test_main_t *mm = &mactime_test_main;
int verbose = va_arg (*args, int);
int current_status = 99;
char *status_string;
u8 *macstring = 0;
f64 now;
int j;
if (dp == 0)
{
s = format (s, "%-15s %5s %18s %14s %10s %11s %13s",
"Device Name", "Index", "Addresses", "Status",
"AllowPkt", "AllowByte", "DropPkt");
vec_add1 (s, '\n');
return s;
}
now = clib_timebase_now (&mm->timebase);
/* Check dynamic ranges */
for (j = 0; j < vec_len (dp->ranges); j++)
{
clib_timebase_range_t *r = dp->ranges + j;
f64 start0, end0;
start0 = r->start + mm->sunday_midnight;
end0 = r->end + mm->sunday_midnight;
if (verbose)
s = format (s, " Range %d: %U - %U\n", j,
format_clib_timebase_time, start0,
format_clib_timebase_time, end0);
if (now >= start0 && now <= end0)
{
if (dp->flags & MACTIME_DEVICE_FLAG_DYNAMIC_ALLOW)
current_status = 3;
else if (dp->flags & MACTIME_DEVICE_FLAG_DYNAMIC_ALLOW_QUOTA)
current_status = 5;
else
current_status = 2;
if (verbose)
{
s = format (s, " Time in range %d:", j);
s = format (s, " %U - %U\n",
format_clib_timebase_time, start0,
format_clib_timebase_time, end0);
}
goto print;
}
}
if (verbose && j)
s = format (s, " No range match.\n");
if (dp->flags & MACTIME_DEVICE_FLAG_STATIC_DROP)
current_status = 0;
if (dp->flags & MACTIME_DEVICE_FLAG_STATIC_ALLOW)
current_status = 1;
if (dp->flags & MACTIME_DEVICE_FLAG_DYNAMIC_ALLOW)
current_status = 2;
if (dp->flags & MACTIME_DEVICE_FLAG_DYNAMIC_DROP)
current_status = 3;
if (dp->flags & MACTIME_DEVICE_FLAG_DYNAMIC_ALLOW_QUOTA)
current_status = 4;
print:
macstring = format (0, "%U", format_mac_address, dp->mac_address);
switch (current_status)
{
case 0:
status_string = "static drop";
break;
case 1:
status_string = "static allow";
break;
case 2:
status_string = "dynamic drop";
break;
case 3:
status_string = "dynamic allow";
break;
case 4:
status_string = "d-quota inact";
break;
case 5:
status_string = "d-quota activ";
break;
default:
status_string = "code bug!";
break;
}
s = format (s, "%-15s %5d %18s %14s\n",
dp->device_name, dp->pool_index, macstring, status_string);
vec_free (macstring);
if (dp->data_quota > 0)
{
s = format (s, "%-59s %s%U %s%U", " ", "Quota ",
format_bytes_with_width, dp->data_quota, 10,
"Use ", format_bytes_with_width, dp->data_used_in_range, 8);
vec_add1 (s, '\n');
}
return s;
}
static int
api_mactime_dump (vat_main_t * vam)
{
mactime_test_main_t *tm = &mactime_test_main;
unformat_input_t *i = vam->input;
vl_api_mactime_dump_t *mp;
int verbose = 0;
int ret;
f64 now;
mactime_device_t *dev;
now = clib_timebase_now (&tm->timebase);
if (PREDICT_FALSE ((now - tm->sunday_midnight) > 86400.0 * 7.0))
tm->sunday_midnight = clib_timebase_find_sunday_midnight (now);
/* Parse args required to build the message */
while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
{
if (unformat (i, "force"))
tm->vpp_table_epoch = 0;
else if (unformat (i, "verbose"))
verbose = 1;
else
break;
}
/* Construct the API message */
M (MACTIME_DUMP, mp);
mp->my_table_epoch = clib_host_to_net_u32 (tm->vpp_table_epoch);
/* send it... */
S (mp);
/* Wait for a reply... */
W (ret);
fformat (vam->ofp, "%U", format_device, 0 /* header */ , 0 /* verbose */ );
/* *INDENT-OFF* */
pool_foreach (dev, tm->devices,
({
fformat (vam->ofp, "%U", format_device, dev, verbose);
}));
/* *INDENT-ON* */
return ret;
}
/* These two ought to be in a library somewhere but they aren't */ /* These two ought to be in a library somewhere but they aren't */
static uword static uword
my_unformat_mac_address (unformat_input_t * input, va_list * args) my_unformat_mac_address (unformat_input_t * input, va_list * args)
@ -212,6 +424,14 @@ api_mactime_add_del_range (vat_main_t * vam)
return ret; return ret;
} }
/* We shouldn't get these... */
static void
vl_api_mactime_details_t_handler (vl_api_mactime_details_t * mp)
{
clib_warning ("WARNING: stub called...");
}
#include <mactime/mactime.api_test.c> #include <mactime/mactime.api_test.c>
/* /*

File diff suppressed because it is too large Load Diff

View File

@ -150,7 +150,9 @@ _(INVALID_ALGORITHM, -154, "Invalid Algorithm") \
_(RSRC_IN_USE, -155, "Resource In Use") \ _(RSRC_IN_USE, -155, "Resource In Use") \
_(KEY_LENGTH, -156, "invalid Key Length") \ _(KEY_LENGTH, -156, "invalid Key Length") \
_(FIB_PATH_UNSUPPORTED_NH_PROTO, -157, "Unsupported FIB Path protocol") \ _(FIB_PATH_UNSUPPORTED_NH_PROTO, -157, "Unsupported FIB Path protocol") \
_(API_ENDIAN_FAILED, -159, "Endian mismatch detected") _(API_ENDIAN_FAILED, -159, "Endian mismatch detected") \
_(NO_CHANGE, -160, "No change in table")
typedef enum typedef enum
{ {
#define _(a,b,c) VNET_API_ERROR_##a = (b), #define _(a,b,c) VNET_API_ERROR_##a = (b),