Browse Source

[netdevice] Avoid registering duplicate network devices

Reject network devices which appear to be duplicates of those already
available via a different underlying hardware device.  On a Xen PV-HVM
system, this allows us to filter out the emulated PCI NICs (which
would otherwise appear alongside the netfront NICs).

Note that we cannot use the Xen facility to "unplug" the emulated PCI
NICs, since there is no guarantee that the OS we subsequently load
will have a native netfront driver.

We permit devices with the same MAC address if they are attached to
the same underlying hardware device (e.g. VLAN devices).

Inspired-by: Marin Hannache <git@mareo.fr>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 10 years ago
parent
commit
98d09a1e03
2 changed files with 42 additions and 5 deletions
  1. 2
    0
      src/include/ipxe/netdevice.h
  2. 40
    5
      src/net/netdevice.c

+ 2
- 0
src/include/ipxe/netdevice.h View File

@@ -685,6 +685,8 @@ extern struct net_device * find_netdev ( const char *name );
685 685
 extern struct net_device * find_netdev_by_index ( unsigned int index );
686 686
 extern struct net_device * find_netdev_by_location ( unsigned int bus_type,
687 687
 						     unsigned int location );
688
+extern struct net_device *
689
+find_netdev_by_ll_addr ( struct ll_protocol *ll_protocol, const void *ll_addr );
688 690
 extern struct net_device * last_opened_netdev ( void );
689 691
 extern int net_tx ( struct io_buffer *iobuf, struct net_device *netdev,
690 692
 		    struct net_protocol *net_protocol, const void *ll_dest,

+ 40
- 5
src/net/netdevice.c View File

@@ -602,9 +602,27 @@ struct net_device * alloc_netdev ( size_t priv_len ) {
602 602
 int register_netdev ( struct net_device *netdev ) {
603 603
 	struct ll_protocol *ll_protocol = netdev->ll_protocol;
604 604
 	struct net_driver *driver;
605
+	struct net_device *duplicate;
605 606
 	uint32_t seed;
606 607
 	int rc;
607 608
 
609
+	/* Set initial link-layer address, if not already set */
610
+	if ( ! netdev_has_ll_addr ( netdev ) ) {
611
+		ll_protocol->init_addr ( netdev->hw_addr, netdev->ll_addr );
612
+	}
613
+
614
+	/* Reject network devices that are already available via a
615
+	 * different hardware device.
616
+	 */
617
+	duplicate = find_netdev_by_ll_addr ( ll_protocol, netdev->ll_addr );
618
+	if ( duplicate && ( duplicate->dev != netdev->dev ) ) {
619
+		DBGC ( netdev, "NETDEV rejecting duplicate (phys %s) of %s "
620
+		       "(phys %s)\n", netdev->dev->name, duplicate->name,
621
+		       duplicate->dev->name );
622
+		rc = -EEXIST;
623
+		goto err_duplicate;
624
+	}
625
+
608 626
 	/* Record device index and create device name */
609 627
 	netdev->index = netdev_index++;
610 628
 	if ( netdev->name[0] == '\0' ) {
@@ -612,11 +630,6 @@ int register_netdev ( struct net_device *netdev ) {
612 630
 			   netdev->index );
613 631
 	}
614 632
 
615
-	/* Set initial link-layer address, if not already set */
616
-	if ( ! netdev_has_ll_addr ( netdev ) ) {
617
-		ll_protocol->init_addr ( netdev->hw_addr, netdev->ll_addr );
618
-	}
619
-
620 633
 	/* Use least significant bits of the link-layer address to
621 634
 	 * improve the randomness of the (non-cryptographic) random
622 635
 	 * number generator.
@@ -660,6 +673,7 @@ int register_netdev ( struct net_device *netdev ) {
660 673
 	clear_settings ( netdev_settings ( netdev ) );
661 674
 	unregister_settings ( netdev_settings ( netdev ) );
662 675
  err_register_settings:
676
+ err_duplicate:
663 677
 	return rc;
664 678
 }
665 679
 
@@ -852,6 +866,27 @@ struct net_device * find_netdev_by_location ( unsigned int bus_type,
852 866
 	return NULL;	
853 867
 }
854 868
 
869
+/**
870
+ * Get network device by link-layer address
871
+ *
872
+ * @v ll_protocol	Link-layer protocol
873
+ * @v ll_addr		Link-layer address
874
+ * @ret netdev		Network device, or NULL
875
+ */
876
+struct net_device * find_netdev_by_ll_addr ( struct ll_protocol *ll_protocol,
877
+					     const void *ll_addr ) {
878
+	struct net_device *netdev;
879
+
880
+	list_for_each_entry ( netdev, &net_devices, list ) {
881
+		if ( ( netdev->ll_protocol == ll_protocol ) &&
882
+		     ( memcmp ( netdev->ll_addr, ll_addr,
883
+				ll_protocol->ll_addr_len ) == 0 ) )
884
+			return netdev;
885
+	}
886
+
887
+	return NULL;
888
+}
889
+
855 890
 /**
856 891
  * Get most recently opened network device
857 892
  *

Loading…
Cancel
Save