From 7cd468a3d7dee7d6c92f69a0bb7061ae208ec727 Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Mon, 19 Dec 2016 23:05:39 +0100 Subject: Reorganize source tree to use single autotools instance Change-Id: I7b51f88292e057c6443b12224486f2d0c9f8ae23 Signed-off-by: Damjan Marion --- src/vnet/dhcp/client.c | 1031 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1031 insertions(+) create mode 100644 src/vnet/dhcp/client.c (limited to 'src/vnet/dhcp/client.c') diff --git a/src/vnet/dhcp/client.c b/src/vnet/dhcp/client.c new file mode 100644 index 00000000..c352e310 --- /dev/null +++ b/src/vnet/dhcp/client.c @@ -0,0 +1,1031 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include + +dhcp_client_main_t dhcp_client_main; +static u8 * format_dhcp_client_state (u8 * s, va_list * va); +static vlib_node_registration_t dhcp_client_process_node; + +static void +dhcp_client_acquire_address (dhcp_client_main_t * dcm, dhcp_client_t * c) +{ + /* + * Install any/all info gleaned from dhcp, right here + */ + ip4_add_del_interface_address (dcm->vlib_main, c->sw_if_index, + (void *) &c->leased_address, + c->subnet_mask_width, 0 /*is_del*/); +} + +static void +dhcp_client_release_address (dhcp_client_main_t * dcm, dhcp_client_t * c) +{ + /* + * Remove any/all info gleaned from dhcp, right here. Caller(s) + * have not wiped out the info yet. + */ + + ip4_add_del_interface_address (dcm->vlib_main, c->sw_if_index, + (void *) &c->leased_address, + c->subnet_mask_width, 1 /*is_del*/); +} + +static void +set_l2_rewrite (dhcp_client_main_t * dcm, dhcp_client_t * c) +{ + /* Acquire the L2 rewrite string for the indicated sw_if_index */ + c->l2_rewrite = vnet_build_rewrite_for_sw_interface( + dcm->vnet_main, + c->sw_if_index, + VNET_LINK_IP4, + 0 /* broadcast */); +} + +/* + * dhcp_client_for_us - server-to-client callback. + * Called from proxy_node.c:dhcp_proxy_to_client_input(). + * This function first decides that the packet in question is + * actually for the dhcp client code in case we're also acting as + * a dhcp proxy. Ay caramba, what a folly! + */ +int dhcp_client_for_us (u32 bi, vlib_buffer_t * b, + ip4_header_t * ip, + udp_header_t * udp, + dhcp_header_t * dhcp) +{ + dhcp_client_main_t * dcm = &dhcp_client_main; + vlib_main_t * vm = dcm->vlib_main; + dhcp_client_t * c; + uword * p; + f64 now = vlib_time_now (dcm->vlib_main); + u8 dhcp_message_type = 0; + dhcp_option_t * o; + + /* + * Doing dhcp client on this interface? + * Presumably we will always receive dhcp clnt for-us pkts on + * the interface that's asking for an address. + */ + p = hash_get (dcm->client_by_sw_if_index, + vnet_buffer(b)->sw_if_index [VLIB_RX]); + if (p == 0) + return 0; /* no */ + + c = pool_elt_at_index (dcm->clients, p[0]); + + /* Mixing dhcp relay and dhcp proxy? DGMS... */ + if (c->state == DHCP_BOUND && c->retry_count == 0) + return 0; + + /* parse through the packet, learn what we can */ + if (dhcp->your_ip_address.as_u32) + c->leased_address.as_u32 = dhcp->your_ip_address.as_u32; + + o = (dhcp_option_t *) dhcp->options; + + while (o->option != 0xFF /* end of options */ && + (u8 *) o < (b->data + b->current_data + b->current_length)) + { + switch (o->option) + { + case 53: /* dhcp message type */ + dhcp_message_type = o->data[0]; + break; + + case 51: /* lease time */ + { + u32 lease_time_in_seconds = + clib_host_to_net_u32 (o->data_as_u32[0]); + c->lease_expires = now + (f64) lease_time_in_seconds; + c->lease_lifetime = lease_time_in_seconds; + /* Set a sensible default, in case we don't get opt 58 */ + c->lease_renewal_interval = lease_time_in_seconds / 2; + } + break; + + case 58: /* lease renew time in seconds */ + { + u32 lease_renew_time_in_seconds = + clib_host_to_net_u32 (o->data_as_u32[0]); + c->lease_renewal_interval = lease_renew_time_in_seconds; + } + break; + + case 54: /* dhcp server address */ + c->dhcp_server.as_u32 = o->data_as_u32[0]; + break; + + case 1: /* subnet mask */ + { + u32 subnet_mask = + clib_host_to_net_u32 (o->data_as_u32[0]); + c->subnet_mask_width = count_set_bits (subnet_mask); + } + break; + case 3: /* router address */ + { + u32 router_address = o->data_as_u32[0]; + c->router_address.as_u32 = router_address; + } + break; + + case 12: /* hostname */ + { + /* Replace the existing hostname if necessary */ + vec_free (c->hostname); + vec_validate (c->hostname, o->length - 1); + clib_memcpy (c->hostname, o->data, o->length); + } + break; + + /* $$$$ Your message in this space, parse more options */ + default: + break; + } + + o = (dhcp_option_t *) (((uword) o) + (o->length + 2)); + } + + switch (c->state) + { + case DHCP_DISCOVER: + if (dhcp_message_type != DHCP_PACKET_OFFER) + { + clib_warning ("sw_if_index %d state %U message type %d", + c->sw_if_index, format_dhcp_client_state, + c->state, dhcp_message_type); + c->next_transmit = now + 5.0; + break; + } + /* Received an offer, go send a request */ + c->state = DHCP_REQUEST; + c->retry_count = 0; + c->next_transmit = 0; /* send right now... */ + /* Poke the client process, which will send the request */ + vlib_process_signal_event (vm, dhcp_client_process_node.index, + EVENT_DHCP_CLIENT_WAKEUP, c - dcm->clients); + break; + + case DHCP_BOUND: + case DHCP_REQUEST: + if (dhcp_message_type != DHCP_PACKET_ACK) + { + clib_warning ("sw_if_index %d state %U message type %d", + c->sw_if_index, format_dhcp_client_state, + c->state, dhcp_message_type); + c->next_transmit = now + 5.0; + break; + } + /* OK, we own the address (etc), add to the routing table(s) */ + if (c->state == DHCP_REQUEST) + { + void (*fp)(u32, u32, u8 *, u8, u8 *, u8 *, u8 *) = c->event_callback; + + dhcp_client_acquire_address (dcm, c); + + /* + * Configure default IP route: + */ + if (c->router_address.as_u32) + { + fib_prefix_t all_0s = + { + .fp_len = 0, + .fp_addr.ip4.as_u32 = 0x0, + .fp_proto = FIB_PROTOCOL_IP4, + }; + ip46_address_t nh = + { + .ip4 = c->router_address, + }; + + fib_table_entry_path_add (fib_table_get_index_for_sw_if_index( + FIB_PROTOCOL_IP4, + c->sw_if_index), + &all_0s, + FIB_SOURCE_DHCP, + FIB_ENTRY_FLAG_NONE, + FIB_PROTOCOL_IP4, + &nh, + c->sw_if_index, + ~0, + 1, + NULL, // no label stack + FIB_ROUTE_PATH_FLAG_NONE); + } + + /* + * Call the user's event callback to report DHCP information + */ + if (fp) + (*fp) (c->client_index, /* clinet index */ + c->pid, + c->hostname, + 0, /* is_ipv6 */ + (u8 *)&c->leased_address, /* host IP address */ + (u8 *)&c->router_address, /* router IP address */ + (u8 *)(c->l2_rewrite + 6));/* host MAC address */ + } + + c->state = DHCP_BOUND; + c->retry_count = 0; + c->next_transmit = now + (f64) c->lease_renewal_interval; + c->lease_expires = now + (f64) c->lease_lifetime; + break; + + default: + clib_warning ("client %d bogus state %d", + c - dcm->clients, c->state); + break; + } + + /* drop the pkt, return 1 */ + vlib_buffer_free (vm, &bi, 1); + return 1; +} + +static void +send_dhcp_pkt (dhcp_client_main_t * dcm, dhcp_client_t * c, + dhcp_packet_type_t type, int is_broadcast) +{ + vlib_main_t * vm = dcm->vlib_main; + vnet_main_t * vnm = dcm->vnet_main; + vnet_hw_interface_t * hw = vnet_get_sup_hw_interface (vnm, c->sw_if_index); + vnet_sw_interface_t * sup_sw + = vnet_get_sup_sw_interface (vnm, c->sw_if_index); + vnet_sw_interface_t * sw = vnet_get_sw_interface (vnm, c->sw_if_index); + vlib_buffer_t * b; + u32 bi; + ip4_header_t * ip; + udp_header_t * udp; + dhcp_header_t * dhcp; + u32 * to_next; + vlib_frame_t * f; + dhcp_option_t * o; + u16 udp_length, ip_length; + + /* Interface(s) down? */ + if ((hw->flags & VNET_HW_INTERFACE_FLAG_LINK_UP) == 0) + return; + if ((sup_sw->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) == 0) + return; + if ((sw->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) == 0) + return; + + if (vlib_buffer_alloc (vm, &bi, 1) != 1) { + clib_warning ("buffer allocation failure"); + c->next_transmit = 0; + return; + } + + /* Build a dhcpv4 pkt from whole cloth */ + b = vlib_get_buffer (vm, bi); + + ASSERT (b->current_data == 0); + + vnet_buffer(b)->sw_if_index[VLIB_RX] = c->sw_if_index; + if (is_broadcast) + { + f = vlib_get_frame_to_node (vm, hw->output_node_index); + vnet_buffer(b)->sw_if_index[VLIB_TX] = c->sw_if_index; + clib_memcpy (b->data, c->l2_rewrite, vec_len(c->l2_rewrite)); + ip = (void *) + (((u8 *)vlib_buffer_get_current (b)) + vec_len (c->l2_rewrite)); + } + else + { + f = vlib_get_frame_to_node (vm, ip4_lookup_node.index); + vnet_buffer(b)->sw_if_index[VLIB_TX] = ~0; /* use interface VRF */ + ip = vlib_buffer_get_current (b); + } + + /* Enqueue the packet right now */ + to_next = vlib_frame_vector_args (f); + to_next[0] = bi; + f->n_vectors = 1; + + if (is_broadcast) + vlib_put_frame_to_node (vm, hw->output_node_index, f); + else + vlib_put_frame_to_node (vm, ip4_lookup_node.index, f); + + udp = (udp_header_t *)(ip+1); + dhcp = (dhcp_header_t *)(udp+1); + + /* $$$ optimize, maybe */ + memset (ip, 0, sizeof (*ip) + sizeof (*udp) + sizeof (*dhcp)); + + ip->ip_version_and_header_length = 0x45; + ip->ttl = 128; + ip->protocol = IP_PROTOCOL_UDP; + + if (is_broadcast) + { + /* src = 0.0.0.0, dst = 255.255.255.255 */ + ip->dst_address.as_u32 = ~0; + } + else + { + /* Renewing an active lease, plain old ip4 src/dst */ + ip->src_address.as_u32 = c->leased_address.as_u32; + ip->dst_address.as_u32 = c->dhcp_server.as_u32; + } + + udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_client); + udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_server); + + /* Send the interface MAC address */ + clib_memcpy (dhcp->client_hardware_address, c->l2_rewrite + 6, 6); + + /* Lease renewal, set up client_ip_address */ + if (is_broadcast == 0) + dhcp->client_ip_address.as_u32 = c->leased_address.as_u32; + + dhcp->opcode = 1; /* request, all we send */ + dhcp->hardware_type = 1; /* ethernet */ + dhcp->hardware_address_length = 6; + dhcp->transaction_identifier = c->transaction_id; + dhcp->flags = clib_host_to_net_u16(is_broadcast ? DHCP_FLAG_BROADCAST : 0); + dhcp->magic_cookie.as_u32 = DHCP_MAGIC; + + o = (dhcp_option_t * )dhcp->options; + + /* Send option 53, the DHCP message type */ + o->option = 53; + o->length = 1; + o->data[0] = type; + o = (dhcp_option_t *) (((uword) o) + (o->length + 2)); + + /* Send option 57, max msg length */ + if (0 /* not needed, apparently */) + { + o->option = 57; + o->length = 2; + { + u16 *o2 = (u16 *) o->data; + *o2 = clib_host_to_net_u16 (1152); + o = (dhcp_option_t *) (((uword) o) + (o->length + 2)); + } + } + + /* + * If server ip address is available with non-zero value, + * option 54 (DHCP Server Identifier) is sent. + */ + if (c->dhcp_server.as_u32) + { + o->option = 54; + o->length = 4; + clib_memcpy (o->data, &c->dhcp_server.as_u32, 4); + o = (dhcp_option_t *) (((uword) o) + (o->length + 2)); + } + + /* send option 50, requested IP address */ + if (c->leased_address.as_u32) + { + o->option = 50; + o->length = 4; + clib_memcpy (o->data, &c->leased_address.as_u32, 4); + o = (dhcp_option_t *) (((uword) o) + (o->length + 2)); + } + + /* send option 12, host name */ + if (vec_len (c->hostname)) + { + o->option = 12; + o->length = vec_len (c->hostname); + clib_memcpy (o->data, c->hostname, vec_len (c->hostname)); + o = (dhcp_option_t *) (((uword) o) + (o->length + 2)); + } + + /* $$ maybe send the client s/w version if anyone cares */ + + /* + * send option 55, parameter request list + * The current list - see below, matches the Linux dhcp client's list + * Any specific dhcp server config and/or dhcp server may or may + * not yield specific options. + */ + o->option = 55; + o->length = vec_len (c->option_55_data); + clib_memcpy (o->data, c->option_55_data, vec_len(c->option_55_data)); + o = (dhcp_option_t *) (((uword) o) + (o->length + 2)); + + /* End of list */ + o->option = 0xff; + o->length = 0; + o++; + + b->current_length = ((u8 *)o) - b->data; + + /* fix ip length, checksum and udp length */ + ip_length = vlib_buffer_length_in_chain (vm, b); + if (is_broadcast) + ip_length -= vec_len (c->l2_rewrite); + + ip->length = clib_host_to_net_u16(ip_length); + ip->checksum = ip4_header_checksum(ip); + + udp_length = ip_length - (sizeof (*ip)); + udp->length = clib_host_to_net_u16 (udp_length); +} + +static int +dhcp_discover_state (dhcp_client_main_t * dcm, dhcp_client_t * c, f64 now) +{ + /* + * State machine "DISCOVER" state. Send a dhcp discover packet, + * eventually back off the retry rate. + */ + send_dhcp_pkt (dcm, c, DHCP_PACKET_DISCOVER, 1 /* is_broadcast */); + + c->retry_count++; + if (c->retry_count > 10) + c->next_transmit = now + 5.0; + else + c->next_transmit = now + 1.0; + return 0; +} + +static int +dhcp_request_state (dhcp_client_main_t * dcm, dhcp_client_t * c, f64 now) +{ + /* + * State machine "REQUEST" state. Send a dhcp request packet, + * eventually drop back to the discover state. + */ + send_dhcp_pkt (dcm, c, DHCP_PACKET_REQUEST, 1 /* is_broadcast */); + + c->retry_count++; + if (c->retry_count > 7 /* lucky you */) + { + c->state = DHCP_DISCOVER; + c->next_transmit = now; + c->retry_count = 0; + return 1; + } + c->next_transmit = now + 1.0; + return 0; +} + +static int +dhcp_bound_state (dhcp_client_main_t * dcm, dhcp_client_t * c, f64 now) +{ + /* + * State machine "BOUND" state. Send a dhcp request packet, + * eventually, when the lease expires, forget the dhcp data + * and go back to the stone age. + */ + send_dhcp_pkt (dcm, c, DHCP_PACKET_REQUEST, 0 /* is_broadcast */); + + c->retry_count++; + if (c->retry_count > 10) + c->next_transmit = now + 5.0; + else + c->next_transmit = now + 1.0; + + if (now > c->lease_expires) + { + if (c->router_address.as_u32) + { + fib_prefix_t all_0s = + { + .fp_len = 0, + .fp_addr.ip4.as_u32 = 0x0, + .fp_proto = FIB_PROTOCOL_IP4, + }; + ip46_address_t nh = { + .ip4 = c->router_address, + }; + + fib_table_entry_path_remove(fib_table_get_index_for_sw_if_index( + FIB_PROTOCOL_IP4, + c->sw_if_index), + &all_0s, + FIB_SOURCE_DHCP, + FIB_PROTOCOL_IP4, + &nh, + c->sw_if_index, + ~0, + 1, + FIB_ROUTE_PATH_FLAG_NONE); + } + + dhcp_client_release_address (dcm, c); + c->state = DHCP_DISCOVER; + c->next_transmit = now; + c->retry_count = 0; + /* Wipe out any memory of the address we had... */ + c->leased_address.as_u32 = 0; + c->subnet_mask_width = 0; + c->router_address.as_u32 = 0; + c->lease_renewal_interval = 0; + c->dhcp_server.as_u32 = 0; + return 1; + } + return 0; +} + +static f64 dhcp_client_sm (f64 now, f64 timeout, uword pool_index) +{ + dhcp_client_main_t * dcm = &dhcp_client_main; + dhcp_client_t * c; + + /* deleted, pooched, yadda yadda yadda */ + if (pool_is_free_index (dcm->clients, pool_index)) + return timeout; + + c = pool_elt_at_index (dcm->clients, pool_index); + + /* Time for us to do something with this client? */ + if (now < c->next_transmit) + return timeout; + + again: + switch (c->state) + { + case DHCP_DISCOVER: /* send a discover */ + if (dhcp_discover_state (dcm, c, now)) + goto again; + break; + + case DHCP_REQUEST: /* send a request */ + if (dhcp_request_state (dcm, c, now)) + goto again; + break; + + case DHCP_BOUND: /* bound, renew needed? */ + if (dhcp_bound_state (dcm, c, now)) + goto again; + break; + + default: + clib_warning ("dhcp client %d bogus state %d", + c - dcm->clients, c->state); + break; + } + + if (c->next_transmit < now + timeout) + return c->next_transmit - now; + + return timeout; +} + +static uword +dhcp_client_process (vlib_main_t * vm, + vlib_node_runtime_t * rt, + vlib_frame_t * f) +{ + f64 timeout = 100.0; + f64 now; + uword event_type; + uword * event_data = 0; + dhcp_client_main_t * dcm = &dhcp_client_main; + dhcp_client_t * c; + int i; + + while (1) + { + vlib_process_wait_for_event_or_clock (vm, timeout); + + event_type = vlib_process_get_events (vm, &event_data); + + now = vlib_time_now (vm); + + switch (event_type) + { + case EVENT_DHCP_CLIENT_WAKEUP: + for (i = 0; i < vec_len (event_data); i++) + timeout = dhcp_client_sm (now, timeout, event_data[i]); + break; + + case ~0: + pool_foreach (c, dcm->clients, + ({ + timeout = dhcp_client_sm (now, timeout, + (uword)(c - dcm->clients)); + })); + if (pool_elts (dcm->clients) == 0) + timeout = 100.0; + break; + } + + vec_reset_length (event_data); + } + + /* NOTREACHED */ + return 0; +} + +VLIB_REGISTER_NODE (dhcp_client_process_node,static) = { + .function = dhcp_client_process, + .type = VLIB_NODE_TYPE_PROCESS, + .name = "dhcp-client-process", + .process_log2_n_stack_bytes = 16, +}; + +static u8 * format_dhcp_client_state (u8 * s, va_list * va) +{ + dhcp_client_state_t state = va_arg (*va, dhcp_client_state_t); + char * str = "BOGUS!"; + + switch (state) + { +#define _(a) \ + case a: \ + str = #a; \ + break; + foreach_dhcp_client_state; +#undef _ + default: + break; + } + + s = format (s, "%s", str); + return s; +} + +static u8 * format_dhcp_client (u8 * s, va_list * va) +{ + dhcp_client_main_t * dcm = va_arg (*va, dhcp_client_main_t *); + dhcp_client_t * c = va_arg (*va, dhcp_client_t *); + int verbose = va_arg (*va, int); + + s = format (s, "[%d] %U state %U ", c - dcm->clients, + format_vnet_sw_if_index_name, dcm->vnet_main, c->sw_if_index, + format_dhcp_client_state, c->state); + + if (c->leased_address.as_u32) + s = format (s, "addr %U/%d gw %U\n", + format_ip4_address, &c->leased_address, + c->subnet_mask_width, format_ip4_address, &c->router_address); + else + s = format (s, "no address\n"); + + if (verbose) + { + s = format (s, "retry count %d, next xmt %.2f", + c->retry_count, c->next_transmit); + } + return s; +} + +static clib_error_t * +show_dhcp_client_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + dhcp_client_main_t * dcm = &dhcp_client_main; + dhcp_client_t * c; + int verbose = 0; + u32 sw_if_index = ~0; + uword * p; + + while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "intfc %U", + unformat_vnet_sw_interface, dcm->vnet_main, + &sw_if_index)) + ; + else if (unformat (input, "verbose")) + verbose = 1; + else + break; + } + + if (sw_if_index != ~0) + { + p = hash_get (dcm->client_by_sw_if_index, sw_if_index); + if (p == 0) + return clib_error_return (0, "dhcp client not configured"); + c = pool_elt_at_index (dcm->clients, p[0]); + vlib_cli_output (vm, "%U", format_dhcp_client, dcm, c, verbose); + return 0; + } + + pool_foreach (c, dcm->clients, + ({ + vlib_cli_output (vm, "%U", format_dhcp_client, dcm, c, verbose); + })); + + return 0; +} + +VLIB_CLI_COMMAND (show_dhcp_client_command, static) = { + .path = "show dhcp client", + .short_help = "show dhcp client [intfc ][verbose]", + .function = show_dhcp_client_command_fn, +}; + + +int dhcp_client_add_del (dhcp_client_add_del_args_t * a) +{ + dhcp_client_main_t * dcm = &dhcp_client_main; + vlib_main_t * vm = dcm->vlib_main; + dhcp_client_t * c; + uword * p; + fib_prefix_t all_1s = + { + .fp_len = 32, + .fp_addr.ip4.as_u32 = 0xffffffff, + .fp_proto = FIB_PROTOCOL_IP4, + }; + fib_prefix_t all_0s = + { + .fp_len = 0, + .fp_addr.ip4.as_u32 = 0x0, + .fp_proto = FIB_PROTOCOL_IP4, + }; + + p = hash_get (dcm->client_by_sw_if_index, a->sw_if_index); + + if ((p && a->is_add) || (!p && a->is_add == 0)) + return VNET_API_ERROR_INVALID_VALUE; + + if (a->is_add) + { + pool_get (dcm->clients, c); + memset (c, 0, sizeof (*c)); + c->state = DHCP_DISCOVER; + c->sw_if_index = a->sw_if_index; + c->client_index = a->client_index; + c->pid = a->pid; + c->event_callback = a->event_callback; + c->option_55_data = a->option_55_data; + c->hostname = a->hostname; + c->client_identifier = a->client_identifier; + do { + c->transaction_id = random_u32 (&dcm->seed); + } while (c->transaction_id == 0); + set_l2_rewrite (dcm, c); + hash_set (dcm->client_by_sw_if_index, a->sw_if_index, c - dcm->clients); + + /* this add is ref counted by FIB so we can add for each itf */ + fib_table_entry_special_add(fib_table_get_index_for_sw_if_index( + FIB_PROTOCOL_IP4, + c->sw_if_index), + &all_1s, + FIB_SOURCE_DHCP, + FIB_ENTRY_FLAG_LOCAL, + ADJ_INDEX_INVALID); + + /* + * enable the interface to RX IPv4 packets + * this is also ref counted + */ + ip4_sw_interface_enable_disable (c->sw_if_index, 1); + + vlib_process_signal_event (vm, dhcp_client_process_node.index, + EVENT_DHCP_CLIENT_WAKEUP, c - dcm->clients); + } + else + { + c = pool_elt_at_index (dcm->clients, p[0]); + + fib_table_entry_special_remove(fib_table_get_index_for_sw_if_index( + FIB_PROTOCOL_IP4, + c->sw_if_index), + &all_1s, + FIB_SOURCE_DHCP); + + if (c->router_address.as_u32) + { + ip46_address_t nh = { + .ip4 = c->router_address, + }; + + fib_table_entry_path_remove(fib_table_get_index_for_sw_if_index( + FIB_PROTOCOL_IP4, + c->sw_if_index), + &all_0s, + FIB_SOURCE_DHCP, + FIB_PROTOCOL_IP4, + &nh, + c->sw_if_index, + ~0, + 1, + FIB_ROUTE_PATH_FLAG_NONE); + } + ip4_sw_interface_enable_disable (c->sw_if_index, 0); + + vec_free (c->option_55_data); + vec_free (c->hostname); + vec_free (c->client_identifier); + vec_free (c->l2_rewrite); + hash_unset (dcm->client_by_sw_if_index, c->sw_if_index); + pool_put (dcm->clients, c); + } + return 0; +} + +int +dhcp_client_config (vlib_main_t * vm, + u32 sw_if_index, + u8 * hostname, + u32 is_add, + u32 client_index, + void * event_callback, + u32 pid) +{ + dhcp_client_add_del_args_t _a, *a = &_a; + int rv; + + memset (a, 0, sizeof (*a)); + a->is_add = is_add; + a->sw_if_index = sw_if_index; + a->client_index = client_index; + a->pid = pid; + a->event_callback = event_callback; + vec_validate(a->hostname, strlen((char *)hostname) - 1); + strncpy((char *)a->hostname, (char *)hostname, vec_len(a->hostname)); + a->client_identifier = format (0, "vpe 1.0%c", 0); + /* + * Option 55 request list. These data precisely match + * the Ubuntu dhcp client. YMMV. + */ + + /* Subnet Mask */ + vec_add1 (a->option_55_data, 1); + /* Broadcast address */ + vec_add1 (a->option_55_data, 28); + /* time offset */ + vec_add1 (a->option_55_data, 2); + /* Router */ + vec_add1 (a->option_55_data, 3); + /* Domain Name */ + vec_add1 (a->option_55_data, 15); + /* DNS */ + vec_add1 (a->option_55_data, 6); + /* Domain search */ + vec_add1 (a->option_55_data, 119); + /* Host name */ + vec_add1 (a->option_55_data, 12); + /* NetBIOS name server */ + vec_add1 (a->option_55_data, 44); + /* NetBIOS Scope */ + vec_add1 (a->option_55_data, 47); + /* MTU */ + vec_add1 (a->option_55_data, 26); + /* Classless static route */ + vec_add1 (a->option_55_data, 121); + /* NTP servers */ + vec_add1 (a->option_55_data, 42); + + rv = dhcp_client_add_del (a); + + switch (rv) + { + case 0: + break; + + case VNET_API_ERROR_INVALID_VALUE: + + vec_free (a->hostname); + vec_free (a->client_identifier); + vec_free (a->option_55_data); + + if (is_add) + clib_warning ("dhcp client already enabled on intf_idx %d", + sw_if_index); + else + clib_warning ("dhcp client not enabled on on intf_idx %d", + sw_if_index); + break; + + default: + clib_warning ("dhcp_client_add_del returned %d", rv); + } + + return rv; +} + +static clib_error_t * +dhcp_client_set_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + + dhcp_client_main_t * dcm = &dhcp_client_main; + u32 sw_if_index; + u8 * hostname = 0; + u8 sw_if_index_set = 0; + int is_add = 1; + dhcp_client_add_del_args_t _a, *a = &_a; + int rv; + + while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "intfc %U", + unformat_vnet_sw_interface, dcm->vnet_main, + &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (input, "hostname %v", &hostname)) + ; + else if (unformat (input, "del")) + is_add = 0; + else + break; + } + + if (sw_if_index_set == 0) + return clib_error_return (0, "interface not specified"); + + memset (a, 0, sizeof (*a)); + a->is_add = is_add; + a->sw_if_index = sw_if_index; + a->hostname = hostname; + a->client_identifier = format (0, "vpe 1.0%c", 0); + + /* + * Option 55 request list. These data precisely match + * the Ubuntu dhcp client. YMMV. + */ + + /* Subnet Mask */ + vec_add1 (a->option_55_data, 1); + /* Broadcast address */ + vec_add1 (a->option_55_data, 28); + /* time offset */ + vec_add1 (a->option_55_data, 2); + /* Router */ + vec_add1 (a->option_55_data, 3); + /* Domain Name */ + vec_add1 (a->option_55_data, 15); + /* DNS */ + vec_add1 (a->option_55_data, 6); + /* Domain search */ + vec_add1 (a->option_55_data, 119); + /* Host name */ + vec_add1 (a->option_55_data, 12); + /* NetBIOS name server */ + vec_add1 (a->option_55_data, 44); + /* NetBIOS Scope */ + vec_add1 (a->option_55_data, 47); + /* MTU */ + vec_add1 (a->option_55_data, 26); + /* Classless static route */ + vec_add1 (a->option_55_data, 121); + /* NTP servers */ + vec_add1 (a->option_55_data, 42); + + rv = dhcp_client_add_del (a); + + switch (rv) + { + case 0: + break; + + case VNET_API_ERROR_INVALID_VALUE: + + vec_free (a->hostname); + vec_free (a->client_identifier); + vec_free (a->option_55_data); + if (is_add) + return clib_error_return (0, "dhcp client already enabled on %U", + format_vnet_sw_if_index_name, + dcm->vnet_main, sw_if_index); + else + return clib_error_return (0, "dhcp client not enabled on %U", + format_vnet_sw_if_index_name, + dcm->vnet_main, sw_if_index); + break; + + default: + vlib_cli_output (vm, "dhcp_client_add_del returned %d", rv); + } + + return 0; +} + +VLIB_CLI_COMMAND (dhcp_client_set_command, static) = { + .path = "set dhcp client", + .short_help = "set dhcp client [del] intfc [hostname ]", + .function = dhcp_client_set_command_fn, +}; + +static clib_error_t * +dhcp_client_init (vlib_main_t * vm) +{ + dhcp_client_main_t * dcm = &dhcp_client_main; + + dcm->vlib_main = vm; + dcm->vnet_main = vnet_get_main(); + dcm->seed = 0xdeaddabe; + return 0; +} + +VLIB_INIT_FUNCTION (dhcp_client_init); -- cgit 1.2.3-korg From 20a175a18414c67e38b5ce0709b33fb1df8069c9 Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Tue, 14 Feb 2017 07:28:41 -0800 Subject: dhcp: multiple additions DHCP additions: 1) DHCPv4 will only relay a message back to the client, if the Option82 information is present. So make this the default. 2) It is no longer possible to select via the API to "insert circuit ID" - since this is now default 3) Remove the version 2 API since it's now the same as version 1. 4) Adding the VSS option is now conditional only on the presence of VSS config (not the 'insert' option in the set API) 5) DHCP proxy dump via API Change-Id: Ia7271ba8c1d4dbf34a02c401d268ccfbb1b74f17 Signed-off-by: Neale Ranns --- src/scripts/vnet/dhcp/proxy | 21 ++ src/vat/api_format.c | 173 ++++++----- src/vnet/dhcp/client.c | 1 + src/vnet/dhcp/client.h | 3 + src/vnet/dhcp/dhcp.api | 67 ++--- src/vnet/dhcp/dhcp_api.c | 112 ++++--- src/vnet/dhcp/proxy.h | 33 ++- src/vnet/dhcp/proxy_error.def | 3 +- src/vnet/dhcp/proxy_node.c | 676 +++++++++++++++++++++++------------------- src/vnet/dhcpv6/proxy.h | 19 +- src/vnet/dhcpv6/proxy_node.c | 513 ++++++++++++++++++-------------- src/vnet/dpo/receive_dpo.c | 5 + src/vpp/api/custom_dump.c | 34 --- test/test_dhcp.py | 166 ++++++----- test/vpp_papi_provider.py | 6 +- 15 files changed, 978 insertions(+), 854 deletions(-) create mode 100644 src/scripts/vnet/dhcp/proxy (limited to 'src/vnet/dhcp/client.c') diff --git a/src/scripts/vnet/dhcp/proxy b/src/scripts/vnet/dhcp/proxy new file mode 100644 index 00000000..c709d87d --- /dev/null +++ b/src/scripts/vnet/dhcp/proxy @@ -0,0 +1,21 @@ +loop create +loop create + +set int state loop0 up +set int state loop1 up + +set int ip table loop1 1 +set int ip6 table loop1 1 + +set int ip addr loop0 10.0.0.1/24 +set int ip addr loop0 10.0.1.1/24 + +set int ip addr loop0 2001::1/64 +set int ip addr loop0 2001:1::1/64 + +set dhcp proxy server 10.255.0.1 src-address 10.0.0.1 server-fib-id 0 rx-fib-id 0 +set dhcp proxy server 10.255.0.2 src-address 10.0.1.1 server-fib-id 1 rx-fib-id 1 + +set dhcpv6 proxy server 3001::1 src-address 2001::1 server-fib-id 0 rx-fib-id 0 +set dhcpv6 proxy server 3002::1 src-address 2001:1::1 server-fib-id 1 rx-fib-id 1 + diff --git a/src/vat/api_format.c b/src/vat/api_format.c index 11e68214..78c5e279 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -3819,7 +3819,6 @@ _(reset_vrf_reply) \ _(oam_add_del_reply) \ _(reset_fib_reply) \ _(dhcp_proxy_config_reply) \ -_(dhcp_proxy_config_2_reply) \ _(dhcp_proxy_set_vss_reply) \ _(dhcp_client_config_reply) \ _(set_ip_flow_hash_reply) \ @@ -4033,8 +4032,8 @@ _(CREATE_SUBIF_REPLY, create_subif_reply) \ _(OAM_ADD_DEL_REPLY, oam_add_del_reply) \ _(RESET_FIB_REPLY, reset_fib_reply) \ _(DHCP_PROXY_CONFIG_REPLY, dhcp_proxy_config_reply) \ -_(DHCP_PROXY_CONFIG_2_REPLY, dhcp_proxy_config_2_reply) \ _(DHCP_PROXY_SET_VSS_REPLY, dhcp_proxy_set_vss_reply) \ +_(DHCP_PROXY_DETAILS, dhcp_proxy_details) \ _(DHCP_CLIENT_CONFIG_REPLY, dhcp_client_config_reply) \ _(SET_IP_FLOW_HASH_REPLY, set_ip_flow_hash_reply) \ _(SW_INTERFACE_IP6_ENABLE_DISABLE_REPLY, \ @@ -7635,9 +7634,9 @@ api_dhcp_proxy_config (vat_main_t * vam) { unformat_input_t *i = vam->input; vl_api_dhcp_proxy_config_t *mp; - u32 vrf_id = 0; + u32 rx_vrf_id = 0; + u32 server_vrf_id = 0; u8 is_add = 1; - u8 insert_cid = 1; u8 v4_address_set = 0; u8 v6_address_set = 0; ip4_address_t v4address; @@ -7653,9 +7652,9 @@ api_dhcp_proxy_config (vat_main_t * vam) { if (unformat (i, "del")) is_add = 0; - else if (unformat (i, "vrf %d", &vrf_id)) + else if (unformat (i, "rx_vrf_id %d", &rx_vrf_id)) ; - else if (unformat (i, "insert-cid %d", &insert_cid)) + else if (unformat (i, "server_vrf_id %d", &server_vrf_id)) ; else if (unformat (i, "svr %U", unformat_ip4_address, &v4address)) v4_address_set = 1; @@ -7701,9 +7700,9 @@ api_dhcp_proxy_config (vat_main_t * vam) /* Construct the API message */ M (DHCP_PROXY_CONFIG, mp); - mp->insert_circuit_id = insert_cid; mp->is_add = is_add; - mp->vrf_id = ntohl (vrf_id); + mp->rx_vrf_id = ntohl (rx_vrf_id); + mp->server_vrf_id = ntohl (server_vrf_id); if (v6_address_set) { mp->is_ipv6 = 1; @@ -7724,100 +7723,98 @@ api_dhcp_proxy_config (vat_main_t * vam) return ret; } -static int -api_dhcp_proxy_config_2 (vat_main_t * vam) +#define vl_api_dhcp_proxy_details_t_endian vl_noop_handler +#define vl_api_dhcp_proxy_details_t_print vl_noop_handler + +static void +vl_api_dhcp_proxy_details_t_handler (vl_api_dhcp_proxy_details_t * mp) { - unformat_input_t *i = vam->input; - vl_api_dhcp_proxy_config_2_t *mp; - u32 rx_vrf_id = 0; - u32 server_vrf_id = 0; - u8 is_add = 1; - u8 insert_cid = 1; - u8 v4_address_set = 0; - u8 v6_address_set = 0; - ip4_address_t v4address; - ip6_address_t v6address; - u8 v4_src_address_set = 0; - u8 v6_src_address_set = 0; - ip4_address_t v4srcaddress; - ip6_address_t v6srcaddress; - int ret; + vat_main_t *vam = &vat_main; - /* Parse args required to build the message */ - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) - { - if (unformat (i, "del")) - is_add = 0; - else if (unformat (i, "rx_vrf_id %d", &rx_vrf_id)) - ; - else if (unformat (i, "server_vrf_id %d", &server_vrf_id)) - ; - else if (unformat (i, "insert-cid %d", &insert_cid)) - ; - else if (unformat (i, "svr %U", unformat_ip4_address, &v4address)) - v4_address_set = 1; - else if (unformat (i, "svr %U", unformat_ip6_address, &v6address)) - v6_address_set = 1; - else if (unformat (i, "src %U", unformat_ip4_address, &v4srcaddress)) - v4_src_address_set = 1; - else if (unformat (i, "src %U", unformat_ip6_address, &v6srcaddress)) - v6_src_address_set = 1; - else - break; - } + if (mp->is_ipv6) + print (vam->ofp, + "RX Table-ID %d, Server Table-ID %d, Server Address %U, Source Address %U, VSS FIB-ID %d, VSS OUI %d", + ntohl (mp->rx_vrf_id), + ntohl (mp->server_vrf_id), + format_ip6_address, mp->dhcp_server, + format_ip6_address, mp->dhcp_src_address, + ntohl (mp->vss_oui), ntohl (mp->vss_fib_id)); + else + print (vam->ofp, + "RX Table-ID %d, Server Table-ID %d, Server Address %U, Source Address %U, VSS FIB-ID %d, VSS OUI %d", + ntohl (mp->rx_vrf_id), + ntohl (mp->server_vrf_id), + format_ip4_address, mp->dhcp_server, + format_ip4_address, mp->dhcp_src_address, + ntohl (mp->vss_oui), ntohl (mp->vss_fib_id)); +} - if (v4_address_set && v6_address_set) - { - errmsg ("both v4 and v6 server addresses set"); - return -99; - } - if (!v4_address_set && !v6_address_set) - { - errmsg ("no server addresses set"); - return -99; - } +static void vl_api_dhcp_proxy_details_t_handler_json + (vl_api_dhcp_proxy_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + struct in_addr ip4; + struct in6_addr ip6; - if (v4_src_address_set && v6_src_address_set) + if (VAT_JSON_ARRAY != vam->json_tree.type) { - errmsg ("both v4 and v6 src addresses set"); - return -99; + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); } - if (!v4_src_address_set && !v6_src_address_set) + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_uint (node, "rx-table-id", ntohl (mp->rx_vrf_id)); + vat_json_object_add_uint (node, "server-table-id", + ntohl (mp->server_vrf_id)); + if (mp->is_ipv6) { - errmsg ("no src addresses set"); - return -99; + clib_memcpy (&ip6, &mp->dhcp_server, sizeof (ip6)); + vat_json_object_add_ip6 (node, "server_address", ip6); + clib_memcpy (&ip6, &mp->dhcp_src_address, sizeof (ip6)); + vat_json_object_add_ip6 (node, "src_address", ip6); } - - if (!(v4_src_address_set && v4_address_set) && - !(v6_src_address_set && v6_address_set)) + else { - errmsg ("no matching server and src addresses set"); - return -99; + clib_memcpy (&ip4, &mp->dhcp_server, sizeof (ip4)); + vat_json_object_add_ip4 (node, "server_address", ip4); + clib_memcpy (&ip4, &mp->dhcp_src_address, sizeof (ip4)); + vat_json_object_add_ip4 (node, "src_address", ip4); } + vat_json_object_add_uint (node, "vss-fib-id", ntohl (mp->vss_fib_id)); + vat_json_object_add_uint (node, "vss-oui", ntohl (mp->vss_oui)); +} - /* Construct the API message */ - M (DHCP_PROXY_CONFIG_2, mp); +static int +api_dhcp_proxy_dump (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_control_ping_t *mp_ping; + vl_api_dhcp_proxy_dump_t *mp; + u8 is_ipv6 = 0; + int ret; - mp->insert_circuit_id = insert_cid; - mp->is_add = is_add; - mp->rx_vrf_id = ntohl (rx_vrf_id); - mp->server_vrf_id = ntohl (server_vrf_id); - if (v6_address_set) - { - mp->is_ipv6 = 1; - clib_memcpy (mp->dhcp_server, &v6address, sizeof (v6address)); - clib_memcpy (mp->dhcp_src_address, &v6srcaddress, sizeof (v6address)); - } - else + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) { - clib_memcpy (mp->dhcp_server, &v4address, sizeof (v4address)); - clib_memcpy (mp->dhcp_src_address, &v4srcaddress, sizeof (v4address)); + if (unformat (i, "ipv6")) + is_ipv6 = 1; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } } - /* send it... */ + M (DHCP_PROXY_DUMP, mp); + + mp->is_ip6 = is_ipv6; S (mp); - /* Wait for a reply, return good/bad news */ + /* Use a control ping for synchronization */ + M (CONTROL_PING, mp_ping); + S (mp_ping); + W (ret); return ret; } @@ -18187,12 +18184,10 @@ _(oam_add_del, "src dst [vrf ] [del]") \ _(reset_fib, "vrf [ipv6]") \ _(dhcp_proxy_config, \ "svr src \n" \ - "insert-cid [del]") \ -_(dhcp_proxy_config_2, \ - "svr src \n" \ - "rx_vrf_id server_vrf_id insert-cid [del]") \ + "rx_vrf_id server_vrf_id [del]") \ _(dhcp_proxy_set_vss, \ "tbl_id fib_id oui [ipv6] [del]") \ +_(dhcp_proxy_dump, "ip6") \ _(dhcp_client_config, \ " | sw_if_index [hostname ] [disable_event] [del]") \ _(set_ip_flow_hash, \ diff --git a/src/vnet/dhcp/client.c b/src/vnet/dhcp/client.c index c352e310..8a1a43b3 100644 --- a/src/vnet/dhcp/client.c +++ b/src/vnet/dhcp/client.c @@ -13,6 +13,7 @@ * limitations under the License. */ #include +#include #include #include diff --git a/src/vnet/dhcp/client.h b/src/vnet/dhcp/client.h index d15e686b..a74368cb 100644 --- a/src/vnet/dhcp/client.h +++ b/src/vnet/dhcp/client.h @@ -19,6 +19,9 @@ #ifndef included_dhcp_client_h #define included_dhcp_client_h +#include +#include + #define foreach_dhcp_client_state \ _(DHCP_DISCOVER) \ _(DHCP_REQUEST) \ diff --git a/src/vnet/dhcp/dhcp.api b/src/vnet/dhcp/dhcp.api index c228cd04..8daadd8c 100644 --- a/src/vnet/dhcp/dhcp.api +++ b/src/vnet/dhcp/dhcp.api @@ -16,7 +16,8 @@ /** \brief DHCP Proxy config add / del request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request - @param vrf_id - vrf id + @param rx_vrf_id - Rx/interface vrf id + @param server_vrf_id - server vrf id @param if_ipv6 - ipv6 if non-zero, else ipv4 @param is_add - add the config if non-zero, else delete @param insert_circuit_id - option82 suboption 1 fib number @@ -27,10 +28,10 @@ define dhcp_proxy_config { u32 client_index; u32 context; - u32 vrf_id; + u32 rx_vrf_id; + u32 server_vrf_id; u8 is_ipv6; u8 is_add; - u8 insert_circuit_id; u8 dhcp_server[16]; u8 dhcp_src_address[16]; }; @@ -45,40 +46,6 @@ define dhcp_proxy_config_reply i32 retval; }; -/** \brief DHCP Proxy config 2 add / del request - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param rx_vrf_id - receive vrf id - @param server_vrf_id - server vrf id - @param if_ipv6 - ipv6 if non-zero, else ipv4 - @param is_add - add the config if non-zero, else delete - @param insert_circuit_id - option82 suboption 1 fib number - @param dhcp_server[] - server address - @param dhcp_src_address[] - -*/ -define dhcp_proxy_config_2 -{ - u32 client_index; - u32 context; - u32 rx_vrf_id; - u32 server_vrf_id; - u8 is_ipv6; - u8 is_add; - u8 insert_circuit_id; - u8 dhcp_server[16]; - u8 dhcp_src_address[16]; -}; - -/** \brief DHCP Proxy config 2 add / del response - @param context - sender context, to match reply w/ request - @param retval - return code for request -*/ -define dhcp_proxy_config_2_reply -{ - u32 context; - i32 retval; -}; - /** \brief DHCP Proxy set / unset vss request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -159,6 +126,32 @@ define dhcp_compl_event u8 host_mac[6]; }; +/** \brief Dump DHCP proxy table + @param client_index - opaque cookie to identify the sender + @param True for IPv6 proxy table +*/ +define dhcp_proxy_dump +{ + u32 client_index; + u32 context; + u8 is_ip6; +}; + +/** \brief Tell client about a DHCP completion event + @param client_index - opaque cookie to identify the sender +*/ +define dhcp_proxy_details +{ + u32 context; + u32 rx_vrf_id; + u32 server_vrf_id; + u32 vss_oui; + u32 vss_fib_id; + u8 is_ipv6; + u8 dhcp_server[16]; + u8 dhcp_src_address[16]; +}; + /* * Local Variables: * eval: (c-set-style "gnu") diff --git a/src/vnet/dhcp/dhcp_api.c b/src/vnet/dhcp/dhcp_api.c index 88b32b24..ce9039b7 100644 --- a/src/vnet/dhcp/dhcp_api.c +++ b/src/vnet/dhcp/dhcp_api.c @@ -46,7 +46,8 @@ #define foreach_vpe_api_msg \ _(DHCP_PROXY_CONFIG,dhcp_proxy_config) \ -_(DHCP_PROXY_CONFIG_2,dhcp_proxy_config_2) \ +_(DHCP_PROXY_DUMP,dhcp_proxy_dump) \ +_(DHCP_PROXY_DETAILS,dhcp_proxy_details) \ _(DHCP_PROXY_SET_VSS,dhcp_proxy_set_vss) \ _(DHCP_CLIENT_CONFIG, dhcp_client_config) @@ -58,8 +59,8 @@ dhcpv4_proxy_config (vl_api_dhcp_proxy_config_t * mp) rv = dhcp_proxy_set_server ((ip4_address_t *) (&mp->dhcp_server), (ip4_address_t *) (&mp->dhcp_src_address), - (u32) ntohl (mp->vrf_id), - (int) mp->insert_circuit_id, + (u32) ntohl (mp->rx_vrf_id), + (u32) ntohl (mp->server_vrf_id), (int) (mp->is_add == 0)); REPLY_MACRO (VL_API_DHCP_PROXY_CONFIG_REPLY); @@ -74,44 +75,11 @@ dhcpv6_proxy_config (vl_api_dhcp_proxy_config_t * mp) rv = dhcpv6_proxy_set_server ((ip6_address_t *) (&mp->dhcp_server), (ip6_address_t *) (&mp->dhcp_src_address), - (u32) ntohl (mp->vrf_id), - (int) mp->insert_circuit_id, - (int) (mp->is_add == 0)); - - REPLY_MACRO (VL_API_DHCP_PROXY_CONFIG_REPLY); -} - -static void -dhcpv4_proxy_config_2 (vl_api_dhcp_proxy_config_2_t * mp) -{ - vl_api_dhcp_proxy_config_reply_t *rmp; - int rv; - - rv = dhcp_proxy_set_server_2 ((ip4_address_t *) (&mp->dhcp_server), - (ip4_address_t *) (&mp->dhcp_src_address), (u32) ntohl (mp->rx_vrf_id), (u32) ntohl (mp->server_vrf_id), - (int) mp->insert_circuit_id, (int) (mp->is_add == 0)); - REPLY_MACRO (VL_API_DHCP_PROXY_CONFIG_2_REPLY); -} - - -static void -dhcpv6_proxy_config_2 (vl_api_dhcp_proxy_config_2_t * mp) -{ - vl_api_dhcp_proxy_config_reply_t *rmp; - int rv = -1; - - rv = dhcpv6_proxy_set_server_2 ((ip6_address_t *) (&mp->dhcp_server), - (ip6_address_t *) (&mp->dhcp_src_address), - (u32) ntohl (mp->rx_vrf_id), - (u32) ntohl (mp->server_vrf_id), - (int) mp->insert_circuit_id, - (int) (mp->is_add == 0)); - - REPLY_MACRO (VL_API_DHCP_PROXY_CONFIG_2_REPLY); + REPLY_MACRO (VL_API_DHCP_PROXY_CONFIG_REPLY); } @@ -143,6 +111,67 @@ static void vl_api_dhcp_proxy_config_t_handler dhcpv6_proxy_config (mp); } +static void +vl_api_dhcp_proxy_dump_t_handler (vl_api_dhcp_proxy_dump_t * mp) +{ + unix_shared_memory_queue_t *q; + + q = vl_api_client_index_to_input_queue (mp->client_index); + if (q == 0) + return; + + if (mp->is_ip6 == 0) + dhcp_proxy_dump (q, mp->context); + else + dhcpv6_proxy_dump (q, mp->context); +} + +void +dhcp_send_details (void *opaque, + u32 context, + const ip46_address_t * server, + const ip46_address_t * src, + u32 server_fib_id, + u32 rx_fib_id, u32 vss_fib_id, u32 vss_oui) +{ + vl_api_dhcp_proxy_details_t *mp; + unix_shared_memory_queue_t *q = opaque; + + mp = vl_msg_api_alloc (sizeof (*mp)); + if (!mp) + return; + memset (mp, 0, sizeof (*mp)); + mp->_vl_msg_id = ntohs (VL_API_DHCP_PROXY_DETAILS); + mp->context = context; + + mp->rx_vrf_id = htonl (rx_fib_id); + mp->server_vrf_id = htonl (server_fib_id); + mp->vss_oui = htonl (vss_oui); + mp->vss_fib_id = htonl (vss_fib_id); + + mp->is_ipv6 = !ip46_address_is_ip4 (server); + + if (mp->is_ipv6) + { + memcpy (mp->dhcp_server, server, 16); + memcpy (mp->dhcp_src_address, src, 16); + } + else + { + /* put the address in the first bytes */ + memcpy (mp->dhcp_server, &server->ip4, 4); + memcpy (mp->dhcp_src_address, &src->ip4, 4); + } + vl_msg_api_send_shmem (q, (u8 *) & mp); +} + + +static void +vl_api_dhcp_proxy_details_t_handler (vl_api_dhcp_proxy_details_t * mp) +{ + clib_warning ("BUG"); +} + void dhcp_compl_event_callback (u32 client_index, u32 pid, u8 * hostname, u8 is_ipv6, u8 * host_address, u8 * router_address, @@ -172,15 +201,6 @@ dhcp_compl_event_callback (u32 client_index, u32 pid, u8 * hostname, vl_msg_api_send_shmem (q, (u8 *) & mp); } -static void vl_api_dhcp_proxy_config_2_t_handler - (vl_api_dhcp_proxy_config_2_t * mp) -{ - if (mp->is_ipv6 == 0) - dhcpv4_proxy_config_2 (mp); - else - dhcpv6_proxy_config_2 (mp); -} - static void vl_api_dhcp_client_config_t_handler (vl_api_dhcp_client_config_t * mp) { diff --git a/src/vnet/dhcp/proxy.h b/src/vnet/dhcp/proxy.h index e12c0d00..4b115c74 100644 --- a/src/vnet/dhcp/proxy.h +++ b/src/vnet/dhcp/proxy.h @@ -27,7 +27,6 @@ #include #include #include -#include typedef enum { #define dhcp_proxy_error(n,s) DHCP_PROXY_ERROR_##n, @@ -49,9 +48,7 @@ typedef union { typedef struct { ip4_address_t dhcp_server; ip4_address_t dhcp_src_address; - u32 insert_option_82; u32 server_fib_index; - u32 valid; } dhcp_server_t; typedef struct { @@ -64,29 +61,39 @@ typedef struct { /* to drop pkts in server-to-client direction */ u32 error_drop_node_index; - vss_info *opt82vss; + vss_info *vss; /* hash lookup specific vrf_id -> option 82 vss suboption */ - uword * opt82vss_index_by_vrf_id; + u32 *vss_index_by_rx_fib_index; /* convenience */ - dhcp_client_main_t * dhcp_client_main; vlib_main_t * vlib_main; vnet_main_t * vnet_main; } dhcp_proxy_main_t; -dhcp_proxy_main_t dhcp_proxy_main; +extern dhcp_proxy_main_t dhcp_proxy_main; -int dhcp_proxy_set_server (ip4_address_t *addr, ip4_address_t *src_address, - u32 fib_id, int insert_option_82, int is_del); +void dhcp_send_details (void *opaque, + u32 context, + const ip46_address_t *server, + const ip46_address_t *src, + u32 server_fib_id, + u32 rx_fib_id, + u32 vss_fib_id, + u32 vss_oui); -int dhcp_proxy_set_server_2 (ip4_address_t *addr, ip4_address_t *src_address, - u32 rx_fib_id, - u32 server_fib_id, - int insert_option_82, int is_del); +int dhcp_proxy_set_server (ip4_address_t *addr, + ip4_address_t *src_address, + u32 fib_id, + u32 server_fib_id, + int is_del); int dhcp_proxy_set_option82_vss(u32 vrf_id, u32 oui, u32 fib_id, int is_del); + +void dhcp_proxy_dump(void *opaque, + u32 context); + #endif /* included_dhcp_proxy_h */ diff --git a/src/vnet/dhcp/proxy_error.def b/src/vnet/dhcp/proxy_error.def index 6aa06eb5..6d790d73 100644 --- a/src/vnet/dhcp/proxy_error.def +++ b/src/vnet/dhcp/proxy_error.def @@ -21,7 +21,8 @@ dhcp_proxy_error (RELAY_TO_SERVER, "DHCP packets relayed to the server") dhcp_proxy_error (RELAY_TO_CLIENT, "DHCP packets relayed to clients") dhcp_proxy_error (OPTION_82_ERROR, "DHCP failed to insert option 82") dhcp_proxy_error (NO_OPTION_82, "DHCP option 82 missing") -dhcp_proxy_error (BAD_OPTION_82, "Bad DHCP option 82 value") +dhcp_proxy_error (BAD_OPTION_82_ITF, "Bad DHCP option 82 interface value") +dhcp_proxy_error (BAD_OPTION_82_ADDR, "Bad DHCP option 82 address value") dhcp_proxy_error (BAD_FIB_ID, "DHCP option 82 fib-id to fib-index map failure") dhcp_proxy_error (NO_INTERFACE_ADDRESS, "DHCP no interface address") dhcp_proxy_error (OPTION_82_VSS_NOT_PROCESSED, "DHCP VSS not processed by DHCP server") diff --git a/src/vnet/dhcp/proxy_node.c b/src/vnet/dhcp/proxy_node.c index 6a58fcdb..ab6819fe 100644 --- a/src/vnet/dhcp/proxy_node.c +++ b/src/vnet/dhcp/proxy_node.c @@ -18,6 +18,7 @@ #include #include #include +#include #include static char * dhcp_proxy_error_strings[] = { @@ -57,6 +58,8 @@ typedef struct { vlib_node_registration_t dhcp_proxy_to_server_node; vlib_node_registration_t dhcp_proxy_to_client_node; +dhcp_proxy_main_t dhcp_proxy_main; + u8 * format_dhcp_proxy_trace (u8 * s, va_list * args) { CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); @@ -94,6 +97,42 @@ u8 * format_dhcp_proxy_header_with_length (u8 * s, va_list * args) return s; } +static inline vss_info * +dhcp_get_vss_info (dhcp_proxy_main_t *dm, + u32 rx_fib_index) +{ + vss_info *v; + + if (vec_len(dm->vss_index_by_rx_fib_index) <= rx_fib_index || + dm->vss_index_by_rx_fib_index[rx_fib_index] == ~0) + { + v = NULL; + } + else + { + v = pool_elt_at_index (dm->vss, + dm->vss_index_by_rx_fib_index[rx_fib_index]); + } + + return (v); +} + +static inline dhcp_server_t * +dhcp_get_server (dhcp_proxy_main_t *dm, + u32 rx_fib_index) +{ + dhcp_server_t *s = NULL; + + if (vec_len(dm->dhcp_server_index_by_rx_fib_index) > rx_fib_index && + dm->dhcp_server_index_by_rx_fib_index[rx_fib_index] != ~0) + { + s = pool_elt_at_index (dm->dhcp_servers, + dm->dhcp_server_index_by_rx_fib_index[rx_fib_index]); + } + + return (s); +} + static uword dhcp_proxy_to_server_input (vlib_main_t * vm, vlib_node_runtime_t * node, @@ -131,9 +170,12 @@ dhcp_proxy_to_server_input (vlib_main_t * vm, u32 sw_if_index = 0; u32 original_sw_if_index = 0; u8 *end = NULL; - u32 fib_index, server_index; + u32 fib_index; dhcp_server_t * server; u32 rx_sw_if_index; + dhcp_option_t *o; + u32 len = 0; + vlib_buffer_free_list_t *fl; bi0 = from[0]; to_next[0] = bi0; @@ -166,26 +208,16 @@ dhcp_proxy_to_server_input (vlib_main_t * vm, rx_sw_if_index = vnet_buffer(b0)->sw_if_index[VLIB_RX]; fib_index = im->fib_index_by_sw_if_index [rx_sw_if_index]; - - if (fib_index < vec_len(dpm->dhcp_server_index_by_rx_fib_index)) - server_index = dpm->dhcp_server_index_by_rx_fib_index[fib_index]; - else - server_index = 0; + server = dhcp_get_server(dpm, fib_index); - if (PREDICT_FALSE (pool_is_free_index (dpm->dhcp_servers, - server_index))) + if (PREDICT_FALSE (NULL == server)) { - no_server: error0 = DHCP_PROXY_ERROR_NO_SERVER; next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_DROP; pkts_no_server++; goto do_trace; } - server = pool_elt_at_index (dpm->dhcp_servers, server_index); - if (server->valid == 0) - goto no_server; - vlib_buffer_advance (b0, -(sizeof(*ip0))); ip0 = vlib_buffer_get_current (b0); @@ -216,142 +248,131 @@ dhcp_proxy_to_server_input (vlib_main_t * vm, h0->gateway_ip_address.as_u32 = server->dhcp_src_address.as_u32; pkts_to_server++; - if (server->insert_option_82) - { - u32 fib_index, fib_id, opt82_fib_id=0, opt82_oui=0; - ip4_fib_t * fib; - dhcp_option_t *o = (dhcp_option_t *) h0->options; - u32 len = 0; - vlib_buffer_free_list_t *fl; + o = (dhcp_option_t *) h0->options; - fib_index = im->fib_index_by_sw_if_index - [vnet_buffer(b0)->sw_if_index[VLIB_RX]]; - fib = ip4_fib_get (fib_index); - fib_id = fib->table_id; - - end = b0->data + b0->current_data + b0->current_length; - /* TLVs are not performance-friendly... */ - while (o->option != 0xFF /* end of options */ && (u8 *)o < end) - o = (dhcp_option_t *) (((uword) o) + (o->length + 2)); - - fl = vlib_buffer_get_free_list (vm, b0->free_list_index); - // start write at (option*)o, some packets have padding - if (((u8 *)o - (u8 *)b0->data + VPP_DHCP_OPTION82_SIZE) > fl->n_data_bytes) - { - next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_DROP; - pkts_too_big++; - goto do_trace; - } + fib_index = im->fib_index_by_sw_if_index + [vnet_buffer(b0)->sw_if_index[VLIB_RX]]; + + end = b0->data + b0->current_data + b0->current_length; + /* TLVs are not performance-friendly... */ + while (o->option != 0xFF /* end of options */ && (u8 *)o < end) + o = (dhcp_option_t *) (((uword) o) + (o->length + 2)); - if ((o->option == 0xFF) && ((u8 *)o <= end)) - { - vnet_main_t *vnm = vnet_get_main(); - u16 old_l0, new_l0; - ip4_address_t _ia0, * ia0 = &_ia0; - uword *p_vss; - vss_info *vss; - vnet_sw_interface_t *swif; - sw_if_index = 0; - original_sw_if_index = 0; + fl = vlib_buffer_get_free_list (vm, b0->free_list_index); + // start write at (option*)o, some packets have padding + if (((u8 *)o - (u8 *)b0->data + VPP_DHCP_OPTION82_SIZE) > fl->n_data_bytes) + { + next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_DROP; + pkts_too_big++; + goto do_trace; + } + + if ((o->option == 0xFF) && ((u8 *)o <= end)) + { + vnet_main_t *vnm = vnet_get_main(); + u16 old_l0, new_l0; + ip4_address_t _ia0, * ia0 = &_ia0; + vss_info *vss; + vnet_sw_interface_t *swif; + sw_if_index = 0; + original_sw_if_index = 0; - original_sw_if_index = sw_if_index = - vnet_buffer(b0)->sw_if_index[VLIB_RX]; - swif = vnet_get_sw_interface (vnm, sw_if_index); - if (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED) - sw_if_index = swif->unnumbered_sw_if_index; + original_sw_if_index = sw_if_index = + vnet_buffer(b0)->sw_if_index[VLIB_RX]; + swif = vnet_get_sw_interface (vnm, sw_if_index); + if (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED) + sw_if_index = swif->unnumbered_sw_if_index; - p_vss = hash_get (dpm->opt82vss_index_by_vrf_id, - fib_id); - if (p_vss) - { - vss = pool_elt_at_index (dpm->opt82vss, p_vss[0]); - opt82_oui = vss->vpn_id.oui; - opt82_fib_id = vss->vpn_id.fib_id; - } - /* - * Get the first ip4 address on the [client-side] - * RX interface, if not unnumbered. otherwise use - * the loopback interface's ip address. - */ - ia0 = ip4_interface_first_address(&ip4_main, sw_if_index, 0); + /* + * Get the first ip4 address on the [client-side] + * RX interface, if not unnumbered. otherwise use + * the loopback interface's ip address. + */ + ia0 = ip4_interface_first_address(&ip4_main, sw_if_index, 0); - if (ia0 == 0) - { - error0 = DHCP_PROXY_ERROR_NO_INTERFACE_ADDRESS; - next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_DROP; - pkts_no_interface_address++; - goto do_trace; - } - - /* Add option 82 */ - o->option = 82; /* option 82 */ - o->length = 12; /* 12 octets to follow */ - o->data[0] = 1; /* suboption 1, circuit ID (=FIB id) */ - o->data[1] = 4; /* length of suboption */ - o->data[2] = (original_sw_if_index >> 24) & 0xFF; - o->data[3] = (original_sw_if_index >> 16) & 0xFF; - o->data[4] = (original_sw_if_index >> 8) & 0xFF; - o->data[5] = (original_sw_if_index >> 0) & 0xFF; - o->data[6] = 5; /* suboption 5 (client RX intfc address) */ - o->data[7] = 4; /* length 4 */ - o->data[8] = ia0->as_u8[0]; - o->data[9] = ia0->as_u8[1]; - o->data[10] = ia0->as_u8[2]; - o->data[11] = ia0->as_u8[3]; - o->data[12] = 0xFF; - if (opt82_oui !=0 || opt82_fib_id != 0) - { - o->data[12] = 151; /* vss suboption */ - if (255 == opt82_fib_id) { - o->data[13] = 1; /* length */ - o->data[14] = 255; /* vss option type */ - o->data[15] = 152; /* vss control suboption */ - o->data[16] = 0; /* length */ - /* and a new "end-of-options" option (0xff) */ - o->data[17] = 0xFF; - o->length += 5; - } else { - o->data[13] = 8; /* length */ - o->data[14] = 1; /* vss option type */ - o->data[15] = (opt82_oui >> 16) & 0xff; - o->data[16] = (opt82_oui >> 8) & 0xff; - o->data[17] = (opt82_oui ) & 0xff; - o->data[18] = (opt82_fib_id >> 24) & 0xff; - o->data[19] = (opt82_fib_id >> 16) & 0xff; - o->data[20] = (opt82_fib_id >> 8) & 0xff; - o->data[21] = (opt82_fib_id) & 0xff; - o->data[22] = 152; /* vss control suboption */ - o->data[23] = 0; /* length */ + if (ia0 == 0) + { + error0 = DHCP_PROXY_ERROR_NO_INTERFACE_ADDRESS; + next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_DROP; + pkts_no_interface_address++; + goto do_trace; + } + + /* Add option 82 */ + o->option = 82; /* option 82 */ + o->length = 12; /* 12 octets to follow */ + o->data[0] = 1; /* suboption 1, circuit ID (=FIB id) */ + o->data[1] = 4; /* length of suboption */ + o->data[2] = (original_sw_if_index >> 24) & 0xFF; + o->data[3] = (original_sw_if_index >> 16) & 0xFF; + o->data[4] = (original_sw_if_index >> 8) & 0xFF; + o->data[5] = (original_sw_if_index >> 0) & 0xFF; + o->data[6] = 5; /* suboption 5 (client RX intfc address) */ + o->data[7] = 4; /* length 4 */ + o->data[8] = ia0->as_u8[0]; + o->data[9] = ia0->as_u8[1]; + o->data[10] = ia0->as_u8[2]; + o->data[11] = ia0->as_u8[3]; + o->data[12] = 0xFF; + + vss = dhcp_get_vss_info (dpm, fib_index); + if (NULL != vss) + { + u32 opt82_fib_id=0, opt82_oui=0; + + opt82_oui = vss->vpn_id.oui; + opt82_fib_id = vss->vpn_id.fib_id; + + o->data[12] = 151; /* vss suboption */ + if (255 == opt82_fib_id) { + o->data[13] = 1; /* length */ + o->data[14] = 255; /* vss option type */ + o->data[15] = 152; /* vss control suboption */ + o->data[16] = 0; /* length */ + /* and a new "end-of-options" option (0xff) */ + o->data[17] = 0xFF; + o->length += 5; + } else { + o->data[13] = 8; /* length */ + o->data[14] = 1; /* vss option type */ + o->data[15] = (opt82_oui >> 16) & 0xff; + o->data[16] = (opt82_oui >> 8) & 0xff; + o->data[17] = (opt82_oui ) & 0xff; + o->data[18] = (opt82_fib_id >> 24) & 0xff; + o->data[19] = (opt82_fib_id >> 16) & 0xff; + o->data[20] = (opt82_fib_id >> 8) & 0xff; + o->data[21] = (opt82_fib_id) & 0xff; + o->data[22] = 152; /* vss control suboption */ + o->data[23] = 0; /* length */ - /* and a new "end-of-options" option (0xff) */ - o->data[24] = 0xFF; - o->length += 12; - } + /* and a new "end-of-options" option (0xff) */ + o->data[24] = 0xFF; + o->length += 12; } - - len = o->length + 3; - b0->current_length += len; - /* Fix IP header length and checksum */ - old_l0 = ip0->length; - new_l0 = clib_net_to_host_u16 (old_l0); - new_l0 += len; - new_l0 = clib_host_to_net_u16 (new_l0); - ip0->length = new_l0; - sum0 = ip0->checksum; - sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t, - length /* changed member */); - ip0->checksum = ip_csum_fold (sum0); - - /* Fix UDP length */ - new_l0 = clib_net_to_host_u16 (u0->length); - new_l0 += len; - u0->length = clib_host_to_net_u16 (new_l0); - } else { - vlib_node_increment_counter - (vm, dhcp_proxy_to_server_node.index, - DHCP_PROXY_ERROR_OPTION_82_ERROR, 1); - } - } + } + + len = o->length + 3; + b0->current_length += len; + /* Fix IP header length and checksum */ + old_l0 = ip0->length; + new_l0 = clib_net_to_host_u16 (old_l0); + new_l0 += len; + new_l0 = clib_host_to_net_u16 (new_l0); + ip0->length = new_l0; + sum0 = ip0->checksum; + sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t, + length /* changed member */); + ip0->checksum = ip_csum_fold (sum0); + + /* Fix UDP length */ + new_l0 = clib_net_to_host_u16 (u0->length); + new_l0 += len; + u0->length = clib_host_to_net_u16 (new_l0); + } else { + vlib_node_increment_counter + (vm, dhcp_proxy_to_server_node.index, + DHCP_PROXY_ERROR_OPTION_82_ERROR, 1); + } next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP; @@ -451,11 +472,13 @@ dhcp_proxy_to_client_input (vlib_main_t * vm, vnet_sw_interface_t *si0; u32 error0 = (u32)~0; vnet_sw_interface_t *swif; - u32 server_index; u32 fib_index; dhcp_server_t * server; u32 original_sw_if_index = (u32) ~0; - + ip4_address_t relay_addr = { + .as_u32 = 0, + }; + bi0 = from[0]; from += 1; n_left_from -= 1; @@ -501,13 +524,21 @@ dhcp_proxy_to_client_input (vlib_main_t * vm, and the sw_if_index */ if (sub->option == 1 && sub->length == 4) { - sw_if_index = (o->data[2] << 24) - | (o->data[3] << 16) - | (o->data[4] << 8) - | (o->data[5]); - } else if (sub->option == 151 && - sub->length == 7 && - sub->data[0] == 1) + sw_if_index = ((sub->data[0] << 24) | + (sub->data[1] << 16) | + (sub->data[2] << 8) | + (sub->data[3])); + } + else if (sub->option == 5 && sub->length == 4) + { + relay_addr.as_u8[0] = sub->data[0]; + relay_addr.as_u8[1] = sub->data[1]; + relay_addr.as_u8[2] = sub->data[2]; + relay_addr.as_u8[3] = sub->data[3]; + } + else if (sub->option == 151 && + sub->length == 7 && + sub->data[0] == 1) vss_exist = 1; else if (sub->option == 152 && sub->length == 0) vss_ctrl = 1; @@ -539,34 +570,27 @@ dhcp_proxy_to_client_input (vlib_main_t * vm, goto do_trace; } + if (relay_addr.as_u32 == 0) + { + error0 = DHCP_PROXY_ERROR_BAD_OPTION_82_ADDR; + goto drop_packet; + } if (sw_if_index >= vec_len (im->fib_index_by_sw_if_index)) { - error0 = DHCP_PROXY_ERROR_BAD_OPTION_82; + error0 = DHCP_PROXY_ERROR_BAD_OPTION_82_ITF; goto drop_packet; } fib_index = im->fib_index_by_sw_if_index [sw_if_index]; + server = dhcp_get_server(dpm, fib_index); - if (fib_index < vec_len(dpm->dhcp_server_index_by_rx_fib_index)) - server_index = dpm->dhcp_server_index_by_rx_fib_index[fib_index]; - else - server_index = 0; - - if (PREDICT_FALSE (pool_is_free_index (dpm->dhcp_servers, - server_index))) - { - error0 = DHCP_PROXY_ERROR_BAD_OPTION_82; - goto drop_packet; - } - - server = pool_elt_at_index (dpm->dhcp_servers, server_index); - if (server->valid == 0) + if (PREDICT_FALSE (NULL == server)) { error0 = DHCP_PROXY_ERROR_NO_SERVER; goto drop_packet; } - + if (ip0->src_address.as_u32 != server->dhcp_server.as_u32) { error0 = DHCP_PROXY_ERROR_BAD_SVR_FIB_OR_ADDRESS; @@ -587,6 +611,12 @@ dhcp_proxy_to_client_input (vlib_main_t * vm, goto drop_packet; } + if (relay_addr.as_u32 != ia0->as_u32) + { + error0 = DHCP_PROXY_ERROR_BAD_YIADDR; + goto drop_packet; + } + u0->checksum = 0; u0->dst_port = clib_net_to_host_u16 (UDP_DST_PORT_dhcp_to_client); sum0 = ip0->checksum; @@ -677,7 +707,7 @@ clib_error_t * dhcp_proxy_init (vlib_main_t * vm) error_drop_node = vlib_get_node_by_name (vm, (u8 *) "error-drop"); dm->error_drop_node_index = error_drop_node->index; - dm->opt82vss_index_by_vrf_id = hash_create (0, sizeof (uword)); + dm->vss_index_by_rx_fib_index = NULL; udp_register_dst_port (vm, UDP_DST_PORT_dhcp_to_client, dhcp_proxy_to_client_node.index, 1 /* is_ip4 */); @@ -694,15 +724,17 @@ clib_error_t * dhcp_proxy_init (vlib_main_t * vm) VLIB_INIT_FUNCTION (dhcp_proxy_init); -int dhcp_proxy_set_server_2 (ip4_address_t *addr, ip4_address_t *src_address, - u32 rx_fib_id, - u32 server_fib_id, - int insert_option_82, int is_del) +int dhcp_proxy_set_server (ip4_address_t *addr, + ip4_address_t *src_address, + u32 rx_fib_id, + u32 server_fib_id, + int is_del) { dhcp_proxy_main_t * dpm = &dhcp_proxy_main; dhcp_server_t * server = 0; u32 server_index = 0; u32 rx_fib_index = 0; + const fib_prefix_t all_1s = { .fp_len = 32, @@ -719,97 +751,68 @@ int dhcp_proxy_set_server_2 (ip4_address_t *addr, ip4_address_t *src_address, rx_fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, rx_fib_id); - if (rx_fib_id == 0) - { - server = pool_elt_at_index (dpm->dhcp_servers, 0); - - if (is_del) - { - memset (server, 0, sizeof (*server)); - fib_table_entry_special_remove(rx_fib_index, - &all_1s, - FIB_SOURCE_DHCP); - return 0; - } - if (!server->valid) - fib_table_entry_special_add(rx_fib_index, - &all_1s, - FIB_SOURCE_DHCP, - FIB_ENTRY_FLAG_LOCAL, - ADJ_INDEX_INVALID); - - goto initialize_it; - } - if (is_del) { if (rx_fib_index >= vec_len(dpm->dhcp_server_index_by_rx_fib_index)) return VNET_API_ERROR_NO_SUCH_ENTRY; server_index = dpm->dhcp_server_index_by_rx_fib_index[rx_fib_index]; - ASSERT(server_index > 0); + + if (server_index == ~0) + return VNET_API_ERROR_NO_SUCH_ENTRY; /* Use the default server again. */ - dpm->dhcp_server_index_by_rx_fib_index[rx_fib_index] = 0; + dpm->dhcp_server_index_by_rx_fib_index[rx_fib_index] = ~0; server = pool_elt_at_index (dpm->dhcp_servers, server_index); - memset (server, 0, sizeof (*server)); - pool_put (dpm->dhcp_servers, server); fib_table_entry_special_remove(rx_fib_index, &all_1s, FIB_SOURCE_DHCP); + fib_table_unlock (rx_fib_index, + FIB_PROTOCOL_IP4); + fib_table_unlock (server->server_fib_index, + FIB_PROTOCOL_IP4); + memset (server, 0, sizeof (*server)); + pool_put (dpm->dhcp_servers, server); return 0; } - - if (rx_fib_index < vec_len(dpm->dhcp_server_index_by_rx_fib_index)) - { - server_index = dpm->dhcp_server_index_by_rx_fib_index[rx_fib_index]; - if (server_index != 0) - { - server = pool_elt_at_index (dpm->dhcp_servers, server_index); - goto initialize_it; - } - } - - pool_get (dpm->dhcp_servers, server); - - fib_table_entry_special_add(rx_fib_index, - &all_1s, - FIB_SOURCE_DHCP, - FIB_ENTRY_FLAG_LOCAL, - ADJ_INDEX_INVALID); - - initialize_it: - - - server->dhcp_server.as_u32 = addr->as_u32; - server->server_fib_index = - fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, - server_fib_id); - server->dhcp_src_address.as_u32 = src_address->as_u32; - server->insert_option_82 = insert_option_82; - server->valid = 1; - if (rx_fib_index) - { - vec_validate (dpm->dhcp_server_index_by_rx_fib_index, rx_fib_index); + else + { + vec_validate_init_empty(dpm->dhcp_server_index_by_rx_fib_index, + rx_fib_index, + ~0); + + pool_get (dpm->dhcp_servers, server); + + server->dhcp_server.as_u32 = addr->as_u32; + server->dhcp_src_address.as_u32 = src_address->as_u32; + + fib_table_entry_special_add(rx_fib_index, + &all_1s, + FIB_SOURCE_DHCP, + FIB_ENTRY_FLAG_LOCAL, + ADJ_INDEX_INVALID); + fib_table_lock (rx_fib_index, + FIB_PROTOCOL_IP4); + + server->server_fib_index = + fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, + server_fib_id); + + vec_validate_init_empty (dpm->dhcp_server_index_by_rx_fib_index, + rx_fib_index, + ~0); dpm->dhcp_server_index_by_rx_fib_index[rx_fib_index] = - server - dpm->dhcp_servers; - } + server - dpm->dhcp_servers; + } - return 0; -} + fib_table_unlock (rx_fib_index, + FIB_PROTOCOL_IP4); -/* Old API, manipulates the default server (only) */ -int dhcp_proxy_set_server (ip4_address_t *addr, ip4_address_t *src_address, - u32 fib_id, int insert_option_82, int is_del) -{ - return dhcp_proxy_set_server_2 (addr, src_address, 0 /* rx_fib_id */, - fib_id /* server_fib_id */, - insert_option_82, is_del); + return 0; } - static clib_error_t * dhcp_proxy_set_command_fn (vlib_main_t * vm, unformat_input_t * input, @@ -818,7 +821,6 @@ dhcp_proxy_set_command_fn (vlib_main_t * vm, ip4_address_t server_addr, src_addr; u32 server_fib_id = 0, rx_fib_id = 0; int is_del = 0; - int add_option_82 = 0; int set_src = 0, set_server = 0; while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) @@ -833,9 +835,6 @@ dhcp_proxy_set_command_fn (vlib_main_t * vm, else if (unformat(input, "src-address %U", unformat_ip4_address, &src_addr)) set_src = 1; - else if (unformat (input, "add-option-82") - || unformat (input, "insert-option-82")) - add_option_82 = 1; else if (unformat (input, "delete") || unformat (input, "del")) is_del = 1; @@ -847,8 +846,8 @@ dhcp_proxy_set_command_fn (vlib_main_t * vm, { int rv; - rv = dhcp_proxy_set_server_2 (&server_addr, &src_addr, rx_fib_id, - server_fib_id, add_option_82, is_del); + rv = dhcp_proxy_set_server (&server_addr, &src_addr, rx_fib_id, + server_fib_id, is_del); switch (rv) { case 0: @@ -882,7 +881,7 @@ dhcp_proxy_set_command_fn (vlib_main_t * vm, VLIB_CLI_COMMAND (dhcp_proxy_set_command, static) = { .path = "set dhcp proxy", - .short_help = "set dhcp proxy [del] server src-address [add-option-82] [server-fib-id ] [rx-fib-id ]", + .short_help = "set dhcp proxy [del] server src-address [server-fib-id ] [rx-fib-id ]", .function = dhcp_proxy_set_command_fn, }; @@ -896,8 +895,8 @@ u8 * format_dhcp_proxy_server (u8 * s, va_list * args) if (dm == 0) { - s = format (s, "%=16s%=16s%=14s%=14s%=20s", "Server", "Src Address", - "Server FIB", "RX FIB", "Insert Option 82"); + s = format (s, "%=16s%=16s%=14s%=14s", "Server", "Src Address", + "Server FIB", "RX FIB"); return s; } @@ -911,11 +910,10 @@ u8 * format_dhcp_proxy_server (u8 * s, va_list * args) if (rx_fib) rx_fib_id = rx_fib->table_id; - s = format (s, "%=16U%=16U%=14u%=14u%=20s", + s = format (s, "%=16U%=16U%=14u%=14u", format_ip4_address, &server->dhcp_server, format_ip4_address, &server->dhcp_src_address, - server_fib_id, rx_fib_id, - server->insert_option_82 ? "yes" : "no"); + server_fib_id, rx_fib_id); return s; } @@ -925,24 +923,22 @@ dhcp_proxy_show_command_fn (vlib_main_t * vm, vlib_cli_command_t * cmd) { dhcp_proxy_main_t * dpm = &dhcp_proxy_main; - ip4_main_t * im = &ip4_main; dhcp_server_t * server; - u32 server_index; - int i; + u32 server_index, i; vlib_cli_output (vm, "%U", format_dhcp_proxy_server, 0 /* header line */, 0, 0); - for (i = 0; i < vec_len (im->fibs); i++) - { - if (i < vec_len(dpm->dhcp_server_index_by_rx_fib_index)) - server_index = dpm->dhcp_server_index_by_rx_fib_index[i]; - else - server_index = 0; + vec_foreach_index (i, dpm->dhcp_server_index_by_rx_fib_index) + { + server_index = dpm->dhcp_server_index_by_rx_fib_index[i]; + if (~0 == server_index) + continue; + server = pool_elt_at_index (dpm->dhcp_servers, server_index); - if (server->valid) - vlib_cli_output (vm, "%U", format_dhcp_proxy_server, dpm, - server, i); + + vlib_cli_output (vm, "%U", format_dhcp_proxy_server, dpm, + server, i); } return 0; @@ -954,50 +950,104 @@ VLIB_CLI_COMMAND (dhcp_proxy_show_command, static) = { .function = dhcp_proxy_show_command_fn, }; +void +dhcp_proxy_dump (void *opaque, + u32 context) +{ + dhcp_proxy_main_t * dpm = &dhcp_proxy_main; + ip4_fib_t *s_fib, *r_fib; + dhcp_server_t * server; + u32 server_index, i; + vss_info *v; + + vec_foreach_index (i, dpm->dhcp_server_index_by_rx_fib_index) + { + server_index = dpm->dhcp_server_index_by_rx_fib_index[i]; + if (~0 == server_index) + continue; + + server = pool_elt_at_index (dpm->dhcp_servers, server_index); + v = dhcp_get_vss_info(dpm, i); + + ip46_address_t src_addr = { + .ip4 = server->dhcp_src_address, + }; + ip46_address_t server_addr = { + .ip4 = server->dhcp_server, + }; + + s_fib = ip4_fib_get(server->server_fib_index); + r_fib = ip4_fib_get(i); + + dhcp_send_details(opaque, + context, + &server_addr, + &src_addr, + s_fib->table_id, + r_fib->table_id, + (v ? v->vpn_id.fib_id : 0), + (v ? v->vpn_id.oui : 0)); + } +} -int dhcp_proxy_set_option82_vss( u32 vrf_id, - u32 oui, - u32 fib_id, - int is_del) +int dhcp_proxy_set_option82_vss(u32 tbl_id, + u32 oui, + u32 fib_id, + int is_del) { dhcp_proxy_main_t *dm = &dhcp_proxy_main; - uword *p; - vss_info *a; - u32 old_oui=0, old_fib_id=0; + vss_info *v = NULL; + u32 rx_fib_index; + int rc = 0; - p = hash_get (dm->opt82vss_index_by_vrf_id, vrf_id); + rx_fib_index = ip4_fib_table_find_or_create_and_lock(tbl_id); + v = dhcp_get_vss_info(dm, rx_fib_index); - if (p) - { - a = pool_elt_at_index (dm->opt82vss, p[0]); - if (!a) - return VNET_API_ERROR_NO_SUCH_FIB; - old_oui = a->vpn_id.oui; - old_fib_id = a->vpn_id.fib_id; - + if (NULL != v) + { if (is_del) - { - if (old_oui == oui && - old_fib_id == fib_id) - { - pool_put(dm->opt82vss, a); - hash_unset (dm->opt82vss_index_by_vrf_id, vrf_id); - return 0; - } - else - return VNET_API_ERROR_NO_SUCH_ENTRY; - } - pool_put(dm->opt82vss, a); - hash_unset (dm->opt82vss_index_by_vrf_id, vrf_id); - } else if (is_del) - return VNET_API_ERROR_NO_SUCH_ENTRY; - pool_get (dm->opt82vss, a); - memset (a, ~0, sizeof (a[0])); - a->vpn_id.oui = oui; - a->vpn_id.fib_id = fib_id; - hash_set (dm->opt82vss_index_by_vrf_id, vrf_id, a - dm->opt82vss); + { + /* release the lock held on the table when the VSS + * info was created */ + fib_table_unlock (rx_fib_index, + FIB_PROTOCOL_IP4); + + pool_put (dm->vss, v); + dm->vss_index_by_rx_fib_index[rx_fib_index] = ~0; + } + else + { + /* this is a modify */ + v->vpn_id.fib_id = fib_id; + v->vpn_id.oui = oui; + } + } + else + { + if (is_del) + rc = VNET_API_ERROR_NO_SUCH_ENTRY; + else + { + /* create a new entry */ + vec_validate_init_empty(dm->vss_index_by_rx_fib_index, + rx_fib_index, ~0); + + /* hold a lock on the table whilst the VSS info exist */ + fib_table_lock (rx_fib_index, + FIB_PROTOCOL_IP4); + + pool_get (dm->vss, v); + v->vpn_id.fib_id = fib_id; + v->vpn_id.oui = oui; + dm->vss_index_by_rx_fib_index[rx_fib_index] = v - dm->vss; + } + } + + /* Release the lock taken during the create_or_lock at the start */ + fib_table_unlock (rx_fib_index, + FIB_PROTOCOL_IP4); - return 0; + return (rc); } static clib_error_t * @@ -1065,20 +1115,20 @@ dhcp_vss_show_command_fn (vlib_main_t * vm, { dhcp_proxy_main_t * dm = &dhcp_proxy_main; + ip4_fib_t *fib; + u32 *fib_index; vss_info *v; - u32 oui; - u32 fib_id; - u32 tbl_id; - uword index; vlib_cli_output (vm, "%=9s%=11s%=12s","Table", "OUI", "VPN-ID"); - hash_foreach (tbl_id, index, dm->opt82vss_index_by_vrf_id, + pool_foreach (fib_index, dm->vss_index_by_rx_fib_index, ({ - v = pool_elt_at_index (dm->opt82vss, index); - oui = v->vpn_id.oui; - fib_id = v->vpn_id.fib_id; - vlib_cli_output (vm, "%=9d 0x%08x%=12d", - tbl_id, oui, fib_id); + fib = ip4_fib_get (*fib_index); + v = pool_elt_at_index (dm->vss, *fib_index); + + vlib_cli_output (vm, "%=6d%=6d%=12d", + fib->table_id, + v->vpn_id.oui, + v->vpn_id.fib_id); })); return 0; diff --git a/src/vnet/dhcpv6/proxy.h b/src/vnet/dhcpv6/proxy.h index 9e18913a..77ced361 100644 --- a/src/vnet/dhcpv6/proxy.h +++ b/src/vnet/dhcpv6/proxy.h @@ -48,9 +48,7 @@ typedef union { typedef struct { ip6_address_t dhcp6_server; ip6_address_t dhcp6_src_address; - u32 insert_vss; u32 server_fib6_index; - u32 valid; } dhcpv6_server_t; typedef struct { @@ -70,7 +68,7 @@ typedef struct { dhcpv6_vss_info *vss; /* hash lookup specific vrf_id -> VSS vector index*/ - uword *vss_index_by_vrf_id; + u32 *vss_index_by_rx_fib_index; /* convenience */ vlib_main_t * vlib_main; @@ -79,17 +77,18 @@ typedef struct { dhcpv6_proxy_main_t dhcpv6_proxy_main; -int dhcpv6_proxy_set_server (ip6_address_t *addr, ip6_address_t *src_address, - u32 fib_id, int insert_vss, int is_del); - int dhcpv6_proxy_set_vss(u32 tbl_id, u32 oui, u32 fib_id, int is_del); -int dhcpv6_proxy_set_server_2 (ip6_address_t *addr, ip6_address_t *src_address, - u32 rx_fib_id, - u32 server_fib_id, - int insert_vss, int is_del); +int dhcpv6_proxy_set_server(ip6_address_t *addr, + ip6_address_t *src_address, + u32 rx_fib_id, + u32 server_fib_id, + int is_del); + +void dhcpv6_proxy_dump(void *opaque, + u32 context); #endif /* included_dhcpv6_proxy_h */ diff --git a/src/vnet/dhcpv6/proxy_node.c b/src/vnet/dhcpv6/proxy_node.c index 4137624c..f40798e6 100644 --- a/src/vnet/dhcpv6/proxy_node.c +++ b/src/vnet/dhcpv6/proxy_node.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -117,6 +118,42 @@ static inline void copy_ip6_address (ip6_address_t *dst, ip6_address_t *src) dst->as_u64[1] = src->as_u64[1]; } +static inline dhcpv6_vss_info * +dhcpv6_get_vss_info (dhcpv6_proxy_main_t *dm, + u32 rx_fib_index) +{ + dhcpv6_vss_info *v; + + if (vec_len(dm->vss_index_by_rx_fib_index) <= rx_fib_index || + dm->vss_index_by_rx_fib_index[rx_fib_index] == ~0) + { + v = NULL; + } + else + { + v = pool_elt_at_index (dm->vss, + dm->vss_index_by_rx_fib_index[rx_fib_index]); + } + + return (v); +} + +static inline dhcpv6_server_t * +dhcpv6_get_server (dhcpv6_proxy_main_t *dm, + u32 rx_fib_index) +{ + dhcpv6_server_t *s = NULL; + + if (vec_len(dm->dhcp6_server_index_by_rx_fib_index) > rx_fib_index && + dm->dhcp6_server_index_by_rx_fib_index[rx_fib_index] != ~0) + { + s = pool_elt_at_index (dm->dhcp6_servers, + dm->dhcp6_server_index_by_rx_fib_index[rx_fib_index]); + } + + return (s); +} + static uword dhcpv6_proxy_to_server_input (vlib_main_t * vm, vlib_node_runtime_t * node, @@ -132,13 +169,10 @@ dhcpv6_proxy_to_server_input (vlib_main_t * vm, u32 pkts_wrong_msg_type=0; u32 pkts_too_big=0; ip6_main_t * im = &ip6_main; - ip6_fib_t * fib; ip6_address_t * src; int bogus_length; dhcpv6_server_t * server; u32 rx_fib_idx = 0, server_fib_idx = 0; - u32 server_idx; - u32 fib_id1 = 0; next_index = node->cached_next_index; @@ -172,12 +206,8 @@ dhcpv6_proxy_to_server_input (vlib_main_t * vm, ethernet_header_t * e_h0; u8 client_src_mac[6]; vlib_buffer_free_list_t *fl; - - uword *p_vss; - u32 oui1=0; dhcpv6_vss_info *vss; - bi0 = from[0]; to_next[0] = bi0; from += 1; @@ -228,25 +258,15 @@ dhcpv6_proxy_to_server_input (vlib_main_t * vm, /* Send to DHCPV6 server via the configured FIB */ rx_sw_if_index = sw_if_index = vnet_buffer(b0)->sw_if_index[VLIB_RX]; rx_fib_idx = im->fib_index_by_sw_if_index [rx_sw_if_index]; + server = dhcpv6_get_server(dpm, rx_fib_idx); - if (vec_len(dpm->dhcp6_server_index_by_rx_fib_index) <= rx_fib_idx) - goto no_server; - - server_idx = dpm->dhcp6_server_index_by_rx_fib_index[rx_fib_idx]; - - if (PREDICT_FALSE (pool_is_free_index (dpm->dhcp6_servers, - server_idx))) - { - no_server: - error0 = DHCPV6_PROXY_ERROR_NO_SERVER; - next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP; - pkts_no_server++; - goto do_trace; - } - - server = pool_elt_at_index(dpm->dhcp6_servers, server_idx); - if (server->valid == 0) - goto no_server; + if (PREDICT_FALSE (NULL == server)) + { + error0 = DHCPV6_PROXY_ERROR_NO_SERVER; + next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP; + pkts_no_server++; + goto do_trace; + } server_fib_idx = server->server_fib6_index; vnet_buffer(b0)->sw_if_index[VLIB_TX] = server_fib_idx; @@ -331,19 +351,6 @@ dhcpv6_proxy_to_server_input (vlib_main_t * vm, id1 = (dhcpv6_int_id_t *) (((uword) ip1) + b0->current_length); b0->current_length += (sizeof (*id1)); - - fib = ip6_fib_get (rx_fib_idx); - - //TODO: Revisit if hash makes sense here - p_vss = hash_get (dpm->vss_index_by_vrf_id, - fib->table_id); - if (p_vss) - { - vss = pool_elt_at_index (dpm->vss, p_vss[0]); - oui1 = vss->vpn_id.oui; - fib_id1 = vss->vpn_id.fib_id; - } - id1->opt.option = clib_host_to_net_u16(DHCPV6_OPTION_INTERFACE_ID); id1->opt.length = clib_host_to_net_u16(sizeof(rx_sw_if_index)); id1->int_idx = clib_host_to_net_u32(rx_sw_if_index); @@ -360,20 +367,24 @@ dhcpv6_proxy_to_server_input (vlib_main_t * vm, clib_memcpy(cmac->data, client_src_mac, 6); u1->length += sizeof(*cmac); } - if (server->insert_vss !=0 ) { + + //TODO: Revisit if hash makes sense here + vss = dhcpv6_get_vss_info(dpm, rx_fib_idx); + + if (NULL != vss) { vss1 = (dhcpv6_vss_t *) (((uword) ip1) + b0->current_length); b0->current_length += (sizeof (*vss1)); vss1->opt.length =clib_host_to_net_u16(sizeof(*vss1) - sizeof(vss1->opt)); vss1->opt.option = clib_host_to_net_u16(DHCPV6_OPTION_VSS); vss1->data[0] = 1; // type - vss1->data[1] = oui1>>16 & 0xff; - vss1->data[2] = oui1>>8 & 0xff; - vss1->data[3] = oui1 & 0xff; - vss1->data[4] = fib_id1>>24 & 0xff; - vss1->data[5] = fib_id1>>16 & 0xff; - vss1->data[6] = fib_id1>>8 & 0xff; - vss1->data[7] = fib_id1 & 0xff; + vss1->data[1] = vss->vpn_id.oui >>16 & 0xff; + vss1->data[2] = vss->vpn_id.oui >>8 & 0xff; + vss1->data[3] = vss->vpn_id.oui & 0xff; + vss1->data[4] = vss->vpn_id.fib_id >> 24 & 0xff; + vss1->data[5] = vss->vpn_id.fib_id >> 16 & 0xff; + vss1->data[6] = vss->vpn_id.fib_id >> 8 & 0xff; + vss1->data[7] = vss->vpn_id.fib_id & 0xff; u1->length += sizeof(*vss1); } @@ -524,9 +535,8 @@ dhcpv6_proxy_to_client_input (vlib_main_t * vm, u16 len = 0; u8 interface_opt_flag = 0; u8 relay_msg_opt_flag = 0; - ip6_fib_t * svr_fib; ip6_main_t * im = &ip6_main; - u32 server_fib_idx, svr_fib_id, client_fib_idx, server_idx; + u32 server_fib_idx, client_fib_idx; bi0 = from[0]; from += 1; @@ -608,31 +618,18 @@ dhcpv6_proxy_to_client_input (vlib_main_t * vm, vlib_buffer_advance (b0, sizeof(*r0)); client_fib_idx = im->fib_index_by_sw_if_index[sw_if_index]; - if (client_fib_idx < vec_len(dm->dhcp6_server_index_by_rx_fib_index)) - server_idx = dm->dhcp6_server_index_by_rx_fib_index[client_fib_idx]; - else - server_idx = 0; - - if (PREDICT_FALSE (pool_is_free_index (dm->dhcp6_servers, server_idx))) - { - error0 = DHCPV6_PROXY_ERROR_WRONG_INTERFACE_ID_OPTION; - goto drop_packet; - } + server = dhcpv6_get_server(dm, client_fib_idx); - server = pool_elt_at_index (dm->dhcp6_servers, server_idx); - if (server->valid == 0) + if (NULL == server) { error0 = DHCPV6_PROXY_ERROR_NO_SERVER; goto drop_packet; } - server_fib_idx = im->fib_index_by_sw_if_index [vnet_buffer(b0)->sw_if_index[VLIB_RX]]; - svr_fib = ip6_fib_get (server_fib_idx); - svr_fib_id = svr_fib->table_id; - if (svr_fib_id != server->server_fib6_index || + if (server_fib_idx != server->server_fib6_index || ip0->src_address.as_u64[0] != server->dhcp6_server.as_u64[0] || ip0->src_address.as_u64[1] != server->dhcp6_server.as_u64[1]) { @@ -760,7 +757,7 @@ clib_error_t * dhcpv6_proxy_init (vlib_main_t * vm) error_drop_node = vlib_get_node_by_name (vm, (u8 *) "error-drop"); dm->error_drop_node_index = error_drop_node->index; - dm->vss_index_by_vrf_id = hash_create (0, sizeof (uword)); + dm->vss_index_by_rx_fib_index = NULL; /* RFC says this is the dhcpv6 server address */ dm->all_dhcpv6_server_address.as_u64[0] = clib_host_to_net_u64 (0xFF05000000000000); @@ -785,121 +782,138 @@ clib_error_t * dhcpv6_proxy_init (vlib_main_t * vm) VLIB_INIT_FUNCTION (dhcpv6_proxy_init); -/* Old API, manipulates a single server (only) shared by all Rx VRFs */ -int dhcpv6_proxy_set_server (ip6_address_t *addr, ip6_address_t *src_address, - u32 fib_id, int insert_vss, int is_del) -{ - return dhcpv6_proxy_set_server_2 (addr, src_address, - 0, fib_id, - insert_vss, is_del); -} - -int dhcpv6_proxy_set_server_2 (ip6_address_t *addr, ip6_address_t *src_address, - u32 rx_fib_id, u32 server_fib_id, - int insert_vss, int is_del) +int dhcpv6_proxy_set_server (ip6_address_t *addr, + ip6_address_t *src_address, + u32 rx_fib_id, + u32 server_fib_id, + int is_del) { dhcpv6_proxy_main_t * dm = &dhcpv6_proxy_main; dhcpv6_server_t * server = 0; - u32 server_fib_index = 0; u32 rx_fib_index = 0; + int rc = 0; rx_fib_index = ip6_mfib_table_find_or_create_and_lock(rx_fib_id); - server_fib_index = ip6_fib_table_find_or_create_and_lock(server_fib_id); - - if (is_del) - { - - if (rx_fib_index >= vec_len(dm->dhcp6_server_index_by_rx_fib_index)) - return VNET_API_ERROR_NO_SUCH_ENTRY; - server_fib_index = dm->dhcp6_server_index_by_rx_fib_index[rx_fib_index]; - - dm->dhcp6_server_index_by_rx_fib_index[rx_fib_index] = 0; - server = pool_elt_at_index (dm->dhcp6_servers, server_fib_index); - memset (server, 0, sizeof (*server)); - pool_put (dm->dhcp6_servers, server); - return 0; + const mfib_prefix_t all_dhcp_servers = { + .fp_len = 128, + .fp_proto = FIB_PROTOCOL_IP6, + .fp_grp_addr = { + .ip6 = dm->all_dhcpv6_server_relay_agent_address, } + }; - if (addr->as_u64[0] == 0 && - addr->as_u64[1] == 0 ) - return VNET_API_ERROR_INVALID_DST_ADDRESS; - - if (src_address->as_u64[0] == 0 && - src_address->as_u64[1] == 0) - return VNET_API_ERROR_INVALID_SRC_ADDRESS; - - if (rx_fib_id == 0) + if (is_del) { - server = pool_elt_at_index (dm->dhcp6_servers, 0); - if (server->valid) - goto reconfigure_it; - else - goto initialize_it; - } + server = dhcpv6_get_server(dm, rx_fib_index); - if (rx_fib_index < vec_len(dm->dhcp6_server_index_by_rx_fib_index)) - { - server_fib_index = dm->dhcp6_server_index_by_rx_fib_index[rx_fib_index]; - if (server_fib_index != 0) + if (NULL == server) { - server = pool_elt_at_index (dm->dhcp6_servers, server_fib_index); - goto initialize_it; + rc = VNET_API_ERROR_NO_SUCH_ENTRY; + goto out; } - } - /*Allocate a new server*/ - pool_get (dm->dhcp6_servers, server); - - initialize_it: - { - const mfib_prefix_t all_dhcp_servers = { - .fp_len = 128, - .fp_proto = FIB_PROTOCOL_IP6, - .fp_grp_addr = { - .ip6 = dm->all_dhcpv6_server_relay_agent_address, - } - }; - const fib_route_path_t path_for_us = { - .frp_proto = FIB_PROTOCOL_IP6, - .frp_addr = zero_addr, - .frp_sw_if_index = 0xffffffff, - .frp_fib_index = ~0, - .frp_weight = 0, - .frp_flags = FIB_ROUTE_PATH_LOCAL, - }; - mfib_table_entry_path_update(rx_fib_index, - &all_dhcp_servers, - MFIB_SOURCE_DHCP, - &path_for_us, - MFIB_ITF_FLAG_FORWARD); /* - * Each interface that is enabled in this table, needs to be added - * as an accepting interface, but this is not easily doable in VPP. - * So we cheat. Add a flag to the entry that indicates accept form - * any interface. - * We will still only accept on v6 enabled interfaces, since the input - * feature ensures this. + * release the locks held on the server fib and rx mfib */ - mfib_table_entry_update(rx_fib_index, + mfib_table_entry_delete(rx_fib_index, &all_dhcp_servers, - MFIB_SOURCE_DHCP, - MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF); - } + MFIB_SOURCE_DHCP); + mfib_table_unlock(rx_fib_index, FIB_PROTOCOL_IP6); + fib_table_unlock(server->server_fib6_index, FIB_PROTOCOL_IP6); -reconfigure_it: + dm->dhcp6_server_index_by_rx_fib_index[rx_fib_index] = ~0; - copy_ip6_address(&server->dhcp6_server, addr); - copy_ip6_address(&server->dhcp6_src_address, src_address); - server->server_fib6_index = server_fib_index; - server->valid = 1; - server->insert_vss = insert_vss; + memset (server, 0, sizeof (*server)); + pool_put (dm->dhcp6_servers, server); + } + else + { + if (addr->as_u64[0] == 0 && + addr->as_u64[1] == 0 ) + { + rc = VNET_API_ERROR_INVALID_DST_ADDRESS; + goto out; + } + if (src_address->as_u64[0] == 0 && + src_address->as_u64[1] == 0) + { + rc = VNET_API_ERROR_INVALID_SRC_ADDRESS; + goto out; + } - vec_validate (dm->dhcp6_server_index_by_rx_fib_index, rx_fib_index); - dm->dhcp6_server_index_by_rx_fib_index[rx_fib_index] = - server - dm->dhcp6_servers; + server = dhcpv6_get_server(dm, rx_fib_index); - return 0; + if (NULL != server) + { + /* modify of an existing entry */ + ip6_fib_t *fib; + + fib = ip6_fib_get(server->server_fib6_index); + + if (fib->table_id != server_fib_id) + { + /* swap tables */ + fib_table_unlock(server->server_fib6_index, FIB_PROTOCOL_IP6); + server->server_fib6_index = + ip6_fib_table_find_or_create_and_lock(server_fib_id); + } + } + else + { + /* Allocate a new server */ + pool_get (dm->dhcp6_servers, server); + + vec_validate_init_empty (dm->dhcp6_server_index_by_rx_fib_index, + rx_fib_index, ~0); + dm->dhcp6_server_index_by_rx_fib_index[rx_fib_index] = + server - dm->dhcp6_servers; + + server->server_fib6_index = + ip6_fib_table_find_or_create_and_lock(server_fib_id); + mfib_table_lock(rx_fib_index, FIB_PROTOCOL_IP6); + + const mfib_prefix_t all_dhcp_servers = { + .fp_len = 128, + .fp_proto = FIB_PROTOCOL_IP6, + .fp_grp_addr = { + .ip6 = dm->all_dhcpv6_server_relay_agent_address, + } + }; + const fib_route_path_t path_for_us = { + .frp_proto = FIB_PROTOCOL_IP6, + .frp_addr = zero_addr, + .frp_sw_if_index = 0xffffffff, + .frp_fib_index = ~0, + .frp_weight = 0, + .frp_flags = FIB_ROUTE_PATH_LOCAL, + }; + mfib_table_entry_path_update(rx_fib_index, + &all_dhcp_servers, + MFIB_SOURCE_DHCP, + &path_for_us, + MFIB_ITF_FLAG_FORWARD); + /* + * Each interface that is enabled in this table, needs to be added + * as an accepting interface, but this is not easily doable in VPP. + * So we cheat. Add a flag to the entry that indicates accept form + * any interface. + * We will still only accept on v6 enabled interfaces, since the + * input feature ensures this. + */ + mfib_table_entry_update(rx_fib_index, + &all_dhcp_servers, + MFIB_SOURCE_DHCP, + MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF); + } + copy_ip6_address(&server->dhcp6_server, addr); + copy_ip6_address(&server->dhcp6_src_address, src_address); + } + +out: + mfib_table_unlock(rx_fib_index, FIB_PROTOCOL_IP6); + + return (rc); } static clib_error_t * @@ -910,7 +924,7 @@ dhcpv6_proxy_set_command_fn (vlib_main_t * vm, ip6_address_t addr, src_addr; int set_server = 0, set_src_address = 0; u32 rx_fib_id = 0, server_fib_id = 0; - int is_del = 0, add_vss = 0; + int is_del = 0; while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) { @@ -924,9 +938,6 @@ dhcpv6_proxy_set_command_fn (vlib_main_t * vm, ; else if (unformat (input, "rx-fib-id %d", &rx_fib_id)) ; - else if (unformat (input, "add-vss-option") - || unformat (input, "insert-option")) - add_vss = 1; else if (unformat (input, "delete") || unformat (input, "del")) is_del = 1; @@ -938,8 +949,8 @@ dhcpv6_proxy_set_command_fn (vlib_main_t * vm, { int rv; - rv = dhcpv6_proxy_set_server_2 (&addr, &src_addr, rx_fib_id, - server_fib_id, add_vss, is_del); + rv = dhcpv6_proxy_set_server (&addr, &src_addr, rx_fib_id, + server_fib_id, is_del); //TODO: Complete the errors switch (rv) @@ -962,7 +973,7 @@ dhcpv6_proxy_set_command_fn (vlib_main_t * vm, VLIB_CLI_COMMAND (dhcpv6_proxy_set_command, static) = { .path = "set dhcpv6 proxy", .short_help = "set dhcpv6 proxy [del] server src-address " - "[add-vss-option] [server-fib-id ] [rx-fib-id ] ", + "[server-fib-id ] [rx-fib-id ] ", .function = dhcpv6_proxy_set_command_fn, }; @@ -976,8 +987,8 @@ u8 * format_dhcpv6_proxy_server (u8 * s, va_list * args) if (dm == 0) { - s = format (s, "%=40s%=40s%=14s%=14s%=20s", "Server Address", "Source Address", - "Server FIB", "RX FIB", "Insert VSS Option"); + s = format (s, "%=40s%=40s%=14s%=14s", "Server Address", "Source Address", + "Server FIB", "RX FIB"); return s; } @@ -990,11 +1001,10 @@ u8 * format_dhcpv6_proxy_server (u8 * s, va_list * args) if (rx_fib) rx_fib_id = rx_fib->table_id; - s = format (s, "%=40U%=40U%=14u%=14u%=20s", + s = format (s, "%=40U%=40U%=14u%=14u", format_ip6_address, &server->dhcp6_server, format_ip6_address, &server->dhcp6_src_address, - server_fib_id, rx_fib_id, - server->insert_vss ? "yes" : "no"); + server_fib_id, rx_fib_id); return s; } @@ -1003,25 +1013,25 @@ dhcpv6_proxy_show_command_fn (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { - dhcpv6_proxy_main_t * dm = &dhcpv6_proxy_main; - ip6_main_t * im = &ip6_main; + dhcpv6_proxy_main_t * dpm = &dhcpv6_proxy_main; int i; u32 server_index; dhcpv6_server_t * server; vlib_cli_output (vm, "%U", format_dhcpv6_proxy_server, 0 /* header line */, 0, 0); - for (i = 0; i < vec_len (im->fibs); i++) - { - if (i < vec_len(dm->dhcp6_server_index_by_rx_fib_index)) - server_index = dm->dhcp6_server_index_by_rx_fib_index[i]; - else - server_index = 0; - server = pool_elt_at_index (dm->dhcp6_servers, server_index); - if (server->valid) - vlib_cli_output (vm, "%U", format_dhcpv6_proxy_server, dm, - server, i); - } + vec_foreach_index (i, dpm->dhcp6_server_index_by_rx_fib_index) + { + server_index = dpm->dhcp6_server_index_by_rx_fib_index[i]; + if (~0 == server_index) + continue; + + server = pool_elt_at_index (dpm->dhcp6_servers, server_index); + + vlib_cli_output (vm, "%U", format_dhcpv6_proxy_server, dpm, + server, i); + } + return 0; } @@ -1031,51 +1041,104 @@ VLIB_CLI_COMMAND (dhcpv6_proxy_show_command, static) = { .function = dhcpv6_proxy_show_command_fn, }; +void +dhcpv6_proxy_dump (void *opaque, + u32 context) +{ + dhcpv6_proxy_main_t * dpm = &dhcpv6_proxy_main; + ip6_fib_t *s_fib, *r_fib; + dhcpv6_server_t * server; + u32 server_index, i; + dhcpv6_vss_info *v; + + vec_foreach_index (i, dpm->dhcp6_server_index_by_rx_fib_index) + { + server_index = dpm->dhcp6_server_index_by_rx_fib_index[i]; + if (~0 == server_index) + continue; + + server = pool_elt_at_index (dpm->dhcp6_servers, server_index); + v = dhcpv6_get_vss_info(dpm, i); + + ip46_address_t src_addr = { + .ip6 = server->dhcp6_src_address, + }; + ip46_address_t server_addr = { + .ip6 = server->dhcp6_server, + }; + + s_fib = ip6_fib_get(server->server_fib6_index); + r_fib = ip6_fib_get(i); + + dhcp_send_details(opaque, + context, + &server_addr, + &src_addr, + s_fib->table_id, + r_fib->table_id, + (v ? v->vpn_id.fib_id : 0), + (v ? v->vpn_id.oui : 0)); + } +} + int dhcpv6_proxy_set_vss(u32 tbl_id, u32 oui, u32 fib_id, int is_del) { dhcpv6_proxy_main_t *dm = &dhcpv6_proxy_main; - u32 old_oui, old_fib_id; - uword *p; - dhcpv6_vss_info *v; + dhcpv6_vss_info *v = NULL; + u32 rx_fib_index; + int rc = 0; - p = hash_get (dm->vss_index_by_vrf_id, tbl_id); + rx_fib_index = ip6_fib_table_find_or_create_and_lock(tbl_id); + v = dhcpv6_get_vss_info(dm, rx_fib_index); - if (p) { - v = pool_elt_at_index (dm->vss, p[0]); - if (!v) - return VNET_API_ERROR_NO_SUCH_FIB; - - old_oui = v->vpn_id.oui; - old_fib_id = v->vpn_id.fib_id; + if (NULL != v) + { + if (is_del) + { + /* release the lock held on the table when the VSS + * info was created */ + fib_table_unlock (rx_fib_index, + FIB_PROTOCOL_IP6); + pool_put (dm->vss, v); + dm->vss_index_by_rx_fib_index[rx_fib_index] = ~0; + } + else + { + /* this is a modify */ + v->vpn_id.fib_id = fib_id; + v->vpn_id.oui = oui; + } + } + else + { if (is_del) + rc = VNET_API_ERROR_NO_SUCH_ENTRY; + else { - if (old_oui == oui && - old_fib_id == fib_id ) - { - pool_put(dm->vss, v); - hash_unset (dm->vss_index_by_vrf_id, tbl_id); - return 0; - } - else - return VNET_API_ERROR_NO_SUCH_ENTRY; + /* create a new entry */ + vec_validate_init_empty(dm->vss_index_by_rx_fib_index, + rx_fib_index, ~0); + + /* hold a lock on the table whilst the VSS info exist */ + fib_table_lock (rx_fib_index, + FIB_PROTOCOL_IP6); + + pool_get (dm->vss, v); + v->vpn_id.fib_id = fib_id; + v->vpn_id.oui = oui; + dm->vss_index_by_rx_fib_index[rx_fib_index] = v - dm->vss; } + } - pool_put(dm->vss, v); - hash_unset (dm->vss_index_by_vrf_id, tbl_id); - } else if (is_del) - return VNET_API_ERROR_NO_SUCH_ENTRY; - - pool_get (dm->vss, v); - memset (v, ~0, sizeof (*v)); - v->vpn_id.fib_id = fib_id; - v->vpn_id.oui = oui; - hash_set (dm->vss_index_by_vrf_id, tbl_id, v - dm->vss); + /* Release the lock taken during the create_or_lock at the start */ + fib_table_unlock (rx_fib_index, + FIB_PROTOCOL_IP6); - return 0; + return (rc); } @@ -1147,19 +1210,19 @@ dhcpv6_vss_show_command_fn (vlib_main_t * vm, { dhcpv6_proxy_main_t * dm = &dhcpv6_proxy_main; dhcpv6_vss_info *v; - u32 oui; - u32 fib_id; - u32 tbl_id; - uword index; + ip6_fib_t *fib; + u32 *fib_index; vlib_cli_output (vm, "%=6s%=6s%=12s","Table", "OUI", "VPN ID"); - hash_foreach (tbl_id, index, dm->vss_index_by_vrf_id, + pool_foreach (fib_index, dm->vss_index_by_rx_fib_index, ({ - v = pool_elt_at_index (dm->vss, index); - oui = v->vpn_id.oui; - fib_id = v->vpn_id.fib_id; - vlib_cli_output (vm, "%=6d%=6d%=12d", - tbl_id, oui, fib_id); + fib = ip6_fib_get (*fib_index); + v = pool_elt_at_index (dm->vss, *fib_index); + + vlib_cli_output (vm, "%=6d%=6d%=12d", + fib->table_id, + v->vpn_id.oui, + v->vpn_id.fib_id); })); return 0; diff --git a/src/vnet/dpo/receive_dpo.c b/src/vnet/dpo/receive_dpo.c index 2b2571c6..83e33ed8 100644 --- a/src/vnet/dpo/receive_dpo.c +++ b/src/vnet/dpo/receive_dpo.c @@ -102,6 +102,11 @@ format_receive_dpo (u8 *s, va_list *ap) vnet_main_t * vnm = vnet_get_main(); receive_dpo_t *rd; + if (pool_is_free_index(receive_dpo_pool, index)) + { + return (format(s, "dpo-receive DELETED")); + } + rd = receive_dpo_get(index); if (~0 != rd->rd_sw_if_index) diff --git a/src/vpp/api/custom_dump.c b/src/vpp/api/custom_dump.c index a7dca989..70b4e4c9 100644 --- a/src/vpp/api/custom_dump.c +++ b/src/vpp/api/custom_dump.c @@ -772,37 +772,6 @@ static void *vl_api_dhcp_proxy_config_t_print { u8 *s; - s = format (0, "SCRIPT: dhcp_proxy_config "); - - s = format (s, "vrf_id %d ", ntohl (mp->vrf_id)); - - if (mp->is_ipv6) - { - s = format (s, "svr %U ", format_ip6_address, - (ip6_address_t *) mp->dhcp_server); - s = format (s, "src %U ", format_ip6_address, - (ip6_address_t *) mp->dhcp_src_address); - } - else - { - s = format (s, "svr %U ", format_ip4_address, - (ip4_address_t *) mp->dhcp_server); - s = format (s, "src %U ", format_ip4_address, - (ip4_address_t *) mp->dhcp_src_address); - } - if (mp->is_add == 0) - s = format (s, "del "); - - s = format (s, "insert-cid %d ", mp->insert_circuit_id); - - FINISH; -} - -static void *vl_api_dhcp_proxy_config_2_t_print - (vl_api_dhcp_proxy_config_2_t * mp, void *handle) -{ - u8 *s; - s = format (0, "SCRIPT: dhcp_proxy_config_2 "); s = format (s, "rx_vrf_id %d ", ntohl (mp->rx_vrf_id)); @@ -825,8 +794,6 @@ static void *vl_api_dhcp_proxy_config_2_t_print if (mp->is_add == 0) s = format (s, "del "); - s = format (s, "insert-cid %d ", mp->insert_circuit_id); - FINISH; } @@ -2954,7 +2921,6 @@ _(BRIDGE_DOMAIN_DUMP, bridge_domain_dump) \ _(CLASSIFY_SET_INTERFACE_IP_TABLE, classify_set_interface_ip_table) \ _(CLASSIFY_SET_INTERFACE_L2_TABLES, classify_set_interface_l2_tables) \ _(ADD_NODE_NEXT, add_node_next) \ -_(DHCP_PROXY_CONFIG_2, dhcp_proxy_config_2) \ _(DHCP_CLIENT_CONFIG, dhcp_client_config) \ _(L2TPV3_CREATE_TUNNEL, l2tpv3_create_tunnel) \ _(L2TPV3_SET_TUNNEL_COOKIES, l2tpv3_set_tunnel_cookies) \ diff --git a/test/test_dhcp.py b/test/test_dhcp.py index 04ab2e11..fbfb8a0c 100644 --- a/test/test_dhcp.py +++ b/test/test_dhcp.py @@ -65,7 +65,7 @@ class TestDHCP(VppTestCase): for i in self.pg_interfaces: i.assert_nothing_captured(remark=remark) - def validate_option_82(self, pkt, intf, ip_addr): + def validate_relay_options(self, pkt, intf, ip_addr, fib_id, oui): dhcp = pkt[DHCP] found = 0 data = [] @@ -77,7 +77,10 @@ class TestDHCP(VppTestCase): # There are two sb-options present - each of length 6. # data = i[1] - self.assertEqual(len(data), 12) + if oui != 0: + self.assertEqual(len(data), 24) + else: + self.assertEqual(len(data), 12) # # First sub-option is ID 1, len 4, then encoded @@ -107,12 +110,30 @@ class TestDHCP(VppTestCase): self.assertEqual(data[10], claddr[2]) self.assertEqual(data[11], claddr[3]) + if oui != 0: + # sub-option 151 encodes the 3 byte oui + # and the 4 byte fib_id + self.assertEqual(ord(data[12]), 151) + self.assertEqual(ord(data[13]), 8) + self.assertEqual(ord(data[14]), 1) + self.assertEqual(ord(data[15]), 0) + self.assertEqual(ord(data[16]), 0) + self.assertEqual(ord(data[17]), oui) + self.assertEqual(ord(data[18]), 0) + self.assertEqual(ord(data[19]), 0) + self.assertEqual(ord(data[20]), 0) + self.assertEqual(ord(data[21]), fib_id) + + # VSS control sub-option + self.assertEqual(ord(data[22]), 152) + self.assertEqual(ord(data[23]), 0) + found = 1 self.assertTrue(found) return data - def verify_dhcp_offer(self, pkt, intf, check_option_82=True): + def verify_dhcp_offer(self, pkt, intf): ether = pkt[Ether] self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff") self.assertEqual(ether.src, intf.local_mac) @@ -134,11 +155,9 @@ class TestDHCP(VppTestCase): is_offer = True self.assertTrue(is_offer) - if check_option_82: - data = self.validate_option_82(pkt, intf, intf.local_ip4) + data = self.validate_relay_options(pkt, intf, intf.local_ip4, 0, 0) - def verify_dhcp_discover(self, pkt, intf, src_intf=None, - option_82_present=True): + def verify_dhcp_discover(self, pkt, intf, src_intf=None, fib_id=0, oui=0): ether = pkt[Ether] self.assertEqual(ether.dst, intf.remote_mac) self.assertEqual(ether.src, intf.local_mac) @@ -161,13 +180,10 @@ class TestDHCP(VppTestCase): is_discover = True self.assertTrue(is_discover) - if option_82_present: - data = self.validate_option_82(pkt, src_intf, src_intf.local_ip4) - return data - else: - for i in dhcp.options: - if type(i) is tuple: - self.assertNotEqual(i[0], "relay_agent_Information") + data = self.validate_relay_options(pkt, src_intf, + src_intf.local_ip4, + fib_id, oui) + return data def verify_dhcp6_solicit(self, pkt, intf, peer_ip, peer_mac, @@ -193,18 +209,19 @@ class TestDHCP(VppTestCase): self.assertEqual(cll.lltype, 1) self.assertEqual(cll.clladdr, peer_mac) - vss = pkt[DHCP6OptVSS] - self.assertEqual(vss.optlen, 8) - self.assertEqual(vss.type, 1) - # the OUI and FIB-id are really 3 and 4 bytes resp. - # but the tested range is small - self.assertEqual(ord(vss.data[0]), 0) - self.assertEqual(ord(vss.data[1]), 0) - self.assertEqual(ord(vss.data[2]), oui) - self.assertEqual(ord(vss.data[3]), 0) - self.assertEqual(ord(vss.data[4]), 0) - self.assertEqual(ord(vss.data[5]), 0) - self.assertEqual(ord(vss.data[6]), fib_id) + if fib_id != 0: + vss = pkt[DHCP6OptVSS] + self.assertEqual(vss.optlen, 8) + self.assertEqual(vss.type, 1) + # the OUI and FIB-id are really 3 and 4 bytes resp. + # but the tested range is small + self.assertEqual(ord(vss.data[0]), 0) + self.assertEqual(ord(vss.data[1]), 0) + self.assertEqual(ord(vss.data[2]), oui) + self.assertEqual(ord(vss.data[3]), 0) + self.assertEqual(ord(vss.data[4]), 0) + self.assertEqual(ord(vss.data[5]), 0) + self.assertEqual(ord(vss.data[6]), fib_id) # the relay message should be an encoded Solicit msg = pkt[DHCP6OptRelayMsg] @@ -267,29 +284,16 @@ class TestDHCP(VppTestCase): rx_table_id=0) # - # Now a DHCP request on pg2, which is in the same VRF - # as the DHCP config, will result in a relayed DHCP - # message to the [fake] server - # - self.pg2.add_stream(pkts_disc_vrf0) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - rx = self.pg0.get_capture(1) - rx = rx[0] - - # - # Rx'd packet should be to the server address and from the configured - # source address - # UDP source ports are unchanged - # we've no option 82 config so that should be absent + # Discover packets from the client are dropped because there is no + # IP address configured on the client facing interface # - self.verify_dhcp_discover(rx, self.pg0, option_82_present=False) + self.send_and_assert_no_replies(self.pg2, pkts_disc_vrf0, + "Discover DHCP no relay address") # # Inject a response from the server - # VPP will only relay the offer if option 82 is present. - # so this one is dropped + # dropped, because there is no IP addrees on the + # clinet interfce to fill in the option. # p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) / @@ -298,24 +302,8 @@ class TestDHCP(VppTestCase): DHCP(options=[('message-type', 'offer'), ('end')])) pkts = [p] - self.send_and_assert_no_replies(self.pg0, pkts, - "DHCP offer no option 82") - - # - # Configure sending option 82 in relayed messages - # - self.vapi.dhcp_proxy_config(server_addr, - src_addr, - rx_table_id=0, - insert_circuit_id=1) - - # - # Send a request: - # again dropped, but ths time because there is no IP addrees on the - # clinet interfce to fill in the option. - # - self.send_and_assert_no_replies(self.pg2, pkts_disc_vrf0, - "DHCP no relay address") + self.send_and_assert_no_replies(self.pg2, pkts, + "Offer DHCP no relay address") # # configure an IP address on the client facing interface @@ -376,15 +364,8 @@ class TestDHCP(VppTestCase): ('relay_agent_Information', bad_ip), ('end')])) pkts = [p] - - self.pg0.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - rx = self.pg2.get_capture(1) - rx = rx[0] - - self.verify_dhcp_offer(rx, self.pg2, check_option_82=False) - self.pg0.assert_nothing_captured(remark="") + self.send_and_assert_no_replies(self.pg0, pkts, + "DHCP offer option 82 bad address") # 2. Not a sw_if_index VPP knows bad_if_index = option_82[0:2] + chr(33) + option_82[3:] @@ -413,8 +394,7 @@ class TestDHCP(VppTestCase): self.vapi.dhcp_proxy_config(server_addr, src_addr, rx_table_id=0, - is_add=0, - insert_circuit_id=1) + is_add=0) self.send_and_assert_no_replies(self.pg2, pkts_disc_vrf0, "DHCP config removed VRF 0") @@ -429,8 +409,7 @@ class TestDHCP(VppTestCase): self.vapi.dhcp_proxy_config(server_addr, src_addr, rx_table_id=1, - server_table_id=1, - insert_circuit_id=1) + server_table_id=1) # # Confim DHCP requests ok in VRF 1. @@ -452,14 +431,41 @@ class TestDHCP(VppTestCase): rx = rx[0] self.verify_dhcp_discover(rx, self.pg1, src_intf=self.pg3) + # + # Add VSS config + # table=1, fib=id=1, oui=4 + self.vapi.dhcp_proxy_set_vss(1, 1, 4) + + self.pg3.add_stream(pkts_disc_vrf1) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg1.get_capture(1) + rx = rx[0] + self.verify_dhcp_discover(rx, self.pg1, src_intf=self.pg3, + fib_id=1, oui=4) + + # + # Remove the VSS config + # relayed DHCP has default vlaues in the option. + # + self.vapi.dhcp_proxy_set_vss(1, 1, 4, is_add=0) + + self.pg3.add_stream(pkts_disc_vrf1) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg1.get_capture(1) + rx = rx[0] + self.verify_dhcp_discover(rx, self.pg1, src_intf=self.pg3) + # # remove DHCP config to cleanup # self.vapi.dhcp_proxy_config(server_addr, src_addr, rx_table_id=1, - server_table_id=1, - insert_circuit_id=1, + server_table_id=11, is_add=0) self.send_and_assert_no_replies(self.pg2, pkts_disc_vrf0, @@ -510,7 +516,6 @@ class TestDHCP(VppTestCase): src_addr_vrf0, rx_table_id=0, server_table_id=0, - insert_circuit_id=1, is_ipv6=1) self.send_and_assert_no_replies(self.pg2, pkts_solicit_vrf0, @@ -630,7 +635,6 @@ class TestDHCP(VppTestCase): src_addr_vrf1, rx_table_id=1, server_table_id=1, - insert_circuit_id=1, is_ipv6=1) self.pg3.config_ip6() @@ -708,14 +712,12 @@ class TestDHCP(VppTestCase): src_addr_vrf1, rx_table_id=1, server_table_id=1, - insert_circuit_id=1, is_ipv6=1, is_add=0) self.vapi.dhcp_proxy_config(server_addr_vrf1, src_addr_vrf1, rx_table_id=0, server_table_id=0, - insert_circuit_id=1, is_ipv6=1, is_add=0) diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py index 32680424..59e58ad0 100644 --- a/test/vpp_papi_provider.py +++ b/test/vpp_papi_provider.py @@ -1240,16 +1240,14 @@ class VppPapiProvider(object): rx_table_id=0, server_table_id=0, is_add=1, - is_ipv6=0, - insert_circuit_id=0): + is_ipv6=0): return self.api( - self.papi.dhcp_proxy_config_2, + self.papi.dhcp_proxy_config, { 'rx_vrf_id': rx_table_id, 'server_vrf_id': server_table_id, 'is_ipv6': is_ipv6, 'is_add': is_add, - 'insert_circuit_id': insert_circuit_id, 'dhcp_server': dhcp_server, 'dhcp_src_address': dhcp_src_address, }) -- cgit 1.2.3-korg From 2dd6852d8109e39d15a5c60f7ba58f1abcf9e455 Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Thu, 16 Feb 2017 03:38:59 -0800 Subject: Consolidate DHCP v4 and V6 implementation. No functional change intended The DHCP proxy and VSS information maintained by VPP is the same for v4 and v6, so we can manage this state using the same code. Packet handling is cleary different, so this is kept separate. Change-Id: I10f10cc1f7f19debcd4c4b099c6de64e56bb0c69 Signed-off-by: Neale Ranns --- src/vnet.am | 26 +- src/vnet/dhcp/client.c | 2 +- src/vnet/dhcp/client.h | 2 +- src/vnet/dhcp/dhcp4_packet.h | 61 ++ src/vnet/dhcp/dhcp4_proxy_error.def | 32 + src/vnet/dhcp/dhcp4_proxy_node.c | 983 +++++++++++++++++++++++++++ src/vnet/dhcp/dhcp6_packet.h | 183 +++++ src/vnet/dhcp/dhcp6_proxy_error.def | 29 + src/vnet/dhcp/dhcp6_proxy_node.c | 1065 +++++++++++++++++++++++++++++ src/vnet/dhcp/dhcp_api.c | 95 ++- src/vnet/dhcp/dhcp_proxy.c | 275 ++++++++ src/vnet/dhcp/dhcp_proxy.h | 248 +++++++ src/vnet/dhcp/packet.h | 61 -- src/vnet/dhcp/proxy.h | 99 --- src/vnet/dhcp/proxy_error.def | 31 - src/vnet/dhcp/proxy_node.c | 1192 -------------------------------- src/vnet/dhcpv6/packet.h | 183 ----- src/vnet/dhcpv6/proxy.h | 94 --- src/vnet/dhcpv6/proxy_error.def | 29 - src/vnet/dhcpv6/proxy_node.c | 1280 ----------------------------------- src/vpp/api/custom_dump.c | 3 +- test/test_dhcp.py | 2 +- 22 files changed, 2933 insertions(+), 3042 deletions(-) create mode 100644 src/vnet/dhcp/dhcp4_packet.h create mode 100644 src/vnet/dhcp/dhcp4_proxy_error.def create mode 100644 src/vnet/dhcp/dhcp4_proxy_node.c create mode 100644 src/vnet/dhcp/dhcp6_packet.h create mode 100644 src/vnet/dhcp/dhcp6_proxy_error.def create mode 100644 src/vnet/dhcp/dhcp6_proxy_node.c create mode 100644 src/vnet/dhcp/dhcp_proxy.c create mode 100644 src/vnet/dhcp/dhcp_proxy.h delete mode 100644 src/vnet/dhcp/packet.h delete mode 100644 src/vnet/dhcp/proxy.h delete mode 100644 src/vnet/dhcp/proxy_error.def delete mode 100644 src/vnet/dhcp/proxy_node.c delete mode 100644 src/vnet/dhcpv6/packet.h delete mode 100644 src/vnet/dhcpv6/proxy.h delete mode 100644 src/vnet/dhcpv6/proxy_error.def delete mode 100644 src/vnet/dhcpv6/proxy_node.c (limited to 'src/vnet/dhcp/client.c') diff --git a/src/vnet.am b/src/vnet.am index 70f1e7e9..64484e18 100644 --- a/src/vnet.am +++ b/src/vnet.am @@ -674,7 +674,7 @@ libvnet_la_SOURCES += \ vnet/dhcp/dhcp_api.c nobase_include_HEADERS += \ - vnet/dhcp/client.h \ + vnet/dhcp/client.h \ vnet/dhcp/dhcp.api.h API_FILES += vnet/dhcp/dhcp.api @@ -683,13 +683,16 @@ API_FILES += vnet/dhcp/dhcp.api # DHCP proxy ######################################## libvnet_la_SOURCES += \ - vnet/dhcp/proxy_node.c \ - vnet/dhcp/proxy.h + vnet/dhcp/dhcp6_proxy_node.c \ + vnet/dhcp/dhcp4_proxy_node.c \ + vnet/dhcp/dhcp_proxy.c nobase_include_HEADERS += \ - vnet/dhcp/packet.h \ - vnet/dhcp/proxy.h \ - vnet/dhcp/proxy_error.def + vnet/dhcp/dhcp4_packet.h \ + vnet/dhcp/dhcp6_packet.h \ + vnet/dhcp/dhcp_proxy.h \ + vnet/dhcp/dhcp6_proxy_error.def \ + vnet/dhcp/dhcp4_proxy_error.def ######################################## # ipv6 segment routing @@ -709,17 +712,6 @@ nobase_include_HEADERS += \ API_FILES += vnet/sr/sr.api -######################################## -# DHCPv6 proxy -######################################## -libvnet_la_SOURCES += \ - vnet/dhcpv6/proxy_node.c - -nobase_include_HEADERS += \ - vnet/dhcpv6/packet.h \ - vnet/dhcpv6/proxy.h \ - vnet/dhcpv6/proxy_error.def - ######################################## # IPFIX / netflow v10 ######################################## diff --git a/src/vnet/dhcp/client.c b/src/vnet/dhcp/client.c index 8a1a43b3..d34c5a64 100644 --- a/src/vnet/dhcp/client.c +++ b/src/vnet/dhcp/client.c @@ -14,7 +14,7 @@ */ #include #include -#include +#include #include dhcp_client_main_t dhcp_client_main; diff --git a/src/vnet/dhcp/client.h b/src/vnet/dhcp/client.h index a74368cb..1f85d7ce 100644 --- a/src/vnet/dhcp/client.h +++ b/src/vnet/dhcp/client.h @@ -20,7 +20,7 @@ #define included_dhcp_client_h #include -#include +#include #define foreach_dhcp_client_state \ _(DHCP_DISCOVER) \ diff --git a/src/vnet/dhcp/dhcp4_packet.h b/src/vnet/dhcp/dhcp4_packet.h new file mode 100644 index 00000000..28c4b156 --- /dev/null +++ b/src/vnet/dhcp/dhcp4_packet.h @@ -0,0 +1,61 @@ +#ifndef included_vnet_dhcp4_packet_h +#define included_vnet_dhcp4_packet_h + +/* + * DHCP packet format + * + * Copyright (c) 2013 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include + +typedef struct { + u8 opcode; /* 1 = request, 2 = reply */ + u8 hardware_type; /* 1 = ethernet */ + u8 hardware_address_length; + u8 hops; + u32 transaction_identifier; + u16 seconds; + u16 flags; +#define DHCP_FLAG_BROADCAST (1<<15) + ip4_address_t client_ip_address; + ip4_address_t your_ip_address; /* use this one */ + ip4_address_t server_ip_address; + ip4_address_t gateway_ip_address; /* use option 3, not this one */ + u8 client_hardware_address[16]; + u8 server_name[64]; + u8 boot_filename[128]; + ip4_address_t magic_cookie; + u8 options[0]; +} dhcp_header_t; + +typedef struct { + u8 option; + u8 length; + union { + u8 data[0]; + u32 data_as_u32[0]; + }; +} __attribute__((packed)) dhcp_option_t; + +typedef enum { + DHCP_PACKET_DISCOVER=1, + DHCP_PACKET_OFFER, + DHCP_PACKET_REQUEST, + DHCP_PACKET_ACK=5, +} dhcp_packet_type_t; + +/* charming antique: 99.130.83.99 is the dhcp magic cookie */ +#define DHCP_MAGIC (clib_host_to_net_u32(0x63825363)) + +#endif /* included_vnet_dhcp4_packet_h */ diff --git a/src/vnet/dhcp/dhcp4_proxy_error.def b/src/vnet/dhcp/dhcp4_proxy_error.def new file mode 100644 index 00000000..adf04808 --- /dev/null +++ b/src/vnet/dhcp/dhcp4_proxy_error.def @@ -0,0 +1,32 @@ +/* + * dhcp_proxy_error.def: dhcp proxy errors + * + * Copyright (c) 2013 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +dhcp_proxy_error (NONE, "no error") +dhcp_proxy_error (NO_SERVER, "no dhcp server configured") +dhcp_proxy_error (RELAY_TO_SERVER, "DHCP packets relayed to the server") +dhcp_proxy_error (RELAY_TO_CLIENT, "DHCP packets relayed to clients") +dhcp_proxy_error (OPTION_82_ERROR, "DHCP failed to insert option 82") +dhcp_proxy_error (NO_OPTION_82, "DHCP option 82 missing") +dhcp_proxy_error (BAD_OPTION_82_ITF, "Bad DHCP option 82 interface value") +dhcp_proxy_error (BAD_OPTION_82_ADDR, "Bad DHCP option 82 address value") +dhcp_proxy_error (BAD_FIB_ID, "DHCP option 82 fib-id to fib-index map failure") +dhcp_proxy_error (NO_INTERFACE_ADDRESS, "DHCP no interface address") +dhcp_proxy_error (OPTION_82_VSS_NOT_PROCESSED, "DHCP VSS not processed by DHCP server") +dhcp_proxy_error (BAD_YIADDR, "DHCP packets with bad your_ip_address fields") +dhcp_proxy_error (BAD_SVR_FIB_OR_ADDRESS, "DHCP packets not from DHCP server or server FIB.") +dhcp_proxy_error (PKT_TOO_BIG, "DHCP packets which are too big.") + diff --git a/src/vnet/dhcp/dhcp4_proxy_node.c b/src/vnet/dhcp/dhcp4_proxy_node.c new file mode 100644 index 00000000..88a99249 --- /dev/null +++ b/src/vnet/dhcp/dhcp4_proxy_node.c @@ -0,0 +1,983 @@ +/* + * proxy_node.c: dhcp proxy node processing + * + * Copyright (c) 2013 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +static char * dhcp_proxy_error_strings[] = { +#define dhcp_proxy_error(n,s) s, +#include +#undef dhcp_proxy_error +}; + +#define foreach_dhcp_proxy_to_server_input_next \ + _ (DROP, "error-drop") \ + _ (LOOKUP, "ip4-lookup") \ + _ (SEND_TO_CLIENT, "dhcp-proxy-to-client") + +typedef enum { +#define _(s,n) DHCP_PROXY_TO_SERVER_INPUT_NEXT_##s, + foreach_dhcp_proxy_to_server_input_next +#undef _ + DHCP_PROXY_TO_SERVER_INPUT_N_NEXT, +} dhcp_proxy_to_server_input_next_t; + +typedef struct { + /* 0 => to server, 1 => to client */ + int which; + ip4_address_t trace_ip4_address; + u32 error; + u32 sw_if_index; + u32 original_sw_if_index; +} dhcp_proxy_trace_t; + +#define VPP_DHCP_OPTION82_SUB1_SIZE 6 +#define VPP_DHCP_OPTION82_SUB5_SIZE 6 +#define VPP_DHCP_OPTION82_VSS_SIZE 12 +#define VPP_DHCP_OPTION82_SIZE (VPP_DHCP_OPTION82_SUB1_SIZE + \ + VPP_DHCP_OPTION82_SUB5_SIZE + \ + VPP_DHCP_OPTION82_VSS_SIZE +3) + +static vlib_node_registration_t dhcp_proxy_to_server_node; +static vlib_node_registration_t dhcp_proxy_to_client_node; + +static u8 * +format_dhcp_proxy_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + dhcp_proxy_trace_t * t = va_arg (*args, dhcp_proxy_trace_t *); + + if (t->which == 0) + s = format (s, "DHCP proxy: sent to server %U\n", + format_ip4_address, &t->trace_ip4_address, t->error); + else + s = format (s, "DHCP proxy: broadcast to client from %U\n", + format_ip4_address, &t->trace_ip4_address); + + if (t->error != (u32)~0) + s = format (s, " error: %s\n", dhcp_proxy_error_strings[t->error]); + + s = format (s, " original_sw_if_index: %d, sw_if_index: %d\n", + t->original_sw_if_index, t->sw_if_index); + + return s; +} + +static u8 * +format_dhcp_proxy_header_with_length (u8 * s, va_list * args) +{ + dhcp_header_t * h = va_arg (*args, dhcp_header_t *); + u32 max_header_bytes = va_arg (*args, u32); + u32 header_bytes; + + header_bytes = sizeof (h[0]); + if (max_header_bytes != 0 && header_bytes > max_header_bytes) + return format (s, "dhcp header truncated"); + + s = format (s, "DHCP Proxy"); + + return s; +} + +static uword +dhcp_proxy_to_server_input (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * from_frame) +{ + u32 n_left_from, next_index, * from, * to_next; + dhcp_proxy_main_t * dpm = &dhcp_proxy_main; + from = vlib_frame_vector_args (from_frame); + n_left_from = from_frame->n_vectors; + u32 pkts_to_server=0, pkts_to_client=0, pkts_no_server=0; + u32 pkts_no_interface_address=0; + u32 pkts_too_big=0; + ip4_main_t * im = &ip4_main; + + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + 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) + { + u32 bi0; + vlib_buffer_t * b0; + udp_header_t * u0; + dhcp_header_t * h0; + ip4_header_t * ip0; + u32 next0; + u32 old0, new0; + ip_csum_t sum0; + u32 error0 = (u32) ~0; + u32 sw_if_index = 0; + u32 original_sw_if_index = 0; + u8 *end = NULL; + u32 fib_index; + dhcp_server_t * server; + u32 rx_sw_if_index; + dhcp_option_t *o; + u32 len = 0; + vlib_buffer_free_list_t *fl; + + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + + b0 = vlib_get_buffer (vm, bi0); + + h0 = vlib_buffer_get_current (b0); + + /* + * udp_local hands us the DHCP header, need udp hdr, + * ip hdr to relay to server + */ + vlib_buffer_advance (b0, -(sizeof(*u0))); + u0 = vlib_buffer_get_current (b0); + + /* This blows. Return traffic has src_port = 67, dst_port = 67 */ + if (u0->src_port == clib_net_to_host_u16(UDP_DST_PORT_dhcp_to_server)) + { + vlib_buffer_advance (b0, sizeof(*u0)); + next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_SEND_TO_CLIENT; + error0 = 0; + pkts_to_client++; + goto do_enqueue; + } + + rx_sw_if_index = vnet_buffer(b0)->sw_if_index[VLIB_RX]; + + fib_index = im->fib_index_by_sw_if_index [rx_sw_if_index]; + server = dhcp_get_server(dpm, fib_index, FIB_PROTOCOL_IP4); + + if (PREDICT_FALSE (NULL == server)) + { + error0 = DHCP_PROXY_ERROR_NO_SERVER; + next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_DROP; + pkts_no_server++; + goto do_trace; + } + + vlib_buffer_advance (b0, -(sizeof(*ip0))); + ip0 = vlib_buffer_get_current (b0); + + /* disable UDP checksum */ + u0->checksum = 0; + sum0 = ip0->checksum; + old0 = ip0->dst_address.as_u32; + new0 = server->dhcp_server.ip4.as_u32; + ip0->dst_address.as_u32 = server->dhcp_server.ip4.as_u32; + sum0 = ip_csum_update (sum0, old0, new0, + ip4_header_t /* structure */, + dst_address /* changed member */); + ip0->checksum = ip_csum_fold (sum0); + + sum0 = ip0->checksum; + old0 = ip0->src_address.as_u32; + new0 = server->dhcp_src_address.ip4.as_u32; + ip0->src_address.as_u32 = new0; + sum0 = ip_csum_update (sum0, old0, new0, + ip4_header_t /* structure */, + src_address /* changed member */); + ip0->checksum = ip_csum_fold (sum0); + + /* Send to DHCP server via the configured FIB */ + vnet_buffer(b0)->sw_if_index[VLIB_TX] = + server->server_fib_index; + + h0->gateway_ip_address.as_u32 = server->dhcp_src_address.ip4.as_u32; + pkts_to_server++; + + o = (dhcp_option_t *) h0->options; + + fib_index = im->fib_index_by_sw_if_index + [vnet_buffer(b0)->sw_if_index[VLIB_RX]]; + + end = b0->data + b0->current_data + b0->current_length; + /* TLVs are not performance-friendly... */ + while (o->option != 0xFF /* end of options */ && (u8 *)o < end) + o = (dhcp_option_t *) (((uword) o) + (o->length + 2)); + + fl = vlib_buffer_get_free_list (vm, b0->free_list_index); + // start write at (option*)o, some packets have padding + if (((u8 *)o - (u8 *)b0->data + VPP_DHCP_OPTION82_SIZE) > fl->n_data_bytes) + { + next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_DROP; + pkts_too_big++; + goto do_trace; + } + + if ((o->option == 0xFF) && ((u8 *)o <= end)) + { + vnet_main_t *vnm = vnet_get_main(); + u16 old_l0, new_l0; + ip4_address_t _ia0, * ia0 = &_ia0; + dhcp_vss_t *vss; + vnet_sw_interface_t *swif; + sw_if_index = 0; + original_sw_if_index = 0; + + original_sw_if_index = sw_if_index = + vnet_buffer(b0)->sw_if_index[VLIB_RX]; + swif = vnet_get_sw_interface (vnm, sw_if_index); + if (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED) + sw_if_index = swif->unnumbered_sw_if_index; + + /* + * Get the first ip4 address on the [client-side] + * RX interface, if not unnumbered. otherwise use + * the loopback interface's ip address. + */ + ia0 = ip4_interface_first_address(&ip4_main, sw_if_index, 0); + + if (ia0 == 0) + { + error0 = DHCP_PROXY_ERROR_NO_INTERFACE_ADDRESS; + next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_DROP; + pkts_no_interface_address++; + goto do_trace; + } + + /* Add option 82 */ + o->option = 82; /* option 82 */ + o->length = 12; /* 12 octets to follow */ + o->data[0] = 1; /* suboption 1, circuit ID (=FIB id) */ + o->data[1] = 4; /* length of suboption */ + o->data[2] = (original_sw_if_index >> 24) & 0xFF; + o->data[3] = (original_sw_if_index >> 16) & 0xFF; + o->data[4] = (original_sw_if_index >> 8) & 0xFF; + o->data[5] = (original_sw_if_index >> 0) & 0xFF; + o->data[6] = 5; /* suboption 5 (client RX intfc address) */ + o->data[7] = 4; /* length 4 */ + o->data[8] = ia0->as_u8[0]; + o->data[9] = ia0->as_u8[1]; + o->data[10] = ia0->as_u8[2]; + o->data[11] = ia0->as_u8[3]; + o->data[12] = 0xFF; + + vss = dhcp_get_vss_info (dpm, fib_index, FIB_PROTOCOL_IP4); + if (NULL != vss) + { + u32 opt82_fib_id=0, opt82_oui=0; + + opt82_oui = vss->oui; + opt82_fib_id = vss->fib_id; + + o->data[12] = 151; /* vss suboption */ + if (255 == opt82_fib_id) { + o->data[13] = 1; /* length */ + o->data[14] = 255; /* vss option type */ + o->data[15] = 152; /* vss control suboption */ + o->data[16] = 0; /* length */ + /* and a new "end-of-options" option (0xff) */ + o->data[17] = 0xFF; + o->length += 5; + } else { + o->data[13] = 8; /* length */ + o->data[14] = 1; /* vss option type */ + o->data[15] = (opt82_oui >> 16) & 0xff; + o->data[16] = (opt82_oui >> 8) & 0xff; + o->data[17] = (opt82_oui ) & 0xff; + o->data[18] = (opt82_fib_id >> 24) & 0xff; + o->data[19] = (opt82_fib_id >> 16) & 0xff; + o->data[20] = (opt82_fib_id >> 8) & 0xff; + o->data[21] = (opt82_fib_id) & 0xff; + o->data[22] = 152; /* vss control suboption */ + o->data[23] = 0; /* length */ + + /* and a new "end-of-options" option (0xff) */ + o->data[24] = 0xFF; + o->length += 12; + } + } + + len = o->length + 3; + b0->current_length += len; + /* Fix IP header length and checksum */ + old_l0 = ip0->length; + new_l0 = clib_net_to_host_u16 (old_l0); + new_l0 += len; + new_l0 = clib_host_to_net_u16 (new_l0); + ip0->length = new_l0; + sum0 = ip0->checksum; + sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t, + length /* changed member */); + ip0->checksum = ip_csum_fold (sum0); + + /* Fix UDP length */ + new_l0 = clib_net_to_host_u16 (u0->length); + new_l0 += len; + u0->length = clib_host_to_net_u16 (new_l0); + } else { + vlib_node_increment_counter + (vm, dhcp_proxy_to_server_node.index, + DHCP_PROXY_ERROR_OPTION_82_ERROR, 1); + } + + next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP; + + do_trace: + if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) + { + dhcp_proxy_trace_t *tr = vlib_add_trace (vm, node, + b0, sizeof (*tr)); + tr->which = 0; /* to server */ + tr->error = error0; + tr->original_sw_if_index = original_sw_if_index; + tr->sw_if_index = sw_if_index; + if (next0 == DHCP_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP) + tr->trace_ip4_address.as_u32 = server->dhcp_server.ip4.as_u32; + } + + do_enqueue: + 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); + } + + vlib_node_increment_counter (vm, dhcp_proxy_to_server_node.index, + DHCP_PROXY_ERROR_RELAY_TO_CLIENT, + pkts_to_client); + vlib_node_increment_counter (vm, dhcp_proxy_to_server_node.index, + DHCP_PROXY_ERROR_RELAY_TO_SERVER, + pkts_to_server); + vlib_node_increment_counter (vm, dhcp_proxy_to_server_node.index, + DHCP_PROXY_ERROR_NO_SERVER, + pkts_no_server); + vlib_node_increment_counter (vm, dhcp_proxy_to_server_node.index, + DHCP_PROXY_ERROR_NO_INTERFACE_ADDRESS, + pkts_no_interface_address); + vlib_node_increment_counter (vm, dhcp_proxy_to_server_node.index, + DHCP_PROXY_ERROR_PKT_TOO_BIG, + pkts_too_big); + return from_frame->n_vectors; +} + +VLIB_REGISTER_NODE (dhcp_proxy_to_server_node, static) = { + .function = dhcp_proxy_to_server_input, + .name = "dhcp-proxy-to-server", + /* Takes a vector of packets. */ + .vector_size = sizeof (u32), + + .n_errors = DHCP_PROXY_N_ERROR, + .error_strings = dhcp_proxy_error_strings, + + .n_next_nodes = DHCP_PROXY_TO_SERVER_INPUT_N_NEXT, + .next_nodes = { +#define _(s,n) [DHCP_PROXY_TO_SERVER_INPUT_NEXT_##s] = n, + foreach_dhcp_proxy_to_server_input_next +#undef _ + }, + + .format_buffer = format_dhcp_proxy_header_with_length, + .format_trace = format_dhcp_proxy_trace, +#if 0 + .unformat_buffer = unformat_dhcp_proxy_header, +#endif +}; + +static uword +dhcp_proxy_to_client_input (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * from_frame) +{ + u32 n_left_from, * from; + ethernet_main_t *em = ethernet_get_main (vm); + dhcp_proxy_main_t * dpm = &dhcp_proxy_main; + vnet_main_t * vnm = vnet_get_main(); + ip4_main_t * im = &ip4_main; + + from = vlib_frame_vector_args (from_frame); + n_left_from = from_frame->n_vectors; + + while (n_left_from > 0) + { + u32 bi0; + vlib_buffer_t * b0; + udp_header_t * u0; + dhcp_header_t * h0; + ip4_header_t * ip0 = 0; + ip4_address_t * ia0 = 0; + u32 old0, new0; + ip_csum_t sum0; + 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; + vnet_sw_interface_t *si0; + u32 error0 = (u32)~0; + vnet_sw_interface_t *swif; + u32 fib_index; + dhcp_server_t * server; + u32 original_sw_if_index = (u32) ~0; + ip4_address_t relay_addr = { + .as_u32 = 0, + }; + + bi0 = from[0]; + from += 1; + n_left_from -= 1; + + b0 = vlib_get_buffer (vm, bi0); + h0 = vlib_buffer_get_current (b0); + + /* + * udp_local hands us the DHCP header, need udp hdr, + * ip hdr to relay to client + */ + vlib_buffer_advance (b0, -(sizeof(*u0))); + u0 = vlib_buffer_get_current (b0); + + vlib_buffer_advance (b0, -(sizeof(*ip0))); + ip0 = vlib_buffer_get_current (b0); + + /* Consumed by dhcp client code? */ + if (dhcp_client_for_us (bi0, b0, ip0, u0, h0)) + continue; + + if (1 /* dpm->insert_option_82 */) + { + dhcp_option_t *o = (dhcp_option_t *) h0->options; + dhcp_option_t *sub; + + /* Parse through TLVs looking for option 82. + The circuit-ID is the FIB number we need + to track down the client-facing interface */ + + while (o->option != 0xFF /* end of options */ && + (u8 *) o < (b0->data + b0->current_data + b0->current_length)) + { + if (o->option == 82) + { + u32 vss_exist = 0; + u32 vss_ctrl = 0; + sub = (dhcp_option_t *) &o->data[0]; + while (sub->option != 0xFF /* end of options */ && + (u8 *) sub < (u8 *)(o + o->length)) { + /* If this is one of ours, it will have + total length 12, circuit-id suboption type, + and the sw_if_index */ + if (sub->option == 1 && sub->length == 4) + { + sw_if_index = ((sub->data[0] << 24) | + (sub->data[1] << 16) | + (sub->data[2] << 8) | + (sub->data[3])); + } + else if (sub->option == 5 && sub->length == 4) + { + relay_addr.as_u8[0] = sub->data[0]; + relay_addr.as_u8[1] = sub->data[1]; + relay_addr.as_u8[2] = sub->data[2]; + relay_addr.as_u8[3] = sub->data[3]; + } + else if (sub->option == 151 && + sub->length == 7 && + sub->data[0] == 1) + vss_exist = 1; + else if (sub->option == 152 && sub->length == 0) + vss_ctrl = 1; + sub = (dhcp_option_t *) + (((uword) sub) + (sub->length + 2)); + } + if (vss_ctrl && vss_exist) + vlib_node_increment_counter + (vm, dhcp_proxy_to_client_node.index, + DHCP_PROXY_ERROR_OPTION_82_VSS_NOT_PROCESSED, 1); + + } + o = (dhcp_option_t *) (((uword) o) + (o->length + 2)); + } + } + + if (sw_if_index == (u32)~0) + { + error0 = DHCP_PROXY_ERROR_NO_OPTION_82; + + drop_packet: + vlib_node_increment_counter (vm, dhcp_proxy_to_client_node.index, + error0, 1); + f0 = vlib_get_frame_to_node (vm, dpm->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, dpm->error_drop_node_index, f0); + goto do_trace; + } + + if (relay_addr.as_u32 == 0) + { + error0 = DHCP_PROXY_ERROR_BAD_OPTION_82_ADDR; + goto drop_packet; + } + + if (sw_if_index >= vec_len (im->fib_index_by_sw_if_index)) + { + error0 = DHCP_PROXY_ERROR_BAD_OPTION_82_ITF; + goto drop_packet; + } + + fib_index = im->fib_index_by_sw_if_index [sw_if_index]; + server = dhcp_get_server(dpm, fib_index, FIB_PROTOCOL_IP4); + + if (PREDICT_FALSE (NULL == server)) + { + error0 = DHCP_PROXY_ERROR_NO_SERVER; + goto drop_packet; + } + + if (ip0->src_address.as_u32 != server->dhcp_server.ip4.as_u32) + { + error0 = DHCP_PROXY_ERROR_BAD_SVR_FIB_OR_ADDRESS; + goto drop_packet; + } + + vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index; + + swif = vnet_get_sw_interface (vnm, sw_if_index); + original_sw_if_index = sw_if_index; + if (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED) + sw_if_index = swif->unnumbered_sw_if_index; + + ia0 = ip4_interface_first_address (&ip4_main, sw_if_index, 0); + if (ia0 == 0) + { + error0 = DHCP_PROXY_ERROR_NO_INTERFACE_ADDRESS; + goto drop_packet; + } + + if (relay_addr.as_u32 != ia0->as_u32) + { + error0 = DHCP_PROXY_ERROR_BAD_YIADDR; + goto drop_packet; + } + + u0->checksum = 0; + u0->dst_port = clib_net_to_host_u16 (UDP_DST_PORT_dhcp_to_client); + sum0 = ip0->checksum; + old0 = ip0->dst_address.as_u32; + new0 = 0xFFFFFFFF; + ip0->dst_address.as_u32 = new0; + sum0 = ip_csum_update (sum0, old0, new0, + ip4_header_t /* structure */, + dst_address /* offset of changed member */); + ip0->checksum = ip_csum_fold (sum0); + + sum0 = ip0->checksum; + old0 = ip0->src_address.as_u32; + new0 = ia0->as_u32; + ip0->src_address.as_u32 = new0; + sum0 = ip_csum_update (sum0, old0, new0, + ip4_header_t /* structure */, + src_address /* offset of changed member */); + ip0->checksum = ip_csum_fold (sum0); + + 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) + vlib_buffer_advance (b0, -4 /* space for VLAN tag */); + + mac0 = vlib_buffer_get_current (b0); + + 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 (ei0->address)); + memset (mac0->dst_address, 0xff, sizeof (mac0->dst_address)); + mac0->type = (si0->type == VNET_SW_INTERFACE_TYPE_SUB) ? + clib_net_to_host_u16(0x8100) : clib_net_to_host_u16 (0x0800); + + if (si0->type == VNET_SW_INTERFACE_TYPE_SUB) + { + u32 * vlan_tag = (u32 *)(mac0+1); + u32 tmp; + tmp = (si0->sub.id << 16) | 0x0800; + *vlan_tag = clib_host_to_net_u32 (tmp); + } + + /* $$$ This needs to be rewritten, for sure */ + 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)) + { + dhcp_proxy_trace_t *tr = vlib_add_trace (vm, node, + b0, sizeof (*tr)); + tr->which = 1; /* to client */ + tr->trace_ip4_address.as_u32 = ia0 ? ia0->as_u32 : 0; + tr->error = error0; + tr->original_sw_if_index = original_sw_if_index; + tr->sw_if_index = sw_if_index; + } + } + return from_frame->n_vectors; +} + +VLIB_REGISTER_NODE (dhcp_proxy_to_client_node, static) = { + .function = dhcp_proxy_to_client_input, + .name = "dhcp-proxy-to-client", + /* Takes a vector of packets. */ + .vector_size = sizeof (u32), + + .n_errors = DHCP_PROXY_N_ERROR, + .error_strings = dhcp_proxy_error_strings, + .format_buffer = format_dhcp_proxy_header_with_length, + .format_trace = format_dhcp_proxy_trace, +#if 0 + .unformat_buffer = unformat_dhcp_proxy_header, +#endif +}; + +static clib_error_t * +dhcp4_proxy_init (vlib_main_t * vm) +{ + dhcp_proxy_main_t * dm = &dhcp_proxy_main; + vlib_node_t * error_drop_node; + + error_drop_node = vlib_get_node_by_name (vm, (u8 *) "error-drop"); + dm->error_drop_node_index = error_drop_node->index; + + udp_register_dst_port (vm, UDP_DST_PORT_dhcp_to_client, + dhcp_proxy_to_client_node.index, 1 /* is_ip4 */); + + udp_register_dst_port (vm, UDP_DST_PORT_dhcp_to_server, + dhcp_proxy_to_server_node.index, 1 /* is_ip4 */); + + return 0; +} + + +VLIB_INIT_FUNCTION (dhcp4_proxy_init); + +int +dhcp4_proxy_set_server (ip46_address_t *addr, + ip46_address_t *src_addr, + u32 rx_table_id, + u32 server_table_id, + int is_del) +{ + u32 rx_fib_index = 0; + int rc = 0; + + const fib_prefix_t all_1s = + { + .fp_len = 32, + .fp_addr.ip4.as_u32 = 0xffffffff, + .fp_proto = FIB_PROTOCOL_IP4, + }; + + if (ip46_address_is_zero(addr)) + return VNET_API_ERROR_INVALID_DST_ADDRESS; + + if (ip46_address_is_zero(src_addr)) + return VNET_API_ERROR_INVALID_SRC_ADDRESS; + + rx_fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, + rx_table_id); + + if (is_del) + { + rc = dhcp_proxy_server_del (FIB_PROTOCOL_IP4, rx_fib_index); + + if (0 == rc) + { + fib_table_entry_special_remove(rx_fib_index, + &all_1s, + FIB_SOURCE_DHCP); + fib_table_unlock (rx_fib_index, FIB_PROTOCOL_IP4); + } + } + else + { + if (dhcp_proxy_server_add (FIB_PROTOCOL_IP4, + addr, src_addr, + rx_fib_index, server_table_id)) + { + fib_table_entry_special_add(rx_fib_index, + &all_1s, + FIB_SOURCE_DHCP, + FIB_ENTRY_FLAG_LOCAL, + ADJ_INDEX_INVALID); + fib_table_lock (rx_fib_index, FIB_PROTOCOL_IP4); + } + } + fib_table_unlock (rx_fib_index, FIB_PROTOCOL_IP4); + + return (rc); +} + +static clib_error_t * +dhcp4_proxy_set_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + ip46_address_t server_addr, src_addr; + u32 server_table_id = 0, rx_table_id = 0; + int is_del = 0; + int set_src = 0, set_server = 0; + + memset(&server_addr, 0, sizeof(server_addr)); + memset(&src_addr, 0, sizeof(src_addr)); + + while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "server %U", + unformat_ip4_address, &server_addr.ip4)) + set_server = 1; + else if (unformat (input, "server-fib-id %d", &server_table_id)) + ; + else if (unformat (input, "rx-fib-id %d", &rx_table_id)) + ; + else if (unformat(input, "src-address %U", + unformat_ip4_address, &src_addr.ip4)) + set_src = 1; + else if (unformat (input, "delete") || + unformat (input, "del")) + is_del = 1; + else + break; + } + + if (is_del || (set_server && set_src)) + { + int rv; + + rv = dhcp4_proxy_set_server (&server_addr, &src_addr, rx_table_id, + server_table_id, is_del); + switch (rv) + { + case 0: + return 0; + + case VNET_API_ERROR_INVALID_DST_ADDRESS: + return clib_error_return (0, "Invalid server address"); + + case VNET_API_ERROR_INVALID_SRC_ADDRESS: + return clib_error_return (0, "Invalid src address"); + + case VNET_API_ERROR_NO_SUCH_ENTRY: + return clib_error_return + (0, "Fib id %d: no per-fib DHCP server configured", rx_table_id); + + default: + return clib_error_return (0, "BUG: rv %d", rv); + } + } + else + return clib_error_return (0, "parse error`%U'", + format_unformat_error, input); +} + +VLIB_CLI_COMMAND (dhcp_proxy_set_command, static) = { + .path = "set dhcp proxy", + .short_help = "set dhcp proxy [del] server src-address [server-fib-id ] [rx-fib-id ]", + .function = dhcp4_proxy_set_command_fn, +}; + +static u8 * +format_dhcp4_proxy_server (u8 * s, va_list * args) +{ + dhcp_server_t * server = va_arg (*args, dhcp_server_t *); + ip4_fib_t * rx_fib, * server_fib; + + if (server == 0) + { + s = format (s, "%=16s%=16s%=14s%=14s", "Server", "Src Address", + "Server FIB", "RX FIB"); + return s; + } + + server_fib = ip4_fib_get(server->server_fib_index); + rx_fib = ip4_fib_get(server->rx_fib_index); + + s = format (s, "%=16U%=16U%=14u%=14u", + format_ip46_address, &server->dhcp_server, IP46_TYPE_ANY, + format_ip46_address, &server->dhcp_src_address, IP46_TYPE_ANY, + server_fib->table_id, + rx_fib->table_id); + return s; +} + +static int +dhcp4_proxy_show_walk (dhcp_server_t *server, + void *ctx) +{ + vlib_main_t * vm = ctx; + + vlib_cli_output (vm, "%U", format_dhcp4_proxy_server, server); + + return (1); +} + +static clib_error_t * +dhcp4_proxy_show_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + vlib_cli_output (vm, "%U", format_dhcp4_proxy_server, NULL /* header line */); + + dhcp_proxy_walk(FIB_PROTOCOL_IP4, dhcp4_proxy_show_walk, vm); + + return (NULL); +} + +VLIB_CLI_COMMAND (dhcp_proxy_show_command, static) = { + .path = "show dhcp proxy", + .short_help = "Display dhcp proxy server info", + .function = dhcp4_proxy_show_command_fn, +}; + +static clib_error_t * +dhcp_option_82_vss_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + int is_del = 0, got_new_vpn_id=0; + u32 oui=0, fib_id=0, tbl_id=~0; + + while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) + { + + if (unformat(input, "delete") || unformat(input, "del")) + is_del = 1; + else if (unformat (input, "oui %d", &oui)) + got_new_vpn_id = 1; + else if (unformat (input, "vpn-id %d", &fib_id)) + got_new_vpn_id = 1; + else if (unformat (input, "table %d", &tbl_id)) + got_new_vpn_id = 1; + else + break; + } + if (tbl_id == ~0) + return clib_error_return (0, "no table ID specified."); + + if (is_del || got_new_vpn_id) + { + int rv; + rv = dhcp_proxy_set_vss(FIB_PROTOCOL_IP4, tbl_id, oui, fib_id, is_del); + switch (rv) + { + case 0: + return 0; + + case VNET_API_ERROR_NO_SUCH_FIB: + return clib_error_return (0, "option 82 vss(oui:%d, vpn-id:%d) not found in table %d", + oui, fib_id, tbl_id); + + case VNET_API_ERROR_NO_SUCH_ENTRY: + return clib_error_return (0, "option 82 vss for table %d not found in in pool.", + tbl_id); + default: + return clib_error_return (0, "BUG: rv %d", rv); + } + } + else + return clib_error_return (0, "parse error`%U'", + format_unformat_error, input); +} + +VLIB_CLI_COMMAND (dhcp_proxy_vss_command,static) = { + .path = "set dhcp option-82 vss", + .short_help = "set dhcp option-82 vss [del] table oui vpn-id ", + .function = dhcp_option_82_vss_fn, +}; + +static clib_error_t * +dhcp_vss_show_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) + +{ + dhcp_vss_walk(FIB_PROTOCOL_IP4, dhcp_vss_show_walk, vm); + + return (NULL); +} + +VLIB_CLI_COMMAND (dhcp_proxy_vss_show_command, static) = { + .path = "show dhcp vss", + .short_help = "show dhcp VSS", + .function = dhcp_vss_show_command_fn, +}; + +static clib_error_t * +dhcp_option_82_address_show_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) + +{ + vnet_main_t *vnm = vnet_get_main(); + u32 sw_if_index0=0, sw_if_index; + vnet_sw_interface_t *swif; + ip4_address_t *ia0; + + while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) + { + + if (unformat(input, "%U", + unformat_vnet_sw_interface, vnm, &sw_if_index0)) + { + swif = vnet_get_sw_interface (vnm, sw_if_index0); + sw_if_index = (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED) ? + swif->unnumbered_sw_if_index : sw_if_index0; + ia0 = ip4_interface_first_address(&ip4_main, sw_if_index, 0); + if (ia0) + { + vlib_cli_output (vm, "%=20s%=20s", "interface", + "source IP address"); + + vlib_cli_output (vm, "%=20U%=20U", + format_vnet_sw_if_index_name, + vnm, sw_if_index0, + format_ip4_address, ia0); + } + else + vlib_cli_output (vm, "%=34s %=20U", + "No IPv4 address configured on", + format_vnet_sw_if_index_name, + vnm, sw_if_index); + } + else + break; + } + + return 0; +} + +VLIB_CLI_COMMAND (dhcp_proxy_address_show_command,static) = { + .path = "show dhcp option-82-address interface", + .short_help = "show dhcp option-82-address interface ", + .function = dhcp_option_82_address_show_command_fn, +}; diff --git a/src/vnet/dhcp/dhcp6_packet.h b/src/vnet/dhcp/dhcp6_packet.h new file mode 100644 index 00000000..ddcde7a0 --- /dev/null +++ b/src/vnet/dhcp/dhcp6_packet.h @@ -0,0 +1,183 @@ +#ifndef included_vnet_dhcp6_packet_h +#define included_vnet_dhcp6_packet_h + +/* + * DHCP packet format + * + * Copyright (c) 2013 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include + +// #define DHCP_VRF_NAME_MAX_LEN L3VM_MAX_NAME_STR_LEN +// #define DHCPV6_MAX_VRF_NAME_LEN L3VM_MAX_NAME_STR_LEN +#define DHCP_MAX_RELAY_ADDR 16 +#define PROTO_UDP 17 +#define DHCPV6_CLIENT_PORT 546 +#define DHCPV6_SERVER_PORT 547 +#define HOP_COUNT_LIMIT 32 +#define DHCPV6_CISCO_ENT_NUM 9 + +/* + * DHCPv6 message types + */ +typedef enum dhcpv6_msg_type_{ + DHCPV6_MSG_SOLICIT = 1, + DHCPV6_MSG_ADVERTISE = 2, + DHCPV6_MSG_REQUEST = 3, + DHCPV6_MSG_CONFIRM = 4, + DHCPV6_MSG_RENEW = 5, + DHCPV6_MSG_REBIND = 6, + DHCPV6_MSG_REPLY = 7, + DHCPV6_MSG_RELEASE = 8, + DHCPV6_MSG_DECLINE = 9, + DHCPV6_MSG_RECONFIGURE = 10, + DHCPV6_MSG_INFORMATION_REQUEST = 11, + DHCPV6_MSG_RELAY_FORW = 12, + DHCPV6_MSG_RELAY_REPL = 13, +} dhcpv6_msg_type_t; + +/* + * DHCPv6 options types + */ +enum { + DHCPV6_OPTION_CLIENTID = 1, + DHCPV6_OPTION_SERVERID = 2, + DHCPV6_OPTION_IA_NA = 3, + DHCPV6_OPTION_IA_TA = 4, + DHCPV6_OPTION_IAADDR = 5, + DHCPV6_OPTION_ORO = 6, + DHCPV6_OPTION_PREFERENCE = 7, + DHCPV6_OPTION_ELAPSED_TIME = 8, + DHCPV6_OPTION_RELAY_MSG = 9, + DHCPV6_OPTION_AUTH = 11, + DHCPV6_OPTION_UNICAST = 12, + DHCPV6_OPTION_STATUS_CODE = 13, + DHCPV6_OPTION_RAPID_COMMIT = 14, + DHCPV6_OPTION_USER_CLASS = 15, + DHCPV6_OPTION_VENDOR_CLASS = 16, + DHCPV6_OPTION_VENDOR_OPTS = 17, + DHCPV6_OPTION_INTERFACE_ID = 18, // relay agent fills this + DHCPV6_OPTION_RECONF_MSG = 19, + DHCPV6_OPTION_RECONF_ACCEPT = 20, + DHCPV6_OPTION_REMOTEID = 37, // relay agent fills this + DHCPV6_OPTION_VSS = 68, // relay agent fills this + DHCPV6_OPTION_CLIENT_LINK_LAYER_ADDRESS = 79, + DHCPV6_OPTION_MAX +}; + +/* +* DHCPv6 status codes + */ +enum { + DHCPV6_STATUS_SUCCESS = 0, + DHCPV6_STATUS_UNSPEC_FAIL = 1, + DHCPV6_STATUS_NOADDRS_AVAIL = 2, + DHCPV6_STATUS_NO_BINDING = 3, + DHCPV6_STATUS_NOT_ONLINK = 4, + DHCPV6_STATUS_USE_MULTICAST = 5, +}; + +/* + * DHCPv6 DUID types + */ +enum { + DHCPV6_DUID_LLT = 1, /* DUID Based on Link-layer Address Plus Time */ + DHCPV6_DUID_EN = 2, /* DUID Based on Enterprise Number */ + DHCPV6_DUID_LL = 3, /* DUID Based on Link-layer Address */ +}; + +//Structure for DHCPv6 payload from client +typedef struct dhcpv6_hdr_ { + union { + u8 msg_type; //DHCP msg type + u32 xid; // transaction id + }u; + u8 data[0]; +} dhcpv6_header_t; + + + +typedef CLIB_PACKED (struct dhcpv6_relay_ctx_ { + dhcpv6_header_t *pkt; + u32 pkt_len; + u32 dhcpv6_len; //DHCPv6 payload load +// if_ordinal iod; + u32 if_index; + u32 ctx_id; + char ctx_name[32+1]; + u8 dhcp_msg_type; +}) dhcpv6_relay_ctx_t; + +//Structure for DHCPv6 RELAY-FORWARD and DHCPv6 RELAY-REPLY pkts +typedef CLIB_PACKED (struct dhcpv6_relay_hdr_ { + u8 msg_type; + u8 hop_count; + ip6_address_t link_addr; + ip6_address_t peer_addr; + u8 data[0]; +}) dhcpv6_relay_hdr_t; + +typedef enum dhcp_stats_action_type_ { + DHCP_STATS_ACTION_FORWARDED=1, + DHCP_STATS_ACTION_RECEIVED, + DHCP_STATS_ACTION_DROPPED +} dhcp_stats_action_type_t; +//Generic counters for a packet +typedef struct dhcp_stats_counters_ { + u64 rx_pkts; //counter for received pkts + u64 tx_pkts; //counter for forwarded pkts + u64 drops; //counter for dropped pkts +} dhcp_stats_counters_t; + + +typedef enum dhcpv6_stats_drop_reason_ { + DHCPV6_RELAY_PKT_DROP_RELAYDISABLE = 1, + DHCPV6_RELAY_PKT_DROP_MAX_HOPS, + DHCPV6_RELAY_PKT_DROP_VALIDATION_FAIL, + DHCPV6_RELAY_PKT_DROP_UNKNOWN_OP_INTF, + DHCPV6_RELAY_PKT_DROP_BAD_CONTEXT, + DHCPV6_RELAY_PKT_DROP_OPT_INSERT_FAIL, + DHCPV6_RELAY_PKT_DROP_REPLY_FROM_CLIENT, +} dhcpv6_stats_drop_reason_t; + +typedef CLIB_PACKED (struct { + u16 option; + u16 length; + u8 data[0]; +}) dhcpv6_option_t; + +typedef CLIB_PACKED (struct { + dhcpv6_option_t opt; + u32 int_idx; +}) dhcpv6_int_id_t; + +typedef CLIB_PACKED (struct { + dhcpv6_option_t opt; + u8 data[8]; // data[0]:type, data[1..7]: VPN ID +}) dhcpv6_vss_t; + +typedef CLIB_PACKED (struct { + dhcpv6_option_t opt; + u32 ent_num; + u32 rmt_id; +}) dhcpv6_rmt_id_t; + +typedef CLIB_PACKED (struct { + dhcpv6_option_t opt; + u16 link_type; + u8 data[6]; // data[0]:data[5]: MAC address +}) dhcpv6_client_mac_t; + + +#endif /* included_vnet_dhcp6_packet_h */ diff --git a/src/vnet/dhcp/dhcp6_proxy_error.def b/src/vnet/dhcp/dhcp6_proxy_error.def new file mode 100644 index 00000000..55fa7317 --- /dev/null +++ b/src/vnet/dhcp/dhcp6_proxy_error.def @@ -0,0 +1,29 @@ +/* + * dhcp_proxy_error.def: dhcp proxy errors + * + * Copyright (c) 2013 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +dhcpv6_proxy_error (NONE, "no error") +dhcpv6_proxy_error (NO_SERVER, "no dhcpv6 server configured") +dhcpv6_proxy_error (RELAY_TO_SERVER, "DHCPV6 packets relayed to the server") +dhcpv6_proxy_error (RELAY_TO_CLIENT, "DHCPV6 packets relayed to clients") +dhcpv6_proxy_error (NO_INTERFACE_ADDRESS, "DHCPV6 no interface address") +dhcpv6_proxy_error (WRONG_MESSAGE_TYPE, "DHCPV6 wrong message type.") +dhcpv6_proxy_error (NO_SRC_ADDRESS, "DHCPV6 no srouce IPv6 address configured.") +dhcpv6_proxy_error (NO_CIRCUIT_ID_OPTION, "DHCPv6 reply packets without circuit ID option") +dhcpv6_proxy_error (NO_RELAY_MESSAGE_OPTION, "DHCPv6 reply packets without relay message option") +dhcpv6_proxy_error (BAD_SVR_FIB_OR_ADDRESS, "DHCPv6 packets not from DHCPv6 server or server FIB.") +dhcpv6_proxy_error (PKT_TOO_BIG, "DHCPv6 packets which are too big.") +dhcpv6_proxy_error (WRONG_INTERFACE_ID_OPTION, "DHCPv6 reply to invalid interface.") diff --git a/src/vnet/dhcp/dhcp6_proxy_node.c b/src/vnet/dhcp/dhcp6_proxy_node.c new file mode 100644 index 00000000..ed44977d --- /dev/null +++ b/src/vnet/dhcp/dhcp6_proxy_node.c @@ -0,0 +1,1065 @@ +/* + * dhcp6_proxy_node.c: dhcpv6 proxy node processing + * + * Copyright (c) 2013 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include + +static char * dhcpv6_proxy_error_strings[] = { +#define dhcpv6_proxy_error(n,s) s, +#include +#undef dhcpv6_proxy_error +}; + +#define foreach_dhcpv6_proxy_to_server_input_next \ + _ (DROP, "error-drop") \ + _ (LOOKUP, "ip6-lookup") \ + _ (SEND_TO_CLIENT, "dhcpv6-proxy-to-client") + + +typedef enum { +#define _(s,n) DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_##s, + foreach_dhcpv6_proxy_to_server_input_next +#undef _ + DHCPV6_PROXY_TO_SERVER_INPUT_N_NEXT, +} dhcpv6_proxy_to_server_input_next_t; + +typedef struct { + /* 0 => to server, 1 => to client */ + int which; + u8 packet_data[64]; + u32 error; + u32 sw_if_index; + u32 original_sw_if_index; +} dhcpv6_proxy_trace_t; + +static vlib_node_registration_t dhcpv6_proxy_to_server_node; +static vlib_node_registration_t dhcpv6_proxy_to_client_node; + +/* all DHCP servers address */ +static ip6_address_t all_dhcpv6_server_address; +static ip6_address_t all_dhcpv6_server_relay_agent_address; + +static u8 * +format_dhcpv6_proxy_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + dhcpv6_proxy_trace_t * t = va_arg (*args, dhcpv6_proxy_trace_t *); + + if (t->which == 0) + s = format (s, "DHCPV6 proxy: sent to server %U", + format_ip6_address, &t->packet_data, sizeof (ip6_address_t)); + else + s = format (s, "DHCPV6 proxy: sent to client from %U", + format_ip6_address, &t->packet_data, sizeof (ip6_address_t)); + if (t->error != (u32)~0) + s = format (s, " error: %s\n", dhcpv6_proxy_error_strings[t->error]); + + s = format (s, " original_sw_if_index: %d, sw_if_index: %d\n", + t->original_sw_if_index, t->sw_if_index); + + return s; +} + +static u8 * +format_dhcpv6_proxy_header_with_length (u8 * s, va_list * args) +{ + dhcpv6_header_t * h = va_arg (*args, dhcpv6_header_t *); + u32 max_header_bytes = va_arg (*args, u32); + u32 header_bytes; + + header_bytes = sizeof (h[0]); + if (max_header_bytes != 0 && header_bytes > max_header_bytes) + return format (s, "dhcpv6 header truncated"); + + s = format (s, "DHCPV6 Proxy"); + + return s; +} +/* get first interface address */ +static ip6_address_t * +ip6_interface_first_global_or_site_address (ip6_main_t * im, u32 sw_if_index) +{ + ip_lookup_main_t * lm = &im->lookup_main; + ip_interface_address_t * ia = 0; + ip6_address_t * result = 0; + + foreach_ip_interface_address (lm, ia, sw_if_index, + 1 /* honor unnumbered */, + ({ + ip6_address_t * a = ip_interface_address_get_address (lm, ia); + if ((a->as_u8[0] & 0xe0) == 0x20 || + (a->as_u8[0] & 0xfe) == 0xfc) { + result = a; + break; + } + })); + return result; +} + +static inline void copy_ip6_address (ip6_address_t *dst, + ip6_address_t *src) +{ + dst->as_u64[0] = src->as_u64[0]; + dst->as_u64[1] = src->as_u64[1]; +} + +static uword +dhcpv6_proxy_to_server_input (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * from_frame) +{ + u32 n_left_from, next_index, * from, * to_next; + dhcp_proxy_main_t * dpm = &dhcp_proxy_main; + from = vlib_frame_vector_args (from_frame); + n_left_from = from_frame->n_vectors; + u32 pkts_to_server=0, pkts_to_client=0, pkts_no_server=0; + u32 pkts_no_interface_address=0, pkts_no_exceeding_max_hop=0; + u32 pkts_no_src_address=0; + u32 pkts_wrong_msg_type=0; + u32 pkts_too_big=0; + ip6_main_t * im = &ip6_main; + ip6_address_t * src; + int bogus_length; + dhcp_server_t * server; + u32 rx_fib_idx = 0, server_fib_idx = 0; + + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + 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) + { + vnet_main_t *vnm = vnet_get_main(); + u32 sw_if_index = 0; + u32 rx_sw_if_index = 0; + vnet_sw_interface_t *swif; + u32 bi0; + vlib_buffer_t * b0; + udp_header_t * u0, *u1; + dhcpv6_header_t * h0; // client msg hdr + ip6_header_t * ip0, *ip1; + ip6_address_t _ia0, *ia0=&_ia0; + u32 next0; + u32 error0 = (u32) ~0; + dhcpv6_option_t *fwd_opt; + dhcpv6_relay_hdr_t *r1; + u16 len; + dhcpv6_int_id_t *id1; + dhcpv6_vss_t *vss1; + dhcpv6_client_mac_t *cmac; // client mac + ethernet_header_t * e_h0; + u8 client_src_mac[6]; + vlib_buffer_free_list_t *fl; + dhcp_vss_t *vss; + + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + + b0 = vlib_get_buffer (vm, bi0); + + h0 = vlib_buffer_get_current (b0); + + /* + * udp_local hands us the DHCPV6 header. + */ + u0 = (void *)h0 -(sizeof(*u0)); + ip0 = (void *)u0 -(sizeof(*ip0)); + e_h0 = (void *)ip0 - ethernet_buffer_header_size(b0); + + clib_memcpy(client_src_mac, e_h0->src_address, 6); + + switch (h0->u.msg_type) { + case DHCPV6_MSG_SOLICIT: + case DHCPV6_MSG_REQUEST: + case DHCPV6_MSG_CONFIRM: + case DHCPV6_MSG_RENEW: + case DHCPV6_MSG_REBIND: + case DHCPV6_MSG_RELEASE: + case DHCPV6_MSG_DECLINE: + case DHCPV6_MSG_INFORMATION_REQUEST: + case DHCPV6_MSG_RELAY_FORW: + /* send to server */ + break; + case DHCPV6_MSG_RELAY_REPL: + /* send to client */ + next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_SEND_TO_CLIENT; + error0 = 0; + pkts_to_client++; + goto do_enqueue; + default: + /* drop the packet */ + pkts_wrong_msg_type++; + error0 = DHCPV6_PROXY_ERROR_WRONG_MESSAGE_TYPE; + next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP; + goto do_trace; + + } + + /* Send to DHCPV6 server via the configured FIB */ + rx_sw_if_index = sw_if_index = vnet_buffer(b0)->sw_if_index[VLIB_RX]; + rx_fib_idx = im->fib_index_by_sw_if_index [rx_sw_if_index]; + server = dhcp_get_server(dpm, rx_fib_idx, FIB_PROTOCOL_IP6); + + if (PREDICT_FALSE (NULL == server)) + { + error0 = DHCPV6_PROXY_ERROR_NO_SERVER; + next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP; + pkts_no_server++; + goto do_trace; + } + + server_fib_idx = server->server_fib_index; + vnet_buffer(b0)->sw_if_index[VLIB_TX] = server_fib_idx; + + + /* relay-option header pointer */ + vlib_buffer_advance(b0, -(sizeof(*fwd_opt))); + fwd_opt = vlib_buffer_get_current(b0); + /* relay message header pointer */ + vlib_buffer_advance(b0, -(sizeof(*r1))); + r1 = vlib_buffer_get_current(b0); + + vlib_buffer_advance(b0, -(sizeof(*u1))); + u1 = vlib_buffer_get_current(b0); + + vlib_buffer_advance(b0, -(sizeof(*ip1))); + ip1 = vlib_buffer_get_current(b0); + + /* fill in all that rubbish... */ + len = clib_net_to_host_u16(u0->length) - sizeof(udp_header_t); + copy_ip6_address(&r1->peer_addr, &ip0->src_address); + + r1->msg_type = DHCPV6_MSG_RELAY_FORW; + fwd_opt->length = clib_host_to_net_u16(len); + fwd_opt->option = clib_host_to_net_u16(DHCPV6_OPTION_RELAY_MSG); + + r1->hop_count++; + r1->hop_count = (h0->u.msg_type != DHCPV6_MSG_RELAY_FORW) ? 0 : r1->hop_count; + + if (PREDICT_FALSE(r1->hop_count >= HOP_COUNT_LIMIT)) + { + error0 = DHCPV6_RELAY_PKT_DROP_MAX_HOPS; + next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP; + pkts_no_exceeding_max_hop++; + goto do_trace; + } + + + /* If relay-fwd and src address is site or global unicast address */ + if (h0->u.msg_type == DHCPV6_MSG_RELAY_FORW && + ((ip0->src_address.as_u8[0] & 0xe0) == 0x20 || + (ip0->src_address.as_u8[0] & 0xfe) == 0xfc)) + { + /* Set link address to zero */ + r1->link_addr.as_u64[0] = 0; + r1->link_addr.as_u64[1] = 0; + goto link_address_set; + } + + /* if receiving interface is unnumbered, use receiving interface + * IP address as link address, otherwise use the loopback interface + * IP address as link address. + */ + + swif = vnet_get_sw_interface (vnm, rx_sw_if_index); + if (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED) + sw_if_index = swif->unnumbered_sw_if_index; + + ia0 = ip6_interface_first_global_or_site_address(&ip6_main, sw_if_index); + if (ia0 == 0) + { + error0 = DHCPV6_PROXY_ERROR_NO_INTERFACE_ADDRESS; + next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP; + pkts_no_interface_address++; + goto do_trace; + } + + copy_ip6_address(&r1->link_addr, ia0); + + link_address_set: + fl = vlib_buffer_get_free_list (vm, b0->free_list_index); + + if ((b0->current_length+sizeof(*id1)+sizeof(*vss1)+sizeof(*cmac)) + > fl->n_data_bytes) + { + error0 = DHCPV6_PROXY_ERROR_PKT_TOO_BIG; + next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP; + pkts_too_big++; + goto do_trace; + } + + id1 = (dhcpv6_int_id_t *) (((uword) ip1) + b0->current_length); + b0->current_length += (sizeof (*id1)); + + id1->opt.option = clib_host_to_net_u16(DHCPV6_OPTION_INTERFACE_ID); + id1->opt.length = clib_host_to_net_u16(sizeof(rx_sw_if_index)); + id1->int_idx = clib_host_to_net_u32(rx_sw_if_index); + + u1->length =0; + if (h0->u.msg_type != DHCPV6_MSG_RELAY_FORW) + { + cmac = (dhcpv6_client_mac_t *) (((uword) ip1) + b0->current_length); + b0->current_length += (sizeof (*cmac)); + cmac->opt.length =clib_host_to_net_u16(sizeof(*cmac) - + sizeof(cmac->opt)); + cmac->opt.option = clib_host_to_net_u16(DHCPV6_OPTION_CLIENT_LINK_LAYER_ADDRESS); + cmac->link_type = clib_host_to_net_u16(1); // ethernet + clib_memcpy(cmac->data, client_src_mac, 6); + u1->length += sizeof(*cmac); + } + + vss = dhcp_get_vss_info(dpm, rx_fib_idx, FIB_PROTOCOL_IP6); + + if (NULL != vss) { + vss1 = (dhcpv6_vss_t *) (((uword) ip1) + b0->current_length); + b0->current_length += (sizeof (*vss1)); + vss1->opt.length =clib_host_to_net_u16(sizeof(*vss1) - + sizeof(vss1->opt)); + vss1->opt.option = clib_host_to_net_u16(DHCPV6_OPTION_VSS); + vss1->data[0] = 1; // type + vss1->data[1] = vss->oui >>16 & 0xff; + vss1->data[2] = vss->oui >>8 & 0xff; + vss1->data[3] = vss->oui & 0xff; + vss1->data[4] = vss->fib_id >> 24 & 0xff; + vss1->data[5] = vss->fib_id >> 16 & 0xff; + vss1->data[6] = vss->fib_id >> 8 & 0xff; + vss1->data[7] = vss->fib_id & 0xff; + u1->length += sizeof(*vss1); + } + + pkts_to_server++; + u1->checksum = 0; + u1->src_port = clib_host_to_net_u16(UDP_DST_PORT_dhcpv6_to_client); + u1->dst_port = clib_host_to_net_u16(UDP_DST_PORT_dhcpv6_to_server); + + u1->length = + clib_host_to_net_u16( clib_net_to_host_u16(fwd_opt->length) + + sizeof(*r1) + sizeof(*fwd_opt) + + sizeof(*u1) + sizeof(*id1) + u1->length); + + memset(ip1, 0, sizeof(*ip1)); + ip1->ip_version_traffic_class_and_flow_label = 0x60; + ip1->payload_length = u1->length; + ip1->protocol = PROTO_UDP; + ip1->hop_limit = HOP_COUNT_LIMIT; + src = (server->dhcp_server.ip6.as_u64[0] || + server->dhcp_server.ip6.as_u64[1]) ? + &server->dhcp_server.ip6 : &all_dhcpv6_server_address; + copy_ip6_address(&ip1->dst_address, src); + + + ia0 = ip6_interface_first_global_or_site_address + (&ip6_main, vnet_buffer(b0)->sw_if_index[VLIB_RX]); + + src = (server->dhcp_src_address.ip6.as_u64[0] || + server->dhcp_src_address.ip6.as_u64[1]) ? + &server->dhcp_src_address.ip6 : ia0; + if (ia0 == 0) + { + error0 = DHCPV6_PROXY_ERROR_NO_SRC_ADDRESS; + next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP; + pkts_no_src_address++; + goto do_trace; + } + + copy_ip6_address (&ip1->src_address, src); + + + u1->checksum = ip6_tcp_udp_icmp_compute_checksum(vm, b0, ip1, + &bogus_length); + ASSERT(bogus_length == 0); + + next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP; + + do_trace: + if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) + { + dhcpv6_proxy_trace_t *tr = vlib_add_trace (vm, node, + b0, sizeof (*tr)); + tr->which = 0; /* to server */ + tr->error = error0; + tr->original_sw_if_index = rx_sw_if_index; + tr->sw_if_index = sw_if_index; + if (DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP == next0) + copy_ip6_address((ip6_address_t *)&tr->packet_data[0], &server->dhcp_server.ip6); + } + + do_enqueue: + 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); + } + + vlib_node_increment_counter (vm, dhcpv6_proxy_to_server_node.index, + DHCPV6_PROXY_ERROR_RELAY_TO_CLIENT, + pkts_to_client); + vlib_node_increment_counter (vm, dhcpv6_proxy_to_server_node.index, + DHCPV6_PROXY_ERROR_RELAY_TO_SERVER, + pkts_to_server); + vlib_node_increment_counter (vm, dhcpv6_proxy_to_server_node.index, + DHCPV6_PROXY_ERROR_NO_INTERFACE_ADDRESS, + pkts_no_interface_address); + vlib_node_increment_counter (vm, dhcpv6_proxy_to_server_node.index, + DHCPV6_PROXY_ERROR_WRONG_MESSAGE_TYPE, + pkts_wrong_msg_type); + vlib_node_increment_counter (vm, dhcpv6_proxy_to_server_node.index, + DHCPV6_PROXY_ERROR_NO_SRC_ADDRESS, + pkts_no_src_address); + vlib_node_increment_counter (vm, dhcpv6_proxy_to_server_node.index, + DHCPV6_PROXY_ERROR_PKT_TOO_BIG, + pkts_too_big); + return from_frame->n_vectors; +} + +VLIB_REGISTER_NODE (dhcpv6_proxy_to_server_node, static) = { + .function = dhcpv6_proxy_to_server_input, + .name = "dhcpv6-proxy-to-server", + /* 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_SERVER_INPUT_N_NEXT, + .next_nodes = { +#define _(s,n) [DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_##s] = n, + foreach_dhcpv6_proxy_to_server_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 +}; + +static uword +dhcpv6_proxy_to_client_input (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * from_frame) +{ + + u32 n_left_from, * from; + ethernet_main_t *em = ethernet_get_main (vm); + dhcp_proxy_main_t * dm = &dhcp_proxy_main; + dhcp_server_t * server; + vnet_main_t * vnm = vnet_get_main(); + int bogus_length; + + from = vlib_frame_vector_args (from_frame); + n_left_from = from_frame->n_vectors; + + 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, * ia0 = &_ia0; + 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 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) + { + error0 = DHCPV6_PROXY_ERROR_WRONG_MESSAGE_TYPE; + + drop_packet: + vlib_node_increment_counter (vm, dhcpv6_proxy_to_client_node.index, + error0, 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)); + + 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 */ + + while ((u8 *) o < (b0->data + b0->current_data + b0->current_length)) + { + if (DHCPV6_OPTION_INTERFACE_ID == clib_net_to_host_u16(o->option)) + { + 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; + goto drop_packet; + } + } + 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 ((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)); + + client_fib_idx = im->fib_index_by_sw_if_index[sw_if_index]; + server = dhcp_get_server(dm, client_fib_idx, FIB_PROTOCOL_IP6); + + if (NULL == server) + { + error0 = DHCPV6_PROXY_ERROR_NO_SERVER; + goto drop_packet; + } + + server_fib_idx = im->fib_index_by_sw_if_index + [vnet_buffer(b0)->sw_if_index[VLIB_RX]]; + + 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]) + { + //drop packet if not from server with configured address or FIB + error0 = DHCPV6_PROXY_ERROR_BAD_SVR_FIB_OR_ADDRESS; + goto drop_packet; + } + + vnet_buffer (b0)->sw_if_index[VLIB_TX] = original_sw_if_index + = sw_if_index; + + 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; + + + /* + * 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); + + vlib_buffer_advance (b0, -(sizeof(*ip1))); + ip1 = vlib_buffer_get_current (b0); + + copy_ip6_address(&client_address, &h0->peer_addr); + + ia0 = ip6_interface_first_address (&ip6_main, sw_if_index); + if (ia0 == 0) + { + error0 = DHCPV6_PROXY_ERROR_NO_INTERFACE_ADDRESS; + goto drop_packet; + } + + len = clib_net_to_host_u16(r0->length); + 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) + vlib_buffer_advance (b0, -4 /* space for VLAN tag */); + + mac0 = vlib_buffer_get_current (b0); + + 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 (ei0->address)); + memset (&mac0->dst_address, 0xff, sizeof (mac0->dst_address)); + mac0->type = (si0->type == VNET_SW_INTERFACE_TYPE_SUB) ? + clib_net_to_host_u16(0x8100) : clib_net_to_host_u16 (0x86dd); + + if (si0->type == VNET_SW_INTERFACE_TYPE_SUB) + { + u32 * vlan_tag = (u32 *)(mac0+1); + u32 tmp; + tmp = (si0->sub.id << 16) | 0x0800; + *vlan_tag = clib_host_to_net_u32 (tmp); + } + + /* $$$ 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, + b0, sizeof (*tr)); + tr->which = 1; /* to client */ + if (ia0) + copy_ip6_address((ip6_address_t*)tr->packet_data, ia0); + tr->error = error0; + tr->original_sw_if_index = original_sw_if_index; + tr->sw_if_index = sw_if_index; + } + } + 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, +#if 0 + .unformat_buffer = unformat_dhcpv6_proxy_header, +#endif +}; + +static clib_error_t * +dhcp6_proxy_init (vlib_main_t * vm) +{ + dhcp_proxy_main_t * dm = &dhcp_proxy_main; + vlib_node_t * error_drop_node; + + error_drop_node = vlib_get_node_by_name (vm, (u8 *) "error-drop"); + dm->error_drop_node_index = error_drop_node->index; + + /* RFC says this is the dhcpv6 server address */ + all_dhcpv6_server_address.as_u64[0] = clib_host_to_net_u64 (0xFF05000000000000); + all_dhcpv6_server_address.as_u64[1] = clib_host_to_net_u64 (0x00010003); + + /* RFC says this is the server and agent address */ + all_dhcpv6_server_relay_agent_address.as_u64[0] = clib_host_to_net_u64 (0xFF02000000000000); + all_dhcpv6_server_relay_agent_address.as_u64[1] = clib_host_to_net_u64 (0x00010002); + + 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 */); + + return 0; +} + +VLIB_INIT_FUNCTION (dhcp6_proxy_init); + +int +dhcp6_proxy_set_server (ip46_address_t *addr, + ip46_address_t *src_addr, + u32 rx_table_id, + u32 server_table_id, + int is_del) +{ + u32 rx_fib_index = 0; + int rc = 0; + + const mfib_prefix_t all_dhcp_servers = { + .fp_len = 128, + .fp_proto = FIB_PROTOCOL_IP6, + .fp_grp_addr = { + .ip6 = all_dhcpv6_server_relay_agent_address, + } + }; + + if (ip46_address_is_zero(addr)) + return VNET_API_ERROR_INVALID_DST_ADDRESS; + + if (ip46_address_is_zero(src_addr)) + return VNET_API_ERROR_INVALID_SRC_ADDRESS; + + rx_fib_index = mfib_table_find_or_create_and_lock(FIB_PROTOCOL_IP6, + rx_table_id); + + if (is_del) + { + rc = dhcp_proxy_server_del (FIB_PROTOCOL_IP6, rx_fib_index); + + if (0 == rc) + { + mfib_table_entry_delete(rx_fib_index, + &all_dhcp_servers, + MFIB_SOURCE_DHCP); + mfib_table_unlock(rx_fib_index, FIB_PROTOCOL_IP6); + } + } + else + { + const fib_route_path_t path_for_us = { + .frp_proto = FIB_PROTOCOL_IP6, + .frp_addr = zero_addr, + .frp_sw_if_index = 0xffffffff, + .frp_fib_index = ~0, + .frp_weight = 0, + .frp_flags = FIB_ROUTE_PATH_LOCAL, + }; + if (dhcp_proxy_server_add (FIB_PROTOCOL_IP6, addr, src_addr, + rx_fib_index, server_table_id)) + { + mfib_table_entry_path_update(rx_fib_index, + &all_dhcp_servers, + MFIB_SOURCE_DHCP, + &path_for_us, + MFIB_ITF_FLAG_FORWARD); + /* + * Each interface that is enabled in this table, needs to be added + * as an accepting interface, but this is not easily doable in VPP. + * So we cheat. Add a flag to the entry that indicates accept form + * any interface. + * We will still only accept on v6 enabled interfaces, since the + * input feature ensures this. + */ + mfib_table_entry_update(rx_fib_index, + &all_dhcp_servers, + MFIB_SOURCE_DHCP, + MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF); + mfib_table_lock(rx_fib_index, FIB_PROTOCOL_IP6); + } + } + + mfib_table_unlock(rx_fib_index, FIB_PROTOCOL_IP6); + + return (rc); +} + +static clib_error_t * +dhcpv6_proxy_set_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + ip46_address_t addr, src_addr; + int set_server = 0, set_src_address = 0; + u32 rx_table_id = 0, server_table_id = 0; + int is_del = 0; + + while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "server %U", + unformat_ip6_address, &addr.ip6)) + set_server = 1; + else if (unformat(input, "src-address %U", + unformat_ip6_address, &src_addr.ip6)) + set_src_address =1; + else if (unformat (input, "server-fib-id %d", &server_table_id)) + ; + else if (unformat (input, "rx-fib-id %d", &rx_table_id)) + ; + else if (unformat (input, "delete") || + unformat (input, "del")) + is_del = 1; + else + break; + } + + if (is_del || (set_server && set_src_address)) + { + int rv; + + rv = dhcp6_proxy_set_server (&addr, &src_addr, rx_table_id, + server_table_id, is_del); + + //TODO: Complete the errors + switch (rv) + { + case 0: + return 0; + + case VNET_API_ERROR_INVALID_DST_ADDRESS: + return clib_error_return (0, "Invalid server address"); + + case VNET_API_ERROR_INVALID_SRC_ADDRESS: + return clib_error_return (0, "Invalid src address"); + + case VNET_API_ERROR_NO_SUCH_ENTRY: + return clib_error_return + (0, "Fib id %d: no per-fib DHCP server configured", rx_table_id); + + default: + return clib_error_return (0, "BUG: rv %d", rv); + } + } + else + return clib_error_return (0, "parse error`%U'", + format_unformat_error, input); +} + +VLIB_CLI_COMMAND (dhcpv6_proxy_set_command, static) = { + .path = "set dhcpv6 proxy", + .short_help = "set dhcpv6 proxy [del] server src-address " + "[server-fib-id ] [rx-fib-id ] ", + .function = dhcpv6_proxy_set_command_fn, +}; + +static u8 * +format_dhcp6_proxy_server (u8 * s, va_list * args) +{ + dhcp_server_t * server = va_arg (*args, dhcp_server_t *); + ip6_fib_t * rx_fib, * server_fib; + + if (NULL == server) + { + s = format (s, "%=40s%=40s%=14s%=14s", "Server Address", "Source Address", + "Server FIB", "RX FIB"); + return s; + } + + server_fib = ip6_fib_get(server->server_fib_index); + rx_fib = ip6_fib_get(server->rx_fib_index); + + + s = format (s, "%=40U%=40U%=14u%=14u", + format_ip46_address, &server->dhcp_server, IP46_TYPE_ANY, + format_ip46_address, &server->dhcp_src_address, IP46_TYPE_ANY, + server_fib->table_id, rx_fib->table_id); + return s; +} + +static int +dhcp6_proxy_show_walk (dhcp_server_t *server, + void *ctx) +{ + vlib_main_t * vm = ctx; + + vlib_cli_output (vm, "%U", format_dhcp6_proxy_server, server); + + return (1); +} + +static clib_error_t * +dhcpv6_proxy_show_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + vlib_cli_output (vm, "%U", format_dhcp6_proxy_server, NULL /* header line */); + + dhcp_proxy_walk(FIB_PROTOCOL_IP6, dhcp6_proxy_show_walk, vm); + + return (NULL); +} + +VLIB_CLI_COMMAND (dhcpv6_proxy_show_command, static) = { + .path = "show dhcpv6 proxy", + .short_help = "Display dhcpv6 proxy info", + .function = dhcpv6_proxy_show_command_fn, +}; + +static clib_error_t * +dhcpv6_vss_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + int is_del = 0, got_new_vss=0; + u32 oui=0; + u32 fib_id=0, tbl_id=~0; + + while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "oui %d", &oui)) + got_new_vss = 1; + else if (unformat (input, "vpn-id %d", &fib_id)) + got_new_vss = 1; + else if (unformat (input, "table %d", &tbl_id)) + got_new_vss = 1; + else if (unformat(input, "delete") || unformat(input, "del")) + is_del = 1; + else + break; + } + + if (tbl_id ==~0) + return clib_error_return (0, "no table ID specified."); + + if (is_del || got_new_vss) + { + int rv; + + rv = dhcp_proxy_set_vss(FIB_PROTOCOL_IP6, tbl_id, oui, fib_id, is_del); + switch (rv) + { + case 0: + return 0; + + case VNET_API_ERROR_NO_SUCH_FIB: + return clib_error_return (0, "vss info (oui:%d, vpn-id:%d) not found in table %d.", + oui, fib_id, tbl_id); + + case VNET_API_ERROR_NO_SUCH_ENTRY: + return clib_error_return (0, "vss for table %d not found in pool.", + tbl_id); + + default: + return clib_error_return (0, "BUG: rv %d", rv); + } + } + else + return clib_error_return (0, "parse error`%U'", + format_unformat_error, input); + +} + +VLIB_CLI_COMMAND (dhcpv6_proxy_vss_command, static) = { + .path = "set dhcpv6 vss", + .short_help = "set dhcpv6 vss table oui vpn-idx ", + .function = dhcpv6_vss_command_fn, +}; + +static clib_error_t * +dhcpv6_vss_show_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) + +{ + dhcp_vss_walk(FIB_PROTOCOL_IP6, dhcp_vss_show_walk, vm); + + return (NULL); +} + +VLIB_CLI_COMMAND (dhcpv6_proxy_vss_show_command, static) = { + .path = "show dhcpv6 vss", + .short_help = "show dhcpv6 VSS", + .function = dhcpv6_vss_show_command_fn, +}; + +static clib_error_t * +dhcpv6_link_address_show_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) + +{ + vnet_main_t *vnm = vnet_get_main(); + u32 sw_if_index0=0, sw_if_index; + vnet_sw_interface_t *swif; + ip6_address_t *ia0; + + while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) + { + + if (unformat(input, "%U", + unformat_vnet_sw_interface, vnm, &sw_if_index0)) + { + swif = vnet_get_sw_interface (vnm, sw_if_index0); + sw_if_index = (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED) ? + swif->unnumbered_sw_if_index : sw_if_index0; + ia0 = ip6_interface_first_address(&ip6_main, sw_if_index); + if (ia0) + { + vlib_cli_output (vm, "%=20s%=48s", "interface", "link-address"); + + vlib_cli_output (vm, "%=20U%=48U", + format_vnet_sw_if_index_name, vnm, sw_if_index0, + format_ip6_address, ia0); + } else + vlib_cli_output (vm, "%=34s%=20U", "No IPv6 address configured on", + format_vnet_sw_if_index_name, vnm, sw_if_index); + } else + break; + } + + return 0; +} + +VLIB_CLI_COMMAND (dhcpv6_proxy_address_show_command, static) = { + .path = "show dhcpv6 link-address interface", + .short_help = "show dhcpv6 link-address interface ", + .function = dhcpv6_link_address_show_command_fn, +}; diff --git a/src/vnet/dhcp/dhcp_api.c b/src/vnet/dhcp/dhcp_api.c index ce9039b7..bdf02cae 100644 --- a/src/vnet/dhcp/dhcp_api.c +++ b/src/vnet/dhcp/dhcp_api.c @@ -22,9 +22,8 @@ #include #include -#include +#include #include -#include #include @@ -51,52 +50,19 @@ _(DHCP_PROXY_DETAILS,dhcp_proxy_details) \ _(DHCP_PROXY_SET_VSS,dhcp_proxy_set_vss) \ _(DHCP_CLIENT_CONFIG, dhcp_client_config) -static void -dhcpv4_proxy_config (vl_api_dhcp_proxy_config_t * mp) -{ - vl_api_dhcp_proxy_config_reply_t *rmp; - int rv; - - rv = dhcp_proxy_set_server ((ip4_address_t *) (&mp->dhcp_server), - (ip4_address_t *) (&mp->dhcp_src_address), - (u32) ntohl (mp->rx_vrf_id), - (u32) ntohl (mp->server_vrf_id), - (int) (mp->is_add == 0)); - - REPLY_MACRO (VL_API_DHCP_PROXY_CONFIG_REPLY); -} - - -static void -dhcpv6_proxy_config (vl_api_dhcp_proxy_config_t * mp) -{ - vl_api_dhcp_proxy_config_reply_t *rmp; - int rv = -1; - - rv = dhcpv6_proxy_set_server ((ip6_address_t *) (&mp->dhcp_server), - (ip6_address_t *) (&mp->dhcp_src_address), - (u32) ntohl (mp->rx_vrf_id), - (u32) ntohl (mp->server_vrf_id), - (int) (mp->is_add == 0)); - - REPLY_MACRO (VL_API_DHCP_PROXY_CONFIG_REPLY); -} - static void vl_api_dhcp_proxy_set_vss_t_handler (vl_api_dhcp_proxy_set_vss_t * mp) { vl_api_dhcp_proxy_set_vss_reply_t *rmp; int rv; - if (!mp->is_ipv6) - rv = dhcp_proxy_set_option82_vss (ntohl (mp->tbl_id), - ntohl (mp->oui), - ntohl (mp->fib_id), - (int) mp->is_add == 0); - else - rv = dhcpv6_proxy_set_vss (ntohl (mp->tbl_id), - ntohl (mp->oui), - ntohl (mp->fib_id), (int) mp->is_add == 0); + + rv = dhcp_proxy_set_vss ((mp->is_ipv6 ? + FIB_PROTOCOL_IP6 : + FIB_PROTOCOL_IP4), + ntohl (mp->tbl_id), + ntohl (mp->oui), + ntohl (mp->fib_id), (int) mp->is_add == 0); REPLY_MACRO (VL_API_DHCP_PROXY_SET_VSS_REPLY); } @@ -105,10 +71,38 @@ vl_api_dhcp_proxy_set_vss_t_handler (vl_api_dhcp_proxy_set_vss_t * mp) static void vl_api_dhcp_proxy_config_t_handler (vl_api_dhcp_proxy_config_t * mp) { - if (mp->is_ipv6 == 0) - dhcpv4_proxy_config (mp); + vl_api_dhcp_proxy_set_vss_reply_t *rmp; + ip46_address_t src, server; + int rv = -1; + + if (mp->is_ipv6) + { + clib_memcpy (&src.ip6, mp->dhcp_src_address, sizeof (src.ip6)); + clib_memcpy (&server.ip6, mp->dhcp_server, sizeof (server.ip6)); + + rv = dhcp6_proxy_set_server (&server, + &src, + (u32) ntohl (mp->rx_vrf_id), + (u32) ntohl (mp->server_vrf_id), + (int) (mp->is_add == 0)); + } else - dhcpv6_proxy_config (mp); + { + ip46_address_reset (&src); + ip46_address_reset (&server); + + clib_memcpy (&src.ip4, mp->dhcp_src_address, sizeof (src.ip4)); + clib_memcpy (&server.ip4, mp->dhcp_server, sizeof (server.ip4)); + + rv = dhcp4_proxy_set_server (&server, + &src, + (u32) ntohl (mp->rx_vrf_id), + (u32) ntohl (mp->server_vrf_id), + (int) (mp->is_add == 0)); + } + + + REPLY_MACRO (VL_API_DHCP_PROXY_CONFIG_REPLY); } static void @@ -120,14 +114,13 @@ vl_api_dhcp_proxy_dump_t_handler (vl_api_dhcp_proxy_dump_t * mp) if (q == 0) return; - if (mp->is_ip6 == 0) - dhcp_proxy_dump (q, mp->context); - else - dhcpv6_proxy_dump (q, mp->context); + dhcp_proxy_dump ((mp->is_ip6 == 0 ? + FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4), q, mp->context); } void -dhcp_send_details (void *opaque, +dhcp_send_details (fib_protocol_t proto, + void *opaque, u32 context, const ip46_address_t * server, const ip46_address_t * src, @@ -149,7 +142,7 @@ dhcp_send_details (void *opaque, mp->vss_oui = htonl (vss_oui); mp->vss_fib_id = htonl (vss_fib_id); - mp->is_ipv6 = !ip46_address_is_ip4 (server); + mp->is_ipv6 = (proto == FIB_PROTOCOL_IP6); if (mp->is_ipv6) { diff --git a/src/vnet/dhcp/dhcp_proxy.c b/src/vnet/dhcp/dhcp_proxy.c new file mode 100644 index 00000000..da2deea6 --- /dev/null +++ b/src/vnet/dhcp/dhcp_proxy.c @@ -0,0 +1,275 @@ +/* + * proxy_node.c: common dhcp v4 and v6 proxy node processing + * + * Copyright (c) 2013 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +/** + * @brief Shard 4/6 instance of DHCP main + */ +dhcp_proxy_main_t dhcp_proxy_main; + +void +dhcp_proxy_walk (fib_protocol_t proto, + dhcp_proxy_walk_fn_t fn, + void *ctx) +{ + dhcp_proxy_main_t * dpm = &dhcp_proxy_main; + dhcp_server_t * server; + u32 server_index, i; + + vec_foreach_index (i, dpm->dhcp_server_index_by_rx_fib_index[proto]) + { + server_index = dpm->dhcp_server_index_by_rx_fib_index[proto][i]; + if (~0 == server_index) + continue; + + server = pool_elt_at_index (dpm->dhcp_servers[proto], server_index); + + if (!fn(server, ctx)) + break; + } +} + +void +dhcp_vss_walk (fib_protocol_t proto, + dhcp_vss_walk_fn_t fn, + void *ctx) +{ + dhcp_proxy_main_t * dpm = &dhcp_proxy_main; + dhcp_vss_t * vss; + u32 vss_index, i; + fib_table_t *fib; + + + vec_foreach_index (i, dpm->vss_index_by_rx_fib_index[proto]) + { + vss_index = dpm->vss_index_by_rx_fib_index[proto][i]; + if (~0 == vss_index) + continue; + + vss = pool_elt_at_index (dpm->vss[proto], vss_index); + + fib = fib_table_get(i, proto); + + if (!fn(vss, fib->ft_table_id, ctx)) + break; + } +} + +int +dhcp_proxy_server_del (fib_protocol_t proto, + u32 rx_fib_index) +{ + dhcp_proxy_main_t * dpm = &dhcp_proxy_main; + dhcp_server_t * server = 0; + int rc = 0; + + server = dhcp_get_server(dpm, rx_fib_index, proto); + + if (NULL == server) + { + rc = VNET_API_ERROR_NO_SUCH_ENTRY; + } + else + { + /* Use the default server again. */ + dpm->dhcp_server_index_by_rx_fib_index[proto][rx_fib_index] = ~0; + + fib_table_unlock (server->server_fib_index, proto); + + pool_put (dpm->dhcp_servers[proto], server); + } + + return (rc); +} + +int +dhcp_proxy_server_add (fib_protocol_t proto, + ip46_address_t *addr, + ip46_address_t *src_address, + u32 rx_fib_index, + u32 server_table_id) +{ + dhcp_proxy_main_t * dpm = &dhcp_proxy_main; + dhcp_server_t * server = 0; + int new = 0; + + server = dhcp_get_server(dpm, rx_fib_index, proto); + + if (NULL == server) + { + vec_validate_init_empty(dpm->dhcp_server_index_by_rx_fib_index[proto], + rx_fib_index, + ~0); + + pool_get (dpm->dhcp_servers[proto], server); + memset (server, 0, sizeof (*server)); + new = 1; + + dpm->dhcp_server_index_by_rx_fib_index[proto][rx_fib_index] = + server - dpm->dhcp_servers[proto]; + + server->rx_fib_index = rx_fib_index; + server->server_fib_index = + fib_table_find_or_create_and_lock(proto, server_table_id); + } + else + { + /* modify, may need to swap server FIBs */ + u32 tmp_index; + + tmp_index = fib_table_find(proto, server_table_id); + + if (tmp_index != server->server_fib_index) + { + tmp_index = server->server_fib_index; + + /* certainly swapping if the fib doesn't exist */ + server->server_fib_index = + fib_table_find_or_create_and_lock(proto, server_table_id); + fib_table_unlock (tmp_index, proto); + } + } + + server->dhcp_server = *addr; + server->dhcp_src_address = *src_address; + + return (new); +} + +typedef struct dhcp4_proxy_dump_walk_ctx_t_ +{ + fib_protocol_t proto; + void *opaque; + u32 context; +} dhcp_proxy_dump_walk_cxt_t; + +static int +dhcp_proxy_dump_walk (dhcp_server_t *server, + void *arg) +{ + dhcp_proxy_dump_walk_cxt_t *ctx = arg; + fib_table_t *s_fib, *r_fib; + dhcp_vss_t *v; + + v = dhcp_get_vss_info(&dhcp_proxy_main, + server->rx_fib_index, + ctx->proto); + + s_fib = fib_table_get(server->server_fib_index, ctx->proto); + r_fib = fib_table_get(server->rx_fib_index, ctx->proto); + + dhcp_send_details(ctx->proto, + ctx->opaque, + ctx->context, + &server->dhcp_server, + &server->dhcp_src_address, + s_fib->ft_table_id, + r_fib->ft_table_id, + (v ? v->fib_id : 0), + (v ? v->oui : 0)); + + return (1); +} + +void +dhcp_proxy_dump (fib_protocol_t proto, + void *opaque, + u32 context) +{ + dhcp_proxy_dump_walk_cxt_t ctx = { + .proto = proto, + .opaque = opaque, + .context = context, + }; + dhcp_proxy_walk(proto, dhcp_proxy_dump_walk, &ctx); +} + +int +dhcp_vss_show_walk (dhcp_vss_t *vss, + u32 rx_table_id, + void *ctx) +{ + vlib_main_t * vm = ctx; + + vlib_cli_output (vm, "%=6d%=6d%=12d", + rx_table_id, + vss->oui, + vss->fib_id); + + return (1); +} + +int dhcp_proxy_set_vss (fib_protocol_t proto, + u32 tbl_id, + u32 oui, + u32 fib_id, + int is_del) +{ + dhcp_proxy_main_t *dm = &dhcp_proxy_main; + dhcp_vss_t *v = NULL; + u32 rx_fib_index; + int rc = 0; + + rx_fib_index = fib_table_find_or_create_and_lock(proto, tbl_id); + v = dhcp_get_vss_info(dm, rx_fib_index, proto); + + if (NULL != v) + { + if (is_del) + { + /* release the lock held on the table when the VSS + * info was created */ + fib_table_unlock (rx_fib_index, proto); + + pool_put (dm->vss[proto], v); + dm->vss_index_by_rx_fib_index[proto][rx_fib_index] = ~0; + } + else + { + /* this is a modify */ + v->fib_id = fib_id; + v->oui = oui; + } + } + else + { + if (is_del) + rc = VNET_API_ERROR_NO_SUCH_ENTRY; + else + { + /* create a new entry */ + vec_validate_init_empty(dm->vss_index_by_rx_fib_index[proto], + rx_fib_index, ~0); + + /* hold a lock on the table whilst the VSS info exist */ + fib_table_lock (rx_fib_index, proto); + + pool_get (dm->vss[proto], v); + v->fib_id = fib_id; + v->oui = oui; + dm->vss_index_by_rx_fib_index[proto][rx_fib_index] = + v - dm->vss[proto]; + } + } + + /* Release the lock taken during the create_or_lock at the start */ + fib_table_unlock (rx_fib_index, proto); + + return (rc); +} diff --git a/src/vnet/dhcp/dhcp_proxy.h b/src/vnet/dhcp/dhcp_proxy.h new file mode 100644 index 00000000..c0d79c41 --- /dev/null +++ b/src/vnet/dhcp/dhcp_proxy.h @@ -0,0 +1,248 @@ +/* + * dhcp_proxy.h: DHCP v4 & v6 proxy common functions/types + * + * Copyright (c) 2013 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef included_dhcp_proxy_h +#define included_dhcp_proxy_h + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef enum { +#define dhcp_proxy_error(n,s) DHCP_PROXY_ERROR_##n, +#include +#undef dhcp_proxy_error + DHCP_PROXY_N_ERROR, +} dhcp_proxy_error_t; + +typedef enum { +#define dhcpv6_proxy_error(n,s) DHCPV6_PROXY_ERROR_##n, +#include +#undef dhcpv6_proxy_error + DHCPV6_PROXY_N_ERROR, +} dhcpv6_proxy_error_t; + + +/** + * @brief The Virtual Sub-net Selection information for a given RX FIB + */ +typedef struct dhcp_vss_t_ { + /** + * @brief ?? RFC doesn't say + */ + u32 oui; + /** + * @brief VPN-ID + */ + u32 fib_id; +} dhcp_vss_t; + +/** + * @brief A DHCP proxy server represenation + */ +typedef struct dhcp_server_t_ { + /** + * @brief The address of the DHCP server to which to relay the client's + * messages + */ + ip46_address_t dhcp_server; + + /** + * @brief The source address to use in relayed messaes + */ + ip46_address_t dhcp_src_address; + + /** + * @brief The FIB index (not the external Table-ID) in which the server + * is reachable. + */ + u32 server_fib_index; + + /** + * @brief The FIB index (not the external Table-ID) in which the client + * is resides. + */ + u32 rx_fib_index; +} dhcp_server_t; + +#define DHCP_N_PROTOS (FIB_PROTOCOL_IP6 + 1) + +/** + * @brief Collection of global DHCP proxy data + */ +typedef struct { + /* Pool of DHCP servers */ + dhcp_server_t *dhcp_servers[DHCP_N_PROTOS]; + + /* Pool of selected DHCP server. Zero is the default server */ + u32 * dhcp_server_index_by_rx_fib_index[DHCP_N_PROTOS]; + + /* to drop pkts in server-to-client direction */ + u32 error_drop_node_index; + + dhcp_vss_t *vss[DHCP_N_PROTOS]; + + /* hash lookup specific vrf_id -> option 82 vss suboption */ + u32 *vss_index_by_rx_fib_index[DHCP_N_PROTOS]; + +} dhcp_proxy_main_t; + +extern dhcp_proxy_main_t dhcp_proxy_main; + +/** + * @brief Send the details of a proxy session to the API client during a dump + */ +void dhcp_send_details (fib_protocol_t proto, + void *opaque, + u32 context, + const ip46_address_t *server, + const ip46_address_t *src, + u32 server_fib_id, + u32 rx_fib_id, + u32 vss_fib_id, + u32 vss_oui); + +/** + * @brief Show (on CLI) a VSS config during a show walk + */ +int dhcp_vss_show_walk (dhcp_vss_t *vss, + u32 rx_table_id, + void *ctx); + +/** + * @brief Configure/set a new VSS info + */ +int dhcp_proxy_set_vss(fib_protocol_t proto, + u32 vrf_id, + u32 oui, + u32 fib_id, + int is_del); + +/** + * @brief Dump the proxy configs to the API + */ +void dhcp_proxy_dump(fib_protocol_t proto, + void *opaque, + u32 context); + +/** + * @brief Add a new DHCP proxy server configuration. + * @return 1 is the config is new, + * 0 otherwise (implying a modify of an existing) + */ +int dhcp_proxy_server_add(fib_protocol_t proto, + ip46_address_t *addr, + ip46_address_t *src_address, + u32 rx_fib_iindex, + u32 server_table_id); + +/** + * @brief Delete a DHCP proxy config + * @return 0 is deleted, otherwise an error code + */ +int dhcp_proxy_server_del(fib_protocol_t proto, + u32 rx_fib_index); + +/** + * @brief Callback function invoked for each DHCP proxy entry + * return 0 to break the walk, non-zero otherwise. + */ +typedef int (*dhcp_proxy_walk_fn_t)(dhcp_server_t *server, + void *ctx); + +/** + * @brief Walk/Visit each DHCP proxy server + */ +void dhcp_proxy_walk(fib_protocol_t proto, + dhcp_proxy_walk_fn_t fn, + void *ctx); + +/** + * @brief Callback function invoked for each DHCP VSS entry + * return 0 to break the walk, non-zero otherwise. + */ +typedef int (*dhcp_vss_walk_fn_t)(dhcp_vss_t *server, + u32 rx_table_id, + void *ctx); + +/** + * @brief Walk/Visit each DHCP proxy VSS + */ +void dhcp_vss_walk(fib_protocol_t proto, + dhcp_vss_walk_fn_t fn, + void *ctx); + +/** + * @brief Get the VSS data for the FIB index + */ +static inline dhcp_vss_t * +dhcp_get_vss_info (dhcp_proxy_main_t *dm, + u32 rx_fib_index, + fib_protocol_t proto) +{ + dhcp_vss_t *v = NULL; + + if (vec_len(dm->vss_index_by_rx_fib_index[proto]) > rx_fib_index && + dm->vss_index_by_rx_fib_index[proto][rx_fib_index] != ~0) + { + v = pool_elt_at_index ( + dm->vss[proto], + dm->vss_index_by_rx_fib_index[proto][rx_fib_index]); + } + + return (v); +} + +/** + * @brief Get the DHCP proxy server data for the FIB index + */ +static inline dhcp_server_t * +dhcp_get_server (dhcp_proxy_main_t *dm, + u32 rx_fib_index, + fib_protocol_t proto) +{ + dhcp_server_t *s = NULL; + + if (vec_len(dm->dhcp_server_index_by_rx_fib_index[proto]) > rx_fib_index && + dm->dhcp_server_index_by_rx_fib_index[proto][rx_fib_index] != ~0) + { + s = pool_elt_at_index ( + dm->dhcp_servers[proto], + dm->dhcp_server_index_by_rx_fib_index[proto][rx_fib_index]); + } + + return (s); +} + +int dhcp6_proxy_set_server (ip46_address_t *addr, + ip46_address_t *src_addr, + u32 rx_table_id, + u32 server_table_id, + int is_del); +int dhcp4_proxy_set_server (ip46_address_t *addr, + ip46_address_t *src_addr, + u32 rx_table_id, + u32 server_table_id, + int is_del); + +#endif /* included_dhcp_proxy_h */ diff --git a/src/vnet/dhcp/packet.h b/src/vnet/dhcp/packet.h deleted file mode 100644 index 267a8eaf..00000000 --- a/src/vnet/dhcp/packet.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef included_vnet_dhcp_packet_h -#define included_vnet_dhcp_packet_h - -/* - * DHCP packet format - * - * Copyright (c) 2013 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include - -typedef struct { - u8 opcode; /* 1 = request, 2 = reply */ - u8 hardware_type; /* 1 = ethernet */ - u8 hardware_address_length; - u8 hops; - u32 transaction_identifier; - u16 seconds; - u16 flags; -#define DHCP_FLAG_BROADCAST (1<<15) - ip4_address_t client_ip_address; - ip4_address_t your_ip_address; /* use this one */ - ip4_address_t server_ip_address; - ip4_address_t gateway_ip_address; /* use option 3, not this one */ - u8 client_hardware_address[16]; - u8 server_name[64]; - u8 boot_filename[128]; - ip4_address_t magic_cookie; - u8 options[0]; -} dhcp_header_t; - -typedef struct { - u8 option; - u8 length; - union { - u8 data[0]; - u32 data_as_u32[0]; - }; -} __attribute__((packed)) dhcp_option_t; - -typedef enum { - DHCP_PACKET_DISCOVER=1, - DHCP_PACKET_OFFER, - DHCP_PACKET_REQUEST, - DHCP_PACKET_ACK=5, -} dhcp_packet_type_t; - -/* charming antique: 99.130.83.99 is the dhcp magic cookie */ -#define DHCP_MAGIC (clib_host_to_net_u32(0x63825363)) - -#endif /* included_vnet_dhcp_packet_h */ diff --git a/src/vnet/dhcp/proxy.h b/src/vnet/dhcp/proxy.h deleted file mode 100644 index 4b115c74..00000000 --- a/src/vnet/dhcp/proxy.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * proxy.h: dhcp proxy - * - * Copyright (c) 2013 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef included_dhcp_proxy_h -#define included_dhcp_proxy_h - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -typedef enum { -#define dhcp_proxy_error(n,s) DHCP_PROXY_ERROR_##n, -#include -#undef dhcp_proxy_error - DHCP_PROXY_N_ERROR, -} dhcp_proxy_error_t; - -typedef struct { - u32 oui; - u32 fib_id; -} vss_id; - -typedef union { - u8 as_u8[8]; - vss_id vpn_id; -} vss_info; - -typedef struct { - ip4_address_t dhcp_server; - ip4_address_t dhcp_src_address; - u32 server_fib_index; -} dhcp_server_t; - -typedef struct { - /* Pool of DHCP servers */ - dhcp_server_t * dhcp_servers; - - /* Pool of selected DHCP server. Zero is the default server */ - u32 * dhcp_server_index_by_rx_fib_index; - - /* to drop pkts in server-to-client direction */ - u32 error_drop_node_index; - - vss_info *vss; - - /* hash lookup specific vrf_id -> option 82 vss suboption */ - u32 *vss_index_by_rx_fib_index; - - /* convenience */ - vlib_main_t * vlib_main; - vnet_main_t * vnet_main; -} dhcp_proxy_main_t; - -extern dhcp_proxy_main_t dhcp_proxy_main; - -void dhcp_send_details (void *opaque, - u32 context, - const ip46_address_t *server, - const ip46_address_t *src, - u32 server_fib_id, - u32 rx_fib_id, - u32 vss_fib_id, - u32 vss_oui); - -int dhcp_proxy_set_server (ip4_address_t *addr, - ip4_address_t *src_address, - u32 fib_id, - u32 server_fib_id, - int is_del); - -int dhcp_proxy_set_option82_vss(u32 vrf_id, - u32 oui, - u32 fib_id, - int is_del); - -void dhcp_proxy_dump(void *opaque, - u32 context); - -#endif /* included_dhcp_proxy_h */ diff --git a/src/vnet/dhcp/proxy_error.def b/src/vnet/dhcp/proxy_error.def deleted file mode 100644 index 6d790d73..00000000 --- a/src/vnet/dhcp/proxy_error.def +++ /dev/null @@ -1,31 +0,0 @@ -/* - * dhcp_proxy_error.def: dhcp proxy errors - * - * Copyright (c) 2013 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -dhcp_proxy_error (NONE, "no error") -dhcp_proxy_error (NO_SERVER, "no dhcp server configured") -dhcp_proxy_error (RELAY_TO_SERVER, "DHCP packets relayed to the server") -dhcp_proxy_error (RELAY_TO_CLIENT, "DHCP packets relayed to clients") -dhcp_proxy_error (OPTION_82_ERROR, "DHCP failed to insert option 82") -dhcp_proxy_error (NO_OPTION_82, "DHCP option 82 missing") -dhcp_proxy_error (BAD_OPTION_82_ITF, "Bad DHCP option 82 interface value") -dhcp_proxy_error (BAD_OPTION_82_ADDR, "Bad DHCP option 82 address value") -dhcp_proxy_error (BAD_FIB_ID, "DHCP option 82 fib-id to fib-index map failure") -dhcp_proxy_error (NO_INTERFACE_ADDRESS, "DHCP no interface address") -dhcp_proxy_error (OPTION_82_VSS_NOT_PROCESSED, "DHCP VSS not processed by DHCP server") -dhcp_proxy_error (BAD_YIADDR, "DHCP packets with bad your_ip_address fields") -dhcp_proxy_error (BAD_SVR_FIB_OR_ADDRESS, "DHCP packets not from DHCP server or server FIB.") -dhcp_proxy_error (PKT_TOO_BIG, "DHCP packets which are too big.") diff --git a/src/vnet/dhcp/proxy_node.c b/src/vnet/dhcp/proxy_node.c deleted file mode 100644 index ab6819fe..00000000 --- a/src/vnet/dhcp/proxy_node.c +++ /dev/null @@ -1,1192 +0,0 @@ -/* - * proxy_node.c: dhcp proxy node processing - * - * Copyright (c) 2013 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include - -static char * dhcp_proxy_error_strings[] = { -#define dhcp_proxy_error(n,s) s, -#include "proxy_error.def" -#undef dhcp_proxy_error -}; - -#define foreach_dhcp_proxy_to_server_input_next \ - _ (DROP, "error-drop") \ - _ (LOOKUP, "ip4-lookup") \ - _ (SEND_TO_CLIENT, "dhcp-proxy-to-client") - -typedef enum { -#define _(s,n) DHCP_PROXY_TO_SERVER_INPUT_NEXT_##s, - foreach_dhcp_proxy_to_server_input_next -#undef _ - DHCP_PROXY_TO_SERVER_INPUT_N_NEXT, -} dhcp_proxy_to_server_input_next_t; - -typedef struct { - /* 0 => to server, 1 => to client */ - int which; - ip4_address_t trace_ip4_address; - u32 error; - u32 sw_if_index; - u32 original_sw_if_index; -} dhcp_proxy_trace_t; - -#define VPP_DHCP_OPTION82_SUB1_SIZE 6 -#define VPP_DHCP_OPTION82_SUB5_SIZE 6 -#define VPP_DHCP_OPTION82_VSS_SIZE 12 -#define VPP_DHCP_OPTION82_SIZE (VPP_DHCP_OPTION82_SUB1_SIZE + \ - VPP_DHCP_OPTION82_SUB5_SIZE + \ - VPP_DHCP_OPTION82_VSS_SIZE +3) - -vlib_node_registration_t dhcp_proxy_to_server_node; -vlib_node_registration_t dhcp_proxy_to_client_node; - -dhcp_proxy_main_t dhcp_proxy_main; - -u8 * format_dhcp_proxy_trace (u8 * s, va_list * args) -{ - CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); - CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); - dhcp_proxy_trace_t * t = va_arg (*args, dhcp_proxy_trace_t *); - - if (t->which == 0) - s = format (s, "DHCP proxy: sent to server %U\n", - format_ip4_address, &t->trace_ip4_address, t->error); - else - s = format (s, "DHCP proxy: broadcast to client from %U\n", - format_ip4_address, &t->trace_ip4_address); - - if (t->error != (u32)~0) - s = format (s, " error: %s\n", dhcp_proxy_error_strings[t->error]); - - s = format (s, " original_sw_if_index: %d, sw_if_index: %d\n", - t->original_sw_if_index, t->sw_if_index); - - return s; -} - -u8 * format_dhcp_proxy_header_with_length (u8 * s, va_list * args) -{ - dhcp_header_t * h = va_arg (*args, dhcp_header_t *); - u32 max_header_bytes = va_arg (*args, u32); - u32 header_bytes; - - header_bytes = sizeof (h[0]); - if (max_header_bytes != 0 && header_bytes > max_header_bytes) - return format (s, "dhcp header truncated"); - - s = format (s, "DHCP Proxy"); - - return s; -} - -static inline vss_info * -dhcp_get_vss_info (dhcp_proxy_main_t *dm, - u32 rx_fib_index) -{ - vss_info *v; - - if (vec_len(dm->vss_index_by_rx_fib_index) <= rx_fib_index || - dm->vss_index_by_rx_fib_index[rx_fib_index] == ~0) - { - v = NULL; - } - else - { - v = pool_elt_at_index (dm->vss, - dm->vss_index_by_rx_fib_index[rx_fib_index]); - } - - return (v); -} - -static inline dhcp_server_t * -dhcp_get_server (dhcp_proxy_main_t *dm, - u32 rx_fib_index) -{ - dhcp_server_t *s = NULL; - - if (vec_len(dm->dhcp_server_index_by_rx_fib_index) > rx_fib_index && - dm->dhcp_server_index_by_rx_fib_index[rx_fib_index] != ~0) - { - s = pool_elt_at_index (dm->dhcp_servers, - dm->dhcp_server_index_by_rx_fib_index[rx_fib_index]); - } - - return (s); -} - -static uword -dhcp_proxy_to_server_input (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * from_frame) -{ - u32 n_left_from, next_index, * from, * to_next; - dhcp_proxy_main_t * dpm = &dhcp_proxy_main; - from = vlib_frame_vector_args (from_frame); - n_left_from = from_frame->n_vectors; - u32 pkts_to_server=0, pkts_to_client=0, pkts_no_server=0; - u32 pkts_no_interface_address=0; - u32 pkts_too_big=0; - ip4_main_t * im = &ip4_main; - - next_index = node->cached_next_index; - - while (n_left_from > 0) - { - 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) - { - u32 bi0; - vlib_buffer_t * b0; - udp_header_t * u0; - dhcp_header_t * h0; - ip4_header_t * ip0; - u32 next0; - u32 old0, new0; - ip_csum_t sum0; - u32 error0 = (u32) ~0; - u32 sw_if_index = 0; - u32 original_sw_if_index = 0; - u8 *end = NULL; - u32 fib_index; - dhcp_server_t * server; - u32 rx_sw_if_index; - dhcp_option_t *o; - u32 len = 0; - vlib_buffer_free_list_t *fl; - - bi0 = from[0]; - to_next[0] = bi0; - from += 1; - to_next += 1; - n_left_from -= 1; - n_left_to_next -= 1; - - b0 = vlib_get_buffer (vm, bi0); - - h0 = vlib_buffer_get_current (b0); - - /* - * udp_local hands us the DHCP header, need udp hdr, - * ip hdr to relay to server - */ - vlib_buffer_advance (b0, -(sizeof(*u0))); - u0 = vlib_buffer_get_current (b0); - - /* This blows. Return traffic has src_port = 67, dst_port = 67 */ - if (u0->src_port == clib_net_to_host_u16(UDP_DST_PORT_dhcp_to_server)) - { - vlib_buffer_advance (b0, sizeof(*u0)); - next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_SEND_TO_CLIENT; - error0 = 0; - pkts_to_client++; - goto do_enqueue; - } - - rx_sw_if_index = vnet_buffer(b0)->sw_if_index[VLIB_RX]; - - fib_index = im->fib_index_by_sw_if_index [rx_sw_if_index]; - server = dhcp_get_server(dpm, fib_index); - - if (PREDICT_FALSE (NULL == server)) - { - error0 = DHCP_PROXY_ERROR_NO_SERVER; - next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_DROP; - pkts_no_server++; - goto do_trace; - } - - vlib_buffer_advance (b0, -(sizeof(*ip0))); - ip0 = vlib_buffer_get_current (b0); - - /* disable UDP checksum */ - u0->checksum = 0; - sum0 = ip0->checksum; - old0 = ip0->dst_address.as_u32; - new0 = server->dhcp_server.as_u32; - ip0->dst_address.as_u32 = server->dhcp_server.as_u32; - sum0 = ip_csum_update (sum0, old0, new0, - ip4_header_t /* structure */, - dst_address /* changed member */); - ip0->checksum = ip_csum_fold (sum0); - - sum0 = ip0->checksum; - old0 = ip0->src_address.as_u32; - new0 = server->dhcp_src_address.as_u32; - ip0->src_address.as_u32 = new0; - sum0 = ip_csum_update (sum0, old0, new0, - ip4_header_t /* structure */, - src_address /* changed member */); - ip0->checksum = ip_csum_fold (sum0); - - /* Send to DHCP server via the configured FIB */ - vnet_buffer(b0)->sw_if_index[VLIB_TX] = - server->server_fib_index; - - h0->gateway_ip_address.as_u32 = server->dhcp_src_address.as_u32; - pkts_to_server++; - - o = (dhcp_option_t *) h0->options; - - fib_index = im->fib_index_by_sw_if_index - [vnet_buffer(b0)->sw_if_index[VLIB_RX]]; - - end = b0->data + b0->current_data + b0->current_length; - /* TLVs are not performance-friendly... */ - while (o->option != 0xFF /* end of options */ && (u8 *)o < end) - o = (dhcp_option_t *) (((uword) o) + (o->length + 2)); - - fl = vlib_buffer_get_free_list (vm, b0->free_list_index); - // start write at (option*)o, some packets have padding - if (((u8 *)o - (u8 *)b0->data + VPP_DHCP_OPTION82_SIZE) > fl->n_data_bytes) - { - next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_DROP; - pkts_too_big++; - goto do_trace; - } - - if ((o->option == 0xFF) && ((u8 *)o <= end)) - { - vnet_main_t *vnm = vnet_get_main(); - u16 old_l0, new_l0; - ip4_address_t _ia0, * ia0 = &_ia0; - vss_info *vss; - vnet_sw_interface_t *swif; - sw_if_index = 0; - original_sw_if_index = 0; - - original_sw_if_index = sw_if_index = - vnet_buffer(b0)->sw_if_index[VLIB_RX]; - swif = vnet_get_sw_interface (vnm, sw_if_index); - if (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED) - sw_if_index = swif->unnumbered_sw_if_index; - - /* - * Get the first ip4 address on the [client-side] - * RX interface, if not unnumbered. otherwise use - * the loopback interface's ip address. - */ - ia0 = ip4_interface_first_address(&ip4_main, sw_if_index, 0); - - if (ia0 == 0) - { - error0 = DHCP_PROXY_ERROR_NO_INTERFACE_ADDRESS; - next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_DROP; - pkts_no_interface_address++; - goto do_trace; - } - - /* Add option 82 */ - o->option = 82; /* option 82 */ - o->length = 12; /* 12 octets to follow */ - o->data[0] = 1; /* suboption 1, circuit ID (=FIB id) */ - o->data[1] = 4; /* length of suboption */ - o->data[2] = (original_sw_if_index >> 24) & 0xFF; - o->data[3] = (original_sw_if_index >> 16) & 0xFF; - o->data[4] = (original_sw_if_index >> 8) & 0xFF; - o->data[5] = (original_sw_if_index >> 0) & 0xFF; - o->data[6] = 5; /* suboption 5 (client RX intfc address) */ - o->data[7] = 4; /* length 4 */ - o->data[8] = ia0->as_u8[0]; - o->data[9] = ia0->as_u8[1]; - o->data[10] = ia0->as_u8[2]; - o->data[11] = ia0->as_u8[3]; - o->data[12] = 0xFF; - - vss = dhcp_get_vss_info (dpm, fib_index); - if (NULL != vss) - { - u32 opt82_fib_id=0, opt82_oui=0; - - opt82_oui = vss->vpn_id.oui; - opt82_fib_id = vss->vpn_id.fib_id; - - o->data[12] = 151; /* vss suboption */ - if (255 == opt82_fib_id) { - o->data[13] = 1; /* length */ - o->data[14] = 255; /* vss option type */ - o->data[15] = 152; /* vss control suboption */ - o->data[16] = 0; /* length */ - /* and a new "end-of-options" option (0xff) */ - o->data[17] = 0xFF; - o->length += 5; - } else { - o->data[13] = 8; /* length */ - o->data[14] = 1; /* vss option type */ - o->data[15] = (opt82_oui >> 16) & 0xff; - o->data[16] = (opt82_oui >> 8) & 0xff; - o->data[17] = (opt82_oui ) & 0xff; - o->data[18] = (opt82_fib_id >> 24) & 0xff; - o->data[19] = (opt82_fib_id >> 16) & 0xff; - o->data[20] = (opt82_fib_id >> 8) & 0xff; - o->data[21] = (opt82_fib_id) & 0xff; - o->data[22] = 152; /* vss control suboption */ - o->data[23] = 0; /* length */ - - /* and a new "end-of-options" option (0xff) */ - o->data[24] = 0xFF; - o->length += 12; - } - } - - len = o->length + 3; - b0->current_length += len; - /* Fix IP header length and checksum */ - old_l0 = ip0->length; - new_l0 = clib_net_to_host_u16 (old_l0); - new_l0 += len; - new_l0 = clib_host_to_net_u16 (new_l0); - ip0->length = new_l0; - sum0 = ip0->checksum; - sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t, - length /* changed member */); - ip0->checksum = ip_csum_fold (sum0); - - /* Fix UDP length */ - new_l0 = clib_net_to_host_u16 (u0->length); - new_l0 += len; - u0->length = clib_host_to_net_u16 (new_l0); - } else { - vlib_node_increment_counter - (vm, dhcp_proxy_to_server_node.index, - DHCP_PROXY_ERROR_OPTION_82_ERROR, 1); - } - - next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP; - - do_trace: - if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) - { - dhcp_proxy_trace_t *tr = vlib_add_trace (vm, node, - b0, sizeof (*tr)); - tr->which = 0; /* to server */ - tr->error = error0; - tr->original_sw_if_index = original_sw_if_index; - tr->sw_if_index = sw_if_index; - if (next0 == DHCP_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP) - tr->trace_ip4_address.as_u32 = server->dhcp_server.as_u32; - } - - do_enqueue: - 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); - } - - vlib_node_increment_counter (vm, dhcp_proxy_to_server_node.index, - DHCP_PROXY_ERROR_RELAY_TO_CLIENT, - pkts_to_client); - vlib_node_increment_counter (vm, dhcp_proxy_to_server_node.index, - DHCP_PROXY_ERROR_RELAY_TO_SERVER, - pkts_to_server); - vlib_node_increment_counter (vm, dhcp_proxy_to_server_node.index, - DHCP_PROXY_ERROR_NO_SERVER, - pkts_no_server); - vlib_node_increment_counter (vm, dhcp_proxy_to_server_node.index, - DHCP_PROXY_ERROR_NO_INTERFACE_ADDRESS, - pkts_no_interface_address); - vlib_node_increment_counter (vm, dhcp_proxy_to_server_node.index, - DHCP_PROXY_ERROR_PKT_TOO_BIG, - pkts_too_big); - return from_frame->n_vectors; -} - -VLIB_REGISTER_NODE (dhcp_proxy_to_server_node) = { - .function = dhcp_proxy_to_server_input, - .name = "dhcp-proxy-to-server", - /* Takes a vector of packets. */ - .vector_size = sizeof (u32), - - .n_errors = DHCP_PROXY_N_ERROR, - .error_strings = dhcp_proxy_error_strings, - - .n_next_nodes = DHCP_PROXY_TO_SERVER_INPUT_N_NEXT, - .next_nodes = { -#define _(s,n) [DHCP_PROXY_TO_SERVER_INPUT_NEXT_##s] = n, - foreach_dhcp_proxy_to_server_input_next -#undef _ - }, - - .format_buffer = format_dhcp_proxy_header_with_length, - .format_trace = format_dhcp_proxy_trace, -#if 0 - .unformat_buffer = unformat_dhcp_proxy_header, -#endif -}; - -static uword -dhcp_proxy_to_client_input (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * from_frame) -{ - u32 n_left_from, * from; - ethernet_main_t *em = ethernet_get_main (vm); - dhcp_proxy_main_t * dpm = &dhcp_proxy_main; - vnet_main_t * vnm = vnet_get_main(); - ip4_main_t * im = &ip4_main; - - from = vlib_frame_vector_args (from_frame); - n_left_from = from_frame->n_vectors; - - while (n_left_from > 0) - { - u32 bi0; - vlib_buffer_t * b0; - udp_header_t * u0; - dhcp_header_t * h0; - ip4_header_t * ip0 = 0; - ip4_address_t * ia0 = 0; - u32 old0, new0; - ip_csum_t sum0; - 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; - vnet_sw_interface_t *si0; - u32 error0 = (u32)~0; - vnet_sw_interface_t *swif; - u32 fib_index; - dhcp_server_t * server; - u32 original_sw_if_index = (u32) ~0; - ip4_address_t relay_addr = { - .as_u32 = 0, - }; - - bi0 = from[0]; - from += 1; - n_left_from -= 1; - - b0 = vlib_get_buffer (vm, bi0); - h0 = vlib_buffer_get_current (b0); - - /* - * udp_local hands us the DHCP header, need udp hdr, - * ip hdr to relay to client - */ - vlib_buffer_advance (b0, -(sizeof(*u0))); - u0 = vlib_buffer_get_current (b0); - - vlib_buffer_advance (b0, -(sizeof(*ip0))); - ip0 = vlib_buffer_get_current (b0); - - /* Consumed by dhcp client code? */ - if (dhcp_client_for_us (bi0, b0, ip0, u0, h0)) - continue; - - if (1 /* dpm->insert_option_82 */) - { - dhcp_option_t *o = (dhcp_option_t *) h0->options; - dhcp_option_t *sub; - - /* Parse through TLVs looking for option 82. - The circuit-ID is the FIB number we need - to track down the client-facing interface */ - - while (o->option != 0xFF /* end of options */ && - (u8 *) o < (b0->data + b0->current_data + b0->current_length)) - { - if (o->option == 82) - { - u32 vss_exist = 0; - u32 vss_ctrl = 0; - sub = (dhcp_option_t *) &o->data[0]; - while (sub->option != 0xFF /* end of options */ && - (u8 *) sub < (u8 *)(o + o->length)) { - /* If this is one of ours, it will have - total length 12, circuit-id suboption type, - and the sw_if_index */ - if (sub->option == 1 && sub->length == 4) - { - sw_if_index = ((sub->data[0] << 24) | - (sub->data[1] << 16) | - (sub->data[2] << 8) | - (sub->data[3])); - } - else if (sub->option == 5 && sub->length == 4) - { - relay_addr.as_u8[0] = sub->data[0]; - relay_addr.as_u8[1] = sub->data[1]; - relay_addr.as_u8[2] = sub->data[2]; - relay_addr.as_u8[3] = sub->data[3]; - } - else if (sub->option == 151 && - sub->length == 7 && - sub->data[0] == 1) - vss_exist = 1; - else if (sub->option == 152 && sub->length == 0) - vss_ctrl = 1; - sub = (dhcp_option_t *) - (((uword) sub) + (sub->length + 2)); - } - if (vss_ctrl && vss_exist) - vlib_node_increment_counter - (vm, dhcp_proxy_to_client_node.index, - DHCP_PROXY_ERROR_OPTION_82_VSS_NOT_PROCESSED, 1); - - } - o = (dhcp_option_t *) (((uword) o) + (o->length + 2)); - } - } - - if (sw_if_index == (u32)~0) - { - error0 = DHCP_PROXY_ERROR_NO_OPTION_82; - - drop_packet: - vlib_node_increment_counter (vm, dhcp_proxy_to_client_node.index, - error0, 1); - f0 = vlib_get_frame_to_node (vm, dpm->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, dpm->error_drop_node_index, f0); - goto do_trace; - } - - if (relay_addr.as_u32 == 0) - { - error0 = DHCP_PROXY_ERROR_BAD_OPTION_82_ADDR; - goto drop_packet; - } - - if (sw_if_index >= vec_len (im->fib_index_by_sw_if_index)) - { - error0 = DHCP_PROXY_ERROR_BAD_OPTION_82_ITF; - goto drop_packet; - } - - fib_index = im->fib_index_by_sw_if_index [sw_if_index]; - server = dhcp_get_server(dpm, fib_index); - - if (PREDICT_FALSE (NULL == server)) - { - error0 = DHCP_PROXY_ERROR_NO_SERVER; - goto drop_packet; - } - - if (ip0->src_address.as_u32 != server->dhcp_server.as_u32) - { - error0 = DHCP_PROXY_ERROR_BAD_SVR_FIB_OR_ADDRESS; - goto drop_packet; - } - - vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index; - - swif = vnet_get_sw_interface (vnm, sw_if_index); - original_sw_if_index = sw_if_index; - if (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED) - sw_if_index = swif->unnumbered_sw_if_index; - - ia0 = ip4_interface_first_address (&ip4_main, sw_if_index, 0); - if (ia0 == 0) - { - error0 = DHCP_PROXY_ERROR_NO_INTERFACE_ADDRESS; - goto drop_packet; - } - - if (relay_addr.as_u32 != ia0->as_u32) - { - error0 = DHCP_PROXY_ERROR_BAD_YIADDR; - goto drop_packet; - } - - u0->checksum = 0; - u0->dst_port = clib_net_to_host_u16 (UDP_DST_PORT_dhcp_to_client); - sum0 = ip0->checksum; - old0 = ip0->dst_address.as_u32; - new0 = 0xFFFFFFFF; - ip0->dst_address.as_u32 = new0; - sum0 = ip_csum_update (sum0, old0, new0, - ip4_header_t /* structure */, - dst_address /* offset of changed member */); - ip0->checksum = ip_csum_fold (sum0); - - sum0 = ip0->checksum; - old0 = ip0->src_address.as_u32; - new0 = ia0->as_u32; - ip0->src_address.as_u32 = new0; - sum0 = ip_csum_update (sum0, old0, new0, - ip4_header_t /* structure */, - src_address /* offset of changed member */); - ip0->checksum = ip_csum_fold (sum0); - - 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) - vlib_buffer_advance (b0, -4 /* space for VLAN tag */); - - mac0 = vlib_buffer_get_current (b0); - - 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 (ei0->address)); - memset (mac0->dst_address, 0xff, sizeof (mac0->dst_address)); - mac0->type = (si0->type == VNET_SW_INTERFACE_TYPE_SUB) ? - clib_net_to_host_u16(0x8100) : clib_net_to_host_u16 (0x0800); - - if (si0->type == VNET_SW_INTERFACE_TYPE_SUB) - { - u32 * vlan_tag = (u32 *)(mac0+1); - u32 tmp; - tmp = (si0->sub.id << 16) | 0x0800; - *vlan_tag = clib_host_to_net_u32 (tmp); - } - - /* $$$ This needs to be rewritten, for sure */ - 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)) - { - dhcp_proxy_trace_t *tr = vlib_add_trace (vm, node, - b0, sizeof (*tr)); - tr->which = 1; /* to client */ - tr->trace_ip4_address.as_u32 = ia0 ? ia0->as_u32 : 0; - tr->error = error0; - tr->original_sw_if_index = original_sw_if_index; - tr->sw_if_index = sw_if_index; - } - } - return from_frame->n_vectors; -} - -VLIB_REGISTER_NODE (dhcp_proxy_to_client_node) = { - .function = dhcp_proxy_to_client_input, - .name = "dhcp-proxy-to-client", - /* Takes a vector of packets. */ - .vector_size = sizeof (u32), - - .n_errors = DHCP_PROXY_N_ERROR, - .error_strings = dhcp_proxy_error_strings, - .format_buffer = format_dhcp_proxy_header_with_length, - .format_trace = format_dhcp_proxy_trace, -#if 0 - .unformat_buffer = unformat_dhcp_proxy_header, -#endif -}; - -clib_error_t * dhcp_proxy_init (vlib_main_t * vm) -{ - dhcp_proxy_main_t * dm = &dhcp_proxy_main; - vlib_node_t * error_drop_node; - dhcp_server_t * server; - - dm->vlib_main = vm; - dm->vnet_main = vnet_get_main(); - error_drop_node = vlib_get_node_by_name (vm, (u8 *) "error-drop"); - dm->error_drop_node_index = error_drop_node->index; - - dm->vss_index_by_rx_fib_index = NULL; - - udp_register_dst_port (vm, UDP_DST_PORT_dhcp_to_client, - dhcp_proxy_to_client_node.index, 1 /* is_ip4 */); - - udp_register_dst_port (vm, UDP_DST_PORT_dhcp_to_server, - dhcp_proxy_to_server_node.index, 1 /* is_ip4 */); - - /* Create the default server, don't mark it valid */ - pool_get (dm->dhcp_servers, server); - memset (server, 0, sizeof (*server)); - - return 0; -} - -VLIB_INIT_FUNCTION (dhcp_proxy_init); - -int dhcp_proxy_set_server (ip4_address_t *addr, - ip4_address_t *src_address, - u32 rx_fib_id, - u32 server_fib_id, - int is_del) -{ - dhcp_proxy_main_t * dpm = &dhcp_proxy_main; - dhcp_server_t * server = 0; - u32 server_index = 0; - u32 rx_fib_index = 0; - - const fib_prefix_t all_1s = - { - .fp_len = 32, - .fp_addr.ip4.as_u32 = 0xffffffff, - .fp_proto = FIB_PROTOCOL_IP4, - }; - - if (addr->as_u32 == 0) - return VNET_API_ERROR_INVALID_DST_ADDRESS; - - if (src_address->as_u32 == 0) - return VNET_API_ERROR_INVALID_SRC_ADDRESS; - - rx_fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, - rx_fib_id); - - if (is_del) - { - if (rx_fib_index >= vec_len(dpm->dhcp_server_index_by_rx_fib_index)) - return VNET_API_ERROR_NO_SUCH_ENTRY; - - server_index = dpm->dhcp_server_index_by_rx_fib_index[rx_fib_index]; - - if (server_index == ~0) - return VNET_API_ERROR_NO_SUCH_ENTRY; - - /* Use the default server again. */ - dpm->dhcp_server_index_by_rx_fib_index[rx_fib_index] = ~0; - server = pool_elt_at_index (dpm->dhcp_servers, server_index); - - fib_table_entry_special_remove(rx_fib_index, - &all_1s, - FIB_SOURCE_DHCP); - fib_table_unlock (rx_fib_index, - FIB_PROTOCOL_IP4); - fib_table_unlock (server->server_fib_index, - FIB_PROTOCOL_IP4); - - memset (server, 0, sizeof (*server)); - pool_put (dpm->dhcp_servers, server); - return 0; - } - else - { - vec_validate_init_empty(dpm->dhcp_server_index_by_rx_fib_index, - rx_fib_index, - ~0); - - pool_get (dpm->dhcp_servers, server); - - server->dhcp_server.as_u32 = addr->as_u32; - server->dhcp_src_address.as_u32 = src_address->as_u32; - - fib_table_entry_special_add(rx_fib_index, - &all_1s, - FIB_SOURCE_DHCP, - FIB_ENTRY_FLAG_LOCAL, - ADJ_INDEX_INVALID); - fib_table_lock (rx_fib_index, - FIB_PROTOCOL_IP4); - - server->server_fib_index = - fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, - server_fib_id); - - vec_validate_init_empty (dpm->dhcp_server_index_by_rx_fib_index, - rx_fib_index, - ~0); - dpm->dhcp_server_index_by_rx_fib_index[rx_fib_index] = - server - dpm->dhcp_servers; - } - - fib_table_unlock (rx_fib_index, - FIB_PROTOCOL_IP4); - - return 0; -} - -static clib_error_t * -dhcp_proxy_set_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - ip4_address_t server_addr, src_addr; - u32 server_fib_id = 0, rx_fib_id = 0; - int is_del = 0; - int set_src = 0, set_server = 0; - - while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (input, "server %U", - unformat_ip4_address, &server_addr)) - set_server = 1; - else if (unformat (input, "server-fib-id %d", &server_fib_id)) - ; - else if (unformat (input, "rx-fib-id %d", &rx_fib_id)) - ; - else if (unformat(input, "src-address %U", - unformat_ip4_address, &src_addr)) - set_src = 1; - else if (unformat (input, "delete") || - unformat (input, "del")) - is_del = 1; - else - break; - } - - if (is_del || (set_server && set_src)) - { - int rv; - - rv = dhcp_proxy_set_server (&server_addr, &src_addr, rx_fib_id, - server_fib_id, is_del); - switch (rv) - { - case 0: - return 0; - - case VNET_API_ERROR_INVALID_DST_ADDRESS: - return clib_error_return (0, "Invalid server address"); - - case VNET_API_ERROR_INVALID_SRC_ADDRESS: - return clib_error_return (0, "Invalid src address"); - - case VNET_API_ERROR_NO_SUCH_INNER_FIB: - return clib_error_return (0, "No such rx fib id %d", rx_fib_id); - - case VNET_API_ERROR_NO_SUCH_FIB: - return clib_error_return (0, "No such server fib id %d", - server_fib_id); - - case VNET_API_ERROR_NO_SUCH_ENTRY: - return clib_error_return - (0, "Fib id %d: no per-fib DHCP server configured", rx_fib_id); - - default: - return clib_error_return (0, "BUG: rv %d", rv); - } - } - else - return clib_error_return (0, "parse error`%U'", - format_unformat_error, input); -} - -VLIB_CLI_COMMAND (dhcp_proxy_set_command, static) = { - .path = "set dhcp proxy", - .short_help = "set dhcp proxy [del] server src-address [server-fib-id ] [rx-fib-id ]", - .function = dhcp_proxy_set_command_fn, -}; - -u8 * format_dhcp_proxy_server (u8 * s, va_list * args) -{ - dhcp_proxy_main_t * dm = va_arg (*args, dhcp_proxy_main_t *); - dhcp_server_t * server = va_arg (*args, dhcp_server_t *); - u32 rx_fib_index = va_arg (*args, u32); - ip4_fib_t * rx_fib, * server_fib; - u32 server_fib_id = ~0, rx_fib_id = ~0; - - if (dm == 0) - { - s = format (s, "%=16s%=16s%=14s%=14s", "Server", "Src Address", - "Server FIB", "RX FIB"); - return s; - } - - server_fib = ip4_fib_get(server->server_fib_index); - - if (server_fib) - server_fib_id = server_fib->table_id; - - rx_fib = ip4_fib_get(rx_fib_index); - - if (rx_fib) - rx_fib_id = rx_fib->table_id; - - s = format (s, "%=16U%=16U%=14u%=14u", - format_ip4_address, &server->dhcp_server, - format_ip4_address, &server->dhcp_src_address, - server_fib_id, rx_fib_id); - return s; -} - -static clib_error_t * -dhcp_proxy_show_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - dhcp_proxy_main_t * dpm = &dhcp_proxy_main; - dhcp_server_t * server; - u32 server_index, i; - - vlib_cli_output (vm, "%U", format_dhcp_proxy_server, 0 /* header line */, - 0, 0); - - vec_foreach_index (i, dpm->dhcp_server_index_by_rx_fib_index) - { - server_index = dpm->dhcp_server_index_by_rx_fib_index[i]; - if (~0 == server_index) - continue; - - server = pool_elt_at_index (dpm->dhcp_servers, server_index); - - vlib_cli_output (vm, "%U", format_dhcp_proxy_server, dpm, - server, i); - } - - return 0; -} - -VLIB_CLI_COMMAND (dhcp_proxy_show_command, static) = { - .path = "show dhcp proxy", - .short_help = "Display dhcp proxy server info", - .function = dhcp_proxy_show_command_fn, -}; - -void -dhcp_proxy_dump (void *opaque, - u32 context) -{ - dhcp_proxy_main_t * dpm = &dhcp_proxy_main; - ip4_fib_t *s_fib, *r_fib; - dhcp_server_t * server; - u32 server_index, i; - vss_info *v; - - vec_foreach_index (i, dpm->dhcp_server_index_by_rx_fib_index) - { - server_index = dpm->dhcp_server_index_by_rx_fib_index[i]; - if (~0 == server_index) - continue; - - server = pool_elt_at_index (dpm->dhcp_servers, server_index); - v = dhcp_get_vss_info(dpm, i); - - ip46_address_t src_addr = { - .ip4 = server->dhcp_src_address, - }; - ip46_address_t server_addr = { - .ip4 = server->dhcp_server, - }; - - s_fib = ip4_fib_get(server->server_fib_index); - r_fib = ip4_fib_get(i); - - dhcp_send_details(opaque, - context, - &server_addr, - &src_addr, - s_fib->table_id, - r_fib->table_id, - (v ? v->vpn_id.fib_id : 0), - (v ? v->vpn_id.oui : 0)); - } -} - -int dhcp_proxy_set_option82_vss(u32 tbl_id, - u32 oui, - u32 fib_id, - int is_del) -{ - dhcp_proxy_main_t *dm = &dhcp_proxy_main; - vss_info *v = NULL; - u32 rx_fib_index; - int rc = 0; - - rx_fib_index = ip4_fib_table_find_or_create_and_lock(tbl_id); - v = dhcp_get_vss_info(dm, rx_fib_index); - - if (NULL != v) - { - if (is_del) - { - /* release the lock held on the table when the VSS - * info was created */ - fib_table_unlock (rx_fib_index, - FIB_PROTOCOL_IP4); - - pool_put (dm->vss, v); - dm->vss_index_by_rx_fib_index[rx_fib_index] = ~0; - } - else - { - /* this is a modify */ - v->vpn_id.fib_id = fib_id; - v->vpn_id.oui = oui; - } - } - else - { - if (is_del) - rc = VNET_API_ERROR_NO_SUCH_ENTRY; - else - { - /* create a new entry */ - vec_validate_init_empty(dm->vss_index_by_rx_fib_index, - rx_fib_index, ~0); - - /* hold a lock on the table whilst the VSS info exist */ - fib_table_lock (rx_fib_index, - FIB_PROTOCOL_IP4); - - pool_get (dm->vss, v); - v->vpn_id.fib_id = fib_id; - v->vpn_id.oui = oui; - dm->vss_index_by_rx_fib_index[rx_fib_index] = v - dm->vss; - } - } - - /* Release the lock taken during the create_or_lock at the start */ - fib_table_unlock (rx_fib_index, - FIB_PROTOCOL_IP4); - - return (rc); -} - -static clib_error_t * -dhcp_option_82_vss_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - int is_del = 0, got_new_vpn_id=0; - u32 oui=0, fib_id=0, tbl_id=~0; - - - while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) - { - - if (unformat(input, "delete") || unformat(input, "del")) - is_del = 1; - else if (unformat (input, "oui %d", &oui)) - got_new_vpn_id = 1; - else if (unformat (input, "vpn-id %d", &fib_id)) - got_new_vpn_id = 1; - else if (unformat (input, "table %d", &tbl_id)) - got_new_vpn_id = 1; - else - break; - } - if (tbl_id == ~0) - return clib_error_return (0, "no table ID specified."); - - if (is_del || got_new_vpn_id) - { - int rv; - rv = dhcp_proxy_set_option82_vss(tbl_id, oui, fib_id, is_del); - switch (rv) - { - case 0: - return 0; - - case VNET_API_ERROR_NO_SUCH_FIB: - return clib_error_return (0, "option 82 vss(oui:%d, vpn-id:%d) not found in table %d", - oui, fib_id, tbl_id); - - case VNET_API_ERROR_NO_SUCH_ENTRY: - return clib_error_return (0, "option 82 vss for table %d not found in in pool.", - tbl_id); - default: - return clib_error_return (0, "BUG: rv %d", rv); - } - } - else - return clib_error_return (0, "parse error`%U'", - format_unformat_error, input); -} - -VLIB_CLI_COMMAND (dhcp_proxy_vss_command,static) = { - .path = "set dhcp option-82 vss", - .short_help = "set dhcp option-82 vss [del] table
oui vpn-id ", - .function = dhcp_option_82_vss_fn, -}; - - -static clib_error_t * -dhcp_vss_show_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) - -{ - dhcp_proxy_main_t * dm = &dhcp_proxy_main; - ip4_fib_t *fib; - u32 *fib_index; - vss_info *v; - - vlib_cli_output (vm, "%=9s%=11s%=12s","Table", "OUI", "VPN-ID"); - pool_foreach (fib_index, dm->vss_index_by_rx_fib_index, - ({ - fib = ip4_fib_get (*fib_index); - v = pool_elt_at_index (dm->vss, *fib_index); - - vlib_cli_output (vm, "%=6d%=6d%=12d", - fib->table_id, - v->vpn_id.oui, - v->vpn_id.fib_id); - })); - - return 0; -} - -VLIB_CLI_COMMAND (dhcp_proxy_vss_show_command, static) = { - .path = "show dhcp vss", - .short_help = "show dhcp VSS", - .function = dhcp_vss_show_command_fn, -}; - -static clib_error_t * -dhcp_option_82_address_show_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) - -{ - dhcp_proxy_main_t *dm = &dhcp_proxy_main; - vnet_main_t *vnm = vnet_get_main(); - u32 sw_if_index0=0, sw_if_index; - ip4_address_t *ia0; - vnet_sw_interface_t *swif; - - while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) - { - - if (unformat(input, "%U", - unformat_vnet_sw_interface, dm->vnet_main, &sw_if_index0)) - { - swif = vnet_get_sw_interface (vnm, sw_if_index0); - sw_if_index = (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED) ? - swif->unnumbered_sw_if_index : sw_if_index0; - ia0 = ip4_interface_first_address(&ip4_main, sw_if_index, 0); - if (ia0) - { - vlib_cli_output (vm, "%=20s%=20s", "interface", - "source IP address"); - - vlib_cli_output (vm, "%=20U%=20U", - format_vnet_sw_if_index_name, - dm->vnet_main, sw_if_index0, - format_ip4_address, ia0); - } - else - vlib_cli_output (vm, "%=34s %=20U", - "No IPv4 address configured on", - format_vnet_sw_if_index_name, - dm->vnet_main, sw_if_index); - } - else - break; - } - - return 0; -} - -VLIB_CLI_COMMAND (dhcp_proxy_address_show_command,static) = { - .path = "show dhcp option-82-address interface", - .short_help = "show dhcp option-82-address interface ", - .function = dhcp_option_82_address_show_command_fn, -}; diff --git a/src/vnet/dhcpv6/packet.h b/src/vnet/dhcpv6/packet.h deleted file mode 100644 index 8634b5d8..00000000 --- a/src/vnet/dhcpv6/packet.h +++ /dev/null @@ -1,183 +0,0 @@ -#ifndef included_vnet_dhcp_packet_h -#define included_vnet_dhcp_packet_h - -/* - * DHCP packet format - * - * Copyright (c) 2013 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include - -// #define DHCP_VRF_NAME_MAX_LEN L3VM_MAX_NAME_STR_LEN -// #define DHCPV6_MAX_VRF_NAME_LEN L3VM_MAX_NAME_STR_LEN -#define DHCP_MAX_RELAY_ADDR 16 -#define PROTO_UDP 17 -#define DHCPV6_CLIENT_PORT 546 -#define DHCPV6_SERVER_PORT 547 -#define HOP_COUNT_LIMIT 32 -#define DHCPV6_CISCO_ENT_NUM 9 - -/* - * DHCPv6 message types - */ -typedef enum dhcpv6_msg_type_{ - DHCPV6_MSG_SOLICIT = 1, - DHCPV6_MSG_ADVERTISE = 2, - DHCPV6_MSG_REQUEST = 3, - DHCPV6_MSG_CONFIRM = 4, - DHCPV6_MSG_RENEW = 5, - DHCPV6_MSG_REBIND = 6, - DHCPV6_MSG_REPLY = 7, - DHCPV6_MSG_RELEASE = 8, - DHCPV6_MSG_DECLINE = 9, - DHCPV6_MSG_RECONFIGURE = 10, - DHCPV6_MSG_INFORMATION_REQUEST = 11, - DHCPV6_MSG_RELAY_FORW = 12, - DHCPV6_MSG_RELAY_REPL = 13, -} dhcpv6_msg_type_t; - -/* - * DHCPv6 options types - */ -enum { - DHCPV6_OPTION_CLIENTID = 1, - DHCPV6_OPTION_SERVERID = 2, - DHCPV6_OPTION_IA_NA = 3, - DHCPV6_OPTION_IA_TA = 4, - DHCPV6_OPTION_IAADDR = 5, - DHCPV6_OPTION_ORO = 6, - DHCPV6_OPTION_PREFERENCE = 7, - DHCPV6_OPTION_ELAPSED_TIME = 8, - DHCPV6_OPTION_RELAY_MSG = 9, - DHCPV6_OPTION_AUTH = 11, - DHCPV6_OPTION_UNICAST = 12, - DHCPV6_OPTION_STATUS_CODE = 13, - DHCPV6_OPTION_RAPID_COMMIT = 14, - DHCPV6_OPTION_USER_CLASS = 15, - DHCPV6_OPTION_VENDOR_CLASS = 16, - DHCPV6_OPTION_VENDOR_OPTS = 17, - DHCPV6_OPTION_INTERFACE_ID = 18, // relay agent fills this - DHCPV6_OPTION_RECONF_MSG = 19, - DHCPV6_OPTION_RECONF_ACCEPT = 20, - DHCPV6_OPTION_REMOTEID = 37, // relay agent fills this - DHCPV6_OPTION_VSS = 68, // relay agent fills this - DHCPV6_OPTION_CLIENT_LINK_LAYER_ADDRESS = 79, - DHCPV6_OPTION_MAX -}; - -/* -* DHCPv6 status codes - */ -enum { - DHCPV6_STATUS_SUCCESS = 0, - DHCPV6_STATUS_UNSPEC_FAIL = 1, - DHCPV6_STATUS_NOADDRS_AVAIL = 2, - DHCPV6_STATUS_NO_BINDING = 3, - DHCPV6_STATUS_NOT_ONLINK = 4, - DHCPV6_STATUS_USE_MULTICAST = 5, -}; - -/* - * DHCPv6 DUID types - */ -enum { - DHCPV6_DUID_LLT = 1, /* DUID Based on Link-layer Address Plus Time */ - DHCPV6_DUID_EN = 2, /* DUID Based on Enterprise Number */ - DHCPV6_DUID_LL = 3, /* DUID Based on Link-layer Address */ -}; - -//Structure for DHCPv6 payload from client -typedef struct dhcpv6_hdr_ { - union { - u8 msg_type; //DHCP msg type - u32 xid; // transaction id - }u; - u8 data[0]; -} dhcpv6_header_t; - - - -typedef CLIB_PACKED (struct dhcpv6_relay_ctx_ { - dhcpv6_header_t *pkt; - u32 pkt_len; - u32 dhcpv6_len; //DHCPv6 payload load -// if_ordinal iod; - u32 if_index; - u32 ctx_id; - char ctx_name[32+1]; - u8 dhcp_msg_type; -}) dhcpv6_relay_ctx_t; - -//Structure for DHCPv6 RELAY-FORWARD and DHCPv6 RELAY-REPLY pkts -typedef CLIB_PACKED (struct dhcpv6_relay_hdr_ { - u8 msg_type; - u8 hop_count; - ip6_address_t link_addr; - ip6_address_t peer_addr; - u8 data[0]; -}) dhcpv6_relay_hdr_t; - -typedef enum dhcp_stats_action_type_ { - DHCP_STATS_ACTION_FORWARDED=1, - DHCP_STATS_ACTION_RECEIVED, - DHCP_STATS_ACTION_DROPPED -} dhcp_stats_action_type_t; -//Generic counters for a packet -typedef struct dhcp_stats_counters_ { - u64 rx_pkts; //counter for received pkts - u64 tx_pkts; //counter for forwarded pkts - u64 drops; //counter for dropped pkts -} dhcp_stats_counters_t; - - -typedef enum dhcpv6_stats_drop_reason_ { - DHCPV6_RELAY_PKT_DROP_RELAYDISABLE = 1, - DHCPV6_RELAY_PKT_DROP_MAX_HOPS, - DHCPV6_RELAY_PKT_DROP_VALIDATION_FAIL, - DHCPV6_RELAY_PKT_DROP_UNKNOWN_OP_INTF, - DHCPV6_RELAY_PKT_DROP_BAD_CONTEXT, - DHCPV6_RELAY_PKT_DROP_OPT_INSERT_FAIL, - DHCPV6_RELAY_PKT_DROP_REPLY_FROM_CLIENT, -} dhcpv6_stats_drop_reason_t; - -typedef CLIB_PACKED (struct { - u16 option; - u16 length; - u8 data[0]; -}) dhcpv6_option_t; - -typedef CLIB_PACKED (struct { - dhcpv6_option_t opt; - u32 int_idx; -}) dhcpv6_int_id_t; - -typedef CLIB_PACKED (struct { - dhcpv6_option_t opt; - u8 data[8]; // data[0]:type, data[1..7]: VPN ID -}) dhcpv6_vss_t; - -typedef CLIB_PACKED (struct { - dhcpv6_option_t opt; - u32 ent_num; - u32 rmt_id; -}) dhcpv6_rmt_id_t; - -typedef CLIB_PACKED (struct { - dhcpv6_option_t opt; - u16 link_type; - u8 data[6]; // data[0]:data[5]: MAC address -}) dhcpv6_client_mac_t; - - -#endif /* included_vnet_dhcp_packet_h */ diff --git a/src/vnet/dhcpv6/proxy.h b/src/vnet/dhcpv6/proxy.h deleted file mode 100644 index 77ced361..00000000 --- a/src/vnet/dhcpv6/proxy.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * proxy.h: dhcp proxy - * - * Copyright (c) 2013 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef included_dhcpv6_proxy_h -#define included_dhcpv6_proxy_h - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -typedef enum { -#define dhcpv6_proxy_error(n,s) DHCPV6_PROXY_ERROR_##n, -#include -#undef dhcpv6_proxy_error - DHCPV6_PROXY_N_ERROR, -} dhcpv6_proxy_error_t; - -typedef struct { - u32 oui; - u32 fib_id; -} dhcpv6_vss_id; - -typedef union { - u8 as_u8[8]; - dhcpv6_vss_id vpn_id; -} dhcpv6_vss_info; - -typedef struct { - ip6_address_t dhcp6_server; - ip6_address_t dhcp6_src_address; - u32 server_fib6_index; -} dhcpv6_server_t; - -typedef struct { - /* Pool of DHCP servers */ - dhcpv6_server_t * dhcp6_servers; - - /* Pool of selected DHCP server. Zero is the default server */ - u32 * dhcp6_server_index_by_rx_fib_index; - - /* all DHCP servers address */ - ip6_address_t all_dhcpv6_server_address; - ip6_address_t all_dhcpv6_server_relay_agent_address; - - /* to drop pkts in server-to-client direction */ - u32 error_drop_node_index; - - dhcpv6_vss_info *vss; - - /* hash lookup specific vrf_id -> VSS vector index*/ - u32 *vss_index_by_rx_fib_index; - - /* convenience */ - vlib_main_t * vlib_main; - vnet_main_t * vnet_main; -} dhcpv6_proxy_main_t; - -dhcpv6_proxy_main_t dhcpv6_proxy_main; - -int dhcpv6_proxy_set_vss(u32 tbl_id, - u32 oui, - u32 fib_id, - int is_del); - -int dhcpv6_proxy_set_server(ip6_address_t *addr, - ip6_address_t *src_address, - u32 rx_fib_id, - u32 server_fib_id, - int is_del); - -void dhcpv6_proxy_dump(void *opaque, - u32 context); - -#endif /* included_dhcpv6_proxy_h */ diff --git a/src/vnet/dhcpv6/proxy_error.def b/src/vnet/dhcpv6/proxy_error.def deleted file mode 100644 index 55fa7317..00000000 --- a/src/vnet/dhcpv6/proxy_error.def +++ /dev/null @@ -1,29 +0,0 @@ -/* - * dhcp_proxy_error.def: dhcp proxy errors - * - * Copyright (c) 2013 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -dhcpv6_proxy_error (NONE, "no error") -dhcpv6_proxy_error (NO_SERVER, "no dhcpv6 server configured") -dhcpv6_proxy_error (RELAY_TO_SERVER, "DHCPV6 packets relayed to the server") -dhcpv6_proxy_error (RELAY_TO_CLIENT, "DHCPV6 packets relayed to clients") -dhcpv6_proxy_error (NO_INTERFACE_ADDRESS, "DHCPV6 no interface address") -dhcpv6_proxy_error (WRONG_MESSAGE_TYPE, "DHCPV6 wrong message type.") -dhcpv6_proxy_error (NO_SRC_ADDRESS, "DHCPV6 no srouce IPv6 address configured.") -dhcpv6_proxy_error (NO_CIRCUIT_ID_OPTION, "DHCPv6 reply packets without circuit ID option") -dhcpv6_proxy_error (NO_RELAY_MESSAGE_OPTION, "DHCPv6 reply packets without relay message option") -dhcpv6_proxy_error (BAD_SVR_FIB_OR_ADDRESS, "DHCPv6 packets not from DHCPv6 server or server FIB.") -dhcpv6_proxy_error (PKT_TOO_BIG, "DHCPv6 packets which are too big.") -dhcpv6_proxy_error (WRONG_INTERFACE_ID_OPTION, "DHCPv6 reply to invalid interface.") diff --git a/src/vnet/dhcpv6/proxy_node.c b/src/vnet/dhcpv6/proxy_node.c deleted file mode 100644 index f40798e6..00000000 --- a/src/vnet/dhcpv6/proxy_node.c +++ /dev/null @@ -1,1280 +0,0 @@ -/* - * proxy_node.c: dhcpv6 proxy node processing - * - * Copyright (c) 2013 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include -#include - -static char * dhcpv6_proxy_error_strings[] = { -#define dhcpv6_proxy_error(n,s) s, -#include "proxy_error.def" -#undef dhcpv6_proxy_error -}; - -#define foreach_dhcpv6_proxy_to_server_input_next \ - _ (DROP, "error-drop") \ - _ (LOOKUP, "ip6-lookup") \ - _ (SEND_TO_CLIENT, "dhcpv6-proxy-to-client") - - -typedef enum { -#define _(s,n) DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_##s, - foreach_dhcpv6_proxy_to_server_input_next -#undef _ - DHCPV6_PROXY_TO_SERVER_INPUT_N_NEXT, -} dhcpv6_proxy_to_server_input_next_t; - -typedef struct { - /* 0 => to server, 1 => to client */ - int which; - u8 packet_data[64]; - u32 error; - u32 sw_if_index; - u32 original_sw_if_index; -} dhcpv6_proxy_trace_t; - -vlib_node_registration_t dhcpv6_proxy_to_server_node; -vlib_node_registration_t dhcpv6_proxy_to_client_node; - - -u8 * format_dhcpv6_proxy_trace (u8 * s, va_list * args) -{ - CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); - CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); - dhcpv6_proxy_trace_t * t = va_arg (*args, dhcpv6_proxy_trace_t *); - - if (t->which == 0) - s = format (s, "DHCPV6 proxy: sent to server %U", - format_ip6_address, &t->packet_data, sizeof (ip6_address_t)); - else - s = format (s, "DHCPV6 proxy: sent to client from %U", - format_ip6_address, &t->packet_data, sizeof (ip6_address_t)); - if (t->error != (u32)~0) - s = format (s, " error: %s\n", dhcpv6_proxy_error_strings[t->error]); - - s = format (s, " original_sw_if_index: %d, sw_if_index: %d\n", - t->original_sw_if_index, t->sw_if_index); - - return s; -} - -u8 * format_dhcpv6_proxy_header_with_length (u8 * s, va_list * args) -{ - dhcpv6_header_t * h = va_arg (*args, dhcpv6_header_t *); - u32 max_header_bytes = va_arg (*args, u32); - u32 header_bytes; - - header_bytes = sizeof (h[0]); - if (max_header_bytes != 0 && header_bytes > max_header_bytes) - return format (s, "dhcpv6 header truncated"); - - s = format (s, "DHCPV6 Proxy"); - - return s; -} -/* get first interface address */ -static ip6_address_t * -ip6_interface_first_global_or_site_address (ip6_main_t * im, u32 sw_if_index) -{ - ip_lookup_main_t * lm = &im->lookup_main; - ip_interface_address_t * ia = 0; - ip6_address_t * result = 0; - - foreach_ip_interface_address (lm, ia, sw_if_index, - 1 /* honor unnumbered */, - ({ - ip6_address_t * a = ip_interface_address_get_address (lm, ia); - if ((a->as_u8[0] & 0xe0) == 0x20 || - (a->as_u8[0] & 0xfe) == 0xfc) { - result = a; - break; - } - })); - return result; -} - -static inline void copy_ip6_address (ip6_address_t *dst, ip6_address_t *src) -{ - - dst->as_u64[0] = src->as_u64[0]; - dst->as_u64[1] = src->as_u64[1]; -} - -static inline dhcpv6_vss_info * -dhcpv6_get_vss_info (dhcpv6_proxy_main_t *dm, - u32 rx_fib_index) -{ - dhcpv6_vss_info *v; - - if (vec_len(dm->vss_index_by_rx_fib_index) <= rx_fib_index || - dm->vss_index_by_rx_fib_index[rx_fib_index] == ~0) - { - v = NULL; - } - else - { - v = pool_elt_at_index (dm->vss, - dm->vss_index_by_rx_fib_index[rx_fib_index]); - } - - return (v); -} - -static inline dhcpv6_server_t * -dhcpv6_get_server (dhcpv6_proxy_main_t *dm, - u32 rx_fib_index) -{ - dhcpv6_server_t *s = NULL; - - if (vec_len(dm->dhcp6_server_index_by_rx_fib_index) > rx_fib_index && - dm->dhcp6_server_index_by_rx_fib_index[rx_fib_index] != ~0) - { - s = pool_elt_at_index (dm->dhcp6_servers, - dm->dhcp6_server_index_by_rx_fib_index[rx_fib_index]); - } - - return (s); -} - -static uword -dhcpv6_proxy_to_server_input (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * from_frame) -{ - u32 n_left_from, next_index, * from, * to_next; - dhcpv6_proxy_main_t * dpm = &dhcpv6_proxy_main; - from = vlib_frame_vector_args (from_frame); - n_left_from = from_frame->n_vectors; - u32 pkts_to_server=0, pkts_to_client=0, pkts_no_server=0; - u32 pkts_no_interface_address=0, pkts_no_exceeding_max_hop=0; - u32 pkts_no_src_address=0; - u32 pkts_wrong_msg_type=0; - u32 pkts_too_big=0; - ip6_main_t * im = &ip6_main; - ip6_address_t * src; - int bogus_length; - dhcpv6_server_t * server; - u32 rx_fib_idx = 0, server_fib_idx = 0; - - next_index = node->cached_next_index; - - while (n_left_from > 0) - { - 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) - { - vnet_main_t *vnm = vnet_get_main(); - u32 sw_if_index = 0; - u32 rx_sw_if_index = 0; - vnet_sw_interface_t *swif; - u32 bi0; - vlib_buffer_t * b0; - udp_header_t * u0, *u1; - dhcpv6_header_t * h0; // client msg hdr - ip6_header_t * ip0, *ip1; - ip6_address_t _ia0, *ia0=&_ia0; - u32 next0; - u32 error0 = (u32) ~0; - dhcpv6_option_t *fwd_opt; - dhcpv6_relay_hdr_t *r1; - u16 len; - dhcpv6_int_id_t *id1; - dhcpv6_vss_t *vss1; - dhcpv6_client_mac_t *cmac; // client mac - ethernet_header_t * e_h0; - u8 client_src_mac[6]; - vlib_buffer_free_list_t *fl; - dhcpv6_vss_info *vss; - - bi0 = from[0]; - to_next[0] = bi0; - from += 1; - to_next += 1; - n_left_from -= 1; - n_left_to_next -= 1; - - b0 = vlib_get_buffer (vm, bi0); - - h0 = vlib_buffer_get_current (b0); - - /* - * udp_local hands us the DHCPV6 header. - */ - u0 = (void *)h0 -(sizeof(*u0)); - ip0 = (void *)u0 -(sizeof(*ip0)); - e_h0 = (void *)ip0 - ethernet_buffer_header_size(b0); - - clib_memcpy(client_src_mac, e_h0->src_address, 6); - - switch (h0->u.msg_type) { - case DHCPV6_MSG_SOLICIT: - case DHCPV6_MSG_REQUEST: - case DHCPV6_MSG_CONFIRM: - case DHCPV6_MSG_RENEW: - case DHCPV6_MSG_REBIND: - case DHCPV6_MSG_RELEASE: - case DHCPV6_MSG_DECLINE: - case DHCPV6_MSG_INFORMATION_REQUEST: - case DHCPV6_MSG_RELAY_FORW: - /* send to server */ - break; - case DHCPV6_MSG_RELAY_REPL: - /* send to client */ - next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_SEND_TO_CLIENT; - error0 = 0; - pkts_to_client++; - goto do_enqueue; - default: - /* drop the packet */ - pkts_wrong_msg_type++; - error0 = DHCPV6_PROXY_ERROR_WRONG_MESSAGE_TYPE; - next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP; - goto do_trace; - - } - - /* Send to DHCPV6 server via the configured FIB */ - rx_sw_if_index = sw_if_index = vnet_buffer(b0)->sw_if_index[VLIB_RX]; - rx_fib_idx = im->fib_index_by_sw_if_index [rx_sw_if_index]; - server = dhcpv6_get_server(dpm, rx_fib_idx); - - if (PREDICT_FALSE (NULL == server)) - { - error0 = DHCPV6_PROXY_ERROR_NO_SERVER; - next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP; - pkts_no_server++; - goto do_trace; - } - - server_fib_idx = server->server_fib6_index; - vnet_buffer(b0)->sw_if_index[VLIB_TX] = server_fib_idx; - - - /* relay-option header pointer */ - vlib_buffer_advance(b0, -(sizeof(*fwd_opt))); - fwd_opt = vlib_buffer_get_current(b0); - /* relay message header pointer */ - vlib_buffer_advance(b0, -(sizeof(*r1))); - r1 = vlib_buffer_get_current(b0); - - vlib_buffer_advance(b0, -(sizeof(*u1))); - u1 = vlib_buffer_get_current(b0); - - vlib_buffer_advance(b0, -(sizeof(*ip1))); - ip1 = vlib_buffer_get_current(b0); - - /* fill in all that rubbish... */ - len = clib_net_to_host_u16(u0->length) - sizeof(udp_header_t); - copy_ip6_address(&r1->peer_addr, &ip0->src_address); - - r1->msg_type = DHCPV6_MSG_RELAY_FORW; - fwd_opt->length = clib_host_to_net_u16(len); - fwd_opt->option = clib_host_to_net_u16(DHCPV6_OPTION_RELAY_MSG); - - r1->hop_count++; - r1->hop_count = (h0->u.msg_type != DHCPV6_MSG_RELAY_FORW) ? 0 : r1->hop_count; - - if (PREDICT_FALSE(r1->hop_count >= HOP_COUNT_LIMIT)) - { - error0 = DHCPV6_RELAY_PKT_DROP_MAX_HOPS; - next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP; - pkts_no_exceeding_max_hop++; - goto do_trace; - } - - - /* If relay-fwd and src address is site or global unicast address */ - if (h0->u.msg_type == DHCPV6_MSG_RELAY_FORW && - ((ip0->src_address.as_u8[0] & 0xe0) == 0x20 || - (ip0->src_address.as_u8[0] & 0xfe) == 0xfc)) - { - /* Set link address to zero */ - r1->link_addr.as_u64[0] = 0; - r1->link_addr.as_u64[1] = 0; - goto link_address_set; - } - - /* if receiving interface is unnumbered, use receiving interface - * IP address as link address, otherwise use the loopback interface - * IP address as link address. - */ - - swif = vnet_get_sw_interface (vnm, rx_sw_if_index); - if (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED) - sw_if_index = swif->unnumbered_sw_if_index; - - ia0 = ip6_interface_first_global_or_site_address(&ip6_main, sw_if_index); - if (ia0 == 0) - { - error0 = DHCPV6_PROXY_ERROR_NO_INTERFACE_ADDRESS; - next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP; - pkts_no_interface_address++; - goto do_trace; - } - - copy_ip6_address(&r1->link_addr, ia0); - - link_address_set: - fl = vlib_buffer_get_free_list (vm, b0->free_list_index); - - if ((b0->current_length+sizeof(*id1)+sizeof(*vss1)+sizeof(*cmac)) - > fl->n_data_bytes) - { - error0 = DHCPV6_PROXY_ERROR_PKT_TOO_BIG; - next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP; - pkts_too_big++; - goto do_trace; - } - - id1 = (dhcpv6_int_id_t *) (((uword) ip1) + b0->current_length); - b0->current_length += (sizeof (*id1)); - - id1->opt.option = clib_host_to_net_u16(DHCPV6_OPTION_INTERFACE_ID); - id1->opt.length = clib_host_to_net_u16(sizeof(rx_sw_if_index)); - id1->int_idx = clib_host_to_net_u32(rx_sw_if_index); - - u1->length =0; - if (h0->u.msg_type != DHCPV6_MSG_RELAY_FORW) - { - cmac = (dhcpv6_client_mac_t *) (((uword) ip1) + b0->current_length); - b0->current_length += (sizeof (*cmac)); - cmac->opt.length =clib_host_to_net_u16(sizeof(*cmac) - - sizeof(cmac->opt)); - cmac->opt.option = clib_host_to_net_u16(DHCPV6_OPTION_CLIENT_LINK_LAYER_ADDRESS); - cmac->link_type = clib_host_to_net_u16(1); // ethernet - clib_memcpy(cmac->data, client_src_mac, 6); - u1->length += sizeof(*cmac); - } - - //TODO: Revisit if hash makes sense here - vss = dhcpv6_get_vss_info(dpm, rx_fib_idx); - - if (NULL != vss) { - vss1 = (dhcpv6_vss_t *) (((uword) ip1) + b0->current_length); - b0->current_length += (sizeof (*vss1)); - vss1->opt.length =clib_host_to_net_u16(sizeof(*vss1) - - sizeof(vss1->opt)); - vss1->opt.option = clib_host_to_net_u16(DHCPV6_OPTION_VSS); - vss1->data[0] = 1; // type - vss1->data[1] = vss->vpn_id.oui >>16 & 0xff; - vss1->data[2] = vss->vpn_id.oui >>8 & 0xff; - vss1->data[3] = vss->vpn_id.oui & 0xff; - vss1->data[4] = vss->vpn_id.fib_id >> 24 & 0xff; - vss1->data[5] = vss->vpn_id.fib_id >> 16 & 0xff; - vss1->data[6] = vss->vpn_id.fib_id >> 8 & 0xff; - vss1->data[7] = vss->vpn_id.fib_id & 0xff; - u1->length += sizeof(*vss1); - } - - pkts_to_server++; - u1->checksum = 0; - u1->src_port = clib_host_to_net_u16(UDP_DST_PORT_dhcpv6_to_client); - u1->dst_port = clib_host_to_net_u16(UDP_DST_PORT_dhcpv6_to_server); - - u1->length = - clib_host_to_net_u16( clib_net_to_host_u16(fwd_opt->length) + - sizeof(*r1) + sizeof(*fwd_opt) + - sizeof(*u1) + sizeof(*id1) + u1->length); - - memset(ip1, 0, sizeof(*ip1)); - ip1->ip_version_traffic_class_and_flow_label = 0x60; - ip1->payload_length = u1->length; - ip1->protocol = PROTO_UDP; - ip1->hop_limit = HOP_COUNT_LIMIT; - src = (server->dhcp6_server.as_u64[0] || server->dhcp6_server.as_u64[1]) ? - &server->dhcp6_server : &dpm->all_dhcpv6_server_address; - copy_ip6_address(&ip1->dst_address, src); - - - ia0 = ip6_interface_first_global_or_site_address - (&ip6_main, vnet_buffer(b0)->sw_if_index[VLIB_RX]); - - src = (server->dhcp6_src_address.as_u64[0] || server->dhcp6_src_address.as_u64[1]) ? - &server->dhcp6_src_address : ia0; - if (ia0 == 0) - { - error0 = DHCPV6_PROXY_ERROR_NO_SRC_ADDRESS; - next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP; - pkts_no_src_address++; - goto do_trace; - } - - copy_ip6_address (&ip1->src_address, src); - - - u1->checksum = ip6_tcp_udp_icmp_compute_checksum(vm, b0, ip1, - &bogus_length); - ASSERT(bogus_length == 0); - - next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP; - - do_trace: - if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) - { - dhcpv6_proxy_trace_t *tr = vlib_add_trace (vm, node, - b0, sizeof (*tr)); - tr->which = 0; /* to server */ - tr->error = error0; - tr->original_sw_if_index = rx_sw_if_index; - tr->sw_if_index = sw_if_index; - if (DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP == next0) - copy_ip6_address((ip6_address_t *)&tr->packet_data[0], &server->dhcp6_server); - } - - do_enqueue: - 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); - } - - vlib_node_increment_counter (vm, dhcpv6_proxy_to_server_node.index, - DHCPV6_PROXY_ERROR_RELAY_TO_CLIENT, - pkts_to_client); - vlib_node_increment_counter (vm, dhcpv6_proxy_to_server_node.index, - DHCPV6_PROXY_ERROR_RELAY_TO_SERVER, - pkts_to_server); - vlib_node_increment_counter (vm, dhcpv6_proxy_to_server_node.index, - DHCPV6_PROXY_ERROR_NO_INTERFACE_ADDRESS, - pkts_no_interface_address); - vlib_node_increment_counter (vm, dhcpv6_proxy_to_server_node.index, - DHCPV6_PROXY_ERROR_WRONG_MESSAGE_TYPE, - pkts_wrong_msg_type); - vlib_node_increment_counter (vm, dhcpv6_proxy_to_server_node.index, - DHCPV6_PROXY_ERROR_NO_SRC_ADDRESS, - pkts_no_src_address); - vlib_node_increment_counter (vm, dhcpv6_proxy_to_server_node.index, - DHCPV6_PROXY_ERROR_PKT_TOO_BIG, - pkts_too_big); - return from_frame->n_vectors; -} - -VLIB_REGISTER_NODE (dhcpv6_proxy_to_server_node) = { - .function = dhcpv6_proxy_to_server_input, - .name = "dhcpv6-proxy-to-server", - /* 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_SERVER_INPUT_N_NEXT, - .next_nodes = { -#define _(s,n) [DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_##s] = n, - foreach_dhcpv6_proxy_to_server_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 -}; - -static uword -dhcpv6_proxy_to_client_input (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * from_frame) -{ - - u32 n_left_from, * from; - ethernet_main_t *em = ethernet_get_main (vm); - dhcpv6_proxy_main_t * dm = &dhcpv6_proxy_main; - dhcpv6_server_t * server; - vnet_main_t * vnm = vnet_get_main(); - int bogus_length; - - from = vlib_frame_vector_args (from_frame); - n_left_from = from_frame->n_vectors; - - 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, * ia0 = &_ia0; - 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 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) - { - error0 = DHCPV6_PROXY_ERROR_WRONG_MESSAGE_TYPE; - - drop_packet: - vlib_node_increment_counter (vm, dhcpv6_proxy_to_client_node.index, - error0, 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)); - - 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 */ - - while ((u8 *) o < (b0->data + b0->current_data + b0->current_length)) - { - if (DHCPV6_OPTION_INTERFACE_ID == clib_net_to_host_u16(o->option)) - { - 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; - goto drop_packet; - } - } - 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 ((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)); - - client_fib_idx = im->fib_index_by_sw_if_index[sw_if_index]; - server = dhcpv6_get_server(dm, client_fib_idx); - - if (NULL == server) - { - error0 = DHCPV6_PROXY_ERROR_NO_SERVER; - goto drop_packet; - } - - server_fib_idx = im->fib_index_by_sw_if_index - [vnet_buffer(b0)->sw_if_index[VLIB_RX]]; - - if (server_fib_idx != server->server_fib6_index || - ip0->src_address.as_u64[0] != server->dhcp6_server.as_u64[0] || - ip0->src_address.as_u64[1] != server->dhcp6_server.as_u64[1]) - { - //drop packet if not from server with configured address or FIB - error0 = DHCPV6_PROXY_ERROR_BAD_SVR_FIB_OR_ADDRESS; - goto drop_packet; - } - - vnet_buffer (b0)->sw_if_index[VLIB_TX] = original_sw_if_index - = sw_if_index; - - 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; - - - /* - * 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); - - vlib_buffer_advance (b0, -(sizeof(*ip1))); - ip1 = vlib_buffer_get_current (b0); - - copy_ip6_address(&client_address, &h0->peer_addr); - - ia0 = ip6_interface_first_address (&ip6_main, sw_if_index); - if (ia0 == 0) - { - error0 = DHCPV6_PROXY_ERROR_NO_INTERFACE_ADDRESS; - goto drop_packet; - } - - len = clib_net_to_host_u16(r0->length); - 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) - vlib_buffer_advance (b0, -4 /* space for VLAN tag */); - - mac0 = vlib_buffer_get_current (b0); - - 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 (ei0->address)); - memset (&mac0->dst_address, 0xff, sizeof (mac0->dst_address)); - mac0->type = (si0->type == VNET_SW_INTERFACE_TYPE_SUB) ? - clib_net_to_host_u16(0x8100) : clib_net_to_host_u16 (0x86dd); - - if (si0->type == VNET_SW_INTERFACE_TYPE_SUB) - { - u32 * vlan_tag = (u32 *)(mac0+1); - u32 tmp; - tmp = (si0->sub.id << 16) | 0x0800; - *vlan_tag = clib_host_to_net_u32 (tmp); - } - - /* $$$ 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, - b0, sizeof (*tr)); - tr->which = 1; /* to client */ - if (ia0) - copy_ip6_address((ip6_address_t*)tr->packet_data, ia0); - tr->error = error0; - tr->original_sw_if_index = original_sw_if_index; - tr->sw_if_index = sw_if_index; - } - } - return from_frame->n_vectors; - -} - -VLIB_REGISTER_NODE (dhcpv6_proxy_to_client_node) = { - .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, -#if 0 - .unformat_buffer = unformat_dhcpv6_proxy_header, -#endif -}; - -clib_error_t * dhcpv6_proxy_init (vlib_main_t * vm) -{ - dhcpv6_proxy_main_t * dm = &dhcpv6_proxy_main; - vlib_node_t * error_drop_node; - dhcpv6_server_t * server; - - dm->vlib_main = vm; - dm->vnet_main = vnet_get_main(); - error_drop_node = vlib_get_node_by_name (vm, (u8 *) "error-drop"); - dm->error_drop_node_index = error_drop_node->index; - - dm->vss_index_by_rx_fib_index = NULL; - - /* RFC says this is the dhcpv6 server address */ - dm->all_dhcpv6_server_address.as_u64[0] = clib_host_to_net_u64 (0xFF05000000000000); - dm->all_dhcpv6_server_address.as_u64[1] = clib_host_to_net_u64 (0x00010003); - - /* RFC says this is the server and agent address */ - dm->all_dhcpv6_server_relay_agent_address.as_u64[0] = clib_host_to_net_u64 (0xFF02000000000000); - dm->all_dhcpv6_server_relay_agent_address.as_u64[1] = clib_host_to_net_u64 (0x00010002); - - 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 */); - - /* Create the default server, don't mark it valid */ - pool_get (dm->dhcp6_servers, server); - memset (server, 0, sizeof (*server)); - - return 0; -} - -VLIB_INIT_FUNCTION (dhcpv6_proxy_init); - -int dhcpv6_proxy_set_server (ip6_address_t *addr, - ip6_address_t *src_address, - u32 rx_fib_id, - u32 server_fib_id, - int is_del) -{ - dhcpv6_proxy_main_t * dm = &dhcpv6_proxy_main; - dhcpv6_server_t * server = 0; - u32 rx_fib_index = 0; - int rc = 0; - - rx_fib_index = ip6_mfib_table_find_or_create_and_lock(rx_fib_id); - - const mfib_prefix_t all_dhcp_servers = { - .fp_len = 128, - .fp_proto = FIB_PROTOCOL_IP6, - .fp_grp_addr = { - .ip6 = dm->all_dhcpv6_server_relay_agent_address, - } - }; - - if (is_del) - { - server = dhcpv6_get_server(dm, rx_fib_index); - - if (NULL == server) - { - rc = VNET_API_ERROR_NO_SUCH_ENTRY; - goto out; - } - - /* - * release the locks held on the server fib and rx mfib - */ - mfib_table_entry_delete(rx_fib_index, - &all_dhcp_servers, - MFIB_SOURCE_DHCP); - mfib_table_unlock(rx_fib_index, FIB_PROTOCOL_IP6); - fib_table_unlock(server->server_fib6_index, FIB_PROTOCOL_IP6); - - dm->dhcp6_server_index_by_rx_fib_index[rx_fib_index] = ~0; - - memset (server, 0, sizeof (*server)); - pool_put (dm->dhcp6_servers, server); - } - else - { - if (addr->as_u64[0] == 0 && - addr->as_u64[1] == 0 ) - { - rc = VNET_API_ERROR_INVALID_DST_ADDRESS; - goto out; - } - if (src_address->as_u64[0] == 0 && - src_address->as_u64[1] == 0) - { - rc = VNET_API_ERROR_INVALID_SRC_ADDRESS; - goto out; - } - - server = dhcpv6_get_server(dm, rx_fib_index); - - if (NULL != server) - { - /* modify of an existing entry */ - ip6_fib_t *fib; - - fib = ip6_fib_get(server->server_fib6_index); - - if (fib->table_id != server_fib_id) - { - /* swap tables */ - fib_table_unlock(server->server_fib6_index, FIB_PROTOCOL_IP6); - server->server_fib6_index = - ip6_fib_table_find_or_create_and_lock(server_fib_id); - } - } - else - { - /* Allocate a new server */ - pool_get (dm->dhcp6_servers, server); - - vec_validate_init_empty (dm->dhcp6_server_index_by_rx_fib_index, - rx_fib_index, ~0); - dm->dhcp6_server_index_by_rx_fib_index[rx_fib_index] = - server - dm->dhcp6_servers; - - server->server_fib6_index = - ip6_fib_table_find_or_create_and_lock(server_fib_id); - mfib_table_lock(rx_fib_index, FIB_PROTOCOL_IP6); - - const mfib_prefix_t all_dhcp_servers = { - .fp_len = 128, - .fp_proto = FIB_PROTOCOL_IP6, - .fp_grp_addr = { - .ip6 = dm->all_dhcpv6_server_relay_agent_address, - } - }; - const fib_route_path_t path_for_us = { - .frp_proto = FIB_PROTOCOL_IP6, - .frp_addr = zero_addr, - .frp_sw_if_index = 0xffffffff, - .frp_fib_index = ~0, - .frp_weight = 0, - .frp_flags = FIB_ROUTE_PATH_LOCAL, - }; - mfib_table_entry_path_update(rx_fib_index, - &all_dhcp_servers, - MFIB_SOURCE_DHCP, - &path_for_us, - MFIB_ITF_FLAG_FORWARD); - /* - * Each interface that is enabled in this table, needs to be added - * as an accepting interface, but this is not easily doable in VPP. - * So we cheat. Add a flag to the entry that indicates accept form - * any interface. - * We will still only accept on v6 enabled interfaces, since the - * input feature ensures this. - */ - mfib_table_entry_update(rx_fib_index, - &all_dhcp_servers, - MFIB_SOURCE_DHCP, - MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF); - } - copy_ip6_address(&server->dhcp6_server, addr); - copy_ip6_address(&server->dhcp6_src_address, src_address); - } - -out: - mfib_table_unlock(rx_fib_index, FIB_PROTOCOL_IP6); - - return (rc); -} - -static clib_error_t * -dhcpv6_proxy_set_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - ip6_address_t addr, src_addr; - int set_server = 0, set_src_address = 0; - u32 rx_fib_id = 0, server_fib_id = 0; - int is_del = 0; - - while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (input, "server %U", - unformat_ip6_address, &addr)) - set_server = 1; - else if (unformat(input, "src-address %U", - unformat_ip6_address, &src_addr)) - set_src_address =1; - else if (unformat (input, "server-fib-id %d", &server_fib_id)) - ; - else if (unformat (input, "rx-fib-id %d", &rx_fib_id)) - ; - else if (unformat (input, "delete") || - unformat (input, "del")) - is_del = 1; - else - break; - } - - if (is_del || (set_server && set_src_address)) - { - int rv; - - rv = dhcpv6_proxy_set_server (&addr, &src_addr, rx_fib_id, - server_fib_id, is_del); - - //TODO: Complete the errors - switch (rv) - { - case 0: - return 0; - - case -1: - return clib_error_return (0, "FIB id %d does not exist", server_fib_id); - - default: - return clib_error_return (0, "BUG: rv %d", rv); - } - } - else - return clib_error_return (0, "parse error`%U'", - format_unformat_error, input); -} - -VLIB_CLI_COMMAND (dhcpv6_proxy_set_command, static) = { - .path = "set dhcpv6 proxy", - .short_help = "set dhcpv6 proxy [del] server src-address " - "[server-fib-id ] [rx-fib-id ] ", - .function = dhcpv6_proxy_set_command_fn, -}; - -u8 * format_dhcpv6_proxy_server (u8 * s, va_list * args) -{ - dhcpv6_proxy_main_t * dm = va_arg (*args, dhcpv6_proxy_main_t *); - dhcpv6_server_t * server = va_arg (*args, dhcpv6_server_t *); - u32 rx_fib_index = va_arg (*args, u32); - ip6_fib_t * rx_fib, * server_fib; - u32 server_fib_id = (u32)~0, rx_fib_id = ~0; - - if (dm == 0) - { - s = format (s, "%=40s%=40s%=14s%=14s", "Server Address", "Source Address", - "Server FIB", "RX FIB"); - return s; - } - - server_fib = ip6_fib_get(server->server_fib6_index); - if (server_fib) - server_fib_id= server_fib->table_id; - - rx_fib= ip6_fib_get(rx_fib_index); - - if (rx_fib) - rx_fib_id = rx_fib->table_id; - - s = format (s, "%=40U%=40U%=14u%=14u", - format_ip6_address, &server->dhcp6_server, - format_ip6_address, &server->dhcp6_src_address, - server_fib_id, rx_fib_id); - return s; -} - -static clib_error_t * -dhcpv6_proxy_show_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - dhcpv6_proxy_main_t * dpm = &dhcpv6_proxy_main; - int i; - u32 server_index; - dhcpv6_server_t * server; - - vlib_cli_output (vm, "%U", format_dhcpv6_proxy_server, 0 /* header line */, - 0, 0); - vec_foreach_index (i, dpm->dhcp6_server_index_by_rx_fib_index) - { - server_index = dpm->dhcp6_server_index_by_rx_fib_index[i]; - if (~0 == server_index) - continue; - - server = pool_elt_at_index (dpm->dhcp6_servers, server_index); - - vlib_cli_output (vm, "%U", format_dhcpv6_proxy_server, dpm, - server, i); - } - - return 0; -} - -VLIB_CLI_COMMAND (dhcpv6_proxy_show_command, static) = { - .path = "show dhcpv6 proxy", - .short_help = "Display dhcpv6 proxy info", - .function = dhcpv6_proxy_show_command_fn, -}; - -void -dhcpv6_proxy_dump (void *opaque, - u32 context) -{ - dhcpv6_proxy_main_t * dpm = &dhcpv6_proxy_main; - ip6_fib_t *s_fib, *r_fib; - dhcpv6_server_t * server; - u32 server_index, i; - dhcpv6_vss_info *v; - - vec_foreach_index (i, dpm->dhcp6_server_index_by_rx_fib_index) - { - server_index = dpm->dhcp6_server_index_by_rx_fib_index[i]; - if (~0 == server_index) - continue; - - server = pool_elt_at_index (dpm->dhcp6_servers, server_index); - v = dhcpv6_get_vss_info(dpm, i); - - ip46_address_t src_addr = { - .ip6 = server->dhcp6_src_address, - }; - ip46_address_t server_addr = { - .ip6 = server->dhcp6_server, - }; - - s_fib = ip6_fib_get(server->server_fib6_index); - r_fib = ip6_fib_get(i); - - dhcp_send_details(opaque, - context, - &server_addr, - &src_addr, - s_fib->table_id, - r_fib->table_id, - (v ? v->vpn_id.fib_id : 0), - (v ? v->vpn_id.oui : 0)); - } -} - -int dhcpv6_proxy_set_vss(u32 tbl_id, - u32 oui, - u32 fib_id, - int is_del) -{ - dhcpv6_proxy_main_t *dm = &dhcpv6_proxy_main; - dhcpv6_vss_info *v = NULL; - u32 rx_fib_index; - int rc = 0; - - rx_fib_index = ip6_fib_table_find_or_create_and_lock(tbl_id); - v = dhcpv6_get_vss_info(dm, rx_fib_index); - - if (NULL != v) - { - if (is_del) - { - /* release the lock held on the table when the VSS - * info was created */ - fib_table_unlock (rx_fib_index, - FIB_PROTOCOL_IP6); - - pool_put (dm->vss, v); - dm->vss_index_by_rx_fib_index[rx_fib_index] = ~0; - } - else - { - /* this is a modify */ - v->vpn_id.fib_id = fib_id; - v->vpn_id.oui = oui; - } - } - else - { - if (is_del) - rc = VNET_API_ERROR_NO_SUCH_ENTRY; - else - { - /* create a new entry */ - vec_validate_init_empty(dm->vss_index_by_rx_fib_index, - rx_fib_index, ~0); - - /* hold a lock on the table whilst the VSS info exist */ - fib_table_lock (rx_fib_index, - FIB_PROTOCOL_IP6); - - pool_get (dm->vss, v); - v->vpn_id.fib_id = fib_id; - v->vpn_id.oui = oui; - dm->vss_index_by_rx_fib_index[rx_fib_index] = v - dm->vss; - } - } - - /* Release the lock taken during the create_or_lock at the start */ - fib_table_unlock (rx_fib_index, - FIB_PROTOCOL_IP6); - - return (rc); -} - - -static clib_error_t * -dhcpv6_vss_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - int is_del = 0, got_new_vss=0; - u32 oui=0; - u32 fib_id=0, tbl_id=~0; - - while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (input, "oui %d", &oui)) - got_new_vss = 1; - else if (unformat (input, "vpn-id %d", &fib_id)) - got_new_vss = 1; - else if (unformat (input, "table %d", &tbl_id)) - got_new_vss = 1; - else if (unformat(input, "delete") || unformat(input, "del")) - is_del = 1; - else - break; - } - - if (tbl_id ==~0) - return clib_error_return (0, "no table ID specified."); - - if (is_del || got_new_vss) - { - int rv; - - rv = dhcpv6_proxy_set_vss(tbl_id, oui, fib_id, is_del); - switch (rv) - { - case 0: - return 0; - - case VNET_API_ERROR_NO_SUCH_FIB: - return clib_error_return (0, "vss info (oui:%d, vpn-id:%d) not found in table %d.", - oui, fib_id, tbl_id); - - case VNET_API_ERROR_NO_SUCH_ENTRY: - return clib_error_return (0, "vss for table %d not found in pool.", - tbl_id); - - default: - return clib_error_return (0, "BUG: rv %d", rv); - } - } - else - return clib_error_return (0, "parse error`%U'", - format_unformat_error, input); - -} - -VLIB_CLI_COMMAND (dhcpv6_proxy_vss_command, static) = { - .path = "set dhcpv6 vss", - .short_help = "set dhcpv6 vss table oui vpn-idx ", - .function = dhcpv6_vss_command_fn, -}; - -static clib_error_t * -dhcpv6_vss_show_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) - -{ - dhcpv6_proxy_main_t * dm = &dhcpv6_proxy_main; - dhcpv6_vss_info *v; - ip6_fib_t *fib; - u32 *fib_index; - - vlib_cli_output (vm, "%=6s%=6s%=12s","Table", "OUI", "VPN ID"); - pool_foreach (fib_index, dm->vss_index_by_rx_fib_index, - ({ - fib = ip6_fib_get (*fib_index); - v = pool_elt_at_index (dm->vss, *fib_index); - - vlib_cli_output (vm, "%=6d%=6d%=12d", - fib->table_id, - v->vpn_id.oui, - v->vpn_id.fib_id); - })); - - return 0; -} - -VLIB_CLI_COMMAND (dhcpv6_proxy_vss_show_command, static) = { - .path = "show dhcpv6 vss", - .short_help = "show dhcpv6 VSS", - .function = dhcpv6_vss_show_command_fn, -}; - -static clib_error_t * -dhcpv6_link_address_show_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) - -{ - dhcpv6_proxy_main_t *dm = &dhcpv6_proxy_main; - vnet_main_t *vnm = vnet_get_main(); - u32 sw_if_index0=0, sw_if_index; - ip6_address_t *ia0; - vnet_sw_interface_t *swif; - - while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) - { - - if (unformat(input, "%U", - unformat_vnet_sw_interface, dm->vnet_main, &sw_if_index0)) - { - swif = vnet_get_sw_interface (vnm, sw_if_index0); - sw_if_index = (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED) ? - swif->unnumbered_sw_if_index : sw_if_index0; - ia0 = ip6_interface_first_address(&ip6_main, sw_if_index); - if (ia0) - { - vlib_cli_output (vm, "%=20s%=48s", "interface", "link-address"); - - vlib_cli_output (vm, "%=20U%=48U", - format_vnet_sw_if_index_name, dm->vnet_main, sw_if_index0, - format_ip6_address, ia0); - } else - vlib_cli_output (vm, "%=34s%=20U", "No IPv6 address configured on", - format_vnet_sw_if_index_name, dm->vnet_main, sw_if_index); - } else - break; - } - - return 0; -} - -VLIB_CLI_COMMAND (dhcpv6_proxy_address_show_command, static) = { - .path = "show dhcpv6 link-address interface", - .short_help = "show dhcpv6 link-address interface ", - .function = dhcpv6_link_address_show_command_fn, -}; diff --git a/src/vpp/api/custom_dump.c b/src/vpp/api/custom_dump.c index 70b4e4c9..4cc6aa73 100644 --- a/src/vpp/api/custom_dump.c +++ b/src/vpp/api/custom_dump.c @@ -21,8 +21,7 @@ #include #include #include -#include -#include +#include #include #include #include diff --git a/test/test_dhcp.py b/test/test_dhcp.py index fbfb8a0c..6299975b 100644 --- a/test/test_dhcp.py +++ b/test/test_dhcp.py @@ -293,7 +293,7 @@ class TestDHCP(VppTestCase): # # Inject a response from the server # dropped, because there is no IP addrees on the - # clinet interfce to fill in the option. + # client interfce to fill in the option. # p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) / -- cgit 1.2.3-korg From 3466c30261950823828d1dad0d2fb170ee2f9aaf Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Thu, 16 Feb 2017 07:45:03 -0800 Subject: DHCP Multiple Servers (VPP-602, VPP-605) Multiple DHCP (4 and/or 6) servers can be added and removed through multiple calls to the 'set dhcp server' API. All 4/6/ discover/solicit messages will then be replicated to all servers in the list. The expectation is that the servers/system is configured in such a way that this is viable. If VSS information is providied for the clinet VRF which also has multiple servers configured, then the same VSS information is sent to each server. Likewise the source address of packets sent to from VPP to each server is the same. Change-Id: I3287cb084c84b3f612b78bc69cfcb5b9c1f8934d Signed-off-by: Neale Ranns --- src/scripts/vnet/dhcp/proxy | 3 +- src/vat/api_format.c | 56 ++++-- src/vnet/dhcp/client.c | 2 +- src/vnet/dhcp/dhcp.api | 12 +- src/vnet/dhcp/dhcp4_packet.h | 5 + src/vnet/dhcp/dhcp4_proxy_node.c | 151 +++++++++++++---- src/vnet/dhcp/dhcp6_proxy_node.c | 158 ++++++++++++----- src/vnet/dhcp/dhcp_api.c | 66 +++++--- src/vnet/dhcp/dhcp_proxy.c | 129 +++++++------- src/vnet/dhcp/dhcp_proxy.h | 85 +++++++--- src/vnet/ip/ip6_packet.h | 2 + src/vnet/pg/input.c | 6 + test/test_dhcp.py | 356 ++++++++++++++++++++++++++++++++++----- 13 files changed, 796 insertions(+), 235 deletions(-) (limited to 'src/vnet/dhcp/client.c') diff --git a/src/scripts/vnet/dhcp/proxy b/src/scripts/vnet/dhcp/proxy index c709d87d..42dff2a0 100644 --- a/src/scripts/vnet/dhcp/proxy +++ b/src/scripts/vnet/dhcp/proxy @@ -14,7 +14,8 @@ set int ip addr loop0 2001::1/64 set int ip addr loop0 2001:1::1/64 set dhcp proxy server 10.255.0.1 src-address 10.0.0.1 server-fib-id 0 rx-fib-id 0 -set dhcp proxy server 10.255.0.2 src-address 10.0.1.1 server-fib-id 1 rx-fib-id 1 +set dhcp proxy server 10.255.0.2 src-address 10.0.0.1 server-fib-id 0 rx-fib-id 0 +set dhcp proxy server 10.255.1.2 src-address 10.0.1.1 server-fib-id 1 rx-fib-id 1 set dhcpv6 proxy server 3001::1 src-address 2001::1 server-fib-id 0 rx-fib-id 0 set dhcpv6 proxy server 3002::1 src-address 2001:1::1 server-fib-id 1 rx-fib-id 1 diff --git a/src/vat/api_format.c b/src/vat/api_format.c index 0b60b910..b5943f03 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -7573,23 +7573,35 @@ static void vl_api_dhcp_proxy_details_t_handler (vl_api_dhcp_proxy_details_t * mp) { vat_main_t *vam = &vat_main; + u32 i, count = mp->count; + vl_api_dhcp_server_t *s; if (mp->is_ipv6) print (vam->ofp, - "RX Table-ID %d, Server Table-ID %d, Server Address %U, Source Address %U, VSS FIB-ID %d, VSS OUI %d", + "RX Table-ID %d, Source Address %U, VSS FIB-ID %d, VSS OUI %d", ntohl (mp->rx_vrf_id), - ntohl (mp->server_vrf_id), - format_ip6_address, mp->dhcp_server, format_ip6_address, mp->dhcp_src_address, ntohl (mp->vss_oui), ntohl (mp->vss_fib_id)); else print (vam->ofp, - "RX Table-ID %d, Server Table-ID %d, Server Address %U, Source Address %U, VSS FIB-ID %d, VSS OUI %d", + "RX Table-ID %d, Source Address %U, VSS FIB-ID %d, VSS OUI %d", ntohl (mp->rx_vrf_id), - ntohl (mp->server_vrf_id), - format_ip4_address, mp->dhcp_server, format_ip4_address, mp->dhcp_src_address, ntohl (mp->vss_oui), ntohl (mp->vss_fib_id)); + + for (i = 0; i < count; i++) + { + s = &mp->servers[i]; + + if (mp->is_ipv6) + print (vam->ofp, + " Server Table-ID %d, Server Address %U", + ntohl (s->server_vrf_id), format_ip6_address, s->dhcp_server); + else + print (vam->ofp, + " Server Table-ID %d, Server Address %U", + ntohl (s->server_vrf_id), format_ip4_address, s->dhcp_server); + } } static void vl_api_dhcp_proxy_details_t_handler_json @@ -7597,8 +7609,10 @@ static void vl_api_dhcp_proxy_details_t_handler_json { vat_main_t *vam = &vat_main; vat_json_node_t *node = NULL; + u32 i, count = mp->count; struct in_addr ip4; struct in6_addr ip6; + vl_api_dhcp_server_t *s; if (VAT_JSON_ARRAY != vam->json_tree.type) { @@ -7609,24 +7623,38 @@ static void vl_api_dhcp_proxy_details_t_handler_json vat_json_init_object (node); vat_json_object_add_uint (node, "rx-table-id", ntohl (mp->rx_vrf_id)); - vat_json_object_add_uint (node, "server-table-id", - ntohl (mp->server_vrf_id)); + vat_json_object_add_uint (node, "vss-fib-id", ntohl (mp->vss_fib_id)); + vat_json_object_add_uint (node, "vss-oui", ntohl (mp->vss_oui)); + if (mp->is_ipv6) { - clib_memcpy (&ip6, &mp->dhcp_server, sizeof (ip6)); - vat_json_object_add_ip6 (node, "server_address", ip6); clib_memcpy (&ip6, &mp->dhcp_src_address, sizeof (ip6)); vat_json_object_add_ip6 (node, "src_address", ip6); } else { - clib_memcpy (&ip4, &mp->dhcp_server, sizeof (ip4)); - vat_json_object_add_ip4 (node, "server_address", ip4); clib_memcpy (&ip4, &mp->dhcp_src_address, sizeof (ip4)); vat_json_object_add_ip4 (node, "src_address", ip4); } - vat_json_object_add_uint (node, "vss-fib-id", ntohl (mp->vss_fib_id)); - vat_json_object_add_uint (node, "vss-oui", ntohl (mp->vss_oui)); + + for (i = 0; i < count; i++) + { + s = &mp->servers[i]; + + vat_json_object_add_uint (node, "server-table-id", + ntohl (s->server_vrf_id)); + + if (mp->is_ipv6) + { + clib_memcpy (&ip4, &s->dhcp_server, sizeof (ip4)); + vat_json_object_add_ip4 (node, "src_address", ip4); + } + else + { + clib_memcpy (&ip6, &s->dhcp_server, sizeof (ip6)); + vat_json_object_add_ip6 (node, "server_address", ip6); + } + } } static int diff --git a/src/vnet/dhcp/client.c b/src/vnet/dhcp/client.c index d34c5a64..29749a33 100644 --- a/src/vnet/dhcp/client.c +++ b/src/vnet/dhcp/client.c @@ -366,7 +366,7 @@ send_dhcp_pkt (dhcp_client_main_t * dcm, dhcp_client_t * c, o = (dhcp_option_t * )dhcp->options; /* Send option 53, the DHCP message type */ - o->option = 53; + o->option = DHCP_PACKET_OPTION_MSG_TYPE; o->length = 1; o->data[0] = type; o = (dhcp_option_t *) (((uword) o) + (o->length + 2)); diff --git a/src/vnet/dhcp/dhcp.api b/src/vnet/dhcp/dhcp.api index 8daadd8c..2db85a79 100644 --- a/src/vnet/dhcp/dhcp.api +++ b/src/vnet/dhcp/dhcp.api @@ -137,19 +137,25 @@ define dhcp_proxy_dump u8 is_ip6; }; +typeonly manual_print manual_endian define dhcp_server +{ + u32 server_vrf_id; + u8 dhcp_server[16]; +}; + /** \brief Tell client about a DHCP completion event @param client_index - opaque cookie to identify the sender */ -define dhcp_proxy_details +manual_endian manual_print define dhcp_proxy_details { u32 context; u32 rx_vrf_id; - u32 server_vrf_id; u32 vss_oui; u32 vss_fib_id; u8 is_ipv6; - u8 dhcp_server[16]; u8 dhcp_src_address[16]; + u8 count; + vl_api_dhcp_server_t servers[count]; }; /* diff --git a/src/vnet/dhcp/dhcp4_packet.h b/src/vnet/dhcp/dhcp4_packet.h index 28c4b156..07829f48 100644 --- a/src/vnet/dhcp/dhcp4_packet.h +++ b/src/vnet/dhcp/dhcp4_packet.h @@ -55,6 +55,11 @@ typedef enum { DHCP_PACKET_ACK=5, } dhcp_packet_type_t; +typedef enum dhcp_packet_option_t_ +{ + DHCP_PACKET_OPTION_MSG_TYPE = 53, +} dhcp_packet_option_t; + /* charming antique: 99.130.83.99 is the dhcp magic cookie */ #define DHCP_MAGIC (clib_host_to_net_u32(0x63825363)) diff --git a/src/vnet/dhcp/dhcp4_proxy_node.c b/src/vnet/dhcp/dhcp4_proxy_node.c index 88a99249..1c84881a 100644 --- a/src/vnet/dhcp/dhcp4_proxy_node.c +++ b/src/vnet/dhcp/dhcp4_proxy_node.c @@ -135,18 +135,17 @@ dhcp_proxy_to_server_input (vlib_main_t * vm, u32 original_sw_if_index = 0; u8 *end = NULL; u32 fib_index; - dhcp_server_t * server; + dhcp_proxy_t *proxy; + dhcp_server_t *server; u32 rx_sw_if_index; dhcp_option_t *o; u32 len = 0; vlib_buffer_free_list_t *fl; + u8 is_discover = 0; bi0 = from[0]; - to_next[0] = bi0; from += 1; - to_next += 1; n_left_from -= 1; - n_left_to_next -= 1; b0 = vlib_get_buffer (vm, bi0); @@ -172,16 +171,17 @@ dhcp_proxy_to_server_input (vlib_main_t * vm, rx_sw_if_index = vnet_buffer(b0)->sw_if_index[VLIB_RX]; fib_index = im->fib_index_by_sw_if_index [rx_sw_if_index]; - server = dhcp_get_server(dpm, fib_index, FIB_PROTOCOL_IP4); - - if (PREDICT_FALSE (NULL == server)) + proxy = dhcp_get_proxy(dpm, fib_index, FIB_PROTOCOL_IP4); + + if (PREDICT_FALSE (NULL == proxy)) { error0 = DHCP_PROXY_ERROR_NO_SERVER; next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_DROP; pkts_no_server++; goto do_trace; } - + + server = &proxy->dhcp_servers[0]; vlib_buffer_advance (b0, -(sizeof(*ip0))); ip0 = vlib_buffer_get_current (b0); @@ -198,7 +198,7 @@ dhcp_proxy_to_server_input (vlib_main_t * vm, sum0 = ip0->checksum; old0 = ip0->src_address.as_u32; - new0 = server->dhcp_src_address.ip4.as_u32; + new0 = proxy->dhcp_src_address.ip4.as_u32; ip0->src_address.as_u32 = new0; sum0 = ip_csum_update (sum0, old0, new0, ip4_header_t /* structure */, @@ -209,7 +209,7 @@ dhcp_proxy_to_server_input (vlib_main_t * vm, vnet_buffer(b0)->sw_if_index[VLIB_TX] = server->server_fib_index; - h0->gateway_ip_address.as_u32 = server->dhcp_src_address.ip4.as_u32; + h0->gateway_ip_address.as_u32 = proxy->dhcp_src_address.ip4.as_u32; pkts_to_server++; o = (dhcp_option_t *) h0->options; @@ -220,7 +220,16 @@ dhcp_proxy_to_server_input (vlib_main_t * vm, end = b0->data + b0->current_data + b0->current_length; /* TLVs are not performance-friendly... */ while (o->option != 0xFF /* end of options */ && (u8 *)o < end) + { + if (DHCP_PACKET_OPTION_MSG_TYPE == o->option) + { + if (DHCP_PACKET_DISCOVER == o->data[0]) + { + is_discover = 1; + } + } o = (dhcp_option_t *) (((uword) o) + (o->length + 2)); + } fl = vlib_buffer_get_free_list (vm, b0->free_list_index); // start write at (option*)o, some packets have padding @@ -340,6 +349,65 @@ dhcp_proxy_to_server_input (vlib_main_t * vm, next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP; + /* + * If we have multiple servers configured and this is the + * client's discover message, then send copies to each of + * those servers + */ + if (is_discover && vec_len(proxy->dhcp_servers) > 1) + { + u32 ii; + + for (ii = 1; ii < vec_len(proxy->dhcp_servers); ii++) + { + vlib_buffer_t *c0; + u32 ci0; + + c0 = vlib_buffer_copy(vm, b0); + ci0 = vlib_get_buffer_index(vm, c0); + server = &proxy->dhcp_servers[ii]; + + ip0 = vlib_buffer_get_current (c0); + + sum0 = ip0->checksum; + old0 = ip0->dst_address.as_u32; + new0 = server->dhcp_server.ip4.as_u32; + ip0->dst_address.as_u32 = server->dhcp_server.ip4.as_u32; + sum0 = ip_csum_update (sum0, old0, new0, + ip4_header_t /* structure */, + dst_address /* changed member */); + ip0->checksum = ip_csum_fold (sum0); + + to_next[0] = ci0; + to_next += 1; + n_left_to_next -= 1; + + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, + to_next, n_left_to_next, + ci0, next0); + + if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) + { + dhcp_proxy_trace_t *tr; + + tr = vlib_add_trace (vm, node, c0, sizeof (*tr)); + tr->which = 0; /* to server */ + tr->error = error0; + tr->original_sw_if_index = original_sw_if_index; + tr->sw_if_index = sw_if_index; + if (next0 == DHCP_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP) + tr->trace_ip4_address.as_u32 = server->dhcp_server.ip4.as_u32; + } + + if (PREDICT_FALSE(0 == n_left_to_next)) + { + vlib_put_next_frame (vm, node, next_index, + n_left_to_next); + vlib_get_next_frame (vm, node, next_index, + to_next, n_left_to_next); + } + } + } do_trace: if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) { @@ -350,10 +418,15 @@ dhcp_proxy_to_server_input (vlib_main_t * vm, tr->original_sw_if_index = original_sw_if_index; tr->sw_if_index = sw_if_index; if (next0 == DHCP_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP) - tr->trace_ip4_address.as_u32 = server->dhcp_server.ip4.as_u32; + tr->trace_ip4_address.as_u32 = + proxy->dhcp_servers[0].dhcp_server.ip4.as_u32; } do_enqueue: + 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); @@ -437,7 +510,8 @@ dhcp_proxy_to_client_input (vlib_main_t * vm, u32 error0 = (u32)~0; vnet_sw_interface_t *swif; u32 fib_index; - dhcp_server_t * server; + dhcp_proxy_t *proxy; + dhcp_server_t *server; u32 original_sw_if_index = (u32) ~0; ip4_address_t relay_addr = { .as_u32 = 0, @@ -547,20 +621,26 @@ dhcp_proxy_to_client_input (vlib_main_t * vm, } fib_index = im->fib_index_by_sw_if_index [sw_if_index]; - server = dhcp_get_server(dpm, fib_index, FIB_PROTOCOL_IP4); + proxy = dhcp_get_proxy(dpm, fib_index, FIB_PROTOCOL_IP4); - if (PREDICT_FALSE (NULL == server)) + if (PREDICT_FALSE (NULL == proxy)) { error0 = DHCP_PROXY_ERROR_NO_SERVER; goto drop_packet; } - if (ip0->src_address.as_u32 != server->dhcp_server.ip4.as_u32) - { - error0 = DHCP_PROXY_ERROR_BAD_SVR_FIB_OR_ADDRESS; - goto drop_packet; + vec_foreach(server, proxy->dhcp_servers) + { + if (ip0->src_address.as_u32 == server->dhcp_server.ip4.as_u32) + { + goto server_found; + } } + error0 = DHCP_PROXY_ERROR_BAD_SVR_FIB_OR_ADDRESS; + goto drop_packet; + + server_found: vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index; swif = vnet_get_sw_interface (vnm, sw_if_index); @@ -709,9 +789,8 @@ dhcp4_proxy_set_server (ip46_address_t *addr, if (is_del) { - rc = dhcp_proxy_server_del (FIB_PROTOCOL_IP4, rx_fib_index); - - if (0 == rc) + if (dhcp_proxy_server_del (FIB_PROTOCOL_IP4, rx_fib_index, + addr, server_table_id)) { fib_table_entry_special_remove(rx_fib_index, &all_1s, @@ -809,29 +888,35 @@ VLIB_CLI_COMMAND (dhcp_proxy_set_command, static) = { static u8 * format_dhcp4_proxy_server (u8 * s, va_list * args) { - dhcp_server_t * server = va_arg (*args, dhcp_server_t *); + dhcp_proxy_t *proxy = va_arg (*args, dhcp_proxy_t *); ip4_fib_t * rx_fib, * server_fib; + dhcp_server_t *server; - if (server == 0) + if (proxy == 0) { - s = format (s, "%=16s%=16s%=14s%=14s", "Server", "Src Address", - "Server FIB", "RX FIB"); + s = format (s, "%=14s%=16s%s", "RX FIB", "Src Address", + "Servers FIB,Address"); return s; } - server_fib = ip4_fib_get(server->server_fib_index); - rx_fib = ip4_fib_get(server->rx_fib_index); + rx_fib = ip4_fib_get(proxy->rx_fib_index); + + s = format (s, "%=14u%=16U", + rx_fib->table_id, + format_ip46_address, &proxy->dhcp_src_address, IP46_TYPE_ANY); - s = format (s, "%=16U%=16U%=14u%=14u", - format_ip46_address, &server->dhcp_server, IP46_TYPE_ANY, - format_ip46_address, &server->dhcp_src_address, IP46_TYPE_ANY, - server_fib->table_id, - rx_fib->table_id); + vec_foreach(server, proxy->dhcp_servers) + { + server_fib = ip4_fib_get(server->server_fib_index); + s = format (s, "%u,%U ", + server_fib->table_id, + format_ip46_address, &server->dhcp_server, IP46_TYPE_ANY); + } return s; } static int -dhcp4_proxy_show_walk (dhcp_server_t *server, +dhcp4_proxy_show_walk (dhcp_proxy_t *server, void *ctx) { vlib_main_t * vm = ctx; diff --git a/src/vnet/dhcp/dhcp6_proxy_node.c b/src/vnet/dhcp/dhcp6_proxy_node.c index 58674209..524cb095 100644 --- a/src/vnet/dhcp/dhcp6_proxy_node.c +++ b/src/vnet/dhcp/dhcp6_proxy_node.c @@ -140,7 +140,8 @@ dhcpv6_proxy_to_server_input (vlib_main_t * vm, ip6_main_t * im = &ip6_main; ip6_address_t * src; int bogus_length; - dhcp_server_t * server; + dhcp_proxy_t *proxy; + dhcp_server_t *server; u32 rx_fib_idx = 0, server_fib_idx = 0; next_index = node->cached_next_index; @@ -176,13 +177,11 @@ dhcpv6_proxy_to_server_input (vlib_main_t * vm, u8 client_src_mac[6]; vlib_buffer_free_list_t *fl; dhcp_vss_t *vss; + u8 is_solicit = 0; bi0 = from[0]; - to_next[0] = bi0; from += 1; - to_next += 1; n_left_from -= 1; - n_left_to_next -= 1; b0 = vlib_get_buffer (vm, bi0); @@ -227,9 +226,9 @@ dhcpv6_proxy_to_server_input (vlib_main_t * vm, /* Send to DHCPV6 server via the configured FIB */ rx_sw_if_index = sw_if_index = vnet_buffer(b0)->sw_if_index[VLIB_RX]; rx_fib_idx = im->mfib_index_by_sw_if_index [rx_sw_if_index]; - server = dhcp_get_server(dpm, rx_fib_idx, FIB_PROTOCOL_IP6); + proxy = dhcp_get_proxy(dpm, rx_fib_idx, FIB_PROTOCOL_IP6); - if (PREDICT_FALSE (NULL == server)) + if (PREDICT_FALSE (NULL == proxy)) { error0 = DHCPV6_PROXY_ERROR_NO_SERVER; next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP; @@ -237,6 +236,7 @@ dhcpv6_proxy_to_server_input (vlib_main_t * vm, goto do_trace; } + server = &proxy->dhcp_servers[0]; server_fib_idx = server->server_fib_index; vnet_buffer(b0)->sw_if_index[VLIB_TX] = server_fib_idx; @@ -371,18 +371,19 @@ dhcpv6_proxy_to_server_input (vlib_main_t * vm, ip1->payload_length = u1->length; ip1->protocol = PROTO_UDP; ip1->hop_limit = HOP_COUNT_LIMIT; - src = (server->dhcp_server.ip6.as_u64[0] || - server->dhcp_server.ip6.as_u64[1]) ? - &server->dhcp_server.ip6 : &all_dhcpv6_server_address; + src = ((server->dhcp_server.ip6.as_u64[0] || + server->dhcp_server.ip6.as_u64[1]) ? + &server->dhcp_server.ip6 : + &all_dhcpv6_server_address); copy_ip6_address(&ip1->dst_address, src); ia0 = ip6_interface_first_global_or_site_address (&ip6_main, vnet_buffer(b0)->sw_if_index[VLIB_RX]); - src = (server->dhcp_src_address.ip6.as_u64[0] || - server->dhcp_src_address.ip6.as_u64[1]) ? - &server->dhcp_src_address.ip6 : ia0; + src = (proxy->dhcp_src_address.ip6.as_u64[0] || + proxy->dhcp_src_address.ip6.as_u64[1]) ? + &proxy->dhcp_src_address.ip6 : ia0; if (ia0 == 0) { error0 = DHCPV6_PROXY_ERROR_NO_SRC_ADDRESS; @@ -400,6 +401,66 @@ dhcpv6_proxy_to_server_input (vlib_main_t * vm, next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP; + is_solicit = (DHCPV6_MSG_SOLICIT == h0->u.msg_type); + + /* + * If we have multiple servers configured and this is the + * client's discover message, then send copies to each of + * those servers + */ + if (is_solicit && vec_len(proxy->dhcp_servers) > 1) + { + u32 ii; + + for (ii = 1; ii < vec_len(proxy->dhcp_servers); ii++) + { + vlib_buffer_t *c0; + u32 ci0; + + c0 = vlib_buffer_copy(vm, b0); + ci0 = vlib_get_buffer_index(vm, c0); + server = &proxy->dhcp_servers[ii]; + + ip0 = vlib_buffer_get_current (c0); + + src = ((server->dhcp_server.ip6.as_u64[0] || + server->dhcp_server.ip6.as_u64[1]) ? + &server->dhcp_server.ip6 : + &all_dhcpv6_server_address); + copy_ip6_address(&ip1->dst_address, src); + + to_next[0] = ci0; + to_next += 1; + n_left_to_next -= 1; + + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, + to_next, n_left_to_next, + ci0, next0); + + if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) + { + dhcpv6_proxy_trace_t *tr; + + tr = vlib_add_trace (vm, node, c0, sizeof (*tr)); + tr->which = 0; /* to server */ + tr->error = error0; + tr->original_sw_if_index = rx_sw_if_index; + tr->sw_if_index = sw_if_index; + if (next0 == DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP) + copy_ip6_address((ip6_address_t *)&tr->packet_data[0], + &server->dhcp_server.ip6); + } + + if (PREDICT_FALSE(0 == n_left_to_next)) + { + vlib_put_next_frame (vm, node, next_index, + n_left_to_next); + vlib_get_next_frame (vm, node, next_index, + to_next, n_left_to_next); + } + } + } + do_trace: if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) { @@ -414,6 +475,10 @@ dhcpv6_proxy_to_server_input (vlib_main_t * vm, } do_enqueue: + 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); @@ -475,7 +540,8 @@ dhcpv6_proxy_to_client_input (vlib_main_t * vm, u32 n_left_from, * from; ethernet_main_t *em = ethernet_get_main (vm); dhcp_proxy_main_t * dm = &dhcp_proxy_main; - dhcp_server_t * server; + dhcp_proxy_t *proxy; + dhcp_server_t *server; vnet_main_t * vnm = vnet_get_main(); int bogus_length; @@ -588,9 +654,9 @@ dhcpv6_proxy_to_client_input (vlib_main_t * vm, vlib_buffer_advance (b0, sizeof(*r0)); client_fib_idx = im->mfib_index_by_sw_if_index[sw_if_index]; - server = dhcp_get_server(dm, client_fib_idx, FIB_PROTOCOL_IP6); + proxy = dhcp_get_proxy(dm, client_fib_idx, FIB_PROTOCOL_IP6); - if (NULL == server) + if (NULL == proxy) { error0 = DHCPV6_PROXY_ERROR_NO_SERVER; goto drop_packet; @@ -599,15 +665,21 @@ dhcpv6_proxy_to_client_input (vlib_main_t * vm, server_fib_idx = im->fib_index_by_sw_if_index [vnet_buffer(b0)->sw_if_index[VLIB_RX]]; - 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]) - { - //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; + } + } + + //drop packet if not from server with configured address or FIB + error0 = DHCPV6_PROXY_ERROR_BAD_SVR_FIB_OR_ADDRESS; + goto drop_packet; + server_found: vnet_buffer (b0)->sw_if_index[VLIB_TX] = original_sw_if_index = sw_if_index; @@ -773,9 +845,8 @@ dhcp6_proxy_set_server (ip46_address_t *addr, if (is_del) { - rc = dhcp_proxy_server_del (FIB_PROTOCOL_IP6, rx_fib_index); - - if (0 == rc) + if (dhcp_proxy_server_del (FIB_PROTOCOL_IP6, rx_fib_index, + addr, server_table_id)) { mfib_table_entry_delete(rx_fib_index, &all_dhcp_servers, @@ -893,43 +964,50 @@ VLIB_CLI_COMMAND (dhcpv6_proxy_set_command, static) = { static u8 * format_dhcp6_proxy_server (u8 * s, va_list * args) { - dhcp_server_t * server = va_arg (*args, dhcp_server_t *); + dhcp_proxy_t * proxy = va_arg (*args, dhcp_proxy_t *); ip6_fib_t *server_fib; + dhcp_server_t *server; ip6_mfib_t *rx_fib; - if (NULL == server) + if (proxy == 0) { - s = format (s, "%=40s%=40s%=14s%=14s", "Server Address", "Source Address", - "Server FIB", "RX FIB"); + s = format (s, "%=14s%=16s%s", "RX FIB", "Src Address", + "Servers FIB,Address"); return s; } - server_fib = ip6_fib_get(server->server_fib_index); - rx_fib = ip6_mfib_get(server->rx_fib_index); + rx_fib = ip6_mfib_get(proxy->rx_fib_index); + + s = format (s, "%=14u%=16U", + rx_fib->table_id, + format_ip46_address, &proxy->dhcp_src_address, IP46_TYPE_ANY); + vec_foreach(server, proxy->dhcp_servers) + { + server_fib = ip6_fib_get(server->server_fib_index); + s = format (s, "%u,%U ", + server_fib->table_id, + format_ip46_address, &server->dhcp_server, IP46_TYPE_ANY); + } - s = format (s, "%=40U%=40U%=14u%=14u", - format_ip46_address, &server->dhcp_server, IP46_TYPE_ANY, - format_ip46_address, &server->dhcp_src_address, IP46_TYPE_ANY, - server_fib->table_id, rx_fib->table_id); return s; } static int -dhcp6_proxy_show_walk (dhcp_server_t *server, +dhcp6_proxy_show_walk (dhcp_proxy_t *proxy, void *ctx) { vlib_main_t * vm = ctx; - vlib_cli_output (vm, "%U", format_dhcp6_proxy_server, server); + vlib_cli_output (vm, "%U", format_dhcp6_proxy_server, proxy); return (1); } static clib_error_t * dhcpv6_proxy_show_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) + unformat_input_t * input, + vlib_cli_command_t * cmd) { vlib_cli_output (vm, "%U", format_dhcp6_proxy_server, NULL /* header line */); diff --git a/src/vnet/dhcp/dhcp_api.c b/src/vnet/dhcp/dhcp_api.c index ce34f6a4..e9c757e8 100644 --- a/src/vnet/dhcp/dhcp_api.c +++ b/src/vnet/dhcp/dhcp_api.c @@ -24,6 +24,7 @@ #include #include #include +#include #include @@ -113,46 +114,73 @@ vl_api_dhcp_proxy_dump_t_handler (vl_api_dhcp_proxy_dump_t * mp) if (q == 0) return; - dhcp_proxy_dump ((mp->is_ip6 == 0 ? + dhcp_proxy_dump ((mp->is_ip6 == 1 ? FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4), q, mp->context); } void dhcp_send_details (fib_protocol_t proto, - void *opaque, - u32 context, - const ip46_address_t * server, - const ip46_address_t * src, - u32 server_fib_id, - u32 rx_fib_id, u32 vss_fib_id, u32 vss_oui) + void *opaque, u32 context, dhcp_proxy_t * proxy) { vl_api_dhcp_proxy_details_t *mp; unix_shared_memory_queue_t *q = opaque; - - mp = vl_msg_api_alloc (sizeof (*mp)); + vl_api_dhcp_server_t *v_server; + dhcp_server_t *server; + fib_table_t *s_fib; + dhcp_vss_t *vss; + u32 count; + size_t n; + + count = vec_len (proxy->dhcp_servers); + n = sizeof (*mp) + (count * sizeof (vl_api_dhcp_server_t)); + mp = vl_msg_api_alloc (n); if (!mp) return; - memset (mp, 0, sizeof (*mp)); + memset (mp, 0, n); mp->_vl_msg_id = ntohs (VL_API_DHCP_PROXY_DETAILS); mp->context = context; - - mp->rx_vrf_id = htonl (rx_fib_id); - mp->server_vrf_id = htonl (server_fib_id); - mp->vss_oui = htonl (vss_oui); - mp->vss_fib_id = htonl (vss_fib_id); + mp->count = count; mp->is_ipv6 = (proto == FIB_PROTOCOL_IP6); + mp->rx_vrf_id = + htonl (dhcp_proxy_rx_table_get_table_id (proto, proxy->rx_fib_index)); + + vss = dhcp_get_vss_info (&dhcp_proxy_main, proxy->rx_fib_index, proto); + + if (NULL != vss) + { + mp->vss_oui = htonl (vss->oui); + mp->vss_fib_id = htonl (vss->fib_id); + } + + vec_foreach_index (count, proxy->dhcp_servers) + { + server = &proxy->dhcp_servers[count]; + v_server = &mp->servers[count]; + + s_fib = fib_table_get (server->server_fib_index, proto); + + v_server->server_vrf_id = htonl (s_fib->ft_table_id); + + if (mp->is_ipv6) + { + memcpy (v_server->dhcp_server, &server->dhcp_server.ip6, 16); + } + else + { + /* put the address in the first bytes */ + memcpy (v_server->dhcp_server, &server->dhcp_server.ip4, 4); + } + } if (mp->is_ipv6) { - memcpy (mp->dhcp_server, server, 16); - memcpy (mp->dhcp_src_address, src, 16); + memcpy (mp->dhcp_src_address, &proxy->dhcp_src_address.ip6, 16); } else { /* put the address in the first bytes */ - memcpy (mp->dhcp_server, &server->ip4, 4); - memcpy (mp->dhcp_src_address, &src->ip4, 4); + memcpy (mp->dhcp_src_address, &proxy->dhcp_src_address.ip4, 4); } vl_msg_api_send_shmem (q, (u8 *) & mp); } diff --git a/src/vnet/dhcp/dhcp_proxy.c b/src/vnet/dhcp/dhcp_proxy.c index 8e31c3db..ba7f354e 100644 --- a/src/vnet/dhcp/dhcp_proxy.c +++ b/src/vnet/dhcp/dhcp_proxy.c @@ -44,7 +44,7 @@ dhcp_proxy_rx_table_unlock (fib_protocol_t proto, mfib_table_unlock(fib_index, proto); } -static u32 + u32 dhcp_proxy_rx_table_get_table_id (fib_protocol_t proto, u32 fib_index) { @@ -72,7 +72,7 @@ dhcp_proxy_walk (fib_protocol_t proto, void *ctx) { dhcp_proxy_main_t * dpm = &dhcp_proxy_main; - dhcp_server_t * server; + dhcp_proxy_t * server; u32 server_index, i; vec_foreach_index (i, dpm->dhcp_server_index_by_rx_fib_index[proto]) @@ -124,31 +124,68 @@ dhcp_vss_walk (fib_protocol_t proto, } } +static u32 +dhcp_proxy_server_find (dhcp_proxy_t *proxy, + fib_protocol_t proto, + ip46_address_t *addr, + u32 server_table_id) +{ + dhcp_server_t *server; + u32 ii, fib_index; + + vec_foreach_index(ii, proxy->dhcp_servers) + { + server = &proxy->dhcp_servers[ii]; + fib_index = fib_table_find(proto, server_table_id); + + if (ip46_address_is_equal(&server->dhcp_server, + addr) && + (server->server_fib_index == fib_index)) + { + return (ii); + } + } + return (~0); +} + int dhcp_proxy_server_del (fib_protocol_t proto, - u32 rx_fib_index) + u32 rx_fib_index, + ip46_address_t *addr, + u32 server_table_id) { dhcp_proxy_main_t * dpm = &dhcp_proxy_main; - dhcp_server_t * server = 0; - int rc = 0; + dhcp_proxy_t *proxy = 0; - server = dhcp_get_server(dpm, rx_fib_index, proto); + proxy = dhcp_get_proxy(dpm, rx_fib_index, proto); - if (NULL == server) - { - rc = VNET_API_ERROR_NO_SUCH_ENTRY; - } - else + if (NULL != proxy) { - /* Use the default server again. */ - dpm->dhcp_server_index_by_rx_fib_index[proto][rx_fib_index] = ~0; + dhcp_server_t *server; + u32 index; - fib_table_unlock (server->server_fib_index, proto); + index = dhcp_proxy_server_find(proxy, proto, addr, server_table_id); - pool_put (dpm->dhcp_servers[proto], server); + if (~0 != index) + { + server = &proxy->dhcp_servers[index]; + fib_table_unlock (server->server_fib_index, proto); + + vec_del1(proxy->dhcp_servers, index); + + if (0 == vec_len(proxy->dhcp_servers)) + { + /* no servers left, delete the proxy config */ + dpm->dhcp_server_index_by_rx_fib_index[proto][rx_fib_index] = ~0; + vec_free(proxy->dhcp_servers); + pool_put (dpm->dhcp_servers[proto], proxy); + return (1); + } + } } - return (rc); + /* the proxy still exists */ + return (0); } int @@ -159,48 +196,42 @@ dhcp_proxy_server_add (fib_protocol_t proto, u32 server_table_id) { dhcp_proxy_main_t * dpm = &dhcp_proxy_main; - dhcp_server_t * server = 0; + dhcp_proxy_t * proxy = 0; int new = 0; - server = dhcp_get_server(dpm, rx_fib_index, proto); + proxy = dhcp_get_proxy(dpm, rx_fib_index, proto); - if (NULL == server) + if (NULL == proxy) { vec_validate_init_empty(dpm->dhcp_server_index_by_rx_fib_index[proto], rx_fib_index, ~0); - pool_get (dpm->dhcp_servers[proto], server); - memset (server, 0, sizeof (*server)); + pool_get (dpm->dhcp_servers[proto], proxy); + memset (proxy, 0, sizeof (*proxy)); new = 1; dpm->dhcp_server_index_by_rx_fib_index[proto][rx_fib_index] = - server - dpm->dhcp_servers[proto]; + proxy - dpm->dhcp_servers[proto]; - server->rx_fib_index = rx_fib_index; - server->server_fib_index = - fib_table_find_or_create_and_lock(proto, server_table_id); + proxy->dhcp_src_address = *src_address; + proxy->rx_fib_index = rx_fib_index; } else { - /* modify, may need to swap server FIBs */ - u32 tmp_index; - - tmp_index = fib_table_find(proto, server_table_id); - - if (tmp_index != server->server_fib_index) + if (~0 != dhcp_proxy_server_find(proxy, proto, addr, server_table_id)) { - tmp_index = server->server_fib_index; - - /* certainly swapping if the fib doesn't exist */ - server->server_fib_index = - fib_table_find_or_create_and_lock(proto, server_table_id); - fib_table_unlock (tmp_index, proto); + return (new); } } - server->dhcp_server = *addr; - server->dhcp_src_address = *src_address; + dhcp_server_t server = { + .dhcp_server = *addr, + .server_fib_index = fib_table_find_or_create_and_lock(proto, + server_table_id), + }; + + vec_add1(proxy->dhcp_servers, server); return (new); } @@ -213,31 +244,15 @@ typedef struct dhcp4_proxy_dump_walk_ctx_t_ } dhcp_proxy_dump_walk_cxt_t; static int -dhcp_proxy_dump_walk (dhcp_server_t *server, +dhcp_proxy_dump_walk (dhcp_proxy_t *proxy, void *arg) { dhcp_proxy_dump_walk_cxt_t *ctx = arg; - fib_table_t *s_fib; - u32 rx_table_id; - dhcp_vss_t *v; - - v = dhcp_get_vss_info(&dhcp_proxy_main, - server->rx_fib_index, - ctx->proto); - - s_fib = fib_table_get(server->server_fib_index, ctx->proto); - rx_table_id = dhcp_proxy_rx_table_get_table_id(server->rx_fib_index, - ctx->proto); dhcp_send_details(ctx->proto, ctx->opaque, ctx->context, - &server->dhcp_server, - &server->dhcp_src_address, - s_fib->ft_table_id, - rx_table_id, - (v ? v->fib_id : 0), - (v ? v->oui : 0)); + proxy); return (1); } diff --git a/src/vnet/dhcp/dhcp_proxy.h b/src/vnet/dhcp/dhcp_proxy.h index 708e92f3..ef2bc0a1 100644 --- a/src/vnet/dhcp/dhcp_proxy.h +++ b/src/vnet/dhcp/dhcp_proxy.h @@ -58,32 +58,58 @@ typedef struct dhcp_vss_t_ { } dhcp_vss_t; /** - * @brief A DHCP proxy server represenation + * @brief A representation of a single DHCP Server within a given VRF config */ -typedef struct dhcp_server_t_ { +typedef struct dhcp_server_t_ +{ /** * @brief The address of the DHCP server to which to relay the client's * messages */ ip46_address_t dhcp_server; - /** - * @brief The source address to use in relayed messaes - */ - ip46_address_t dhcp_src_address; - /** * @brief The FIB index (not the external Table-ID) in which the server * is reachable. */ u32 server_fib_index; +} dhcp_server_t; + +/** + * @brief A DHCP proxy represenation fpr per-client VRF config + */ +typedef struct dhcp_proxy_t_ { + /** + * @brief The set of DHCP servers to which messages are relayed. + * If multiple servers are configured then discover/solict messages + * are relayed to each. A cookie is maintained for the relay, and only + * one message is replayed to the client, based on the presence of the + * cookie. + * The expectation is there are only 1 or 2 servers, hence no fancy DB. + */ + dhcp_server_t *dhcp_servers; + + /** + * @brief Hash table of pending requets key'd on the clients MAC address + */ + uword *dhcp_pending; + + /** + * @brief A lock for the pending request DB. + */ + int lock; + + /** + * @brief The source address to use in relayed messaes + */ + ip46_address_t dhcp_src_address; /** * @brief The FIB index (not the external Table-ID) in which the client * is resides. */ u32 rx_fib_index; -} dhcp_server_t; +} dhcp_proxy_t; #define DHCP_N_PROTOS (FIB_PROTOCOL_IP6 + 1) @@ -92,7 +118,7 @@ typedef struct dhcp_server_t_ { */ typedef struct { /* Pool of DHCP servers */ - dhcp_server_t *dhcp_servers[DHCP_N_PROTOS]; + dhcp_proxy_t *dhcp_servers[DHCP_N_PROTOS]; /* Pool of selected DHCP server. Zero is the default server */ u32 * dhcp_server_index_by_rx_fib_index[DHCP_N_PROTOS]; @@ -114,12 +140,7 @@ extern dhcp_proxy_main_t dhcp_proxy_main; void dhcp_send_details (fib_protocol_t proto, void *opaque, u32 context, - const ip46_address_t *server, - const ip46_address_t *src, - u32 server_fib_id, - u32 rx_fib_id, - u32 vss_fib_id, - u32 vss_oui); + dhcp_proxy_t *proxy); /** * @brief Show (on CLI) a VSS config during a show walk @@ -157,16 +178,22 @@ int dhcp_proxy_server_add(fib_protocol_t proto, /** * @brief Delete a DHCP proxy config - * @return 0 is deleted, otherwise an error code + * @return 1 if the proxy is deleted, 0 otherwise */ int dhcp_proxy_server_del(fib_protocol_t proto, - u32 rx_fib_index); + u32 rx_fib_index, + ip46_address_t *addr, + u32 server_table_id); + +u32 +dhcp_proxy_rx_table_get_table_id (fib_protocol_t proto, + u32 fib_index); /** * @brief Callback function invoked for each DHCP proxy entry * return 0 to break the walk, non-zero otherwise. */ -typedef int (*dhcp_proxy_walk_fn_t)(dhcp_server_t *server, +typedef int (*dhcp_proxy_walk_fn_t)(dhcp_proxy_t *server, void *ctx); /** @@ -191,6 +218,18 @@ void dhcp_vss_walk(fib_protocol_t proto, dhcp_vss_walk_fn_t fn, void *ctx); +/** + * @brief Lock a proxy object to prevent simultaneous access of its + * pending store + */ +void dhcp_proxy_lock (dhcp_proxy_t *server); + +/** + * @brief Lock a proxy object to prevent simultaneous access of its + * pending store + */ +void dhcp_proxy_unlock (dhcp_proxy_t *server); + /** * @brief Get the VSS data for the FIB index */ @@ -215,12 +254,12 @@ dhcp_get_vss_info (dhcp_proxy_main_t *dm, /** * @brief Get the DHCP proxy server data for the FIB index */ -static inline dhcp_server_t * -dhcp_get_server (dhcp_proxy_main_t *dm, - u32 rx_fib_index, - fib_protocol_t proto) +static inline dhcp_proxy_t * +dhcp_get_proxy (dhcp_proxy_main_t *dm, + u32 rx_fib_index, + fib_protocol_t proto) { - dhcp_server_t *s = NULL; + dhcp_proxy_t *s = NULL; if (vec_len(dm->dhcp_server_index_by_rx_fib_index[proto]) > rx_fib_index && dm->dhcp_server_index_by_rx_fib_index[proto][rx_fib_index] != ~0) diff --git a/src/vnet/ip/ip6_packet.h b/src/vnet/ip/ip6_packet.h index 6eabeef1..9bf19edb 100644 --- a/src/vnet/ip/ip6_packet.h +++ b/src/vnet/ip/ip6_packet.h @@ -79,6 +79,8 @@ typedef CLIB_PACKED (union { #define ip46_address_reset(ip46) ((ip46)->as_u64[0] = (ip46)->as_u64[1] = 0) #define ip46_address_cmp(ip46_1, ip46_2) (memcmp(ip46_1, ip46_2, sizeof(*ip46_1))) #define ip46_address_is_zero(ip46) (((ip46)->as_u64[0] == 0) && ((ip46)->as_u64[1] == 0)) +#define ip46_address_is_equal(a1, a2) (((a1)->as_u64[0] == (a2)->as_u64[0]) \ + && ((a1)->as_u64[1] == (a2)->as_u64[1])) always_inline void ip46_from_addr_buf (u32 is_ipv6, u8 * buf, ip46_address_t * ip) diff --git a/src/vnet/pg/input.c b/src/vnet/pg/input.c index 4a65b024..2649798b 100644 --- a/src/vnet/pg/input.c +++ b/src/vnet/pg/input.c @@ -1373,6 +1373,7 @@ typedef struct u32 stream_index; u32 packet_length; + u32 sw_if_index; /* Use pre data for packet data. */ vlib_buffer_t buffer; @@ -1399,6 +1400,7 @@ format_pg_input_trace (u8 * s, va_list * va) s = format (s, "stream %d", t->stream_index); s = format (s, ", %d bytes", t->packet_length); + s = format (s, ", %d sw_if_index", t->sw_if_index); s = format (s, "\n%U%U", format_white_space, indent, format_vlib_buffer, &t->buffer); @@ -1458,6 +1460,9 @@ pg_input_trace (pg_main_t * pg, t0->packet_length = vlib_buffer_length_in_chain (vm, b0); t1->packet_length = vlib_buffer_length_in_chain (vm, b1); + t0->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + t1->sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_RX]; + clib_memcpy (&t0->buffer, b0, sizeof (b0[0]) - sizeof (b0->pre_data)); clib_memcpy (&t1->buffer, b1, sizeof (b1[0]) - sizeof (b1->pre_data)); @@ -1484,6 +1489,7 @@ pg_input_trace (pg_main_t * pg, t0->stream_index = stream_index; t0->packet_length = vlib_buffer_length_in_chain (vm, b0); + t0->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; clib_memcpy (&t0->buffer, b0, sizeof (b0[0]) - sizeof (b0->pre_data)); clib_memcpy (t0->buffer.pre_data, b0->data, sizeof (t0->buffer.pre_data)); diff --git a/test/test_dhcp.py b/test/test_dhcp.py index a09c9bdb..89667d3d 100644 --- a/test/test_dhcp.py +++ b/test/test_dhcp.py @@ -2,8 +2,10 @@ import unittest import socket +import struct from framework import VppTestCase, VppTestRunner +from vpp_neighbor import VppNeighbor from scapy.layers.l2 import Ether, getmacbyip from scapy.layers.inet import IP, UDP, ICMP @@ -11,7 +13,7 @@ from scapy.layers.inet6 import IPv6, in6_getnsmac, in6_mactoifaceid from scapy.layers.dhcp import DHCP, BOOTP, DHCPTypes from scapy.layers.dhcp6 import DHCP6, DHCP6_Solicit, DHCP6_RelayForward, \ DHCP6_RelayReply, DHCP6_Advertise, DHCP6OptRelayMsg, DHCP6OptIfaceId, \ - DHCP6OptStatusCode, DHCP6OptVSS, DHCP6OptClientLinkLayerAddr + DHCP6OptStatusCode, DHCP6OptVSS, DHCP6OptClientLinkLayerAddr, DHCP6_Request from socket import AF_INET, AF_INET6 from scapy.utils import inet_pton, inet_ntop from scapy.utils6 import in6_ptop @@ -140,7 +142,7 @@ class TestDHCP(VppTestCase): return data - def verify_dhcp_offer(self, pkt, intf): + def verify_dhcp_offer(self, pkt, intf, fib_id=0, oui=0): ether = pkt[Ether] self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff") self.assertEqual(ether.src, intf.local_mac) @@ -162,15 +164,22 @@ class TestDHCP(VppTestCase): is_offer = True self.assertTrue(is_offer) - data = self.validate_relay_options(pkt, intf, intf.local_ip4, 0, 0) + data = self.validate_relay_options(pkt, intf, intf.local_ip4, + fib_id, oui) + + def verify_dhcp_discover(self, pkt, intf, src_intf=None, fib_id=0, oui=0, + dst_mac=None, dst_ip=None): + if not dst_mac: + dst_mac = intf.remote_mac + if not dst_ip: + dst_ip = intf.remote_ip4 - def verify_dhcp_discover(self, pkt, intf, src_intf=None, fib_id=0, oui=0): ether = pkt[Ether] - self.assertEqual(ether.dst, intf.remote_mac) + self.assertEqual(ether.dst, dst_mac) self.assertEqual(ether.src, intf.local_mac) ip = pkt[IP] - self.assertEqual(ip.dst, intf.remote_ip4) + self.assertEqual(ip.dst, dst_ip) self.assertEqual(ip.src, intf.local_ip4) udp = pkt[UDP] @@ -195,13 +204,20 @@ class TestDHCP(VppTestCase): def verify_dhcp6_solicit(self, pkt, intf, peer_ip, peer_mac, fib_id=0, - oui=0): + oui=0, + dst_mac=None, + dst_ip=None): + if not dst_mac: + dst_mac = intf.remote_mac + if not dst_ip: + dst_ip = in6_ptop(intf.remote_ip6) + ether = pkt[Ether] - self.assertEqual(ether.dst, intf.remote_mac) + self.assertEqual(ether.dst, dst_mac) self.assertEqual(ether.src, intf.local_mac) ip = pkt[IPv6] - self.assertEqual(in6_ptop(ip.dst), in6_ptop(intf.remote_ip6)) + self.assertEqual(in6_ptop(ip.dst), dst_ip) self.assertEqual(in6_ptop(ip.src), in6_ptop(intf.local_ip6)) udp = pkt[UDP] @@ -447,6 +463,128 @@ class TestDHCP(VppTestCase): self.pg_enable_capture(self.pg_interfaces) self.pg_start() + rx = self.pg1.get_capture(1) + rx = rx[0] + self.verify_dhcp_discover(rx, self.pg1, src_intf=self.pg3, + fib_id=1, oui=4) + + # + # Add a second DHCP server in VRF 1 + # expect clients messages to be relay to both configured servers + # + self.pg1.generate_remote_hosts(2) + server_addr2 = socket.inet_pton(AF_INET, self.pg1.remote_hosts[1].ip4) + + self.vapi.dhcp_proxy_config(server_addr2, + src_addr, + rx_table_id=1, + server_table_id=1, + is_add=1) + + # + # We'll need an ARP entry for the server to send it packets + # + arp_entry = VppNeighbor(self, + self.pg1.sw_if_index, + self.pg1.remote_hosts[1].mac, + self.pg1.remote_hosts[1].ip4) + arp_entry.add_vpp_config() + + # + # Send a discover from the client. expect two relayed messages + # The frist packet is sent to the second server + # We're not enforcing that here, it's just the way it is. + # + self.pg3.add_stream(pkts_disc_vrf1) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg1.get_capture(2) + + option_82 = self.verify_dhcp_discover( + rx[0], self.pg1, + src_intf=self.pg3, + dst_mac=self.pg1.remote_hosts[1].mac, + dst_ip=self.pg1.remote_hosts[1].ip4, + fib_id=1, oui=4) + self.verify_dhcp_discover(rx[1], self.pg1, src_intf=self.pg3, + fib_id=1, oui=4) + + # + # Send both packets back. Client gets both. + # + p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / + IP(src=self.pg1.remote_ip4, dst=self.pg1.local_ip4) / + UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) / + BOOTP(op=1) / + DHCP(options=[('message-type', 'offer'), + ('relay_agent_Information', option_82), + ('end')])) + p2 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / + IP(src=self.pg1.remote_hosts[1].ip4, dst=self.pg1.local_ip4) / + UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) / + BOOTP(op=1) / + DHCP(options=[('message-type', 'offer'), + ('relay_agent_Information', option_82), + ('end')])) + pkts = [p1, p2] + + self.pg1.add_stream(pkts) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg3.get_capture(2) + + self.verify_dhcp_offer(rx[0], self.pg3, fib_id=1, oui=4) + self.verify_dhcp_offer(rx[1], self.pg3, fib_id=1, oui=4) + + # + # Ensure offers from non-servers are dropeed + # + p2 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / + IP(src="8.8.8.8", dst=self.pg1.local_ip4) / + UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) / + BOOTP(op=1) / + DHCP(options=[('message-type', 'offer'), + ('relay_agent_Information', option_82), + ('end')])) + self.send_and_assert_no_replies(self.pg1, p2, + "DHCP offer from non-server") + + # + # Ensure only the discover is sent to multiple servers + # + p_req_vrf1 = (Ether(dst="ff:ff:ff:ff:ff:ff", + src=self.pg3.remote_mac) / + IP(src="0.0.0.0", dst="255.255.255.255") / + UDP(sport=DHCP4_CLIENT_PORT, + dport=DHCP4_SERVER_PORT) / + BOOTP(op=1) / + DHCP(options=[('message-type', 'request'), + ('end')])) + + self.pg3.add_stream(p_req_vrf1) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg1.get_capture(1) + + # + # Remove the second DHCP server + # + self.vapi.dhcp_proxy_config(server_addr2, + src_addr, + rx_table_id=1, + server_table_id=1, + is_add=0) + + # + # Test we can still relay with the first + # + self.pg3.add_stream(pkts_disc_vrf1) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + rx = self.pg1.get_capture(1) rx = rx[0] self.verify_dhcp_discover(rx, self.pg1, src_intf=self.pg3, @@ -472,7 +610,7 @@ class TestDHCP(VppTestCase): self.vapi.dhcp_proxy_config(server_addr, src_addr, rx_table_id=1, - server_table_id=11, + server_table_id=1, is_add=0) self.send_and_assert_no_replies(self.pg2, pkts_disc_vrf0, @@ -500,18 +638,16 @@ class TestDHCP(VppTestCase): UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_CLIENT_PORT) / DHCP6_Solicit()) - pkts_solicit_vrf0 = [p_solicit_vrf0] p_solicit_vrf1 = (Ether(dst=dmac, src=self.pg3.remote_mac) / IPv6(src=dhcp_solicit_src_vrf1, dst=dhcp_solicit_dst) / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_CLIENT_PORT) / DHCP6_Solicit()) - pkts_solicit_vrf1 = [p_solicit_vrf1] - self.send_and_assert_no_replies(self.pg2, pkts_solicit_vrf0, + self.send_and_assert_no_replies(self.pg2, p_solicit_vrf0, "DHCP with no configuration") - self.send_and_assert_no_replies(self.pg3, pkts_solicit_vrf1, + self.send_and_assert_no_replies(self.pg3, p_solicit_vrf1, "DHCP with no configuration") # @@ -525,9 +661,9 @@ class TestDHCP(VppTestCase): server_table_id=0, is_ipv6=1) - self.send_and_assert_no_replies(self.pg2, pkts_solicit_vrf0, + self.send_and_assert_no_replies(self.pg2, p_solicit_vrf0, "DHCP with no configuration") - self.send_and_assert_no_replies(self.pg3, pkts_solicit_vrf1, + self.send_and_assert_no_replies(self.pg3, p_solicit_vrf1, "DHCP with no configuration") # @@ -538,13 +674,13 @@ class TestDHCP(VppTestCase): # # Now the DHCP requests are relayed to the server # - self.pg2.add_stream(pkts_solicit_vrf0) + self.pg2.add_stream(p_solicit_vrf0) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture(1) - rx = rx[0] - self.verify_dhcp6_solicit(rx, self.pg0, + + self.verify_dhcp6_solicit(rx[0], self.pg0, dhcp_solicit_src_vrf0, self.pg2.remote_mac) @@ -557,8 +693,7 @@ class TestDHCP(VppTestCase): IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / DHCP6_Advertise()) - pkts_adv_vrf0 = [p_adv_vrf0] - self.send_and_assert_no_replies(self.pg2, pkts_adv_vrf0, + self.send_and_assert_no_replies(self.pg2, p_adv_vrf0, "DHCP6 not a relay reply") # 2 - no relay message option @@ -567,8 +702,7 @@ class TestDHCP(VppTestCase): UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / DHCP6_RelayReply() / DHCP6_Advertise()) - pkts_adv_vrf0 = [p_adv_vrf0] - self.send_and_assert_no_replies(self.pg2, pkts_adv_vrf0, + self.send_and_assert_no_replies(self.pg2, p_adv_vrf0, "DHCP not a relay message") # 3 - no circuit ID @@ -578,8 +712,7 @@ class TestDHCP(VppTestCase): DHCP6_RelayReply() / DHCP6OptRelayMsg(optlen=0) / DHCP6_Advertise()) - pkts_adv_vrf0 = [p_adv_vrf0] - self.send_and_assert_no_replies(self.pg2, pkts_adv_vrf0, + self.send_and_assert_no_replies(self.pg2, p_adv_vrf0, "DHCP6 no circuit ID") # 4 - wrong circuit ID p_adv_vrf0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / @@ -589,8 +722,7 @@ class TestDHCP(VppTestCase): DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x05') / DHCP6OptRelayMsg(optlen=0) / DHCP6_Advertise()) - pkts_adv_vrf0 = [p_adv_vrf0] - self.send_and_assert_no_replies(self.pg2, pkts_adv_vrf0, + self.send_and_assert_no_replies(self.pg2, p_adv_vrf0, "DHCP6 wrong circuit ID") # @@ -611,8 +743,8 @@ class TestDHCP(VppTestCase): self.pg_start() rx = self.pg2.get_capture(1) - rx = rx[0] - self.verify_dhcp6_advert(rx, self.pg2, "::") + + self.verify_dhcp6_advert(rx[0], self.pg2, "::") # # Send the relay response (the advertisement) @@ -632,8 +764,8 @@ class TestDHCP(VppTestCase): self.pg_start() rx = self.pg2.get_capture(1) - rx = rx[0] - self.verify_dhcp6_advert(rx, self.pg2, dhcp_solicit_src_vrf0) + + self.verify_dhcp6_advert(rx[0], self.pg2, dhcp_solicit_src_vrf0) # # Add all the config for VRF 1 @@ -648,13 +780,13 @@ class TestDHCP(VppTestCase): # # VRF 1 solicit # - self.pg3.add_stream(pkts_solicit_vrf1) + self.pg3.add_stream(p_solicit_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) - rx = rx[0] - self.verify_dhcp6_solicit(rx, self.pg1, + + self.verify_dhcp6_solicit(rx[0], self.pg1, dhcp_solicit_src_vrf1, self.pg3.remote_mac) @@ -676,21 +808,21 @@ class TestDHCP(VppTestCase): self.pg_start() rx = self.pg3.get_capture(1) - rx = rx[0] - self.verify_dhcp6_advert(rx, self.pg3, dhcp_solicit_src_vrf1) + + self.verify_dhcp6_advert(rx[0], self.pg3, dhcp_solicit_src_vrf1) # # Add VSS config # table=1, fib=id=1, oui=4 self.vapi.dhcp_proxy_set_vss(1, 1, 4, is_ip6=1) - self.pg3.add_stream(pkts_solicit_vrf1) + self.pg3.add_stream(p_solicit_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) - rx = rx[0] - self.verify_dhcp6_solicit(rx, self.pg1, + + self.verify_dhcp6_solicit(rx[0], self.pg1, dhcp_solicit_src_vrf1, self.pg3.remote_mac, fib_id=1, @@ -702,27 +834,163 @@ class TestDHCP(VppTestCase): # self.vapi.dhcp_proxy_set_vss(1, 1, 4, is_ip6=1, is_add=0) - self.pg3.add_stream(pkts_solicit_vrf1) + self.pg3.add_stream(p_solicit_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) - rx = rx[0] - self.verify_dhcp6_solicit(rx, self.pg1, + + self.verify_dhcp6_solicit(rx[0], self.pg1, dhcp_solicit_src_vrf1, self.pg3.remote_mac) # - # Cleanup + # Add a second DHCP server in VRF 1 + # expect clients messages to be relay to both configured servers # - self.vapi.dhcp_proxy_config(server_addr_vrf1, + self.pg1.generate_remote_hosts(2) + server_addr2 = socket.inet_pton(AF_INET6, self.pg1.remote_hosts[1].ip6) + + self.vapi.dhcp_proxy_config(server_addr2, + src_addr_vrf1, + rx_table_id=1, + server_table_id=1, + is_ipv6=1) + + # + # We'll need an ND entry for the server to send it packets + # + nd_entry = VppNeighbor(self, + self.pg1.sw_if_index, + self.pg1.remote_hosts[1].mac, + self.pg1.remote_hosts[1].ip6, + af=AF_INET6) + nd_entry.add_vpp_config() + + # + # Send a discover from the client. expect two relayed messages + # The frist packet is sent to the second server + # We're not enforcing that here, it's just the way it is. + # + self.pg3.add_stream(p_solicit_vrf1) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg1.get_capture(2) + + self.verify_dhcp6_solicit(rx[0], self.pg1, + dhcp_solicit_src_vrf1, + self.pg3.remote_mac) + self.verify_dhcp6_solicit(rx[1], self.pg1, + dhcp_solicit_src_vrf1, + self.pg3.remote_mac, + dst_mac=self.pg1.remote_hosts[1].mac, + dst_ip=self.pg1.remote_hosts[1].ip6) + + # + # Send both packets back. Client gets both. + # + p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / + IPv6(dst=self.pg1.local_ip6, src=self.pg1.remote_ip6) / + UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / + DHCP6_RelayReply(peeraddr=dhcp_solicit_src_vrf1) / + DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x04') / + DHCP6OptRelayMsg(optlen=0) / + DHCP6_Advertise(trid=1) / + DHCP6OptStatusCode(statuscode=0)) + p2 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_hosts[1].mac) / + IPv6(dst=self.pg1.local_ip6, src=self.pg1._remote_hosts[1].ip6) / + UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / + DHCP6_RelayReply(peeraddr=dhcp_solicit_src_vrf1) / + DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x04') / + DHCP6OptRelayMsg(optlen=0) / + DHCP6_Advertise(trid=1) / + DHCP6OptStatusCode(statuscode=0)) + + pkts = [p1, p2] + + self.pg1.add_stream(pkts) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg3.get_capture(2) + + self.verify_dhcp6_advert(rx[0], self.pg3, dhcp_solicit_src_vrf1) + self.verify_dhcp6_advert(rx[1], self.pg3, dhcp_solicit_src_vrf1) + + # + # Ensure only solicit messages are duplicated + # + p_request_vrf1 = (Ether(dst=dmac, src=self.pg3.remote_mac) / + IPv6(src=dhcp_solicit_src_vrf1, + dst=dhcp_solicit_dst) / + UDP(sport=DHCP6_SERVER_PORT, + dport=DHCP6_CLIENT_PORT) / + DHCP6_Request()) + + self.pg3.add_stream(p_request_vrf1) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg1.get_capture(1) + + # + # Test we drop DHCP packets from addresses that are not configured as + # DHCP servers + # + p2 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_hosts[1].mac) / + IPv6(dst=self.pg1.local_ip6, src="3001::1") / + UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / + DHCP6_RelayReply(peeraddr=dhcp_solicit_src_vrf1) / + DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x04') / + DHCP6OptRelayMsg(optlen=0) / + DHCP6_Advertise(trid=1) / + DHCP6OptStatusCode(statuscode=0)) + self.send_and_assert_no_replies(self.pg1, p2, + "DHCP6 not from server") + + # + # Remove the second DHCP server + # + self.vapi.dhcp_proxy_config(server_addr2, src_addr_vrf1, rx_table_id=1, server_table_id=1, is_ipv6=1, is_add=0) + + # + # Test we can still relay with the first + # + self.pg3.add_stream(p_solicit_vrf1) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg1.get_capture(1) + + self.verify_dhcp6_solicit(rx[0], self.pg1, + dhcp_solicit_src_vrf1, + self.pg3.remote_mac) + + # + # Cleanup + # self.vapi.dhcp_proxy_config(server_addr_vrf1, src_addr_vrf1, + rx_table_id=1, + server_table_id=1, + is_ipv6=1, + is_add=0) + self.vapi.dhcp_proxy_config(server_addr_vrf0, + src_addr_vrf0, + rx_table_id=0, + server_table_id=0, + is_ipv6=1, + is_add=0) + + # duplicate delete + self.vapi.dhcp_proxy_config(server_addr_vrf0, + src_addr_vrf0, rx_table_id=0, server_table_id=0, is_ipv6=1, -- cgit 1.2.3-korg From a0558307187ef2317f31e3e876a1a5e1faa2541c Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Thu, 13 Apr 2017 00:44:52 -0700 Subject: Remove unsed parameter from fib_table_entry_special_add() (only used in FIB tests). The DPO was incorrectly initialised with FIB_PROTO_MAX Change-Id: I962df9e162e4dfb6837a5ce79ea795d5ff2d7315 Signed-off-by: Neale Ranns --- src/plugins/ila/ila.c | 3 +-- src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_ioam.c | 4 +--- src/plugins/lb/lb.c | 3 +-- src/vnet/dhcp/client.c | 3 +-- src/vnet/dhcp/dhcp4_proxy_node.c | 3 +-- src/vnet/fib/fib_bfd.c | 3 +-- src/vnet/fib/fib_path.c | 3 +-- src/vnet/fib/fib_table.c | 15 ++------------- src/vnet/fib/fib_table.h | 14 ++++++-------- src/vnet/fib/fib_test.c | 16 ++++++++-------- src/vnet/fib/ip4_fib.c | 3 +-- src/vnet/fib/ip6_fib.c | 6 ++---- src/vnet/gre/interface.c | 3 +-- src/vnet/ip/ip4_forward.c | 6 ++---- src/vnet/ip/ip4_source_check.c | 2 +- src/vnet/lisp-gpe/lisp_gpe_tunnel.c | 3 +-- src/vnet/map/map.c | 4 +--- src/vnet/vxlan/vxlan.c | 2 +- 18 files changed, 33 insertions(+), 63 deletions(-) (limited to 'src/vnet/dhcp/client.c') diff --git a/src/plugins/ila/ila.c b/src/plugins/ila/ila.c index edbf3017..fd56043e 100644 --- a/src/plugins/ila/ila.c +++ b/src/plugins/ila/ila.c @@ -736,8 +736,7 @@ ila_add_del_entry (ila_add_del_entry_args_t * args) fib_table_entry_special_add(0, &next_hop, FIB_SOURCE_RR, - FIB_ENTRY_FLAG_NONE, - ADJ_INDEX_INVALID); + FIB_ENTRY_FLAG_NONE); e->next_hop_child_index = fib_entry_child_add(e->next_hop_fib_entry_index, ila_fib_node_type, diff --git a/src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_ioam.c b/src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_ioam.c index 88d7d205..cfc550cd 100644 --- a/src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_ioam.c +++ b/src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_ioam.c @@ -336,9 +336,7 @@ vxlan_gpe_enable_disable_ioam_for_dest (vlib_main_t * vm, t1->fib_entry_index = fib_table_entry_special_add (outer_fib_index, &tun_dst_pfx, - FIB_SOURCE_RR, - FIB_ENTRY_FLAG_NONE, - ADJ_INDEX_INVALID); + FIB_SOURCE_RR, FIB_ENTRY_FLAG_NONE); t1->sibling_index = fib_entry_child_add (t1->fib_entry_index, hm->fib_entry_type, t1 - hm->dst_tunnels); diff --git a/src/plugins/lb/lb.c b/src/plugins/lb/lb.c index addc2a42..cc3f8532 100644 --- a/src/plugins/lb/lb.c +++ b/src/plugins/lb/lb.c @@ -510,8 +510,7 @@ next: fib_table_entry_special_add(0, &nh, FIB_SOURCE_RR, - FIB_ENTRY_FLAG_NONE, - ADJ_INDEX_INVALID); + FIB_ENTRY_FLAG_NONE); as->next_hop_child_index = fib_entry_child_add(as->next_hop_fib_entry_index, lbm->fib_node_type, diff --git a/src/vnet/dhcp/client.c b/src/vnet/dhcp/client.c index 29749a33..7c3f7f6a 100644 --- a/src/vnet/dhcp/client.c +++ b/src/vnet/dhcp/client.c @@ -781,8 +781,7 @@ int dhcp_client_add_del (dhcp_client_add_del_args_t * a) c->sw_if_index), &all_1s, FIB_SOURCE_DHCP, - FIB_ENTRY_FLAG_LOCAL, - ADJ_INDEX_INVALID); + FIB_ENTRY_FLAG_LOCAL); /* * enable the interface to RX IPv4 packets diff --git a/src/vnet/dhcp/dhcp4_proxy_node.c b/src/vnet/dhcp/dhcp4_proxy_node.c index 1c84881a..26e1e65c 100644 --- a/src/vnet/dhcp/dhcp4_proxy_node.c +++ b/src/vnet/dhcp/dhcp4_proxy_node.c @@ -807,8 +807,7 @@ dhcp4_proxy_set_server (ip46_address_t *addr, fib_table_entry_special_add(rx_fib_index, &all_1s, FIB_SOURCE_DHCP, - FIB_ENTRY_FLAG_LOCAL, - ADJ_INDEX_INVALID); + FIB_ENTRY_FLAG_LOCAL); fib_table_lock (rx_fib_index, FIB_PROTOCOL_IP4); } } diff --git a/src/vnet/fib/fib_bfd.c b/src/vnet/fib/fib_bfd.c index e5affb8d..734ee8cc 100644 --- a/src/vnet/fib/fib_bfd.c +++ b/src/vnet/fib/fib_bfd.c @@ -109,8 +109,7 @@ fib_bfd_notify (bfd_listen_event_e event, fei = fib_table_entry_special_add(key->fib_index, &pfx, FIB_SOURCE_RR, - FIB_ENTRY_FLAG_NONE, - ADJ_INDEX_INVALID); + FIB_ENTRY_FLAG_NONE); fib_entry_lock(fei); fed = fib_entry_delegate_find_or_add(fib_entry_get(fei), diff --git a/src/vnet/fib/fib_path.c b/src/vnet/fib/fib_path.c index cd7d9278..70c87905 100644 --- a/src/vnet/fib/fib_path.c +++ b/src/vnet/fib/fib_path.c @@ -1621,8 +1621,7 @@ fib_path_resolve (fib_node_index_t path_index) fei = fib_table_entry_special_add(path->recursive.fp_tbl_id, &pfx, FIB_SOURCE_RR, - FIB_ENTRY_FLAG_NONE, - ADJ_INDEX_INVALID); + FIB_ENTRY_FLAG_NONE); path = fib_path_get(path_index); path->fp_via_fib = fei; diff --git a/src/vnet/fib/fib_table.c b/src/vnet/fib/fib_table.c index b31f35e3..0938ce9b 100644 --- a/src/vnet/fib/fib_table.c +++ b/src/vnet/fib/fib_table.c @@ -371,23 +371,12 @@ fib_node_index_t fib_table_entry_special_add (u32 fib_index, const fib_prefix_t *prefix, fib_source_t source, - fib_entry_flag_t flags, - adj_index_t adj_index) + fib_entry_flag_t flags) { fib_node_index_t fib_entry_index; dpo_id_t tmp_dpo = DPO_INVALID; - if (ADJ_INDEX_INVALID != adj_index) - { - dpo_set(&tmp_dpo, - DPO_ADJACENCY, - FIB_PROTOCOL_MAX, - adj_index); - } - else - { - dpo_copy(&tmp_dpo, drop_dpo_get(fib_proto_to_dpo(prefix->fp_proto))); - } + dpo_copy(&tmp_dpo, drop_dpo_get(fib_proto_to_dpo(prefix->fp_proto))); fib_entry_index = fib_table_entry_special_dpo_add(fib_index, prefix, source, flags, &tmp_dpo); diff --git a/src/vnet/fib/fib_table.h b/src/vnet/fib/fib_table.h index b310aea6..f24d28b7 100644 --- a/src/vnet/fib/fib_table.h +++ b/src/vnet/fib/fib_table.h @@ -126,14 +126,16 @@ extern fib_node_index_t fib_table_get_less_specific(u32 fib_index, /** * @brief - * Add a 'special' entry to the FIB that links to the adj passed + * Add a 'special' entry to the FIB. * A special entry is an entry that the FIB is not expect to resolve * via the usual mechanisms (i.e. recurisve or neighbour adj DB lookup). - * Instead the client/source provides the adj to link to. + * Instead the will link to a DPO valid for the source and/or the flags. * This add is reference counting per-source. So n 'removes' are required * for n 'adds', if the entry is no longer required. + * If the source needs to provide non-default forwarding use: + * fib_table_entry_special_dpo_add() * - * @param fib_index + * @param fib_index * The index of the FIB * * @param prefix @@ -145,17 +147,13 @@ extern fib_node_index_t fib_table_get_less_specific(u32 fib_index, * @param flags * Flags for the entry. * - * @param adj_index - * The adjacency to link to. - * * @return * the index of the fib_entry_t that is created (or exists already). */ extern fib_node_index_t fib_table_entry_special_add(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source, - fib_entry_flag_t flags, - adj_index_t adj_index); + fib_entry_flag_t flags); /** * @brief diff --git a/src/vnet/fib/fib_test.c b/src/vnet/fib/fib_test.c index e4a8a70e..c58dc5a1 100644 --- a/src/vnet/fib/fib_test.c +++ b/src/vnet/fib/fib_test.c @@ -1378,8 +1378,8 @@ fib_test_v4 (void) fib_entry_pool_size()); /* - * An EXCLUSIVE route; one where the user (me) provides the exclusive - * adjacency through which the route will resovle + * An special route; one where the user (me) provides the + * adjacency through which the route will resovle by setting the flags */ fib_prefix_t ex_pfx = { .fp_len = 32, @@ -1393,11 +1393,12 @@ fib_test_v4 (void) fib_table_entry_special_add(fib_index, &ex_pfx, FIB_SOURCE_SPECIAL, - FIB_ENTRY_FLAG_EXCLUSIVE, - locked_ai); + FIB_ENTRY_FLAG_LOCAL); fei = fib_table_lookup_exact_match(fib_index, &ex_pfx); - FIB_TEST((ai == fib_entry_get_adj(fei)), - "Exclusive route links to user adj"); + dpo = fib_entry_contribute_ip_forwarding(fei); + dpo = load_balance_get_bucket(dpo->dpoi_index, 0); + FIB_TEST((DPO_RECEIVE == dpo->dpoi_type), + "local interface adj is local"); fib_table_entry_special_remove(fib_index, &ex_pfx, @@ -3675,8 +3676,7 @@ fib_test_v4 (void) fei = fib_table_entry_special_add(fib_index, &pfx_4_1_1_1_s_32, FIB_SOURCE_URPF_EXEMPT, - FIB_ENTRY_FLAG_DROP, - ADJ_INDEX_INVALID); + FIB_ENTRY_FLAG_DROP); dpo = fib_entry_contribute_ip_forwarding(fei); FIB_TEST(load_balance_is_drop(dpo), "uRPF exempt 4.1.1.1/32 DROP"); diff --git a/src/vnet/fib/ip4_fib.c b/src/vnet/fib/ip4_fib.c index b03186e8..8e92d851 100644 --- a/src/vnet/fib/ip4_fib.c +++ b/src/vnet/fib/ip4_fib.c @@ -149,8 +149,7 @@ ip4_create_fib_with_table_id (u32 table_id) fib_table_entry_special_add(fib_table->ft_index, &prefix, ip4_specials[ii].ift_source, - ip4_specials[ii].ift_flag, - ADJ_INDEX_INVALID); + ip4_specials[ii].ift_flag); } return (fib_table->ft_index); diff --git a/src/vnet/fib/ip6_fib.c b/src/vnet/fib/ip6_fib.c index 00297140..d00f4c55 100644 --- a/src/vnet/fib/ip6_fib.c +++ b/src/vnet/fib/ip6_fib.c @@ -35,8 +35,7 @@ vnet_ip6_fib_init (u32 fib_index) fib_table_entry_special_add(fib_index, &pfx, FIB_SOURCE_DEFAULT_ROUTE, - FIB_ENTRY_FLAG_DROP, - ADJ_INDEX_INVALID); + FIB_ENTRY_FLAG_DROP); /* * all link local for us @@ -47,8 +46,7 @@ vnet_ip6_fib_init (u32 fib_index) fib_table_entry_special_add(fib_index, &pfx, FIB_SOURCE_SPECIAL, - FIB_ENTRY_FLAG_LOCAL, - ADJ_INDEX_INVALID); + FIB_ENTRY_FLAG_LOCAL); } static u32 diff --git a/src/vnet/gre/interface.c b/src/vnet/gre/interface.c index 91a3899f..d574e596 100644 --- a/src/vnet/gre/interface.c +++ b/src/vnet/gre/interface.c @@ -427,8 +427,7 @@ vnet_gre_tunnel_add (vnet_gre_add_del_tunnel_args_t *a, fib_table_entry_special_add(outer_fib_index, &t->tunnel_dst, FIB_SOURCE_RR, - FIB_ENTRY_FLAG_NONE, - ADJ_INDEX_INVALID); + FIB_ENTRY_FLAG_NONE); t->sibling_index = fib_entry_child_add(t->fib_entry_index, FIB_NODE_TYPE_GRE_TUNNEL, diff --git a/src/vnet/ip/ip4_forward.c b/src/vnet/ip/ip4_forward.c index e42b3637..0f562037 100644 --- a/src/vnet/ip/ip4_forward.c +++ b/src/vnet/ip/ip4_forward.c @@ -732,16 +732,14 @@ ip4_add_interface_routes (u32 sw_if_index, &net_pfx, FIB_SOURCE_INTERFACE, (FIB_ENTRY_FLAG_DROP | - FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT), - ADJ_INDEX_INVALID); + FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT)); net_pfx.fp_addr.ip4.as_u32 |= ~im->fib_masks[pfx.fp_len]; if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32) fib_table_entry_special_add(fib_index, &net_pfx, FIB_SOURCE_INTERFACE, (FIB_ENTRY_FLAG_DROP | - FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT), - ADJ_INDEX_INVALID); + FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT)); } else if (pfx.fp_len == 31) { diff --git a/src/vnet/ip/ip4_source_check.c b/src/vnet/ip/ip4_source_check.c index 63b7594d..17a1cb1b 100644 --- a/src/vnet/ip/ip4_source_check.c +++ b/src/vnet/ip/ip4_source_check.c @@ -509,7 +509,7 @@ ip_source_check_accept (vlib_main_t * vm, fib_table_entry_special_add (fib_index, &pfx, FIB_SOURCE_URPF_EXEMPT, - FIB_ENTRY_FLAG_DROP, ADJ_INDEX_INVALID); + FIB_ENTRY_FLAG_DROP); } else { diff --git a/src/vnet/lisp-gpe/lisp_gpe_tunnel.c b/src/vnet/lisp-gpe/lisp_gpe_tunnel.c index 444bfe14..dd6c6fdd 100644 --- a/src/vnet/lisp-gpe/lisp_gpe_tunnel.c +++ b/src/vnet/lisp-gpe/lisp_gpe_tunnel.c @@ -179,8 +179,7 @@ lisp_gpe_tunnel_find_or_create_and_lock (const locator_pair_t * pair, lgt->fib_entry_index = fib_table_entry_special_add (rloc_fib_index, &pfx, FIB_SOURCE_RR, - FIB_ENTRY_FLAG_NONE, - ADJ_INDEX_INVALID); + FIB_ENTRY_FLAG_NONE); hash_set_mem (lisp_gpe_tunnel_db, &lgt->key, (lgt - lisp_gpe_tunnel_pool)); diff --git a/src/vnet/map/map.c b/src/vnet/map/map.c index 811a0abc..6a707df1 100644 --- a/src/vnet/map/map.c +++ b/src/vnet/map/map.c @@ -518,9 +518,7 @@ map_fib_resolve (map_main_pre_resolved_t * pr, pr->fei = fib_table_entry_special_add (0, // default fib &pfx, - FIB_SOURCE_RR, - FIB_ENTRY_FLAG_NONE, - ADJ_INDEX_INVALID); + FIB_SOURCE_RR, FIB_ENTRY_FLAG_NONE); pr->sibling = fib_entry_child_add (pr->fei, FIB_NODE_TYPE_MAP_E, proto); map_stack (pr); } diff --git a/src/vnet/vxlan/vxlan.c b/src/vnet/vxlan/vxlan.c index 61cb13c9..1b3df2a8 100644 --- a/src/vnet/vxlan/vxlan.c +++ b/src/vnet/vxlan/vxlan.c @@ -486,7 +486,7 @@ int vnet_vxlan_add_del_tunnel vtep_addr_ref(&t->src); t->fib_entry_index = fib_table_entry_special_add (t->encap_fib_index, &tun_dst_pfx, FIB_SOURCE_RR, - FIB_ENTRY_FLAG_NONE, ADJ_INDEX_INVALID); + FIB_ENTRY_FLAG_NONE); t->sibling_index = fib_entry_child_add (t->fib_entry_index, FIB_NODE_TYPE_VXLAN_TUNNEL, t - vxm->tunnels); vxlan_tunnel_restack_dpo(t); -- cgit 1.2.3-korg From 4729b1ec83855268adcea3e00a3462c06a631075 Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Thu, 6 Jul 2017 01:39:05 -0700 Subject: DHCP complete event sends mask length Change-Id: I4a529dfab5d0ce6b0bbc0ccbbd89c6b109dbf917 Signed-off-by: Neale Ranns --- src/vnet/dhcp/client.c | 3 ++- src/vnet/dhcp/dhcp.api | 2 ++ src/vnet/dhcp/dhcp_api.c | 5 +++-- 3 files changed, 7 insertions(+), 3 deletions(-) (limited to 'src/vnet/dhcp/client.c') diff --git a/src/vnet/dhcp/client.c b/src/vnet/dhcp/client.c index 7c3f7f6a..014f17a1 100644 --- a/src/vnet/dhcp/client.c +++ b/src/vnet/dhcp/client.c @@ -194,7 +194,7 @@ int dhcp_client_for_us (u32 bi, vlib_buffer_t * b, /* OK, we own the address (etc), add to the routing table(s) */ if (c->state == DHCP_REQUEST) { - void (*fp)(u32, u32, u8 *, u8, u8 *, u8 *, u8 *) = c->event_callback; + void (*fp)(u32, u32, u8 *, u8, u8, u8 *, u8 *, u8 *) = c->event_callback; dhcp_client_acquire_address (dcm, c); @@ -236,6 +236,7 @@ int dhcp_client_for_us (u32 bi, vlib_buffer_t * b, (*fp) (c->client_index, /* clinet index */ c->pid, c->hostname, + c->subnet_mask_width, 0, /* is_ipv6 */ (u8 *)&c->leased_address, /* host IP address */ (u8 *)&c->router_address, /* router IP address */ diff --git a/src/vnet/dhcp/dhcp.api b/src/vnet/dhcp/dhcp.api index eb0b070d..a2803728 100644 --- a/src/vnet/dhcp/dhcp.api +++ b/src/vnet/dhcp/dhcp.api @@ -81,6 +81,7 @@ autoreply define dhcp_client_config @param client_index - opaque cookie to identify the sender @param pid - client pid registered to receive notification @param is_ipv6 - if non-zero the address is ipv6, else ipv4 + @param mask_width - The length of the subnet mask assigned @param host_address - Host IP address @param router_address - Router IP address @param host_mac - Host MAC address @@ -91,6 +92,7 @@ define dhcp_compl_event u32 pid; u8 hostname[64]; u8 is_ipv6; + u8 mask_width; u8 host_address[16]; u8 router_address[16]; u8 host_mac[6]; diff --git a/src/vnet/dhcp/dhcp_api.c b/src/vnet/dhcp/dhcp_api.c index 2c0dd77d..5ea93660 100644 --- a/src/vnet/dhcp/dhcp_api.c +++ b/src/vnet/dhcp/dhcp_api.c @@ -187,8 +187,8 @@ dhcp_send_details (fib_protocol_t proto, void dhcp_compl_event_callback (u32 client_index, u32 pid, u8 * hostname, - u8 is_ipv6, u8 * host_address, u8 * router_address, - u8 * host_mac) + u8 mask_width, u8 is_ipv6, u8 * host_address, + u8 * router_address, u8 * host_mac) { unix_shared_memory_queue_t *q; vl_api_dhcp_compl_event_t *mp; @@ -205,6 +205,7 @@ dhcp_compl_event_callback (u32 client_index, u32 pid, u8 * hostname, len = (vec_len (hostname) < 63) ? vec_len (hostname) : 63; clib_memcpy (&mp->hostname, hostname, len); mp->hostname[len] = 0; + mp->mask_width = mask_width; clib_memcpy (&mp->host_address[0], host_address, 16); clib_memcpy (&mp->router_address[0], router_address, 16); -- cgit 1.2.3-korg From a2fbf6ba0e2553687f56d9a9fb63e2972bdb26c6 Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Tue, 18 Jul 2017 08:23:32 -0700 Subject: DHCP client - remove interface address when DHCP de-configured Change-Id: I63c59e3c13859b51999d283774f7783ef0a6a5ed Signed-off-by: Neale Ranns --- src/vnet/dhcp/client.c | 1 + test/test_dhcp.py | 158 ++++++++++++++++++++++++++++++++++++++++------ test/vpp_papi_provider.py | 15 +++++ 3 files changed, 153 insertions(+), 21 deletions(-) (limited to 'src/vnet/dhcp/client.c') diff --git a/src/vnet/dhcp/client.c b/src/vnet/dhcp/client.c index 014f17a1..8f033d25 100644 --- a/src/vnet/dhcp/client.c +++ b/src/vnet/dhcp/client.c @@ -821,6 +821,7 @@ int dhcp_client_add_del (dhcp_client_add_del_args_t * a) 1, FIB_ROUTE_PATH_FLAG_NONE); } + dhcp_client_release_address (dcm, c); ip4_sw_interface_enable_disable (c->sw_if_index, 0); vec_free (c->option_55_data); diff --git a/test/test_dhcp.py b/test/test_dhcp.py index 03c749d3..1700f6ba 100644 --- a/test/test_dhcp.py +++ b/test/test_dhcp.py @@ -6,6 +6,7 @@ import struct from framework import VppTestCase, VppTestRunner from vpp_neighbor import VppNeighbor +from vpp_ip_route import find_route from util import mk_ll_addr from scapy.layers.l2 import Ether, getmacbyip @@ -68,6 +69,18 @@ class TestDHCP(VppTestCase): for i in self.pg_interfaces: i.assert_nothing_captured(remark=remark) + def verify_dhcp_has_option(self, pkt, option, value): + dhcp = pkt[DHCP] + found = False + + for i in dhcp.options: + if type(i) is tuple: + if i[0] == option: + self.assertEqual(i[1], value) + found = True + + self.assertTrue(found) + def validate_relay_options(self, pkt, intf, ip_addr, fib_id, oui): dhcp = pkt[DHCP] found = 0 @@ -136,6 +149,16 @@ class TestDHCP(VppTestCase): return data + def verify_dhcp_msg_type(self, pkt, name): + dhcp = pkt[DHCP] + found = False + for o in dhcp.options: + if type(o) is tuple: + if o[0] == "message-type" \ + and DHCPTypes[o[1]] == name: + found = True + self.assertTrue(found) + def verify_dhcp_offer(self, pkt, intf, fib_id=0, oui=0): ether = pkt[Ether] self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff") @@ -149,20 +172,39 @@ class TestDHCP(VppTestCase): self.assertEqual(udp.dport, DHCP4_CLIENT_PORT) self.assertEqual(udp.sport, DHCP4_SERVER_PORT) - dhcp = pkt[DHCP] - is_offer = False - for o in dhcp.options: - if type(o) is tuple: - if o[0] == "message-type" \ - and DHCPTypes[o[1]] == "offer": - is_offer = True - self.assertTrue(is_offer) - + self.verify_dhcp_msg_type(pkt, "offer") data = self.validate_relay_options(pkt, intf, intf.local_ip4, fib_id, oui) - def verify_dhcp_discover(self, pkt, intf, src_intf=None, fib_id=0, oui=0, - dst_mac=None, dst_ip=None): + def verify_orig_dhcp_pkt(self, pkt, intf): + ether = pkt[Ether] + self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff") + self.assertEqual(ether.src, intf.local_mac) + + ip = pkt[IP] + self.assertEqual(ip.dst, "255.255.255.255") + self.assertEqual(ip.src, "0.0.0.0") + + udp = pkt[UDP] + self.assertEqual(udp.dport, DHCP4_SERVER_PORT) + self.assertEqual(udp.sport, DHCP4_CLIENT_PORT) + + def verify_orig_dhcp_discover(self, pkt, intf, hostname): + self.verify_orig_dhcp_pkt(pkt, intf) + + self.verify_dhcp_msg_type(pkt, "discover") + self.verify_dhcp_has_option(pkt, "hostname", hostname) + + def verify_orig_dhcp_request(self, pkt, intf, hostname, ip): + self.verify_orig_dhcp_pkt(pkt, intf) + + self.verify_dhcp_msg_type(pkt, "request") + self.verify_dhcp_has_option(pkt, "hostname", hostname) + self.verify_dhcp_has_option(pkt, "requested_addr", ip) + + def verify_relayed_dhcp_discover(self, pkt, intf, src_intf=None, + fib_id=0, oui=0, + dst_mac=None, dst_ip=None): if not dst_mac: dst_mac = intf.remote_mac if not dst_ip: @@ -341,7 +383,8 @@ class TestDHCP(VppTestCase): rx = self.pg0.get_capture(1) rx = rx[0] - option_82 = self.verify_dhcp_discover(rx, self.pg0, src_intf=self.pg2) + option_82 = self.verify_relayed_dhcp_discover(rx, self.pg0, + src_intf=self.pg2) # # Create an DHCP offer reply from the server with a correctly formatted @@ -446,7 +489,7 @@ class TestDHCP(VppTestCase): rx = self.pg1.get_capture(1) rx = rx[0] - self.verify_dhcp_discover(rx, self.pg1, src_intf=self.pg3) + self.verify_relayed_dhcp_discover(rx, self.pg1, src_intf=self.pg3) # # Add VSS config @@ -459,8 +502,9 @@ class TestDHCP(VppTestCase): rx = self.pg1.get_capture(1) rx = rx[0] - self.verify_dhcp_discover(rx, self.pg1, src_intf=self.pg3, - fib_id=1, oui=4) + self.verify_relayed_dhcp_discover(rx, self.pg1, + src_intf=self.pg3, + fib_id=1, oui=4) # # Add a second DHCP server in VRF 1 @@ -495,14 +539,15 @@ class TestDHCP(VppTestCase): rx = self.pg1.get_capture(2) - option_82 = self.verify_dhcp_discover( + option_82 = self.verify_relayed_dhcp_discover( rx[0], self.pg1, src_intf=self.pg3, dst_mac=self.pg1.remote_hosts[1].mac, dst_ip=self.pg1.remote_hosts[1].ip4, fib_id=1, oui=4) - self.verify_dhcp_discover(rx[1], self.pg1, src_intf=self.pg3, - fib_id=1, oui=4) + self.verify_relayed_dhcp_discover(rx[1], self.pg1, + src_intf=self.pg3, + fib_id=1, oui=4) # # Send both packets back. Client gets both. @@ -581,8 +626,9 @@ class TestDHCP(VppTestCase): rx = self.pg1.get_capture(1) rx = rx[0] - self.verify_dhcp_discover(rx, self.pg1, src_intf=self.pg3, - fib_id=1, oui=4) + self.verify_relayed_dhcp_discover(rx, self.pg1, + src_intf=self.pg3, + fib_id=1, oui=4) # # Remove the VSS config @@ -596,7 +642,7 @@ class TestDHCP(VppTestCase): rx = self.pg1.get_capture(1) rx = rx[0] - self.verify_dhcp_discover(rx, self.pg1, src_intf=self.pg3) + self.verify_relayed_dhcp_discover(rx, self.pg1, src_intf=self.pg3) # # remove DHCP config to cleanup @@ -990,5 +1036,75 @@ class TestDHCP(VppTestCase): is_ipv6=1, is_add=0) + def test_dhcp_client(self): + """ DHCP Client""" + + hostname = 'universal-dp' + + self.pg_enable_capture(self.pg_interfaces) + + # + # Configure DHCP client on PG2 and capture the discover sent + # + self.vapi.dhcp_client(self.pg2.sw_if_index, hostname) + + rx = self.pg2.get_capture(1) + + self.verify_orig_dhcp_discover(rx[0], self.pg2, hostname) + + # + # Sned back on offer, expect the request + # + p = (Ether(dst=self.pg2.local_mac, src=self.pg2.remote_mac) / + IP(src=self.pg2.remote_ip4, dst="255.255.255.255") / + UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_CLIENT_PORT) / + BOOTP(op=1, + yiaddr=self.pg2.local_ip4) / + DHCP(options=[('message-type', 'offer'), ('end')])) + + self.pg2.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg2.get_capture(1) + self.verify_orig_dhcp_request(rx[0], self.pg2, hostname, + self.pg2.local_ip4) + + # + # Send an acknowloedgement + # + p = (Ether(dst=self.pg2.local_mac, src=self.pg2.remote_mac) / + IP(src=self.pg2.remote_ip4, dst="255.255.255.255") / + UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_CLIENT_PORT) / + BOOTP(op=1, + yiaddr=self.pg2.local_ip4) / + DHCP(options=[('message-type', 'ack'), + ('subnet_mask', "255.255.255.0"), + ('router', self.pg2.remote_ip4), + ('server_id', self.pg2.remote_ip4), + ('lease_time', 43200), + ('end')])) + + self.pg2.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + # + # At the end of this procedure there should be a connected route + # in the FIB + # + self.assertTrue(find_route(self, self.pg2.local_ip4, 32)) + + # + # remove the DHCP config + # + self.vapi.dhcp_client(self.pg2.sw_if_index, hostname, is_add=0) + + # + # and now the route should be gone + # + self.assertFalse(find_route(self, self.pg2.local_ip4, 32)) + + if __name__ == '__main__': unittest.main(testRunner=VppTestRunner) diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py index 51c359e8..31eadad8 100644 --- a/test/vpp_papi_provider.py +++ b/test/vpp_papi_provider.py @@ -1755,6 +1755,21 @@ class VppPapiProvider(object): 'oui': oui, }) + def dhcp_client(self, + sw_if_index, + hostname, + is_add=1, + want_dhcp_events=0): + return self.api( + self.papi.dhcp_client_config, + { + 'sw_if_index': sw_if_index, + 'hostname': hostname, + 'is_add': is_add, + 'want_dhcp_event': want_dhcp_events, + 'pid': os.getpid(), + }) + def ip_mroute_add_del(self, src_address, grp_address, -- cgit 1.2.3-korg From 51822bf07a3f0fe72834ea94659faf6e262475ba Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Tue, 18 Jul 2017 09:26:53 -0700 Subject: DHCP client option 61 "client_id" the existing seeting of client_id to a VPP version number was unused and so overridden Change-Id: If9ebea936336f1fcca8d07e67186c95f8f8f0ccd Signed-off-by: Neale Ranns --- src/vnet/dhcp/client.c | 15 ++++++++++++++- src/vnet/dhcp/client.h | 1 + src/vnet/dhcp/dhcp.api | 2 ++ src/vnet/dhcp/dhcp_api.c | 3 ++- test/test_dhcp.py | 34 ++++++++++++++++++++++++++++++++-- test/vpp_papi_provider.py | 2 ++ 6 files changed, 53 insertions(+), 4 deletions(-) (limited to 'src/vnet/dhcp/client.c') diff --git a/src/vnet/dhcp/client.c b/src/vnet/dhcp/client.c index 8f033d25..25ab3176 100644 --- a/src/vnet/dhcp/client.c +++ b/src/vnet/dhcp/client.c @@ -414,6 +414,16 @@ send_dhcp_pkt (dhcp_client_main_t * dcm, dhcp_client_t * c, o = (dhcp_option_t *) (((uword) o) + (o->length + 2)); } + /* send option 61, client_id */ + if (vec_len (c->client_identifier)) + { + o->option = 61; + o->length = vec_len (c->client_identifier); + clib_memcpy (o->data, c->client_identifier, + vec_len (c->client_identifier)); + o = (dhcp_option_t *) (((uword) o) + (o->length + 2)); + } + /* $$ maybe send the client s/w version if anyone cares */ /* @@ -838,6 +848,7 @@ int dhcp_client_config (vlib_main_t * vm, u32 sw_if_index, u8 * hostname, + u8 * client_id, u32 is_add, u32 client_index, void * event_callback, @@ -854,7 +865,9 @@ dhcp_client_config (vlib_main_t * vm, a->event_callback = event_callback; vec_validate(a->hostname, strlen((char *)hostname) - 1); strncpy((char *)a->hostname, (char *)hostname, vec_len(a->hostname)); - a->client_identifier = format (0, "vpe 1.0%c", 0); + vec_validate(a->client_identifier, strlen((char *)client_id) - 1); + strncpy((char *)a->client_identifier, (char *)client_id, vec_len(a->client_identifier)); + /* * Option 55 request list. These data precisely match * the Ubuntu dhcp client. YMMV. diff --git a/src/vnet/dhcp/client.h b/src/vnet/dhcp/client.h index 1f85d7ce..509d5d4c 100644 --- a/src/vnet/dhcp/client.h +++ b/src/vnet/dhcp/client.h @@ -113,6 +113,7 @@ int dhcp_client_for_us (u32 bi0, int dhcp_client_config (vlib_main_t * vm, u32 sw_if_index, u8 * hostname, + u8 * client_id, u32 is_add, u32 client_index, void *event_callback, diff --git a/src/vnet/dhcp/dhcp.api b/src/vnet/dhcp/dhcp.api index a2803728..c632c087 100644 --- a/src/vnet/dhcp/dhcp.api +++ b/src/vnet/dhcp/dhcp.api @@ -61,6 +61,7 @@ autoreply define dhcp_proxy_set_vss @param context - sender context, to match reply w/ request @param sw_if_index - index of the interface for DHCP client @param hostname - hostname + @param client_id - Client ID - option 61 @param is_add - add the config if non-zero, else delete @param want_dhcp_event - DHCP event sent to the sender via dhcp_compl_event API message if non-zero @@ -72,6 +73,7 @@ autoreply define dhcp_client_config u32 context; u32 sw_if_index; u8 hostname[64]; + u8 client_id[64]; u8 is_add; u8 want_dhcp_event; u32 pid; diff --git a/src/vnet/dhcp/dhcp_api.c b/src/vnet/dhcp/dhcp_api.c index 5ea93660..d6984f2d 100644 --- a/src/vnet/dhcp/dhcp_api.c +++ b/src/vnet/dhcp/dhcp_api.c @@ -227,7 +227,8 @@ static void vl_api_dhcp_client_config_t_handler VALIDATE_SW_IF_INDEX (mp); rv = dhcp_client_config (vm, ntohl (mp->sw_if_index), - mp->hostname, mp->is_add, mp->client_index, + mp->hostname, mp->client_id, + mp->is_add, mp->client_index, mp->want_dhcp_event ? dhcp_compl_event_callback : NULL, mp->pid); diff --git a/test/test_dhcp.py b/test/test_dhcp.py index 1700f6ba..4e8ed4ce 100644 --- a/test/test_dhcp.py +++ b/test/test_dhcp.py @@ -9,7 +9,7 @@ from vpp_neighbor import VppNeighbor from vpp_ip_route import find_route from util import mk_ll_addr -from scapy.layers.l2 import Ether, getmacbyip +from scapy.layers.l2 import Ether, getmacbyip, ARP from scapy.layers.inet import IP, UDP, ICMP from scapy.layers.inet6 import IPv6, in6_getnsmac, in6_mactoifaceid from scapy.layers.dhcp import DHCP, BOOTP, DHCPTypes @@ -189,11 +189,13 @@ class TestDHCP(VppTestCase): self.assertEqual(udp.dport, DHCP4_SERVER_PORT) self.assertEqual(udp.sport, DHCP4_CLIENT_PORT) - def verify_orig_dhcp_discover(self, pkt, intf, hostname): + def verify_orig_dhcp_discover(self, pkt, intf, hostname, client_id=None): self.verify_orig_dhcp_pkt(pkt, intf) self.verify_dhcp_msg_type(pkt, "discover") self.verify_dhcp_has_option(pkt, "hostname", hostname) + if client_id: + self.verify_dhcp_has_option(pkt, "client_id", client_id) def verify_orig_dhcp_request(self, pkt, intf, hostname, ip): self.verify_orig_dhcp_pkt(pkt, intf) @@ -1089,12 +1091,25 @@ class TestDHCP(VppTestCase): self.pg_enable_capture(self.pg_interfaces) self.pg_start() + # + # We'll get an ARP request for the router address + # + rx = self.pg2.get_capture(1) + + self.assertEqual(rx[0][ARP].pdst, self.pg2.remote_ip4) + self.pg_enable_capture(self.pg_interfaces) + # # At the end of this procedure there should be a connected route # in the FIB # self.assertTrue(find_route(self, self.pg2.local_ip4, 32)) + # remove the left over ARP entry + self.vapi.ip_neighbor_add_del(self.pg2.sw_if_index, + self.pg2.remote_mac, + self.pg2.remote_ip4, + is_add=0) # # remove the DHCP config # @@ -1105,6 +1120,21 @@ class TestDHCP(VppTestCase): # self.assertFalse(find_route(self, self.pg2.local_ip4, 32)) + # + # Start the procedure again. this time have VPP send the clientiid + # + self.vapi.dhcp_client(self.pg2.sw_if_index, hostname, + client_id=self.pg2.local_mac) + + rx = self.pg2.get_capture(1) + + self.verify_orig_dhcp_discover(rx[0], self.pg2, hostname, + self.pg2.local_mac) + + # + # remove the DHCP config + # + self.vapi.dhcp_client(self.pg2.sw_if_index, hostname, is_add=0) if __name__ == '__main__': unittest.main(testRunner=VppTestRunner) diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py index 31eadad8..2814ef97 100644 --- a/test/vpp_papi_provider.py +++ b/test/vpp_papi_provider.py @@ -1758,6 +1758,7 @@ class VppPapiProvider(object): def dhcp_client(self, sw_if_index, hostname, + client_id='', is_add=1, want_dhcp_events=0): return self.api( @@ -1765,6 +1766,7 @@ class VppPapiProvider(object): { 'sw_if_index': sw_if_index, 'hostname': hostname, + 'client_id': client_id, 'is_add': is_add, 'want_dhcp_event': want_dhcp_events, 'pid': os.getpid(), -- cgit 1.2.3-korg From 808c5b21c2759564689933d004223052b7895a42 Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Wed, 2 Aug 2017 05:15:07 -0700 Subject: DHCP Client: receive unicast ACKs despite VPP DHCP client setting neither ciaddr nor giaddr and setting the broadcast bit (see RFC 2131 section 4.1) some DHCP servers will still send a unicast DCHPACK. So as not to drop this VPP must have both 1) a receive FIB entry for the OFFERED IP adress and 2) a 'don't drop me because of uRPF' FIB entry for the DHCP server's address. Change-Id: I167d858deb45629318cbdccf5bf67d971730a42f Signed-off-by: Neale Ranns --- src/vnet/dhcp/client.c | 79 ++++++++++++++++++++++++++++++++++++++++- src/vnet/fib/fib_entry.h | 9 ++--- test/test_dhcp.py | 92 +++++++++++++++++++++++++++++++++++++----------- 3 files changed, 151 insertions(+), 29 deletions(-) (limited to 'src/vnet/dhcp/client.c') diff --git a/src/vnet/dhcp/client.c b/src/vnet/dhcp/client.c index 25ab3176..cfe62a6f 100644 --- a/src/vnet/dhcp/client.c +++ b/src/vnet/dhcp/client.c @@ -22,6 +22,70 @@ static u8 * format_dhcp_client_state (u8 * s, va_list * va); static vlib_node_registration_t dhcp_client_process_node; static void +dhcp_client_add_rx_address (dhcp_client_main_t * dcm, dhcp_client_t * c) +{ + /* Install a local entry for the offered address */ + fib_prefix_t rx = + { + .fp_len = 32, + .fp_addr.ip4 = c->leased_address, + .fp_proto = FIB_PROTOCOL_IP4, + }; + + fib_table_entry_special_add(fib_table_get_index_for_sw_if_index( + FIB_PROTOCOL_IP4, + c->sw_if_index), + &rx, + FIB_SOURCE_DHCP, + (FIB_ENTRY_FLAG_LOCAL)); + + /* And add the server's address as uRPF exempt so we can accept + * local packets from it */ + fib_prefix_t server = + { + .fp_len = 32, + .fp_addr.ip4 = c->dhcp_server, + .fp_proto = FIB_PROTOCOL_IP4, + }; + + fib_table_entry_special_add(fib_table_get_index_for_sw_if_index( + FIB_PROTOCOL_IP4, + c->sw_if_index), + &server, + FIB_SOURCE_URPF_EXEMPT, + (FIB_ENTRY_FLAG_DROP)); +} + +static void +dhcp_client_remove_rx_address (dhcp_client_main_t * dcm, dhcp_client_t * c) +{ + fib_prefix_t rx = + { + .fp_len = 32, + .fp_addr.ip4 = c->leased_address, + .fp_proto = FIB_PROTOCOL_IP4, + }; + + fib_table_entry_special_remove(fib_table_get_index_for_sw_if_index( + FIB_PROTOCOL_IP4, + c->sw_if_index), + &rx, + FIB_SOURCE_DHCP); + fib_prefix_t server = + { + .fp_len = 32, + .fp_addr.ip4 = c->dhcp_server, + .fp_proto = FIB_PROTOCOL_IP4, + }; + + fib_table_entry_special_remove(fib_table_get_index_for_sw_if_index( + FIB_PROTOCOL_IP4, + c->sw_if_index), + &server, + FIB_SOURCE_URPF_EXEMPT); +} + +static void dhcp_client_acquire_address (dhcp_client_main_t * dcm, dhcp_client_t * c) { /* @@ -95,7 +159,9 @@ int dhcp_client_for_us (u32 bi, vlib_buffer_t * b, /* parse through the packet, learn what we can */ if (dhcp->your_ip_address.as_u32) c->leased_address.as_u32 = dhcp->your_ip_address.as_u32; - + + c->dhcp_server.as_u32 = dhcp->server_ip_address.as_u32; + o = (dhcp_option_t *) dhcp->options; while (o->option != 0xFF /* end of options */ && @@ -172,6 +238,14 @@ int dhcp_client_for_us (u32 bi, vlib_buffer_t * b, c->next_transmit = now + 5.0; break; } + /* + * in order to accept unicasted ACKs we need to configure the offered + * address on the interface. However, at this point we may not know the + * subnet-mask (an OFFER may not contain it). So add a temporary receice + * and uRPF excempt entry + */ + dhcp_client_add_rx_address (dcm, c); + /* Received an offer, go send a request */ c->state = DHCP_REQUEST; c->retry_count = 0; @@ -196,6 +270,8 @@ int dhcp_client_for_us (u32 bi, vlib_buffer_t * b, { void (*fp)(u32, u32, u8 *, u8, u8, u8 *, u8 *, u8 *) = c->event_callback; + /* replace the temporary RX address with the correct subnet */ + dhcp_client_remove_rx_address (dcm, c); dhcp_client_acquire_address (dcm, c); /* @@ -831,6 +907,7 @@ int dhcp_client_add_del (dhcp_client_add_del_args_t * a) 1, FIB_ROUTE_PATH_FLAG_NONE); } + dhcp_client_remove_rx_address (dcm, c); dhcp_client_release_address (dcm, c); ip4_sw_interface_enable_disable (c->sw_if_index, 0); diff --git a/src/vnet/fib/fib_entry.h b/src/vnet/fib/fib_entry.h index 5f6ff312..93b8016d 100644 --- a/src/vnet/fib/fib_entry.h +++ b/src/vnet/fib/fib_entry.h @@ -205,14 +205,9 @@ typedef enum fib_entry_attribute_t_ { /** * Marker. add new entries before this one. */ - FIB_ENTRY_ATTRIBUTE_LAST = FIB_ENTRY_ATTRIBUTE_MULTICAST, + FIB_ENTRY_ATTRIBUTE_LAST = FIB_ENTRY_ATTRIBUTE_URPF_EXEMPT, } fib_entry_attribute_t; -/** - * The maximum number of sources - */ -#define FIB_ENTRY_ATTRIBUTE_MAX (FIB_ENTRY_ATTRIBUTE_LAST+1) - #define FIB_ENTRY_ATTRIBUTES { \ [FIB_ENTRY_ATTRIBUTE_CONNECTED] = "connected", \ [FIB_ENTRY_ATTRIBUTE_ATTACHED] = "attached", \ @@ -226,7 +221,7 @@ typedef enum fib_entry_attribute_t_ { #define FOR_EACH_FIB_ATTRIBUTE(_item) \ for (_item = FIB_ENTRY_ATTRIBUTE_FIRST; \ - _item < FIB_ENTRY_ATTRIBUTE_MAX; \ + _item <= FIB_ENTRY_ATTRIBUTE_LAST; \ _item++) typedef enum fib_entry_flag_t_ { diff --git a/test/test_dhcp.py b/test/test_dhcp.py index 4e8ed4ce..6fc29182 100644 --- a/test/test_dhcp.py +++ b/test/test_dhcp.py @@ -196,6 +196,10 @@ class TestDHCP(VppTestCase): self.verify_dhcp_has_option(pkt, "hostname", hostname) if client_id: self.verify_dhcp_has_option(pkt, "client_id", client_id) + bootp = pkt[BOOTP] + self.assertEqual(bootp.ciaddr, "0.0.0.0") + self.assertEqual(bootp.giaddr, "0.0.0.0") + self.assertEqual(bootp.flags, 0x8000) def verify_orig_dhcp_request(self, pkt, intf, hostname, ip): self.verify_orig_dhcp_pkt(pkt, intf) @@ -203,6 +207,10 @@ class TestDHCP(VppTestCase): self.verify_dhcp_msg_type(pkt, "request") self.verify_dhcp_has_option(pkt, "hostname", hostname) self.verify_dhcp_has_option(pkt, "requested_addr", ip) + bootp = pkt[BOOTP] + self.assertEqual(bootp.ciaddr, "0.0.0.0") + self.assertEqual(bootp.giaddr, "0.0.0.0") + self.assertEqual(bootp.flags, 0x8000) def verify_relayed_dhcp_discover(self, pkt, intf, src_intf=None, fib_id=0, oui=0, @@ -1057,14 +1065,15 @@ class TestDHCP(VppTestCase): # # Sned back on offer, expect the request # - p = (Ether(dst=self.pg2.local_mac, src=self.pg2.remote_mac) / - IP(src=self.pg2.remote_ip4, dst="255.255.255.255") / - UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_CLIENT_PORT) / - BOOTP(op=1, - yiaddr=self.pg2.local_ip4) / - DHCP(options=[('message-type', 'offer'), ('end')])) + p_offer = (Ether(dst=self.pg2.local_mac, src=self.pg2.remote_mac) / + IP(src=self.pg2.remote_ip4, dst="255.255.255.255") / + UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_CLIENT_PORT) / + BOOTP(op=1, yiaddr=self.pg2.local_ip4) / + DHCP(options=[('message-type', 'offer'), + ('server_id', self.pg2.remote_ip4), + ('end')])) - self.pg2.add_stream(p) + self.pg2.add_stream(p_offer) self.pg_enable_capture(self.pg_interfaces) self.pg_start() @@ -1075,19 +1084,18 @@ class TestDHCP(VppTestCase): # # Send an acknowloedgement # - p = (Ether(dst=self.pg2.local_mac, src=self.pg2.remote_mac) / - IP(src=self.pg2.remote_ip4, dst="255.255.255.255") / - UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_CLIENT_PORT) / - BOOTP(op=1, - yiaddr=self.pg2.local_ip4) / - DHCP(options=[('message-type', 'ack'), - ('subnet_mask', "255.255.255.0"), - ('router', self.pg2.remote_ip4), - ('server_id', self.pg2.remote_ip4), - ('lease_time', 43200), - ('end')])) - - self.pg2.add_stream(p) + p_ack = (Ether(dst=self.pg2.local_mac, src=self.pg2.remote_mac) / + IP(src=self.pg2.remote_ip4, dst="255.255.255.255") / + UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_CLIENT_PORT) / + BOOTP(op=1, yiaddr=self.pg2.local_ip4) / + DHCP(options=[('message-type', 'ack'), + ('subnet_mask', "255.255.255.0"), + ('router', self.pg2.remote_ip4), + ('server_id', self.pg2.remote_ip4), + ('lease_time', 43200), + ('end')])) + + self.pg2.add_stream(p_ack) self.pg_enable_capture(self.pg_interfaces) self.pg_start() @@ -1103,6 +1111,7 @@ class TestDHCP(VppTestCase): # At the end of this procedure there should be a connected route # in the FIB # + self.assertTrue(find_route(self, self.pg2.local_ip4, 24)) self.assertTrue(find_route(self, self.pg2.local_ip4, 32)) # remove the left over ARP entry @@ -1119,10 +1128,14 @@ class TestDHCP(VppTestCase): # and now the route should be gone # self.assertFalse(find_route(self, self.pg2.local_ip4, 32)) + self.assertFalse(find_route(self, self.pg2.local_ip4, 24)) # - # Start the procedure again. this time have VPP send the clientiid + # Start the procedure again. this time have VPP send the client-ID # + self.pg2.admin_down() + self.sleep(1) + self.pg2.admin_up() self.vapi.dhcp_client(self.pg2.sw_if_index, hostname, client_id=self.pg2.local_mac) @@ -1131,10 +1144,47 @@ class TestDHCP(VppTestCase): self.verify_orig_dhcp_discover(rx[0], self.pg2, hostname, self.pg2.local_mac) + self.pg2.add_stream(p_offer) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg2.get_capture(1) + self.verify_orig_dhcp_request(rx[0], self.pg2, hostname, + self.pg2.local_ip4) + + # + # unicast the ack to the offered address + # + p_ack = (Ether(dst=self.pg2.local_mac, src=self.pg2.remote_mac) / + IP(src=self.pg2.remote_ip4, dst=self.pg2.local_ip4) / + UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_CLIENT_PORT) / + BOOTP(op=1, yiaddr=self.pg2.local_ip4) / + DHCP(options=[('message-type', 'ack'), + ('subnet_mask', "255.255.255.0"), + ('router', self.pg2.remote_ip4), + ('server_id', self.pg2.remote_ip4), + ('lease_time', 43200), + ('end')])) + + self.pg2.add_stream(p_ack) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + # + # At the end of this procedure there should be a connected route + # in the FIB + # + self.assertTrue(find_route(self, self.pg2.local_ip4, 32)) + self.assertTrue(find_route(self, self.pg2.local_ip4, 24)) + # # remove the DHCP config # self.vapi.dhcp_client(self.pg2.sw_if_index, hostname, is_add=0) + self.assertFalse(find_route(self, self.pg2.local_ip4, 32)) + self.assertFalse(find_route(self, self.pg2.local_ip4, 24)) + + if __name__ == '__main__': unittest.main(testRunner=VppTestRunner) -- cgit 1.2.3-korg From da78f957e46c686434149d332a477d7ea055d76a Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Wed, 24 May 2017 09:15:43 -0700 Subject: L2 over MPLS [support for VPWS/VPLS] - switch to using dpo_proto_t rather than fib_protocol_t in fib_paths so that we can describe L2 paths - VLIB nodes to handle pop/push of MPLS labels to L2 Change-Id: Id050d06a11fd2c9c1c81ce5a0654e6c5ae6afa6e Signed-off-by: Neale Ranns --- src/plugins/gtpu/gtpu.c | 2 +- src/plugins/snat/snat.c | 2 +- src/vat/api_format.c | 17 +- src/vnet/dhcp/client.c | 6 +- src/vnet/dhcp/dhcp6_proxy_node.c | 2 +- src/vnet/dpo/dpo.c | 19 ++ src/vnet/dpo/dpo.h | 11 +- src/vnet/dpo/interface_dpo.c | 30 +++ src/vnet/dpo/mpls_label_dpo.c | 45 +++- src/vnet/ethernet/arp.c | 4 +- src/vnet/fib/fib_api.h | 4 +- src/vnet/fib/fib_entry.c | 8 +- src/vnet/fib/fib_entry_src.c | 16 +- src/vnet/fib/fib_entry_src.h | 4 +- src/vnet/fib/fib_entry_src_api.c | 2 +- src/vnet/fib/fib_entry_src_default_route.c | 2 +- src/vnet/fib/fib_entry_src_interface.c | 2 +- src/vnet/fib/fib_entry_src_lisp.c | 8 +- src/vnet/fib/fib_entry_src_mpls.c | 4 +- src/vnet/fib/fib_entry_src_rr.c | 15 +- src/vnet/fib/fib_entry_src_special.c | 2 +- src/vnet/fib/fib_path.c | 79 +++---- src/vnet/fib/fib_path.h | 11 +- src/vnet/fib/fib_path_ext.c | 3 + src/vnet/fib/fib_path_list.c | 4 +- src/vnet/fib/fib_path_list.h | 4 +- src/vnet/fib/fib_table.c | 6 +- src/vnet/fib/fib_table.h | 6 +- src/vnet/fib/fib_test.c | 338 ++++++++++++++--------------- src/vnet/fib/fib_types.h | 8 +- src/vnet/interface_format.c | 12 +- src/vnet/ip/ip4_forward.c | 6 +- src/vnet/ip/ip6_forward.c | 4 +- src/vnet/ip/ip6_neighbor.c | 10 +- src/vnet/ip/ip_api.c | 38 ++-- src/vnet/ip/lookup.c | 18 +- src/vnet/lisp-gpe/lisp_gpe.c | 13 +- src/vnet/lisp-gpe/lisp_gpe_api.c | 10 +- src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c | 5 +- src/vnet/mfib/ip6_mfib.c | 6 +- src/vnet/mfib/mfib_entry.c | 10 +- src/vnet/mfib/mfib_test.c | 14 +- src/vnet/mpls/mpls.api | 4 +- src/vnet/mpls/mpls.c | 36 +-- src/vnet/mpls/mpls_api.c | 21 +- src/vnet/mpls/mpls_tunnel.c | 75 ++++--- src/vnet/mpls/mpls_tunnel.h | 38 ++-- src/vnet/srmpls/sr_mpls_policy.c | 6 +- src/vnet/srmpls/sr_mpls_steering.c | 2 +- src/vnet/srv6/sr_steering.c | 4 +- src/vnet/vxlan-gpe/vxlan_gpe.c | 2 +- src/vnet/vxlan/vxlan.c | 2 +- src/vpp/app/vpe_cli.c | 2 +- test/test_bfd.py | 6 +- test/test_gre.py | 24 +- test/test_ip6.py | 26 +-- test/test_map.py | 19 +- test/test_mpls.py | 318 ++++++++++++++++++++++----- test/test_p2p_ethernet.py | 16 +- test/vpp_ip_route.py | 24 +- test/vpp_mpls_tunnel_interface.py | 6 +- test/vpp_papi_provider.py | 4 +- 62 files changed, 889 insertions(+), 556 deletions(-) (limited to 'src/vnet/dhcp/client.c') diff --git a/src/plugins/gtpu/gtpu.c b/src/plugins/gtpu/gtpu.c index 84745bd8..3dfb4210 100755 --- a/src/plugins/gtpu/gtpu.c +++ b/src/plugins/gtpu/gtpu.c @@ -534,7 +534,7 @@ int vnet_gtpu_add_del_tunnel fib_node_index_t mfei; adj_index_t ai; fib_route_path_t path = { - .frp_proto = fp, + .frp_proto = fib_proto_to_dpo (fp), .frp_addr = zero_addr, .frp_sw_if_index = 0xffffffff, .frp_fib_index = ~0, diff --git a/src/plugins/snat/snat.c b/src/plugins/snat/snat.c index 9fbc1e54..f196b5c2 100644 --- a/src/plugins/snat/snat.c +++ b/src/plugins/snat/snat.c @@ -135,7 +135,7 @@ snat_add_del_addr_to_fib (ip4_address_t * addr, u8 p_len, u32 sw_if_index, (FIB_ENTRY_FLAG_CONNECTED | FIB_ENTRY_FLAG_LOCAL | FIB_ENTRY_FLAG_EXCLUSIVE), - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, NULL, sw_if_index, ~0, diff --git a/src/vat/api_format.c b/src/vat/api_format.c index f97cdeef..009cf173 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -7498,7 +7498,7 @@ api_mpls_route_add_del (vat_main_t * vam) mpls_label_t *next_hop_out_label_stack = NULL; mpls_label_t local_label = MPLS_LABEL_INVALID; u8 is_eos = 0; - u8 next_hop_proto_is_ip4 = 1; + dpo_proto_t next_hop_proto = DPO_PROTO_IP4; /* Parse args required to build the message */ while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) @@ -7517,13 +7517,13 @@ api_mpls_route_add_del (vat_main_t * vam) &v4_next_hop_address)) { next_hop_set = 1; - next_hop_proto_is_ip4 = 1; + next_hop_proto = DPO_PROTO_IP4; } else if (unformat (i, "via %U", unformat_ip6_address, &v6_next_hop_address)) { next_hop_set = 1; - next_hop_proto_is_ip4 = 0; + next_hop_proto = DPO_PROTO_IP6; } else if (unformat (i, "weight %d", &next_hop_weight)) ; @@ -7548,12 +7548,12 @@ api_mpls_route_add_del (vat_main_t * vam) else if (unformat (i, "lookup-in-ip4-table %d", &next_hop_table_id)) { next_hop_set = 1; - next_hop_proto_is_ip4 = 1; + next_hop_proto = DPO_PROTO_IP4; } else if (unformat (i, "lookup-in-ip6-table %d", &next_hop_table_id)) { next_hop_set = 1; - next_hop_proto_is_ip4 = 0; + next_hop_proto = DPO_PROTO_IP6; } else if (unformat (i, "next-hop-table %d", &next_hop_table_id)) ; @@ -7599,7 +7599,7 @@ api_mpls_route_add_del (vat_main_t * vam) mp->mr_create_table_if_needed = create_table_if_needed; mp->mr_is_add = is_add; - mp->mr_next_hop_proto_is_ip4 = next_hop_proto_is_ip4; + mp->mr_next_hop_proto = next_hop_proto; mp->mr_is_classify = is_classify; mp->mr_is_multipath = is_multipath; mp->mr_is_resolve_host = resolve_host; @@ -7622,13 +7622,14 @@ api_mpls_route_add_del (vat_main_t * vam) if (next_hop_set) { - if (next_hop_proto_is_ip4) + if (DPO_PROTO_IP4 == next_hop_proto) { clib_memcpy (mp->mr_next_hop, &v4_next_hop_address, sizeof (v4_next_hop_address)); } - else + else if (DPO_PROTO_IP6 == next_hop_proto) + { clib_memcpy (mp->mr_next_hop, &v6_next_hop_address, diff --git a/src/vnet/dhcp/client.c b/src/vnet/dhcp/client.c index cfe62a6f..dd5e99f2 100644 --- a/src/vnet/dhcp/client.c +++ b/src/vnet/dhcp/client.c @@ -296,7 +296,7 @@ int dhcp_client_for_us (u32 bi, vlib_buffer_t * b, &all_0s, FIB_SOURCE_DHCP, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh, c->sw_if_index, ~0, @@ -605,7 +605,7 @@ dhcp_bound_state (dhcp_client_main_t * dcm, dhcp_client_t * c, f64 now) c->sw_if_index), &all_0s, FIB_SOURCE_DHCP, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh, c->sw_if_index, ~0, @@ -900,7 +900,7 @@ int dhcp_client_add_del (dhcp_client_add_del_args_t * a) c->sw_if_index), &all_0s, FIB_SOURCE_DHCP, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh, c->sw_if_index, ~0, diff --git a/src/vnet/dhcp/dhcp6_proxy_node.c b/src/vnet/dhcp/dhcp6_proxy_node.c index e109cc4c..9c2f5220 100644 --- a/src/vnet/dhcp/dhcp6_proxy_node.c +++ b/src/vnet/dhcp/dhcp6_proxy_node.c @@ -857,7 +857,7 @@ dhcp6_proxy_set_server (ip46_address_t *addr, else { const fib_route_path_t path_for_us = { - .frp_proto = FIB_PROTOCOL_IP6, + .frp_proto = DPO_PROTO_IP6, .frp_addr = zero_addr, .frp_sw_if_index = 0xffffffff, .frp_fib_index = ~0, diff --git a/src/vnet/dpo/dpo.c b/src/vnet/dpo/dpo.c index 389f995b..aa770838 100644 --- a/src/vnet/dpo/dpo.c +++ b/src/vnet/dpo/dpo.c @@ -109,6 +109,25 @@ vnet_link_to_dpo_proto (vnet_link_t linkt) return (0); } +vnet_link_t +dpo_proto_to_link (dpo_proto_t dp) +{ + switch (dp) + { + case DPO_PROTO_IP6: + return (VNET_LINK_IP6); + case DPO_PROTO_IP4: + return (VNET_LINK_IP4); + case DPO_PROTO_MPLS: + return (VNET_LINK_MPLS); + case DPO_PROTO_ETHERNET: + return (VNET_LINK_ETHERNET); + case DPO_PROTO_NSH: + return (VNET_LINK_NSH); + } + return (~0); +} + u8 * format_dpo_type (u8 * s, va_list * args) { diff --git a/src/vnet/dpo/dpo.h b/src/vnet/dpo/dpo.h index 5aa4e2d2..42fc51d4 100644 --- a/src/vnet/dpo/dpo.h +++ b/src/vnet/dpo/dpo.h @@ -59,14 +59,10 @@ typedef u32 index_t; */ typedef enum dpo_proto_t_ { -#if CLIB_DEBUG > 0 - DPO_PROTO_IP4 = 1, -#else DPO_PROTO_IP4 = 0, -#endif DPO_PROTO_IP6, - DPO_PROTO_ETHERNET, DPO_PROTO_MPLS, + DPO_PROTO_ETHERNET, DPO_PROTO_NSH, } __attribute__((packed)) dpo_proto_t; @@ -272,6 +268,11 @@ extern u8 *format_dpo_type(u8 * s, va_list * args); */ extern u8 *format_dpo_proto(u8 * s, va_list * args); +/** + * @brief format a DPO protocol + */ +extern vnet_link_t dpo_proto_to_link(dpo_proto_t dp); + /** * @brief * Set and stack a DPO. diff --git a/src/vnet/dpo/interface_dpo.c b/src/vnet/dpo/interface_dpo.c index 8d700c23..780bfa2a 100644 --- a/src/vnet/dpo/interface_dpo.c +++ b/src/vnet/dpo/interface_dpo.c @@ -195,11 +195,17 @@ const static char* const interface_dpo_ip6_nodes[] = "interface-dpo-ip4", NULL, }; +const static char* const interface_dpo_l2_nodes[] = +{ + "interface-dpo-l2", + NULL, +}; const static char* const * const interface_dpo_nodes[DPO_PROTO_NUM] = { [DPO_PROTO_IP4] = interface_dpo_ip4_nodes, [DPO_PROTO_IP6] = interface_dpo_ip6_nodes, + [DPO_PROTO_ETHERNET] = interface_dpo_l2_nodes, [DPO_PROTO_MPLS] = NULL, }; @@ -382,6 +388,14 @@ interface_dpo_ip6 (vlib_main_t * vm, return (interface_dpo_inline(vm, node, from_frame)); } +static uword +interface_dpo_l2 (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * from_frame) +{ + return (interface_dpo_inline(vm, node, from_frame)); +} + VLIB_REGISTER_NODE (interface_dpo_ip4_node) = { .function = interface_dpo_ip4, .name = "interface-dpo-ip4", @@ -414,3 +428,19 @@ VLIB_REGISTER_NODE (interface_dpo_ip6_node) = { VLIB_NODE_FUNCTION_MULTIARCH (interface_dpo_ip6_node, interface_dpo_ip6) +VLIB_REGISTER_NODE (interface_dpo_l2_node) = { + .function = interface_dpo_l2, + .name = "interface-dpo-l2", + .vector_size = sizeof (u32), + .format_trace = format_interface_dpo_trace, + + .n_next_nodes = 2, + .next_nodes = { + [INTERFACE_DPO_DROP] = "error-drop", + [INTERFACE_DPO_INPUT] = "l2-input", + }, +}; + +VLIB_NODE_FUNCTION_MULTIARCH (interface_dpo_l2_node, + interface_dpo_l2) + diff --git a/src/vnet/dpo/mpls_label_dpo.c b/src/vnet/dpo/mpls_label_dpo.c index 1c451a51..b178a902 100644 --- a/src/vnet/dpo/mpls_label_dpo.c +++ b/src/vnet/dpo/mpls_label_dpo.c @@ -192,7 +192,8 @@ mpls_label_imposition_inline (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * from_frame, u8 payload_is_ip4, - u8 payload_is_ip6) + u8 payload_is_ip6, + u8 payload_is_ethernet) { u32 n_left_from, next_index, * from, * to_next; @@ -320,6 +321,13 @@ mpls_label_imposition_inline (vlib_main_t * vm, ttl2 = ip2->hop_limit; ttl3 = ip3->hop_limit; } + else if (payload_is_ethernet) + { + /* + * nothing to chang ein the ethernet header + */ + ttl0 = ttl1 = ttl2 = ttl3 = 255; + } else { /* @@ -551,7 +559,7 @@ mpls_label_imposition (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { - return (mpls_label_imposition_inline(vm, node, frame, 0, 0)); + return (mpls_label_imposition_inline(vm, node, frame, 0, 0, 0)); } VLIB_REGISTER_NODE (mpls_label_imposition_node) = { @@ -573,7 +581,7 @@ ip4_mpls_label_imposition (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { - return (mpls_label_imposition_inline(vm, node, frame, 1, 0)); + return (mpls_label_imposition_inline(vm, node, frame, 1, 0, 0)); } VLIB_REGISTER_NODE (ip4_mpls_label_imposition_node) = { @@ -595,7 +603,7 @@ ip6_mpls_label_imposition (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { - return (mpls_label_imposition_inline(vm, node, frame, 0, 1)); + return (mpls_label_imposition_inline(vm, node, frame, 0, 1, 0)); } VLIB_REGISTER_NODE (ip6_mpls_label_imposition_node) = { @@ -612,6 +620,28 @@ VLIB_REGISTER_NODE (ip6_mpls_label_imposition_node) = { VLIB_NODE_FUNCTION_MULTIARCH (ip6_mpls_label_imposition_node, ip6_mpls_label_imposition) +static uword +ethernet_mpls_label_imposition (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return (mpls_label_imposition_inline(vm, node, frame, 0, 0, 1)); +} + +VLIB_REGISTER_NODE (ethernet_mpls_label_imposition_node) = { + .function = ethernet_mpls_label_imposition, + .name = "ethernet-mpls-label-imposition", + .vector_size = sizeof (u32), + + .format_trace = format_mpls_label_imposition_trace, + .n_next_nodes = 1, + .next_nodes = { + [0] = "error-drop", + } +}; +VLIB_NODE_FUNCTION_MULTIARCH (ethernet_mpls_label_imposition_node, + ethernet_mpls_label_imposition) + static void mpls_label_dpo_mem_show (void) { @@ -643,11 +673,18 @@ const static char* const mpls_label_imp_mpls_nodes[] = "mpls-label-imposition", NULL, }; +const static char* const mpls_label_imp_ethernet_nodes[] = +{ + "ethernet-mpls-label-imposition", + NULL, +}; + const static char* const * const mpls_label_imp_nodes[DPO_PROTO_NUM] = { [DPO_PROTO_IP4] = mpls_label_imp_ip4_nodes, [DPO_PROTO_IP6] = mpls_label_imp_ip6_nodes, [DPO_PROTO_MPLS] = mpls_label_imp_mpls_nodes, + [DPO_PROTO_ETHERNET] = mpls_label_imp_ethernet_nodes, }; diff --git a/src/vnet/ethernet/arp.c b/src/vnet/ethernet/arp.c index 4d9edaf5..8a394006 100644 --- a/src/vnet/ethernet/arp.c +++ b/src/vnet/ethernet/arp.c @@ -588,7 +588,7 @@ vnet_arp_set_ip4_over_ethernet_internal (vnet_main_t * vnm, e->fib_entry_index = fib_table_entry_path_add (fib_index, &pfx, FIB_SOURCE_ADJ, FIB_ENTRY_FLAG_ATTACHED, - FIB_PROTOCOL_IP4, &pfx.fp_addr, + DPO_PROTO_IP4, &pfx.fp_addr, e->sw_if_index, ~0, 1, NULL, FIB_ROUTE_PATH_FLAG_NONE); } @@ -1621,7 +1621,7 @@ arp_entry_free (ethernet_arp_interface_t * eai, ethernet_arp_ip4_entry_t * e) fib_table_entry_path_remove (fib_index, &pfx, FIB_SOURCE_ADJ, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx.fp_addr, e->sw_if_index, ~0, 1, FIB_ROUTE_PATH_FLAG_NONE); diff --git a/src/vnet/fib/fib_api.h b/src/vnet/fib/fib_api.h index 73d76a42..d07d6cae 100644 --- a/src/vnet/fib/fib_api.h +++ b/src/vnet/fib/fib_api.h @@ -21,7 +21,7 @@ int add_del_route_check (fib_protocol_t table_proto, u32 table_id, u32 next_hop_sw_if_index, - fib_protocol_t next_hop_table_proto, + dpo_proto_t next_hop_table_proto, u32 next_hop_table_id, u8 create_missing_tables, u8 is_rpf_id, @@ -43,7 +43,7 @@ add_del_route_t_handler (u8 is_multipath, u8 is_rpf_id, u32 fib_index, const fib_prefix_t * prefix, - u8 next_hop_proto_is_ip4, + dpo_proto_t next_hop_proto, const ip46_address_t * next_hop, u32 next_hop_sw_if_index, u8 next_hop_fib_index, diff --git a/src/vnet/fib/fib_entry.c b/src/vnet/fib/fib_entry.c index d7ff1c8c..2027f2be 100644 --- a/src/vnet/fib/fib_entry.c +++ b/src/vnet/fib/fib_entry.c @@ -58,12 +58,18 @@ fib_entry_get_index (const fib_entry_t * fib_entry) return (fib_entry - fib_entry_pool); } -static fib_protocol_t +fib_protocol_t fib_entry_get_proto (const fib_entry_t * fib_entry) { return (fib_entry->fe_prefix.fp_proto); } +dpo_proto_t +fib_entry_get_dpo_proto (const fib_entry_t * fib_entry) +{ + return (fib_proto_to_dpo(fib_entry->fe_prefix.fp_proto)); +} + fib_forward_chain_type_t fib_entry_get_default_chain_type (const fib_entry_t *fib_entry) { diff --git a/src/vnet/fib/fib_entry_src.c b/src/vnet/fib/fib_entry_src.c index ff73cbf9..173df74f 100644 --- a/src/vnet/fib/fib_entry_src.c +++ b/src/vnet/fib/fib_entry_src.c @@ -29,12 +29,6 @@ */ static fib_entry_src_vft_t fib_entry_src_vft[FIB_SOURCE_MAX]; -static fib_protocol_t -fib_entry_get_proto (const fib_entry_t * fib_entry) -{ - return (fib_entry->fe_prefix.fp_proto); -} - void fib_entry_src_register (fib_source_t source, const fib_entry_src_vft_t *vft) @@ -861,7 +855,7 @@ fib_entry_src_action_add (fib_entry_t *fib_entry, fib_entry_src_vft[source].fesv_add(esrc, fib_entry, flags, - fib_entry_get_proto(fib_entry), + fib_entry_get_dpo_proto(fib_entry), dpo); } @@ -914,7 +908,7 @@ fib_entry_src_action_update (fib_entry_t *fib_entry, fib_entry_src_vft[source].fesv_add(esrc, fib_entry, flags, - fib_entry_get_proto(fib_entry), + fib_entry_get_dpo_proto(fib_entry), dpo); } @@ -1106,8 +1100,7 @@ fib_entry_src_action_path_add (fib_entry_t *fib_entry, source, flags, drop_dpo_get( - fib_proto_to_dpo( - fib_entry_get_proto(fib_entry)))); + fib_entry_get_dpo_proto(fib_entry))); esrc = fib_entry_src_find(fib_entry, source, NULL); } @@ -1166,8 +1159,7 @@ fib_entry_src_action_path_swap (fib_entry_t *fib_entry, source, flags, drop_dpo_get( - fib_proto_to_dpo( - fib_entry_get_proto(fib_entry)))); + fib_entry_get_dpo_proto(fib_entry))); esrc = fib_entry_src_find(fib_entry, source, NULL); } diff --git a/src/vnet/fib/fib_entry_src.h b/src/vnet/fib/fib_entry_src.h index 640c174d..35c43936 100644 --- a/src/vnet/fib/fib_entry_src.h +++ b/src/vnet/fib/fib_entry_src.h @@ -73,7 +73,7 @@ typedef void (*fib_entry_src_deactivate_t)(fib_entry_src_t *src, typedef void (*fib_entry_src_add_t)(fib_entry_src_t *src, const fib_entry_t *entry, fib_entry_flag_t flags, - fib_protocol_t proto, + dpo_proto_t proto, const dpo_id_t *dpo); /** @@ -277,6 +277,8 @@ extern void fib_entry_src_mk_lb (fib_entry_t *fib_entry, fib_forward_chain_type_t fct, dpo_id_t *dpo_lb); +extern fib_protocol_t fib_entry_get_proto(const fib_entry_t * fib_entry); +extern dpo_proto_t fib_entry_get_dpo_proto(const fib_entry_t * fib_entry); /* * Per-source registration. declared here so we save a separate .h file for each diff --git a/src/vnet/fib/fib_entry_src_api.c b/src/vnet/fib/fib_entry_src_api.c index f895886b..1cdcfbde 100644 --- a/src/vnet/fib/fib_entry_src_api.c +++ b/src/vnet/fib/fib_entry_src_api.c @@ -131,7 +131,7 @@ static void fib_entry_src_api_add (fib_entry_src_t *src, const fib_entry_t *entry, fib_entry_flag_t flags, - fib_protocol_t proto, + dpo_proto_t proto, const dpo_id_t *dpo) { if (FIB_ENTRY_FLAG_NONE != flags) diff --git a/src/vnet/fib/fib_entry_src_default_route.c b/src/vnet/fib/fib_entry_src_default_route.c index 9f4e7c36..431abb66 100644 --- a/src/vnet/fib/fib_entry_src_default_route.c +++ b/src/vnet/fib/fib_entry_src_default_route.c @@ -35,7 +35,7 @@ static void fib_entry_src_default_route_add (fib_entry_src_t *src, const fib_entry_t *entry, fib_entry_flag_t flags, - fib_protocol_t proto, + dpo_proto_t proto, const dpo_id_t *dpo) { src->fes_pl = fib_path_list_create_special(proto, diff --git a/src/vnet/fib/fib_entry_src_interface.c b/src/vnet/fib/fib_entry_src_interface.c index bb87818f..6c087f34 100644 --- a/src/vnet/fib/fib_entry_src_interface.c +++ b/src/vnet/fib/fib_entry_src_interface.c @@ -35,7 +35,7 @@ static void fib_entry_src_interface_add (fib_entry_src_t *src, const fib_entry_t *entry, fib_entry_flag_t flags, - fib_protocol_t proto, + dpo_proto_t proto, const dpo_id_t *dpo) { src->fes_pl = fib_path_list_create_special( diff --git a/src/vnet/fib/fib_entry_src_lisp.c b/src/vnet/fib/fib_entry_src_lisp.c index 7f8b91bb..e72dce63 100644 --- a/src/vnet/fib/fib_entry_src_lisp.c +++ b/src/vnet/fib/fib_entry_src_lisp.c @@ -79,10 +79,10 @@ fib_entry_src_lisp_path_remove (fib_entry_src_t *src, static void fib_entry_src_lisp_add (fib_entry_src_t *src, - const fib_entry_t *entry, - fib_entry_flag_t flags, - fib_protocol_t proto, - const dpo_id_t *dpo) + const fib_entry_t *entry, + fib_entry_flag_t flags, + dpo_proto_t proto, + const dpo_id_t *dpo) { if (FIB_ENTRY_FLAG_NONE != flags) { diff --git a/src/vnet/fib/fib_entry_src_mpls.c b/src/vnet/fib/fib_entry_src_mpls.c index 14c7310f..a616458f 100644 --- a/src/vnet/fib/fib_entry_src_mpls.c +++ b/src/vnet/fib/fib_entry_src_mpls.c @@ -57,13 +57,13 @@ static void fib_entry_src_mpls_add (fib_entry_src_t *src, const fib_entry_t *entry, fib_entry_flag_t flags, - fib_protocol_t proto, + dpo_proto_t proto, const dpo_id_t *dpo) { src->fes_pl = fib_path_list_create_special(proto, FIB_PATH_LIST_FLAG_DROP, - drop_dpo_get(fib_proto_to_dpo(proto))); + drop_dpo_get(proto)); } static void diff --git a/src/vnet/fib/fib_entry_src_rr.c b/src/vnet/fib/fib_entry_src_rr.c index d66ef7b1..1153f3f1 100644 --- a/src/vnet/fib/fib_entry_src_rr.c +++ b/src/vnet/fib/fib_entry_src_rr.c @@ -35,7 +35,7 @@ fib_entry_src_rr_resolve_via_connected (fib_entry_src_t *src, const fib_entry_t *cover) { const fib_route_path_t path = { - .frp_proto = fib_entry->fe_prefix.fp_proto, + .frp_proto = fib_proto_to_dpo(fib_entry->fe_prefix.fp_proto), .frp_addr = fib_entry->fe_prefix.fp_addr, .frp_sw_if_index = fib_entry_get_resolving_interface( fib_entry_get_index(cover)), @@ -90,18 +90,17 @@ fib_entry_src_rr_use_covers_pl (fib_entry_src_t *src, const fib_entry_t *cover) { fib_node_index_t *entries = NULL; - fib_protocol_t proto; + dpo_proto_t proto; - proto = fib_entry->fe_prefix.fp_proto; + proto = fib_proto_to_dpo(fib_entry->fe_prefix.fp_proto); vec_add1(entries, fib_entry_get_index(fib_entry)); if (fib_path_list_recursive_loop_detect(cover->fe_parent, &entries)) { - src->fes_pl = fib_path_list_create_special( - proto, - FIB_PATH_LIST_FLAG_DROP, - drop_dpo_get(fib_proto_to_dpo(proto))); + src->fes_pl = fib_path_list_create_special(proto, + FIB_PATH_LIST_FLAG_DROP, + drop_dpo_get(proto)); } else { @@ -126,7 +125,7 @@ fib_entry_src_rr_activate (fib_entry_src_t *src, */ if (FIB_PROTOCOL_MPLS == fib_entry->fe_prefix.fp_proto) { - src->fes_pl = fib_path_list_create_special(FIB_PROTOCOL_MPLS, + src->fes_pl = fib_path_list_create_special(DPO_PROTO_MPLS, FIB_PATH_LIST_FLAG_DROP, NULL); fib_path_list_lock(src->fes_pl); diff --git a/src/vnet/fib/fib_entry_src_special.c b/src/vnet/fib/fib_entry_src_special.c index 75605d7f..e979e18f 100644 --- a/src/vnet/fib/fib_entry_src_special.c +++ b/src/vnet/fib/fib_entry_src_special.c @@ -43,7 +43,7 @@ static void fib_entry_src_special_add (fib_entry_src_t *src, const fib_entry_t *entry, fib_entry_flag_t flags, - fib_protocol_t proto, + dpo_proto_t proto, const dpo_id_t *dpo) { src->fes_pl = diff --git a/src/vnet/fib/fib_path.c b/src/vnet/fib/fib_path.c index 3a67a544..58050ccb 100644 --- a/src/vnet/fib/fib_path.c +++ b/src/vnet/fib/fib_path.c @@ -193,7 +193,7 @@ typedef struct fib_path_t_ { * next-hop's address. We can't derive this from the address itself * since the address can be all zeros */ - fib_protocol_t fp_nh_proto; + dpo_proto_t fp_nh_proto; /** * UCMP [unnormalised] weigth @@ -381,7 +381,7 @@ format_fib_path (u8 * s, va_list * args) s = format (s, " index:%d ", fib_path_get_index(path)); s = format (s, "pl-index:%d ", path->fp_pl_index); - s = format (s, "%U ", format_fib_protocol, path->fp_nh_proto); + s = format (s, "%U ", format_dpo_proto, path->fp_nh_proto); s = format (s, "weight=%d ", path->fp_weight); s = format (s, "pref=%d ", path->fp_preference); s = format (s, "%s: ", fib_path_type_names[path->fp_type]); @@ -454,7 +454,7 @@ format_fib_path (u8 * s, va_list * args) } break; case FIB_PATH_TYPE_RECURSIVE: - if (FIB_PROTOCOL_MPLS == path->fp_nh_proto) + if (DPO_PROTO_MPLS == path->fp_nh_proto) { s = format (s, "via %U %U", format_mpls_unicast_label, @@ -552,14 +552,14 @@ fib_path_attached_next_hop_get_adj (fib_path_t *path, * the subnet address (the attached route) links to the * auto-adj (see below), we want that adj here too. */ - return (adj_nbr_add_or_lock(path->fp_nh_proto, + return (adj_nbr_add_or_lock(dpo_proto_to_fib(path->fp_nh_proto), link, &zero_addr, path->attached_next_hop.fp_interface)); } else { - return (adj_nbr_add_or_lock(path->fp_nh_proto, + return (adj_nbr_add_or_lock(dpo_proto_to_fib(path->fp_nh_proto), link, &path->attached_next_hop.fp_nh, path->attached_next_hop.fp_interface)); @@ -575,10 +575,10 @@ fib_path_attached_next_hop_set (fib_path_t *path) */ dpo_set(&path->fp_dpo, DPO_ADJACENCY, - fib_proto_to_dpo(path->fp_nh_proto), + path->fp_nh_proto, fib_path_attached_next_hop_get_adj( path, - fib_proto_to_link(path->fp_nh_proto))); + dpo_proto_to_link(path->fp_nh_proto))); /* * become a child of the adjacency so we receive updates @@ -607,14 +607,14 @@ fib_path_attached_get_adj (fib_path_t *path, * point-2-point interfaces do not require a glean, since * there is nothing to ARP. Install a rewrite/nbr adj instead */ - return (adj_nbr_add_or_lock(path->fp_nh_proto, + return (adj_nbr_add_or_lock(dpo_proto_to_fib(path->fp_nh_proto), link, &zero_addr, path->attached.fp_interface)); } else { - return (adj_glean_add_or_lock(path->fp_nh_proto, + return (adj_glean_add_or_lock(dpo_proto_to_fib(path->fp_nh_proto), path->attached.fp_interface, NULL)); } @@ -650,7 +650,7 @@ fib_path_recursive_adj_update (fib_path_t *path, if (path->fp_oper_flags & FIB_PATH_OPER_FLAG_RECURSIVE_LOOP) { path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RESOLVED; - dpo_copy(&via_dpo, drop_dpo_get(fib_proto_to_dpo(path->fp_nh_proto))); + dpo_copy(&via_dpo, drop_dpo_get(path->fp_nh_proto)); } else if (path->fp_cfg_flags & FIB_PATH_CFG_FLAG_RESOLVE_HOST) { @@ -668,7 +668,7 @@ fib_path_recursive_adj_update (fib_path_t *path, if (fib_entry_get_best_source(path->fp_via_fib) >= FIB_SOURCE_RR) { path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RESOLVED; - dpo_copy(&via_dpo, drop_dpo_get(fib_proto_to_dpo(path->fp_nh_proto))); + dpo_copy(&via_dpo, drop_dpo_get(path->fp_nh_proto)); /* * PIC edge trigger. let the load-balance maps know @@ -685,7 +685,7 @@ fib_path_recursive_adj_update (fib_path_t *path, if (!(FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags(path->fp_via_fib))) { path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RESOLVED; - dpo_copy(&via_dpo, drop_dpo_get(fib_proto_to_dpo(path->fp_nh_proto))); + dpo_copy(&via_dpo, drop_dpo_get(path->fp_nh_proto)); /* * PIC edge trigger. let the load-balance maps know @@ -699,7 +699,7 @@ fib_path_recursive_adj_update (fib_path_t *path, if (!fib_entry_is_resolved(path->fp_via_fib)) { path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RESOLVED; - dpo_copy(&via_dpo, drop_dpo_get(fib_proto_to_dpo(path->fp_nh_proto))); + dpo_copy(&via_dpo, drop_dpo_get(path->fp_nh_proto)); /* * PIC edge trigger. let the load-balance maps know @@ -720,9 +720,7 @@ fib_path_recursive_adj_update (fib_path_t *path, */ dpo_copy(dpo, &via_dpo); - FIB_PATH_DBG(path, "recursive update: %U", - fib_get_lookup_main(path->fp_nh_proto), - &path->fp_dpo, 2); + FIB_PATH_DBG(path, "recursive update:"); dpo_reset(&via_dpo); } @@ -804,13 +802,8 @@ fib_path_unresolve (fib_path_t *path) static fib_forward_chain_type_t fib_path_to_chain_type (const fib_path_t *path) { - switch (path->fp_nh_proto) + if (DPO_PROTO_MPLS == path->fp_nh_proto) { - case FIB_PROTOCOL_IP4: - return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4); - case FIB_PROTOCOL_IP6: - return (FIB_FORW_CHAIN_TYPE_UNICAST_IP6); - case FIB_PROTOCOL_MPLS: if (FIB_PATH_TYPE_RECURSIVE == path->fp_type && MPLS_EOS == path->recursive.fp_nh.fp_eos) { @@ -821,7 +814,10 @@ fib_path_to_chain_type (const fib_path_t *path) return (FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS); } } - return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4); + else + { + return (fib_forw_chain_type_from_dpo_proto(path->fp_nh_proto)); + } } /* @@ -927,7 +923,7 @@ FIXME comment ai = fib_path_attached_next_hop_get_adj( path, - fib_proto_to_link(path->fp_nh_proto)); + dpo_proto_to_link(path->fp_nh_proto)); path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RESOLVED; if (if_is_up && adj_is_up(ai)) @@ -935,9 +931,7 @@ FIXME comment path->fp_oper_flags |= FIB_PATH_OPER_FLAG_RESOLVED; } - dpo_set(&path->fp_dpo, DPO_ADJACENCY, - fib_proto_to_dpo(path->fp_nh_proto), - ai); + dpo_set(&path->fp_dpo, DPO_ADJACENCY, path->fp_nh_proto, ai); adj_unlock(ai); if (!if_is_up) @@ -1141,7 +1135,7 @@ fib_path_create (fib_node_index_t pl_index, else { path->fp_type = FIB_PATH_TYPE_RECURSIVE; - if (FIB_PROTOCOL_MPLS == path->fp_nh_proto) + if (DPO_PROTO_MPLS == path->fp_nh_proto) { path->recursive.fp_nh.fp_local_label = rpath->frp_local_label; path->recursive.fp_nh.fp_eos = rpath->frp_eos; @@ -1167,7 +1161,7 @@ fib_path_create (fib_node_index_t pl_index, */ fib_node_index_t fib_path_create_special (fib_node_index_t pl_index, - fib_protocol_t nh_proto, + dpo_proto_t nh_proto, fib_path_cfg_flags_t flags, const dpo_id_t *dpo) { @@ -1433,7 +1427,7 @@ fib_path_cmp_w_route_path (fib_node_index_t path_index, res = (path->attached.fp_interface - rpath->frp_sw_if_index); break; case FIB_PATH_TYPE_RECURSIVE: - if (FIB_PROTOCOL_MPLS == path->fp_nh_proto) + if (DPO_PROTO_MPLS == path->fp_nh_proto) { res = path->recursive.fp_nh.fp_local_label - rpath->frp_local_label; @@ -1535,8 +1529,7 @@ fib_path_recursive_loop_detect (fib_node_index_t path_index, FIB_PATH_DBG(path, "recursive loop formed"); path->fp_oper_flags |= FIB_PATH_OPER_FLAG_RECURSIVE_LOOP; - dpo_copy(&path->fp_dpo, - drop_dpo_get(fib_proto_to_dpo(path->fp_nh_proto))); + dpo_copy(&path->fp_dpo, drop_dpo_get(path->fp_nh_proto)); } else { @@ -1590,8 +1583,7 @@ fib_path_resolve (fib_node_index_t path_index) */ if (fib_path_is_permanent_drop(path)) { - dpo_copy(&path->fp_dpo, - drop_dpo_get(fib_proto_to_dpo(path->fp_nh_proto))); + dpo_copy(&path->fp_dpo, drop_dpo_get(path->fp_nh_proto)); path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RESOLVED; return (fib_path_is_resolved(path_index)); } @@ -1612,9 +1604,9 @@ fib_path_resolve (fib_node_index_t path_index) } dpo_set(&path->fp_dpo, DPO_ADJACENCY, - fib_proto_to_dpo(path->fp_nh_proto), + path->fp_nh_proto, fib_path_attached_get_adj(path, - fib_proto_to_link(path->fp_nh_proto))); + dpo_proto_to_link(path->fp_nh_proto))); /* * become a child of the adjacency so we receive updates @@ -1639,7 +1631,7 @@ fib_path_resolve (fib_node_index_t path_index) ASSERT(FIB_NODE_INDEX_INVALID == path->fp_via_fib); - if (FIB_PROTOCOL_MPLS == path->fp_nh_proto) + if (DPO_PROTO_MPLS == path->fp_nh_proto) { fib_prefix_from_mpls_label(path->recursive.fp_nh.fp_local_label, path->recursive.fp_nh.fp_eos, @@ -1680,8 +1672,7 @@ fib_path_resolve (fib_node_index_t path_index) /* * Resolve via the drop */ - dpo_copy(&path->fp_dpo, - drop_dpo_get(fib_proto_to_dpo(path->fp_nh_proto))); + dpo_copy(&path->fp_dpo, drop_dpo_get(path->fp_nh_proto)); break; case FIB_PATH_TYPE_DEAG: { @@ -1696,7 +1687,7 @@ fib_path_resolve (fib_node_index_t path_index) LOOKUP_UNICAST); lookup_dpo_add_or_lock_w_fib_index(path->deag.fp_tbl_id, - fib_proto_to_dpo(path->fp_nh_proto), + path->fp_nh_proto, cast, LOOKUP_INPUT_DST_ADDR, LOOKUP_TABLE_FROM_CONFIG, @@ -1707,7 +1698,7 @@ fib_path_resolve (fib_node_index_t path_index) /* * Resolve via a receive DPO. */ - receive_dpo_add_or_lock(fib_proto_to_dpo(path->fp_nh_proto), + receive_dpo_add_or_lock(path->fp_nh_proto, path->receive.fp_interface, &path->receive.fp_addr, &path->fp_dpo); @@ -1716,7 +1707,7 @@ fib_path_resolve (fib_node_index_t path_index) /* * Resolve via a receive DPO. */ - interface_dpo_add_or_lock(fib_proto_to_dpo(path->fp_nh_proto), + interface_dpo_add_or_lock(path->fp_nh_proto, path->intf_rx.fp_interface, &path->fp_dpo); break; @@ -2035,7 +2026,7 @@ fib_path_contribute_forwarding (fib_node_index_t path_index, /* * Create the adj needed for sending IP multicast traffic */ - ai = adj_mcast_add_or_lock(path->fp_nh_proto, + ai = adj_mcast_add_or_lock(dpo_proto_to_fib(path->fp_nh_proto), fib_forw_chain_type_to_link_type(fct), path->attached.fp_interface); dpo_set(dpo, DPO_ADJACENCY, @@ -2187,7 +2178,7 @@ fib_path_encode (fib_node_index_t path_list_index, return (FIB_PATH_LIST_WALK_CONTINUE); } -fib_protocol_t +dpo_proto_t fib_path_get_proto (fib_node_index_t path_index) { fib_path_t *path; diff --git a/src/vnet/fib/fib_path.h b/src/vnet/fib/fib_path.h index a34cb43f..f986e437 100644 --- a/src/vnet/fib/fib_path.h +++ b/src/vnet/fib/fib_path.h @@ -78,6 +78,11 @@ typedef enum fib_path_cfg_attribute_t_ { * The path is an interface recieve */ FIB_PATH_CFG_ATTRIBUTE_LOCAL, + /** + * The path is L2. i.e. the parameters therein are to be interpreted as + * pertaining to L2 config. + */ + FIB_PATH_CFG_ATTRIBUTE_L2, /** * Marker. Add new types before this one, then update it. */ @@ -98,6 +103,7 @@ typedef enum fib_path_cfg_attribute_t_ { [FIB_PATH_CFG_ATTRIBUTE_ATTACHED] = "attached", \ [FIB_PATH_CFG_ATTRIBUTE_INTF_RX] = "interface-rx", \ [FIB_PATH_CFG_ATTRIBUTE_RPF_ID] = "rpf-id", \ + [FIB_PATH_CFG_ATTRIBUTE_L2] = "l2", \ } #define FOR_EACH_FIB_PATH_CFG_ATTRIBUTE(_item) \ @@ -118,6 +124,7 @@ typedef enum fib_path_cfg_flags_t_ { FIB_PATH_CFG_FLAG_ATTACHED = (1 << FIB_PATH_CFG_ATTRIBUTE_ATTACHED), FIB_PATH_CFG_FLAG_INTF_RX = (1 << FIB_PATH_CFG_ATTRIBUTE_INTF_RX), FIB_PATH_CFG_FLAG_RPF_ID = (1 << FIB_PATH_CFG_ATTRIBUTE_RPF_ID), + FIB_PATH_CFG_FLAG_L2 = (1 << FIB_PATH_CFG_ATTRIBUTE_L2), } __attribute__ ((packed)) fib_path_cfg_flags_t; @@ -131,7 +138,7 @@ extern u8 * format_fib_path(u8 * s, va_list * args); extern fib_node_index_t fib_path_create(fib_node_index_t pl_index, const fib_route_path_t *path); extern fib_node_index_t fib_path_create_special(fib_node_index_t pl_index, - fib_protocol_t nh_proto, + dpo_proto_t nh_proto, fib_path_cfg_flags_t flags, const dpo_id_t *dpo); @@ -148,7 +155,7 @@ extern int fib_path_is_recursive_constrained(fib_node_index_t path_index); extern int fib_path_is_exclusive(fib_node_index_t path_index); extern int fib_path_is_deag(fib_node_index_t path_index); extern int fib_path_is_looped(fib_node_index_t path_index); -extern fib_protocol_t fib_path_get_proto(fib_node_index_t path_index); +extern dpo_proto_t fib_path_get_proto(fib_node_index_t path_index); extern void fib_path_destroy(fib_node_index_t path_index); extern uword fib_path_hash(fib_node_index_t path_index); extern load_balance_path_t * fib_path_append_nh_for_multipath_hash( diff --git a/src/vnet/fib/fib_path_ext.c b/src/vnet/fib/fib_path_ext.c index 26f2b9b6..4438671b 100644 --- a/src/vnet/fib/fib_path_ext.c +++ b/src/vnet/fib/fib_path_ext.c @@ -191,6 +191,9 @@ fib_path_ext_stack (fib_path_ext_t *path_ext, case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS: parent_fct = child_fct; break; + case FIB_FORW_CHAIN_TYPE_ETHERNET: + parent_fct = FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS; + break; default: return (nhs); break; diff --git a/src/vnet/fib/fib_path_list.c b/src/vnet/fib/fib_path_list.c index 7a9c328c..f30fd7ea 100644 --- a/src/vnet/fib/fib_path_list.c +++ b/src/vnet/fib/fib_path_list.c @@ -611,7 +611,7 @@ fib_path_list_get_resolving_interface (fib_node_index_t path_list_index) return (sw_if_index); } -fib_protocol_t +dpo_proto_t fib_path_list_get_proto (fib_node_index_t path_list_index) { fib_path_list_t *path_list; @@ -753,7 +753,7 @@ fib_path_list_flags_2_path_flags (fib_path_list_flags_t plf) } fib_node_index_t -fib_path_list_create_special (fib_protocol_t nh_proto, +fib_path_list_create_special (dpo_proto_t nh_proto, fib_path_list_flags_t flags, const dpo_id_t *dpo) { diff --git a/src/vnet/fib/fib_path_list.h b/src/vnet/fib/fib_path_list.h index b4b6985b..a54b79e2 100644 --- a/src/vnet/fib/fib_path_list.h +++ b/src/vnet/fib/fib_path_list.h @@ -106,7 +106,7 @@ typedef enum fib_path_list_flags_t_ { extern fib_node_index_t fib_path_list_create(fib_path_list_flags_t flags, const fib_route_path_t *paths); -extern fib_node_index_t fib_path_list_create_special(fib_protocol_t nh_proto, +extern fib_node_index_t fib_path_list_create_special(dpo_proto_t nh_proto, fib_path_list_flags_t flags, const dpo_id_t *dpo); @@ -150,7 +150,7 @@ extern int fib_path_list_recursive_loop_detect(fib_node_index_t path_list_index, extern u32 fib_path_list_get_resolving_interface(fib_node_index_t path_list_index); extern int fib_path_list_is_looped(fib_node_index_t path_list_index); extern int fib_path_list_is_popular(fib_node_index_t path_list_index); -extern fib_protocol_t fib_path_list_get_proto(fib_node_index_t path_list_index); +extern dpo_proto_t fib_path_list_get_proto(fib_node_index_t path_list_index); extern u8 * fib_path_list_format(fib_node_index_t pl_index, u8 * s); extern index_t fib_path_list_lb_map_add_or_lock(fib_node_index_t pl_index, diff --git a/src/vnet/fib/fib_table.c b/src/vnet/fib/fib_table.c index 5aa02dd0..6b6cc5cb 100644 --- a/src/vnet/fib/fib_table.c +++ b/src/vnet/fib/fib_table.c @@ -505,7 +505,7 @@ fib_table_entry_path_add (u32 fib_index, const fib_prefix_t *prefix, fib_source_t source, fib_entry_flag_t flags, - fib_protocol_t next_hop_proto, + dpo_proto_t next_hop_proto, const ip46_address_t *next_hop, u32 next_hop_sw_if_index, u32 next_hop_fib_index, @@ -664,7 +664,7 @@ void fib_table_entry_path_remove (u32 fib_index, const fib_prefix_t *prefix, fib_source_t source, - fib_protocol_t next_hop_proto, + dpo_proto_t next_hop_proto, const ip46_address_t *next_hop, u32 next_hop_sw_if_index, u32 next_hop_fib_index, @@ -755,7 +755,7 @@ fib_table_entry_update_one_path (u32 fib_index, const fib_prefix_t *prefix, fib_source_t source, fib_entry_flag_t flags, - fib_protocol_t next_hop_proto, + dpo_proto_t next_hop_proto, const ip46_address_t *next_hop, u32 next_hop_sw_if_index, u32 next_hop_fib_index, diff --git a/src/vnet/fib/fib_table.h b/src/vnet/fib/fib_table.h index a65fea74..579740e9 100644 --- a/src/vnet/fib/fib_table.h +++ b/src/vnet/fib/fib_table.h @@ -288,7 +288,7 @@ extern fib_node_index_t fib_table_entry_path_add(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source, fib_entry_flag_t flags, - fib_protocol_t next_hop_proto, + dpo_proto_t next_hop_proto, const ip46_address_t *next_hop, u32 next_hop_sw_if_index, u32 next_hop_fib_index, @@ -364,7 +364,7 @@ extern fib_node_index_t fib_table_entry_path_add2(u32 fib_index, extern void fib_table_entry_path_remove(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source, - fib_protocol_t next_hop_proto, + dpo_proto_t next_hop_proto, const ip46_address_t *next_hop, u32 next_hop_sw_if_index, u32 next_hop_fib_index, @@ -471,7 +471,7 @@ extern fib_node_index_t fib_table_entry_update_one_path(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source, fib_entry_flag_t flags, - fib_protocol_t next_hop_proto, + dpo_proto_t next_hop_proto, const ip46_address_t *next_hop, u32 next_hop_sw_if_index, u32 next_hop_fib_index, diff --git a/src/vnet/fib/fib_test.c b/src/vnet/fib/fib_test.c index 4c891667..59d5da2a 100644 --- a/src/vnet/fib/fib_test.c +++ b/src/vnet/fib/fib_test.c @@ -833,7 +833,7 @@ fib_test_v4 (void) FIB_SOURCE_INTERFACE, (FIB_ENTRY_FLAG_CONNECTED | FIB_ENTRY_FLAG_ATTACHED), - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, NULL, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -861,7 +861,7 @@ fib_test_v4 (void) FIB_SOURCE_INTERFACE, (FIB_ENTRY_FLAG_CONNECTED | FIB_ENTRY_FLAG_LOCAL), - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, NULL, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -911,7 +911,7 @@ fib_test_v4 (void) fib_table_entry_path_add(fib_index, &pfx, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_1, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -963,7 +963,7 @@ fib_test_v4 (void) pfx.fp_len = 0; fib_table_entry_path_remove(fib_index, &pfx, FIB_SOURCE_API, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_1, tm->hw[0]->sw_if_index, ~0, // non-recursive path, so no FIB index @@ -1029,7 +1029,7 @@ fib_test_v4 (void) &pfx_11_11_11_11_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_ATTACHED, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_10_10_10_1_s_32.fp_addr, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -1095,7 +1095,7 @@ fib_test_v4 (void) &pfx_10_10_10_1_s_32, FIB_SOURCE_ADJ, FIB_ENTRY_FLAG_ATTACHED, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_10_10_10_1_s_32.fp_addr, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -1110,7 +1110,7 @@ fib_test_v4 (void) fib_table_entry_path_remove(fib_index, &pfx_11_11_11_11_s_32, FIB_SOURCE_API, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_10_10_10_1_s_32.fp_addr, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -1144,7 +1144,7 @@ fib_test_v4 (void) &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ, FIB_ENTRY_FLAG_ATTACHED, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_10_10_10_2_s_32.fp_addr, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -1181,7 +1181,7 @@ fib_test_v4 (void) &pfx_1_1_1_1_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_1, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -1214,7 +1214,7 @@ fib_test_v4 (void) &pfx_1_1_2_0_s_24, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_1, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -1241,7 +1241,7 @@ fib_test_v4 (void) &pfx_1_1_2_0_s_24, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_2, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -1280,7 +1280,7 @@ fib_test_v4 (void) fib_table_entry_path_remove(fib_index, &pfx_1_1_2_0_s_24, FIB_SOURCE_API, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_2, tm->hw[0]->sw_if_index, ~0, @@ -1327,7 +1327,7 @@ fib_test_v4 (void) &bgp_100_pfx, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_1_1_1_1, ~0, // no index provided. fib_index, // nexthop in same fib as route @@ -1363,7 +1363,7 @@ fib_test_v4 (void) &bgp_101_pfx, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_1_1_1_1, ~0, // no index provided. fib_index, // nexthop in same fib as route @@ -1487,7 +1487,7 @@ fib_test_v4 (void) &bgp_200_pfx, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_1_1_1_2_s_32.fp_addr, ~0, // no index provided. fib_index, // nexthop in same fib as route @@ -1534,7 +1534,7 @@ fib_test_v4 (void) &pfx_1_2_3_4_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_1, tm->hw[0]->sw_if_index, ~0, @@ -1545,7 +1545,7 @@ fib_test_v4 (void) &pfx_1_2_3_4_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_12_12_12_12, tm->hw[1]->sw_if_index, ~0, @@ -1586,7 +1586,7 @@ fib_test_v4 (void) &pfx_1_2_3_5_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_12_12_12_12, tm->hw[1]->sw_if_index, ~0, @@ -1597,7 +1597,7 @@ fib_test_v4 (void) &pfx_1_2_3_5_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_1, tm->hw[0]->sw_if_index, ~0, @@ -1669,7 +1669,7 @@ fib_test_v4 (void) &pfx_6_6_6_6_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_1, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -1688,7 +1688,7 @@ fib_test_v4 (void) &pfx_6_6_6_6_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_2, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -1770,7 +1770,7 @@ fib_test_v4 (void) &pfx_6_6_6_6_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_12_12_12_12, tm->hw[1]->sw_if_index, ~0, // invalid fib index @@ -1915,7 +1915,7 @@ fib_test_v4 (void) fib_table_entry_path_remove(fib_index, &pfx_6_6_6_6_s_32, FIB_SOURCE_API, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_12_12_12_12, tm->hw[1]->sw_if_index, ~0, // invalid fib index @@ -1995,7 +1995,7 @@ fib_test_v4 (void) fib_table_entry_path_remove(fib_index, &pfx_6_6_6_6_s_32, FIB_SOURCE_API, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_2, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -2026,7 +2026,7 @@ fib_test_v4 (void) &bgp_44_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_1_2_3_4_s_32.fp_addr, ~0, fib_index, @@ -2037,7 +2037,7 @@ fib_test_v4 (void) &bgp_44_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_1_2_3_5_s_32.fp_addr, ~0, fib_index, @@ -2107,7 +2107,7 @@ fib_test_v4 (void) &bgp_201_pfx, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_1_1_1_200_s_32.fp_addr, ~0, // no index provided. fib_index, // nexthop in same fib as route @@ -2151,7 +2151,7 @@ fib_test_v4 (void) &pfx_1_1_1_0_s_24, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_1, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -2209,7 +2209,7 @@ fib_test_v4 (void) &pfx_1_1_1_0_s_28, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_2, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -2244,7 +2244,7 @@ fib_test_v4 (void) fib_table_entry_path_remove(fib_index, &pfx_1_1_1_0_s_28, FIB_SOURCE_API, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_2, tm->hw[0]->sw_if_index, ~0, @@ -2275,7 +2275,7 @@ fib_test_v4 (void) fib_table_entry_path_remove(fib_index, &pfx_1_1_1_0_s_24, FIB_SOURCE_API, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_1, tm->hw[0]->sw_if_index, ~0, @@ -2316,7 +2316,7 @@ fib_test_v4 (void) &pfx_1_1_1_2_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_1, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -2351,7 +2351,7 @@ fib_test_v4 (void) &bgp_201_pfx, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_1_1_1_2_s_32.fp_addr, ~0, fib_index, @@ -2362,7 +2362,7 @@ fib_test_v4 (void) fib_table_entry_path_remove(fib_index, &bgp_201_pfx, FIB_SOURCE_API, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_1_1_1_2_s_32.fp_addr, ~0, fib_index, @@ -2375,7 +2375,7 @@ fib_test_v4 (void) fib_table_entry_path_remove(fib_index, &bgp_201_pfx, FIB_SOURCE_API, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_1_1_1_200_s_32.fp_addr, ~0, // no index provided. fib_index, @@ -2405,7 +2405,7 @@ fib_test_v4 (void) fib_table_entry_path_remove(fib_index, &bgp_200_pfx, FIB_SOURCE_API, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_1_1_1_2_s_32.fp_addr, ~0, // no index provided. fib_index, @@ -2446,7 +2446,7 @@ fib_test_v4 (void) &bgp_102, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_1_1_1_1_s_32.fp_addr, ~0, // no index provided. fib_index, // same as route @@ -2457,7 +2457,7 @@ fib_test_v4 (void) &bgp_102, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_1_1_1_2_s_32.fp_addr, ~0, // no index provided. fib_index, // same as route's FIB @@ -2483,7 +2483,7 @@ fib_test_v4 (void) fib_table_entry_path_remove(fib_index, &bgp_102, FIB_SOURCE_API, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_1_1_1_1_s_32.fp_addr, ~0, // no index provided. fib_index, // same as route's FIB @@ -2492,7 +2492,7 @@ fib_test_v4 (void) fib_table_entry_path_remove(fib_index, &bgp_102, FIB_SOURCE_API, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_1_1_1_2_s_32.fp_addr, ~0, // no index provided. fib_index, // same as route's FIB @@ -2507,7 +2507,7 @@ fib_test_v4 (void) fib_table_entry_path_remove(fib_index, &bgp_100_pfx, FIB_SOURCE_API, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_1_1_1_1_s_32.fp_addr, ~0, // no index provided. fib_index, // same as route's FIB @@ -2516,7 +2516,7 @@ fib_test_v4 (void) fib_table_entry_path_remove(fib_index, &bgp_101_pfx, FIB_SOURCE_API, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_1_1_1_1_s_32.fp_addr, ~0, // no index provided. fib_index, // same as route's FIB @@ -2546,7 +2546,7 @@ fib_test_v4 (void) &bgp_200_pfx, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_1, ~0, // no index provided. fib_index, // Same as route's FIB @@ -2593,7 +2593,7 @@ fib_test_v4 (void) &bgp_201_pfx, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_3, ~0, // no index provided. fib_index, @@ -2639,7 +2639,7 @@ fib_test_v4 (void) fib_table_entry_path_remove(fib_index, &bgp_200_pfx, FIB_SOURCE_API, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_1, ~0, // no index provided. fib_index, // same as route's FIB @@ -2648,7 +2648,7 @@ fib_test_v4 (void) fib_table_entry_path_remove(fib_index, &bgp_201_pfx, FIB_SOURCE_API, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_3, ~0, // no index provided. fib_index, // same as route's FIB @@ -2707,7 +2707,7 @@ fib_test_v4 (void) &pfx_5_5_5_5_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_5_5_5_6_s_32.fp_addr, ~0, // no index provided. fib_index, @@ -2718,7 +2718,7 @@ fib_test_v4 (void) &pfx_5_5_5_6_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_5_5_5_7_s_32.fp_addr, ~0, // no index provided. fib_index, @@ -2729,7 +2729,7 @@ fib_test_v4 (void) &pfx_5_5_5_7_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_5_5_5_5_s_32.fp_addr, ~0, // no index provided. fib_index, @@ -2768,7 +2768,7 @@ fib_test_v4 (void) &pfx_5_5_5_6_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_1, tm->hw[0]->sw_if_index, ~0, @@ -2801,7 +2801,7 @@ fib_test_v4 (void) fib_table_entry_path_remove(fib_index, &pfx_5_5_5_6_s_32, FIB_SOURCE_API, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_1, tm->hw[0]->sw_if_index, ~0, @@ -2826,7 +2826,7 @@ fib_test_v4 (void) &pfx_5_5_5_5_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_1, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -2868,7 +2868,7 @@ fib_test_v4 (void) &pfx_5_5_5_5_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_5_5_5_6_s_32.fp_addr, ~0, // no index provided. fib_index, @@ -2892,7 +2892,7 @@ fib_test_v4 (void) fib_table_entry_path_remove(fib_index, &pfx_5_5_5_5_s_32, FIB_SOURCE_API, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_5_5_5_6_s_32.fp_addr, ~0, // no index provided. fib_index, // same as route's FIB @@ -2901,7 +2901,7 @@ fib_test_v4 (void) fib_table_entry_path_remove(fib_index, &pfx_5_5_5_6_s_32, FIB_SOURCE_API, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_5_5_5_7_s_32.fp_addr, ~0, // no index provided. fib_index, // same as route's FIB @@ -2910,7 +2910,7 @@ fib_test_v4 (void) fib_table_entry_path_remove(fib_index, &pfx_5_5_5_7_s_32, FIB_SOURCE_API, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_5_5_5_5_s_32.fp_addr, ~0, // no index provided. fib_index, // same as route's FIB @@ -2919,7 +2919,7 @@ fib_test_v4 (void) fib_table_entry_path_remove(fib_index, &pfx_5_5_5_6_s_32, FIB_SOURCE_API, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_2, ~0, // no index provided. fib_index, // same as route's FIB @@ -2943,7 +2943,7 @@ fib_test_v4 (void) &pfx_5_5_5_6_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_5_5_5_6_s_32.fp_addr, ~0, // no index provided. fib_index, @@ -2957,7 +2957,7 @@ fib_test_v4 (void) fib_table_entry_path_remove(fib_index, &pfx_5_5_5_6_s_32, FIB_SOURCE_API, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_5_5_5_6_s_32.fp_addr, ~0, // no index provided. fib_index, // same as route's FIB @@ -2991,7 +2991,7 @@ fib_test_v4 (void) &pfx_23_23_23_0_s_24, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_23_23_23_23_s_32.fp_addr, ~0, // recursive fib_index, @@ -3021,7 +3021,7 @@ fib_test_v4 (void) &pfx_0_0_0_0_s_0, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_23_23_23_23_s_32.fp_addr, ~0, // recursive fib_index, @@ -3051,7 +3051,7 @@ fib_test_v4 (void) &bgp_200_pfx, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_1_1_1_1, ~0, fib_index, @@ -3081,7 +3081,7 @@ fib_test_v4 (void) &pfx_1_1_1_0_s_28, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_1, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -3099,7 +3099,7 @@ fib_test_v4 (void) fib_table_entry_path_remove(fib_index, &pfx_1_1_1_1_s_32, FIB_SOURCE_API, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_1, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -3116,7 +3116,7 @@ fib_test_v4 (void) &pfx_1_1_1_1_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_1, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -3140,7 +3140,7 @@ fib_test_v4 (void) &pfx_1_1_1_3_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_2, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -3152,7 +3152,7 @@ fib_test_v4 (void) &bgp_200_pfx, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_1_1_1_3_s_32.fp_addr, ~0, fib_index, @@ -3177,7 +3177,7 @@ fib_test_v4 (void) &bgp_78s[ii], FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_1_1_1_3_s_32.fp_addr, ~0, fib_index, @@ -3188,7 +3188,7 @@ fib_test_v4 (void) &bgp_78s[ii], FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_1_1_1_1, ~0, fib_index, @@ -3238,7 +3238,7 @@ fib_test_v4 (void) fib_table_entry_path_remove(fib_index, &pfx_1_1_1_1_s_32, FIB_SOURCE_API, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_1, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -3277,7 +3277,7 @@ fib_test_v4 (void) &pfx_1_1_1_1_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_1, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -3307,7 +3307,7 @@ fib_test_v4 (void) &bgp_200_pfx, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_1_1_1_2_s_32.fp_addr, ~0, fib_index, @@ -3320,7 +3320,7 @@ fib_test_v4 (void) &bgp_78s[ii], FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_1_1_1_2_s_32.fp_addr, ~0, fib_index, @@ -3354,7 +3354,7 @@ fib_test_v4 (void) fib_table_entry_path_remove(fib_index, &pfx_1_1_1_1_s_32, FIB_SOURCE_API, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_1, tm->hw[0]->sw_if_index, ~0, @@ -3391,7 +3391,7 @@ fib_test_v4 (void) &pfx_1_1_1_1_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_1, tm->hw[0]->sw_if_index, ~0, @@ -3412,7 +3412,7 @@ fib_test_v4 (void) fib_table_entry_path_remove(fib_index, &bgp_200_pfx, FIB_SOURCE_API, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_1_1_1_2_s_32.fp_addr, ~0, fib_index, @@ -3421,7 +3421,7 @@ fib_test_v4 (void) fib_table_entry_path_remove(fib_index, &bgp_200_pfx, FIB_SOURCE_API, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_1_1_1_1, ~0, fib_index, @@ -3430,7 +3430,7 @@ fib_test_v4 (void) fib_table_entry_path_remove(fib_index, &bgp_200_pfx, FIB_SOURCE_API, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_1_1_1_3_s_32.fp_addr, ~0, fib_index, @@ -3481,7 +3481,7 @@ fib_test_v4 (void) &pfx_4_4_4_4_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_1, tm->hw[0]->sw_if_index, ~0, @@ -3492,7 +3492,7 @@ fib_test_v4 (void) &pfx_4_4_4_4_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_2, tm->hw[0]->sw_if_index, ~0, @@ -3503,7 +3503,7 @@ fib_test_v4 (void) &pfx_4_4_4_4_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_3, tm->hw[0]->sw_if_index, ~0, @@ -3539,7 +3539,7 @@ fib_test_v4 (void) for (ii = 0; ii < 4; ii++) { fib_route_path_t r_path = { - .frp_proto = FIB_PROTOCOL_IP4, + .frp_proto = DPO_PROTO_IP4, .frp_addr = { .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02 + ii), }, @@ -3588,7 +3588,7 @@ fib_test_v4 (void) &pfx_4_4_4_4_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &zero_addr, ~0, fib_index, @@ -3648,7 +3648,7 @@ fib_test_v4 (void) &pfx_34_34_1_1_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_1, tm->hw[0]->sw_if_index, 0, @@ -3659,7 +3659,7 @@ fib_test_v4 (void) &pfx_34_1_1_1_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_34_34_1_1_s_32.fp_addr, ~0, fib_index, @@ -3670,7 +3670,7 @@ fib_test_v4 (void) &pfx_34_1_1_1_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_34_34_1_1_s_32.fp_addr, ~0, fib_index, @@ -3691,7 +3691,7 @@ fib_test_v4 (void) fib_table_entry_path_remove(fib_index, &pfx_1_1_1_2_s_32, FIB_SOURCE_API, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_1, tm->hw[0]->sw_if_index, ~0, @@ -3700,7 +3700,7 @@ fib_test_v4 (void) fib_table_entry_path_remove(fib_index, &pfx_1_1_1_1_s_32, FIB_SOURCE_API, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_1, tm->hw[0]->sw_if_index, ~0, @@ -3709,7 +3709,7 @@ fib_test_v4 (void) fib_table_entry_path_remove(fib_index, &pfx_1_1_2_0_s_24, FIB_SOURCE_API, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_1, tm->hw[0]->sw_if_index, ~0, @@ -3751,7 +3751,7 @@ fib_test_v4 (void) &pfx_4_1_1_1_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &zero_addr, tm->hw[0]->sw_if_index, fib_index, @@ -3805,7 +3805,7 @@ fib_test_v4 (void) &pfx_2001_s_64, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_1, tm->hw[0]->sw_if_index, fib_index, @@ -3863,7 +3863,7 @@ fib_test_v4 (void) &pfx_12_10_10_2_s_32, FIB_SOURCE_ADJ, FIB_ENTRY_FLAG_ATTACHED, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_12_10_10_2_s_32.fp_addr, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -3897,7 +3897,7 @@ fib_test_v4 (void) &pfx_10_10_10_127_s_32, FIB_SOURCE_ADJ, FIB_ENTRY_FLAG_ATTACHED, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_10_10_10_127_s_32.fp_addr, tm->hw[1]->sw_if_index, ~0, // invalid fib index @@ -3945,7 +3945,7 @@ fib_test_v4 (void) &pfx_10_10_10_3_s_32, FIB_SOURCE_ADJ, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_3, tm->hw[0]->sw_if_index, fib_index, @@ -3956,7 +3956,7 @@ fib_test_v4 (void) &pfx_10_10_10_3_s_32, FIB_SOURCE_ADJ, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_12_12_12_12, tm->hw[1]->sw_if_index, fib_index, @@ -3975,7 +3975,7 @@ fib_test_v4 (void) fib_table_entry_path_remove(fib_index, &pfx_10_10_10_3_s_32, FIB_SOURCE_ADJ, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_3, tm->hw[0]->sw_if_index, fib_index, @@ -3992,7 +3992,7 @@ fib_test_v4 (void) &pfx_10_10_10_3_s_32, FIB_SOURCE_ADJ, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_3, tm->hw[0]->sw_if_index, fib_index, @@ -4011,7 +4011,7 @@ fib_test_v4 (void) fib_table_entry_path_remove(fib_index, &pfx_10_10_10_3_s_32, FIB_SOURCE_ADJ, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_12_12_12_12, tm->hw[1]->sw_if_index, fib_index, @@ -4030,7 +4030,7 @@ fib_test_v4 (void) fib_table_entry_path_remove(fib_index, &pfx_10_10_10_3_s_32, FIB_SOURCE_ADJ, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_3, tm->hw[0]->sw_if_index, fib_index, @@ -4269,7 +4269,7 @@ fib_test_v6 (void) FIB_SOURCE_INTERFACE, (FIB_ENTRY_FLAG_CONNECTED | FIB_ENTRY_FLAG_ATTACHED), - FIB_PROTOCOL_IP6, + DPO_PROTO_IP6, NULL, tm->hw[0]->sw_if_index, ~0, @@ -4300,7 +4300,7 @@ fib_test_v6 (void) FIB_SOURCE_INTERFACE, (FIB_ENTRY_FLAG_CONNECTED | FIB_ENTRY_FLAG_LOCAL), - FIB_PROTOCOL_IP6, + DPO_PROTO_IP6, NULL, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -4345,7 +4345,7 @@ fib_test_v6 (void) fib_table_entry_path_add(fib_index, &pfx_0_0, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP6, + DPO_PROTO_IP6, &nh_2001_2, tm->hw[0]->sw_if_index, ~0, @@ -4389,7 +4389,7 @@ fib_test_v6 (void) */ fib_table_entry_path_remove(fib_index, &pfx_0_0, FIB_SOURCE_API, - FIB_PROTOCOL_IP6, + DPO_PROTO_IP6, &nh_2001_2, tm->hw[0]->sw_if_index, ~0, @@ -4466,7 +4466,7 @@ fib_test_v6 (void) &pfx_2001_1_2_s_128, FIB_SOURCE_ADJ, FIB_ENTRY_FLAG_ATTACHED, - FIB_PROTOCOL_IP6, + DPO_PROTO_IP6, &pfx_2001_1_2_s_128.fp_addr, tm->hw[0]->sw_if_index, ~0, @@ -4505,7 +4505,7 @@ fib_test_v6 (void) &pfx_2001_1_3_s_128, FIB_SOURCE_ADJ, FIB_ENTRY_FLAG_ATTACHED, - FIB_PROTOCOL_IP6, + DPO_PROTO_IP6, &pfx_2001_1_3_s_128.fp_addr, tm->hw[0]->sw_if_index, ~0, @@ -4559,7 +4559,7 @@ fib_test_v6 (void) &pfx_2001_a_s_64, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP6, + DPO_PROTO_IP6, &nh_2001_2, tm->hw[0]->sw_if_index, ~0, @@ -4573,7 +4573,7 @@ fib_test_v6 (void) &pfx_2001_b_s_64, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP6, + DPO_PROTO_IP6, &nh_2001_2, tm->hw[0]->sw_if_index, ~0, @@ -4608,7 +4608,7 @@ fib_test_v6 (void) &pfx_1_1_1_1_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP6, + DPO_PROTO_IP6, &nh_2001_2, tm->hw[0]->sw_if_index, ~0, @@ -4646,7 +4646,7 @@ fib_test_v6 (void) &pfx_2001_c_s_64, FIB_SOURCE_CLI, FIB_ENTRY_FLAG_ATTACHED, - FIB_PROTOCOL_IP6, + DPO_PROTO_IP6, NULL, tm->hw[0]->sw_if_index, ~0, @@ -4663,7 +4663,7 @@ fib_test_v6 (void) fib_table_entry_path_remove(fib_index, &pfx_2001_c_s_64, FIB_SOURCE_CLI, - FIB_PROTOCOL_IP6, + DPO_PROTO_IP6, NULL, tm->hw[0]->sw_if_index, ~0, @@ -4748,7 +4748,7 @@ fib_test_v6 (void) FIB_SOURCE_INTERFACE, (FIB_ENTRY_FLAG_CONNECTED | FIB_ENTRY_FLAG_ATTACHED), - FIB_PROTOCOL_IP6, + DPO_PROTO_IP6, NULL, tm->hw[1]->sw_if_index, ~0, @@ -4767,7 +4767,7 @@ fib_test_v6 (void) FIB_SOURCE_INTERFACE, (FIB_ENTRY_FLAG_CONNECTED | FIB_ENTRY_FLAG_LOCAL), - FIB_PROTOCOL_IP6, + DPO_PROTO_IP6, NULL, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -5095,7 +5095,7 @@ fib_test_ae (void) FIB_SOURCE_INTERFACE, (FIB_ENTRY_FLAG_CONNECTED | FIB_ENTRY_FLAG_ATTACHED), - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, NULL, tm->hw[0]->sw_if_index, ~0, @@ -5111,7 +5111,7 @@ fib_test_ae (void) FIB_SOURCE_INTERFACE, (FIB_ENTRY_FLAG_CONNECTED | FIB_ENTRY_FLAG_LOCAL), - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, NULL, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -5140,7 +5140,7 @@ fib_test_ae (void) &pfx_10_10_10_1_s_32, FIB_SOURCE_ADJ, FIB_ENTRY_FLAG_ATTACHED, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_10_10_10_1_s_32.fp_addr, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -5167,7 +5167,7 @@ fib_test_ae (void) &local_pfx, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, NULL, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -5209,7 +5209,7 @@ fib_test_ae (void) &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ, FIB_ENTRY_FLAG_ATTACHED, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_10_10_10_2_s_32.fp_addr, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -5243,7 +5243,7 @@ fib_test_ae (void) &local_pfx, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, NULL, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -5280,7 +5280,7 @@ fib_test_ae (void) &pfx_10_10_10_3_s_32, FIB_SOURCE_ADJ, FIB_ENTRY_FLAG_ATTACHED, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_10_10_10_3_s_32.fp_addr, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -5352,7 +5352,7 @@ fib_test_ae (void) &local_pfx, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_10_10_10_2_s_32.fp_addr, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -5375,7 +5375,7 @@ fib_test_ae (void) &local_pfx, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, NULL, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -5407,7 +5407,7 @@ fib_test_ae (void) &pfx_10_0_0_0_s_8, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_10_10_10_3_s_32.fp_addr, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -5463,7 +5463,7 @@ fib_test_ae (void) &local_pfx, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_10_10_10_1_s_32.fp_addr, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -5499,7 +5499,7 @@ fib_test_ae (void) &local_pfx, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, NULL, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -5538,7 +5538,7 @@ fib_test_ae (void) FIB_SOURCE_INTERFACE, (FIB_ENTRY_FLAG_CONNECTED | FIB_ENTRY_FLAG_ATTACHED), - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, NULL, tm->hw[0]->sw_if_index, ~0, @@ -5626,7 +5626,7 @@ fib_test_pref (void) * 2 high, 2 medium and 2 low preference non-recursive paths */ fib_route_path_t nr_path_hi_1 = { - .frp_proto = FIB_PROTOCOL_IP4, + .frp_proto = DPO_PROTO_IP4, .frp_sw_if_index = tm->hw[0]->sw_if_index, .frp_fib_index = ~0, .frp_weight = 1, @@ -5637,7 +5637,7 @@ fib_test_pref (void) }, }; fib_route_path_t nr_path_hi_2 = { - .frp_proto = FIB_PROTOCOL_IP4, + .frp_proto = DPO_PROTO_IP4, .frp_sw_if_index = tm->hw[0]->sw_if_index, .frp_fib_index = ~0, .frp_weight = 1, @@ -5648,7 +5648,7 @@ fib_test_pref (void) }, }; fib_route_path_t nr_path_med_1 = { - .frp_proto = FIB_PROTOCOL_IP4, + .frp_proto = DPO_PROTO_IP4, .frp_sw_if_index = tm->hw[1]->sw_if_index, .frp_fib_index = ~0, .frp_weight = 1, @@ -5659,7 +5659,7 @@ fib_test_pref (void) }, }; fib_route_path_t nr_path_med_2 = { - .frp_proto = FIB_PROTOCOL_IP4, + .frp_proto = DPO_PROTO_IP4, .frp_sw_if_index = tm->hw[1]->sw_if_index, .frp_fib_index = ~0, .frp_weight = 1, @@ -5670,7 +5670,7 @@ fib_test_pref (void) }, }; fib_route_path_t nr_path_low_1 = { - .frp_proto = FIB_PROTOCOL_IP4, + .frp_proto = DPO_PROTO_IP4, .frp_sw_if_index = tm->hw[2]->sw_if_index, .frp_fib_index = ~0, .frp_weight = 1, @@ -5681,7 +5681,7 @@ fib_test_pref (void) }, }; fib_route_path_t nr_path_low_2 = { - .frp_proto = FIB_PROTOCOL_IP4, + .frp_proto = DPO_PROTO_IP4, .frp_sw_if_index = tm->hw[2]->sw_if_index, .frp_fib_index = ~0, .frp_weight = 1, @@ -5897,7 +5897,7 @@ fib_test_pref (void) }, }; fib_route_path_t r_path_hi = { - .frp_proto = FIB_PROTOCOL_IP4, + .frp_proto = DPO_PROTO_IP4, .frp_sw_if_index = ~0, .frp_fib_index = 0, .frp_weight = 1, @@ -5906,7 +5906,7 @@ fib_test_pref (void) .frp_addr = pfx_1_1_1_1_s_32.fp_addr, }; fib_route_path_t r_path_med = { - .frp_proto = FIB_PROTOCOL_IP4, + .frp_proto = DPO_PROTO_IP4, .frp_sw_if_index = ~0, .frp_fib_index = 0, .frp_weight = 1, @@ -5915,7 +5915,7 @@ fib_test_pref (void) .frp_addr = pfx_1_1_1_2_s_32.fp_addr, }; fib_route_path_t r_path_low = { - .frp_proto = FIB_PROTOCOL_IP4, + .frp_proto = DPO_PROTO_IP4, .frp_sw_if_index = ~0, .frp_fib_index = 0, .frp_weight = 1, @@ -6099,7 +6099,7 @@ fib_test_label (void) FIB_SOURCE_INTERFACE, (FIB_ENTRY_FLAG_CONNECTED | FIB_ENTRY_FLAG_ATTACHED), - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, NULL, tm->hw[0]->sw_if_index, ~0, @@ -6115,7 +6115,7 @@ fib_test_label (void) FIB_SOURCE_INTERFACE, (FIB_ENTRY_FLAG_CONNECTED | FIB_ENTRY_FLAG_LOCAL), - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, NULL, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -6145,7 +6145,7 @@ fib_test_label (void) FIB_SOURCE_INTERFACE, (FIB_ENTRY_FLAG_CONNECTED | FIB_ENTRY_FLAG_ATTACHED), - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, NULL, tm->hw[1]->sw_if_index, ~0, @@ -6161,7 +6161,7 @@ fib_test_label (void) FIB_SOURCE_INTERFACE, (FIB_ENTRY_FLAG_CONNECTED | FIB_ENTRY_FLAG_LOCAL), - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, NULL, tm->hw[1]->sw_if_index, ~0, // invalid fib index @@ -6243,7 +6243,7 @@ fib_test_label (void) &pfx_1_1_1_1_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_1, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -6282,7 +6282,7 @@ fib_test_label (void) &pfx_1_1_1_1_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_11_1, tm->hw[1]->sw_if_index, ~0, // invalid fib index @@ -6360,7 +6360,7 @@ fib_test_label (void) &pfx_1_1_1_1_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_11_2, tm->hw[1]->sw_if_index, ~0, // invalid fib index @@ -6440,7 +6440,7 @@ fib_test_label (void) &pfx_2_2_2_2_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_1_1_1_1_s_32.fp_addr, ~0, fib_index, @@ -6612,7 +6612,7 @@ fib_test_label (void) fib_table_entry_path_remove(fib_index, &pfx_1_1_1_1_s_32, FIB_SOURCE_API, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_1, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -6669,7 +6669,7 @@ fib_test_label (void) fib_table_entry_path_remove(fib_index, &pfx_1_1_1_1_s_32, FIB_SOURCE_API, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_11_1, tm->hw[1]->sw_if_index, ~0, // invalid fib index @@ -6711,7 +6711,7 @@ fib_test_label (void) &pfx_1_1_1_1_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_1, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -6842,7 +6842,7 @@ fib_test_label (void) &pfx_1_1_1_2_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_1, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -6884,7 +6884,7 @@ fib_test_label (void) &pfx_2_2_2_2_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_1_1_1_2_s_32.fp_addr, ~0, fib_index, @@ -6912,7 +6912,7 @@ fib_test_label (void) &pfx_1_1_1_2_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_11_1, tm->hw[1]->sw_if_index, ~0, // invalid fib index @@ -6945,7 +6945,7 @@ fib_test_label (void) &pfx_1_1_1_2_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_11_1, tm->hw[1]->sw_if_index, ~0, // invalid fib index @@ -6987,7 +6987,7 @@ fib_test_label (void) &pfx_2_2_2_3_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_1_1_1_1_s_32.fp_addr, ~0, fib_index, @@ -7031,7 +7031,7 @@ fib_test_label (void) &pfx_2_2_2_4_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx_1_1_1_1_s_32.fp_addr, ~0, fib_index, @@ -7081,7 +7081,7 @@ fib_test_label (void) &pfx_2_2_5_5_s_32, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_11_1, tm->hw[1]->sw_if_index, ~0, // invalid fib index @@ -7689,7 +7689,7 @@ fib_test_bfd (void) FIB_SOURCE_INTERFACE, (FIB_ENTRY_FLAG_CONNECTED | FIB_ENTRY_FLAG_ATTACHED), - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, NULL, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -7706,7 +7706,7 @@ fib_test_bfd (void) FIB_SOURCE_INTERFACE, (FIB_ENTRY_FLAG_CONNECTED | FIB_ENTRY_FLAG_LOCAL), - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, NULL, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -7780,7 +7780,7 @@ fib_test_bfd (void) &pfx_10_10_10_1_s_32, FIB_SOURCE_ADJ, FIB_ENTRY_FLAG_ATTACHED, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_1, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -7819,7 +7819,7 @@ fib_test_bfd (void) &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ, FIB_ENTRY_FLAG_ATTACHED, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_2, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -7851,7 +7851,7 @@ fib_test_bfd (void) &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ, FIB_ENTRY_FLAG_ATTACHED, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_2, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -7907,7 +7907,7 @@ fib_test_bfd (void) &pfx_200_0_0_0_s_24, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_2, ~0, // recursive 0, // default fib index @@ -7926,7 +7926,7 @@ fib_test_bfd (void) &pfx_200_0_0_0_s_24, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_1, ~0, // recursive 0, // default fib index @@ -8065,7 +8065,7 @@ fib_test_bfd (void) &pfx_5_5_5_5_s_32, FIB_SOURCE_CLI, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_1, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -8096,7 +8096,7 @@ fib_test_bfd (void) &pfx_5_5_5_5_s_32, FIB_SOURCE_CLI, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_2, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -8234,7 +8234,7 @@ lfib_test (void) &pfx, FIB_SOURCE_CLI, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &zero_addr, ~0, fib_index, @@ -8285,7 +8285,7 @@ lfib_test (void) &pfx, FIB_SOURCE_CLI, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &zero_addr, ~0, lfib_index, @@ -8363,7 +8363,7 @@ lfib_test (void) &pfx_1200, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_1, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -8389,7 +8389,7 @@ lfib_test (void) }, }; fib_route_path_t *rpaths = NULL, rpath = { - .frp_proto = FIB_PROTOCOL_MPLS, + .frp_proto = DPO_PROTO_MPLS, .frp_local_label = 1200, .frp_eos = MPLS_NON_EOS, .frp_sw_if_index = ~0, // recurive @@ -8545,7 +8545,7 @@ lfib_test (void) &pfx_2500, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, NULL, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -8590,7 +8590,7 @@ lfib_test (void) &pfx_3500, FIB_SOURCE_API, FIB_ENTRY_FLAG_MULTICAST, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_1, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -8610,7 +8610,7 @@ lfib_test (void) &pfx_3500, FIB_SOURCE_API, FIB_ENTRY_FLAG_MULTICAST, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, NULL, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -8637,7 +8637,7 @@ lfib_test (void) &pfx_3500, FIB_SOURCE_API, FIB_ENTRY_FLAG_MULTICAST, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, NULL, 5, // rpf-id 0, // default table diff --git a/src/vnet/fib/fib_types.h b/src/vnet/fib/fib_types.h index a209ff3c..f11a55da 100644 --- a/src/vnet/fib/fib_types.h +++ b/src/vnet/fib/fib_types.h @@ -32,9 +32,9 @@ typedef u32 fib_node_index_t; * Protocol Type. packed so it consumes a u8 only */ typedef enum fib_protocol_t_ { - FIB_PROTOCOL_IP4 = 0, - FIB_PROTOCOL_IP6, - FIB_PROTOCOL_MPLS, + FIB_PROTOCOL_IP4 = DPO_PROTO_IP4, + FIB_PROTOCOL_IP6 = DPO_PROTO_IP6, + FIB_PROTOCOL_MPLS = DPO_PROTO_MPLS, } __attribute__ ((packed)) fib_protocol_t; #define FIB_PROTOCOLS { \ @@ -338,7 +338,7 @@ typedef struct fib_route_path_t_ { * The protocol of the address below. We need this since the all * zeros address is ambiguous. */ - fib_protocol_t frp_proto; + dpo_proto_t frp_proto; union { /** diff --git a/src/vnet/interface_format.c b/src/vnet/interface_format.c index df7e9388..5694bb2f 100644 --- a/src/vnet/interface_format.c +++ b/src/vnet/interface_format.c @@ -165,9 +165,15 @@ format_vnet_sw_if_index_name (u8 * s, va_list * args) { vnet_main_t *vnm = va_arg (*args, vnet_main_t *); u32 sw_if_index = va_arg (*args, u32); - return format (s, "%U", - format_vnet_sw_interface_name, vnm, - vnet_get_sw_interface (vnm, sw_if_index)); + vnet_sw_interface_t *si; + + si = vnet_get_sw_interface_safe (vnm, sw_if_index); + + if (NULL == si) + { + return format (s, "DELETED"); + } + return format (s, "%U", format_vnet_sw_interface_name, vnm, si); } u8 * diff --git a/src/vnet/ip/ip4_forward.c b/src/vnet/ip/ip4_forward.c index ee17ea88..7a8d7a0c 100755 --- a/src/vnet/ip/ip4_forward.c +++ b/src/vnet/ip/ip4_forward.c @@ -724,7 +724,7 @@ ip4_add_interface_routes (u32 sw_if_index, FIB_SOURCE_INTERFACE, (FIB_ENTRY_FLAG_CONNECTED | FIB_ENTRY_FLAG_ATTACHED), - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, /* No next-hop address */ NULL, sw_if_index, @@ -767,7 +767,7 @@ ip4_add_interface_routes (u32 sw_if_index, fib_table_entry_update_one_path (fib_index, &net_pfx, FIB_SOURCE_INTERFACE, (FIB_ENTRY_FLAG_ATTACHED), - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &net_pfx.fp_addr, sw_if_index, // invalid FIB index @@ -803,7 +803,7 @@ ip4_add_interface_routes (u32 sw_if_index, FIB_SOURCE_INTERFACE, (FIB_ENTRY_FLAG_CONNECTED | FIB_ENTRY_FLAG_LOCAL), - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &pfx.fp_addr, sw_if_index, // invalid FIB index diff --git a/src/vnet/ip/ip6_forward.c b/src/vnet/ip/ip6_forward.c index bc66416e..8ae08a01 100644 --- a/src/vnet/ip/ip6_forward.c +++ b/src/vnet/ip/ip6_forward.c @@ -355,7 +355,7 @@ ip6_add_interface_routes (vnet_main_t * vnm, u32 sw_if_index, FIB_SOURCE_INTERFACE, (FIB_ENTRY_FLAG_CONNECTED | FIB_ENTRY_FLAG_ATTACHED), - FIB_PROTOCOL_IP6, + DPO_PROTO_IP6, /* No next-hop address */ NULL, sw_if_index, /* invalid FIB index */ @@ -390,7 +390,7 @@ ip6_add_interface_routes (vnet_main_t * vnm, u32 sw_if_index, FIB_SOURCE_INTERFACE, (FIB_ENTRY_FLAG_CONNECTED | FIB_ENTRY_FLAG_LOCAL), - FIB_PROTOCOL_IP6, + DPO_PROTO_IP6, &pfx.fp_addr, sw_if_index, ~0, 1, NULL, FIB_ROUTE_PATH_FLAG_NONE); diff --git a/src/vnet/ip/ip6_neighbor.c b/src/vnet/ip/ip6_neighbor.c index e8eebd4e..6a9139ab 100644 --- a/src/vnet/ip/ip6_neighbor.c +++ b/src/vnet/ip/ip6_neighbor.c @@ -284,7 +284,7 @@ ip6_neighbor_sw_interface_up_down (vnet_main_t * vnm, (ip6_fib_table_get_index_for_sw_if_index (n->key.sw_if_index), &pfx, FIB_SOURCE_ADJ, - FIB_PROTOCOL_IP6, + DPO_PROTO_IP6, &pfx.fp_addr, n->key.sw_if_index, ~0, 1, FIB_ROUTE_PATH_FLAG_NONE); pool_put (nm->neighbor_pool, n); @@ -645,7 +645,7 @@ vnet_set_ip6_ethernet_neighbor (vlib_main_t * vm, n->fib_entry_index = fib_table_entry_path_add (fib_index, &pfx, FIB_SOURCE_ADJ, FIB_ENTRY_FLAG_ATTACHED, - FIB_PROTOCOL_IP6, &pfx.fp_addr, + DPO_PROTO_IP6, &pfx.fp_addr, n->key.sw_if_index, ~0, 1, NULL, FIB_ROUTE_PATH_FLAG_NONE); } @@ -776,7 +776,7 @@ vnet_unset_ip6_ethernet_neighbor (vlib_main_t * vm, (ip6_fib_table_get_index_for_sw_if_index (n->key.sw_if_index), &pfx, FIB_SOURCE_ADJ, - FIB_PROTOCOL_IP6, + DPO_PROTO_IP6, &pfx.fp_addr, n->key.sw_if_index, ~0, 1, FIB_ROUTE_PATH_FLAG_NONE); } pool_put (nm->neighbor_pool, n); @@ -4110,7 +4110,7 @@ ip6_neighbor_proxy_add_del (u32 sw_if_index, ip6_address_t * addr, u8 is_del) fib_table_entry_path_remove (fib_index, &pfx, FIB_SOURCE_IP6_ND_PROXY, - FIB_PROTOCOL_IP6, + DPO_PROTO_IP6, &nh, sw_if_index, ~0, 1, FIB_ROUTE_PATH_FLAG_NONE); @@ -4124,7 +4124,7 @@ ip6_neighbor_proxy_add_del (u32 sw_if_index, ip6_address_t * addr, u8 is_del) &pfx, FIB_SOURCE_IP6_ND_PROXY, FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP6, + DPO_PROTO_IP6, &nh, sw_if_index, ~0, 1, NULL, FIB_ROUTE_PATH_FLAG_NONE); diff --git a/src/vnet/ip/ip_api.c b/src/vnet/ip/ip_api.c index 4cbf75a3..0676a387 100644 --- a/src/vnet/ip/ip_api.c +++ b/src/vnet/ip/ip_api.c @@ -156,9 +156,9 @@ copy_fib_next_hop (fib_route_path_encode_t * api_rpath, void *fp_arg) int is_ip4; vl_api_fib_path_t *fp = (vl_api_fib_path_t *) fp_arg; - if (api_rpath->rpath.frp_proto == FIB_PROTOCOL_IP4) + if (api_rpath->rpath.frp_proto == DPO_PROTO_IP4) fp->afi = IP46_TYPE_IP4; - else if (api_rpath->rpath.frp_proto == FIB_PROTOCOL_IP6) + else if (api_rpath->rpath.frp_proto == DPO_PROTO_IP6) fp->afi = IP46_TYPE_IP6; else { @@ -714,7 +714,7 @@ add_del_route_t_handler (u8 is_multipath, u8 is_rpf_id, u32 fib_index, const fib_prefix_t * prefix, - u8 next_hop_proto_is_ip4, + dpo_proto_t next_hop_proto, const ip46_address_t * next_hop, u32 next_hop_sw_if_index, u8 next_hop_fib_index, @@ -726,8 +726,7 @@ add_del_route_t_handler (u8 is_multipath, vnet_classify_main_t *cm = &vnet_classify_main; fib_route_path_flags_t path_flags = FIB_ROUTE_PATH_FLAG_NONE; fib_route_path_t path = { - .frp_proto = (next_hop_proto_is_ip4 ? - FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6), + .frp_proto = next_hop_proto, .frp_addr = (NULL == next_hop ? zero_addr : *next_hop), .frp_sw_if_index = next_hop_sw_if_index, .frp_fib_index = next_hop_fib_index, @@ -740,7 +739,7 @@ add_del_route_t_handler (u8 is_multipath, if (MPLS_LABEL_INVALID != next_hop_via_label) { - path.frp_proto = FIB_PROTOCOL_MPLS; + path.frp_proto = DPO_PROTO_MPLS; path.frp_local_label = next_hop_via_label; path.frp_eos = MPLS_NON_EOS; } @@ -855,7 +854,7 @@ int add_del_route_check (fib_protocol_t table_proto, u32 table_id, u32 next_hop_sw_if_index, - fib_protocol_t next_hop_table_proto, + dpo_proto_t next_hop_table_proto, u32 next_hop_table_id, u8 create_missing_tables, u8 is_rpf_id, u32 * fib_index, u32 * next_hop_fib_index) @@ -887,11 +886,18 @@ add_del_route_check (fib_protocol_t table_proto, } else { + fib_protocol_t fib_nh_proto; + + if (next_hop_table_proto > DPO_PROTO_MPLS) + return (0); + + fib_nh_proto = dpo_proto_to_fib (next_hop_table_proto); + if (is_rpf_id) - *next_hop_fib_index = mfib_table_find (next_hop_table_proto, + *next_hop_fib_index = mfib_table_find (fib_nh_proto, ntohl (next_hop_table_id)); else - *next_hop_fib_index = fib_table_find (next_hop_table_proto, + *next_hop_fib_index = fib_table_find (fib_nh_proto, ntohl (next_hop_table_id)); if (~0 == *next_hop_fib_index) @@ -900,12 +906,12 @@ add_del_route_check (fib_protocol_t table_proto, { if (is_rpf_id) *next_hop_fib_index = - mfib_table_find_or_create_and_lock (next_hop_table_proto, + mfib_table_find_or_create_and_lock (fib_nh_proto, ntohl (next_hop_table_id)); else *next_hop_fib_index = - fib_table_find_or_create_and_lock (next_hop_table_proto, + fib_table_find_or_create_and_lock (fib_nh_proto, ntohl (next_hop_table_id)); } @@ -930,7 +936,7 @@ ip4_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp) rv = add_del_route_check (FIB_PROTOCOL_IP4, mp->table_id, mp->next_hop_sw_if_index, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, mp->next_hop_table_id, mp->create_vrf_if_needed, 0, &fib_index, &next_hop_fib_index); @@ -970,7 +976,7 @@ ip4_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp) mp->classify_table_index, mp->is_resolve_host, mp->is_resolve_attached, 0, 0, - fib_index, &pfx, 1, + fib_index, &pfx, DPO_PROTO_IP4, &nh, ntohl (mp->next_hop_sw_if_index), next_hop_fib_index, @@ -990,7 +996,7 @@ ip6_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp) rv = add_del_route_check (FIB_PROTOCOL_IP6, mp->table_id, mp->next_hop_sw_if_index, - FIB_PROTOCOL_IP6, + DPO_PROTO_IP6, mp->next_hop_table_id, mp->create_vrf_if_needed, 0, &fib_index, &next_hop_fib_index); @@ -1030,7 +1036,7 @@ ip6_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp) mp->classify_table_index, mp->is_resolve_host, mp->is_resolve_attached, 0, 0, - fib_index, &pfx, 0, + fib_index, &pfx, DPO_PROTO_IP6, &nh, ntohl (mp->next_hop_sw_if_index), next_hop_fib_index, mp->next_hop_weight, @@ -1106,7 +1112,7 @@ mroute_add_del_handler (u8 is_add, fib_route_path_t path = { .frp_sw_if_index = next_hop_sw_if_index, - .frp_proto = prefix->fp_proto, + .frp_proto = fib_proto_to_dpo (prefix->fp_proto), }; if (is_local) diff --git a/src/vnet/ip/lookup.c b/src/vnet/ip/lookup.c index 533d010a..41e46070 100755 --- a/src/vnet/ip/lookup.c +++ b/src/vnet/ip/lookup.c @@ -423,7 +423,7 @@ vnet_ip_route_cmd (vlib_main_t * vm, { rpath.frp_weight = 1; rpath.frp_eos = MPLS_NON_EOS; - rpath.frp_proto = FIB_PROTOCOL_MPLS; + rpath.frp_proto = DPO_PROTO_MPLS; rpath.frp_sw_if_index = ~0; vec_add1 (rpaths, rpath); } @@ -449,7 +449,7 @@ vnet_ip_route_cmd (vlib_main_t * vm, &rpath.frp_sw_if_index)) { rpath.frp_weight = 1; - rpath.frp_proto = FIB_PROTOCOL_IP4; + rpath.frp_proto = DPO_PROTO_IP4; vec_add1 (rpaths, rpath); } @@ -460,7 +460,7 @@ vnet_ip_route_cmd (vlib_main_t * vm, &rpath.frp_sw_if_index)) { rpath.frp_weight = 1; - rpath.frp_proto = FIB_PROTOCOL_IP6; + rpath.frp_proto = DPO_PROTO_IP6; vec_add1 (rpaths, rpath); } else if (unformat (line_input, "weight %u", &weight)) @@ -479,7 +479,7 @@ vnet_ip_route_cmd (vlib_main_t * vm, { rpath.frp_weight = 1; rpath.frp_sw_if_index = ~0; - rpath.frp_proto = FIB_PROTOCOL_IP4; + rpath.frp_proto = DPO_PROTO_IP4; vec_add1 (rpaths, rpath); } else if (unformat (line_input, "via %U next-hop-table %d", @@ -488,7 +488,7 @@ vnet_ip_route_cmd (vlib_main_t * vm, { rpath.frp_weight = 1; rpath.frp_sw_if_index = ~0; - rpath.frp_proto = FIB_PROTOCOL_IP6; + rpath.frp_proto = DPO_PROTO_IP6; vec_add1 (rpaths, rpath); } else if (unformat (line_input, "via %U", @@ -501,7 +501,7 @@ vnet_ip_route_cmd (vlib_main_t * vm, rpath.frp_fib_index = table_id; rpath.frp_weight = 1; rpath.frp_sw_if_index = ~0; - rpath.frp_proto = FIB_PROTOCOL_IP4; + rpath.frp_proto = DPO_PROTO_IP4; vec_add1 (rpaths, rpath); } else if (unformat (line_input, "via %U", @@ -510,13 +510,13 @@ vnet_ip_route_cmd (vlib_main_t * vm, rpath.frp_fib_index = table_id; rpath.frp_weight = 1; rpath.frp_sw_if_index = ~0; - rpath.frp_proto = FIB_PROTOCOL_IP6; + rpath.frp_proto = DPO_PROTO_IP6; vec_add1 (rpaths, rpath); } else if (unformat (line_input, "lookup in table %d", &rpath.frp_fib_index)) { - rpath.frp_proto = pfx.fp_proto; + rpath.frp_proto = fib_proto_to_dpo (pfx.fp_proto); rpath.frp_sw_if_index = ~0; vec_add1 (rpaths, rpath); } @@ -526,7 +526,7 @@ vnet_ip_route_cmd (vlib_main_t * vm, &rpath.frp_sw_if_index)) { rpath.frp_weight = 1; - rpath.frp_proto = prefixs[0].fp_proto; + rpath.frp_proto = fib_proto_to_dpo (prefixs[0].fp_proto); vec_add1 (rpaths, rpath); } else if (vec_len (prefixs) > 0 && diff --git a/src/vnet/lisp-gpe/lisp_gpe.c b/src/vnet/lisp-gpe/lisp_gpe.c index 0acc7349..018895ad 100644 --- a/src/vnet/lisp-gpe/lisp_gpe.c +++ b/src/vnet/lisp-gpe/lisp_gpe.c @@ -454,7 +454,7 @@ vnet_gpe_add_del_native_fwd_rpath (vnet_gpe_native_fwd_rpath_args_t * a) fib_route_path_t *rpath; u8 ip_version; - ip_version = a->rpath.frp_proto == FIB_PROTOCOL_IP4 ? IP4 : IP6; + ip_version = a->rpath.frp_proto == DPO_PROTO_IP4 ? IP4 : IP6; if (a->is_add) { @@ -511,7 +511,7 @@ gpe_native_forward_command_fn (vlib_main_t * vm, unformat_input_t * input, &rpath.frp_sw_if_index)) { rpath.frp_weight = 1; - rpath.frp_proto = FIB_PROTOCOL_IP4; + rpath.frp_proto = DPO_PROTO_IP4; } else if (unformat (line_input, "via %U %U", unformat_ip6_address, @@ -520,21 +520,21 @@ gpe_native_forward_command_fn (vlib_main_t * vm, unformat_input_t * input, &rpath.frp_sw_if_index)) { rpath.frp_weight = 1; - rpath.frp_proto = FIB_PROTOCOL_IP6; + rpath.frp_proto = DPO_PROTO_IP6; } else if (unformat (line_input, "via %U", unformat_ip4_address, &rpath.frp_addr.ip4)) { rpath.frp_weight = 1; rpath.frp_sw_if_index = ~0; - rpath.frp_proto = FIB_PROTOCOL_IP4; + rpath.frp_proto = DPO_PROTO_IP4; } else if (unformat (line_input, "via %U", unformat_ip6_address, &rpath.frp_addr.ip6)) { rpath.frp_weight = 1; rpath.frp_sw_if_index = ~0; - rpath.frp_proto = FIB_PROTOCOL_IP6; + rpath.frp_proto = DPO_PROTO_IP6; } else { @@ -549,7 +549,8 @@ gpe_native_forward_command_fn (vlib_main_t * vm, unformat_input_t * input, } else { - rpath.frp_fib_index = fib_table_find (rpath.frp_proto, table_id); + rpath.frp_fib_index = + fib_table_find (dpo_proto_to_fib (rpath.frp_proto), table_id); if ((u32) ~ 0 == rpath.frp_fib_index) { error = clib_error_return (0, "Nonexistent table id %d", table_id); diff --git a/src/vnet/lisp-gpe/lisp_gpe_api.c b/src/vnet/lisp-gpe/lisp_gpe_api.c index f1663699..4367a719 100644 --- a/src/vnet/lisp-gpe/lisp_gpe_api.c +++ b/src/vnet/lisp-gpe/lisp_gpe_api.c @@ -455,10 +455,10 @@ static void clib_memcpy (&a->rpath.frp_addr.ip6, mp->nh_addr, sizeof (ip6_address_t)); a->is_add = mp->is_add; - a->rpath.frp_proto = mp->is_ip4 ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6; - a->rpath.frp_fib_index = fib_table_find (a->rpath.frp_proto, - clib_net_to_host_u32 - (mp->table_id)); + a->rpath.frp_proto = mp->is_ip4 ? DPO_PROTO_IP4 : DPO_PROTO_IP6; + a->rpath.frp_fib_index = + fib_table_find (dpo_proto_to_fib (a->rpath.frp_proto), + clib_net_to_host_u32 (mp->table_id)); if (~0 == a->rpath.frp_fib_index) { rv = VNET_API_ERROR_INVALID_VALUE; @@ -484,7 +484,7 @@ gpe_native_fwd_rpaths_copy (vl_api_gpe_native_fwd_rpath_t * dst, vec_foreach (e, src) { memset (&dst[i], 0, sizeof (*dst)); - table = fib_table_get (e->frp_fib_index, e->frp_proto); + table = fib_table_get (e->frp_fib_index, dpo_proto_to_fib (e->frp_proto)); dst[i].fib_index = table->ft_table_id; dst[i].nh_sw_if_index = e->frp_sw_if_index; dst[i].is_ip4 = is_ip4; diff --git a/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c b/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c index 395b493a..ac048149 100644 --- a/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c +++ b/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c @@ -225,6 +225,7 @@ lisp_gpe_mk_fib_paths (const lisp_fwd_path_t * paths) { const lisp_gpe_adjacency_t *ladj; fib_route_path_t *rpaths = NULL; + fib_protocol_t fp; u8 best_priority; u32 ii; @@ -239,9 +240,9 @@ lisp_gpe_mk_fib_paths (const lisp_fwd_path_t * paths) ladj = lisp_gpe_adjacency_get (paths[ii].lisp_adj); - ip_address_to_46 (&ladj->remote_rloc, - &rpaths[ii].frp_addr, &rpaths[ii].frp_proto); + ip_address_to_46 (&ladj->remote_rloc, &rpaths[ii].frp_addr, &fp); + rpaths[ii].frp_proto = fib_proto_to_dpo (fp); rpaths[ii].frp_sw_if_index = ladj->sw_if_index; rpaths[ii].frp_weight = (paths[ii].weight ? paths[ii].weight : 1); } diff --git a/src/vnet/mfib/ip6_mfib.c b/src/vnet/mfib/ip6_mfib.c index 5c6f8126..5e48e919 100644 --- a/src/vnet/mfib/ip6_mfib.c +++ b/src/vnet/mfib/ip6_mfib.c @@ -158,7 +158,7 @@ ip6_create_mfib_with_table_id (u32 table_id) .fp_proto = FIB_PROTOCOL_IP6, }; const fib_route_path_t path_for_us = { - .frp_proto = FIB_PROTOCOL_IP6, + .frp_proto = DPO_PROTO_IP6, .frp_addr = zero_addr, .frp_sw_if_index = 0xffffffff, .frp_fib_index = ~0, @@ -222,7 +222,7 @@ ip6_mfib_table_destroy (ip6_mfib_t *mfib) .fp_proto = FIB_PROTOCOL_IP6, }; const fib_route_path_t path_for_us = { - .frp_proto = FIB_PROTOCOL_IP6, + .frp_proto = DPO_PROTO_IP6, .frp_addr = zero_addr, .frp_sw_if_index = 0xffffffff, .frp_fib_index = ~0, @@ -259,7 +259,7 @@ void ip6_mfib_interface_enable_disable (u32 sw_if_index, int is_enable) { const fib_route_path_t path = { - .frp_proto = FIB_PROTOCOL_IP6, + .frp_proto = DPO_PROTO_IP6, .frp_addr = zero_addr, .frp_sw_if_index = sw_if_index, .frp_fib_index = ~0, diff --git a/src/vnet/mfib/mfib_entry.c b/src/vnet/mfib/mfib_entry.c index cf25b67a..b37f8825 100644 --- a/src/vnet/mfib/mfib_entry.c +++ b/src/vnet/mfib/mfib_entry.c @@ -764,18 +764,16 @@ mfib_entry_update (fib_node_index_t mfib_entry_index, * entry */ fib_node_index_t old_pl_index; - fib_protocol_t fp; + dpo_proto_t dp; dpo_id_t dpo = DPO_INVALID; - fp = mfib_entry_get_proto(mfib_entry); + dp = fib_proto_to_dpo(mfib_entry_get_proto(mfib_entry)); old_pl_index = msrc->mfes_pl; - dpo_set(&dpo, DPO_REPLICATE, - fib_proto_to_dpo(fp), - repi); + dpo_set(&dpo, DPO_REPLICATE, dp, repi); msrc->mfes_pl = - fib_path_list_create_special(fp, + fib_path_list_create_special(dp, FIB_PATH_LIST_FLAG_EXCLUSIVE, &dpo); diff --git a/src/vnet/mfib/mfib_test.c b/src/vnet/mfib/mfib_test.c index 7c92ae99..57787eca 100644 --- a/src/vnet/mfib/mfib_test.c +++ b/src/vnet/mfib/mfib_test.c @@ -387,7 +387,7 @@ mfib_test_i (fib_protocol_t PROTO, fib_route_path_t path_via_if0 = { - .frp_proto = PROTO, + .frp_proto = fib_proto_to_dpo(PROTO), .frp_addr = zero_addr, .frp_sw_if_index = tm->hw[0]->sw_if_index, .frp_fib_index = ~0, @@ -411,7 +411,7 @@ mfib_test_i (fib_protocol_t PROTO, MFIB_ITF_FLAG_ACCEPT)); fib_route_path_t path_via_if1 = { - .frp_proto = PROTO, + .frp_proto = fib_proto_to_dpo(PROTO), .frp_addr = zero_addr, .frp_sw_if_index = tm->hw[1]->sw_if_index, .frp_fib_index = ~0, @@ -419,7 +419,7 @@ mfib_test_i (fib_protocol_t PROTO, .frp_flags = 0, }; fib_route_path_t path_via_if2 = { - .frp_proto = PROTO, + .frp_proto = fib_proto_to_dpo(PROTO), .frp_addr = zero_addr, .frp_sw_if_index = tm->hw[2]->sw_if_index, .frp_fib_index = ~0, @@ -427,7 +427,7 @@ mfib_test_i (fib_protocol_t PROTO, .frp_flags = 0, }; fib_route_path_t path_via_if3 = { - .frp_proto = PROTO, + .frp_proto = fib_proto_to_dpo(PROTO), .frp_addr = zero_addr, .frp_sw_if_index = tm->hw[3]->sw_if_index, .frp_fib_index = ~0, @@ -435,7 +435,7 @@ mfib_test_i (fib_protocol_t PROTO, .frp_flags = 0, }; fib_route_path_t path_for_us = { - .frp_proto = PROTO, + .frp_proto = fib_proto_to_dpo(PROTO), .frp_addr = zero_addr, .frp_sw_if_index = 0xffffffff, .frp_fib_index = ~0, @@ -1121,7 +1121,7 @@ mfib_test_i (fib_protocol_t PROTO, &pfx_3500, FIB_SOURCE_API, FIB_ENTRY_FLAG_MULTICAST, - FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, &nh_10_10_10_1, tm->hw[0]->sw_if_index, ~0, // invalid fib index @@ -1138,7 +1138,7 @@ mfib_test_i (fib_protocol_t PROTO, * An (S,G) that resolves via the mLDP head-end */ fib_route_path_t path_via_mldp = { - .frp_proto = FIB_PROTOCOL_MPLS, + .frp_proto = DPO_PROTO_MPLS, .frp_local_label = pfx_3500.fp_label, .frp_eos = MPLS_EOS, .frp_sw_if_index = 0xffffffff, diff --git a/src/vnet/mpls/mpls.api b/src/vnet/mpls/mpls.api index 67f1045d..5973a0a6 100644 --- a/src/vnet/mpls/mpls.api +++ b/src/vnet/mpls/mpls.api @@ -156,7 +156,7 @@ manual_endian manual_print define mpls_tunnel_details @param mr_is_interface_rx - Interface Receive path @param mr_is_interface_rx - RPF-ID Receive path. The next-hop interface is used as the RPF-ID - @param mr_next_hop_proto_is_ip4 - The next-hop is IPV4 + @param mr_next_hop_proto - The next-hop protocol, of type dpo_proto_t @param mr_next_hop_weight - The weight, for UCMP @param mr_next_hop[16] - the nextop address @param mr_next_hop_sw_if_index - the next-hop SW interface @@ -182,7 +182,7 @@ autoreply define mpls_route_add_del u8 mr_is_resolve_attached; u8 mr_is_interface_rx; u8 mr_is_rpf_id; - u8 mr_next_hop_proto_is_ip4; + u8 mr_next_hop_proto; u8 mr_next_hop_weight; u8 mr_next_hop_preference; u8 mr_next_hop[16]; diff --git a/src/vnet/mpls/mpls.c b/src/vnet/mpls/mpls.c index 068d31f4..266ba42c 100644 --- a/src/vnet/mpls/mpls.c +++ b/src/vnet/mpls/mpls.c @@ -261,7 +261,7 @@ vnet_mpls_local_label (vlib_main_t * vm, &rpath.frp_sw_if_index, &rpath.frp_weight)) { - rpath.frp_proto = FIB_PROTOCOL_IP4; + rpath.frp_proto = DPO_PROTO_IP4; vec_add1(rpaths, rpath); } @@ -272,7 +272,7 @@ vnet_mpls_local_label (vlib_main_t * vm, &rpath.frp_sw_if_index, &rpath.frp_weight)) { - rpath.frp_proto = FIB_PROTOCOL_IP6; + rpath.frp_proto = DPO_PROTO_IP6; vec_add1(rpaths, rpath); } @@ -283,7 +283,7 @@ vnet_mpls_local_label (vlib_main_t * vm, &rpath.frp_sw_if_index)) { rpath.frp_weight = 1; - rpath.frp_proto = FIB_PROTOCOL_IP4; + rpath.frp_proto = DPO_PROTO_IP4; vec_add1(rpaths, rpath); } else if (unformat (line_input, "rx-ip4 %U", @@ -291,7 +291,7 @@ vnet_mpls_local_label (vlib_main_t * vm, &rpath.frp_sw_if_index)) { rpath.frp_weight = 1; - rpath.frp_proto = FIB_PROTOCOL_IP4; + rpath.frp_proto = DPO_PROTO_IP4; rpath.frp_flags = FIB_ROUTE_PATH_INTF_RX; vec_add1(rpaths, rpath); } @@ -302,7 +302,7 @@ vnet_mpls_local_label (vlib_main_t * vm, &rpath.frp_sw_if_index)) { rpath.frp_weight = 1; - rpath.frp_proto = FIB_PROTOCOL_IP6; + rpath.frp_proto = DPO_PROTO_IP6; vec_add1(rpaths, rpath); } else if (unformat (line_input, "via %U next-hop-table %d", @@ -312,7 +312,7 @@ vnet_mpls_local_label (vlib_main_t * vm, { rpath.frp_weight = 1; rpath.frp_sw_if_index = ~0; - rpath.frp_proto = FIB_PROTOCOL_IP4; + rpath.frp_proto = DPO_PROTO_IP4; vec_add1(rpaths, rpath); } else if (unformat (line_input, "via %U next-hop-table %d", @@ -322,7 +322,7 @@ vnet_mpls_local_label (vlib_main_t * vm, { rpath.frp_weight = 1; rpath.frp_sw_if_index = ~0; - rpath.frp_proto = FIB_PROTOCOL_IP6; + rpath.frp_proto = DPO_PROTO_IP6; vec_add1(rpaths, rpath); } else if (unformat (line_input, "via %U", @@ -336,7 +336,7 @@ vnet_mpls_local_label (vlib_main_t * vm, rpath.frp_fib_index = table_id; rpath.frp_weight = 1; rpath.frp_sw_if_index = ~0; - rpath.frp_proto = FIB_PROTOCOL_IP4; + rpath.frp_proto = DPO_PROTO_IP4; vec_add1(rpaths, rpath); } else if (unformat (line_input, "via %U", @@ -346,7 +346,7 @@ vnet_mpls_local_label (vlib_main_t * vm, rpath.frp_fib_index = table_id; rpath.frp_weight = 1; rpath.frp_sw_if_index = ~0; - rpath.frp_proto = FIB_PROTOCOL_IP6; + rpath.frp_proto = DPO_PROTO_IP6; vec_add1(rpaths, rpath); } else if (unformat (line_input, "%d", &local_label)) @@ -355,7 +355,7 @@ vnet_mpls_local_label (vlib_main_t * vm, "ip4-lookup-in-table %d", &rpath.frp_fib_index)) { - rpath.frp_proto = FIB_PROTOCOL_IP4; + rpath.frp_proto = DPO_PROTO_IP4; rpath.frp_sw_if_index = FIB_NODE_INDEX_INVALID; pfx.fp_payload_proto = DPO_PROTO_IP4; vec_add1(rpaths, rpath); @@ -364,7 +364,7 @@ vnet_mpls_local_label (vlib_main_t * vm, "ip6-lookup-in-table %d", &rpath.frp_fib_index)) { - rpath.frp_proto = FIB_PROTOCOL_IP6; + rpath.frp_proto = DPO_PROTO_IP6; rpath.frp_sw_if_index = FIB_NODE_INDEX_INVALID; vec_add1(rpaths, rpath); pfx.fp_payload_proto = DPO_PROTO_IP6; @@ -373,11 +373,21 @@ vnet_mpls_local_label (vlib_main_t * vm, "mpls-lookup-in-table %d", &rpath.frp_fib_index)) { - rpath.frp_proto = FIB_PROTOCOL_MPLS; + rpath.frp_proto = DPO_PROTO_MPLS; rpath.frp_sw_if_index = FIB_NODE_INDEX_INVALID; pfx.fp_payload_proto = DPO_PROTO_MPLS; vec_add1(rpaths, rpath); } + else if (unformat (line_input, + "l2-input-on %U", + unformat_vnet_sw_interface, vnm, + &rpath.frp_sw_if_index)) + { + rpath.frp_proto = DPO_PROTO_ETHERNET; + pfx.fp_payload_proto = DPO_PROTO_ETHERNET; + rpath.frp_flags = FIB_ROUTE_PATH_INTF_RX; + vec_add1(rpaths, rpath); + } else if (unformat (line_input, "out-label %U", unformat_mpls_unicast_label, &out_label)) @@ -440,7 +450,7 @@ vnet_mpls_local_label (vlib_main_t * vm, pfx.fp_proto = FIB_PROTOCOL_MPLS; pfx.fp_len = 21; pfx.fp_label = local_label; - pfx.fp_payload_proto = fib_proto_to_dpo(rpaths[0].frp_proto); + pfx.fp_payload_proto = rpaths[0].frp_proto; /* * the CLI parsing stored table Ids, swap to FIB indicies diff --git a/src/vnet/mpls/mpls_api.c b/src/vnet/mpls/mpls_api.c index 92fb24a6..737299e6 100644 --- a/src/vnet/mpls/mpls_api.c +++ b/src/vnet/mpls/mpls_api.c @@ -144,14 +144,7 @@ mpls_route_add_del_t_handler (vnet_main_t * vnm, }; if (pfx.fp_eos) { - if (mp->mr_next_hop_proto_is_ip4) - { - pfx.fp_payload_proto = DPO_PROTO_IP4; - } - else - { - pfx.fp_payload_proto = DPO_PROTO_IP6; - } + pfx.fp_payload_proto = mp->mr_next_hop_proto; } else { @@ -161,7 +154,7 @@ mpls_route_add_del_t_handler (vnet_main_t * vnm, rv = add_del_route_check (FIB_PROTOCOL_MPLS, mp->mr_table_id, mp->mr_next_hop_sw_if_index, - dpo_proto_to_fib (pfx.fp_payload_proto), + pfx.fp_payload_proto, mp->mr_next_hop_table_id, mp->mr_create_table_if_needed, mp->mr_is_rpf_id, @@ -173,9 +166,9 @@ mpls_route_add_del_t_handler (vnet_main_t * vnm, ip46_address_t nh; memset (&nh, 0, sizeof (nh)); - if (mp->mr_next_hop_proto_is_ip4) + if (DPO_PROTO_IP4 == mp->mr_next_hop_proto) memcpy (&nh.ip4, mp->mr_next_hop, sizeof (nh.ip4)); - else + else if (DPO_PROTO_IP6 == mp->mr_next_hop_proto) memcpy (&nh.ip6, mp->mr_next_hop, sizeof (nh.ip6)); n_labels = mp->mr_next_hop_n_out_labels; @@ -202,7 +195,7 @@ mpls_route_add_del_t_handler (vnet_main_t * vnm, mp->mr_is_interface_rx, mp->mr_is_rpf_id, fib_index, &pfx, - mp->mr_next_hop_proto_is_ip4, + mp->mr_next_hop_proto, &nh, ntohl (mp->mr_next_hop_sw_if_index), next_hop_fib_index, mp->mr_next_hop_weight, @@ -243,13 +236,13 @@ vl_api_mpls_tunnel_add_del_t_handler (vl_api_mpls_tunnel_add_del_t * mp) if (mp->mt_next_hop_proto_is_ip4) { - rpath.frp_proto = FIB_PROTOCOL_IP4; + rpath.frp_proto = DPO_PROTO_IP4; clib_memcpy (&rpath.frp_addr.ip4, mp->mt_next_hop, sizeof (rpath.frp_addr.ip4)); } else { - rpath.frp_proto = FIB_PROTOCOL_IP6; + rpath.frp_proto = DPO_PROTO_IP6; clib_memcpy (&rpath.frp_addr.ip6, mp->mt_next_hop, sizeof (rpath.frp_addr.ip6)); } diff --git a/src/vnet/mpls/mpls_tunnel.c b/src/vnet/mpls/mpls_tunnel.c index c025cc58..6452a60b 100644 --- a/src/vnet/mpls/mpls_tunnel.c +++ b/src/vnet/mpls/mpls_tunnel.c @@ -171,7 +171,7 @@ mpls_tunnel_mk_lb (mpls_tunnel_t *mt, vec_validate(ctx.next_hops, fib_path_list_get_n_paths(mt->mt_path_list)); vec_reset_length(ctx.next_hops); - lb_proto = vnet_link_to_dpo_proto(linkt); + lb_proto = fib_forw_chain_type_to_dpo_proto(fct); fib_path_list_walk(mt->mt_path_list, mpls_tunnel_collect_forwarding, @@ -313,12 +313,34 @@ mpls_tunnel_restack (mpls_tunnel_t *mt) /* * walk all the adjacencies on the MPLS interface and restack them */ - FOR_EACH_FIB_PROTOCOL(proto) + if (mt->mt_flags & MPLS_TUNNEL_FLAG_L2) { - adj_nbr_walk(mt->mt_sw_if_index, - proto, - mpls_adj_walk_cb, - NULL); + /* + * Stack a load-balance that drops, whilst we have no paths + */ + vnet_hw_interface_t * hi; + dpo_id_t dpo = DPO_INVALID; + + mpls_tunnel_mk_lb(mt, + VNET_LINK_MPLS, + FIB_FORW_CHAIN_TYPE_ETHERNET, + &dpo); + + hi = vnet_get_hw_interface(vnet_get_main(), mt->mt_hw_if_index); + dpo_stack_from_node(hi->tx_node_index, + &mt->mt_l2_lb, + &dpo); + dpo_reset(&dpo); + } + else + { + FOR_EACH_FIB_PROTOCOL(proto) + { + adj_nbr_walk(mt->mt_sw_if_index, + proto, + mpls_adj_walk_cb, + NULL); + } } } @@ -495,7 +517,7 @@ mpls_tunnel_tx (vlib_main_t * vm, b0 = vlib_get_buffer(vm, bi0); - vnet_buffer(b0)->ip.adj_index[VLIB_TX] = mt->mt_l2_adj; + vnet_buffer(b0)->ip.adj_index[VLIB_TX] = mt->mt_l2_lb.dpoi_index; if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) { @@ -506,7 +528,7 @@ mpls_tunnel_tx (vlib_main_t * vm, vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, n_left_to_next, - bi0, mt->mt_l2_tx_arc); + bi0, mt->mt_l2_lb.dpoi_next_node); } vlib_put_next_frame (vm, node, next_index, n_left_to_next); @@ -565,8 +587,7 @@ vnet_mpls_tunnel_del (u32 sw_if_index) if (FIB_NODE_INDEX_INVALID != mt->mt_path_list) fib_path_list_child_remove(mt->mt_path_list, mt->mt_sibling_index); - if (ADJ_INDEX_INVALID != mt->mt_l2_adj) - adj_unlock(mt->mt_l2_adj); + dpo_reset(&mt->mt_l2_lb); vec_add1 (mpls_tunnel_free_hw_if_indices, mt->mt_hw_if_index); pool_put(mpls_tunnel_pool, mt); @@ -587,12 +608,13 @@ vnet_mpls_tunnel_create (u8 l2_only, memset (mt, 0, sizeof (*mt)); mti = mt - mpls_tunnel_pool; fib_node_init(&mt->mt_node, FIB_NODE_TYPE_MPLS_TUNNEL); - mt->mt_l2_adj = ADJ_INDEX_INVALID; mt->mt_path_list = FIB_NODE_INDEX_INVALID; mt->mt_sibling_index = FIB_NODE_INDEX_INVALID; if (is_multicast) mt->mt_flags |= MPLS_TUNNEL_FLAG_MCAST; + if (l2_only) + mt->mt_flags |= MPLS_TUNNEL_FLAG_L2; /* * Create a new, or re=use and old, tunnel HW interface @@ -614,7 +636,7 @@ vnet_mpls_tunnel_create (u8 l2_only, mti, mpls_tunnel_hw_interface_class.index, mti); - hi = vnet_get_hw_interface(vnm, mt->mt_hw_if_index); + hi = vnet_get_hw_interface (vnm, mt->mt_hw_if_index); } /* @@ -624,19 +646,6 @@ vnet_mpls_tunnel_create (u8 l2_only, vec_validate_init_empty(mpls_tunnel_db, mt->mt_sw_if_index, ~0); mpls_tunnel_db[mt->mt_sw_if_index] = mti; - if (l2_only) - { - mt->mt_l2_adj = - adj_nbr_add_or_lock(fib_path_list_get_proto(mt->mt_path_list), - VNET_LINK_ETHERNET, - &zero_addr, - mt->mt_sw_if_index); - - mt->mt_l2_tx_arc = vlib_node_add_named_next(vlib_get_main(), - hi->tx_node_index, - "adj-l2-midchain"); - } - return (mt->mt_sw_if_index); } @@ -803,7 +812,7 @@ vnet_create_mpls_tunnel_command_fn (vlib_main_t * vm, &rpath.frp_sw_if_index)) { rpath.frp_weight = 1; - rpath.frp_proto = FIB_PROTOCOL_IP4; + rpath.frp_proto = DPO_PROTO_IP4; } else if (unformat (line_input, "via %U %U", @@ -813,7 +822,7 @@ vnet_create_mpls_tunnel_command_fn (vlib_main_t * vm, &rpath.frp_sw_if_index)) { rpath.frp_weight = 1; - rpath.frp_proto = FIB_PROTOCOL_IP6; + rpath.frp_proto = DPO_PROTO_IP6; } else if (unformat (line_input, "via %U", unformat_ip6_address, @@ -822,7 +831,7 @@ vnet_create_mpls_tunnel_command_fn (vlib_main_t * vm, rpath.frp_fib_index = 0; rpath.frp_weight = 1; rpath.frp_sw_if_index = ~0; - rpath.frp_proto = FIB_PROTOCOL_IP6; + rpath.frp_proto = DPO_PROTO_IP6; } else if (unformat (line_input, "via %U", unformat_ip4_address, @@ -831,7 +840,7 @@ vnet_create_mpls_tunnel_command_fn (vlib_main_t * vm, rpath.frp_fib_index = 0; rpath.frp_weight = 1; rpath.frp_sw_if_index = ~0; - rpath.frp_proto = FIB_PROTOCOL_IP4; + rpath.frp_proto = DPO_PROTO_IP4; } else if (unformat (line_input, "l2-only")) l2_only = 1; @@ -915,6 +924,14 @@ format_mpls_tunnel (u8 * s, va_list * args) s = format(s, "%U", format_fib_path_ext_list, &mt->mt_path_exts); s = format(s, "\n"); + if (mt->mt_flags & MPLS_TUNNEL_FLAG_L2) + { + s = format(s, " forwarding: %U\n", + format_fib_forw_chain_type, + FIB_FORW_CHAIN_TYPE_ETHERNET); + s = format(s, " %U\n", format_dpo_id, &mt->mt_l2_lb, 2); + } + return (s); } diff --git a/src/vnet/mpls/mpls_tunnel.h b/src/vnet/mpls/mpls_tunnel.h index 4cb0a860..285817c3 100644 --- a/src/vnet/mpls/mpls_tunnel.h +++ b/src/vnet/mpls/mpls_tunnel.h @@ -22,15 +22,20 @@ typedef enum mpls_tunnel_attribute_t_ { MPLS_TUNNEL_ATTRIBUTE_FIRST = 0, + /** + * @brief The tunnel is L2 only + */ + MPLS_TUNNEL_ATTRIBUTE_L2 = MPLS_TUNNEL_ATTRIBUTE_FIRST, /** * @brief The tunnel has an underlying multicast LSP */ - MPLS_TUNNEL_ATTRIBUTE_MCAST = MPLS_TUNNEL_ATTRIBUTE_FIRST, + MPLS_TUNNEL_ATTRIBUTE_MCAST, MPLS_TUNNEL_ATTRIBUTE_LAST = MPLS_TUNNEL_ATTRIBUTE_MCAST, } mpls_tunnel_attribute_t; #define MPLS_TUNNEL_ATTRIBUTES { \ [MPLS_TUNNEL_ATTRIBUTE_MCAST] = "multicast", \ + [MPLS_TUNNEL_ATTRIBUTE_L2] = "L2", \ } #define FOR_EACH_MPLS_TUNNEL_ATTRIBUTE(_item) \ for (_item = MPLS_TUNNEL_ATTRIBUTE_FIRST; \ @@ -39,6 +44,7 @@ typedef enum mpls_tunnel_attribute_t_ typedef enum mpls_tunnel_flag_t_ { MPLS_TUNNEL_FLAG_NONE = 0, + MPLS_TUNNEL_FLAG_L2 = (1 << MPLS_TUNNEL_ATTRIBUTE_L2), MPLS_TUNNEL_FLAG_MCAST = (1 << MPLS_TUNNEL_ATTRIBUTE_MCAST), } __attribute__ ((packed)) mpls_tunnel_flags_t; @@ -60,14 +66,19 @@ typedef struct mpls_tunnel_t_ /** * @brief If the tunnel is an L2 tunnel, this is the link type ETHERNET - * adjacency + * load-balance + */ + dpo_id_t mt_l2_lb; + + /** + * @brief The HW interface index of the tunnel interfaces */ - adj_index_t mt_l2_adj; + u32 mt_hw_if_index; /** - * @brief on a L2 tunnel this is the VLIB arc from the L2-tx to the l2-midchain + * @brief The SW interface index of the tunnel interfaces */ - u32 mt_l2_tx_arc; + u32 mt_sw_if_index; /** * @brief The path-list over which the tunnel's destination is reachable @@ -83,23 +94,6 @@ typedef struct mpls_tunnel_t_ * A vector of path extensions o hold the label stack for each path */ fib_path_ext_list_t mt_path_exts; - - /** - * @brief Flag to indicate the tunnel is only for L2 traffic, that is - * this tunnel belongs in a bridge domain. - */ - u8 mt_l2_only; - - /** - * @brief The HW interface index of the tunnel interfaces - */ - u32 mt_hw_if_index; - - /** - * @brief The SW interface index of the tunnel interfaces - */ - u32 mt_sw_if_index; - } mpls_tunnel_t; /** diff --git a/src/vnet/srmpls/sr_mpls_policy.c b/src/vnet/srmpls/sr_mpls_policy.c index 5ebbc60d..db4ad2a7 100755 --- a/src/vnet/srmpls/sr_mpls_policy.c +++ b/src/vnet/srmpls/sr_mpls_policy.c @@ -75,7 +75,7 @@ create_sl (mpls_sr_policy_t * sr_policy, mpls_label_t * sl, u32 weight) segment_list->segments = vec_dup (sl); fib_route_path_t path = { - .frp_proto = FIB_PROTOCOL_MPLS, + .frp_proto = DPO_PROTO_MPLS, .frp_sw_if_index = ~0, .frp_fib_index = 0, .frp_weight = segment_list->weight, @@ -203,7 +203,7 @@ sr_mpls_policy_del (mpls_label_t bsid, u32 index) segment_list = pool_elt_at_index (sm->sid_lists, *sl_index); fib_route_path_t path = { - .frp_proto = FIB_PROTOCOL_MPLS, + .frp_proto = DPO_PROTO_MPLS, .frp_sw_if_index = ~0, .frp_fib_index = 0, .frp_weight = segment_list->weight, @@ -308,7 +308,7 @@ sr_mpls_policy_mod (mpls_label_t bsid, u32 index, u8 operation, mpls_eos_bit_t eos; fib_route_path_t path = { - .frp_proto = FIB_PROTOCOL_MPLS, + .frp_proto = DPO_PROTO_MPLS, .frp_sw_if_index = ~0, .frp_fib_index = 0, .frp_weight = segment_list->weight, diff --git a/src/vnet/srmpls/sr_mpls_steering.c b/src/vnet/srmpls/sr_mpls_steering.c index 37707049..3a9aea2d 100755 --- a/src/vnet/srmpls/sr_mpls_steering.c +++ b/src/vnet/srmpls/sr_mpls_steering.c @@ -218,7 +218,7 @@ sr_mpls_steering_policy (int is_del, mpls_label_t bsid, u32 sr_policy_index, update_fib:; fib_route_path_t path = { - .frp_proto = FIB_PROTOCOL_MPLS, + .frp_proto = DPO_PROTO_MPLS, .frp_local_label = sr_policy->bsid, .frp_eos = MPLS_EOS, .frp_sw_if_index = ~0, diff --git a/src/vnet/srv6/sr_steering.c b/src/vnet/srv6/sr_steering.c index a7903751..704adaa7 100755 --- a/src/vnet/srv6/sr_steering.c +++ b/src/vnet/srv6/sr_steering.c @@ -310,7 +310,7 @@ update_fib: table_id : 0)), &pfx, FIB_SOURCE_SR, FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT, - FIB_PROTOCOL_IP6, + DPO_PROTO_IP6, (ip46_address_t *) & sr_policy->bsid, ~0, sm->fib_table_ip6, 1, NULL, FIB_ROUTE_PATH_FLAG_NONE); @@ -327,7 +327,7 @@ update_fib: table_id : 0)), &pfx, FIB_SOURCE_SR, FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT, - FIB_PROTOCOL_IP6, + DPO_PROTO_IP6, (ip46_address_t *) & sr_policy->bsid, ~0, sm->fib_table_ip4, 1, NULL, FIB_ROUTE_PATH_FLAG_NONE); diff --git a/src/vnet/vxlan-gpe/vxlan_gpe.c b/src/vnet/vxlan-gpe/vxlan_gpe.c index 97bb1b15..462c79a0 100644 --- a/src/vnet/vxlan-gpe/vxlan_gpe.c +++ b/src/vnet/vxlan-gpe/vxlan_gpe.c @@ -638,7 +638,7 @@ int vnet_vxlan_gpe_add_del_tunnel fib_node_index_t mfei; adj_index_t ai; fib_route_path_t path = { - .frp_proto = fp, + .frp_proto = fib_proto_to_dpo(fp), .frp_addr = zero_addr, .frp_sw_if_index = 0xffffffff, .frp_fib_index = ~0, diff --git a/src/vnet/vxlan/vxlan.c b/src/vnet/vxlan/vxlan.c index 1b3df2a8..dc973372 100644 --- a/src/vnet/vxlan/vxlan.c +++ b/src/vnet/vxlan/vxlan.c @@ -505,7 +505,7 @@ int vnet_vxlan_add_del_tunnel fib_node_index_t mfei; adj_index_t ai; fib_route_path_t path = { - .frp_proto = fp, + .frp_proto = fib_proto_to_dpo(fp), .frp_addr = zero_addr, .frp_sw_if_index = 0xffffffff, .frp_fib_index = ~0, diff --git a/src/vpp/app/vpe_cli.c b/src/vpp/app/vpe_cli.c index 94bdc84c..fcc496ad 100644 --- a/src/vpp/app/vpe_cli.c +++ b/src/vpp/app/vpe_cli.c @@ -98,7 +98,7 @@ virtual_ip_cmd_fn_command_fn (vlib_main_t * vm, vec_add2 (rpaths, rpath, 1); - rpath->frp_proto = FIB_PROTOCOL_IP4; + rpath->frp_proto = DPO_PROTO_IP4; rpath->frp_addr = next_hops[i]; rpath->frp_sw_if_index = sw_if_index; rpath->frp_fib_index = ~0; diff --git a/test/test_bfd.py b/test/test_bfd.py index be42cdad..4cb6d379 100644 --- a/test/test_bfd.py +++ b/test/test_bfd.py @@ -20,7 +20,7 @@ from vpp_pg_interface import CaptureTimeoutError, is_ipv6_misc from vpp_lo_interface import VppLoInterface from util import ppp from vpp_papi_provider import UnexpectedApiReturnValueError -from vpp_ip_route import VppIpRoute, VppRoutePath +from vpp_ip_route import VppIpRoute, VppRoutePath, DpoProto USEC_IN_SEC = 1000000 @@ -1678,12 +1678,12 @@ class BFDFIBTestCase(VppTestCase): ip_2001_s_64 = VppIpRoute(self, "2001::", 64, [VppRoutePath(self.pg0.remote_ip6, self.pg0.sw_if_index, - is_ip6=1)], + proto=DPO_PROTO_IP6)], is_ip6=1) ip_2002_s_64 = VppIpRoute(self, "2002::", 64, [VppRoutePath(self.pg0.remote_ip6, 0xffffffff, - is_ip6=1)], + proto=DPO_PROTO_IP6)], is_ip6=1) ip_2001_s_64.add_vpp_config() ip_2002_s_64.add_vpp_config() diff --git a/test/test_gre.py b/test/test_gre.py index 18b67dbd..1afc44fb 100644 --- a/test/test_gre.py +++ b/test/test_gre.py @@ -6,7 +6,7 @@ from logging import * from framework import VppTestCase, VppTestRunner from vpp_sub_interface import VppDot1QSubint from vpp_gre_interface import VppGreInterface, VppGre6Interface -from vpp_ip_route import VppIpRoute, VppRoutePath +from vpp_ip_route import VppIpRoute, VppRoutePath, DpoProto from vpp_papi_provider import L2_VTR_OP from scapy.packet import Raw @@ -516,11 +516,12 @@ class TestGRE(VppTestCase): gre_if.admin_up() gre_if.config_ip6() - route_via_tun = VppIpRoute(self, "4004::1", 128, - [VppRoutePath("0::0", - gre_if.sw_if_index, - is_ip6=1)], - is_ip6=1) + route_via_tun = VppIpRoute( + self, "4004::1", 128, + [VppRoutePath("0::0", + gre_if.sw_if_index, + proto=DpoProto.DPO_PROTO_IP6)], + is_ip6=1) route_via_tun.add_vpp_config() @@ -542,11 +543,12 @@ class TestGRE(VppTestCase): # # Add a route that resolves the tunnel's destination # - route_tun_dst = VppIpRoute(self, "1002::1", 128, - [VppRoutePath(self.pg2.remote_ip6, - self.pg2.sw_if_index, - is_ip6=1)], - is_ip6=1) + route_tun_dst = VppIpRoute( + self, "1002::1", 128, + [VppRoutePath(self.pg2.remote_ip6, + self.pg2.sw_if_index, + proto=DpoProto.DPO_PROTO_IP6)], + is_ip6=1) route_tun_dst.add_vpp_config() # diff --git a/test/test_ip6.py b/test/test_ip6.py index 593f6868..285ce181 100644 --- a/test/test_ip6.py +++ b/test/test_ip6.py @@ -8,7 +8,7 @@ from vpp_sub_interface import VppSubInterface, VppDot1QSubint from vpp_pg_interface import is_ipv6_misc from vpp_ip_route import VppIpRoute, VppRoutePath, find_route, VppIpMRoute, \ VppMRoutePath, MRouteItfFlags, MRouteEntryFlags, VppMplsIpBind, \ - VppMplsRoute + VppMplsRoute, DpoProto from vpp_neighbor import find_nbr, VppNeighbor from scapy.packet import Raw @@ -490,7 +490,7 @@ class TestIPv6(TestIPv6ND): inet=AF_INET6)) def test_ns_duplicates(self): - """ ARP Duplicates""" + """ ND Duplicates""" # # Generate some hosts on the LAN @@ -537,7 +537,7 @@ class TestIPv6(TestIPv6ND): # # remove the duplicate on pg1 - # packet stream shoud generate ARPs out of pg1 + # packet stream shoud generate NSs out of pg1 # ns_pg1.remove_vpp_config() @@ -1347,10 +1347,10 @@ class TestIP6LoadBalance(VppTestCase): route_3000_1 = VppIpRoute(self, "3000::1", 128, [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index, - is_ip6=1), + proto=DpoProto.DPO_PROTO_IP6), VppRoutePath(self.pg2.remote_ip6, self.pg2.sw_if_index, - is_ip6=1)], + proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) route_3000_1.add_vpp_config() @@ -1367,11 +1367,11 @@ class TestIP6LoadBalance(VppTestCase): [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index, labels=[67], - is_ip6=1), + proto=DpoProto.DPO_PROTO_IP6), VppRoutePath(self.pg2.remote_ip6, self.pg2.sw_if_index, labels=[67], - is_ip6=1)]) + proto=DpoProto.DPO_PROTO_IP6)]) route_67.add_vpp_config() # @@ -1441,20 +1441,20 @@ class TestIP6LoadBalance(VppTestCase): route_3000_2 = VppIpRoute(self, "3000::2", 128, [VppRoutePath(self.pg3.remote_ip6, self.pg3.sw_if_index, - is_ip6=1), + proto=DpoProto.DPO_PROTO_IP6), VppRoutePath(self.pg4.remote_ip6, self.pg4.sw_if_index, - is_ip6=1)], + proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) route_3000_2.add_vpp_config() route_4000_1 = VppIpRoute(self, "4000::1", 128, [VppRoutePath("3000::1", 0xffffffff, - is_ip6=1), + proto=DpoProto.DPO_PROTO_IP6), VppRoutePath("3000::2", 0xffffffff, - is_ip6=1)], + proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) route_4000_1.add_vpp_config() @@ -1485,14 +1485,14 @@ class TestIP6LoadBalance(VppTestCase): route_5000_2 = VppIpRoute(self, "5000::2", 128, [VppRoutePath(self.pg3.remote_ip6, self.pg3.sw_if_index, - is_ip6=1)], + proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) route_5000_2.add_vpp_config() route_6000_1 = VppIpRoute(self, "6000::1", 128, [VppRoutePath("5000::2", 0xffffffff, - is_ip6=1)], + proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) route_6000_1.add_vpp_config() diff --git a/test/test_map.py b/test/test_map.py index 9ac3948a..bbf4aec2 100644 --- a/test/test_map.py +++ b/test/test_map.py @@ -4,7 +4,7 @@ import unittest import socket from framework import VppTestCase, VppTestRunner -from vpp_ip_route import VppIpRoute, VppRoutePath +from vpp_ip_route import VppIpRoute, VppRoutePath, DpoProto from scapy.layers.l2 import Ether, Raw from scapy.layers.inet import IP, UDP, ICMP @@ -75,7 +75,7 @@ class TestMAP(VppTestCase): map_br_pfx_len, [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index, - is_ip6=1)], + proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) map_route.add_vpp_config() @@ -138,13 +138,12 @@ class TestMAP(VppTestCase): # Add a route to 4001::1. Expect the encapped traffic to be # sent via that routes next-hop # - pre_res_route = VppIpRoute(self, - "4001::1", - 128, - [VppRoutePath(self.pg1.remote_hosts[2].ip6, - self.pg1.sw_if_index, - is_ip6=1)], - is_ip6=1) + pre_res_route = VppIpRoute( + self, "4001::1", 128, + [VppRoutePath(self.pg1.remote_hosts[2].ip6, + self.pg1.sw_if_index, + proto=DpoProto.DPO_PROTO_IP6)], + is_ip6=1) pre_res_route.add_vpp_config() self.send_and_assert_encapped(v4, map_src, @@ -156,7 +155,7 @@ class TestMAP(VppTestCase): # pre_res_route.modify([VppRoutePath(self.pg1.remote_hosts[3].ip6, self.pg1.sw_if_index, - is_ip6=1)]) + proto=DpoProto.DPO_PROTO_IP6)]) pre_res_route.add_vpp_config() self.send_and_assert_encapped(v4, map_src, diff --git a/test/test_mpls.py b/test/test_mpls.py index e3d013af..b2226a74 100644 --- a/test/test_mpls.py +++ b/test/test_mpls.py @@ -6,7 +6,7 @@ import socket from framework import VppTestCase, VppTestRunner from vpp_ip_route import VppIpRoute, VppRoutePath, VppMplsRoute, \ VppMplsIpBind, VppIpMRoute, VppMRoutePath, \ - MRouteItfFlags, MRouteEntryFlags + MRouteItfFlags, MRouteEntryFlags, DpoProto from vpp_mpls_tunnel_interface import VppMPLSTunnelInterface from scapy.packet import Raw @@ -16,6 +16,38 @@ from scapy.layers.inet6 import IPv6 from scapy.contrib.mpls import MPLS +def verify_filter(capture, sent): + if not len(capture) == len(sent): + # filter out any IPv6 RAs from the capture + for p in capture: + if p.haslayer(IPv6): + capture.remove(p) + return capture + + +def verify_mpls_stack(tst, rx, mpls_labels, ttl=255, num=0): + # the rx'd packet has the MPLS label popped + eth = rx[Ether] + tst.assertEqual(eth.type, 0x8847) + + rx_mpls = rx[MPLS] + + for ii in range(len(mpls_labels)): + tst.assertEqual(rx_mpls.label, mpls_labels[ii]) + tst.assertEqual(rx_mpls.cos, 0) + if ii == num: + tst.assertEqual(rx_mpls.ttl, ttl) + else: + tst.assertEqual(rx_mpls.ttl, 255) + if ii == len(mpls_labels) - 1: + tst.assertEqual(rx_mpls.s, 1) + else: + # not end of stack + tst.assertEqual(rx_mpls.s, 0) + # pop the label to expose the next + rx_mpls = rx_mpls[MPLS].payload + + class TestMPLS(VppTestCase): """ MPLS Test Case """ @@ -120,18 +152,9 @@ class TestMPLS(VppTestCase): pkts.append(p) return pkts - @staticmethod - def verify_filter(capture, sent): - if not len(capture) == len(sent): - # filter out any IPv6 RAs from the capture - for p in capture: - if p.haslayer(IPv6): - capture.remove(p) - return capture - def verify_capture_ip4(self, src_if, capture, sent, ping_resp=0): try: - capture = self.verify_filter(capture, sent) + capture = verify_filter(capture, sent) self.assertEqual(len(capture), len(sent)) @@ -158,33 +181,10 @@ class TestMPLS(VppTestCase): except: raise - def verify_mpls_stack(self, rx, mpls_labels, ttl=255, num=0): - # the rx'd packet has the MPLS label popped - eth = rx[Ether] - self.assertEqual(eth.type, 0x8847) - - rx_mpls = rx[MPLS] - - for ii in range(len(mpls_labels)): - self.assertEqual(rx_mpls.label, mpls_labels[ii]) - self.assertEqual(rx_mpls.cos, 0) - if ii == num: - self.assertEqual(rx_mpls.ttl, ttl) - else: - self.assertEqual(rx_mpls.ttl, 255) - - if ii == len(mpls_labels) - 1: - self.assertEqual(rx_mpls.s, 1) - else: - # not end of stack - self.assertEqual(rx_mpls.s, 0) - # pop the label to expose the next - rx_mpls = rx_mpls[MPLS].payload - def verify_capture_labelled_ip4(self, src_if, capture, sent, mpls_labels): try: - capture = self.verify_filter(capture, sent) + capture = verify_filter(capture, sent) self.assertEqual(len(capture), len(sent)) @@ -195,8 +195,8 @@ class TestMPLS(VppTestCase): rx_ip = rx[IP] # the MPLS TTL is copied from the IP - self.verify_mpls_stack( - rx, mpls_labels, rx_ip.ttl, len(mpls_labels) - 1) + verify_mpls_stack(self, rx, mpls_labels, rx_ip.ttl, + len(mpls_labels) - 1) self.assertEqual(rx_ip.src, tx_ip.src) self.assertEqual(rx_ip.dst, tx_ip.dst) @@ -211,7 +211,7 @@ class TestMPLS(VppTestCase): if top is None: top = len(mpls_labels) - 1 try: - capture = self.verify_filter(capture, sent) + capture = verify_filter(capture, sent) self.assertEqual(len(capture), len(sent)) @@ -222,8 +222,7 @@ class TestMPLS(VppTestCase): rx_ip = rx[IP] # the MPLS TTL is 255 since it enters a new tunnel - self.verify_mpls_stack( - rx, mpls_labels, ttl, top) + verify_mpls_stack(self, rx, mpls_labels, ttl, top) self.assertEqual(rx_ip.src, tx_ip.src) self.assertEqual(rx_ip.dst, tx_ip.dst) @@ -236,13 +235,13 @@ class TestMPLS(VppTestCase): def verify_capture_labelled(self, src_if, capture, sent, mpls_labels, ttl=254, num=0): try: - capture = self.verify_filter(capture, sent) + capture = verify_filter(capture, sent) self.assertEqual(len(capture), len(sent)) for i in range(len(capture)): rx = capture[i] - self.verify_mpls_stack(rx, mpls_labels, ttl, num) + verify_mpls_stack(self, rx, mpls_labels, ttl, num) except: raise @@ -1049,7 +1048,7 @@ class TestMPLS(VppTestCase): self.pg1.sw_if_index, nh_table_id=1, rpf_id=55, - is_ip6=1)], + proto=DpoProto.DPO_PROTO_IP6)], is_multicast=1) route_34_eos.add_vpp_config() @@ -1440,19 +1439,20 @@ class TestMPLSPIC(VppTestCase): for ii in range(64): dst = "3000::%d" % ii local_label = 1600 + ii - vpn_routes.append(VppIpRoute(self, dst, 128, - [VppRoutePath(self.pg2.remote_ip6, - 0xffffffff, - nh_table_id=1, - is_resolve_attached=1, - is_ip6=1), - VppRoutePath(self.pg3.remote_ip6, - 0xffffffff, - nh_table_id=1, - is_ip6=1, - is_resolve_attached=1)], - table_id=1, - is_ip6=1)) + vpn_routes.append(VppIpRoute( + self, dst, 128, + [VppRoutePath(self.pg2.remote_ip6, + 0xffffffff, + nh_table_id=1, + is_resolve_attached=1, + proto=DpoProto.DPO_PROTO_IP6), + VppRoutePath(self.pg3.remote_ip6, + 0xffffffff, + nh_table_id=1, + proto=DpoProto.DPO_PROTO_IP6, + is_resolve_attached=1)], + table_id=1, + is_ip6=1)) vpn_routes[ii].add_vpp_config() vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 128, @@ -1525,5 +1525,211 @@ class TestMPLSPIC(VppTestCase): self.assertNotEqual(0, len(rx1)) +class TestMPLSL2(VppTestCase): + """ MPLS-L2 """ + + def setUp(self): + super(TestMPLSL2, self).setUp() + + # create 2 pg interfaces + self.create_pg_interfaces(range(2)) + + # use pg0 as the core facing interface + self.pg0.admin_up() + self.pg0.config_ip4() + self.pg0.resolve_arp() + self.pg0.enable_mpls() + + # use the other 2 for customer facg L2 links + for i in self.pg_interfaces[1:]: + i.admin_up() + + def tearDown(self): + super(TestMPLSL2, self).tearDown() + for i in self.pg_interfaces[1:]: + i.admin_down() + + self.pg0.disable_mpls() + self.pg0.unconfig_ip4() + self.pg0.admin_down() + + def verify_capture_tunneled_ethernet(self, capture, sent, mpls_labels, + ttl=255, top=None): + if top is None: + top = len(mpls_labels) - 1 + + capture = verify_filter(capture, sent) + + self.assertEqual(len(capture), len(sent)) + + for i in range(len(capture)): + tx = sent[i] + rx = capture[i] + + # the MPLS TTL is 255 since it enters a new tunnel + verify_mpls_stack(self, rx, mpls_labels, ttl, top) + + tx_eth = tx[Ether] + rx_eth = Ether(str(rx[MPLS].payload)) + + self.assertEqual(rx_eth.src, tx_eth.src) + self.assertEqual(rx_eth.dst, tx_eth.dst) + + def test_vpws(self): + """ Virtual Private Wire Service """ + + # + # Create an MPLS tunnel that pushes 1 label + # + mpls_tun_1 = VppMPLSTunnelInterface(self, + [VppRoutePath(self.pg0.remote_ip4, + self.pg0.sw_if_index, + labels=[42])], + is_l2=1) + mpls_tun_1.add_vpp_config() + mpls_tun_1.admin_up() + + # + # Create a label entry to for 55 that does L2 input to the tunnel + # + route_55_eos = VppMplsRoute( + self, 55, 1, + [VppRoutePath("0.0.0.0", + mpls_tun_1.sw_if_index, + is_interface_rx=1, + proto=DpoProto.DPO_PROTO_ETHERNET)]) + route_55_eos.add_vpp_config() + + # + # Cross-connect the tunnel with one of the customers L2 interfaces + # + self.vapi.sw_interface_set_l2_xconnect(self.pg1.sw_if_index, + mpls_tun_1.sw_if_index, + enable=1) + self.vapi.sw_interface_set_l2_xconnect(mpls_tun_1.sw_if_index, + self.pg1.sw_if_index, + enable=1) + + # + # inject a packet from the core + # + pcore = (Ether(dst=self.pg0.local_mac, + src=self.pg0.remote_mac) / + MPLS(label=55, ttl=64) / + Ether(dst="00:00:de:ad:ba:be", + src="00:00:de:ad:be:ef") / + IP(src="10.10.10.10", dst="11.11.11.11") / + UDP(sport=1234, dport=1234) / + Raw('\xa5' * 100)) + + self.pg0.add_stream(pcore * 65) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx0 = self.pg1.get_capture(65) + tx = pcore[MPLS].payload + + self.assertEqual(rx0[0][Ether].dst, tx[Ether].dst) + self.assertEqual(rx0[0][Ether].src, tx[Ether].src) + + # + # Inject a packet from the custoer/L2 side + # + self.pg1.add_stream(tx * 65) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx0 = self.pg0.get_capture(65) + + self.verify_capture_tunneled_ethernet(rx0, tx*65, [42]) + + def test_vpls(self): + """ Virtual Private LAN Service """ + # + # Create an L2 MPLS tunnel + # + mpls_tun = VppMPLSTunnelInterface(self, + [VppRoutePath(self.pg0.remote_ip4, + self.pg0.sw_if_index, + labels=[42])], + is_l2=1) + mpls_tun.add_vpp_config() + mpls_tun.admin_up() + + # + # Create a label entry to for 55 that does L2 input to the tunnel + # + route_55_eos = VppMplsRoute( + self, 55, 1, + [VppRoutePath("0.0.0.0", + mpls_tun.sw_if_index, + is_interface_rx=1, + proto=DpoProto.DPO_PROTO_ETHERNET)]) + route_55_eos.add_vpp_config() + + # + # add to tunnel to the customers bridge-domain + # + self.vapi.sw_interface_set_l2_bridge(mpls_tun.sw_if_index, + bd_id=1) + self.vapi.sw_interface_set_l2_bridge(self.pg1.sw_if_index, + bd_id=1) + + # + # Packet from the customer interface and from the core + # + p_cust = (Ether(dst="00:00:de:ad:ba:be", + src="00:00:de:ad:be:ef") / + IP(src="10.10.10.10", dst="11.11.11.11") / + UDP(sport=1234, dport=1234) / + Raw('\xa5' * 100)) + p_core = (Ether(src="00:00:de:ad:ba:be", + dst="00:00:de:ad:be:ef") / + IP(dst="10.10.10.10", src="11.11.11.11") / + UDP(sport=1234, dport=1234) / + Raw('\xa5' * 100)) + + # + # The BD is learning, so send in one of each packet to learn + # + p_core_encap = (Ether(dst=self.pg0.local_mac, + src=self.pg0.remote_mac) / + MPLS(label=55, ttl=64) / + p_core) + + self.pg1.add_stream(p_cust) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + self.pg0.add_stream(p_core_encap) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + # we've learnt this so expect it be be forwarded + rx0 = self.pg1.get_capture(1) + + self.assertEqual(rx0[0][Ether].dst, p_core[Ether].dst) + self.assertEqual(rx0[0][Ether].src, p_core[Ether].src) + + # + # now a stream in each direction + # + self.pg1.add_stream(p_cust * 65) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx0 = self.pg0.get_capture(65) + + self.verify_capture_tunneled_ethernet(rx0, p_cust*65, [42]) + + # + # remove interfaces from customers bridge-domain + # + self.vapi.sw_interface_set_l2_bridge(mpls_tun.sw_if_index, + bd_id=1, + enable=0) + self.vapi.sw_interface_set_l2_bridge(self.pg1.sw_if_index, + bd_id=1, + enable=0) + if __name__ == '__main__': unittest.main(testRunner=VppTestRunner) diff --git a/test/test_p2p_ethernet.py b/test/test_p2p_ethernet.py index 37a1d18b..8688f7e6 100644 --- a/test/test_p2p_ethernet.py +++ b/test/test_p2p_ethernet.py @@ -11,7 +11,7 @@ from scapy.layers.inet6 import IPv6 from framework import VppTestCase, VppTestRunner, running_extended_tests from vpp_sub_interface import VppP2PSubint -from vpp_ip_route import VppIpRoute, VppRoutePath +from vpp_ip_route import VppIpRoute, VppRoutePath, DpoProto from util import mactobinary @@ -219,7 +219,7 @@ class P2PEthernetIPV6(VppTestCase): route_8000 = VppIpRoute(self, "8000::", 64, [VppRoutePath(self.pg0.remote_ip6, self.pg0.sw_if_index, - is_ip6=1)], + proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) route_8000.add_vpp_config() @@ -239,7 +239,7 @@ class P2PEthernetIPV6(VppTestCase): route_9001 = VppIpRoute(self, "9001::", 64, [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index, - is_ip6=1)], + proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) route_9001.add_vpp_config() @@ -264,7 +264,7 @@ class P2PEthernetIPV6(VppTestCase): route_3 = VppIpRoute(self, "9000::", 64, [VppRoutePath(self.pg1._remote_hosts[0].ip6, self.pg1.sw_if_index, - is_ip6=1)], + proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) route_3.add_vpp_config() @@ -289,7 +289,7 @@ class P2PEthernetIPV6(VppTestCase): route_9001 = VppIpRoute(self, "9000::", 64, [VppRoutePath(self.pg1._remote_hosts[0].ip6, self.pg1.sw_if_index, - is_ip6=1)], + proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) route_9001.add_vpp_config() @@ -310,19 +310,19 @@ class P2PEthernetIPV6(VppTestCase): route_8000 = VppIpRoute(self, "8000::", 64, [VppRoutePath(self.pg0.remote_ip6, self.pg0.sw_if_index, - is_ip6=1)], + proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) route_8000.add_vpp_config() route_8001 = VppIpRoute(self, "8001::", 64, [VppRoutePath(self.p2p_sub_ifs[0].remote_ip6, self.p2p_sub_ifs[0].sw_if_index, - is_ip6=1)], + proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) route_8001.add_vpp_config() route_8002 = VppIpRoute(self, "8002::", 64, [VppRoutePath(self.p2p_sub_ifs[1].remote_ip6, self.p2p_sub_ifs[1].sw_if_index, - is_ip6=1)], + proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) route_8002.add_vpp_config() diff --git a/test/vpp_ip_route.py b/test/vpp_ip_route.py index badb3102..2c489e3c 100644 --- a/test/vpp_ip_route.py +++ b/test/vpp_ip_route.py @@ -29,6 +29,14 @@ class MRouteEntryFlags: MFIB_ENTRY_FLAG_INHERIT_ACCEPT = 8 +class DpoProto: + DPO_PROTO_IP4 = 0 + DPO_PROTO_IP6 = 1 + DPO_PROTO_MPLS = 2 + DPO_PROTO_ETHERNET = 3 + DPO_PROTO_NSH = 4 + + def find_route(test, ip_addr, len, table_id=0, inet=AF_INET): if inet == AF_INET: s = 4 @@ -55,22 +63,24 @@ class VppRoutePath(object): nh_table_id=0, labels=[], nh_via_label=MPLS_LABEL_INVALID, - is_ip6=0, rpf_id=0, is_interface_rx=0, is_resolve_host=0, - is_resolve_attached=0): + is_resolve_attached=0, + proto=DpoProto.DPO_PROTO_IP4): self.nh_itf = nh_sw_if_index self.nh_table_id = nh_table_id self.nh_via_label = nh_via_label self.nh_labels = labels self.weight = 1 self.rpf_id = rpf_id - self.is_ip4 = 1 if is_ip6 == 0 else 0 - if self.is_ip4: + self.proto = proto + if self.proto is DpoProto.DPO_PROTO_IP6: + self.nh_addr = inet_pton(AF_INET6, nh_addr) + elif self.proto is DpoProto.DPO_PROTO_IP4: self.nh_addr = inet_pton(AF_INET, nh_addr) else: - self.nh_addr = inet_pton(AF_INET6, nh_addr) + self.nh_addr = inet_pton(AF_INET6, "::") self.is_resolve_host = is_resolve_host self.is_resolve_attached = is_resolve_attached self.is_interface_rx = is_interface_rx @@ -401,7 +411,7 @@ class VppMplsRoute(VppObject): self._test.vapi.mpls_route_add_del( self.local_label, self.eos_bit, - path.is_ip4, + path.proto, path.nh_addr, path.nh_itf, is_multicast=self.is_multicast, @@ -420,7 +430,7 @@ class VppMplsRoute(VppObject): for path in self.paths: self._test.vapi.mpls_route_add_del(self.local_label, self.eos_bit, - 1, + path.proto, path.nh_addr, path.nh_itf, is_rpf_id=path.is_rpf_id, diff --git a/test/vpp_mpls_tunnel_interface.py b/test/vpp_mpls_tunnel_interface.py index f2001574..0542b05c 100644 --- a/test/vpp_mpls_tunnel_interface.py +++ b/test/vpp_mpls_tunnel_interface.py @@ -9,13 +9,14 @@ class VppMPLSTunnelInterface(VppInterface): VPP MPLS Tunnel interface """ - def __init__(self, test, paths, is_multicast=0): + def __init__(self, test, paths, is_multicast=0, is_l2=0): """ Create MPLS Tunnel interface """ self._sw_if_index = 0 super(VppMPLSTunnelInterface, self).__init__(test) self._test = test self.t_paths = paths self.is_multicast = is_multicast + self.is_l2 = is_l2 def add_vpp_config(self): self._sw_if_index = 0xffffffff @@ -29,7 +30,8 @@ class VppMPLSTunnelInterface(VppInterface): path.weight, next_hop_out_label_stack=path.nh_labels, next_hop_n_out_labels=len(path.nh_labels), - is_multicast=self.is_multicast) + is_multicast=self.is_multicast, + l2_only=self.is_l2) self._sw_if_index = reply.sw_if_index def remove_vpp_config(self): diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py index 801a6c2d..3ba2ad4a 100644 --- a/test/vpp_papi_provider.py +++ b/test/vpp_papi_provider.py @@ -921,7 +921,7 @@ class VppPapiProvider(object): self, label, eos, - next_hop_proto_is_ip4, + next_hop_proto, next_hop_address, next_hop_sw_if_index=0xFFFFFFFF, table_id=0, @@ -982,7 +982,7 @@ class VppPapiProvider(object): 'mr_is_resolve_attached': is_resolve_attached, 'mr_is_interface_rx': is_interface_rx, 'mr_is_rpf_id': is_rpf_id, - 'mr_next_hop_proto_is_ip4': next_hop_proto_is_ip4, + 'mr_next_hop_proto': next_hop_proto, 'mr_next_hop_weight': next_hop_weight, 'mr_next_hop': next_hop_address, 'mr_next_hop_n_out_labels': next_hop_n_out_labels, -- cgit 1.2.3-korg From 609707ea530de6a0f9fa989b8269b973dd89174e Mon Sep 17 00:00:00 2001 From: John Lo Date: Tue, 19 Sep 2017 21:45:10 -0400 Subject: Fix DHCP client so it works for worker threads Fix dhcp_client_for_us() function to utilize rpc_call_main_thread to call vlib_process_signal_event() to ensure proper handling irrespective of it being called in main thread or worker thread. Added ASSERT to vlib_process_sinal.. path to make sure it is called in main thread. Change-Id: I4109cc049d8e4225d896ce492ce201011dc9c911 Signed-off-by: John Lo --- src/vlib/node_funcs.h | 3 +++ src/vnet/dhcp/client.c | 16 ++++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) (limited to 'src/vnet/dhcp/client.c') diff --git a/src/vlib/node_funcs.h b/src/vlib/node_funcs.h index 0059b9be..3ae4e541 100644 --- a/src/vlib/node_funcs.h +++ b/src/vlib/node_funcs.h @@ -851,6 +851,9 @@ vlib_process_signal_event_data (vlib_main_t * vm, vlib_process_t *p = vec_elt (nm->processes, n->runtime_index); uword *h, t; + /* Must be in main thread */ + ASSERT (vlib_get_thread_index () == 0); + h = hash_get (p->event_type_index_by_type_opaque, type_opaque); if (!h) { diff --git a/src/vnet/dhcp/client.c b/src/vnet/dhcp/client.c index dd5e99f2..5986438b 100644 --- a/src/vnet/dhcp/client.c +++ b/src/vnet/dhcp/client.c @@ -120,6 +120,17 @@ set_l2_rewrite (dhcp_client_main_t * dcm, dhcp_client_t * c) 0 /* broadcast */); } +void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length); + +static void +dhcp_client_proc_callback (uword * client_index) +{ + vlib_main_t *vm = vlib_get_main (); + ASSERT (vlib_get_thread_index () == 0); + vlib_process_signal_event (vm, dhcp_client_process_node.index, + EVENT_DHCP_CLIENT_WAKEUP, *client_index); +} + /* * dhcp_client_for_us - server-to-client callback. * Called from proxy_node.c:dhcp_proxy_to_client_input(). @@ -251,8 +262,9 @@ int dhcp_client_for_us (u32 bi, vlib_buffer_t * b, c->retry_count = 0; c->next_transmit = 0; /* send right now... */ /* Poke the client process, which will send the request */ - vlib_process_signal_event (vm, dhcp_client_process_node.index, - EVENT_DHCP_CLIENT_WAKEUP, c - dcm->clients); + uword client_id = c - dcm->clients; + vl_api_rpc_call_main_thread (dhcp_client_proc_callback, + (u8 *) &client_id, sizeof (uword)); break; case DHCP_BOUND: -- cgit 1.2.3-korg