iPXE
Data Structures | Functions | Variables
vlan.c File Reference

Virtual LANs. More...

#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <byteswap.h>
#include <ipxe/features.h>
#include <ipxe/if_ether.h>
#include <ipxe/ethernet.h>
#include <ipxe/netdevice.h>
#include <ipxe/iobuf.h>
#include <ipxe/vlan.h>

Go to the source code of this file.

Data Structures

struct  vlan_device
 VLAN device private data. More...

Functions

 FILE_LICENCE (GPL2_OR_LATER)
 FEATURE (FEATURE_PROTOCOL,"VLAN", DHCP_EB_FEATURE_VLAN, 1)
static int vlan_open (struct net_device *netdev)
 Open VLAN device.
static void vlan_close (struct net_device *netdev)
 Close VLAN device.
static int vlan_transmit (struct net_device *netdev, struct io_buffer *iobuf)
 Transmit packet on VLAN device.
static void vlan_poll (struct net_device *netdev)
 Poll VLAN device.
static void vlan_irq (struct net_device *netdev, int enable)
 Enable/disable interrupts on VLAN device.
static void vlan_sync (struct net_device *netdev)
 Synchronise VLAN device.
struct net_devicevlan_find (struct net_device *trunk, unsigned int tag)
 Identify VLAN device.
static int vlan_rx (struct io_buffer *iobuf, struct net_device *trunk, const void *ll_dest, const void *ll_source, unsigned int flags __unused)
 Process incoming VLAN packet.
unsigned int vlan_tag (struct net_device *netdev)
 Get the VLAN tag.
int vlan_can_be_trunk (struct net_device *trunk)
 Check if network device can be used as a VLAN trunk device.
int vlan_create (struct net_device *trunk, unsigned int tag, unsigned int priority)
 Create VLAN device.
int vlan_destroy (struct net_device *netdev)
 Destroy VLAN device.
static void vlan_notify (struct net_device *trunk)
 Handle trunk network device link state change.
static int vlan_remove_first (struct net_device *trunk)
 Destroy first VLAN device for a given trunk.
static void vlan_remove (struct net_device *trunk)
 Destroy all VLAN devices for a given trunk.

Variables

struct net_protocol vlan_protocol __net_protocol
 VLAN protocol.
static struct net_device_operations vlan_operations
 VLAN device operations.
struct net_driver vlan_driver __net_driver
 VLAN driver.

Detailed Description

Virtual LANs.

Definition in file vlan.c.


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER  )
FEATURE ( FEATURE_PROTOCOL  ,
"VLAN"  ,
DHCP_EB_FEATURE_VLAN  ,
 
)
static int vlan_open ( struct net_device netdev) [static]

Open VLAN device.

Parameters:
netdevNetwork device
Return values:
rcReturn status code

Definition at line 60 of file vlan.c.

References netdev_open(), net_device::priv, and vlan_device::trunk.

                                                   {
        struct vlan_device *vlan = netdev->priv;

        return netdev_open ( vlan->trunk );
}
static void vlan_close ( struct net_device netdev) [static]

Close VLAN device.

Parameters:
netdevNetwork device

Definition at line 71 of file vlan.c.

References netdev_close(), net_device::priv, and vlan_device::trunk.

                                                     {
        struct vlan_device *vlan = netdev->priv;

        netdev_close ( vlan->trunk );
}
static int vlan_transmit ( struct net_device netdev,
struct io_buffer iobuf 
) [static]

Transmit packet on VLAN device.

Parameters:
netdevNetwork device
iobufI/O buffer
Return values:
rcReturn status code

Definition at line 84 of file vlan.c.

