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