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