Browse Source

[fcoe] Add support for FIP VLAN discovery

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 13 years ago
parent
commit
1790f56fb2
2 changed files with 152 additions and 3 deletions
  1. 3
    0
      src/include/ipxe/fcoe.h
  2. 149
    3
      src/net/fcoe.c

+ 3
- 0
src/include/ipxe/fcoe.h View File

@@ -86,4 +86,7 @@ enum fcoe_eof {
86 86
 	FCOE_EOF_A = 0x50,	/**< End of Frame Abort */
87 87
 };
88 88
 
89
+/** FCoE VLAN priority */
90
+#define FCOE_VLAN_PRIORITY 3
91
+
89 92
 #endif /* _IPXE_FCOE_H */

+ 149
- 3
src/net/fcoe.c View File

@@ -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

Loading…
Cancel
Save