Hello,

I am trying to imitate the medium access behavior in HSDPA using wired
ethernet in my research in order to see how TCP behaves under such a
MAC. What I want to do is to send packets (if there are any in the
queue) for the duration of about 2 milliseconds and then keep silent
for some time, in the order of 100milliseconds.

I managed to modify sch_tbf.c to prevent the interface from sending
packets if microseconds in the system clock is not between 3000 and
5000. These particular numbers are irrelevant, I just found it easier
to implement like this. So, for 2 milliseconds the interface can send
packets, otherwise it is silent. What I did was to read the system
time in tbf_dequeue funciton and return a NULL pointer if microseconds
didn't fall in the specified interval.

This is my first attempt to do any kernel programming, so I could
really use some advice on style and approach with this. Is it sensible
to use udelay in kernel code? Is there a more appropriate way of
programming the device to sleep for a number of milliseconds? Should I
try to implement this behavior in the network code rather than queuing
disciplines?

Also a I noticed that every time a packet is enqueued, tbf_dequeue is
called immediately, but I could not track down where exactly this was
called. Is this the expected behavior, or did I forget to set some
flags?

The modified version of tbf_dequeue function follows, only minor
changes. Thanks in advance for any help and suggestions.
Ali Özyagci


Here is the function:

static struct sk_buff *tbf_dequeue(struct Qdisc* sch)
{
        struct tbf_sched_data *q = qdisc_priv(sch);

/* Modifications to tbf_dequeue function to keep the queue silent (although
  there are backlogged packets) until the beginning of the next timeslot.
  The timeslot during which I can send packets is (3, 5) milliseconds of each
  100 milliseconds.
*/
        psched_time_t currentTime;
        PSCHED_GET_TIME(currentTime);
        int excess_usecs = currentTime.tv_usec % 100000;
        
        if ( excess_usecs  > 5000) {
        /* Missed this slot for transmission. Sleep until the beginning of
        the next 100msec interval, so do not send the packet now (therefore
        return NULL), but set the timer so we return to tbf_dequeue near the
        beginning of the next 100msec timeslot. Ideally next time tbf_dequeue
        is called, this block should not execute but the else block below should
         execute. */
                mod_timer(&q->wd_timer, jiffies+ 101 - 
(int)(excess_usecs/1000));
        /* I'm not sure if this is needed, I got to study the network code
        more. */
                sch->flags |= TCQ_F_THROTTLED;
                return NULL;
        }
        else if ( excess_usecs < 3000 ){
        /* tv_usec is less than 3000, sleep until 3000 usecs have passed into 
this
           interval. I used udelay instead of programming the watchdog because I
           didn't want to miss some microseconds in the beginning of this 
timeslot
           because of timer tick jitters.*/
                udelay(3000 - excess_usecs);
        }
        /* Here, 3000<tv_usec<5000 so proceed with transmission. I didn't make 
any
           further changes to the code.*/

        struct sk_buff *skb;

        skb = q->qdisc->dequeue(q->qdisc);

        if (skb) {
                psched_time_t now;
                long toks, delay;
                long ptoks = 0;
                unsigned int len = skb->len;

                PSCHED_GET_TIME(now);
                toks = PSCHED_TDIFF_SAFE(now, q->t_c, q->buffer);
                if (q->P_tab) {
                        ptoks = toks + q->ptokens;
                        if (ptoks > (long)q->mtu)
                                ptoks = q->mtu;
                        ptoks -= L2T_P(q, len);
                }
                toks += q->tokens;
                if (toks > (long)q->buffer)
                        toks = q->buffer;
                toks -= L2T(q, len);

                if ((toks|ptoks) >= 0) {
                        q->t_c = now;
                        q->tokens = toks;
                        q->ptokens = ptoks;
                        sch->q.qlen--;
                        sch->flags &= ~TCQ_F_THROTTLED;
                        return skb;
                }

                delay = PSCHED_US2JIFFIE(max_t(long, -toks, -ptoks));

                if (delay == 0)
                        delay = 1;

                mod_timer(&q->wd_timer, jiffies+delay);

                /* Maybe we have a shorter packet in the queue,
                   which can be sent now. It sounds cool,
                   but, however, this is wrong in principle.
                   We MUST NOT reorder packets under these circumstances.

                   Really, if we split the flow into independent
                   subflows, it would be a very good solution.
                   This is the main idea of all FQ algorithms
                   (cf. CSZ, HPFQ, HFSC)
                 */

                if (q->qdisc->ops->requeue(skb, q->qdisc) != NET_XMIT_SUCCESS) {
                        /* When requeue fails skb is dropped */
                        sch->q.qlen--;
                        sch->qstats.drops++;
                }

                sch->flags |= TCQ_F_THROTTLED;
                sch->qstats.overlimits++;
        }
        return NULL;
}
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to