84b3e53e065cfea03f225cc1c6fe0f8ebaa27582
[controller.git] / opendaylight / md-sal / forwardingrules-manager / src / main / java / org / opendaylight / controller / forwardingrulesmanager / consumer / impl / FRMUtil.java
1 package org.opendaylight.controller.forwardingrulesmanager.consumer.impl;
2
3 import java.util.ArrayList;
4 import java.util.List;
5 import java.util.regex.Matcher;
6 import java.util.regex.Pattern;
7
8 import org.opendaylight.controller.sal.core.NodeConnector.NodeConnectorIDType;
9 import org.opendaylight.controller.sal.utils.IPProtocols;
10 import org.opendaylight.controller.sal.utils.NetUtils;
11 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
12 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
13 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
14 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.ControllerAction;
15 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputAction;
16 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PushMplsAction;
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PushPbbAction;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PushVlanAction;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetDlDstAction;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetDlSrcAction;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetQueueAction;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetTpDstAction;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetTpSrcAction;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetVlanIdAction;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetVlanPcpAction;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Instructions;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActions;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ClearActions;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.GoToTable;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.Meter;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.WriteActions;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanPcp;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.Match;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatch;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.IpMatch;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatch;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4Match;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6Match;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47 public class FRMUtil {
48     protected static final Logger logger = LoggerFactory.getLogger(FRMUtil.class);
49     private static final String NAMEREGEX = "^[a-zA-Z0-9]+$";
50
51     public static enum operation {
52         ADD, DELETE, UPDATE, GET
53     };
54
55     private enum EtherIPType {
56         ANY, V4, V6;
57     };
58
59     public static boolean isNameValid(String name) {
60
61         // Name validation
62         if (name == null || name.trim().isEmpty() || !name.matches(NAMEREGEX)) {
63             return false;
64         }
65         return true;
66
67     }
68
69     public static boolean validateMatch(Flow flow) {
70         EtherIPType etype = EtherIPType.ANY;
71         EtherIPType ipsrctype = EtherIPType.ANY;
72         EtherIPType ipdsttype = EtherIPType.ANY;
73
74         Match match = flow.getMatch();
75         if (match != null) {
76             EthernetMatch ethernetmatch = match.getEthernetMatch();
77             IpMatch ipmatch = match.getIpMatch();
78             Layer3Match layer3match = match.getLayer3Match();
79             VlanMatch vlanmatch = match.getVlanMatch();
80             match.getIcmpv4Match();
81
82             if (ethernetmatch != null) {
83                 if ((ethernetmatch.getEthernetSource() != null)
84                         && !isL2AddressValid(ethernetmatch.getEthernetSource().getAddress().getValue())) {
85
86                     logger.error("Ethernet source address is not valid. Example: 00:05:b9:7c:81:5f",
87                             ethernetmatch.getEthernetSource());
88                     return false;
89                 }
90
91                 if ((ethernetmatch.getEthernetDestination() != null)
92                         && !isL2AddressValid(ethernetmatch.getEthernetDestination().getAddress().getValue())) {
93                     logger.error("Ethernet destination address is not valid. Example: 00:05:b9:7c:81:5f",
94                             ethernetmatch.getEthernetDestination());
95                     return false;
96                 }
97
98                 if (ethernetmatch.getEthernetType() != null) {
99                     long type = ethernetmatch.getEthernetType().getType().getValue().longValue();
100                     if ((type < 0) || (type > 0xffff)) {
101                         logger.error("Ethernet type is not valid");
102                         return false;
103                     } else {
104                         if (type == 0x0800) {
105                             etype = EtherIPType.V4;
106                         } else if (type == 0x86dd) {
107                             etype = EtherIPType.V6;
108                         }
109                     }
110
111                 }
112             }
113
114             if (layer3match != null) {
115                 if (layer3match instanceof Ipv4Match) {
116                     if (((Ipv4Match) layer3match).getIpv4Source() != null) {
117                         if (NetUtils.isIPv4AddressValid(((Ipv4Match) layer3match).getIpv4Source().getValue())) {
118                             ipsrctype = EtherIPType.V4;
119                         } else {
120                             logger.error("IP source address is not valid");
121                             return false;
122                         }
123
124                     } else if (((Ipv4Match) layer3match).getIpv4Destination() != null) {
125                         if (NetUtils.isIPv4AddressValid(((Ipv4Match) layer3match).getIpv4Destination().getValue())) {
126                             ipdsttype = EtherIPType.V4;
127                         } else {
128                             logger.error("IP Destination address is not valid");
129                             return false;
130                         }
131
132                     }
133                 } else if (layer3match instanceof Ipv6Match) {
134                     if (((Ipv6Match) layer3match).getIpv6Source() != null) {
135                         if (NetUtils.isIPv6AddressValid(((Ipv6Match) layer3match).getIpv6Source().getValue())) {
136                             ipsrctype = EtherIPType.V6;
137                         } else {
138                             logger.error("IPv6 source address is not valid");
139                             return false;
140                         }
141
142                     } else if (((Ipv6Match) layer3match).getIpv6Destination() != null) {
143                         if (NetUtils.isIPv6AddressValid(((Ipv6Match) layer3match).getIpv6Destination().getValue())) {
144                             ipdsttype = EtherIPType.V6;
145                         } else {
146                             logger.error("IPv6 Destination address is not valid");
147                             return false;
148                         }
149
150                     }
151
152                 }
153
154                 if (etype != EtherIPType.ANY) {
155                     if ((ipsrctype != EtherIPType.ANY) && (ipsrctype != etype)) {
156                         logger.error("Type mismatch between Ethernet & Src IP");
157                         return false;
158                     }
159                     if ((ipdsttype != EtherIPType.ANY) && (ipdsttype != etype)) {
160                         logger.error("Type mismatch between Ethernet & Dst IP");
161                         return false;
162                     }
163                 }
164                 if (ipsrctype != ipdsttype) {
165                     if (!((ipsrctype == EtherIPType.ANY) || (ipdsttype == EtherIPType.ANY))) {
166                         logger.error("IP Src Dest Type mismatch");
167                         return false;
168                     }
169                 }
170             }
171
172             if (ipmatch != null) {
173                 if (ipmatch.getIpProtocol() != null && !(isProtocolValid(ipmatch.getIpProtocol().toString()))) {
174                     logger.error("Protocol is not valid");
175                     return false;
176                 }
177
178             }
179
180             if (vlanmatch != null) {
181                 if (vlanmatch.getVlanId() != null
182                         && !(isVlanIdValid(vlanmatch.getVlanId().getVlanId().getValue().toString()))) {
183                     logger.error("Vlan ID is not in the range 0 - 4095");
184                     return false;
185                 }
186
187                 if (vlanmatch.getVlanPcp() != null
188                         && !(isVlanPriorityValid(vlanmatch.getVlanPcp().getValue().toString()))) {
189                     logger.error("Vlan priority is not in the range 0 - 7");
190                     return false;
191                 }
192             }
193
194         }
195
196         return true;
197
198     }
199
200     public static boolean validateActions(List<Action> actions) {
201
202         if (actions == null || actions.isEmpty()) {
203             logger.error("Actions value is null or empty");
204             return false;
205         }
206
207         for (Action curaction : actions) {
208             org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action action = curaction
209                     .getAction();
210             if (action instanceof ControllerAction) {
211                 Integer length = ((ControllerAction) action).getMaxLength();
212                 if (length < 0 || length > 65294) {
213                     logger.error("Controller: MaxLength is not valid");
214                     return false;
215                 }
216             } else if (action instanceof OutputAction) {
217                 Integer length = ((OutputAction) action).getMaxLength();
218                 Uri outputnodeconnector = ((OutputAction) action).getOutputNodeConnector();
219                 if (length < 0 || length > 65294) {
220                     logger.error("OutputAction: MaxLength is not valid");
221                     return false;
222                 }
223                 if (outputnodeconnector != null) {
224                     if (!outputnodeconnector.getValue().equals(NodeConnectorIDType.ALL)
225                             || !outputnodeconnector.getValue().equals(NodeConnectorIDType.CONTROLLER)
226                             || !outputnodeconnector.getValue().equals(NodeConnectorIDType.HWPATH)
227                             || !outputnodeconnector.getValue().equals(NodeConnectorIDType.ONEPK)
228                             || !outputnodeconnector.getValue().equals(NodeConnectorIDType.ONEPK2OPENFLOW)
229                             || !outputnodeconnector.getValue().equals(NodeConnectorIDType.ONEPK2PCEP)
230                             || !outputnodeconnector.getValue().equals(NodeConnectorIDType.OPENFLOW)
231                             || !outputnodeconnector.getValue().equals(NodeConnectorIDType.OPENFLOW2ONEPK)
232                             || !outputnodeconnector.getValue().equals(NodeConnectorIDType.OPENFLOW2PCEP)
233                             || !outputnodeconnector.getValue().equals(NodeConnectorIDType.PCEP)
234                             || !outputnodeconnector.getValue().equals(NodeConnectorIDType.PCEP2ONEPK)
235                             || !outputnodeconnector.getValue().equals(NodeConnectorIDType.PCEP2OPENFLOW)
236                             || !outputnodeconnector.getValue().equals(NodeConnectorIDType.PRODUCTION)
237                             || !outputnodeconnector.getValue().equals(NodeConnectorIDType.SWSTACK)) {
238                         logger.error("Output Action: NodeConnector Type is not valid");
239                         return false;
240                     }
241
242                 }
243             } else if (action instanceof PushMplsAction) {
244                 Integer ethertype = ((PushMplsAction) action).getEthernetType();
245                 if (ethertype != null && ethertype != 0x8847 && ethertype != 0x8848) {
246                     logger.error("Ether Type is not valid for PushMplsAction");
247                     return false;
248                 }
249             } else if (action instanceof PushPbbAction) {
250                 Integer ethertype = ((PushPbbAction) action).getEthernetType();
251                 if (ethertype != null && ethertype != 0x88E7) {
252                     logger.error("Ether type is not valid for PushPbbAction");
253                     return false;
254                 }
255             } else if (action instanceof PushVlanAction) {
256                 Integer ethertype = ((PushVlanAction) action).getEthernetType();
257                 if (ethertype != null && ethertype != 0x8100 && ethertype != 0x88a8) {
258                     logger.error("Ether Type is not valid for PushVlanAction");
259                     return false;
260                 }
261             } else if (action instanceof SetDlDstAction) {
262                 MacAddress address = ((SetDlDstAction) action).getAddress();
263                 if (address != null && !isL2AddressValid(address.getValue())) {
264                     logger.error("SetDlDstAction: Address not valid");
265                     return false;
266                 }
267             } else if (action instanceof SetDlSrcAction) {
268                 MacAddress address = ((SetDlSrcAction) action).getAddress();
269                 if (address != null && !isL2AddressValid(address.getValue())) {
270                     logger.error("SetDlSrcAction: Address not valid");
271                     return false;
272                 }
273             } else if (action instanceof SetQueueAction) {
274                 String queue = ((SetQueueAction) action).getQueue();
275                 if (queue != null && !isQueueValid(queue)) {
276                     logger.error("Queue Id not valid");
277                     return false;
278                 }
279             } else if (action instanceof SetTpDstAction) {
280                 PortNumber port = ((SetTpDstAction) action).getPort();
281                 if (port != null && !isPortValid(port)) {
282                     logger.error("Port not valid");
283                 }
284             } else if (action instanceof SetTpSrcAction) {
285                 PortNumber port = ((SetTpSrcAction) action).getPort();
286                 if (port != null && !isPortValid(port)) {
287                     logger.error("Port not valid");
288                 }
289             } else if (action instanceof SetVlanIdAction) {
290                 VlanId vlanid = ((SetVlanIdAction) action).getVlanId();
291                 if (vlanid != null && !isVlanIdValid(vlanid.getValue().toString())) {
292                     logger.error("Vlan ID is not in the range 0 - 4095");
293                     return false;
294                 }
295             } else if (action instanceof SetVlanPcpAction) {
296                 VlanPcp vlanpcp = ((SetVlanPcpAction) action).getVlanPcp();
297                 if (vlanpcp != null && !isVlanPriorityValid(vlanpcp.getValue().toString())) {
298                     logger.error("Vlan priority is not in the range 0 - 7");
299                     return false;
300                 }
301             }
302         }
303         return true;
304
305     }
306
307     public static boolean validateInstructions(Flow flow) {
308         List<Instruction> instructionsList = new ArrayList<>();
309         Instructions instructions = flow.getInstructions();
310         if (instructions == null) {
311             return false;
312         }
313         instructionsList = instructions.getInstruction();
314
315         for (Instruction instruction : instructionsList) {
316             org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction curInstruction = instruction
317                     .getInstruction();
318             if (curInstruction instanceof GoToTable) {
319
320                 Short tableid = ((GoToTable) curInstruction).getTableId();
321                 if (tableid < 0) {
322                     logger.error("table id is not valid");
323                     return false;
324                 }
325             }
326
327             else if (curInstruction instanceof WriteActions) {
328
329                 List<Action> action = ((WriteActions) curInstruction).getAction();
330                 validateActions(action);
331
332             }
333
334             else if (curInstruction instanceof ApplyActions) {
335                 List<Action> action = ((ApplyActions) curInstruction).getAction();
336                 validateActions(action);
337             }
338
339             else if (curInstruction instanceof ClearActions) {
340                 List<Action> action = ((ClearActions) curInstruction).getAction();
341                 validateActions(action);
342             }
343
344             else if (curInstruction instanceof Meter) {
345
346                 String meter = ((Meter) curInstruction).getMeter();
347                 if (meter != null && !isValidMeter(meter)) {
348                     logger.error("Meter Id is not valid");
349                     return false;
350                 }
351             }
352
353         }
354
355         return true;
356     }
357
358     public static boolean isValidMeter(String meter) {
359         // TODO
360         return true;
361     }
362
363     public static boolean isQueueValid(String queue) {
364         // TODO
365         return true;
366     }
367
368     public static boolean isPortValid(PortNumber port) {
369         // TODO
370         return true;
371     }
372
373     public static boolean isL2AddressValid(String mac) {
374         if (mac == null) {
375             return false;
376         }
377
378         Pattern macPattern = Pattern.compile("([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}");
379         Matcher mm = macPattern.matcher(mac);
380         if (!mm.matches()) {
381             logger.debug("Ethernet address {} is not valid. Example: 00:05:b9:7c:81:5f", mac);
382             return false;
383         }
384         return true;
385     }
386
387     public static boolean isProtocolValid(String protocol) {
388         IPProtocols proto = IPProtocols.fromString(protocol);
389         return (proto != null);
390     }
391
392     public static boolean isVlanIdValid(String vlanId) {
393         int vlan = Integer.decode(vlanId);
394         return ((vlan >= 0) && (vlan < 4096));
395     }
396
397     public static boolean isVlanPriorityValid(String vlanPriority) {
398         int pri = Integer.decode(vlanPriority);
399         return ((pri >= 0) && (pri < 8));
400     }
401 }