Project 3: Network Packet Buffer / Traffic Shaper
Build a userspace packet buffer with backpressure, priority queues, and rate limits.
Quick Reference
| Attribute | Value |
|---|---|
| Difficulty | Advanced |
| Time Estimate | 1-2 weeks |
| Language | C |
| Prerequisites | C, basic networking concepts |
| Key Topics | ring buffers, backpressure, priority queues |
1. Learning Objectives
By completing this project, you will:
- Implement a lock-free ring buffer with wrap-around arithmetic.
- Apply backpressure when the buffer is full.
- Add priority queues for traffic classes.
- Implement rate limiting and basic metrics.
2. Theoretical Foundation
2.1 Core Concepts
- Ring buffers: Fixed-size circular arrays with O(1) enqueue/dequeue.
- Backpressure: Feedback that slows producers to prevent overflow.
- Priority queues: Heaps allow higher-priority traffic to jump ahead.
2.2 Why This Matters
Buffers decide whether systems are stable or collapse under load. Understanding them is core to networking.
2.3 Historical Context / Background
Most network stacks use ring buffers in NIC drivers and kernel queues for their speed and cache locality.
2.4 Common Misconceptions
- “Bigger buffers solve everything”: They increase latency and hide problems.
- “Linked lists are fine”: They are slower and less cache-friendly than arrays.
3. Project Specification
3.1 What You Will Build
A userspace traffic shaper that accepts packet-like inputs, buffers them, and outputs at a controlled rate with priority handling.
3.2 Functional Requirements
- Implement a ring buffer for packets.
- Apply backpressure when full (drop or block).
- Support at least two priority classes.
- Rate limit output using a token bucket or fixed interval.
3.3 Non-Functional Requirements
- Performance: O(1) enqueue/dequeue.
- Reliability: No buffer overrun.
- Usability: Metrics for drops and throughput.
3.4 Example Usage / Output
$ ./traffic_shaper --rate 1000 --buffer 4096
Packets in: 10000
Packets out: 9500
Drops: 500
3.5 Real World Outcome
You will inject bursts and observe smoothing and drops based on buffer capacity:
$ ./traffic_shaper --rate 1000 --buffer 4096
Packets in: 10000
Packets out: 9500
Drops: 500
4. Solution Architecture
4.1 High-Level Design
input -> enqueue ring -> scheduler -> dequeue -> rate limit -> output
4.2 Key Components
| Component | Responsibility | Key Decisions |
|---|---|---|
| Ring buffer | Store packets | Fixed-size array |
| Priority queue | Pick next packet | Heap per class |
| Rate limiter | Control output rate | Token bucket |
| Metrics | Track drops and latency | Counters |
4.3 Data Structures
typedef struct {
uint8_t *data;
size_t len;
int priority;
} packet_t;
4.4 Algorithm Overview
Key Algorithm: Enqueue/Dequeue
- If buffer full, apply backpressure policy.
- Enqueue packet with wrap-around index.
- Dequeue in priority order.
Complexity Analysis:
- Time: O(1) enqueue, O(log n) for priority selection
- Space: O(n) buffer
5. Implementation Guide
5.1 Development Environment Setup
gcc --version
5.2 Project Structure
project-root/
├── src/
│ ├── ring.c
│ ├── shaper.c
│ └── main.c
└── README.md
5.3 The Core Question You’re Answering
“How do you keep traffic stable when bursts exceed output capacity?”
5.4 Concepts You Must Understand First
Stop and research these before coding:
- Ring buffer arithmetic
- Priority queue basics
- Backpressure vs dropping
5.5 Questions to Guide Your Design
Before implementing, think through these:
- Should you drop new packets or oldest packets when full?
- How do you avoid starvation of low-priority traffic?
- How will you simulate packets for testing?
5.6 Thinking Exercise
Buffer overflow scenario
If input rate is 10x output, what should happen over 60 seconds? Sketch drop rates and latency.
5.7 The Interview Questions They’ll Ask
Prepare to answer these:
- “What is backpressure and why is it important?”
- “Why are ring buffers popular in systems code?”
- “How do you avoid starvation in priority queues?”
5.8 Hints in Layers
Hint 1: Use power-of-two sizes It simplifies modulo with bit masks.
Hint 2: Start without priority Implement FIFO first, then add priority.
Hint 3: Use token bucket Tokens accumulate at rate and allow bursts.
5.9 Books That Will Help
| Topic | Book | Chapter |
|---|---|---|
| Ring buffers | “The Linux Programming Interface” | Ch. 44 |
| Priority queues | “Algorithms” | Ch. 2.4 |
| Backpressure | “Designing Data-Intensive Applications” | Ch. 11 |
5.10 Implementation Phases
Phase 1: Foundation (3-4 days)
Goals:
- Ring buffer working for FIFO.
Tasks:
- Implement enqueue/dequeue.
- Add overflow policy.
Checkpoint: FIFO works under load.
Phase 2: Core Functionality (4-5 days)
Goals:
- Add priority queues and rate limiting.
Tasks:
- Implement priority selection.
- Add token bucket.
Checkpoint: High priority traffic passes first.
Phase 3: Polish & Edge Cases (2-3 days)
Goals:
- Add metrics and fairness tweaks.
Tasks:
- Track drops, latency, throughput.
- Add weighted priorities.
Checkpoint: Output stable across bursts.
5.11 Key Implementation Decisions
| Decision | Options | Recommendation | Rationale |
|---|---|---|---|
| Buffer overflow | drop-new vs drop-old | drop-new | Preserves FIFO order |
| Rate limit | fixed interval vs token bucket | token bucket | Handles bursts |
6. Testing Strategy
6.1 Test Categories
| Category | Purpose | Examples |
|---|---|---|
| Ring buffer | Wrap-around | Fill and drain |
| Priority | Order correctness | Mixed priorities |
| Backpressure | Full buffer | Drop counts |
6.2 Critical Test Cases
- Buffer wrap-around preserves order.
- High-priority packets are sent first.
- Drops occur when buffer full.
6.3 Test Data
Packets: 1000, priority mix
7. Common Pitfalls & Debugging
7.1 Frequent Mistakes
| Pitfall | Symptom | Solution |
|---|---|---|
| Off-by-one in ring | Data corruption | Use head/tail invariants |
| Priority starvation | Low-priority never sent | Add weights |
| Time drift | Rate unstable | Use monotonic clock |
7.2 Debugging Strategies
- Log head/tail indices on overflow.
- Add assertions for buffer size invariants.
7.3 Performance Traps
Using malloc per packet adds overhead; use a fixed pool.
8. Extensions & Challenges
8.1 Beginner Extensions
- Add CLI to switch drop policy.
- Add a stats-only mode.
8.2 Intermediate Extensions
- Add fairness (weighted round-robin).
- Add latency histogram.
8.3 Advanced Extensions
- Implement lock-free multi-producer/consumer.
- Integrate with real UDP sockets.
9. Real-World Connections
9.1 Industry Applications
- Traffic shaping in routers, proxies, and message queues.
9.2 Related Open Source Projects
- tc (Linux traffic control): https://man7.org/linux/man-pages/man8/tc.8.html
- DPDK: https://www.dpdk.org
9.3 Interview Relevance
- Backpressure and ring buffers are common systems topics.
10. Resources
10.1 Essential Reading
- Ring buffer notes in TLPI Ch. 44
- token bucket algorithm references
10.2 Video Resources
- Networking buffering talks (search “ring buffer network”)
10.3 Tools & Documentation
- clock_gettime(2) -
man 2 clock_gettime
10.4 Related Projects in This Series
- In-Memory Cache with LRU: similar queue and memory patterns.
11. Self-Assessment Checklist
11.1 Understanding
- I can explain ring buffer wrap-around.
- I can explain backpressure.
- I can describe priority queue behavior.
11.2 Implementation
- Ring buffer is correct under load.
- Priority scheduling works.
- Rate limiting behaves as expected.
11.3 Growth
- I can extend to real sockets.
- I can tune for fairness and latency.
12. Submission / Completion Criteria
Minimum Viable Completion:
- Ring buffer with backpressure and FIFO output.
Full Completion:
- Priority classes and rate limiting.
Excellence (Going Above & Beyond):
- Real network integration and weighted scheduling.
This guide was generated from SPRINT_4_5_REAL_WORLD_PROJECTS.md. For the complete learning path, see the parent directory.