SDN开发之基于floodlight控制器做QoS策略

---温州大学 12网络工程

在floodlight中写主要策略。通过python脚本与ubuntu console界面交互

利用floodlight提供的restAPI开发webUI界面

JAVA部分代码:

package net.floodlightcontroller.qos;

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.IOException;

import java.util.Collection;

import java.util.Collections;

import java.util.HashMap;

import java.util.Iterator;

import java.util.List;

import java.util.Map;

import java.util.Properties;

import org.openflow.protocol.OFFlowMod;

import org.openflow.protocol.OFMatch;

import org.openflow.protocol.OFMessage;

import org.openflow.protocol.OFPacketOut;

import org.openflow.protocol.OFPort;

import org.openflow.protocol.OFType;

import org.openflow.protocol.action.OFAction;

import org.openflow.protocol.action.OFActionEnqueue;

import org.openflow.protocol.action.OFActionNetworkTypeOfService;

import org.openflow.protocol.action.OFActionType;

import org.openflow.util.HexString;

import net.floodlightcontroller.core.FloodlightContext;

import net.floodlightcontroller.core.IOFMessageListener;

import net.floodlightcontroller.core.IOFSwitch;

import net.floodlightcontroller.core.module.FloodlightModuleContext;

import net.floodlightcontroller.core.module.FloodlightModuleException;

import net.floodlightcontroller.core.module.IFloodlightModule;

import net.floodlightcontroller.core.module.IFloodlightService;

import net.floodlightcontroller.restserver.IRestApiService;

import net.floodlightcontroller.staticflowentry.IStaticFlowEntryPusherService;

import net.floodlightcontroller.storage.IResultSet;

import net.floodlightcontroller.storage.IStorageSourceService;

import net.floodlightcontroller.storage.StorageException;

import net.floodlightcontroller.qos.QoSPolicy;

import net.floodlightcontroller.qos.QoSTypeOfService;

import net.floodlightcontroller.core.IFloodlightProviderService;

import java.util.ArrayList;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

public class QoS implements IQoSService, IFloodlightModule,

