Bug-731: Fixed few major Sonar warnings
[bgpcep.git] / bgp / parser-impl / src / main / java / org / opendaylight / protocol / bgp / parser / impl / message / BGPOpenMessageParser.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 package org.opendaylight.protocol.bgp.parser.impl.message;
9
10 import com.google.common.base.Preconditions;
11 import io.netty.buffer.ByteBuf;
12 import io.netty.buffer.ByteBufUtil;
13 import io.netty.buffer.Unpooled;
14 import java.util.ArrayList;
15 import java.util.Arrays;
16 import java.util.List;
17 import org.opendaylight.protocol.bgp.parser.BGPDocumentedException;
18 import org.opendaylight.protocol.bgp.parser.BGPError;
19 import org.opendaylight.protocol.bgp.parser.BGPParsingException;
20 import org.opendaylight.protocol.bgp.parser.spi.MessageParser;
21 import org.opendaylight.protocol.bgp.parser.spi.MessageSerializer;
22 import org.opendaylight.protocol.bgp.parser.spi.MessageUtil;
23 import org.opendaylight.protocol.bgp.parser.spi.ParameterRegistry;
24 import org.opendaylight.protocol.util.Ipv4Util;
25 import org.opendaylight.protocol.util.Values;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.AsNumber;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.Open;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.OpenBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.BgpParameters;
31 import org.opendaylight.yangtools.yang.binding.Notification;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35 /**
36  * Parser for BGP Open message.
37  */
38 public final class BGPOpenMessageParser implements MessageParser, MessageSerializer {
39     public static final int TYPE = 1;
40
41     private static final Logger LOG = LoggerFactory.getLogger(BGPOpenMessageParser.class);
42
43     private static final int VERSION_SIZE = 1;
44     private static final int AS_SIZE = 2;
45     private static final int HOLD_TIME_SIZE = 2;
46     private static final int BGP_ID_SIZE = 4;
47     private static final int OPT_PARAM_LENGTH_SIZE = 1;
48
49     private static final int MIN_MSG_LENGTH = VERSION_SIZE + AS_SIZE + HOLD_TIME_SIZE + BGP_ID_SIZE + OPT_PARAM_LENGTH_SIZE;
50
51     private static final int BGP_VERSION = 4;
52
53     private static final int AS_TRANS = 2345;
54
55     private final ParameterRegistry reg;
56
57     public BGPOpenMessageParser(final ParameterRegistry reg) {
58         this.reg = Preconditions.checkNotNull(reg);
59     }
60
61     /**
62      * Serializes given BGP Open message to byte array, without the header.
63      *
64      * @param msg BGP Open message to be serialized.
65      * @param bytes ByteBuf where the message will be serialized
66      */
67     @Override
68     public void serializeMessage(final Notification msg, final ByteBuf bytes) {
69         Preconditions.checkArgument(msg instanceof Open, "BGP Open message cannot be null");
70         LOG.trace("Started serializing open message: {}", msg);
71         final Open open = (Open) msg;
72         final ByteBuf msgBody = Unpooled.buffer();
73
74         msgBody.writeByte(BGP_VERSION);
75
76         // When our AS number does not fit into two bytes, we report it as AS_TRANS
77         int openAS = open.getMyAsNumber();
78         if (openAS > Values.UNSIGNED_SHORT_MAX_VALUE) {
79             openAS = AS_TRANS;
80         }
81         msgBody.writeShort(openAS);
82         msgBody.writeShort(open.getHoldTimer());
83         msgBody.writeBytes(Ipv4Util.bytesForAddress(open.getBgpIdentifier()));
84
85         final ByteBuf paramsBuffer = Unpooled.buffer();
86         if (open.getBgpParameters() != null) {
87             for (final BgpParameters param : open.getBgpParameters()) {
88                 this.reg.serializeParameter(param, paramsBuffer);
89             }
90         }
91         msgBody.writeByte(paramsBuffer.writerIndex());
92         msgBody.writeBytes(paramsBuffer);
93
94         LOG.trace("Open message serialized to: {}", ByteBufUtil.hexDump(bytes));
95         MessageUtil.formatMessage(TYPE, msgBody, bytes);
96     }
97
98     /**
99      * Parses given byte array to BGP Open message
100      *
101      * @param body byte array representing BGP Open message, without header
102      * @return BGP Open Message
103      * @throws BGPDocumentedException if the parsing was unsuccessful
104      */
105     @Override
106     public Open parseMessageBody(final ByteBuf body, final int messageLength) throws BGPDocumentedException {
107         Preconditions.checkArgument(body != null, "Byte array cannot be null.");
108         LOG.trace("Started parsing of open message: {}", ByteBufUtil.hexDump(body));
109
110         if (body.readableBytes() < MIN_MSG_LENGTH) {
111             throw BGPDocumentedException.badMessageLength("Open message too small.", messageLength);
112         }
113         final int version = body.readUnsignedByte();
114         if (version != BGP_VERSION) {
115             throw new BGPDocumentedException("BGP Protocol version " + version + " not supported.", BGPError.VERSION_NOT_SUPPORTED);
116         }
117         final AsNumber as = new AsNumber((long) body.readUnsignedShort());
118         final int holdTime = body.readUnsignedShort();
119         if (holdTime == 1 || holdTime == 2) {
120             throw new BGPDocumentedException("Hold time value not acceptable.", BGPError.HOLD_TIME_NOT_ACC);
121         }
122         Ipv4Address bgpId = null;
123         try {
124             bgpId = Ipv4Util.addressForByteBuf(body);
125         } catch (final IllegalArgumentException e) {
126             throw new BGPDocumentedException("BGP Identifier is not a valid IPv4 Address", BGPError.BAD_BGP_ID, e);
127         }
128         final int optLength = body.readUnsignedByte();
129
130         final List<BgpParameters> optParams = new ArrayList<>();
131         if (optLength > 0) {
132             fillParams(body.slice(body.readerIndex(), optLength), optParams);
133         }
134         LOG.debug("BGP Open message was parsed: AS = {}, holdTimer = {}, bgpId = {}, optParams = {}", as, holdTime, bgpId, optParams);
135         return new OpenBuilder().setMyAsNumber(as.getValue().intValue()).setHoldTimer(holdTime).setBgpIdentifier(bgpId).setBgpParameters(
136             optParams).build();
137     }
138
139     private void fillParams(final ByteBuf buffer, final List<BgpParameters> params) throws BGPDocumentedException {
140         Preconditions.checkArgument(buffer != null && buffer.isReadable(), "Byte array cannot be null or empty.");
141         LOG.trace("Started parsing of BGP parameter: {}", ByteBufUtil.hexDump(buffer));
142         while (buffer.isReadable()) {
143             if (buffer.readableBytes() <= 2) {
144                 throw new BGPDocumentedException("Malformed parameter encountered (" + buffer.readableBytes() + " bytes left)", BGPError.OPT_PARAM_NOT_SUPPORTED);
145             }
146             final int paramType = buffer.readUnsignedByte();
147             final int paramLength = buffer.readUnsignedByte();
148             final ByteBuf paramBody = buffer.slice(buffer.readerIndex(), paramLength);
149
150             final BgpParameters param;
151             try {
152                 param = this.reg.parseParameter(paramType, paramBody);
153             } catch (final BGPParsingException e) {
154                 throw new BGPDocumentedException("Optional parameter not parsed", BGPError.UNSPECIFIC_OPEN_ERROR, e);
155             }
156             if (param != null) {
157                 params.add(param);
158             } else {
159                 LOG.debug("Ignoring BGP Parameter type: {}", paramType);
160             }
161             buffer.skipBytes(paramLength);
162         }
163         LOG.trace("Parsed BGP parameters: {}", Arrays.toString(params.toArray()));
164     }
165 }