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