Line data Source code
1 : /*
2 : * Copyright (c) 2017-2019 Cisco and/or its affiliates.
3 : * Licensed under the Apache License, Version 2.0 (the "License");
4 : * you may not use this file except in compliance with the License.
5 : * You may obtain a copy of the License at:
6 : *
7 : * http://www.apache.org/licenses/LICENSE-2.0
8 : *
9 : * Unless required by applicable law or agreed to in writing, software
10 : * distributed under the License is distributed on an "AS IS" BASIS,
11 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : * See the License for the specific language governing permissions and
13 : * limitations under the License.
14 : */
15 :
16 : /** Generate typed init functions for multiple hash table styles... */
17 : #include <vppinfra/bihash_16_8.h>
18 : #include <vppinfra/bihash_template.h>
19 :
20 : #include <vppinfra/bihash_template.c>
21 :
22 : #undef __included_bihash_template_h__
23 :
24 : #include <vppinfra/bihash_48_8.h>
25 : #include <vppinfra/bihash_template.h>
26 :
27 : #include <vppinfra/bihash_template.c>
28 : #include <vnet/session/session_lookup.h>
29 : #include <vnet/session/session.h>
30 : #include <vnet/session/application.h>
31 :
32 : /**
33 : * Network namespace index (i.e., fib index) to session lookup table. We
34 : * should have one per network protocol type but for now we only support IP4/6
35 : */
36 : static u32 *fib_index_to_table_index[2];
37 :
38 : /* *INDENT-OFF* */
39 : /* 16 octets */
40 : typedef CLIB_PACKED (struct {
41 : union
42 : {
43 : struct
44 : {
45 : ip4_address_t src;
46 : ip4_address_t dst;
47 : u16 src_port;
48 : u16 dst_port;
49 : /* align by making this 4 octets even though its a 1-bit field
50 : * NOTE: avoid key overlap with other transports that use 5 tuples for
51 : * session identification.
52 : */
53 : u32 proto;
54 : };
55 : u64 as_u64[2];
56 : };
57 : }) v4_connection_key_t;
58 :
59 : typedef CLIB_PACKED (struct {
60 : union
61 : {
62 : struct
63 : {
64 : /* 48 octets */
65 : ip6_address_t src;
66 : ip6_address_t dst;
67 : u16 src_port;
68 : u16 dst_port;
69 : u32 proto;
70 : u64 unused;
71 : };
72 : u64 as_u64[6];
73 : };
74 : }) v6_connection_key_t;
75 : /* *INDENT-ON* */
76 :
77 : typedef clib_bihash_kv_16_8_t session_kv4_t;
78 : typedef clib_bihash_kv_48_8_t session_kv6_t;
79 :
80 : always_inline void
81 1080440 : make_v4_ss_kv (session_kv4_t * kv, ip4_address_t * lcl, ip4_address_t * rmt,
82 : u16 lcl_port, u16 rmt_port, u8 proto)
83 : {
84 1080440 : kv->key[0] = (u64) rmt->as_u32 << 32 | (u64) lcl->as_u32;
85 1080440 : kv->key[1] = (u64) proto << 32 | (u64) rmt_port << 16 | (u64) lcl_port;
86 1080440 : kv->value = ~0ULL;
87 1080440 : }
88 :
89 : always_inline void
90 525 : make_v4_listener_kv (session_kv4_t * kv, ip4_address_t * lcl, u16 lcl_port,
91 : u8 proto)
92 : {
93 525 : kv->key[0] = (u64) lcl->as_u32;
94 525 : kv->key[1] = (u64) proto << 32 | (u64) lcl_port;
95 525 : kv->value = ~0ULL;
96 525 : }
97 :
98 : always_inline void
99 17 : make_v4_proxy_kv (session_kv4_t * kv, ip4_address_t * lcl, u8 proto)
100 : {
101 17 : kv->key[0] = (u64) lcl->as_u32;
102 17 : kv->key[1] = (u64) proto << 32;
103 17 : kv->value = ~0ULL;
104 17 : }
105 :
106 : always_inline void
107 800 : make_v4_ss_kv_from_tc (session_kv4_t * kv, transport_connection_t * tc)
108 : {
109 800 : make_v4_ss_kv (kv, &tc->lcl_ip.ip4, &tc->rmt_ip.ip4, tc->lcl_port,
110 800 : tc->rmt_port, tc->proto);
111 800 : }
112 :
113 : always_inline void
114 36 : make_v6_ss_kv (session_kv6_t * kv, ip6_address_t * lcl, ip6_address_t * rmt,
115 : u16 lcl_port, u16 rmt_port, u8 proto)
116 : {
117 36 : kv->key[0] = lcl->as_u64[0];
118 36 : kv->key[1] = lcl->as_u64[1];
119 36 : kv->key[2] = rmt->as_u64[0];
120 36 : kv->key[3] = rmt->as_u64[1];
121 36 : kv->key[4] = (u64) proto << 32 | (u64) rmt_port << 16 | (u64) lcl_port;
122 36 : kv->key[5] = 0;
123 36 : kv->value = ~0ULL;
124 36 : }
125 :
126 : always_inline void
127 36 : make_v6_listener_kv (session_kv6_t * kv, ip6_address_t * lcl, u16 lcl_port,
128 : u8 proto)
129 : {
130 36 : kv->key[0] = lcl->as_u64[0];
131 36 : kv->key[1] = lcl->as_u64[1];
132 36 : kv->key[2] = 0;
133 36 : kv->key[3] = 0;
134 36 : kv->key[4] = (u64) proto << 32 | (u64) lcl_port;
135 36 : kv->key[5] = 0;
136 36 : kv->value = ~0ULL;
137 36 : }
138 :
139 : always_inline void
140 0 : make_v6_proxy_kv (session_kv6_t * kv, ip6_address_t * lcl, u8 proto)
141 : {
142 0 : kv->key[0] = lcl->as_u64[0];
143 0 : kv->key[1] = lcl->as_u64[1];
144 0 : kv->key[2] = 0;
145 0 : kv->key[3] = 0;
146 0 : kv->key[4] = (u64) proto << 32;
147 0 : kv->key[5] = 0;
148 0 : kv->value = ~0ULL;
149 0 : }
150 :
151 : always_inline void
152 14 : make_v6_ss_kv_from_tc (session_kv6_t * kv, transport_connection_t * tc)
153 : {
154 14 : make_v6_ss_kv (kv, &tc->lcl_ip.ip6, &tc->rmt_ip.ip6, tc->lcl_port,
155 14 : tc->rmt_port, tc->proto);
156 14 : }
157 :
158 : static session_table_t *
159 689 : session_table_get_or_alloc (u8 fib_proto, u32 fib_index)
160 : {
161 : session_table_t *st;
162 : u32 table_index;
163 689 : ASSERT (fib_index != ~0);
164 689 : if (vec_len (fib_index_to_table_index[fib_proto]) > fib_index &&
165 651 : fib_index_to_table_index[fib_proto][fib_index] != ~0)
166 : {
167 651 : table_index = fib_index_to_table_index[fib_proto][fib_index];
168 651 : return session_table_get (table_index);
169 : }
170 : else
171 : {
172 38 : st = session_table_alloc ();
173 38 : table_index = session_table_index (st);
174 77 : vec_validate_init_empty (fib_index_to_table_index[fib_proto], fib_index,
175 : ~0);
176 38 : fib_index_to_table_index[fib_proto][fib_index] = table_index;
177 38 : st->active_fib_proto = fib_proto;
178 38 : session_table_init (st, fib_proto);
179 38 : return st;
180 : }
181 : }
182 :
183 : static session_table_t *
184 445 : session_table_get_or_alloc_for_connection (transport_connection_t * tc)
185 : {
186 : u32 fib_proto;
187 445 : fib_proto = transport_connection_fib_proto (tc);
188 445 : return session_table_get_or_alloc (fib_proto, tc->fib_index);
189 : }
190 :
191 : static session_table_t *
192 369 : session_table_get_for_connection (transport_connection_t * tc)
193 : {
194 369 : u32 fib_proto = transport_connection_fib_proto (tc);
195 369 : if (vec_len (fib_index_to_table_index[fib_proto]) <= tc->fib_index)
196 0 : return 0;
197 : return
198 369 : session_table_get (fib_index_to_table_index[fib_proto][tc->fib_index]);
199 : }
200 :
201 : static session_table_t *
202 1079680 : session_table_get_for_fib_index (u32 fib_proto, u32 fib_index)
203 : {
204 1079680 : if (vec_len (fib_index_to_table_index[fib_proto]) <= fib_index)
205 0 : return 0;
206 1079680 : return session_table_get (fib_index_to_table_index[fib_proto][fib_index]);
207 : }
208 :
209 : u32
210 76 : session_lookup_get_index_for_fib (u32 fib_proto, u32 fib_index)
211 : {
212 76 : if (vec_len (fib_index_to_table_index[fib_proto]) <= fib_index)
213 0 : return SESSION_TABLE_INVALID_INDEX;
214 76 : return fib_index_to_table_index[fib_proto][fib_index];
215 : }
216 :
217 : u32
218 54 : session_lookup_get_or_alloc_index_for_fib (u32 fib_proto, u32 fib_index)
219 : {
220 : session_table_t *st;
221 54 : st = session_table_get_or_alloc (fib_proto, fib_index);
222 54 : return session_table_index (st);
223 : }
224 :
225 : /**
226 : * Add transport connection to a session table
227 : *
228 : * Session lookup 5-tuple (src-ip, dst-ip, src-port, dst-port, session-type)
229 : * is added to requested session table.
230 : *
231 : * @param tc transport connection to be added
232 : * @param value value to be stored
233 : *
234 : * @return non-zero if failure
235 : */
236 : int
237 313 : session_lookup_add_connection (transport_connection_t * tc, u64 value)
238 : {
239 : session_table_t *st;
240 : session_kv4_t kv4;
241 : session_kv6_t kv6;
242 :
243 313 : st = session_table_get_or_alloc_for_connection (tc);
244 313 : if (!st)
245 0 : return -1;
246 313 : if (tc->is_ip4)
247 : {
248 311 : make_v4_ss_kv_from_tc (&kv4, tc);
249 311 : kv4.value = value;
250 311 : return clib_bihash_add_del_16_8 (&st->v4_session_hash, &kv4,
251 : 1 /* is_add */ );
252 : }
253 : else
254 : {
255 2 : make_v6_ss_kv_from_tc (&kv6, tc);
256 2 : kv6.value = value;
257 2 : return clib_bihash_add_del_48_8 (&st->v6_session_hash, &kv6,
258 : 1 /* is_add */ );
259 : }
260 : }
261 :
262 : int
263 75 : session_lookup_add_session_endpoint (u32 table_index,
264 : session_endpoint_t * sep, u64 value)
265 : {
266 : session_table_t *st;
267 : session_kv4_t kv4;
268 : session_kv6_t kv6;
269 :
270 75 : st = session_table_get (table_index);
271 75 : if (!st)
272 0 : return -1;
273 75 : if (sep->is_ip4)
274 : {
275 65 : make_v4_listener_kv (&kv4, &sep->ip.ip4, sep->port,
276 65 : sep->transport_proto);
277 65 : kv4.value = value;
278 65 : return clib_bihash_add_del_16_8 (&st->v4_session_hash, &kv4, 1);
279 : }
280 : else
281 : {
282 10 : make_v6_listener_kv (&kv6, &sep->ip.ip6, sep->port,
283 10 : sep->transport_proto);
284 10 : kv6.value = value;
285 10 : return clib_bihash_add_del_48_8 (&st->v6_session_hash, &kv6, 1);
286 : }
287 : }
288 :
289 : int
290 21 : session_lookup_del_session_endpoint (u32 table_index,
291 : session_endpoint_t * sep)
292 : {
293 : session_table_t *st;
294 : session_kv4_t kv4;
295 : session_kv6_t kv6;
296 :
297 21 : st = session_table_get (table_index);
298 21 : if (!st)
299 0 : return -1;
300 21 : if (sep->is_ip4)
301 : {
302 15 : make_v4_listener_kv (&kv4, &sep->ip.ip4, sep->port,
303 15 : sep->transport_proto);
304 15 : return clib_bihash_add_del_16_8 (&st->v4_session_hash, &kv4, 0);
305 : }
306 : else
307 : {
308 6 : make_v6_listener_kv (&kv6, &sep->ip.ip6, sep->port,
309 6 : sep->transport_proto);
310 6 : return clib_bihash_add_del_48_8 (&st->v6_session_hash, &kv6, 0);
311 : }
312 : }
313 :
314 : int
315 3 : session_lookup_del_session_endpoint2 (session_endpoint_t * sep)
316 : {
317 : fib_protocol_t fib_proto;
318 : session_table_t *st;
319 : session_kv4_t kv4;
320 : session_kv6_t kv6;
321 :
322 3 : fib_proto = sep->is_ip4 ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6;
323 3 : st = session_table_get_for_fib_index (fib_proto, sep->fib_index);
324 3 : if (!st)
325 0 : return -1;
326 3 : if (sep->is_ip4)
327 : {
328 3 : make_v4_listener_kv (&kv4, &sep->ip.ip4, sep->port,
329 3 : sep->transport_proto);
330 3 : return clib_bihash_add_del_16_8 (&st->v4_session_hash, &kv4, 0);
331 : }
332 : else
333 : {
334 0 : make_v6_listener_kv (&kv6, &sep->ip.ip6, sep->port,
335 0 : sep->transport_proto);
336 0 : return clib_bihash_add_del_48_8 (&st->v6_session_hash, &kv6, 0);
337 : }
338 : }
339 :
340 : /**
341 : * Delete transport connection from session table
342 : *
343 : * @param table_index session table index
344 : * @param tc transport connection to be removed
345 : *
346 : * @return non-zero if failure
347 : */
348 : int
349 237 : session_lookup_del_connection (transport_connection_t * tc)
350 : {
351 : session_table_t *st;
352 : session_kv4_t kv4;
353 : session_kv6_t kv6;
354 :
355 237 : st = session_table_get_for_connection (tc);
356 237 : if (!st)
357 0 : return -1;
358 237 : if (tc->is_ip4)
359 : {
360 227 : make_v4_ss_kv_from_tc (&kv4, tc);
361 227 : return clib_bihash_add_del_16_8 (&st->v4_session_hash, &kv4,
362 : 0 /* is_add */ );
363 : }
364 : else
365 : {
366 10 : make_v6_ss_kv_from_tc (&kv6, tc);
367 10 : return clib_bihash_add_del_48_8 (&st->v6_session_hash, &kv6,
368 : 0 /* is_add */ );
369 : }
370 : }
371 :
372 : int
373 253 : session_lookup_del_session (session_t * s)
374 : {
375 : transport_connection_t *ts;
376 253 : ts = transport_get_connection (session_get_transport_proto (s),
377 253 : s->connection_index, s->thread_index);
378 253 : if (!ts || (ts->flags & TRANSPORT_CONNECTION_F_NO_LOOKUP))
379 76 : return 0;
380 177 : return session_lookup_del_connection (ts);
381 : }
382 :
383 : static u8
384 470 : session_lookup_action_index_is_valid (u32 action_index)
385 : {
386 470 : if (action_index == SESSION_RULES_TABLE_ACTION_ALLOW
387 467 : || action_index == SESSION_RULES_TABLE_INVALID_INDEX)
388 454 : return 0;
389 16 : return 1;
390 : }
391 :
392 : static u64
393 15 : session_lookup_action_to_handle (u32 action_index)
394 : {
395 15 : switch (action_index)
396 : {
397 8 : case SESSION_RULES_TABLE_ACTION_DROP:
398 8 : return SESSION_DROP_HANDLE;
399 0 : case SESSION_RULES_TABLE_ACTION_ALLOW:
400 : case SESSION_RULES_TABLE_INVALID_INDEX:
401 0 : return SESSION_INVALID_HANDLE;
402 7 : default:
403 : /* application index */
404 7 : return action_index;
405 : }
406 : }
407 :
408 : static session_t *
409 6 : session_lookup_app_listen_session (u32 app_index, u8 fib_proto,
410 : u8 transport_proto)
411 : {
412 : application_t *app;
413 6 : app = application_get_if_valid (app_index);
414 6 : if (!app)
415 0 : return 0;
416 :
417 6 : return app_worker_first_listener (application_get_default_worker (app),
418 : fib_proto, transport_proto);
419 : }
420 :
421 : static session_t *
422 6 : session_lookup_action_to_session (u32 action_index, u8 fib_proto,
423 : u8 transport_proto)
424 : {
425 : u32 app_index;
426 6 : app_index = session_lookup_action_to_handle (action_index);
427 : /* Nothing sophisticated for now, action index is app index */
428 6 : return session_lookup_app_listen_session (app_index, fib_proto,
429 : transport_proto);
430 : }
431 :
432 : /** UNUSED */
433 : session_t *
434 0 : session_lookup_rules_table_session4 (session_table_t * st, u8 proto,
435 : ip4_address_t * lcl, u16 lcl_port,
436 : ip4_address_t * rmt, u16 rmt_port)
437 : {
438 0 : session_rules_table_t *srt = &st->session_rules[proto];
439 : u32 action_index, app_index;
440 0 : action_index = session_rules_table_lookup4 (srt, lcl, rmt, lcl_port,
441 : rmt_port);
442 0 : app_index = session_lookup_action_to_handle (action_index);
443 : /* Nothing sophisticated for now, action index is app index */
444 0 : return session_lookup_app_listen_session (app_index, FIB_PROTOCOL_IP4,
445 : proto);
446 : }
447 :
448 : /** UNUSED */
449 : session_t *
450 0 : session_lookup_rules_table_session6 (session_table_t * st, u8 proto,
451 : ip6_address_t * lcl, u16 lcl_port,
452 : ip6_address_t * rmt, u16 rmt_port)
453 : {
454 0 : session_rules_table_t *srt = &st->session_rules[proto];
455 : u32 action_index, app_index;
456 0 : action_index = session_rules_table_lookup6 (srt, lcl, rmt, lcl_port,
457 : rmt_port);
458 0 : app_index = session_lookup_action_to_handle (action_index);
459 0 : return session_lookup_app_listen_session (app_index, FIB_PROTOCOL_IP6,
460 : proto);
461 : }
462 :
463 : /**
464 : * Lookup listener for session endpoint in table
465 : *
466 : * @param table_index table where the endpoint should be looked up
467 : * @param sep session endpoint to be looked up
468 : * @param use_rules flag that indicates if the session rules of the table
469 : * should be used
470 : * @return invalid handle if nothing is found, the handle of a valid listener
471 : * or an action derived handle if a rule is hit
472 : */
473 : u64
474 124 : session_lookup_endpoint_listener (u32 table_index, session_endpoint_t * sep,
475 : u8 use_rules)
476 : {
477 : session_rules_table_t *srt;
478 : session_table_t *st;
479 : u32 ai;
480 : int rv;
481 :
482 124 : st = session_table_get (table_index);
483 124 : if (!st)
484 0 : return SESSION_INVALID_HANDLE;
485 124 : if (sep->is_ip4)
486 : {
487 : session_kv4_t kv4;
488 : ip4_address_t lcl4;
489 :
490 109 : make_v4_listener_kv (&kv4, &sep->ip.ip4, sep->port,
491 109 : sep->transport_proto);
492 109 : rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
493 109 : if (rv == 0)
494 1 : return kv4.value;
495 108 : if (use_rules)
496 : {
497 108 : clib_memset (&lcl4, 0, sizeof (lcl4));
498 108 : srt = &st->session_rules[sep->transport_proto];
499 108 : ai = session_rules_table_lookup4 (srt, &lcl4, &sep->ip.ip4, 0,
500 108 : sep->port);
501 108 : if (session_lookup_action_index_is_valid (ai))
502 0 : return session_lookup_action_to_handle (ai);
503 : }
504 : }
505 : else
506 : {
507 : session_kv6_t kv6;
508 : ip6_address_t lcl6;
509 :
510 15 : make_v6_listener_kv (&kv6, &sep->ip.ip6, sep->port,
511 15 : sep->transport_proto);
512 15 : rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
513 15 : if (rv == 0)
514 1 : return kv6.value;
515 :
516 14 : if (use_rules)
517 : {
518 14 : clib_memset (&lcl6, 0, sizeof (lcl6));
519 14 : srt = &st->session_rules[sep->transport_proto];
520 14 : ai = session_rules_table_lookup6 (srt, &lcl6, &sep->ip.ip6, 0,
521 14 : sep->port);
522 14 : if (session_lookup_action_index_is_valid (ai))
523 0 : return session_lookup_action_to_handle (ai);
524 : }
525 : }
526 122 : return SESSION_INVALID_HANDLE;
527 : }
528 :
529 : /**
530 : * Look up endpoint in local session table
531 : *
532 : * The result, for now, is an application index and it may in the future
533 : * be extended to a more complicated "action object". The only action we
534 : * emulate now is "drop" and for that we return a special app index.
535 : *
536 : * Lookup logic is to check in order:
537 : * - the rules in the table (connect acls)
538 : * - session sub-table for a listener
539 : * - session sub-table for a local listener (zeroed addr)
540 : *
541 : * @param table_index table where the lookup should be done
542 : * @param sep session endpoint to be looked up
543 : * @return session handle that can be interpreted as an adjacency
544 : */
545 : u64
546 35 : session_lookup_local_endpoint (u32 table_index, session_endpoint_t * sep)
547 : {
548 : session_rules_table_t *srt;
549 : session_table_t *st;
550 : u32 ai;
551 : int rv;
552 :
553 35 : st = session_table_get (table_index);
554 35 : if (!st)
555 0 : return SESSION_INVALID_INDEX;
556 35 : ASSERT (st->is_local);
557 :
558 35 : if (sep->is_ip4)
559 : {
560 : session_kv4_t kv4;
561 : ip4_address_t lcl4;
562 :
563 : /*
564 : * Check if endpoint has special rules associated
565 : */
566 32 : clib_memset (&lcl4, 0, sizeof (lcl4));
567 32 : srt = &st->session_rules[sep->transport_proto];
568 32 : ai = session_rules_table_lookup4 (srt, &lcl4, &sep->ip.ip4, 0,
569 32 : sep->port);
570 32 : if (session_lookup_action_index_is_valid (ai))
571 23 : return session_lookup_action_to_handle (ai);
572 :
573 : /*
574 : * Check if session endpoint is a listener
575 : */
576 23 : make_v4_listener_kv (&kv4, &sep->ip.ip4, sep->port,
577 23 : sep->transport_proto);
578 23 : rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
579 23 : if (rv == 0)
580 3 : return kv4.value;
581 :
582 : /*
583 : * Zero out the ip. Logic is that connect to local ips, say
584 : * 127.0.0.1:port, can match 0.0.0.0:port
585 : */
586 20 : if (ip4_is_local_host (&sep->ip.ip4))
587 : {
588 11 : kv4.key[0] = 0;
589 11 : rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
590 11 : if (rv == 0)
591 10 : return kv4.value;
592 : }
593 : else
594 : {
595 9 : kv4.key[0] = 0;
596 : }
597 :
598 : /*
599 : * Zero out the port and check if we have proxy
600 : */
601 10 : kv4.key[1] = 0;
602 10 : rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
603 10 : if (rv == 0)
604 1 : return kv4.value;
605 : }
606 : else
607 : {
608 : session_kv6_t kv6;
609 : ip6_address_t lcl6;
610 :
611 3 : clib_memset (&lcl6, 0, sizeof (lcl6));
612 3 : srt = &st->session_rules[sep->transport_proto];
613 3 : ai = session_rules_table_lookup6 (srt, &lcl6, &sep->ip.ip6, 0,
614 3 : sep->port);
615 3 : if (session_lookup_action_index_is_valid (ai))
616 3 : return session_lookup_action_to_handle (ai);
617 :
618 3 : make_v6_listener_kv (&kv6, &sep->ip.ip6, sep->port,
619 3 : sep->transport_proto);
620 3 : rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
621 3 : if (rv == 0)
622 0 : return kv6.value;
623 :
624 : /*
625 : * Zero out the ip. Same logic as above.
626 : */
627 :
628 3 : if (ip6_is_local_host (&sep->ip.ip6))
629 : {
630 3 : kv6.key[0] = kv6.key[1] = 0;
631 3 : rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
632 3 : if (rv == 0)
633 3 : return kv6.value;
634 : }
635 : else
636 : {
637 0 : kv6.key[0] = kv6.key[1] = 0;
638 : }
639 :
640 : /*
641 : * Zero out the port. Same logic as above.
642 : */
643 0 : kv6.key[4] = kv6.key[5] = 0;
644 0 : rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
645 0 : if (rv == 0)
646 0 : return kv6.value;
647 : }
648 9 : return SESSION_INVALID_HANDLE;
649 : }
650 :
651 : static inline session_t *
652 310 : session_lookup_listener4_i (session_table_t * st, ip4_address_t * lcl,
653 : u16 lcl_port, u8 proto, u8 use_wildcard)
654 : {
655 : session_kv4_t kv4;
656 : int rv;
657 :
658 : /*
659 : * First, try a fully formed listener
660 : */
661 310 : make_v4_listener_kv (&kv4, lcl, lcl_port, proto);
662 310 : rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
663 310 : if (rv == 0)
664 287 : return listen_session_get ((u32) kv4.value);
665 :
666 : /*
667 : * Zero out the lcl ip and check if any 0/0 port binds have been done
668 : */
669 23 : if (use_wildcard)
670 : {
671 20 : kv4.key[0] = 0;
672 20 : rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
673 20 : if (rv == 0)
674 6 : return listen_session_get ((u32) kv4.value);
675 : }
676 : else
677 : {
678 3 : kv4.key[0] = 0;
679 : }
680 :
681 : /*
682 : * Zero out port and check if we have a proxy set up for our ip
683 : */
684 17 : make_v4_proxy_kv (&kv4, lcl, proto);
685 17 : rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
686 17 : if (rv == 0)
687 1 : return listen_session_get ((u32) kv4.value);
688 :
689 16 : return 0;
690 : }
691 :
692 : session_t *
693 0 : session_lookup_listener4 (u32 fib_index, ip4_address_t * lcl, u16 lcl_port,
694 : u8 proto, u8 use_wildcard)
695 : {
696 : session_table_t *st;
697 0 : st = session_table_get_for_fib_index (FIB_PROTOCOL_IP4, fib_index);
698 0 : if (!st)
699 0 : return 0;
700 0 : return session_lookup_listener4_i (st, lcl, lcl_port, proto, use_wildcard);
701 : }
702 :
703 : static session_t *
704 2 : session_lookup_listener6_i (session_table_t * st, ip6_address_t * lcl,
705 : u16 lcl_port, u8 proto, u8 ip_wildcard)
706 : {
707 : session_kv6_t kv6;
708 : int rv;
709 :
710 2 : make_v6_listener_kv (&kv6, lcl, lcl_port, proto);
711 2 : rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
712 2 : if (rv == 0)
713 2 : return listen_session_get ((u32) kv6.value);
714 :
715 : /* Zero out the lcl ip */
716 0 : if (ip_wildcard)
717 : {
718 0 : kv6.key[0] = kv6.key[1] = 0;
719 0 : rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
720 0 : if (rv == 0)
721 0 : return listen_session_get ((u32) kv6.value);
722 : }
723 : else
724 : {
725 0 : kv6.key[0] = kv6.key[1] = 0;
726 : }
727 :
728 0 : make_v6_proxy_kv (&kv6, lcl, proto);
729 0 : rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
730 0 : if (rv == 0)
731 0 : return listen_session_get ((u32) kv6.value);
732 0 : return 0;
733 : }
734 :
735 : session_t *
736 0 : session_lookup_listener6 (u32 fib_index, ip6_address_t * lcl, u16 lcl_port,
737 : u8 proto, u8 use_wildcard)
738 : {
739 : session_table_t *st;
740 0 : st = session_table_get_for_fib_index (FIB_PROTOCOL_IP6, fib_index);
741 0 : if (!st)
742 0 : return 0;
743 0 : return session_lookup_listener6_i (st, lcl, lcl_port, proto, use_wildcard);
744 : }
745 :
746 : /**
747 : * Lookup listener, exact or proxy (inaddr_any:0) match
748 : */
749 : session_t *
750 7 : session_lookup_listener (u32 table_index, session_endpoint_t * sep)
751 : {
752 : session_table_t *st;
753 7 : st = session_table_get (table_index);
754 7 : if (!st)
755 1 : return 0;
756 6 : if (sep->is_ip4)
757 6 : return session_lookup_listener4_i (st, &sep->ip.ip4, sep->port,
758 6 : sep->transport_proto, 0);
759 : else
760 0 : return session_lookup_listener6_i (st, &sep->ip.ip6, sep->port,
761 0 : sep->transport_proto, 0);
762 : return 0;
763 : }
764 :
765 : /**
766 : * Lookup listener wildcard match
767 : */
768 : session_t *
769 0 : session_lookup_listener_wildcard (u32 table_index, session_endpoint_t * sep)
770 : {
771 : session_table_t *st;
772 0 : st = session_table_get (table_index);
773 0 : if (!st)
774 0 : return 0;
775 0 : if (sep->is_ip4)
776 0 : return session_lookup_listener4_i (st, &sep->ip.ip4, sep->port,
777 0 : sep->transport_proto,
778 : 1 /* use_wildcard */ );
779 : else
780 0 : return session_lookup_listener6_i (st, &sep->ip.ip6, sep->port,
781 0 : sep->transport_proto,
782 : 1 /* use_wildcard */ );
783 : return 0;
784 : }
785 :
786 : int
787 132 : session_lookup_add_half_open (transport_connection_t * tc, u64 value)
788 : {
789 : session_table_t *st;
790 : session_kv4_t kv4;
791 : session_kv6_t kv6;
792 :
793 132 : st = session_table_get_or_alloc_for_connection (tc);
794 132 : if (!st)
795 0 : return 0;
796 132 : if (tc->is_ip4)
797 : {
798 131 : make_v4_ss_kv_from_tc (&kv4, tc);
799 131 : kv4.value = value;
800 131 : return clib_bihash_add_del_16_8 (&st->v4_half_open_hash, &kv4,
801 : 1 /* is_add */ );
802 : }
803 : else
804 : {
805 1 : make_v6_ss_kv_from_tc (&kv6, tc);
806 1 : kv6.value = value;
807 1 : return clib_bihash_add_del_48_8 (&st->v6_half_open_hash, &kv6,
808 : 1 /* is_add */ );
809 : }
810 : }
811 :
812 : int
813 132 : session_lookup_del_half_open (transport_connection_t * tc)
814 : {
815 : session_table_t *st;
816 : session_kv4_t kv4;
817 : session_kv6_t kv6;
818 :
819 132 : st = session_table_get_for_connection (tc);
820 132 : if (!st)
821 0 : return -1;
822 132 : if (tc->is_ip4)
823 : {
824 131 : make_v4_ss_kv_from_tc (&kv4, tc);
825 131 : return clib_bihash_add_del_16_8 (&st->v4_half_open_hash, &kv4,
826 : 0 /* is_add */ );
827 : }
828 : else
829 : {
830 1 : make_v6_ss_kv_from_tc (&kv6, tc);
831 1 : return clib_bihash_add_del_48_8 (&st->v6_half_open_hash, &kv6,
832 : 0 /* is_add */ );
833 : }
834 : }
835 :
836 : u64
837 0 : session_lookup_half_open_handle (transport_connection_t * tc)
838 : {
839 : session_table_t *st;
840 : session_kv4_t kv4;
841 : session_kv6_t kv6;
842 : int rv;
843 :
844 0 : st = session_table_get_for_fib_index (transport_connection_fib_proto (tc),
845 : tc->fib_index);
846 0 : if (!st)
847 0 : return HALF_OPEN_LOOKUP_INVALID_VALUE;
848 0 : if (tc->is_ip4)
849 : {
850 0 : make_v4_ss_kv (&kv4, &tc->lcl_ip.ip4, &tc->rmt_ip.ip4, tc->lcl_port,
851 0 : tc->rmt_port, tc->proto);
852 0 : rv = clib_bihash_search_inline_16_8 (&st->v4_half_open_hash, &kv4);
853 0 : if (rv == 0)
854 0 : return kv4.value;
855 : }
856 : else
857 : {
858 0 : make_v6_ss_kv (&kv6, &tc->lcl_ip.ip6, &tc->rmt_ip.ip6, tc->lcl_port,
859 0 : tc->rmt_port, tc->proto);
860 0 : rv = clib_bihash_search_inline_48_8 (&st->v6_half_open_hash, &kv6);
861 0 : if (rv == 0)
862 0 : return kv6.value;
863 : }
864 0 : return HALF_OPEN_LOOKUP_INVALID_VALUE;
865 : }
866 :
867 : transport_connection_t *
868 0 : session_lookup_half_open_connection (u64 handle, u8 proto, u8 is_ip4)
869 : {
870 0 : if (handle != HALF_OPEN_LOOKUP_INVALID_VALUE)
871 : {
872 0 : u32 sst = session_type_from_proto_and_ip (proto, is_ip4);
873 0 : return transport_get_half_open (sst, handle & 0xFFFFFFFF);
874 : }
875 0 : return 0;
876 : }
877 :
878 : /**
879 : * Lookup connection with ip4 and transport layer information
880 : *
881 : * This is used on the fast path so it needs to be fast. Thereby,
882 : * duplication of code and 'hacks' allowed.
883 : *
884 : * The lookup is incremental and returns whenever something is matched. The
885 : * steps are:
886 : * - Try to find an established session
887 : * - Try to find a half-open connection
888 : * - Try session rules table
889 : * - Try to find a fully-formed or local source wildcarded (listener bound to
890 : * all interfaces) listener session
891 : * - return 0
892 : *
893 : * @param fib_index index of fib wherein the connection was received
894 : * @param lcl local ip4 address
895 : * @param rmt remote ip4 address
896 : * @param lcl_port local port
897 : * @param rmt_port remote port
898 : * @param proto transport protocol (e.g., tcp, udp)
899 : * @param thread_index thread index for request
900 : * @param is_filtered return flag that indicates if connection was filtered.
901 : *
902 : * @return pointer to transport connection, if one is found, 0 otherwise
903 : */
904 : transport_connection_t *
905 1021470 : session_lookup_connection_wt4 (u32 fib_index, ip4_address_t * lcl,
906 : ip4_address_t * rmt, u16 lcl_port,
907 : u16 rmt_port, u8 proto, u32 thread_index,
908 : u8 * result)
909 : {
910 : session_table_t *st;
911 : session_kv4_t kv4;
912 : session_t *s;
913 : u32 action_index;
914 : int rv;
915 :
916 1021470 : st = session_table_get_for_fib_index (FIB_PROTOCOL_IP4, fib_index);
917 1021470 : if (PREDICT_FALSE (!st))
918 0 : return 0;
919 :
920 : /*
921 : * Lookup session amongst established ones
922 : */
923 1021470 : make_v4_ss_kv (&kv4, lcl, rmt, lcl_port, rmt_port, proto);
924 1021470 : rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
925 1021470 : if (rv == 0)
926 : {
927 1021050 : if (PREDICT_FALSE ((u32) (kv4.value >> 32) != thread_index))
928 : {
929 0 : *result = SESSION_LOOKUP_RESULT_WRONG_THREAD;
930 0 : return 0;
931 : }
932 1021050 : s = session_get (kv4.value & 0xFFFFFFFFULL, thread_index);
933 1021050 : return transport_get_connection (proto, s->connection_index,
934 : thread_index);
935 : }
936 :
937 : /*
938 : * Try half-open connections
939 : */
940 417 : rv = clib_bihash_search_inline_16_8 (&st->v4_half_open_hash, &kv4);
941 417 : if (rv == 0)
942 131 : return transport_get_half_open (proto, kv4.value & 0xFFFFFFFF);
943 :
944 : /*
945 : * Check the session rules table
946 : */
947 286 : action_index = session_rules_table_lookup4 (&st->session_rules[proto], lcl,
948 : rmt, lcl_port, rmt_port);
949 286 : if (session_lookup_action_index_is_valid (action_index))
950 : {
951 5 : if (action_index == SESSION_RULES_TABLE_ACTION_DROP)
952 : {
953 1 : *result = SESSION_LOOKUP_RESULT_FILTERED;
954 1 : return 0;
955 : }
956 4 : if ((s = session_lookup_action_to_session (action_index,
957 : FIB_PROTOCOL_IP4, proto)))
958 4 : return transport_get_listener (proto, s->connection_index);
959 0 : return 0;
960 : }
961 :
962 : /*
963 : * If nothing is found, check if any listener is available
964 : */
965 281 : s = session_lookup_listener4_i (st, lcl, lcl_port, proto, 1);
966 281 : if (s)
967 269 : return transport_get_listener (proto, s->connection_index);
968 :
969 12 : return 0;
970 : }
971 :
972 : /**
973 : * Lookup connection with ip4 and transport layer information
974 : *
975 : * Not optimized. Lookup logic is identical to that of
976 : * @ref session_lookup_connection_wt4
977 : *
978 : * @param fib_index index of the fib wherein the connection was received
979 : * @param lcl local ip4 address
980 : * @param rmt remote ip4 address
981 : * @param lcl_port local port
982 : * @param rmt_port remote port
983 : * @param proto transport protocol (e.g., tcp, udp)
984 : *
985 : * @return pointer to transport connection, if one is found, 0 otherwise
986 : */
987 : transport_connection_t *
988 2 : session_lookup_connection4 (u32 fib_index, ip4_address_t * lcl,
989 : ip4_address_t * rmt, u16 lcl_port, u16 rmt_port,
990 : u8 proto)
991 : {
992 : session_table_t *st;
993 : session_kv4_t kv4;
994 : session_t *s;
995 : u32 action_index;
996 : int rv;
997 :
998 2 : st = session_table_get_for_fib_index (FIB_PROTOCOL_IP4, fib_index);
999 2 : if (PREDICT_FALSE (!st))
1000 0 : return 0;
1001 :
1002 : /*
1003 : * Lookup session amongst established ones
1004 : */
1005 2 : make_v4_ss_kv (&kv4, lcl, rmt, lcl_port, rmt_port, proto);
1006 2 : rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
1007 2 : if (rv == 0)
1008 : {
1009 0 : s = session_get_from_handle (kv4.value);
1010 0 : return transport_get_connection (proto, s->connection_index,
1011 0 : s->thread_index);
1012 : }
1013 :
1014 : /*
1015 : * Try half-open connections
1016 : */
1017 2 : rv = clib_bihash_search_inline_16_8 (&st->v4_half_open_hash, &kv4);
1018 2 : if (rv == 0)
1019 0 : return transport_get_half_open (proto, kv4.value & 0xFFFFFFFF);
1020 :
1021 : /*
1022 : * Check the session rules table
1023 : */
1024 2 : action_index = session_rules_table_lookup4 (&st->session_rules[proto], lcl,
1025 : rmt, lcl_port, rmt_port);
1026 2 : if (session_lookup_action_index_is_valid (action_index))
1027 : {
1028 1 : if (action_index == SESSION_RULES_TABLE_ACTION_DROP)
1029 0 : return 0;
1030 1 : if ((s = session_lookup_action_to_session (action_index,
1031 : FIB_PROTOCOL_IP4, proto)))
1032 1 : return transport_get_listener (proto, s->connection_index);
1033 0 : return 0;
1034 : }
1035 :
1036 : /*
1037 : * If nothing is found, check if any listener is available
1038 : */
1039 1 : s = session_lookup_listener4_i (st, lcl, lcl_port, proto, 1);
1040 1 : if (s)
1041 0 : return transport_get_listener (proto, s->connection_index);
1042 :
1043 1 : return 0;
1044 : }
1045 :
1046 : /**
1047 : * Lookup session with ip4 and transport layer information
1048 : *
1049 : * Important note: this may look into another thread's pool table
1050 : *
1051 : * Lookup logic is similar to that of @ref session_lookup_connection_wt4 but
1052 : * this returns a session as opposed to a transport connection and it does not
1053 : * try to lookup half-open sessions.
1054 : *
1055 : * Typically used by dgram connections
1056 : */
1057 : session_t *
1058 58172 : session_lookup_safe4 (u32 fib_index, ip4_address_t * lcl, ip4_address_t * rmt,
1059 : u16 lcl_port, u16 rmt_port, u8 proto)
1060 : {
1061 : session_table_t *st;
1062 : session_kv4_t kv4;
1063 : session_t *s;
1064 : u32 action_index;
1065 : int rv;
1066 :
1067 58172 : st = session_table_get_for_fib_index (FIB_PROTOCOL_IP4, fib_index);
1068 58172 : if (PREDICT_FALSE (!st))
1069 0 : return 0;
1070 :
1071 : /*
1072 : * Lookup session amongst established ones
1073 : */
1074 58172 : make_v4_ss_kv (&kv4, lcl, rmt, lcl_port, rmt_port, proto);
1075 58172 : rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
1076 58172 : if (rv == 0)
1077 58149 : return session_get_from_handle_safe (kv4.value);
1078 :
1079 : /*
1080 : * Check the session rules table
1081 : */
1082 23 : action_index = session_rules_table_lookup4 (&st->session_rules[proto], lcl,
1083 : rmt, lcl_port, rmt_port);
1084 23 : if (session_lookup_action_index_is_valid (action_index))
1085 : {
1086 1 : if (action_index == SESSION_RULES_TABLE_ACTION_DROP)
1087 0 : return 0;
1088 1 : return session_lookup_action_to_session (action_index, FIB_PROTOCOL_IP4,
1089 : proto);
1090 : }
1091 :
1092 : /*
1093 : * If nothing is found, check if any listener is available
1094 : */
1095 22 : if ((s = session_lookup_listener4_i (st, lcl, lcl_port, proto, 1)))
1096 22 : return s;
1097 :
1098 0 : return 0;
1099 : }
1100 :
1101 : /**
1102 : * Lookup connection with ip6 and transport layer information
1103 : *
1104 : * This is used on the fast path so it needs to be fast. Thereby,
1105 : * duplication of code and 'hacks' allowed.
1106 : *
1107 : * The lookup is incremental and returns whenever something is matched. The
1108 : * steps are:
1109 : * - Try to find an established session
1110 : * - Try to find a half-open connection
1111 : * - Try session rules table
1112 : * - Try to find a fully-formed or local source wildcarded (listener bound to
1113 : * all interfaces) listener session
1114 : * - return 0
1115 : *
1116 : * @param fib_index index of the fib wherein the connection was received
1117 : * @param lcl local ip6 address
1118 : * @param rmt remote ip6 address
1119 : * @param lcl_port local port
1120 : * @param rmt_port remote port
1121 : * @param proto transport protocol (e.g., tcp, udp)
1122 : * @param thread_index thread index for request
1123 : *
1124 : * @return pointer to transport connection, if one is found, 0 otherwise
1125 : */
1126 : transport_connection_t *
1127 22 : session_lookup_connection_wt6 (u32 fib_index, ip6_address_t * lcl,
1128 : ip6_address_t * rmt, u16 lcl_port,
1129 : u16 rmt_port, u8 proto, u32 thread_index,
1130 : u8 * result)
1131 : {
1132 : session_table_t *st;
1133 : session_t *s;
1134 : session_kv6_t kv6;
1135 : u32 action_index;
1136 : int rv;
1137 :
1138 22 : st = session_table_get_for_fib_index (FIB_PROTOCOL_IP6, fib_index);
1139 22 : if (PREDICT_FALSE (!st))
1140 0 : return 0;
1141 :
1142 22 : make_v6_ss_kv (&kv6, lcl, rmt, lcl_port, rmt_port, proto);
1143 22 : rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
1144 22 : if (rv == 0)
1145 : {
1146 19 : ASSERT ((u32) (kv6.value >> 32) == thread_index);
1147 19 : if (PREDICT_FALSE ((u32) (kv6.value >> 32) != thread_index))
1148 : {
1149 0 : *result = SESSION_LOOKUP_RESULT_WRONG_THREAD;
1150 0 : return 0;
1151 : }
1152 19 : s = session_get (kv6.value & 0xFFFFFFFFULL, thread_index);
1153 19 : return transport_get_connection (proto, s->connection_index,
1154 : thread_index);
1155 : }
1156 :
1157 : /* Try half-open connections */
1158 3 : rv = clib_bihash_search_inline_48_8 (&st->v6_half_open_hash, &kv6);
1159 3 : if (rv == 0)
1160 1 : return transport_get_half_open (proto, kv6.value & 0xFFFFFFFF);
1161 :
1162 : /* Check the session rules table */
1163 2 : action_index = session_rules_table_lookup6 (&st->session_rules[proto], lcl,
1164 : rmt, lcl_port, rmt_port);
1165 2 : if (session_lookup_action_index_is_valid (action_index))
1166 : {
1167 0 : if (action_index == SESSION_RULES_TABLE_ACTION_DROP)
1168 : {
1169 0 : *result = SESSION_LOOKUP_RESULT_FILTERED;
1170 0 : return 0;
1171 : }
1172 0 : if ((s = session_lookup_action_to_session (action_index,
1173 : FIB_PROTOCOL_IP6, proto)))
1174 0 : return transport_get_listener (proto, s->connection_index);
1175 0 : return 0;
1176 : }
1177 :
1178 : /* If nothing is found, check if any listener is available */
1179 2 : s = session_lookup_listener6_i (st, lcl, lcl_port, proto, 1);
1180 2 : if (s)
1181 2 : return transport_get_listener (proto, s->connection_index);
1182 :
1183 0 : return 0;
1184 : }
1185 :
1186 : /**
1187 : * Lookup connection with ip6 and transport layer information
1188 : *
1189 : * Not optimized. This is used on the fast path so it needs to be fast.
1190 : * Thereby, duplication of code and 'hacks' allowed. Lookup logic is identical
1191 : * to that of @ref session_lookup_connection_wt4
1192 : *
1193 : * @param fib_index index of the fib wherein the connection was received
1194 : * @param lcl local ip6 address
1195 : * @param rmt remote ip6 address
1196 : * @param lcl_port local port
1197 : * @param rmt_port remote port
1198 : * @param proto transport protocol (e.g., tcp, udp)
1199 : *
1200 : * @return pointer to transport connection, if one is found, 0 otherwise
1201 : */
1202 : transport_connection_t *
1203 0 : session_lookup_connection6 (u32 fib_index, ip6_address_t * lcl,
1204 : ip6_address_t * rmt, u16 lcl_port, u16 rmt_port,
1205 : u8 proto)
1206 : {
1207 : session_table_t *st;
1208 : session_t *s;
1209 : session_kv6_t kv6;
1210 : u32 action_index;
1211 : int rv;
1212 :
1213 0 : st = session_table_get_for_fib_index (FIB_PROTOCOL_IP6, fib_index);
1214 0 : if (PREDICT_FALSE (!st))
1215 0 : return 0;
1216 :
1217 0 : make_v6_ss_kv (&kv6, lcl, rmt, lcl_port, rmt_port, proto);
1218 0 : rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
1219 0 : if (rv == 0)
1220 : {
1221 0 : s = session_get_from_handle (kv6.value);
1222 0 : return transport_get_connection (proto, s->connection_index,
1223 0 : s->thread_index);
1224 : }
1225 :
1226 : /* Try half-open connections */
1227 0 : rv = clib_bihash_search_inline_48_8 (&st->v6_half_open_hash, &kv6);
1228 0 : if (rv == 0)
1229 0 : return transport_get_half_open (proto, kv6.value & 0xFFFFFFFF);
1230 :
1231 : /* Check the session rules table */
1232 0 : action_index = session_rules_table_lookup6 (&st->session_rules[proto], lcl,
1233 : rmt, lcl_port, rmt_port);
1234 0 : if (session_lookup_action_index_is_valid (action_index))
1235 : {
1236 0 : if (action_index == SESSION_RULES_TABLE_ACTION_DROP)
1237 0 : return 0;
1238 0 : if ((s = session_lookup_action_to_session (action_index,
1239 : FIB_PROTOCOL_IP6, proto)))
1240 0 : return transport_get_listener (proto, s->connection_index);
1241 0 : return 0;
1242 : }
1243 :
1244 : /* If nothing is found, check if any listener is available */
1245 0 : s = session_lookup_listener6_i (st, lcl, lcl_port, proto, 1);
1246 0 : if (s)
1247 0 : return transport_get_listener (proto, s->connection_index);
1248 :
1249 0 : return 0;
1250 : }
1251 :
1252 : /**
1253 : * Lookup session with ip6 and transport layer information
1254 : *
1255 : * Important note: this may look into another thread's pool table and
1256 : * register as 'peeker'. Caller should call @ref session_pool_remove_peeker as
1257 : * if needed as soon as possible.
1258 : *
1259 : * Lookup logic is similar to that of @ref session_lookup_connection_wt6 but
1260 : * this returns a session as opposed to a transport connection and it does not
1261 : * try to lookup half-open sessions.
1262 : *
1263 : * Typically used by dgram connections
1264 : */
1265 : session_t *
1266 0 : session_lookup_safe6 (u32 fib_index, ip6_address_t * lcl, ip6_address_t * rmt,
1267 : u16 lcl_port, u16 rmt_port, u8 proto)
1268 : {
1269 : session_table_t *st;
1270 : session_kv6_t kv6;
1271 : session_t *s;
1272 : u32 action_index;
1273 : int rv;
1274 :
1275 0 : st = session_table_get_for_fib_index (FIB_PROTOCOL_IP6, fib_index);
1276 0 : if (PREDICT_FALSE (!st))
1277 0 : return 0;
1278 :
1279 0 : make_v6_ss_kv (&kv6, lcl, rmt, lcl_port, rmt_port, proto);
1280 0 : rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
1281 0 : if (rv == 0)
1282 0 : return session_get_from_handle_safe (kv6.value);
1283 :
1284 : /* Check the session rules table */
1285 0 : action_index = session_rules_table_lookup6 (&st->session_rules[proto], lcl,
1286 : rmt, lcl_port, rmt_port);
1287 0 : if (session_lookup_action_index_is_valid (action_index))
1288 : {
1289 0 : if (action_index == SESSION_RULES_TABLE_ACTION_DROP)
1290 0 : return 0;
1291 0 : return session_lookup_action_to_session (action_index, FIB_PROTOCOL_IP6,
1292 : proto);
1293 : }
1294 :
1295 : /* If nothing is found, check if any listener is available */
1296 0 : if ((s = session_lookup_listener6_i (st, lcl, lcl_port, proto, 1)))
1297 0 : return s;
1298 0 : return 0;
1299 : }
1300 :
1301 : transport_connection_t *
1302 1 : session_lookup_connection (u32 fib_index, ip46_address_t * lcl,
1303 : ip46_address_t * rmt, u16 lcl_port, u16 rmt_port,
1304 : u8 proto, u8 is_ip4)
1305 : {
1306 1 : if (is_ip4)
1307 1 : return session_lookup_connection4 (fib_index, &lcl->ip4, &rmt->ip4,
1308 : lcl_port, rmt_port, proto);
1309 : else
1310 0 : return session_lookup_connection6 (fib_index, &lcl->ip6, &rmt->ip6,
1311 : lcl_port, rmt_port, proto);
1312 : }
1313 :
1314 : int
1315 19 : vnet_session_rule_add_del (session_rule_add_del_args_t * args)
1316 : {
1317 19 : app_namespace_t *app_ns = app_namespace_get (args->appns_index);
1318 : session_rules_table_t *srt;
1319 : session_table_t *st;
1320 : u32 fib_index;
1321 : u8 fib_proto;
1322 19 : int rv = 0;
1323 :
1324 19 : if (!app_ns)
1325 0 : return VNET_API_ERROR_APP_INVALID_NS;
1326 :
1327 19 : if (args->scope > 3)
1328 0 : return VNET_API_ERROR_INVALID_VALUE;
1329 :
1330 19 : if (args->transport_proto != TRANSPORT_PROTO_TCP
1331 0 : && args->transport_proto != TRANSPORT_PROTO_UDP)
1332 0 : return VNET_API_ERROR_INVALID_VALUE;
1333 :
1334 19 : if ((args->scope & SESSION_RULE_SCOPE_GLOBAL) || args->scope == 0)
1335 : {
1336 13 : fib_proto = args->table_args.rmt.fp_proto;
1337 13 : fib_index = app_namespace_get_fib_index (app_ns, fib_proto);
1338 13 : st = session_table_get_for_fib_index (fib_proto, fib_index);
1339 13 : srt = &st->session_rules[args->transport_proto];
1340 13 : if ((rv = session_rules_table_add_del (srt, &args->table_args)))
1341 0 : return rv;
1342 : }
1343 19 : if (args->scope & SESSION_RULE_SCOPE_LOCAL)
1344 : {
1345 18 : clib_memset (&args->table_args.lcl, 0, sizeof (args->table_args.lcl));
1346 18 : args->table_args.lcl.fp_proto = args->table_args.rmt.fp_proto;
1347 18 : args->table_args.lcl_port = 0;
1348 18 : st = app_namespace_get_local_table (app_ns);
1349 18 : srt = &st->session_rules[args->transport_proto];
1350 18 : rv = session_rules_table_add_del (srt, &args->table_args);
1351 : }
1352 19 : return rv;
1353 : }
1354 :
1355 : /**
1356 : * Mark (global) tables as pertaining to app ns
1357 : */
1358 : void
1359 95 : session_lookup_set_tables_appns (app_namespace_t * app_ns)
1360 : {
1361 : session_table_t *st;
1362 : u32 fib_index;
1363 : u8 fp;
1364 :
1365 285 : for (fp = 0; fp < ARRAY_LEN (fib_index_to_table_index); fp++)
1366 : {
1367 190 : fib_index = app_namespace_get_fib_index (app_ns, fp);
1368 190 : st = session_table_get_or_alloc (fp, fib_index);
1369 190 : if (st)
1370 190 : st->appns_index = app_namespace_index (app_ns);
1371 : }
1372 95 : }
1373 :
1374 : u8 *
1375 0 : format_ip4_session_lookup_kvp (u8 * s, va_list * args)
1376 : {
1377 0 : clib_bihash_kv_16_8_t *kvp = va_arg (*args, clib_bihash_kv_16_8_t *);
1378 0 : u32 is_local = va_arg (*args, u32);
1379 0 : v4_connection_key_t *key = (v4_connection_key_t *) kvp->key;
1380 : session_t *session;
1381 : app_worker_t *app_wrk;
1382 : const u8 *app_name;
1383 0 : u8 *str = 0;
1384 :
1385 0 : if (!is_local)
1386 : {
1387 0 : session = session_get_from_handle (kvp->value);
1388 0 : app_wrk = app_worker_get (session->app_wrk_index);
1389 0 : app_name = application_name_from_index (app_wrk->app_index);
1390 0 : str = format (0, "[%U] %U:%d->%U:%d", format_transport_proto_short,
1391 : key->proto, format_ip4_address, &key->src,
1392 0 : clib_net_to_host_u16 (key->src_port), format_ip4_address,
1393 0 : &key->dst, clib_net_to_host_u16 (key->dst_port));
1394 0 : s = format (s, "%-40v%-30v", str, app_name);
1395 : }
1396 : else
1397 : {
1398 0 : session = session_get_from_handle (kvp->value);
1399 0 : app_wrk = app_worker_get (session->app_wrk_index);
1400 0 : app_name = application_name_from_index (app_wrk->app_index);
1401 0 : str = format (0, "[%U] %U:%d", format_transport_proto_short, key->proto,
1402 : format_ip4_address, &key->src,
1403 0 : clib_net_to_host_u16 (key->src_port));
1404 0 : s = format (s, "%-30v%-30v", str, app_name);
1405 : }
1406 0 : return s;
1407 : }
1408 :
1409 : typedef struct _ip4_session_table_show_ctx_t
1410 : {
1411 : vlib_main_t *vm;
1412 : u8 is_local;
1413 : } ip4_session_table_show_ctx_t;
1414 :
1415 : static int
1416 0 : ip4_session_table_show (clib_bihash_kv_16_8_t * kvp, void *arg)
1417 : {
1418 0 : ip4_session_table_show_ctx_t *ctx = arg;
1419 0 : vlib_cli_output (ctx->vm, "%U", format_ip4_session_lookup_kvp, kvp,
1420 0 : ctx->is_local);
1421 0 : return 1;
1422 : }
1423 :
1424 : void
1425 0 : session_lookup_show_table_entries (vlib_main_t * vm, session_table_t * table,
1426 : u8 type, u8 is_local)
1427 : {
1428 0 : ip4_session_table_show_ctx_t ctx = {
1429 : .vm = vm,
1430 : .is_local = is_local,
1431 : };
1432 0 : if (!is_local)
1433 0 : vlib_cli_output (vm, "%-40s%-30s", "Session", "Application");
1434 : else
1435 0 : vlib_cli_output (vm, "%-30s%-30s", "Listener", "Application");
1436 0 : switch (type)
1437 : {
1438 : /* main table v4 */
1439 0 : case 0:
1440 0 : ip4_session_table_walk (&table->v4_session_hash, ip4_session_table_show,
1441 : &ctx);
1442 0 : break;
1443 0 : default:
1444 0 : clib_warning ("not supported");
1445 : }
1446 0 : }
1447 :
1448 : static clib_error_t *
1449 0 : session_rule_command_fn (vlib_main_t * vm, unformat_input_t * input,
1450 : vlib_cli_command_t * cmd)
1451 : {
1452 0 : u32 proto = ~0, lcl_port, rmt_port, action = 0, lcl_plen = 0, rmt_plen = 0;
1453 0 : clib_error_t *error = 0;
1454 0 : u32 appns_index, scope = 0;
1455 : ip46_address_t lcl_ip, rmt_ip;
1456 0 : u8 is_ip4 = 1, conn_set = 0;
1457 0 : u8 fib_proto, is_add = 1, *ns_id = 0;
1458 0 : u8 *tag = 0;
1459 : app_namespace_t *app_ns;
1460 : int rv;
1461 :
1462 0 : session_cli_return_if_not_enabled ();
1463 :
1464 0 : clib_memset (&lcl_ip, 0, sizeof (lcl_ip));
1465 0 : clib_memset (&rmt_ip, 0, sizeof (rmt_ip));
1466 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1467 : {
1468 0 : if (unformat (input, "del"))
1469 0 : is_add = 0;
1470 0 : else if (unformat (input, "add"))
1471 : ;
1472 0 : else if (unformat (input, "appns %_%v%_", &ns_id))
1473 : ;
1474 0 : else if (unformat (input, "scope global"))
1475 0 : scope = SESSION_RULE_SCOPE_GLOBAL;
1476 0 : else if (unformat (input, "scope local"))
1477 0 : scope = SESSION_RULE_SCOPE_LOCAL;
1478 0 : else if (unformat (input, "scope all"))
1479 0 : scope = SESSION_RULE_SCOPE_LOCAL | SESSION_RULE_SCOPE_GLOBAL;
1480 0 : else if (unformat (input, "proto %U", unformat_transport_proto, &proto))
1481 : ;
1482 0 : else if (unformat (input, "%U/%d %d %U/%d %d", unformat_ip4_address,
1483 : &lcl_ip.ip4, &lcl_plen, &lcl_port,
1484 : unformat_ip4_address, &rmt_ip.ip4, &rmt_plen,
1485 : &rmt_port))
1486 : {
1487 0 : is_ip4 = 1;
1488 0 : conn_set = 1;
1489 : }
1490 0 : else if (unformat (input, "%U/%d %d %U/%d %d", unformat_ip6_address,
1491 : &lcl_ip.ip6, &lcl_plen, &lcl_port,
1492 : unformat_ip6_address, &rmt_ip.ip6, &rmt_plen,
1493 : &rmt_port))
1494 : {
1495 0 : is_ip4 = 0;
1496 0 : conn_set = 1;
1497 : }
1498 0 : else if (unformat (input, "action %d", &action))
1499 : ;
1500 0 : else if (unformat (input, "tag %_%v%_", &tag))
1501 : ;
1502 : else
1503 : {
1504 0 : error = clib_error_return (0, "unknown input `%U'",
1505 : format_unformat_error, input);
1506 0 : goto done;
1507 : }
1508 : }
1509 :
1510 0 : if (proto == ~0)
1511 : {
1512 0 : vlib_cli_output (vm, "proto must be set");
1513 0 : goto done;
1514 : }
1515 0 : if (is_add && !conn_set && action == ~0)
1516 : {
1517 0 : vlib_cli_output (vm, "connection and action must be set for add");
1518 0 : goto done;
1519 : }
1520 0 : if (!is_add && !tag && !conn_set)
1521 : {
1522 0 : vlib_cli_output (vm, "connection or tag must be set for delete");
1523 0 : goto done;
1524 : }
1525 0 : if (vec_len (tag) > SESSION_RULE_TAG_MAX_LEN)
1526 : {
1527 0 : vlib_cli_output (vm, "tag too long (max u64)");
1528 0 : goto done;
1529 : }
1530 :
1531 0 : if (ns_id)
1532 : {
1533 0 : app_ns = app_namespace_get_from_id (ns_id);
1534 0 : if (!app_ns)
1535 : {
1536 0 : vlib_cli_output (vm, "namespace %v does not exist", ns_id);
1537 0 : goto done;
1538 : }
1539 : }
1540 : else
1541 : {
1542 0 : app_ns = app_namespace_get_default ();
1543 : }
1544 0 : appns_index = app_namespace_index (app_ns);
1545 :
1546 0 : fib_proto = is_ip4 ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6;
1547 0 : session_rule_add_del_args_t args = {
1548 : .transport_proto = proto,
1549 : .table_args.lcl.fp_addr = lcl_ip,
1550 : .table_args.lcl.fp_len = lcl_plen,
1551 : .table_args.lcl.fp_proto = fib_proto,
1552 : .table_args.rmt.fp_addr = rmt_ip,
1553 : .table_args.rmt.fp_len = rmt_plen,
1554 : .table_args.rmt.fp_proto = fib_proto,
1555 : .table_args.lcl_port = lcl_port,
1556 : .table_args.rmt_port = rmt_port,
1557 : .table_args.action_index = action,
1558 : .table_args.is_add = is_add,
1559 : .table_args.tag = tag,
1560 : .appns_index = appns_index,
1561 : .scope = scope,
1562 : };
1563 0 : if ((rv = vnet_session_rule_add_del (&args)))
1564 0 : error = clib_error_return (0, "rule add del returned %u", rv);
1565 :
1566 0 : done:
1567 0 : vec_free (ns_id);
1568 0 : vec_free (tag);
1569 0 : return error;
1570 : }
1571 :
1572 : /* *INDENT-OFF* */
1573 272887 : VLIB_CLI_COMMAND (session_rule_command, static) =
1574 : {
1575 : .path = "session rule",
1576 : .short_help = "session rule [add|del] appns <ns_id> proto <proto> "
1577 : "<lcl-ip/plen> <lcl-port> <rmt-ip/plen> <rmt-port> action <action>",
1578 : .function = session_rule_command_fn,
1579 : };
1580 : /* *INDENT-ON* */
1581 :
1582 : void
1583 0 : session_lookup_dump_rules_table (u32 fib_index, u8 fib_proto,
1584 : u8 transport_proto)
1585 : {
1586 0 : vlib_main_t *vm = vlib_get_main ();
1587 : session_rules_table_t *srt;
1588 : session_table_t *st;
1589 0 : st = session_table_get_for_fib_index (fib_index, fib_proto);
1590 0 : srt = &st->session_rules[transport_proto];
1591 0 : session_rules_table_cli_dump (vm, srt, fib_proto);
1592 0 : }
1593 :
1594 : void
1595 0 : session_lookup_dump_local_rules_table (u32 table_index, u8 fib_proto,
1596 : u8 transport_proto)
1597 : {
1598 0 : vlib_main_t *vm = vlib_get_main ();
1599 : session_rules_table_t *srt;
1600 : session_table_t *st;
1601 0 : st = session_table_get (table_index);
1602 0 : srt = &st->session_rules[transport_proto];
1603 0 : session_rules_table_cli_dump (vm, srt, fib_proto);
1604 0 : }
1605 :
1606 : static clib_error_t *
1607 0 : show_session_rules_command_fn (vlib_main_t * vm, unformat_input_t * input,
1608 : vlib_cli_command_t * cmd)
1609 : {
1610 0 : u32 transport_proto = ~0, lcl_port, rmt_port, lcl_plen, rmt_plen;
1611 0 : u32 fib_index, scope = 0;
1612 : ip46_address_t lcl_ip, rmt_ip;
1613 0 : u8 is_ip4 = 1, show_one = 0;
1614 : app_namespace_t *app_ns;
1615 : session_rules_table_t *srt;
1616 : session_table_t *st;
1617 0 : u8 *ns_id = 0, fib_proto;
1618 :
1619 0 : session_cli_return_if_not_enabled ();
1620 :
1621 0 : clib_memset (&lcl_ip, 0, sizeof (lcl_ip));
1622 0 : clib_memset (&rmt_ip, 0, sizeof (rmt_ip));
1623 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1624 : {
1625 0 : if (unformat (input, "%U", unformat_transport_proto, &transport_proto))
1626 : ;
1627 0 : else if (unformat (input, "appns %_%v%_", &ns_id))
1628 : ;
1629 0 : else if (unformat (input, "scope global"))
1630 0 : scope = 1;
1631 0 : else if (unformat (input, "scope local"))
1632 0 : scope = 2;
1633 0 : else if (unformat (input, "%U/%d %d %U/%d %d", unformat_ip4_address,
1634 : &lcl_ip.ip4, &lcl_plen, &lcl_port,
1635 : unformat_ip4_address, &rmt_ip.ip4, &rmt_plen,
1636 : &rmt_port))
1637 : {
1638 0 : is_ip4 = 1;
1639 0 : show_one = 1;
1640 : }
1641 0 : else if (unformat (input, "%U/%d %d %U/%d %d", unformat_ip6_address,
1642 : &lcl_ip.ip6, &lcl_plen, &lcl_port,
1643 : unformat_ip6_address, &rmt_ip.ip6, &rmt_plen,
1644 : &rmt_port))
1645 : {
1646 0 : is_ip4 = 0;
1647 0 : show_one = 1;
1648 : }
1649 : else
1650 0 : return clib_error_return (0, "unknown input `%U'",
1651 : format_unformat_error, input);
1652 : }
1653 :
1654 0 : if (transport_proto == ~0)
1655 : {
1656 0 : vlib_cli_output (vm, "transport proto must be set");
1657 0 : return 0;
1658 : }
1659 :
1660 0 : if (ns_id)
1661 : {
1662 0 : app_ns = app_namespace_get_from_id (ns_id);
1663 0 : if (!app_ns)
1664 : {
1665 0 : vlib_cli_output (vm, "appns %v doesn't exist", ns_id);
1666 0 : return 0;
1667 : }
1668 : }
1669 : else
1670 : {
1671 0 : app_ns = app_namespace_get_default ();
1672 : }
1673 :
1674 0 : if (scope == 1 || scope == 0)
1675 : {
1676 0 : fib_proto = is_ip4 ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6;
1677 0 : fib_index = is_ip4 ? app_ns->ip4_fib_index : app_ns->ip6_fib_index;
1678 0 : st = session_table_get_for_fib_index (fib_proto, fib_index);
1679 : }
1680 : else
1681 : {
1682 0 : st = app_namespace_get_local_table (app_ns);
1683 : }
1684 :
1685 0 : if (show_one)
1686 : {
1687 0 : srt = &st->session_rules[transport_proto];
1688 0 : session_rules_table_show_rule (vm, srt, &lcl_ip, lcl_port, &rmt_ip,
1689 : rmt_port, is_ip4);
1690 0 : return 0;
1691 : }
1692 :
1693 0 : vlib_cli_output (vm, "%U rules table", format_transport_proto,
1694 : transport_proto);
1695 0 : srt = &st->session_rules[transport_proto];
1696 0 : session_rules_table_cli_dump (vm, srt, FIB_PROTOCOL_IP4);
1697 0 : session_rules_table_cli_dump (vm, srt, FIB_PROTOCOL_IP6);
1698 :
1699 0 : vec_free (ns_id);
1700 0 : return 0;
1701 : }
1702 :
1703 : /* *INDENT-OFF* */
1704 272887 : VLIB_CLI_COMMAND (show_session_rules_command, static) =
1705 : {
1706 : .path = "show session rules",
1707 : .short_help = "show session rules [<proto> appns <id> <lcl-ip/plen> "
1708 : "<lcl-port> <rmt-ip/plen> <rmt-port> scope <scope>]",
1709 : .function = show_session_rules_command_fn,
1710 : };
1711 : /* *INDENT-ON* */
1712 :
1713 : void
1714 49 : session_lookup_init (void)
1715 : {
1716 : /*
1717 : * Allocate default table and map it to fib_index 0
1718 : */
1719 49 : session_table_t *st = session_table_alloc ();
1720 49 : vec_validate (fib_index_to_table_index[FIB_PROTOCOL_IP4], 0);
1721 49 : fib_index_to_table_index[FIB_PROTOCOL_IP4][0] = session_table_index (st);
1722 49 : st->active_fib_proto = FIB_PROTOCOL_IP4;
1723 49 : session_table_init (st, FIB_PROTOCOL_IP4);
1724 49 : st = session_table_alloc ();
1725 49 : vec_validate (fib_index_to_table_index[FIB_PROTOCOL_IP6], 0);
1726 49 : fib_index_to_table_index[FIB_PROTOCOL_IP6][0] = session_table_index (st);
1727 49 : st->active_fib_proto = FIB_PROTOCOL_IP6;
1728 49 : session_table_init (st, FIB_PROTOCOL_IP6);
1729 49 : }
1730 :
1731 : /*
1732 : * fd.io coding-style-patch-verification: ON
1733 : *
1734 : * Local Variables:
1735 : * eval: (c-set-style "gnu")
1736 : * End:
1737 : */
|