blob: ba286195f774fc5c84242e183a4ae167c4d67781 [file] [log] [blame]
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001package net.floodlightcontroller.staticflowentry;
2
3import java.io.IOException;
4import java.util.Arrays;
5import java.util.HashMap;
6import java.util.LinkedList;
7import java.util.List;
8import java.util.Map;
9import java.util.regex.Matcher;
10import java.util.regex.Pattern;
11
12import net.floodlightcontroller.core.annotations.LogMessageCategory;
13import net.floodlightcontroller.core.annotations.LogMessageDoc;
14import net.floodlightcontroller.core.util.AppCookie;
15import net.floodlightcontroller.packet.IPv4;
16
17import org.slf4j.Logger;
18import org.slf4j.LoggerFactory;
19
20
21import org.codehaus.jackson.JsonParseException;
22import org.codehaus.jackson.JsonParser;
23import org.codehaus.jackson.JsonToken;
24import org.codehaus.jackson.map.MappingJsonFactory;
25import org.openflow.protocol.OFFlowMod;
26import org.openflow.protocol.OFMatch;
27import org.openflow.protocol.OFPacketOut;
28import org.openflow.protocol.OFPort;
29import org.openflow.protocol.action.OFAction;
30import org.openflow.protocol.action.OFActionDataLayerDestination;
31import org.openflow.protocol.action.OFActionDataLayerSource;
32import org.openflow.protocol.action.OFActionEnqueue;
33import org.openflow.protocol.action.OFActionNetworkLayerDestination;
34import org.openflow.protocol.action.OFActionNetworkLayerSource;
35import org.openflow.protocol.action.OFActionNetworkTypeOfService;
36import org.openflow.protocol.action.OFActionOutput;
37import org.openflow.protocol.action.OFActionStripVirtualLan;
38import org.openflow.protocol.action.OFActionTransportLayerDestination;
39import org.openflow.protocol.action.OFActionTransportLayerSource;
40import org.openflow.protocol.action.OFActionVirtualLanIdentifier;
41import org.openflow.protocol.action.OFActionVirtualLanPriorityCodePoint;
42import org.openflow.util.HexString;
43
44/**
45 * Represents static flow entries to be maintained by the controller on the
46 * switches.
47 */
48@LogMessageCategory("Static Flow Pusher")
49public class StaticFlowEntries {
50 protected static Logger log = LoggerFactory.getLogger(StaticFlowEntries.class);
51
52 private static class SubActionStruct {
53 OFAction action;
54 int len;
55 }
56
57 private static byte[] zeroMac = new byte[] {0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
58
59 /**
60 * This function generates a random hash for the bottom half of the cookie
61 *
62 * @param fm
63 * @param userCookie
64 * @param name
65 * @return A cookie that encodes the application ID and a hash
66 */
67 public static long computeEntryCookie(OFFlowMod fm, int userCookie, String name) {
68 // flow-specific hash is next 20 bits LOOK! who knows if this
69 int prime = 211;
70 int flowHash = 2311;
71 for (int i=0; i < name.length(); i++)
72 flowHash = flowHash * prime + (int)name.charAt(i);
73
74 return AppCookie.makeCookie(StaticFlowEntryPusher.STATIC_FLOW_APP_ID, flowHash);
75 }
76
77 /**
78 * Sets defaults for an OFFlowMod
79 * @param fm The OFFlowMod to set defaults for
80 * @param entryName The name of the entry. Used to compute the cookie.
81 */
82 public static void initDefaultFlowMod(OFFlowMod fm, String entryName) {
83 fm.setIdleTimeout((short) 0); // infinite
84 fm.setHardTimeout((short) 0); // infinite
85 fm.setBufferId(OFPacketOut.BUFFER_ID_NONE);
86 fm.setCommand((short) 0);
87 fm.setFlags((short) 0);
88 fm.setOutPort(OFPort.OFPP_NONE.getValue());
89 fm.setCookie(computeEntryCookie(fm, 0, entryName));
90 fm.setPriority(Short.MAX_VALUE);
91 }
92
93 /**
94 * Gets the entry name of a flow mod
95 * @param fmJson The OFFlowMod in a JSON representation
96 * @return The name of the OFFlowMod, null if not found
97 * @throws IOException If there was an error parsing the JSON
98 */
99 public static String getEntryNameFromJson(String fmJson) throws IOException{
100 MappingJsonFactory f = new MappingJsonFactory();
101 JsonParser jp;
102
103 try {
104 jp = f.createJsonParser(fmJson);
105 } catch (JsonParseException e) {
106 throw new IOException(e);
107 }
108
109 jp.nextToken();
110 if (jp.getCurrentToken() != JsonToken.START_OBJECT) {
111 throw new IOException("Expected START_OBJECT");
112 }
113
114 while (jp.nextToken() != JsonToken.END_OBJECT) {
115 if (jp.getCurrentToken() != JsonToken.FIELD_NAME) {
116 throw new IOException("Expected FIELD_NAME");
117 }
118
119 String n = jp.getCurrentName();
120 jp.nextToken();
121 if (jp.getText().equals(""))
122 continue;
123
124 if (n == "name")
125 return jp.getText();
126 }
127
128 return null;
129 }
130
131 /**
132 * Parses an OFFlowMod (and it's inner OFMatch) to the storage entry format.
133 * @param fm The FlowMod to parse
134 * @param sw The switch the FlowMod is going to be installed on
135 * @param name The name of this static flow entry
136 * @return A Map representation of the storage entry
137 */
138 public static Map<String, Object> flowModToStorageEntry(OFFlowMod fm, String sw, String name) {
139 Map<String, Object> entry = new HashMap<String, Object>();
140 OFMatch match = fm.getMatch();
141 entry.put(StaticFlowEntryPusher.COLUMN_NAME, name);
142 entry.put(StaticFlowEntryPusher.COLUMN_SWITCH, sw);
143 entry.put(StaticFlowEntryPusher.COLUMN_ACTIVE, Boolean.toString(true));
144 entry.put(StaticFlowEntryPusher.COLUMN_PRIORITY, Short.toString(fm.getPriority()));
145 entry.put(StaticFlowEntryPusher.COLUMN_WILDCARD, Integer.toString(match.getWildcards()));
146
147 if ((fm.getActions() != null) && (fm.getActions().size() > 0))
148 entry.put(StaticFlowEntryPusher.COLUMN_ACTIONS, StaticFlowEntries.flowModActionsToString(fm.getActions()));
149
150 if (match.getInputPort() != 0)
151 entry.put(StaticFlowEntryPusher.COLUMN_IN_PORT, Short.toString(match.getInputPort()));
152
153 if (!Arrays.equals(match.getDataLayerSource(), zeroMac))
154 entry.put(StaticFlowEntryPusher.COLUMN_DL_SRC, HexString.toHexString(match.getDataLayerSource()));
155
156 if (!Arrays.equals(match.getDataLayerDestination(), zeroMac))
157 entry.put(StaticFlowEntryPusher.COLUMN_DL_DST, HexString.toHexString(match.getDataLayerDestination()));
158
159 if (match.getDataLayerVirtualLan() != -1)
160 entry.put(StaticFlowEntryPusher.COLUMN_DL_VLAN, Short.toString(match.getDataLayerVirtualLan()));
161
162 if (match.getDataLayerVirtualLanPriorityCodePoint() != 0)
163 entry.put(StaticFlowEntryPusher.COLUMN_DL_VLAN_PCP, Short.toString(match.getDataLayerVirtualLanPriorityCodePoint()));
164
165 if (match.getDataLayerType() != 0)
166 entry.put(StaticFlowEntryPusher.COLUMN_DL_TYPE, Short.toString(match.getDataLayerType()));
167
168 if (match.getNetworkTypeOfService() != 0)
169 entry.put(StaticFlowEntryPusher.COLUMN_NW_TOS, Short.toString(match.getNetworkTypeOfService()));
170
171 if (match.getNetworkProtocol() != 0)
172 entry.put(StaticFlowEntryPusher.COLUMN_NW_PROTO, Short.toString(match.getNetworkProtocol()));
173
174 if (match.getNetworkSource() != 0)
175 entry.put(StaticFlowEntryPusher.COLUMN_NW_SRC, IPv4.fromIPv4Address(match.getNetworkSource()));
176
177 if (match.getNetworkDestination() != 0)
178 entry.put(StaticFlowEntryPusher.COLUMN_NW_DST, IPv4.fromIPv4Address(match.getNetworkDestination()));
179
180 if (match.getTransportSource() != 0)
181 entry.put(StaticFlowEntryPusher.COLUMN_TP_SRC, Short.toString(match.getTransportSource()));
182
183 if (match.getTransportDestination() != 0)
184 entry.put(StaticFlowEntryPusher.COLUMN_TP_DST, Short.toString(match.getTransportDestination()));
185
186 return entry;
187 }
188
189 /**
190 * Returns a String representation of all the openflow actions.
191 * @param fmActions A list of OFActions to encode into one string
192 * @return A string of the actions encoded for our database
193 */
194 @LogMessageDoc(level="ERROR",
195 message="Could not decode action {action}",
196 explanation="A static flow entry contained an invalid action",
197 recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG)
198 private static String flowModActionsToString(List<OFAction> fmActions) {
199 StringBuilder sb = new StringBuilder();
200 for (OFAction a : fmActions) {
201 if (sb.length() > 0) {
202 sb.append(',');
203 }
204 switch(a.getType()) {
205 case OUTPUT:
206 sb.append("output=" + Short.toString(((OFActionOutput)a).getPort()));
207 break;
208 case OPAQUE_ENQUEUE:
209 int queue = ((OFActionEnqueue)a).getQueueId();
210 short port = ((OFActionEnqueue)a).getPort();
211 sb.append("enqueue=" + Short.toString(port) + ":0x" + String.format("%02x", queue));
212 break;
213 case STRIP_VLAN:
214 sb.append("strip-vlan");
215 break;
216 case SET_VLAN_ID:
217 sb.append("set-vlan-id=" +
218 Short.toString(((OFActionVirtualLanIdentifier)a).getVirtualLanIdentifier()));
219 break;
220 case SET_VLAN_PCP:
221 sb.append("set-vlan-priority=" +
222 Byte.toString(((OFActionVirtualLanPriorityCodePoint)a).getVirtualLanPriorityCodePoint()));
223 break;
224 case SET_DL_SRC:
225 sb.append("set-src-mac=" +
226 HexString.toHexString(((OFActionDataLayerSource)a).getDataLayerAddress()));
227 break;
228 case SET_DL_DST:
229 sb.append("set-dst-mac=" +
230 HexString.toHexString(((OFActionDataLayerDestination)a).getDataLayerAddress()));
231 break;
232 case SET_NW_TOS:
233 sb.append("set-tos-bits=" +
234 Byte.toString(((OFActionNetworkTypeOfService)a).getNetworkTypeOfService()));
235 break;
236 case SET_NW_SRC:
237 sb.append("set-src-ip=" +
238 IPv4.fromIPv4Address(((OFActionNetworkLayerSource)a).getNetworkAddress()));
239 break;
240 case SET_NW_DST:
241 sb.append("set-dst-ip=" +
242 IPv4.fromIPv4Address(((OFActionNetworkLayerDestination)a).getNetworkAddress()));
243 break;
244 case SET_TP_SRC:
245 sb.append("set-src-port=" +
246 Short.toString(((OFActionTransportLayerSource)a).getTransportPort()));
247 break;
248 case SET_TP_DST:
249 sb.append("set-dst-port=" +
250 Short.toString(((OFActionTransportLayerDestination)a).getTransportPort()));
251 break;
252 default:
253 log.error("Could not decode action: {}", a);
254 break;
255 }
256
257 }
258 return sb.toString();
259 }
260
261 /**
262 * Turns a JSON formatted Static Flow Pusher string into a storage entry
263 * Expects a string in JSON along the lines of:
264 * {
265 * "switch": "AA:BB:CC:DD:EE:FF:00:11",
266 * "name": "flow-mod-1",
267 * "cookie": "0",
268 * "priority": "32768",
269 * "ingress-port": "1",
270 * "actions": "output=2",
271 * }
272 * @param fmJson The JSON formatted static flow pusher entry
273 * @return The map of the storage entry
274 * @throws IOException If there was an error parsing the JSON
275 */
276 public static Map<String, Object> jsonToStorageEntry(String fmJson) throws IOException {
277 Map<String, Object> entry = new HashMap<String, Object>();
278 MappingJsonFactory f = new MappingJsonFactory();
279 JsonParser jp;
280
281 try {
282 jp = f.createJsonParser(fmJson);
283 } catch (JsonParseException e) {
284 throw new IOException(e);
285 }
286
287 jp.nextToken();
288 if (jp.getCurrentToken() != JsonToken.START_OBJECT) {
289 throw new IOException("Expected START_OBJECT");
290 }
291
292 while (jp.nextToken() != JsonToken.END_OBJECT) {
293 if (jp.getCurrentToken() != JsonToken.FIELD_NAME) {
294 throw new IOException("Expected FIELD_NAME");
295 }
296
297 String n = jp.getCurrentName();
298 jp.nextToken();
299 if (jp.getText().equals(""))
300 continue;
301
302 if (n == "name")
303 entry.put(StaticFlowEntryPusher.COLUMN_NAME, jp.getText());
304 else if (n == "switch")
305 entry.put(StaticFlowEntryPusher.COLUMN_SWITCH, jp.getText());
306 else if (n == "actions")
307 entry.put(StaticFlowEntryPusher.COLUMN_ACTIONS, jp.getText());
308 else if (n == "priority")
309 entry.put(StaticFlowEntryPusher.COLUMN_PRIORITY, jp.getText());
310 else if (n == "active")
311 entry.put(StaticFlowEntryPusher.COLUMN_ACTIVE, jp.getText());
312 else if (n == "wildcards")
313 entry.put(StaticFlowEntryPusher.COLUMN_WILDCARD, jp.getText());
314 else if (n == "ingress-port")
315 entry.put(StaticFlowEntryPusher.COLUMN_IN_PORT, jp.getText());
316 else if (n == "src-mac")
317 entry.put(StaticFlowEntryPusher.COLUMN_DL_SRC, jp.getText());
318 else if (n == "dst-mac")
319 entry.put(StaticFlowEntryPusher.COLUMN_DL_DST, jp.getText());
320 else if (n == "vlan-id")
321 entry.put(StaticFlowEntryPusher.COLUMN_DL_VLAN, jp.getText());
322 else if (n == "vlan-priority")
323 entry.put(StaticFlowEntryPusher.COLUMN_DL_VLAN_PCP, jp.getText());
324 else if (n == "ether-type")
325 entry.put(StaticFlowEntryPusher.COLUMN_DL_TYPE, jp.getText());
326 else if (n == "tos-bits")
327 entry.put(StaticFlowEntryPusher.COLUMN_NW_TOS, jp.getText());
328 else if (n == "protocol")
329 entry.put(StaticFlowEntryPusher.COLUMN_NW_PROTO, jp.getText());
330 else if (n == "src-ip")
331 entry.put(StaticFlowEntryPusher.COLUMN_NW_SRC, jp.getText());
332 else if (n == "dst-ip")
333 entry.put(StaticFlowEntryPusher.COLUMN_NW_DST, jp.getText());
334 else if (n == "src-port")
335 entry.put(StaticFlowEntryPusher.COLUMN_TP_SRC, jp.getText());
336 else if (n == "dst-port")
337 entry.put(StaticFlowEntryPusher.COLUMN_TP_DST, jp.getText());
338 }
339
340 return entry;
341 }
342
343 /**
344 * Parses OFFlowMod actions from strings.
345 * @param flowMod The OFFlowMod to set the actions for
346 * @param actionstr The string containing all the actions
347 * @param log A logger to log for errors.
348 */
349 @LogMessageDoc(level="ERROR",
350 message="Unexpected action '{action}', '{subaction}'",
351 explanation="A static flow entry contained an invalid action",
352 recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG)
353 public static void parseActionString(OFFlowMod flowMod, String actionstr, Logger log) {
354 List<OFAction> actions = new LinkedList<OFAction>();
355 int actionsLength = 0;
356 if (actionstr != null) {
357 actionstr = actionstr.toLowerCase();
358 for (String subaction : actionstr.split(",")) {
359 String action = subaction.split("[=:]")[0];
360 SubActionStruct subaction_struct = null;
361
362 if (action.equals("output")) {
363 subaction_struct = StaticFlowEntries.decode_output(subaction, log);
364 }
365 else if (action.equals("enqueue")) {
366 subaction_struct = decode_enqueue(subaction, log);
367 }
368 else if (action.equals("strip-vlan")) {
369 subaction_struct = decode_strip_vlan(subaction, log);
370 }
371 else if (action.equals("set-vlan-id")) {
372 subaction_struct = decode_set_vlan_id(subaction, log);
373 }
374 else if (action.equals("set-vlan-priority")) {
375 subaction_struct = decode_set_vlan_priority(subaction, log);
376 }
377 else if (action.equals("set-src-mac")) {
378 subaction_struct = decode_set_src_mac(subaction, log);
379 }
380 else if (action.equals("set-dst-mac")) {
381 subaction_struct = decode_set_dst_mac(subaction, log);
382 }
383 else if (action.equals("set-tos-bits")) {
384 subaction_struct = decode_set_tos_bits(subaction, log);
385 }
386 else if (action.equals("set-src-ip")) {
387 subaction_struct = decode_set_src_ip(subaction, log);
388 }
389 else if (action.equals("set-dst-ip")) {
390 subaction_struct = decode_set_dst_ip(subaction, log);
391 }
392 else if (action.equals("set-src-port")) {
393 subaction_struct = decode_set_src_port(subaction, log);
394 }
395 else if (action.equals("set-dst-port")) {
396 subaction_struct = decode_set_dst_port(subaction, log);
397 }
398 else {
399 log.error("Unexpected action '{}', '{}'", action, subaction);
400 }
401
402 if (subaction_struct != null) {
403 actions.add(subaction_struct.action);
404 actionsLength += subaction_struct.len;
405 }
406 }
407 }
408 log.debug("action {}", actions);
409
410 flowMod.setActions(actions);
411 flowMod.setLengthU(OFFlowMod.MINIMUM_LENGTH + actionsLength);
412 }
413
414 @LogMessageDoc(level="ERROR",
415 message="Invalid subaction: '{subaction}'",
416 explanation="A static flow entry contained an invalid subaction",
417 recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG)
418 private static SubActionStruct decode_output(String subaction, Logger log) {
419 SubActionStruct sa = null;
420 Matcher n;
421
422 n = Pattern.compile("output=(?:((?:0x)?\\d+)|(all)|(controller)|(local)|(ingress-port)|(normal)|(flood))").matcher(subaction);
423 if (n.matches()) {
424 OFActionOutput action = new OFActionOutput();
425 action.setMaxLength((short) Short.MAX_VALUE);
426 short port = OFPort.OFPP_NONE.getValue();
427 if (n.group(1) != null) {
428 try {
429 port = get_short(n.group(1));
430 }
431 catch (NumberFormatException e) {
432 log.debug("Invalid port in: '{}' (error ignored)", subaction);
433 return null;
434 }
435 }
436 else if (n.group(2) != null)
437 port = OFPort.OFPP_ALL.getValue();
438 else if (n.group(3) != null)
439 port = OFPort.OFPP_CONTROLLER.getValue();
440 else if (n.group(4) != null)
441 port = OFPort.OFPP_LOCAL.getValue();
442 else if (n.group(5) != null)
443 port = OFPort.OFPP_IN_PORT.getValue();
444 else if (n.group(6) != null)
445 port = OFPort.OFPP_NORMAL.getValue();
446 else if (n.group(7) != null)
447 port = OFPort.OFPP_FLOOD.getValue();
448 action.setPort(port);
449 log.debug("action {}", action);
450
451 sa = new SubActionStruct();
452 sa.action = action;
453 sa.len = OFActionOutput.MINIMUM_LENGTH;
454 }
455 else {
456 log.error("Invalid subaction: '{}'", subaction);
457 return null;
458 }
459
460 return sa;
461 }
462
463 private static SubActionStruct decode_enqueue(String subaction, Logger log) {
464 SubActionStruct sa = null;
465 Matcher n;
466
467 n = Pattern.compile("enqueue=(?:((?:0x)?\\d+)\\:((?:0x)?\\d+))").matcher(subaction);
468 if (n.matches()) {
469 short portnum = 0;
470 if (n.group(1) != null) {
471 try {
472 portnum = get_short(n.group(1));
473 }
474 catch (NumberFormatException e) {
475 log.debug("Invalid port-num in: '{}' (error ignored)", subaction);
476 return null;
477 }
478 }
479
480 int queueid = 0;
481 if (n.group(2) != null) {
482 try {
483 queueid = get_int(n.group(2));
484 }
485 catch (NumberFormatException e) {
486 log.debug("Invalid queue-id in: '{}' (error ignored)", subaction);
487 return null;
488 }
489 }
490
491 OFActionEnqueue action = new OFActionEnqueue();
492 action.setPort(portnum);
493 action.setQueueId(queueid);
494 log.debug("action {}", action);
495
496 sa = new SubActionStruct();
497 sa.action = action;
498 sa.len = OFActionEnqueue.MINIMUM_LENGTH;
499 }
500 else {
501 log.debug("Invalid action: '{}'", subaction);
502 return null;
503 }
504
505 return sa;
506 }
507
508 private static SubActionStruct decode_strip_vlan(String subaction, Logger log) {
509 SubActionStruct sa = null;
510 Matcher n = Pattern.compile("strip-vlan").matcher(subaction);
511
512 if (n.matches()) {
513 OFActionStripVirtualLan action = new OFActionStripVirtualLan();
514 log.debug("action {}", action);
515
516 sa = new SubActionStruct();
517 sa.action = action;
518 sa.len = OFActionStripVirtualLan.MINIMUM_LENGTH;
519 }
520 else {
521 log.debug("Invalid action: '{}'", subaction);
522 return null;
523 }
524
525 return sa;
526 }
527
528 private static SubActionStruct decode_set_vlan_id(String subaction, Logger log) {
529 SubActionStruct sa = null;
530 Matcher n = Pattern.compile("set-vlan-id=((?:0x)?\\d+)").matcher(subaction);
531
532 if (n.matches()) {
533 if (n.group(1) != null) {
534 try {
535 short vlanid = get_short(n.group(1));
536 OFActionVirtualLanIdentifier action = new OFActionVirtualLanIdentifier();
537 action.setVirtualLanIdentifier(vlanid);
538 log.debug(" action {}", action);
539
540 sa = new SubActionStruct();
541 sa.action = action;
542 sa.len = OFActionVirtualLanIdentifier.MINIMUM_LENGTH;
543 }
544 catch (NumberFormatException e) {
545 log.debug("Invalid VLAN in: {} (error ignored)", subaction);
546 return null;
547 }
548 }
549 }
550 else {
551 log.debug("Invalid action: '{}'", subaction);
552 return null;
553 }
554
555 return sa;
556 }
557
558 private static SubActionStruct decode_set_vlan_priority(String subaction, Logger log) {
559 SubActionStruct sa = null;
560 Matcher n = Pattern.compile("set-vlan-priority=((?:0x)?\\d+)").matcher(subaction);
561
562 if (n.matches()) {
563 if (n.group(1) != null) {
564 try {
565 byte prior = get_byte(n.group(1));
566 OFActionVirtualLanPriorityCodePoint action = new OFActionVirtualLanPriorityCodePoint();
567 action.setVirtualLanPriorityCodePoint(prior);
568 log.debug(" action {}", action);
569
570 sa = new SubActionStruct();
571 sa.action = action;
572 sa.len = OFActionVirtualLanPriorityCodePoint.MINIMUM_LENGTH;
573 }
574 catch (NumberFormatException e) {
575 log.debug("Invalid VLAN priority in: {} (error ignored)", subaction);
576 return null;
577 }
578 }
579 }
580 else {
581 log.debug("Invalid action: '{}'", subaction);
582 return null;
583 }
584
585 return sa;
586 }
587
588 private static SubActionStruct decode_set_src_mac(String subaction, Logger log) {
589 SubActionStruct sa = null;
590 Matcher n = Pattern.compile("set-src-mac=(?:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+))").matcher(subaction);
591
592 if (n.matches()) {
593 byte[] macaddr = get_mac_addr(n, subaction, log);
594 if (macaddr != null) {
595 OFActionDataLayerSource action = new OFActionDataLayerSource();
596 action.setDataLayerAddress(macaddr);
597 log.debug("action {}", action);
598
599 sa = new SubActionStruct();
600 sa.action = action;
601 sa.len = OFActionDataLayerSource.MINIMUM_LENGTH;
602 }
603 }
604 else {
605 log.debug("Invalid action: '{}'", subaction);
606 return null;
607 }
608
609 return sa;
610 }
611
612 private static SubActionStruct decode_set_dst_mac(String subaction, Logger log) {
613 SubActionStruct sa = null;
614 Matcher n = Pattern.compile("set-dst-mac=(?:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+))").matcher(subaction);
615
616 if (n.matches()) {
617 byte[] macaddr = get_mac_addr(n, subaction, log);
618 if (macaddr != null) {
619 OFActionDataLayerDestination action = new OFActionDataLayerDestination();
620 action.setDataLayerAddress(macaddr);
621 log.debug(" action {}", action);
622
623 sa = new SubActionStruct();
624 sa.action = action;
625 sa.len = OFActionDataLayerDestination.MINIMUM_LENGTH;
626 }
627 }
628 else {
629 log.debug("Invalid action: '{}'", subaction);
630 return null;
631 }
632
633 return sa;
634 }
635
636 private static SubActionStruct decode_set_tos_bits(String subaction, Logger log) {
637 SubActionStruct sa = null;
638 Matcher n = Pattern.compile("set-tos-bits=((?:0x)?\\d+)").matcher(subaction);
639
640 if (n.matches()) {
641 if (n.group(1) != null) {
642 try {
643 byte tosbits = get_byte(n.group(1));
644 OFActionNetworkTypeOfService action = new OFActionNetworkTypeOfService();
645 action.setNetworkTypeOfService(tosbits);
646 log.debug(" action {}", action);
647
648 sa = new SubActionStruct();
649 sa.action = action;
650 sa.len = OFActionNetworkTypeOfService.MINIMUM_LENGTH;
651 }
652 catch (NumberFormatException e) {
653 log.debug("Invalid dst-port in: {} (error ignored)", subaction);
654 return null;
655 }
656 }
657 }
658 else {
659 log.debug("Invalid action: '{}'", subaction);
660 return null;
661 }
662
663 return sa;
664 }
665
666 private static SubActionStruct decode_set_src_ip(String subaction, Logger log) {
667 SubActionStruct sa = null;
668 Matcher n = Pattern.compile("set-src-ip=(?:(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+))").matcher(subaction);
669
670 if (n.matches()) {
671 int ipaddr = get_ip_addr(n, subaction, log);
672 OFActionNetworkLayerSource action = new OFActionNetworkLayerSource();
673 action.setNetworkAddress(ipaddr);
674 log.debug(" action {}", action);
675
676 sa = new SubActionStruct();
677 sa.action = action;
678 sa.len = OFActionNetworkLayerSource.MINIMUM_LENGTH;
679 }
680 else {
681 log.debug("Invalid action: '{}'", subaction);
682 return null;
683 }
684
685 return sa;
686 }
687
688 private static SubActionStruct decode_set_dst_ip(String subaction, Logger log) {
689 SubActionStruct sa = null;
690 Matcher n = Pattern.compile("set-dst-ip=(?:(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+))").matcher(subaction);
691
692 if (n.matches()) {
693 int ipaddr = get_ip_addr(n, subaction, log);
694 OFActionNetworkLayerDestination action = new OFActionNetworkLayerDestination();
695 action.setNetworkAddress(ipaddr);
696 log.debug("action {}", action);
697
698 sa = new SubActionStruct();
699 sa.action = action;
700 sa.len = OFActionNetworkLayerDestination.MINIMUM_LENGTH;
701 }
702 else {
703 log.debug("Invalid action: '{}'", subaction);
704 return null;
705 }
706
707 return sa;
708 }
709
710 private static SubActionStruct decode_set_src_port(String subaction, Logger log) {
711 SubActionStruct sa = null;
712 Matcher n = Pattern.compile("set-src-port=((?:0x)?\\d+)").matcher(subaction);
713
714 if (n.matches()) {
715 if (n.group(1) != null) {
716 try {
717 short portnum = get_short(n.group(1));
718 OFActionTransportLayerSource action = new OFActionTransportLayerSource();
719 action.setTransportPort(portnum);
720 log.debug("action {}", action);
721
722 sa = new SubActionStruct();
723 sa.action = action;
724 sa.len = OFActionTransportLayerSource.MINIMUM_LENGTH;;
725 }
726 catch (NumberFormatException e) {
727 log.debug("Invalid src-port in: {} (error ignored)", subaction);
728 return null;
729 }
730 }
731 }
732 else {
733 log.debug("Invalid action: '{}'", subaction);
734 return null;
735 }
736
737 return sa;
738 }
739
740 private static SubActionStruct decode_set_dst_port(String subaction, Logger log) {
741 SubActionStruct sa = null;
742 Matcher n = Pattern.compile("set-dst-port=((?:0x)?\\d+)").matcher(subaction);
743
744 if (n.matches()) {
745 if (n.group(1) != null) {
746 try {
747 short portnum = get_short(n.group(1));
748 OFActionTransportLayerDestination action = new OFActionTransportLayerDestination();
749 action.setTransportPort(portnum);
750 log.debug("action {}", action);
751
752 sa = new SubActionStruct();
753 sa.action = action;
754 sa.len = OFActionTransportLayerDestination.MINIMUM_LENGTH;;
755 }
756 catch (NumberFormatException e) {
757 log.debug("Invalid dst-port in: {} (error ignored)", subaction);
758 return null;
759 }
760 }
761 }
762 else {
763 log.debug("Invalid action: '{}'", subaction);
764 return null;
765 }
766
767 return sa;
768 }
769
770 private static byte[] get_mac_addr(Matcher n, String subaction, Logger log) {
771 byte[] macaddr = new byte[6];
772
773 for (int i=0; i<6; i++) {
774 if (n.group(i+1) != null) {
775 try {
776 macaddr[i] = get_byte("0x" + n.group(i+1));
777 }
778 catch (NumberFormatException e) {
779 log.debug("Invalid src-mac in: '{}' (error ignored)", subaction);
780 return null;
781 }
782 }
783 else {
784 log.debug("Invalid src-mac in: '{}' (null, error ignored)", subaction);
785 return null;
786 }
787 }
788
789 return macaddr;
790 }
791
792 private static int get_ip_addr(Matcher n, String subaction, Logger log) {
793 int ipaddr = 0;
794
795 for (int i=0; i<4; i++) {
796 if (n.group(i+1) != null) {
797 try {
798 ipaddr = ipaddr<<8;
799 ipaddr = ipaddr | get_int(n.group(i+1));
800 }
801 catch (NumberFormatException e) {
802 log.debug("Invalid src-ip in: '{}' (error ignored)", subaction);
803 return 0;
804 }
805 }
806 else {
807 log.debug("Invalid src-ip in: '{}' (null, error ignored)", subaction);
808 return 0;
809 }
810 }
811
812 return ipaddr;
813 }
814
815 // Parse int as decimal, hex (start with 0x or #) or octal (starts with 0)
816 private static int get_int(String str) {
817 return (int)Integer.decode(str);
818 }
819
820 // Parse short as decimal, hex (start with 0x or #) or octal (starts with 0)
821 private static short get_short(String str) {
822 return (short)(int)Integer.decode(str);
823 }
824
825 // Parse byte as decimal, hex (start with 0x or #) or octal (starts with 0)
826 private static byte get_byte(String str) {
827 return Integer.decode(str).byteValue();
828 }
829
830}
831