|
@@ -29,6 +29,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
29
|
29
|
#include <ipxe/xfer.h>
|
30
|
30
|
#include <ipxe/netdevice.h>
|
31
|
31
|
#include <ipxe/ethernet.h>
|
|
32
|
+#include <ipxe/vlan.h>
|
32
|
33
|
#include <ipxe/features.h>
|
33
|
34
|
#include <ipxe/errortab.h>
|
34
|
35
|
#include <ipxe/device.h>
|
|
@@ -103,6 +104,10 @@ enum fcoe_flags {
|
103
|
104
|
FCOE_HAVE_FIP_FCF = 0x0004,
|
104
|
105
|
/** FCoE forwarder supports server-provided MAC addresses */
|
105
|
106
|
FCOE_FCF_ALLOWS_SPMA = 0x0008,
|
|
107
|
+ /** An alternative VLAN has been found */
|
|
108
|
+ FCOE_VLAN_FOUND = 0x0010,
|
|
109
|
+ /** VLAN discovery has timed out */
|
|
110
|
+ FCOE_VLAN_TIMED_OUT = 0x0020,
|
106
|
111
|
};
|
107
|
112
|
|
108
|
113
|
struct net_protocol fcoe_protocol __net_protocol;
|
|
@@ -124,6 +129,15 @@ static uint8_t all_fcf_macs[ETH_ALEN] =
|
124
|
129
|
static uint8_t default_fcf_mac[ETH_ALEN] =
|
125
|
130
|
{ 0x0e, 0xfc, 0x00, 0xff, 0xff, 0xfe };
|
126
|
131
|
|
|
132
|
+/** Maximum number of VLAN requests before giving up on VLAN discovery */
|
|
133
|
+#define FCOE_MAX_VLAN_REQUESTS 2
|
|
134
|
+
|
|
135
|
+/** Delay between retrying VLAN requests */
|
|
136
|
+#define FCOE_VLAN_RETRY_DELAY ( TICKS_PER_SEC )
|
|
137
|
+
|
|
138
|
+/** Delay between retrying polling VLAN requests */
|
|
139
|
+#define FCOE_VLAN_POLL_DELAY ( 30 * TICKS_PER_SEC )
|
|
140
|
+
|
127
|
141
|
/** Maximum number of FIP solicitations before giving up on FIP */
|
128
|
142
|
#define FCOE_MAX_FIP_SOLICITATIONS 2
|
129
|
143
|
|
|
@@ -182,8 +196,9 @@ static void fcoe_reset ( struct fcoe_port *fcoe ) {
|
182
|
196
|
netdev_link_ok ( fcoe->netdev ) ) {
|
183
|
197
|
fcoe->flags |= FCOE_HAVE_NETWORK;
|
184
|
198
|
start_timer_nodelay ( &fcoe->timer );
|
185
|
|
- DBGC ( fcoe, "FCoE %s starting FIP solicitation\n",
|
186
|
|
- fcoe->netdev->name );
|
|
199
|
+ DBGC ( fcoe, "FCoE %s starting %s\n", fcoe->netdev->name,
|
|
200
|
+ ( vlan_can_be_trunk ( fcoe->netdev ) ?
|
|
201
|
+ "VLAN discovery" : "FIP solicitation" ) );
|
187
|
202
|
}
|
188
|
203
|
|
189
|
204
|
/* Send notification of window change */
|
|
@@ -533,6 +548,100 @@ static int fcoe_fip_parse ( struct fcoe_port *fcoe, struct fip_header *fiphdr,
|
533
|
548
|
return 0;
|
534
|
549
|
}
|
535
|
550
|
|
|
551
|
+/**
|
|
552
|
+ * Send FIP VLAN request
|
|
553
|
+ *
|
|
554
|
+ * @v fcoe FCoE port
|
|
555
|
+ * @ret rc Return status code
|
|
556
|
+ */
|
|
557
|
+static int fcoe_fip_tx_vlan ( struct fcoe_port *fcoe ) {
|
|
558
|
+ struct io_buffer *iobuf;
|
|
559
|
+ struct {
|
|
560
|
+ struct fip_header hdr;
|
|
561
|
+ struct fip_mac_address mac_address;
|
|
562
|
+ } __attribute__ (( packed )) *request;
|
|
563
|
+ int rc;
|
|
564
|
+
|
|
565
|
+ /* Allocate I/O buffer */
|
|
566
|
+ iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( *request ) );
|
|
567
|
+ if ( ! iobuf )
|
|
568
|
+ return -ENOMEM;
|
|
569
|
+ iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
|
|
570
|
+
|
|
571
|
+ /* Construct VLAN request */
|
|
572
|
+ request = iob_put ( iobuf, sizeof ( *request ) );
|
|
573
|
+ memset ( request, 0, sizeof ( *request ) );
|
|
574
|
+ request->hdr.version = FIP_VERSION;
|
|
575
|
+ request->hdr.code = htons ( FIP_CODE_VLAN );
|
|
576
|
+ request->hdr.subcode = FIP_VLAN_REQUEST;
|
|
577
|
+ request->hdr.len = htons ( ( sizeof ( *request ) -
|
|
578
|
+ sizeof ( request->hdr ) ) / 4 );
|
|
579
|
+ request->mac_address.type = FIP_MAC_ADDRESS;
|
|
580
|
+ request->mac_address.len =
|
|
581
|
+ ( sizeof ( request->mac_address ) / 4 );
|
|
582
|
+ memcpy ( request->mac_address.mac, fcoe->netdev->ll_addr,
|
|
583
|
+ sizeof ( request->mac_address.mac ) );
|
|
584
|
+
|
|
585
|
+ /* Send VLAN request */
|
|
586
|
+ if ( ( rc = net_tx ( iob_disown ( iobuf ), fcoe->netdev,
|
|
587
|
+ &fip_protocol, all_fcf_macs,
|
|
588
|
+ fcoe->netdev->ll_addr ) ) != 0 ) {
|
|
589
|
+ DBGC ( fcoe, "FCoE %s could not send VLAN request: "
|
|
590
|
+ "%s\n", fcoe->netdev->name, strerror ( rc ) );
|
|
591
|
+ return rc;
|
|
592
|
+ }
|
|
593
|
+
|
|
594
|
+ return 0;
|
|
595
|
+}
|
|
596
|
+
|
|
597
|
+/**
|
|
598
|
+ * Handle received FIP VLAN notification
|
|
599
|
+ *
|
|
600
|
+ * @v fcoe FCoE port
|
|
601
|
+ * @v descs Descriptor list
|
|
602
|
+ * @v flags Flags
|
|
603
|
+ * @ret rc Return status code
|
|
604
|
+ */
|
|
605
|
+static int fcoe_fip_rx_vlan ( struct fcoe_port *fcoe,
|
|
606
|
+ struct fip_descriptors *descs,
|
|
607
|
+ unsigned int flags __unused ) {
|
|
608
|
+ struct fip_mac_address *mac_address = fip_mac_address ( descs );
|
|
609
|
+ struct fip_vlan *vlan = fip_vlan ( descs );
|
|
610
|
+ unsigned int tag;
|
|
611
|
+ int rc;
|
|
612
|
+
|
|
613
|
+ /* Sanity checks */
|
|
614
|
+ if ( ! mac_address ) {
|
|
615
|
+ DBGC ( fcoe, "FCoE %s received VLAN notification missing MAC "
|
|
616
|
+ "address\n", fcoe->netdev->name );
|
|
617
|
+ return -EINVAL;
|
|
618
|
+ }
|
|
619
|
+ if ( ! vlan ) {
|
|
620
|
+ DBGC ( fcoe, "FCoE %s received VLAN notification missing VLAN "
|
|
621
|
+ "tag\n", fcoe->netdev->name );
|
|
622
|
+ return -EINVAL;
|
|
623
|
+ }
|
|
624
|
+
|
|
625
|
+ /* Create VLAN */
|
|
626
|
+ tag = ntohs ( vlan->vlan );
|
|
627
|
+ DBGC ( fcoe, "FCoE %s creating VLAN %d for FCF %s\n",
|
|
628
|
+ fcoe->netdev->name, tag, eth_ntoa ( mac_address->mac ) );
|
|
629
|
+ if ( ( rc = vlan_create ( fcoe->netdev, tag,
|
|
630
|
+ FCOE_VLAN_PRIORITY ) ) != 0 ) {
|
|
631
|
+ DBGC ( fcoe, "FCoE %s could not create VLAN %d: %s\n",
|
|
632
|
+ fcoe->netdev->name, tag, strerror ( rc ) );
|
|
633
|
+ return rc;
|
|
634
|
+ }
|
|
635
|
+
|
|
636
|
+ /* Record that a VLAN was found. This FCoE port will play no
|
|
637
|
+ * further active role; the real FCoE traffic will use the
|
|
638
|
+ * port automatically created for the new VLAN device.
|
|
639
|
+ */
|
|
640
|
+ fcoe->flags |= FCOE_VLAN_FOUND;
|
|
641
|
+
|
|
642
|
+ return 0;
|
|
643
|
+}
|
|
644
|
+
|
536
|
645
|
/**
|
537
|
646
|
* Send FIP discovery solicitation
|
538
|
647
|
*
|
|
@@ -797,6 +906,8 @@ struct fip_handler {
|
797
|
906
|
|
798
|
907
|
/** FIP handlers */
|
799
|
908
|
static struct fip_handler fip_handlers[] = {
|
|
909
|
+ { FIP_CODE_VLAN, FIP_VLAN_NOTIFY,
|
|
910
|
+ fcoe_fip_rx_vlan },
|
800
|
911
|
{ FIP_CODE_DISCOVERY, FIP_DISCOVERY_ADVERTISE,
|
801
|
912
|
fcoe_fip_rx_advertisement },
|
802
|
913
|
{ FIP_CODE_ELS, FIP_ELS_RESPONSE,
|
|
@@ -891,7 +1002,42 @@ static void fcoe_expired ( struct retry_timer *timer, int over __unused ) {
|
891
|
1002
|
/* Increment the timeout counter */
|
892
|
1003
|
fcoe->timeouts++;
|
893
|
1004
|
|
894
|
|
- if ( ! ( fcoe->flags & FCOE_HAVE_FCF ) ) {
|
|
1005
|
+ if ( vlan_can_be_trunk ( fcoe->netdev ) &
|
|
1006
|
+ ! ( fcoe->flags & FCOE_VLAN_TIMED_OUT ) ) {
|
|
1007
|
+
|
|
1008
|
+ /* If we have already found a VLAN, send infrequent
|
|
1009
|
+ * VLAN requests, in case VLAN information changes.
|
|
1010
|
+ */
|
|
1011
|
+ if ( fcoe->flags & FCOE_VLAN_FOUND ) {
|
|
1012
|
+ fcoe->flags &= ~FCOE_VLAN_FOUND;
|
|
1013
|
+ fcoe->timeouts = 0;
|
|
1014
|
+ start_timer_fixed ( &fcoe->timer,
|
|
1015
|
+ FCOE_VLAN_POLL_DELAY );
|
|
1016
|
+ fcoe_fip_tx_vlan ( fcoe );
|
|
1017
|
+ return;
|
|
1018
|
+ }
|
|
1019
|
+
|
|
1020
|
+ /* If we have not yet found a VLAN, and we have not
|
|
1021
|
+ * yet timed out and given up on finding one, then
|
|
1022
|
+ * send a VLAN request and wait.
|
|
1023
|
+ */
|
|
1024
|
+ if ( fcoe->timeouts <= FCOE_MAX_VLAN_REQUESTS ) {
|
|
1025
|
+ start_timer_fixed ( &fcoe->timer,
|
|
1026
|
+ FCOE_VLAN_RETRY_DELAY );
|
|
1027
|
+ fcoe_fip_tx_vlan ( fcoe );
|
|
1028
|
+ return;
|
|
1029
|
+ }
|
|
1030
|
+
|
|
1031
|
+ /* We have timed out waiting for a VLAN; proceed to
|
|
1032
|
+ * FIP discovery.
|
|
1033
|
+ */
|
|
1034
|
+ fcoe->flags |= FCOE_VLAN_TIMED_OUT;
|
|
1035
|
+ fcoe->timeouts = 0;
|
|
1036
|
+ DBGC ( fcoe, "FCoE %s giving up on VLAN discovery\n",
|
|
1037
|
+ fcoe->netdev->name );
|
|
1038
|
+ start_timer_nodelay ( &fcoe->timer );
|
|
1039
|
+
|
|
1040
|
+ } else if ( ! ( fcoe->flags & FCOE_HAVE_FCF ) ) {
|
895
|
1041
|
|
896
|
1042
|
/* If we have not yet found a FIP-capable forwarder,
|
897
|
1043
|
* and we have not yet timed out and given up on
|