Skip to content

Commit 177ac2a

Browse files
Merge pull request #24 from vpp-dev/dhcp
DHCP fixes
2 parents fc7ecf6 + 528680a commit 177ac2a

File tree

13 files changed

+594
-121
lines changed

13 files changed

+594
-121
lines changed

src/vnet.am

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -724,7 +724,7 @@ API_FILES += vnet/lisp-gpe/lisp_gpe.api
724724
########################################
725725
libvnet_la_SOURCES += \
726726
vnet/dhcp/client.c \
727-
vnet/dhcp/client.h \
727+
vnet/dhcp/dhcp_client_detect.c \
728728
vnet/dhcp/dhcp_api.c
729729

730730
nobase_include_HEADERS += \

src/vnet/dhcp/client.c

Lines changed: 101 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -21,79 +21,36 @@ dhcp_client_main_t dhcp_client_main;
2121
static u8 *format_dhcp_client_state (u8 * s, va_list * va);
2222
static vlib_node_registration_t dhcp_client_process_node;
2323

24-
#define foreach_dhcp_client_process_stat \
24+
#define foreach_dhcp_sent_packet_stat \
2525
_(DISCOVER, "DHCP discover packets sent") \
2626
_(OFFER, "DHCP offer packets sent") \
2727
_(REQUEST, "DHCP request packets sent") \
2828
_(ACK, "DHCP ack packets sent")
2929

30+
#define foreach_dhcp_error_counter \
31+
_(NOT_FOR_US, "DHCP packets for other hosts, dropped") \
32+
_(NAK, "DHCP nak packets received") \
33+
_(NON_OFFER_DISCOVER, "DHCP non-offer packets in discover state") \
34+
_(ODDBALL, "DHCP non-ack, non-offer packets received") \
35+
_(BOUND, "DHCP bind success")
36+
3037
typedef enum
3138
{
3239
#define _(sym,str) DHCP_STAT_##sym,
33-
foreach_dhcp_client_process_stat
40+
foreach_dhcp_sent_packet_stat foreach_dhcp_error_counter
3441
#undef _
3542
DHCP_STAT_UNKNOWN,
3643
DHCP_STAT_N_STAT,
3744
} sample_error_t;
3845

3946
static char *dhcp_client_process_stat_strings[] = {
4047
#define _(sym,string) string,
41-
foreach_dhcp_client_process_stat
48+
foreach_dhcp_sent_packet_stat foreach_dhcp_error_counter
4249
#undef _
4350
"DHCP unknown packets sent",
4451
};
4552

4653

