2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.protocol.bgp.flowspec;
10 import com.google.common.base.Optional;
11 import com.google.common.primitives.Bytes;
12 import io.netty.buffer.ByteBuf;
13 import io.netty.buffer.Unpooled;
14 import java.util.ArrayList;
15 import java.util.List;
17 import org.opendaylight.protocol.util.BitArray;
18 import org.opendaylight.protocol.util.ByteArray;
19 import org.opendaylight.protocol.util.Ipv6Util;
20 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.Fragment;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.NumericOperand;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.Flowspec;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.FlowspecBuilder;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.flowspec.FlowspecType;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.flowspec.flowspec.type.FragmentCase;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.flowspec.flowspec.type.FragmentCaseBuilder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.ipv6.flowspec.flowspec.type.DestinationIpv6PrefixCase;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.ipv6.flowspec.flowspec.type.DestinationIpv6PrefixCaseBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.ipv6.flowspec.flowspec.type.FlowLabelCase;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.ipv6.flowspec.flowspec.type.FlowLabelCaseBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.ipv6.flowspec.flowspec.type.NextHeaderCase;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.ipv6.flowspec.flowspec.type.NextHeaderCaseBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.ipv6.flowspec.flowspec.type.SourceIpv6PrefixCase;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.ipv6.flowspec.flowspec.type.SourceIpv6PrefixCaseBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.ipv6.flowspec.flowspec.type.flow.label._case.FlowLabel;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.ipv6.flowspec.flowspec.type.flow.label._case.FlowLabelBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.ipv6.flowspec.flowspec.type.next.header._case.NextHeaders;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.ipv6.flowspec.flowspec.type.next.header._case.NextHeadersBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.update.attributes.mp.unreach.nlri.withdrawn.routes.destination.type.DestinationFlowspecIpv6Case;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.update.attributes.mp.unreach.nlri.withdrawn.routes.destination.type.DestinationFlowspecIpv6CaseBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.update.attributes.mp.unreach.nlri.withdrawn.routes.destination.type.destination.flowspec.ipv6._case.DestinationFlowspecBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.Attributes1;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.Attributes2;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.destination.DestinationType;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpUnreachNlri;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.mp.reach.nlri.AdvertizedRoutes;
48 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
49 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
50 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
51 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
52 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
53 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
55 public final class FSIpv6NlriParser extends AbstractFSNlriParser {
57 private static final int NEXT_HEADER_VALUE = 3;
58 private static final int FLOW_LABLE_VALUE = 13;
60 static final NodeIdentifier NEXT_HEADER_NID = new NodeIdentifier(NextHeaders.QNAME);
61 static final NodeIdentifier FLOW_LABEL_NID = new NodeIdentifier(FlowLabel.QNAME);
64 protected void serializeMpReachNlri(final Attributes1 pathAttributes, final ByteBuf byteAggregator) {
65 if (pathAttributes == null) {
68 final AdvertizedRoutes routes = (pathAttributes.getMpReachNlri()).getAdvertizedRoutes();
69 if (routes != null && routes.getDestinationType() instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.update.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationFlowspecIpv6Case) {
70 final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.update.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationFlowspecIpv6Case flowspecCase = (org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.update.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationFlowspecIpv6Case) routes.getDestinationType();
71 serializeNlri(flowspecCase.getDestinationFlowspec().getFlowspec(), byteAggregator);
76 protected void serializeMpUnreachNlri(final Attributes2 pathAttributes, final ByteBuf byteAggregator) {
77 if (pathAttributes == null) {
80 final MpUnreachNlri mpUnreachNlri = pathAttributes.getMpUnreachNlri();
81 if (mpUnreachNlri.getWithdrawnRoutes() != null && mpUnreachNlri.getWithdrawnRoutes().getDestinationType() instanceof DestinationFlowspecIpv6Case) {
82 final DestinationFlowspecIpv6Case flowspecCase = (DestinationFlowspecIpv6Case) mpUnreachNlri.getWithdrawnRoutes().getDestinationType();
83 serializeNlri(flowspecCase.getDestinationFlowspec().getFlowspec(), byteAggregator);
88 protected void serializeSpecificFSType(final FlowspecType value, final ByteBuf nlriByteBuf) {
89 if (value instanceof DestinationIpv6PrefixCase) {
90 nlriByteBuf.writeByte(DESTINATION_PREFIX_VALUE);
91 nlriByteBuf.writeBytes(insertOffsetByte(Ipv6Util.bytesForPrefixBegin(((DestinationIpv6PrefixCase) value).getDestinationPrefix())));
92 } else if (value instanceof SourceIpv6PrefixCase) {
93 nlriByteBuf.writeByte(SOURCE_PREFIX_VALUE);
94 nlriByteBuf.writeBytes(insertOffsetByte(Ipv6Util.bytesForPrefixBegin(((SourceIpv6PrefixCase) value).getSourcePrefix())));
95 } else if (value instanceof NextHeaderCase) {
96 nlriByteBuf.writeByte(NEXT_HEADER_VALUE);
97 serializeNumericOneByteValue(((NextHeaderCase) value).getNextHeaders(), nlriByteBuf);
98 } else if (value instanceof FragmentCase) {
99 nlriByteBuf.writeByte(FRAGMENT_VALUE);
100 serializeFragments(((FragmentCase) value).getFragments(), nlriByteBuf);
101 } else if (value instanceof FlowLabelCase) {
102 nlriByteBuf.writeByte(FLOW_LABLE_VALUE);
103 serializeNumericFourByteValue(((FlowLabelCase) value).getFlowLabel(), nlriByteBuf);
107 private static void serializeNumericFourByteValue(final List<FlowLabel> list, final ByteBuf nlriByteBuf) {
108 for (final FlowLabel item : list) {
109 final ByteBuf protoBuf = Unpooled.buffer();
110 writeShortest(item.getValue().intValue(), protoBuf);
111 serializeNumericOperand(item.getOp(), protoBuf.readableBytes(), nlriByteBuf);
112 nlriByteBuf.writeBytes(protoBuf);
116 private static byte[] insertOffsetByte(final byte[] ipPrefix) {
117 // income <len, prefix>
118 return Bytes.concat(new byte[] { ipPrefix[0] }, new byte[] { 0 }, ByteArray.subByte(ipPrefix, 1 , ipPrefix.length-1));
122 protected byte serializeFragment(final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.Fragment fragment) {
123 final BitArray bs = new BitArray(Byte.SIZE);
124 bs.set(DONT_FRAGMENT, Boolean.FALSE);
125 bs.set(FIRST_FRAGMENT, fragment.isFirst());
126 bs.set(IS_A_FRAGMENT, fragment.isIsA());
127 bs.set(LAST_FRAGMENT, fragment.isLast());
132 DestinationType createWidthdrawnDestinationType(final List<Flowspec> dst) {
133 return new DestinationFlowspecIpv6CaseBuilder().setDestinationFlowspec(
134 new DestinationFlowspecBuilder().setFlowspec(
135 dst).build()).build();
139 DestinationType createAdvertizedRoutesDestinationType(final List<Flowspec> dst) {
140 return new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.update.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationFlowspecIpv6CaseBuilder()
141 .setDestinationFlowspec(new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.update.attributes.mp.reach.nlri.advertized.routes.destination.type.destination.flowspec.ipv6._case.DestinationFlowspecBuilder()
142 .setFlowspec(dst).build()).build();
146 protected void setSpecificFlowspecType(final FlowspecBuilder builder, final short type, final ByteBuf nlri) {
148 case DESTINATION_PREFIX_VALUE:
149 builder.setFlowspecType(new DestinationIpv6PrefixCaseBuilder().setDestinationPrefix(parseIpv6Prefix(nlri)).build());
151 case SOURCE_PREFIX_VALUE:
152 builder.setFlowspecType(new SourceIpv6PrefixCaseBuilder().setSourcePrefix(parseIpv6Prefix(nlri)).build());
154 case NEXT_HEADER_VALUE:
155 builder.setFlowspecType(new NextHeaderCaseBuilder().setNextHeaders(parseNextHeader(nlri)).build());
158 builder.setFlowspecType(new FragmentCaseBuilder().setFragments(parseFragment(nlri)).build());
160 case FLOW_LABLE_VALUE:
161 builder.setFlowspecType(new FlowLabelCaseBuilder().setFlowLabel(parseFlowLabel(nlri)).build());
168 private static Ipv6Prefix parseIpv6Prefix(final ByteBuf nlri) {
169 final int bitLength = nlri.readByte();
170 final int offset = nlri.readByte();
171 nlri.readBytes(offset);
172 return Ipv6Util.prefixForBytes(ByteArray.readBytes(nlri, bitLength / Byte.SIZE), bitLength);
176 protected Fragment parseFragment(final byte fragment) {
177 final BitArray bs = BitArray.valueOf(fragment);
178 return new Fragment(Boolean.FALSE, bs.get(FIRST_FRAGMENT), bs.get(IS_A_FRAGMENT), bs.get(LAST_FRAGMENT));
181 private static List<NextHeaders> parseNextHeader(final ByteBuf nlri) {
182 final List<NextHeaders> headers = new ArrayList<>();
184 // we can do this as all fields will be rewritten in the cycle
185 final NextHeadersBuilder builder = new NextHeadersBuilder();
187 final byte b = nlri.readByte();
188 final NumericOperand op = parseNumeric(b);
190 builder.setValue(nlri.readUnsignedByte());
191 end = op.isEndOfList();
192 headers.add(builder.build());
197 private static List<FlowLabel> parseFlowLabel(final ByteBuf nlri) {
198 final List<FlowLabel> labels = new ArrayList<>();
200 // we can do this as all fields will be rewritten in the cycle
201 final FlowLabelBuilder builder = new FlowLabelBuilder();
203 final byte b = nlri.readByte();
204 final NumericOperand op = parseNumeric(b);
206 final short length = parseLength(b);
207 builder.setValue(ByteArray.bytesToLong(ByteArray.readBytes(nlri, length)));
208 end = op.isEndOfList();
209 labels.add(builder.build());
215 public void extractSpecificFlowspec(final ChoiceNode fsType, final FlowspecBuilder fsBuilder) {
216 if (fsType.getChild(DEST_PREFIX_NID).isPresent()) {
217 fsBuilder.setFlowspecType(new DestinationIpv6PrefixCaseBuilder()
218 .setDestinationPrefix(new Ipv6Prefix((String) fsType.getChild(DEST_PREFIX_NID).get().getValue()))
220 } else if (fsType.getChild(SOURCE_PREFIX_NID).isPresent()) {
221 fsBuilder.setFlowspecType(new SourceIpv6PrefixCaseBuilder()
222 .setSourcePrefix(new Ipv6Prefix((String) fsType.getChild(SOURCE_PREFIX_NID).get().getValue()))
224 } else if (fsType.getChild(NEXT_HEADER_NID).isPresent()) {
225 fsBuilder.setFlowspecType(new NextHeaderCaseBuilder().setNextHeaders(createNextHeaders((UnkeyedListNode) fsType.getChild(NEXT_HEADER_NID).get())).build());
226 } else if (fsType.getChild(FLOW_LABEL_NID).isPresent()) {
227 fsBuilder.setFlowspecType(new FlowLabelCaseBuilder().setFlowLabel(createFlowLabels((UnkeyedListNode) fsType.getChild(FLOW_LABEL_NID).get())).build());
231 private List<NextHeaders> createNextHeaders(final UnkeyedListNode nextHeadersData) {
232 final List<NextHeaders> nextHeaders = new ArrayList<>();
234 for (final UnkeyedListEntryNode node : nextHeadersData.getValue()) {
235 final NextHeadersBuilder nextHeadersBuilder = new NextHeadersBuilder();
236 final Optional<DataContainerChild<? extends PathArgument, ?>> opValue = node.getChild(OP_NID);
237 if (opValue.isPresent()) {
238 nextHeadersBuilder.setOp(createNumericOperand((Set<String>) opValue.get().getValue()));
240 final Optional<DataContainerChild<? extends PathArgument, ?>> valueNode = node.getChild(VALUE_NID);
241 if (valueNode.isPresent()) {
242 nextHeadersBuilder.setValue((Short) valueNode.get().getValue());
244 nextHeaders.add(nextHeadersBuilder.build());
250 private List<FlowLabel> createFlowLabels(final UnkeyedListNode flowLabelsData) {
251 final List<FlowLabel> flowLabels = new ArrayList<>();
253 for (final UnkeyedListEntryNode node : flowLabelsData.getValue()) {
254 final FlowLabelBuilder flowLabelsBuilder = new FlowLabelBuilder();
255 final Optional<DataContainerChild<? extends PathArgument, ?>> opValue = node.getChild(OP_NID);
256 if (opValue.isPresent()) {
257 flowLabelsBuilder.setOp(createNumericOperand((Set<String>) opValue.get().getValue()));
259 final Optional<DataContainerChild<? extends PathArgument, ?>> valueNode = node.getChild(VALUE_NID);
260 if (valueNode.isPresent()) {
261 flowLabelsBuilder.setValue((Long) valueNode.get().getValue());
263 flowLabels.add(flowLabelsBuilder.build());
270 protected void stringSpecificFSNlriType(final FlowspecType value, final StringBuilder buffer) {
271 if (value instanceof DestinationIpv6PrefixCase) {
272 buffer.append("to ");
273 buffer.append(((DestinationIpv6PrefixCase) value).getDestinationPrefix().getValue());
274 } else if (value instanceof SourceIpv6PrefixCase) {
275 buffer.append("from ");
276 buffer.append(((SourceIpv6PrefixCase) value).getSourcePrefix().getValue());
277 } else if (value instanceof NextHeaderCase) {
278 buffer.append("where next header ");
279 buffer.append(stringNumericOne(((NextHeaderCase) value).getNextHeaders()));
280 } else if (value instanceof FlowLabelCase) {
281 buffer.append("where flow label ");
282 buffer.append(stringFlowLabel(((FlowLabelCase) value).getFlowLabel()));
286 private static String stringFlowLabel(final List<FlowLabel> list) {
287 final StringBuilder buffer = new StringBuilder();
288 boolean isFirst = true;
289 for (final FlowLabel item : list) {
290 buffer.append(stringNumericOperand(item.getOp(), isFirst));
291 buffer.append(item.getValue());
297 return buffer.toString();