Skip to content

Add NetworkLimiter with bidirectional bandwidth limiting via tc integration#4

Draft
Copilot wants to merge 10 commits intodevelopfrom
copilot/add-network-limiter
Draft

Add NetworkLimiter with bidirectional bandwidth limiting via tc integration#4
Copilot wants to merge 10 commits intodevelopfrom
copilot/add-network-limiter

Conversation

Copy link

Copilot AI commented Feb 7, 2026

Implementation Plan for NetworkLimiter - COMPLETED ✓

  • Explore the repository structure and understand existing limiter patterns
  • Create network.go file with NetworkLimiter implementation
  • Create network_test.go file with comprehensive tests
  • Update CLI to add network-related flags (--network-class-id, --network-priority)
  • Update README.md documentation to describe the new network limiter flags
  • Run tests to validate the implementation
  • Build the project to ensure no compilation errors
  • Address code review feedback
  • Run security checks (CodeQL - no vulnerabilities found)
  • Add network bandwidth limiting with tc integration
  • Address code review improvements
  • Refactor to use interface-based design (no special handling)
  • Improve error handling and cleanup logic
  • Add ingress bandwidth limiting with IFB device pattern
  • Format test code
  • Create comprehensive documentation for NetworkLimiter

Summary

Successfully implemented bidirectional network bandwidth limiting with clean interface-based design, robust error handling, and comprehensive documentation:

LifecycleLimiter interface - Optional Setup/Cleanup methods for limiters needing lifecycle management
No special handling - Executor treats all limiters uniformly through interfaces
Proper cleanup tracking - Only cleans up successfully initialized limiters
Error recovery - Cleans up on setup failure in reverse order
Input validation - Validates interface name before tc setup
Egress bandwidth limiting - Direct HTB on main interface for outgoing traffic
Ingress bandwidth limiting - IFB device redirection pattern for incoming traffic
Bidirectional control - Both egress and ingress can be limited independently
Formatted code - All test code properly formatted
Comprehensive documentation - Detailed docs/network-limiter.md file

Documentation Highlights (docs/network-limiter.md):

  • Architecture explanation for egress and ingress patterns
  • Step-by-step implementation details
  • Complete tc command references
  • Usage examples and bandwidth units
  • Requirements and limitations
  • Debugging and troubleshooting guide
  • Performance considerations

Example usage:

# Egress only (outgoing traffic)
sudo giogo --network-class-id=100 --network-max-bandwidth=1m -- your_app

# Ingress only (incoming traffic)
sudo giogo --network-class-id=100 --network-max-bandwidth-ingress=500k -- your_app

# Bidirectional (both egress and ingress)
sudo giogo --network-class-id=100 --network-max-bandwidth=1m --network-max-bandwidth-ingress=500k -- your_app
Original prompt

This section details on the original issue you should resolve

<issue_title>Missing Network Limiter</issue_title>
<issue_description>It would be great to add a new NetworkLimiter to allow users to define network limits</issue_description>

Comments on the Issue (you are @copilot in this section)


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI changed the title [WIP] Add NetworkLimiter to define network limits Add NetworkLimiter for cgroup network resource control Feb 7, 2026
Copilot AI requested a review from pmarchini February 7, 2026 01:43
Copy link
Owner

@pmarchini pmarchini left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to be able to set a defined max bandwidth

Copy link
Author

Copilot AI commented Feb 7, 2026

I want to be able to set a defined max bandwidth

I'd like to clarify the requirement. The cgroups v2 network controller doesn't directly support bandwidth limiting - it only provides classID (for packet classification) and priority settings.

Network bandwidth limiting in Linux is typically achieved through:

  1. Traffic Control (tc) using the classID we already support
  2. eBPF programs for advanced traffic shaping
  3. Other kernel mechanisms outside of cgroups

Are you looking for:

  • Integration with tc to automatically set bandwidth limits based on the classID?
  • Support for cgroup unified interface parameters (if any exist for bandwidth)?
  • A different approach?

Could you provide more details on your use case and preferred implementation approach?

Copy link
Owner

@pmarchini pmarchini left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I’m looking for is integration with Traffic Control (tc) rather than a new kernel-level bandwidth controller.
Concretely, my requirement is:
assign processes/services to a cgroup
use the cgroup’s classID / packet classification
automatically attach those packets to a tc HTB/TBF class
enforce a configurable max bandwidth (rate/ceil)
So the expected behavior would be something like:
cgroup → automatic tc class → bandwidth limit enforced

Copilot AI and others added 2 commits February 7, 2026 01:59
- Add --network-max-bandwidth flag for setting bandwidth limits
- Implement tc (traffic control) HTB setup and cleanup
- Integrate tc lifecycle management in executor
- Add comprehensive tests for bandwidth parsing
- Update README with bandwidth limiting documentation

