2 * Copyright (c) 2016, 2017 Ericsson India Global Services Pvt Ltd. 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
8 package org.opendaylight.genius.interfacemanager.renderer.ovs.confighelpers;
10 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
11 import static org.opendaylight.genius.infra.Datastore.OPERATIONAL;
13 import com.google.common.base.Strings;
14 import com.google.common.util.concurrent.FutureCallback;
15 import com.google.common.util.concurrent.Futures;
16 import com.google.common.util.concurrent.ListenableFuture;
17 import com.google.common.util.concurrent.MoreExecutors;
18 import java.time.Duration;
19 import java.util.ArrayList;
20 import java.util.Collections;
21 import java.util.List;
22 import javax.inject.Inject;
23 import javax.inject.Singleton;
24 import org.apache.aries.blueprint.annotation.service.Reference;
25 import org.eclipse.jdt.annotation.Nullable;
26 import org.opendaylight.genius.datastoreutils.listeners.DataTreeEventCallbackRegistrar;
27 import org.opendaylight.genius.infra.Datastore.Configuration;
28 import org.opendaylight.genius.infra.Datastore.Operational;
29 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
30 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
31 import org.opendaylight.genius.infra.TypedWriteTransaction;
32 import org.opendaylight.genius.interfacemanager.IfmUtil;
33 import org.opendaylight.genius.interfacemanager.commons.AlivenessMonitorUtils;
34 import org.opendaylight.genius.interfacemanager.commons.InterfaceManagerCommonUtils;
35 import org.opendaylight.genius.interfacemanager.commons.InterfaceMetaUtils;
36 import org.opendaylight.genius.interfacemanager.renderer.ovs.statehelpers.OvsInterfaceStateAddHelper;
37 import org.opendaylight.genius.interfacemanager.renderer.ovs.utilities.SouthboundUtils;
38 import org.opendaylight.genius.interfacemanager.servicebindings.flowbased.utilities.FlowBasedServicesUtils;
39 import org.opendaylight.genius.mdsalutil.MDSALUtil;
40 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
41 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
42 import org.opendaylight.mdsal.binding.api.DataBroker;
43 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
44 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.BridgeRefInfo;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge._interface.info.BridgeEntry;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge.ref.info.BridgeRefEntry;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge.ref.info.BridgeRefEntryKey;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfL2vlan;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.ParentRefs;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeLogicalGroup;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
58 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
59 import org.opendaylight.yangtools.yang.common.Uint64;
60 import org.slf4j.Logger;
61 import org.slf4j.LoggerFactory;
64 public final class OvsInterfaceConfigAddHelper {
65 private static final Logger LOG = LoggerFactory.getLogger(OvsInterfaceConfigAddHelper.class);
67 private final ManagedNewTransactionRunner txRunner;
68 private final IMdsalApiManager mdsalApiManager;
69 private final JobCoordinator coordinator;
70 private final AlivenessMonitorUtils alivenessMonitorUtils;
71 private final InterfaceManagerCommonUtils interfaceManagerCommonUtils;
72 private final OvsInterfaceStateAddHelper ovsInterfaceStateAddHelper;
73 private final InterfaceMetaUtils interfaceMetaUtils;
74 private final SouthboundUtils southboundUtils;
75 private final DataTreeEventCallbackRegistrar eventCallbacks;
78 public OvsInterfaceConfigAddHelper(@Reference DataBroker dataBroker,
79 AlivenessMonitorUtils alivenessMonitorUtils,
80 @Reference IMdsalApiManager mdsalApiManager,
81 @Reference JobCoordinator coordinator,
82 InterfaceManagerCommonUtils interfaceManagerCommonUtils,
83 OvsInterfaceStateAddHelper ovsInterfaceStateAddHelper,
84 InterfaceMetaUtils interfaceMetaUtils,
85 SouthboundUtils southboundUtils,
86 DataTreeEventCallbackRegistrar eventCallbacks) {
87 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
88 this.alivenessMonitorUtils = alivenessMonitorUtils;
89 this.mdsalApiManager = mdsalApiManager;
90 this.coordinator = coordinator;
91 this.interfaceManagerCommonUtils = interfaceManagerCommonUtils;
92 this.ovsInterfaceStateAddHelper = ovsInterfaceStateAddHelper;
93 this.interfaceMetaUtils = interfaceMetaUtils;
94 this.southboundUtils = southboundUtils;
95 this.eventCallbacks = eventCallbacks;
98 public List<ListenableFuture<Void>> addConfiguration(ParentRefs parentRefs, Interface interfaceNew) {
99 List<ListenableFuture<Void>> futures = new ArrayList<>();
100 // TODO Disentangle the transactions
101 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, configTx -> {
102 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, operTx -> {
103 IfTunnel ifTunnel = interfaceNew.augmentation(IfTunnel.class);
104 if (ifTunnel != null) {
105 addTunnelConfiguration(parentRefs, interfaceNew, ifTunnel, configTx, operTx, futures);
107 addVlanConfiguration(interfaceNew, parentRefs, configTx, operTx, futures);
114 private void addVlanConfiguration(Interface interfaceNew, ParentRefs parentRefs,
115 TypedWriteTransaction<Configuration> confTx, TypedWriteTransaction<Operational> operTx,
116 List<ListenableFuture<Void>> futures) {
117 IfL2vlan ifL2vlan = interfaceNew.augmentation(IfL2vlan.class);
118 if (ifL2vlan == null || IfL2vlan.L2vlanMode.Trunk != ifL2vlan.getL2vlanMode()
119 && IfL2vlan.L2vlanMode.Transparent != ifL2vlan.getL2vlanMode()) {
122 if (!interfaceManagerCommonUtils.createInterfaceChildEntryIfNotPresent(confTx,
123 parentRefs.getParentInterface(), interfaceNew.getName(), ifL2vlan.getL2vlanMode())) {
126 LOG.info("adding vlan configuration for interface {}", interfaceNew.getName());
127 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
128 .ietf.interfaces.rev140508.interfaces.state.Interface ifState = interfaceManagerCommonUtils
129 .getInterfaceState(parentRefs.getParentInterface());
131 interfaceManagerCommonUtils.addStateEntry(operTx, interfaceNew.getName(), futures, ifState);
134 private void addTunnelConfiguration(ParentRefs parentRefs, Interface interfaceNew, IfTunnel ifTunnel,
135 TypedWriteTransaction<Configuration> confTx, TypedWriteTransaction<Operational> operTx,
136 List<ListenableFuture<Void>> futures) {
137 if (parentRefs == null) {
139 "ParentRefs for interface: {} Not Found. "
140 + "Creation of Tunnel OF-Port not supported when dpid not provided.",
141 interfaceNew.getName());
145 Uint64 dpId = parentRefs.getDatapathNodeIdentifier();
147 LOG.warn("dpid for interface: {} Not Found. No DPID provided. " + "Creation of OF-Port not supported.",
148 interfaceNew.getName());
151 LOG.info("adding tunnel configuration for interface {}", interfaceNew.getName());
153 if (ifTunnel.getTunnelInterfaceType().isAssignableFrom(TunnelTypeLogicalGroup.class)) {
154 futures.add(addLogicalTunnelGroup(interfaceNew, operTx, confTx));
158 boolean createTunnelPort = true;
159 final String tunnelName;
160 if (SouthboundUtils.isOfTunnel(ifTunnel)) {
161 BridgeEntry bridgeEntry = interfaceMetaUtils.getBridgeEntryFromConfigDS(dpId);
162 createTunnelPort = bridgeEntry == null
163 || bridgeEntry.getBridgeInterfaceEntry() == null
164 || bridgeEntry.getBridgeInterfaceEntry().isEmpty();
165 tunnelName = SouthboundUtils.generateOfTunnelName(dpId, ifTunnel);
166 interfaceManagerCommonUtils.createInterfaceChildEntry(confTx, tunnelName, interfaceNew.getName());
167 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state
169 interfaceState = interfaceManagerCommonUtils.getInterfaceState(tunnelName);
170 if (interfaceState != null) {
171 coordinator.enqueueJob(tunnelName, () -> ovsInterfaceStateAddHelper.addState(interfaceNew.getName(),
175 tunnelName = interfaceNew.getName();
178 String parentInterface = parentRefs.getParentInterface();
179 if (ifTunnel.getTunnelInterfaceType().isAssignableFrom(TunnelTypeVxlan.class)
180 && !Strings.isNullOrEmpty(parentInterface)) {
181 LOG.debug("MULTIPLE_VxLAN_TUNNELS: createInterfaceChildEntry for {} in logical group {}",
182 tunnelName, parentInterface);
183 interfaceManagerCommonUtils.createInterfaceChildEntry(confTx, parentInterface, tunnelName);
185 LOG.debug("creating bridge interfaceEntry in ConfigDS {}", dpId);
186 interfaceMetaUtils.createBridgeInterfaceEntryInConfigDS(dpId, interfaceNew.getName());
188 // create bridge on switch, if switch is connected
189 BridgeRefEntry bridgeRefEntry = interfaceMetaUtils.getBridgeRefEntryFromOperDS(dpId);
190 if (bridgeRefEntry != null && bridgeRefEntry.getBridgeReference() != null) {
191 LOG.debug("creating bridge interface on dpn {}", dpId);
192 InstanceIdentifier<OvsdbBridgeAugmentation> bridgeIid =
193 (InstanceIdentifier<OvsdbBridgeAugmentation>) bridgeRefEntry
194 .getBridgeReference().getValue();
195 if (createTunnelPort) {
196 southboundUtils.addPortToBridge(bridgeIid, interfaceNew, tunnelName);
198 setupTunnelFlowsAndMonitoring(interfaceNew, confTx, ifTunnel, dpId, futures);
199 } else if (createTunnelPort) {
200 LOG.debug("Bridge not found. Registering eventcallback for dpid {}", dpId);
201 InstanceIdentifier<BridgeRefEntry> bridgeRefEntryInstanceIdentifier =
202 InstanceIdentifier.builder(BridgeRefInfo.class)
203 .child(BridgeRefEntry.class, new BridgeRefEntryKey(dpId)).build();
204 eventCallbacks.onAdd(LogicalDatastoreType.OPERATIONAL, bridgeRefEntryInstanceIdentifier,
205 (bridgeRefEntryOnCallback) -> {
206 LOG.debug("eventcallback triggered on bridge reference entry addition {}", dpId);
207 southboundUtils.addPortToBridge(bridgeRefEntryOnCallback.getBridgeReference().getValue(),
208 interfaceNew, tunnelName);
209 return DataTreeEventCallbackRegistrar.NextAction.UNREGISTER;
210 }, Duration.ofMillis(5000), (id) -> {
211 LOG.info("event call back timed-out for bridge creation, {}", dpId);
216 private long createLogicalTunnelSelectGroup(TypedWriteTransaction<Configuration> tx,
217 Uint64 srcDpnId, String interfaceName, int lportTag) {
218 long groupId = IfmUtil.getLogicalTunnelSelectGroupId(lportTag);
219 Group group = MDSALUtil.buildGroup(groupId, interfaceName, GroupTypes.GroupSelect,
220 MDSALUtil.buildBucketLists(Collections.emptyList()));
221 LOG.debug("MULTIPLE_VxLAN_TUNNELS: group id {} installed for {} srcDpnId {}",
222 group.getGroupId().getValue(), interfaceName, srcDpnId);
223 mdsalApiManager.addGroup(tx, srcDpnId, group);
227 private ListenableFuture<Void> addLogicalTunnelGroup(Interface itfNew, TypedWriteTransaction<Operational> operTx,
228 TypedWriteTransaction<Configuration> confTx) {
229 String ifaceName = itfNew.getName();
230 LOG.debug("MULTIPLE_VxLAN_TUNNELS: adding Interface State for logic tunnel group {}", ifaceName);
231 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state
232 .Interface ifState = interfaceManagerCommonUtils.addStateEntry(itfNew, ifaceName, operTx,
233 null /*physAddress*/, org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf
234 .interfaces.rev140508.interfaces.state.Interface.OperStatus.Up,
235 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf
236 .interfaces.rev140508.interfaces.state.Interface.AdminStatus.Up,
237 null /*nodeConnectorId*/);
238 long groupId = createLogicalTunnelSelectGroup(confTx, IfmUtil.getDpnFromInterface(ifState),
239 itfNew.getName(), ifState.getIfIndex());
240 return FlowBasedServicesUtils.bindDefaultEgressDispatcherService(txRunner, itfNew,
241 ifaceName, ifState.getIfIndex(), groupId);
244 private void setupTunnelFlowsAndMonitoring(Interface interfaceNew, TypedWriteTransaction<Configuration> confTx,
245 IfTunnel ifTunnel, Uint64 dpId,
246 List<ListenableFuture<Void>> futures) {
247 // if TEP is already configured on switch, start LLDP monitoring and
248 // program tunnel ingress flow
249 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
250 .ietf.interfaces.rev140508.interfaces.state.Interface ifState = interfaceManagerCommonUtils
251 .getInterfaceState(interfaceNew.getName());
252 if (ifState != null) {
253 NodeConnectorId ncId = IfmUtil.getNodeConnectorIdFromInterface(ifState);
255 long portNo = IfmUtil.getPortNumberFromNodeConnectorId(ncId);
256 interfaceManagerCommonUtils.addTunnelIngressFlow(confTx, ifTunnel, dpId, portNo,
257 interfaceNew.getName(), ifState.getIfIndex());
258 ListenableFuture<Void> future =
259 FlowBasedServicesUtils.bindDefaultEgressDispatcherService(txRunner, interfaceNew,
260 Long.toString(portNo), interfaceNew.getName(), ifState.getIfIndex());
262 Futures.addCallback(future, new FutureCallback<Void>() {
264 public void onSuccess(@Nullable Void result) {
265 // start LLDP monitoring for the tunnel interface
266 alivenessMonitorUtils.startLLDPMonitoring(ifTunnel, interfaceNew.getName());
270 public void onFailure(Throwable throwable) {
271 LOG.error("Unable to add tunnel monitoring", throwable);
273 }, MoreExecutors.directExecutor());