IPSEC: SPD counters in the stats sgement
[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_tunnel_if_t *t;
90   ipsec_policy_t *p;
91
92   /* *INDENT-OFF* */
93   pool_foreach(p, im->policies, ({
94      if (p->policy == IPSEC_POLICY_ACTION_PROTECT)
95        {
96          if (p->sa_index == sa_index)
97            return 1;
98        }
99   }));
100
101   pool_foreach(t, im->tunnel_interfaces, ({
102     if (t->input_sa_index == sa_index)
103       return 1;
104     if (t->output_sa_index == sa_index)
105       return 1;
106   }));
107   /* *INDENT-ON* */
108
109   return 0;
110 }
111
112 int
113 ipsec_set_sa_key (vlib_main_t * vm, ipsec_sa_t * sa_update)
114 {
115   ipsec_main_t *im = &ipsec_main;
116   uword *p;
117   u32 sa_index;
118   ipsec_sa_t *sa = 0;
119   clib_error_t *err;
120
121   p = hash_get (im->sa_index_by_sa_id, sa_update->id);
122   if (!p)
123     return VNET_API_ERROR_SYSCALL_ERROR_1;      /* no such sa-id */
124
125   sa_index = p[0];
126   sa = pool_elt_at_index (im->sad, sa_index);
127
128   /* new crypto key */
129   if (0 < sa_update->crypto_key_len)
130     {
131       clib_memcpy (sa->crypto_key, sa_update->crypto_key,
132                    sa_update->crypto_key_len);
133       sa->crypto_key_len = sa_update->crypto_key_len;
134     }
135
136   /* new integ key */
137   if (0 < sa_update->integ_key_len)
138     {
139       clib_memcpy (sa->integ_key, sa_update->integ_key,
140                    sa_update->integ_key_len);
141       sa->integ_key_len = sa_update->integ_key_len;
142     }
143
144   if (0 < sa_update->crypto_key_len || 0 < sa_update->integ_key_len)
145     {
146       err = ipsec_call_add_del_callbacks (im, sa, sa_index, 0);
147       if (err)
148         return VNET_API_ERROR_SYSCALL_ERROR_1;
149     }
150
151   return 0;
152 }
153
154 u32
155 ipsec_get_sa_index_by_sa_id (u32 sa_id)
156 {
157   ipsec_main_t *im = &ipsec_main;
158   uword *p = hash_get (im->sa_index_by_sa_id, sa_id);
159   if (!p)
160     return ~0;
161
162   return p[0];
163 }
164
165 /*
166  * fd.io coding-style-patch-verification: ON
167  *
168  * Local Variables:
169  * eval: (c-set-style "gnu")
170  * End:
171  */