MDSAL-API Migration
[genius.git] / interfacemanager / interfacemanager-impl / src / main / java / org / opendaylight / genius / interfacemanager / renderer / ovs / confighelpers / OvsInterfaceConfigAddHelper.java
1 /*
2  * Copyright (c) 2016, 2017 Ericsson India Global Services Pvt Ltd. 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 package org.opendaylight.genius.interfacemanager.renderer.ovs.confighelpers;
9
10 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
11 import static org.opendaylight.genius.infra.Datastore.OPERATIONAL;
12
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;
62
63 @Singleton
64 public final class OvsInterfaceConfigAddHelper {
65     private static final Logger LOG = LoggerFactory.getLogger(OvsInterfaceConfigAddHelper.class);
66
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;
76
77     @Inject
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;
96     }
97
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);
106                 } else {
107                     addVlanConfiguration(interfaceNew, parentRefs, configTx, operTx, futures);
108                 }
109             }));
110         }));
111         return futures;
112     }
113
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()) {
120             return;
121         }
122         if (!interfaceManagerCommonUtils.createInterfaceChildEntryIfNotPresent(confTx,
123                 parentRefs.getParentInterface(), interfaceNew.getName(), ifL2vlan.getL2vlanMode())) {
124             return;
125         }
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());
130
131         interfaceManagerCommonUtils.addStateEntry(operTx, interfaceNew.getName(), futures, ifState);
132     }
133
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) {
138             LOG.warn(
139                     "ParentRefs for interface: {} Not Found. "
140                             + "Creation of Tunnel OF-Port not supported when dpid not provided.",
141                     interfaceNew.getName());
142             return;
143         }
144
145         Uint64 dpId = parentRefs.getDatapathNodeIdentifier();
146         if (dpId == null) {
147             LOG.warn("dpid for interface: {} Not Found. No DPID provided. " + "Creation of OF-Port not supported.",
148                     interfaceNew.getName());
149             return;
150         }
151         LOG.info("adding tunnel configuration for interface {}", interfaceNew.getName());
152
153         if (ifTunnel.getTunnelInterfaceType().isAssignableFrom(TunnelTypeLogicalGroup.class)) {
154             futures.add(addLogicalTunnelGroup(interfaceNew, operTx, confTx));
155             return;
156         }
157
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
168                     .Interface
169                     interfaceState = interfaceManagerCommonUtils.getInterfaceState(tunnelName);
170             if (interfaceState != null) {
171                 coordinator.enqueueJob(tunnelName, () -> ovsInterfaceStateAddHelper.addState(interfaceNew.getName(),
172                         interfaceState));
173             }
174         } else {
175             tunnelName = interfaceNew.getName();
176         }
177
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);
184         }
185         LOG.debug("creating bridge interfaceEntry in ConfigDS {}", dpId);
186         interfaceMetaUtils.createBridgeInterfaceEntryInConfigDS(dpId, interfaceNew.getName());
187
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);
197             }
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);
212                 });
213         }
214     }
215
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);
224         return groupId;
225     }
226
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);
242     }
243
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);
254             if (ncId != null) {
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());
261                 futures.add(future);
262                 Futures.addCallback(future, new FutureCallback<Void>() {
263                     @Override
264                     public void onSuccess(@Nullable Void result) {
265                         // start LLDP monitoring for the tunnel interface
266                         alivenessMonitorUtils.startLLDPMonitoring(ifTunnel, interfaceNew.getName());
267                     }
268
269                     @Override
270                     public void onFailure(Throwable throwable) {
271                         LOG.error("Unable to add tunnel monitoring", throwable);
272                     }
273                 }, MoreExecutors.directExecutor());
274             }
275         }
276     }
277
278 }