Fix PcRequest Message Parser in presence of LSP 07/97007/9
authorOlivier Dugeon <olivier.dugeon@orange.com>
Thu, 16 Sep 2021 15:07:04 +0000 (17:07 +0200)
committerguillaume.lambert <guillaume.lambert@orange.com>
Fri, 17 Sep 2021 18:30:59 +0000 (20:30 +0200)
Since RFC8231, PcRequest messages can include a LSP Object.
However, the insertObject() method of the PCEPRequestMessageParser class
does not handle LSP Objects.
Thus, when a PCC sends a PcRequest message with a LSP, ODL throws a
Java Exception about Unknown Object and sends a PcError with RP
Missing Object type.

- override initial PcRequest parser with a new StatefulPcRequest
  message parser in the ietf-stateful package
- add support for LSP Objects when validating the PcRequest message

JIRA: BGPCEP-975
Signed-off-by: Olivier Dugeon <olivier.dugeon@orange.com>
Change-Id: I525cd933237bf3633da8c2ff854989b1f9968aa8

pcep/ietf-stateful/src/main/java/org/opendaylight/protocol/pcep/ietf/stateful/StatefulActivator.java
pcep/ietf-stateful/src/main/java/org/opendaylight/protocol/pcep/ietf/stateful/StatefulPCRequestMessageParser.java [new file with mode: 0644]
pcep/ietf-stateful/src/test/java/org/opendaylight/protocol/pcep/ietf/PCEPValidatorTest.java
pcep/ietf-stateful/src/test/resources/PCReq.1.bin [new file with mode: 0644]

index 9592ce546f3e5490eca276c8a300561375073b5f..d032da2b8bb80adf2d59d27dfabb8394206cf01a 100644 (file)
@@ -28,6 +28,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.iet
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.stateful.capability.tlv.Stateful;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.symbolic.path.name.tlv.SymbolicPathName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev181109.Pcerr;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev181109.Pcreq;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.open.object.Open;
 import org.opendaylight.yangtools.concepts.Registration;
 import org.osgi.service.component.annotations.Component;
