struct tc_u32_key
{
        __u32           mask;
        __u32           val;
        int             off;
        int             offmask;
};
The structure represents a rule applied at each packet. The
rule is very generic. It matches any packet if it has value
val at offset off. Only these bits where mask is 1 are compared.
Offmask value is used to mask protocol offsets - the exact
meaning is not known to me yet.
struct tc_u32_sel
{
        unsigned char           flags;
        unsigned char           offshift;
        unsigned char           nkeys;
        __u16                   offmask;
        __u16                   off;
        short                   offoff;
        short                   hoff;
        __u32                   hmask;
        struct tc_u32_key       keys[0];
};
This structure contains nkeys count of tc_u32_key. Various flags
can be:TC_U32_TERMINAL when reached during classify, result is copied from here
TC_U32_OFFSET this is used on only one line in source code, it seems as bug. Probably it should tell classifier to apply tc_u32_sel.off when going into subtable.
TC_U32_VAROFFSET similar to previous one, only the offset is fetched from packet at position tc_u32_sel.offoff masked by tc_u32_sel.offmask and shifted right by tc_u32_sel.offshift shifts. It's useful when you need to "locate" subprotocol in protocol (TCP in IP) and apply subtable to the subprotocol.
TC_U32_EAT don't know exactly. It seems it influences way how offsets above are applied
to subtables. When this flag is set, base pointer of packet is changed by offset and change is
visible only to this and subsequent levels. Without the flag, offset is stored into off2 variable
and applied using tc_u32_key.offmask (WHY!??). But when you set offset later again to another
value, old value is replaced (with EAT flag, offset is permanent for current level).
Also it seems thst there is BUG in sources. In my opinion the off2 variable should be put onto
stack along with ptr and node. If not, WHY !??
if (ht->divisor)
    sel = ht->divisor&u32_hash_fold(*(u32*)(ptr+n->sel.hoff), &n->sel);
From code above I realized that divisor HAS to be value in format 2^n-1 because
sel is computed by ANDing it with hash_fold value ... Am I right ??Line 262:
static u32 gen_new_htid(struct tc_u_common *tp_c)
{
    int i = 0x800;
    do {
        if (++tp_c->hgenerator == 0x7FF)
            tp_c->hgenerator = 1;
    } while (i>0 && u32_lookup_ht(tp_c, (tp_c->hgenerator|0x800)<<20));
    return i > 0 ? (tp_c->hgenerator|0x800)<<20 : 0;
}
Variable i is used here but NEVER CHANGED ! It seems as bug ..Line 176:
     if (!(n->sel.flags&(TC_U32_VAROFFSET|TC_U32_OFFSET|TC_U32_EAT)))
            goto next_ht;
        if (n->sel.flags&(TC_U32_EAT|TC_U32_VAROFFSET)) {
            off2 = n->sel.off + 3;
            if (n->sel.flags&TC_U32_VAROFFSET)
                off2 += ntohs(n->sel.offmask & *(u16*)(ptr+n->sel.offoff)) >>n->sel.offshift;
            off2 &= ~3;
        }
        if (n->sel.flags&TC_U32_EAT) {
            ptr += off2;
            off2 = 0;
        }
When only TC_U32_OFFSET is set, value of off2 is never changed. Probably there should
be (TC_U32_OFFSET|TC_U32_VAROFFSET) instead of (TC_U32_EAT|TC_U32_VAROFFSET), right ?
In classify routine, off2 should be also pushed on stack, shouldn't ?
Martin DEVERA, devik@cdi.cz