cnat: Add DHCP support
[vpp.git] / src / plugins / cnat / cnat_types.c
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 #include <cnat/cnat_types.h>
17
18 cnat_main_t cnat_main;
19 fib_source_t cnat_fib_source;
20 cnat_timestamp_t *cnat_timestamps;
21 throttle_t cnat_throttle;
22
23 char *cnat_error_strings[] = {
24 #define cnat_error(n,s) s,
25 #include <cnat/cnat_error.def>
26 #undef cnat_error
27 };
28
29 u8
30 cnat_resolve_addr (u32 sw_if_index, ip_address_family_t af,
31                    ip_address_t * addr)
32 {
33   /* Tries to resolve IP from sw_if_index
34    * returns 1 if we need to schedule DHCP */
35   if (INDEX_INVALID == sw_if_index)
36     return 0;
37   if (af == AF_IP6)
38     {
39       ip6_address_t *ip6 = 0;
40       ip6 = ip6_interface_first_address (&ip6_main, sw_if_index);
41       if (ip6)
42         {
43           ip_address_set (addr, ip6, AF_IP6);
44           return 0;
45         }
46       else
47         return 1;
48     }
49   else
50     {
51       ip4_address_t *ip4 = 0;
52       ip4 = ip4_interface_first_address (&ip4_main, sw_if_index, 0);
53       if (ip4)
54         {
55           ip_address_set (addr, ip4, AF_IP4);
56           return 0;
57         }
58       else
59         return 1;
60     }
61 }
62
63 u8
64 cnat_resolve_ep (cnat_endpoint_t * ep)
65 {
66   int rv;
67   rv = cnat_resolve_addr (ep->ce_sw_if_index, ep->ce_ip.version, &ep->ce_ip);
68   if (0 == rv)
69     ep->ce_flags |= CNAT_EP_FLAG_RESOLVED;
70   return rv;
71 }
72
73 uword
74 unformat_cnat_ep (unformat_input_t * input, va_list * args)
75 {
76   cnat_endpoint_t *a = va_arg (*args, cnat_endpoint_t *);
77   vnet_main_t *vnm = vnet_get_main ();
78   int port = 0;
79
80   clib_memset (a, 0, sizeof (*a));
81   a->ce_sw_if_index = INDEX_INVALID;
82   if (unformat (input, "%U %d", unformat_ip_address, &a->ce_ip, &port))
83     ;
84   else if (unformat_user (input, unformat_ip_address, &a->ce_ip))
85     ;
86   else if (unformat (input, "%U v6 %d", unformat_vnet_sw_interface,
87                      vnm, &a->ce_sw_if_index, &port))
88     a->ce_ip.version = AF_IP6;
89   else if (unformat (input, "%U v6", unformat_vnet_sw_interface,
90                      vnm, &a->ce_sw_if_index))
91     a->ce_ip.version = AF_IP6;
92   else if (unformat (input, "%U %d", unformat_vnet_sw_interface,
93                      vnm, &a->ce_sw_if_index, &port))
94     a->ce_ip.version = AF_IP4;
95   else if (unformat_user (input, unformat_vnet_sw_interface,
96                           vnm, &a->ce_sw_if_index))
97     a->ce_ip.version = AF_IP4;
98   else if (unformat (input, "%d", &port))
99     ;
100   else
101     return 0;
102   a->ce_port = (u16) port;
103   return 1;
104 }
105
106 uword
107 unformat_cnat_ep_tuple (unformat_input_t * input, va_list * args)
108 {
109   cnat_endpoint_tuple_t *a = va_arg (*args, cnat_endpoint_tuple_t *);
110   if (unformat (input, "%U->%U", unformat_cnat_ep, &a->src_ep,
111                 unformat_cnat_ep, &a->dst_ep))
112     ;
113   else if (unformat (input, "->%U", unformat_cnat_ep, &a->dst_ep))
114     ;
115   else if (unformat (input, "%U->", unformat_cnat_ep, &a->src_ep))
116     ;
117   else
118     return 0;
119   return 1;
120 }
121
122 u8 *
123 format_cnat_endpoint (u8 * s, va_list * args)
124 {
125   cnat_endpoint_t *cep = va_arg (*args, cnat_endpoint_t *);
126   vnet_main_t *vnm = vnet_get_main ();
127   if (INDEX_INVALID == cep->ce_sw_if_index)
128     s = format (s, "%U;%d", format_ip_address, &cep->ce_ip, cep->ce_port);
129   else
130     {
131       if (cep->ce_flags & CNAT_EP_FLAG_RESOLVED)
132         s = format (s, "%U (%U);%d", format_vnet_sw_if_index_name, vnm,
133                     cep->ce_sw_if_index, format_ip_address, &cep->ce_ip,
134                     cep->ce_port);
135       else
136         s =
137           format (s, "%U (%U);%d", format_vnet_sw_if_index_name, vnm,
138                   cep->ce_sw_if_index, format_ip_address_family,
139                   cep->ce_ip.version, cep->ce_port);
140     }
141   return (s);
142 }
143
144 static clib_error_t *
145 cnat_types_init (vlib_main_t * vm)
146 {
147   vlib_thread_main_t *tm = &vlib_thread_main;
148   u32 n_vlib_mains = tm->n_vlib_mains;
149   cnat_fib_source = fib_source_allocate ("cnat",
150                                          CNAT_FIB_SOURCE_PRIORITY,
151                                          FIB_SOURCE_BH_SIMPLE);
152
153
154   clib_rwlock_init (&cnat_main.ts_lock);
155   throttle_init (&cnat_throttle, n_vlib_mains, 1e-3);
156
157   return (NULL);
158 }
159
160 void
161 cnat_enable_disable_scanner (cnat_scanner_cmd_t event_type)
162 {
163   vlib_main_t *vm = vlib_get_main ();
164   vlib_process_signal_event (vm, cnat_main.scanner_node_index, event_type, 0);
165 }
166
167 void
168 cnat_lazy_init ()
169 {
170   cnat_main_t *cm = &cnat_main;
171   if (cm->lazy_init_done)
172     return;
173   cnat_enable_disable_scanner (cm->default_scanner_state);
174   cm->lazy_init_done = 1;
175 }
176
177 static clib_error_t *
178 cnat_config (vlib_main_t * vm, unformat_input_t * input)
179 {
180   cnat_main_t *cm = &cnat_main;
181
182   cm->session_hash_memory = CNAT_DEFAULT_SESSION_MEMORY;
183   cm->session_hash_buckets = CNAT_DEFAULT_SESSION_BUCKETS;
184   cm->translation_hash_memory = CNAT_DEFAULT_TRANSLATION_MEMORY;
185   cm->translation_hash_buckets = CNAT_DEFAULT_TRANSLATION_BUCKETS;
186   cm->snat_hash_memory = CNAT_DEFAULT_SNAT_MEMORY;
187   cm->snat_hash_buckets = CNAT_DEFAULT_SNAT_BUCKETS;
188   cm->scanner_timeout = CNAT_DEFAULT_SCANNER_TIMEOUT;
189   cm->session_max_age = CNAT_DEFAULT_SESSION_MAX_AGE;
190   cm->tcp_max_age = CNAT_DEFAULT_TCP_MAX_AGE;
191   cm->default_scanner_state = CNAT_SCANNER_ON;
192   cm->lazy_init_done = 0;
193
194   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
195     {
196       if (unformat
197           (input, "session-db-buckets %u", &cm->session_hash_buckets))
198         ;
199       else if (unformat (input, "session-db-memory %U",
200                          unformat_memory_size, &cm->session_hash_memory))
201         ;
202       else if (unformat (input, "translation-db-buckets %u",
203                          &cm->translation_hash_buckets))
204         ;
205       else if (unformat (input, "translation-db-memory %U",
206                          unformat_memory_size, &cm->translation_hash_memory))
207         ;
208       else if (unformat (input, "snat-db-buckets %u", &cm->snat_hash_buckets))
209         ;
210       else if (unformat (input, "snat-db-memory %U",
211                          unformat_memory_size, &cm->snat_hash_memory))
212         ;
213       else if (unformat (input, "session-cleanup-timeout %f",
214                          &cm->scanner_timeout))
215         ;
216       else if (unformat (input, "scanner off"))
217         cm->default_scanner_state = CNAT_SCANNER_OFF;
218       else if (unformat (input, "scanner on"))
219         cm->default_scanner_state = CNAT_SCANNER_ON;
220       else if (unformat (input, "session-max-age %u", &cm->session_max_age))
221         ;
222       else if (unformat (input, "tcp-max-age %u", &cm->tcp_max_age))
223         ;
224       else
225         return clib_error_return (0, "unknown input '%U'",
226                                   format_unformat_error, input);
227     }
228
229   return 0;
230 }
231
232 cnat_main_t *
233 cnat_get_main ()
234 {
235   return &cnat_main;
236 }
237
238 VLIB_EARLY_CONFIG_FUNCTION (cnat_config, "cnat");
239 VLIB_INIT_FUNCTION (cnat_types_init);
240
241 /*
242  * fd.io coding-style-patch-verification: ON
243  *
244  * Local Variables:
245  * eval: (c-set-style "gnu")
246  * End:
247  */