FD.io VPP  v19.08-27-gf4dcae4
Vector Packet Processing
ipsec_tun.c
Go to the documentation of this file.
1 /*
2  * ipsec_tun.h : IPSEC tunnel protection
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/ipsec/ipsec_tun.h>
19 #include <vnet/ipsec/esp.h>
20 #include <vnet/udp/udp.h>
21 
22 /**
23  * Pool of tunnel protection objects
24  */
26 
27 /**
28  * DB of protected tunnels
29  */
30 typedef struct ipsec_protect_db_t_
31 {
35 
37 
38 static int
40 {
41  u32 sai = itp->itp_out_sa;
42  int is_ip4, is_l2, rv;
43 
44  is_ip4 = ip46_address_is_ip4 (&itp->itp_tun.src);
45  is_l2 = itp->itp_flags & IPSEC_PROTECT_L2;
46 
47  if (is_ip4)
48  {
49  if (is_l2)
50  rv = vnet_feature_enable_disable ("ethernet-output",
51  "esp4-encrypt-tun",
52  itp->itp_sw_if_index, enable,
53  &sai, sizeof (sai));
54  else
55  rv = vnet_feature_enable_disable ("ip4-output",
56  "esp4-encrypt-tun",
57  itp->itp_sw_if_index, enable,
58  &sai, sizeof (sai));
59  }
60  else
61  {
62  if (is_l2)
63  rv = vnet_feature_enable_disable ("ethernet-output",
64  "esp6-encrypt-tun",
65  itp->itp_sw_if_index, enable,
66  &sai, sizeof (sai));
67  else
68  rv = vnet_feature_enable_disable ("ip6-output",
69  "esp6-encrypt-tun",
70  itp->itp_sw_if_index, enable,
71  &sai, sizeof (sai));
72  }
73 
74  ASSERT (!rv);
75  return (rv);
76 }
77 
78 static void
80 {
81  const ipsec_sa_t *sa;
82  u32 sai;
83 
84  /* *INDENT-OFF* */
86  ({
87  sa = ipsec_sa_get (sai);
88 
91  .sa_index = sai,
92  };
93 
94  /*
95  * The key is formed from the tunnel's destination
96  * as the packet lookup is done from the packet's source
97  */
99  {
100  ipsec4_tunnel_key_t key = {
101  .remote_ip = itp->itp_crypto.dst.ip4,
102  .spi = clib_host_to_net_u32 (sa->spi),
103  };
104  hash_set (im->tun4_protect_by_key, key.as_u64, res.as_u64);
105  if (1 == hash_elts(im->tun4_protect_by_key))
107  UDP_DST_PORT_ipsec,
108  ipsec4_tun_input_node.index, 1);
109  }
110  else
111  {
112  ipsec6_tunnel_key_t key = {
113  .remote_ip = itp->itp_crypto.dst.ip6,
114  .spi = clib_host_to_net_u32 (sa->spi),
115  };
117  }
118  }))
119  /* *INDENT-ON* */
120 }
121 
122 static void
124  const ipsec_tun_protect_t * itp)
125 {
126  const ipsec_sa_t *sa;
127 
128  /* *INDENT-OFF* */
130  ({
131  if (ip46_address_is_ip4 (&itp->itp_crypto.dst))
132  {
133  ipsec4_tunnel_key_t key = {
134  .remote_ip = itp->itp_crypto.dst.ip4,
135  .spi = clib_host_to_net_u32 (sa->spi),
136  };
138  if (0 == hash_elts(im->tun4_protect_by_key))
140  UDP_DST_PORT_ipsec,
141  1);
142  }
143  else
144  {
145  ipsec6_tunnel_key_t key = {
146  .remote_ip = itp->itp_crypto.dst.ip6,
147  .spi = clib_host_to_net_u32 (sa->spi),
148  };
150  }
151  }))
152  /* *INDENT-ON* */
153 }
154 
155 static void
157  ipsec_tun_protect_t * itp, u32 sa_out, u32 * sas_in)
158 {
159  ipsec_sa_t *sa;
160  u32 ii;
161 
162  itp->itp_n_sa_in = vec_len (sas_in);
163  for (ii = 0; ii < itp->itp_n_sa_in; ii++)
164  itp->itp_in_sas[ii] = sas_in[ii];
165  itp->itp_out_sa = sa_out;
166 
167  /* *INDENT-OFF* */
169  ({
170  if (ipsec_sa_is_set_IS_TUNNEL (sa))
171  {
172  itp->itp_crypto.src = sa->tunnel_dst_addr;
173  itp->itp_crypto.dst = sa->tunnel_src_addr;
174  ipsec_sa_set_IS_PROTECT (sa);
176  }
177  else
178  {
179  itp->itp_crypto.src = itp->itp_tun.src;
180  itp->itp_crypto.dst = itp->itp_tun.dst;
182  }
183  }));
184  /* *INDENT-ON* */
185 
186  /*
187  * add to the DB against each SA
188  */
189  ipsec_tun_protect_db_add (im, itp);
190 
191  /*
192  * enable the encrypt feature for egress.
193  */
195 
196 }
197 
198 static void
200 {
201  ipsec_sa_t *sa;
202  index_t sai;
203 
205 
206  /* *INDENT-OFF* */
208  ({
209  ipsec_sa_unset_IS_PROTECT (sa);
210  }));
211 
212  ipsec_tun_protect_db_remove (im, itp);
213 
215 
217  ({
218  ipsec_sa_unlock(sai);
219  }));
220  /* *INDENT-ON* */
221 }
222 
223 index_t
225 {
226  if (vec_len (ipsec_protect_db.tunnels) < sw_if_index)
227  return (INDEX_INVALID);
228 
229  return (ipsec_protect_db.tunnels[sw_if_index]);
230 }
231 
232 int
234 {
235  u32 itpi, ii;
236  ipsec_tun_protect_t *itp;
237  ipsec_main_t *im;
238  int rv;
239 
240  rv = 0;
241  im = &ipsec_main;
242  vec_validate_init_empty (ipsec_protect_db.tunnels, sw_if_index,
243  INDEX_INVALID);
244  itpi = ipsec_protect_db.tunnels[sw_if_index];
245 
246  vec_foreach_index (ii, sas_in)
247  {
248  sas_in[ii] = ipsec_sa_find_and_lock (sas_in[ii]);
249  if (~0 == sas_in[ii])
250  {
251  rv = VNET_API_ERROR_INVALID_VALUE;
252  goto out;
253  }
254  }
255 
256  sa_out = ipsec_sa_find_and_lock (sa_out);
257 
258  if (~0 == sa_out)
259  {
260  rv = VNET_API_ERROR_INVALID_VALUE;
261  goto out;
262  }
263 
264  if (INDEX_INVALID == itpi)
265  {
266  vnet_device_class_t *dev_class;
268  vnet_main_t *vnm;
269  u8 is_l2;
270 
271  vnm = vnet_get_main ();
272  hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
273  dev_class = vnet_get_device_class (vnm, hi->dev_class_index);
274 
275  if (NULL == dev_class->ip_tun_desc)
276  {
277  rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
278  goto out;
279  }
280 
281  pool_get_zero (ipsec_protect_pool, itp);
282 
284  ipsec_protect_db.tunnels[sw_if_index] = itp - ipsec_protect_pool;
285  ipsec_protect_db.count++;
286 
287  itp->itp_n_sa_in = vec_len (sas_in);
288  for (ii = 0; ii < itp->itp_n_sa_in; ii++)
289  itp->itp_in_sas[ii] = sas_in[ii];
290  itp->itp_out_sa = sa_out;
291 
292  rv = dev_class->ip_tun_desc (sw_if_index,
293  &itp->itp_tun.src,
294  &itp->itp_tun.dst, &is_l2);
295 
296  if (rv)
297  goto out;
298 
299  if (is_l2)
300  itp->itp_flags |= IPSEC_PROTECT_L2;
301 
302  /*
303  * add to the tunnel DB for ingress
304  * - if the SA is in trasnport mode, then the packates will arrivw
305  * with the IP src,dst of the protected tunnel, in which case we can
306  * simply strip the IP header and hand the payload to the protocol
307  * appropriate input handler
308  * - if the SA is in tunnel mode then there are two IP headers present
309  * one for the crytpo tunnel endpoints (described in the SA) and one
310  * for the tunnel endpoints. The outer IP headers in the srriving
311  * packets will have the crypto endpoints. So the DB needs to contain
312  * the crpto endpoint. Once the crypto header is stripped, revealing,
313  * the tunnel-IP we have 2 choices:
314  * 1) do a tunnel lookup based on the revealed header
315  * 2) skip the tunnel lookup and assume that the packet matches the
316  * one that is protected here.
317  * If we did 1) then we would allow our peer to use the SA for tunnel
318  * X to inject traffic onto tunnel Y, this is not good. If we do 2)
319  * then we don't verify that the peer is indeed using SA for tunnel
320  * X and addressing tunnel X. So we take a compromise, once the SA
321  * matches to tunnel X we veriy that the inner IP matches the value
322  * of the tunnel we are protecting, else it's dropped.
323  */
324  ipsec_tun_protect_config (im, itp, sa_out, sas_in);
325 
326  if (1 == hash_elts (im->tun4_protect_by_key))
327  ip4_register_protocol (IP_PROTOCOL_IPSEC_ESP,
328  ipsec4_tun_input_node.index);
329  if (1 == hash_elts (im->tun6_protect_by_key))
330  ip6_register_protocol (IP_PROTOCOL_IPSEC_ESP,
331  ipsec6_tun_input_node.index);
332  }
333  else
334  {
335  /* updating SAs only */
336  itp = pool_elt_at_index (ipsec_protect_pool, itpi);
337 
338  ipsec_tun_protect_unconfig (im, itp);
339  ipsec_tun_protect_config (im, itp, sa_out, sas_in);
340  }
341 
342  vec_free (sas_in);
343 out:
344  return (rv);
345 }
346 
347 int
349 {
350  ipsec_tun_protect_t *itp;
351  ipsec_main_t *im;
352  index_t itpi;
353 
354  im = &ipsec_main;
355 
356  vec_validate_init_empty (ipsec_protect_db.tunnels, sw_if_index,
357  INDEX_INVALID);
358  itpi = ipsec_protect_db.tunnels[sw_if_index];
359 
360  if (INDEX_INVALID == itpi)
361  return (VNET_API_ERROR_NO_SUCH_ENTRY);
362 
363  itp = ipsec_tun_protect_get (itpi);
364  ipsec_tun_protect_unconfig (im, itp);
365 
366  ipsec_protect_db.tunnels[itp->itp_sw_if_index] = INDEX_INVALID;
367 
368  pool_put (ipsec_protect_pool, itp);
369 
370  if (0 == hash_elts (im->tun4_protect_by_key))
371  ip4_unregister_protocol (IP_PROTOCOL_IPSEC_ESP);
372  if (0 == hash_elts (im->tun6_protect_by_key))
373  ip6_unregister_protocol (IP_PROTOCOL_IPSEC_ESP);
374 
375  return (0);
376 }
377 
378 void
380 {
381  index_t itpi;
382 
383  /* *INDENT-OFF* */
384  pool_foreach_index(itpi, ipsec_protect_pool,
385  ({
386  fn (itpi, ctx);
387  }));
388  /* *INDENT-ON* */
389 }
390 
391 clib_error_t *
393 {
394  ipsec_main_t *im;
395 
396  im = &ipsec_main;
398  sizeof (ipsec6_tunnel_key_t),
399  sizeof (u64));
400  im->tun4_protect_by_key = hash_create (0, sizeof (u64));
401 
402  return 0;
403 }
404 
406 
407 
408 /*
409  * fd.io coding-style-patch-verification: ON
410  *
411  * Local Variables:
412  * eval: (c-set-style "gnu")
413  * End:
414  */
vmrglw vmrglh hi
#define vec_foreach_index(var, v)
Iterate over vector indices.
walk_rc_t(* ipsec_tun_protect_walk_cb_t)(index_t itpi, void *arg)
Definition: ipsec_tun.h:73
#define hash_set(h, key, value)
Definition: hash.h:255
static void ipsec_tun_protect_db_add(ipsec_main_t *im, const ipsec_tun_protect_t *itp)
Definition: ipsec_tun.c:79
ip46_address_t tunnel_src_addr
Definition: ipsec_sa.h:154
uword * tun6_protect_by_key
Definition: ipsec.h:119
#define hash_unset(h, key)
Definition: hash.h:261
void ip6_register_protocol(u32 protocol, u32 node_index)
Definition: ip6_forward.c:1447
vlib_node_registration_t ipsec6_tun_input_node
(constructor) VLIB_REGISTER_NODE (ipsec6_tun_input_node)
Definition: ipsec_tun_in.c:440
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
static vnet_hw_interface_t * vnet_get_sup_hw_interface(vnet_main_t *vnm, u32 sw_if_index)
#define pool_get_zero(P, E)
Allocate an object E from a pool P and zero it.
Definition: pool.h:239
void ip6_unregister_protocol(u32 protocol)
Definition: ip6_forward.c:1459
unsigned long u64
Definition: types.h:89
#define NULL
Definition: clib.h:58
DB of protected tunnels.
Definition: ipsec_tun.c:30
u32 index_t
A Data-Path Object is an object that represents actions that are applied to packets are they are swit...
Definition: dpo.h:41
#define FOR_EACH_IPSEC_PROTECT_INPUT_SA(_itp, _sa, body)
Definition: ipsec_tun.h:60
struct _vnet_device_class vnet_device_class_t
void ip4_register_protocol(u32 protocol, u32 node_index)
Definition: ip4_forward.c:1748
static ipsec_protect_db_t ipsec_protect_db
Definition: ipsec_tun.c:36
void ipsec_tun_protect_walk(ipsec_tun_protect_walk_cb_t fn, void *ctx)
Definition: ipsec_tun.c:379
unsigned char u8
Definition: types.h:56
ip46_address_t src
Definition: ipsec_tun.h:28
vl_api_interface_index_t sw_if_index
Definition: gre.api:50
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:173
ipsec_main_t ipsec_main
Definition: ipsec.c:28
static vnet_device_class_t * vnet_get_device_class(vnet_main_t *vnm, u32 dev_class_index)
static void ipsec_tun_protect_unconfig(ipsec_main_t *im, ipsec_tun_protect_t *itp)
Definition: ipsec_tun.c:199
ipsec_ep_t itp_tun
Definition: ipsec_tun.h:48
unsigned int u32
Definition: types.h:88
index_t itp_in_sas[4]
Definition: ipsec_tun.h:40
vlib_node_registration_t ipsec4_tun_input_node
(constructor) VLIB_REGISTER_NODE (ipsec4_tun_input_node)
Definition: ipsec_tun_in.c:415
u32 sa_out
Definition: ipsec.api:350
#define hash_create_mem(elts, key_bytes, value_bytes)
Definition: hash.h:661
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:514
index_t ipsec_sa_find_and_lock(u32 id)
Definition: ipsec_sa.c:313
static void ipsec_tun_protect_config(ipsec_main_t *im, ipsec_tun_protect_t *itp, u32 sa_out, u32 *sas_in)
Definition: ipsec_tun.c:156
long ctx[MAX_CONNS]
Definition: main.c:144
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:286
int ipsec_tun_protect_del(u32 sw_if_index)
Definition: ipsec_tun.c:348
static ipsec_sa_t * ipsec_sa_get(u32 sa_index)
Definition: ipsec.h:243
ip46_address_t tunnel_dst_addr
Definition: ipsec_sa.h:155
#define ip46_address_is_ip4(ip46)
Definition: ip6_packet.h:88
static void ipsec_tun_protect_db_remove(ipsec_main_t *im, const ipsec_tun_protect_t *itp)
Definition: ipsec_tun.c:123
static int ipsec_tun_protect_feature_set(ipsec_tun_protect_t *itp, u8 enable)
Definition: ipsec_tun.c:39
vlib_main_t * vm
Definition: buffer.c:312
int ipsec_tun_protect_update(u32 sw_if_index, u32 sa_out, u32 *sas_in)
Definition: ipsec_tun.c:233
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:341
clib_error_t * ipsec_tunnel_protect_init(vlib_main_t *vm)
Definition: ipsec_tun.c:392
void udp_unregister_dst_port(vlib_main_t *vm, udp_dst_port_t dst_port, u8 is_ip4)
Definition: udp_local.c:509
#define FOR_EACH_IPSEC_PROTECT_INPUT_SAI(_itp, _sai, body)
Definition: ipsec_tun.h:52
void ipsec_sa_unlock(index_t sai)
Definition: ipsec_sa.c:299
#define hash_create(elts, value_bytes)
Definition: hash.h:696
ip46_address_t dst
Definition: ipsec_tun.h:29
static uword hash_elts(void *v)
Definition: hash.h:118
#define ASSERT(truth)
ipsec_tun_protect_t * ipsec_protect_pool
Pool of tunnel protection objects.
Definition: ipsec_tun.c:25
static ipsec_tun_protect_t * ipsec_tun_protect_get(u32 index)
Definition: ipsec_tun.h:103
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
ipsec_ep_t itp_crypto
Definition: ipsec_tun.h:44
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
#define INDEX_INVALID
Invalid index - used when no index is known blazoned capitals INVALID speak volumes where ~0 does not...
Definition: dpo.h:47
static void hash_set_mem_alloc(uword **h, void *key, uword v)
Definition: hash.h:279
ipsec_protect_flags_t itp_flags
Definition: ipsec_tun.h:46
typedef key
Definition: ipsec.api:245
static void hash_unset_mem_free(uword **h, void *key)
Definition: hash.h:295
index_t ipsec_tun_protect_find(u32 sw_if_index)
Definition: ipsec_tun.c:224
void udp_register_dst_port(vlib_main_t *vm, udp_dst_port_t dst_port, u32 node_index, u8 is_ip4)
Definition: udp_local.c:471
#define pool_foreach_index(i, v, body)
Iterate pool by index.
Definition: pool.h:538
#define vec_validate_init_empty(V, I, INIT)
Make sure vector is long enough for given index and initialize empty space (no header, unspecified alignment)
Definition: vec.h:486
struct ipsec_protect_db_t_ ipsec_protect_db_t
DB of protected tunnels.
void ip4_unregister_protocol(u32 protocolx)
Definition: ip4_forward.c:1760
int vnet_feature_enable_disable(const char *arc_name, const char *node_name, u32 sw_if_index, int enable_disable, void *feature_config, u32 n_feature_config_bytes)
Definition: feature.c:274
uword * tun4_protect_by_key
Definition: ipsec.h:118