2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
\r
4 * This program and the accompanying materials are made available under the
\r
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
\r
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
\r
9 package org.opendaylight.groupbasedpolicy.renderer.vpp.nat;
\r
11 import java.net.Inet4Address;
\r
12 import java.net.Inet6Address;
\r
13 import java.net.InetAddress;
\r
14 import java.net.UnknownHostException;
\r
15 import java.util.List;
\r
16 import java.util.concurrent.atomic.AtomicInteger;
\r
17 import java.util.stream.Collectors;
\r
19 import org.apache.commons.net.util.SubnetUtils;
\r
20 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
\r
21 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
\r
22 import org.opendaylight.groupbasedpolicy.renderer.vpp.policy.PolicyContext;
\r
23 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.GbpNetconfTransaction;
\r
24 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.MountedDataBrokerProvider;
\r
25 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.VppIidFactory;
\r
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
\r
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
\r
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
\r
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
\r
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
\r
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
\r
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.NatInstance;
\r
33 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.NatInstanceBuilder;
\r
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.nat.instance.MappingTable;
\r
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.nat.instance.MappingTableBuilder;
\r
36 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
37 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
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.parameters.ExternalIpAddressPool;
\r
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.nodes.RendererNode;
\r
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.renderers.renderer.renderer.nodes.renderer.node.PhysicalInterface;
\r
41 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
\r
42 import org.slf4j.Logger;
\r
43 import org.slf4j.LoggerFactory;
\r
45 import com.google.common.base.Optional;
\r
46 public class NatManager {
\r
48 private static final Logger LOG = LoggerFactory.getLogger(NatManager.class);
\r
50 private final Long id;
\r
51 private final DataBroker dataBroker;
\r
52 private final MountedDataBrokerProvider mountDataProvider;
\r
54 public NatManager(DataBroker dataBroker, MountedDataBrokerProvider mountDataProvider) {
\r
56 this.dataBroker = dataBroker;
\r
57 this.mountDataProvider = mountDataProvider;
\r
60 public Optional<MappingEntryBuilder> resolveSnatEntry(String internal, Ipv4Address external) {
\r
61 IpAddress internalIp = null;
\r
62 LOG.trace("Resolving SNAT entry for internal: {}, external: {}", internal, external);
\r
64 InetAddress inetAddr = InetAddress.getByName(internal);
\r
65 if (inetAddr instanceof Inet4Address) {
\r
66 internalIp = new IpAddress(new Ipv4Address(internal));
\r
67 } else if (inetAddr instanceof Inet6Address) {
\r
68 internalIp = new IpAddress(new Ipv6Address(internal));
\r
70 } catch (UnknownHostException e) {
\r
71 LOG.error("Cannot resolve host IP {}. {}", internal, e.getMessage());
\r
72 return Optional.absent();
\r
74 SubnetUtils subnet = new SubnetUtils(internal + "/32" );
\r
75 Long index = Integer.toUnsignedLong(subnet.getInfo().asInteger(internal));
\r
76 MappingEntryBuilder mappingEntryBuilder =
\r
77 new MappingEntryBuilder().setType(
\r
78 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.MappingEntry.Type.Static)
\r
80 .setInternalSrcAddress(internalIp)
\r
81 .setExternalSrcAddress(external);
\r
82 LOG.trace("Resolved SNAT mapping: {}", mappingEntryBuilder.build().toString());
\r
83 return Optional.of(mappingEntryBuilder);
\r
86 public void submitNatChanges(List<InstanceIdentifier<PhysicalInterface>> physIfacesIid,
\r
87 List<MappingEntryBuilder> natEntries, PolicyContext policyCtx, boolean add) {
\r
88 LOG.trace("Preparing to submit NAT changes {} on physical interfaces", natEntries.toArray(), physIfacesIid);
\r
89 for (InstanceIdentifier<PhysicalInterface> iidPhysIface : physIfacesIid) {
\r
90 InstanceIdentifier<?> nodeIid = iidPhysIface.firstKeyOf(RendererNode.class).getNodePath();
\r
91 Optional<DataBroker> mountPointDataBroker = mountDataProvider.getDataBrokerForMountPoint(nodeIid);
\r
92 if (!mountPointDataBroker.isPresent()) {
\r
93 throw new IllegalStateException("Cannot find data broker for mount point " + nodeIid);
\r
95 String phInterfaceName = iidPhysIface.firstKeyOf(PhysicalInterface.class).getInterfaceName();
\r
96 InstanceIdentifier<Interface> interfaceIID =
\r
97 VppIidFactory.getInterfaceIID(new InterfaceKey(phInterfaceName));
\r
99 Optional<Interface> readIface =
\r
100 GbpNetconfTransaction.read(mountPointDataBroker.get(), LogicalDatastoreType.CONFIGURATION, interfaceIID,
\r
101 GbpNetconfTransaction.RETRY_COUNT);
\r
103 if (!readIface.isPresent()) {
\r
104 LOG.error("Interface {} not found on mount point {}", phInterfaceName, nodeIid);
\r
108 LOG.trace("Setting outbound NAT on interface {} on node: {}", iidPhysIface.getPathArguments(), nodeIid);
\r
109 NatUtil.setOutboundInterface(readIface.get(), mountPointDataBroker.get());
\r
110 NatInstance natInstance =
\r
111 buildNatInstance(natEntries, NatUtil.resolveDynamicNat(policyCtx, natEntries));
\r
112 GbpNetconfTransaction.netconfSyncedWrite(mountPointDataBroker.get(),
\r
113 VppIidFactory.getNatInstanceIid(id), natInstance, GbpNetconfTransaction.RETRY_COUNT);
\r
115 LOG.trace("UNsetting outbound NAT on interface {}.", iidPhysIface.getPathArguments());
\r
116 NatUtil.unsetOutboundInterface(readIface.get(), mountPointDataBroker.get());
\r
117 if (GbpNetconfTransaction.read(mountPointDataBroker.get(), LogicalDatastoreType.CONFIGURATION,
\r
118 VppIidFactory.getNatInstanceIid(id), GbpNetconfTransaction.RETRY_COUNT).isPresent()) {
\r
119 GbpNetconfTransaction.netconfSyncedDelete(mountPointDataBroker.get(),
\r
120 VppIidFactory.getNatInstanceIid(id), GbpNetconfTransaction.RETRY_COUNT);
\r
127 private NatInstance buildNatInstance(List<MappingEntryBuilder> natEntries,
\r
128 List<ExternalIpAddressPool> poolEntries) {
\r
129 AtomicInteger ai = new AtomicInteger();
\r
130 List<MappingEntry> mappingEntries = natEntries.stream().map(me -> {
\r
131 int value = ai.get();
\r
132 ai.incrementAndGet();
\r
133 return me.setIndex((long) value).build();
\r
134 }).collect(Collectors.toList());
\r
135 MappingTable mappingTable = new MappingTableBuilder().setMappingEntry(mappingEntries).build();
\r
136 return new NatInstanceBuilder()
\r
138 .setExternalIpAddressPool(poolEntries)
\r
139 .setMappingTable(mappingTable)
\r