Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Computer Networks  Module 18 – Data centres, cloud and the full picture

QoS, queues and traffic shaping

How DiffServ marks packets with a DSCP, why queues form at the slowest link, how a token bucket polices or shapes traffic, and how schedulers share a link.

  • Advanced
  • 35 minutes
  • Examples run with Python 3.14.8 and Pyodide 314.0.7
  • By MySmartCoPilot
Free core, Pro depth: 12 of 35 minutes free
Free: Where queues form · Marking: one byte in the IP header · One token bucket, two jobs · Schedulers and queue managers, by name. With a pass: 3 in-depth parts and 3 interview answers, about 23 minutes.

What you will learn

  • Explain DSCP marking, per-hop behaviours and the DiffServ model
  • Compare policing and shaping and model both with a token bucket
  • Compare FIFO, priority, round-robin and weighted fair queueing schedulers
  • Measure how a queue manager such as CoDel or FQ-CoDel changes the delay a call sees during an upload

Before you start

What you’ll learn · Before you start

What you will learn

  • Explain DSCP marking, per-hop behaviours and the DiffServ model
  • Compare policing and shaping and model both with a token bucket
  • Compare FIFO, priority, round-robin and weighted fair queueing schedulers
  • Measure how a queue manager such as CoDel or FQ-CoDel changes the delay a call sees during an upload

Before you start

On this page

Quality of service (QoS) means giving some traffic better treatment than other traffic where they compete for the same link. It matters only where packets wait, so QoS is about queues: they form at the slowest link of a path, such as a home uplink or a busy office circuit. Three tools do the work. Marking labels each packet with a class in a 6-bit field of the IP header, the DSCP of the Differentiated Services (DiffServ) architecture. Metering with a token bucket checks a class against its rate: policing drops or re-marks the excess, and traffic shaping delays it until it fits. Scheduling decides which of several queues sends the next packet. This lesson shows where queues form, what the marks mean, runs one token bucket in both of its modes, and names the schedulers and queue managers that keep a call clear while a large upload runs.

Where queues form

A router can send only as fast as its output link. When packets arrive faster, they wait in a buffer, and the delay is simply the bytes waiting divided by the link’s rate. A home router with a 20 Mbit/s uplink and room for 500 full-size packets holds 500 × 1,500 = 750,000 bytes, or 6 megabits: a packet at the back waits 6 ÷ 20 = 0.3 seconds. A call’s packet stuck behind an upload’s full queue arrives a third of a second late, although the call needs a tiny share of the link.

Queues form only where traffic slows down. Gigabit switches in front of that uplink rarely queue at all, so a QoS policy on them changes nothing; the policy must sit where the queue builds. Buffers that are large and stay full are called bufferbloat, and the cure is to keep queues short rather than to make them longer.

Marking: one byte in the IP header

Packets are marked, metered by a token bucket, queued by class and picked by a scheduler before the slowest link.Packets arrive fasterthan the link can sendClassify and markDSCP: EF, AF41, DF ...Meter with a token bucketpolice: drop or re-mark the excessA queue per classSchedulerpicks which queue sends nextThe slowest linksends at its own rateEFcallsAF41videoDFeverything elseshaped to a rate, or as fast as the link goes

The QoS tools at one output port

Text description of the diagram

The diagram is a chain of steps, top to bottom, at the output port of a router or switch where packets arrive faster than the link can send them.

  1. Classify and mark: each packet is put in a class and its DSCP is set, for example EF for calls, AF41 for video and DF for everything else.
  2. Meter: a token bucket checks each class against its rate; policing drops or re-marks the packets that exceed it.
  3. Queue: each class waits in a queue of its own, here three queues for EF, AF41 and DF.
  4. Schedule: the scheduler picks which queue sends the next packet.
  5. Send: packets leave at the rate of the slowest link, or at a lower rate if a shaper holds them back.

