Line data Source code
1 : /*
2 : * Copyright (c) 2019 Arrcus Inc 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 : #include <vlib/vlib.h>
16 : #include <vnet/vnet.h>
17 : #include <vppinfra/error.h>
18 : #include <vppinfra/hash.h>
19 : #include <srv6-mobile/mobile.h>
20 :
21 : extern ip6_address_t sr_pr_encaps_src;
22 :
23 : typedef struct
24 : {
25 : ip6_address_t src, dst;
26 : ip6_address_t sr_prefix;
27 : u16 sr_prefixlen;
28 : u32 teid;
29 : } srv6_end_rewrite_trace_t;
30 :
31 : static u16 srh_tagfield[256] = {
32 : /* 0 */
33 : 0x0,
34 : /* 1 : Echo Request */
35 : 0x0004,
36 : /* 2 : Echo Reply */
37 : 0x0008,
38 : /* 3 - 7 */
39 : 0x0, 0x0, 0x0, 0x0, 0x0,
40 : /* 8 - 15 */
41 : 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
42 : /* 16 - 23 */
43 : 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
44 : /* 24 - 25 */
45 : 0x0, 0x0,
46 : /* 26 : Error Indication */
47 : 0x0002,
48 : /* 27 - 31 */
49 : 0x0, 0x0, 0x0, 0x0, 0x0,
50 : /* 32 - 247 */
51 : 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
52 : 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
53 : 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
54 : 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
55 : 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
56 : 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
57 : 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
58 : 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
59 : 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
60 : 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
61 : 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
62 : 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
63 : 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
64 : 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
65 : 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
66 : 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
67 : 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
68 : 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
69 : 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
70 : 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
71 : 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
72 : 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
73 : 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
74 : 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
75 : 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
76 : 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
77 : 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
78 : /* 248 - 253 */
79 : 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
80 : /* 254 : End Maker */
81 : 0x0001,
82 : /* 255 : G_PDU */
83 : 0x0
84 : };
85 :
86 : static u8 *
87 4 : format_srv6_end_rewrite_trace (u8 * s, va_list * args)
88 : {
89 4 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
90 4 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
91 4 : srv6_end_rewrite_trace_t *t = va_arg (*args, srv6_end_rewrite_trace_t *);
92 :
93 4 : return format (s, "SRv6-END-rewrite: src %U dst %U\n\tTEID: 0x%x",
94 : format_ip4_address, &t->src, format_ip4_address, &t->dst,
95 : clib_net_to_host_u32 (t->teid));
96 : }
97 :
98 : static u8 *
99 4 : format_srv6_end_rewrite_trace6 (u8 * s, va_list * args)
100 : {
101 4 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
102 4 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
103 4 : srv6_end_rewrite_trace_t *t = va_arg (*args, srv6_end_rewrite_trace_t *);
104 :
105 4 : return format (
106 : s, "SRv6-END-rewrite: src %U dst %U\n\tTEID: 0x%x\n\tsr_prefix: %U/%d",
107 : format_ip6_address, &t->src, format_ip6_address, &t->dst,
108 : clib_net_to_host_u32 (t->teid), format_ip6_address, &t->sr_prefix,
109 4 : t->sr_prefixlen);
110 : }
111 :
112 : #define foreach_srv6_end_v4_error \
113 : _(M_GTP4_E_PACKETS, "srv6 End.M.GTP4.E packets") \
114 : _(M_GTP4_E_BAD_PACKETS, "srv6 End.M.GTP4.E bad packets")
115 :
116 : #define foreach_srv6_t_v4_d_error \
117 : _(M_GTP4_D_PACKETS, "srv6 T.M.GTP4.D packets") \
118 : _(M_GTP4_D_BAD_PACKETS, "srv6 T.M.GTP4.D bad packets")
119 :
120 : #define foreach_srv6_end_v6_e_error \
121 : _(M_GTP6_E_PACKETS, "srv6 End.M.GTP6.E packets") \
122 : _(M_GTP6_E_BAD_PACKETS, "srv6 End.M.GTP6.E bad packets")
123 :
124 : #define foreach_srv6_end_v6_d_error \
125 : _(M_GTP6_D_PACKETS, "srv6 End.M.GTP6.D packets") \
126 : _(M_GTP6_D_BAD_PACKETS, "srv6 End.M.GTP6.D bad packets")
127 :
128 : #define foreach_srv6_end_v6_d_di_error \
129 : _(M_GTP6_D_DI_PACKETS, "srv6 End.M.GTP6.D.DI packets") \
130 : _(M_GTP6_D_DI_BAD_PACKETS, "srv6 End.M.GTP6.D.DI bad packets")
131 :
132 : #define foreach_srv6_end_v6_dt_error \
133 : _(M_GTP6_DT_PACKETS, "srv6 End.M.GTP6.DT packets") \
134 : _(M_GTP6_DT_BAD_PACKETS, "srv6 End.M.GTP6.DT bad packets")
135 :
136 : #define foreach_srv6_t_v4_dt_error \
137 : _(M_GTP4_DT_PACKETS, "srv6 T.M.GTP4.DT packets") \
138 : _(M_GTP4_DT_BAD_PACKETS, "srv6 T.M.GTP4.DT bad packets")
139 :
140 : typedef enum
141 : {
142 : #define _(sym,str) SRV6_END_ERROR_##sym,
143 : foreach_srv6_end_v4_error
144 : #undef _
145 : SRV6_END_N_V4_ERROR,
146 : } srv6_end_error_v4_t;
147 :
148 : typedef enum
149 : {
150 : #define _(sym,str) SRV6_T_ERROR_##sym,
151 : foreach_srv6_t_v4_d_error
152 : #undef _
153 : SRV6_T_N_V4_D_ERROR,
154 : } srv6_t_error_v4_d_t;
155 :
156 : typedef enum
157 : {
158 : #define _(sym,str) SRV6_END_ERROR_##sym,
159 : foreach_srv6_end_v6_e_error
160 : #undef _
161 : SRV6_END_N_V6_E_ERROR,
162 : } srv6_end_error_v6_e_t;
163 :
164 : typedef enum
165 : {
166 : #define _(sym,str) SRV6_END_ERROR_##sym,
167 : foreach_srv6_end_v6_d_error
168 : #undef _
169 : SRV6_END_N_V6_D_ERROR,
170 : } srv6_end_error_v6_d_t;
171 :
172 : typedef enum
173 : {
174 : #define _(sym,str) SRV6_END_ERROR_##sym,
175 : foreach_srv6_end_v6_d_di_error
176 : #undef _
177 : SRV6_END_N_V6_D_DI_ERROR,
178 : } srv6_end_error_v6_d_di_t;
179 :
180 : typedef enum
181 : {
182 : #define _(sym,str) SRV6_END_ERROR_##sym,
183 : foreach_srv6_end_v6_dt_error
184 : #undef _
185 : SRV6_END_N_V6_DT_ERROR,
186 : } srv6_end_error_v6_dt_t;
187 :
188 : typedef enum
189 : {
190 : #define _(sym,str) SRV6_T_ERROR_##sym,
191 : foreach_srv6_t_v4_dt_error
192 : #undef _
193 : SRV6_T_N_V4_DT_ERROR,
194 : } srv6_t_error_v4_dt_t;
195 :
196 : static char *srv6_end_error_v4_strings[] = {
197 : #define _(sym,string) string,
198 : foreach_srv6_end_v4_error
199 : #undef _
200 : };
201 :
202 : static char *srv6_t_error_v4_d_strings[] = {
203 : #define _(sym,string) string,
204 : foreach_srv6_t_v4_d_error
205 : #undef _
206 : };
207 :
208 : static char *srv6_end_error_v6_e_strings[] = {
209 : #define _(sym,string) string,
210 : foreach_srv6_end_v6_e_error
211 : #undef _
212 : };
213 :
214 : static char *srv6_end_error_v6_d_strings[] = {
215 : #define _(sym,string) string,
216 : foreach_srv6_end_v6_d_error
217 : #undef _
218 : };
219 :
220 : static char *srv6_end_error_v6_d_di_strings[] = {
221 : #define _(sym,string) string,
222 : foreach_srv6_end_v6_d_di_error
223 : #undef _
224 : };
225 :
226 : static char *srv6_end_error_v6_dt_strings[] = {
227 : #define _(sym,string) string,
228 : foreach_srv6_end_v6_dt_error
229 : #undef _
230 : };
231 :
232 : static char *srv6_t_error_v4_dt_strings[] = {
233 : #define _(sym,string) string,
234 : foreach_srv6_t_v4_dt_error
235 : #undef _
236 : };
237 :
238 : typedef enum
239 : {
240 : SRV6_END_M_GTP4_E_NEXT_DROP,
241 : SRV6_END_M_GTP4_E_NEXT_LOOKUP,
242 : SRV6_END_M_GTP4_E_N_NEXT,
243 : } srv6_end_m_gtp4_e_next_t;
244 :
245 : typedef enum
246 : {
247 : SRV6_T_M_GTP4_D_NEXT_DROP,
248 : SRV6_T_M_GTP4_D_NEXT_LOOKUP4,
249 : SRV6_T_M_GTP4_D_NEXT_LOOKUP6,
250 : SRV6_T_M_GTP4_D_N_NEXT,
251 : } srv6_T_m_gtp4_d_next_t;
252 :
253 : typedef enum
254 : {
255 : SRV6_END_M_GTP6_E_NEXT_DROP,
256 : SRV6_END_M_GTP6_E_NEXT_LOOKUP,
257 : SRV6_END_M_GTP6_E_N_NEXT,
258 : } srv6_end_m_gtp6_e_next_t;
259 :
260 : typedef enum
261 : {
262 : SRV6_END_M_GTP6_D_NEXT_DROP,
263 : SRV6_END_M_GTP6_D_NEXT_LOOKUP4,
264 : SRV6_END_M_GTP6_D_NEXT_LOOKUP6,
265 : SRV6_END_M_GTP6_D_N_NEXT,
266 : } srv6_end_m_gtp6_d_next_t;
267 :
268 : typedef enum
269 : {
270 : SRV6_END_M_GTP6_D_DI_NEXT_DROP,
271 : SRV6_END_M_GTP6_D_DI_NEXT_LOOKUP,
272 : SRV6_END_M_GTP6_D_DI_N_NEXT,
273 : } srv6_end_m_gtp6_d_di_next_t;
274 :
275 : typedef enum
276 : {
277 : SRV6_END_M_GTP6_DT_NEXT_DROP,
278 : SRV6_END_M_GTP6_DT_NEXT_LOOKUP4,
279 : SRV6_END_M_GTP6_DT_NEXT_LOOKUP6,
280 : SRV6_END_M_GTP6_DT_N_NEXT,
281 : } srv6_end_m_gtp6_dt_next_t;
282 :
283 : typedef enum
284 : {
285 : SRV6_T_M_GTP4_DT_NEXT_DROP,
286 : SRV6_T_M_GTP4_DT_NEXT_LOOKUP4,
287 : SRV6_T_M_GTP4_DT_NEXT_LOOKUP6,
288 : SRV6_T_M_GTP4_DT_N_NEXT,
289 : } srv6_t_m_gtp4_dt_next_t;
290 :
291 : static inline u16
292 4 : hash_uword_to_u16 (uword * key)
293 : {
294 : u16 *val;
295 4 : val = (u16 *) key;
296 : #if uword_bits == 64
297 4 : return val[0] ^ val[1] ^ val[2] ^ val[3];
298 : #else
299 : return val[0] ^ val[1];
300 : #endif
301 : }
302 :
303 : static inline u8
304 4 : gtpu_type_get (u16 tag)
305 : {
306 : u16 val;
307 :
308 4 : val = clib_net_to_host_u16 (tag);
309 4 : if (val & SRH_TAG_ECHO_REPLY)
310 0 : return GTPU_TYPE_ECHO_REPLY;
311 4 : else if (val & SRH_TAG_ECHO_REQUEST)
312 0 : return GTPU_TYPE_ECHO_REQUEST;
313 4 : else if (val & SRH_TAG_ERROR_INDICATION)
314 0 : return GTPU_TYPE_ERROR_INDICATION;
315 4 : else if (val & SRH_TAG_END_MARKER)
316 0 : return GTPU_TYPE_END_MARKER;
317 :
318 4 : return GTPU_TYPE_GTPU;
319 : }
320 :
321 : // Function for SRv6 GTP4.E function.
322 576 : VLIB_NODE_FN (srv6_end_m_gtp4_e)
323 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
324 : {
325 1 : srv6_end_main_v4_t *sm = &srv6_end_main_v4;
326 1 : ip6_sr_main_t *sm2 = &sr_main;
327 : u32 n_left_from, next_index, *from, *to_next;
328 1 : u32 thread_index = vm->thread_index;
329 :
330 1 : u32 good_n = 0, bad_n = 0;
331 :
332 1 : from = vlib_frame_vector_args (frame);
333 1 : n_left_from = frame->n_vectors;
334 1 : next_index = node->cached_next_index;
335 :
336 2 : while (n_left_from > 0)
337 : {
338 : u32 n_left_to_next;
339 :
340 1 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
341 :
342 3 : while (n_left_from > 0 && n_left_to_next > 0)
343 : {
344 : u32 bi0;
345 : vlib_buffer_t *b0;
346 : ip6_sr_localsid_t *ls0;
347 : srv6_end_gtp4_e_param_t *ls_param;
348 :
349 : ip6srv_combo_header_t *ip6srv0;
350 : ip6_address_t src0, dst0;
351 :
352 2 : ip4_gtpu_header_t *hdr0 = NULL;
353 : uword len0;
354 :
355 2 : u32 next0 = SRV6_END_M_GTP4_E_NEXT_LOOKUP;
356 :
357 : // defaults
358 2 : bi0 = from[0];
359 2 : to_next[0] = bi0;
360 2 : from += 1;
361 2 : to_next += 1;
362 2 : n_left_from -= 1;
363 2 : n_left_to_next -= 1;
364 :
365 2 : b0 = vlib_get_buffer (vm, bi0);
366 2 : ls0 = pool_elt_at_index (sm2->localsids,
367 : vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
368 :
369 2 : ls_param = (srv6_end_gtp4_e_param_t *) ls0->plugin_mem;
370 :
371 2 : ip6srv0 = vlib_buffer_get_current (b0);
372 2 : src0 = ip6srv0->ip.src_address;
373 2 : dst0 = ip6srv0->ip.dst_address;
374 :
375 2 : len0 = vlib_buffer_length_in_chain (vm, b0);
376 :
377 2 : if ((ip6srv0->ip.protocol == IPPROTO_IPV6_ROUTE &&
378 : len0 <
379 2 : sizeof (ip6srv_combo_header_t) + ip6srv0->sr.length * 8) ||
380 : (len0 < sizeof (ip6_header_t)))
381 : {
382 0 : next0 = SRV6_END_M_GTP4_E_NEXT_DROP;
383 :
384 0 : bad_n++;
385 : }
386 : else
387 : {
388 2 : u8 gtpu_type = 0;
389 2 : u16 tag = 0;
390 2 : u32 teid = 0;
391 2 : u8 *teid8p = (u8 *) &teid;
392 2 : u8 qfi = 0;
393 2 : u16 seq = 0;
394 : u32 index;
395 : u32 offset, shift;
396 2 : u32 hdrlen = 0;
397 : uword key;
398 : u16 port;
399 : ip4_address_t dst4;
400 2 : u16 ie_size = 0;
401 : u8 ie_buf[GTPU_IE_MAX_SIZ];
402 : void *p;
403 : uword plen;
404 :
405 2 : if (ip6srv0->ip.protocol == IPPROTO_IPV6_ROUTE)
406 : {
407 2 : tag = ip6srv0->sr.tag;
408 : }
409 :
410 2 : offset = ls0->localsid_prefix_len / 8;
411 2 : shift = ls0->localsid_prefix_len % 8;
412 :
413 2 : gtpu_type = gtpu_type_get (tag);
414 :
415 2 : if (PREDICT_TRUE (shift == 0))
416 : {
417 2 : clib_memcpy_fast (&dst4.as_u8[0], &dst0.as_u8[offset], 4);
418 :
419 2 : qfi = dst0.as_u8[offset + 4];
420 :
421 2 : if (gtpu_type == GTPU_TYPE_ECHO_REQUEST ||
422 2 : gtpu_type == GTPU_TYPE_ECHO_REPLY ||
423 : gtpu_type == GTPU_TYPE_ERROR_INDICATION)
424 : {
425 0 : clib_memcpy_fast (&seq, &dst0.as_u8[offset + 5], 2);
426 : }
427 : else
428 : {
429 2 : clib_memcpy_fast (teid8p, &dst0.as_u8[offset + 5], 4);
430 : }
431 : }
432 : else
433 : {
434 : u8 *sp;
435 :
436 0 : for (index = 0; index < 4; index++)
437 : {
438 0 : dst4.as_u8[index] = dst0.as_u8[offset + index] << shift;
439 0 : dst4.as_u8[index] |=
440 0 : dst0.as_u8[offset + index + 1] >> (8 - shift);
441 : }
442 :
443 0 : qfi |= dst0.as_u8[offset + 4] << shift;
444 0 : qfi |= dst0.as_u8[offset + 5] >> (8 - shift);
445 :
446 0 : if (gtpu_type == GTPU_TYPE_ECHO_REQUEST ||
447 0 : gtpu_type == GTPU_TYPE_ECHO_REPLY ||
448 : gtpu_type == GTPU_TYPE_ERROR_INDICATION)
449 : {
450 0 : sp = (u8 *) &seq;
451 0 : for (index = 0; index < 2; index++)
452 : {
453 0 : sp[index] = dst0.as_u8[offset + 5 + index] << shift;
454 0 : sp[index] |=
455 0 : dst0.as_u8[offset + 6 + index] >> (8 - shift);
456 : }
457 : }
458 : else
459 : {
460 0 : for (index = 0; index < 4; index++)
461 : {
462 0 : *teid8p = dst0.as_u8[offset + 5 + index] << shift;
463 0 : *teid8p |=
464 0 : dst0.as_u8[offset + 6 + index] >> (8 - shift);
465 0 : teid8p++;
466 : }
467 : }
468 : }
469 :
470 2 : if (qfi)
471 : {
472 2 : hdrlen =
473 : sizeof (gtpu_exthdr_t) + sizeof (gtpu_pdu_session_t);
474 : }
475 0 : else if (gtpu_type == GTPU_TYPE_ECHO_REQUEST ||
476 0 : gtpu_type == GTPU_TYPE_ECHO_REPLY ||
477 : gtpu_type == GTPU_TYPE_ERROR_INDICATION)
478 : {
479 0 : hdrlen = sizeof (gtpu_exthdr_t);
480 : }
481 :
482 2 : if (PREDICT_FALSE (gtpu_type == GTPU_TYPE_ECHO_REPLY))
483 : {
484 0 : hdrlen += sizeof (gtpu_recovery_ie);
485 : }
486 :
487 2 : if (PREDICT_FALSE (gtpu_type == GTPU_TYPE_ERROR_INDICATION))
488 : {
489 : ip6_sr_tlv_t *tlv;
490 : u16 ext_len;
491 :
492 0 : ext_len = ip6srv0->sr.length * 8;
493 :
494 0 : if (ext_len >
495 0 : sizeof (ip6_address_t) * (ip6srv0->sr.last_entry + 1))
496 : {
497 0 : tlv = (ip6_sr_tlv_t *) ((u8 *) &ip6srv0->sr +
498 0 : sizeof (ip6_sr_header_t) +
499 0 : sizeof (ip6_address_t) *
500 0 : (ip6srv0->sr.last_entry + 1));
501 :
502 0 : if (tlv->type == SRH_TLV_USER_PLANE_CONTAINER)
503 : {
504 : user_plane_sub_tlv_t *sub_tlv;
505 :
506 0 : sub_tlv = (user_plane_sub_tlv_t *) tlv->value;
507 :
508 0 : ie_size = sub_tlv->length;
509 0 : clib_memcpy_fast (ie_buf, sub_tlv->value, ie_size);
510 :
511 0 : hdrlen += ie_size;
512 : }
513 : }
514 : }
515 :
516 2 : if (ip6srv0->ip.protocol == IPPROTO_IPV6_ROUTE)
517 : {
518 2 : vlib_buffer_advance (b0,
519 : (word) sizeof (ip6srv_combo_header_t) +
520 2 : ip6srv0->sr.length * 8);
521 : }
522 : else
523 : {
524 0 : vlib_buffer_advance (b0, (word) sizeof (ip6_header_t));
525 : }
526 :
527 : // get length of encapsulated IPv6 packet (the remaining part)
528 2 : p = vlib_buffer_get_current (b0);
529 :
530 2 : plen = len0 = vlib_buffer_length_in_chain (vm, b0);
531 :
532 2 : len0 += hdrlen;
533 :
534 2 : hdrlen += sizeof (ip4_gtpu_header_t);
535 :
536 : // IPv4 GTP-U header creation.
537 2 : vlib_buffer_advance (b0, -(word) hdrlen);
538 :
539 2 : hdr0 = vlib_buffer_get_current (b0);
540 :
541 2 : clib_memcpy_fast (hdr0, &sm->cache_hdr,
542 : sizeof (ip4_gtpu_header_t));
543 :
544 2 : hdr0->ip4.dst_address.as_u32 = dst4.as_u32;
545 :
546 2 : hdr0->gtpu.teid = teid;
547 2 : hdr0->gtpu.length = clib_host_to_net_u16 (len0);
548 :
549 2 : hdr0->gtpu.type = gtpu_type;
550 :
551 2 : if (gtpu_type == GTPU_TYPE_ECHO_REPLY ||
552 2 : gtpu_type == GTPU_TYPE_ECHO_REQUEST ||
553 : gtpu_type == GTPU_TYPE_ERROR_INDICATION)
554 : {
555 0 : hdr0->gtpu.ver_flags |= GTPU_SEQ_FLAG;
556 0 : hdr0->gtpu.ext->seq = seq;
557 0 : hdr0->gtpu.ext->npdu_num = 0;
558 0 : hdr0->gtpu.ext->nextexthdr = 0;
559 :
560 0 : if (gtpu_type == GTPU_TYPE_ECHO_REPLY)
561 : {
562 : gtpu_recovery_ie *recovery;
563 :
564 0 : recovery =
565 0 : (gtpu_recovery_ie *) ((u8 *) hdr0 +
566 : (hdrlen -
567 : sizeof (gtpu_recovery_ie)));
568 0 : recovery->type = GTPU_RECOVERY_IE_TYPE;
569 0 : recovery->restart_counter = 0;
570 : }
571 0 : else if (gtpu_type == GTPU_TYPE_ERROR_INDICATION)
572 : {
573 0 : if (ie_size)
574 : {
575 : u8 *ie_ptr;
576 :
577 0 : ie_ptr = (u8 *) ((u8 *) hdr0 + (hdrlen - ie_size));
578 0 : clib_memcpy_fast (ie_ptr, ie_buf, ie_size);
579 : }
580 : }
581 : }
582 : else
583 : {
584 2 : if (qfi)
585 : {
586 2 : hdr0->gtpu.ext->seq = 0;
587 2 : hdr0->gtpu.ext->npdu_num = 0;
588 : }
589 : }
590 :
591 2 : if (qfi)
592 : {
593 2 : u8 type = 0;
594 : gtpu_pdu_session_t *sess;
595 :
596 2 : hdr0->gtpu.ver_flags |= GTPU_EXTHDR_FLAG;
597 :
598 2 : hdr0->gtpu.ext->nextexthdr = GTPU_EXTHDR_PDU_SESSION;
599 :
600 2 : type = qfi & SRV6_PDU_SESSION_U_BIT_MASK;
601 :
602 2 : qfi = ((qfi & SRV6_PDU_SESSION_QFI_MASK) >> 2) |
603 2 : ((qfi & SRV6_PDU_SESSION_R_BIT_MASK) << 5);
604 :
605 2 : sess = (gtpu_pdu_session_t *) (((char *) hdr0) +
606 : sizeof (ip4_gtpu_header_t) +
607 : sizeof (gtpu_exthdr_t));
608 2 : sess->exthdrlen = 1;
609 2 : sess->type = type;
610 2 : sess->spare = 0;
611 2 : sess->u.val = qfi;
612 2 : sess->nextexthdr = 0;
613 : }
614 :
615 2 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = ls_param->fib4_index;
616 :
617 2 : if (ls_param->v4src_position)
618 : {
619 2 : offset = ls_param->v4src_position / 8;
620 2 : shift = ls_param->v4src_position % 8;
621 :
622 2 : if (PREDICT_TRUE (shift == 0))
623 : {
624 10 : for (index = 0; index < 4; index++)
625 : {
626 8 : hdr0->ip4.src_address.as_u8[index] =
627 8 : src0.as_u8[offset + index];
628 : }
629 : }
630 : else
631 : {
632 0 : for (index = 0; index < 4; index++)
633 : {
634 0 : hdr0->ip4.src_address.as_u8[index] =
635 0 : src0.as_u8[offset + index] << shift;
636 0 : hdr0->ip4.src_address.as_u8[index] |=
637 0 : src0.as_u8[offset + index + 1] >> (8 - shift);
638 : }
639 : }
640 : }
641 : else
642 : {
643 0 : clib_memcpy_fast (&hdr0->ip4.src_address,
644 0 : &ls_param->v4src_addr, 4);
645 : }
646 :
647 2 : key = hash_memory (p, plen < 40 ? plen : 40, 0);
648 2 : port = hash_uword_to_u16 (&key);
649 2 : hdr0->udp.src_port = port;
650 :
651 4 : hdr0->udp.length = clib_host_to_net_u16 (
652 2 : len0 + sizeof (udp_header_t) + sizeof (gtpu_header_t));
653 :
654 2 : hdr0->ip4.length =
655 2 : clib_host_to_net_u16 (len0 + sizeof (ip4_gtpu_header_t));
656 :
657 2 : hdr0->ip4.checksum = ip4_header_checksum (&hdr0->ip4);
658 :
659 2 : good_n++;
660 :
661 2 : if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
662 2 : PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
663 : {
664 : srv6_end_rewrite_trace_t *tr =
665 2 : vlib_add_trace (vm, node, b0, sizeof (*tr));
666 2 : clib_memcpy (tr->src.as_u8, hdr0->ip4.src_address.as_u8,
667 : sizeof (hdr0->ip4.src_address.as_u8));
668 2 : clib_memcpy (tr->dst.as_u8, hdr0->ip4.dst_address.as_u8,
669 : sizeof (hdr0->ip4.dst_address.as_u8));
670 2 : tr->teid = hdr0->gtpu.teid;
671 : }
672 : }
673 :
674 4 : vlib_increment_combined_counter (
675 : ((next0 == SRV6_END_M_GTP4_E_NEXT_DROP) ?
676 : &(sm2->sr_ls_invalid_counters) :
677 : &(sm2->sr_ls_valid_counters)),
678 2 : thread_index, ls0 - sm2->localsids, 1,
679 : vlib_buffer_length_in_chain (vm, b0));
680 :
681 2 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
682 : n_left_to_next, bi0, next0);
683 : }
684 :
685 1 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
686 : }
687 :
688 1 : vlib_node_increment_counter (vm, sm->end_m_gtp4_e_node_index,
689 : SRV6_END_ERROR_M_GTP4_E_BAD_PACKETS, bad_n);
690 :
691 1 : vlib_node_increment_counter (vm, sm->end_m_gtp4_e_node_index,
692 : SRV6_END_ERROR_M_GTP4_E_PACKETS, good_n);
693 :
694 1 : return frame->n_vectors;
695 : }
696 :
697 : // Function for SRv6 GTP4.D function.
698 : static inline u32
699 2 : srv6_gtp4_decap_processing (vlib_main_t *vm, vlib_node_runtime_t *node,
700 : vlib_buffer_t *b0)
701 : {
702 2 : srv6_t_main_v4_decap_t *sm = &srv6_t_main_v4_decap;
703 2 : ip6_sr_main_t *sm2 = &sr_main;
704 :
705 : ip6_sr_sl_t *sl0;
706 : srv6_end_gtp4_d_param_t *ls_param;
707 : ip4_header_t *ip4;
708 :
709 : uword len0;
710 :
711 2 : u32 next0 = SRV6_T_M_GTP4_D_NEXT_LOOKUP6;
712 :
713 2 : sl0 = pool_elt_at_index (sm2->sid_lists,
714 : vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
715 :
716 2 : ls_param = (srv6_end_gtp4_d_param_t *) sl0->plugin_mem;
717 :
718 2 : len0 = vlib_buffer_length_in_chain (vm, b0);
719 :
720 2 : ip4 = vlib_buffer_get_current (b0);
721 :
722 2 : if (ip4->protocol != IP_PROTOCOL_UDP || len0 < sizeof (ip4_gtpu_header_t))
723 : {
724 0 : next0 = SRV6_T_M_GTP4_D_NEXT_DROP;
725 : }
726 : else
727 : {
728 : uword *p;
729 2 : ip6_sr_policy_t *sr_policy = NULL;
730 2 : ip6_sr_sl_t *sl = NULL;
731 : u32 *sl_index;
732 : u32 hdr_len;
733 :
734 : ip4_gtpu_header_t *hdr;
735 : ip4_address_t src, dst;
736 : u8 *srcp, *dstp;
737 2 : ip6_header_t *encap = NULL;
738 : ip6_address_t seg;
739 : ip6_address_t src6;
740 : u8 gtpu_type;
741 : u32 teid;
742 : u8 *teidp;
743 2 : u8 qfi = 0;
744 2 : u8 *qfip = NULL;
745 2 : u16 seq = 0;
746 : u8 *seqp;
747 : u32 offset, shift, index;
748 : ip6srv_combo_header_t *ip6srv;
749 2 : gtpu_pdu_session_t *sess = NULL;
750 2 : int ie_size = 0;
751 2 : u16 tlv_siz = 0;
752 : u8 ie_buf[GTPU_IE_MAX_SIZ];
753 :
754 : // Decap from GTP-U.
755 2 : hdr = (ip4_gtpu_header_t *) ip4;
756 :
757 2 : hdr_len = sizeof (ip4_gtpu_header_t);
758 :
759 2 : teid = hdr->gtpu.teid;
760 2 : teidp = (u8 *) &teid;
761 :
762 2 : seqp = (u8 *) &seq;
763 :
764 2 : gtpu_type = hdr->gtpu.type;
765 :
766 2 : if (hdr->gtpu.ver_flags & (GTPU_EXTHDR_FLAG | GTPU_SEQ_FLAG))
767 : {
768 : // Extention header.
769 0 : hdr_len += sizeof (gtpu_exthdr_t);
770 :
771 0 : seq = hdr->gtpu.ext->seq;
772 :
773 0 : if (hdr->gtpu.ext->nextexthdr == GTPU_EXTHDR_PDU_SESSION)
774 : {
775 : // PDU Session Container.
776 0 : sess = (gtpu_pdu_session_t *) (((char *) hdr) + hdr_len);
777 0 : qfi = sess->u.val & ~GTPU_PDU_SESSION_P_BIT_MASK;
778 0 : qfip = (u8 *) &qfi;
779 :
780 0 : hdr_len += sizeof (gtpu_pdu_session_t);
781 :
782 0 : if (sess->u.val & GTPU_PDU_SESSION_P_BIT_MASK)
783 : {
784 0 : hdr_len += sizeof (gtpu_paging_policy_t);
785 : }
786 : }
787 : }
788 :
789 2 : src = hdr->ip4.src_address;
790 2 : srcp = (u8 *) &src;
791 :
792 2 : dst = hdr->ip4.dst_address;
793 2 : dstp = (u8 *) &dst;
794 :
795 2 : seg = ls_param->sr_prefix;
796 :
797 2 : offset = ls_param->sr_prefixlen / 8;
798 2 : shift = ls_param->sr_prefixlen % 8;
799 :
800 2 : if (PREDICT_TRUE (shift == 0))
801 : {
802 2 : clib_memcpy_fast (&seg.as_u8[offset], dstp, 4);
803 :
804 2 : if (qfip)
805 : {
806 0 : qfi = ((qfi & GTPU_PDU_SESSION_QFI_MASK) << 2) |
807 0 : ((qfi & GTPU_PDU_SESSION_R_BIT_MASK) >> 5);
808 :
809 0 : if (sess->type)
810 : {
811 0 : qfi |= SRV6_PDU_SESSION_U_BIT_MASK;
812 : }
813 :
814 0 : seg.as_u8[offset + 4] = qfi;
815 : }
816 :
817 2 : if (gtpu_type == GTPU_TYPE_ECHO_REQUEST ||
818 2 : gtpu_type == GTPU_TYPE_ECHO_REPLY ||
819 : gtpu_type == GTPU_TYPE_ERROR_INDICATION)
820 : {
821 0 : clib_memcpy_fast (&seg.as_u8[offset + 5], seqp, 2);
822 : }
823 : else
824 : {
825 2 : clib_memcpy_fast (&seg.as_u8[offset + 5], teidp, 4);
826 : }
827 : }
828 : else
829 : {
830 0 : for (index = 0; index < 4; index++)
831 : {
832 0 : seg.as_u8[offset + index] |= dstp[index] >> shift;
833 0 : seg.as_u8[offset + index + 1] |= dstp[index] << (8 - shift);
834 : }
835 :
836 0 : if (qfip)
837 : {
838 0 : qfi = ((qfi & GTPU_PDU_SESSION_QFI_MASK) << 2) |
839 0 : ((qfi & GTPU_PDU_SESSION_R_BIT_MASK) >> 5);
840 :
841 0 : if (sess->type)
842 : {
843 0 : qfi |= SRV6_PDU_SESSION_U_BIT_MASK;
844 : }
845 :
846 0 : seg.as_u8[offset + 4] |= qfi >> shift;
847 0 : seg.as_u8[offset + 5] |= qfi << (8 - shift);
848 : }
849 :
850 0 : if (gtpu_type == GTPU_TYPE_ECHO_REQUEST ||
851 0 : gtpu_type == GTPU_TYPE_ECHO_REPLY ||
852 : gtpu_type == GTPU_TYPE_ERROR_INDICATION)
853 : {
854 0 : for (index = 0; index < 2; index++)
855 : {
856 0 : seg.as_u8[offset + 5 + index] |= seqp[index] >> shift;
857 0 : seg.as_u8[offset + 6 + index] |= seqp[index] << (8 - shift);
858 : }
859 : }
860 : else
861 : {
862 0 : for (index = 0; index < 4; index++)
863 : {
864 0 : seg.as_u8[offset + index + 5] |= teidp[index] >> shift;
865 0 : seg.as_u8[offset + index + 6] |= teidp[index] << (8 - shift);
866 : }
867 : }
868 : }
869 :
870 2 : if (PREDICT_FALSE (gtpu_type == GTPU_TYPE_ERROR_INDICATION))
871 : {
872 : u16 payload_len;
873 :
874 0 : payload_len = clib_net_to_host_u16 (hdr->gtpu.length);
875 0 : if (payload_len != 0)
876 : {
877 0 : ie_size = payload_len - (hdr_len - sizeof (ip4_gtpu_header_t));
878 0 : if (ie_size > 0)
879 : {
880 : u8 *ies;
881 :
882 0 : ies = (u8 *) ((u8 *) hdr + hdr_len);
883 0 : clib_memcpy_fast (ie_buf, ies, ie_size);
884 0 : hdr_len += ie_size;
885 : }
886 : }
887 : }
888 :
889 2 : src6 = ls_param->v6src_prefix;
890 :
891 2 : offset = ls_param->v6src_prefixlen / 8;
892 2 : shift = ls_param->v6src_prefixlen % 8;
893 :
894 2 : if (PREDICT_TRUE (shift == 0))
895 : {
896 2 : clib_memcpy_fast (&src6.as_u8[offset], srcp, 4);
897 : }
898 : else
899 : {
900 0 : for (index = 0; index < 4; index++)
901 : {
902 0 : src6.as_u8[offset + index] |= srcp[offset] >> shift;
903 0 : src6.as_u8[offset + index + 1] |= srcp[offset] << (8 - shift);
904 : }
905 : }
906 :
907 2 : vlib_buffer_advance (b0, (word) hdr_len);
908 :
909 : // Encap to SRv6.
910 2 : if (PREDICT_TRUE (gtpu_type == GTPU_TYPE_GTPU))
911 : {
912 2 : encap = vlib_buffer_get_current (b0);
913 : }
914 :
915 2 : len0 = vlib_buffer_length_in_chain (vm, b0);
916 :
917 2 : p = mhash_get (&sm2->sr_policies_index_hash, &ls_param->sr_prefix);
918 2 : if (p)
919 : {
920 2 : sr_policy = pool_elt_at_index (sm2->sr_policies, p[0]);
921 : }
922 :
923 2 : if (sr_policy)
924 : {
925 2 : vec_foreach (sl_index, sr_policy->segments_lists)
926 : {
927 2 : sl = pool_elt_at_index (sm2->sid_lists, *sl_index);
928 2 : if (sl != NULL)
929 2 : break;
930 : }
931 : }
932 :
933 2 : if (sl)
934 : {
935 2 : hdr_len = sizeof (ip6srv_combo_header_t);
936 2 : hdr_len += vec_len (sl->segments) * sizeof (ip6_address_t);
937 2 : hdr_len += sizeof (ip6_address_t);
938 : }
939 : else
940 : {
941 0 : hdr_len = sizeof (ip6_header_t);
942 :
943 0 : if (PREDICT_FALSE (gtpu_type != GTPU_TYPE_GTPU))
944 : {
945 0 : hdr_len += sizeof (ip6_sr_header_t);
946 0 : hdr_len += sizeof (ip6_address_t);
947 : }
948 : }
949 :
950 2 : if (ie_size)
951 : {
952 0 : tlv_siz =
953 0 : sizeof (ip6_sr_tlv_t) + sizeof (user_plane_sub_tlv_t) + ie_size;
954 :
955 0 : tlv_siz = (tlv_siz & ~0x07) + (tlv_siz & 0x07 ? 0x08 : 0x0);
956 0 : hdr_len += tlv_siz;
957 : }
958 :
959 2 : vlib_buffer_advance (b0, -(word) hdr_len);
960 2 : ip6srv = vlib_buffer_get_current (b0);
961 :
962 2 : if (sl)
963 : {
964 2 : clib_memcpy_fast (ip6srv, sl->rewrite, vec_len (sl->rewrite));
965 :
966 2 : if (vec_len (sl->segments) > 1)
967 : {
968 2 : ip6srv->sr.tag = clib_host_to_net_u16 (srh_tagfield[gtpu_type]);
969 :
970 2 : ip6srv->sr.segments_left += 1;
971 2 : ip6srv->sr.last_entry += 1;
972 :
973 2 : ip6srv->sr.length += sizeof (ip6_address_t) / 8;
974 2 : ip6srv->sr.segments[0] = seg;
975 :
976 0 : clib_memcpy_fast (&ip6srv->sr.segments[1],
977 2 : (u8 *) (sl->rewrite + sizeof (ip6_header_t) +
978 : sizeof (ip6_sr_header_t)),
979 2 : vec_len (sl->segments) *
980 : sizeof (ip6_address_t));
981 : }
982 : else
983 : {
984 0 : ip6srv->ip.protocol = IP_PROTOCOL_IPV6_ROUTE;
985 :
986 0 : ip6srv->sr.type = ROUTING_HEADER_TYPE_SR;
987 :
988 0 : ip6srv->sr.segments_left = 1;
989 0 : ip6srv->sr.last_entry = 0;
990 :
991 0 : ip6srv->sr.length =
992 : ((sizeof (ip6_sr_header_t) + sizeof (ip6_address_t)) / 8) - 1;
993 0 : ip6srv->sr.flags = 0;
994 :
995 0 : ip6srv->sr.tag = clib_host_to_net_u16 (srh_tagfield[gtpu_type]);
996 :
997 0 : ip6srv->sr.segments[0] = seg;
998 0 : if (vec_len (sl->segments))
999 : {
1000 0 : ip6srv->sr.segments[1] = sl->segments[0];
1001 0 : ip6srv->sr.length += sizeof (ip6_address_t) / 8;
1002 0 : ip6srv->sr.last_entry++;
1003 : }
1004 : }
1005 :
1006 2 : if (PREDICT_TRUE (encap != NULL))
1007 : {
1008 2 : if (ls_param->nhtype == SRV6_NHTYPE_NONE)
1009 : {
1010 0 : if ((clib_net_to_host_u32 (
1011 0 : encap->ip_version_traffic_class_and_flow_label) >>
1012 : 28) == 6)
1013 0 : ip6srv->sr.protocol = IP_PROTOCOL_IPV6;
1014 : else
1015 0 : ip6srv->sr.protocol = IP_PROTOCOL_IP_IN_IP;
1016 : }
1017 2 : else if (ls_param->nhtype == SRV6_NHTYPE_IPV4)
1018 : {
1019 0 : ip6srv->sr.protocol = IP_PROTOCOL_IP_IN_IP;
1020 0 : if ((clib_net_to_host_u32 (
1021 0 : encap->ip_version_traffic_class_and_flow_label) >>
1022 : 28) != 4)
1023 : {
1024 : // Bad encap packet.
1025 0 : next0 = SRV6_T_M_GTP4_D_NEXT_DROP;
1026 0 : goto DONE;
1027 : }
1028 : }
1029 2 : else if (ls_param->nhtype == SRV6_NHTYPE_IPV6)
1030 : {
1031 2 : ip6srv->sr.protocol = IP_PROTOCOL_IPV6;
1032 2 : if ((clib_net_to_host_u32 (
1033 2 : encap->ip_version_traffic_class_and_flow_label) >>
1034 : 28) != 6)
1035 : {
1036 : // Bad encap packet.
1037 0 : next0 = SRV6_T_M_GTP4_D_NEXT_DROP;
1038 0 : goto DONE;
1039 : }
1040 : }
1041 0 : else if (ls_param->nhtype == SRV6_NHTYPE_NON_IP)
1042 : {
1043 0 : ip6srv->sr.protocol = IP_PROTOCOL_IP6_ETHERNET;
1044 : }
1045 : }
1046 : else
1047 : {
1048 0 : ip6srv->sr.protocol = IP_PROTOCOL_IP6_ETHERNET;
1049 : }
1050 : }
1051 : else
1052 : {
1053 0 : clib_memcpy_fast (ip6srv, &sm->cache_hdr, sizeof (ip6_header_t));
1054 :
1055 0 : ip6srv->ip.dst_address = seg;
1056 :
1057 0 : if (PREDICT_FALSE (gtpu_type != GTPU_TYPE_GTPU))
1058 : {
1059 0 : ip6srv->ip.protocol = IP_PROTOCOL_IPV6_ROUTE;
1060 :
1061 0 : ip6srv->sr.protocol = IP_PROTOCOL_IP6_ETHERNET;
1062 :
1063 0 : ip6srv->sr.type = ROUTING_HEADER_TYPE_SR;
1064 :
1065 0 : ip6srv->sr.tag = clib_host_to_net_u16 (srh_tagfield[gtpu_type]);
1066 :
1067 0 : ip6srv->sr.segments_left = 0;
1068 0 : ip6srv->sr.last_entry = 0;
1069 :
1070 0 : ip6srv->sr.length = sizeof (ip6_address_t) / 8;
1071 0 : ip6srv->sr.segments[0] = seg;
1072 : }
1073 : else
1074 : {
1075 0 : if (ls_param->nhtype == SRV6_NHTYPE_NONE)
1076 : {
1077 0 : if ((clib_net_to_host_u32 (
1078 0 : encap->ip_version_traffic_class_and_flow_label) >>
1079 : 28) == 6)
1080 0 : ip6srv->ip.protocol = IP_PROTOCOL_IPV6;
1081 : else
1082 0 : ip6srv->ip.protocol = IP_PROTOCOL_IP_IN_IP;
1083 : }
1084 0 : else if (ls_param->nhtype == SRV6_NHTYPE_IPV4)
1085 : {
1086 0 : ip6srv->ip.protocol = IP_PROTOCOL_IP_IN_IP;
1087 0 : if ((clib_net_to_host_u32 (
1088 0 : encap->ip_version_traffic_class_and_flow_label) >>
1089 : 28) != 4)
1090 : {
1091 : // Bad encap packet.
1092 0 : next0 = SRV6_T_M_GTP4_D_NEXT_DROP;
1093 0 : goto DONE;
1094 : }
1095 : }
1096 0 : else if (ls_param->nhtype == SRV6_NHTYPE_IPV6)
1097 : {
1098 0 : ip6srv->ip.protocol = IP_PROTOCOL_IPV6;
1099 0 : if ((clib_net_to_host_u32 (
1100 0 : encap->ip_version_traffic_class_and_flow_label) >>
1101 : 28) != 6)
1102 : {
1103 : // Bad encap packet.
1104 0 : next0 = SRV6_T_M_GTP4_D_NEXT_DROP;
1105 0 : goto DONE;
1106 : }
1107 : }
1108 0 : else if (ls_param->nhtype == SRV6_NHTYPE_NON_IP)
1109 : {
1110 0 : ip6srv->ip.protocol = IP_PROTOCOL_IP6_ETHERNET;
1111 : }
1112 : }
1113 : }
1114 :
1115 2 : ip6srv->ip.src_address = src6;
1116 :
1117 2 : if (PREDICT_FALSE (ie_size))
1118 : {
1119 : ip6_sr_tlv_t *tlv;
1120 : user_plane_sub_tlv_t *sub_tlv;
1121 :
1122 0 : tlv = (ip6_sr_tlv_t *) ((u8 *) ip6srv + (hdr_len - tlv_siz));
1123 0 : tlv->type = SRH_TLV_USER_PLANE_CONTAINER;
1124 0 : tlv->length = (u8) (tlv_siz - sizeof (ip6_sr_tlv_t));
1125 0 : clib_memset (tlv->value, 0, tlv->length);
1126 :
1127 0 : sub_tlv = (user_plane_sub_tlv_t *) tlv->value;
1128 0 : sub_tlv->type = USER_PLANE_SUB_TLV_IE;
1129 0 : sub_tlv->length = (u8) ie_size;
1130 0 : clib_memcpy_fast (sub_tlv->value, ie_buf, ie_size);
1131 :
1132 0 : ip6srv->sr.length += (u8) (tlv_siz / 8);
1133 : }
1134 :
1135 2 : ip6srv->ip.payload_length =
1136 2 : clib_host_to_net_u16 (len0 + hdr_len - sizeof (ip6_header_t));
1137 :
1138 2 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = 0; /* default FIB */
1139 :
1140 2 : if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1141 2 : PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1142 : {
1143 : srv6_end_rewrite_trace_t *tr =
1144 2 : vlib_add_trace (vm, node, b0, sizeof (*tr));
1145 2 : clib_memcpy (tr->src.as_u8, ip6srv->ip.src_address.as_u8,
1146 : sizeof (tr->src.as_u8));
1147 2 : clib_memcpy (tr->dst.as_u8, ip6srv->ip.dst_address.as_u8,
1148 : sizeof (tr->dst.as_u8));
1149 : }
1150 : }
1151 :
1152 2 : DONE:
1153 2 : return next0;
1154 : }
1155 :
1156 576 : VLIB_NODE_FN (srv6_t_m_gtp4_d)
1157 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
1158 : {
1159 1 : srv6_t_main_v4_decap_t *sm = &srv6_t_main_v4_decap;
1160 1 : ip6_sr_main_t *sm2 = &sr_main;
1161 : u32 n_left_from, next_index, *from, *to_next;
1162 :
1163 : ip6_sr_sl_t *sl0;
1164 : srv6_end_gtp4_d_param_t *ls_param;
1165 :
1166 1 : u32 good_n = 0, bad_n = 0;
1167 :
1168 1 : from = vlib_frame_vector_args (frame);
1169 1 : n_left_from = frame->n_vectors;
1170 1 : next_index = node->cached_next_index;
1171 :
1172 2 : while (n_left_from > 0)
1173 : {
1174 : u32 n_left_to_next;
1175 :
1176 1 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1177 :
1178 3 : while (n_left_from > 0 && n_left_to_next > 0)
1179 : {
1180 : u32 bi0;
1181 : vlib_buffer_t *b0;
1182 :
1183 : u32 next0;
1184 :
1185 : ip4_gtpu_header_t *hdr;
1186 : u32 hdrlen;
1187 : u8 gtpu_type;
1188 : bool gtp4;
1189 : bool ipv4;
1190 :
1191 : // defaults
1192 2 : bi0 = from[0];
1193 2 : to_next[0] = bi0;
1194 2 : from += 1;
1195 2 : to_next += 1;
1196 2 : n_left_from -= 1;
1197 2 : n_left_to_next -= 1;
1198 :
1199 2 : b0 = vlib_get_buffer (vm, bi0);
1200 :
1201 2 : sl0 = pool_elt_at_index (sm2->sid_lists,
1202 : vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1203 :
1204 2 : ls_param = (srv6_end_gtp4_d_param_t *) sl0->plugin_mem;
1205 :
1206 2 : hdr = vlib_buffer_get_current (b0);
1207 2 : gtpu_type = hdr->gtpu.type;
1208 :
1209 2 : gtp4 = false;
1210 2 : ipv4 = true;
1211 :
1212 2 : if (PREDICT_FALSE (gtpu_type != GTPU_TYPE_GTPU || ls_param->drop_in))
1213 : {
1214 2 : gtp4 = true;
1215 : }
1216 : else
1217 : {
1218 : ip6_header_t *ip6;
1219 :
1220 0 : hdrlen = sizeof (ip4_gtpu_header_t);
1221 :
1222 0 : if (hdr->gtpu.ver_flags & (GTPU_EXTHDR_FLAG | GTPU_SEQ_FLAG))
1223 : {
1224 0 : hdrlen += sizeof (gtpu_exthdr_t);
1225 0 : if (hdr->gtpu.ext->nextexthdr == GTPU_EXTHDR_PDU_SESSION)
1226 : {
1227 : gtpu_pdu_session_t *sess;
1228 0 : sess = (gtpu_pdu_session_t *) (((char *) hdr) + hdrlen);
1229 0 : hdrlen += sizeof (gtpu_pdu_session_t);
1230 :
1231 0 : if (sess->u.val & GTPU_PDU_SESSION_P_BIT_MASK)
1232 : {
1233 0 : hdrlen += sizeof (gtpu_paging_policy_t);
1234 : }
1235 : }
1236 : }
1237 :
1238 0 : ip6 = (ip6_header_t *) (((char *) hdr) + hdrlen);
1239 0 : if ((clib_net_to_host_u32 (
1240 0 : ip6->ip_version_traffic_class_and_flow_label) >>
1241 : 28) == 6)
1242 : {
1243 0 : ipv4 = false;
1244 0 : if (((ip6->dst_address.as_u8[0] == 0xff) &&
1245 0 : (ip6->dst_address.as_u8[1] == 0x02)) ||
1246 0 : ((ip6->dst_address.as_u8[0] == 0xfe) &&
1247 0 : ((ip6->dst_address.as_u8[1] & 0xc0) == 0x80)))
1248 : {
1249 : // Inner desitnation is IPv6 link local
1250 0 : gtp4 = true;
1251 : }
1252 : }
1253 : }
1254 :
1255 2 : if (gtp4)
1256 : {
1257 2 : next0 = srv6_gtp4_decap_processing (vm, node, b0);
1258 2 : if (PREDICT_TRUE (next0 == SRV6_T_M_GTP4_D_NEXT_LOOKUP6))
1259 2 : good_n++;
1260 : else
1261 0 : bad_n++;
1262 : }
1263 : else
1264 : {
1265 : /* Strip off the outer header (IPv4 + GTP + UDP + IEs) */
1266 0 : vlib_buffer_advance (b0, (word) hdrlen);
1267 :
1268 0 : if (ipv4)
1269 : {
1270 0 : next0 = SRV6_T_M_GTP4_D_NEXT_LOOKUP4;
1271 0 : vnet_buffer (b0)->sw_if_index[VLIB_TX] =
1272 0 : ls_param->fib4_index;
1273 : }
1274 : else
1275 : {
1276 0 : next0 = SRV6_T_M_GTP4_D_NEXT_LOOKUP6;
1277 0 : vnet_buffer (b0)->sw_if_index[VLIB_TX] =
1278 0 : ls_param->fib6_index;
1279 : }
1280 : }
1281 :
1282 2 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1283 : n_left_to_next, bi0, next0);
1284 : }
1285 :
1286 1 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1287 : }
1288 :
1289 1 : vlib_node_increment_counter (vm, sm->t_m_gtp4_d_node_index,
1290 : SRV6_T_ERROR_M_GTP4_D_BAD_PACKETS, bad_n);
1291 :
1292 1 : vlib_node_increment_counter (vm, sm->t_m_gtp4_d_node_index,
1293 : SRV6_T_ERROR_M_GTP4_D_PACKETS, good_n);
1294 :
1295 1 : return frame->n_vectors;
1296 : }
1297 :
1298 32255 : VLIB_REGISTER_NODE (srv6_end_m_gtp4_e) =
1299 : {
1300 : .name = "srv6-end-m-gtp4-e",.vector_size = sizeof (u32),.format_trace =
1301 : format_srv6_end_rewrite_trace,.type = VLIB_NODE_TYPE_INTERNAL,.n_errors =
1302 : ARRAY_LEN (srv6_end_error_v4_strings),.error_strings =
1303 : srv6_end_error_v4_strings,.n_next_nodes =
1304 : SRV6_END_M_GTP4_E_N_NEXT,.next_nodes =
1305 : {
1306 : [SRV6_END_M_GTP4_E_NEXT_DROP] = "error-drop",
1307 : [SRV6_END_M_GTP4_E_NEXT_LOOKUP] = "ip4-lookup",}
1308 : ,};
1309 :
1310 32255 : VLIB_REGISTER_NODE (srv6_t_m_gtp4_d) =
1311 : {
1312 : .name = "srv6-t-m-gtp4-d",.vector_size = sizeof (u32),.format_trace =
1313 : format_srv6_end_rewrite_trace,.type = VLIB_NODE_TYPE_INTERNAL,.n_errors =
1314 : ARRAY_LEN (srv6_t_error_v4_d_strings),.error_strings =
1315 : srv6_t_error_v4_d_strings,.n_next_nodes =
1316 : SRV6_T_M_GTP4_D_N_NEXT,.next_nodes =
1317 : {
1318 : [SRV6_T_M_GTP4_D_NEXT_DROP] = "error-drop",
1319 : [SRV6_T_M_GTP4_D_NEXT_LOOKUP4] = "ip4-lookup",
1320 : [SRV6_T_M_GTP4_D_NEXT_LOOKUP6] = "ip6-lookup",}
1321 : ,};
1322 :
1323 : // Function for SRv6 GTP6.E function
1324 576 : VLIB_NODE_FN (srv6_end_m_gtp6_e)
1325 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
1326 : {
1327 1 : srv6_end_main_v6_t *sm = &srv6_end_main_v6;
1328 1 : ip6_sr_main_t *sm2 = &sr_main;
1329 : u32 n_left_from, next_index, *from, *to_next;
1330 1 : u32 thread_index = vm->thread_index;
1331 :
1332 1 : u32 good_n = 0, bad_n = 0;
1333 :
1334 1 : from = vlib_frame_vector_args (frame);
1335 1 : n_left_from = frame->n_vectors;
1336 1 : next_index = node->cached_next_index;
1337 :
1338 2 : while (n_left_from > 0)
1339 : {
1340 : u32 n_left_to_next;
1341 :
1342 1 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1343 :
1344 3 : while (n_left_from > 0 && n_left_to_next > 0)
1345 : {
1346 : u32 bi0;
1347 : vlib_buffer_t *b0;
1348 : ip6_sr_localsid_t *ls0;
1349 : srv6_end_gtp6_e_param_t *ls_param;
1350 :
1351 : ip6srv_combo_header_t *ip6srv0;
1352 : ip6_address_t dst0, src0, seg0;
1353 :
1354 2 : ip6_gtpu_header_t *hdr0 = NULL;
1355 : uword len0;
1356 : uword key;
1357 : u16 port;
1358 : u16 tag;
1359 : void *p;
1360 : uword plen;
1361 :
1362 2 : u32 next0 = SRV6_END_M_GTP6_E_NEXT_LOOKUP;
1363 :
1364 : // defaults
1365 2 : bi0 = from[0];
1366 2 : to_next[0] = bi0;
1367 2 : from += 1;
1368 2 : to_next += 1;
1369 2 : n_left_from -= 1;
1370 2 : n_left_to_next -= 1;
1371 :
1372 2 : b0 = vlib_get_buffer (vm, bi0);
1373 2 : ls0 = pool_elt_at_index (sm2->localsids,
1374 : vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1375 :
1376 2 : ls_param = (srv6_end_gtp6_e_param_t *) ls0->plugin_mem;
1377 :
1378 2 : ip6srv0 = vlib_buffer_get_current (b0);
1379 2 : dst0 = ip6srv0->ip.dst_address;
1380 2 : src0 = ip6srv0->ip.src_address;
1381 2 : seg0 = ip6srv0->sr.segments[0];
1382 :
1383 2 : tag = ip6srv0->sr.tag;
1384 :
1385 2 : len0 = vlib_buffer_length_in_chain (vm, b0);
1386 :
1387 2 : if ((ip6srv0->ip.protocol != IPPROTO_IPV6_ROUTE) ||
1388 2 : (len0 < sizeof (ip6srv_combo_header_t) + 8 * ip6srv0->sr.length))
1389 : {
1390 0 : next0 = SRV6_END_M_GTP6_E_NEXT_DROP;
1391 :
1392 0 : bad_n++;
1393 : }
1394 : else
1395 : {
1396 : // we need to be sure there is enough space before
1397 : // ip6srv0 header, there is some extra space
1398 : // in the pre_data area for this kind of
1399 : // logic
1400 :
1401 2 : u32 teid = 0;
1402 2 : u8 *teid8p = (u8 *) &teid;
1403 2 : u8 qfi = 0;
1404 2 : u16 seq = 0;
1405 2 : u8 gtpu_type = 0;
1406 : u16 index;
1407 : u16 offset, shift;
1408 2 : u32 hdrlen = 0;
1409 2 : u16 ie_size = 0;
1410 : u8 ie_buf[GTPU_IE_MAX_SIZ];
1411 :
1412 2 : index = ls0->localsid_prefix_len;
1413 2 : offset = index / 8;
1414 2 : shift = index % 8;
1415 :
1416 2 : gtpu_type = gtpu_type_get (tag);
1417 :
1418 2 : if (PREDICT_TRUE (shift == 0))
1419 : {
1420 2 : qfi = dst0.as_u8[offset];
1421 2 : if (gtpu_type == GTPU_TYPE_ECHO_REQUEST ||
1422 2 : gtpu_type == GTPU_TYPE_ECHO_REPLY ||
1423 : gtpu_type == GTPU_TYPE_ERROR_INDICATION)
1424 : {
1425 0 : clib_memcpy_fast (&seq, &dst0.as_u8[offset + 1], 2);
1426 : }
1427 : else
1428 : {
1429 2 : clib_memcpy_fast (teid8p, &dst0.as_u8[offset + 1], 4);
1430 : }
1431 : }
1432 : else
1433 : {
1434 : u8 *sp;
1435 :
1436 0 : qfi |= dst0.as_u8[offset] << shift;
1437 0 : qfi |= dst0.as_u8[offset + 1] >> (8 - shift);
1438 :
1439 0 : if (gtpu_type == GTPU_TYPE_ECHO_REQUEST ||
1440 0 : gtpu_type == GTPU_TYPE_ECHO_REPLY ||
1441 : gtpu_type == GTPU_TYPE_ERROR_INDICATION)
1442 : {
1443 0 : sp = (u8 *) &seq;
1444 0 : for (index = 0; index < 2; index++)
1445 : {
1446 0 : sp[index] = dst0.as_u8[offset + 1 + index] << shift;
1447 0 : sp[index] |=
1448 0 : dst0.as_u8[offset + index + 2] >> (8 - shift);
1449 : }
1450 : }
1451 : else
1452 : {
1453 0 : for (index = 0; index < 4; index++)
1454 : {
1455 0 : *teid8p = dst0.as_u8[offset + index + 1] << shift;
1456 0 : *teid8p |=
1457 0 : dst0.as_u8[offset + index + 2] >> (8 - shift);
1458 0 : teid8p++;
1459 : }
1460 : }
1461 : }
1462 :
1463 2 : if (qfi)
1464 : {
1465 0 : hdrlen =
1466 : sizeof (gtpu_exthdr_t) + sizeof (gtpu_pdu_session_t);
1467 : }
1468 2 : else if (gtpu_type == GTPU_TYPE_ECHO_REQUEST ||
1469 2 : gtpu_type == GTPU_TYPE_ECHO_REPLY ||
1470 : gtpu_type == GTPU_TYPE_ERROR_INDICATION)
1471 : {
1472 0 : hdrlen = sizeof (gtpu_exthdr_t);
1473 : }
1474 :
1475 2 : if (gtpu_type == GTPU_TYPE_ECHO_REPLY)
1476 : {
1477 0 : hdrlen += sizeof (gtpu_recovery_ie);
1478 : }
1479 :
1480 2 : if (PREDICT_FALSE (gtpu_type == GTPU_TYPE_ERROR_INDICATION))
1481 : {
1482 : ip6_sr_tlv_t *tlv;
1483 : u16 ext_len;
1484 :
1485 0 : ext_len = ip6srv0->sr.length * 8;
1486 :
1487 0 : if (ext_len >
1488 0 : sizeof (ip6_address_t) * (ip6srv0->sr.last_entry + 1))
1489 : {
1490 0 : tlv = (ip6_sr_tlv_t *) ((u8 *) &ip6srv0->sr +
1491 0 : sizeof (ip6_sr_header_t) +
1492 0 : sizeof (ip6_address_t) *
1493 0 : (ip6srv0->sr.last_entry + 1));
1494 :
1495 0 : if (tlv->type == SRH_TLV_USER_PLANE_CONTAINER)
1496 : {
1497 : user_plane_sub_tlv_t *sub_tlv;
1498 :
1499 0 : sub_tlv = (user_plane_sub_tlv_t *) tlv->value;
1500 :
1501 0 : ie_size = sub_tlv->length;
1502 0 : clib_memcpy_fast (ie_buf, sub_tlv->value, ie_size);
1503 :
1504 0 : hdrlen += ie_size;
1505 : }
1506 : }
1507 : }
1508 :
1509 2 : vlib_buffer_advance (b0, (word) sizeof (ip6srv_combo_header_t) +
1510 2 : ip6srv0->sr.length * 8);
1511 :
1512 : // get length of encapsulated IPv6 packet (the remaining part)
1513 2 : p = vlib_buffer_get_current (b0);
1514 :
1515 2 : plen = len0 = vlib_buffer_length_in_chain (vm, b0);
1516 :
1517 2 : len0 += hdrlen;
1518 :
1519 2 : hdrlen += sizeof (ip6_gtpu_header_t);
1520 :
1521 2 : vlib_buffer_advance (b0, -(word) hdrlen);
1522 :
1523 2 : hdr0 = vlib_buffer_get_current (b0);
1524 :
1525 2 : clib_memcpy_fast (hdr0, &sm->cache_hdr,
1526 : sizeof (ip6_gtpu_header_t));
1527 :
1528 2 : hdr0->gtpu.teid = teid;
1529 2 : hdr0->gtpu.length = clib_host_to_net_u16 (len0);
1530 :
1531 2 : hdr0->gtpu.type = gtpu_type;
1532 :
1533 2 : if (gtpu_type == GTPU_TYPE_ECHO_REQUEST ||
1534 2 : gtpu_type == GTPU_TYPE_ECHO_REPLY ||
1535 : gtpu_type == GTPU_TYPE_ERROR_INDICATION)
1536 : {
1537 0 : hdr0->gtpu.ver_flags |= GTPU_SEQ_FLAG;
1538 0 : hdr0->gtpu.ext->seq = seq;
1539 0 : hdr0->gtpu.ext->npdu_num = 0;
1540 0 : hdr0->gtpu.ext->nextexthdr = 0;
1541 :
1542 0 : if (gtpu_type == GTPU_TYPE_ECHO_REPLY)
1543 : {
1544 : gtpu_recovery_ie *recovery;
1545 :
1546 0 : recovery =
1547 0 : (gtpu_recovery_ie *) ((u8 *) hdr0 +
1548 : (hdrlen -
1549 : sizeof (gtpu_recovery_ie)));
1550 0 : recovery->type = GTPU_RECOVERY_IE_TYPE;
1551 0 : recovery->restart_counter = 0;
1552 : }
1553 0 : else if (gtpu_type == GTPU_TYPE_ERROR_INDICATION)
1554 : {
1555 0 : if (ie_size)
1556 : {
1557 : u8 *ie_ptr;
1558 :
1559 0 : ie_ptr = (u8 *) ((u8 *) hdr0 + (hdrlen - ie_size));
1560 0 : clib_memcpy_fast (ie_ptr, ie_buf, ie_size);
1561 : }
1562 : }
1563 : }
1564 : else
1565 : {
1566 2 : if (qfi)
1567 : {
1568 0 : hdr0->gtpu.ext->seq = 0;
1569 0 : hdr0->gtpu.ext->npdu_num = 0;
1570 : }
1571 : }
1572 :
1573 2 : if (qfi)
1574 : {
1575 0 : u8 type = 0;
1576 : gtpu_pdu_session_t *sess;
1577 :
1578 0 : hdr0->gtpu.ver_flags |= GTPU_EXTHDR_FLAG;
1579 :
1580 0 : hdr0->gtpu.ext->nextexthdr = GTPU_EXTHDR_PDU_SESSION;
1581 :
1582 0 : type = qfi & SRV6_PDU_SESSION_U_BIT_MASK;
1583 :
1584 0 : qfi = ((qfi & SRV6_PDU_SESSION_QFI_MASK) >> 2) |
1585 0 : ((qfi & SRV6_PDU_SESSION_R_BIT_MASK) << 5);
1586 :
1587 0 : sess = (gtpu_pdu_session_t *) (((char *) hdr0) +
1588 : sizeof (ip6_gtpu_header_t) +
1589 : sizeof (gtpu_exthdr_t));
1590 0 : sess->exthdrlen = 1;
1591 0 : sess->type = type;
1592 0 : sess->spare = 0;
1593 0 : sess->u.val = qfi;
1594 0 : sess->nextexthdr = 0;
1595 : }
1596 :
1597 4 : hdr0->udp.length = clib_host_to_net_u16 (
1598 2 : len0 + sizeof (udp_header_t) + sizeof (gtpu_header_t));
1599 :
1600 2 : clib_memcpy_fast (hdr0->ip6.src_address.as_u8, src0.as_u8,
1601 : sizeof (ip6_address_t));
1602 2 : clib_memcpy_fast (hdr0->ip6.dst_address.as_u8, &seg0.as_u8,
1603 : sizeof (ip6_address_t));
1604 :
1605 4 : hdr0->ip6.payload_length = clib_host_to_net_u16 (
1606 2 : len0 + sizeof (udp_header_t) + sizeof (gtpu_header_t));
1607 :
1608 : // UDP source port.
1609 2 : key = hash_memory (p, plen < 40 ? plen : 40, 0);
1610 2 : port = hash_uword_to_u16 (&key);
1611 2 : hdr0->udp.src_port = port;
1612 :
1613 2 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = ls_param->fib6_index;
1614 :
1615 2 : good_n++;
1616 :
1617 2 : if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1618 2 : PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1619 : {
1620 : srv6_end_rewrite_trace_t *tr =
1621 2 : vlib_add_trace (vm, node, b0, sizeof (*tr));
1622 2 : clib_memcpy (tr->src.as_u8, hdr0->ip6.src_address.as_u8,
1623 : sizeof (ip6_address_t));
1624 2 : clib_memcpy (tr->dst.as_u8, hdr0->ip6.dst_address.as_u8,
1625 : sizeof (ip6_address_t));
1626 2 : tr->teid = hdr0->gtpu.teid;
1627 : }
1628 : }
1629 :
1630 4 : vlib_increment_combined_counter (
1631 : ((next0 == SRV6_END_M_GTP6_E_NEXT_DROP) ?
1632 : &(sm2->sr_ls_invalid_counters) :
1633 : &(sm2->sr_ls_valid_counters)),
1634 2 : thread_index, ls0 - sm2->localsids, 1,
1635 : vlib_buffer_length_in_chain (vm, b0));
1636 :
1637 2 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1638 : n_left_to_next, bi0, next0);
1639 : }
1640 :
1641 1 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1642 : }
1643 :
1644 1 : vlib_node_increment_counter (vm, sm->end_m_gtp6_e_node_index,
1645 : SRV6_END_ERROR_M_GTP6_E_BAD_PACKETS, bad_n);
1646 :
1647 1 : vlib_node_increment_counter (vm, sm->end_m_gtp6_e_node_index,
1648 : SRV6_END_ERROR_M_GTP6_E_PACKETS, good_n);
1649 :
1650 1 : return frame->n_vectors;
1651 : }
1652 :
1653 : // Function for SRv6 GTP6.D function
1654 : static inline u32
1655 2 : srv6_gtp6_decap_processing (vlib_main_t *vm, vlib_node_runtime_t *node,
1656 : vlib_buffer_t *b0)
1657 : {
1658 2 : srv6_end_main_v6_decap_t *sm = &srv6_end_main_v6_decap;
1659 2 : ip6_sr_main_t *sm2 = &sr_main;
1660 :
1661 : ip6_sr_localsid_t *ls0;
1662 : srv6_end_gtp6_d_param_t *ls_param;
1663 :
1664 2 : ip6_gtpu_header_t *hdr0 = NULL;
1665 : uword len0;
1666 :
1667 : ip6_address_t seg0, src0, dst0;
1668 2 : u32 teid = 0;
1669 : u8 *teidp;
1670 2 : u8 gtpu_type = 0;
1671 : u8 qfi;
1672 2 : u8 *qfip = NULL;
1673 2 : u16 seq = 0;
1674 : u8 *seqp;
1675 : u32 offset, shift;
1676 : u32 hdrlen;
1677 2 : ip6_header_t *encap = NULL;
1678 2 : gtpu_pdu_session_t *sess = NULL;
1679 2 : int ie_size = 0;
1680 2 : u16 tlv_siz = 0;
1681 : u8 ie_buf[GTPU_IE_MAX_SIZ];
1682 :
1683 2 : u32 next0 = SRV6_END_M_GTP6_D_NEXT_LOOKUP6;
1684 :
1685 2 : ls0 = pool_elt_at_index (sm2->localsids,
1686 : vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1687 :
1688 2 : ls_param = (srv6_end_gtp6_d_param_t *) ls0->plugin_mem;
1689 :
1690 2 : hdr0 = vlib_buffer_get_current (b0);
1691 :
1692 2 : hdrlen = sizeof (ip6_gtpu_header_t);
1693 :
1694 2 : len0 = vlib_buffer_length_in_chain (vm, b0);
1695 :
1696 4 : if ((hdr0->ip6.protocol != IP_PROTOCOL_UDP) ||
1697 4 : (hdr0->udp.dst_port != clib_host_to_net_u16 (SRV6_GTP_UDP_DST_PORT)) ||
1698 : (len0 < sizeof (ip6_gtpu_header_t)))
1699 : {
1700 0 : next0 = SRV6_END_M_GTP6_D_NEXT_DROP;
1701 : }
1702 : else
1703 : {
1704 2 : seg0 = ls_param->sr_prefix;
1705 2 : src0 = hdr0->ip6.src_address;
1706 2 : dst0 = hdr0->ip6.dst_address;
1707 :
1708 2 : gtpu_type = hdr0->gtpu.type;
1709 :
1710 2 : teid = hdr0->gtpu.teid;
1711 2 : teidp = (u8 *) &teid;
1712 :
1713 2 : seqp = (u8 *) &seq;
1714 :
1715 2 : if (hdr0->gtpu.ver_flags & (GTPU_EXTHDR_FLAG | GTPU_SEQ_FLAG))
1716 : {
1717 : // Extention header.
1718 0 : hdrlen += sizeof (gtpu_exthdr_t);
1719 :
1720 0 : seq = hdr0->gtpu.ext->seq;
1721 :
1722 0 : if (hdr0->gtpu.ext->nextexthdr == GTPU_EXTHDR_PDU_SESSION)
1723 : {
1724 : // PDU Session Container.
1725 0 : sess = (gtpu_pdu_session_t *) (((char *) hdr0) +
1726 : sizeof (ip6_gtpu_header_t) +
1727 : sizeof (gtpu_exthdr_t));
1728 0 : qfi = sess->u.val & ~GTPU_PDU_SESSION_P_BIT_MASK;
1729 0 : qfip = (u8 *) &qfi;
1730 :
1731 0 : hdrlen += sizeof (gtpu_pdu_session_t);
1732 :
1733 0 : if (sess->u.val & GTPU_PDU_SESSION_P_BIT_MASK)
1734 : {
1735 0 : hdrlen += sizeof (gtpu_paging_policy_t);
1736 : }
1737 : }
1738 : }
1739 :
1740 2 : offset = ls_param->sr_prefixlen / 8;
1741 2 : shift = ls_param->sr_prefixlen % 8;
1742 :
1743 2 : if (PREDICT_TRUE (shift == 0))
1744 : {
1745 2 : if (qfip)
1746 : {
1747 0 : qfi = ((qfi & GTPU_PDU_SESSION_QFI_MASK) << 2) |
1748 0 : ((qfi & GTPU_PDU_SESSION_R_BIT_MASK) >> 5);
1749 :
1750 0 : if (sess->type)
1751 : {
1752 0 : qfi |= SRV6_PDU_SESSION_U_BIT_MASK;
1753 : }
1754 :
1755 0 : seg0.as_u8[offset] = qfi;
1756 : }
1757 :
1758 2 : if (gtpu_type == GTPU_TYPE_ECHO_REQUEST ||
1759 2 : gtpu_type == GTPU_TYPE_ECHO_REPLY ||
1760 : gtpu_type == GTPU_TYPE_ERROR_INDICATION)
1761 : {
1762 0 : clib_memcpy_fast (&seg0.as_u8[offset + 1], seqp, 2);
1763 : }
1764 : else
1765 : {
1766 2 : clib_memcpy_fast (&seg0.as_u8[offset + 1], teidp, 4);
1767 : }
1768 : }
1769 : else
1770 : {
1771 : int idx;
1772 :
1773 0 : if (qfip)
1774 : {
1775 0 : qfi = ((qfi & GTPU_PDU_SESSION_QFI_MASK) << 2) |
1776 0 : ((qfi & ~GTPU_PDU_SESSION_R_BIT_MASK) >> 5);
1777 :
1778 0 : if (sess->type)
1779 : {
1780 0 : qfi |= SRV6_PDU_SESSION_U_BIT_MASK;
1781 : }
1782 :
1783 0 : seg0.as_u8[offset] |= qfi >> shift;
1784 0 : seg0.as_u8[offset + 1] |= qfi << (8 - shift);
1785 : }
1786 :
1787 0 : if (gtpu_type == GTPU_TYPE_ECHO_REQUEST ||
1788 0 : gtpu_type == GTPU_TYPE_ECHO_REPLY ||
1789 : gtpu_type == GTPU_TYPE_ERROR_INDICATION)
1790 : {
1791 0 : for (idx = 0; idx < 2; idx++)
1792 : {
1793 0 : seg0.as_u8[offset + idx + 1] |= seqp[idx] >> shift;
1794 0 : seg0.as_u8[offset + idx + 2] |= seqp[idx] << (8 - shift);
1795 : }
1796 : }
1797 : else
1798 : {
1799 0 : for (idx = 0; idx < 4; idx++)
1800 : {
1801 0 : seg0.as_u8[offset + idx + 1] |= teidp[idx] >> shift;
1802 0 : seg0.as_u8[offset + idx + 2] |= teidp[idx] << (8 - shift);
1803 : }
1804 : }
1805 : }
1806 :
1807 2 : if (PREDICT_FALSE (gtpu_type == GTPU_TYPE_ERROR_INDICATION))
1808 : {
1809 : u16 payload_len;
1810 :
1811 0 : payload_len = clib_net_to_host_u16 (hdr0->gtpu.length);
1812 0 : if (payload_len != 0)
1813 : {
1814 0 : ie_size = payload_len - (hdrlen - sizeof (ip6_gtpu_header_t));
1815 0 : if (ie_size > 0)
1816 : {
1817 : u8 *ies;
1818 :
1819 0 : ies = (u8 *) ((u8 *) hdr0 + hdrlen);
1820 0 : clib_memcpy_fast (ie_buf, ies, ie_size);
1821 0 : hdrlen += ie_size;
1822 : }
1823 : }
1824 : }
1825 :
1826 : // jump over variable length data
1827 2 : vlib_buffer_advance (b0, (word) hdrlen);
1828 :
1829 : // get length of encapsulated IPv6 packet (the remaining part)
1830 2 : len0 = vlib_buffer_length_in_chain (vm, b0);
1831 :
1832 2 : if (PREDICT_TRUE (gtpu_type == GTPU_TYPE_GTPU))
1833 : {
1834 2 : encap = vlib_buffer_get_current (b0);
1835 : }
1836 :
1837 : uword *p;
1838 : ip6srv_combo_header_t *ip6srv;
1839 2 : ip6_sr_policy_t *sr_policy = NULL;
1840 2 : ip6_sr_sl_t *sl = NULL;
1841 : u32 *sl_index;
1842 : u32 hdr_len;
1843 :
1844 2 : p = mhash_get (&sm2->sr_policies_index_hash, &ls_param->sr_prefix);
1845 2 : if (p)
1846 : {
1847 2 : sr_policy = pool_elt_at_index (sm2->sr_policies, p[0]);
1848 : }
1849 :
1850 2 : if (sr_policy)
1851 : {
1852 2 : vec_foreach (sl_index, sr_policy->segments_lists)
1853 : {
1854 2 : sl = pool_elt_at_index (sm2->sid_lists, *sl_index);
1855 2 : if (sl != NULL)
1856 2 : break;
1857 : }
1858 : }
1859 :
1860 2 : if (sl)
1861 : {
1862 2 : hdr_len = sizeof (ip6srv_combo_header_t);
1863 2 : hdr_len += vec_len (sl->segments) * sizeof (ip6_address_t);
1864 2 : hdr_len += sizeof (ip6_address_t) * 2;
1865 : }
1866 : else
1867 : {
1868 0 : hdr_len = sizeof (ip6_header_t);
1869 0 : hdr_len += sizeof (ip6_sr_header_t);
1870 0 : hdr_len += sizeof (ip6_address_t) * 2;
1871 : }
1872 :
1873 2 : if (ie_size)
1874 : {
1875 0 : tlv_siz =
1876 0 : sizeof (ip6_sr_tlv_t) + sizeof (user_plane_sub_tlv_t) + ie_size;
1877 :
1878 0 : tlv_siz = (tlv_siz & ~0x07) + (tlv_siz & 0x07 ? 0x08 : 0x0);
1879 0 : hdr_len += tlv_siz;
1880 : }
1881 :
1882 : // jump back to data[0] or pre_data if required
1883 2 : vlib_buffer_advance (b0, -(word) hdr_len);
1884 :
1885 2 : ip6srv = vlib_buffer_get_current (b0);
1886 :
1887 2 : if (sl)
1888 : {
1889 2 : clib_memcpy_fast (ip6srv, sl->rewrite, vec_len (sl->rewrite));
1890 :
1891 2 : if (vec_len (sl->segments) > 1)
1892 : {
1893 2 : ip6srv->ip.src_address = src0;
1894 :
1895 2 : ip6srv->sr.tag = clib_host_to_net_u16 (srh_tagfield[gtpu_type]);
1896 :
1897 2 : ip6srv->sr.type = ROUTING_HEADER_TYPE_SR;
1898 2 : ip6srv->sr.segments_left += 2;
1899 2 : ip6srv->sr.last_entry += 2;
1900 :
1901 2 : ip6srv->sr.length += (sizeof (ip6_address_t) * 2) / 8;
1902 2 : ip6srv->sr.segments[0] = dst0;
1903 2 : ip6srv->sr.segments[1] = seg0;
1904 :
1905 0 : clib_memcpy_fast (&ip6srv->sr.segments[2],
1906 2 : (u8 *) (sl->rewrite + sizeof (ip6_header_t) +
1907 : sizeof (ip6_sr_header_t)),
1908 2 : vec_len (sl->segments) *
1909 : sizeof (ip6_address_t));
1910 : }
1911 : else
1912 : {
1913 0 : ip6srv->ip.src_address = src0;
1914 0 : ip6srv->ip.protocol = IP_PROTOCOL_IPV6_ROUTE;
1915 :
1916 0 : ip6srv->sr.type = ROUTING_HEADER_TYPE_SR;
1917 0 : ip6srv->sr.segments_left = 2;
1918 0 : ip6srv->sr.last_entry = 1;
1919 0 : ip6srv->sr.length = (sizeof (ip6_address_t) * 2) / 8;
1920 0 : ip6srv->sr.flags = 0;
1921 :
1922 0 : ip6srv->sr.tag = clib_host_to_net_u16 (srh_tagfield[gtpu_type]);
1923 :
1924 0 : ip6srv->sr.segments[0] = dst0;
1925 0 : ip6srv->sr.segments[1] = seg0;
1926 :
1927 0 : if (vec_len (sl->segments))
1928 : {
1929 0 : ip6srv->sr.segments[2] = sl->segments[0];
1930 0 : ip6srv->sr.last_entry++;
1931 0 : ip6srv->sr.length += sizeof (ip6_address_t) / 8;
1932 : }
1933 : }
1934 :
1935 2 : if (PREDICT_TRUE (encap != NULL))
1936 : {
1937 2 : if (ls_param->nhtype == SRV6_NHTYPE_NONE)
1938 : {
1939 2 : if ((clib_net_to_host_u32 (
1940 2 : encap->ip_version_traffic_class_and_flow_label) >>
1941 : 28) == 6)
1942 2 : ip6srv->sr.protocol = IP_PROTOCOL_IPV6;
1943 : else
1944 0 : ip6srv->sr.protocol = IP_PROTOCOL_IP_IN_IP;
1945 : }
1946 0 : else if (ls_param->nhtype == SRV6_NHTYPE_IPV4)
1947 : {
1948 0 : ip6srv->sr.protocol = IP_PROTOCOL_IP_IN_IP;
1949 0 : if ((clib_net_to_host_u32 (
1950 0 : encap->ip_version_traffic_class_and_flow_label) >>
1951 : 28) != 4)
1952 : {
1953 : // Bad encap packet.
1954 0 : next0 = SRV6_END_M_GTP6_D_NEXT_DROP;
1955 0 : goto DONE;
1956 : }
1957 : }
1958 0 : else if (ls_param->nhtype == SRV6_NHTYPE_IPV6)
1959 : {
1960 0 : ip6srv->sr.protocol = IP_PROTOCOL_IPV6;
1961 0 : if ((clib_net_to_host_u32 (
1962 0 : encap->ip_version_traffic_class_and_flow_label) >>
1963 : 28) != 6)
1964 : {
1965 : // Bad encap packet.
1966 0 : next0 = SRV6_END_M_GTP6_D_NEXT_DROP;
1967 0 : goto DONE;
1968 : }
1969 : }
1970 0 : else if (ls_param->nhtype == SRV6_NHTYPE_NON_IP)
1971 : {
1972 0 : ip6srv->sr.protocol = IP_PROTOCOL_IP6_ETHERNET;
1973 : }
1974 : }
1975 : else
1976 : {
1977 0 : ip6srv->sr.protocol = IP_PROTOCOL_IP6_ETHERNET;
1978 : }
1979 : }
1980 : else
1981 : {
1982 0 : clib_memcpy_fast (ip6srv, &sm->cache_hdr, sizeof (ip6_header_t));
1983 :
1984 0 : ip6srv->ip.src_address = src0;
1985 0 : ip6srv->ip.dst_address = seg0;
1986 :
1987 0 : ip6srv->ip.protocol = IP_PROTOCOL_IPV6_ROUTE;
1988 :
1989 0 : ip6srv->sr.type = ROUTING_HEADER_TYPE_SR;
1990 0 : ip6srv->sr.segments_left = 1;
1991 0 : ip6srv->sr.last_entry = 1;
1992 :
1993 0 : ip6srv->sr.length = (sizeof (ip6_address_t) * 2) / 8;
1994 0 : ip6srv->sr.segments[0] = dst0;
1995 0 : ip6srv->sr.segments[1] = seg0;
1996 :
1997 0 : if (PREDICT_FALSE (gtpu_type) != GTPU_TYPE_GTPU)
1998 : {
1999 0 : ip6srv->sr.protocol = IP_PROTOCOL_IP6_ETHERNET;
2000 0 : ip6srv->sr.tag = clib_host_to_net_u16 (srh_tagfield[gtpu_type]);
2001 : }
2002 : else
2003 : {
2004 0 : if (ls_param->nhtype == SRV6_NHTYPE_NONE)
2005 : {
2006 0 : if ((clib_net_to_host_u32 (
2007 0 : encap->ip_version_traffic_class_and_flow_label) >>
2008 : 28) != 6)
2009 0 : ip6srv->sr.protocol = IP_PROTOCOL_IP_IN_IP;
2010 : }
2011 0 : else if (ls_param->nhtype == SRV6_NHTYPE_IPV4)
2012 : {
2013 0 : ip6srv->sr.protocol = IP_PROTOCOL_IP_IN_IP;
2014 0 : if ((clib_net_to_host_u32 (
2015 0 : encap->ip_version_traffic_class_and_flow_label) >>
2016 : 28) != 4)
2017 : {
2018 : // Bad encap packet.
2019 0 : next0 = SRV6_END_M_GTP6_D_NEXT_DROP;
2020 0 : goto DONE;
2021 : }
2022 : }
2023 0 : else if (ls_param->nhtype == SRV6_NHTYPE_IPV6)
2024 : {
2025 0 : ip6srv->sr.protocol = IP_PROTOCOL_IPV6;
2026 0 : if ((clib_net_to_host_u32 (
2027 0 : encap->ip_version_traffic_class_and_flow_label) >>
2028 : 28) != 6)
2029 : {
2030 : // Bad encap packet.
2031 0 : next0 = SRV6_END_M_GTP6_D_NEXT_DROP;
2032 0 : goto DONE;
2033 : }
2034 : }
2035 0 : else if (ls_param->nhtype == SRV6_NHTYPE_NON_IP)
2036 : {
2037 0 : ip6srv->sr.protocol = IP_PROTOCOL_IP6_ETHERNET;
2038 : }
2039 : }
2040 : }
2041 :
2042 2 : if (PREDICT_FALSE (ie_size))
2043 : {
2044 : ip6_sr_tlv_t *tlv;
2045 : user_plane_sub_tlv_t *sub_tlv;
2046 :
2047 0 : tlv = (ip6_sr_tlv_t *) ((u8 *) ip6srv + (hdr_len - tlv_siz));
2048 0 : tlv->type = SRH_TLV_USER_PLANE_CONTAINER;
2049 0 : tlv->length = (u8) (tlv_siz - sizeof (ip6_sr_tlv_t));
2050 0 : clib_memset (tlv->value, 0, tlv->length);
2051 :
2052 0 : sub_tlv = (user_plane_sub_tlv_t *) tlv->value;
2053 0 : sub_tlv->type = USER_PLANE_SUB_TLV_IE;
2054 0 : sub_tlv->length = (u8) ie_size;
2055 0 : clib_memcpy_fast (sub_tlv->value, ie_buf, ie_size);
2056 :
2057 0 : ip6srv->sr.length += (u8) (tlv_siz / 8);
2058 : }
2059 :
2060 2 : ip6srv->ip.payload_length =
2061 2 : clib_host_to_net_u16 (len0 + hdr_len - sizeof (ip6_header_t));
2062 :
2063 2 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = 0; /* default FIB */
2064 :
2065 2 : if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2066 2 : PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2067 : {
2068 : srv6_end_rewrite_trace_t *tr =
2069 2 : vlib_add_trace (vm, node, b0, sizeof (*tr));
2070 2 : clib_memcpy (tr->src.as_u8, ip6srv->ip.src_address.as_u8,
2071 : sizeof (ip6_address_t));
2072 2 : clib_memcpy (tr->dst.as_u8, ip6srv->ip.dst_address.as_u8,
2073 : sizeof (ip6_address_t));
2074 2 : tr->teid = teid;
2075 2 : clib_memcpy (tr->sr_prefix.as_u8, ls_param->sr_prefix.as_u8,
2076 : sizeof (ip6_address_t));
2077 2 : tr->sr_prefixlen = ls_param->sr_prefixlen;
2078 : }
2079 : }
2080 :
2081 0 : DONE:
2082 2 : return next0;
2083 : }
2084 :
2085 576 : VLIB_NODE_FN (srv6_end_m_gtp6_d)
2086 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
2087 : {
2088 1 : srv6_end_main_v6_decap_t *sm = &srv6_end_main_v6_decap;
2089 1 : ip6_sr_main_t *sm2 = &sr_main;
2090 : u32 n_left_from, next_index, *from, *to_next;
2091 1 : u32 thread_index = vm->thread_index;
2092 : ip6_sr_localsid_t *ls0;
2093 : srv6_end_gtp6_d_param_t *ls_param;
2094 :
2095 1 : u32 good_n = 0, bad_n = 0;
2096 :
2097 1 : from = vlib_frame_vector_args (frame);
2098 1 : n_left_from = frame->n_vectors;
2099 1 : next_index = node->cached_next_index;
2100 :
2101 2 : while (n_left_from > 0)
2102 : {
2103 : u32 n_left_to_next;
2104 :
2105 1 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2106 :
2107 3 : while (n_left_from > 0 && n_left_to_next > 0)
2108 : {
2109 : u32 bi0;
2110 : vlib_buffer_t *b0;
2111 :
2112 : u32 next0;
2113 :
2114 : ip6_gtpu_header_t *hdr;
2115 : u32 hdrlen;
2116 : u8 gtpu_type;
2117 : bool gtp6;
2118 : bool ipv4;
2119 :
2120 : // defaults
2121 2 : bi0 = from[0];
2122 2 : to_next[0] = bi0;
2123 2 : from += 1;
2124 2 : to_next += 1;
2125 2 : n_left_from -= 1;
2126 2 : n_left_to_next -= 1;
2127 :
2128 2 : b0 = vlib_get_buffer (vm, bi0);
2129 :
2130 2 : ls0 = pool_elt_at_index (sm2->localsids,
2131 : vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2132 :
2133 2 : ls_param = (srv6_end_gtp6_d_param_t *) ls0->plugin_mem;
2134 :
2135 2 : hdr = vlib_buffer_get_current (b0);
2136 2 : gtpu_type = hdr->gtpu.type;
2137 :
2138 2 : gtp6 = false;
2139 2 : ipv4 = true;
2140 :
2141 2 : if (PREDICT_FALSE (gtpu_type != GTPU_TYPE_GTPU || ls_param->drop_in))
2142 : {
2143 2 : gtp6 = true;
2144 : }
2145 : else
2146 : {
2147 : ip6_header_t *ip6;
2148 :
2149 0 : hdrlen = sizeof (ip6_gtpu_header_t);
2150 :
2151 0 : if (hdr->gtpu.ver_flags & (GTPU_EXTHDR_FLAG | GTPU_SEQ_FLAG))
2152 : {
2153 0 : hdrlen += sizeof (gtpu_exthdr_t);
2154 0 : if (hdr->gtpu.ext->nextexthdr == GTPU_EXTHDR_PDU_SESSION)
2155 : {
2156 : gtpu_pdu_session_t *sess;
2157 0 : sess = (gtpu_pdu_session_t *) (((char *) hdr) + hdrlen);
2158 0 : hdrlen += sizeof (gtpu_pdu_session_t);
2159 :
2160 0 : if (sess->u.val & GTPU_PDU_SESSION_P_BIT_MASK)
2161 : {
2162 0 : hdrlen += sizeof (gtpu_paging_policy_t);
2163 : }
2164 : }
2165 : }
2166 :
2167 0 : ip6 = (ip6_header_t *) (((char *) hdr) + hdrlen);
2168 0 : if ((clib_net_to_host_u32 (
2169 0 : ip6->ip_version_traffic_class_and_flow_label) >>
2170 : 28) == 6)
2171 : {
2172 0 : ipv4 = false;
2173 0 : if (((ip6->dst_address.as_u8[0] == 0xff) &&
2174 0 : (ip6->dst_address.as_u8[1] == 0x02)) ||
2175 0 : ((ip6->dst_address.as_u8[0] == 0xfe) &&
2176 0 : ((ip6->dst_address.as_u8[1] & 0xc0) == 0x80)))
2177 : {
2178 : // Inner desitnation is IPv6 link local
2179 0 : gtp6 = true;
2180 : }
2181 : }
2182 : }
2183 :
2184 2 : if (gtp6)
2185 : {
2186 2 : next0 = srv6_gtp6_decap_processing (vm, node, b0);
2187 2 : if (PREDICT_TRUE (next0 == SRV6_END_M_GTP6_D_NEXT_LOOKUP6))
2188 2 : good_n++;
2189 : else
2190 0 : bad_n++;
2191 :
2192 4 : vlib_increment_combined_counter (
2193 : ((next0 == SRV6_END_M_GTP6_D_NEXT_DROP) ?
2194 : &(sm2->sr_ls_invalid_counters) :
2195 : &(sm2->sr_ls_valid_counters)),
2196 2 : thread_index, ls0 - sm2->localsids, 1,
2197 : vlib_buffer_length_in_chain (vm, b0));
2198 : }
2199 : else
2200 : {
2201 : /* Strip off the outer header (IPv6 + GTP + UDP + IEs) */
2202 0 : vlib_buffer_advance (b0, (word) hdrlen);
2203 :
2204 0 : if (ipv4)
2205 : {
2206 0 : next0 = SRV6_END_M_GTP6_D_NEXT_LOOKUP4;
2207 0 : vnet_buffer (b0)->sw_if_index[VLIB_TX] =
2208 0 : ls_param->fib4_index;
2209 : }
2210 : else
2211 : {
2212 0 : next0 = SRV6_END_M_GTP6_D_NEXT_LOOKUP6;
2213 0 : vnet_buffer (b0)->sw_if_index[VLIB_TX] =
2214 0 : ls_param->fib6_index;
2215 : }
2216 : }
2217 :
2218 2 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2219 : n_left_to_next, bi0, next0);
2220 : }
2221 :
2222 1 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2223 : }
2224 :
2225 1 : vlib_node_increment_counter (vm, sm->end_m_gtp6_d_node_index,
2226 : SRV6_END_ERROR_M_GTP6_D_BAD_PACKETS, bad_n);
2227 :
2228 1 : vlib_node_increment_counter (vm, sm->end_m_gtp6_d_node_index,
2229 : SRV6_END_ERROR_M_GTP6_D_PACKETS, good_n);
2230 :
2231 1 : return frame->n_vectors;
2232 : }
2233 :
2234 : // Function for SRv6 GTP6.D.DI function
2235 575 : VLIB_NODE_FN (srv6_end_m_gtp6_d_di)
2236 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
2237 : {
2238 0 : srv6_end_main_v6_decap_di_t *sm = &srv6_end_main_v6_decap_di;
2239 0 : ip6_sr_main_t *sm2 = &sr_main;
2240 : u32 n_left_from, next_index, *from, *to_next;
2241 0 : u32 thread_index = vm->thread_index;
2242 : srv6_end_gtp6_d_param_t *ls_param;
2243 :
2244 0 : u32 good_n = 0, bad_n = 0;
2245 :
2246 0 : from = vlib_frame_vector_args (frame);
2247 0 : n_left_from = frame->n_vectors;
2248 0 : next_index = node->cached_next_index;
2249 :
2250 0 : while (n_left_from > 0)
2251 : {
2252 : u32 n_left_to_next;
2253 :
2254 0 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2255 :
2256 0 : while (n_left_from > 0 && n_left_to_next > 0)
2257 : {
2258 : u32 bi0;
2259 : vlib_buffer_t *b0;
2260 : ip6_sr_localsid_t *ls0;
2261 :
2262 0 : ip6_gtpu_header_t *hdr0 = NULL;
2263 : uword len0;
2264 :
2265 : ip6_address_t dst0;
2266 : ip6_address_t src0;
2267 : ip6_address_t seg0;
2268 0 : u32 teid = 0;
2269 : u8 *teidp;
2270 0 : u8 gtpu_type = 0;
2271 0 : u8 qfi = 0;
2272 0 : u8 *qfip = NULL;
2273 0 : u16 seq = 0;
2274 : u8 *seqp;
2275 : u32 offset, shift;
2276 : u32 hdrlen;
2277 0 : ip6_header_t *encap = NULL;
2278 : gtpu_pdu_session_t *sess;
2279 0 : int ie_size = 0;
2280 0 : u16 tlv_siz = 0;
2281 : u8 ie_buf[GTPU_IE_MAX_SIZ];
2282 :
2283 0 : u32 next0 = SRV6_END_M_GTP6_D_DI_NEXT_LOOKUP;
2284 :
2285 : // defaults
2286 0 : bi0 = from[0];
2287 0 : to_next[0] = bi0;
2288 0 : from += 1;
2289 0 : to_next += 1;
2290 0 : n_left_from -= 1;
2291 0 : n_left_to_next -= 1;
2292 :
2293 0 : b0 = vlib_get_buffer (vm, bi0);
2294 0 : ls0 = pool_elt_at_index (sm2->localsids,
2295 : vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2296 :
2297 0 : ls_param = (srv6_end_gtp6_d_param_t *) ls0->plugin_mem;
2298 :
2299 0 : hdr0 = vlib_buffer_get_current (b0);
2300 :
2301 0 : hdrlen = sizeof (ip6_gtpu_header_t);
2302 :
2303 0 : len0 = vlib_buffer_length_in_chain (vm, b0);
2304 :
2305 0 : if ((hdr0->ip6.protocol != IP_PROTOCOL_UDP) ||
2306 0 : (hdr0->udp.dst_port !=
2307 0 : clib_host_to_net_u16 (SRV6_GTP_UDP_DST_PORT)) ||
2308 : (len0 < sizeof (ip6_gtpu_header_t)))
2309 : {
2310 0 : next0 = SRV6_END_M_GTP6_D_DI_NEXT_DROP;
2311 :
2312 0 : bad_n++;
2313 : }
2314 : else
2315 : {
2316 0 : dst0 = hdr0->ip6.dst_address;
2317 0 : src0 = hdr0->ip6.src_address;
2318 :
2319 0 : gtpu_type = hdr0->gtpu.type;
2320 :
2321 0 : seg0 = ls_param->sr_prefix;
2322 0 : teid = hdr0->gtpu.teid;
2323 0 : teidp = (u8 *) &teid;
2324 :
2325 0 : seqp = (u8 *) &seq;
2326 :
2327 0 : if (hdr0->gtpu.ver_flags & (GTPU_EXTHDR_FLAG | GTPU_SEQ_FLAG))
2328 : {
2329 : // Extention header.
2330 0 : hdrlen += sizeof (gtpu_exthdr_t);
2331 :
2332 0 : seq = hdr0->gtpu.ext->seq;
2333 :
2334 0 : if (hdr0->gtpu.ext->nextexthdr == GTPU_EXTHDR_PDU_SESSION)
2335 : {
2336 : // PDU Session Container.
2337 0 : sess = (gtpu_pdu_session_t *) (((char *) hdr0) + hdrlen);
2338 0 : qfi = sess->u.val & ~GTPU_PDU_SESSION_P_BIT_MASK;
2339 0 : qfip = &qfi;
2340 :
2341 0 : hdrlen += sizeof (gtpu_pdu_session_t);
2342 :
2343 0 : if (sess->u.val & GTPU_PDU_SESSION_P_BIT_MASK)
2344 : {
2345 0 : hdrlen += sizeof (gtpu_paging_policy_t);
2346 : }
2347 : }
2348 : }
2349 :
2350 0 : offset = ls_param->sr_prefixlen / 8;
2351 0 : shift = ls_param->sr_prefixlen % 8;
2352 :
2353 0 : offset += 1;
2354 0 : if (PREDICT_TRUE (shift == 0))
2355 : {
2356 0 : if (gtpu_type == GTPU_TYPE_ECHO_REQUEST ||
2357 0 : gtpu_type == GTPU_TYPE_ECHO_REPLY ||
2358 : gtpu_type == GTPU_TYPE_ERROR_INDICATION)
2359 : {
2360 0 : clib_memcpy_fast (&seg0.as_u8[offset], seqp, 2);
2361 : }
2362 : else
2363 : {
2364 0 : clib_memcpy_fast (&seg0.as_u8[offset], teidp, 4);
2365 : }
2366 :
2367 0 : if (qfip)
2368 : {
2369 0 : qfi = ((qfi & GTPU_PDU_SESSION_QFI_MASK) << 2) |
2370 0 : ((qfi & GTPU_PDU_SESSION_R_BIT_MASK) >> 5);
2371 :
2372 0 : if (sess->type)
2373 : {
2374 0 : qfi |= SRV6_PDU_SESSION_U_BIT_MASK;
2375 : }
2376 :
2377 0 : seg0.as_u8[offset + 4] = qfi;
2378 : }
2379 : }
2380 : else
2381 : {
2382 : int idx;
2383 :
2384 0 : if (gtpu_type == GTPU_TYPE_ECHO_REQUEST ||
2385 0 : gtpu_type == GTPU_TYPE_ECHO_REPLY ||
2386 : gtpu_type == GTPU_TYPE_ERROR_INDICATION)
2387 : {
2388 0 : for (idx = 0; idx < 2; idx++)
2389 : {
2390 0 : seg0.as_u8[offset + idx] |= seqp[idx] >> shift;
2391 0 : seg0.as_u8[offset + idx + 1] |= seqp[idx]
2392 0 : << (8 - shift);
2393 : }
2394 : }
2395 : else
2396 : {
2397 0 : for (idx = 0; idx < 4; idx++)
2398 : {
2399 0 : seg0.as_u8[offset + idx] |= teidp[idx] >> shift;
2400 0 : seg0.as_u8[offset + idx + 1] |= teidp[idx]
2401 0 : << (8 - shift);
2402 : }
2403 : }
2404 :
2405 0 : if (qfip)
2406 : {
2407 0 : qfi = ((qfi & GTPU_PDU_SESSION_QFI_MASK) << 2) |
2408 0 : ((qfi & GTPU_PDU_SESSION_R_BIT_MASK) >> 5);
2409 :
2410 0 : if (sess->type)
2411 : {
2412 0 : qfi |= SRV6_PDU_SESSION_U_BIT_MASK;
2413 : }
2414 :
2415 0 : seg0.as_u8[offset + 4] |= qfi >> shift;
2416 0 : seg0.as_u8[offset + 5] |= qfi << (8 - shift);
2417 : }
2418 : }
2419 :
2420 0 : if (PREDICT_FALSE (gtpu_type == GTPU_TYPE_ERROR_INDICATION))
2421 : {
2422 : u16 payload_len;
2423 :
2424 0 : payload_len = clib_net_to_host_u16 (hdr0->gtpu.length);
2425 0 : if (payload_len != 0)
2426 : {
2427 0 : ie_size =
2428 0 : payload_len - (hdrlen - sizeof (ip6_gtpu_header_t));
2429 0 : if (ie_size > 0)
2430 : {
2431 : u8 *ies;
2432 :
2433 0 : ies = (u8 *) ((u8 *) hdr0 + hdrlen);
2434 0 : clib_memcpy_fast (ie_buf, ies, ie_size);
2435 0 : hdrlen += ie_size;
2436 : }
2437 : }
2438 : }
2439 :
2440 : // jump over variable length data
2441 0 : vlib_buffer_advance (b0, (word) hdrlen);
2442 :
2443 : // get length of encapsulated IPv6 packet (the remaining part)
2444 0 : len0 = vlib_buffer_length_in_chain (vm, b0);
2445 :
2446 0 : if (PREDICT_TRUE (gtpu_type == GTPU_TYPE_GTPU))
2447 : {
2448 0 : encap = vlib_buffer_get_current (b0);
2449 : }
2450 :
2451 : uword *p;
2452 : ip6srv_combo_header_t *ip6srv;
2453 0 : ip6_sr_policy_t *sr_policy = NULL;
2454 0 : ip6_sr_sl_t *sl = NULL;
2455 : u32 *sl_index;
2456 : u32 hdr_len;
2457 :
2458 : p =
2459 0 : mhash_get (&sm2->sr_policies_index_hash, &ls_param->sr_prefix);
2460 0 : if (p)
2461 : {
2462 0 : sr_policy = pool_elt_at_index (sm2->sr_policies, p[0]);
2463 : }
2464 :
2465 0 : if (sr_policy)
2466 : {
2467 0 : vec_foreach (sl_index, sr_policy->segments_lists)
2468 : {
2469 0 : sl = pool_elt_at_index (sm2->sid_lists, *sl_index);
2470 0 : if (sl != NULL)
2471 0 : break;
2472 : }
2473 : }
2474 :
2475 0 : hdr_len = sizeof (ip6srv_combo_header_t);
2476 :
2477 0 : if (sl)
2478 0 : hdr_len += vec_len (sl->segments) * sizeof (ip6_address_t);
2479 :
2480 0 : hdr_len += sizeof (ip6_address_t) * 2;
2481 :
2482 0 : if (ie_size)
2483 : {
2484 0 : tlv_siz = sizeof (ip6_sr_tlv_t) +
2485 0 : sizeof (user_plane_sub_tlv_t) + ie_size;
2486 :
2487 0 : tlv_siz = (tlv_siz & ~0x07) + (tlv_siz & 0x07 ? 0x08 : 0x0);
2488 0 : hdr_len += tlv_siz;
2489 : }
2490 :
2491 : // jump back to data[0] or pre_data if required
2492 0 : vlib_buffer_advance (b0, -(word) hdr_len);
2493 :
2494 0 : ip6srv = vlib_buffer_get_current (b0);
2495 :
2496 0 : if (sl)
2497 : {
2498 0 : clib_memcpy_fast (ip6srv, sl->rewrite,
2499 0 : vec_len (sl->rewrite));
2500 :
2501 0 : if (vec_len (sl->segments) > 1)
2502 : {
2503 0 : ip6srv->ip.src_address = src0;
2504 :
2505 0 : ip6srv->sr.tag =
2506 0 : clib_host_to_net_u16 (srh_tagfield[gtpu_type]);
2507 :
2508 0 : ip6srv->sr.segments_left += 2;
2509 0 : ip6srv->sr.last_entry += 2;
2510 :
2511 0 : ip6srv->sr.length += ((sizeof (ip6_address_t) * 2) / 8);
2512 :
2513 0 : ip6srv->sr.segments[0] = dst0;
2514 0 : ip6srv->sr.segments[1] = seg0;
2515 :
2516 0 : clib_memcpy_fast (
2517 0 : &ip6srv->sr.segments[2],
2518 0 : (u8 *) (sl->rewrite + sizeof (ip6_header_t) +
2519 : sizeof (ip6_sr_header_t)),
2520 0 : vec_len (sl->segments) * sizeof (ip6_address_t));
2521 : }
2522 : else
2523 : {
2524 0 : ip6srv->ip.src_address = src0;
2525 0 : ip6srv->ip.protocol = IP_PROTOCOL_IPV6_ROUTE;
2526 :
2527 0 : ip6srv->sr.type = ROUTING_HEADER_TYPE_SR;
2528 0 : ip6srv->sr.segments_left = 2;
2529 0 : ip6srv->sr.last_entry = 1;
2530 0 : ip6srv->sr.length = ((sizeof (ip6_sr_header_t) +
2531 : 2 * sizeof (ip6_address_t)) /
2532 : 8) -
2533 : 1;
2534 0 : ip6srv->sr.flags = 0;
2535 :
2536 0 : ip6srv->sr.tag =
2537 0 : clib_host_to_net_u16 (srh_tagfield[gtpu_type]);
2538 :
2539 0 : ip6srv->sr.segments[0] = dst0;
2540 0 : ip6srv->sr.segments[1] = seg0;
2541 :
2542 0 : if (vec_len (sl->segments))
2543 : {
2544 0 : ip6srv->sr.segments[2] = sl->segments[0];
2545 0 : ip6srv->sr.last_entry++;
2546 0 : ip6srv->sr.length += sizeof (ip6_address_t) / 8;
2547 : }
2548 : }
2549 : }
2550 : else
2551 : {
2552 0 : clib_memcpy_fast (ip6srv, &sm->cache_hdr,
2553 : sizeof (ip6_header_t));
2554 :
2555 0 : ip6srv->ip.src_address = src0;
2556 0 : ip6srv->ip.dst_address = seg0;
2557 :
2558 0 : ip6srv->sr.type = ROUTING_HEADER_TYPE_SR;
2559 0 : ip6srv->sr.segments_left = 1;
2560 0 : ip6srv->sr.last_entry = 0;
2561 0 : ip6srv->sr.length =
2562 : ((sizeof (ip6_sr_header_t) + sizeof (ip6_address_t)) / 8) -
2563 : 1;
2564 0 : ip6srv->sr.flags = 0;
2565 :
2566 0 : ip6srv->sr.tag =
2567 0 : clib_host_to_net_u16 (srh_tagfield[gtpu_type]);
2568 :
2569 0 : ip6srv->sr.segments[0] = dst0;
2570 : }
2571 :
2572 0 : if (PREDICT_FALSE (ie_size))
2573 : {
2574 : ip6_sr_tlv_t *tlv;
2575 : user_plane_sub_tlv_t *sub_tlv;
2576 :
2577 0 : tlv = (ip6_sr_tlv_t *) ((u8 *) ip6srv + (hdr_len - tlv_siz));
2578 0 : tlv->type = SRH_TLV_USER_PLANE_CONTAINER;
2579 0 : tlv->length = (u8) (tlv_siz - sizeof (ip6_sr_tlv_t));
2580 0 : clib_memset (tlv->value, 0, tlv->length);
2581 :
2582 0 : sub_tlv = (user_plane_sub_tlv_t *) tlv->value;
2583 0 : sub_tlv->length = (u8) (ie_size);
2584 0 : clib_memcpy_fast (sub_tlv->value, ie_buf, ie_size);
2585 :
2586 0 : ip6srv->sr.length += (u8) (tlv_siz / 8);
2587 : }
2588 :
2589 0 : ip6srv->ip.payload_length =
2590 0 : clib_host_to_net_u16 (len0 + hdr_len - sizeof (ip6_header_t));
2591 0 : ip6srv->ip.protocol = IP_PROTOCOL_IPV6_ROUTE;
2592 :
2593 0 : if (PREDICT_TRUE (encap != NULL))
2594 : {
2595 0 : if (ls_param->nhtype == SRV6_NHTYPE_NONE)
2596 : {
2597 0 : if ((clib_net_to_host_u32 (
2598 0 : encap->ip_version_traffic_class_and_flow_label) >>
2599 : 28) == 6)
2600 0 : ip6srv->sr.protocol = IP_PROTOCOL_IPV6;
2601 : else
2602 0 : ip6srv->sr.protocol = IP_PROTOCOL_IP_IN_IP;
2603 : }
2604 0 : else if (ls_param->nhtype == SRV6_NHTYPE_IPV4)
2605 : {
2606 0 : ip6srv->sr.protocol = IP_PROTOCOL_IP_IN_IP;
2607 0 : if ((clib_net_to_host_u32 (
2608 0 : encap->ip_version_traffic_class_and_flow_label) >>
2609 : 28) != 4)
2610 : {
2611 : // Bad encap packet.
2612 0 : next0 = SRV6_END_M_GTP6_D_DI_NEXT_DROP;
2613 0 : bad_n++;
2614 0 : goto DONE;
2615 : }
2616 : }
2617 0 : else if (ls_param->nhtype == SRV6_NHTYPE_IPV6)
2618 : {
2619 0 : ip6srv->sr.protocol = IP_PROTOCOL_IPV6;
2620 0 : if ((clib_net_to_host_u32 (
2621 0 : encap->ip_version_traffic_class_and_flow_label) >>
2622 : 28) != 6)
2623 : {
2624 : // Bad encap packet.
2625 0 : next0 = SRV6_END_M_GTP6_D_DI_NEXT_DROP;
2626 0 : bad_n++;
2627 0 : goto DONE;
2628 : }
2629 : }
2630 0 : else if (ls_param->nhtype == SRV6_NHTYPE_NON_IP)
2631 : {
2632 0 : ip6srv->sr.protocol = IP_PROTOCOL_IP6_ETHERNET;
2633 : }
2634 : }
2635 : else
2636 : {
2637 0 : ip6srv->sr.protocol = IP_PROTOCOL_IP6_ETHERNET;
2638 : }
2639 :
2640 0 : good_n++;
2641 :
2642 0 : if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2643 0 : PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2644 : {
2645 : srv6_end_rewrite_trace_t *tr =
2646 0 : vlib_add_trace (vm, node, b0, sizeof (*tr));
2647 0 : clib_memcpy (tr->src.as_u8, ip6srv->ip.src_address.as_u8,
2648 : sizeof (ip6_address_t));
2649 0 : clib_memcpy (tr->dst.as_u8, ip6srv->ip.dst_address.as_u8,
2650 : sizeof (ip6_address_t));
2651 0 : tr->teid = teid;
2652 0 : clib_memcpy (tr->sr_prefix.as_u8, ls_param->sr_prefix.as_u8,
2653 : sizeof (ip6_address_t));
2654 0 : tr->sr_prefixlen = ls_param->sr_prefixlen;
2655 : }
2656 : }
2657 :
2658 0 : DONE:
2659 0 : vlib_increment_combined_counter (
2660 : ((next0 == SRV6_END_M_GTP6_D_DI_NEXT_DROP) ?
2661 : &(sm2->sr_ls_invalid_counters) :
2662 : &(sm2->sr_ls_valid_counters)),
2663 0 : thread_index, ls0 - sm2->localsids, 1,
2664 : vlib_buffer_length_in_chain (vm, b0));
2665 :
2666 0 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2667 : n_left_to_next, bi0, next0);
2668 : }
2669 :
2670 0 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2671 : }
2672 :
2673 0 : vlib_node_increment_counter (vm, sm->end_m_gtp6_d_di_node_index,
2674 : SRV6_END_ERROR_M_GTP6_D_DI_BAD_PACKETS, bad_n);
2675 :
2676 0 : vlib_node_increment_counter (vm, sm->end_m_gtp6_d_di_node_index,
2677 : SRV6_END_ERROR_M_GTP6_D_DI_PACKETS, good_n);
2678 :
2679 0 : return frame->n_vectors;
2680 : }
2681 :
2682 : // Function for SRv6 GTP6.DT function
2683 575 : VLIB_NODE_FN (srv6_end_m_gtp6_dt)
2684 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
2685 : {
2686 0 : srv6_end_main_v6_dt_t *sm = &srv6_end_main_v6_dt;
2687 0 : ip6_sr_main_t *sm2 = &sr_main;
2688 : u32 n_left_from, next_index, *from, *to_next;
2689 0 : u32 thread_index = vm->thread_index;
2690 :
2691 0 : u32 good_n = 0, bad_n = 0;
2692 :
2693 0 : from = vlib_frame_vector_args (frame);
2694 0 : n_left_from = frame->n_vectors;
2695 0 : next_index = node->cached_next_index;
2696 :
2697 0 : while (n_left_from > 0)
2698 : {
2699 : u32 n_left_to_next;
2700 :
2701 0 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2702 :
2703 0 : while (n_left_from > 0 && n_left_to_next > 0)
2704 : {
2705 : u32 bi0;
2706 : vlib_buffer_t *b0;
2707 : srv6_end_gtp6_dt_param_t *ls_param;
2708 : ip6_sr_localsid_t *ls0;
2709 :
2710 0 : ip6_gtpu_header_t *hdr0 = NULL;
2711 0 : ip4_header_t *ip4 = NULL;
2712 0 : ip6_header_t *ip6 = NULL;
2713 : ip6_address_t src, dst;
2714 : u32 teid;
2715 : u32 hdrlen;
2716 : u32 len0;
2717 :
2718 0 : u32 next0 = SRV6_END_M_GTP6_DT_NEXT_DROP;
2719 :
2720 0 : bi0 = from[0];
2721 0 : to_next[0] = bi0;
2722 0 : from += 1;
2723 0 : to_next += 1;
2724 0 : n_left_from -= 1;
2725 0 : n_left_to_next -= 1;
2726 :
2727 0 : b0 = vlib_get_buffer (vm, bi0);
2728 0 : ls0 = pool_elt_at_index (sm2->localsids,
2729 : vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2730 :
2731 0 : ls_param = (srv6_end_gtp6_dt_param_t *) ls0->plugin_mem;
2732 :
2733 0 : hdr0 = vlib_buffer_get_current (b0);
2734 :
2735 0 : hdrlen = sizeof (ip6_gtpu_header_t);
2736 :
2737 0 : len0 = vlib_buffer_length_in_chain (vm, b0);
2738 :
2739 0 : if ((hdr0->ip6.protocol != IP_PROTOCOL_UDP) ||
2740 0 : (hdr0->udp.dst_port !=
2741 0 : clib_host_to_net_u16 (SRV6_GTP_UDP_DST_PORT)) ||
2742 : (len0 < sizeof (ip6_gtpu_header_t)))
2743 : {
2744 0 : next0 = SRV6_END_M_GTP6_DT_NEXT_DROP;
2745 :
2746 0 : bad_n++;
2747 : }
2748 : else
2749 : {
2750 0 : clib_memcpy_fast (src.as_u8, hdr0->ip6.src_address.as_u8,
2751 : sizeof (ip6_address_t));
2752 0 : clib_memcpy_fast (dst.as_u8, hdr0->ip6.dst_address.as_u8,
2753 : sizeof (ip6_address_t));
2754 :
2755 0 : teid = hdr0->gtpu.teid;
2756 :
2757 0 : if (hdr0->gtpu.ver_flags & GTPU_EXTHDR_FLAG)
2758 : {
2759 0 : hdrlen += sizeof (gtpu_exthdr_t);
2760 0 : if (hdr0->gtpu.ext->nextexthdr == GTPU_EXTHDR_PDU_SESSION)
2761 : {
2762 : gtpu_pdu_session_t *sess;
2763 :
2764 0 : sess =
2765 : (gtpu_pdu_session_t *) (((char *) hdr0) +
2766 : sizeof (ip6_gtpu_header_t) +
2767 : sizeof (gtpu_exthdr_t));
2768 :
2769 0 : hdrlen += sizeof (gtpu_pdu_session_t);
2770 0 : if (sess->u.val & GTPU_PDU_SESSION_P_BIT_MASK)
2771 : {
2772 0 : hdrlen += sizeof (gtpu_paging_policy_t);
2773 : }
2774 : }
2775 : }
2776 :
2777 0 : if (ls_param->type == SRV6_GTP6_DT4)
2778 : {
2779 0 : vlib_buffer_advance (b0, (word) hdrlen);
2780 0 : ip4 = vlib_buffer_get_current (b0);
2781 0 : if ((ip4->ip_version_and_header_length & 0xf0) != 0x40)
2782 : {
2783 0 : next0 = SRV6_END_M_GTP6_DT_NEXT_DROP;
2784 0 : bad_n++;
2785 0 : goto DONE;
2786 : }
2787 :
2788 0 : next0 = SRV6_END_M_GTP6_DT_NEXT_LOOKUP4;
2789 0 : vnet_buffer (b0)->sw_if_index[VLIB_TX] =
2790 0 : ls_param->fib4_index;
2791 : }
2792 0 : else if (ls_param->type == SRV6_GTP6_DT6)
2793 : {
2794 0 : ip6 = (ip6_header_t *) ((u8 *) hdr0 + hdrlen);
2795 0 : if ((clib_net_to_host_u32 (
2796 0 : ip6->ip_version_traffic_class_and_flow_label) >>
2797 : 28) != 6)
2798 : {
2799 0 : next0 = SRV6_END_M_GTP6_DT_NEXT_DROP;
2800 0 : bad_n++;
2801 0 : goto DONE;
2802 : }
2803 :
2804 0 : next0 = SRV6_END_M_GTP6_DT_NEXT_LOOKUP6;
2805 0 : if (((ip6->dst_address.as_u8[0] == 0xff) &&
2806 0 : (ip6->dst_address.as_u8[1] == 0x02)) ||
2807 0 : ((ip6->dst_address.as_u8[0] == 0xfe) &&
2808 0 : ((ip6->dst_address.as_u8[1] & 0xc0) == 0x80)))
2809 : {
2810 0 : vnet_buffer (b0)->sw_if_index[VLIB_TX] =
2811 0 : ls_param->local_fib_index;
2812 : }
2813 : else
2814 : {
2815 0 : vlib_buffer_advance (b0, (word) hdrlen);
2816 0 : vnet_buffer (b0)->sw_if_index[VLIB_TX] =
2817 0 : ls_param->fib6_index;
2818 : }
2819 : }
2820 0 : else if (ls_param->type == SRV6_GTP6_DT46)
2821 : {
2822 0 : ip6 = (ip6_header_t *) ((u8 *) hdr0 + hdrlen);
2823 0 : if ((clib_net_to_host_u32 (
2824 0 : ip6->ip_version_traffic_class_and_flow_label) >>
2825 : 28) == 6)
2826 : {
2827 0 : next0 = SRV6_END_M_GTP6_DT_NEXT_LOOKUP6;
2828 0 : if (((ip6->dst_address.as_u8[0] == 0xff) &&
2829 0 : (ip6->dst_address.as_u8[1] == 0x02)) ||
2830 0 : ((ip6->dst_address.as_u8[0] == 0xfe) &&
2831 0 : ((ip6->dst_address.as_u8[1] & 0xc0) == 0x80)))
2832 : {
2833 0 : vnet_buffer (b0)->sw_if_index[VLIB_TX] =
2834 0 : ls_param->local_fib_index;
2835 : }
2836 : else
2837 : {
2838 0 : vlib_buffer_advance (b0, (word) hdrlen);
2839 0 : vnet_buffer (b0)->sw_if_index[VLIB_TX] =
2840 0 : ls_param->fib6_index;
2841 : }
2842 : }
2843 0 : else if ((clib_net_to_host_u32 (
2844 0 : ip6->ip_version_traffic_class_and_flow_label) >>
2845 : 28) == 4)
2846 : {
2847 0 : vlib_buffer_advance (b0, (word) hdrlen);
2848 0 : next0 = SRV6_END_M_GTP6_DT_NEXT_LOOKUP4;
2849 0 : vnet_buffer (b0)->sw_if_index[VLIB_TX] =
2850 0 : ls_param->fib4_index;
2851 : }
2852 : else
2853 : {
2854 0 : next0 = SRV6_END_M_GTP6_DT_NEXT_DROP;
2855 0 : bad_n++;
2856 0 : goto DONE;
2857 : }
2858 : }
2859 : else
2860 : {
2861 0 : next0 = SRV6_END_M_GTP6_DT_NEXT_DROP;
2862 0 : bad_n++;
2863 0 : goto DONE;
2864 : }
2865 :
2866 0 : good_n++;
2867 :
2868 0 : if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2869 0 : PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2870 : {
2871 : srv6_end_rewrite_trace_t *tr =
2872 0 : vlib_add_trace (vm, node, b0, sizeof (*tr));
2873 0 : clib_memcpy (tr->src.as_u8, src.as_u8,
2874 : sizeof (ip6_address_t));
2875 0 : clib_memcpy (tr->dst.as_u8, dst.as_u8,
2876 : sizeof (ip6_address_t));
2877 0 : tr->teid = teid;
2878 : }
2879 : }
2880 :
2881 0 : DONE:
2882 0 : vlib_increment_combined_counter (
2883 : ((next0 == SRV6_END_M_GTP6_DT_NEXT_DROP) ?
2884 : &(sm2->sr_ls_invalid_counters) :
2885 : &(sm2->sr_ls_valid_counters)),
2886 0 : thread_index, ls0 - sm2->localsids, 1,
2887 : vlib_buffer_length_in_chain (vm, b0));
2888 :
2889 0 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2890 : n_left_to_next, bi0, next0);
2891 : }
2892 :
2893 0 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2894 : }
2895 :
2896 0 : vlib_node_increment_counter (vm, sm->end_m_gtp6_dt_node_index,
2897 : SRV6_END_ERROR_M_GTP6_DT_BAD_PACKETS, bad_n);
2898 :
2899 0 : vlib_node_increment_counter (vm, sm->end_m_gtp6_dt_node_index,
2900 : SRV6_END_ERROR_M_GTP6_DT_PACKETS, good_n);
2901 :
2902 0 : return frame->n_vectors;
2903 : }
2904 :
2905 : // Function for SRv6 GTP4.DT function
2906 575 : VLIB_NODE_FN (srv6_t_m_gtp4_dt)
2907 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
2908 : {
2909 0 : srv6_t_main_v4_dt_t *sm = &srv6_t_main_v4_dt;
2910 0 : ip6_sr_main_t *sm2 = &sr_main;
2911 : u32 n_left_from, next_index, *from, *to_next;
2912 :
2913 0 : u32 good_n = 0, bad_n = 0;
2914 :
2915 0 : from = vlib_frame_vector_args (frame);
2916 0 : n_left_from = frame->n_vectors;
2917 0 : next_index = node->cached_next_index;
2918 :
2919 0 : while (n_left_from > 0)
2920 : {
2921 : u32 n_left_to_next;
2922 :
2923 0 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2924 :
2925 0 : while (n_left_from > 0 && n_left_to_next > 0)
2926 : {
2927 : u32 bi0;
2928 : vlib_buffer_t *b0;
2929 : srv6_t_gtp4_dt_param_t *ls_param;
2930 : ip6_sr_sl_t *ls0;
2931 :
2932 0 : ip4_gtpu_header_t *hdr0 = NULL;
2933 0 : ip4_header_t *ip4 = NULL;
2934 0 : ip6_header_t *ip6 = NULL;
2935 : ip6_address_t src, dst;
2936 : u32 teid;
2937 : u32 hdrlen;
2938 : u32 len0;
2939 :
2940 0 : u32 next0 = SRV6_T_M_GTP4_DT_NEXT_DROP;
2941 :
2942 0 : bi0 = from[0];
2943 0 : to_next[0] = bi0;
2944 0 : from += 1;
2945 0 : to_next += 1;
2946 0 : n_left_from -= 1;
2947 0 : n_left_to_next -= 1;
2948 :
2949 0 : b0 = vlib_get_buffer (vm, bi0);
2950 0 : ls0 = pool_elt_at_index (sm2->sid_lists,
2951 : vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2952 :
2953 0 : ls_param = (srv6_t_gtp4_dt_param_t *) ls0->plugin_mem;
2954 :
2955 0 : hdr0 = vlib_buffer_get_current (b0);
2956 :
2957 0 : hdrlen = sizeof (ip4_gtpu_header_t);
2958 :
2959 0 : len0 = vlib_buffer_length_in_chain (vm, b0);
2960 :
2961 0 : if ((hdr0->ip4.protocol != IP_PROTOCOL_UDP) ||
2962 0 : (hdr0->udp.dst_port !=
2963 0 : clib_host_to_net_u16 (SRV6_GTP_UDP_DST_PORT)) ||
2964 : (len0 < sizeof (ip4_gtpu_header_t)))
2965 : {
2966 0 : next0 = SRV6_T_M_GTP4_DT_NEXT_DROP;
2967 :
2968 0 : bad_n++;
2969 : }
2970 : else
2971 : {
2972 0 : clib_memcpy_fast (src.as_u8, hdr0->ip4.src_address.as_u8,
2973 : sizeof (ip4_address_t));
2974 0 : clib_memcpy_fast (dst.as_u8, hdr0->ip4.dst_address.as_u8,
2975 : sizeof (ip4_address_t));
2976 :
2977 0 : teid = hdr0->gtpu.teid;
2978 :
2979 0 : if (hdr0->gtpu.ver_flags & GTPU_EXTHDR_FLAG)
2980 : {
2981 0 : hdrlen += sizeof (gtpu_exthdr_t);
2982 0 : if (hdr0->gtpu.ext->nextexthdr == GTPU_EXTHDR_PDU_SESSION)
2983 : {
2984 : gtpu_pdu_session_t *sess;
2985 :
2986 0 : sess =
2987 : (gtpu_pdu_session_t *) (((char *) hdr0) +
2988 : sizeof (ip6_gtpu_header_t) +
2989 : sizeof (gtpu_exthdr_t));
2990 :
2991 0 : hdrlen += sizeof (gtpu_pdu_session_t);
2992 0 : if (sess->u.val & GTPU_PDU_SESSION_P_BIT_MASK)
2993 : {
2994 0 : hdrlen += sizeof (gtpu_paging_policy_t);
2995 : }
2996 : }
2997 : }
2998 :
2999 0 : if (ls_param->type == SRV6_GTP4_DT4)
3000 : {
3001 0 : vlib_buffer_advance (b0, (word) hdrlen);
3002 0 : ip4 = vlib_buffer_get_current (b0);
3003 0 : if ((ip4->ip_version_and_header_length & 0xf0) != 0x40)
3004 : {
3005 0 : next0 = SRV6_T_M_GTP4_DT_NEXT_DROP;
3006 0 : bad_n++;
3007 0 : goto DONE;
3008 : }
3009 :
3010 0 : next0 = SRV6_T_M_GTP4_DT_NEXT_LOOKUP4;
3011 0 : vnet_buffer (b0)->sw_if_index[VLIB_TX] =
3012 0 : ls_param->fib4_index;
3013 : }
3014 0 : else if (ls_param->type == SRV6_GTP4_DT6)
3015 : {
3016 0 : ip6 = (ip6_header_t *) ((u8 *) hdr0 + hdrlen);
3017 0 : if ((clib_net_to_host_u32 (
3018 0 : ip6->ip_version_traffic_class_and_flow_label) >>
3019 : 28) != 6)
3020 : {
3021 0 : next0 = SRV6_T_M_GTP4_DT_NEXT_DROP;
3022 0 : bad_n++;
3023 0 : goto DONE;
3024 : }
3025 :
3026 0 : next0 = SRV6_T_M_GTP4_DT_NEXT_LOOKUP6;
3027 0 : if (((ip6->dst_address.as_u8[0] == 0xff) &&
3028 0 : (ip6->dst_address.as_u8[1] == 0x02)) ||
3029 0 : ((ip6->dst_address.as_u8[0] == 0xfe) &&
3030 0 : ((ip6->dst_address.as_u8[1] & 0xc0) == 0x80)))
3031 : {
3032 0 : next0 = SRV6_T_M_GTP4_DT_NEXT_LOOKUP4;
3033 0 : vnet_buffer (b0)->sw_if_index[VLIB_TX] =
3034 0 : ls_param->local_fib_index;
3035 : }
3036 : else
3037 : {
3038 0 : vlib_buffer_advance (b0, (word) hdrlen);
3039 0 : vnet_buffer (b0)->sw_if_index[VLIB_TX] =
3040 0 : ls_param->fib6_index;
3041 : }
3042 : }
3043 0 : else if (ls_param->type == SRV6_GTP4_DT46)
3044 : {
3045 0 : ip6 = (ip6_header_t *) ((u8 *) hdr0 + hdrlen);
3046 0 : if ((clib_net_to_host_u32 (
3047 0 : ip6->ip_version_traffic_class_and_flow_label) >>
3048 : 28) == 6)
3049 : {
3050 0 : next0 = SRV6_T_M_GTP4_DT_NEXT_LOOKUP6;
3051 0 : if (((ip6->dst_address.as_u8[0] == 0xff) &&
3052 0 : (ip6->dst_address.as_u8[1] == 0x02)) ||
3053 0 : ((ip6->dst_address.as_u8[0] == 0xfe) &&
3054 0 : ((ip6->dst_address.as_u8[1] & 0xc0) == 0x80)))
3055 : {
3056 0 : next0 = SRV6_T_M_GTP4_DT_NEXT_LOOKUP4;
3057 0 : vnet_buffer (b0)->sw_if_index[VLIB_TX] =
3058 0 : ls_param->local_fib_index;
3059 : }
3060 : else
3061 : {
3062 0 : vlib_buffer_advance (b0, (word) hdrlen);
3063 0 : vnet_buffer (b0)->sw_if_index[VLIB_TX] =
3064 0 : ls_param->fib6_index;
3065 : }
3066 : }
3067 0 : else if ((clib_net_to_host_u32 (
3068 0 : ip6->ip_version_traffic_class_and_flow_label) >>
3069 : 28) == 4)
3070 : {
3071 0 : vlib_buffer_advance (b0, (word) hdrlen);
3072 0 : next0 = SRV6_T_M_GTP4_DT_NEXT_LOOKUP4;
3073 0 : vnet_buffer (b0)->sw_if_index[VLIB_TX] =
3074 0 : ls_param->fib4_index;
3075 : }
3076 : else
3077 : {
3078 0 : next0 = SRV6_T_M_GTP4_DT_NEXT_DROP;
3079 0 : bad_n++;
3080 0 : goto DONE;
3081 : }
3082 : }
3083 : else
3084 : {
3085 0 : next0 = SRV6_T_M_GTP4_DT_NEXT_DROP;
3086 0 : bad_n++;
3087 0 : goto DONE;
3088 : }
3089 :
3090 0 : good_n++;
3091 :
3092 0 : if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3093 0 : PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3094 : {
3095 : srv6_end_rewrite_trace_t *tr =
3096 0 : vlib_add_trace (vm, node, b0, sizeof (*tr));
3097 0 : clib_memcpy (tr->src.as_u8, src.as_u8,
3098 : sizeof (ip6_address_t));
3099 0 : clib_memcpy (tr->dst.as_u8, dst.as_u8,
3100 : sizeof (ip6_address_t));
3101 0 : tr->teid = teid;
3102 : }
3103 : }
3104 :
3105 0 : DONE:
3106 0 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3107 : n_left_to_next, bi0, next0);
3108 : }
3109 :
3110 0 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3111 : }
3112 :
3113 0 : vlib_node_increment_counter (vm, sm->t_m_gtp4_dt_node_index,
3114 : SRV6_T_ERROR_M_GTP4_DT_BAD_PACKETS, bad_n);
3115 :
3116 0 : vlib_node_increment_counter (vm, sm->t_m_gtp4_dt_node_index,
3117 : SRV6_T_ERROR_M_GTP4_DT_PACKETS, good_n);
3118 :
3119 0 : return frame->n_vectors;
3120 : }
3121 :
3122 32255 : VLIB_REGISTER_NODE (srv6_end_m_gtp6_e) =
3123 : {
3124 : .name = "srv6-end-m-gtp6-e",.vector_size = sizeof (u32),.format_trace =
3125 : format_srv6_end_rewrite_trace6,.type = VLIB_NODE_TYPE_INTERNAL,.n_errors =
3126 : ARRAY_LEN (srv6_end_error_v6_e_strings),.error_strings =
3127 : srv6_end_error_v6_e_strings,.n_next_nodes =
3128 : SRV6_END_M_GTP6_E_N_NEXT,.next_nodes =
3129 : {
3130 : [SRV6_END_M_GTP6_E_NEXT_DROP] = "error-drop",
3131 : [SRV6_END_M_GTP6_E_NEXT_LOOKUP] = "ip6-lookup",}
3132 : ,};
3133 :
3134 32255 : VLIB_REGISTER_NODE (srv6_end_m_gtp6_d) =
3135 : {
3136 : .name = "srv6-end-m-gtp6-d",.vector_size = sizeof (u32),.format_trace =
3137 : format_srv6_end_rewrite_trace6,.type = VLIB_NODE_TYPE_INTERNAL,.n_errors =
3138 : ARRAY_LEN (srv6_end_error_v6_d_strings),.error_strings =
3139 : srv6_end_error_v6_d_strings,.n_next_nodes =
3140 : SRV6_END_M_GTP6_D_N_NEXT,.next_nodes =
3141 : {
3142 : [SRV6_END_M_GTP6_D_NEXT_DROP] = "error-drop",
3143 : [SRV6_END_M_GTP6_D_NEXT_LOOKUP4] = "ip4-lookup",
3144 : [SRV6_END_M_GTP6_D_NEXT_LOOKUP6] = "ip6-lookup",}
3145 : ,};
3146 :
3147 32255 : VLIB_REGISTER_NODE (srv6_end_m_gtp6_d_di) =
3148 : {
3149 : .name = "srv6-end-m-gtp6-d-di",.vector_size = sizeof (u32),.format_trace =
3150 : format_srv6_end_rewrite_trace6,.type = VLIB_NODE_TYPE_INTERNAL,.n_errors =
3151 : ARRAY_LEN (srv6_end_error_v6_d_di_strings),.error_strings =
3152 : srv6_end_error_v6_d_di_strings,.n_next_nodes =
3153 : SRV6_END_M_GTP6_D_DI_N_NEXT,.next_nodes =
3154 : {
3155 : [SRV6_END_M_GTP6_D_DI_NEXT_DROP] = "error-drop",
3156 : [SRV6_END_M_GTP6_D_DI_NEXT_LOOKUP] = "ip6-lookup",}
3157 : ,};
3158 :
3159 32255 : VLIB_REGISTER_NODE (srv6_end_m_gtp6_dt) =
3160 : {
3161 : .name = "srv6-end-m-gtp6-dt",.vector_size = sizeof (u32),.format_trace =
3162 : format_srv6_end_rewrite_trace6,.type = VLIB_NODE_TYPE_INTERNAL,.n_errors =
3163 : ARRAY_LEN (srv6_end_error_v6_dt_strings),.error_strings =
3164 : srv6_end_error_v6_dt_strings,.n_next_nodes =
3165 : SRV6_END_M_GTP6_DT_N_NEXT,.next_nodes =
3166 : {
3167 : [SRV6_END_M_GTP6_DT_NEXT_DROP] = "error-drop",
3168 : [SRV6_END_M_GTP6_DT_NEXT_LOOKUP4] = "ip4-lookup",
3169 : [SRV6_END_M_GTP6_DT_NEXT_LOOKUP6] = "ip6-lookup",}
3170 : ,};
3171 :
3172 32255 : VLIB_REGISTER_NODE (srv6_t_m_gtp4_dt) =
3173 : {
3174 : .name = "srv6-t-m-gtp4-dt",.vector_size = sizeof (u32),.format_trace =
3175 : format_srv6_end_rewrite_trace6,.type = VLIB_NODE_TYPE_INTERNAL,.n_errors =
3176 : ARRAY_LEN (srv6_t_error_v4_dt_strings),.error_strings =
3177 : srv6_t_error_v4_dt_strings,.n_next_nodes =
3178 : SRV6_T_M_GTP4_DT_N_NEXT,.next_nodes =
3179 : {
3180 : [SRV6_T_M_GTP4_DT_NEXT_DROP] = "error-drop",
3181 : [SRV6_T_M_GTP4_DT_NEXT_LOOKUP4] = "ip4-lookup",
3182 : [SRV6_T_M_GTP4_DT_NEXT_LOOKUP6] = "ip6-lookup",}
3183 : ,};
3184 :
3185 : /*
3186 : * fd.io coding-style-patch-verification: ON
3187 : *
3188 : * Local Variables:
3189 : * eval: (c-set-style "gnu")
3190 : * End:
3191 : */
|