Line data Source code
1 : /*
2 : * dhcp6_proxy_node.c: dhcpv6 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 <vlib/vlib.h>
19 : #include <dhcp/dhcp_proxy.h>
20 : #include <dhcp/dhcp6_packet.h>
21 : #include <vnet/mfib/mfib_table.h>
22 : #include <vnet/mfib/ip6_mfib.h>
23 : #include <vnet/fib/fib.h>
24 :
25 : static char *dhcpv6_proxy_error_strings[] = {
26 : #define dhcpv6_proxy_error(n,s) s,
27 : #include <dhcp/dhcp6_proxy_error.def>
28 : #undef dhcpv6_proxy_error
29 : };
30 :
31 : #define foreach_dhcpv6_proxy_to_server_input_next \
32 : _ (DROP, "error-drop") \
33 : _ (LOOKUP, "ip6-lookup") \
34 : _ (SEND_TO_CLIENT, "dhcpv6-proxy-to-client")
35 :
36 :
37 : typedef enum
38 : {
39 : #define _(s,n) DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_##s,
40 : foreach_dhcpv6_proxy_to_server_input_next
41 : #undef _
42 : DHCPV6_PROXY_TO_SERVER_INPUT_N_NEXT,
43 : } dhcpv6_proxy_to_server_input_next_t;
44 :
45 : typedef struct
46 : {
47 : /* 0 => to server, 1 => to client */
48 : int which;
49 : u8 packet_data[64];
50 : u32 error;
51 : u32 sw_if_index;
52 : u32 original_sw_if_index;
53 : } dhcpv6_proxy_trace_t;
54 :
55 : static vlib_node_registration_t dhcpv6_proxy_to_server_node;
56 : static vlib_node_registration_t dhcpv6_proxy_to_client_node;
57 :
58 : /* all DHCP servers address */
59 : static ip6_address_t all_dhcpv6_server_address;
60 : static ip6_address_t all_dhcpv6_server_relay_agent_address;
61 :
62 : static u8 *
63 5 : format_dhcpv6_proxy_trace (u8 * s, va_list * args)
64 : {
65 5 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
66 5 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
67 5 : dhcpv6_proxy_trace_t *t = va_arg (*args, dhcpv6_proxy_trace_t *);
68 :
69 5 : if (t->which == 0)
70 1 : s = format (s, "DHCPV6 proxy: sent to server %U",
71 : format_ip6_address, &t->packet_data, sizeof (ip6_address_t));
72 : else
73 4 : s = format (s, "DHCPV6 proxy: sent to client from %U",
74 : format_ip6_address, &t->packet_data, sizeof (ip6_address_t));
75 5 : if (t->error != (u32) ~ 0)
76 4 : s = format (s, " error: %s\n", dhcpv6_proxy_error_strings[t->error]);
77 :
78 5 : s = format (s, " original_sw_if_index: %d, sw_if_index: %d\n",
79 : t->original_sw_if_index, t->sw_if_index);
80 :
81 5 : return s;
82 : }
83 :
84 : static u8 *
85 0 : format_dhcpv6_proxy_header_with_length (u8 * s, va_list * args)
86 : {
87 0 : dhcpv6_header_t *h = va_arg (*args, dhcpv6_header_t *);
88 0 : u32 max_header_bytes = va_arg (*args, u32);
89 : u32 header_bytes;
90 :
91 0 : header_bytes = sizeof (h[0]);
92 0 : if (max_header_bytes != 0 && header_bytes > max_header_bytes)
93 0 : return format (s, "dhcpv6 header truncated");
94 :
95 0 : s = format (s, "DHCPV6 Proxy");
96 :
97 0 : return s;
98 : }
99 :
100 : /* get first interface address */
101 : static ip6_address_t *
102 18 : ip6_interface_first_global_or_site_address (ip6_main_t * im, u32 sw_if_index)
103 : {
104 18 : ip_lookup_main_t *lm = &im->lookup_main;
105 18 : ip_interface_address_t *ia = 0;
106 18 : ip6_address_t *result = 0;
107 :
108 : /* *INDENT-OFF* */
109 18 : foreach_ip_interface_address (lm, ia, sw_if_index,
110 : 1 /* honor unnumbered */,
111 : ({
112 : ip6_address_t * a = ip_interface_address_get_address (lm, ia);
113 : if ((a->as_u8[0] & 0xe0) == 0x20 ||
114 : (a->as_u8[0] & 0xfe) == 0xfc) {
115 : result = a;
116 : break;
117 : }
118 : }));
119 : /* *INDENT-ON* */
120 18 : return result;
121 : }
122 :
123 : static inline void
124 67 : copy_ip6_address (ip6_address_t * dst, ip6_address_t * src)
125 : {
126 67 : dst->as_u64[0] = src->as_u64[0];
127 67 : dst->as_u64[1] = src->as_u64[1];
128 67 : }
129 :
130 : static uword
131 9 : dhcpv6_proxy_to_server_input (vlib_main_t * vm,
132 : vlib_node_runtime_t * node,
133 : vlib_frame_t * from_frame)
134 : {
135 : u32 n_left_from, next_index, *from, *to_next;
136 9 : dhcp_proxy_main_t *dpm = &dhcp_proxy_main;
137 9 : from = vlib_frame_vector_args (from_frame);
138 9 : n_left_from = from_frame->n_vectors;
139 9 : u32 pkts_to_server = 0, pkts_to_client = 0;
140 9 : u32 pkts_no_interface_address = 0;
141 9 : u32 pkts_no_src_address = 0;
142 9 : u32 pkts_wrong_msg_type = 0;
143 9 : u32 pkts_too_big = 0;
144 9 : ip6_main_t *im = &ip6_main;
145 : ip6_address_t *src;
146 : int bogus_length;
147 : dhcp_proxy_t *proxy;
148 : dhcp_server_t *server;
149 9 : u32 rx_fib_idx = 0, server_fib_idx = 0;
150 :
151 9 : next_index = node->cached_next_index;
152 :
153 18 : while (n_left_from > 0)
154 : {
155 : u32 n_left_to_next;
156 :
157 9 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
158 :
159 18 : while (n_left_from > 0 && n_left_to_next > 0)
160 : {
161 9 : vnet_main_t *vnm = vnet_get_main ();
162 9 : u32 sw_if_index = 0;
163 9 : u32 rx_sw_if_index = 0;
164 : vnet_sw_interface_t *swif;
165 : u32 bi0;
166 : vlib_buffer_t *b0;
167 : udp_header_t *u0, *u1;
168 : dhcpv6_header_t *h0; // client msg hdr
169 : ip6_header_t *ip0, *ip1;
170 9 : ip6_address_t _ia0, *ia0 = &_ia0;
171 : u32 next0;
172 9 : u32 error0 = (u32) ~ 0;
173 : dhcpv6_option_t *fwd_opt;
174 : dhcpv6_relay_hdr_t *r1;
175 : u16 len;
176 : dhcpv6_int_id_t *id1;
177 : dhcpv6_vss_t *vss1;
178 : dhcpv6_client_mac_t *cmac; // client mac
179 : ethernet_header_t *e_h0;
180 : u8 client_src_mac[6];
181 : dhcp_vss_t *vss;
182 9 : u8 is_solicit = 0;
183 :
184 9 : bi0 = from[0];
185 9 : from += 1;
186 9 : n_left_from -= 1;
187 :
188 9 : b0 = vlib_get_buffer (vm, bi0);
189 :
190 9 : h0 = vlib_buffer_get_current (b0);
191 :
192 : /*
193 : * udp_local hands us the DHCPV6 header.
194 : */
195 9 : u0 = (void *) h0 - (sizeof (*u0));
196 9 : ip0 = (void *) u0 - (sizeof (*ip0));
197 9 : e_h0 = (void *) ip0 - ethernet_buffer_header_size (b0);
198 :
199 9 : clib_memcpy (client_src_mac, e_h0->src_address, 6);
200 :
201 9 : switch (h0->msg_type)
202 : {
203 9 : case DHCPV6_MSG_SOLICIT:
204 : case DHCPV6_MSG_REQUEST:
205 : case DHCPV6_MSG_CONFIRM:
206 : case DHCPV6_MSG_RENEW:
207 : case DHCPV6_MSG_REBIND:
208 : case DHCPV6_MSG_RELEASE:
209 : case DHCPV6_MSG_DECLINE:
210 : case DHCPV6_MSG_INFORMATION_REQUEST:
211 : case DHCPV6_MSG_RELAY_FORW:
212 : /* send to server */
213 9 : break;
214 0 : case DHCPV6_MSG_RELAY_REPL:
215 : /* send to client */
216 0 : next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_SEND_TO_CLIENT;
217 0 : error0 = 0;
218 0 : pkts_to_client++;
219 0 : goto do_enqueue;
220 0 : default:
221 : /* drop the packet */
222 0 : pkts_wrong_msg_type++;
223 0 : error0 = DHCPV6_PROXY_ERROR_WRONG_MESSAGE_TYPE;
224 0 : next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP;
225 0 : goto do_trace;
226 :
227 : }
228 :
229 : /* Send to DHCPV6 server via the configured FIB */
230 9 : rx_sw_if_index = sw_if_index =
231 9 : vnet_buffer (b0)->sw_if_index[VLIB_RX];
232 9 : rx_fib_idx = im->mfib_index_by_sw_if_index[rx_sw_if_index];
233 9 : proxy = dhcp_get_proxy (dpm, rx_fib_idx, FIB_PROTOCOL_IP6);
234 :
235 9 : if (PREDICT_FALSE (NULL == proxy))
236 : {
237 0 : error0 = DHCPV6_PROXY_ERROR_NO_SERVER;
238 0 : next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP;
239 0 : goto do_trace;
240 : }
241 :
242 9 : server = &proxy->dhcp_servers[0];
243 9 : server_fib_idx = server->server_fib_index;
244 9 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = server_fib_idx;
245 :
246 :
247 : /* relay-option header pointer */
248 9 : vlib_buffer_advance (b0, -(sizeof (*fwd_opt)));
249 9 : fwd_opt = vlib_buffer_get_current (b0);
250 : /* relay message header pointer */
251 9 : vlib_buffer_advance (b0, -(sizeof (*r1)));
252 9 : r1 = vlib_buffer_get_current (b0);
253 :
254 9 : vlib_buffer_advance (b0, -(sizeof (*u1)));
255 9 : u1 = vlib_buffer_get_current (b0);
256 :
257 9 : vlib_buffer_advance (b0, -(sizeof (*ip1)));
258 9 : ip1 = vlib_buffer_get_current (b0);
259 :
260 : /* fill in all that rubbish... */
261 9 : len = clib_net_to_host_u16 (u0->length) - sizeof (udp_header_t);
262 9 : copy_ip6_address (&r1->peer_addr, &ip0->src_address);
263 :
264 9 : r1->msg_type = DHCPV6_MSG_RELAY_FORW;
265 9 : fwd_opt->length = clib_host_to_net_u16 (len);
266 9 : fwd_opt->option = clib_host_to_net_u16 (DHCPV6_OPTION_RELAY_MSG);
267 :
268 9 : r1->hop_count++;
269 9 : r1->hop_count =
270 9 : (h0->msg_type != DHCPV6_MSG_RELAY_FORW) ? 0 : r1->hop_count;
271 :
272 9 : if (PREDICT_FALSE (r1->hop_count >= HOP_COUNT_LIMIT))
273 : {
274 0 : error0 = DHCPV6_RELAY_PKT_DROP_MAX_HOPS;
275 0 : next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP;
276 0 : goto do_trace;
277 : }
278 :
279 :
280 : /* If relay-fwd and src address is site or global unicast address */
281 9 : if (h0->msg_type == DHCPV6_MSG_RELAY_FORW &&
282 0 : ((ip0->src_address.as_u8[0] & 0xe0) == 0x20 ||
283 0 : (ip0->src_address.as_u8[0] & 0xfe) == 0xfc))
284 : {
285 : /* Set link address to zero */
286 0 : r1->link_addr.as_u64[0] = 0;
287 0 : r1->link_addr.as_u64[1] = 0;
288 0 : goto link_address_set;
289 : }
290 :
291 : /* if receiving interface is unnumbered, use receiving interface
292 : * IP address as link address, otherwise use the loopback interface
293 : * IP address as link address.
294 : */
295 :
296 9 : swif = vnet_get_sw_interface (vnm, rx_sw_if_index);
297 9 : if (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED)
298 0 : sw_if_index = swif->unnumbered_sw_if_index;
299 :
300 : ia0 =
301 9 : ip6_interface_first_global_or_site_address (&ip6_main,
302 : sw_if_index);
303 9 : if (ia0 == 0)
304 : {
305 0 : error0 = DHCPV6_PROXY_ERROR_NO_INTERFACE_ADDRESS;
306 0 : next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP;
307 0 : pkts_no_interface_address++;
308 0 : goto do_trace;
309 : }
310 :
311 9 : copy_ip6_address (&r1->link_addr, ia0);
312 :
313 9 : link_address_set:
314 :
315 18 : if ((b0->current_data + b0->current_length + sizeof (*id1) +
316 9 : sizeof (*vss1) + sizeof (*cmac)) >
317 9 : vlib_buffer_get_default_data_size (vm))
318 : {
319 0 : error0 = DHCPV6_PROXY_ERROR_PKT_TOO_BIG;
320 0 : next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP;
321 0 : pkts_too_big++;
322 0 : goto do_trace;
323 : }
324 :
325 9 : id1 = (dhcpv6_int_id_t *) (((uword) ip1) + b0->current_length);
326 9 : b0->current_length += (sizeof (*id1));
327 :
328 9 : id1->opt.option = clib_host_to_net_u16 (DHCPV6_OPTION_INTERFACE_ID);
329 9 : id1->opt.length = clib_host_to_net_u16 (sizeof (rx_sw_if_index));
330 9 : id1->int_idx = clib_host_to_net_u32 (rx_sw_if_index);
331 :
332 9 : u1->length = 0;
333 9 : if (h0->msg_type != DHCPV6_MSG_RELAY_FORW)
334 : {
335 9 : cmac =
336 9 : (dhcpv6_client_mac_t *) (((uword) ip1) + b0->current_length);
337 9 : b0->current_length += (sizeof (*cmac));
338 9 : cmac->opt.length = clib_host_to_net_u16 (sizeof (*cmac) -
339 : sizeof (cmac->opt));
340 9 : cmac->opt.option =
341 9 : clib_host_to_net_u16
342 : (DHCPV6_OPTION_CLIENT_LINK_LAYER_ADDRESS);
343 9 : cmac->link_type = clib_host_to_net_u16 (1); /* ethernet */
344 9 : clib_memcpy (cmac->data, client_src_mac, 6);
345 9 : u1->length += sizeof (*cmac);
346 : }
347 :
348 9 : vss = dhcp_get_vss_info (dpm, rx_fib_idx, FIB_PROTOCOL_IP6);
349 :
350 9 : if (vss)
351 : {
352 : u16 id_len; /* length of VPN ID */
353 2 : u16 type_len = sizeof (vss1->vss_type);
354 :
355 2 : vss1 = (dhcpv6_vss_t *) (((uword) ip1) + b0->current_length);
356 2 : vss1->vss_type = vss->vss_type;
357 2 : if (vss->vss_type == VSS_TYPE_VPN_ID)
358 : {
359 1 : id_len = sizeof (vss->vpn_id); /* vpn_id is 7 bytes */
360 1 : memcpy (vss1->data, vss->vpn_id, id_len);
361 : }
362 1 : else if (vss->vss_type == VSS_TYPE_ASCII)
363 : {
364 1 : id_len = vec_len (vss->vpn_ascii_id);
365 1 : memcpy (vss1->data, vss->vpn_ascii_id, id_len);
366 : }
367 : else /* must be VSS_TYPE_DEFAULT, no VPN ID */
368 0 : id_len = 0;
369 :
370 2 : vss1->opt.option = clib_host_to_net_u16 (DHCPV6_OPTION_VSS);
371 2 : vss1->opt.length = clib_host_to_net_u16 (type_len + id_len);
372 2 : u1->length += type_len + id_len + sizeof (vss1->opt);
373 2 : b0->current_length += type_len + id_len + sizeof (vss1->opt);
374 : }
375 :
376 9 : pkts_to_server++;
377 9 : u1->checksum = 0;
378 9 : u1->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dhcpv6_to_client);
379 9 : u1->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dhcpv6_to_server);
380 :
381 9 : u1->length =
382 9 : clib_host_to_net_u16 (clib_net_to_host_u16 (fwd_opt->length) +
383 : sizeof (*r1) + sizeof (*fwd_opt) +
384 9 : sizeof (*u1) + sizeof (*id1) + u1->length);
385 :
386 9 : clib_memset (ip1, 0, sizeof (*ip1));
387 9 : ip1->ip_version_traffic_class_and_flow_label = 0x60;
388 9 : ip1->payload_length = u1->length;
389 9 : ip1->protocol = PROTO_UDP;
390 9 : ip1->hop_limit = HOP_COUNT_LIMIT;
391 18 : src = ((server->dhcp_server.ip6.as_u64[0] ||
392 0 : server->dhcp_server.ip6.as_u64[1]) ?
393 9 : &server->dhcp_server.ip6 : &all_dhcpv6_server_address);
394 9 : copy_ip6_address (&ip1->dst_address, src);
395 :
396 :
397 9 : ia0 = ip6_interface_first_global_or_site_address
398 9 : (&ip6_main, vnet_buffer (b0)->sw_if_index[VLIB_RX]);
399 :
400 18 : src = (proxy->dhcp_src_address.ip6.as_u64[0] ||
401 0 : proxy->dhcp_src_address.ip6.as_u64[1]) ?
402 9 : &proxy->dhcp_src_address.ip6 : ia0;
403 9 : if (ia0 == 0)
404 : {
405 0 : error0 = DHCPV6_PROXY_ERROR_NO_SRC_ADDRESS;
406 0 : next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP;
407 0 : pkts_no_src_address++;
408 0 : goto do_trace;
409 : }
410 :
411 9 : copy_ip6_address (&ip1->src_address, src);
412 :
413 :
414 9 : u1->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b0, ip1,
415 : &bogus_length);
416 9 : ASSERT (bogus_length == 0);
417 :
418 9 : next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP;
419 :
420 9 : is_solicit = (DHCPV6_MSG_SOLICIT == h0->msg_type);
421 :
422 : /*
423 : * If we have multiple servers configured and this is the
424 : * client's discover message, then send copies to each of
425 : * those servers
426 : */
427 9 : if (is_solicit && vec_len (proxy->dhcp_servers) > 1)
428 : {
429 : u32 ii;
430 :
431 2 : for (ii = 1; ii < vec_len (proxy->dhcp_servers); ii++)
432 : {
433 : vlib_buffer_t *c0;
434 : u32 ci0;
435 :
436 1 : c0 = vlib_buffer_copy (vm, b0);
437 1 : if (c0 == NULL)
438 : {
439 0 : vlib_node_increment_counter
440 : (vm, dhcpv6_proxy_to_server_node.index,
441 : DHCPV6_PROXY_ERROR_ALLOC_FAIL, 1);
442 0 : continue;
443 : }
444 1 : ci0 = vlib_get_buffer_index (vm, c0);
445 1 : server = &proxy->dhcp_servers[ii];
446 :
447 1 : ip0 = vlib_buffer_get_current (c0);
448 :
449 2 : src = ((server->dhcp_server.ip6.as_u64[0] ||
450 0 : server->dhcp_server.ip6.as_u64[1]) ?
451 1 : &server->dhcp_server.ip6 :
452 : &all_dhcpv6_server_address);
453 1 : copy_ip6_address (&ip1->dst_address, src);
454 :
455 1 : to_next[0] = ci0;
456 1 : to_next += 1;
457 1 : n_left_to_next -= 1;
458 :
459 1 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
460 : to_next, n_left_to_next,
461 : ci0, next0);
462 :
463 1 : if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
464 : {
465 : dhcpv6_proxy_trace_t *tr;
466 :
467 1 : tr = vlib_add_trace (vm, node, c0, sizeof (*tr));
468 1 : tr->which = 0; /* to server */
469 1 : tr->error = error0;
470 1 : tr->original_sw_if_index = rx_sw_if_index;
471 1 : tr->sw_if_index = sw_if_index;
472 1 : if (next0 == DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP)
473 1 : copy_ip6_address ((ip6_address_t *) &
474 : tr->packet_data[0],
475 : &server->dhcp_server.ip6);
476 : }
477 :
478 1 : if (PREDICT_FALSE (0 == n_left_to_next))
479 : {
480 0 : vlib_put_next_frame (vm, node, next_index,
481 : n_left_to_next);
482 0 : vlib_get_next_frame (vm, node, next_index,
483 : to_next, n_left_to_next);
484 : }
485 : }
486 : }
487 :
488 9 : do_trace:
489 9 : if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
490 : {
491 9 : dhcpv6_proxy_trace_t *tr = vlib_add_trace (vm, node,
492 : b0, sizeof (*tr));
493 9 : tr->which = 0; /* to server */
494 9 : tr->error = error0;
495 9 : tr->original_sw_if_index = rx_sw_if_index;
496 9 : tr->sw_if_index = sw_if_index;
497 9 : if (DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP == next0)
498 9 : copy_ip6_address ((ip6_address_t *) & tr->packet_data[0],
499 : &server->dhcp_server.ip6);
500 : }
501 :
502 0 : do_enqueue:
503 9 : to_next[0] = bi0;
504 9 : to_next += 1;
505 9 : n_left_to_next -= 1;
506 :
507 9 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
508 : to_next, n_left_to_next,
509 : bi0, next0);
510 : }
511 :
512 9 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
513 : }
514 :
515 9 : vlib_node_increment_counter (vm, dhcpv6_proxy_to_server_node.index,
516 : DHCPV6_PROXY_ERROR_RELAY_TO_CLIENT,
517 : pkts_to_client);
518 9 : vlib_node_increment_counter (vm, dhcpv6_proxy_to_server_node.index,
519 : DHCPV6_PROXY_ERROR_RELAY_TO_SERVER,
520 : pkts_to_server);
521 9 : vlib_node_increment_counter (vm, dhcpv6_proxy_to_server_node.index,
522 : DHCPV6_PROXY_ERROR_NO_INTERFACE_ADDRESS,
523 : pkts_no_interface_address);
524 9 : vlib_node_increment_counter (vm, dhcpv6_proxy_to_server_node.index,
525 : DHCPV6_PROXY_ERROR_WRONG_MESSAGE_TYPE,
526 : pkts_wrong_msg_type);
527 9 : vlib_node_increment_counter (vm, dhcpv6_proxy_to_server_node.index,
528 : DHCPV6_PROXY_ERROR_NO_SRC_ADDRESS,
529 : pkts_no_src_address);
530 9 : vlib_node_increment_counter (vm, dhcpv6_proxy_to_server_node.index,
531 : DHCPV6_PROXY_ERROR_PKT_TOO_BIG, pkts_too_big);
532 9 : return from_frame->n_vectors;
533 : }
534 :
535 : /* *INDENT-OFF* */
536 153836 : VLIB_REGISTER_NODE (dhcpv6_proxy_to_server_node, static) = {
537 : .function = dhcpv6_proxy_to_server_input,
538 : .name = "dhcpv6-proxy-to-server",
539 : /* Takes a vector of packets. */
540 : .vector_size = sizeof (u32),
541 :
542 : .n_errors = DHCPV6_PROXY_N_ERROR,
543 : .error_strings = dhcpv6_proxy_error_strings,
544 :
545 : .n_next_nodes = DHCPV6_PROXY_TO_SERVER_INPUT_N_NEXT,
546 : .next_nodes = {
547 : #define _(s,n) [DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_##s] = n,
548 : foreach_dhcpv6_proxy_to_server_input_next
549 : #undef _
550 : },
551 :
552 : .format_buffer = format_dhcpv6_proxy_header_with_length,
553 : .format_trace = format_dhcpv6_proxy_trace,
554 : #if 0
555 : .unformat_buffer = unformat_dhcpv6_proxy_header,
556 : #endif
557 : };
558 : /* *INDENT-ON* */
559 :
560 : static uword
561 8 : dhcpv6_proxy_to_client_input (vlib_main_t * vm,
562 : vlib_node_runtime_t * node,
563 : vlib_frame_t * from_frame)
564 : {
565 :
566 : u32 n_left_from, *from;
567 8 : ethernet_main_t *em = vnet_get_ethernet_main ();
568 8 : dhcp_proxy_main_t *dm = &dhcp_proxy_main;
569 : dhcp_proxy_t *proxy;
570 : dhcp_server_t *server;
571 8 : vnet_main_t *vnm = vnet_get_main ();
572 : int bogus_length;
573 :
574 8 : from = vlib_frame_vector_args (from_frame);
575 8 : n_left_from = from_frame->n_vectors;
576 :
577 17 : while (n_left_from > 0)
578 : {
579 : u32 bi0;
580 : vlib_buffer_t *b0;
581 9 : udp_header_t *u0, *u1 = 0;
582 : dhcpv6_relay_hdr_t *h0;
583 9 : ip6_header_t *ip1 = 0, *ip0;
584 9 : ip6_address_t *ia0 = 0;
585 : ip6_address_t client_address;
586 : ethernet_interface_t *ei0;
587 : ethernet_header_t *mac0;
588 : vnet_hw_interface_t *hi0;
589 : vlib_frame_t *f0;
590 : u32 *to_next0;
591 9 : u32 sw_if_index = ~0;
592 9 : u32 original_sw_if_index = ~0;
593 : vnet_sw_interface_t *si0;
594 9 : u32 inner_vlan = (u32) ~ 0;
595 9 : u32 outer_vlan = (u32) ~ 0;
596 9 : u32 error0 = (u32) ~ 0;
597 : vnet_sw_interface_t *swif;
598 9 : dhcpv6_option_t *r0 = 0, *o;
599 9 : u16 len = 0;
600 9 : u8 interface_opt_flag = 0;
601 9 : u8 relay_msg_opt_flag = 0;
602 9 : ip6_main_t *im = &ip6_main;
603 : u32 server_fib_idx, client_fib_idx;
604 :
605 9 : bi0 = from[0];
606 9 : from += 1;
607 9 : n_left_from -= 1;
608 :
609 9 : b0 = vlib_get_buffer (vm, bi0);
610 9 : h0 = vlib_buffer_get_current (b0);
611 :
612 9 : if (DHCPV6_MSG_RELAY_REPL != h0->msg_type)
613 : {
614 1 : error0 = DHCPV6_PROXY_ERROR_WRONG_MESSAGE_TYPE;
615 :
616 4 : drop_packet:
617 4 : vlib_node_increment_counter (vm, dhcpv6_proxy_to_client_node.index,
618 : error0, 1);
619 :
620 4 : f0 = vlib_get_frame_to_node (vm, dm->error_drop_node_index);
621 4 : to_next0 = vlib_frame_vector_args (f0);
622 4 : to_next0[0] = bi0;
623 4 : f0->n_vectors = 1;
624 4 : vlib_put_frame_to_node (vm, dm->error_drop_node_index, f0);
625 4 : goto do_trace;
626 : }
627 : /* hop count seems not need to be checked */
628 8 : if (HOP_COUNT_LIMIT < h0->hop_count)
629 : {
630 0 : error0 = DHCPV6_RELAY_PKT_DROP_MAX_HOPS;
631 0 : goto drop_packet;
632 : }
633 8 : u0 = (void *) h0 - (sizeof (*u0));
634 8 : ip0 = (void *) u0 - (sizeof (*ip0));
635 :
636 8 : vlib_buffer_advance (b0, sizeof (*h0));
637 8 : o = vlib_buffer_get_current (b0);
638 :
639 : /* Parse through TLVs looking for option 18 (DHCPV6_OPTION_INTERFACE_ID)
640 : _and_ option 9 (DHCPV6_OPTION_RELAY_MSG) option which must be there.
641 : Currently assuming no other options need to be processed
642 : The interface-ID is the FIB number we need
643 : to track down the client-facing interface */
644 :
645 18 : while ((u8 *) o < (b0->data + b0->current_data + b0->current_length))
646 : {
647 16 : if (DHCPV6_OPTION_INTERFACE_ID == clib_net_to_host_u16 (o->option))
648 : {
649 6 : interface_opt_flag = 1;
650 6 : if (clib_net_to_host_u16 (o->length) == sizeof (sw_if_index))
651 : sw_if_index =
652 6 : clib_net_to_host_u32 (((dhcpv6_int_id_t *) o)->int_idx);
653 6 : if (sw_if_index >= vec_len (im->fib_index_by_sw_if_index))
654 : {
655 0 : error0 = DHCPV6_PROXY_ERROR_WRONG_INTERFACE_ID_OPTION;
656 0 : goto drop_packet;
657 : }
658 : }
659 16 : if (DHCPV6_OPTION_RELAY_MSG == clib_net_to_host_u16 (o->option))
660 : {
661 7 : relay_msg_opt_flag = 1;
662 7 : r0 = vlib_buffer_get_current (b0);
663 : }
664 16 : if ((relay_msg_opt_flag == 1) && (interface_opt_flag == 1))
665 6 : break;
666 10 : vlib_buffer_advance (b0,
667 10 : sizeof (*o) +
668 10 : clib_net_to_host_u16 (o->length));
669 10 : o =
670 10 : (dhcpv6_option_t *) (((uword) o) +
671 10 : clib_net_to_host_u16 (o->length) +
672 : sizeof (*o));
673 : }
674 :
675 8 : if ((relay_msg_opt_flag == 0) || (r0 == 0))
676 : {
677 1 : error0 = DHCPV6_PROXY_ERROR_NO_RELAY_MESSAGE_OPTION;
678 1 : goto drop_packet;
679 : }
680 :
681 7 : if ((u32) ~ 0 == sw_if_index)
682 : {
683 1 : error0 = DHCPV6_PROXY_ERROR_NO_CIRCUIT_ID_OPTION;
684 1 : goto drop_packet;
685 : }
686 :
687 : //Advance buffer to start of encapsulated DHCPv6 message
688 6 : vlib_buffer_advance (b0, sizeof (*r0));
689 :
690 6 : client_fib_idx = im->mfib_index_by_sw_if_index[sw_if_index];
691 6 : proxy = dhcp_get_proxy (dm, client_fib_idx, FIB_PROTOCOL_IP6);
692 :
693 6 : if (NULL == proxy)
694 : {
695 1 : error0 = DHCPV6_PROXY_ERROR_NO_SERVER;
696 1 : goto drop_packet;
697 : }
698 :
699 5 : server_fib_idx = im->fib_index_by_sw_if_index
700 5 : [vnet_buffer (b0)->sw_if_index[VLIB_RX]];
701 :
702 6 : vec_foreach (server, proxy->dhcp_servers)
703 : {
704 6 : if (server_fib_idx == server->server_fib_index &&
705 6 : ip0->src_address.as_u64[0] == server->dhcp_server.ip6.as_u64[0] &&
706 6 : ip0->src_address.as_u64[1] == server->dhcp_server.ip6.as_u64[1])
707 : {
708 5 : goto server_found;
709 : }
710 : }
711 :
712 : //drop packet if not from server with configured address or FIB
713 0 : error0 = DHCPV6_PROXY_ERROR_BAD_SVR_FIB_OR_ADDRESS;
714 0 : goto drop_packet;
715 :
716 5 : server_found:
717 5 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = original_sw_if_index
718 5 : = sw_if_index;
719 :
720 5 : swif = vnet_get_sw_interface (vnm, original_sw_if_index);
721 5 : if (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED)
722 0 : sw_if_index = swif->unnumbered_sw_if_index;
723 :
724 :
725 : /*
726 : * udp_local hands us the DHCPV6 header, need udp hdr,
727 : * ip hdr to relay to client
728 : */
729 5 : vlib_buffer_advance (b0, -(sizeof (*u1)));
730 5 : u1 = vlib_buffer_get_current (b0);
731 :
732 5 : vlib_buffer_advance (b0, -(sizeof (*ip1)));
733 5 : ip1 = vlib_buffer_get_current (b0);
734 :
735 5 : copy_ip6_address (&client_address, &h0->peer_addr);
736 :
737 5 : ia0 = ip6_interface_first_address (&ip6_main, sw_if_index);
738 5 : if (ia0 == 0)
739 : {
740 0 : error0 = DHCPV6_PROXY_ERROR_NO_INTERFACE_ADDRESS;
741 0 : goto drop_packet;
742 : }
743 :
744 5 : len = clib_net_to_host_u16 (r0->length);
745 5 : clib_memset (ip1, 0, sizeof (*ip1));
746 5 : copy_ip6_address (&ip1->dst_address, &client_address);
747 5 : u1->checksum = 0;
748 5 : u1->src_port = clib_net_to_host_u16 (UDP_DST_PORT_dhcpv6_to_server);
749 5 : u1->dst_port = clib_net_to_host_u16 (UDP_DST_PORT_dhcpv6_to_client);
750 5 : u1->length = clib_host_to_net_u16 (len + sizeof (udp_header_t));
751 :
752 5 : ip1->ip_version_traffic_class_and_flow_label =
753 5 : ip0->ip_version_traffic_class_and_flow_label & 0x00000fff;
754 5 : ip1->payload_length = u1->length;
755 5 : ip1->protocol = PROTO_UDP;
756 5 : ip1->hop_limit = HOP_COUNT_LIMIT;
757 5 : copy_ip6_address (&ip1->src_address, ia0);
758 :
759 5 : u1->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b0, ip1,
760 : &bogus_length);
761 5 : ASSERT (bogus_length == 0);
762 :
763 5 : vlib_buffer_advance (b0, -(sizeof (ethernet_header_t)));
764 5 : si0 = vnet_get_sw_interface (vnm, original_sw_if_index);
765 5 : if (si0->type == VNET_SW_INTERFACE_TYPE_SUB)
766 : {
767 0 : if (si0->sub.eth.flags.one_tag == 1)
768 : {
769 0 : vlib_buffer_advance (b0, -4 /* space for 1 VLAN tag */ );
770 0 : outer_vlan = (si0->sub.eth.outer_vlan_id << 16) | 0x86dd;
771 : }
772 0 : else if (si0->sub.eth.flags.two_tags == 1)
773 : {
774 0 : vlib_buffer_advance (b0, -8 /* space for 2 VLAN tag */ );
775 0 : outer_vlan = (si0->sub.eth.outer_vlan_id << 16) | 0x8100;
776 0 : inner_vlan = (si0->sub.eth.inner_vlan_id << 16) | 0x86dd;
777 : }
778 : }
779 :
780 5 : mac0 = vlib_buffer_get_current (b0);
781 :
782 5 : hi0 = vnet_get_sup_hw_interface (vnm, original_sw_if_index);
783 5 : ei0 = pool_elt_at_index (em->interfaces, hi0->hw_instance);
784 5 : clib_memcpy (mac0->src_address, &ei0->address,
785 : sizeof (mac0->src_address));
786 5 : clib_memset (&mac0->dst_address, 0xff, sizeof (mac0->dst_address));
787 :
788 5 : if (si0->type == VNET_SW_INTERFACE_TYPE_SUB && outer_vlan != (u32) ~ 0)
789 0 : {
790 0 : mac0->type = (si0->sub.eth.flags.dot1ad == 1) ?
791 0 : clib_net_to_host_u16 (0x88a8) : clib_net_to_host_u16 (0x8100);
792 0 : u32 *vlan_tag = (u32 *) (mac0 + 1);
793 0 : *vlan_tag = clib_host_to_net_u32 (outer_vlan);
794 0 : if (inner_vlan != (u32) ~ 0)
795 : {
796 0 : u32 *inner_vlan_tag = (u32 *) (vlan_tag + 1);
797 0 : *inner_vlan_tag = clib_host_to_net_u32 (inner_vlan);
798 : }
799 : }
800 : else
801 : {
802 5 : mac0->type = clib_net_to_host_u16 (0x86dd);
803 : }
804 :
805 : /* $$$ consider adding a dynamic next to the graph node, for performance */
806 5 : f0 = vlib_get_frame_to_node (vm, hi0->output_node_index);
807 5 : to_next0 = vlib_frame_vector_args (f0);
808 5 : to_next0[0] = bi0;
809 5 : f0->n_vectors = 1;
810 5 : vlib_put_frame_to_node (vm, hi0->output_node_index, f0);
811 :
812 9 : do_trace:
813 9 : if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
814 : {
815 9 : dhcpv6_proxy_trace_t *tr = vlib_add_trace (vm, node,
816 : b0, sizeof (*tr));
817 9 : tr->which = 1; /* to client */
818 9 : if (ia0)
819 5 : copy_ip6_address ((ip6_address_t *) tr->packet_data, ia0);
820 9 : tr->error = error0;
821 9 : tr->original_sw_if_index = original_sw_if_index;
822 9 : tr->sw_if_index = sw_if_index;
823 : }
824 : }
825 8 : return from_frame->n_vectors;
826 :
827 : }
828 :
829 : /* *INDENT-OFF* */
830 153836 : VLIB_REGISTER_NODE (dhcpv6_proxy_to_client_node, static) = {
831 : .function = dhcpv6_proxy_to_client_input,
832 : .name = "dhcpv6-proxy-to-client",
833 : /* Takes a vector of packets. */
834 : .vector_size = sizeof (u32),
835 :
836 : .n_errors = DHCPV6_PROXY_N_ERROR,
837 : .error_strings = dhcpv6_proxy_error_strings,
838 : .format_buffer = format_dhcpv6_proxy_header_with_length,
839 : .format_trace = format_dhcpv6_proxy_trace,
840 : #if 0
841 : .unformat_buffer = unformat_dhcpv6_proxy_header,
842 : #endif
843 : };
844 : /* *INDENT-ON* */
845 :
846 : static clib_error_t *
847 575 : dhcp6_proxy_init (vlib_main_t * vm)
848 : {
849 575 : dhcp_proxy_main_t *dm = &dhcp_proxy_main;
850 : vlib_node_t *error_drop_node;
851 :
852 575 : error_drop_node = vlib_get_node_by_name (vm, (u8 *) "error-drop");
853 575 : dm->error_drop_node_index = error_drop_node->index;
854 :
855 : /* RFC says this is the dhcpv6 server address */
856 575 : all_dhcpv6_server_address.as_u64[0] =
857 575 : clib_host_to_net_u64 (0xFF05000000000000);
858 575 : all_dhcpv6_server_address.as_u64[1] = clib_host_to_net_u64 (0x00010003);
859 :
860 : /* RFC says this is the server and agent address */
861 575 : all_dhcpv6_server_relay_agent_address.as_u64[0] =
862 575 : clib_host_to_net_u64 (0xFF02000000000000);
863 575 : all_dhcpv6_server_relay_agent_address.as_u64[1] =
864 575 : clib_host_to_net_u64 (0x00010002);
865 :
866 575 : return 0;
867 : }
868 :
869 5183 : VLIB_INIT_FUNCTION (dhcp6_proxy_init);
870 :
871 : int
872 8 : dhcp6_proxy_set_server (ip46_address_t * addr,
873 : ip46_address_t * src_addr,
874 : u32 rx_table_id, u32 server_table_id, int is_del)
875 : {
876 8 : vlib_main_t *vm = vlib_get_main ();
877 8 : u32 rx_fib_index = 0;
878 8 : int rc = 0;
879 :
880 8 : const mfib_prefix_t all_dhcp_servers = {
881 : .fp_len = 128,
882 : .fp_proto = FIB_PROTOCOL_IP6,
883 : .fp_grp_addr = {
884 : .ip6 = all_dhcpv6_server_relay_agent_address,
885 : }
886 : };
887 :
888 8 : if (ip46_address_is_zero (addr))
889 0 : return VNET_API_ERROR_INVALID_DST_ADDRESS;
890 :
891 8 : if (ip46_address_is_zero (src_addr))
892 0 : return VNET_API_ERROR_INVALID_SRC_ADDRESS;
893 :
894 8 : rx_fib_index = mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
895 : rx_table_id,
896 : MFIB_SOURCE_DHCP);
897 :
898 8 : if (is_del)
899 : {
900 4 : if (dhcp_proxy_server_del (FIB_PROTOCOL_IP6, rx_fib_index,
901 : addr, server_table_id))
902 : {
903 3 : mfib_table_entry_delete (rx_fib_index,
904 : &all_dhcp_servers, MFIB_SOURCE_DHCP);
905 3 : mfib_table_unlock (rx_fib_index, FIB_PROTOCOL_IP6,
906 : MFIB_SOURCE_DHCP);
907 :
908 3 : udp_unregister_dst_port (vm, UDP_DST_PORT_dhcpv6_to_client,
909 : 0 /* is_ip6 */ );
910 3 : udp_unregister_dst_port (vm, UDP_DST_PORT_dhcpv6_to_server,
911 : 0 /* is_ip6 */ );
912 : }
913 : }
914 : else
915 : {
916 4 : const fib_route_path_t path_for_us = {
917 : .frp_proto = DPO_PROTO_IP6,
918 : .frp_addr = zero_addr,
919 : .frp_sw_if_index = 0xffffffff,
920 : .frp_fib_index = ~0,
921 : .frp_weight = 1,
922 : .frp_flags = FIB_ROUTE_PATH_LOCAL,
923 : .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
924 : };
925 4 : if (dhcp_proxy_server_add (FIB_PROTOCOL_IP6, addr, src_addr,
926 : rx_fib_index, server_table_id))
927 : {
928 3 : mfib_table_entry_path_update (rx_fib_index, &all_dhcp_servers,
929 : MFIB_SOURCE_DHCP, MFIB_ENTRY_FLAG_NONE,
930 : &path_for_us);
931 : /*
932 : * Each interface that is enabled in this table, needs to be added
933 : * as an accepting interface, but this is not easily doable in VPP.
934 : * So we cheat. Add a flag to the entry that indicates accept form
935 : * any interface.
936 : * We will still only accept on v6 enabled interfaces, since the
937 : * input feature ensures this.
938 : */
939 3 : mfib_table_entry_update (rx_fib_index,
940 : &all_dhcp_servers,
941 : MFIB_SOURCE_DHCP,
942 : MFIB_RPF_ID_NONE,
943 : MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF);
944 3 : mfib_table_lock (rx_fib_index, FIB_PROTOCOL_IP6, MFIB_SOURCE_DHCP);
945 :
946 3 : udp_register_dst_port (vm, UDP_DST_PORT_dhcpv6_to_client,
947 : dhcpv6_proxy_to_client_node.index,
948 : 0 /* is_ip6 */ );
949 3 : udp_register_dst_port (vm, UDP_DST_PORT_dhcpv6_to_server,
950 : dhcpv6_proxy_to_server_node.index,
951 : 0 /* is_ip6 */ );
952 : }
953 : }
954 :
955 8 : mfib_table_unlock (rx_fib_index, FIB_PROTOCOL_IP6, MFIB_SOURCE_DHCP);
956 :
957 8 : return (rc);
958 : }
959 :
960 : static clib_error_t *
961 0 : dhcpv6_proxy_set_command_fn (vlib_main_t * vm,
962 : unformat_input_t * input,
963 : vlib_cli_command_t * cmd)
964 : {
965 : ip46_address_t addr, src_addr;
966 0 : int set_server = 0, set_src_address = 0;
967 0 : u32 rx_table_id = 0, server_table_id = 0;
968 0 : int is_del = 0;
969 :
970 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
971 : {
972 0 : if (unformat (input, "server %U", unformat_ip6_address, &addr.ip6))
973 0 : set_server = 1;
974 0 : else if (unformat (input, "src-address %U",
975 : unformat_ip6_address, &src_addr.ip6))
976 0 : set_src_address = 1;
977 0 : else if (unformat (input, "server-fib-id %d", &server_table_id))
978 : ;
979 0 : else if (unformat (input, "rx-fib-id %d", &rx_table_id))
980 : ;
981 0 : else if (unformat (input, "delete") || unformat (input, "del"))
982 0 : is_del = 1;
983 : else
984 : break;
985 : }
986 :
987 0 : if (is_del || (set_server && set_src_address))
988 : {
989 : int rv;
990 :
991 0 : rv = dhcp6_proxy_set_server (&addr, &src_addr, rx_table_id,
992 : server_table_id, is_del);
993 :
994 : //TODO: Complete the errors
995 0 : switch (rv)
996 : {
997 0 : case 0:
998 0 : return 0;
999 :
1000 0 : case VNET_API_ERROR_INVALID_DST_ADDRESS:
1001 0 : return clib_error_return (0, "Invalid server address");
1002 :
1003 0 : case VNET_API_ERROR_INVALID_SRC_ADDRESS:
1004 0 : return clib_error_return (0, "Invalid src address");
1005 :
1006 0 : case VNET_API_ERROR_NO_SUCH_ENTRY:
1007 0 : return clib_error_return
1008 : (0, "Fib id %d: no per-fib DHCP server configured", rx_table_id);
1009 :
1010 0 : default:
1011 0 : return clib_error_return (0, "BUG: rv %d", rv);
1012 : }
1013 : }
1014 : else
1015 0 : return clib_error_return (0, "parse error`%U'",
1016 : format_unformat_error, input);
1017 : }
1018 :
1019 : /* *INDENT-OFF* */
1020 235753 : VLIB_CLI_COMMAND (dhcpv6_proxy_set_command, static) = {
1021 : .path = "set dhcpv6 proxy",
1022 : .short_help = "set dhcpv6 proxy [del] server <ipv6-addr> src-address <ipv6-addr> "
1023 : "[server-fib-id <fib-id>] [rx-fib-id <fib-id>] ",
1024 : .function = dhcpv6_proxy_set_command_fn,
1025 : };
1026 : /* *INDENT-ON* */
1027 :
1028 : static u8 *
1029 0 : format_dhcp6_proxy_server (u8 * s, va_list * args)
1030 : {
1031 0 : dhcp_proxy_t *proxy = va_arg (*args, dhcp_proxy_t *);
1032 : fib_table_t *server_fib;
1033 : dhcp_server_t *server;
1034 : ip6_mfib_t *rx_fib;
1035 :
1036 0 : if (proxy == 0)
1037 : {
1038 0 : s = format (s, "%=14s%=16s%s", "RX FIB", "Src Address",
1039 : "Servers FIB,Address");
1040 0 : return s;
1041 : }
1042 :
1043 0 : rx_fib = ip6_mfib_get (proxy->rx_fib_index);
1044 :
1045 0 : s = format (s, "%=14u%=16U",
1046 : rx_fib->table_id,
1047 : format_ip46_address, &proxy->dhcp_src_address, IP46_TYPE_ANY);
1048 :
1049 0 : vec_foreach (server, proxy->dhcp_servers)
1050 : {
1051 0 : server_fib = fib_table_get (server->server_fib_index, FIB_PROTOCOL_IP6);
1052 0 : s = format (s, "%u,%U ",
1053 : server_fib->ft_table_id,
1054 : format_ip46_address, &server->dhcp_server, IP46_TYPE_ANY);
1055 : }
1056 :
1057 0 : return s;
1058 : }
1059 :
1060 : static int
1061 0 : dhcp6_proxy_show_walk (dhcp_proxy_t * proxy, void *ctx)
1062 : {
1063 0 : vlib_main_t *vm = ctx;
1064 :
1065 0 : vlib_cli_output (vm, "%U", format_dhcp6_proxy_server, proxy);
1066 :
1067 0 : return (1);
1068 : }
1069 :
1070 : static clib_error_t *
1071 0 : dhcpv6_proxy_show_command_fn (vlib_main_t * vm,
1072 : unformat_input_t * input,
1073 : vlib_cli_command_t * cmd)
1074 : {
1075 0 : vlib_cli_output (vm, "%U", format_dhcp6_proxy_server,
1076 : NULL /* header line */ );
1077 :
1078 0 : dhcp_proxy_walk (FIB_PROTOCOL_IP6, dhcp6_proxy_show_walk, vm);
1079 :
1080 0 : return (NULL);
1081 : }
1082 :
1083 : /* *INDENT-OFF* */
1084 235753 : VLIB_CLI_COMMAND (dhcpv6_proxy_show_command, static) = {
1085 : .path = "show dhcpv6 proxy",
1086 : .short_help = "Display dhcpv6 proxy info",
1087 : .function = dhcpv6_proxy_show_command_fn,
1088 : };
1089 : /* *INDENT-ON* */
1090 :
1091 : static clib_error_t *
1092 0 : dhcpv6_vss_command_fn (vlib_main_t * vm,
1093 : unformat_input_t * input, vlib_cli_command_t * cmd)
1094 : {
1095 0 : u8 is_del = 0, vss_type = VSS_TYPE_DEFAULT;
1096 0 : u8 *vpn_ascii_id = 0;
1097 0 : u32 oui = 0, fib_id = 0, tbl_id = ~0;
1098 :
1099 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1100 : {
1101 0 : if (unformat (input, "table %d", &tbl_id))
1102 : ;
1103 0 : else if (unformat (input, "oui %d", &oui))
1104 0 : vss_type = VSS_TYPE_VPN_ID;
1105 0 : else if (unformat (input, "vpn-id %d", &fib_id))
1106 0 : vss_type = VSS_TYPE_VPN_ID;
1107 0 : else if (unformat (input, "vpn-ascii-id %s", &vpn_ascii_id))
1108 0 : vss_type = VSS_TYPE_ASCII;
1109 0 : else if (unformat (input, "delete") || unformat (input, "del"))
1110 0 : is_del = 1;
1111 : else
1112 : break;
1113 : }
1114 :
1115 0 : if (tbl_id == ~0)
1116 0 : return clib_error_return (0, "no table ID specified.");
1117 :
1118 0 : int rv = dhcp_proxy_set_vss (FIB_PROTOCOL_IP6, tbl_id, vss_type,
1119 : vpn_ascii_id, oui, fib_id, is_del);
1120 0 : switch (rv)
1121 : {
1122 0 : case 0:
1123 0 : return 0;
1124 0 : case VNET_API_ERROR_NO_SUCH_ENTRY:
1125 0 : return clib_error_return (0, "vss for table %d not found in pool.",
1126 : tbl_id);
1127 0 : default:
1128 0 : return clib_error_return (0, "BUG: rv %d", rv);
1129 : }
1130 : }
1131 :
1132 : /* *INDENT-OFF* */
1133 235753 : VLIB_CLI_COMMAND (dhcpv6_proxy_vss_command, static) = {
1134 : .path = "set dhcpv6 vss",
1135 : .short_help = "set dhcpv6 vss table <table-id> [oui <n> vpn-id <n> | vpn-ascii-id <text>]",
1136 : .function = dhcpv6_vss_command_fn,
1137 : };
1138 : /* *INDENT-ON* */
1139 :
1140 : static clib_error_t *
1141 0 : dhcpv6_vss_show_command_fn (vlib_main_t * vm,
1142 : unformat_input_t * input,
1143 : vlib_cli_command_t * cmd)
1144 : {
1145 0 : dhcp_vss_walk (FIB_PROTOCOL_IP6, dhcp_vss_show_walk, vm);
1146 :
1147 0 : return (NULL);
1148 : }
1149 :
1150 : /* *INDENT-OFF* */
1151 235753 : VLIB_CLI_COMMAND (dhcpv6_proxy_vss_show_command, static) = {
1152 : .path = "show dhcpv6 vss",
1153 : .short_help = "show dhcpv6 VSS",
1154 : .function = dhcpv6_vss_show_command_fn,
1155 : };
1156 : /* *INDENT-ON* */
1157 :
1158 : static clib_error_t *
1159 0 : dhcpv6_link_address_show_command_fn (vlib_main_t * vm,
1160 : unformat_input_t * input,
1161 : vlib_cli_command_t * cmd)
1162 : {
1163 0 : vnet_main_t *vnm = vnet_get_main ();
1164 0 : u32 sw_if_index0 = 0, sw_if_index;
1165 : vnet_sw_interface_t *swif;
1166 : ip6_address_t *ia0;
1167 :
1168 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1169 : {
1170 :
1171 0 : if (unformat (input, "%U",
1172 : unformat_vnet_sw_interface, vnm, &sw_if_index0))
1173 : {
1174 0 : swif = vnet_get_sw_interface (vnm, sw_if_index0);
1175 0 : sw_if_index = (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED) ?
1176 0 : swif->unnumbered_sw_if_index : sw_if_index0;
1177 0 : ia0 = ip6_interface_first_address (&ip6_main, sw_if_index);
1178 0 : if (ia0)
1179 : {
1180 0 : vlib_cli_output (vm, "%=20s%=48s", "interface", "link-address");
1181 :
1182 0 : vlib_cli_output (vm, "%=20U%=48U",
1183 : format_vnet_sw_if_index_name, vnm,
1184 : sw_if_index0, format_ip6_address, ia0);
1185 : }
1186 : else
1187 0 : vlib_cli_output (vm, "%=34s%=20U",
1188 : "No IPv6 address configured on",
1189 : format_vnet_sw_if_index_name, vnm, sw_if_index);
1190 : }
1191 : else
1192 0 : break;
1193 : }
1194 :
1195 0 : return 0;
1196 : }
1197 :
1198 : /* *INDENT-OFF* */
1199 235753 : VLIB_CLI_COMMAND (dhcpv6_proxy_address_show_command, static) = {
1200 : .path = "show dhcpv6 link-address interface",
1201 : .short_help = "show dhcpv6 link-address interface <interface>",
1202 : .function = dhcpv6_link_address_show_command_fn,
1203 : };
1204 : /* *INDENT-ON* */
1205 :
1206 : /*
1207 : * fd.io coding-style-patch-verification: ON
1208 : *
1209 : * Local Variables:
1210 : * eval: (c-set-style "gnu")
1211 : * End:
1212 : */
|