Use plain @Nullable
[genius.git] / interfacemanager / interfacemanager-impl / src / main / java / org / opendaylight / genius / interfacemanager / servicebindings / flowbased / config / helpers / FlowBasedIngressServicesConfigBindHelper.java
1 /*
2  * Copyright (c) 2016, 2017 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 static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
11
12 import com.google.common.util.concurrent.ListenableFuture;
13 import java.math.BigInteger;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.concurrent.ConcurrentHashMap;
17 import javax.inject.Inject;
18 import javax.inject.Singleton;
19 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
20 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
21 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
22 import org.opendaylight.genius.interfacemanager.commons.InterfaceManagerCommonUtils;
23 import org.opendaylight.genius.interfacemanager.servicebindings.flowbased.utilities.FlowBasedServicesUtils;
24 import org.opendaylight.genius.mdsalutil.MatchInfo;
25 import org.opendaylight.genius.mdsalutil.NwConstants;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.L2vlan;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.bound.services.state.list.BoundServicesState;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34 @Singleton
35 public class FlowBasedIngressServicesConfigBindHelper extends AbstractFlowBasedServicesConfigBindHelper {
36
37     private static final Logger LOG = LoggerFactory.getLogger(FlowBasedIngressServicesConfigBindHelper.class);
38
39     private final ManagedNewTransactionRunner txRunner;
40     private final InterfaceManagerCommonUtils interfaceManagerCommonUtils;
41
42     @Inject
43     public FlowBasedIngressServicesConfigBindHelper(final DataBroker dataBroker,
44             final InterfaceManagerCommonUtils interfaceManagerCommonUtils) {
45         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
46         this.interfaceManagerCommonUtils = interfaceManagerCommonUtils;
47     }
48
49     @Override
50     protected void bindServiceOnInterface(List<ListenableFuture<Void>> futures,BoundServices boundServiceNew,
51                                           List<BoundServices> allServices, BoundServicesState boundServiceState) {
52         if (allServices.isEmpty()) {
53             LOG.error("Reached Impossible part 1 in the code during bind service for: {}", boundServiceNew);
54             return;
55         }
56         // Split based on type of interface...
57         if (L2vlan.class.equals(boundServiceState.getInterfaceType())) {
58             bindServiceOnVlan(futures, boundServiceNew, allServices, boundServiceState);
59         } else if (Tunnel.class.equals(boundServiceState.getInterfaceType())) {
60             bindServiceOnTunnel(futures, boundServiceNew, allServices, boundServiceState);
61         }
62     }
63
64     private void bindServiceOnTunnel(List<ListenableFuture<Void>> futures, BoundServices boundServiceNew,
65                                      List<BoundServices> allServices, BoundServicesState boundServiceState) {
66         long portNo = boundServiceState.getPortNo();
67         BigInteger dpId = boundServiceState.getDpid();
68         LOG.info("binding ingress service {} for tunnel port: {}", boundServiceNew.getServiceName(),
69                 boundServiceState.getInterfaceName());
70         futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
71             Interface iface =
72                     interfaceManagerCommonUtils.getInterfaceFromConfigDS(boundServiceState.getInterfaceName());
73             if (allServices.size() == 1) {
74                 // If only one service present, install instructions in table 0.
75                 List<MatchInfo> matches =  FlowBasedServicesUtils.getMatchInfoForTunnelPortAtIngressTable(dpId, portNo);
76                 FlowBasedServicesUtils.installInterfaceIngressFlow(dpId, iface, boundServiceNew, tx, matches,
77                         boundServiceState.getIfIndex(), NwConstants.VLAN_INTERFACE_INGRESS_TABLE);
78                 return;
79             }
80
81             boolean isCurrentServiceHighestPriority = true;
82             Map<Short, BoundServices> tmpServicesMap = new ConcurrentHashMap<>();
83             short highestPriority = 0xFF;
84             for (BoundServices boundService : allServices) {
85                 if (boundService.getServicePriority() < boundServiceNew.getServicePriority()) {
86                     isCurrentServiceHighestPriority = false;
87                     break;
88                 }
89                 if (!boundService.equals(boundServiceNew)) {
90                     tmpServicesMap.put(boundService.getServicePriority(), boundService);
91                     if (boundService.getServicePriority() < highestPriority) {
92                         highestPriority = boundService.getServicePriority();
93                     }
94                 }
95             }
96
97             if (!isCurrentServiceHighestPriority) {
98                 FlowBasedServicesUtils.installLPortDispatcherFlow(dpId, boundServiceNew,
99                         boundServiceState.getInterfaceName(), tx, boundServiceState.getIfIndex(),
100                         boundServiceNew.getServicePriority(), (short) (boundServiceNew.getServicePriority() + 1));
101             } else {
102                 BoundServices serviceToReplace = tmpServicesMap.get(highestPriority);
103                 FlowBasedServicesUtils.installLPortDispatcherFlow(dpId, serviceToReplace,
104                         boundServiceState.getInterfaceName(), tx, boundServiceState.getIfIndex(),
105                         serviceToReplace.getServicePriority(), (short) (serviceToReplace.getServicePriority() + 1));
106                 List<MatchInfo> matches = FlowBasedServicesUtils.getMatchInfoForTunnelPortAtIngressTable(dpId, portNo);
107
108                 // Separate transactions to remove and install flows
109                 // TODO skitt Should these be sequential?
110                 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
111                     removeFlowTx -> FlowBasedServicesUtils.removeIngressFlow(iface.getName(), serviceToReplace,
112                             dpId, removeFlowTx)));
113                 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
114                     installFlowTransaction -> FlowBasedServicesUtils.installInterfaceIngressFlow(dpId, iface,
115                             boundServiceNew, installFlowTransaction, matches, boundServiceState.getIfIndex(),
116                             NwConstants.VLAN_INTERFACE_INGRESS_TABLE)));
117             }
118         }));
119     }
120
121     private void bindServiceOnVlan(List<ListenableFuture<Void>> futures, BoundServices boundServiceNew,
122                                    List<BoundServices> allServices, BoundServicesState boundServiceState) {
123         BigInteger dpId = boundServiceState.getDpid();
124         futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
125             LOG.info("binding ingress service {} for vlan port: {}", boundServiceNew.getServiceName(), boundServiceState
126                     .getInterfaceName());
127             if (allServices.size() == 1) {
128                 // calling LportDispatcherTableForService with current service index
129                 // as 0 and next service index as some value since this is the only
130                 // service bound.
131                 FlowBasedServicesUtils.installLPortDispatcherFlow(dpId, boundServiceNew,
132                         boundServiceState.getInterfaceName(), tx, boundServiceState.getIfIndex(),
133                         NwConstants.DEFAULT_SERVICE_INDEX, (short) (boundServiceNew.getServicePriority() + 1));
134                 return;
135             }
136             allServices.remove(boundServiceNew);
137             BoundServices[] highLowPriorityService = FlowBasedServicesUtils.getHighAndLowPriorityService(allServices,
138                     boundServiceNew);
139             BoundServices low = highLowPriorityService[0];
140             BoundServices high = highLowPriorityService[1];
141             BoundServices highest = FlowBasedServicesUtils.getHighestPriorityService(allServices);
142             short currentServiceIndex = NwConstants.DEFAULT_SERVICE_INDEX;
143             short nextServiceIndex = (short) (boundServiceNew.getServicePriority() + 1); // dummy
144             // service
145             // index
146             if (low != null) {
147                 nextServiceIndex = low.getServicePriority();
148                 if (low.equals(highest)) {
149                     // In this case the match criteria of existing service should be
150                     // changed.
151                     BoundServices lower = FlowBasedServicesUtils.getHighAndLowPriorityService(allServices, low)[0];
152                     short lowerServiceIndex = (short) (lower != null ? lower.getServicePriority()
153                             : low.getServicePriority() + 1);
154                     LOG.trace("Installing ingress dispatcher table entry for existing service {} service match on "
155                                     + "service index {} update with service index {}",
156                             low, low.getServicePriority(), lowerServiceIndex);
157                     FlowBasedServicesUtils.installLPortDispatcherFlow(dpId, low, boundServiceState.getInterfaceName(),
158                             tx, boundServiceState.getIfIndex(), low.getServicePriority(), lowerServiceIndex);
159                 } else {
160                     currentServiceIndex = boundServiceNew.getServicePriority();
161                 }
162             }
163             if (high != null) {
164                 currentServiceIndex = boundServiceNew.getServicePriority();
165                 if (high.equals(highest)) {
166                     LOG.trace("Installing ingress dispatcher table entry for existing service {} service match on "
167                                     + "service index {} update with service index {}",
168                             high, NwConstants.DEFAULT_SERVICE_INDEX, currentServiceIndex);
169                     FlowBasedServicesUtils.installLPortDispatcherFlow(dpId, high, boundServiceState.getInterfaceName(),
170                             tx, boundServiceState.getIfIndex(), NwConstants.DEFAULT_SERVICE_INDEX,
171                             currentServiceIndex);
172                 } else {
173                     LOG.trace("Installing ingress dispatcher table entry for existing service {} service match on "
174                                     + "service index {} update with service index {}",
175                             high, high.getServicePriority(), currentServiceIndex);
176                     FlowBasedServicesUtils.installLPortDispatcherFlow(dpId, high, boundServiceState.getInterfaceName(),
177                             tx, boundServiceState.getIfIndex(), high.getServicePriority(), currentServiceIndex);
178                 }
179             }
180             LOG.trace("Installing ingress dispatcher table entry for new service match on service index {} update with "
181                     + "service index {}", currentServiceIndex, nextServiceIndex);
182             FlowBasedServicesUtils.installLPortDispatcherFlow(dpId, boundServiceNew,
183                     boundServiceState.getInterfaceName(), tx, boundServiceState.getIfIndex(), currentServiceIndex,
184                     nextServiceIndex);
185         }));
186     }
187
188     @Override
189     protected void bindServiceOnInterfaceType(List<ListenableFuture<Void>> futures, BoundServices boundServiceNew,
190                                               List<BoundServices> allServices) {
191         LOG.info("Interface Type based ingress service binding - WIP");
192     }
193 }