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