[Re-send, forgot to attach the patches. Argh.]

Lars Eggert wrote:

> This causes the problem decribed in PR kern/41632
> (http://www.freebsd.org/cgi/query-pr.cgi?pr=kern/41632), where dhcpd
> "listens" on interface A which is bridged to interface B. When A has no
> carrier, DHCP requests arriving on B are ignored. When A has a carrier,
> dhcp will get a copy of the packet when it is bridge-forwarded out A, so
> the problem doesn't occur then.
>
> Attached is a rough patch to if_ethersubr.c that fixes the problem.

That patch (new version attached) turned out to only fix part of the
problem.

When bridge-forwarding packets to an interface without a carrier, they
start to fill up its outbout queue. Once the queue is full, new packets
that are routed to that interfaces won't be bridged anymore.

This happens in the example above with dhcpd. DHCP requests come in on B
and get bridge-forwarded to A (filling up A's outbound queue). dhcpd
generates responses, which are sent via A and then bridge-forwarded to
B. Once A's outbound queue is full, those responses fall on the floor.

Attached is an ugly hack that fixes this in my setup.

The next issue is bridge interactions with IPv6 stateless autoconf. IPv6
doesn't like link-local addresses appearing on (apparently) different
interfaces...

Lars
--
Lars Eggert <[EMAIL PROTECTED]>           USC Information Sciences Institute
--- /nfs/ruby/larse/if_var.h    Sun Oct 27 11:48:06 2002
+++ sys/net/if_var.h    Sun Oct 27 11:47:47 2002
@@ -272,6 +272,38 @@
        int need_if_start = 0;
        int s = splimp();
  
+        /*
+         * Drop the packet if the outbound interface has no carrier.
+         * This prevents the queue from filling up, causing bridging
+         * to fail, since packets would be dropped before being bridged. 
+         *
+         * XXX I'd be nice if we could easily peek at the media status
+         *     here. Instead, use a 50% full queue together with the
+         *     interface not sending is an indicator.
+         */
+        if (ifp && (!(ifp->if_flags & IFF_OACTIVE)) &&
+           ifq->ifq_len > ifq->ifq_maxlen / 2) {
+                /*   
+                 * Flush the queue here, otherwise we send out stale
+                 * packets once the interface gets a carrier.
+                *
+                * XXX This duplicates ifq_qflush().
+                 */ 
+               register struct mbuf *m2, *n;
+               n = ifq->ifq_head;
+               while ((m2 = n) != 0) {
+                       n = m2->m_act;
+                       m_freem(m2);
+               }
+               ifq->ifq_head = 0;
+               ifq->ifq_tail = 0;
+               ifq->ifq_len = 0;
+
+               /* Now drop the packet. */ 
+                m_freem(m);
+                return (0);
+        }
+
        if (IF_QFULL(ifq)) {
                IF_DROP(ifq);
                splx(s);
--- /nfs/ruby/larse/bridge.c    Sun Oct 27 11:48:14 2002
+++ sys/net/bridge.c    Sun Oct 27 11:51:54 2002
@@ -104,6 +104,7 @@
 #include <net/if.h>
 #include <net/if_types.h>
 #include <net/if_var.h>
+#include <net/bpf.h>
 
 #include <netinet/in.h> /* for struct arpcom */
 #include <netinet/in_systm.h>
@@ -197,7 +198,7 @@
  *
  */
 
-#define DDB(x) x
+#define DDB(x)
 #define DEB(x)
 
 static int bdginit(void);
@@ -813,7 +814,7 @@
      */
     struct ether_header save_eh = *eh ;
 
-    DEB(quad_t ticks; ticks = rdtsc();)
+    DDB(quad_t ticks; ticks = rdtsc();)
 
     args.rule = NULL;          /* did we match a firewall rule ? */
     /* Fetch state from dummynet tag, ignore others */
@@ -1015,6 +1016,21 @@
                    return m0 ; /* the original is still there... */
                }
            }
+
+           /*
+            * Deliver a copy of the packet to the bpf even if the interface
+            * has no carrier. This fixes kern/41632.
+            */
+           if ((!(last->if_flags & IFF_OACTIVE)) && last->if_bpf != NULL) {
+               struct m_hdr mh;
+
+               /* This kludge is OK; BPF treats the "mbuf" as read-only */
+               mh.mh_next = m;
+               mh.mh_data = (char *)eh;
+               mh.mh_len = ETHER_HDR_LEN;
+               bpf_mtap(last, (struct mbuf *)&mh);
+            }
+ 
            /*
             * Add header (optimized for the common case of eh pointing
             * already into the mbuf) and execute last part of ether_output:
@@ -1058,7 +1074,7 @@
        if (ifp == NULL)
            once = 1 ;
     }
-    DEB(bdg_fw_ticks += (u_long)(rdtsc() - ticks) ; bdg_fw_count++ ;
+    DDB(bdg_fw_ticks += (u_long)(rdtsc() - ticks) ; bdg_fw_count++ ;
        if (bdg_fw_count != 0) bdg_fw_avg = bdg_fw_ticks/bdg_fw_count; )
     return m0 ;
 }

Attachment: smime.p7s
Description: S/MIME Cryptographic Signature

Reply via email to