References DBGC, ETH_ALEN, flags, htons, iob_disown, iob_push, io_buffer::list, list_del, net_device::ll_protocol, net_device::name, vlan_header::net_proto, net_proto, net_tx(), vlan_device::priority, net_device::priv, ll_protocol::pull, rc, strerror(), vlan_device::tag, vlan_header::tci, vlan_device::trunk, and VLAN_TCI.

                                                     {
        struct vlan_device *vlan = netdev->priv;
        struct net_device *trunk = vlan->trunk;
        struct ll_protocol *ll_protocol;
        struct vlan_header *vlanhdr;
        uint8_t ll_dest_copy[ETH_ALEN];
        uint8_t ll_source_copy[ETH_ALEN];
        const void *ll_dest;
        const void *ll_source;
        uint16_t net_proto;
        unsigned int flags;
        int rc;

        /* Strip link-layer header and preserve link-layer header fields */
        ll_protocol = netdev->ll_protocol;
        if ( ( rc = ll_protocol->pull ( netdev, iobuf, &ll_dest, &ll_source,
                                        &net_proto, &flags ) ) != 0 ) {
                DBGC ( netdev, "VLAN %s could not parse link-layer header: "
                       "%s\n", netdev->name, strerror ( rc ) );
                return rc;
        }
        memcpy ( ll_dest_copy, ll_dest, ETH_ALEN );
        memcpy ( ll_source_copy, ll_source, ETH_ALEN );

        /* Construct VLAN header */
        vlanhdr = iob_push ( iobuf, sizeof ( *vlanhdr ) );
        vlanhdr->tci = htons ( VLAN_TCI ( vlan->tag, vlan->priority ) );
        vlanhdr->net_proto = net_proto;

        /* Reclaim I/O buffer from VLAN device's TX queue */
        list_del ( &iobuf->list );

        /* Transmit packet on trunk device */
        if ( ( rc = net_tx ( iob_disown ( iobuf ), trunk, &vlan_protocol,
                             ll_dest_copy, ll_source_copy ) ) != 0 ) {
                DBGC ( netdev, "VLAN %s could not transmit: %s\n",
                       netdev->name, strerror ( rc ) );
                /* Cannot return an error status, since that would
                 * cause the I/O buffer to be double-freed.
                 */
                return 0;
        }

        return 0;
}
static void vlan_poll ( struct net_device netdev) [static]

Poll VLAN device.

Parameters:
netdevNetwork device

Definition at line 136 of file vlan.c.

References netdev_poll(), net_device::priv, and vlan_device::trunk.

                                                    {
        struct vlan_device *vlan = netdev->priv;

        /* Poll trunk device */
        netdev_poll ( vlan->trunk );
}
static void vlan_irq ( struct net_device netdev,
int  enable 
) [static]

Enable/disable interrupts on VLAN device.

Parameters:
netdevNetwork device
enableInterrupts should be enabled

Definition at line 149 of file vlan.c.

References netdev_irq(), net_device::priv, and vlan_device::trunk.

                                                               {
        struct vlan_device *vlan = netdev->priv;

        /* Enable/disable interrupts on trunk device.  This is not at
         * all robust, but there is no sensible course of action
         * available.
         */
        netdev_irq ( vlan->trunk, enable );
}
static void vlan_sync ( struct net_device netdev) [static]

Synchronise VLAN device.

Parameters:
netdevNetwork device

Definition at line 173 of file vlan.c.

References net_device::link_rc, netdev_close(), netdev_is_open(), netdev_link_err(), netdev_open(), net_device::priv, and vlan_device::trunk.

Referenced by vlan_create(), and vlan_notify().

                                                    {
        struct vlan_device *vlan = netdev->priv;
        struct net_device *trunk = vlan->trunk;

        /* Synchronise link status */
        if ( netdev->link_rc != trunk->link_rc )
                netdev_link_err ( netdev, trunk->link_rc );

        /* Synchronise open/closed status */
        if ( netdev_is_open ( trunk ) ) {
                if ( ! netdev_is_open ( netdev ) )
                        netdev_open ( netdev );
        } else {
                if ( netdev_is_open ( netdev ) )
                        netdev_close ( netdev );
        }
}
struct net_device* vlan_find ( struct net_device trunk,
unsigned int  tag 
) [read]

Identify VLAN device.

Parameters:
trunkTrunk network device
tagVLAN tag
Return values:
netdevVLAN device, if any

Definition at line 198 of file vlan.c.

