blob: fc8520d5ebbe5772b14a133cb34702af4910f9fe [file] [log] [blame]
Neale Ranns999c8ee2019-02-01 03:31:24 -08001/*
2 * Copyright (c) 2015 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 <vnet/ipsec/ipsec.h>
Neale Ranns8d7c5022019-02-06 01:41:05 -080017#include <vnet/fib/fib_table.h>
Neale Ranns999c8ee2019-02-01 03:31:24 -080018
Neale Rannseba31ec2019-02-17 18:04:27 +000019/**
20 * @brief
21 * SA packet & bytes counters
22 */
23vlib_combined_counter_main_t ipsec_sa_counters = {
24 .name = "SA",
25 .stat_segment_name = "/net/ipsec/sa",
26};
27
28
Neale Ranns999c8ee2019-02-01 03:31:24 -080029static clib_error_t *
30ipsec_call_add_del_callbacks (ipsec_main_t * im, ipsec_sa_t * sa,
31 u32 sa_index, int is_add)
32{
33 ipsec_ah_backend_t *ab;
34 ipsec_esp_backend_t *eb;
35 switch (sa->protocol)
36 {
37 case IPSEC_PROTOCOL_AH:
38 ab = pool_elt_at_index (im->ah_backends, im->ah_current_backend);
39 if (ab->add_del_sa_sess_cb)
40 return ab->add_del_sa_sess_cb (sa_index, is_add);
41 break;
42 case IPSEC_PROTOCOL_ESP:
43 eb = pool_elt_at_index (im->esp_backends, im->esp_current_backend);
44 if (eb->add_del_sa_sess_cb)
45 return eb->add_del_sa_sess_cb (sa_index, is_add);
46 break;
47 }
48 return 0;
49}
50
Neale Ranns8d7c5022019-02-06 01:41:05 -080051void
52ipsec_mk_key (ipsec_key_t * key, const u8 * data, u8 len)
53{
54 memset (key, 0, sizeof (*key));
55
56 if (len > sizeof (key->data))
57 key->len = sizeof (key->data);
58 else
59 key->len = len;
60
61 memcpy (key->data, data, key->len);
62}
63
64/**
65 * 'stack' (resolve the recursion for) the SA tunnel destination
66 */
Neale Rannsb4cfd552019-02-13 02:08:06 -080067void
Neale Ranns8d7c5022019-02-06 01:41:05 -080068ipsec_sa_stack (ipsec_sa_t * sa)
69{
Neale Rannsb4cfd552019-02-13 02:08:06 -080070 ipsec_main_t *im = &ipsec_main;
Neale Ranns8d7c5022019-02-06 01:41:05 -080071 fib_forward_chain_type_t fct;
72 dpo_id_t tmp = DPO_INVALID;
Neale Ranns8d7c5022019-02-06 01:41:05 -080073
74 fct = fib_forw_chain_type_from_fib_proto ((sa->is_tunnel_ip6 ?
75 FIB_PROTOCOL_IP6 :
76 FIB_PROTOCOL_IP4));
77
78 fib_entry_contribute_forwarding (sa->fib_entry_index, fct, &tmp);
79
Neale Rannsb4cfd552019-02-13 02:08:06 -080080 dpo_stack_from_node ((sa->is_tunnel_ip6 ?
81 im->ah6_encrypt_node_index :
82 im->ah4_encrypt_node_index),
83 &sa->dpo[IPSEC_PROTOCOL_AH], &tmp);
84 dpo_stack_from_node ((sa->is_tunnel_ip6 ?
85 im->esp6_encrypt_node_index :
86 im->esp4_encrypt_node_index),
87 &sa->dpo[IPSEC_PROTOCOL_ESP], &tmp);
88 dpo_reset (&tmp);
Neale Ranns8d7c5022019-02-06 01:41:05 -080089}
90
Neale Ranns999c8ee2019-02-01 03:31:24 -080091int
Neale Ranns8d7c5022019-02-06 01:41:05 -080092ipsec_sa_add (u32 id,
93 u32 spi,
94 ipsec_protocol_t proto,
95 ipsec_crypto_alg_t crypto_alg,
96 const ipsec_key_t * ck,
97 ipsec_integ_alg_t integ_alg,
98 const ipsec_key_t * ik,
99 ipsec_sa_flags_t flags,
100 u32 tx_table_id,
101 const ip46_address_t * tun_src,
102 const ip46_address_t * tun_dst, u32 * sa_out_index)
103{
104 ipsec_main_t *im = &ipsec_main;
105 clib_error_t *err;
106 ipsec_sa_t *sa;
107 u32 sa_index;
108 uword *p;
109
110 p = hash_get (im->sa_index_by_sa_id, id);
111 if (p)
112 return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
113
114 pool_get_zero (im->sad, sa);
115
116 fib_node_init (&sa->node, FIB_NODE_TYPE_IPSEC_SA);
117 sa_index = sa - im->sad;
118
Neale Rannseba31ec2019-02-17 18:04:27 +0000119 vlib_validate_combined_counter (&ipsec_sa_counters, sa_index);
120 vlib_zero_combined_counter (&ipsec_sa_counters, sa_index);
121
Neale Ranns8d7c5022019-02-06 01:41:05 -0800122 sa->id = id;
123 sa->spi = spi;
Neale Rannseba31ec2019-02-17 18:04:27 +0000124 sa->stat_index = sa_index;
Neale Ranns8d7c5022019-02-06 01:41:05 -0800125 sa->protocol = proto;
126 sa->crypto_alg = crypto_alg;
127 clib_memcpy (&sa->crypto_key, ck, sizeof (sa->crypto_key));
128 sa->integ_alg = integ_alg;
129 clib_memcpy (&sa->integ_key, ik, sizeof (sa->integ_key));
130 ip46_address_copy (&sa->tunnel_src_addr, tun_src);
131 ip46_address_copy (&sa->tunnel_dst_addr, tun_dst);
132
133 if (flags & IPSEC_SA_FLAG_USE_EXTENDED_SEQ_NUM)
134 sa->use_esn = 1;
135 if (flags & IPSEC_SA_FLAG_USE_ANTI_REPLAY)
136 sa->use_anti_replay = 1;
137 if (flags & IPSEC_SA_FLAG_IS_TUNNEL)
138 sa->is_tunnel = 1;
139 if (flags & IPSEC_SA_FLAG_IS_TUNNEL_V6)
140 sa->is_tunnel_ip6 = 1;
141 if (flags & IPSEC_SA_FLAG_UDP_ENCAP)
142 sa->udp_encap = 1;
143
144 err = ipsec_check_support_cb (im, sa);
145 if (err)
146 {
147 clib_warning ("%s", err->what);
148 pool_put (im->sad, sa);
149 return VNET_API_ERROR_UNIMPLEMENTED;
150 }
151
152 err = ipsec_call_add_del_callbacks (im, sa, sa_index, 1);
153 if (err)
154 {
155 pool_put (im->sad, sa);
156 return VNET_API_ERROR_SYSCALL_ERROR_1;
157 }
158
159 if (sa->is_tunnel)
160 {
161 fib_protocol_t fproto = (sa->is_tunnel_ip6 ?
162 FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4);
163 fib_prefix_t pfx = {
164 .fp_addr = sa->tunnel_dst_addr,
165 .fp_len = (sa->is_tunnel_ip6 ? 128 : 32),
166 .fp_proto = fproto,
167 };
168 sa->tx_fib_index = fib_table_find (fproto, tx_table_id);
169 if (sa->tx_fib_index == ~((u32) 0))
170 {
171 pool_put (im->sad, sa);
172 return VNET_API_ERROR_NO_SUCH_FIB;
173 }
174
175 sa->fib_entry_index = fib_table_entry_special_add (sa->tx_fib_index,
176 &pfx,
177 FIB_SOURCE_RR,
178 FIB_ENTRY_FLAG_NONE);
179 sa->sibling = fib_entry_child_add (sa->fib_entry_index,
180 FIB_NODE_TYPE_IPSEC_SA, sa_index);
181 ipsec_sa_stack (sa);
182 }
183 hash_set (im->sa_index_by_sa_id, sa->id, sa_index);
184
185 if (sa_out_index)
186 *sa_out_index = sa_index;
187
188 return (0);
189}
190
191u32
192ipsec_sa_del (u32 id)
Neale Ranns999c8ee2019-02-01 03:31:24 -0800193{
194 ipsec_main_t *im = &ipsec_main;
195 ipsec_sa_t *sa = 0;
196 uword *p;
197 u32 sa_index;
198 clib_error_t *err;
199
Neale Ranns8d7c5022019-02-06 01:41:05 -0800200 p = hash_get (im->sa_index_by_sa_id, id);
Neale Ranns999c8ee2019-02-01 03:31:24 -0800201
Neale Ranns8d7c5022019-02-06 01:41:05 -0800202 if (!p)
Neale Ranns999c8ee2019-02-01 03:31:24 -0800203 return VNET_API_ERROR_NO_SUCH_ENTRY;
204
Neale Ranns8d7c5022019-02-06 01:41:05 -0800205 sa_index = p[0];
206 sa = pool_elt_at_index (im->sad, sa_index);
207 if (ipsec_is_sa_used (sa_index))
Neale Ranns999c8ee2019-02-01 03:31:24 -0800208 {
Neale Ranns8d7c5022019-02-06 01:41:05 -0800209 clib_warning ("sa_id %u used in policy", sa->id);
210 /* sa used in policy */
211 return VNET_API_ERROR_SYSCALL_ERROR_1;
Neale Ranns999c8ee2019-02-01 03:31:24 -0800212 }
Neale Ranns8d7c5022019-02-06 01:41:05 -0800213 hash_unset (im->sa_index_by_sa_id, sa->id);
214 err = ipsec_call_add_del_callbacks (im, sa, sa_index, 0);
215 if (err)
216 return VNET_API_ERROR_SYSCALL_ERROR_1;
217 if (sa->is_tunnel)
Neale Ranns999c8ee2019-02-01 03:31:24 -0800218 {
Neale Ranns8d7c5022019-02-06 01:41:05 -0800219 fib_entry_child_remove (sa->fib_entry_index, sa->sibling);
220 fib_table_entry_special_remove
221 (sa->tx_fib_index,
222 fib_entry_get_prefix (sa->fib_entry_index), FIB_SOURCE_RR);
223 dpo_reset (&sa->dpo[IPSEC_PROTOCOL_AH]);
224 dpo_reset (&sa->dpo[IPSEC_PROTOCOL_ESP]);
Neale Ranns999c8ee2019-02-01 03:31:24 -0800225 }
Neale Ranns8d7c5022019-02-06 01:41:05 -0800226 pool_put (im->sad, sa);
Neale Ranns999c8ee2019-02-01 03:31:24 -0800227 return 0;
228}
229
230u8
231ipsec_is_sa_used (u32 sa_index)
232{
233 ipsec_main_t *im = &ipsec_main;
Neale Ranns999c8ee2019-02-01 03:31:24 -0800234 ipsec_tunnel_if_t *t;
Neale Rannsa09c1ff2019-02-04 01:10:30 -0800235 ipsec_policy_t *p;
Neale Ranns999c8ee2019-02-01 03:31:24 -0800236
237 /* *INDENT-OFF* */
Neale Rannsa09c1ff2019-02-04 01:10:30 -0800238 pool_foreach(p, im->policies, ({
239 if (p->policy == IPSEC_POLICY_ACTION_PROTECT)
240 {
241 if (p->sa_index == sa_index)
242 return 1;
243 }
Neale Ranns999c8ee2019-02-01 03:31:24 -0800244 }));
245
246 pool_foreach(t, im->tunnel_interfaces, ({
247 if (t->input_sa_index == sa_index)
248 return 1;
249 if (t->output_sa_index == sa_index)
250 return 1;
251 }));
252 /* *INDENT-ON* */
253
254 return 0;
255}
256
257int
Neale Ranns8d7c5022019-02-06 01:41:05 -0800258ipsec_set_sa_key (u32 id, const ipsec_key_t * ck, const ipsec_key_t * ik)
Neale Ranns999c8ee2019-02-01 03:31:24 -0800259{
260 ipsec_main_t *im = &ipsec_main;
261 uword *p;
262 u32 sa_index;
263 ipsec_sa_t *sa = 0;
264 clib_error_t *err;
265
Neale Ranns8d7c5022019-02-06 01:41:05 -0800266 p = hash_get (im->sa_index_by_sa_id, id);
Neale Ranns999c8ee2019-02-01 03:31:24 -0800267 if (!p)
268 return VNET_API_ERROR_SYSCALL_ERROR_1; /* no such sa-id */
269
270 sa_index = p[0];
271 sa = pool_elt_at_index (im->sad, sa_index);
272
273 /* new crypto key */
Neale Ranns8d7c5022019-02-06 01:41:05 -0800274 if (ck)
Neale Ranns999c8ee2019-02-01 03:31:24 -0800275 {
Neale Ranns8d7c5022019-02-06 01:41:05 -0800276 clib_memcpy (&sa->crypto_key, ck, sizeof (sa->crypto_key));
Neale Ranns999c8ee2019-02-01 03:31:24 -0800277 }
278
279 /* new integ key */
Neale Ranns8d7c5022019-02-06 01:41:05 -0800280 if (ik)
Neale Ranns999c8ee2019-02-01 03:31:24 -0800281 {
Neale Ranns8d7c5022019-02-06 01:41:05 -0800282 clib_memcpy (&sa->integ_key, 0, sizeof (sa->integ_key));
Neale Ranns999c8ee2019-02-01 03:31:24 -0800283 }
284
Neale Ranns8d7c5022019-02-06 01:41:05 -0800285 if (ck || ik)
Neale Ranns999c8ee2019-02-01 03:31:24 -0800286 {
287 err = ipsec_call_add_del_callbacks (im, sa, sa_index, 0);
288 if (err)
Kingwel Xie364b1ca2019-02-12 04:47:33 -0800289 {
290 clib_error_free (err);
291 return VNET_API_ERROR_SYSCALL_ERROR_1;
292 }
Neale Ranns999c8ee2019-02-01 03:31:24 -0800293 }
294
295 return 0;
296}
297
298u32
299ipsec_get_sa_index_by_sa_id (u32 sa_id)
300{
301 ipsec_main_t *im = &ipsec_main;
302 uword *p = hash_get (im->sa_index_by_sa_id, sa_id);
303 if (!p)
304 return ~0;
305
306 return p[0];
307}
308
Neale Rannsb4cfd552019-02-13 02:08:06 -0800309void
310ipsec_sa_walk (ipsec_sa_walk_cb_t cb, void *ctx)
311{
312 ipsec_main_t *im = &ipsec_main;
313 ipsec_sa_t *sa;
314
315 /* *INDENT-OFF* */
316 pool_foreach (sa, im->sad,
317 ({
318 if (WALK_CONTINUE != cb(sa, ctx))
319 break;
320 }));
321 /* *INDENT-ON* */
322}
323
Neale Ranns8d7c5022019-02-06 01:41:05 -0800324/**
325 * Function definition to get a FIB node from its index
326 */
327static fib_node_t *
328ipsec_sa_fib_node_get (fib_node_index_t index)
329{
330 ipsec_main_t *im;
331 ipsec_sa_t *sa;
332
333 im = &ipsec_main;
334 sa = pool_elt_at_index (im->sad, index);
335
336 return (&sa->node);
337}
338
339/**
340 * Function definition to inform the FIB node that its last lock has gone.
341 */
342static void
343ipsec_sa_last_lock_gone (fib_node_t * node)
344{
345 /*
346 * The ipsec SA is a root of the graph. As such
347 * it never has children and thus is never locked.
348 */
349 ASSERT (0);
350}
351
352static ipsec_sa_t *
353ipsec_sa_from_fib_node (fib_node_t * node)
354{
355 ASSERT (FIB_NODE_TYPE_IPSEC_SA == node->fn_type);
356 return ((ipsec_sa_t *) (((char *) node) -
357 STRUCT_OFFSET_OF (ipsec_sa_t, node)));
358
359}
360
361/**
362 * Function definition to backwalk a FIB node
363 */
364static fib_node_back_walk_rc_t
365ipsec_sa_back_walk (fib_node_t * node, fib_node_back_walk_ctx_t * ctx)
366{
367 ipsec_sa_stack (ipsec_sa_from_fib_node (node));
368
369 return (FIB_NODE_BACK_WALK_CONTINUE);
370}
371
372/*
373 * Virtual function table registered by MPLS GRE tunnels
374 * for participation in the FIB object graph.
375 */
376const static fib_node_vft_t ipsec_sa_vft = {
377 .fnv_get = ipsec_sa_fib_node_get,
378 .fnv_last_lock = ipsec_sa_last_lock_gone,
379 .fnv_back_walk = ipsec_sa_back_walk,
380};
381
382/* force inclusion from application's main.c */
383clib_error_t *
384ipsec_sa_interface_init (vlib_main_t * vm)
385{
386 fib_node_register_type (FIB_NODE_TYPE_IPSEC_SA, &ipsec_sa_vft);
387
388 return 0;
389}
390
391VLIB_INIT_FUNCTION (ipsec_sa_interface_init);
392
Neale Ranns999c8ee2019-02-01 03:31:24 -0800393/*
394 * fd.io coding-style-patch-verification: ON
395 *
396 * Local Variables:
397 * eval: (c-set-style "gnu")
398 * End:
399 */