Port-vax archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: qt multi- and broadcast (was Re: dhcpcd not working in simh-vax with xq0:nat networking)



Den 2021-12-14 kl. 18:34, skrev Rhialto:
On Mon 13 Dec 2021 at 19:08:25 +0100, Anders Magnusson wrote:
good start, but I think it would be a bad idea to require to include the
lance code just for the multicast hash.
I assume that what you really want is to call the function ether_crc32_le()
which is already included.
The GENERIC code already contains the lance code, probably at least
because of sys/arch/vax/if/if_le.c, so for GENERIC it wastes a bit of
space to make a copy. For a trimmed down kernel it is a win, though.

I trimmed out the m68k code variant though, since I don't expect this
file to be compiled on a m68k cpu (but there are le drivers for m68k in
e.g. sys/arch/mvme68k/dev/if_le.c and sys/arch/sun3/dev/if_le.c, so the
code works regardless of endianness).

Unless somebody tells me this is bad to do I propose to commit it early
next week or so.
I think it's great!
An idea though: replace ETHER_CMP(enm->enm_addrlo, enm->enm_addrhi) with memcmp(enm->enm_addrlo, enm->enm_addrhi, 6). This will generate the cmpc3 instruction, which is the most efficient string compare on a vax :-)

-- R


I was made aware of the "ifmcstat" commaand to tell me about multicast
addresses that should be associated with interfaces.

localhost# ifmcstat
qt0:
         inet6 fe80::a00:2bff:feaf:2ce8%qt0
                 group ff02::2:65d0:d71e%qt0 refcount 1
                 group ff02::1:ff2e:f242%qt0 refcount 1
                 group ff01:1::1 refcount 3
                 group ff02::1%qt0 refcount 3
                 group ff02::1:ffaf:2ce8%qt0 refcount 2
         enaddr 08:00:2b:af:2c:e8: multicnt 5
                 33:33:65:d0:d7:1e: -- 33:33:65:d0:d7:1e: 1
                 01:00:5e:00:00:01: -- 01:00:5e:00:00:01: 1
                 33:33:ff:2e:f2:42: -- 33:33:ff:2e:f2:42: 1
                 33:33:00:00:00:01: -- 33:33:00:00:00:01: 2
                 33:33:ff:af:2c:e8: -- 33:33:ff:af:2c:e8: 1
lo0:
         inet6 ::1
                 group ff01:2::1 refcount 2
                 group ff02::1%lo0 refcount 2
                 group ff02::1:ff00:1%lo0 refcount 2
localhost#
Simulation stopped, PC: 801A1A0F (MTPR R0,#12)
sim> show xq filter
Physical Address=08:00:2B:AF:2C:E8
Multicast Hash: 00 00 80 40 80 10 40 00

33:33:* are for IPv6, and 01:00:5e:* for IPv4, and the number of
addresses matches the number of bits in the hash.

So the patch is now like this:

cvs diff: Diffing dev/qbus
Index: dev/qbus/if_qt.c
===================================================================
RCS file: /cvsroot/src/sys/dev/qbus/if_qt.c,v
retrieving revision 1.25
diff -u -r1.25 if_qt.c
--- dev/qbus/if_qt.c	29 Jan 2020 05:57:21 -0000	1.25
+++ dev/qbus/if_qt.c	14 Dec 2021 14:37:48 -0000
@@ -162,6 +162,7 @@
static int qtmatch(device_t, cfdata_t, void *);
  static	void qtattach(device_t, device_t, void *);
+static	void lance_setladrf(struct ethercom *ec, uint16_t *af);
  static	void qtintr(void *);
  static	int qtinit(struct ifnet *);
  static	int qtioctl(struct ifnet *, u_long, void *);
@@ -332,6 +333,98 @@
  	return(1);
  }
