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