X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvnet%2Fdhcp%2Fdhcp4_proxy_node.c;h=cd52be83f7140bdef77f6e94d683f6bd49bf473f;hb=70bfcaf47779340951c1e6f169b1cedcabe708d1;hp=88a99249684aefa3a9eb134fa6dcae3ca0aa98a1;hpb=2dd6852d8109e39d15a5c60f7ba58f1abcf9e455;p=vpp.git diff --git a/src/vnet/dhcp/dhcp4_proxy_node.c b/src/vnet/dhcp/dhcp4_proxy_node.c index 88a99249684..cd52be83f71 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,19 +220,28 @@ 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); + fl = vlib_buffer_get_free_list (vm, vlib_buffer_get_free_list_index (b0)); // 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; @@ -255,65 +264,53 @@ dhcp_proxy_to_server_input (vlib_main_t * vm, 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; + u32 *o_ifid = (u32 *) &o->data[2]; + *o_ifid = clib_host_to_net_u32 (original_sw_if_index); 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]; + u32 *o_addr = (u32 *) &o->data[8]; + *o_addr = ia0->as_u32; 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; - } - } + if (vss) + { + u32 id_len; /* length of VPN ID */ + + if (vss->vss_type == VSS_TYPE_VPN_ID) + { + id_len = sizeof (vss->vpn_id); /* vpn_id is 7 bytes */ + memcpy (&o->data[15], vss->vpn_id, id_len); + } + else if (vss->vss_type == VSS_TYPE_ASCII) + { + id_len = vec_len (vss->vpn_ascii_id); + memcpy (&o->data[15], vss->vpn_ascii_id, id_len); + } + else /* must be VSS_TYPE_DEFAULT, no VPN ID */ + id_len = 0; + + o->data[12] = 151; /* vss suboption */ + o->data[13] = id_len + 1; /* length: vss_type + id_len */ + o->data[14] = vss->vss_type; /* vss option type */ + o->data[15 + id_len] = 152; /* vss control suboption */ + o->data[16 + id_len] = 0; /* length */ + o->data[17 + id_len] = 0xFF; /* "end-of-options" (0xFF) */ + /* 5 bytes for suboption headers 151+len, 152+len and 0xFF */ + o->length += id_len + 5; + } len = o->length + 3; b0->current_length += len; @@ -332,14 +329,75 @@ dhcp_proxy_to_server_input (vlib_main_t * vm, new_l0 = clib_net_to_host_u16 (u0->length); new_l0 += len; u0->length = clib_host_to_net_u16 (new_l0); - } else { + } + 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; + /* + * 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 +408,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 +500,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 +611,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); @@ -705,18 +775,18 @@ dhcp4_proxy_set_server (ip46_address_t *addr, return VNET_API_ERROR_INVALID_SRC_ADDRESS; rx_fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, - rx_table_id); + rx_table_id, + FIB_SOURCE_DHCP); 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, FIB_SOURCE_DHCP); - fib_table_unlock (rx_fib_index, FIB_PROTOCOL_IP4); + fib_table_unlock (rx_fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_DHCP); } } else @@ -728,12 +798,11 @@ 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_table_lock (rx_fib_index, FIB_PROTOCOL_IP4); + FIB_ENTRY_FLAG_LOCAL); + fib_table_lock (rx_fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_DHCP); } } - fib_table_unlock (rx_fib_index, FIB_PROTOCOL_IP4); + fib_table_unlock (rx_fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_DHCP); return (rc); } @@ -809,29 +878,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; @@ -864,54 +939,47 @@ 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; + u8 is_del = 0, vss_type = VSS_TYPE_DEFAULT; + u32 oui = 0, fib_id = 0, tbl_id = ~0; + u8 *vpn_ascii_id = 0; while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) { - - if (unformat(input, "delete") || unformat(input, "del")) - is_del = 1; + if (unformat (input, "table %d", &tbl_id)) + ; else if (unformat (input, "oui %d", &oui)) - got_new_vpn_id = 1; + vss_type = VSS_TYPE_VPN_ID; 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; + vss_type = VSS_TYPE_VPN_ID; + else if (unformat (input, "vpn-ascii-id %s", &vpn_ascii_id)) + vss_type = VSS_TYPE_ASCII; + else if (unformat(input, "delete") || unformat(input, "del")) + is_del = 1; else - break; - } + break; + } + if (tbl_id == ~0) return clib_error_return (0, "no table ID specified."); - if (is_del || got_new_vpn_id) + int rv = dhcp_proxy_set_vss (FIB_PROTOCOL_IP4, tbl_id, vss_type, + vpn_ascii_id, oui, fib_id, is_del); + switch (rv) { - 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); - } + case 0: + return 0; + 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 ", + .short_help = "set dhcp option-82 vss [del] table
[oui vpn-id | vpn-ascii-id ]", .function = dhcp_option_82_vss_fn, };