Modernize bgp-flowspec
[bgpcep.git] / bgp / extensions / flowspec / src / test / java / org / opendaylight / protocol / bgp / flowspec / SimpleFlowspecIpv4NlriParserTest.java
1 /*
2  * Copyright (c) 2015 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.flowspec;
9
10 import static org.junit.Assert.assertArrayEquals;
11 import static org.junit.Assert.assertEquals;
12 import static org.mockito.ArgumentMatchers.any;
13 import static org.mockito.Mockito.doReturn;
14
15 import io.netty.buffer.ByteBuf;
16 import io.netty.buffer.Unpooled;
17 import java.util.ArrayList;
18 import java.util.List;
19 import java.util.Optional;
20 import java.util.Set;
21 import org.junit.Before;
22 import org.junit.Test;
23 import org.junit.runner.RunWith;
24 import org.mockito.Mock;
25 import org.mockito.junit.MockitoJUnitRunner;
26 import org.opendaylight.protocol.bgp.flowspec.FlowspecTypeRegistries.SAFI;
27 import org.opendaylight.protocol.bgp.flowspec.handlers.AbstractNumericOperandParser;
28 import org.opendaylight.protocol.bgp.flowspec.handlers.AbstractOperandParser;
29 import org.opendaylight.protocol.bgp.flowspec.handlers.BitmaskOperandParser;
30 import org.opendaylight.protocol.bgp.parser.BGPParsingException;
31 import org.opendaylight.protocol.bgp.parser.spi.MultiPathSupport;
32 import org.opendaylight.protocol.bgp.parser.spi.PeerSpecificParserConstraint;
33 import org.opendaylight.protocol.util.ByteArray;
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.BitmaskOperand;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.Dscp;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.FlowspecSubsequentAddressFamily;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.Fragment;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.NumericOperand;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.Flowspec;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.FlowspecBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.flowspec.FlowspecType;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.flowspec.flowspec.type.DestinationPortCaseBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.flowspec.flowspec.type.DscpCaseBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.flowspec.flowspec.type.FragmentCaseBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.flowspec.flowspec.type.IcmpCodeCaseBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.flowspec.flowspec.type.IcmpTypeCaseBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.flowspec.flowspec.type.PacketLengthCase;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.flowspec.flowspec.type.PacketLengthCaseBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.flowspec.flowspec.type.PortCase;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.flowspec.flowspec.type.PortCaseBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.flowspec.flowspec.type.SourcePortCaseBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.flowspec.flowspec.type.TcpFlagsCase;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.flowspec.flowspec.type.TcpFlagsCaseBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.flowspec.flowspec.type.destination.port._case.DestinationPorts;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.flowspec.flowspec.type.destination.port._case.DestinationPortsBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.flowspec.flowspec.type.dscp._case.Dscps;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.flowspec.flowspec.type.dscp._case.DscpsBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.flowspec.flowspec.type.fragment._case.Fragments;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.flowspec.flowspec.type.fragment._case.FragmentsBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.flowspec.flowspec.type.icmp.code._case.Codes;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.flowspec.flowspec.type.icmp.code._case.CodesBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.flowspec.flowspec.type.icmp.type._case.Types;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.flowspec.flowspec.type.icmp.type._case.TypesBuilder;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.flowspec.flowspec.type.packet.length._case.PacketLengths;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.flowspec.flowspec.type.packet.length._case.PacketLengthsBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.flowspec.flowspec.type.port._case.Ports;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.flowspec.flowspec.type.port._case.PortsBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.flowspec.flowspec.type.source.port._case.SourcePorts;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.flowspec.flowspec.type.source.port._case.SourcePortsBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.flowspec.flowspec.type.tcp.flags._case.TcpFlags;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.flowspec.flowspec.type.tcp.flags._case.TcpFlagsBuilder;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.group.ipv4.flowspec.flowspec.type.DestinationPrefixCase;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.group.ipv4.flowspec.flowspec.type.DestinationPrefixCaseBuilder;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.group.ipv4.flowspec.flowspec.type.ProtocolIpCaseBuilder;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.group.ipv4.flowspec.flowspec.type.SourcePrefixCase;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.group.ipv4.flowspec.flowspec.type.SourcePrefixCaseBuilder;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.group.ipv4.flowspec.flowspec.type.protocol.ip._case.ProtocolIps;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.group.ipv4.flowspec.flowspec.type.protocol.ip._case.ProtocolIpsBuilder;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.destination.ipv4.DestinationFlowspecIpv4Builder;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.flowspec.ipv4.route.FlowspecRoute;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.update.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationFlowspecCase;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.PathId;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.path.attributes.AttributesBuilder;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.AttributesReachBuilder;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.AttributesUnreachBuilder;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.attributes.reach.MpReachNlri;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.attributes.reach.MpReachNlriBuilder;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.attributes.reach.mp.reach.nlri.AdvertizedRoutesBuilder;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.attributes.unreach.MpUnreachNlriBuilder;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.attributes.unreach.mp.unreach.nlri.WithdrawnRoutesBuilder;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev200120.Ipv4AddressFamily;
93 import org.opendaylight.yangtools.yang.common.Uint16;
94 import org.opendaylight.yangtools.yang.common.Uint32;
95 import org.opendaylight.yangtools.yang.common.Uint8;
96 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
97 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
98 import org.opendaylight.yangtools.yang.data.spi.node.ImmutableNodes;
99
100 @RunWith(MockitoJUnitRunner.StrictStubs.class)
101 public class SimpleFlowspecIpv4NlriParserTest {
102
103     private static final NodeIdentifier PROTOCOL_IP_NID = new NodeIdentifier(ProtocolIps.QNAME);
104
105     static final PathId PATH_ID = new PathId(Uint32.ONE);
106     @Mock
107     private PeerSpecificParserConstraint constraint;
108     @Mock
109     private MultiPathSupport muliPathSupport;
110
111     private static final byte[] REACHED_NLRI = new byte[] {
112         0x21,   // NLRI length: 33
113         01, 0x20, 0x0a, 00, 01, 00,
114         02, 0x20, 01, 02, 03, 04,
115         03, (byte) 0x81, 06,
116         04, 03, (byte) 0x89, 0x45, (byte) 0x8b, (byte) 0x91, 0x1f, (byte) 0x90,
117         05, 0x12, 0x0f, (byte) 0xf9, (byte) 0x81, (byte) 0xb3,
118         06, (byte) 0x91, 0x1f, (byte) 0x90
119     };
120
121     private static final byte[] REACHED_NLRI_ADD_PATH = new byte[] {
122         0x0, 0x0, 0x0, 0x1,
123         0x21,   // NLRI length: 33
124         01, 0x20, 0x0a, 00, 01, 00,
125         02, 0x20, 01, 02, 03, 04,
126         03, (byte) 0x81, 06,
127         04, 03, (byte) 0x89, 0x45, (byte) 0x8b, (byte) 0x91, 0x1f, (byte) 0x90,
128         05, 0x12, 0x0f, (byte) 0xf9, (byte) 0x81, (byte) 0xb3,
129         06, (byte) 0x91, 0x1f, (byte) 0x90
130     };
131
132     private static final byte[] REACHED_NLRI_BATCHED = new byte[] {
133         0x06, 0x01, 0x20, (byte) 0xd8, 0x3a, (byte) 0xf5, 0x65,
134         0x06, 0x01, 0x20, (byte) 0xd8, 0x3a, (byte) 0xda, (byte) 0xc4,
135         0x06, 0x01, 0x20, (byte) 0xd8, 0x3a, (byte) 0xd8, (byte) 0xc3
136     };
137
138     private static final byte[] UNREACHED_NLRI = new byte[] {
139         0x1B,   // NLRI length: 27
140         07, 4, 2, (byte) 0x84, 3,
141         0x08, 4, 04, (byte) 0x80, 05,
142         0x09, 0x12, 04, 01, (byte) 0x91, 0x56, (byte) 0xb1,
143         0x0a, (byte) 0x94, (byte) 0xde, (byte) 0xad,
144         0x0b, (byte) 0x82, 0x2a,
145         0x0c, (byte) 0x81, (byte) 0x0e
146     };
147
148     private static final byte[] UNREACHED_NLRI_ADD_PATH = new byte[] {
149         0x0, 0x0, 0x0, 0x1,
150         0x1B,   // NLRI length: 27
151         07, 4, 2, (byte) 0x84, 3,
152         0x08, 4, 04, (byte) 0x80, 05,
153         0x09, 0x12, 04, 01, (byte) 0x91, 0x56, (byte) 0xb1,
154         0x0a, (byte) 0x94, (byte) 0xde, (byte) 0xad,
155         0x0b, (byte) 0x82, 0x2a,
156         0x0c, (byte) 0x81, (byte) 0x0e
157     };
158
159     private final SimpleFlowspecIpv4NlriParser fsParser = new SimpleFlowspecIpv4NlriParser(SAFI.FLOWSPEC);
160
161     @Before
162     public void setUp() {
163         doReturn(Optional.of(muliPathSupport)).when(constraint).getPeerConstraint(any());
164         doReturn(true).when(muliPathSupport).isTableTypeSupported(any());
165     }
166
167     @Test
168     public void testParseMpReachNlri() throws BGPParsingException {
169         final List<Flowspec> fs = new ArrayList<>();
170         final MpReachNlriBuilder mp = new MpReachNlriBuilder();
171
172         final FlowspecBuilder builder = new FlowspecBuilder();
173         final DestinationPrefixCase destinationPrefix = new DestinationPrefixCaseBuilder().setDestinationPrefix(
174             new Ipv4Prefix("10.0.1.0/32")).build();
175         builder.setFlowspecType(destinationPrefix);
176         fs.add(builder.build());
177         final SourcePrefixCase sourcePrefix = new SourcePrefixCaseBuilder()
178                 .setSourcePrefix(new Ipv4Prefix("1.2.3.4/32")).build();
179         builder.setFlowspecType(sourcePrefix);
180         fs.add(builder.build());
181
182         final FlowspecType prots = createProts();
183         builder.setFlowspecType(prots);
184         fs.add(builder.build());
185
186         final PortCase ps = createPorts();
187         builder.setFlowspecType(ps);
188         fs.add(builder.build());
189
190         final FlowspecType dps = createDps();
191         builder.setFlowspecType(dps);
192         fs.add(builder.build());
193
194         final FlowspecType sps = createSps();
195         builder.setFlowspecType(sps);
196         fs.add(builder.build());
197
198         mp.setAdvertizedRoutes(new AdvertizedRoutesBuilder().setDestinationType(
199             new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120
200                 .update.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationFlowspecCaseBuilder()
201             .setDestinationFlowspecIpv4(new DestinationFlowspecIpv4Builder().setFlowspec(fs).build())
202             .build()).build());
203
204         final SimpleFlowspecIpv4NlriParser parser = new SimpleFlowspecIpv4NlriParser(SAFI.FLOWSPEC);
205
206         final MpReachNlriBuilder result = new MpReachNlriBuilder()
207             .setAfi(Ipv4AddressFamily.VALUE)
208             .setSafi(FlowspecSubsequentAddressFamily.VALUE);
209         parser.parseNlri(Unpooled.wrappedBuffer(REACHED_NLRI), result, null);
210
211         final List<Flowspec> flows = ((org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang
212             .bgp.flowspec.rev200120.update.attributes.mp.reach.nlri.advertized.routes.destination.type
213             .DestinationFlowspecCase)
214                 result.getAdvertizedRoutes().getDestinationType()).getDestinationFlowspecIpv4().getFlowspec();
215         testFlows(flows, destinationPrefix, sourcePrefix, prots, ps, dps, sps);
216
217         final ByteBuf buffer = Unpooled.buffer();
218         parser.serializeAttribute(new AttributesBuilder()
219             .addAugmentation(new AttributesReachBuilder()
220                 .setMpReachNlri(mp.setAfi(Ipv4AddressFamily.VALUE).build())
221                 .build())
222             .build(), buffer);
223         assertArrayEquals(REACHED_NLRI, ByteArray.readAllBytes(buffer));
224
225         assertEquals("""
226             all packets to 10.0.1.0/32 AND from 1.2.3.4/32 AND where IP protocol equals to 6 AND where port \
227             is greater than or equals to 137 and is less than or equals to 139 or equals to 8080 AND where \
228             destination port is greater than 4089 or equals to 179 AND where source port equals to 8080 \
229             """,
230             fsParser.stringNlri(flows));
231     }
232
233     private static void testFlows(final List<Flowspec> flows, final DestinationPrefixCase destinationPrefix,
234             final SourcePrefixCase sourcePrefix, final FlowspecType prots, final PortCase ps, final FlowspecType dps,
235             final FlowspecType sps) {
236         assertEquals(6, flows.size());
237         assertEquals(destinationPrefix, flows.get(0).getFlowspecType());
238         assertEquals(sourcePrefix, flows.get(1).getFlowspecType());
239         assertEquals(prots, flows.get(2).getFlowspecType());
240         assertEquals(ps, flows.get(3).getFlowspecType());
241         assertEquals(dps, flows.get(4).getFlowspecType());
242         assertEquals(sps, flows.get(5).getFlowspecType());
243     }
244
245     private static FlowspecType createSps() {
246         final List<SourcePorts> sports = List.of(new SourcePortsBuilder().setOp(
247             new NumericOperand(false, true, true, false, false)).setValue(Uint16.valueOf(8080)).build());
248         return new SourcePortCaseBuilder().setSourcePorts(sports).build();
249     }
250
251     private static FlowspecType createProts() {
252         final List<ProtocolIps> protocols = List.of(new ProtocolIpsBuilder().setOp(
253             new NumericOperand(false, true, true, false, false)).setValue(Uint8.valueOf(6)).build());
254         return new ProtocolIpCaseBuilder().setProtocolIps(protocols).build();
255     }
256
257     private static FlowspecType createDps() {
258         final List<DestinationPorts> destports = List.of(new DestinationPortsBuilder().setOp(
259             new NumericOperand(false, false, false, true, false)).setValue(Uint16.valueOf(4089)).build(),
260             new DestinationPortsBuilder().setOp(new NumericOperand(false, true, true, false, false))
261                 .setValue(Uint16.valueOf(179)).build());
262         return new DestinationPortCaseBuilder().setDestinationPorts(destports).build();
263     }
264
265     @Test
266     public void testParseMpReachNlriConstraint() throws BGPParsingException {
267         final List<Flowspec> fs = new ArrayList<>();
268         final MpReachNlriBuilder mp = new MpReachNlriBuilder();
269
270         final FlowspecBuilder builder = new FlowspecBuilder();
271         final DestinationPrefixCase destinationPrefix = new DestinationPrefixCaseBuilder().setDestinationPrefix(
272             new Ipv4Prefix("10.0.1.0/32")).build();
273         builder.setFlowspecType(destinationPrefix);
274         fs.add(builder.build());
275         final SourcePrefixCase sourcePrefix = new SourcePrefixCaseBuilder().setSourcePrefix(
276             new Ipv4Prefix("1.2.3.4/32")).build();
277         builder.setFlowspecType(sourcePrefix);
278         fs.add(builder.build());
279
280         final FlowspecType prots = createProts();
281         builder.setFlowspecType(prots);
282         fs.add(builder.build());
283
284         final PortCase ps = createPorts();
285         builder.setFlowspecType(ps);
286         fs.add(builder.build());
287
288         final FlowspecType dps = createDps();
289         builder.setFlowspecType(dps);
290         fs.add(builder.build());
291
292         final FlowspecType sps = createSps();
293         builder.setFlowspecType(sps);
294         fs.add(builder.build());
295
296         mp.setAdvertizedRoutes(new AdvertizedRoutesBuilder().setDestinationType(new org.opendaylight.yang.gen.v1.urn
297             .opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.update.attributes.mp.reach.nlri.advertized.routes
298             .destination.type.DestinationFlowspecCaseBuilder()
299                 .setDestinationFlowspecIpv4(
300                     new DestinationFlowspecIpv4Builder()
301                         .setPathId(PATH_ID)
302                         .setFlowspec(fs)
303                         .build()
304                 ).build()
305             ).build()
306         );
307
308         final SimpleFlowspecIpv4NlriParser parser = new SimpleFlowspecIpv4NlriParser(SAFI.FLOWSPEC);
309
310         final MpReachNlriBuilder result = new MpReachNlriBuilder()
311             .setAfi(Ipv4AddressFamily.VALUE)
312             .setSafi(FlowspecSubsequentAddressFamily.VALUE);
313         parser.parseNlri(Unpooled.wrappedBuffer(REACHED_NLRI_ADD_PATH), result, constraint);
314
315         final List<Flowspec> flows = ((org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang
316             .bgp.flowspec.rev200120.update.attributes.mp.reach.nlri.advertized.routes.destination.type
317             .DestinationFlowspecCase)
318                 result.getAdvertizedRoutes().getDestinationType()).getDestinationFlowspecIpv4().getFlowspec();
319         testFlows(flows, destinationPrefix, sourcePrefix, prots, ps, dps, sps);
320
321         final ByteBuf buffer = Unpooled.buffer();
322         parser.serializeAttribute(new AttributesBuilder()
323             .addAugmentation(new AttributesReachBuilder()
324                 .setMpReachNlri(mp.setAfi(Ipv4AddressFamily.VALUE).build())
325                 .build())
326             .build(), buffer);
327         assertArrayEquals(REACHED_NLRI_ADD_PATH, ByteArray.readAllBytes(buffer));
328
329         assertEquals("""
330             all packets to 10.0.1.0/32 AND from 1.2.3.4/32 AND where IP protocol equals to 6 AND where port \
331             is greater than or equals to 137 and is less than or equals to 139 or equals to 8080 AND where \
332             destination port is greater than 4089 or equals to 179 AND where source port equals to 8080 \
333             """,
334             fsParser.stringNlri(flows));
335     }
336
337     private static PortCase createPorts() {
338         final List<Ports> ports = List.of(
339             new PortsBuilder().setOp(new NumericOperand(false, false, true, true, false)).setValue(Uint16.valueOf(137))
340                 .build(),
341             new PortsBuilder().setOp(new NumericOperand(true, false, true, false, true)).setValue(Uint16.valueOf(139))
342                 .build(),
343             new PortsBuilder().setOp(new NumericOperand(false, true, true, false, false)).setValue(Uint16.valueOf(8080))
344                 .build());
345
346         return new PortCaseBuilder().setPorts(ports).build();
347     }
348
349     @Test
350     public void testParseMpUnreachNlri() throws BGPParsingException {
351         final List<Flowspec> fs = new ArrayList<>();
352
353         final FlowspecBuilder builder = new FlowspecBuilder();
354
355         final FlowspecType icmpType = createIcmpType();
356         builder.setFlowspecType(icmpType);
357         fs.add(builder.build());
358
359         final FlowspecType icmpCode = createIcmpCode();
360         builder.setFlowspecType(icmpCode);
361         fs.add(builder.build());
362
363         final TcpFlagsCase tcp = createTcp();
364         builder.setFlowspecType(tcp);
365         fs.add(builder.build());
366
367         final PacketLengthCase packet = createPackets();
368         builder.setFlowspecType(packet);
369         fs.add(builder.build());
370
371         final FlowspecType dscp = createDscp();
372         builder.setFlowspecType(dscp);
373         fs.add(builder.build());
374
375         final FlowspecType fragment = createFragment();
376         builder.setFlowspecType(fragment);
377         fs.add(builder.build());
378
379         final MpUnreachNlriBuilder mp = new MpUnreachNlriBuilder()
380             .setAfi(Ipv4AddressFamily.VALUE)
381             .setWithdrawnRoutes(new WithdrawnRoutesBuilder()
382                 .setDestinationType(new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec
383                     .rev200120.update.attributes.mp.unreach.nlri.withdrawn.routes.destination.type
384                     .DestinationFlowspecCaseBuilder().setDestinationFlowspecIpv4(new DestinationFlowspecIpv4Builder()
385                         .setFlowspec(fs)
386                         .build())
387                     .build())
388                 .build());
389
390         final SimpleFlowspecIpv4NlriParser parser = new SimpleFlowspecIpv4NlriParser(SAFI.FLOWSPEC);
391
392         final MpUnreachNlriBuilder result = new MpUnreachNlriBuilder()
393             .setAfi(Ipv4AddressFamily.VALUE)
394             .setSafi(FlowspecSubsequentAddressFamily.VALUE);
395         parser.parseNlri(Unpooled.wrappedBuffer(UNREACHED_NLRI), result, null);
396
397         final List<Flowspec> flows = ((org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang
398             .bgp.flowspec.rev200120.update.attributes.mp.unreach.nlri.withdrawn.routes.destination.type
399                 .DestinationFlowspecCase)
400                 result.getWithdrawnRoutes().getDestinationType()).getDestinationFlowspecIpv4().getFlowspec();
401         checkUnreachFlows(flows, icmpType, icmpCode, tcp, packet, dscp, fragment);
402
403         final ByteBuf buffer = Unpooled.buffer();
404         parser.serializeNlri(flows, null, buffer);
405         assertArrayEquals(UNREACHED_NLRI, ByteArray.readAllBytes(buffer));
406
407         parser.serializeAttribute(new AttributesBuilder()
408             .addAugmentation(new AttributesUnreachBuilder().setMpUnreachNlri(mp.build()).build())
409             .build(), buffer);
410         assertArrayEquals(UNREACHED_NLRI, ByteArray.readAllBytes(buffer));
411
412         assertEquals("""
413             all packets where ICMP type is less than 2 or is less than 3 AND where ICMP code is less than 4 \
414             or 5 AND where TCP flags is not 1025 or does match 22193 AND where packet length is less than 57005 \
415             AND where DSCP is greater than 42 AND where fragment does match 'IS FIRST' 'IS LAST' 'IS A' \
416             """,
417             fsParser.stringNlri(flows));
418     }
419
420     private static FlowspecType createFragment() {
421         final List<Fragments> fragments = List.of(new FragmentsBuilder()
422             .setOp(new BitmaskOperand(false, true, true, false))
423             .setValue(new Fragment(false, true, true, true)).build());
424         return new FragmentCaseBuilder().setFragments(fragments).build();
425     }
426
427     private static FlowspecType createDscp() {
428         final List<Dscps> dscps = List.of(new DscpsBuilder()
429             .setOp(new NumericOperand(false, true, false, true, false))
430             .setValue(new Dscp(Uint8.valueOf(42))).build());
431         return new DscpCaseBuilder().setDscps(dscps).build();
432     }
433
434     private static PacketLengthCase createPackets() {
435         final List<PacketLengths> packets = List.of(new PacketLengthsBuilder()
436             .setOp(new NumericOperand(false, true, false, false, true))
437             .setValue(Uint16.valueOf(57005)).build());
438         return new PacketLengthCaseBuilder().setPacketLengths(packets).build();
439     }
440
441     private static TcpFlagsCase createTcp() {
442         final List<TcpFlags> flags = List.of(new TcpFlagsBuilder()
443             .setOp(new BitmaskOperand(false, false, false, true)).setValue(Uint16.valueOf(1025))
444             .build(), new TcpFlagsBuilder()
445             .setOp(new BitmaskOperand(false, true, true, false))
446             .setValue(Uint16.valueOf(22193)).build());
447         return new TcpFlagsCaseBuilder().setTcpFlags(flags).build();
448     }
449
450     private static FlowspecType createIcmpCode() {
451         final List<Codes> codes = List.of(new CodesBuilder()
452             .setOp(new NumericOperand(false, false, false, false, true))
453             .setValue(Uint8.valueOf(4))
454             .build(), new CodesBuilder()
455             .setOp(new NumericOperand(false, true, false, false, false))
456             .setValue(Uint8.valueOf(5)).build());
457         return new IcmpCodeCaseBuilder().setCodes(codes).build();
458     }
459
460     private static FlowspecType createIcmpType() {
461         final List<Types> types = List.of(
462             new TypesBuilder().setOp(new NumericOperand(false, false, false, false, true)).setValue(Uint8.TWO)
463                 .build(),
464             new TypesBuilder().setOp(new NumericOperand(false, true, false, false, true)).setValue(Uint8.valueOf(3))
465                 .build());
466         return new IcmpTypeCaseBuilder().setTypes(types).build();
467     }
468
469     private static void checkUnreachFlows(final List<Flowspec> flows, final FlowspecType icmpType,
470             final FlowspecType icmpCode, final TcpFlagsCase tcp, final PacketLengthCase packet,
471             final FlowspecType dscp, final FlowspecType fragment) {
472         assertEquals(6, flows.size());
473         assertEquals(icmpType, flows.get(0).getFlowspecType());
474         assertEquals(icmpCode, flows.get(1).getFlowspecType());
475         assertEquals(tcp, flows.get(2).getFlowspecType());
476         assertEquals(packet, flows.get(3).getFlowspecType());
477         assertEquals(dscp, flows.get(4).getFlowspecType());
478         assertEquals(fragment, flows.get(5).getFlowspecType());
479     }
480
481     @Test
482     public void testParseMpUnreachNlriConstraint() throws BGPParsingException {
483         final List<Flowspec> fs = new ArrayList<>();
484         final MpUnreachNlriBuilder mp = new MpUnreachNlriBuilder();
485
486         final FlowspecBuilder builder = new FlowspecBuilder();
487
488         final FlowspecType icmpType = createIcmpType();
489         builder.setFlowspecType(icmpType);
490         fs.add(builder.build());
491
492         final FlowspecType icmpCode = createIcmpCode();
493         builder.setFlowspecType(icmpCode);
494         fs.add(builder.build());
495
496         final TcpFlagsCase tcp = createTcp();
497         builder.setFlowspecType(tcp);
498         fs.add(builder.build());
499
500         final PacketLengthCase packet = createPackets();
501         builder.setFlowspecType(packet);
502         fs.add(builder.build());
503
504         final FlowspecType dscp = createDscp();
505         builder.setFlowspecType(dscp);
506         fs.add(builder.build());
507
508         final FlowspecType fragment = createFragment();
509         builder.setFlowspecType(fragment);
510         fs.add(builder.build());
511
512         mp.setAfi(Ipv4AddressFamily.VALUE).setWithdrawnRoutes(new WithdrawnRoutesBuilder().setDestinationType(
513             new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev200120.update
514                 .attributes.mp.unreach.nlri.withdrawn.routes.destination.type.DestinationFlowspecCaseBuilder()
515                 .setDestinationFlowspecIpv4(
516                     new DestinationFlowspecIpv4Builder()
517                         .setPathId(PATH_ID)
518                         .setFlowspec(fs)
519                         .build()
520                 ).build()
521             ).build()
522         );
523
524         final SimpleFlowspecIpv4NlriParser parser = new SimpleFlowspecIpv4NlriParser(SAFI.FLOWSPEC);
525
526         final MpUnreachNlriBuilder result = new MpUnreachNlriBuilder()
527             .setAfi(Ipv4AddressFamily.VALUE)
528             .setSafi(FlowspecSubsequentAddressFamily.VALUE);
529         parser.parseNlri(Unpooled.wrappedBuffer(UNREACHED_NLRI_ADD_PATH), result, constraint);
530
531         final List<Flowspec> flows = ((org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang
532             .bgp.flowspec.rev200120.update.attributes.mp.unreach.nlri.withdrawn.routes.destination.type
533             .DestinationFlowspecCase)
534                 result.getWithdrawnRoutes().getDestinationType()).getDestinationFlowspecIpv4().getFlowspec();
535         checkUnreachFlows(flows, icmpType, icmpCode, tcp, packet, dscp, fragment);
536
537
538         final ByteBuf buffer = Unpooled.buffer();
539         parser.serializeNlri(flows, PATH_ID, buffer);
540         assertArrayEquals(UNREACHED_NLRI_ADD_PATH, ByteArray.readAllBytes(buffer));
541
542         parser.serializeAttribute(new AttributesBuilder()
543             .addAugmentation(new AttributesUnreachBuilder().setMpUnreachNlri(mp.build()).build())
544             .build(), buffer);
545         assertArrayEquals(UNREACHED_NLRI_ADD_PATH, ByteArray.readAllBytes(buffer));
546
547         assertEquals("""
548             all packets where ICMP type is less than 2 or is less than 3 AND where ICMP code is less than 4 \
549             or 5 AND where TCP flags is not 1025 or does match 22193 AND where packet length is less than 57005 \
550             AND where DSCP is greater than 42 AND where fragment does match 'IS FIRST' 'IS LAST' 'IS A' \
551             """,
552             fsParser.stringNlri(flows));
553     }
554
555     @Test
556     public void testExtractFlowspecDestPrefix() {
557         final var entry = ImmutableNodes.newMapEntryBuilder();
558         entry.withNodeIdentifier(NodeIdentifierWithPredicates.of(FlowspecRoute.QNAME, FlowspecRoute.QNAME, entry));
559         entry.withChild(ImmutableNodes.newUnkeyedListBuilder()
560             .withNodeIdentifier(AbstractFlowspecNlriParser.FLOWSPEC_NID)
561             .withChild(ImmutableNodes.newUnkeyedListEntryBuilder()
562                 .withNodeIdentifier(AbstractFlowspecNlriParser.FLOWSPEC_NID)
563                 .withChild(ImmutableNodes.newChoiceBuilder()
564                     .withNodeIdentifier(AbstractFlowspecNlriParser.FLOWSPEC_TYPE_NID)
565                     .withChild(ImmutableNodes.leafNode(AbstractFlowspecNlriParser.DEST_PREFIX_NID, "127.0.0.5/32"))
566                     .build()).build()).build());
567
568         final FlowspecBuilder expectedFS = new FlowspecBuilder();
569         expectedFS.setFlowspecType(new DestinationPrefixCaseBuilder().setDestinationPrefix(
570             new Ipv4Prefix("127.0.0.5/32")).build());
571         assertEquals(List.of(expectedFS.build()), fsParser.extractFlowspec(entry.build()));
572     }
573
574     @Test
575     public void testExtractFlowspecSourcePrefix() {
576         final var entry = ImmutableNodes.newMapEntryBuilder();
577         entry.withNodeIdentifier(NodeIdentifierWithPredicates.of(FlowspecRoute.QNAME, FlowspecRoute.QNAME, entry));
578         entry.withChild(ImmutableNodes.newUnkeyedListBuilder()
579             .withNodeIdentifier(AbstractFlowspecNlriParser.FLOWSPEC_NID)
580             .withChild(ImmutableNodes.newUnkeyedListEntryBuilder()
581                 .withNodeIdentifier(AbstractFlowspecNlriParser.FLOWSPEC_NID)
582                 .withChild(ImmutableNodes.newChoiceBuilder()
583                     .withNodeIdentifier(AbstractFlowspecNlriParser.FLOWSPEC_TYPE_NID)
584                     .withChild(ImmutableNodes.leafNode(AbstractFlowspecNlriParser.SOURCE_PREFIX_NID, "127.0.0.6/32"))
585                     .build()).build()).build());
586
587         final FlowspecBuilder expectedFS = new FlowspecBuilder();
588         expectedFS.setFlowspecType(new SourcePrefixCaseBuilder().setSourcePrefix(new Ipv4Prefix("127.0.0.6/32"))
589             .build());
590         assertEquals(List.of(expectedFS.build()), fsParser.extractFlowspec(entry.build()));
591     }
592
593     @Test
594     public void testExtractFlowspecProtocolIps() {
595         final var entry = ImmutableNodes.newMapEntryBuilder();
596         entry.withNodeIdentifier(NodeIdentifierWithPredicates.of(FlowspecRoute.QNAME, FlowspecRoute.QNAME, entry));
597         entry.withChild(ImmutableNodes.newUnkeyedListBuilder()
598             .withNodeIdentifier(AbstractFlowspecNlriParser.FLOWSPEC_NID)
599             .withChild(ImmutableNodes.newUnkeyedListEntryBuilder()
600                 .withNodeIdentifier(AbstractFlowspecNlriParser.FLOWSPEC_NID)
601                 .withChild(ImmutableNodes.newChoiceBuilder()
602                     .withNodeIdentifier(AbstractFlowspecNlriParser.FLOWSPEC_TYPE_NID)
603                     .withChild(ImmutableNodes.newUnkeyedListBuilder().withNodeIdentifier(PROTOCOL_IP_NID)
604                         .withChild(ImmutableNodes.newUnkeyedListEntryBuilder().withNodeIdentifier(PROTOCOL_IP_NID)
605                             .withChild(ImmutableNodes.leafNode(AbstractFlowspecNlriParser.OP_NID, Set.of(
606                                 AbstractOperandParser.END_OF_LIST_VALUE, AbstractOperandParser.AND_BIT_VALUE)))
607                             .withChild(
608                                 ImmutableNodes.leafNode(AbstractFlowspecNlriParser.VALUE_NID, Uint8.valueOf(100)))
609                             .build())
610                         .withChild(ImmutableNodes.newUnkeyedListEntryBuilder().withNodeIdentifier(PROTOCOL_IP_NID)
611                             .withChild(ImmutableNodes.leafNode(AbstractFlowspecNlriParser.OP_NID, Set.of(
612                                 AbstractOperandParser.AND_BIT_VALUE)))
613                             .withChild(
614                                 ImmutableNodes.leafNode(AbstractFlowspecNlriParser.VALUE_NID, Uint8.valueOf(200)))
615                             .build())
616                         .withChild(ImmutableNodes.newUnkeyedListEntryBuilder().withNodeIdentifier(PROTOCOL_IP_NID)
617                             .withChild(ImmutableNodes.leafNode(AbstractFlowspecNlriParser.OP_NID, Set.of(
618                                 AbstractOperandParser.END_OF_LIST_VALUE, AbstractOperandParser.AND_BIT_VALUE,
619                                 AbstractNumericOperandParser.EQUALS_VALUE)))
620                             .withChild(
621                                 ImmutableNodes.leafNode(AbstractFlowspecNlriParser.VALUE_NID, Uint8.valueOf(240)))
622                             .build())
623                         .build()).build()).build()).build());
624
625         final FlowspecBuilder expectedFS = new FlowspecBuilder();
626         expectedFS.setFlowspecType(new ProtocolIpCaseBuilder().setProtocolIps(
627             List.of(
628                 new ProtocolIpsBuilder().setValue(Uint8.valueOf(100)).setOp(
629                     new NumericOperand(true, true, false, false, false)).build(),
630                 new ProtocolIpsBuilder().setValue(Uint8.valueOf(200)).setOp(
631                     new NumericOperand(true, false, false, false, false)).build(),
632                 new ProtocolIpsBuilder().setValue(Uint8.valueOf(240)).setOp(
633                     new NumericOperand(true, true, true, false, false)).build())).build());
634         assertEquals(List.of(expectedFS.build()), fsParser.extractFlowspec(entry.build()));
635     }
636
637     @Test
638     public void testExtractFlowspecPorts() {
639         final var entry = ImmutableNodes.newMapEntryBuilder();
640         entry.withNodeIdentifier(NodeIdentifierWithPredicates.of(FlowspecRoute.QNAME, FlowspecRoute.QNAME, entry));
641         entry.withChild(ImmutableNodes.newUnkeyedListBuilder()
642             .withNodeIdentifier(AbstractFlowspecNlriParser.FLOWSPEC_NID)
643             .withChild(ImmutableNodes.newUnkeyedListEntryBuilder()
644                 .withNodeIdentifier(AbstractFlowspecNlriParser.FLOWSPEC_NID)
645                 .withChild(ImmutableNodes.newChoiceBuilder()
646                     .withNodeIdentifier(AbstractFlowspecNlriParser.FLOWSPEC_TYPE_NID)
647                     .withChild(ImmutableNodes.newUnkeyedListBuilder()
648                         .withNodeIdentifier(AbstractFlowspecNlriParser.PORTS_NID)
649                         .withChild(ImmutableNodes.newUnkeyedListEntryBuilder().withNodeIdentifier(PROTOCOL_IP_NID)
650                             .withChild(ImmutableNodes.leafNode(AbstractFlowspecNlriParser.OP_NID, Set.of(
651                                 AbstractOperandParser.END_OF_LIST_VALUE, AbstractOperandParser.AND_BIT_VALUE,
652                                 AbstractNumericOperandParser.LESS_THAN_VALUE)))
653                             .withChild(
654                                 ImmutableNodes.leafNode(AbstractFlowspecNlriParser.VALUE_NID, Uint16.valueOf(100)))
655                             .build())
656                         .build()).build()).build()).build());
657
658         final FlowspecBuilder expectedFS = new FlowspecBuilder()
659                 .setFlowspecType(new PortCaseBuilder()
660                     .setPorts(List.of(new PortsBuilder()
661                         .setValue(Uint16.valueOf(100))
662                         .setOp(new NumericOperand(true, true, false, false, true))
663                         .build()))
664                     .build());
665         assertEquals(List.of(expectedFS.build()), fsParser.extractFlowspec(entry.build()));
666     }
667
668     @Test
669     public void testExtractFlowspecDestinationPorts() {
670         final var entry = ImmutableNodes.newMapEntryBuilder();
671         entry.withNodeIdentifier(NodeIdentifierWithPredicates.of(FlowspecRoute.QNAME, FlowspecRoute.QNAME, entry));
672         entry.withChild(ImmutableNodes.newUnkeyedListBuilder()
673             .withNodeIdentifier(AbstractFlowspecNlriParser.FLOWSPEC_NID)
674             .withChild(ImmutableNodes.newUnkeyedListEntryBuilder()
675                 .withNodeIdentifier(AbstractFlowspecNlriParser.FLOWSPEC_NID)
676                 .withChild(ImmutableNodes.newChoiceBuilder()
677                     .withNodeIdentifier(AbstractFlowspecNlriParser.FLOWSPEC_TYPE_NID)
678                     .withChild(ImmutableNodes.newUnkeyedListBuilder()
679                         .withNodeIdentifier(AbstractFlowspecNlriParser.DEST_PORT_NID)
680                         .withChild(ImmutableNodes.newUnkeyedListEntryBuilder()
681                             .withNodeIdentifier(AbstractFlowspecNlriParser.OP_NID)
682                             .withChild(ImmutableNodes.leafNode(AbstractFlowspecNlriParser.OP_NID, Set.of(
683                                 AbstractOperandParser.END_OF_LIST_VALUE, AbstractNumericOperandParser.EQUALS_VALUE)))
684                             .withChild(
685                                 ImmutableNodes.leafNode(AbstractFlowspecNlriParser.VALUE_NID, Uint16.valueOf(1024)))
686                             .build())
687                         .build()).build()).build()).build());
688         final FlowspecBuilder expectedFS = new FlowspecBuilder();
689         expectedFS.setFlowspecType(new DestinationPortCaseBuilder()
690             .setDestinationPorts(List.of(new DestinationPortsBuilder()
691                 .setValue(Uint16.valueOf(1024))
692                 .setOp(new NumericOperand(false, true, true, false, false))
693                 .build()))
694             .build());
695         assertEquals(List.of(expectedFS.build()), fsParser.extractFlowspec(entry.build()));
696     }
697
698     @Test
699     public void testExtractFlowspecSourcePorts() {
700         final var entry = ImmutableNodes.newMapEntryBuilder();
701         entry.withNodeIdentifier(NodeIdentifierWithPredicates.of(FlowspecRoute.QNAME, FlowspecRoute.QNAME, entry));
702         entry.withChild(ImmutableNodes.newUnkeyedListBuilder()
703             .withNodeIdentifier(AbstractFlowspecNlriParser.FLOWSPEC_NID)
704             .withChild(ImmutableNodes.newUnkeyedListEntryBuilder()
705                 .withNodeIdentifier(AbstractFlowspecNlriParser.FLOWSPEC_NID)
706                 .withChild(ImmutableNodes.newChoiceBuilder()
707                     .withNodeIdentifier(AbstractFlowspecNlriParser.FLOWSPEC_TYPE_NID)
708                     .withChild(ImmutableNodes.newUnkeyedListBuilder()
709                         .withNodeIdentifier(AbstractFlowspecNlriParser.SOURCE_PORT_NID)
710                         .withChild(ImmutableNodes.newUnkeyedListEntryBuilder()
711                             .withNodeIdentifier(AbstractFlowspecNlriParser.OP_NID)
712                             .withChild(ImmutableNodes.leafNode(AbstractFlowspecNlriParser.OP_NID, Set.of(
713                                 AbstractOperandParser.AND_BIT_VALUE, AbstractOperandParser.END_OF_LIST_VALUE,
714                                 AbstractNumericOperandParser.EQUALS_VALUE,
715                                 AbstractNumericOperandParser.GREATER_THAN_VALUE,
716                                 AbstractNumericOperandParser.LESS_THAN_VALUE)))
717                             .withChild(
718                                 ImmutableNodes.leafNode(AbstractFlowspecNlriParser.VALUE_NID, Uint16.valueOf(8080)))
719                             .build())
720                         .build()).build()).build()).build());
721         final FlowspecBuilder expectedFS = new FlowspecBuilder();
722         expectedFS.setFlowspecType(new SourcePortCaseBuilder()
723             .setSourcePorts(List.of(new SourcePortsBuilder()
724                 .setValue(Uint16.valueOf(8080))
725                 .setOp(new NumericOperand(true, true, true, true, true))
726                 .build()))
727             .build());
728         assertEquals(List.of(expectedFS.build()), fsParser.extractFlowspec(entry.build()));
729     }
730
731     @Test
732     public void testExtractFlowspecSourceTypes() {
733         final var entry = ImmutableNodes.newMapEntryBuilder();
734         entry.withNodeIdentifier(NodeIdentifierWithPredicates.of(FlowspecRoute.QNAME, FlowspecRoute.QNAME, entry));
735         entry.withChild(ImmutableNodes.newUnkeyedListBuilder()
736             .withNodeIdentifier(AbstractFlowspecNlriParser.FLOWSPEC_NID)
737             .withChild(ImmutableNodes.newUnkeyedListEntryBuilder()
738                 .withNodeIdentifier(AbstractFlowspecNlriParser.FLOWSPEC_NID)
739                 .withChild(ImmutableNodes.newChoiceBuilder()
740                     .withNodeIdentifier(AbstractFlowspecNlriParser.FLOWSPEC_TYPE_NID)
741                     .withChild(ImmutableNodes.newUnkeyedListBuilder()
742                         .withNodeIdentifier(AbstractFlowspecNlriParser.ICMP_TYPE_NID)
743                         .withChild(ImmutableNodes.newUnkeyedListEntryBuilder()
744                             .withNodeIdentifier(AbstractFlowspecNlriParser.OP_NID)
745                             .withChild(ImmutableNodes.leafNode(AbstractFlowspecNlriParser.OP_NID, Set.of(
746                                 AbstractOperandParser.AND_BIT_VALUE, AbstractOperandParser.END_OF_LIST_VALUE,
747                                 AbstractNumericOperandParser.EQUALS_VALUE,
748                                 AbstractNumericOperandParser.GREATER_THAN_VALUE,
749                                 AbstractNumericOperandParser.LESS_THAN_VALUE)))
750                             .withChild(ImmutableNodes.leafNode(AbstractFlowspecNlriParser.VALUE_NID, Uint8.valueOf(22)))
751                             .build())
752                         .build()).build()).build()).build());
753         final FlowspecBuilder expectedFS = new FlowspecBuilder();
754         expectedFS.setFlowspecType(new IcmpTypeCaseBuilder().setTypes(List.of(new TypesBuilder()
755             .setValue(Uint8.valueOf(22)).setOp(new NumericOperand(true, true, true, true, true)).build())).build());
756         assertEquals(List.of(expectedFS.build()), fsParser.extractFlowspec(entry.build()));
757     }
758
759     @Test
760     public void testExtractFlowspecSourceCodes() {
761         final var entry = ImmutableNodes.newMapEntryBuilder();
762         entry.withNodeIdentifier(NodeIdentifierWithPredicates.of(FlowspecRoute.QNAME, FlowspecRoute.QNAME, entry));
763         entry.withChild(ImmutableNodes.newUnkeyedListBuilder()
764             .withNodeIdentifier(AbstractFlowspecNlriParser.FLOWSPEC_NID)
765             .withChild(ImmutableNodes.newUnkeyedListEntryBuilder()
766                 .withNodeIdentifier(AbstractFlowspecNlriParser.FLOWSPEC_NID)
767                 .withChild(ImmutableNodes.newChoiceBuilder()
768                     .withNodeIdentifier(AbstractFlowspecNlriParser.FLOWSPEC_TYPE_NID)
769                     .withChild(ImmutableNodes.newUnkeyedListBuilder()
770                         .withNodeIdentifier(AbstractFlowspecNlriParser.ICMP_CODE_NID)
771                         .withChild(ImmutableNodes.newUnkeyedListEntryBuilder()
772                             .withNodeIdentifier(AbstractFlowspecNlriParser.OP_NID)
773                             .withChild(ImmutableNodes.leafNode(AbstractFlowspecNlriParser.OP_NID, Set.of()))
774                             .withChild(ImmutableNodes.leafNode(AbstractFlowspecNlriParser.VALUE_NID, Uint8.valueOf(23)))
775                             .build())
776                         .build()).build()).build()).build());
777         final FlowspecBuilder expectedFS = new FlowspecBuilder();
778         expectedFS.setFlowspecType(new IcmpCodeCaseBuilder().setCodes(List.of(new CodesBuilder()
779             .setValue(Uint8.valueOf(23)).setOp(new NumericOperand(false, false, false, false, false)).build()))
780             .build());
781         assertEquals(List.of(expectedFS.build()), fsParser.extractFlowspec(entry.build()));
782     }
783
784     @Test
785     public void testExtractFlowspecSourceTcpFlags() {
786         final var entry = ImmutableNodes.newMapEntryBuilder();
787         entry.withNodeIdentifier(NodeIdentifierWithPredicates.of(FlowspecRoute.QNAME, FlowspecRoute.QNAME, entry));
788         entry.withChild(ImmutableNodes.newUnkeyedListBuilder()
789             .withNodeIdentifier(AbstractFlowspecNlriParser.FLOWSPEC_NID)
790             .withChild(ImmutableNodes.newUnkeyedListEntryBuilder()
791                 .withNodeIdentifier(AbstractFlowspecNlriParser.FLOWSPEC_NID)
792                 .withChild(ImmutableNodes.newChoiceBuilder()
793                     .withNodeIdentifier(AbstractFlowspecNlriParser.FLOWSPEC_TYPE_NID)
794                     .withChild(ImmutableNodes.newUnkeyedListBuilder()
795                         .withNodeIdentifier(AbstractFlowspecNlriParser.TCP_FLAGS_NID)
796                         .withChild(ImmutableNodes.newUnkeyedListEntryBuilder()
797                             .withNodeIdentifier(AbstractFlowspecNlriParser.OP_NID)
798                             .withChild(ImmutableNodes.leafNode(AbstractFlowspecNlriParser.OP_NID, Set.of(
799                                 AbstractOperandParser.AND_BIT_VALUE, AbstractOperandParser.END_OF_LIST_VALUE)))
800                             .withChild(
801                                 ImmutableNodes.leafNode(AbstractFlowspecNlriParser.VALUE_NID, Uint16.valueOf(99)))
802                             .build())
803                         .build()).build()).build()).build());
804         final FlowspecBuilder expectedFS = new FlowspecBuilder();
805         expectedFS.setFlowspecType(new TcpFlagsCaseBuilder()
806             .setTcpFlags(List.of(new TcpFlagsBuilder()
807                 .setValue(Uint16.valueOf(99))
808                 .setOp(new BitmaskOperand(true, true, false, false))
809                 .build()))
810             .build());
811         assertEquals(List.of(expectedFS.build()), fsParser.extractFlowspec(entry.build()));
812     }
813
814     @Test
815     public void testExtractFlowspecPacketLengths() {
816         final var entry = ImmutableNodes.newMapEntryBuilder();
817         entry.withNodeIdentifier(NodeIdentifierWithPredicates.of(FlowspecRoute.QNAME, FlowspecRoute.QNAME, entry));
818         entry.withChild(ImmutableNodes.newUnkeyedListBuilder()
819             .withNodeIdentifier(AbstractFlowspecNlriParser.FLOWSPEC_NID)
820             .withChild(ImmutableNodes.newUnkeyedListEntryBuilder()
821                 .withNodeIdentifier(AbstractFlowspecNlriParser.FLOWSPEC_NID)
822                 .withChild(ImmutableNodes.newChoiceBuilder()
823                     .withNodeIdentifier(AbstractFlowspecNlriParser.FLOWSPEC_TYPE_NID)
824                     .withChild(ImmutableNodes.newUnkeyedListBuilder()
825                         .withNodeIdentifier(AbstractFlowspecNlriParser.PACKET_LENGTHS_NID)
826                         .withChild(ImmutableNodes.newUnkeyedListEntryBuilder()
827                             .withNodeIdentifier(AbstractFlowspecNlriParser.OP_NID)
828                             .withChild(ImmutableNodes.leafNode(AbstractFlowspecNlriParser.OP_NID, Set.of(
829                                 AbstractOperandParser.AND_BIT_VALUE, AbstractNumericOperandParser.GREATER_THAN_VALUE)))
830                             .withChild(
831                                 ImmutableNodes.leafNode(AbstractFlowspecNlriParser.VALUE_NID, Uint16.valueOf(101)))
832                             .build())
833                         .build()).build()).build()).build());
834         final FlowspecBuilder expectedFS = new FlowspecBuilder();
835         expectedFS.setFlowspecType(new PacketLengthCaseBuilder()
836             .setPacketLengths(List.of(new PacketLengthsBuilder()
837                 .setValue(Uint16.valueOf(101))
838                 .setOp(new NumericOperand(true, false, false, true, false))
839                 .build()))
840             .build());
841         assertEquals(List.of(expectedFS.build()), fsParser.extractFlowspec(entry.build()));
842     }
843
844     @Test
845     public void testExtractFlowspecDscps() {
846         final var entry = ImmutableNodes.newMapEntryBuilder();
847         entry.withNodeIdentifier(NodeIdentifierWithPredicates.of(FlowspecRoute.QNAME, FlowspecRoute.QNAME, entry));
848         entry.withChild(ImmutableNodes.newUnkeyedListBuilder()
849             .withNodeIdentifier(AbstractFlowspecNlriParser.FLOWSPEC_NID)
850             .withChild(ImmutableNodes.newUnkeyedListEntryBuilder()
851                 .withNodeIdentifier(AbstractFlowspecNlriParser.FLOWSPEC_NID)
852                 .withChild(ImmutableNodes.newChoiceBuilder()
853                     .withNodeIdentifier(AbstractFlowspecNlriParser.FLOWSPEC_TYPE_NID)
854                     .withChild(ImmutableNodes.newUnkeyedListBuilder()
855                         .withNodeIdentifier(AbstractFlowspecNlriParser.DSCP_NID)
856                         .withChild(ImmutableNodes.newUnkeyedListEntryBuilder()
857                             .withNodeIdentifier(AbstractFlowspecNlriParser.OP_NID)
858                             .withChild(ImmutableNodes.leafNode(AbstractFlowspecNlriParser.OP_NID, Set.of(
859                                 AbstractOperandParser.AND_BIT_VALUE, AbstractOperandParser.END_OF_LIST_VALUE,
860                                 AbstractNumericOperandParser.GREATER_THAN_VALUE)))
861                             .withChild(ImmutableNodes.leafNode(AbstractFlowspecNlriParser.VALUE_NID, Uint8.valueOf(15)))
862                             .build())
863                         .build()).build()).build()).build());
864         final FlowspecBuilder expectedFS = new FlowspecBuilder();
865         expectedFS.setFlowspecType(new DscpCaseBuilder().setDscps(List.of(new DscpsBuilder()
866             .setValue(new Dscp(Uint8.valueOf(15))).setOp(new NumericOperand(true, true, false, true, false)).build()))
867             .build());
868         assertEquals(List.of(expectedFS.build()), fsParser.extractFlowspec(entry.build()));
869     }
870
871     @Test
872     public void testExtractFlowspecFragments() {
873         final var entry = ImmutableNodes.newMapEntryBuilder();
874         entry.withNodeIdentifier(NodeIdentifierWithPredicates.of(FlowspecRoute.QNAME, FlowspecRoute.QNAME, entry));
875         entry.withChild(ImmutableNodes.newUnkeyedListBuilder()
876             .withNodeIdentifier(AbstractFlowspecNlriParser.FLOWSPEC_NID)
877             .withChild(ImmutableNodes.newUnkeyedListEntryBuilder()
878                 .withNodeIdentifier(AbstractFlowspecNlriParser.FLOWSPEC_NID)
879                 .withChild(ImmutableNodes.newChoiceBuilder()
880                     .withNodeIdentifier(AbstractFlowspecNlriParser.FLOWSPEC_TYPE_NID)
881                     .withChild(ImmutableNodes.newUnkeyedListBuilder()
882                         .withNodeIdentifier(AbstractFlowspecNlriParser.FRAGMENT_NID)
883                         .withChild(ImmutableNodes.newUnkeyedListEntryBuilder()
884                             .withNodeIdentifier(AbstractFlowspecNlriParser.OP_NID)
885                             .withChild(ImmutableNodes.leafNode(AbstractFlowspecNlriParser.OP_NID, Set.of(
886                                 AbstractOperandParser.AND_BIT_VALUE, AbstractOperandParser.END_OF_LIST_VALUE,
887                                 BitmaskOperandParser.MATCH_VALUE, BitmaskOperandParser.NOT_VALUE)))
888                             .withChild(ImmutableNodes.leafNode(AbstractFlowspecNlriParser.VALUE_NID, Set.of(
889                                 AbstractFlowspecNlriParser.DO_NOT_VALUE, AbstractFlowspecNlriParser.FIRST_VALUE,
890                                 AbstractFlowspecNlriParser.IS_A_VALUE, AbstractFlowspecNlriParser.LAST_VALUE)))
891                             .build())
892                         .build()).build()).build()).build());
893         final FlowspecBuilder expectedFS = new FlowspecBuilder();
894         expectedFS.setFlowspecType(new FragmentCaseBuilder().setFragments(List.of(new FragmentsBuilder()
895             .setValue(new Fragment(true, true, true, true)).setOp(new BitmaskOperand(true, true, true, true)).build()))
896             .build());
897         assertEquals(List.of(expectedFS.build()), fsParser.extractFlowspec(entry.build()));
898     }
899
900     @Test
901     public void testBatchedFlowspecNlri() throws Exception {
902         final SimpleFlowspecIpv4NlriParser parser = new SimpleFlowspecIpv4NlriParser(SAFI.FLOWSPEC);
903
904         final MpReachNlriBuilder result = new MpReachNlriBuilder()
905             .setAfi(Ipv4AddressFamily.VALUE)
906             .setSafi(FlowspecSubsequentAddressFamily.VALUE);
907
908         parser.parseNlri(Unpooled.wrappedBuffer(REACHED_NLRI_BATCHED), result, null);
909         final MpReachNlri nlri = result.build();
910
911         final List<Flowspec> flowspecList = ((DestinationFlowspecCase) nlri.getAdvertizedRoutes().getDestinationType())
912                 .getDestinationFlowspecIpv4().nonnullFlowspec();
913         assertEquals(3, flowspecList.size());
914         assertEquals("216.58.245.101/32", ((DestinationPrefixCase) flowspecList.get(0).getFlowspecType())
915             .getDestinationPrefix().getValue());
916         assertEquals("216.58.218.196/32", ((DestinationPrefixCase) flowspecList.get(1).getFlowspecType())
917             .getDestinationPrefix().getValue());
918         assertEquals("216.58.216.195/32", ((DestinationPrefixCase) flowspecList.get(2).getFlowspecType())
919             .getDestinationPrefix().getValue());
920     }
921 }
922