Bug 8228 - metadata service fix made cleaner
[groupbasedpolicy.git] / renderers / vpp / src / main / java / org / opendaylight / groupbasedpolicy / renderer / vpp / policy / ForwardingManager.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.groupbasedpolicy.renderer.vpp.policy;
10
11 import java.util.ArrayList;
12 import java.util.HashMap;
13 import java.util.List;
14 import java.util.Map;
15 import java.util.Set;
16 import java.util.concurrent.ExecutionException;
17 import java.util.concurrent.TimeUnit;
18 import java.util.concurrent.TimeoutException;
19
20 import javax.annotation.Nonnull;
21 import javax.annotation.Nullable;
22
23 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
24 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
25 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
26 import org.opendaylight.groupbasedpolicy.renderer.vpp.api.BridgeDomainManager;
27 import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.RoutingCommand;
28 import org.opendaylight.groupbasedpolicy.renderer.vpp.config.ConfigUtil;
29 import org.opendaylight.groupbasedpolicy.renderer.vpp.iface.InterfaceManager;
30 import org.opendaylight.groupbasedpolicy.renderer.vpp.nat.NatManager;
31 import org.opendaylight.groupbasedpolicy.renderer.vpp.nat.NatUtil;
32 import org.opendaylight.groupbasedpolicy.renderer.vpp.policy.acl.AclManager;
33 import org.opendaylight.groupbasedpolicy.renderer.vpp.routing.RoutingManager;
34 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.General;
35 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.KeyFactory;
36 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.nat.instance.mapping.table.MappingEntryBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.common.endpoint.fields.NetworkContainment;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.common.endpoint.fields.network.containment.Containment;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.common.endpoint.fields.network.containment.containment.ForwardingContextContainment;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.common.endpoint.fields.network.containment.containment.NetworkDomainContainment;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.absolute.location.LocationType;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.absolute.location.location.type.ExternalLocationCase;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.ParentEndpointChoice;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.parent.endpoint.choice.ParentEndpointCase;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.parent.endpoint.choice.parent.endpoint._case.ParentEndpoint;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContextId;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.NetworkDomainId;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.IpPrefixType;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.L2FloodDomain;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.MacAddressType;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.SubnetAugmentRenderer;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.rev160427.NetworkDomain;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.rev160427.forwarding.fields.Parent;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.NatAddressRenderer;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.Configuration;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.Endpoints;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.endpoints.AddressEndpointWithLocation;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.endpoints.RendererEndpointKey;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.forwarding.RendererForwardingByTenant;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.forwarding.renderer.forwarding.by.tenant.RendererForwardingContext;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.forwarding.renderer.forwarding.by.tenant.RendererForwardingContextKey;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.forwarding.renderer.forwarding.by.tenant.RendererNetworkDomain;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.forwarding.renderer.forwarding.by.tenant.RendererNetworkDomainKey;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.Config;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.VlanNetwork;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425._interface.attributes.InterfaceTypeChoice;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425._interface.attributes._interface.type.choice.LoopbackCase;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.GbpBridgeDomain;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.GbpBridgeDomainKey;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpoint;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpointKey;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.renderers.renderer.renderer.nodes.renderer.node.PhysicalInterface;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev170315.VxlanVni;
78 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
79 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
80 import org.slf4j.Logger;
81 import org.slf4j.LoggerFactory;
82
83 import com.google.common.annotations.VisibleForTesting;
84 import com.google.common.base.Optional;
85 import com.google.common.base.Preconditions;
86 import com.google.common.base.Strings;
87 import com.google.common.collect.SetMultimap;
88 import com.google.common.collect.Table;
89
90 public final class ForwardingManager {
91
92     private static final Logger LOG = LoggerFactory.getLogger(ForwardingManager.class);
93     @VisibleForTesting
94     private byte WAIT_FOR_BD_PROCESSING = 60; // seconds
95     private long lastVxlanVni = 1L;
96     private final Map<String, VxlanVni> vxlanVniByBridgeDomain = new HashMap<>();
97     private final InterfaceManager ifaceManager;
98     private final AclManager aclManager;
99     private final BridgeDomainManager bdManager;
100     private final NatManager natManager;
101     private final RoutingManager routingManager;
102     private final DataBroker dataBroker;
103
104     public ForwardingManager(@Nonnull InterfaceManager ifaceManager, @Nonnull AclManager aclManager,
105         @Nonnull NatManager natManager, @Nonnull RoutingManager routingManager, @Nonnull BridgeDomainManager bdManager,
106         @Nonnull DataBroker dataBroker) {
107         this.ifaceManager = Preconditions.checkNotNull(ifaceManager);
108         this.bdManager = Preconditions.checkNotNull(bdManager);
109         this.natManager = Preconditions.checkNotNull(natManager);
110         this.routingManager = Preconditions.checkNotNull(routingManager);
111         this.dataBroker = Preconditions.checkNotNull(dataBroker);
112         this.aclManager = Preconditions.checkNotNull(aclManager);
113     }
114
115     public Optional<GbpBridgeDomain> readGbpBridgeDomainConfig(String name) {
116         InstanceIdentifier<GbpBridgeDomain> bdIid = InstanceIdentifier.builder(Config.class)
117             .child(GbpBridgeDomain.class, new GbpBridgeDomainKey(name))
118             .build();
119         ReadOnlyTransaction rTx = dataBroker.newReadOnlyTransaction();
120         Optional<GbpBridgeDomain> optBd = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION, bdIid, rTx);
121         rTx.close();
122         return optBd;
123     }
124
125     public void createBridgeDomainOnNodes(SetMultimap<String, NodeId> vppNodesByBridgeDomain) {
126         for (String bd : vppNodesByBridgeDomain.keySet()) {
127             Optional<GbpBridgeDomain> bdConfig = readGbpBridgeDomainConfig(bd);
128             Set<NodeId> vppNodes = vppNodesByBridgeDomain.get(bd);
129             if (bdConfig.isPresent()) {
130                 if (bdConfig.get().getType().equals(VlanNetwork.class)) {
131                     createVlanBridgeDomains(bd, bdConfig.get().getVlan(), vppNodes);
132                 }
133             } else {
134                 VxlanVni vxlanVni = vxlanVniByBridgeDomain.get(bd);
135                 if (vxlanVni == null) {
136                     vxlanVni = new VxlanVni(lastVxlanVni++);
137                     vxlanVniByBridgeDomain.put(bd, vxlanVni);
138                 }
139                 createVxlanBridgeDomains(bd, vxlanVni, vppNodes);
140             }
141         }
142     }
143
144     private void createVxlanBridgeDomains(final String bd, final VxlanVni vni, final Set<NodeId> vppNodes) {
145         for (NodeId vppNode : vppNodes) {
146             try {
147                 LOG.debug("Creating VXLAN bridge-domain {} on node {} with VNI {}", bd, vppNode.getValue(),
148                         vni);
149                 bdManager.createVxlanBridgeDomainOnVppNode(bd, vni, vppNode).get(WAIT_FOR_BD_PROCESSING,
150                         TimeUnit.SECONDS);
151             } catch (InterruptedException | ExecutionException e) {
152                 LOG.warn("VXLAN Bridge domain {} was not created on node {}", bd, vppNode.getValue(), e);
153             } catch (TimeoutException e) {
154                 LOG.warn("Probably, VXLAN Bridge domain {} was not created on node {} because BridgeDomainManager "
155                         + "did not respond by {} seconds. Check VBD log for more details",
156                         bd, vppNode.getValue(), WAIT_FOR_BD_PROCESSING, e);
157             }
158         }
159     }
160
161     private void createVlanBridgeDomains(final String bd, final VlanId vlanId, final Set<NodeId> vppNodes) {
162         for (NodeId vppNode : vppNodes) {
163             try {
164                 LOG.debug("Creating VLAN bridge-domain {} on node {} with VLAN ID {}", bd, vppNode.getValue(),
165                         vlanId.getValue());
166                 bdManager.createVlanBridgeDomainOnVppNode(bd, vlanId, vppNode).get(WAIT_FOR_BD_PROCESSING,
167                         TimeUnit.SECONDS);
168             } catch (InterruptedException | ExecutionException e) {
169                 LOG.warn("VLAN Bridge domain {} was not created on node {}", bd, vppNode.getValue(), e);
170             } catch (TimeoutException e) {
171                 LOG.warn("Probably, VLAN Bridge domain {} was not created on node {} because BridgeDomainManager "
172                         + "did not respond by {} seconds. Check VBD log for more details",
173                         bd, vppNode.getValue(), WAIT_FOR_BD_PROCESSING, e);
174             }
175         }
176     }
177
178     public void removeBridgeDomainOnNodes(final SetMultimap<String, NodeId> vppNodesByBridgeDomain) {
179         for (String bd : vppNodesByBridgeDomain.keySet()) {
180             Set<NodeId> vppNodes = vppNodesByBridgeDomain.get(bd);
181             for (NodeId vppNode : vppNodes) {
182                 try {
183                     bdManager.removeBridgeDomainFromVppNode(bd, vppNode).get(WAIT_FOR_BD_PROCESSING,
184                             TimeUnit.SECONDS);
185                 } catch (InterruptedException | ExecutionException e) {
186                     LOG.warn("Bridge domain {} was not removed from node {}", bd, vppNode.getValue(), e);
187                 } catch (TimeoutException e) {
188                     LOG.warn("Probably, bridge domain {} was not removed from node {} because BridgeDomainManager "
189                             + "did not respond by {} seconds. Check VBD log for more details",
190                             bd, vppNode.getValue(), WAIT_FOR_BD_PROCESSING, e);
191                 }
192             }
193         }
194     }
195
196     public void createForwardingForEndpoint(RendererEndpointKey rEpKey, PolicyContext policyCtx) {
197         AddressEndpointWithLocation rEp = policyCtx.getAddrEpByKey().get(KeyFactory.addressEndpointKey(rEpKey));
198         ExternalLocationCase rEpLoc = resolveAndValidateLocation(rEp);
199         if (Strings.isNullOrEmpty(rEpLoc.getExternalNodeConnector())) {
200             // TODO add it to the status for renderer manager
201             LOG.info("Renderer endpoint does not have external-node-connector therefore it is ignored {}", rEp);
202             return;
203         }
204
205         if (Strings.isNullOrEmpty(rEpLoc.getExternalNode())) {
206             java.util.Optional<String> optL2FloodDomain = resolveL2FloodDomain(rEp, policyCtx);
207             if (!optL2FloodDomain.isPresent()) {
208                 // TODO add it to the status for renderer manager
209                 LOG.info("Renderer endpoint does not have l2FloodDomain as network containment {}", rEp);
210                 return;
211             }
212             if (!ConfigUtil.getInstance().isL3FlatEnabled()) {
213                 String l2FloodDomain = optL2FloodDomain.get();
214                 try {
215                     ifaceManager.addBridgeDomainToInterface(l2FloodDomain, rEp, aclManager.resolveAclsOnInterface(
216                         rEpKey, policyCtx), isBviForEndpoint(rEp)).get();
217                     LOG.debug("Interface added to bridge-domain {} for endpoint {}", l2FloodDomain, rEp);
218
219                 } catch (InterruptedException | ExecutionException e) {
220                     // TODO add it to the status for renderer manager
221                     LOG.warn("Interface was not added to bridge-domain {} for endpoint {}", l2FloodDomain, rEp, e);
222                 }
223             }
224             aclManager.updateAclsForPeers(policyCtx, rEpKey);
225         } else {
226             LOG.debug("Forwarding is not created - Location of renderer endpoint contains "
227                     + "external-node therefore VPP renderer assumes that interface for endpoint is "
228                     + "already assigned in bridge-domain representing external-node. {}", rEp);
229         }
230     }
231
232     private boolean isBviForEndpoint(AddressEndpointWithLocation rEp) {
233         VppEndpointKey vppEndpointKey =
234             new VppEndpointKey(rEp.getAddress(), rEp.getAddressType(), rEp.getContextId(), rEp.getContextType());
235         ReadOnlyTransaction rTx = dataBroker.newReadOnlyTransaction();
236         Optional<VppEndpoint> vppEndpointOptional =
237             DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
238                 InstanceIdentifier.builder(Config.class).child(VppEndpoint.class, vppEndpointKey).build(), rTx);
239         if (vppEndpointOptional.isPresent()) {
240             InterfaceTypeChoice interfaceTypeChoice = vppEndpointOptional.get().getInterfaceTypeChoice();
241             if (interfaceTypeChoice instanceof LoopbackCase) {
242                 LOG.trace("Vpp renderer endpoint {} IS a BVI interface.", rEp.getKey());
243                 return ((LoopbackCase) interfaceTypeChoice).isBvi();
244             }
245         }
246         rTx.close();
247         LOG.trace("Vpp renderer endpoint {} IS NOT a BVI interface.", rEp.getKey());
248         return false;
249     }
250
251     public void removeForwardingForEndpoint(RendererEndpointKey rEpKey, PolicyContext policyCtx) {
252         AddressEndpointWithLocation rEp = policyCtx.getAddrEpByKey().get(KeyFactory.addressEndpointKey(rEpKey));
253         ExternalLocationCase rEpLoc = resolveAndValidateLocation(rEp);
254         if (Strings.isNullOrEmpty(rEpLoc.getExternalNodeConnector())) {
255             // nothing was created for endpoint therefore nothing is removed
256             return;
257         }
258         if (!Strings.isNullOrEmpty(rEpLoc.getExternalNode())) {
259             try {
260                 ifaceManager.deleteBridgeDomainFromInterface(rEp).get();
261                 LOG.debug("bridge-domain was deleted from interface for endpoint {}", rEp);
262             } catch (InterruptedException | ExecutionException e) {
263                 // TODO add it to the status for renderer manager
264                 LOG.warn("bridge-domain was not deleted from interface for endpoint {}", rEp, e);
265             }
266         } else {
267             LOG.debug("Forwarding is not removed - Location of renderer endpoint does not contain "
268                     + "external-node therefore VPP renderer assumes that interface for endpoint is not "
269                     + "assigned to bridge-domain representing external-node. {}", rEp);
270         }
271     }
272
273     public static ExternalLocationCase resolveAndValidateLocation(AddressEndpointWithLocation addrEpWithLoc) {
274         LocationType locationType = addrEpWithLoc.getAbsoluteLocation().getLocationType();
275         if (!(locationType instanceof ExternalLocationCase)) {
276             throw new IllegalStateException("Endpoint does not have external location " + addrEpWithLoc);
277         }
278         ExternalLocationCase result = (ExternalLocationCase) locationType;
279         if (result.getExternalNodeMountPoint() == null) {
280             throw new IllegalStateException("Endpoint does not have external-node-mount-point " + addrEpWithLoc);
281         }
282         return result;
283     }
284
285     public static java.util.Optional<String> resolveL2FloodDomain(@Nonnull AddressEndpointWithLocation ep,
286             @Nonnull PolicyContext policyCtx) {
287         NetworkContainment netCont = ep.getNetworkContainment();
288         if (netCont == null) {
289             return java.util.Optional.empty();
290         }
291         Containment containment = netCont.getContainment();
292         if (containment instanceof ForwardingContextContainment) {
293             ForwardingContextContainment fwCtxCont = (ForwardingContextContainment) containment;
294             if (L2FloodDomain.class.equals(fwCtxCont.getContextType())) {
295                 return fwCtxCont.getContextId() == null ? java.util.Optional.empty() : java.util.Optional
296                     .of(fwCtxCont.getContextId().getValue());
297             }
298         }
299         if (containment instanceof NetworkDomainContainment) {
300             final NetworkDomainContainment netDomainCont = (NetworkDomainContainment) containment;
301             final TenantId tenantId = ep.getTenant();
302             final NetworkDomainId domainId = netDomainCont.getNetworkDomainId();
303             final Class<? extends NetworkDomain> domainKey = netDomainCont.getNetworkDomainType();
304             final RendererNetworkDomainKey rendererNetworkDomainKey = new RendererNetworkDomainKey(domainId, domainKey);
305             final RendererNetworkDomain rendererNetworkDomain =
306                     policyCtx.getNetworkDomainTable().get(tenantId, rendererNetworkDomainKey);
307             if (rendererNetworkDomain == null) {
308                 LOG.debug("Network domain not found. Containment: {}", containment);
309                 return java.util.Optional.empty();
310             }
311             java.util.Optional<String> optL2Fd = getForwardingCtxForParent(ep.getTenant(),
312                     rendererNetworkDomain.getParent(), policyCtx.getForwardingCtxTable())
313                         .filter(fwdCtx -> L2FloodDomain.class.equals(fwdCtx.getContextType()))
314                         .map(RendererForwardingContext::getContextId)
315                         .map(ContextId::getValue);
316             if (!optL2Fd.isPresent()) {
317                 LOG.debug("network-domain-containment in endpoint does not have L2-flood-domain as parent. "
318                         + "This case is not supported in VPP renderer. {}", ep);
319             }
320             return optL2Fd;
321         }
322         return java.util.Optional.empty();
323     }
324
325     private static @Nonnull java.util.Optional<RendererForwardingContext> getForwardingCtxForParent(
326             @Nullable TenantId tenant, @Nullable Parent parent,
327             Table<TenantId, RendererForwardingContextKey, RendererForwardingContext> forwardingCtxTable) {
328         if (tenant == null || parent == null) {
329             return java.util.Optional.empty();
330         }
331         if (parent.getContextId() != null && parent.getContextType() != null) {
332             return java.util.Optional.ofNullable(forwardingCtxTable.get(tenant,
333                     new RendererForwardingContextKey(parent.getContextId(), parent.getContextType())));
334         }
335         return java.util.Optional.empty();
336     }
337
338     void syncNatEntries(PolicyContext policyCtx) {
339         Configuration cfg = policyCtx.getPolicy().getConfiguration();
340         if(cfg != null) {
341             final List<MappingEntryBuilder> sNatEntries = resolveStaticNatTableEntries(cfg.getEndpoints());
342             LOG.trace("Syncing static NAT entries {}", sNatEntries);
343             if (cfg.getRendererForwarding() != null) {
344                 for (RendererForwardingByTenant fwd : cfg.getRendererForwarding().getRendererForwardingByTenant()) {
345                     List<InstanceIdentifier<PhysicalInterface>> physIfacesIid =
346                         resolvePhysicalInterfacesForNat(fwd.getRendererNetworkDomain());
347                     natManager.submitNatChanges(physIfacesIid, sNatEntries, policyCtx, true);
348                 }
349             }
350         }
351     }
352
353     public void deleteNatEntries(PolicyContext policyCtx) {
354         Configuration cfg = policyCtx.getPolicy().getConfiguration();
355         if(cfg != null) {
356             List<MappingEntryBuilder> natEntries = resolveStaticNatTableEntries(cfg.getEndpoints());
357             if (natEntries.isEmpty()) {
358                 LOG.trace("NAT entries are empty,nothing to delete, skipping processing.");
359                 return;
360             }
361             LOG.trace("Deleting NAT entries {}", natEntries);
362             if (cfg.getRendererForwarding() != null) {
363                 for (RendererForwardingByTenant fwd : cfg.getRendererForwarding().getRendererForwardingByTenant()) {
364                     List<InstanceIdentifier<PhysicalInterface>> physIfacesIid =
365                         resolvePhysicalInterfacesForNat(fwd.getRendererNetworkDomain());
366                     natManager.submitNatChanges(physIfacesIid, natEntries, policyCtx, false);
367                 }
368             }
369         }
370     }
371
372     public List<InstanceIdentifier<PhysicalInterface>> resolvePhysicalInterfacesForNat(
373             List<RendererNetworkDomain> rendNetDomains) {
374         List<InstanceIdentifier<PhysicalInterface>> physIfaces = new ArrayList<>();
375         for (RendererNetworkDomain rendDomain : rendNetDomains) {
376             Optional<IpPrefix> resolvedIpPrefix = resolveIpPrefix(rendDomain);
377             if (resolvedIpPrefix.isPresent()) {
378                 Optional<InstanceIdentifier<PhysicalInterface>> resPhIface =
379                     NatUtil.resolvePhysicalInterface(resolvedIpPrefix.get(), dataBroker.newReadOnlyTransaction());
380                 if (resPhIface.isPresent()) {
381                     physIfaces.add(resPhIface.get());
382                 }
383             }
384         }
385         return physIfaces;
386     }
387
388     private Optional<IpPrefix> resolveIpPrefix(RendererNetworkDomain rendDomain) {
389         SubnetAugmentRenderer subnetAug = rendDomain.getAugmentation(SubnetAugmentRenderer.class);
390         if (subnetAug.getSubnet() != null) {
391             return Optional.of(subnetAug.getSubnet().getIpPrefix());
392         }
393         return Optional.absent();
394     }
395
396     private List<MappingEntryBuilder> resolveStaticNatTableEntries(Endpoints endpoints) {
397         List<MappingEntryBuilder> sNatEntries = new ArrayList<>();
398         for (AddressEndpointWithLocation addrEp : endpoints.getAddressEndpointWithLocation()) {
399             if (addrEp.getAugmentation(NatAddressRenderer.class) == null) {
400                 continue;
401             }
402             String endpointIP = resolveEpIpAddressForSnat(addrEp);
403
404             if (endpointIP == null) {
405                 LOG.warn("Endpoints {} IP cannot be null, skipping processing of SNAT", addrEp);
406                 continue;
407             }
408
409             NatAddressRenderer natAddr = addrEp.getAugmentation(NatAddressRenderer.class);
410             if (natAddr.getNatAddress() == null && natAddr.getNatAddress().getIpv4Address() == null) {
411                 LOG.warn("Only Ipv4 SNAT is currently supported. Cannot apply SNAT for [{},{}]", endpointIP,
412                         natAddr.getNatAddress());
413                 continue;
414             }
415             Optional<MappingEntryBuilder> entry = natManager.resolveSnatEntry(endpointIP, natAddr.getNatAddress()
416                 .getIpv4Address());
417             if (entry.isPresent()) {
418                 sNatEntries.add(entry.get());
419             }
420         }
421         return sNatEntries;
422     }
423
424     private String resolveEpIpAddressForSnat(AddressEndpointWithLocation addrEp) {
425         if (addrEp.getAddressType().equals(MacAddressType.class)) {
426             ParentEndpointChoice parentEndpointChoice = addrEp.getParentEndpointChoice();
427             if (parentEndpointChoice instanceof ParentEndpointCase
428                 && !((ParentEndpointCase) parentEndpointChoice).getParentEndpoint().isEmpty()) {
429                 ParentEndpoint parentEndpoint = ((ParentEndpointCase) parentEndpointChoice).getParentEndpoint().get(0);
430                 if (parentEndpoint.getAddressType().equals(IpPrefixType.class)) {
431                     String[] ipWithPrefix = parentEndpoint.getAddress().split("/");
432                     return ipWithPrefix[0];
433                 } else {
434                     LOG.warn("Endpoint {} Does not have a Parent Ep with IP for SNAT. skipping processing of SNAT",
435                         addrEp);
436                     return null;
437                 }
438
439             } else {
440                 LOG.warn("Endpoint {} Does not contain IP address for SNAT. skipping processing of SNAT", addrEp);
441                 return null;
442             }
443         } else if (addrEp.getAddressType().equals(IpPrefixType.class)) {
444             return addrEp.getAddress();
445         }
446         return null;
447     }
448
449     @VisibleForTesting
450     void setTimer(byte time) {
451         WAIT_FOR_BD_PROCESSING = time;
452     }
453
454     public void syncRouting(PolicyContext policyCtx) {
455         Configuration cfg = policyCtx.getPolicy().getConfiguration();
456         if (cfg != null && cfg.getRendererForwarding() != null) {
457             for (RendererForwardingByTenant fwd : cfg.getRendererForwarding().getRendererForwardingByTenant()) {
458                 if (fwd == null) {
459                     continue;
460                 }
461
462                 List<InstanceIdentifier<PhysicalInterface>>
463                     physIfacesIid = resolvePhysicalInterfacesForNat(fwd.getRendererNetworkDomain());
464                 Map<InstanceIdentifier<?>, RoutingCommand> routingCommandMap =
465                     routingManager.createRouting(fwd, physIfacesIid, General.Operations.PUT);
466
467                 routingCommandMap.forEach((node, command) -> {
468                     if (command != null && routingManager.submitRouting(command, node)) {
469                         LOG.debug("Routing was successfully applied: {}.", command);
470                     }
471                 });
472             }
473         }
474     }
475
476     public void deleteRouting(PolicyContext policyCtx) {
477         Configuration cfg = policyCtx.getPolicy().getConfiguration();
478         if (cfg != null && cfg.getRendererForwarding() != null) {
479             for (RendererForwardingByTenant fwd : cfg.getRendererForwarding().getRendererForwardingByTenant()) {
480                 if (fwd == null) {
481                     continue;
482                 }
483
484                 List<InstanceIdentifier<PhysicalInterface>>
485                     physIfacesIid = resolvePhysicalInterfacesForNat(fwd.getRendererNetworkDomain());
486                 Map<InstanceIdentifier<?>, RoutingCommand> routingCommandMap =
487                     routingManager.createRouting(fwd, physIfacesIid, General.Operations.DELETE);
488                 routingCommandMap.forEach((node, command) -> {
489                     if (command != null && routingManager.submitRouting(command, node)) {
490                         LOG.debug("Routing was successfully removed: {}.", command);
491                     }
492                 });
493             }
494         }
495     }
496 }