Initial code drop
[bgpcep.git] / bgp / parser-impl / src / main / java / org / opendaylight / protocol / bgp / parser / impl / message / update / CommunitiesParser.java
1 /*
2  * Copyright (c) 2013 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
9 package org.opendaylight.protocol.bgp.parser.impl.message.update;
10
11 import java.util.Arrays;
12
13 import org.opendaylight.protocol.bgp.concepts.ASSpecificExtendedCommunity;
14 import org.opendaylight.protocol.bgp.concepts.Community;
15 import org.opendaylight.protocol.bgp.concepts.ExtendedCommunity;
16 import org.opendaylight.protocol.bgp.concepts.Inet4SpecificExtendedCommunity;
17 import org.opendaylight.protocol.bgp.concepts.OpaqueExtendedCommunity;
18 import org.opendaylight.protocol.bgp.concepts.RouteOriginCommunity;
19 import org.opendaylight.protocol.bgp.concepts.RouteTargetCommunity;
20 import org.opendaylight.protocol.bgp.parser.BGPDocumentedException;
21 import org.opendaylight.protocol.bgp.parser.BGPError;
22 import org.opendaylight.protocol.util.ByteArray;
23 import org.opendaylight.protocol.concepts.ASNumber;
24 import org.opendaylight.protocol.concepts.IPv4Address;
25 import com.google.common.annotations.VisibleForTesting;
26 import com.google.common.primitives.UnsignedBytes;
27
28 /**
29  * Parser for Extended Communities Path Attribute.
30  */
31 public class CommunitiesParser {
32
33         public static final int EXTENDED_COMMUNITY_LENGTH = 8; // bytes
34
35         public static final int COMMUNITY_LENGTH = 4; // bytes
36
37         private static final int TYPE_LENGTH = 2; // bytes
38
39         private static final int AS_NUMBER_LENGTH = 2; // bytes
40
41         private static final int AS_LOCAL_ADMIN_LENGTH = 4; // bytes
42
43         private CommunitiesParser() {
44
45         }
46
47         /**
48          * Parse known Community, if unknown, a new one will be created.
49          * 
50          * @param bytes byte array to be parsed
51          * @return new Community
52          * @throws BGPDocumentedException
53          */
54         static Community parseCommunity(final byte[] bytes) throws BGPDocumentedException {
55                 if (bytes.length != COMMUNITY_LENGTH)
56                         throw new BGPDocumentedException("Community with wrong length: " + bytes.length, BGPError.OPT_ATTR_ERROR);
57                 if (Arrays.equals(bytes, new byte[] { (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x01 })) {
58                         return Community.NO_EXPORT;
59                 } else if (Arrays.equals(bytes, new byte[] { (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x02 })) {
60                         return Community.NO_ADVERTISE;
61                 } else if (Arrays.equals(bytes, new byte[] { (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x03 })) {
62                         return Community.NO_EXPORT_SUBCONFED;
63                 }
64                 return new Community(new ASNumber(ByteArray.bytesToLong(Arrays.copyOfRange(bytes, 0, AS_NUMBER_LENGTH))), ByteArray.bytesToInt(Arrays.copyOfRange(
65                                 bytes, AS_NUMBER_LENGTH, AS_NUMBER_LENGTH + AS_NUMBER_LENGTH)));
66         }
67
68         /**
69          * Parse Extended Community according to their type.
70          * 
71          * @param bytes byte array to be parsed
72          * @return new Specific Extended Community
73          * @throws BGPDocumentedException if the type is not recognized
74          */
75         @VisibleForTesting
76         public static ExtendedCommunity parseExtendedCommunity(final byte[] bytes) throws BGPDocumentedException {
77                 // final int type = ByteArray.bytesToInt(ByteArray.subByte(bytes, 0, TYPE_LENGTH));
78                 final int type = UnsignedBytes.toInt(bytes[0]);
79                 final int subType = UnsignedBytes.toInt(bytes[1]);
80                 final byte[] value = ByteArray.subByte(bytes, TYPE_LENGTH, bytes.length - TYPE_LENGTH);
81                 switch (type) {
82                 case 0:
83                         if (subType == 2) {
84                                 return new RouteTargetCommunity(new ASNumber(ByteArray.bytesToInt(ByteArray.subByte(value, 0, AS_NUMBER_LENGTH))), ByteArray.subByte(
85                                                 value, AS_NUMBER_LENGTH, AS_LOCAL_ADMIN_LENGTH));
86                         } else if (subType == 3) {
87                                 return new RouteOriginCommunity(new ASNumber(ByteArray.bytesToInt(ByteArray.subByte(value, 0, AS_NUMBER_LENGTH))), ByteArray.subByte(
88                                                 value, AS_NUMBER_LENGTH, AS_LOCAL_ADMIN_LENGTH));
89                         } else
90                                 return new ASSpecificExtendedCommunity(false, subType, new ASNumber(ByteArray.bytesToInt(ByteArray.subByte(value, 0,
91                                                 AS_NUMBER_LENGTH))), ByteArray.subByte(value, AS_NUMBER_LENGTH, AS_LOCAL_ADMIN_LENGTH));
92                 case 40: // 01000000
93                         return new ASSpecificExtendedCommunity(true, subType, new ASNumber(ByteArray.bytesToInt(ByteArray.subByte(value, 0,
94                                         AS_NUMBER_LENGTH))), ByteArray.subByte(value, AS_NUMBER_LENGTH, AS_LOCAL_ADMIN_LENGTH));
95                 case 2:
96                         if (subType == 2) {
97                                 return new RouteTargetCommunity(new ASNumber(ByteArray.bytesToInt(ByteArray.subByte(value, 0, AS_NUMBER_LENGTH))), ByteArray.subByte(
98                                                 value, AS_NUMBER_LENGTH, AS_LOCAL_ADMIN_LENGTH));
99                         } else if (subType == 3) {
100                                 return new RouteOriginCommunity(new ASNumber(ByteArray.bytesToInt(ByteArray.subByte(value, 0, AS_NUMBER_LENGTH))), ByteArray.subByte(
101                                                 value, AS_NUMBER_LENGTH, AS_LOCAL_ADMIN_LENGTH));
102                         } else
103                                 throw new BGPDocumentedException("Could not parse Extended Community subtype: " + subType, BGPError.OPT_ATTR_ERROR);
104                 case 1:
105                         if (subType == 2) {
106                                 return new RouteTargetCommunity(new ASNumber(ByteArray.bytesToInt(ByteArray.subByte(value, 0, AS_NUMBER_LENGTH))), ByteArray.subByte(
107                                                 value, AS_NUMBER_LENGTH, AS_LOCAL_ADMIN_LENGTH));
108                         } else if (subType == 3) {
109                                 return new RouteOriginCommunity(new ASNumber(ByteArray.bytesToInt(ByteArray.subByte(value, 0, AS_NUMBER_LENGTH))), ByteArray.subByte(
110                                                 value, AS_NUMBER_LENGTH, AS_LOCAL_ADMIN_LENGTH));
111                         } else
112                                 return new Inet4SpecificExtendedCommunity(false, subType, new IPv4Address(ByteArray.subByte(value, 0, 4)), ByteArray.subByte(
113                                                 value, 4, 2));
114                 case 41: // 01000001
115                         return new Inet4SpecificExtendedCommunity(true, subType, new IPv4Address(ByteArray.subByte(value, 0, 4)), ByteArray.subByte(
116                                         value, 4, 2));
117                 case 3:
118                         return new OpaqueExtendedCommunity(false, subType, value);
119                 case 43: // 01000011
120                         return new OpaqueExtendedCommunity(true, subType, value);
121                 default:
122                         throw new BGPDocumentedException("Could not parse Extended Community type: " + type, BGPError.OPT_ATTR_ERROR);
123                 }
124         }
125 }