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