Browse Source

[netdevice] Add generic concept of a network device configurator

iPXE supports multiple mechanisms for network device configuration:
DHCPv4 for IPv4, FIP for FCoE, and SLAAC for IPv6.  At present, DHCPv4
requires an explicit action (e.g. a "dhcp" command), FIP is initiated
implicitly upon opening a network device, and SLAAC takes place
whenever a RA happens to be received.

Add a generic concept of a network device configurator, which provides
a common interface to triggering configuration and to reporting the
result of the configuration process.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 11 years ago
parent
commit
f2bc138391
2 changed files with 282 additions and 5 deletions
  1. 79
    0
      src/include/ipxe/netdevice.h
  2. 203
    5
      src/net/netdevice.c

+ 79
- 0
src/include/ipxe/netdevice.h View File

14
 #include <ipxe/tables.h>
14
 #include <ipxe/tables.h>
15
 #include <ipxe/refcnt.h>
15
 #include <ipxe/refcnt.h>
16
 #include <ipxe/settings.h>
16
 #include <ipxe/settings.h>
17
+#include <ipxe/interface.h>
17
 
18
 
18
 struct io_buffer;
19
 struct io_buffer;
19
 struct net_device;
20
 struct net_device;
292
 	struct net_device_error errors[NETDEV_MAX_UNIQUE_ERRORS];
293
 	struct net_device_error errors[NETDEV_MAX_UNIQUE_ERRORS];
293
 };
294
 };
294
 
295
 
296
+/** A network device configuration */
297
+struct net_device_configuration {
298
+	/** Network device */
299
+	struct net_device *netdev;
300
+	/** Network device configurator */
301
+	struct net_device_configurator *configurator;
302
+	/** Configuration status */
303
+	int rc;
304
+	/** Job control interface */
305
+	struct interface job;
306
+};
307
+
308
+/** A network device configurator */
309
+struct net_device_configurator {
310
+	/** Name */
311
+	const char *name;
312
+	/** Check applicability of configurator
313
+	 *
314
+	 * @v netdev		Network device
315
+	 * @ret applies		Configurator applies to this network device
316
+	 */
317
+	int ( * applies ) ( struct net_device *netdev );
318
+	/** Start configuring network device
319
+	 *
320
+	 * @v job		Job control interface
321
+	 * @v netdev		Network device
322
+	 * @ret rc		Return status code
323
+	 */
324
+	int ( * start ) ( struct interface *job, struct net_device *netdev );
325
+};
326
+
327
+/** Network device configurator table */
328
+#define NET_DEVICE_CONFIGURATORS \
329
+	__table ( struct net_device_configurator, "net_device_configurators" )
330
+
331
+/** Declare a network device configurator */
332
+#define __net_device_configurator \
333
+	__table_entry ( NET_DEVICE_CONFIGURATORS, 01 )
334
+
295
 /** Maximum length of a network device name */
335
 /** Maximum length of a network device name */
296
 #define NETDEV_NAME_LEN 12
336
 #define NETDEV_NAME_LEN 12
297
 
337
 
374
 
414
 
375
 	/** Driver private data */
415
 	/** Driver private data */
376
 	void *priv;
416
 	void *priv;
417
+
418
+	/** Network device configurations (variable length) */
419
+	struct net_device_configuration configs[0];
377
 };
420
 };
378
 
421
 
379
 /** Network device is open */
422
 /** Network device is open */
531
 	netdev->settings.settings.op = &netdev_settings_operations;
574
 	netdev->settings.settings.op = &netdev_settings_operations;
532
 }
575
 }
533
 
576
 
