--- /vobs/fw-bsd/src/sys/net/if_lagg.c 2012-01-24 05:28:25.000000000 -0500 +++ /vobs/fw-bsd/src/sys/net/if_lagg.c 2012-02-03 09:11:50.000000000 -0500 @@ -54,13 +54,19 @@ #ifdef INET #include +#include #include #include #include #endif #ifdef INET6 +#include #include +#include +#include +#include +#include #endif #include @@ -746,6 +752,7 @@ switch (dst->sa_family) { case pseudo_AF_HDRCMPLT: + return ((*lp->lp_output)(ifp, m, dst, ro)); case AF_UNSPEC: eh = (struct ether_header *)dst->sa_data; type = eh->ether_type; @@ -1053,7 +1060,38 @@ error = EINVAL; break; - default: + case SIOCSPLAGGPORT: + + if (rp->rp_portname[0] == '\0' || + (tpif = ifunit(rp->rp_portname)) == NULL) { + error = EINVAL; + break; + } + + LAGG_WLOCK(sc); + if ((lp = (struct lagg_port *)tpif->if_lagg) == NULL || + lp->lp_softc != sc) { + error = ENOENT; + LAGG_WUNLOCK(sc); + break; + } + /* This port is already primary port no need to do any thing */ + if(SLIST_FIRST(&sc->sc_ports)== lp){ + LAGG_WUNLOCK(sc); + return (error); + } + else{ + SLIST_REMOVE(&sc->sc_ports, lp, lagg_port, lp_entries); + SLIST_INSERT_HEAD(&sc->sc_ports, lp, lp_entries); + sc->sc_primary = lp; + lagg_lladdr(sc, lp->lp_lladdr); + sc->sc_ifp->if_mtu = tpif->if_mtu; + SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) + lagg_port_lladdr(lp, IF_LLADDR(ifp)); + LAGG_WUNLOCK(sc); + } + break; + default: error = ether_ioctl(ifp, cmd, data); break; } @@ -1309,17 +1347,47 @@ { struct lagg_port *lp = (struct lagg_port *)ifp->if_lagg; struct lagg_softc *sc = NULL; + struct ifaddr *ifa ; + struct in6_ifaddr *ia = NULL; + struct in6_addr *in6 = NULL; + struct ifaddrhead ifaddrh; + struct in_ifaddr *laddr = NULL; if (lp != NULL) sc = lp->lp_softc; if (sc == NULL) return; - + LAGG_WLOCK(sc); lagg_linkstate(sc); + if (sc->sc_linkstate != NULL) (*sc->sc_linkstate)(lp); + LAGG_WUNLOCK(sc); + + /* If status changed on primary port send gratuitous ARP */ + + if(sc->sc_primary == lp){ + IFP_TO_IA(sc->sc_ifp, laddr); + if (laddr == NULL) + return; + ifaddrh = sc->sc_ifp->if_addrhead; + TAILQ_FOREACH(ifa, &ifaddrh, ifa_link) { +#ifdef INET + if(ifa->ifa_addr->sa_family == AF_INET) + arp_ifinit(sc->sc_ifp,(struct ifaddr *) laddr); +#endif + +#ifdef INET6 + if (ifa->ifa_addr->sa_family == AF_INET6){ + ia = in6ifa_ifpforlinklocal(sc->sc_ifp, 0); + in6 = &ifatoia6(ifa)->ia_addr.sin6_addr; + nd6_ns_output(sc->sc_ifp, NULL,in6, 0, 1); + } +#endif + } + } } struct lagg_port * --- /vobs/fw-bsd/src/sys/net/if_lagg.h 2012-02-03 03:45:32.000000000 -0500 +++ /vobs/fw-bsd/src/sys/net/if_lagg.h 2012-02-03 03:53:18.000000000 -0500 @@ -119,6 +119,7 @@ #define SIOCGLAGG _IOWR('i', 143, struct lagg_reqall) #define SIOCSLAGG _IOW('i', 144, struct lagg_reqall) +#define SIOCSPLAGGPORT _IOWR('i', 145, struct lagg_reqport) #ifdef _KERNEL /* --- /vobs/fw-bsd/src/sbin/ifconfig/iflagg.c 2012-02-03 00:48:38.000000000 -0500 +++ /vobs/fw-bsd/src/sbin/ifconfig/iflagg.c 2012-02-03 01:41:34.000000000 -0500 @@ -43,6 +43,18 @@ if (ioctl(s, SIOCSLAGGPORT, &rp)) err(1, "SIOCSLAGGPORT"); } +static void +setlaggpport(const char *val, int d, int s, const struct afswtch *afp) +{ + struct lagg_reqport rp; + + bzero(&rp, sizeof(rp)); + strlcpy(rp.rp_ifname, name, sizeof(rp.rp_ifname)); + strlcpy(rp.rp_portname, val, sizeof(rp.rp_portname)); + + if (ioctl(s, SIOCSLAGGPPORT, &rp)) + err(1, "SIOCSLAGPPORT"); +} static void unsetlaggport(const char *val, int d, int s, const struct afswtch *afp) @@ -174,6 +186,7 @@ DEF_CMD_ARG("laggport", setlaggport), DEF_CMD_ARG("-laggport", unsetlaggport), DEF_CMD_ARG("laggproto", setlaggproto), + DEF_CMD_ARG("laggpport", setlaggpport), }; static struct afswtch af_lagg = { .af_name = "af_lagg",