Skip to content
Snippets Groups Projects
Commit c884235c authored by Gregor Maier's avatar Gregor Maier
Browse files

Merge remote-tracking branch 'bigswitch/master' into zeromacfix

parents c8dfacd2 8d66fd68
No related branches found
No related tags found
No related merge requests found
package com.bigswitch.floodlight.vendor;
import org.jboss.netty.buffer.ChannelBuffer;
import org.openflow.protocol.action.OFActionVendor;
import org.openflow.protocol.factory.OFVendorActionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class OFNiciraVendorActionFactory implements OFVendorActionFactory {
protected static Logger logger =
LoggerFactory.getLogger(OFNiciraVendorActionFactory.class);
static class OFActionNiciraVendorDemux extends OFActionNiciraVendor {
OFActionNiciraVendorDemux() {
super((short) 0);
}
}
@Override
public OFActionVendor readFrom(ChannelBuffer data) {
data.markReaderIndex();
OFActionNiciraVendorDemux demux = new OFActionNiciraVendorDemux();
demux.readFrom(data);
data.resetReaderIndex();
switch(demux.getSubtype()) {
case OFActionNiciraTtlDecrement.TTL_DECREMENT_SUBTYPE:
OFActionNiciraTtlDecrement ttlAction = new OFActionNiciraTtlDecrement();
ttlAction.readFrom(data);
return ttlAction;
default:
logger.error("Unknown Nicira vendor action subtype: "+demux.getSubtype());
return null;
}
}
}
package com.bigswitch.floodlight.vendor;
import org.openflow.protocol.factory.OFVendorActionRegistry;
public final class OFVendorActions {
public static final void registerStandardVendorActions() {
OFVendorActionRegistry registry = OFVendorActionRegistry.getInstance();
registry.register(OFActionBigSwitchVendor.BSN_VENDOR_ID, new OFBigSwitchVendorActionFactory());
registry.register(OFActionNiciraVendor.NICIRA_VENDOR_ID, new OFNiciraVendorActionFactory());
}
}
\ No newline at end of file
......@@ -612,4 +612,28 @@ public interface IOFSwitch {
* Set the flow table full flag in the switch
*/
public void setTableFull(boolean isFull);
/**
* Set the suggested priority to use when installing access flows in
* this switch.
*/
public void setAccessFlowPriority(short prio);
/**
* Set the suggested priority to use when installing core flows in
* this switch.
*/
public void setCoreFlowPriority(short prio);
/**
* Get the suggested priority to use when installing access flows in
* this switch.
*/
public short getAccessFlowPriority();
/**
* Get the suggested priority to use when installing core flows in
* this switch.
*/
public short getCoreFlowPriority();
}
......@@ -104,6 +104,9 @@ public abstract class OFSwitchBase implements IOFSwitch {
protected long datapathId;
protected String stringId;
protected short accessFlowPriority;
protected short coreFlowPriority;
/**
* Members hidden from subclasses
*/
......@@ -1504,4 +1507,28 @@ public abstract class OFSwitchBase implements IOFSwitch {
}
flowTableFull = isFull;
}
@Override
public short getAccessFlowPriority() {
return accessFlowPriority;
}
@Override
public short getCoreFlowPriority() {
return coreFlowPriority;
}
@Override
public void setAccessFlowPriority(short accessFlowPriority) {
this.accessFlowPriority = accessFlowPriority;
}
@Override
public void setCoreFlowPriority(short coreFlowPriority) {
this.coreFlowPriority = coreFlowPriority;
}
}
......@@ -202,6 +202,24 @@ public class Controller implements IFloodlightProviderService,
protected static final String CONTROLLER_INTERFACE_NUMBER = "number";
protected static final String CONTROLLER_INTERFACE_DISCOVERED_IP = "discovered_ip";
// FIXME: don't use "forwardingconfig" as table name
private static final String FLOW_PRIORITY_TABLE_NAME = "controller_forwardingconfig";
private static final String FLOW_COLUMN_PRIMARY_KEY = "id";
private static final String FLOW_VALUE_PRIMARY_KEY = "forwarding";
private static final String FLOW_COLUMN_ACCESS_PRIORITY = "access_priority";
private static final String FLOW_COLUMN_CORE_PRIORITY = "core_priority";
private static final String[] FLOW_COLUMN_NAMES = new String[] {
FLOW_COLUMN_PRIMARY_KEY,
FLOW_COLUMN_ACCESS_PRIORITY,
FLOW_COLUMN_CORE_PRIORITY
};
private static final short DEFAULT_ACCESS_PRIORITY = 10;
private static final short DEFAULT_CORE_PRIORITY = 1000;
private short accessPriority = DEFAULT_ACCESS_PRIORITY;
private short corePriority = DEFAULT_CORE_PRIORITY;
// Perf. related configuration
protected static final int SEND_BUFFER_SIZE = 4 * 1024 * 1024;
public static final int BATCH_MAX_SIZE = 100;
......@@ -2233,6 +2251,12 @@ public class Controller implements IFloodlightProviderService,
CONTROLLER_ID);
storageSource.addListener(CONTROLLER_INTERFACE_TABLE_NAME, this);
storageSource.createTable(FLOW_PRIORITY_TABLE_NAME, null);
storageSource.setTablePrimaryKeyName(FLOW_PRIORITY_TABLE_NAME,
FLOW_COLUMN_PRIMARY_KEY);
storageSource.addListener(FLOW_PRIORITY_TABLE_NAME, this);
readFlowPriorityConfigurationFromStorage();
// Startup load monitoring
if (overload_drop) {
this.loadmonitor.startMonitoring(
......@@ -2264,6 +2288,47 @@ public class Controller implements IFloodlightProviderService,
registerControllerDebugEvents();
}
@LogMessageDoc(level="ERROR",
message="failed to access storage: {reason}",
explanation="Could not retrieve forwarding configuration",
recommendation=LogMessageDoc.CHECK_CONTROLLER)
private void readFlowPriorityConfigurationFromStorage() {
try {
Map<String, Object> row;
IResultSet resultSet = storageSource.executeQuery(
FLOW_PRIORITY_TABLE_NAME, FLOW_COLUMN_NAMES, null, null);
if (resultSet == null)
return;
for (Iterator<IResultSet> it = resultSet.iterator(); it.hasNext();) {
row = it.next().getRow();
if (row.containsKey(FLOW_COLUMN_PRIMARY_KEY)) {
String primary_key = (String) row.get(FLOW_COLUMN_PRIMARY_KEY);
if (primary_key.equals(FLOW_VALUE_PRIMARY_KEY)) {
if (row.containsKey(FLOW_COLUMN_ACCESS_PRIORITY)) {
accessPriority =
Short.valueOf((String) row.get(FLOW_COLUMN_ACCESS_PRIORITY));
}
if (row.containsKey(FLOW_COLUMN_CORE_PRIORITY)) {
corePriority =
Short.valueOf((String) row.get(FLOW_COLUMN_CORE_PRIORITY));
}
}
}
}
}
catch (StorageException e) {
log.error("Failed to access storage for forwarding configuration: {}",
e.getMessage());
}
catch (NumberFormatException e) {
// log error, no stack-trace
log.error("Failed to read core or access flow priority from " +
"storage. Illegal number: {}", e.getMessage());
}
}
private void registerControllerDebugEvents() {
if (debugEvents == null) {
debugEvents = new NullDebugEvent();
......@@ -2398,18 +2463,34 @@ public class Controller implements IFloodlightProviderService,
return retval;
}
private static final String FLOW_PRIORITY_CHANGED_AFTER_STARTUP =
"Flow priority configuration has changed after " +
"controller startup. Restart controller for new " +
"configuration to take effect.";
@LogMessageDoc(level="WARN",
message=FLOW_PRIORITY_CHANGED_AFTER_STARTUP,
explanation="A user has changed the priority with which access " +
"and core flows are installed after controller startup. " +
"Changing this setting will only take affect after a " +
"controller restart",
recommendation="Restart controller")
@Override
public void rowsModified(String tableName, Set<Object> rowKeys) {
if (tableName.equals(CONTROLLER_INTERFACE_TABLE_NAME)) {
handleControllerNodeIPChanges();
} else if (tableName.equals(FLOW_PRIORITY_TABLE_NAME)) {
log.warn(FLOW_PRIORITY_CHANGED_AFTER_STARTUP);
}
}
@Override
public void rowsDeleted(String tableName, Set<Object> rowKeys) {
if (tableName.equals(CONTROLLER_INTERFACE_TABLE_NAME)) {
handleControllerNodeIPChanges();
} else if (tableName.equals(FLOW_PRIORITY_TABLE_NAME)) {
log.warn(FLOW_PRIORITY_CHANGED_AFTER_STARTUP);
}
}
......@@ -2492,6 +2573,14 @@ public class Controller implements IFloodlightProviderService,
debugEvents.flushEvents();
}
short getAccessFlowPriority() {
return accessPriority;
}
short getCoreFlowPriority() {
return corePriority;
}
/**
* FOR TESTING ONLY.
* Dispatch all updates in the update queue until queue is empty
......
......@@ -70,6 +70,9 @@ import org.openflow.vendor.nicira.OFRoleRequestVendorData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.bigswitch.floodlight.vendor.OFBigSwitchVendorData;
import com.bigswitch.floodlight.vendor.OFBsnL2TableSetVendorData;
/**
......@@ -83,9 +86,7 @@ class OFChannelHandler
private static final Logger log = LoggerFactory.getLogger(OFChannelHandler.class);
private static final long DEFAULT_ROLE_TIMEOUT_MS = 10*1000; // 10 sec
/**
*
*/
private final Controller controller;
private final Counters counters;
private IOFSwitch sw;
......@@ -463,15 +464,58 @@ class OFChannelHandler
/**
* We are waiting for a features reply message. Once we receive it
* we send a SetConfig request, barrier, and GetConfig request.
* Next stats is WAIT_CONFIG_REPLY
* Next stats is WAIT_CONFIG_REPLY or WAIT_SET_L2_TABLE_REPLY
*/
WAIT_FEATURES_REPLY(false) {
@Override
void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply m)
throws IOException {
h.featuresReply = m;
if (m.getTables() > 1) {
log.debug("Have {} table for switch {}", m.getTables(),
h.getSwitchInfoString());
// likely supports L2 table extensions. Send set
h.sendHandshakeL2TableSet();
// TODO: no L2 SET reply yet, so fire and forget the set
// table message and move directly to sendHandshakeConfig
h.sendHandshakeSetConfig();
h.setState(WAIT_CONFIG_REPLY);
//h.setState(WAIT_SET_L2_TABLE_REPLY);
} else {
h.sendHandshakeSetConfig();
h.setState(WAIT_CONFIG_REPLY);
}
}
@Override
void processOFStatisticsReply(OFChannelHandler h,
OFStatisticsReply m)
throws IOException {
illegalMessageReceived(h, m);
}
@Override
void processOFError(OFChannelHandler h, OFError m) {
logErrorDisconnect(h, m);
}
},
WAIT_SET_L2_TABLE_REPLY(false) {
@Override void processOFVendor(OFChannelHandler h, OFVendor m)
throws IOException {
// TODO: actually parse the response
h.sendHandshakeSetConfig();
h.setState(WAIT_CONFIG_REPLY);
};
@Override
void processOFBarrierReply(OFChannelHandler h, OFBarrierReply m) {
// do nothing;
}
@Override
void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply m)
throws IOException {
// TODO: we could re-set the features reply
illegalMessageReceived(h, m);
}
@Override
void processOFStatisticsReply(OFChannelHandler h,
......@@ -479,10 +523,17 @@ class OFChannelHandler
throws IOException {
illegalMessageReceived(h, m);
}
@Override
void processOFError(OFChannelHandler h, OFError m) {
logErrorDisconnect(h, m);
}
@Override
void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
throws IOException {
h.pendingPortStatusMsg.add(m);
}
},
/**
......@@ -541,6 +592,14 @@ class OFChannelHandler
@Override
void processOFError(OFChannelHandler h, OFError m) {
if (m.getErrorType() == OFErrorType.OFPET_BAD_REQUEST.getValue()
&& m.getErrorCode() ==
OFBadRequestCode.OFPBRC_BAD_VENDOR.ordinal()) {
log.debug("Switch {} has multiple tables but does not " +
"support L2 table extension",
h.getSwitchInfoString());
return;
}
logErrorDisconnect(h, m);
}
......@@ -592,6 +651,8 @@ class OFChannelHandler
h.sw.setFloodlightProvider(h.controller);
h.sw.setThreadPoolService(h.controller.getThreadPoolService());
h.sw.setDebugCounterService(h.controller.getDebugCounter());
h.sw.setAccessFlowPriority(h.controller.getAccessFlowPriority());
h.sw.setCoreFlowPriority(h.controller.getCoreFlowPriority());
for (OFPortStatus ps: h.pendingPortStatusMsg)
handlePortStatusMessage(h, ps, false);
h.pendingPortStatusMsg.clear();
......@@ -1251,9 +1312,14 @@ class OFChannelHandler
explanation="The specified switch has disconnected.")
public void channelDisconnected(ChannelHandlerContext ctx,
ChannelStateEvent e) throws Exception {
controller.switchDisconnected(this.sw);
controller.removeSwitchChannel(this);
this.sw.setConnected(false);
if (this.sw != null) {
// TODO: switchDisconnected() will check if we've previously
// activated the switch. Nevertheless, we might want to check
// here as well.
controller.switchDisconnected(this.sw);
this.sw.setConnected(false);
}
log.info("Disconnected switch {}", getSwitchInfoString());
}
......@@ -1543,6 +1609,23 @@ class OFChannelHandler
channel.write(Collections.singletonList(m));
}
/**
* Send an setL2TableSet message to the switch.
*/
private void sendHandshakeL2TableSet() {
OFVendor l2TableSet = (OFVendor)
BasicFactory.getInstance().getMessage(OFType.VENDOR);
l2TableSet.setXid(handshakeTransactionIds--);
OFBsnL2TableSetVendorData l2TableSetData =
new OFBsnL2TableSetVendorData(true,
controller.getCoreFlowPriority());
l2TableSet.setVendor(OFBigSwitchVendorData.BSN_VENDOR_ID);
l2TableSet.setVendorData(l2TableSetData);
l2TableSet.setLengthU(OFVendor.MINIMUM_LENGTH +
l2TableSetData.getLength());
channel.write(Collections.singletonList(l2TableSet));
}
/**
* Send the configuration requests to tell the switch we want full
* packets
......
......@@ -63,6 +63,8 @@ import static org.junit.Assert.*;
public class OFChannelHandlerTest {
private static final short CORE_PRIORITY = 4242;
private static final short ACCESS_PRIORITY = 42;
private Controller controller;
private IThreadPoolService threadPool;
private IDebugCounterService debugCounterService;
......@@ -92,7 +94,7 @@ public class OFChannelHandlerTest {
.getMessage(OFType.FEATURES_REPLY);
featuresReply.setDatapathId(0x42L);
featuresReply.setBuffers(1);
featuresReply.setTables((byte)2);
featuresReply.setTables((byte)1);
featuresReply.setCapabilities(3);
featuresReply.setActions(4);
List<OFPhysicalPort> ports = new ArrayList<OFPhysicalPort>();
......@@ -206,14 +208,7 @@ public class OFChannelHandlerTest {
verify(controller);
reset(controller);
setupMessageEvent(messages);
// mock controller
controller.flushAll();
expectLastCall().atLeastOnce();
replay(controller);
handler.messageReceived(ctx, messageEvent);
verify(controller);
sendMessageToHandlerNoControllerReset(messages);
}
/** reset, setup, and replay the messageEvent mock for the given
......@@ -516,6 +511,11 @@ public class OFChannelHandlerTest {
expectLastCall().andReturn(cfg.dpid).atLeastOnce();
sw.isWriteThrottleEnabled(); // used for log message only
expectLastCall().andReturn(false).anyTimes();
sw.setAccessFlowPriority(ACCESS_PRIORITY);
expectLastCall().once();
sw.setCoreFlowPriority(CORE_PRIORITY);
expectLastCall().once();
if (cfg.isPresent)
sw.setAttribute(IOFSwitch.SWITCH_IS_CORE_SWITCH, cfg.isCoreSwitch);
replay(sw);
......@@ -530,6 +530,10 @@ public class OFChannelHandlerTest {
.andReturn(threadPool).once();
expect(controller.getOFSwitchInstance(eq(desc)))
.andReturn(sw).once();
expect(controller.getCoreFlowPriority())
.andReturn(CORE_PRIORITY).once();
expect(controller.getAccessFlowPriority())
.andReturn(ACCESS_PRIORITY).once();
controller.addSwitchChannelAndSendInitialRole(handler);
expectLastCall().once();
expect(controller.getStorageSourceService())
......
......@@ -455,6 +455,29 @@ public class OFMessageDamperMockSwitch implements IOFSwitch {
@Override
public void setTableFull(boolean isFull) {
fail("Unexpected method call");
// TODO Auto-generated method stub
}
@Override
public void setAccessFlowPriority(short prio) {
fail("Unexpected method call");
}
@Override
public void setCoreFlowPriority(short prio) {
fail("Unexpected method call");
}
@Override
public short getAccessFlowPriority() {
fail("Unexpected method call");
return 0;
}
@Override
public short getCoreFlowPriority() {
fail("Unexpected method call");
return 0;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment