Fix for validity check of Action field in FlowConfig
[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.Set;
17 import java.util.regex.Matcher;
18 import java.util.regex.Pattern;
19
20 import javax.xml.bind.annotation.XmlAccessType;
21 import javax.xml.bind.annotation.XmlAccessorType;
22 import javax.xml.bind.annotation.XmlElement;
23 import javax.xml.bind.annotation.XmlRootElement;
24
25 import org.opendaylight.controller.sal.action.Action;
26 import org.opendaylight.controller.sal.action.ActionType;
27 import org.opendaylight.controller.sal.action.Controller;
28 import org.opendaylight.controller.sal.action.Drop;
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, Short port) {
613         if (port < 1) {
614             log.debug("port {} is not valid", port);
615             return false;
616         }
617
618         if (sw == null) {
619             log.debug("switch info is not available. Skip checking if port is part of a switch or not.");
620             return true;
621         }
622
623         Set<NodeConnector> nodeConnectorSet = sw.getNodeConnectors();
624         for (NodeConnector nodeConnector : nodeConnectorSet) {
625             if (((Short) nodeConnector.getID()).equals(port)) {
626                 return true;
627             }
628         }
629         log.debug("port {} is not a valid port of node {}", port, sw.getNode());
630         return false;
631     }
632
633     public boolean isVlanIdValid(String vlanId) {
634         int vlan = Integer.decode(vlanId);
635         return ((vlan >= 0) && (vlan < 4096));
636     }
637
638     public boolean isVlanPriorityValid(String vlanPriority) {
639         int pri = Integer.decode(vlanPriority);
640         return ((pri >= 0) && (pri < 8));
641     }
642
643     public boolean isTOSBitsValid(String tosBits) {
644         int tos = Integer.decode(tosBits);
645         return ((tos >= 0) && (tos < 64));
646     }
647
648     public boolean isTpPortValid(String tpPort) {
649         int port = Integer.decode(tpPort);
650         return ((port >= 0) && (port <= 0xffff));
651     }
652
653     public boolean isTimeoutValid(String timeout) {
654         int to = Integer.decode(timeout);
655         return ((to >= 0) && (to <= 0xffff));
656     }
657
658     public boolean isProtocolValid(String protocol) {
659         IPProtocols proto = IPProtocols.fromString(protocol);
660         return (proto != null);
661     }
662
663     private Status conflictWithContainerFlow(IContainer container) {
664         // Return true if it's default container
665         if (container.getName().equals(GlobalConstants.DEFAULT.toString())) {
666             return new Status(StatusCode.SUCCESS);
667         }
668
669         // No container flow = no conflict
670         List<ContainerFlow> cFlowList = container.getContainerFlows();
671         if (((cFlowList == null)) || cFlowList.isEmpty()) {
672             return new Status(StatusCode.SUCCESS);
673         }
674
675         // Check against each container's flow
676         Flow flow = this.getFlow();
677
678         // Configuration is rejected if it conflicts with _all_ the container
679         // flows
680         for (ContainerFlow cFlow : cFlowList) {
681             if (cFlow.allowsFlow(flow)) {
682                 log.trace("Config is congruent with at least one container flow");
683                 return new Status(StatusCode.SUCCESS);
684             }
685         }
686         String msg = "Flow Config conflicts with all existing container flows";
687         log.trace(msg);
688
689         return new Status(StatusCode.BADREQUEST, msg);
690     }
691
692     public Status validate(IContainer container) {
693         EtherIPType etype = EtherIPType.ANY;
694         EtherIPType ipsrctype = EtherIPType.ANY;
695         EtherIPType ipdsttype = EtherIPType.ANY;
696
697         String containerName = (container == null) ? GlobalConstants.DEFAULT.toString() : container.getName();
698         ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName,
699                 this);
700
701         Switch sw = null;
702         try {
703             if (name == null || name.trim().isEmpty() || !name.matches(FlowConfig.NAMEREGEX)) {
704                 return new Status(StatusCode.BADREQUEST, "Invalid name");
705             }
706
707             if (node == null) {
708                 return new Status(StatusCode.BADREQUEST, "Node is null");
709             }
710
711             if (switchManager != null) {
712                 for (Switch device : switchManager.getNetworkDevices()) {
713                     if (device.getNode().equals(node)) {
714                         sw = device;
715                         break;
716                     }
717                 }
718                 if (sw == null) {
719                     return new Status(StatusCode.BADREQUEST, String.format("Node %s not found", node));
720                 }
721             } else {
722                 log.debug("switchmanager is not set yet");
723             }
724
725             if (priority != null) {
726                 if (Integer.decode(priority) < 0 || (Integer.decode(priority) > 65535)) {
727                     return new Status(StatusCode.BADREQUEST, String.format("priority %s is not in the range 0 - 65535",
728                             priority));
729                 }
730             }
731
732             // make sure it's a valid number
733             if (cookie != null) {
734                 Long.decode(cookie);
735             }
736
737             if (ingressPort != null) {
738                 Short port = Short.decode(ingressPort);
739                 if (isPortValid(sw, port) == false) {
740                     String msg = String.format("Ingress port %d is not valid for the Switch", port);
741                     if (!containerName.equals(GlobalConstants.DEFAULT.toString())) {
742                         msg += " in Container " + containerName;
743                     }
744                     return new Status(StatusCode.BADREQUEST, msg);
745                 }
746             }
747
748             if ((vlanId != null) && !isVlanIdValid(vlanId)) {
749                 return new Status(StatusCode.BADREQUEST, String.format("Vlan ID %s is not in the range 0 - 4095",
750                         vlanId));
751             }
752
753             if ((vlanPriority != null) && !isVlanPriorityValid(vlanPriority)) {
754                 return new Status(StatusCode.BADREQUEST, String.format("Vlan priority %s is not in the range 0 - 7",
755                         vlanPriority));
756             }
757             if (etherType != null) {
758                 int type = Integer.decode(etherType);
759                 if ((type < 0) || (type > 0xffff)) {
760                     return new Status(StatusCode.BADREQUEST, String.format("Ethernet type %s is not valid", etherType));
761                 } else {
762                     if (type == 0x800) {
763                         etype = EtherIPType.V4;
764                     } else if (type == 0x86dd) {
765                         etype = EtherIPType.V6;
766                     }
767                 }
768             }
769
770             if ((protocol != null) && !isProtocolValid(protocol)) {
771                 return new Status(StatusCode.BADREQUEST, String.format("Protocol %s is not valid", protocol));
772             }
773
774             if ((tosBits != null) && !isTOSBitsValid(tosBits)) {
775                 return new Status(StatusCode.BADREQUEST, String.format("IP ToS bits %s is not in the range 0 - 63",
776                         tosBits));
777             }
778
779             if ((tpSrc != null) && !isTpPortValid(tpSrc)) {
780                 return new Status(StatusCode.BADREQUEST, String.format("Transport source port %s is not valid", tpSrc));
781             }
782
783             if ((tpDst != null) && !isTpPortValid(tpDst)) {
784                 return new Status(StatusCode.BADREQUEST, String.format("Transport destination port %s is not valid",
785                         tpDst));
786             }
787
788             if ((dlSrc != null) && !isL2AddressValid(dlSrc)) {
789                 return new Status(StatusCode.BADREQUEST, String.format(
790                         "Ethernet source address %s is not valid. Example: 00:05:b9:7c:81:5f", dlSrc));
791             }
792
793             if ((dlDst != null) && !isL2AddressValid(dlDst)) {
794                 return new Status(StatusCode.BADREQUEST, String.format(
795                         "Ethernet destination address %s is not valid. Example: 00:05:b9:7c:81:5f", dlDst));
796             }
797
798             if (nwSrc != null) {
799                 if (NetUtils.isIPv4AddressValid(nwSrc)) {
800                     ipsrctype = EtherIPType.V4;
801                 } else if (NetUtils.isIPv6AddressValid(nwSrc)) {
802                     ipsrctype = EtherIPType.V6;
803                 } else {
804                     return new Status(StatusCode.BADREQUEST, String.format("IP source address %s is not valid", nwSrc));
805                 }
806             }
807
808             if (nwDst != null) {
809                 if (NetUtils.isIPv4AddressValid(nwDst)) {
810                     ipdsttype = EtherIPType.V4;
811                 } else if (NetUtils.isIPv6AddressValid(nwDst)) {
812                     ipdsttype = EtherIPType.V6;
813                 } else {
814                     return new Status(StatusCode.BADREQUEST, String.format("IP destination address %s is not valid",
815                             nwDst));
816                 }
817             }
818
819             if (etype != EtherIPType.ANY) {
820                 if ((ipsrctype != EtherIPType.ANY) && (ipsrctype != etype)) {
821                     return new Status(StatusCode.BADREQUEST, String.format("Type mismatch between Ethernet & Src IP"));
822                 }
823                 if ((ipdsttype != EtherIPType.ANY) && (ipdsttype != etype)) {
824                     return new Status(StatusCode.BADREQUEST, String.format("Type mismatch between Ethernet & Dst IP"));
825                 }
826             }
827             if (ipsrctype != ipdsttype) {
828                 if (!((ipsrctype == EtherIPType.ANY) || (ipdsttype == EtherIPType.ANY))) {
829                     return new Status(StatusCode.BADREQUEST, String.format("IP Src Dest Type mismatch"));
830                 }
831             }
832
833             if ((idleTimeout != null) && !isTimeoutValid(idleTimeout)) {
834                 return new Status(StatusCode.BADREQUEST, String.format("Idle Timeout value %s is not valid",
835                         idleTimeout));
836             }
837
838             if ((hardTimeout != null) && !isTimeoutValid(hardTimeout)) {
839                 return new Status(StatusCode.BADREQUEST, String.format("Hard Timeout value %s is not valid",
840                         hardTimeout));
841             }
842
843             Matcher sstr;
844             if (actions == null || actions.isEmpty()) {
845                 return new Status(StatusCode.BADREQUEST, "Actions value is null or empty");
846             }
847             for (String actiongrp : actions) {
848                 // check output ports
849                 sstr = Pattern.compile("OUTPUT=(.*)").matcher(actiongrp);
850                 if (sstr.matches()) {
851                     for (String t : sstr.group(1).split(",")) {
852                         Matcher n = Pattern.compile("(?:(\\d+))").matcher(t);
853                         if (n.matches()) {
854                             if (n.group(1) != null) {
855                                 Short port = Short.parseShort(n.group(1));
856                                 if (isPortValid(sw, port) == false) {
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                         } else {
865                             String msg = String.format("Output port %s is not valid", t);
866                             return new Status(StatusCode.BADREQUEST, msg);
867                         }
868                     }
869                     continue;
870                 }
871                 // Check src IP
872                 sstr = Pattern.compile(ActionType.FLOOD.toString()).matcher(actiongrp);
873                 if (sstr.matches()) {
874                     if (!containerName.equals(GlobalConstants.DEFAULT.toString())) {
875                         return new Status(StatusCode.BADREQUEST, String.format(
876                                 "flood is not allowed in container %s", containerName));
877                     }
878                     continue;
879                 }
880                 // Check src IP
881                 sstr = Pattern.compile(ActionType.SET_NW_SRC.toString() + "=(.*)").matcher(actiongrp);
882                 if (sstr.matches()) {
883                     if (!NetUtils.isIPv4AddressValid(sstr.group(1))) {
884                         return new Status(StatusCode.BADREQUEST, String.format("IP source address %s is not valid",
885                                 sstr.group(1)));
886                     }
887                     continue;
888                 }
889                 // Check dst IP
890                 sstr = Pattern.compile(ActionType.SET_NW_DST.toString() + "=(.*)").matcher(actiongrp);
891                 if (sstr.matches()) {
892                     if (!NetUtils.isIPv4AddressValid(sstr.group(1))) {
893                         return new Status(StatusCode.BADREQUEST, String.format(
894                                 "IP destination address %s is not valid", sstr.group(1)));
895                     }
896                     continue;
897                 }
898
899                 sstr = Pattern.compile(ActionType.SET_VLAN_ID.toString() + "=(.*)").matcher(actiongrp);
900                 if (sstr.matches()) {
901                     if ((sstr.group(1) != null) && !isVlanIdValid(sstr.group(1))) {
902                         return new Status(StatusCode.BADREQUEST, String.format(
903                                 "Vlan ID %s is not in the range 0 - 4095", sstr.group(1)));
904                     }
905                     continue;
906                 }
907
908                 sstr = Pattern.compile(ActionType.SET_VLAN_PCP.toString() + "=(.*)").matcher(actiongrp);
909                 if (sstr.matches()) {
910                     if ((sstr.group(1) != null) && !isVlanPriorityValid(sstr.group(1))) {
911                         return new Status(StatusCode.BADREQUEST, String.format(
912                                 "Vlan priority %s is not in the range 0 - 7", sstr.group(1)));
913                     }
914                     continue;
915                 }
916
917                 sstr = Pattern.compile(ActionType.SET_DL_SRC.toString() + "=(.*)").matcher(actiongrp);
918                 if (sstr.matches()) {
919                     if ((sstr.group(1) != null) && !isL2AddressValid(sstr.group(1))) {
920                         return new Status(StatusCode.BADREQUEST, String.format(
921                                 "Ethernet source address %s is not valid. Example: 00:05:b9:7c:81:5f",
922                                 sstr.group(1)));
923                     }
924                     continue;
925                 }
926                 sstr = Pattern.compile(ActionType.SET_DL_DST.toString() + "=(.*)").matcher(actiongrp);
927                 if (sstr.matches()) {
928                     if ((sstr.group(1) != null) && !isL2AddressValid(sstr.group(1))) {
929                         return new Status(StatusCode.BADREQUEST, String.format(
930                                 "Ethernet destination address %s is not valid. Example: 00:05:b9:7c:81:5f",
931                                 sstr.group(1)));
932                     }
933                     continue;
934                 }
935
936                 sstr = Pattern.compile(ActionType.SET_NW_TOS.toString() + "=(.*)").matcher(actiongrp);
937                 if (sstr.matches()) {
938                     if ((sstr.group(1) != null) && !isTOSBitsValid(sstr.group(1))) {
939                         return new Status(StatusCode.BADREQUEST, String.format(
940                                 "IP ToS bits %s is not in the range 0 - 63", sstr.group(1)));
941                     }
942                     continue;
943                 }
944
945                 sstr = Pattern.compile(ActionType.SET_TP_SRC.toString() + "=(.*)").matcher(actiongrp);
946                 if (sstr.matches()) {
947                     if ((sstr.group(1) != null) && !isTpPortValid(sstr.group(1))) {
948                         return new Status(StatusCode.BADREQUEST, String.format(
949                                 "Transport source port %s is not valid", sstr.group(1)));
950                     }
951                     continue;
952                 }
953
954                 sstr = Pattern.compile(ActionType.SET_TP_DST.toString() + "=(.*)").matcher(actiongrp);
955                 if (sstr.matches()) {
956                     if ((sstr.group(1) != null) && !isTpPortValid(sstr.group(1))) {
957                         return new Status(StatusCode.BADREQUEST, String.format(
958                                 "Transport destination port %s is not valid", sstr.group(1)));
959                     }
960                     continue;
961                 }
962                 sstr = Pattern.compile(ActionType.SET_NEXT_HOP.toString() + "=(.*)").matcher(actiongrp);
963                 if (sstr.matches()) {
964                     if (!NetUtils.isIPAddressValid(sstr.group(1))) {
965                         return new Status(StatusCode.BADREQUEST, String.format(
966                                 "IP destination address %s is not valid", sstr.group(1)));
967                     }
968                     continue;
969                 }
970             }
971             // Check against the container flow
972             Status status;
973             if (!containerName.equals(GlobalConstants.DEFAULT.toString()) && !(status = conflictWithContainerFlow(container)).isSuccess()) {
974                 return status;
975             }
976         } catch (NumberFormatException e) {
977             return new Status(StatusCode.BADREQUEST, String.format("Invalid number format %s", e.getMessage()));
978         }
979
980         return new Status(StatusCode.SUCCESS);
981     }
982
983     public FlowEntry getFlowEntry() {
984         String group = this.isInternalFlow() ? FlowConfig.INTERNALSTATICFLOWGROUP : FlowConfig.STATICFLOWGROUP;
985         return new FlowEntry(group, this.name, this.getFlow(), this.getNode());
986     }
987
988     public Flow getFlow() {
989         Match match = new Match();
990
991         if (this.ingressPort != null) {
992             match.setField(MatchType.IN_PORT,
993                     NodeConnectorCreator.createOFNodeConnector(Short.parseShort(ingressPort), getNode()));
994         }
995         if (this.dlSrc != null) {
996             match.setField(MatchType.DL_SRC, HexEncode.bytesFromHexString(this.dlSrc));
997         }
998         if (this.dlDst != null) {
999             match.setField(MatchType.DL_DST, HexEncode.bytesFromHexString(this.dlDst));
1000         }
1001         if (this.etherType != null) {
1002             match.setField(MatchType.DL_TYPE, Integer.decode(etherType).shortValue());
1003         }
1004         if (this.vlanId != null) {
1005             match.setField(MatchType.DL_VLAN, Short.parseShort(this.vlanId));
1006         }
1007         if (this.vlanPriority != null) {
1008             match.setField(MatchType.DL_VLAN_PR, Byte.parseByte(this.vlanPriority));
1009         }
1010         if (this.nwSrc != null) {
1011             String parts[] = this.nwSrc.split("/");
1012             InetAddress ip = NetUtils.parseInetAddress(parts[0]);
1013             InetAddress mask = null;
1014             int maskLen = 0;
1015             if (parts.length > 1) {
1016                 maskLen = Integer.parseInt(parts[1]);
1017             } else {
1018                 maskLen = (ip instanceof Inet6Address) ? 128 : 32;
1019             }
1020             mask = NetUtils.getInetNetworkMask(maskLen, ip instanceof Inet6Address);
1021             match.setField(MatchType.NW_SRC, ip, mask);
1022         }
1023         if (this.nwDst != null) {
1024             String parts[] = this.nwDst.split("/");
1025             InetAddress ip = NetUtils.parseInetAddress(parts[0]);
1026             InetAddress mask = null;
1027             int maskLen = 0;
1028             if (parts.length > 1) {
1029                 maskLen = Integer.parseInt(parts[1]);
1030             } else {
1031                 maskLen = (ip instanceof Inet6Address) ? 128 : 32;
1032             }
1033             mask = NetUtils.getInetNetworkMask(maskLen, ip instanceof Inet6Address);
1034             match.setField(MatchType.NW_DST, ip, mask);
1035         }
1036         if (IPProtocols.fromString(this.protocol) != IPProtocols.ANY) {
1037             match.setField(MatchType.NW_PROTO, IPProtocols.getProtocolNumberByte(this.protocol));
1038         }
1039         if (this.tosBits != null) {
1040             match.setField(MatchType.NW_TOS, Byte.parseByte(this.tosBits));
1041         }
1042         if (this.tpSrc != null) {
1043             match.setField(MatchType.TP_SRC, Integer.valueOf(this.tpSrc).shortValue());
1044         }
1045         if (this.tpDst != null) {
1046             match.setField(MatchType.TP_DST, Integer.valueOf(this.tpDst).shortValue());
1047         }
1048
1049         Flow flow = new Flow(match, getActionList());
1050         if (this.cookie != null) {
1051             flow.setId(Long.parseLong(cookie));
1052         }
1053         if (this.hardTimeout != null) {
1054             flow.setHardTimeout(Short.parseShort(this.hardTimeout));
1055         }
1056         if (this.idleTimeout != null) {
1057             flow.setIdleTimeout(Short.parseShort(idleTimeout));
1058         }
1059         if (this.priority != null) {
1060             flow.setPriority(Integer.decode(this.priority).shortValue());
1061         }
1062         return flow;
1063     }
1064
1065     public boolean isByNameAndNodeIdEqual(FlowConfig that) {
1066         return (this.name.equals(that.name) && this.node.equals(that.node));
1067     }
1068
1069     public boolean isByNameAndNodeIdEqual(String name, Node node) {
1070         return (this.name.equals(name) && this.node.equals(node));
1071     }
1072
1073     public boolean onNode(Node node) {
1074         return this.node.equals(node);
1075     }
1076
1077     public void toggleInstallation() {
1078         installInHw = (installInHw == null) ? Boolean.toString(false) : Boolean.toString(!Boolean.valueOf(installInHw));
1079     }
1080
1081     /*
1082      * Parses the actions string and return the List of SAL Action No syntax
1083      * check run, as this function will be called when the config validation
1084      * check has already been performed
1085      */
1086     private List<Action> getActionList() {
1087         List<Action> actionList = new ArrayList<Action>();
1088
1089         if (actions != null) {
1090             Matcher sstr;
1091             for (String actiongrp : actions) {
1092                 sstr = Pattern.compile(ActionType.OUTPUT + "=(.*)").matcher(actiongrp);
1093                 if (sstr.matches()) {
1094                     for (String t : sstr.group(1).split(",")) {
1095                         Matcher n = Pattern.compile("(?:(\\d+))").matcher(t);
1096                         if (n.matches()) {
1097                             if (n.group(1) != null) {
1098                                 short ofPort = Short.parseShort(n.group(1));
1099                                 actionList.add(new Output(NodeConnectorCreator.createOFNodeConnector(ofPort,
1100                                         this.getNode())));
1101                             }
1102                         }
1103                     }
1104                     continue;
1105                 }
1106
1107                 sstr = Pattern.compile(ActionType.DROP.toString()).matcher(actiongrp);
1108                 if (sstr.matches()) {
1109                     actionList.add(new Drop());
1110                     continue;
1111                 }
1112
1113                 sstr = Pattern.compile(ActionType.LOOPBACK.toString()).matcher(actiongrp);
1114                 if (sstr.matches()) {
1115                     actionList.add(new Loopback());
1116                     continue;
1117                 }
1118
1119                 sstr = Pattern.compile(ActionType.FLOOD.toString()).matcher(actiongrp);
1120                 if (sstr.matches()) {
1121                     actionList.add(new Flood());
1122                     continue;
1123                 }
1124
1125                 sstr = Pattern.compile(ActionType.SW_PATH.toString()).matcher(actiongrp);
1126                 if (sstr.matches()) {
1127                     actionList.add(new SwPath());
1128                     continue;
1129                 }
1130
1131                 sstr = Pattern.compile(ActionType.HW_PATH.toString()).matcher(actiongrp);
1132                 if (sstr.matches()) {
1133                     actionList.add(new HwPath());
1134                     continue;
1135                 }
1136
1137                 sstr = Pattern.compile(ActionType.CONTROLLER.toString()).matcher(actiongrp);
1138                 if (sstr.matches()) {
1139                     actionList.add(new Controller());
1140                     continue;
1141                 }
1142
1143                 sstr = Pattern.compile(ActionType.SET_VLAN_ID.toString() + "=(.*)").matcher(actiongrp);
1144                 if (sstr.matches()) {
1145                     actionList.add(new SetVlanId(Short.parseShort(sstr.group(1))));
1146                     continue;
1147                 }
1148
1149                 sstr = Pattern.compile(ActionType.SET_VLAN_PCP.toString() + "=(.*)").matcher(actiongrp);
1150                 if (sstr.matches()) {
1151                     actionList.add(new SetVlanPcp(Byte.parseByte(sstr.group(1))));
1152                     continue;
1153                 }
1154
1155                 sstr = Pattern.compile(ActionType.POP_VLAN.toString()).matcher(actiongrp);
1156                 if (sstr.matches()) {
1157                     actionList.add(new PopVlan());
1158                     continue;
1159                 }
1160
1161                 sstr = Pattern.compile(ActionType.SET_DL_SRC.toString() + "=(.*)").matcher(actiongrp);
1162                 if (sstr.matches()) {
1163                     actionList.add(new SetDlSrc(HexEncode.bytesFromHexString(sstr.group(1))));
1164                     continue;
1165                 }
1166
1167                 sstr = Pattern.compile(ActionType.SET_DL_DST.toString() + "=(.*)").matcher(actiongrp);
1168                 if (sstr.matches()) {
1169                     actionList.add(new SetDlDst(HexEncode.bytesFromHexString(sstr.group(1))));
1170                     continue;
1171                 }
1172                 sstr = Pattern.compile(ActionType.SET_NW_SRC.toString() + "=(.*)").matcher(actiongrp);
1173                 if (sstr.matches()) {
1174                     actionList.add(new SetNwSrc(NetUtils.parseInetAddress(sstr.group(1))));
1175                     continue;
1176                 }
1177                 sstr = Pattern.compile(ActionType.SET_NW_DST.toString() + "=(.*)").matcher(actiongrp);
1178                 if (sstr.matches()) {
1179                     actionList.add(new SetNwDst(NetUtils.parseInetAddress(sstr.group(1))));
1180                     continue;
1181                 }
1182
1183                 sstr = Pattern.compile(ActionType.SET_NW_TOS.toString() + "=(.*)").matcher(actiongrp);
1184                 if (sstr.matches()) {
1185                     actionList.add(new SetNwTos(Byte.parseByte(sstr.group(1))));
1186                     continue;
1187                 }
1188
1189                 sstr = Pattern.compile(ActionType.SET_TP_SRC.toString() + "=(.*)").matcher(actiongrp);
1190                 if (sstr.matches()) {
1191                     actionList.add(new SetTpSrc(Integer.valueOf(sstr.group(1))));
1192                     continue;
1193                 }
1194
1195                 sstr = Pattern.compile(ActionType.SET_TP_DST.toString() + "=(.*)").matcher(actiongrp);
1196                 if (sstr.matches()) {
1197                     actionList.add(new SetTpDst(Integer.valueOf(sstr.group(1))));
1198                     continue;
1199                 }
1200
1201                 sstr = Pattern.compile(ActionType.SET_NEXT_HOP.toString() + "=(.*)").matcher(actiongrp);
1202                 if (sstr.matches()) {
1203                     actionList.add(new SetNextHop(NetUtils.parseInetAddress(sstr.group(1))));
1204                     continue;
1205                 }
1206             }
1207         }
1208         return actionList;
1209     }
1210
1211 }