|
diff --git a/src/plugins/dhcp/dhcp6_proxy_node.c b/src/plugins/dhcp/dhcp6_proxy_node.c |
|
index 55348ff86..56da84cf6 100644 |
|
--- a/src/plugins/dhcp/dhcp6_proxy_node.c |
|
+++ b/src/plugins/dhcp/dhcp6_proxy_node.c |
|
@@ -31,6 +31,18 @@ typedef enum |
|
DHCPV6_PROXY_TO_SERVER_INPUT_N_NEXT, |
|
} dhcpv6_proxy_to_server_input_next_t; |
|
|
|
+#define foreach_dhcpv6_proxy_to_client_input_next \ |
|
+ _ (DROP, "error-drop") \ |
|
+ _ (LOOKUP, "ip6-lookup") |
|
+ |
|
+typedef enum |
|
+{ |
|
+#define _(s, n) DHCPV6_PROXY_TO_CLIENT_INPUT_NEXT_##s, |
|
+ foreach_dhcpv6_proxy_to_client_input_next |
|
+#undef _ |
|
+ DHCPV6_PROXY_TO_CLIENT_INPUT_N_NEXT, |
|
+} dhcpv6_proxy_to_client_input_next_t; |
|
+ |
|
typedef struct |
|
{ |
|
/* 0 => to server, 1 => to client */ |
|
@@ -549,7 +561,7 @@ dhcpv6_proxy_to_client_input (vlib_main_t * vm, |
|
{ |
|
|
|
u32 n_left_from, *from; |
|
- ethernet_main_t *em = vnet_get_ethernet_main (); |
|
+ u32 next_index, *to_next; |
|
dhcp_proxy_main_t *dm = &dhcp_proxy_main; |
|
dhcp_proxy_t *proxy; |
|
dhcp_server_t *server; |
|
@@ -558,243 +570,190 @@ dhcpv6_proxy_to_client_input (vlib_main_t * vm, |
|
|
|
from = vlib_frame_vector_args (from_frame); |
|
n_left_from = from_frame->n_vectors; |
|
+ next_index = node->cached_next_index; |
|
|
|
while (n_left_from > 0) |
|
{ |
|
- u32 bi0; |
|
- vlib_buffer_t *b0; |
|
- udp_header_t *u0, *u1 = 0; |
|
- dhcpv6_relay_hdr_t *h0; |
|
- ip6_header_t *ip1 = 0, *ip0; |
|
- ip6_address_t *ia0 = 0; |
|
- ip6_address_t client_address; |
|
- ethernet_interface_t *ei0; |
|
- ethernet_header_t *mac0; |
|
- vnet_hw_interface_t *hi0; |
|
- vlib_frame_t *f0; |
|
- u32 *to_next0; |
|
- u32 sw_if_index = ~0; |
|
- u32 original_sw_if_index = ~0; |
|
- vnet_sw_interface_t *si0; |
|
- u32 inner_vlan = (u32) ~ 0; |
|
- u32 outer_vlan = (u32) ~ 0; |
|
- u32 error0 = (u32) ~ 0; |
|
- vnet_sw_interface_t *swif; |
|
- dhcpv6_option_t *r0 = 0, *o; |
|
- u16 len = 0; |
|
- u8 interface_opt_flag = 0; |
|
- u8 relay_msg_opt_flag = 0; |
|
- ip6_main_t *im = &ip6_main; |
|
- u32 server_fib_idx, client_fib_idx; |
|
- |
|
- bi0 = from[0]; |
|
- from += 1; |
|
- n_left_from -= 1; |
|
- |
|
- b0 = vlib_get_buffer (vm, bi0); |
|
- h0 = vlib_buffer_get_current (b0); |
|
- |
|
- if (DHCPV6_MSG_RELAY_REPL != h0->msg_type) |
|
+ u32 n_left_to_next; |
|
+ vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); |
|
+ |
|
+ while (n_left_from > 0 && n_left_to_next > 0) |
|
{ |
|
- error0 = DHCPV6_PROXY_ERROR_WRONG_MESSAGE_TYPE; |
|
+ u32 bi0; |
|
+ vlib_buffer_t *b0; |
|
+ udp_header_t *u0, *u1 = 0; |
|
+ dhcpv6_relay_hdr_t *h0; |
|
+ ip6_header_t *ip1 = 0, *ip0; |
|
+ ip6_address_t *ia0 = 0; |
|
+ ip6_address_t client_address; |
|
+ u32 sw_if_index = ~0; |
|
+ u32 original_sw_if_index = ~0; |
|
+ u32 error0 = (u32) ~0; |
|
+ u32 next0 = DHCPV6_PROXY_TO_CLIENT_INPUT_NEXT_LOOKUP; |
|
+ vnet_sw_interface_t *swif; |
|
+ dhcpv6_option_t *r0 = 0, *o; |
|
+ u16 len = 0; |
|
+ u8 interface_opt_flag = 0; |
|
+ u8 relay_msg_opt_flag = 0; |
|
+ ip6_main_t *im = &ip6_main; |
|
+ u32 server_fib_idx, client_fib_idx; |
|
|
|
- drop_packet: |
|
- vlib_node_increment_counter (vm, dhcpv6_proxy_to_client_node.index, |
|
- error0, 1); |
|
+ bi0 = from[0]; |
|
+ from += 1; |
|
+ n_left_from -= 1; |
|
|
|
- f0 = vlib_get_frame_to_node (vm, dm->error_drop_node_index); |
|
- to_next0 = vlib_frame_vector_args (f0); |
|
- to_next0[0] = bi0; |
|
- f0->n_vectors = 1; |
|
- vlib_put_frame_to_node (vm, dm->error_drop_node_index, f0); |
|
- goto do_trace; |
|
- } |
|
- /* hop count seems not need to be checked */ |
|
- if (HOP_COUNT_LIMIT < h0->hop_count) |
|
- { |
|
- error0 = DHCPV6_RELAY_PKT_DROP_MAX_HOPS; |
|
- goto drop_packet; |
|
- } |
|
- u0 = (void *) h0 - (sizeof (*u0)); |
|
- ip0 = (void *) u0 - (sizeof (*ip0)); |
|
+ b0 = vlib_get_buffer (vm, bi0); |
|
+ h0 = vlib_buffer_get_current (b0); |
|
+ |
|
+ if (DHCPV6_MSG_RELAY_REPL != h0->msg_type) |
|
+ { |
|
+ error0 = DHCPV6_PROXY_ERROR_WRONG_MESSAGE_TYPE; |
|
+ next0 = DHCPV6_PROXY_TO_CLIENT_INPUT_NEXT_DROP; |
|
+ goto do_trace; |
|
+ } |
|
+ /* hop count seems not need to be checked */ |
|
+ if (HOP_COUNT_LIMIT < h0->hop_count) |
|
+ { |
|
+ error0 = DHCPV6_RELAY_PKT_DROP_MAX_HOPS; |
|
+ next0 = DHCPV6_PROXY_TO_CLIENT_INPUT_NEXT_DROP; |
|
+ goto do_trace; |
|
+ } |
|
+ u0 = (void *) h0 - (sizeof (*u0)); |
|
+ ip0 = (void *) u0 - (sizeof (*ip0)); |
|
|
|
- vlib_buffer_advance (b0, sizeof (*h0)); |
|
- o = vlib_buffer_get_current (b0); |
|
+ vlib_buffer_advance (b0, sizeof (*h0)); |
|
+ o = vlib_buffer_get_current (b0); |
|
|
|
- /* Parse through TLVs looking for option 18 (DHCPV6_OPTION_INTERFACE_ID) |
|
- _and_ option 9 (DHCPV6_OPTION_RELAY_MSG) option which must be there. |
|
- Currently assuming no other options need to be processed |
|
- The interface-ID is the FIB number we need |
|
- to track down the client-facing interface */ |
|
+ /* Parse through TLVs looking for option 18 (DHCPV6_OPTION_INTERFACE_ID) |
|
+ _and_ option 9 (DHCPV6_OPTION_RELAY_MSG) option which must be there. |
|
+ Currently assuming no other options need to be processed |
|
+ The interface-ID is the FIB number we need |
|
+ to track down the client-facing interface */ |
|
|
|
- while ((u8 *) o < (b0->data + b0->current_data + b0->current_length)) |
|
- { |
|
- if (DHCPV6_OPTION_INTERFACE_ID == clib_net_to_host_u16 (o->option)) |
|
+ while ((u8 *) o < (b0->data + b0->current_data + b0->current_length)) |
|
{ |
|
- interface_opt_flag = 1; |
|
- if (clib_net_to_host_u16 (o->length) == sizeof (sw_if_index)) |
|
- sw_if_index = |
|
- clib_net_to_host_u32 (((dhcpv6_int_id_t *) o)->int_idx); |
|
- if (sw_if_index >= vec_len (im->fib_index_by_sw_if_index)) |
|
+ if (DHCPV6_OPTION_INTERFACE_ID == clib_net_to_host_u16 (o->option)) |
|
{ |
|
- error0 = DHCPV6_PROXY_ERROR_WRONG_INTERFACE_ID_OPTION; |
|
- goto drop_packet; |
|
+ interface_opt_flag = 1; |
|
+ if (clib_net_to_host_u16 (o->length) == sizeof (sw_if_index)) |
|
+ sw_if_index = clib_net_to_host_u32 (((dhcpv6_int_id_t *) o)->int_idx); |
|
+ if (sw_if_index >= vec_len (im->fib_index_by_sw_if_index)) |
|
+ { |
|
+ error0 = DHCPV6_PROXY_ERROR_WRONG_INTERFACE_ID_OPTION; |
|
+ next0 = DHCPV6_PROXY_TO_CLIENT_INPUT_NEXT_DROP; |
|
+ goto do_trace; |
|
+ } |
|
+ } |
|
+ if (DHCPV6_OPTION_RELAY_MSG == clib_net_to_host_u16 (o->option)) |
|
+ { |
|
+ relay_msg_opt_flag = 1; |
|
+ r0 = vlib_buffer_get_current (b0); |
|
} |
|
+ if ((relay_msg_opt_flag == 1) && (interface_opt_flag == 1)) |
|
+ break; |
|
+ vlib_buffer_advance (b0, sizeof (*o) + clib_net_to_host_u16 (o->length)); |
|
+ o = |
|
+ (dhcpv6_option_t *) (((uword) o) + clib_net_to_host_u16 (o->length) + sizeof (*o)); |
|
} |
|
- if (DHCPV6_OPTION_RELAY_MSG == clib_net_to_host_u16 (o->option)) |
|
+ |
|
+ if ((relay_msg_opt_flag == 0) || (r0 == 0)) |
|
{ |
|
- relay_msg_opt_flag = 1; |
|
- r0 = vlib_buffer_get_current (b0); |
|
+ error0 = DHCPV6_PROXY_ERROR_NO_RELAY_MESSAGE_OPTION; |
|
+ next0 = DHCPV6_PROXY_TO_CLIENT_INPUT_NEXT_DROP; |
|
+ goto do_trace; |
|
} |
|
- if ((relay_msg_opt_flag == 1) && (interface_opt_flag == 1)) |
|
- break; |
|
- vlib_buffer_advance (b0, |
|
- sizeof (*o) + |
|
- clib_net_to_host_u16 (o->length)); |
|
- o = |
|
- (dhcpv6_option_t *) (((uword) o) + |
|
- clib_net_to_host_u16 (o->length) + |
|
- sizeof (*o)); |
|
- } |
|
|
|
- if ((relay_msg_opt_flag == 0) || (r0 == 0)) |
|
- { |
|
- error0 = DHCPV6_PROXY_ERROR_NO_RELAY_MESSAGE_OPTION; |
|
- goto drop_packet; |
|
- } |
|
- |
|
- if ((u32) ~ 0 == sw_if_index) |
|
- { |
|
- error0 = DHCPV6_PROXY_ERROR_NO_CIRCUIT_ID_OPTION; |
|
- goto drop_packet; |
|
- } |
|
- |
|
- //Advance buffer to start of encapsulated DHCPv6 message |
|
- vlib_buffer_advance (b0, sizeof (*r0)); |
|
+ if ((u32) ~0 == sw_if_index) |
|
+ { |
|
+ error0 = DHCPV6_PROXY_ERROR_NO_CIRCUIT_ID_OPTION; |
|
+ next0 = DHCPV6_PROXY_TO_CLIENT_INPUT_NEXT_DROP; |
|
+ goto do_trace; |
|
+ } |
|
|
|
- client_fib_idx = im->mfib_index_by_sw_if_index[sw_if_index]; |
|
- proxy = dhcp_get_proxy (dm, client_fib_idx, FIB_PROTOCOL_IP6); |
|
+ // Advance buffer to start of encapsulated DHCPv6 message |
|
+ vlib_buffer_advance (b0, sizeof (*r0)); |
|
|
|
- if (NULL == proxy) |
|
- { |
|
- error0 = DHCPV6_PROXY_ERROR_NO_SERVER; |
|
- goto drop_packet; |
|
- } |
|
+ client_fib_idx = im->mfib_index_by_sw_if_index[sw_if_index]; |
|
+ proxy = dhcp_get_proxy (dm, client_fib_idx, FIB_PROTOCOL_IP6); |
|
|
|
- server_fib_idx = im->fib_index_by_sw_if_index |
|
- [vnet_buffer (b0)->sw_if_index[VLIB_RX]]; |
|
+ if (NULL == proxy) |
|
+ { |
|
+ error0 = DHCPV6_PROXY_ERROR_NO_SERVER; |
|
+ next0 = DHCPV6_PROXY_TO_CLIENT_INPUT_NEXT_DROP; |
|
+ goto do_trace; |
|
+ } |
|
|
|
- vec_foreach (server, proxy->dhcp_servers) |
|
- { |
|
- if (server_fib_idx == server->server_fib_index && |
|
- ip0->src_address.as_u64[0] == server->dhcp_server.ip6.as_u64[0] && |
|
- ip0->src_address.as_u64[1] == server->dhcp_server.ip6.as_u64[1]) |
|
- { |
|
- goto server_found; |
|
- } |
|
- } |
|
+ server_fib_idx = im->fib_index_by_sw_if_index[vnet_buffer (b0)->sw_if_index[VLIB_RX]]; |
|
|
|
- //drop packet if not from server with configured address or FIB |
|
- error0 = DHCPV6_PROXY_ERROR_BAD_SVR_FIB_OR_ADDRESS; |
|
- goto drop_packet; |
|
+ vec_foreach (server, proxy->dhcp_servers) |
|
+ { |
|
+ if (server_fib_idx == server->server_fib_index && |
|
+ ip0->src_address.as_u64[0] == server->dhcp_server.ip6.as_u64[0] && |
|
+ ip0->src_address.as_u64[1] == server->dhcp_server.ip6.as_u64[1]) |
|
+ { |
|
+ goto server_found; |
|
+ } |
|
+ } |
|
|
|
- server_found: |
|
- vnet_buffer (b0)->sw_if_index[VLIB_TX] = original_sw_if_index |
|
- = sw_if_index; |
|
+ // drop packet if not from server with configured address or FIB |
|
+ error0 = DHCPV6_PROXY_ERROR_BAD_SVR_FIB_OR_ADDRESS; |
|
+ next0 = DHCPV6_PROXY_TO_CLIENT_INPUT_NEXT_DROP; |
|
+ goto do_trace; |
|
|
|
- swif = vnet_get_sw_interface (vnm, original_sw_if_index); |
|
- if (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED) |
|
- sw_if_index = swif->unnumbered_sw_if_index; |
|
+ server_found: |
|
+ original_sw_if_index = sw_if_index; |
|
|
|
+ vnet_buffer (b0)->sw_if_index[VLIB_RX] = original_sw_if_index; |
|
+ vnet_buffer (b0)->sw_if_index[VLIB_TX] = ~0; |
|
|
|
- /* |
|
- * udp_local hands us the DHCPV6 header, need udp hdr, |
|
- * ip hdr to relay to client |
|
- */ |
|
- vlib_buffer_advance (b0, -(sizeof (*u1))); |
|
- u1 = vlib_buffer_get_current (b0); |
|
+ swif = vnet_get_sw_interface (vnm, original_sw_if_index); |
|
+ if (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED) |
|
+ sw_if_index = swif->unnumbered_sw_if_index; |
|
|
|
- vlib_buffer_advance (b0, -(sizeof (*ip1))); |
|
- ip1 = vlib_buffer_get_current (b0); |
|
+ /* |
|
+ * udp_local hands us the DHCPV6 header, need udp hdr, |
|
+ * ip hdr to relay to client |
|
+ */ |
|
+ vlib_buffer_advance (b0, -(sizeof (*u1))); |
|
+ u1 = vlib_buffer_get_current (b0); |
|
|
|
- copy_ip6_address (&client_address, &h0->peer_addr); |
|
+ vlib_buffer_advance (b0, -(sizeof (*ip1))); |
|
+ ip1 = vlib_buffer_get_current (b0); |
|
|
|
- ia0 = ip6_interface_first_address (&ip6_main, sw_if_index); |
|
- if (ia0 == 0) |
|
- { |
|
- error0 = DHCPV6_PROXY_ERROR_NO_INTERFACE_ADDRESS; |
|
- goto drop_packet; |
|
- } |
|
+ copy_ip6_address (&client_address, &h0->peer_addr); |
|
|
|
- len = clib_net_to_host_u16 (r0->length); |
|
- clib_memset (ip1, 0, sizeof (*ip1)); |
|
- copy_ip6_address (&ip1->dst_address, &client_address); |
|
- u1->checksum = 0; |
|
- u1->src_port = clib_net_to_host_u16 (UDP_DST_PORT_dhcpv6_to_server); |
|
- u1->dst_port = clib_net_to_host_u16 (UDP_DST_PORT_dhcpv6_to_client); |
|
- u1->length = clib_host_to_net_u16 (len + sizeof (udp_header_t)); |
|
- |
|
- ip1->ip_version_traffic_class_and_flow_label = |
|
- ip0->ip_version_traffic_class_and_flow_label & 0x00000fff; |
|
- ip1->payload_length = u1->length; |
|
- ip1->protocol = PROTO_UDP; |
|
- ip1->hop_limit = HOP_COUNT_LIMIT; |
|
- copy_ip6_address (&ip1->src_address, ia0); |
|
- |
|
- u1->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b0, ip1, |
|
- &bogus_length); |
|
- ASSERT (bogus_length == 0); |
|
- |
|
- vlib_buffer_advance (b0, -(sizeof (ethernet_header_t))); |
|
- si0 = vnet_get_sw_interface (vnm, original_sw_if_index); |
|
- if (si0->type == VNET_SW_INTERFACE_TYPE_SUB) |
|
- { |
|
- if (si0->sub.eth.flags.one_tag == 1) |
|
- { |
|
- vlib_buffer_advance (b0, -4 /* space for 1 VLAN tag */ ); |
|
- outer_vlan = (si0->sub.eth.outer_vlan_id << 16) | 0x86dd; |
|
- } |
|
- else if (si0->sub.eth.flags.two_tags == 1) |
|
+ ia0 = ip6_interface_first_address (&ip6_main, sw_if_index); |
|
+ if (ia0 == 0) |
|
{ |
|
- vlib_buffer_advance (b0, -8 /* space for 2 VLAN tag */ ); |
|
- outer_vlan = (si0->sub.eth.outer_vlan_id << 16) | 0x8100; |
|
- inner_vlan = (si0->sub.eth.inner_vlan_id << 16) | 0x86dd; |
|
+ error0 = DHCPV6_PROXY_ERROR_NO_INTERFACE_ADDRESS; |
|
+ next0 = DHCPV6_PROXY_TO_CLIENT_INPUT_NEXT_DROP; |
|
+ goto do_trace; |
|
} |
|
- } |
|
|
|
- mac0 = vlib_buffer_get_current (b0); |
|
+ len = clib_net_to_host_u16 (r0->length); |
|
+ clib_memset (ip1, 0, sizeof (*ip1)); |
|
+ copy_ip6_address (&ip1->dst_address, &client_address); |
|
+ u1->checksum = 0; |
|
+ u1->src_port = clib_net_to_host_u16 (UDP_DST_PORT_dhcpv6_to_server); |
|
+ u1->dst_port = clib_net_to_host_u16 (UDP_DST_PORT_dhcpv6_to_client); |
|
+ u1->length = clib_host_to_net_u16 (len + sizeof (udp_header_t)); |
|
|
|
- hi0 = vnet_get_sup_hw_interface (vnm, original_sw_if_index); |
|
- ei0 = pool_elt_at_index (em->interfaces, hi0->hw_instance); |
|
- clib_memcpy (mac0->src_address, &ei0->address, |
|
- sizeof (mac0->src_address)); |
|
- clib_memset (&mac0->dst_address, 0xff, sizeof (mac0->dst_address)); |
|
+ ip1->ip_version_traffic_class_and_flow_label = |
|
+ ip0->ip_version_traffic_class_and_flow_label & 0x00000fff; |
|
+ ip1->payload_length = u1->length; |
|
+ ip1->protocol = PROTO_UDP; |
|
+ ip1->hop_limit = HOP_COUNT_LIMIT; |
|
+ copy_ip6_address (&ip1->src_address, ia0); |
|
|
|
- if (si0->type == VNET_SW_INTERFACE_TYPE_SUB && outer_vlan != (u32) ~ 0) |
|
- { |
|
- mac0->type = (si0->sub.eth.flags.dot1ad == 1) ? |
|
- clib_net_to_host_u16 (0x88a8) : clib_net_to_host_u16 (0x8100); |
|
- u32 *vlan_tag = (u32 *) (mac0 + 1); |
|
- *vlan_tag = clib_host_to_net_u32 (outer_vlan); |
|
- if (inner_vlan != (u32) ~ 0) |
|
+ u1->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b0, ip1, &bogus_length); |
|
+ ASSERT (bogus_length == 0); |
|
+ |
|
+ do_trace: |
|
+ if (PREDICT_FALSE (error0 != (u32) ~0)) |
|
{ |
|
- u32 *inner_vlan_tag = (u32 *) (vlan_tag + 1); |
|
- *inner_vlan_tag = clib_host_to_net_u32 (inner_vlan); |
|
+ vlib_node_increment_counter (vm, dhcpv6_proxy_to_client_node.index, error0, 1); |
|
} |
|
- } |
|
- else |
|
- { |
|
- mac0->type = clib_net_to_host_u16 (0x86dd); |
|
- } |
|
- |
|
- /* $$$ consider adding a dynamic next to the graph node, for performance */ |
|
- f0 = vlib_get_frame_to_node (vm, hi0->output_node_index); |
|
- to_next0 = vlib_frame_vector_args (f0); |
|
- to_next0[0] = bi0; |
|
- f0->n_vectors = 1; |
|
- vlib_put_frame_to_node (vm, hi0->output_node_index, f0); |
|
|
|
- do_trace: |
|
if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) |
|
{ |
|
dhcpv6_proxy_trace_t *tr = vlib_add_trace (vm, node, |
|
@@ -806,21 +765,33 @@ dhcpv6_proxy_to_client_input (vlib_main_t * vm, |
|
tr->original_sw_if_index = original_sw_if_index; |
|
tr->sw_if_index = sw_if_index; |
|
} |
|
+ to_next[0] = bi0; |
|
+ to_next += 1; |
|
+ n_left_to_next -= 1; |
|
+ |
|
+ vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, n_left_to_next, bi0, next0); |
|
+ } |
|
+ vlib_put_next_frame (vm, node, next_index, n_left_to_next); |
|
} |
|
return from_frame->n_vectors; |
|
- |
|
} |
|
|
|
-VLIB_REGISTER_NODE (dhcpv6_proxy_to_client_node, static) = { |
|
- .function = dhcpv6_proxy_to_client_input, |
|
- .name = "dhcpv6-proxy-to-client", |
|
- /* Takes a vector of packets. */ |
|
- .vector_size = sizeof (u32), |
|
- |
|
- .n_errors = DHCPV6_PROXY_N_ERROR, |
|
- .error_strings = dhcpv6_proxy_error_strings, |
|
- .format_buffer = format_dhcpv6_proxy_header_with_length, |
|
- .format_trace = format_dhcpv6_proxy_trace, |
|
+VLIB_REGISTER_NODE (dhcpv6_proxy_to_client_node, |
|
+ static) = { .function = dhcpv6_proxy_to_client_input, |
|
+ .name = "dhcpv6-proxy-to-client", |
|
+ /* Takes a vector of packets. */ |
|
+ .vector_size = sizeof (u32), |
|
+ |
|
+ .n_errors = DHCPV6_PROXY_N_ERROR, |
|
+ .error_strings = dhcpv6_proxy_error_strings, |
|
+ .n_next_nodes = DHCPV6_PROXY_TO_CLIENT_INPUT_N_NEXT, |
|
+ .next_nodes = { |
|
+#define _(s, n) [DHCPV6_PROXY_TO_CLIENT_INPUT_NEXT_##s] = n, |
|
+ foreach_dhcpv6_proxy_to_client_input_next |
|
+#undef _ |
|
+ }, |
|
+ .format_buffer = format_dhcpv6_proxy_header_with_length, |
|
+ .format_trace = format_dhcpv6_proxy_trace, |
|
#if 0 |
|
.unformat_buffer = unformat_dhcpv6_proxy_header, |
|
#endif |
|
@@ -888,8 +859,6 @@ dhcp6_proxy_set_server (ip46_address_t * addr, |
|
mfib_table_unlock (rx_fib_index, FIB_PROTOCOL_IP6, |
|
MFIB_SOURCE_DHCP); |
|
|
|
- udp_unregister_dst_port (vm, UDP_DST_PORT_dhcpv6_to_client, |
|
- 0 /* is_ip6 */ ); |
|
udp_unregister_dst_port (vm, UDP_DST_PORT_dhcpv6_to_server, |
|
0 /* is_ip6 */ ); |
|
} |
|
@@ -926,9 +895,6 @@ dhcp6_proxy_set_server (ip46_address_t * addr, |
|
MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF); |
|
mfib_table_lock (rx_fib_index, FIB_PROTOCOL_IP6, MFIB_SOURCE_DHCP); |
|
|
|
- udp_register_dst_port (vm, UDP_DST_PORT_dhcpv6_to_client, |
|
- dhcpv6_proxy_to_client_node.index, |
|
- 0 /* is_ip6 */ ); |
|
udp_register_dst_port (vm, UDP_DST_PORT_dhcpv6_to_server, |
|
dhcpv6_proxy_to_server_node.index, |
|
0 /* is_ip6 */ ); |
|
diff --git a/src/vnet/ip/icmp46_packet.h b/src/vnet/ip/icmp46_packet.h |
|
index 9cca6d134..c5c0b2d8b 100644 |
|
--- a/src/vnet/ip/icmp46_packet.h |
|
+++ b/src/vnet/ip/icmp46_packet.h |
|
@@ -248,6 +248,13 @@ typedef CLIB_PACKED (struct |
|
u16 unused; u32 mtu; |
|
}) icmp6_neighbor_discovery_mtu_option_t; |
|
|
|
+typedef CLIB_PACKED (struct { |
|
+ icmp6_neighbor_discovery_option_header_t header; |
|
+ u16 reserved; |
|
+ u32 lifetime; |
|
+ ip6_address_t dns_servers[0]; |
|
+}) icmp6_neighbor_discovery_recursive_dns_server_option_t; |
|
+ |
|
typedef CLIB_PACKED (struct |
|
{ |
|
icmp6_neighbor_discovery_option_header_t header; |
|
diff --git a/src/vnet/ip6-nd/ip6_nd.api b/src/vnet/ip6-nd/ip6_nd.api |
|
index 3ddf25103..646c0d53a 100644 |
|
--- a/src/vnet/ip6-nd/ip6_nd.api |
|
+++ b/src/vnet/ip6-nd/ip6_nd.api |
|
@@ -41,6 +41,8 @@ import "vnet/interface_types.api"; |
|
@param lifetime - |
|
@param initial_count - |
|
@param initial_interval - |
|
+ @param reachable_time - |
|
+ @param retransmit_interval - |
|
*/ |
|
autoreply define sw_interface_ip6nd_ra_config |
|
{ |
|
@@ -60,6 +62,8 @@ autoreply define sw_interface_ip6nd_ra_config |
|
u32 lifetime; |
|
u32 initial_count; |
|
u32 initial_interval; |
|
+ u32 reachable_time; |
|
+ u32 retransmit_interval; |
|
}; |
|
|
|
/** \brief IPv6 router advertisement prefix config request |
|
@@ -140,6 +144,24 @@ typedef ip6nd_ra_prefix |
|
bool no_advertise; |
|
}; |
|
|
|
+/** \brief IPv6 router advertisement RDNSS (DNS server) config request |
|
+ @param client_index - opaque cookie to identify the sender |
|
+ @param context - sender context, to match reply w/ request |
|
+ @param sw_if_index - The interface the RA DNS server config applies to |
|
+ @param is_no - 0 for add, 1 for remove |
|
+ @param server - IPv6 address of the DNS server |
|
+ @param lifetime - DNS server lifetime in seconds |
|
+*/ |
|
+autoreply define sw_interface_ip6nd_ra_dns_server_config |
|
+{ |
|
+ u32 client_index; |
|
+ u32 context; |
|
+ vl_api_interface_index_t sw_if_index; |
|
+ bool is_no; |
|
+ vl_api_ip6_address_t server; |
|
+ u32 lifetime; |
|
+}; |
|
+ |
|
/** \brief Dump IPv6 Router Advertisements details on a per-interface basis |
|
@param client_index - opaque cookie to identify the sender |
|
@param context - sender context, to match reply w/ request |
|
diff --git a/src/vnet/ip6-nd/ip6_nd_api.c b/src/vnet/ip6-nd/ip6_nd_api.c |
|
index 218ea710e..7f6f7668e 100644 |
|
--- a/src/vnet/ip6-nd/ip6_nd_api.c |
|
+++ b/src/vnet/ip6-nd/ip6_nd_api.c |
|
@@ -163,14 +163,11 @@ static void |
|
|
|
VALIDATE_SW_IF_INDEX (mp); |
|
|
|
- rv = ip6_ra_config (vm, ntohl (mp->sw_if_index), |
|
- suppress, managed, other, |
|
- ll_option, send_unicast, cease, |
|
- default_router, ntohl (mp->lifetime), |
|
- ntohl (mp->initial_count), |
|
- ntohl (mp->initial_interval), |
|
- ntohl (mp->max_interval), |
|
- ntohl (mp->min_interval), is_no); |
|
+ rv = |
|
+ ip6_ra_config (vm, ntohl (mp->sw_if_index), suppress, managed, other, ll_option, send_unicast, |
|
+ cease, default_router, ntohl (mp->lifetime), ntohl (mp->initial_count), |
|
+ ntohl (mp->initial_interval), ntohl (mp->max_interval), ntohl (mp->min_interval), |
|
+ ntohl (mp->reachable_time), ntohl (mp->retransmit_interval), is_no); |
|
|
|
BAD_SW_IF_INDEX_LABEL; |
|
|
|
@@ -208,6 +205,26 @@ static void |
|
REPLY_MACRO (VL_API_SW_INTERFACE_IP6ND_RA_PREFIX_REPLY); |
|
} |
|
|
|
+static void |
|
+vl_api_sw_interface_ip6nd_ra_dns_server_config_t_handler ( |
|
+ vl_api_sw_interface_ip6nd_ra_dns_server_config_t *mp) |
|
+{ |
|
+ vlib_main_t *vm = vlib_get_main (); |
|
+ vl_api_sw_interface_ip6nd_ra_dns_server_config_reply_t *rmp; |
|
+ ip6_address_t server_addr; |
|
+ int rv = 0; |
|
+ |
|
+ VALIDATE_SW_IF_INDEX (mp); |
|
+ |
|
+ ip6_address_decode (mp->server, &server_addr); |
|
+ |
|
+ rv = |
|
+ ip6_ra_dns_server (vm, ntohl (mp->sw_if_index), &server_addr, ntohl (mp->lifetime), mp->is_no); |
|
+ |
|
+ BAD_SW_IF_INDEX_LABEL; |
|
+ REPLY_MACRO (VL_API_SW_INTERFACE_IP6ND_RA_DNS_SERVER_CONFIG_REPLY); |
|
+} |
|
+ |
|
static void |
|
ip6_radv_prefix_encode (f64 now, const ip6_radv_prefix_t *in, |
|
vl_api_ip6nd_ra_prefix_t *out) |
|
diff --git a/src/vnet/ip6-nd/ip6_nd_test.c b/src/vnet/ip6-nd/ip6_nd_test.c |
|
index cf5c0a145..8b9074af6 100644 |
|
--- a/src/vnet/ip6-nd/ip6_nd_test.c |
|
+++ b/src/vnet/ip6-nd/ip6_nd_test.c |
|
@@ -234,6 +234,8 @@ api_sw_interface_ip6nd_ra_config (vat_main_t * vam) |
|
u32 lifetime = 0; |
|
u32 initial_count = 0; |
|
u32 initial_interval = 0; |
|
+ u32 reachable_time = 0; |
|
+ u32 retransmit_interval = 0; |
|
int ret; |
|
|
|
|
|
@@ -254,6 +256,10 @@ api_sw_interface_ip6nd_ra_config (vat_main_t * vam) |
|
; |
|
else if (unformat (i, "interval %d", &initial_interval)) |
|
; |
|
+ else if (unformat (i, "reachable %d", &reachable_time)) |
|
+ ; |
|
+ else if (unformat (i, "retrans %d", &retransmit_interval)) |
|
+ ; |
|
else if (unformat (i, "suppress") || unformat (i, "surpress")) |
|
suppress = 1; |
|
else if (unformat (i, "managed")) |
|
@@ -300,6 +306,8 @@ api_sw_interface_ip6nd_ra_config (vat_main_t * vam) |
|
mp->cease = cease; |
|
mp->is_no = is_no; |
|
mp->default_router = default_router; |
|
+ mp->reachable_time = reachable_time; |
|
+ mp->retransmit_interval = retransmit_interval; |
|
|
|
/* send it... */ |
|
S (mp); |
|
@@ -308,6 +316,65 @@ api_sw_interface_ip6nd_ra_config (vat_main_t * vam) |
|
W (ret); |
|
return ret; |
|
} |
|
+ |
|
+static int |
|
+api_sw_interface_ip6nd_ra_dns_server_config (vat_main_t *vam) |
|
+{ |
|
+ unformat_input_t *i = vam->input; |
|
+ vl_api_sw_interface_ip6nd_ra_dns_server_config_t *mp; |
|
+ u32 sw_if_index = ~0; |
|
+ u8 sw_if_index_set = 0; |
|
+ u8 is_no = 0; |
|
+ vl_api_ip6_address_t server_addr; |
|
+ u32 lifetime = ~0; |
|
+ u8 server_addr_set = 0; |
|
+ int ret; |
|
+ |
|
+ /* Parse args required to build the message */ |
|
+ while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) |
|
+ { |
|
+ if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index)) |
|
+ sw_if_index_set = 1; |
|
+ else if (unformat (i, "sw_if_index %d", &sw_if_index)) |
|
+ sw_if_index_set = 1; |
|
+ else if (unformat (i, "del") || unformat (i, "no")) |
|
+ is_no = 1; |
|
+ else if (unformat (i, "server %U", unformat_ip6_address, &server_addr)) |
|
+ server_addr_set = 1; |
|
+ else if (unformat (i, "lifetime %d", &lifetime)) |
|
+ ; |
|
+ else |
|
+ break; |
|
+ } |
|
+ |
|
+ if (sw_if_index_set == 0) |
|
+ { |
|
+ errmsg ("missing interface name or sw_if_index"); |
|
+ return -99; |
|
+ } |
|
+ if (server_addr_set == 0) |
|
+ { |
|
+ errmsg ("missing DNS server address"); |
|
+ return -99; |
|
+ } |
|
+ |
|
+ /* Construct the API message */ |
|
+ M (SW_INTERFACE_IP6ND_RA_DNS_SERVER_CONFIG, mp); |
|
+ |
|
+ mp->sw_if_index = ntohl (sw_if_index); |
|
+ mp->is_no = is_no; |
|
+ mp->lifetime = ntohl (lifetime); |
|
+ |
|
+ clib_memcpy (mp->server, server_addr, sizeof (server_addr)); |
|
+ |
|
+ /* send it... */ |
|
+ S (mp); |
|
+ |
|
+ /* Wait for a reply... */ |
|
+ W (ret); |
|
+ return ret; |
|
+} |
|
+ |
|
static int |
|
api_ip6nd_proxy_enable_disable (vat_main_t *vam) |
|
{ |
|
diff --git a/src/vnet/ip6-nd/ip6_ra.c b/src/vnet/ip6-nd/ip6_ra.c |
|
index 7c2a3d342..433027231 100644 |
|
--- a/src/vnet/ip6-nd/ip6_ra.c |
|
+++ b/src/vnet/ip6-nd/ip6_ra.c |
|
@@ -511,6 +511,42 @@ icmp6_router_solicitation (vlib_main_t * vm, |
|
} |
|
} |
|
|
|
+ /* add RDNSS option */ |
|
+ if (vec_len (radv_info->adv_dns_servers) > 0) |
|
+ { |
|
+ icmp6_neighbor_discovery_recursive_dns_server_option_t h; |
|
+ |
|
+ u32 n_servers = vec_len (radv_info->adv_dns_servers); |
|
+ |
|
+ h.header.type = ICMP6_NEIGHBOR_DISCOVERY_OPTION_recursive_dns_server; |
|
+ h.header.n_data_u64s = 1 + 2 * n_servers; |
|
+ h.reserved = 0; |
|
+ h.lifetime = clib_host_to_net_u32 (radv_info->adv_dns_server_lifetime); |
|
+ |
|
+ /* fixed length */ |
|
+ if (vlib_buffer_add_data (vm, &bi0, (void *) &h, sizeof (h))) |
|
+ { |
|
+ error0 = ICMP6_ERROR_ALLOC_FAILURE; |
|
+ goto drop0; |
|
+ } |
|
+ |
|
+ payload_length += sizeof (h); |
|
+ |
|
+ /* dynamic length */ |
|
+ int i; |
|
+ for (i = 0; i < n_servers; i++) |
|
+ { |
|
+ if (vlib_buffer_add_data (vm, &bi0, |
|
+ (void *) &radv_info->adv_dns_servers[i], |
|
+ sizeof (ip6_address_t))) |
|
+ { |
|
+ error0 = ICMP6_ERROR_ALLOC_FAILURE; |
|
+ goto drop0; |
|
+ } |
|
+ payload_length += sizeof (ip6_address_t); |
|
+ } |
|
+ } |
|
+ |
|
/* add additional options before here */ |
|
|
|
/* finish building the router advertisement... */ |
|
@@ -1299,6 +1335,8 @@ ip6_ra_link_enable (u32 sw_if_index) |
|
radv_info->initial_adverts_sent = radv_info->initial_adverts_count - 1; |
|
radv_info->initial_adverts_interval = MAX_INITIAL_RTR_ADVERT_INTERVAL; |
|
|
|
+ radv_info->adv_dns_server_lifetime = DEF_DEF_RTR_LIFETIME; |
|
+ |
|
/* fill in delegate for this interface that will be needed later */ |
|
radv_info->adv_link_mtu = |
|
vnet_sw_interface_get_mtu (vnet_get_main (), sw_if_index, VNET_MTU_IP6); |
|
@@ -1326,6 +1364,8 @@ ip6_ra_delegate_disable (index_t rai) |
|
|
|
pool_free (radv_info->adv_prefixes_pool); |
|
|
|
+ vec_free (radv_info->adv_dns_servers); |
|
+ |
|
mhash_free (&radv_info->address_to_prefix_index); |
|
|
|
pool_put (ip6_ra_pool, radv_info); |
|
@@ -1364,14 +1404,15 @@ ip6_ra_update_secondary_radv_info (ip6_address_t * address, u8 prefix_len, |
|
|
|
pool_foreach (this_prefix, radv_info->adv_prefixes_pool) |
|
{ |
|
- if (this_prefix->prefix_len == prefix_len |
|
+ /* clang-format off */ |
|
+ if (this_prefix->prefix_len >= prefix_len |
|
&& ip6_address_is_equal_masked (&this_prefix->prefix, address, |
|
&mask)) |
|
{ |
|
int rv = ip6_ra_prefix (vm, |
|
radv_info->sw_if_index, |
|
- address, |
|
- prefix_len, |
|
+ &this_prefix->prefix, |
|
+ this_prefix->prefix_len, |
|
0 /* use_default */, |
|
valid_time, |
|
preferred_time, |
|
@@ -1383,6 +1424,7 @@ ip6_ra_update_secondary_radv_info (ip6_address_t * address, u8 prefix_len, |
|
if (rv != 0) |
|
clib_warning ("ip6_neighbor_ra_prefix returned %d", rv); |
|
} |
|
+ /* clang-format on */ |
|
} |
|
} |
|
} |
|
@@ -1581,12 +1623,10 @@ ip6_ra_publish (ip6_ra_report_t * r) |
|
|
|
/* API support functions */ |
|
int |
|
-ip6_ra_config (vlib_main_t * vm, u32 sw_if_index, |
|
- u8 suppress, u8 managed, u8 other, |
|
- u8 ll_option, u8 send_unicast, u8 cease, |
|
- u8 use_lifetime, u32 lifetime, |
|
- u32 initial_count, u32 initial_interval, |
|
- u32 max_interval, u32 min_interval, u8 is_no) |
|
+ip6_ra_config (vlib_main_t *vm, u32 sw_if_index, u8 suppress, u8 managed, u8 other, u8 ll_option, |
|
+ u8 send_unicast, u8 cease, u8 use_lifetime, u32 lifetime, u32 initial_count, |
|
+ u32 initial_interval, u32 max_interval, u32 min_interval, u32 reachable_time, |
|
+ u32 retransmit_interval, u8 is_no) |
|
{ |
|
ip6_ra_t *radv_info; |
|
|
|
@@ -1664,6 +1704,17 @@ ip6_ra_config (vlib_main_t * vm, u32 sw_if_index, |
|
0) ? ((is_no) ? MAX_INITIAL_RTR_ADVERT_INTERVAL : initial_interval) : |
|
radv_info->initial_adverts_interval; |
|
|
|
+ if (reachable_time != ~0) |
|
+ { |
|
+ radv_info->adv_neighbor_reachable_time_in_msec = (is_no) ? 0 : reachable_time; |
|
+ } |
|
+ |
|
+ if (retransmit_interval != ~0) |
|
+ { |
|
+ radv_info->adv_time_in_msec_between_retransmitted_neighbor_solicitations = |
|
+ (is_no) ? 0 : retransmit_interval; |
|
+ } |
|
+ |
|
/* restart */ |
|
if ((cease != 0) && (is_no)) |
|
radv_info->send_radv = 1; |
|
@@ -1803,6 +1854,60 @@ restart: |
|
return (0); |
|
} |
|
|
|
+int |
|
+ip6_ra_dns_server (vlib_main_t *vm, u32 sw_if_index, ip6_address_t *dns_server_addr, u32 lifetime, |
|
+ u8 is_no) |
|
+{ |
|
+ ip6_ra_t *radv_info; |
|
+ |
|
+ radv_info = ip6_ra_get_itf (sw_if_index); |
|
+ |
|
+ if (!radv_info) |
|
+ return (VNET_API_ERROR_IP6_NOT_ENABLED); |
|
+ |
|
+ if (is_no) |
|
+ { |
|
+ /* delete */ |
|
+ int i; |
|
+ vec_foreach_index (i, radv_info->adv_dns_servers) |
|
+ { |
|
+ if (ip6_address_is_equal (&radv_info->adv_dns_servers[i], dns_server_addr)) |
|
+ { |
|
+ vec_del1 (radv_info->adv_dns_servers, i); |
|
+ break; |
|
+ } |
|
+ } |
|
+ } |
|
+ else |
|
+ { |
|
+ /* add (check duplication) */ |
|
+ int i, found = 0; |
|
+ vec_foreach_index (i, radv_info->adv_dns_servers) |
|
+ { |
|
+ if (ip6_address_is_equal (&radv_info->adv_dns_servers[i], dns_server_addr)) |
|
+ { |
|
+ found = 1; |
|
+ break; |
|
+ } |
|
+ } |
|
+ |
|
+ if (!found) |
|
+ vec_add1 (radv_info->adv_dns_servers, *dns_server_addr); |
|
+ |
|
+ /* set lifetime (if specified) */ |
|
+ if (lifetime != ~0) |
|
+ radv_info->adv_dns_server_lifetime = lifetime; |
|
+ } |
|
+ |
|
+ /* restart */ |
|
+ radv_info->initial_adverts_sent = radv_info->initial_adverts_count - 1; |
|
+ radv_info->next_multicast_time = vlib_time_now (vm); |
|
+ radv_info->last_multicast_time = vlib_time_now (vm); |
|
+ radv_info->last_radv_time = 0; |
|
+ |
|
+ return (0); |
|
+} |
|
+ |
|
clib_error_t * |
|
ip6_ra_cmd (vlib_main_t * vm, |
|
unformat_input_t * main_input, vlib_cli_command_t * cmd) |
|
@@ -1816,10 +1921,14 @@ ip6_ra_cmd (vlib_main_t * vm, |
|
u32 sw_if_index, ra_lifetime = 0, ra_initial_count = |
|
0, ra_initial_interval = 0; |
|
u32 ra_max_interval = 0, ra_min_interval = 0; |
|
+ u32 ra_reachable_time = ~0; |
|
+ u32 ra_retransmit_interval = ~0; |
|
|
|
unformat_input_t _line_input, *line_input = &_line_input; |
|
|
|
int add_radv_info = 1; |
|
+ int add_dns_server = 0; |
|
+ u32 dns_server_lifetime = ~0; |
|
ip6_address_t ip6_addr; |
|
u32 addr_len; |
|
|
|
@@ -1867,6 +1976,11 @@ ip6_ra_cmd (vlib_main_t * vm, |
|
{ |
|
add_radv_info = 0; |
|
} |
|
+ else if (unformat (line_input, "dns server %U", unformat_ip6_address, &ip6_addr)) |
|
+ { |
|
+ add_radv_info = 0; |
|
+ add_dns_server = 1; |
|
+ } |
|
else if (unformat (line_input, "ra-managed-config-flag")) |
|
{ |
|
managed = 1; |
|
@@ -1918,6 +2032,22 @@ ip6_ra_cmd (vlib_main_t * vm, |
|
if (!unformat (line_input, "%d", &ra_min_interval)) |
|
ra_min_interval = 0; |
|
} |
|
+ else if (unformat (line_input, "ra-reachable-time")) |
|
+ { |
|
+ if (!unformat (line_input, "%d", &ra_reachable_time)) |
|
+ { |
|
+ error = unformat_parse_error (line_input); |
|
+ goto done; |
|
+ } |
|
+ } |
|
+ else if (unformat (line_input, "ra-retransmit-interval")) |
|
+ { |
|
+ if (!unformat (line_input, "%d", &ra_retransmit_interval)) |
|
+ { |
|
+ error = unformat_parse_error (line_input); |
|
+ goto done; |
|
+ } |
|
+ } |
|
else if (unformat (line_input, "ra-cease")) |
|
{ |
|
cease = 1; |
|
@@ -1930,12 +2060,25 @@ ip6_ra_cmd (vlib_main_t * vm, |
|
|
|
if (add_radv_info) |
|
{ |
|
- ip6_ra_config (vm, sw_if_index, |
|
- suppress, managed, other, |
|
- suppress_ll_option, send_unicast, cease, |
|
- use_lifetime, ra_lifetime, |
|
- ra_initial_count, ra_initial_interval, |
|
- ra_max_interval, ra_min_interval, is_no); |
|
+ ip6_ra_config (vm, sw_if_index, suppress, managed, other, suppress_ll_option, send_unicast, |
|
+ cease, use_lifetime, ra_lifetime, ra_initial_count, ra_initial_interval, |
|
+ ra_max_interval, ra_min_interval, ra_reachable_time, ra_retransmit_interval, |
|
+ is_no); |
|
+ } |
|
+ else if (add_dns_server) |
|
+ { |
|
+ /* get the rest of the command */ |
|
+ while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) |
|
+ { |
|
+ if (unformat (line_input, "lifetime %d", &dns_server_lifetime)) |
|
+ ; |
|
+ else |
|
+ { |
|
+ error = unformat_parse_error (line_input); |
|
+ goto done; |
|
+ } |
|
+ } |
|
+ ip6_ra_dns_server (vm, sw_if_index, &ip6_addr, dns_server_lifetime, is_no); |
|
} |
|
else |
|
{ |
|
@@ -2023,6 +2166,19 @@ format_ip6_ra (u8 * s, va_list * args) |
|
format_ip6_address, &p->prefix, p->prefix_len); |
|
} |
|
|
|
+ if (vec_len (radv_info->adv_dns_servers) > 0) |
|
+ { |
|
+ s = format (s, "%UAdvertised DNS Servers:\n", format_white_space, indent); |
|
+ int i; |
|
+ vec_foreach_index (i, radv_info->adv_dns_servers) |
|
+ { |
|
+ s = format (s, "%U%U\n", format_white_space, indent + 2, format_ip6_address, |
|
+ &radv_info->adv_dns_servers[i]); |
|
+ } |
|
+ s = format (s, "%UDNS Server Lifetime is %d\n", format_white_space, indent + 2, |
|
+ radv_info->adv_dns_server_lifetime); |
|
+ } |
|
+ |
|
s = format (s, "%UMTU is %d\n", |
|
format_white_space, indent, radv_info->adv_link_mtu); |
|
s = format (s, "%UICMP error messages are unlimited\n", |
|
@@ -2082,7 +2238,9 @@ format_ip6_ra (u8 * s, va_list * args) |
|
* [ra-other-config-flag] | [ra-suppress] | [ra-suppress-link-layer] | |
|
* [ra-send-unicast] | [ra-lifetime <lifetime>] | |
|
* [ra-initial <cnt> <interval>] | |
|
- * [ra-interval <max-interval> [<min-interval>]] | [ra-cease] |
|
+ * [ra-interval <max-interval> [<min-interval>]] | |
|
+ * [ra-reachable-time <reachable-time>] | |
|
+ * [ra-retransmit-interval <interval>] | [ra-cease] |
|
* @cliend |
|
* |
|
* Where: |
|
@@ -2133,6 +2291,10 @@ format_ip6_ra (u8 * s, va_list * args) |
|
* 150 seconds. The '<em>no</em>' option returns both to their default |
|
* value. |
|
* |
|
+ * <em>[no] ra-reachable-time <reachable-time></em> - Configures AdvReachableTime |
|
+ * |
|
+ * <em>[no] ra-retransmit-interval <interval></em> - Configures AdvRetransTimer |
|
+ * |
|
* <em>[no] ra-cease</em> - Cease sending ICMPv6 router-advertisement messages. |
|
* The '<em>no</em>' options implies to start (or restart) sending |
|
* ICMPv6 router-advertisement messages. |
|
@@ -2196,6 +2358,20 @@ format_ip6_ra (u8 * s, va_list * args) |
|
* infinite no-advertise} |
|
* Example of how to delete a prefix: |
|
* @cliexcmd{ip6 nd GigabitEthernet2/0/0 no prefix fe80::fe:28ff:fe9c:75b3/64} |
|
+ * |
|
+ * |
|
+ * <b>Format 4 - DNS Option:</b> |
|
+ * |
|
+ * @clistart |
|
+ * ip6 nd <interface> [no] dns [server <ip6-address> [lifetime <seconds>]] |
|
+ * [search <domain>] |
|
+ * @cliend |
|
+ * |
|
+ * Where: |
|
+ * |
|
+ * <em>no</em> - Removes the specified DNS server address from the advertisement. |
|
+ * |
|
+ * <em>lifetime</em> - The maximum time in seconds that the DNS server address may be used. |
|
?*/ |
|
VLIB_CLI_COMMAND (ip6_nd_command, static) = |
|
{ |
|
diff --git a/src/vnet/ip6-nd/ip6_ra.h b/src/vnet/ip6-nd/ip6_ra.h |
|
index 61247bde4..8d188c85b 100644 |
|
--- a/src/vnet/ip6-nd/ip6_ra.h |
|
+++ b/src/vnet/ip6-nd/ip6_ra.h |
|
@@ -57,6 +57,10 @@ typedef struct ip6_ra_t_ |
|
/* mtu option */ |
|
u32 adv_link_mtu; |
|
|
|
+ /* rdnss option */ |
|
+ ip6_address_t *adv_dns_servers; |
|
+ u32 adv_dns_server_lifetime; |
|
+ |
|
/* local information */ |
|
u32 sw_if_index; |
|
int send_radv; /* radv on/off on this interface - set by config */ |
|
@@ -108,12 +112,10 @@ typedef struct ip6_ra_t_ |
|
|
|
extern ip6_ra_t *ip6_ra_get_itf (u32 sw_if_index); |
|
|
|
-extern int ip6_ra_config (vlib_main_t * vm, u32 sw_if_index, |
|
- u8 suppress, u8 managed, u8 other, |
|
- u8 ll_option, u8 send_unicast, u8 cease, |
|
- u8 use_lifetime, u32 lifetime, |
|
- u32 initial_count, u32 initial_interval, |
|
- u32 max_interval, u32 min_interval, u8 is_no); |
|
+extern int ip6_ra_config (vlib_main_t *vm, u32 sw_if_index, u8 suppress, u8 managed, u8 other, |
|
+ u8 ll_option, u8 send_unicast, u8 cease, u8 use_lifetime, u32 lifetime, |
|
+ u32 initial_count, u32 initial_interval, u32 max_interval, |
|
+ u32 min_interval, u32 reachable_time, u32 retransmit_interval, u8 is_no); |
|
|
|
extern int ip6_ra_prefix (vlib_main_t * vm, u32 sw_if_index, |
|
ip6_address_t * prefix_addr, u8 prefix_len, |
|
@@ -122,6 +124,9 @@ extern int ip6_ra_prefix (vlib_main_t * vm, u32 sw_if_index, |
|
u8 off_link, u8 no_autoconfig, |
|
u8 no_onlink, u8 is_no); |
|
|
|
+extern int ip6_ra_dns_server (vlib_main_t *vm, u32 sw_if_index, ip6_address_t *dns_server_addr, |
|
+ u32 lifetime, u8 is_no); |
|
+ |
|
typedef walk_rc_t (*ip6_ra_itf_walk_fn_t) (u32 sw_if_index, void *ctx); |
|
|
|
extern void ip6_ra_itf_walk (ip6_ra_itf_walk_fn_t fn, void *ctx); |