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