import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import com.google.common.collect.Lists;
import org.junit.BeforeClass;
import org.junit.Test;
import org.opendaylight.protocol.bgp.parser.spi.MessageRegistry;
+import org.opendaylight.protocol.bgp.parser.spi.RevisedErrorHandlingSupport;
+import org.opendaylight.protocol.bgp.parser.spi.pojo.PeerSpecificParserConstraintImpl;
+import org.opendaylight.protocol.bgp.parser.spi.pojo.RevisedErrorHandlingSupportImpl;
import org.opendaylight.protocol.bgp.parser.spi.pojo.ServiceLoaderBGPExtensionProviderContext;
import org.opendaylight.protocol.util.ByteArray;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path.attributes.attributes.OriginatorIdBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path.attributes.attributes.as.path.Segments;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path.attributes.attributes.as.path.SegmentsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.update.message.WithdrawnRoutes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.Attributes1;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.Attributes1Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.Attributes2;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.MpReachNlriBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.MpUnreachNlri;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.mp.reach.nlri.AdvertizedRoutesBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.BgpOrigin;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.ClusterIdentifier;
private static MessageRegistry messageRegistry;
- private static byte[] input;
+ private static List<byte[]> input;
+
+ private static int MESSAGE_COUNT = 2;
@BeforeClass
public static void setUp() throws Exception {
messageRegistry = ServiceLoaderBGPExtensionProviderContext.getSingletonInstance().getMessageRegistry();
-
- final String name = "/up2.bin";
- try (InputStream is = BGPParserTest.class.getResourceAsStream(name)) {
- if (is == null) {
- throw new IOException("Failed to get resource " + name);
- }
- final ByteArrayOutputStream bis = new ByteArrayOutputStream();
- final byte[] data = new byte[MAX_SIZE];
- int position;
- while ((position = is.read(data, 0, data.length)) != -1) {
- bis.write(data, 0, position);
+ input = new ArrayList<>(MESSAGE_COUNT);
+ for (int i = 1; i <= MESSAGE_COUNT; i++) {
+
+ final String name = "/up" + i + ".bin";
+ try (InputStream is = BGPParserTest.class.getResourceAsStream(name)) {
+ if (is == null) {
+ throw new IOException("Failed to get resource " + name);
+ }
+ final ByteArrayOutputStream bis = new ByteArrayOutputStream();
+ final byte[] data = new byte[MAX_SIZE];
+ int position;
+ while ((position = is.read(data, 0, data.length)) != -1) {
+ bis.write(data, 0, position);
+ }
+ bis.flush();
+
+ input.add(bis.toByteArray());
+ is.close();
}
- bis.flush();
-
- input = bis.toByteArray();
- is.close();
}
}
*/
@Test
public void testIPv6Nlri() throws Exception {
- final Update message = (Update) messageRegistry.parseMessage(Unpooled.wrappedBuffer(input), null);
+ final Update message = (Update) messageRegistry.parseMessage(Unpooled.wrappedBuffer(input.get(1)), null);
// check fields
assertNull(message.getWithdrawnRoutes());
final ByteBuf buffer = Unpooled.buffer();
messageRegistry.serializeMessage(message, buffer);
- assertArrayEquals(input, ByteArray.readAllBytes(buffer));
+ assertArrayEquals(input.get(1), ByteArray.readAllBytes(buffer));
}
+ /*
+ * Tests withdrawn routes with malformed attribute.
+ *
+ * ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff <- marker
+ * 00 36 <- length (54) - including header
+ * 02 <- message type
+ * 00 00 <- withdrawn routes length
+ * 00 1b <- total path attribute length (27)
+ * 40 <- attribute flags
+ * 01 <- attribute type code (origin)
+ * 01 <- WRONG attribute length
+ * 00 <- Origin value (IGP)
+ * 40 <- attribute flags
+ * 03 <- attribute type code (Next Hop)
+ * 04 <- attribute length
+ * 0a 00 00 02 <- value (10.0.0.2)
+ * 40 <- attribute flags
+ * 0e <- attribute type code (MP_REACH)
+ * 0d <- attribute length
+ * 00 01 <- AFI (Ipv4)
+ * 01 <- SAFI (Unicast)
+ * 04 <- next hop length
+ * ff ff ff ff <- next hop
+ * 00 <- reserved
+ * 18 <- length
+ * 0a 00 01 <- prefix (10.0.1.0)
+ * //NLRI
+ * 18 <- length
+ * 0a 00 02 <- prefix (10.0.2.0)
+ */
+ @Test
+ public void testParseUpdateMessageWithMalformedAttributes() throws Exception {
+ final PeerSpecificParserConstraintImpl constraint = new PeerSpecificParserConstraintImpl();
+ constraint.addPeerConstraint(RevisedErrorHandlingSupport.class,
+ RevisedErrorHandlingSupportImpl.forExternalPeer());
+ final Update message = (Update) messageRegistry.parseMessage(Unpooled.wrappedBuffer(input.get(0)), constraint);
+ assertNotNull(message);
+ assertNull(message.getNlri());
+ final List<WithdrawnRoutes> withdrawnRoutes = message.getWithdrawnRoutes();
+ assertNotNull(withdrawnRoutes);
+ assertEquals(1, withdrawnRoutes.size());
+ final Attributes attributes = message.getAttributes();
+ assertNotNull(attributes);
+ assertNull(attributes.augmentation(Attributes1.class));
+ final Attributes2 attributes2 = attributes.augmentation(Attributes2.class);
+ assertNotNull(attributes2);
+ final MpUnreachNlri mpUnreachNlri = attributes2.getMpUnreachNlri();
+ assertNotNull(mpUnreachNlri);
+ }
}
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.Mockito;
+import org.opendaylight.protocol.bgp.parser.BGPDocumentedException;
import org.opendaylight.protocol.bgp.parser.impl.message.BGPUpdateMessageParser;
import org.opendaylight.protocol.bgp.parser.impl.message.update.CommunityUtil;
import org.opendaylight.protocol.bgp.parser.spi.MessageUtil;
import org.opendaylight.protocol.bgp.parser.spi.MultiPathSupport;
import org.opendaylight.protocol.bgp.parser.spi.NlriRegistry;
import org.opendaylight.protocol.bgp.parser.spi.PeerSpecificParserConstraint;
+import org.opendaylight.protocol.bgp.parser.spi.RevisedErrorHandlingSupport;
+import org.opendaylight.protocol.bgp.parser.spi.pojo.PeerSpecificParserConstraintImpl;
+import org.opendaylight.protocol.bgp.parser.spi.pojo.RevisedErrorHandlingSupportImpl;
import org.opendaylight.protocol.bgp.parser.spi.pojo.ServiceLoaderBGPExtensionProviderContext;
import org.opendaylight.protocol.bgp.util.HexDumpBGPFileParser;
import org.opendaylight.protocol.util.ByteArray;
public class BGPParserTest {
private static final List<byte[]> INPUT_BYTES = new ArrayList<>();
- private static final int COUNTER = 7;
+ private static final int COUNTER = 8;
private static final int MAX_SIZE = 300;
private static List<byte[]> updatesWithMultiplePath;
- private static PeerSpecificParserConstraint constraint;
+ private static PeerSpecificParserConstraint mpConstraint;
private static MultiPathSupport mpSupport;
}
updatesWithMultiplePath = HexDumpBGPFileParser.parseMessages(BGPParserTest.class.getResourceAsStream(
MULTIPATH_HEX_FILE));
- constraint = mock(PeerSpecificParserConstraint.class);
+ mpConstraint = mock(PeerSpecificParserConstraint.class);
mpSupport = mock(MultiPathSupport.class);
- Mockito.doReturn(Optional.empty()).when(constraint).getPeerConstraint(Mockito.any());
- Mockito.doReturn(Optional.of(mpSupport)).when(constraint).getPeerConstraint(MultiPathSupport.class);
+ Mockito.doReturn(Optional.empty()).when(mpConstraint).getPeerConstraint(Mockito.any());
+ Mockito.doReturn(Optional.of(mpSupport)).when(mpConstraint).getPeerConstraint(MultiPathSupport.class);
Mockito.doReturn(true).when(mpSupport).isTableTypeSupported(Mockito.any());
}
final int messageLength = ByteArray.bytesToInt(ByteArray.subByte(updatesWithMultiplePath.get(0),
MessageUtil.MARKER_LENGTH, LENGTH_FIELD_LENGTH));
final Update message = BGPParserTest.updateParser.parseMessageBody(Unpooled.copiedBuffer(body), messageLength,
- constraint);
+ mpConstraint);
// check fields
* 00 00 00 02 <- path-id (2)
* 1e ac 10 00 04 <- route (172.16.0.4)
* 00 00 <- total path attribute length
+ *
*/
@Test
public void testUpdateMessageWithdrawAddPath() throws Exception {
final int messageLength = ByteArray.bytesToInt(ByteArray.subByte(updatesWithMultiplePath.get(1),
MessageUtil.MARKER_LENGTH, LENGTH_FIELD_LENGTH));
final Update message = BGPParserTest.updateParser.parseMessageBody(Unpooled.copiedBuffer(body), messageLength,
- constraint);
+ mpConstraint);
// attributes
final List<WithdrawnRoutes> withdrawnRoutes = Lists.newArrayList();
BGPParserTest.updateParser.serializeMessage(message, buffer);
assertArrayEquals(updatesWithMultiplePath.get(1), ByteArray.readAllBytes(buffer));
}
+
+ /*
+ * Tests withdrawn routes with malformed attribute.
+ *
+ * ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff <- marker
+ * 00 35 <- length (53) - including header
+ * 02 <- message type
+ * 00 00 <- withdrawn routes length
+ * 00 1a <- total path attribute length (26)
+ * 40 <- attribute flags
+ * 01 <- attribute type code (origin)
+ * 02 <- WRONG attribute length
+ * 00 <- Origin value (IGP)
+ * 40 <- attribute flags
+ * 03 <- attribute type code (Next Hop)
+ * 04 <- attribute length
+ * 0a 00 00 02 <- value (10.0.0.2)
+ * 40 <- attribute flags
+ * 0e <- attribute type code (MP_REACH)
+ * 00 01 <- AFI (Ipv4)
+ * 01 <- SAFI (Unicast)
+ * 04 <- next hop length
+ * ff ff ff ff <- next hop
+ * 00 <- reserved
+ * 18 <- length
+ * 0a 00 01 <- prefix (10.0.1.0)
+ * //NLRI
+ * 18 <- length
+ * 0a 00 02 <- prefix (10.0.2.0)
+ */
+ @Test
+ public void testUpdateMessageWithMalformedAttribute() throws BGPDocumentedException {
+ final byte[] body = ByteArray.cutBytes(INPUT_BYTES.get(7), MessageUtil.COMMON_HEADER_LENGTH);
+ final int messageLength = ByteArray.bytesToInt(ByteArray.subByte(INPUT_BYTES.get(6), MessageUtil.MARKER_LENGTH,
+ LENGTH_FIELD_LENGTH));
+ final PeerSpecificParserConstraintImpl constraint = new PeerSpecificParserConstraintImpl();
+ constraint.addPeerConstraint(RevisedErrorHandlingSupport.class,
+ RevisedErrorHandlingSupportImpl.forExternalPeer());
+ final Update message = BGPParserTest.updateParser.parseMessageBody(Unpooled.copiedBuffer(body), messageLength,
+ constraint);
+ assertNotNull(message);
+ assertNull(message.getNlri());
+ final List<WithdrawnRoutes> withdrawnRoutes = message.getWithdrawnRoutes();
+ assertNotNull(withdrawnRoutes);
+ assertEquals(1, withdrawnRoutes.size());
+ }
}
}
private void addAttribute(final ByteBuf buffer, final RevisedErrorHandling errorHandling,
- final Map<Integer, RawAttribute> attributes) throws BGPDocumentedException {
+ final Map<Integer, RawAttribute> attributes)
+ throws BGPDocumentedException, BGPTreatAsWithdrawException {
final BitArray flags = BitArray.valueOf(buffer.readByte());
final int type = buffer.readUnsignedByte();
final int len = flags.get(EXTENDED_LENGTH_BIT) ? buffer.readUnsignedShort() : buffer.readUnsignedByte();
return;
}
+ final int readable = buffer.readableBytes();
+ if (readable < len) {
+ throw errorHandling.reportError(BGPError.MALFORMED_ATTR_LIST,
+ "Attribute {} length {} cannot be satisfied, only {} bytes are left", type, len, readable);
+ }
+
if (parser == null) {
processUnrecognized(flags, type, buffer, len);
} else {
throws BGPDocumentedException, BGPParsingException {
final RevisedErrorHandling errorHandling = RevisedErrorHandling.from(constraint);
final Map<Integer, RawAttribute> attributes = new TreeMap<>();
+ BGPTreatAsWithdrawException withdrawCause = null;
while (buffer.isReadable()) {
- addAttribute(buffer, errorHandling, attributes);
+ try {
+ addAttribute(buffer, errorHandling, attributes);
+ } catch (BGPTreatAsWithdrawException e) {
+ LOG.info("Failed to completely parse attributes list.");
+ withdrawCause = e;
+ break;
+ }
}
/*
// all attributes before we can decide whether we can discard attributes, or whether we need to terminate
// the session.
final AttributesBuilder builder = new AttributesBuilder();
- BGPTreatAsWithdrawException withdrawCause = null;
for (final Entry<Integer, RawAttribute> entry : attributes.entrySet()) {
LOG.debug("Parsing attribute type {}", entry.getKey());