Hi All,

I've hit a road block that I'm hoping people with better C/macro fu can help me with. It also may be the case that what I'm trying to do can't be done, so I welcome alternative suggestions as well.

The problem:

I'm working on a KPI to modularise congestion control support in the kernel (overview of KPI is visible in [1]). So far, I've been focused solely on TCP, but I want to have the framework generalise to be able to share congestion control algorithms between other congestion aware transports e.g. SCTP, DCCP.

To achieve this, I need to pass congestion control information into the hook functions in a protocol agnostic way. The current KPI passes the tcpcb ptr and this works nicely, but obviously doesn't help.

The cleanest option as I see it is to embed a new CC specific struct in the appropriate TCP and SCTP structs, and pass this in to the KPI. I started down this road and quickly stopped - the amount of code churn this will cause in the TCP and SCTP stacks is to my mind far to intrusive, at least for an initial import of the framework.

So the next idea I've been trying to prototype was to pass a union of the various protocol struct types into the KPI and then use macro magic to allow the CC algorithms to access commonly named variables across the different transport struct types. It would require vars to have the same name, which would still mean some code churn, but less than the first option. Here are the basic bits I'm currently working with:

struct cc_var {
        uint16_t type;
        union {
                struct tcpcb *tcp;
                struct sctp_nets *sctp;
        } ccvc;
};

All function ptrs in struct cc_algo [1] are modified to accept a "struct cc_var *ccv".

In an algorithm implementation e.g. NewReno [2], I then want to be able to do things like this with the fictitious CCVC() macro:

void
newreno_ack_received(struct cc_var *ccv)
{
        u_int cw = CCVC(ccv)->snd_cwnd;
        ...
        CCVC(ccv)->snd_cwnd = blah;
}


So far I haven't found a way to achieve the above, and the best I've come up (with help) is this:

#define CCV_DO(ccv, what) \
( \
        (ccv)->type == IPPROTO_TCP ?    (ccv)->ccvc.tcp->what : \
                                        (ccv)->ccvc.sctp->what \
)

which can be used like this:

void
newreno_ack_received(struct cc_var *ccv)
{
        u_int cw = CCV_DO(ccv, snd_cwnd);
        ...
        CCVC(ccv, snd_cwnd = blah);
}

Of course, this falls apart if you try do this for example:

        CCVC(ccv, snd_cwnd = min(blah, bleh));


So... I'm sure there are some good ideas out there and would really appreciate hearing about them.


Cheers,
Lawrence

PS: Cookie will only be awarded after complete working solution has been demonstrated and verified in my development branch!


[1] http://svn.freebsd.org/viewvc/base/projects/tcp_cc_head/sys/netinet/cc.h?view=markup

[2] http://svn.freebsd.org/viewvc/base/projects/tcp_cc_head/sys/netinet/cc_newreno.c?view=markup
_______________________________________________
freebsd-hackers@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-hackers
To unsubscribe, send any mail to "freebsd-hackers-unsubscr...@freebsd.org"

Reply via email to