mirror of https://github.com/ipxe/ipxe.git
[netdevice] Add the concept of a network upper-layer driver
Add the concept of a network upper-layer driver, which can create arbitrary devices on top of network devices. Signed-off-by: Michael Brown <mcb30@ipxe.org>pull/1/head
parent
97ef28aea0
commit
ca4df90a63
|
@ -344,6 +344,34 @@ struct net_device {
|
||||||
/** Declare a network-layer protocol */
|
/** Declare a network-layer protocol */
|
||||||
#define __net_protocol __table_entry ( NET_PROTOCOLS, 01 )
|
#define __net_protocol __table_entry ( NET_PROTOCOLS, 01 )
|
||||||
|
|
||||||
|
/** A network upper-layer driver */
|
||||||
|
struct net_driver {
|
||||||
|
/** Name */
|
||||||
|
const char *name;
|
||||||
|
/** Probe device
|
||||||
|
*
|
||||||
|
* @v netdev Network device
|
||||||
|
* @ret rc Return status code
|
||||||
|
*/
|
||||||
|
int ( * probe ) ( struct net_device *netdev );
|
||||||
|
/** Notify of device or link state change
|
||||||
|
*
|
||||||
|
* @v netdev Network device
|
||||||
|
*/
|
||||||
|
void ( * notify ) ( struct net_device *netdev );
|
||||||
|
/** Remove device
|
||||||
|
*
|
||||||
|
* @v netdev Network device
|
||||||
|
*/
|
||||||
|
void ( * remove ) ( struct net_device *netdev );
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Network driver table */
|
||||||
|
#define NET_DRIVERS __table ( struct net_driver, "net_drivers" )
|
||||||
|
|
||||||
|
/** Declare a network driver */
|
||||||
|
#define __net_driver __table_entry ( NET_DRIVERS, 01 )
|
||||||
|
|
||||||
extern struct list_head net_devices;
|
extern struct list_head net_devices;
|
||||||
extern struct net_device_operations null_netdev_operations;
|
extern struct net_device_operations null_netdev_operations;
|
||||||
extern struct settings_operations netdev_settings_operations;
|
extern struct settings_operations netdev_settings_operations;
|
||||||
|
@ -451,27 +479,6 @@ netdev_settings_init ( struct net_device *netdev ) {
|
||||||
netdev->settings.settings.op = &netdev_settings_operations;
|
netdev->settings.settings.op = &netdev_settings_operations;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Mark network device as having link up
|
|
||||||
*
|
|
||||||
* @v netdev Network device
|
|
||||||
*/
|
|
||||||
static inline __attribute__ (( always_inline )) void
|
|
||||||
netdev_link_up ( struct net_device *netdev ) {
|
|
||||||
netdev->link_rc = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mark network device as having link down due to a specific error
|
|
||||||
*
|
|
||||||
* @v netdev Network device
|
|
||||||
* @v rc Link status code
|
|
||||||
*/
|
|
||||||
static inline __attribute__ (( always_inline )) void
|
|
||||||
netdev_link_err ( struct net_device *netdev, int rc ) {
|
|
||||||
netdev->link_rc = rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check link state of network device
|
* Check link state of network device
|
||||||
*
|
*
|
||||||
|
@ -505,6 +512,7 @@ netdev_irq_enabled ( struct net_device *netdev ) {
|
||||||
return ( netdev->state & NETDEV_IRQ_ENABLED );
|
return ( netdev->state & NETDEV_IRQ_ENABLED );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern void netdev_link_err ( struct net_device *netdev, int rc );
|
||||||
extern void netdev_link_down ( struct net_device *netdev );
|
extern void netdev_link_down ( struct net_device *netdev );
|
||||||
extern int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf );
|
extern int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf );
|
||||||
extern void netdev_tx_complete_err ( struct net_device *netdev,
|
extern void netdev_tx_complete_err ( struct net_device *netdev,
|
||||||
|
@ -554,4 +562,14 @@ static inline void netdev_tx_complete_next ( struct net_device *netdev ) {
|
||||||
netdev_tx_complete_next_err ( netdev, 0 );
|
netdev_tx_complete_next_err ( netdev, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark network device as having link up
|
||||||
|
*
|
||||||
|
* @v netdev Network device
|
||||||
|
*/
|
||||||
|
static inline __attribute__ (( always_inline )) void
|
||||||
|
netdev_link_up ( struct net_device *netdev ) {
|
||||||
|
netdev_link_err ( netdev, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* _IPXE_NETDEVICE_H */
|
#endif /* _IPXE_NETDEVICE_H */
|
||||||
|
|
|
@ -56,6 +56,39 @@ struct errortab netdev_errors[] __errortab = {
|
||||||
__einfo_errortab ( EINFO_EUNKNOWN_LINK_STATUS ),
|
__einfo_errortab ( EINFO_EUNKNOWN_LINK_STATUS ),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notify drivers of network device or link state change
|
||||||
|
*
|
||||||
|
* @v netdev Network device
|
||||||
|
*/
|
||||||
|
static void netdev_notify ( struct net_device *netdev ) {
|
||||||
|
struct net_driver *driver;
|
||||||
|
|
||||||
|
for_each_table_entry ( driver, NET_DRIVERS )
|
||||||
|
driver->notify ( netdev );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark network device as having a specific link state
|
||||||
|
*
|
||||||
|
* @v netdev Network device
|
||||||
|
* @v rc Link status code
|
||||||
|
*/
|
||||||
|
void netdev_link_err ( struct net_device *netdev, int rc ) {
|
||||||
|
|
||||||
|
/* Record link state */
|
||||||
|
netdev->link_rc = rc;
|
||||||
|
if ( netdev->link_rc == 0 ) {
|
||||||
|
DBGC ( netdev, "NETDEV %p link is up\n", netdev );
|
||||||
|
} else {
|
||||||
|
DBGC ( netdev, "NETDEV %p link is down: %s\n",
|
||||||
|
netdev, strerror ( netdev->link_rc ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Notify drivers of link state change */
|
||||||
|
netdev_notify ( netdev );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark network device as having link down
|
* Mark network device as having link down
|
||||||
*
|
*
|
||||||
|
@ -68,7 +101,7 @@ void netdev_link_down ( struct net_device *netdev ) {
|
||||||
*/
|
*/
|
||||||
if ( ( netdev->link_rc == 0 ) ||
|
if ( ( netdev->link_rc == 0 ) ||
|
||||||
( netdev->link_rc == -EUNKNOWN_LINK_STATUS ) ) {
|
( netdev->link_rc == -EUNKNOWN_LINK_STATUS ) ) {
|
||||||
netdev->link_rc = -ENOTCONN;
|
netdev_link_err ( netdev, -ENOTCONN );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,6 +400,7 @@ struct net_device * alloc_netdev ( size_t priv_size ) {
|
||||||
*/
|
*/
|
||||||
int register_netdev ( struct net_device *netdev ) {
|
int register_netdev ( struct net_device *netdev ) {
|
||||||
static unsigned int ifindex = 0;
|
static unsigned int ifindex = 0;
|
||||||
|
struct net_driver *driver;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Create device name */
|
/* Create device name */
|
||||||
|
@ -376,14 +410,6 @@ int register_netdev ( struct net_device *netdev ) {
|
||||||
/* Set initial link-layer address */
|
/* Set initial link-layer address */
|
||||||
netdev->ll_protocol->init_addr ( netdev->hw_addr, netdev->ll_addr );
|
netdev->ll_protocol->init_addr ( netdev->hw_addr, netdev->ll_addr );
|
||||||
|
|
||||||
/* Register per-netdev configuration settings */
|
|
||||||
if ( ( rc = register_settings ( netdev_settings ( netdev ),
|
|
||||||
NULL ) ) != 0 ) {
|
|
||||||
DBGC ( netdev, "NETDEV %p could not register settings: %s\n",
|
|
||||||
netdev, strerror ( rc ) );
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add to device list */
|
/* Add to device list */
|
||||||
netdev_get ( netdev );
|
netdev_get ( netdev );
|
||||||
list_add_tail ( &netdev->list, &net_devices );
|
list_add_tail ( &netdev->list, &net_devices );
|
||||||
|
@ -391,7 +417,31 @@ int register_netdev ( struct net_device *netdev ) {
|
||||||
netdev, netdev->name, netdev->dev->name,
|
netdev, netdev->name, netdev->dev->name,
|
||||||
netdev_addr ( netdev ) );
|
netdev_addr ( netdev ) );
|
||||||
|
|
||||||
|
/* Register per-netdev configuration settings */
|
||||||
|
if ( ( rc = register_settings ( netdev_settings ( netdev ),
|
||||||
|
NULL ) ) != 0 ) {
|
||||||
|
DBGC ( netdev, "NETDEV %p could not register settings: %s\n",
|
||||||
|
netdev, strerror ( rc ) );
|
||||||
|
goto err_register_settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Probe device */
|
||||||
|
for_each_table_entry ( driver, NET_DRIVERS ) {
|
||||||
|
if ( ( rc = driver->probe ( netdev ) ) != 0 ) {
|
||||||
|
DBGC ( netdev, "NETDEV %p could not add %s device: "
|
||||||
|
"%s\n", netdev, driver->name, strerror ( rc ) );
|
||||||
|
goto err_probe;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
err_probe:
|
||||||
|
for_each_table_entry_continue_reverse ( driver, NET_DRIVERS )
|
||||||
|
driver->remove ( netdev );
|
||||||
|
unregister_settings ( netdev_settings ( netdev ) );
|
||||||
|
err_register_settings:
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -419,6 +469,9 @@ int netdev_open ( struct net_device *netdev ) {
|
||||||
/* Add to head of open devices list */
|
/* Add to head of open devices list */
|
||||||
list_add ( &netdev->open_list, &open_net_devices );
|
list_add ( &netdev->open_list, &open_net_devices );
|
||||||
|
|
||||||
|
/* Notify drivers of device state change */
|
||||||
|
netdev_notify ( netdev );
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -435,18 +488,21 @@ void netdev_close ( struct net_device *netdev ) {
|
||||||
|
|
||||||
DBGC ( netdev, "NETDEV %p closing\n", netdev );
|
DBGC ( netdev, "NETDEV %p closing\n", netdev );
|
||||||
|
|
||||||
|
/* Remove from open devices list */
|
||||||
|
list_del ( &netdev->open_list );
|
||||||
|
|
||||||
|
/* Mark as closed */
|
||||||
|
netdev->state &= ~NETDEV_OPEN;
|
||||||
|
|
||||||
|
/* Notify drivers of device state change */
|
||||||
|
netdev_notify ( netdev );
|
||||||
|
|
||||||
/* Close the device */
|
/* Close the device */
|
||||||
netdev->op->close ( netdev );
|
netdev->op->close ( netdev );
|
||||||
|
|
||||||
/* Flush TX and RX queues */
|
/* Flush TX and RX queues */
|
||||||
netdev_tx_flush ( netdev );
|
netdev_tx_flush ( netdev );
|
||||||
netdev_rx_flush ( netdev );
|
netdev_rx_flush ( netdev );
|
||||||
|
|
||||||
/* Mark as closed */
|
|
||||||
netdev->state &= ~NETDEV_OPEN;
|
|
||||||
|
|
||||||
/* Remove from open devices list */
|
|
||||||
list_del ( &netdev->open_list );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -457,10 +513,15 @@ void netdev_close ( struct net_device *netdev ) {
|
||||||
* Removes the network device from the list of network devices.
|
* Removes the network device from the list of network devices.
|
||||||
*/
|
*/
|
||||||
void unregister_netdev ( struct net_device *netdev ) {
|
void unregister_netdev ( struct net_device *netdev ) {
|
||||||
|
struct net_driver *driver;
|
||||||
|
|
||||||
/* Ensure device is closed */
|
/* Ensure device is closed */
|
||||||
netdev_close ( netdev );
|
netdev_close ( netdev );
|
||||||
|
|
||||||
|
/* Remove device */
|
||||||
|
for_each_table_entry_reverse ( driver, NET_DRIVERS )
|
||||||
|
driver->remove ( netdev );
|
||||||
|
|
||||||
/* Unregister per-netdev configuration settings */
|
/* Unregister per-netdev configuration settings */
|
||||||
unregister_settings ( netdev_settings ( netdev ) );
|
unregister_settings ( netdev_settings ( netdev ) );
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue