The feature is implemented in VPP renderer.
There are two implementation of SNAT:
- centralized
- DVR
In centralized scenario, NAT is configured on one dedicated node.
The node is the one where BVI interface is configured. All static
entries and dynamic entries are on the same node.
In DVR scenario, NAT is configured on every node where endpoints
resode. Static entries on a node are significant only to local
endpoints. There is no support for dynamic NAT yet.
Change-Id: If3c0e80b0fb1c98b85a8c8d7cbd7c25000d33238
Signed-off-by: Tomas Cechvala <tcechval@cisco.com>
Signed-off-by: Michal Cmarada <mcmarada@cisco.com>
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.interests.followed.tenants.FollowedTenantKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.interests.followed.tenants.followed.tenant.FollowedEndpointGroup;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.interests.followed.tenants.followed.tenant.FollowedEndpointGroupKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.endpoints.AddressEndpointWithLocationKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.statistics.store.rev151215.StatisticsStore;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.statistics.store.rev151215.statistics.store.StatisticRecord;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.statistics.store.rev151215.statistics.store.StatisticRecordKey;
.build();
}
+ public static InstanceIdentifier<AddressEndpointLocation> addressEndpointLocationIid(
+ AddressEndpointWithLocationKey key) {
+ return addressEndpointLocationIid(new AddressEndpointLocationKey(key.getAddress(), key.getAddressType(),
+ key.getContextId(), key.getContextType()));
+ }
+
public static InstanceIdentifier<AddressEndpointLocation> addressEndpointLocationIid(
AddressEndpointLocationKey addrEndpointLocationKey) {
return InstanceIdentifier.builder(EndpointLocations.class)
if (oldEpIp != null && oldFloatingIp.getRouterId() != null) {
L3ContextId routerL3ContextId = new L3ContextId(oldFloatingIp.getRouterId().getValue());
DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL,
- IidFactory.l3EndpointIid(routerL3ContextId, oldEpIp).augmentation(NatAddress.class), rwTx);
+ IidFactory.l3EndpointIid(routerL3ContextId, oldEpIp).augmentation(NatAddress.class), rwTx);
}
if (epNatIp != null && newEpIp != null && newFloatingIp.getRouterId() != null) {
L3ContextId routerL3ContextId = new L3ContextId(newFloatingIp.getRouterId().getValue());
NatAddress nat = new NatAddressBuilder().setNatAddress(epNatIp).build();
- AddressEndpointKey aek =
- new AddressEndpointKey(newEpIp.getIpv4Address().getValue() + "/32", IpPrefixType.class,
- routerL3ContextId, L3Context.class);
- LOG.info("Adding NAT augmentation {} for base-endpoint {}", epNatIp, aek);
- rwTx.put(LogicalDatastoreType.OPERATIONAL, IidFactory.addressEndpointIid(aek)
- .augmentation(
- org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.NatAddress.class),
- new org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.NatAddressBuilder()
- .setNatAddress(epNatIp)
- .build(), true);
- rwTx.put(LogicalDatastoreType.OPERATIONAL, IidFactory.l3EndpointIid(routerL3ContextId, newEpIp)
- .augmentation(NatAddress.class), nat, true);
+ LOG.info("Adding NAT augmentation {} for endpoint (deperecated model) {}", epNatIp, newEpIp.getValue());
+ rwTx.put(LogicalDatastoreType.OPERATIONAL,
+ IidFactory.l3EndpointIid(routerL3ContextId, newEpIp).augmentation(NatAddress.class), nat, true);
}
}
return;
}
ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
- boolean isNeutronSecurityRuleAdded = addNeutronSecurityRule(secRule, neutron, rwTx);
+ boolean isNeutronSecurityRuleAdded = true;
+ try {
+ isNeutronSecurityRuleAdded = addNeutronSecurityRule(secRule, neutron, rwTx);
+ } catch (NullPointerException e) {
+ LOG.error("Failed to process rule {}", secRule.getUuid());
+ isNeutronSecurityRuleAdded = false;
+ }
if (isNeutronSecurityRuleAdded) {
DataStoreHelper.submitToDs(rwTx);
} else {
import java.net.Inet4Address;
import java.net.InetAddress;
-import java.util.concurrent.ExecutionException;
import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.NatAddress;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.NatAddressBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.address.endpoints.AddressEndpointKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L3ContextId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContextId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.UniqueId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev170511.IpPrefixType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev170511.L3Context;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.gbp.by.neutron.mappings.base.endpoints.by.ports.BaseEndpointByPort;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.floatingips.attributes.floatingips.Floatingip;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
public class Utils {
+ private static final String MASK_32 = "/32";
+
private Utils() {
throw new UnsupportedOperationException("Cannot create an instance.");
}
IpAddress newEpIp = newFloatingIp.getFixedIpAddress();
IpAddress epNatIp = newFloatingIp.getFloatingIpAddress();
if (epNatIp != null && newEpIp != null) {
- InstanceIdentifier<BaseEndpointByPort> baseEpByPortId =
- NeutronGbpIidFactory.baseEndpointByPortIid(new UniqueId(newFloatingIp.getPortId().getValue()));
- Optional<BaseEndpointByPort> optional =
- DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL, baseEpByPortId, rwTx);
- if (!optional.isPresent()) {
- return;
- }
- NatAddress nat = new NatAddressBuilder().setNatAddress(epNatIp).build();
- AddressEndpointKey addrEpKey = new AddressEndpointKey(optional.get().getAddress(),
- optional.get().getAddressType(), optional.get().getContextId(), optional.get().getContextType());
+ NatAddress natAddr = new NatAddressBuilder().setNatAddress(epNatIp).build();
+ AddressEndpointKey addrEpKey = new AddressEndpointKey(newEpIp.getIpv4Address().getValue() + MASK_32,
+ IpPrefixType.class, new ContextId(newFloatingIp.getRouterId().getValue()), L3Context.class);
rwTx.put(LogicalDatastoreType.OPERATIONAL,
- IidFactory.addressEndpointIid(addrEpKey).augmentation(NatAddress.class), nat, true);
+ IidFactory.addressEndpointIid(addrEpKey).augmentation(NatAddress.class), natAddr, true);
}
if (oldEpIp != null) {
InstanceIdentifier<BaseEndpointByPort> baseEpByPortId =
// NAT augmentation should have been already removed
return;
}
- InstanceIdentifier<BaseEndpointByPort> baseEpByPortId =
- NeutronGbpIidFactory.baseEndpointByPortIid(new UniqueId(removedFloatingIp.getPortId().getValue()));
- Optional<BaseEndpointByPort> optional =
- DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL, baseEpByPortId, rwTx);
- if (!optional.isPresent()) {
- return;
- }
- AddressEndpointKey addrEpKey = new AddressEndpointKey(optional.get().getAddress(),
- optional.get().getAddressType(), optional.get().getContextId(), optional.get().getContextType());
+ AddressEndpointKey addrEpKey =
+ new AddressEndpointKey(removedFloatingIp.getFixedIpAddress().getIpv4Address().getValue() + MASK_32,
+ IpPrefixType.class, new ContextId(removedFloatingIp.getRouterId().getValue()), L3Context.class);
rwTx.delete(LogicalDatastoreType.OPERATIONAL,
IidFactory.addressEndpointIid(addrEpKey).augmentation(NatAddress.class));
}
# To explicitly specify which IP prefix should be used for metadata
# service in openstack, uncomment and modify following line.
# Specifying one IP for metadata service is currently supported.
-metadata-ip = 169.254.169.254
+#metadata-ip = 169.254.169.254
# To explicitly specify which port should be used for metadata
# service in openstack, uncomment and modify following line.
-metadata-port = 80
+#metadata-port = 80
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
import org.opendaylight.groupbasedpolicy.renderer.vpp.api.BridgeDomainManager;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.config.ConfigUtil;
import org.opendaylight.groupbasedpolicy.renderer.vpp.dhcp.DhcpRelayHandler;
import org.opendaylight.groupbasedpolicy.renderer.vpp.iface.InterfaceManager;
import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.LispStateManager;
import org.opendaylight.groupbasedpolicy.renderer.vpp.listener.VppEndpointListener;
import org.opendaylight.groupbasedpolicy.renderer.vpp.listener.VppNodeListener;
import org.opendaylight.groupbasedpolicy.renderer.vpp.manager.VppNodeManager;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.nat.CentralizedNatImpl;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.nat.DvrNatImpl;
import org.opendaylight.groupbasedpolicy.renderer.vpp.nat.NatManager;
import org.opendaylight.groupbasedpolicy.renderer.vpp.policy.BridgeDomainManagerImpl;
import org.opendaylight.groupbasedpolicy.renderer.vpp.policy.ForwardingManager;
interfaceManager = new InterfaceManager(mountDataProvider, dataBroker, flatOverlayManager);
AclManager aclManager = new AclManager(mountDataProvider, interfaceManager);
- NatManager natManager = new NatManager(dataBroker, mountDataProvider);
+ NatManager natManager =
+ (ConfigUtil.getInstance().isL3FlatEnabled()) ? new DvrNatImpl(dataBroker) : new CentralizedNatImpl(
+ dataBroker);
+ LOG.info("Instantiated NAT manager implementation {}", natManager.getClass());
subnetEventManager = new GbpSubnetEventManager(loopbackManager);
dtoEventBus.register(interfaceManager);
dtoEventBus.register(subnetEventManager);
ForwardingManager fwManager =
new ForwardingManager(interfaceManager, aclManager, natManager, routingManager, bdManager,
lispStateManager, loopbackManager, flatOverlayManager, dhcpRelayHandler, dataBroker);
- VppRendererPolicyManager vppRendererPolicyManager = new VppRendererPolicyManager(fwManager, aclManager, dataBroker);
+ VppRendererPolicyManager vppRendererPolicyManager =
+ new VppRendererPolicyManager(fwManager, aclManager, dataBroker);
dtoEventBus.register(vppRendererPolicyManager);
vppNodeListener = new VppNodeListener(dataBroker, vppNodeManager, dtoEventBus);
import org.opendaylight.groupbasedpolicy.renderer.vpp.util.VppIidFactory;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.proxy.arp.rev170315.ProxyArpInterfaceAugmentation;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.proxy.arp.rev170315.ProxyArpInterfaceAugmentationBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.proxy.arp.rev170315.interfaces._interface.ProxyArpBuilder;
protected Boolean enabled;
protected Boolean enableProxyArp;
protected Long vrfId;
+ protected Boolean snatEnabled;
+
public General.Operations getOperation() {
return operation;
return bridgeDomain;
}
+ public boolean isSnatEnabled() {
+ return snatEnabled;
+ }
+
public void execute(ReadWriteTransaction rwTx) {
switch (getOperation()) {
case PUT:
}
protected void addEnableProxyArpAugmentation(InterfaceBuilder interfaceBuilder) {
- if (enableProxyArp != null) {
+ if (enableProxyArp != null && enableProxyArp) {
ProxyArpInterfaceAugmentationBuilder augmentationBuilder = new ProxyArpInterfaceAugmentationBuilder();
augmentationBuilder.setProxyArp((new ProxyArpBuilder()).build());
interfaceBuilder.addAugmentation(ProxyArpInterfaceAugmentation.class, augmentationBuilder.build());
import java.util.Collections;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.config.ConfigUtil;
import org.opendaylight.groupbasedpolicy.renderer.vpp.util.General.Operations;
import org.opendaylight.groupbasedpolicy.util.NetUtils;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
.setDescription(description)
.setType(Loopback.class)
.setName(name)
- .setLinkUpDownTrapEnable(Interface.LinkUpDownTrapEnable.Enabled)
- .addAugmentation(NatInterfaceAugmentation.class, buildInboundNatAugmentation());
+ .setLinkUpDownTrapEnable(Interface.LinkUpDownTrapEnable.Enabled);
+
+ if (!ConfigUtil.getInstance().isL3FlatEnabled()) {
+ interfaceBuilder.addAugmentation(NatInterfaceAugmentation.class, buildInboundNatAugmentation());
+ }
// Create the Loopback augmentation
VppInterfaceAugmentationBuilder
--- /dev/null
+/*
+ * Copyright (c) 2017 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.commands;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+
+import javax.annotation.Nonnull;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.util.General;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.util.VppIidFactory;
+import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.NatInstances;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.NatInstancesBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.NatInstance;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.NatInstanceBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.nat.instance.MappingTable;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.nat.instance.MappingTableBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.nat.instance.mapping.table.MappingEntry;
+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.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.parameters.ExternalIpAddressPool;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+
+public class NatInstanceCommand extends AbstractConfigCommand {
+
+ private final General.Operations operation;
+ private final List<ExternalIpAddressPool> dynamicEntries;
+ private final Map<Long, List<MappingEntryBuilder>> staticEntries;
+ private final Long DEFAULT_FIB = 0L;
+
+ public NatInstanceCommand(NatInstanceCommandBuilder builder) {
+ operation = builder.getOperation();
+ dynamicEntries = builder.getDynamicEntries();
+ staticEntries = builder.getStaticEntries();
+ }
+
+ public General.Operations getOperation() {
+ return operation;
+ }
+
+ public List<ExternalIpAddressPool> getDynamicEntries() {
+ return dynamicEntries;
+ }
+
+ public Map<Long, List<MappingEntryBuilder>> getStaticEntries() {
+ return staticEntries;
+ }
+
+ public List<MappingEntryBuilder> getStaticEntries(long fibId) {
+ if (staticEntries == null) {
+ return Collections.emptyList();
+ }
+ return staticEntries.get(fibId);
+ }
+
+ @Override
+ public InstanceIdentifier<NatInstances> getIid() {
+ return VppIidFactory.getNatInstancesIid();
+ }
+
+ @Override
+ void put(ReadWriteTransaction rwTx) {
+ rwTx.put(LogicalDatastoreType.CONFIGURATION, getIid(), buildNatInstances(), true);
+ }
+
+ @Override
+ void merge(ReadWriteTransaction rwTx) {
+ rwTx.merge(LogicalDatastoreType.CONFIGURATION, getIid(), buildNatInstances(), true);
+ }
+
+ @Override
+ void delete(ReadWriteTransaction rwTx) {
+ DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION, getIid(), rwTx);
+ }
+
+ private NatInstances buildNatInstances() {
+ List<NatInstance> instances = Lists.newArrayList();
+ NatInstanceBuilder builder = new NatInstanceBuilder();
+ builder.setId(DEFAULT_FIB).setExternalIpAddressPool(this.getDynamicEntries());
+ if (getStaticEntries().keySet().contains(DEFAULT_FIB)) {
+ addStaticEntries(builder, getStaticEntries().get(DEFAULT_FIB));
+ getStaticEntries().remove(DEFAULT_FIB);
+ }
+ instances.add(builder.build());
+ builder.setExternalIpAddressPool(null);
+ instances.addAll(getStaticEntries().entrySet().stream().map(entry -> {
+ builder.setId(entry.getKey());
+ addStaticEntries(builder, getStaticEntries().get(entry.getKey()));
+ return builder.build();
+ }).collect(Collectors.toList()));
+ return new NatInstancesBuilder().setNatInstance(instances).build();
+ }
+
+ private void addStaticEntries(@Nonnull NatInstanceBuilder builder,
+ @Nonnull List<MappingEntryBuilder> staticEntries) {
+ builder.setMappingTable(null);
+ AtomicInteger ai = new AtomicInteger();
+ List<MappingEntry> mappingEntries = staticEntries.stream().map(me -> {
+ int value = ai.get();
+ ai.incrementAndGet();
+ return me.setIndex((long) value).build();
+ }).collect(Collectors.toList());
+ MappingTable mappingTable = new MappingTableBuilder().setMappingEntry(mappingEntries).build();
+ builder.setMappingTable(mappingTable);
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer stringBuffer = new StringBuffer();
+ stringBuffer.append("NatInstanceCommand [operations=")
+ .append(operation)
+ .append(", dynamicEntries=")
+ .append(Arrays.toString(dynamicEntries.toArray()))
+ .append(", staticEntries= [");
+
+ staticEntries.forEach((aLong, mappingEntryBuilders) -> {
+ stringBuffer.append("VrfId= ").append(aLong).append(", mappingEntries= [");
+ mappingEntryBuilders.forEach(
+ mappingEntryBuilder -> stringBuffer.append(mappingEntryBuilder.build().toString()).append(", "));
+ stringBuffer.append("]");
+ });
+ stringBuffer.append("]");
+
+ return stringBuffer.toString();
+ }
+
+ public static class NatInstanceCommandBuilder {
+
+ private General.Operations operation;
+ private List<ExternalIpAddressPool> dynamicEntries;
+ private Map<Long, List<MappingEntryBuilder>> staticEntries;
+
+ public NatInstanceCommandBuilder setOperation(General.Operations operation) {
+ this.operation = operation;
+ return this;
+ }
+
+ public NatInstanceCommandBuilder setDynamicEntries(List<ExternalIpAddressPool> dynamicEntries) {
+ this.dynamicEntries = dynamicEntries;
+ return this;
+ }
+
+ public NatInstanceCommandBuilder setStaticEntries(Map<Long, List<MappingEntryBuilder>> staticEntries) {
+ this.staticEntries = staticEntries;
+ return this;
+ }
+
+ public NatInstanceCommandBuilder setStaticEntries(Long fibId, List<MappingEntryBuilder> staticEntries) {
+ if (staticEntries == null) {
+ this.staticEntries = new HashMap<Long, List<MappingEntryBuilder>>();
+ }
+ this.staticEntries.put(fibId, staticEntries);
+ return this;
+ }
+
+ public General.Operations getOperation() {
+ return operation;
+ }
+
+ public List<ExternalIpAddressPool> getDynamicEntries() {
+ return dynamicEntries;
+ }
+
+ public Map<Long, List<MappingEntryBuilder>> getStaticEntries() {
+ return staticEntries;
+ }
+
+ public List<MappingEntryBuilder> getStaticEntries(long fibId) {
+ if (staticEntries == null) {
+ return Collections.emptyList();
+ }
+ return staticEntries.get(Long.valueOf(fibId));
+ }
+
+ public NatInstanceCommand build() {
+ Preconditions.checkNotNull(operation, "Operation of NAT command not specified.");
+ if (staticEntries == null) {
+ staticEntries = new HashMap<Long, List<MappingEntryBuilder>>();
+ }
+ if (dynamicEntries == null) {
+ dynamicEntries = Lists.newArrayList();
+ }
+ return new NatInstanceCommand(this);
+ }
+
+ @Override
+ public String toString() {
+ return build().toString();
+ }
+ }
+}
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
+
+import org.opendaylight.groupbasedpolicy.renderer.vpp.config.ConfigUtil;
import org.opendaylight.groupbasedpolicy.renderer.vpp.util.General;
import org.opendaylight.groupbasedpolicy.renderer.vpp.util.General.Operations;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev170816.NatInterfaceAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev170816.NatInterfaceAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev170816._interface.nat.attributes.Nat;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev170816._interface.nat.attributes.NatBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev170816._interface.nat.attributes.nat.InboundBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev170607.VhostUserRole;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev170607.VppInterfaceAugmentation;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev170607.VppInterfaceAugmentationBuilder;
this.socket = builder.getSocket();
this.role = builder.getRole();
this.enabled = builder.isEnabled();
+ this.snatEnabled = builder.isSnatEnabled();
this.description = builder.getDescription();
this.bridgeDomain = builder.getBridgeDomain();
this.enableProxyArp = builder.getEnableProxyArp();
@Override
public InterfaceBuilder getInterfaceBuilder() {
InterfaceBuilder interfaceBuilder =
- new InterfaceBuilder().setKey(new InterfaceKey(name))
- .setEnabled(enabled)
- .setDescription(description)
- .setType(
- org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev170607.VhostUser.class)
- .setName(name)
- .setLinkUpDownTrapEnable(Interface.LinkUpDownTrapEnable.Enabled);
+ new InterfaceBuilder().setKey(new InterfaceKey(name))
+ .setEnabled(enabled)
+ .setDescription(description)
+ .setType(
+ org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev170607.VhostUser.class)
+ .setName(name)
+ .setLinkUpDownTrapEnable(Interface.LinkUpDownTrapEnable.Enabled);
// Create the vhost augmentation
VppInterfaceAugmentationBuilder vppAugmentationBuilder = new VppInterfaceAugmentationBuilder()
vppAugmentationBuilder.setL2(new L2Builder()
.setInterconnection(new BridgeBasedBuilder().setBridgeDomain(bridgeDomain).build()).build());
}
-
+ if (snatEnabled) {
+ Nat nat = new NatBuilder().setInbound(new InboundBuilder()
+ .setNat44Support(true)
+ .setPostRouting(ConfigUtil.getInstance().isL3FlatEnabled()).build()).build();
+ interfaceBuilder.addAugmentation(NatInterfaceAugmentation.class,
+ new NatInterfaceAugmentationBuilder().setNat(nat).build());
+ }
interfaceBuilder.addAugmentation(VppInterfaceAugmentation.class, vppAugmentationBuilder.build());
addEnableProxyArpAugmentation(interfaceBuilder);
return interfaceBuilder;
public String toString() {
return "VhostUserCommand [socket=" + socket + ", role=" + role + ", bridgeDomain=" + bridgeDomain
+ ", operation=" + operation + ", name=" + name + ", description=" + description + ", enabled="
- + enabled + "]";
+ + enabled + ", enableProxyArp=" + enableProxyArp + ", vrfId=" + vrfId + ", snatEnabled=" + snatEnabled
+ + "]";
}
public static class VhostUserCommandBuilder {
private String bridgeDomain;
private Boolean enableProxyArp;
private Long vrfId;
+ private boolean snatEnabled;
public String getName() {
return name;
return this;
}
+ boolean isSnatEnabled() {
+ return snatEnabled;
+ }
+
+ public VhostUserCommandBuilder setSnatEnabled(boolean snatEnabled) {
+ this.snatEnabled = snatEnabled;
+ return this;
+ }
+
public String getDescription() {
return description;
}
return new VhostUserCommand(this);
}
}
-}
\ No newline at end of file
+}
builder.setSocket(socket);
builder.setRole(VhostUserRole.Client);
}
-
if (ConfigUtil.getInstance().isL3FlatEnabled()) {
builder.setEnableProxyArp(true);
+ builder.setSnatEnabled(true);
}
-
VhostUserCommand vhostUserCommand =
builder.setOperation(operations).setDescription(vppEp.getDescription()).build();
return Optional.of(vhostUserCommand);
}
}
- private long getVni(String tenantUuid) {
- return neutronTenantToVniMapper.getVni(tenantUuid);
+ public long getVni(String tenantUuid) {
+ long vni = neutronTenantToVniMapper.getVni(tenantUuid);
+ LOG.debug("Debugging: getVni {} = {}", tenantUuid, vni);
+ return vni;
}
}
--- /dev/null
+/*
+ * Copyright (c) 2017 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.nat;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+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.commands.NatInstanceCommand;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.NatInstanceCommand.NatInstanceCommandBuilder;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.policy.PolicyContext;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.util.GbpNetconfTransaction;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.util.General;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.util.General.Operations;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.util.VppIidFactory;
+import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
+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.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.parameters.ExternalIpAddressPool;
+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._interface.attributes._interface.type.choice.LoopbackCase;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Table;
+
+public class CentralizedNatImpl extends NatManager {
+
+ private NodeId routingNode = null;
+ private static final Logger LOG = LoggerFactory.getLogger(CentralizedNatImpl.class);
+ private static final long DEFAULT_FIB = 0L;
+
+ public CentralizedNatImpl(DataBroker dataBroker) {
+ super(dataBroker);
+ }
+
+ @Override
+ void submit(NatInstanceCommandBuilder builder, NodeId nodeId) {
+ NatInstanceCommand nat = builder.build();
+ switch (nat.getOperation()) {
+ case MERGE:
+ case PUT:
+ GbpNetconfTransaction.netconfSyncedWrite(VppIidFactory.getNetconfNodeIid(nodeId), nat,
+ GbpNetconfTransaction.RETRY_COUNT);
+ break;
+ case DELETE:
+ GbpNetconfTransaction.netconfSyncedDelete(VppIidFactory.getNetconfNodeIid(nodeId), nat,
+ GbpNetconfTransaction.RETRY_COUNT);
+ break;
+ }
+ }
+
+ @Override
+ public List<NodeId> resolveNodesForSnat() {
+ if (routingNode == null) {
+ ReadOnlyTransaction rTx = dataBroker.newReadOnlyTransaction();
+ Optional<Config> cfg = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
+ VppIidFactory.getVppRendererConfig(), rTx);
+ rTx.close();
+ if (!cfg.isPresent() || cfg.get().getVppEndpoint() == null) {
+ return Collections.emptyList();
+ } ;
+ java.util.Optional<NodeId> nodeId = cfg.get()
+ .getVppEndpoint()
+ .stream()
+ .filter(vppEp -> vppEp.getInterfaceTypeChoice() instanceof LoopbackCase)
+ .filter(vppEp -> ((LoopbackCase) vppEp.getInterfaceTypeChoice()).isBvi() != null)
+ .filter(vppEp -> ((LoopbackCase) vppEp.getInterfaceTypeChoice()).isBvi())
+ .map(vppEp -> vppEp.getVppNodeId())
+ .findFirst();
+ if (!nodeId.isPresent()) {
+ return Collections.emptyList();
+ }
+ routingNode = nodeId.get();
+ }
+ LOG.debug("Resolved node for SNAT: {}", routingNode);
+ return ImmutableList.of(routingNode);
+ }
+
+ @Override public Map<NodeId, NatInstanceCommandBuilder> staticEntries(
+ Table<NodeId, Long, List<MappingEntryBuilder>> staticEntries) {
+ NatInstanceCommandBuilder builder = new NatInstanceCommandBuilder();
+ builder.setOperation(General.Operations.PUT);
+ staticEntries.rowKeySet().forEach(nodeId -> {
+ builder.setStaticEntries(staticEntries.row(nodeId)
+ .entrySet()
+ .stream()
+ .collect(Collectors.toMap(x -> DEFAULT_FIB, y -> y.getValue())));
+ });
+ Map<NodeId, NatInstanceCommandBuilder> result = new HashMap<>();
+ resolveNodesForSnat().forEach(nodeId -> {
+ result.put(nodeId, builder);
+ LOG.debug("Resolved static NAT entries for node {}: {}", nodeId, builder.toString());
+ });
+ return result;
+ }
+
+ @Override
+ public void dynamicEntries(PolicyContext ctx, Map<NodeId, NatInstanceCommandBuilder> nodeBuilders) {
+ List<MappingEntryBuilder> collect = nodeBuilders.values()
+ .stream()
+ .filter(natInstCmdBldr -> natInstCmdBldr.getStaticEntries() != null)
+ .map(natInstCmdBldr -> natInstCmdBldr.getStaticEntries().values())
+ .flatMap(mappingEntryBldr -> mappingEntryBldr.stream())
+ .flatMap(mappingEntryBldr -> mappingEntryBldr.stream())
+ .collect(Collectors.toList());
+ List<ExternalIpAddressPool> dynamicEntries = NatUtil.resolveDynamicNat(ctx, collect);
+ LOG.info("Resolved dynamic NAT entries in cfg version {} for node {}: {}", ctx.getPolicy().getVersion(),
+ routingNode, dynamicEntries);
+ if (routingNode != null && nodeBuilders.get(routingNode) != null) {
+ nodeBuilders.get(routingNode).setDynamicEntries(dynamicEntries);
+ return;
+ } else if (routingNode != null) {
+ nodeBuilders.put(routingNode,
+ new NatInstanceCommandBuilder().setOperation(Operations.PUT).setDynamicEntries(dynamicEntries));
+ }
+ }
+
+ @Override
+ Logger getLogger() {
+ return LOG;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2017 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.nat;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.NatInstanceCommand;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.NatInstanceCommand.NatInstanceCommandBuilder;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.policy.PolicyContext;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.util.GbpNetconfTransaction;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.util.General;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.util.VppIidFactory;
+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.vpp_renderer.rev160425.renderers.renderer.renderer.nodes.renderer.node.PhysicalInterface;
+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.collect.Table;
+
+public class DvrNatImpl extends NatManager {
+
+ public DvrNatImpl(DataBroker dataBroker) {
+ super(dataBroker);
+ }
+
+ private static final Logger LOG = LoggerFactory.getLogger(DvrNatImpl.class);
+
+ @Override
+ void submit(NatInstanceCommandBuilder builder, NodeId nodeId) {
+ NatInstanceCommand nat = builder.build();
+ switch (nat.getOperation()) {
+ case MERGE:
+ case PUT:
+ GbpNetconfTransaction.netconfSyncedWrite(VppIidFactory.getNetconfNodeIid(nodeId), nat,
+ GbpNetconfTransaction.RETRY_COUNT);
+ break;
+ case DELETE:
+ GbpNetconfTransaction.netconfSyncedDelete(VppIidFactory.getNetconfNodeIid(nodeId), nat,
+ GbpNetconfTransaction.RETRY_COUNT);
+ break;
+ }
+ }
+
+ @Override
+ public List<NodeId> resolveNodesForSnat() {
+ ReadOnlyTransaction rTx = dataBroker.newReadOnlyTransaction();
+ List<InstanceIdentifier<PhysicalInterface>> intfcs = NatUtil.resolvePhysicalInterface(rTx);
+ rTx.close();
+ return intfcs.stream().map(NatUtil.resolveNodeId::apply).collect(Collectors.toList());
+ }
+
+ @Override
+ public Map<NodeId, NatInstanceCommandBuilder> staticEntries(
+ Table<NodeId, Long, List<MappingEntryBuilder>> staticEntries) {
+ Map<NodeId, NatInstanceCommandBuilder> result = new HashMap<>();
+ List<NodeId> nodes = resolveNodesForSnat();
+ staticEntries.rowKeySet().forEach(nodeId -> {
+ NatInstanceCommandBuilder builder = new NatInstanceCommandBuilder()
+ .setOperation(General.Operations.PUT)
+ .setStaticEntries(staticEntries.row(nodeId));
+ if (nodes.contains(nodeId)) {
+ result.put(nodeId, builder);
+ LOG.debug("Resolved static NAT entries for node {}, NatEntries: {}.", nodeId, builder.toString());
+ }
+ });
+ return result;
+ }
+
+ @Override
+ public void dynamicEntries(PolicyContext ctx, Map<NodeId, NatInstanceCommandBuilder> nodeBuilders) {
+ LOG.info("No dynamic SNAT entries resolved, not supported yet.");
+ }
+
+ @Override
+ Logger getLogger() {
+ return LOG;
+ }
+}
\r
package org.opendaylight.groupbasedpolicy.renderer.vpp.nat;\r
\r
-import java.net.Inet4Address;\r
-import java.net.Inet6Address;\r
-import java.net.InetAddress;\r
-import java.net.UnknownHostException;\r
+import java.util.Collections;\r
import java.util.List;\r
-import java.util.concurrent.atomic.AtomicInteger;\r
+import java.util.Map;\r
+import java.util.Set;\r
import java.util.stream.Collectors;\r
\r
+import javax.annotation.Nonnull;\r
import javax.annotation.Nullable;\r
\r
-import org.apache.commons.net.util.SubnetUtils;\r
import org.opendaylight.controller.md.sal.binding.api.DataBroker;\r
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;\r
+import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.NatInstanceCommand;\r
+import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.NatInstanceCommand.NatInstanceCommandBuilder;\r
import org.opendaylight.groupbasedpolicy.renderer.vpp.policy.PolicyContext;\r
import org.opendaylight.groupbasedpolicy.renderer.vpp.util.GbpNetconfTransaction;\r
-import org.opendaylight.groupbasedpolicy.renderer.vpp.util.MountedDataBrokerProvider;\r
+import org.opendaylight.groupbasedpolicy.renderer.vpp.util.General;\r
import org.opendaylight.groupbasedpolicy.renderer.vpp.util.VppIidFactory;\r
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;\r
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;\r
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;\r
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;\r
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;\r
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.NatInstance;\r
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.NatInstanceBuilder;\r
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.nat.instance.MappingTable;\r
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.nat.instance.MappingTableBuilder;\r
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.nat.instance.mapping.table.MappingEntry;\r
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.nat.instance.mapping.table.MappingEntryBuilder;\r
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.parameters.ExternalIpAddressPool;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.nodes.RendererNode;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.renderers.renderer.renderer.nodes.renderer.node.PhysicalInterface;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.absolute.location.location.type.ExternalLocationCase;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.NatAddressRenderer;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.Endpoints;\r
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;\r
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;\r
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;\r
import org.slf4j.Logger;\r
-import org.slf4j.LoggerFactory;\r
\r
-import com.google.common.base.Optional;\r
+import com.google.common.base.Function;\r
+import com.google.common.collect.Sets;\r
+import com.google.common.collect.Table;\r
\r
-public class NatManager {\r
+public abstract class NatManager {\r
\r
- private static final Logger LOG = LoggerFactory.getLogger(NatManager.class);\r
+ protected final DataBroker dataBroker;\r
\r
- private final Long id;\r
- private final DataBroker dataBroker;\r
- private final MountedDataBrokerProvider mountDataProvider;\r
-\r
- public NatManager(DataBroker dataBroker, MountedDataBrokerProvider mountDataProvider) {\r
- this.id = 0L;\r
+ public NatManager(DataBroker dataBroker) {\r
this.dataBroker = dataBroker;\r
- this.mountDataProvider = mountDataProvider;\r
}\r
\r
- public Optional<MappingEntryBuilder> resolveSnatEntry(String internal, Ipv4Address external) {\r
- IpAddress internalIp = null;\r
- LOG.trace("Resolving SNAT entry for internal: {}, external: {}", internal, external);\r
- try {\r
- InetAddress inetAddr = InetAddress.getByName(internal);\r
- if (inetAddr instanceof Inet4Address) {\r
- internalIp = new IpAddress(new Ipv4Address(internal));\r
- } else if (inetAddr instanceof Inet6Address) {\r
- internalIp = new IpAddress(new Ipv6Address(internal));\r
- }\r
- } catch (UnknownHostException e) {\r
- LOG.error("Cannot resolve host IP {}. {}", internal, e.getMessage());\r
- return Optional.absent();\r
- }\r
- SubnetUtils subnet = new SubnetUtils(internal + "/32" );\r
- Long index = Integer.toUnsignedLong(subnet.getInfo().asInteger(internal));\r
- MappingEntryBuilder mappingEntryBuilder =\r
- new MappingEntryBuilder().setType(\r
- org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.MappingEntry.Type.Static)\r
- .setIndex(index)\r
- .setInternalSrcAddress(internalIp)\r
- .setExternalSrcAddress(external);\r
- LOG.trace("Resolved SNAT mapping: {}", mappingEntryBuilder.build().toString());\r
- return Optional.of(mappingEntryBuilder);\r
+ abstract Logger getLogger();\r
+\r
+ abstract void submit(NatInstanceCommandBuilder nat, NodeId nodeId);\r
+\r
+ public abstract List<NodeId> resolveNodesForSnat();\r
+\r
+ abstract public Map<NodeId, NatInstanceCommandBuilder> staticEntries(\r
+ Table<NodeId, Long, List<MappingEntryBuilder>> staticEntries);\r
+\r
+ public abstract void dynamicEntries(PolicyContext ctx, Map<NodeId, NatInstanceCommandBuilder> nodeBuilders);\r
+\r
+ public void clearNodes(@Nonnull Endpoints before, @Nullable Endpoints after) {\r
+ Function<Endpoints, Set<NodeId>> f = x -> {\r
+ return nullToEmpty(x.getAddressEndpointWithLocation()).stream()\r
+ .filter(ep -> ep.getAugmentation(NatAddressRenderer.class) != null)\r
+ .filter(ep -> ep.getAbsoluteLocation() != null)\r
+ .map(ep -> (ExternalLocationCase) ep.getAbsoluteLocation().getLocationType())\r
+ .filter(loc -> loc.getExternalNodeMountPoint() != null)\r
+ .map(loc -> loc.getExternalNodeMountPoint().firstKeyOf(Node.class).getNodeId())\r
+ .collect(Collectors.toSet());\r
+ };\r
+ Set<NodeId> nodesToClear = (after != null) ? Sets.difference(f.apply(before), f.apply(after)) : f.apply(before);\r
+ NatInstanceCommand natCmd = new NatInstanceCommandBuilder().setOperation(General.Operations.DELETE).build();\r
+ getLogger().info("Clearing NAT from nodes {}", nodesToClear);\r
+ nodesToClear.forEach(nodeId -> GbpNetconfTransaction\r
+ .netconfSyncedDelete(VppIidFactory.getNetconfNodeIid(nodeId), natCmd, GbpNetconfTransaction.RETRY_COUNT));\r
}\r
\r
- public void submitNatChanges(final List<InstanceIdentifier<PhysicalInterface>> physIfacesIid,\r
- final @Nullable List<MappingEntryBuilder> sNatEntries,\r
- final PolicyContext policyCtx,\r
- final boolean add) {\r
- if (sNatEntries == null) {\r
- LOG.trace("No static NAT entries to submit");\r
- } else{\r
- LOG.trace("Preparing to submit NAT changes {} on physical interfaces", sNatEntries.toArray(), physIfacesIid);\r
- }\r
- for (InstanceIdentifier<PhysicalInterface> iidPhysIface : physIfacesIid) {\r
- InstanceIdentifier<Node> nodeIid = (InstanceIdentifier<Node>) iidPhysIface.firstKeyOf(RendererNode.class).getNodePath();\r
- String phInterfaceName = iidPhysIface.firstKeyOf(PhysicalInterface.class).getInterfaceName();\r
- InstanceIdentifier<Interface> interfaceIID =\r
- VppIidFactory.getInterfaceIID(new InterfaceKey(phInterfaceName));\r
-\r
- Optional<Interface> readIface =\r
- GbpNetconfTransaction.read(nodeIid, LogicalDatastoreType.CONFIGURATION, interfaceIID,\r
- GbpNetconfTransaction.RETRY_COUNT);\r
-\r
- if (!readIface.isPresent()) {\r
- LOG.error("Interface {} not found on mount point {}", phInterfaceName, nodeIid);\r
- continue;\r
- }\r
- if (add) {\r
- NatInstance natInstance =\r
- buildNatInstance(sNatEntries, NatUtil.resolveDynamicNat(policyCtx, sNatEntries));\r
- GbpNetconfTransaction.netconfSyncedWrite(nodeIid,\r
- VppIidFactory.getNatInstanceIid(id), natInstance, GbpNetconfTransaction.RETRY_COUNT);\r
- } else {\r
- if (GbpNetconfTransaction.read(nodeIid, LogicalDatastoreType.CONFIGURATION,\r
- VppIidFactory.getNatInstanceIid(id), GbpNetconfTransaction.RETRY_COUNT).isPresent()) {\r
- GbpNetconfTransaction.netconfSyncedDelete(nodeIid,\r
- VppIidFactory.getNatInstanceIid(id), GbpNetconfTransaction.RETRY_COUNT);\r
- }\r
- }\r
- }\r
+ private <T> List<T> nullToEmpty(@Nullable List<T> list) {\r
+ return list == null ? Collections.emptyList() : list;\r
}\r
\r
- private NatInstance buildNatInstance(List<MappingEntryBuilder> natEntries,\r
- List<ExternalIpAddressPool> poolEntries) {\r
- AtomicInteger ai = new AtomicInteger();\r
- List<MappingEntry> mappingEntries = natEntries.stream().map(me -> {\r
- int value = ai.get();\r
- ai.incrementAndGet();\r
- return me.setIndex((long) value).build();\r
- }).collect(Collectors.toList());\r
- MappingTable mappingTable = new MappingTableBuilder().setMappingEntry(mappingEntries).build();\r
- return new NatInstanceBuilder()\r
- .setId(id)\r
- .setExternalIpAddressPool(poolEntries)\r
- .setMappingTable(mappingTable)\r
- .build();\r
+ public void submitNatChanges(Map<NodeId, NatInstanceCommandBuilder> nat) {\r
+ nat.keySet().forEach(nodeId -> {\r
+ submit(nat.get(nodeId), nodeId);\r
+ });\r
}\r
}\r
\r
package org.opendaylight.groupbasedpolicy.renderer.vpp.nat;\r
\r
+import java.net.Inet4Address;\r
+import java.net.Inet6Address;\r
+import java.net.InetAddress;\r
+import java.net.UnknownHostException;\r
import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Collections;\r
import java.util.HashMap;\r
import java.util.List;\r
import java.util.Map;\r
-import java.util.Map.Entry;\r
import java.util.stream.Collectors;\r
\r
import javax.annotation.Nonnull;\r
import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;\r
import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;\r
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;\r
+import org.opendaylight.groupbasedpolicy.renderer.vpp.config.ConfigUtil;\r
import org.opendaylight.groupbasedpolicy.renderer.vpp.policy.PolicyContext;\r
import org.opendaylight.groupbasedpolicy.renderer.vpp.util.GbpNetconfTransaction;\r
import org.opendaylight.groupbasedpolicy.renderer.vpp.util.VppIidFactory;\r
import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;\r
import org.opendaylight.groupbasedpolicy.util.NetUtils;\r
import org.opendaylight.vbd.impl.transaction.VbdNetconfTransaction;\r
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;\r
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;\r
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;\r
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;\r
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;\r
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;\r
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;\r
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;\r
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.nat.instance.mapping.table.MappingEntryBuilder;\r
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.parameters.ExternalIpAddressPool;\r
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.parameters.ExternalIpAddressPoolBuilder;\r
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev170511.SubnetAugmentRenderer;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev170511.has.subnet.Subnet;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev170511.has.subnet.subnet.AllocationPool;\r
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.RendererNodes;\r
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.nodes.RendererNode;\r
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.forwarding.RendererForwardingByTenant;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.forwarding.renderer.forwarding.by.tenant.RendererNetworkDomain;\r
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.VppInterfaceAugmentation;\r
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.renderers.renderer.renderer.nodes.renderer.node.PhysicalInterface;\r
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.renderers.renderer.renderer.nodes.renderer.node.PhysicalInterfaceKey;\r
import org.slf4j.Logger;\r
import org.slf4j.LoggerFactory;\r
\r
-import com.google.common.annotations.VisibleForTesting;\r
+import com.google.common.base.Function;\r
import com.google.common.base.Optional;\r
+import com.google.common.base.Preconditions;\r
+import com.google.common.collect.ImmutableList;\r
\r
public class NatUtil {\r
private static final Logger LOG = LoggerFactory.getLogger(NatUtil.class);\r
\r
+ @SuppressWarnings("unchecked")\r
+ static Function<InstanceIdentifier<PhysicalInterface>, NodeId> resolveNodeId = (intf) -> {\r
+ return Preconditions\r
+ .checkNotNull(checkIid(intf).firstKeyOf(RendererNode.class).getNodePath().firstKeyOf(Node.class))\r
+ .getNodeId();\r
+ };\r
+\r
+ @SuppressWarnings("unchecked")\r
+ static Function<InstanceIdentifier<PhysicalInterface>, InstanceIdentifier<Interface>> resolveInterfaceIid = (intf) -> {\r
+ checkIid(intf);\r
+ return VppIidFactory\r
+ .getInterfaceIID(new InterfaceKey(checkIid(intf).firstKeyOf(PhysicalInterface.class).getInterfaceName()));\r
+ };\r
+\r
+ static private InstanceIdentifier<PhysicalInterface> checkIid(InstanceIdentifier<PhysicalInterface> iid) {\r
+ Preconditions.checkNotNull(iid.firstKeyOf(RendererNode.class).getNodePath().firstKeyOf(Node.class));\r
+ return iid;\r
+ }\r
+\r
public void setInboundInterface(Interface iface, WriteTransaction wTx) {\r
InstanceIdentifier<Nat> natIid = buildNatIid(VppIidFactory.getInterfaceIID(iface.getKey()));\r
Nat nat =\r
- new NatBuilder().setInbound(new InboundBuilder().setNat44Support(true).setPostRouting(false).build())\r
+ new NatBuilder().setInbound(new InboundBuilder().setNat44Support(true).setPostRouting(ConfigUtil.getInstance().isL3FlatEnabled()).build())\r
.build();\r
wTx.put(LogicalDatastoreType.CONFIGURATION, natIid, nat);\r
}\r
public static void setOutboundInterface(Interface iface, InstanceIdentifier<Node> vppIid) {\r
InstanceIdentifier<Nat> natIid = buildNatIid(VppIidFactory.getInterfaceIID(iface.getKey()));\r
Nat nat =\r
- new NatBuilder().setOutbound(new OutboundBuilder().setNat44Support(true).setPostRouting(false).build())\r
+ new NatBuilder().setOutbound(new OutboundBuilder().setNat44Support(true).setPostRouting(ConfigUtil.getInstance().isL3FlatEnabled()).build())\r
.build();\r
GbpNetconfTransaction.netconfSyncedWrite(vppIid, natIid, nat, GbpNetconfTransaction.RETRY_COUNT);\r
\r
return ifaceIid.builder().augmentation(NatInterfaceAugmentation.class).child(Nat.class).build();\r
}\r
\r
- public static Optional<InstanceIdentifier<PhysicalInterface>> resolvePhysicalInterface(IpPrefix extSubnetPrefix,\r
+ public static @Nonnull List<InstanceIdentifier<PhysicalInterface>> resolvePhysicalInterface(IpPrefix extSubnetPrefix,\r
ReadOnlyTransaction rTx) {\r
Optional<RendererNodes> readFromDs =\r
DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL, VppIidFactory.getRendererNodesIid(), rTx);\r
rTx.close();\r
if (!readFromDs.isPresent() || readFromDs.get().getRendererNode() == null) {\r
- return Optional.absent();\r
+ return Collections.emptyList();\r
}\r
RendererNodes rendererNodes = readFromDs.get();\r
List<RendererNode>\r
.filter(rn -> rn.getAugmentation(VppInterfaceAugmentation.class) != null)\r
.filter(rn -> rn.getAugmentation(VppInterfaceAugmentation.class).getPhysicalInterface() != null)\r
.collect(Collectors.toList());\r
+ List<InstanceIdentifier<PhysicalInterface>> iids = new ArrayList<>();\r
for (RendererNode rn : vppNodes) {\r
java.util.Optional<PhysicalInterface>\r
optResolvedIface =\r
.anyMatch(ipAddr -> NetUtils.isInRange(extSubnetPrefix, String.valueOf(ipAddr.getValue()))))\r
.findFirst();\r
if (optResolvedIface.isPresent()) {\r
- return Optional.of(VppIidFactory.getRendererNodeIid(rn)\r
+ iids.add(VppIidFactory.getRendererNodeIid(rn)\r
.builder()\r
.augmentation(VppInterfaceAugmentation.class)\r
.child(PhysicalInterface.class, new PhysicalInterfaceKey(optResolvedIface.get().getKey()))\r
.build());\r
}\r
}\r
- return Optional.absent();\r
+ return iids;\r
}\r
\r
- static List<ExternalIpAddressPool> resolveDynamicNat(@Nonnull PolicyContext policyCtx,\r
- @Nullable List<MappingEntryBuilder> sNatEntries) {\r
- List<RendererForwardingByTenant> forwardingByTenantList =\r
- policyCtx.getPolicy().getConfiguration().getRendererForwarding().getRendererForwardingByTenant();\r
- Map<Long, Ipv4Prefix> extCache = new HashMap<>();\r
- // loop through forwarding by tenant\r
- for (RendererForwardingByTenant rft : forwardingByTenantList) {\r
- // loop through renderer network domain\r
- for (RendererNetworkDomain domain : rft.getRendererNetworkDomain()) {\r
- final SubnetAugmentRenderer subnetAugmentation = domain.getAugmentation(SubnetAugmentRenderer.class);\r
- final Subnet subnet = subnetAugmentation.getSubnet();\r
- if (subnet != null && !subnet.isIsTenant() && subnet.getAllocationPool() != null) {\r
- // loop through allocation pool\r
- for (AllocationPool pool : subnet.getAllocationPool()) {\r
- final IpPrefix subnetIpPrefix = subnet.getIpPrefix();\r
- if (subnetIpPrefix.getIpv4Prefix() != null) {\r
- final String firstEntry = pool.getFirst();\r
- final String lastEntry = pool.getLast();\r
- extCache.putAll(resolveDynamicNatPrefix(subnetIpPrefix.getIpv4Prefix(), firstEntry, lastEntry,\r
- sNatEntries));\r
- }\r
- }\r
+ public static @Nonnull List<InstanceIdentifier<PhysicalInterface>> resolvePhysicalInterface(ReadOnlyTransaction rTx) {\r
+ Optional<RendererNodes> readFromDs =\r
+ DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL, VppIidFactory.getRendererNodesIid(), rTx);\r
+ rTx.close();\r
+ if (!readFromDs.isPresent() || readFromDs.get().getRendererNode() == null) {\r
+ return Collections.emptyList();\r
+ }\r
+ RendererNodes rendererNodes = readFromDs.get();\r
+ List<RendererNode>\r
+ vppNodes =\r
+ rendererNodes.getRendererNode()\r
+ .stream()\r
+ .filter(rn -> rn.getAugmentation(VppInterfaceAugmentation.class) != null)\r
+ .filter(rn -> rn.getAugmentation(VppInterfaceAugmentation.class).getPhysicalInterface() != null)\r
+ .collect(Collectors.toList());\r
+ List<InstanceIdentifier<PhysicalInterface>> iids = new ArrayList<>();\r
+ for (RendererNode rn : vppNodes) {\r
+ java.util.Optional<PhysicalInterface>\r
+ optResolvedIface =\r
+ rn.getAugmentation(VppInterfaceAugmentation.class)\r
+ .getPhysicalInterface()\r
+ .stream()\r
+ .filter(phIface -> phIface.getAddress() != null)\r
+ .filter(phIface -> phIface.isExternal())\r
+ .findFirst();\r
+ if (optResolvedIface.isPresent()) {\r
+ iids.add(VppIidFactory.getRendererNodeIid(rn)\r
+ .builder()\r
+ .augmentation(VppInterfaceAugmentation.class)\r
+ .child(PhysicalInterface.class, new PhysicalInterfaceKey(optResolvedIface.get().getKey()))\r
+ .build());\r
}\r
}\r
+ return iids;\r
}\r
- final List<ExternalIpAddressPool> extIps = new ArrayList<>();\r
- for (Entry<Long, Ipv4Prefix> entry : extCache.entrySet()) {\r
- extIps.add(new ExternalIpAddressPoolBuilder().setPoolId(entry.getKey())\r
- .setExternalIpPool(entry.getValue())\r
- .build());\r
+\r
+ public static Optional<MappingEntryBuilder> createStaticEntry(String internal, Ipv4Address external) {\r
+ IpAddress internalIp = null;\r
+ try {\r
+ InetAddress inetAddr = InetAddress.getByName(internal);\r
+ if (inetAddr instanceof Inet4Address) {\r
+ internalIp = new IpAddress(new Ipv4Address(internal));\r
+ } else if (inetAddr instanceof Inet6Address) {\r
+ internalIp = new IpAddress(new Ipv6Address(internal));\r
+ }\r
+ } catch (UnknownHostException e) {\r
+ LOG.error("Cannot resolve host IP {}. {}", internal, e.getMessage());\r
+ return Optional.absent();\r
+ }\r
+ SubnetUtils subnet = new SubnetUtils(internal + "/32");\r
+ Long index = Integer.toUnsignedLong(subnet.getInfo().asInteger(internal));\r
+ MappingEntryBuilder mappingEntryBuilder = new MappingEntryBuilder()\r
+ .setType(\r
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.MappingEntry.Type.Static)\r
+ .setIndex(index)\r
+ .setInternalSrcAddress(internalIp)\r
+ .setExternalSrcAddress(external);\r
+ return Optional.of(mappingEntryBuilder);\r
+ }\r
+\r
+ public static List<ExternalIpAddressPool> resolveDynamicNat(@Nonnull PolicyContext policyCtx,\r
+ @Nullable List<MappingEntryBuilder> sNatEntries) {\r
+ Optional<List<RendererForwardingByTenant>> forwardingByTenantLists = Optional.of(policyCtx)\r
+ .transform(x -> x.getPolicy())\r
+ .transform(x -> x.getConfiguration())\r
+ .transform(x -> x.getRendererForwarding())\r
+ .transform(x -> x.getRendererForwardingByTenant());\r
+ if (!forwardingByTenantLists.isPresent()) {\r
+ LOG.warn("No dynamic NAT resolved in cfg version {}.", policyCtx.getPolicy().getVersion());\r
+ return ImmutableList.of();\r
}\r
- return extIps;\r
+ Map<Long, Ipv4Prefix> extCache = new HashMap<>();\r
+ forwardingByTenantLists.get()\r
+ .stream()\r
+ .map(rft -> rft.getRendererNetworkDomain())\r
+ .flatMap(Collection::stream)\r
+ .filter(domain -> domain.getAugmentation(SubnetAugmentRenderer.class) != null)\r
+ .map(domain -> domain.getAugmentation(SubnetAugmentRenderer.class).getSubnet())\r
+ .filter(subnet -> !subnet.isIsTenant() && subnet.getAllocationPool() != null)\r
+ .forEach(subnet -> {\r
+ final IpPrefix subnetIpPrefix = subnet.getIpPrefix();\r
+ subnet.getAllocationPool().forEach(pool -> {\r
+ if (subnetIpPrefix.getIpv4Prefix() != null) {\r
+ final String firstEntry = pool.getFirst();\r
+ final String lastEntry = pool.getLast();\r
+ extCache.putAll(resolveDynamicNatPrefix(subnetIpPrefix.getIpv4Prefix(), firstEntry, lastEntry,\r
+ sNatEntries));\r
+ }\r
+ });\r
+ });\r
+ List<ExternalIpAddressPool> extPools = extCache.entrySet()\r
+ .stream()\r
+ .map(entry -> new ExternalIpAddressPoolBuilder().setPoolId(entry.getKey())\r
+ .setExternalIpPool(entry.getValue())\r
+ .build())\r
+ .collect(Collectors.toList());\r
+ LOG.trace("Resolved dynamic NAT pools in cfg version {}: {}", policyCtx.getPolicy().getVersion(), extPools);\r
+ return extPools;\r
}\r
\r
- @VisibleForTesting\r
- private static Map<Long, Ipv4Prefix> resolveDynamicNatPrefix(@Nonnull final Ipv4Prefix prefix,\r
+\r
+ static Map<Long, Ipv4Prefix> resolveDynamicNatPrefix(@Nonnull final Ipv4Prefix prefix,\r
@Nonnull final String first,\r
@Nullable final String last,\r
@Nullable final List<MappingEntryBuilder> natEntries) {\r
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.DhcpRelayCommand;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.NatInstanceCommand.NatInstanceCommandBuilder;
import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.RoutingCommand;
import org.opendaylight.groupbasedpolicy.renderer.vpp.config.ConfigUtil;
import org.opendaylight.groupbasedpolicy.renderer.vpp.dhcp.DhcpRelayHandler;
import org.opendaylight.groupbasedpolicy.renderer.vpp.iface.InterfaceManager;
import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.LispStateManager;
-import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.loopback.LoopbackManager;
import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.flat.overlay.FlatOverlayManager;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.loopback.LoopbackManager;
import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.mappers.NeutronTenantToVniMapper;
import org.opendaylight.groupbasedpolicy.renderer.vpp.nat.NatManager;
import org.opendaylight.groupbasedpolicy.renderer.vpp.nat.NatUtil;
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.RendererPolicy;
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.RendererForwarding;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
import com.google.common.base.Strings;
+import com.google.common.collect.HashBasedTable;
+import com.google.common.collect.ImmutableTable;
+import com.google.common.collect.Lists;
import com.google.common.collect.SetMultimap;
import com.google.common.collect.Table;
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);
+ private static Optional<Endpoints> checkEndpoints(PolicyContext ctx) {
+ Optional<PolicyContext> contextOptional = Optional.fromNullable(ctx);
+ if (contextOptional.isPresent()) {
+ Optional<RendererPolicy> policyOptional = Optional.fromNullable(contextOptional.get().getPolicy());
+ if (policyOptional.isPresent()) {
+ Optional<Configuration> configOptional = Optional.fromNullable(policyOptional.get().getConfiguration());
+ if (configOptional.isPresent()) {
+ return Optional.fromNullable(configOptional.get().getEndpoints());
}
}
}
+ return Optional.absent();
}
- 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);
- }
- }
- }
+
+ void createNatEntries(@Nonnull PolicyContext after) {
+ LOG.info("Resolving NAT for cfg version {}", after.getPolicy().getVersion());
+ Preconditions.checkArgument(checkEndpoints(after).isPresent());
+ final Table<NodeId, Long, List<MappingEntryBuilder>> staticEntries =
+ resolveStaticNatTableEntries(checkEndpoints(after).get());
+ Map<NodeId, NatInstanceCommandBuilder> natByNode = natManager.staticEntries(staticEntries);
+ natManager.dynamicEntries(after, natByNode);
+ natManager.submitNatChanges(natByNode);
}
- private 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());
- }
- }
+ void syncNatEntries(@Nonnull PolicyContext before,@Nonnull PolicyContext after) {
+ LOG.info("Syncing NAT entries for version {}", after.getPolicy().getVersion());
+ Optional<Endpoints> endpointsBeforeOptional = checkEndpoints(before);
+
+ Endpoints endpointsAfter = null;
+ Optional<Endpoints> endpointsAfterOptional = checkEndpoints(after);
+ if (endpointsAfterOptional != null && endpointsAfterOptional.isPresent()) {
+ endpointsAfter = endpointsAfterOptional.get();
+ }
+
+ if (endpointsBeforeOptional.isPresent()) {
+ natManager.clearNodes(endpointsBeforeOptional.get(), endpointsAfter);
+ }
+
+ if (endpointsAfter != null) {
+ createNatEntries(after);
}
- return physIfaces;
}
- private Optional<IpPrefix> resolveIpPrefix(RendererNetworkDomain rendDomain) {
- SubnetAugmentRenderer subnetAug = rendDomain.getAugmentation(SubnetAugmentRenderer.class);
- if (subnetAug.getSubnet() != null) {
- return Optional.of(subnetAug.getSubnet().getIpPrefix());
+ void deleteNatEntries(@Nonnull PolicyContext before) {
+ Optional<Endpoints> endpointsBeforeOptional = checkEndpoints(before);
+ if (endpointsBeforeOptional.isPresent()) {
+ natManager.clearNodes(endpointsBeforeOptional.get(), null);
}
- 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;
+ private ImmutableTable<NodeId, Long, List<MappingEntryBuilder>> resolveStaticNatTableEntries(
+ @Nonnull Endpoints endpoints) {
+ Table<NodeId, Long, List<MappingEntryBuilder>> resultBuilder = HashBasedTable.create();
+ List<Predicate<AddressEndpointWithLocation>> filter = Lists.newArrayList();
+ filter.add(ep -> ep.getAugmentation(NatAddressRenderer.class) != null);
+ filter.add(ep -> resolveEpIpAddressForSnat(ep) != null);
+ filter.add(ep -> ep.getAbsoluteLocation() != null);
+ filter.add(ep -> ep.getAbsoluteLocation().getLocationType() instanceof ExternalLocationCase);
+ filter.add(ep -> ep.getAugmentation(NatAddressRenderer.class) != null);
+ filter.add(ep -> ep.getAugmentation(NatAddressRenderer.class).getNatAddress() != null);
+ filter.add(ep -> ep.getAugmentation(NatAddressRenderer.class).getNatAddress().getIpv4Address() != null);
+
+ endpoints.getAddressEndpointWithLocation().forEach(addrEp -> {
+ if (!filter.stream().allMatch(f -> f.apply(addrEp))) {
+ return;
}
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());
+ NodeId nodeId = ((ExternalLocationCase) addrEp.getAbsoluteLocation().getLocationType())
+ .getExternalNodeMountPoint().firstKeyOf(Node.class).getNodeId();
+ Optional<MappingEntryBuilder> entry =
+ NatUtil.createStaticEntry(endpointIP, natAddr.getNatAddress().getIpv4Address());
if (entry.isPresent()) {
- sNatEntries.add(entry.get());
+ long tenantId = flatOverlayManager.getVni(addrEp.getTenant().getValue());
+ if (resultBuilder.get(nodeId, tenantId) != null) {
+ resultBuilder.get(nodeId, tenantId).add(entry.get());
+ } else {
+ resultBuilder.put(nodeId, tenantId, Lists.newArrayList(entry.get()));
+ }
}
- }
- return sNatEntries;
+ });
+ return ImmutableTable.copyOf(resultBuilder);
}
private String resolveEpIpAddressForSnat(AddressEndpointWithLocation addrEp) {
if (fwd == null) {
continue;
}
-
List<InstanceIdentifier<PhysicalInterface>>
physIfacesIid = resolvePhysicalInterfacesForNat(fwd.getRendererNetworkDomain());
Map<InstanceIdentifier<Node>, RoutingCommand> routingCommandMap =
}
}
+ 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()) {
+ List<InstanceIdentifier<PhysicalInterface>> resPhIface =
+ NatUtil.resolvePhysicalInterface(resolvedIpPrefix.get(), dataBroker.newReadOnlyTransaction());
+ if (!resPhIface.isEmpty()) {
+ physIfaces.addAll(resPhIface);
+ }
+ }
+ }
+ return physIfaces;
+ }
+
+ public static Optional<IpPrefix> resolveIpPrefix(RendererNetworkDomain rendDomain) {
+ SubnetAugmentRenderer subnetAug = rendDomain.getAugmentation(SubnetAugmentRenderer.class);
+ if (subnetAug.getSubnet() != null) {
+ return Optional.of(subnetAug.getSubnet().getIpPrefix());
+ }
+ return Optional.absent();
+ }
+
List<DhcpRelayCommand> createDhcpRelay(RendererForwarding rendererForwarding,
SetMultimap<String, NodeId> vppNodesByL2Fd) {
for (RendererForwardingByTenant forwardingByTenant : rendererForwarding.getRendererForwardingByTenant()) {
fwManager.syncDhcpRelay(createdDhcpRelays, deletedDhcpRelays);
}
- fwManager.syncNatEntries(policyCtxAfter);
-
+ fwManager.syncNatEntries(policyCtxBefore, policyCtxAfter);
fwManager.deleteRouting(policyCtxBefore);
fwManager.syncRouting(policyCtxAfter);
}
rEpKeys.forEach(rEpKey -> fwManager.createForwardingForEndpoint(rEpKey, policyCtx));
- fwManager.syncNatEntries(policyCtx);
+ fwManager.createNatEntries(policyCtx);
fwManager.syncRouting(policyCtx);
}
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.NatInstances;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.NatInstance;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.NatInstanceKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.nat.instance.MappingTable;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.nat.instance.mapping.table.MappingEntry;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.nat.instance.mapping.table.MappingEntryKey;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.Routing;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.RoutingInstance;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.RoutingInstanceKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170801.gpe.entry.table.grouping.gpe.entry.table.GpeEntry;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170801.gpe.entry.table.grouping.gpe.entry.table.GpeEntryKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170801.gpe.feature.data.grouping.GpeFeatureData;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev170911.ItrRemoteLocatorSetsGrouping;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev170911.Lisp;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev170911.dp.subtable.grouping.LocalMappings;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev170911.dp.subtable.grouping.local.mappings.LocalMapping;
org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214._interface.acl.attributes.Acl.class);
}
- public static InstanceIdentifier<NatInstance> getNatInstanceIid(Long natInstance) {
+ public static InstanceIdentifier<MappingEntry> getMappingEntryIid(long natInstance, long index) {
return InstanceIdentifier.builder(NatConfig.class)
- .child(NatInstances.class)
- .child(NatInstance.class, new NatInstanceKey(natInstance))
- .build();
+ .child(NatInstances.class)
+ .child(NatInstance.class, new NatInstanceKey(natInstance))
+ .child(MappingTable.class)
+ .child(MappingEntry.class, new MappingEntryKey(index))
+ .build();
+ }
+
+ public static InstanceIdentifier<NatInstances> getNatInstancesIid() {
+ return InstanceIdentifier.builder(NatConfig.class).child(NatInstances.class).build();
+ }
+
+ public static InstanceIdentifier<NatInstance> getNatInstanceIid(Long natInstance) {
+ return getNatInstancesIid().child(NatInstance.class, new NatInstanceKey(natInstance));
}
public static InstanceIdentifier<RoutingProtocol> getRoutingInstanceIid(
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev170607.VhostUser;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev170607.VhostUserRole;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev170607.VppInterfaceAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev170816._interface.nat.attributes.Nat;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
@Override
public Collection<Class<?>> getClassesFromModules() {
return Arrays.asList(Node.class, VppEndpoint.class, Interfaces.class, BridgeDomains.class,
- LocationProviders.class, IpPrefixType.class, MacAddressType.class);
+ LocationProviders.class, IpPrefixType.class, MacAddressType.class, Nat.class);
}
@Before
import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.LispStateManager;
import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.flat.overlay.FlatOverlayManager;
import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.loopback.LoopbackManager;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.nat.CentralizedNatImpl;
import org.opendaylight.groupbasedpolicy.renderer.vpp.nat.NatManager;
import org.opendaylight.groupbasedpolicy.renderer.vpp.policy.acl.AclManager;
import org.opendaylight.groupbasedpolicy.renderer.vpp.routing.RoutingManager;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.TopologyVbridgeAugment;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.tunnel.vxlan.rev170327.TunnelTypeVxlan;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.tunnel.vxlan.rev170327.network.topology.topology.tunnel.parameters.VxlanTunnelParameters;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev170615.access.lists.acl.access.list.entries.ace.matches.ace.type.VppAce;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev170816._interface.nat.attributes.Nat;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
public Collection<Class<?>> getClassesFromModules() {
return Arrays.asList(Node.class, VppEndpoint.class, Interfaces.class, BridgeDomains.class,
LocationProviders.class, L2FloodDomain.class, VxlanVni.class, TopologyVbridgeAugment.class,
- TunnelTypeVxlan.class, PhysicalLocationRef.class, AccessLists.class,
- VppInterfaceAugmentation.class, VppAclInterfaceAugmentation.class, VxlanTunnelParameters.class);
- }
+ TunnelTypeVxlan.class, PhysicalLocationRef.class, AccessLists.class, VppAce.class,
+ VppInterfaceAugmentation.class, VppAclInterfaceAugmentation.class, VxlanTunnelParameters.class,
+ PhysicalLocationRef.class, Nat.class);
+ }
@Before
public void init() throws Exception {
flatOverlayManager = new FlatOverlayManager(dataBroker, mountedDataProviderMock);
ifaceManager = new InterfaceManager(mountedDataProviderMock, dataBroker, flatOverlayManager);
aclManager = new AclManager(mountedDataProviderMock, ifaceManager);
- natManager = new NatManager(dataBroker, mountedDataProviderMock);
+ natManager = new CentralizedNatImpl(dataBroker);
routingManager = new RoutingManager(dataBroker, mountedDataProviderMock);
bdManager = new BridgeDomainManagerImpl(mountPointDataBroker);
dhcpRelayHandler = new DhcpRelayHandler(dataBroker);
storeVppEndpoint(clientEp.getKey(), CLIENT_MAC, CLIENT_1_IFACE_NAME, createVppEndpointIid(clientEp.getKey()));
storeVppEndpoint(webEp.getKey(), WEB_MAC, WEB_1_IFACE_NAME, createVppEndpointIid(webEp.getKey()));
- Configuration configuration = DtoFactory.createConfiguration(Arrays.asList(clientEp), Arrays.asList(webEp));
+ Configuration configuration = DtoFactory.createConfiguration(Collections.singletonList(clientEp),
+ Collections.singletonList(webEp));
RendererPolicy rendererPolicy =
new RendererPolicyBuilder().setVersion(1L).setConfiguration(configuration).build();
RendererPolicyConfEvent event = new RendererPolicyConfEvent(RENDERER_POLICY_IID, null, rendererPolicy);
Assert.assertTrue(interconnection instanceof BridgeBased);
Assert.assertEquals(expectedBridgeDomain, ((BridgeBased) interconnection).getBridgeDomain());
} else {
- if (vppIfaceAug != null) {
- L2 l2 = vppIfaceAug.getL2();
- if (l2 != null) {
- Assert.assertNull(l2.getInterconnection());
- }
+ L2 l2 = vppIfaceAug.getL2();
+ if (l2 != null) {
+ Assert.assertNull(l2.getInterconnection());
}
}
}