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
This commit is contained in:
Max Laier 2008-03-29 00:24:36 +00:00
parent 9e74206fe0
commit 4239d24b98
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=177700
5 changed files with 167 additions and 2 deletions

View File

@ -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))

View File

@ -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:

View File

@ -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();
}

View File

@ -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);

View File

@ -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;