IOFMessageListener {

protected IFloodlightProviderService floodlightProvider;

protected IStaticFlowEntryPusherService flowPusher;

protected List<QoSPolicy> policies; //Synchronized

protected List<QoSTypeOfService> services; //Synchronized

protected IRestApiService restApi;

protected FloodlightContext cntx;

protected IStorageSourceService storageSource;

protected Properties props = new Properties();

protected String[] tools;

protected static Logger logger;

protected boolean enabled;

protected String dpidPattern = "^[\\d|\\D][\\d|\\D]:[\\d|\\D][\\d|\\D]:" +

"[\\d|\\D][\\d|\\D]:[\\d|\\D][\\d|\\D]:" +

"[\\d|\\D][\\d|\\D]:[\\d|\\D][\\d|\\D]:" +

"[\\d|\\D][\\d|\\D]:[\\d|\\D][\\d|\\D]$";

public static final String TABLE_NAME = "controller_qos";

public static final String COLUMN_POLID = "policyid";

public static final String COLUMN_NAME = "name";

public static final String COLUMN_MATCH_PROTOCOL = "protocol";

public static final String COLUMN_MATCH_ETHTYPE = "eth-type";

public static final String COLUMN_MATCH_INGRESSPRT = "ingressport";

public static final String COLUMN_MATCH_IPDST = "ipdst";

public static final String COLUMN_MATCH_IPSRC = "ipsrc";

public static final String COLUMN_MATCH_VLANID = "vlanid";

public static final String COLUMN_MATCH_ETHSRC = "ethsrc";

public static final String COLUMN_MATCH_ETHDST = "ethdst";

public static final String COLUMN_MATCH_TCPUDP_SRCPRT = "tcpudpsrcport";

public static final String COLUMN_MATCH_TCPUDP_DSTPRT = "tcpudpdstport";

public static final String COLUMN_NW_TOS = "nw_tos";

public static final String COLUMN_SW = "switches";

public static final String COLUMN_QUEUE = "queue";

public static final String COLUMN_ENQPORT = "equeueport";

public static final String COLUMN_PRIORITY = "priority";

public static final String COLUMN_SERVICE = "service";

public static String ColumnNames[] = { COLUMN_POLID,

COLUMN_NAME,COLUMN_MATCH_PROTOCOL, COLUMN_MATCH_ETHTYPE,COLUMN_MATCH_INGRESSPRT,

COLUMN_MATCH_IPDST,COLUMN_MATCH_IPSRC,COLUMN_MATCH_VLANID,

COLUMN_MATCH_ETHSRC,COLUMN_MATCH_ETHDST,COLUMN_MATCH_TCPUDP_SRCPRT,

COLUMN_MATCH_TCPUDP_DSTPRT,COLUMN_NW_TOS,COLUMN_SW,

COLUMN_QUEUE,COLUMN_ENQPORT,COLUMN_PRIORITY,COLUMN_SERVICE,};

public static final String TOS_TABLE_NAME = "controller_qos_tos";

public static final String COLUMN_SID = "serviceid";

public static final String COLUMN_SNAME = "servicename";

public static final String COLUMN_TOSBITS = "tosbits";

public static String TOSColumnNames[] = {COLUMN_SID,

COLUMN_SNAME,

COLUMN_TOSBITS};

@Override

public String getName() {

return "qos";

}

@Override

public boolean isCallbackOrderingPrereq(OFType type, String name) {

return false;

}

@Override

public boolean isCallbackOrderingPostreq(OFType type, String name) {

return false;

}

@Override

public Collection<Class<? extends IFloodlightService>> getModuleServices() {

Collection<Class<? extends IFloodlightService>> l =

new ArrayList<Class<? extends IFloodlightService>>();

l.add(IQoSService.class);

return l;

}

@Override

public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {

Map<Class<? extends IFloodlightService>,

IFloodlightService> m =

new HashMap<Class<? extends IFloodlightService>,

IFloodlightService>();

// We are the class that implements the service

m.put(IQoSService.class, this);

return m;

}

@Override

public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {

//This module should depend on FloodlightProviderService,

// IStorageSourceProviderService, IRestApiService, &

// IStaticFlowEntryPusherService

Collection<Class<? extends IFloodlightService>> l =

new ArrayList<Class<? extends IFloodlightService>>();

l.add(IFloodlightProviderService.class);

l.add(IStorageSourceService.class);

l.add(IRestApiService.class);

l.add(IStaticFlowEntryPusherService.class);

return l;

}

protected ArrayList<QoSPolicy> readPoliciesFromStorage() {

ArrayList<QoSPolicy> l = new ArrayList<QoSPolicy>();

try{

Map<String, Object> row;

IResultSet policySet = storageSource

.executeQuery(TABLE_NAME, ColumnNames, null, null );

for( Iterator<IResultSet> iter = policySet.iterator(); iter.hasNext();){

row = iter.next().getRow();

QoSPolicy p = new QoSPolicy();

if(!row.containsKey(COLUMN_POLID)

|| !row.containsKey(COLUMN_SW)

|| !row.containsKey(COLUMN_QUEUE)

|| !row.containsKey(COLUMN_ENQPORT)

|| !row.containsKey(COLUMN_SERVICE)){

logger.error("Skipping entry with required fields {}", row);

continue;

}

try{

p.policyid = Integer.parseInt((String) row.get(COLUMN_POLID));

p.queue = Short.parseShort((String) row.get(COLUMN_QUEUE));

p.enqueueport = Short.parseShort((String) row.get(COLUMN_ENQPORT));

p.service = (String) row.get(COLUMN_SERVICE);

//TODO change for String[] of switches

p.sw = (String) row.get(COLUMN_SW);

for(String key: row.keySet()){

if(row.get(key) == null){

continue;

}

else if(key.equals(COLUMN_POLID)

|| key.equals(COLUMN_SW)

|| key.equals(COLUMN_QUEUE)

|| key.equals(COLUMN_ENQPORT)

|| key.equals(COLUMN_SERVICE)){

continue;

}

else if(key.equals(COLUMN_NAME)){

p.name = (String) row.get(COLUMN_NAME);

}

else if(key.equals(COLUMN_MATCH_ETHDST)){

p.ethdst = (String) row.get(COLUMN_MATCH_ETHDST);

}

else if(key.equals(COLUMN_MATCH_ETHSRC)){

p.ethsrc = (String) row.get(COLUMN_MATCH_ETHSRC);

}

else if(key.equals(COLUMN_MATCH_ETHTYPE)){

p.ethtype = Short.parseShort((String)

row.get(COLUMN_MATCH_ETHTYPE));

}

else if(key.equals(COLUMN_MATCH_INGRESSPRT)){

p.ingressport = Short.parseShort((String)

row.get(COLUMN_MATCH_INGRESSPRT));

}

else if(key.equals(COLUMN_MATCH_IPDST)){

p.ipdst = Integer.parseInt((String)

row.get(COLUMN_MATCH_IPDST));

}

else if(key.equals(COLUMN_MATCH_IPSRC)){

p.ipsrc = Integer.parseInt((String)

row.get(COLUMN_MATCH_IPSRC));

}

else if(key.equals(COLUMN_MATCH_PROTOCOL)){

p.protocol = Byte.parseByte((String)

row.get(COLUMN_MATCH_PROTOCOL));

}

else if(key.equals(COLUMN_MATCH_TCPUDP_DSTPRT)){

p.tcpudpdstport = Short.parseShort((String)

row.get(COLUMN_MATCH_TCPUDP_DSTPRT));

}

else if(key.equals(COLUMN_MATCH_TCPUDP_SRCPRT)){

p.tcpudpsrcport = Short.parseShort((String)

row.get(COLUMN_MATCH_TCPUDP_SRCPRT));

}

else if(key.equals(COLUMN_MATCH_VLANID)){

p.vlanid = Short.parseShort((String)

row.get(COLUMN_MATCH_VLANID));

}

else if(key.equals(COLUMN_NW_TOS)){

p.tos = Byte.parseByte((String)

row.get(COLUMN_NW_TOS));

}

else if(key.equals(COLUMN_PRIORITY)){

p.priority = Short.parseShort((String)

row.get(COLUMN_PRIORITY));

}

}

}catch(ClassCastException e){

logger.error("Error, Skipping rule, Bad Data "

+ e.getMessage()+" on Rule {}", p.policyid);

}

//make sure its a queueing rule or service rule only.

if(p.enqueueport != -1 && p.queue != -1 && p.service != null){

l.add(p);

}

else if(p.enqueueport > -1 && p.queue > -1 && p.service == null){

l.add(p);

}

else{

continue;//not a valid rule

}

}

}catch(StorageException e){

logger.error("Error with storage source: {}", e);

}

Collections.sort(l);

return l;

}

protected ArrayList<QoSTypeOfService> readServicesFromStorage() {

ArrayList<QoSTypeOfService> l = new ArrayList<QoSTypeOfService>();

try{

Map<String, Object> row;

IResultSet serviceSet = storageSource

.executeQuery(TOS_TABLE_NAME, TOSColumnNames, null, null );

for( Iterator<IResultSet> iter = serviceSet.iterator(); iter.hasNext();){

row = iter.next().getRow();

QoSTypeOfService s = new QoSTypeOfService();

if(!row.containsKey(COLUMN_SID)

|| !row.containsKey(COLUMN_TOSBITS)){

logger.error("Skipping entry with required fields {}", row);

continue;

}

try{

s.sid = Integer.parseInt((String) row.get(COLUMN_SID));

s.tos = Byte.parseByte((String) row.get(COLUMN_TOSBITS));

for(String key: row.keySet()){

if(row.get(key) == null){

continue;

}

else if(key.equals(COLUMN_SID)

|| key.equals(COLUMN_TOSBITS)){

continue;

}

else if(key.equals(COLUMN_SNAME)){

s.name = (String) row.get(COLUMN_SNAME);

}

}

}catch(ClassCastException e){

logger.error("Error, Skipping rule, Bad Data "

+ e.getMessage()+" on Rule {}", s.sid);

}

if(s.tos != -1){

l.add(s);

}

}

}catch(StorageException e){

logger.error("Error with storage source: {}", e);

}

Collections.sort(l);

return l;

}

@Override

public void init(FloodlightModuleContext context)

throws FloodlightModuleException {

//initiate services

floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);

flowPusher = context.getServiceImpl(IStaticFlowEntryPusherService.class);

logger = LoggerFactory.getLogger(QoS.class);

storageSource = context.getServiceImpl(IStorageSourceService.class);

restApi = context.getServiceImpl(IRestApiService.class);

policies = new ArrayList<QoSPolicy>();

services = new ArrayList<QoSTypeOfService>();

logger = LoggerFactory.getLogger(QoS.class);

// start disabled

// can be overridden by tools.properties.

enabled = false;

try {

//load a properties file

props.load(new FileInputStream("src/main/resources/tools.properties"));

tools = props.getProperty("tools").split(",");

System.out.println(props.getProperty("qos"));

if(props.getProperty("qos").equalsIgnoreCase("enabled")){

logger.info("Enabling QoS on Start-up. Edit tools.properties to change this.");

this.enableQoS(true);

}

}catch (FileNotFoundException e) {

e.printStackTrace();

} catch(IOException e) {

e.printStackTrace();

}

}

