aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS5
-rw-r--r--src/vat/api_format.c4
-rw-r--r--src/vnet/qos/qos.api174
-rw-r--r--src/vnet/qos/qos_api.c168
-rw-r--r--src/vnet/qos/qos_egress_map.c150
-rw-r--r--src/vnet/qos/qos_egress_map.h9
-rw-r--r--src/vnet/qos/qos_mark.c102
-rw-r--r--src/vnet/qos/qos_mark.h6
-rw-r--r--src/vnet/qos/qos_record.c102
-rw-r--r--src/vnet/qos/qos_record.h5
-rw-r--r--src/vpp/api/custom_dump.c4
-rw-r--r--test/test_qos.py182
-rw-r--r--test/vpp_papi_provider.py22
-rw-r--r--test/vpp_qos.py110
14 files changed, 774 insertions, 269 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 9c9af5d9584..40d1383b2cd 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -116,6 +116,11 @@ I: ip
M: Dave Barach <dave@barachs.net>
F: src/vnet/ip/
+VNET QoS
+I: qos
+M: Neale Ranns <nranns@cisco.com>
+F: src/vnet/qos/
+
VNET Interface Common
I: interface
M: Dave Barach <dave@barachs.net>
diff --git a/src/vat/api_format.c b/src/vat/api_format.c
index d2313106fc6..69a57ab3d33 100644
--- a/src/vat/api_format.c
+++ b/src/vat/api_format.c
@@ -21373,8 +21373,8 @@ api_qos_record_enable_disable (vat_main_t * vam)
M (QOS_RECORD_ENABLE_DISABLE, mp);
- mp->sw_if_index = ntohl (sw_if_index);
- mp->input_source = qs;
+ mp->record.sw_if_index = ntohl (sw_if_index);
+ mp->record.input_source = qs;
mp->enable = enable;
S (mp);
diff --git a/src/vnet/qos/qos.api b/src/vnet/qos/qos.api
index 1960ccb9548..11c91638c5b 100644
--- a/src/vnet/qos/qos.api
+++ b/src/vnet/qos/qos.api
@@ -22,7 +22,7 @@
option version = "1.0.0";
-enum qos_source
+enum qos_source : u8
{
QOS_API_SOURCE_EXT = 0,
QOS_API_SOURCE_VLAN = 1,
@@ -30,76 +30,164 @@ enum qos_source
QOS_API_SOURCE_IP = 3,
};
-/** \brief Enable/Disable QoS recording
- The QoS bits from the packet at the specified input layer are copied
- into the packet. Recording should be used in conjunction with marking
- @param sw_if_index - The interface on which recording is enabled.
- @param enable - enable=1 or disable the feature
- @param input_source - The input source/layer at which the QoS bits
- are copied from the packet. See qos_source_t.
-*/
+/**
+ * QoS recording.
+ * @param sw_if_index - The interface on which recording is enabled.
+ * @param input_source - The input source/layer at which the QoS bits
+ are copied from the packet. See qos_source_t.
+ */
+typedef qos_record
+{
+ u32 sw_if_index;
+ vl_api_qos_source_t input_source;
+};
+
+/**
+ * Enable/Disable QoS recording
+ * The QoS bits from the packet at the specified input layer are copied
+ * into the packet. Recording should be used in conjunction with marking
+ * @param enable - enable=1 or disable the feature
+ * @param record - Recording configuration
+ */
autoreply define qos_record_enable_disable
{
u32 client_index;
u32 context;
- u32 sw_if_index;
- vl_api_qos_source_t input_source;
u8 enable;
+ vl_api_qos_record_t record;
};
-/** \brief A row within a QoS map
- Each value translates from an input value to an output.
-*/
-typeonly define qos_egress_map_row
+/**
+ * Dump the QoS record configs
+ */
+define qos_record_dump
{
- u8 outputs[256];
+ u32 client_index;
+ u32 context;
};
-/** \brief Update a QoS Map
- A QoS map, translates from the QoS value in the packet set by the 'record'
- feature, to the value used for output in the 'mark' feature.
- There is one row in the map for each input/record source.
- The MAP is then applied to the egress interface at for a given output source
- @param map_id - client provided identifier for the map
- @param rows - one row (per-input source) of output values
-*/
+/**
+ * Details of QoS recording configs
+ */
+define qos_record_details
+{
+ u32 context;
+ vl_api_qos_record_t record;
+};
+
+/**
+ * @brief A row within a QoS map
+ * Each value translates from an input value to an output.
+ */
+typedef qos_egress_map_row
+{
+ u8 outputs[256];
+};
+
+/**
+ * QoS Translation Map
+ *
+ * @param id - client provided identifier for the map
+ * @param rows - one row (per-input source) of output values
+ */
+typedef qos_egress_map
+{
+ u32 id;
+ vl_api_qos_egress_map_row_t rows[4];
+};
+
+/**
+ * @brief Update a QoS Map
+ * A QoS map, translates from the QoS value in the packet set by the 'record'
+ * feature, to the value used for output in the 'mark' feature.
+ * There is one row in the map for each input/record source.
+ * The MAP is then applied to the egress interface at for a given output source
+ * @param map - The Map
+ */
autoreply define qos_egress_map_update
{
u32 client_index;
u32 context;
- u32 map_id;
- vl_api_qos_egress_map_row_t rows[4];
+ vl_api_qos_egress_map_t map;
};
-/** \brief Delete a Qos Map
- @param map_id - ID of the map to delete
-*/
+/**
+ * @brief Delete a Qos Map
+ * @param map_id - ID of the map to delete
+ */
autoreply define qos_egress_map_delete
{
u32 client_index;
u32 context;
- u32 map_id;
+ u32 id;
};
-/** \brief Enable/Disable QoS marking
- The QoS bits from the packet are mapped (using the desired egress map)
- into the header of the 'output-source'. Marking should be used in
- conjunction with recording
- @param sw_if_index - The interface on which recording is enabled.
- @param enable - enable=1 or disable the feature
- @param output_source - The output source/layer at which the QoS bits
- are written into the packet. See qos_source_t.
- @param map_id - The ID of the MAP in which the translation from input
- to output is performed.
-*/
-autoreply define qos_mark_enable_disable
+/**
+ * Dump the QoS egress maps
+ */
+define qos_egress_map_dump
{
u32 client_index;
u32 context;
- u32 map_id;
+};
+
+/**
+ * QoS map details
+ */
+define qos_egress_map_details
+{
+ u32 context;
+ vl_api_qos_egress_map_t map;
+};
+
+/**
+ * QoS marking Cponfiguration
+ * The QoS bits from the buffer are mapped (using the desired egress map)
+ * into the header of the 'output-source'. Marking should be used in
+ * conjunction with recording
+ * @param sw_if_index - The interface on which recording is enabled.
+ * @param output_source - The output source/layer at which the QoS bits
+ * are written into the packet. See qos_source_t.
+ * @param map_id - The ID of the MAP in which the translation from input
+ * to output is performed.
+ */
+typedef qos_mark
+{
u32 sw_if_index;
+ u32 map_id;
vl_api_qos_source_t output_source;
+};
+
+/**
+ * @brief Enable/Disable QoS marking
+ * @param enable - enable=1 or disable the feature
+ * @param mark - Marking config
+ */
+autoreply define qos_mark_enable_disable
+{
+ u32 client_index;
+ u32 context;
u8 enable;
+ vl_api_qos_mark_t mark;
+};
+
+/**
+ * Dump QoS marking configs
+ */
+define qos_mark_dump
+{
+ u32 client_index;
+ u32 context;
+ u32 sw_if_index;
+};
+
+/**
+ * QoS marking details
+ */
+autoreply define qos_mark_details
+{
+ u32 context;
+ vl_api_qos_mark_t mark;
};
/*
diff --git a/src/vnet/qos/qos_api.c b/src/vnet/qos/qos_api.c
index 6297c24a843..966ffcce395 100644
--- a/src/vnet/qos/qos_api.c
+++ b/src/vnet/qos/qos_api.c
@@ -44,15 +44,16 @@
#define foreach_qos_api_msg \
_(QOS_RECORD_ENABLE_DISABLE, qos_record_enable_disable) \
+ _(QOS_RECORD_DUMP, qos_record_dump) \
_(QOS_EGRESS_MAP_DELETE, qos_egress_map_delete) \
_(QOS_EGRESS_MAP_UPDATE, qos_egress_map_update) \
- _(QOS_MARK_ENABLE_DISABLE, qos_mark_enable_disable)
+ _(QOS_EGRESS_MAP_DUMP, qos_egress_map_dump) \
+ _(QOS_MARK_ENABLE_DISABLE, qos_mark_enable_disable) \
+ _(QOS_MARK_DUMP, qos_mark_dump)
static int
qos_source_decode (vl_api_qos_source_t v, qos_source_t * q)
{
- v = ntohl (v);
-
switch (v)
{
case QOS_API_SOURCE_EXT:
@@ -72,6 +73,12 @@ qos_source_decode (vl_api_qos_source_t v, qos_source_t * q)
return (VNET_API_ERROR_INVALID_VALUE);
}
+static vl_api_qos_source_t
+qos_source_encode (qos_source_t q)
+{
+ return ((vl_api_qos_source_t) q);
+}
+
void
vl_api_qos_record_enable_disable_t_handler (vl_api_qos_record_enable_disable_t
* mp)
@@ -80,19 +87,63 @@ vl_api_qos_record_enable_disable_t_handler (vl_api_qos_record_enable_disable_t
qos_source_t qs;
int rv = 0;
- rv = qos_source_decode (mp->input_source, &qs);
+ VALIDATE_SW_IF_INDEX (&(mp->record));
+
+ rv = qos_source_decode (mp->record.input_source, &qs);
if (0 == rv)
{
if (mp->enable)
- rv = qos_record_enable (ntohl (mp->sw_if_index), qs);
+ rv = qos_record_enable (ntohl (mp->record.sw_if_index), qs);
else
- rv = qos_record_disable (ntohl (mp->sw_if_index), qs);
+ rv = qos_record_disable (ntohl (mp->record.sw_if_index), qs);
}
+ BAD_SW_IF_INDEX_LABEL;
REPLY_MACRO (VL_API_QOS_RECORD_ENABLE_DISABLE_REPLY);
}
+typedef struct qos_record_send_walk_ctx_t_
+{
+ vl_api_registration_t *reg;
+ u32 context;
+} qos_record_send_walk_ctx_t;
+
+static walk_rc_t
+send_qos_record_details (u32 sw_if_index, qos_source_t input_source, void *c)
+{
+ qos_record_send_walk_ctx_t *ctx;
+ vl_api_qos_record_details_t *mp;
+
+ ctx = c;
+ mp = vl_msg_api_alloc_zero (sizeof (*mp));
+
+ mp->_vl_msg_id = ntohs (VL_API_QOS_RECORD_DETAILS);
+ mp->context = ctx->context;
+ mp->record.sw_if_index = htonl (sw_if_index);
+ mp->record.input_source = qos_source_encode (input_source);
+
+ vl_api_send_msg (ctx->reg, (u8 *) mp);
+
+ return (WALK_CONTINUE);
+}
+
+static void
+vl_api_qos_record_dump_t_handler (vl_api_qos_record_dump_t * mp)
+{
+ vl_api_registration_t *reg;
+
+ reg = vl_api_client_index_to_registration (mp->client_index);
+ if (!reg)
+ return;
+
+ qos_record_send_walk_ctx_t ctx = {
+ .reg = reg,
+ .context = mp->context,
+ };
+ qos_record_walk (send_qos_record_details, &ctx);
+}
+
void
vl_api_qos_egress_map_update_t_handler (vl_api_qos_egress_map_update_t * mp)
{
@@ -102,7 +153,8 @@ vl_api_qos_egress_map_update_t_handler (vl_api_qos_egress_map_update_t * mp)
FOR_EACH_QOS_SOURCE (qs)
{
- qos_egress_map_update (ntohl (mp->map_id), qs, &mp->rows[qs].outputs[0]);
+ qos_egress_map_update (ntohl (mp->map.id), qs,
+ &mp->map.rows[qs].outputs[0]);
}
REPLY_MACRO (VL_API_QOS_EGRESS_MAP_UPDATE_REPLY);
@@ -114,33 +166,121 @@ vl_api_qos_egress_map_delete_t_handler (vl_api_qos_egress_map_delete_t * mp)
vl_api_qos_egress_map_delete_reply_t *rmp;
int rv = 0;
- qos_egress_map_delete (ntohl (mp->map_id));
+ qos_egress_map_delete (ntohl (mp->id));
REPLY_MACRO (VL_API_QOS_EGRESS_MAP_DELETE_REPLY);
}
+typedef struct qos_egress_map_send_walk_ctx_t_
+{
+ vl_api_registration_t *reg;
+ u32 context;
+} qos_egress_map_send_walk_ctx_t;
+
+static walk_rc_t
+send_qos_egress_map_details (qos_egress_map_id_t id,
+ const qos_egress_map_t * m, void *c)
+{
+ qos_egress_map_send_walk_ctx_t *ctx;
+ vl_api_qos_egress_map_details_t *mp;
+ u8 ii;
+
+ ctx = c;
+ mp = vl_msg_api_alloc_zero (sizeof (*mp));
+
+ mp->_vl_msg_id = ntohs (VL_API_QOS_EGRESS_MAP_DETAILS);
+ mp->context = ctx->context;
+ mp->map.id = htonl (id);
+
+ for (ii = 0; ii < 4; ii++)
+ clib_memcpy (mp->map.rows[ii].outputs, m->qem_output[ii], 256);
+
+ vl_api_send_msg (ctx->reg, (u8 *) mp);
+
+ return (WALK_CONTINUE);
+}
+
+static void
+vl_api_qos_egress_map_dump_t_handler (vl_api_qos_egress_map_dump_t * mp)
+{
+ vl_api_registration_t *reg;
+
+ reg = vl_api_client_index_to_registration (mp->client_index);
+ if (!reg)
+ return;
+
+ qos_egress_map_send_walk_ctx_t ctx = {
+ .reg = reg,
+ .context = mp->context,
+ };
+ qos_egress_map_walk (send_qos_egress_map_details, &ctx);
+}
+
void
- vl_api_qos_mark_enable_disable_t_handler
- (vl_api_qos_mark_enable_disable_t * mp)
+vl_api_qos_mark_enable_disable_t_handler (vl_api_qos_mark_enable_disable_t *
+ mp)
{
vl_api_qos_mark_enable_disable_reply_t *rmp;
qos_source_t qs;
int rv = 0;
- rv = qos_source_decode (mp->output_source, &qs);
+ rv = qos_source_decode (mp->mark.output_source, &qs);
if (0 == rv)
{
if (mp->enable)
- rv =
- qos_mark_enable (ntohl (mp->sw_if_index), qs, ntohl (mp->map_id));
+ rv = qos_mark_enable (ntohl (mp->mark.sw_if_index),
+ qs, ntohl (mp->mark.map_id));
else
- rv = qos_mark_disable (ntohl (mp->sw_if_index), qs);
+ rv = qos_mark_disable (ntohl (mp->mark.sw_if_index), qs);
}
REPLY_MACRO (VL_API_QOS_MARK_ENABLE_DISABLE_REPLY);
}
+typedef struct qos_mark_send_walk_ctx_t_
+{
+ vl_api_registration_t *reg;
+ u32 context;
+} qos_mark_send_walk_ctx_t;
+
+static walk_rc_t
+send_qos_mark_details (u32 sw_if_index,
+ u32 map_id, qos_source_t output_source, void *c)
+{
+ qos_mark_send_walk_ctx_t *ctx;
+ vl_api_qos_mark_details_t *mp;
+
+ ctx = c;
+ mp = vl_msg_api_alloc_zero (sizeof (*mp));
+
+ mp->_vl_msg_id = ntohs (VL_API_QOS_MARK_DETAILS);
+ mp->context = ctx->context;
+ mp->mark.sw_if_index = htonl (sw_if_index);
+ mp->mark.output_source = qos_source_encode (output_source);
+ mp->mark.map_id = htonl (map_id);
+
+ vl_api_send_msg (ctx->reg, (u8 *) mp);
+
+ return (WALK_CONTINUE);
+}
+
+static void
+vl_api_qos_mark_dump_t_handler (vl_api_qos_mark_dump_t * mp)
+{
+ vl_api_registration_t *reg;
+
+ reg = vl_api_client_index_to_registration (mp->client_index);
+ if (!reg)
+ return;
+
+ qos_mark_send_walk_ctx_t ctx = {
+ .reg = reg,
+ .context = mp->context,
+ };
+ qos_mark_walk (send_qos_mark_details, &ctx);
+}
+
#define vl_msg_name_crc_list
#include <vnet/qos/qos.api.h>
#undef vl_msg_name_crc_list
diff --git a/src/vnet/qos/qos_egress_map.c b/src/vnet/qos/qos_egress_map.c
index 158ff8445c6..7985579d3cf 100644
--- a/src/vnet/qos/qos_egress_map.c
+++ b/src/vnet/qos/qos_egress_map.c
@@ -41,6 +41,23 @@ qos_egress_map_find (qos_egress_map_id_t mid)
return (INDEX_INVALID);
}
+qos_egress_map_id_t
+qos_egress_map_get_id (index_t qemi)
+{
+ qos_egress_map_id_t qid;
+ index_t qmi;
+
+ /* *INDENT-OFF* */
+ hash_foreach(qid, qmi, qem_db,
+ ({
+ if (qmi == qemi)
+ return (qid);
+ }));
+ /* *INDENT-OFF* */
+
+ return (~0);
+}
+
qos_egress_map_t *
qos_egress_map_find_i (qos_egress_map_id_t mid)
{
@@ -106,6 +123,20 @@ qos_egress_map_delete (qos_egress_map_id_t mid)
}
}
+void
+qos_egress_map_walk (qos_egress_map_walk_cb_t fn, void *c)
+{
+ qos_egress_map_id_t qid;
+ index_t qmi;
+
+ /* *INDENT-OFF* */
+ hash_foreach(qid, qmi, qem_db,
+ ({
+ fn(qid, pool_elt_at_index(qem_pool, qmi), c);
+ }));
+ /* *INDENT-OFF* */
+}
+
static clib_error_t *
qos_egress_map_update_cli (vlib_main_t * vm,
unformat_input_t * input, vlib_cli_command_t * cmd)
@@ -159,55 +190,54 @@ VLIB_CLI_COMMAND (qos_egress_map_update_command, static) = {
};
/* *INDENT-ON* */
-u8 *
-format_qos_egress_map (u8 * s, va_list * args)
-{
- qos_egress_map_t *qem = va_arg (*args, qos_egress_map_t *);
- u32 indent = va_arg (*args, u32);
- int qs;
- u32 ii;
-
- FOR_EACH_QOS_SOURCE (qs)
+ u8 *format_qos_egress_map (u8 * s, va_list * args)
{
- s = format (s, "%U%U:[",
- format_white_space, indent, format_qos_source, qs);
-
- for (ii = 0; ii < ARRAY_LEN (qem->qem_output[qs]) - 1; ii++)
- {
- s = format (s, "%d,", qem->qem_output[qs][ii]);
- }
- s = format (s, "%d]\n", qem->qem_output[qs][ii]);
- }
+ qos_egress_map_t *qem = va_arg (*args, qos_egress_map_t *);
+ u32 indent = va_arg (*args, u32);
+ int qs;
+ u32 ii;
- return (s);
-}
-
-static clib_error_t *
-qos_egress_map_show (vlib_main_t * vm,
- unformat_input_t * input, vlib_cli_command_t * cmd)
-{
- qos_egress_map_id_t map_id;
- qos_egress_map_t *qem;
- clib_error_t *error;
-
- map_id = ~0;
- qem = NULL;
- error = NULL;
-
- while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ FOR_EACH_QOS_SOURCE (qs)
{
- if (unformat (input, "id %d", &map_id))
- ;
- else
+ s = format (s, "%U%U:[",
+ format_white_space, indent, format_qos_source, qs);
+
+ for (ii = 0; ii < ARRAY_LEN (qem->qem_output[qs]) - 1; ii++)
{
- error = unformat_parse_error (input);
- goto done;
+ s = format (s, "%d,", qem->qem_output[qs][ii]);
}
+ s = format (s, "%d]\n", qem->qem_output[qs][ii]);
}
- if (~0 == map_id)
- {
- index_t qemi;
+ return (s);
+ }
+
+ static clib_error_t *qos_egress_map_show (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+ {
+ qos_egress_map_id_t map_id;
+ qos_egress_map_t *qem;
+ clib_error_t *error;
+
+ map_id = ~0;
+ qem = NULL;
+ error = NULL;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "id %d", &map_id))
+ ;
+ else
+ {
+ error = unformat_parse_error (input);
+ goto done;
+ }
+ }
+
+ if (~0 == map_id)
+ {
+ index_t qemi;
/* *INDENT-OFF* */
hash_foreach(map_id, qemi, qem_db,
@@ -218,25 +248,25 @@ qos_egress_map_show (vlib_main_t * vm,
pool_elt_at_index(qem_pool, qemi), 2);
}));
/* *INDENT-ON* */
- }
- else
- {
- qem = qos_egress_map_find_i (map_id);
-
- if (NULL == qem)
- {
- error = clib_error_return (0, "No Map for ID %d", map_id);
- }
- else
- {
- vlib_cli_output (vm, " Map-ID:%d\n%U",
- map_id, format_qos_egress_map, qem, 2);
- }
- }
+ }
+ else
+ {
+ qem = qos_egress_map_find_i (map_id);
+
+ if (NULL == qem)
+ {
+ error = clib_error_return (0, "No Map for ID %d", map_id);
+ }
+ else
+ {
+ vlib_cli_output (vm, " Map-ID:%d\n%U",
+ map_id, format_qos_egress_map, qem, 2);
+ }
+ }
-done:
- return (error);
-}
+ done:
+ return (error);
+ }
/*?
* Show Egress Qos Maps
diff --git a/src/vnet/qos/qos_egress_map.h b/src/vnet/qos/qos_egress_map.h
index 3b6e0b45a43..0dab7adc2dd 100644
--- a/src/vnet/qos/qos_egress_map.h
+++ b/src/vnet/qos/qos_egress_map.h
@@ -66,6 +66,15 @@ extern void qos_egress_map_delete (qos_egress_map_id_t tid);
* Get the VPP QoS map index from the user's map-ID
*/
extern index_t qos_egress_map_find (qos_egress_map_id_t tid);
+extern qos_egress_map_id_t qos_egress_map_get_id (index_t qemi);
+
+/**
+ * Walk each of the configured maps
+ */
+typedef walk_rc_t (*qos_egress_map_walk_cb_t) (qos_egress_map_id_t id,
+ const qos_egress_map_t * m,
+ void *c);
+void qos_egress_map_walk (qos_egress_map_walk_cb_t fn, void *c);
/**
* Data-plane functions
diff --git a/src/vnet/qos/qos_mark.c b/src/vnet/qos/qos_mark.c
index dcb0f9d1ab3..44bb34bd010 100644
--- a/src/vnet/qos/qos_mark.c
+++ b/src/vnet/qos/qos_mark.c
@@ -117,6 +117,24 @@ qos_mark_disable (u32 sw_if_index, qos_source_t output_source)
return (0);
}
+void
+qos_mark_walk (qos_mark_walk_cb_t fn, void *c)
+{
+ qos_source_t qs;
+
+ FOR_EACH_QOS_SOURCE (qs)
+ {
+ u32 sw_if_index;
+
+ vec_foreach_index (sw_if_index, qos_mark_configs[qs])
+ {
+ if (INDEX_INVALID != qos_mark_configs[qs][sw_if_index])
+ fn (sw_if_index,
+ qos_egress_map_get_id (qos_mark_configs[qs][sw_if_index]), qs, c);
+ }
+ }
+}
+
static clib_error_t *
qos_mark_cli (vlib_main_t * vm,
unformat_input_t * input, vlib_cli_command_t * cmd)
@@ -178,6 +196,90 @@ VLIB_CLI_COMMAND (qos_egress_map_interface_command, static) = {
};
/* *INDENT-ON* */
+static void
+qos_mark_show_one_interface (vlib_main_t * vm, u32 sw_if_index)
+{
+ index_t qemis[QOS_N_SOURCES];
+ qos_source_t qs;
+ bool set;
+
+ set = false;
+ clib_memset_u32 (qemis, INDEX_INVALID, QOS_N_SOURCES);
+
+ FOR_EACH_QOS_SOURCE (qs)
+ {
+ if (vec_len (qos_mark_configs[qs]) <= sw_if_index)
+ continue;
+ if (INDEX_INVALID != (qemis[qs] = qos_mark_configs[qs][sw_if_index]))
+ set = true;
+ }
+
+ if (set)
+ {
+ vlib_cli_output (vm, " %U:", format_vnet_sw_if_index_name,
+ vnet_get_main (), sw_if_index);
+
+ FOR_EACH_QOS_SOURCE (qs)
+ {
+ if (qemis[qs] != INDEX_INVALID)
+ vlib_cli_output (vm, " %U: map:%d", format_qos_source, qs,
+ qemis[qs]);
+ }
+ }
+}
+
+static clib_error_t *
+qos_mark_show (vlib_main_t * vm,
+ unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+ vnet_main_t *vnm = vnet_get_main ();
+ qos_source_t qs;
+ u32 sw_if_index;
+
+ sw_if_index = ~0;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "%U", unformat_vnet_sw_interface,
+ vnm, &sw_if_index))
+ ;
+ }
+
+ if (~0 == sw_if_index)
+ {
+ u32 ii, n_ints = 0;
+
+ FOR_EACH_QOS_SOURCE (qs)
+ {
+ n_ints = clib_max (n_ints, vec_len (qos_mark_configs[qs]));
+ }
+
+ for (ii = 0; ii < n_ints; ii++)
+ {
+ qos_mark_show_one_interface (vm, ii);
+ }
+ }
+ else
+ qos_mark_show_one_interface (vm, sw_if_index);
+
+ return (NULL);
+}
+
+/*?
+ * Show Egress Qos Maps
+ *
+ * @cliexpar
+ * @cliexcmd{show qos egress map}
+ ?*/
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (qos_mark_show_command, static) = {
+ .path = "show qos mark",
+ .short_help = "show qos mark [interface]",
+ .function = qos_mark_show,
+ .is_mp_safe = 1,
+};
+/* *INDENT-ON* */
+
/*
* fd.io coding-style-patch-verification: ON
*
diff --git a/src/vnet/qos/qos_mark.h b/src/vnet/qos/qos_mark.h
index f1705d1bb33..91e2024af94 100644
--- a/src/vnet/qos/qos_mark.h
+++ b/src/vnet/qos/qos_mark.h
@@ -28,6 +28,12 @@ extern int qos_mark_enable (u32 sw_if_index,
qos_egress_map_id_t tid);
extern int qos_mark_disable (u32 sw_if_index, qos_source_t output_source);
+typedef walk_rc_t (*qos_mark_walk_cb_t) (u32 sw_if_index,
+ u32 map_id,
+ qos_source_t input_source,
+ void *ctx);
+void qos_mark_walk (qos_mark_walk_cb_t fn, void *c);
+
#endif
/*
diff --git a/src/vnet/qos/qos_record.c b/src/vnet/qos/qos_record.c
index 20d0b5bf4f5..40e6b0778bb 100644
--- a/src/vnet/qos/qos_record.c
+++ b/src/vnet/qos/qos_record.c
@@ -100,6 +100,23 @@ qos_record_disable (u32 sw_if_index, qos_source_t input_source)
return (0);
}
+void
+qos_record_walk (qos_record_walk_cb_t fn, void *c)
+{
+ qos_source_t qs;
+
+ FOR_EACH_QOS_SOURCE (qs)
+ {
+ u32 sw_if_index;
+
+ vec_foreach_index (sw_if_index, qos_record_configs[qs])
+ {
+ if (0 != qos_record_configs[qs][sw_if_index])
+ fn (sw_if_index, qs, c);
+ }
+ }
+}
+
/*
* Disable recording feature for all protocols when the interface
* is deleted
@@ -124,7 +141,7 @@ qos_record_ip_interface_add_del (vnet_main_t * vnm,
VNET_SW_INTERFACE_ADD_DEL_FUNCTION (qos_record_ip_interface_add_del);
clib_error_t *
-l2_ip_qos_init (vlib_main_t * vm)
+qos_record_init (vlib_main_t * vm)
{
qos_source_t qs;
vlib_node_t *node = vlib_get_node_by_name (vm, (u8 *) "l2-ip-qos-record");
@@ -139,7 +156,7 @@ l2_ip_qos_init (vlib_main_t * vm)
return 0;
}
-VLIB_INIT_FUNCTION (l2_ip_qos_init);
+VLIB_INIT_FUNCTION (qos_record_init);
static clib_error_t *
qos_record_cli (vlib_main_t * vm,
@@ -199,6 +216,87 @@ VLIB_CLI_COMMAND (qos_record_command, static) = {
};
/* *INDENT-ON* */
+static void
+qos_record_show_one_interface (vlib_main_t * vm, u32 sw_if_index)
+{
+ u8 n_cfgs[QOS_N_SOURCES] = { };
+ qos_source_t qs;
+ bool set;
+
+ set = false;
+
+ FOR_EACH_QOS_SOURCE (qs)
+ {
+ if (vec_len (qos_record_configs[qs]) <= sw_if_index)
+ continue;
+ if (0 != (n_cfgs[qs] = qos_record_configs[qs][sw_if_index]))
+ set = true;
+ }
+
+ if (set)
+ {
+ vlib_cli_output (vm, " %U:", format_vnet_sw_if_index_name,
+ vnet_get_main (), sw_if_index);
+
+ FOR_EACH_QOS_SOURCE (qs)
+ {
+ if (n_cfgs[qs] != 0)
+ vlib_cli_output (vm, " %U", format_qos_source, qs);
+ }
+ }
+}
+
+static clib_error_t *
+qos_record_show (vlib_main_t * vm,
+ unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+ vnet_main_t *vnm = vnet_get_main ();
+ qos_source_t qs;
+ u32 sw_if_index;
+
+ sw_if_index = ~0;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "%U", unformat_vnet_sw_interface,
+ vnm, &sw_if_index))
+ ;
+ }
+
+ if (~0 == sw_if_index)
+ {
+ u32 ii, n_ints = 0;
+
+ FOR_EACH_QOS_SOURCE (qs)
+ {
+ n_ints = clib_max (n_ints, vec_len (qos_record_configs[qs]));
+ }
+
+ for (ii = 0; ii < n_ints; ii++)
+ {
+ qos_record_show_one_interface (vm, ii);
+ }
+ }
+ else
+ qos_record_show_one_interface (vm, sw_if_index);
+
+ return (NULL);
+}
+
+/*?
+ * Show Egress Qos Maps
+ *
+ * @cliexpar
+ * @cliexcmd{show qos egress map}
+ ?*/
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (qos_record_show_command, static) = {
+ .path = "show qos record",
+ .short_help = "show qos record [interface]",
+ .function = qos_record_show,
+ .is_mp_safe = 1,
+};
+/* *INDENT-ON* */
/*
* fd.io coding-style-patch-verification: ON
diff --git a/src/vnet/qos/qos_record.h b/src/vnet/qos/qos_record.h
index e5726d650a7..b80041f3241 100644
--- a/src/vnet/qos/qos_record.h
+++ b/src/vnet/qos/qos_record.h
@@ -21,6 +21,11 @@
extern int qos_record_disable (u32 sw_if_index, qos_source_t input_source);
extern int qos_record_enable (u32 sw_if_index, qos_source_t input_source);
+typedef walk_rc_t (*qos_record_walk_cb_t) (u32 sw_if_index,
+ qos_source_t input_source,
+ void *ctx);
+void qos_record_walk (qos_record_walk_cb_t fn, void *c);
+
#endif
/*
diff --git a/src/vpp/api/custom_dump.c b/src/vpp/api/custom_dump.c
index 840889d6cc3..11ff41aa86c 100644
--- a/src/vpp/api/custom_dump.c
+++ b/src/vpp/api/custom_dump.c
@@ -3765,9 +3765,9 @@ static void *vl_api_qos_record_enable_disable_t_print
u8 *s;
s = format (0, "SCRIPT: qos_record_enable_disable ");
- s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+ s = format (s, "sw_if_index %d ", ntohl (mp->record.sw_if_index));
s = format (s, "input_source %U ", format_qos_source,
- ntohl (mp->input_source));
+ mp->record.input_source);
if (!mp->enable)
s = format (s, "disable ");
diff --git a/test/test_qos.py b/test/test_qos.py
index 94062b89ae2..9efa79854bf 100644
--- a/test/test_qos.py
+++ b/test/test_qos.py
@@ -15,6 +15,7 @@ from scapy.layers.inet import IP, UDP
from scapy.layers.inet6 import IPv6
from scapy.contrib.mpls import MPLS
from vpp_papi import VppEnum
+from vpp_qos import VppQosRecord, VppQosEgressMap, VppQosMark
NUM_PKTS = 67
@@ -77,7 +78,7 @@ class TestQOS(VppTestCase):
{'outputs': os},
{'outputs': os}]
- self.vapi.qos_egress_map_update(1, rows)
+ qem1 = VppQosEgressMap(self, 1, rows).add_vpp_config()
#
# For table 2 (and up) use the value n for everything
@@ -89,7 +90,7 @@ class TestQOS(VppTestCase):
{'outputs': os},
{'outputs': os}]
- self.vapi.qos_egress_map_update(2, rows)
+ qem2 = VppQosEgressMap(self, 2, rows).add_vpp_config()
output = [scapy.compat.chb(3)] * 256
os = b''.join(output)
@@ -98,7 +99,7 @@ class TestQOS(VppTestCase):
{'outputs': os},
{'outputs': os}]
- self.vapi.qos_egress_map_update(3, rows)
+ qem3 = VppQosEgressMap(self, 3, rows).add_vpp_config()
output = [scapy.compat.chb(4)] * 256
os = b''.join(output)
@@ -106,32 +107,29 @@ class TestQOS(VppTestCase):
{'outputs': os},
{'outputs': os},
{'outputs': os}]
- self.vapi.qos_egress_map_update(4, rows)
- self.vapi.qos_egress_map_update(5, rows)
- self.vapi.qos_egress_map_update(6, rows)
- self.vapi.qos_egress_map_update(7, rows)
+ qem4 = VppQosEgressMap(self, 4, rows).add_vpp_config()
+ qem5 = VppQosEgressMap(self, 5, rows).add_vpp_config()
+ qem6 = VppQosEgressMap(self, 6, rows).add_vpp_config()
+ qem7 = VppQosEgressMap(self, 7, rows).add_vpp_config()
+
+ self.assertTrue(qem7.query_vpp_config())
self.logger.info(self.vapi.cli("sh qos eg map"))
#
# Bind interface pgN to table n
#
- self.vapi.qos_mark_enable_disable(self.pg1.sw_if_index,
- self.QOS_SOURCE.QOS_API_SOURCE_IP,
- 1,
- 1)
- self.vapi.qos_mark_enable_disable(self.pg2.sw_if_index,
- self.QOS_SOURCE.QOS_API_SOURCE_IP,
- 2,
- 1)
- self.vapi.qos_mark_enable_disable(self.pg3.sw_if_index,
- self.QOS_SOURCE.QOS_API_SOURCE_IP,
- 3,
- 1)
- self.vapi.qos_mark_enable_disable(self.pg4.sw_if_index,
- self.QOS_SOURCE.QOS_API_SOURCE_IP,
- 4,
- 1)
+ qm1 = VppQosMark(self, self.pg1, qem1,
+ self.QOS_SOURCE.QOS_API_SOURCE_IP).add_vpp_config()
+ qm2 = VppQosMark(self, self.pg2, qem2,
+ self.QOS_SOURCE.QOS_API_SOURCE_IP).add_vpp_config()
+ qm3 = VppQosMark(self, self.pg3, qem3,
+ self.QOS_SOURCE.QOS_API_SOURCE_IP).add_vpp_config()
+ qm4 = VppQosMark(self, self.pg4, qem4,
+ self.QOS_SOURCE.QOS_API_SOURCE_IP).add_vpp_config()
+ self.assertTrue(qm3.query_vpp_config())
+
+ self.logger.info(self.vapi.cli("sh qos mark"))
#
# packets ingress on Pg0
@@ -160,9 +158,10 @@ class TestQOS(VppTestCase):
#
# Enable QoS recording on IP input for pg0
#
- self.vapi.qos_record_enable_disable(self.pg0.sw_if_index,
- self.QOS_SOURCE.QOS_API_SOURCE_IP,
- 1)
+ qr1 = VppQosRecord(self, self.pg0,
+ self.QOS_SOURCE.QOS_API_SOURCE_IP)
+ qr1.add_vpp_config()
+ self.logger.info(self.vapi.cli("sh qos record"))
#
# send the same packets, this time expect the input TOS of 1
@@ -218,14 +217,11 @@ class TestQOS(VppTestCase):
#
# remove the map on pg2 and pg3, now expect an unchanged IP tos
#
- self.vapi.qos_mark_enable_disable(self.pg2.sw_if_index,
- self.QOS_SOURCE.QOS_API_SOURCE_IP,
- 2,
- 0)
- self.vapi.qos_mark_enable_disable(self.pg3.sw_if_index,
- self.QOS_SOURCE.QOS_API_SOURCE_IP,
- 3,
- 0)
+ qm2.remove_vpp_config()
+ qm3.remove_vpp_config()
+ self.logger.info(self.vapi.cli("sh qos mark"))
+
+ self.assertFalse(qm3.query_vpp_config())
self.logger.info(self.vapi.cli("sh int feat pg2"))
p_v4[IP].dst = self.pg2.remote_ip4
@@ -249,9 +245,8 @@ class TestQOS(VppTestCase):
#
# disable the input recording on pg0
#
- self.vapi.qos_record_enable_disable(self.pg0.sw_if_index,
- self.QOS_SOURCE.QOS_API_SOURCE_IP,
- 0)
+ self.assertTrue(qr1.query_vpp_config())
+ qr1.remove_vpp_config()
#
# back to an unchanged TOS value
@@ -263,14 +258,8 @@ class TestQOS(VppTestCase):
#
# disable the egress map on pg1 and pg4
#
- self.vapi.qos_mark_enable_disable(self.pg1.sw_if_index,
- self.QOS_SOURCE.QOS_API_SOURCE_IP,
- 1,
- 0)
- self.vapi.qos_mark_enable_disable(self.pg4.sw_if_index,
- self.QOS_SOURCE.QOS_API_SOURCE_IP,
- 4,
- 0)
+ qm1.remove_vpp_config()
+ qm4.remove_vpp_config()
#
# unchanged Tos on pg1
@@ -279,17 +268,6 @@ class TestQOS(VppTestCase):
for p in rx:
self.assertEqual(p[IP].tos, 254)
- #
- # clean-up the map
- #
- self.vapi.qos_egress_map_delete(1)
- self.vapi.qos_egress_map_delete(4)
- self.vapi.qos_egress_map_delete(2)
- self.vapi.qos_egress_map_delete(3)
- self.vapi.qos_egress_map_delete(5)
- self.vapi.qos_egress_map_delete(6)
- self.vapi.qos_egress_map_delete(7)
-
def test_qos_mpls(self):
""" QoS Mark/Record MPLS """
@@ -313,7 +291,7 @@ class TestQOS(VppTestCase):
{'outputs': os3},
{'outputs': os4}]
- self.vapi.qos_egress_map_update(1, rows)
+ qem1 = VppQosEgressMap(self, 1, rows).add_vpp_config()
#
# a route with 1 MPLS label
@@ -337,13 +315,10 @@ class TestQOS(VppTestCase):
# enable IP QoS recording on the input Pg0 and MPLS egress marking
# on Pg1
#
- self.vapi.qos_record_enable_disable(self.pg0.sw_if_index,
- self.QOS_SOURCE.QOS_API_SOURCE_IP,
- 1)
- self.vapi.qos_mark_enable_disable(self.pg1.sw_if_index,
- self.QOS_SOURCE.QOS_API_SOURCE_MPLS,
- 1,
- 1)
+ qr1 = VppQosRecord(self, self.pg0,
+ self.QOS_SOURCE.QOS_API_SOURCE_IP).add_vpp_config()
+ qm1 = VppQosMark(self, self.pg1, qem1,
+ self.QOS_SOURCE.QOS_API_SOURCE_MPLS).add_vpp_config()
#
# packet that will get one label added and 3 labels added resp.
@@ -385,14 +360,12 @@ class TestQOS(VppTestCase):
# enable MPLS QoS recording on the input Pg0 and IP egress marking
# on Pg1
#
- self.vapi.qos_record_enable_disable(
- self.pg0.sw_if_index,
- self.QOS_SOURCE.QOS_API_SOURCE_MPLS,
- 1)
- self.vapi.qos_mark_enable_disable(self.pg1.sw_if_index,
- self.QOS_SOURCE.QOS_API_SOURCE_IP,
- 1,
- 1)
+ qr2 = VppQosRecord(
+ self, self.pg0,
+ self.QOS_SOURCE.QOS_API_SOURCE_MPLS).add_vpp_config()
+ qm2 = VppQosMark(
+ self, self.pg1, qem1,
+ self.QOS_SOURCE.QOS_API_SOURCE_IP).add_vpp_config()
#
# MPLS x-connect - COS according to pg1 map
@@ -440,26 +413,6 @@ class TestQOS(VppTestCase):
for p in rx:
self.assertEqual(p[IP].tos, from_mpls)
- #
- # cleanup
- #
- self.vapi.qos_record_enable_disable(self.pg0.sw_if_index,
- self.QOS_SOURCE.QOS_API_SOURCE_IP,
- 0)
- self.vapi.qos_mark_enable_disable(self.pg1.sw_if_index,
- self.QOS_SOURCE.QOS_API_SOURCE_MPLS,
- 1,
- 0)
- self.vapi.qos_record_enable_disable(
- self.pg0.sw_if_index,
- self.QOS_SOURCE.QOS_API_SOURCE_MPLS,
- 0)
- self.vapi.qos_mark_enable_disable(self.pg1.sw_if_index,
- self.QOS_SOURCE.QOS_API_SOURCE_IP,
- 1,
- 0)
- self.vapi.qos_egress_map_delete(1)
-
def test_qos_vlan(self):
"""QoS mark/record VLAN """
@@ -475,7 +428,7 @@ class TestQOS(VppTestCase):
{'outputs': os},
{'outputs': os}]
- self.vapi.qos_egress_map_update(1, rows)
+ qem1 = VppQosEgressMap(self, 1, rows).add_vpp_config()
sub_if = VppDot1QSubint(self, self.pg0, 11)
@@ -488,25 +441,22 @@ class TestQOS(VppTestCase):
#
# enable VLAN QoS recording/marking on the input Pg0 subinterface and
#
- self.vapi.qos_record_enable_disable(
- sub_if.sw_if_index,
- self.QOS_SOURCE.QOS_API_SOURCE_VLAN,
- 1)
- self.vapi.qos_mark_enable_disable(sub_if.sw_if_index,
- self.QOS_SOURCE.QOS_API_SOURCE_VLAN,
- 1,
- 1)
+ qr_v = VppQosRecord(
+ self, sub_if,
+ self.QOS_SOURCE.QOS_API_SOURCE_VLAN).add_vpp_config()
+ qm_v = VppQosMark(
+ self, sub_if, qem1,
+ self.QOS_SOURCE.QOS_API_SOURCE_VLAN).add_vpp_config()
#
# IP marking/recording on pg1
#
- self.vapi.qos_record_enable_disable(self.pg1.sw_if_index,
- self.QOS_SOURCE.QOS_API_SOURCE_IP,
- 1)
- self.vapi.qos_mark_enable_disable(self.pg1.sw_if_index,
- self.QOS_SOURCE.QOS_API_SOURCE_IP,
- 1,
- 1)
+ qr_ip = VppQosRecord(
+ self, self.pg1,
+ self.QOS_SOURCE.QOS_API_SOURCE_IP).add_vpp_config()
+ qm_ip = VppQosMark(
+ self, self.pg1, qem1,
+ self.QOS_SOURCE.QOS_API_SOURCE_IP).add_vpp_config()
#
# a routes to/from sub-interface
@@ -576,22 +526,6 @@ class TestQOS(VppTestCase):
sub_if.unconfig_ip4()
sub_if.unconfig_ip6()
- self.vapi.qos_record_enable_disable(
- sub_if.sw_if_index,
- self.QOS_SOURCE.QOS_API_SOURCE_VLAN,
- 0)
- self.vapi.qos_mark_enable_disable(sub_if.sw_if_index,
- self.QOS_SOURCE.QOS_API_SOURCE_VLAN,
- 1,
- 0)
- self.vapi.qos_record_enable_disable(self.pg1.sw_if_index,
- self.QOS_SOURCE.QOS_API_SOURCE_IP,
- 0)
- self.vapi.qos_mark_enable_disable(self.pg1.sw_if_index,
- self.QOS_SOURCE.QOS_API_SOURCE_IP,
- 1,
- 0)
-
if __name__ == '__main__':
unittest.main(testRunner=VppTestRunner)
diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py
index 40c6045c517..e40ef79cbf2 100644
--- a/test/vpp_papi_provider.py
+++ b/test/vpp_papi_provider.py
@@ -2125,28 +2125,6 @@ class VppPapiProvider(object):
""" GBP VXLAN tunnel add/del """
return self.api(self.papi.gbp_vxlan_tunnel_dump, {})
- def qos_egress_map_update(self, id, outputs):
- """ QOS egress map update """
- return self.api(self.papi.qos_egress_map_update,
- {'map_id': id,
- 'rows': outputs})
-
- def qos_egress_map_delete(self, id):
- """ QOS egress map delete """
- return self.api(self.papi.qos_egress_map_delete,
- {'map_id': id})
-
- def qos_mark_enable_disable(self, sw_if_index,
- output_source,
- map_id,
- enable):
- """ QOS Mark Enable/Disable """
- return self.api(self.papi.qos_mark_enable_disable,
- {'map_id': map_id,
- 'sw_if_index': sw_if_index,
- 'output_source': output_source,
- 'enable': enable})
-
def igmp_enable_disable(self, sw_if_index, enable, host):
""" Enable/disable IGMP on a given interface """
return self.api(self.papi.igmp_enable_disable,
diff --git a/test/vpp_qos.py b/test/vpp_qos.py
new file mode 100644
index 00000000000..0577863ef8c
--- /dev/null
+++ b/test/vpp_qos.py
@@ -0,0 +1,110 @@
+"""
+ QoS
+
+ object abstractions for representing QoS config VPP
+"""
+
+from vpp_object import VppObject
+
+
+class VppQosRecord(VppObject):
+ """ QoS Record(ing) configuration """
+
+ def __init__(self, test, intf, source):
+ self._test = test
+ self.intf = intf
+ self.source = source
+
+ def add_vpp_config(self):
+ self._test.vapi.qos_record_enable_disable(
+ enable=1,
+ record={'sw_if_index': self.intf.sw_if_index,
+ 'input_source': self.source})
+ self._test.registry.register(self, self._test.logger)
+ return self
+
+ def remove_vpp_config(self):
+ self._test.vapi.qos_record_enable_disable(
+ enable=0,
+ record={'sw_if_index': self.intf.sw_if_index,
+ 'input_source': self.source})
+
+ def query_vpp_config(self):
+ rs = self._test.vapi.qos_record_dump()
+
+ for r in rs:
+ if self.intf.sw_if_index == r.record.sw_if_index and \
+ self.source == r.record.input_source:
+ return True
+ return False
+
+ def object_id(self):
+ return ("qos-record-%s-%d" % (self.intf, self.source))
+
+
+class VppQosEgressMap(VppObject):
+ """ QoS Egress Map(ping) configuration """
+
+ def __init__(self, test, id, rows):
+ self._test = test
+ self.id = id
+ self.rows = rows
+
+ def add_vpp_config(self):
+ self._test.vapi.qos_egress_map_update(
+ map={'id': self.id,
+ 'rows': self.rows})
+ self._test.registry.register(self, self._test.logger)
+ return self
+
+ def remove_vpp_config(self):
+ self._test.vapi.qos_egress_map_delete(id=self.id)
+
+ def query_vpp_config(self):
+ rs = self._test.vapi.qos_egress_map_dump()
+
+ for r in rs:
+ if self.id == r.map.id:
+ return True
+ return False
+
+ def object_id(self):
+ return ("qos-map-%d" % (self.id))
+
+
+class VppQosMark(VppObject):
+ """ QoS Mark(ing) configuration """
+
+ def __init__(self, test, intf, map, source):
+ self._test = test
+ self.intf = intf
+ self.source = source
+ self.map = map
+
+ def add_vpp_config(self):
+ self._test.vapi.qos_mark_enable_disable(
+ enable=1,
+ mark={'sw_if_index': self.intf.sw_if_index,
+ 'map_id': self.map.id,
+ 'output_source': self.source})
+ self._test.registry.register(self, self._test.logger)
+ return self
+
+ def remove_vpp_config(self):
+ self._test.vapi.qos_mark_enable_disable(
+ enable=0,
+ mark={'sw_if_index': self.intf.sw_if_index,
+ 'output_source': self.source})
+
+ def query_vpp_config(self):
+ ms = self._test.vapi.qos_mark_dump()
+
+ for m in ms:
+ if self.intf.sw_if_index == m.mark.sw_if_index and \
+ self.source == m.mark.output_source and \
+ self.map.id == m.mark.map_id:
+ return True
+ return False
+
+ def object_id(self):
+ return ("qos-mark-%s-%d" % (self.intf, self.source))