Annotation of qemu/roms/ipxe/src/net/vlan.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (C) 2010 Michael Brown <[email protected]>.
                      3:  *
                      4:  * This program is free software; you can redistribute it and/or
                      5:  * modify it under the terms of the GNU General Public License as
                      6:  * published by the Free Software Foundation; either version 2 of the
                      7:  * License, or any later version.
                      8:  *
                      9:  * This program is distributed in the hope that it will be useful, but
                     10:  * WITHOUT ANY WARRANTY; without even the implied warranty of
                     11:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                     12:  * General Public License for more details.
                     13:  *
                     14:  * You should have received a copy of the GNU General Public License
                     15:  * along with this program; if not, write to the Free Software
                     16:  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
                     17:  */
                     18: 
                     19: FILE_LICENCE ( GPL2_OR_LATER );
                     20: 
                     21: #include <stdint.h>
                     22: #include <string.h>
                     23: #include <stdio.h>
                     24: #include <errno.h>
                     25: #include <byteswap.h>
                     26: #include <ipxe/features.h>
                     27: #include <ipxe/if_ether.h>
                     28: #include <ipxe/ethernet.h>
                     29: #include <ipxe/netdevice.h>
                     30: #include <ipxe/iobuf.h>
                     31: #include <ipxe/vlan.h>
                     32: 
                     33: /** @file
                     34:  *
                     35:  * Virtual LANs
                     36:  *
                     37:  */
                     38: 
                     39: FEATURE ( FEATURE_PROTOCOL, "VLAN", DHCP_EB_FEATURE_VLAN, 1 );
                     40: 
                     41: struct net_protocol vlan_protocol __net_protocol;
                     42: 
                     43: /** VLAN device private data */
                     44: struct vlan_device {
                     45:        /** Trunk network device */
                     46:        struct net_device *trunk;
                     47:        /** VLAN tag */
                     48:        unsigned int tag;
                     49:        /** Default priority */
                     50:        unsigned int priority;
                     51: };
                     52: 
                     53: /**
                     54:  * Open VLAN device
                     55:  *
                     56:  * @v netdev           Network device
                     57:  * @ret rc             Return status code
                     58:  */
                     59: static int vlan_open ( struct net_device *netdev ) {
                     60:        struct vlan_device *vlan = netdev->priv;
                     61: 
                     62:        return netdev_open ( vlan->trunk );
                     63: }
                     64: 
                     65: /**
                     66:  * Close VLAN device
                     67:  *
                     68:  * @v netdev           Network device
                     69:  */
                     70: static void vlan_close ( struct net_device *netdev ) {
                     71:        struct vlan_device *vlan = netdev->priv;
                     72: 
                     73:        netdev_close ( vlan->trunk );
                     74: }
                     75: 
                     76: /**
                     77:  * Transmit packet on VLAN device
                     78:  *
                     79:  * @v netdev           Network device
                     80:  * @v iobuf            I/O buffer
                     81:  * @ret rc             Return status code
                     82:  */
                     83: static int vlan_transmit ( struct net_device *netdev,
                     84:                           struct io_buffer *iobuf ) {
                     85:        struct vlan_device *vlan = netdev->priv;
                     86:        struct net_device *trunk = vlan->trunk;
                     87:        struct ll_protocol *ll_protocol;
                     88:        struct vlan_header *vlanhdr;
                     89:        uint8_t ll_dest_copy[ETH_ALEN];
                     90:        uint8_t ll_source_copy[ETH_ALEN];
                     91:        const void *ll_dest;
                     92:        const void *ll_source;
                     93:        uint16_t net_proto;
                     94:        int rc;
                     95: 
                     96:        /* Strip link-layer header and preserve link-layer header fields */
                     97:        ll_protocol = netdev->ll_protocol;
                     98:        if ( ( rc = ll_protocol->pull ( netdev, iobuf, &ll_dest, &ll_source,
                     99:                                        &net_proto ) ) != 0 ) {
                    100:                DBGC ( netdev, "VLAN %s could not parse link-layer header: "
                    101:                       "%s\n", netdev->name, strerror ( rc ) );
                    102:                return rc;
                    103:        }
                    104:        memcpy ( ll_dest_copy, ll_dest, ETH_ALEN );
                    105:        memcpy ( ll_source_copy, ll_source, ETH_ALEN );
                    106: 
                    107:        /* Construct VLAN header */
                    108:        vlanhdr = iob_push ( iobuf, sizeof ( *vlanhdr ) );
                    109:        vlanhdr->tci = htons ( VLAN_TCI ( vlan->tag, vlan->priority ) );
                    110:        vlanhdr->net_proto = net_proto;
                    111: 
                    112:        /* Reclaim I/O buffer from VLAN device's TX queue */
                    113:        list_del ( &iobuf->list );
                    114: 
                    115:        /* Transmit packet on trunk device */
                    116:        if ( ( rc = net_tx ( iob_disown ( iobuf ), trunk, &vlan_protocol,
                    117:                             ll_dest_copy, ll_source_copy ) ) != 0 ) {
                    118:                DBGC ( netdev, "VLAN %s could not transmit: %s\n",
                    119:                       netdev->name, strerror ( rc ) );
                    120:                /* Cannot return an error status, since that would
                    121:                 * cause the I/O buffer to be double-freed.
                    122:                 */
                    123:                return 0;
                    124:        }
                    125: 
                    126:        return 0;
                    127: }
                    128: 
                    129: /**
                    130:  * Poll VLAN device
                    131:  *
                    132:  * @v netdev           Network device
                    133:  */
                    134: static void vlan_poll ( struct net_device *netdev ) {
                    135:        struct vlan_device *vlan = netdev->priv;
                    136: 
                    137:        /* Poll trunk device */
                    138:        netdev_poll ( vlan->trunk );
                    139: }
                    140: 
                    141: /**
                    142:  * Enable/disable interrupts on VLAN device
                    143:  *
                    144:  * @v netdev           Network device
                    145:  * @v enable           Interrupts should be enabled
                    146:  */
                    147: static void vlan_irq ( struct net_device *netdev, int enable ) {
                    148:        struct vlan_device *vlan = netdev->priv;
                    149: 
                    150:        /* Enable/disable interrupts on trunk device.  This is not at
                    151:         * all robust, but there is no sensible course of action
                    152:         * available.
                    153:         */
                    154:        netdev_irq ( vlan->trunk, enable );
                    155: }
                    156: 
                    157: /** VLAN device operations */
                    158: static struct net_device_operations vlan_operations = {
                    159:        .open           = vlan_open,
                    160:        .close          = vlan_close,
                    161:        .transmit       = vlan_transmit,
                    162:        .poll           = vlan_poll,
                    163:        .irq            = vlan_irq,
                    164: };
                    165: 
                    166: /**
                    167:  * Synchronise VLAN device
                    168:  *
                    169:  * @v netdev           Network device
                    170:  */
                    171: static void vlan_sync ( struct net_device *netdev ) {
                    172:        struct vlan_device *vlan = netdev->priv;
                    173:        struct net_device *trunk = vlan->trunk;
                    174: 
                    175:        /* Synchronise link status */
                    176:        if ( netdev->link_rc != trunk->link_rc )
                    177:                netdev_link_err ( netdev, trunk->link_rc );
                    178: 
                    179:        /* Synchronise open/closed status */
                    180:        if ( netdev_is_open ( trunk ) ) {
                    181:                if ( ! netdev_is_open ( netdev ) )
                    182:                        netdev_open ( netdev );
                    183:        } else {
                    184:                if ( netdev_is_open ( netdev ) )
                    185:                        netdev_close ( netdev );
                    186:        }
                    187: }
                    188: 
                    189: /**
                    190:  * Identify VLAN device
                    191:  *
                    192:  * @v trunk            Trunk network device
                    193:  * @v tag              VLAN tag
                    194:  * @ret netdev         VLAN device, if any
                    195:  */
                    196: struct net_device * vlan_find ( struct net_device *trunk, unsigned int tag ) {
                    197:        struct net_device *netdev;
                    198:        struct vlan_device *vlan;
                    199: 
                    200:        for_each_netdev ( netdev ) {
                    201:                if ( netdev->op != &vlan_operations )
                    202:                        continue;
                    203:                vlan = netdev->priv;
                    204:                if ( ( vlan->trunk == trunk ) && ( vlan->tag == tag ) )
                    205:                        return netdev;
                    206:        }
                    207:        return NULL;
                    208: }
                    209: 
                    210: /**
                    211:  * Process incoming VLAN packet
                    212:  *
                    213:  * @v iobuf            I/O buffer
                    214:  * @v trunk            Trunk network device
                    215:  * @v ll_dest          Link-layer destination address
                    216:  * @v ll_source                Link-layer source address
                    217:  * @ret rc             Return status code
                    218:  */
                    219: static int vlan_rx ( struct io_buffer *iobuf, struct net_device *trunk,
                    220:                     const void *ll_dest, const void *ll_source ) {
                    221:        struct vlan_header *vlanhdr = iobuf->data;
                    222:        struct net_device *netdev;
                    223:        struct ll_protocol *ll_protocol;
                    224:        uint8_t ll_dest_copy[ETH_ALEN];
                    225:        uint8_t ll_source_copy[ETH_ALEN];
                    226:        uint16_t tag;
                    227:        int rc;
                    228: 
                    229:        /* Sanity check */
                    230:        if ( iob_len ( iobuf ) < sizeof ( *vlanhdr ) ) {
                    231:                DBGC ( trunk, "VLAN %s received underlength packet (%zd "
                    232:                       "bytes)\n", trunk->name, iob_len ( iobuf ) );
                    233:                rc = -EINVAL;
                    234:                goto err_sanity;
                    235:        }
                    236: 
                    237:        /* Identify VLAN device */
                    238:        tag = VLAN_TAG ( ntohs ( vlanhdr->tci ) );
                    239:        netdev = vlan_find ( trunk, tag );
                    240:        if ( ! netdev ) {
                    241:                DBGC2 ( trunk, "VLAN %s received packet for unknown VLAN "
                    242:                        "%d\n", trunk->name, tag );
                    243:                rc = -EPIPE;
                    244:                goto err_no_vlan;
                    245:        }
                    246: 
                    247:        /* Strip VLAN header and preserve original link-layer header fields */
                    248:        iob_pull ( iobuf, sizeof ( *vlanhdr ) );
                    249:        ll_protocol = trunk->ll_protocol;
                    250:        memcpy ( ll_dest_copy, ll_dest, ETH_ALEN );
                    251:        memcpy ( ll_source_copy, ll_source, ETH_ALEN );
                    252: 
                    253:        /* Reconstruct link-layer header for VLAN device */
                    254:        ll_protocol = netdev->ll_protocol;
                    255:        if ( ( rc = ll_protocol->push ( netdev, iobuf, ll_dest_copy,
                    256:                                        ll_source_copy,
                    257:                                        vlanhdr->net_proto ) ) != 0 ) {
                    258:                DBGC ( netdev, "VLAN %s could not reconstruct link-layer "
                    259:                       "header: %s\n", netdev->name, strerror ( rc ) );
                    260:                goto err_ll_push;
                    261:        }
                    262: 
                    263:        /* Enqueue packet on VLAN device */
                    264:        netdev_rx ( netdev, iob_disown ( iobuf ) );
                    265:        return 0;
                    266: 
                    267:  err_ll_push:
                    268:  err_no_vlan:
                    269:  err_sanity:
                    270:        free_iob ( iobuf );
                    271:        return rc;
                    272: }
                    273: 
                    274: /** VLAN protocol */
                    275: struct net_protocol vlan_protocol __net_protocol = {
                    276:        .name = "VLAN",
                    277:        .net_proto = htons ( ETH_P_8021Q ),
                    278:        .rx = vlan_rx,
                    279: };
                    280: 
                    281: /**
                    282:  * Check if network device can be used as a VLAN trunk device
                    283:  *
                    284:  * @v trunk            Trunk network device
                    285:  * @ret is_ok          Trunk network device is usable
                    286:  *
                    287:  * VLAN devices will be created as Ethernet devices.  (We cannot
                    288:  * simply clone the link layer of the trunk network device, because
                    289:  * this link layer may expect the network device structure to contain
                    290:  * some link-layer-private data.)  The trunk network device must
                    291:  * therefore have a link layer that is in some sense 'compatible' with
                    292:  * Ethernet; specifically, it must have link-layer addresses that are
                    293:  * the same length as Ethernet link-layer addresses.
                    294:  *
                    295:  * As an additional check, and primarily to assist with the sanity of
                    296:  * the FCoE code, we refuse to allow nested VLANs.
                    297:  */
                    298: int vlan_can_be_trunk ( struct net_device *trunk ) {
                    299: 
                    300:        return ( ( trunk->ll_protocol->ll_addr_len == ETH_ALEN ) &&
                    301:                 ( trunk->op != &vlan_operations ) );
                    302: }
                    303: 
                    304: /**
                    305:  * Create VLAN device
                    306:  *
                    307:  * @v trunk            Trunk network device
                    308:  * @v tag              VLAN tag
                    309:  * @v priority         Default VLAN priority
                    310:  * @ret rc             Return status code
                    311:  */
                    312: int vlan_create ( struct net_device *trunk, unsigned int tag,
                    313:                  unsigned int priority ) {
                    314:        struct net_device *netdev;
                    315:        struct vlan_device *vlan;
                    316:        int rc;
                    317: 
                    318:        /* If VLAN already exists, just update the priority */
                    319:        if ( ( netdev = vlan_find ( trunk, tag ) ) != NULL ) {
                    320:                vlan = netdev->priv;
                    321:                if ( priority != vlan->priority ) {
                    322:                        DBGC ( netdev, "VLAN %s priority changed from %d to "
                    323:                               "%d\n", netdev->name, vlan->priority, priority );
                    324:                }
                    325:                vlan->priority = priority;
                    326:                return 0;
                    327:        }
                    328: 
                    329:        /* Sanity checks */
                    330:        if ( ! vlan_can_be_trunk ( trunk ) ) {
                    331:                DBGC ( trunk, "VLAN %s cannot create VLAN on non-trunk "
                    332:                       "device\n", trunk->name );
                    333:                rc = -ENOTTY;
                    334:                goto err_sanity;
                    335:        }
                    336:        if ( ! VLAN_TAG_IS_VALID ( tag ) ) {
                    337:                DBGC ( trunk, "VLAN %s cannot create VLAN with invalid tag "
                    338:                       "%d\n", trunk->name, tag );
                    339:                rc = -EINVAL;
                    340:                goto err_sanity;
                    341:        }
                    342:        if ( ! VLAN_PRIORITY_IS_VALID ( priority ) ) {
                    343:                DBGC ( trunk, "VLAN %s cannot create VLAN with invalid "
                    344:                       "priority %d\n", trunk->name, priority );
                    345:                rc = -EINVAL;
                    346:                goto err_sanity;
                    347:        }
                    348: 
                    349:        /* Allocate and initialise structure */
                    350:        netdev = alloc_etherdev ( sizeof ( *vlan ) );
                    351:        if ( ! netdev ) {
                    352:                rc = -ENOMEM;
                    353:                goto err_alloc_etherdev;
                    354:        }
                    355:        netdev_init ( netdev, &vlan_operations );
                    356:        netdev->dev = trunk->dev;
                    357:        memcpy ( netdev->hw_addr, trunk->ll_addr, ETH_ALEN );
                    358:        vlan = netdev->priv;
                    359:        vlan->trunk = netdev_get ( trunk );
                    360:        vlan->tag = tag;
                    361:        vlan->priority = priority;
                    362: 
                    363:        /* Construct VLAN device name */
                    364:        snprintf ( netdev->name, sizeof ( netdev->name ), "%s-%d",
                    365:                   trunk->name, vlan->tag );
                    366: 
                    367:        /* Register VLAN device */
                    368:        if ( ( rc = register_netdev ( netdev ) ) != 0 ) {
                    369:                DBGC ( netdev, "VLAN %s could not register: %s\n",
                    370:                       netdev->name, strerror ( rc ) );
                    371:                goto err_register;
                    372:        }
                    373: 
                    374:        /* Synchronise with trunk device */
                    375:        vlan_sync ( netdev );
                    376: 
                    377:        DBGC ( netdev, "VLAN %s created with tag %d and priority %d\n",
                    378:               netdev->name, vlan->tag, vlan->priority );
                    379: 
                    380:        return 0;
                    381: 
                    382:        unregister_netdev ( netdev );
                    383:  err_register:
                    384:        netdev_nullify ( netdev );
                    385:        netdev_put ( netdev );
                    386:        netdev_put ( trunk );
                    387:  err_alloc_etherdev:
                    388:  err_sanity:
                    389:        return rc;
                    390: }
                    391: 
                    392: /**
                    393:  * Destroy VLAN device
                    394:  *
                    395:  * @v netdev           Network device
                    396:  * @ret rc             Return status code
                    397:  */
                    398: int vlan_destroy ( struct net_device *netdev ) {
                    399:        struct vlan_device *vlan = netdev->priv;
                    400:        struct net_device *trunk;
                    401: 
                    402:        /* Sanity check */
                    403:        if ( netdev->op != &vlan_operations ) {
                    404:                DBGC ( netdev, "VLAN %s cannot destroy non-VLAN device\n",
                    405:                       netdev->name );
                    406:                return -ENOTTY;
                    407:        }
                    408: 
                    409:        DBGC ( netdev, "VLAN %s destroyed\n", netdev->name );
                    410: 
                    411:        /* Remove VLAN device */
                    412:        unregister_netdev ( netdev );
                    413:        trunk = vlan->trunk;
                    414:        netdev_nullify ( netdev );
                    415:        netdev_put ( netdev );
                    416:        netdev_put ( trunk );
                    417: 
                    418:        return 0;
                    419: }
                    420: 
                    421: /**
                    422:  * Do nothing
                    423:  *
                    424:  * @v trunk            Trunk network device
                    425:  * @ret rc             Return status code
                    426:  */
                    427: static int vlan_probe ( struct net_device *trunk __unused ) {
                    428:        return 0;
                    429: }
                    430: 
                    431: /**
                    432:  * Handle trunk network device link state change
                    433:  *
                    434:  * @v trunk            Trunk network device
                    435:  */
                    436: static void vlan_notify ( struct net_device *trunk ) {
                    437:        struct net_device *netdev;
                    438:        struct vlan_device *vlan;
                    439: 
                    440:        for_each_netdev ( netdev ) {
                    441:                if ( netdev->op != &vlan_operations )
                    442:                        continue;
                    443:                vlan = netdev->priv;
                    444:                if ( vlan->trunk == trunk )
                    445:                        vlan_sync ( netdev );
                    446:        }
                    447: }
                    448: 
                    449: /**
                    450:  * Destroy first VLAN device for a given trunk
                    451:  *
                    452:  * @v trunk            Trunk network device
                    453:  * @ret found          A VLAN device was found
                    454:  */
                    455: static int vlan_remove_first ( struct net_device *trunk ) {
                    456:        struct net_device *netdev;
                    457:        struct vlan_device *vlan;
                    458: 
                    459:        for_each_netdev ( netdev ) {
                    460:                if ( netdev->op != &vlan_operations )
                    461:                        continue;
                    462:                vlan = netdev->priv;
                    463:                if ( vlan->trunk == trunk ) {
                    464:                        vlan_destroy ( netdev );
                    465:                        return 1;
                    466:                }
                    467:        }
                    468:        return 0;
                    469: }
                    470: 
                    471: /**
                    472:  * Destroy all VLAN devices for a given trunk
                    473:  *
                    474:  * @v trunk            Trunk network device
                    475:  */
                    476: static void vlan_remove ( struct net_device *trunk ) {
                    477: 
                    478:        /* Remove all VLAN devices attached to this trunk, safe
                    479:         * against arbitrary net device removal.
                    480:         */
                    481:        while ( vlan_remove_first ( trunk ) ) {}
                    482: }
                    483: 
                    484: /** VLAN driver */
                    485: struct net_driver vlan_driver __net_driver = {
                    486:        .name = "VLAN",
                    487:        .probe = vlan_probe,
                    488:        .notify = vlan_notify,
                    489:        .remove = vlan_remove,
                    490: };

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.