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