577
+/**
578
+ * Get network device configuration
579
+ *
580
+ * @v netdev		Network device
581
+ * @v configurator	Network device configurator
582
+ * @ret config		Network device configuration
583
+ */
584
+static inline struct net_device_configuration *
585
+netdev_configuration ( struct net_device *netdev,
586
+		       struct net_device_configurator *configurator ) {
587
+
588
+	return &netdev->configs[ table_index ( NET_DEVICE_CONFIGURATORS,
589
+					       configurator ) ];
590
+}
591
+
592
+/**
593
+ * Check if configurator applies to network device
594
+ *
595
+ * @v netdev		Network device
596
+ * @v configurator	Network device configurator
597
+ * @ret applies		Configurator applies to network device
598
+ */
599
+static inline int
600
+netdev_configurator_applies ( struct net_device *netdev,
601
+			      struct net_device_configurator *configurator ) {
602
+	return ( ( configurator->applies == NULL ) ||
603
+		 configurator->applies ( netdev ) );
604
+}
605
+
534
 /**
606
 /**
535
  * Check link state of network device
607
  * Check link state of network device
536
  *
608
  *
619
 		    uint16_t net_proto, const void *ll_dest,
691
 		    uint16_t net_proto, const void *ll_dest,
620
 		    const void *ll_source, unsigned int flags );
692
 		    const void *ll_source, unsigned int flags );
621
 extern void net_poll ( void );
693
 extern void net_poll ( void );
694
+extern struct net_device_configurator *
695
+find_netdev_configurator ( const char *name );
696
+extern int netdev_configure ( struct net_device *netdev,
697
+			      struct net_device_configurator *configurator );
698
+extern int netdev_configure_all ( struct net_device *netdev );
699
+extern int netdev_configuration_in_progress ( struct net_device *netdev );
700
+extern int netdev_configuration_ok ( struct net_device *netdev );
622
 
701
 
623
 /**
702
 /**
624
  * Complete network transmission
703
  * Complete network transmission

+ 203
- 5
src/net/netdevice.c View File

54
 #define EINFO_EUNKNOWN_LINK_STATUS \
54
 #define EINFO_EUNKNOWN_LINK_STATUS \
55
 	__einfo_uniqify ( EINFO_EINPROGRESS, 0x01, "Unknown" )
55
 	__einfo_uniqify ( EINFO_EINPROGRESS, 0x01, "Unknown" )
56
 
56
 
57
+/** Default not-yet-attempted-configuration status code */
58
+#define EUNUSED_CONFIG __einfo_error ( EINFO_EUNUSED_CONFIG )
59
+#define EINFO_EUNUSED_CONFIG \
60
+	__einfo_uniqify ( EINFO_EINPROGRESS, 0x02, "Unused" )
61
+
62
+/** Default configuration-in-progress status code */
63
+#define EINPROGRESS_CONFIG __einfo_error ( EINFO_EINPROGRESS_CONFIG )
64
+#define EINFO_EINPROGRESS_CONFIG \
65
+	__einfo_uniqify ( EINFO_EINPROGRESS, 0x03, "Incomplete" )
66
+
57
 /** Default link-down status code */
67
 /** Default link-down status code */
58
 #define ENOTCONN_LINK_DOWN __einfo_error ( EINFO_ENOTCONN_LINK_DOWN )
68
 #define ENOTCONN_LINK_DOWN __einfo_error ( EINFO_ENOTCONN_LINK_DOWN )
59
 #define EINFO_ENOTCONN_LINK_DOWN \
69
 #define EINFO_ENOTCONN_LINK_DOWN \
63
 struct errortab netdev_errors[] __errortab = {
73
 struct errortab netdev_errors[] __errortab = {
64
 	__einfo_errortab ( EINFO_EUNKNOWN_LINK_STATUS ),
74
 	__einfo_errortab ( EINFO_EUNKNOWN_LINK_STATUS ),
65
 	__einfo_errortab ( EINFO_ENOTCONN_LINK_DOWN ),
75
 	__einfo_errortab ( EINFO_ENOTCONN_LINK_DOWN ),
76
+	__einfo_errortab ( EINFO_EUNUSED_CONFIG ),
77
+	__einfo_errortab ( EINFO_EINPROGRESS_CONFIG ),
66
 };
78
 };
