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.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
18 import javax.annotation.Nonnull;
\r
19 import javax.annotation.Nullable;
\r
21 import org.apache.commons.net.util.SubnetUtils;
\r
22 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
\r
23 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
\r
24 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
\r
25 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
\r
26 import org.opendaylight.groupbasedpolicy.renderer.vpp.policy.PolicyContext;
\r
27 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.GbpNetconfTransaction;
\r
28 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.VppIidFactory;
\r
29 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
\r
30 import org.opendaylight.groupbasedpolicy.util.NetUtils;
\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
60 import com.google.common.annotations.VisibleForTesting;
\r
61 import com.google.common.base.Optional;
\r
63 public class NatUtil {
\r
64 private static final Logger LOG = LoggerFactory.getLogger(NatUtil.class);
\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
72 public static void setOutboundInterface(Interface iface, DataBroker dataBroker) {
\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(dataBroker, natIid, nat, GbpNetconfTransaction.RETRY_COUNT);
\r
79 public static void unsetOutboundInterface(Interface iface, DataBroker dataBroker) {
\r
80 InstanceIdentifier<Nat> natIid = buildNatIid(VppIidFactory.getInterfaceIID(iface.getKey()));
\r
81 GbpNetconfTransaction.netconfSyncedDelete(dataBroker, natIid, GbpNetconfTransaction.RETRY_COUNT);
\r
84 public static InstanceIdentifier<Nat> buildNatIid(InstanceIdentifier<Interface> ifaceIid) {
\r
85 return ifaceIid.builder().augmentation(NatInterfaceAugmentation.class).child(Nat.class).build();
\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
93 if (!readFromDs.isPresent() || readFromDs.get().getRendererNode() == null) {
\r
94 return Optional.absent();
\r
96 RendererNodes rendererNodes = readFromDs.get();
\r
99 rendererNodes.getRendererNode()
\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
107 rn.getAugmentation(VppInterfaceAugmentation.class)
\r
108 .getPhysicalInterface()
\r
110 .filter(phIface -> phIface.getAddress() != null)
\r
111 .filter(phIface -> phIface.getAddress()
\r
113 .anyMatch(ipAddr -> NetUtils.isInRange(extSubnetPrefix, String.valueOf(ipAddr.getValue()))))
\r
115 if (optResolvedIface.isPresent()) {
\r
116 return Optional.of(VppIidFactory.getRendererNodeIid(rn)
\r
118 .augmentation(VppInterfaceAugmentation.class)
\r
119 .child(PhysicalInterface.class, new PhysicalInterfaceKey(optResolvedIface.get().getKey()))
\r
123 return Optional.absent();
\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
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
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
175 extCache.put(Integer.toUnsignedLong(asInt), new Ipv4Prefix(address + "/32"));
\r
176 if (last == null || subnet.getInfo().asInteger(address) >= subnet.getInfo().asInteger(last)) {
\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
193 public static void resolveOutboundNatInterface(DataBroker mountpoint, 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), mountpoint.newReadOnlyTransaction());
\r
199 if(readIfaces.isPresent() ) {
\r
200 for (Interface nodeInterface : readIfaces.get().getInterface()) {
\r
201 if (nodeInterface.getName().equals(physicalInterfaceKey.getInterfaceName())) {
\r
202 LOG.trace("Setting outbound NAT on interface {} on node: {}", nodeInterface.getName(), mountPointIid);
\r
203 NatUtil.setOutboundInterface(nodeInterface, mountpoint);
\r