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