99a9627fb3f01e3cba89d1a45536e6f7a973b70c
[bgpcep.git] / bgp / concepts / src / main / java / org / opendaylight / bgp / concepts / RouteDistinguisherUtil.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.bgp.concepts;
9
10 import static java.util.Objects.requireNonNull;
11
12 import com.google.common.base.Preconditions;
13 import io.netty.buffer.ByteBuf;
14 import org.opendaylight.protocol.util.ByteBufWriteUtil;
15 import org.opendaylight.protocol.util.Ipv4Util;
16 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.RdAs;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.RdIpv4;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.RdTwoOctetAs;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.RouteDistinguisher;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.RouteDistinguisherBuilder;
22 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
23 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
24 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
25 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
28
29 /**
30  * Utility class for of RouteDistinguisher serialization and parsing.
31  * https://tools.ietf.org/html/rfc4364#section-4.2
32  */
33 public final class RouteDistinguisherUtil {
34     public static final int RD_LENGTH = 8;
35     private static final Logger LOG = LoggerFactory.getLogger(RouteDistinguisherUtil.class);
36     private static final String SEPARATOR = ":";
37
38     private RouteDistinguisherUtil() {
39         throw new UnsupportedOperationException();
40     }
41
42     /**
43      * Serializes route distinguisher according to type and writes into ByteBuf.
44      */
45     public static void serializeRouteDistinquisher(final RouteDistinguisher distinguisher,
46             final ByteBuf byteAggregator) {
47         requireNonNull(distinguisher);
48         Preconditions.checkState(byteAggregator != null && byteAggregator.isWritable(RD_LENGTH),
49                 "Cannot write Route Distinguisher to provided buffer.");
50         if (distinguisher.getRdTwoOctetAs() != null) {
51             final String[] values = distinguisher.getRdTwoOctetAs().getValue().split(SEPARATOR);
52             byteAggregator.writeShort(RDType.AS_2BYTE.value);
53             ByteBufWriteUtil.writeUnsignedShort(Integer.parseInt(values[1]), byteAggregator);
54             final long assignedNumber = Integer.parseUnsignedInt(values[2]);
55             ByteBufWriteUtil.writeUnsignedInt(assignedNumber, byteAggregator);
56         } else if (distinguisher.getRdAs() != null) {
57             final String[] values = distinguisher.getRdAs().getValue().split(SEPARATOR);
58             byteAggregator.writeShort(RDType.AS_4BYTE.value);
59             final long admin = Integer.parseUnsignedInt(values[0]);
60             ByteBufWriteUtil.writeUnsignedInt(admin, byteAggregator);
61             ByteBufWriteUtil.writeUnsignedShort(Integer.parseInt(values[1]), byteAggregator);
62         } else if (distinguisher.getRdIpv4() != null) {
63             final String[] values = distinguisher.getRdIpv4().getValue().split(SEPARATOR);
64             final Ipv4Address ip = new Ipv4Address(values[0]);
65             byteAggregator.writeShort(RDType.IPV4.value);
66             ByteBufWriteUtil.writeIpv4Address(ip, byteAggregator);
67             ByteBufWriteUtil.writeUnsignedShort(Integer.parseInt(values[1]), byteAggregator);
68         } else {
69             LOG.warn("Unable to serialize Route Distinguisher. Invalid RD value found. RD={}", distinguisher);
70         }
71     }
72
73     /**
74      * Parses three types of route distinguisher from given ByteBuf.
75      */
76     public static RouteDistinguisher parseRouteDistinguisher(final ByteBuf buffer) {
77         Preconditions.checkState(buffer != null && buffer.isReadable(RD_LENGTH),
78                 "Cannot read Route Distinguisher from provided buffer.");
79         final int type = buffer.readUnsignedShort();
80         final RDType rdType = RDType.valueOf(type);
81         final StringBuilder routeDistiguisher = new StringBuilder();
82         switch (rdType) {
83             case AS_2BYTE:
84                 routeDistiguisher.append(type);
85                 routeDistiguisher.append(SEPARATOR);
86                 routeDistiguisher.append(buffer.readUnsignedShort());
87                 routeDistiguisher.append(SEPARATOR);
88                 routeDistiguisher.append(buffer.readUnsignedInt());
89                 return new RouteDistinguisher(new RdTwoOctetAs(routeDistiguisher.toString()));
90             case IPV4:
91                 routeDistiguisher.append(Ipv4Util.addressForByteBuf(buffer).getValue());
92                 routeDistiguisher.append(SEPARATOR);
93                 routeDistiguisher.append(buffer.readUnsignedShort());
94                 return new RouteDistinguisher(new RdIpv4(routeDistiguisher.toString()));
95             case AS_4BYTE:
96                 routeDistiguisher.append(buffer.readUnsignedInt());
97                 routeDistiguisher.append(SEPARATOR);
98                 routeDistiguisher.append(buffer.readUnsignedShort());
99                 return new RouteDistinguisher(new RdAs(routeDistiguisher.toString()));
100             default:
101                 // now that this RD type is not supported, we want to read the remain 6 bytes
102                 // in order to get the byte index correct
103                 for (int i = 0; i < 6; i++) {
104                     routeDistiguisher.append("0x").append(Integer.toHexString(buffer.readByte() & 0xFF)).append(" ");
105                 }
106                 LOG.debug("Invalid Route Distinguisher: type={}, rawRouteDistinguisherValue={}", type,
107                         routeDistiguisher.toString());
108                 throw new IllegalArgumentException("Invalid Route Distinguisher type " + type);
109         }
110     }
111
112     public static RouteDistinguisher parseRouteDistinguisher(final String str) {
113         return str == null ? null : RouteDistinguisherBuilder.getDefaultInstance(str);
114     }
115
116     public static RouteDistinguisher parseRouteDistinguisher(final Object obj) {
117         if (obj instanceof String) {
118             return RouteDistinguisherBuilder.getDefaultInstance((String) obj);
119         } else if (obj instanceof RouteDistinguisher) {
120             return (RouteDistinguisher) obj;
121         } else {
122             return null;
123         }
124     }
125
126     public static RouteDistinguisher extractRouteDistinguisher(final DataContainerNode<?> route,
127             final NodeIdentifier rdNid) {
128         final NormalizedNode<?, ?> rdNode = NormalizedNodes.findNode(route, rdNid).orNull();
129         if (rdNode != null) {
130             return parseRouteDistinguisher(rdNode.getValue());
131         }
132         return null;
133     }
134
135     private enum RDType {
136         AS_2BYTE(0),
137         IPV4(1),
138         AS_4BYTE(2),
139         INVALID(-1);
140
141         public final int value;
142
143         RDType(int val) {
144             this.value = val;
145         }
146
147         public static RDType valueOf(final int value) {
148             for (RDType type : values()) {
149                 if (type.value == value) {
150                     return type;
151                 }
152             }
153             return INVALID;
154         }
155     }
156 }