Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Traffic control for Eden-SDN #880

Merged
merged 1 commit into from
Aug 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@
// *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 @@
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 All @@ -113,7 +115,7 @@
a.intendedState.PutSubGraph(a.getIntendedHttpSrvEp(httpSrv))
}

// TODO (ntp servers, netboot servers)

Check failure on line 118 in sdn/vm/cmd/sdnagent/config.go

View workflow job for this annotation

GitHub Actions / yetus

golangcilint: cmd/sdnagent/config.go:118: Line contains TODO/BUG/FIXME: "TODO (ntp servers, netboot servers)" (godox)
}

func (a *agent) getIntendedPhysIfs() dg.Graph {
Expand Down Expand Up @@ -183,6 +185,27 @@
return intendedCfg
}

func (a *agent) getIntendedTrafficControl() dg.Graph {

Check failure on line 188 in sdn/vm/cmd/sdnagent/config.go

View workflow job for this annotation

GitHub Actions / yetus

golangcilint: getIntendedTrafficControl returns interface (github.com/lf-edge/eve/libs/depgraph.Graph) (ireturn)
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 @@ -84,7 +84,7 @@
return
}

func (a *agent) validatePorts(netModel *parsedNetModel) (err error) {

Check failure on line 87 in sdn/vm/cmd/sdnagent/parse.go

View workflow job for this annotation

GitHub Actions / yetus

golangcilint: calculated cyclomatic complexity for function validatePorts is 12, max is 10 (cyclop)
// Every port should have a valid and unique MAC address.
macs := make(map[string]struct{})
for _, port := range netModel.Ports {
Expand Down Expand Up @@ -120,6 +120,22 @@
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 Expand Up @@ -206,12 +222,12 @@
}
}

// TODO: check that within a network it is IPv4 or IPv6, not both (for now)

Check failure on line 225 in sdn/vm/cmd/sdnagent/parse.go

View workflow job for this annotation

GitHub Actions / yetus

golangcilint: cmd/sdnagent/parse.go:225: Line contains TODO/BUG/FIXME: "TODO: check that within a network it is ..." (godox)
return nil
}

func (a *agent) validateEndpoints(netModel *parsedNetModel) (err error) {
// TODO

Check failure on line 230 in sdn/vm/cmd/sdnagent/parse.go

View workflow job for this annotation

GitHub Actions / yetus

golangcilint: cmd/sdnagent/parse.go:230: Line contains TODO/BUG/FIXME: "TODO" (godox)
// - NetbootArtifacts:
// - exactly one is entrypoint, Filename and URL are non-empty
for _, client := range netModel.Endpoints.Clients {
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
Loading