BUG-45 : migrated Origin path attribute to generated source code.
[bgpcep.git] / bgp / parser-impl / src / main / java / org / opendaylight / protocol / bgp / parser / impl / BGPUpdateEventBuilder.java
1 /*
2  * Copyright (c) 2013 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.parser.impl;
9
10 import java.util.Collection;
11 import java.util.HashSet;
12 import java.util.List;
13 import java.util.Map;
14 import java.util.Map.Entry;
15 import java.util.Set;
16
17 import javax.annotation.concurrent.NotThreadSafe;
18
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;
52
53 import com.google.common.collect.Maps;
54 import com.google.common.collect.Sets;
55
56 /**
57  * 
58  * Builds BGPUpdateEvent. This code was originally in {@link BGPUpdateMessageParser}. Moved here during refactoring.
59  * 
60  * Withdrawn routes or nlri that contain directly prefixes, can contain only IPv4 Prefixes.
61  */
62 @NotThreadSafe
63 public class BGPUpdateEventBuilder {
64
65         private static final Logger log = LoggerFactory.getLogger(BGPUpdateEventBuilder.class);
66
67         /**
68          * 
69          * Length of the withdrawn_routes field, in bytes.
70          */
71
72         private int withdrawnRoutesLength;
73
74         /**
75          * 
76          * List of IP address prefixes for the routes that are being withdrawn. Can be empty when there are no routes to
77          * 
78          * withdraw.
79          */
80
81         private Set<Prefix<IPv4Address>> withdrawnRoutes;
82
83         /**
84          * 
85          * Length of the total_path_attributes field, in bytes.
86          */
87
88         private int totalPathAttrLength;
89
90         /**
91          * 
92          * List of path attributes. Can be empty when there are only withdrawn routes present.
93          */
94
95         private List<PathAttribute> pathAttributes;
96
97         /**
98          * 
99          * List of IP address prefixes of routes that are advertised.
100          */
101
102         private Set<Prefix<IPv4Address>> nlri;
103
104         /**
105          * 
106          * Fills in BGP Objects that need to be added to topology. The method first checks and sets Path Attributes. If the
107          * 
108          * NLRI field is not empty, create for each of the prefixes present in NLRI, a BGPRoute with the attributes and
109          * 
110          * corresponding Prefix. If MP_REACH_NLRI attribute is found, check its NLRI, if its not of type Link State, do the
111          * 
112          * same.
113          * 
114          * 
115          * 
116          * @param pathAttributes
117          * 
118          * @param nlri
119          * 
120          * 
121          * 
122          * @return set of BGP Objects that need to be added
123          * 
124          * @throws BGPParsingException
125          */
126
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);
151                                         }
152                                 }
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);
158                                         }
159                                 }
160                         }
161                 }
162
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));
170                         }
171                 }
172
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));
181                                 }
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));
188                                 }
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);
195                                         n.setASPath(aspath);
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);
200                                         added.add(bgpNode);
201                                 }
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);
208                                         l.setASPath(aspath);
209                                         l.setExtendedCommunities(ecomm);
210                                         l.setCommunities(comm);
211                                         log.debug("Adding bgp link {}", l);
212                                         added.add(new BGPLinkImpl(base, desc, l.currentState()));
213                                 }
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,
219                                                 linkstate);
220                                 for (final IPv4PrefixIdentifier desc : prefixes) {
221                                         log.debug("Adding IPv4 Prefix {} State {}", desc, nps);
222                                         added.add(new BGPIPv4PrefixImpl(base, desc, nps));
223                                 }
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.");
228
229                                 final NetworkPrefixState nps = LinkStateParser.parsePrefixAttributes(((BGPIPv6PrefixMP) mpreach).getSourceProtocol(), nos,
230                                                 linkstate);
231                                 for (final IPv6PrefixIdentifier desc : prefixes) {
232                                         log.debug("Adding IPv6 Prefix {} State {}", desc, nps);
233                                         added.add(new BGPIPv6PrefixImpl(base, desc, nps));
234                                 }
235                         }
236                 }
237                 return added;
238
239         }
240
241         /**
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.
245          * 
246          * @param pathAttributes
247          * @param withdrawnRoutes
248          * 
249          * @return set of identifiers that need to be removed
250          */
251
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);
256                 }
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());
263                                 }
264                         } else if (mpunreach instanceof IPv6MP) {
265                                 final IPv6MP ipv6mp = (IPv6MP) mpunreach;
266                                 if (!ipv6mp.getNlri().isEmpty()) {
267                                         removed.addAll(ipv6mp.getNlri());
268                                 }
269                         } else if (mpunreach instanceof BGPNodeMP) {
270                                 for (final NodeIdentifier node : ((BGPNodeMP) mpunreach).getNlri()) {
271                                         removed.add(node);
272                                 }
273                         } else if (mpunreach instanceof BGPLinkMP) {
274                                 for (final LinkIdentifier link : ((BGPLinkMP) mpunreach).getNlri()) {
275                                         removed.add(link);
276                                 }
277                         } else if (mpunreach instanceof BGPIPv4PrefixMP) {
278                                 for (final IPv4PrefixIdentifier pref : ((BGPIPv4PrefixMP) mpunreach).getNlri()) {
279                                         removed.add(pref);
280                                 }
281                         } else if (mpunreach instanceof BGPIPv6PrefixMP) {
282                                 for (final IPv6PrefixIdentifier pref : ((BGPIPv6PrefixMP) mpunreach).getNlri()) {
283                                         removed.add(pref);
284                                 }
285                         }
286                 }
287                 return removed;
288
289         }
290
291         /**
292          * Finds MPReach object in Path Attribute list (depending on reachability boolean) and returns typecasted object.
293          * 
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
296          * 
297          * @return cated MPReach object
298          */
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)
305                                         return t;
306                         }
307                 }
308                 return null;
309         }
310
311         int getWithdrawnRoutesLength() {
312                 return this.withdrawnRoutesLength;
313         }
314
315         public void setWithdrawnRoutesLength(final int withdrawnRoutesLength) {
316                 this.withdrawnRoutesLength = withdrawnRoutesLength;
317         }
318
319         Set<Prefix<IPv4Address>> getWithdrawnRoutes() {
320                 return this.withdrawnRoutes;
321         }
322
323         public void setWithdrawnRoutes(final Set<Prefix<IPv4Address>> withdrawnRoutes) {
324                 this.withdrawnRoutes = withdrawnRoutes;
325         }
326
327         int getTotalPathAttrLength() {
328                 return this.totalPathAttrLength;
329         }
330
331         public void setTotalPathAttrLength(final int totalPathAttrLength) {
332                 this.totalPathAttrLength = totalPathAttrLength;
333         }
334
335         List<PathAttribute> getPathAttributes() {
336                 return this.pathAttributes;
337         }
338
339         public void setPathAttributes(final List<PathAttribute> pathAttributes) {
340                 this.pathAttributes = pathAttributes;
341         }
342
343         Set<Prefix<IPv4Address>> getNlri() {
344                 return this.nlri;
345         }
346
347         public void setNlri(final Set<Prefix<IPv4Address>> nlri) {
348                 this.nlri = nlri;
349         }
350
351         /**
352          * Builds BGP Update message.
353          * 
354          * @return BGP Update message
355          * @throws BGPParsingException
356          */
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);
361         }
362 }