Make MatchReactor a proper constant
[openflowplugin.git] / openflowplugin / src / main / java / org / opendaylight / openflowplugin / openflow / md / core / sal / convertor / IpConversionUtil.java
1 /*
2  * Copyright (c) 2015 Brocade, Communications Systems, Inc
3  * Copyright (c) 2015 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.openflowplugin.openflow.md.core.sal.convertor;
11
12 import com.google.common.base.Splitter;
13 import io.netty.buffer.ByteBufUtil;
14 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
15 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
16 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Address;
17 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix;
18 import java.util.Iterator;
19 import com.google.common.collect.Iterators;
20 import java.util.Arrays;
21 import java.net.UnknownHostException;
22 import java.net.Inet6Address;
23 import java.net.Inet4Address;
24 import java.net.InetAddress;
25 import com.google.common.net.InetAddresses;
26 import com.google.common.base.Preconditions;
27
28
29 /**
30  * Created by Martin Bobak <mbobak@cisco.com> on 5.3.2015.
31  * v6 routines added by Anton Ivanov on 14.6.2015
32  */
33 public final class IpConversionUtil {
34
35     public static final String PREFIX_SEPARATOR = "/";
36     public static final Splitter PREFIX_SPLITTER = Splitter.on('/');
37     final private static int INADDR4SZ = 4;
38     final private static int INADDR6SZ = 16;
39     final private static int INT16SZ = 2;
40
41     private IpConversionUtil() {
42         throw new IllegalStateException("This class should not be instantiated.");
43     }
44
45     public static Iterator<String> splitToParts(final Ipv4Prefix ipv4Prefix) {
46         return PREFIX_SPLITTER.split(ipv4Prefix.getValue()).iterator();
47     }
48
49     public static Iterator<String> splitToParts(final Ipv4Address ipv4Address) {
50         /* Invalid (Ab)use of ip address as prefix!!! */
51         String [] tempPrefix = {ipv4Address.getValue(), "32"};
52         return Iterators.forArray(tempPrefix);
53     }
54
55     public static Iterator<String> splitToParts(final Ipv6Prefix ipv6Prefix) {
56         return PREFIX_SPLITTER.split(ipv6Prefix.getValue()).iterator();
57     }
58
59     public static Iterator<String> splitToParts(final Ipv6Address ipv6Address) {
60         /* Invalid (Ab)use of ip address as prefix!!! */
61         String [] tempPrefix = {ipv6Address.getValue(), "128"};
62         return Iterators.forArray(tempPrefix);
63     }
64
65
66     /* This forest of functions has a purpose:
67      *
68      * 1. There are multiple coding styles around the plugin, this is necessary in order to have
69      *   one mechanism to convert them all, one mechanism to find them...
70      * 2. I hope that one day yangtools will actually deliver code fit for purpose in a packet
71      *   processing application (presently it is not. When this happens, these can be optimized
72      *   for "side-load" of pre-vetted data. Example. IP Address (v4 or v6) is prevetted left of the
73      *   prefix. It should be loadable into Prefix without _RERUNNING_ 100ms+ of regexps. When (and if)
74      *   that happens, it will be a simple fix here without chasing it across the whole plugin.
75     */
76
77     public static Ipv4Prefix createPrefix(Ipv4Address ipv4Address){
78         return new Ipv4Prefix(ipv4Address.getValue() + PREFIX_SEPARATOR + 32);
79     }
80
81     public static Ipv4Prefix createPrefix(Ipv4Address ipv4Address, String mask){
82         /* 
83          * Ipv4Address has already validated the address part of the prefix,
84          * It is mandated to comply to the same regexp as the address
85          * There is absolutely no point rerunning additional checks vs this
86          * Note - there is no canonical form check here!!!
87          */
88         if (null != mask && !mask.equals("")) {
89             return new Ipv4Prefix(ipv4Address.getValue() + PREFIX_SEPARATOR + mask);
90         } else {
91             return new Ipv4Prefix(ipv4Address.getValue() + PREFIX_SEPARATOR + "32");
92         }
93     }
94
95     public static Ipv4Prefix createPrefix(Ipv4Address ipv4Address, int intmask){
96         return createPrefix(ipv4Address, "" + intmask); 
97     }
98
99     public static Ipv4Prefix createPrefix(Ipv4Address ipv4Address, byte [] bytemask){
100         return createPrefix(ipv4Address, "" + countBits(bytemask)); 
101     }
102
103     public static Ipv6Prefix createPrefix(Ipv6Address ipv6Address){
104         return new Ipv6Prefix(ipv6Address.getValue() + PREFIX_SEPARATOR + 128);
105     }
106
107     public static Ipv6Prefix createPrefix(Ipv6Address ipv6Address, String mask){
108         /* 
109          * Ipv6Address has already validated the address part of the prefix,
110          * It is mandated to comply to the same regexp as the address
111          * There is absolutely no point rerunning additional checks vs this
112          * Note - there is no canonical form check here!!!
113          */
114         if (null != mask && !mask.equals("")) {
115             return new Ipv6Prefix(ipv6Address.getValue() + PREFIX_SEPARATOR + mask);
116         } else {
117             return new Ipv6Prefix(ipv6Address.getValue() + PREFIX_SEPARATOR + "128");
118         }
119     }
120
121     public static Ipv6Prefix createPrefix(Ipv6Address ipv6Address, int intmask){
122         return createPrefix(ipv6Address, "" + intmask); 
123     }
124
125     public static Ipv6Prefix createPrefix(Ipv6Address ipv6Address, byte [] bytemask){
126         /* 
127          * Ipv4Address has already validated the address part of the prefix,
128          * It is mandated to comply to the same regexp as the address
129          * There is absolutely no point rerunning additional checks vs this
130          * Note - there is no canonical form check here!!!
131          */
132          return createPrefix(ipv6Address, "" + countBits(bytemask)); 
133     }
134     public static Integer extractPrefix(Ipv4Prefix ipv4Prefix) {
135         Iterator<String> addressParts = splitToParts(ipv4Prefix);
136         addressParts.next();
137         Integer retval = null;
138         if (addressParts.hasNext()) {
139             retval = Integer.parseInt(addressParts.next());
140         }
141         return retval;
142     }
143
144     public static Integer extractPrefix(Ipv6Prefix ipv6Prefix) {
145         Iterator<String> addressParts = splitToParts(ipv6Prefix);
146         addressParts.next();
147         Integer retval = null;
148         if (addressParts.hasNext()) {
149             retval = Integer.parseInt(addressParts.next());
150         }
151         return retval;
152     }
153
154     public static Integer extractPrefix(Ipv4Address ipv4Prefix) {
155         return 32;
156     }
157
158     public static Integer extractPrefix(Ipv6Address ipv6Prefix) {
159         return 128;
160     }
161
162     /*
163      * BIG FAT WARNING!!!
164      * Read all of the following before you touch any v6 code or decide to
165      * optimize it by invoking a "simple" Guava call
166      *
167      * Java IPv6 is fundamentally broken and Google libraries do not fix it.
168      * 1. Java will allways implicitly rewrite v4 mapped into v6 as a v4 address
169      *      and there is absolutely no way to override this behaviour
170      * 2. Guava libraries cannot parse non-canonical IPv6. They will throw an
171      *      exception. Even if they did, they re-use the same broken java code
172      *      underneath.
173      *
174      * This is why we have to parse v6 by ourselves.
175      *
176      * The following conversion code is based on inet_cidr_pton_ipv6 in NetBSD
177      *
178      * The original BSD code is licensed under standard BSD license. While we
179      * are not obliged to provide an attribution, credit where credit is due.
180      * As far as why it is similar to Sun's sun.net.util please ask Sun why
181      * their code has the same variable names, comments and code flow.
182      *
183      */
184
185
186      /**
187      * Convert Ipv6Address object to a valid Canonical v6 address in byte format
188      *
189      * @param ipv6Address - v6 Address object
190      * @return - byte array of size 16. Last byte contains netmask
191      */
192
193
194     public static byte[] canonicalBinaryV6Address(Ipv6Address ipv6Address) {
195         /* 
196          * Do not modify this routine to take direct strings input!!!
197          * Key checks have been removed based on the assumption that
198          * the input is validated via regexps in Ipv6Prefix()
199          */
200
201         String [] address =  (ipv6Address.getValue()).split("%");
202
203         int colonp;
204         char ch;
205         boolean saw_xdigit;
206
207         /* Isn't it fun - the above variable names are the same in BSD and Sun sources */
208
209         int val;
210
211         char[] src = address[0].toCharArray();
212
213         byte[] dst = new byte[INADDR6SZ];
214
215         int src_length = src.length;
216
217         colonp = -1;
218         int i = 0, j = 0;
219
220         /* Leading :: requires some special handling. */
221
222         /* Isn't it fun - the above comment is again the same in BSD and Sun sources,
223          * We will derive our code from BSD. Shakespear always sounds better
224          * in original Clingon. So does Dilbert.
225          */
226
227         if (src[i] == ':') {
228             Preconditions.checkArgument(src[++i] == ':', "Invalid v6 address");
229         }
230
231         int curtok = i;
232         saw_xdigit = false;
233
234
235         val = 0;
236         while (i < src_length) {
237             ch = src[i++];
238             int chval = Character.digit(ch, 16);
239
240             /* Business as usual - ipv6 address digit.
241              * We can remove all checks from the original BSD code because
242              * the regexp has already verified that we are not being fed
243              * anything bigger than 0xffff between the separators.
244              */
245
246             if (chval != -1) {
247                 val <<= 4;
248                 val |= chval;
249                 saw_xdigit = true;
250                 continue;
251             }
252
253             /* v6 separator */
254
255             if (ch == ':') {
256                 curtok = i;
257                 if (!saw_xdigit) {
258                     /* no need to check separator position validity - regexp does that */
259                     colonp = j;
260                     continue;
261                 }
262
263                 /* removed overrun check - the regexp checks for valid data */
264
265                 dst[j++] = (byte) ((val >> 8) & 0xff);
266                 dst[j++] = (byte) (val & 0xff);
267                 saw_xdigit = false;
268                 val = 0;
269                 continue;
270             }
271
272             /* frankenstein - v4 attached to v6, mixed notation */
273
274             if (ch == '.' && ((j + INADDR4SZ) <= INADDR6SZ)) {
275
276                 /* this has passed the regexp so it is fairly safe to parse it
277                  * straight away. As v4 addresses do not suffer from the same
278                  * defficiencies as the java v6 implementation we can invoke it
279                  * straight away and be done with it
280                  */
281
282                 Preconditions.checkArgument(j != (INADDR6SZ - INADDR4SZ - 1), "Invalid v4 in v6 mapping");
283
284                 InetAddress _inet_form = InetAddresses.forString(address[0].substring(curtok, src_length));
285
286                 Preconditions.checkArgument(_inet_form instanceof Inet4Address);
287
288                 byte[] v4addr =  _inet_form.getAddress();
289
290                 for (int k = 0; k < INADDR4SZ; k++) {
291                     dst[j++] = v4addr[k];
292                 }
293                 saw_xdigit = false;
294                 break;
295             }
296             /* removed parser exit on ivalid char - no need to do it, regexp checks it */
297         }
298         if (saw_xdigit) {
299             Preconditions.checkArgument(j + INT16SZ <= INADDR6SZ, "Overrun in v6 parsing, should not occur");
300             dst[j++] = (byte) ((val >> 8) & 0xff);
301             dst[j++] = (byte) (val & 0xff);
302         }
303
304         if (colonp != -1) {
305             int n = j - colonp;
306
307             Preconditions.checkArgument(j != INADDR6SZ, "Overrun in v6 parsing, should not occur");
308             for (i = 1; i <= n; i++) {
309                 dst[INADDR6SZ - i] = dst[colonp + n - i];
310                 dst[colonp + n - i] = 0;
311             }
312             j = INADDR6SZ;
313         }
314
315         Preconditions.checkArgument(j == INADDR6SZ, "Overrun in v6 parsing, should not occur");
316
317         return dst;
318     }
319
320     static public String byteArrayV6AddressToString (byte [] _binary_form) throws UnknownHostException{
321         /* DO NOT DIY!!! - InetAddresses will actually print correct canonical
322          * zero compressed form. 
323          */
324         return InetAddresses.toAddrString(InetAddress.getByAddress(_binary_form));
325     }
326     
327
328     static private int nextNibble(int mask) {
329         if (mask <= 0) {
330             return 0;
331         }
332         if (mask > 8) {
333             return 0xff;
334         }
335         return 0xff << (8 - mask);
336     }
337
338      /**
339      * Convert Ipv6Prefix object to a valid Canonical v6 prefix in byte format
340      *
341      * @param ipv6Prefix - v6 prefix object
342      * @return - byte array of size 16 + 1. Last byte contains netmask
343      */
344
345
346     public static byte[] canonicalBinaryV6Prefix(Ipv6Prefix ipv6Prefix) {
347         /* 
348          * Do not modify this routine to take direct strings input!!!
349          * Key checks have been removed based on the assumption that
350          * the input is validated via regexps in Ipv6Prefix()
351          */
352
353         int mask = 128;
354
355         String [] address = null; 
356
357         boolean valid = true;
358
359         address =  (ipv6Prefix.getValue()).split("/");
360         try {
361             mask = Integer.parseInt(address[1]);
362             if (mask > 128) {
363                 valid = false;
364             }
365         } catch (NumberFormatException | ArrayIndexOutOfBoundsException e) {
366             valid = false;
367         }
368
369         Preconditions.checkArgument(valid, "Supplied netmask in %s is invalid", ipv6Prefix.getValue());
370
371     
372         int colonp;
373         char ch;
374         boolean saw_xdigit;
375
376         /* Isn't it fun - the above variable names are the same in BSD and Sun sources */
377
378         int val;
379
380         char[] src = address[0].toCharArray();
381
382         byte[] dst = new byte[INADDR6SZ + 1];
383
384         int m = mask;
385
386         int src_length = src.length;
387
388         colonp = -1;
389         int i = 0, j = 0;
390
391         /* Leading :: requires some special handling. */
392
393         /* Isn't it fun - the above comment is again the same in BSD and Sun sources,
394          * We will derive our code from BSD. Shakespear always sounds better
395          * in original Clingon. So does Dilbert.
396          */
397
398         if (src[i] == ':') {
399             Preconditions.checkArgument(src[++i] == ':', "Invalid v6 address");
400         }
401
402         int curtok = i;
403         saw_xdigit = false;
404
405
406         val = 0;
407         while (i < src_length) {
408             ch = src[i++];
409             int chval = Character.digit(ch, 16);
410
411             /* Business as usual - ipv6 address digit.
412              * We can remove all checks from the original BSD code because
413              * the regexp has already verified that we are not being fed
414              * anything bigger than 0xffff between the separators.
415              */
416
417             if (chval != -1) {
418                 val <<= 4;
419                 val |= chval;
420                 saw_xdigit = true;
421                 continue;
422             }
423
424             /* v6 separator */
425
426             if (ch == ':') {
427                 curtok = i;
428                 if (!saw_xdigit) {
429                     /* no need to check separator position validity - regexp does that */
430                     colonp = j;
431                     continue;
432                 }
433
434                 /* removed overrun check - the regexp checks for valid data */
435
436                 saw_xdigit = false;
437
438                 if (m < 0) {
439                     /* stop parsing if we are past the mask */
440                     break;
441                 }
442
443                 dst[j] = (byte) ((val >> 8) & nextNibble(m)); j++; m = m - 8;
444
445                 if (m < 0) {
446                     /* stop parsing if we are past the mask */
447                     break;
448                 }
449
450                 dst[j] = (byte) (val & nextNibble(m)); j++; m = m - 8;
451
452                 val = 0;
453                 continue;
454             }
455
456             /* frankenstein - v4 attached to v6, mixed notation */
457
458             if (ch == '.' && ((j + INADDR4SZ) <= INADDR6SZ)) {
459
460                 /* this has passed the regexp so it is fairly safe to parse it
461                  * straight away. As v4 addresses do not suffer from the same
462                  * defficiencies as the java v6 implementation we can invoke it
463                  * straight away and be done with it
464                  */
465
466                 Preconditions.checkArgument(j != (INADDR6SZ - INADDR4SZ - 1), "Invalid v4 in v6 mapping");
467
468                 InetAddress _inet_form = InetAddresses.forString(address[0].substring(curtok, src_length));
469
470                 Preconditions.checkArgument(_inet_form instanceof Inet4Address);
471
472                 byte[] v4addr =  _inet_form.getAddress();
473
474                 for (int k = 0; k < INADDR4SZ; k++) {
475                     dst[j++] = v4addr[k];
476                 }
477                 saw_xdigit = false;
478                 break;
479             }
480             /* removed parser exit on ivalid char - no need to do it, regexp checks it */
481         }
482         if (saw_xdigit) {
483             Preconditions.checkArgument(j + INT16SZ <= INADDR6SZ, "Overrun in v6 parsing, should not occur");
484             dst[j] = (byte) ((val >> 8) & nextNibble(m)) ; j++; m = m - 8;
485             dst[j] = (byte) (val & nextNibble(m)); j++; m = m - 8;
486         }
487
488         if ((j < INADDR6SZ) && (m < 0)) {
489             /* past the mask */
490             for (i = j; i < INADDR6SZ; i++) {
491                 dst[i] = 0;
492             }
493         } else {
494             /* normal parsing */
495             if (colonp != -1) {
496                 int n = j - colonp;
497
498                 Preconditions.checkArgument(j != INADDR6SZ, "Overrun in v6 parsing, should not occur");
499                 for (i = 1; i <= n; i++) {
500                     dst[INADDR6SZ - i] = dst[colonp + n - i];
501                     dst[colonp + n - i] = 0;
502                 }
503                 j = INADDR6SZ;
504             }
505             Preconditions.checkArgument(j == INADDR6SZ, "Overrun in v6 parsing, should not occur");
506         }
507
508         dst[INADDR6SZ] = (byte) mask;
509         return dst;
510     }
511
512      /**
513      * Print a v6 prefix in byte array + 1 notation
514      *
515      * @param _binary_form - prefix, in byte [] form, last byte is netmask
516      */
517
518
519     static public String byteArrayV6PrefixToString(byte [] _binary_form) throws UnknownHostException {
520         /* NO DIY!!! - InetAddresses will actually print correct canonical
521          * zero compressed form
522          */
523         StringBuilder sb = new java.lang.StringBuilder();
524         /* Yang RFC specifies that the normalized form is RFC 5952, note - java
525          * core type is not RFC compliant, guava is.
526          */
527         sb.append(
528             InetAddresses.toAddrString(
529                 InetAddress.getByAddress(
530                     Arrays.copyOfRange(_binary_form, 0, INADDR6SZ)
531                 )
532             )
533         );
534         sb.append("/");
535         sb.append(_binary_form[INADDR6SZ] & 0xff);
536         return sb.toString();
537     }
538
539
540      /**
541      * Canonicalize a v6 prefix while in binary form
542      *
543      * @param _prefix - prefix, in byte [] form
544      * @param mask - mask - number of bits
545      */
546
547     static public void canonicalizeIpv6Prefix(byte [] _prefix, int mask) {
548
549         for (int i=0; i < INADDR6SZ; i++) {
550             _prefix[i] = (byte) (_prefix[i] & nextNibble(mask));
551             mask = mask - 8;
552         }
553     }
554
555     public static byte[] convertIpv6PrefixToByteArray(int prefix) {
556         byte[] mask = new byte[16];
557         for (int count = 0; count < 16; count++) {
558             mask[count] = (byte) nextNibble(prefix);
559             prefix = prefix - 8;
560         }
561         return mask;
562     }
563
564     public static Ipv6Address extractIpv6Address(final Ipv6Prefix ipv6Prefix) {
565         Iterator<String> addressParts = PREFIX_SPLITTER.split(ipv6Prefix.getValue()).iterator();
566         return new Ipv6Address(addressParts.next());
567     }
568
569     public static Integer extractIpv6Prefix(final Ipv6Prefix ipv6Prefix) {
570         Iterator<String> addressParts = PREFIX_SPLITTER.split(ipv6Prefix.getValue()).iterator();
571         addressParts.next();
572
573         Integer prefix = null;
574         if (addressParts.hasNext()) {
575             prefix = Integer.parseInt(addressParts.next());
576         }
577         return prefix;
578     }
579
580     private static int toInt(byte b) {
581         return b < 0 ? b + 256 : b;
582     }
583
584     public static int countBits(byte[] mask) {
585         int netmask = 0;
586         for (byte b : mask) {
587             netmask += Integer.bitCount(toInt(b));
588         }
589         return netmask;
590     }
591
592
593
594 }