IPSEC: minor refactor
[vpp.git] / src / vnet / ipsec / ipsec_sa.c
1 /*
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>
17
18 static clib_error_t *
19 ipsec_call_add_del_callbacks (ipsec_main_t * im, ipsec_sa_t * sa,
20                               u32 sa_index, int is_add)
21 {
22   ipsec_ah_backend_t *ab;
23   ipsec_esp_backend_t *eb;
24   switch (sa->protocol)
25     {
26     case IPSEC_PROTOCOL_AH:
27       ab = pool_elt_at_index (im->ah_backends, im->ah_current_backend);
28       if (ab->add_del_sa_sess_cb)
29         return ab->add_del_sa_sess_cb (sa_index, is_add);
30       break;
31     case IPSEC_PROTOCOL_ESP:
32       eb = pool_elt_at_index (im->esp_backends, im->esp_current_backend);
33       if (eb->add_del_sa_sess_cb)
34         return eb->add_del_sa_sess_cb (sa_index, is_add);
35       break;
36     }
37   return 0;
38 }
39
40 int
41 ipsec_add_del_sa (vlib_main_t * vm, ipsec_sa_t * new_sa, int is_add)
42 {
43   ipsec_main_t *im = &ipsec_main;
44   ipsec_sa_t *sa = 0;
45   uword *p;
46   u32 sa_index;
47   clib_error_t *err;
48
49   clib_warning ("id %u spi %u", new_sa->id, new_sa->spi);
50
51   p = hash_get (im->sa_index_by_sa_id, new_sa->id);
52   if (p && is_add)
53     return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
54   if (!p && !is_add)
55     return VNET_API_ERROR_NO_SUCH_ENTRY;
56
57   if (!is_add)                  /* delete */
58     {
59       sa_index = p[0];
60       sa = pool_elt_at_index (im->sad, sa_index);
61       if (ipsec_is_sa_used (sa_index))
62         {
63           clib_warning ("sa_id %u used in policy", sa->id);
64           return VNET_API_ERROR_SYSCALL_ERROR_1;        /* sa used in policy */
65         }
66       hash_unset (im->sa_index_by_sa_id, sa->id);
67       err = ipsec_call_add_del_callbacks (im, sa, sa_index, 0);
68       if (err)
69         return VNET_API_ERROR_SYSCALL_ERROR_1;
70       pool_put (im->sad, sa);
71     }
72   else                          /* create new SA */
73     {
74       pool_get (im->sad, sa);
75       clib_memcpy (sa, new_sa, sizeof (*sa));
76       sa_index = sa - im->sad;
77       hash_set (im->sa_index_by_sa_id, sa->id, sa_index);
78       err = ipsec_call_add_del_callbacks (im, sa, sa_index, 1);
79       if (err)
80         return VNET_API_ERROR_SYSCALL_ERROR_1;
81     }
82   return 0;
83 }
84
85 u8
86 ipsec_is_sa_used (u32 sa_index)
87 {
88   ipsec_main_t *im = &ipsec_main;
89   ipsec_spd_t *spd;
90   ipsec_policy_t *p;
91   ipsec_tunnel_if_t *t;
92
93   /* *INDENT-OFF* */
94   pool_foreach(spd, im->spds, ({
95     pool_foreach(p, spd->policies, ({
96       if (p->policy == IPSEC_POLICY_ACTION_PROTECT)
97         {
98           if (p->sa_index == sa_index)
99             return 1;
100         }
101     }));
102   }));
103
104   pool_foreach(t, im->tunnel_interfaces, ({
105     if (t->input_sa_index == sa_index)
106       return 1;
107     if (t->output_sa_index == sa_index)
108       return 1;
109   }));
110   /* *INDENT-ON* */
111
112   return 0;
113 }
114
115 int
116 ipsec_set_sa_key (vlib_main_t * vm, ipsec_sa_t * sa_update)
117 {
118   ipsec_main_t *im = &ipsec_main;
119   uword *p;
120   u32 sa_index;
121   ipsec_sa_t *sa = 0;
122   clib_error_t *err;
123
124   p = hash_get (im->sa_index_by_sa_id, sa_update->id);
125   if (!p)
126     return VNET_API_ERROR_SYSCALL_ERROR_1;      /* no such sa-id */
127
128   sa_index = p[0];
129   sa = pool_elt_at_index (im->sad, sa_index);
130
131   /* new crypto key */
132   if (0 < sa_update->crypto_key_len)
133     {
134       clib_memcpy (sa->crypto_key, sa_update->crypto_key,
135                    sa_update->crypto_key_len);
136       sa->crypto_key_len = sa_update->crypto_key_len;
137     }
138
139   /* new integ key */
140   if (0 < sa_update->integ_key_len)
141     {
142       clib_memcpy (sa->integ_key, sa_update->integ_key,
143                    sa_update->integ_key_len);
144       sa->integ_key_len = sa_update->integ_key_len;
145     }
146
147   if (0 < sa_update->crypto_key_len || 0 < sa_update->integ_key_len)
148     {
149       err = ipsec_call_add_del_callbacks (im, sa, sa_index, 0);
150       if (err)
151         return VNET_API_ERROR_SYSCALL_ERROR_1;
152     }
153
154   return 0;
155 }
156
157 u32
158 ipsec_get_sa_index_by_sa_id (u32 sa_id)
159 {
160   ipsec_main_t *im = &ipsec_main;
161   uword *p = hash_get (im->sa_index_by_sa_id, sa_id);
162   if (!p)
163     return ~0;
164
165   return p[0];
166 }
167
168 /*
169  * fd.io coding-style-patch-verification: ON
170  *
171  * Local Variables:
172  * eval: (c-set-style "gnu")
173  * End:
174  */