Added codes to send ICMP response with either OFPP_TABLE action or MPLS label according to a flag
Change-Id: If4db8e4ea26395d123c939393308ff96909a4110
diff --git a/src/main/java/net/onrc/onos/apps/segmentrouting/ArpHandler.java b/src/main/java/net/onrc/onos/apps/segmentrouting/ArpHandler.java
index 9f0fa86..fc6c02e 100644
--- a/src/main/java/net/onrc/onos/apps/segmentrouting/ArpHandler.java
+++ b/src/main/java/net/onrc/onos/apps/segmentrouting/ArpHandler.java
@@ -8,10 +8,6 @@
package net.onrc.onos.apps.segmentrouting;
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-
import net.floodlightcontroller.core.IFloodlightProviderService;
import net.floodlightcontroller.core.module.FloodlightModuleContext;
import net.floodlightcontroller.util.MACAddress;
@@ -149,54 +145,7 @@
}
}
- /**
- * The function checks if given IP matches to the given subnet mask
- *
- * @param addr - subnet address to match
- * @param addr1 - IP address to check
- * @return true if the IP address matches to the subnet, otherwise false
- */
- public static boolean netMatch(String addr, String addr1){ //addr is subnet address and addr1 is ip address. Function will return true, if addr1 is within addr(subnet)
-
- String[] parts = addr.split("/");
- String ip = parts[0];
- int prefix;
-
- if (parts.length < 2) {
- prefix = 0;
- } else {
- prefix = Integer.parseInt(parts[1]);
- }
-
- Inet4Address a =null;
- Inet4Address a1 =null;
- try {
- a = (Inet4Address) InetAddress.getByName(ip);
- a1 = (Inet4Address) InetAddress.getByName(addr1);
- } catch (UnknownHostException e){}
-
- byte[] b = a.getAddress();
- int ipInt = ((b[0] & 0xFF) << 24) |
- ((b[1] & 0xFF) << 16) |
- ((b[2] & 0xFF) << 8) |
- ((b[3] & 0xFF) << 0);
-
- byte[] b1 = a1.getAddress();
- int ipInt1 = ((b1[0] & 0xFF) << 24) |
- ((b1[1] & 0xFF) << 16) |
- ((b1[2] & 0xFF) << 8) |
- ((b1[3] & 0xFF) << 0);
-
- int mask = ~((1 << (32 - prefix)) - 1);
-
- if ((ipInt & mask) == (ipInt1 & mask)) {
- return true;
- }
- else {
- return false;
- }
-}
diff --git a/src/main/java/net/onrc/onos/apps/segmentrouting/IcmpHandler.java b/src/main/java/net/onrc/onos/apps/segmentrouting/IcmpHandler.java
index 676e68a..8e58eac 100644
--- a/src/main/java/net/onrc/onos/apps/segmentrouting/IcmpHandler.java
+++ b/src/main/java/net/onrc/onos/apps/segmentrouting/IcmpHandler.java
@@ -19,6 +19,8 @@
import net.onrc.onos.core.topology.Switch;
import net.onrc.onos.core.util.SwitchPort;
+import org.json.JSONArray;
+import org.json.JSONException;
import org.projectfloodlight.openflow.protocol.OFFactory;
import org.projectfloodlight.openflow.protocol.OFMatchV3;
import org.projectfloodlight.openflow.protocol.OFMessage;
@@ -29,6 +31,7 @@
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.OFOxmMplsLabel;
import org.projectfloodlight.openflow.protocol.oxm.OFOxmVlanVid;
@@ -54,7 +57,7 @@
.getLogger(IcmpHandler.class);
private IFlowPusherService flowPusher;
- private boolean added;
+ private boolean controllerPortAllowed = false;
private static final int TABLE_VLAN = 0;
private static final int TABLE_TMAC = 1;
@@ -69,6 +72,9 @@
private static final short SLASH_8_PRIORITY = (short) 0xf000;
private static final short MIN_PRIORITY = 0x0;
+ private static final int ICMP_TYPE_ECHO = 0x08;
+ private static final int ICMP_TYPE_REPLY = 0x00;
+
public IcmpHandler(FloodlightModuleContext context, SegmentRoutingManager manager) {
@@ -79,7 +85,6 @@
this.mutableTopology = topologyService.getTopology();
this.srManager = manager;
- this.added = false;
packetService.registerPacketListener(this);
@@ -101,9 +106,8 @@
String switchIpAddressStr = switchIpAddressSlash.substring(0, switchIpAddressSlash.indexOf('/'));
IPv4Address switchIpAddress = IPv4Address.of(switchIpAddressStr);
- if (((ICMP)ipv4.getPayload()).getIcmpType() == 0x08 &&
+ if (((ICMP)ipv4.getPayload()).getIcmpType() == ICMP_TYPE_ECHO &&
destinationAddress == switchIpAddress.getInt()) {
- //addControlPortInVlanTable(sw);
sendICMPResponse(sw, inPort, payload);
return;
}
@@ -150,7 +154,7 @@
ICMP icmpReply = (ICMP)icmpRequestIpv4.getPayload().clone();
icmpReply.setIcmpCode((byte)0x00);
- icmpReply.setIcmpType((byte) 0x00);
+ icmpReply.setIcmpType((byte) ICMP_TYPE_REPLY);
icmpReply.setChecksum((short)0);
icmpReplyIpv4.setPayload(icmpReply);
@@ -160,22 +164,23 @@
icmpReplyEth.setDestinationMACAddress(icmpRequest.getSourceMACAddress());
icmpReplyEth.setSourceMACAddress(icmpRequest.getDestinationMACAddress());
- sendPacketOut(sw, icmpReplyEth, new SwitchPort(sw.getDpid(), inPort.getPortNumber()));
+ sendPacketOut(sw, icmpReplyEth, new SwitchPort(sw.getDpid(), inPort.getPortNumber()), false);
log.debug("Send an ICMP response {}", icmpReplyIpv4.toString());
}
-
-
/**
- * Send PACKET_OUT message with some actions
+ * Send PACKET_OUT message with actions
+ * If switches support OFPP_TABLE action, it sends out packet to TABLE port
+ * Otherwise, it sends the packet to the port the packet came from
+ * (in this case, MPLS label is added if the packet needs go through transit switches)
*
* @param sw Switch the packet came from
* @param packet Ethernet packet to send
* @param switchPort port to send the packet
*/
- private void sendPacketOut(Switch sw, Ethernet packet, SwitchPort switchPort) {
+ private void sendPacketOut(Switch sw, Ethernet packet, SwitchPort switchPort, boolean supportOfppTable) {
boolean sameSubnet = false;
IOFSwitch ofSwitch = floodlightProvider.getMasterSwitch(sw.getDpid().value());
@@ -183,31 +188,50 @@
List<OFAction> actions = new ArrayList<>();
- // Check if the destination is the host attached to the switch
- int destinationAddress = ((IPv4)packet.getPayload()).getDestinationAddress();
- for (net.onrc.onos.core.topology.Host host: mutableTopology.getHosts(switchPort)) {
- IPv4Address hostIpAddress = IPv4Address.of(host.getIpAddress());
- if (hostIpAddress != null && hostIpAddress.getInt() == destinationAddress) {
- sameSubnet = true;
- break;
+ // If OFPP_TABLE action is not supported in the switch, MPLS label needs to be set
+ // if the packet needs to be delivered crossing switches
+ if (!supportOfppTable) {
+ // Check if the destination is the host attached to the switch
+ int destinationAddress = ((IPv4)packet.getPayload()).getDestinationAddress();
+ for (net.onrc.onos.core.topology.Host host: mutableTopology.getHosts(switchPort)) {
+ IPv4Address hostIpAddress = IPv4Address.of(host.getIpAddress());
+ if (hostIpAddress != null && hostIpAddress.getInt() == destinationAddress) {
+ sameSubnet = true;
+ break;
+ }
}
- }
- // If the destination host is not attached in the switch, add MPLS label
- if (!sameSubnet) {
- OFAction pushlabel = factory.actions().pushMpls(EthType.MPLS_UNICAST);
- OFOxmMplsLabel l = factory.oxms()
- .mplsLabel(U32.of(103));
- OFAction setlabelid = factory.actions().buildSetField()
- .setField(l).build();
- OFAction copyTtlOut = factory.actions().copyTtlOut();
- actions.add(pushlabel);
- actions.add(setlabelid);
- actions.add(copyTtlOut);
- }
+ // If the destination host is not attached in the switch, add MPLS label
+ if (!sameSubnet) {
- OFAction outport = factory.actions().output(OFPort.of((int) switchPort.getPortNumber().value()), Short.MAX_VALUE);
- actions.add(outport);
+ IPv4Address targetAddress = IPv4Address.of(((IPv4)packet.getPayload()).getDestinationAddress());
+ int mplsLabel = getMplsLabelFromConfig(targetAddress);
+ if (mplsLabel > 0) {
+ OFAction pushlabel = factory.actions().pushMpls(EthType.MPLS_UNICAST);
+ OFOxmMplsLabel l = factory.oxms()
+ .mplsLabel(U32.of(mplsLabel));
+ OFAction setlabelid = factory.actions().buildSetField()
+ .setField(l).build();
+ OFAction copyTtlOut = factory.actions().copyTtlOut();
+ actions.add(pushlabel);
+ actions.add(setlabelid);
+ actions.add(copyTtlOut);
+ }
+ }
+
+ OFAction outport = factory.actions().output(OFPort.of(switchPort.getPortNumber().shortValue()), Short.MAX_VALUE);
+ actions.add(outport);
+ }
+ // If OFPP_TABLE action is supported, first set a rule to allow packet from CONTROLLER port.
+ // Then, send the packet to the table port
+ else {
+ if (!controllerPortAllowed) {
+ addControlPortInVlanTable(sw);
+ controllerPortAllowed = true;
+ }
+ OFAction outport = factory.actions().output(OFPort.TABLE, Short.MAX_VALUE);
+ actions.add(outport);
+ }
OFPacketOut po = factory.buildPacketOut()
.setData(packet.serialize())
@@ -218,6 +242,38 @@
}
/**
+ * Get MPLS label for the target address from the network config file
+ *
+ * @param targetAddress - IP address of the target host
+ * @return MPLS label of the switch to send packets to the target address
+ */
+ private int getMplsLabelFromConfig(IPv4Address targetAddress) {
+
+ int mplsLabel = -1;
+
+ for (Switch sw: mutableTopology.getSwitches()) {
+
+ String subnets = sw.getStringAttribute("subnets");
+ try {
+ JSONArray arry = new JSONArray(subnets);
+ for (int i = 0; i < arry.length(); i++) {
+ String subnetIp = (String) arry.getJSONObject(i).get("subnetIp");
+ if (srManager.netMatch(subnetIp, targetAddress.toString())) {
+ String mplsLabelStr = sw.getStringAttribute("nodeSid");
+ if (mplsLabelStr != null)
+ mplsLabel = Integer.parseInt(mplsLabelStr);
+ }
+ }
+ } catch (JSONException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ return mplsLabel;
+ }
+
+ /**
* Add routing rules to forward packets to known hosts
*
* @param sw Switch
@@ -319,19 +375,16 @@
*/
private void addControlPortInVlanTable(Switch sw) {
- if (added)
- return;
- else
- added = true;
-
IOFSwitch ofSwitch = floodlightProvider.getMasterSwitch(sw.getDpid().value());
OFFactory factory = ofSwitch.getFactory();
- //OFOxmInPort oxp = factory.oxms().inPort(p.getPortNo());
+ OFOxmInPort oxp = factory.oxms().inPort(OFPort.CONTROLLER);
OFOxmVlanVid oxv = factory.oxms()
.vlanVid(OFVlanVidMatch.UNTAGGED);
OFOxmList oxmList = OFOxmList.of(oxv);
+ /* Cqpd switch does not seems to support CONTROLLER port as in_port match rule */
+ //OFOxmList oxmList = OFOxmList.of(oxp, oxv);
OFMatchV3 match = factory.buildMatchV3()
.setOxmList(oxmList)
@@ -340,7 +393,6 @@
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))
@@ -355,7 +407,7 @@
.build();
flowPusher.add(sw.getDpid(), flowEntry);;
- //log.debug("Adding {} vlan-rules in sw {}", msglist.size(), getStringId());
+ log.debug("Adding a new vlan-rules in sw {}", sw.getDpid());
}
diff --git a/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingManager.java b/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingManager.java
index 257d143..d710b10 100644
--- a/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingManager.java
+++ b/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingManager.java
@@ -1,5 +1,8 @@
package net.onrc.onos.apps.segmentrouting;
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
@@ -12,16 +15,16 @@
import net.floodlightcontroller.core.module.IFloodlightModule;
import net.floodlightcontroller.core.module.IFloodlightService;
import net.onrc.onos.api.packet.IPacketService;
-import net.onrc.onos.core.datastore.serializers.Topology;
import net.onrc.onos.core.flowprogrammer.IFlowPusherService;
+import net.onrc.onos.core.intent.Path;
import net.onrc.onos.core.main.config.IConfigInfoService;
import net.onrc.onos.core.packet.ARP;
-import net.onrc.onos.core.topology.ITopologyService;
import net.onrc.onos.core.topology.ITopologyListener;
+import net.onrc.onos.core.topology.ITopologyService;
+import net.onrc.onos.core.topology.LinkData;
import net.onrc.onos.core.topology.MutableTopology;
-import net.onrc.onos.core.topology.TopologyEvents;
import net.onrc.onos.core.topology.Switch;
-import net.onrc.onos.core.intent.Path;
+import net.onrc.onos.core.topology.TopologyEvents;
import org.projectfloodlight.openflow.types.IPv4Address;
import org.projectfloodlight.openflow.util.HexString;
@@ -170,8 +173,77 @@
log.debug("ECMPShortestPathGraph:Paths from switch {} to switch {} is {}",
HexString.toHexString(sw.getDpid().value()),
HexString.toHexString(dstSw.getDpid().value()), paths);
+ setSegmentRoutingRule(sw, paths);
}
}
}
}
+
+ /**
+ * Set segment routing rule to switches in the ECMP shortest path to the switch
+ *
+ * @param sw source switch
+ * @param paths ECMP path
+ */
+ private void setSegmentRoutingRule(Switch sw, ArrayList<Path> paths) {
+
+ log.debug("Set routing infor for {} to .. ", sw.getDpid());
+ for (Path path: paths) {
+
+ for (Object obj : path.toArray()) {
+ LinkData link = (LinkData)obj;
+ log.debug(" ---- Set a rule in {} [Forward to {}] " , link.getSrc(), link.getDst().getDpid());
+ }
+ }
+
+ }
+
+ /**
+ * The function checks if given IP matches to the given subnet mask
+ *
+ * @param addr - subnet address to match
+ * @param addr1 - IP address to check
+ * @return true if the IP address matches to the subnet, otherwise false
+ */
+
+ public boolean netMatch(String addr, String addr1){ //addr is subnet address and addr1 is ip address. Function will return true, if addr1 is within addr(subnet)
+
+ String[] parts = addr.split("/");
+ String ip = parts[0];
+ int prefix;
+
+ if (parts.length < 2) {
+ prefix = 0;
+ } else {
+ prefix = Integer.parseInt(parts[1]);
+ }
+
+ Inet4Address a =null;
+ Inet4Address a1 =null;
+ try {
+ a = (Inet4Address) InetAddress.getByName(ip);
+ a1 = (Inet4Address) InetAddress.getByName(addr1);
+ } catch (UnknownHostException e){}
+
+ byte[] b = a.getAddress();
+ int ipInt = ((b[0] & 0xFF) << 24) |
+ ((b[1] & 0xFF) << 16) |
+ ((b[2] & 0xFF) << 8) |
+ ((b[3] & 0xFF) << 0);
+
+ byte[] b1 = a1.getAddress();
+ int ipInt1 = ((b1[0] & 0xFF) << 24) |
+ ((b1[1] & 0xFF) << 16) |
+ ((b1[2] & 0xFF) << 8) |
+ ((b1[3] & 0xFF) << 0);
+
+ int mask = ~((1 << (32 - prefix)) - 1);
+
+ if ((ipInt & mask) == (ipInt1 & mask)) {
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
}