- /* 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];
- 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);
-
- /* 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 = proxy->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 = proxy->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)
- {
- 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, 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;
- 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;
-
- /*
- * 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))
- {
- 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 =
- proxy->dhcp_servers[0].dhcp_server.ip4.as_u32;
- }
-
- do_enqueue:
+ /* 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];
+ 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;
+ }
+
+ space_left = vlib_buffer_chain_linearize (vm, b0);
+ /* cant parse chains...
+ * and we need some space for option 82*/
+ if ((b0->flags & VLIB_BUFFER_NEXT_PRESENT) != 0 ||
+ space_left < VPP_DHCP_OPTION82_SIZE)
+ {
+ error0 = DHCP_PROXY_ERROR_PKT_TOO_BIG;
+ next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_DROP;
+ pkts_too_big++;
+ goto do_trace;
+ }
+
+ server = &proxy->dhcp_servers[0];
+ 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 = proxy->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 = proxy->dhcp_src_address.ip4;
+ pkts_to_server++;
+
+ o = h0->options;
+ end = (void *) vlib_buffer_get_tail (b0);
+
+ /* TLVs are not performance-friendly... */
+ while (o->option != DHCP_PACKET_OPTION_END && o < end)
+ {
+ if (DHCP_PACKET_OPTION_MSG_TYPE == o->option)
+ {
+ if (DHCP_PACKET_DISCOVER == o->data[0])
+ {
+ is_discover = 1;
+ }
+ }
+ o = (dhcp_option_t *) (o->data + o->length);
+ }
+
+ if (o->option == DHCP_PACKET_OPTION_END && 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;
+
+ 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 */
+ 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 */
+ u32 *o_addr = (u32 *) & o->data[8];
+ *o_addr = ia0->as_u32;
+ o->data[12] = DHCP_PACKET_OPTION_END;
+
+ vss = dhcp_get_vss_info (dpm, fib_index, FIB_PROTOCOL_IP4);
+ 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] = DHCP_PACKET_OPTION_END; /* "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;
+ /* 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;
+
+ /*
+ * 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);
+ vlib_buffer_copy_trace_flag (vm, c0, bi0);
+ VLIB_BUFFER_TRACE_TRAJECTORY_INIT (c0);
+ 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))
+ {
+ 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 =
+ proxy->dhcp_servers[0].dhcp_server.ip4.as_u32;
+ }
+
+ do_enqueue: