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.forwarding.l2_l3.rev160427.L2FloodDomain;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.endpoints.AddressEndpointWithLocation;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.endpoints.RendererEndpointKey;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.Config;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.VlanNetwork;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.BridgeDomain;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.BridgeDomainKey;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanVni;
43 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
44 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
48 import com.google.common.annotations.VisibleForTesting;
49 import com.google.common.base.Optional;
50 import com.google.common.base.Preconditions;
51 import com.google.common.base.Strings;
52 import com.google.common.collect.SetMultimap;
54 public final class ForwardingManager {
56 private static final Logger LOG = LoggerFactory.getLogger(ForwardingManager.class);
58 static long WAIT_FOR_BD_CREATION = 10; // seconds
59 private long lastVxlanVni = 1L;
60 private final Map<String, VxlanVni> vxlanVniByBridgeDomain = new HashMap<>();
61 private final InterfaceManager ifaceManager;
62 private final BridgeDomainManager bdManager;
63 private final DataBroker dataBroker;
64 public ForwardingManager(@Nonnull InterfaceManager ifaceManager, @Nonnull BridgeDomainManager bdManager, @Nonnull DataBroker dataBroker) {
65 this.ifaceManager = Preconditions.checkNotNull(ifaceManager);
66 this.bdManager = Preconditions.checkNotNull(bdManager);
67 this.dataBroker = Preconditions.checkNotNull(dataBroker);
70 public Optional<BridgeDomain> readBridgeDomainConfig(String name) {
71 InstanceIdentifier<BridgeDomain> bdIid = InstanceIdentifier.builder(Config.class)
72 .child(BridgeDomain.class, new BridgeDomainKey(name))
74 ReadOnlyTransaction rTx = dataBroker.newReadOnlyTransaction();
75 return DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION, bdIid, rTx);
78 public void createBridgeDomainOnNodes(SetMultimap<String, NodeId> vppNodesByBridgeDomain) {
79 for (String bd : vppNodesByBridgeDomain.keySet()) {
80 Optional<BridgeDomain> bdConfig = readBridgeDomainConfig(bd);
81 Set<NodeId> vppNodes = vppNodesByBridgeDomain.get(bd);
82 if (bdConfig.isPresent()) {
83 if (bdConfig.get().getType().equals(VlanNetwork.class)) {
84 createVlanBridgeDomains(bd, bdConfig.get().getVlan(), vppNodes);
87 VxlanVni vxlanVni = vxlanVniByBridgeDomain.get(bd);
88 if (vxlanVni == null) {
89 vxlanVni = new VxlanVni(lastVxlanVni++);
90 vxlanVniByBridgeDomain.put(bd, vxlanVni);
92 createVxlanBridgeDomains(bd, vxlanVni, vppNodes);
97 private void createVxlanBridgeDomains(String bd, VxlanVni vni, Set<NodeId> vppNodes) {
98 for (NodeId vppNode : vppNodes) {
100 LOG.trace("Creating VXLAN bridge-domain {} on node {} with VNI {}", bd, vppNode.getValue(),
102 // TODO think about propagating ListenableFuture - timeout set as workaround
103 bdManager.createVxlanBridgeDomainOnVppNode(bd, vni, vppNode).get(WAIT_FOR_BD_CREATION,
105 } catch (InterruptedException | ExecutionException e) {
106 LOG.warn("VXLAN Bridge domain {} was not created on node {}", bd, vppNode.getValue(), e);
107 } catch (TimeoutException e) {
108 LOG.warn("Probably, VXLAN Bridge domain {} was not created on node {} because BridgeDomainManager "
109 + "did not respond by {} seconds.", bd, vppNode.getValue(), WAIT_FOR_BD_CREATION, e);
114 private void createVlanBridgeDomains(String bd, VlanId vlanId, Set<NodeId> vppNodes) {
115 for (NodeId vppNode : vppNodes) {
117 LOG.trace("Creating VLAN bridge-domain {} on node {} with VLAN ID {}", bd, vppNode.getValue(),
119 // TODO think about propagating ListenableFuture - timeout set as workaround
120 bdManager.createVlanBridgeDomainOnVppNode(bd, vlanId, vppNode).get(WAIT_FOR_BD_CREATION,
122 } catch (InterruptedException | ExecutionException e) {
123 LOG.warn("VLAN Bridge domain {} was not created on node {}", bd, vppNode.getValue(), e);
124 } catch (TimeoutException e) {
125 LOG.warn("Probably, VLAN Bridge domain {} was not created on node {} because BridgeDomainManager "
126 + "did not respond by {} seconds.", bd, vppNode.getValue(), WAIT_FOR_BD_CREATION, e);
131 public void removeBridgeDomainOnNodes(SetMultimap<String, NodeId> vppNodesByBridgeDomain) {
132 for (String bd : vppNodesByBridgeDomain.keySet()) {
133 Set<NodeId> vppNodes = vppNodesByBridgeDomain.get(bd);
134 for (NodeId vppNode : vppNodes) {
136 bdManager.removeBridgeDomainFromVppNode(bd, vppNode).get(WAIT_FOR_BD_CREATION,
138 } catch (InterruptedException | ExecutionException e) {
139 LOG.warn("Bridge domain {} was not removed from node {}", bd, vppNode.getValue(), e);
140 } catch (TimeoutException e) {
141 LOG.warn("Probably, bridge domain {} was not removed from node {} because BridgeDomainManager "
142 + "did not respond by {} seconds.", bd, vppNode.getValue(), WAIT_FOR_BD_CREATION, e);
148 public void createForwardingForEndpoint(RendererEndpointKey rEpKey, PolicyContext policyCtx) {
149 AddressEndpointWithLocation rEp = policyCtx.getAddrEpByKey().get(KeyFactory.addressEndpointKey(rEpKey));
150 ExternalLocationCase rEpLoc = resolveAndValidateLocation(rEp);
151 if (Strings.isNullOrEmpty(rEpLoc.getExternalNodeConnector())) {
152 // TODO add it to the status for renderer manager
153 LOG.info("Rednerer endpoint does not have external-node-connector therefore it is ignored {}", rEp);
157 if (Strings.isNullOrEmpty(rEpLoc.getExternalNode())) {
158 Optional<String> optL2FloodDomain = resolveL2FloodDomain(rEp.getNetworkContainment());
159 if (!optL2FloodDomain.isPresent()) {
160 // TODO add it to the status for renderer manager
161 LOG.info("Rednerer endpoint does not have l2FloodDomain as network containment {}", rEp);
164 String l2FloodDomain = optL2FloodDomain.get();
166 ifaceManager.addBridgeDomainToInterface(l2FloodDomain, rEp).get();
167 LOG.debug("Interface added to bridge-domain {} for endpoint {}", l2FloodDomain, rEp);
168 } catch (InterruptedException | ExecutionException e) {
169 // TODO add it to the status for renderer manager
170 LOG.warn("Interface was not added to bridge-domain {} for endpoint {}", l2FloodDomain, rEp, e);
173 LOG.debug("Forwarding is not created - Location of renderer endpoint contains "
174 + "external-node therefore VPP renderer assumes that interface for endpoint is "
175 + "already assigned in bridge-domain representing external-node. {}", rEp);
179 public void removeForwardingForEndpoint(RendererEndpointKey rEpKey, PolicyContext policyCtx) {
180 AddressEndpointWithLocation rEp = policyCtx.getAddrEpByKey().get(KeyFactory.addressEndpointKey(rEpKey));
181 ExternalLocationCase rEpLoc = resolveAndValidateLocation(rEp);
182 if (Strings.isNullOrEmpty(rEpLoc.getExternalNodeConnector())) {
183 // nothing was created for endpoint therefore nothing is removed
187 if (!Strings.isNullOrEmpty(rEpLoc.getExternalNode())) {
189 ifaceManager.deleteBridgeDomainFromInterface(rEp).get();
190 LOG.debug("bridge-domain was deleted from interface for endpoint {}", rEp);
191 } catch (InterruptedException | ExecutionException e) {
192 // TODO add it to the status for renderer manager
193 LOG.warn("bridge-domain was not deleted from interface for endpoint {}", rEp, e);
196 LOG.debug("Forwarding is not removed - Location of renderer endpoint does not contain "
197 + "external-node therefore VPP renderer assumes that interface for endpoint is not "
198 + "assigned to bridge-domain representing external-node. {}", rEp);
202 public static ExternalLocationCase resolveAndValidateLocation(AddressEndpointWithLocation addrEpWithLoc) {
203 LocationType locationType = addrEpWithLoc.getAbsoluteLocation().getLocationType();
204 if (!(locationType instanceof ExternalLocationCase)) {
205 throw new IllegalStateException("Endpoint does not have external location " + addrEpWithLoc);
207 ExternalLocationCase result = (ExternalLocationCase) locationType;
208 if (result.getExternalNodeMountPoint() == null) {
209 throw new IllegalStateException("Endpoint does not have external-node-mount-point " + addrEpWithLoc);
214 public static Optional<String> resolveL2FloodDomain(@Nullable NetworkContainment netCont) {
215 if (netCont == null) {
216 return Optional.absent();
218 Containment containment = netCont.getContainment();
219 if (containment instanceof ForwardingContextContainment) {
220 ForwardingContextContainment fwCtxCont = (ForwardingContextContainment) containment;
221 if (fwCtxCont.getContextType().isAssignableFrom(L2FloodDomain.class)) {
222 return fwCtxCont.getContextId() == null ? null : Optional.of(fwCtxCont.getContextId().getValue());
225 if (containment instanceof NetworkDomainContainment) {
226 // TODO address missing impl
227 LOG.info("Network domain containment in endpoint is not supported yet. {}", netCont);
228 return Optional.absent();
230 return Optional.absent();