@Override

public void startUp(FloodlightModuleContext context) {

// initialize REST interface

restApi.addRestletRoutable(new QoSWebRoutable());

floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);

//Storage for policies

storageSource.createTable(TABLE_NAME, null);

storageSource.setTablePrimaryKeyName(TABLE_NAME, COLUMN_POLID);

//avoid thread issues for concurrency

synchronized (policies) {

this.policies = readPoliciesFromStorage();

}

//Storage for services

storageSource.createTable(TOS_TABLE_NAME, null);

storageSource.setTablePrimaryKeyName(TOS_TABLE_NAME, COLUMN_SID);

//avoid thread issues for concurrency

synchronized (services) {

this.services = readServicesFromStorage();

}

// create default "Best Effort" service

// most networks use this as default, adding here for defaulting

try{

QoSTypeOfService service = new QoSTypeOfService();

service.name = "Best Effort";

service.tos = (byte)0x00;

service.sid = service.genID();

this.addService(service);

}catch(Exception e){

logger.error("Error adding default Best Effort {}", e);

}

}

@Override

public net.floodlightcontroller.core.IListener.Command receive(

IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {

//do not process packet if not enabled

if (!this.enabled) {

return Command.CONTINUE;

}

//logger.debug("Message Recieved: Type - {}",msg.getType().toString());

//Listen for Packets that match Policies

switch (msg.getType()) {

case PACKET_IN:

//logger.debug("PACKET_IN recieved");

byte[] packetData = OFMessage.getData(sw, msg, cntx);

//Temporary match from packet to compare

OFMatch tmpMatch = new OFMatch();

tmpMatch.loadFromPacket(packetData, OFPort.OFPP_NONE.getValue());

checkIfQoSApplied(tmpMatch);

break;

default:

return Command.CONTINUE;

}

return Command.CONTINUE;

}

/**

* Allow access to enable module

* @param boolean

*/

@Override

public void enableQoS(boolean enable) {

logger.info("Setting QoS to {}", enable);

this.enabled = enable;

}

/**

* Return whether of not the module is enabled

*/

@Override

public boolean isEnabled(){

return this.enabled;

}

/**

* Return a List of Quality of Service Policies

*/

@Override

public List<QoSPolicy> getPolicies() {

return this.policies;

}

/**

* Returns a list of services available for Network Type of Service

* @return List

*/

@Override

public List<QoSTypeOfService> getServices() {

return this.services;

}

/**

* Add a service class to use in policies

* Used to make ToS/DiffServ Bits human readable.

* Bit notation 000000 becomes "Best Effort"

* @param QoSTypeOfService

*/

@Override

public synchronized void addService(QoSTypeOfService service) {

//debug

logger.debug("Adding Service to List and Storage");

//create the UID

service.sid = service.genID();

//check tos bits are within bounds

if (service.tos >= (byte)0x00 && service.tos <= (byte)0x3F ){

try{

//Add to the list of services

//un-ordered, naturally a short list

this.services.add(service);

//add to the storage source

Map<String, Object> serviceEntry = new HashMap<String,Object>();

serviceEntry.put(COLUMN_SID, Integer.toString(service.sid));

serviceEntry.put(COLUMN_SNAME, service.name);

serviceEntry.put(COLUMN_TOSBITS, Byte.toString(service.tos));

//ad to storage

storageSource.insertRow(TOS_TABLE_NAME, serviceEntry);

}catch(Exception e){

logger.debug("Error adding service, error: {}" ,e);

}

}

else{

logger.debug("Type of Service must be 0-64");

}

}

/**

* Removes a Network Type of Service

* @category by sid

*/

@Override

public synchronized void deleteService(int sid) {

Iterator<QoSTypeOfService> sIter = this.services.iterator();

while(sIter.hasNext()){

QoSTypeOfService s = sIter.next();

if(s.sid == sid){

sIter.remove();

break; //done only one can exist

}

}

}

@Override

public synchronized void addPolicy(QoSPolicy policy){

//debug

logger.debug("Adding Policy to List and Storage");

//create the UID

policy.policyid = policy.genID();

int p = 0;

for (p = 0; p < this.policies.size(); p++){

//check if empy

if(this.policies.isEmpty()){

//p is zero

break;

}

//starts at the first(lowest) policy based on priority

//insertion sort, gets hairy when n # of switches increases.

//larger networks may need a merge sort.

if(this.policies.get(p).priority >= policy.priority){

//this keeps "p" in the correct position to place new policy in

break;

}

}

if (p <= this.policies.size()) {

this.policies.add(p, policy);

}

else {

this.policies.add(policy);

}

//Add to the storageSource

Map<String, Object> policyEntry = new HashMap<String, Object>();

policyEntry.put(COLUMN_POLID, Long.toString(policy.policyid));

policyEntry.put(COLUMN_NAME, policy.name);

policyEntry.put(COLUMN_MATCH_PROTOCOL, Short.toString(policy.protocol));

policyEntry.put(COLUMN_MATCH_ETHTYPE, Short.toString(policy.ethtype));

policyEntry.put(COLUMN_MATCH_INGRESSPRT, Short.toString(policy.ingressport));

policyEntry.put(COLUMN_MATCH_IPSRC, Integer.toString(policy.ipsrc));

policyEntry.put(COLUMN_MATCH_IPDST, Integer.toBinaryString(policy.ipdst));

policyEntry.put(COLUMN_MATCH_VLANID, Short.toString(policy.vlanid));

policyEntry.put(COLUMN_MATCH_ETHSRC, policy.ethsrc);

policyEntry.put(COLUMN_MATCH_ETHDST, policy.ethdst);

policyEntry.put(COLUMN_MATCH_TCPUDP_SRCPRT, Short.toString(policy.tcpudpsrcport));

policyEntry.put(COLUMN_MATCH_TCPUDP_DSTPRT, Short.toString(policy.tcpudpdstport));

policyEntry.put(COLUMN_NW_TOS, policy.service);

policyEntry.put(COLUMN_SW, policy.sw);

policyEntry.put(COLUMN_QUEUE, Short.toString(policy.queue));

policyEntry.put(COLUMN_ENQPORT, Short.toString(policy.enqueueport));

policyEntry.put(COLUMN_PRIORITY, Short.toString(policy.priority));

policyEntry.put(COLUMN_SERVICE, policy.service);

storageSource.insertRow(TABLE_NAME, policyEntry);

/**

* TODO Morph this to use a String[] of switches

**/

if (policy.sw.equals("all")){

logger.debug("Adding Policy {} to Entire Network", policy.toString());

addPolicyToNetwork(policy);

}

/** [NOTE] Note utilized yet, future revision used to "save" policies

*  to the controller, then modified to be added to switched **/

else if (policy.sw.equals("none")){

logger.debug("Adding Policy {} to Controller", policy.toString());

}

//add to a specified switch b/c "all" not specified

else if(policy.sw.matches(dpidPattern)){

logger.debug("Adding policy {} to Switch {}", policy.toString(), policy.sw);

// add appropriate hex string converted to a long type

addPolicy(policy, policy.sw);

}

else{

logger.error("***Policy {} error at switch input {} ***" +

"", policy.toString(), policy.sw);

}

}

/**

* Add a policy-flowMod to all switches in network

* @param policy

*/

@Override

public void addPolicyToNetwork(QoSPolicy policy) {

OFFlowMod flow = policyToFlowMod(policy);

logger.info("adding policy-flow {} to all switches",flow.toString());

//add to all switches

Map<Long, IOFSwitch> switches = floodlightProvider.getSwitches();

//simple check

if(!(switches.isEmpty())){

for(IOFSwitch sw : switches.values()){

if(!(sw.isConnected())){

break;// cannot add

}

logger.info("Add flow Name: {} Flow: {} Switch "+ sw.getStringId(),

policy.name, flow.toString());

//add unique flow names based on dpid hasCode :)

flowPusher.addFlow(policy.name+Integer

.toString(sw.getStringId()

.hashCode()), flow, sw.getStringId());

}

}

}

/**

* Adds a policy to a switch (dpid)

* @param QoSPolicy policy

* @param String sw

*/

//This will change to list sws[]

//of switches, including a single sw

@Override

public void addPolicy(QoSPolicy policy, String swid) {

//get the flowmod

OFFlowMod flow = policyToFlowMod(policy);

logger.info("Adding policy-flow {} to switch {}",flow.toString(),swid);

//add unique flow names based on dpid hasCode :)

flowPusher.addFlow(policy.name+Integer

.toString(swid.hashCode()), flow, swid);

}

/**

* Removes a policy from entire network

* @param policy

*/

@Override

public void deletePolicyFromNetwork(String policyName) {

//all switches

Map<Long, IOFSwitch> switches = floodlightProvider.getSwitches();

//simple check

if(!(switches.isEmpty())){

for(IOFSwitch sw : switches.values()){

if(!(sw.isConnected())){

break;// cannot add

}

logger.debug("{} has {}",sw.getStringId(),flowPusher.getFlows());

flowPusher.deleteFlow(policyName+Integer

.toString(sw.getStringId().hashCode()));

}

}

}

@Override

public synchronized void deletePolicy(QoSPolicy policy){

logger.info("Deleting policy {} attached to switches: {}", policy.name, policy.sw);

//dont have to catch policy.sw == "non" just delete it

if(policy.sw.equalsIgnoreCase("none")){logger.info("policy match no switches, removeing from storage");}

else if(policy.sw.equalsIgnoreCase("all")){

logger.info("Delete flows from network!");

deletePolicyFromNetwork(policy.name);

}

else if(policy.sw.matches(dpidPattern)){

deletePolicy(policy.sw, policy.name);

}

else{

logger.error("Error!, Unrecognized switches! Switch is : {}",policy.sw);

}

//remove from storage

Iterator<QoSPolicy> sIter = this.policies.iterator();

while(sIter.hasNext()){

QoSPolicy p = sIter.next();

if(p.policyid == policy.policyid){

sIter.remove();

break; //done only one can exist

}

}

}

/**

* Delete policy from a switch (dpid)

* @param policyid

* @param sw

* @throws

*/

//This will change to list sws[]

//of switches, including a single sw

@Override

public void deletePolicy(String switches, String policyName){

//TODO Morph this to use a String[] of switches

IOFSwitch sw = floodlightProvider.getSwitches()

.get(HexString.toLong(switches));

if(sw != null){

assert(sw.isActive());

}

// delete flow based on hasCode

flowPusher.deleteFlow(policyName+sw.getStringId().hashCode());

}

/**

* Returns a flowmod from a policy

* @param policy

* @return

*/

public OFFlowMod policyToFlowMod(QoSPolicy policy){

//initialize a match structure that matches everything

OFMatch match = new OFMatch();

//Based on the policy match appropriately.

//no wildcards

match.setWildcards(0);

if(policy.ethtype != -1){

match.setDataLayerType((policy.ethtype));

//logger.debug("setting match on eth-type");

}

if(policy.protocol != -1){

match.setNetworkProtocol(policy.protocol);

//logger.debug("setting match on protocol ");

}

if(policy.ingressport != -1){

match.setInputPort(policy.ingressport);

//logger.debug("setting match on ingress port ");

}

if(policy.ipdst != -1){

match.setNetworkDestination(policy.ipdst);

//logger.debug("setting match on network destination");

}

if(policy.ipsrc != -1){

match.setNetworkSource(policy.ipsrc);

//logger.debug("setting match on network source");

}

if(policy.vlanid != -1){

match.setDataLayerVirtualLan(policy.vlanid);

//logger.debug("setting match on VLAN");

}

if(policy.tos != -1){

match.setNetworkTypeOfService(policy.tos);

//logger.debug("setting match on ToS");

}

if(policy.ethsrc != null){

match.setDataLayerSource(policy.ethsrc);

//logger.debug("setting match on data layer source");

}

if(policy.ethdst != null){

match.setDataLayerDestination(policy.ethdst);

//logger.debug("setting match on data layer destination");

}

if(policy.tcpudpsrcport != -1){

match.setTransportSource(policy.tcpudpsrcport);

//logger.debug("setting match on transport source port");

}

if(policy.tcpudpdstport != -1){

match.setTransportDestination(policy.tcpudpdstport);

//logger.debug("setting match on transport destination");

}

//Create a flow mod using the previous match structure

OFFlowMod fm = new OFFlowMod();

fm.setType(OFType.FLOW_MOD);

//depending on the policy nw_tos or queue the flow mod

// will change the type of service bits or enqueue the packets

if(policy.queue > -1 && policy.service == null){

logger.info("This policy is a queuing policy");

List<OFAction> actions = new ArrayList<OFAction>();

//add the queuing action

OFActionEnqueue enqueue = new OFActionEnqueue();

enqueue.setLength((short) 0xffff);

enqueue.setType(OFActionType.OPAQUE_ENQUEUE); // I think this happens anyway in the constructor

enqueue.setPort(policy.enqueueport);

enqueue.setQueueId(policy.queue);

actions.add((OFAction) enqueue);

logger.info("Match is : {}", match.toString());

//add the matches and actions and return

fm.setMatch(match)

.setActions(actions)

.setIdleTimeout((short) 0)  // infinite

.setHardTimeout((short) 0)  // infinite

.setBufferId(OFPacketOut.BUFFER_ID_NONE)

.setFlags((short) 0)

.setOutPort(OFPort.OFPP_NONE.getValue())

.setPriority(policy.priority)

.setLengthU((short)OFFlowMod.MINIMUM_LENGTH + OFActionEnqueue.MINIMUM_LENGTH);

}

else if(policy.queue == -1 && policy.service != null){

logger.info("This policy is a type of service policy");

List<OFAction> actions = new ArrayList<OFAction>();

//add the queuing action

OFActionNetworkTypeOfService tosAction = new OFActionNetworkTypeOfService();

tosAction.setType(OFActionType.SET_NW_TOS);

tosAction.setLength((short) 0xffff);

//Find the appropriate type of service bits in policy

Byte pTos = null;

List<QoSTypeOfService> serviceList = this.getServices();

for(QoSTypeOfService s : serviceList){

if(s.name.equals(policy.service)){

//policy‘s service ToS bits

pTos = s.tos;

}

}

tosAction.setNetworkTypeOfService(pTos);

actions.add((OFAction)tosAction);

logger.info("Match is : {}", match.toString());

//add the matches and actions and return.class.ge

fm.setMatch(match)

.setActions(actions)

.setIdleTimeout((short) 0)  // infinite

.setHardTimeout((short) 0)  // infinite

.setBufferId(OFPacketOut.BUFFER_ID_NONE)

.setFlags((short) 0)

.setOutPort(OFPort.OFPP_NONE.getValue())

.setPriority(Short.MAX_VALUE)

.setLengthU((short)OFFlowMod.MINIMUM_LENGTH + OFActionNetworkTypeOfService.MINIMUM_LENGTH);

}

else{

logger.error("Policy Misconfiguration");

}

return fm;

}

/**

* Logs which, if any QoS is applied to PACKET_IN

* @param tmpMatch

* @throws IOException

*/

private void checkIfQoSApplied(OFMatch tmpMatch){

List<QoSPolicy> pols = this.getPolicies();

//policies dont apply to wildcards, (yet)

if (!pols.isEmpty()){

for(QoSPolicy policy : pols){

OFMatch m = new OFMatch();

m = policyToFlowMod(policy).getMatch();

//check

if (tmpMatch.equals(m)){

logger.info("PACKET_IN matched, Applied QoS Policy {}",policy.toString());

}

//Commented out checks, annoying in console log. For debug I‘ll leave though.

//else{

//
logger.debug("Pass, no match on PACKET_IN");

//}

}

}//else{logger.info("No Policies to Check Against PACKET_IN");}

}

}

python包写在floodlight/apps/目录里面

以下是一些基于python脚本命令:

写qos策略到ovs中

sudo ovs-vsctl -- set port s1-eth1 [email protected] -- set port s1-eth2 [email protected] -- [email protected] create qos type=linux-htb other-config:max-rate=1000000000 [email protected],[email protected],[email protected] -- [email protected] create queue other-config:min-rate=1000000000
other-config:max-rate=1000000000 -- [email protected] create queue other-config:max-rate=20000000 -- [email protected] create queue other-config:max-rate=2000000 other-config:mix-rate=200000

查看qos策略:

ovs-vsctl list qos

ovs-vsctl list queue

cat qos-state.json

命名一条实际的qos:

./qospath2.py -a --name 2Mbps01-02 -S 10.0.0.1 -D 10.0.0.2 -J‘{"eth-type":"0x0800","protocol":"6","queue":"2"}‘

删除一条策略:

./qospath2.py -d -N 22Mbps01-02

在mininet中的测试命令:

iperf -s

iperf -c

在网页上显示qos policy:

未加入qos policy之前(上图):

加入限制流量为2M之后(当然这个数值可以随便改):

时间: 2024-08-04 01:36:10

SDN开发之基于floodlight控制器做QoS策略的相关文章

SDN 实践之floodlight控制器统计流量种类

