IPSEC: minor refactor
[vpp.git] / src / vnet / ipsec / ipsec.c
1 /*
2  * ipsec.c : IPSEC module functions
3  *
4  * Copyright (c) 2015 Cisco and/or its affiliates.
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #include <vnet/vnet.h>
19 #include <vnet/api_errno.h>
20 #include <vnet/ip/ip.h>
21 #include <vnet/interface.h>
22 #include <vnet/udp/udp.h>
23
24 #include <vnet/ipsec/ipsec.h>
25 #include <vnet/ipsec/ikev2.h>
26 #include <vnet/ipsec/esp.h>
27 #include <vnet/ipsec/ah.h>
28
29 ipsec_main_t ipsec_main;
30
31 static void
32 ipsec_rand_seed (void)
33 {
34   struct
35   {
36     time_t time;
37     pid_t pid;
38     void *p;
39   } seed_data;
40
41   seed_data.time = time (NULL);
42   seed_data.pid = getpid ();
43   seed_data.p = (void *) &seed_data;
44
45   RAND_seed ((const void *) &seed_data, sizeof (seed_data));
46 }
47
48 static clib_error_t *
49 ipsec_check_ah_support (ipsec_sa_t * sa)
50 {
51   if (sa->integ_alg == IPSEC_INTEG_ALG_NONE)
52     return clib_error_return (0, "unsupported none integ-alg");
53   return 0;
54 }
55
56 static clib_error_t *
57 ipsec_check_esp_support (ipsec_sa_t * sa)
58 {
59   if (sa->crypto_alg == IPSEC_CRYPTO_ALG_AES_GCM_128)
60     return clib_error_return (0, "unsupported aes-gcm-128 crypto-alg");
61   if (sa->crypto_alg == IPSEC_CRYPTO_ALG_AES_GCM_192)
62     return clib_error_return (0, "unsupported aes-gcm-192 crypto-alg");
63   if (sa->crypto_alg == IPSEC_CRYPTO_ALG_AES_GCM_256)
64     return clib_error_return (0, "unsupported aes-gcm-256 crypto-alg");
65
66   return 0;
67 }
68
69 clib_error_t *
70 ipsec_add_del_sa_sess_cb (ipsec_main_t * im, u32 sa_index, u8 is_add)
71 {
72   ipsec_ah_backend_t *ah =
73     pool_elt_at_index (im->ah_backends, im->ah_current_backend);
74   if (ah->add_del_sa_sess_cb)
75     {
76       clib_error_t *err = ah->add_del_sa_sess_cb (sa_index, is_add);
77       if (err)
78         return err;
79     }
80   ipsec_esp_backend_t *esp =
81     pool_elt_at_index (im->esp_backends, im->esp_current_backend);
82   if (esp->add_del_sa_sess_cb)
83     {
84       clib_error_t *err = esp->add_del_sa_sess_cb (sa_index, is_add);
85       if (err)
86         return err;
87     }
88   return 0;
89 }
90
91 clib_error_t *
92 ipsec_check_support_cb (ipsec_main_t * im, ipsec_sa_t * sa)
93 {
94   clib_error_t *error = 0;
95
96   if (PREDICT_FALSE (sa->protocol == IPSEC_PROTOCOL_AH))
97     {
98       ipsec_ah_backend_t *ah =
99         pool_elt_at_index (im->ah_backends, im->ah_current_backend);
100       ASSERT (ah->check_support_cb);
101       error = ah->check_support_cb (sa);
102     }
103   else
104     {
105       ipsec_esp_backend_t *esp =
106         pool_elt_at_index (im->esp_backends, im->esp_current_backend);
107       ASSERT (esp->check_support_cb);
108       error = esp->check_support_cb (sa);
109     }
110   return error;
111 }
112
113
114 static void
115 ipsec_add_node (vlib_main_t * vm, const char *node_name,
116                 const char *prev_node_name, u32 * out_node_index,
117                 u32 * out_next_index)
118 {
119   vlib_node_t *prev_node, *node;
120   prev_node = vlib_get_node_by_name (vm, (u8 *) prev_node_name);
121   ASSERT (prev_node);
122   node = vlib_get_node_by_name (vm, (u8 *) node_name);
123   ASSERT (node);
124   *out_node_index = node->index;
125   *out_next_index = vlib_node_add_next (vm, prev_node->index, node->index);
126 }
127
128 u32
129 ipsec_register_ah_backend (vlib_main_t * vm, ipsec_main_t * im,
130                            const char *name,
131                            const char *ah4_encrypt_node_name,
132                            const char *ah4_decrypt_node_name,
133                            const char *ah6_encrypt_node_name,
134                            const char *ah6_decrypt_node_name,
135                            check_support_cb_t ah_check_support_cb,
136                            add_del_sa_sess_cb_t ah_add_del_sa_sess_cb)
137 {
138   ipsec_ah_backend_t *b;
139   pool_get (im->ah_backends, b);
140   b->name = format (NULL, "%s", name);
141
142   ipsec_add_node (vm, ah4_encrypt_node_name, "ipsec4-output-feature",
143                   &b->ah4_encrypt_node_index, &b->ah4_encrypt_next_index);
144   ipsec_add_node (vm, ah4_decrypt_node_name, "ipsec4-input-feature",
145                   &b->ah4_decrypt_node_index, &b->ah4_decrypt_next_index);
146   ipsec_add_node (vm, ah6_encrypt_node_name, "ipsec6-output-feature",
147                   &b->ah6_encrypt_node_index, &b->ah6_encrypt_next_index);
148   ipsec_add_node (vm, ah6_decrypt_node_name, "ipsec6-input-feature",
149                   &b->ah6_decrypt_node_index, &b->ah6_decrypt_next_index);
150
151   b->check_support_cb = ah_check_support_cb;
152   b->add_del_sa_sess_cb = ah_add_del_sa_sess_cb;
153   return b - im->ah_backends;
154 }
155
156 u32
157 ipsec_register_esp_backend (vlib_main_t * vm, ipsec_main_t * im,
158                             const char *name,
159                             const char *esp4_encrypt_node_name,
160                             const char *esp4_decrypt_node_name,
161                             const char *esp6_encrypt_node_name,
162                             const char *esp6_decrypt_node_name,
163                             check_support_cb_t esp_check_support_cb,
164                             add_del_sa_sess_cb_t esp_add_del_sa_sess_cb)
165 {
166   ipsec_esp_backend_t *b;
167   pool_get (im->esp_backends, b);
168   b->name = format (NULL, "%s", name);
169
170   ipsec_add_node (vm, esp4_encrypt_node_name, "ipsec4-output-feature",
171                   &b->esp4_encrypt_node_index, &b->esp4_encrypt_next_index);
172   ipsec_add_node (vm, esp4_decrypt_node_name, "ipsec4-input-feature",
173                   &b->esp4_decrypt_node_index, &b->esp4_decrypt_next_index);
174   ipsec_add_node (vm, esp6_encrypt_node_name, "ipsec6-output-feature",
175                   &b->esp6_encrypt_node_index, &b->esp6_encrypt_next_index);
176   ipsec_add_node (vm, esp6_decrypt_node_name, "ipsec6-input-feature",
177                   &b->esp6_decrypt_node_index, &b->esp6_decrypt_next_index);
178
179   b->check_support_cb = esp_check_support_cb;
180   b->add_del_sa_sess_cb = esp_add_del_sa_sess_cb;
181   return b - im->esp_backends;
182 }
183
184 int
185 ipsec_select_ah_backend (ipsec_main_t * im, u32 backend_idx)
186 {
187   if (pool_elts (im->sad) > 0
188       || pool_is_free_index (im->ah_backends, backend_idx))
189     {
190       return -1;
191     }
192   ipsec_ah_backend_t *b = pool_elt_at_index (im->ah_backends, backend_idx);
193   im->ah_current_backend = backend_idx;
194   im->ah4_encrypt_node_index = b->ah4_encrypt_node_index;
195   im->ah4_decrypt_node_index = b->ah4_decrypt_node_index;
196   im->ah4_encrypt_next_index = b->ah4_encrypt_next_index;
197   im->ah4_decrypt_next_index = b->ah4_decrypt_next_index;
198   im->ah6_encrypt_node_index = b->ah6_encrypt_node_index;
199   im->ah6_decrypt_node_index = b->ah6_decrypt_node_index;
200   im->ah6_encrypt_next_index = b->ah6_encrypt_next_index;
201   im->ah6_decrypt_next_index = b->ah6_decrypt_next_index;
202   return 0;
203 }
204
205 int
206 ipsec_select_esp_backend (ipsec_main_t * im, u32 backend_idx)
207 {
208   if (pool_elts (im->sad) > 0
209       || pool_is_free_index (im->esp_backends, backend_idx))
210     {
211       return -1;
212     }
213   ipsec_esp_backend_t *b = pool_elt_at_index (im->esp_backends, backend_idx);
214   im->esp_current_backend = backend_idx;
215   im->esp4_encrypt_node_index = b->esp4_encrypt_node_index;
216   im->esp4_decrypt_node_index = b->esp4_decrypt_node_index;
217   im->esp4_encrypt_next_index = b->esp4_encrypt_next_index;
218   im->esp4_decrypt_next_index = b->esp4_decrypt_next_index;
219   im->esp6_encrypt_node_index = b->esp6_encrypt_node_index;
220   im->esp6_decrypt_node_index = b->esp6_decrypt_node_index;
221   im->esp6_encrypt_next_index = b->esp6_encrypt_next_index;
222   im->esp6_decrypt_next_index = b->esp6_decrypt_next_index;
223   return 0;
224 }
225
226 static clib_error_t *
227 ipsec_init (vlib_main_t * vm)
228 {
229   clib_error_t *error;
230   ipsec_main_t *im = &ipsec_main;
231   vlib_thread_main_t *tm = vlib_get_thread_main ();
232
233   ipsec_rand_seed ();
234
235   clib_memset (im, 0, sizeof (im[0]));
236
237   im->vnet_main = vnet_get_main ();
238   im->vlib_main = vm;
239
240   im->spd_index_by_spd_id = hash_create (0, sizeof (uword));
241   im->sa_index_by_sa_id = hash_create (0, sizeof (uword));
242   im->spd_index_by_sw_if_index = hash_create (0, sizeof (uword));
243
244   vec_validate_aligned (im->empty_buffers, tm->n_vlib_mains - 1,
245                         CLIB_CACHE_LINE_BYTES);
246
247   vlib_node_t *node = vlib_get_node_by_name (vm, (u8 *) "error-drop");
248   ASSERT (node);
249   im->error_drop_node_index = node->index;
250
251   u32 idx = ipsec_register_ah_backend (vm, im, "default openssl backend",
252                                        "ah4-encrypt",
253                                        "ah4-decrypt",
254                                        "ah6-encrypt",
255                                        "ah6-decrypt",
256                                        ipsec_check_ah_support,
257                                        NULL);
258
259   im->ah_default_backend = idx;
260   int rv = ipsec_select_ah_backend (im, idx);
261   ASSERT (0 == rv);
262   (void) (rv);                  // avoid warning
263
264   idx = ipsec_register_esp_backend (vm, im, "default openssl backend",
265                                     "esp4-encrypt",
266                                     "esp4-decrypt",
267                                     "esp6-encrypt",
268                                     "esp6-decrypt",
269                                     ipsec_check_esp_support, NULL);
270   im->esp_default_backend = idx;
271
272   rv = ipsec_select_esp_backend (im, idx);
273   ASSERT (0 == rv);
274   (void) (rv);                  // avoid warning
275
276   if ((error = vlib_call_init_function (vm, ipsec_cli_init)))
277     return error;
278
279   if ((error = vlib_call_init_function (vm, ipsec_tunnel_if_init)))
280     return error;
281
282   ipsec_proto_init ();
283
284   if ((error = ikev2_init (vm)))
285     return error;
286
287   return 0;
288 }
289
290 VLIB_INIT_FUNCTION (ipsec_init);
291
292 /*
293  * fd.io coding-style-patch-verification: ON
294  *
295  * Local Variables:
296  * eval: (c-set-style "gnu")
297  * End:
298  */