import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public abstract class AbstractFlowspecNlriParser implements NlriParser, NlriSerializer {
+ private static final Logger LOG = LoggerFactory.getLogger(AbstractFlowspecNlriParser.class);
+
@VisibleForTesting
static final NodeIdentifier FLOWSPEC_NID = new NodeIdentifier(Flowspec.QNAME);
@VisibleForTesting
@VisibleForTesting
public static final NodeIdentifier VALUE_NID = new NodeIdentifier(QName.create(Flowspec.QNAME.getNamespace(), Flowspec.QNAME.getRevision(), "value"));
- protected static final int NLRI_LENGTH = 1;
- protected static final int NLRI_LENGTH_EXTENDED = 2;
-
protected SimpleFlowspecTypeRegistry flowspecTypeRegistry;
/**
* Add this constant to length value to achieve all ones in the leftmost nibble.
*/
protected static final int LENGTH_MAGIC = 61440;
- protected static final int MAX_NLRI_LENGTH = 4095;
- protected static final int MAX_NLRI_LENGTH_ONE_BYTE = 240;
+ protected static final int MAX_NLRI_LENGTH = 0xFFF;
+ protected static final int MAX_NLRI_LENGTH_ONE_BYTE = 0xF0;
@VisibleForTesting
static final String DO_NOT_VALUE = "do-not";
return buffer.toString();
}
+ public static final int readNlriLength(@Nonnull final ByteBuf nlri) {
+ Preconditions.checkNotNull(nlri, "NLRI information cannot be null");
+ Preconditions.checkState(nlri.isReadable(), "NLRI Byte buffer is not readable.");
+ int length = nlri.readUnsignedByte();
+ if (length >= MAX_NLRI_LENGTH_ONE_BYTE) {
+ length = (length << Byte.SIZE | nlri.readUnsignedByte()) & MAX_NLRI_LENGTH;
+ }
+ Preconditions.checkState(length > 0 && length <= nlri.readableBytes(), "Invalid flowspec NLRI length %s", length);
+ return length;
+ }
+
/**
* Parses Flowspec NLRI into list of Flowspec.
*
final List<Flowspec> fss = new ArrayList<>();
while (nlri.isReadable()) {
- final FlowspecBuilder builder = new FlowspecBuilder();
- builder.setFlowspecType(this.flowspecTypeRegistry.parseFlowspecType(nlri));
- fss.add(builder.build());
+ int nlriLength = readNlriLength(nlri);
+ Preconditions.checkState(nlriLength > 0 && nlriLength <= nlri.readableBytes(), "Invalid flowspec NLRI length %s", nlriLength);
+ LOG.trace("Flowspec NLRI length is {}", nlriLength);
+
+ while (nlriLength > 0) {
+ final int readableLength = nlri.readableBytes();
+ final FlowspecBuilder builder = new FlowspecBuilder();
+ builder.setFlowspecType(this.flowspecTypeRegistry.parseFlowspecType(nlri));
+ fss.add(builder.build());
+ final int flowspecTypeLength = readableLength - nlri.readableBytes();
+ nlriLength -= flowspecTypeLength;
+ }
+ Preconditions.checkState(nlriLength == 0, "Remain NLRI length should be 0 instead of %s", nlriLength);
}
- return fss;
- }
- /**
- * This step is used to verify the NLRI length we read from BGP message
- *
- * @param nlri
- */
- private static final void verifyNlriLength(@Nonnull final ByteBuf nlri) {
- // length field can be one or two bytes (if needed)
- // check the length of nlri to see how many bytes we can skip
- int readableLength = nlri.readableBytes();
- // read the length from field
- final int expectedLength;
- if (readableLength > MAX_NLRI_LENGTH_ONE_BYTE) {
- expectedLength = nlri.readUnsignedShort();
- // deduct the two bytes of the NLRI length field
- readableLength -= NLRI_LENGTH_EXTENDED;
- } else {
- expectedLength = nlri.readUnsignedByte();
- // deduct the one byte of the NLRI length field
- readableLength -= NLRI_LENGTH;
- }
- Preconditions.checkState(readableLength == expectedLength, "NLRI length read from message doesn't match. Length expected (read from NLRI) is %s, length readable is %s", expectedLength, readableLength);
+ return fss;
}
/**
return;
}
final PathId pathId = readPathId(nlri, builder.getAfi(), builder.getSafi(), constraint);
- verifyNlriLength(nlri);
final Object[] nlriFields = parseNlri(nlri);
builder.setAdvertizedRoutes(
new AdvertizedRoutesBuilder()
return;
}
final PathId pathId = readPathId(nlri, builder.getAfi(), builder.getSafi(), constraint);
- verifyNlriLength(nlri);
final Object[] nlriFields = parseNlri(nlri);
builder.setWithdrawnRoutes(
new WithdrawnRoutesBuilder()
serializer.serializeType(fsType, output);
}
- public FlowspecType parseFlowspecType(ByteBuf buffer) {
+ public FlowspecType parseFlowspecType(final ByteBuf buffer) {
final short type = buffer.readUnsignedByte();
final FlowspecTypeParser parser = getFlowspecTypeParser(type);
Preconditions.checkNotNull(parser, "parser for flowspec type %s is not registered", type);
import com.google.common.base.Preconditions;
import io.netty.buffer.ByteBuf;
+import java.util.ArrayList;
import java.util.List;
-import javax.annotation.Nonnull;
import org.opendaylight.bgp.concepts.RouteDistinguisherUtil;
import org.opendaylight.protocol.bgp.flowspec.AbstractFlowspecNlriParser;
import org.opendaylight.protocol.bgp.flowspec.SimpleFlowspecTypeRegistry;
import org.opendaylight.protocol.bgp.parser.BGPParsingException;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.Flowspec;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.FlowspecBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.RouteDistinguisher;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
}
@Override
- protected void serializeNlri(@Nonnull final Object[] nlriFields, @Nonnull final ByteBuf buffer) {
+ protected void serializeNlri(final Object[] nlriFields, final ByteBuf buffer) {
final RouteDistinguisher rd = Preconditions.checkNotNull((RouteDistinguisher) nlriFields[0]);
RouteDistinguisherUtil.serializeRouteDistinquisher(rd, buffer);
final List<Flowspec> flowspecList = (List<Flowspec>) nlriFields[1];
}
@Override
- @Nonnull
- protected Object[] parseNlri(@Nonnull final ByteBuf nlri) throws BGPParsingException {
+ protected Object[] parseNlri(final ByteBuf nlri) throws BGPParsingException {
+ readNlriLength(nlri);
return new Object[] {
Preconditions.checkNotNull(readRouteDistinguisher(nlri)),
- parseNlriFlowspecList(nlri)
+ parseL3vpnNlriFlowspecList(nlri)
};
}
+
+ protected final List<Flowspec> parseL3vpnNlriFlowspecList(final ByteBuf nlri) throws BGPParsingException {
+ if (!nlri.isReadable()) {
+ return null;
+ }
+ final List<Flowspec> fss = new ArrayList<>();
+
+ while (nlri.isReadable()) {
+ final FlowspecBuilder builder = new FlowspecBuilder();
+ builder.setFlowspecType(this.flowspecTypeRegistry.parseFlowspecType(nlri));
+ fss.add(builder.build());
+ }
+
+ return fss;
+ }
}
--- /dev/null
+/*
+ * Copyright (c) 2017 Brocade Communications Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.protocol.bgp.flowspec;
+
+import static org.junit.Assert.assertEquals;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import java.nio.ByteBuffer;
+import org.junit.Test;
+
+public class AbstractFlowspecNlriParserTest {
+
+ @Test(expected = IllegalStateException.class)
+ public void zeroNlriLengthTest() throws Exception {
+ // invalid zero NRLI length
+ AbstractFlowspecNlriParser.readNlriLength(Unpooled.wrappedBuffer(new byte[]{0x00, 0x0}));
+ }
+
+ @Test
+ public void readNlriLength() throws Exception {
+ final ByteBuffer byteBuffer = ByteBuffer.allocate(5003);
+ byteBuffer.put(new byte[]{(byte) 0x01}); // length = 1
+ byteBuffer.put(new byte[]{(byte) 0xf0, (byte) 0xf0}); // length = 240
+ byteBuffer.put(new byte[]{(byte) 0xf0, (byte) 0xf1}); // length = 241
+ byteBuffer.put(new byte[]{(byte) 0xff, (byte) 0xff}); // length = 4095
+ byteBuffer.rewind();
+ final ByteBuf byteBuf = Unpooled.wrappedBuffer(byteBuffer);
+ assertEquals(1, AbstractFlowspecNlriParser.readNlriLength(byteBuf));
+ assertEquals(240, AbstractFlowspecNlriParser.readNlriLength(byteBuf));
+ assertEquals(241, AbstractFlowspecNlriParser.readNlriLength(byteBuf));
+ assertEquals(4095, AbstractFlowspecNlriParser.readNlriLength(byteBuf));
+ }
+
+}
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.group.ipv4.flowspec.flowspec.type.protocol.ip._case.ProtocolIpsBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.ipv4.DestinationFlowspecBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.ipv4.route.FlowspecRoute;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.update.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationFlowspecCase;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.PathId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.AttributesBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.Attributes1;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.Attributes1Builder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.Attributes2;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.Attributes2Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpReachNlri;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpReachNlriBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpUnreachNlriBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.mp.reach.nlri.AdvertizedRoutesBuilder;
06, (byte) 0x91, 0x1f, (byte) 0x90
};
+ private static final byte[] REACHED_NLRI_BATCHED = new byte[] {
+ 0x06, 0x01, 0x20, (byte) 0xd8, 0x3a, (byte) 0xf5, 0x65,
+ 0x06, 0x01, 0x20, (byte) 0xd8, 0x3a, (byte) 0xda, (byte) 0xc4,
+ 0x06, 0x01, 0x20, (byte) 0xd8, 0x3a, (byte) 0xd8, (byte) 0xc3
+ };
+
private static final byte[] UNREACHED_NLRI = new byte[] {
0x1B, // NLRI length: 27
07, 4, 2, (byte) 0x84, 3,
expected.add(expectedFS.build());
assertEquals(expected, this.FS_PARSER.extractFlowspec(entry.build()));
}
+
+ @Test
+ public void testBatchedFlowspecNlri() throws Exception {
+ final SimpleFlowspecIpv4NlriParser parser = new SimpleFlowspecIpv4NlriParser(flowspecContext.getFlowspecTypeRegistry(SimpleFlowspecExtensionProviderContext.AFI.IPV4, SimpleFlowspecExtensionProviderContext.SAFI.FLOWSPEC));
+
+ final MpReachNlriBuilder result = new MpReachNlriBuilder();
+ result.setAfi(Ipv4AddressFamily.class);
+ result.setSafi(FlowspecSubsequentAddressFamily.class);
+
+ parser.parseNlri(Unpooled.wrappedBuffer(REACHED_NLRI_BATCHED), result);
+ final MpReachNlri nlri = result.build();
+
+ final List<Flowspec> flowspecList = ((DestinationFlowspecCase) nlri.getAdvertizedRoutes().getDestinationType())
+ .getDestinationFlowspec().getFlowspec();
+ assertEquals(3, flowspecList.size());
+ assertEquals("216.58.245.101/32", ((DestinationPrefixCase) flowspecList.get(0).getFlowspecType()).getDestinationPrefix().getValue());
+ assertEquals("216.58.218.196/32", ((DestinationPrefixCase) flowspecList.get(1).getFlowspecType()).getDestinationPrefix().getValue());
+ assertEquals("216.58.216.195/32", ((DestinationPrefixCase) flowspecList.get(2).getFlowspecType()).getDestinationPrefix().getValue());
+ }
+
}