Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 18 Jun 1997 16:36:45 -0400 (EDT)
From:      dcurtis@lcs.mit.edu
To:        FreeBSD-gnats-submit@FreeBSD.ORG
Subject:   kern/3901: Improving multicast for Intel 10/100 Ethernet cards
Message-ID:  <199706182036.QAA00410@ananke.lcs.mit.edu>
Resent-Message-ID: <199706182040.NAA09983@hub.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         3901
>Category:       kern
>Synopsis:       Multicast for Intel 10/100 Ethernet Card
>Confidential:   no
>Severity:       non-critical
>Priority:       high
>Responsible:    freebsd-bugs
>State:          open
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Wed Jun 18 13:40:00 PDT 1997
>Last-Modified:
>Originator:     Dorothy Curtis
>Organization:
MIT/LCS
>Release:        FreeBSD 3.0-CURRENT i386
>Environment:

	Not applicable.

>Description:

	The existing driver for the Intel 10/100 Ethernet card behaves
	suboptimally in supporting multicast: it passes all multicast
	traffic through to the kernel for filtering.  The supplied
	patches enhance the driver to use the card's hardware multicast
	filtering feature, thus offloading the address filtering from
	the cpu.

	Also included is a fix to if.c so that the interface is notified
	when a multicast address is deleted.

>How-To-Repeat:

	Currently, assuming you are on a net with multicast traffic,
		tcpdump -p ip multicast
	shows all of the multicast traffic.

	With the following fix, the above command shows almost no traffic:
	occasional messages directed to ALL-SYSTEMS.MCAST.NET should appear,
	but no others.  The mtest program can be used to join and leave
	multicast groups.  The above tcpdump command will show messages
	from the groups that have been joined.  When a group has been left,
	no messages will appear from that group.  (Note that quitting the
	mtest program leaves all groups.)

>Fix:
	

Three patches follow for 
	/usr/src/sys/pci/if_fxpreg.h
	/usr/src/sys/pci/if_fxp.c
	/usr/src/sys/net/if.c

--- /usr/src/sys/pci/if_fxpreg.h	Wed Jun 18 13:01:07 1997
+++ /new/usr/src/sys/pci/if_fxpreg.h	Wed Jun 18 13:02:18 1997
@@ -102,6 +102,23 @@
 	volatile u_int32_t link_addr;
 	volatile u_int8_t macaddr[6];
 };
+
+/*
+ * Multicast support
+ */
+#define MAXMCAST 50
+struct fxp_en_addr {
+        u_char data[6];
+};
+
+struct fxp_cb_mas {
+	volatile u_int16_t cb_status;
+	volatile u_int16_t cb_command;
+	volatile u_int32_t link_addr;
+	volatile u_int16_t mcast_bytes;
+	volatile struct fxp_en_addr mcast_addrs[MAXMCAST+1];
+};
+
 /* I hate bit-fields :-( */
 struct fxp_cb_config {
 	volatile u_int16_t	cb_status;


--- /usr/src/sys/pci/if_fxp.c		Wed Jun 18 13:00:47 1997
+++ /new/usr/src/sys/pci/if_fxp.c	Wed Jun 18 15:21:07 1997
@@ -28,6 +28,13 @@
  */
 
 /*
+ * 3/25/97: dcurtis: improved multicast handling by stealing code
+ * from GAWollman's if_ie.c.  This change enables control of the card's
+ * multicast address filtering per IOCTL calls from user code.  By using
+ * the hardware filtering work is offloaded from the cpu.
+ */
+
+/*
  * Intel EtherExpress Pro/100B PCI Fast Ethernet driver
  */
 
@@ -91,6 +98,8 @@
 	int phy_primary_addr;		/* address of primary PHY */
 	int phy_primary_device;		/* device type of primary PHY */
 	int phy_10Mbps_only;		/* PHY is 10Mbps-only device */
+	int mcast_count;              /* count of mcast addrs */
+	struct fxp_en_addr mcast_addrs[MAXMCAST+1]; /* array of mcast addrs */
 };
 
 static u_long fxp_count;
@@ -810,6 +819,42 @@
 	fxp_init(ifp->if_softc);
 }
 
