@@ -21,79 +21,36 @@ dhcp_client_main_t dhcp_client_main;
21
21
static u8 * format_dhcp_client_state (u8 * s , va_list * va );
22
22
static vlib_node_registration_t dhcp_client_process_node ;
23
23
24
- #define foreach_dhcp_client_process_stat \
24
+ #define foreach_dhcp_sent_packet_stat \
25
25
_(DISCOVER, "DHCP discover packets sent") \
26
26
_(OFFER, "DHCP offer packets sent") \
27
27
_(REQUEST, "DHCP request packets sent") \
28
28
_(ACK, "DHCP ack packets sent")
29
29
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
+
30
37
typedef enum
31
38
{
32
39
#define _(sym,str) DHCP_STAT_##sym,
33
- foreach_dhcp_client_process_stat
40
+ foreach_dhcp_sent_packet_stat foreach_dhcp_error_counter
34
41
#undef _
35
42
DHCP_STAT_UNKNOWN ,
36
43
DHCP_STAT_N_STAT ,
37
44
} sample_error_t ;
38
45
39
46
static char * dhcp_client_process_stat_strings [] = {
40
47
#define _ (sym ,string ) string ,
41
- foreach_dhcp_client_process_stat
48
+ foreach_dhcp_sent_packet_stat foreach_dhcp_error_counter
42
49
#undef _
43
50
"DHCP unknown packets sent" ,
44
51
};
45
52
46
53
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
-
97
54
static void
98
55
dhcp_client_acquire_address (dhcp_client_main_t * dcm , dhcp_client_t * c )
99
56
{
@@ -145,9 +102,11 @@ dhcp_client_addr_callback (dhcp_client_t * c)
145
102
dhcp_client_main_t * dcm = & dhcp_client_main ;
146
103
void (* fp ) (u32 , u32 , u8 * , u8 , u8 , u8 * , u8 * , u8 * ) = c -> event_callback ;
147
104
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 */
150
106
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 );
151
110
152
111
/*
153
112
* Configure default IP route:
@@ -225,6 +184,15 @@ dhcp_client_for_us (u32 bi, vlib_buffer_t * b,
225
184
if (c -> state == DHCP_BOUND && c -> retry_count == 0 )
226
185
return 0 ;
227
186
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
+
228
196
/* parse through the packet, learn what we can */
229
197
if (dhcp -> your_ip_address .as_u32 )
230
198
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,
300
268
case DHCP_DISCOVER :
301
269
if (dhcp_message_type != DHCP_PACKET_OFFER )
302
270
{
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 );
306
273
c -> next_transmit = now + 5.0 ;
307
274
break ;
308
275
}
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 );
316
276
317
277
/* Received an offer, go send a request */
318
278
c -> state = DHCP_REQUEST ;
@@ -326,8 +286,39 @@ dhcp_client_for_us (u32 bi, vlib_buffer_t * b,
326
286
327
287
case DHCP_BOUND :
328
288
case DHCP_REQUEST :
329
- if (dhcp_message_type != DHCP_PACKET_ACK )
289
+ if (dhcp_message_type == DHCP_PACKET_NAK )
330
290
{
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 );
331
322
clib_warning ("sw_if_index %d state %U message type %d" ,
332
323
c -> sw_if_index , format_dhcp_client_state ,
333
324
c -> state , dhcp_message_type );
@@ -343,6 +334,8 @@ dhcp_client_for_us (u32 bi, vlib_buffer_t * b,
343
334
c -> retry_count = 0 ;
344
335
c -> next_transmit = now + (f64 ) c -> lease_renewal_interval ;
345
336
c -> lease_expires = now + (f64 ) c -> lease_lifetime ;
337
+ vlib_node_increment_counter (vm , dhcp_client_process_node .index ,
338
+ DHCP_STAT_BOUND , 1 );
346
339
break ;
347
340
348
341
default :
@@ -450,6 +443,10 @@ send_dhcp_pkt (dhcp_client_main_t * dcm, dhcp_client_t * c,
450
443
/* Send the interface MAC address */
451
444
clib_memcpy (dhcp -> client_hardware_address , c -> l2_rewrite + 6 , 6 );
452
445
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
+
453
450
/* Lease renewal, set up client_ip_address */
454
451
if (is_broadcast == 0 )
455
452
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,
458
455
dhcp -> hardware_type = 1 ; /* ethernet */
459
456
dhcp -> hardware_address_length = 6 ;
460
457
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 );
462
461
dhcp -> magic_cookie .as_u32 = DHCP_MAGIC ;
463
462
464
463
o = (dhcp_option_t * ) dhcp -> options ;
@@ -555,7 +554,7 @@ send_dhcp_pkt (dhcp_client_main_t * dcm, dhcp_client_t * c,
555
554
switch (type )
556
555
{
557
556
#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
559
558
#undef _
560
559
default :
561
560
counter_index = DHCP_STAT_UNKNOWN ;
@@ -659,7 +658,7 @@ dhcp_bound_state (dhcp_client_main_t * dcm, dhcp_client_t * c, f64 now)
659
658
*/
660
659
vnet_feature_enable_disable ("ip4-unicast" ,
661
660
"ip4-dhcp-client-detect" ,
662
- c -> sw_if_index , 1 , 0 , 0 );
661
+ c -> sw_if_index , 1 /* enable */ , 0 , 0 );
663
662
return 1 ;
664
663
}
665
664
return 0 ;
@@ -739,14 +738,13 @@ dhcp_client_process (vlib_main_t * vm,
739
738
break ;
740
739
741
740
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* */
750
748
if (pool_elts (dcm -> clients ) == 0 )
751
749
timeout = 100.0 ;
752
750
break ;
@@ -850,13 +848,14 @@ show_dhcp_client_command_fn (vlib_main_t * vm,
850
848
return 0 ;
851
849
}
852
850
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* */
860
859
861
860
return 0 ;
862
861
}
@@ -877,11 +876,6 @@ dhcp_client_add_del (dhcp_client_add_del_args_t * a)
877
876
vlib_main_t * vm = dcm -> vlib_main ;
878
877
dhcp_client_t * c ;
879
878
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
- };
885
879
fib_prefix_t all_0s = {
886
880
.fp_len = 0 ,
887
881
.fp_addr .ip4 .as_u32 = 0x0 ,
@@ -905,6 +899,7 @@ dhcp_client_add_del (dhcp_client_add_del_args_t * a)
905
899
c -> option_55_data = a -> option_55_data ;
906
900
c -> hostname = a -> hostname ;
907
901
c -> client_identifier = a -> client_identifier ;
902
+ c -> set_broadcast_flag = a -> set_broadcast_flag ;
908
903
do
909
904
{
910
905
c -> transaction_id = random_u32 (& dcm -> seed );
@@ -913,17 +908,18 @@ dhcp_client_add_del (dhcp_client_add_del_args_t * a)
913
908
set_l2_rewrite (dcm , c );
914
909
hash_set (dcm -> client_by_sw_if_index , a -> sw_if_index , c - dcm -> clients );
915
910
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
-
922
911
/*
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
925
919
*/
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 );
927
923
928
924
vlib_process_signal_event (vm , dhcp_client_process_node .index ,
929
925
EVENT_DHCP_CLIENT_WAKEUP , c - dcm -> clients );
@@ -932,10 +928,6 @@ dhcp_client_add_del (dhcp_client_add_del_args_t * a)
932
928
{
933
929
c = pool_elt_at_index (dcm -> clients , p [0 ]);
934
930
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
-
939
931
if (c -> router_address .as_u32 )
940
932
{
941
933
ip46_address_t nh = {
@@ -948,9 +940,7 @@ dhcp_client_add_del (dhcp_client_add_del_args_t * a)
948
940
DPO_PROTO_IP4 , & nh , c -> sw_if_index , ~0 ,
949
941
1 , FIB_ROUTE_PATH_FLAG_NONE );
950
942
}
951
- dhcp_client_remove_rx_address (dcm , c );
952
943
dhcp_client_release_address (dcm , c );
953
- ip4_sw_interface_enable_disable (c -> sw_if_index , 0 );
954
944
955
945
vec_free (c -> option_55_data );
956
946
vec_free (c -> hostname );
@@ -968,7 +958,8 @@ dhcp_client_config (vlib_main_t * vm,
968
958
u8 * hostname ,
969
959
u8 * client_id ,
970
960
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 )
972
963
{
973
964
dhcp_client_add_del_args_t _a , * a = & _a ;
974
965
int rv ;
@@ -979,6 +970,7 @@ dhcp_client_config (vlib_main_t * vm,
979
970
a -> client_index = client_index ;
980
971
a -> pid = pid ;
981
972
a -> event_callback = event_callback ;
973
+ a -> set_broadcast_flag = set_broadcast_flag ;
982
974
vec_validate (a -> hostname , strlen ((char * ) hostname ) - 1 );
983
975
strncpy ((char * ) a -> hostname , (char * ) hostname , vec_len (a -> hostname ));
984
976
vec_validate (a -> client_identifier , strlen ((char * ) client_id ) - 1 );
@@ -1055,6 +1047,7 @@ dhcp_client_set_command_fn (vlib_main_t * vm,
1055
1047
u32 sw_if_index ;
1056
1048
u8 * hostname = 0 ;
1057
1049
u8 sw_if_index_set = 0 ;
1050
+ u8 set_broadcast_flag = 1 ;
1058
1051
int is_add = 1 ;
1059
1052
dhcp_client_add_del_args_t _a , * a = & _a ;
1060
1053
int rv ;
@@ -1068,6 +1061,8 @@ dhcp_client_set_command_fn (vlib_main_t * vm,
1068
1061
;
1069
1062
else if (unformat (input , "del" ))
1070
1063
is_add = 0 ;
1064
+ else if (unformat (input , "broadcast" , & set_broadcast_flag ))
1065
+ is_add = 0 ;
1071
1066
else
1072
1067
break ;
1073
1068
}
@@ -1080,6 +1075,7 @@ dhcp_client_set_command_fn (vlib_main_t * vm,
1080
1075
a -> sw_if_index = sw_if_index ;
1081
1076
a -> hostname = hostname ;
1082
1077
a -> client_identifier = format (0 , "vpe 1.0%c" , 0 );
1078
+ a -> set_broadcast_flag = set_broadcast_flag ;
1083
1079
1084
1080
/*
1085
1081
* Option 55 request list. These data precisely match
0 commit comments