0ad11ba842e91b6182e4af4d591e5bc4a826baef
[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 static walk_rc_t
185 ipsec_sa_restack (ipsec_sa_t * sa, void *ctx)
186 {
187   ipsec_sa_stack (sa);
188
189   return (WALK_CONTINUE);
190 }
191
192 int
193 ipsec_select_ah_backend (ipsec_main_t * im, u32 backend_idx)
194 {
195   if (pool_elts (im->sad) > 0
196       || pool_is_free_index (im->ah_backends, backend_idx))
197     {
198       return -1;
199     }
200   ipsec_ah_backend_t *b = pool_elt_at_index (im->ah_backends, backend_idx);
201   im->ah_current_backend = backend_idx;
202   im->ah4_encrypt_node_index = b->ah4_encrypt_node_index;
203   im->ah4_decrypt_node_index = b->ah4_decrypt_node_index;
204   im->ah4_encrypt_next_index = b->ah4_encrypt_next_index;
205   im->ah4_decrypt_next_index = b->ah4_decrypt_next_index;
206   im->ah6_encrypt_node_index = b->ah6_encrypt_node_index;
207   im->ah6_decrypt_node_index = b->ah6_decrypt_node_index;
208   im->ah6_encrypt_next_index = b->ah6_encrypt_next_index;
209   im->ah6_decrypt_next_index = b->ah6_decrypt_next_index;
210
211   ipsec_sa_walk (ipsec_sa_restack, NULL);
212   return 0;
213 }
214
215 int
216 ipsec_select_esp_backend (ipsec_main_t * im, u32 backend_idx)
217 {
218   if (pool_elts (im->sad) > 0
219       || pool_is_free_index (im->esp_backends, backend_idx))
220     {
221       return -1;
222     }
223   ipsec_esp_backend_t *b = pool_elt_at_index (im->esp_backends, backend_idx);
224   im->esp_current_backend = backend_idx;
225   im->esp4_encrypt_node_index = b->esp4_encrypt_node_index;
226   im->esp4_decrypt_node_index = b->esp4_decrypt_node_index;
227   im->esp4_encrypt_next_index = b->esp4_encrypt_next_index;
228   im->esp4_decrypt_next_index = b->esp4_decrypt_next_index;
229   im->esp6_encrypt_node_index = b->esp6_encrypt_node_index;
230   im->esp6_decrypt_node_index = b->esp6_decrypt_node_index;
231   im->esp6_encrypt_next_index = b->esp6_encrypt_next_index;
232   im->esp6_decrypt_next_index = b->esp6_decrypt_next_index;
233
234   ipsec_sa_walk (ipsec_sa_restack, NULL);
235   return 0;
236 }
237
238 static clib_error_t *
239 ipsec_init (vlib_main_t * vm)
240 {
241   clib_error_t *error;
242   ipsec_main_t *im = &ipsec_main;
243   vlib_thread_main_t *tm = vlib_get_thread_main ();
244
245   ipsec_rand_seed ();
246
247   clib_memset (im, 0, sizeof (im[0]));
248
249   im->vnet_main = vnet_get_main ();
250   im->vlib_main = vm;
251
252   im->spd_index_by_spd_id = hash_create (0, sizeof (uword));
253   im->sa_index_by_sa_id = hash_create (0, sizeof (uword));
254   im->spd_index_by_sw_if_index = hash_create (0, sizeof (uword));
255
256   vec_validate_aligned (im->empty_buffers, tm->n_vlib_mains - 1,
257                         CLIB_CACHE_LINE_BYTES);
258
259   vlib_node_t *node = vlib_get_node_by_name (vm, (u8 *) "error-drop");
260   ASSERT (node);
261   im->error_drop_node_index = node->index;
262
263   u32 idx = ipsec_register_ah_backend (vm, im, "default openssl backend",
264                                        "ah4-encrypt",
265                                        "ah4-decrypt",
266                                        "ah6-encrypt",
267                                        "ah6-decrypt",
268                                        ipsec_check_ah_support,
269                                        NULL);
270
271   im->ah_default_backend = idx;
272   int rv = ipsec_select_ah_backend (im, idx);
273   ASSERT (0 == rv);
274   (void) (rv);                  // avoid warning
275
276   idx = ipsec_register_esp_backend (vm, im, "default openssl backend",
277                                     "esp4-encrypt",
278                                     "esp4-decrypt",
279                                     "esp6-encrypt",
280                                     "esp6-decrypt",
281                                     ipsec_check_esp_support, NULL);
282   im->esp_default_backend = idx;
283
284   rv = ipsec_select_esp_backend (im, idx);
285   ASSERT (0 == rv);
286   (void) (rv);                  // avoid warning
287
288   if ((error = vlib_call_init_function (vm, ipsec_cli_init)))
289     return error;
290
291   if ((error = vlib_call_init_function (vm, ipsec_tunnel_if_init)))
292     return error;
293
294   ipsec_proto_init ();
295
296   if ((error = ikev2_init (vm)))
297     return error;
298
299   return 0;
300 }
301
302 VLIB_INIT_FUNCTION (ipsec_init);
303
304 /*
305  * fd.io coding-style-patch-verification: ON
306  *
307  * Local Variables:
308  * eval: (c-set-style "gnu")
309  * End:
310  */