Co-authored-by: pmarchini <[email protected]>
- Export GetDefaultInterface to avoid duplication
- Use os.Stderr for warning messages in executor
- Return cleanup errors instead of silently logging
- Remove duplicate getDefaultInterface function

Co-authored-by: pmarchini <[email protected]>
Copy link
Author

Copilot AI commented Feb 7, 2026

What I’m looking for is integration with Traffic Control (tc) rather than a new kernel-level bandwidth controller.
Concretely, my requirement is:
assign processes/services to a cgroup...

Implemented! The feature now provides automatic tc integration exactly as requested:

cgroup → automatic tc class → bandwidth limit enforced

Added in commit 5ed595e:

  • --network-max-bandwidth flag (e.g., 1m, 500k)
  • Automatic HTB qdisc setup with cgroup filter
  • Configurable rate/ceil enforcement
  • Automatic cleanup on exit

Example:

sudo giogo --network-class-id=100 --network-max-bandwidth=1m -- your_app

The implementation:

  1. Sets cgroup classID via network controller
  2. Configures tc HTB qdisc on default interface
  3. Creates cgroup filter to match packets
  4. Enforces bandwidth limit with rate=ceil
  5. Cleans up tc rules when process exits

All tests pass with no security vulnerabilities detected.

Copilot AI changed the title Add NetworkLimiter for cgroup network resource control Add NetworkLimiter with bandwidth limiting via tc integration Feb 7, 2026
Copilot AI requested a review from pmarchini February 7, 2026 02:02
Comment on lines 19 to 31
executor := &Executor{
Limiters: limiters,
}

// Extract NetworkLimiter if present for special handling
for _, l := range limiters {
if netLimiter, ok := l.(*limiter.NetworkLimiter); ok {
executor.NetworkLimiter = netLimiter
break
}
}

return executor
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not break the design having special handling here

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit 595e495. Refactored to use LifecycleLimiter interface instead of special handling:

  • Added optional LifecycleLimiter interface with Setup/Cleanup methods
  • Executor uses type assertion to check for the interface
  • No special NetworkLimiter field or hardcoded logic
  • Any limiter can implement LifecycleLimiter if needed

The design now maintains clean separation of concerns with interface-based patterns.

}

// Set up traffic control if network limiter with bandwidth is configured
if e.NetworkLimiter != nil && e.NetworkLimiter.MaxBandwidth > 0 {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit 595e495. Removed all special handling by using the LifecycleLimiter interface pattern. The executor now treats all limiters uniformly through interfaces.

Copilot AI and others added 2 commits February 7, 2026 02:09
…Limiter handling

- Add LifecycleLimiter interface with Setup/Cleanup methods
- Implement Setup/Cleanup on NetworkLimiter
- Remove special NetworkLimiter field from Executor
- Use interface-based design for lifecycle management
- Maintains clean separation of concerns

Co-authored-by: pmarchini <[email protected]>
- Track successfully setup limiters separately
- Cleanup only limiters that were successfully initialized
- Cleanup in reverse order on error
- Add interface name validation in Setup method

Co-authored-by: pmarchini <[email protected]>
pmarchini

This comment was marked as resolved.

Copy link
Owner

@pmarchini pmarchini left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want now to handle the incoming traffic too.

We can achieve it following this schema:

Redirect ingress → IFB → tc rules

- Add --network-max-bandwidth-ingress flag
- Implement setupIngressHTB with IFB device redirection
- Pattern: Redirect ingress → IFB → tc rules
- Support bidirectional bandwidth control (egress + ingress)
- Add comprehensive tests for ingress bandwidth
- Update README with ingress examples

Co-authored-by: pmarchini <[email protected]>
Copy link
Author

Copilot AI commented Feb 7, 2026

I want now to handle the incoming traffic too.

We can achieve it following this schema:...

Implemented in commit 0584d41! The ingress traffic handling now follows the IFB pattern exactly as requested:

Redirect ingress → IFB → tc rules

Added --network-max-bandwidth-ingress flag that:

  1. Loads IFB kernel module
  2. Creates IFB device (ifb-{interface})
  3. Redirects ingress traffic from main interface to IFB
  4. Applies HTB rate limiting on IFB device
  5. Automatic cleanup on exit

Example usage:

# Ingress only
sudo giogo --network-class-id=100 --network-max-bandwidth-ingress=500k -- app

# Bidirectional (egress + ingress)
sudo giogo --network-class-id=100 --network-max-bandwidth=1m --network-max-bandwidth-ingress=500k -- app

Both egress and ingress can be limited independently for full bidirectional bandwidth control.

Copilot AI changed the title Add NetworkLimiter with bandwidth limiting via tc integration Add NetworkLimiter with bidirectional bandwidth limiting via tc integration Feb 7, 2026
Copilot AI requested a review from pmarchini February 7, 2026 02:42
Comment on lines 186 to 314

// Helper function to create a pointer to uint32
func uint32Ptr(v uint32) *uint32 {
return &v
}

func TestNewNetworkLimiterWithBandwidth(t *testing.T) {
tests := []struct {
name string
init *limiter.NetworkLimiterInitializer
wantMaxBandwidth uint64
wantErr bool
}{
{
name: "valid bandwidth in kilobytes",
init: &limiter.NetworkLimiterInitializer{
ClassID: "100",
MaxBandwidth: "500k",
},
wantMaxBandwidth: 500 * 1024,
wantErr: false,
},
{
name: "valid bandwidth in megabytes",
init: &limiter.NetworkLimiterInitializer{
ClassID: "100",
MaxBandwidth: "1m",
},
wantMaxBandwidth: 1024 * 1024,
wantErr: false,
},
{
name: "valid bandwidth in gigabytes",
init: &limiter.NetworkLimiterInitializer{
ClassID: "100",
MaxBandwidth: "2g",
},
wantMaxBandwidth: 2 * 1024 * 1024 * 1024,
wantErr: false,
},
{
name: "invalid bandwidth",
init: &limiter.NetworkLimiterInitializer{
ClassID: "100",
MaxBandwidth: "invalid",
},
wantErr: true,
},
{
name: "bandwidth without classID should work",
init: &limiter.NetworkLimiterInitializer{
MaxBandwidth: "1m",
},
wantMaxBandwidth: 1024 * 1024,
wantErr: false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
netLimiter, err := limiter.NewNetworkLimiter(tt.init)
if (err != nil) != tt.wantErr {
t.Errorf("NewNetworkLimiter() error = %v, wantErr %v", err, tt.wantErr)
return
}
if tt.wantErr {
return
}

if netLimiter.MaxBandwidth != tt.wantMaxBandwidth {
t.Errorf("MaxBandwidth = %v, expected %v", netLimiter.MaxBandwidth, tt.wantMaxBandwidth)
}
})
}
}