47-
static void
48-
dhcp_client_add_rx_address (dhcp_client_main_t * dcm, dhcp_client_t * c)
49-
{
50-
/* Install a local entry for the offered address */
51-
fib_prefix_t rx = {
52-
.fp_len = 32,
53-
.fp_addr.ip4 = c->leased_address,
54-
.fp_proto = FIB_PROTOCOL_IP4,
55-
};
56-
57-
fib_table_entry_special_add (fib_table_get_index_for_sw_if_index
58-
(FIB_PROTOCOL_IP4, c->sw_if_index), &rx,
59-
FIB_SOURCE_DHCP, (FIB_ENTRY_FLAG_LOCAL));
60-
61-
/* And add the server's address as uRPF exempt so we can accept
62-
* local packets from it */
63-
fib_prefix_t server = {
64-
.fp_len = 32,
65-
.fp_addr.ip4 = c->dhcp_server,
66-
.fp_proto = FIB_PROTOCOL_IP4,
67-
};
68-
69-
fib_table_entry_special_add (fib_table_get_index_for_sw_if_index
70-
(FIB_PROTOCOL_IP4, c->sw_if_index), &server,
71-
FIB_SOURCE_URPF_EXEMPT, (FIB_ENTRY_FLAG_DROP));
72-
}
73-
74-
static void
75-
dhcp_client_remove_rx_address (dhcp_client_main_t * dcm, dhcp_client_t * c)
76-
{
77-
fib_prefix_t rx = {
78-
.fp_len = 32,
79-
.fp_addr.ip4 = c->leased_address,
80-
.fp_proto = FIB_PROTOCOL_IP4,
81-
};
82-
83-
fib_table_entry_special_remove (fib_table_get_index_for_sw_if_index
84-
(FIB_PROTOCOL_IP4, c->sw_if_index), &rx,
85-
FIB_SOURCE_DHCP);
86-
fib_prefix_t server = {
87-
.fp_len = 32,
88-
.fp_addr.ip4 = c->dhcp_server,
89-
.fp_proto = FIB_PROTOCOL_IP4,
90-
};
91-
92-
fib_table_entry_special_remove (fib_table_get_index_for_sw_if_index
93-
(FIB_PROTOCOL_IP4, c->sw_if_index), &server,
94-
FIB_SOURCE_URPF_EXEMPT);
95-
}
96-
9754
static void
9855
dhcp_client_acquire_address (dhcp_client_main_t * dcm, dhcp_client_t * c)
9956
{
@@ -145,9 +102,11 @@ dhcp_client_addr_callback (dhcp_client_t * c)
145102
dhcp_client_main_t *dcm = &dhcp_client_main;
146103
void (*fp) (u32, u32, u8 *, u8, u8, u8 *, u8 *, u8 *) = c->event_callback;
147104

148-
/* replace the temporary RX address with the correct subnet */
149-
dhcp_client_remove_rx_address (dcm, c);
105+
/* add the advertised subnet and disable the feature */
150106
dhcp_client_acquire_address (dcm, c);
107+
vnet_feature_enable_disable ("ip4-unicast",
108+
"ip4-dhcp-client-detect",
109+
c->sw_if_index, 0 /* disable */ , 0, 0);
151110

152111
/*
153112
* Configure default IP route:
@@ -225,6 +184,15 @@ dhcp_client_for_us (u32 bi, vlib_buffer_t * b,
225184
if (c->state == DHCP_BOUND && c->retry_count == 0)
226185
return 0;
227186

187+
/* Packet not for us? Turf it... */
188+
if (memcmp (dhcp->client_hardware_address, c->client_hardware_address,
189+
sizeof (c->client_hardware_address)))
190+
{
191+
vlib_node_increment_counter (vm, dhcp_client_process_node.index,
192+
DHCP_STAT_NOT_FOR_US, 1);
193+
return 0;
194+
}
195+
228196
/* parse through the packet, learn what we can */
229197
if (dhcp->your_ip_address.as_u32)
230198
c->leased_address.as_u32 = dhcp->your_ip_address.as_u32;
@@ -300,19 +268,11 @@ dhcp_client_for_us (u32 bi, vlib_buffer_t * b,
300268
case DHCP_DISCOVER:
301269
if (dhcp_message_type != DHCP_PACKET_OFFER)
302270
{
303-
clib_warning ("sw_if_index %d state %U message type %d",
304-
c->sw_if_index, format_dhcp_client_state,
305-
c->state, dhcp_message_type);
271+
vlib_node_increment_counter (vm, dhcp_client_process_node.index,
272+
DHCP_STAT_NON_OFFER_DISCOVER, 1);
306273
c->next_transmit = now + 5.0;
307274
break;
308275
}
309-
/*
310-
* in order to accept unicasted ACKs we need to configure the offered
311-
* address on the interface. However, at this point we may not know the
312-
* subnet-mask (an OFFER may not contain it). So add a temporary receice
313-
* and uRPF excempt entry
314-
*/
315-
dhcp_client_add_rx_address (dcm, c);
316276

317277
/* Received an offer, go send a request */
318278
c->state = DHCP_REQUEST;
@@ -326,8 +286,39 @@ dhcp_client_for_us (u32 bi, vlib_buffer_t * b,
326286

327287
case DHCP_BOUND:
328288
case DHCP_REQUEST:
329-
if (dhcp_message_type != DHCP_PACKET_ACK)
289+
if (dhcp_message_type == DHCP_PACKET_NAK)
330290
{
291+
vlib_node_increment_counter (vm, dhcp_client_process_node.index,
292+
DHCP_STAT_NAK, 1);
293+
/* Probably never happens in bound state, but anyhow... */
294+
if (c->state == DHCP_BOUND)
295+
{
296+
ip4_add_del_interface_address (dcm->vlib_main, c->sw_if_index,
297+
(void *) &c->leased_address,
298+
c->subnet_mask_width,
299+
1 /*is_del */ );
300+
vnet_feature_enable_disable ("ip4-unicast",
301+
"ip4-dhcp-client-detect",
302+
c->sw_if_index, 1 /* enable */ ,
303+
0, 0);
304+
}
305+
/* Wipe out any memory of the address we had... */
306+
c->state = DHCP_DISCOVER;
307+
c->next_transmit = now;
308+
c->retry_count = 0;
309+
c->leased_address.as_u32 = 0;
310+
c->subnet_mask_width = 0;
311+
c->router_address.as_u32 = 0;
312+
c->lease_renewal_interval = 0;
313+
c->dhcp_server.as_u32 = 0;
314+
break;
315+
}
316+
317+
if (dhcp_message_type != DHCP_PACKET_ACK &&
318+
dhcp_message_type != DHCP_PACKET_OFFER)
319+
{
320+
vlib_node_increment_counter (vm, dhcp_client_process_node.index,
321+
DHCP_STAT_NON_OFFER_DISCOVER, 1);
331322
clib_warning ("sw_if_index %d state %U message type %d",
332323
c->sw_if_index, format_dhcp_client_state,
333324
c->state, dhcp_message_type);
@@ -343,6 +334,8 @@ dhcp_client_for_us (u32 bi, vlib_buffer_t * b,
343334
c->retry_count = 0;
344335
c->next_transmit = now + (f64) c->lease_renewal_interval;
345336
c->lease_expires = now + (f64) c->lease_lifetime;
337+
vlib_node_increment_counter (vm, dhcp_client_process_node.index,
338+
DHCP_STAT_BOUND, 1);
346339
break;
347340

348341
default:
@@ -450,6 +443,10 @@ send_dhcp_pkt (dhcp_client_main_t * dcm, dhcp_client_t * c,
450443
/* Send the interface MAC address */
451444
clib_memcpy (dhcp->client_hardware_address, c->l2_rewrite + 6, 6);
452445

446+
/* And remember it for rx-packet-for-us checking */
447+
clib_memcpy (c->client_hardware_address, dhcp->client_hardware_address,
448+
sizeof (c->client_hardware_address));
449+
453450
/* Lease renewal, set up client_ip_address */
454451
if (is_broadcast == 0)
455452
dhcp->client_ip_address.as_u32 = c->leased_address.as_u32;
@@ -458,7 +455,9 @@ send_dhcp_pkt (dhcp_client_main_t * dcm, dhcp_client_t * c,
458455
dhcp->hardware_type = 1; /* ethernet */
459456
dhcp->hardware_address_length = 6;
460457
dhcp->transaction_identifier = c->transaction_id;
461-
dhcp->flags = clib_host_to_net_u16 (is_broadcast ? DHCP_FLAG_BROADCAST : 0);
458+
dhcp->flags =
459+
clib_host_to_net_u16 (is_broadcast && c->set_broadcast_flag ?
460+
DHCP_FLAG_BROADCAST : 0);
462461
dhcp->magic_cookie.as_u32 = DHCP_MAGIC;
463462

464463
o = (dhcp_option_t *) dhcp->options;
@@ -555,7 +554,7 @@ send_dhcp_pkt (dhcp_client_main_t * dcm, dhcp_client_t * c,
555554
switch (type)
556555
{
557556
#define _(a,b) case DHCP_PACKET_##a: {counter_index = DHCP_STAT_##a; break;}
558-
foreach_dhcp_client_process_stat
557+
foreach_dhcp_sent_packet_stat
559558
#undef _
560559
default:
561560
counter_index = DHCP_STAT_UNKNOWN;
@@ -659,7 +658,7 @@ dhcp_bound_state (dhcp_client_main_t * dcm, dhcp_client_t * c, f64 now)
659658
*/
660659
vnet_feature_enable_disable ("ip4-unicast",
661660
"ip4-dhcp-client-detect",
662-
c->sw_if_index, 1, 0, 0);
661+
c->sw_if_index, 1 /* enable */ , 0, 0);
663662
return 1;
664663
}
665664
return 0;
@@ -739,14 +738,13 @@ dhcp_client_process (vlib_main_t * vm,
739738
break;
740739

741740
case ~0:
742-
pool_foreach (c, dcm->clients, (
743-
{
744-
timeout =
745-
dhcp_client_sm (now, timeout,
746-
(uword) (c -
747-
dcm->clients));
748-
}
749-
));
741+
/* *INDENT-OFF* */
742+
pool_foreach (c, dcm->clients,
743+
({
744+
timeout = dhcp_client_sm (now, timeout,
745+
(uword) (c - dcm->clients));
746+
}));
747+
/* *INDENT-ON* */
750748
if (pool_elts (dcm->clients) == 0)
751749
timeout = 100.0;
752750
break;
@@ -850,13 +848,14 @@ show_dhcp_client_command_fn (vlib_main_t * vm,
850848
return 0;
851849
}
852850

853-
pool_foreach (c, dcm->clients, (
854-
{
855-
vlib_cli_output (vm, "%U",
856-
format_dhcp_client, dcm,
857-
c, verbose);
858-
}
859-
));
851+
/* *INDENT-OFF* */
852+
pool_foreach (c, dcm->clients,
853+
({
854+
vlib_cli_output (vm, "%U",
855+
format_dhcp_client, dcm,
856+
c, verbose);
857+
}));
858+
/* *INDENT-ON* */
860859

861860
return 0;
862861
}
@@ -877,11 +876,6 @@ dhcp_client_add_del (dhcp_client_add_del_args_t * a)
877876
vlib_main_t *vm = dcm->vlib_main;
878877
dhcp_client_t *c;
879878
uword *p;
880-
fib_prefix_t all_1s = {
881-
.fp_len = 32,
882-
.fp_addr.ip4.as_u32 = 0xffffffff,
883-
.fp_proto = FIB_PROTOCOL_IP4,
884-
};
885879
fib_prefix_t all_0s = {
886880
.fp_len = 0,
887881
.fp_addr.ip4.as_u32 = 0x0,
@@ -905,6 +899,7 @@ dhcp_client_add_del (dhcp_client_add_del_args_t * a)
905899
c->option_55_data = a->option_55_data;
906900
c->hostname = a->hostname;
907901
c->client_identifier = a->client_identifier;
902+
c->set_broadcast_flag = a->set_broadcast_flag;
908903
do
909904
{
910905
c->transaction_id = random_u32 (&dcm->seed);
@@ -913,17 +908,18 @@ dhcp_client_add_del (dhcp_client_add_del_args_t * a)
913908
set_l2_rewrite (dcm, c);
914909
hash_set (dcm->client_by_sw_if_index, a->sw_if_index, c - dcm->clients);
915910

916-
/* this add is ref counted by FIB so we can add for each itf */
917-
fib_table_entry_special_add (fib_table_get_index_for_sw_if_index
918-
(FIB_PROTOCOL_IP4, c->sw_if_index),
919-
&all_1s, FIB_SOURCE_DHCP,
920-
FIB_ENTRY_FLAG_LOCAL);
921-
922911
/*
923-
* enable the interface to RX IPv4 packets
924-
* this is also ref counted
912+
* In order to accept any OFFER, whether broadcasted or unicasted, we
913+
* need to configure the dhcp-client-detect feature as an input feature
914+
* so the DHCP OFFER is sent to the ip4-local node. Without this a
915+
* broadcasted OFFER hits the 255.255.255.255/32 address and a unicast
916+
* hits 0.0.0.0/0 both of which default to drop and the latter may forward
917+
* of box - not what we want. Nor to we want to change these route for
918+
* all interfaces in this table
925919
*/
926-
ip4_sw_interface_enable_disable (c->sw_if_index, 1);
920+
vnet_feature_enable_disable ("ip4-unicast",
921+
"ip4-dhcp-client-detect",
922+
c->sw_if_index, 1 /* enable */ , 0, 0);
927923

928924
vlib_process_signal_event (vm, dhcp_client_process_node.index,
929925
EVENT_DHCP_CLIENT_WAKEUP, c - dcm->clients);
@@ -932,10 +928,6 @@ dhcp_client_add_del (dhcp_client_add_del_args_t * a)
932928
{
933929
c = pool_elt_at_index (dcm->clients, p[0]);
934930

935-
fib_table_entry_special_remove (fib_table_get_index_for_sw_if_index
936-
(FIB_PROTOCOL_IP4, c->sw_if_index),
937-
&all_1s, FIB_SOURCE_DHCP);
938-
939931
if (c->router_address.as_u32)
940932
{
941933
ip46_address_t nh = {
@@ -948,9 +940,7 @@ dhcp_client_add_del (dhcp_client_add_del_args_t * a)
948940
DPO_PROTO_IP4, &nh, c->sw_if_index, ~0,
949941
1, FIB_ROUTE_PATH_FLAG_NONE);
950942
}
951-
dhcp_client_remove_rx_address (dcm, c);
952943
dhcp_client_release_address (dcm, c);
953-
ip4_sw_interface_enable_disable (c->sw_if_index, 0);
954944

955945
vec_free (c->option_55_data);
956946
vec_free (c->hostname);
@@ -968,7 +958,8 @@ dhcp_client_config (vlib_main_t * vm,
968958
u8 * hostname,
969959
u8 * client_id,
970960
u32 is_add,
971-
u32 client_index, void *event_callback, u32 pid)
961+
u32 client_index,
962+
void *event_callback, u8 set_broadcast_flag, u32 pid)
972963
{
973964
dhcp_client_add_del_args_t _a, *a = &_a;
974965
int rv;
@@ -979,6 +970,7 @@ dhcp_client_config (vlib_main_t * vm,
979970
a->client_index = client_index;
980971
a->pid = pid;
981972
a->event_callback = event_callback;
973+
a->set_broadcast_flag = set_broadcast_flag;
982974
vec_validate (a->hostname, strlen ((char *) hostname) - 1);
983975
strncpy ((char *) a->hostname, (char *) hostname, vec_len (a->hostname));
984976
vec_validate (a->client_identifier, strlen ((char *) client_id) - 1);
@@ -1055,6 +1047,7 @@ dhcp_client_set_command_fn (vlib_main_t * vm,
10551047
u32 sw_if_index;
10561048
u8 *hostname = 0;
10571049
u8 sw_if_index_set = 0;
1050+
u8 set_broadcast_flag = 1;
10581051
int is_add = 1;
10591052
dhcp_client_add_del_args_t _a, *a = &_a;
10601053
int rv;
@@ -1068,6 +1061,8 @@ dhcp_client_set_command_fn (vlib_main_t * vm,
10681061
;
10691062
else if (unformat (input, "del"))
10701063
is_add = 0;
1064+
else if (unformat (input, "broadcast", &set_broadcast_flag))
1065+
is_add = 0;
10711066
else
10721067
break;
10731068
}
@@ -1080,6 +1075,7 @@ dhcp_client_set_command_fn (vlib_main_t * vm,
10801075
a->sw_if_index = sw_if_index;
10811076
a->hostname = hostname;
10821077
a->client_identifier = format (0, "vpe 1.0%c", 0);
1078+
a->set_broadcast_flag = set_broadcast_flag;
10831079

10841080
/*
10851081
* Option 55 request list. These data precisely match

0 commit comments

Comments
 (0)