Policy exclusions & parallel netconf transactions
[groupbasedpolicy.git] / renderers / vpp / src / main / java / org / opendaylight / groupbasedpolicy / renderer / vpp / nat / NatUtil.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.util.ArrayList;\r
12 import java.util.HashMap;\r
13 import java.util.List;\r
14 import java.util.Map;\r
15 import java.util.Map.Entry;\r
16 import java.util.stream.Collectors;\r
17 \r
18 import javax.annotation.Nonnull;\r
19 import javax.annotation.Nullable;\r
20 \r
21 import org.apache.commons.net.util.SubnetUtils;\r
22 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;\r
23 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;\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.GbpNetconfTransaction;\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.vbd.impl.transaction.VbdNetconfTransaction;\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.Ipv4Prefix;\r
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;\r
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;\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.MappingEntryBuilder;\r
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.parameters.ExternalIpAddressPool;\r
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.parameters.ExternalIpAddressPoolBuilder;\r
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev170511.SubnetAugmentRenderer;\r
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev170511.has.subnet.Subnet;\r
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev170511.has.subnet.subnet.AllocationPool;\r
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.RendererNodes;\r
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.nodes.RendererNode;\r
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.forwarding.RendererForwardingByTenant;\r
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.forwarding.renderer.forwarding.by.tenant.RendererNetworkDomain;\r
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.VppInterfaceAugmentation;\r
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.renderers.renderer.renderer.nodes.renderer.node.PhysicalInterface;\r
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.renderers.renderer.renderer.nodes.renderer.node.PhysicalInterfaceKey;\r
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214.NatInterfaceAugmentation;\r
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214._interface.nat.attributes.Nat;\r
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214._interface.nat.attributes.NatBuilder;\r
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214._interface.nat.attributes.nat.InboundBuilder;\r
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214._interface.nat.attributes.nat.OutboundBuilder;\r
54 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;\r
55 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;\r
56 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;\r
57 import org.slf4j.Logger;\r
58 import org.slf4j.LoggerFactory;\r
59 \r
60 import com.google.common.annotations.VisibleForTesting;\r
61 import com.google.common.base.Optional;\r
62 \r
63 public class NatUtil {\r
64     private static final Logger LOG = LoggerFactory.getLogger(NatUtil.class);\r
65 \r
66     public void setInboundInterface(Interface iface, WriteTransaction wTx) {\r
67         InstanceIdentifier<Nat> natIid = buildNatIid(VppIidFactory.getInterfaceIID(iface.getKey()));\r
68         Nat nat = new NatBuilder().setInbound(new InboundBuilder().build()).build();\r
69         wTx.put(LogicalDatastoreType.CONFIGURATION, natIid, nat);\r
70     }\r
71 \r
72     public static void setOutboundInterface(Interface iface, InstanceIdentifier<Node> vppIid) {\r
73         InstanceIdentifier<Nat> natIid = buildNatIid(VppIidFactory.getInterfaceIID(iface.getKey()));\r
74         Nat nat = new NatBuilder().setOutbound(new OutboundBuilder().build()).build();\r
75         GbpNetconfTransaction.netconfSyncedWrite(vppIid, natIid, nat, GbpNetconfTransaction.RETRY_COUNT);\r
76 \r
77     }\r
78 \r
79     public static void unsetOutboundInterface(Interface iface, InstanceIdentifier<Node> vppIid) {\r
80         InstanceIdentifier<Nat> natIid = buildNatIid(VppIidFactory.getInterfaceIID(iface.getKey()));\r
81         GbpNetconfTransaction.netconfSyncedDelete(vppIid, natIid, GbpNetconfTransaction.RETRY_COUNT);\r
82     }\r
83 \r
84     public static InstanceIdentifier<Nat> buildNatIid(InstanceIdentifier<Interface> ifaceIid) {\r
85         return ifaceIid.builder().augmentation(NatInterfaceAugmentation.class).child(Nat.class).build();\r
86     }\r
87 \r
88     public static Optional<InstanceIdentifier<PhysicalInterface>> resolvePhysicalInterface(IpPrefix extSubnetPrefix,\r
89         ReadOnlyTransaction rTx) {\r
90         Optional<RendererNodes> readFromDs =\r
91             DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL, VppIidFactory.getRendererNodesIid(), rTx);\r
92         rTx.close();\r
93         if (!readFromDs.isPresent() || readFromDs.get().getRendererNode() == null) {\r
94             return Optional.absent();\r
95         }\r
96         RendererNodes rendererNodes = readFromDs.get();\r
97         List<RendererNode>\r
98             vppNodes =\r
99             rendererNodes.getRendererNode()\r
100                 .stream()\r
101                 .filter(rn -> rn.getAugmentation(VppInterfaceAugmentation.class) != null)\r
102                 .filter(rn -> rn.getAugmentation(VppInterfaceAugmentation.class).getPhysicalInterface() != null)\r
103                 .collect(Collectors.toList());\r
104         for (RendererNode rn : vppNodes) {\r
105             java.util.Optional<PhysicalInterface>\r
106                 optResolvedIface =\r
107                 rn.getAugmentation(VppInterfaceAugmentation.class)\r
108                     .getPhysicalInterface()\r
109                     .stream()\r
110                     .filter(phIface -> phIface.getAddress() != null)\r
111                     .filter(phIface -> phIface.getAddress()\r
112                         .stream()\r
113                         .anyMatch(ipAddr -> NetUtils.isInRange(extSubnetPrefix, String.valueOf(ipAddr.getValue()))))\r
114                     .findFirst();\r
115             if (optResolvedIface.isPresent()) {\r
116                 return Optional.of(VppIidFactory.getRendererNodeIid(rn)\r
117                     .builder()\r
118                     .augmentation(VppInterfaceAugmentation.class)\r
119                     .child(PhysicalInterface.class, new PhysicalInterfaceKey(optResolvedIface.get().getKey()))\r
120                     .build());\r
121             }\r
122         }\r
123         return Optional.absent();\r
124     }\r
125 \r
126     static List<ExternalIpAddressPool> resolveDynamicNat(@Nonnull PolicyContext policyCtx,\r
127         @Nullable List<MappingEntryBuilder> sNatEntries) {\r
128         List<RendererForwardingByTenant> forwardingByTenantList =\r
129                 policyCtx.getPolicy().getConfiguration().getRendererForwarding().getRendererForwardingByTenant();\r
130         Map<Long, Ipv4Prefix> extCache = new HashMap<>();\r
131         // loop through forwarding by tenant\r
132         for (RendererForwardingByTenant rft : forwardingByTenantList) {\r
133             // loop through renderer network domain\r
134             for (RendererNetworkDomain domain : rft.getRendererNetworkDomain()) {\r
135                 final SubnetAugmentRenderer subnetAugmentation = domain.getAugmentation(SubnetAugmentRenderer.class);\r
136                 final Subnet subnet = subnetAugmentation.getSubnet();\r
137                 if (subnet != null && !subnet.isIsTenant() && subnet.getAllocationPool() != null) {\r
138                     // loop through allocation pool\r
139                     for (AllocationPool pool : subnet.getAllocationPool()) {\r
140                         final IpPrefix subnetIpPrefix = subnet.getIpPrefix();\r
141                         if (subnetIpPrefix.getIpv4Prefix() != null) {\r
142                             final String firstEntry = pool.getFirst();\r
143                             final String lastEntry = pool.getLast();\r
144                             extCache.putAll(resolveDynamicNatPrefix(subnetIpPrefix.getIpv4Prefix(), firstEntry, lastEntry,\r
145                                     sNatEntries));\r
146                         }\r
147                     }\r
148                 }\r
149             }\r
150         }\r
151         final List<ExternalIpAddressPool> extIps = new ArrayList<>();\r
152         for (Entry<Long, Ipv4Prefix> entry : extCache.entrySet()) {\r
153             extIps.add(new ExternalIpAddressPoolBuilder().setPoolId(entry.getKey())\r
154                 .setExternalIpPool(entry.getValue())\r
155                 .build());\r
156         }\r
157         return extIps;\r
158     }\r
159 \r
160     @VisibleForTesting\r
161     private static Map<Long, Ipv4Prefix> resolveDynamicNatPrefix(@Nonnull final Ipv4Prefix prefix,\r
162                                                                  @Nonnull final String first,\r
163                                                                  @Nullable final String last,\r
164                                                                  @Nullable final List<MappingEntryBuilder> natEntries) {\r
165         LOG.trace("Resolving Ipv4Prefix. prefix: {}, first: {}, last: {}", prefix.getValue(), first, last);\r
166         final SubnetUtils subnet = new SubnetUtils(prefix.getValue());\r
167         final Map<Long, Ipv4Prefix> extCache = new HashMap<>();\r
168         int min = subnet.getInfo().asInteger(first);\r
169         // loop through all addresses\r
170         for (String address : subnet.getInfo().getAllAddresses()) {\r
171             int asInt = subnet.getInfo().asInteger(address);\r
172             if (asInt < min) {\r
173                 continue;\r
174             }\r
175             extCache.put(Integer.toUnsignedLong(asInt), new Ipv4Prefix(address + "/32"));\r
176             if (last == null || subnet.getInfo().asInteger(address) >= subnet.getInfo().asInteger(last)) {\r
177                 break;\r
178             }\r
179         }\r
180         if (natEntries != null) {\r
181             // remove every static NAT entry from extCache\r
182             for (MappingEntryBuilder natEntry : natEntries) {\r
183                 final Ipv4Address externalSrcAddress = natEntry.getExternalSrcAddress();\r
184                 final long id = Integer.toUnsignedLong(subnet.getInfo().asInteger(externalSrcAddress.getValue()));\r
185                 if (extCache.get(id) != null) {\r
186                     extCache.remove(id);\r
187                 }\r
188             }\r
189         }\r
190         return extCache;\r
191     }\r
192 \r
193     public static void resolveOutboundNatInterface(InstanceIdentifier<Node> mountPointIid,\r
194         NodeId nodeId, Map<NodeId, PhysicalInterfaceKey> extInterfaces) {\r
195         if (extInterfaces.containsKey(nodeId)){\r
196             PhysicalInterfaceKey physicalInterfaceKey = extInterfaces.get(nodeId);\r
197             Optional<Interfaces> readIfaces = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,\r
198                 InstanceIdentifier.create(Interfaces.class),\r
199                 VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(mountPointIid).getKey().newReadOnlyTransaction());\r
200             if(readIfaces.isPresent() ) {\r
201                 for (Interface nodeInterface : readIfaces.get().getInterface()) {\r
202                     if (nodeInterface.getName().equals(physicalInterfaceKey.getInterfaceName())) {\r
203                         LOG.trace("Setting outbound NAT on interface {} on node: {}", nodeInterface.getName(), mountPointIid);\r
204                         NatUtil.setOutboundInterface(nodeInterface, mountPointIid);\r
205                     }\r
206                 }\r
207 \r
208             }\r
209 \r
210         }\r
211 \r
212     }\r
213 }\r