Skip to content

Commit

Permalink
Traffic control for Eden-SDN (lf-edge#880)
Browse files Browse the repository at this point in the history
With this patch, Eden-SDN now allows to apply traffic control
individually for every network port. This can be used to model
poor network connectivity and observe how EVE is able to deal
with such challenging conditions.

Signed-off-by: Milan Lenco <milan@zededa.com>
  • Loading branch information
milan-zededa authored Aug 30, 2023
1 parent 4f562e4 commit 0187c3c
Show file tree
Hide file tree
Showing 10 changed files with 453 additions and 1 deletion.
24 changes: 24 additions & 0 deletions sdn/examples/poor-network/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# SDN Example with emulated poor network connectivity

Eden-SDN Network Model allows to configure traffic control individually for every network port.
Included is traffic shaping, i.e. limiting traffic to meet but not exceed a configured rate,
and emulating network impairments, such as packet delay, loss, corruption, reordering, etc.
This can be used to simulate poor network connectivity and observe how EVE is able to deal
with such challenging conditions.

In this example, traffic control parameters are set for the single and only network interface.
The intention is to model rather poor network connection with a low bandwidth and a high
percentage of packet loss or corruption. For the purposes of the showcase, we set every
available traffic control attribute to a specific non-default value.

Run the example with:

```shell
make clean && make build-tests
./eden config add default
./eden config set default --key sdn.disable --value false
./eden setup
./eden start --sdn-network-model $(pwd)/sdn/examples/poor-network/network-model.json
./eden eve onboard
./eden controller edge-node set-config --file $(pwd)/sdn/examples/poor-network/device-config.json
```
67 changes: 67 additions & 0 deletions sdn/examples/poor-network/device-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
{
"deviceIoList": [
{
"ptype": 1,
"phylabel": "eth0",
"phyaddrs": {
"Ifname": "eth0"
},
"logicallabel": "eth0",
"assigngrp": "eth0",
"usage": 1,
"usagePolicy": {
"freeUplink": true
}
}
],
"networks": [
{
"id": "6605d17b-3273-4108-8e6e-4965441ebe01",
"type": 4,
"ip": {
"dhcp": 4
}
}
],
"systemAdapterList": [
{
"name": "eth0",
"uplink": true,
"networkUUID": "6605d17b-3273-4108-8e6e-4965441ebe01"
}
],
"configItems": [
{
"key": "network.fallback.any.eth",
"value": "disabled"
},
{
"key": "newlog.allow.fastupload",
"value": "true"
},
{
"key": "timer.config.interval",
"value": "10"
},
{
"key": "timer.location.app.interval",
"value": "10"
},
{
"key": "timer.location.cloud.interval",
"value": "300"
},
{
"key": "app.allow.vnc",
"value": "true"
},
{
"key": "timer.download.retry",
"value": "60"
},
{
"key": "debug.default.loglevel",
"value": "debug"
}
]
}
66 changes: 66 additions & 0 deletions sdn/examples/poor-network/network-model.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
{
"ports": [
{
"logicalLabel": "eveport0",
"adminUP": true,
"trafficControl": {
"delay": 250,
"delayJitter": 50,
"lossProbability": 20,
"corruptProbability": 5,
"duplicateProbability": 10,
"reorderProbability": 30,
"rateLimit": 512,
"queueLimit": 1024,
"burstLimit": 64
}
}
],
"bridges": [
{
"logicalLabel": "bridge0",
"ports": ["eveport0"]
}
],
"networks": [
{
"logicalLabel": "network0",
"bridge": "bridge0",
"subnet": "172.22.12.0/24",
"gwIP": "172.22.12.1",
"dhcp": {
"enable": true,
"ipRange": {
"fromIP": "172.22.12.10",
"toIP": "172.22.12.20"
},
"domainName": "sdn",
"privateDNS": ["my-dns-server"]
},
"router": {
"outsideReachability": true,
"reachableEndpoints": ["my-dns-server"]
}
}
],
"endpoints": {
"dnsServers": [
{
"logicalLabel": "my-dns-server",
"fqdn": "my-dns-server.sdn",
"subnet": "10.16.16.0/24",
"ip": "10.16.16.25",
"staticEntries": [
{
"fqdn": "mydomain.adam",
"ip": "adam-ip"
}
],
"upstreamServers": [
"1.1.1.1",
"8.8.8.8"
]
}
]
}
}
33 changes: 33 additions & 0 deletions sdn/vm/api/netModel.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,39 @@ type Port struct {
AdminUP bool `json:"adminUP"`
// EVEConnect : plug the other side of the port into a given EVE instance.
EVEConnect EVEConnect `json:"eveConnect"`
// TC : traffic control.
TC TrafficControl `json:"trafficControl"`
}

// TrafficControl allows to control traffic going through a port.
// It can be used to emulate slow and faulty networks.
type TrafficControl struct {
// Delay refers to the duration, measured in milliseconds, by which each packet
// will be delayed.
Delay uint32 `json:"delay"`
// DelayJitter : jitter in milliseconds added to the delay.
DelayJitter uint32 `json:"delayJitter"`
// LossProbability : probability of a packet loss (in percent).
LossProbability uint8 `json:"lossProbability"`
// CorruptProbability : probability of a packet corruption (in percent).
CorruptProbability uint8 `json:"corruptProbability"`
// DuplicateProbability : probability of a packet duplication (in percent).
DuplicateProbability uint8 `json:"duplicateProbability"`
// ReorderProbability represents the percentage probability of a packet's order
// being modified within the queue.
ReorderProbability uint8 `json:"reorderProbability"`
// RateLimit represents the maximum speed, measured in kilobytes per second,
// at which traffic can flow through the port.
RateLimit uint32 `json:"rateLimit"`
// QueueLimit : number of kilobytes that can be queued before being sent further.
// Packets that would exceed the queue size are dropped.
// Mandatory if RateLimit is set.
QueueLimit uint32 `json:"queueLimit"`
// BurstLimit represents the maximum amount of data, measured in kilobytes,
// that can be sent or received in a short burst or interval, temporarily exceeding
// the rate limit.
// Mandatory if RateLimit is set.
BurstLimit uint32 `json:"burstLimit"`
}

// ItemType
Expand Down
23 changes: 23 additions & 0 deletions sdn/vm/cmd/sdnagent/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const (
// *SG are names of sub-graphs.
configGraphName = "SDN-Config"
physicalIfsSG = "Physical-Interfaces"
trafficControlSG = "Traffic-Control"
hostConnectivitySG = "Host-Connectivity"
bridgesSG = "Bridges"
firewallSG = "Firewall"
Expand Down Expand Up @@ -92,6 +93,7 @@ func (a *agent) updateIntendedState() {
a.intendedState = dg.New(graphArgs)
a.intendedState.PutSubGraph(a.getIntendedPhysIfs())
a.intendedState.PutSubGraph(a.getIntendedHostConnectivity())
a.intendedState.PutSubGraph(a.getIntendedTrafficControl())
a.intendedState.PutSubGraph(a.getIntendedBridges())
a.intendedState.PutSubGraph(a.getIntendedFirewall())
for _, network := range a.netModel.Networks {
Expand Down Expand Up @@ -183,6 +185,27 @@ func (a *agent) getIntendedHostConnectivity() dg.Graph {
return intendedCfg
}

func (a *agent) getIntendedTrafficControl() dg.Graph {
graphArgs := dg.InitArgs{Name: trafficControlSG}
intendedCfg := dg.New(graphArgs)
emptyTC := api.TrafficControl{}
for _, port := range a.netModel.Ports {
if port.TC == emptyTC {
continue
}
// MAC address is already validated
mac, _ := net.ParseMAC(port.MAC)
intendedCfg.PutItem(configitems.TrafficControl{
TrafficControl: port.TC,
PhysIf: configitems.PhysIf{
LogicalLabel: port.LogicalLabel,
MAC: mac,
},
}, nil)
}
return intendedCfg
}

func (a *agent) getIntendedBridges() dg.Graph {
graphArgs := dg.InitArgs{Name: bridgesSG}
intendedCfg := dg.New(graphArgs)
Expand Down
16 changes: 16 additions & 0 deletions sdn/vm/cmd/sdnagent/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,22 @@ func (a *agent) validatePorts(netModel *parsedNetModel) (err error) {
return
}
}

// QueueLimit and BurstLimit are mandatory when RateLimit is set.
for _, port := range netModel.Ports {
if port.TC.RateLimit != 0 {
if port.TC.QueueLimit == 0 {
err = fmt.Errorf("RateLimit set for port %s without QueueLimit",
port.LogicalLabel)
return
}
if port.TC.BurstLimit == 0 {
err = fmt.Errorf("RateLimit set for port %s without BurstLimit",
port.LogicalLabel)
return
}
}
}
return nil
}

Expand Down
2 changes: 1 addition & 1 deletion sdn/vm/pkg/configitems/ifHandle.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ package configitems
import (
"context"
"fmt"
"github.com/lf-edge/eden/sdn/vm/pkg/maclookup"
"net"

"github.com/lf-edge/eden/sdn/vm/pkg/maclookup"
"github.com/lf-edge/eve/libs/depgraph"
log "github.com/sirupsen/logrus"
"github.com/vishvananda/netlink"
Expand Down
1 change: 1 addition & 0 deletions sdn/vm/pkg/configitems/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ func RegisterItems(
{c: &IptablesChainConfigurator{}, t: IP6tablesChainTypename},
{c: &HttpProxyConfigurator{}, t: HTTPProxyTypename},
{c: &HttpServerConfigurator{}, t: HTTPServerTypename},
{c: &TrafficControlConfigurator{MacLookup: macLookup}, t: TrafficControlTypename},
}
for _, configurator := range configurators {
err := registry.Register(configurator.c, configurator.t)
Expand Down
Loading

0 comments on commit 0187c3c

Please sign in to comment.