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.ArrayList;
\r
16 import java.util.List;
\r
17 import java.util.concurrent.ExecutionException;
\r
18 import java.util.concurrent.atomic.AtomicInteger;
\r
19 import java.util.stream.Collectors;
\r
21 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
\r
22 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
\r
23 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
\r
24 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
\r
25 import org.opendaylight.groupbasedpolicy.renderer.vpp.policy.PolicyContext;
\r
26 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.MountedDataBrokerProvider;
\r
27 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.VppIidFactory;
\r
28 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
\r
29 import org.opendaylight.groupbasedpolicy.util.NetUtils;
\r
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
\r
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
\r
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
\r
33 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
\r
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
\r
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
\r
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.NatInstance;
\r
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.NatInstanceBuilder;
\r
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.nat.instance.MappingTable;
\r
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.nat.instance.MappingTableBuilder;
\r
40 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
41 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
42 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.parameters.ExternalIpAddressPool;
\r
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.RendererNodes;
\r
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.nodes.RendererNode;
\r
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.VppInterfaceAugmentation;
\r
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.renderers.renderer.renderer.nodes.renderer.node.PhysicalInterface;
\r
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.renderers.renderer.renderer.nodes.renderer.node.PhysicalInterfaceKey;
\r
48 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
\r
49 import org.slf4j.Logger;
\r
50 import org.slf4j.LoggerFactory;
\r
52 import com.google.common.base.Optional;
\r
53 import com.google.common.util.concurrent.AsyncFunction;
\r
54 import com.google.common.util.concurrent.Futures;
\r
55 import com.google.common.util.concurrent.ListenableFuture;
\r
57 public class NatManager {
\r
59 private static final Logger LOG = LoggerFactory.getLogger(NatManager.class);
\r
61 private final Long id;
\r
62 private final DataBroker dataBroker;
\r
63 private final MountedDataBrokerProvider mountDataProvider;
\r
65 public NatManager(DataBroker dataBroker, MountedDataBrokerProvider mountDataProvider) {
\r
67 this.dataBroker = dataBroker;
\r
68 this.mountDataProvider = mountDataProvider;
\r
71 public Optional<InstanceIdentifier<PhysicalInterface>> resolvePhysicalInterface(IpPrefix extSubnetPrefix) {
\r
72 ReadOnlyTransaction rTx = dataBroker.newReadOnlyTransaction();
\r
73 Optional<RendererNodes> readFromDs = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
\r
74 VppIidFactory.getRendererNodesIid(), rTx);
\r
76 if (!readFromDs.isPresent() || readFromDs.get().getRendererNode() == null) {
\r
77 return Optional.absent();
\r
79 RendererNodes rendererNodes = readFromDs.get();
\r
80 List<RendererNode> vppNodes = rendererNodes.getRendererNode()
\r
82 .filter(rn -> rn.getAugmentation(VppInterfaceAugmentation.class) != null)
\r
83 .filter(rn -> rn.getAugmentation(VppInterfaceAugmentation.class).getPhysicalInterface() != null)
\r
84 .collect(Collectors.toList());
\r
85 for (RendererNode rn : vppNodes) {
\r
86 java.util.Optional<PhysicalInterface> optResolvedIface = rn.getAugmentation(VppInterfaceAugmentation.class)
\r
87 .getPhysicalInterface()
\r
89 .filter(phIface -> phIface.getAddress() != null)
\r
90 .filter(phIface -> phIface.getAddress()
\r
92 .anyMatch(ipAddr -> NetUtils.isInRange(extSubnetPrefix, String.valueOf(ipAddr.getValue()))))
\r
94 if (optResolvedIface.isPresent()) {
\r
95 return Optional.of(VppIidFactory.getRendererNodeIid(rn)
\r
97 .augmentation(VppInterfaceAugmentation.class)
\r
98 .child(PhysicalInterface.class, new PhysicalInterfaceKey(optResolvedIface.get().getKey()))
\r
102 return Optional.absent();
\r
105 public Optional<MappingEntryBuilder> resolveSnatEntry(String internal, Ipv4Address external) {
\r
106 IpAddress internalIp = null;
\r
108 InetAddress inetAddr = InetAddress.getByName(internal);
\r
109 if (inetAddr instanceof Inet4Address) {
\r
110 internalIp = new IpAddress(new Ipv4Address(internal));
\r
111 } else if (inetAddr instanceof Inet6Address) {
\r
112 internalIp = new IpAddress(new Ipv6Address(internal));
\r
114 } catch (UnknownHostException e) {
\r
115 LOG.error("Cannot resolve host IP {}. {}", internal, e.getMessage());
\r
116 return Optional.absent();
\r
118 return Optional.of(new MappingEntryBuilder().setInternalSrcAddress(internalIp).setExternalSrcAddress(external));
\r
121 public ListenableFuture<Void> submitNatChanges(List<InstanceIdentifier<PhysicalInterface>> physIfacesIid,
\r
122 List<MappingEntryBuilder> natEntries, PolicyContext policyCtx, boolean add) {
\r
123 List<ListenableFuture<Void>> submitedFutures = new ArrayList<>();
\r
124 for (InstanceIdentifier<PhysicalInterface> iidPhysIface : physIfacesIid) {
\r
125 InstanceIdentifier<?> nodeIid = iidPhysIface.firstKeyOf(RendererNode.class).getNodePath();
\r
126 Optional<DataBroker> mountPointDataBroker = mountDataProvider.getDataBrokerForMountPoint(nodeIid);
\r
127 if (!mountPointDataBroker.isPresent()) {
\r
128 throw new IllegalStateException("Cannot find data broker for mount point " + nodeIid);
\r
130 String phInterfaceName = iidPhysIface.firstKeyOf(PhysicalInterface.class).getInterfaceName();
\r
131 ReadWriteTransaction rwTx = mountPointDataBroker.get().newReadWriteTransaction();
\r
132 InstanceIdentifier<Interface> interfaceIID = VppIidFactory.getInterfaceIID(new InterfaceKey(phInterfaceName));
\r
133 submitedFutures.add(Futures.transform(rwTx.read(LogicalDatastoreType.CONFIGURATION, interfaceIID),
\r
134 new AsyncFunction<Optional<Interface>, Void>() {
\r
137 public ListenableFuture<Void> apply(Optional<Interface> readIface) throws Exception {
\r
138 if (!readIface.isPresent()) {
\r
139 LOG.error("Interface {} not found on mount point {}", phInterfaceName, nodeIid);
\r
140 return Futures.immediateFuture(null);
\r
143 LOG.trace("Setting outbound NAT on interface {}.", iidPhysIface.getPathArguments());
\r
144 NatUtil.setOutboundInterface(readIface.get(), rwTx);
\r
145 rwTx.put(LogicalDatastoreType.CONFIGURATION, VppIidFactory.getNatInstanceIid(id),
\r
146 buildNatInstance(natEntries, NatUtil.resolveDynamicNat(policyCtx)));
\r
148 LOG.trace("UNsetting outbound NAT on interface {}.", iidPhysIface.getPathArguments());
\r
149 NatUtil.unsetOutboundInterface(readIface.get(), rwTx);
\r
150 if (rwTx.read(LogicalDatastoreType.CONFIGURATION, VppIidFactory.getNatInstanceIid(id))
\r
153 rwTx.delete(LogicalDatastoreType.CONFIGURATION, VppIidFactory.getNatInstanceIid(id));
\r
156 return rwTx.submit();
\r
161 Futures.allAsList(submitedFutures).get();
\r
162 } catch (InterruptedException | ExecutionException e) {
\r
163 LOG.error("Failed to sync NAT. {}", e.getMessage());
\r
164 e.printStackTrace();
\r
166 return Futures.immediateFuture(null);
\r
169 private NatInstance buildNatInstance(List<MappingEntryBuilder> natEntries, List<ExternalIpAddressPool> poolEntries) {
\r
170 AtomicInteger ai = new AtomicInteger();
\r
171 List<MappingEntry> mappingEntries = natEntries.stream().map(me -> {
\r
172 int value = ai.get();
\r
173 ai.incrementAndGet();
\r
174 return me.setIndex((long) value).build();
\r
175 }).collect(Collectors.toList());
\r
176 MappingTable mappingTable = new MappingTableBuilder().setMappingEntry(mappingEntries).build();
\r
177 return new NatInstanceBuilder().setId(id).setExternalIpAddressPool(poolEntries).setMappingTable(mappingTable).build();
\r