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