67
 
79
 
68
 /**
80
 /**
443
 	}
455
 	}
444
 }
456
 }
445
 
457
 
458
+/**
459
+ * Finish network device configuration
460
+ *
461
+ * @v config		Network device configuration
462
+ * @v rc		Reason for completion
463
+ */
464
+static void netdev_config_close ( struct net_device_configuration *config,
465
+				  int rc ) {
466
+	struct net_device_configurator *configurator = config->configurator;
467
+	struct net_device *netdev = config->netdev;
468
+
469
+	/* Restart interface */
470
+	intf_restart ( &config->job, rc );
471
+
472
+	/* Record configuration result */
473
+	config->rc = rc;
474
+	if ( rc == 0 ) {
475
+		DBGC ( netdev, "NETDEV %s configured via %s\n",
476
+		       netdev->name, configurator->name );
477
+	} else {
478
+		DBGC ( netdev, "NETDEV %s configuration via %s failed: %s\n",
479
+		       netdev->name, configurator->name, strerror ( rc ) );
480
+	}
481
+}
482
+
483
+/** Network device configuration interface operations */
484
+static struct interface_operation netdev_config_ops[] = {
485
+	INTF_OP ( intf_close, struct net_device_configuration *,
486
+		  netdev_config_close ),
487
+};
488
+
489
+/** Network device configuration interface descriptor */
490
+static struct interface_descriptor netdev_config_desc =
491
+	INTF_DESC ( struct net_device_configuration, job, netdev_config_ops );
492
+
446
 /**
493
 /**
447
  * Free network device
494
  * Free network device
448
  *
495
  *
461
 /**
508
 /**
462
  * Allocate network device
509
  * Allocate network device
463
  *
510
  *
464
- * @v priv_size		Size of private data area (net_device::priv)
511
+ * @v priv_len		Length of private data area (net_device::priv)
465
  * @ret netdev		Network device, or NULL
512
  * @ret netdev		Network device, or NULL
466
  *
513
  *
467
  * Allocates space for a network device and its private data area.
514
  * Allocates space for a network device and its private data area.
468
  */
515
  */
469
-struct net_device * alloc_netdev ( size_t priv_size ) {
516
+struct net_device * alloc_netdev ( size_t priv_len ) {
470
 	struct net_device *netdev;
517
 	struct net_device *netdev;
518
+	struct net_device_configurator *configurator;
519
+	struct net_device_configuration *config;
520
+	unsigned int num_configs;
521
+	size_t confs_len;
471
 	size_t total_len;
522
 	size_t total_len;
472
 
523
 
473
-	total_len = ( sizeof ( *netdev ) + priv_size );
524
+	num_configs = table_num_entries ( NET_DEVICE_CONFIGURATORS );
525
+	confs_len = ( num_configs * sizeof ( netdev->configs[0] ) );
526
+	total_len = ( sizeof ( *netdev ) + confs_len + priv_len );
474
 	netdev = zalloc ( total_len );
527
 	netdev = zalloc ( total_len );
475
 	if ( netdev ) {
528
 	if ( netdev ) {
476
 		ref_init ( &netdev->refcnt, free_netdev );
529
 		ref_init ( &netdev->refcnt, free_netdev );
479
 		INIT_LIST_HEAD ( &netdev->tx_deferred );
532
 		INIT_LIST_HEAD ( &netdev->tx_deferred );
480
 		INIT_LIST_HEAD ( &netdev->rx_queue );
533
 		INIT_LIST_HEAD ( &netdev->rx_queue );
481
 		netdev_settings_init ( netdev );
534
 		netdev_settings_init ( netdev );
482
-		netdev->priv = ( ( ( void * ) netdev ) + sizeof ( *netdev ) );
535
+		config = netdev->configs;
536
+		for_each_table_entry ( configurator, NET_DEVICE_CONFIGURATORS ){
537
+			config->netdev = netdev;
538
+			config->configurator = configurator;
539
+			config->rc = -EUNUSED_CONFIG;
540
+			intf_init ( &config->job, &netdev_config_desc,
541
+				    &netdev->refcnt );
542
+			config++;
543
+		}
544
+		netdev->priv = ( ( ( void * ) netdev ) + sizeof ( *netdev ) +
545
+				 confs_len );
483
 	}
546
 	}
484
 	return netdev;
547
 	return netdev;
485
 }
548
 }
