Merge "Support for binding multiple egress services on the same interface"
[genius.git] / interfacemanager / interfacemanager-impl / src / main / java / org / opendaylight / genius / interfacemanager / servicebindings / flowbased / config / helpers / FlowBasedEgressServicesConfigUnbindHelper.java
1 /*
2  * Copyright (c) 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.genius.interfacemanager.servicebindings.flowbased.config.helpers;
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.genius.interfacemanager.IfmConstants;
14 import org.opendaylight.genius.interfacemanager.InterfacemgrProvider;
15 import org.opendaylight.genius.interfacemanager.commons.InterfaceManagerCommonUtils;
16 import org.opendaylight.genius.interfacemanager.servicebindings.flowbased.config.factory.FlowBasedServicesConfigRemovable;
17 import org.opendaylight.genius.interfacemanager.servicebindings.flowbased.utilities.FlowBasedServicesUtils;
18 import org.opendaylight.genius.mdsalutil.NwConstants;
19 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.L2vlan;
20 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeBase;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfo;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
25 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
28
29 import java.math.BigInteger;
30 import java.util.ArrayList;
31 import java.util.List;
32
33 public class FlowBasedEgressServicesConfigUnbindHelper implements FlowBasedServicesConfigRemovable {
34     private static final Logger LOG = LoggerFactory.getLogger(FlowBasedEgressServicesConfigUnbindHelper.class);
35
36     private InterfacemgrProvider interfaceMgrProvider;
37     private static volatile FlowBasedServicesConfigRemovable flowBasedEgressServicesRemovable;
38
39     private FlowBasedEgressServicesConfigUnbindHelper(InterfacemgrProvider interfaceMgrProvider) {
40         this.interfaceMgrProvider = interfaceMgrProvider;
41     }
42
43     public static void intitializeFlowBasedEgressServicesConfigRemoveHelper(InterfacemgrProvider interfaceMgrProvider) {
44         if (flowBasedEgressServicesRemovable == null) {
45             synchronized (FlowBasedEgressServicesConfigUnbindHelper.class) {
46                 if (flowBasedEgressServicesRemovable == null) {
47                     flowBasedEgressServicesRemovable = new FlowBasedEgressServicesConfigUnbindHelper(interfaceMgrProvider);
48                 }
49             }
50         }
51     }
52
53     public static FlowBasedServicesConfigRemovable getFlowBasedEgressServicesRemoveHelper() {
54         if (flowBasedEgressServicesRemovable == null) {
55             LOG.error("FlowBasedIngressBindHelper`` is not initialized");
56         }
57         return flowBasedEgressServicesRemovable;
58     }
59
60     public List<ListenableFuture<Void>> unbindService(InstanceIdentifier<BoundServices> instanceIdentifier,
61                                                              BoundServices boundServiceOld) {
62         List<ListenableFuture<Void>> futures = new ArrayList<>();
63         DataBroker dataBroker = interfaceMgrProvider.getDataBroker();
64         String interfaceName =
65                 InstanceIdentifier.keyOf(instanceIdentifier.firstIdentifierOf(ServicesInfo.class)).getInterfaceName();
66         Class<? extends ServiceModeBase> serviceMode = InstanceIdentifier.keyOf(instanceIdentifier.firstIdentifierOf(ServicesInfo.class)).getServiceMode();
67
68         // Get the Parent ServiceInfo
69         ServicesInfo servicesInfo = FlowBasedServicesUtils.getServicesInfoForInterface(interfaceName, serviceMode, dataBroker);
70         if (servicesInfo == null) {
71             LOG.error("Reached Impossible part in the code for bound service: {}", boundServiceOld);
72             return futures;
73         }
74
75         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifState =
76                 InterfaceManagerCommonUtils.getInterfaceStateFromOperDS(interfaceName, dataBroker);
77         if (ifState == null || ifState.getOperStatus() == OperStatus.Down) {
78             LOG.info("Not unbinding Service since operstatus is DOWN for Interface: {}", interfaceName);
79             return futures;
80         }
81         List<BoundServices> boundServices = servicesInfo.getBoundServices();
82
83         // Split based on type of interface....
84         if (ifState.getType().isAssignableFrom(L2vlan.class)) {
85             return unbindServiceOnVlan(boundServiceOld, boundServices, ifState, dataBroker);
86         } else if (ifState.getType().isAssignableFrom(Tunnel.class)) {
87             return unbindServiceOnTunnel(boundServiceOld, boundServices, ifState, dataBroker);
88         }
89         return futures;
90     }
91
92     private static List<ListenableFuture<Void>> unbindServiceOnVlan(
93             BoundServices boundServiceOld,
94             List<BoundServices> boundServices, org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifaceState,
95             DataBroker dataBroker) {
96
97         List<ListenableFuture<Void>> futures = new ArrayList<>();
98         WriteTransaction t = dataBroker.newWriteOnlyTransaction();
99         BigInteger dpId = FlowBasedServicesUtils.getDpnIdFromInterface(ifaceState);
100         if (boundServices.isEmpty()) {
101             // Remove default entry from Lport Dispatcher Table.
102             FlowBasedServicesUtils.removeEgressDispatcherFlow(dpId, ifaceState.getName(), boundServiceOld, t, NwConstants.DEFAULT_SERVICE_INDEX);
103             if (t != null) {
104                 futures.add(t.submit());
105             }
106             return futures;
107         }
108         BoundServices[] highLow = FlowBasedServicesUtils.getHighAndLowPriorityService(boundServices, boundServiceOld);
109         BoundServices low = highLow[0];
110         BoundServices high = highLow[1];
111         // This means the one removed was the highest priority service
112         if (high == null) {
113             FlowBasedServicesUtils.removeEgressDispatcherFlow(dpId, ifaceState.getName(), boundServiceOld, t, NwConstants.DEFAULT_SERVICE_INDEX);
114             if (low != null) {
115                 //delete the lower services flow entry.
116                 FlowBasedServicesUtils.removeEgressDispatcherFlow(dpId, ifaceState.getName(), low, t, low.getServicePriority());
117                 BoundServices lower = FlowBasedServicesUtils.getHighAndLowPriorityService(boundServices, low)[0];
118                 short lowerServiceIndex = (short) ((lower!=null) ? lower.getServicePriority() : low.getServicePriority() + 1);
119                 FlowBasedServicesUtils.installEgressDispatcherFlow(dpId, low, ifaceState.getName(), t, ifaceState.getIfIndex(), NwConstants.DEFAULT_SERVICE_INDEX, lowerServiceIndex);
120             }
121         } else {
122             FlowBasedServicesUtils.removeEgressDispatcherFlow(dpId, ifaceState.getName(), boundServiceOld, t, boundServiceOld.getServicePriority());
123             short lowerServiceIndex = (short) ((low!=null) ? low.getServicePriority() : boundServiceOld.getServicePriority() + 1);
124             BoundServices highest = FlowBasedServicesUtils.getHighestPriorityService(boundServices);
125             if (high.equals(highest)) {
126                 FlowBasedServicesUtils.installEgressDispatcherFlow(dpId, high, ifaceState.getName(),t, ifaceState.getIfIndex(), NwConstants.DEFAULT_SERVICE_INDEX, lowerServiceIndex);
127             } else {
128                 FlowBasedServicesUtils.installEgressDispatcherFlow(dpId, high, ifaceState.getName(),t, ifaceState.getIfIndex(), high.getServicePriority(), lowerServiceIndex);
129             }
130         }
131         futures.add(t.submit());
132         return futures;
133     }
134
135     private static List<ListenableFuture<Void>> unbindServiceOnTunnel(
136             BoundServices boundServiceOld,
137             List<BoundServices> boundServices, org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifState,
138             DataBroker dataBroker) {
139         List<ListenableFuture<Void>> futures = new ArrayList<>();
140
141         // FIXME : not yet supported
142         return futures;
143     }
144 }