blob: edef00a7685e0c079e064a8add6860b140bc9958 [file] [log] [blame]
janani b9ed76be2017-08-29 19:11:33 +05301/*
2 * Copyright 2017-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onosproject.l3vpn.netl3vpn.impl;
18
19import org.onosproject.config.DynamicConfigService;
20import org.onosproject.core.IdGenerator;
21import org.onosproject.incubator.net.tunnel.Tunnel;
22import org.onosproject.l3vpn.netl3vpn.DeviceInfo;
23import org.onosproject.l3vpn.netl3vpn.ModelIdLevel;
24import org.onosproject.l3vpn.netl3vpn.NetL3VpnException;
25import org.onosproject.l3vpn.netl3vpn.NetL3VpnStore;
26import org.onosproject.l3vpn.netl3vpn.TunnelInfo;
27import org.onosproject.l3vpn.netl3vpn.VpnType;
28import org.onosproject.net.Device;
29import org.onosproject.net.DeviceId;
30import org.onosproject.net.device.DeviceService;
31import org.onosproject.net.driver.DriverService;
32import org.onosproject.pce.pceservice.api.PceService;
33import org.onosproject.yang.model.DataNode;
34import org.onosproject.yang.model.ModelConverter;
35import org.onosproject.yang.model.ModelObjectData;
36import org.onosproject.yang.model.ResourceData;
37
38import java.util.List;
39import java.util.Map;
40
41import static org.onosproject.l3vpn.netl3vpn.ModelIdLevel.DEVICE;
42import static org.onosproject.l3vpn.netl3vpn.ModelIdLevel.DEVICES;
43import static org.onosproject.l3vpn.netl3vpn.ModelIdLevel.TNL_M;
44import static org.onosproject.l3vpn.netl3vpn.ModelIdLevel.TNL_POL;
45import static org.onosproject.l3vpn.netl3vpn.ModelIdLevel.TP_HOP;
46import static org.onosproject.l3vpn.netl3vpn.VpnType.SPOKE;
47import static org.onosproject.l3vpn.netl3vpn.impl.NetL3VpnUtil.NEW_NAME;
48import static org.onosproject.l3vpn.netl3vpn.impl.NetL3VpnUtil.getId;
49import static org.onosproject.l3vpn.netl3vpn.impl.NetL3VpnUtil.getIpFromDevId;
50import static org.onosproject.pce.pceservice.LspType.WITH_SIGNALLING;
51
52/**
53 * Represents net l3VPN tunnel handler, which handles tunnel operations like
54 * creation and deletion and updating it to the driver.
55 */
56public class NetL3VpnTunnelHandler {
57
58 private PceService pceSvc;
59 private DriverService driSvc;
60 private DynamicConfigService configSvc;
61 private NetL3VpnStore store;
62 private DeviceService devSvc;
63 private IdGenerator tnlIdGen;
64 private ModelConverter modelCon;
65 private String sIp;
66 private String vpnName;
67 private DeviceInfo sInfo;
68 private VpnType type;
69
70 /**
71 * Constructs net l3VPN tunnel handler with required services.
72 *
73 * @param p pce service
74 * @param d driver service
75 * @param c dynamic config service
76 * @param s net l3VPN store
77 * @param dev device service
78 * @param id ID generator
79 * @param m model converter
80 */
81 public NetL3VpnTunnelHandler(PceService p, DriverService d,
82 DynamicConfigService c,
83 NetL3VpnStore s, DeviceService dev,
84 IdGenerator id, ModelConverter m) {
85 pceSvc = p;
86 driSvc = d;
87 configSvc = c;
88 store = s;
89 devSvc = dev;
90 tnlIdGen = id;
91 modelCon = m;
92 }
93
94 /**
95 * Creates the source information for tunnel creation. It creates from
96 * source device info and VPN name.
97 *
98 * @param vName VPN name
99 * @param devInfo device info
100 */
101 public void createSrcInfo(String vName, DeviceInfo devInfo) {
102 vpnName = vName;
103 sInfo = devInfo;
104 type = devInfo.type();
105 sIp = getIpFromDevId(sInfo.deviceId());
106 }
107
108 /**
109 * Creates tunnel between source and destination devices.
110 *
111 * @param dInfo destination device
112 */
113 public void createSrcDesTunnel(DeviceInfo dInfo) {
114 VpnType dType = dInfo.type();
115 if (type == SPOKE && dType == SPOKE) {
116 return;
117 }
118 String dIp = getIpFromDevId(dInfo.deviceId());
119 createTunnelInfo(sIp, dIp, sInfo);
120 createTunnelInfo(dIp, sIp, dInfo);
121 }
122
123 /**
124 * Creates tunnel info and tunnel based on source and destination ip
125 * address and configures it in the source device.
126 *
127 * @param sIp source ip address
128 * @param dIp destination ip address
129 * @param sInfo source device info
130 */
131 private void createTunnelInfo(String sIp, String dIp, DeviceInfo sInfo) {
132 DeviceId id = sInfo.deviceId();
133 Map<DeviceId, Integer> tnlMap = store.getTunnelInfo();
134 int count = 0;
135 if (tnlMap.containsKey(id)) {
136 count = tnlMap.get(id);
137 }
138 String tnlName = createTunnel(sIp, dIp);
139 sInfo.addTnlName(tnlName);
140 store.addTunnelInfo(id, count + 1);
141 TunnelInfo tnl = new TunnelInfo(dIp, tnlName, vpnName, id.toString());
142 configureDevTnl(sInfo, tnl, tnlMap);
143 }
144
145 /**
146 * Creates tunnel between source ip address and destination ip address
147 * with pce service.
148 *
149 * @param srcIp source ip address
150 * @param desIp destination ip address
151 * @return tunnel name
152 */
153 private String createTunnel(String srcIp, String desIp) {
154 Iterable<Device> devices = devSvc.getAvailableDevices();
155 DeviceId srcDevId = getId(srcIp, false, devices);
156 DeviceId desDevId = getId(desIp, false, devices);
157 String name = getNewName();
158 boolean isCreated = pceSvc.setupPath(srcDevId, desDevId, name,
159 null, WITH_SIGNALLING);
160 if (!isCreated) {
161 throw new NetL3VpnException("Tunnel is not created between " +
162 srcDevId.toString() + " and " +
163 desDevId.toString());
164 }
165 return name;
166 }
167
168 /**
169 * Returns a unique name for tunnel to be created.
170 *
171 * @return unique tunnel name
172 */
173 private String getNewName() {
174 return NEW_NAME + String.valueOf(tnlIdGen.getNewId());
175 }
176
177 /**
178 * Configures the created tunnel to the device by processing it at the
179 * proper level and sending it to the driver.
180 *
181 * @param info source device info
182 * @param tnlInfo tunnel info
183 * @param tnlMap store tunnel map
184 */
185 private void configureDevTnl(DeviceInfo info, TunnelInfo tnlInfo,
186 Map<DeviceId, Integer> tnlMap) {
187 DeviceId id = info.deviceId();
188 int count = 0;
189 if (tnlMap.containsKey(id)) {
190 count = tnlMap.get(id);
191 }
192 if (tnlMap.size() == 0) {
193 tnlInfo.level(DEVICES);
194 } else if (count == 0) {
195 tnlInfo.level(DEVICE);
196 }
197
198 if (tnlInfo.level() != null) {
199 ModelObjectData mod = info.processCreateTnlDev(driSvc, tnlInfo);
200 addDataNodeToStore(mod);
201 tnlInfo.level(TNL_M);
202 tnlPolToStore(info, tnlInfo);
203 }
204 if (!info.isTnlPolCreated()) {
205 tnlInfo.level(TNL_POL);
206 tnlPolToStore(info, tnlInfo);
207 }
208 if (tnlInfo.level() == null) {
209 tnlInfo.level(TP_HOP);
210 }
211
212 ModelObjectData tnlMod = info.processCreateTnl(driSvc, tnlInfo);
213 addDataNodeToStore(tnlMod);
214 if (tnlInfo.level() != TP_HOP) {
215 ModelObjectData mod = info.processBindTnl(driSvc, tnlInfo);
216 addDataNodeToStore(mod);
217 }
218 }
219
220 /**
221 * Adds data node to the store after converting it to the resource data.
222 *
223 * @param driMod driver model object data
224 */
225 private void addDataNodeToStore(ModelObjectData driMod) {
226 ResourceData resData = modelCon.createDataNode(driMod);
227 addToStore(resData);
228 }
229
230 /**
231 * Adds resource data to the store.
232 *
233 * @param resData resource data
234 */
235 private void addToStore(ResourceData resData) {
236 if (resData != null && resData.dataNodes() != null) {
237 List<DataNode> dataNodes = resData.dataNodes();
238 for (DataNode node : dataNodes) {
239 configSvc.createNode(resData.resourceId(), node);
240 }
241 }
242 }
243
244 /**
245 * Creates tunnel policy from driver and adds it to the store.
246 *
247 * @param info device info
248 * @param tnlInfo tunnel info
249 */
250 private void tnlPolToStore(DeviceInfo info, TunnelInfo tnlInfo) {
251 ModelObjectData mod = info.processCreateTnlPol(driSvc, tnlInfo);
252 addDataNodeToStore(mod);
253 info.setTnlPolCreated(true);
254 }
255
256 /**
257 * Deletes the tunnel with the source tunnel info and VPN name.
258 * //FIXME: PCE does'nt have api, which can give tunnel by providing the
259 * tunnel name.
260 *
261 * @param info device info
262 * @param vName VPN name
263 */
264 public void deleteTunnel(DeviceInfo info, String vName) {
265 List<String> tnlNames = info.tnlNames();
266 for (String tnlName : tnlNames) {
267 Iterable<Tunnel> path = pceSvc.queryAllPath();
268 for (Tunnel tnl : path) {
269 if (tnl.tunnelName().toString().equals(tnlName)) {
270 pceSvc.releasePath(tnl.tunnelId());
271 break;
272 }
273 }
274 }
275 deleteFromDevice(info, vName);
276 }
277
278 /**
279 * Deletes tunnel configuration from the device by updating various
280 * levels in the store.
281 *
282 * @param info device info
283 * @param vName VPN name
284 */
285 private void deleteFromDevice(DeviceInfo info, String vName) {
286 Map<DeviceId, Integer> map = store.getTunnelInfo();
287 DeviceId id = info.deviceId();
288 Integer count = map.get(id);
289 int tnlCount = info.tnlNames().size();
290 int upCount = count - tnlCount;
291 ModelIdLevel level;
292 TunnelInfo tnlInfo = new TunnelInfo(null, null, vName, id.toString());
293 if (upCount == 0) {
294 if (map.size() == 1) {
295 level = DEVICES;
296 } else {
297 level = DEVICE;
298 }
299 } else {
300 if (map.size() > 1) {
301 level = TNL_POL;
302 } else {
303 return;
304 }
305 }
306 tnlInfo.level(level);
307 ModelObjectData mod = info.processDeleteTnl(driSvc, tnlInfo);
308 deleteFromStore(mod);
309 info.tnlNames(null);
310 info.setTnlPolCreated(false);
311 if (upCount == 0) {
312 store.removeTunnelInfo(id);
313 } else {
314 store.addTunnelInfo(id, upCount);
315 }
316 }
317
318 /**
319 * Deletes the data node from the store.
320 *
321 * @param mod driver model object data
322 */
323 private void deleteFromStore(ModelObjectData mod) {
324 ResourceData resData = modelCon.createDataNode(mod);
325 if (resData != null) {
326 configSvc.deleteNode(resData.resourceId());
327 }
328 }
329}