+static int
+fxp_mc_reset(struct fxp_softc *sc) {
+   struct ifmultiaddr *ifma;
+   struct ifnet *ifp;
+
+  /*
+   * Step through the list of addresses.
+   */
+
+  sc->mcast_count = 0;
+  for (ifma = sc->arpcom.ac_if.if_multiaddrs.lh_first; ifma;
+       ifma = ifma->ifma_link.le_next) {
+	  char *eaptr;
+          if (ifma->ifma_addr->sa_family != AF_LINK)
+                  continue;
+
+          if(sc->mcast_count >= MAXMCAST) {
+		  ifp = &sc->arpcom.ac_if;
+		  printf("fxp%d: warning: exceeded max (%d) multicast addrs\n",
+		     ifp->if_unit, MAXMCAST);
+  		  return 1;
+          }
+          bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
+                &(sc->mcast_addrs[sc->mcast_count]), 6);
+#ifdef FXP_DEBUG
+	  eaptr = &(sc->mcast_addrs[sc->mcast_count]);
+	  printf("copying in %dth\n", sc->mcast_count);
+	  printf("addr = %d:%d:%d:%d:%d:%d\n", 
+		eaptr[0], eaptr[1], eaptr[2], eaptr[3], eaptr[4], eaptr[5]);
+#endif
+          sc->mcast_count++;
+  }
+  return 0;
+}
+
+
 static void
 fxp_init(xsc)
 	void *xsc;
@@ -818,6 +863,7 @@
 	struct ifnet *ifp = &sc->arpcom.ac_if;
 	struct fxp_cb_config *cbp;
 	struct fxp_cb_ias *cb_ias;
+	struct fxp_cb_mas *cb_mas;
 	struct fxp_cb_tx *txp;
 	struct fxp_csr *csr = sc->csr;
 	int i, s, mcast, prm;
@@ -830,13 +876,18 @@
 
 	prm = (ifp->if_flags & IFF_PROMISC) ? 1 : 0;
 	sc->promisc_mode = prm;
+
 	/*
-	 * Sleeze out here and enable reception of all multicasts if
-	 * multicasts are enabled. Ideally, we'd program the multicast
-	 * address filter to only accept specific multicasts.
+	 * Handle multicast addresses.
 	 */
-	mcast = (ifp->if_flags & (IFF_MULTICAST|IFF_ALLMULTI)) ? 1 : 0;
+	mcast = fxp_mc_reset(sc);
 
+        /*
+	 * Set mcast if IFF_ALLMULTI is set.
+	 * (It may have already been set if there were too many discrete		 * multicast addrs.)
+         */
+	mcast |= ((ifp->if_flags & IFF_ALLMULTI)) ? 1 : 0;
+  
 	/*
 	 * Initialize base of CBL and RFA memory. Loading with zero
 	 * sets it up for regular linear addressing.
@@ -931,6 +982,30 @@
 	while (!(cb_ias->cb_status & FXP_CB_STATUS_C));
 
 	/*
+	 * Program the multicast addresses, if any.  Temporarily use
+	 * the TxCB memory area as above.
+	 */
+	if (sc->mcast_count) {
+		cb_mas = (struct fxp_cb_mas *) sc->cbl_base;
+		cb_mas->cb_status = 0;
+		cb_mas->cb_command = FXP_CB_COMMAND_MAS | FXP_CB_COMMAND_EL;
+		cb_mas->link_addr = -1;
+
+		bcopy(sc->mcast_addrs, (void *)cb_mas->mcast_addrs,
+			sc->mcast_count * sizeof *sc->mcast_addrs);
+		cb_mas->mcast_bytes = sc->mcast_count * 6; /* grrr... */ 
+
+		/*
+		 * Start the MAS (Multicast Address Setup) command/DMA.
+		 */
+		fxp_scb_wait(csr);
+		csr->scb_command = FXP_SCB_COMMAND_CU_START;
+		/* ...and wait for it to complete. */
+		while (!(cb_ias->cb_status & FXP_CB_STATUS_C));
+		}
+
+
+	/*
 	 * Initialize transmit control block (TxCB) list.
 	 */
 
@@ -1157,6 +1232,9 @@
 		 * Multicast list has changed; set the hardware filter
 		 * accordingly.
 		 */
+#ifdef FXP_DEBUG
+		printf("calling fxp_init due to SIOCADD/DELMULTI\n");
+#endif
 		fxp_init(sc);
 		error = 0;
 		break;


--- /usr/src/sys/net/if.c		Wed Jun 18 13:01:25 1997
+++ /new/usr/src/sys/net/if.c		Wed Jun 18 15:31:08 1997
@@ -943,8 +943,12 @@
 	splx(s);
 	free(ifma->ifma_addr, M_IFMADDR);
 	free(ifma, M_IFMADDR);
-	if (sa == 0)
+	if (sa == 0) {
+		s = splimp();
+		ifp->if_ioctl(ifp, SIOCDELMULTI, 0);
+		splx(s);
 		return 0;
+		}
 
 	/*
 	 * Now look for the link-layer address which corresponds to
@@ -971,6 +975,7 @@
 
 	s = splimp();
 	LIST_REMOVE(ifma, ifma_link);
+	ifp->if_ioctl(ifp, SIOCDELMULTI, 0);
 	splx(s);
 	free(ifma->ifma_addr, M_IFMADDR);
 	free(sa, M_IFMADDR);
>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199706182036.QAA00410>