SDN 实践之floodlight控制器统计流量种类 @温州大学12网工蒋暕青.郑明社 在floodlight控制器统计流量的基础上接着把packed-in流量的种类也区分一下.counter这个类琢磨了一个月终于有些会用了. 下面贴代码: 分两个.java 1. package edu.wzu.steve.trafficanalyser; import java.util.ArrayList; import java.util.Collection; import java.util.Hash

(sdn)在floodlight控制器中统计进入packed-in数量的代码(改)

在floodlight控制器中统计进入packed-in数量的代码: package edu.wzu.steve.trafficanalyser; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import org.restl

Unity3D游戏开发之基于Terrain Toolkit实现地形的制作

 今天继续由我为大家带来Unity3D游戏开发系列文章.今天我们来通过Terrain Toolkit来实现地形的制作.尽管Unity3D已经为我们提供了地形绘制工具,但是在实际的运用中我们发现,这个地形绘制工具并不能满足我们的要求,因为通过手动绘制这种方法来画地形的起伏缺少了自然的侵蚀感,人力雕琢的感觉过于强烈,毕竟通过人去感觉自然界地形的起伏变化是力不从心的,所以我们建议通过程序来生成地形,因此就有了我们今天的这篇文章.下面,请大家跟随我一起来学习这个插件的使用吧. 首先我们创建一个空的项