References for_each_netdev, netdev, NULL, net_device::op, net_device::priv, vlan_device::tag, and vlan_device::trunk.

                                                                             {
        struct net_device *netdev;
        struct vlan_device *vlan;

        for_each_netdev ( netdev ) {
                if ( netdev->op != &vlan_operations )
                        continue;
                vlan = netdev->priv;
                if ( ( vlan->trunk == trunk ) && ( vlan->tag == tag ) )
                        return netdev;
        }
        return NULL;
}
static int vlan_rx ( struct io_buffer iobuf,
struct net_device trunk,
const void *  ll_dest,
const void *  ll_source,
unsigned int flags  __unused 
) [static]

Process incoming VLAN packet.

Parameters:
iobufI/O buffer
trunkTrunk network device
ll_destLink-layer destination address
ll_sourceLink-layer source address
flagsPacket flags
Return values:
rcReturn status code

Definition at line 222 of file vlan.c.

References io_buffer::data, DBGC, DBGC2, EINVAL, EPIPE, ETH_ALEN, free_iob(), iob_disown, iob_len(), iob_pull, net_device::ll_protocol, net_device::name, vlan_header::net_proto, netdev, netdev_rx(), ntohs, ll_protocol::push, rc, strerror(), tag, vlan_header::tci, vlan_find(), and VLAN_TAG.

                                                   {
        struct vlan_header *vlanhdr = iobuf->data;
        struct net_device *netdev;
        struct ll_protocol *ll_protocol;
        uint8_t ll_dest_copy[ETH_ALEN];
        uint8_t ll_source_copy[ETH_ALEN];
        uint16_t tag;
        int rc;

        /* Sanity check */
        if ( iob_len ( iobuf ) < sizeof ( *vlanhdr ) ) {
                DBGC ( trunk, "VLAN %s received underlength packet (%zd "
                       "bytes)\n", trunk->name, iob_len ( iobuf ) );
                rc = -EINVAL;
                goto err_sanity;
        }

        /* Identify VLAN device */
        tag = VLAN_TAG ( ntohs ( vlanhdr->tci ) );
        netdev = vlan_find ( trunk, tag );
        if ( ! netdev ) {
                DBGC2 ( trunk, "VLAN %s received packet for unknown VLAN "
                        "%d\n", trunk->name, tag );
                rc = -EPIPE;
                goto err_no_vlan;
        }

        /* Strip VLAN header and preserve original link-layer header fields */
        iob_pull ( iobuf, sizeof ( *vlanhdr ) );
        ll_protocol = trunk->ll_protocol;
        memcpy ( ll_dest_copy, ll_dest, ETH_ALEN );
        memcpy ( ll_source_copy, ll_source, ETH_ALEN );

        /* Reconstruct link-layer header for VLAN device */
        ll_protocol = netdev->ll_protocol;
        if ( ( rc = ll_protocol->push ( netdev, iobuf, ll_dest_copy,
                                        ll_source_copy,
                                        vlanhdr->net_proto ) ) != 0 ) {
                DBGC ( netdev, "VLAN %s could not reconstruct link-layer "
                       "header: %s\n", netdev->name, strerror ( rc ) );
                goto err_ll_push;
        }

        /* Enqueue packet on VLAN device */
        netdev_rx ( netdev, iob_disown ( iobuf ) );
        return 0;

 err_ll_push:
 err_no_vlan:
 err_sanity:
        free_iob ( iobuf );
        return rc;
}
unsigned int vlan_tag ( struct net_device netdev)

Get the VLAN tag.

Parameters:
netdevNetwork device
Return values:
tagVLAN tag, or 0 if device is not a VLAN device

Definition at line 291 of file vlan.c.

References net_device::op, net_device::priv, and vlan_device::tag.

                                                    {
        struct vlan_device *vlan;

        if ( netdev->op == &vlan_operations ) {
                vlan = netdev->priv;
                return vlan->tag;
        } else {
                return 0;
        }
}
int vlan_can_be_trunk ( struct net_device trunk)

Check if network device can be used as a VLAN trunk device.

Parameters:
trunkTrunk network device
Return values:
is_okTrunk network device is usable

