Initial opendaylight infrastructure commit!!
[controller.git] / third-party / openflowj / src / main / java / org / openflow / protocol / OFMatch.java
1 package org.openflow.protocol;
2
3 import java.io.Serializable;
4 import java.nio.ByteBuffer;
5 import java.util.Arrays;
6
7 import org.openflow.util.HexString;
8 import org.openflow.util.U16;
9 import org.openflow.util.U8;
10
11 /**
12  * Represents an ofp_match structure
13  * 
14  * @author David Erickson (daviderickson@cs.stanford.edu)
15  * @author Rob Sherwood (rob.sherwood@stanford.edu)
16  * 
17  */
18 public class OFMatch implements Cloneable, Serializable {
19     /**
20      * 
21      */
22     private static final long serialVersionUID = 1L;
23     public static int MINIMUM_LENGTH = 40;
24     final public static int OFPFW_ALL = ((1 << 22) - 1);
25
26     final public static int OFPFW_IN_PORT = 1 << 0; /* Switch input port. */
27     final public static int OFPFW_DL_VLAN = 1 << 1; /* VLAN id. */
28     final public static int OFPFW_DL_SRC = 1 << 2; /* Ethernet source address. */
29     final public static int OFPFW_DL_DST = 1 << 3; /*
30                                                     * Ethernet destination
31                                                     * address.
32                                                     */
33     final public static int OFPFW_DL_TYPE = 1 << 4; /* Ethernet frame type. */
34     final public static int OFPFW_NW_PROTO = 1 << 5; /* IP protocol. */
35     final public static int OFPFW_TP_SRC = 1 << 6; /* TCP/UDP source port. */
36     final public static int OFPFW_TP_DST = 1 << 7; /* TCP/UDP destination port. */
37
38     /*
39      * IP source address wildcard bit count. 0 is exact match, 1 ignores the
40      * LSB, 2 ignores the 2 least-significant bits, ..., 32 and higher wildcard
41      * the entire field. This is the *opposite* of the usual convention where
42      * e.g. /24 indicates that 8 bits (not 24 bits) are wildcarded.
43      */
44     final public static int OFPFW_NW_SRC_SHIFT = 8;
45     final public static int OFPFW_NW_SRC_BITS = 6;
46     final public static int OFPFW_NW_SRC_MASK = ((1 << OFPFW_NW_SRC_BITS) - 1) << OFPFW_NW_SRC_SHIFT;
47     final public static int OFPFW_NW_SRC_ALL = 32 << OFPFW_NW_SRC_SHIFT;
48
49     /* IP destination address wildcard bit count. Same format as source. */
50     final public static int OFPFW_NW_DST_SHIFT = 14;
51     final public static int OFPFW_NW_DST_BITS = 6;
52     final public static int OFPFW_NW_DST_MASK = ((1 << OFPFW_NW_DST_BITS) - 1) << OFPFW_NW_DST_SHIFT;
53     final public static int OFPFW_NW_DST_ALL = 32 << OFPFW_NW_DST_SHIFT;
54
55     final public static int OFPFW_DL_VLAN_PCP = 1 << 20; /* VLAN priority. */
56     final public static int OFPFW_NW_TOS = 1 << 21; /*
57                                                      * IP ToS (DSCP field, 6
58                                                      * bits).
59                                                      */
60
61     /* List of Strings for marshalling and unmarshalling to human readable forms */
62     final public static String STR_IN_PORT = "in_port";
63     final public static String STR_DL_DST = "dl_dst";
64     final public static String STR_DL_SRC = "dl_src";
65     final public static String STR_DL_TYPE = "dl_type";
66     final public static String STR_DL_VLAN = "dl_vlan";
67     final public static String STR_DL_VLAN_PCP = "dl_vpcp";
68     final public static String STR_NW_DST = "nw_dst";
69     final public static String STR_NW_SRC = "nw_src";
70     final public static String STR_NW_PROTO = "nw_proto";
71     final public static String STR_NW_TOS = "nw_tos";
72     final public static String STR_TP_DST = "tp_dst";
73     final public static String STR_TP_SRC = "tp_src";
74
75     protected int wildcards;
76     protected short inputPort;
77     protected byte[] dataLayerSource;
78     protected byte[] dataLayerDestination;
79     protected short dataLayerVirtualLan;
80     protected byte dataLayerVirtualLanPriorityCodePoint;
81     protected short dataLayerType;
82     protected byte networkTypeOfService;
83     protected byte networkProtocol;
84     protected int networkSource;
85     protected int networkDestination;
86     protected short transportSource;
87     protected short transportDestination;
88
89     /**
90      * By default, create a OFMatch that matches everything
91      * 
92      * (mostly because it's the least amount of work to make a valid OFMatch)
93      */
94     public OFMatch() {
95         this.wildcards = OFPFW_ALL;
96         this.dataLayerDestination = new byte[6];
97         this.dataLayerSource = new byte[6];
98     }
99
100     /**
101      * Get dl_dst
102      * 
103      * @return an arrays of bytes
104      */
105     public byte[] getDataLayerDestination() {
106         return this.dataLayerDestination;
107     }
108
109     /**
110      * Set dl_dst
111      * 
112      * @param dataLayerDestination
113      */
114     public OFMatch setDataLayerDestination(byte[] dataLayerDestination) {
115         this.dataLayerDestination = dataLayerDestination;
116         return this;
117     }
118
119     /**
120      * Set dl_dst, but first translate to byte[] using HexString
121      * 
122      * @param mac
123      *            A colon separated string of 6 pairs of octets, e..g.,
124      *            "00:17:42:EF:CD:8D"
125      */
126     public OFMatch setDataLayerDestination(String mac) {
127         byte bytes[] = HexString.fromHexString(mac);
128         if (bytes.length != 6)
129             throw new IllegalArgumentException(
130                     "expected string with 6 octets, got '" + mac + "'");
131         this.dataLayerDestination = bytes;
132         return this;
133     }
134
135     /**
136      * Get dl_src
137      * 
138      * @return an array of bytes
139      */
140     public byte[] getDataLayerSource() {
141         return this.dataLayerSource;
142     }
143
144     /**
145      * Set dl_src
146      * 
147      * @param dataLayerSource
148      */
149     public OFMatch setDataLayerSource(byte[] dataLayerSource) {
150         this.dataLayerSource = dataLayerSource;
151         return this;
152     }
153
154     /**
155      * Set dl_src, but first translate to byte[] using HexString
156      * 
157      * @param mac
158      *            A colon separated string of 6 pairs of octets, e..g.,
159      *            "00:17:42:EF:CD:8D"
160      */
161     public OFMatch setDataLayerSource(String mac) {
162         byte bytes[] = HexString.fromHexString(mac);
163         if (bytes.length != 6)
164             throw new IllegalArgumentException(
165                     "expected string with 6 octets, got '" + mac + "'");
166         this.dataLayerSource = bytes;
167         return this;
168     }
169
170     /**
171      * Get dl_type
172      * 
173      * @return ether_type
174      */
175     public short getDataLayerType() {
176         return this.dataLayerType;
177     }
178
179     /**
180      * Set dl_type
181      * 
182      * @param dataLayerType
183      */
184     public OFMatch setDataLayerType(short dataLayerType) {
185         this.dataLayerType = dataLayerType;
186         return this;
187     }
188
189     /**
190      * Get dl_vlan
191      * 
192      * @return vlan tag; VLAN_NONE == no tag
193      */
194     public short getDataLayerVirtualLan() {
195         return this.dataLayerVirtualLan;
196     }
197
198     /**
199      * Set dl_vlan
200      * 
201      * @param dataLayerVirtualLan
202      */
203     public OFMatch setDataLayerVirtualLan(short dataLayerVirtualLan) {
204         this.dataLayerVirtualLan = dataLayerVirtualLan;
205         return this;
206     }
207
208     /**
209      * Get dl_vlan_pcp
210      * 
211      * @return
212      */
213     public byte getDataLayerVirtualLanPriorityCodePoint() {
214         return this.dataLayerVirtualLanPriorityCodePoint;
215     }
216
217     /**
218      * Set dl_vlan_pcp
219      * 
220      * @param pcp
221      */
222     public OFMatch setDataLayerVirtualLanPriorityCodePoint(byte pcp) {
223         this.dataLayerVirtualLanPriorityCodePoint = pcp;
224         return this;
225     }
226
227     /**
228      * Get in_port
229      * 
230      * @return
231      */
232     public short getInputPort() {
233         return this.inputPort;
234     }
235
236     /**
237      * Set in_port
238      * 
239      * @param inputPort
240      */
241     public OFMatch setInputPort(short inputPort) {
242         this.inputPort = inputPort;
243         return this;
244     }
245
246     /**
247      * Get nw_dst
248      * 
249      * @return
250      */
251     public int getNetworkDestination() {
252         return this.networkDestination;
253     }
254
255     /**
256      * Set nw_dst
257      * 
258      * @param networkDestination
259      */
260     public OFMatch setNetworkDestination(int networkDestination) {
261         this.networkDestination = networkDestination;
262         return this;
263     }
264
265     /**
266      * Parse this match's wildcard fields and return the number of significant
267      * bits in the IP destination field.
268      * 
269      * NOTE: this returns the number of bits that are fixed, i.e., like CIDR,
270      * not the number of bits that are free like OpenFlow encodes.
271      * 
272      * @return a number between 0 (matches all IPs) and 63 ( 32>= implies exact
273      *         match)
274      */
275     public int getNetworkDestinationMaskLen() {
276         return Math
277                 .max(32 - ((wildcards & OFPFW_NW_DST_MASK) >> OFPFW_NW_DST_SHIFT),
278                         0);
279     }
280
281     /**
282      * Parse this match's wildcard fields and return the number of significant
283      * bits in the IP destination field.
284      * 
285      * NOTE: this returns the number of bits that are fixed, i.e., like CIDR,
286      * not the number of bits that are free like OpenFlow encodes.
287      * 
288      * @return a number between 0 (matches all IPs) and 32 (exact match)
289      */
290     public int getNetworkSourceMaskLen() {
291         return Math
292                 .max(32 - ((wildcards & OFPFW_NW_SRC_MASK) >> OFPFW_NW_SRC_SHIFT),
293                         0);
294     }
295
296     /**
297      * Get nw_proto
298      * 
299      * @return
300      */
301     public byte getNetworkProtocol() {
302         return this.networkProtocol;
303     }
304
305     /**
306      * Set nw_proto
307      * 
308      * @param networkProtocol
309      */
310     public OFMatch setNetworkProtocol(byte networkProtocol) {
311         this.networkProtocol = networkProtocol;
312         return this;
313     }
314
315     /**
316      * Get nw_src
317      * 
318      * @return
319      */
320     public int getNetworkSource() {
321         return this.networkSource;
322     }
323
324     /**
325      * Set nw_src
326      * 
327      * @param networkSource
328      */
329     public OFMatch setNetworkSource(int networkSource) {
330         this.networkSource = networkSource;
331         return this;
332     }
333
334     /**
335      * Get nw_tos
336      * 
337      * @return
338      */
339     public byte getNetworkTypeOfService() {
340         return this.networkTypeOfService;
341     }
342
343     /**
344      * Set nw_tos
345      * 
346      * @param networkTypeOfService
347      */
348     public OFMatch setNetworkTypeOfService(byte networkTypeOfService) {
349         this.networkTypeOfService = networkTypeOfService;
350         return this;
351     }
352
353     /**
354      * Get tp_dst
355      * 
356      * @return
357      */
358     public short getTransportDestination() {
359         return this.transportDestination;
360     }
361
362     /**
363      * Set tp_dst
364      * 
365      * @param transportDestination
366      */
367     public OFMatch setTransportDestination(short transportDestination) {
368         this.transportDestination = transportDestination;
369         return this;
370     }
371
372     /**
373      * Get tp_src
374      * 
375      * @return
376      */
377     public short getTransportSource() {
378         return this.transportSource;
379     }
380
381     /**
382      * Set tp_src
383      * 
384      * @param transportSource
385      */
386     public OFMatch setTransportSource(short transportSource) {
387         this.transportSource = transportSource;
388         return this;
389     }
390
391     /**
392      * Get wildcards
393      * 
394      * @return
395      */
396     public int getWildcards() {
397         return this.wildcards;
398     }
399
400     /**
401      * Set wildcards
402      * 
403      * @param wildcards
404      */
405     public OFMatch setWildcards(int wildcards) {
406         this.wildcards = wildcards;
407         return this;
408     }
409
410     /**
411      * Initializes this OFMatch structure with the corresponding data from the
412      * specified packet.
413      * 
414      * Must specify the input port, to ensure that this.in_port is set
415      * correctly.
416      * 
417      * Specify OFPort.NONE or OFPort.ANY if input port not applicable or
418      * available
419      * 
420      * @param packetData
421      *            The packet's data
422      * @param inputPort
423      *            the port the packet arrived on
424      */
425     public OFMatch loadFromPacket(byte[] packetData, short inputPort) {
426         short scratch;
427         int transportOffset = 34;
428         ByteBuffer packetDataBB = ByteBuffer.wrap(packetData);
429         int limit = packetDataBB.limit();
430
431         this.wildcards = 0; // all fields have explicit entries
432
433         this.inputPort = inputPort;
434
435         if (inputPort == OFPort.OFPP_ALL.getValue())
436             this.wildcards |= OFPFW_IN_PORT;
437
438         assert (limit >= 14);
439         // dl dst
440         this.dataLayerDestination = new byte[6];
441         packetDataBB.get(this.dataLayerDestination);
442         // dl src
443         this.dataLayerSource = new byte[6];
444         packetDataBB.get(this.dataLayerSource);
445         // dl type
446         this.dataLayerType = packetDataBB.getShort();
447
448         if (getDataLayerType() != (short) 0x8100) { // need cast to avoid signed
449             // bug
450             setDataLayerVirtualLan((short) 0xffff);
451             setDataLayerVirtualLanPriorityCodePoint((byte) 0);
452         } else {
453             // has vlan tag
454             scratch = packetDataBB.getShort();
455             setDataLayerVirtualLan((short) (0xfff & scratch));
456             setDataLayerVirtualLanPriorityCodePoint((byte) ((0xe000 & scratch) >> 13));
457             this.dataLayerType = packetDataBB.getShort();
458         }
459
460         switch (getDataLayerType()) {
461         case 0x0800:
462             // ipv4
463             // check packet length
464             scratch = packetDataBB.get();
465             scratch = (short) (0xf & scratch);
466             transportOffset = (packetDataBB.position() - 1) + (scratch * 4);
467             // nw tos (dscp)
468             scratch = packetDataBB.get();
469             setNetworkTypeOfService((byte) ((0xfc & scratch) >> 2));
470             // nw protocol
471             packetDataBB.position(packetDataBB.position() + 7);
472             this.networkProtocol = packetDataBB.get();
473             // nw src
474             packetDataBB.position(packetDataBB.position() + 2);
475             this.networkSource = packetDataBB.getInt();
476             // nw dst
477             this.networkDestination = packetDataBB.getInt();
478             packetDataBB.position(transportOffset);
479             break;
480         case 0x0806:
481             // arp
482             int arpPos = packetDataBB.position();
483             // opcode
484             scratch = packetDataBB.getShort(arpPos + 6);
485             setNetworkProtocol((byte) (0xff & scratch));
486
487             scratch = packetDataBB.getShort(arpPos + 2);
488             // if ipv4 and addr len is 4
489             if (scratch == 0x800 && packetDataBB.get(arpPos + 5) == 4) {
490                 // nw src
491                 this.networkSource = packetDataBB.getInt(arpPos + 14);
492                 // nw dst
493                 this.networkDestination = packetDataBB.getInt(arpPos + 24);
494             } else {
495                 setNetworkSource(0);
496                 setNetworkDestination(0);
497             }
498             break;
499         default:
500             setNetworkTypeOfService((byte) 0);
501             setNetworkProtocol((byte) 0);
502             setNetworkSource(0);
503             setNetworkDestination(0);
504             break;
505         }
506
507         switch (getNetworkProtocol()) {
508         case 0x01:
509             // icmp
510             // type
511             this.transportSource = U8.f(packetDataBB.get());
512             // code
513             this.transportDestination = U8.f(packetDataBB.get());
514             break;
515         case 0x06:
516             // tcp
517             // tcp src
518             this.transportSource = packetDataBB.getShort();
519             // tcp dest
520             this.transportDestination = packetDataBB.getShort();
521             break;
522         case 0x11:
523             // udp
524             // udp src
525             this.transportSource = packetDataBB.getShort();
526             // udp dest
527             this.transportDestination = packetDataBB.getShort();
528             break;
529         default:
530             setTransportDestination((short) 0);
531             setTransportSource((short) 0);
532             break;
533         }
534         return this;
535     }
536
537     /**
538      * Read this message off the wire from the specified ByteBuffer
539      * 
540      * @param data
541      */
542     public void readFrom(ByteBuffer data) {
543         this.wildcards = data.getInt();
544         this.inputPort = data.getShort();
545         this.dataLayerSource = new byte[6];
546         data.get(this.dataLayerSource);
547         this.dataLayerDestination = new byte[6];
548         data.get(this.dataLayerDestination);
549         this.dataLayerVirtualLan = data.getShort();
550         this.dataLayerVirtualLanPriorityCodePoint = data.get();
551         data.get(); // pad
552         this.dataLayerType = data.getShort();
553         this.networkTypeOfService = data.get();
554         this.networkProtocol = data.get();
555         data.get(); // pad
556         data.get(); // pad
557         this.networkSource = data.getInt();
558         this.networkDestination = data.getInt();
559         this.transportSource = data.getShort();
560         this.transportDestination = data.getShort();
561     }
562
563     /**
564      * Write this message's binary format to the specified ByteBuffer
565      * 
566      * @param data
567      */
568     public void writeTo(ByteBuffer data) {
569         data.putInt(wildcards);
570         data.putShort(inputPort);
571         data.put(this.dataLayerSource);
572         data.put(this.dataLayerDestination);
573         data.putShort(dataLayerVirtualLan);
574         data.put(dataLayerVirtualLanPriorityCodePoint);
575         data.put((byte) 0x0); // pad
576         data.putShort(dataLayerType);
577         data.put(networkTypeOfService);
578         data.put(networkProtocol);
579         data.put((byte) 0x0); // pad
580         data.put((byte) 0x0); // pad
581         data.putInt(networkSource);
582         data.putInt(networkDestination);
583         data.putShort(transportSource);
584         data.putShort(transportDestination);
585     }
586
587     @Override
588     public int hashCode() {
589         final int prime = 131;
590         int result = 1;
591         result = prime * result + Arrays.hashCode(dataLayerDestination);
592         result = prime * result + Arrays.hashCode(dataLayerSource);
593         result = prime * result + dataLayerType;
594         result = prime * result + dataLayerVirtualLan;
595         result = prime * result + dataLayerVirtualLanPriorityCodePoint;
596         result = prime * result + inputPort;
597         result = prime * result + networkDestination;
598         result = prime * result + networkProtocol;
599         result = prime * result + networkSource;
600         result = prime * result + networkTypeOfService;
601         result = prime * result + transportDestination;
602         result = prime * result + transportSource;
603         result = prime * result + wildcards;
604         return result;
605     }
606
607     @Override
608     public boolean equals(Object obj) {
609         if (this == obj) {
610             return true;
611         }
612         if (obj == null) {
613             return false;
614         }
615         if (!(obj instanceof OFMatch)) {
616             return false;
617         }
618         OFMatch other = (OFMatch) obj;
619         if (!Arrays.equals(dataLayerDestination, other.dataLayerDestination)) {
620             return false;
621         }
622         if (!Arrays.equals(dataLayerSource, other.dataLayerSource)) {
623             return false;
624         }
625         if (dataLayerType != other.dataLayerType) {
626             return false;
627         }
628         if (dataLayerVirtualLan != other.dataLayerVirtualLan) {
629             return false;
630         }
631         if (dataLayerVirtualLanPriorityCodePoint != other.dataLayerVirtualLanPriorityCodePoint) {
632             return false;
633         }
634         if (inputPort != other.inputPort) {
635             return false;
636         }
637         if (networkDestination != other.networkDestination) {
638             return false;
639         }
640         if (networkProtocol != other.networkProtocol) {
641             return false;
642         }
643         if (networkSource != other.networkSource) {
644             return false;
645         }
646         if (networkTypeOfService != other.networkTypeOfService) {
647             return false;
648         }
649         if (transportDestination != other.transportDestination) {
650             return false;
651         }
652         if (transportSource != other.transportSource) {
653             return false;
654         }
655         if ((wildcards & OFMatch.OFPFW_ALL) != (other.wildcards & OFPFW_ALL)) { // only
656             // consider
657             // allocated
658             // part
659             // of
660             // wildcards
661             return false;
662         }
663         return true;
664     }
665
666     /**
667      * Implement clonable interface
668      */
669     @Override
670     public OFMatch clone() {
671         try {
672             OFMatch ret = (OFMatch) super.clone();
673             ret.dataLayerDestination = this.dataLayerDestination.clone();
674             ret.dataLayerSource = this.dataLayerSource.clone();
675             return ret;
676         } catch (CloneNotSupportedException e) {
677             throw new RuntimeException(e);
678         }
679     }
680
681     /**
682      * Output a dpctl-styled string, i.e., only list the elements that are not
683      * wildcarded
684      * 
685      * A match-everything OFMatch outputs "OFMatch[]"
686      * 
687      * @return 
688      *         "OFMatch[dl_src:00:20:01:11:22:33,nw_src:192.168.0.0/24,tp_dst:80]"
689      */
690     @Override
691     public String toString() {
692         String str = "";
693
694         // l1
695         if ((wildcards & OFPFW_IN_PORT) == 0)
696             str += "," + STR_IN_PORT + "=" + U16.f(this.inputPort);
697
698         // l2
699         if ((wildcards & OFPFW_DL_DST) == 0)
700             str += "," + STR_DL_DST + "="
701                     + HexString.toHexString(this.dataLayerDestination);
702         if ((wildcards & OFPFW_DL_SRC) == 0)
703             str += "," + STR_DL_SRC + "="
704                     + HexString.toHexString(this.dataLayerSource);
705         if ((wildcards & OFPFW_DL_TYPE) == 0)
706             str += "," + STR_DL_TYPE + "=0x"
707                     + Integer.toHexString(U16.f(this.dataLayerType));
708         if ((wildcards & OFPFW_DL_VLAN) == 0)
709             str += "," + STR_DL_VLAN + "=0x"
710                     + Integer.toHexString(U16.f(this.dataLayerVirtualLan));
711         if ((wildcards & OFPFW_DL_VLAN_PCP) == 0)
712             str += ","
713                     + STR_DL_VLAN_PCP
714                     + "="
715                     + Integer.toHexString(U8
716                             .f(this.dataLayerVirtualLanPriorityCodePoint));
717
718         // l3
719         if (getNetworkDestinationMaskLen() > 0)
720             str += ","
721                     + STR_NW_DST
722                     + "="
723                     + cidrToString(networkDestination,
724                             getNetworkDestinationMaskLen());
725         if (getNetworkSourceMaskLen() > 0)
726             str += "," + STR_NW_SRC + "="
727                     + cidrToString(networkSource, getNetworkSourceMaskLen());
728         if ((wildcards & OFPFW_NW_PROTO) == 0)
729             str += "," + STR_NW_PROTO + "=" + this.networkProtocol;
730         if ((wildcards & OFPFW_NW_TOS) == 0)
731             str += "," + STR_NW_TOS + "=" + this.networkTypeOfService;
732
733         // l4
734         if ((wildcards & OFPFW_TP_DST) == 0)
735             str += "," + STR_TP_DST + "=" + this.transportDestination;
736         if ((wildcards & OFPFW_TP_SRC) == 0)
737             str += "," + STR_TP_SRC + "=" + this.transportSource;
738         if ((str.length() > 0) && (str.charAt(0) == ','))
739             str = str.substring(1); // trim the leading ","
740         // done
741         return "OFMatch[" + str + "]";
742     }
743
744     private String cidrToString(int ip, int prefix) {
745         String str;
746         if (prefix >= 32) {
747             str = ipToString(ip);
748         } else {
749             // use the negation of mask to fake endian magic
750             int mask = ~((1 << (32 - prefix)) - 1);
751             str = ipToString(ip & mask) + "/" + prefix;
752         }
753
754         return str;
755     }
756
757     /**
758      * Set this OFMatch's parameters based on a comma-separated key=value pair
759      * dpctl-style string, e.g., from the output of OFMatch.toString() <br>
760      * <p>
761      * Supported keys/values include <br>
762      * <p>
763      * <TABLE border=1>
764      * <TR>
765      * <TD>KEY(s)
766      * <TD>VALUE
767      * </TR>
768      * <TR>
769      * <TD>"in_port","input_port"
770      * <TD>integer
771      * </TR>
772      * <TR>
773      * <TD>"dl_src","eth_src", "dl_dst","eth_dst"
774      * <TD>hex-string
775      * </TR>
776      * <TR>
777      * <TD>"dl_type", "dl_vlan", "dl_vlan_pcp"
778      * <TD>integer
779      * </TR>
780      * <TR>
781      * <TD>"nw_src", "nw_dst", "ip_src", "ip_dst"
782      * <TD>CIDR-style netmask
783      * </TR>
784      * <TR>
785      * <TD>"tp_src","tp_dst"
786      * <TD>integer (max 64k)
787      * </TR>
788      * </TABLE>
789      * <p>
790      * The CIDR-style netmasks assume 32 netmask if none given, so:
791      * "128.8.128.118/32" is the same as "128.8.128.118"
792      * 
793      * @param match
794      *            a key=value comma separated string, e.g.
795      *            "in_port=5,ip_dst=192.168.0.0/16,tp_src=80"
796      * @throws IllegalArgumentException
797      *             on unexpected key or value
798      */
799
800     public void fromString(String match) throws IllegalArgumentException {
801         if (match.equals("") || match.equalsIgnoreCase("any")
802                 || match.equalsIgnoreCase("all") || match.equals("[]"))
803             match = "OFMatch[]";
804         String[] tokens = match.split("[\\[,\\]]");
805         String[] values;
806         int initArg = 0;
807         if (tokens[0].equals("OFMatch"))
808             initArg = 1;
809         this.wildcards = OFPFW_ALL;
810         int i;
811         for (i = initArg; i < tokens.length; i++) {
812             values = tokens[i].split("=");
813             if (values.length != 2)
814                 throw new IllegalArgumentException("Token " + tokens[i]
815                         + " does not have form 'key=value' parsing " + match);
816             values[0] = values[0].toLowerCase(); // try to make this case insens
817             if (values[0].equals(STR_IN_PORT) || values[0].equals("input_port")) {
818                 this.inputPort = U16.t(Integer.valueOf(values[1]));
819                 this.wildcards &= ~OFPFW_IN_PORT;
820             } else if (values[0].equals(STR_DL_DST)
821                     || values[0].equals("eth_dst")) {
822                 this.dataLayerDestination = HexString.fromHexString(values[1]);
823                 this.wildcards &= ~OFPFW_DL_DST;
824             } else if (values[0].equals(STR_DL_SRC)
825                     || values[0].equals("eth_src")) {
826                 this.dataLayerSource = HexString.fromHexString(values[1]);
827                 this.wildcards &= ~OFPFW_DL_SRC;
828             } else if (values[0].equals(STR_DL_TYPE)
829                     || values[0].equals("eth_type")) {
830                 if (values[1].startsWith("0x"))
831                     this.dataLayerType = U16.t(Integer.valueOf(
832                             values[1].replaceFirst("0x", ""), 16));
833                 else
834                     this.dataLayerType = U16.t(Integer.valueOf(values[1]));
835                 this.wildcards &= ~OFPFW_DL_TYPE;
836             } else if (values[0].equals(STR_DL_VLAN)) {
837                 this.dataLayerVirtualLan = U16.t(Integer.valueOf(values[1]));
838                 this.wildcards &= ~OFPFW_DL_VLAN;
839             } else if (values[0].equals(STR_DL_VLAN_PCP)) {
840                 this.dataLayerVirtualLanPriorityCodePoint = U8.t(Short
841                         .valueOf(values[1]));
842                 this.wildcards &= ~OFPFW_DL_VLAN_PCP;
843             } else if (values[0].equals(STR_NW_DST)
844                     || values[0].equals("ip_dst"))
845                 setFromCIDR(values[1], STR_NW_DST);
846             else if (values[0].equals(STR_NW_SRC) || values[0].equals("ip_src"))
847                 setFromCIDR(values[1], STR_NW_SRC);
848             else if (values[0].equals(STR_NW_PROTO)) {
849                 this.networkProtocol = U8.t(Short.valueOf(values[1]));
850                 this.wildcards &= ~OFPFW_NW_PROTO;
851             } else if (values[0].equals(STR_NW_TOS)) {
852                 this.networkTypeOfService = U8.t(Short.valueOf(values[1]));
853                 this.wildcards &= ~OFPFW_NW_TOS;
854             } else if (values[0].equals(STR_TP_DST)) {
855                 this.transportDestination = U16.t(Integer.valueOf(values[1]));
856                 this.wildcards &= ~OFPFW_TP_DST;
857             } else if (values[0].equals(STR_TP_SRC)) {
858                 this.transportSource = U16.t(Integer.valueOf(values[1]));
859                 this.wildcards &= ~OFPFW_TP_SRC;
860             } else
861                 throw new IllegalArgumentException("unknown token " + tokens[i]
862                         + " parsing " + match);
863         }
864     }
865
866     /**
867      * Set the networkSource or networkDestionation address and their wildcards
868      * from the CIDR string
869      * 
870      * @param cidr
871      *            "192.168.0.0/16" or "172.16.1.5"
872      * @param which
873      *            one of STR_NW_DST or STR_NW_SRC
874      * @throws IllegalArgumentException
875      */
876     private void setFromCIDR(String cidr, String which)
877             throws IllegalArgumentException {
878         String values[] = cidr.split("/");
879         String[] ip_str = values[0].split("\\.");
880         int ip = 0;
881         ip += Integer.valueOf(ip_str[0]) << 24;
882         ip += Integer.valueOf(ip_str[1]) << 16;
883         ip += Integer.valueOf(ip_str[2]) << 8;
884         ip += Integer.valueOf(ip_str[3]);
885         int prefix = 32; // all bits are fixed, by default
886
887         if (values.length >= 2)
888             prefix = Integer.valueOf(values[1]);
889         int mask = 32 - prefix;
890         if (which.equals(STR_NW_DST)) {
891             this.networkDestination = ip;
892             this.wildcards = (wildcards & ~OFPFW_NW_DST_MASK)
893                     | (mask << OFPFW_NW_DST_SHIFT);
894         } else if (which.equals(STR_NW_SRC)) {
895             this.networkSource = ip;
896             this.wildcards = (wildcards & ~OFPFW_NW_SRC_MASK)
897                     | (mask << OFPFW_NW_SRC_SHIFT);
898         }
899     }
900
901     protected static String ipToString(int ip) {
902         return Integer.toString(U8.f((byte) ((ip & 0xff000000) >> 24))) + "."
903                 + Integer.toString((ip & 0x00ff0000) >> 16) + "."
904                 + Integer.toString((ip & 0x0000ff00) >> 8) + "."
905                 + Integer.toString(ip & 0x000000ff);
906     }
907
908     /**
909      * Reverses a match such that source and destination values plus
910      * corresponding masks are swapped. An input port must be explicitly
911      * passed in as the match does not contain an output port.
912      *
913      * @param inputPort new input port to use in match
914      * @param wildcardInputPort should the input port be wildcarded
915      *
916      * @return Reversed copy of match
917      */
918     public OFMatch reverse(short inputPort, boolean wildcardInputPort) {
919         OFMatch ret = this.clone();
920
921         // Set the input port
922         if (wildcardInputPort) {
923             ret.inputPort = 0;
924             ret.wildcards |= OFPFW_IN_PORT;
925         } else {
926             ret.inputPort = inputPort;
927             ret.wildcards &= ~OFPFW_IN_PORT;
928         }
929
930         // Switch the source/dest fields
931         ret.dataLayerDestination = this.dataLayerSource.clone();
932         ret.dataLayerSource = this.dataLayerDestination.clone();
933
934         ret.networkDestination = this.networkSource;
935         ret.networkSource = this.networkDestination;
936
937         ret.transportDestination = this.transportSource;
938         ret.transportSource = this.transportDestination;
939
940         // Switch the wildcards on source/dest fields
941         ret.wildcards &= ~(OFPFW_DL_DST | OFPFW_DL_SRC |
942                 OFPFW_NW_DST_MASK | OFPFW_NW_SRC_MASK |
943                 OFPFW_TP_DST | OFPFW_TP_SRC);
944         ret.wildcards |= ((this.wildcards & OFPFW_DL_DST) != 0 ) ? OFPFW_DL_SRC : 0;
945         ret.wildcards |= ((this.wildcards & OFPFW_DL_SRC) != 0 ) ? OFPFW_DL_DST : 0;
946         ret.wildcards |= (((this.wildcards & OFPFW_NW_DST_MASK) >> OFPFW_NW_DST_SHIFT) << OFPFW_NW_SRC_SHIFT);
947         ret.wildcards |= (((this.wildcards & OFPFW_NW_SRC_MASK) >> OFPFW_NW_SRC_SHIFT) << OFPFW_NW_DST_SHIFT);
948         ret.wildcards |= ((this.wildcards & OFPFW_TP_DST) != 0 ) ? OFPFW_TP_SRC : 0;
949         ret.wildcards |= ((this.wildcards & OFPFW_TP_SRC) != 0 ) ? OFPFW_TP_DST : 0;
950
951         return ret;
952     }
953
954     /**
955      * Check whether this match subsumes another match.
956      *
957      * This match subsumes another match if each field in this
958      * object either:
959      * <ol>
960      *   <li> exactly matches the corresponding field in the other match
961      *   <li> the field is wildcarded in this object
962      * </ol>
963      * Note: The network source and destination wildcards must have fewer
964      * or the same number of bits wildcarded in this object as the other.
965      *
966      * @param match match used for comparison when checking subsumes
967      * @return boolean indicating whether this match subsumes another match
968      */
969     public boolean subsumes(OFMatch match) {
970         // L1
971         if ((wildcards & OFPFW_IN_PORT) == 0) {
972             if (inputPort != match.inputPort) {
973                 return false;
974             }
975         }
976
977         // L2
978         if ((wildcards & OFPFW_DL_DST) == 0) {
979             if (!Arrays.equals(dataLayerDestination, match.dataLayerDestination)) {
980                 return false;
981             }
982         }
983         if ((wildcards & OFPFW_DL_SRC) == 0) {
984             if (!Arrays.equals(dataLayerSource, match.dataLayerSource)) {
985                 return false;
986             }
987         }
988         if ((wildcards & OFPFW_DL_TYPE) == 0) {
989             if (dataLayerType != match.dataLayerType) {
990                 return false;
991             }
992         }
993         if ((wildcards & OFPFW_DL_VLAN) == 0) {
994             if (dataLayerVirtualLan!= match.dataLayerVirtualLan) {
995                 return false;
996             }
997         }
998         if ((wildcards & OFPFW_DL_VLAN_PCP) == 0) {
999             if (dataLayerVirtualLanPriorityCodePoint != match.dataLayerVirtualLanPriorityCodePoint) {
1000                 return false;
1001             }
1002         }
1003
1004         // L3
1005         int maskLen = getNetworkDestinationMaskLen();
1006         if (maskLen > match.getNetworkDestinationMaskLen()) {
1007             return false;
1008         }
1009         int mask = (maskLen == 0) ? 0 : (0xffffffff << (32 - maskLen));
1010         if ((networkDestination & mask) != (match.networkDestination & mask)) {
1011             return false;
1012         }
1013         maskLen = getNetworkSourceMaskLen();
1014         if (maskLen > match.getNetworkSourceMaskLen()) {
1015             return false;
1016         }
1017         mask = (maskLen == 0) ? 0 : (0xffffffff << (32 - maskLen));
1018         if ((networkSource & mask) != (match.networkSource & mask)) {
1019             return false;
1020         }
1021         if ((wildcards & OFPFW_NW_PROTO) == 0) {
1022             if (networkProtocol != match.networkProtocol) {
1023                 return false;
1024             }
1025         }
1026         if ((wildcards & OFPFW_NW_TOS) == 0) {
1027             if (networkTypeOfService != match.networkTypeOfService) {
1028                 return false;
1029             }
1030         }
1031
1032         // L4
1033         if ((wildcards & OFPFW_TP_DST) == 0) {
1034             if (transportDestination != match.transportDestination) {
1035                 return false;
1036             }
1037         }
1038         if ((wildcards & OFPFW_TP_SRC) == 0) {
1039             if (transportSource != match.transportSource) {
1040                 return false;
1041             }
1042         }
1043
1044         return true;
1045     }
1046
1047 }