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