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