2 * Copyright (c) 2015 - 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.vpnservice.fibmanager;
10 import com.google.common.base.Optional;
11 import com.google.common.base.Preconditions;
12 import com.google.common.util.concurrent.FutureCallback;
13 import com.google.common.util.concurrent.Futures;
15 import java.math.BigInteger;
16 import java.net.InetAddress;
17 import java.net.UnknownHostException;
18 import java.util.ArrayList;
19 import java.util.Collection;
20 import java.util.List;
21 import java.util.concurrent.ExecutionException;
22 import java.util.concurrent.Future;
24 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
25 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
26 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
27 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
28 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
29 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
30 import org.opendaylight.vpnmanager.api.IVpnManager;
31 import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
32 import org.opendaylight.vpnservice.itm.globals.ITMConstants;
33 import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
34 import org.opendaylight.vpnservice.mdsalutil.ActionType;
35 import org.opendaylight.vpnservice.mdsalutil.FlowEntity;
36 import org.opendaylight.vpnservice.mdsalutil.InstructionInfo;
37 import org.opendaylight.vpnservice.mdsalutil.InstructionType;
38 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
39 import org.opendaylight.vpnservice.mdsalutil.MatchFieldType;
40 import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
41 import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
42 import org.opendaylight.vpnservice.mdsalutil.NwConstants;
43 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.PrefixToInterface;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstanceOpData;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnToExtraroute;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.VpnIds;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.VpnIdsKey;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.vpn.ids.PrefixesKey;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.Vpn;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.VpnKey;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.vpn.Extraroute;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.vpn.ExtrarouteBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.vpn.ExtrarouteKey;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.FibEntries;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTables;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTablesKey;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.vrfentries.VrfEntry;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeBase;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeMplsOverGre;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceInputBuilder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceOutput;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetTunnelTypeInputBuilder;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetTunnelTypeOutput;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthop;
73 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.Adjacencies;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.Adjacency;
76 import org.opendaylight.yangtools.concepts.ListenerRegistration;
77 import org.opendaylight.yangtools.yang.binding.DataObject;
78 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
79 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
80 import org.opendaylight.yangtools.yang.common.RpcResult;
81 import org.slf4j.Logger;
82 import org.slf4j.LoggerFactory;
84 public class FibManager extends AbstractDataChangeListener<VrfEntry> implements AutoCloseable{
85 private static final Logger LOG = LoggerFactory.getLogger(FibManager.class);
86 private static final String FLOWID_PREFIX = "L3.";
87 private ListenerRegistration<DataChangeListener> listenerRegistration;
88 private final DataBroker broker;
89 private IMdsalApiManager mdsalManager;
90 private IVpnManager vpnmanager;
91 private NexthopManager nextHopManager;
92 private ItmRpcService itmManager;
93 private OdlInterfaceRpcService interfaceManager;
94 private static final BigInteger COOKIE_VM_LFIB_TABLE = new BigInteger("8000002", 16);
95 private static final BigInteger COOKIE_VM_FIB_TABLE = new BigInteger("8000003", 16);
96 private static final int DEFAULT_FIB_FLOW_PRIORITY = 10;
97 private static final BigInteger METADATA_MASK_CLEAR = new BigInteger("000000FFFFFFFFFF", 16);
98 private static final BigInteger CLEAR_METADATA = BigInteger.valueOf(0);
99 public static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
102 public FibManager(final DataBroker db) {
103 super(VrfEntry.class);
105 registerListener(db);
109 public void close() throws Exception {
110 if (listenerRegistration != null) {
112 listenerRegistration.close();
113 } catch (final Exception e) {
114 LOG.error("Error when cleaning up DataChangeListener.", e);
116 listenerRegistration = null;
118 LOG.info("Fib Manager Closed");
121 public void setNextHopManager(NexthopManager nextHopManager) {
122 this.nextHopManager = nextHopManager;
125 public void setMdsalManager(IMdsalApiManager mdsalManager) {
126 this.mdsalManager = mdsalManager;
129 public void setVpnmanager(IVpnManager vpnmanager) {
130 this.vpnmanager = vpnmanager;
133 public void setITMRpcService(ItmRpcService itmManager) {
134 this.itmManager = itmManager;
137 public void setInterfaceManager(OdlInterfaceRpcService ifManager) {
138 this.interfaceManager = ifManager;
141 private void registerListener(final DataBroker db) {
143 listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
144 getWildCardPath(), FibManager.this, DataChangeScope.SUBTREE);
145 } catch (final Exception e) {
146 LOG.error("FibManager DataChange listener registration fail!", e);
147 throw new IllegalStateException("FibManager registration Listener failed.", e);
152 private InstanceIdentifier<VrfEntry> getWildCardPath() {
153 return InstanceIdentifier.create(FibEntries.class).child(VrfTables.class).child(VrfEntry.class);
158 protected void add(final InstanceIdentifier<VrfEntry> identifier,
159 final VrfEntry vrfEntry) {
160 LOG.trace("key: " + identifier + ", value=" + vrfEntry );
161 createFibEntries(identifier, vrfEntry);
165 protected void remove(InstanceIdentifier<VrfEntry> identifier, VrfEntry vrfEntry) {
166 LOG.trace("key: " + identifier + ", value=" + vrfEntry);
167 deleteFibEntries(identifier, vrfEntry);
171 protected void update(InstanceIdentifier<VrfEntry> identifier, VrfEntry original, VrfEntry update) {
172 LOG.trace("key: " + identifier + ", original=" + original + ", update=" + update );
173 createFibEntries(identifier, update);
176 private void createFibEntries(final InstanceIdentifier<VrfEntry> identifier,
177 final VrfEntry vrfEntry) {
178 final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class, VrfTablesKey.class);
179 Preconditions.checkNotNull(vrfTableKey, "VrfTablesKey cannot be null or empty!");
180 Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!");
182 VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
183 Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available!");
184 Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId() + "has null vpnId!");
186 Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
187 BigInteger localDpnId = createLocalFibEntry(vpnInstance.getVpnId(),
188 vrfTableKey.getRouteDistinguisher(), vrfEntry);
189 if (vpnToDpnList != null) {
190 for (VpnToDpnList curDpn : vpnToDpnList) {
191 if (!curDpn.getDpnId().equals(localDpnId)) {
192 createRemoteFibEntry(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(),
193 vrfTableKey, vrfEntry);
199 public BigInteger createLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
200 BigInteger localDpnId = BigInteger.ZERO;
201 Prefixes localNextHopInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
202 String localNextHopIP = vrfEntry.getDestPrefix();
204 if(localNextHopInfo == null) {
205 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
206 Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
207 if (extra_route != null) {
208 localNextHopInfo = getPrefixToInterface(vpnId, extra_route.getNexthopIp() + "/32");
209 localNextHopIP = extra_route.getNexthopIp() + "/32";
213 if(localNextHopInfo != null) {
214 localDpnId = localNextHopInfo.getDpnId();
215 long groupId = nextHopManager.createLocalNextHop(vpnId, localDpnId, localNextHopInfo.getVpnInterfaceName(), localNextHopIP);
216 List<ActionInfo> actionInfos = new ArrayList<ActionInfo>();
218 actionInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId)}));
220 makeConnectedRoute(localDpnId, vpnId, vrfEntry, rd, actionInfos, NwConstants.ADD_FLOW);
221 makeLFibTableEntry(localDpnId, vrfEntry.getLabel(), groupId, vrfEntry.getNextHopAddress(), NwConstants.ADD_FLOW);
223 LOG.debug("Installing tunnel table entry on dpn {} for interface {} with label {}",
224 localDpnId, localNextHopInfo.getVpnInterfaceName(), vrfEntry.getLabel());
225 makeTunnelTableEntry(localDpnId, vrfEntry.getLabel(), groupId);
231 private void makeTunnelTableEntry(BigInteger dpId, long label, long groupId/*String egressInterfaceName*/) {
232 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
233 actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }));
236 createTerminatingServiceActions(dpId, (int)label, actionsInfos);
238 LOG.debug("Terminating service Entry for dpID {} : label : {} egress : {} installed successfully {}",
239 dpId, label, groupId);
242 public void createTerminatingServiceActions( BigInteger destDpId, int label, List<ActionInfo> actionsInfos) {
243 List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
245 LOG.info("create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}", destDpId , label,actionsInfos);
248 // FIXME vxlan vni bit set is not working properly with OVS.need to revisit
249 mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(label)}));
251 List<InstructionInfo> mkInstructions = new ArrayList<InstructionInfo>();
252 mkInstructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
254 FlowEntity terminatingServiceTableFlowEntity = MDSALUtil.buildFlowEntity(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,
255 getFlowRef(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,label), 5, String.format("%s:%d","TST Flow Entry ",label),
256 0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(label)),mkMatches, mkInstructions);
258 mdsalManager.installFlow(terminatingServiceTableFlowEntity);
261 private void removeTunnelTableEntry(BigInteger dpId, long label) {
262 FlowEntity flowEntity;
263 LOG.info("remove terminatingServiceActions called with DpnId = {} and label = {}", dpId , label);
264 List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
266 mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(label)}));
267 flowEntity = MDSALUtil.buildFlowEntity(dpId,
268 NwConstants.INTERNAL_TUNNEL_TABLE,
269 getFlowRef(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, (int)label),
270 5, String.format("%s:%d","TST Flow Entry ",label), 0, 0,
271 COOKIE_TUNNEL.add(BigInteger.valueOf(label)), mkMatches, null);
272 mdsalManager.removeFlow(flowEntity);
273 LOG.debug("Terminating service Entry for dpID {} : label : {} removed successfully {}",dpId, label);
276 public BigInteger deleteLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
277 BigInteger localDpnId = BigInteger.ZERO;
278 VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
279 String localNextHopIP = vrfEntry.getDestPrefix();
281 if(localNextHopInfo == null) {
282 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
283 Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
284 if (extra_route != null) {
285 localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, extra_route.getNexthopIp());
286 localNextHopIP = extra_route.getNexthopIp() + "/32";
291 if(localNextHopInfo != null) {
292 localDpnId = localNextHopInfo.getDpnId();
293 //if (getPrefixToInterface(vpnId, (staticRoute == true) ? extra_route.getNextHopAddress() + "/32" : vrfEntry.getDestPrefix()) == null)
295 makeConnectedRoute(localDpnId, vpnId, vrfEntry, rd, null /* invalid */,
296 NwConstants.DEL_FLOW);
297 makeLFibTableEntry(localDpnId, vrfEntry.getLabel(), 0 /* invalid */,
298 vrfEntry.getNextHopAddress(), NwConstants.DEL_FLOW);
299 removeTunnelTableEntry(localDpnId, vrfEntry.getLabel());
300 deleteLocalAdjacency(localDpnId, vpnId, localNextHopIP);
306 private InstanceIdentifier<Prefixes> getPrefixToInterfaceIdentifier(Long vpnId, String ipPrefix) {
307 return InstanceIdentifier.builder(PrefixToInterface.class)
308 .child(VpnIds.class, new VpnIdsKey(vpnId)).child(Prefixes.class, new PrefixesKey(ipPrefix)).build();
311 private Prefixes getPrefixToInterface(Long vpnId, String ipPrefix) {
312 Optional<Prefixes> localNextHopInfoData =
313 FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, getPrefixToInterfaceIdentifier(vpnId, ipPrefix));
314 return localNextHopInfoData.isPresent() ? localNextHopInfoData.get() : null;
317 private InstanceIdentifier<Extraroute> getVpnToExtrarouteIdentifier(String vrfId, String ipPrefix) {
318 return InstanceIdentifier.builder(VpnToExtraroute.class)
319 .child(Vpn.class, new VpnKey(vrfId)).child(Extraroute.class,
320 new ExtrarouteKey(ipPrefix)).build();
323 private Extraroute getVpnToExtraroute(String rd, String ipPrefix) {
324 Optional<Extraroute> extraRouteInfo =
325 FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, getVpnToExtrarouteIdentifier(rd, ipPrefix));
326 return extraRouteInfo.isPresent() ? extraRouteInfo.get() : null;
330 private Class<? extends TunnelTypeBase> getTunnelType(String ifName) {
332 Future<RpcResult<GetTunnelTypeOutput>> result = interfaceManager.getTunnelType(
333 new GetTunnelTypeInputBuilder().setIntfName(ifName).build());
334 RpcResult<GetTunnelTypeOutput> rpcResult = result.get();
335 if(!rpcResult.isSuccessful()) {
336 LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
338 return rpcResult.getResult().getTunnelType();
341 } catch (InterruptedException | ExecutionException e) {
342 LOG.warn("Exception when getting tunnel interface Id for tunnel type {}", e);
348 private void createRemoteFibEntry(final BigInteger localDpnId, final BigInteger remoteDpnId,
349 final long vpnId, final VrfTablesKey vrfTableKey,
350 final VrfEntry vrfEntry) {
351 String rd = vrfTableKey.getRouteDistinguisher();
352 LOG.debug("adding route " + vrfEntry.getDestPrefix() + " " + rd);
353 /********************************************/
354 String tunnelInterface = resolveAdjacency(localDpnId, remoteDpnId, vpnId, vrfEntry, rd);
355 if(tunnelInterface == null) {
356 LOG.error("Could not get interface for nexthop: {} in vpn {}",
357 vrfEntry.getNextHopAddress(), rd);
358 LOG.warn("Failed to add Route: {} in vpn: {}",
359 vrfEntry.getDestPrefix(), rd);
362 List<ActionInfo> actionInfos = new ArrayList<>();
363 Class<? extends TunnelTypeBase> tunnel_type = getTunnelType(tunnelInterface);
364 if (tunnel_type.equals(TunnelTypeMplsOverGre.class)) {
365 LOG.debug("Push label action for prefix {}", vrfEntry.getDestPrefix());
366 actionInfos.add(new ActionInfo(ActionType.push_mpls, new String[] { null }));
367 actionInfos.add(new ActionInfo(ActionType.set_field_mpls_label, new String[] { Long.toString(vrfEntry.getLabel())}));
369 int label = vrfEntry.getLabel().intValue();
371 // FIXME vxlan vni bit set is not working properly with OVS.need to revisit
372 if(tunnel_type.equals(TunnelTypeVxlan.class)) {
373 tunnelId = BigInteger.valueOf(label);
375 tunnelId = BigInteger.valueOf(label);
377 LOG.debug("adding set tunnel id action for label {}", label);
378 actionInfos.add(new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[]{
381 actionInfos.addAll(nextHopManager.getEgressActionsForInterface(tunnelInterface));
383 List<ActionInfo> actionInfos = resolveAdjacency(localDpnId, remoteDpnId, vpnId, vrfEntry);
384 if(actionInfos == null) {
385 LOG.error("Could not get nexthop group id for nexthop: {} in vpn {}",
386 vrfEntry.getNextHopAddress(), rd);
387 LOG.warn("Failed to add Route: {} in vpn: {}",
388 vrfEntry.getDestPrefix(), rd);
391 BigInteger dpnId = nextHopManager.getDpnForPrefix(vpnId, vrfEntry.getDestPrefix());
393 //This route may be extra route... try to query with nexthop Ip
394 LOG.debug("Checking for extra route to install remote fib entry {}", vrfEntry.getDestPrefix());
395 dpnId = nextHopManager.getDpnForPrefix(vpnId, vrfEntry.getNextHopAddress() + "/32");
398 LOG.debug("Push label action for prefix {}", vrfEntry.getDestPrefix());
399 actionInfos.add(new ActionInfo(ActionType.push_mpls, new String[] { null }));
400 actionInfos.add(new ActionInfo(ActionType.set_field_mpls_label, new String[] { Long.toString(vrfEntry.getLabel())}));
402 int label = vrfEntry.getLabel().intValue();
403 LOG.debug("adding set tunnel id action for label {}", label);
404 actionInfos.add(new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] {
405 MetaDataUtil.getTunnelIdWithValidVniBitAndVniSet(label),
406 MetaDataUtil.METADA_MASK_VALID_TUNNEL_ID_BIT_AND_TUNNEL_ID }));
409 makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, actionInfos, NwConstants.ADD_FLOW);
411 "Successfully added fib entry for " + vrfEntry.getDestPrefix() + " vpnId " + vpnId);
414 private void delIntfFromDpnToVpnList(long vpnId, BigInteger dpnId, String intfName, String rd) {
415 InstanceIdentifier<VpnToDpnList> id = FibUtil.getVpnToDpnListIdentifier(rd, dpnId);
416 Optional<VpnToDpnList> dpnInVpn = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
417 if (dpnInVpn.isPresent()) {
418 List<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
419 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces> vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
420 org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces
421 currVpnInterface = new org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesBuilder().setInterfaceName(intfName).build();
423 if (vpnInterfaces.remove(currVpnInterface)) {
424 if (vpnInterfaces.isEmpty()) {
425 //FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id);
426 cleanUpDpnForVpn(dpnId, vpnId, rd);
428 FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id.child(
429 org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
430 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces.class,
431 new org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesKey(intfName)));
437 private void cleanUpOpDataForFib(Long vpnId, String rd, final VrfEntry vrfEntry) {
438 /* Get interface info from prefix to interface mapping;
439 Use the interface info to get the corresponding vpn interface op DS entry,
440 remove the adjacency corresponding to this fib entry.
441 If adjacency removed is the last adjacency, clean up the following:
442 - vpn interface from dpntovpn list, dpn if last vpn interface on dpn
443 - prefix to interface entry
444 - vpn interface op DS
446 Prefixes prefixInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
447 boolean extra_route = false;
448 if (prefixInfo == null) {
449 prefixInfo = getPrefixToInterface(vpnId, vrfEntry.getNextHopAddress() + "/32");
452 if (prefixInfo == null)
453 return; //Don't have any info for this prefix (shouldn't happen); need to return
454 String ifName = prefixInfo.getVpnInterfaceName();
455 Optional<Adjacencies> optAdjacencies = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, FibUtil.getAdjListPath(ifName));
457 if (optAdjacencies.isPresent()) {
458 numAdj = optAdjacencies.get().getAdjacency().size();
460 //remove adjacency corr to prefix
461 FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, FibUtil.getAdjacencyIdentifier(ifName, vrfEntry.getDestPrefix()));
463 if((numAdj - 1) == 0) { //there are no adjacencies left for this vpn interface, clean up
464 //clean up the vpn interface from DpnToVpn list
465 delIntfFromDpnToVpnList(vpnId, prefixInfo.getDpnId(), ifName, rd);
466 FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
467 FibUtil.getPrefixToInterfaceIdentifier(
469 (extra_route) ? vrfEntry.getNextHopAddress() + "/32" : vrfEntry.getDestPrefix()));
470 FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
471 FibUtil.getVpnInterfaceIdentifier(ifName));
475 private void deleteFibEntries(final InstanceIdentifier<VrfEntry> identifier,
476 final VrfEntry vrfEntry) {
477 final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class, VrfTablesKey.class);
478 Preconditions.checkNotNull(vrfTableKey, "VrfTablesKey cannot be null or empty!");
479 Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!");
481 VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
482 Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available!");
483 Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
484 BigInteger localDpnId = deleteLocalFibEntry(vpnInstance.getVpnId(),
485 vrfTableKey.getRouteDistinguisher(), vrfEntry);
486 if (vpnToDpnList != null) {
487 for (VpnToDpnList curDpn : vpnToDpnList) {
488 if (!curDpn.getDpnId().equals(localDpnId)) {
489 deleteRemoteRoute(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry);
493 //The flow/group entry has been deleted from config DS; need to clean up associated operational
494 //DS entries in VPN Op DS, VpnInstanceOpData and PrefixToInterface to complete deletion
495 cleanUpOpDataForFib(vpnInstance.getVpnId(), vrfTableKey.getRouteDistinguisher(), vrfEntry);
498 public void deleteRemoteRoute(final BigInteger localDpnId, final BigInteger remoteDpnId,
499 final long vpnId, final VrfTablesKey vrfTableKey,
500 final VrfEntry vrfEntry) {
501 LOG.debug("deleting route "+ vrfEntry.getDestPrefix() + " "+vpnId);
502 String rd = vrfTableKey.getRouteDistinguisher();
503 String egressInterface = resolveAdjacency(localDpnId, remoteDpnId, vpnId, vrfEntry, rd);
504 if(egressInterface == null) {
505 LOG.error("Could not get nexthop group id for nexthop: {} in vpn {}",
506 vrfEntry.getNextHopAddress(), rd);
507 LOG.warn("Failed to delete Route: {} in vpn: {}",
508 vrfEntry.getDestPrefix(), rd);
512 makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW);
513 LOG.debug("Successfully delete fib entry for "+ vrfEntry.getDestPrefix() + " vpnId "+vpnId);
516 private long getIpAddress(byte[] rawIpAddress) {
517 return (((rawIpAddress[0] & 0xFF) << (3 * 8)) + ((rawIpAddress[1] & 0xFF) << (2 * 8))
518 + ((rawIpAddress[2] & 0xFF) << (1 * 8)) + (rawIpAddress[3] & 0xFF)) & 0xffffffffL;
521 private void makeConnectedRoute(BigInteger dpId, long vpnId, VrfEntry vrfEntry, String rd,
522 List<ActionInfo> actionInfos, int addOrRemove) {
523 LOG.trace("makeConnectedRoute: vrfEntry {}",vrfEntry);
524 String values[] = vrfEntry.getDestPrefix().split("/");
525 String ipAddress = values[0];
526 int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]);
527 LOG.debug("Adding route to DPN. ip {} masklen {}", ipAddress, prefixLength);
528 InetAddress destPrefix = null;
530 destPrefix = InetAddress.getByName(ipAddress);
531 } catch (UnknownHostException e) {
532 LOG.error("UnknowHostException in addRoute. Failed to add Route for ipPrefix {}", vrfEntry.getDestPrefix());
536 List<MatchInfo> matches = new ArrayList<MatchInfo>();
538 matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
539 BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
541 matches.add(new MatchInfo(MatchFieldType.eth_type,
542 new long[] { 0x0800L }));
544 if(prefixLength != 0) {
545 matches.add(new MatchInfo(MatchFieldType.ipv4_dst, new long[] {
546 getIpAddress(destPrefix.getAddress()), prefixLength }));
549 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
550 if(addOrRemove == NwConstants.ADD_FLOW) {
551 instructions.add(new InstructionInfo(InstructionType.write_actions, actionInfos));
554 String flowRef = getFlowRef(dpId, NwConstants.L3_FIB_TABLE, rd, destPrefix);
556 FlowEntity flowEntity;
558 int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
559 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_FIB_TABLE, flowRef,
560 priority, flowRef, 0, 0,
561 COOKIE_VM_FIB_TABLE, matches, instructions);
563 if (addOrRemove == NwConstants.ADD_FLOW) {
564 /* We need to call sync API to install flow so that 2 DS operations on the same object do not
565 * happen at same time. However, MDSALManager's syncInstallFlow takes a delay time (or uses a default one) to wait
566 * for or for notification that operational DS write for flows is done. We do not turn on the stats writing for flows,
567 * so that notification never comes, so we do not need that wait. Sending the lowest value of wait "1 ms" since 0 wait means
568 * wait indefinitely. */
569 mdsalManager.syncInstallFlow(flowEntity, 1);
571 mdsalManager.syncRemoveFlow(flowEntity, 1);
575 private void makeLFibTableEntry(BigInteger dpId, long label, long groupId,
576 String nextHop, int addOrRemove) {
577 List<MatchInfo> matches = new ArrayList<MatchInfo>();
578 matches.add(new MatchInfo(MatchFieldType.eth_type,
579 new long[] { 0x8847L }));
580 matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(label)}));
582 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
583 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
584 actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{}));
585 actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }));
586 instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
588 // Install the flow entry in L3_LFIB_TABLE
589 String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, label, nextHop);
591 FlowEntity flowEntity;
592 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_LFIB_TABLE, flowRef,
593 DEFAULT_FIB_FLOW_PRIORITY, flowRef, 0, 0,
594 COOKIE_VM_LFIB_TABLE, matches, instructions);
596 if (addOrRemove == NwConstants.ADD_FLOW) {
597 /* We need to call sync API to install flow so that 2 DS operations on the same object do not
598 * happen at same time. However, MDSALManager's syncInstallFlow takes a delay time (or uses a default one) to wait
599 * for or for notification that operational DS write for flows is done. We do not turn on the stats writing for flows,
600 * so that notification never comes, so we do not need that wait. Sending the lowest value of wait "1 ms" since 0 wait means
601 * wait indefinitely. */
603 mdsalManager.syncInstallFlow(flowEntity, 1);
605 mdsalManager.syncRemoveFlow(flowEntity, 1);
607 LOG.debug("LFIB Entry for dpID {} : label : {} group {} modified successfully {}",dpId, label, groupId );
610 private void deleteLocalAdjacency(final BigInteger dpId, final long vpnId, final String ipAddress) {
611 LOG.trace("deleteLocalAdjacency called with dpid {}, vpnId{}, ipAddress {}",dpId, vpnId, ipAddress);
613 nextHopManager.removeLocalNextHop(dpId, vpnId, ipAddress);
614 } catch (NullPointerException e) {
619 public void populateFibOnNewDpn(BigInteger dpnId, long vpnId, String rd) {
620 LOG.trace("New dpn {} for vpn {} : populateFibOnNewDpn", dpnId, rd);
621 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
622 Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
623 if(vrfTable.isPresent()) {
624 for(VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
625 // Passing null as we don't know the dpn
626 // to which prefix is attached at this point
627 createRemoteFibEntry(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
632 public void cleanUpDpnForVpn(BigInteger dpnId, long vpnId, String rd) {
633 LOG.trace("Remove dpn {} for vpn {} : cleanUpDpnForVpn", dpnId, rd);
634 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
635 Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
636 if(vrfTable.isPresent()) {
637 for(VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
638 // Passing null as we don't know the dpn
639 // to which prefix is attached at this point
640 deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
645 public static InstanceIdentifier<VrfTables> buildVrfId(String rd) {
646 InstanceIdentifierBuilder<VrfTables> idBuilder =
647 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
648 InstanceIdentifier<VrfTables> id = idBuilder.build();
652 private String getFlowRef(BigInteger dpnId, short tableId, long label, String nextHop) {
653 return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
654 .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
655 .append(label).append(NwConstants.FLOWID_SEPARATOR)
656 .append(nextHop).toString();
659 private String getFlowRef(BigInteger dpnId, short tableId, String rd, InetAddress destPrefix) {
660 return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
661 .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
662 .append(rd).append(NwConstants.FLOWID_SEPARATOR)
663 .append(destPrefix.getHostAddress()).toString();
666 protected String resolveAdjacency(final BigInteger localDpnId, final BigInteger remoteDpnId,
667 final long vpnId, final VrfEntry vrfEntry, String rd) {
668 String adjacency = null;
669 boolean staticRoute = false;
670 LOG.trace("resolveAdjacency called with localdpid{} remotedpid {}, vpnId{}, VrfEntry {}", localDpnId, remoteDpnId, vpnId, vrfEntry);
672 Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
673 if(extra_route != null) {
678 nextHopManager.getRemoteNextHopPointer(localDpnId, remoteDpnId, vpnId,
679 vrfEntry.getDestPrefix(),
680 (staticRoute == true) ? extra_route.getNexthopIp() : vrfEntry.getNextHopAddress());
681 } catch (NullPointerException e) {
687 protected VpnInstanceOpDataEntry getVpnInstance(String rd) {
688 InstanceIdentifier<VpnInstanceOpDataEntry> id = InstanceIdentifier.create(VpnInstanceOpData.class).child(
689 VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd));
690 Optional<VpnInstanceOpDataEntry> vpnInstanceOpData = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
691 if(vpnInstanceOpData.isPresent()) {
692 return vpnInstanceOpData.get();
697 public void processNodeAdd(BigInteger dpnId) {
698 LOG.debug("Received notification to install TableMiss entries for dpn {} ", dpnId);
699 makeTableMissFlow(dpnId, NwConstants.ADD_FLOW);
700 makeL3IntfTblMissFlow(dpnId, NwConstants.ADD_FLOW);
703 private void makeTableMissFlow(BigInteger dpnId, int addOrRemove) {
704 final BigInteger COOKIE_TABLE_MISS = new BigInteger("1030000", 16);
705 // Instruction to goto L3 InterfaceTable
706 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
707 instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_INTERFACE_TABLE }));
708 List<MatchInfo> matches = new ArrayList<MatchInfo>();
709 FlowEntity flowEntityLfib = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_LFIB_TABLE,
710 getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, NwConstants.TABLE_MISS_FLOW),
711 NwConstants.TABLE_MISS_PRIORITY, "Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions);
713 FlowEntity flowEntityFib = MDSALUtil.buildFlowEntity(dpnId,NwConstants.L3_FIB_TABLE, getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, NwConstants.TABLE_MISS_FLOW),
714 NwConstants.TABLE_MISS_PRIORITY, "FIB Table Miss Flow", 0, 0, COOKIE_VM_FIB_TABLE,
715 matches, instructions);
717 if (addOrRemove == NwConstants.ADD_FLOW) {
718 LOG.debug("Invoking MDSAL to install Table Miss Entries");
719 mdsalManager.installFlow(flowEntityLfib);
720 mdsalManager.installFlow(flowEntityFib);
722 mdsalManager.removeFlow(flowEntityLfib);
723 mdsalManager.removeFlow(flowEntityFib);
728 private String getFlowRef(BigInteger dpnId, short tableId, int tableMiss) {
729 return new StringBuffer().append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
730 .append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(tableMiss)
731 .append(FLOWID_PREFIX).toString();
735 * Install flow entry in protocol table to forward mpls
736 * coming through gre tunnel to LFIB table.
738 private void makeProtocolTableFlow(BigInteger dpnId, int addOrRemove) {
739 final BigInteger COOKIE_PROTOCOL_TABLE = new BigInteger("1070000", 16);
740 // Instruction to goto L3 InterfaceTable
741 List<InstructionInfo> instructions = new ArrayList<>();
742 instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] {NwConstants.L3_LFIB_TABLE}));
743 List<MatchInfo> matches = new ArrayList<MatchInfo>();
744 matches.add(new MatchInfo(MatchFieldType.eth_type,
745 new long[] { 0x8847L }));
746 FlowEntity flowEntityToLfib = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_PROTOCOL_TABLE,
747 getFlowRef(dpnId, NwConstants.L3_PROTOCOL_TABLE,
748 NwConstants.L3_LFIB_TABLE),
749 DEFAULT_FIB_FLOW_PRIORITY,
750 "Protocol Table For LFIB",
752 COOKIE_PROTOCOL_TABLE,
753 matches, instructions);
755 if (addOrRemove == NwConstants.ADD_FLOW) {
756 LOG.debug("Invoking MDSAL to install Protocol Entries for dpn {}", dpnId);
757 mdsalManager.installFlow(flowEntityToLfib);
759 mdsalManager.removeFlow(flowEntityToLfib);
763 public List<String> printFibEntries() {
764 List<String> result = new ArrayList<String>();
765 result.add(String.format(" %-7s %-20s %-20s %-7s", "RD", "Prefix", "Nexthop", "Label"));
766 result.add("-------------------------------------------------------------------");
767 InstanceIdentifier<FibEntries> id = InstanceIdentifier.create(FibEntries.class);
768 Optional<FibEntries> fibEntries = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
769 if (fibEntries.isPresent()) {
770 List<VrfTables> vrfTables = fibEntries.get().getVrfTables();
771 for (VrfTables vrfTable : vrfTables) {
772 for (VrfEntry vrfEntry : vrfTable.getVrfEntry()) {
773 result.add(String.format(" %-7s %-20s %-20s %-7s", vrfTable.getRouteDistinguisher(),
774 vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddress(), vrfEntry.getLabel()));
781 private void makeL3IntfTblMissFlow(BigInteger dpnId, int addOrRemove) {
782 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
783 List<MatchInfo> matches = new ArrayList<MatchInfo>();
784 final BigInteger COOKIE_TABLE_MISS = new BigInteger("1030000", 16);
785 // Instruction to clear metadata except SI and LportTag bits
786 instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] {
787 CLEAR_METADATA, METADATA_MASK_CLEAR }));
788 // Instruction to clear action
789 instructions.add(new InstructionInfo(InstructionType.clear_actions));
790 // Instruction to goto L3 InterfaceTable
792 instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.LPORT_DISPATCHER_TABLE }));
794 FlowEntity flowEntityL3Intf = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_INTERFACE_TABLE,
795 getFlowRef(dpnId, NwConstants.L3_INTERFACE_TABLE, NwConstants.TABLE_MISS_FLOW),
796 NwConstants.TABLE_MISS_PRIORITY, "L3 Interface Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions);
797 if (addOrRemove == NwConstants.ADD_FLOW) {
798 LOG.info("Invoking MDSAL to install L3 interface Table Miss Entries");
799 mdsalManager.installFlow(flowEntityL3Intf);
801 mdsalManager.removeFlow(flowEntityL3Intf);