/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * 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 * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * 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 org.openflow.protocol; import java.io.Serializable; import java.nio.ByteBuffer; import java.util.Arrays; import net.floodlightcontroller.packet.Ethernet; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import org.jboss.netty.buffer.ChannelBuffer; import org.openflow.protocol.serializers.OFMatchJSONSerializer; import org.openflow.util.HexString; import org.openflow.util.U16; import org.openflow.util.U8; /** * Represents an ofp_match structure * * @author David Erickson (daviderickson@cs.stanford.edu) * @author Rob Sherwood (rob.sherwood@stanford.edu) */ @JsonSerialize(using = OFMatchJSONSerializer.class) public class OFMatch implements Cloneable, Serializable { /** * */ private static final long serialVersionUID = 1L; public static int MINIMUM_LENGTH = 40; final public static int OFPFW_ALL = ((1 << 22) - 1); final public static int OFPFW_IN_PORT = 1 << 0; /* Switch input port. */ final public static int OFPFW_DL_VLAN = 1 << 1; /* VLAN id. */ final public static int OFPFW_DL_SRC = 1 << 2; /* Ethernet source address. */ final public static int OFPFW_DL_DST = 1 << 3; /* * Ethernet destination * address. */ final public static int OFPFW_DL_TYPE = 1 << 4; /* Ethernet frame type. */ final public static int OFPFW_NW_PROTO = 1 << 5; /* IP protocol. */ final public static int OFPFW_TP_SRC = 1 << 6; /* TCP/UDP source port. */ final public static int OFPFW_TP_DST = 1 << 7; /* TCP/UDP destination port. */ /* * IP source address wildcard bit count. 0 is exact match, 1 ignores the * LSB, 2 ignores the 2 least-significant bits, ..., 32 and higher wildcard * the entire field. This is the *opposite* of the usual convention where * e.g. /24 indicates that 8 bits (not 24 bits) are wildcarded. */ final public static int OFPFW_NW_SRC_SHIFT = 8; final public static int OFPFW_NW_SRC_BITS = 6; final public static int OFPFW_NW_SRC_MASK = ((1 << OFPFW_NW_SRC_BITS) - 1) << OFPFW_NW_SRC_SHIFT; final public static int OFPFW_NW_SRC_ALL = 32 << OFPFW_NW_SRC_SHIFT; /* IP destination address wildcard bit count. Same format as source. */ final public static int OFPFW_NW_DST_SHIFT = 14; final public static int OFPFW_NW_DST_BITS = 6; final public static int OFPFW_NW_DST_MASK = ((1 << OFPFW_NW_DST_BITS) - 1) << OFPFW_NW_DST_SHIFT; final public static int OFPFW_NW_DST_ALL = 32 << OFPFW_NW_DST_SHIFT; final public static int OFPFW_DL_VLAN_PCP = 1 << 20; /* VLAN priority. */ final public static int OFPFW_NW_TOS = 1 << 21; /* * IP ToS (DSCP field, 6 * bits). */ final public static int OFPFW_ALL_SANITIZED = (((1 << 22) - 1) & ~OFPFW_NW_SRC_MASK & ~OFPFW_NW_DST_MASK) | OFPFW_NW_SRC_ALL | OFPFW_NW_DST_ALL; /* List of Strings for marshalling and unmarshalling to human readable forms */ final public static String STR_IN_PORT = "in_port"; final public static String STR_DL_DST = "dl_dst"; final public static String STR_DL_SRC = "dl_src"; final public static String STR_DL_TYPE = "dl_type"; final public static String STR_DL_VLAN = "dl_vlan"; final public static String STR_DL_VLAN_PCP = "dl_vlan_pcp"; final public static String STR_NW_DST = "nw_dst"; final public static String STR_NW_SRC = "nw_src"; final public static String STR_NW_PROTO = "nw_proto"; final public static String STR_NW_TOS = "nw_tos"; final public static String STR_TP_DST = "tp_dst"; final public static String STR_TP_SRC = "tp_src"; protected int wildcards; protected short inputPort; protected byte[] dataLayerSource; protected byte[] dataLayerDestination; protected short dataLayerVirtualLan; protected byte dataLayerVirtualLanPriorityCodePoint; protected short dataLayerType; protected byte networkTypeOfService; protected byte networkProtocol; protected int networkSource; protected int networkDestination; protected short transportSource; protected short transportDestination; /** * By default, create a OFMatch that matches everything (mostly because it's * the least amount of work to make a valid OFMatch) */ public OFMatch() { this.wildcards = OFPFW_ALL; this.dataLayerDestination = new byte[] { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; this.dataLayerSource = new byte[] { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; this.dataLayerVirtualLan = Ethernet.VLAN_UNTAGGED; this.dataLayerVirtualLanPriorityCodePoint = 0; this.dataLayerType = 0; this.inputPort = 0; this.networkProtocol = 0; this.networkTypeOfService = 0; this.networkSource = 0; this.networkDestination = 0; this.transportDestination = 0; this.transportSource = 0; } /** * Get dl_dst * * @return an arrays of bytes */ public byte[] getDataLayerDestination() { return this.dataLayerDestination; } /** * Set dl_dst * * @param dataLayerDestination */ public OFMatch setDataLayerDestination(byte[] dataLayerDestination) { this.dataLayerDestination = dataLayerDestination; return this; } /** * Set dl_dst, but first translate to byte[] using HexString * * @param mac * A colon separated string of 6 pairs of octets, e..g., * "00:17:42:EF:CD:8D" */ public OFMatch setDataLayerDestination(String mac) { byte bytes[] = HexString.fromHexString(mac); if (bytes.length != 6) throw new IllegalArgumentException( "expected string with 6 octets, got '" + mac + "'"); this.dataLayerDestination = bytes; return this; } /** * Get dl_src * * @return an array of bytes */ public byte[] getDataLayerSource() { return this.dataLayerSource; } /** * Set dl_src * * @param dataLayerSource */ public OFMatch setDataLayerSource(byte[] dataLayerSource) { this.dataLayerSource = dataLayerSource; return this; } /** * Set dl_src, but first translate to byte[] using HexString * * @param mac * A colon separated string of 6 pairs of octets, e..g., * "00:17:42:EF:CD:8D" */ public OFMatch setDataLayerSource(String mac) { byte bytes[] = HexString.fromHexString(mac); if (bytes.length != 6) throw new IllegalArgumentException( "expected string with 6 octets, got '" + mac + "'"); this.dataLayerSource = bytes; return this; } /** * Get dl_type * * @return ether_type */ public short getDataLayerType() { return this.dataLayerType; } /** * Set dl_type * * @param dataLayerType */ public OFMatch setDataLayerType(short dataLayerType) { this.dataLayerType = dataLayerType; return this; } /** * Get dl_vlan * * @return vlan tag; VLAN_NONE == no tag */ public short getDataLayerVirtualLan() { return this.dataLayerVirtualLan; } /** * Set dl_vlan * * @param dataLayerVirtualLan */ public OFMatch setDataLayerVirtualLan(short dataLayerVirtualLan) { this.dataLayerVirtualLan = dataLayerVirtualLan; return this; } /** * Get dl_vlan_pcp * * @return */ public byte getDataLayerVirtualLanPriorityCodePoint() { return this.dataLayerVirtualLanPriorityCodePoint; } /** * Set dl_vlan_pcp * * @param pcp */ public OFMatch setDataLayerVirtualLanPriorityCodePoint(byte pcp) { this.dataLayerVirtualLanPriorityCodePoint = pcp; return this; } /** * Get in_port * * @return */ public short getInputPort() { return this.inputPort; } /** * Set in_port * * @param inputPort */ public OFMatch setInputPort(short inputPort) { this.inputPort = inputPort; return this; } /** * Get nw_dst * * @return */ public int getNetworkDestination() { return this.networkDestination; } /** * Set nw_dst * * @param networkDestination */ public OFMatch setNetworkDestination(int networkDestination) { this.networkDestination = networkDestination; return this; } /** * Parse this match's wildcard fields and return the number of significant * bits in the IP destination field. NOTE: this returns the number of bits * that are fixed, i.e., like CIDR, not the number of bits that are free * like OpenFlow encodes. * * @return a number between 0 (matches all IPs) and 63 ( 32>= implies exact * match) */ public int getNetworkDestinationMaskLen() { return Math.max(32 - ((wildcards & OFPFW_NW_DST_MASK) >> OFPFW_NW_DST_SHIFT), 0); } /** * Parse this match's wildcard fields and return the number of significant * bits in the IP destination field. NOTE: this returns the number of bits * that are fixed, i.e., like CIDR, not the number of bits that are free * like OpenFlow encodes. * * @return a number between 0 (matches all IPs) and 32 (exact match) */ public int getNetworkSourceMaskLen() { return Math.max(32 - ((wildcards & OFPFW_NW_SRC_MASK) >> OFPFW_NW_SRC_SHIFT), 0); } /** * Get nw_proto * * @return */ public byte getNetworkProtocol() { return this.networkProtocol; } /** * Set nw_proto * * @param networkProtocol */ public OFMatch setNetworkProtocol(byte networkProtocol) { this.networkProtocol = networkProtocol; return this; } /** * Get nw_src * * @return */ public int getNetworkSource() { return this.networkSource; } /** * Set nw_src * * @param networkSource */ public OFMatch setNetworkSource(int networkSource) { this.networkSource = networkSource; return this; } /** * Get nw_tos OFMatch stores the ToS bits as top 6-bits, so right shift by 2 * bits before returning the value * * @return : 6-bit DSCP value (0-63) */ public byte getNetworkTypeOfService() { return (byte) ((this.networkTypeOfService >> 2) & 0x3f); } /** * Set nw_tos OFMatch stores the ToS bits as top 6-bits, so left shift by 2 * bits before storing the value * * @param networkTypeOfService * : 6-bit DSCP value (0-63) */ public OFMatch setNetworkTypeOfService(byte networkTypeOfService) { this.networkTypeOfService = (byte) (networkTypeOfService << 2); return this; } /** * Get tp_dst * * @return */ public short getTransportDestination() { return this.transportDestination; } /** * Set tp_dst * * @param transportDestination */ public OFMatch setTransportDestination(short transportDestination) { this.transportDestination = transportDestination; return this; } /** * Get tp_src * * @return */ public short getTransportSource() { return this.transportSource; } /** * Set tp_src * * @param transportSource */ public OFMatch setTransportSource(short transportSource) { this.transportSource = transportSource; return this; } /** * Get wildcards * * @return */ public int getWildcards() { return this.wildcards; } /** * Get wildcards * * @return */ public Wildcards getWildcardObj() { return Wildcards.of(wildcards); } /** * Set wildcards * * @param wildcards */ public OFMatch setWildcards(int wildcards) { this.wildcards = wildcards; return this; } /** set the wildcard using the Wildcards convenience object */ public OFMatch setWildcards(Wildcards wildcards) { this.wildcards = wildcards.getInt(); return this; } /** * Initializes this OFMatch structure with the corresponding data from the * specified packet. Must specify the input port, to ensure that * this.in_port is set correctly. Specify OFPort.NONE or OFPort.ANY if input * port not applicable or available * * @param packetData * The packet's data * @param inputPort * the port the packet arrived on */ public OFMatch loadFromPacket(byte[] packetData, short inputPort) { short scratch; int transportOffset = 34; ByteBuffer packetDataBB = ByteBuffer.wrap(packetData); int limit = packetDataBB.limit(); this.wildcards = 0; // all fields have explicit entries this.inputPort = inputPort; if (inputPort == OFPort.OFPP_ALL.getValue()) this.wildcards |= OFPFW_IN_PORT; assert (limit >= 14); // dl dst this.dataLayerDestination = new byte[6]; packetDataBB.get(this.dataLayerDestination); // dl src this.dataLayerSource = new byte[6]; packetDataBB.get(this.dataLayerSource); // dl type this.dataLayerType = packetDataBB.getShort(); if (getDataLayerType() != (short) 0x8100) { // need cast to avoid signed // bug setDataLayerVirtualLan((short) 0xffff); setDataLayerVirtualLanPriorityCodePoint((byte) 0); } else { // has vlan tag scratch = packetDataBB.getShort(); setDataLayerVirtualLan((short) (0xfff & scratch)); setDataLayerVirtualLanPriorityCodePoint((byte) ((0xe000 & scratch) >> 13)); this.dataLayerType = packetDataBB.getShort(); } switch (getDataLayerType()) { case 0x0800: // ipv4 // check packet length scratch = packetDataBB.get(); scratch = (short) (0xf & scratch); transportOffset = (packetDataBB.position() - 1) + (scratch * 4); // nw tos (dscp) scratch = packetDataBB.get(); setNetworkTypeOfService((byte) ((0xfc & scratch) >> 2)); // nw protocol packetDataBB.position(packetDataBB.position() + 7); this.networkProtocol = packetDataBB.get(); // nw src packetDataBB.position(packetDataBB.position() + 2); this.networkSource = packetDataBB.getInt(); // nw dst this.networkDestination = packetDataBB.getInt(); packetDataBB.position(transportOffset); break; case 0x0806: // arp int arpPos = packetDataBB.position(); // opcode scratch = packetDataBB.getShort(arpPos + 6); setNetworkProtocol((byte) (0xff & scratch)); scratch = packetDataBB.getShort(arpPos + 2); // if ipv4 and addr len is 4 if (scratch == 0x800 && packetDataBB.get(arpPos + 5) == 4) { // nw src this.networkSource = packetDataBB.getInt(arpPos + 14); // nw dst this.networkDestination = packetDataBB.getInt(arpPos + 24); } else { setNetworkSource(0); setNetworkDestination(0); } break; default: // Not ARP or IP. Wildcard NW_DST and NW_SRC this.wildcards |= OFPFW_NW_DST_ALL | OFPFW_NW_SRC_ALL | OFPFW_NW_PROTO | OFPFW_NW_TOS; setNetworkTypeOfService((byte) 0); setNetworkProtocol((byte) 0); setNetworkSource(0); setNetworkDestination(0); break; } switch (getNetworkProtocol()) { case 0x01: // icmp // type this.transportSource = U8.f(packetDataBB.get()); // code this.transportDestination = U8.f(packetDataBB.get()); break; case 0x06: // tcp // tcp src this.transportSource = packetDataBB.getShort(); // tcp dest this.transportDestination = packetDataBB.getShort(); break; case 0x11: // udp // udp src this.transportSource = packetDataBB.getShort(); // udp dest this.transportDestination = packetDataBB.getShort(); break; default: // Unknown network proto. this.wildcards |= OFPFW_TP_DST | OFPFW_TP_SRC; setTransportDestination((short) 0); setTransportSource((short) 0); break; } return this; } /** * Read this message off the wire from the specified ByteBuffer * * @param data */ public void readFrom(ChannelBuffer data) { this.wildcards = data.readInt(); this.inputPort = data.readShort(); this.dataLayerSource = new byte[6]; data.readBytes(this.dataLayerSource); this.dataLayerDestination = new byte[6]; data.readBytes(this.dataLayerDestination); this.dataLayerVirtualLan = data.readShort(); this.dataLayerVirtualLanPriorityCodePoint = data.readByte(); data.readByte(); // pad this.dataLayerType = data.readShort(); this.networkTypeOfService = data.readByte(); this.networkProtocol = data.readByte(); data.readByte(); // pad data.readByte(); // pad this.networkSource = data.readInt(); this.networkDestination = data.readInt(); this.transportSource = data.readShort(); this.transportDestination = data.readShort(); } /** * Write this message's binary format to the specified ByteBuffer * * @param data */ public void writeTo(ChannelBuffer data) { data.writeInt(wildcards); data.writeShort(inputPort); data.writeBytes(this.dataLayerSource); data.writeBytes(this.dataLayerDestination); data.writeShort(dataLayerVirtualLan); data.writeByte(dataLayerVirtualLanPriorityCodePoint); data.writeByte((byte) 0x0); // pad data.writeShort(dataLayerType); data.writeByte(networkTypeOfService); data.writeByte(networkProtocol); data.writeByte((byte) 0x0); // pad data.writeByte((byte) 0x0); // pad data.writeInt(networkSource); data.writeInt(networkDestination); data.writeShort(transportSource); data.writeShort(transportDestination); } @Override public int hashCode() { final int prime = 131; int result = 1; result = prime * result + Arrays.hashCode(dataLayerDestination); result = prime * result + Arrays.hashCode(dataLayerSource); result = prime * result + dataLayerType; result = prime * result + dataLayerVirtualLan; result = prime * result + dataLayerVirtualLanPriorityCodePoint; result = prime * result + inputPort; result = prime * result + networkDestination; result = prime * result + networkProtocol; result = prime * result + networkSource; result = prime * result + networkTypeOfService; result = prime * result + transportDestination; result = prime * result + transportSource; result = prime * result + wildcards; return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof OFMatch)) { return false; } OFMatch other = (OFMatch) obj; if (!Arrays.equals(dataLayerDestination, other.dataLayerDestination)) { return false; } if (!Arrays.equals(dataLayerSource, other.dataLayerSource)) { return false; } if (dataLayerType != other.dataLayerType) { return false; } if (dataLayerVirtualLan != other.dataLayerVirtualLan) { return false; } if (dataLayerVirtualLanPriorityCodePoint != other.dataLayerVirtualLanPriorityCodePoint) { return false; } if (inputPort != other.inputPort) { return false; } if (networkDestination != other.networkDestination) { return false; } if (networkProtocol != other.networkProtocol) { return false; } if (networkSource != other.networkSource) { return false; } if (networkTypeOfService != other.networkTypeOfService) { return false; } if (transportDestination != other.transportDestination) { return false; } if (transportSource != other.transportSource) { return false; } if ((wildcards & OFMatch.OFPFW_ALL) != (other.wildcards & OFPFW_ALL)) { // only // consider // allocated // part // of // wildcards return false; } return true; } /** * Implement clonable interface */ @Override public OFMatch clone() { try { OFMatch ret = (OFMatch) super.clone(); ret.dataLayerDestination = this.dataLayerDestination.clone(); ret.dataLayerSource = this.dataLayerSource.clone(); return ret; } catch (CloneNotSupportedException e) { throw new RuntimeException(e); } } /** * matching two OFMatch * @param toCompare * @return */ public boolean match(OFMatch toCompare) { if ((wildcards & OFPFW_IN_PORT) == 0 && this.inputPort != toCompare.getInputPort()) return false; if ((wildcards & OFPFW_DL_DST) == 0 && !Arrays.equals(this.dataLayerDestination, toCompare.getDataLayerDestination())) return false; if ((wildcards & OFPFW_DL_SRC) == 0 && !Arrays.equals(this.dataLayerSource, toCompare.getDataLayerSource())) return false; if ((wildcards & OFPFW_DL_TYPE) == 0 && this.dataLayerType != toCompare.getDataLayerType()) return false; if ((wildcards & OFPFW_DL_VLAN) == 0 && this.dataLayerVirtualLan != toCompare.getDataLayerVirtualLan()) return false; if ((wildcards & OFPFW_DL_VLAN_PCP) == 0 && this.dataLayerVirtualLanPriorityCodePoint != toCompare.getDataLayerVirtualLanPriorityCodePoint()) return false; if ((wildcards & OFPFW_NW_PROTO) == 0 && this.networkProtocol != toCompare.getNetworkProtocol()) return false; if ((wildcards & OFPFW_NW_TOS) == 0 && this.networkTypeOfService != toCompare.getNetworkTypeOfService()) return false; //compare network layer src/dst int dstmasklen = getNetworkDestinationMaskLen(); int srcmasklen = getNetworkSourceMaskLen(); if (dstmasklen >= 32 && networkDestination != toCompare.getNetworkDestination()) return false; if (srcmasklen >= 32 && networkSource != toCompare.getNetworkSource()) return false; int dstmask = ~((1 << (32 - dstmasklen)) - 1); int srcmask = ~((1 << (32 - srcmasklen)) - 1); if (dstmasklen < 32 && (networkDestination & dstmask) != (toCompare.getNetworkDestination() & dstmask)) return false; if (srcmasklen < 32 && (networkSource & srcmask) != (toCompare.getNetworkSource() & srcmask)) return false; //layer 4 if ((wildcards & OFPFW_TP_DST) == 0 && this.transportDestination != toCompare.getTransportDestination()) return false; if ((wildcards & OFPFW_TP_SRC) == 0 && this.transportSource != toCompare.getTransportSource()) return false; return true; } /** * Output a dpctl-styled string, i.e., only list the elements that are not * wildcarded A match-everything OFMatch outputs "OFMatch[]" * * @return * "OFMatch[dl_src:00:20:01:11:22:33,nw_src:192.168.0.0/24,tp_dst:80]" */ @Override public String toString() { String str = ""; // l1 if ((wildcards & OFPFW_IN_PORT) == 0) str += "," + STR_IN_PORT + "=" + U16.f(this.inputPort); // l2 if ((wildcards & OFPFW_DL_DST) == 0) str += "," + STR_DL_DST + "=" + HexString.toHexString(this.dataLayerDestination); if ((wildcards & OFPFW_DL_SRC) == 0) str += "," + STR_DL_SRC + "=" + HexString.toHexString(this.dataLayerSource); if ((wildcards & OFPFW_DL_TYPE) == 0) str += "," + STR_DL_TYPE + "=0x" + Integer.toHexString(U16.f(this.dataLayerType)); if ((wildcards & OFPFW_DL_VLAN) == 0) str += "," + STR_DL_VLAN + "=0x" + Integer.toHexString(U16.f(this.dataLayerVirtualLan)); if ((wildcards & OFPFW_DL_VLAN_PCP) == 0) str += "," + STR_DL_VLAN_PCP + "=" + Integer.toHexString(U8.f(this.dataLayerVirtualLanPriorityCodePoint)); // l3 if (getNetworkDestinationMaskLen() > 0) str += "," + STR_NW_DST + "=" + cidrToString(networkDestination, getNetworkDestinationMaskLen()); if (getNetworkSourceMaskLen() > 0) str += "," + STR_NW_SRC + "=" + cidrToString(networkSource, getNetworkSourceMaskLen()); if ((wildcards & OFPFW_NW_PROTO) == 0) str += "," + STR_NW_PROTO + "=" + this.networkProtocol; if ((wildcards & OFPFW_NW_TOS) == 0) str += "," + STR_NW_TOS + "=" + this.getNetworkTypeOfService(); // l4 if ((wildcards & OFPFW_TP_DST) == 0) str += "," + STR_TP_DST + "=" + this.transportDestination; if ((wildcards & OFPFW_TP_SRC) == 0) str += "," + STR_TP_SRC + "=" + this.transportSource; if ((str.length() > 0) && (str.charAt(0) == ',')) str = str.substring(1); // trim // the // leading // "," // done return "OFMatch[" + str + "]"; } /** * Return a string including all match fields, regardless whether they * are wildcarded or not. */ public String toStringUnmasked() { String str = ""; // l1 str += STR_IN_PORT + "=" + U16.f(this.inputPort); // l2 str += "," + STR_DL_DST + "=" + HexString.toHexString(this.dataLayerDestination); str += "," + STR_DL_SRC + "=" + HexString.toHexString(this.dataLayerSource); str += "," + STR_DL_TYPE + "=0x" + Integer.toHexString(U16.f(this.dataLayerType)); str += "," + STR_DL_VLAN + "=0x" + Integer.toHexString(U16.f(this.dataLayerVirtualLan)); str += "," + STR_DL_VLAN_PCP + "=" + Integer.toHexString(U8.f(this.dataLayerVirtualLanPriorityCodePoint)); // l3 str += "," + STR_NW_DST + "=" + cidrToString(networkDestination, getNetworkDestinationMaskLen()); str += "," + STR_NW_SRC + "=" + cidrToString(networkSource, getNetworkSourceMaskLen()); str += "," + STR_NW_PROTO + "=" + this.networkProtocol; str += "," + STR_NW_TOS + "=" + this.getNetworkTypeOfService(); // l4 str += "," + STR_TP_DST + "=" + this.transportDestination; str += "," + STR_TP_SRC + "=" + this.transportSource; // wildcards str += ", wildcards=" + debugWildCards(wildcards); return "OFMatch[" + str + "]"; } /** * debug a set of wildcards */ public static String debugWildCards(int wildcards) { String str = ""; // l1 if ((wildcards & OFPFW_IN_PORT) != 0) str += "|" + STR_IN_PORT; // l2 if ((wildcards & OFPFW_DL_DST) != 0) str += "|" + STR_DL_DST; if ((wildcards & OFPFW_DL_SRC) != 0) str += "|" + STR_DL_SRC; if ((wildcards & OFPFW_DL_TYPE) != 0) str += "|" + STR_DL_TYPE; if ((wildcards & OFPFW_DL_VLAN) != 0) str += "|" + STR_DL_VLAN; if ((wildcards & OFPFW_DL_VLAN_PCP) != 0) str += "|" + STR_DL_VLAN_PCP; int nwDstMask = Math.max(32 - ((wildcards & OFPFW_NW_DST_MASK) >> OFPFW_NW_DST_SHIFT), 0); int nwSrcMask = Math.max(32 - ((wildcards & OFPFW_NW_SRC_MASK) >> OFPFW_NW_SRC_SHIFT), 0); // l3 if (nwDstMask < 32) str += "|" + STR_NW_DST + "(/" + nwDstMask + ")"; if (nwSrcMask < 32) str += "|" + STR_NW_SRC + "(/" + nwSrcMask + ")"; if ((wildcards & OFPFW_NW_PROTO) != 0) str += "|" + STR_NW_PROTO; if ((wildcards & OFPFW_NW_TOS) != 0) str += "|" + STR_NW_TOS; // l4 if ((wildcards & OFPFW_TP_DST) != 0) str += "|" + STR_TP_DST; if ((wildcards & OFPFW_TP_SRC) != 0) str += "|" + STR_TP_SRC; if ((str.length() > 0) && (str.charAt(0) == '|')) str = str.substring(1); // trim // the // leading // "," // done return str; } private String cidrToString(int ip, int prefix) { String str; if (prefix >= 32) { str = ipToString(ip); } else { // use the negation of mask to fake endian magic int mask = ~((1 << (32 - prefix)) - 1); str = ipToString(ip & mask) + "/" + prefix; } return str; } /** * Set this OFMatch's parameters based on a comma-separated key=value pair * dpctl-style string, e.g., from the output of OFMatch.toString() <br> * <p> * Supported keys/values include <br> * <p> * <TABLE border=1> * <TR> * <TD>KEY(s) * <TD>VALUE * </TR> * <TR> * <TD>"in_port","input_port" * <TD>integer * </TR> * <TR> * <TD>"dl_src","eth_src", "dl_dst","eth_dst" * <TD>hex-string * </TR> * <TR> * <TD>"dl_type", "dl_vlan", "dl_vlan_pcp" * <TD>integer * </TR> * <TR> * <TD>"nw_src", "nw_dst", "ip_src", "ip_dst" * <TD>CIDR-style netmask * </TR> * <TR> * <TD>"tp_src","tp_dst" * <TD>integer (max 64k) * </TR> * </TABLE> * <p> * The CIDR-style netmasks assume 32 netmask if none given, so: * "128.8.128.118/32" is the same as "128.8.128.118" * * @param match * a key=value comma separated string, e.g. * "in_port=5,ip_dst=192.168.0.0/16,tp_src=80" * @throws IllegalArgumentException * on unexpected key or value */ public void fromString(String match) throws IllegalArgumentException { if (match.equals("") || match.equalsIgnoreCase("any") || match.equalsIgnoreCase("all") || match.equals("[]")) match = "OFMatch[]"; String[] tokens = match.split("[\\[,\\]]"); String[] values; int initArg = 0; if (tokens[0].equals("OFMatch")) initArg = 1; this.wildcards = OFPFW_ALL; int i; for (i = initArg; i < tokens.length; i++) { values = tokens[i].split("="); if (values.length != 2) throw new IllegalArgumentException( "Token " + tokens[i] + " does not have form 'key=value' parsing " + match); values[0] = values[0].toLowerCase(); // try to make this case insens if (values[0].equals(STR_IN_PORT) || values[0].equals("input_port")) { this.inputPort = U16.t(Integer.valueOf(values[1])); this.wildcards &= ~OFPFW_IN_PORT; } else if (values[0].equals(STR_DL_DST) || values[0].equals("eth_dst")) { this.dataLayerDestination = HexString.fromHexString(values[1]); this.wildcards &= ~OFPFW_DL_DST; } else if (values[0].equals(STR_DL_SRC) || values[0].equals("eth_src")) { this.dataLayerSource = HexString.fromHexString(values[1]); this.wildcards &= ~OFPFW_DL_SRC; } else if (values[0].equals(STR_DL_TYPE) || values[0].equals("eth_type")) { if (values[1].startsWith("0x")) this.dataLayerType = U16.t(Integer.valueOf(values[1].replaceFirst("0x", ""), 16)); else this.dataLayerType = U16.t(Integer.valueOf(values[1])); this.wildcards &= ~OFPFW_DL_TYPE; } else if (values[0].equals(STR_DL_VLAN)) { if (values[1].startsWith("0x")) this.dataLayerVirtualLan = U16.t(Integer.valueOf(values[1].replaceFirst("0x", ""), 16)); else this.dataLayerVirtualLan = U16.t(Integer.valueOf(values[1])); this.wildcards &= ~OFPFW_DL_VLAN; } else if (values[0].equals(STR_DL_VLAN_PCP)) { this.dataLayerVirtualLanPriorityCodePoint = U8.t(Short.valueOf(values[1])); this.wildcards &= ~OFPFW_DL_VLAN_PCP; } else if (values[0].equals(STR_NW_DST) || values[0].equals("ip_dst")) { setFromCIDR(values[1], STR_NW_DST); } else if (values[0].equals(STR_NW_SRC) || values[0].equals("ip_src")) { setFromCIDR(values[1], STR_NW_SRC); } else if (values[0].equals(STR_NW_PROTO)) { if (values[1].startsWith("0x")) this.networkProtocol = U8.t(Short.valueOf(values[1].replaceFirst("0x",""),16)); else this.networkProtocol = U8.t(Short.valueOf(values[1])); this.wildcards &= ~OFPFW_NW_PROTO; } else if (values[0].equals(STR_NW_TOS)) { this.setNetworkTypeOfService(U8.t(Short.valueOf(values[1]))); this.wildcards &= ~OFPFW_NW_TOS; } else if (values[0].equals(STR_TP_DST)) { this.transportDestination = U16.t(Integer.valueOf(values[1])); this.wildcards &= ~OFPFW_TP_DST; } else if (values[0].equals(STR_TP_SRC)) { this.transportSource = U16.t(Integer.valueOf(values[1])); this.wildcards &= ~OFPFW_TP_SRC; } else { throw new IllegalArgumentException("unknown token " + tokens[i] + " parsing " + match); } } } /** * Set the networkSource or networkDestionation address and their wildcards * from the CIDR string * * @param cidr * "192.168.0.0/16" or "172.16.1.5" * @param which * one of STR_NW_DST or STR_NW_SRC * @throws IllegalArgumentException */ private void setFromCIDR(String cidr, String which) throws IllegalArgumentException { String values[] = cidr.split("/"); String[] ip_str = values[0].split("\\."); int ip = 0; ip += Integer.valueOf(ip_str[0]) << 24; ip += Integer.valueOf(ip_str[1]) << 16; ip += Integer.valueOf(ip_str[2]) << 8; ip += Integer.valueOf(ip_str[3]); int prefix = 32; // all bits are fixed, by default if (values.length >= 2) prefix = Integer.valueOf(values[1]); int mask = 32 - prefix; if (which.equals(STR_NW_DST)) { this.networkDestination = ip; this.wildcards = (wildcards & ~OFPFW_NW_DST_MASK) | (mask << OFPFW_NW_DST_SHIFT); } else if (which.equals(STR_NW_SRC)) { this.networkSource = ip; this.wildcards = (wildcards & ~OFPFW_NW_SRC_MASK) | (mask << OFPFW_NW_SRC_SHIFT); } } protected static String ipToString(int ip) { return Integer.toString(U8.f((byte) ((ip & 0xff000000) >> 24))) + "." + Integer.toString((ip & 0x00ff0000) >> 16) + "." + Integer.toString((ip & 0x0000ff00) >> 8) + "." + Integer.toString(ip & 0x000000ff); } }