Bug 8346 - Conflicting modification for vpnNextHops.
[netvirt.git] / vpnservice / vpnmanager / vpnmanager-impl / src / main / java / org / opendaylight / netvirt / vpnmanager / intervpnlink / InterVpnLinkUtil.java
1 /*
2  * Copyright (c) 2016, 2017 Ericsson India Global Services Pvt Ltd. 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.netvirt.vpnmanager.intervpnlink;
9
10 import com.google.common.base.Optional;
11 import com.google.common.base.Preconditions;
12 import com.google.common.util.concurrent.ListenableFuture;
13
14 import java.math.BigInteger;
15 import java.util.ArrayList;
16 import java.util.Collections;
17 import java.util.List;
18 import java.util.stream.Collectors;
19
20 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
21 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
22 import org.opendaylight.genius.mdsalutil.MDSALUtil;
23 import org.opendaylight.genius.mdsalutil.MatchInfo;
24 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
25 import org.opendaylight.genius.mdsalutil.NwConstants;
26 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
27 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
28 import org.opendaylight.genius.utils.ServiceIndex;
29 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
30 import org.opendaylight.netvirt.fibmanager.api.FibHelper;
31 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
32 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
33 import org.opendaylight.netvirt.vpnmanager.VpnConstants;
34 import org.opendaylight.netvirt.vpnmanager.VpnFootprintService;
35 import org.opendaylight.netvirt.vpnmanager.VpnUtil;
36 import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkCache;
37 import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkDataComposite;
38 import org.opendaylight.netvirt.vpnmanager.utilities.InterfaceUtils;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.InterVpnLinkStates;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.InterVpnLinks;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkState;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkStateBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkStateKey;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.inter.vpn.link.state.FirstEndpointState;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.inter.vpn.link.state.FirstEndpointStateBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.inter.vpn.link.state.SecondEndpointState;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.inter.vpn.link.state.SecondEndpointStateBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.links.InterVpnLink;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.links.InterVpnLinkKey;
58 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
59 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
61
62 /**
63  * This class contains methods to be used as utilities related with inter-vpn-link.
64  */
65 public class InterVpnLinkUtil {
66
67     private static final Logger LOG = LoggerFactory.getLogger(InterVpnLinkUtil.class);
68
69     /**
70      * Retrieves the Instance Identifier that points to an InterVpnLink object
71      * in MD-SAL.
72      *
73      * @param interVpnLinkName The name of the InterVpnLink
74      * @return The requested InstanceIdentifier
75      */
76     public static InstanceIdentifier<InterVpnLink> getInterVpnLinkPath(String interVpnLinkName) {
77         return InstanceIdentifier.builder(InterVpnLinks.class)
78             .child(InterVpnLink.class, new InterVpnLinkKey(interVpnLinkName))
79             .build();
80     }
81
82     /**
83      * Retrieves the Instance Identifier that points to an InterVpnLinkState object
84      * in MD-SAL.
85      *
86      * @param vpnLinkName The name of the InterVpnLink
87      * @return The requested InstanceIdentifier
88      */
89     public static InstanceIdentifier<InterVpnLinkState> getInterVpnLinkStateIid(String vpnLinkName) {
90         return InstanceIdentifier.builder(InterVpnLinkStates.class)
91             .child(InterVpnLinkState.class, new InterVpnLinkStateKey(vpnLinkName))
92             .build();
93     }
94
95     public static String buildInterVpnLinkIfaceName(String vpnName, BigInteger dpnId) {
96         return String.format("InterVpnLink.%s.%s", vpnName, dpnId.toString());
97     }
98
99     /**
100      * Updates VpnToDpn map by adding a fake VpnInterface related to an
101      * InterVpnLink in the corresponding DPNs. If the fake iface is the
102      * first one on the any of the specified DPNs, the installation of
103      * Fib flows on that DPN will be triggered.
104      *
105      * @param vpnFootprintService VpnFootprintService service reference
106      * @param vpnName Name of the VPN to which the fake interfaces belong
107      * @param dpnList List of DPNs where the fake InterVpnLink interface must be added
108      */
109     public static void updateVpnFootprint(VpnFootprintService vpnFootprintService, String vpnName,
110         String primaryRd, List<BigInteger> dpnList) {
111         LOG.debug("updateVpnFootprint (add):  vpn={}  dpnList={}", vpnName, dpnList);
112         // Note: when a set of DPNs is calculated for Vpn1, these DPNs are added to the VpnToDpn map of Vpn2. Why?
113         // because we do the handover from Vpn1 to Vpn2 in those DPNs, so in those DPNs we must know how to reach
114         // to Vpn2 targets. If new Vpn2 targets are added later, the Fib will be maintained in these DPNs even if
115         // Vpn2 is not physically present there.
116         for (BigInteger dpnId : dpnList) {
117             String ifaceName = buildInterVpnLinkIfaceName(vpnName, dpnId);
118             vpnFootprintService.updateVpnToDpnMapping(dpnId, vpnName, primaryRd, ifaceName,
119                     null/*ipAddressSourceValuePair*/, true /* addition */);
120         }
121     }
122
123     /**
124      * Updates VpnToDpn map by removing the fake VpnInterface related to an
125      * InterVpnLink in the corresponding DPNs.
126      *
127      * @param vpnFootprintService VpnFootprintService service reference
128      * @param vpnName Name of the VPN to which the fake interfaces belong
129      * @param dpnId DPN where the fake InterVpnLink interface must be removed from
130      */
131     public static void removeIVpnLinkIfaceFromVpnFootprint(VpnFootprintService vpnFootprintService,
132         String vpnName, String rd, BigInteger dpnId) {
133         String ifaceName = buildInterVpnLinkIfaceName(vpnName, dpnId);
134         LOG.debug("updateVpnFootprint (remove):  vpn={}  dpn={}  ifaceName={}", vpnName, dpnId, ifaceName);
135         vpnFootprintService.updateVpnToDpnMapping(dpnId, vpnName, rd, ifaceName,
136                 null/*ipAddressSourceValuePair*/, false /* removal */);
137     }
138
139
140     public static FirstEndpointState buildFirstEndpointState(FirstEndpointState original,
141                                                              Optional<List<BigInteger>> new1stEndpointDpns,
142                                                              Optional<Long> new1stEndpointLportTag) {
143         FirstEndpointStateBuilder builder = new FirstEndpointStateBuilder(original);
144         if (new1stEndpointDpns.isPresent()) {
145             builder.setDpId(new1stEndpointDpns.get());
146         }
147         if (new1stEndpointLportTag.isPresent()) {
148             builder.setLportTag(new1stEndpointLportTag.get());
149         }
150         return builder.build();
151     }
152
153     public static FirstEndpointState buildFirstEndpointState(String vpnName, List<BigInteger> dpnList, long lportTag) {
154         return new FirstEndpointStateBuilder().setVpnUuid(new Uuid(vpnName)).setDpId(dpnList).setLportTag(lportTag)
155                                               .build();
156     }
157
158     public static SecondEndpointState buildSecondEndpointState(SecondEndpointState original,
159                                                                Optional<List<BigInteger>> new2ndEndpointDpns,
160                                                                Optional<Long> new2ndEndpointLportTag) {
161         SecondEndpointStateBuilder builder = new SecondEndpointStateBuilder(original);
162         if (new2ndEndpointDpns.isPresent()) {
163             builder.setDpId(new2ndEndpointDpns.get());
164         }
165         if (new2ndEndpointLportTag.isPresent()) {
166             builder.setLportTag(new2ndEndpointLportTag.get());
167         }
168         return builder.build();
169     }
170
171     public static SecondEndpointState buildSecondEndpointState(String vpnName, List<BigInteger> dpnList,
172                                                                long lportTag) {
173         return new SecondEndpointStateBuilder().setVpnUuid(new Uuid(vpnName)).setDpId(dpnList).setLportTag(lportTag)
174                                               .build();
175     }
176
177     /**
178      * Creates an InterVpnLinkState out of an existing one and modifying only the desired attributes.
179      *
180      * @param original InterVpnLinkState to start from.
181      * @param new1stEndpointState Sets this FirstEndpointState if present
182      * @param new2ndEndpointState  Sets this SecondEndpointState if present
183      * @param errDescription  Sets this ErrorDescription if present
184      * @return the newly build InterVpnLinkState
185      */
186     public static InterVpnLinkState buildIvlStateFromOriginal(InterVpnLinkState original,
187                                                              Optional<FirstEndpointState> new1stEndpointState,
188                                                              Optional<SecondEndpointState> new2ndEndpointState,
189                                                              Optional<String> errDescription) {
190         InterVpnLinkStateBuilder ivlStateBuilder = new InterVpnLinkStateBuilder(original);
191         if (new1stEndpointState.isPresent()) {
192             ivlStateBuilder.setFirstEndpointState(new1stEndpointState.get());
193         }
194         if (new2ndEndpointState.isPresent()) {
195             ivlStateBuilder.setSecondEndpointState(new2ndEndpointState.get());
196         }
197         if (errDescription.isPresent()) {
198             ivlStateBuilder.setErrorDescription(errDescription.get());
199         }
200         return ivlStateBuilder.build();
201     }
202
203     /**
204      * Updates inter-VPN link state.
205      *
206      * @param broker dataBroker service reference
207      * @param vpnLinkName The name of the InterVpnLink
208      * @param state Sets the state of the InterVpnLink to Active or Error
209      * @param newFirstEndpointState Updates the lportTag and/or DPNs of the 1st endpoint of the InterVpnLink
210      * @param newSecondEndpointState Updates the lportTag and/or DPNs of the 2nd endpoint of the InterVpnLink
211      */
212     public static void updateInterVpnLinkState(DataBroker broker, String vpnLinkName, InterVpnLinkState.State state,
213         FirstEndpointState newFirstEndpointState,
214         SecondEndpointState newSecondEndpointState) {
215         Optional<InterVpnLinkState> optOldVpnLinkState = getInterVpnLinkState(broker, vpnLinkName);
216         if (optOldVpnLinkState.isPresent()) {
217             InterVpnLinkState newVpnLinkState =
218                 new InterVpnLinkStateBuilder(optOldVpnLinkState.get()).setState(state)
219                             .setFirstEndpointState(newFirstEndpointState)
220                             .setSecondEndpointState(newSecondEndpointState)
221                             .build();
222             VpnUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION,
223                 InterVpnLinkUtil.getInterVpnLinkStateIid(vpnLinkName), newVpnLinkState);
224             InterVpnLinkCache.addInterVpnLinkStateToCaches(newVpnLinkState);
225         } else {
226             InterVpnLinkState newIVpnLinkState =
227                 new InterVpnLinkStateBuilder().setKey(new InterVpnLinkStateKey(vpnLinkName))
228                     .setInterVpnLinkName(vpnLinkName)
229                     .setFirstEndpointState(newFirstEndpointState)
230                     .setSecondEndpointState(newSecondEndpointState)
231                     .setState(InterVpnLinkState.State.Active)
232                     .build();
233             VpnUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
234                 InterVpnLinkUtil.getInterVpnLinkStateIid(vpnLinkName), newIVpnLinkState);
235             InterVpnLinkCache.addInterVpnLinkStateToCaches(newIVpnLinkState);
236         }
237     }
238
239     /**
240      * Installs a Flow in LPortDispatcher table that matches on SI=2 and
241      * the lportTag of one InterVpnLink's endpoint and sets the vrfTag of the
242      * other endpoint and sends to FIB table.
243      *
244      * @param broker dataBroker service reference
245      * @param mdsalManager MDSAL API accessor
246      * @param interVpnLinkName Name of the InterVpnLink.
247      * @param dpnList The list of DPNs where this flow must be installed
248      * @param vpnUuidOtherEndpoint UUID of the other endpoint of the InterVpnLink
249      * @param lportTagOfOtherEndpoint Dataplane identifier of the other endpoint of the InterVpnLink
250      * @return the list of Futures for each and every flow that has been installed
251      */
252     public static List<ListenableFuture<Void>> installLPortDispatcherTableFlow(DataBroker broker,
253                                                                                IMdsalApiManager mdsalManager,
254                                                                                String interVpnLinkName,
255                                                                                List<BigInteger> dpnList,
256                                                                                String vpnUuidOtherEndpoint,
257                                                                                Long lportTagOfOtherEndpoint) {
258         List<ListenableFuture<Void>> result = new ArrayList<>();
259         long vpnId = VpnUtil.getVpnId(broker, vpnUuidOtherEndpoint);
260         for (BigInteger dpnId : dpnList) {
261             // insert into LPortDispatcher table
262             Flow lportDispatcherFlow = buildLPortDispatcherFlow(interVpnLinkName, vpnId,
263                                                                 lportTagOfOtherEndpoint.intValue());
264             result.add(mdsalManager.installFlow(dpnId, lportDispatcherFlow));
265         }
266
267         return result;
268     }
269
270     /**
271      * Builds a Flow to be installed into LPortDispatcher table, that matches on
272      * SI=2 + vpnLinkEndpointPseudoPortTag and sends to FIB.
273      *
274      * @param interVpnLinkName The name of the InterVpnLink
275      * @param vpnId Dataplane identifier of the VPN, the Vrf Tag.
276      * @param lportTag DataPlane identifier of the LogicalPort.
277      * @return the Flow ready to be installed
278      */
279     public static Flow buildLPortDispatcherFlow(String interVpnLinkName, long vpnId, int lportTag) {
280         LOG.info("Inter-vpn-link : buildLPortDispatcherFlow. vpnId {}   lportTag {} ", vpnId, lportTag);
281         List<MatchInfo> matches = Collections.singletonList(new MatchMetadata(
282                         MetaDataUtil.getMetaDataForLPortDispatcher(lportTag,
283                                 ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME, NwConstants.L3VPN_SERVICE_INDEX)),
284                         MetaDataUtil.getMetaDataMaskForLPortDispatcher()));
285         String flowRef = getLportDispatcherFlowRef(interVpnLinkName, lportTag);
286
287         return MDSALUtil.buildFlowNew(NwConstants.LPORT_DISPATCHER_TABLE, flowRef,
288                                       VpnConstants.DEFAULT_LPORT_DISPATCHER_FLOW_PRIORITY, flowRef,
289                                       0, 0, VpnUtil.getCookieL3((int) vpnId), matches,
290                                       buildLportDispatcherTableInstructions(vpnId));
291     }
292
293     /**
294      * Builds a flowRef to be assigned to the flow to be installed into
295      * LPortDispatcher table.
296      *
297      * @param interVpnLinkName The name of the InterVpnLink
298      * @param lportTag Dataplane identifier of the LogicalPort
299      * @return the flow reference string
300      */
301     public static String getLportDispatcherFlowRef(String interVpnLinkName, Integer lportTag) {
302         return VpnConstants.FLOWID_PREFIX + "INTERVPNLINK" + NwConstants.FLOWID_SEPARATOR + interVpnLinkName
303              + NwConstants.FLOWID_SEPARATOR + lportTag
304              + NwConstants.FLOWID_SEPARATOR + ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME,
305                                                                     NwConstants.L3VPN_SERVICE_INDEX)
306              + NwConstants.FLOWID_SEPARATOR + VpnConstants.DEFAULT_LPORT_DISPATCHER_FLOW_PRIORITY;
307     }
308
309
310     public static List<Instruction> buildLportDispatcherTableInstructions(long vpnId) {
311         int instructionKey = 0;
312         List<Instruction> instructions = new ArrayList<>();
313         instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(MetaDataUtil.getVpnIdMetadata(vpnId),
314             MetaDataUtil.METADATA_MASK_VRFID,
315             ++instructionKey));
316         instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.L3_FIB_TABLE, ++instructionKey));
317
318         return instructions;
319     }
320
321     /**
322      * Retrieves the States of all InterVpnLinks.
323      *
324      * @param broker dataBroker service reference
325      * @return the list of objects that holds the InterVpnLink state information
326      */
327     public static List<InterVpnLinkState> getAllInterVpnLinkState(DataBroker broker) {
328         InstanceIdentifier<InterVpnLinkStates> interVpnLinkStateIid =
329             InstanceIdentifier.builder(InterVpnLinkStates.class).build();
330
331         Optional<InterVpnLinkStates> interVpnLinkStateOpData =
332             MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, interVpnLinkStateIid);
333
334         return (interVpnLinkStateOpData.isPresent()) ? interVpnLinkStateOpData.get().getInterVpnLinkState()
335             : new ArrayList<>();
336     }
337
338     /**
339      * Retrieves the State of an InterVpnLink.
340      *
341      * @param broker dataBroker service reference
342      * @param interVpnLinkName The name of the InterVpnLink
343      * @return the object that contains the State of the specified InterVpnLink or Optional.absent() if it doesnt exist
344      */
345     public static Optional<InterVpnLinkState> getInterVpnLinkState(DataBroker broker, String interVpnLinkName) {
346         return MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, getInterVpnLinkStateIid(interVpnLinkName));
347     }
348
349     /**
350      * Retrieves all configured InterVpnLinks.
351      *
352      * @param broker dataBroker service reference
353      * @return the list of InterVpnLinks
354      */
355     public static List<InterVpnLink> getAllInterVpnLinks(DataBroker broker) {
356         InstanceIdentifier<InterVpnLinks> interVpnLinksIid = InstanceIdentifier.builder(InterVpnLinks.class).build();
357
358         Optional<InterVpnLinks> interVpnLinksOpData =
359             MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, interVpnLinksIid);
360
361         return interVpnLinksOpData.isPresent() ? interVpnLinksOpData.get().getInterVpnLink()
362             : new ArrayList<>();
363     }
364
365     /**
366      * Leaks a route from one VPN to another. By default, the origin for this leaked route is INTERVPN.
367      *
368      * @param broker dataBroker service reference
369      * @param bgpManager Used to advertise routes to the BGP Router
370      * @param interVpnLink Reference to the object that holds the info about the link between the 2 VPNs
371      * @param srcVpnUuid UUID of the VPN that has the route that is going to be leaked to the other VPN
372      * @param dstVpnUuid UUID of the VPN that is going to receive the route
373      * @param prefix Prefix of the route
374      * @param label Label of the route in the original VPN
375      */
376     public static void leakRoute(DataBroker broker, IBgpManager bgpManager, InterVpnLink interVpnLink,
377         String srcVpnUuid, String dstVpnUuid, String prefix, Long label) {
378         leakRoute(broker, bgpManager, interVpnLink, srcVpnUuid, dstVpnUuid, prefix, label, RouteOrigin.INTERVPN);
379     }
380
381     /**
382      * Leaks a route from one VPN to another.
383      *
384      * @param broker dataBroker service reference
385      * @param bgpManager Used to advertise routes to the BGP Router
386      * @param interVpnLink Reference to the object that holds the info about the link between the 2 VPNs
387      * @param srcVpnUuid UUID of the VPN that has the route that is going to be leaked to the other VPN
388      * @param dstVpnUuid UUID of the VPN that is going to receive the route
389      * @param prefix Prefix of the route
390      * @param label Label of the route in the original VPN
391      * @param forcedOrigin By default, origin for leaked routes should be INTERVPN, however it is possible to provide
392      *     a different origin if desired.
393      */
394     // TODO Clean up the exception handling
395     @SuppressWarnings("checkstyle:IllegalCatch")
396     public static void leakRoute(DataBroker broker, IBgpManager bgpManager, InterVpnLink interVpnLink,
397         String srcVpnUuid, String dstVpnUuid, String prefix, Long label,
398         RouteOrigin forcedOrigin) {
399         Preconditions.checkNotNull(interVpnLink);
400
401         // The source VPN must participate in the InterVpnLink
402         Preconditions.checkArgument(interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(srcVpnUuid)
403                 || interVpnLink.getSecondEndpoint().getVpnUuid().getValue().equals(srcVpnUuid),
404             "The source VPN {} does not participate in the interVpnLink {}",
405             srcVpnUuid, interVpnLink.getName());
406         // The destination VPN must participate in the InterVpnLink
407         Preconditions.checkArgument(interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(dstVpnUuid)
408                 || interVpnLink.getSecondEndpoint().getVpnUuid().getValue().equals(dstVpnUuid),
409             "The destination VPN {} does not participate in the interVpnLink {}",
410             dstVpnUuid, interVpnLink.getName());
411
412         boolean destinationIs1stEndpoint = interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(dstVpnUuid);
413
414         String endpointIp = destinationIs1stEndpoint ? interVpnLink.getSecondEndpoint().getIpAddress().getValue()
415             : interVpnLink.getFirstEndpoint().getIpAddress().getValue();
416
417         VrfEntry newVrfEntry = FibHelper.getVrfEntryBuilder(prefix, label, endpointIp, RouteOrigin.INTERVPN,
418                 null /* parentVpnRd */).build();
419
420         String dstVpnRd = VpnUtil.getVpnRd(broker, dstVpnUuid);
421         InstanceIdentifier<VrfEntry> newVrfEntryIid =
422             InstanceIdentifier.builder(FibEntries.class)
423                 .child(VrfTables.class, new VrfTablesKey(dstVpnRd))
424                 .child(VrfEntry.class, new VrfEntryKey(newVrfEntry.getDestPrefix()))
425                 .build();
426         VpnUtil.asyncWrite(broker, LogicalDatastoreType.CONFIGURATION, newVrfEntryIid, newVrfEntry);
427
428         // Finally, route is advertised it to the DC-GW. But while in the FibEntries the nexthop is the other
429         // endpoint's IP, in the DC-GW the nexthop for those prefixes are the IPs of those DPNs where the target
430         // VPN has been instantiated
431         Optional<InterVpnLinkState> optVpnLinkState = getInterVpnLinkState(broker, interVpnLink.getName());
432         if (optVpnLinkState.isPresent()) {
433             InterVpnLinkState vpnLinkState = optVpnLinkState.get();
434             List<BigInteger> dpnIdList = destinationIs1stEndpoint ? vpnLinkState.getFirstEndpointState().getDpId()
435                 : vpnLinkState.getSecondEndpointState().getDpId();
436             List<String> nexthops = new ArrayList<>();
437             for (BigInteger dpnId : dpnIdList) {
438                 nexthops.add(InterfaceUtils.getEndpointIpAddressForDPN(broker, dpnId));
439             }
440             try {
441                 LOG.debug("Advertising route in VPN={} [prefix={} label={}  nexthops={}] to DC-GW",
442                     dstVpnRd, newVrfEntry.getDestPrefix(), label.intValue(), nexthops);
443                 bgpManager.advertisePrefix(dstVpnRd, null /*macAddress*/, newVrfEntry.getDestPrefix(), nexthops,
444                         VrfEntry.EncapType.Mplsgre, label.intValue(), 0 /*l3vni*/, 0 /*l2vni*/,
445                         null /*gatewayMacAddress*/);
446             } catch (Exception exc) {
447                 LOG.error("Could not advertise prefix {} with label {} to VPN rd={}",
448                     newVrfEntry.getDestPrefix(), label.intValue(), dstVpnRd);
449             }
450         } else {
451             LOG.warn("Error when advertising leaked routes: Could not find State for InterVpnLink={}",
452                 interVpnLink.getName());
453         }
454     }
455
456     public static void handleStaticRoute(InterVpnLinkDataComposite interVpnLink, String vpnName,
457         String destination, String nexthop, int label,
458         DataBroker dataBroker, IFibManager fibManager, IBgpManager bgpManager) throws Exception {
459
460         LOG.debug("handleStaticRoute [vpnLink={} srcVpn={} destination={} nextHop={} label={}]",
461             interVpnLink.getInterVpnLinkName(), vpnName, destination, nexthop, label);
462
463         String vpnRd = VpnUtil.getVpnRd(dataBroker, vpnName);
464         if (vpnRd == null) {
465             LOG.warn("Could not find Route-Distinguisher for VpnName {}", vpnName);
466             return;
467         }
468         LOG.debug("Writing FibEntry to DS:  vpnRd={}, prefix={}, label={}, nexthop={} (interVpnLink)",
469             vpnRd, destination, label, nexthop);
470         fibManager.addOrUpdateFibEntry(dataBroker, vpnRd, null /*macAddress*/, destination,
471                 Collections.singletonList(nexthop), VrfEntry.EncapType.Mplsgre, label,
472                 0 /*l3vni*/, null /*gatewayMacAddress*/, null /*parentVpnRd*/, RouteOrigin.STATIC, null /*writeTxn*/);
473
474         // Now advertise to BGP. The nexthop that must be advertised to BGP are the IPs of the DPN where the
475         // VPN's endpoint have been instantiated
476         // List<String> nexthopList = new ArrayList<>(); // The nexthops to be advertised to BGP
477         List<BigInteger> endpointDpns = interVpnLink.getEndpointDpnsByVpnName(vpnName);
478         List<String> nexthopList =
479             endpointDpns.stream().map(dpnId -> InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, dpnId))
480                         .collect(Collectors.toList());
481         LOG.debug("advertising IVpnLink route to BGP:  vpnRd={}, prefix={}, label={}, nexthops={}",
482             vpnRd, destination, label, nexthopList);
483         bgpManager.advertisePrefix(vpnRd, null /*macAddress*/, destination, nexthopList,
484                 VrfEntry.EncapType.Mplsgre, label, 0 /*l3vni*/, 0 /*l2vni*/,
485                 null /*gatewayMacAddress*/);
486     }
487 }