FD.io VPP  v18.07-rc0-415-g6c78436
Vector Packet Processing
qos_record.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/qos/qos_record.h>
17 #include <vnet/ip/ip.h>
18 #include <vnet/ip/ip6_to_ip4.h>
19 #include <vnet/feature/feature.h>
20 #include <vnet/qos/qos_types.h>
21 
22 /**
23  * Per-interface, per-protocol vector of feature on/off configurations
24  */
27 
28 static void
30  qos_source_t input_source, u8 enable)
31 {
32  switch (input_source)
33  {
34  case QOS_SOURCE_IP:
35  vnet_feature_enable_disable ("ip6-unicast", "ip6-qos-record",
36  sw_if_index, enable, NULL, 0);
37  vnet_feature_enable_disable ("ip6-multicast", "ip6-qos-record",
38  sw_if_index, enable, NULL, 0);
39  vnet_feature_enable_disable ("ip4-unicast", "ip4-qos-record",
40  sw_if_index, enable, NULL, 0);
41  vnet_feature_enable_disable ("ip4-multicast", "ip4-qos-record",
42  sw_if_index, enable, NULL, 0);
43  l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_L2_IP_QOS_RECORD,
44  enable);
45  break;
46  case QOS_SOURCE_MPLS:
47  case QOS_SOURCE_VLAN:
48  case QOS_SOURCE_EXT:
49  // not implemented yet
50  break;
51  }
52 }
53 
54 int
55 qos_record_enable (u32 sw_if_index, qos_source_t input_source)
56 {
57  vec_validate (qos_record_configs[input_source], sw_if_index);
58 
59  if (0 == qos_record_configs[input_source][sw_if_index])
60  {
61  qos_record_feature_config (sw_if_index, input_source, 1);
62  }
63 
64  qos_record_configs[input_source][sw_if_index]++;
65  return (0);
66 }
67 
68 int
69 qos_record_disable (u32 sw_if_index, qos_source_t input_source)
70 {
71  if (vec_len (qos_record_configs[input_source]) < sw_if_index)
72  return VNET_API_ERROR_NO_MATCHING_INTERFACE;
73 
74  if (0 == qos_record_configs[input_source][sw_if_index])
75  return VNET_API_ERROR_VALUE_EXIST;
76 
77  qos_record_configs[input_source][sw_if_index]--;
78 
79  if (0 == qos_record_configs[input_source][sw_if_index])
80  {
81  qos_record_feature_config (sw_if_index, input_source, 0);
82  }
83 
84  return (0);
85 }
86 
87 /*
88  * Disable recording feautre for all protocols when the interface
89  * is deleted
90  */
91 static clib_error_t *
93  u32 sw_if_index, u32 is_add)
94 {
95  if (!is_add)
96  {
97  qos_source_t qs;
98 
100  {
101  qos_record_disable (sw_if_index, qs);
102  }
103  }
104 
105  return (NULL);
106 }
107 
109 
110 /**
111  * per-packet trace data
112  */
113 typedef struct qos_record_trace_t_
114 {
115  /* per-pkt trace data */
118 
119 static inline uword
121  vlib_node_runtime_t * node,
122  vlib_frame_t * frame, int is_ip6, int is_l2)
123 {
124  u32 n_left_from, *from, *to_next, next_index;
125 
126  next_index = 0;
127  n_left_from = frame->n_vectors;
128  from = vlib_frame_vector_args (frame);
129 
130  while (n_left_from > 0)
131  {
132  u32 n_left_to_next;
133 
134  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
135 
136  while (n_left_from > 0 && n_left_to_next > 0)
137  {
138  ip4_header_t *ip4_0;
139  ip6_header_t *ip6_0;
140  vlib_buffer_t *b0;
141  u32 sw_if_index0, next0, bi0;
142  qos_bits_t qos0;
143  u8 l2_len;
144 
145  next0 = 0;
146  bi0 = from[0];
147  to_next[0] = bi0;
148  from += 1;
149  to_next += 1;
150  n_left_from -= 1;
151  n_left_to_next -= 1;
152 
153  b0 = vlib_get_buffer (vm, bi0);
154 
155  if (is_l2)
156  {
157  l2_len = vnet_buffer (b0)->l2.l2_len;
158  u8 *l3h;
159  u16 ethertype;
160 
161  vlib_buffer_advance (b0, l2_len);
162 
163  l3h = vlib_buffer_get_current (b0);
164  ethertype = clib_net_to_host_u16 (*(u16 *) (l3h - 2));
165 
166  if (ethertype == ETHERNET_TYPE_IP4)
167  is_ip6 = 0;
168  else if (ethertype == ETHERNET_TYPE_IP6)
169  is_ip6 = 1;
170  else
171  goto non_ip;
172  }
173 
174  if (is_ip6)
175  {
176  ip6_0 = vlib_buffer_get_current (b0);
177  qos0 = ip6_traffic_class_network_order (ip6_0);
178  }
179  else
180  {
181  ip4_0 = vlib_buffer_get_current (b0);
182  qos0 = ip4_0->tos;
183  }
184  vnet_buffer2 (b0)->qos.bits = qos0;
185  vnet_buffer2 (b0)->qos.source = QOS_SOURCE_IP;
186  b0->flags |= VNET_BUFFER_F_QOS_DATA_VALID;
187  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
188 
189  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
190  (b0->flags & VLIB_BUFFER_IS_TRACED)))
191  {
192  qos_record_trace_t *t =
193  vlib_add_trace (vm, node, b0, sizeof (*t));
194  t->bits = qos0;
195  }
196 
197  non_ip:
198  if (is_l2)
199  {
200  vlib_buffer_advance (b0, -l2_len);
201  next0 = vnet_l2_feature_next (b0,
203  L2INPUT_FEAT_L2_IP_QOS_RECORD);
204  }
205  else
206  vnet_feature_next (sw_if_index0, &next0, b0);
207 
208  /* verify speculative enqueue, maybe switch current next frame */
209  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
210  to_next, n_left_to_next,
211  bi0, next0);
212  }
213 
214  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
215  }
216 
217  return frame->n_vectors;
218 }
219 
220 /* packet trace format function */
221 static u8 *
222 format_qos_record_trace (u8 * s, va_list * args)
223 {
224  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
225  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
226  qos_record_trace_t *t = va_arg (*args, qos_record_trace_t *);
227 
228  s = format (s, "qos:%d", t->bits);
229 
230  return s;
231 }
232 
233 static inline uword
235  vlib_frame_t * frame)
236 {
237  return (qos_record_inline (vm, node, frame, 0, 0));
238 }
239 
240 static inline uword
242  vlib_frame_t * frame)
243 {
244  return (qos_record_inline (vm, node, frame, 1, 0));
245 }
246 
247 static inline uword
249  vlib_frame_t * frame)
250 {
251  return (qos_record_inline (vm, node, frame, 0, 1));
252 }
253 
254 /* *INDENT-OFF* */
256  .function = ip4_qos_record,
257  .name = "ip4-qos-record",
258  .vector_size = sizeof (u32),
259  .format_trace = format_qos_record_trace,
260  .type = VLIB_NODE_TYPE_INTERNAL,
261 
262  .n_errors = 0,
263  .n_next_nodes = 1,
264 
265  .next_nodes = {
266  [0] = "ip4-drop",
267  },
268 };
269 
271 
273  .arc_name = "ip4-unicast",
274  .node_name = "ip4-qos-record",
275 };
276 
278  .function = ip6_qos_record,
279  .name = "ip6-qos-record",
280  .vector_size = sizeof (u32),
281  .format_trace = format_qos_record_trace,
282  .type = VLIB_NODE_TYPE_INTERNAL,
283 
284  .n_errors = 0,
285  .n_next_nodes = 1,
286 
287  .next_nodes = {
288  [0] = "ip6-drop",
289  },
290 };
291 
293 
295  .arc_name = "ip6-unicast",
296  .node_name = "ip6-qos-record",
297 };
298 
300  .function = l2_ip_qos_record,
301  .name = "l2-ip-qos-record",
302  .vector_size = sizeof (u32),
303  .format_trace = format_qos_record_trace,
304  .type = VLIB_NODE_TYPE_INTERNAL,
305 
306  .n_errors = 0,
307  .n_next_nodes = 1,
308 
309  /* Consider adding error "no IP after L2, no recording" */
310  .next_nodes = {
311  [0] = "error-drop",
312  },
313 };
314 
316 /* *INDENT-ON* */
317 
318 clib_error_t *
320 {
321  /* Initialize the feature next-node indexes */
323  l2_ip_qos_record_node.index,
327  return 0;
328 }
329 
331 
332 static clib_error_t *
334  unformat_input_t * input, vlib_cli_command_t * cmd)
335 {
336  vnet_main_t *vnm = vnet_get_main ();
337  u32 sw_if_index, qs;
338  u8 enable;
339 
340  qs = 0xff;
341  enable = 1;
342  sw_if_index = ~0;
343 
345  {
346  if (unformat (input, "%U", unformat_vnet_sw_interface,
347  vnm, &sw_if_index))
348  ;
349  else if (unformat (input, "%U", unformat_qos_source, &qs))
350  ;
351  else if (unformat (input, "enable"))
352  enable = 1;
353  else if (unformat (input, "disable"))
354  enable = 0;
355  else
356  break;
357  }
358 
359  if (~0 == sw_if_index)
360  return clib_error_return (0, "interface must be specified");
361  if (0xff == qs)
362  return clib_error_return (0, "input location must be specified");
363 
364  if (enable)
365  qos_record_enable (sw_if_index, qs);
366  else
367  qos_record_disable (sw_if_index, qs);
368 
369  return (NULL);
370 }
371 
372 /*?
373  * Enable QoS bit recording on an interface using the packet's input DSCP bits
374  * Which input QoS bits to use are either; IP, MPLS or VLAN. If more than
375  * one protocol is chosen (which is foolish) the higer layers override the
376  * lower.
377  *
378  * @cliexpar
379  * @cliexcmd{qos record ip GigEthernet0/1/0}
380  ?*/
381 /* *INDENT-OFF* */
382 VLIB_CLI_COMMAND (qos_record_command, static) = {
383  .path = "qos record",
384  .short_help = "qos record <record-source> <INTERFACE> [disable]",
385  .function = qos_record_cli,
386  .is_mp_safe = 1,
387 };
388 /* *INDENT-ON* */
389 
390 
391 /*
392  * fd.io coding-style-patch-verification: ON
393  *
394  * Local Variables:
395  * eval: (c-set-style "gnu")
396  * End:
397  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:437
vlib_node_registration_t ip6_qos_record_node
(constructor) VLIB_REGISTER_NODE (ip6_qos_record_node)
Definition: qos_record.c:277
#define CLIB_UNUSED(x)
Definition: clib.h:79
static uword ip4_qos_record(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: qos_record.c:234
vnet_main_t * vnet_get_main(void)
Definition: misc.c:47
#define vnet_buffer2(b)
Definition: buffer.h:402
#define NULL
Definition: clib.h:55
VNET_SW_INTERFACE_ADD_DEL_FUNCTION(qos_record_ip_interface_add_del)
static u8 * qos_record_configs[QOS_N_SOURCES]
Per-interface, per-protocol vector of feature on/off configurations.
Definition: qos_record.c:25
clib_error_t * l2_ip_qos_init(vlib_main_t *vm)
Definition: qos_record.c:319
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
unformat_function_t unformat_vnet_sw_interface
unsigned char u8
Definition: types.h:56
static u32 vnet_l2_feature_next(vlib_buffer_t *b, u32 *next_nodes, u32 feat_bit)
Return the graph node index for the feature corresponding to the next set bit after clearing the curr...
Definition: feat_bitmap.h:94
Some external source, e.g.
Definition: qos_types.h:35
static clib_error_t * qos_record_cli(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: qos_record.c:333
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:156
static_always_inline u8 ip6_traffic_class_network_order(const ip6_header_t *ip6)
Definition: ip6_packet.h:357
#define clib_error_return(e, args...)
Definition: error.h:99
#define FOR_EACH_QOS_SOURCE(_src)
Definition: qos_types.h:54
unsigned int u32
Definition: types.h:88
struct qos_record_trace_t_ qos_record_trace_t
per-packet trace data
static clib_error_t * qos_record_ip_interface_add_del(vnet_main_t *vnm, u32 sw_if_index, u32 is_add)
Definition: qos_record.c:92
VLIB_NODE_FUNCTION_MULTIARCH(ip4_qos_record_node, ip4_qos_record)
static u32 l2_qos_input_next[QOS_N_SOURCES][32]
Definition: qos_record.c:26
struct _unformat_input_t unformat_input_t
unsigned short u16
Definition: types.h:57
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:202
#define PREDICT_FALSE(x)
Definition: clib.h:105
static void qos_record_feature_config(u32 sw_if_index, qos_source_t input_source, u8 enable)
Definition: qos_record.c:29
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
#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_main_t * vm
Definition: buffer.c:294
enum qos_source_t_ qos_source_t
QoS tyeps.
static void feat_bitmap_init_next_nodes(vlib_main_t *vm, u32 node_index, u32 num_features, char **feat_names, u32 *next_nodes)
Initialize the feature next-node indexes of a graph node.
Definition: feat_bitmap.h:43
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
char ** l2input_get_feat_names(void)
Return an array of strings containing graph node names of each feature.
Definition: l2_input.c:60
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:154
int qos_record_disable(u32 sw_if_index, qos_source_t input_source)
Definition: qos_record.c:69
static u8 * format_qos_record_trace(u8 *s, va_list *args)
Definition: qos_record.c:222
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:215
static uword ip6_qos_record(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: qos_record.c:241
IPv6 to IPv4 translation.
static uword qos_record_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, int is_ip6, int is_l2)
Definition: qos_record.c:120
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
u32 l2input_intf_bitmap_enable(u32 sw_if_index, u32 feature_bitmap, u32 enable)
Enable (or disable) the feature in the bitmap for the given interface.
Definition: l2_input.c:520
static vlib_node_registration_t l2_ip_qos_record_node
(constructor) VLIB_REGISTER_NODE (l2_ip_qos_record_node)
Definition: qos_record.c:299
static uword l2_ip_qos_record(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: qos_record.c:248
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
u64 uword
Definition: types.h:112
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
int qos_record_enable(u32 sw_if_index, qos_source_t input_source)
Definition: qos_record.c:55
per-packet trace data
Definition: qos_record.c:113
u16 flags
Copy of main node flags.
Definition: node.h:486
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:295
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
vlib_node_registration_t ip4_qos_record_node
(constructor) VLIB_REGISTER_NODE (ip4_qos_record_node)
Definition: qos_record.c:255
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
u8 qos_bits_t
Type, er, safety for us water based entities.
Definition: qos_types.h:68
VNET_FEATURE_INIT(ip4_qos_record_node, static)
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:972
Definition: defs.h:46
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