595
  * @v netdev		Network device
658
  * @v netdev		Network device
596
  */
659
  */
597
 void netdev_close ( struct net_device *netdev ) {
660
 void netdev_close ( struct net_device *netdev ) {
661
+	unsigned int num_configs;
662
+	unsigned int i;
598
 
663
 
599
 	/* Do nothing if device is already closed */
664
 	/* Do nothing if device is already closed */
600
 	if ( ! ( netdev->state & NETDEV_OPEN ) )
665
 	if ( ! ( netdev->state & NETDEV_OPEN ) )
602
 
667
 
603
 	DBGC ( netdev, "NETDEV %s closing\n", netdev->name );
668
 	DBGC ( netdev, "NETDEV %s closing\n", netdev->name );
604
 
669
 
670
+	/* Terminate any ongoing configurations.  Use intf_close()
671
+	 * rather than intf_restart() to allow the cancellation to be
672
+	 * reported back to us if a configuration is actually in
673
+	 * progress.
674
+	 */
675
+	num_configs = table_num_entries ( NET_DEVICE_CONFIGURATORS );
676
+	for ( i = 0 ; i < num_configs ; i++ )
677
+		intf_close ( &netdev->configs[i].job, -ECANCELED );
678
+
605
 	/* Remove from open devices list */
679
 	/* Remove from open devices list */
606
 	list_del ( &netdev->open_list );
680
 	list_del ( &netdev->open_list );
607
 
681
 
643
 	unregister_settings ( netdev_settings ( netdev ) );
717
 	unregister_settings ( netdev_settings ( netdev ) );
644
 
718
 
645
 	/* Remove from device list */
719
 	/* Remove from device list */
720
+	DBGC ( netdev, "NETDEV %s unregistered\n", netdev->name );
646
 	list_del ( &netdev->list );
721
 	list_del ( &netdev->list );
647
 	netdev_put ( netdev );
722
 	netdev_put ( netdev );
648
-	DBGC ( netdev, "NETDEV %s unregistered\n", netdev->name );
649
 }
723
 }
650
 
724
 
