13.01.2016, 13:02, "Olivier Cochard-Labbé" <oliv...@cochard.me>:
> On Wed, Jan 13, 2016 at 9:45 AM, Alexander V. Chernikov <melif...@ipfw.ru>
> wrote:
>
>>  I suspect the reason here is link state bridge handling.
>>  ix0 does not seem to have IFCAP_LINKSTATE option but re(4) does. Probably
>>  wlan0 doesn't have LINKSTATE option.
>>  Code in bridge_linkcheck() doesn't handle the case with both "has link
>>  state" and "no link state" interfaces well:
>>  if reX is the only interface w/ IFCAP_LINKSTATE and it goes down, bridge
>>  will also change its link state to down.
>>  (However, bridge does not seem to have link state option itself, so
>>  RT_LINK_IS_UP() macro should return true...)
>
> ​For validating your "IFCAP_LINKSTATE" hypothesis, I've plug an USB
> ethernet adapter ue(4) that didn't support IFCAP_LINKSTATE.
> And I've setup the bridge0 with wlan0 and ue0 (in place of re1): same bug
> triggered. I need to ​plug a cable for correct routing.
We discussed/investigated this behaviour on IRC. To summarise:
1) ip_tryforward() does check interface linkstate regardless of linkstate 
capability
2) bridge linkcheck function does not seem to care about linkstate capability.

What happened in original case:
802.11 does not provide linkstate cap and actual linkstate value is 0 (unknown).
re0 does provide linkstate cap, so on link down, bridge_linkcheck() code 
decided to set own linkstate as DOWN as well (has non-zero linkstate interface, 
0 up).
On packet transmission. ip_tryforward() checked bridge0 state, found it to be 
DOWN so the icmp_error() was triggered.

Attached patch fixes the problem, but I'm still thinking about better solution.

>
> ​root@fbsd-router:~ # ifconfig bridge0
> bridge0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu
> 1500
>         ether 02:6b:c0:de:b8:00
>         inet 1.1.1.1 netmask 0xffffff00 broadcast 1.1.1.255
>         nd6 options=9<PERFORMNUD,IFDISABLED>
>         groups: bridge
>         id 00:00:00:00:00:00 priority 32768 hellotime 2 fwddelay 15
>         maxage 20 holdcnt 6 proto rstp maxaddr 2000 timeout 1200
>         root id 00:00:00:00:00:00 priority 32768 ifcost 0 port 0
>         member: ue0 flags=143<LEARNING,DISCOVER,AUTOEDGE,AUTOPTP>
>                 ifmaxaddr 0 port 7 priority 128 path cost 55
>         member: wlan0 flags=143<LEARNING,DISCOVER,AUTOEDGE,AUTOPTP>
>                 ifmaxaddr 0 port 5 priority 128 path cost 33333
> root@fbsd-router:~ # ifconfig ue0
> ue0: flags=8943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST> metric 0
> mtu 1500
>         options=80008<VLAN_MTU,LINKSTATE>
>         ether 00:19:fd:4e:77:4d
>         nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
>         media: Ethernet autoselect (none)
>         status: no carrier
> ​
> ​Regards,
> _______________________________________________
> freebsd-curr...@freebsd.org mailing list
> https://lists.freebsd.org/mailman/listinfo/freebsd-current
> To unsubscribe, send any mail to "freebsd-current-unsubscr...@freebsd.org"
Index: /usr/src/sys/net/if_bridge.c
===================================================================
--- /usr/src/sys/net/if_bridge.c	(revision 293659)
+++ /usr/src/sys/net/if_bridge.c	(working copy)
@@ -3550,22 +3550,25 @@ static void
 bridge_linkcheck(struct bridge_softc *sc)
 {
 	struct bridge_iflist *bif;
-	int new_link, hasls;
+	int new_link, nols;
 
 	BRIDGE_LOCK_ASSERT(sc);
 	new_link = LINK_STATE_DOWN;
-	hasls = 0;
+	nols = 0;
 	/* Our link is considered up if at least one of our ports is active */
 	LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
-		if (bif->bif_ifp->if_capabilities & IFCAP_LINKSTATE)
-			hasls++;
+		if ((bif->bif_ifp->if_capabilities & IFCAP_LINKSTATE) == 0) {
+			/* XXX: Handle admin down? */
+			nols++;
+			continue;
+		}
 		if (bif->bif_ifp->if_link_state == LINK_STATE_UP) {
 			new_link = LINK_STATE_UP;
 			break;
 		}
 	}
-	if (!LIST_EMPTY(&sc->sc_iflist) && !hasls) {
-		/* If no interfaces support link-state then we default to up */
+	if (!LIST_EMPTY(&sc->sc_iflist) && nols != 0) {
+		/* If some ifaces don't support link-state then we default to up */
 		new_link = LINK_STATE_UP;
 	}
 	if_link_state_change(sc->sc_ifp, new_link);
_______________________________________________
freebsd-wireless@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/freebsd-wireless
To unsubscribe, send any mail to "freebsd-wireless-unsubscr...@freebsd.org"

Reply via email to