FD.io VPP  v21.10.1-2-g0a485f517
Vector Packet Processing
ip_sas.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2021 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 "ip_sas.h"
17 #include <vppinfra/types.h>
18 #include <vnet/ip/ip_interface.h>
19 #include <vnet/fib/fib_table.h>
20 #include <vnet/ip/ip6_link.h>
21 #include <vppinfra/byte_order.h>
22 
23 /*
24  * This file implement source address selection for VPP applications
25  * (e.g. ping, DNS, ICMP)
26  * It does not yet implement full fledged RFC6724 SAS.
27  * SAS assumes every IP enabled interface has an address. The algorithm will
28  * not go and hunt for a suitable IP address on other interfaces than the
29  * output interface or the specified preferred sw_if_index.
30  * That means that an interface with just an IPv6 link-local address must also
31  * be configured with an unnumbered configuration pointing to a numbered
32  * interface.
33  */
34 
35 static int
36 ip6_sas_commonlen (const ip6_address_t *a1, const ip6_address_t *a2)
37 {
38  u64 fa = clib_net_to_host_u64 (a1->as_u64[0]) ^
39  clib_net_to_host_u64 (a2->as_u64[0]);
40  if (fa == 0)
41  {
42  u64 la = clib_net_to_host_u64 (a1->as_u64[1]) ^
43  clib_net_to_host_u64 (a2->as_u64[1]);
44  if (la == 0)
45  return 128;
46  return 64 + __builtin_clzll (la);
47  }
48  else
49  {
50  return __builtin_clzll (fa);
51  }
52 }
53 
54 static int
56 {
57  u64 a =
58  clib_net_to_host_u32 (a1->as_u32) ^ clib_net_to_host_u32 (a2->as_u32);
59  if (a == 0)
60  return 32;
61  return __builtin_clz (a);
62 }
63 
64 /*
65  * walk all addresses on an interface:
66  * - prefer a source matching the scope of the destination address.
67  * - last resort pick the source address with the longest
68  * common prefix with destination
69  * NOTE: This should at some point implement RFC6724.
70  */
71 bool
72 ip6_sas_by_sw_if_index (u32 sw_if_index, const ip6_address_t *dst,
73  ip6_address_t *src)
74 {
75  ip_interface_address_t *ia = 0;
77  ip6_address_t *tmp, *bestsrc = 0;
78  int bestlen = 0, l;
79 
81  dst->as_u32[0] == clib_host_to_net_u32 (0xff020000))
82  {
84  return true;
85  }
86 
88  lm6, ia, sw_if_index, 1, ({
90  continue;
92  l = ip6_sas_commonlen (tmp, dst);
93  if (l > bestlen || bestsrc == 0)
94  {
95  bestsrc = tmp;
96  bestlen = l;
97  }
98  }));
99  if (bestsrc)
100  {
101  ip6_address_copy (src, bestsrc);
102  return true;
103  }
104  return false;
105 }
106 
107 /*
108  * walk all addresses on an interface and pick the source address with the
109  * longest common prefix with destination.
110  */
111 bool
114 {
115  ip_interface_address_t *ia = 0;
117  ip4_address_t *tmp, *bestsrc = 0;
118  int bestlen = 0, l;
119 
121  lm4, ia, sw_if_index, 1, ({
123  continue;
125  l = ip4_sas_commonlen (tmp, dst);
126  if (l > bestlen || bestsrc == 0)
127  {
128  bestsrc = tmp;
129  bestlen = l;
130  }
131  }));
132  if (bestsrc)
133  {
134  src->as_u32 = bestsrc->as_u32;
135  return true;
136  }
137  return false;
138 }
139 
140 /*
141  * table_id must be set. Default = 0.
142  * sw_if_index is the interface to pick SA from otherwise ~0 will pick from
143  * outbound interface.
144  *
145  * NOTE: What to do if multiple output interfaces?
146  *
147  */
148 bool
149 ip6_sas (u32 table_id, u32 sw_if_index, const ip6_address_t *dst,
150  ip6_address_t *src)
151 {
153  u32 if_index = sw_if_index;
154 
155  /* If sw_if_index is not specified use the output interface. */
156  if (sw_if_index == ~0)
157  {
158  clib_memcpy (&prefix.fp_addr.ip6, dst, sizeof (*dst));
159  prefix.fp_proto = FIB_PROTOCOL_IP6;
160  prefix.fp_len = 128;
161 
162  u32 fib_index = fib_table_find (prefix.fp_proto, table_id);
163  if (fib_index == (u32) ~0)
164  return false;
165 
166  fib_node_index_t fei = fib_table_lookup (fib_index, &prefix);
167  if (fei == FIB_NODE_INDEX_INVALID)
168  return false;
169 
170  u32 output_sw_if_index = fib_entry_get_resolving_interface (fei);
171  if (output_sw_if_index == ~0)
172  return false;
173  if_index = output_sw_if_index;
174  }
175  return ip6_sas_by_sw_if_index (if_index, dst, src);
176 }
177 
178 /*
179  * table_id must be set. Default = 0.
180  * sw_if_index is the interface to pick SA from otherwise ~0 will pick from
181  * outbound interface.
182  *
183  * NOTE: What to do if multiple output interfaces?
184  *
185  */
186 bool
189 {
191  u32 if_index = sw_if_index;
192 
193  /* If sw_if_index is not specified use the output interface. */
194  if (sw_if_index == ~0)
195  {
196  clib_memcpy (&prefix.fp_addr.ip4, dst, sizeof (*dst));
197  prefix.fp_proto = FIB_PROTOCOL_IP4;
198  prefix.fp_len = 32;
199 
200  u32 fib_index = fib_table_find (prefix.fp_proto, table_id);
201  if (fib_index == (u32) ~0)
202  return false;
203 
204  fib_node_index_t fei = fib_table_lookup (fib_index, &prefix);
205  if (fei == FIB_NODE_INDEX_INVALID)
206  return false;
207 
208  u32 output_sw_if_index = fib_entry_get_resolving_interface (fei);
209  if (output_sw_if_index == ~0)
210  return false;
211  if_index = output_sw_if_index;
212  }
213  return ip4_sas_by_sw_if_index (if_index, dst, src);
214 }
IP_INTERFACE_ADDRESS_FLAG_STALE
@ IP_INTERFACE_ADDRESS_FLAG_STALE
Definition: lookup.h:67
tmp
u32 * tmp
Definition: interface_output.c:1096
ip6_address_is_link_local_unicast
static uword ip6_address_is_link_local_unicast(const ip6_address_t *a)
Definition: ip6_packet.h:253
ip_interface_address_get_address
static void * ip_interface_address_get_address(ip_lookup_main_t *lm, ip_interface_address_t *a)
Definition: ip_interface.h:43
foreach_ip_interface_address
#define foreach_ip_interface_address(lm, a, sw_if_index, loop, body)
Definition: ip_interface.h:57
ip4_main_t::lookup_main
ip_lookup_main_t lookup_main
Definition: ip4.h:109
clib_memcpy
#define clib_memcpy(d, s, n)
Definition: string.h:197
types.h
ip4_main
ip4_main_t ip4_main
Global ip4 main structure.
Definition: ip4_forward.c:1104
ip4_address_t::as_u32
u32 as_u32
Definition: ip4_packet.h:57
ip_sas.h
FIB_NODE_INDEX_INVALID
#define FIB_NODE_INDEX_INVALID
Definition: fib_types.h:30
fib_table.h
byte_order.h
fib_table_lookup
fib_node_index_t fib_table_lookup(u32 fib_index, const fib_prefix_t *prefix)
Perfom a longest prefix match in the non-forwarding table.
Definition: fib_table.c:68
ip4_sas
bool ip4_sas(u32 table_id, u32 sw_if_index, const ip4_address_t *dst, ip4_address_t *src)
Definition: ip_sas.c:187
ip6_sas
bool ip6_sas(u32 table_id, u32 sw_if_index, const ip6_address_t *dst, ip6_address_t *src)
Definition: ip_sas.c:149
ip4_sas_by_sw_if_index
bool ip4_sas_by_sw_if_index(u32 sw_if_index, const ip4_address_t *dst, ip4_address_t *src)
Definition: ip_sas.c:112
fib_node_index_t
u32 fib_node_index_t
A typedef of a node index.
Definition: fib_types.h:29
ip4_sas_commonlen
static int ip4_sas_commonlen(const ip4_address_t *a1, const ip4_address_t *a2)
Definition: ip_sas.c:55
src
vl_api_address_t src
Definition: gre.api:54
ip4_address_t
Definition: ip4_packet.h:50
FIB_PROTOCOL_IP4
@ FIB_PROTOCOL_IP4
Definition: fib_types.h:36
ip6_address_copy
static void ip6_address_copy(ip6_address_t *dst, const ip6_address_t *src)
Definition: ip6_packet.h:127
fib_entry_get_resolving_interface
u32 fib_entry_get_resolving_interface(fib_node_index_t entry_index)
Definition: fib_entry.c:1474
ip6_main
ip6_main_t ip6_main
Definition: ip6_forward.c:2785
u64
unsigned long u64
Definition: types.h:89
u32
unsigned int u32
Definition: types.h:88
table_id
u32 table_id
Definition: wireguard.api:102
FIB_PROTOCOL_IP6
@ FIB_PROTOCOL_IP6
Definition: fib_types.h:37
dst
vl_api_ip4_address_t dst
Definition: pnat.api:41
ip6_main_t::lookup_main
ip_lookup_main_t lookup_main
Definition: ip6.h:112
ip_lookup_main_t
Definition: lookup.h:121
ip_interface.h
IP prefix management on interfaces.
a
a
Definition: bitmap.h:525
ip6_sas_by_sw_if_index
bool ip6_sas_by_sw_if_index(u32 sw_if_index, const ip6_address_t *dst, ip6_address_t *src)
Definition: ip_sas.c:72
ip_interface_address_t
Definition: lookup.h:89
fib_table_find
u32 fib_table_find(fib_protocol_t proto, u32 table_id)
Get the index of the FIB for a Table-ID.
Definition: fib_table.c:1111
sw_if_index
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:34
ip_interface_address_t::flags
ip_interface_address_flags_t flags
Definition: lookup.h:101
fib_prefix_t_
Aggregate type for a prefix.
Definition: fib_types.h:202
ip6_sas_commonlen
static int ip6_sas_commonlen(const ip6_address_t *a1, const ip6_address_t *a2)
Definition: ip_sas.c:36
prefix
vl_api_prefix_t prefix
Definition: ip.api:175