651
 /** Enable or disable interrupts
725
 /** Enable or disable interrupts
931
 struct cache_discarder net_discarder __cache_discarder ( CACHE_NORMAL ) = {
1005
 struct cache_discarder net_discarder __cache_discarder ( CACHE_NORMAL ) = {
932
 	.discard = net_discard,
1006
 	.discard = net_discard,
933
 };
1007
 };
1008
+
1009
+/**
1010
+ * Find network device configurator
1011
+ *
1012
+ * @v name		Name
1013
+ * @ret configurator	Network device configurator, or NULL
1014
+ */
1015
+struct net_device_configurator * find_netdev_configurator ( const char *name ) {
1016
+	struct net_device_configurator *configurator;
1017
+
1018
+	for_each_table_entry ( configurator, NET_DEVICE_CONFIGURATORS ) {
1019
+		if ( strcmp ( configurator->name, name ) == 0 )
1020
+			return configurator;
1021
+	}
1022
+	return NULL;
1023
+}
1024
+
1025
+/**
1026
+ * Start network device configuration
1027
+ *
1028
+ * @v netdev		Network device
1029
+ * @v configurator	Network device configurator
1030
+ * @ret rc		Return status code
1031
+ */
1032
+int netdev_configure ( struct net_device *netdev,
1033
+		       struct net_device_configurator *configurator ) {
1034
+	struct net_device_configuration *config =
1035
+		netdev_configuration ( netdev, configurator );
1036
+	int rc;
1037
+
1038
+	/* Check applicability of configurator */
1039
+	if ( ! netdev_configurator_applies ( netdev, configurator ) ) {
1040
+		DBGC ( netdev, "NETDEV %s does not support configuration via "
1041
+		       "%s\n", netdev->name, configurator->name );
1042
+		return -ENOTSUP;
1043
+	}
1044
+
1045
+	/* Terminate any ongoing configuration */
1046
+	intf_restart ( &config->job, -ECANCELED );
1047
+
1048
+	/* Mark configuration as being in progress */
1049
+	config->rc = -EINPROGRESS_CONFIG;
1050
+
1051
+	DBGC ( netdev, "NETDEV %s starting configuration via %s\n",
1052
+	       netdev->name, configurator->name );
1053
+
1054
+	/* Start configuration */
1055
+	if ( ( rc = configurator->start ( &config->job, netdev ) ) != 0 ) {
1056
+		DBGC ( netdev, "NETDEV %s could not start configuration via "
1057
+		       "%s: %s\n", netdev->name, configurator->name,
1058
+		       strerror ( rc ) );
1059
+		config->rc = rc;
1060
+		return rc;
1061
+	}
1062
+
1063
+	return 0;
1064
+}
1065
+
1066
+/**
1067
+ * Start network device configuration via all supported configurators
1068
+ *
1069
+ * @v netdev		Network device
1070
+ * @ret rc		Return status code
1071
+ */
1072
+int netdev_configure_all ( struct net_device *netdev ) {
1073
+	struct net_device_configurator *configurator;
1074
+	int rc;
1075
+
1076
+	/* Start configuration for each configurator */
1077
+	for_each_table_entry ( configurator, NET_DEVICE_CONFIGURATORS ) {
1078
+
1079
+		/* Skip any inapplicable configurators */
1080
+		if ( ! netdev_configurator_applies ( netdev, configurator ) )
1081
+			continue;
1082
+
1083
+		/* Start configuration */
1084
+		if ( ( rc = netdev_configure ( netdev, configurator ) ) != 0 )
1085
+			return rc;
1086
+	}
1087
+
1088
+	return 0;
1089
+}
1090
+
1091
+/**
1092
+ * Check if network device has a configuration with a specified status code
1093
+ *
1094
+ * @v netdev		Network device
1095
+ * @v rc		Status code
1096
+ * @ret has_rc		Network device has a configuration with this status code
1097
+ */
1098
+static int netdev_has_configuration_rc ( struct net_device *netdev, int rc ) {
1099
+	unsigned int num_configs;
1100
+	unsigned int i;
1101
+
1102
+	num_configs = table_num_entries ( NET_DEVICE_CONFIGURATORS );
1103
+	for ( i = 0 ; i < num_configs ; i++ ) {
1104
+		if ( netdev->configs[i].rc == rc )
1105
+			return 1;
1106
+	}
1107
+	return 0;
1108
+}
1109
+
1110
+/**
1111
+ * Check if network device configuration is in progress
1112
+ *
1113
+ * @v netdev		Network device
1114
+ * @ret is_in_progress	Network device configuration is in progress
1115
+ */
1116
+int netdev_configuration_in_progress ( struct net_device *netdev ) {
1117
+
1118
+	return netdev_has_configuration_rc ( netdev, -EINPROGRESS_CONFIG );
1119
+}
1120
+
1121
+/**
1122
+ * Check if network device has at least one successful configuration
1123
+ *
1124
+ * @v netdev		Network device
1125
+ * @v configurator	Configurator
1126
+ * @ret rc		Return status code
1127
+ */
1128
+int netdev_configuration_ok ( struct net_device *netdev ) {
1129
+
1130
+	return netdev_has_configuration_rc ( netdev, 0 );
1131
+}

Loading…
Cancel
Save