X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=fibmanager%2Ffibmanager-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fvpnservice%2Ffibmanager%2FFibManager.java;h=128444c65991b8f57dbcb88593d7c75afda3587e;hb=f30638fcc162d85f21f33cef401b4fb5da05caaf;hp=611de0973997847b11cdbb7aeed4c6da14ce329c;hpb=ddb1c151299813365c1bcb877a1f01484e964e90;p=vpnservice.git diff --git a/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/FibManager.java b/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/FibManager.java index 611de097..128444c6 100644 --- a/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/FibManager.java +++ b/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/FibManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. All rights reserved. + * Copyright (c) 2015 - 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, @@ -7,15 +7,29 @@ */ package org.opendaylight.vpnservice.fibmanager; +import com.google.common.base.Optional; import com.google.common.base.Preconditions; -import com.google.common.util.concurrent.Futures; -import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; + +import java.math.BigInteger; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; -import org.opendaylight.vpnmanager.api.IVpnManager; -import org.opendaylight.vpnservice.AbstractDataChangeListener; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; +import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; +import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.vpnmanager.api.IVpnManager; +import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener; +import org.opendaylight.vpnservice.itm.globals.ITMConstants; import org.opendaylight.vpnservice.mdsalutil.ActionInfo; import org.opendaylight.vpnservice.mdsalutil.ActionType; import org.opendaylight.vpnservice.mdsalutil.FlowEntity; @@ -27,70 +41,65 @@ import org.opendaylight.vpnservice.mdsalutil.MatchInfo; import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil; import org.opendaylight.vpnservice.mdsalutil.NwConstants; import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager; -import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances; -import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance; -import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstance1; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.PrefixToInterface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstanceOpData; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnToExtraroute; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.VpnIds; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.VpnIdsKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.vpn.ids.PrefixesKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.Vpn; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.VpnKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.vpn.Extraroute; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.vpn.ExtrarouteBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.vpn.ExtrarouteKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.FibEntries; import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTables; import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTablesKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.vrfentries.VrfEntry; -import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150409.GetEgressPointerInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150409.GetEgressPointerOutput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150409.L3nexthopService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeBase; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeMplsOverGre; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetTunnelTypeInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetTunnelTypeOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthop; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.Adjacencies; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder; -import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; -import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.FibEntries; -import org.opendaylight.yangtools.yang.binding.RpcService; import org.opendaylight.yangtools.yang.common.RpcResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.base.Optional; - -import java.math.BigInteger; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Set; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; public class FibManager extends AbstractDataChangeListener implements AutoCloseable{ private static final Logger LOG = LoggerFactory.getLogger(FibManager.class); private static final String FLOWID_PREFIX = "L3."; private ListenerRegistration listenerRegistration; private final DataBroker broker; - private final L3nexthopService l3nexthopService; private IMdsalApiManager mdsalManager; private IVpnManager vpnmanager; - - private static final short L3_FIB_TABLE = 20; - private static final short L3_LFIB_TABLE = 21; + private NexthopManager nextHopManager; + private ItmRpcService itmManager; + private OdlInterfaceRpcService interfaceManager; private static final BigInteger COOKIE_VM_LFIB_TABLE = new BigInteger("8000002", 16); private static final BigInteger COOKIE_VM_FIB_TABLE = new BigInteger("8000003", 16); private static final int DEFAULT_FIB_FLOW_PRIORITY = 10; + private static final BigInteger METADATA_MASK_CLEAR = new BigInteger("000000FFFFFFFFFF", 16); + private static final BigInteger CLEAR_METADATA = BigInteger.valueOf(0); + public static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16); - private static final FutureCallback DEFAULT_CALLBACK = - new FutureCallback() { - public void onSuccess(Void result) { - LOG.debug("Success in Datastore write operation"); - } - - public void onFailure(Throwable error) { - LOG.error("Error in Datastore write operation", error); - }; - }; - - public FibManager(final DataBroker db, final RpcService nextHopService) { + public FibManager(final DataBroker db) { super(VrfEntry.class); broker = db; - l3nexthopService = (L3nexthopService)nextHopService; registerListener(db); } @@ -107,6 +116,9 @@ public class FibManager extends AbstractDataChangeListener implements LOG.info("Fib Manager Closed"); } + public void setNextHopManager(NexthopManager nextHopManager) { + this.nextHopManager = nextHopManager; + } public void setMdsalManager(IMdsalApiManager mdsalManager) { this.mdsalManager = mdsalManager; @@ -116,6 +128,14 @@ public class FibManager extends AbstractDataChangeListener implements this.vpnmanager = vpnmanager; } + public void setITMRpcService(ItmRpcService itmManager) { + this.itmManager = itmManager; + } + + public void setInterfaceManager(OdlInterfaceRpcService ifManager) { + this.interfaceManager = ifManager; + } + private void registerListener(final DataBroker db) { try { listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, @@ -126,31 +146,11 @@ public class FibManager extends AbstractDataChangeListener implements } } - private Optional read(LogicalDatastoreType datastoreType, - InstanceIdentifier path) { - - ReadOnlyTransaction tx = broker.newReadOnlyTransaction(); - - Optional result = Optional.absent(); - try { - result = tx.read(datastoreType, path).get(); - } catch (Exception e) { - throw new RuntimeException(e); - } - - return result; - } private InstanceIdentifier getWildCardPath() { return InstanceIdentifier.create(FibEntries.class).child(VrfTables.class).child(VrfEntry.class); } - private void asyncWrite(LogicalDatastoreType datastoreType, - InstanceIdentifier path, T data, FutureCallback callback) { - WriteTransaction tx = broker.newWriteOnlyTransaction(); - tx.put(datastoreType, path, data, true); - Futures.addCallback(tx.submit(), callback); - } @Override protected void add(final InstanceIdentifier identifier, @@ -168,6 +168,7 @@ public class FibManager extends AbstractDataChangeListener implements @Override protected void update(InstanceIdentifier identifier, VrfEntry original, VrfEntry update) { LOG.trace("key: " + identifier + ", original=" + original + ", update=" + update ); + createFibEntries(identifier, update); } private void createFibEntries(final InstanceIdentifier identifier, @@ -176,84 +177,356 @@ public class FibManager extends AbstractDataChangeListener implements Preconditions.checkNotNull(vrfTableKey, "VrfTablesKey cannot be null or empty!"); Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!"); - Long vpnId = getVpnId(vrfTableKey.getRouteDistinguisher()); - Preconditions.checkNotNull(vpnId, "Vpn Instance not available!"); - Collection dpns = vpnmanager.getDpnsForVpn(vpnId); - for (Long dpId : dpns) { - addRouteInternal(dpId, vpnId, vrfTableKey, vrfEntry); + VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher()); + Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available!"); + Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId() + "has null vpnId!"); + + Collection vpnToDpnList = vpnInstance.getVpnToDpnList(); + BigInteger localDpnId = createLocalFibEntry(vpnInstance.getVpnId(), + vrfTableKey.getRouteDistinguisher(), vrfEntry); + if (vpnToDpnList != null) { + for (VpnToDpnList curDpn : vpnToDpnList) { + if (!curDpn.getDpnId().equals(localDpnId)) { + createRemoteFibEntry(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(), + vrfTableKey, vrfEntry); + } + } } } - private void addRouteInternal(final long dpId, final long vpnId, final VrfTablesKey vrfTableKey, - final VrfEntry vrfEntry) { + public BigInteger createLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) { + BigInteger localDpnId = BigInteger.ZERO; + Prefixes localNextHopInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix()); + String localNextHopIP = vrfEntry.getDestPrefix(); + + if(localNextHopInfo == null) { + //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn + Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix()); + if (extra_route != null) { + localNextHopInfo = getPrefixToInterface(vpnId, extra_route.getNexthopIp() + "/32"); + localNextHopIP = extra_route.getNexthopIp() + "/32"; + } + } + + if(localNextHopInfo != null) { + localDpnId = localNextHopInfo.getDpnId(); + long groupId = nextHopManager.createLocalNextHop(vpnId, localDpnId, localNextHopInfo.getVpnInterfaceName(), localNextHopIP); + List actionInfos = new ArrayList(); + + actionInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId)})); + + makeConnectedRoute(localDpnId, vpnId, vrfEntry, rd, actionInfos, NwConstants.ADD_FLOW); + makeLFibTableEntry(localDpnId, vrfEntry.getLabel(), groupId, vrfEntry.getNextHopAddress(), NwConstants.ADD_FLOW); + + LOG.debug("Installing tunnel table entry on dpn {} for interface {} with label {}", + localDpnId, localNextHopInfo.getVpnInterfaceName(), vrfEntry.getLabel()); + makeTunnelTableEntry(localDpnId, vrfEntry.getLabel(), groupId); + + } + return localDpnId; + } + + private void makeTunnelTableEntry(BigInteger dpId, long label, long groupId/*String egressInterfaceName*/) { + List actionsInfos = new ArrayList(); + actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) })); + + + createTerminatingServiceActions(dpId, (int)label, actionsInfos); + + LOG.debug("Terminating service Entry for dpID {} : label : {} egress : {} installed successfully {}", + dpId, label, groupId); + } + + public void createTerminatingServiceActions( BigInteger destDpId, int label, List actionsInfos) { + List mkMatches = new ArrayList(); + + LOG.info("create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}", destDpId , label,actionsInfos); + + // Matching metadata + // FIXME vxlan vni bit set is not working properly with OVS.need to revisit + mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(label)})); + + List mkInstructions = new ArrayList(); + mkInstructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos)); + + FlowEntity terminatingServiceTableFlowEntity = MDSALUtil.buildFlowEntity(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE, + getFlowRef(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,label), 5, String.format("%s:%d","TST Flow Entry ",label), + 0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(label)),mkMatches, mkInstructions); + + mdsalManager.installFlow(terminatingServiceTableFlowEntity); + } + + private void removeTunnelTableEntry(BigInteger dpId, long label) { + FlowEntity flowEntity; + LOG.info("remove terminatingServiceActions called with DpnId = {} and label = {}", dpId , label); + List mkMatches = new ArrayList(); + // Matching metadata + mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(label)})); + flowEntity = MDSALUtil.buildFlowEntity(dpId, + NwConstants.INTERNAL_TUNNEL_TABLE, + getFlowRef(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, (int)label), + 5, String.format("%s:%d","TST Flow Entry ",label), 0, 0, + COOKIE_TUNNEL.add(BigInteger.valueOf(label)), mkMatches, null); + mdsalManager.removeFlow(flowEntity); + LOG.debug("Terminating service Entry for dpID {} : label : {} removed successfully {}",dpId, label); + } + + public BigInteger deleteLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) { + BigInteger localDpnId = BigInteger.ZERO; + boolean isExtraRoute = false; + VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix()); + String localNextHopIP = vrfEntry.getDestPrefix(); + + if(localNextHopInfo == null) { + //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn + Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix()); + if (extra_route != null) { + localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, extra_route.getNexthopIp() + "/32"); + localNextHopIP = extra_route.getNexthopIp() + "/32"; + isExtraRoute = true; + } + } + + + if(localNextHopInfo != null) { + localDpnId = localNextHopInfo.getDpnId(); + Prefixes prefix = getPrefixToInterface(vpnId, isExtraRoute ? localNextHopIP : vrfEntry.getDestPrefix()); + makeConnectedRoute(localDpnId, vpnId, vrfEntry, rd, null /* invalid */, + NwConstants.DEL_FLOW); + makeLFibTableEntry(localDpnId, vrfEntry.getLabel(), 0 /* invalid */, + vrfEntry.getNextHopAddress(), NwConstants.DEL_FLOW); + removeTunnelTableEntry(localDpnId, vrfEntry.getLabel()); + deleteLocalAdjacency(localDpnId, vpnId, localNextHopIP); + } + return localDpnId; + } + + private InstanceIdentifier getPrefixToInterfaceIdentifier(Long vpnId, String ipPrefix) { + return InstanceIdentifier.builder(PrefixToInterface.class) + .child(VpnIds.class, new VpnIdsKey(vpnId)).child(Prefixes.class, new PrefixesKey(ipPrefix)).build(); + } + + private Prefixes getPrefixToInterface(Long vpnId, String ipPrefix) { + Optional localNextHopInfoData = + FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, getPrefixToInterfaceIdentifier(vpnId, ipPrefix)); + return localNextHopInfoData.isPresent() ? localNextHopInfoData.get() : null; + } + + private InstanceIdentifier getVpnToExtrarouteIdentifier(String vrfId, String ipPrefix) { + return InstanceIdentifier.builder(VpnToExtraroute.class) + .child(Vpn.class, new VpnKey(vrfId)).child(Extraroute.class, + new ExtrarouteKey(ipPrefix)).build(); + } + + private Extraroute getVpnToExtraroute(String rd, String ipPrefix) { + Optional extraRouteInfo = + FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, getVpnToExtrarouteIdentifier(rd, ipPrefix)); + return extraRouteInfo.isPresent() ? extraRouteInfo.get() : null; + + } + + private Class getTunnelType(String ifName) { + try { + Future> result = interfaceManager.getTunnelType( + new GetTunnelTypeInputBuilder().setIntfName(ifName).build()); + RpcResult rpcResult = result.get(); + if(!rpcResult.isSuccessful()) { + LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors()); + } else { + return rpcResult.getResult().getTunnelType(); + } + + } catch (InterruptedException | ExecutionException e) { + LOG.warn("Exception when getting tunnel interface Id for tunnel type {}", e); + } + + return null; + + } + private void createRemoteFibEntry(final BigInteger localDpnId, final BigInteger remoteDpnId, + final long vpnId, final VrfTablesKey vrfTableKey, + final VrfEntry vrfEntry) { String rd = vrfTableKey.getRouteDistinguisher(); LOG.debug("adding route " + vrfEntry.getDestPrefix() + " " + rd); - - GetEgressPointerOutput adjacency = resolveAdjacency(dpId, vpnId, vrfEntry); - long groupId = -1; - boolean isLocalRoute = false; - if(adjacency != null) { - groupId = adjacency.getEgressPointer(); - isLocalRoute = adjacency.isLocalDestination(); + /********************************************/ + String tunnelInterface = resolveAdjacency(localDpnId, remoteDpnId, vpnId, vrfEntry, rd); + if(tunnelInterface == null) { + LOG.error("Could not get interface for nexthop: {} in vpn {}", + vrfEntry.getNextHopAddress(), rd); + LOG.warn("Failed to add Route: {} in vpn: {}", + vrfEntry.getDestPrefix(), rd); + return; } - if(groupId == -1) { + List actionInfos = new ArrayList<>(); + Class tunnel_type = getTunnelType(tunnelInterface); + if (tunnel_type.equals(TunnelTypeMplsOverGre.class)) { + LOG.debug("Push label action for prefix {}", vrfEntry.getDestPrefix()); + actionInfos.add(new ActionInfo(ActionType.push_mpls, new String[] { null })); + actionInfos.add(new ActionInfo(ActionType.set_field_mpls_label, new String[] { Long.toString(vrfEntry.getLabel())})); + } else { + int label = vrfEntry.getLabel().intValue(); + BigInteger tunnelId; + // FIXME vxlan vni bit set is not working properly with OVS.need to revisit + if(tunnel_type.equals(TunnelTypeVxlan.class)) { + tunnelId = BigInteger.valueOf(label); + } else { + tunnelId = BigInteger.valueOf(label); + } + LOG.debug("adding set tunnel id action for label {}", label); + actionInfos.add(new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[]{ + tunnelId})); + } + actionInfos.addAll(nextHopManager.getEgressActionsForInterface(tunnelInterface)); +/* + List actionInfos = resolveAdjacency(localDpnId, remoteDpnId, vpnId, vrfEntry); + if(actionInfos == null) { LOG.error("Could not get nexthop group id for nexthop: {} in vpn {}", vrfEntry.getNextHopAddress(), rd); LOG.warn("Failed to add Route: {} in vpn: {}", vrfEntry.getDestPrefix(), rd); return; } - - makeConnectedRoute(dpId, vpnId, vrfEntry, rd, groupId, NwConstants.ADD_FLOW); - - if (isLocalRoute) { - makeLFibTableEntry(dpId, vrfEntry.getLabel(), groupId, vrfEntry.getNextHopAddress(), NwConstants.ADD_FLOW); + BigInteger dpnId = nextHopManager.getDpnForPrefix(vpnId, vrfEntry.getDestPrefix()); + if(dpnId == null) { + //This route may be extra route... try to query with nexthop Ip + LOG.debug("Checking for extra route to install remote fib entry {}", vrfEntry.getDestPrefix()); + dpnId = nextHopManager.getDpnForPrefix(vpnId, vrfEntry.getNextHopAddress() + "/32"); } - + if(dpnId == null) { + LOG.debug("Push label action for prefix {}", vrfEntry.getDestPrefix()); + actionInfos.add(new ActionInfo(ActionType.push_mpls, new String[] { null })); + actionInfos.add(new ActionInfo(ActionType.set_field_mpls_label, new String[] { Long.toString(vrfEntry.getLabel())})); + } else { + int label = vrfEntry.getLabel().intValue(); + LOG.debug("adding set tunnel id action for label {}", label); + actionInfos.add(new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] { + MetaDataUtil.getTunnelIdWithValidVniBitAndVniSet(label), + MetaDataUtil.METADA_MASK_VALID_TUNNEL_ID_BIT_AND_TUNNEL_ID })); + } +**/ + makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, actionInfos, NwConstants.ADD_FLOW); LOG.debug( "Successfully added fib entry for " + vrfEntry.getDestPrefix() + " vpnId " + vpnId); } + private void delIntfFromDpnToVpnList(long vpnId, BigInteger dpnId, String intfName, String rd) { + InstanceIdentifier id = FibUtil.getVpnToDpnListIdentifier(rd, dpnId); + Optional dpnInVpn = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id); + if (dpnInVpn.isPresent()) { + List vpnInterfaces = dpnInVpn.get().getVpnInterfaces(); + org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces + 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(); + + if (vpnInterfaces.remove(currVpnInterface)) { + if (vpnInterfaces.isEmpty()) { + LOG.trace("Last vpn interface {} on dpn {} for vpn {}. Clean up fib in dpn", intfName, dpnId, rd); + FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id); + cleanUpDpnForVpn(dpnId, vpnId, rd); + } else { + LOG.trace("Delete vpn interface {} from dpn {} to vpn {} list.", intfName, dpnId, rd); + FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id.child( + org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data + .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces.class, + 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))); + } + } + } + } + + private void cleanUpOpDataForFib(Long vpnId, String rd, final VrfEntry vrfEntry) { + /* Get interface info from prefix to interface mapping; + Use the interface info to get the corresponding vpn interface op DS entry, + remove the adjacency corresponding to this fib entry. + If adjacency removed is the last adjacency, clean up the following: + - vpn interface from dpntovpn list, dpn if last vpn interface on dpn + - prefix to interface entry + - vpn interface op DS + */ + Prefixes prefixInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix()); + Extraroute extraRoute = null; + if (prefixInfo == null) { + extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix()); + if(extraRoute != null) { + prefixInfo = getPrefixToInterface(vpnId, extraRoute.getNexthopIp() + "/32"); + //clean up the vpn to extra route entry in DS + FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, FibUtil.getVpnToExtrarouteIdentifier(rd, vrfEntry.getDestPrefix())); + } + } + if (prefixInfo == null) { + LOG.debug("Cleanup VPN Data Failed as unable to find prefix Info for " + vrfEntry.getDestPrefix()); + return; //Don't have any info for this prefix (shouldn't happen); need to return + } + String ifName = prefixInfo.getVpnInterfaceName(); + Optional optAdjacencies = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, FibUtil.getAdjListPath(ifName)); + int numAdj = 0; + if (optAdjacencies.isPresent()) { + numAdj = optAdjacencies.get().getAdjacency().size(); + } + LOG.trace("cleanUpOpDataForFib: remove adjacency for prefix: {} {}", vpnId, vrfEntry.getDestPrefix()); + //remove adjacency corr to prefix + if (numAdj > 1) { + FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, + FibUtil.getAdjacencyIdentifier(ifName, vrfEntry.getDestPrefix())); + } + + if ((numAdj - 1) == 0) { //there are no adjacencies left for this vpn interface, clean up + //clean up the vpn interface from DpnToVpn list + LOG.trace("Clean up vpn interface {} from dpn {} to vpn {} list.", ifName, prefixInfo.getDpnId(), rd); + FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, + FibUtil.getVpnInterfaceIdentifier(ifName)); + } + } + private void deleteFibEntries(final InstanceIdentifier identifier, final VrfEntry vrfEntry) { final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class, VrfTablesKey.class); Preconditions.checkNotNull(vrfTableKey, "VrfTablesKey cannot be null or empty!"); Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!"); - Long vpnId = getVpnId(vrfTableKey.getRouteDistinguisher()); - Preconditions.checkNotNull(vpnId, "Vpn Instance not available!"); - Collection dpns = vpnmanager.getDpnsForVpn(vpnId); - for (Long dpId : dpns) { - deleteRoute(dpId, vpnId, vrfTableKey, vrfEntry); + VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher()); + Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available!"); + Collection vpnToDpnList = vpnInstance.getVpnToDpnList(); + BigInteger localDpnId = deleteLocalFibEntry(vpnInstance.getVpnId(), + vrfTableKey.getRouteDistinguisher(), vrfEntry); + if (vpnToDpnList != null) { + for (VpnToDpnList curDpn : vpnToDpnList) { + if (!curDpn.getDpnId().equals(localDpnId)) { + deleteRemoteRoute(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry); + } + } } + //The flow/group entry has been deleted from config DS; need to clean up associated operational + //DS entries in VPN Op DS, VpnInstanceOpData and PrefixToInterface to complete deletion + cleanUpOpDataForFib(vpnInstance.getVpnId(), vrfTableKey.getRouteDistinguisher(), vrfEntry); } - public void deleteRoute(final long dpId, final long vpnId, final VrfTablesKey vrfTableKey, - final VrfEntry vrfEntry) { + public void deleteRemoteRoute(final BigInteger localDpnId, final BigInteger remoteDpnId, + final long vpnId, final VrfTablesKey vrfTableKey, + final VrfEntry vrfEntry) { LOG.debug("deleting route "+ vrfEntry.getDestPrefix() + " "+vpnId); String rd = vrfTableKey.getRouteDistinguisher(); - GetEgressPointerOutput adjacency = resolveAdjacency(dpId, vpnId, vrfEntry); - long groupId = -1; - boolean isLocalRoute = false; - if(adjacency != null) { - groupId = adjacency.getEgressPointer(); - isLocalRoute = adjacency.isLocalDestination(); - } - if(groupId == -1) { - LOG.error("Could not get nexthop group id for nexthop: {} in vpn {}", - vrfEntry.getNextHopAddress(), rd); - LOG.warn("Failed to add Route: {} in vpn: {}", - vrfEntry.getDestPrefix(), rd); - return; + boolean isRemoteRoute = true; + if (localDpnId == null) { + // localDpnId is not known when clean up happens for last vm for a vpn on a dpn + VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix()); + if(localNextHopInfo == null) { + //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn + Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix()); + if (extra_route != null) { + localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, extra_route.getNexthopIp()); + } + } + if (localNextHopInfo != null) { + isRemoteRoute = (!remoteDpnId.equals(localNextHopInfo.getDpnId())); + } } - - makeConnectedRoute(dpId, vpnId, vrfEntry, rd, groupId, NwConstants.DEL_FLOW); - - if (isLocalRoute) { - makeLFibTableEntry(dpId, vrfEntry.getLabel(), groupId, vrfEntry.getNextHopAddress(), NwConstants.DEL_FLOW); + if (isRemoteRoute) { + makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW); + LOG.debug("Successfully delete fib entry for "+ vrfEntry.getDestPrefix() + " vpnId "+vpnId); + } else{ + LOG.debug("Did not delete fib entry rd: {} =, prefix: {} as it is local to dpn {}", rd, vrfEntry.getDestPrefix(), remoteDpnId); } - - LOG.debug("Successfully delete fib entry for "+ vrfEntry.getDestPrefix() + " vpnId "+vpnId); } private long getIpAddress(byte[] rawIpAddress) { @@ -261,17 +534,18 @@ public class FibManager extends AbstractDataChangeListener implements + ((rawIpAddress[2] & 0xFF) << (1 * 8)) + (rawIpAddress[3] & 0xFF)) & 0xffffffffL; } - private void makeConnectedRoute(long dpId, long vpnId, VrfEntry vrfEntry, String rd, - long groupId, int addOrRemove) { + private void makeConnectedRoute(BigInteger dpId, long vpnId, VrfEntry vrfEntry, String rd, + List actionInfos, int addOrRemove) { + LOG.trace("makeConnectedRoute: vrfEntry {}",vrfEntry); String values[] = vrfEntry.getDestPrefix().split("/"); - LOG.debug("Adding route to DPN. ip {} masklen {}", values[0], values[1]); String ipAddress = values[0]; - int prefixLength = Integer.parseInt(values[1]); + int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]); + LOG.debug("Adding route to DPN. ip {} masklen {}", ipAddress, prefixLength); InetAddress destPrefix = null; try { destPrefix = InetAddress.getByName(ipAddress); } catch (UnknownHostException e) { - LOG.error("UnknowHostException in addRoute. Failed to add Route for ipPrefix {}", vrfEntry.getDestPrefix()); + LOG.error("UnknowHostException in addRoute. Failed to add Route for ipPrefix {}", vrfEntry.getDestPrefix()); return; } @@ -289,31 +563,32 @@ public class FibManager extends AbstractDataChangeListener implements } List instructions = new ArrayList(); - List actionsInfos = new ArrayList(); - if(addOrRemove == NwConstants.ADD_FLOW) { - actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId)})); - actionsInfos.add(new ActionInfo(ActionType.push_mpls, new String[] { Long.toString(vrfEntry.getLabel())})); - instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos)); + instructions.add(new InstructionInfo(InstructionType.write_actions, actionInfos)); } - String flowRef = getFlowRef(dpId, L3_FIB_TABLE, rd, destPrefix); + String flowRef = getFlowRef(dpId, NwConstants.L3_FIB_TABLE, rd, destPrefix); FlowEntity flowEntity; int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength; - flowEntity = MDSALUtil.buildFlowEntity(dpId, L3_FIB_TABLE, flowRef, + flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_FIB_TABLE, flowRef, priority, flowRef, 0, 0, COOKIE_VM_FIB_TABLE, matches, instructions); if (addOrRemove == NwConstants.ADD_FLOW) { - mdsalManager.installFlow(flowEntity); + /* We need to call sync API to install flow so that 2 DS operations on the same object do not + * happen at same time. However, MDSALManager's syncInstallFlow takes a delay time (or uses a default one) to wait + * for or for notification that operational DS write for flows is done. We do not turn on the stats writing for flows, + * so that notification never comes, so we do not need that wait. Sending the lowest value of wait "1 ms" since 0 wait means + * wait indefinitely. */ + mdsalManager.syncInstallFlow(flowEntity, 1); } else { - mdsalManager.removeFlow(flowEntity); + mdsalManager.syncRemoveFlow(flowEntity, 1); } } - private void makeLFibTableEntry(long dpId, long label, long groupId, + private void makeLFibTableEntry(BigInteger dpId, long label, long groupId, String nextHop, int addOrRemove) { List matches = new ArrayList(); matches.add(new MatchInfo(MatchFieldType.eth_type, @@ -322,77 +597,271 @@ public class FibManager extends AbstractDataChangeListener implements List instructions = new ArrayList(); List actionsInfos = new ArrayList(); + actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{})); actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) })); instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos)); // Install the flow entry in L3_LFIB_TABLE - String flowRef = getFlowRef(dpId, L3_LFIB_TABLE, label, nextHop); + String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, label, nextHop); FlowEntity flowEntity; - flowEntity = MDSALUtil.buildFlowEntity(dpId, L3_LFIB_TABLE, flowRef, + flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_LFIB_TABLE, flowRef, DEFAULT_FIB_FLOW_PRIORITY, flowRef, 0, 0, COOKIE_VM_LFIB_TABLE, matches, instructions); if (addOrRemove == NwConstants.ADD_FLOW) { - mdsalManager.installFlow(flowEntity); + /* We need to call sync API to install flow so that 2 DS operations on the same object do not + * happen at same time. However, MDSALManager's syncInstallFlow takes a delay time (or uses a default one) to wait + * for or for notification that operational DS write for flows is done. We do not turn on the stats writing for flows, + * so that notification never comes, so we do not need that wait. Sending the lowest value of wait "1 ms" since 0 wait means + * wait indefinitely. */ + + mdsalManager.syncInstallFlow(flowEntity, 1); } else { - mdsalManager.removeFlow(flowEntity); + mdsalManager.syncRemoveFlow(flowEntity, 1); + } + LOG.debug("LFIB Entry for dpID {} : label : {} group {} modified successfully {}",dpId, label, groupId ); + } + + private void deleteLocalAdjacency(final BigInteger dpId, final long vpnId, final String ipAddress) { + LOG.trace("deleteLocalAdjacency called with dpid {}, vpnId{}, ipAddress {}",dpId, vpnId, ipAddress); + try { + nextHopManager.removeLocalNextHop(dpId, vpnId, ipAddress); + } catch (NullPointerException e) { + LOG.trace("", e); + } + } + + public void populateFibOnNewDpn(BigInteger dpnId, long vpnId, String rd) { + LOG.trace("New dpn {} for vpn {} : populateFibOnNewDpn", dpnId, rd); + InstanceIdentifier id = buildVrfId(rd); + String lockOnDpnVpn = new String(dpnId.toString()+ vpnId); + synchronized (lockOnDpnVpn.intern()) { + Optional vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id); + if (vrfTable.isPresent()) { + for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) { + // Passing null as we don't know the dpn + // to which prefix is attached at this point + createRemoteFibEntry(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry); + } + } + } + } + + public void populateFibOnDpn(BigInteger dpnId, long vpnId, String rd, String nexthopIp) { + LOG.trace("dpn {} for vpn {}, nexthopIp {} : populateFibOnDpn", dpnId, rd, nexthopIp); + InstanceIdentifier id = buildVrfId(rd); + String lockOnDpnVpn = new String(dpnId.toString()+ vpnId); + synchronized (lockOnDpnVpn.intern()) { + Optional vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id); + if (vrfTable.isPresent()) { + for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) { + // Passing null as we don't know the dpn + // to which prefix is attached at this point + if (nexthopIp == vrfEntry.getNextHopAddress()) { + createRemoteFibEntry(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry); + } + } + } } - LOG.debug("LFIB Entry for dpID {} : label : {} grpup {} modified successfully {}",dpId, label, groupId ); } - private String getFlowRef(long dpnId, short tableId, long label, String nextHop) { + public void cleanUpDpnForVpn(BigInteger dpnId, long vpnId, String rd) { + LOG.trace("Remove dpn {} for vpn {} : cleanUpDpnForVpn", dpnId, rd); + InstanceIdentifier id = buildVrfId(rd); + String lockOnDpnVpn = new String(dpnId.toString()+ vpnId); + synchronized (lockOnDpnVpn.intern()) { + Optional vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id); + if (vrfTable.isPresent()) { + for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) { + // Passing null as we don't know the dpn + // to which prefix is attached at this point + deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry); + } + } + } + } + + public void cleanUpDpnForVpn(BigInteger dpnId, long vpnId, String rd, String nexthopIp) { + LOG.trace("dpn {} for vpn {}, nexthopIp {} : cleanUpDpnForVpn", dpnId, rd, nexthopIp); + InstanceIdentifier id = buildVrfId(rd); + String lockOnDpnVpn = new String(dpnId.toString()+ vpnId); + synchronized (lockOnDpnVpn.intern()) { + Optional vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id); + if (vrfTable.isPresent()) { + for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) { + // Passing null as we don't know the dpn + // to which prefix is attached at this point + if (nexthopIp == vrfEntry.getNextHopAddress()) { + deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry); + } + } + } + } + } + + public static InstanceIdentifier buildVrfId(String rd) { + InstanceIdentifierBuilder idBuilder = + InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd)); + InstanceIdentifier id = idBuilder.build(); + return id; + } + + private String getFlowRef(BigInteger dpnId, short tableId, long label, String nextHop) { return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR) .append(tableId).append(NwConstants.FLOWID_SEPARATOR) .append(label).append(NwConstants.FLOWID_SEPARATOR) .append(nextHop).toString(); } - private String getFlowRef(long dpnId, short tableId, String rd, InetAddress destPrefix) { + private String getFlowRef(BigInteger dpnId, short tableId, String rd, InetAddress destPrefix) { return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR) .append(tableId).append(NwConstants.FLOWID_SEPARATOR) .append(rd).append(NwConstants.FLOWID_SEPARATOR) .append(destPrefix.getHostAddress()).toString(); } - private GetEgressPointerOutput resolveAdjacency(final long dpId, final long vpnId, - final VrfEntry vrfEntry) { - GetEgressPointerOutput adjacency = null; + protected String resolveAdjacency(final BigInteger localDpnId, final BigInteger remoteDpnId, + final long vpnId, final VrfEntry vrfEntry, String rd) { + String adjacency = null; + boolean staticRoute = false; + LOG.trace("resolveAdjacency called with localdpid{} remotedpid {}, vpnId{}, VrfEntry {}", localDpnId, remoteDpnId, vpnId, vrfEntry); try { - Future> result = - l3nexthopService.getEgressPointer(new GetEgressPointerInputBuilder().setDpnId(dpId) - .setIpPrefix(vrfEntry.getDestPrefix()) - .setNexthopIp(vrfEntry.getNextHopAddress()) - .setVpnId(vpnId) - .build()); - RpcResult rpcResult = result.get(); - if (rpcResult.isSuccessful()) { - adjacency = rpcResult.getResult(); - } else { - LOG.error("Next hop information not available"); - } - } catch (NullPointerException | InterruptedException | ExecutionException e) { + Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix()); + if(extra_route != null) { + staticRoute = true; + } + + adjacency = + nextHopManager.getRemoteNextHopPointer(localDpnId, remoteDpnId, vpnId, + (staticRoute == true) ? extra_route.getNexthopIp() + "/32" : vrfEntry.getDestPrefix(), + vrfEntry.getNextHopAddress()); + } catch (NullPointerException e) { LOG.trace("", e); } return adjacency; } - private Long getVpnId(String rd) { - Long vpnId = null; - InstanceIdentifier id = InstanceIdentifier.create(VpnInstances.class); - Optional vpnInstances = read(LogicalDatastoreType.OPERATIONAL, id); - if(vpnInstances.isPresent()) { - List vpns = vpnInstances.get().getVpnInstance(); - for(VpnInstance vpn : vpns) { - if(vpn.getIpv4Family().getRouteDistinguisher().equals(rd)) { - VpnInstance1 vpnInstanceId = vpn.getAugmentation(VpnInstance1.class); - if (vpnInstanceId != null) { - vpnId = vpnInstanceId.getVpnId(); - break; - } + protected VpnInstanceOpDataEntry getVpnInstance(String rd) { + InstanceIdentifier id = InstanceIdentifier.create(VpnInstanceOpData.class).child( + VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd)); + Optional vpnInstanceOpData = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id); + if(vpnInstanceOpData.isPresent()) { + return vpnInstanceOpData.get(); + } + return null; + } + + public void processNodeAdd(BigInteger dpnId) { + LOG.debug("Received notification to install TableMiss entries for dpn {} ", dpnId); + makeTableMissFlow(dpnId, NwConstants.ADD_FLOW); + makeL3IntfTblMissFlow(dpnId, NwConstants.ADD_FLOW); + } + + private void makeTableMissFlow(BigInteger dpnId, int addOrRemove) { + final BigInteger COOKIE_TABLE_MISS = new BigInteger("1030000", 16); + // Instruction to goto L3 InterfaceTable + List instructions = new ArrayList(); + instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_INTERFACE_TABLE })); + List matches = new ArrayList(); + FlowEntity flowEntityLfib = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_LFIB_TABLE, + getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, NwConstants.TABLE_MISS_FLOW), + NwConstants.TABLE_MISS_PRIORITY, "Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions); + + FlowEntity flowEntityFib = MDSALUtil.buildFlowEntity(dpnId,NwConstants.L3_FIB_TABLE, getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, NwConstants.TABLE_MISS_FLOW), + NwConstants.TABLE_MISS_PRIORITY, "FIB Table Miss Flow", 0, 0, COOKIE_VM_FIB_TABLE, + matches, instructions); + + if (addOrRemove == NwConstants.ADD_FLOW) { + LOG.debug("Invoking MDSAL to install Table Miss Entries"); + mdsalManager.installFlow(flowEntityLfib); + mdsalManager.installFlow(flowEntityFib); + } else { + mdsalManager.removeFlow(flowEntityLfib); + mdsalManager.removeFlow(flowEntityFib); + + } + } + + private String getFlowRef(BigInteger dpnId, short tableId, int tableMiss) { + return new StringBuffer().append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR) + .append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(tableMiss) + .append(FLOWID_PREFIX).toString(); + } + + /* + * Install flow entry in protocol table to forward mpls + * coming through gre tunnel to LFIB table. + */ + private void makeProtocolTableFlow(BigInteger dpnId, int addOrRemove) { + final BigInteger COOKIE_PROTOCOL_TABLE = new BigInteger("1070000", 16); + // Instruction to goto L3 InterfaceTable + List instructions = new ArrayList<>(); + instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] {NwConstants.L3_LFIB_TABLE})); + List matches = new ArrayList(); + matches.add(new MatchInfo(MatchFieldType.eth_type, + new long[] { 0x8847L })); + FlowEntity flowEntityToLfib = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_PROTOCOL_TABLE, + getFlowRef(dpnId, NwConstants.L3_PROTOCOL_TABLE, + NwConstants.L3_LFIB_TABLE), + DEFAULT_FIB_FLOW_PRIORITY, + "Protocol Table For LFIB", + 0, 0, + COOKIE_PROTOCOL_TABLE, + matches, instructions); + + if (addOrRemove == NwConstants.ADD_FLOW) { + LOG.debug("Invoking MDSAL to install Protocol Entries for dpn {}", dpnId); + mdsalManager.installFlow(flowEntityToLfib); + } else { + mdsalManager.removeFlow(flowEntityToLfib); + } + } + + public List printFibEntries() { + List result = new ArrayList(); + result.add(String.format(" %-7s %-20s %-20s %-7s", "RD", "Prefix", "Nexthop", "Label")); + result.add("-------------------------------------------------------------------"); + InstanceIdentifier id = InstanceIdentifier.create(FibEntries.class); + Optional fibEntries = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id); + if (fibEntries.isPresent()) { + List vrfTables = fibEntries.get().getVrfTables(); + for (VrfTables vrfTable : vrfTables) { + for (VrfEntry vrfEntry : vrfTable.getVrfEntry()) { + result.add(String.format(" %-7s %-20s %-20s %-7s", vrfTable.getRouteDistinguisher(), + vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddress(), vrfEntry.getLabel())); } } } - return vpnId; + return result; + } + + private void makeL3IntfTblMissFlow(BigInteger dpnId, int addOrRemove) { + List instructions = new ArrayList(); + List matches = new ArrayList(); + final BigInteger COOKIE_TABLE_MISS = new BigInteger("1030000", 16); + // Instruction to clear metadata except SI and LportTag bits + instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { + CLEAR_METADATA, METADATA_MASK_CLEAR })); + // Instruction to clear action + instructions.add(new InstructionInfo(InstructionType.clear_actions)); + // Instruction to goto L3 InterfaceTable + + List actionsInfos = new ArrayList (); + actionsInfos.add(new ActionInfo(ActionType.nx_resubmit, new String[]{ + Short.toString(NwConstants.LPORT_DISPATCHER_TABLE)})); + instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos)); + //instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.LPORT_DISPATCHER_TABLE })); + + FlowEntity flowEntityL3Intf = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_INTERFACE_TABLE, + getFlowRef(dpnId, NwConstants.L3_INTERFACE_TABLE, NwConstants.TABLE_MISS_FLOW), + NwConstants.TABLE_MISS_PRIORITY, "L3 Interface Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions); + if (addOrRemove == NwConstants.ADD_FLOW) { + LOG.info("Invoking MDSAL to install L3 interface Table Miss Entries"); + mdsalManager.installFlow(flowEntityL3Intf); + } else { + mdsalManager.removeFlow(flowEntityL3Intf); + } } + }