boolean removeCentralizedRouter(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
BigInteger primarySwitchId, BigInteger dpnId) throws ExecutionException, InterruptedException;
+ /**
+ * Handles changes to external router.
+ * @param origRouter the Orignal router.
+ * @param updatedRouter the Updated router.
+ * @return returns success/failure.
+ */
+ boolean handleRouterUpdate(TypedReadWriteTransaction<Configuration> confTx, Routers origRouter,
+ Routers updatedRouter) throws ExecutionException, InterruptedException;
}
SNAT_ALL_SWITCH_DISBL,
SNAT_ROUTER_ENBL,
SNAT_ROUTER_DISBL,
+ SNAT_ROUTER_UPDATE,
CNT_ROUTER_ALL_SWITCH_ENBL,
CNT_ROUTER_ALL_SWITCH_DISBL,
CNT_ROUTER_ENBL,
import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
-import javax.annotation.Nullable;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
import org.opendaylight.genius.mdsalutil.ActionInfo;
import org.opendaylight.genius.mdsalutil.BucketInfo;
-import org.opendaylight.genius.mdsalutil.FlowEntity;
import org.opendaylight.genius.mdsalutil.GroupEntity;
import org.opendaylight.genius.mdsalutil.InstructionInfo;
import org.opendaylight.genius.mdsalutil.MDSALUtil;
import org.opendaylight.genius.mdsalutil.MatchInfo;
-import org.opendaylight.genius.mdsalutil.MatchInfoBase;
import org.opendaylight.genius.mdsalutil.MetaDataUtil;
import org.opendaylight.genius.mdsalutil.NWUtil;
import org.opendaylight.genius.mdsalutil.NwConstants;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeGre;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
return true;
}
+ @Override
+ public boolean handleRouterUpdate(TypedReadWriteTransaction<Configuration> confTx,
+ Routers origRouter, Routers updatedRouter) throws ExecutionException, InterruptedException {
+ return true;
+ }
+
protected void addCommonEntriesForNaptSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
BigInteger dpnId) {
String routerName = routers.getRouterName();
String flowRef = getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, routerId);
flowRef = flowRef + "inbound" + externalIp;
- addFlow(confTx, dpnId, NwConstants.L3_FIB_TABLE, flowRef, NatConstants.SNAT_FIB_FLOW_PRIORITY, flowRef,
- NwConstants.COOKIE_SNAT_TABLE, matches, instructionInfo);
+ NatUtil.addFlow(confTx, mdsalManager,dpnId, NwConstants.L3_FIB_TABLE, flowRef,
+ NatConstants.SNAT_FIB_FLOW_PRIORITY, flowRef, NwConstants.COOKIE_SNAT_TABLE, matches,
+ instructionInfo);
String rd = NatUtil.getVpnRd(dataBroker, subNetId);
String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, dpnId);
String ipPrefix = externalIp + "/32";
String externalIp, Long routerId, String subNetId) throws ExecutionException, InterruptedException {
String flowRef = getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, routerId);
flowRef = flowRef + "inbound" + externalIp;
- removeFlow(confTx, dpnId, NwConstants.L3_FIB_TABLE, flowRef);
+ NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.L3_FIB_TABLE, flowRef);
String rd = NatUtil.getVpnRd(dataBroker, subNetId);
String ipPrefix = externalIp + "/32";
fibManager.removeFibEntry(rd, ipPrefix, confTx);
List<InstructionInfo> instructions = new ArrayList<>();
instructions.add(new InstructionApplyActions(actionsInfos));
String flowRef = getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId);
- addFlow(confTx, dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef, NatConstants.DEFAULT_TS_FLOW_PRIORITY,
- flowRef, NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
+ NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef,
+ NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef, NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
}
protected void removeTerminatingServiceTblEntry(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
+ "for switch {}, routerId {}", dpnId, routerId);
String flowRef = getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId);
- removeFlow(confTx, dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef);
+ NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef);
}
protected void addSnatMissEntry(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
Long routerId, String routerName, BigInteger primarySwitchId) {
LOG.debug("installSnatMissEntry : Installing SNAT miss entry in switch {}", dpnId);
List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
- String ifNamePrimary = getTunnelInterfaceName(dpnId, primarySwitchId);
+ String ifNamePrimary = NatUtil.getTunnelInterfaceName(dpnId, primarySwitchId, itmManager);
List<BucketInfo> listBucketInfo = new ArrayList<>();
if (ifNamePrimary != null) {
LOG.debug("installSnatMissEntry : On Non- Napt switch , Primary Tunnel interface is {}", ifNamePrimary);
List<InstructionInfo> instructions = new ArrayList<>();
instructions.add(new InstructionApplyActions(actionsInfo));
String flowRef = getFlowRef(dpnId, NwConstants.PSNAT_TABLE, routerId);
- addFlow(confTx, dpnId, NwConstants.PSNAT_TABLE, flowRef, NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef,
- NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
+ NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.PSNAT_TABLE, flowRef,
+ NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, NwConstants.COOKIE_SNAT_TABLE, matches,
+ instructions);
}
protected void removeSnatMissEntry(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
dpnId, routerName, groupId);
String flowRef = getFlowRef(dpnId, NwConstants.PSNAT_TABLE, routerId);
- removeFlow(confTx, dpnId, NwConstants.PSNAT_TABLE, flowRef);
+ NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.PSNAT_TABLE, flowRef);
}
protected void addInboundTerminatingServiceTblEntry(TypedReadWriteTransaction<Configuration> confTx,
BigInteger dpnId, Long routerId, long extSubnetId) {
- //Install the tunnel table entry in NAPT switch for inbound traffic to SNAP IP from a non a NAPT switch.
+ //Install the tunnel table entry in NAPT switch for inbound traffic to SNAT IP from a non a NAPT switch.
LOG.info("installInboundTerminatingServiceTblEntry : creating entry for Terminating Service Table "
+ "for switch {}, routerId {}", dpnId, routerId);
List<MatchInfo> matches = new ArrayList<>();
List<InstructionInfo> instructions = new ArrayList<>();
instructions.add(new InstructionApplyActions(actionsInfos));
String flowRef = getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId.longValue()) + "INBOUND";
- addFlow(confTx, dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef, NatConstants.SNAT_FIB_FLOW_PRIORITY, flowRef,
- NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
+ NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef,
+ NatConstants.SNAT_FIB_FLOW_PRIORITY, flowRef, NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
}
protected void removeInboundTerminatingServiceTblEntry(TypedReadWriteTransaction<Configuration> confTx,
BigInteger dpnId, Long routerId) throws ExecutionException, InterruptedException {
- //Install the tunnel table entry in NAPT switch for inbound traffic to SNAP IP from a non a NAPT switch.
+ //Install the tunnel table entry in NAPT switch for inbound traffic to SNAT IP from a non a NAPT switch.
LOG.info("installInboundTerminatingServiceTblEntry : creating entry for Terminating Service Table "
+ "for switch {}, routerId {}", dpnId, routerId);
String flowRef = getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId.longValue()) + "INBOUND";
- removeFlow(confTx, dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef);
+ NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef);
}
protected void addDefaultFibRouteForSNAT(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
instructions.add(new InstructionGotoTable(NwConstants.PSNAT_TABLE));
String flowRef = "DefaultFibRouteForSNAT" + getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, extNetId);
- addFlow(confTx, dpnId, NwConstants.L3_FIB_TABLE, flowRef, NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef,
- NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
+ NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.L3_FIB_TABLE, flowRef,
+ NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, NwConstants.COOKIE_SNAT_TABLE, matches,
+ instructions);
}
protected void removeDefaultFibRouteForSNAT(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
Long extNetId) throws ExecutionException, InterruptedException {
String flowRef = "DefaultFibRouteForSNAT" + getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, extNetId);
- removeFlow(confTx, dpnId, NwConstants.L3_FIB_TABLE, flowRef);
+ NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.L3_FIB_TABLE, flowRef);
}
protected String getFlowRef(BigInteger dpnId, short tableId, long routerID) {
+ tableId + NatConstants.FLOWID_SEPARATOR + routerID;
}
- protected void addFlow(TypedWriteTransaction<Configuration> confTx, BigInteger dpId, short tableId,
- String flowId, int priority, String flowName, BigInteger cookie, List<? extends MatchInfoBase> matches,
- List<InstructionInfo> instructions) {
- FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId, flowId, priority, flowName,
- NatConstants.DEFAULT_IDLE_TIMEOUT, NatConstants.DEFAULT_IDLE_TIMEOUT, cookie, matches,
- instructions);
- LOG.trace("syncFlow : Installing DpnId {}, flowId {}", dpId, flowId);
- mdsalManager.addFlow(confTx, flowEntity);
- }
-
- protected void removeFlow(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpId, short tableId,
- String flowId) throws ExecutionException, InterruptedException {
- LOG.trace("syncFlow : Removing Acl Flow DpnId {}, flowId {}", dpId, flowId);
- mdsalManager.removeFlow(confTx, dpId, flowId, tableId);
- }
-
protected long createGroupId(String groupIdKey) {
AllocateIdInput getIdInput = new AllocateIdInputBuilder()
.setPoolName(NatConstants.SNAT_IDPOOL_NAME).setIdKey(groupIdKey)
return "snatmiss." + routerName;
}
- @Nullable
- protected String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId) {
- Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
- RpcResult<GetTunnelInterfaceNameOutput> rpcResult;
- try {
- Future<RpcResult<GetTunnelInterfaceNameOutput>> result = itmManager
- .getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder().setSourceDpid(srcDpId)
- .setDestinationDpid(dstDpId).setTunnelType(tunType).build());
- rpcResult = result.get();
- if (!rpcResult.isSuccessful()) {
- tunType = TunnelTypeGre.class ;
- result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
- .setSourceDpid(srcDpId)
- .setDestinationDpid(dstDpId)
- .setTunnelType(tunType)
- .build());
- rpcResult = result.get();
- if (!rpcResult.isSuccessful()) {
- LOG.warn("getTunnelInterfaceName : RPC Call to getTunnelInterfaceId returned with Errors {}",
- rpcResult.getErrors());
- } else {
- return rpcResult.getResult().getInterfaceName();
- }
- LOG.warn("getTunnelInterfaceName : RPC Call to getTunnelInterfaceId returned with Errors {}",
- rpcResult.getErrors());
- } else {
- return rpcResult.getResult().getInterfaceName();
- }
- } catch (InterruptedException | ExecutionException | NullPointerException e) {
- LOG.error("getTunnelInterfaceName : Exception when getting tunnel interface Id for tunnel "
- + "between {} and {}", srcDpId, dstDpId);
- }
- return null;
- }
-
protected void removeMipAdjacencies(Routers routers) {
LOG.info("removeMipAdjacencies for router {}", routers.getRouterName());
String externalSubNetId = null;
instructions.add(new InstructionApplyActions(actionsInfos));
String flowRef = getFlowRef(dpnId, NwConstants.PSNAT_TABLE, routerId);
- addFlow(confTx, dpnId, NwConstants.PSNAT_TABLE, flowRef, NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef,
- NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
+ NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.PSNAT_TABLE, flowRef,
+ NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, NwConstants.COOKIE_SNAT_TABLE, matches,
+ instructions);
}
protected void removeSnatMissEntryForPrimrySwch(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
LOG.info("installSnatSpecificEntriesForNaptSwitch : called for the primary NAPT switch dpnId {}", dpnId);
String flowRef = getFlowRef(dpnId, NwConstants.PSNAT_TABLE, routerId);
- removeFlow(confTx, dpnId, NwConstants.PSNAT_TABLE, flowRef);
+ NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.PSNAT_TABLE, flowRef);
}
protected void addOutboundTblTrackEntry(TypedWriteTransaction<Configuration> confTx, BigInteger dpnId,
instructionInfo.add(new InstructionApplyActions(listActionInfo));
String flowRef = getFlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId) + "trkest";
- addFlow(confTx, dpnId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef, NatConstants.SNAT_TRK_FLOW_PRIORITY, flowRef,
- NwConstants.COOKIE_SNAT_TABLE, matches, instructionInfo);
+ NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef,
+ NatConstants.SNAT_TRK_FLOW_PRIORITY, flowRef, NwConstants.COOKIE_SNAT_TABLE, matches,
+ instructionInfo);
}
protected void removeOutboundTblTrackEntry(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
LOG.info("createOutboundTblTrackEntry : called for switch {}, routerId {}", dpnId, routerId);
String flowRef = getFlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId) + "trkest";
- removeFlow(confTx, dpnId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef);
+ NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef);
}
protected void addOutboundTblEntry(TypedWriteTransaction<Configuration> confTx, BigInteger dpnId, long routerId,
List<InstructionInfo> instructions = new ArrayList<>();
instructions.add(new InstructionApplyActions(actionsInfos));
String flowRef = getFlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId);
- addFlow(confTx, dpnId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef, NatConstants.SNAT_NEW_FLOW_PRIORITY,
- flowRef, NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
+ NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef,
+ NatConstants.SNAT_NEW_FLOW_PRIORITY, flowRef, NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
}
protected void removeOutboundTblEntry(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
long routerId) throws ExecutionException, InterruptedException {
LOG.info("createOutboundTblEntry : dpId {} and routerId {}", dpnId, routerId);
String flowRef = getFlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId);
- removeFlow(confTx, dpnId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef);
+ NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef);
}
protected void addNaptPfibFlow(TypedReadWriteTransaction<Configuration> confTx, Routers routers, BigInteger dpnId,
instructions.add(new InstructionApplyActions(listActionInfo));
String flowRef = getFlowRef(dpnId, NwConstants.NAPT_PFIB_TABLE, routerId);
flowRef = flowRef + "OUTBOUND";
- addFlow(confTx, dpnId, NwConstants.NAPT_PFIB_TABLE, flowRef, NatConstants.SNAT_TRK_FLOW_PRIORITY,
- flowRef, NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
+ NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.NAPT_PFIB_TABLE, flowRef,
+ NatConstants.SNAT_TRK_FLOW_PRIORITY, flowRef, NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
}
protected void removeNaptPfibFlow(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
Long extNetId = NatUtil.getVpnId(confTx, routers.getNetworkId().getValue());
LOG.info("installNaptPfibFlow : dpId {}, extNetId {}", dpnId, extNetId);
String flowRef = getFlowRef(dpnId, NwConstants.NAPT_PFIB_TABLE, routerId) + "OUTBOUND";
- removeFlow(confTx, dpnId, NwConstants.NAPT_PFIB_TABLE, flowRef);
+ NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.NAPT_PFIB_TABLE, flowRef);
}
protected void addInboundEntry(TypedWriteTransaction<Configuration> confTx, BigInteger dpnId, long routerId,
instructions.add(new InstructionApplyActions(actionsInfos));
String flowRef = getFlowRef(dpnId, NwConstants.INBOUND_NAPT_TABLE, routerId);
flowRef = flowRef + "OUTBOUND";
- addFlow(confTx, dpnId, NwConstants.INBOUND_NAPT_TABLE, flowRef, NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef,
- NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
+ NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.INBOUND_NAPT_TABLE, flowRef,
+ NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef, NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
}
protected void removeInboundEntry(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
LOG.info("installInboundEntry : dpId {} and routerId {}", dpnId, routerId);
String flowRef = getFlowRef(dpnId, NwConstants.INBOUND_NAPT_TABLE, routerId) + "OUTBOUND";
- removeFlow(confTx, dpnId, NwConstants.INBOUND_NAPT_TABLE, flowRef);
+ NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.INBOUND_NAPT_TABLE, flowRef);
}
protected void addNaptPfibEntry(TypedWriteTransaction<Configuration> confTx, BigInteger dpnId, long routerId) {
instructionInfo.add(new InstructionApplyActions(listActionInfo));
String flowRef = getFlowRef(dpnId, NwConstants.NAPT_PFIB_TABLE, routerId) + "INBOUND";
- addFlow(confTx, dpnId, NwConstants.NAPT_PFIB_TABLE, flowRef, NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef,
- NwConstants.COOKIE_SNAT_TABLE, matches, instructionInfo);
+ NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.NAPT_PFIB_TABLE, flowRef,
+ NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, NwConstants.COOKIE_SNAT_TABLE, matches,
+ instructionInfo);
}
protected void removeNaptPfibEntry(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
long routerId) throws ExecutionException, InterruptedException {
LOG.info("installNaptPfibEntry : called for dpnId {} and routerId {} ", dpnId, routerId);
String flowRef = getFlowRef(dpnId, NwConstants.NAPT_PFIB_TABLE, routerId) + "INBOUND";
- removeFlow(confTx, dpnId, NwConstants.NAPT_PFIB_TABLE, flowRef);
+ NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.NAPT_PFIB_TABLE, flowRef);
}
}
--- /dev/null
+/*
+ * Copyright (c) 2018 Red Hat, Inc. 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,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netvirt.natservice.internal;
+
+import static org.opendaylight.netvirt.natservice.internal.AbstractSnatService.LOAD_END;
+import static org.opendaylight.netvirt.natservice.internal.AbstractSnatService.LOAD_START;
+import static org.opendaylight.netvirt.natservice.internal.NatUtil.getGroupIdKey;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.genius.infra.Datastore.Configuration;
+import org.opendaylight.genius.infra.TypedReadWriteTransaction;
+import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
+import org.opendaylight.genius.mdsalutil.ActionInfo;
+import org.opendaylight.genius.mdsalutil.BucketInfo;
+import org.opendaylight.genius.mdsalutil.GroupEntity;
+import org.opendaylight.genius.mdsalutil.InstructionInfo;
+import org.opendaylight.genius.mdsalutil.MDSALUtil;
+import org.opendaylight.genius.mdsalutil.MatchInfo;
+import org.opendaylight.genius.mdsalutil.MatchInfoBase;
+import org.opendaylight.genius.mdsalutil.MetaDataUtil;
+import org.opendaylight.genius.mdsalutil.NWUtil;
+import org.opendaylight.genius.mdsalutil.NwConstants;
+import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
+import org.opendaylight.genius.mdsalutil.actions.ActionNxLoadInPort;
+import org.opendaylight.genius.mdsalutil.actions.ActionNxLoadMetadata;
+import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
+import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId;
+import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
+import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
+import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
+import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
+import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
+import org.opendaylight.netvirt.natservice.api.SnatServiceListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.routers.ExternalIps;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Ipv6ForwardingService implements SnatServiceListener {
+ private static final Logger LOG = LoggerFactory.getLogger(Ipv6ForwardingService.class);
+
+ protected final DataBroker dataBroker;
+ protected final IMdsalApiManager mdsalManager;
+ protected final IdManagerService idManager;
+ protected final NAPTSwitchSelector naptSwitchSelector;
+ protected final ItmRpcService itmManager;
+ protected final OdlInterfaceRpcService odlInterfaceRpcService;
+ protected final IInterfaceManager interfaceManager;
+ protected final Ipv6SubnetFlowProgrammer ipv6SubnetFlowProgrammer;
+
+ public Ipv6ForwardingService(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
+ final ItmRpcService itmManager,
+ final OdlInterfaceRpcService odlInterfaceRpcService,
+ final IdManagerService idManager,
+ final NAPTSwitchSelector naptSwitchSelector,
+ final IInterfaceManager interfaceManager,
+ final Ipv6SubnetFlowProgrammer ipv6SubnetFlowProgrammer) {
+ this.dataBroker = dataBroker;
+ this.mdsalManager = mdsalManager;
+ this.itmManager = itmManager;
+ this.odlInterfaceRpcService = odlInterfaceRpcService;
+ this.idManager = idManager;
+ this.naptSwitchSelector = naptSwitchSelector;
+ this.interfaceManager = interfaceManager;
+ this.ipv6SubnetFlowProgrammer = ipv6SubnetFlowProgrammer;
+ }
+
+ public void init() {
+ LOG.info("Ipv6ForwardingService: {} init", getClass().getSimpleName());
+ }
+
+ @Override
+ public boolean addCentralizedRouterAllSwitch(TypedReadWriteTransaction<Configuration> confTx,
+ Routers routers, BigInteger primarySwitchId) {
+ String routerName = routers.getRouterName();
+ LOG.info("handleSnatAllSwitch : invoked for router {} with NAPTSwitch {} for {} flows",
+ routerName, primarySwitchId, "installing");
+ List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
+ /*
+ * Primary switch handled separately since the pseudo port created may
+ * not be present in the switch list on delete.
+ */
+ addCentralizedRouter(confTx, routers, primarySwitchId, primarySwitchId);
+ for (BigInteger dpnId : switches) {
+ if (primarySwitchId != dpnId) {
+ addCentralizedRouter(confTx, routers, primarySwitchId, dpnId);
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public boolean addCentralizedRouter(TypedReadWriteTransaction<Configuration> confTx,
+ Routers routers, BigInteger primarySwitchId, BigInteger dpnId) {
+ Long routerId = NatUtil.getVpnId(dataBroker, routers.getRouterName());
+ BigInteger routerMetadata = MetaDataUtil.getVpnIdMetadata(routerId);
+
+ if (!dpnId.equals(primarySwitchId)) {
+ LOG.info("handleSnat (non-NAPTSwitch) : {} flows on switch {} for router {}",
+ "Installing", dpnId, routers.getRouterName());
+ // Program default flow from FIB_TABLE(21) to PSNAT_TABLE(26) (egress direction)
+ addIpv6DefaultFibRoute(confTx, dpnId, routerId, routerMetadata);
+
+ // Currently we are only programming flows when ext-net has an IPv6Subnet
+ if (routerHasIpv6ExtSubnet(routers)) {
+ // Program flows on non-NAPTSwitch to send N/S packets to the NAPTSwitch
+ addIpv6PsNatMissEntryNonNaptSwitch(confTx, dpnId, routerId, routers.getRouterName(),
+ primarySwitchId);
+ }
+ } else {
+ LOG.info("handleSnat (NAPTSwitch) : {} flows on switch {} for router {}",
+ "Installing", dpnId, routers.getRouterName());
+ // Program default flow from FIB_TABLE(21) to PSNAT_TABLE(26) (egress direction)
+ addIpv6DefaultFibRoute(confTx, dpnId, routerId, routerMetadata);
+
+ // Program flows from PSNAT_TABLE(26) to OUTBOUND_NAPT_TABLE(46) (egress direction)
+ addIpv6SnatMissEntryForNaptSwitch(confTx, dpnId, routerId, routerMetadata);
+
+ // Program flows in INTERNAL_TUNNEL_TABLE(36) for packets coming from non-NAPTSwitch (egress direction)
+ addIpv6TerminatingServiceTblEntry(confTx, dpnId, routerId, routerMetadata);
+
+ // Program flows from NAPT_PFIB_TABLE(47) to FIB_TABLE(21) (ingress direction)
+ addIpv6NaptPfibInboundFlow(confTx, dpnId, routerId, routerMetadata);
+
+ // Now installing flows that use SubnetInfo
+ ipv6SubnetFlowProgrammer. addSubnetSpecificFlows(confTx, dpnId, routerId, routers, routerMetadata);
+ }
+ return true;
+ }
+
+ @Override
+ public boolean removeCentralizedRouterAllSwitch(TypedReadWriteTransaction<Configuration> confTx,
+ Routers routers, BigInteger primarySwitchId) throws ExecutionException, InterruptedException {
+ String routerName = routers.getRouterName();
+ LOG.info("handleSnatAllSwitch : invoked for router {} with NAPTSwitch {} for {} flows",
+ routerName, primarySwitchId, "removing");
+ List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
+ /*
+ * Primary switch handled separately since the pseudo port created may
+ * not be present in the switch list on delete.
+ */
+ removeCentralizedRouter(confTx, routers, primarySwitchId, primarySwitchId);
+ for (BigInteger dpnId : switches) {
+ if (primarySwitchId != dpnId) {
+ removeCentralizedRouter(confTx, routers, primarySwitchId, dpnId);
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public boolean removeCentralizedRouter(TypedReadWriteTransaction<Configuration> confTx,
+ Routers routers, BigInteger primarySwitchId, BigInteger dpnId)
+ throws ExecutionException, InterruptedException {
+ Long routerId = NatUtil.getVpnId(dataBroker, routers.getRouterName());
+ BigInteger routerMetadata = MetaDataUtil.getVpnIdMetadata(routerId);
+
+ if (!dpnId.equals(primarySwitchId)) {
+ LOG.info("handleSnat (non-NAPTSwitch) : {} flows on switch {} for router {}",
+ "Removing", dpnId, routers.getRouterName());
+ // Program default flow from FIB_TABLE(21) to PSNAT_TABLE(26) (egress direction)
+ addIpv6DefaultFibRoute(confTx, dpnId, routerId, routerMetadata);
+
+ // Currently we are only programming flows when ext-net has an IPv6Subnet
+ if (routerHasIpv6ExtSubnet(routers)) {
+ // Program flows on non-NAPTSwitch to send N/S packets to the NAPTSwitch
+ addIpv6PsNatMissEntryNonNaptSwitch(confTx, dpnId, routerId, routers.getRouterName(),
+ primarySwitchId);
+ }
+ } else {
+ LOG.info("handleSnat (NAPTSwitch) : {} flows on switch {} for router {}",
+ "Removing", dpnId, routers.getRouterName());
+ // Program default flow from FIB_TABLE(21) to PSNAT_TABLE(26) (egress direction)
+ removeIpv6DefaultFibRoute(confTx, dpnId, routerId);
+
+ // Program flows from PSNAT_TABLE(26) to OUTBOUND_NAPT_TABLE(46) (egress direction)
+ removeIpv6SnatMissEntryForNaptSwitch(confTx, dpnId, routerId);
+
+ // Program flows in INTERNAL_TUNNEL_TABLE(36) for packets coming from non-NAPTSwitch (egress direction)
+ removeIpv6TerminatingServiceTblEntry(confTx, dpnId, routerId);
+
+ // Program flows from NAPT_PFIB_TABLE(47) to FIB_TABLE(21) (ingress direction)
+ removeIpv6NaptPfibInboundFlow(confTx, dpnId, routerId);
+
+ // Now installing flows that use SubnetInfo
+ ipv6SubnetFlowProgrammer.removeSubnetSpecificFlows(confTx, dpnId, routerId, routers);
+ }
+ return true;
+ }
+
+ @Override
+ public boolean handleRouterUpdate(TypedReadWriteTransaction<Configuration> confTx,
+ Routers origRouter, Routers updatedRouter) throws ExecutionException, InterruptedException {
+ LOG.info("handleRouterUpdate : originalRouter {}, updatedRouter {}", origRouter, updatedRouter);
+ String routerName = origRouter.getRouterName();
+ BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
+ Long routerId = NatUtil.getVpnId(dataBroker, routerName);
+ BigInteger routerMetadata = MetaDataUtil.getVpnIdMetadata(routerId);
+
+ // If the external network is updated with an IPv6Subnet, program the necessary flows on non-NAPTSwitch
+ if (!routerHasIpv6ExtSubnet(origRouter) && routerHasIpv6ExtSubnet(updatedRouter)) {
+ List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
+ for (BigInteger dpnId : switches) {
+ if (primarySwitchId != dpnId) {
+ LOG.info("handleRouterUpdate (non-NAPTSwitch) : Installing flows on switch {} for router {}",
+ dpnId, routerName);
+ addIpv6PsNatMissEntryNonNaptSwitch(confTx, dpnId, routerId, routerName,
+ primarySwitchId);
+ }
+ }
+ }
+
+ ipv6SubnetFlowProgrammer.removeSubnetSpecificFlows(confTx, primarySwitchId, routerId, origRouter);
+ ipv6SubnetFlowProgrammer.addSubnetSpecificFlows(confTx, primarySwitchId, routerId, updatedRouter,
+ routerMetadata);
+ return true;
+ }
+
+ @Override
+ public boolean addSnatAllSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
+ BigInteger primarySwitchId) {
+ return true;
+ }
+
+ @Override
+ public boolean addSnat(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
+ BigInteger primarySwitchId, BigInteger dpnId) {
+ return true;
+ }
+
+ @Override
+ public boolean removeSnatAllSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
+ BigInteger primarySwitchId) throws ExecutionException, InterruptedException {
+ return true;
+ }
+
+ @Override
+ public boolean removeSnat(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
+ BigInteger primarySwitchId, BigInteger dpnId) throws ExecutionException, InterruptedException {
+ return true;
+ }
+
+
+ protected void addIpv6DefaultFibRoute(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
+ Long routerId, BigInteger routerMetadata) {
+ LOG.debug("installIpv6DefaultFibRoute : Installing default FIB route to PSNAT_TABLE on {}", dpnId);
+ List<MatchInfo> matches = new ArrayList<>();
+ matches.add(MatchEthernetType.IPV6);
+ matches.add(new MatchMetadata(routerMetadata, MetaDataUtil.METADATA_MASK_VRFID));
+
+ List<InstructionInfo> instructions = new ArrayList<>();
+ instructions.add(new InstructionGotoTable(NwConstants.PSNAT_TABLE));
+
+ String flowRef = NatUtil.getIpv6FlowRef(dpnId, NwConstants.L3_FIB_TABLE, routerId);
+ flowRef += ".Outbound";
+ NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.L3_FIB_TABLE, flowRef,
+ NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef,
+ NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
+ }
+
+ protected void removeIpv6DefaultFibRoute(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
+ Long routerId) throws ExecutionException, InterruptedException {
+ LOG.debug("installIpv6DefaultFibRoute : Installing default FIB route to PSNAT_TABLE on {}", dpnId);
+ String flowRef = NatUtil.getIpv6FlowRef(dpnId, NwConstants.L3_FIB_TABLE, routerId);
+ flowRef += ".Outbound";
+ NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.L3_FIB_TABLE, flowRef);
+ }
+
+ protected void addIpv6PsNatMissEntryNonNaptSwitch(TypedReadWriteTransaction<Configuration> confTx,
+ BigInteger dpnId, Long routerId, String routerName, BigInteger primarySwitchId) {
+ LOG.debug("installIpv6PsNatMissEntryNonNaptSwitch : On Non-Napt Switch, installing SNAT miss entry in"
+ + " switch {} for router {}", dpnId, routerName);
+ List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
+ List<BucketInfo> listBucketInfo = new ArrayList<>();
+
+ String ifNamePrimary = NatUtil.getTunnelInterfaceName(dpnId, primarySwitchId, itmManager);
+ if (ifNamePrimary != null) {
+ LOG.debug("installIpv6PsNatMissEntryNonNaptSwitch : On Non-Napt Switch, Primary Tunnel interface is {}",
+ ifNamePrimary);
+ listActionInfoPrimary = NatUtil.getEgressActionsForInterface(odlInterfaceRpcService, itmManager,
+ interfaceManager, ifNamePrimary, routerId, true);
+ } else {
+ LOG.warn("installIpv6PsNatMissEntryNonNaptSwitch: could not get tunnelInterface for {} on Switch {}",
+ primarySwitchId, dpnId);
+ }
+
+ BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
+ listBucketInfo.add(0, bucketPrimary);
+
+ LOG.debug("installIpv6PsNatMissEntryNonNaptSwitch : installSnatMissEntry called for dpnId {} with"
+ + " primaryBucket {} ", dpnId, listBucketInfo.get(0));
+
+ long groupId = createGroupIdForIpv6Router(getGroupIdKey(routerName + "IPv6"));
+ GroupEntity groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll,
+ listBucketInfo);
+ LOG.debug("installing the PSNAT to NAPTSwitch GroupEntity:{} with GroupId: {}", groupEntity, groupId);
+ mdsalManager.addGroup(confTx, groupEntity);
+ List<MatchInfo> matches = new ArrayList<>();
+ matches.add(MatchEthernetType.IPV6);
+ matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
+
+ List<ActionInfo> actionsInfo = new ArrayList<>();
+ actionsInfo.add(new ActionSetFieldTunnelId(BigInteger.valueOf(routerId)));
+ actionsInfo.add(new ActionGroup(groupId));
+ List<InstructionInfo> instructions = new ArrayList<>();
+ instructions.add(new InstructionApplyActions(actionsInfo));
+
+ String flowRef = NatUtil.getIpv6FlowRef(dpnId, NwConstants.PSNAT_TABLE, routerId);
+ NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.PSNAT_TABLE, flowRef,
+ NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef,
+ NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
+ }
+
+ protected void removeIpv6PsNatMissEntryNonNaptSwitch(TypedReadWriteTransaction<Configuration> confTx,
+ BigInteger dpnId, Long routerId, String routerName, BigInteger primarySwitchId)
+ throws ExecutionException, InterruptedException {
+ LOG.debug("installIpv6PsNatMissEntryNonNaptSwitch : On Non-Napt Switch, installing SNAT miss entry in"
+ + " switch {} for router {}", dpnId, routerName);
+ List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
+ List<BucketInfo> listBucketInfo = new ArrayList<>();
+
+ String ifNamePrimary = NatUtil.getTunnelInterfaceName(dpnId, primarySwitchId, itmManager);
+ if (ifNamePrimary != null) {
+ LOG.debug("installIpv6PsNatMissEntryNonNaptSwitch : On Non-Napt Switch, Primary Tunnel interface is {}",
+ ifNamePrimary);
+ listActionInfoPrimary = NatUtil.getEgressActionsForInterface(odlInterfaceRpcService, itmManager,
+ interfaceManager, ifNamePrimary, routerId, true);
+ } else {
+ LOG.warn("installIpv6PsNatMissEntryNonNaptSwitch: could not get tunnelInterface for {} on Switch {}",
+ primarySwitchId, dpnId);
+ }
+
+ BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
+ listBucketInfo.add(0, bucketPrimary);
+
+ LOG.debug("installIpv6PsNatMissEntryNonNaptSwitch : installSnatMissEntry called for dpnId {} with"
+ + " primaryBucket {} ", dpnId, listBucketInfo.get(0));
+
+ long groupId = createGroupIdForIpv6Router(getGroupIdKey(routerName + "IPv6"));
+ GroupEntity groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll,
+ listBucketInfo);
+ LOG.debug("removing the PSNAT to NAPTSwitch GroupEntity:{} with GroupId: {}", groupEntity, groupId);
+ mdsalManager.removeGroup(confTx, groupEntity);
+
+ String flowRef = NatUtil.getIpv6FlowRef(dpnId, NwConstants.PSNAT_TABLE, routerId);
+ NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.PSNAT_TABLE, flowRef);
+ }
+
+
+ protected void addIpv6SnatMissEntryForNaptSwitch(TypedReadWriteTransaction<Configuration> confTx,
+ BigInteger dpnId, Long routerId, BigInteger routerMetadata) {
+ LOG.debug("installIpv6SnatMissEntryForNaptSwitch {} called for routerId {}", dpnId, routerId);
+ List<MatchInfo> matches = new ArrayList<>();
+ matches.add(MatchEthernetType.IPV6);
+ matches.add(new MatchMetadata(routerMetadata, MetaDataUtil.METADATA_MASK_VRFID));
+
+ List<InstructionInfo> instructions = new ArrayList<>();
+ instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
+
+ String flowRef = NatUtil.getIpv6FlowRef(dpnId, NwConstants.PSNAT_TABLE, routerId);
+ flowRef += ".Outbound";
+ NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.PSNAT_TABLE, flowRef,
+ NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef,
+ NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
+ }
+
+ protected void removeIpv6SnatMissEntryForNaptSwitch(TypedReadWriteTransaction<Configuration> confTx,
+ BigInteger dpnId, Long routerId)
+ throws ExecutionException, InterruptedException {
+ LOG.debug("installIpv6SnatMissEntryForNaptSwitch {} called for routerId {}", dpnId, routerId);
+ String flowRef = NatUtil.getIpv6FlowRef(dpnId, NwConstants.PSNAT_TABLE, routerId);
+ flowRef += ".Outbound";
+ NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.PSNAT_TABLE, flowRef);
+ }
+
+ protected void addIpv6TerminatingServiceTblEntry(TypedReadWriteTransaction<Configuration> confTx,
+ BigInteger dpnId, Long routerId, BigInteger routerMetadata) {
+ LOG.debug("installIpv6TerminatingServiceTblEntry : creating entry for Terminating Service Table "
+ + "for switch {}, routerId {}", dpnId, routerId);
+ List<MatchInfo> matches = new ArrayList<>();
+ matches.add(MatchEthernetType.IPV6);
+ matches.add(new MatchTunnelId(BigInteger.valueOf(routerId)));
+
+ List<ActionInfo> actionsInfos = new ArrayList<>();
+ ActionNxLoadMetadata actionLoadMeta = new ActionNxLoadMetadata(routerMetadata, LOAD_START, LOAD_END);
+ actionsInfos.add(actionLoadMeta);
+ actionsInfos.add(new ActionNxResubmit(NwConstants.OUTBOUND_NAPT_TABLE));
+ List<InstructionInfo> instructions = new ArrayList<>();
+ instructions.add(new InstructionApplyActions(actionsInfos));
+
+ String flowRef = NatUtil.getIpv6FlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId);
+ flowRef += ".Outbound";
+ NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef,
+ NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef,
+ NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
+
+ }
+
+ protected void removeIpv6TerminatingServiceTblEntry(TypedReadWriteTransaction<Configuration> confTx,
+ BigInteger dpnId, Long routerId) throws ExecutionException, InterruptedException {
+ LOG.debug("installIpv6TerminatingServiceTblEntry : creating entry for Terminating Service Table "
+ + "for switch {}, routerId {}", dpnId, routerId);
+ String flowRef = NatUtil.getIpv6FlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId);
+ flowRef += ".Outbound";
+ NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef);
+
+ }
+
+ protected void addIpv6NaptPfibInboundFlow(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
+ long routerId, BigInteger routerMetadata) {
+ LOG.debug("installIpv6NaptPfibInboundFlow : called for dpnId {} and routerId {} ", dpnId, routerId);
+ List<MatchInfoBase> matches = new ArrayList<>();
+ matches.add(MatchEthernetType.IPV6);
+ matches.add(new MatchMetadata(routerMetadata, MetaDataUtil.METADATA_MASK_VRFID));
+
+ ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
+ ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
+ listActionInfo.add(new ActionNxLoadInPort(BigInteger.ZERO));
+ listActionInfo.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
+ instructionInfo.add(new InstructionApplyActions(listActionInfo));
+
+ String flowRef = NatUtil.getIpv6FlowRef(dpnId, NwConstants.NAPT_PFIB_TABLE, routerId);
+ flowRef += ".Inbound";
+ NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.NAPT_PFIB_TABLE, flowRef,
+ NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY,
+ flowRef, NwConstants.COOKIE_SNAT_TABLE,
+ matches, instructionInfo);
+ }
+
+ protected void removeIpv6NaptPfibInboundFlow(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
+ long routerId)
+ throws ExecutionException, InterruptedException {
+ LOG.debug("installIpv6NaptPfibInboundFlow : called for dpnId {} and routerId {} ", dpnId, routerId);
+ String flowRef = NatUtil.getIpv6FlowRef(dpnId, NwConstants.NAPT_PFIB_TABLE, routerId);
+ flowRef += ".Inbound";
+ NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.NAPT_PFIB_TABLE, flowRef);
+ }
+
+ protected long createGroupIdForIpv6Router(String groupIdKey) {
+ AllocateIdInput getIdInput = new AllocateIdInputBuilder()
+ .setPoolName(NatConstants.SNAT_IDPOOL_NAME).setIdKey(groupIdKey)
+ .build();
+ try {
+ Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
+ RpcResult<AllocateIdOutput> rpcResult = result.get();
+ return rpcResult.getResult().getIdValue();
+ } catch (NullPointerException | InterruptedException | ExecutionException e) {
+ LOG.error("createGroupIdForIPv6Router: Exception while creating group with key : {}", groupIdKey, e);
+ }
+ return 0;
+ }
+
+ protected boolean routerHasIpv6ExtSubnet(Routers routers) {
+ for (ExternalIps externalIp : routers.getExternalIps()) {
+ if (!NWUtil.isIpv4Address(externalIp.getIpAddress())) {
+ LOG.debug("router {}, has an external IPv6 subnet {}",
+ routers.getRouterName(), externalIp.getIpAddress());
+ return true;
+ }
+ }
+ LOG.debug("router {}, does not have an external IPv6 subnet", routers.getRouterName());
+ return false;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2018 Red Hat, Inc. 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,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netvirt.natservice.internal;
+
+import static org.opendaylight.netvirt.natservice.internal.AbstractSnatService.LOAD_END;
+import static org.opendaylight.netvirt.natservice.internal.AbstractSnatService.LOAD_START;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.genius.infra.Datastore.Configuration;
+import org.opendaylight.genius.infra.TypedReadWriteTransaction;
+import org.opendaylight.genius.mdsalutil.ActionInfo;
+import org.opendaylight.genius.mdsalutil.InstructionInfo;
+import org.opendaylight.genius.mdsalutil.MatchInfo;
+import org.opendaylight.genius.mdsalutil.MatchInfoBase;
+import org.opendaylight.genius.mdsalutil.MetaDataUtil;
+import org.opendaylight.genius.mdsalutil.NWUtil;
+import org.opendaylight.genius.mdsalutil.NwConstants;
+import org.opendaylight.genius.mdsalutil.actions.ActionNxLoadInPort;
+import org.opendaylight.genius.mdsalutil.actions.ActionNxLoadMetadata;
+import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
+import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldEthernetSource;
+import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
+import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
+import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
+import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
+import org.opendaylight.genius.mdsalutil.matches.MatchIpv6Destination;
+import org.opendaylight.genius.mdsalutil.matches.MatchIpv6Source;
+import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
+import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.routers.ExternalIps;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Singleton
+public class Ipv6SubnetFlowProgrammer {
+ private static final Logger LOG = LoggerFactory.getLogger(Ipv6SubnetFlowProgrammer.class);
+ protected final DataBroker dataBroker;
+ protected final IMdsalApiManager mdsalManager;
+
+ @Inject
+ public Ipv6SubnetFlowProgrammer(final DataBroker dataBroker, final IMdsalApiManager mdsalManager) {
+ this.dataBroker = dataBroker;
+ this.mdsalManager = mdsalManager;
+ }
+
+ public void addSubnetSpecificFlows(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
+ long routerId, Routers routers, BigInteger routerMetadata) {
+ String extGwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routers.getRouterName());
+ for (ExternalIps externalIp : routers.getExternalIps()) {
+ if (NWUtil.isIpv4Address(externalIp.getIpAddress())) {
+ // Skip ipv4 subnets in the external network
+ continue;
+ }
+
+ // Currently we only handle one external IPv6 address per router, others if present will be ignored.
+ long extSubnetId = NatUtil.getExternalSubnetVpnId(dataBroker, externalIp.getSubnetId());
+
+ BigInteger extIpv6SubnetMetadata = MetaDataUtil.getVpnIdMetadata(extSubnetId);
+ LOG.info("addSubnetSpecificFlows : flows on NAPTSwitch {} for routerId {}, routerName {},"
+ + " extIPv6Address {} Installing", dpnId, routerId, routers.getRouterName(),
+ externalIp.getIpAddress());
+
+ // Program flows to handle ingress traffic coming over the tunnel port (i.e., from tableId 36 to 44)
+ addIpv6InboundTerminatingServiceTblEntry(confTx, extSubnetId, extIpv6SubnetMetadata, dpnId, routerId);
+
+ // Program flows in OUTBOUND_NAPT_TABLE(46) with action to send packets to NAPT_PFIB_TABLE(47)
+ addIPv6FlowToUpdateSrcMacToRouterGwMac(confTx, extGwMacAddress, extSubnetId, dpnId, routerId,
+ routerMetadata);
+
+ for (Uuid subnetId : routers.getSubnetIds()) {
+ String tenantSubnetCidr = NatUtil.getSubnetIp(dataBroker, subnetId);
+ if (!NatUtil.isIPv6Subnet(tenantSubnetCidr)) {
+ // Skip ipv4 subnets in the tenant network
+ continue;
+ }
+
+ LOG.info("addSubnetSpecificFlows : flows for NAPTSwitch {} for routerName {},"
+ + " tenantSubnetCidr {}, Installing",
+ dpnId, routers.getRouterName(), tenantSubnetCidr);
+
+ // Program flows from NAPT_PFIB_TABLE(47) to FIB_TABLE(21) (egress direction)
+ addIpv6NaptPfibOutboundFlow(confTx, tenantSubnetCidr, extIpv6SubnetMetadata, dpnId, routerId);
+ // Program flows from FIB_TABLE(21) to INBOUND_NAPT_TABLE(44) (ingress direction)
+ addIpv6NaptInboundFibEntry(confTx, extSubnetId, tenantSubnetCidr, extIpv6SubnetMetadata,
+ dpnId, routerId);
+ // Program flows from INBOUND_NAPT_TABLE(44) to NAPT_PFIB_TABLE(47) (ingress direction)
+ addIpv6NaptInboundNaptFlow(confTx, extSubnetId, tenantSubnetCidr, extIpv6SubnetMetadata,
+ dpnId, routerId, routerMetadata);
+ }
+ }
+ }
+
+ public void removeSubnetSpecificFlows(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
+ long routerId, Routers routers) throws ExecutionException, InterruptedException {
+ for (ExternalIps externalIp : routers.getExternalIps()) {
+ if (NWUtil.isIpv4Address(externalIp.getIpAddress())) {
+ // Skip ipv4 subnets in the external network
+ continue;
+ }
+ // Currently we only handle one external IPv6 address per router, others if present will be ignored.
+ LOG.info("removeSubnetSpecificFlows : flows on NAPTSwitch {} for routerId {}, routerName {},"
+ + " extIPv6Address {}, Removing",
+ dpnId, routerId, routers.getRouterName(), externalIp.getIpAddress());
+
+ // Program flows to handle ingress traffic coming over the tunnel port (i.e., from tableId 36 to 44)
+ removeIpv6InboundTerminatingServiceTblEntry(confTx, dpnId, routerId);
+
+ // Program flows in OUTBOUND_NAPT_TABLE(46) with action to send packets to NAPT_PFIB_TABLE(47)
+ removeIPv6FlowToUpdateSrcMacToRouterGwMac(confTx, dpnId, routerId);
+
+ for (Uuid subnetId : routers.getSubnetIds()) {
+ String tenantSubnetCidr = NatUtil.getSubnetIp(dataBroker, subnetId);
+ if (!NatUtil.isIPv6Subnet(tenantSubnetCidr)) {
+ // Skip ipv4 subnets in the tenant network
+ continue;
+ }
+
+ LOG.info("removeSubnetSpecificFlows : flows for NAPTSwitch {} for routerName {},"
+ + " tenantSubnetCidr {}, Removing",
+ dpnId, routers.getRouterName(), tenantSubnetCidr);
+
+ // Program flows from NAPT_PFIB_TABLE(47) to FIB_TABLE(21) (egress direction)
+ removeIpv6NaptPfibOutboundFlow(confTx, tenantSubnetCidr, dpnId, routerId);
+ // Program flows from FIB_TABLE(21) to INBOUND_NAPT_TABLE(44) (ingress direction)
+ removeIpv6NaptInboundFibEntry(confTx, tenantSubnetCidr, dpnId, routerId);
+ // Program flows from INBOUND_NAPT_TABLE(44) to NAPT_PFIB_TABLE(47) (ingress direction)
+ removeIpv6NaptInboundNaptFlow(confTx, tenantSubnetCidr, dpnId, routerId);
+ }
+ }
+ }
+
+ private void addIpv6InboundTerminatingServiceTblEntry(TypedReadWriteTransaction<Configuration> confTx,
+ long extSubnetId, BigInteger extIpv6SubnetMetadata,BigInteger dpnId, long routerId) {
+ // Install the tunnel table entry in NAPT Switch for inbound traffic from a non NAPT Switch.
+ LOG.debug("addIpv6InboundTerminatingServiceTblEntry : entry for Terminating Service Table for switch {},"
+ + " routerId {}, Installing", dpnId, routerId);
+ List<MatchInfo> matches = new ArrayList<>();
+ matches.add(MatchEthernetType.IPV6);
+
+ List<ActionInfo> actionsInfos = new ArrayList<>();
+ if (extSubnetId == NatConstants.INVALID_ID) {
+ LOG.error("addIpv6InboundTerminatingServiceTblEntry : external subnet id is invalid.");
+ return;
+ }
+ matches.add(new MatchTunnelId(BigInteger.valueOf(extSubnetId)));
+ ActionNxLoadMetadata actionLoadMeta = new ActionNxLoadMetadata(extIpv6SubnetMetadata, LOAD_START, LOAD_END);
+ actionsInfos.add(actionLoadMeta);
+ actionsInfos.add(new ActionNxResubmit(NwConstants.INBOUND_NAPT_TABLE));
+ List<InstructionInfo> instructions = new ArrayList<>();
+ instructions.add(new InstructionApplyActions(actionsInfos));
+
+ String flowRef = NatUtil.getIpv6FlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId);
+ flowRef = flowRef + ".Inbound";
+ NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef,
+ NatConstants.SNAT_FIB_FLOW_PRIORITY, flowRef,
+ NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
+ }
+
+ private void removeIpv6InboundTerminatingServiceTblEntry(TypedReadWriteTransaction<Configuration> confTx,
+ BigInteger dpnId, long routerId) throws ExecutionException, InterruptedException {
+ // Install the tunnel table entry in NAPT Switch for inbound traffic from a non NAPT Switch.
+ LOG.debug("removeIpv6InboundTerminatingServiceTblEntry : entry for Terminating Service Table for switch {},"
+ + " routerId {}, Removing", dpnId, routerId);
+ String flowRef = NatUtil.getIpv6FlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId);
+ flowRef = flowRef + ".Inbound";
+ NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef);
+ }
+
+ private void addIPv6FlowToUpdateSrcMacToRouterGwMac(TypedReadWriteTransaction<Configuration> confTx,
+ String extGwMacAddress, long extSubnetId, BigInteger dpnId, long routerId, BigInteger routerMetadata) {
+ LOG.debug("addIPv6FlowToUpdateSrcMacToRouterGwMac : called for switch {}, routerId {}", dpnId, routerId);
+ List<MatchInfoBase> matches = new ArrayList<>();
+ matches.add(MatchEthernetType.IPV6);
+ matches.add(new MatchMetadata(routerMetadata, MetaDataUtil.METADATA_MASK_VRFID));
+
+ ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
+ listActionInfo.add(new ActionSetFieldEthernetSource(new MacAddress(extGwMacAddress)));
+ ActionNxLoadMetadata actionLoadMeta = new ActionNxLoadMetadata(MetaDataUtil
+ .getVpnIdMetadata(extSubnetId), LOAD_START, LOAD_END);
+ listActionInfo.add(actionLoadMeta);
+ ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
+ listActionInfo.add(new ActionNxResubmit(NwConstants.NAPT_PFIB_TABLE));
+ instructionInfo.add(new InstructionApplyActions(listActionInfo));
+
+ String flowRef = NatUtil.getIpv6FlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId);
+ flowRef += ".Outbound";
+ NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef,
+ NatConstants.SNAT_TRK_FLOW_PRIORITY, flowRef,
+ NwConstants.COOKIE_SNAT_TABLE, matches, instructionInfo);
+ }
+
+ private void removeIPv6FlowToUpdateSrcMacToRouterGwMac(TypedReadWriteTransaction<Configuration> confTx,
+ BigInteger dpnId, long routerId)
+ throws ExecutionException, InterruptedException {
+ LOG.debug("removeIPv6FlowToUpdateSrcMacToRouterGwMac : called for switch {}, routerId {}", dpnId, routerId);
+ String flowRef = NatUtil.getIpv6FlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId);
+ flowRef += ".Outbound";
+ NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef);
+ }
+
+ private void addIpv6NaptPfibOutboundFlow(TypedReadWriteTransaction<Configuration> confTx,
+ String tenantIpv6SubnetCidr, BigInteger extIpv6SubnetMetadata, BigInteger dpnId, long routerId) {
+ LOG.debug("addIpv6NaptPfibOutboundFlow : called for NAPTSwitch {}, routerId {}, tenantIPv6Cidr {}",
+ dpnId, routerId, tenantIpv6SubnetCidr);
+ List<MatchInfoBase> matches = new ArrayList<>();
+ matches.add(MatchEthernetType.IPV6);
+ matches.add(new MatchMetadata(extIpv6SubnetMetadata, MetaDataUtil.METADATA_MASK_VRFID));
+ matches.add(new MatchIpv6Source(tenantIpv6SubnetCidr));
+
+ List<ActionInfo> listActionInfo = new ArrayList<>();
+ ArrayList<InstructionInfo> instructions = new ArrayList<>();
+ listActionInfo.add(new ActionNxLoadInPort(BigInteger.ZERO));
+ listActionInfo.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
+ instructions.add(new InstructionApplyActions(listActionInfo));
+
+ String flowRef = NatUtil.getIpv6FlowRef(dpnId, NwConstants.NAPT_PFIB_TABLE, routerId);
+ flowRef += NatConstants.FLOWID_SEPARATOR + tenantIpv6SubnetCidr + ".Outbound";
+ NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.NAPT_PFIB_TABLE, flowRef,
+ NatConstants.SNAT_TRK_FLOW_PRIORITY,
+ flowRef, NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
+ }
+
+ private void removeIpv6NaptPfibOutboundFlow(TypedReadWriteTransaction<Configuration> confTx,
+ String tenantIpv6SubnetCidr, BigInteger dpnId, long routerId)
+ throws ExecutionException, InterruptedException {
+ LOG.debug("removeIpv6NaptPfibOutboundFlow : called for NAPTSwitch {}, routerId {}, tenantIPv6Cidr {}",
+ dpnId, routerId, tenantIpv6SubnetCidr);
+ String flowRef = NatUtil.getIpv6FlowRef(dpnId, NwConstants.NAPT_PFIB_TABLE, routerId);
+ flowRef += NatConstants.FLOWID_SEPARATOR + tenantIpv6SubnetCidr + ".Outbound";
+ NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.NAPT_PFIB_TABLE, flowRef);
+ }
+
+ private void addIpv6NaptInboundFibEntry(TypedReadWriteTransaction<Configuration> confTx, long extSubnetId,
+ String tenantIpv6SubnetCidr, BigInteger extIpv6SubnetMetadata, BigInteger dpnId, long routerId) {
+ LOG.debug("addIpv6NaptInboundFibEntry : called for NAPTSwitch {}, routerId {}, tenantIPv6Cidr {}",
+ dpnId, routerId, tenantIpv6SubnetCidr);
+ List<MatchInfo> matches = new ArrayList<>();
+ matches.add(MatchEthernetType.IPV6);
+ if (extSubnetId == NatConstants.INVALID_ID) {
+ LOG.error("installIpv6NaptInboundFibEntry: external subnet id is invalid.");
+ return;
+ }
+ matches.add(new MatchMetadata(extIpv6SubnetMetadata, MetaDataUtil.METADATA_MASK_VRFID));
+ matches.add(new MatchIpv6Destination(tenantIpv6SubnetCidr));
+
+ List<InstructionInfo> instructions = new ArrayList<>();
+ instructions.add(new InstructionGotoTable(NwConstants.INBOUND_NAPT_TABLE));
+
+ String flowRef = NatUtil.getIpv6FlowRef(dpnId, NwConstants.L3_FIB_TABLE, routerId);
+ flowRef += NatConstants.FLOWID_SEPARATOR + tenantIpv6SubnetCidr + ".Inbound";
+ NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.L3_FIB_TABLE, flowRef,
+ NatConstants.SNAT_FIB_FLOW_PRIORITY, flowRef,
+ NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
+ }
+
+ private void removeIpv6NaptInboundFibEntry(TypedReadWriteTransaction<Configuration> confTx,
+ String tenantIpv6SubnetCidr, BigInteger dpnId, long routerId)
+ throws ExecutionException, InterruptedException {
+ LOG.debug("removeIpv6NaptInboundFibEntry : called for NAPTSwitch {}, routerId {}, tenantIPv6Cidr {}",
+ dpnId, routerId, tenantIpv6SubnetCidr);
+ String flowRef = NatUtil.getIpv6FlowRef(dpnId, NwConstants.L3_FIB_TABLE, routerId);
+ flowRef += NatConstants.FLOWID_SEPARATOR + tenantIpv6SubnetCidr + ".Inbound";
+ NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.L3_FIB_TABLE, flowRef);
+ }
+
+ private void addIpv6NaptInboundNaptFlow(TypedReadWriteTransaction<Configuration> confTx, long extSubnetId,
+ String tenantIpv6SubnetCidr, BigInteger extIpv6SubnetMetadata, BigInteger dpnId, long routerId,
+ BigInteger routerMetadata) {
+ LOG.debug("addIpv6NaptInboundNaptFlow : called for switch {}, routerId {}, tenantIPv6Cidr {}",
+ dpnId, routerId, tenantIpv6SubnetCidr);
+ List<MatchInfoBase> matches = new ArrayList<>();
+ matches.add(MatchEthernetType.IPV6);
+ if (extSubnetId == NatConstants.INVALID_ID) {
+ LOG.error("installIpv6NaptInboundNaptFlow : external subnet id is invalid.");
+ return;
+ }
+ matches.add(new MatchMetadata(extIpv6SubnetMetadata, MetaDataUtil.METADATA_MASK_VRFID));
+
+ matches.add(new MatchIpv6Destination(tenantIpv6SubnetCidr));
+
+ List<InstructionInfo> instructions = new ArrayList<>();
+ instructions.add(new InstructionGotoTable(NwConstants.NAPT_PFIB_TABLE));
+ instructions.add(new InstructionWriteMetadata(routerMetadata, MetaDataUtil.METADATA_MASK_VRFID));
+
+ String flowRef = NatUtil.getIpv6FlowRef(dpnId, NwConstants.INBOUND_NAPT_TABLE, routerId);
+ flowRef += NatConstants.FLOWID_SEPARATOR + tenantIpv6SubnetCidr + ".Inbound";
+ NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.INBOUND_NAPT_TABLE, flowRef,
+ NatConstants.DEFAULT_TS_FLOW_PRIORITY,
+ flowRef, NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
+ }
+
+ private void removeIpv6NaptInboundNaptFlow(TypedReadWriteTransaction<Configuration> confTx,
+ String tenantIpv6SubnetCidr,BigInteger dpnId, long routerId)
+ throws ExecutionException, InterruptedException {
+ LOG.debug("removeIpv6NaptInboundNaptFlow : called for switch {}, routerId {}, tenantIPv6Cidr {}",
+ dpnId, routerId, tenantIpv6SubnetCidr);
+ String flowRef = NatUtil.getIpv6FlowRef(dpnId, NwConstants.INBOUND_NAPT_TABLE, routerId);
+ flowRef += NatConstants.FLOWID_SEPARATOR + tenantIpv6SubnetCidr + ".Inbound";
+ NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.INBOUND_NAPT_TABLE, flowRef);
+ }
+}
String NAPT_FLOW_NAME = "SNAT";
BigInteger COOKIE_NAPT_BASE = new BigInteger("8000000", 16);
String NAPT_FLOWID_PREFIX = "SNAT.";
+ String IPV6_FLOWID_PREFIX = "IPv6.";
String FLOWID_SEPARATOR = ".";
String COLON_SEPARATOR = ":";
int DEFAULT_NAPT_IDLE_TIMEOUT = 300;
import org.opendaylight.genius.mdsalutil.InstructionInfo;
import org.opendaylight.genius.mdsalutil.MDSALUtil;
import org.opendaylight.genius.mdsalutil.MatchInfo;
+import org.opendaylight.genius.mdsalutil.MatchInfoBase;
import org.opendaylight.genius.mdsalutil.MetaDataUtil;
import org.opendaylight.genius.mdsalutil.NwConstants;
import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.BridgeRefInfo;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge.ref.info.BridgeRefEntry;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge.ref.info.BridgeRefEntryKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeGre;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.dpn.teps.info.TunnelEndPoints;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetEgressActionsForTunnelInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetEgressActionsForTunnelOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
return null;
}
+
+ public static void addFlow(TypedWriteTransaction<Configuration> confTx, IMdsalApiManager mdsalManager,
+ BigInteger dpId, short tableId, String flowId, int priority, String flowName, BigInteger cookie,
+ List<? extends MatchInfoBase> matches, List<InstructionInfo> instructions) {
+ FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId, flowId, priority, flowName,
+ NatConstants.DEFAULT_IDLE_TIMEOUT, NatConstants.DEFAULT_IDLE_TIMEOUT, cookie, matches,
+ instructions);
+ LOG.trace("syncFlow : Installing DpnId {}, flowId {}", dpId, flowId);
+ mdsalManager.addFlow(confTx, flowEntity);
+ }
+
+ public static void removeFlow(TypedReadWriteTransaction<Configuration> confTx, IMdsalApiManager mdsalManager,
+ BigInteger dpId, short tableId, String flowId) throws ExecutionException, InterruptedException {
+ LOG.trace("syncFlow : Removing Acl Flow DpnId {}, flowId {}", dpId, flowId);
+ mdsalManager.removeFlow(confTx, dpId, flowId, tableId);
+ }
+
+ public static String getIpv6FlowRef(BigInteger dpnId, short tableId, long routerID) {
+ return new StringBuilder().append(NatConstants.IPV6_FLOWID_PREFIX).append(dpnId).append(NatConstants
+ .FLOWID_SEPARATOR).append(tableId).append(NatConstants.FLOWID_SEPARATOR).append(routerID).toString();
+ }
+
+ public static String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId,
+ ItmRpcService itmManager) {
+ Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
+ RpcResult<GetTunnelInterfaceNameOutput> rpcResult;
+ try {
+ Future<RpcResult<GetTunnelInterfaceNameOutput>> result = itmManager
+ .getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder().setSourceDpid(srcDpId)
+ .setDestinationDpid(dstDpId).setTunnelType(tunType).build());
+ rpcResult = result.get();
+ if (!rpcResult.isSuccessful()) {
+ tunType = TunnelTypeGre.class ;
+ result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
+ .setSourceDpid(srcDpId)
+ .setDestinationDpid(dstDpId)
+ .setTunnelType(tunType)
+ .build());
+ rpcResult = result.get();
+ if (!rpcResult.isSuccessful()) {
+ LOG.warn("getTunnelInterfaceName : RPC Call to getTunnelInterfaceId returned with Errors {}",
+ rpcResult.getErrors());
+ } else {
+ return rpcResult.getResult().getInterfaceName();
+ }
+ LOG.warn("getTunnelInterfaceName : RPC Call to getTunnelInterfaceId returned with Errors {}",
+ rpcResult.getErrors());
+ } else {
+ return rpcResult.getResult().getInterfaceName();
+ }
+ } catch (InterruptedException | ExecutionException | NullPointerException e) {
+ LOG.error("getTunnelInterfaceName : Exception when getting tunnel interface Id for tunnel "
+ + "between {} and {}", srcDpId, dstDpId);
+ }
+ return null;
+ }
+
+ public static String getIpv6JobKey(String routerName) {
+ return "Ipv6." + routerName;
+ }
}
*/
package org.opendaylight.netvirt.natservice.internal;
+import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
+
+import java.util.Objects;
+
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
+import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
+import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
+import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
import org.opendaylight.netvirt.natservice.api.CentralizedSwitchScheduler;
import org.opendaylight.netvirt.natservice.api.SnatServiceManager;
import org.opendaylight.serviceutils.upgrade.UpgradeState;
private static final Logger LOG = LoggerFactory.getLogger(SnatExternalRoutersListener.class);
private final DataBroker dataBroker;
+ private final ManagedNewTransactionRunner txRunner;
private final IdManagerService idManager;
private final CentralizedSwitchScheduler centralizedSwitchScheduler;
private final NatMode natMode;
final UpgradeState upgradeState) {
super(Routers.class, SnatExternalRoutersListener.class);
this.dataBroker = dataBroker;
+ this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
this.idManager = idManager;
this.centralizedSwitchScheduler = centralizedSwitchScheduler;
this.upgradeState = upgradeState;
LOG.error("update : external router event - Invalid routerId for routerName {}", routerName);
return;
}
-
- // Check if its update on SNAT flag
- boolean originalSNATEnabled = original.isEnableSnat();
- boolean updatedSNATEnabled = update.isEnableSnat();
LOG.info("update :called for router {} with originalSNATStatus {} and updatedSNATStatus {}",
- routerName, originalSNATEnabled, updatedSNATEnabled);
+ routerName, original.isEnableSnat(), update.isEnableSnat());
if (!upgradeState.isUpgradeInProgress()) {
- centralizedSwitchScheduler.scheduleCentralizedSwitch(update);
+ centralizedSwitchScheduler.updateCentralizedSwitch(original, update);
+ }
+ if (!Objects.equals(original.getSubnetIds(), update.getSubnetIds())
+ || !Objects.equals(original.getExternalIps(), update.getExternalIps())) {
+ ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
+ confTx -> natServiceManager.notify(confTx, update, original, null, null,
+ SnatServiceManager.Action.SNAT_ROUTER_UPDATE)), LOG,
+ "error handling external router update");
}
}
private final NatDataUtil natDataUtil;
private final DataTreeEventCallbackRegistrar eventCallbacks;
private final NatOverVxlanUtil natOverVxlanUtil;
+ private final Ipv6SubnetFlowProgrammer ipv6SubnetFlowProgrammer;
@Inject
public SnatServiceImplFactory(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
final IFibManager fibManager,
final NatDataUtil natDataUtil,
final DataTreeEventCallbackRegistrar eventCallbacks,
- final NatOverVxlanUtil natOverVxlanUtil) {
+ final NatOverVxlanUtil natOverVxlanUtil,
+ final Ipv6SubnetFlowProgrammer ipv6SubnetFlowProgrammer) {
this.dataBroker = dataBroker;
this.mdsalManager = mdsalManager;
this.itmManager = itmManager;
this.natDataUtil = natDataUtil;
this.eventCallbacks = eventCallbacks;
this.natOverVxlanUtil = natOverVxlanUtil;
+ this.ipv6SubnetFlowProgrammer = ipv6SubnetFlowProgrammer;
}
@Override
return null;
}
+ public Ipv6ForwardingService createFlatVlanIpv6ServiceImpl() {
+ return new Ipv6ForwardingService(dataBroker, mdsalManager, itmManager, odlInterfaceRpcService,
+ idManager, naptSwitchSelector, interfaceManager, ipv6SubnetFlowProgrammer);
+ }
+
@Nullable
public AbstractSnatService createVxlanGreSnatServiceImpl() {
if (natMode == NatMode.Conntrack) {
if (flatVlaSnatServiceImpl != null) {
addNatServiceListener(flatVlaSnatServiceImpl);
}
+ addNatServiceListener(factory.createFlatVlanIpv6ServiceImpl());
AbstractSnatService vxlanGreSnatServiceImpl = factory.createVxlanGreSnatServiceImpl();
if (vxlanGreSnatServiceImpl != null) {
addNatServiceListener(vxlanGreSnatServiceImpl);
result = snatServiceListener.removeSnat(confTx, router, primarySwitchId, dpnId);
break;
+ case SNAT_ROUTER_UPDATE:
+ result = snatServiceListener.handleRouterUpdate(confTx, oldRouter, router);
+ break;
+
//Enables or disables flows to send the traffic to the NAT tables in NAPT switch and
//the flows to send the traffic to the NAPT switch from a NON-NAPT switch.
case CNT_ROUTER_ALL_SWITCH_ENBL:
instructionInfo.add(new InstructionApplyActions(listActionInfo));
String flowRef = getFlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId) + "trkest";
- addFlow(confTx, dpnId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef, NatConstants.SNAT_TRK_FLOW_PRIORITY, flowRef,
- NwConstants.COOKIE_SNAT_TABLE, matches, instructionInfo);
+ NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef,
+ NatConstants.SNAT_TRK_FLOW_PRIORITY, flowRef, NwConstants.COOKIE_SNAT_TABLE, matches, instructionInfo);
}
+ "routerId {}", dpnId, routerId);
String flowRef = getFlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId) + "trkest";
- removeFlow(confTx, dpnId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef);
+ NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef);
}
List<InstructionInfo> instructions = new ArrayList<>();
instructions.add(new InstructionApplyActions(actionsInfos));
String flowRef = getFlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId);
- addFlow(confTx, dpnId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef, NatConstants.SNAT_NEW_FLOW_PRIORITY,
- flowRef, NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
+ NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef,
+ NatConstants.SNAT_NEW_FLOW_PRIORITY, flowRef, NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
}
protected void removeOutboundTblEntryForVxlanGre(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
}
//The logic now handle only one external IP per router, others if present will be ignored.
String flowRef = getFlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId);
- removeFlow(confTx, dpnId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef);
+ NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef);
}
protected void addNaptPfibFlowForVxlanGre(TypedWriteTransaction<Configuration> confTx, Routers routers,
listActionInfo.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
instructions.add(new InstructionApplyActions(listActionInfo));
String flowRef = getFlowRef(dpnId, NwConstants.NAPT_PFIB_TABLE, extNetVpnId);
- addFlow(confTx, dpnId, NwConstants.NAPT_PFIB_TABLE, flowRef, NatConstants.SNAT_TRK_FLOW_PRIORITY,
- flowRef, NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
+ NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.NAPT_PFIB_TABLE, flowRef,
+ NatConstants.SNAT_TRK_FLOW_PRIORITY, flowRef, NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
}
protected void removeNaptPfibFlowForVxlanGre(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
LOG.info("installNaptPfibFlowForVxlanGre: Install Napt preFibFlow on dpId {} with matching extNetVpnId {} "
+ "for router {}", dpnId, extNetVpnId, routers.getRouterName());
String flowRef = getFlowRef(dpnId, NwConstants.NAPT_PFIB_TABLE, extNetVpnId);
- removeFlow(confTx, dpnId, NwConstants.NAPT_PFIB_TABLE, flowRef);
+ NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.NAPT_PFIB_TABLE, flowRef);
}
protected void addInboundEntryForVxlanGre(TypedWriteTransaction<Configuration> confTx, BigInteger dpnId,
List<InstructionInfo> instructions = new ArrayList<>();
instructions.add(new InstructionApplyActions(actionsInfos));
String flowRef = getFlowRef(dpnId, NwConstants.INBOUND_NAPT_TABLE, routerId);
- addFlow(confTx, dpnId, NwConstants.INBOUND_NAPT_TABLE, flowRef, NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef,
- NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
+ NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.INBOUND_NAPT_TABLE, flowRef,
+ NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef, NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
}
protected void removeInboundEntryForVxlanGre(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
}
String flowRef = getFlowRef(dpnId, NwConstants.INBOUND_NAPT_TABLE, routerId);
- removeFlow(confTx, dpnId, NwConstants.INBOUND_NAPT_TABLE, flowRef);
+ NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.INBOUND_NAPT_TABLE, flowRef);
}
protected void addTerminatingServiceTblEntryForVxlanGre(TypedWriteTransaction<Configuration> confTx,
List<InstructionInfo> instructions = new ArrayList<>();
instructions.add(new InstructionApplyActions(actionsInfos));
String flowRef = getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId.longValue());
- addFlow(confTx, dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef, NatConstants.DEFAULT_TS_FLOW_PRIORITY,
- flowRef, NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
+ NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef,
+ NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef, NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
}
+ "Terminating Service Table for switch {}, routerId {}", dpnId, routerId);
String flowRef = getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId.longValue());
- removeFlow(confTx, dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef);
+ NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef);
}
String routerName, BigInteger primarySwitchId) {
LOG.debug("installSnatMissEntry : Installing SNAT miss entry in switch {}", dpnId);
List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
- String ifNamePrimary = getTunnelInterfaceName(dpnId, primarySwitchId);
+ String ifNamePrimary = NatUtil.getTunnelInterfaceName(dpnId, primarySwitchId, itmManager);
List<BucketInfo> listBucketInfo = new ArrayList<>();
if (ifNamePrimary != null) {
LOG.debug("installSnatMissEntry : On Non- Napt switch , Primary Tunnel interface is {}", ifNamePrimary);
List<InstructionInfo> instructions = new ArrayList<>();
instructions.add(new InstructionApplyActions(actionsInfo));
String flowRef = getFlowRef(dpnId, NwConstants.PSNAT_TABLE, routerId);
- addFlow(confTx, dpnId, NwConstants.PSNAT_TABLE, flowRef, NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef,
- NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
+ NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.PSNAT_TABLE, flowRef,
+ NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, NwConstants.COOKIE_SNAT_TABLE, matches,
+ instructions);
}
@Override
LOG.debug("installSnatMissEntry : Removing SNAT miss entry in switch {}", dpnId);
String flowRef = getFlowRef(dpnId, NwConstants.PSNAT_TABLE, routerId);
- removeFlow(confTx, dpnId, NwConstants.PSNAT_TABLE, flowRef);
+ NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.PSNAT_TABLE, flowRef);
}
}
<version>${infrautils.version}</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.genius</groupId>
+ <artifactId>ipv6util-api</artifactId>
+ <version>${genius.version}</version>
+ </dependency>
</dependencies>
<build>
import com.google.common.util.concurrent.JdkFutureAdapters;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.math.BigInteger;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nullable;
import javax.inject.Singleton;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.genius.arputil.api.ArpConstants;
+import org.opendaylight.genius.mdsalutil.NWUtil;
import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
import org.opendaylight.netvirt.elanmanager.api.IElanService;
import org.opendaylight.netvirt.vpnmanager.api.ICentralizedSwitchProvider;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.SendArpRequestInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.interfaces.InterfaceAddress;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.interfaces.InterfaceAddressBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.ipv6.nd.util.rev170210.Ipv6NdUtilService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.ipv6.nd.util.rev170210.SendNeighborSolicitationInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.ipv6.nd.util.rev170210.SendNeighborSolicitationInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.ipv6.nd.util.rev170210.SendNeighborSolicitationOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.router.ExternalGatewayInfo;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;
+import org.opendaylight.yangtools.yang.common.RpcResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private final NeutronvpnUtils neutronvpnUtils;
private final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(
new ThreadFactoryBuilder().setNameFormat("Gw-Mac-Res").build());
+ private final Ipv6NdUtilService ipv6NdUtilService;
@Inject
public NeutronSubnetGwMacResolver(final DataBroker broker,
final OdlArputilService arputilService, final IElanService elanService,
- final ICentralizedSwitchProvider cswitchProvider, final NeutronvpnUtils neutronvpnUtils) {
+ final ICentralizedSwitchProvider cswitchProvider, final NeutronvpnUtils neutronvpnUtils,
+ final Ipv6NdUtilService ipv6NdUtilService) {
this.broker = broker;
this.arpUtilService = arputilService;
this.elanService = elanService;
this.cswitchProvider = cswitchProvider;
this.neutronvpnUtils = neutronvpnUtils;
+ this.ipv6NdUtilService = ipv6NdUtilService;
}
// TODO Clean up the exception handling
Uuid subnetId = fixIp.getSubnetId();
IpAddress srcIpAddress = fixIp.getIpAddress();
IpAddress dstIpAddress = getExternalGwIpAddress(subnetId);
- sendArpRequest(srcIpAddress, dstIpAddress, macAddress, extInterface);
+ String srcIpAddressString = srcIpAddress.stringValue();
+ String dstIpAddressString = dstIpAddress.stringValue();
+ if (NWUtil.isIpv4Address(srcIpAddressString)) {
+ sendArpRequest(srcIpAddress, dstIpAddress, macAddress, extInterface);
+ } else {
+ sendNeighborSolication(new Ipv6Address(srcIpAddressString),macAddress,
+ new Ipv6Address(dstIpAddressString), extInterface);
+ }
}
}
}
}
+ private void sendNeighborSolication(Ipv6Address srcIpv6Address,
+ MacAddress srcMac, Ipv6Address dstIpv6Address, String interfaceName) {
+ List<org.opendaylight.yang.gen.v1.urn.opendaylight.genius.ipv6
+ .nd.util.rev170210.interfaces.InterfaceAddress> interfaceAddresses = new ArrayList<>();
+ interfaceAddresses.add(new org.opendaylight.yang.gen.v1.urn.opendaylight.genius.ipv6
+ .nd.util.rev170210.interfaces.InterfaceAddressBuilder()
+ .setInterface(interfaceName)
+ .setSrcIpAddress(srcIpv6Address)
+ .setSrcMacAddress(new PhysAddress(srcMac.getValue())).build());
+ SendNeighborSolicitationInput input = new SendNeighborSolicitationInputBuilder()
+ .setInterfaceAddress(interfaceAddresses).setTargetIpAddress(dstIpv6Address)
+ .build();
+ try {
+ Future<RpcResult<SendNeighborSolicitationOutput>> result = ipv6NdUtilService
+ .sendNeighborSolicitation(input);
+ RpcResult<SendNeighborSolicitationOutput> rpcResult = result.get();
+ if (!rpcResult.isSuccessful()) {
+ LOG.error("sendNeighborSolicitationToOfGroup: RPC Call failed for input={} and Errors={}", input,
+ rpcResult.getErrors());
+ }
+ } catch (InterruptedException | ExecutionException e) {
+ LOG.error("Failed to send NS packet to ELAN group, input={}", input, e);
+ }
+ }
+
@Nullable
private Port getRouterExtGatewayPort(Router router) {
if (router == null) {
interface="org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.VpnRpcService" />
<odl:rpc-service id="odlArputilService"
interface="org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.OdlArputilService" />
+ <odl:rpc-service id="ipv6NdUtilService"
+ interface="org.opendaylight.yang.gen.v1.urn.opendaylight.genius.ipv6.nd.util.rev170210.Ipv6NdUtilService"/>
<odl:clustered-app-config id="neutronvpnConfig"
binding-class="org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.config.rev160806.NeutronvpnConfig"
return routerName;
}
+ @Nullable
+ public String getAssociatedExternalSubnet(String extIp) {
+ InstanceIdentifier<ExtRouters> extRouterInstanceIndentifier =
+ InstanceIdentifier.builder(ExtRouters.class).build();
+ Optional<ExtRouters> extRouterData = read(LogicalDatastoreType.CONFIGURATION, extRouterInstanceIndentifier);
+ if (!extRouterData.isPresent()) {
+ return null;
+ }
+ for (Routers routerData : requireNonNullElse(extRouterData.get().getRouters(),
+ Collections.<Routers>emptyList())) {
+ List<ExternalIps> externalIps = requireNonNullElse(routerData.getExternalIps(), emptyList());
+ for (ExternalIps externalIp : externalIps) {
+ Subnet neutronSubnet = neutronVpnService.getNeutronSubnet(externalIp.getSubnetId());
+ if (neutronSubnet == null) {
+ LOG.warn("Failed to retrieve subnet {} referenced by router {}",
+ externalIp.getSubnetId(), routerData);
+ continue;
+ }
+ if (NWUtil.isIpAddressInRange(IpAddressBuilder.getDefaultInstance(extIp), neutronSubnet.getCidr())) {
+ return neutronSubnet.getUuid().getValue();
+ }
+ }
+ }
+ return null;
+ }
+
static InstanceIdentifier<Routers> buildRouterIdentifier(String routerId) {
return InstanceIdentifier.builder(ExtRouters.class).child(Routers.class, new RoutersKey(routerId)).build();
}
srcMac.getValue(), srcIpToQuery, srcInterface);
VpnPortipToPort vpnPortipToPort =
vpnUtil.getNeutronPortFromVpnPortFixedIp(vpnName, srcIpToQuery);
+ // Check if this IP belongs to external network
+ if (vpnPortipToPort == null) {
+ String extSubnetId = vpnUtil.getAssociatedExternalSubnet(srcIpToQuery);
+ if (extSubnetId != null) {
+ vpnPortipToPort =
+ vpnUtil.getNeutronPortFromVpnPortFixedIp(extSubnetId, srcIpToQuery);
+ }
+ }
if (vpnPortipToPort != null) {
/* This is a well known neutron port and so should be ignored
* from being discovered...unless it is an Octavia VIP
}
}
+ // Check if this IP belongs to external network
+ String extSubnetId = vpnUtil.getAssociatedExternalSubnet(ip);
+ if (extSubnetId != null) {
+ LOG.info("The IP belongs to extenal subnet {} ", extSubnetId);
+ return extSubnetId;
+ }
+
return null;
}
}