FD.io VPP  v19.01.2-3-gf61a1a8
Vector Packet Processing
qos_mark.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <vnet/ip/ip.h>
17 #include <vnet/feature/feature.h>
19 #include <vnet/qos/qos_mark.h>
20 
21 /**
22  * per-interface vector of which MAP is used by which interface
23  * for each output source
24  */
26 
27 void
29 {
30  vnet_feature_enable_disable ("ip6-output", "ip6-qos-mark",
31  sw_if_index, enable, NULL, 0);
32  vnet_feature_enable_disable ("ip4-output", "ip4-qos-mark",
33  sw_if_index, enable, NULL, 0);
34 }
35 
36 void
38 {
39  /*
40  * one cannot run a feature on a sub-interface, so we need
41  * to enable a feature on all the L3 output paths
42  */
43  vnet_feature_enable_disable ("ip6-output", "vlan-ip6-qos-mark",
44  sw_if_index, enable, NULL, 0);
45  vnet_feature_enable_disable ("ip4-output", "vlan-ip4-qos-mark",
46  sw_if_index, enable, NULL, 0);
47  vnet_feature_enable_disable ("mpls-output", "vlan-mpls-qos-mark",
48  sw_if_index, enable, NULL, 0);
49 }
50 
51 void
53 {
54  vnet_feature_enable_disable ("mpls-output", "mpls-qos-mark",
55  sw_if_index, enable, NULL, 0);
56 }
57 
58 static void
60 {
61  switch (qs)
62  {
63  case QOS_SOURCE_EXT:
64  ASSERT (0);
65  break;
66  case QOS_SOURCE_VLAN:
67  qos_mark_vlan_enable_disable (sw_if_index, enable);
68  break;
69  case QOS_SOURCE_MPLS:
70  qos_mark_mpls_enable_disable (sw_if_index, enable);
71  break;
72  case QOS_SOURCE_IP:
73  qos_mark_ip_enable_disable (sw_if_index, enable);
74  break;
75  }
76 }
77 
80 {
81  ASSERT (vec_len (qos_mark_configs[output_source]) > sw_if_index);
82 
84  qos_mark_configs[output_source][sw_if_index]);
85 }
86 
87 /**
88  * per-packet trace data
89  */
90 typedef struct qos_mark_trace_t_
91 {
92  /* per-pkt trace data */
97 
98 static inline uword
100  vlib_node_runtime_t * node,
101  vlib_frame_t * frame, qos_source_t output_source, int is_ip6)
102 {
103  u32 n_left_from, *from, *to_next, next_index;
104 
105  next_index = 0;
106  n_left_from = frame->n_vectors;
107  from = vlib_frame_vector_args (frame);
108 
109  while (n_left_from > 0)
110  {
111  u32 n_left_to_next;
112 
113  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
114 
115  while (n_left_from > 0 && n_left_to_next > 0)
116  {
117  qos_source_t input_source0;
118  ethernet_vlan_header_t *vlan0;
119  u32 sw_if_index0, next0, bi0;
120  qos_egress_map_t *qem0;
121  ip4_header_t *ip4_0;
122  ip6_header_t *ip6_0;
123  vlib_buffer_t *b0;
124  qos_bits_t qos0;
125  u8 *mpls_bytes_0;
126  u8 eos0;
127 
128  next0 = 0;
129  bi0 = from[0];
130  to_next[0] = bi0;
131  from += 1;
132  to_next += 1;
133  n_left_from -= 1;
134  n_left_to_next -= 1;
135 
136  b0 = vlib_get_buffer (vm, bi0);
137  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
138  input_source0 = vnet_buffer2 (b0)->qos.source;
139 
140  qem0 = qos_egress_map_interface (sw_if_index0, output_source);
141  qos0 = qem0->qem_output[input_source0][vnet_buffer2 (b0)->qos.bits];
142 
143  if (PREDICT_TRUE (b0->flags & VNET_BUFFER_F_QOS_DATA_VALID))
144  {
145  /* there is a source of QoS recording for this packet */
146  if (QOS_SOURCE_IP == output_source)
147  {
148  if (is_ip6)
149  {
150  ip6_0 = (vlib_buffer_get_current (b0) +
151  vnet_buffer (b0)->ip.save_rewrite_length);
152 
154  }
155  else
156  {
157  ip4_0 = (vlib_buffer_get_current (b0) +
158  vnet_buffer (b0)->ip.save_rewrite_length);
159  if (PREDICT_FALSE (qos0 != ip4_0->tos))
160  {
161  ip4_0->tos = qos0;
162  ip4_0->checksum = ip4_header_checksum (ip4_0);
163  }
164  }
165  }
166  else if (QOS_SOURCE_MPLS == output_source)
167  {
168  mpls_bytes_0 = (vlib_buffer_get_current (b0) +
169  vnet_buffer (b0)->mpls.save_rewrite_length);
170 
171  /* apply to all the labels in the stack */
172  do
173  {
174  /* clear out the old COS bts */
175  mpls_bytes_0[2] &= 0xf1;
176  /* OR in 3 bits of the mapped value */
177  mpls_bytes_0[2] |= (qos0 & 0x7) << 1;
178  eos0 = mpls_bytes_0[2] & 0x1;
179  mpls_bytes_0 += 4;
180  }
181  while (!eos0);
182  }
183  else if (QOS_SOURCE_VLAN == output_source)
184  {
185  vlan0 = (vlib_buffer_get_current (b0) +
186  sizeof (ethernet_header_t));
187 
189  }
190  }
191  vnet_feature_next (&next0, b0);
192 
193  if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
194  {
195  qos_mark_trace_t *t =
196  vlib_add_trace (vm, node, b0, sizeof (*t));
197  t->bits = qos0;
198  t->input = input_source0;
199  t->used = (b0->flags & VNET_BUFFER_F_QOS_DATA_VALID);
200  }
201 
202  /* verify speculative enqueue, maybe switch current next frame */
203  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
204  to_next, n_left_to_next,
205  bi0, next0);
206  }
207 
208  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
209  }
210 
211  return frame->n_vectors;
212 }
213 
214 /* packet trace format function */
215 static u8 *
216 format_qos_mark_trace (u8 * s, va_list * args)
217 {
218  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
219  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
220  qos_mark_trace_t *t = va_arg (*args, qos_mark_trace_t *);
221 
222  s = format (s, "source:%U qos:%d used:%s",
223  format_qos_source, t->input, t->bits, (t->used ? "yes" : "no"));
224 
225  return s;
226 }
227 
228 static inline uword
230  vlib_frame_t * frame)
231 {
232  return (qos_mark_inline (vm, node, frame, QOS_SOURCE_IP, 0));
233 }
234 
235 static inline uword
237  vlib_frame_t * frame)
238 {
239  return (qos_mark_inline (vm, node, frame, QOS_SOURCE_IP, 1));
240 }
241 
242 static inline uword
244  vlib_frame_t * frame)
245 {
246  return (qos_mark_inline (vm, node, frame, QOS_SOURCE_MPLS, 0));
247 }
248 
249 static inline uword
251  vlib_frame_t * frame)
252 {
253  return (qos_mark_inline (vm, node, frame, QOS_SOURCE_VLAN, 0));
254 }
255 
256 static inline uword
258  vlib_frame_t * frame)
259 {
260  return (qos_mark_inline (vm, node, frame, QOS_SOURCE_VLAN, 0));
261 }
262 
263 static inline uword
265  vlib_frame_t * frame)
266 {
267  return (qos_mark_inline (vm, node, frame, QOS_SOURCE_VLAN, 0));
268 }
269 
270 /* *INDENT-OFF* */
272  .function = ip4_qos_mark,
273  .name = "ip4-qos-mark",
274  .vector_size = sizeof (u32),
275  .format_trace = format_qos_mark_trace,
276  .type = VLIB_NODE_TYPE_INTERNAL,
277 
278  .n_errors = 0,
279  .n_next_nodes = 1,
280 
281  .next_nodes = {
282  [0] = "ip4-drop",
283  },
284 };
285 
287 
289  .arc_name = "ip4-output",
290  .node_name = "ip4-qos-mark",
291 };
292 
294  .function = ip6_qos_mark,
295  .name = "ip6-qos-mark",
296  .vector_size = sizeof (u32),
297  .format_trace = format_qos_mark_trace,
298  .type = VLIB_NODE_TYPE_INTERNAL,
299 
300  .n_errors = 0,
301  .n_next_nodes = 1,
302 
303  .next_nodes = {
304  [0] = "ip6-drop",
305  },
306 };
307 
309 
311  .arc_name = "ip6-output",
312  .node_name = "ip6-qos-mark",
313 };
314 
316  .function = mpls_qos_mark,
317  .name = "mpls-qos-mark",
318  .vector_size = sizeof (u32),
319  .format_trace = format_qos_mark_trace,
320  .type = VLIB_NODE_TYPE_INTERNAL,
321 
322  .n_errors = 0,
323  .n_next_nodes = 1,
324 
325  .next_nodes = {
326  [0] = "mpls-drop",
327  },
328 };
329 
331 
333  .arc_name = "mpls-output",
334  .node_name = "mpls-qos-mark",
335 };
336 
338  .function = vlan_ip4_qos_mark,
339  .name = "vlan-ip4-qos-mark",
340  .vector_size = sizeof (u32),
341  .format_trace = format_qos_mark_trace,
342  .type = VLIB_NODE_TYPE_INTERNAL,
343 
344  .n_errors = 0,
345  .n_next_nodes = 1,
346 
347  .next_nodes = {
348  [0] = "error-drop",
349  },
350 };
351 
353 
355  .arc_name = "ip4-output",
356  .node_name = "vlan-ip4-qos-mark",
357  .runs_after = VNET_FEATURES ("ip4-qos-mark"),
358 };
359 
361  .function = vlan_ip6_qos_mark,
362  .name = "vlan-ip6-qos-mark",
363  .vector_size = sizeof (u32),
364  .format_trace = format_qos_mark_trace,
365  .type = VLIB_NODE_TYPE_INTERNAL,
366 
367  .n_errors = 0,
368  .n_next_nodes = 1,
369 
370  .next_nodes = {
371  [0] = "error-drop",
372  },
373 };
374 
376 
378  .arc_name = "ip6-output",
379  .node_name = "vlan-ip6-qos-mark",
380  .runs_after = VNET_FEATURES ("ip6-qos-mark"),
381 };
382 
384  .function = vlan_mpls_qos_mark,
385  .name = "vlan-mpls-qos-mark",
386  .vector_size = sizeof (u32),
387  .format_trace = format_qos_mark_trace,
388  .type = VLIB_NODE_TYPE_INTERNAL,
389 
390  .n_errors = 0,
391  .n_next_nodes = 1,
392 
393  .next_nodes = {
394  [0] = "error-drop",
395  },
396 };
397 
399 
401  .arc_name = "mpls-output",
402  .node_name = "vlan-mpls-qos-mark",
403  .runs_after = VNET_FEATURES ("mpls-qos-mark"),
404 };
405 /* *INDENT-ON* */
406 
407 int
409  qos_source_t output_source, qos_egress_map_id_t mid)
410 {
411  index_t qemi;
412 
414  sw_if_index, INDEX_INVALID);
415 
416  qemi = qos_egress_map_find (mid);
417 
418  if (INDEX_INVALID == qemi)
419  return VNET_API_ERROR_NO_SUCH_TABLE;
420 
421  if (INDEX_INVALID == qos_mark_configs[output_source][sw_if_index])
422  {
423  qos_egress_map_feature_config (sw_if_index, output_source, 1);
424  }
425 
426  qos_mark_configs[output_source][sw_if_index] = qemi;
427 
428  return (0);
429 }
430 
431 int
433 {
434  if (vec_len (qos_mark_configs[output_source]) <= sw_if_index)
435  return VNET_API_ERROR_NO_MATCHING_INTERFACE;
436  if (INDEX_INVALID == qos_mark_configs[output_source][sw_if_index])
437  return VNET_API_ERROR_VALUE_EXIST;
438 
439  if (INDEX_INVALID != qos_mark_configs[output_source][sw_if_index])
440  {
441  qos_egress_map_feature_config (sw_if_index, output_source, 0);
442  }
443 
444  qos_mark_configs[output_source][sw_if_index] = INDEX_INVALID;
445 
446  return (0);
447 }
448 
449 static clib_error_t *
452 {
453  qos_egress_map_id_t map_id;
454  u32 sw_if_index, qs;
455  vnet_main_t *vnm;
456  int rv, enable;
457 
458  vnm = vnet_get_main ();
459  map_id = ~0;
460  qs = 0xff;
461  enable = 1;
462 
464  {
465  if (unformat (input, "id %d", &map_id))
466  ;
467  else if (unformat (input, "disable"))
468  enable = 0;
469  else if (unformat (input, "%U", unformat_qos_source, &qs))
470  ;
471  else if (unformat (input, "%U",
472  unformat_vnet_sw_interface, vnm, &sw_if_index))
473  ;
474  else
475  break;
476  }
477 
478  if (~0 == sw_if_index)
479  return clib_error_return (0, "interface must be specified");
480  if (0xff == qs)
481  return clib_error_return (0, "output location must be specified");
482 
483  if (enable)
484  rv = qos_mark_enable (sw_if_index, qs, map_id);
485  else
486  rv = qos_mark_disable (sw_if_index, qs);
487 
488  if (0 == rv)
489  return (NULL);
490 
491  return clib_error_return (0, "Failed to map interface");
492 }
493 
494 /*?
495  * Apply a QoS egress mapping table to an interface for QoS marking packets
496  * at the given output protocol.
497  *
498  * @cliexpar
499  * @cliexcmd{qos egress interface GigEthernet0/9/0 id 0 output ip}
500  ?*/
501 /* *INDENT-OFF* */
502 VLIB_CLI_COMMAND (qos_egress_map_interface_command, static) = {
503  .path = "qos mark",
504  .short_help = "qos mark <SOURCE> <INTERFACE> id <MAP>",
505  .function = qos_mark_cli,
506  .is_mp_safe = 1,
507 };
508 /* *INDENT-ON* */
509 
510 /*
511  * fd.io coding-style-patch-verification: ON
512  *
513 * Local Variables:
514 * eval: (c-set-style "gnu")
515 * End:
516 *
517 */
static uword qos_mark_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, qos_source_t output_source, int is_ip6)
Definition: qos_mark.c:99
qos_egress_map_t * qem_pool
Pool from which to allocate table.
#define CLIB_UNUSED(x)
Definition: clib.h:82
vnet_main_t * vnet_get_main(void)
Definition: misc.c:47
index_t qos_egress_map_find(qos_egress_map_id_t mid)
Get the VPP QoS map index from the user&#39;s map-ID.
#define vnet_buffer2(b)
Definition: buffer.h:413
VLIB_NODE_FUNCTION_MULTIARCH(ip4_qos_mark_node, ip4_qos_mark)
#define PREDICT_TRUE(x)
Definition: clib.h:112
#define NULL
Definition: clib.h:58
u32 index_t
A Data-Path Object is an object that represents actions that are applied to packets are they are swit...
Definition: dpo.h:41
void qos_mark_vlan_enable_disable(u32 sw_if_index, u8 enable)
Definition: qos_mark.c:37
void qos_mark_ip_enable_disable(u32 sw_if_index, u8 enable)
Definition: qos_mark.c:28
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
unformat_function_t unformat_vnet_sw_interface
static uword ip6_qos_mark(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: qos_mark.c:236
unsigned char u8
Definition: types.h:56
int qos_mark_disable(u32 sw_if_index, qos_source_t output_source)
Definition: qos_mark.c:432
Some external source, e.g.
Definition: qos_types.h:35
u32 sw_if_index
Definition: vxlan_gbp.api:37
#define always_inline
Definition: clib.h:98
static_always_inline void ip6_set_traffic_class_network_order(ip6_header_t *ip6, u8 dscp)
Definition: ip6_packet.h:395
vlib_node_registration_t mpls_qos_mark_node
(constructor) VLIB_REGISTER_NODE (mpls_qos_mark_node)
Definition: qos_mark.c:315
#define clib_error_return(e, args...)
Definition: error.h:99
struct qos_mark_trace_t_ qos_mark_trace_t
per-packet trace data
vlib_node_registration_t vlan_ip6_qos_mark_node
(constructor) VLIB_REGISTER_NODE (vlan_ip6_qos_mark_node)
Definition: qos_mark.c:360
int qos_mark_enable(u32 sw_if_index, qos_source_t output_source, qos_egress_map_id_t mid)
enable QoS marking by associating a MAP with an interface.
Definition: qos_mark.c:408
unsigned int u32
Definition: types.h:88
u8 * format_qos_source(u8 *s, va_list *args)
format/unformat QoS source types
Definition: qos_types.c:27
vlib_node_registration_t vlan_mpls_qos_mark_node
(constructor) VLIB_REGISTER_NODE (vlan_mpls_qos_mark_node)
Definition: qos_mark.c:383
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:511
static uword vlan_mpls_qos_mark(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: qos_mark.c:250
static void ethernet_vlan_header_set_priority_net_order(ethernet_vlan_header_t *h, u8 prio)
Definition: packet.h:140
struct _unformat_input_t unformat_input_t
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:214
static qos_egress_map_t * qos_egress_map_interface(u32 sw_if_index, qos_source_t output_source)
Definition: qos_mark.c:79
#define PREDICT_FALSE(x)
Definition: clib.h:111
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Finish enqueueing one buffer forward in the graph.
Definition: buffer_node.h:218
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Get pointer to next frame vector data by (vlib_node_runtime_t, next_index).
Definition: node_funcs.h:368
qos_source_t input
Definition: qos_mark.c:94
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
#define UNFORMAT_END_OF_INPUT
Definition: format.h:144
u16 n_vectors
Definition: node.h:420
vlib_node_registration_t ip4_qos_mark_node
(constructor) VLIB_REGISTER_NODE (ip4_qos_mark_node)
Definition: qos_mark.c:271
vlib_main_t * vm
Definition: buffer.c:301
enum qos_source_t_ qos_source_t
QoS types.
static_always_inline void vnet_feature_next(u32 *next0, vlib_buffer_t *b0)
Definition: feature.h:295
static void qos_egress_map_feature_config(u32 sw_if_index, qos_source_t qs, u8 enable)
Definition: qos_mark.c:59
vlib_node_registration_t ip6_qos_mark_node
(constructor) VLIB_REGISTER_NODE (ip6_qos_mark_node)
Definition: qos_mark.c:293
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Release pointer to next frame vector data.
Definition: main.c:459
static u8 * format_qos_mark_trace(u8 *s, va_list *args)
Definition: qos_mark.c:216
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:155
For a given output source a table maps each value of every input source.
static uword ip4_qos_mark(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: qos_mark.c:229
index_t * qos_mark_configs[QOS_N_SOURCES]
per-interface vector of which MAP is used by which interface for each output source ...
Definition: qos_mark.c:25
#define ASSERT(truth)
per-packet trace data
Definition: qos_mark.c:90
vlib_node_registration_t vlan_ip4_qos_mark_node
(constructor) VLIB_REGISTER_NODE (vlan_ip4_qos_mark_node)
Definition: qos_mark.c:337
static uword vlan_ip6_qos_mark(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: qos_mark.c:264
static uword mpls_qos_mark(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: qos_mark.c:243
#define VNET_FEATURES(...)
Definition: feature.h:435
static void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace_funcs.h:57
Definition: defs.h:47
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
VNET_FEATURE_INIT(ip4_qos_mark_node, static)
#define INDEX_INVALID
Invalid index - used when no index is known blazoned capitals INVALID speak volumes where ~0 does not...
Definition: dpo.h:47
static uword vlan_ip4_qos_mark(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: qos_mark.c:257
u64 uword
Definition: types.h:112
qos_bits_t bits
Definition: qos_mark.c:93
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:274
#define vnet_buffer(b)
Definition: buffer.h:368
static clib_error_t * qos_mark_cli(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: qos_mark.c:450
#define vec_validate_init_empty(V, I, INIT)
Make sure vector is long enough for given index and initialize empty space (no header, unspecified alignment)
Definition: vec.h:488
void qos_mark_mpls_enable_disable(u32 sw_if_index, u8 enable)
Definition: qos_mark.c:52
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:117
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:62
uword unformat_qos_source(unformat_input_t *input, va_list *args)
Definition: qos_types.c:35
static u16 ip4_header_checksum(ip4_header_t *i)
Definition: ip4_packet.h:247
qos_bits_t qem_output[QOS_N_SOURCES][256]
The array of output mapped values; output = eq_qos[input-source][input-value].
u8 qos_bits_t
Type, er, safety for us water based entities.
Definition: qos_types.h:68
u32 qos_egress_map_id_t
A QOS egress map translates from the COS bits stored in the packet&#39;s meta-data into a per-protocol CO...
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:972
int vnet_feature_enable_disable(const char *arc_name, const char *node_name, u32 sw_if_index, int enable_disable, void *feature_config, u32 n_feature_config_bytes)
Definition: feature.c:274
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:170
#define QOS_N_SOURCES
The maximum number of sources.
Definition: qos_types.h:45