[SCSI] libfcoe: fcoe: fnic: add FIP VN2VN point-to-multipoint support

The FC-BB-6 committee is proposing a new FIP usage model called
VN_port to VN_port mode.  It allows VN_ports to discover each other
over a loss-free L2 Ethernet without any FCF or Fibre-channel fabric
services.  This is point-to-multipoint.  There is also a variant
of this called point-to-point which provides for making sure there
is just one pair of ports operating over the Ethernet fabric.

We add these new states:  VNMP_START, _PROBE1, _PROBE2, _CLAIM, and _UP.
These usually go quickly in that sequence.  After waiting a random
amount of time up to 100 ms in START, we select a pseudo-random
proposed locally-unique port ID and send out probes in states PROBE1
and PROBE2, 100 ms apart.  If no probe responses are heard, we
proceed to CLAIM state 400 ms later and send a claim notification.
We wait another 400 ms to receive claim responses, which give us
a list of the other nodes on the network, including their FC-4
capabilities.  After another 400 ms we go to VNMP_UP state and
should start interoperating with any of the nodes for whic we
receivec claim responses.  More details are in the spec.j

Add the new mode as FIP_MODE_VN2VN.  The driver must specify
explicitly that it wants to operate in this mode.  There is
no automatic detection between point-to-multipoint and fabric
mode, and the local port initialization is affected, so it isn't
anticipated that there will ever be any such automatic switchover.

It may eventually be possible to have both fabric and VN2VN
modes on the same L2 network, which may be done by two separate
local VN_ports (lports).

When in VN2VN mode, FIP replaces libfc's fabric-oriented discovery
module with its own simple code that adds remote ports as they
are discovered from incoming claim notifications and responses.
These hooks are placed by fcoe_disc_init().

A linear list of discovered vn_ports is maintained under the
fcoe_ctlr struct.  It is expected to be short for now, and
accessed infrequently.  It is kept under RCU for lock-ordering
reasons.  The lport and/or rport mutexes may be held when we
need to lookup a fcoe_vnport during an ELS send.

Change fcoe_ctlr_encaps() to lookup the destination vn_port in
the list of peers for the destination MAC address of the
FIP-encapsulated frame.

Add a new function fcoe_disc_init() to initialize just the
discovery portion of libfcoe for VN2VN mode.

Signed-off-by: Joe Eykholt <jeykholt@cisco.com>
Signed-off-by: Robert Love <robert.w.love@intel.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
This commit is contained in:
Joe Eykholt 2010-07-20 15:20:30 -07:00 committed by James Bottomley
parent 9b651da900
commit e10f8c667b
4 changed files with 1071 additions and 69 deletions

View file

