8a77825d7943c12e8be971687cb4f3e8ac187b72
[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 ((container != null) && !container.getName().equals(GlobalConstants.DEFAULT.toString())) {
734                         msg += " in Container " + container.getName();
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 ((container != null)
845                                                 && !container.getName().equals(GlobalConstants.DEFAULT.toString())) {
846                                             msg += " in Container " + container.getName();
847                                         }
848                                         return new Status(StatusCode.BADREQUEST, msg);
849                                     }
850                                 }
851                             }
852                         }
853                         continue;
854                     }
855                     // Check src IP
856                     sstr = Pattern.compile(ActionType.FLOOD.toString()).matcher(actiongrp);
857                     if (sstr.matches()) {
858                         if (container != null) {
859                             return new Status(StatusCode.BADREQUEST, String.format(
860                                     "flood is not allowed in container %s", container.getName()));
861                         }
862                         continue;
863                     }
864                     // Check src IP
865                     sstr = Pattern.compile(ActionType.SET_NW_SRC.toString() + "=(.*)").matcher(actiongrp);
866                     if (sstr.matches()) {
867                         if (!NetUtils.isIPv4AddressValid(sstr.group(1))) {
868                             return new Status(StatusCode.BADREQUEST, String.format("IP source address %s is not valid",
869                                     sstr.group(1)));
870                         }
871                         continue;
872                     }
873                     // Check dst IP
874                     sstr = Pattern.compile(ActionType.SET_NW_DST.toString() + "=(.*)").matcher(actiongrp);
875                     if (sstr.matches()) {
876                         if (!NetUtils.isIPv4AddressValid(sstr.group(1))) {
877                             return new Status(StatusCode.BADREQUEST, String.format(
878                                     "IP destination address %s is not valid", sstr.group(1)));
879                         }
880                         continue;
881                     }
882
883                     sstr = Pattern.compile(ActionType.SET_VLAN_ID.toString() + "=(.*)").matcher(actiongrp);
884                     if (sstr.matches()) {
885                         if ((sstr.group(1) != null) && !isVlanIdValid(sstr.group(1))) {
886                             return new Status(StatusCode.BADREQUEST, String.format(
887                                     "Vlan ID %s is not in the range 0 - 4095", sstr.group(1)));
888                         }
889                         continue;
890                     }
891
892                     sstr = Pattern.compile(ActionType.SET_VLAN_PCP.toString() + "=(.*)").matcher(actiongrp);
893                     if (sstr.matches()) {
894                         if ((sstr.group(1) != null) && !isVlanPriorityValid(sstr.group(1))) {
895                             return new Status(StatusCode.BADREQUEST, String.format(
896                                     "Vlan priority %s is not in the range 0 - 7", sstr.group(1)));
897                         }
898                         continue;
899                     }
900
901                     sstr = Pattern.compile(ActionType.SET_DL_SRC.toString() + "=(.*)").matcher(actiongrp);
902                     if (sstr.matches()) {
903                         if ((sstr.group(1) != null) && !isL2AddressValid(sstr.group(1))) {
904                             return new Status(StatusCode.BADREQUEST, String.format(
905                                     "Ethernet source address %s is not valid. Example: 00:05:b9:7c:81:5f",
906                                     sstr.group(1)));
907                         }
908                         continue;
909                     }
910                     sstr = Pattern.compile(ActionType.SET_DL_DST.toString() + "=(.*)").matcher(actiongrp);
911                     if (sstr.matches()) {
912                         if ((sstr.group(1) != null) && !isL2AddressValid(sstr.group(1))) {
913                             return new Status(StatusCode.BADREQUEST, String.format(
914                                     "Ethernet destination address %s is not valid. Example: 00:05:b9:7c:81:5f",
915                                     sstr.group(1)));
916                         }
917                         continue;
918                     }
919
920                     sstr = Pattern.compile(ActionType.SET_NW_TOS.toString() + "=(.*)").matcher(actiongrp);
921                     if (sstr.matches()) {
922                         if ((sstr.group(1) != null) && !isTOSBitsValid(sstr.group(1))) {
923                             return new Status(StatusCode.BADREQUEST, String.format(
924                                     "IP ToS bits %s is not in the range 0 - 63", sstr.group(1)));
925                         }
926                         continue;
927                     }
928
929                     sstr = Pattern.compile(ActionType.SET_TP_SRC.toString() + "=(.*)").matcher(actiongrp);
930                     if (sstr.matches()) {
931                         if ((sstr.group(1) != null) && !isTpPortValid(sstr.group(1))) {
932                             return new Status(StatusCode.BADREQUEST, String.format(
933                                     "Transport source port %s is not valid", sstr.group(1)));
934                         }
935                         continue;
936                     }
937
938                     sstr = Pattern.compile(ActionType.SET_TP_DST.toString() + "=(.*)").matcher(actiongrp);
939                     if (sstr.matches()) {
940                         if ((sstr.group(1) != null) && !isTpPortValid(sstr.group(1))) {
941                             return new Status(StatusCode.BADREQUEST, String.format(
942                                     "Transport destination port %s is not valid", sstr.group(1)));
943                         }
944                         continue;
945                     }
946                     sstr = Pattern.compile(ActionType.SET_NEXT_HOP.toString() + "=(.*)").matcher(actiongrp);
947                     if (sstr.matches()) {
948                         if (!NetUtils.isIPAddressValid(sstr.group(1))) {
949                             return new Status(StatusCode.BADREQUEST, String.format(
950                                     "IP destination address %s is not valid", sstr.group(1)));
951                         }
952                         continue;
953                     }
954                 }
955             }
956             // Check against the container flow
957             Status status;
958             if ((container != null) && !(status = conflictWithContainerFlow(container)).isSuccess()) {
959                 return status;
960             }
961         } catch (NumberFormatException e) {
962             return new Status(StatusCode.BADREQUEST, String.format("Invalid number format %s", e.getMessage()));
963         }
964
965         return new Status(StatusCode.SUCCESS);
966     }
967
968     public FlowEntry getFlowEntry() {
969         return new FlowEntry(FlowConfig.staticFlowsGroup, this.name, this.getFlow(), this.getNode());
970     }
971
972     public Flow getFlow() {
973         Match match = new Match();
974
975         if (this.ingressPort != null) {
976             match.setField(MatchType.IN_PORT,
977                     NodeConnectorCreator.createOFNodeConnector(Short.parseShort(ingressPort), getNode()));
978         }
979         if (this.dlSrc != null) {
980             match.setField(MatchType.DL_SRC, HexEncode.bytesFromHexString(this.dlSrc));
981         }
982         if (this.dlDst != null) {
983             match.setField(MatchType.DL_DST, HexEncode.bytesFromHexString(this.dlDst));
984         }
985         if (this.etherType != null) {
986             match.setField(MatchType.DL_TYPE, Integer.decode(etherType).shortValue());
987         }
988         if (this.vlanId != null) {
989             match.setField(MatchType.DL_VLAN, Short.parseShort(this.vlanId));
990         }
991         if (this.vlanPriority != null) {
992             match.setField(MatchType.DL_VLAN_PR, Byte.parseByte(this.vlanPriority));
993         }
994         if (this.nwSrc != null) {
995             String parts[] = this.nwSrc.split("/");
996             InetAddress ip = NetUtils.parseInetAddress(parts[0]);
997             InetAddress mask = null;
998             int maskLen = 0;
999             if (parts.length > 1) {
1000                 maskLen = Integer.parseInt(parts[1]);
1001             } else {
1002                 maskLen = (ip instanceof Inet6Address) ? 128 : 32;
1003             }
1004             mask = NetUtils.getInetNetworkMask(maskLen, ip instanceof Inet6Address);
1005             match.setField(MatchType.NW_SRC, ip, mask);
1006         }
1007         if (this.nwDst != null) {
1008             String parts[] = this.nwDst.split("/");
1009             InetAddress ip = NetUtils.parseInetAddress(parts[0]);
1010             InetAddress mask = null;
1011             int maskLen = 0;
1012             if (parts.length > 1) {
1013                 maskLen = Integer.parseInt(parts[1]);
1014             } else {
1015                 maskLen = (ip instanceof Inet6Address) ? 128 : 32;
1016             }
1017             mask = NetUtils.getInetNetworkMask(maskLen, ip instanceof Inet6Address);
1018             match.setField(MatchType.NW_DST, ip, mask);
1019         }
1020         if (this.protocol != null) {
1021             match.setField(MatchType.NW_PROTO, IPProtocols.getProtocolNumberByte(this.protocol));
1022         }
1023         if (this.tosBits != null) {
1024             match.setField(MatchType.NW_TOS, Byte.parseByte(this.tosBits));
1025         }
1026         if (this.tpSrc != null) {
1027             match.setField(MatchType.TP_SRC, Integer.valueOf(this.tpSrc).shortValue());
1028         }
1029         if (this.tpDst != null) {
1030             match.setField(MatchType.TP_DST, Integer.valueOf(this.tpDst).shortValue());
1031         }
1032
1033         Flow flow = new Flow(match, getActionList());
1034         if (this.cookie != null) {
1035             flow.setId(Long.parseLong(cookie));
1036         }
1037         if (this.hardTimeout != null) {
1038             flow.setHardTimeout(Short.parseShort(this.hardTimeout));
1039         }
1040         if (this.idleTimeout != null) {
1041             flow.setIdleTimeout(Short.parseShort(idleTimeout));
1042         }
1043         if (this.priority != null) {
1044             flow.setPriority(Integer.decode(this.priority).shortValue());
1045         }
1046         return flow;
1047     }
1048
1049     public boolean isByNameAndNodeIdEqual(FlowConfig that) {
1050         return (this.name.equals(that.name) && this.node.equals(that.node));
1051     }
1052
1053     public boolean isByNameAndNodeIdEqual(String name, Node node) {
1054         return (this.name.equals(name) && this.node.equals(node));
1055     }
1056
1057     public boolean onNode(Node node) {
1058         return this.node.equals(node);
1059     }
1060
1061     public void toggleInstallation() {
1062         installInHw = (installInHw == null) ? "true" : (installInHw.equals("true")) ? "false" : "true";
1063     }
1064
1065     /*
1066      * Parses the actions string and return the List of SAL Action No syntax
1067      * check run, as this function will be called when the config validation
1068      * check has already been performed
1069      */
1070     private List<Action> getActionList() {
1071         List<Action> actionList = new ArrayList<Action>();
1072
1073         if (actions != null) {
1074             Matcher sstr;
1075             for (String actiongrp : actions) {
1076                 sstr = Pattern.compile(ActionType.OUTPUT + "=(.*)").matcher(actiongrp);
1077                 if (sstr.matches()) {
1078                     for (String t : sstr.group(1).split(",")) {
1079                         Matcher n = Pattern.compile("(?:(\\d+))").matcher(t);
1080                         if (n.matches()) {
1081                             if (n.group(1) != null) {
1082                                 short ofPort = Short.parseShort(n.group(1));
1083                                 actionList.add(new Output(NodeConnectorCreator.createOFNodeConnector(ofPort,
1084                                         this.getNode())));
1085                             }
1086                         }
1087                     }
1088                     continue;
1089                 }
1090
1091                 sstr = Pattern.compile(ActionType.DROP.toString()).matcher(actiongrp);
1092                 if (sstr.matches()) {
1093                     actionList.add(new Drop());
1094                     continue;
1095                 }
1096
1097                 sstr = Pattern.compile(ActionType.LOOPBACK.toString()).matcher(actiongrp);
1098                 if (sstr.matches()) {
1099                     actionList.add(new Loopback());
1100                     continue;
1101                 }
1102
1103                 sstr = Pattern.compile(ActionType.FLOOD.toString()).matcher(actiongrp);
1104                 if (sstr.matches()) {
1105                     actionList.add(new Flood());
1106                     continue;
1107                 }
1108
1109                 sstr = Pattern.compile(ActionType.SW_PATH.toString()).matcher(actiongrp);
1110                 if (sstr.matches()) {
1111                     actionList.add(new SwPath());
1112                     continue;
1113                 }
1114
1115                 sstr = Pattern.compile(ActionType.HW_PATH.toString()).matcher(actiongrp);
1116                 if (sstr.matches()) {
1117                     actionList.add(new HwPath());
1118                     continue;
1119                 }
1120
1121                 sstr = Pattern.compile(ActionType.CONTROLLER.toString()).matcher(actiongrp);
1122                 if (sstr.matches()) {
1123                     actionList.add(new Controller());
1124                     continue;
1125                 }
1126
1127                 sstr = Pattern.compile(ActionType.SET_VLAN_ID.toString() + "=(.*)").matcher(actiongrp);
1128                 if (sstr.matches()) {
1129                     actionList.add(new SetVlanId(Short.parseShort(sstr.group(1))));
1130                     continue;
1131                 }
1132
1133                 sstr = Pattern.compile(ActionType.SET_VLAN_PCP.toString() + "=(.*)").matcher(actiongrp);
1134                 if (sstr.matches()) {
1135                     actionList.add(new SetVlanPcp(Byte.parseByte(sstr.group(1))));
1136                     continue;
1137                 }
1138
1139                 sstr = Pattern.compile(ActionType.POP_VLAN.toString()).matcher(actiongrp);
1140                 if (sstr.matches()) {
1141                     actionList.add(new PopVlan());
1142                     continue;
1143                 }
1144
1145                 sstr = Pattern.compile(ActionType.SET_DL_SRC.toString() + "=(.*)").matcher(actiongrp);
1146                 if (sstr.matches()) {
1147                     actionList.add(new SetDlSrc(HexEncode.bytesFromHexString(sstr.group(1))));
1148                     continue;
1149                 }
1150
1151                 sstr = Pattern.compile(ActionType.SET_DL_DST.toString() + "=(.*)").matcher(actiongrp);
1152                 if (sstr.matches()) {
1153                     actionList.add(new SetDlDst(HexEncode.bytesFromHexString(sstr.group(1))));
1154                     continue;
1155                 }
1156                 sstr = Pattern.compile(ActionType.SET_NW_SRC.toString() + "=(.*)").matcher(actiongrp);
1157                 if (sstr.matches()) {
1158                     actionList.add(new SetNwSrc(NetUtils.parseInetAddress(sstr.group(1))));
1159                     continue;
1160                 }
1161                 sstr = Pattern.compile(ActionType.SET_NW_DST.toString() + "=(.*)").matcher(actiongrp);
1162                 if (sstr.matches()) {
1163                     actionList.add(new SetNwDst(NetUtils.parseInetAddress(sstr.group(1))));
1164                     continue;
1165                 }
1166
1167                 sstr = Pattern.compile(ActionType.SET_NW_TOS.toString() + "=(.*)").matcher(actiongrp);
1168                 if (sstr.matches()) {
1169                     actionList.add(new SetNwTos(Byte.parseByte(sstr.group(1))));
1170                     continue;
1171                 }
1172
1173                 sstr = Pattern.compile(ActionType.SET_TP_SRC.toString() + "=(.*)").matcher(actiongrp);
1174                 if (sstr.matches()) {
1175                     actionList.add(new SetTpSrc(Integer.valueOf(sstr.group(1))));
1176                     continue;
1177                 }
1178
1179                 sstr = Pattern.compile(ActionType.SET_TP_DST.toString() + "=(.*)").matcher(actiongrp);
1180                 if (sstr.matches()) {
1181                     actionList.add(new SetTpDst(Integer.valueOf(sstr.group(1))));
1182                     continue;
1183                 }
1184
1185                 sstr = Pattern.compile(ActionType.SET_NEXT_HOP.toString() + "=(.*)").matcher(actiongrp);
1186                 if (sstr.matches()) {
1187                     actionList.add(new SetNextHop(NetUtils.parseInetAddress(sstr.group(1))));
1188                     continue;
1189                 }
1190             }
1191         }
1192         return actionList;
1193     }
1194
1195 }