ipsec: IPSec protection for multi-point tunnel interfaces
[vpp.git] / src / vnet / ip / ip_types.c
1 /*
2  * Copyright (c) 2016 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/ip/ip_types.h>
17 #include <vnet/ip/format.h>
18
19 u8 *
20 format_ip_address (u8 * s, va_list * args)
21 {
22   ip_address_t *a = va_arg (*args, ip_address_t *);
23   u8 ver = ip_addr_version (a);
24   if (ver == AF_IP4)
25     {
26       return format (s, "%U", format_ip4_address, &ip_addr_v4 (a));
27     }
28   else if (ver == AF_IP6)
29     {
30       return format (s, "%U", format_ip6_address, &ip_addr_v6 (a));
31     }
32   else
33     {
34       clib_warning ("Can't format IP version %d!", ver);
35       return 0;
36     }
37 }
38
39 uword
40 unformat_ip_address (unformat_input_t * input, va_list * args)
41 {
42   ip_address_t *a = va_arg (*args, ip_address_t *);
43
44   clib_memset (a, 0, sizeof (*a));
45   if (unformat (input, "%U", unformat_ip4_address, &ip_addr_v4 (a)))
46     ip_addr_version (a) = AF_IP4;
47   else if (unformat_user (input, unformat_ip6_address, &ip_addr_v6 (a)))
48     ip_addr_version (a) = AF_IP6;
49   else
50     return 0;
51   return 1;
52 }
53
54 u8 *
55 format_ip_prefix (u8 * s, va_list * args)
56 {
57   ip_prefix_t *a = va_arg (*args, ip_prefix_t *);
58   return format (s, "%U/%d", format_ip_address, &ip_prefix_addr (a),
59                  ip_prefix_len (a));
60 }
61
62 uword
63 unformat_ip_prefix (unformat_input_t * input, va_list * args)
64 {
65   ip_prefix_t *a = va_arg (*args, ip_prefix_t *);
66   if (unformat (input, "%U/%d", unformat_ip_address, &ip_prefix_addr (a),
67                 &ip_prefix_len (a)))
68     {
69       if ((ip_prefix_version (a) == AF_IP4 && 32 < ip_prefix_len (a)) ||
70           (ip_prefix_version (a) == AF_IP6 && 128 < ip_prefix_len (a)))
71         {
72           clib_warning ("Prefix length to big: %d!", ip_prefix_len (a));
73           return 0;
74         }
75       ip_prefix_normalize (a);
76     }
77   else
78     return 0;
79   return 1;
80 }
81
82 u16
83 ip_address_size (const ip_address_t * a)
84 {
85   switch (ip_addr_version (a))
86     {
87     case AF_IP4:
88       return sizeof (ip4_address_t);
89       break;
90     case AF_IP6:
91       return sizeof (ip6_address_t);
92       break;
93     }
94   return 0;
95 }
96
97 bool
98 ip_address_is_zero (const ip_address_t * ip)
99 {
100   switch (ip_addr_version (ip))
101     {
102     case AF_IP4:
103       return (ip_addr_v4 (ip).as_u32 == 0);
104     case AF_IP6:
105       return (ip_addr_v6 (ip).as_u64[0] == 0 &&
106               ip_addr_v6 (ip).as_u64[1] == 0);
107       break;
108     }
109   return false;
110 }
111
112 int
113 ip_address_cmp (const ip_address_t * ip1, const ip_address_t * ip2)
114 {
115   int res = 0;
116   if (ip_addr_version (ip1) != ip_addr_version (ip2))
117     return -1;
118   res =
119     memcmp (&ip_addr_addr (ip1), &ip_addr_addr (ip2), ip_address_size (ip1));
120
121   if (res < 0)
122     res = 2;
123   else if (res > 0)
124     res = 1;
125
126   return res;
127 }
128
129 void
130 ip_address_copy (ip_address_t * dst, const ip_address_t * src)
131 {
132   if (AF_IP4 == ip_addr_version (src))
133     {
134       /* don't copy any garbage from the union */
135       clib_memset (dst, 0, sizeof (*dst));
136       dst->ip.v4 = src->ip.v4;
137       dst->version = AF_IP4;
138     }
139   else
140     {
141       clib_memcpy (dst, src, sizeof (ip_address_t));
142     }
143 }
144
145 void
146 ip_address_copy_addr (void *dst, const ip_address_t * src)
147 {
148   clib_memcpy (dst, src, ip_address_size (src));
149 }
150
151 u16
152 ip_version_to_size (u8 ver)
153 {
154   switch (ver)
155     {
156     case AF_IP4:
157       return sizeof (ip4_address_t);
158       break;
159     case AF_IP6:
160       return sizeof (ip6_address_t);
161       break;
162     }
163   return 0;
164 }
165
166 void
167 ip_address_set (ip_address_t * dst, const void *src, u8 version)
168 {
169   clib_memcpy (dst, src, ip_version_to_size (version));
170   ip_addr_version (dst) = version;
171 }
172
173 fib_protocol_t
174 ip_address_to_46 (const ip_address_t * addr, ip46_address_t * a)
175 {
176   fib_protocol_t proto;
177
178   proto = (AF_IP4 == ip_addr_version (addr) ?
179            FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6);
180   switch (proto)
181     {
182     case FIB_PROTOCOL_IP4:
183       ip46_address_set_ip4 (a, &addr->ip.v4);
184       break;
185     case FIB_PROTOCOL_IP6:
186       a->ip6 = addr->ip.v6;
187       break;
188     default:
189       ASSERT (0);
190       break;
191     }
192
193   return (proto);
194 }
195
196 void
197 ip_address_from_46 (const ip46_address_t * nh,
198                     fib_protocol_t fproto, ip_address_t * ip)
199 {
200   switch (fproto)
201     {
202     case FIB_PROTOCOL_IP4:
203       clib_memset (ip, 0, sizeof (*ip));
204       ip_address_set (ip, &nh->ip4, AF_IP4);
205       break;
206     case FIB_PROTOCOL_IP6:
207       ip_address_set (ip, &nh->ip6, AF_IP6);
208       break;
209     default:
210       ASSERT (0);
211       break;
212     }
213 }
214
215 static void
216 ip_prefix_normalize_ip4 (ip4_address_t * ip4, u8 preflen)
217 {
218   u32 mask = ~0;
219
220   ASSERT (ip4);
221
222   if (32 <= preflen)
223     {
224       return;
225     }
226
227   mask = pow2_mask (preflen) << (32 - preflen);
228   mask = clib_host_to_net_u32 (mask);
229   ip4->data_u32 &= mask;
230 }
231
232 static void
233 ip_prefix_normalize_ip6 (ip6_address_t * ip6, u8 preflen)
234 {
235   u8 mask_6[16];
236   u32 *m;
237   u8 j, i0, i1;
238
239   ASSERT (ip6);
240
241   clib_memset (mask_6, 0, sizeof (mask_6));
242
243   if (128 <= preflen)
244     {
245       return;
246     }
247
248   i1 = preflen % 32;
249   i0 = preflen / 32;
250   m = (u32 *) & mask_6[0];
251
252   for (j = 0; j < i0; j++)
253     {
254       m[j] = ~0;
255     }
256
257   if (i1)
258     {
259       m[i0] = clib_host_to_net_u32 (pow2_mask (i1) << (32 - i1));
260     }
261
262   for (j = 0; j < sizeof (mask_6); j++)
263     {
264       ip6->as_u8[j] &= mask_6[j];
265     }
266 }
267
268 void
269 ip_prefix_normalize (ip_prefix_t * a)
270 {
271   u8 preflen = ip_prefix_len (a);
272
273   switch (ip_prefix_version (a))
274     {
275     case AF_IP4:
276       ip_prefix_normalize_ip4 (&ip_prefix_v4 (a), preflen);
277       break;
278
279     case AF_IP6:
280       ip_prefix_normalize_ip6 (&ip_prefix_v6 (a), preflen);
281       break;
282
283     default:
284       ASSERT (0);
285     }
286 }
287
288 void
289 ip_prefix_copy (void *dst, void *src)
290 {
291   clib_memcpy (dst, src, sizeof (ip_prefix_t));
292 }
293
294 int
295 ip_prefix_cmp (ip_prefix_t * p1, ip_prefix_t * p2)
296 {
297   int cmp = 0;
298
299   ip_prefix_normalize (p1);
300   ip_prefix_normalize (p2);
301
302   cmp = ip_address_cmp (&ip_prefix_addr (p1), &ip_prefix_addr (p2));
303   if (cmp == 0)
304     {
305       if (ip_prefix_len (p1) < ip_prefix_len (p2))
306         {
307           cmp = 1;
308         }
309       else
310         {
311           if (ip_prefix_len (p1) > ip_prefix_len (p2))
312             cmp = 2;
313         }
314     }
315   return cmp;
316 }
317
318 /*
319  * fd.io coding-style-patch-verification: ON
320  *
321  * Local Variables:
322  * eval: (c-set-style "gnu")
323  * End:
324  */