Giant patch of changes to support OpenFlow 1.3
The following people have contributed to this patch:
- Ali Al-Shabibi <alshabibi.ali@gmail.com>
- Ayaka Koshibe <ayaka@onlab.us>
- Brian O'Connor <bocon@onlab.us>
- Jonathan Hart <jono@onlab.us>
- Matteo Gerola <mgerola@create-net.org>
- Michele Santuari <michele.santuari@create-net.org>
- Pavlin Radoslavov <pavlin@onlab.us>
- Saurav Das <sauravdas@alumni.stanford.edu>
- Toshio Koide <t-koide@onlab.us>
- Yuta HIGUCHI <y-higuchi@onlab.us>
The patch includes the following changes:
- New Floodlight I/O loop / state machine
- New switch/port handling
- New role management (incl. Role.EQUAL)
- Added Floodlight debug framework
- Updates to Controller.java
- Move to Loxigen's OpenflowJ library
- Added OF1.3 support
- Added support for different switches (via DriverManager)
- Updated ONOS modules to use new APIs
- Added and updated unit tests
Change-Id: Ic70a8d50f7136946193d2ba2e4dc0b4bfac5f599
diff --git a/src/main/java/net/onrc/onos/core/drivermanager/DriverManager.java b/src/main/java/net/onrc/onos/core/drivermanager/DriverManager.java
new file mode 100644
index 0000000..fe86077
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/drivermanager/DriverManager.java
@@ -0,0 +1,58 @@
+package net.onrc.onos.core.drivermanager;
+
+import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.internal.OFSwitchImplBase;
+
+import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A simple implementation of a driver manager that differentiates between
+ * connected switches using the OF Description Statistics Reply message.
+ */
+public final class DriverManager {
+
+ private static final Logger log = LoggerFactory.getLogger(DriverManager.class);
+
+ /**
+ * Return an IOFSwitch object based on switch's manufacturer description
+ * from OFDescStatsReply.
+ *
+ * @param desc DescriptionStatistics reply from the switch
+ * @return A IOFSwitch instance if the driver found an implementation for
+ * the given description. Otherwise it returns OFSwitchImplBase
+ */
+ public static IOFSwitch getOFSwitchImpl(OFDescStatsReply desc, OFVersion ofv) {
+ String vendor = desc.getMfrDesc();
+ String hw = desc.getHwDesc();
+ if (vendor.startsWith("Stanford University, Ericsson Research and CPqD Research")
+ &&
+ hw.startsWith("OpenFlow 1.3 Reference Userspace Switch")) {
+ return new OFSwitchImplCPqD13(desc);
+ }
+
+ if (vendor.startsWith("Nicira") &&
+ hw.startsWith("Open vSwitch")) {
+ if (ofv == OFVersion.OF_10) {
+ return new OFSwitchImplOVS10(desc);
+ } else if (ofv == OFVersion.OF_13) {
+ return new OFSwitchImplOVS13(desc);
+ }
+ }
+
+ log.warn("DriverManager could not identify switch desc: {}. "
+ + "Assigning OFSwitchImplBase", desc);
+ OFSwitchImplBase base = new OFSwitchImplBase();
+ base.setSwitchDescription(desc);
+ // XXX S must set counter here - unidentified switch
+ return base;
+ }
+
+ /**
+ * Private constructor to avoid instantiation.
+ */
+ private DriverManager() {
+ }
+}
diff --git a/src/main/java/net/onrc/onos/core/drivermanager/OFSwitchImplCPqD13.java b/src/main/java/net/onrc/onos/core/drivermanager/OFSwitchImplCPqD13.java
new file mode 100644
index 0000000..c2bb344
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/drivermanager/OFSwitchImplCPqD13.java
@@ -0,0 +1,1208 @@
+package net.onrc.onos.core.drivermanager;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import net.floodlightcontroller.core.IFloodlightProviderService.Role;
+import net.floodlightcontroller.core.SwitchDriverSubHandshakeAlreadyStarted;
+import net.floodlightcontroller.core.SwitchDriverSubHandshakeCompleted;
+import net.floodlightcontroller.core.SwitchDriverSubHandshakeNotStarted;
+import net.floodlightcontroller.core.internal.OFSwitchImplBase;
+
+import org.projectfloodlight.openflow.protocol.OFAsyncGetReply;
+import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
+import org.projectfloodlight.openflow.protocol.OFBucket;
+import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
+import org.projectfloodlight.openflow.protocol.OFErrorMsg;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFGroupDescStatsReply;
+import org.projectfloodlight.openflow.protocol.OFGroupFeaturesStatsReply;
+import org.projectfloodlight.openflow.protocol.OFGroupType;
+import org.projectfloodlight.openflow.protocol.OFMatchV3;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFOxmList;
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
+import org.projectfloodlight.openflow.protocol.OFStatsReply;
+import org.projectfloodlight.openflow.protocol.action.OFAction;
+import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthDst;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthSrc;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthType;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmInPort;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmIpv4DstMasked;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmMetadataMasked;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmMplsLabel;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmVlanVid;
+import org.projectfloodlight.openflow.types.EthType;
+import org.projectfloodlight.openflow.types.IPv4Address;
+import org.projectfloodlight.openflow.types.MacAddress;
+import org.projectfloodlight.openflow.types.OFBufferId;
+import org.projectfloodlight.openflow.types.OFGroup;
+import org.projectfloodlight.openflow.types.OFMetadata;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.OFVlanVidMatch;
+import org.projectfloodlight.openflow.types.TableId;
+import org.projectfloodlight.openflow.types.U32;
+import org.projectfloodlight.openflow.types.U64;
+import org.projectfloodlight.openflow.util.HexString;
+
+/**
+ * OFDescriptionStatistics Vendor (Manufacturer Desc.): Stanford University,
+ * Ericsson Research and CPqD Research. Make (Hardware Desc.) : OpenFlow 1.3
+ * Reference Userspace Switch Model (Datapath Desc.) : None Software : Serial :
+ * None
+ */
+public class OFSwitchImplCPqD13 extends OFSwitchImplBase {
+ private static final int VLAN_ID_OFFSET = 16;
+ private AtomicBoolean driverHandshakeComplete;
+ private OFFactory factory;
+ private static final int OFPCML_NO_BUFFER = 0xffff;
+ // Configuration of asynch messages to controller. We need different
+ // asynch messages depending on role-equal or role-master.
+ // We don't want to get anything if we are slave.
+ private static final long SET_FLOW_REMOVED_MASK_MASTER = 0xf;
+ private static final long SET_PACKET_IN_MASK_MASTER = 0x7;
+ private static final long SET_PORT_STATUS_MASK_MASTER = 0x7;
+ private static final long SET_FLOW_REMOVED_MASK_EQUAL = 0x0;
+ private static final long SET_PACKET_IN_MASK_EQUAL = 0x0;
+ private static final long SET_PORT_STATUS_MASK_EQUAL = 0x7;
+ private static final long SET_ALL_SLAVE = 0x0;
+
+ private static final long TEST_FLOW_REMOVED_MASK = 0xf;
+ private static final long TEST_PACKET_IN_MASK = 0x7;
+ private static final long TEST_PORT_STATUS_MASK = 0x7;
+ private long barrierXidToWaitFor = -1;
+
+ private static final int TABLE_VLAN = 0;
+ private static final int TABLE_TMAC = 1;
+ private static final int TABLE_IPV4_UNICAST = 2;
+ private static final int TABLE_MPLS = 3;
+ private static final int TABLE_META = 4;
+ private static final int TABLE_ACL = 5;
+
+ private static final short MAX_PRIORITY = (short) 0xffff;
+ private static final short SLASH_24_PRIORITY = (short) 0xfff0;
+ private static final short SLASH_16_PRIORITY = (short) 0xff00;
+ private static final short SLASH_8_PRIORITY = (short) 0xf000;
+ private static final short MIN_PRIORITY = 0x0;
+ private static final U64 METADATA_MASK = U64.of(Long.MAX_VALUE << 1 | 0x1);
+
+ ConcurrentHashMap<Integer, OFGroup> l2groups;
+
+ public OFSwitchImplCPqD13(OFDescStatsReply desc) {
+ super();
+ driverHandshakeComplete = new AtomicBoolean(false);
+ l2groups = new ConcurrentHashMap<Integer, OFGroup>();
+ setSwitchDescription(desc);
+
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "OFSwitchImplCPqD13 [" + ((channel != null)
+ ? channel.getRemoteAddress() : "?")
+ + " DPID[" + ((stringId != null) ? stringId : "?") + "]]";
+ }
+
+ @Override
+ public void startDriverHandshake() throws IOException {
+ log.debug("Starting driver handshake for sw {}", getStringId());
+ if (startDriverHandshakeCalled) {
+ throw new SwitchDriverSubHandshakeAlreadyStarted();
+ }
+ startDriverHandshakeCalled = true;
+ factory = floodlightProvider.getOFMessageFactory_13();
+ // configureSwitch();
+ sendBarrier(true);
+ }
+
+ @Override
+ public boolean isDriverHandshakeComplete() {
+ if (!startDriverHandshakeCalled) {
+ throw new SwitchDriverSubHandshakeNotStarted();
+ }
+ return driverHandshakeComplete.get();
+ }
+
+ @Override
+ public void processDriverHandshakeMessage(OFMessage m) {
+ if (!startDriverHandshakeCalled) {
+ throw new SwitchDriverSubHandshakeNotStarted();
+ }
+ if (driverHandshakeComplete.get()) {
+ throw new SwitchDriverSubHandshakeCompleted(m);
+ }
+
+ if (!startDriverHandshakeCalled) {
+ throw new SwitchDriverSubHandshakeNotStarted();
+ }
+ if (driverHandshakeComplete.get()) {
+ throw new SwitchDriverSubHandshakeCompleted(m);
+ }
+
+ switch (m.getType()) {
+ case BARRIER_REPLY:
+ if (m.getXid() == barrierXidToWaitFor) {
+ driverHandshakeComplete.set(true);
+ }
+ break;
+
+ case ERROR:
+ log.error("Switch {} Error {}", getStringId(), (OFErrorMsg) m);
+ break;
+
+ case FEATURES_REPLY:
+ break;
+ case FLOW_REMOVED:
+ break;
+ case GET_ASYNC_REPLY:
+ OFAsyncGetReply asrep = (OFAsyncGetReply) m;
+ decodeAsyncGetReply(asrep);
+ break;
+
+ case PACKET_IN:
+ break;
+ case PORT_STATUS:
+ break;
+ case QUEUE_GET_CONFIG_REPLY:
+ break;
+ case ROLE_REPLY:
+ break;
+
+ case STATS_REPLY:
+ processStatsReply((OFStatsReply) m);
+ break;
+
+ default:
+ log.debug("Received message {} during switch-driver subhandshake "
+ + "from switch {} ... Ignoring message", m, getStringId());
+
+ }
+ }
+
+ private void configureSwitch() throws IOException {
+ // setAsyncConfig();
+ // getTableFeatures();
+ sendGroupFeaturesRequest();
+ setL2Groups();
+ sendBarrier(false);
+ setL3Groups();
+ setL25Groups();
+ sendGroupDescRequest();
+ populateTableVlan();
+ populateTableTMac();
+ populateIpTable();
+ populateMplsTable();
+ populateTableMissEntry(TABLE_ACL, false, false, false, -1);
+ sendBarrier(true);
+ }
+
+ private void setAsyncConfig() throws IOException {
+ List<OFMessage> msglist = new ArrayList<OFMessage>(3);
+ OFMessage setAC = null;
+
+ if (role == Role.MASTER) {
+ setAC = factory.buildAsyncSet()
+ .setFlowRemovedMaskEqualMaster(SET_FLOW_REMOVED_MASK_MASTER)
+ .setPacketInMaskEqualMaster(SET_PACKET_IN_MASK_MASTER)
+ .setPortStatusMaskEqualMaster(SET_PORT_STATUS_MASK_MASTER)
+ .setFlowRemovedMaskSlave(SET_ALL_SLAVE)
+ .setPacketInMaskSlave(SET_ALL_SLAVE)
+ .setPortStatusMaskSlave(SET_ALL_SLAVE)
+ .setXid(getNextTransactionId())
+ .build();
+ } else if (role == Role.EQUAL) {
+ setAC = factory.buildAsyncSet()
+ .setFlowRemovedMaskEqualMaster(SET_FLOW_REMOVED_MASK_EQUAL)
+ .setPacketInMaskEqualMaster(SET_PACKET_IN_MASK_EQUAL)
+ .setPortStatusMaskEqualMaster(SET_PORT_STATUS_MASK_EQUAL)
+ .setFlowRemovedMaskSlave(SET_ALL_SLAVE)
+ .setPacketInMaskSlave(SET_ALL_SLAVE)
+ .setPortStatusMaskSlave(SET_ALL_SLAVE)
+ .setXid(getNextTransactionId())
+ .build();
+ }
+ msglist.add(setAC);
+
+ OFMessage br = factory.buildBarrierRequest()
+ .setXid(getNextTransactionId())
+ .build();
+ msglist.add(br);
+
+ OFMessage getAC = factory.buildAsyncGetRequest()
+ .setXid(getNextTransactionId())
+ .build();
+ msglist.add(getAC);
+
+ write(msglist);
+ }
+
+ private void decodeAsyncGetReply(OFAsyncGetReply rep) {
+ long frm = rep.getFlowRemovedMaskEqualMaster();
+ //long frs = rep.getFlowRemovedMaskSlave();
+ long pim = rep.getPacketInMaskEqualMaster();
+ //long pis = rep.getPacketInMaskSlave();
+ long psm = rep.getPortStatusMaskEqualMaster();
+ //long pss = rep.getPortStatusMaskSlave();
+
+ if (role == Role.MASTER || role == Role.EQUAL) { // should separate
+ log.info("FRM:{}", HexString.toHexString((frm & TEST_FLOW_REMOVED_MASK)));
+ log.info("PIM:{}", HexString.toHexString((pim & TEST_PACKET_IN_MASK)));
+ log.info("PSM:{}", HexString.toHexString((psm & TEST_PORT_STATUS_MASK)));
+ }
+
+ }
+
+ private void getTableFeatures() throws IOException {
+ OFMessage gtf = factory.buildTableFeaturesStatsRequest()
+ .setXid(getNextTransactionId())
+ .build();
+ write(gtf, null);
+ }
+
+ private void sendGroupFeaturesRequest() throws IOException {
+ OFMessage gfr = factory.buildGroupFeaturesStatsRequest()
+ .setXid(getNextTransactionId())
+ .build();
+ write(gfr, null);
+ }
+
+ private void sendGroupDescRequest() throws IOException {
+ OFMessage gdr = factory.buildGroupDescStatsRequest()
+ .setXid(getNextTransactionId())
+ .build();
+ write(gdr, null);
+ }
+
+ /*Create L2 interface groups for all physical ports
+ Naming convention followed is the same as OF-DPA spec
+ eg. port 1 with allowed vlan 10, is enveloped in group with id,
+ 0x0 00a 0001, where the uppermost 4 bits identify an L2 interface,
+ the next 12 bits identify the vlan-id, and the lowermost 16 bits
+ identify the port number.*/
+ private void setL2Groups() throws IOException {
+ List<OFMessage> msglist = new ArrayList<OFMessage>();
+ for (OFPortDesc p : getPorts()) {
+ int pnum = p.getPortNo().getPortNumber();
+ int portVlan = getVlanConfig(pnum);
+ if (U32.of(pnum).compareTo(U32.of(OFPort.MAX.getPortNumber())) < 1) {
+ OFGroup gl2 = OFGroup.of(pnum | (portVlan << VLAN_ID_OFFSET));
+ OFAction out = factory.actions().buildOutput()
+ .setPort(p.getPortNo()).build();
+ OFAction popVlan = factory.actions().popVlan();
+ List<OFAction> actions = new ArrayList<OFAction>();
+ actions.add(popVlan);
+ actions.add(out);
+ OFBucket bucket = factory.buildBucket()
+ .setActions(actions).build();
+ List<OFBucket> buckets = Collections.singletonList(bucket);
+ OFMessage gmAdd = factory.buildGroupAdd()
+ .setGroup(gl2)
+ .setBuckets(buckets)
+ .setGroupType(OFGroupType.INDIRECT)
+ .setXid(getNextTransactionId())
+ .build();
+ msglist.add(gmAdd);
+ l2groups.put(pnum, gl2);
+ }
+ }
+ log.debug("Creating {} L2 groups in sw {}", msglist.size(), getStringId());
+ write(msglist);
+ }
+
+ private int getVlanConfig(int portnum) {
+ int portVlan = 10 * portnum;
+ if ((getId() == 0x1 && portnum == 6) ||
+ (getId() == 0x2) ||
+ (getId() == 0x3 && portnum == 2)) {
+ portVlan = 192; // 0xc0
+ }
+ return portVlan;
+ }
+
+ private MacAddress getRouterMacAddr() {
+ if (getId() == 0x3) {
+ return MacAddress.of("00:00:07:07:07:80"); // router mac
+ }
+ if (getId() == 0x1) {
+ return MacAddress.of("00:00:01:01:01:80");
+ }
+ // switch 0x2
+ return MacAddress.of("00:00:02:02:02:80");
+ }
+
+ // only for ports connected to other routers
+ private OFAction getDestAction(int portnum) {
+ OFAction setDA = null;
+ MacAddress dAddr = null;
+ if (getId() == 0x1 && portnum == 6) { // connected to switch 2
+ dAddr = MacAddress.of("00:00:02:02:02:80");
+ }
+ if (getId() == 0x2) {
+ if (portnum == 1) { // connected to sw 1
+ dAddr = MacAddress.of("00:00:01:01:01:80");
+ } else if (portnum == 2) { // connected to sw 3
+ dAddr = MacAddress.of("00:00:07:07:07:80");
+ }
+ }
+ if (getId() == 0x3) {
+ if (portnum == 2) { // connected to switch 2
+ dAddr = MacAddress.of("00:00:02:02:02:80");
+ }
+ }
+
+ if (dAddr != null) {
+ OFOxmEthDst dstAddr = factory.oxms().ethDst(dAddr);
+ setDA = factory.actions().buildSetField()
+ .setField(dstAddr).build();
+ }
+ return setDA;
+ }
+
+ /*
+ * L3 groups are created for all router ports and they all point to corresponding
+ * L2 groups. Only the ports that connect to other routers will have the
+ * DA set.
+ */
+ private void setL3Groups() throws IOException {
+ List<OFMessage> msglist = new ArrayList<OFMessage>();
+ for (OFGroup gl2 : l2groups.values()) {
+ int gnum = gl2.getGroupNumber();
+ int portnum = gnum & 0x0000ffff;
+ int vlanid = ((gnum & 0x0fff0000) >> VLAN_ID_OFFSET);
+ MacAddress sAddr = getRouterMacAddr();
+
+ OFGroup gl3 = OFGroup.of(0x20000000 | portnum);
+ OFAction group = factory.actions().buildGroup()
+ .setGroup(gl2).build();
+ OFOxmEthSrc srcAddr = factory.oxms().ethSrc(sAddr);
+ OFAction setSA = factory.actions().buildSetField()
+ .setField(srcAddr).build();
+ OFOxmVlanVid vid = factory.oxms().vlanVid(OFVlanVidMatch.ofVlan(vlanid));
+ OFAction setVlan = factory.actions().buildSetField()
+ .setField(vid).build();
+ OFAction decTtl = factory.actions().decNwTtl();
+
+ List<OFAction> actions = new ArrayList<OFAction>();
+ actions.add(decTtl); // decrement the IP TTL/do-checksum/check TTL
+ // and MTU
+ actions.add(setVlan); // set the vlan-id of the exit-port (and
+ // l2group)
+ actions.add(setSA); // set this routers mac address
+ // make L3Unicast group setDA for known (configured) ports
+ // that connect to other routers
+ OFAction setDA = getDestAction(portnum);
+ if (setDA != null) {
+ actions.add(setDA);
+ }
+ actions.add(group);
+
+ OFBucket bucket = factory.buildBucket()
+ .setActions(actions).build();
+ List<OFBucket> buckets = Collections.singletonList(bucket);
+ OFMessage gmAdd = factory.buildGroupAdd()
+ .setGroup(gl3)
+ .setBuckets(buckets)
+ .setGroupType(OFGroupType.INDIRECT)
+ .setXid(getNextTransactionId())
+ .build();
+ msglist.add(gmAdd);
+ }
+ write(msglist);
+ log.debug("Creating {} L3 groups in sw {}", msglist.size(), getStringId());
+ }
+
+ /*
+ * L2.5 or mpls-unicast groups are only created for those router ports
+ * connected to other router ports. They differ from the corresponding
+ * L3-unicast group only by the fact that they decrement the MPLS TTL
+ * instead of the IP ttl
+ */
+ private void setL25Groups() throws IOException {
+ List<OFMessage> msglist = new ArrayList<OFMessage>();
+ for (OFGroup gl2 : l2groups.values()) {
+ int gnum = gl2.getGroupNumber();
+ int portnum = gnum & 0x0000ffff;
+ int vlanid = ((gnum & 0x0fff0000) >> VLAN_ID_OFFSET);
+ MacAddress sAddr = getRouterMacAddr();
+ OFAction setDA = getDestAction(portnum);
+ // setDA will only be non-null for ports connected to routers
+ if (setDA != null) {
+ OFGroup gl3 = OFGroup.of(0xa0000000 | portnum); // different id
+ // for mpls
+ // group
+ OFAction group = factory.actions().buildGroup()
+ .setGroup(gl2).build();
+ OFOxmEthSrc srcAddr = factory.oxms().ethSrc(sAddr);
+ OFAction setSA = factory.actions().buildSetField()
+ .setField(srcAddr).build();
+ OFOxmVlanVid vid = factory.oxms().vlanVid(OFVlanVidMatch.ofVlan(vlanid));
+ OFAction setVlan = factory.actions().buildSetField()
+ .setField(vid).build();
+ OFAction decMplsTtl = factory.actions().decMplsTtl();
+ List<OFAction> actions = new ArrayList<OFAction>();
+ actions.add(decMplsTtl); // decrement the MPLS
+ // TTL/do-checksum/check TTL and MTU
+ actions.add(setVlan); // set the vlan-id of the exit-port (and
+ // l2group)
+ actions.add(setSA); // set this routers mac address
+ actions.add(setDA);
+ actions.add(group);
+ OFBucket bucket = factory.buildBucket()
+ .setActions(actions).build();
+ List<OFBucket> buckets = Collections.singletonList(bucket);
+ OFMessage gmAdd = factory.buildGroupAdd()
+ .setGroup(gl3)
+ .setBuckets(buckets)
+ .setGroupType(OFGroupType.INDIRECT)
+ .setXid(getNextTransactionId())
+ .build();
+ msglist.add(gmAdd);
+ }
+ }
+ write(msglist);
+ log.debug("Creating {} MPLS groups in sw {}", msglist.size(), getStringId());
+ }
+
+ /* Using ECMP groups
+ *
+ * OFGroup group47 = OFGroup.of(47);
+ OFAction outgroup1 = factory.actions()
+ .buildGroup()
+ .setGroup(group61)
+ .build();
+ OFBucket buc47_1 = factory.buildBucket()
+ .setWeight(1)
+ .setActions(Collections.singletonList(outgroup1))
+ .build();
+ OFAction outgroup2 = factory.actions()
+ .buildGroup()
+ .setGroup(group62)
+ .build();
+ OFBucket buc47_2 = factory.buildBucket()
+ .setWeight(1)
+ .setActions(Collections.singletonList(outgroup2))
+ .build();
+ List<OFBucket> buckets47 = new ArrayList<OFBucket>();
+ buckets47.add(buc47_1);
+ buckets47.add(buc47_2);
+ OFMessage gmS12 = factory.buildGroupAdd()
+ .setGroup(group47)
+ .setBuckets(buckets47)
+ .setGroupType(OFGroupType.SELECT)
+ .setXid(getNextTransactionId())
+ .build();
+ write(gmS12, null); */
+
+ private void processStatsReply(OFStatsReply sr) {
+ switch (sr.getStatsType()) {
+ case AGGREGATE:
+ break;
+ case DESC:
+ break;
+ case EXPERIMENTER:
+ break;
+ case FLOW:
+ break;
+ case GROUP_DESC:
+ processGroupDesc((OFGroupDescStatsReply) sr);
+ break;
+ case GROUP_FEATURES:
+ processGroupFeatures((OFGroupFeaturesStatsReply) sr);
+ break;
+ case METER_CONFIG:
+ break;
+ case METER_FEATURES:
+ break;
+ case PORT_DESC:
+ break;
+ case TABLE_FEATURES:
+ break;
+ default:
+ break;
+
+ }
+ }
+
+ private void processGroupFeatures(OFGroupFeaturesStatsReply gfsr) {
+ log.info("Sw: {} Group Features {}", getStringId(), gfsr);
+ }
+
+ private void processGroupDesc(OFGroupDescStatsReply gdsr) {
+ log.info("Sw: {} Group Desc {}", getStringId(), gdsr);
+ }
+
+ private void populateTableVlan() throws IOException {
+ // for all incoming ports assign configured port-vlans
+ // currently assign portnum*10 -> vlanid to access ports
+ // and vlan 192 to router to router ports
+ List<OFMessage> msglist = new ArrayList<OFMessage>();
+ for (OFPortDesc p : getPorts()) {
+ int pnum = p.getPortNo().getPortNumber();
+ if (U32.of(pnum).compareTo(U32.of(OFPort.MAX.getPortNumber())) < 1) {
+ int vlanid = getVlanConfig(pnum);
+ OFOxmInPort oxp = factory.oxms().inPort(p.getPortNo());
+ OFOxmVlanVid oxv = factory.oxms()
+ .vlanVid(OFVlanVidMatch.UNTAGGED);
+ OFOxmList oxmList = OFOxmList.of(oxp, oxv);
+ OFMatchV3 match = factory.buildMatchV3()
+ .setOxmList(oxmList).build();
+ OFOxmVlanVid vidToSet = factory.oxms()
+ .vlanVid(OFVlanVidMatch.ofVlan(vlanid));
+ OFAction pushVlan = factory.actions().pushVlan(EthType.VLAN_FRAME);
+ OFAction setVlan = factory.actions().setField(vidToSet);
+ List<OFAction> actionlist = new ArrayList<OFAction>();
+ actionlist.add(pushVlan);
+ actionlist.add(setVlan);
+ OFInstruction appAction = factory.instructions().buildApplyActions()
+ .setActions(actionlist).build();
+ OFInstruction gotoTbl = factory.instructions().buildGotoTable()
+ .setTableId(TableId.of(TABLE_TMAC)).build();
+ List<OFInstruction> instructions = new ArrayList<OFInstruction>();
+ instructions.add(appAction);
+ instructions.add(gotoTbl);
+ OFMessage flowEntry = factory.buildFlowAdd()
+ .setTableId(TableId.of(TABLE_VLAN))
+ .setMatch(match)
+ .setInstructions(instructions)
+ .setPriority(1000) // does not matter - all rules
+ // exclusive
+ .setBufferId(OFBufferId.NO_BUFFER)
+ .setIdleTimeout(0)
+ .setHardTimeout(0)
+ .setXid(getNextTransactionId())
+ .build();
+ msglist.add(flowEntry);
+ }
+ }
+ // table-vlan has no table-miss entry, and so packets that miss are
+ // essentially dropped
+ write(msglist);
+ log.debug("Adding {} vlan-rules in sw {}", msglist.size(), getStringId());
+ }
+
+ private void populateTableTMac() throws IOException {
+ // match for ip packets
+ OFOxmEthType oxe = factory.oxms().ethType(EthType.IPv4);
+ OFOxmList oxmListIp = OFOxmList.of(oxe);
+ OFMatchV3 matchIp = factory.buildMatchV3()
+ .setOxmList(oxmListIp).build();
+ OFInstruction gotoTblIp = factory.instructions().buildGotoTable()
+ .setTableId(TableId.of(TABLE_IPV4_UNICAST)).build();
+ List<OFInstruction> instructionsIp = Collections.singletonList(gotoTblIp);
+ OFMessage ipEntry = factory.buildFlowAdd()
+ .setTableId(TableId.of(TABLE_TMAC))
+ .setMatch(matchIp)
+ .setInstructions(instructionsIp)
+ .setPriority(1000) // strict priority required lower than
+ // multicastMac
+ .setBufferId(OFBufferId.NO_BUFFER)
+ .setIdleTimeout(0)
+ .setHardTimeout(0)
+ .setXid(getNextTransactionId())
+ .build();
+
+ // match for mpls packets
+ OFOxmEthType oxmpls = factory.oxms().ethType(EthType.MPLS_UNICAST);
+ OFOxmList oxmListMpls = OFOxmList.of(oxmpls);
+ OFMatchV3 matchMpls = factory.buildMatchV3()
+ .setOxmList(oxmListMpls).build();
+ OFInstruction gotoTblMpls = factory.instructions().buildGotoTable()
+ .setTableId(TableId.of(TABLE_MPLS)).build();
+ List<OFInstruction> instructionsMpls = Collections.singletonList(gotoTblMpls);
+ OFMessage mplsEntry = factory.buildFlowAdd()
+ .setTableId(TableId.of(TABLE_TMAC))
+ .setMatch(matchMpls)
+ .setInstructions(instructionsMpls)
+ .setPriority(1001) // strict priority required lower than
+ // multicastMac
+ .setBufferId(OFBufferId.NO_BUFFER)
+ .setIdleTimeout(0)
+ .setHardTimeout(0)
+ .setXid(getNextTransactionId())
+ .build();
+
+ // match for everything else to send to controller. Essentially
+ // the table miss flow entry
+ populateTableMissEntry(TABLE_TMAC, true, false, false, -1);
+ log.debug("Adding termination-mac-rules in sw {}", getStringId());
+ List<OFMessage> msglist = new ArrayList<OFMessage>(2);
+ msglist.add(ipEntry);
+ msglist.add(mplsEntry);
+ write(msglist);
+ }
+
+ private List<String> getMyIps() { // send to controller
+ List<String> myIps = new ArrayList<String>();
+ if (getId() == 0x1) {
+ myIps.add("10.0.2.128");
+ myIps.add("10.0.3.128");
+ myIps.add("10.0.1.128");
+ myIps.add("192.168.0.1");
+ }
+ if (getId() == 0x2) {
+ myIps.add("192.168.0.2");
+ }
+ if (getId() == 0x3) {
+ myIps.add("192.168.0.3");
+ myIps.add("7.7.7.128");
+ }
+ return myIps;
+ }
+
+ private List<String> getMySubnetIps() { // send to controller
+ List<String> subnetIps = new ArrayList<String>();
+ if (getId() == 0x1) {
+ subnetIps.add("10.0.2.0");
+ subnetIps.add("10.0.3.0");
+ subnetIps.add("10.0.1.0");
+ }
+ // TODO needed?
+ //if (getId() == 0x2) {
+ //}
+ if (getId() == 0x3) {
+ subnetIps.add("7.7.7.0");
+ }
+ return subnetIps;
+ }
+
+ private static class RouteEntry {
+ String prefix;
+ String mask;
+ int nextHopPort;
+ String dstMac;
+ int label;
+
+ public RouteEntry(String prefix, String mask, int nextHopPort, int label) {
+ this.prefix = prefix;
+ this.mask = mask;
+ this.nextHopPort = nextHopPort;
+ this.label = label;
+ }
+
+ public RouteEntry(String prefix, int nextHopPort, String dstMac) {
+ this.prefix = prefix;
+ this.nextHopPort = nextHopPort;
+ this.dstMac = dstMac;
+ }
+ }
+
+ // send out of mpls-group where the next-hop mac-da is already set
+ private List<RouteEntry> getRouterNextHopIps() {
+ List<RouteEntry> routerNextHopIps = new ArrayList<RouteEntry>();
+ if (getId() == 0x1) {
+ routerNextHopIps
+ .add(new RouteEntry("192.168.0.2", "255.255.255.255", 6, 102));
+ routerNextHopIps
+ .add(new RouteEntry("192.168.0.3", "255.255.255.255", 6, 103));
+ routerNextHopIps.add(new RouteEntry("7.7.7.0", "255.255.255.0", 6, 103));
+ }
+ //if (getId() == 0x2) {
+ /* These are required for normal IP routing without labels.
+ routerNextHopIps.add(new RouteEntry("192.168.0.1","255.255.255.255",1));
+ routerNextHopIps.add(new RouteEntry("192.168.0.3","255.255.255.255",2));
+ routerNextHopIps.add(new RouteEntry("10.0.1.0","255.255.255.0",1));
+ routerNextHopIps.add(new RouteEntry("10.0.2.0","255.255.255.0",1));
+ routerNextHopIps.add(new RouteEntry("10.0.3.0","255.255.255.0",1));
+ routerNextHopIps.add(new RouteEntry("7.7.7.0","255.255.255.0",2));*/
+ //}
+ if (getId() == 0x3) {
+ routerNextHopIps
+ .add(new RouteEntry("192.168.0.2", "255.255.255.255", 2, 102));
+ routerNextHopIps
+ .add(new RouteEntry("192.168.0.1", "255.255.255.255", 2, 101));
+ routerNextHopIps.add(new RouteEntry("10.0.1.0", "255.255.255.0", 2, 101));
+ routerNextHopIps.add(new RouteEntry("10.0.2.0", "255.255.255.0", 2, 101));
+ routerNextHopIps.add(new RouteEntry("10.0.3.0", "255.255.255.0", 2, 101));
+ }
+ return routerNextHopIps;
+ }
+
+ // known host mac-addr, setDA/send out of l3group
+ private List<RouteEntry> getHostNextHopIps() {
+ List<RouteEntry> hostNextHopIps = new ArrayList<RouteEntry>();
+ if (getId() == 0x1) {
+ hostNextHopIps.add(new RouteEntry("10.0.2.1", 4, "00:00:00:00:02:01"));
+ hostNextHopIps.add(new RouteEntry("10.0.3.1", 5, "00:00:00:00:03:01"));
+ }
+ // TODO needed?
+ //if (getId() == 0x2) {
+ //}
+ if (getId() == 0x3) {
+ hostNextHopIps.add(new RouteEntry("7.7.7.7", 1, "00:00:07:07:07:07"));
+ }
+ return hostNextHopIps;
+ }
+
+ private void populateIpTable() throws IOException {
+ populateMyIps();
+ populateMySubnets();
+ populateRoutes();
+ populateHostRoutes();
+
+ // match for everything else to send to ACL table. Essentially
+ // the table miss flow entry
+ populateTableMissEntry(TABLE_IPV4_UNICAST, false, true,
+ true, TABLE_ACL);
+ }
+
+ private void populateMyIps() throws IOException {
+ List<OFMessage> msglist = new ArrayList<OFMessage>();
+ // first all my ip's as exact-matches
+ // write-action instruction to send to controller
+ List<String> myIps = getMyIps();
+ for (int i = 0; i < myIps.size(); i++) {
+ OFOxmEthType ethTypeIp = factory.oxms()
+ .ethType(EthType.IPv4);
+ OFOxmIpv4DstMasked ipPrefix = factory.oxms()
+ .ipv4DstMasked(IPv4Address.of(myIps.get(i)), IPv4Address.NO_MASK);
+ OFOxmList oxmListSlash32 = OFOxmList.of(ethTypeIp, ipPrefix);
+ OFMatchV3 match = factory.buildMatchV3()
+ .setOxmList(oxmListSlash32).build();
+ OFAction outc = factory.actions().buildOutput()
+ .setPort(OFPort.CONTROLLER).setMaxLen(OFPCML_NO_BUFFER)
+ .build();
+ OFInstruction writeInstr = factory.instructions().buildWriteActions()
+ .setActions(Collections.singletonList(outc)).build();
+ OFInstruction gotoInstr = factory.instructions().buildGotoTable()
+ .setTableId(TableId.of(TABLE_ACL)).build();
+ List<OFInstruction> instructions = new ArrayList<OFInstruction>();
+ instructions.add(writeInstr);
+ instructions.add(gotoInstr);
+ OFMessage myIpEntry = factory.buildFlowAdd()
+ .setTableId(TableId.of(TABLE_IPV4_UNICAST))
+ .setMatch(match)
+ .setInstructions(instructions)
+ .setPriority(MAX_PRIORITY) // highest priority for exact
+ // match
+ .setBufferId(OFBufferId.NO_BUFFER)
+ .setIdleTimeout(0)
+ .setHardTimeout(0)
+ .setXid(getNextTransactionId())
+ .build();
+ msglist.add(myIpEntry);
+ }
+ write(msglist);
+ log.debug("Adding {} my-ip-rules in sw {}", msglist.size(), getStringId());
+ }
+
+ private void populateMySubnets() throws IOException {
+ List<OFMessage> msglist = new ArrayList<OFMessage>();
+ // next prefix-based subnet-IP's configured on my interfaces
+ // need to ARP for exact-IP, so write-action instruction to send to
+ // controller
+ // this has different mask and priority than earlier case
+ List<String> subnetIps = getMySubnetIps();
+ for (int i = 0; i < subnetIps.size(); i++) {
+ OFOxmEthType ethTypeIp = factory.oxms()
+ .ethType(EthType.IPv4);
+ OFOxmIpv4DstMasked ipPrefix = factory.oxms().ipv4DstMasked(
+ IPv4Address.of(subnetIps.get(i)),
+ IPv4Address.of(0xffffff00)); // '/24' mask
+ OFOxmList oxmListSlash24 = OFOxmList.of(ethTypeIp, ipPrefix);
+ OFMatchV3 match = factory.buildMatchV3()
+ .setOxmList(oxmListSlash24).build();
+ OFAction outc = factory.actions().buildOutput()
+ .setPort(OFPort.CONTROLLER).setMaxLen(OFPCML_NO_BUFFER)
+ .build();
+ OFInstruction writeInstr = factory.instructions().buildWriteActions()
+ .setActions(Collections.singletonList(outc)).build();
+ OFInstruction gotoInstr = factory.instructions().buildGotoTable()
+ .setTableId(TableId.of(TABLE_ACL)).build();
+ List<OFInstruction> instructions = new ArrayList<OFInstruction>();
+ instructions.add(writeInstr);
+ instructions.add(gotoInstr);
+ OFMessage myIpEntry = factory.buildFlowAdd()
+ .setTableId(TableId.of(TABLE_IPV4_UNICAST))
+ .setMatch(match)
+ .setInstructions(instructions)
+ .setPriority(SLASH_24_PRIORITY)
+ .setBufferId(OFBufferId.NO_BUFFER)
+ .setIdleTimeout(0)
+ .setHardTimeout(0)
+ .setXid(getNextTransactionId())
+ .build();
+ msglist.add(myIpEntry);
+ }
+ write(msglist);
+ log.debug("Adding {} subnet-ip-rules in sw {}", msglist.size(), getStringId());
+ msglist.clear();
+ }
+
+ private void populateRoutes() throws IOException {
+ List<OFMessage> msglist = new ArrayList<OFMessage>();
+ // addresses where I know the next-hop's mac-address because it is a
+ // router port - so I have an L3 interface to it (and an MPLS interface)
+ List<RouteEntry> routerNextHopIps = getRouterNextHopIps();
+ for (int i = 0; i < routerNextHopIps.size(); i++) {
+ OFOxmEthType ethTypeIp = factory.oxms()
+ .ethType(EthType.IPv4);
+ OFOxmIpv4DstMasked ipPrefix = factory.oxms()
+ .ipv4DstMasked(
+ IPv4Address.of(routerNextHopIps.get(i).prefix),
+ IPv4Address.of(routerNextHopIps.get(i).mask)
+ );
+ OFOxmList oxmListSlash32 = OFOxmList.of(ethTypeIp, ipPrefix);
+ OFMatchV3 match = factory.buildMatchV3()
+ .setOxmList(oxmListSlash32).build();
+ OFAction outg = factory.actions().buildGroup()
+ .setGroup(OFGroup.of(0xa0000000 | // mpls group id
+ routerNextHopIps.get(i).nextHopPort))
+ .build();
+ // lots of actions before forwarding to mpls group, and
+ // unfortunately
+ // they need to be apply-actions
+
+ OFAction pushlabel = factory.actions().pushMpls(EthType.MPLS_UNICAST);
+ OFOxmMplsLabel l = factory.oxms()
+ .mplsLabel(U32.of(routerNextHopIps.get(i).label));
+ OFAction setlabelid = factory.actions().buildSetField()
+ .setField(l).build();
+ OFAction copyTtlOut = factory.actions().copyTtlOut();
+ // OFAction setBos =
+ // factory.actions().buildSetField().setField(bos).build();
+
+ /*
+ writeActions.add(pushlabel); // need to be apply actions so can be
+ writeActions.add(copyTtlOut); // matched in pseudo-table
+ //writeActions.add(setlabelid); // bad support in cpqd
+ //writeActions.add(setBos); no support in loxigen
+ */
+
+ List<OFAction> applyActions = new ArrayList<OFAction>();
+ applyActions.add(pushlabel);
+ applyActions.add(copyTtlOut);
+ OFInstruction applyInstr = factory.instructions().buildApplyActions()
+ .setActions(applyActions).build();
+ List<OFAction> writeActions = new ArrayList<OFAction>();
+ writeActions.add(outg); // group will decr mpls-ttl, set mac-sa/da,
+ // vlan
+ OFInstruction writeInstr = factory.instructions().buildWriteActions()
+ .setActions(writeActions).build();
+
+ // necessary to match in pseudo-table to overcome cpqd 1.3 flaw
+ OFInstruction writeMeta = factory.instructions().buildWriteMetadata()
+ .setMetadata(U64.of(routerNextHopIps.get(i).label))
+ .setMetadataMask(METADATA_MASK).build();
+ /*OFInstruction gotoInstr = factory.instructions().buildGotoTable()
+ .setTableId(TableId.of(TABLE_ACL)).build();*/
+ OFInstruction gotoInstr = factory.instructions().buildGotoTable()
+ .setTableId(TableId.of(TABLE_META)).build();
+ List<OFInstruction> instructions = new ArrayList<OFInstruction>();
+ instructions.add(applyInstr);
+ // instructions.add(writeInstr);// cannot write here - causes switch
+ // to crash
+ instructions.add(writeMeta);
+ instructions.add(gotoInstr);
+
+ int priority = -1;
+ if (routerNextHopIps.get(i).mask.equals("255.255.255.255")) {
+ priority = MAX_PRIORITY;
+ } else {
+ priority = SLASH_24_PRIORITY;
+ }
+ OFMessage myIpEntry = factory.buildFlowAdd()
+ .setTableId(TableId.of(TABLE_IPV4_UNICAST))
+ .setMatch(match)
+ .setInstructions(instructions)
+ .setPriority(priority)
+ .setBufferId(OFBufferId.NO_BUFFER)
+ .setIdleTimeout(0)
+ .setHardTimeout(0)
+ .setXid(getNextTransactionId())
+ .build();
+ msglist.add(myIpEntry);
+
+ // need to also handle psuedo-table entries to match-metadata and
+ // set mpls
+ // label-id
+ OFOxmEthType ethTypeMpls = factory.oxms()
+ .ethType(EthType.MPLS_UNICAST);
+ OFOxmMetadataMasked meta = factory.oxms()
+ .metadataMasked(
+ OFMetadata.ofRaw(routerNextHopIps.get(i).label),
+ OFMetadata.NO_MASK);
+ OFOxmList oxmListMeta = OFOxmList.of(ethTypeMpls, meta);
+ OFMatchV3 matchMeta = factory.buildMatchV3()
+ .setOxmList(oxmListMeta).build();
+ List<OFAction> writeActions2 = new ArrayList<OFAction>();
+ writeActions2.add(setlabelid);
+ OFAction outg2 = factory.actions().buildGroup()
+ .setGroup(OFGroup.of(routerNextHopIps.get(i).nextHopPort |
+ (192 << VLAN_ID_OFFSET)))
+ .build();
+ writeActions2.add(outg2);
+ OFInstruction writeInstr2 = factory.instructions().buildWriteActions()
+ .setActions(writeActions2).build();
+ OFInstruction gotoInstr2 = factory.instructions().buildGotoTable()
+ .setTableId(TableId.of(TABLE_ACL)).build();
+ List<OFInstruction> instructions2 = new ArrayList<OFInstruction>();
+ // unfortunately have to apply this action too
+ OFInstruction applyInstr2 = factory.instructions().buildApplyActions()
+ .setActions(writeActions2).build();
+ instructions2.add(applyInstr2);
+ // instructions2.add(writeInstr2);
+ // instructions2.add(gotoInstr2);
+
+ /*OFMatchV3 match3 = factory.buildMatchV3()
+ .setOxmList(OFOxmList.of(meta)).build();
+ OFInstruction clearInstruction = factory.instructions().clearActions();
+ List<OFInstruction> instructions3 = new ArrayList<OFInstruction>();
+ OFAction outc = factory.actions().buildOutput()
+ .setPort(OFPort.CONTROLLER).setMaxLen(OFPCML_NO_BUFFER)
+ .build();
+ OFInstruction writec = factory.instructions()
+ .writeActions(Collections.singletonList(outc));
+ instructions3.add(clearInstruction);
+ instructions3.add(writec);
+ instructions3.add(gotoInstr2); */
+ OFMessage myMetaEntry = factory.buildFlowAdd()
+ .setTableId(TableId.of(TABLE_META))
+ .setMatch(matchMeta)
+ .setInstructions(instructions2)
+ .setPriority(MAX_PRIORITY)
+ .setBufferId(OFBufferId.NO_BUFFER)
+ .setIdleTimeout(0)
+ .setHardTimeout(0)
+ .setXid(getNextTransactionId())
+ .build();
+ msglist.add(myMetaEntry);
+
+ }
+ write(msglist);
+ log.debug("Adding {} next-hop-router-rules in sw {}", msglist.size(),
+ getStringId());
+
+ // add a table-miss entry to table 4 for debugging - leave it out
+ // unclear packet state - causes switch to crash
+ // populateTableMissEntry(TABLE_META, false, true,
+ // true, TABLE_ACL);
+ }
+
+ private void populateHostRoutes() throws IOException {
+ List<OFMessage> msglist = new ArrayList<OFMessage>();
+ // addresses where I know the next hop's mac-address and I can set the
+ // destination mac in the match-instruction.write-action
+ // either I sent out arp-request or I got an arp-request from this host
+ List<RouteEntry> hostNextHopIps = getHostNextHopIps();
+ for (int i = 0; i < hostNextHopIps.size(); i++) {
+ OFOxmEthType ethTypeIp = factory.oxms()
+ .ethType(EthType.IPv4);
+ OFOxmIpv4DstMasked ipPrefix = factory.oxms()
+ .ipv4DstMasked(
+ IPv4Address.of(hostNextHopIps.get(i).prefix),
+ IPv4Address.NO_MASK); // host addr should be /32
+ OFOxmList oxmListSlash32 = OFOxmList.of(ethTypeIp, ipPrefix);
+ OFMatchV3 match = factory.buildMatchV3()
+ .setOxmList(oxmListSlash32).build();
+ OFAction setDmac = null, outg = null;
+ OFOxmEthDst dmac = factory.oxms()
+ .ethDst(MacAddress.of(hostNextHopIps.get(i).dstMac));
+ setDmac = factory.actions().buildSetField()
+ .setField(dmac).build();
+ outg = factory.actions().buildGroup()
+ .setGroup(OFGroup.of(0x20000000 | hostNextHopIps.get(i).nextHopPort)) // l3group
+ // id
+ .build();
+ List<OFAction> writeActions = new ArrayList<OFAction>();
+ writeActions.add(setDmac);
+ writeActions.add(outg);
+ OFInstruction writeInstr = factory.instructions().buildWriteActions()
+ .setActions(writeActions).build();
+ OFInstruction gotoInstr = factory.instructions().buildGotoTable()
+ .setTableId(TableId.of(TABLE_ACL)).build();
+ List<OFInstruction> instructions = new ArrayList<OFInstruction>();
+ instructions.add(writeInstr);
+ instructions.add(gotoInstr);
+ OFMessage myIpEntry = factory.buildFlowAdd()
+ .setTableId(TableId.of(TABLE_IPV4_UNICAST))
+ .setMatch(match)
+ .setInstructions(instructions)
+ .setPriority(MAX_PRIORITY) // highest priority for exact
+ // match
+ .setBufferId(OFBufferId.NO_BUFFER)
+ .setIdleTimeout(0)
+ .setHardTimeout(0)
+ .setXid(getNextTransactionId())
+ .build();
+ msglist.add(myIpEntry);
+ }
+ write(msglist);
+ log.debug("Adding {} next-hop-host-rules in sw {}", msglist.size(), getStringId());
+ }
+
+ private static class MplsEntry {
+ int labelid;
+ int portnum;
+
+ public MplsEntry(int labelid, int portnum) {
+ this.labelid = labelid;
+ this.portnum = portnum;
+ }
+ }
+
+ private List<MplsEntry> getMplsEntries() {
+ List<MplsEntry> myLabels = new ArrayList<MplsEntry>();
+ if (getId() == 0x1) {
+ myLabels.add(new MplsEntry(101, OFPort.CONTROLLER.getPortNumber()));
+ myLabels.add(new MplsEntry(103, 6));
+ }
+ if (getId() == 0x2) {
+ myLabels.add(new MplsEntry(103, 2));
+ myLabels.add(new MplsEntry(102, OFPort.CONTROLLER.getPortNumber()));
+ myLabels.add(new MplsEntry(101, 1));
+ }
+ if (getId() == 0x3) {
+ myLabels.add(new MplsEntry(103, OFPort.CONTROLLER.getPortNumber()));
+ myLabels.add(new MplsEntry(101, 2));
+ }
+ return myLabels;
+ }
+
+ private void populateMplsTable() throws IOException {
+ List<OFMessage> msglist = new ArrayList<OFMessage>();
+ List<MplsEntry> lfibEntries = getMplsEntries();
+ for (int i = 0; i < lfibEntries.size(); i++) {
+ OFOxmEthType ethTypeMpls = factory.oxms()
+ .ethType(EthType.MPLS_UNICAST);
+ OFOxmMplsLabel labelid = factory.oxms()
+ .mplsLabel(U32.of(lfibEntries.get(i).labelid));
+ OFOxmList oxmList = OFOxmList.of(ethTypeMpls, labelid);
+ OFMatchV3 matchlabel = factory.buildMatchV3()
+ .setOxmList(oxmList).build();
+ OFAction poplabel = factory.actions().popMpls(EthType.IPv4);
+ OFAction sendTo = null;
+ if (lfibEntries.get(i).portnum == OFPort.CONTROLLER.getPortNumber()) {
+ sendTo = factory.actions().output(OFPort.CONTROLLER,
+ OFPCML_NO_BUFFER);
+ } else {
+ sendTo = factory.actions().group(OFGroup.of(
+ 0xa0000000 | lfibEntries.get(i).portnum));
+ }
+ List<OFAction> writeActions = new ArrayList<OFAction>();
+ writeActions.add(poplabel);
+ writeActions.add(sendTo);
+ OFInstruction writeInstr = factory.instructions().buildWriteActions()
+ .setActions(writeActions).build();
+ OFInstruction gotoInstr = factory.instructions().buildGotoTable()
+ .setTableId(TableId.of(TABLE_ACL)).build();
+ List<OFInstruction> instructions = new ArrayList<OFInstruction>();
+ instructions.add(writeInstr);
+ instructions.add(gotoInstr);
+ OFMessage myMplsEntry = factory.buildFlowAdd()
+ .setTableId(TableId.of(TABLE_MPLS))
+ .setMatch(matchlabel)
+ .setInstructions(instructions)
+ .setPriority(MAX_PRIORITY) // exact match and exclusive
+ .setBufferId(OFBufferId.NO_BUFFER)
+ .setIdleTimeout(0)
+ .setHardTimeout(0)
+ .setXid(getNextTransactionId())
+ .build();
+ msglist.add(myMplsEntry);
+ }
+ write(msglist);
+ log.debug("Adding {} mpls-forwarding-rules in sw {}", msglist.size(),
+ getStringId());
+
+ // match for everything else to send to ACL table. Essentially
+ // the table miss flow entry
+ populateTableMissEntry(TABLE_MPLS, false, true,
+ true, TABLE_ACL);
+
+ }
+
+ /**
+ * By default if none of the booleans in the call are set, then the
+ * table-miss entry is added with no instructions, which means that pipeline
+ * execution will stop, and the action set associated with the packet will
+ * be executed.
+ *
+ * @param tableToAdd
+ * @param toControllerNow as an APPLY_ACTION instruction
+ * @param toControllerWrite as a WRITE_ACITION instruction
+ * @param toTable as a GOTO_TABLE instruction
+ * @param tableToSend
+ * @throws IOException
+ */
+ @SuppressWarnings("unchecked")
+ private void populateTableMissEntry(int tableToAdd, boolean toControllerNow,
+ boolean toControllerWrite,
+ boolean toTable, int tableToSend) throws IOException {
+ OFOxmList oxmList = OFOxmList.EMPTY;
+ OFMatchV3 match = factory.buildMatchV3()
+ .setOxmList(oxmList)
+ .build();
+ OFAction outc = factory.actions()
+ .buildOutput()
+ .setPort(OFPort.CONTROLLER)
+ .setMaxLen(OFPCML_NO_BUFFER)
+ .build();
+ List<OFInstruction> instructions = new ArrayList<OFInstruction>();
+ if (toControllerNow) {
+ // table-miss instruction to send to controller immediately
+ OFInstruction instr = factory.instructions()
+ .buildApplyActions()
+ .setActions(Collections.singletonList(outc))
+ .build();
+ instructions.add(instr);
+ }
+
+ if (toControllerWrite) {
+ // table-miss instruction to write-action to send to controller
+ // this will be executed whenever the action-set gets executed
+ OFInstruction instr = factory.instructions()
+ .buildWriteActions()
+ .setActions(Collections.singletonList(outc))
+ .build();
+ instructions.add(instr);
+ }
+
+ if (toTable) {
+ // table-miss instruction to goto-table x
+ OFInstruction instr = factory.instructions()
+ .gotoTable(TableId.of(tableToSend));
+ instructions.add(instr);
+ }
+
+ if (!toControllerNow && !toControllerWrite && !toTable) {
+ // table-miss has no instruction - at which point action-set will be
+ // executed - if there is an action to output/group in the action
+ // set
+ // the packet will be sent there, otherwise it will be dropped.
+ instructions = (List<OFInstruction>) Collections.EMPTY_LIST;
+ }
+
+ OFMessage tableMissEntry = factory.buildFlowAdd()
+ .setTableId(TableId.of(tableToAdd))
+ .setMatch(match) // match everything
+ .setInstructions(instructions)
+ .setPriority(MIN_PRIORITY)
+ .setBufferId(OFBufferId.NO_BUFFER)
+ .setIdleTimeout(0)
+ .setHardTimeout(0)
+ .setXid(getNextTransactionId())
+ .build();
+ write(tableMissEntry, null);
+ }
+
+ private void sendBarrier(boolean finalBarrier) throws IOException {
+ int xid = getNextTransactionId();
+ if (finalBarrier) {
+ barrierXidToWaitFor = xid;
+ }
+ OFBarrierRequest br = factory
+ .buildBarrierRequest()
+ .setXid(xid)
+ .build();
+ write(br, null);
+ }
+
+}
diff --git a/src/main/java/net/onrc/onos/core/drivermanager/OFSwitchImplOVS10.java b/src/main/java/net/onrc/onos/core/drivermanager/OFSwitchImplOVS10.java
new file mode 100644
index 0000000..bfe613e
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/drivermanager/OFSwitchImplOVS10.java
@@ -0,0 +1,29 @@
+package net.onrc.onos.core.drivermanager;
+
+import net.floodlightcontroller.core.internal.OFSwitchImplBase;
+
+import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
+
+/**
+ * OFDescriptionStatistics Vendor (Manufacturer Desc.): Nicira, Inc. Make
+ * (Hardware Desc.) : Open vSwitch Model (Datapath Desc.) : None Software :
+ * 1.11.90 (or whatever version + build) Serial : None
+ */
+public class OFSwitchImplOVS10 extends OFSwitchImplBase {
+
+ public OFSwitchImplOVS10(OFDescStatsReply desc) {
+ super();
+ setSwitchDescription(desc);
+ setAttribute(SWITCH_SUPPORTS_NX_ROLE, true);
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "OFSwitchImplOVS10 [" + ((channel != null)
+ ? channel.getRemoteAddress() : "?")
+ + " DPID[" + ((stringId != null) ? stringId : "?") + "]]";
+ }
+}
diff --git a/src/main/java/net/onrc/onos/core/drivermanager/OFSwitchImplOVS13.java b/src/main/java/net/onrc/onos/core/drivermanager/OFSwitchImplOVS13.java
new file mode 100644
index 0000000..efe43a0
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/drivermanager/OFSwitchImplOVS13.java
@@ -0,0 +1,138 @@
+package net.onrc.onos.core.drivermanager;
+
+import java.io.IOException;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import net.floodlightcontroller.core.SwitchDriverSubHandshakeAlreadyStarted;
+import net.floodlightcontroller.core.SwitchDriverSubHandshakeCompleted;
+import net.floodlightcontroller.core.SwitchDriverSubHandshakeNotStarted;
+import net.floodlightcontroller.core.internal.OFSwitchImplBase;
+
+import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
+import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
+import org.projectfloodlight.openflow.protocol.OFErrorMsg;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+
+/**
+ * OFDescriptionStatistics Vendor (Manufacturer Desc.): Nicira, Inc. Make
+ * (Hardware Desc.) : Open vSwitch Model (Datapath Desc.) : None Software :
+ * 2.1.0 (or whatever version + build) Serial : None
+ */
+public class OFSwitchImplOVS13 extends OFSwitchImplBase {
+ private AtomicBoolean driverHandshakeComplete;
+ private OFFactory factory;
+ private long barrierXidToWaitFor = -1;
+
+ public OFSwitchImplOVS13(OFDescStatsReply desc) {
+ super();
+ driverHandshakeComplete = new AtomicBoolean(false);
+ setSwitchDescription(desc);
+ }
+
+ @Override
+ public String toString() {
+ return "OFSwitchImplOVS13 [" + ((channel != null)
+ ? channel.getRemoteAddress() : "?")
+ + " DPID[" + ((stringId != null) ? stringId : "?") + "]]";
+ }
+
+ @Override
+ public void startDriverHandshake() throws IOException {
+ log.debug("Starting driver handshake for sw {}", getStringId());
+ if (startDriverHandshakeCalled) {
+ throw new SwitchDriverSubHandshakeAlreadyStarted();
+ }
+ startDriverHandshakeCalled = true;
+ factory = floodlightProvider.getOFMessageFactory_13();
+ configureSwitch();
+ }
+
+ @Override
+ public boolean isDriverHandshakeComplete() {
+ if (!startDriverHandshakeCalled) {
+ throw new SwitchDriverSubHandshakeNotStarted();
+ }
+ return driverHandshakeComplete.get();
+ }
+
+ @Override
+ public void processDriverHandshakeMessage(OFMessage m) {
+ if (!startDriverHandshakeCalled) {
+ throw new SwitchDriverSubHandshakeNotStarted();
+ }
+ if (driverHandshakeComplete.get()) {
+ throw new SwitchDriverSubHandshakeCompleted(m);
+ }
+
+ switch (m.getType()) {
+ case BARRIER_REPLY:
+ if (m.getXid() == barrierXidToWaitFor) {
+ driverHandshakeComplete.set(true);
+ }
+ break;
+
+ case ERROR:
+ log.error("Switch {} Error {}", getStringId(), (OFErrorMsg) m);
+ break;
+
+ case FEATURES_REPLY:
+ break;
+ case FLOW_REMOVED:
+ break;
+ case GET_ASYNC_REPLY:
+ // OFAsyncGetReply asrep = (OFAsyncGetReply)m;
+ // decodeAsyncGetReply(asrep);
+ break;
+
+ case PACKET_IN:
+ break;
+ case PORT_STATUS:
+ break;
+ case QUEUE_GET_CONFIG_REPLY:
+ break;
+ case ROLE_REPLY:
+ break;
+
+ case STATS_REPLY:
+ // processStatsReply((OFStatsReply) m);
+ break;
+
+ default:
+ log.debug("Received message {} during switch-driver subhandshake "
+ + "from switch {} ... Ignoring message", m, getStringId());
+
+ }
+ }
+
+
+ private void configureSwitch() throws IOException {
+ // setAsyncConfig();
+ // getTableFeatures();
+ /*sendGroupFeaturesRequest();
+ setL2Groups();
+ sendBarrier(false);
+ setL3Groups();
+ setL25Groups();
+ sendGroupDescRequest();*/
+ // populateTableVlan();
+ // populateTableTMac();
+ // populateIpTable();
+ // populateMplsTable();
+ // populateTableMissEntry(TABLE_ACL, false, false, false, -1);
+ sendBarrier(true);
+ }
+
+
+ private void sendBarrier(boolean finalBarrier) throws IOException {
+ int xid = getNextTransactionId();
+ if (finalBarrier) {
+ barrierXidToWaitFor = xid;
+ }
+ OFBarrierRequest br = factory
+ .buildBarrierRequest()
+ .setXid(xid)
+ .build();
+ write(br, null);
+ }
+}
diff --git a/src/main/java/net/onrc/onos/core/flowprogrammer/FlowProgrammer.java b/src/main/java/net/onrc/onos/core/flowprogrammer/FlowProgrammer.java
index 046d130..4a62947 100644
--- a/src/main/java/net/onrc/onos/core/flowprogrammer/FlowProgrammer.java
+++ b/src/main/java/net/onrc/onos/core/flowprogrammer/FlowProgrammer.java
@@ -7,6 +7,7 @@
import net.floodlightcontroller.core.IFloodlightProviderService;
import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.IOFSwitch.PortChangeType;
import net.floodlightcontroller.core.IOFSwitchListener;
import net.floodlightcontroller.core.module.FloodlightModuleContext;
import net.floodlightcontroller.core.module.FloodlightModuleException;
@@ -16,19 +17,20 @@
import net.onrc.onos.core.flowprogrammer.web.FlowProgrammerWebRoutable;
import net.onrc.onos.core.registry.IControllerRegistryService;
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
- * FlowProgrammer is a module responsible to maintain flows installed to switches.
- * FlowProgrammer consists of FlowPusher and FlowSynchronizer.
- * FlowPusher manages the rate of installation, and FlowSynchronizer synchronizes
- * flows between GraphDB and switches.
- * FlowProgrammer also watch the event of addition/deletion of switches to
- * start/stop synchronization. When a switch is added to network, FlowProgrammer
- * immediately kicks synchronization to keep switch's flow table latest state.
- * Adversely, when a switch is removed from network, FlowProgrammer immediately
- * stops synchronization.
+ * FlowProgrammer is a module responsible to maintain flows installed to
+ * switches. FlowProgrammer consists of FlowPusher and FlowSynchronizer.
+ * FlowPusher manages the rate of installation, and FlowSynchronizer
+ * synchronizes flows between GraphDB and switches. FlowProgrammer also watch
+ * the event of addition/deletion of switches to start/stop synchronization.
+ * When a switch is added to network, FlowProgrammer immediately kicks
+ * synchronization to keep switch's flow table latest state. Adversely, when a
+ * switch is removed from network, FlowProgrammer immediately stops
+ * synchronization.
*/
public class FlowProgrammer implements IFloodlightModule,
IOFSwitchListener {
@@ -57,7 +59,7 @@
floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
registryService = context.getServiceImpl(IControllerRegistryService.class);
restApi = context.getServiceImpl(IRestApiService.class);
- pusher.init(null, context, floodlightProvider.getOFMessageFactory(), null);
+ pusher.init(context);
if (ENABLE_FLOW_SYNC) {
synchronizer.init(pusher);
}
@@ -83,8 +85,7 @@
@Override
public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
- Map<Class<? extends IFloodlightService>,
- IFloodlightService> m =
+ Map<Class<? extends IFloodlightService>, IFloodlightService> m =
new HashMap<Class<? extends IFloodlightService>,
IFloodlightService>();
m.put(IFlowPusherService.class, pusher);
@@ -103,25 +104,56 @@
return l;
}
+ // ***********************
+ // IOFSwitchListener
+ // ***********************
+
@Override
public String getName() {
- // TODO Auto-generated method stub
return "FlowProgrammer";
}
@Override
- public void addedSwitch(IOFSwitch sw) {
- log.debug("Switch added: {}", sw.getId());
+ public void switchActivatedMaster(long swId) {
+ IOFSwitch sw = floodlightProvider.getSwitch(swId);
+ if (sw == null) {
+ log.warn("Added switch not available {} ", swId);
+ return;
+ }
+ log.debug("Switch added: {}", swId);
if (ENABLE_FLOW_SYNC) {
- if (registryService.hasControl(sw.getId())) {
+ if (registryService.hasControl(swId)) {
synchronizer.synchronize(sw);
}
}
}
@Override
- public void removedSwitch(IOFSwitch sw) {
+ public void switchActivatedEqual(long swId) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void switchMasterToEqual(long swId) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void switchEqualToMaster(long swId) {
+ // for now treat as switchActivatedMaster
+ switchActivatedMaster(swId);
+ }
+
+ @Override
+ public void switchDisconnected(long swId) {
+ IOFSwitch sw = floodlightProvider.getSwitch(swId);
+ if (sw == null) {
+ log.warn("Removed switch not available {} ", swId);
+ return;
+ }
log.debug("Switch removed: {}", sw.getId());
if (ENABLE_FLOW_SYNC) {
@@ -132,7 +164,7 @@
}
@Override
- public void switchPortChanged(Long switchId) {
+ public void switchPortChanged(long swId, OFPortDesc port, PortChangeType pct) {
// TODO Auto-generated method stub
}
diff --git a/src/main/java/net/onrc/onos/core/flowprogrammer/FlowPusher.java b/src/main/java/net/onrc/onos/core/flowprogrammer/FlowPusher.java
index 37e1b44..17bbc1a 100644
--- a/src/main/java/net/onrc/onos/core/flowprogrammer/FlowPusher.java
+++ b/src/main/java/net/onrc/onos/core/flowprogrammer/FlowPusher.java
@@ -4,7 +4,6 @@
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.EnumSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
@@ -25,48 +24,17 @@
import net.floodlightcontroller.core.internal.OFMessageFuture;
import net.floodlightcontroller.core.module.FloodlightModuleContext;
import net.floodlightcontroller.threadpool.IThreadPoolService;
-import net.floodlightcontroller.util.MACAddress;
import net.floodlightcontroller.util.OFMessageDamper;
-import net.onrc.onos.core.util.FlowEntry;
-import net.onrc.onos.core.util.FlowEntryAction;
-import net.onrc.onos.core.util.FlowEntryAction.ActionEnqueue;
-import net.onrc.onos.core.util.FlowEntryAction.ActionOutput;
-import net.onrc.onos.core.util.FlowEntryAction.ActionSetEthernetAddr;
-import net.onrc.onos.core.util.FlowEntryAction.ActionSetIPv4Addr;
-import net.onrc.onos.core.util.FlowEntryAction.ActionSetIpToS;
-import net.onrc.onos.core.util.FlowEntryAction.ActionSetTcpUdpPort;
-import net.onrc.onos.core.util.FlowEntryAction.ActionSetVlanId;
-import net.onrc.onos.core.util.FlowEntryAction.ActionSetVlanPriority;
-import net.onrc.onos.core.util.FlowEntryAction.ActionStripVlan;
-import net.onrc.onos.core.util.FlowEntryActions;
-import net.onrc.onos.core.util.FlowEntryMatch;
-import net.onrc.onos.core.util.FlowEntryUserState;
-import net.onrc.onos.core.util.IPv4Net;
+import net.onrc.onos.core.intent.FlowEntry;
import net.onrc.onos.core.util.Pair;
-import net.onrc.onos.core.util.PortNumber;
-import org.openflow.protocol.OFBarrierReply;
-import org.openflow.protocol.OFBarrierRequest;
-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.OFActionDataLayerDestination;
-import org.openflow.protocol.action.OFActionDataLayerSource;
-import org.openflow.protocol.action.OFActionEnqueue;
-import org.openflow.protocol.action.OFActionNetworkLayerDestination;
-import org.openflow.protocol.action.OFActionNetworkLayerSource;
-import org.openflow.protocol.action.OFActionNetworkTypeOfService;
-import org.openflow.protocol.action.OFActionOutput;
-import org.openflow.protocol.action.OFActionStripVirtualLan;
-import org.openflow.protocol.action.OFActionTransportLayerDestination;
-import org.openflow.protocol.action.OFActionTransportLayerSource;
-import org.openflow.protocol.action.OFActionVirtualLanIdentifier;
-import org.openflow.protocol.action.OFActionVirtualLanPriorityCodePoint;
-import org.openflow.protocol.factory.BasicFactory;
+import org.projectfloodlight.openflow.protocol.OFBarrierReply;
+import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFFlowMod;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFType;
+import org.projectfloodlight.openflow.protocol.OFVersion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -75,14 +43,13 @@
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
/**
- * FlowPusher is a implementation of FlowPusherService.
- * FlowPusher assigns one message queue instance for each one switch.
- * Number of message processing threads is configurable by constructor, and
- * one thread can handle multiple message queues. Each queue will be assigned to
- * a thread according to hash function defined by getHash().
- * Each processing thread reads messages from queues and sends it to switches
- * in round-robin. Processing thread also calculates rate of sending to suppress
- * excessive message sending.
+ * FlowPusher is a implementation of FlowPusherService. FlowPusher assigns one
+ * message queue instance for each one switch. Number of message processing
+ * threads is configurable by constructor, and one thread can handle multiple
+ * message queues. Each queue will be assigned to a thread according to hash
+ * function defined by getHash(). Each processing thread reads messages from
+ * queues and sends it to switches in round-robin. Processing thread also
+ * calculates rate of sending to suppress excessive message sending.
*/
public final class FlowPusher implements IFlowPusherService, IOFMessageListener {
private static final Logger log = LoggerFactory.getLogger(FlowPusher.class);
@@ -91,8 +58,9 @@
// TODO: Values copied from elsewhere (class LearningSwitch).
// The local copy should go away!
//
- protected static final int OFMESSAGE_DAMPER_CAPACITY = 10000; // TODO: find sweet spot
- protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
+ protected static final int OFMESSAGE_DAMPER_CAPACITY = 10000; // TODO: find
+ // sweet spot
+ protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
// Number of messages sent to switch at once
protected static final int MAX_MESSAGE_SEND = 100;
@@ -110,15 +78,15 @@
}
/**
- * SwitchQueue represents message queue attached to a switch.
- * This consists of queue itself and variables used for limiting sending rate.
+ * SwitchQueue represents message queue attached to a switch. This consists
+ * of queue itself and variables used for limiting sending rate.
*/
private static class SwitchQueue {
List<Queue<SwitchQueueEntry>> rawQueues;
QueueState state;
// Max rate of sending message (bytes/ms). 0 implies no limitation.
- long maxRate = 0; // 0 indicates no limitation
+ long maxRate = 0; // 0 indicates no limitation
long lastSentTime = 0;
long lastSentSize = 0;
@@ -137,7 +105,7 @@
/**
* Check if sending rate is within the rate.
- *
+ * <p>
* @param current Current time
* @return true if within the rate
*/
@@ -158,9 +126,9 @@
/**
* Log time and size of last sent data.
- *
+ * <p>
* @param current Time to be sent.
- * @param size Size of sent data (in bytes).
+ * @param size Size of sent data (in bytes).
*/
void logSentData(long current, long size) {
lastSentTime = current;
@@ -178,52 +146,52 @@
/**
* Poll single appropriate entry object according to QueueState.
- *
+ * <p>
* @return Entry object.
*/
SwitchQueueEntry poll() {
switch (state) {
- case READY: {
- for (int i = 0; i < rawQueues.size(); ++i) {
- SwitchQueueEntry entry = rawQueues.get(i).poll();
- if (entry != null) {
- return entry;
- }
+ case READY: {
+ for (int i = 0; i < rawQueues.size(); ++i) {
+ SwitchQueueEntry entry = rawQueues.get(i).poll();
+ if (entry != null) {
+ return entry;
}
+ }
- return null;
- }
- case SUSPENDED: {
- // Only polling from high priority queue
- SwitchQueueEntry entry = getQueue(MsgPriority.HIGH).poll();
- return entry;
- }
- default:
- log.error("Unexpected QueueState: {}", state);
- return null;
+ return null;
+ }
+ case SUSPENDED: {
+ // Only polling from high priority queue
+ SwitchQueueEntry entry = getQueue(MsgPriority.HIGH).poll();
+ return entry;
+ }
+ default:
+ log.error("Unexpected QueueState: {}", state);
+ return null;
}
}
/**
* Check if this object has any messages in the queues to be sent.
- *
+ * <p>
* @return True if there are some messages to be sent.
*/
boolean hasMessageToSend() {
switch (state) {
- case READY:
- for (Queue<SwitchQueueEntry> queue : rawQueues) {
- if (!queue.isEmpty()) {
- return true;
- }
+ case READY:
+ for (Queue<SwitchQueueEntry> queue : rawQueues) {
+ if (!queue.isEmpty()) {
+ return true;
}
- break;
- case SUSPENDED:
- // Only checking high priority queue
- return (!getQueue(MsgPriority.HIGH).isEmpty());
- default:
- log.error("Unexpected QueueState: {}", state);
- return false;
+ }
+ break;
+ case SUSPENDED:
+ // Only checking high priority queue
+ return (!getQueue(MsgPriority.HIGH).isEmpty());
+ default:
+ log.error("Unexpected QueueState: {}", state);
+ return false;
}
return false;
@@ -239,7 +207,7 @@
*/
private static final class BarrierInfo {
final long dpid;
- final int xid;
+ final long xid;
static BarrierInfo create(IOFSwitch sw, OFBarrierRequest req) {
return new BarrierInfo(sw.getId(), req.getXid());
@@ -249,7 +217,7 @@
return new BarrierInfo(sw.getId(), rpy.getXid());
}
- private BarrierInfo(long dpid, int xid) {
+ private BarrierInfo(long dpid, long xid) {
this.dpid = dpid;
this.xid = xid;
}
@@ -260,7 +228,7 @@
final int prime = 31;
int result = 1;
result = prime * result + (int) (dpid ^ (dpid >>> 32));
- result = prime * result + xid;
+ result = prime * result + (int) (xid ^ (xid >>> 32));
return result;
}
@@ -280,32 +248,30 @@
return (this.dpid == other.dpid) && (this.xid == other.xid);
}
-
}
+ private FloodlightModuleContext context = null;
private OFMessageDamper messageDamper = null;
private IThreadPoolService threadPool = null;
-
- private FloodlightContext context = null;
- private BasicFactory factory = null;
+ private IFloodlightProviderService floodlightProvider = null;
+ protected Map<OFVersion, OFFactory> ofFactoryMap = null;
// Map of threads versus dpid
private Map<Long, FlowPusherThread> threadMap = null;
// Map from (DPID and transaction ID) to Future objects.
- private Map<BarrierInfo, OFBarrierReplyFuture> barrierFutures
- = new ConcurrentHashMap<BarrierInfo, OFBarrierReplyFuture>();
+ private Map<BarrierInfo, OFBarrierReplyFuture> barrierFutures =
+ new ConcurrentHashMap<BarrierInfo, OFBarrierReplyFuture>();
private int numberThread;
/**
* Main thread that reads messages from queues and sends them to switches.
*/
- private class FlowPusherThread extends Thread {
- // Weak ConncurrentHashMap
- private Map<IOFSwitch, SwitchQueue> assignedQueues
- = CacheBuilder.newBuilder()
- .weakKeys()
- .<IOFSwitch, SwitchQueue>build().asMap();
+ private static class FlowPusherThread extends Thread {
+ // Weak ConcurrentHashMap
+ private Map<IOFSwitch, SwitchQueue> assignedQueues = CacheBuilder.newBuilder()
+ .weakKeys()
+ .<IOFSwitch, SwitchQueue>build().asMap();
final Lock queuingLock = new ReentrantLock();
final Condition messagePushed = queuingLock.newCondition();
@@ -329,9 +295,8 @@
}
}
- for (Iterator<Entry<IOFSwitch, SwitchQueue>> it = assignedQueues.entrySet().iterator();
- it.hasNext();
- ) {
+ for (Iterator<Entry<IOFSwitch, SwitchQueue>> it = assignedQueues
+ .entrySet().iterator(); it.hasNext();) {
Entry<IOFSwitch, SwitchQueue> entry = it.next();
IOFSwitch sw = entry.getKey();
SwitchQueue queue = entry.getValue();
@@ -352,13 +317,13 @@
}
/**
- * Read messages from queue and send them to the switch.
- * If number of messages excess the limit, stop sending messages.
- *
- * @param sw Switch to which messages will be sent.
- * @param queue Queue of messages.
- * @param maxMsg Limitation of number of messages to be sent. If set to 0,
- * all messages in queue will be sent.
+ * Read messages from queue and send them to the switch. If number of
+ * messages excess the limit, stop sending messages.
+ * <p>
+ * @param sw Switch to which messages will be sent.
+ * @param queue Queue of messages.
+ * @param maxMsg Limitation of number of messages to be sent. If set to
+ * 0, all messages in queue will be sent.
*/
private void processQueue(IOFSwitch sw, SwitchQueue queue, int maxMsg) {
// check sending rate and determine it to be sent or not
@@ -381,11 +346,14 @@
OFMessage msg = queueEntry.getOFMessage();
try {
- messageDamper.write(sw, msg, context);
+ // TODO BOC do we need to use the message damper?
+ // messageDamper.write(sw, msg, context);
+ sw.write(msg, null);
if (log.isTraceEnabled()) {
- log.trace("Pusher sends message: {}", msg);
+ log.trace("Pusher sends message to switch {}: {}", sw.getStringId(), msg);
}
- size += msg.getLength();
+ // TODO BOC how do we get the size?
+ // size += msg.getLength();
} catch (IOException e) {
log.error("Exception in sending message (" + msg + "):", e);
}
@@ -425,7 +393,7 @@
/**
* Initialize object with threads of given number.
- *
+ * <p>
* @param numberThreadValue Number of threads to handle messages.
*/
public FlowPusher(int numberThreadValue) {
@@ -438,44 +406,42 @@
/**
* Set parameters needed for sending messages.
- *
- * @param floodlightContext FloodlightContext used for sending messages.
- * If null, FlowPusher uses default context.
- * @param modContext FloodlightModuleContext used for acquiring
- * ThreadPoolService and registering MessageListener.
- * @param basicFactory Factory object to create OFMessage objects.
- * @param damper Message damper used for sending messages.
- * If null, FlowPusher creates its own damper object.
+ * <p>
+ * @param floodlightContext FloodlightModuleContext used for acquiring
+ * ThreadPoolService and registering MessageListener.
*/
- public void init(FloodlightContext floodlightContext,
- FloodlightModuleContext modContext,
- BasicFactory basicFactory,
- OFMessageDamper damper) {
- context = floodlightContext;
- factory = basicFactory;
- this.threadPool = modContext.getServiceImpl(IThreadPoolService.class);
- IFloodlightProviderService flservice
- = modContext.getServiceImpl(IFloodlightProviderService.class);
- flservice.addOFMessageListener(OFType.BARRIER_REPLY, this);
+ public void init(FloodlightModuleContext floodlightContext) {
+ this.context = floodlightContext;
+ this.floodlightProvider = context
+ .getServiceImpl(IFloodlightProviderService.class);
+ this.threadPool = context.getServiceImpl(IThreadPoolService.class);
+ this.messageDamper = null;
- if (damper != null) {
- messageDamper = damper;
- } else {
- // use default values
- messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
- EnumSet.of(OFType.FLOW_MOD),
- OFMESSAGE_DAMPER_TIMEOUT);
- }
+ ofFactoryMap = new HashMap<>();
+ ofFactoryMap.put(OFVersion.OF_10, floodlightProvider.getOFMessageFactory_10());
+ ofFactoryMap.put(OFVersion.OF_13, floodlightProvider.getOFMessageFactory_13());
+ floodlightProvider.addOFMessageListener(OFType.BARRIER_REPLY, this);
+
+ // TODO BOC message damper may not be needed...
+ // if (damper != null) {
+ // messageDamper = damper;
+ // } else {
+ // use default values
+ /*messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
+ EnumSet.of(OFType.FLOW_MOD),
+ OFMESSAGE_DAMPER_TIMEOUT);*/
+ // }
}
/**
* Begin processing queue.
*/
public void start() {
- if (factory == null) {
- log.error("FlowPusher not yet initialized.");
- return;
- }
+ // TODO BOC
+ // if (factory == null) {
+ // log.error("FlowPusher not yet initialized.");
+ // return;
+ // }
threadMap = new HashMap<Long, FlowPusherThread>();
for (long i = 0; i < numberThread; ++i) {
@@ -491,7 +457,8 @@
SwitchQueue queue = getQueue(sw);
if (queue == null) {
- // create queue in case suspend is called before first message addition
+ // create queue in case suspend is called before first message
+ // addition
queue = createQueueImpl(sw);
}
@@ -509,7 +476,7 @@
SwitchQueue queue = getQueue(sw);
if (queue == null) {
- log.error("No queue is attached to DPID: {}", sw.getId());
+ log.error("No queue is attached to DPID: {}", sw.getStringId());
return false;
}
@@ -560,7 +527,7 @@
}
if (rate > 0) {
- log.debug("rate for {} is set to {}", sw.getId(), rate);
+ log.debug("rate for {} is set to {}", sw.getStringId(), rate);
synchronized (queue) {
queue.maxRate = rate;
}
@@ -569,7 +536,7 @@
@Override
@SuppressFBWarnings(value = "RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE",
- justification = "Future versions of createQueueImpl() might return null")
+ justification = "Future versions of createQueueImpl() might return null")
public boolean createQueue(IOFSwitch sw) {
SwitchQueue queue = createQueueImpl(sw);
@@ -619,13 +586,12 @@
/**
* Invalidate.
- *
+ * <p>
* @param sw switch
- *
* @see OFMessageDamper#invalidate(IOFSwitch)
*/
public void invalidate(IOFSwitch sw) {
- messageDamper.invalidate(sw);
+ // messageDamper.invalidate(sw); currently a null ptr - commenting out
}
@Override
@@ -668,226 +634,9 @@
}
/**
- * Fetch the match conditions.
- * NOTE: The Flow matching conditions common for all Flow Entries are
- * used ONLY if a Flow Entry does NOT have the corresponding matching
- * condition set.
- *
- * @param flowEntryMatch Flow entry to create a matcher for
- * @return open flow matcher for the given values
- */
- private OFMatch computeMatch(FlowEntryMatch flowEntryMatch) {
- OFMatch match = new OFMatch();
- match.setWildcards(OFMatch.OFPFW_ALL);
-
- // Match the Incoming Port
- PortNumber matchInPort = flowEntryMatch.inPort();
- if (matchInPort != null) {
- match.setInputPort(matchInPort.shortValue());
- match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
- }
-
- // Match the Source MAC address
- MACAddress matchSrcMac = flowEntryMatch.srcMac();
- if (matchSrcMac != null) {
- match.setDataLayerSource(matchSrcMac.toString());
- match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
- }
-
- // Match the Destination MAC address
- MACAddress matchDstMac = flowEntryMatch.dstMac();
- if (matchDstMac != null) {
- match.setDataLayerDestination(matchDstMac.toString());
- match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
- }
-
- // Match the Ethernet Frame Type
- Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
- if (matchEthernetFrameType != null) {
- match.setDataLayerType(matchEthernetFrameType);
- match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
- }
-
- // Match the VLAN ID
- Short matchVlanId = flowEntryMatch.vlanId();
- if (matchVlanId != null) {
- match.setDataLayerVirtualLan(matchVlanId);
- match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN);
- }
-
- // Match the VLAN priority
- Byte matchVlanPriority = flowEntryMatch.vlanPriority();
- if (matchVlanPriority != null) {
- match.setDataLayerVirtualLanPriorityCodePoint(matchVlanPriority);
- match.setWildcards(match.getWildcards()
- & ~OFMatch.OFPFW_DL_VLAN_PCP);
- }
-
- // Match the Source IPv4 Network prefix
- IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
- if (matchSrcIPv4Net != null) {
- match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
- }
-
- // Natch the Destination IPv4 Network prefix
- IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
- if (matchDstIPv4Net != null) {
- match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
- }
-
- // Match the IP protocol
- Byte matchIpProto = flowEntryMatch.ipProto();
- if (matchIpProto != null) {
- match.setNetworkProtocol(matchIpProto);
- match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_PROTO);
- }
-
- // Match the IP ToS (DSCP field, 6 bits)
- Byte matchIpToS = flowEntryMatch.ipToS();
- if (matchIpToS != null) {
- match.setNetworkTypeOfService(matchIpToS);
- match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_TOS);
- }
-
- // Match the Source TCP/UDP port
- Short matchSrcTcpUdpPort = flowEntryMatch.srcTcpUdpPort();
- if (matchSrcTcpUdpPort != null) {
- match.setTransportSource(matchSrcTcpUdpPort);
- match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
- }
-
- // Match the Destination TCP/UDP port
- Short matchDstTcpUdpPort = flowEntryMatch.dstTcpUdpPort();
- if (matchDstTcpUdpPort != null) {
- match.setTransportDestination(matchDstTcpUdpPort);
- match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_DST);
- }
-
- return match;
- }
-
-
- /**
- * Wrapper object to hold a port number. Used to pass around output ports.
- */
- private static class OutputPort {
- private Short portNumber;
- }
-
- /**
- * Process a flow action entry, putting the resulting flow
- * actions into a list. Will also set the actionOutputPort
- * if one is encountered while processing an action.
- *
- * @param action Flow Entry Action to process
- * @param openFlowActions actions to perform get added to this list
- * @param actionOutputPort this will get set if an action output
- * port is found
- */
- private void processAction(final FlowEntryAction action,
- final List<OFAction> openFlowActions,
- final OutputPort actionOutputPort) {
- ActionOutput actionOutput = action.actionOutput();
- ActionSetVlanId actionSetVlanId = action.actionSetVlanId();
- ActionSetVlanPriority actionSetVlanPriority = action
- .actionSetVlanPriority();
- ActionStripVlan actionStripVlan = action.actionStripVlan();
- ActionSetEthernetAddr actionSetEthernetSrcAddr = action
- .actionSetEthernetSrcAddr();
- ActionSetEthernetAddr actionSetEthernetDstAddr = action
- .actionSetEthernetDstAddr();
- ActionSetIPv4Addr actionSetIPv4SrcAddr = action
- .actionSetIPv4SrcAddr();
- ActionSetIPv4Addr actionSetIPv4DstAddr = action
- .actionSetIPv4DstAddr();
- ActionSetIpToS actionSetIpToS = action.actionSetIpToS();
- ActionSetTcpUdpPort actionSetTcpUdpSrcPort = action
- .actionSetTcpUdpSrcPort();
- ActionSetTcpUdpPort actionSetTcpUdpDstPort = action
- .actionSetTcpUdpDstPort();
- ActionEnqueue actionEnqueue = action.actionEnqueue();
-
- if (actionOutput != null) {
- actionOutputPort.portNumber = actionOutput.port().shortValue();
- // XXX: The max length is hard-coded for now
- OFActionOutput ofa = new OFActionOutput(actionOutput.port()
- .shortValue(), (short) 0xffff);
- openFlowActions.add(ofa);
- }
-
- if (actionSetVlanId != null) {
- OFActionVirtualLanIdentifier ofa =
- new OFActionVirtualLanIdentifier(actionSetVlanId.vlanId());
- openFlowActions.add(ofa);
- }
-
- if (actionSetVlanPriority != null) {
- OFActionVirtualLanPriorityCodePoint ofa =
- new OFActionVirtualLanPriorityCodePoint(actionSetVlanPriority.vlanPriority());
- openFlowActions.add(ofa);
- }
-
- if (actionStripVlan != null) {
- if (actionStripVlan.stripVlan()) {
- OFActionStripVirtualLan ofa = new OFActionStripVirtualLan();
- openFlowActions.add(ofa);
- }
- }
-
- if (actionSetEthernetSrcAddr != null) {
- OFActionDataLayerSource ofa =
- new OFActionDataLayerSource(actionSetEthernetSrcAddr.addr().toBytes());
- openFlowActions.add(ofa);
- }
-
- if (actionSetEthernetDstAddr != null) {
- OFActionDataLayerDestination ofa =
- new OFActionDataLayerDestination(actionSetEthernetDstAddr.addr().toBytes());
- openFlowActions.add(ofa);
- }
-
- if (actionSetIPv4SrcAddr != null) {
- OFActionNetworkLayerSource ofa =
- new OFActionNetworkLayerSource(actionSetIPv4SrcAddr.addr().value());
- openFlowActions.add(ofa);
- }
-
- if (actionSetIPv4DstAddr != null) {
- OFActionNetworkLayerDestination ofa =
- new OFActionNetworkLayerDestination(actionSetIPv4DstAddr.addr().value());
- openFlowActions.add(ofa);
- }
-
- if (actionSetIpToS != null) {
- OFActionNetworkTypeOfService ofa =
- new OFActionNetworkTypeOfService(actionSetIpToS.ipToS());
- openFlowActions.add(ofa);
- }
-
- if (actionSetTcpUdpSrcPort != null) {
- OFActionTransportLayerSource ofa =
- new OFActionTransportLayerSource(actionSetTcpUdpSrcPort.port());
- openFlowActions.add(ofa);
- }
-
- if (actionSetTcpUdpDstPort != null) {
- OFActionTransportLayerDestination ofa =
- new OFActionTransportLayerDestination(actionSetTcpUdpDstPort.port());
- openFlowActions.add(ofa);
- }
-
- if (actionEnqueue != null) {
- OFActionEnqueue ofa =
- new OFActionEnqueue(actionEnqueue.port().shortValue(), actionEnqueue.queueId());
- openFlowActions.add(ofa);
- }
- }
-
-
- /**
* Create a message from FlowEntry and add it to the queue of the switch.
- *
- * @param sw Switch to which message is pushed.
+ * <p>
+ * @param sw Switch to which message is pushed.
* @param flowEntry FlowEntry object used for creating message.
* @return true if message is successfully added to a queue.
*/
@@ -895,90 +644,14 @@
//
// Create the OpenFlow Flow Modification Entry to push
//
- OFFlowMod fm = (OFFlowMod) factory.getMessage(OFType.FLOW_MOD);
- long cookie = flowEntry.flowEntryId().value();
-
- short flowModCommand = OFFlowMod.OFPFC_ADD;
- if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
- flowModCommand = OFFlowMod.OFPFC_ADD;
- } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
- flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
- } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
- flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
- } else {
- // Unknown user state. Ignore the entry
- log.debug(
- "Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
- flowEntry.flowEntryId(),
- flowEntry.flowEntryUserState());
- return false;
- }
-
- final FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
- final OFMatch match = computeMatch(flowEntryMatch);
-
- final PortNumber matchInPort = flowEntryMatch.inPort();
- final MACAddress matchSrcMac = flowEntryMatch.srcMac();
- final MACAddress matchDstMac = flowEntryMatch.dstMac();
-
- //
- // Fetch the actions
- //
- final List<OFAction> openFlowActions = new ArrayList<OFAction>();
- final FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
- //
- final OutputPort actionOutputPort = new OutputPort();
- for (FlowEntryAction action : flowEntryActions.actions()) {
- processAction(action, openFlowActions, actionOutputPort);
- }
- int actionsLen = 0;
- for (OFAction ofa : openFlowActions) {
- actionsLen += ofa.getLength();
- }
-
- fm.setIdleTimeout((short) flowEntry.idleTimeout())
- .setHardTimeout((short) flowEntry.hardTimeout())
- .setPriority((short) flowEntry.priority())
- .setBufferId(OFPacketOut.BUFFER_ID_NONE).setCookie(cookie)
- .setCommand(flowModCommand).setMatch(match)
- .setActions(openFlowActions)
- .setLengthU(OFFlowMod.MINIMUM_LENGTH + actionsLen);
- fm.setOutPort(OFPort.OFPP_NONE.getValue());
- if ((flowModCommand == OFFlowMod.OFPFC_DELETE)
- || (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
- if (actionOutputPort.portNumber != null) {
- fm.setOutPort(actionOutputPort.portNumber);
- }
- }
-
- //
- // Set the OFPFF_SEND_FLOW_REM flag if the Flow Entry is not
- // permanent.
- //
- if ((flowEntry.idleTimeout() != 0) ||
- (flowEntry.hardTimeout() != 0)) {
- fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
- }
-
- if (log.isTraceEnabled()) {
- log.trace("Installing flow entry {} into switch DPID: {} " +
- "flowEntryId: {} srcMac: {} dstMac: {} inPort: {} outPort: {}"
- , flowEntry.flowEntryUserState()
- , sw.getStringId()
- , flowEntry.flowEntryId()
- , matchSrcMac
- , matchDstMac
- , matchInPort
- , actionOutputPort
- );
- }
-
+ OFFlowMod fm = flowEntry.buildFlowMod(ofFactoryMap.get(sw.getOFVersion()));
+ // log.trace("Pushing flow mod {}", fm);
return addMessageImpl(sw, fm, priority);
}
/**
* Add message to queue.
- *
+ * <p>
* @param sw
* @param msg
* @param priority
@@ -999,7 +672,7 @@
synchronized (queue) {
queue.add(entry, priority);
if (log.isTraceEnabled()) {
- log.trace("Message is pushed: {}", entry.getOFMessage());
+ log.trace("Message is pushed to switch {}: {}", sw.getStringId(), entry.getOFMessage());
}
}
@@ -1014,20 +687,18 @@
if (future == null) {
return null;
}
-
try {
return future.get();
} catch (InterruptedException e) {
log.error("InterruptedException", e);
- return null;
} catch (ExecutionException e) {
log.error("ExecutionException", e);
- return null;
}
+ return null;
}
@Override
- public OFBarrierReplyFuture barrierAsync(IOFSwitch sw) {
+ public OFMessageFuture<OFBarrierReply> barrierAsync(IOFSwitch sw) {
// TODO creation of message and future should be moved to OFSwitchImpl
if (sw == null) {
@@ -1035,25 +706,28 @@
}
OFBarrierRequest msg = createBarrierRequest(sw);
-
- OFBarrierReplyFuture future = new OFBarrierReplyFuture(threadPool, sw, msg.getXid());
+ OFBarrierReplyFuture future = new OFBarrierReplyFuture(threadPool, sw,
+ (int) msg.getXid());
barrierFutures.put(BarrierInfo.create(sw, msg), future);
-
addMessageImpl(sw, msg, MsgPriority.NORMAL);
-
return future;
}
protected OFBarrierRequest createBarrierRequest(IOFSwitch sw) {
- OFBarrierRequest msg = (OFBarrierRequest) factory.getMessage(OFType.BARRIER_REQUEST);
- msg.setXid(sw.getNextTransactionId());
-
- return msg;
+ OFFactory factory = ofFactoryMap.get(sw.getOFVersion());
+ if (factory == null) {
+ log.error("No OF Message Factory for switch {} with OFVersion {}", sw,
+ sw.getOFVersion());
+ return null;
+ }
+ return factory.buildBarrierRequest()
+ .setXid(sw.getNextTransactionId())
+ .build();
}
/**
* Get a queue attached to a switch.
- *
+ * <p>
* @param sw Switch object
* @return Queue object
*/
@@ -1072,7 +746,7 @@
/**
* Get a hash value correspondent to a switch.
- *
+ * <p>
* @param sw Switch object
* @return Hash value
*/
@@ -1084,7 +758,7 @@
/**
* Get a Thread object which processes the queue attached to a switch.
- *
+ * <p>
* @param sw Switch object
* @return Thread object
*/
@@ -1112,18 +786,17 @@
@Override
public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
if (log.isTraceEnabled()) {
- log.trace("Received BARRIER_REPLY from: {}", sw.getId());
+ log.trace("Received BARRIER_REPLY from : {}", sw.getStringId());
}
if ((msg.getType() != OFType.BARRIER_REPLY) ||
- !(msg instanceof OFBarrierReply)) {
+ !(msg instanceof OFBarrierReply)) {
log.error("Unexpected reply message: {}", msg.getType());
return Command.CONTINUE;
}
OFBarrierReply reply = (OFBarrierReply) msg;
BarrierInfo info = BarrierInfo.create(sw, reply);
-
// Deliver future if exists
OFBarrierReplyFuture future = barrierFutures.get(info);
if (future != null) {
@@ -1133,4 +806,5 @@
return Command.CONTINUE;
}
+
}
diff --git a/src/main/java/net/onrc/onos/core/flowprogrammer/FlowSynchronizer.java b/src/main/java/net/onrc/onos/core/flowprogrammer/FlowSynchronizer.java
index af3cc70..7b2bfd0 100644
--- a/src/main/java/net/onrc/onos/core/flowprogrammer/FlowSynchronizer.java
+++ b/src/main/java/net/onrc/onos/core/flowprogrammer/FlowSynchronizer.java
@@ -1,6 +1,5 @@
package net.onrc.onos.core.flowprogrammer;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
@@ -8,12 +7,10 @@
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import net.floodlightcontroller.core.IOFSwitch;
-import net.onrc.onos.core.flowprogrammer.IFlowPusherService.MsgPriority;
import net.onrc.onos.core.util.FlowEntryId;
import org.openflow.protocol.OFFlowMod;
@@ -99,10 +96,6 @@
Set<FlowEntryWrapper> graphEntries = getFlowEntriesFromGraph();
long step1 = System.nanoTime();
Set<FlowEntryWrapper> switchEntries = getFlowEntriesFromSwitch();
- if (switchEntries == null) {
- log.debug("getFlowEntriesFromSwitch() failed");
- return null;
- }
long step2 = System.nanoTime();
SyncResult result = compare(graphEntries, switchEntries);
long step3 = System.nanoTime();
@@ -184,12 +177,12 @@
Set<FlowEntryWrapper> entries = new HashSet<FlowEntryWrapper>();
// TODO: fix when FlowSynchronizer is refactored
- /*
+ /*
for(IFlowEntry entry : swObj.getFlowEntries()) {
FlowEntryWrapper fe = new FlowEntryWrapper(entry);
entries.add(fe);
}
- */
+ */
return entries;
}
@@ -218,8 +211,9 @@
lengthU += req.getLengthU();
req.setLengthU(lengthU);
- List<OFStatistics> entries = null;
- try {
+ //List<OFStatistics> entries = null;
+ // XXX S when we fix stats, we fix this
+ /*try {
Future<List<OFStatistics>> dfuture = sw.getStatistics(req);
entries = dfuture.get();
} catch (IOException e) {
@@ -231,14 +225,16 @@
} catch (ExecutionException e) {
log.error("Error getting statistics", e);
return null;
- }
+ }*/
Set<FlowEntryWrapper> results = new HashSet<FlowEntryWrapper>();
+ /*
for (OFStatistics result : entries) {
OFFlowStatisticsReply entry = (OFFlowStatisticsReply) result;
FlowEntryWrapper fe = new FlowEntryWrapper(entry);
results.add(fe);
}
+ */
return results;
}
@@ -248,7 +244,7 @@
* FlowEntryWrapper represents abstract FlowEntry which is embodied
* by FlowEntryId (from GraphDB) or OFFlowStatisticsReply (from switch).
*/
- class FlowEntryWrapper {
+ static class FlowEntryWrapper {
FlowEntryId flowEntryId;
// TODO: fix when FlowSynchronizer is refactored
// IFlowEntry iFlowEntry;
@@ -256,12 +252,12 @@
// TODO: fix when FlowSynchronizer is refactored
- /*
+ /*
public FlowEntryWrapper(IFlowEntry entry) {
flowEntryId = new FlowEntryId(entry.getFlowEntryId());
iFlowEntry = entry;
}
- */
+ */
public FlowEntryWrapper(OFFlowStatisticsReply entry) {
flowEntryId = new FlowEntryId(entry.getCookie());
@@ -285,7 +281,7 @@
double startDB = System.nanoTime();
// Get the Flow Entry state from the Network Graph
// TODO: fix when FlowSynchronizer is refactored
- /*
+ /*
if (iFlowEntry == null) {
try {
// TODO: fix when FlowSynchronizer is refactored
@@ -296,13 +292,13 @@
return;
}
}
- */
+ */
dbTime = System.nanoTime() - startDB;
//
// TODO: The old FlowDatabaseOperation class is gone, so the code
//
- /*
+ /*
double startExtract = System.nanoTime();
FlowEntry flowEntry =
FlowDatabaseOperation.extractFlowEntry(iFlowEntry);
@@ -316,7 +312,7 @@
double startPush = System.nanoTime();
pusher.pushFlowEntry(sw, flowEntry, MsgPriority.HIGH);
pushTime = System.nanoTime() - startPush;
- */
+ */
}
/**
@@ -340,7 +336,8 @@
fm.setPriority(statisticsReply.getPriority());
fm.setOutPort(OFPort.OFPP_NONE);
- pusher.add(sw, fm, MsgPriority.HIGH);
+ // XXX BOC commented out pending FlowSync refactor
+ //pusher.add(sw, fm, MsgPriority.HIGH);
}
/**
diff --git a/src/main/java/net/onrc/onos/core/flowprogrammer/IFlowPusherService.java b/src/main/java/net/onrc/onos/core/flowprogrammer/IFlowPusherService.java
index 37911a8..e94119a 100644
--- a/src/main/java/net/onrc/onos/core/flowprogrammer/IFlowPusherService.java
+++ b/src/main/java/net/onrc/onos/core/flowprogrammer/IFlowPusherService.java
@@ -5,11 +5,11 @@
import net.floodlightcontroller.core.IOFSwitch;
import net.floodlightcontroller.core.internal.OFMessageFuture;
import net.floodlightcontroller.core.module.IFloodlightService;
-import net.onrc.onos.core.util.FlowEntry;
+import net.onrc.onos.core.intent.FlowEntry;
import net.onrc.onos.core.util.Pair;
-import org.openflow.protocol.OFBarrierReply;
-import org.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFBarrierReply;
+import org.projectfloodlight.openflow.protocol.OFMessage;
/**
* FlowPusherService is a service to send message to switches in proper rate.
diff --git a/src/main/java/net/onrc/onos/core/flowprogrammer/OFBarrierReplyFuture.java b/src/main/java/net/onrc/onos/core/flowprogrammer/OFBarrierReplyFuture.java
index bbd10cb..3991019 100644
--- a/src/main/java/net/onrc/onos/core/flowprogrammer/OFBarrierReplyFuture.java
+++ b/src/main/java/net/onrc/onos/core/flowprogrammer/OFBarrierReplyFuture.java
@@ -6,22 +6,24 @@
import net.floodlightcontroller.core.internal.OFMessageFuture;
import net.floodlightcontroller.threadpool.IThreadPoolService;
-import org.openflow.protocol.OFBarrierReply;
-import org.openflow.protocol.OFMessage;
-import org.openflow.protocol.OFType;
+import org.projectfloodlight.openflow.protocol.OFBarrierReply;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFType;
+
+//XXX S note that other places are using old OFBarrierReply - so we broke that
public class OFBarrierReplyFuture extends OFMessageFuture<OFBarrierReply> {
protected volatile boolean finished;
public OFBarrierReplyFuture(IThreadPoolService tp,
- IOFSwitch sw, int transactionId) {
+ IOFSwitch sw, int transactionId) {
super(tp, sw, OFType.FEATURES_REPLY, transactionId);
init();
}
public OFBarrierReplyFuture(IThreadPoolService tp,
- IOFSwitch sw, int transactionId, long timeout, TimeUnit unit) {
+ IOFSwitch sw, int transactionId, long timeout, TimeUnit unit) {
super(tp, sw, OFType.FEATURES_REPLY, transactionId, timeout, unit);
init();
}
diff --git a/src/main/java/net/onrc/onos/core/flowprogrammer/web/SendBarrierResource.java b/src/main/java/net/onrc/onos/core/flowprogrammer/web/SendBarrierResource.java
index 236cc85..4fc6782 100644
--- a/src/main/java/net/onrc/onos/core/flowprogrammer/web/SendBarrierResource.java
+++ b/src/main/java/net/onrc/onos/core/flowprogrammer/web/SendBarrierResource.java
@@ -2,8 +2,8 @@
import net.floodlightcontroller.core.IOFSwitch;
-import org.openflow.protocol.OFBarrierReply;
import org.openflow.util.HexString;
+import org.projectfloodlight.openflow.protocol.OFBarrierReply;
import org.restlet.resource.Get;
/**
diff --git a/src/main/java/net/onrc/onos/core/hostmanager/HostManager.java b/src/main/java/net/onrc/onos/core/hostmanager/HostManager.java
index 6843fa9..9f6373d 100644
--- a/src/main/java/net/onrc/onos/core/hostmanager/HostManager.java
+++ b/src/main/java/net/onrc/onos/core/hostmanager/HostManager.java
@@ -30,15 +30,15 @@
import net.onrc.onos.core.util.Dpid;
import net.onrc.onos.core.util.PortNumber;
-import org.openflow.protocol.OFMessage;
-import org.openflow.protocol.OFPacketIn;
-import org.openflow.protocol.OFType;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFPacketIn;
+import org.projectfloodlight.openflow.protocol.OFType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HostManager implements IFloodlightModule,
- IOFMessageListener,
- IHostService {
+IOFMessageListener,
+IHostService {
private static final Logger log = LoggerFactory.getLogger(HostManager.class);
private static final long HOST_CLEANING_INITIAL_DELAY = 30;
@@ -106,8 +106,10 @@
Ethernet eth = IFloodlightProviderService.bcStore.
get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
+ short inport = (short) cntx.getStorage()
+ .get(IFloodlightProviderService.CONTEXT_PI_INPORT);
- return processPacketIn(sw, pi, eth);
+ return processPacketIn(sw, pi, eth, inport);
}
return Command.CONTINUE;
@@ -116,13 +118,14 @@
// This "protected" modifier is for unit test.
// The above "receive" method couldn't be tested
// because of IFloodlightProviderService static final field.
- protected Command processPacketIn(IOFSwitch sw, OFPacketIn pi, Ethernet eth) {
+ protected Command processPacketIn(IOFSwitch sw, OFPacketIn pi, Ethernet eth,
+ short inport) {
if (log.isTraceEnabled()) {
log.trace("Receive PACKET_IN swId {}, portId {}", sw.getId(), pi.getInPort());
}
final Dpid dpid = new Dpid(sw.getId());
- final PortNumber portNum = new PortNumber(pi.getInPort());
+ final PortNumber portNum = new PortNumber(inport);
Host srcHost =
getSourceHostFromPacket(eth, dpid.value(), portNum.value());
@@ -140,8 +143,8 @@
if (topology.getOutgoingLink(dpid, portNum) != null ||
topology.getIncomingLink(dpid, portNum) != null) {
log.debug("Not adding host {} as " +
- "there is a link on the port: dpid {} port {}",
- srcHost.getMacAddress(), dpid, portNum);
+ "there is a link on the port: dpid {} port {}",
+ srcHost.getMacAddress(), dpid, portNum);
return Command.CONTINUE;
}
} finally {
diff --git a/src/main/java/net/onrc/onos/core/intent/Action.java b/src/main/java/net/onrc/onos/core/intent/Action.java
index 100dc33..8f8c8b2 100644
--- a/src/main/java/net/onrc/onos/core/intent/Action.java
+++ b/src/main/java/net/onrc/onos/core/intent/Action.java
@@ -2,6 +2,9 @@
import net.onrc.onos.core.util.FlowEntryAction;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.action.OFAction;
+
/**
* An abstract class that represents an OpenFlow action.
*/
@@ -14,4 +17,12 @@
* @return an equivalent FlowEntryAction object
*/
public abstract FlowEntryAction getFlowEntryAction();
+
+ /**
+ * Builds and returns an OFAction given an OFFactory.
+ *
+ * @param factory the OFFactory to use for building
+ * @return the OFAction
+ */
+ public abstract OFAction getOFAction(OFFactory factory);
}
diff --git a/src/main/java/net/onrc/onos/core/intent/FlowEntry.java b/src/main/java/net/onrc/onos/core/intent/FlowEntry.java
index c738cbc..0fd618e 100644
--- a/src/main/java/net/onrc/onos/core/intent/FlowEntry.java
+++ b/src/main/java/net/onrc/onos/core/intent/FlowEntry.java
@@ -1,22 +1,32 @@
package net.onrc.onos.core.intent;
+import java.util.ArrayList;
import java.util.HashSet;
+import java.util.List;
import java.util.Objects;
import java.util.Set;
import net.floodlightcontroller.util.MACAddress;
import net.onrc.onos.core.intent.IntentOperation.Operator;
-import net.onrc.onos.core.util.Dpid;
-import net.onrc.onos.core.util.FlowEntryActions;
-import net.onrc.onos.core.util.FlowEntryId;
-import net.onrc.onos.core.util.FlowEntryUserState;
+
+import org.projectfloodlight.openflow.protocol.OFActionType;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFFlowMod;
+import org.projectfloodlight.openflow.protocol.action.OFAction;
+import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
+import org.projectfloodlight.openflow.protocol.match.Match.Builder;
+import org.projectfloodlight.openflow.types.OFBufferId;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.U64;
/**
- * A class to represent an OpenFlow FlowMod.
+ * A class to represent an OpenFlow FlowMod. <br>
* It is OpenFlow v.1.0-centric and contains a Match and an Action.
*/
public class FlowEntry {
+ public static final int PRIORITY_DEFAULT = 32768; // Default Flow Priority
+
protected long sw;
protected Match match;
protected Set<Action> actions;
@@ -37,12 +47,12 @@
* @param dstIpAddress destination IP address
* @param operator OpenFlow operation/command (add, remove, etc.)
*/
-// CHECKSTYLE:OFF suppress the warning about too many parameters
+ // CHECKSTYLE:OFF suppress the warning about too many parameters
public FlowEntry(long sw, long srcPort, long dstPort,
- MACAddress srcMac, MACAddress dstMac,
- int srcIpAddress, int dstIpAddress,
- Operator operator) {
-// CHECKSTYLE:ON
+ MACAddress srcMac, MACAddress dstMac,
+ int srcIpAddress, int dstIpAddress,
+ Operator operator) {
+ // CHECKSTYLE:ON
this.sw = sw;
this.match = new Match(sw, srcPort, srcMac, dstMac, srcIpAddress, dstIpAddress);
this.actions = new HashSet<Action>();
@@ -133,33 +143,91 @@
}
/**
- * Converts the FlowEntry in to a legacy FlowEntry object.
+ * Builds and returns an OFFlowMod given an OFFactory.
*
- * @return an equivalent legacy FlowEntry object
+ * @param factory the OFFactory to use for building
+ * @return the OFFlowMod
*/
- public net.onrc.onos.core.util.FlowEntry getFlowEntry() {
- net.onrc.onos.core.util.FlowEntry entry = new net.onrc.onos.core.util.FlowEntry();
- entry.setDpid(new Dpid(sw));
- entry.setFlowEntryId(new FlowEntryId(flowEntryId));
- entry.setFlowEntryMatch(match.getFlowEntryMatch());
- FlowEntryActions flowEntryActions = new FlowEntryActions();
- for (Action action : actions) {
- flowEntryActions.addAction(action.getFlowEntryAction());
- }
- entry.setFlowEntryActions(flowEntryActions);
+ public OFFlowMod buildFlowMod(OFFactory factory) {
+ OFFlowMod.Builder builder = null;
+
switch (operator) {
- case ADD:
- entry.setFlowEntryUserState(FlowEntryUserState.FE_USER_MODIFY);
- break;
- case REMOVE:
- entry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
- break;
- default:
- break;
+ case ADD:
+ builder = factory.buildFlowModifyStrict();
+ break;
+ case REMOVE:
+ builder = factory.buildFlowDeleteStrict();
+ break;
+ default:
+ // TODO throw error?
+ return null;
}
- entry.setIdleTimeout(idleTimeout);
- entry.setHardTimeout(hardTimeout);
- return entry;
+
+ // Build OFMatch
+ Builder matchBuilder = match.getOFMatchBuilder(factory);
+
+ // Build OFAction Set
+ List<OFAction> actionList = new ArrayList<>(actions.size());
+ for (Action action : actions) {
+ actionList.add(action.getOFAction(factory));
+ }
+
+ OFPort outp = OFPort.of((short) 0xffff); // OF1.0 OFPP.NONE
+ if (operator == Operator.REMOVE) {
+ if (actionList.size() == 1) {
+ if (actionList.get(0).getType() == OFActionType.OUTPUT) {
+ OFActionOutput oa = (OFActionOutput) actionList.get(0);
+ outp = oa.getPort();
+ }
+ }
+ }
+
+ // Build OFFlowMod
+ builder.setMatch(matchBuilder.build())
+ .setActions(actionList)
+ .setIdleTimeout(idleTimeout)
+ .setHardTimeout(hardTimeout)
+ .setCookie(U64.of(flowEntryId))
+ .setBufferId(OFBufferId.NO_BUFFER)
+ .setPriority(PRIORITY_DEFAULT)
+ .setOutPort(outp);
+
+ /* Note: The following are NOT USED.
+ * builder.setFlags()
+ * builder.setInstructions()
+ * builder.setOutGroup()
+ * builder.setTableId()
+ * builder.setXid()
+ */
+
+ // TODO from Flow Pusher
+ // Set the OFPFF_SEND_FLOW_REM flag if the Flow Entry is not
+ // permanent.
+ //
+ // if ((flowEntry.idleTimeout() != 0) ||
+ // (flowEntry.hardTimeout() != 0)) {
+ // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
+ // }
+
+ // TODO do we care?
+ // fm.setOutPort(OFPort.OFPP_NONE.getValue());
+ // if ((flowModCommand == OFFlowMod.OFPFC_DELETE)
+ // || (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
+ // if (actionOutputPort.portNumber != null) {
+ // fm.setOutPort(actionOutputPort.portNumber);
+ // }
+ // }
+
+ // TODO
+ // Set the OFPFF_SEND_FLOW_REM flag if the Flow Entry is not
+ // permanent.
+ //
+ // if ((flowEntry.idleTimeout() != 0) ||
+ // (flowEntry.hardTimeout() != 0)) {
+ // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
+ // }
+
+ return builder.build();
}
/**
diff --git a/src/main/java/net/onrc/onos/core/intent/ForwardAction.java b/src/main/java/net/onrc/onos/core/intent/ForwardAction.java
index ef6dd00..a3792d1 100644
--- a/src/main/java/net/onrc/onos/core/intent/ForwardAction.java
+++ b/src/main/java/net/onrc/onos/core/intent/ForwardAction.java
@@ -3,6 +3,10 @@
import net.onrc.onos.core.util.FlowEntryAction;
import net.onrc.onos.core.util.PortNumber;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.action.OFAction;
+import org.projectfloodlight.openflow.types.OFPort;
+
/**
* A class to represent the OpenFlow forwarding action.
*/
@@ -41,6 +45,11 @@
return action;
}
+ @Override
+ public OFAction getOFAction(OFFactory factory) {
+ return factory.actions().output(OFPort.of((int) dstPort), Short.MAX_VALUE);
+ }
+
/**
* A simple hash function that just used the destination port.
*
diff --git a/src/main/java/net/onrc/onos/core/intent/Match.java b/src/main/java/net/onrc/onos/core/intent/Match.java
index cddd6de..a3c397b 100644
--- a/src/main/java/net/onrc/onos/core/intent/Match.java
+++ b/src/main/java/net/onrc/onos/core/intent/Match.java
@@ -1,6 +1,5 @@
package net.onrc.onos.core.intent;
-
import java.util.Objects;
import net.floodlightcontroller.util.MACAddress;
@@ -10,6 +9,14 @@
import net.onrc.onos.core.util.IPv4Net;
import net.onrc.onos.core.util.PortNumber;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.match.Match.Builder;
+import org.projectfloodlight.openflow.protocol.match.MatchField;
+import org.projectfloodlight.openflow.types.EthType;
+import org.projectfloodlight.openflow.types.IPv4AddressWithMask;
+import org.projectfloodlight.openflow.types.MacAddress;
+import org.projectfloodlight.openflow.types.OFPort;
+
/**
* A class to represent the OpenFlow match.
* <p>
@@ -41,8 +48,10 @@
* @param dstMac destination Ethernet MAC address
*/
public Match(long sw, long srcPort,
- MACAddress srcMac, MACAddress dstMac) {
- this(sw, srcPort, srcMac, dstMac, ShortestPathIntent.EMPTYIPADDRESS, ShortestPathIntent.EMPTYIPADDRESS);
+ MACAddress srcMac, MACAddress dstMac) {
+ this(sw, srcPort, srcMac, dstMac,
+ ShortestPathIntent.EMPTYIPADDRESS,
+ ShortestPathIntent.EMPTYIPADDRESS);
}
/**
@@ -56,7 +65,7 @@
* @param dstIp destination IP address
*/
public Match(long sw, long srcPort, MACAddress srcMac, MACAddress dstMac,
- int srcIp, int dstIp) {
+ int srcIp, int dstIp) {
this.sw = sw;
this.srcPort = srcPort;
@@ -75,7 +84,7 @@
public boolean equals(Object obj) {
if (obj instanceof Match) {
Match other = (Match) obj;
- //TODO: we might consider excluding sw from this comparison
+ // TODO: we might consider excluding sw from this comparison
if (this.sw != other.sw) {
return false;
}
@@ -130,6 +139,30 @@
return match;
}
+ public Builder getOFMatchBuilder(OFFactory factory) {
+ Builder matchBuilder = factory.buildMatch();
+
+ if (srcMac != null) {
+ matchBuilder.setExact(MatchField.ETH_SRC, MacAddress.of(srcMac.toLong()));
+ }
+ if (dstMac != null) {
+ matchBuilder.setExact(MatchField.ETH_DST, MacAddress.of(dstMac.toLong()));
+ }
+ if (srcIp != ShortestPathIntent.EMPTYIPADDRESS) {
+ matchBuilder.setExact(MatchField.ETH_TYPE, EthType.IPv4)
+ .setMasked(MatchField.IPV4_SRC,
+ IPv4AddressWithMask.of(srcIp, IPV4_PREFIX_LEN));
+ }
+ if (dstIp != ShortestPathIntent.EMPTYIPADDRESS) {
+ matchBuilder.setExact(MatchField.ETH_TYPE, EthType.IPv4)
+ .setMasked(MatchField.IPV4_DST,
+ IPv4AddressWithMask.of(dstIp, IPV4_PREFIX_LEN));
+ }
+ matchBuilder.setExact(MatchField.IN_PORT, OFPort.of((int) srcPort));
+
+ return matchBuilder;
+ }
+
/**
* Returns a String representation of this Match.
*
@@ -137,7 +170,9 @@
*/
@Override
public String toString() {
- return "Sw:" + sw + " (" + srcPort + "," + srcMac + "," + dstMac + "," + srcIp + "," + dstIp + ")";
+ return "Sw:" + sw + " (" + srcPort + ","
+ + srcMac + "," + dstMac + ","
+ + srcIp + "," + dstIp + ")";
}
/**
@@ -147,8 +182,8 @@
*/
@Override
public int hashCode() {
- //TODO: we might consider excluding sw from the hash function
- // to make it easier to compare matches between switches
- return Objects.hash(sw, srcPort, srcMac, dstMac, srcIp, dstIp);
+ // TODO: we might consider excluding sw from the hash function
+ // to make it easier to compare matches between switches
+ return Objects.hash(sw, srcPort, srcMac, dstMac, srcIp, dstIp);
}
}
diff --git a/src/main/java/net/onrc/onos/core/intent/runtime/PlanInstallModule.java b/src/main/java/net/onrc/onos/core/intent/runtime/PlanInstallModule.java
index 025b6d7..058b2d0 100644
--- a/src/main/java/net/onrc/onos/core/intent/runtime/PlanInstallModule.java
+++ b/src/main/java/net/onrc/onos/core/intent/runtime/PlanInstallModule.java
@@ -31,17 +31,17 @@
import net.onrc.onos.core.intent.ShortestPathIntent;
import net.onrc.onos.core.topology.ITopologyService;
-import org.openflow.protocol.OFFlowRemoved;
-import org.openflow.protocol.OFMessage;
-import org.openflow.protocol.OFType;
+import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The PlanInstallModule contains the PlanCalcRuntime and PlanInstallRuntime.
* <p>
- * It is responsible for converting Intents into FlowMods and seeing that
- * they are properly installed.
+ * It is responsible for converting Intents into FlowMods and seeing that they
+ * are properly installed.
*/
public class PlanInstallModule implements IFloodlightModule, IOFMessageListener {
@@ -76,8 +76,8 @@
while (true) {
try {
IntentOperationList intents = intentQueue.take();
- //TODO: consider draining the remaining intent lists
- // and processing in one big batch
+ // TODO: consider draining the remaining intent lists
+ // and processing in one big batch
processIntents(intents);
} catch (InterruptedException e) {
@@ -111,8 +111,9 @@
}
/***
- * This function is for sending intent state notification to other ONOS instances.
- * The argument of "domainSwitchDpids" is required for dispatching this ONOS's managed switches.
+ * This function is for sending intent state notification to other ONOS
+ * instances. The argument of "domainSwitchDpids" is required for
+ * dispatching this ONOS's managed switches.
*
* @param intents list of intents
* @param installed true if Intents were installed
@@ -125,31 +126,32 @@
for (IntentOperation i : intents) {
IntentState newState;
switch (i.operator) {
- case REMOVE:
- if (installed) {
- newState = success ? IntentState.DEL_ACK : IntentState.DEL_PENDING;
- } else {
- newState = IntentState.DEL_REQ;
+ case REMOVE:
+ if (installed) {
+ newState = success ? IntentState.DEL_ACK
+ : IntentState.DEL_PENDING;
+ } else {
+ newState = IntentState.DEL_REQ;
+ }
+ break;
+ case ADD:
+ default:
+ if (installed) {
+ if (domainSwitchDpids != null) {
+ states.domainSwitchDpids.addAll(domainSwitchDpids);
}
- break;
- case ADD:
- default:
- if (installed) {
- if (domainSwitchDpids != null) {
- states.domainSwitchDpids.addAll(domainSwitchDpids);
- }
- newState = success ? IntentState.INST_ACK : IntentState.INST_NACK;
- } else {
- newState = IntentState.INST_REQ;
- }
- break;
+ newState = success ? IntentState.INST_ACK : IntentState.INST_NACK;
+ } else {
+ newState = IntentState.INST_REQ;
+ }
+ break;
}
states.put(i.intent.getId(), newState);
}
if (log.isTraceEnabled()) {
log.trace("sendNotifications, states {}, domainSwitchDpids {}",
- states, states.domainSwitchDpids);
+ states, states.domainSwitchDpids);
}
// Send notifications using the same key every time
@@ -222,6 +224,7 @@
/**
* Formatted log for debugging.
+ * <p>
* TODO: merge this into debugging framework
*
* @param step the step of computation
@@ -261,7 +264,8 @@
IntentOperationList.class);
eventListener.start();
// start publisher
- intentStateChannel = datagridService.createChannel(INTENT_STATE_EVENT_CHANNEL_NAME,
+ intentStateChannel = datagridService.createChannel(
+ INTENT_STATE_EVENT_CHANNEL_NAME,
Long.class,
IntentStateList.class);
floodlightProvider.addOFMessageListener(OFType.FLOW_REMOVED, this);
@@ -308,19 +312,19 @@
@Override
public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
if (msg.getType().equals(OFType.FLOW_REMOVED) &&
- (msg instanceof OFFlowRemoved)) {
+ (msg instanceof OFFlowRemoved)) {
OFFlowRemoved flowRemovedMsg = (OFFlowRemoved) msg;
if (log.isTraceEnabled()) {
- log.trace("Receive flowRemoved from sw {} : Cookie {}",
- sw.getId(), flowRemovedMsg.getCookie());
+ log.trace("Receive flowRemoved from sw {} : Cookie {}",
+ sw.getId(), flowRemovedMsg.getCookie());
}
- String intentParentId = Long.toString(flowRemovedMsg.getCookie());
+ String intentParentId = Long.toString(flowRemovedMsg.getCookie().getValue());
Intent intent = parentIntentMap.get(intentParentId);
- //We assume if the path src sw flow entry is expired,
- //the path is expired.
+ // We assume if the path src sw flow entry is expired,
+ // the path is expired.
if (!isFlowSrcRemoved(sw.getId(), intentParentId)) {
return Command.CONTINUE;
}
@@ -343,7 +347,8 @@
log.debug("addEntry to intentStateChannel intentId {}, states {}",
pathIntentId, newState);
- intentStateChannel.addTransientEntry(flowRemovedMsg.getCookie(), states);
+ intentStateChannel.addTransientEntry(flowRemovedMsg.getCookie().getValue(),
+ states);
}
return Command.CONTINUE;
@@ -355,10 +360,10 @@
* @param dpid DPID of affected switch
* @param shortestPathIntentId Intent to check
* @return true if the flow's source switch entry is removed or expired,
- * otherwise false.
+ * otherwise false.
*/
private boolean isFlowSrcRemoved(long dpid, String shortestPathIntentId) {
- Intent intent = parentIntentMap.get(shortestPathIntentId);
+ Intent intent = parentIntentMap.get(shortestPathIntentId);
ShortestPathIntent spfIntent = null;
if (intent instanceof ShortestPathIntent) {
spfIntent = (ShortestPathIntent) intent;
@@ -376,33 +381,19 @@
return false;
}
- /*
- * (non-Javadoc)
- * @see net.floodlightcontroller.core.IListener#getName()
- */
@Override
public String getName() {
- // TODO Auto-generated method stub
- return null;
+ return "planInstall";
}
- /*
- * (non-Javadoc)
- * @see net.floodlightcontroller.core.IListener#isCallbackOrderingPrereq(java.lang.Object, java.lang.String)
- */
@Override
public boolean isCallbackOrderingPrereq(OFType type, String name) {
- // TODO Auto-generated method stub
return false;
}
- /*
- * (non-Javadoc)
- * @see net.floodlightcontroller.core.IListener#isCallbackOrderingPostreq(java.lang.Object, java.lang.String)
- */
@Override
public boolean isCallbackOrderingPostreq(OFType type, String name) {
- // TODO Auto-generated method stub
return false;
}
+
}
diff --git a/src/main/java/net/onrc/onos/core/intent/runtime/PlanInstallRuntime.java b/src/main/java/net/onrc/onos/core/intent/runtime/PlanInstallRuntime.java
index f942fa8..8a444d7 100644
--- a/src/main/java/net/onrc/onos/core/intent/runtime/PlanInstallRuntime.java
+++ b/src/main/java/net/onrc/onos/core/intent/runtime/PlanInstallRuntime.java
@@ -16,14 +16,15 @@
import net.onrc.onos.core.intent.FlowEntry;
import net.onrc.onos.core.util.Pair;
-import org.openflow.protocol.OFBarrierReply;
+import org.projectfloodlight.openflow.protocol.OFBarrierReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
- * This class is responsible for installing plans (lists of sets of FlowEntries) into local switches.
- * In this context, a local switch is a switch for which this ONOS instance is the master.
- * It also is responsible for sending barrier messages between sets.
+ * This class is responsible for installing plans (lists of sets of FlowEntries)
+ * into local switches. In this context, a local switch is a switch for which
+ * this ONOS instance is the master. It also is responsible for sending barrier
+ * messages between sets.
*/
public class PlanInstallRuntime {
@@ -39,16 +40,18 @@
* @param pusher the FlowPusherService to use for FlowEntry installation
*/
public PlanInstallRuntime(IFloodlightProviderService provider,
- IFlowPusherService pusher) {
+ IFlowPusherService pusher) {
this.provider = provider;
this.pusher = pusher;
}
/**
- * This class is a temporary class for collecting FlowMod installation information. It is
- * largely used for debugging purposes, and it should not be depended on for other purposes.
+ * This class is a temporary class for collecting FlowMod installation
+ * information. It is largely used for debugging purposes, and it should not
+ * be depended on for other purposes.
* <p>
- * TODO: This class should be wrapped into a more generic debugging framework when available.
+ * TODO: This class should be wrapped into a more generic debugging
+ * framework when available.
*/
private static class FlowModCount {
WeakReference<IOFSwitch> sw;
@@ -72,17 +75,17 @@
*/
void addFlowEntry(FlowEntry entry) {
switch (entry.getOperator()) {
- case ADD:
- modFlows++;
- break;
- case ERROR:
- errors++;
- break;
- case REMOVE:
- delFlows++;
- break;
- default:
- break;
+ case ADD:
+ modFlows++;
+ break;
+ case ERROR:
+ errors++;
+ break;
+ case REMOVE:
+ delFlows++;
+ break;
+ default:
+ break;
}
}
@@ -101,13 +104,15 @@
static Map<IOFSwitch, FlowModCount> map = new WeakHashMap<>();
/**
- * This function is used for collecting statistics information. It should be called for
- * every FlowEntry that is pushed to the switch for accurate statistics.
+ * This function is used for collecting statistics information. It
+ * should be called for every FlowEntry that is pushed to the switch for
+ * accurate statistics.
* <p>
- * This class maintains a map of Switches and FlowModCount collection objects, which
- * are used for collection.
+ * This class maintains a map of Switches and FlowModCount collection
+ * objects, which are used for collection.
* <p>
- * TODO: This should be refactored to use a more generic mechanism when available.
+ * TODO: This should be refactored to use a more generic mechanism when
+ * available.
*
* @param sw the switch that entry is being pushed to
* @param entry the FlowEntry being pushed
@@ -122,7 +127,8 @@
}
/**
- * Reset the statistics collection. It should be called when required for debugging.
+ * Reset the statistics collection. It should be called when required
+ * for debugging.
*/
static void startCount() {
map.clear();
@@ -148,11 +154,11 @@
/**
* This function should be called to install the FlowEntries in the plan.
* <p>
- * Each set of FlowEntries can be installed together, but all entries should be installed
- * proceeded to the next set.
+ * Each set of FlowEntries can be installed together, but all entries should
+ * be installed proceeded to the next set.
* <p>
- * TODO: This method lack coordination between the other ONOS instances before proceeded
- * with the next set of entries
+ * TODO: This method lack coordination between the other ONOS instances
+ * before proceeded with the next set of entries
*
* @param plan list of set of FlowEntries for installation on local switches
* @return true (we assume installation is successful)
@@ -164,7 +170,7 @@
log.debug("IOFSwitches: {}", switches);
FlowModCount.startCount();
for (Set<FlowEntry> phase : plan) {
- Set<Pair<IOFSwitch, net.onrc.onos.core.util.FlowEntry>> entries = new HashSet<>();
+ Set<Pair<IOFSwitch, FlowEntry>> entries = new HashSet<>();
Set<IOFSwitch> modifiedSwitches = new HashSet<>();
long step1 = System.nanoTime();
@@ -176,7 +182,7 @@
log.debug("Skipping flow entry: {}", entry);
continue;
}
- entries.add(new Pair<>(sw, entry.getFlowEntry()));
+ entries.add(new Pair<>(sw, entry));
modifiedSwitches.add(sw);
FlowModCount.countFlowEntry(sw, entry);
}
diff --git a/src/main/java/net/onrc/onos/core/linkdiscovery/LinkDiscoveryManager.java b/src/main/java/net/onrc/onos/core/linkdiscovery/LinkDiscoveryManager.java
index a924f00..4c87501 100644
--- a/src/main/java/net/onrc/onos/core/linkdiscovery/LinkDiscoveryManager.java
+++ b/src/main/java/net/onrc/onos/core/linkdiscovery/LinkDiscoveryManager.java
@@ -24,7 +24,6 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
-import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -38,6 +37,7 @@
import net.floodlightcontroller.core.IFloodlightProviderService;
import net.floodlightcontroller.core.IOFMessageListener;
import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.IOFSwitch.PortChangeType;
import net.floodlightcontroller.core.IOFSwitchListener;
import net.floodlightcontroller.core.IUpdate;
import net.floodlightcontroller.core.annotations.LogMessageCategory;
@@ -57,35 +57,37 @@
import net.onrc.onos.core.registry.IControllerRegistryService;
import net.onrc.onos.core.util.SwitchPort;
-import org.openflow.protocol.OFMessage;
-import org.openflow.protocol.OFPacketIn;
-import org.openflow.protocol.OFPacketOut;
-import org.openflow.protocol.OFPhysicalPort;
-import org.openflow.protocol.OFPhysicalPort.OFPortConfig;
-import org.openflow.protocol.OFPhysicalPort.OFPortState;
-import org.openflow.protocol.OFPort;
-import org.openflow.protocol.OFPortStatus;
-import org.openflow.protocol.OFPortStatus.OFPortReason;
-import org.openflow.protocol.OFType;
-import org.openflow.protocol.action.OFAction;
-import org.openflow.protocol.action.OFActionOutput;
-import org.openflow.protocol.action.OFActionType;
-import org.openflow.util.HexString;
+import org.projectfloodlight.openflow.protocol.OFFactories;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFPacketIn;
+import org.projectfloodlight.openflow.protocol.OFPacketOut;
+import org.projectfloodlight.openflow.protocol.OFPortConfig;
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
+import org.projectfloodlight.openflow.protocol.OFPortReason;
+import org.projectfloodlight.openflow.protocol.OFPortState;
+import org.projectfloodlight.openflow.protocol.OFPortStatus;
+import org.projectfloodlight.openflow.protocol.OFType;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+import org.projectfloodlight.openflow.protocol.action.OFAction;
+import org.projectfloodlight.openflow.types.OFBufferId;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.util.HexString;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Discovers links between OpenFlow switches.
- * <p/>
- * Discovery is performed by sending probes (LLDP packets) over the links in
- * the data plane. The LinkDiscoveryManager sends probes periodically on all
- * ports on all connected switches. The probes contain the sending switch's
- * DPID and outgoing port number. LLDP packets that are received (via an
- * OpenFlow packet-in) indicate there is a link between the receiving port and
- * the sending port, which was encoded in the LLDP. When the
- * LinkDiscoveryManager observes a new link, a Link object is created and an
- * event is fired for any event listeners.
- * <p/>
+ * <p>
+ * Discovery is performed by sending probes (LLDP packets) over the links in the
+ * data plane. The LinkDiscoveryManager sends probes periodically on all ports
+ * on all connected switches. The probes contain the sending switch's DPID and
+ * outgoing port number. LLDP packets that are received (via an OpenFlow
+ * packet-in) indicate there is a link between the receiving port and the
+ * sending port, which was encoded in the LLDP. When the LinkDiscoveryManager
+ * observes a new link, a Link object is created and an event is fired for any
+ * event listeners.
+ * </p>
* Links are removed for one of three reasons:
* <ul>
* <li>A probe has not been received on the link for an interval (the timeout
@@ -104,6 +106,9 @@
private static final Logger log =
LoggerFactory.getLogger(LinkDiscoveryManager.class);
+ // TODO Remove these factories.
+ protected OFFactory factory13 = OFFactories.getFactory(OFVersion.OF_13);
+ protected OFFactory factory10 = OFFactories.getFactory(OFVersion.OF_10);
private IFloodlightProviderService controller;
@@ -121,13 +126,16 @@
// Link discovery task details.
private SingletonTask discoveryTask;
private static final int DISCOVERY_TASK_INTERVAL = 1;
- private static final int LINK_TIMEOUT = 35; // original 35 secs, aggressive 5 secs
- private static final int LLDP_TO_ALL_INTERVAL = 15; //original 15 seconds, aggressive 2 secs.
+ private static final int LINK_TIMEOUT = 35; // original 35 secs, aggressive
+ // 5 secs
+ private static final int LLDP_TO_ALL_INTERVAL = 15; // original 15 seconds,
+ // aggressive 2 secs.
private long lldpClock = 0;
// This value is intentionally kept higher than LLDP_TO_ALL_INTERVAL.
// If we want to identify link failures faster, we could decrease this
// value to a small number, say 1 or 2 sec.
- private static final int LLDP_TO_KNOWN_INTERVAL = 20; // LLDP frequency for known links
+ private static final int LLDP_TO_KNOWN_INTERVAL = 20; // LLDP frequency for
+ // known links
private ReentrantReadWriteLock lock;
@@ -149,8 +157,8 @@
/**
* Listeners are called in the order they were added to the the list.
*/
- private final List<ILinkDiscoveryListener> linkDiscoveryListeners
- = new CopyOnWriteArrayList<>();
+ private final List<ILinkDiscoveryListener> linkDiscoveryListeners =
+ new CopyOnWriteArrayList<>();
/**
* List of ports through which LLDPs are not sent.
@@ -230,8 +238,8 @@
discover(npt);
}
- private boolean isLinkDiscoverySuppressed(long sw, short portNumber) {
- return this.suppressLinkDiscovery.contains(new NodePortTuple(sw, portNumber));
+ private boolean isLinkDiscoverySuppressed(long sw, short p) {
+ return this.suppressLinkDiscovery.contains(new NodePortTuple(sw, p));
}
private void discoverLinks() {
@@ -239,7 +247,7 @@
// time out known links.
timeOutLinks();
- //increment LLDP clock
+ // increment LLDP clock
lldpClock = (lldpClock + 1) % LLDP_TO_ALL_INTERVAL;
if (lldpClock == 0) {
@@ -271,8 +279,8 @@
}
/**
- * Send link discovery message out of a given switch port.
- * The discovery message is a standard LLDP containing ONOS-specific TLVs.
+ * Send link discovery message out of a given switch port. The discovery
+ * message is a standard LLDP containing ONOS-specific TLVs.
*
* @param sw the switch to send on
* @param port the port to send out
@@ -284,18 +292,18 @@
"to the switch.",
recommendation = LogMessageDoc.CHECK_SWITCH)
protected void sendDiscoveryMessage(long sw, short port,
- boolean isReverse) {
+ boolean isReverse) {
IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw);
if (iofSwitch == null) {
return;
}
- if (port == OFPort.OFPP_LOCAL.getValue()) {
+ if (port == OFPort.LOCAL.getShortPortNumber()) {
return;
}
- OFPhysicalPort ofpPort = iofSwitch.getPort(port);
+ OFPortDesc ofpPort = iofSwitch.getPort(port);
if (ofpPort == null) {
if (log.isTraceEnabled()) {
@@ -314,7 +322,9 @@
sw, port);
}
- OFPacketOut po = createLLDPPacketOut(sw, ofpPort, isReverse);
+ OFFactory factory = (iofSwitch.getOFVersion() == OFVersion.OF_10)
+ ? factory10 : factory13;
+ OFPacketOut po = createLLDPPacketOut(sw, ofpPort, isReverse, factory);
try {
iofSwitch.write(po, null);
@@ -332,10 +342,11 @@
* @param dpid the dpid of the outgoing switch
* @param port the outgoing port
* @param isReverse whether this is a reverse LLDP or not
+ * @param factory the factory to use to create the message
* @return Packet_out message with LLDP data
*/
private OFPacketOut createLLDPPacketOut(long dpid,
- final OFPhysicalPort port, boolean isReverse) {
+ final OFPortDesc port, boolean isReverse, OFFactory factory) {
// Set up packets
// TODO optimize by not creating new packets each time
OnosLldp lldpPacket = new OnosLldp();
@@ -346,29 +357,25 @@
ethPacket.setPayload(lldpPacket);
ethPacket.setPad(true);
- final OFPacketOut packetOut = (OFPacketOut) floodlightProvider.getOFMessageFactory()
- .getMessage(OFType.PACKET_OUT);
- packetOut.setBufferId(OFPacketOut.BUFFER_ID_NONE);
-
- final List<OFAction> actionsList = new LinkedList<OFAction>();
- final OFActionOutput out = (OFActionOutput) floodlightProvider.getOFMessageFactory()
- .getAction(OFActionType.OUTPUT);
- out.setPort(port.getPortNumber());
- actionsList.add(out);
- packetOut.setActions(actionsList);
- final short alen = (short) OFActionOutput.MINIMUM_LENGTH;
-
lldpPacket.setSwitch(dpid);
- lldpPacket.setPort(port.getPortNumber());
+ lldpPacket.setPort(port.getPortNo().getShortPortNumber());
lldpPacket.setReverse(isReverse);
- ethPacket.setSourceMACAddress(port.getHardwareAddress());
-
+ ethPacket.setSourceMACAddress(port.getHwAddr().getBytes());
final byte[] lldp = ethPacket.serialize();
- packetOut.setActionsLength(alen);
- packetOut.setPacketData(lldp);
- packetOut
- .setLength((short) (OFPacketOut.MINIMUM_LENGTH + alen + lldp.length));
- return packetOut;
+
+ List<OFAction> actions = new ArrayList<OFAction>();
+ actions.add(factory.actions()
+ .buildOutput()
+ .setPort(OFPort.ofShort(port.getPortNo().getShortPortNumber()))
+ .build());
+ OFPacketOut po = factory.buildPacketOut()
+ .setData(lldp)
+ .setBufferId(OFBufferId.NO_BUFFER)
+ .setInPort(OFPort.CONTROLLER)
+ .setActions(actions)
+ .build();
+
+ return po;
}
/**
@@ -383,12 +390,14 @@
if (sw.getEnabledPorts() == null) {
continue;
}
- for (OFPhysicalPort ofp : sw.getEnabledPorts()) {
- if (isLinkDiscoverySuppressed(sw.getId(), ofp.getPortNumber())) {
+ for (OFPortDesc ofp : sw.getEnabledPorts()) {
+ if (isLinkDiscoverySuppressed(sw.getId(),
+ ofp.getPortNo().getShortPortNumber())) {
continue;
}
- sendDiscoveryMessage(sw.getId(), ofp.getPortNumber(), false);
+ sendDiscoveryMessage(sw.getId(),
+ ofp.getPortNo().getShortPortNumber(), false);
}
}
}
@@ -401,31 +410,31 @@
@Override
public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
switch (msg.getType()) {
- case PACKET_IN:
- if (msg instanceof OFPacketIn) {
- return this.handlePacketIn(sw.getId(), (OFPacketIn) msg,
- cntx);
- }
- break;
- case PORT_STATUS:
- if (msg instanceof OFPortStatus) {
- return this.handlePortStatus(sw, (OFPortStatus) msg);
- }
- break;
- default:
- break;
+ case PACKET_IN:
+ if (msg instanceof OFPacketIn) {
+ return this.handlePacketIn(sw.getId(), (OFPacketIn) msg,
+ cntx);
+ }
+ break;
+ case PORT_STATUS:
+ if (msg instanceof OFPortStatus) {
+ return this.handlePortStatus(sw, (OFPortStatus) msg);
+ }
+ break;
+ default:
+ break;
}
return Command.CONTINUE;
}
- protected Command handleLldp(LLDP lldp, long sw, OFPacketIn pi) {
+ protected Command handleLldp(LLDP lldp, long sw, OFPacketIn pi, short inport) {
// If LLDP is suppressed on this port, ignore received packet as well
- IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw);
+ IOFSwitch iofSwitch = floodlightProvider.getSwitch(sw);
if (iofSwitch == null) {
return Command.STOP;
}
- if (isLinkDiscoverySuppressed(sw, pi.getInPort())) {
+ if (isLinkDiscoverySuppressed(sw, inport)) {
return Command.STOP;
}
@@ -435,7 +444,7 @@
}
// Verify this LLDP packet matches what we're looking for
- byte[] packetData = pi.getPacketData();
+ byte[] packetData = pi.getData();
if (!OnosLldp.isOnosLldp(packetData)) {
log.trace("Dropping LLDP that wasn't sent by ONOS");
return Command.STOP;
@@ -444,10 +453,10 @@
SwitchPort switchPort = OnosLldp.extractSwitchPort(packetData);
long remoteDpid = switchPort.dpid().value();
short remotePort = switchPort.port().shortValue();
- IOFSwitch remoteSwitch = floodlightProvider.getSwitches().get(switchPort.dpid().value());
+ IOFSwitch remoteSwitch = floodlightProvider.getSwitches().get(
+ switchPort.dpid().value());
-
- OFPhysicalPort physicalPort = null;
+ OFPortDesc physicalPort = null;
if (remoteSwitch != null) {
physicalPort = remoteSwitch.getPort(remotePort);
if (!remoteSwitch.portEnabled(remotePort)) {
@@ -466,20 +475,24 @@
return Command.STOP;
}
}
- if (!iofSwitch.portEnabled(pi.getInPort())) {
+ if (!iofSwitch.portEnabled(inport)) {
if (log.isTraceEnabled()) {
log.trace("Ignoring link with disabled dest port: " +
- "switch {} port {}", sw, pi.getInPort());
+ "switch {} port {}", sw, inport);
}
return Command.STOP;
}
- int srcPortState = (physicalPort != null) ? physicalPort.getState() : 0;
- physicalPort = iofSwitch.getPort(pi.getInPort());
- int dstPortState = (physicalPort != null) ? physicalPort.getState() : 0;
+ // TODO It probably should be empty Set instead of null. Confirm and fix.
+ Set<OFPortState> srcPortState = (physicalPort != null)
+ ? physicalPort.getState() : null;
+ physicalPort = iofSwitch.getPort(inport);
+ Set<OFPortState> dstPortState = (physicalPort != null)
+ ? physicalPort.getState() : null;
- // Store the time of update to this link, and push it out to routingEngine
- Link lt = new Link(remoteDpid, remotePort, iofSwitch.getId(), pi.getInPort());
+ // Store the time of update to this link, and push it out to
+ // routingEngine
+ Link lt = new Link(remoteDpid, remotePort, iofSwitch.getId(), inport);
LinkInfo linkInfo = new LinkInfo(System.currentTimeMillis(),
System.currentTimeMillis(), srcPortState, dstPortState);
@@ -499,8 +512,8 @@
LinkInfo reverseInfo = links.get(reverseLink);
if (reverseInfo == null) {
// the reverse link does not exist.
- if (newLinkInfo.getFirstSeenTime() >
- System.currentTimeMillis() - LINK_TIMEOUT) {
+ if (newLinkInfo.getFirstSeenTime() > System.currentTimeMillis()
+ - LINK_TIMEOUT) {
this.sendDiscoveryMessage(lt.getDst(), lt.getDstPort(), true);
}
}
@@ -511,13 +524,15 @@
}
protected Command handlePacketIn(long sw, OFPacketIn pi,
- FloodlightContext cntx) {
+ FloodlightContext cntx) {
Ethernet eth =
IFloodlightProviderService.bcStore.get(cntx,
IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
+ short inport = (short) cntx.getStorage()
+ .get(IFloodlightProviderService.CONTEXT_PI_INPORT);
if (eth.getEtherType() == Ethernet.TYPE_LLDP) {
- return handleLldp((LLDP) eth.getPayload(), sw, pi);
+ return handleLldp((LLDP) eth.getPayload(), sw, pi, inport);
} else if (eth.getEtherType() < 1500) {
long destMac = eth.getDestinationMAC().toLong();
if ((destMac & LINK_LOCAL_MASK) == LINK_LOCAL_VALUE) {
@@ -557,6 +572,7 @@
// If this is the first time we've seen the link, add the Link
// object to the data structures/indexes as well
if (existingInfo == null) {
+ log.trace("Creating new Link: {}", lt);
// index it by switch source
if (!switchLinks.containsKey(lt.getSrc())) {
switchLinks.put(lt.getSrc(), new HashSet<Link>());
@@ -639,8 +655,8 @@
}
/**
- * Handles an OFPortStatus message from a switch. We will add or
- * delete LinkTupes as well re-compute the topology if needed.
+ * Handles an OFPortStatus message from a switch. We will add or delete
+ * LinkTupes as well re-compute the topology if needed.
*
* @param sw The dpid of the switch that sent the port status message
* @param ps The OFPortStatus message
@@ -657,14 +673,14 @@
if (log.isTraceEnabled()) {
log.trace("handlePortStatus: Switch {} port #{} reason {}; " +
"config is {} state is {}",
- new Object[]{sw.getStringId(),
- ps.getDesc().getPortNumber(),
+ new Object[] {sw.getStringId(),
+ ps.getDesc().getPortNo(),
ps.getReason(),
ps.getDesc().getConfig(),
ps.getDesc().getState()});
}
- short port = ps.getDesc().getPortNumber();
+ short port = ps.getDesc().getPortNo().getShortPortNumber();
NodePortTuple npt = new NodePortTuple(sw.getId(), port);
boolean linkDeleted = false;
boolean linkInfoChanged = false;
@@ -673,14 +689,12 @@
try {
// if ps is a delete, or a modify where the port is down or
// configured down
- if ((byte) OFPortReason.OFPPR_DELETE.ordinal() == ps.getReason() ||
- ((byte) OFPortReason.OFPPR_MODIFY.ordinal() ==
- ps.getReason() && !portEnabled(ps.getDesc()))) {
-
+ if (OFPortReason.DELETE == ps.getReason() ||
+ (OFPortReason.MODIFY == ps.getReason() &&
+ !portEnabled(ps.getDesc()))) {
deleteLinksOnPort(npt);
linkDeleted = true;
- } else if (ps.getReason() ==
- (byte) OFPortReason.OFPPR_MODIFY.ordinal()) {
+ } else if (ps.getReason() == OFPortReason.MODIFY) {
// If ps is a port modification and the port state has changed
// that affects links in the topology
@@ -691,18 +705,22 @@
LinkInfo newLinkInfo = null;
if (lt.isSrcPort(npt) &&
- linkInfo.getSrcPortState() != ps.getDesc().getState()) {
- // If this port status is for the src port and the port
- // state has changed, create a new link info with the new state
+ !linkInfo.getSrcPortState().equals(
+ ps.getDesc().getState())) {
+ // If this port status is for the src port and the
+ // port state has changed, create a new link info
+ // with the new state
newLinkInfo = new LinkInfo(linkInfo.getFirstSeenTime(),
linkInfo.getLastProbeReceivedTime(),
ps.getDesc().getState(),
linkInfo.getDstPortState());
} else if (lt.isDstPort(npt) &&
- linkInfo.getDstPortState() != ps.getDesc().getState()) {
- // If this port status is for the dst port and the port
- // state has changed, create a new link info with the new state
+ !linkInfo.getDstPortState().equals(
+ ps.getDesc().getState())) {
+ // If this port status is for the dst port and the
+ // port state has changed, create a new link info
+ // with the new state
newLinkInfo = new LinkInfo(linkInfo.getFirstSeenTime(),
linkInfo.getLastProbeReceivedTime(),
@@ -718,13 +736,12 @@
}
}
-
if (!linkDeleted && !linkInfoChanged) {
if (log.isTraceEnabled()) {
log.trace("handlePortStatus: Switch {} port #{} reason {};" +
" no links to update/remove",
- new Object[]{HexString.toHexString(sw.getId()),
- ps.getDesc().getPortNumber(),
+ new Object[] {HexString.toHexString(sw.getId()),
+ ps.getDesc().getPortNo(),
ps.getReason()});
}
}
@@ -745,32 +762,37 @@
}
/**
- * Process a new port.
- * If link discovery is disabled on the port, then do nothing.
- * Otherwise, send LLDP message.
+ * Process a new port. If link discovery is disabled on the port, then do
+ * nothing. Otherwise, send LLDP message.
*
* @param sw the dpid of the switch the port is on
* @param p the number of the port
*/
- private void processNewPort(long sw, short p) {
- if (isLinkDiscoverySuppressed(sw, p)) {
+ private void processNewPort(long sw, int p) {
+ if (isLinkDiscoverySuppressed(sw, (short) p)) {
// Do nothing as link discovery is suppressed.
return;
} else {
- discover(sw, p);
+ discover(sw, (short) p);
}
}
/**
- * We send out LLDP messages when a switch is added to discover the topology.
+ * We send out LLDP messages when a switch is added to discover the
+ * topology.
*
- * @param sw The IOFSwitch that connected to the controller
+ * @param swId the datapath Id of the new switch
*/
@Override
- public void addedSwitch(IOFSwitch sw) {
+ public void switchActivatedMaster(long swId) {
+ IOFSwitch sw = floodlightProvider.getSwitch(swId);
+ if (sw == null) {
+ log.warn("Added switch not available {} ", swId);
+ return;
+ }
if (sw.getEnabledPorts() != null) {
- for (Short p : sw.getEnabledPortNumbers()) {
- processNewPort(sw.getId(), p);
+ for (Integer p : sw.getEnabledPortNumbers()) {
+ processNewPort(swId, p);
}
}
}
@@ -778,23 +800,27 @@
/**
* When a switch disconnects we remove any links from our map and notify.
*
- * @param iofSwitch the switch that was removed
+ * @param swId the datapath Id of the switch that was removed
*/
@Override
- public void removedSwitch(IOFSwitch iofSwitch) {
+ public void switchDisconnected(long swId) {
+ IOFSwitch sw = floodlightProvider.getSwitch(swId);
+ if (sw == null) {
+ log.warn("Removed switch not available {} ", swId);
+ return;
+ }
// Update event history
- long sw = iofSwitch.getId();
List<Link> eraseList = new ArrayList<Link>();
lock.writeLock().lock();
try {
- if (switchLinks.containsKey(sw)) {
+ if (switchLinks.containsKey(swId)) {
if (log.isTraceEnabled()) {
log.trace("Handle switchRemoved. Switch {}; removing links {}",
- HexString.toHexString(sw), switchLinks.get(sw));
+ HexString.toHexString(swId), switchLinks.get(swId));
}
// add all tuples with an endpoint on this switch to erase list
- eraseList.addAll(switchLinks.get(sw));
+ eraseList.addAll(switchLinks.get(swId));
deleteLinks(eraseList);
}
} finally {
@@ -802,14 +828,34 @@
}
}
+ @Override
+ public void switchActivatedEqual(long swId) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void switchMasterToEqual(long swId) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void switchEqualToMaster(long swId) {
+ // for now treat as switchActivatedMaster
+ switchActivatedMaster(swId);
+ }
+
/*
- * We don't react the port changed notifications here. we listen for
+ * We don't react to port changed notifications here. we listen for
* OFPortStatus messages directly. Might consider using this notifier
* instead
*/
@Override
- public void switchPortChanged(Long switchId) {
- // no-op
+ public void switchPortChanged(long swId, OFPortDesc port,
+ PortChangeType changeType) {
+ // TODO Auto-generated method stub
+
}
/**
@@ -823,7 +869,7 @@
if (log.isTraceEnabled()) {
log.trace("handlePortStatus: Switch {} port #{} " +
"removing links {}",
- new Object[]{HexString.toHexString(npt.getNodeId()),
+ new Object[] {HexString.toHexString(npt.getNodeId()),
npt.getPortId(),
this.portLinks.get(npt)});
}
@@ -833,8 +879,8 @@
}
/**
- * Iterates through the list of links and deletes if the
- * last discovery message reception time exceeds timeout values.
+ * Iterates through the list of links and deletes if the last discovery
+ * message reception time exceeds timeout values.
*/
protected void timeOutLinks() {
List<Link> eraseList = new ArrayList<Link>();
@@ -850,7 +896,7 @@
LinkInfo info = entry.getValue();
if ((info.getLastProbeReceivedTime() + (1000L * LINK_TIMEOUT)
- < curTime)) {
+ < curTime)) {
eraseList.add(entry.getKey());
}
}
@@ -861,14 +907,14 @@
}
}
- private boolean portEnabled(OFPhysicalPort port) {
+ private boolean portEnabled(OFPortDesc port) {
if (port == null) {
return false;
}
- if ((OFPortConfig.OFPPC_PORT_DOWN.getValue() & port.getConfig()) > 0) {
+ if (port.getConfig().contains(OFPortConfig.PORT_DOWN)) {
return false;
}
- if ((OFPortState.OFPPS_LINK_DOWN.getValue() & port.getState()) > 0) {
+ if (port.getState().contains(OFPortState.LINK_DOWN)) {
return false;
}
return true;
@@ -955,7 +1001,8 @@
@LogMessageDocs({
@LogMessageDoc(level = "ERROR",
message = "No storage source found.",
- explanation = "Storage source was not initialized; cannot initialize " +
+ explanation = "Storage source was not initialized; cannot initialize "
+ +
"link discovery.",
recommendation = LogMessageDoc.REPORT_CONTROLLER_BUG),
@LogMessageDoc(level = "ERROR",
@@ -966,7 +1013,8 @@
recommendation = LogMessageDoc.REPORT_CONTROLLER_BUG),
@LogMessageDoc(level = "ERROR",
message = "No storage source found.",
- explanation = "Storage source was not initialized; cannot initialize " +
+ explanation = "Storage source was not initialized; cannot initialize "
+ +
"link discovery.",
recommendation = LogMessageDoc.REPORT_CONTROLLER_BUG),
@LogMessageDoc(level = "ERROR",
diff --git a/src/main/java/net/onrc/onos/core/linkdiscovery/LinkInfo.java b/src/main/java/net/onrc/onos/core/linkdiscovery/LinkInfo.java
index fc19951..bc11c91 100644
--- a/src/main/java/net/onrc/onos/core/linkdiscovery/LinkInfo.java
+++ b/src/main/java/net/onrc/onos/core/linkdiscovery/LinkInfo.java
@@ -1,6 +1,7 @@
/**
* Copyright 2011, Big Switch Networks, Inc.
* Originally created by David Erickson, Stanford University
+ *
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may obtain
* a copy of the License at
@@ -12,34 +13,35 @@
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
- */
+ **/
package net.onrc.onos.core.linkdiscovery;
+import java.util.Set;
+
import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryService.LinkType;
+import org.projectfloodlight.openflow.protocol.OFPortState;
+
import com.google.common.primitives.Longs;
/**
* Records information about a link.
*/
public final class LinkInfo {
-
/**
- * The port states stored here are topology's last knowledge of
- * the state of the port. This mostly mirrors the state
- * maintained in the port list in IOFSwitch (i.e. the one returned
- * from getPort), except that during a port status message the
- * IOFSwitch port state will already have been updated with the
- * new port state, so topology needs to keep its own copy so that
- * it can determine if the port state has changed and therefore
- * requires the new state to be written to storage.
- *
- * Note the port state values are defined in the OF 1.0 spec.
- * These will change in some way once we move to OF 1.3.
+ * The port states stored here are topology's last knowledge of the state of
+ * the port. This mostly mirrors the state maintained in the port list in
+ * IOFSwitch (i.e. the one returned from getPort), except that during a port
+ * status message the IOFSwitch port state will already have been updated
+ * with the new port state, so topology needs to keep its own copy so that
+ * it can determine if the port state has changed and therefore requires the
+ * new state to be written to storage. Note the port state values are
+ * defined in the OF 1.0 spec. These will change in some way once we move to
+ * OF 1.3.
*/
- private final int srcPortState;
- private final int dstPortState;
+ private final Set<OFPortState> srcPortState;
+ private final Set<OFPortState> dstPortState;
private final long firstSeenTime;
private final long lastLldpReceivedTime;
@@ -54,8 +56,8 @@
*/
public LinkInfo(long firstSeenTime,
long lastLldpReceivedTime,
- int srcPortState,
- int dstPortState) {
+ Set<OFPortState> srcPortState,
+ Set<OFPortState> dstPortState) {
this.srcPortState = srcPortState;
this.dstPortState = dstPortState;
this.firstSeenTime = firstSeenTime;
@@ -85,20 +87,47 @@
*
* @return the source port state, as defined in the OF1.0 spec
*/
- public int getSrcPortState() {
+ public Set<OFPortState> getSrcPortState() {
return srcPortState;
}
+ public int getSrcPortStateInteger() {
+ return convertPortState(srcPortState);
+ }
+
/**
* Gets the state of the destination port.
*
* @return the destination port state, as defined in the OF1.0 spec
*/
- public int getDstPortState() {
+ public Set<OFPortState> getDstPortState() {
return dstPortState;
}
/**
+ * Gets the state of the destination port.
+ *
+ * @return the destination port state, as defined in the OF1.0 spec
+ */
+ public int getDstPortStateInteger() {
+ return convertPortState(dstPortState);
+ }
+
+ private int convertPortState(Set<OFPortState> ps) {
+ int ret = 0;
+ if (ps.contains(OFPortState.LINK_DOWN)) {
+ ret = 1 << 0;
+ }
+ if (ps.contains(OFPortState.BLOCKED)) {
+ ret = ret | 1 << 1;
+ }
+ if (ps.contains(OFPortState.LIVE)) {
+ ret = ret | 1 << 2;
+ }
+ return ret;
+ }
+
+ /**
* Gets the link type.
*
* @return the link type
@@ -117,8 +146,8 @@
int result = 1;
result = prime * result + Longs.hashCode(firstSeenTime);
result = prime * result + Longs.hashCode(lastLldpReceivedTime);
- result = prime * result + srcPortState;
- result = prime * result + dstPortState;
+ result = prime * result + convertPortState(srcPortState);
+ result = prime * result + convertPortState(dstPortState);
return result;
}
@@ -138,12 +167,11 @@
LinkInfo other = (LinkInfo) obj;
return firstSeenTime == other.firstSeenTime &&
- lastLldpReceivedTime == other.lastLldpReceivedTime &&
- srcPortState == other.srcPortState &&
- dstPortState == other.dstPortState;
+ lastLldpReceivedTime == other.lastLldpReceivedTime &&
+ srcPortState == other.srcPortState &&
+ dstPortState == other.dstPortState;
}
-
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
diff --git a/src/main/java/net/onrc/onos/core/linkdiscovery/web/LinksResource.java b/src/main/java/net/onrc/onos/core/linkdiscovery/web/LinksResource.java
index 2738041..cb83972 100644
--- a/src/main/java/net/onrc/onos/core/linkdiscovery/web/LinksResource.java
+++ b/src/main/java/net/onrc/onos/core/linkdiscovery/web/LinksResource.java
@@ -28,8 +28,8 @@
Link link = e.getKey();
LinkInfo info = e.getValue();
LinkWithType lwt = new LinkWithType(link,
- info.getSrcPortState(),
- info.getDstPortState(),
+ info.getSrcPortStateInteger(),
+ info.getDstPortStateInteger(),
info.getLinkType());
returnLinkSet.add(lwt);
}
diff --git a/src/main/java/net/onrc/onos/core/main/IOFSwitchPortListener.java b/src/main/java/net/onrc/onos/core/main/IOFSwitchPortListener.java
index edf4539..6f6e21b 100644
--- a/src/main/java/net/onrc/onos/core/main/IOFSwitchPortListener.java
+++ b/src/main/java/net/onrc/onos/core/main/IOFSwitchPortListener.java
@@ -3,9 +3,9 @@
*/
package net.onrc.onos.core.main;
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
import net.floodlightcontroller.core.IOFSwitchListener;
-import org.openflow.protocol.OFPhysicalPort;
/**
* Extra event handler added to IOFSwitchListener by ONOS.
@@ -15,11 +15,11 @@
/**
* Fired when ports on a switch area added.
*/
- public void switchPortAdded(Long switchId, OFPhysicalPort port);
+ public void switchPortAdded(Long switchId, OFPortDesc port);
/**
* Fired when ports on a switch area removed.
*/
- public void switchPortRemoved(Long switchId, OFPhysicalPort port);
+ public void switchPortRemoved(Long switchId, OFPortDesc port);
}
diff --git a/src/main/java/net/onrc/onos/core/main/Main.java b/src/main/java/net/onrc/onos/core/main/Main.java
index 78dad3c..7c7ec03 100644
--- a/src/main/java/net/onrc/onos/core/main/Main.java
+++ b/src/main/java/net/onrc/onos/core/main/Main.java
@@ -12,8 +12,6 @@
/**
* Host for the ONOS main method.
- * <!-- CHECKSTYLE IGNORE WriteTag FOR NEXT 1 LINES -->
- * @author alexreimers
*/
public final class Main {
diff --git a/src/main/java/net/onrc/onos/core/packetservice/PacketModule.java b/src/main/java/net/onrc/onos/core/packetservice/PacketModule.java
index afe2770..63143cd 100644
--- a/src/main/java/net/onrc/onos/core/packetservice/PacketModule.java
+++ b/src/main/java/net/onrc/onos/core/packetservice/PacketModule.java
@@ -30,14 +30,14 @@
import net.onrc.onos.core.util.PortNumber;
import net.onrc.onos.core.util.SwitchPort;
-import org.openflow.protocol.OFMessage;
-import org.openflow.protocol.OFPacketIn;
-import org.openflow.protocol.OFPacketOut;
-import org.openflow.protocol.OFPhysicalPort;
-import org.openflow.protocol.OFPort;
-import org.openflow.protocol.OFType;
-import org.openflow.protocol.action.OFAction;
-import org.openflow.protocol.action.OFActionOutput;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFPacketIn;
+import org.projectfloodlight.openflow.protocol.OFPacketOut;
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
+import org.projectfloodlight.openflow.protocol.OFType;
+import org.projectfloodlight.openflow.protocol.action.OFAction;
+import org.projectfloodlight.openflow.types.OFPort;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -45,7 +45,7 @@
import com.google.common.collect.Multimap;
public class PacketModule implements IOFMessageListener, IPacketService,
- IFloodlightModule {
+ IFloodlightModule {
private static final Logger log = LoggerFactory.getLogger(PacketModule.class);
private final CopyOnWriteArrayList<IPacketListener> listeners;
@@ -54,9 +54,9 @@
private Topology topology;
private IDatagridService datagrid;
private IFlowPusherService flowPusher;
+ private OFFactory factory;
- private IEventChannel<Long, PacketOutNotification>
- packetOutEventChannel;
+ private IEventChannel<Long, PacketOutNotification> packetOutEventChannel;
private static final String PACKET_OUT_CHANNEL_NAME =
"onos.packet_out";
@@ -71,8 +71,9 @@
public void entryAdded(PacketOutNotification value) {
Multimap<Long, Short> localPorts = HashMultimap.create();
for (IOFSwitch sw : floodlightProvider.getSwitches().values()) {
- for (OFPhysicalPort port : sw.getEnabledPorts()) {
- localPorts.put(sw.getId(), port.getPortNumber());
+ for (OFPortDesc port : sw.getEnabledPorts()) {
+ // XXX S fix this to int
+ localPorts.put(sw.getId(), port.getPortNo().getShortPortNumber());
}
}
Multimap<Long, Short> outPorts = value.calculateOutPorts(
@@ -104,7 +105,7 @@
public void sendPacket(Ethernet eth, SwitchPort switchPort) {
SinglePacketOutNotification notification =
new SinglePacketOutNotification(eth.serialize(), 0,
- switchPort.dpid().value(), switchPort.port().shortValue());
+ switchPort.dpid().value(), switchPort.port().shortValue());
// TODO We shouldn't care what the destination MAC is
long dstMac = eth.getDestinationMAC().toLong();
@@ -127,7 +128,7 @@
public void broadcastPacketOutEdge(Ethernet eth, SwitchPort inSwitchPort) {
BroadcastPacketOutNotification notification =
new BroadcastPacketOutNotification(eth.serialize(), 0,
- inSwitchPort.dpid().value(), inSwitchPort.port().shortValue());
+ inSwitchPort.dpid().value(), inSwitchPort.port().shortValue());
long dstMac = eth.getDestinationMAC().toLong();
packetOutEventChannel.addTransientEntry(dstMac, notification);
@@ -140,7 +141,6 @@
@Override
public boolean isCallbackOrderingPrereq(OFType type, String name) {
- // TODO Auto-generated method stub
return false;
}
@@ -156,18 +156,19 @@
return Command.CONTINUE;
}
- OFPacketIn pi = (OFPacketIn) msg;
-
Ethernet eth = IFloodlightProviderService.bcStore.
get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
+ short inport = (short) cntx.getStorage()
+ .get(IFloodlightProviderService.CONTEXT_PI_INPORT);
Switch topologySwitch;
Port inPort;
- final Dpid dpid = new Dpid(sw.getId());
- topology.acquireReadLock();
try {
+ topology.acquireReadLock();
+ Dpid dpid = new Dpid(sw.getId());
+ PortNumber p = new PortNumber(inport);
topologySwitch = topology.getSwitch(dpid);
- inPort = topology.getPort(dpid, new PortNumber(pi.getInPort()));
+ inPort = topology.getPort(dpid, p);
} finally {
topology.releaseReadLock();
}
@@ -194,9 +195,9 @@
@Override
public Map<Class<? extends IFloodlightService>, IFloodlightService>
- getServiceImpls() {
- Map<Class<? extends IFloodlightService>, IFloodlightService>
- serviceImpls = new HashMap<>();
+ getServiceImpls() {
+
+ Map<Class<? extends IFloodlightService>, IFloodlightService> serviceImpls = new HashMap<>();
serviceImpls.put(IPacketService.class, this);
return serviceImpls;
}
@@ -220,12 +221,12 @@
.getTopology();
datagrid = context.getServiceImpl(IDatagridService.class);
flowPusher = context.getServiceImpl(IFlowPusherService.class);
+ factory = floodlightProvider.getOFMessageFactory_10();
}
@Override
public void startUp(FloodlightModuleContext context) {
floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
-
packetOutEventChannel = datagrid.addListener(PACKET_OUT_CHANNEL_NAME,
packetOutEventHandler,
Long.class,
@@ -235,31 +236,25 @@
private void sendPacketToSwitches(Multimap<Long, Short> outPorts,
byte[] packetData) {
for (Long dpid : outPorts.keySet()) {
- OFPacketOut po = new OFPacketOut();
- po.setInPort(OFPort.OFPP_NONE)
- .setBufferId(OFPacketOut.BUFFER_ID_NONE)
- .setPacketData(packetData);
-
- List<OFAction> actions = new ArrayList<OFAction>();
- for (Short port : outPorts.get(dpid)) {
- actions.add(new OFActionOutput(port));
- }
-
- po.setActions(actions);
- short actionsLength = (short)
- (actions.size() * OFActionOutput.MINIMUM_LENGTH);
- po.setActionsLength(actionsLength);
- po.setLengthU(OFPacketOut.MINIMUM_LENGTH + actionsLength
- + packetData.length);
-
IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
if (sw == null) {
- log.warn("Switch not found when sending packet");
- return;
+ log.warn("Switch {} not found when sending packet", dpid);
+ continue;
}
+ List<OFAction> actions = new ArrayList<>();
+ for (Short port : outPorts.get(dpid)) {
+ actions.add(factory.actions().output(OFPort.of(port), Short.MAX_VALUE));
+ }
+
+ OFPacketOut po = factory.buildPacketOut()
+ .setData(packetData)
+ .setActions(actions)
+ .build();
+
flowPusher.add(sw, po);
}
}
+
}
diff --git a/src/main/java/net/onrc/onos/core/registry/IControllerRegistryService.java b/src/main/java/net/onrc/onos/core/registry/IControllerRegistryService.java
index cfc47c8..ef441db 100644
--- a/src/main/java/net/onrc/onos/core/registry/IControllerRegistryService.java
+++ b/src/main/java/net/onrc/onos/core/registry/IControllerRegistryService.java
@@ -8,18 +8,18 @@
import net.onrc.onos.core.util.OnosInstanceId;
/**
- * A registry service that allows ONOS to register controllers and switches
- * in a way that is global to the entire ONOS cluster. The registry is the
- * arbiter for allowing controllers to control switches.
+ * A registry service that allows ONOS to register controllers and switches in a
+ * way that is global to the entire ONOS cluster. The registry is the arbiter
+ * for allowing controllers to control switches.
* <p/>
* The OVS/OF1.{2,3} fault tolerance model is a switch connects to multiple
- * controllers, and the controllers send role requests to determine what their
- * role is in controlling the switch.
+ * controllers, and the controllers send role requests to tell the switch their
+ * role in controlling the switch.
* <p/>
* The ONOS fault tolerance model allows only a single controller to have
* control of a switch (MASTER role) at once. Controllers therefore need a
- * mechanism that enables them to decide who should control a each switch.
- * The registry service provides this mechanism.
+ * mechanism that enables them to decide who should control a each switch. The
+ * registry service provides this mechanism.
*/
public interface IControllerRegistryService extends IFloodlightService {
@@ -29,43 +29,41 @@
public interface ControlChangeCallback {
/**
* Called whenever the control changes from the point of view of the
- * registry. The callee can check whether they have control or not
- * using the hasControl parameter.
+ * registry. The callee can check whether they have control or not using
+ * the hasControl parameter.
*
- * @param dpid The switch that control has changed for
+ * @param dpid The switch that control has changed for
* @param hasControl Whether the listener now has control or not
*/
void controlChanged(long dpid, boolean hasControl);
}
/**
- * Request for control of a switch. This method does not block. When
- * control for a switch changes, the controlChanged method on the
- * callback object will be called. This happens any time the control
- * changes while the request is still active (until releaseControl is
- * called)
+ * Request for control of a switch. This method does not block. When control
+ * for a switch changes, the controlChanged method on the callback object
+ * will be called. This happens any time the control changes while the
+ * request is still active (until releaseControl is called)
*
* @param dpid Switch to request control for
- * @param cb Callback that will be used to notify caller of control
- * changes
+ * @param cb Callback that will be used to notify caller of control changes
* @throws RegistryException Errors contacting the registry service
*/
public void requestControl(long dpid, ControlChangeCallback cb)
throws RegistryException;
/**
- * Stop trying to take control of a switch. This removes the entry
- * for this controller requesting this switch in the registry.
- * If the controller had control when this is called, another controller
- * will now gain control of the switch. This call doesn't block.
+ * Stop trying to take control of a switch. This removes the entry for this
+ * controller requesting this switch in the registry. If the controller had
+ * control when this is called, another controller will now gain control of
+ * the switch. This call doesn't block.
*
* @param dpid Switch to release control of
*/
public void releaseControl(long dpid);
/**
- * Check whether the controller has control of the switch
- * This call doesn't block.
+ * Check whether the controller has control of the switch This call doesn't
+ * block.
*
* @param dpid Switch to check control of
* @return true if controller has control of the switch.
@@ -73,11 +71,11 @@
public boolean hasControl(long dpid);
/**
- * Check whether this instance is the leader for the cluster.
- * This call doesn't block.
+ * Check whether this instance is the leader for the cluster. This call
+ * doesn't block.
*
- * @return true if the instance is the leader for the cluster,
- * otherwise false.
+ * @return true if the instance is the leader for the cluster, otherwise
+ * false.
*/
public boolean isClusterLeader();
@@ -89,13 +87,13 @@
public OnosInstanceId getOnosInstanceId();
/**
- * Register a controller to the ONOS cluster. Must be called before
- * the registry can be used to take control of any switches.
+ * Register a controller to the ONOS cluster. Must be called before the
+ * registry can be used to take control of any switches.
*
- * @param controllerId A unique string ID identifying this controller
- * in the cluster
+ * @param controllerId A unique string ID identifying this controller in the
+ * cluster
* @throws RegistryException for errors connecting to registry service,
- * controllerId already registered
+ * controllerId already registered
*/
public void registerController(String controllerId)
throws RegistryException;
@@ -109,9 +107,9 @@
public Collection<String> getAllControllers() throws RegistryException;
/**
- * Get all switches in the cluster, along with which controller is
- * in control of them (if any) and any other controllers that have
- * requested control.
+ * Get all switches in the cluster, along with which controller is in
+ * control of them (if any) and any other controllers that have requested
+ * control.
*
* @return Map of all switches.
*/
@@ -149,7 +147,6 @@
*/
public IdBlock allocateUniqueIdBlock(long range);
-
/**
* Get a globally unique ID.
*
diff --git a/src/main/java/net/onrc/onos/core/topology/TopologyPublisher.java b/src/main/java/net/onrc/onos/core/topology/TopologyPublisher.java
index ed450f2..8b77745 100644
--- a/src/main/java/net/onrc/onos/core/topology/TopologyPublisher.java
+++ b/src/main/java/net/onrc/onos/core/topology/TopologyPublisher.java
@@ -9,20 +9,20 @@
import net.floodlightcontroller.core.IFloodlightProviderService;
import net.floodlightcontroller.core.IFloodlightProviderService.Role;
import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.IOFSwitch.PortChangeType;
+import net.floodlightcontroller.core.IOFSwitchListener;
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.core.util.SingletonTask;
import net.floodlightcontroller.threadpool.IThreadPoolService;
-import net.onrc.onos.api.registry.ILocalSwitchMastershipListener;
import net.onrc.onos.core.hostmanager.Host;
import net.onrc.onos.core.hostmanager.IHostListener;
import net.onrc.onos.core.hostmanager.IHostService;
import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryListener;
import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryService;
import net.onrc.onos.core.linkdiscovery.Link;
-import net.onrc.onos.core.main.IOFSwitchPortListener;
import net.onrc.onos.core.registry.IControllerRegistryService;
import net.onrc.onos.core.registry.IControllerRegistryService.ControlChangeCallback;
import net.onrc.onos.core.registry.RegistryException;
@@ -30,8 +30,8 @@
import net.onrc.onos.core.util.PortNumber;
import net.onrc.onos.core.util.SwitchPort;
-import org.openflow.protocol.OFPhysicalPort;
-import org.openflow.util.HexString;
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
+import org.projectfloodlight.openflow.util.HexString;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -40,12 +40,10 @@
* discovery modules. These events are reformatted and relayed to the in-memory
* topology instance.
*/
-public class TopologyPublisher implements /*IOFSwitchListener,*/
- IOFSwitchPortListener,
+public class TopologyPublisher implements IOFSwitchListener,
ILinkDiscoveryListener,
IFloodlightModule,
- IHostListener,
- ILocalSwitchMastershipListener {
+ IHostListener {
private static final Logger log =
LoggerFactory.getLogger(TopologyPublisher.class);
@@ -65,8 +63,8 @@
private SingletonTask cleanupTask;
/**
- * Cleanup old switches from the topology. Old switches are those
- * which have no controller in the registry.
+ * Cleanup old switches from the topology. Old switches are those which have
+ * no controller in the registry.
*/
private class SwitchCleanup implements ControlChangeCallback, Runnable {
@Override
@@ -97,7 +95,8 @@
if (log.isTraceEnabled()) {
log.trace("Checking for inactive switches");
}
- // For each switch check if a controller exists in controller registry
+ // For each switch check if a controller exists in controller
+ // registry
for (Switch sw : switches) {
// FIXME How to handle case where Switch has never been
// registered to ZK
@@ -120,10 +119,10 @@
/**
* Second half of the switch cleanup operation. If the registry grants
- * control of a switch, we can be sure no other instance is writing
- * this switch to the topology, so we can remove it now.
- *
- * @param dpid the dpid of the switch we requested control for
+ * control of a switch, we can be sure no other instance is writing this
+ * switch to the topology, so we can remove it now.
+ * <p>
+ * @param dpid the dpid of the switch we requested control for
* @param hasControl whether we got control or not
*/
@Override
@@ -150,7 +149,7 @@
// TODO define attr name as constant somewhere.
// TODO populate appropriate attributes.
linkEvent.createStringAttribute(TopologyElement.TYPE,
- TopologyElement.TYPE_PACKET_LAYER);
+ TopologyElement.TYPE_PACKET_LAYER);
linkEvent.createStringAttribute(TopologyElement.ELEMENT_CONFIG_STATE,
ConfigState.NOT_CONFIGURED.toString());
linkEvent.createStringAttribute(TopologyElement.ELEMENT_ADMIN_STATUS,
@@ -177,51 +176,173 @@
// TODO define attr name as constant somewhere.
// TODO populate appropriate attributes.
linkEvent.createStringAttribute(TopologyElement.TYPE,
- TopologyElement.TYPE_PACKET_LAYER);
+ TopologyElement.TYPE_PACKET_LAYER);
linkEvent.freeze();
if (!registryService.hasControl(link.getDst())) {
// Don't process or send a link event if we're not master for the
// destination switch
- log.debug("Not the master for dst switch {}. Suppressed link remove event {}.",
+ log.debug(
+ "Not the master for dst switch {}. Suppressed link remove event {}.",
link.getDst(), linkEvent);
return;
}
topologyDiscoveryInterface.removeLinkDiscoveryEvent(linkEvent);
}
+ /* *****************
+ * IOFSwitchListener
+ * *****************/
+
@Override
- public void switchPortAdded(Long switchId, OFPhysicalPort port) {
+ public void switchActivatedMaster(long swId) {
+ IOFSwitch sw = floodlightProvider.getSwitch(swId);
+ final Dpid dpid = new Dpid(swId);
+ if (sw == null) {
+ log.warn("Added switch not available {} ", dpid);
+ return;
+ }
+
+ controllerRoleChanged(dpid, Role.MASTER);
+
+ SwitchEvent switchEvent = new SwitchEvent(dpid);
+ // FIXME should be merging, with existing attrs, etc..
+ // TODO define attr name as constant somewhere.
+ // TODO populate appropriate attributes.
+ switchEvent.createStringAttribute(TopologyElement.TYPE,
+ TopologyElement.TYPE_PACKET_LAYER);
+ switchEvent.createStringAttribute("ConnectedSince",
+ sw.getConnectedSince().toString());
+ switchEvent.createStringAttribute(TopologyElement.ELEMENT_CONFIG_STATE,
+ ConfigState.NOT_CONFIGURED.toString());
+ switchEvent.createStringAttribute(TopologyElement.ELEMENT_ADMIN_STATUS,
+ AdminStatus.ACTIVE.toString());
+ switchEvent.freeze();
+ // TODO Not very robust
+ if (!registryService.hasControl(swId)) {
+ log.debug("Not the master for switch {}. Suppressed switch add event {}.",
+ dpid, switchEvent);
+ return;
+ }
+ List<PortEvent> portEvents = new ArrayList<PortEvent>();
+ for (OFPortDesc port : sw.getPorts()) {
+ PortEvent portEvent = new PortEvent(dpid,
+ new PortNumber(port.getPortNo().getShortPortNumber()));
+ // FIXME should be merging, with existing attrs, etc..
+ // TODO define attr name as constant somewhere.
+ // TODO populate appropriate attributes.
+ portEvent.createStringAttribute("name", port.getName());
+ portEvent.createStringAttribute(TopologyElement.TYPE,
+ TopologyElement.TYPE_PACKET_LAYER);
+ portEvent.createStringAttribute(TopologyElement.ELEMENT_CONFIG_STATE,
+ ConfigState.NOT_CONFIGURED.toString());
+ portEvent.createStringAttribute(TopologyElement.ELEMENT_ADMIN_STATUS,
+ AdminStatus.ACTIVE.toString());
+
+ portEvent.freeze();
+ portEvents.add(portEvent);
+ }
+ topologyDiscoveryInterface.putSwitchDiscoveryEvent(switchEvent, portEvents);
+
+ for (OFPortDesc port : sw.getPorts()) {
+ // Allow links to be discovered on this port now that it's
+ // in the database
+ linkDiscovery.enableDiscoveryOnPort(sw.getId(),
+ port.getPortNo().getShortPortNumber());
+ }
+ }
+
+ @Override
+ public void switchActivatedEqual(long swId) {
+ final Dpid dpid = new Dpid(swId);
+ controllerRoleChanged(dpid, Role.EQUAL);
+ }
+
+ @Override
+ public void switchMasterToEqual(long swId) {
+ final Dpid dpid = new Dpid(swId);
+ controllerRoleChanged(dpid, Role.EQUAL);
+ }
+
+ @Override
+ public void switchEqualToMaster(long swId) {
+ // for now treat as switchActivatedMaster
+ switchActivatedMaster(swId);
+ }
+
+ @Override
+ public void switchDisconnected(long swId) {
+ final Dpid dpid = new Dpid(swId);
+
+ log.debug("Local switch disconnected: dpid = {} role = {}", dpid);
+
+ Role role = Role.SLAVE; // TODO: Should be Role.UNKNOWN
+
+ MastershipEvent mastershipEvent =
+ new MastershipEvent(dpid, registryService.getOnosInstanceId(),
+ role);
+ // FIXME should be merging, with existing attrs, etc..
+ // TODO define attr name as constant somewhere.
+ // TODO populate appropriate attributes.
+ mastershipEvent.createStringAttribute(TopologyElement.TYPE,
+ TopologyElement.TYPE_ALL_LAYERS);
+ mastershipEvent.freeze();
+ topologyDiscoveryInterface.removeSwitchMastershipEvent(mastershipEvent);
+ }
+
+ @Override
+ public void switchPortChanged(long swId, OFPortDesc port,
+ PortChangeType changeType) {
+ switch (changeType) {
+ case ADD:
+ switchPortAdded(swId, port);
+ break;
+ case DELETE:
+ switchPortRemoved(swId, port);
+ break;
+ case DOWN:
+ case UP:
+ case OTHER_UPDATE:
+ default:
+ // XXX S what is the right set of port change handlers?
+ log.debug("Topology publisher does not handle these port updates: {}",
+ changeType);
+ }
+ }
+
+ private void switchPortAdded(long switchId, OFPortDesc port) {
final Dpid dpid = new Dpid(switchId);
- PortEvent portEvent = new PortEvent(dpid, new PortNumber(port.getPortNumber()));
+ PortEvent portEvent = new PortEvent(dpid,
+ new PortNumber(port.getPortNo().getShortPortNumber()));
// FIXME should be merging, with existing attrs, etc..
// TODO define attr name as constant somewhere.
// TODO populate appropriate attributes.
portEvent.createStringAttribute(TopologyElement.TYPE,
- TopologyElement.TYPE_PACKET_LAYER);
+ TopologyElement.TYPE_PACKET_LAYER);
portEvent.createStringAttribute("name", port.getName());
portEvent.freeze();
if (registryService.hasControl(switchId)) {
topologyDiscoveryInterface.putPortDiscoveryEvent(portEvent);
- linkDiscovery.enableDiscoveryOnPort(switchId, port.getPortNumber());
+ linkDiscovery.enableDiscoveryOnPort(switchId,
+ port.getPortNo().getShortPortNumber());
} else {
log.debug("Not the master for switch {}. Suppressed port add event {}.",
new Dpid(switchId), portEvent);
}
}
- @Override
- public void switchPortRemoved(Long switchId, OFPhysicalPort port) {
+ private void switchPortRemoved(long switchId, OFPortDesc port) {
final Dpid dpid = new Dpid(switchId);
- PortEvent portEvent = new PortEvent(dpid, new PortNumber(port.getPortNumber()));
+ PortEvent portEvent = new PortEvent(dpid, new PortNumber(
+ port.getPortNo().getShortPortNumber()));
// FIXME should be merging, with existing attrs, etc..
// TODO define attr name as constant somewhere.
// TODO populate appropriate attributes.
portEvent.createStringAttribute(TopologyElement.TYPE,
- TopologyElement.TYPE_PACKET_LAYER);
+ TopologyElement.TYPE_PACKET_LAYER);
portEvent.createStringAttribute("name", port.getName());
portEvent.freeze();
@@ -235,70 +356,8 @@
}
@Override
- public void addedSwitch(IOFSwitch sw) {
- final Dpid dpid = new Dpid(sw.getId());
- SwitchEvent switchEvent = new SwitchEvent(dpid);
- // FIXME should be merging, with existing attrs, etc..
- // TODO define attr name as constant somewhere.
- // TODO populate appropriate attributes.
- switchEvent.createStringAttribute(TopologyElement.TYPE,
- TopologyElement.TYPE_PACKET_LAYER);
- switchEvent.createStringAttribute("ConnectedSince",
- sw.getConnectedSince().toString());
- switchEvent.createStringAttribute(TopologyElement.ELEMENT_CONFIG_STATE,
- ConfigState.NOT_CONFIGURED.toString());
- switchEvent.createStringAttribute(TopologyElement.ELEMENT_ADMIN_STATUS,
- AdminStatus.ACTIVE.toString());
- switchEvent.freeze();
-
- // TODO Not very robust
- if (!registryService.hasControl(sw.getId())) {
- log.debug("Not the master for switch {}. Suppressed switch add event {}.",
- dpid, switchEvent);
- return;
- }
-
- List<PortEvent> portEvents = new ArrayList<PortEvent>();
- for (OFPhysicalPort port : sw.getPorts()) {
- PortEvent portEvent = new PortEvent(dpid, new PortNumber(port.getPortNumber()));
- // FIXME should be merging, with existing attrs, etc..
- // TODO define attr name as constant somewhere.
- // TODO populate appropriate attributes.
- portEvent.createStringAttribute("name", port.getName());
- portEvent.createStringAttribute(TopologyElement.TYPE,
- TopologyElement.TYPE_PACKET_LAYER);
- portEvent.createStringAttribute(TopologyElement.ELEMENT_CONFIG_STATE,
- ConfigState.NOT_CONFIGURED.toString());
- portEvent.createStringAttribute(TopologyElement.ELEMENT_ADMIN_STATUS,
- AdminStatus.ACTIVE.toString());
-
- portEvent.freeze();
- portEvents.add(portEvent);
- }
- topologyDiscoveryInterface
- .putSwitchDiscoveryEvent(switchEvent, portEvents);
-
- for (OFPhysicalPort port : sw.getPorts()) {
- // Allow links to be discovered on this port now that it's
- // in the database
- linkDiscovery.enableDiscoveryOnPort(sw.getId(), port.getPortNumber());
- }
- }
-
- @Override
- public void removedSwitch(IOFSwitch sw) {
- // We don't use this event - switch remove is done by cleanup thread
- }
-
- @Override
- public void switchPortChanged(Long switchId) {
- // We don't use this event
- }
-
- @Override
public String getName() {
- // TODO Auto-generated method stub
- return null;
+ return "topologyPublisher";
}
/* *****************
@@ -312,13 +371,13 @@
@Override
public Map<Class<? extends IFloodlightService>, IFloodlightService>
- getServiceImpls() {
+ getServiceImpls() {
return null;
}
@Override
public Collection<Class<? extends IFloodlightService>>
- getModuleDependencies() {
+ getModuleDependencies() {
Collection<Class<? extends IFloodlightService>> l =
new ArrayList<Class<? extends IFloodlightService>>();
l.add(IFloodlightProviderService.class);
@@ -339,8 +398,6 @@
hostService = context.getServiceImpl(IHostService.class);
topologyService = context.getServiceImpl(ITopologyService.class);
-
- floodlightProvider.addLocalSwitchMastershipListener(this);
}
@Override
@@ -393,41 +450,23 @@
public void hostRemoved(Host host) {
log.debug("Called onosDeviceRemoved");
HostEvent event = new HostEvent(host.getMacAddress());
- //XXX shouldn't we be setting attachment points?
+ // XXX shouldn't we be setting attachment points?
event.freeze();
topologyDiscoveryInterface.removeHostDiscoveryEvent(event);
}
- @Override
- public void controllerRoleChanged(Dpid dpid, Role role) {
- log.debug("Local switch controller mastership role changed: dpid = {} role = {}", dpid, role);
+ private void controllerRoleChanged(Dpid dpid, Role role) {
+ log.debug("Local switch controller mastership role changed: dpid = {} role = {}",
+ dpid, role);
MastershipEvent mastershipEvent =
- new MastershipEvent(dpid, registryService.getOnosInstanceId(),
- role);
+ new MastershipEvent(dpid, registryService.getOnosInstanceId(),
+ role);
// FIXME should be merging, with existing attrs, etc..
// TODO define attr name as constant somewhere.
// TODO populate appropriate attributes.
mastershipEvent.createStringAttribute(TopologyElement.TYPE,
- TopologyElement.TYPE_ALL_LAYERS);
+ TopologyElement.TYPE_ALL_LAYERS);
mastershipEvent.freeze();
topologyDiscoveryInterface.putSwitchMastershipEvent(mastershipEvent);
}
-
- @Override
- public void switchDisconnected(Dpid dpid) {
- log.debug("Local switch disconnected: dpid = {} role = {}", dpid);
-
- Role role = Role.SLAVE; // TODO: Should be Role.UNKNOWN
-
- MastershipEvent mastershipEvent =
- new MastershipEvent(dpid, registryService.getOnosInstanceId(),
- role);
- // FIXME should be merging, with existing attrs, etc..
- // TODO define attr name as constant somewhere.
- // TODO populate appropriate attributes.
- mastershipEvent.createStringAttribute(TopologyElement.TYPE,
- TopologyElement.TYPE_ALL_LAYERS);
- mastershipEvent.freeze();
- topologyDiscoveryInterface.removeSwitchMastershipEvent(mastershipEvent);
- }
}