Follow-up to https://git.opendaylight.org/gerrit/#/c/64492/
[genius.git] / interfacemanager / interfacemanager-impl / src / main / java / org / opendaylight / genius / interfacemanager / renderer / ovs / statehelpers / OvsInterfaceStateUpdateHelper.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.statehelpers;
9
10 import com.google.common.util.concurrent.ListenableFuture;
11 import java.util.Collections;
12 import java.util.List;
13 import javax.inject.Inject;
14 import javax.inject.Singleton;
15 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
16 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
17 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
18 import org.opendaylight.genius.interfacemanager.IfmUtil;
19 import org.opendaylight.genius.interfacemanager.commons.AlivenessMonitorUtils;
20 import org.opendaylight.genius.interfacemanager.commons.InterfaceManagerCommonUtils;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
22 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel;
28 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31
32 @Singleton
33 public class OvsInterfaceStateUpdateHelper {
34     private static final Logger LOG = LoggerFactory.getLogger(OvsInterfaceStateUpdateHelper.class);
35
36     private final DataBroker dataBroker;
37     private final InterfaceManagerCommonUtils interfaceManagerCommonUtils;
38     private final AlivenessMonitorUtils alivenessMonitorUtils;
39
40     @Inject
41     public OvsInterfaceStateUpdateHelper(DataBroker dataBroker, AlivenessMonitorUtils alivenessMonitorUtils,
42             InterfaceManagerCommonUtils interfaceManagerCommonUtils) {
43         this.dataBroker = dataBroker;
44         this.interfaceManagerCommonUtils =  interfaceManagerCommonUtils;
45         this.alivenessMonitorUtils = alivenessMonitorUtils;
46     }
47
48     public List<ListenableFuture<Void>> updateState(String interfaceName,
49             FlowCapableNodeConnector flowCapableNodeConnectorNew,
50             FlowCapableNodeConnector flowCapableNodeConnectorOld) {
51         LOG.debug("Updating interface state information for interface: {}", interfaceName);
52
53         Interface.OperStatus operStatusNew = InterfaceManagerCommonUtils.getOpState(flowCapableNodeConnectorNew);
54         MacAddress macAddressNew = flowCapableNodeConnectorNew.getHardwareAddress();
55
56         Interface.OperStatus operStatusOld = InterfaceManagerCommonUtils.getOpState(flowCapableNodeConnectorOld);
57         MacAddress macAddressOld = flowCapableNodeConnectorOld.getHardwareAddress();
58
59         boolean opstateModified = false;
60         boolean hardwareAddressModified = false;
61         if (!operStatusNew.equals(operStatusOld)) {
62             opstateModified = true;
63         }
64         if (!macAddressNew.equals(macAddressOld)) {
65             hardwareAddressModified = true;
66         }
67
68         if (!opstateModified && !hardwareAddressModified) {
69             LOG.debug("If State entry for port: {} Not Modified.", interfaceName);
70             return Collections.emptyList();
71         }
72
73         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf
74             .interfaces.rev140508.interfaces.Interface iface = interfaceManagerCommonUtils
75                 .getInterfaceFromConfigDS(interfaceName);
76
77         // For monitoring enabled tunnels, skip opstate update
78         if (isTunnelInterface(iface) && !modifyTunnelOpState(iface, opstateModified)) {
79             LOG.debug("skip interface-state updation for monitoring enabled tunnel interface {}", interfaceName);
80             opstateModified = false;
81         }
82
83         if (!opstateModified && !hardwareAddressModified) {
84             LOG.debug("If State entry for port: {} Not Modified.", interfaceName);
85             return Collections.emptyList();
86         }
87         InterfaceBuilder ifaceBuilder = new InterfaceBuilder();
88         if (hardwareAddressModified) {
89             LOG.debug("Hw-Address Modified for Port: {}", interfaceName);
90             PhysAddress physAddress = new PhysAddress(macAddressNew.getValue());
91             ifaceBuilder.setPhysAddress(physAddress);
92         }
93         // modify the attributes in interface operational DS
94         WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();
95         handleInterfaceStateUpdates(iface, transaction, ifaceBuilder, opstateModified, interfaceName,
96                 flowCapableNodeConnectorNew.getName(), operStatusNew);
97
98         // start/stop monitoring based on opState
99         if (isTunnelInterface(iface) && opstateModified) {
100             handleTunnelMonitoringUpdates(iface.getAugmentation(IfTunnel.class), iface.getName(), operStatusNew);
101         }
102
103         return Collections.singletonList(transaction.submit());
104     }
105
106     public void updateInterfaceStateOnNodeRemove(String interfaceName,
107             FlowCapableNodeConnector flowCapableNodeConnector, WriteTransaction transaction) {
108         LOG.debug("Updating interface oper-status to UNKNOWN for : {}", interfaceName);
109
110         InterfaceBuilder ifaceBuilder = new InterfaceBuilder();
111         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
112             .ietf.interfaces.rev140508.interfaces.Interface iface = interfaceManagerCommonUtils
113                 .getInterfaceFromConfigDS(interfaceName);
114         handleInterfaceStateUpdates(iface, transaction, ifaceBuilder, true, interfaceName,
115                 flowCapableNodeConnector.getName(), Interface.OperStatus.Unknown);
116         if (InterfaceManagerCommonUtils.isTunnelInterface(iface)) {
117             handleTunnelMonitoringUpdates(iface.getAugmentation(IfTunnel.class), interfaceName,
118                     Interface.OperStatus.Unknown);
119         }
120     }
121
122     public static void handleInterfaceStateUpdates(
123             org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
124                 .ietf.interfaces.rev140508.interfaces.Interface iface,
125             WriteTransaction transaction, InterfaceBuilder ifaceBuilder, boolean opStateModified,
126             String interfaceName, String portName, Interface.OperStatus opState) {
127         // if interface config DS is null, do the update only for the
128         // lower-layer-interfaces
129         // which have no corresponding config entries
130         if (iface == null && !interfaceName.equals(portName)) {
131             return;
132         }
133         LOG.debug("updating interface state entry for {}", interfaceName);
134         InstanceIdentifier<Interface> ifStateId = IfmUtil.buildStateInterfaceId(interfaceName);
135         ifaceBuilder.setKey(new InterfaceKey(interfaceName));
136         if (modifyOpState(iface, opStateModified)) {
137             LOG.debug("updating interface oper status as {} for {}", opState.name(), interfaceName);
138             ifaceBuilder.setOperStatus(opState);
139         }
140         transaction.merge(LogicalDatastoreType.OPERATIONAL, ifStateId, ifaceBuilder.build(), false);
141     }
142
143     public void handleTunnelMonitoringUpdates(IfTunnel ifTunnel,
144             String interfaceName, Interface.OperStatus operStatus) {
145         LOG.debug("handling tunnel monitoring updates for {} due to opstate modification", interfaceName);
146         if (operStatus == Interface.OperStatus.Down || operStatus == Interface.OperStatus.Unknown) {
147             alivenessMonitorUtils.stopLLDPMonitoring(ifTunnel, interfaceName);
148         } else {
149             alivenessMonitorUtils.startLLDPMonitoring(ifTunnel, interfaceName);
150         }
151     }
152
153     public static boolean modifyOpState(
154             org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf
155                 .interfaces.rev140508.interfaces.Interface iface,
156             boolean opStateModified) {
157         return opStateModified && (iface == null || iface != null && iface.isEnabled());
158     }
159
160     public static boolean isTunnelInterface(
161             org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
162                 .ietf.interfaces.rev140508.interfaces.Interface iface) {
163         return iface != null && iface.getAugmentation(IfTunnel.class) != null;
164     }
165
166     public static boolean modifyTunnelOpState(
167             org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
168                 .ietf.interfaces.rev140508.interfaces.Interface iface,
169             boolean opStateModified) {
170         if (!iface.getAugmentation(IfTunnel.class).isMonitorEnabled()) {
171             return modifyOpState(iface, opStateModified);
172         }
173         return false;
174     }
175 }