On Mon, Jun 06, 2016 at 12:50:04PM +0200, Martin Pieuchot wrote:
> On 06/06/16(Mon) 16:23, Masao Uebayashi wrote:
> > On Mon, Jun 06, 2016 at 08:50:49AM +0200, Martin Pieuchot wrote:
> > > On 06/06/16(Mon) 13:04, Masao Uebayashi wrote:
> > > > Broadcast frame, coming into a bridge'ed interface, passes if_input() 3 
> > > > times,
> > > > and actually input (ether_input()) twice.
> > > > 
> > > > - A frame enters an interface (e.g. pair(4)), the interface calls 
> > > > if_input()
> > > >   on it.  The frame is queued in if_input_queue.
> > > > 
> > > > - A task running if_input_process() is triggered.  It takes the frame 
> > > > and
> > > >   calls bridge_input().  Frame is queued in bridgeintrq.
> > > > 
> > > > - bridge_process() dispatches frame as multicast/broadcast (if
> > > >   (ETHER_IS_MULTICAST())) and calls bridge_ifinput() on it, then passes 
> > > > the
> > > >   frame to bridgeintr_frame().
> > > > 
> > > > - bridgeintr_frame() calls bridge_broadcast() on it.
> > > > 
> > > > - bridge_broadcast() calls bridge_localbroadcast(), which again calls
> > > >   bridge_ifinput().
> > > > 
> > > > bridge_ifinput() is called twice for each broadcast frames.  
> > > > bridge_ifinput()
> > > > calls if_input().  Thus 3 if_input() for each.
> > > > 
> > > > These duplicate frames confuse pppoe(4), that's why it stops working.
> > > 
> > > What do you mean by "confuse pppoe(4)"?  I still don't understand what's
> > > the link between pppoe(4) and bpf(4) in this case and why BPF matters
> > > for a kernel driver.
> > 
> > - PPPoE client (pppoe(4)) sends a PPPoE Discovery "initiation" frame, which 
> > is
> >   broadcast.
> > 
> > - PPPoE server (npppd(8)) receives 3 copies of it via bpf(4), then returns
> >   3 PPPoE Discovery "offer" frames.
> > 
> > - pppoe(4) receives 3 "offer" frames and gets confused ... somehow.
> > 
> > I don't know the internal of pppoe(4) yet.  pppoe(4) might have a bug, it
> > might be able to work even if it receives 3 replies at once, I don't know.
> > 
> > I don't think that npppd(8) receiving 3 copies of broadcast frames (via
> > bpf(4)) is an intentional design anyway.
> 
> I agree.  Diff below should reduce the number of copies to 2.

Diff works as expected for me, and reads me good.  OK uebayasi@.

> In order
> to remove the last copy somebody has to turn bridge_process() MP-safe
> and merge it with bridge_input().  
> 
> Once this is done, bridge_input() can return "0" for multicast packets
> and ether_input() will be call directly without the need for requeueing
> the packet.

I admit I don't fully understand the intention of if_ih_* handler.  Can
you safely assume that there is always ether_input() hook just after
bridge_input()?

> Index: net/if_bridge.c
> ===================================================================
> RCS file: /cvs/src/sys/net/if_bridge.c,v
> retrieving revision 1.279
> diff -u -p -r1.279 if_bridge.c
> --- net/if_bridge.c   30 May 2016 12:56:16 -0000      1.279
> +++ net/if_bridge.c   6 Jun 2016 10:46:01 -0000
> @@ -1129,7 +1129,7 @@ bridge_process(struct ifnet *ifp, struct
>               } else
>  #endif /* NGIF */
>               bridge_ifinput(ifp, mc);
> -             
> +
>               bridgeintr_frame(sc, ifp, m);
>               return;
>       }
> @@ -1225,14 +1225,15 @@ bridge_broadcast(struct bridge_softc *sc
>               if (bridge_filterrule(&p->bif_brlout, eh, m) == 
> BRL_ACTION_BLOCK)
>                       continue;
>  
> -             bridge_localbroadcast(sc, dst_if, eh, m);
> -
>               /*
>                * Don't retransmit out of the same interface where
>                * the packet was received from.
>                */
>               if (dst_if->if_index == ifp->if_index)
>                       continue;
> +
> +             bridge_localbroadcast(sc, dst_if, eh, m);
> +
>  #if NMPW > 0
>               /*
>                * Split horizon: avoid broadcasting messages from wire to

Reply via email to