From 4239d24b98a8a28300e57c230ae1bd8fce23eb4a Mon Sep 17 00:00:00 2001 From: Max Laier Date: Sat, 29 Mar 2008 00:24:36 +0000 Subject: [PATCH] Make ALTQ cope with disappearing interfaces (particularly common with mpd and netgraph in gernal). This also allows to add queues for an interface that is not yet existing (you have to provide the bandwidth for the interface, however). PR: kern/106400, kern/117827 MFC after: 2 weeks --- contrib/pf/pfctl/pfctl_altq.c | 12 ++++ contrib/pf/pfctl/pfctl_qstats.c | 26 +++++++ sys/contrib/pf/net/pf_if.c | 6 ++ sys/contrib/pf/net/pf_ioctl.c | 118 +++++++++++++++++++++++++++++++- sys/contrib/pf/net/pfvar.h | 7 ++ 5 files changed, 167 insertions(+), 2 deletions(-) diff --git a/contrib/pf/pfctl/pfctl_altq.c b/contrib/pf/pfctl/pfctl_altq.c index 3f2efeee30aa..b90e7c6b2742 100644 --- a/contrib/pf/pfctl/pfctl_altq.c +++ b/contrib/pf/pfctl/pfctl_altq.c @@ -153,6 +153,10 @@ print_altq(const struct pf_altq *a, unsigned level, struct node_queue_bw *bw, return; } +#ifdef __FreeBSD__ + if (a->local_flags & PFALTQ_FLAG_IF_REMOVED) + printf("INACTIVE "); +#endif printf("altq on %s ", a->ifname); switch (a->scheduler) { @@ -187,6 +191,10 @@ print_queue(const struct pf_altq *a, unsigned level, struct node_queue_bw *bw, { unsigned i; +#ifdef __FreeBSD__ + if (a->local_flags & PFALTQ_FLAG_IF_REMOVED) + printf("INACTIVE "); +#endif printf("queue "); for (i = 0; i < level; ++i) printf(" "); @@ -1145,7 +1153,11 @@ getifmtu(char *ifname) sizeof(ifr.ifr_name)) errx(1, "getifmtu: strlcpy"); if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) == -1) +#ifdef __FreeBSD__ + ifr.ifr_mtu = 1500; +#else err(1, "SIOCGIFMTU"); +#endif if (shutdown(s, SHUT_RDWR) == -1) err(1, "shutdown"); if (close(s)) diff --git a/contrib/pf/pfctl/pfctl_qstats.c b/contrib/pf/pfctl/pfctl_qstats.c index 28535c2410fb..d4089d6fbc83 100644 --- a/contrib/pf/pfctl/pfctl_qstats.c +++ b/contrib/pf/pfctl/pfctl_qstats.c @@ -118,6 +118,10 @@ pfctl_show_altq(int dev, const char *iface, int opts, int verbose2) for (node = root; node != NULL; node = node->next) { if (iface != NULL && strcmp(node->altq.ifname, iface)) continue; +#ifdef __FreeBSD__ + if (node->altq.local_flags & PFALTQ_FLAG_IF_REMOVED) + continue; +#endif pfctl_print_altq_node(dev, node, 0, opts); } } @@ -157,7 +161,12 @@ pfctl_update_qstats(int dev, struct pf_altq_node **root) warn("DIOCGETALTQ"); return (-1); } +#ifdef __FreeBSD__ + if (pa.altq.qid > 0 && + !(pa.altq.local_flags & PFALTQ_FLAG_IF_REMOVED)) { +#else if (pa.altq.qid > 0) { +#endif pq.nr = nr; pq.ticket = pa.ticket; pq.buf = &qstats.data; @@ -175,6 +184,19 @@ pfctl_update_qstats(int dev, struct pf_altq_node **root) pfctl_insert_altq_node(root, pa.altq, qstats); } } +#ifdef __FreeBSD__ + else if (pa.altq.local_flags & PFALTQ_FLAG_IF_REMOVED) { + memset(&qstats.data, 0, sizeof(qstats.data)); + if ((node = pfctl_find_altq_node(*root, pa.altq.qname, + pa.altq.ifname)) != NULL) { + memcpy(&node->qstats.data, &qstats.data, + sizeof(qstats.data)); + update_avg(node); + } else { + pfctl_insert_altq_node(root, pa.altq, qstats); + } + } +#endif } return (mnr); } @@ -280,6 +302,10 @@ pfctl_print_altq_nodestat(int dev, const struct pf_altq_node *a) { if (a->altq.qid == 0) return; +#ifdef __FreeBSD__ + if (a->altq.local_flags & PFALTQ_FLAG_IF_REMOVED) + return; +#endif switch (a->altq.scheduler) { case ALTQT_CBQ: diff --git a/sys/contrib/pf/net/pf_if.c b/sys/contrib/pf/net/pf_if.c index f62b4974a477..2b823751047d 100644 --- a/sys/contrib/pf/net/pf_if.c +++ b/sys/contrib/pf/net/pf_if.c @@ -893,6 +893,9 @@ pfi_attach_ifnet_event(void *arg __unused, struct ifnet *ifp) { PF_LOCK(); pfi_attach_ifnet(ifp); +#ifdef ALTQ + pf_altq_ifnet_event(ifp, 0); +#endif PF_UNLOCK(); } @@ -901,6 +904,9 @@ pfi_detach_ifnet_event(void *arg __unused, struct ifnet *ifp) { PF_LOCK(); pfi_detach_ifnet(ifp); +#ifdef ALTQ + pf_altq_ifnet_event(ifp, 1); +#endif PF_UNLOCK(); } diff --git a/sys/contrib/pf/net/pf_ioctl.c b/sys/contrib/pf/net/pf_ioctl.c index 6314b4c3bbda..f9110cbec03f 100644 --- a/sys/contrib/pf/net/pf_ioctl.c +++ b/sys/contrib/pf/net/pf_ioctl.c @@ -787,7 +787,12 @@ pf_begin_altq(u_int32_t *ticket) /* Purge the old altq list */ while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) { TAILQ_REMOVE(pf_altqs_inactive, altq, entries); +#ifdef __FreeBSD__ + if (altq->qname[0] == 0 && + (altq->local_flags & PFALTQ_FLAG_IF_REMOVED) == 0) { +#else if (altq->qname[0] == 0) { +#endif /* detach and destroy the discipline */ error = altq_remove(altq); } else @@ -812,7 +817,12 @@ pf_rollback_altq(u_int32_t ticket) /* Purge the old altq list */ while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) { TAILQ_REMOVE(pf_altqs_inactive, altq, entries); +#ifdef __FreeBSD__ + if (altq->qname[0] == 0 && + (altq->local_flags & PFALTQ_FLAG_IF_REMOVED) == 0) { +#else if (altq->qname[0] == 0) { +#endif /* detach and destroy the discipline */ error = altq_remove(altq); } else @@ -842,7 +852,12 @@ pf_commit_altq(u_int32_t ticket) /* Attach new disciplines */ TAILQ_FOREACH(altq, pf_altqs_active, entries) { +#ifdef __FreeBSD__ + if (altq->qname[0] == 0 && + (altq->local_flags & PFALTQ_FLAG_IF_REMOVED) == 0) { +#else if (altq->qname[0] == 0) { +#endif /* attach the discipline */ error = altq_pfattach(altq); if (error == 0 && pf_altq_running) @@ -857,7 +872,12 @@ pf_commit_altq(u_int32_t ticket) /* Purge the old altq list */ while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) { TAILQ_REMOVE(pf_altqs_inactive, altq, entries); +#ifdef __FreeBSD__ + if (altq->qname[0] == 0 && + (altq->local_flags & PFALTQ_FLAG_IF_REMOVED) == 0) { +#else if (altq->qname[0] == 0) { +#endif /* detach and destroy the discipline */ if (pf_altq_running) error = pf_disable_altq(altq); @@ -943,6 +963,76 @@ pf_disable_altq(struct pf_altq *altq) return (error); } + +#ifdef __FreeBSD__ +void +pf_altq_ifnet_event(struct ifnet *ifp, int remove) +{ + struct ifnet *ifp1; + struct pf_altq *a1, *a2, *a3; + u_int32_t ticket; + int error = 0; + + /* Interrupt userland queue modifications */ + if (altqs_inactive_open) + pf_rollback_altq(ticket_altqs_inactive); + + /* Start new altq ruleset */ + if (pf_begin_altq(&ticket)) + return; + + /* Copy the current active set */ + TAILQ_FOREACH(a1, pf_altqs_active, entries) { + a2 = pool_get(&pf_altq_pl, PR_NOWAIT); + if (a2 == NULL) { + error = ENOMEM; + break; + } + bcopy(a1, a2, sizeof(struct pf_altq)); + + if (a2->qname[0] != 0) { + if ((a2->qid = pf_qname2qid(a2->qname)) == 0) { + error = EBUSY; + pool_put(&pf_altq_pl, a2); + break; + } + a2->altq_disc = NULL; + TAILQ_FOREACH(a3, pf_altqs_inactive, entries) { + if (strncmp(a3->ifname, a2->ifname, + IFNAMSIZ) == 0 && a3->qname[0] == 0) { + a2->altq_disc = a3->altq_disc; + break; + } + } + } + /* Deactivate the interface in question */ + a2->local_flags &= ~PFALTQ_FLAG_IF_REMOVED; + if ((ifp1 = ifunit(a2->ifname)) == NULL || + (remove && ifp1 == ifp)) { + a2->local_flags |= PFALTQ_FLAG_IF_REMOVED; + } else { + PF_UNLOCK(); + error = altq_add(a2); + PF_LOCK(); + + if (ticket != ticket_altqs_inactive) + error = EBUSY; + + if (error) { + pool_put(&pf_altq_pl, a2); + break; + } + } + + TAILQ_INSERT_TAIL(pf_altqs_inactive, a2, entries); + } + + if (error != 0) + pf_rollback_altq(ticket); + else + pf_commit_altq(ticket); +} +#endif #endif /* ALTQ */ int @@ -2273,7 +2363,12 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) /* enable all altq interfaces on active list */ TAILQ_FOREACH(altq, pf_altqs_active, entries) { +#ifdef __FreeBSD__ + if (altq->qname[0] == 0 && (altq->local_flags & + PFALTQ_FLAG_IF_REMOVED) == 0) { +#else if (altq->qname[0] == 0) { +#endif error = pf_enable_altq(altq); if (error != 0) break; @@ -2290,7 +2385,12 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) /* disable all altq interfaces on active list */ TAILQ_FOREACH(altq, pf_altqs_active, entries) { +#ifdef __FreeBSD__ + if (altq->qname[0] == 0 && (altq->local_flags & + PFALTQ_FLAG_IF_REMOVED) == 0) { +#else if (altq->qname[0] == 0) { +#endif error = pf_disable_altq(altq); if (error != 0) break; @@ -2316,6 +2416,9 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } bcopy(&pa->altq, altq, sizeof(struct pf_altq)); +#ifdef __FreeBSD__ + altq->local_flags = 0; +#endif /* * if this is for a queue, find the discipline and @@ -2327,6 +2430,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) pool_put(&pf_altq_pl, altq); break; } + altq->altq_disc = NULL; TAILQ_FOREACH(a, pf_altqs_inactive, entries) { if (strncmp(a->ifname, altq->ifname, IFNAMSIZ) == 0 && a->qname[0] == 0) { @@ -2337,11 +2441,17 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } #ifdef __FreeBSD__ - PF_UNLOCK(); + struct ifnet *ifp; + + if ((ifp = ifunit(altq->ifname)) == NULL) { + altq->local_flags |= PFALTQ_FLAG_IF_REMOVED; + } else { + PF_UNLOCK(); #endif error = altq_add(altq); #ifdef __FreeBSD__ - PF_LOCK(); + PF_LOCK(); + } #endif if (error) { pool_put(&pf_altq_pl, altq); @@ -2414,6 +2524,10 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } #ifdef __FreeBSD__ + if ((altq->local_flags & PFALTQ_FLAG_IF_REMOVED) != 0) { + error = ENXIO; + break; + } PF_UNLOCK(); #endif error = altq_getqstats(altq, pq->buf, &nbytes); diff --git a/sys/contrib/pf/net/pfvar.h b/sys/contrib/pf/net/pfvar.h index 6c5c23a8098d..bd75bfcae96f 100644 --- a/sys/contrib/pf/net/pfvar.h +++ b/sys/contrib/pf/net/pfvar.h @@ -1247,6 +1247,10 @@ struct pf_altq { u_int32_t parent_qid; /* parent queue id */ u_int32_t bandwidth; /* queue bandwidth */ u_int8_t priority; /* priority */ +#ifdef __FreeBSD__ + u_int8_t local_flags; /* dynamic interface */ +#define PFALTQ_FLAG_IF_REMOVED 0x01 +#endif u_int16_t qlimit; /* queue size limit */ u_int16_t flags; /* misc flags */ union { @@ -1574,6 +1578,9 @@ extern void pf_tbladdr_remove(struct pf_addr_wrap *); extern void pf_tbladdr_copyout(struct pf_addr_wrap *); extern void pf_calc_skip_steps(struct pf_rulequeue *); #ifdef __FreeBSD__ +#ifdef ALTQ +extern void pf_altq_ifnet_event(struct ifnet *, int); +#endif extern uma_zone_t pf_src_tree_pl, pf_rule_pl; extern uma_zone_t pf_state_pl, pf_altq_pl, pf_pooladdr_pl; extern uma_zone_t pfr_ktable_pl, pfr_kentry_pl, pfr_kentry_pl2;