DiffServ redefines the byte that IPv4 calls the TOS octet and IPv6 the Traffic Class: its first six bits carry the DSCP (RFC 2474) and the last two the ECN field, which routers use to signal congestion without dropping (RFC 3168). A DSCP selects a per-hop behaviour (PHB), the treatment each router gives the packet:

  • Default forwarding (DF), DSCP 0, is ordinary best effort.
  • Expedited Forwarding (EF), DSCP 46, asks for low delay and low loss, such as for voice (RFC 3246).
  • Assured Forwarding has four classes with three drop levels each, AF11 to AF43 (RFC 2597).
  • Class Selectors CS0 to CS7 keep the old IP precedence values working.
  • Lower Effort (LE), DSCP 1, is for traffic that should only use spare capacity (RFC 8622).

A mark is a request, not a guarantee. Each network decides whether to trust it, and many re-mark what they do not recognise to zero at their border (RFC 8100).

One token bucket, two jobs

A token bucket earns tokens at a rate r, holds at most b of them, and lets a packet pass when it can pay its size in tokens. Policing drops or re-marks a packet that finds too few tokens, so it adds no delay but loses data. Traffic shaping holds such a packet in a queue until the tokens arrive, so it loses nothing but adds delay. The program sends bursts of 30 packets every 100 ms, 3.6 Mbit/s on average, against a contract of 8 Mbit/s:

Policing and shaping the same bursts Python · token_bucket.py
"""One token bucket, two jobs: policing drops the excess, shaping delays it.

A video encoder sends a burst of 30 packets of 1,500 bytes every 100 ms, back to back at
1 Gbit/s. On average that is 3.6 Mbit/s. The contract allows 8 Mbit/s with a bucket of
15,000 bytes (10 packets). Tokens are bytes; times are whole microseconds, so the
arithmetic is exact.
"""

PACKET = 1_500
RATE = 1_000_000  # 8 Mbit/s = 1,000,000 bytes a second, so one byte of credit per microsecond
BURSTS, PER_BURST, GAP_US = 5, 30, 100_000
WIRE_US = 12  # one 1,500-byte packet at 1 Gbit/s


def arrivals():
    return [b * GAP_US + i * WIRE_US for b in range(BURSTS) for i in range(PER_BURST)]


