ip.c revision 9534696b
1/*
2 * Copyright (c) 2017 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.h>
17#include <vnet/fib/fib_table.h>
18
19u8
20ip_is_zero (ip46_address_t * ip46_address, u8 is_ip4)
21{
22  if (is_ip4)
23    return (ip46_address->ip4.as_u32 == 0);
24  else
25    return (ip46_address->as_u64[0] == 0 && ip46_address->as_u64[1] == 0);
26}
27
28u8
29ip_is_local_host (ip46_address_t * ip46_address, u8 is_ip4)
30{
31  if (is_ip4)
32    return (ip46_address->ip4.as_u8[0] == 127);
33  else
34    return (ip46_address->as_u64[0] == 0 &&
35	    clib_net_to_host_u64 (ip46_address->as_u64[1]) == 1);
36}
37
38u8
39ip4_is_local_host (ip4_address_t * ip4_address)
40{
41  return (ip4_address->as_u8[0] == 127);
42}
43
44u8
45ip6_is_local_host (ip6_address_t * ip6_address)
46{
47  return (ip6_address->as_u64[0] == 0 &&
48	  clib_net_to_host_u64 (ip6_address->as_u64[1]) == 1);
49}
50
51/**
52 * Checks that an ip is local to the requested fib
53 */
54u8
55ip_is_local (u32 fib_index, ip46_address_t * ip46_address, u8 is_ip4)
56{
57  fib_node_index_t fei;
58  fib_entry_flag_t flags;
59  fib_prefix_t prefix;
60
61  /* Check if requester is local */
62  if (is_ip4)
63    {
64      prefix.fp_len = 32;
65      prefix.fp_proto = FIB_PROTOCOL_IP4;
66    }
67  else
68    {
69      prefix.fp_len = 128;
70      prefix.fp_proto = FIB_PROTOCOL_IP6;
71    }
72
73  clib_memcpy_fast (&prefix.fp_addr, ip46_address, sizeof (ip46_address_t));
74  fei = fib_table_lookup (fib_index, &prefix);
75  flags = fib_entry_get_flags (fei);
76
77  return (flags & FIB_ENTRY_FLAG_LOCAL);
78}
79
80void
81ip_copy (ip46_address_t * dst, ip46_address_t * src, u8 is_ip4)
82{
83  if (is_ip4)
84    dst->ip4.as_u32 = src->ip4.as_u32;
85  else
86    clib_memcpy_fast (&dst->ip6, &src->ip6, sizeof (ip6_address_t));
87}
88
89void
90ip_set (ip46_address_t * dst, void *src, u8 is_ip4)
91{
92  if (is_ip4)
93    dst->ip4.as_u32 = ((ip4_address_t *) src)->as_u32;
94  else
95    clib_memcpy_fast (&dst->ip6, (ip6_address_t *) src,
96		      sizeof (ip6_address_t));
97}
98
99u8
100ip_interface_has_address (u32 sw_if_index, ip46_address_t * ip, u8 is_ip4)
101{
102  ip_interface_address_t *ia = 0;
103
104  if (is_ip4)
105    {
106      ip_lookup_main_t *lm4 = &ip4_main.lookup_main;
107      ip4_address_t *ip4;
108      /* *INDENT-OFF* */
109      foreach_ip_interface_address (lm4, ia, sw_if_index, 1 /* unnumbered */ ,
110      ({
111        ip4 = ip_interface_address_get_address (lm4, ia);
112        if (ip4_address_compare (ip4, &ip->ip4) == 0)
113          return 1;
114      }));
115      /* *INDENT-ON* */
116    }
117  else
118    {
119      ip_lookup_main_t *lm6 = &ip6_main.lookup_main;
120      ip6_address_t *ip6;
121      /* *INDENT-OFF* */
122      foreach_ip_interface_address (lm6, ia, sw_if_index, 1 /* unnumbered */ ,
123      ({
124        ip6 = ip_interface_address_get_address (lm6, ia);
125        if (ip6_address_compare (ip6, &ip->ip6) == 0)
126          return 1;
127      }));
128      /* *INDENT-ON* */
129    }
130  return 0;
131}
132
133void *
134ip_interface_get_first_ip (u32 sw_if_index, u8 is_ip4)
135{
136  ip_lookup_main_t *lm4 = &ip4_main.lookup_main;
137  ip_lookup_main_t *lm6 = &ip6_main.lookup_main;
138  ip_interface_address_t *ia = 0;
139
140  if (is_ip4)
141    {
142      /* *INDENT-OFF* */
143      foreach_ip_interface_address (lm4, ia, sw_if_index, 1 /* unnumbered */ ,
144      ({
145        return ip_interface_address_get_address (lm4, ia);
146      }));
147      /* *INDENT-ON* */
148    }
149  else
150    {
151      /* *INDENT-OFF* */
152      foreach_ip_interface_address (lm6, ia, sw_if_index, 1 /* unnumbered */ ,
153      ({
154        ip6_address_t *rv;
155        rv = ip_interface_address_get_address (lm6, ia);
156        /* Trying to use a link-local ip6 src address is a fool's errand */
157        if (!ip6_address_is_link_local_unicast (rv))
158          return rv;
159      }));
160      /* *INDENT-ON* */
161    }
162
163  return 0;
164}
165
166void
167ip4_address_normalize (ip4_address_t * ip4, u8 preflen)
168{
169  ASSERT (preflen <= 32);
170  if (preflen == 0)
171    ip4->data_u32 = 0;
172  else
173    ip4->data_u32 &= clib_net_to_host_u32 (0xffffffff << (32 - preflen));
174}
175
176void
177ip6_address_normalize (ip6_address_t * ip6, u8 preflen)
178{
179  ASSERT (preflen <= 128);
180  if (preflen == 0)
181    {
182      ip6->as_u64[0] = 0;
183      ip6->as_u64[1] = 0;
184    }
185  else if (preflen <= 64)
186    {
187      ip6->as_u64[0] &=
188	clib_host_to_net_u64 (0xffffffffffffffffL << (64 - preflen));
189      ip6->as_u64[1] = 0;
190    }
191  else
192    ip6->as_u64[1] &=
193      clib_host_to_net_u64 (0xffffffffffffffffL << (128 - preflen));
194}
195
196void
197ip4_preflen_to_mask (u8 pref_len, ip4_address_t * ip)
198{
199  if (pref_len == 0)
200    ip->as_u32 = 0;
201  else
202    ip->as_u32 = clib_host_to_net_u32 (~((1 << (32 - pref_len)) - 1));
203}
204
205u32
206ip4_mask_to_preflen (ip4_address_t * mask)
207{
208  if (mask->as_u32 == 0)
209    return 0;
210  return (32 - log2_first_set (clib_net_to_host_u32 (mask->as_u32)));
211}
212
213void
214ip4_prefix_max_address_host_order (ip4_address_t * ip, u8 plen,
215				   ip4_address_t * res)
216{
217  u32 not_mask;
218  not_mask = (1 << (32 - plen)) - 1;
219  res->as_u32 = clib_net_to_host_u32 (ip->as_u32) + not_mask;
220}
221
222void
223ip6_preflen_to_mask (u8 pref_len, ip6_address_t * mask)
224{
225  if (pref_len == 0)
226    {
227      mask->as_u64[0] = 0;
228      mask->as_u64[1] = 0;
229    }
230  else if (pref_len <= 64)
231    {
232      mask->as_u64[0] =
233	clib_host_to_net_u64 (0xffffffffffffffffL << (64 - pref_len));
234      mask->as_u64[1] = 0;
235    }
236  else
237    {
238      mask->as_u64[0] = 0xffffffffffffffffL;
239      mask->as_u64[1] =
240	clib_host_to_net_u64 (0xffffffffffffffffL << (128 - pref_len));
241    }
242}
243
244void
245ip6_prefix_max_address_host_order (ip6_address_t * ip, u8 plen,
246				   ip6_address_t * res)
247{
248  u64 not_mask;
249  if (plen == 0)
250    {
251      res->as_u64[0] = 0xffffffffffffffffL;
252      res->as_u64[1] = 0xffffffffffffffffL;
253    }
254  else if (plen <= 64)
255    {
256      not_mask = ((u64) 1 << (64 - plen)) - 1;
257      res->as_u64[0] = clib_net_to_host_u64 (ip->as_u64[0]) + not_mask;
258      res->as_u64[1] = 0xffffffffffffffffL;
259    }
260  else
261    {
262      not_mask = ((u64) 1 << (128 - plen)) - 1;
263      res->as_u64[1] = clib_net_to_host_u64 (ip->as_u64[1]) + not_mask;
264    }
265}
266
267u32
268ip6_mask_to_preflen (ip6_address_t * mask)
269{
270  u8 first1, first0;
271  if (mask->as_u64[0] == 0 && mask->as_u64[1] == 0)
272    return 0;
273  first1 = log2_first_set (clib_net_to_host_u64 (mask->as_u64[1]));
274  first0 = log2_first_set (clib_net_to_host_u64 (mask->as_u64[0]));
275
276  if (first1 != 0)
277    return 128 - first1;
278  else
279    return 64 - first0;
280}
281
282u8 *
283format_ip_address_family (u8 * s, va_list * args)
284{
285  ip_address_family_t af = va_arg (*args, ip_address_family_t);
286
287  switch (af)
288    {
289    case AF_IP4:
290      return (format (s, "ip4"));
291    case AF_IP6:
292      return (format (s, "ip6"));
293    }
294
295  return (format (s, "unknown"));
296}
297
298u8 *
299format_ip_dscp (u8 * s, va_list * va)
300{
301  ip_dscp_t dscp = va_arg (*va, u32);	// int promotion of u8
302
303  switch (dscp)
304    {
305#define _(n,v)                                                  \
306    case IP_DSCP_##v:                                           \
307      return (format (s, "%s", #v));
308      foreach_ip_dscp
309#undef _
310    }
311
312  return (format (s, "unknown"));
313}
314
315u8 *
316format_ip_ecn (u8 * s, va_list * va)
317{
318  ip_ecn_t ecn = va_arg (*va, u32);	// int promotion of u8
319
320  switch (ecn)
321    {
322#define _(n,v)                                                  \
323    case IP_ECN_##v:                                           \
324      return (format (s, "%s", #v));
325      foreach_ip_ecn
326#undef _
327    }
328
329  return (format (s, "unknown"));
330}
331
332/*
333 * fd.io coding-style-patch-verification: ON
334 *
335 * Local Variables:
336 * eval: (c-set-style "gnu")
337 * End:
338 */
339