2 * Copyright (c) 2017 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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 /** Generate typed init functions for multiple hash table styles... */
17 #include <vppinfra/bihash_16_8.h>
18 #include <vppinfra/bihash_template.h>
20 #include <vppinfra/bihash_template.c>
22 #undef __included_bihash_template_h__
24 #include <vppinfra/bihash_48_8.h>
25 #include <vppinfra/bihash_template.h>
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>
33 * External vector of per transport virtual functions table
35 extern transport_proto_vft_t *tp_vfts;
38 * Network namespace index (i.e., fib index) to session lookup table. We
39 * should have one per network protocol type but for now we only support IP4/6
41 static u32 *fib_index_to_table_index[2];
45 typedef CLIB_PACKED (struct {
54 /* align by making this 4 octets even though its a 1-bit field
55 * NOTE: avoid key overlap with other transports that use 5 tuples for
56 * session identification.
62 }) v4_connection_key_t;
64 typedef CLIB_PACKED (struct {
79 }) v6_connection_key_t;
82 typedef clib_bihash_kv_16_8_t session_kv4_t;
83 typedef clib_bihash_kv_48_8_t session_kv6_t;
86 make_v4_ss_kv (session_kv4_t * kv, ip4_address_t * lcl, ip4_address_t * rmt,
87 u16 lcl_port, u16 rmt_port, u8 proto)
89 v4_connection_key_t *key = (v4_connection_key_t *) kv->key;
91 key->src.as_u32 = lcl->as_u32;
92 key->dst.as_u32 = rmt->as_u32;
93 key->src_port = lcl_port;
94 key->dst_port = rmt_port;
101 make_v4_listener_kv (session_kv4_t * kv, ip4_address_t * lcl, u16 lcl_port,
104 v4_connection_key_t *key = (v4_connection_key_t *) kv->key;
106 key->src.as_u32 = lcl->as_u32;
108 key->src_port = lcl_port;
116 make_v4_ss_kv_from_tc (session_kv4_t * kv, transport_connection_t * t)
118 make_v4_ss_kv (kv, &t->lcl_ip.ip4, &t->rmt_ip.ip4, t->lcl_port, t->rmt_port,
119 session_type_from_proto_and_ip (t->proto, 1));
123 make_v6_ss_kv (session_kv6_t * kv, ip6_address_t * lcl, ip6_address_t * rmt,
124 u16 lcl_port, u16 rmt_port, u8 proto)
126 v6_connection_key_t *key = (v6_connection_key_t *) kv->key;
128 key->src.as_u64[0] = lcl->as_u64[0];
129 key->src.as_u64[1] = lcl->as_u64[1];
130 key->dst.as_u64[0] = rmt->as_u64[0];
131 key->dst.as_u64[1] = rmt->as_u64[1];
132 key->src_port = lcl_port;
133 key->dst_port = rmt_port;
141 make_v6_listener_kv (session_kv6_t * kv, ip6_address_t * lcl, u16 lcl_port,
144 v6_connection_key_t *key = (v6_connection_key_t *) kv->key;
146 key->src.as_u64[0] = lcl->as_u64[0];
147 key->src.as_u64[1] = lcl->as_u64[1];
148 key->dst.as_u64[0] = 0;
149 key->dst.as_u64[1] = 0;
150 key->src_port = lcl_port;
159 make_v6_ss_kv_from_tc (session_kv6_t * kv, transport_connection_t * t)
161 make_v6_ss_kv (kv, &t->lcl_ip.ip6, &t->rmt_ip.ip6, t->lcl_port, t->rmt_port,
162 session_type_from_proto_and_ip (t->proto, 0));
165 static session_table_t *
166 session_table_get_or_alloc (u8 fib_proto, u8 fib_index)
170 if (vec_len (fib_index_to_table_index[fib_proto]) <= fib_index)
172 st = session_table_alloc ();
173 table_index = session_table_index (st);
174 vec_validate (fib_index_to_table_index[fib_proto], fib_index);
175 fib_index_to_table_index[fib_proto][fib_index] = table_index;
176 st->active_fib_proto = fib_proto;
181 table_index = fib_index_to_table_index[fib_proto][fib_index];
182 return session_table_get (table_index);
186 static session_table_t *
187 session_table_get_or_alloc_for_connection (transport_connection_t * tc)
190 fib_proto = transport_connection_fib_proto (tc);
191 return session_table_get_or_alloc (fib_proto, tc->fib_index);
194 static session_table_t *
195 session_table_get_for_connection (transport_connection_t * tc)
197 u32 fib_proto = transport_connection_fib_proto (tc);
198 if (vec_len (fib_index_to_table_index[fib_proto]) <= tc->fib_index)
201 session_table_get (fib_index_to_table_index[fib_proto][tc->fib_index]);
204 static session_table_t *
205 session_table_get_for_fib_index (u32 fib_proto, u32 fib_index)
207 if (vec_len (fib_index_to_table_index[fib_proto]) <= fib_index)
209 return session_table_get (fib_index_to_table_index[fib_proto][fib_index]);
213 session_lookup_get_index_for_fib (u32 fib_proto, u32 fib_index)
215 if (vec_len (fib_index_to_table_index[fib_proto]) <= fib_index)
216 return SESSION_TABLE_INVALID_INDEX;
217 return fib_index_to_table_index[fib_proto][fib_index];
221 * Add transport connection to a session table
223 * Session lookup 5-tuple (src-ip, dst-ip, src-port, dst-port, session-type)
224 * is added to requested session table.
226 * @param tc transport connection to be added
227 * @param value value to be stored
229 * @return non-zero if failure
232 session_lookup_add_connection (transport_connection_t * tc, u64 value)
238 st = session_table_get_or_alloc_for_connection (tc);
243 make_v4_ss_kv_from_tc (&kv4, tc);
245 return clib_bihash_add_del_16_8 (&st->v4_session_hash, &kv4,
250 make_v6_ss_kv_from_tc (&kv6, tc);
252 return clib_bihash_add_del_48_8 (&st->v6_session_hash, &kv6,
258 session_lookup_add_session_endpoint (u32 table_index,
259 session_endpoint_t * sep, u64 value)
265 st = session_table_get (table_index);
270 make_v4_listener_kv (&kv4, &sep->ip.ip4, sep->port,
271 sep->transport_proto);
273 return clib_bihash_add_del_16_8 (&st->v4_session_hash, &kv4, 1);
277 make_v6_listener_kv (&kv6, &sep->ip.ip6, sep->port,
278 sep->transport_proto);
280 return clib_bihash_add_del_48_8 (&st->v6_session_hash, &kv6, 1);
285 session_lookup_del_session_endpoint (u32 table_index,
286 session_endpoint_t * sep)
292 st = session_table_get (table_index);
297 make_v4_listener_kv (&kv4, &sep->ip.ip4, sep->port,
298 sep->transport_proto);
299 return clib_bihash_add_del_16_8 (&st->v4_session_hash, &kv4, 0);
303 make_v6_listener_kv (&kv6, &sep->ip.ip6, sep->port,
304 sep->transport_proto);
305 return clib_bihash_add_del_48_8 (&st->v6_session_hash, &kv6, 0);
310 * Delete transport connection from session table
312 * @param table_index session table index
313 * @param tc transport connection to be removed
315 * @return non-zero if failure
318 session_lookup_del_connection (transport_connection_t * tc)
324 st = session_table_get_for_connection (tc);
329 make_v4_ss_kv_from_tc (&kv4, tc);
330 return clib_bihash_add_del_16_8 (&st->v4_session_hash, &kv4,
335 make_v6_ss_kv_from_tc (&kv6, tc);
336 return clib_bihash_add_del_48_8 (&st->v6_session_hash, &kv6,
342 session_lookup_del_session (stream_session_t * s)
344 transport_connection_t *ts;
345 ts = tp_vfts[s->session_type].get_connection (s->connection_index,
347 return session_lookup_del_connection (ts);
351 session_lookup_action_to_session (u32 action_index)
353 if (action_index != SESSION_RULES_TABLE_ACTION_DROP)
355 return SESSION_INVALID_INDEX;
358 static stream_session_t *
359 session_lookup_app_listen_session (u32 app_index, u8 fib_proto,
363 app = application_get (app_index);
367 return application_first_listener (app, fib_proto, transport_proto);
371 session_lookup_rules_table4 (session_table_t * st, u8 proto,
372 ip4_address_t * lcl, u16 lcl_port,
373 ip4_address_t * rmt, u16 rmt_port)
375 session_rules_table_t *srt = &st->session_rules[proto];
376 u32 action_index, session_index;
377 action_index = session_rules_table_lookup4 (srt, lcl, rmt, lcl_port,
379 session_index = session_lookup_action_to_session (action_index);
380 /* Nothing sophisticated for now, action index is app index */
381 return session_lookup_app_listen_session (session_index, FIB_PROTOCOL_IP4,
386 session_lookup_rules_table6 (session_table_t * st, u8 proto,
387 ip6_address_t * lcl, u16 lcl_port,
388 ip6_address_t * rmt, u16 rmt_port)
390 session_rules_table_t *srt = &st->session_rules[proto];
391 u32 action_index, session_index;
392 action_index = session_rules_table_lookup6 (srt, lcl, rmt, lcl_port,
394 session_index = session_lookup_action_to_session (action_index);
395 return session_lookup_app_listen_session (session_index, FIB_PROTOCOL_IP6,
400 session_lookup_session_endpoint (u32 table_index, session_endpoint_t * sep)
402 session_rules_table_t *srt;
411 st = session_table_get (table_index);
413 return SESSION_INVALID_HANDLE;
416 make_v4_listener_kv (&kv4, &sep->ip.ip4, sep->port,
417 sep->transport_proto);
418 rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
422 memset (&lcl4, 0, sizeof (lcl4));
423 srt = &st->session_rules[sep->transport_proto];
424 ai = session_rules_table_lookup4 (srt, &lcl4, &sep->ip.ip4, 0,
426 if (ai != SESSION_RULES_TABLE_INVALID_INDEX)
427 return session_lookup_action_to_session (ai);
431 make_v6_listener_kv (&kv6, &sep->ip.ip6, sep->port,
432 sep->transport_proto);
433 rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
437 memset (&lcl6, 0, sizeof (lcl6));
438 srt = &st->session_rules[sep->transport_proto];
439 ai = session_rules_table_lookup6 (srt, &lcl6, &sep->ip.ip6, 0,
441 if (ai != SESSION_RULES_TABLE_INVALID_INDEX)
442 return session_lookup_action_to_session (ai);
444 return SESSION_INVALID_HANDLE;
448 session_lookup_global_session_endpoint (session_endpoint_t * sep)
459 fib_proto = session_endpoint_fib_proto (sep);
460 table_index = session_lookup_get_index_for_fib (fib_proto, sep->fib_index);
461 st = session_table_get (table_index);
466 make_v4_listener_kv (&kv4, &sep->ip.ip4, sep->port,
467 sep->transport_proto);
468 rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
470 return session_get_from_handle (kv4.value);
471 memset (&lcl4, 0, sizeof (lcl4));
472 return session_lookup_rules_table4 (st, sep->transport_proto, &lcl4, 0,
473 &sep->ip.ip4, sep->port);
477 make_v6_listener_kv (&kv6, &sep->ip.ip6, sep->port,
478 sep->transport_proto);
479 rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
481 return session_get_from_handle (kv6.value);
482 memset (&lcl6, 0, sizeof (lcl6));
483 return session_lookup_rules_table6 (st, sep->transport_proto, &lcl6, 0,
484 &sep->ip.ip6, sep->port);
489 session_lookup_local_session_endpoint (u32 table_index,
490 session_endpoint_t * sep)
492 session_rules_table_t *srt;
501 st = session_table_get (table_index);
503 return SESSION_INVALID_INDEX;
506 make_v4_listener_kv (&kv4, &sep->ip.ip4, sep->port,
507 sep->transport_proto);
508 rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
510 return (u32) kv4.value;
513 * Zero out the ip. Logic is that connect to local ips, say
514 * 127.0.0.1:port, can match 0.0.0.0:port
517 rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
519 return (u32) kv4.value;
521 memset (&lcl4, 0, sizeof (lcl4));
522 srt = &st->session_rules[sep->transport_proto];
523 ai = session_rules_table_lookup4 (srt, &lcl4, &sep->ip.ip4, 0,
525 if (ai != SESSION_RULES_TABLE_INVALID_INDEX)
526 return session_lookup_action_to_session (ai);
530 make_v6_listener_kv (&kv6, &sep->ip.ip6, sep->port,
531 sep->transport_proto);
532 rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
534 return (u32) kv6.value;
537 * Zero out the ip. Same logic as above.
539 kv6.key[0] = kv6.key[1] = 0;
540 rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
542 return (u32) kv6.value;
544 memset (&lcl6, 0, sizeof (lcl6));
545 srt = &st->session_rules[sep->transport_proto];
546 ai = session_rules_table_lookup6 (srt, &lcl6, &sep->ip.ip6, 0,
548 if (ai != SESSION_RULES_TABLE_INVALID_INDEX)
549 return session_lookup_action_to_session (ai);
551 return SESSION_INVALID_INDEX;
554 static stream_session_t *
555 session_lookup_listener4_i (session_table_t * st, ip4_address_t * lcl,
556 u16 lcl_port, u8 proto)
561 make_v4_listener_kv (&kv4, lcl, lcl_port, proto);
562 rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
564 return session_manager_get_listener (proto, (u32) kv4.value);
566 /* Zero out the lcl ip */
568 rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
570 return session_manager_get_listener (proto, (u32) kv4.value);
576 session_lookup_listener4 (u32 fib_index, ip4_address_t * lcl, u16 lcl_port,
580 st = session_table_get_for_fib_index (FIB_PROTOCOL_IP4, fib_index);
583 return session_lookup_listener4_i (st, lcl, lcl_port, proto);
586 static stream_session_t *
587 session_lookup_listener6_i (session_table_t * st, ip6_address_t * lcl,
588 u16 lcl_port, u8 proto)
593 make_v6_listener_kv (&kv6, lcl, lcl_port, proto);
594 rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
596 return session_manager_get_listener (proto, (u32) kv6.value);
598 /* Zero out the lcl ip */
599 kv6.key[0] = kv6.key[1] = 0;
600 rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
602 return session_manager_get_listener (proto, (u32) kv6.value);
608 session_lookup_listener6 (u32 fib_index, ip6_address_t * lcl, u16 lcl_port,
612 st = session_table_get_for_fib_index (FIB_PROTOCOL_IP6, fib_index);
615 return session_lookup_listener6_i (st, lcl, lcl_port, proto);
619 session_lookup_listener (u32 table_index, session_endpoint_t * sep)
622 st = session_table_get (table_index);
626 return session_lookup_listener4_i (st, &sep->ip.ip4, sep->port,
627 sep->transport_proto);
629 return session_lookup_listener6_i (st, &sep->ip.ip6, sep->port,
630 sep->transport_proto);
635 session_lookup_add_half_open (transport_connection_t * tc, u64 value)
641 st = session_table_get_or_alloc_for_connection (tc);
646 make_v4_ss_kv_from_tc (&kv4, tc);
648 return clib_bihash_add_del_16_8 (&st->v4_half_open_hash, &kv4,
653 make_v6_ss_kv_from_tc (&kv6, tc);
655 return clib_bihash_add_del_48_8 (&st->v6_half_open_hash, &kv6,
661 session_lookup_del_half_open (transport_connection_t * tc)
667 st = session_table_get_for_connection (tc);
672 make_v4_ss_kv_from_tc (&kv4, tc);
673 return clib_bihash_add_del_16_8 (&st->v4_half_open_hash, &kv4,
678 make_v6_ss_kv_from_tc (&kv6, tc);
679 return clib_bihash_add_del_48_8 (&st->v6_half_open_hash, &kv6,
685 session_lookup_half_open_handle (transport_connection_t * tc)
692 st = session_table_get_for_fib_index (transport_connection_fib_proto (tc),
695 return HALF_OPEN_LOOKUP_INVALID_VALUE;
698 make_v4_ss_kv (&kv4, &tc->lcl_ip.ip4, &tc->rmt_ip.ip4, tc->lcl_port,
699 tc->rmt_port, tc->proto);
700 rv = clib_bihash_search_inline_16_8 (&st->v4_half_open_hash, &kv4);
706 make_v6_ss_kv (&kv6, &tc->lcl_ip.ip6, &tc->rmt_ip.ip6, tc->lcl_port,
707 tc->rmt_port, tc->proto);
708 rv = clib_bihash_search_inline_48_8 (&st->v6_half_open_hash, &kv6);
712 return HALF_OPEN_LOOKUP_INVALID_VALUE;
715 transport_connection_t *
716 session_lookup_half_open_connection (u64 handle, u8 proto, u8 is_ip4)
720 if (handle != HALF_OPEN_LOOKUP_INVALID_VALUE)
722 sst = session_type_from_proto_and_ip (proto, is_ip4);
723 return tp_vfts[sst].get_half_open (handle & 0xFFFFFFFF);
728 static transport_connection_t *
729 session_lookup_rules_table_connection4 (session_table_t * st, u8 proto,
730 ip4_address_t * lcl, u16 lcl_port,
731 ip4_address_t * rmt, u16 rmt_port)
734 s = session_lookup_rules_table4 (st, proto, lcl, lcl_port, rmt, rmt_port);
736 return tp_vfts[s->session_type].get_listener (s->connection_index);
740 static transport_connection_t *
741 session_lookup_rules_table_connection6 (session_table_t * srt, u8 proto,
742 ip6_address_t * lcl, u16 lcl_port,
743 ip6_address_t * rmt, u16 rmt_port)
746 s = session_lookup_rules_table6 (srt, proto, lcl, lcl_port, rmt, rmt_port);
748 return tp_vfts[s->session_type].get_listener (s->connection_index);
753 * Lookup connection with ip4 and transport layer information
755 * This is used on the fast path so it needs to be fast. Thereby,
756 * duplication of code and 'hacks' allowed.
758 * The lookup is incremental and returns whenever something is matched. The
760 * - Try to find an established session
761 * - Try to find a fully-formed or local source wildcarded (listener bound to
762 * all interfaces) listener session
763 * - Try to find a half-open connection
764 * - Try session rules table
767 * @param fib_index index of fib wherein the connection was received
768 * @param lcl local ip4 address
769 * @param rmt remote ip4 address
770 * @param lcl_port local port
771 * @param rmt_port remote port
772 * @param proto transport protocol (e.g., tcp, udp)
773 * @param thread_index thread index for request
775 * @return pointer to transport connection, if one is found, 0 otherwise
777 transport_connection_t *
778 session_lookup_connection_wt4 (u32 fib_index, ip4_address_t * lcl,
779 ip4_address_t * rmt, u16 lcl_port,
780 u16 rmt_port, u8 proto, u32 thread_index)
787 st = session_table_get_for_fib_index (FIB_PROTOCOL_IP4, fib_index);
788 if (PREDICT_FALSE (!st))
791 /* Lookup session amongst established ones */
792 make_v4_ss_kv (&kv4, lcl, rmt, lcl_port, rmt_port, proto);
793 rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
796 ASSERT ((u32) (kv4.value >> 32) == thread_index);
797 s = session_get (kv4.value & 0xFFFFFFFFULL, thread_index);
798 return tp_vfts[s->session_type].get_connection (s->connection_index,
802 /* If nothing is found, check if any listener is available */
803 s = session_lookup_listener4_i (st, lcl, lcl_port, proto);
805 return tp_vfts[s->session_type].get_listener (s->connection_index);
807 /* Try half-open connections */
808 rv = clib_bihash_search_inline_16_8 (&st->v4_half_open_hash, &kv4);
811 u32 sst = session_type_from_proto_and_ip (proto, 1);
812 return tp_vfts[sst].get_half_open (kv4.value & 0xFFFFFFFF);
815 /* Check the session rules table */
816 return session_lookup_rules_table_connection4 (st, proto, lcl, lcl_port,
821 * Lookup connection with ip4 and transport layer information
823 * Not optimized. This is used on the fast path so it needs to be fast.
824 * Thereby, duplication of code and 'hacks' allowed. Lookup logic is identical
825 * to that of @ref session_lookup_connection_wt4
827 * @param fib_index index of the fib wherein the connection was received
828 * @param lcl local ip4 address
829 * @param rmt remote ip4 address
830 * @param lcl_port local port
831 * @param rmt_port remote port
832 * @param proto transport protocol (e.g., tcp, udp)
834 * @return pointer to transport connection, if one is found, 0 otherwise
836 transport_connection_t *
837 session_lookup_connection4 (u32 fib_index, ip4_address_t * lcl,
838 ip4_address_t * rmt, u16 lcl_port, u16 rmt_port,
846 st = session_table_get_for_fib_index (FIB_PROTOCOL_IP4, fib_index);
847 if (PREDICT_FALSE (!st))
850 /* Lookup session amongst established ones */
851 make_v4_ss_kv (&kv4, lcl, rmt, lcl_port, rmt_port, proto);
852 rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
855 s = session_get_from_handle (kv4.value);
856 return tp_vfts[s->session_type].get_connection (s->connection_index,
860 /* If nothing is found, check if any listener is available */
861 s = session_lookup_listener4_i (st, lcl, lcl_port, proto);
863 return tp_vfts[s->session_type].get_listener (s->connection_index);
865 /* Finally, try half-open connections */
866 rv = clib_bihash_search_inline_16_8 (&st->v4_half_open_hash, &kv4);
869 u32 sst = session_type_from_proto_and_ip (proto, 1);
870 return tp_vfts[sst].get_half_open (kv4.value & 0xFFFFFFFF);
872 /* Check the session rules table */
873 return session_lookup_rules_table_connection4 (st, proto, lcl, lcl_port,
878 * Lookup session with ip4 and transport layer information
880 * Important note: this may look into another thread's pool table and
881 * register as 'peeker'. Caller should call @ref session_pool_remove_peeker as
882 * if needed as soon as possible.
884 * Lookup logic is similar to that of @ref session_lookup_connection_wt4 but
885 * this returns a session as opposed to a transport connection and it does not
886 * try to lookup half-open sessions.
888 * Typically used by dgram connections
891 session_lookup_safe4 (u32 fib_index, ip4_address_t * lcl, ip4_address_t * rmt,
892 u16 lcl_port, u16 rmt_port, u8 proto)
899 st = session_table_get_for_fib_index (FIB_PROTOCOL_IP4, fib_index);
900 if (PREDICT_FALSE (!st))
903 /* Lookup session amongst established ones */
904 make_v4_ss_kv (&kv4, lcl, rmt, lcl_port, rmt_port, proto);
905 rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
907 return session_get_from_handle_safe (kv4.value);
909 /* If nothing is found, check if any listener is available */
910 if ((s = session_lookup_listener4_i (st, lcl, lcl_port, proto)))
912 return session_lookup_rules_table4 (st, proto, lcl,
913 lcl_port, rmt, rmt_port);
917 * Lookup connection with ip6 and transport layer information
919 * This is used on the fast path so it needs to be fast. Thereby,
920 * duplication of code and 'hacks' allowed.
922 * The lookup is incremental and returns whenever something is matched. The
924 * - Try to find an established session
925 * - Try to find a fully-formed or local source wildcarded (listener bound to
926 * all interfaces) listener session
927 * - Try to find a half-open connection
928 * - Try session rules table
931 * @param fib_index index of the fib wherein the connection was received
932 * @param lcl local ip6 address
933 * @param rmt remote ip6 address
934 * @param lcl_port local port
935 * @param rmt_port remote port
936 * @param proto transport protocol (e.g., tcp, udp)
937 * @param thread_index thread index for request
939 * @return pointer to transport connection, if one is found, 0 otherwise
941 transport_connection_t *
942 session_lookup_connection_wt6 (u32 fib_index, ip6_address_t * lcl,
943 ip6_address_t * rmt, u16 lcl_port,
944 u16 rmt_port, u8 proto, u32 thread_index)
951 st = session_table_get_for_fib_index (FIB_PROTOCOL_IP6, fib_index);
952 if (PREDICT_FALSE (!st))
955 make_v6_ss_kv (&kv6, lcl, rmt, lcl_port, rmt_port, proto);
956 rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
959 ASSERT ((u32) (kv6.value >> 32) == thread_index);
960 s = session_get (kv6.value & 0xFFFFFFFFULL, thread_index);
961 return tp_vfts[s->session_type].get_connection (s->connection_index,
965 /* If nothing is found, check if any listener is available */
966 s = session_lookup_listener6_i (st, lcl, lcl_port, proto);
968 return tp_vfts[s->session_type].get_listener (s->connection_index);
970 /* Finally, try half-open connections */
971 rv = clib_bihash_search_inline_48_8 (&st->v6_half_open_hash, &kv6);
974 u32 sst = session_type_from_proto_and_ip (proto, 1);
975 return tp_vfts[sst].get_half_open (kv6.value & 0xFFFFFFFF);
978 return session_lookup_rules_table_connection6 (st, proto, lcl, lcl_port,
983 * Lookup connection with ip6 and transport layer information
985 * Not optimized. This is used on the fast path so it needs to be fast.
986 * Thereby, duplication of code and 'hacks' allowed. Lookup logic is identical
987 * to that of @ref session_lookup_connection_wt4
989 * @param fib_index index of the fib wherein the connection was received
990 * @param lcl local ip6 address
991 * @param rmt remote ip6 address
992 * @param lcl_port local port
993 * @param rmt_port remote port
994 * @param proto transport protocol (e.g., tcp, udp)
996 * @return pointer to transport connection, if one is found, 0 otherwise
998 transport_connection_t *
999 session_lookup_connection6 (u32 fib_index, ip6_address_t * lcl,
1000 ip6_address_t * rmt, u16 lcl_port, u16 rmt_port,
1003 session_table_t *st;
1004 stream_session_t *s;
1008 st = session_table_get_for_fib_index (FIB_PROTOCOL_IP6, fib_index);
1009 if (PREDICT_FALSE (!st))
1012 make_v6_ss_kv (&kv6, lcl, rmt, lcl_port, rmt_port, proto);
1013 rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
1016 s = session_get_from_handle (kv6.value);
1017 return tp_vfts[s->session_type].get_connection (s->connection_index,
1021 /* If nothing is found, check if any listener is available */
1022 s = session_lookup_listener6 (fib_index, lcl, lcl_port, proto);
1024 return tp_vfts[s->session_type].get_listener (s->connection_index);
1026 /* Finally, try half-open connections */
1027 rv = clib_bihash_search_inline_48_8 (&st->v6_half_open_hash, &kv6);
1030 u32 sst = session_type_from_proto_and_ip (proto, 1);
1031 return tp_vfts[sst].get_half_open (kv6.value & 0xFFFFFFFF);
1034 return session_lookup_rules_table_connection6 (st, proto, lcl, lcl_port,
1039 * Lookup session with ip6 and transport layer information
1041 * Important note: this may look into another thread's pool table and
1042 * register as 'peeker'. Caller should call @ref session_pool_remove_peeker as
1043 * if needed as soon as possible.
1045 * Lookup logic is similar to that of @ref session_lookup_connection_wt6 but
1046 * this returns a session as opposed to a transport connection and it does not
1047 * try to lookup half-open sessions.
1049 * Typically used by dgram connections
1052 session_lookup_safe6 (u32 fib_index, ip6_address_t * lcl, ip6_address_t * rmt,
1053 u16 lcl_port, u16 rmt_port, u8 proto)
1055 session_table_t *st;
1057 stream_session_t *s;
1060 st = session_table_get_for_fib_index (FIB_PROTOCOL_IP6, fib_index);
1061 if (PREDICT_FALSE (!st))
1064 make_v6_ss_kv (&kv6, lcl, rmt, lcl_port, rmt_port, proto);
1065 rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
1067 return session_get_from_handle_safe (kv6.value);
1069 /* If nothing is found, check if any listener is available */
1070 if ((s = session_lookup_listener6_i (st, lcl, lcl_port, proto)))
1072 return session_lookup_rules_table6 (st, proto, lcl,
1073 lcl_port, rmt, rmt_port);
1077 session_lookup_local_listener_make_handle (session_endpoint_t * sep)
1079 return ((u64) SESSION_LOCAL_TABLE_PREFIX << 32
1080 | (u32) sep->port << 16 | (u32) sep->transport_proto << 8
1081 | (u32) sep->is_ip4);
1085 session_lookup_local_is_handle (u64 handle)
1087 if (handle >> 32 == SESSION_LOCAL_TABLE_PREFIX)
1093 session_lookup_local_listener_parse_handle (u64 handle,
1094 session_endpoint_t * sep)
1096 u32 local_table_handle;
1097 if (handle >> 32 != SESSION_LOCAL_TABLE_PREFIX)
1099 local_table_handle = handle & 0xFFFFFFFFULL;
1100 sep->is_ip4 = local_table_handle & 0xff;
1101 local_table_handle >>= 8;
1102 sep->transport_proto = local_table_handle & 0xff;
1103 sep->port = local_table_handle >> 8;
1108 vnet_session_rule_add_del (session_rule_add_del_args_t * args)
1110 app_namespace_t *app_ns = app_namespace_get (args->appns_index);
1111 session_rules_table_t *srt;
1112 session_table_t *st;
1115 clib_error_t *error;
1118 return clib_error_return_code (0, VNET_API_ERROR_APP_INVALID_NS, 0,
1120 if (args->scope > 3)
1121 return clib_error_return_code (0, VNET_API_ERROR_INVALID_VALUE, 0,
1123 if (args->transport_proto != TRANSPORT_PROTO_TCP
1124 && args->transport_proto != TRANSPORT_PROTO_UDP)
1125 return clib_error_return_code (0, VNET_API_ERROR_INVALID_VALUE, 0,
1126 "invalid transport proto");
1127 if ((args->scope & SESSION_RULE_SCOPE_GLOBAL) || args->scope == 0)
1129 fib_proto = args->table_args.rmt.fp_proto;
1130 fib_index = app_namespace_get_fib_index (app_ns, fib_proto);
1131 st = session_table_get_for_fib_index (fib_proto, fib_index);
1132 srt = &st->session_rules[args->transport_proto];
1133 if ((error = session_rules_table_add_del (srt, &args->table_args)))
1135 clib_error_report (error);
1139 if (args->scope & SESSION_RULE_SCOPE_LOCAL)
1141 st = app_namespace_get_local_table (app_ns);
1142 srt = &st->session_rules[args->transport_proto];
1143 error = session_rules_table_add_del (srt, &args->table_args);
1149 * Mark (global) tables as pertaining to app ns
1152 session_lookup_set_tables_appns (app_namespace_t * app_ns)
1154 session_table_t *st;
1158 for (fp = 0; fp < ARRAY_LEN (fib_index_to_table_index); fp++)
1160 fib_index = app_namespace_get_fib_index (app_ns, fp);
1161 st = session_table_get_for_fib_index (fp, fib_index);
1163 st->appns_index = app_namespace_index (app_ns);
1168 format_ip4_session_lookup_kvp (u8 * s, va_list * args)
1170 clib_bihash_kv_16_8_t *kvp = va_arg (*args, clib_bihash_kv_16_8_t *);
1171 u32 is_local = va_arg (*args, u32);
1172 u8 *app_name, *str = 0;
1173 stream_session_t *session;
1174 v4_connection_key_t *key = (v4_connection_key_t *) kvp->key;
1176 char *proto = key->proto == TRANSPORT_PROTO_TCP ? "T" : "U";
1179 session = session_get_from_handle (kvp->value);
1180 app_name = application_name_from_index (session->app_index);
1181 str = format (0, "[%s] %U:%d->%U:%d", proto, format_ip4_address,
1182 &key->src, clib_net_to_host_u16 (key->src_port),
1183 format_ip4_address, &key->dst,
1184 clib_net_to_host_u16 (key->dst_port));
1185 s = format (s, "%-40v%-30v", str, app_name);
1189 app_name = application_name_from_index (kvp->value);
1190 str = format (0, "[%s] %U:%d", proto, format_ip4_address,
1191 &key->src, clib_net_to_host_u16 (key->src_port));
1192 s = format (s, "%-30v%-30v", str, app_name);
1194 vec_free (app_name);
1198 typedef struct _ip4_session_table_show_ctx_t
1202 } ip4_session_table_show_ctx_t;
1205 ip4_session_table_show (clib_bihash_kv_16_8_t * kvp, void *arg)
1207 ip4_session_table_show_ctx_t *ctx = arg;
1208 vlib_cli_output (ctx->vm, "%U", format_ip4_session_lookup_kvp, kvp,
1214 session_lookup_show_table_entries (vlib_main_t * vm, session_table_t * table,
1215 u8 type, u8 is_local)
1217 ip4_session_table_show_ctx_t ctx = {
1219 .is_local = is_local,
1222 vlib_cli_output (vm, "%-40s%-30s", "Session", "Application");
1224 vlib_cli_output (vm, "%-30s%-30s", "Listener", "Application");
1229 ip4_session_table_walk (&table->v4_session_hash, ip4_session_table_show,
1233 clib_warning ("not supported");
1237 static clib_error_t *
1238 session_rule_command_fn (vlib_main_t * vm, unformat_input_t * input,
1239 vlib_cli_command_t * cmd)
1241 u32 proto = ~0, lcl_port, rmt_port, action = 0, lcl_plen = 0, rmt_plen = 0;
1242 u32 appns_index, scope = 0;
1243 ip46_address_t lcl_ip, rmt_ip;
1244 u8 is_ip4 = 1, conn_set = 0;
1245 u8 fib_proto, is_add = 1, *ns_id = 0;
1247 app_namespace_t *app_ns;
1248 clib_error_t *error;
1250 memset (&lcl_ip, 0, sizeof (lcl_ip));
1251 memset (&rmt_ip, 0, sizeof (rmt_ip));
1252 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1254 if (unformat (input, "del"))
1256 else if (unformat (input, "add"))
1258 else if (unformat (input, "appns %_%v%_", &ns_id))
1260 else if (unformat (input, "scope global"))
1261 scope = SESSION_RULE_SCOPE_GLOBAL;
1262 else if (unformat (input, "scope local"))
1263 scope = SESSION_RULE_SCOPE_LOCAL;
1264 else if (unformat (input, "scope all"))
1265 scope = SESSION_RULE_SCOPE_LOCAL | SESSION_RULE_SCOPE_GLOBAL;
1266 else if (unformat (input, "proto %U", unformat_transport_proto, &proto))
1268 else if (unformat (input, "%U/%d %d %U/%d %d", unformat_ip4_address,
1269 &lcl_ip.ip4, &lcl_plen, &lcl_port,
1270 unformat_ip4_address, &rmt_ip.ip4, &rmt_plen,
1276 else if (unformat (input, "%U/%d %d %U/%d %d", unformat_ip6_address,
1277 &lcl_ip.ip6, &lcl_plen, &lcl_port,
1278 unformat_ip6_address, &rmt_ip.ip6, &rmt_plen,
1284 else if (unformat (input, "action %d", &action))
1286 else if (unformat (input, "tag %_%v%_", &tag))
1289 return clib_error_return (0, "unknown input `%U'",
1290 format_unformat_error, input);
1295 vlib_cli_output (vm, "proto must be set");
1298 if (is_add && !conn_set && action == ~0)
1300 vlib_cli_output (vm, "connection and action must be set for add");
1303 if (!is_add && !tag && !conn_set)
1305 vlib_cli_output (vm, "connection or tag must be set for delete");
1308 if (vec_len (tag) > SESSION_RULE_TAG_MAX_LEN)
1310 vlib_cli_output (vm, "tag too long (max u64)");
1316 app_ns = app_namespace_get_from_id (ns_id);
1319 vlib_cli_output (vm, "namespace %v does not exist", ns_id);
1325 app_ns = app_namespace_get_default ();
1327 appns_index = app_namespace_index (app_ns);
1329 fib_proto = is_ip4 ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6;
1330 session_rule_add_del_args_t args = {
1331 .table_args.lcl.fp_addr = lcl_ip,
1332 .table_args.lcl.fp_len = lcl_plen,
1333 .table_args.lcl.fp_proto = fib_proto,
1334 .table_args.rmt.fp_addr = rmt_ip,
1335 .table_args.rmt.fp_len = rmt_plen,
1336 .table_args.rmt.fp_proto = fib_proto,
1337 .table_args.lcl_port = lcl_port,
1338 .table_args.rmt_port = rmt_port,
1339 .table_args.action_index = action,
1340 .table_args.is_add = is_add,
1341 .table_args.tag = tag,
1342 .appns_index = appns_index,
1345 error = vnet_session_rule_add_del (&args);
1351 VLIB_CLI_COMMAND (session_rule_command, static) =
1353 .path = "session rule",
1354 .short_help = "session rule [add|del] appns <ns_id> proto <proto> "
1355 "<lcl-ip/plen> <lcl-port> <rmt-ip/plen> <rmt-port> action <action>",
1356 .function = session_rule_command_fn,
1361 session_lookup_dump_rules_table (u32 fib_index, u8 fib_proto,
1364 vlib_main_t *vm = vlib_get_main ();
1365 session_rules_table_t *srt;
1366 session_table_t *st;
1367 st = session_table_get_for_fib_index (fib_index, fib_proto);
1368 srt = &st->session_rules[transport_proto];
1369 session_rules_table_cli_dump (vm, srt, fib_proto);
1373 session_lookup_dump_local_rules_table (u32 table_index, u8 fib_proto,
1376 vlib_main_t *vm = vlib_get_main ();
1377 session_rules_table_t *srt;
1378 session_table_t *st;
1379 st = session_table_get (table_index);
1380 srt = &st->session_rules[transport_proto];
1381 session_rules_table_cli_dump (vm, srt, fib_proto);
1384 static clib_error_t *
1385 show_session_rules_command_fn (vlib_main_t * vm, unformat_input_t * input,
1386 vlib_cli_command_t * cmd)
1388 u32 transport_proto = ~0, lcl_port, rmt_port, lcl_plen, rmt_plen;
1389 u32 fib_index, scope = 0;
1390 ip46_address_t lcl_ip, rmt_ip;
1391 u8 is_ip4 = 1, show_one = 0;
1392 app_namespace_t *app_ns;
1393 session_rules_table_t *srt;
1394 session_table_t *st;
1395 u8 *ns_id = 0, fib_proto;
1397 memset (&lcl_ip, 0, sizeof (lcl_ip));
1398 memset (&rmt_ip, 0, sizeof (rmt_ip));
1399 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1401 if (unformat (input, "%U", unformat_transport_proto, &transport_proto))
1403 else if (unformat (input, "appns %_%v%_", &ns_id))
1405 else if (unformat (input, "scope global"))
1407 else if (unformat (input, "scope local"))
1409 else if (unformat (input, "%U/%d %d %U/%d %d", unformat_ip4_address,
1410 &lcl_ip.ip4, &lcl_plen, &lcl_port,
1411 unformat_ip4_address, &rmt_ip.ip4, &rmt_plen,
1417 else if (unformat (input, "%U/%d %d %U/%d %d", unformat_ip6_address,
1418 &lcl_ip.ip6, &lcl_plen, &lcl_port,
1419 unformat_ip6_address, &rmt_ip.ip6, &rmt_plen,
1426 return clib_error_return (0, "unknown input `%U'",
1427 format_unformat_error, input);
1430 if (transport_proto == ~0)
1432 vlib_cli_output (vm, "transport proto must be set");
1438 app_ns = app_namespace_get_from_id (ns_id);
1441 vlib_cli_output (vm, "appns %v doesn't exist", ns_id);
1447 app_ns = app_namespace_get_default ();
1450 if (scope == 1 || scope == 0)
1452 fib_proto = is_ip4 ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6;
1453 fib_index = is_ip4 ? app_ns->ip4_fib_index : app_ns->ip6_fib_index;
1454 st = session_table_get_for_fib_index (fib_proto, fib_index);
1458 st = app_namespace_get_local_table (app_ns);
1463 srt = &st->session_rules[transport_proto];
1464 session_rules_table_show_rule (vm, srt, &lcl_ip, lcl_port, &rmt_ip,
1469 vlib_cli_output (vm, "%U rules table", format_transport_proto,
1471 srt = &st->session_rules[transport_proto];
1472 session_rules_table_cli_dump (vm, srt, FIB_PROTOCOL_IP4);
1473 session_rules_table_cli_dump (vm, srt, FIB_PROTOCOL_IP6);
1480 VLIB_CLI_COMMAND (show_session_rules_command, static) =
1482 .path = "show session rules",
1483 .short_help = "show session rules [appns <id> proto <proto> <lcl-ip/plen>"
1484 " <lcl-port> <rmt-ip/plen> <rmt-port>]",
1485 .function = show_session_rules_command_fn,
1490 session_lookup_init (void)
1493 * Allocate default table and map it to fib_index 0
1495 session_table_t *st = session_table_alloc ();
1496 vec_validate (fib_index_to_table_index[FIB_PROTOCOL_IP4], 0);
1497 fib_index_to_table_index[FIB_PROTOCOL_IP4][0] = session_table_index (st);
1498 st->active_fib_proto = FIB_PROTOCOL_IP4;
1499 session_table_init (st, FIB_PROTOCOL_IP4);
1500 st = session_table_alloc ();
1501 vec_validate (fib_index_to_table_index[FIB_PROTOCOL_IP6], 0);
1502 fib_index_to_table_index[FIB_PROTOCOL_IP6][0] = session_table_index (st);
1503 st->active_fib_proto = FIB_PROTOCOL_IP6;
1504 session_table_init (st, FIB_PROTOCOL_IP6);
1508 * fd.io coding-style-patch-verification: ON
1511 * eval: (c-set-style "gnu")