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