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