/* * 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 #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; #define foreach_dhcp_sent_packet_stat \ _(DISCOVER, "DHCP discover packets sent") \ _(OFFER, "DHCP offer packets sent") \ _(REQUEST, "DHCP request packets sent") \ _(ACK, "DHCP ack packets sent") #define foreach_dhcp_error_counter \ _(NOT_FOR_US, "DHCP packets for other hosts, dropped") \ _(NAK, "DHCP nak packets received") \ _(NON_OFFER_DISCOVER, "DHCP non-offer packets in discover state") \ _(ODDBALL, "DHCP non-ack, non-offer packets received") \ _(BOUND, "DHCP bind success") typedef enum { #define _(sym,str) DHCP_STAT_##sym, foreach_dhcp_sent_packet_stat foreach_dhcp_error_counter #undef _ DHCP_STAT_UNKNOWN, DHCP_STAT_N_STAT, } sample_error_t; static char *dhcp_client_process_stat_strings[] = { #define _(sym,string) string, foreach_dhcp_sent_packet_stat foreach_dhcp_error_counter #undef _ "DHCP unknown packets sent", }; 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 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); } static void dhcp_client_addr_callback (dhcp_client_t * c) { dhcp_client_main_t *dcm = &dhcp_client_main; /* disable the feature */ vnet_feature_enable_disable ("ip4-unicast", "ip4-dhcp-client-detect", c->sw_if_index, 0 /* disable */ , 0, 0); c->client_detect_feature_enabled = 0; /* if renewing the lease, the address and route have already been added */ if (c->state == DHCP_BOUND) return; /* add the address to the interface */ 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, }; /* *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* */ } if (c->dhcp_server.as_u32) { ip46_address_t dst = { .ip4 = c->dhcp_server, }; c->ai_ucast = adj_nbr_add_or_lock (FIB_PROTOCOL_IP4, VNET_LINK_IP4, &dst, c->sw_if_index); } /* * Call the user's event callback to report DHCP information */ if (c->event_callback) c->event_callback (c->client_index, c); } /* * 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; /* Packet not for us? Turf it... */ if (memcmp (dhcp->client_hardware_address, c->client_hardware_address, sizeof (c->client_hardware_address))) { vlib_node_increment_counter (vm, dhcp_client_process_node.index, DHCP_STAT_NOT_FOR_US, 1); 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; c->dhcp_server.as_u32 = dhcp->server_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]); // for debug: lease_time_in_seconds = 20; /*$$$$*/ 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 6: /* domain server address */ { vec_free (c->domain_server_address); vec_validate (c->domain_server_address, o->length / sizeof (ip4_address_t) - 1); clib_memcpy (c->domain_server_address, o->data, o->length); } 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) { vlib_node_increment_counter (vm, dhcp_client_process_node.index, DHCP_STAT_NON_OFFER_DISCOVER, 1); 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 */ 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: case DHCP_REQUEST: if (dhcp_message_type == DHCP_PACKET_NAK) {
From 3609c4fb4d07d4285e96187598f54cb21e9e9b08 Mon Sep 17 00:00:00 2001
From: Shesha Sreenivasamurthy <shesha@cisco.com>
Date: Wed, 2 Sep 2015 08:57:24 -0700
Subject: [PATCH 2/9] mbuf: rearrange rte_mbuf metadata to suit vpp

Offload structure in the second cache line, next pointer in the
first cache line. Issue reported to Intel.
---
 .../linuxapp/eal/include/exec-env/rte_kni_common.h | 10 +++++++--
 lib/librte_mbuf/rte_mbuf.h                         | 25 ++++++++++++++--------
 2 files changed, 24 insertions(+), 11 deletions(-)

