2 * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
8 package org.opendaylight.genius.interfacemanager.servicebindings.flowbased.config.helpers;
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;
33 import java.math.BigInteger;
34 import java.util.ArrayList;
35 import java.util.List;
37 import java.util.concurrent.ConcurrentHashMap;
39 public class FlowBasedIngressServicesConfigBindHelper implements FlowBasedServicesConfigAddable {
40 private static final Logger LOG = LoggerFactory.getLogger(FlowBasedIngressServicesConfigBindHelper.class);
42 private InterfacemgrProvider interfaceMgrProvider;
43 private static volatile FlowBasedServicesConfigAddable flowBasedIngressServicesAddable;
45 private FlowBasedIngressServicesConfigBindHelper(InterfacemgrProvider interfaceMgrProvider) {
46 this.interfaceMgrProvider = interfaceMgrProvider;
49 public static void intitializeFlowBasedIngressServicesConfigAddHelper(InterfacemgrProvider interfaceMgrProvider) {
50 if (flowBasedIngressServicesAddable == null) {
51 synchronized (FlowBasedIngressServicesConfigBindHelper.class) {
52 if (flowBasedIngressServicesAddable == null) {
53 flowBasedIngressServicesAddable = new FlowBasedIngressServicesConfigBindHelper(interfaceMgrProvider);
59 public static void clearFlowBasedIngressServicesConfigAddHelper() {
60 flowBasedIngressServicesAddable = null;
63 public static FlowBasedServicesConfigAddable getFlowBasedIngressServicesAddHelper() {
64 if (flowBasedIngressServicesAddable == null) {
65 LOG.error("OvsInterfaceConfigAdd Renderer is not initialized");
67 return flowBasedIngressServicesAddable;
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();
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);
85 // Get the Parent ServiceInfo
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);
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);
98 if(ifState.getType() == null) {
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);
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 = new BigInteger(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());
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;
138 if (!boundService.equals(boundServiceNew)) {
139 tmpServicesMap.put(boundService.getServicePriority(), boundService);
140 if (boundService.getServicePriority() < highestPriority) {
141 highestPriority = boundService.getServicePriority();
146 if (!isCurrentServiceHighestPriority) {
147 FlowBasedServicesUtils.installLPortDispatcherFlow(dpId, boundServiceNew, ifState.getName(), transaction,
148 ifState.getIfIndex(), boundServiceNew.getServicePriority(), (short) (boundServiceNew.getServicePriority()+1));
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);
156 if (matches != null) {
158 WriteTransaction removeFlowTransaction = dataBroker.newWriteOnlyTransaction();
159 FlowBasedServicesUtils.removeIngressFlow(iface.getName(), serviceToReplace, dpId, removeFlowTransaction);
160 futures.add(removeFlowTransaction.submit());
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());
169 if (transaction != null) {
170 futures.add(transaction.submit());
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());
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
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);
206 currentServiceIndex = boundServiceNew.getServicePriority();
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);
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);
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());