构建一个基本的前端自动化开发环境 —— 基于 Gulp 的前端集成解决方案(四)

通过前面几节的准备工作,对于 npm / node / gulp 应该已经有了基本的认识,本节主要介绍如何构建一个基本的前端自动化开发环境. 下面将逐步构建一个可以自动编译 sass 文件.压缩 javascript 文件.多终端多浏览器同步测试的开发环境,并且还可以通过 piblish 命令对项目下的文件进行打包操作. 相关连接导航 在windows下安装gulp —— 基于 Gulp 的前端集成解决方案(一) 执行 $Gulp 时发生了什么 —— 基于 Gulp 的前端集成解决方案(二) 常

《开源框架那点事儿13》:基于开源框架做应用是未来中小型软件公司的发展趋势

在我的周边朋友身边就发生过这样的事情: 故事1:A君在北京从事Java开发好多年了,萌发了创业的念头,想组建了一个开发团队想大干一场.但是慢慢发现,构建一个有战斗力的团队真不容易.后来技术团队的组建初步有了起色,但是技术路线却非常难成一致意见.折腾来折腾去,把有点上道的技术人员都折腾得跳槽了.费了巨高的成本搞了一个架构师,就是利用SSH框架搭建了一个开发环境,数据量小,业务初期还是不错的,但是当业务快速增长的时候,运行速度就无法满足需要了.是重新来过还是在SSH的基础上继续折腾,非常难以抉择!

