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