Subject: Re: multiple Tx queues
To: None <tech-net@NetBSD.org>
From: David Young <dyoung@pobox.com>
List: tech-net
Date: 01/08/2004 16:54:50
--sdtB3X0nJg68CQEu
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
On Thu, Jan 08, 2004 at 12:48:30PM +1100, Daniel Carosone wrote:
> On Wed, Jan 07, 2004 at 05:31:33PM -0800, Erik E. Fair wrote:
> > So, you're suggesting a driver-specific queueing mechanism based on
> > TOS, rather than a more general packet queueing framework?
>
> In discussion on icb, there were two main areas of thought:
>
> - we need a good, general, appropriate interface from the driver, to
> expose this hardware feature into something like altq, so the
> administrator can set policy based on his own choices. This partly
> presumes that some other chips (wired or not) likely have some
> similar features.
>
> - a collection of ideas of quick hacks for types of packets that
> could meaningfully benefit "in the meantime". This set included
> tiny ACKS, perhaps TCP PSH frames (though that potentially creates
> ordering problems), and now TOS bits. Another idea was to allow
> individial source addresses (ie, aliases) to bind to l/m/h queues,
> and use the ip addresses accordingly in the external network.
> All cheesy in one way or another.
Here is my proposal in code for associating VLAN tags with hardware
queues.
Add to three new ioctls to interfaces: SIOCGIFQLIST, SIOCSIFQASSOC,
and SIOCGIFQASLIST.
SIOCGIFQLIST: list a device's hardware queues and their properties
SIOCSIFQASSOC: add/delete a tag->queue association
SIOCGIFQASLIST: list a device's queue<->tag associations
ifq.h contains definitions for the data structures and ioctls.
ifconfig.c contains subroutines for ifconfig to add/delete associations
and to list the queues.
It is still an open question, "what entity classifies packets and
applies tags?" To prioritize each packet, perhaps you can "bond" the
prioritized VLANs in a bridge(4) and use ipf rules to fast-forward to
the right VLAN. For example,
% ifconfig vlan0 create
% ifconfig vlan1 create
% ifconfig vlan2 create
% ifconfig bridge0 create
% ifconfig vlan0 vlan 6 vlanif rtw0
% ifconfig vlan1 vlan 7 vlanif rtw0
% ifconfig vlan2 vlan 8 vlanif rtw0
% ifconfig rtw0 addpri hi vlan 6
% ifconfig rtw0 addpri norm vlan 7
% ifconfig rtw0 addpri lo vlan 8
% ifconfig bridge0 add vlan0 add vlan1 add vlan2 up
#
# prioritize OSPF packets, give FTP data low priority, and pass
# all others at "normal" priority.
#
% pass out to vlan0 proto ospf
% pass out to vlan2 tcp port ftp-data
% pass out to vlan1
% ifconfig rtw0 inet 192.168.1.1/24
Dave
--
David Young OJC Technologies
dyoung@ojctech.com Urbana, IL * (217) 278-3933
--sdtB3X0nJg68CQEu
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="ifq.h"
enum ifqd_type {
IFQDESC_T_CFP = 0, /* 802.11 contention-free period, CFP */
IFQDESC_T_PRIORITY = 1 /* priority queue */
};
#define IFQDESC_F_OUT 0x1 /* output queue (the usual case) */
#define IFQDESC_F_IN 0x2 /* input queue */
#define IFQDESC_F_DFL 0x4 /* default queue */
struct ifqdesc {
enum ifqd_type iqd_type;
u_int16_t iqd_flags;
char iqd_name[IFNAMSIZ];
u_int iqd_depth; /* max queue depth */
union {
u_int u_prio; /* priority, 0 is highest */
struct {
u_int32_t cfpival; /* uS interval between CFPs */
u_int32_t cfpdur; /* uS duration of CFP */
} u_cfp;
} u;
/* ... */
};
#define iqd_prio u.iqdu_prio
#define iqd_cfpival u.u_cfp.cfpival
#define iqd_cfpival u.u_cfp.cfpdur
struct ifqlist {
u_int iql_len;
struct ifqdesc *iql_list;
};
enum ifqa_type {
IFQASSOC_T_TOS = 1, /* match TOS field */
IFQASSOC_T_VLAN = 2, /* match VLAN tag */
IFQASSOC_T_MTAG = 3 /* match m_tag ID */
};
enum ifqa_cmd {
IFQASSOC_CMD_ADD = 1, /* add */
IFQASSOC_CMD_DEL = 2 /* delete */
};
struct ifqassoc {
enum ifqa_cmd iqa_cmd; /* add, delete */
enum ifqa_type iqa_type; /* tag type */
u_int iqa_idx; /* index into ifqlist */
u_int16_t iqa_tag; /* TOS, VLAN tag, or m_tag ID */
};
struct ifqaslist {
u_int iqal_len;
struct ifqassoc *iqal_list;
};
struct ifreq {
char ifr_name[IFNAMSIZ];
union {
/* ... */
struct ifqlist ifru_qlist;
struct ifqassoc ifru_qassoc;
struct ifqaslist ifru_qaslist;
} ifr_ifru;
};
#define ifr_qlist ifr_ifru.ifru_qlist
#define ifr_qassoc ifr_ifru.ifru_qassoc
#define ifr_qaslist ifr_ifru.ifru_qaslist
#define SIOCGIFQLIST _IOWR('i', /*TBD*/, struct ifreq)
#define SIOCSIFQASSOC _IOW('i', /*TBD*/, struct ifreq)
#define SIOCSIFQASLIST _IOWR('i', /*TBD*/, struct ifreq)
--sdtB3X0nJg68CQEu
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="ifconfig.c"
/* list queues
*
* # ifconfig -q atw0
* cfp: 802.11 contention-free period
* # ifconfig -q rtw0
* hi: priority 0
* norm: priority 1 [default]
* lo: priority 2
*/
void
listqs(void)
{
int i;
struct ifreq ifr;
struct ifqdesc *iqd;
#define NQDESC 20
struct ifqdesc qdescs[NQDESC]; /* XXX should be dynamic */
ifr.ifr_qlist.iql_len = NQDESC;
ifr.ifr_qlist.iql_list = &qdescs[0];
(void)strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
/* returns ENOMEM if too many (> NQDESC) descriptors */
if (ioctl(s, SIOCGIFQLIST, &ifr) != 0)
err(EXIT_FAILURE, "ioctl(,SIOCGIFQLIST,)");
/* print each queue */
for (i = 0; i < ifr.ifr_qlist.iql_len; i++) {
iqd = &qdescs[i];
printf("%s: ", iqd->iqd_type);
switch (iqd->iqd_type) {
case IFQDESC_T_CFP:
printf("802.11 contention-free period");
break;
case IFQDESC_T_PRIORITY:
printf("priority %u", iqd->iqd_pri);
break;
default:
printf("unknown");
break;
}
if ((iqd->iqd_flags & IFQDESC_F_DFL) == 0)
printf("\n");
else
printf(" [default]\n");
}
}
/* add/delete tag->queue association
*
* # ifconfig vlan0 create
* # ifconfig vlan0 vlan 6 vlanif rtw0
* # ifconfig vlan1 create
* # ifconfig vlan1 vlan 7 vlanif rtw0
* # ifconfig vlan2 create
* # ifconfig vlan2 vlan 8 vlanif rtw0
*
* # ifconfig rtw0 addpri hi vlan 6
* # ifconfig rtw0 addpri med vlan 7
* # ifconfig atw0 addpri lo vlan 8
*
* # ifconfig atw0 delpri lo vlan 8
* # ifconfig atw0 delpri norm vlan 7
* # ifconfig atw0 delpri hi vlan 6
*/
void
setifqassoc(char *priname, u_int16_t tag, enum ifqa_cmd assoc_cmd,
enum ifqa_type assoc_type)
{
int i;
struct ifreq ifr;
struct ifqdesc *iqd;
#define NQDESC 20
struct ifqdesc qdescs[NQDESC];
ifr.ifr_qlist.iql_len = NQDESC;
ifr.ifr_qlist.iql_list = &qdescs[0];
(void)strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
/* returns ENOMEM if too many (> NQDESC) descriptors */
if (ioctl(s, SIOCGIFQLIST, &ifr) != 0)
err(EXIT_FAILURE, "ioctl(,SIOCGIFQLIST,)");
/* find the queue */
for (i = 0; i < ifr.ifr_qlist.iql_len; i++) {
iqd = &qdescs[i];
if (strcmp(iqd->iqd_name, priname) == 0)
break;
}
if (i == ifr.ifr_qlist.iql_len)
errx(EXIT_FAILURE, "%s: no such priority %d", ifname, pri);
ifr.ifr_qassoc.iqa_cmd = assoc_cmd;
ifr.ifr_qassoc.iqa_type = assoc_type;
ifr.ifr_qassoc.iqa_idx = i;
ifr.ifr_qassoc.iqa_tag = tag;
if (ioctl(s, SIOCSIFQASSOC, &ifr) != 0)
err(EXIT_FAILURE, "ioctl(,SIOCGIFQASSOC,)");
}
--sdtB3X0nJg68CQEu--