summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Brown2023-09-13 21:23:59 +0200
committerMichael Brown2023-09-14 00:02:47 +0200
commitcc1e27e525201f5ee7fcc098f47f04ec26814289 (patch)
tree43d0730fb0c4a896348cacccea01aa410b2c6ccd
parent[netdevice] Allocate private data for each network upper-layer driver (diff)
downloadipxe-cc1e27e525201f5ee7fcc098f47f04ec26814289.tar.gz
ipxe-cc1e27e525201f5ee7fcc098f47f04ec26814289.tar.xz
ipxe-cc1e27e525201f5ee7fcc098f47f04ec26814289.zip
[lldp] Use driver-private data to hold LLDP settings block
Simplify the LLDP code by using driver-private data to hold the LLDP settings block, instead of using a separate allocation. This avoids the need to maintain a list of LLDP settings blocks (since the LLDP settings block pointer can always be obtained using netdev_priv()) and obviates several failure paths. Any recorded LLDP data is now freed when the network device is unregistered, since there is no longer a dedicated reference counter for the LLDP settings block. To minimise surprise, we also now explicitly unregister the settings block. This is not strictly necessary (since the block will be automatically unregistered when the parent network device settings block is unregistered), but it maintains symmetry between lldp_probe() and lldp_remove(). The overall reduction in the size of the LLDP code is around 15%. Signed-off-by: Michael Brown <mcb30@ipxe.org>
-rw-r--r--src/net/lldp.c94
1 files changed, 31 insertions, 63 deletions
diff --git a/src/net/lldp.c b/src/net/lldp.c
index 2ef32cb0..a854d0ac 100644
--- a/src/net/lldp.c
+++ b/src/net/lldp.c
@@ -40,12 +40,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** An LLDP settings block */
struct lldp_settings {
- /** Reference counter */
- struct refcnt refcnt;
/** Settings interface */
struct settings settings;
- /** List of LLDP settings blocks */
- struct list_head list;
/** Name */
const char *name;
/** LLDP data */
@@ -54,45 +50,12 @@ struct lldp_settings {
size_t len;
};
+/* Forward declaration */
+struct net_driver lldp_driver __net_driver;
+
/** LLDP settings scope */
static const struct settings_scope lldp_settings_scope;
-/** List of LLDP settings blocks */
-static LIST_HEAD ( lldp_settings );
-
-/**
- * Free LLDP settings block
- *
- * @v refcnt Reference counter
- */
-static void lldp_free ( struct refcnt *refcnt ) {
- struct lldp_settings *lldpset =
- container_of ( refcnt, struct lldp_settings, refcnt );
-
- DBGC ( lldpset, "LLDP %s freed\n", lldpset->name );
- list_del ( &lldpset->list );
- free ( lldpset->data );
- free ( lldpset );
-}
-
-/**
- * Find LLDP settings block
- *
- * @v netdev Network device
- * @ret lldpset LLDP settings block
- */
-static struct lldp_settings * lldp_find ( struct net_device *netdev ) {
- struct lldp_settings *lldpset;
-
- /* Find matching LLDP settings block */
- list_for_each_entry ( lldpset, &lldp_settings, list ) {
- if ( netdev_settings ( netdev ) == lldpset->settings.parent )
- return lldpset;
- }
-
- return NULL;
-}
-
/**
* Check applicability of LLDP setting
*
@@ -246,13 +209,7 @@ static int lldp_rx ( struct io_buffer *iobuf, struct net_device *netdev,
int rc;
/* Find matching LLDP settings block */
- lldpset = lldp_find ( netdev );
- if ( ! lldpset ) {
- DBGC ( netdev, "LLDP %s has no \"%s\" settings block\n",
- netdev->name, LLDP_SETTINGS_NAME );
- rc = -ENOENT;
- goto err_find;
- }
+ lldpset = netdev_priv ( netdev, &lldp_driver );
/* Create trimmed copy of received LLDP data */
len = iob_len ( iobuf );
@@ -280,7 +237,6 @@ static int lldp_rx ( struct io_buffer *iobuf, struct net_device *netdev,
free ( data );
err_alloc:
- err_find:
free_iob ( iobuf );
return rc;
}
@@ -299,24 +255,18 @@ struct net_protocol lldp_protocol __net_protocol = {
* @v priv Private data
* @ret rc Return status code
*/
-static int lldp_probe ( struct net_device *netdev, void *priv __unused ) {
- struct lldp_settings *lldpset;
+static int lldp_probe ( struct net_device *netdev, void *priv ) {
+ struct lldp_settings *lldpset = priv;
int rc;
- /* Allocate LLDP settings block */
- lldpset = zalloc ( sizeof ( *lldpset ) );
- if ( ! lldpset ) {
- rc = -ENOMEM;
- goto err_alloc;
- }
- ref_init ( &lldpset->refcnt, lldp_free );
+ /* Initialise LLDP settings block */
settings_init ( &lldpset->settings, &lldp_settings_operations,
- &lldpset->refcnt, &lldp_settings_scope );
- list_add_tail ( &lldpset->list, &lldp_settings );
+ &netdev->refcnt, &lldp_settings_scope );
lldpset->name = netdev->name;
/* Register settings */
- if ( ( rc = register_settings ( &lldpset->settings, netdev_settings ( netdev ),
+ if ( ( rc = register_settings ( &lldpset->settings,
+ netdev_settings ( netdev ),
LLDP_SETTINGS_NAME ) ) != 0 ) {
DBGC ( lldpset, "LLDP %s could not register settings: %s\n",
lldpset->name, strerror ( rc ) );
@@ -324,18 +274,36 @@ static int lldp_probe ( struct net_device *netdev, void *priv __unused ) {
}
DBGC ( lldpset, "LLDP %s registered\n", lldpset->name );
- ref_put ( &lldpset->refcnt );
return 0;
unregister_settings ( &lldpset->settings );
err_register:
- ref_put ( &lldpset->refcnt );
- err_alloc:
+ assert ( lldpset->data == NULL );
return rc;
}
+/**
+ * Remove LLDP settings block
+ *
+ * @v netdev Network device
+ * @v priv Private data
+ */
+static void lldp_remove ( struct net_device *netdev __unused, void *priv ) {
+ struct lldp_settings *lldpset = priv;
+
+ /* Unregister settings */
+ unregister_settings ( &lldpset->settings );
+ DBGC ( lldpset, "LLDP %s unregistered\n", lldpset->name );
+
+ /* Free any LLDP data */
+ free ( lldpset->data );
+ lldpset->data = NULL;
+}
+
/** LLDP driver */
struct net_driver lldp_driver __net_driver = {
.name = "LLDP",
+ .priv_len = sizeof ( struct lldp_settings ),
.probe = lldp_probe,
+ .remove = lldp_remove,
};