Line data Source code
1 : /*
2 : * proxy_node.c: common dhcp v4 and v6 proxy node processing
3 : *
4 : * Copyright (c) 2013 Cisco and/or its affiliates.
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at:
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 :
18 : #include <dhcp/dhcp_proxy.h>
19 : #include <vnet/fib/fib_table.h>
20 : #include <vnet/mfib/mfib_table.h>
21 :
22 : /**
23 : * @brief Shard 4/6 instance of DHCP main
24 : */
25 : dhcp_proxy_main_t dhcp_proxy_main;
26 :
27 : static void
28 4 : dhcp_proxy_rx_table_lock (fib_protocol_t proto, u32 fib_index)
29 : {
30 4 : if (FIB_PROTOCOL_IP4 == proto)
31 2 : fib_table_lock (fib_index, proto, FIB_SOURCE_DHCP);
32 : else
33 2 : mfib_table_lock (fib_index, proto, MFIB_SOURCE_DHCP);
34 4 : }
35 :
36 : static void
37 10 : dhcp_proxy_rx_table_unlock (fib_protocol_t proto, u32 fib_index)
38 : {
39 10 : if (FIB_PROTOCOL_IP4 == proto)
40 6 : fib_table_unlock (fib_index, proto, FIB_SOURCE_DHCP);
41 : else
42 4 : mfib_table_unlock (fib_index, proto, MFIB_SOURCE_DHCP);
43 10 : }
44 :
45 : u32
46 0 : dhcp_proxy_rx_table_get_table_id (fib_protocol_t proto, u32 fib_index)
47 : {
48 0 : if (FIB_PROTOCOL_IP4 == proto)
49 : {
50 : fib_table_t *fib;
51 :
52 0 : fib = fib_table_get (fib_index, proto);
53 :
54 0 : return (fib->ft_table_id);
55 : }
56 : else
57 : {
58 : mfib_table_t *mfib;
59 :
60 0 : mfib = mfib_table_get (fib_index, proto);
61 :
62 0 : return (mfib->mft_table_id);
63 : }
64 : }
65 :
66 : void
67 6 : dhcp_proxy_walk (fib_protocol_t proto, dhcp_proxy_walk_fn_t fn, void *ctx)
68 : {
69 6 : dhcp_proxy_main_t *dpm = &dhcp_proxy_main;
70 : dhcp_proxy_t *server;
71 : u32 server_index, i;
72 :
73 15 : vec_foreach_index (i, dpm->dhcp_server_index_by_rx_fib_index[proto])
74 : {
75 9 : server_index = dpm->dhcp_server_index_by_rx_fib_index[proto][i];
76 9 : if (~0 == server_index)
77 9 : continue;
78 :
79 0 : server = pool_elt_at_index (dpm->dhcp_servers[proto], server_index);
80 :
81 0 : if (!fn (server, ctx))
82 0 : break;
83 : }
84 6 : }
85 :
86 : void
87 0 : dhcp_vss_walk (fib_protocol_t proto, dhcp_vss_walk_fn_t fn, void *ctx)
88 : {
89 0 : dhcp_proxy_main_t *dpm = &dhcp_proxy_main;
90 : mfib_table_t *mfib;
91 : dhcp_vss_t *vss;
92 : u32 vss_index, i;
93 : fib_table_t *fib;
94 :
95 0 : vec_foreach_index (i, dpm->vss_index_by_rx_fib_index[proto])
96 : {
97 0 : vss_index = dpm->vss_index_by_rx_fib_index[proto][i];
98 0 : if (~0 == vss_index)
99 0 : continue;
100 :
101 0 : vss = pool_elt_at_index (dpm->vss[proto], vss_index);
102 :
103 0 : if (FIB_PROTOCOL_IP4 == proto)
104 : {
105 0 : fib = fib_table_get (i, proto);
106 :
107 0 : if (!fn (vss, fib->ft_table_id, ctx))
108 0 : break;
109 : }
110 : else
111 : {
112 0 : mfib = mfib_table_get (i, proto);
113 :
114 0 : if (!fn (vss, mfib->mft_table_id, ctx))
115 0 : break;
116 : }
117 : }
118 0 : }
119 :
120 : static u32
121 10 : dhcp_proxy_server_find (dhcp_proxy_t * proxy,
122 : fib_protocol_t proto,
123 : ip46_address_t * addr, u32 server_table_id)
124 : {
125 : dhcp_server_t *server;
126 : u32 ii, fib_index;
127 :
128 14 : vec_foreach_index (ii, proxy->dhcp_servers)
129 : {
130 12 : server = &proxy->dhcp_servers[ii];
131 12 : fib_index = fib_table_find (proto, server_table_id);
132 :
133 12 : if (ip46_address_is_equal (&server->dhcp_server,
134 8 : addr) &&
135 8 : (server->server_fib_index == fib_index))
136 : {
137 8 : return (ii);
138 : }
139 : }
140 2 : return (~0);
141 : }
142 :
143 : int
144 8 : dhcp_proxy_server_del (fib_protocol_t proto,
145 : u32 rx_fib_index,
146 : ip46_address_t * addr, u32 server_table_id)
147 : {
148 8 : dhcp_proxy_main_t *dpm = &dhcp_proxy_main;
149 8 : dhcp_proxy_t *proxy = 0;
150 :
151 8 : proxy = dhcp_get_proxy (dpm, rx_fib_index, proto);
152 :
153 8 : if (NULL != proxy)
154 : {
155 : dhcp_server_t *server;
156 : u32 index;
157 :
158 8 : index = dhcp_proxy_server_find (proxy, proto, addr, server_table_id);
159 :
160 8 : if (~0 != index)
161 : {
162 8 : server = &proxy->dhcp_servers[index];
163 8 : fib_table_unlock (server->server_fib_index, proto, FIB_SOURCE_DHCP);
164 :
165 8 : vec_del1 (proxy->dhcp_servers, index);
166 :
167 8 : if (0 == vec_len (proxy->dhcp_servers))
168 : {
169 : /* no servers left, delete the proxy config */
170 6 : dpm->dhcp_server_index_by_rx_fib_index[proto][rx_fib_index] =
171 : ~0;
172 6 : vec_free (proxy->dhcp_servers);
173 6 : pool_put (dpm->dhcp_servers[proto], proxy);
174 6 : return (1);
175 : }
176 : }
177 : }
178 :
179 : /* the proxy still exists */
180 2 : return (0);
181 : }
182 :
183 : int
184 8 : dhcp_proxy_server_add (fib_protocol_t proto,
185 : ip46_address_t * addr,
186 : ip46_address_t * src_address,
187 : u32 rx_fib_index, u32 server_table_id)
188 : {
189 8 : dhcp_proxy_main_t *dpm = &dhcp_proxy_main;
190 8 : dhcp_proxy_t *proxy = 0;
191 8 : int new = 0;
192 :
193 8 : proxy = dhcp_get_proxy (dpm, rx_fib_index, proto);
194 :
195 8 : if (NULL == proxy)
196 : {
197 12 : vec_validate_init_empty (dpm->dhcp_server_index_by_rx_fib_index[proto],
198 : rx_fib_index, ~0);
199 :
200 6 : pool_get (dpm->dhcp_servers[proto], proxy);
201 6 : clib_memset (proxy, 0, sizeof (*proxy));
202 6 : new = 1;
203 :
204 6 : dpm->dhcp_server_index_by_rx_fib_index[proto][rx_fib_index] =
205 6 : proxy - dpm->dhcp_servers[proto];
206 :
207 6 : proxy->dhcp_src_address = *src_address;
208 6 : proxy->rx_fib_index = rx_fib_index;
209 : }
210 : else
211 : {
212 2 : if (~0 != dhcp_proxy_server_find (proxy, proto, addr, server_table_id))
213 : {
214 0 : return (new);
215 : }
216 : }
217 :
218 16 : dhcp_server_t server = {
219 : .dhcp_server = *addr,
220 8 : .server_fib_index = fib_table_find_or_create_and_lock (proto,
221 : server_table_id,
222 : FIB_SOURCE_DHCP),
223 : };
224 :
225 8 : vec_add1 (proxy->dhcp_servers, server);
226 :
227 8 : return (new);
228 : }
229 :
230 : typedef struct dhcp4_proxy_dump_walk_ctx_t_
231 : {
232 : fib_protocol_t proto;
233 : void *opaque;
234 : u32 context;
235 : } dhcp_proxy_dump_walk_cxt_t;
236 :
237 : static int
238 0 : dhcp_proxy_dump_walk (dhcp_proxy_t * proxy, void *arg)
239 : {
240 0 : dhcp_proxy_dump_walk_cxt_t *ctx = arg;
241 :
242 0 : dhcp_send_details (ctx->proto, ctx->opaque, ctx->context, proxy);
243 :
244 0 : return (1);
245 : }
246 :
247 : void
248 6 : dhcp_proxy_dump (fib_protocol_t proto, void *opaque, u32 context)
249 : {
250 6 : dhcp_proxy_dump_walk_cxt_t ctx = {
251 : .proto = proto,
252 : .opaque = opaque,
253 : .context = context,
254 : };
255 6 : dhcp_proxy_walk (proto, dhcp_proxy_dump_walk, &ctx);
256 6 : }
257 :
258 : int
259 0 : dhcp_vss_show_walk (dhcp_vss_t * vss, u32 rx_table_id, void *ctx)
260 : {
261 0 : vlib_main_t *vm = ctx;
262 :
263 0 : if (vss->vss_type == VSS_TYPE_VPN_ID)
264 : {
265 0 : u32 oui = ((u32) vss->vpn_id[0] << 16) + ((u32) vss->vpn_id[1] << 8)
266 0 : + ((u32) vss->vpn_id[2]);
267 0 : u32 fib_id = ((u32) vss->vpn_id[3] << 24) + ((u32) vss->vpn_id[4] << 16)
268 0 : + ((u32) vss->vpn_id[5] << 8) + ((u32) vss->vpn_id[6]);
269 0 : vlib_cli_output (vm, " fib_table: %d oui: %d vpn_index: %d",
270 : rx_table_id, oui, fib_id);
271 : }
272 0 : else if (vss->vss_type == VSS_TYPE_ASCII)
273 0 : vlib_cli_output (vm, " fib_table: %d vpn_id: %s",
274 : rx_table_id, vss->vpn_ascii_id);
275 : else
276 0 : vlib_cli_output (vm, " fib_table: %d default global vpn", rx_table_id);
277 :
278 0 : return (1);
279 : }
280 :
281 : void
282 4 : update_vss (dhcp_vss_t * v,
283 : u8 vss_type, u8 * vpn_ascii_id, u32 oui, u32 vpn_index)
284 : {
285 4 : v->vss_type = vss_type;
286 4 : if (v->vpn_ascii_id)
287 : {
288 0 : if (v->vpn_ascii_id == (u8 *) ~ 0)
289 0 : v->vpn_ascii_id = 0;
290 : else
291 0 : vec_free (v->vpn_ascii_id);
292 : }
293 :
294 4 : if (vss_type == VSS_TYPE_ASCII)
295 2 : v->vpn_ascii_id = vpn_ascii_id;
296 2 : else if (vss_type == VSS_TYPE_VPN_ID)
297 : {
298 2 : v->vpn_id[0] = (oui >> 16) & 0xff;
299 2 : v->vpn_id[1] = (oui >> 8) & 0xff;
300 2 : v->vpn_id[2] = (oui >> 0) & 0xff;
301 2 : v->vpn_id[3] = (vpn_index >> 24) & 0xff;
302 2 : v->vpn_id[4] = (vpn_index >> 16) & 0xff;
303 2 : v->vpn_id[5] = (vpn_index >> 8) & 0xff;
304 2 : v->vpn_id[6] = (vpn_index >> 0) & 0xff;
305 : }
306 4 : }
307 :
308 : int
309 7 : dhcp_proxy_set_vss (fib_protocol_t proto,
310 : u32 tbl_id,
311 : u8 vss_type,
312 : u8 * vpn_ascii_id, u32 oui, u32 vpn_index, u8 is_del)
313 : {
314 7 : dhcp_proxy_main_t *dm = &dhcp_proxy_main;
315 7 : dhcp_vss_t *v = NULL;
316 : u32 rx_fib_index;
317 7 : int rc = 0;
318 :
319 7 : if (proto == FIB_PROTOCOL_IP4)
320 4 : rx_fib_index = fib_table_find_or_create_and_lock (proto, tbl_id,
321 : FIB_SOURCE_DHCP);
322 : else
323 3 : rx_fib_index = mfib_table_find_or_create_and_lock (proto, tbl_id,
324 : MFIB_SOURCE_DHCP);
325 7 : v = dhcp_get_vss_info (dm, rx_fib_index, proto);
326 :
327 7 : if (NULL != v)
328 : {
329 3 : if (is_del)
330 : {
331 : /* release the lock held on the table when the VSS
332 : * info was created */
333 3 : dhcp_proxy_rx_table_unlock (proto, rx_fib_index);
334 :
335 3 : vec_free (v->vpn_ascii_id);
336 3 : pool_put (dm->vss[proto], v);
337 3 : dm->vss_index_by_rx_fib_index[proto][rx_fib_index] = ~0;
338 : }
339 : else
340 : {
341 0 : update_vss (v, vss_type, vpn_ascii_id, oui, vpn_index);
342 : }
343 : }
344 : else
345 : {
346 4 : if (is_del)
347 0 : rc = VNET_API_ERROR_NO_SUCH_ENTRY;
348 : else
349 : {
350 : /* create a new entry */
351 10 : vec_validate_init_empty (dm->vss_index_by_rx_fib_index[proto],
352 : rx_fib_index, ~0);
353 :
354 : /* hold a lock on the table whilst the VSS info exist */
355 4 : pool_get (dm->vss[proto], v);
356 4 : update_vss (v, vss_type, vpn_ascii_id, oui, vpn_index);
357 4 : dm->vss_index_by_rx_fib_index[proto][rx_fib_index] =
358 4 : v - dm->vss[proto];
359 4 : dhcp_proxy_rx_table_lock (proto, rx_fib_index);
360 : }
361 : }
362 :
363 : /* Release the lock taken during the create_or_lock at the start */
364 7 : dhcp_proxy_rx_table_unlock (proto, rx_fib_index);
365 :
366 7 : return (rc);
367 : }
368 :
369 : /*
370 : * fd.io coding-style-patch-verification: ON
371 : *
372 : * Local Variables:
373 : * eval: (c-set-style "gnu")
374 : * End:
375 : */
|