2 * Copyright (c) 2013 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.parser.impl;
10 import java.util.Collection;
11 import java.util.HashSet;
12 import java.util.List;
14 import java.util.Map.Entry;
17 import javax.annotation.concurrent.NotThreadSafe;
19 import org.opendaylight.protocol.bgp.concepts.ASPath;
20 import org.opendaylight.protocol.bgp.concepts.BGPAggregator;
21 import org.opendaylight.protocol.bgp.concepts.BGPObject;
22 import org.opendaylight.protocol.bgp.concepts.BaseBGPObjectState;
23 import org.opendaylight.protocol.bgp.concepts.Community;
24 import org.opendaylight.protocol.bgp.concepts.ExtendedCommunity;
25 import org.opendaylight.protocol.bgp.concepts.IPv4NextHop;
26 import org.opendaylight.protocol.bgp.concepts.IPv6NextHop;
27 import org.opendaylight.protocol.bgp.linkstate.IPv4PrefixIdentifier;
28 import org.opendaylight.protocol.bgp.linkstate.IPv6PrefixIdentifier;
29 import org.opendaylight.protocol.bgp.linkstate.LinkIdentifier;
30 import org.opendaylight.protocol.bgp.linkstate.NetworkLinkImpl;
31 import org.opendaylight.protocol.bgp.linkstate.NetworkNodeImpl;
32 import org.opendaylight.protocol.bgp.linkstate.NetworkObjectState;
33 import org.opendaylight.protocol.bgp.linkstate.NetworkPrefixState;
34 import org.opendaylight.protocol.bgp.linkstate.NetworkRouteState;
35 import org.opendaylight.protocol.bgp.linkstate.NodeIdentifier;
36 import org.opendaylight.protocol.bgp.parser.BGPParsingException;
37 import org.opendaylight.protocol.bgp.parser.BGPUpdateEvent;
38 import org.opendaylight.protocol.bgp.parser.impl.message.BGPUpdateMessageParser;
39 import org.opendaylight.protocol.bgp.parser.impl.message.update.LinkStateParser;
40 import org.opendaylight.protocol.bgp.util.BGPIPv4PrefixImpl;
41 import org.opendaylight.protocol.bgp.util.BGPIPv4RouteImpl;
42 import org.opendaylight.protocol.bgp.util.BGPIPv6PrefixImpl;
43 import org.opendaylight.protocol.bgp.util.BGPIPv6RouteImpl;
44 import org.opendaylight.protocol.bgp.util.BGPLinkImpl;
45 import org.opendaylight.protocol.bgp.util.BGPNodeImpl;
46 import org.opendaylight.protocol.concepts.IPv4Address;
47 import org.opendaylight.protocol.concepts.IPv6Address;
48 import org.opendaylight.protocol.concepts.Prefix;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.BgpOrigin;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
53 import com.google.common.collect.Maps;
54 import com.google.common.collect.Sets;
58 * Builds BGPUpdateEvent. This code was originally in {@link BGPUpdateMessageParser}. Moved here during refactoring.
60 * Withdrawn routes or nlri that contain directly prefixes, can contain only IPv4 Prefixes.
63 public class BGPUpdateEventBuilder {
65 private static final Logger log = LoggerFactory.getLogger(BGPUpdateEventBuilder.class);
69 * Length of the withdrawn_routes field, in bytes.
72 private int withdrawnRoutesLength;
76 * List of IP address prefixes for the routes that are being withdrawn. Can be empty when there are no routes to
81 private Set<Prefix<IPv4Address>> withdrawnRoutes;
85 * Length of the total_path_attributes field, in bytes.
88 private int totalPathAttrLength;
92 * List of path attributes. Can be empty when there are only withdrawn routes present.
95 private List<PathAttribute> pathAttributes;
99 * List of IP address prefixes of routes that are advertised.
102 private Set<Prefix<IPv4Address>> nlri;
106 * Fills in BGP Objects that need to be added to topology. The method first checks and sets Path Attributes. If the
108 * NLRI field is not empty, create for each of the prefixes present in NLRI, a BGPRoute with the attributes and
110 * corresponding Prefix. If MP_REACH_NLRI attribute is found, check its NLRI, if its not of type Link State, do the
116 * @param pathAttributes
122 * @return set of BGP Objects that need to be added
124 * @throws BGPParsingException
127 private Set<BGPObject> fillAddedObjects(final List<PathAttribute> pathAttributes, final Set<Prefix<IPv4Address>> nlri)
128 throws BGPParsingException {
129 BgpOrigin origin = null;
130 ASPath aspath = null;
131 IPv4NextHop nextHop = null;
132 BGPAggregator aggregator = null;
133 final Set<ExtendedCommunity> ecomm = Sets.newHashSet();
134 final Set<Community> comm = Sets.newHashSet();
135 final Map<Integer, ByteList> linkstate = Maps.newHashMap();
136 for (final PathAttribute pa : pathAttributes) {
137 if (pa.getValue() instanceof BgpOrigin) {
138 origin = (BgpOrigin) pa.getValue();
139 } else if (pa.getValue() instanceof ASPath) {
140 aspath = (ASPath) pa.getValue();
141 } else if (pa.getValue() instanceof IPv4NextHop) {
142 nextHop = (IPv4NextHop) pa.getValue();
143 } else if (pa.getValue() instanceof BGPAggregator) {
144 aggregator = (BGPAggregator) pa.getValue();
145 } else if (pa.getValue() instanceof Set) {
146 for (final Object o : (Set<?>) pa.getValue()) {
147 if (o instanceof ExtendedCommunity) {
148 ecomm.add((ExtendedCommunity) o);
149 } else if (o instanceof Community) {
150 comm.add((Community) o);
153 } else if (pa.getValue() instanceof Map) {
154 for (final Entry<?, ?> entry : ((Map<?, ?>) pa.getValue()).entrySet()) {
155 if (entry.getValue() instanceof ByteList) {
156 final ByteList lb = (ByteList) entry.getValue();
157 linkstate.put((Integer) entry.getKey(), lb);
163 final BaseBGPObjectState base = new BaseBGPObjectState(origin, aggregator);
164 final NetworkObjectState nos = new NetworkObjectState(aspath, comm, ecomm);
165 final Set<BGPObject> added = new HashSet<BGPObject>();
166 if (!nlri.isEmpty()) {
167 final NetworkRouteState<IPv4Address> nrs = new NetworkRouteState<>(nos, nextHop);
168 for (final Prefix<IPv4Address> p : nlri) {
169 added.add(new BGPIPv4RouteImpl(p, base, nrs));
173 final MPReach<?> mpreach = findMP(pathAttributes, true);
174 if (mpreach != null) {
175 if (mpreach instanceof IPv4MP) {
176 final IPv4MP ipv4mp = (IPv4MP) mpreach;
177 final IPv4NextHop v4nextHop = ipv4mp.getNextHop();
178 final NetworkRouteState<IPv4Address> nrs = new NetworkRouteState<>(nos, v4nextHop);
179 for (final Prefix<IPv4Address> p : ipv4mp.getNlri()) {
180 added.add(new BGPIPv4RouteImpl(p, base, nrs));
182 } else if (mpreach instanceof IPv6MP) {
183 final IPv6MP ipv6mp = (IPv6MP) mpreach;
184 final IPv6NextHop v6nextHop = ipv6mp.getNextHop();
185 final NetworkRouteState<IPv6Address> nrs = new NetworkRouteState<>(nos, v6nextHop);
186 for (final Prefix<IPv6Address> p : ipv6mp.getNlri()) {
187 added.add(new BGPIPv6RouteImpl(p, base, nrs));
189 } else if (mpreach instanceof BGPNodeMP) {
190 final Set<NodeIdentifier> nodes = ((BGPNodeMP) mpreach).getNlri();
191 if (!LinkStateParser.verifyNode(linkstate.keySet()))
192 throw new BGPParsingException("Some attributes from LINK_STATE Path attribute don't belong to advertised node.");
193 for (final NodeIdentifier desc : nodes) {
194 final NetworkNodeImpl n = LinkStateParser.parseNodeAttributes(desc, linkstate);
196 n.setExtendedCommunities(ecomm);
197 n.setCommunities(comm);
198 final BGPNodeImpl bgpNode = new BGPNodeImpl(base, desc, n.currentState());
199 log.debug("Adding bgp node {}", bgpNode);
202 } else if (mpreach instanceof BGPLinkMP) {
203 final Set<LinkIdentifier> links = ((BGPLinkMP) mpreach).getNlri();
204 if (!LinkStateParser.verifyLink(linkstate.keySet()))
205 throw new BGPParsingException("Some attributes from LINK_STATE Path attribute don't belong to advertised link.");
206 for (final LinkIdentifier desc : links) {
207 final NetworkLinkImpl l = LinkStateParser.parseLinkAttributes(desc, linkstate);
209 l.setExtendedCommunities(ecomm);
210 l.setCommunities(comm);
211 log.debug("Adding bgp link {}", l);
212 added.add(new BGPLinkImpl(base, desc, l.currentState()));
214 } else if (mpreach instanceof BGPIPv4PrefixMP) {
215 final Set<IPv4PrefixIdentifier> prefixes = ((BGPIPv4PrefixMP) mpreach).getNlri();
216 if (!LinkStateParser.verifyPrefix(linkstate.keySet()))
217 throw new BGPParsingException("Some attributes from LINK_STATE Path attribute don't belong to advertised prefix.");
218 final NetworkPrefixState nps = LinkStateParser.parsePrefixAttributes(((BGPIPv4PrefixMP) mpreach).getSourceProtocol(), nos,
220 for (final IPv4PrefixIdentifier desc : prefixes) {
221 log.debug("Adding IPv4 Prefix {} State {}", desc, nps);
222 added.add(new BGPIPv4PrefixImpl(base, desc, nps));
224 } else if (mpreach instanceof BGPIPv6PrefixMP) {
225 final Set<IPv6PrefixIdentifier> prefixes = ((BGPIPv6PrefixMP) mpreach).getNlri();
226 if (!LinkStateParser.verifyPrefix(linkstate.keySet()))
227 throw new BGPParsingException("Some attributes from LINK_STATE Path attribute don't belong to advertised prefix.");
229 final NetworkPrefixState nps = LinkStateParser.parsePrefixAttributes(((BGPIPv6PrefixMP) mpreach).getSourceProtocol(), nos,
231 for (final IPv6PrefixIdentifier desc : prefixes) {
232 log.debug("Adding IPv6 Prefix {} State {}", desc, nps);
233 added.add(new BGPIPv6PrefixImpl(base, desc, nps));
242 * Fills in Identifiers that need to be removed. First, check field withdrawn routes, that can contain only IPv4
243 * prefixes. Then, check the presence of MP_UNREACH_NLRI and if its NLRI contains Prefixes, add them to removed
244 * field. For link state information, Node & LinkIdentifiers are added to the Set.
246 * @param pathAttributes
247 * @param withdrawnRoutes
249 * @return set of identifiers that need to be removed
252 private Set<?> fillRemovedObjects(final List<PathAttribute> pathAttributes, final Set<Prefix<IPv4Address>> withdrawnRoutes) {
253 final Set<Object> removed = Sets.newHashSet();
254 if (!withdrawnRoutes.isEmpty()) {
255 removed.addAll(withdrawnRoutes);
257 final MPReach<?> mpunreach = findMP(pathAttributes, false);
258 if (mpunreach != null) {
259 if (mpunreach instanceof IPv4MP) {
260 final IPv4MP ipv4mp = (IPv4MP) mpunreach;
261 if (!ipv4mp.getNlri().isEmpty()) {
262 removed.addAll(ipv4mp.getNlri());
264 } else if (mpunreach instanceof IPv6MP) {
265 final IPv6MP ipv6mp = (IPv6MP) mpunreach;
266 if (!ipv6mp.getNlri().isEmpty()) {
267 removed.addAll(ipv6mp.getNlri());
269 } else if (mpunreach instanceof BGPNodeMP) {
270 for (final NodeIdentifier node : ((BGPNodeMP) mpunreach).getNlri()) {
273 } else if (mpunreach instanceof BGPLinkMP) {
274 for (final LinkIdentifier link : ((BGPLinkMP) mpunreach).getNlri()) {
277 } else if (mpunreach instanceof BGPIPv4PrefixMP) {
278 for (final IPv4PrefixIdentifier pref : ((BGPIPv4PrefixMP) mpunreach).getNlri()) {
281 } else if (mpunreach instanceof BGPIPv6PrefixMP) {
282 for (final IPv6PrefixIdentifier pref : ((BGPIPv6PrefixMP) mpunreach).getNlri()) {
292 * Finds MPReach object in Path Attribute list (depending on reachability boolean) and returns typecasted object.
294 * @param arrayList list of path attributes
295 * @param reachable true if we search for MP_REACH_NLRI, false if we search for MP_UNREACH_NLRI
297 * @return cated MPReach object
299 private static <T> MPReach<?> findMP(final Collection<PathAttribute> arrayList, final boolean reachable) {
300 for (final PathAttribute o : arrayList) {
301 final Object v = o.getValue();
302 if (v != null && v instanceof MPReach<?>) {
303 final MPReach<?> t = (MPReach<?>) v;
304 if (t.isReachable() == reachable)
311 int getWithdrawnRoutesLength() {
312 return this.withdrawnRoutesLength;
315 public void setWithdrawnRoutesLength(final int withdrawnRoutesLength) {
316 this.withdrawnRoutesLength = withdrawnRoutesLength;
319 Set<Prefix<IPv4Address>> getWithdrawnRoutes() {
320 return this.withdrawnRoutes;
323 public void setWithdrawnRoutes(final Set<Prefix<IPv4Address>> withdrawnRoutes) {
324 this.withdrawnRoutes = withdrawnRoutes;
327 int getTotalPathAttrLength() {
328 return this.totalPathAttrLength;
331 public void setTotalPathAttrLength(final int totalPathAttrLength) {
332 this.totalPathAttrLength = totalPathAttrLength;
335 List<PathAttribute> getPathAttributes() {
336 return this.pathAttributes;
339 public void setPathAttributes(final List<PathAttribute> pathAttributes) {
340 this.pathAttributes = pathAttributes;
343 Set<Prefix<IPv4Address>> getNlri() {
347 public void setNlri(final Set<Prefix<IPv4Address>> nlri) {
352 * Builds BGP Update message.
354 * @return BGP Update message
355 * @throws BGPParsingException
357 public BGPUpdateEvent buildEvent() throws BGPParsingException {
358 final Set<BGPObject> added = fillAddedObjects(this.pathAttributes, this.nlri);
359 final Set<?> removed = fillRemovedObjects(this.pathAttributes, this.withdrawnRoutes);
360 return new BGPUpdateMessageImpl(added, removed);