Merge "Adding the Add/Remove ExternalEndpoint commands."
[genius.git] / interfacemanager / interfacemanager-impl / src / main / java / org / opendaylight / genius / interfacemanager / servicebindings / flowbased / config / helpers / FlowBasedIngressServicesConfigBindHelper.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.IfmUtil;
15 import org.opendaylight.genius.interfacemanager.InterfacemgrProvider;
16 import org.opendaylight.genius.interfacemanager.commons.InterfaceManagerCommonUtils;
17 import org.opendaylight.genius.interfacemanager.servicebindings.flowbased.config.factory.FlowBasedServicesConfigAddable;
18 import org.opendaylight.genius.interfacemanager.servicebindings.flowbased.utilities.FlowBasedServicesUtils;
19 import org.opendaylight.genius.mdsalutil.MatchInfo;
20 import org.opendaylight.genius.mdsalutil.NwConstants;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.L2vlan;
22 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeBase;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfo;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
29 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 import java.math.BigInteger;
34 import java.util.ArrayList;
35 import java.util.List;
36 import java.util.Map;
37 import java.util.concurrent.ConcurrentHashMap;
38
39 public class FlowBasedIngressServicesConfigBindHelper implements FlowBasedServicesConfigAddable {
40     private static final Logger LOG = LoggerFactory.getLogger(FlowBasedIngressServicesConfigBindHelper.class);
41
42     private InterfacemgrProvider interfaceMgrProvider;
43     private static volatile FlowBasedServicesConfigAddable flowBasedIngressServicesAddable;
44
45     private FlowBasedIngressServicesConfigBindHelper(InterfacemgrProvider interfaceMgrProvider) {
46         this.interfaceMgrProvider = interfaceMgrProvider;
47     }
48
49     public static void intitializeFlowBasedIngressServicesConfigAddHelper(InterfacemgrProvider interfaceMgrProvider) {
50         if (flowBasedIngressServicesAddable == null) {
51             synchronized (FlowBasedIngressServicesConfigBindHelper.class) {
52                 if (flowBasedIngressServicesAddable == null) {
53                     flowBasedIngressServicesAddable = new FlowBasedIngressServicesConfigBindHelper(interfaceMgrProvider);
54                 }
55             }
56         }
57     }
58
59     public static void clearFlowBasedIngressServicesConfigAddHelper() {
60         flowBasedIngressServicesAddable = null;
61     }
62
63     public static FlowBasedServicesConfigAddable getFlowBasedIngressServicesAddHelper() {
64         if (flowBasedIngressServicesAddable == null) {
65             LOG.error("OvsInterfaceConfigAdd Renderer is not initialized");
66         }
67         return flowBasedIngressServicesAddable;
68     }
69
70     public List<ListenableFuture<Void>> bindService(InstanceIdentifier<BoundServices> instanceIdentifier,
71                                                            BoundServices boundServiceNew) {
72         List<ListenableFuture<Void>> futures = new ArrayList<>();
73         DataBroker dataBroker = interfaceMgrProvider.getDataBroker();
74         String interfaceName =
75                 InstanceIdentifier.keyOf(instanceIdentifier.firstIdentifierOf(ServicesInfo.class)).getInterfaceName();
76         Class<? extends ServiceModeBase> serviceMode = InstanceIdentifier.keyOf(instanceIdentifier.firstIdentifierOf(ServicesInfo.class)).getServiceMode();
77
78         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifState =
79                 InterfaceManagerCommonUtils.getInterfaceStateFromOperDS(interfaceName, dataBroker);
80         if (ifState == null || ifState.getOperStatus() == OperStatus.Down) {
81             LOG.warn("Interface not up, not Binding Service for Interface: {}", interfaceName);
82             return futures;
83         }
84
85         // Get the Parent ServiceInfo
86
87         ServicesInfo servicesInfo = FlowBasedServicesUtils.getServicesInfoForInterface(interfaceName, serviceMode, dataBroker);
88         if (servicesInfo == null) {
89             LOG.error("Reached Impossible part 1 in the code during bind service for: {}", boundServiceNew);
90             return futures;
91         }
92
93         List<BoundServices> allServices = servicesInfo.getBoundServices();
94         if (allServices.isEmpty()) {
95             LOG.error("Reached Impossible part 2 in the code during bind service for: {}", boundServiceNew);
96             return futures;
97         }
98         if(ifState.getType() == null) {
99             return futures;
100         }
101         // Split based on type of interface...
102         if (ifState.getType().isAssignableFrom(L2vlan.class)) {
103             return bindServiceOnVlan(boundServiceNew, allServices, ifState, dataBroker);
104         } else if (ifState.getType().isAssignableFrom(Tunnel.class)) {
105             return bindServiceOnTunnel(boundServiceNew, allServices, ifState, dataBroker);
106         }
107         return futures;
108     }
109
110     private static List<ListenableFuture<Void>> bindServiceOnTunnel(BoundServices boundServiceNew, List<BoundServices> allServices,
111                                                                     org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifState, DataBroker dataBroker) {
112         List<ListenableFuture<Void>> futures = new ArrayList<>();
113         NodeConnectorId nodeConnectorId = FlowBasedServicesUtils.getNodeConnectorIdFromInterface(ifState);
114         long portNo = Long.parseLong(IfmUtil.getPortNoFromNodeConnectorId(nodeConnectorId));
115         BigInteger dpId = IfmUtil.getDpnFromNodeConnectorId(nodeConnectorId);
116         WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();
117         Interface iface = InterfaceManagerCommonUtils.getInterfaceFromConfigDS(ifState.getName(), dataBroker);
118         if (allServices.size() == 1) {
119             // If only one service present, install instructions in table 0.
120             List<MatchInfo> matches = null;
121             matches = FlowBasedServicesUtils.getMatchInfoForTunnelPortAtIngressTable (dpId, portNo);
122             FlowBasedServicesUtils.installInterfaceIngressFlow(dpId, iface, boundServiceNew,
123                     transaction, matches, ifState.getIfIndex(), NwConstants.VLAN_INTERFACE_INGRESS_TABLE);
124             if (transaction != null) {
125                 futures.add(transaction.submit());
126             }
127             return futures;
128         }
129
130         boolean isCurrentServiceHighestPriority = true;
131         Map<Short, BoundServices> tmpServicesMap = new ConcurrentHashMap<>();
132         short highestPriority = 0xFF;
133         for (BoundServices boundService : allServices) {
134             if (boundService.getServicePriority() < boundServiceNew.getServicePriority()) {
135                 isCurrentServiceHighestPriority = false;
136                 break;
137             }
138             if (!boundService.equals(boundServiceNew)) {
139                 tmpServicesMap.put(boundService.getServicePriority(), boundService);
140                 if (boundService.getServicePriority() < highestPriority) {
141                     highestPriority = boundService.getServicePriority();
142                 }
143             }
144         }
145
146         if (!isCurrentServiceHighestPriority) {
147             FlowBasedServicesUtils.installLPortDispatcherFlow(dpId, boundServiceNew, ifState.getName(), transaction,
148                     ifState.getIfIndex(), boundServiceNew.getServicePriority(), (short) (boundServiceNew.getServicePriority()+1));
149         } else {
150             BoundServices serviceToReplace = tmpServicesMap.get(highestPriority);
151             FlowBasedServicesUtils.installLPortDispatcherFlow(dpId, serviceToReplace, ifState.getName(), transaction,
152                     ifState.getIfIndex(), boundServiceNew.getServicePriority(), (short) (boundServiceNew.getServicePriority()+1));
153             List<MatchInfo> matches = null;
154             matches = FlowBasedServicesUtils.getMatchInfoForTunnelPortAtIngressTable (dpId, portNo);
155
156             if (matches != null) {
157
158                 WriteTransaction removeFlowTransaction = dataBroker.newWriteOnlyTransaction();
159                 FlowBasedServicesUtils.removeIngressFlow(iface.getName(), serviceToReplace, dpId, removeFlowTransaction);
160                 futures.add(removeFlowTransaction.submit());
161
162                 WriteTransaction installFlowTransaction = dataBroker.newWriteOnlyTransaction();
163                 FlowBasedServicesUtils.installInterfaceIngressFlow(dpId, iface, boundServiceNew, installFlowTransaction,
164                         matches, ifState.getIfIndex(), NwConstants.VLAN_INTERFACE_INGRESS_TABLE);
165                 futures.add(installFlowTransaction.submit());
166             }
167         }
168
169         if (transaction != null) {
170             futures.add(transaction.submit());
171         }
172         return futures;
173     }
174
175     private static List<ListenableFuture<Void>> bindServiceOnVlan(BoundServices boundServiceNew, List<BoundServices> allServices,
176                                                                   org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifState, DataBroker dataBroker) {
177         List<ListenableFuture<Void>> futures = new ArrayList<>();
178         BigInteger dpId = FlowBasedServicesUtils.getDpnIdFromInterface(ifState);
179         WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();
180         LOG.info("binding service for vlan port: {}", ifState.getName());
181         if (allServices.size() == 1) {
182             //calling LportDispatcherTableForService with current service index as 0 and next service index as some value since this is the only service bound.
183             FlowBasedServicesUtils.installLPortDispatcherFlow(dpId, boundServiceNew, ifState.getName(),
184                     transaction, ifState.getIfIndex(), NwConstants.DEFAULT_SERVICE_INDEX,(short) (boundServiceNew.getServicePriority() + 1));
185             if (transaction != null) {
186                 futures.add(transaction.submit());
187             }
188             return futures;
189         }
190         allServices.remove(boundServiceNew);
191         BoundServices[] highLowPriorityService = FlowBasedServicesUtils.getHighAndLowPriorityService(allServices, boundServiceNew);
192         BoundServices low = highLowPriorityService[0];
193         BoundServices high = highLowPriorityService[1];
194         BoundServices highest = FlowBasedServicesUtils.getHighestPriorityService(allServices);
195         short currentServiceIndex = NwConstants.DEFAULT_SERVICE_INDEX;
196         short nextServiceIndex = (short) (boundServiceNew.getServicePriority() + 1); // dummy service index
197         if (low != null) {
198             nextServiceIndex = low.getServicePriority();
199             if (low.equals(highest)) {
200                 //In this case the match criteria of existing service should be changed.
201                 BoundServices lower = FlowBasedServicesUtils.getHighAndLowPriorityService(allServices, low)[0];
202                 short lowerServiceIndex = (short) ((lower!=null) ? lower.getServicePriority() : low.getServicePriority() + 1);
203                 LOG.trace("Installing table 17 entry for existing service {} service match on service index {} update with service index {}", low, low.getServicePriority(), lowerServiceIndex);
204                 FlowBasedServicesUtils.installLPortDispatcherFlow(dpId,low, ifState.getName(), transaction, ifState.getIfIndex(),low.getServicePriority(), lowerServiceIndex);
205             } else {
206                 currentServiceIndex = boundServiceNew.getServicePriority();
207             }
208         }
209         if (high != null) {
210             currentServiceIndex = boundServiceNew.getServicePriority();
211             if (high.equals(highest)) {
212                 LOG.trace("Installing table 17 entry for existing service {} service match on service index {} update with service index {}", high, NwConstants.DEFAULT_SERVICE_INDEX, currentServiceIndex);
213                 FlowBasedServicesUtils.installLPortDispatcherFlow(dpId, high, ifState.getName(), transaction, ifState.getIfIndex(), NwConstants.DEFAULT_SERVICE_INDEX, currentServiceIndex);
214             } else {
215                 LOG.trace("Installing table 17 entry for existing service {} service match on service index {} update with service index {}", high, high.getServicePriority(), currentServiceIndex);
216                 FlowBasedServicesUtils.installLPortDispatcherFlow(dpId, high, ifState.getName(), transaction, ifState.getIfIndex(), high.getServicePriority(), currentServiceIndex);
217             }
218         }
219         LOG.trace("Installing table 17 entry for new service match on service index {} update with service index {}", currentServiceIndex, nextServiceIndex);
220         FlowBasedServicesUtils.installLPortDispatcherFlow(dpId, boundServiceNew, ifState.getName(), transaction, ifState.getIfIndex(), currentServiceIndex, nextServiceIndex);
221         futures.add(transaction.submit());
222         return futures;
223     }
224 }