/*
* Copyright (c) 2016 Cisco Systems, 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.groupbasedpolicy.renderer.vpp.policy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.groupbasedpolicy.renderer.vpp.api.BridgeDomainManager;
import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.RoutingCommand;
import org.opendaylight.groupbasedpolicy.renderer.vpp.config.ConfigUtil;
import org.opendaylight.groupbasedpolicy.renderer.vpp.iface.InterfaceManager;
import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.LispStateManager;
import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.bvi.BviManager;
import org.opendaylight.groupbasedpolicy.renderer.vpp.nat.NatManager;
import org.opendaylight.groupbasedpolicy.renderer.vpp.nat.NatUtil;
import org.opendaylight.groupbasedpolicy.renderer.vpp.policy.acl.AclManager;
import org.opendaylight.groupbasedpolicy.renderer.vpp.routing.RoutingManager;
import org.opendaylight.groupbasedpolicy.renderer.vpp.util.General;
import org.opendaylight.groupbasedpolicy.renderer.vpp.util.KeyFactory;
import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.nat.instance.mapping.table.MappingEntryBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.common.endpoint.fields.NetworkContainment;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.common.endpoint.fields.network.containment.Containment;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.common.endpoint.fields.network.containment.containment.ForwardingContextContainment;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.common.endpoint.fields.network.containment.containment.NetworkDomainContainment;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.absolute.location.LocationType;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.absolute.location.location.type.ExternalLocationCase;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.ParentEndpointChoice;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.parent.endpoint.choice.ParentEndpointCase;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.parent.endpoint.choice.parent.endpoint._case.ParentEndpoint;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContextId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.NetworkDomainId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.IpPrefixType;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.L2FloodDomain;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.MacAddressType;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.SubnetAugmentRenderer;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.rev160427.NetworkDomain;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.rev160427.forwarding.fields.Parent;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.NatAddressRenderer;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.Configuration;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.Endpoints;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.endpoints.AddressEndpointWithLocation;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.endpoints.RendererEndpointKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.forwarding.RendererForwardingByTenant;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.forwarding.renderer.forwarding.by.tenant.RendererForwardingContext;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.forwarding.renderer.forwarding.by.tenant.RendererForwardingContextKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.forwarding.renderer.forwarding.by.tenant.RendererNetworkDomain;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.forwarding.renderer.forwarding.by.tenant.RendererNetworkDomainKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.Config;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.VlanNetwork;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425._interface.attributes.InterfaceTypeChoice;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425._interface.attributes._interface.type.choice.LoopbackCase;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.GbpBridgeDomain;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.GbpBridgeDomainKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpoint;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpointKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.renderers.renderer.renderer.nodes.renderer.node.PhysicalInterface;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev170315.VxlanVni;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.SetMultimap;
import com.google.common.collect.Table;
public final class ForwardingManager {
private static final Logger LOG = LoggerFactory.getLogger(ForwardingManager.class);
@VisibleForTesting
private byte WAIT_FOR_BD_PROCESSING = 60; // seconds
private long lastVxlanVni = 1L;
private final Map<String, VxlanVni> vxlanVniByBridgeDomain = new HashMap<>();
private final InterfaceManager ifaceManager;
private final AclManager aclManager;
private final BridgeDomainManager bdManager;
private final NatManager natManager;
private final RoutingManager routingManager;
private final LispStateManager lispStateManager;
private final BviManager bviManager;
private final DataBroker dataBroker;
public ForwardingManager(@Nonnull InterfaceManager ifaceManager, @Nonnull AclManager aclManager,
@Nonnull NatManager natManager, @Nonnull RoutingManager routingManager, @Nonnull BridgeDomainManager bdManager,
@Nonnull LispStateManager lispStateManager, @Nonnull BviManager bviManager,
@Nonnull DataBroker dataBroker) {
this.ifaceManager = Preconditions.checkNotNull(ifaceManager);
this.bdManager = Preconditions.checkNotNull(bdManager);
this.natManager = Preconditions.checkNotNull(natManager);
this.routingManager = Preconditions.checkNotNull(routingManager);
this.lispStateManager = Preconditions.checkNotNull(lispStateManager);
this.bviManager = Preconditions.checkNotNull(bviManager);
this.dataBroker = Preconditions.checkNotNull(dataBroker);
this.aclManager = Preconditions.checkNotNull(aclManager);
}
public Optional<GbpBridgeDomain> readGbpBridgeDomainConfig(String name) {
InstanceIdentifier<GbpBridgeDomain> bdIid = InstanceIdentifier.builder(Config.class)
.child(GbpBridgeDomain.class, new GbpBridgeDomainKey(name))
.build();
ReadOnlyTransaction rTx = dataBroker.newReadOnlyTransaction();
Optional<GbpBridgeDomain> optBd = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION, bdIid, rTx);
rTx.close();
return optBd;
}
public void createBridgeDomainOnNodes(SetMultimap<String, NodeId> vppNodesByBridgeDomain) {
for (String bd : vppNodesByBridgeDomain.keySet()) {
Optional<GbpBridgeDomain> bdConfig = readGbpBridgeDomainConfig(bd);
Set<NodeId> vppNodes = vppNodesByBridgeDomain.get(bd);
if (bdConfig.isPresent()) {
if (bdConfig.get().getType().equals(VlanNetwork.class)) {
createVlanBridgeDomains(bd, bdConfig.get().getVlan(), vppNodes);
}
} else {
VxlanVni vxlanVni = vxlanVniByBridgeDomain.get(bd);
if (vxlanVni == null) {
vxlanVni = new VxlanVni(lastVxlanVni++);
vxlanVniByBridgeDomain.put(bd, vxlanVni);
}
createVxlanBridgeDomains(bd, vxlanVni, vppNodes);
}
}
}
private void createVxlanBridgeDomains(final String bd, final VxlanVni vni, final Set<NodeId> vppNodes) {
for (NodeId vppNode : vppNodes) {
try {
LOG.debug("Creating VXLAN bridge-domain {} on node {} with VNI {}", bd, vppNode.getValue(),
vni);
bdManager.createVxlanBridgeDomainOnVppNode(bd, vni, vppNode).get(WAIT_FOR_BD_PROCESSING,
TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException e) {
LOG.warn("VXLAN Bridge domain {} was not created on node {}", bd, vppNode.getValue(), e);
} catch (TimeoutException e) {
LOG.warn("Probably, VXLAN Bridge domain {} was not created on node {} because BridgeDomainManager "
+ "did not respond by {} seconds. Check VBD log for more details",
bd, vppNode.getValue(), WAIT_FOR_BD_PROCESSING, e);
}
}
}
private void createVlanBridgeDomains(final String bd, final VlanId vlanId, final Set<NodeId> vppNodes) {
for (NodeId vppNode : vppNodes) {
try {
LOG.debug("Creating VLAN bridge-domain {} on node {} with VLAN ID {}", bd, vppNode.getValue(),
vlanId.getValue());
bdManager.createVlanBridgeDomainOnVppNode(bd, vlanId, vppNode).get(WAIT_FOR_BD_PROCESSING,
TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException e) {
LOG.warn("VLAN Bridge domain {} was not created on node {}", bd, vppNode.getValue(), e);
} catch (TimeoutException e) {
LOG.warn("Probably, VLAN Bridge domain {} was not created on node {} because BridgeDomainManager "
+ "did not respond by {} seconds. Check VBD log for more details",
bd, vppNode.getValue(), WAIT_FOR_BD_PROCESSING, e);
}
}
}
public void removeBridgeDomainOnNodes(final SetMultimap<String, NodeId> vppNodesByBridgeDomain) {
for (String bd : vppNodesByBridgeDomain.keySet()) {
Set<NodeId> vppNodes = vppNodesByBridgeDomain.get(bd);
for (NodeId vppNode : vppNodes) {
try {
bdManager.removeBridgeDomainFromVppNode(bd, vppNode).get(WAIT_FOR_BD_PROCESSING,
TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException e) {
LOG.warn("Bridge domain {} was not removed from node {}", bd, vppNode.getValue(), e);
} catch (TimeoutException e) {
LOG.warn("Probably, bridge domain {} was not removed from node {} because BridgeDomainManager "
+ "did not respond by {} seconds. Check VBD log for more details",
bd, vppNode.getValue(), WAIT_FOR_BD_PROCESSING, e);
}
}
}
}
public void createForwardingForEndpoint(RendererEndpointKey rEpKey, PolicyContext policyCtx) {
AddressEndpointWithLocation rEp = policyCtx.getAddrEpByKey().get(KeyFactory.addressEndpointKey(rEpKey));
if (ConfigUtil.getInstance().isLispOverlayEnabled()) {
lispStateManager.configureEndPoint(rEp);
}
ExternalLocationCase rEpLoc = resolveAndValidateLocation(rEp);
if (Strings.isNullOrEmpty(rEpLoc.getExternalNodeConnector())) {
// TODO add it to the status for renderer manager
LOG.info("Renderer endpoint does not have external-node-connector therefore it is ignored {}", rEp);
return;
}
if (Strings.isNullOrEmpty(rEpLoc.getExternalNode())) {
java.util.Optional<String> optL2FloodDomain = resolveL2FloodDomain(rEp, policyCtx);
if (!optL2FloodDomain.isPresent()) {
// TODO add it to the status for renderer manager
LOG.info("Renderer endpoint does not have l2FloodDomain as network containment {}", rEp);
return;
}
if (!ConfigUtil.getInstance().isL3FlatEnabled()) {
String l2FloodDomain = optL2FloodDomain.get();
try {
ifaceManager.addBridgeDomainToInterface(l2FloodDomain, rEp, aclManager.resolveAclsOnInterface(
rEpKey, policyCtx), isBviForEndpoint(rEp)).get();
LOG.debug("Interface added to bridge-domain {} for endpoint {}", l2FloodDomain, rEp);
if (ConfigUtil.getInstance().isLispOverlayEnabled()) {
bviManager.createBviIfNecessary(rEp, l2FloodDomain);
}
} catch (InterruptedException | ExecutionException e) {
// TODO add it to the status for renderer manager
LOG.warn("Interface was not added to bridge-domain {} for endpoint {}", l2FloodDomain, rEp, e);
}
}
aclManager.updateAclsForPeers(policyCtx, rEpKey);
} else {
LOG.debug("Forwarding is not created - Location of renderer endpoint contains "
+ "external-node therefore VPP renderer assumes that interface for endpoint is "
+ "already assigned in bridge-domain representing external-node. {}", rEp);
}
}
private boolean isBviForEndpoint(AddressEndpointWithLocation rEp) {
VppEndpointKey vppEndpointKey =
new VppEndpointKey(rEp.getAddress(), rEp.getAddressType(), rEp.getContextId(), rEp.getContextType());
ReadOnlyTransaction rTx = dataBroker.newReadOnlyTransaction();
Optional<VppEndpoint> vppEndpointOptional =
DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
InstanceIdentifier.builder(Config.class).child(VppEndpoint.class, vppEndpointKey).build(), rTx);
if (vppEndpointOptional.isPresent()) {
InterfaceTypeChoice interfaceTypeChoice = vppEndpointOptional.get().getInterfaceTypeChoice();
if (interfaceTypeChoice instanceof LoopbackCase) {
LOG.trace("Vpp renderer endpoint {} IS a BVI interface.", rEp.getKey());
return ((LoopbackCase) interfaceTypeChoice).isBvi();
}
}
rTx.close();
LOG.trace("Vpp renderer endpoint {} IS NOT a BVI interface.", rEp.getKey());
return false;
}
public void removeForwardingForEndpoint(RendererEndpointKey rEpKey, PolicyContext policyCtx) {
AddressEndpointWithLocation rEp = policyCtx.getAddrEpByKey().get(KeyFactory.addressEndpointKey(rEpKey));
ExternalLocationCase rEpLoc = resolveAndValidateLocation(rEp);
if (Strings.isNullOrEmpty(rEpLoc.getExternalNodeConnector())) {
// nothing was created for endpoint therefore nothing is removed
return;
}
if (!Strings.isNullOrEmpty(rEpLoc.getExternalNode())) {
try {
if (ConfigUtil.getInstance().isLispOverlayEnabled()) {
lispStateManager.deleteLispConfigurationForEndpoint(rEp);
}
ifaceManager.deleteBridgeDomainFromInterface(rEp).get();
LOG.debug("bridge-domain was deleted from interface for endpoint {}", rEp);
} catch (InterruptedException | ExecutionException e) {
// TODO add it to the status for renderer manager
LOG.warn("bridge-domain was not deleted from interface for endpoint {}", rEp, e);
}
} else {
LOG.debug("Forwarding is not removed - Location of renderer endpoint does not contain "
+ "external-node therefore VPP renderer assumes that interface for endpoint is not "
+ "assigned to bridge-domain representing external-node. {}", rEp);
}
}
public static ExternalLocationCase resolveAndValidateLocation(AddressEndpointWithLocation addrEpWithLoc) {
LocationType locationType = addrEpWithLoc.getAbsoluteLocation().getLocationType();
if (!(locationType instanceof ExternalLocationCase)) {
throw new IllegalStateException("Endpoint does not have external location " + addrEpWithLoc);
}
ExternalLocationCase result = (ExternalLocationCase) locationType;
if (result.getExternalNodeMountPoint() == null) {
throw new IllegalStateException("Endpoint does not have external-node-mount-point " + addrEpWithLoc);
}
return result;
}
public static java.util.Optional<String> resolveL2FloodDomain(@Nonnull AddressEndpointWithLocation ep,
@Nonnull PolicyContext policyCtx) {
NetworkContainment netCont = ep.getNetworkContainment();
if (netCont == null) {
return java.util.Optional.empty();
}
Containment containment = netCont.getContainment();
if (containment instanceof ForwardingContextContainment) {
ForwardingContextContainment fwCtxCont = (ForwardingContextContainment) containment;
if (L2FloodDomain.class.equals(fwCtxCont.getContextType())) {
return fwCtxCont.getContextId() == null ? java.util.Optional.empty() : java.util.Optional
.of(fwCtxCont.getContextId().getValue());
}
}
if (containment instanceof NetworkDomainContainment) {
final NetworkDomainContainment netDomainCont = (NetworkDomainContainment) containment;
final TenantId tenantId = ep.getTenant();
final NetworkDomainId domainId = netDomainCont.getNetworkDomainId();
final Class<? extends NetworkDomain> domainKey = netDomainCont.getNetworkDomainType();
final RendererNetworkDomainKey rendererNetworkDomainKey = new RendererNetworkDomainKey(domainId, domainKey);
final RendererNetworkDomain rendererNetworkDomain =
policyCtx.getNetworkDomainTable().get(tenantId, rendererNetworkDomainKey);
if (rendererNetworkDomain == null) {
LOG.debug("Network domain not found. Containment: {}", containment);
return java.util.Optional.empty();
}
java.util.Optional<String> optL2Fd = getForwardingCtxForParent(ep.getTenant(),
rendererNetworkDomain.getParent(), policyCtx.getForwardingCtxTable())
.filter(fwdCtx -> L2FloodDomain.class.equals(fwdCtx.getContextType()))
.map(RendererForwardingContext::getContextId)
.map(ContextId::getValue);
if (!optL2Fd.isPresent()) {
LOG.debug("network-domain-containment in endpoint does not have L2-flood-domain as parent. "
+ "This case is not supported in VPP renderer. {}", ep);
}
return optL2Fd;
}
return java.util.Optional.empty();
}
private static @Nonnull java.util.Optional<RendererForwardingContext> getForwardingCtxForParent(
@Nullable TenantId tenant, @Nullable Parent parent,
Table<TenantId, RendererForwardingContextKey, RendererForwardingContext> forwardingCtxTable) {
if (tenant == null || parent == null) {
return java.util.Optional.empty();
}
if (parent.getContextId() != null && parent.getContextType() != null) {
return java.util.Optional.ofNullable(forwardingCtxTable.get(tenant,
new RendererForwardingContextKey(parent.getContextId(), parent.getContextType())));
}
return java.util.Optional.empty();
}
void syncNatEntries(PolicyContext policyCtx) {
Configuration cfg = policyCtx.getPolicy().getConfiguration();
if(cfg != null) {
final List<MappingEntryBuilder> sNatEntries = resolveStaticNatTableEntries(cfg.getEndpoints());
LOG.trace("Syncing static NAT entries {}", sNatEntries);
if (cfg.getRendererForwarding() != null) {
for (RendererForwardingByTenant fwd : cfg.getRendererForwarding().getRendererForwardingByTenant()) {
List<InstanceIdentifier<PhysicalInterface>> physIfacesIid =
resolvePhysicalInterfacesForNat(fwd.getRendererNetworkDomain());
natManager.submitNatChanges(physIfacesIid, sNatEntries, policyCtx, true);
}
}
}
}
public void deleteNatEntries(PolicyContext policyCtx) {
Configuration cfg = policyCtx.getPolicy().getConfiguration();
if(cfg != null) {
List<MappingEntryBuilder> natEntries = resolveStaticNatTableEntries(cfg.getEndpoints());
if (natEntries.isEmpty()) {
LOG.trace("NAT entries are empty,nothing to delete, skipping processing.");
return;
}
LOG.trace("Deleting NAT entries {}", natEntries);
if (cfg.getRendererForwarding() != null) {
for (RendererForwardingByTenant fwd : cfg.getRendererForwarding().getRendererForwardingByTenant()) {
List<InstanceIdentifier<PhysicalInterface>> physIfacesIid =
resolvePhysicalInterfacesForNat(fwd.getRendererNetworkDomain());
natManager.submitNatChanges(physIfacesIid, natEntries, policyCtx, false);
}
}
}
}
public List<InstanceIdentifier<PhysicalInterface>> resolvePhysicalInterfacesForNat(
List<RendererNetworkDomain> rendNetDomains) {
List<InstanceIdentifier<PhysicalInterface>> physIfaces = new ArrayList<>();
for (RendererNetworkDomain rendDomain : rendNetDomains) {
Optional<IpPrefix> resolvedIpPrefix = resolveIpPrefix(rendDomain);
if (resolvedIpPrefix.isPresent()) {
Optional<InstanceIdentifier<PhysicalInterface>> resPhIface =
NatUtil.resolvePhysicalInterface(resolvedIpPrefix.get(), dataBroker.newReadOnlyTransaction());
if (resPhIface.isPresent()) {
physIfaces.add(resPhIface.get());
}
}
}
return physIfaces;
}
private Optional<IpPrefix> resolveIpPrefix(RendererNetworkDomain rendDomain) {
SubnetAugmentRenderer subnetAug = rendDomain.getAugmentation(SubnetAugmentRenderer.class);
if (subnetAug.getSubnet() != null) {
return Optional.of(subnetAug.getSubnet().getIpPrefix());
}
return Optional.absent();
}
private List<MappingEntryBuilder> resolveStaticNatTableEntries(Endpoints endpoints) {
List<MappingEntryBuilder> sNatEntries = new ArrayList<>();
for (AddressEndpointWithLocation addrEp : endpoints.getAddressEndpointWithLocation()) {
if (addrEp.getAugmentation(NatAddressRenderer.class) == null) {
continue;
}
String endpointIP = resolveEpIpAddressForSnat(addrEp);
if (endpointIP == null) {
LOG.warn("Endpoints {} IP cannot be null, skipping processing of SNAT", addrEp);
continue;
}
NatAddressRenderer natAddr = addrEp.getAugmentation(NatAddressRenderer.class);
if (natAddr.getNatAddress() == null && natAddr.getNatAddress().getIpv4Address() == null) {
LOG.warn("Only Ipv4 SNAT is currently supported. Cannot apply SNAT for [{},{}]", endpointIP,
natAddr.getNatAddress());
continue;
}
Optional<MappingEntryBuilder> entry = natManager.resolveSnatEntry(endpointIP, natAddr.getNatAddress()
.getIpv4Address());
if (entry.isPresent()) {
sNatEntries.add(entry.get());
}
}
return sNatEntries;
}
private String resolveEpIpAddressForSnat(AddressEndpointWithLocation addrEp) {
if (addrEp.getAddressType().equals(MacAddressType.class)) {
ParentEndpointChoice parentEndpointChoice = addrEp.getParentEndpointChoice();
if (parentEndpointChoice instanceof ParentEndpointCase
&& !((ParentEndpointCase) parentEndpointChoice).getParentEndpoint().isEmpty()) {
ParentEndpoint parentEndpoint = ((ParentEndpointCase) parentEndpointChoice).getParentEndpoint().get(0);
if (parentEndpoint.getAddressType().equals(IpPrefixType.class)) {
String[] ipWithPrefix = parentEndpoint.getAddress().split("/");
return ipWithPrefix[0];
} else {
LOG.warn("Endpoint {} Does not have a Parent Ep with IP for SNAT. skipping processing of SNAT",
addrEp);
return null;
}
} else {
LOG.warn("Endpoint {} Does not contain IP address for SNAT. skipping processing of SNAT", addrEp);
return null;
}
} else if (addrEp.getAddressType().equals(IpPrefixType.class)) {
return addrEp.getAddress();
}
return null;
}
@VisibleForTesting
void setTimer(byte time) {
WAIT_FOR_BD_PROCESSING = time;
}
public void syncRouting(PolicyContext policyCtx) {
Configuration cfg = policyCtx.getPolicy().getConfiguration();
if (cfg != null && cfg.getRendererForwarding() != null) {
for (RendererForwardingByTenant fwd : cfg.getRendererForwarding().getRendererForwardingByTenant()) {
if (fwd == null) {
continue;
}
List<InstanceIdentifier<PhysicalInterface>>
physIfacesIid = resolvePhysicalInterfacesForNat(fwd.getRendererNetworkDomain());
Map<InstanceIdentifier<?>, RoutingCommand> routingCommandMap =
routingManager.createRouting(fwd, physIfacesIid, General.Operations.PUT);
routingCommandMap.forEach((node, command) -> {
if (command != null && routingManager.submitRouting(command, node)) {
LOG.debug("Routing was successfully applied: {}.", command);
}
});
}
}
}
public void deleteRouting(PolicyContext policyCtx) {
Configuration cfg = policyCtx.getPolicy().getConfiguration();
if (cfg != null && cfg.getRendererForwarding() != null) {
for (RendererForwardingByTenant fwd : cfg.getRendererForwarding().getRendererForwardingByTenant()) {
if (fwd == null) {
continue;
}
List<InstanceIdentifier<PhysicalInterface>>
physIfacesIid = resolvePhysicalInterfacesForNat(fwd.getRendererNetworkDomain());
Map<InstanceIdentifier<?>, RoutingCommand> routingCommandMap =
routingManager.createRouting(fwd, physIfacesIid, General.Operations.DELETE);
routingCommandMap.forEach((node, command) -> {
if (command != null && routingManager.submitRouting(command, node)) {
LOG.debug("Routing was successfully removed: {}.", command);
}
});
}
}
}
}