Optional clean-up
[netvirt.git] / vpnservice / cloud-servicechain / cloud-servicechain-impl / src / main / java / org / opendaylight / netvirt / cloudservicechain / ElanServiceChainHandler.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.netvirt.cloudservicechain;
9
10 import com.google.common.base.Optional;
11 import java.math.BigInteger;
12 import java.util.Collection;
13 import java.util.List;
14
15 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
16 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
17 import org.opendaylight.genius.mdsalutil.MDSALUtil;
18 import org.opendaylight.genius.mdsalutil.NWUtil;
19 import org.opendaylight.genius.mdsalutil.NwConstants;
20 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
21 import org.opendaylight.netvirt.cloudservicechain.utils.ElanServiceChainUtils;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.cloud.servicechain.state.rev170511.ElanServiceChainState;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.cloud.servicechain.state.rev170511.elan.to.pseudo.port.data.list.ElanToPseudoPortData;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceKey;
27
28 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
29
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 /**
34  * It is in charge of executing the changes in the Pipeline that are related to
35  * Elan Pseudo Ports when participating in ServiceChains.
36  *
37  */
38 public class ElanServiceChainHandler {
39
40     private static final Logger LOG = LoggerFactory.getLogger(ElanServiceChainHandler.class);
41
42     private final DataBroker broker;
43     private final IMdsalApiManager mdsalManager;
44
45
46     public ElanServiceChainHandler(final DataBroker db, final IMdsalApiManager mdsalMgr) {
47         this.broker = db;
48         this.mdsalManager = mdsalMgr;
49     }
50
51     /**
52      * Programs the needed flows for sending traffic to the SCF pipeline when
53      * it is comming from an L2-GW (ELAN) and also for handing over that
54      * traffic from SCF to ELAN when the packets does not match any Service
55      * Chain.
56      *
57      * @param elanName Name of the ELAN to be considered
58      * @param tableId Table id, in the SCF Pipeline, to which the traffic must
59      *        go to.
60      * @param scfTag Tag of the ServiceChain
61      * @param elanLportTag LPortTag of the ElanPseudoPort that participates in
62      *        the ServiceChain
63      * @param addOrRemove States if the flows must be created or removed
64      */
65     public void programElanScfPipeline(String elanName, short tableId, long scfTag, int elanLportTag, int addOrRemove) {
66         LOG.info("programElanScfPipeline:  elanName={}   scfTag={}   elanLportTag={}    addOrRemove={}",
67                  elanName, scfTag, elanLportTag, addOrRemove);
68         // There are 3 rules to be considered:
69         //  1. LportDispatcher To Scf. Matches on elanPseudoPort + SI=1. Goes to DL Subscriber table
70         //  2. LportDispatcher From Scf. Matches on elanPseudoPort + SI=3. Goes to ELAN DMAC
71         //  3. ExtTunnelTable From L2GwDevice. Matches on VNI + SI=1. Sets ElanPseudoPort tag and goes
72         //             to LportDispatcher table.
73         // And these rules must be programmed in all the Elan footprint
74
75         // Find the ElanInstance
76         Optional<ElanInstance> elanInstance = ElanServiceChainUtils.getElanInstanceByName(broker, elanName);
77         if ( !elanInstance.isPresent() ) {
78             LOG.debug("Could not find an Elan Instance with name={}", elanName);
79             return;
80         }
81
82         Collection<BigInteger> elanDpnsOpc = ElanServiceChainUtils.getElanDpnsByName(broker, elanName);
83         if (elanDpnsOpc.isEmpty()) {
84             LOG.debug("Could not find any DPN related to Elan {}", elanName);
85             return;
86         }
87
88         // updates map which stores relationship between elan and elanLPortTag and scfTag
89         ElanServiceChainUtils.updateElanToLportTagMap(broker, elanName, elanLportTag, scfTag, addOrRemove);
90
91         Long vni = elanInstance.get().getSegmentationId();
92         if ( vni == null ) {
93             LOG.warn("There is no VNI for elan {}. VNI is mandatory. Returning", elanName);
94             return;
95         }
96
97         int elanTag = elanInstance.get().getElanTag().intValue();
98         LOG.debug("elanName={}  ->  vni={}  elanTag={}", elanName, vni, elanTag);
99         // For each DPN in the Elan, do
100         //    Program LPortDispatcher to Scf
101         //    Program LPortDispatcher from Scf
102         //    Program ExtTunnelTable.
103         for (BigInteger dpnId : elanDpnsOpc) {
104             ElanServiceChainUtils.programLPortDispatcherToScf(mdsalManager, dpnId, elanTag, elanLportTag, tableId,
105                                                               scfTag, addOrRemove);
106             ElanServiceChainUtils.programLPortDispatcherFromScf(mdsalManager, dpnId, elanLportTag, elanTag,
107                                                                 addOrRemove);
108             ElanServiceChainUtils.programExternalTunnelTable(mdsalManager, dpnId, elanLportTag, vni, elanTag,
109                                                              addOrRemove);
110         }
111
112     }
113
114     public void removeElanPseudoPortFlows(String elanName, int elanLportTag) {
115         Optional<ElanServiceChainState> elanServiceChainState =
116             ElanServiceChainUtils.getElanServiceChainState(broker, elanName);
117         if (!elanServiceChainState.isPresent()) {
118             LOG.warn("Could not find ServiceChain state data for Elan {}, elanPseudoLportTag={}",
119                      elanName, elanLportTag);
120             return;
121         }
122         Optional<ElanInstance> elanInstance = ElanServiceChainUtils.getElanInstanceByName(broker, elanName);
123         if ( !elanInstance.isPresent() ) {
124             LOG.warn("Could not find ElanInstance for name {}", elanName);
125             return;
126         }
127
128         Long vni = elanInstance.get().getSegmentationId();
129         if (vni == null) {
130             LOG.warn("Elan {} is not related to a VNI. VNI is mandatory for ServiceChaining. Returning", elanName);
131             return;
132         }
133
134         List<ElanToPseudoPortData> elanToPseudoPortDataList = elanServiceChainState.get().getElanToPseudoPortData();
135         if ( elanToPseudoPortDataList == null || elanToPseudoPortDataList.isEmpty() ) {
136             LOG.info("Could not find elan {} with elanPseudoPort {} participating in any ServiceChain",
137                      elanName, elanLportTag);
138             return;
139         }
140
141         if ( elanInstance.get().getElanTag() == null ) {
142             LOG.info("Could not find elanTag for elan {} ", elanName);
143             return;
144         }
145
146         int elanTag = elanInstance.get().getElanTag().intValue();
147
148         List<BigInteger> operativeDPNs = NWUtil.getOperativeDPNs(broker);
149         for (ElanToPseudoPortData elanToPseudoPortData : elanToPseudoPortDataList) {
150             Long scfTag = elanToPseudoPortData.getScfTag();
151
152             for (BigInteger dpnId : operativeDPNs) {
153                 ElanServiceChainUtils.programLPortDispatcherToScf(mdsalManager, dpnId, elanTag, elanLportTag,
154                         CloudServiceChainConstants.SCF_DOWN_SUB_FILTER_TCP_BASED_TABLE,
155                         scfTag, NwConstants.DEL_FLOW);
156                 ElanServiceChainUtils.programLPortDispatcherFromScf(mdsalManager, dpnId, elanLportTag, elanTag,
157                                                                     NwConstants.DEL_FLOW);
158                 ElanServiceChainUtils.programExternalTunnelTable(mdsalManager, dpnId, elanLportTag, vni, elanTag,
159                                                                  NwConstants.DEL_FLOW);
160             }
161         }
162
163         // Lastly, remove the serviceChain-state for the Elan
164         InstanceIdentifier<ElanServiceChainState> path =
165             InstanceIdentifier.builder(ElanInstances.class).child(ElanInstance.class, new ElanInstanceKey(elanName))
166                               .augmentation(ElanServiceChainState.class)
167                               .build();
168
169         MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, path);
170     }
171
172 }