summaryrefslogtreecommitdiffstats
path: root/sys/netgraph/ng_fec.c
diff options
context:
space:
mode:
authordwmalone <dwmalone@FreeBSD.org>2007-05-18 15:05:49 +0000
committerdwmalone <dwmalone@FreeBSD.org>2007-05-18 15:05:49 +0000
commit5ad0d6d6def6c5a2575dabcd2da461fab7c9e671 (patch)
treedea82612d4b2efca8b5cf91197d44d93d7a2f94c /sys/netgraph/ng_fec.c
parentb12787f5fb03b5f8984a608fe5ea86042aa671b4 (diff)
downloadFreeBSD-src-5ad0d6d6def6c5a2575dabcd2da461fab7c9e671.zip
FreeBSD-src-5ad0d6d6def6c5a2575dabcd2da461fab7c9e671.tar.gz
Help ng_fec deal with multicast addresses.
While ng_fec called the ioctl to let interfaces in the bundle know the list of multicast addresses had changed, it never actually updated that list on the interfaces in the bundle. Consequently, the multicast filters could be programmed incorrectly. if_lagg does this correctly, by maintaining a list of addresses that it has added to interfaces in the bundle. This commit basically takes the if_lagg code and adds it to ng_fec. A version of this patch for RELENG_6 has fixed some problems with IPv6 ND over ng_fec. This is probably the problem in PR 107523. PR: 107523 Tested by: Rob Gallagher <robert.gallagher@heanet.ie> Obtained from: if_lagg MFC after: 3 weeks
Diffstat (limited to 'sys/netgraph/ng_fec.c')
-rw-r--r--sys/netgraph/ng_fec.c79
1 files changed, 77 insertions, 2 deletions
diff --git a/sys/netgraph/ng_fec.c b/sys/netgraph/ng_fec.c
index ccd3c84..58f16a9 100644
--- a/sys/netgraph/ng_fec.c
+++ b/sys/netgraph/ng_fec.c
@@ -149,9 +149,15 @@ struct ng_fec_portlist {
int fec_idx;
int fec_ifstat;
struct ether_addr fec_mac;
+ SLIST_HEAD(__mclhd, ng_fec_mc) fec_mc_head;
TAILQ_ENTRY(ng_fec_portlist) fec_list;
};
+struct ng_fec_mc {
+ struct ifmultiaddr *mc_ifma;
+ SLIST_ENTRY(ng_fec_mc) mc_entries;
+};
+
struct ng_fec_bundle {
TAILQ_HEAD(,ng_fec_portlist) ng_fec_ports;
int fec_ifcnt;
@@ -195,6 +201,7 @@ static int ng_fec_output(struct ifnet *ifp, struct mbuf *m0,
static void ng_fec_tick(void *arg);
static int ng_fec_addport(struct ng_fec_private *priv, char *iface);
static int ng_fec_delport(struct ng_fec_private *priv, char *iface);
+static int ng_fec_ether_cmdmulti(struct ifnet *trifp, struct ng_fec_portlist *p, int set);
#ifdef DEBUG
static void ng_fec_print_ioctl(struct ifnet *ifp, int cmd, caddr_t data);
@@ -417,6 +424,9 @@ ng_fec_addport(struct ng_fec_private *priv, char *iface)
new->fec_idx = b->fec_ifcnt;
b->fec_ifcnt++;
+ /* Initialise the list of multicast addresses that we own. */
+ SLIST_INIT(&new->fec_mc_head);
+
/* Save the real MAC address. */
bcopy(IF_LLADDR(bifp),
(char *)&new->fec_mac, ETHER_ADDR_LEN);
@@ -439,6 +449,9 @@ ng_fec_addport(struct ng_fec_private *priv, char *iface)
new->fec_ifstat = -1;
TAILQ_INSERT_TAIL(&b->ng_fec_ports, new, fec_list);
+ /* Add multicast addresses to this port. */
+ ng_fec_ether_cmdmulti(ifp, new, 1);
+
return(0);
}
@@ -507,9 +520,70 @@ ng_fec_delport(struct ng_fec_private *priv, char *iface)
return(0);
}
+static int
+ng_fec_ether_cmdmulti(struct ifnet *trifp, struct ng_fec_portlist *p, int set)
+{
+ struct ifnet *ifp = p->fec_if;
+ struct ng_fec_mc *mc;
+ struct ifmultiaddr *ifma, *rifma = NULL;
+ struct sockaddr_dl sdl;
+ int error;
+
+ bzero((char *)&sdl, sizeof(sdl));
+ sdl.sdl_len = sizeof(sdl);
+ sdl.sdl_family = AF_LINK;
+ sdl.sdl_type = IFT_ETHER;
+ sdl.sdl_alen = ETHER_ADDR_LEN;
+ sdl.sdl_index = ifp->if_index;
+
+ if (set) {
+ TAILQ_FOREACH(ifma, &trifp->if_multiaddrs, ifma_link) {
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+ bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
+ LLADDR(&sdl), ETHER_ADDR_LEN);
+
+ error = if_addmulti(ifp, (struct sockaddr *)&sdl, &rifma);
+ if (error)
+ return (error);
+ mc = malloc(sizeof(struct ng_fec_mc), M_DEVBUF, M_NOWAIT);
+ if (mc == NULL)
+ return (ENOMEM);
+ mc->mc_ifma = rifma;
+ SLIST_INSERT_HEAD(&p->fec_mc_head, mc, mc_entries);
+ }
+ } else {
+ while ((mc = SLIST_FIRST(&p->fec_mc_head)) != NULL) {
+ SLIST_REMOVE(&p->fec_mc_head, mc, ng_fec_mc, mc_entries);
+ if_delmulti_ifma(mc->mc_ifma);
+ free(mc, M_DEVBUF);
+ }
+ }
+ return (0);
+}
+
+static int
+ng_fec_ether_setmulti(struct ifnet *ifp)
+{
+ struct ng_fec_private *priv;
+ struct ng_fec_bundle *b;
+ struct ng_fec_portlist *p;
+
+ priv = ifp->if_softc;
+ b = &priv->fec_bundle;
+
+ TAILQ_FOREACH(p, &b->ng_fec_ports, fec_list) {
+ /* First, remove any existing filter entries. */
+ ng_fec_ether_cmdmulti(ifp, p, 0);
+ /* copy all addresses from the fec interface to the port */
+ ng_fec_ether_cmdmulti(ifp, p, 1);
+ }
+ return (0);
+}
+
/*
* Pass an ioctl command down to all the underyling interfaces in a
- * bundle. Used for setting multicast filters and flags.
+ * bundle. Used for setting flags.
*/
static int
@@ -752,7 +826,7 @@ ng_fec_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
case SIOCADDMULTI:
case SIOCDELMULTI:
- ng_fec_setport(ifp, command, data);
+ ng_fec_ether_setmulti(ifp);
error = 0;
break;
case SIOCGIFMEDIA:
@@ -1255,6 +1329,7 @@ ng_fec_shutdown(node_p node)
while (!TAILQ_EMPTY(&b->ng_fec_ports)) {
p = TAILQ_FIRST(&b->ng_fec_ports);
+ ng_fec_ether_cmdmulti(priv->ifp, p, 0);
ng_fec_delport(priv, p->fec_if->if_xname);
}
OpenPOWER on IntegriCloud