d793d71fff096e455aef93409d4ff7be726b0e14
[vpnservice.git] / interfacemgr / interfacemgr-impl / src / main / java / org / opendaylight / vpnservice / interfacemgr / renderer / ovs / statehelpers / OvsInterfaceStateUpdateHelper.java
1 /*
2  * Copyright (c) 2015 - 2016 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.vpnservice.interfacemgr.renderer.ovs.statehelpers;
9
10 import com.google.common.util.concurrent.ListenableFuture;
11 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
12 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
13 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
14 import org.opendaylight.vpnservice.interfacemgr.IfmUtil;
15 import org.opendaylight.vpnservice.interfacemgr.commons.AlivenessMonitorUtils;
16 import org.opendaylight.vpnservice.interfacemgr.commons.InterfaceManagerCommonUtils;
17 import org.opendaylight.vpnservice.interfacemgr.commons.InterfaceMetaUtils;
18 import org.opendaylight.vpnservice.interfacemgr.servicebindings.flowbased.utilities.FlowBasedServicesUtils;
19 import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
20 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder;
22 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.AlivenessMonitorService;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007._interface.child.info.InterfaceParentEntry;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007._interface.child.info._interface.parent.entry.InterfaceChildEntry;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnel;
32 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36 import java.math.BigInteger;
37 import java.util.ArrayList;
38 import java.util.List;
39
40 public class OvsInterfaceStateUpdateHelper {
41     private static final Logger LOG = LoggerFactory.getLogger(OvsInterfaceStateUpdateHelper.class);
42
43     public static List<ListenableFuture<Void>> updateState(InstanceIdentifier<FlowCapableNodeConnector> key,
44                                                            AlivenessMonitorService alivenessMonitorService,
45                                                            DataBroker dataBroker, String portName,
46                                                            FlowCapableNodeConnector flowCapableNodeConnectorNew,
47                                                            FlowCapableNodeConnector flowCapableNodeConnectorOld) {
48         LOG.debug("Update of Interface State for port: {}", portName);
49         List<ListenableFuture<Void>> futures = new ArrayList<>();
50         WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();
51
52         Interface.OperStatus operStatusNew = getOpState(flowCapableNodeConnectorNew);
53         MacAddress macAddressNew = flowCapableNodeConnectorNew.getHardwareAddress();
54
55         Interface.OperStatus operStatusOld = getOpState(flowCapableNodeConnectorOld);
56         MacAddress macAddressOld = flowCapableNodeConnectorOld.getHardwareAddress();
57
58         boolean opstateModified = false;
59         boolean hardwareAddressModified = false;
60         if (!operStatusNew.equals(operStatusOld)) {
61             opstateModified = true;
62         }
63         if (!macAddressNew.equals(macAddressOld)) {
64             hardwareAddressModified = true;
65         }
66
67         if (!opstateModified && !hardwareAddressModified) {
68             LOG.debug("If State entry for port: {} Not Modified.", portName);
69             return futures;
70         }
71
72         InterfaceBuilder ifaceBuilder = new InterfaceBuilder();
73         if (hardwareAddressModified) {
74             LOG.debug("Hw-Address Modified for Port: {}", portName);
75             PhysAddress physAddress = new PhysAddress(macAddressNew.getValue());
76             ifaceBuilder.setPhysAddress(physAddress);
77         }
78
79         NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(key.firstIdentifierOf(NodeConnector.class)).getId();
80         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface =
81                 handleInterfaceStateUpdates(portName, nodeConnectorId,
82                 transaction, dataBroker, ifaceBuilder, opstateModified, operStatusNew);
83
84         InterfaceParentEntry interfaceParentEntry =
85                 InterfaceMetaUtils.getInterfaceParentEntryFromConfigDS(portName, dataBroker);
86         if (interfaceParentEntry != null && interfaceParentEntry.getInterfaceChildEntry() != null) {
87             for (InterfaceChildEntry higherlayerChild : interfaceParentEntry.getInterfaceChildEntry()) {
88                 handleInterfaceStateUpdates(higherlayerChild.getChildInterface(),
89                         nodeConnectorId, transaction, dataBroker, ifaceBuilder, opstateModified, operStatusNew);
90                 InterfaceParentEntry higherLayerParent =
91                         InterfaceMetaUtils.getInterfaceParentEntryFromConfigDS(higherlayerChild.getChildInterface(), dataBroker);
92                 if (higherLayerParent != null && higherLayerParent.getInterfaceChildEntry() != null) {
93                     for (InterfaceChildEntry interfaceChildEntry : higherLayerParent.getInterfaceChildEntry()) {
94                         //FIXME: If the no. of child entries exceeds 100, perform txn updates in batches of 100.
95                         handleInterfaceStateUpdates(interfaceChildEntry.getChildInterface(), nodeConnectorId,
96                                 transaction, dataBroker, ifaceBuilder, opstateModified, operStatusNew);
97                     }
98                 }
99             }
100         }else {
101             handleTunnelMonitoringUpdates(alivenessMonitorService, dataBroker, iface, operStatusNew, opstateModified);
102         }
103         futures.add(transaction.submit());
104         return futures;
105     }
106
107     public static Interface.OperStatus getOpState(FlowCapableNodeConnector flowCapableNodeConnector){
108         Interface.OperStatus operStatus =
109                 (flowCapableNodeConnector.getState().isLive() &&
110                         !flowCapableNodeConnector.getConfiguration().isPORTDOWN())
111                         ? Interface.OperStatus.Up: Interface.OperStatus.Down;
112         return operStatus;
113     }
114
115     public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface
116     handleInterfaceStateUpdates(String interfaceName, NodeConnectorId nodeConnectorId,WriteTransaction transaction,
117                                 DataBroker dataBroker, InterfaceBuilder ifaceBuilder, boolean opStateModified,
118                                 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus opState){
119         LOG.debug("updating interface state entry for {}", interfaceName);
120         InstanceIdentifier<Interface> ifStateId = IfmUtil.buildStateInterfaceId(interfaceName);
121         ifaceBuilder.setKey(new InterfaceKey(interfaceName));
122         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface =
123                 InterfaceManagerCommonUtils.getInterfaceFromConfigDS(interfaceName, dataBroker);
124         if (modifyOpState(iface, opStateModified)) {
125             LOG.debug("updating interface oper status as {} for {}", opState.name(), interfaceName);
126             ifaceBuilder.setOperStatus(opState);
127         }
128         transaction.merge(LogicalDatastoreType.OPERATIONAL, ifStateId, ifaceBuilder.build());
129
130         // if opstate has changed, add or remove ingress flow for l2vlan interfaces accordingly
131         if(modifyIngressFlow(iface, opStateModified)) {
132             handleVlanIngressFlowUpdates(dataBroker, opState, transaction, iface, nodeConnectorId, ifStateId);
133         }
134         return iface;
135     }
136
137     public static void handleTunnelMonitoringUpdates(AlivenessMonitorService alivenessMonitorService, DataBroker dataBroker,
138                                                      org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface,
139                                                      Interface.OperStatus operStatus, boolean opStateModified){
140         // start/stop monitoring based on opState
141         if(!modifyTunnel(iface, opStateModified)){
142             return;
143         }
144
145         LOG.debug("handling tunnel monitoring updates for {} due to opstate modification", iface.getName());
146         if (operStatus == Interface.OperStatus.Down)
147             AlivenessMonitorUtils.stopLLDPMonitoring(alivenessMonitorService, dataBroker, iface);
148         else
149             AlivenessMonitorUtils.startLLDPMonitoring(alivenessMonitorService, dataBroker, iface);
150     }
151
152     public static boolean modifyOpState(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface,
153                                         boolean opStateModified){
154         return (opStateModified && (iface == null || iface != null && iface.isEnabled()));
155     }
156
157     public static boolean modifyIngressFlow(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface,
158                                         boolean opStateModified){
159         return modifyOpState(iface, opStateModified) && iface != null && iface.getAugmentation(IfTunnel.class) == null;
160     }
161
162     public static boolean modifyTunnel(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface,
163                                             boolean opStateModified){
164         return modifyOpState(iface, opStateModified) && iface != null && iface.getAugmentation(IfTunnel.class) != null;
165     }
166
167     public static void handleVlanIngressFlowUpdates(DataBroker dataBroker, Interface.OperStatus opState, WriteTransaction transaction,
168                                                     org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface,
169                                                     NodeConnectorId nodeConnectorId, InstanceIdentifier<Interface> ifStateId){
170         LOG.debug("handling vlan ingress flow updates for {}", iface.getName());
171         Interface ifState = InterfaceManagerCommonUtils.getInterfaceStateFromOperDS(ifStateId, dataBroker);
172         BigInteger dpId = new BigInteger(IfmUtil.getDpnFromNodeConnectorId(nodeConnectorId));
173         if (opState == org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus.Up) {
174             long portNo = Long.valueOf(IfmUtil.getPortNoFromNodeConnectorId(nodeConnectorId));
175             List<MatchInfo> matches = FlowBasedServicesUtils.getMatchInfoForVlanPortAtIngressTable(dpId, portNo, iface);
176             FlowBasedServicesUtils.installVlanFlow(dpId, portNo, iface, transaction, matches, ifState.getIfIndex());
177         } else {
178             FlowBasedServicesUtils.removeIngressFlow(iface.getName(), dpId, transaction);
179         }
180     }
181 }