a5821228beda73aa7e1e89f1410cad4f5ebaaeeb
[groupbasedpolicy.git] / renderers / vpp / src / main / java / org / opendaylight / groupbasedpolicy / renderer / vpp / nat / NatManager.java
1 /*\r
2  * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.\r
3  *\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
7  */\r
8 \r
9 package org.opendaylight.groupbasedpolicy.renderer.vpp.nat;\r
10 \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
20 \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
51 \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
56 \r
57 public class NatManager {\r
58 \r
59     private static final Logger LOG = LoggerFactory.getLogger(NatManager.class);\r
60 \r
61     private final Long id;\r
62     private final DataBroker dataBroker;\r
63     private final MountedDataBrokerProvider mountDataProvider;\r
64 \r
65     public NatManager(DataBroker dataBroker, MountedDataBrokerProvider mountDataProvider) {\r
66         this.id = 0L;\r
67         this.dataBroker = dataBroker;\r
68         this.mountDataProvider = mountDataProvider;\r
69     }\r
70 \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
75         rTx.close();\r
76         if (!readFromDs.isPresent() || readFromDs.get().getRendererNode() == null) {\r
77             return Optional.absent();\r
78         }\r
79         RendererNodes rendererNodes = readFromDs.get();\r
80         List<RendererNode> vppNodes = rendererNodes.getRendererNode()\r
81             .stream()\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
88                 .stream()\r
89                 .filter(phIface -> phIface.getAddress() != null)\r
90                 .filter(phIface -> phIface.getAddress()\r
91                     .stream()\r
92                     .anyMatch(ipAddr -> NetUtils.isInRange(extSubnetPrefix, String.valueOf(ipAddr.getValue()))))\r
93                 .findFirst();\r
94             if (optResolvedIface.isPresent()) {\r
95                 return Optional.of(VppIidFactory.getRendererNodeIid(rn)\r
96                     .builder()\r
97                     .augmentation(VppInterfaceAugmentation.class)\r
98                     .child(PhysicalInterface.class, new PhysicalInterfaceKey(optResolvedIface.get().getKey()))\r
99                     .build());\r
100             }\r
101         }\r
102         return Optional.absent();\r
103     }\r
104 \r
105     public Optional<MappingEntryBuilder> resolveSnatEntry(String internal, Ipv4Address external) {\r
106         IpAddress internalIp = null;\r
107         try {\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
113             }\r
114         } catch (UnknownHostException e) {\r
115             LOG.error("Cannot resolve host IP {}. {}", internal, e.getMessage());\r
116             return Optional.absent();\r
117         }\r
118         return Optional.of(new MappingEntryBuilder().setInternalSrcAddress(internalIp).setExternalSrcAddress(external));\r
119     }\r
120 \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
129             }\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
135 \r
136                         @Override\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
141                             }\r
142                             if (add) {\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
147                             } else {\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
151                                     .get()\r
152                                     .isPresent()) {\r
153                                     rwTx.delete(LogicalDatastoreType.CONFIGURATION, VppIidFactory.getNatInstanceIid(id));\r
154                                 }\r
155                             }\r
156                             return rwTx.submit();\r
157                         }\r
158                     }));\r
159         }\r
160         try {\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
165         }\r
166         return Futures.immediateFuture(null);\r
167     }\r
168 \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
178     }\r
179 }\r