cnat: add ip/client bihash
[vpp.git] / src / plugins / cnat / cnat_client.h
1 /*
2  * Copyright (c) 2020 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 #ifndef __CNAT_CLIENT_H__
17 #define __CNAT_CLIENT_H__
18
19 #include <cnat/cnat_types.h>
20 #include <vppinfra/bihash_16_8.h>
21
22 /**
23  * A client is a representation of an IP address behind the NAT.
24  * A client thus sends packet to a VIP.
25  * Clients are learned in the Data-plane when they send packets,
26  * but, since they make additions to the FIB they must be programmed
27  * in the main thread. They are aged out when they become idle.
28  *
29  * A client interposes in the FIB graph for the prefix corresponding
30  * to the client (e.g. client's-IP/32). As a result this client object
31  * is cloned as the interpose DPO. The clones are removed when the lock
32  * count drops to zero. The originals are removed when the client ages.
33  * At forwarding time the client preforms the reverse translation and
34  * then ships the packet to where the FIB would send it.
35  */
36 typedef struct cnat_client_t_
37 {
38   CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
39
40   /**
41    * the client's IP address
42    */
43   ip_address_t cc_ip;
44
45   /**
46    * How to send packets to this client post translation
47    */
48   dpo_id_t cc_parent;
49
50   /**
51    * the FIB entry this client sources
52    */
53   fib_node_index_t cc_fei;
54
55   /**
56    * number of DPO locks
57    */
58   u32 cc_locks;
59
60   /**
61    * Translations refcount for cleanup
62    */
63   u32 tr_refcnt;
64
65   /**
66    * Session refcount for cleanup
67    */
68   u32 session_refcnt;
69
70   /**
71    * Parent cnat_client index if cloned via interpose
72    * or own index if vanilla client.
73    * Used to get translations & update session_refcnt
74    */
75   index_t parent_cci;
76
77   /**
78    * Client flags
79    */
80   u8 flags;
81 } cnat_client_t;
82
83 extern u8 *format_cnat_client (u8 * s, va_list * args);
84 extern void cnat_client_free_by_ip (ip46_address_t * addr, u8 af);
85
86 extern cnat_client_t *cnat_client_pool;
87 extern dpo_type_t cnat_client_dpo;
88
89 #define CC_INDEX_INVALID ((u32)(~0))
90
91 static_always_inline cnat_client_t *
92 cnat_client_get (index_t i)
93 {
94   return (pool_elt_at_index (cnat_client_pool, i));
95 }
96
97 /**
98  * A translation that references this VIP was deleted
99  */
100 extern void cnat_client_translation_deleted (index_t cci);
101
102 /**
103  * A translation that references this VIP was added
104  */
105 extern void cnat_client_translation_added (index_t cci);
106 /**
107  * Called in the main thread by RPC from the workers to learn a
108  * new client
109  */
110 extern void cnat_client_learn (const ip_address_t *addr);
111
112 extern index_t cnat_client_add (const ip_address_t * ip, u8 flags);
113
114 /**
115  * Check all the clients were purged by translation & session purge
116  */
117 extern int cnat_client_purge (void);
118
119 /**
120  * CNat Client (dpo) flags
121  */
122 typedef enum
123 {
124   /* IP already present in the FIB, need to interpose dpo */
125   CNAT_FLAG_EXCLUSIVE = (1 << 1),
126 } cnat_entry_flag_t;
127
128
129 extern void cnat_client_throttle_pool_process ();
130
131 /**
132  * DB of clients
133  */
134 typedef struct cnat_client_db_t_
135 {
136   clib_bihash_16_8_t cc_ip_id_hash;
137   /* Pool of addresses that have been throttled
138      and need to be refcounted before calling
139      cnat_client_free_by_ip */
140   clib_spinlock_t throttle_lock;
141   uword *throttle_mem;
142 } cnat_client_db_t;
143
144 extern cnat_client_db_t cnat_client_db;
145
146 /**
147  * Find a client from an IP4 address
148  */
149 static_always_inline cnat_client_t *
150 cnat_client_ip4_find (const ip4_address_t * ip)
151 {
152   clib_bihash_kv_16_8_t bkey, bval;
153
154   bkey.key[0] = ip->as_u32;
155   bkey.key[1] = 0;
156
157   if (clib_bihash_search_16_8 (&cnat_client_db.cc_ip_id_hash, &bkey, &bval))
158     return (NULL);
159
160   return (pool_elt_at_index (cnat_client_pool, bval.value));
161 }
162
163 /**
164  * Find a client from an IP6 address
165  */
166 static_always_inline cnat_client_t *
167 cnat_client_ip6_find (const ip6_address_t * ip)
168 {
169   clib_bihash_kv_16_8_t bkey, bval;
170
171   bkey.key[0] = ip->as_u64[0];
172   bkey.key[1] = ip->as_u64[1];
173
174   if (clib_bihash_search_16_8 (&cnat_client_db.cc_ip_id_hash, &bkey, &bval))
175     return (NULL);
176
177   return (pool_elt_at_index (cnat_client_pool, bval.value));
178 }
179
180 /**
181  * Add a session refcnt to this client
182  */
183 static_always_inline u32
184 cnat_client_cnt_session (cnat_client_t * cc)
185 {
186   cnat_client_t *ccp = cnat_client_get (cc->parent_cci);
187   return clib_atomic_add_fetch (&ccp->session_refcnt, 1);
188 }
189
190 /**
191  * Del a session refcnt to this client
192  */
193 static_always_inline u32
194 cnat_client_uncnt_session (cnat_client_t * cc)
195 {
196   cnat_client_t *ccp = cnat_client_get (cc->parent_cci);
197   return clib_atomic_sub_fetch (&ccp->session_refcnt, 1);
198 }
199
200 /*
201  * fd.io coding-style-patch-verification: ON
202  *
203  * Local Variables:
204  * eval: (c-set-style "gnu")
205  * End:
206  */
207
208 #endif