玩转Android Camera开发(五):基于Google自带算法实时检测人脸并绘制人脸框(网络首发,附完整demo)

本文主要介绍使用Google自带的FaceDetectionListener进行人脸检测,并将检测到的人脸用矩形框绘制出来.本文代码基于PlayCameraV1.0.0,在Camera的open和preview流程上进行了改动.原先是放在单独线程里,这次我又把它放到Surfaceview的生命周期里进行打开和开预览. 首先要反省下,去年就推出了静态图片的人脸检测demo,当时许诺一周内推出Camera预览实时检测并绘制的demo,结果拖到现在才整.哎,屌丝一天又一天,蹉跎啊.在demo制作过程中

Flask之旅《Flask Web开发:基于Python的Web应用开发实战》学习笔记

<Flask Web开发:基于Python的Web应用开发实战> 点击上方的"目录"快速到达哦! 虽然简单的网站(Flask+Python+SAE)已经上线,但只是入门.开发大型网站,系统地学习一遍还是有必要的. 1 虚拟环境 2016-6-8 书上介绍了 virtualenv,每个venv都会拷贝一份packages到项目 /venv目录. virtualenv venv venv\Scripts\activate.bat (venv) $ pip freeze >

Swift项目开发实战-基于分层架构的多版本iPhone计算器-直播公开课