func TestNewNetworkLimiterWithIngressBandwidth(t *testing.T) {
tests := []struct {
name string
init *limiter.NetworkLimiterInitializer
wantMaxBandwidthIngress uint64
wantErr bool
}{
{
name: "valid ingress bandwidth",
init: &limiter.NetworkLimiterInitializer{
ClassID: "100",
MaxBandwidthIngress: "1m",
},
wantMaxBandwidthIngress: 1024 * 1024,
wantErr: false,
},
{
name: "both egress and ingress",
init: &limiter.NetworkLimiterInitializer{
ClassID: "100",
MaxBandwidth: "500k",
MaxBandwidthIngress: "1m",
},
wantMaxBandwidthIngress: 1024 * 1024,
wantErr: false,
},
{
name: "invalid ingress bandwidth",
init: &limiter.NetworkLimiterInitializer{
ClassID: "100",
MaxBandwidthIngress: "invalid",
},
wantErr: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
netLimiter, err := limiter.NewNetworkLimiter(tt.init)
if (err != nil) != tt.wantErr {
t.Errorf("NewNetworkLimiter() error = %v, wantErr %v", err, tt.wantErr)
return
}
if tt.wantErr {
return
}

if netLimiter.MaxBandwidthIngress != tt.wantMaxBandwidthIngress {
t.Errorf("MaxBandwidthIngress = %v, expected %v", netLimiter.MaxBandwidthIngress, tt.wantMaxBandwidthIngress)
}
})
}
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Format this code

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Formatted in commit 0af5d28. Test tables now use proper indentation and alignment.


// setupHTB sets up HTB (Hierarchical Token Bucket) qdisc for bandwidth limiting
// It creates a root qdisc and a class with the specified rate limit
func setupHTB(interfaceName string, classID uint32, rateBytesPerSec uint64) error {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Create a separated documentation markdown file for this specific limiter in order to explain how it works (both in ingress and egress)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created in commit 0af5d28. Added docs/network-limiter.md with comprehensive documentation covering:

  • Architecture for egress and ingress patterns
  • Detailed explanations of how both work
  • tc command references
  • Usage examples and requirements
  • Implementation details and lifecycle
  • Limitations, debugging, and troubleshooting

- Format TestNewNetworkLimiterWithBandwidth and TestNewNetworkLimiterWithIngressBandwidth
- Create docs/network-limiter.md with detailed documentation
- Document egress and ingress traffic control patterns
- Include architecture, usage examples, and implementation details
- Add tc command references and troubleshooting guide

Co-authored-by: pmarchini <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Missing Network Limiter

2 participants