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