ipsec: IPSec protection for multi-point tunnel interfaces
[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 /* *INDENT-OFF* */
226 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 VNET_FEATURE_INIT (ip4_qos_record_node, static) = {
241     .arc_name = "ip4-unicast",
242     .node_name = "ip4-qos-record",
243 };
244 VNET_FEATURE_INIT (ip4m_qos_record_node, static) = {
245     .arc_name = "ip4-multicast",
246     .node_name = "ip4-qos-record",
247 };
248
249 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 VNET_FEATURE_INIT (ip6_qos_record_node, static) = {
264     .arc_name = "ip6-unicast",
265     .node_name = "ip6-qos-record",
266 };
267 VNET_FEATURE_INIT (ip6m_qos_record_node, static) = {
268     .arc_name = "ip6-multicast",
269     .node_name = "ip6-qos-record",
270 };
271
272 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 VNET_FEATURE_INIT (mpls_qos_record_node, static) = {
287     .arc_name = "mpls-input",
288     .node_name = "mpls-qos-record",
289 };
290
291 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 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 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 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 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 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 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 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 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  */