d3d584201d7d97fb3026d06c495143fbd5b03883
[vpnservice.git] / fibmanager / fibmanager-impl / src / main / java / org / opendaylight / vpnservice / fibmanager / FibManager.java
1 /*
2  * Copyright (c) 2015 - 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.vpnservice.fibmanager;
9
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;
14
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;
23
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.prefix.to._interface.VpnIds;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.VpnIdsKey;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.vpn.ids.PrefixesKey;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetTunnelInterfaceNameOutput;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.FibEntries;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTables;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTablesKey;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.vrfentries.VrfEntry;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeBase;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeMplsOverGre;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceInputBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceOutput;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetTunnelTypeInputBuilder;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetTunnelTypeOutput;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthop;
68 import org.opendaylight.yangtools.concepts.ListenerRegistration;
69 import org.opendaylight.yangtools.yang.binding.DataObject;
70 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
71 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
72 import org.opendaylight.yangtools.yang.common.RpcResult;
73 import org.slf4j.Logger;
74 import org.slf4j.LoggerFactory;
75
76 public class FibManager extends AbstractDataChangeListener<VrfEntry> implements AutoCloseable{
77   private static final Logger LOG = LoggerFactory.getLogger(FibManager.class);
78   private static final String FLOWID_PREFIX = "L3.";
79   private ListenerRegistration<DataChangeListener> listenerRegistration;
80   private final DataBroker broker;
81   private IMdsalApiManager mdsalManager;
82   private IVpnManager vpnmanager;
83   private NexthopManager nextHopManager;
84   private ItmRpcService itmManager;
85   private OdlInterfaceRpcService interfaceManager;
86
87   private static final short L3_FIB_TABLE = 21;
88   private static final short L3_LFIB_TABLE = 20;
89   private static final short L3_PROTOCOL_TABLE = 36;
90   private static final short L3_INTERFACE_TABLE = 80;
91   public static final short LPORT_DISPATCHER_TABLE = 30;
92   private static final BigInteger COOKIE_VM_LFIB_TABLE = new BigInteger("8000002", 16);
93   private static final BigInteger COOKIE_VM_FIB_TABLE =  new BigInteger("8000003", 16);
94   private static final int DEFAULT_FIB_FLOW_PRIORITY = 10;
95   private static final BigInteger METADATA_MASK_CLEAR = new BigInteger("000000FFFFFFFFFF", 16);
96   private static final BigInteger CLEAR_METADATA = BigInteger.valueOf(0);
97
98
99   private static final FutureCallback<Void> DEFAULT_CALLBACK =
100       new FutureCallback<Void>() {
101         public void onSuccess(Void result) {
102           LOG.debug("Success in Datastore write operation");
103         }
104
105         public void onFailure(Throwable error) {
106           LOG.error("Error in Datastore write operation", error);
107         };
108       };
109
110   public FibManager(final DataBroker db) {
111     super(VrfEntry.class);
112     broker = db;
113     registerListener(db);
114   }
115
116   @Override
117   public void close() throws Exception {
118     if (listenerRegistration != null) {
119       try {
120         listenerRegistration.close();
121       } catch (final Exception e) {
122         LOG.error("Error when cleaning up DataChangeListener.", e);
123       }
124       listenerRegistration = null;
125     }
126     LOG.info("Fib Manager Closed");
127   }
128
129   public void setNextHopManager(NexthopManager nextHopManager) {
130     this.nextHopManager = nextHopManager;
131   }
132
133   public void setMdsalManager(IMdsalApiManager mdsalManager) {
134     this.mdsalManager = mdsalManager;
135   }
136
137   public void setVpnmanager(IVpnManager vpnmanager) {
138     this.vpnmanager = vpnmanager;
139   }
140
141   public void setITMRpcService(ItmRpcService itmManager) {
142       this.itmManager = itmManager;
143   }
144   
145   public void setInterfaceManager(OdlInterfaceRpcService ifManager) {
146       this.interfaceManager = ifManager;
147   }
148
149   private void registerListener(final DataBroker db) {
150     try {
151       listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
152                                                            getWildCardPath(), FibManager.this, DataChangeScope.SUBTREE);
153     } catch (final Exception e) {
154       LOG.error("FibManager DataChange listener registration fail!", e);
155       throw new IllegalStateException("FibManager registration Listener failed.", e);
156     }
157   }
158
159   private <T extends DataObject> Optional<T> read(LogicalDatastoreType datastoreType,
160                                                   InstanceIdentifier<T> path) {
161
162     ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
163
164     Optional<T> result = Optional.absent();
165     try {
166       result = tx.read(datastoreType, path).get();
167     } catch (Exception e) {
168       throw new RuntimeException(e);
169     }
170
171     return result;
172   }
173
174   private InstanceIdentifier<VrfEntry> getWildCardPath() {
175     return InstanceIdentifier.create(FibEntries.class).child(VrfTables.class).child(VrfEntry.class);
176   }
177
178   private <T extends DataObject> void asyncWrite(LogicalDatastoreType datastoreType,
179                                                  InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
180     WriteTransaction tx = broker.newWriteOnlyTransaction();
181     tx.put(datastoreType, path, data, true);
182     Futures.addCallback(tx.submit(), callback);
183   }
184
185   @Override
186   protected void add(final InstanceIdentifier<VrfEntry> identifier,
187                      final VrfEntry vrfEntry) {
188     LOG.trace("key: " + identifier + ", value=" + vrfEntry );
189     createFibEntries(identifier, vrfEntry);
190   }
191
192   @Override
193   protected void remove(InstanceIdentifier<VrfEntry> identifier, VrfEntry vrfEntry) {
194     LOG.trace("key: " + identifier + ", value=" + vrfEntry);
195     deleteFibEntries(identifier, vrfEntry);
196   }
197
198   @Override
199   protected void update(InstanceIdentifier<VrfEntry> identifier, VrfEntry original, VrfEntry update) {
200     LOG.trace("key: " + identifier + ", original=" + original + ", update=" + update );
201     createFibEntries(identifier, update);
202   }
203
204   private void createFibEntries(final InstanceIdentifier<VrfEntry> identifier,
205                                 final VrfEntry vrfEntry) {
206     final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class, VrfTablesKey.class);
207     Preconditions.checkNotNull(vrfTableKey, "VrfTablesKey cannot be null or empty!");
208     Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!");
209
210     VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
211     Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available!");
212     Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId() + "has null vpnId!");
213
214     Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
215     if (vpnToDpnList != null) {
216       BigInteger localDpnId = createLocalFibEntry(vpnInstance.getVpnId(),
217                           vrfTableKey.getRouteDistinguisher(), vrfEntry);
218       for (VpnToDpnList curDpn : vpnToDpnList) {
219         if (!curDpn.getDpnId().equals(localDpnId)) {
220           createRemoteFibEntry(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(),
221                                vrfTableKey, vrfEntry);
222         }
223       }
224     }
225   }
226
227   public BigInteger createLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
228     BigInteger localDpnId = BigInteger.ZERO;
229     Prefixes localNextHopInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
230     boolean staticRoute = false;
231
232     //If the vrf entry is a static/extra route, the nexthop of the entry would be a adjacency in the vpn
233     if(localNextHopInfo == null) {
234       localNextHopInfo = getPrefixToInterface(vpnId, vrfEntry.getNextHopAddress() + "/32");
235       staticRoute = true;
236     }
237
238     if(localNextHopInfo != null) {
239       localDpnId = localNextHopInfo.getDpnId();
240       long groupId = nextHopManager.createLocalNextHop(vpnId, localDpnId, localNextHopInfo.getVpnInterfaceName(),
241                                                         (staticRoute == true) ? vrfEntry.getNextHopAddress() + "/32" : vrfEntry.getDestPrefix());
242       List<ActionInfo> actionInfos = new ArrayList<ActionInfo>();
243
244       actionInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId)}));
245
246       makeConnectedRoute(localDpnId, vpnId, vrfEntry, rd, actionInfos, NwConstants.ADD_FLOW);
247       makeLFibTableEntry(localDpnId, vrfEntry.getLabel(), groupId, vrfEntry.getNextHopAddress(), NwConstants.ADD_FLOW);
248
249       LOG.debug("Installing tunnel table entry on dpn {} for interface {} with label {}", 
250                       localDpnId, localNextHopInfo.getVpnInterfaceName(), vrfEntry.getLabel());
251       makeTunnelTableEntry(localDpnId, vrfEntry.getLabel(), groupId);
252
253     }
254     return localDpnId;
255   }
256
257   private void makeTunnelTableEntry(BigInteger dpId, long label, long groupId/*String egressInterfaceName*/) {
258       List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
259       actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }));
260
261
262       createTerminatingServiceActions(dpId, (int)label, actionsInfos);
263
264       LOG.debug("Terminating service Entry for dpID {} : label : {} egress : {} installed successfully {}",
265               dpId, label, groupId);
266   }
267
268   public void createTerminatingServiceActions( BigInteger destDpId, int label, List<ActionInfo> actionsInfos) {
269     // FIXME
270 /*      List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
271
272       LOG.info("create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}", destDpId , label,actionsInfos);
273
274       // Matching metadata
275       mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {
276                                   MetaDataUtil.getTunnelIdWithValidVniBitAndVniSet(label),
277                                   MetaDataUtil.METADA_MASK_TUNNEL_ID }));
278
279       List<InstructionInfo> mkInstructions = new ArrayList<InstructionInfo>();
280       mkInstructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
281
282       FlowEntity terminatingServiceTableFlowEntity = MDSALUtil.buildFlowEntity(destDpId,ITMConstants.TERMINATING_SERVICE_TABLE,
283                       getFlowRef(destDpId, ITMConstants.TERMINATING_SERVICE_TABLE,label), 5, String.format("%s:%d","TST Flow Entry ",label),
284                       0, 0, ITMConstants.COOKIE_ITM.add(BigInteger.valueOf(label)),mkMatches, mkInstructions);
285
286       mdsalManager.installFlow(terminatingServiceTableFlowEntity);*/
287  }
288
289   private void removeTunnelTableEntry(BigInteger dpId, long label) {
290       // FIXME
291       // itmManager.removeTerminatingServiceAction(dpId, (int)label);
292
293       // LOG.debug("Terminating service Entry for dpID {} : label : {} removed successfully {}",dpId, label);
294   }
295
296   public BigInteger deleteLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
297     BigInteger localDpnId = BigInteger.ZERO;
298     VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
299     boolean staticRoute = false;
300
301     //If the vrf entry is a static/extra route, the nexthop of the entry would be a adjacency in the vpn
302     if(localNextHopInfo == null) {
303       localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getNextHopAddress() + "/32");
304       staticRoute = true;
305     }
306
307     if(localNextHopInfo != null) {
308       localDpnId = localNextHopInfo.getDpnId();
309       if (getPrefixToInterface(vpnId, (staticRoute == true) ? vrfEntry.getNextHopAddress() + "/32" : vrfEntry.getDestPrefix()) == null) {
310         makeConnectedRoute(localDpnId, vpnId, vrfEntry, rd, null /* invalid */,
311                            NwConstants.DEL_FLOW);
312         makeLFibTableEntry(localDpnId, vrfEntry.getLabel(), 0 /* invalid */,
313                            vrfEntry.getNextHopAddress(), NwConstants.DEL_FLOW);
314         removeTunnelTableEntry(localDpnId, vrfEntry.getLabel());
315         deleteLocalAdjacency(localDpnId, vpnId, (staticRoute == true) ? vrfEntry.getNextHopAddress() + "/32" : vrfEntry.getDestPrefix());
316       }
317     }
318     return localDpnId;
319   }
320
321   private InstanceIdentifier<Prefixes> getPrefixToInterfaceIdentifier(Long vpnId, String ipPrefix) {
322     return InstanceIdentifier.builder(PrefixToInterface.class)
323         .child(VpnIds.class, new VpnIdsKey(vpnId)).child(Prefixes.class, new PrefixesKey(ipPrefix)).build();
324   }
325
326   private Prefixes getPrefixToInterface(Long vpnId, String ipPrefix) {
327     Optional<Prefixes> localNextHopInfoData =
328         read(LogicalDatastoreType.OPERATIONAL, getPrefixToInterfaceIdentifier(vpnId, ipPrefix));
329     return  localNextHopInfoData.isPresent() ? localNextHopInfoData.get() : null;
330   }
331   
332
333   private Class<? extends TunnelTypeBase> getTunnelType(String ifName) {
334         try {
335             Future<RpcResult<GetTunnelTypeOutput>> result = interfaceManager.getTunnelType(
336                           new GetTunnelTypeInputBuilder().setIntfName(ifName).build());
337           RpcResult<GetTunnelTypeOutput> rpcResult = result.get();
338           if(!rpcResult.isSuccessful()) {
339               LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
340           } else {
341               return rpcResult.getResult().getTunnelType();
342           }
343           
344       } catch (InterruptedException | ExecutionException e) {
345           LOG.warn("Exception when getting tunnel interface Id for tunnel type {}", e);
346       }
347   
348   return null;
349
350   }
351   private void createRemoteFibEntry(final BigInteger localDpnId, final BigInteger remoteDpnId,
352                                     final long vpnId, final VrfTablesKey vrfTableKey,
353                                     final VrfEntry vrfEntry) {
354     String rd = vrfTableKey.getRouteDistinguisher();
355     LOG.debug("adding route " + vrfEntry.getDestPrefix() + " " + rd);
356     /********************************************/
357     String tunnelInterface = resolveAdjacency(localDpnId, remoteDpnId, vpnId, vrfEntry);
358     if(tunnelInterface == null) {
359       LOG.error("Could not get interface for nexthop: {} in vpn {}",
360                                    vrfEntry.getNextHopAddress(), rd);
361       LOG.warn("Failed to add Route: {} in vpn: {}",
362                              vrfEntry.getDestPrefix(), rd);
363       return;
364     }
365         List<ActionInfo> actionInfos = nextHopManager.getEgressActionsForInterface(tunnelInterface);
366         Class<? extends TunnelTypeBase> tunnel_type = getTunnelType(tunnelInterface);
367     if (tunnel_type.equals(TunnelTypeMplsOverGre.class)) {
368         LOG.debug("Push label action for prefix {}", vrfEntry.getDestPrefix());
369         actionInfos.add(new ActionInfo(ActionType.push_mpls, new String[] { null }));
370         actionInfos.add(new ActionInfo(ActionType.set_field_mpls_label, new String[] { Long.toString(vrfEntry.getLabel())}));
371     } else {
372         int label = vrfEntry.getLabel().intValue();
373         BigInteger tunnelId;
374         if(tunnel_type.equals(TunnelTypeVxlan.class)) {
375                 tunnelId = MetaDataUtil.getTunnelIdWithValidVniBitAndVniSet(label);
376         } else {
377                 tunnelId = BigInteger.valueOf(label);
378         }
379         LOG.debug("adding set tunnel id action for label {}", label);
380         actionInfos.add(new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] {
381                         tunnelId, MetaDataUtil.METADA_MASK_VALID_TUNNEL_ID_BIT_AND_TUNNEL_ID }));
382     }
383 /*
384     List<ActionInfo> actionInfos = resolveAdjacency(localDpnId, remoteDpnId, vpnId, vrfEntry);
385     if(actionInfos == null) {
386       LOG.error("Could not get nexthop group id for nexthop: {} in vpn {}",
387                                    vrfEntry.getNextHopAddress(), rd);
388       LOG.warn("Failed to add Route: {} in vpn: {}",
389                              vrfEntry.getDestPrefix(), rd);
390       return;
391     }
392     BigInteger dpnId = nextHopManager.getDpnForPrefix(vpnId, vrfEntry.getDestPrefix());
393     if(dpnId == null) {
394         //This route may be extra route... try to query with nexthop Ip
395         LOG.debug("Checking for extra route to install remote fib entry {}", vrfEntry.getDestPrefix());
396         dpnId = nextHopManager.getDpnForPrefix(vpnId, vrfEntry.getNextHopAddress() + "/32");
397     }
398     if(dpnId == null) {
399         LOG.debug("Push label action for prefix {}", vrfEntry.getDestPrefix());
400         actionInfos.add(new ActionInfo(ActionType.push_mpls, new String[] { null }));
401         actionInfos.add(new ActionInfo(ActionType.set_field_mpls_label, new String[] { Long.toString(vrfEntry.getLabel())}));
402     } else {
403         int label = vrfEntry.getLabel().intValue();
404         LOG.debug("adding set tunnel id action for label {}", label);
405         actionInfos.add(new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] {
406                 MetaDataUtil.getTunnelIdWithValidVniBitAndVniSet(label),
407                 MetaDataUtil.METADA_MASK_VALID_TUNNEL_ID_BIT_AND_TUNNEL_ID }));
408     }
409 **/
410     makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, actionInfos, NwConstants.ADD_FLOW);
411     LOG.debug(
412         "Successfully added fib entry for " + vrfEntry.getDestPrefix() + " vpnId " + vpnId);
413   }
414
415   private void deleteFibEntries(final InstanceIdentifier<VrfEntry> identifier,
416                                 final VrfEntry vrfEntry) {
417     final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class, VrfTablesKey.class);
418     Preconditions.checkNotNull(vrfTableKey, "VrfTablesKey cannot be null or empty!");
419     Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!");
420
421     VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
422     Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available!");
423     Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
424     if (vpnToDpnList != null) {
425       BigInteger localDpnId = deleteLocalFibEntry(vpnInstance.getVpnId(),
426                           vrfTableKey.getRouteDistinguisher(), vrfEntry);
427       for (VpnToDpnList curDpn : vpnToDpnList) {
428         if (!curDpn.getDpnId().equals(localDpnId)) {
429           deleteRemoteRoute(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry);
430         }
431       }
432
433     }
434   }
435
436   public void deleteRemoteRoute(final BigInteger localDpnId, final BigInteger remoteDpnId,
437                                 final long vpnId, final VrfTablesKey vrfTableKey,
438                                 final VrfEntry vrfEntry) {
439     LOG.debug("deleting route "+ vrfEntry.getDestPrefix() + " "+vpnId);
440     String rd = vrfTableKey.getRouteDistinguisher();
441     String egressInterface = resolveAdjacency(localDpnId, remoteDpnId, vpnId, vrfEntry);
442     if(egressInterface == null) {
443       LOG.error("Could not get nexthop group id for nexthop: {} in vpn {}",
444                 vrfEntry.getNextHopAddress(), rd);
445       LOG.warn("Failed to delete Route: {} in vpn: {}",
446                vrfEntry.getDestPrefix(), rd);
447       return;
448     }
449
450     makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW);
451     LOG.debug("Successfully delete fib entry for "+ vrfEntry.getDestPrefix() + " vpnId "+vpnId);
452   }
453
454   private long getIpAddress(byte[] rawIpAddress) {
455     return (((rawIpAddress[0] & 0xFF) << (3 * 8)) + ((rawIpAddress[1] & 0xFF) << (2 * 8))
456             + ((rawIpAddress[2] & 0xFF) << (1 * 8)) + (rawIpAddress[3] & 0xFF)) & 0xffffffffL;
457   }
458
459   private void makeConnectedRoute(BigInteger dpId, long vpnId, VrfEntry vrfEntry, String rd,
460                                   List<ActionInfo> actionInfos, int addOrRemove) {
461     LOG.trace("makeConnectedRoute: vrfEntry {}",vrfEntry);
462     String values[] = vrfEntry.getDestPrefix().split("/");
463     String ipAddress = values[0];
464     int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]);
465     LOG.debug("Adding route to DPN. ip {} masklen {}", ipAddress, prefixLength);
466     InetAddress destPrefix = null;
467     try {
468       destPrefix = InetAddress.getByName(ipAddress);
469     } catch (UnknownHostException e) {
470       LOG.error("UnknowHostException in addRoute. Failed  to add Route for ipPrefix {}", vrfEntry.getDestPrefix());
471       return;
472     }
473
474     List<MatchInfo> matches = new ArrayList<MatchInfo>();
475
476     matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
477         BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
478
479     matches.add(new MatchInfo(MatchFieldType.eth_type,
480                               new long[] { 0x0800L }));
481
482     if(prefixLength != 0) {
483       matches.add(new MatchInfo(MatchFieldType.ipv4_dst, new long[] {
484           getIpAddress(destPrefix.getAddress()), prefixLength }));
485     }
486
487     List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
488     if(addOrRemove == NwConstants.ADD_FLOW) {
489       instructions.add(new InstructionInfo(InstructionType.write_actions, actionInfos));
490     }
491
492     String flowRef = getFlowRef(dpId, L3_FIB_TABLE, rd, destPrefix);
493
494     FlowEntity flowEntity;
495
496     int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
497     flowEntity = MDSALUtil.buildFlowEntity(dpId, L3_FIB_TABLE, flowRef,
498                                            priority, flowRef, 0, 0,
499                                            COOKIE_VM_FIB_TABLE, matches, instructions);
500
501     if (addOrRemove == NwConstants.ADD_FLOW) {
502       /* We need to call sync API to install flow so that 2 DS operations on the same object do not
503       * happen at same time. However, MDSALManager's syncInstallFlow takes a delay time (or uses a default one) to wait
504       * for or for notification that operational DS write for flows is done. We do not turn on the stats writing for flows,
505       * so that notification never comes, so we do not need that wait. Sending the lowest value of wait "1 ms" since 0 wait means
506       * wait indefinitely. */
507       // FIXME: sync calls.
508       //mdsalManager.syncInstallFlow(flowEntity, 1);
509       mdsalManager.installFlow(flowEntity);
510     } else {
511       // FIXME: sync calls.
512       // mdsalManager.syncRemoveFlow(flowEntity, 1);
513       mdsalManager.removeFlow(flowEntity);
514     }
515   }
516
517   private void makeLFibTableEntry(BigInteger dpId, long label, long groupId,
518                                   String nextHop, int addOrRemove) {
519     List<MatchInfo> matches = new ArrayList<MatchInfo>();
520     matches.add(new MatchInfo(MatchFieldType.eth_type,
521                               new long[] { 0x8847L }));
522     matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(label)}));
523
524     List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
525     List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
526     actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{}));
527     actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }));
528     instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
529
530     // Install the flow entry in L3_LFIB_TABLE
531     String flowRef = getFlowRef(dpId, L3_LFIB_TABLE, label, nextHop);
532
533     FlowEntity flowEntity;
534     flowEntity = MDSALUtil.buildFlowEntity(dpId, L3_LFIB_TABLE, flowRef,
535                                            DEFAULT_FIB_FLOW_PRIORITY, flowRef, 0, 0,
536                                            COOKIE_VM_LFIB_TABLE, matches, instructions);
537
538     if (addOrRemove == NwConstants.ADD_FLOW) {
539       /* We need to call sync API to install flow so that 2 DS operations on the same object do not
540       * happen at same time. However, MDSALManager's syncInstallFlow takes a delay time (or uses a default one) to wait
541       * for or for notification that operational DS write for flows is done. We do not turn on the stats writing for flows,
542       * so that notification never comes, so we do not need that wait. Sending the lowest value of wait "1 ms" since 0 wait means
543       * wait indefinitely. */
544
545       // FIXME:
546       // mdsalManager.syncInstallFlow(flowEntity, 1);
547       mdsalManager.installFlow(flowEntity);
548     } else {
549       // FIXME:
550       // mdsalManager.syncRemoveFlow(flowEntity, 1);
551       mdsalManager.removeFlow(flowEntity);
552     }
553     LOG.debug("LFIB Entry for dpID {} : label : {} group {} modified successfully {}",dpId, label, groupId );
554   }
555
556   private void deleteLocalAdjacency(final BigInteger dpId, final long vpnId, final String ipAddress) {
557     LOG.trace("deleteLocalAdjacency called with dpid {}, vpnId{}, ipAddress {}",dpId, vpnId, ipAddress);
558     try {
559       nextHopManager.removeLocalNextHop(dpId, vpnId, ipAddress);
560     } catch (NullPointerException e) {
561       LOG.trace("", e);
562     }
563   }
564
565   public void populateFibOnNewDpn(BigInteger dpnId, long vpnId, String rd) {
566     LOG.trace("New dpn {} for vpn {} : populateFibOnNewDpn", dpnId, rd);
567     InstanceIdentifier<VrfTables> id = buildVrfId(rd);
568     Optional<VrfTables> vrfTable = read(LogicalDatastoreType.OPERATIONAL, id);
569     if(vrfTable.isPresent()) {
570       for(VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
571         // Passing null as we don't know the dpn
572         // to which prefix is attached at this point
573         createRemoteFibEntry(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
574       }
575     }
576   }
577
578   public void cleanUpDpnForVpn(BigInteger dpnId, long vpnId, String rd) {
579     LOG.trace("Remove dpn {} for vpn {} : cleanUpDpnForVpn", dpnId, rd);
580     InstanceIdentifier<VrfTables> id = buildVrfId(rd);
581     Optional<VrfTables> vrfTable = read(LogicalDatastoreType.OPERATIONAL, id);
582     if(vrfTable.isPresent()) {
583       for(VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
584         // Passing null as we don't know the dpn
585         // to which prefix is attached at this point
586         deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
587       }
588     }
589   }
590
591   public static InstanceIdentifier<VrfTables> buildVrfId(String rd) {
592     InstanceIdentifierBuilder<VrfTables> idBuilder =
593         InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
594     InstanceIdentifier<VrfTables> id = idBuilder.build();
595     return id;
596   }
597
598   private String getFlowRef(BigInteger dpnId, short tableId, long label, String nextHop) {
599     return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
600         .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
601         .append(label).append(NwConstants.FLOWID_SEPARATOR)
602         .append(nextHop).toString();
603   }
604
605   private String getFlowRef(BigInteger dpnId, short tableId, String rd, InetAddress destPrefix) {
606     return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
607         .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
608         .append(rd).append(NwConstants.FLOWID_SEPARATOR)
609         .append(destPrefix.getHostAddress()).toString();
610   }
611
612   protected String resolveAdjacency(final BigInteger localDpnId, final BigInteger remoteDpnId,
613                                               final long vpnId, final VrfEntry vrfEntry) {
614     String adjacency = null;
615     LOG.trace("resolveAdjacency called with localdpid{} remotedpid {}, vpnId{}, VrfEntry {}", localDpnId, remoteDpnId, vpnId, vrfEntry);;
616     try {
617       adjacency =
618           nextHopManager.getRemoteNextHopPointer(localDpnId, remoteDpnId, vpnId,
619                                                  vrfEntry.getDestPrefix(),
620                                                  vrfEntry.getNextHopAddress());
621     } catch (NullPointerException e) {
622       LOG.trace("", e);
623     }
624     return adjacency;
625   }
626
627   protected VpnInstanceOpDataEntry getVpnInstance(String rd) {
628     InstanceIdentifier<VpnInstanceOpDataEntry> id = InstanceIdentifier.create(VpnInstanceOpData.class).child(
629         VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd));
630     Optional<VpnInstanceOpDataEntry> vpnInstanceOpData = read(LogicalDatastoreType.OPERATIONAL, id);
631     if(vpnInstanceOpData.isPresent()) {
632       return vpnInstanceOpData.get();
633     }
634     return null;
635   }
636
637     public void processNodeAdd(BigInteger dpnId) {
638         LOG.debug("Received notification to install TableMiss entries for dpn {} ", dpnId);
639         makeTableMissFlow(dpnId, NwConstants.ADD_FLOW);
640         makeProtocolTableFlow(dpnId, NwConstants.ADD_FLOW);
641         makeL3IntfTblMissFlow(dpnId, NwConstants.ADD_FLOW);
642     }
643
644     private void makeTableMissFlow(BigInteger dpnId, int addOrRemove) {
645         final BigInteger COOKIE_TABLE_MISS = new BigInteger("1030000", 16);
646         // Instruction to goto L3 InterfaceTable
647         List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
648         instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { L3_INTERFACE_TABLE }));
649         List<MatchInfo> matches = new ArrayList<MatchInfo>();
650         FlowEntity flowEntityLfib = MDSALUtil.buildFlowEntity(dpnId, L3_LFIB_TABLE,
651                 getFlowRef(dpnId, L3_LFIB_TABLE, NwConstants.TABLE_MISS_FLOW),
652                 NwConstants.TABLE_MISS_PRIORITY, "Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions);
653
654         FlowEntity flowEntityFib = MDSALUtil.buildFlowEntity(dpnId,L3_FIB_TABLE, getFlowRef(dpnId, L3_FIB_TABLE, NwConstants.TABLE_MISS_FLOW),
655                 NwConstants.TABLE_MISS_PRIORITY, "FIB Table Miss Flow", 0, 0, COOKIE_VM_FIB_TABLE,
656                 matches, instructions);
657
658         if (addOrRemove == NwConstants.ADD_FLOW) {
659             LOG.debug("Invoking MDSAL to install Table Miss Entries");
660             mdsalManager.installFlow(flowEntityLfib);
661             mdsalManager.installFlow(flowEntityFib);
662         } else {
663             mdsalManager.removeFlow(flowEntityLfib);
664             mdsalManager.removeFlow(flowEntityFib);
665
666         }
667     }
668
669     private String getFlowRef(BigInteger dpnId, short tableId, int tableMiss) {
670         return new StringBuffer().append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
671                 .append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(tableMiss)
672                 .append(FLOWID_PREFIX).toString();
673     }
674
675   /*
676    * Install flow entry in protocol table to forward mpls
677    * coming through gre tunnel to LFIB table.
678    */
679   private void makeProtocolTableFlow(BigInteger dpnId, int addOrRemove) {
680     final BigInteger COOKIE_PROTOCOL_TABLE = new BigInteger("1070000", 16);
681     // Instruction to goto L3 InterfaceTable
682     List<InstructionInfo> instructions = new ArrayList<>();
683     instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] {L3_LFIB_TABLE}));
684     List<MatchInfo> matches = new ArrayList<MatchInfo>();
685     matches.add(new MatchInfo(MatchFieldType.eth_type,
686                               new long[] { 0x8847L }));
687     FlowEntity flowEntityToLfib = MDSALUtil.buildFlowEntity(dpnId, L3_PROTOCOL_TABLE,
688                                                           getFlowRef(dpnId, L3_PROTOCOL_TABLE,
689                                                                      L3_LFIB_TABLE),
690                                                           DEFAULT_FIB_FLOW_PRIORITY,
691                                                           "Protocol Table For LFIB",
692                                                           0, 0,
693                                                           COOKIE_PROTOCOL_TABLE,
694                                                           matches, instructions);
695
696     if (addOrRemove == NwConstants.ADD_FLOW) {
697       LOG.debug("Invoking MDSAL to install Protocol Entries for dpn {}", dpnId);
698       mdsalManager.installFlow(flowEntityToLfib);
699     } else {
700       mdsalManager.removeFlow(flowEntityToLfib);
701     }
702   }
703
704   public List<String> printFibEntries() {
705     List<String> result = new ArrayList<String>();
706     result.add(String.format("   %-7s  %-20s  %-20s  %-7s", "RD", "Prefix", "Nexthop", "Label"));
707     result.add("-------------------------------------------------------------------");
708     InstanceIdentifier<FibEntries> id = InstanceIdentifier.create(FibEntries.class);
709     Optional<FibEntries> fibEntries = read(LogicalDatastoreType.OPERATIONAL, id);
710     if (fibEntries.isPresent()) {
711       List<VrfTables> vrfTables = fibEntries.get().getVrfTables();
712       for (VrfTables vrfTable : vrfTables) {
713         for (VrfEntry vrfEntry : vrfTable.getVrfEntry()) {
714           result.add(String.format("   %-7s  %-20s  %-20s  %-7s", vrfTable.getRouteDistinguisher(),
715                   vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddress(), vrfEntry.getLabel()));
716         }
717       }
718     }
719     return result;
720   }
721
722   private void makeL3IntfTblMissFlow(BigInteger dpnId, int addOrRemove) {
723     List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
724     List<MatchInfo> matches = new ArrayList<MatchInfo>();
725     final BigInteger COOKIE_TABLE_MISS = new BigInteger("1030000", 16);
726     // Instruction to clear metadata except SI and LportTag bits
727     instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] {
728                     CLEAR_METADATA, METADATA_MASK_CLEAR }));
729     // Instruction to clear action
730     instructions.add(new InstructionInfo(InstructionType.clear_actions));
731     // Instruction to goto L3 InterfaceTable
732
733     instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { LPORT_DISPATCHER_TABLE }));
734
735     FlowEntity flowEntityL3Intf = MDSALUtil.buildFlowEntity(dpnId, L3_INTERFACE_TABLE,
736             getFlowRef(dpnId, L3_INTERFACE_TABLE, NwConstants.TABLE_MISS_FLOW),
737             NwConstants.TABLE_MISS_PRIORITY, "L3 Interface Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions);
738     if (addOrRemove == NwConstants.ADD_FLOW) {
739       LOG.info("Invoking MDSAL to install L3 interface Table Miss Entries");
740       mdsalManager.installFlow(flowEntityL3Intf);
741     } else {
742       mdsalManager.removeFlow(flowEntityL3Intf);
743     }
744   }
745
746 }