VPP renderer: fixed imports after changes in vpp yang models
[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.HashMap;
12 import java.util.Map;
13 import java.util.Set;
14 import java.util.concurrent.ExecutionException;
15 import java.util.concurrent.TimeUnit;
16 import java.util.concurrent.TimeoutException;
17
18 import javax.annotation.Nonnull;
19 import javax.annotation.Nullable;
20
21 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
22 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
23 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
24 import org.opendaylight.groupbasedpolicy.renderer.vpp.api.BridgeDomainManager;
25 import org.opendaylight.groupbasedpolicy.renderer.vpp.iface.InterfaceManager;
26 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.KeyFactory;
27 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.common.endpoint.fields.NetworkContainment;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.common.endpoint.fields.network.containment.Containment;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.common.endpoint.fields.network.containment.containment.ForwardingContextContainment;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.common.endpoint.fields.network.containment.containment.NetworkDomainContainment;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.absolute.location.LocationType;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.absolute.location.location.type.ExternalLocationCase;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContextId;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.L2FloodDomain;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.rev160427.forwarding.fields.Parent;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.endpoints.AddressEndpointWithLocation;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.endpoints.RendererEndpointKey;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.forwarding.renderer.forwarding.by.tenant.RendererForwardingContext;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.forwarding.renderer.forwarding.by.tenant.RendererForwardingContextKey;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.forwarding.renderer.forwarding.by.tenant.RendererNetworkDomain;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.forwarding.renderer.forwarding.by.tenant.RendererNetworkDomainKey;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.Config;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.VlanNetwork;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.GbpBridgeDomain;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.GbpBridgeDomainKey;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VxlanVni;
50 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
51 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
54
55 import com.google.common.annotations.VisibleForTesting;
56 import com.google.common.base.Optional;
57 import com.google.common.base.Preconditions;
58 import com.google.common.base.Strings;
59 import com.google.common.collect.SetMultimap;
60 import com.google.common.collect.Table;
61
62 public final class ForwardingManager {
63
64     private static final Logger LOG = LoggerFactory.getLogger(ForwardingManager.class);
65     @VisibleForTesting
66     private byte WAIT_FOR_BD_CREATION = 60; // seconds
67     private long lastVxlanVni = 1L;
68     private final Map<String, VxlanVni> vxlanVniByBridgeDomain = new HashMap<>();
69     private final InterfaceManager ifaceManager;
70     private final BridgeDomainManager bdManager;
71     private final DataBroker dataBroker;
72     public ForwardingManager(@Nonnull InterfaceManager ifaceManager, @Nonnull BridgeDomainManager bdManager, @Nonnull DataBroker dataBroker) {
73         this.ifaceManager = Preconditions.checkNotNull(ifaceManager);
74         this.bdManager = Preconditions.checkNotNull(bdManager);
75         this.dataBroker = Preconditions.checkNotNull(dataBroker);
76     }
77
78     public Optional<GbpBridgeDomain> readGbpBridgeDomainConfig(String name) {
79         InstanceIdentifier<GbpBridgeDomain> bdIid = InstanceIdentifier.builder(Config.class)
80             .child(GbpBridgeDomain.class, new GbpBridgeDomainKey(name))
81             .build();
82         ReadOnlyTransaction rTx = dataBroker.newReadOnlyTransaction();
83         return DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION, bdIid, rTx);
84     }
85
86     public void createBridgeDomainOnNodes(SetMultimap<String, NodeId> vppNodesByBridgeDomain) {
87         for (String bd : vppNodesByBridgeDomain.keySet()) {
88             Optional<GbpBridgeDomain> bdConfig = readGbpBridgeDomainConfig(bd);
89             Set<NodeId> vppNodes = vppNodesByBridgeDomain.get(bd);
90             if (bdConfig.isPresent()) {
91                 if (bdConfig.get().getType().equals(VlanNetwork.class)) {
92                     createVlanBridgeDomains(bd, bdConfig.get().getVlan(), vppNodes);
93                 }
94             } else {
95                 VxlanVni vxlanVni = vxlanVniByBridgeDomain.get(bd);
96                 if (vxlanVni == null) {
97                     vxlanVni = new VxlanVni(lastVxlanVni++);
98                     vxlanVniByBridgeDomain.put(bd, vxlanVni);
99                 }
100                 createVxlanBridgeDomains(bd, vxlanVni, vppNodes);
101             }
102         }
103     }
104
105     private void createVxlanBridgeDomains(final String bd, final VxlanVni vni, final Set<NodeId> vppNodes) {
106         for (NodeId vppNode : vppNodes) {
107             try {
108                 LOG.debug("Creating VXLAN bridge-domain {} on node {} with VNI {}", bd, vppNode.getValue(),
109                         vni);
110                 bdManager.createVxlanBridgeDomainOnVppNode(bd, vni, vppNode).get(WAIT_FOR_BD_CREATION,
111                         TimeUnit.SECONDS);
112             } catch (InterruptedException | ExecutionException e) {
113                 LOG.warn("VXLAN Bridge domain {} was not created on node {}", bd, vppNode.getValue(), e);
114             } catch (TimeoutException e) {
115                 LOG.warn("Probably, VXLAN Bridge domain {} was not created on node {} because BridgeDomainManager "
116                         + "did not respond by {} seconds. Check VBD log for more details",
117                         bd, vppNode.getValue(), WAIT_FOR_BD_CREATION, e);
118             }
119         }
120     }
121
122     private void createVlanBridgeDomains(final String bd, final VlanId vlanId, final Set<NodeId> vppNodes) {
123         for (NodeId vppNode : vppNodes) {
124             try {
125                 LOG.debug("Creating VLAN bridge-domain {} on node {} with VLAN ID {}", bd, vppNode.getValue(),
126                         vlanId.getValue());
127                 bdManager.createVlanBridgeDomainOnVppNode(bd, vlanId, vppNode).get(WAIT_FOR_BD_CREATION,
128                         TimeUnit.SECONDS);
129             } catch (InterruptedException | ExecutionException e) {
130                 LOG.warn("VLAN Bridge domain {} was not created on node {}", bd, vppNode.getValue(), e);
131             } catch (TimeoutException e) {
132                 LOG.warn("Probably, VLAN Bridge domain {} was not created on node {} because BridgeDomainManager "
133                         + "did not respond by {} seconds. Check VBD log for more details",
134                         bd, vppNode.getValue(), WAIT_FOR_BD_CREATION, e);
135             }
136         }
137     }
138
139     public void removeBridgeDomainOnNodes(final SetMultimap<String, NodeId> vppNodesByBridgeDomain) {
140         for (String bd : vppNodesByBridgeDomain.keySet()) {
141             Set<NodeId> vppNodes = vppNodesByBridgeDomain.get(bd);
142             for (NodeId vppNode : vppNodes) {
143                 try {
144                     bdManager.removeBridgeDomainFromVppNode(bd, vppNode).get(WAIT_FOR_BD_CREATION,
145                             TimeUnit.SECONDS);
146                 } catch (InterruptedException | ExecutionException e) {
147                     LOG.warn("Bridge domain {} was not removed from node {}", bd, vppNode.getValue(), e);
148                 } catch (TimeoutException e) {
149                     LOG.warn("Probably, bridge domain {} was not removed from node {} because BridgeDomainManager "
150                             + "did not respond by {} seconds. Check VBD log for more details",
151                             bd, vppNode.getValue(), WAIT_FOR_BD_CREATION, e);
152                 }
153             }
154         }
155     }
156
157     public void createForwardingForEndpoint(RendererEndpointKey rEpKey, PolicyContext policyCtx) {
158         AddressEndpointWithLocation rEp = policyCtx.getAddrEpByKey().get(KeyFactory.addressEndpointKey(rEpKey));
159         ExternalLocationCase rEpLoc = resolveAndValidateLocation(rEp);
160         if (Strings.isNullOrEmpty(rEpLoc.getExternalNodeConnector())) {
161             // TODO add it to the status for renderer manager
162             LOG.info("Renderer endpoint does not have external-node-connector therefore it is ignored {}", rEp);
163             return;
164         }
165
166         if (Strings.isNullOrEmpty(rEpLoc.getExternalNode())) {
167             java.util.Optional<String> optL2FloodDomain = resolveL2FloodDomain(rEp, policyCtx);
168             if (!optL2FloodDomain.isPresent()) {
169                 // TODO add it to the status for renderer manager
170                 LOG.info("Renderer endpoint does not have l2FloodDomain as network containment {}", rEp);
171                 return;
172             }
173             String l2FloodDomain = optL2FloodDomain.get();
174             try {
175                 ifaceManager.addBridgeDomainToInterface(l2FloodDomain, rEp).get();
176                 LOG.debug("Interface added to bridge-domain {} for endpoint {}", l2FloodDomain, rEp);
177             } catch (InterruptedException | ExecutionException e) {
178                 // TODO add it to the status for renderer manager
179                 LOG.warn("Interface was not added to bridge-domain {} for endpoint {}", l2FloodDomain, rEp, e);
180             }
181         } else {
182             LOG.debug("Forwarding is not created - Location of renderer endpoint contains "
183                     + "external-node therefore VPP renderer assumes that interface for endpoint is "
184                     + "already assigned in bridge-domain representing external-node. {}", rEp);
185         }
186     }
187
188     public void removeForwardingForEndpoint(RendererEndpointKey rEpKey, PolicyContext policyCtx) {
189         AddressEndpointWithLocation rEp = policyCtx.getAddrEpByKey().get(KeyFactory.addressEndpointKey(rEpKey));
190         ExternalLocationCase rEpLoc = resolveAndValidateLocation(rEp);
191         if (Strings.isNullOrEmpty(rEpLoc.getExternalNodeConnector())) {
192             // nothing was created for endpoint therefore nothing is removed
193             return;
194         }
195
196         if (!Strings.isNullOrEmpty(rEpLoc.getExternalNode())) {
197             try {
198                 ifaceManager.deleteBridgeDomainFromInterface(rEp).get();
199                 LOG.debug("bridge-domain was deleted from interface for endpoint {}", rEp);
200             } catch (InterruptedException | ExecutionException e) {
201                 // TODO add it to the status for renderer manager
202                 LOG.warn("bridge-domain was not deleted from interface for endpoint {}", rEp, e);
203             }
204         } else {
205             LOG.debug("Forwarding is not removed - Location of renderer endpoint does not contain "
206                     + "external-node therefore VPP renderer assumes that interface for endpoint is not "
207                     + "assigned to bridge-domain representing external-node. {}", rEp);
208         }
209     }
210
211     public static ExternalLocationCase resolveAndValidateLocation(AddressEndpointWithLocation addrEpWithLoc) {
212         LocationType locationType = addrEpWithLoc.getAbsoluteLocation().getLocationType();
213         if (!(locationType instanceof ExternalLocationCase)) {
214             throw new IllegalStateException("Endpoint does not have external location " + addrEpWithLoc);
215         }
216         ExternalLocationCase result = (ExternalLocationCase) locationType;
217         if (result.getExternalNodeMountPoint() == null) {
218             throw new IllegalStateException("Endpoint does not have external-node-mount-point " + addrEpWithLoc);
219         }
220         return result;
221     }
222
223     public static java.util.Optional<String> resolveL2FloodDomain(@Nonnull AddressEndpointWithLocation ep,
224             @Nonnull PolicyContext policyCtx) {
225         NetworkContainment netCont = ep.getNetworkContainment();
226         if (netCont == null) {
227             return java.util.Optional.empty();
228         }
229         Containment containment = netCont.getContainment();
230         if (containment instanceof ForwardingContextContainment) {
231             ForwardingContextContainment fwCtxCont = (ForwardingContextContainment) containment;
232             if (L2FloodDomain.class.equals(fwCtxCont.getContextType())) {
233                 return fwCtxCont.getContextId() == null ? java.util.Optional.empty() : java.util.Optional
234                     .of(fwCtxCont.getContextId().getValue());
235             }
236         }
237         if (containment instanceof NetworkDomainContainment) {
238             NetworkDomainContainment netDomainCont = (NetworkDomainContainment) containment;
239             RendererNetworkDomain rendererNetworkDomain =
240                     policyCtx.getNetworkDomainTable().get(ep.getTenant(), new RendererNetworkDomainKey(
241                             netDomainCont.getNetworkDomainId(), netDomainCont.getNetworkDomainType()));
242             java.util.Optional<String> optL2Fd = getForwardingCtxForParent(ep.getTenant(),
243                     rendererNetworkDomain.getParent(), policyCtx.getForwardingCtxTable())
244                         .filter(fwdCtx -> L2FloodDomain.class.equals(fwdCtx.getContextType()))
245                         .map(RendererForwardingContext::getContextId)
246                         .map(ContextId::getValue);
247             if (!optL2Fd.isPresent()) {
248                 LOG.info("network-domain-containment in endpoint does not have L2-flood-domain as parent. "
249                         + "This case is not supported in VPP renderer. {}", ep);
250             }
251             return optL2Fd;
252         }
253         return java.util.Optional.empty();
254     }
255
256     private static @Nonnull java.util.Optional<RendererForwardingContext> getForwardingCtxForParent(
257             @Nullable TenantId tenant, @Nullable Parent parent,
258             Table<TenantId, RendererForwardingContextKey, RendererForwardingContext> forwardingCtxTable) {
259         if (tenant == null || parent == null) {
260             return java.util.Optional.empty();
261         }
262         if (parent.getContextId() != null && parent.getContextType() != null) {
263             return java.util.Optional.ofNullable(forwardingCtxTable.get(tenant,
264                     new RendererForwardingContextKey(parent.getContextId(), parent.getContextType())));
265         }
266         return java.util.Optional.empty();
267     }
268
269     @VisibleForTesting
270     void setTimer(byte time) {
271         WAIT_FOR_BD_CREATION = time;
272     }
273 }