This article looks takes the DDoS example and repeats it using the OpenDaylight controller.
First install Open Daylight in the Mininet testbed.
The following sFlow-RT script modified the original to use the OpenDaylight Flow Programmer REST API to push OpenFlow rules to the switch.
When the controller is disabled, the attack traffic exceeds 6,000 packets per second and persists until the attacker stops sending. When the controller is enabled, traffic is stopped the instant it hits the 1,000 packet per second threshold in the application. The control is removed 20 seconds later and re-triggers if the attacker is still sending traffic.
DDoS mitigation is only one use case for large flow control, others described on this blog include: ECMP / LAG load balancing, traffic marking and packet capture. This script can be modified to address these different use cases. The Mininet test bed provides a useful way to test OpenFlow control schemes before moving them into production using physical switches.
First install Open Daylight in the Mininet testbed.
$ wget https://jenkins.opendaylight.org/controller/job/controller-merge/lastSuccessfulBuild/artifact/opendaylight/distribution/opendaylight/target/distribution.opendaylight-osgipackage.zipNext start Mininet.
unzip distribution.opendaylight-osgipackage.zip
sudo mn --topo single,3 --controller=remote,ip=127.0.0.1Enable sFlow on the switch:
sudo ovs-vsctl -- --id=@sflow create sflow agent=eth0 target=\"127.0.0.1:6343\" sampling=10 polling=20 -- -- set bridge s1 sflow=@sflowStart OpenDaylight.
cd opendaylightConfirm that the controller is running and has discovered the switch by connecting a browser to port 8080 on the testbed - the screen shot at the start of the article shows the OpenDaylight Devices tab with the switch 00:00:00:00:00:00:00:01 shown in the Nodes Learned list and in the map (the default credentials to log into the OpenDaylight interface are User:admin, Password:admin).
./run.sh
The following sFlow-RT script modified the original to use the OpenDaylight Flow Programmer REST API to push OpenFlow rules to the switch.
include('extras/json2.js');The following command line argument loads the script on startup:
var flowkeys = 'ipsource';
var value = 'frames';
var filter = 'outputifindex!=discard&direction=ingress&sourcegroup=external';
var threshold = 1000;
var groups = {'external':['0.0.0.0/0'],'internal':['10.0.0.2/32']};
var metricName = 'ddos';
var controls = {};
var enabled = true;
var blockSeconds = 20;
var ruleid = 0;
var flowprogrammer = 'http://127.0.0.1:8080/controller/nb/v2/flowprogrammer/default/node/OF/';
var user = 'admin';
var password = 'admin';
var bridge = '00:00:00:00:00:00:00:01';
function setOpenFlow(bridge,name,spec) {
http(flowprogrammer+bridge+'/staticFlow/'+name,'put','application/json',
JSON.stringify(spec),user,password);
}
function deleteOpenFlow(bridge,name) {
http(flowprogrammer+bridge+'/staticFlow/'+name,'delete','application/json',
null,user,password);
}
function block(address) {
if(!controls[address]) {
var name = 'block' + ruleid++;
setOpenFlow(bridge,name,{installInHw:true,name:name,
node:{id:bridge, type:'OF'},
priority:'11', etherType:'0x0800',
nwSrc: address, actions:['DROP']});
controls[address] = { name: name, action:'block',
time: (new Date()).getTime() };
}
}
function allow(address) {
if(controls[address]) {
deleteOpenFlow(bridge,controls[address].name);
delete controls[address];
}
}
setEventHandler(function(evt) {
if(!enabled) return;
var addr = evt.flowKey;
block(addr);
},[metricName]);
setIntervalHandler(function() {
// remove stale controls
var stale = [];
var now = (new Date()).getTime();
var threshMs = 1000 * blockSeconds;
for(var addr in controls) {
if((now - controls[addr].time) > threshMs) stale.push(addr);
}
for(var i = 0; i < stale.length; i++) allow(stale[i]);
},10);
setHttpHandler(function(request) {
var result = {};
try {
var action = '' + request.query.action;
switch(action) {
case 'block':
var address = request.query.address[0];
if(address) block(address);
break;
case 'allow':
var address = request.query.address[0];
if(address) allow(address);
break;
case 'enable':
enabled = true;
break;
case 'disable':
enabled = false;
break;
}
}
catch(e) { result.error = e.message }
result.controls = controls;
result.enabled = enabled;
return JSON.stringify(result);
});
setGroups(groups);
setFlow(metricName,{keys:flowkeys,value:value,filter:filter});
setThreshold(metricName,{metric:metricName,value:threshold,byFlow:true,timeout:5});
-D file.script=odl.jsRepeating the simulated denial of service attack without the controller active and with the controller active shows the same results demonstrated in the previous article:
When the controller is disabled, the attack traffic exceeds 6,000 packets per second and persists until the attacker stops sending. When the controller is enabled, traffic is stopped the instant it hits the 1,000 packet per second threshold in the application. The control is removed 20 seconds later and re-triggers if the attacker is still sending traffic.
DDoS mitigation is only one use case for large flow control, others described on this blog include: ECMP / LAG load balancing, traffic marking and packet capture. This script can be modified to address these different use cases. The Mininet test bed provides a useful way to test OpenFlow control schemes before moving them into production using physical switches.