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.controller.md.sal.binding.api.WriteTransaction;
import org.opendaylight.genius.mdsalutil.ActionInfo;
import org.opendaylight.genius.mdsalutil.BucketInfo;
import org.opendaylight.genius.mdsalutil.FlowEntity;
import org.opendaylight.genius.mdsalutil.MetaDataUtil;
import org.opendaylight.genius.mdsalutil.NwConstants;
import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
+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.matches.MatchEthernetType;
import org.opendaylight.genius.mdsalutil.matches.MatchIpv4Destination;
import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
+import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
import org.opendaylight.netvirt.natservice.api.SnatServiceListener;
-import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
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.idmanager.rev160406.AllocateIdInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
import org.slf4j.LoggerFactory;
public abstract class AbstractSnatService implements SnatServiceListener {
+ private static final Logger LOG = LoggerFactory.getLogger(AbstractSnatService.class);
+
+ static final int LOAD_START = mostSignificantBit(MetaDataUtil.METADATA_MASK_SH_FLAG.intValue());
+ static final int LOAD_END = mostSignificantBit(MetaDataUtil.METADATA_MASK_VRFID.intValue() | MetaDataUtil
+ .METADATA_MASK_SH_FLAG.intValue());
protected final DataBroker dataBroker;
protected final IMdsalApiManager mdsalManager;
protected final IdManagerService idManager;
- protected final NaptManager naptManager;
protected final NAPTSwitchSelector naptSwitchSelector;
protected final ItmRpcService itmManager;
protected final OdlInterfaceRpcService interfaceManager;
- private final IVpnManager vpnManager;
- private static final Logger LOG = LoggerFactory.getLogger(AbstractSnatService.class);
- public AbstractSnatService(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
+ protected AbstractSnatService(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
final ItmRpcService itmManager,
final OdlInterfaceRpcService interfaceManager,
final IdManagerService idManager,
- final NaptManager naptManager,
- final NAPTSwitchSelector naptSwitchSelector,
- final IVpnManager vpnManager) {
+ final NAPTSwitchSelector naptSwitchSelector) {
this.dataBroker = dataBroker;
this.mdsalManager = mdsalManager;
this.itmManager = itmManager;
this.interfaceManager = interfaceManager;
this.idManager = idManager;
- this.naptManager = naptManager;
this.naptSwitchSelector = naptSwitchSelector;
- this.vpnManager = vpnManager;
+ }
+
+ protected DataBroker getDataBroker() {
+ return dataBroker;
}
public void init() {
}
public void close() {
-
LOG.debug("AbstractSnatService Closed");
}
@Override
public boolean handleSnatAllSwitch(Routers routers, BigInteger primarySwitchId, int addOrRemove) {
- LOG.debug("AbstractSnatService : Handle Snat in all switches");
+ LOG.debug("handleSnatAllSwitch : Handle Snat in all switches");
String routerName = routers.getRouterName();
- installRouterGwFlows(routers, primarySwitchId, addOrRemove);
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.
*/
handleSnat(routers, primarySwitchId, primarySwitchId, addOrRemove);
- if (switches != null) {
- for (BigInteger dpnId : switches) {
- if (primarySwitchId != dpnId) {
- handleSnat(routers, primarySwitchId, dpnId, addOrRemove);
- }
+ for (BigInteger dpnId : switches) {
+ if (primarySwitchId != dpnId) {
+ handleSnat(routers, primarySwitchId, dpnId, addOrRemove);
}
}
+
return true;
}
// Handle non NAPT switches and NAPT switches separately
if (!dpnId.equals(primarySwitchId)) {
- LOG.debug("AbstractSnatService : Handle non NAPT switch {}", dpnId);
+ LOG.debug("handleSnat : Handle non NAPT switch {}", dpnId);
installSnatCommonEntriesForNonNaptSwitch(routers, primarySwitchId, dpnId, addOrRemove);
installSnatSpecificEntriesForNonNaptSwitch(routers, dpnId, addOrRemove);
} else {
- LOG.debug("AbstractSnatService : Handle NAPT switch {}", dpnId);
+ LOG.debug("handleSnat : Handle NAPT switch {}", dpnId);
installSnatCommonEntriesForNaptSwitch(routers, dpnId, addOrRemove);
installSnatSpecificEntriesForNaptSwitch(routers, dpnId, addOrRemove);
routerId);
return;
}
+ //The logic now handle only one external IP per router, others if present will be ignored.
String externalIp = externalIps.get(0).getIpAddress();
- installInboundFibEntry(dpnId, externalIp, routerName, routerId, addOrRemove);
+ Uuid externalSubnetId = externalIps.get(0).getSubnetId();
+ long extSubnetId = NatConstants.INVALID_ID;
+ if (addOrRemove == NwConstants.ADD_FLOW) {
+ extSubnetId = NatUtil.getExternalSubnetVpnId(dataBroker,externalSubnetId);
+ }
+ installInboundFibEntry(dpnId, externalIp, routerName, routerId, extSubnetId, addOrRemove);
+ installInboundTerminatingServiceTblEntry(dpnId, routerId, routerName, externalIp, extSubnetId, addOrRemove);
}
protected void installSnatCommonEntriesForNonNaptSwitch(Routers routers, BigInteger primarySwitchId,
BigInteger dpnId, int addOrRemove) {
String routerName = routers.getRouterName();
Long routerId = NatUtil.getVpnId(dataBroker, routerName);
+ List<ExternalIps> externalIps = routers.getExternalIps();
+ if (externalIps.isEmpty()) {
+ LOG.error("AbstractSnatService: installSnatCommonEntriesForNaptSwitch no externalIP present"
+ + " for routerId {}",
+ routerId);
+ return;
+ }
+ String externalIp = externalIps.get(0).getIpAddress();
+ Uuid externalSubnetId = externalIps.get(0).getSubnetId();
+ long extSubnetId = NatConstants.INVALID_ID;
+ if (addOrRemove == NwConstants.ADD_FLOW) {
+ extSubnetId = NatUtil.getExternalSubnetVpnId(dataBroker,externalSubnetId);
+ }
+
installDefaultFibRouteForSNAT(dpnId, routerId, addOrRemove);
- installSnatMissEntry(dpnId, routerId, routerName, primarySwitchId, addOrRemove);
+ installSnatMissEntry(dpnId, routerId, routerName, primarySwitchId, externalIp, extSubnetId, addOrRemove);
}
protected abstract void installSnatSpecificEntriesForNaptSwitch(Routers routers, BigInteger dpnId,
int addOrRemove);
protected void installInboundFibEntry(BigInteger dpnId, String externalIp, String routerName, Long routerId,
- int addOrRemove) {
- List<MatchInfo> matches = new ArrayList<MatchInfo>();
+ long extSubnetId, int addOrRemove) {
+ List<MatchInfo> matches = new ArrayList<>();
matches.add(MatchEthernetType.IPV4);
if (addOrRemove == NwConstants.ADD_FLOW) {
- Long extSubnetId = NatUtil.getVpnIdFromExternalSubnet(dataBroker, routerName, externalIp);
if (extSubnetId == NatConstants.INVALID_ID) {
LOG.error("ConntrackBasedSnatService : installInboundFibEntry : external subnet id is invalid.");
return;
NwConstants.COOKIE_SNAT_TABLE, matches, instructionInfo, addOrRemove);
}
- protected void installRouterGwFlows(Routers router, BigInteger primarySwitchId, int addOrRemove) {
- WriteTransaction writeTx = dataBroker.newWriteOnlyTransaction();
- List<ExternalIps> externalIps = router.getExternalIps();
- List<String> externalIpsSting = new ArrayList<>();
- for (ExternalIps externalIp : externalIps) {
- externalIpsSting.add(externalIp.getIpAddress());
- }
- Uuid subnetVpnName = externalIps.get(0).getSubnetId();
- vpnManager.setupRouterGwMacFlow(router.getRouterName(), router.getExtGwMacAddress(), primarySwitchId,
- router.getNetworkId(), subnetVpnName.getValue(), writeTx, addOrRemove);
- vpnManager.setupArpResponderFlowsToExternalNetworkIps(router.getRouterName(), externalIpsSting,
- router.getExtGwMacAddress(), primarySwitchId,
- router.getNetworkId(), writeTx, addOrRemove);
- writeTx.submit();
- }
-
protected void installSnatMissEntry(BigInteger dpnId, Long routerId, String routerName, BigInteger primarySwitchId,
- int addOrRemove) {
- LOG.debug("AbstractSnatService : Installing SNAT miss entry in switch {}", dpnId);
+ String externalIp, long extSubnetId, int addOrRemove) {
+ LOG.debug("installSnatMissEntry : Installing SNAT miss entry in switch {}", dpnId);
List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
String ifNamePrimary = getTunnelInterfaceName(dpnId, primarySwitchId);
List<BucketInfo> listBucketInfo = new ArrayList<>();
if (ifNamePrimary != null) {
- LOG.debug("AbstractSnatService : On Non- Napt switch , Primary Tunnel interface is {}", ifNamePrimary);
+ LOG.debug("installSnatMissEntry : On Non- Napt switch , Primary Tunnel interface is {}", ifNamePrimary);
listActionInfoPrimary = NatUtil.getEgressActionsForInterface(interfaceManager, ifNamePrimary, routerId);
}
BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
listBucketInfo.add(0, bucketPrimary);
- LOG.debug("AbstractSnatService : installSnatMissEntry called for dpnId {} with primaryBucket {} ", dpnId,
+ LOG.debug("installSnatMissEntry : installSnatMissEntry called for dpnId {} with primaryBucket {} ", dpnId,
listBucketInfo.get(0));
// Install the select group
long groupId = createGroupId(getGroupIdKey(routerName));
GroupEntity groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll,
listBucketInfo);
- LOG.debug("AbstractSnatService : installing the SNAT to NAPT GroupEntity:{}", groupEntity);
+ LOG.debug("installSnatMissEntry : installing the SNAT to NAPT GroupEntity:{}", groupEntity);
mdsalManager.installGroup(groupEntity);
// Install miss entry pointing to group
- LOG.debug("AbstractSnatService : buildSnatFlowEntity is called for dpId {}, routerName {} and groupId {}",
+ LOG.debug("installSnatMissEntry : buildSnatFlowEntity is called for dpId {}, routerName {} and groupId {}",
dpnId, routerName, groupId);
List<MatchInfo> matches = new ArrayList<>();
matches.add(new MatchEthernetType(0x0800L));
List<ActionInfo> actionsInfo = new ArrayList<>();
actionsInfo.add(new ActionSetFieldTunnelId(BigInteger.valueOf(routerId)));
- LOG.debug("AbstractSnatService : Setting the tunnel to the list of action infos {}", actionsInfo);
+ LOG.debug("installSnatMissEntry : Setting the tunnel to the list of action infos {}", actionsInfo);
actionsInfo.add(new ActionGroup(groupId));
List<InstructionInfo> instructions = new ArrayList<>();
instructions.add(new InstructionApplyActions(actionsInfo));
String flowRef = getFlowRef(dpnId, NwConstants.PSNAT_TABLE, routerId);
syncFlow(dpnId, NwConstants.PSNAT_TABLE, flowRef, NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef,
NwConstants.COOKIE_SNAT_TABLE, matches, instructions, addOrRemove);
+ //Install the FIB entry for traffic destined to SNAT IP in Non-NAPT switch.
+ matches = new ArrayList<>();
+ actionsInfo = new ArrayList<>();
+ matches.add(new MatchEthernetType(0x0800L));
+ if (addOrRemove == NwConstants.ADD_FLOW) {
+ if (extSubnetId == NatConstants.INVALID_ID) {
+ LOG.error("installSnatMissEntry : external subnet id is invalid.");
+ return;
+ }
+ actionsInfo.add(new ActionSetFieldTunnelId(BigInteger.valueOf(extSubnetId)));
+ matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(extSubnetId),
+ MetaDataUtil.METADATA_MASK_VRFID));
+ }
+ matches.add(new MatchIpv4Destination(externalIp, "32"));
+ LOG.debug("installSnatMissEntry : Setting the tunnel to the list of action infos {}", actionsInfo);
+ actionsInfo.add(new ActionGroup(groupId));
+ instructions = new ArrayList<>();
+ instructions.add(new InstructionApplyActions(actionsInfo));
+ flowRef = getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, routerId);
+ flowRef = flowRef + "inboundmiss" + externalIp;
+ syncFlow(dpnId, NwConstants.L3_FIB_TABLE, flowRef, NatConstants.SNAT_FIB_FLOW_PRIORITY, flowRef,
+ NwConstants.COOKIE_SNAT_TABLE, matches, instructions, addOrRemove);
+ }
+
+ protected void installInboundTerminatingServiceTblEntry(BigInteger dpnId, Long routerId, String routerName,
+ String externalIp, long extSubnetId, int addOrRemove) {
+ //Install the tunnel table entry in NAPT switch for inbound traffic to SNAP 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<>();
+ matches.add(MatchEthernetType.IPV4);
+ List<ActionInfo> actionsInfos = new ArrayList<>();
+ if (addOrRemove == NwConstants.ADD_FLOW) {
+ if (extSubnetId == NatConstants.INVALID_ID) {
+ LOG.error("installInboundTerminatingServiceTblEntry : external subnet id is invalid.");
+ return;
+ }
+ matches.add(new MatchTunnelId(BigInteger.valueOf(extSubnetId)));
+ ActionNxLoadMetadata actionLoadMeta = new ActionNxLoadMetadata(MetaDataUtil
+ .getVpnIdMetadata(extSubnetId), 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 = getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId.longValue());
+ flowRef = flowRef + "INBOUND";
+ syncFlow(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef, NatConstants.SNAT_FIB_FLOW_PRIORITY, flowRef,
+ NwConstants.COOKIE_SNAT_TABLE, matches, instructions, addOrRemove);
+
}
protected void installDefaultFibRouteForSNAT(BigInteger dpnId, Long extNetId, int addOrRemove) {
NwConstants.COOKIE_SNAT_TABLE, matches, instructions, addOrRemove);
}
- protected BigInteger getPrimaryNaptSwitch(String routerName, long routerId) {
- // Allocate Primary Napt Switch for this router
- BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
- if (primarySwitchId != null && !primarySwitchId.equals(BigInteger.ZERO)) {
- LOG.debug("AbstractSnatService : Primary NAPT switch with DPN ID {} is already elected for router",
- primarySwitchId, routerName);
- return primarySwitchId;
- }
-
- primarySwitchId = naptSwitchSelector.selectNewNAPTSwitch(routerName);
- LOG.debug("AbstractSnatService : Primary NAPT switch DPN ID {}", primarySwitchId);
- if (primarySwitchId == null || primarySwitchId.equals(BigInteger.ZERO)) {
- LOG.error("AbstractSnatService : Unable to to select the primary NAPT switch");
- }
-
- return primarySwitchId;
- }
-
protected String getFlowRef(BigInteger dpnId, short tableId, long routerID) {
return new StringBuilder().append(NatConstants.NAPT_FLOWID_PREFIX).append(dpnId).append(NatConstants
.FLOWID_SEPARATOR).append(tableId).append(NatConstants.FLOWID_SEPARATOR).append(routerID).toString();
if (addOrRemove == NwConstants.DEL_FLOW) {
FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId, flowId, priority, flowName,
NatConstants.DEFAULT_IDLE_TIMEOUT, NatConstants.DEFAULT_IDLE_TIMEOUT, cookie, matches, null);
- LOG.trace("Removing Acl Flow DpnId {}, flowId {}", dpId, flowId);
+ LOG.trace("syncFlow : Removing Acl Flow DpnId {}, flowId {}", dpId, flowId);
mdsalManager.removeFlow(flowEntity);
} else {
FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId, flowId, priority, flowName,
NatConstants.DEFAULT_IDLE_TIMEOUT, NatConstants.DEFAULT_IDLE_TIMEOUT, cookie, matches,
instructions);
- LOG.trace("Installing DpnId {}, flowId {}", dpId, flowId);
+ LOG.trace("syncFlow : Installing DpnId {}, flowId {}", dpId, flowId);
mdsalManager.installFlow(flowEntity);
}
}
- private long createGroupId(String groupIdKey) {
+ protected long createGroupId(String groupIdKey) {
AllocateIdInput getIdInput = new AllocateIdInputBuilder()
.setPoolName(NatConstants.SNAT_IDPOOL_NAME).setIdKey(groupIdKey)
.build();
RpcResult<AllocateIdOutput> rpcResult = result.get();
return rpcResult.getResult().getIdValue();
} catch (NullPointerException | InterruptedException | ExecutionException e) {
- LOG.trace("",e);
+ LOG.error("createGroupId: Exception while creating group with key : {}",groupIdKey, e);
}
return 0;
}
- private String getGroupIdKey(String routerName) {
- String groupIdKey = new String("snatmiss." + routerName);
- return groupIdKey;
+ protected String getGroupIdKey(String routerName) {
+ return "snatmiss." + routerName;
}
- private String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId) {
+ protected String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId) {
Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
RpcResult<GetTunnelInterfaceNameOutput> rpcResult;
try {
.build());
rpcResult = result.get();
if (!rpcResult.isSuccessful()) {
- LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
+ LOG.warn("getTunnelInterfaceName : RPC Call to getTunnelInterfaceId returned with Errors {}",
+ rpcResult.getErrors());
} else {
return rpcResult.getResult().getInterfaceName();
}
- LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
+ LOG.warn("getTunnelInterfaceName : RPC Call to getTunnelInterfaceId returned with Errors {}",
+ rpcResult.getErrors());
} else {
return rpcResult.getResult().getInterfaceName();
}
} catch (InterruptedException | ExecutionException | NullPointerException e) {
- LOG.warn("AbstractSnatService : Exception when getting tunnel interface Id for tunnel between {} and {}",
- srcDpId, dstDpId);
+ LOG.error("getTunnelInterfaceName : Exception when getting tunnel interface Id for tunnel "
+ + "between {} and {}", srcDpId, dstDpId);
}
return null;
}
-}
\ No newline at end of file
+
+ static int mostSignificantBit(int value) {
+ return 31 - Integer.numberOfLeadingZeros(value);
+ }
+}