VLAN devices will be created as Ethernet devices. (We cannot simply clone the link layer of the trunk network device, because this link layer may expect the network device structure to contain some link-layer-private data.) The trunk network device must therefore have a link layer that is in some sense 'compatible' with Ethernet; specifically, it must have link-layer addresses that are the same length as Ethernet link-layer addresses.

As an additional check, and primarily to assist with the sanity of the FCoE code, we refuse to allow nested VLANs.

Definition at line 319 of file vlan.c.

References ETH_ALEN, ll_protocol::ll_addr_len, net_device::ll_protocol, and net_device::op.

Referenced by fcoe_expired(), fcoe_reset(), and vlan_create().

                                                   {

        return ( ( trunk->ll_protocol->ll_addr_len == ETH_ALEN ) &&
                 ( trunk->op != &vlan_operations ) );
}
int vlan_create ( struct net_device trunk,
unsigned int  tag,
unsigned int  priority 
)

Create VLAN device.

Parameters:
trunkTrunk network device
tagVLAN tag
priorityDefault VLAN priority
Return values:
rcReturn status code

Definition at line 333 of file vlan.c.

References alloc_etherdev(), DBGC, net_device::dev, EINVAL, ENOMEM, ENOTTY, ETH_ALEN, net_device::hw_addr, net_device::ll_addr, net_device::name, netdev, netdev_get(), netdev_init(), netdev_nullify(), netdev_put(), NULL, vlan_device::priority, net_device::priv, rc, register_netdev(), snprintf(), strerror(), vlan_device::tag, tag, vlan_device::trunk, unregister_netdev(), vlan_can_be_trunk(), vlan_find(), VLAN_PRIORITY_IS_VALID, vlan_sync(), and VLAN_TAG_IS_VALID.

Referenced by fcoe_fip_rx_vlan(), and vcreate_exec().

                                          {
        struct net_device *netdev;
        struct vlan_device *vlan;
        int rc;

        /* If VLAN already exists, just update the priority */
        if ( ( netdev = vlan_find ( trunk, tag ) ) != NULL ) {
                vlan = netdev->priv;
                if ( priority != vlan->priority ) {
                        DBGC ( netdev, "VLAN %s priority changed from %d to "
                               "%d\n", netdev->name, vlan->priority, priority );
                }
                vlan->priority = priority;
                return 0;
        }

        /* Sanity checks */
        if ( ! vlan_can_be_trunk ( trunk ) ) {
                DBGC ( trunk, "VLAN %s cannot create VLAN on non-trunk "
                       "device\n", trunk->name );
                rc = -ENOTTY;
                goto err_sanity;
        }
        if ( ! VLAN_TAG_IS_VALID ( tag ) ) {
                DBGC ( trunk, "VLAN %s cannot create VLAN with invalid tag "
                       "%d\n", trunk->name, tag );
                rc = -EINVAL;
                goto err_sanity;
        }
        if ( ! VLAN_PRIORITY_IS_VALID ( priority ) ) {
                DBGC ( trunk, "VLAN %s cannot create VLAN with invalid "
                       "priority %d\n", trunk->name, priority );
                rc = -EINVAL;
                goto err_sanity;
        }

        /* Allocate and initialise structure */
        netdev = alloc_etherdev ( sizeof ( *vlan ) );
        if ( ! netdev ) {
                rc = -ENOMEM;
                goto err_alloc_etherdev;
        }
        netdev_init ( netdev, &vlan_operations );
        netdev->dev = trunk->dev;
        memcpy ( netdev->hw_addr, trunk->ll_addr, ETH_ALEN );
        vlan = netdev->priv;
        vlan->trunk = netdev_get ( trunk );
        vlan->tag = tag;
        vlan->priority = priority;

        /* Construct VLAN device name */
        snprintf ( netdev->name, sizeof ( netdev->name ), "%s-%d",
                   trunk->name, vlan->tag );

        /* Register VLAN device */
        if ( ( rc = register_netdev ( netdev ) ) != 0 ) {
                DBGC ( netdev, "VLAN %s could not register: %s\n",
                       netdev->name, strerror ( rc ) );
                goto err_register;
        }

        /* Synchronise with trunk device */
        vlan_sync ( netdev );

        DBGC ( netdev, "VLAN %s created with tag %d and priority %d\n",
               netdev->name, vlan->tag, vlan->priority );

        return 0;

        unregister_netdev ( netdev );
 err_register:
        netdev_nullify ( netdev );
        netdev_put ( netdev );
        netdev_put ( trunk );
 err_alloc_etherdev:
 err_sanity:
        return rc;
}
int vlan_destroy ( struct net_device netdev)

