2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
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
9 package org.opendaylight.groupbasedpolicy.renderer.vpp.policy;
11 import java.util.HashMap;
14 import java.util.concurrent.ExecutionException;
15 import java.util.concurrent.TimeUnit;
16 import java.util.concurrent.TimeoutException;
18 import javax.annotation.Nonnull;
19 import javax.annotation.Nullable;
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;
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;
62 public final class ForwardingManager {
64 private static final Logger LOG = LoggerFactory.getLogger(ForwardingManager.class);
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);
78 public Optional<GbpBridgeDomain> readGbpBridgeDomainConfig(String name) {
79 InstanceIdentifier<GbpBridgeDomain> bdIid = InstanceIdentifier.builder(Config.class)
80 .child(GbpBridgeDomain.class, new GbpBridgeDomainKey(name))
82 ReadOnlyTransaction rTx = dataBroker.newReadOnlyTransaction();
83 return DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION, bdIid, rTx);
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);
95 VxlanVni vxlanVni = vxlanVniByBridgeDomain.get(bd);
96 if (vxlanVni == null) {
97 vxlanVni = new VxlanVni(lastVxlanVni++);
98 vxlanVniByBridgeDomain.put(bd, vxlanVni);
100 createVxlanBridgeDomains(bd, vxlanVni, vppNodes);
105 private void createVxlanBridgeDomains(final String bd, final VxlanVni vni, final Set<NodeId> vppNodes) {
106 for (NodeId vppNode : vppNodes) {
108 LOG.debug("Creating VXLAN bridge-domain {} on node {} with VNI {}", bd, vppNode.getValue(),
110 bdManager.createVxlanBridgeDomainOnVppNode(bd, vni, vppNode).get(WAIT_FOR_BD_CREATION,
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);
122 private void createVlanBridgeDomains(final String bd, final VlanId vlanId, final Set<NodeId> vppNodes) {
123 for (NodeId vppNode : vppNodes) {
125 LOG.debug("Creating VLAN bridge-domain {} on node {} with VLAN ID {}", bd, vppNode.getValue(),
127 bdManager.createVlanBridgeDomainOnVppNode(bd, vlanId, vppNode).get(WAIT_FOR_BD_CREATION,
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);
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) {
144 bdManager.removeBridgeDomainFromVppNode(bd, vppNode).get(WAIT_FOR_BD_CREATION,
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);
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);
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);
173 String l2FloodDomain = optL2FloodDomain.get();
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);
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);
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
196 if (!Strings.isNullOrEmpty(rEpLoc.getExternalNode())) {
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);
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);
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);
216 ExternalLocationCase result = (ExternalLocationCase) locationType;
217 if (result.getExternalNodeMountPoint() == null) {
218 throw new IllegalStateException("Endpoint does not have external-node-mount-point " + addrEpWithLoc);
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();
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());
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);
253 return java.util.Optional.empty();
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();
262 if (parent.getContextId() != null && parent.getContextType() != null) {
263 return java.util.Optional.ofNullable(forwardingCtxTable.get(tenant,
264 new RendererForwardingContextKey(parent.getContextId(), parent.getContextType())));
266 return java.util.Optional.empty();
270 void setTimer(byte time) {
271 WAIT_FOR_BD_CREATION = time;