@@ -52,6 +53,9 @@ public final class StatefulActivator implements PCEPExtensionProviderActivator {
         regs.add(context.registerMessageParser(StatefulPCReportMessageParser.TYPE,
             new StatefulPCReportMessageParser(objReg)));
         regs.add(context.registerMessageSerializer(Pcrpt.class, new StatefulPCReportMessageParser(objReg)));
+        regs.add(context.registerMessageParser(StatefulPCRequestMessageParser.TYPE,
+                new StatefulPCRequestMessageParser(objReg)));
+        regs.add(context.registerMessageSerializer(Pcreq.class, new StatefulPCRequestMessageParser(objReg)));
         regs.add(context.registerMessageParser(StatefulErrorMessageParser.TYPE,
             new StatefulErrorMessageParser(objReg)));
         regs.add(context.registerMessageSerializer(Pcerr.class, new StatefulErrorMessageParser(objReg)));
diff --git a/pcep/ietf-stateful/src/main/java/org/opendaylight/protocol/pcep/ietf/stateful/StatefulPCRequestMessageParser.java b/pcep/ietf-stateful/src/main/java/org/opendaylight/protocol/pcep/ietf/stateful/StatefulPCRequestMessageParser.java
new file mode 100644 (file)
index 0000000..d4909a5
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2021 Orange.  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.pcep.ietf.stateful;
+
+import io.netty.buffer.ByteBuf;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.Queue;
+import org.opendaylight.protocol.pcep.parser.message.PCEPRequestMessageParser;
+import org.opendaylight.protocol.pcep.spi.ObjectRegistry;
+import org.opendaylight.protocol.pcep.spi.PCEPErrors;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.P2p1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.P2p1Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.lsp.object.Lsp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev181109.Pcreq;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.Message;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.Object;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.bandwidth.object.Bandwidth;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.classtype.object.ClassType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.exclude.route.object.Xro;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.include.route.object.Iro;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.load.balancing.object.LoadBalancing;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.lsp.attributes.Metrics;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.lsp.attributes.MetricsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.lspa.object.Lspa;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.metric.object.Metric;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.of.object.Of;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcreq.message.pcreq.message.requests.SegmentComputation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcreq.message.pcreq.message.requests.SegmentComputationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcreq.message.pcreq.message.requests.segment.computation.P2p;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcreq.message.pcreq.message.requests.segment.computation.P2pBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcreq.message.pcreq.message.requests.segment.computation.p2p.ReportedRoute;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.reoptimization.bandwidth.object.ReoptimizationBandwidth;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.reported.route.object.Rro;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.rp.object.Rp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.vendor.information.objects.VendorInformationObject;
+
+
+/**
+ * Parser for {@link Pcreq}.
+ */
+public class StatefulPCRequestMessageParser extends PCEPRequestMessageParser {
+
+    public static final int TYPE = 3;
+
+    public StatefulPCRequestMessageParser(final ObjectRegistry registry) {
+        super(registry);
+    }
+
+    @Override
+    protected void serializeP2P(final ByteBuf buffer, final P2p p2p) {
+        serializeObject(p2p.getEndpointsObj(), buffer);
+        serializeVendorInformationObjects(p2p.getVendorInformationObject(), buffer);
+        if (p2p.getReportedRoute() != null) {
+            final ReportedRoute rr = p2p.getReportedRoute();
+            if (rr != null) {
+                serializeObject(rr.getRro(), buffer);
+                serializeObject(rr.getReoptimizationBandwidth(), buffer);
+            }
+        }
+        serializeObject(p2p.getLoadBalancing(), buffer);
+        if (p2p.augmentation(P2p1.class) != null) {
+            final P2p1 aug = p2p.augmentation(P2p1.class);
+            serializeObject(aug.getLsp(), buffer);
+        }
+        serializeObject(p2p.getLspa(), buffer);
+        serializeObject(p2p.getBandwidth(), buffer);
+        for (final Metrics m : p2p.nonnullMetrics()) {
+            serializeObject(m.getMetric(), buffer);
+        }
+        serializeObject(p2p.getIro(), buffer);
+        serializeObject(p2p.getRro(), buffer);
+        serializeObject(p2p.getXro(), buffer);
+        serializeObject(p2p.getOf(), buffer);
+        serializeObject(p2p.getClassType(), buffer);
+    }
+
+
+    @Override
+    protected SegmentComputation getP2PSegmentComputation(final P2pBuilder builder,
+                                                          final Queue<Object> objects,
+                                                          final List<Message> errors,
+                                                          final Rp rp) {
+        final List<Metrics> metrics = new ArrayList<>();
+        final List<VendorInformationObject> viObjects = new ArrayList<>();
+
+        P2PState p2PState = P2PState.INIT;
+        while (!objects.isEmpty() && p2PState != P2PState.END) {
+            p2PState = insertP2PObject(p2PState, objects, viObjects, builder, metrics, errors, rp);
+            if (!p2PState.equals(P2PState.END)) {
+                objects.remove();
+            }
+        }
+        if (!metrics.isEmpty()) {
+            builder.setMetrics(metrics);
+        }
+        if (!viObjects.isEmpty()) {
+            builder.setVendorInformationObject(viObjects);
+        }
+
+        if (rp.getReoptimization() && builder.getBandwidth() != null
+                && !builder.getReportedRoute().getReoptimizationBandwidth().getBandwidth().equals(
+                        new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network
+                            .concepts.rev131125.Bandwidth(new byte[] { 0 }))
+                && builder.getReportedRoute().getRro() == null) {
+            errors.add(createErrorMsg(PCEPErrors.RRO_MISSING, Optional.of(rp)));
+            return null;
+        }
+        return new SegmentComputationBuilder().setP2p(builder.build()).build();
+    }
+
+    // Note: objects is expected to be non-empty and caller will remove the first object if non-empty
+    @SuppressWarnings("fallthrough")
+    private static P2PState insertP2PObject(final P2PState p2PState,
+                                            final Queue<Object> objects,
+                                            final List<VendorInformationObject> viObjects,
+                                            final P2pBuilder builder,
+                                            final List<Metrics> metrics,
+                                            final List<Message> errors,
+                                            final Rp rp) {
+        final Object obj = objects.element();
+        switch (p2PState) {
+            case INIT:
+                if (obj instanceof Rro) {
+                    builder.setRro((Rro) obj);
+                    objects.remove();
+
+                    // FIXME: should we guard against empty objects?
+                    final Object nextObj = objects.element();
+                    if (nextObj instanceof ReoptimizationBandwidth) {
+                        builder.setReoptimizationBandwidth((ReoptimizationBandwidth) nextObj);
+                    }
+                    return P2PState.REPORTED_IN;
+                }
+                // fallthrough
+            case REPORTED_IN:
+                if (obj instanceof VendorInformationObject) {
+                    viObjects.add((VendorInformationObject) obj);
+                    return P2PState.REPORTED_IN;
+                }
+                // fallthrough
+            case VENDOR_INFO_LIST:
+                if (obj instanceof LoadBalancing) {
+                    builder.setLoadBalancing((LoadBalancing) obj);
+                    return P2PState.LOAD_BIN;
+                }
+                // fallthrough
+            case LOAD_BIN:
+                if (obj instanceof Lsp) {
+                    builder.addAugmentation(new P2p1Builder().setLsp((Lsp) obj).build());
+                    return P2PState.LSP_IN;
+                }
+                // fallthrough
+            case LSP_IN:
+                if (obj instanceof Lspa) {
+                    builder.setLspa((Lspa) obj);
+                    return P2PState.LSPA_IN;
+                }
+                // fallthrough
+            case LSPA_IN:
+                if (obj instanceof Bandwidth) {
+                    builder.setBandwidth((Bandwidth) obj);
+                    return P2PState.BANDWIDTH_IN;
+                }
+                // fallthrough
+            case BANDWIDTH_IN:
+                if (obj instanceof Metric) {
+                    metrics.add(new MetricsBuilder().setMetric((Metric) obj).build());
+                    return P2PState.BANDWIDTH_IN;
+                }
+                // fallthrough
+            case METRIC_IN:
+                if (obj instanceof Iro) {
+                    builder.setIro((Iro) obj);
+                    return P2PState.IRO_IN;
+                }
+                // fallthrough
+            case IRO_IN:
+                if (obj instanceof Rro) {
+                    builder.setRro((Rro) obj);
+                    return P2PState.RRO_IN;
+                }
+                // fallthrough
+            case RRO_IN:
+                if (obj instanceof Xro) {
+                    builder.setXro((Xro) obj);
+                    return P2PState.XRO_IN;
+                }
+                // fallthrough
+            case XRO_IN:
+                if (obj instanceof Of) {
+                    builder.setOf((Of) obj);
+                    return P2PState.OF_IN;
+                }
+                // fallthrough
+            case OF_IN:
+                if (obj instanceof ClassType) {
+                    final ClassType classType = (ClassType) obj;
+                    if (!classType.getProcessingRule()) {
+                        errors.add(createErrorMsg(PCEPErrors.P_FLAG_NOT_SET, Optional.of(rp)));
+                    } else {
+                        builder.setClassType(classType);
+                    }
+                    return P2PState.CT_IN;
+                }
+                // fallthrough
+            case CT_IN:
+            case END:
+                return P2PState.END;
+            default:
+                return p2PState;
+        }
+    }
+
+    private enum P2PState {
+        INIT,
+        REPORTED_IN,
+        VENDOR_INFO_LIST,
+        LOAD_BIN,
+        LSP_IN,
+        LSPA_IN,
+        BANDWIDTH_IN,
+        METRIC_IN,
+        IRO_IN,
+        RRO_IN,
+        XRO_IN,
+        OF_IN,
+        CT_IN,
+        END
+    }
+}
index 585b7c5f43aa520a7d89b06b3335e20abadcb6d9..85c712febdb2f2d83daed6928e8a15546e1de96e 100644 (file)
@@ -16,6 +16,7 @@ import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import org.junit.Before;
 import org.junit.Test;
@@ -24,6 +25,7 @@ import org.opendaylight.protocol.pcep.ietf.initiated.InitiatedPCInitiateMessageP
 import org.opendaylight.protocol.pcep.ietf.stateful.StatefulActivator;
 import org.opendaylight.protocol.pcep.ietf.stateful.StatefulErrorMessageParser;
 import org.opendaylight.protocol.pcep.ietf.stateful.StatefulPCReportMessageParser;
+import org.opendaylight.protocol.pcep.ietf.stateful.StatefulPCRequestMessageParser;
 import org.opendaylight.protocol.pcep.ietf.stateful.StatefulPCUpdateRequestMessageParser;
 import org.opendaylight.protocol.pcep.parser.BaseParserExtensionActivator;
 import org.opendaylight.protocol.pcep.parser.message.PCEPOpenMessageParser;
@@ -40,6 +42,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.iet
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev200720.pcinitiate.message.PcinitiateMessageBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev200720.pcinitiate.message.pcinitiate.message.RequestsBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.OperationalStatus;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.P2p1Builder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.PcrptBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.PcupdBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.PlspId;
@@ -64,6 +67,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.iet
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.stateful.capability.tlv.StatefulBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev181109.OpenBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev181109.PcerrBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev181109.Pcreq;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev181109.PcreqBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.Message;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.ProtocolVersion;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.RequestId;
@@ -89,8 +94,12 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.typ
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcerr.message.pcerr.message.error.type.SessionCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcerr.message.pcerr.message.error.type.request._case.RequestBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcerr.message.pcerr.message.error.type.session._case.SessionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcreq.message.PcreqMessageBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcreq.message.pcreq.message.requests.SegmentComputationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcreq.message.pcreq.message.requests.segment.computation.P2pBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.reported.route.object.Rro;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.reported.route.object.RroBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.rp.object.Rp;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.rp.object.RpBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.rsvp.rev150820.AttributeFilter;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.rsvp.rev150820.Ipv4ExtendedTunnelId;
@@ -347,6 +356,86 @@ public class PCEPValidatorTest {
         new SyncOptimizationsActivator().start(ctx);
     }
 
+    @Test
+    public void testReqMesgWithLSP() throws IOException, PCEPDeserializerException {
+        // Test PcRequest message with an LSP Object as per RFC8231
+        new StatefulActivator().start(ctx);
+
+        final Rp rp = new RpBuilder()
+                .setProcessingRule(true)
+                .setIgnore(false)
+                .setReoptimization(false)
+                .setBiDirectional(false)
+                .setLoose(true)
+                .setMakeBeforeBreak(false)
+                .setOrder(false)
+                .setPathKey(false)
+                .setSupplyOf(false)
+                .setFragmentation(false)
+                .setP2mp(false)
+                .setEroCompression(false)
+                .setPriority(Uint8.ONE)
+                .setRequestId(new RequestId(Uint32.TEN))
+                .setTlvs(new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109
+                    .rp.object.rp.TlvsBuilder().build())
+                .build();
+
+        final Lsp lspReq = new LspBuilder()
+                .setIgnore(false)
+                .setProcessingRule(false)
+                .setAdministrative(false)
+                .setDelegate(false)
+                .setPlspId(new PlspId(Uint32.ZERO))
+                .setOperational(OperationalStatus.Down)
+                .setSync(false)
+                .setRemove(false)
+                .setTlvs(new TlvsBuilder().build())
+                .build();
+
+        final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109
+            .endpoints.object.EndpointsObjBuilder epBuilder =
+                new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109
+                    .endpoints.object.EndpointsObjBuilder()
+                .setIgnore(false)
+                .setProcessingRule(true)
+                .setAddressFamily(
+                    new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109
+                            .endpoints.address.family.Ipv4CaseBuilder()
+                        .setIpv4(
+                            new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109
+                                    .endpoints.address.family.ipv4._case.Ipv4Builder()
+                                .setSourceIpv4Address(new Ipv4AddressNoZone("255.255.255.255"))
+                                .setDestinationIpv4Address(new Ipv4AddressNoZone("255.255.255.255"))
+                                .build())
+                        .build());
+
+        final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109
+            .pcreq.message.pcreq.message.RequestsBuilder rBuilder =
+                new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109
+                    .pcreq.message.pcreq.message.RequestsBuilder()
+                .setRp(rp)
+                .setSegmentComputation(new SegmentComputationBuilder().setP2p(new P2pBuilder()
+                .setEndpointsObj(epBuilder.build()).addAugmentation(new P2p1Builder().setLsp(lspReq).build())
+                .build()).build());
+
+        final List<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109
+            .pcreq.message.pcreq.message.Requests> reqs = new ArrayList<>();
+        reqs.add(rBuilder.build());
+
+        final Pcreq pcReq = new PcreqBuilder()
+            .setPcreqMessage(new PcreqMessageBuilder().setRequests(reqs).build())
+            .build();
+
+        final StatefulPCRequestMessageParser parser = new StatefulPCRequestMessageParser(
+                this.ctx.getObjectHandlerRegistry());
+        ByteBuf result = Unpooled.wrappedBuffer(ByteArray.fileToBytes("src/test/resources/PCReq.1.bin"));
+        assertEquals(pcReq, parser.parseMessage(result.slice(4, result.readableBytes() - 4), Collections.emptyList()));
+
+        ByteBuf buf = Unpooled.buffer(result.readableBytes());
+        parser.serializeMessage(pcReq, buf);
+        assertArrayEquals(result.array(), buf.array());
+    }
+
     @Test
     public void testUpdMsg() throws IOException, PCEPDeserializerException {
         new InitiatedActivator().start(ctx);
diff --git a/pcep/ietf-stateful/src/test/resources/PCReq.1.bin b/pcep/ietf-stateful/src/test/resources/PCReq.1.bin
new file mode 100644 (file)
index 0000000..634648a
Binary files /dev/null and b/pcep/ietf-stateful/src/test/resources/PCReq.1.bin differ