Destroy VLAN device.

Parameters:
netdevNetwork device
Return values:
rcReturn status code

Definition at line 419 of file vlan.c.

References DBGC, ENOTTY, net_device::name, netdev_nullify(), netdev_put(), net_device::op, net_device::priv, vlan_device::trunk, and unregister_netdev().

Referenced by vdestroy_exec(), and vlan_remove_first().

                                               {
        struct vlan_device *vlan = netdev->priv;
        struct net_device *trunk;

        /* Sanity check */
        if ( netdev->op != &vlan_operations ) {
                DBGC ( netdev, "VLAN %s cannot destroy non-VLAN device\n",
                       netdev->name );
                return -ENOTTY;
        }

        DBGC ( netdev, "VLAN %s destroyed\n", netdev->name );

        /* Remove VLAN device */
        unregister_netdev ( netdev );
        trunk = vlan->trunk;
        netdev_nullify ( netdev );
        netdev_put ( netdev );
        netdev_put ( trunk );

        return 0;
}
static void vlan_notify ( struct net_device trunk) [static]

Handle trunk network device link state change.

Parameters:
trunkTrunk network device

Definition at line 447 of file vlan.c.

References for_each_netdev, netdev, net_device::op, net_device::priv, vlan_device::trunk, and vlan_sync().

                                                     {
        struct net_device *netdev;
        struct vlan_device *vlan;

        for_each_netdev ( netdev ) {
                if ( netdev->op != &vlan_operations )
                        continue;
                vlan = netdev->priv;
                if ( vlan->trunk == trunk )
                        vlan_sync ( netdev );
        }
}
static int vlan_remove_first ( struct net_device trunk) [static]

Destroy first VLAN device for a given trunk.

Parameters:
trunkTrunk network device
Return values:
foundA VLAN device was found

Definition at line 466 of file vlan.c.

References for_each_netdev, netdev, net_device::op, net_device::priv, vlan_device::trunk, and vlan_destroy().

Referenced by vlan_remove().

                                                          {
        struct net_device *netdev;
        struct vlan_device *vlan;

        for_each_netdev ( netdev ) {
                if ( netdev->op != &vlan_operations )
                        continue;
                vlan = netdev->priv;
                if ( vlan->trunk == trunk ) {
                        vlan_destroy ( netdev );
                        return 1;
                }
        }
        return 0;
}
static void vlan_remove ( struct net_device trunk) [static]

Destroy all VLAN devices for a given trunk.

Parameters:
trunkTrunk network device

Definition at line 487 of file vlan.c.

References vlan_remove_first().

                                                     {

        /* Remove all VLAN devices attached to this trunk, safe
         * against arbitrary net device removal.
         */
        while ( vlan_remove_first ( trunk ) ) {}
}

Variable Documentation

struct net_protocol vlan_protocol __net_protocol
Initial value:
 {
        .name = "VLAN",
        .net_proto = htons ( ETH_P_8021Q ),
        .rx = vlan_rx,
}

VLAN protocol.

AoE protocol.

Definition at line 42 of file vlan.c.

Initial value:
 {
        .open           = vlan_open,
        .close          = vlan_close,
        .transmit       = vlan_transmit,
        .poll           = vlan_poll,
        .irq            = vlan_irq,
}

VLAN device operations.

Definition at line 160 of file vlan.c.

struct net_driver vlan_driver __net_driver
Initial value:
 {
        .name = "VLAN",
        .notify = vlan_notify,
        .remove = vlan_remove,
}

VLAN driver.

Definition at line 496 of file vlan.c.