本课程采用Q Q群直播方式进行直播,价值99元视频课程免费直播.完整的基于Swift项目实战,手把手教你做一个Swift版iPhone计算器.(直播过程也有惊喜!)直播Q Q群:362298485(直播时点击群视频即可进入直播课堂)直播时间:8月26日(周二),9月2日(周四),每天20:00-22:00欢迎咨询客服Q Q:1575716557直播后希望继续深入学习了解本课程可在51CTO学院购买本课程,定价99元.购买课程更有惊喜:买课程送书,送优惠券了! 购买本课程赠送关东升老师价值69元国

基于NodeJS的全栈式开发(基于NodeJS的前后端分离)

也谈基于NodeJS的全栈式开发(基于NodeJS的前后端分离) 前言 为了解决传统Web开发模式带来的各种问题,我们进行了许多尝试,但由于前/后端的物理鸿沟,尝试的方案都大同小异.痛定思痛,今天我们重新思考了“前后端”的定义,引入前端同学都熟悉的NodeJS,试图探索一条全新的前后端分离模式. 随着不同终端(Pad/Mobile/PC)的兴起,对开发人员的要求越来越高,纯浏览器端的响应式已经不能满足用户体验的高要求,我们往往需要针对不同的终端开发定制的版本.为了提升开发效率,前后端分离的需求越