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.BGPObject;
20 import org.opendaylight.protocol.bgp.concepts.BaseBGPObjectState;
21 import org.opendaylight.protocol.bgp.linkstate.IPv4PrefixIdentifier;
22 import org.opendaylight.protocol.bgp.linkstate.IPv6PrefixIdentifier;
23 import org.opendaylight.protocol.bgp.linkstate.LinkIdentifier;
24 import org.opendaylight.protocol.bgp.linkstate.NetworkLinkImpl;
25 import org.opendaylight.protocol.bgp.linkstate.NetworkNodeImpl;
26 import org.opendaylight.protocol.bgp.linkstate.NetworkObjectState;
27 import org.opendaylight.protocol.bgp.linkstate.NetworkPrefixState;
28 import org.opendaylight.protocol.bgp.linkstate.NetworkRouteState;
29 import org.opendaylight.protocol.bgp.linkstate.NodeIdentifier;
30 import org.opendaylight.protocol.bgp.parser.BGPParsingException;
31 import org.opendaylight.protocol.bgp.parser.BGPUpdateEvent;
32 import org.opendaylight.protocol.bgp.parser.impl.message.BGPUpdateMessageParser;
33 import org.opendaylight.protocol.bgp.parser.impl.message.update.LinkStateParser;
34 import org.opendaylight.protocol.bgp.util.BGPIPv4PrefixImpl;
35 import org.opendaylight.protocol.bgp.util.BGPIPv4RouteImpl;
36 import org.opendaylight.protocol.bgp.util.BGPIPv6PrefixImpl;
37 import org.opendaylight.protocol.bgp.util.BGPIPv6RouteImpl;
38 import org.opendaylight.protocol.bgp.util.BGPLinkImpl;
39 import org.opendaylight.protocol.bgp.util.BGPNodeImpl;
40 import org.opendaylight.protocol.concepts.IPv4Address;
41 import org.opendaylight.protocol.concepts.IPv6Address;
42 import org.opendaylight.protocol.concepts.Prefix;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.AsPathSegment;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.BgpAggregator;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.BgpOrigin;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.Community;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.extended.community.ExtendedCommunity;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.next.hop.c.next.hop.CIpv4NextHop;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.next.hop.c.next.hop.CIpv6NextHop;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
53 import com.google.common.collect.Lists;
54 import com.google.common.collect.Maps;
55 import com.google.common.collect.Sets;
59 * Builds BGPUpdateEvent. This code was originally in {@link BGPUpdateMessageParser}. Moved here during refactoring.
61 * Withdrawn routes or nlri that contain directly prefixes, can contain only IPv4 Prefixes.
64 public class BGPUpdateEventBuilder {
66 private static final Logger log = LoggerFactory.getLogger(BGPUpdateEventBuilder.class);
70 * Length of the withdrawn_routes field, in bytes.
73 private int withdrawnRoutesLength;
77 * List of IP address prefixes for the routes that are being withdrawn. Can be empty when there are no routes to
82 private Set<Prefix<IPv4Address>> withdrawnRoutes;
86 * Length of the total_path_attributes field, in bytes.
89 private int totalPathAttrLength;
93 * List of path attributes. Can be empty when there are only withdrawn routes present.
96 private List<PathAttribute> pathAttributes;
100 * List of IP address prefixes of routes that are advertised.
103 private Set<Prefix<IPv4Address>> nlri;
107 * Fills in BGP Objects that need to be added to topology. The method first checks and sets Path Attributes. If the
109 * NLRI field is not empty, create for each of the prefixes present in NLRI, a BGPRoute with the attributes and
111 * corresponding Prefix. If MP_REACH_NLRI attribute is found, check its NLRI, if its not of type Link State, do the
117 * @param pathAttributes
123 * @return set of BGP Objects that need to be added
125 * @throws BGPParsingException
128 private Set<BGPObject> fillAddedObjects(final List<PathAttribute> pathAttributes, final Set<Prefix<IPv4Address>> nlri)
129 throws BGPParsingException {
130 BgpOrigin origin = null;
131 final List<AsPathSegment> aspath = Lists.newArrayList();
132 CIpv4NextHop nextHop = null;
133 BgpAggregator aggregator = null;
134 final Set<ExtendedCommunity> ecomm = Sets.newHashSet();
135 final Set<Community> comm = Sets.newHashSet();
136 final Map<Integer, ByteList> linkstate = Maps.newHashMap();
137 for (final PathAttribute pa : pathAttributes) {
138 if (pa.getValue() instanceof BgpOrigin) {
139 origin = (BgpOrigin) pa.getValue();
140 } else if (pa.getValue() instanceof List) {
141 for (final Object o : (List<?>) pa.getValue()) {
142 if (o instanceof AsPathSegment) {
143 aspath.add((AsPathSegment) o);
146 } else if (pa.getValue() instanceof CIpv4NextHop) {
147 nextHop = (CIpv4NextHop) pa.getValue();
148 } else if (pa.getValue() instanceof BgpAggregator) {
149 aggregator = (BgpAggregator) pa.getValue();
150 } else if (pa.getValue() instanceof Set) {
151 for (final Object o : (Set<?>) pa.getValue()) {
152 if (o instanceof ExtendedCommunity) {
153 ecomm.add((ExtendedCommunity) o);
154 } else if (o instanceof Community) {
155 comm.add((Community) o);
158 } else if (pa.getValue() instanceof Map) {
159 for (final Entry<?, ?> entry : ((Map<?, ?>) pa.getValue()).entrySet()) {
160 if (entry.getValue() instanceof ByteList) {
161 final ByteList lb = (ByteList) entry.getValue();
162 linkstate.put((Integer) entry.getKey(), lb);
168 final BaseBGPObjectState base = new BaseBGPObjectState(origin, aggregator);
169 final NetworkObjectState nos = new NetworkObjectState(aspath, comm, ecomm);
170 final Set<BGPObject> added = new HashSet<BGPObject>();
171 if (!nlri.isEmpty()) {
172 final NetworkRouteState nrs = new NetworkRouteState(nos, nextHop);
173 for (final Prefix<IPv4Address> p : nlri) {
174 added.add(new BGPIPv4RouteImpl(p, base, nrs));
178 final MPReach<?> mpreach = findMP(pathAttributes, true);
179 if (mpreach != null) {
180 if (mpreach instanceof IPv4MP) {
181 final IPv4MP ipv4mp = (IPv4MP) mpreach;
182 final CIpv4NextHop v4nextHop = ipv4mp.getNextHop();
183 final NetworkRouteState nrs = new NetworkRouteState(nos, v4nextHop);
184 for (final Prefix<IPv4Address> p : ipv4mp.getNlri()) {
185 added.add(new BGPIPv4RouteImpl(p, base, nrs));
187 } else if (mpreach instanceof IPv6MP) {
188 final IPv6MP ipv6mp = (IPv6MP) mpreach;
189 final CIpv6NextHop v6nextHop = ipv6mp.getNextHop();
190 final NetworkRouteState nrs = new NetworkRouteState(nos, v6nextHop);
191 for (final Prefix<IPv6Address> p : ipv6mp.getNlri()) {
192 added.add(new BGPIPv6RouteImpl(p, base, nrs));
194 } else if (mpreach instanceof BGPNodeMP) {
195 final Set<NodeIdentifier> nodes = ((BGPNodeMP) mpreach).getNlri();
196 if (!LinkStateParser.verifyNode(linkstate.keySet()))
197 throw new BGPParsingException("Some attributes from LINK_STATE Path attribute don't belong to advertised node.");
198 for (final NodeIdentifier desc : nodes) {
199 final NetworkNodeImpl n = LinkStateParser.parseNodeAttributes(desc, linkstate);
201 n.setExtendedCommunities(ecomm);
202 n.setCommunities(comm);
203 final BGPNodeImpl bgpNode = new BGPNodeImpl(base, desc, n.currentState());
204 log.debug("Adding bgp node {}", bgpNode);
207 } else if (mpreach instanceof BGPLinkMP) {
208 final Set<LinkIdentifier> links = ((BGPLinkMP) mpreach).getNlri();
209 if (!LinkStateParser.verifyLink(linkstate.keySet()))
210 throw new BGPParsingException("Some attributes from LINK_STATE Path attribute don't belong to advertised link.");
211 for (final LinkIdentifier desc : links) {
212 final NetworkLinkImpl l = LinkStateParser.parseLinkAttributes(desc, linkstate);
214 l.setExtendedCommunities(ecomm);
215 l.setCommunities(comm);
216 log.debug("Adding bgp link {}", l);
217 added.add(new BGPLinkImpl(base, desc, l.currentState()));
219 } else if (mpreach instanceof BGPIPv4PrefixMP) {
220 final Set<IPv4PrefixIdentifier> prefixes = ((BGPIPv4PrefixMP) mpreach).getNlri();
221 if (!LinkStateParser.verifyPrefix(linkstate.keySet()))
222 throw new BGPParsingException("Some attributes from LINK_STATE Path attribute don't belong to advertised prefix.");
223 final NetworkPrefixState nps = LinkStateParser.parsePrefixAttributes(((BGPIPv4PrefixMP) mpreach).getSourceProtocol(), nos,
225 for (final IPv4PrefixIdentifier desc : prefixes) {
226 log.debug("Adding IPv4 Prefix {} State {}", desc, nps);
227 added.add(new BGPIPv4PrefixImpl(base, desc, nps));
229 } else if (mpreach instanceof BGPIPv6PrefixMP) {
230 final Set<IPv6PrefixIdentifier> prefixes = ((BGPIPv6PrefixMP) mpreach).getNlri();
231 if (!LinkStateParser.verifyPrefix(linkstate.keySet()))
232 throw new BGPParsingException("Some attributes from LINK_STATE Path attribute don't belong to advertised prefix.");
234 final NetworkPrefixState nps = LinkStateParser.parsePrefixAttributes(((BGPIPv6PrefixMP) mpreach).getSourceProtocol(), nos,
236 for (final IPv6PrefixIdentifier desc : prefixes) {
237 log.debug("Adding IPv6 Prefix {} State {}", desc, nps);
238 added.add(new BGPIPv6PrefixImpl(base, desc, nps));
247 * Fills in Identifiers that need to be removed. First, check field withdrawn routes, that can contain only IPv4
248 * prefixes. Then, check the presence of MP_UNREACH_NLRI and if its NLRI contains Prefixes, add them to removed
249 * field. For link state information, Node & LinkIdentifiers are added to the Set.
251 * @param pathAttributes
252 * @param withdrawnRoutes
254 * @return set of identifiers that need to be removed
257 private Set<?> fillRemovedObjects(final List<PathAttribute> pathAttributes, final Set<Prefix<IPv4Address>> withdrawnRoutes) {
258 final Set<Object> removed = Sets.newHashSet();
259 if (!withdrawnRoutes.isEmpty()) {
260 removed.addAll(withdrawnRoutes);
262 final MPReach<?> mpunreach = findMP(pathAttributes, false);
263 if (mpunreach != null) {
264 if (mpunreach instanceof IPv4MP) {
265 final IPv4MP ipv4mp = (IPv4MP) mpunreach;
266 if (!ipv4mp.getNlri().isEmpty()) {
267 removed.addAll(ipv4mp.getNlri());
269 } else if (mpunreach instanceof IPv6MP) {
270 final IPv6MP ipv6mp = (IPv6MP) mpunreach;
271 if (!ipv6mp.getNlri().isEmpty()) {
272 removed.addAll(ipv6mp.getNlri());
274 } else if (mpunreach instanceof BGPNodeMP) {
275 for (final NodeIdentifier node : ((BGPNodeMP) mpunreach).getNlri()) {
278 } else if (mpunreach instanceof BGPLinkMP) {
279 for (final LinkIdentifier link : ((BGPLinkMP) mpunreach).getNlri()) {
282 } else if (mpunreach instanceof BGPIPv4PrefixMP) {
283 for (final IPv4PrefixIdentifier pref : ((BGPIPv4PrefixMP) mpunreach).getNlri()) {
286 } else if (mpunreach instanceof BGPIPv6PrefixMP) {
287 for (final IPv6PrefixIdentifier pref : ((BGPIPv6PrefixMP) mpunreach).getNlri()) {
297 * Finds MPReach object in Path Attribute list (depending on reachability boolean) and returns typecasted object.
299 * @param arrayList list of path attributes
300 * @param reachable true if we search for MP_REACH_NLRI, false if we search for MP_UNREACH_NLRI
302 * @return cated MPReach object
304 private static <T> MPReach<?> findMP(final Collection<PathAttribute> arrayList, final boolean reachable) {
305 for (final PathAttribute o : arrayList) {
306 final Object v = o.getValue();
307 if (v != null && v instanceof MPReach<?>) {
308 final MPReach<?> t = (MPReach<?>) v;
309 if (t.isReachable() == reachable)
316 int getWithdrawnRoutesLength() {
317 return this.withdrawnRoutesLength;
320 public void setWithdrawnRoutesLength(final int withdrawnRoutesLength) {
321 this.withdrawnRoutesLength = withdrawnRoutesLength;
324 Set<Prefix<IPv4Address>> getWithdrawnRoutes() {
325 return this.withdrawnRoutes;
328 public void setWithdrawnRoutes(final Set<Prefix<IPv4Address>> withdrawnRoutes) {
329 this.withdrawnRoutes = withdrawnRoutes;
332 int getTotalPathAttrLength() {
333 return this.totalPathAttrLength;
336 public void setTotalPathAttrLength(final int totalPathAttrLength) {
337 this.totalPathAttrLength = totalPathAttrLength;
340 List<PathAttribute> getPathAttributes() {
341 return this.pathAttributes;
344 public void setPathAttributes(final List<PathAttribute> pathAttributes) {
345 this.pathAttributes = pathAttributes;
348 Set<Prefix<IPv4Address>> getNlri() {
352 public void setNlri(final Set<Prefix<IPv4Address>> nlri) {
357 * Builds BGP Update message.
359 * @return BGP Update message
360 * @throws BGPParsingException
362 public BGPUpdateEvent buildEvent() throws BGPParsingException {
363 final Set<BGPObject> added = fillAddedObjects(this.pathAttributes, this.nlri);
364 final Set<?> removed = fillRemovedObjects(this.pathAttributes, this.withdrawnRoutes);
365 return new BGPUpdateMessageImpl(added, removed);