summaryrefslogtreecommitdiffstats
path: root/src/net/fcoe.c
diff options
context:
space:
mode:
authorMichael Brown2010-11-26 02:06:32 +0100
committerMichael Brown2010-11-26 02:09:41 +0100
commit1790f56fb27d9fae43aa71a7cd65565f03caf27b (patch)
treeed4303fe8ecd487da8da90917cc3c307aef2347e /src/net/fcoe.c
parent[vlan] Provide vlan_can_be_trunk() (diff)
downloadipxe-1790f56fb27d9fae43aa71a7cd65565f03caf27b.tar.gz
ipxe-1790f56fb27d9fae43aa71a7cd65565f03caf27b.tar.xz
ipxe-1790f56fb27d9fae43aa71a7cd65565f03caf27b.zip
[fcoe] Add support for FIP VLAN discovery
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/net/fcoe.c')
-rw-r--r--src/net/fcoe.c152
1 files changed, 149 insertions, 3 deletions
diff --git a/src/net/fcoe.c b/src/net/fcoe.c
index 47446799..70728771 100644
--- a/src/net/fcoe.c
+++ b/src/net/fcoe.c
@@ -29,6 +29,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/xfer.h>
#include <ipxe/netdevice.h>
#include <ipxe/ethernet.h>
+#include <ipxe/vlan.h>
#include <ipxe/features.h>
#include <ipxe/errortab.h>
#include <ipxe/device.h>
@@ -103,6 +104,10 @@ enum fcoe_flags {
FCOE_HAVE_FIP_FCF = 0x0004,
/** FCoE forwarder supports server-provided MAC addresses */
FCOE_FCF_ALLOWS_SPMA = 0x0008,
+ /** An alternative VLAN has been found */
+ FCOE_VLAN_FOUND = 0x0010,
+ /** VLAN discovery has timed out */
+ FCOE_VLAN_TIMED_OUT = 0x0020,
};
struct net_protocol fcoe_protocol __net_protocol;
@@ -124,6 +129,15 @@ static uint8_t all_fcf_macs[ETH_ALEN] =
static uint8_t default_fcf_mac[ETH_ALEN] =
{ 0x0e, 0xfc, 0x00, 0xff, 0xff, 0xfe };
+/** Maximum number of VLAN requests before giving up on VLAN discovery */
+#define FCOE_MAX_VLAN_REQUESTS 2
+
+/** Delay between retrying VLAN requests */
+#define FCOE_VLAN_RETRY_DELAY ( TICKS_PER_SEC )
+
+/** Delay between retrying polling VLAN requests */
+#define FCOE_VLAN_POLL_DELAY ( 30 * TICKS_PER_SEC )
+
/** Maximum number of FIP solicitations before giving up on FIP */
#define FCOE_MAX_FIP_SOLICITATIONS 2
@@ -182,8 +196,9 @@ static void fcoe_reset ( struct fcoe_port *fcoe ) {
netdev_link_ok ( fcoe->netdev ) ) {
fcoe->flags |= FCOE_HAVE_NETWORK;
start_timer_nodelay ( &fcoe->timer );
- DBGC ( fcoe, "FCoE %s starting FIP solicitation\n",
- fcoe->netdev->name );
+ DBGC ( fcoe, "FCoE %s starting %s\n", fcoe->netdev->name,
+ ( vlan_can_be_trunk ( fcoe->netdev ) ?
+ "VLAN discovery" : "FIP solicitation" ) );
}
/* Send notification of window change */
@@ -534,6 +549,100 @@ static int fcoe_fip_parse ( struct fcoe_port *fcoe, struct fip_header *fiphdr,
}
/**
+ * Send FIP VLAN request
+ *
+ * @v fcoe FCoE port
+ * @ret rc Return status code
+ */
+static int fcoe_fip_tx_vlan ( struct fcoe_port *fcoe ) {
+ struct io_buffer *iobuf;
+ struct {
+ struct fip_header hdr;
+ struct fip_mac_address mac_address;
+ } __attribute__ (( packed )) *request;
+ int rc;
+
+ /* Allocate I/O buffer */
+ iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( *request ) );
+ if ( ! iobuf )
+ return -ENOMEM;
+ iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
+
+ /* Construct VLAN request */
+ request = iob_put ( iobuf, sizeof ( *request ) );
+ memset ( request, 0, sizeof ( *request ) );
+ request->hdr.version = FIP_VERSION;
+ request->hdr.code = htons ( FIP_CODE_VLAN );
+ request->hdr.subcode = FIP_VLAN_REQUEST;
+ request->hdr.len = htons ( ( sizeof ( *request ) -
+ sizeof ( request->hdr ) ) / 4 );
+ request->mac_address.type = FIP_MAC_ADDRESS;
+ request->mac_address.len =
+ ( sizeof ( request->mac_address ) / 4 );
+ memcpy ( request->mac_address.mac, fcoe->netdev->ll_addr,
+ sizeof ( request->mac_address.mac ) );
+
+ /* Send VLAN request */
+ if ( ( rc = net_tx ( iob_disown ( iobuf ), fcoe->netdev,
+ &fip_protocol, all_fcf_macs,
+ fcoe->netdev->ll_addr ) ) != 0 ) {
+ DBGC ( fcoe, "FCoE %s could not send VLAN request: "
+ "%s\n", fcoe->netdev->name, strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Handle received FIP VLAN notification
+ *
+ * @v fcoe FCoE port
+ * @v descs Descriptor list
+ * @v flags Flags
+ * @ret rc Return status code
+ */
+static int fcoe_fip_rx_vlan ( struct fcoe_port *fcoe,
+ struct fip_descriptors *descs,
+ unsigned int flags __unused ) {
+ struct fip_mac_address *mac_address = fip_mac_address ( descs );
+ struct fip_vlan *vlan = fip_vlan ( descs );
+ unsigned int tag;
+ int rc;
+
+ /* Sanity checks */
+ if ( ! mac_address ) {
+ DBGC ( fcoe, "FCoE %s received VLAN notification missing MAC "
+ "address\n", fcoe->netdev->name );
+ return -EINVAL;
+ }
+ if ( ! vlan ) {
+ DBGC ( fcoe, "FCoE %s received VLAN notification missing VLAN "
+ "tag\n", fcoe->netdev->name );
+ return -EINVAL;
+ }
+
+ /* Create VLAN */
+ tag = ntohs ( vlan->vlan );
+ DBGC ( fcoe, "FCoE %s creating VLAN %d for FCF %s\n",
+ fcoe->netdev->name, tag, eth_ntoa ( mac_address->mac ) );
+ if ( ( rc = vlan_create ( fcoe->netdev, tag,
+ FCOE_VLAN_PRIORITY ) ) != 0 ) {
+ DBGC ( fcoe, "FCoE %s could not create VLAN %d: %s\n",
+ fcoe->netdev->name, tag, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Record that a VLAN was found. This FCoE port will play no
+ * further active role; the real FCoE traffic will use the
+ * port automatically created for the new VLAN device.
+ */
+ fcoe->flags |= FCOE_VLAN_FOUND;
+
+ return 0;
+}
+
+/**
* Send FIP discovery solicitation
*
* @v fcoe FCoE port
@@ -797,6 +906,8 @@ struct fip_handler {
/** FIP handlers */
static struct fip_handler fip_handlers[] = {
+ { FIP_CODE_VLAN, FIP_VLAN_NOTIFY,
+ fcoe_fip_rx_vlan },
{ FIP_CODE_DISCOVERY, FIP_DISCOVERY_ADVERTISE,
fcoe_fip_rx_advertisement },
{ FIP_CODE_ELS, FIP_ELS_RESPONSE,
@@ -891,7 +1002,42 @@ static void fcoe_expired ( struct retry_timer *timer, int over __unused ) {
/* Increment the timeout counter */
fcoe->timeouts++;
- if ( ! ( fcoe->flags & FCOE_HAVE_FCF ) ) {
+ if ( vlan_can_be_trunk ( fcoe->netdev ) &
+ ! ( fcoe->flags & FCOE_VLAN_TIMED_OUT ) ) {
+
+ /* If we have already found a VLAN, send infrequent
+ * VLAN requests, in case VLAN information changes.
+ */
+ if ( fcoe->flags & FCOE_VLAN_FOUND ) {
+ fcoe->flags &= ~FCOE_VLAN_FOUND;
+ fcoe->timeouts = 0;
+ start_timer_fixed ( &fcoe->timer,
+ FCOE_VLAN_POLL_DELAY );
+ fcoe_fip_tx_vlan ( fcoe );
+ return;
+ }
+
+ /* If we have not yet found a VLAN, and we have not
+ * yet timed out and given up on finding one, then
+ * send a VLAN request and wait.
+ */
+ if ( fcoe->timeouts <= FCOE_MAX_VLAN_REQUESTS ) {
+ start_timer_fixed ( &fcoe->timer,
+ FCOE_VLAN_RETRY_DELAY );
+ fcoe_fip_tx_vlan ( fcoe );
+ return;
+ }
+
+ /* We have timed out waiting for a VLAN; proceed to
+ * FIP discovery.
+ */
+ fcoe->flags |= FCOE_VLAN_TIMED_OUT;
+ fcoe->timeouts = 0;
+ DBGC ( fcoe, "FCoE %s giving up on VLAN discovery\n",
+ fcoe->netdev->name );
+ start_timer_nodelay ( &fcoe->timer );
+
+ } else if ( ! ( fcoe->flags & FCOE_HAVE_FCF ) ) {
/* If we have not yet found a FIP-capable forwarder,
* and we have not yet timed out and given up on