FD.io VPP  v18.07-rc0-415-g6c78436
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
28 qos_mark_ip_enable_disable (u32 sw_if_index, u8 enable)
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
37 qos_mark_vlan_enable_disable (u32 sw_if_index, u8 enable)
38 {
39  vnet_feature_enable_disable ("interface-output", "vlan-qos-mark",
40  sw_if_index, enable, NULL, 0);
41 }
42 
43 void
44 qos_mark_mpls_enable_disable (u32 sw_if_index, u8 enable)
45 {
46  vnet_feature_enable_disable ("mpls-output", "mpls-qos-mark",
47  sw_if_index, enable, NULL, 0);
48 }
49 
50 static void
52 {
53  switch (qs)
54  {
55  case QOS_SOURCE_EXT:
56  ASSERT (0);
57  break;
58  case QOS_SOURCE_VLAN:
59  qos_mark_vlan_enable_disable (sw_if_index, enable);
60  break;
61  case QOS_SOURCE_MPLS:
62  qos_mark_mpls_enable_disable (sw_if_index, enable);
63  break;
64  case QOS_SOURCE_IP:
65  qos_mark_ip_enable_disable (sw_if_index, enable);
66  break;
67  }
68 }
69 
71 qos_egress_map_interface (u32 sw_if_index, qos_source_t output_source)
72 {
73  ASSERT (vec_len (qos_mark_configs[output_source]) > sw_if_index);
74 
76  qos_mark_configs[output_source][sw_if_index]);
77 }
78 
79 /**
80  * per-packet trace data
81  */
82 typedef struct qos_mark_trace_t_
83 {
84  /* per-pkt trace data */
89 
90 static inline uword
92  vlib_node_runtime_t * node,
93  vlib_frame_t * frame, qos_source_t output_source, int is_ip6)
94 {
95  u32 n_left_from, *from, *to_next, next_index;
96 
97  next_index = 0;
98  n_left_from = frame->n_vectors;
99  from = vlib_frame_vector_args (frame);
100 
101  while (n_left_from > 0)
102  {
103  u32 n_left_to_next;
104 
105  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
106 
107  while (n_left_from > 0 && n_left_to_next > 0)
108  {
109  qos_source_t input_source0;
110  ethernet_vlan_header_t *vlan0;
111  u32 sw_if_index0, next0, bi0;
112  qos_egress_map_t *qem0;
113  ip4_header_t *ip4_0;
114  ip6_header_t *ip6_0;
115  vlib_buffer_t *b0;
116  qos_bits_t qos0;
117  u8 *mpls_bytes_0;
118  u8 eos0;
119 
120  next0 = 0;
121  bi0 = from[0];
122  to_next[0] = bi0;
123  from += 1;
124  to_next += 1;
125  n_left_from -= 1;
126  n_left_to_next -= 1;
127 
128  b0 = vlib_get_buffer (vm, bi0);
129  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
130  input_source0 = vnet_buffer2 (b0)->qos.source;
131 
132  qem0 = qos_egress_map_interface (sw_if_index0, output_source);
133  qos0 = qem0->qem_output[input_source0][vnet_buffer2 (b0)->qos.bits];
134 
135  if (PREDICT_TRUE (b0->flags & VNET_BUFFER_F_QOS_DATA_VALID))
136  {
137  /* there is a source of QoS recording for this packet */
138  if (QOS_SOURCE_IP == output_source)
139  {
140  if (is_ip6)
141  {
142  ip6_0 = (vlib_buffer_get_current (b0) +
143  vnet_buffer (b0)->ip.save_rewrite_length);
144 
146  }
147  else
148  {
149  ip4_0 = (vlib_buffer_get_current (b0) +
150  vnet_buffer (b0)->ip.save_rewrite_length);
151  if (PREDICT_FALSE (qos0 != ip4_0->tos))
152  {
153  ip4_0->tos = qos0;
154  ip4_0->checksum = ip4_header_checksum (ip4_0);
155  }
156  }
157  }
158  else if (QOS_SOURCE_MPLS == output_source)
159  {
160  mpls_bytes_0 = (vlib_buffer_get_current (b0) +
161  vnet_buffer (b0)->mpls.save_rewrite_length);
162 
163  /* apply to all the labels in the stack */
164  do
165  {
166  /* clear out the old COS bts */
167  mpls_bytes_0[2] &= 0xf1;
168  /* OR in 3 bits of the mapped value */
169  mpls_bytes_0[2] |= (qos0 & 0x7) << 1;
170  eos0 = mpls_bytes_0[2] & 0x1;
171  mpls_bytes_0 += 4;
172  }
173  while (!eos0);
174  }
175  else if (QOS_SOURCE_VLAN == output_source)
176  {
177  vlan0 = (vlib_buffer_get_current (b0) +
178  sizeof (ethernet_header_t));
179 
181  }
182  }
183  vnet_feature_next (sw_if_index0, &next0, b0);
184 
185  if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
186  {
187  qos_mark_trace_t *t =
188  vlib_add_trace (vm, node, b0, sizeof (*t));
189  t->bits = qos0;
190  t->input = input_source0;
191  t->used = (b0->flags & VNET_BUFFER_F_QOS_DATA_VALID);
192  }
193 
194  /* verify speculative enqueue, maybe switch current next frame */
195  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
196  to_next, n_left_to_next,
197  bi0, next0);
198  }
199 
200  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
201  }
202 
203  return frame->n_vectors;
204 }
205 
206 /* packet trace format function */
207 static u8 *
208 format_qos_mark_trace (u8 * s, va_list * args)
209 {
210  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
211  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
212  qos_mark_trace_t *t = va_arg (*args, qos_mark_trace_t *);
213 
214  s = format (s, "source:%U qos:%d used:%s",
215  format_qos_source, t->input, t->bits, (t->used ? "yes" : "no"));
216 
217  return s;
218 }
219 
220 static inline uword
222  vlib_frame_t * frame)
223 {
224  return (qos_mark_inline (vm, node, frame, QOS_SOURCE_IP, 0));
225 }
226 
227 static inline uword
229  vlib_frame_t * frame)
230 {
231  return (qos_mark_inline (vm, node, frame, QOS_SOURCE_IP, 1));
232 }
233 
234 static inline uword
236  vlib_frame_t * frame)
237 {
238  return (qos_mark_inline (vm, node, frame, QOS_SOURCE_MPLS, 0));
239 }
240 
241 static inline uword
243  vlib_frame_t * frame)
244 {
245  return (qos_mark_inline (vm, node, frame, QOS_SOURCE_VLAN, 0));
246 }
247 
248 /* *INDENT-OFF* */
250  .function = ip4_qos_mark,
251  .name = "ip4-qos-mark",
252  .vector_size = sizeof (u32),
253  .format_trace = format_qos_mark_trace,
254  .type = VLIB_NODE_TYPE_INTERNAL,
255 
256  .n_errors = 0,
257  .n_next_nodes = 1,
258 
259  .next_nodes = {
260  [0] = "ip4-drop",
261  },
262 };
263 
265 
267  .arc_name = "ip4-output",
268  .node_name = "ip4-qos-mark",
269 };
270 
272  .function = ip6_qos_mark,
273  .name = "ip6-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] = "ip6-drop",
283  },
284 };
285 
287 
289  .arc_name = "ip6-output",
290  .node_name = "ip6-qos-mark",
291 };
292 
294  .function = mpls_qos_mark,
295  .name = "mpls-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] = "mpls-drop",
305  },
306 };
307 
309 
311  .arc_name = "mpls-output",
312  .node_name = "mpls-qos-mark",
313 };
315  .function = vlan_qos_mark,
316  .name = "vlan-qos-mark",
317  .vector_size = sizeof (u32),
318  .format_trace = format_qos_mark_trace,
319  .type = VLIB_NODE_TYPE_INTERNAL,
320 
321  .n_errors = 0,
322  .n_next_nodes = 1,
323 
324  .next_nodes = {
325  [0] = "error-drop",
326  },
327 };
328 
330 
332  .arc_name = "interface-output",
333  .node_name = "vlan-qos-mark",
334 };
335 /* *INDENT-ON* */
336 
337 int
338 qos_mark_enable (u32 sw_if_index,
339  qos_source_t output_source, qos_egress_map_id_t mid)
340 {
341  index_t qemi;
342 
344  sw_if_index, INDEX_INVALID);
345 
346  qemi = qos_egress_map_find (mid);
347 
348  if (INDEX_INVALID == qemi)
349  return VNET_API_ERROR_NO_SUCH_TABLE;
350 
351  if (INDEX_INVALID == qos_mark_configs[output_source][sw_if_index])
352  {
353  qos_egress_map_feature_config (sw_if_index, output_source, 1);
354  }
355 
356  qos_mark_configs[output_source][sw_if_index] = qemi;
357 
358  return (0);
359 }
360 
361 int
362 qos_mark_disable (u32 sw_if_index, qos_source_t output_source)
363 {
364  if (vec_len (qos_mark_configs[output_source]) < sw_if_index)
365  return VNET_API_ERROR_NO_MATCHING_INTERFACE;
366  if (INDEX_INVALID == qos_mark_configs[output_source][sw_if_index])
367  return VNET_API_ERROR_VALUE_EXIST;
368 
369  if (INDEX_INVALID != qos_mark_configs[output_source][sw_if_index])
370  {
371  qos_egress_map_feature_config (sw_if_index, output_source, 0);
372  }
373 
374  qos_mark_configs[output_source][sw_if_index] = INDEX_INVALID;
375 
376  return (0);
377 }
378 
379 static clib_error_t *
382 {
383  qos_egress_map_id_t map_id;
384  u32 sw_if_index, qs;
385  vnet_main_t *vnm;
386  int rv, enable;
387 
388  vnm = vnet_get_main ();
389  map_id = ~0;
390  qs = 0xff;
391  enable = 1;
392 
394  {
395  if (unformat (input, "id %d", &map_id))
396  ;
397  else if (unformat (input, "disable"))
398  enable = 0;
399  else if (unformat (input, "%U", unformat_qos_source, &qs))
400  ;
401  else if (unformat (input, "%U",
402  unformat_vnet_sw_interface, vnm, &sw_if_index))
403  ;
404  else
405  break;
406  }
407 
408  if (~0 == sw_if_index)
409  return clib_error_return (0, "interface must be specified");
410  if (0xff == qs)
411  return clib_error_return (0, "output location must be specified");
412 
413  if (enable)
414  rv = qos_mark_enable (sw_if_index, qs, map_id);
415  else
416  rv = qos_mark_disable (sw_if_index, qs);
417 
418  if (0 == rv)
419  return (NULL);
420 
421  return clib_error_return (0, "Failed to map interface");
422 }
423 
424 /*?
425  * Apply a QoS egress mapping table to an interface for QoS marking packets
426  * at the given output protocol.
427  *
428  * @cliexpar
429  * @cliexcmd{qos egress interface GigEthernet0/9/0 id 0 output ip}
430  ?*/
431 /* *INDENT-OFF* */
432 VLIB_CLI_COMMAND (qos_egress_map_interface_command, static) = {
433  .path = "qos mark",
434  .short_help = "qos mark <SOURCE> <INTERFACE> id <MAP>",
435  .function = qos_mark_cli,
436  .is_mp_safe = 1,
437 };
438 /* *INDENT-ON* */
439 
440 /*
441  * fd.io coding-style-patch-verification: ON
442  *
443 * Local Variables:
444 * eval: (c-set-style "gnu")
445 * End:
446 *
447 */
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:91
qos_egress_map_t * qem_pool
Pool from which to allocate table.
#define CLIB_UNUSED(x)
Definition: clib.h:79
static uword vlan_qos_mark(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: qos_mark.c:242
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:402
VLIB_NODE_FUNCTION_MULTIARCH(ip4_qos_mark_node, ip4_qos_mark)
#define PREDICT_TRUE(x)
Definition: clib.h:106
vlib_node_registration_t vlan_qos_mark_node
(constructor) VLIB_REGISTER_NODE (vlan_qos_mark_node)
Definition: qos_mark.c:314
#define NULL
Definition: clib.h:55
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:228
unsigned char u8
Definition: types.h:56
int qos_mark_disable(u32 sw_if_index, qos_source_t output_source)
Definition: qos_mark.c:362
Some external source, e.g.
Definition: qos_types.h:35
#define always_inline
Definition: clib.h:92
static_always_inline void ip6_set_traffic_class_network_order(ip6_header_t *ip6, u8 dscp)
Definition: ip6_packet.h:364
vlib_node_registration_t mpls_qos_mark_node
(constructor) VLIB_REGISTER_NODE (mpls_qos_mark_node)
Definition: qos_mark.c:293
#define clib_error_return(e, args...)
Definition: error.h:99
struct qos_mark_trace_t_ qos_mark_trace_t
per-packet trace data
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:338
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
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:461
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:202
static qos_egress_map_t * qos_egress_map_interface(u32 sw_if_index, qos_source_t output_source)
Definition: qos_mark.c:71
#define PREDICT_FALSE(x)
Definition: clib.h:105
static_always_inline void vnet_feature_next(u32 sw_if_index, u32 *next0, vlib_buffer_t *b0)
Definition: feature.h:237
#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:364
qos_source_t input
Definition: qos_mark.c:86
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:153
#define UNFORMAT_END_OF_INPUT
Definition: format.h:143
u16 n_vectors
Definition: node.h:380
vlib_node_registration_t ip4_qos_mark_node
(constructor) VLIB_REGISTER_NODE (ip4_qos_mark_node)
Definition: qos_mark.c:249
vlib_main_t * vm
Definition: buffer.c:294
enum qos_source_t_ qos_source_t
QoS tyeps.
static void qos_egress_map_feature_config(u32 sw_if_index, qos_source_t qs, u8 enable)
Definition: qos_mark.c:51
vlib_node_registration_t ip6_qos_mark_node
(constructor) VLIB_REGISTER_NODE (ip6_qos_mark_node)
Definition: qos_mark.c:271
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:454
static u8 * format_qos_mark_trace(u8 *s, va_list *args)
Definition: qos_mark.c:208
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:154
For a given output source a table maps each value of every input sorce.
static uword ip4_qos_mark(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: qos_mark.c:221
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:82
static uword mpls_qos_mark(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: qos_mark.c:235
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:55
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
u64 uword
Definition: types.h:112
qos_bits_t bits
Definition: qos_mark.c:85
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:267
#define vnet_buffer(b)
Definition: buffer.h:360
static clib_error_t * qos_mark_cli(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: qos_mark.c:380
#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:486
void qos_mark_mpls_enable_disable(u32 sw_if_index, u8 enable)
Definition: qos_mark.c:44
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:111
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:57
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:244
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:233
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169
#define QOS_N_SOURCES
The maximum number of sources.
Definition: qos_types.h:45