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