qos: QoS dump APIs 23/20823/5
authorNeale Ranns <nranns@cisco.com>
Tue, 23 Jul 2019 15:16:19 +0000 (08:16 -0700)
committerDamjan Marion <dmarion@me.com>
Wed, 24 Jul 2019 14:55:59 +0000 (14:55 +0000)
Type: feature

Change-Id: I514b40026986f3828c8727453456b20a0a45f3af
Signed-off-by: Neale Ranns <nranns@cisco.com>
14 files changed:
MAINTAINERS
src/vat/api_format.c
src/vnet/qos/qos.api
src/vnet/qos/qos_api.c
src/vnet/qos/qos_egress_map.c
src/vnet/qos/qos_egress_map.h
src/vnet/qos/qos_mark.c
src/vnet/qos/qos_mark.h
src/vnet/qos/qos_record.c
src/vnet/qos/qos_record.h
src/vpp/api/custom_dump.c
test/test_qos.py
test/vpp_papi_provider.py
test/vpp_qos.py [new file with mode: 0644]

index 9c9af5d..40d1383 100644 (file)
@@ -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>
index d231310..69a57ab 100644 (file)
@@ -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);
index 1960ccb..11c9163 100644 (file)
@@ -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;
 };
 
 /*
index 6297c24..966ffcc 100644 (file)
 
 #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
index 158ff84..7985579 100644 (file)
@@ -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
index 3b6e0b4..0dab7ad 100644 (file)
@@ -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
index dcb0f9d..44bb34b 100644 (file)
@@ -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
  *
index f1705d1..91e2024 100644 (file)
@@ -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
 
 /*
index 20d0b5b..40e6b07 100644 (file)
@@ -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
index e5726d6..b80041f 100644 (file)
 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
 
 /*
index 840889d..11ff41a 100644 (file)
@@ -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 ");
index 94062b8..9efa798 100644 (file)
@@ -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)
index 40c6045..e40ef79 100644 (file)
@@ -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 (file)
index 0000000..0577863
--- /dev/null
@@ -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))