/* * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.protocol.bgp.linkstate.impl.attribute; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import org.opendaylight.protocol.bgp.parser.BGPParsingException; import org.opendaylight.protocol.bgp.parser.spi.AbstractAttributeParser; import org.opendaylight.protocol.bgp.parser.spi.AttributeSerializer; import org.opendaylight.protocol.bgp.parser.spi.AttributeUtil; import org.opendaylight.protocol.bgp.parser.spi.PeerSpecificParserConstraint; import org.opendaylight.protocol.bgp.parser.spi.RevisedErrorHandling; import org.opendaylight.protocol.rsvp.parser.spi.RSVPTeObjectRegistry; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.Attributes1; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.Attributes1Builder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.ProtocolId; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.ObjectType; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.destination.CLinkstateDestination; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.object.type.LinkCase; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.object.type.NodeCase; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.object.type.PrefixCase; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.object.type.TeLspCase; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.path.attribute.LinkStateAttribute; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.path.attribute.link.state.attribute.LinkAttributesCase; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.path.attribute.link.state.attribute.NodeAttributesCase; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.path.attribute.link.state.attribute.PrefixAttributesCase; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.path.attribute.link.state.attribute.TeLspAttributesCase; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.update.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationLinkstateCase; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.path.attributes.Attributes; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.path.attributes.AttributesBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.AttributesReach; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.AttributesUnreach; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.destination.DestinationType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Parser for Link State Path Attribute. * * @see BGP-LS draft */ public final class LinkstateAttributeParser extends AbstractAttributeParser implements AttributeSerializer { private static final Logger LOG = LoggerFactory.getLogger(LinkstateAttributeParser.class); private static final int TYPE = 29; private static final int LEGACY_TYPE = 99; private final int type; private final RSVPTeObjectRegistry rsvpTeObjectRegistry; public LinkstateAttributeParser(final boolean isIanaAssignedType, final RSVPTeObjectRegistry rsvpTeObjectRegistry) { this.type = isIanaAssignedType ? TYPE : LEGACY_TYPE; this.rsvpTeObjectRegistry = rsvpTeObjectRegistry; } private static Multimap getAttributesMap(final ByteBuf buffer) { /* * e.g. IS-IS Area Identifier TLV can occur multiple times */ final Multimap map = HashMultimap.create(); while (buffer.isReadable()) { final int type = buffer.readUnsignedShort(); final int length = buffer.readUnsignedShort(); final ByteBuf value = buffer.readSlice(length); map.put(type, value); } return map; } public int getType() { return this.type; } @Override public void parseAttribute(final ByteBuf buffer, final AttributesBuilder builder, final RevisedErrorHandling errorHandling, final PeerSpecificParserConstraint constraint) throws BGPParsingException { // FIXME: BGPCEP-359: we need an updated link-state spec for RFC7606 final CLinkstateDestination lsDestination = getNlriType(builder); if (lsDestination == null) { LOG.warn("No Linkstate NLRI found, not parsing Linkstate attribute"); return; } final ObjectType nlriType = lsDestination.getObjectType(); final ProtocolId protocolId = lsDestination.getProtocolId(); builder.addAugmentation(new Attributes1Builder() .setLinkStateAttribute(parseLinkState(nlriType, protocolId, buffer)) .build()); } private static CLinkstateDestination getNlriType(final AttributesBuilder pab) { final AttributesReach mpr = pab.augmentation(AttributesReach.class); if (mpr != null && mpr.getMpReachNlri() != null) { final DestinationType dt = mpr.getMpReachNlri().getAdvertizedRoutes().getDestinationType(); if (dt instanceof DestinationLinkstateCase) { for (final CLinkstateDestination d : ((DestinationLinkstateCase) dt).getDestinationLinkstate() .getCLinkstateDestination()) { return d; } } } final AttributesUnreach mpu = pab.augmentation(AttributesUnreach.class); if (mpu != null && mpu.getMpUnreachNlri() != null) { final DestinationType dt = mpu.getMpUnreachNlri().getWithdrawnRoutes().getDestinationType(); if (dt instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120 .update.attributes.mp.unreach.nlri.withdrawn.routes.destination.type.DestinationLinkstateCase) { for (final CLinkstateDestination d : ((org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang .bgp.linkstate.rev200120.update.attributes.mp.unreach.nlri.withdrawn.routes.destination.type .DestinationLinkstateCase) dt).getDestinationLinkstate().getCLinkstateDestination()) { return d; } } } return null; } private LinkStateAttribute parseLinkState(final ObjectType nlri, final ProtocolId protocolId, final ByteBuf buffer) throws BGPParsingException { if (nlri instanceof PrefixCase) { return PrefixAttributesParser.parsePrefixAttributes(getAttributesMap(buffer), protocolId); } else if (nlri instanceof LinkCase) { return LinkAttributesParser.parseLinkAttributes(getAttributesMap(buffer), protocolId); } else if (nlri instanceof NodeCase) { return NodeAttributesParser.parseNodeAttributes(getAttributesMap(buffer), protocolId); } else if (nlri instanceof TeLspCase) { return TeLspAttributesParser.parseTeLspAttributes(this.rsvpTeObjectRegistry, getAttributesMap(buffer) .entries().iterator().next().getValue()); } else { throw new IllegalStateException("Unhandled NLRI type " + nlri); } } /** * Serialize linkstate attributes. * * @param attribute DataObject representing LinkstatePathAttribute * @param byteAggregator ByteBuf where all serialized data are aggregated */ @Override public void serializeAttribute(final Attributes attribute, final ByteBuf byteAggregator) { final Attributes1 pathAttributes1 = attribute.augmentation(Attributes1.class); if (pathAttributes1 == null) { return; } final LinkStateAttribute linkState = pathAttributes1.getLinkStateAttribute(); final ByteBuf lsBuffer = Unpooled.buffer(); if (linkState instanceof LinkAttributesCase) { LinkAttributesParser.serializeLinkAttributes((LinkAttributesCase) linkState, lsBuffer); } else if (linkState instanceof NodeAttributesCase) { NodeAttributesParser.serializeNodeAttributes((NodeAttributesCase) linkState, lsBuffer); } else if (linkState instanceof PrefixAttributesCase) { PrefixAttributesParser.serializePrefixAttributes((PrefixAttributesCase) linkState, lsBuffer); } else if (linkState instanceof TeLspAttributesCase) { TeLspAttributesParser.serializeLspAttributes(this.rsvpTeObjectRegistry, (TeLspAttributesCase) linkState, lsBuffer); byteAggregator.writeBytes(lsBuffer); return; } AttributeUtil.formatAttribute(AttributeUtil.OPTIONAL, getType(), lsBuffer, byteAggregator); } }