diff --git a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_kni_common.h b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_kni_common.h
index e9f38bd..d327f71 100644
--- a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_kni_common.h
+++ b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_kni_common.h
@@ -111,6 +111,10 @@ struct rte_kni_fifo {
  * The kernel image of the rte_mbuf struct, with only the relevant fields.
  * Padding is necessary to assure the offsets of these fields
  */
+/*
+ * offload in the second cache line, next in the first. Better for vpp
+ * at least as of right now.
+ */
 struct rte_kni_mbuf {
 	void *buf_addr __attribute__((__aligned__(RTE_CACHE_LINE_SIZE)));
 	char pad0[10];
@@ -121,16 +125,18 @@ struct rte_kni_mbuf {
 	char pad2[4];
 	uint32_t pkt_len;       /**< Total pkt len: sum of all segment data_len. */
 	uint16_t data_len;      /**< Amount of data in segment buffer. */
+	char pad3[2];
 #else
 	char pad2[2];
 	uint16_t data_len;      /**< Amount of data in segment buffer. */
 	uint32_t pkt_len;       /**< Total pkt len: sum of all segment data_len. */
+	char pad3[4];
 #endif
+	void *next;
 
 	/* fields on second cache line */
-	char pad3[8] __attribute__((__aligned__(RTE_CACHE_LINE_SIZE)));
+	char pad4[12] __attribute__((__aligned__(RTE_CACHE_LINE_SIZE)));
 	void *pool;
-	void *next;
 };
 
 /*
diff --git a/lib/librte_mbuf/rte_mbuf.h b/lib/librte_mbuf/rte_mbuf.h
index 8c2db1b..61cbbd7 100644
--- a/lib/librte_mbuf/rte_mbuf.h
+++ b/lib/librte_mbuf/rte_mbuf.h
@@ -743,6 +743,12 @@ typedef uint64_t MARKER64[0]; /**< marker that allows us to overwrite 8 bytes
 /**
  * The generic rte_mbuf, containing a packet mbuf.
  */
+/*
+ * offload in the second cache line, next in the first. Better for vpp 
+ * at least as of right now.
+ * If you change this structure, you must change the user-mode
+ * version in rte_mbuf.h
+ */
 struct rte_mbuf {
 	MARKER cacheline0;
 
@@ -809,6 +815,16 @@ struct rte_mbuf {
 	uint16_t vlan_tci;        /**< VLAN Tag Control Identifier (CPU order) */
 	uint16_t vlan_tci_outer;  /**< Outer VLAN Tag Control Identifier (CPU order) */
 #endif /* RTE_NEXT_ABI */
+	struct rte_mbuf *next;    /**< Next segment of scattered packet. */
+
+	uint32_t seqn; /**< Sequence number. See also rte_reorder_insert() */
+#ifdef RTE_NEXT_ABI
+	uint16_t vlan_tci_outer;  /**< Outer VLAN Tag Control Identifier (CPU order) */
+#endif /* RTE_NEXT_ABI */
+
+	/* second cache line - fields only used in slow path or on TX */
+	MARKER cacheline1 __rte_cache_aligned;
+
 	union {
 		uint32_t rss;     /**< RSS hash result if RSS enabled */
 		struct {
@@ -828,21 +844,12 @@ struct rte_mbuf {
 		uint32_t usr;	  /**< User defined tags. See rte_distributor_process() */
 	} hash;                   /**< hash information */
 
-	uint32_t seqn; /**< Sequence number. See also rte_reorder_insert() */
-#ifdef RTE_NEXT_ABI
-	uint16_t vlan_tci_outer;  /**< Outer VLAN Tag Control Identifier (CPU order) */
-#endif /* RTE_NEXT_ABI */
-
-	/* second cache line - fields only used in slow path or on TX */
-	MARKER cacheline1 __rte_cache_aligned;
-
 	union {
 		void *userdata;   /**< Can be used for external metadata */
 		uint64_t udata64; /**< Allow 8-byte userdata on 32-bit */
 	};
 
 	struct rte_mempool *pool; /**< Pool from which mbuf was allocated. */
-	struct rte_mbuf *next;    /**< Next segment of scattered packet. */
 
 	/* fields to support TX offloads */
 	union {
-- 
2.5.0
"addr %U/%d gw %U", format_ip4_address, &c->leased_address, c->subnet_mask_width, format_ip4_address, &c->router_address); vec_foreach (addr, c->domain_server_address) s = format (s, " dns %U", format_ip4_address, addr); } else { s = format (s, "no address\n"); } if (verbose) { s = format (s, "\n lease: lifetime:%d renewal-interval:%d expires:%.2f (now:%.2f)", c->lease_lifetime, c->lease_renewal_interval, c->lease_expires, vlib_time_now (dcm->vlib_main)); s = format (s, "\n retry-count:%d, next-xmt:%.2f", c->retry_count, c->next_transmit); s = format (s, "\n adjacencies:[unicast:%d broadcast:%d]", c->ai_ucast, c->ai_bcast); } 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; } /* *INDENT-OFF* */ pool_foreach (c, dcm->clients, ({ vlib_cli_output (vm, "%U", format_dhcp_client, dcm, c, verbose); })); /* *INDENT-ON* */ return 0; } /* *INDENT-OFF* */ 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, }; /* *INDENT-ON* */ 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_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) { dhcp_maybe_register_udp_ports (DHCP_PORT_REG_CLIENT); pool_get (dcm->clients, c); clib_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; c->set_broadcast_flag = a->set_broadcast_flag; c->dscp = a->dscp; c->ai_ucast = ADJ_INDEX_INVALID; c->ai_bcast = adj_nbr_add_or_lock (FIB_PROTOCOL_IP4, VNET_LINK_IP4, &ADJ_BCAST_ADDR, c->sw_if_index); do { c->transaction_id = random_u32 (&dcm->seed); } while (c->transaction_id == 0); hash_set (dcm->client_by_sw_if_index, a->sw_if_index, c - dcm->clients); /* * 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 */ vnet_feature_enable_disable ("ip4-unicast", "ip4-dhcp-client-detect", c->sw_if_index, 1 /* enable */ , 0, 0); c->client_detect_feature_enabled = 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]); 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, DPO_PROTO_IP4, &nh, c->sw_if_index, ~0, 1, FIB_ROUTE_PATH_FLAG_NONE); } dhcp_client_release_address (dcm, c); adj_unlock (c->ai_ucast); adj_unlock (c->ai_bcast); vec_free (c->domain_server_address); vec_free (c->option_55_data); vec_free (c->hostname); vec_free (c->client_identifier); hash_unset (dcm->client_by_sw_if_index, c->sw_if_index); pool_put (dcm->clients, c); } return 0; } int dhcp_client_config (u32 is_add, u32 client_index, vlib_main_t * vm, u32 sw_if_index, u8 * hostname, u8 * client_id, dhcp_event_cb_t event_callback, u8 set_broadcast_flag, ip_dscp_t dscp, u32 pid) { dhcp_client_add_del_args_t _a, *a = &_a; int rv; clib_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; a->set_broadcast_flag = set_broadcast_flag; a->dscp = dscp; 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); 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. */ /* 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; } void dhcp_client_walk (dhcp_client_walk_cb_t cb, void *ctx) { dhcp_client_main_t *dcm = &dhcp_client_main; dhcp_client_t *c; /* *INDENT-OFF* */ pool_foreach (c, dcm->clients, ({ if (!cb(c, ctx)) break; })); /* *INDENT-ON* */ } 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; u8 set_broadcast_flag = 1; 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 if (unformat (input, "broadcast", &set_broadcast_flag)) is_add = 0; else break; } if (sw_if_index_set == 0) return clib_error_return (0, "interface not specified"); clib_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); a->set_broadcast_flag = set_broadcast_flag; /* * 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; } /* *INDENT-OFF* */ 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, }; /* *INDENT-ON* */ 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 = (u32) clib_cpu_time_now (); return 0; } VLIB_INIT_FUNCTION (dhcp_client_init); /* * fd.io coding-style-patch-verification: ON * * Local Variables: * eval: (c-set-style "gnu") * End: */