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);
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);
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 */,
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;
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;
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;
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))
{
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);
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,
}
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);
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
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);
}
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;
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 <table id> oui <oui> vpn-id <vpn-id>",
+ .short_help = "set dhcp option-82 vss [del] table <table id> [oui <n> vpn-id <n> | vpn-ascii-id <text>]",
.function = dhcp_option_82_vss_fn,
};