diff --git a/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java b/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java index e341d6dc91133edb8845ccbc24751821a4c26dcf..3732d38e379d2ffc05ee35b6e212ceb28e5843c3 100644 --- a/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java +++ b/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java @@ -47,7 +47,7 @@ import net.floodlightcontroller.routing.IRoutingDecision; import net.floodlightcontroller.routing.IRoutingService; import net.floodlightcontroller.routing.Route; import net.floodlightcontroller.topology.ITopologyService; -import net.floodlightcontroller.util.MatchMaskUtils; +import net.floodlightcontroller.util.MatchUtils; import org.projectfloodlight.openflow.protocol.OFFlowMod; import org.projectfloodlight.openflow.protocol.match.Match; @@ -278,11 +278,12 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule { MacAddress srcMac = eth.getSourceMACAddress(); MacAddress dstMac = eth.getDestinationMACAddress(); - Match.Builder mb = m.createBuilder(); // TODO @Ryan based on packet in's match, m; ingress port should be included already, but it's not.... - mb.setExact(MatchField.IN_PORT, m.get(MatchField.IN_PORT)) - .setExact(MatchField.ETH_SRC, srcMac) - .setExact(MatchField.ETH_DST, dstMac); - //.setExact(MatchField.VLAN_VID, OFVlanVidMatch.ofVlanVid(vlan)); + // A retentive builder will remember all MatchFields of the parent the builder was generated from + // With a normal builder, all parent MatchFields will be lost if any MatchFields are added, mod, del + Match.Builder mb = MatchUtils.createRetentiveBuilder(m); + mb.setExact(MatchField.ETH_SRC, srcMac) + .setExact(MatchField.ETH_DST, dstMac) + .setExact(MatchField.VLAN_VID, OFVlanVidMatch.ofVlanVid(vlan)); if (eth.getEtherType() == Ethernet.TYPE_IPv4) { IPv4 ip = (IPv4) eth.getPayload(); @@ -295,11 +296,7 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule { mb.setExact(MatchField.ETH_TYPE, EthType.ARP); } //TODO @Ryan should probably include other ethertypes - // A Match will contain only what you want to match on. - // Absence of a MatchField --> it can be anything (wildcarded). - // Remove all matches except for L2 and L3 addresses & VLAN - // to allow forwarding on a (V)LAN - routeMatch = /*MatchMaskUtils.maskL4AndUp(*/mb.build()/*)*/; + routeMatch = mb.build(); } pushRoute(route, routeMatch, pi, sw.getId(), cookie, diff --git a/src/main/java/net/floodlightcontroller/packet/Ethernet.java b/src/main/java/net/floodlightcontroller/packet/Ethernet.java index e6fa316db6f2c9e286bad31354351ba20eda4211..2b9d0ea3a88fe2933f63ac2a898471022109635b 100644 --- a/src/main/java/net/floodlightcontroller/packet/Ethernet.java +++ b/src/main/java/net/floodlightcontroller/packet/Ethernet.java @@ -23,6 +23,7 @@ import java.util.HashMap; import java.util.Map; import org.projectfloodlight.openflow.types.MacAddress; +import org.projectfloodlight.openflow.types.VlanVid; /** * @@ -35,7 +36,7 @@ public class Ethernet extends BasePacket { public static final short TYPE_IPv4 = 0x0800; public static final short TYPE_LLDP = (short) 0x88cc; public static final short TYPE_BSN = (short) 0x8942; - public static final short VLAN_UNTAGGED = (short)0xffff; + public static final short VLAN_UNTAGGED = VlanVid.ZERO.getVlan(); // untagged vlan must be 0x0000 for loxi. We can use the convenient ZERO field public static final short DATALAYER_ADDRESS_LENGTH = 6; // bytes public static Map<Short, Class<? extends IPacket>> etherTypeClassMap; diff --git a/src/main/java/net/floodlightcontroller/util/MatchMaskUtils.java b/src/main/java/net/floodlightcontroller/util/MatchMaskUtils.java deleted file mode 100644 index 67b0a6576d53dca2156efecbec4ff2af1be6db5d..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/util/MatchMaskUtils.java +++ /dev/null @@ -1,45 +0,0 @@ -package net.floodlightcontroller.util; - -import org.projectfloodlight.openflow.protocol.OFFactories; -import org.projectfloodlight.openflow.protocol.match.Match; -import org.projectfloodlight.openflow.protocol.match.MatchField; - -/** - * Apply certain, routine masks to existing matches. - * - * @author Ryan Izard <ryan.izard@bigswitch.com, rizard@g.clemson.edu> - */ -public class MatchMaskUtils { - /** - * Create a point-to-point match for two devices at the IP layer. - * Takes an existing match (e.g. from a PACKET_IN), and masks all - * MatchFields leaving behind: - * IN_PORT - * VLAN_VID - * ETH_SRC - * ETH_DST - * IPV4_SRC - * IPV4_DST - * - * @param m The match to remove all L4+ MatchFields from - * @return A new Match object with all MatchFields masked/wildcared - * except for those listed above. - */ - public static Match maskL4AndUp(Match m) { - // cannot create builder from existing match; will retain all MatchFields set - Match.Builder mb = OFFactories.getFactory(m.getVersion()).buildMatch(); - mb.setExact(MatchField.IN_PORT, m.get(MatchField.IN_PORT)) - .setExact(MatchField.VLAN_VID, m.get(MatchField.VLAN_VID)) - .setExact(MatchField.ETH_SRC, m.get(MatchField.ETH_SRC)) - .setExact(MatchField.ETH_DST, m.get(MatchField.ETH_DST)); - if (m.get(MatchField.IPV4_SRC) != null) { - mb.setExact(MatchField.IPV4_SRC, m.get(MatchField.IPV4_SRC)); - } - if (m.get(MatchField.IPV4_DST) != null) { - mb.setExact(MatchField.IPV4_DST, m.get(MatchField.IPV4_DST)); - } - return mb.build(); - } - - -} diff --git a/src/main/java/net/floodlightcontroller/util/MatchUtils.java b/src/main/java/net/floodlightcontroller/util/MatchUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..1d08b05d4174dde3002761801d74a331eebaa8d5 --- /dev/null +++ b/src/main/java/net/floodlightcontroller/util/MatchUtils.java @@ -0,0 +1,125 @@ +package net.floodlightcontroller.util; + +import java.util.Iterator; + +import org.projectfloodlight.openflow.protocol.OFFactories; +import org.projectfloodlight.openflow.protocol.match.Match; +import org.projectfloodlight.openflow.protocol.match.MatchField; + +/** + * Match helper functions. Use with any OpenFlowJ-Loxi Match. + * + * @author Ryan Izard <ryan.izard@bigswitch.com, rizard@g.clemson.edu> + */ +public class MatchUtils { + /** + * Create a point-to-point match for two devices at the IP layer. + * Takes an existing match (e.g. from a PACKET_IN), and masks all + * MatchFields leaving behind: + * IN_PORT + * VLAN_VID + * ETH_TYPE + * ETH_SRC + * ETH_DST + * IPV4_SRC + * IPV4_DST + * IP_PROTO (might remove this) + * + * If one of the above MatchFields is wildcarded in Match m, + * that MatchField will be wildcarded in the returned Match. + * + * @param m The match to remove all L4+ MatchFields from + * @return A new Match object with all MatchFields masked/wildcared + * except for those listed above. + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + public static Match maskL4AndUp(Match m) { + Match.Builder mb = m.createBuilder(); + Iterator<MatchField<?>> itr = m.getMatchFields().iterator(); // only get exact or masked fields (not fully wildcarded) + while(itr.hasNext()) { + MatchField mf = itr.next(); + // restrict MatchFields only to L3 and below: IN_PORT, ETH_TYPE, ETH_SRC, ETH_DST, IPV4_SRC, IPV4_DST, IP_PROTO (this one debatable...) + // if a MatchField is not in the access list below, it will not be set --> it will be left wildcarded (default) + if (mf.equals(MatchField.IN_PORT) || mf.equals(MatchField.ETH_TYPE) || mf.equals(MatchField.ETH_SRC) || mf.equals(MatchField.ETH_DST) || + mf.equals(MatchField.IPV4_SRC) || mf.equals(MatchField.IPV4_DST) || mf.equals(MatchField.IP_PROTO)) { + if (m.isExact(mf)) { + mb.setExact(mf, m.get(mf)); + } else if (m.isPartiallyMasked(mf)) { + mb.setMasked(mf, m.getMasked(mf)); + } else { + // it's either exact, masked, or wildcarded + // itr only contains exact and masked MatchFields + // we should never get here + } + } + } + return mb.build(); + } + + /** + * Create a builder from an existing Match object. Unlike Match's + * createBuilder(), this utility function will preserve all of + * Match m's MatchFields, even if new MatchFields are set or modified + * with the builder after it is returned to the calling function. + * + * All original MatchFields in m will be set if the build() method is + * invoked upon the returned builder. After the builder is returned, if + * a MatchField is modified via setExact(), setMasked(), or wildcard(), + * the newly modified MatchField will replace the original found in m. + * + * @param m; the match to create the builder from + * @return Match.Builder; the builder that can be modified, and when built, + * will retain all of m's MatchFields, unless you explicitly overwrite them. + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + public static Match.Builder createRetentiveBuilder(Match m) { + /* Builder retains a parent MatchField list, but list will not be used to + * build the new match if the builder's set methods have been invoked; only + * additions will be built, and all parent MatchFields will be ignored, + * even if they were not modified by the new builder. Create a builder, and + * walk through m's list of non-wildcarded MatchFields. Set them all in the + * new builder by invoking a set method for each. This will make them persist + * in the Match built from this builder if the user decides to add or subtract + * from the MatchField list. + */ + Match.Builder mb = m.createBuilder(); + Iterator<MatchField<?>> itr = m.getMatchFields().iterator(); // only get exact or masked fields (not fully wildcarded) + while(itr.hasNext()) { + MatchField mf = itr.next(); + if (m.isExact(mf)) { + mb.setExact(mf, m.get(mf)); + } else if (m.isPartiallyMasked(mf)) { + mb.setMasked(mf, m.getMasked(mf)); + } else { + // it's either exact, masked, or wildcarded + // itr only contains exact and masked MatchFields + // we should never get here + } + } + return mb; + } + + /** + * Create a Match builder the same OF version as Match m. The returned builder + * will not retain any MatchField information from Match m and will + * essentially return a clean-slate Match builder with no parent history. + * This simple method is included as a wrapper to provide the opposite functionality + * of createRetentiveBuilder(). + * + * @param m; the match to create the builder from + * @return Match.Builder; the builder retains no history from the parent Match m + */ + public static Match.Builder createForgetfulBuilder(Match m) { + return OFFactories.getFactory(m.getVersion()).buildMatch(); + } + + /** + * Create a duplicate Match object from Match m. + * + * @param m; the match to copy + * @return Match; the new copy of Match m + */ + public static Match createCopy(Match m) { + return m.createBuilder().build(); // will use parent MatchFields to produce the new Match only if the builder is never modified + } +}