瀏覽代碼

[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 年之前
父節點
當前提交
f2bc138391
共有 2 個檔案被更改,包括 282 行新增5 行删除
  1. 79
    0
      src/include/ipxe/netdevice.h
  2. 203
    5
      src/net/netdevice.c

+ 79
- 0
src/include/ipxe/netdevice.h 查看文件

@@ -14,6 +14,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
14 14
 #include <ipxe/tables.h>
15 15
 #include <ipxe/refcnt.h>
16 16
 #include <ipxe/settings.h>
17
+#include <ipxe/interface.h>
17 18
 
18 19
 struct io_buffer;
19 20
 struct net_device;
@@ -292,6 +293,45 @@ struct net_device_stats {
292 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 335
 /** Maximum length of a network device name */
296 336
 #define NETDEV_NAME_LEN 12
297 337
 
@@ -374,6 +414,9 @@ struct net_device {
374 414
 
375 415
 	/** Driver private data */
376 416
 	void *priv;
417
+
418
+	/** Network device configurations (variable length) */
419
+	struct net_device_configuration configs[0];
377 420
 };
378 421
 
379 422
 /** Network device is open */
@@ -531,6 +574,35 @@ netdev_settings_init ( struct net_device *netdev ) {
531 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 607
  * Check link state of network device
536 608
  *
@@ -619,6 +691,13 @@ extern int net_rx ( struct io_buffer *iobuf, struct net_device *netdev,
619 691
 		    uint16_t net_proto, const void *ll_dest,
620 692
 		    const void *ll_source, unsigned int flags );
621 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 703
  * Complete network transmission

+ 203
- 5
src/net/netdevice.c 查看文件

@@ -54,6 +54,16 @@ static struct list_head open_net_devices = LIST_HEAD_INIT ( open_net_devices );
54 54
 #define EINFO_EUNKNOWN_LINK_STATUS \
55 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 67
 /** Default link-down status code */
58 68
 #define ENOTCONN_LINK_DOWN __einfo_error ( EINFO_ENOTCONN_LINK_DOWN )
59 69
 #define EINFO_ENOTCONN_LINK_DOWN \
@@ -63,6 +73,8 @@ static struct list_head open_net_devices = LIST_HEAD_INIT ( open_net_devices );
63 73
 struct errortab netdev_errors[] __errortab = {
64 74
 	__einfo_errortab ( EINFO_EUNKNOWN_LINK_STATUS ),
65 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,6 +455,41 @@ static void netdev_rx_flush ( struct net_device *netdev ) {
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 494
  * Free network device
448 495
  *
@@ -461,16 +508,22 @@ static void free_netdev ( struct refcnt *refcnt ) {
461 508
 /**
462 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 512
  * @ret netdev		Network device, or NULL
466 513
  *
467 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 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 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 527
 	netdev = zalloc ( total_len );
475 528
 	if ( netdev ) {
476 529
 		ref_init ( &netdev->refcnt, free_netdev );
@@ -479,7 +532,17 @@ struct net_device * alloc_netdev ( size_t priv_size ) {
479 532
 		INIT_LIST_HEAD ( &netdev->tx_deferred );
480 533
 		INIT_LIST_HEAD ( &netdev->rx_queue );
481 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 547
 	return netdev;
485 548
 }
@@ -595,6 +658,8 @@ int netdev_open ( struct net_device *netdev ) {
595 658
  * @v netdev		Network device
596 659
  */
597 660
 void netdev_close ( struct net_device *netdev ) {
661
+	unsigned int num_configs;
662
+	unsigned int i;
598 663
 
599 664
 	/* Do nothing if device is already closed */
600 665
 	if ( ! ( netdev->state & NETDEV_OPEN ) )
@@ -602,6 +667,15 @@ void netdev_close ( struct net_device *netdev ) {
602 667
 
603 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 679
 	/* Remove from open devices list */
606 680
 	list_del ( &netdev->open_list );
607 681
 
@@ -643,9 +717,9 @@ void unregister_netdev ( struct net_device *netdev ) {
643 717
 	unregister_settings ( netdev_settings ( netdev ) );
644 718
 
645 719
 	/* Remove from device list */
720
+	DBGC ( netdev, "NETDEV %s unregistered\n", netdev->name );
646 721
 	list_del ( &netdev->list );
647 722
 	netdev_put ( netdev );
648
-	DBGC ( netdev, "NETDEV %s unregistered\n", netdev->name );
649 723
 }
650 724
 
651 725
 /** Enable or disable interrupts
@@ -931,3 +1005,127 @@ static unsigned int net_discard ( void ) {
931 1005
 struct cache_discarder net_discarder __cache_discarder ( CACHE_NORMAL ) = {
932 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…
取消
儲存