aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobert Love <robert.w.love@intel.com>2010-10-08 20:12:46 -0400
committerJames Bottomley <James.Bottomley@suse.de>2010-10-25 16:11:39 -0400
commit0ee31cb5df4b717de923266879964d0418c3308f (patch)
tree99c318a25f1ef948fc8ff9d26701c56df77fcca2
parent2dc02ee52f32aac6d8dd1172f104dc30ae1051bb (diff)
[SCSI] fcoe: Fix broken NPIV with correction to MAC validation
A previous patch attempted to validate the destination MAC address of a FCoE frame by checking that MAC address against the received port's MAC address. The implementation seems fine on the surface, but any VN_Ports added using the NPIV feature will have their own MAC addresses and these MACs were not being checked, which prevented any NPIV VN_Ports from receiving frames. In other words, the following patch has broken NPIV. 519e5135e2537c9dbc1cbcc0891b0a936ff5dcd2 [SCSI] fcoe: adds src and dest mac address checking for fcoe frames Part of the offending patch is correct, but the part that broke NPIV was attempting to satisfy FC-BB-5 section D.5, 2.1- (discard frames that) "contain a destination MAC address/destination N_Port_ID pair that was not assigned by an FCF to one of the VN_Ports on the ENode" The language does _not_ say to compare the destination FC-MAP/destination N_Port_ID, but instead to compare the destination MAC address/destination N_Port_ID. >From the FC-BB-5 specification, "A properly formed FPMA is one in which the 24 most significant bits equal the Fabric’s FC-MAP value and the least significant 24 bits equal the N_Port_ID assigned to the VN_Port by the FCF." This means that we need to compare the FC Frame's destination FCID against the embedded FCID in the destination MAC address. This patch checks the lower 24 bits of the destination MAC address against destination FCID in the Fibre Channel frame. For MAC validation the first line of defense is the hardware MAC filtering. Each VN_Port will have a unicast MAC addresses added to the hardware's filtering table. The Ethernet driver should drop any MACs not destined for a programmed MAC. This patch adds a second line of defense that very specfically compares an element in the FC frame against an element in the Ethernet header, which is appropriate for the FCoE layer. Many alternative approaches were considered, including a LLD callback from libfc. The second most reasonable approach seemed to be walking the list of NPIV ports and check each of their MAC addresses against the destination MAC address of the received frame. The problem with this approach was that it is likely that performance would suffer with the more NPIV ports added to the system since every received frame would need to walk this list, comparing each entry's MAC. Signed-off-by: Robert Love <robert.w.love@intel.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
-rw-r--r--drivers/scsi/fcoe/fcoe.c16
1 files changed, 6 insertions, 10 deletions
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index 8225b821a906..d23a538a9dfc 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -1243,7 +1243,6 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev,
1243 struct fcoe_interface *fcoe; 1243 struct fcoe_interface *fcoe;
1244 struct fc_frame_header *fh; 1244 struct fc_frame_header *fh;
1245 struct fcoe_percpu_s *fps; 1245 struct fcoe_percpu_s *fps;
1246 struct fcoe_port *port;
1247 struct ethhdr *eh; 1246 struct ethhdr *eh;
1248 unsigned int cpu; 1247 unsigned int cpu;
1249 1248
@@ -1262,16 +1261,7 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev,
1262 skb_tail_pointer(skb), skb_end_pointer(skb), 1261 skb_tail_pointer(skb), skb_end_pointer(skb),
1263 skb->csum, skb->dev ? skb->dev->name : "<NULL>"); 1262 skb->csum, skb->dev ? skb->dev->name : "<NULL>");
1264 1263
1265 /* check for mac addresses */
1266 eh = eth_hdr(skb); 1264 eh = eth_hdr(skb);
1267 port = lport_priv(lport);
1268 if (compare_ether_addr(eh->h_dest, port->data_src_addr) &&
1269 compare_ether_addr(eh->h_dest, fcoe->ctlr.ctl_src_addr) &&
1270 compare_ether_addr(eh->h_dest, (u8[6])FC_FCOE_FLOGI_MAC)) {
1271 FCOE_NETDEV_DBG(netdev, "wrong destination mac address:%pM\n",
1272 eh->h_dest);
1273 goto err;
1274 }
1275 1265
1276 if (is_fip_mode(&fcoe->ctlr) && 1266 if (is_fip_mode(&fcoe->ctlr) &&
1277 compare_ether_addr(eh->h_source, fcoe->ctlr.dest_addr)) { 1267 compare_ether_addr(eh->h_source, fcoe->ctlr.dest_addr)) {
@@ -1291,6 +1281,12 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev,
1291 skb_set_transport_header(skb, sizeof(struct fcoe_hdr)); 1281 skb_set_transport_header(skb, sizeof(struct fcoe_hdr));
1292 fh = (struct fc_frame_header *) skb_transport_header(skb); 1282 fh = (struct fc_frame_header *) skb_transport_header(skb);
1293 1283
1284 if (ntoh24(&eh->h_dest[3]) != ntoh24(fh->fh_d_id)) {
1285 FCOE_NETDEV_DBG(netdev, "FC frame d_id mismatch with MAC:%pM\n",
1286 eh->h_dest);
1287 goto err;
1288 }
1289
1294 fr = fcoe_dev_from_skb(skb); 1290 fr = fcoe_dev_from_skb(skb);
1295 fr->fr_dev = lport; 1291 fr->fr_dev = lport;
1296 fr->ptype = ptype; 1292 fr->ptype = ptype;