def police(times, depth):
    """Send a packet if the bucket holds enough tokens, else drop it."""
    tokens, last, sent, dropped = depth, 0, [], 0
    for t in times:
        tokens = min(depth, tokens + (t - last) * RATE // 1_000_000)
        last = t
        if tokens >= PACKET:
            tokens -= PACKET
            sent.append(t)
        else:
            dropped += 1
    return sent, dropped


def shape(times, depth):
    """Hold each packet in a queue until the bucket holds enough tokens: nothing is dropped."""
    tokens, last, out = depth, 0, []
    for t in times:
        t = max(t, out[-1] if out else 0)  # packets leave in order
        tokens = min(depth, tokens + (t - last) * RATE // 1_000_000)
        last = t
        if tokens < PACKET:  # wait for the missing tokens
            wait = -(-(PACKET - tokens) * 1_000_000 // RATE)
            t, tokens, last = t + wait, tokens + wait * RATE // 1_000_000, t + wait
        tokens -= PACKET
        out.append(t)
    return out


def mbit(nbytes, seconds):
    return nbytes * 8 / seconds / 1e6


times = arrivals()
span = BURSTS * GAP_US / 1e6
print(f"offered: {len(times)} packets, {mbit(len(times) * PACKET, span):.1f} Mbit/s on average, "
      f"in bursts of {PER_BURST} at 1 Gbit/s")
for depth in (15_000, 45_000):
    sent, dropped = police(times, depth)
    out = shape(times, depth)
    delays = [o - t for o, t in zip(out, times)]
    print(f"bucket {depth:,} bytes ({depth // PACKET} packets), rate 8 Mbit/s:")
    print(f"  policed: {len(sent)} sent, {dropped} dropped ({dropped / len(times):.0%}), "
          f"{mbit(len(sent) * PACKET, span):.1f} Mbit/s delivered")
    print(f"  shaped:  {len(out)} sent, 0 dropped, largest delay {max(delays) / 1000:.1f} ms, "
          f"last packet of a burst leaves {(out[PER_BURST - 1] - times[0]) / 1000:.1f} ms after the first arrived")

Output

offered: 150 packets, 3.6 Mbit/s on average, in bursts of 30 at 1 Gbit/s
bucket 15,000 bytes (10 packets), rate 8 Mbit/s:
  policed: 50 sent, 100 dropped (67%), 1.2 Mbit/s delivered
  shaped:  150 sent, 0 dropped, largest delay 29.7 ms, last packet of a burst leaves 30.0 ms after the first arrived
bucket 45,000 bytes (30 packets), rate 8 Mbit/s:
  policed: 150 sent, 0 dropped (0%), 3.6 Mbit/s delivered
  shaped:  150 sent, 0 dropped, largest delay 0.0 ms, last packet of a burst leaves 0.3 ms after the first arrived

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 token_bucket.py

With a 15,000-byte bucket, the policer dropped 67 % of a stream whose average was under half the contracted rate: each burst found only ten packets’ worth of tokens. Traffic shaping delivered every packet, the last one of each burst 29.7 ms late. A bucket as large as one burst let both pass everything at once. Size the bucket for the burst, not only the rate.

Interactive model Token bucket rate limiter

Send requests one at a time or in a burst, let time pass, and change the bucket size and the refill rate. A request needs one token; without one it is rejected with 429.

At the start: The bucket holds 5 of 5 tokens and gains 1 token a second, so up to 5 requests pass at once and 1 a second keep passing after that. No requests yet.

Exercise · Medium · Python

Police and shape traffic with one token bucket

Write token_bucket(arrivals, rate, depth, mode) in bucket.py. arrivals is a list of (time_us, size) pairs in time order: when a packet arrives, in microseconds, and its size in bytes. The bucket earns rate bytes of tokens a second, holds at most depth bytes and starts full.

  • mode="police": return a list with one value per packet: True when the packet is sent (the bucket holds at least its size in tokens, which it spends) and False when it is dropped (it spends nothing).
  • mode="shape": return the time in microseconds at which each packet leaves. A packet waits until every packet before it has left and the bucket holds enough tokens; nothing is dropped. Round a waiting time up to the next whole microsecond. A packet larger than depth could never leave: raise ValueError.

Tokens accrue continuously: after t microseconds the bucket has gained t * rate / 1_000_000 bytes, never beyond depth. The starter keeps tokens multiplied by 1,000,000 so that the arithmetic stays exact with whole numbers.

With rate=1_000_000 (8 Mbit/s) and depth=3_000, three 1,500-byte packets that arrive together at time 0 are policed to [True, True, False] and shaped to [0, 0, 1500]. The five sample tests check both modes.

Starter code · bucket.py

def token_bucket(arrivals, rate, depth, mode):
    """Police (a list of True/False) or shape (departure times) packets with one token bucket.

    arrivals: (time_us, size_bytes) pairs in time order; rate: bytes a second; depth: bytes.
    """
    scale = 1_000_000              # tokens are kept in micro-bytes: whole numbers, exact arithmetic
    tokens = depth * scale         # the bucket starts full
    last = 0
    out = []
    for time_us, size in arrivals:
        # Replace these lines: add the tokens earned since `last`, then send, drop or delay the packet.
        out.append(True if mode == "police" else time_us)
    return out
The sample tests · test_bucket.py
from bucket import token_bucket

R = 1_000_000  # bytes a second: one byte of tokens per microsecond


def test_police_a_burst():
    """sends what the full bucket covers and drops the rest of a burst"""
    burst = [(0, 1_500)] * 5
    assert token_bucket(burst, R, 3_000, "police") == [True, True, False, False, False]
    assert token_bucket(burst, R, 7_500, "police") == [True] * 5


def test_police_refills_over_time():
    """earns rate bytes a second, never more than the depth"""
    pkts = [(0, 1_500), (0, 1_500), (1_499, 1_500), (1_500, 1_500), (100_000, 1_500), (100_000, 1_500), (100_000, 1_500)]
    assert token_bucket(pkts, R, 3_000, "police") == [True, True, False, True, True, True, False]


def test_police_spends_nothing_on_a_drop():
    """a dropped packet leaves the tokens for the next one"""
    pkts = [(0, 1_000), (0, 1_500), (0, 1_000)]
    assert token_bucket(pkts, R, 2_000, "police") == [True, False, True]


def test_shape_delays_instead_of_dropping():
    """holds packets until the tokens are there, in order, rounding waits up"""
    burst = [(0, 1_500)] * 4
    assert token_bucket(burst, R, 3_000, "shape") == [0, 0, 1_500, 3_000]
    slow = [(0, 1_000), (0, 1_000), (10, 1_000)]
    assert token_bucket(slow, 3_000, 1_000, "shape") == [0, 333_334, 666_668]
    small_behind_big = [(0, 1_500), (0, 1_500), (100, 100)]  # the small packet must wait its turn
    assert token_bucket(small_behind_big, R, 1_500, "shape") == [0, 1_500, 1_600]


def test_shape_conforming_traffic_and_oversized_packets():
    """does not delay traffic within the rate, and refuses a packet larger than the bucket"""
    steady = [(i * 2_000, 1_500) for i in range(5)]
    assert token_bucket(steady, R, 1_500, "shape") == [0, 2_000, 4_000, 6_000, 8_000]
    try:
        token_bucket([(0, 9_000)], R, 1_500, "shape")
    except ValueError:
        pass
    else:
        raise AssertionError("a 9,000-byte packet can never fit a 1,500-byte bucket")
A hint

Keep two variables: the tokens in micro-bytes and the time you last updated them. For each packet, first add (now - last) * rate micro-bytes, capped at depth * 1_000_000. In shape mode, now is the later of the arrival and the previous departure; if the tokens are short, the wait is the missing micro-bytes divided by rate, rounded up with -(-a // b).

The sample tests run on this device, in your browser (Pyodide): nothing is sent to mysmartcopilot.com. The first run downloads Python (about 13.5 MB), which is kept for the next runs. A check in your browser is feedback for you, not proof that the code is right for every input.

Schedulers and queue managers, by name

  • FIFO keeps one queue and sends packets in the order they arrived.
  • Strict priority always empties the higher-priority queues first.
  • Round robin lets the queues take turns; deficit round robin (DRR) counts bytes, so large packets earn no extra share.
  • Weighted fair queueing (WFQ) sends packets in the order a bit-by-bit weighted share of the link would finish them.
  • RED drops packets at random as the average queue length grows, before the buffer is full.
  • CoDel drops when packets have waited longer than a target time for a while.
  • FQ-CoDel gives each flow a queue of its own, served by DRR, and runs CoDel in each (RFC 8290).
Internet Speed Test Measure your line's speed and its latency while it is busy: a large rise under load is a bloated queue.

Check yourself

5 questions about this lesson. Every answer and why it is right is on the page, behind “Show the answer”. Your score stays in this browser.

  1. Question 1 of 5 An office has gigabit switches and a 20 Mbit/s uplink to its ISP. Calls break up when people upload files. Where does a QoS policy have to act?

    Choose one answer.

    Show the answer to question 1

    Answer: Where traffic leaves for the 20 Mbit/s uplink, because that is where the queue forms

    Packets wait only where they arrive faster than a link can send them, here at the uplink. Gigabit switch ports rarely queue, so a policy there changes nothing, and marks set by every laptop cannot be trusted.

  2. Question 2 of 5 A router's queue holds 500 packets of 1,500 bytes in front of a 20 Mbit/s link. How many milliseconds does a packet at the back of the queue wait?

    Type a number.

    Show the answer to question 2

    Answer: 300 ms (anything from 299 to 301 counts)

    500 × 1,500 bytes is 750,000 bytes, or 6,000,000 bits. At 20,000,000 bits a second, sending them takes 0.3 seconds, 300 ms.

  3. Question 3 of 5 Which token-bucket mode never drops a packet for exceeding the rate, but may delay it?

    Choose one answer.

    Show the answer to question 3

    Answer: Shaping

    A shaper holds a packet in a queue until the bucket has enough tokens, so it adds delay instead of loss (until its own queue fills). A policer drops or re-marks the packet at once.

  4. Question 4 of 5 Which DSCP value does Expedited Forwarding use, the class meant for voice?

    Choose one answer.

    Show the answer to question 4

    Answer: 46

    RFC 3246 recommends codepoint 101110, which is 46. 0 is default forwarding (best effort), 34 is AF41 and 1 is Lower Effort.

  5. Question 5 of 5 Which of these manage a queue by dropping or marking packets before the buffer is full?

    Choose every answer that is right.

    Show the answer to question 5

    Answer:

    • CoDel
    • FQ-CoDel
    • RED

    RED drops as the average queue grows, CoDel when packets wait longer than its target, and FQ-CoDel runs CoDel in a queue per flow. Strict priority only chooses which queue sends; tail drop waits until the buffer is full.

Four schedulers on one link, run and measured Pro: opens with a Pro, Premium or Ultimate pass

A scheduler decides who waits. This part runs FIFO, strict priority and deficit round robin on the same link with a call, a video stream and an upload, then breaks priority on purpose with a misbehaving source.

In this part:

  • Three flows on a 10 Mbit/s link, run four ways
  • Starvation reproduced, and the two ways out
  • How fair sharing is computed, with worked numbers

1 runnable example (Python) · about 3 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Marks that survive the path: DSCP plans, trust and Wi-Fi Pro: opens with a Pro, Premium or Ultimate pass

A mark helps only where a device trusts it and maps it to the right queue. This part lists the classes the standards recommend, shows the byte an application sets, what Wi-Fi does with the mark, and how a border’s re-marking can erase a congestion signal.

In this part:

  • A DSCP plan from RFC 4594, and the byte an application sets
  • Wi-Fi turns six bits into eight priorities, sometimes wrongly
  • Trust boundaries, and what a border does to marks
  • Sizing the priority class for calls, with worked numbers

1 runnable example (Python) · about 3 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Owning the queue: shaping below the bottleneck and AQM, measured Pro: opens with a Pro, Premium or Ultimate pass

Marks and schedulers work only where your device holds the queue. This part reproduces bufferbloat with an upload and a call, shows why shaping a little below the slowest link moves the queue to a device you control, and how CoDel and FQ-CoDel keep it short.

In this part:

  • Bufferbloat reproduced: an upload and a call on 20 Mbit/s
  • Why shaping to 95 % moves the queue, with worked numbers
  • How CoDel decides when to drop

1 runnable example (Python) · about 3 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Interview questions

  1. Fresher to mid · Warm-up

    What is the difference between traffic policing and traffic shaping?

    Both measure traffic against a rate with a token bucket, which earns tokens at the agreed rate and holds at most a set burst. They differ in what happens to a packet that finds too few tokens. A policer drops it, or re-marks it to a lower class, at once: it adds no delay, but bursts larger than the bucket are lost, and TCP reacts to those losses by slowing down. A shaper holds the packet in a queue until enough tokens have arrived: nothing is lost while its queue has room, but packets wait, and the output leaves smoothly at the agreed rate. Providers often police at their edge to enforce a contract, and customers shape slightly below that rate on their side, so that the provider's policer has nothing to drop.

  2. Fresher to mid

    A home office has a connection of 100 Mbit/s down and 20 Mbit/s up. Video calls break up whenever a large file is uploading, although a call needs about 3 Mbit/s. Explain why, and say what you would change on the router.

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  3. Mid to senior

    After video conferencing was given a strict-priority queue on a 50 Mbit/s branch link, nightly backups and some daytime file transfers began to fail during company-wide meetings. Why, and how would you configure the link instead?

    Model answer, Pro. First step and follow-ups

  4. Mid to senior

    Calls between two offices are marked EF on the LAN, but captures at the far office show DSCP 0, and the calls are choppy only when the WAN link is busy. Where can the marks be lost, and what would you do?

    Model answer, Pro. First step and follow-ups

Key takeaways

  • QoS only acts where a queue forms, usually at the slowest link; the delay there is the bytes waiting divided by the link’s rate.
  • DiffServ marks packets with a 6-bit DSCP: DF 0 for best effort, EF 46 for low delay, AF11 to AF43 for assured classes, LE 1 for spare capacity. Each network decides whether to trust a mark.
  • A token bucket with rate r and depth b polices by dropping or re-marking the excess and shapes by delaying it; a bucket smaller than the bursts drops traffic even when the average rate is low.
  • Schedulers decide who waits: FIFO, strict priority, round robin and DRR, and WFQ; queue managers such as RED, CoDel and FQ-CoDel keep the queue itself short.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.