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:

committed by
Florin Coras

parent
0eb75d0e9c
commit
2c41a61d5f
@ -22,3 +22,21 @@ add_vpp_plugin(mactime
|
||||
API_TEST_SOURCES
|
||||
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()
|
||||
|
@ -13,12 +13,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
/** @file
|
||||
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
|
||||
*/
|
||||
|
||||
@ -31,7 +31,7 @@ autoreply define mactime_enable_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,
|
||||
* which was a Thursday.
|
||||
*/
|
||||
@ -41,7 +41,7 @@ typedef time_range
|
||||
f64 end; /**< end of the time range */
|
||||
};
|
||||
|
||||
/** \brief configure per src-mac time ranges
|
||||
/** @brief configure per src-mac time ranges
|
||||
*
|
||||
* Usage:
|
||||
* to create a static allow entry:
|
||||
@ -56,6 +56,10 @@ typedef time_range
|
||||
* 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 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:
|
||||
* Same procedure to create a dynamic allow entry,
|
||||
* 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";
|
||||
};
|
||||
|
||||
/** @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:
|
||||
* eval: (c-set-style "gnu")
|
||||
|
@ -158,6 +158,77 @@ static void vl_api_mactime_enable_disable_t_handler
|
||||
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
|
||||
*/
|
||||
void
|
||||
@ -201,6 +272,14 @@ static void vl_api_mactime_add_del_range_t_handler
|
||||
|
||||
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);
|
||||
|
||||
clib_memset (&kv, 0, sizeof (kv));
|
||||
|
@ -29,26 +29,7 @@
|
||||
#include <vppinfra/time_range.h>
|
||||
#include <vppinfra/bihash_8_8.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;
|
||||
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)
|
||||
#include <mactime/mactime_device.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@ -75,6 +56,7 @@ typedef struct
|
||||
|
||||
/* Device table */
|
||||
mactime_device_t *devices;
|
||||
u32 device_table_epoch;
|
||||
|
||||
/* Counters */
|
||||
vlib_combined_counter_main_t allow_counters;
|
||||
|
53
src/plugins/mactime/mactime_device.h
Normal file
53
src/plugins/mactime/mactime_device.h
Normal 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:
|
||||
*/
|
@ -20,6 +20,8 @@
|
||||
#include <vppinfra/error.h>
|
||||
#include <vppinfra/time_range.h>
|
||||
#include <vnet/ethernet/ethernet.h>
|
||||
#include <mactime/mactime_device.h>
|
||||
#include <vpp-api/client/stat_client.h>
|
||||
|
||||
/* Declare message IDs */
|
||||
#include <mactime/mactime.api_enum.h>
|
||||
@ -27,6 +29,16 @@
|
||||
|
||||
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 */
|
||||
u16 msg_id_base;
|
||||
vat_main_t *vat_main;
|
||||
@ -78,6 +90,206 @@ api_mactime_enable_disable (vat_main_t * vam)
|
||||
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 */
|
||||
static uword
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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>
|
||||
|
||||
/*
|
||||
|
505
src/plugins/mactime/mactime_top.c
Normal file
505
src/plugins/mactime/mactime_top.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -150,7 +150,9 @@ _(INVALID_ALGORITHM, -154, "Invalid Algorithm") \
|
||||
_(RSRC_IN_USE, -155, "Resource In Use") \
|
||||
_(KEY_LENGTH, -156, "invalid Key Length") \
|
||||
_(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
|
||||
{
|
||||
#define _(a,b,c) VNET_API_ERROR_##a = (b),
|
||||
|
Reference in New Issue
Block a user