de6b8182b07c71c8975cd5fcfa49e3326197ef9e
[controller.git] / opendaylight / forwardingrulesmanager / api / src / main / java / org / opendaylight / controller / forwardingrulesmanager / FlowConfig.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.controller.forwardingrulesmanager;
10
11 import org.opendaylight.controller.sal.action.Action;
12 import org.opendaylight.controller.sal.action.ActionType;
13 import org.opendaylight.controller.sal.action.Controller;
14 import org.opendaylight.controller.sal.action.Drop;
15 import org.opendaylight.controller.sal.action.Enqueue;
16 import org.opendaylight.controller.sal.action.Flood;
17 import org.opendaylight.controller.sal.action.HwPath;
18 import org.opendaylight.controller.sal.action.Loopback;
19 import org.opendaylight.controller.sal.action.Output;
20 import org.opendaylight.controller.sal.action.PopVlan;
21 import org.opendaylight.controller.sal.action.SetDlDst;
22 import org.opendaylight.controller.sal.action.SetDlSrc;
23 import org.opendaylight.controller.sal.action.SetNextHop;
24 import org.opendaylight.controller.sal.action.SetNwDst;
25 import org.opendaylight.controller.sal.action.SetNwSrc;
26 import org.opendaylight.controller.sal.action.SetNwTos;
27 import org.opendaylight.controller.sal.action.SetTpDst;
28 import org.opendaylight.controller.sal.action.SetTpSrc;
29 import org.opendaylight.controller.sal.action.SetVlanId;
30 import org.opendaylight.controller.sal.action.SetVlanPcp;
31 import org.opendaylight.controller.sal.action.SwPath;
32 import org.opendaylight.controller.sal.core.ContainerFlow;
33 import org.opendaylight.controller.sal.core.IContainer;
34 import org.opendaylight.controller.sal.core.Node;
35 import org.opendaylight.controller.sal.core.NodeConnector;
36 import org.opendaylight.controller.sal.flowprogrammer.Flow;
37 import org.opendaylight.controller.sal.match.Match;
38 import org.opendaylight.controller.sal.match.MatchType;
39 import org.opendaylight.controller.sal.utils.GlobalConstants;
40 import org.opendaylight.controller.sal.utils.HexEncode;
41 import org.opendaylight.controller.sal.utils.IPProtocols;
42 import org.opendaylight.controller.sal.utils.NetUtils;
43 import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
44 import org.opendaylight.controller.sal.utils.ServiceHelper;
45 import org.opendaylight.controller.sal.utils.Status;
46 import org.opendaylight.controller.sal.utils.StatusCode;
47 import org.opendaylight.controller.switchmanager.ISwitchManager;
48 import org.opendaylight.controller.switchmanager.Switch;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
51
52 import javax.xml.bind.annotation.XmlAccessType;
53 import javax.xml.bind.annotation.XmlAccessorType;
54 import javax.xml.bind.annotation.XmlElement;
55 import javax.xml.bind.annotation.XmlRootElement;
56 import java.io.Serializable;
57 import java.net.Inet6Address;
58 import java.net.InetAddress;
59 import java.util.ArrayList;
60 import java.util.List;
61 import java.util.regex.Matcher;
62 import java.util.regex.Pattern;
63
64 /**
65  * Configuration Java Object which represents a flow configuration information
66  * for Forwarding Rules Manager.
67  */
68 @XmlRootElement
69 @XmlAccessorType(XmlAccessType.NONE)
70 public class FlowConfig implements Serializable {
71     private static final long serialVersionUID = 1L;
72     private static final Logger log = LoggerFactory.getLogger(FlowConfig.class);
73     private static final String NAMEREGEX = "^[a-zA-Z0-9]+$";
74     public static final String STATICFLOWGROUP = "__StaticFlows__";
75     public static final String INTERNALSTATICFLOWGROUP = "__InternalStaticFlows__";
76     public static final String INTERNALSTATICFLOWBEGIN = "__";
77     public static final String INTERNALSTATICFLOWEND = "__";
78     private boolean dynamic;
79     private String status;
80
81     /*
82      * The order of the object data defined below is used directly in the UI
83      * built using JSP. Hence try to keep the order in a more logical way.
84      */
85     @XmlElement
86     private String installInHw;
87     @XmlElement
88     private String name;
89     @XmlElement
90     private Node node;
91     @XmlElement
92     private String ingressPort;
93     private String portGroup;
94     @XmlElement
95     private String priority;
96     @XmlElement
97     private String etherType;
98     @XmlElement
99     private String vlanId;
100     @XmlElement
101     private String vlanPriority;
102     @XmlElement
103     private String dlSrc;
104     @XmlElement
105     private String dlDst;
106     @XmlElement
107     private String nwSrc;
108     @XmlElement
109     private String nwDst;
110     @XmlElement
111     private String protocol;
112     @XmlElement
113     private String tosBits;
114     @XmlElement
115     private String tpSrc;
116     @XmlElement
117     private String tpDst;
118     @XmlElement
119     private String cookie;
120     @XmlElement
121     private String idleTimeout;
122     @XmlElement
123     private String hardTimeout;
124     @XmlElement
125     private List<String> actions;
126
127     private enum EtherIPType {
128         ANY, V4, V6;
129     };
130
131     public FlowConfig() {
132     }
133
134     public FlowConfig(String installInHw, String name, Node node, String priority, String cookie, String ingressPort,
135             String portGroup, String vlanId, String vlanPriority, String etherType, String srcMac, String dstMac,
136             String protocol, String tosBits, String srcIP, String dstIP, String tpSrc, String tpDst,
137             String idleTimeout, String hardTimeout, List<String> actions) {
138         super();
139         this.installInHw = installInHw;
140         this.name = name;
141         this.node = node;
142         this.priority = priority;
143         this.cookie = cookie;
144         this.ingressPort = ingressPort;
145         this.portGroup = portGroup;
146         this.vlanId = vlanId;
147         this.vlanPriority = vlanPriority;
148         this.etherType = etherType;
149         this.dlSrc = srcMac;
150         this.dlDst = dstMac;
151         this.protocol = protocol;
152         this.tosBits = tosBits;
153         this.nwSrc = srcIP;
154         this.nwDst = dstIP;
155         this.tpSrc = tpSrc;
156         this.tpDst = tpDst;
157         this.idleTimeout = idleTimeout;
158         this.hardTimeout = hardTimeout;
159         this.actions = actions;
160         this.status = StatusCode.SUCCESS.toString();
161     }
162
163     public FlowConfig(FlowConfig from) {
164         this.installInHw = from.installInHw;
165         this.name = from.name;
166         this.node = from.node;
167         this.priority = from.priority;
168         this.cookie = from.cookie;
169         this.ingressPort = from.ingressPort;
170         this.portGroup = from.portGroup;
171         this.vlanId = from.vlanId;
172         this.vlanPriority = from.vlanPriority;
173         this.etherType = from.etherType;
174         this.dlSrc = from.dlSrc;
175         this.dlDst = from.dlDst;
176         this.protocol = from.protocol;
177         this.tosBits = from.tosBits;
178         this.nwSrc = from.nwSrc;
179         this.nwDst = from.nwDst;
180         this.tpSrc = from.tpSrc;
181         this.tpDst = from.tpDst;
182         this.idleTimeout = from.idleTimeout;
183         this.hardTimeout = from.hardTimeout;
184         this.actions = new ArrayList<String>(from.actions);
185     }
186
187     public boolean installInHw() {
188         if (installInHw == null) {
189             // backward compatibility
190             installInHw = Boolean.toString(true);
191         }
192         return Boolean.valueOf(installInHw);
193     }
194
195     public void setInstallInHw(boolean inHw) {
196         installInHw = String.valueOf(inHw);
197     }
198
199     public String getInstallInHw() {
200         return installInHw;
201     }
202
203     public boolean isInternalFlow() {
204         return (this.name != null &&
205                 this.name.startsWith(FlowConfig.INTERNALSTATICFLOWBEGIN) &&
206                 this.name.endsWith(FlowConfig.INTERNALSTATICFLOWEND));
207     }
208
209     public String getName() {
210         return name;
211     }
212
213     public void setName(String name) {
214         if (name == null) {
215             return;
216         }
217         this.name = name;
218     }
219
220     public Node getNode() {
221         return this.node;
222     }
223
224     public void setNode(Node node) {
225         this.node = node;
226     }
227
228     public String getPriority() {
229         return priority;
230     }
231
232     public void setPriority(String priority) {
233         this.priority = priority;
234     }
235
236     public String getCookie() {
237         return cookie;
238     }
239
240     public void setCookie(String cookie) {
241         this.cookie = cookie;
242     }
243
244     public String getIngressPort() {
245         return ingressPort;
246     }
247
248     public void setIngressPort(String ingressPort) {
249         this.ingressPort = ingressPort;
250     }
251
252     public String getPortGroup() {
253         return portGroup;
254     }
255
256     @Override
257     public String toString() {
258         return "FlowConfig [dynamic=" + dynamic + ", status=" + status + ", installInHw=" + installInHw + ", name="
259                 + name + ", switchId=" + node + ", ingressPort=" + ingressPort + ", portGroup=" + portGroup
260                 + ", etherType=" + etherType + ", priority=" + priority + ", vlanId=" + vlanId + ", vlanPriority="
261                 + vlanPriority + ", dlSrc=" + dlSrc + ", dlDst=" + dlDst + ", nwSrc=" + nwSrc + ", nwDst=" + nwDst
262                 + ", protocol=" + protocol + ", tosBits=" + tosBits + ", tpSrc=" + tpSrc + ", tpDst=" + tpDst
263                 + ", cookie=" + cookie + ", idleTimeout=" + idleTimeout + ", hardTimeout=" + hardTimeout + ", actions="
264                 + actions + "]";
265     }
266
267     public void setPortGroup(String portGroup) {
268         this.portGroup = portGroup;
269     }
270
271     public String getVlanId() {
272         return vlanId;
273     }
274
275     public void setVlanId(String vlanId) {
276         this.vlanId = vlanId;
277     }
278
279     public String getVlanPriority() {
280         return vlanPriority;
281     }
282
283     public void setVlanPriority(String vlanPriority) {
284         this.vlanPriority = vlanPriority;
285     }
286
287     public String getEtherType() {
288         return etherType;
289     }
290
291     public void setEtherType(String etherType) {
292         this.etherType = etherType;
293     }
294
295     public String getSrcMac() {
296         return dlSrc;
297     }
298
299     public void setSrcMac(String srcMac) {
300         this.dlSrc = srcMac;
301     }
302
303     public String getDstMac() {
304         return dlDst;
305     }
306
307     public void setDstMac(String dstMac) {
308         this.dlDst = dstMac;
309     }
310
311     public String getProtocol() {
312         return protocol;
313     }
314
315     public void setProtocol(String protocol) {
316         this.protocol = protocol;
317     }
318
319     public String getTosBits() {
320         return tosBits;
321     }
322
323     public void setTosBits(String tos_bits) {
324         this.tosBits = tos_bits;
325     }
326
327     public String getSrcIp() {
328         return nwSrc;
329     }
330
331     public void setSrcIp(String src_ip) {
332         this.nwSrc = src_ip;
333     }
334
335     public String getDstIp() {
336         return nwDst;
337     }
338
339     public void setDstIp(String dst_ip) {
340         this.nwDst = dst_ip;
341     }
342
343     public String getSrcPort() {
344         return tpSrc;
345     }
346
347     public void setSrcPort(String src_port) {
348         this.tpSrc = src_port;
349     }
350
351     public String getDstPort() {
352         return tpDst;
353     }
354
355     public void setDstPort(String dst_port) {
356         this.tpDst = dst_port;
357     }
358
359     public String getIdleTimeout() {
360         return idleTimeout;
361     }
362
363     public void setIdleTimeout(String idleTimeout) {
364         this.idleTimeout = idleTimeout;
365     }
366
367     public String getHardTimeout() {
368         return hardTimeout;
369     }
370
371     public void setHardTimeout(String hardTimeout) {
372         this.hardTimeout = hardTimeout;
373     }
374
375     public boolean isIPv6() {
376         return NetUtils.isIPv6AddressValid(this.getSrcIp()) || NetUtils.isIPv6AddressValid(this.getDstIp());
377     }
378
379     public List<String> getActions() {
380         return actions;
381     }
382
383     public void setActions(List<String> actions) {
384         this.actions = actions;
385     }
386
387     public boolean isPortGroupEnabled() {
388         return (portGroup != null);
389     }
390
391     public boolean isDynamic() {
392         return dynamic;
393     }
394
395     public void setDynamic(boolean dynamic) {
396         this.dynamic = dynamic;
397     }
398
399     public String getStatus() {
400         return status;
401     }
402
403     public void setStatus(String status) {
404         this.status = status;
405     }
406
407     public boolean isStatusSuccessful() {
408         return status.equals(StatusCode.SUCCESS.toString());
409     }
410
411     @Override
412     public int hashCode() {
413         final int prime = 31;
414         int result = 1;
415         result = prime * result + ((actions == null) ? 0 : actions.hashCode());
416         result = prime * result + ((cookie == null) ? 0 : cookie.hashCode());
417         result = prime * result + ((dlDst == null) ? 0 : dlDst.hashCode());
418         result = prime * result + ((dlSrc == null) ? 0 : dlSrc.hashCode());
419         result = prime * result + (dynamic ? 1231 : 1237);
420         result = prime * result + ((etherType == null) ? 0 : etherType.hashCode());
421         result = prime * result + ((ingressPort == null) ? 0 : ingressPort.hashCode());
422         result = prime * result + ((name == null) ? 0 : name.hashCode());
423         result = prime * result + ((nwDst == null) ? 0 : nwDst.hashCode());
424         result = prime * result + ((nwSrc == null) ? 0 : nwSrc.hashCode());
425         result = prime * result + ((portGroup == null) ? 0 : portGroup.hashCode());
426         result = prime * result + ((priority == null) ? 0 : priority.hashCode());
427         result = prime * result + ((protocol == null) ? 0 : protocol.hashCode());
428         result = prime * result + ((node == null) ? 0 : node.hashCode());
429         result = prime * result + ((tosBits == null) ? 0 : tosBits.hashCode());
430         result = prime * result + ((tpDst == null) ? 0 : tpDst.hashCode());
431         result = prime * result + ((tpSrc == null) ? 0 : tpSrc.hashCode());
432         result = prime * result + ((vlanId == null) ? 0 : vlanId.hashCode());
433         result = prime * result + ((vlanPriority == null) ? 0 : vlanPriority.hashCode());
434         result = prime * result + ((idleTimeout == null) ? 0 : idleTimeout.hashCode());
435         result = prime * result + ((hardTimeout == null) ? 0 : hardTimeout.hashCode());
436         return result;
437     }
438
439     @Override
440     public boolean equals(Object obj) {
441         if (this == obj) {
442             return true;
443         }
444         if (obj == null) {
445             return false;
446         }
447         if (getClass() != obj.getClass()) {
448             return false;
449         }
450         FlowConfig other = (FlowConfig) obj;
451         if (actions == null) {
452             if (other.actions != null) {
453                 return false;
454             }
455         } else if (!actions.equals(other.actions)) {
456             return false;
457         }
458         if (cookie == null) {
459             if (other.cookie != null) {
460                 return false;
461             }
462         } else if (!cookie.equals(other.cookie)) {
463             return false;
464         }
465         if (dlDst == null) {
466             if (other.dlDst != null) {
467                 return false;
468             }
469         } else if (!dlDst.equals(other.dlDst)) {
470             return false;
471         }
472         if (dlSrc == null) {
473             if (other.dlSrc != null) {
474                 return false;
475             }
476         } else if (!dlSrc.equals(other.dlSrc)) {
477             return false;
478         }
479         if (dynamic != other.dynamic) {
480             return false;
481         }
482         if (etherType == null) {
483             if (other.etherType != null) {
484                 return false;
485             }
486         } else if (!etherType.equals(other.etherType)) {
487             return false;
488         }
489         if (ingressPort == null) {
490             if (other.ingressPort != null) {
491                 return false;
492             }
493         } else if (!ingressPort.equals(other.ingressPort)) {
494             return false;
495         }
496         if (name == null) {
497             if (other.name != null) {
498                 return false;
499             }
500         } else if (!name.equals(other.name)) {
501             return false;
502         }
503         if (nwDst == null) {
504             if (other.nwDst != null) {
505                 return false;
506             }
507         } else if (!nwDst.equals(other.nwDst)) {
508             return false;
509         }
510         if (nwSrc == null) {
511             if (other.nwSrc != null) {
512                 return false;
513             }
514         } else if (!nwSrc.equals(other.nwSrc)) {
515             return false;
516         }
517         if (portGroup == null) {
518             if (other.portGroup != null) {
519                 return false;
520             }
521         } else if (!portGroup.equals(other.portGroup)) {
522             return false;
523         }
524         if (priority == null) {
525             if (other.priority != null) {
526                 return false;
527             }
528         } else if (!priority.equals(other.priority)) {
529             return false;
530         }
531         if (protocol == null) {
532             if (other.protocol != null) {
533                 return false;
534             }
535         } else if (!protocol.equals(other.protocol)) {
536             return false;
537         }
538         if (node == null) {
539             if (other.node != null) {
540                 return false;
541             }
542         } else if (!node.equals(other.node)) {
543             return false;
544         }
545         if (tosBits == null) {
546             if (other.tosBits != null) {
547                 return false;
548             }
549         } else if (!tosBits.equals(other.tosBits)) {
550             return false;
551         }
552         if (tpDst == null) {
553             if (other.tpDst != null) {
554                 return false;
555             }
556         } else if (!tpDst.equals(other.tpDst)) {
557             return false;
558         }
559         if (tpSrc == null) {
560             if (other.tpSrc != null) {
561                 return false;
562             }
563         } else if (!tpSrc.equals(other.tpSrc)) {
564             return false;
565         }
566         if (vlanId == null) {
567             if (other.vlanId != null) {
568                 return false;
569             }
570         } else if (!vlanId.equals(other.vlanId)) {
571             return false;
572         }
573         if (vlanPriority == null) {
574             if (other.vlanPriority != null) {
575                 return false;
576             }
577         } else if (!vlanPriority.equals(other.vlanPriority)) {
578             return false;
579         }
580         if (idleTimeout == null) {
581             if (other.idleTimeout != null) {
582                 return false;
583             }
584         } else if (!idleTimeout.equals(other.idleTimeout)) {
585             return false;
586         }
587         if (hardTimeout == null) {
588             if (other.hardTimeout != null) {
589                 return false;
590             }
591         } else if (!hardTimeout.equals(other.hardTimeout)) {
592             return false;
593         }
594         return true;
595     }
596
597     public boolean isL2AddressValid(String mac) {
598         if (mac == null) {
599             return false;
600         }
601
602         Pattern macPattern = Pattern.compile("([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}");
603         Matcher mm = macPattern.matcher(mac);
604         if (!mm.matches()) {
605             log.debug("Ethernet address {} is not valid. Example: 00:05:b9:7c:81:5f", mac);
606             return false;
607         }
608         return true;
609     }
610
611     public boolean isPortValid(Switch sw, String port) {
612         if (sw == null) {
613             log.debug("switch info is not available. Skip checking if port is part of a switch or not.");
614             return true;
615         }
616         NodeConnector nc = NodeConnectorCreator.createNodeConnector(port, sw.getNode());
617         return sw.getNodeConnectors().contains(nc);
618     }
619
620     public boolean isVlanIdValid(String vlanId) {
621         int vlan = Integer.decode(vlanId);
622         return ((vlan >= 0) && (vlan < 4096));
623     }
624
625     public boolean isVlanPriorityValid(String vlanPriority) {
626         int pri = Integer.decode(vlanPriority);
627         return ((pri >= 0) && (pri < 8));
628     }
629
630     public boolean isTOSBitsValid(String tosBits) {
631         int tos = Integer.decode(tosBits);
632         return ((tos >= 0) && (tos < 64));
633     }
634
635     public boolean isTpPortValid(String tpPort) {
636         int port = Integer.decode(tpPort);
637         return ((port >= 0) && (port <= 0xffff));
638     }
639
640     public boolean isTimeoutValid(String timeout) {
641         int to = Integer.decode(timeout);
642         return ((to >= 0) && (to <= 0xffff));
643     }
644
645     public boolean isProtocolValid(String protocol) {
646         IPProtocols proto = IPProtocols.fromString(protocol);
647         return (proto != null);
648     }
649
650     private Status conflictWithContainerFlow(IContainer container) {
651         // Return true if it's default container
652         if (container.getName().equals(GlobalConstants.DEFAULT.toString())) {
653             return new Status(StatusCode.SUCCESS);
654         }
655
656         // No container flow = no conflict
657         List<ContainerFlow> cFlowList = container.getContainerFlows();
658         if (((cFlowList == null)) || cFlowList.isEmpty()) {
659             return new Status(StatusCode.SUCCESS);
660         }
661
662         // Check against each container's flow
663         Flow flow = this.getFlow();
664
665         // Configuration is rejected if it conflicts with _all_ the container
666         // flows
667         for (ContainerFlow cFlow : cFlowList) {
668             if (cFlow.allowsFlow(flow)) {
669                 log.trace("Config is congruent with at least one container flow");
670                 return new Status(StatusCode.SUCCESS);
671             }
672         }
673         String msg = "Flow Config conflicts with all existing container flows";
674         log.trace(msg);
675
676         return new Status(StatusCode.BADREQUEST, msg);
677     }
678
679     public Status validate(IContainer container) {
680         EtherIPType etype = EtherIPType.ANY;
681         EtherIPType ipsrctype = EtherIPType.ANY;
682         EtherIPType ipdsttype = EtherIPType.ANY;
683
684         String containerName = (container == null) ? GlobalConstants.DEFAULT.toString() : container.getName();
685         ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName,
686                 this);
687
688         Switch sw = null;
689         try {
690             if (name == null || name.trim().isEmpty() || !name.matches(FlowConfig.NAMEREGEX)) {
691                 return new Status(StatusCode.BADREQUEST, "Invalid name");
692             }
693
694             if (node == null) {
695                 return new Status(StatusCode.BADREQUEST, "Node is null");
696             }
697
698             if (switchManager != null) {
699                 for (Switch device : switchManager.getNetworkDevices()) {
700                     if (device.getNode().equals(node)) {
701                         sw = device;
702                         break;
703                     }
704                 }
705                 if (sw == null) {
706                     return new Status(StatusCode.BADREQUEST, String.format("Node %s not found", node));
707                 }
708             } else {
709                 log.debug("switchmanager is not set yet");
710             }
711
712             if (priority != null) {
713                 if (Integer.decode(priority) < 0 || (Integer.decode(priority) > 65535)) {
714                     return new Status(StatusCode.BADREQUEST, String.format("priority %s is not in the range 0 - 65535",
715                             priority));
716                 }
717             }
718
719             // make sure it's a valid number
720             if (cookie != null) {
721                 Long.decode(cookie);
722             }
723
724             if (ingressPort != null) {
725                 if (!isPortValid(sw, ingressPort)) {
726                     String msg = String.format("Ingress port %s is not valid for the Switch", ingressPort);
727                     if (!containerName.equals(GlobalConstants.DEFAULT.toString())) {
728                         msg += " in Container " + containerName;
729                     }
730                     return new Status(StatusCode.BADREQUEST, msg);
731                 }
732             }
733
734             if ((vlanId != null) && !isVlanIdValid(vlanId)) {
735                 return new Status(StatusCode.BADREQUEST, String.format("Vlan ID %s is not in the range 0 - 4095",
736                         vlanId));
737             }
738
739             if ((vlanPriority != null) && !isVlanPriorityValid(vlanPriority)) {
740                 return new Status(StatusCode.BADREQUEST, String.format("Vlan priority %s is not in the range 0 - 7",
741                         vlanPriority));
742             }
743             if (etherType != null) {
744                 int type = Integer.decode(etherType);
745                 if ((type < 0) || (type > 0xffff)) {
746                     return new Status(StatusCode.BADREQUEST, String.format("Ethernet type %s is not valid", etherType));
747                 } else {
748                     if (type == 0x800) {
749                         etype = EtherIPType.V4;
750                     } else if (type == 0x86dd) {
751                         etype = EtherIPType.V6;
752                     }
753                 }
754             }
755
756             if ((protocol != null) && !isProtocolValid(protocol)) {
757                 return new Status(StatusCode.BADREQUEST, String.format("Protocol %s is not valid", protocol));
758             }
759
760             if ((tosBits != null) && !isTOSBitsValid(tosBits)) {
761                 return new Status(StatusCode.BADREQUEST, String.format("IP ToS bits %s is not in the range 0 - 63",
762                         tosBits));
763             }
764
765             if ((tpSrc != null) && !isTpPortValid(tpSrc)) {
766                 return new Status(StatusCode.BADREQUEST, String.format("Transport source port %s is not valid", tpSrc));
767             }
768
769             if ((tpDst != null) && !isTpPortValid(tpDst)) {
770                 return new Status(StatusCode.BADREQUEST, String.format("Transport destination port %s is not valid",
771                         tpDst));
772             }
773
774             if ((dlSrc != null) && !isL2AddressValid(dlSrc)) {
775                 return new Status(StatusCode.BADREQUEST, String.format(
776                         "Ethernet source address %s is not valid. Example: 00:05:b9:7c:81:5f", dlSrc));
777             }
778
779             if ((dlDst != null) && !isL2AddressValid(dlDst)) {
780                 return new Status(StatusCode.BADREQUEST, String.format(
781                         "Ethernet destination address %s is not valid. Example: 00:05:b9:7c:81:5f", dlDst));
782             }
783
784             if (nwSrc != null) {
785                 if (NetUtils.isIPv4AddressValid(nwSrc)) {
786                     ipsrctype = EtherIPType.V4;
787                 } else if (NetUtils.isIPv6AddressValid(nwSrc)) {
788                     ipsrctype = EtherIPType.V6;
789                 } else {
790                     return new Status(StatusCode.BADREQUEST, String.format("IP source address %s is not valid", nwSrc));
791                 }
792             }
793
794             if (nwDst != null) {
795                 if (NetUtils.isIPv4AddressValid(nwDst)) {
796                     ipdsttype = EtherIPType.V4;
797                 } else if (NetUtils.isIPv6AddressValid(nwDst)) {
798                     ipdsttype = EtherIPType.V6;
799                 } else {
800                     return new Status(StatusCode.BADREQUEST, String.format("IP destination address %s is not valid",
801                             nwDst));
802                 }
803             }
804
805             if (etype != EtherIPType.ANY) {
806                 if ((ipsrctype != EtherIPType.ANY) && (ipsrctype != etype)) {
807                     return new Status(StatusCode.BADREQUEST, String.format("Type mismatch between Ethernet & Src IP"));
808                 }
809                 if ((ipdsttype != EtherIPType.ANY) && (ipdsttype != etype)) {
810                     return new Status(StatusCode.BADREQUEST, String.format("Type mismatch between Ethernet & Dst IP"));
811                 }
812             }
813             if (ipsrctype != ipdsttype) {
814                 if (!((ipsrctype == EtherIPType.ANY) || (ipdsttype == EtherIPType.ANY))) {
815                     return new Status(StatusCode.BADREQUEST, String.format("IP Src Dest Type mismatch"));
816                 }
817             }
818
819             if ((idleTimeout != null) && !isTimeoutValid(idleTimeout)) {
820                 return new Status(StatusCode.BADREQUEST, String.format("Idle Timeout value %s is not valid",
821                         idleTimeout));
822             }
823
824             if ((hardTimeout != null) && !isTimeoutValid(hardTimeout)) {
825                 return new Status(StatusCode.BADREQUEST, String.format("Hard Timeout value %s is not valid",
826                         hardTimeout));
827             }
828
829             Matcher sstr;
830             if (actions == null || actions.isEmpty()) {
831                 return new Status(StatusCode.BADREQUEST, "Actions value is null or empty");
832             }
833             for (String actiongrp : actions) {
834                 // check output ports
835                 sstr = Pattern.compile("OUTPUT=(.*)").matcher(actiongrp);
836                 if (sstr.matches()) {
837                     for (String t : sstr.group(1).split(",")) {
838                         if (t != null) {
839                             if (!isPortValid(sw, t)) {
840                                 String msg = String.format("Output port %s is not valid for this switch", t);
841                                 if (!containerName.equals(GlobalConstants.DEFAULT.toString())) {
842                                     msg += " in Container " + containerName;
843                                 }
844                                 return new Status(StatusCode.BADREQUEST, msg);
845                             }
846                         }
847                     }
848                     continue;
849                 }
850                 // check enqueue
851                 sstr = Pattern.compile("ENQUEUE=(.*)").matcher(actiongrp);
852                 if (sstr.matches()) {
853                     for (String t : sstr.group(1).split(",")) {
854                         if (t != null) {
855                             String port = t.split(":")[0];
856                             if (!isPortValid(sw, port)) {
857                                 String msg = String.format("Output port %d is not valid for this switch", port);
858                                 if (!containerName.equals(GlobalConstants.DEFAULT.toString())) {
859                                     msg += " in Container " + containerName;
860                                 }
861                                 return new Status(StatusCode.BADREQUEST, msg);
862                             }
863                         }
864                     }
865                     continue;
866                 }
867                 // Check src IP
868                 sstr = Pattern.compile(ActionType.FLOOD.toString()).matcher(actiongrp);
869                 if (sstr.matches()) {
870                     if (!containerName.equals(GlobalConstants.DEFAULT.toString())) {
871                         return new Status(StatusCode.BADREQUEST, String.format(
872                                 "flood is not allowed in container %s", containerName));
873                     }
874                     continue;
875                 }
876                 // Check src IP
877                 sstr = Pattern.compile(ActionType.SET_NW_SRC.toString() + "=(.*)").matcher(actiongrp);
878                 if (sstr.matches()) {
879                     if (!NetUtils.isIPv4AddressValid(sstr.group(1))) {
880                         return new Status(StatusCode.BADREQUEST, String.format("IP source address %s is not valid",
881                                 sstr.group(1)));
882                     }
883                     continue;
884                 }
885                 // Check dst IP
886                 sstr = Pattern.compile(ActionType.SET_NW_DST.toString() + "=(.*)").matcher(actiongrp);
887                 if (sstr.matches()) {
888                     if (!NetUtils.isIPv4AddressValid(sstr.group(1))) {
889                         return new Status(StatusCode.BADREQUEST, String.format(
890                                 "IP destination address %s is not valid", sstr.group(1)));
891                     }
892                     continue;
893                 }
894
895                 sstr = Pattern.compile(ActionType.SET_VLAN_ID.toString() + "=(.*)").matcher(actiongrp);
896                 if (sstr.matches()) {
897                     if ((sstr.group(1) != null) && !isVlanIdValid(sstr.group(1))) {
898                         return new Status(StatusCode.BADREQUEST, String.format(
899                                 "Vlan ID %s is not in the range 0 - 4095", sstr.group(1)));
900                     }
901                     continue;
902                 }
903
904                 sstr = Pattern.compile(ActionType.SET_VLAN_PCP.toString() + "=(.*)").matcher(actiongrp);
905                 if (sstr.matches()) {
906                     if ((sstr.group(1) != null) && !isVlanPriorityValid(sstr.group(1))) {
907                         return new Status(StatusCode.BADREQUEST, String.format(
908                                 "Vlan priority %s is not in the range 0 - 7", sstr.group(1)));
909                     }
910                     continue;
911                 }
912
913                 sstr = Pattern.compile(ActionType.SET_DL_SRC.toString() + "=(.*)").matcher(actiongrp);
914                 if (sstr.matches()) {
915                     if ((sstr.group(1) != null) && !isL2AddressValid(sstr.group(1))) {
916                         return new Status(StatusCode.BADREQUEST, String.format(
917                                 "Ethernet source address %s is not valid. Example: 00:05:b9:7c:81:5f",
918                                 sstr.group(1)));
919                     }
920                     continue;
921                 }
922                 sstr = Pattern.compile(ActionType.SET_DL_DST.toString() + "=(.*)").matcher(actiongrp);
923                 if (sstr.matches()) {
924                     if ((sstr.group(1) != null) && !isL2AddressValid(sstr.group(1))) {
925                         return new Status(StatusCode.BADREQUEST, String.format(
926                                 "Ethernet destination address %s is not valid. Example: 00:05:b9:7c:81:5f",
927                                 sstr.group(1)));
928                     }
929                     continue;
930                 }
931
932                 sstr = Pattern.compile(ActionType.SET_NW_TOS.toString() + "=(.*)").matcher(actiongrp);
933                 if (sstr.matches()) {
934                     if ((sstr.group(1) != null) && !isTOSBitsValid(sstr.group(1))) {
935                         return new Status(StatusCode.BADREQUEST, String.format(
936                                 "IP ToS bits %s is not in the range 0 - 63", sstr.group(1)));
937                     }
938                     continue;
939                 }
940
941                 sstr = Pattern.compile(ActionType.SET_TP_SRC.toString() + "=(.*)").matcher(actiongrp);
942                 if (sstr.matches()) {
943                     if ((sstr.group(1) != null) && !isTpPortValid(sstr.group(1))) {
944                         return new Status(StatusCode.BADREQUEST, String.format(
945                                 "Transport source port %s is not valid", sstr.group(1)));
946                     }
947                     continue;
948                 }
949
950                 sstr = Pattern.compile(ActionType.SET_TP_DST.toString() + "=(.*)").matcher(actiongrp);
951                 if (sstr.matches()) {
952                     if ((sstr.group(1) != null) && !isTpPortValid(sstr.group(1))) {
953                         return new Status(StatusCode.BADREQUEST, String.format(
954                                 "Transport destination port %s is not valid", sstr.group(1)));
955                     }
956                     continue;
957                 }
958                 sstr = Pattern.compile(ActionType.SET_NEXT_HOP.toString() + "=(.*)").matcher(actiongrp);
959                 if (sstr.matches()) {
960                     if (!NetUtils.isIPAddressValid(sstr.group(1))) {
961                         return new Status(StatusCode.BADREQUEST, String.format(
962                                 "IP destination address %s is not valid", sstr.group(1)));
963                     }
964                     continue;
965                 }
966             }
967             // Check against the container flow
968             Status status;
969             if (!containerName.equals(GlobalConstants.DEFAULT.toString()) && !(status = conflictWithContainerFlow(container)).isSuccess()) {
970                 return status;
971             }
972         } catch (NumberFormatException e) {
973             return new Status(StatusCode.BADREQUEST, String.format("Invalid number format %s", e.getMessage()));
974         }
975
976         return new Status(StatusCode.SUCCESS);
977     }
978
979     public FlowEntry getFlowEntry() {
980         String group = this.isInternalFlow() ? FlowConfig.INTERNALSTATICFLOWGROUP : FlowConfig.STATICFLOWGROUP;
981         return new FlowEntry(group, this.name, this.getFlow(), this.getNode());
982     }
983
984     public Flow getFlow() {
985         Match match = new Match();
986
987         if (this.ingressPort != null) {
988             match.setField(MatchType.IN_PORT,
989                     NodeConnector.fromString(String.format("%s|%s@%s", node.getType(), ingressPort, node.toString())));
990         }
991         if (this.dlSrc != null) {
992             match.setField(MatchType.DL_SRC, HexEncode.bytesFromHexString(this.dlSrc));
993         }
994         if (this.dlDst != null) {
995             match.setField(MatchType.DL_DST, HexEncode.bytesFromHexString(this.dlDst));
996         }
997         if (this.etherType != null) {
998             match.setField(MatchType.DL_TYPE, Integer.decode(etherType).shortValue());
999         }
1000         if (this.vlanId != null) {
1001             match.setField(MatchType.DL_VLAN, Short.parseShort(this.vlanId));
1002         }
1003         if (this.vlanPriority != null) {
1004             match.setField(MatchType.DL_VLAN_PR, Byte.parseByte(this.vlanPriority));
1005         }
1006         if (this.nwSrc != null) {
1007             String parts[] = this.nwSrc.split("/");
1008             InetAddress ip = NetUtils.parseInetAddress(parts[0]);
1009             InetAddress mask = null;
1010             int maskLen = 0;
1011             if (parts.length > 1) {
1012                 maskLen = Integer.parseInt(parts[1]);
1013             } else {
1014                 maskLen = (ip instanceof Inet6Address) ? 128 : 32;
1015             }
1016             mask = NetUtils.getInetNetworkMask(maskLen, ip instanceof Inet6Address);
1017             match.setField(MatchType.NW_SRC, ip, mask);
1018         }
1019         if (this.nwDst != null) {
1020             String parts[] = this.nwDst.split("/");
1021             InetAddress ip = NetUtils.parseInetAddress(parts[0]);
1022             InetAddress mask = null;
1023             int maskLen = 0;
1024             if (parts.length > 1) {
1025                 maskLen = Integer.parseInt(parts[1]);
1026             } else {
1027                 maskLen = (ip instanceof Inet6Address) ? 128 : 32;
1028             }
1029             mask = NetUtils.getInetNetworkMask(maskLen, ip instanceof Inet6Address);
1030             match.setField(MatchType.NW_DST, ip, mask);
1031         }
1032         if (IPProtocols.fromString(this.protocol) != IPProtocols.ANY) {
1033             match.setField(MatchType.NW_PROTO, IPProtocols.getProtocolNumberByte(this.protocol));
1034         }
1035         if (this.tosBits != null) {
1036             match.setField(MatchType.NW_TOS, Byte.parseByte(this.tosBits));
1037         }
1038         if (this.tpSrc != null) {
1039             match.setField(MatchType.TP_SRC, Integer.valueOf(this.tpSrc).shortValue());
1040         }
1041         if (this.tpDst != null) {
1042             match.setField(MatchType.TP_DST, Integer.valueOf(this.tpDst).shortValue());
1043         }
1044
1045         Flow flow = new Flow(match, getActionList());
1046
1047         if (this.cookie != null) {
1048             flow.setId(Long.parseLong(cookie));
1049         }
1050         if (this.hardTimeout != null) {
1051             flow.setHardTimeout(Short.parseShort(this.hardTimeout));
1052         }
1053         if (this.idleTimeout != null) {
1054             flow.setIdleTimeout(Short.parseShort(idleTimeout));
1055         }
1056         if (this.priority != null) {
1057             flow.setPriority(Integer.decode(this.priority).shortValue());
1058         }
1059
1060
1061         return flow;
1062     }
1063
1064     public boolean isByNameAndNodeIdEqual(FlowConfig that) {
1065         return (this.name.equals(that.name) && this.node.equals(that.node));
1066     }
1067
1068     public boolean isByNameAndNodeIdEqual(String name, Node node) {
1069         return (this.name.equals(name) && this.node.equals(node));
1070     }
1071
1072     public boolean onNode(Node node) {
1073         return this.node.equals(node);
1074     }
1075
1076     public void toggleInstallation() {
1077         installInHw = (installInHw == null) ? Boolean.toString(false) : Boolean.toString(!Boolean.valueOf(installInHw));
1078     }
1079
1080     /*
1081      * Parses the actions string and return the List of SAL Action No syntax
1082      * check run, as this function will be called when the config validation
1083      * check has already been performed
1084      */
1085     private List<Action> getActionList() {
1086         List<Action> actionList = new ArrayList<Action>();
1087
1088         if (actions != null) {
1089             Matcher sstr;
1090             for (String actiongrp : actions) {
1091                 sstr = Pattern.compile(ActionType.OUTPUT + "=(.*)").matcher(actiongrp);
1092                 if (sstr.matches()) {
1093                     for (String t : sstr.group(1).split(",")) {
1094                         if (t != null) {
1095                             String nc = String.format("%s|%s@%s", node.getType(), t, node.toString());
1096                             actionList.add(new Output(NodeConnector.fromString(nc)));
1097                         }
1098                     }
1099                     continue;
1100                 }
1101
1102                 sstr = Pattern.compile(ActionType.ENQUEUE + "=(.*)").matcher(actiongrp);
1103                 if (sstr.matches()) {
1104                     for (String t : sstr.group(1).split(",")) {
1105                         if (t != null) {
1106                             String parts[] = t.split(":");
1107                             String nc = String.format("%s|%s@%s", node.getType(), parts[0], node.toString());
1108                             if (parts.length == 1) {
1109                                 actionList.add(new Enqueue(NodeConnector.fromString(nc)));
1110                             } else {
1111                                 actionList
1112                                 .add(new Enqueue(NodeConnector.fromString(nc), Integer.parseInt(parts[1])));
1113                             }
1114                         }
1115                     }
1116                     continue;
1117                 }
1118
1119                 sstr = Pattern.compile(ActionType.DROP.toString()).matcher(actiongrp);
1120                 if (sstr.matches()) {
1121                     actionList.add(new Drop());
1122                     continue;
1123                 }
1124
1125                 sstr = Pattern.compile(ActionType.LOOPBACK.toString()).matcher(actiongrp);
1126                 if (sstr.matches()) {
1127                     actionList.add(new Loopback());
1128                     continue;
1129                 }
1130
1131                 sstr = Pattern.compile(ActionType.FLOOD.toString()).matcher(actiongrp);
1132                 if (sstr.matches()) {
1133                     actionList.add(new Flood());
1134                     continue;
1135                 }
1136
1137                 sstr = Pattern.compile(ActionType.SW_PATH.toString()).matcher(actiongrp);
1138                 if (sstr.matches()) {
1139                     actionList.add(new SwPath());
1140                     continue;
1141                 }
1142
1143                 sstr = Pattern.compile(ActionType.HW_PATH.toString()).matcher(actiongrp);
1144                 if (sstr.matches()) {
1145                     actionList.add(new HwPath());
1146                     continue;
1147                 }
1148
1149                 sstr = Pattern.compile(ActionType.CONTROLLER.toString()).matcher(actiongrp);
1150                 if (sstr.matches()) {
1151                     actionList.add(new Controller());
1152                     continue;
1153                 }
1154
1155                 sstr = Pattern.compile(ActionType.SET_VLAN_ID.toString() + "=(.*)").matcher(actiongrp);
1156                 if (sstr.matches()) {
1157                     actionList.add(new SetVlanId(Short.parseShort(sstr.group(1))));
1158                     continue;
1159                 }
1160
1161                 sstr = Pattern.compile(ActionType.SET_VLAN_PCP.toString() + "=(.*)").matcher(actiongrp);
1162                 if (sstr.matches()) {
1163                     actionList.add(new SetVlanPcp(Byte.parseByte(sstr.group(1))));
1164                     continue;
1165                 }
1166
1167                 sstr = Pattern.compile(ActionType.POP_VLAN.toString()).matcher(actiongrp);
1168                 if (sstr.matches()) {
1169                     actionList.add(new PopVlan());
1170                     continue;
1171                 }
1172
1173                 sstr = Pattern.compile(ActionType.SET_DL_SRC.toString() + "=(.*)").matcher(actiongrp);
1174                 if (sstr.matches()) {
1175                     actionList.add(new SetDlSrc(HexEncode.bytesFromHexString(sstr.group(1))));
1176                     continue;
1177                 }
1178
1179                 sstr = Pattern.compile(ActionType.SET_DL_DST.toString() + "=(.*)").matcher(actiongrp);
1180                 if (sstr.matches()) {
1181                     actionList.add(new SetDlDst(HexEncode.bytesFromHexString(sstr.group(1))));
1182                     continue;
1183                 }
1184                 sstr = Pattern.compile(ActionType.SET_NW_SRC.toString() + "=(.*)").matcher(actiongrp);
1185                 if (sstr.matches()) {
1186                     actionList.add(new SetNwSrc(NetUtils.parseInetAddress(sstr.group(1))));
1187                     continue;
1188                 }
1189                 sstr = Pattern.compile(ActionType.SET_NW_DST.toString() + "=(.*)").matcher(actiongrp);
1190                 if (sstr.matches()) {
1191                     actionList.add(new SetNwDst(NetUtils.parseInetAddress(sstr.group(1))));
1192                     continue;
1193                 }
1194
1195                 sstr = Pattern.compile(ActionType.SET_NW_TOS.toString() + "=(.*)").matcher(actiongrp);
1196                 if (sstr.matches()) {
1197                     actionList.add(new SetNwTos(Byte.parseByte(sstr.group(1))));
1198                     continue;
1199                 }
1200
1201                 sstr = Pattern.compile(ActionType.SET_TP_SRC.toString() + "=(.*)").matcher(actiongrp);
1202                 if (sstr.matches()) {
1203                     actionList.add(new SetTpSrc(Integer.valueOf(sstr.group(1))));
1204                     continue;
1205                 }
1206
1207                 sstr = Pattern.compile(ActionType.SET_TP_DST.toString() + "=(.*)").matcher(actiongrp);
1208                 if (sstr.matches()) {
1209                     actionList.add(new SetTpDst(Integer.valueOf(sstr.group(1))));
1210                     continue;
1211                 }
1212
1213                 sstr = Pattern.compile(ActionType.SET_NEXT_HOP.toString() + "=(.*)").matcher(actiongrp);
1214                 if (sstr.matches()) {
1215                     actionList.add(new SetNextHop(NetUtils.parseInetAddress(sstr.group(1))));
1216                     continue;
1217                 }
1218             }
1219         }
1220         return actionList;
1221     }
1222
1223 }