+/*
+ * Compare two Ether/802 addresses for equality, inlined and
+ * unrolled for speed.  Use this like memcmp().
+ *
+ * XXX: Add <machine/inlines.h> for stuff like this?
+ * XXX: or maybe add it to libkern.h instead?
+ *
+ * "I'd love to have an inline assembler version of this."
+ * XXX: Who wanted that? mycroft?  I wrote one, but this
+ * version in C is as good as hand-coded assembly. -gwr
+ *
+ * Please do NOT tweak this without looking at the actual
+ * assembly code generated before and after your tweaks!
+ */
+static inline uint16_t
+ether_cmp(void *one, void *two)
+{
+	uint16_t *a = (uint16_t *)one;
+	uint16_t *b = (uint16_t *)two;
+	uint16_t diff;
+
+	/*
+	 * Most modern CPUs do better with a single expression.
+	 * Note that short-cut evaluation is NOT helpful here,
+	 * because it just makes the code longer, not faster!
+	 */
+	diff = (a[0] - b[0]) | (a[1] - b[1]) | (a[2] - b[2]);
+
+	return (diff);
+}
+
+#define ETHER_CMP	ether_cmp
+
+/*
+ * Set up the logical address filter.
+ */
+void
+lance_setladrf(struct ethercom *ec, uint16_t *af)
+{
+	struct ifnet *ifp = &ec->ec_if;
+	struct ether_multi *enm;
+	uint32_t crc;
+	struct ether_multistep step;
+
+	/*
+	 * Set up multicast address filter by passing all multicast addresses
+	 * through a crc generator, and then using the high order 6 bits as an
+	 * index into the 64 bit logical address filter.  The high order bit
+	 * selects the word, while the rest of the bits select the bit within
+	 * the word.
+	 */
+
+	if (ifp->if_flags & IFF_PROMISC)
+		goto allmulti;
+
+	af[0] = af[1] = af[2] = af[3] = 0x0000;
+
+	ETHER_LOCK(ec);
+	ETHER_FIRST_MULTI(step, ec, enm);
+	while (enm != NULL) {
+		if (ETHER_CMP(enm->enm_addrlo, enm->enm_addrhi)) {
+			/*
+			 * We must listen to a range of multicast addresses.
+			 * For now, just accept all multicasts, rather than
+			 * trying to set only those filter bits needed to match
+			 * the range.  (At this time, the only use of address
+			 * ranges is for IP multicast routing, for which the
+			 * range is big enough to require all bits set.)
+			 */
+			ETHER_UNLOCK(ec);
+			goto allmulti;
+		}
+
+		crc = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN);
+
+		/* Just want the 6 most significant bits. */
+		crc >>= 26;
+
+		/* Set the corresponding bit in the filter. */
+		af[crc >> 4] |= 1 << (crc & 0xf);
+
+		ETHER_NEXT_MULTI(step, enm);
+	}
+	ETHER_UNLOCK(ec);
+	ifp->if_flags &= ~IFF_ALLMULTI;
+	return;
+
+allmulti:
+	ifp->if_flags |= IFF_ALLMULTI;
+	af[0] = af[1] = af[2] = af[3] = 0xffff;
+}
+
  int
  qtinit(struct ifnet *ifp)
  {
@@ -388,7 +481,10 @@
  	}
  	iniblk = &sc->sc_ib->qc_init;
  	iniblk->mode = ifp->if_flags & IFF_PROMISC ? INIT_MODE_PRO : 0;
-
+/*
+ * The multicast filter works "like LANCE".
+ */
+	lance_setladrf(&sc->is_ec, iniblk->laddr);
/*
   * Now initialize the receive ring descriptors.  Because this routine can be
Index: dev/qbus/if_qtreg.h
===================================================================
RCS file: /cvsroot/src/sys/dev/qbus/if_qtreg.h,v
retrieving revision 1.5
diff -u -r1.5 if_qtreg.h
--- dev/qbus/if_qtreg.h	11 Dec 2005 12:23:29 -0000	1.5
+++ dev/qbus/if_qtreg.h	14 Dec 2021 14:37:48 -0000
@@ -207,18 +207,18 @@
struct qt_init
  		{
-		short	mode;
-		u_char	paddr[6];	/* 48 bit physical address */
-		u_char	laddr[8];	/* 64 bit logical address filter */
-		u_short	rx_lo;		/* low 16 bits of receive ring addr */
-		u_short	rx_hi;		/* high 6 bits of receive ring addr */
-		u_short	tx_lo;		/* low 16 bits of transmit ring addr */
-		u_short	tx_hi;		/* high 6 bits of transmit ring addr */
-		u_short	options;
-		u_short	vector;
-		u_short	hit;
-		char	passwd[6];
-		char	pad[4];		/* even on 40 byte for alignment */
+		int16_t		mode;
+		u_char		paddr[6];	/* 48 bit physical address */
+		uint16_t	laddr[4];	/* 64 bit logical address filter */
+		uint16_t	rx_lo;		/* low 16 bits of receive ring addr */
+		uint16_t	rx_hi;		/* high 6 bits of receive ring addr */
+		uint16_t	tx_lo;		/* low 16 bits of transmit ring addr */
+		uint16_t	tx_hi;		/* high 6 bits of transmit ring addr */
+		uint16_t	options;
+		uint16_t	vector;
+		uint16_t	hit;
+		char		passwd[6];
+		char		pad[4];		/* even on 40 byte for alignment */
  		};
#define INIT_MODE_PRO 0x8000 /* Promiscuous mode */

-Olaf.



Home | Main Index | Thread Index | Old Index