fibmanager dead code removal
[netvirt.git] / fibmanager / impl / src / main / java / org / opendaylight / netvirt / fibmanager / EvpnVrfEntryHandler.java
1 /*
2  * Copyright (c) 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.fibmanager;
9
10 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
11
12 import com.google.common.base.Optional;
13 import com.google.common.base.Preconditions;
14 import java.math.BigInteger;
15 import java.util.ArrayList;
16 import java.util.Collections;
17 import java.util.List;
18 import java.util.Objects;
19 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
20 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
21 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
22 import org.opendaylight.genius.datastoreutils.listeners.DataTreeEventCallbackRegistrar;
23 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
24 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
25 import org.opendaylight.genius.mdsalutil.ActionInfo;
26 import org.opendaylight.genius.mdsalutil.InstructionInfo;
27 import org.opendaylight.genius.mdsalutil.NwConstants;
28 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
29 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldEthernetDestination;
30 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId;
31 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
32 import org.opendaylight.genius.utils.batching.SubTransaction;
33 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
34 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
35 import org.opendaylight.serviceutils.upgrade.UpgradeState;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelOperStatus;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.SubnetRoute;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthop;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.vpn.extra.routes.Routes;
48 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
51
52
53 public class EvpnVrfEntryHandler extends BaseVrfEntryHandler {
54     private static final Logger LOG = LoggerFactory.getLogger(EvpnVrfEntryHandler.class);
55     private final ManagedNewTransactionRunner txRunner;
56     private final VrfEntryListener vrfEntryListener;
57     private final BgpRouteVrfEntryHandler bgpRouteVrfEntryHandler;
58     private final NexthopManager nexthopManager;
59     private final JobCoordinator jobCoordinator;
60
61     EvpnVrfEntryHandler(DataBroker broker, VrfEntryListener vrfEntryListener,
62             BgpRouteVrfEntryHandler bgpRouteVrfEntryHandler, NexthopManager nexthopManager,
63             JobCoordinator jobCoordinator, FibUtil fibUtil,
64             final UpgradeState upgradeState, final DataTreeEventCallbackRegistrar eventCallbacks) {
65         super(broker, nexthopManager, null, fibUtil, upgradeState, eventCallbacks);
66         this.txRunner = new ManagedNewTransactionRunnerImpl(broker);
67         this.vrfEntryListener = vrfEntryListener;
68         this.bgpRouteVrfEntryHandler = bgpRouteVrfEntryHandler;
69         this.nexthopManager = nexthopManager;
70         this.jobCoordinator = jobCoordinator;
71     }
72
73     void createFlows(InstanceIdentifier<VrfEntry> identifier, VrfEntry vrfEntry, String rd) {
74         LOG.info("Initiating creation of Evpn Flows");
75         final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class);
76         final VpnInstanceOpDataEntry vpnInstance = getFibUtil().getVpnInstanceOpData(
77                 vrfTableKey.getRouteDistinguisher()).get();
78         Long vpnId = vpnInstance.getVpnId();
79         Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available " + vrfTableKey.getRouteDistinguisher());
80         Preconditions.checkNotNull(vpnId, "Vpn Instance with rd " + vpnInstance.getVrfId()
81                 + " has null vpnId!");
82         if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.CONNECTED) {
83             SubnetRoute subnetRoute = vrfEntry.augmentation(SubnetRoute.class);
84             final List<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
85             final long elanTag = subnetRoute.getElantag();
86             LOG.trace("SubnetRoute augmented vrfentry found for rd {} prefix {} with elantag {}",
87                     rd, vrfEntry.getDestPrefix(), elanTag);
88             if (vpnToDpnList != null) {
89                 jobCoordinator.enqueueJob("FIB-" + rd + "-" + vrfEntry.getDestPrefix(),
90                     () -> Collections.singletonList(
91                         txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
92                             for (final VpnToDpnList curDpn : vpnToDpnList) {
93                                 if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
94                                     vrfEntryListener.installSubnetRouteInFib(curDpn.getDpnId(), elanTag, rd,
95                                         vpnId, vrfEntry, tx);
96                                 }
97                             }
98                         })));
99             }
100             return;
101         }
102         Prefixes localNextHopInfo = getFibUtil().getPrefixToInterface(vpnInstance.getVpnId(), vrfEntry.getDestPrefix());
103         List<BigInteger> localDpnId = new ArrayList<>();
104         boolean isNatPrefix = false;
105         if (Prefixes.PrefixCue.Nat.equals(localNextHopInfo.getPrefixCue())) {
106             LOG.info("NAT Prefix {} with vpnId {} rd {}. Skip local dpn {} FIB processing",
107                     vrfEntry.getDestPrefix(), vpnId, rd, localNextHopInfo.getDpnId());
108             localDpnId.add(localNextHopInfo.getDpnId());
109             isNatPrefix = true;
110         } else {
111             localDpnId = createLocalEvpnFlows(vpnInstance.getVpnId(), rd, vrfEntry,
112                     localNextHopInfo);
113         }
114         createRemoteEvpnFlows(rd, vrfEntry, vpnInstance, localDpnId, vrfTableKey, isNatPrefix);
115     }
116
117     void removeFlows(InstanceIdentifier<VrfEntry> identifier, VrfEntry vrfEntry, String rd) {
118         final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class);
119         final VpnInstanceOpDataEntry vpnInstance = getFibUtil().getVpnInstanceOpData(
120                 vrfTableKey.getRouteDistinguisher()).get();
121         if (vpnInstance == null) {
122             LOG.error("VPN Instance for rd {} is not available from VPN Op Instance Datastore", rd);
123             return;
124         }
125         VpnNexthop localNextHopInfo = nexthopManager.getVpnNexthop(vpnInstance.getVpnId(),
126                 vrfEntry.getDestPrefix());
127         List<BigInteger> localDpnId = checkDeleteLocalEvpnFLows(vpnInstance.getVpnId(), rd, vrfEntry, localNextHopInfo);
128         deleteRemoteEvpnFlows(rd, vrfEntry, vpnInstance, vrfTableKey, localDpnId);
129         vrfEntryListener.cleanUpOpDataForFib(vpnInstance.getVpnId(), rd, vrfEntry);
130     }
131
132     private List<BigInteger> createLocalEvpnFlows(long vpnId, String rd, VrfEntry vrfEntry,
133                                                   Prefixes localNextHopInfo) {
134         List<BigInteger> returnLocalDpnId = new ArrayList<>();
135         String localNextHopIP = vrfEntry.getDestPrefix();
136         if (localNextHopInfo == null) {
137             //Handle extra routes and imported routes
138             Routes extraRoute = getVpnToExtraroute(vpnId, rd, vrfEntry.getDestPrefix());
139             if (extraRoute != null && extraRoute.getNexthopIpList() != null) {
140                 for (String nextHopIp : extraRoute.getNexthopIpList()) {
141                     LOG.info("NextHop IP for destination {} is {}", vrfEntry.getDestPrefix(), nextHopIp);
142                     if (nextHopIp != null) {
143                         localNextHopInfo = getFibUtil().getPrefixToInterface(vpnId, nextHopIp + "/32");
144                         if (localNextHopInfo != null) {
145                             localNextHopIP = nextHopIp + "/32";
146                             BigInteger dpnId = checkCreateLocalEvpnFlows(localNextHopInfo, localNextHopIP, vpnId,
147                                     rd, vrfEntry);
148                             returnLocalDpnId.add(dpnId);
149                         }
150                     }
151                 }
152             }
153         } else {
154             LOG.info("Creating local EVPN flows for prefix {} rd {} route-paths {} evi {}.",
155                     vrfEntry.getDestPrefix(), rd, vrfEntry.getRoutePaths(), vrfEntry.getL3vni());
156             BigInteger dpnId = checkCreateLocalEvpnFlows(localNextHopInfo, localNextHopIP, vpnId,
157                     rd, vrfEntry);
158             returnLocalDpnId.add(dpnId);
159         }
160         return returnLocalDpnId;
161     }
162
163     private BigInteger checkCreateLocalEvpnFlows(Prefixes localNextHopInfo, String localNextHopIP,
164                                                  final Long vpnId, final String rd,
165                                                  final VrfEntry vrfEntry) {
166         final BigInteger dpnId = localNextHopInfo.getDpnId();
167         String jobKey = FibUtil.getCreateLocalNextHopJobKey(vpnId, dpnId, vrfEntry.getDestPrefix());
168         final long groupId = nexthopManager.createLocalNextHop(vpnId, dpnId,
169             localNextHopInfo.getVpnInterfaceName(), localNextHopIP, vrfEntry.getDestPrefix(),
170             vrfEntry.getGatewayMacAddress());
171         LOG.debug("LocalNextHopGroup {} created/reused for prefix {} rd {} evi {} route-paths {}", groupId,
172             vrfEntry.getDestPrefix(), rd, vrfEntry.getL3vni(), vrfEntry.getRoutePaths());
173
174         final List<InstructionInfo> instructions = Collections.singletonList(
175             new InstructionApplyActions(
176                 Collections.singletonList(new ActionGroup(groupId))));
177         jobCoordinator.enqueueJob(jobKey,
178             () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(
179                 tx -> makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW, tx,
180                         null))));
181         return dpnId;
182     }
183
184     private void createRemoteEvpnFlows(String rd, VrfEntry vrfEntry, VpnInstanceOpDataEntry vpnInstance,
185                                        List<BigInteger> localDpnId, VrfTablesKey vrfTableKey, boolean isNatPrefix) {
186         LOG.info("Creating remote EVPN flows for prefix {} rd {} route-paths {} evi {}",
187             vrfEntry.getDestPrefix(), rd, vrfEntry.getRoutePaths(), vrfEntry.getL3vni());
188         List<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
189         if (vpnToDpnList != null) {
190             jobCoordinator.enqueueJob("FIB" + rd + vrfEntry.getDestPrefix(),
191                 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
192                     for (VpnToDpnList vpnDpn : vpnToDpnList) {
193                         if (!localDpnId.contains(vpnDpn.getDpnId())) {
194                             if (vpnDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
195                                 createRemoteFibEntry(vpnDpn.getDpnId(), vpnInstance.getVpnId(),
196                                         vrfTableKey, vrfEntry, isNatPrefix, tx);
197                             }
198                         }
199                     }
200                 })));
201         }
202     }
203
204     private void createRemoteFibEntry(final BigInteger remoteDpnId, final long vpnId, final VrfTablesKey vrfTableKey,
205                                       final VrfEntry vrfEntry, boolean isNatPrefix, WriteTransaction tx) {
206
207         String rd = vrfTableKey.getRouteDistinguisher();
208         List<SubTransaction> subTxns =  new ArrayList<>();
209         LOG.debug("createremotefibentry: adding route {} for rd {} with transaction {}",
210                 vrfEntry.getDestPrefix(), rd, tx);
211         List<NexthopManager.AdjacencyResult> tunnelInterfaceList = resolveAdjacency(remoteDpnId, vpnId, vrfEntry, rd);
212
213         if (tunnelInterfaceList.isEmpty()) {
214             LOG.error("Could not get interface for route-paths: {} in vpn {}",
215                     vrfEntry.getRoutePaths(), rd);
216             LOG.warn("Failed to add Route: {} in vpn: {}",
217                     vrfEntry.getDestPrefix(), rd);
218             return;
219         }
220
221         for (NexthopManager.AdjacencyResult adjacencyResult : tunnelInterfaceList) {
222             List<ActionInfo> actionInfos = new ArrayList<>();
223             BigInteger tunnelId = BigInteger.ZERO;
224             String prefix = adjacencyResult.getPrefix();
225             Prefixes prefixInfo = getFibUtil().getPrefixToInterface(vpnId, prefix);
226             String interfaceName = prefixInfo.getVpnInterfaceName();
227             if (RouteOrigin.BGP.getValue().equals(vrfEntry.getOrigin()) || isNatPrefix) {
228                 tunnelId = BigInteger.valueOf(vrfEntry.getL3vni());
229             } else if (FibUtil.isVxlanNetwork(prefixInfo.getNetworkType())) {
230                 tunnelId = BigInteger.valueOf(prefixInfo.getSegmentationId());
231             } else {
232                 try {
233                     StateTunnelList stateTunnelList = getFibUtil().getTunnelState(interfaceName);
234                     if (stateTunnelList == null || stateTunnelList.getOperState() != TunnelOperStatus.Up) {
235                         LOG.trace("Tunnel is not up for interface {}", interfaceName);
236                         return;
237                     }
238                     tunnelId = BigInteger.valueOf(stateTunnelList.getIfIndex());
239                 } catch (ReadFailedException e) {
240                     LOG.error("createRemoteFibEntry: error in fetching tunnel state for interface {}",
241                             interfaceName, e);
242                     continue;
243                 }
244             }
245             LOG.debug("adding set tunnel id action for label {}", tunnelId);
246             String macAddress = null;
247             String vpnName = getFibUtil().getVpnNameFromId(vpnId);
248             if (vpnName == null) {
249                 LOG.debug("Failed to get VPN name for vpnId {}", vpnId);
250                 return;
251             }
252             if (interfaceName != null) {
253                 macAddress = getFibUtil().getMacAddressFromPrefix(interfaceName, vpnName, prefix);
254                 actionInfos.add(new ActionSetFieldEthernetDestination(new MacAddress(macAddress)));
255             }
256             actionInfos.add(new ActionSetFieldTunnelId(tunnelId));
257             List<ActionInfo> egressActions =
258                     nexthopManager.getEgressActionsForInterface(adjacencyResult.getInterfaceName(), actionInfos.size(),
259                             true);
260             if (egressActions.isEmpty()) {
261                 LOG.error("Failed to retrieve egress action for prefix {} route-paths {} interface {}."
262                         + " Aborting remote FIB entry creation..", vrfEntry.getDestPrefix(),
263                         vrfEntry.getRoutePaths(), adjacencyResult.getInterfaceName());
264                 return;
265             }
266             actionInfos.addAll(egressActions);
267             List<InstructionInfo> instructions = new ArrayList<>();
268             instructions.add(new InstructionApplyActions(actionInfos));
269             makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW, tx, subTxns);
270         }
271         LOG.debug("Successfully added FIB entry for prefix {} in rd {}", vrfEntry.getDestPrefix(), rd);
272     }
273
274     private void deleteRemoteEvpnFlows(String rd, VrfEntry vrfEntry, VpnInstanceOpDataEntry vpnInstance,
275                                        VrfTablesKey vrfTableKey, List<BigInteger> localDpnIdList) {
276         List<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
277         List<SubTransaction> subTxns =  new ArrayList<>();
278         if (vpnToDpnList != null) {
279             jobCoordinator.enqueueJob("FIB" + rd + vrfEntry.getDestPrefix(),
280                 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
281                     final Optional<Routes> extraRouteOptional = Optional.absent();
282                     if (localDpnIdList.size() <= 0) {
283                         for (VpnToDpnList curDpn1 : vpnToDpnList) {
284                             if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
285                                 if (curDpn1.getDpnState() == VpnToDpnList.DpnState.Active) {
286                                     bgpRouteVrfEntryHandler.deleteRemoteRoute(BigInteger.ZERO, curDpn1.getDpnId(),
287                                             vpnInstance.getVpnId(), vrfTableKey, vrfEntry,
288                                             extraRouteOptional, tx, subTxns);
289                                 }
290                             } else {
291                                 deleteRemoteRoute(BigInteger.ZERO, curDpn1.getDpnId(),
292                                         vpnInstance.getVpnId(), vrfTableKey, vrfEntry,
293                                         extraRouteOptional, tx);
294                             }
295                         }
296                     } else {
297                         for (BigInteger localDpnId : localDpnIdList) {
298                             for (VpnToDpnList curDpn2 : vpnToDpnList) {
299                                 if (!Objects.equals(curDpn2.getDpnId(), localDpnId)) {
300                                     if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
301                                         if (curDpn2.getDpnState() == VpnToDpnList.DpnState.Active) {
302                                             bgpRouteVrfEntryHandler.deleteRemoteRoute(localDpnId, curDpn2.getDpnId(),
303                                                     vpnInstance.getVpnId(), vrfTableKey, vrfEntry,
304                                                     extraRouteOptional, tx, subTxns);
305                                         }
306                                     } else {
307                                         deleteRemoteRoute(localDpnId, curDpn2.getDpnId(),
308                                                 vpnInstance.getVpnId(), vrfTableKey, vrfEntry,
309                                                 extraRouteOptional, tx);
310                                     }
311                                 }
312                             }
313                         }
314                     }
315                 })));
316         }
317     }
318
319     private List<BigInteger> checkDeleteLocalEvpnFLows(long vpnId, String rd, VrfEntry vrfEntry,
320                                                        VpnNexthop localNextHopInfo) {
321         List<BigInteger> returnLocalDpnId = new ArrayList<>();
322         if (localNextHopInfo == null) {
323             //Handle extra routes and imported routes
324         } else {
325             final BigInteger dpnId = localNextHopInfo.getDpnId();
326             jobCoordinator.enqueueJob("FIB-" + rd + "-" + vrfEntry.getDestPrefix(),
327                 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(
328                     tx -> makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW, tx,
329                             null))));
330             //TODO: verify below adjacency call need to be optimized (?)
331             deleteLocalAdjacency(dpnId, vpnId, vrfEntry.getDestPrefix(), vrfEntry.getDestPrefix());
332             returnLocalDpnId.add(dpnId);
333         }
334         return returnLocalDpnId;
335     }
336 }