[gPXE-devel] [PATCH] 802.1Q support for gpxe

Stefan Hajnoczi stefanha at gmail.com
Mon Apr 19 15:26:24 EDT 2010


+static const char * vid_ntoa ( const void *net_addr ) {
+	static char buf[2]; /* "00" */
+        const uint8_t eth_addr = * (uint8_t*)net_addr;
+
+        sprintf ( buf, "%02x", eth_addr);
+        return buf;
+}
The array should be buf[3] so there is space for the NUL terminator.

How about something like the following to eliminate memory management
and simplify things (I have not tried compiling this code):

struct vlan_device {
	struct net_device* target;	/* the underlying raw device */
	struct net_device* netdev;	/* the vlan device */
	struct list_head list;		/* vlan devices */

	uint16_t vlanid;
	uint8_t prio;

	struct ll_protocol ll_protocol;
};

static LIST_HEAD ( ieee8021q_devices );

struct net_device * ieee8021q_create ( struct net_device* target,
uint16_t vid, uint8_t prio ) {
	struct vlan_device *vdev;
	struct net_device* netdev;

	netdev = alloc_netdev ( sizeof ( *vdev ) );
	if ( !netdev )
		return NULL;

	netdev_init ( netdev, &ieee8021q_operations );
	vdev = netdev->priv;
	vdev->target = target;

	memcpy ( &vdev->ll_protocol, target->ll_protocol, sizeof (
*target->ll_protocol ) );
	vdev->ll_protocol.push = ieee8021q_push;
	netdev->ll_protocol = &vdev->ll_protocol;

	netdev->ll_broadcast = target->ll_broadcast;
	netdev->max_pkt_len = target->max_pkt_len;
	memcpy(netdev->hw_addr,target->hw_addr,sizeof(netdev->hw_addr));
	netdev->state = target->state;

	snprintf ( netdev->name, sizeof ( netdev->name ), "%s.%d", target->name, vid);

	/* Mark as link up; we don't yet handle link state */
	netdev_link_up ( netdev );

	/* Register network device */
	if ( register_netdev ( netdev ) != 0 )
		goto err_register_netdev;

	/* write-back ll_addr init */
	memcpy(netdev->ll_addr,target->ll_addr,sizeof(netdev->ll_addr));

	/* add netdev to list */
	vdev->netdev = netdev;
	list_add(&vdev->list, &ieee8021q_devices);

	/* set target device */
	vdev->target = netdev_get(target);
	vdev->vlanid = vid;
	vdev->prio = prio;

	DBG("Added device %s.\n", netdev->name);

	return netdev;

 err_register_netdev:
	netdev_nullify ( netdev );
	netdev_put ( netdev );
	return NULL;
}

int ieee8021q_remove ( struct net_device* netdev) {
	struct vlan_device* vdev = netdev->priv;

	if (netdev->op->open != ieee8021q_open) {
		DBG("Sorry, but this does not look like a ieee8021q device.\n"
				"So I won't remove it!\n");
		return -EINVAL;
	}

	unregister_netdev ( netdev );
	netdev_put ( vdev->target );
	netdev_nullify ( netdev );
	netdev_put ( netdev );
	return 0;
}

Some minor changes also added above were using NULL instead of 0 for a pointer
value to follow gPXE coding style.  I also suggest adding error code to
ieee8021q_remove() so that the user can get error feedback if they tried to
remove a non-802.1q device.

As for the zero-copy transmit approach, I think it could be done with
a iob_orphan()
function which calls list_del() on the io_buffer.  It might require
always returning
success from the transmit function though.

Another side effect is that transmit statistics will be missing for
the vlan netdevice.
I think we already don't collect receive statistics on the vlan device
because the
io_buffers are received by the target device.  So perhaps that is not
a big loss.

Stefan


More information about the gPXE-devel mailing list