@ -315,7 +315,11 @@ static int fcoe_interface_setup(struct fcoe_interface *fcoe,
dev_uc_add(netdev, flogi_maddr);
if (fip->spma)
dev_uc_add(netdev, fip->ctl_src_addr);
dev_mc_add(netdev, FIP_ALL_ENODE_MACS);
if (fip->mode == FIP_MODE_VN2VN) {
dev_mc_add(netdev, FIP_ALL_VN2VN_MACS);
dev_mc_add(netdev, FIP_ALL_P2P_MACS);
} else
dev_mc_add(netdev, FIP_ALL_ENODE_MACS);
/*
* setup the receive function from ethernet driver
@ -401,7 +405,11 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe)
dev_uc_del(netdev, flogi_maddr);
if (fip->spma)
dev_uc_del(netdev, fip->ctl_src_addr);
dev_mc_del(netdev, FIP_ALL_ENODE_MACS);
if (fip->mode == FIP_MODE_VN2VN) {
dev_mc_del(netdev, FIP_ALL_VN2VN_MACS);
dev_mc_del(netdev, FIP_ALL_P2P_MACS);
} else
dev_mc_del(netdev, FIP_ALL_ENODE_MACS);
/* Tell the LLD we are done w/ FCoE */
ops = netdev->netdev_ops;
@ -967,7 +975,7 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe,
}
/* Initialize the library */
rc = fcoe_libfc_config(lport, &fcoe_libfc_fcn_templ);
rc = fcoe_libfc_config(lport, &fcoe->ctlr, &fcoe_libfc_fcn_templ, 1);
if (rc) {
FCOE_NETDEV_DBG(netdev, "Could not configure libfc for the "
"interface\n");
@ -2533,6 +2541,8 @@ static struct fc_seq *fcoe_elsct_send(struct fc_lport *lport, u32 did,
switch (op) {
case ELS_FLOGI:
case ELS_FDISC:
if (lport->point_to_multipoint)
break;
return fc_elsct_send(lport, did, fp, op, fcoe_flogi_resp,
fip, timeout);
case ELS_LOGO:

File diff suppressed because it is too large Load diff

View file

@ -673,7 +673,6 @@ static int __devinit fnic_probe(struct pci_dev *pdev,
/* Start local port initiatialization */
lp->link_up = 0;
lp->tt = fnic_transport_template;
lp->max_retry_count = fnic->config.flogi_retries;
lp->max_rport_retry_count = fnic->config.plogi_retries;
@ -689,11 +688,7 @@ static int __devinit fnic_probe(struct pci_dev *pdev,
fc_set_wwnn(lp, fnic->config.node_wwn);
fc_set_wwpn(lp, fnic->config.port_wwn);
fc_lport_init(lp);
fc_exch_init(lp);
fc_elsct_init(lp);
fc_rport_init(lp);
fc_disc_init(lp);
fcoe_libfc_config(lp, &fnic->ctlr, &fnic_transport_template, 0);
if (!fc_exch_mgr_alloc(lp, FC_CLASS_3, FCPIO_HOST_EXCH_RANGE_START,
FCPIO_HOST_EXCH_RANGE_END, NULL)) {

View file

@ -26,6 +26,7 @@
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/workqueue.h>
#include <linux/random.h>
#include <scsi/fc/fc_fcoe.h>
#include <scsi/libfc.h>
@ -37,6 +38,7 @@
#define FCOE_CTLR_START_DELAY 2000 /* mS after first adv. to choose FCF */
#define FCOE_CTRL_SOL_TOV 2000 /* min. solicitation interval (mS) */
#define FCOE_CTLR_FCF_LIMIT 20 /* max. number of FCF entries */
#define FCOE_CTLR_VN2VN_LOGIN_LIMIT 3 /* max. VN2VN rport login retries */
/**
* enum fip_state - internal state of FCoE controller.
@ -45,6 +47,11 @@
* @FIP_ST_AUTO: determining whether to use FIP or non-FIP mode.
* @FIP_ST_NON_FIP: non-FIP mode selected.
* @FIP_ST_ENABLED: FIP mode selected.
* @FIP_ST_VNMP_START: VN2VN multipath mode start, wait
* @FIP_ST_VNMP_PROBE1: VN2VN sent first probe, listening
* @FIP_ST_VNMP_PROBE2: VN2VN sent second probe, listening
* @FIP_ST_VNMP_CLAIM: VN2VN sent claim, waiting for responses
* @FIP_ST_VNMP_UP: VN2VN multipath mode operation
*/
enum fip_state {
FIP_ST_DISABLED,
@ -52,6 +59,11 @@ enum fip_state {
FIP_ST_AUTO,
FIP_ST_NON_FIP,
FIP_ST_ENABLED,
FIP_ST_VNMP_START,
FIP_ST_VNMP_PROBE1,
FIP_ST_VNMP_PROBE2,
FIP_ST_VNMP_CLAIM,
FIP_ST_VNMP_UP,
};
/*
@ -62,6 +74,7 @@ enum fip_state {
#define FIP_MODE_AUTO FIP_ST_AUTO
#define FIP_MODE_NON_FIP FIP_ST_NON_FIP
#define FIP_MODE_FABRIC FIP_ST_ENABLED
#define FIP_MODE_VN2VN FIP_ST_VNMP_START
/**
* struct fcoe_ctlr - FCoE Controller and FIP state
@ -79,11 +92,14 @@ enum fip_state {
* @timer_work: &work_struct for doing keep-alives and resets.
* @recv_work: &work_struct for receiving FIP frames.
* @fip_recv_list: list of received FIP frames.
* @rnd_state: state for pseudo-random number generator.
* @port_id: proposed or selected local-port ID.
* @user_mfs: configured maximum FC frame size, including FC header.
* @flogi_oxid: exchange ID of most recent fabric login.
* @flogi_count: number of FLOGI attempts in AUTO mode.
* @map_dest: use the FC_MAP mode for destination MAC addresses.
* @spma: supports SPMA server-provided MACs mode
* @probe_tries: number of FC_IDs probed
* @dest_addr: MAC address of the selected FC forwarder.
* @ctl_src_addr: the native MAC address of our local port.
* @send: LLD-supplied function to handle sending FIP Ethernet frames
@ -110,11 +126,16 @@ struct fcoe_ctlr {
struct work_struct timer_work;
struct work_struct recv_work;
struct sk_buff_head fip_recv_list;
struct rnd_state rnd_state;
u32 port_id;
u16 user_mfs;
u16 flogi_oxid;
u8 flogi_count;
u8 map_dest;
u8 spma;
u8 probe_tries;
u8 dest_addr[ETH_ALEN];
u8 ctl_src_addr[ETH_ALEN];
@ -160,6 +181,24 @@ struct fcoe_fcf {
u8 fd_flags:1;
};
/**
* struct fcoe_rport - VN2VN remote port
* @time: time of create or last beacon packet received from node
* @fcoe_len: max FCoE frame size, not including VLAN or Ethernet headers
* @flags: flags from probe or claim
* @login_count: number of unsuccessful rport logins to this port
* @enode_mac: E_Node control MAC address
* @vn_mac: VN_Node assigned MAC address for data
*/
struct fcoe_rport {
unsigned long time;
u16 fcoe_len;
u16 flags;
u8 login_count;
u8 enode_mac[ETH_ALEN];
u8 vn_mac[ETH_ALEN];
};
/* FIP API functions */
void fcoe_ctlr_init(struct fcoe_ctlr *, enum fip_state);
void fcoe_ctlr_destroy(struct fcoe_ctlr *);
@ -172,7 +211,8 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *, struct fc_lport *,
/* libfcoe funcs */
u64 fcoe_wwn_from_mac(unsigned char mac[], unsigned int, unsigned int);
int fcoe_libfc_config(struct fc_lport *, struct libfc_function_template *);
int fcoe_libfc_config(struct fc_lport *, struct fcoe_ctlr *,
const struct libfc_function_template *, int init_fcp);
/**
* is_fip_mode() - returns true if FIP mode selected.