MatchInfo redesign
[netvirt.git] / vpnservice / vpnmanager / vpnmanager-impl / src / main / java / org / opendaylight / netvirt / vpnmanager / intervpnlink / InterVpnLinkUtil.java
1 /*
2  * Copyright (c) 2016 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 org.opendaylight.controller.md.sal.binding.api.DataBroker;
13 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
14 import org.opendaylight.genius.mdsalutil.MDSALUtil;
15 import org.opendaylight.genius.mdsalutil.MatchInfo;
16 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
17 import org.opendaylight.genius.mdsalutil.NwConstants;
18 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
19 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
20 import org.opendaylight.genius.utils.ServiceIndex;
21 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
22 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
23 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
24 import org.opendaylight.netvirt.vpnmanager.VpnConstants;
25 import org.opendaylight.netvirt.vpnmanager.VpnFootprintService;
26 import org.opendaylight.netvirt.vpnmanager.VpnUtil;
27 import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkCache;
28 import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkDataComposite;
29 import org.opendaylight.netvirt.vpnmanager.utilities.InterfaceUtils;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.InterVpnLinkStates;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.InterVpnLinks;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkState;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkStateBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkStateKey;
44 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;
45 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;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.links.InterVpnLink;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.links.InterVpnLinkKey;
48 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
51
52 import com.google.common.util.concurrent.ListenableFuture;
53 import java.math.BigInteger;
54 import java.util.ArrayList;
55 import java.util.Arrays;
56 import java.util.Collections;
57 import java.util.List;
58 import java.util.stream.Collectors;
59
60
61 /**
62  * This class contains methods to be used as utilities related with inter-vpn-link.
63  *
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 MDSL
72      *
73      * @param iVpnLinkName The name of the InterVpnLink
74      * @return The requested InstanceIdentifier
75      */
76     public static InstanceIdentifier<InterVpnLink> getInterVpnLinkPath(String iVpnLinkName) {
77         return InstanceIdentifier.builder(InterVpnLinks.class)
78                 .child(InterVpnLink.class, new InterVpnLinkKey(iVpnLinkName))
79                 .build();
80     }
81
82     /**
83      * Retrieves the Instance Identifier that points to an InterVpnLinkState object
84      * in MDSL
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
108      *     be added
109      */
110     public static void updateVpnFootprint(VpnFootprintService vpnFootprintService, String vpnName,
111                                           List<BigInteger> dpnList) {
112         LOG.debug("updateVpnFootprint (add):  vpn={}  dpnList={}", vpnName, dpnList);
113         // Note: when a set of DPNs is calculated for Vpn1, these DPNs are added to the VpnToDpn map of Vpn2. Why?
114         // because we do the handover from Vpn1 to Vpn2 in those DPNs, so in those DPNs we must know how to reach
115         // to Vpn2 targets. If new Vpn2 targets are added later, the Fib will be maintained in these DPNs even if
116         // Vpn2 is not physically present there.
117         for ( BigInteger dpnId : dpnList ) {
118             String ifaceName = buildInterVpnLinkIfaceName(vpnName, dpnId);
119             vpnFootprintService.updateVpnToDpnMapping(dpnId, vpnName, ifaceName, 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, BigInteger dpnId) {
133         String ifaceName = buildInterVpnLinkIfaceName(vpnName, dpnId);
134         LOG.debug("updateVpnFootprint (remove):  vpn={}  dpn={}  ifaceName={}", vpnName, dpnId, ifaceName);
135         vpnFootprintService.updateVpnToDpnMapping(dpnId, vpnName, ifaceName, false /* removal */);
136     }
137
138     /**
139      * Retrieves the InterVpnLink object searching by its name
140      *
141      * @param broker dataBroker service reference
142      * @param vpnLinkName Name of the InterVpnLink
143      * @return the InterVpnLink or Optional.absent() if there is no
144      *     InterVpnLink with the specified name
145      */
146     public static Optional<InterVpnLink> getInterVpnLinkByName(DataBroker broker, String vpnLinkName) {
147         InstanceIdentifier<InterVpnLink> interVpnLinksIid =
148                 InstanceIdentifier.builder(InterVpnLinks.class)
149                         .child(InterVpnLink.class, new InterVpnLinkKey(vpnLinkName)).build();
150         return  VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, interVpnLinksIid);
151     }
152
153     /**
154      * Updates inter-VPN link state
155      *
156      * @param broker dataBroker service reference
157      * @param vpnLinkName The name of the InterVpnLink
158      * @param state Sets the state of the InterVpnLink to Active or Error
159      * @param newFirstEndpointState Updates the lportTag and/or DPNs of the 1st
160      *     endpoint of the InterVpnLink
161      * @param newSecondEndpointState Updates the lportTag and/or DPNs of the
162      *     2nd endpoint of the InterVpnLink
163      */
164     public static void updateInterVpnLinkState(DataBroker broker, String vpnLinkName, InterVpnLinkState.State state,
165                                                FirstEndpointState newFirstEndpointState,
166                                                SecondEndpointState newSecondEndpointState) {
167         Optional<InterVpnLinkState> optOldVpnLinkState = getInterVpnLinkState(broker, vpnLinkName);
168         if ( optOldVpnLinkState.isPresent() ) {
169             InterVpnLinkState newVpnLinkState =
170                     new InterVpnLinkStateBuilder(optOldVpnLinkState.get()).setState(state)
171                             .setFirstEndpointState(newFirstEndpointState)
172                             .setSecondEndpointState(newSecondEndpointState)
173                             .build();
174             VpnUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION,
175                     InterVpnLinkUtil.getInterVpnLinkStateIid(vpnLinkName), newVpnLinkState);
176             InterVpnLinkCache.addInterVpnLinkStateToCaches(newVpnLinkState);
177         } else {
178             InterVpnLinkState newIVpnLinkState =
179                     new InterVpnLinkStateBuilder().setKey(new InterVpnLinkStateKey(vpnLinkName))
180                             .setInterVpnLinkName(vpnLinkName)
181                             .setFirstEndpointState(newFirstEndpointState)
182                             .setSecondEndpointState(newSecondEndpointState)
183                             .setState(InterVpnLinkState.State.Active)
184                             .build();
185             VpnUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
186                     InterVpnLinkUtil.getInterVpnLinkStateIid(vpnLinkName), newIVpnLinkState);
187             InterVpnLinkCache.addInterVpnLinkStateToCaches(newIVpnLinkState);
188         }
189     }
190
191     /**
192      * Installs a Flow in LPortDispatcher table that matches on SI=2 and
193      * the lportTag of one InterVpnLink's endpoint and sets the vrfTag of the
194      * other endpoint and sends to FIB table
195      *
196      * @param broker dataBroker service reference
197      * @param mdsalManager MDSAL API accessor
198      * @param interVpnLink Object that holds the needed information about both
199      *     endpoints of the InterVpnLink.
200      * @param dpnList The list of DPNs where this flow must be installed
201      * @param vpnUuidOtherEndpoint UUID of the other endpoint of the
202      *     InterVpnLink
203      * @param lPortTagOfOtherEndpoint Dataplane identifier of the other
204      *     endpoint of the InterVpnLink
205      * @return the list of Futures for each and every flow that has been
206      *     installed
207      */
208     public static List<ListenableFuture<Void>> installLPortDispatcherTableFlow(DataBroker broker,
209                                                                                IMdsalApiManager mdsalManager,
210                                                                                InterVpnLink interVpnLink,
211                                                                                List<BigInteger> dpnList,
212                                                                                Uuid vpnUuidOtherEndpoint,
213                                                                                Long lPortTagOfOtherEndpoint) {
214         List<ListenableFuture<Void>> result = new ArrayList<>();
215         long vpnId = VpnUtil.getVpnId(broker, vpnUuidOtherEndpoint.getValue());
216         for ( BigInteger dpnId : dpnList ) {
217             // insert into LPortDispatcher table
218             Flow lPortDispatcherFlow = buildLPortDispatcherFlow(interVpnLink.getName(), vpnId,
219                                                                 lPortTagOfOtherEndpoint.intValue());
220             result.add(mdsalManager.installFlow(dpnId, lPortDispatcherFlow));
221         }
222
223         return result;
224     }
225
226     /**
227      * Builds a Flow to be installed into LPortDispatcher table, that matches on
228      * SI=2 + vpnLinkEndpointPseudoPortTag and sends to FIB
229      *
230      * @param interVpnLinkName The name of the InterVpnLink
231      * @param vpnId Dataplane identifier of the VPN, the Vrf Tag.
232      * @param lportTag DataPlane identifier of the LogicalPort.
233      * @return the Flow ready to be installed
234      */
235     public static Flow buildLPortDispatcherFlow(String interVpnLinkName, long vpnId, int lportTag) {
236         LOG.info("Inter-vpn-link : buildLPortDispatcherFlow. vpnId {}   lportTag {} ", vpnId, lportTag);
237         List<MatchInfo> matches = Collections.singletonList(new MatchMetadata(
238                         MetaDataUtil.getMetaDataForLPortDispatcher(lportTag,
239                                 ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME, NwConstants.L3VPN_SERVICE_INDEX)),
240                         MetaDataUtil.getMetaDataMaskForLPortDispatcher()));
241         String flowRef = getLportDispatcherFlowRef(interVpnLinkName, lportTag);
242         Flow lPortDispatcherFlow = MDSALUtil.buildFlowNew(NwConstants.LPORT_DISPATCHER_TABLE, flowRef,
243                 VpnConstants.DEFAULT_LPORT_DISPATCHER_FLOW_PRIORITY, flowRef,
244                 0, 0, VpnUtil.getCookieL3((int) vpnId), matches,
245                 buildLportDispatcherTableInstructions(vpnId));
246         return lPortDispatcherFlow;
247     }
248
249     /**
250      * Builds a flowRef to be assigned to the flow to be installed into
251      * LPortDispatcher table
252      *
253      * @param interVpnLinkName The name of the InterVpnLink
254      * @param lportTag Dataplane identifier of the LogicalPort
255      * @return the flow reference string
256      */
257     public static String getLportDispatcherFlowRef(String interVpnLinkName, Integer lportTag) {
258         return new StringBuffer()
259                 .append(VpnConstants.FLOWID_PREFIX).append("INTERVPNLINK")
260                 .append(NwConstants.FLOWID_SEPARATOR).append(interVpnLinkName)
261                 .append(NwConstants.FLOWID_SEPARATOR).append(lportTag)
262                 .append(NwConstants.FLOWID_SEPARATOR).append(ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME,
263                                                                                    NwConstants.L3VPN_SERVICE_INDEX))
264                 .append(NwConstants.FLOWID_SEPARATOR)
265                 .append(VpnConstants.DEFAULT_LPORT_DISPATCHER_FLOW_PRIORITY)
266                 .toString();
267     }
268
269
270     public static List<Instruction> buildLportDispatcherTableInstructions (long vpnId) {
271         int instructionKey = 0;
272         List<Instruction> instructions = new ArrayList<Instruction>();
273         instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(MetaDataUtil.getVpnIdMetadata(vpnId),
274                 MetaDataUtil.METADATA_MASK_VRFID,
275                 ++instructionKey));
276         instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.L3_FIB_TABLE, ++instructionKey));
277
278         return instructions;
279     }
280
281     /**
282      * Retrieves the States of all InterVpnLinks
283      *
284      * @param broker dataBroker service reference
285      * @return the list of objects that holds the InterVpnLink state information
286      */
287     public static List<InterVpnLinkState> getAllInterVpnLinkState(DataBroker broker) {
288         InstanceIdentifier<InterVpnLinkStates> interVpnLinkStateIid =
289                 InstanceIdentifier.builder(InterVpnLinkStates.class).build();
290
291         Optional<InterVpnLinkStates> interVpnLinkStateOpData =
292                 MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, interVpnLinkStateIid);
293
294         return (interVpnLinkStateOpData.isPresent()) ? interVpnLinkStateOpData.get().getInterVpnLinkState()
295                 : new ArrayList<InterVpnLinkState>();
296     }
297
298     /**
299      * Retrieves the State of an InterVpnLink
300      *
301      * @param broker dataBroker service reference
302      * @param iVpnLinkName The name of the InterVpnLink
303      * @return the object that contains the State of the specified InterVpnLink
304      *         or Optional.absent() if it doesnt exist
305      */
306     public static Optional<InterVpnLinkState> getInterVpnLinkState(DataBroker broker, String iVpnLinkName) {
307         return MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, getInterVpnLinkStateIid(iVpnLinkName));
308     }
309
310     /**
311      * Checks if the specified InterVpnLink is currently Active
312      *
313      * @param broker dataBroker service reference
314      * @param iVpnLinkName The name of the InterVpnLink
315      * @return true if the InterVpnLink is Active
316      */
317     public static boolean isInterVpnLinkActive(DataBroker broker, String iVpnLinkName) {
318         Optional<InterVpnLinkState> optIVpnLinkState = getInterVpnLinkState(broker, iVpnLinkName);
319         if ( ! optIVpnLinkState.isPresent() ) {
320             return false;
321         }
322         InterVpnLinkState iVpnLinkState = optIVpnLinkState.get();
323         return iVpnLinkState.getState() == InterVpnLinkState.State.Active;
324     }
325
326     /**
327      * Retrieves an InterVpnLink by searching by one of its endpoint's IP.
328      *
329      * @param broker dataBroker service reference
330      * @param endpointIp IP to serch for.
331      * @return the InterVpnLink or null if no InterVpnLink can be found
332      */
333     public static Optional<InterVpnLink> getInterVpnLinkByEndpointIp(DataBroker broker, String endpointIp) {
334         List<InterVpnLink> allInterVpnLinks = InterVpnLinkUtil.getAllInterVpnLinks(broker);
335         for (InterVpnLink interVpnLink : allInterVpnLinks) {
336             if (interVpnLink.getFirstEndpoint().getIpAddress().getValue().equals(endpointIp)
337                     || interVpnLink.getSecondEndpoint().getIpAddress().getValue().equals(endpointIp)) {
338                 return Optional.of(interVpnLink);
339             }
340         }
341         return Optional.absent();
342     }
343
344
345     /**
346      * Retrieves the InterVpnLink that has one of its 2 endpoints installed in
347      * the specified DpnId
348      *
349      * @param broker dataBroker service reference
350      * @param dpnId Id of the DPN
351      * @return The InterVpnLink object if found, Optional.absent() otherwise
352      */
353     public static Optional<InterVpnLink> getInterVpnLinkByDpnId(DataBroker broker, BigInteger dpnId) {
354         List<InterVpnLink> allInterVpnLinks = InterVpnLinkUtil.getAllInterVpnLinks(broker);
355         for (InterVpnLink interVpnLink : allInterVpnLinks) {
356             Optional<InterVpnLinkState> optInterVpnLinkState = getInterVpnLinkState(broker, interVpnLink.getName());
357             if ( optInterVpnLinkState.isPresent()
358                     && ( optInterVpnLinkState.get().getFirstEndpointState().getDpId().contains(dpnId)
359                     || optInterVpnLinkState.get().getSecondEndpointState().getDpId().contains(dpnId) ) ) {
360                 return Optional.fromNullable(interVpnLink);
361             }
362         }
363         return Optional.absent();
364     }
365
366     /**
367      * Retrieves all configured InterVpnLinks
368      *
369      * @param broker dataBroker service reference
370      * @return the list of InterVpnLinks
371      */
372     public static List<InterVpnLink> getAllInterVpnLinks(DataBroker broker) {
373         InstanceIdentifier<InterVpnLinks> interVpnLinksIid = InstanceIdentifier.builder(InterVpnLinks.class).build();
374
375         Optional<InterVpnLinks> interVpnLinksOpData =
376                 MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, interVpnLinksIid);
377
378         return interVpnLinksOpData.isPresent() ? interVpnLinksOpData.get().getInterVpnLink()
379                 : new ArrayList<>();
380     }
381
382     /**
383      * Retrieves the list of DPNs where the endpoint of a VPN in an InterVPNLink was instantiated
384      *
385      * @param broker dataBroker service reference
386      * @param vpnLinkName the name of the InterVpnLink
387      * @param vpnUuid UUID of the VPN whose endpoint to be checked
388      * @return the list of DPN Ids
389      */
390     public static List<BigInteger> getVpnLinkEndpointDPNs(DataBroker broker, String vpnLinkName, String vpnUuid) {
391         Optional<InterVpnLinkState> interVpnLinkState = getInterVpnLinkState(broker, vpnLinkName);
392         if ( interVpnLinkState.isPresent()) {
393             if (interVpnLinkState.get().getFirstEndpointState().getVpnUuid().getValue().equals(vpnUuid)) {
394                 return interVpnLinkState.get().getFirstEndpointState().getDpId();
395             } else {
396                 return interVpnLinkState.get().getSecondEndpointState().getDpId();
397             }
398         } else {
399             LOG.trace("Could not find InterVpnLinkState for interVpnLink {}", vpnLinkName);
400             return new ArrayList<BigInteger>();
401         }
402     }
403
404     /**
405      * Retrieves the list of DPNs where the endpoint of a VPN in an InterVPNLink was instantiated
406      *
407      * @param broker dataBroker service reference
408      * @param endpointIp Ip of the endpoint specified in the InterVpnLink
409      * @return the list of DPN Ids
410      */
411     public static List<BigInteger> getVpnLinkEndpointDPNsByIp(DataBroker broker, String endpointIp) {
412         Optional<InterVpnLink> optIVpnLink = getInterVpnLinkByEndpointIp(broker, endpointIp);
413         if ( optIVpnLink.isPresent() ) {
414             InterVpnLink iVpnLink = optIVpnLink.get();
415             boolean isFirstEndpoint = iVpnLink.getFirstEndpoint().getIpAddress().getValue().equals(endpointIp);
416             return isFirstEndpoint ? getVpnLinkEndpointDPNs(broker, iVpnLink.getName(),
417                     iVpnLink.getFirstEndpoint().getVpnUuid().getValue())
418                     : getVpnLinkEndpointDPNs(broker, iVpnLink.getName(),
419                     iVpnLink.getSecondEndpoint().getVpnUuid().getValue());
420         } else {
421             LOG.trace("Could not find an InterVpnLink with endpoint IpAddr={}", endpointIp);
422             return new ArrayList<BigInteger>();
423         }
424     }
425
426
427     /**
428      * Leaks a route from one VPN to another. By default, the origin for this leaked route is INTERVPN
429      *
430      * @param broker           dataBroker service reference
431      * @param bgpManager       Used to advertise routes to the BGP Router
432      * @param interVpnLink     Reference to the object that holds the info about the link between the 2 VPNs
433      * @param srcVpnUuid       UUID of the VPN that has the route that is going to be leaked to the other VPN
434      * @param dstVpnUuid       UUID of the VPN that is going to receive the route
435      * @param prefix           Prefix of the route
436      * @param label            Label of the route in the original VPN
437      */
438     public static void leakRoute(DataBroker broker, IBgpManager bgpManager, InterVpnLink interVpnLink,
439                                  String srcVpnUuid, String dstVpnUuid, String prefix, Long label) {
440         leakRoute(broker, bgpManager, interVpnLink, srcVpnUuid, dstVpnUuid, prefix, label, RouteOrigin.INTERVPN);
441     }
442
443     /**
444      * Leaks a route from one VPN to another.
445      *
446      * @param broker           dataBroker service reference
447      * @param bgpManager       Used to advertise routes to the BGP Router
448      * @param interVpnLink     Reference to the object that holds the info about the link between the 2 VPNs
449      * @param srcVpnUuid       UUID of the VPN that has the route that is going to be leaked to the other VPN
450      * @param dstVpnUuid       UUID of the VPN that is going to receive the route
451      * @param prefix           Prefix of the route
452      * @param label            Label of the route in the original VPN
453      * @param forcedOrigin     By default, origin for leaked routes should be INTERVPN, however it is possible to
454      *                         provide a different origin if desired.
455      */
456     public static void leakRoute(DataBroker broker, IBgpManager bgpManager, InterVpnLink interVpnLink,
457                                  String srcVpnUuid, String dstVpnUuid, String prefix, Long label,
458                                  RouteOrigin forcedOrigin) {
459         Preconditions.checkNotNull(interVpnLink);
460
461         // The source VPN must participate in the InterVpnLink
462         Preconditions.checkArgument(interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(srcVpnUuid)
463                         || interVpnLink.getSecondEndpoint().getVpnUuid().getValue().equals(srcVpnUuid),
464                 "The source VPN {} does not participate in the interVpnLink {}",
465                 srcVpnUuid, interVpnLink.getName());
466         // The destination VPN must participate in the InterVpnLink
467         Preconditions.checkArgument(interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(dstVpnUuid)
468                         || interVpnLink.getSecondEndpoint().getVpnUuid().getValue().equals(dstVpnUuid),
469                 "The destination VPN {} does not participate in the interVpnLink {}",
470                 dstVpnUuid, interVpnLink.getName());
471
472         boolean destinationIs1stEndpoint = interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(dstVpnUuid);
473
474         String endpointIp = destinationIs1stEndpoint ? interVpnLink.getSecondEndpoint().getIpAddress().getValue()
475                 : interVpnLink.getFirstEndpoint().getIpAddress().getValue();
476
477         VrfEntry newVrfEntry = new VrfEntryBuilder().setKey(new VrfEntryKey(prefix)).setDestPrefix(prefix)
478                 .setLabel(label).setNextHopAddressList(Arrays.asList(endpointIp))
479                 .setOrigin(RouteOrigin.INTERVPN.getValue())
480                 .build();
481
482         String dstVpnRd = VpnUtil.getVpnRd(broker, dstVpnUuid);
483         InstanceIdentifier<VrfEntry> newVrfEntryIid =
484                 InstanceIdentifier.builder(FibEntries.class)
485                         .child(VrfTables.class, new VrfTablesKey(dstVpnRd))
486                         .child(VrfEntry.class, new VrfEntryKey(newVrfEntry.getDestPrefix()))
487                         .build();
488         VpnUtil.asyncWrite(broker, LogicalDatastoreType.CONFIGURATION, newVrfEntryIid, newVrfEntry);
489
490         // Finally, route is advertised it to the DC-GW. But while in the FibEntries the nexthop is the other
491         // endpoint's IP, in the DC-GW the nexthop for those prefixes are the IPs of those DPNs where the target
492         // VPN has been instantiated
493         Optional<InterVpnLinkState> optVpnLinkState = getInterVpnLinkState(broker, interVpnLink.getName());
494         if ( optVpnLinkState.isPresent() ) {
495             InterVpnLinkState vpnLinkState = optVpnLinkState.get();
496             List<BigInteger> dpnIdList = destinationIs1stEndpoint ? vpnLinkState.getFirstEndpointState().getDpId()
497                     : vpnLinkState.getSecondEndpointState().getDpId();
498             List<String> nexthops = new ArrayList<String>();
499             for (BigInteger dpnId : dpnIdList) {
500                 nexthops.add(InterfaceUtils.getEndpointIpAddressForDPN(broker, dpnId));
501             }
502             try {
503                 LOG.debug("Advertising route in VPN={} [prefix={} label={}  nexthops={}] to DC-GW",
504                         dstVpnRd, newVrfEntry.getDestPrefix(), label.intValue(), nexthops);
505                 bgpManager.advertisePrefix(dstVpnRd, newVrfEntry.getDestPrefix(), nexthops, label.intValue());
506             } catch (Exception exc) {
507                 LOG.error("Could not advertise prefix {} with label {} to VPN rd={}",
508                         newVrfEntry.getDestPrefix(), label.intValue(), dstVpnRd);
509             }
510         } else {
511             LOG.warn("Error when advertising leaked routes: Could not find State for InterVpnLink={}",
512                     interVpnLink.getName());
513         }
514     }
515
516     public static void handleStaticRoute(InterVpnLinkDataComposite iVpnLink, String vpnName,
517                                          String destination, String nexthop, int label,
518                                          DataBroker dataBroker, IFibManager fibManager, IBgpManager bgpManager)
519              throws Exception {
520
521         LOG.debug("handleStaticRoute [vpnLink={} srcVpn={} destination={} nextHop={} label={}]",
522                   iVpnLink.getInterVpnLinkName(), vpnName, destination, nexthop, label);
523
524         String vpnRd = VpnUtil.getVpnRd(dataBroker, vpnName);
525         if ( vpnRd == null ) {
526             LOG.warn("Could not find Route-Distinguisher for VpnName {}", vpnName);
527             return;
528         }
529         LOG.debug("Writing FibEntry to DS:  vpnRd={}, prefix={}, label={}, nexthop={} (interVpnLink)",
530                   vpnRd, destination, label, nexthop);
531         fibManager.addOrUpdateFibEntry(dataBroker, vpnRd, destination, Collections.singletonList(nexthop), label,
532                                        RouteOrigin.STATIC, null);
533
534         // Now advertise to BGP. The nexthop that must be advertised to BGP are the IPs of the DPN where the
535         // VPN's endpoint have been instantiated
536         // List<String> nexthopList = new ArrayList<>(); // The nexthops to be advertised to BGP
537         List<BigInteger> endpointDpns = iVpnLink.getEndpointDpnsByVpnName(vpnName);
538         List<String> nexthopList =
539             endpointDpns.stream().map(dpnId -> InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, dpnId))
540                                  .collect(Collectors.toList());
541         LOG.debug("advertising IVpnLink route to BGP:  vpnRd={}, prefix={}, label={}, nexthops={}",
542                   vpnRd, destination, label, nexthopList);
543         bgpManager.advertisePrefix(vpnRd, destination, nexthopList, label);
544
545         // TODO: Leak if static-routes-leaking flag is active
546
547     }
548 }