|
|
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: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.