octeon: add clear counters for port and queues
[vpp.git] / src / vnet / qos / qos_record_node.c
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 #include <vnet/l2/l2_input.h>
22 #include <vnet/l2/feat_bitmap.h>
23
24 extern u8 *qos_record_configs[QOS_N_SOURCES];
25 extern u32 l2_qos_input_next[QOS_N_SOURCES][32];
26
27 /**
28  * per-packet trace data
29  */
30 typedef struct qos_record_trace_t_
31 {
32   /* per-pkt trace data */
33   qos_bits_t bits;
34 } qos_record_trace_t;
35
36 /* packet trace format function */
37 static u8 *
38 format_qos_record_trace (u8 * s, va_list * args)
39 {
40   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
41   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
42   qos_record_trace_t *t = va_arg (*args, qos_record_trace_t *);
43
44   s = format (s, "qos:%d", t->bits);
45
46   return s;
47 }
48
49 static inline uword
50 qos_record_inline (vlib_main_t * vm,
51                    vlib_node_runtime_t * node,
52                    vlib_frame_t * frame,
53                    qos_source_t qos_src, dpo_proto_t dproto, int is_l2)
54 {
55   u32 n_left_from, *from, *to_next, next_index;
56
57   next_index = 0;
58   n_left_from = frame->n_vectors;
59   from = vlib_frame_vector_args (frame);
60
61   while (n_left_from > 0)
62     {
63       u32 n_left_to_next;
64
65       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
66
67       while (n_left_from > 0 && n_left_to_next > 0)
68         {
69           ip4_header_t *ip4_0;
70           ip6_header_t *ip6_0;
71           vlib_buffer_t *b0;
72           u32 next0, bi0;
73           qos_bits_t qos0;
74           u8 l2_len;
75
76           next0 = 0;
77           bi0 = from[0];
78           to_next[0] = bi0;
79           from += 1;
80           to_next += 1;
81           n_left_from -= 1;
82           n_left_to_next -= 1;
83
84           b0 = vlib_get_buffer (vm, bi0);
85
86           if (is_l2)
87             {
88               l2_len = vnet_buffer (b0)->l2.l2_len;
89               u8 *l3h;
90               u16 ethertype;
91
92               vlib_buffer_advance (b0, l2_len);
93
94               l3h = vlib_buffer_get_current (b0);
95               ethertype = clib_net_to_host_u16 (*(u16 *) (l3h - 2));
96
97               if (ethertype == ETHERNET_TYPE_IP4)
98                 dproto = DPO_PROTO_IP4;
99               else if (ethertype == ETHERNET_TYPE_IP6)
100                 dproto = DPO_PROTO_IP6;
101               else if (ethertype == ETHERNET_TYPE_MPLS)
102                 dproto = DPO_PROTO_MPLS;
103               else
104                 goto non_ip;
105             }
106
107           if (DPO_PROTO_IP6 == dproto)
108             {
109               ip6_0 = vlib_buffer_get_current (b0);
110               qos0 = ip6_traffic_class_network_order (ip6_0);
111             }
112           else if (DPO_PROTO_IP4 == dproto)
113             {
114               ip4_0 = vlib_buffer_get_current (b0);
115               qos0 = ip4_0->tos;
116             }
117           else if (DPO_PROTO_ETHERNET == dproto)
118             {
119               ethernet_vlan_header_t *vlan0;
120
121               vlan0 = (vlib_buffer_get_current (b0) -
122                        sizeof (ethernet_vlan_header_t));
123
124               qos0 = ethernet_vlan_header_get_priority_net_order (vlan0);
125             }
126           else if (DPO_PROTO_MPLS)
127             {
128               mpls_unicast_header_t *mh;
129
130               mh = vlib_buffer_get_current (b0);
131               qos0 = vnet_mpls_uc_get_exp (mh->label_exp_s_ttl);
132             }
133
134           vnet_buffer2 (b0)->qos.bits = qos0;
135           vnet_buffer2 (b0)->qos.source = qos_src;
136           b0->flags |= VNET_BUFFER_F_QOS_DATA_VALID;
137
138           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
139                              (b0->flags & VLIB_BUFFER_IS_TRACED)))
140             {
141               qos_record_trace_t *t =
142                 vlib_add_trace (vm, node, b0, sizeof (*t));
143               t->bits = qos0;
144             }
145
146         non_ip:
147           if (is_l2)
148             {
149               vlib_buffer_advance (b0, -l2_len);
150               next0 = vnet_l2_feature_next (b0,
151                                             l2_qos_input_next[qos_src],
152                                             L2INPUT_FEAT_L2_IP_QOS_RECORD);
153             }
154           else
155             vnet_feature_next (&next0, b0);
156
157           /* verify speculative enqueue, maybe switch current next frame */
158           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
159                                            to_next, n_left_to_next,
160                                            bi0, next0);
161         }
162
163       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
164     }
165
166   return frame->n_vectors;
167 }
168
169
170 VLIB_NODE_FN (ip4_qos_record_node) (vlib_main_t * vm,
171                                     vlib_node_runtime_t * node,
172                                     vlib_frame_t * frame)
173 {
174   return (qos_record_inline (vm, node, frame, QOS_SOURCE_IP,
175                              DPO_PROTO_IP4, 0));
176 }
177
178 VLIB_NODE_FN (ip6_qos_record_node) (vlib_main_t * vm,
179                                     vlib_node_runtime_t * node,
180                                     vlib_frame_t * frame)
181 {
182   return (qos_record_inline (vm, node, frame, QOS_SOURCE_IP,
183                              DPO_PROTO_IP6, 0));
184 }
185
186 VLIB_NODE_FN (mpls_qos_record_node) (vlib_main_t * vm,
187                                      vlib_node_runtime_t * node,
188                                      vlib_frame_t * frame)
189 {
190   return (qos_record_inline (vm, node, frame, QOS_SOURCE_MPLS,
191                              DPO_PROTO_MPLS, 0));
192 }
193
194 VLIB_NODE_FN (vlan_ip4_qos_record_node) (vlib_main_t * vm,
195                                          vlib_node_runtime_t * node,
196                                          vlib_frame_t * frame)
197 {
198   return (qos_record_inline (vm, node, frame, QOS_SOURCE_VLAN,
199                              DPO_PROTO_ETHERNET, 0));
200 }
201
202 VLIB_NODE_FN (vlan_ip6_qos_record_node) (vlib_main_t * vm,
203                                          vlib_node_runtime_t * node,
204                                          vlib_frame_t * frame)
205 {
206   return (qos_record_inline (vm, node, frame, QOS_SOURCE_VLAN,
207                              DPO_PROTO_ETHERNET, 0));
208 }
209
210 VLIB_NODE_FN (vlan_mpls_qos_record_node) (vlib_main_t * vm,
211                                           vlib_node_runtime_t * node,
212                                           vlib_frame_t * frame)
213 {
214   return (qos_record_inline (vm, node, frame, QOS_SOURCE_VLAN,
215                              DPO_PROTO_ETHERNET, 0));
216 }
217
218 VLIB_NODE_FN (l2_ip_qos_record_node) (vlib_main_t * vm,
219                                       vlib_node_runtime_t * node,
220                                       vlib_frame_t * frame)
221 {
222   return (qos_record_inline (vm, node, frame, QOS_SOURCE_VLAN, 0, 1));
223 }
224
225 VLIB_REGISTER_NODE (ip4_qos_record_node) = {
226   .name = "ip4-qos-record",
227   .vector_size = sizeof (u32),
228   .format_trace = format_qos_record_trace,
229   .type = VLIB_NODE_TYPE_INTERNAL,
230
231   .n_errors = 0,
232   .n_next_nodes = 1,
233
234   .next_nodes = {
235     [0] = "ip4-drop",
236   },
237 };
238
239 VNET_FEATURE_INIT (ip4_qos_record_node, static) = {
240     .arc_name = "ip4-unicast",
241     .node_name = "ip4-qos-record",
242 };
243 VNET_FEATURE_INIT (ip4m_qos_record_node, static) = {
244     .arc_name = "ip4-multicast",
245     .node_name = "ip4-qos-record",
246 };
247
248 VLIB_REGISTER_NODE (ip6_qos_record_node) = {
249   .name = "ip6-qos-record",
250   .vector_size = sizeof (u32),
251   .format_trace = format_qos_record_trace,
252   .type = VLIB_NODE_TYPE_INTERNAL,
253
254   .n_errors = 0,
255   .n_next_nodes = 1,
256
257   .next_nodes = {
258     [0] = "ip6-drop",
259   },
260 };
261
262 VNET_FEATURE_INIT (ip6_qos_record_node, static) = {
263     .arc_name = "ip6-unicast",
264     .node_name = "ip6-qos-record",
265 };
266 VNET_FEATURE_INIT (ip6m_qos_record_node, static) = {
267     .arc_name = "ip6-multicast",
268     .node_name = "ip6-qos-record",
269 };
270
271 VLIB_REGISTER_NODE (mpls_qos_record_node) = {
272   .name = "mpls-qos-record",
273   .vector_size = sizeof (u32),
274   .format_trace = format_qos_record_trace,
275   .type = VLIB_NODE_TYPE_INTERNAL,
276
277   .n_errors = 0,
278   .n_next_nodes = 1,
279
280   .next_nodes = {
281     [0] = "mpls-drop",
282   },
283 };
284
285 VNET_FEATURE_INIT (mpls_qos_record_node, static) = {
286     .arc_name = "mpls-input",
287     .node_name = "mpls-qos-record",
288 };
289
290 VLIB_REGISTER_NODE (vlan_mpls_qos_record_node) = {
291   .name = "vlan-mpls-qos-record",
292   .vector_size = sizeof (u32),
293   .format_trace = format_qos_record_trace,
294   .type = VLIB_NODE_TYPE_INTERNAL,
295
296   .n_errors = 0,
297   .n_next_nodes = 1,
298
299   .next_nodes = {
300     [0] = "mpls-drop",
301   },
302 };
303
304 VNET_FEATURE_INIT (vlan_mpls_qos_record_node, static) = {
305     .arc_name = "mpls-input",
306     .node_name = "vlan-mpls-qos-record",
307     .runs_before = VNET_FEATURES ("mpls-qos-record"),
308 };
309
310 VLIB_REGISTER_NODE (vlan_ip4_qos_record_node) = {
311   .name = "vlan-ip4-qos-record",
312   .vector_size = sizeof (u32),
313   .format_trace = format_qos_record_trace,
314   .type = VLIB_NODE_TYPE_INTERNAL,
315
316   .n_errors = 0,
317   .n_next_nodes = 1,
318
319   .next_nodes = {
320     [0] = "ip4-drop",
321   },
322 };
323
324 VNET_FEATURE_INIT (vlan_ip4_qos_record_node, static) = {
325     .arc_name = "ip4-unicast",
326     .node_name = "vlan-ip4-qos-record",
327     .runs_before = VNET_FEATURES ("ip4-qos-record"),
328 };
329 VNET_FEATURE_INIT (vlan_ip4m_qos_record_node, static) = {
330     .arc_name = "ip4-multicast",
331     .node_name = "vlan-ip4-qos-record",
332     .runs_before = VNET_FEATURES ("ip4-qos-record"),
333 };
334
335 VLIB_REGISTER_NODE (vlan_ip6_qos_record_node) = {
336   .name = "vlan-ip6-qos-record",
337   .vector_size = sizeof (u32),
338   .format_trace = format_qos_record_trace,
339   .type = VLIB_NODE_TYPE_INTERNAL,
340
341   .n_errors = 0,
342   .n_next_nodes = 1,
343
344   .next_nodes = {
345     [0] = "ip6-drop",
346   },
347 };
348
349 VNET_FEATURE_INIT (vlan_ip6_qos_record_node, static) = {
350     .arc_name = "ip6-unicast",
351     .node_name = "vlan-ip6-qos-record",
352     .runs_before = VNET_FEATURES ("ip6-qos-record"),
353 };
354 VNET_FEATURE_INIT (vlan_ip6m_qos_record_node, static) = {
355     .arc_name = "ip6-multicast",
356     .node_name = "vlan-ip6-qos-record",
357     .runs_before = VNET_FEATURES ("ip6-qos-record"),
358 };
359
360 VLIB_REGISTER_NODE (l2_ip_qos_record_node) = {
361   .name = "l2-ip-qos-record",
362   .vector_size = sizeof (u32),
363   .format_trace = format_qos_record_trace,
364   .type = VLIB_NODE_TYPE_INTERNAL,
365
366   .n_errors = 0,
367   .n_next_nodes = 1,
368
369   /* Consider adding error "no IP after L2, no recording" */
370   .next_nodes = {
371     [0] = "error-drop",
372   },
373 };
374
375 /*
376  * fd.io coding-style-patch-verification: ON
377  *
378  * Local Variables:
379  * eval: (c-set-style "gnu")
380  * End:
381  */