Line data Source code
1 : /*
2 : * Copyright (c) 2020 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 :
18 : /**
19 : * @file
20 : * @brief IP prefix management on interfaces
21 : */
22 :
23 : u32
24 8967 : ip_interface_address_find (ip_lookup_main_t * lm,
25 : void *addr_fib, u32 address_length)
26 : {
27 8967 : uword *p = mhash_get (&lm->address_to_if_address_index, addr_fib);
28 :
29 8967 : if (p)
30 4291 : return (p[0]);
31 :
32 4676 : return (~0);
33 : }
34 :
35 : clib_error_t *
36 4682 : ip_interface_address_add (ip_lookup_main_t * lm,
37 : u32 sw_if_index,
38 : void *addr_fib,
39 : u32 address_length, u32 * result_if_address_index)
40 : {
41 4682 : vnet_main_t *vnm = vnet_get_main ();
42 : ip_interface_address_t *a, *prev;
43 : u32 pi; /* previous index */
44 : u32 ai;
45 : u32 hi; /* head index */
46 :
47 : /* Verify given length. */
48 4682 : if ((address_length == 0) ||
49 4682 : (lm->is_ip6 && address_length > 128) ||
50 4682 : (!lm->is_ip6 && address_length > 32))
51 : {
52 0 : vnm->api_errno = VNET_API_ERROR_ADDRESS_LENGTH_MISMATCH;
53 0 : return clib_error_create
54 : ("%U wrong length for interface %U",
55 : lm->format_address_and_length, addr_fib,
56 : address_length, format_vnet_sw_if_index_name, vnm, sw_if_index);
57 : }
58 :
59 4682 : vec_validate_init_empty (lm->if_address_pool_index_by_sw_if_index,
60 : sw_if_index, ~0);
61 :
62 4682 : pool_get_zero (lm->if_address_pool, a);
63 :
64 4682 : ai = a - lm->if_address_pool;
65 4682 : hi = pi = lm->if_address_pool_index_by_sw_if_index[sw_if_index];
66 :
67 4682 : prev = 0;
68 4801 : while (pi != (u32) ~ 0)
69 : {
70 119 : prev = pool_elt_at_index (lm->if_address_pool, pi);
71 119 : pi = prev->next_this_sw_interface;
72 : }
73 4682 : pi = prev ? prev - lm->if_address_pool : (u32) ~ 0;
74 :
75 4682 : a->address_key = mhash_set (&lm->address_to_if_address_index,
76 : addr_fib, ai, /* old_value */ 0);
77 4682 : a->address_length = address_length;
78 4682 : a->sw_if_index = sw_if_index;
79 4682 : a->flags = 0;
80 4682 : a->prev_this_sw_interface = pi;
81 4682 : a->next_this_sw_interface = ~0;
82 4682 : if (prev)
83 76 : prev->next_this_sw_interface = ai;
84 :
85 4682 : lm->if_address_pool_index_by_sw_if_index[sw_if_index] =
86 4682 : (hi != ~0) ? hi : ai;
87 :
88 4682 : *result_if_address_index = ai;
89 :
90 4682 : return (NULL);
91 : }
92 :
93 : clib_error_t *
94 4273 : ip_interface_address_del (ip_lookup_main_t * lm,
95 : vnet_main_t * vnm,
96 : u32 address_index, void *addr_fib,
97 : u32 address_length, u32 sw_if_index)
98 : {
99 : ip_interface_address_t *a, *prev, *next;
100 :
101 4273 : a = pool_elt_at_index (lm->if_address_pool, address_index);
102 :
103 4273 : if (a->sw_if_index != sw_if_index)
104 : {
105 2 : vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
106 2 : return clib_error_create ("%U not found for interface %U",
107 : lm->format_address_and_length,
108 : addr_fib, address_length,
109 : format_vnet_sw_if_index_name,
110 : vnet_get_main (), sw_if_index);
111 : }
112 :
113 4271 : if (a->prev_this_sw_interface != ~0)
114 : {
115 10 : prev = pool_elt_at_index (lm->if_address_pool,
116 : a->prev_this_sw_interface);
117 10 : prev->next_this_sw_interface = a->next_this_sw_interface;
118 : }
119 4271 : if (a->next_this_sw_interface != ~0)
120 : {
121 66 : next = pool_elt_at_index (lm->if_address_pool,
122 : a->next_this_sw_interface);
123 66 : next->prev_this_sw_interface = a->prev_this_sw_interface;
124 :
125 66 : if (a->prev_this_sw_interface == ~0)
126 61 : lm->if_address_pool_index_by_sw_if_index[a->sw_if_index] =
127 61 : a->next_this_sw_interface;
128 : }
129 :
130 4271 : if ((a->next_this_sw_interface == ~0) && (a->prev_this_sw_interface == ~0))
131 4200 : lm->if_address_pool_index_by_sw_if_index[a->sw_if_index] = ~0;
132 :
133 4271 : mhash_unset (&lm->address_to_if_address_index, addr_fib,
134 : /* old_value */ 0);
135 4271 : pool_put (lm->if_address_pool, a);
136 4271 : return NULL;
137 : }
138 :
139 : u8
140 15 : ip_interface_has_address (u32 sw_if_index, ip46_address_t * ip, u8 is_ip4)
141 : {
142 15 : ip_interface_address_t *ia = 0;
143 :
144 15 : if (is_ip4)
145 : {
146 14 : ip_lookup_main_t *lm4 = &ip4_main.lookup_main;
147 : ip4_address_t *ip4;
148 : /* *INDENT-OFF* */
149 14 : foreach_ip_interface_address (lm4, ia, sw_if_index, 1 /* unnumbered */ ,
150 : ({
151 : ip4 = ip_interface_address_get_address (lm4, ia);
152 : if (ip4_address_compare (ip4, &ip->ip4) == 0)
153 : return 1;
154 : }));
155 : /* *INDENT-ON* */
156 : }
157 : else
158 : {
159 1 : ip_lookup_main_t *lm6 = &ip6_main.lookup_main;
160 : ip6_address_t *ip6;
161 : /* *INDENT-OFF* */
162 1 : foreach_ip_interface_address (lm6, ia, sw_if_index, 1 /* unnumbered */ ,
163 : ({
164 : ip6 = ip_interface_address_get_address (lm6, ia);
165 : if (ip6_address_compare (ip6, &ip->ip6) == 0)
166 : return 1;
167 : }));
168 : /* *INDENT-ON* */
169 : }
170 0 : return 0;
171 : }
172 :
173 : void *
174 228 : ip_interface_get_first_ip (u32 sw_if_index, u8 is_ip4)
175 : {
176 228 : ip_lookup_main_t *lm4 = &ip4_main.lookup_main;
177 228 : ip_lookup_main_t *lm6 = &ip6_main.lookup_main;
178 228 : ip_interface_address_t *ia = 0;
179 :
180 228 : if (is_ip4)
181 : {
182 : /* *INDENT-OFF* */
183 219 : foreach_ip_interface_address (lm4, ia, sw_if_index, 1 /* unnumbered */ ,
184 : ({
185 : return ip_interface_address_get_address (lm4, ia);
186 : }));
187 : /* *INDENT-ON* */
188 : }
189 : else
190 : {
191 : /* *INDENT-OFF* */
192 9 : foreach_ip_interface_address (lm6, ia, sw_if_index, 1 /* unnumbered */ ,
193 : ({
194 : ip6_address_t *rv;
195 : rv = ip_interface_address_get_address (lm6, ia);
196 : /* Trying to use a link-local ip6 src address is a fool's errand */
197 : if (!ip6_address_is_link_local_unicast (rv))
198 : return rv;
199 : }));
200 : /* *INDENT-ON* */
201 : }
202 :
203 1 : return 0;
204 : }
205 :
206 : walk_rc_t
207 50 : ip_interface_address_mark_one_interface (vnet_main_t *vnm,
208 : vnet_sw_interface_t *si, void *ctx)
209 : {
210 50 : ip_lookup_main_t *lm4 = &ip4_main.lookup_main;
211 50 : ip_lookup_main_t *lm6 = &ip6_main.lookup_main;
212 50 : ip_interface_address_t *ia = 0;
213 :
214 : /* *INDENT-OFF* */
215 94 : foreach_ip_interface_address (lm4, ia, si->sw_if_index, 1 /* unnumbered */ ,
216 : ({
217 : ia->flags |= IP_INTERFACE_ADDRESS_FLAG_STALE;
218 : }));
219 94 : foreach_ip_interface_address (lm6, ia, si->sw_if_index, 1 /* unnumbered */ ,
220 : ({
221 : ia->flags |= IP_INTERFACE_ADDRESS_FLAG_STALE;
222 : }));
223 : /* *INDENT-ON* */
224 :
225 50 : return (WALK_CONTINUE);
226 : }
227 :
228 : void
229 10 : ip_interface_address_mark (void)
230 : {
231 10 : vnet_sw_interface_walk (vnet_get_main (),
232 : ip_interface_address_mark_one_interface, NULL);
233 10 : }
234 :
235 : static walk_rc_t
236 50 : ip_interface_address_sweep_one_interface (vnet_main_t * vnm,
237 : vnet_sw_interface_t * si, void *ctx)
238 : {
239 50 : vlib_main_t *vm = vlib_get_main ();
240 50 : ip4_address_t *ip4_addrs = 0;
241 50 : ip6_address_t *ip6_addrs = 0;
242 50 : ip4_main_t *im4 = &ip4_main;
243 50 : ip6_main_t *im6 = &ip6_main;
244 : ip_interface_address_t *ia;
245 50 : u32 *ip6_masks = 0;
246 50 : u32 *ip4_masks = 0;
247 : int i;
248 :
249 : /* *INDENT-OFF* */
250 99 : foreach_ip_interface_address (&im4->lookup_main, ia, si->sw_if_index, 1,
251 : ({
252 : if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
253 : {
254 : ip4_address_t * x = (ip4_address_t *)
255 : ip_interface_address_get_address (&im4->lookup_main, ia);
256 : vec_add1 (ip4_addrs, x[0]);
257 : vec_add1 (ip4_masks, ia->address_length);
258 : }
259 : }));
260 :
261 99 : foreach_ip_interface_address (&im6->lookup_main, ia, si->sw_if_index, 1,
262 : ({
263 : if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
264 : {
265 : ip6_address_t * x = (ip6_address_t *)
266 : ip_interface_address_get_address (&im6->lookup_main, ia);
267 : vec_add1 (ip6_addrs, x[0]);
268 : vec_add1 (ip6_masks, ia->address_length);
269 : }
270 : }));
271 : /* *INDENT-ON* */
272 :
273 85 : for (i = 0; i < vec_len (ip4_addrs); i++)
274 35 : ip4_add_del_interface_address (vm, si->sw_if_index, &ip4_addrs[i],
275 35 : ip4_masks[i], 1 /* is_del */ );
276 85 : for (i = 0; i < vec_len (ip6_addrs); i++)
277 35 : ip6_add_del_interface_address (vm, si->sw_if_index, &ip6_addrs[i],
278 35 : ip6_masks[i], 1 /* is_del */ );
279 :
280 50 : vec_free (ip4_addrs);
281 50 : vec_free (ip4_masks);
282 50 : vec_free (ip6_addrs);
283 50 : vec_free (ip6_masks);
284 :
285 50 : return (WALK_CONTINUE);
286 : }
287 :
288 : void
289 10 : ip_interface_address_sweep (void)
290 : {
291 10 : vnet_sw_interface_walk (vnet_get_main (),
292 : ip_interface_address_sweep_one_interface, NULL);
293 10 : }
294 :
295 : /*
296 : * fd.io coding-style-patch-verification: ON
297 : *
298 : * Local Variables:
299 : * eval: (c-set-style "gnu")
300 : * End:
301 : */
|