InfraUtil JobCordinator Changes.
[genius.git] / interfacemanager / interfacemanager-impl / src / main / java / org / opendaylight / genius / interfacemanager / renderer / ovs / confighelpers / OvsInterfaceConfigUpdateHelper.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.util.concurrent.ListenableFuture;
14 import java.util.ArrayList;
15 import java.util.Collections;
16 import java.util.List;
17 import java.util.Objects;
18 import java.util.concurrent.Callable;
19 import javax.inject.Inject;
20 import javax.inject.Singleton;
21
22 import org.apache.aries.blueprint.annotation.service.Reference;
23 import org.opendaylight.genius.infra.Datastore.Configuration;
24 import org.opendaylight.genius.infra.Datastore.Operational;
25 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
26 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
27 import org.opendaylight.genius.infra.TypedWriteTransaction;
28 import org.opendaylight.genius.interfacemanager.IfmConstants;
29 import org.opendaylight.genius.interfacemanager.commons.AlivenessMonitorUtils;
30 import org.opendaylight.genius.interfacemanager.commons.InterfaceManagerCommonUtils;
31 import org.opendaylight.genius.interfacemanager.commons.InterfaceMetaUtils;
32 import org.opendaylight.genius.interfacemanager.renderer.ovs.utilities.SouthboundUtils;
33 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
34 import org.opendaylight.mdsal.binding.api.DataBroker;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406._interface.child.info.InterfaceParentEntry;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406._interface.child.info.InterfaceParentEntryKey;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406._interface.child.info._interface.parent.entry.InterfaceChildEntry;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge.ref.info.BridgeRefEntry;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfL2vlan;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.ParentRefs;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47 @Singleton
48 public class OvsInterfaceConfigUpdateHelper {
49     private static final Logger LOG = LoggerFactory.getLogger(OvsInterfaceConfigUpdateHelper.class);
50     private static final Logger EVENT_LOGGER = LoggerFactory.getLogger("GeniusEventLogger");
51
52     private final ManagedNewTransactionRunner txRunner;
53     private final JobCoordinator coordinator;
54     private final InterfaceManagerCommonUtils interfaceManagerCommonUtils;
55     private final AlivenessMonitorUtils alivenessMonitorUtils;
56     private final OvsInterfaceConfigRemoveHelper ovsInterfaceConfigRemoveHelper;
57     private final OvsInterfaceConfigAddHelper ovsInterfaceConfigAddHelper;
58     private final InterfaceMetaUtils interfaceMetaUtils;
59
60     @Inject
61     public OvsInterfaceConfigUpdateHelper(@Reference DataBroker dataBroker,
62                                           @Reference JobCoordinator coordinator,
63                                           InterfaceManagerCommonUtils interfaceManagerCommonUtils,
64                                           AlivenessMonitorUtils alivenessMonitorUtils,
65                                           OvsInterfaceConfigRemoveHelper ovsInterfaceConfigRemoveHelper,
66                                           OvsInterfaceConfigAddHelper ovsInterfaceConfigAddHelper,
67                                           InterfaceMetaUtils interfaceMetaUtils) {
68         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
69         this.coordinator = coordinator;
70         this.interfaceManagerCommonUtils = interfaceManagerCommonUtils;
71         this.alivenessMonitorUtils = alivenessMonitorUtils;
72         this.ovsInterfaceConfigRemoveHelper = ovsInterfaceConfigRemoveHelper;
73         this.ovsInterfaceConfigAddHelper = ovsInterfaceConfigAddHelper;
74         this.interfaceMetaUtils = interfaceMetaUtils;
75     }
76
77     public List<ListenableFuture<Void>> updateConfiguration(Interface interfaceNew, Interface interfaceOld) {
78         List<ListenableFuture<Void>> futures = new ArrayList<>();
79         // If any of the port attributes are modified, treat it as a delete and
80         // recreate scenario
81         if (portAttributesModified(interfaceOld, interfaceNew)) {
82             LOG.info("port attributes modified, requires a delete and recreate of {} configuration", interfaceNew
83                     .getName());
84             futures.addAll(ovsInterfaceConfigRemoveHelper.removeConfiguration(interfaceOld,
85                     interfaceOld.augmentation(ParentRefs.class)));
86             futures.addAll(ovsInterfaceConfigAddHelper.addConfiguration(interfaceNew.augmentation(ParentRefs.class),
87                     interfaceNew));
88             return futures;
89         }
90
91         // If there is no operational state entry for the interface, treat it as
92         // create
93         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
94             .ietf.interfaces.rev140508.interfaces.state.Interface ifState = interfaceManagerCommonUtils
95                 .getInterfaceState(interfaceNew.getName());
96         if (ifState == null) {
97             futures.addAll(ovsInterfaceConfigAddHelper.addConfiguration(interfaceNew.augmentation(ParentRefs.class),
98                     interfaceNew));
99             return futures;
100         }
101
102         if (tunnelMonitoringAttributesModified(interfaceOld, interfaceNew)) {
103             futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
104                 tx -> handleTunnelMonitorUpdates(tx, interfaceNew, interfaceOld)));
105         } else if (!Objects.equals(interfaceNew.isEnabled(), interfaceOld.isEnabled())) {
106             EVENT_LOGGER.debug("IFM-OvsInterfaceConfig,UPDATE {}", interfaceNew.getName());
107             futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL,
108                 tx -> handleInterfaceAdminStateUpdates(tx, interfaceNew, ifState)));
109         }
110
111         return futures;
112     }
113
114     private static boolean portAttributesModified(Interface interfaceOld, Interface interfaceNew) {
115         ParentRefs parentRefsOld = interfaceOld.augmentation(ParentRefs.class);
116         ParentRefs parentRefsNew = interfaceNew.augmentation(ParentRefs.class);
117         if (checkAugmentations(parentRefsOld, parentRefsNew)) {
118             return true;
119         }
120
121         IfL2vlan ifL2vlanOld = interfaceOld.augmentation(IfL2vlan.class);
122         IfL2vlan ifL2vlanNew = interfaceNew.augmentation(IfL2vlan.class);
123         if (checkAugmentations(ifL2vlanOld, ifL2vlanNew)) {
124             return true;
125         }
126
127         IfTunnel ifTunnelOld = interfaceOld.augmentation(IfTunnel.class);
128         IfTunnel ifTunnelNew = interfaceNew.augmentation(IfTunnel.class);
129         if (checkAugmentations(ifTunnelOld, ifTunnelNew)) {
130             if (!Objects.equals(ifTunnelNew.getTunnelDestination(), ifTunnelOld.getTunnelDestination())
131                     || !Objects.equals(ifTunnelNew.getTunnelSource(), ifTunnelOld.getTunnelSource())
132                     || ifTunnelNew.getTunnelGateway() != null && ifTunnelOld.getTunnelGateway() != null
133                             && !ifTunnelNew.getTunnelGateway().equals(ifTunnelOld.getTunnelGateway())) {
134                 return true;
135             }
136         }
137
138         return false;
139     }
140
141     private static boolean tunnelMonitoringAttributesModified(Interface interfaceOld, Interface interfaceNew) {
142         IfTunnel ifTunnelOld = interfaceOld.augmentation(IfTunnel.class);
143         IfTunnel ifTunnelNew = interfaceNew.augmentation(IfTunnel.class);
144         return checkAugmentations(ifTunnelOld, ifTunnelNew);
145     }
146
147     /*
148      * if the tunnel monitoring attributes have changed, handle it based on the
149      * tunnel type. As of now internal vxlan tunnels use LLDP monitoring and
150      * external tunnels use BFD monitoring.
151      */
152     private void handleTunnelMonitorUpdates(TypedWriteTransaction<Configuration> transaction,
153             Interface interfaceNew, Interface interfaceOld) {
154         LOG.debug("tunnel monitoring attributes modified for interface {}", interfaceNew.getName());
155         // update termination point on switch, if switch is connected
156         BridgeRefEntry bridgeRefEntry = interfaceMetaUtils.getBridgeReferenceForInterface(interfaceNew);
157         IfTunnel ifTunnel = interfaceNew.augmentation(IfTunnel.class);
158         if (SouthboundUtils.isMonitorProtocolBfd(ifTunnel)
159                 && interfaceMetaUtils.bridgeExists(bridgeRefEntry)) {
160             SouthboundUtils.updateBfdParamtersForTerminationPoint(bridgeRefEntry.getBridgeReference().getValue(),
161                     interfaceNew.augmentation(IfTunnel.class), interfaceNew.getName(), transaction);
162         } else {
163             // update lldp tunnel monitoring attributes for an internal vxlan
164             // tunnel interface
165             alivenessMonitorUtils.handleTunnelMonitorUpdates(interfaceOld, interfaceNew);
166         }
167     }
168
169     private void handleInterfaceAdminStateUpdates(TypedWriteTransaction<Operational> transaction,
170             Interface interfaceNew,
171             org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
172                 .ietf.interfaces.rev140508.interfaces.state.Interface ifState) {
173         IfL2vlan ifL2vlan = interfaceNew.augmentation(IfL2vlan.class);
174         if (ifL2vlan == null || IfL2vlan.L2vlanMode.Trunk != ifL2vlan.getL2vlanMode()
175                 && IfL2vlan.L2vlanMode.Transparent != ifL2vlan.getL2vlanMode()) {
176             return;
177         }
178         LOG.info("admin-state modified for interface {}", interfaceNew.getName());
179         OperStatus operStatus = interfaceManagerCommonUtils.updateStateEntry(interfaceNew, transaction , ifState);
180         InterfaceParentEntryKey interfaceParentEntryKey = new InterfaceParentEntryKey(interfaceNew.getName());
181         InterfaceParentEntry interfaceParentEntry = interfaceMetaUtils
182                 .getInterfaceParentEntryFromConfigDS(interfaceParentEntryKey);
183         if (interfaceParentEntry == null || interfaceParentEntry.getInterfaceChildEntry() == null) {
184             return;
185         }
186
187         VlanMemberStateUpdateWorker vlanMemberStateUpdateWorker = new VlanMemberStateUpdateWorker(txRunner,
188                 operStatus, interfaceParentEntry.getInterfaceChildEntry());
189         coordinator.enqueueJob(interfaceNew.getName(), vlanMemberStateUpdateWorker, IfmConstants.JOB_MAX_RETRIES);
190     }
191
192     private static <T> boolean checkAugmentations(T oldAug, T newAug) {
193         if (oldAug != null && newAug == null || oldAug == null && newAug != null) {
194             return true;
195         }
196
197         return newAug != null && !newAug.equals(oldAug);
198     }
199
200     private static class VlanMemberStateUpdateWorker implements Callable<List<? extends ListenableFuture<?>>> {
201
202         private final ManagedNewTransactionRunner txRunner;
203         private final OperStatus operStatus;
204         private final List<InterfaceChildEntry> interfaceChildEntries;
205
206         VlanMemberStateUpdateWorker(ManagedNewTransactionRunner txRunner, OperStatus operStatus,
207                 List<InterfaceChildEntry> interfaceChildEntries) {
208             this.txRunner = txRunner;
209             this.operStatus = operStatus;
210             this.interfaceChildEntries = interfaceChildEntries;
211         }
212
213         @Override
214         public List<ListenableFuture<Void>> call() {
215             return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, tx -> {
216                 for (InterfaceChildEntry interfaceChildEntry : interfaceChildEntries) {
217                     InterfaceManagerCommonUtils.updateOperStatus(interfaceChildEntry.getChildInterface(), operStatus,
218                             tx);
219                 }
220             }));
221         }
222
223         @Override
224         public String toString() {
225             return "VlanMemberStateUpdateWorker [operStatus=" + operStatus + ", interfaceChildEntries="
226                     + interfaceChildEntries + "]";
227         }
228     }
229 }