2 * Copyright (c) 2016, 2017 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
8 package org.opendaylight.genius.itm.confighelpers;
10 import com.google.common.util.concurrent.ListenableFuture;
11 import java.math.BigInteger;
12 import java.util.ArrayList;
13 import java.util.Collections;
14 import java.util.List;
15 import java.util.Objects;
16 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
17 import org.opendaylight.genius.infra.Datastore;
18 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
19 import org.opendaylight.genius.infra.TypedWriteTransaction;
20 import org.opendaylight.genius.itm.globals.ITMConstants;
21 import org.opendaylight.genius.itm.impl.ItmUtils;
22 import org.opendaylight.genius.mdsalutil.MDSALUtil;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressBuilder;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.NotHostedTransportZones;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.TransportZones;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.not.hosted.transport.zones.TepsInNotHostedTransportZone;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.not.hosted.transport.zones.TepsInNotHostedTransportZoneBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.not.hosted.transport.zones.TepsInNotHostedTransportZoneKey;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.not.hosted.transport.zones.tepsinnothostedtransportzone.UnknownVteps;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.not.hosted.transport.zones.tepsinnothostedtransportzone.UnknownVtepsBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.not.hosted.transport.zones.tepsinnothostedtransportzone.UnknownVtepsKey;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.TransportZone;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.TransportZoneBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.TransportZoneKey;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.Subnets;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.SubnetsBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.SubnetsKey;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.subnets.Vteps;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.subnets.VtepsBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.subnets.VtepsKey;
43 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
47 public final class OvsdbTepAddConfigHelper {
49 private static final Logger LOG = LoggerFactory.getLogger(OvsdbTepAddConfigHelper.class);
51 private OvsdbTepAddConfigHelper() { }
54 * Adds the TEP into ITM configuration/operational Datastore in one of the following cases.
55 * 1) default transport zone
56 * 2) Configured transport zone
57 * 3) Unhosted transport zone
59 * @param tepIp TEP-IP address in string
60 * @param strDpnId bridge datapath ID in string
61 * @param tzName transport zone name in string
62 * @param ofTunnel boolean flag for TEP to enable/disable of-tunnel feature on it
63 * @param dataBroker data broker handle to perform operations on config/operational datastore
64 * @param txRunner ManagedTransactionRunner object
67 public static List<ListenableFuture<Void>> addTepReceivedFromOvsdb(String tepIp, String strDpnId, String tzName,
68 boolean ofTunnel, DataBroker dataBroker, ManagedNewTransactionRunner txRunner) {
69 List<ListenableFuture<Void>> futures = new ArrayList<>();
70 BigInteger dpnId = BigInteger.valueOf(0);
72 if (strDpnId != null && !strDpnId.isEmpty()) {
73 dpnId = MDSALUtil.getDpnId(strDpnId);
77 IpAddress tepIpAddress = IpAddressBuilder.getDefaultInstance(tepIp);
78 TransportZone tzone = null;
80 // Case: TZ name is not given with OVS TEP.
82 tzName = ITMConstants.DEFAULT_TRANSPORT_ZONE;
83 // add TEP into default-TZ
84 tzone = ItmUtils.getTransportZoneFromConfigDS(tzName, dataBroker);
86 // Case: default-TZ is not yet created, then add TEP into "teps-in-not-hosted-transport-zone"
87 LOG.trace("Adding TEP with default TZ into teps-in-not-hosted-transport-zone.");
88 return addUnknownTzTepIntoTepsNotHostedAndReturnFutures(tzName, tepIpAddress, dpnId, ofTunnel,
89 dataBroker, txRunner);
91 LOG.trace("Add TEP into default-transport-zone.");
93 // Case: Add TEP into corresponding TZ created from Northbound.
94 tzone = ItmUtils.getTransportZoneFromConfigDS(tzName, dataBroker);
96 // Case: TZ is not configured from Northbound, then add TEP into "teps-in-not-hosted-transport-zone"
97 LOG.trace("Adding TEP with unknown TZ into teps-in-not-hosted-transport-zone.");
98 return addUnknownTzTepIntoTepsNotHostedAndReturnFutures(tzName, tepIpAddress, dpnId, ofTunnel,
99 dataBroker, txRunner);
101 LOG.trace("Add TEP into transport-zone already configured by Northbound.");
105 // Get subnet list of corresponding TZ created from Northbound.
106 final List<Subnets> subnetList = tzone.getSubnets();
107 final BigInteger id = dpnId;
108 final String name = tzName;
109 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(Datastore.CONFIGURATION,
110 tx -> addConfig(subnetList, name, id, tepIpAddress, ofTunnel, tx)));
115 * Adds the TEP into Vtep list in the subnet list in the transport zone list
116 * from ITM configuration Datastore by merge operation with write transaction.
118 * @param subnetList subnets list object
119 * @param subnetMaskObj subnet mask in IpPrefix object
120 * @param updatedVtepList updated Vteps list object which will have new TEP for addition
121 * @param tepIpAddress TEP IP address in IpAddress object
122 * @param tzName transport zone name in string
123 * @param dpid bridge datapath ID in BigInteger
124 * @param portName port name as a part of VtepsKey
125 * @param ofTunnel boolean flag for TEP to enable/disable of-tunnel feature on it
126 * @param tx TypedWriteTransaction object
128 public static void addVtepInITMConfigDS(List<Subnets> subnetList, IpPrefix subnetMaskObj,
129 List<Vteps> updatedVtepList, IpAddress tepIpAddress, String tzName, BigInteger dpid,
130 String portName, boolean ofTunnel, TypedWriteTransaction<Datastore.Configuration> tx) {
131 //Create TZ node path
132 InstanceIdentifier<TransportZone> tranzportZonePath =
133 InstanceIdentifier.builder(TransportZones.class)
134 .child(TransportZone.class, new TransportZoneKey(tzName)).build();
136 // this check is needed to reuse same function from TransportZoneListener
137 // when VTEP is moved from TepsNotHosted list to TZ configured from Northbound.
138 if (dpid.compareTo(BigInteger.ZERO) > 0) {
140 VtepsKey vtepkey = new VtepsKey(dpid, portName);
142 new VtepsBuilder().setDpnId(dpid).setIpAddress(tepIpAddress).withKey(vtepkey).setPortname(portName)
143 .setOptionOfTunnel(ofTunnel).build();
145 // Add vtep obtained from bridge into list
146 updatedVtepList.add(vtepObj);
148 LOG.trace("Adding TEP (TZ: {} Subnet: {} TEP IP: {} DPID: {}, of-tunnel: {}) in ITM Config DS.", tzName,
149 subnetMaskObj, tepIpAddress, dpid, ofTunnel);
151 // this is case when this function is called while TEPs movement from tepsNotHosted list when
152 // corresponding TZ is configured from northbound.
153 for (Vteps vtep: updatedVtepList) {
154 LOG.trace("Moving TEP (TEP IP: {} DPID: {}, of-tunnel: {})"
155 + "from not-hosted-transport-zone {} into ITM Config DS.",
156 vtep.getIpAddress(), vtep.getDpnId(), ofTunnel, tzName);
160 // Create subnet object
161 SubnetsKey subKey = new SubnetsKey(subnetMaskObj);
162 IpAddress gatewayIP = IpAddressBuilder.getDefaultInstance(ITMConstants.DUMMY_GATEWAY_IP);
163 int vlanID = ITMConstants.DUMMY_VLANID;
166 new SubnetsBuilder().setGatewayIp(gatewayIP)
167 .withKey(subKey).setPrefix(subnetMaskObj)
168 .setVlanId(vlanID).setVteps(updatedVtepList).build();
170 // add subnet into subnet list
171 subnetList.add(subnet);
173 // create TZ node with updated subnet having new vtep
174 TransportZone updatedTzone =
175 new TransportZoneBuilder().withKey(new TransportZoneKey(tzName)).setSubnets(subnetList)
176 .setZoneName(tzName).build();
178 // Update TZ in Config DS to add vtep in TZ
179 tx.merge(tranzportZonePath, updatedTzone, true);
183 * Adds the TEP into Vtep list in the subnet list in the transport zone list
184 * from ITM operational Datastore by merge operation with write transaction.
186 * @param tzName transport zone name in string
187 * @param tepIpAddress TEP IP address in IpAddress object
188 * @param dpid bridge datapath ID in BigInteger
189 * @param ofTunnel boolean flag for TEP to enable/disable of-tunnel feature on it
190 * @param dataBroker data broker handle to perform operations on operational datastore
191 * @param tx TypedWriteTransaction object
193 protected static void addUnknownTzTepIntoTepsNotHosted(String tzName, IpAddress tepIpAddress,
194 BigInteger dpid, boolean ofTunnel, DataBroker dataBroker, TypedWriteTransaction<Datastore.Operational> tx) {
195 List<UnknownVteps> vtepList;
196 TepsInNotHostedTransportZone tepsInNotHostedTransportZone =
197 ItmUtils.getUnknownTransportZoneFromITMOperDS(tzName, dataBroker);
198 if (tepsInNotHostedTransportZone == null) {
199 LOG.trace("Unhosted TransportZone ({}) does not exist in OperDS.", tzName);
200 vtepList = new ArrayList<>();
201 addVtepIntoTepsNotHosted(vtepList, tepIpAddress, tzName, dpid, ofTunnel, tx);
203 vtepList = tepsInNotHostedTransportZone.getUnknownVteps();
204 if (vtepList == null || vtepList.isEmpty()) {
205 // case: vtep list does not exist or it has no elements
206 if (vtepList == null) {
207 vtepList = new ArrayList<>();
209 LOG.trace("Add TEP into unhosted TZ ({}) when no vtep-list in the TZ.", tzName);
210 addVtepIntoTepsNotHosted(vtepList, tepIpAddress, tzName, dpid, ofTunnel, tx);
212 // case: vtep list has elements
213 boolean vtepFound = false;
214 UnknownVteps oldVtep = null;
216 for (UnknownVteps vtep : vtepList) {
217 if (Objects.equals(vtep.getDpnId(), dpid)) {
224 addVtepIntoTepsNotHosted(vtepList, tepIpAddress, tzName, dpid, ofTunnel, tx);
226 // vtep is found, update it with tep-ip
227 vtepList.remove(oldVtep);
228 addVtepIntoTepsNotHosted(vtepList, tepIpAddress, tzName, dpid, ofTunnel, tx);
235 * Adds the TEP into Unknown Vtep list under the transport zone in the TepsNotHosted list
236 * from ITM operational Datastore by merge operation with write transaction.
238 * @param updatedVtepList updated UnknownVteps list object which will have new TEP for addition
240 * @param tepIpAddress TEP IP address in IpAddress object
241 * @param tzName transport zone name in string
242 * @param dpid bridge datapath ID in BigInteger
243 * @param ofTunnel boolean flag for TEP to enable/disable of-tunnel feature on it
244 * @param tx TypedWriteTransaction object
246 protected static void addVtepIntoTepsNotHosted(List<UnknownVteps> updatedVtepList,
247 IpAddress tepIpAddress, String tzName, BigInteger dpid, boolean ofTunnel,
248 TypedWriteTransaction<Datastore.Operational> tx) {
249 //Create TZ node path
250 InstanceIdentifier<TepsInNotHostedTransportZone> tepsInNotHostedTransportZoneIid =
251 InstanceIdentifier.builder(NotHostedTransportZones.class)
252 .child(TepsInNotHostedTransportZone.class,
253 new TepsInNotHostedTransportZoneKey(tzName)).build();
256 UnknownVtepsKey vtepkey = new UnknownVtepsKey(dpid);
257 UnknownVteps vtepObj =
258 new UnknownVtepsBuilder().setDpnId(dpid).setIpAddress(tepIpAddress).withKey(vtepkey)
259 .setOfTunnel(ofTunnel).build();
261 // Add vtep obtained into unknown TZ tep list
262 updatedVtepList.add(vtepObj);
264 // create unknown TZ node with updated vtep list
265 TepsInNotHostedTransportZone updatedTzone = new TepsInNotHostedTransportZoneBuilder()
266 .withKey(new TepsInNotHostedTransportZoneKey(tzName)).setZoneName(tzName)
267 .setUnknownVteps(updatedVtepList).build();
269 LOG.trace("Adding TEP (DPID: {}, TEP IP: {}, of-tunnel: {}) into unhosted TZ: {}"
270 + "inside ITM Oper DS.", dpid, tepIpAddress, ofTunnel, tzName);
272 // Update TZ in Oper DS.
273 tx.merge(tepsInNotHostedTransportZoneIid, updatedTzone, true);
276 private static void addConfig(List<Subnets> subnets, String tzName, BigInteger dpnId, IpAddress ipAdd,
277 boolean ofTunnel, TypedWriteTransaction<Datastore.Configuration> tx) {
278 String portName = ITMConstants.DUMMY_PORT;
279 IpPrefix subnetMask = ItmUtils.getDummySubnet(); // get subnetMaskObject
281 if (subnets == null || subnets.isEmpty()) {
282 if (subnets == null) {
283 subnets = new ArrayList<>();
285 List<Vteps> vtepList = new ArrayList<>();
286 LOG.trace("Add TEP in transport-zone when no subnet-list.");
287 addVtepInITMConfigDS(subnets, subnetMask, vtepList, ipAdd, tzName, dpnId, portName, ofTunnel, tx);
289 List<Vteps> vtepList = null;
291 // subnet list already exists case; check for dummy-subnet
292 for (Subnets subnet : subnets) {
293 if (subnet.key().getPrefix().equals(subnetMask)) {
294 LOG.trace("Subnet exists in the subnet list of transport-zone {}.", tzName);
295 // get vtep list of existing subnet
296 vtepList = subnet.getVteps();
301 if (vtepList == null || vtepList.isEmpty()) {
302 // case: vtep list does not exist or it has no elements
303 if (vtepList == null) {
304 vtepList = new ArrayList<>();
306 LOG.trace("Add TEP in transport-zone when no vtep-list for specific subnet.");
307 addVtepInITMConfigDS(subnets, subnetMask, vtepList, ipAdd, tzName, dpnId, portName, ofTunnel, tx);
309 // case: vtep list has elements
310 boolean vtepFound = false;
311 Vteps oldVtep = null;
313 for (Vteps vtep : vtepList) {
314 if (Objects.equals(vtep.getDpnId(),dpnId)) {
317 // get portName of existing vtep
318 portName = vtep.getPortname();
323 addVtepInITMConfigDS(subnets, subnetMask, vtepList, ipAdd, tzName, dpnId, portName, ofTunnel, tx);
325 // vtep is found, update it with tep-ip
326 vtepList.remove(oldVtep);
327 addVtepInITMConfigDS(subnets, subnetMask, vtepList, ipAdd, tzName, dpnId, portName, ofTunnel, tx);
333 private static List<ListenableFuture<Void>> addUnknownTzTepIntoTepsNotHostedAndReturnFutures(String tzName,
334 IpAddress tepIpAddress, BigInteger id, boolean ofTunnel, DataBroker dataBroker,
335 ManagedNewTransactionRunner txRunner) {
336 return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(Datastore.OPERATIONAL,
337 tx -> addUnknownTzTepIntoTepsNotHosted(tzName, tepIpAddress, id, ofTunnel, dataBroker, tx)));