aboutsummaryrefslogtreecommitdiffstats
path: root/src/vnet
diff options
context:
space:
mode:
Diffstat (limited to 'src/vnet')
-rw-r--r--src/vnet/dhcp/client.c151
-rw-r--r--src/vnet/dhcp/client.h8
-rw-r--r--src/vnet/dhcp/dhcp.api3
-rw-r--r--src/vnet/dhcp/dhcp_api.c2
-rw-r--r--src/vnet/dhcp/dhcp_client_detect.c333
5 files changed, 397 insertions, 100 deletions
diff --git a/src/vnet/dhcp/client.c b/src/vnet/dhcp/client.c
index 8043bf22d43..03fc2689abf 100644
--- a/src/vnet/dhcp/client.c
+++ b/src/vnet/dhcp/client.c
@@ -22,56 +22,6 @@ 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)
{
/*
@@ -233,13 +183,6 @@ 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;
@@ -267,9 +210,11 @@ 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);
+ /* add the advertised subnet and disable the feature */
dhcp_client_acquire_address (dcm, c);
+ vnet_feature_enable_disable ("ip4-unicast",
+ "ip4-dhcp-client-detect",
+ c->sw_if_index, 0, 0, 0);
/*
* Configure default IP route:
@@ -285,8 +230,19 @@ dhcp_client_for_us (u32 bi, vlib_buffer_t * b,
.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, DPO_PROTO_IP4, &nh, c->sw_if_index, ~0, 1, NULL, // no label stack
- FIB_ROUTE_PATH_FLAG_NONE);
+ /* *INDENT-OFF* */
+ 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,
+ DPO_PROTO_IP4,
+ &nh, c->sw_if_index,
+ ~0, 1, NULL, // no label stack
+ FIB_ROUTE_PATH_FLAG_NONE);
+ /* *INDENT-ON* */
}
/*
@@ -418,7 +374,9 @@ send_dhcp_pkt (dhcp_client_main_t * dcm, dhcp_client_t * c,
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->flags =
+ clib_host_to_net_u16 (is_broadcast && c->set_broadcast_flag ?
+ DHCP_FLAG_BROADCAST : 0);
dhcp->magic_cookie.as_u32 = DHCP_MAGIC;
o = (dhcp_option_t *) dhcp->options;
@@ -676,14 +634,13 @@ dhcp_client_process (vlib_main_t * vm,
break;
case ~0:
- pool_foreach (c, dcm->clients, (
- {
- timeout =
- dhcp_client_sm (now, timeout,
- (uword) (c -
- dcm->clients));
- }
- ));
+ /* *INDENT-OFF* */
+ pool_foreach (c, dcm->clients,
+ ({
+ timeout = dhcp_client_sm (now, timeout,
+ (uword) (c - dcm->clients));
+ }));
+ /* *INDENT-ON* */
if (pool_elts (dcm->clients) == 0)
timeout = 100.0;
break;
@@ -785,13 +742,14 @@ show_dhcp_client_command_fn (vlib_main_t * vm,
return 0;
}
- pool_foreach (c, dcm->clients, (
- {
- vlib_cli_output (vm, "%U",
- format_dhcp_client, dcm,
- c, verbose);
- }
- ));
+ /* *INDENT-OFF* */
+ pool_foreach (c, dcm->clients,
+ ({
+ vlib_cli_output (vm, "%U",
+ format_dhcp_client, dcm,
+ c, verbose);
+ }));
+ /* *INDENT-ON* */
return 0;
}
@@ -812,11 +770,6 @@ dhcp_client_add_del (dhcp_client_add_del_args_t * a)
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,
@@ -840,6 +793,7 @@ dhcp_client_add_del (dhcp_client_add_del_args_t * a)
c->option_55_data = a->option_55_data;
c->hostname = a->hostname;
c->client_identifier = a->client_identifier;
+ c->set_broadcast_flag = a->set_broadcast_flag;
do
{
c->transaction_id = random_u32 (&dcm->seed);
@@ -848,17 +802,18 @@ dhcp_client_add_del (dhcp_client_add_del_args_t * a)
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);
-
/*
- * enable the interface to RX IPv4 packets
- * this is also ref counted
+ * In order to accept any OFFER, whether broadcasted or unicasted, we
+ * need to configure the dhcp-client-detect feature as an input feature
+ * so the DHCP OFFER is sent to the ip4-local node. Without this a
+ * broadcasted OFFER hits the 255.255.255.255/32 address and a unicast
+ * hits 0.0.0.0/0 both of which default to drop and the latter may forward
+ * of box - not what we want. Nor to we want to change these route for
+ * all interfaces in this table
*/
- ip4_sw_interface_enable_disable (c->sw_if_index, 1);
+ vnet_feature_enable_disable ("ip4-unicast",
+ "ip4-dhcp-client-detect",
+ c->sw_if_index, 1, 0, 0);
vlib_process_signal_event (vm, dhcp_client_process_node.index,
EVENT_DHCP_CLIENT_WAKEUP, c - dcm->clients);
@@ -867,10 +822,6 @@ dhcp_client_add_del (dhcp_client_add_del_args_t * a)
{
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 = {
@@ -883,9 +834,7 @@ dhcp_client_add_del (dhcp_client_add_del_args_t * a)
DPO_PROTO_IP4, &nh, c->sw_if_index, ~0,
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);
vec_free (c->option_55_data);
vec_free (c->hostname);
@@ -903,7 +852,8 @@ dhcp_client_config (vlib_main_t * vm,
u8 * hostname,
u8 * client_id,
u32 is_add,
- u32 client_index, void *event_callback, u32 pid)
+ u32 client_index,
+ void *event_callback, u8 set_broadcast_flag, u32 pid)
{
dhcp_client_add_del_args_t _a, *a = &_a;
int rv;
@@ -914,6 +864,7 @@ dhcp_client_config (vlib_main_t * vm,
a->client_index = client_index;
a->pid = pid;
a->event_callback = event_callback;
+ a->set_broadcast_flag = set_broadcast_flag;
vec_validate (a->hostname, strlen ((char *) hostname) - 1);
strncpy ((char *) a->hostname, (char *) hostname, vec_len (a->hostname));
vec_validate (a->client_identifier, strlen ((char *) client_id) - 1);
@@ -990,6 +941,7 @@ dhcp_client_set_command_fn (vlib_main_t * vm,
u32 sw_if_index;
u8 *hostname = 0;
u8 sw_if_index_set = 0;
+ u8 set_broadcast_flag = 1;
int is_add = 1;
dhcp_client_add_del_args_t _a, *a = &_a;
int rv;
@@ -1003,6 +955,8 @@ dhcp_client_set_command_fn (vlib_main_t * vm,
;
else if (unformat (input, "del"))
is_add = 0;
+ else if (unformat (input, "broadcast", &set_broadcast_flag))
+ is_add = 0;
else
break;
}
@@ -1015,6 +969,7 @@ dhcp_client_set_command_fn (vlib_main_t * vm,
a->sw_if_index = sw_if_index;
a->hostname = hostname;
a->client_identifier = format (0, "vpe 1.0%c", 0);
+ a->set_broadcast_flag = set_broadcast_flag;
/*
* Option 55 request list. These data precisely match
diff --git a/src/vnet/dhcp/client.h b/src/vnet/dhcp/client.h
index d9c7e25d0b2..1c2becb3058 100644
--- a/src/vnet/dhcp/client.h
+++ b/src/vnet/dhcp/client.h
@@ -71,6 +71,10 @@ typedef struct
/* Information used for event callback */
u32 client_index;
u32 pid;
+
+ /* Set the broadcast Flag in the Discover/Request messages */
+ u8 set_broadcast_flag;
+
void *event_callback;
} dhcp_client_t;
@@ -90,6 +94,7 @@ typedef struct
{
int is_add;
u32 sw_if_index;
+ u8 set_broadcast_flag;
/* vectors, consumed by dhcp client code */
u8 *hostname;
@@ -118,7 +123,8 @@ int dhcp_client_config (vlib_main_t * vm,
u8 * hostname,
u8 * client_id,
u32 is_add,
- u32 client_index, void *event_callback, u32 pid);
+ u32 client_index,
+ void *event_callback, u8 set_broadcast_flag, u32 pid);
#endif /* included_dhcp_client_h */
diff --git a/src/vnet/dhcp/dhcp.api b/src/vnet/dhcp/dhcp.api
index 528915a46e9..721a1be3547 100644
--- a/src/vnet/dhcp/dhcp.api
+++ b/src/vnet/dhcp/dhcp.api
@@ -71,6 +71,8 @@ autoreply define dhcp_proxy_set_vss
@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
+ @param set_broadcast_flag - in the DHCP Discover to control
+ how the resulting OFFER is addressed.
@param pid - sender's pid
*/
autoreply define dhcp_client_config
@@ -82,6 +84,7 @@ autoreply define dhcp_client_config
u8 client_id[64];
u8 is_add;
u8 want_dhcp_event;
+ u8 set_broadcast_flag;
u32 pid;
};
diff --git a/src/vnet/dhcp/dhcp_api.c b/src/vnet/dhcp/dhcp_api.c
index 8e210cdd5b0..401f6b75edc 100644
--- a/src/vnet/dhcp/dhcp_api.c
+++ b/src/vnet/dhcp/dhcp_api.c
@@ -248,7 +248,7 @@ static void vl_api_dhcp_client_config_t_handler
mp->hostname, mp->client_id,
mp->is_add, mp->client_index,
mp->want_dhcp_event ? dhcp_compl_event_callback :
- NULL, mp->pid);
+ NULL, mp->set_broadcast_flag, mp->pid);
BAD_SW_IF_INDEX_LABEL;
diff --git a/src/vnet/dhcp/dhcp_client_detect.c b/src/vnet/dhcp/dhcp_client_detect.c
new file mode 100644
index 00000000000..1b916cdd356
--- /dev/null
+++ b/src/vnet/dhcp/dhcp_client_detect.c
@@ -0,0 +1,333 @@
+/*
+ * DHCP feature; applied as an input feature to select DHCP packets
+ *
+ * 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 <vnet/dhcp/client.h>
+#include <vnet/udp/udp.h>
+
+#define foreach_dhcp_client_detect \
+ _(EXTRACT, "Extract")
+
+typedef enum
+{
+#define _(sym,str) DHCP_CLIENT_DETECT_ERROR_##sym,
+ foreach_dhcp_client_detect
+#undef _
+ DHCP_CLIENT_DETECT_N_ERROR,
+} dhcp_client_detect_error_t;
+
+static char *dhcp_client_detect_error_strings[] = {
+#define _(sym,string) string,
+ foreach_dhcp_client_detect
+#undef _
+};
+
+typedef enum
+{
+#define _(sym,str) DHCP_CLIENT_DETECT_NEXT_##sym,
+ foreach_dhcp_client_detect
+#undef _
+ DHCP_CLIENT_DETECT_N_NEXT,
+} dhcp_client_detect_next_t;
+
+/**
+ * per-packet trace data
+ */
+typedef struct dhcp_client_detect_trace_t_
+{
+ /* per-pkt trace data */
+ u8 extracted;
+} dhcp_client_detect_trace_t;
+
+static uword
+dhcp_client_detect_node_fn (vlib_main_t * vm,
+ vlib_node_runtime_t * node, vlib_frame_t * frame)
+{
+ dhcp_client_detect_next_t next_index;
+ u16 dhcp_client_port_network_order;
+ u32 n_left_from, *from, *to_next;
+ u32 extractions;
+
+ dhcp_client_port_network_order =
+ clib_net_to_host_u16 (UDP_DST_PORT_dhcp_to_client);
+ next_index = 0;
+ extractions = 0;
+ n_left_from = frame->n_vectors;
+ from = vlib_frame_vector_args (frame);
+
+ while (n_left_from > 0)
+ {
+ u32 n_left_to_next;
+
+ vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
+
+ /*
+ * This loop is optimised not so we can really quickly process DHCp
+ * offers... but so we can quickly sift them out when the interface
+ * is also receving 'normal' packets
+ */
+ while (n_left_from >= 8 && n_left_to_next >= 4)
+ {
+ udp_header_t *udp0, *udp1, *udp2, *udp3;
+ ip4_header_t *ip0, *ip1, *ip2, *ip3;
+ vlib_buffer_t *b0, *b1, *b2, *b3;
+ u32 next0, next1, next2, next3;
+ u32 bi0, bi1, bi2, bi3;
+
+ next0 = next1 = next2 = next3 = ~0;
+ bi0 = to_next[0] = from[0];
+ bi1 = to_next[1] = from[1];
+ bi2 = to_next[2] = from[2];
+ bi3 = to_next[3] = from[3];
+
+ /* Prefetch next iteration. */
+ {
+ vlib_buffer_t *p2, *p3, *p4, *p5;
+
+ p2 = vlib_get_buffer (vm, from[2]);
+ p3 = vlib_get_buffer (vm, from[3]);
+ p4 = vlib_get_buffer (vm, from[4]);
+ p5 = vlib_get_buffer (vm, from[5]);
+
+ vlib_prefetch_buffer_header (p2, STORE);
+ vlib_prefetch_buffer_header (p3, STORE);
+ vlib_prefetch_buffer_header (p4, STORE);
+ vlib_prefetch_buffer_header (p5, STORE);
+
+ CLIB_PREFETCH (p2->data, sizeof (ip0[0]) + sizeof (udp0[0]),
+ STORE);
+ CLIB_PREFETCH (p3->data, sizeof (ip0[0]) + sizeof (udp0[0]),
+ STORE);
+ CLIB_PREFETCH (p4->data, sizeof (ip0[0]) + sizeof (udp0[0]),
+ STORE);
+ CLIB_PREFETCH (p5->data, sizeof (ip0[0]) + sizeof (udp0[0]),
+ STORE);
+ }
+
+ from += 4;
+ to_next += 4;
+ n_left_from -= 4;
+ n_left_to_next -= 4;
+
+ b0 = vlib_get_buffer (vm, bi0);
+ b1 = vlib_get_buffer (vm, bi1);
+ b2 = vlib_get_buffer (vm, bi2);
+ b3 = vlib_get_buffer (vm, bi3);
+ ip0 = vlib_buffer_get_current (b0);
+ ip1 = vlib_buffer_get_current (b1);
+ ip2 = vlib_buffer_get_current (b2);
+ ip3 = vlib_buffer_get_current (b2);
+
+ vnet_feature_next (vnet_buffer (b0)->sw_if_index[VLIB_TX],
+ &next0, b0);
+ vnet_feature_next (vnet_buffer (b1)->sw_if_index[VLIB_TX],
+ &next1, b1);
+ vnet_feature_next (vnet_buffer (b2)->sw_if_index[VLIB_TX],
+ &next2, b2);
+ vnet_feature_next (vnet_buffer (b3)->sw_if_index[VLIB_TX],
+ &next3, b3);
+
+ if (ip0->protocol == IP_PROTOCOL_UDP)
+ {
+ udp0 = (udp_header_t *) (ip0 + 1);
+
+ if (dhcp_client_port_network_order == udp0->dst_port)
+ {
+ next0 = DHCP_CLIENT_DETECT_NEXT_EXTRACT;
+ extractions++;
+ }
+ }
+ if (ip1->protocol == IP_PROTOCOL_UDP)
+ {
+ udp1 = (udp_header_t *) (ip1 + 1);
+
+ if (dhcp_client_port_network_order == udp1->dst_port)
+ {
+ next1 = DHCP_CLIENT_DETECT_NEXT_EXTRACT;
+ extractions++;
+ }
+ }
+ if (ip2->protocol == IP_PROTOCOL_UDP)
+ {
+ udp2 = (udp_header_t *) (ip2 + 1);
+
+ if (dhcp_client_port_network_order == udp2->dst_port)
+ {
+ next2 = DHCP_CLIENT_DETECT_NEXT_EXTRACT;
+ extractions++;
+ }
+ }
+ if (ip3->protocol == IP_PROTOCOL_UDP)
+ {
+ udp3 = (udp_header_t *) (ip3 + 1);
+
+ if (dhcp_client_port_network_order == udp3->dst_port)
+ {
+ next3 = DHCP_CLIENT_DETECT_NEXT_EXTRACT;
+ extractions++;
+ }
+ }
+
+ if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
+ {
+ dhcp_client_detect_trace_t *t =
+ vlib_add_trace (vm, node, b0, sizeof (*t));
+ t->extracted = (next0 == DHCP_CLIENT_DETECT_NEXT_EXTRACT);
+ }
+ if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
+ {
+ dhcp_client_detect_trace_t *t =
+ vlib_add_trace (vm, node, b1, sizeof (*t));
+ t->extracted = (next1 == DHCP_CLIENT_DETECT_NEXT_EXTRACT);
+ }
+ if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
+ {
+ dhcp_client_detect_trace_t *t =
+ vlib_add_trace (vm, node, b2, sizeof (*t));
+ t->extracted = (next2 == DHCP_CLIENT_DETECT_NEXT_EXTRACT);
+ }
+ if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
+ {
+ dhcp_client_detect_trace_t *t =
+ vlib_add_trace (vm, node, b3, sizeof (*t));
+ t->extracted = (next3 == DHCP_CLIENT_DETECT_NEXT_EXTRACT);
+ }
+
+ /* verify speculative enqueue, maybe switch current next frame */
+ vlib_validate_buffer_enqueue_x4 (vm, node, next_index,
+ to_next, n_left_to_next,
+ bi0, bi1, bi2, bi3,
+ next0, next1, next2, next3);
+ }
+
+ while (n_left_from > 0 && n_left_to_next > 0)
+ {
+ udp_header_t *udp0;
+ vlib_buffer_t *b0;
+ ip4_header_t *ip0;
+ u32 next0 = ~0;
+ u32 bi0;
+
+ 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);
+ ip0 = vlib_buffer_get_current (b0);
+
+ /*
+ * when this feature is applied on an interface that is already
+ * accepting packets (because e.g. the interface has other addresses
+ * assigned) we are looking for the preverbial needle in the haystack
+ * so assume the packet is not the one we are looking for.
+ */
+ vnet_feature_next (vnet_buffer (b0)->sw_if_index[VLIB_TX],
+ &next0, b0);
+
+ /*
+ * all we are looking for here is DHCP/BOOTP packet-to-client
+ * UDO port.
+ */
+ if (ip0->protocol == IP_PROTOCOL_UDP)
+ {
+ udp0 = (udp_header_t *) (ip0 + 1);
+
+ if (dhcp_client_port_network_order == udp0->dst_port)
+ {
+ next0 = DHCP_CLIENT_DETECT_NEXT_EXTRACT;
+ extractions++;
+ }
+ }
+
+ if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
+ {
+ dhcp_client_detect_trace_t *t =
+ vlib_add_trace (vm, node, b0, sizeof (*t));
+ t->extracted = (next0 == DHCP_CLIENT_DETECT_NEXT_EXTRACT);
+ }
+
+ /* verify speculative enqueue, maybe switch current next frame */
+ 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, node->node_index,
+ DHCP_CLIENT_DETECT_ERROR_EXTRACT, extractions);
+
+ return frame->n_vectors;
+}
+
+/* packet trace format function */
+static u8 *
+format_dhcp_client_detect_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_client_detect_trace_t *t =
+ va_arg (*args, dhcp_client_detect_trace_t *);
+
+ s = format (s, "dhcp-client-detect: %s", (t->extracted ? "yes" : "no"));
+
+ return s;
+}
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (dhcp_client_detect_node) = {
+ .function = dhcp_client_detect_node_fn,
+ .name = "ip4-dhcp-client-detect",
+ .vector_size = sizeof (u32),
+ .format_trace = format_dhcp_client_detect_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+
+ .n_errors = ARRAY_LEN(dhcp_client_detect_error_strings),
+ .error_strings = dhcp_client_detect_error_strings,
+
+ .n_next_nodes = DHCP_CLIENT_DETECT_N_NEXT,
+ .next_nodes = {
+ /*
+ * Jump straight to the UDP dispatch node thus avoiding
+ * the RPF checks in ip4-local that will fail
+ */
+ [DHCP_CLIENT_DETECT_NEXT_EXTRACT] = "ip4-udp-lookup",
+ },
+};
+
+VLIB_NODE_FUNCTION_MULTIARCH (dhcp_client_detect_node,
+ dhcp_client_detect_node_fn);
+
+VNET_FEATURE_INIT (ip4_dvr_reinject_feat_node, static) =
+{
+ .arc_name = "ip4-unicast",
+ .node_name = "ip4-dhcp-client-detect",
+ .runs_before = VNET_FEATURES ("ip4-drop"),
+};
+
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */