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