2 * Copyright (c) 2017 Red Hat, Inc. 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
9 package org.opendaylight.netvirt.natservice.ha;
11 import java.math.BigInteger;
12 import java.util.ArrayList;
13 import java.util.Iterator;
14 import java.util.List;
16 import java.util.concurrent.ConcurrentHashMap;
18 import javax.inject.Inject;
19 import javax.inject.Singleton;
20 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
21 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
22 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
23 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
24 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
25 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
26 import org.opendaylight.netvirt.natservice.api.CentralizedSwitchScheduler;
27 import org.opendaylight.netvirt.natservice.internal.NatUtil;
28 import org.opendaylight.netvirt.vpnmanager.api.IVpnFootprintService;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.NaptSwitches;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitch;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.Subnetmaps;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapKey;
39 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
44 public class WeightedCentralizedSwitchScheduler implements CentralizedSwitchScheduler {
45 private static final Logger LOG = LoggerFactory.getLogger(WeightedCentralizedSwitchScheduler.class);
46 private final Map<BigInteger,Integer> switchWeightsMap = new ConcurrentHashMap<>();
47 private final Map<String,String> subnetIdToRouterPortMap = new ConcurrentHashMap<>();
48 private final DataBroker dataBroker;
49 final OdlInterfaceRpcService interfaceManager;
50 private final int initialSwitchWeight = 0;
51 private final IVpnFootprintService vpnFootprintService;
54 public WeightedCentralizedSwitchScheduler(DataBroker dataBroker, OdlInterfaceRpcService interfaceManager,
55 IVpnFootprintService vpnFootprintService) {
56 this.dataBroker = dataBroker;
57 this.interfaceManager = interfaceManager;
58 this.vpnFootprintService = vpnFootprintService;
62 public boolean scheduleCentralizedSwitch(Routers router) {
63 BigInteger nextSwitchId = getSwitchWithLowestWeight();
64 String routerName = router.getRouterName();
65 RouterToNaptSwitchBuilder routerToNaptSwitchBuilder =
66 new RouterToNaptSwitchBuilder().setRouterName(routerName);
67 RouterToNaptSwitch id = routerToNaptSwitchBuilder.setPrimarySwitchId(nextSwitchId).build();
68 addToDpnMaps(routerName, router.getSubnetIds(), nextSwitchId);
70 SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
71 getNaptSwitchesIdentifier(routerName), id);
72 switchWeightsMap.put(nextSwitchId,switchWeightsMap.get(nextSwitchId) + 1);
74 } catch (TransactionCommitFailedException e) {
75 LOG.error("ScheduleCentralizedSwitch failed for {}", routerName);
82 public boolean updateCentralizedSwitch(Routers oldRouter, Routers newRouter) {
83 String routerName = newRouter.getRouterName();
84 List<Uuid> addedSubnetIds = getUpdatedSubnetIds(newRouter.getSubnetIds(), oldRouter.getSubnetIds());
85 List<Uuid> deletedSubnetIds = getUpdatedSubnetIds(oldRouter.getSubnetIds(), newRouter.getSubnetIds());
86 BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, newRouter.getRouterName());
87 addToDpnMaps(routerName, addedSubnetIds, primarySwitchId);
88 deleteFromDpnMaps(routerName, deletedSubnetIds, primarySwitchId);
93 public boolean releaseCentralizedSwitch(Routers router) {
94 String routerName = router.getRouterName();
95 BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
96 deleteFromDpnMaps(routerName, router.getSubnetIds(), primarySwitchId);
98 SingleTransactionDataBroker.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION,
99 getNaptSwitchesIdentifier(routerName));
100 switchWeightsMap.put(primarySwitchId,switchWeightsMap.get(primarySwitchId) - 1);
101 } catch (TransactionCommitFailedException e) {
107 private void addToDpnMaps(String routerName, List<Uuid> addedSubnetIds, BigInteger primarySwitchId) {
108 if (addedSubnetIds == null || addedSubnetIds.isEmpty()) {
109 LOG.debug("addToDpnMaps no subnets associated with {}", routerName);
112 String primaryRd = NatUtil.getPrimaryRd(dataBroker, routerName);
113 WriteTransaction writeOperTxn = dataBroker.newWriteOnlyTransaction();
114 for (Uuid subnetUuid : addedSubnetIds) {
116 Subnetmap subnetMapEntry = SingleTransactionDataBroker.syncRead(dataBroker,
117 LogicalDatastoreType.CONFIGURATION, getSubnetMapIdentifier(subnetUuid));
118 Uuid routerPortUuid = subnetMapEntry.getRouterInterfacePortId();
119 subnetIdToRouterPortMap.put(subnetUuid.getValue(), routerPortUuid.getValue());
120 vpnFootprintService.updateVpnToDpnMapping(primarySwitchId, routerName, primaryRd,
121 routerPortUuid.getValue(), null, true);
122 NatUtil.addToNeutronRouterDpnsMap(dataBroker, routerName, routerPortUuid.getValue(),
123 primarySwitchId, writeOperTxn);
124 NatUtil.addToDpnRoutersMap(dataBroker, routerName, routerPortUuid.getValue(),
125 primarySwitchId, writeOperTxn);
126 } catch (ReadFailedException e) {
127 LOG.error("addToDpnMaps failed for {}", routerName);
130 writeOperTxn.submit();
135 private void deleteFromDpnMaps(String routerName, List<Uuid> deletedSubnetIds, BigInteger primarySwitchId) {
136 if (deletedSubnetIds == null || deletedSubnetIds.isEmpty()) {
137 LOG.debug("deleteFromDpnMaps no subnets associated with {}", routerName);
140 WriteTransaction writeOperTxn = dataBroker.newWriteOnlyTransaction();
141 String primaryRd = NatUtil.getPrimaryRd(dataBroker, routerName);
142 for (Uuid subnetUuid :deletedSubnetIds) {
143 String routerPort = subnetIdToRouterPortMap.remove(subnetUuid.getValue());
144 if (routerPort == null) {
145 LOG.error("The router port was not found for {}", subnetUuid.getValue());
148 vpnFootprintService.updateVpnToDpnMapping(primarySwitchId, routerName, primaryRd,
149 routerPort, null, false);
150 NatUtil.removeFromNeutronRouterDpnsMap(dataBroker, routerName, primarySwitchId, writeOperTxn);
151 NatUtil.removeFromDpnRoutersMap(dataBroker, routerName, routerName, interfaceManager,
154 writeOperTxn.submit();
158 public boolean addSwitch(BigInteger dpnId) {
159 /* Initialize the switch in the map with weight 0 */
160 switchWeightsMap.put(dpnId, initialSwitchWeight);
166 public boolean removeSwitch(BigInteger dpnId) {
167 if (switchWeightsMap.get(dpnId) != initialSwitchWeight) {
168 NaptSwitches naptSwitches = getNaptSwitches(dataBroker);
169 for (RouterToNaptSwitch routerToNaptSwitch : naptSwitches.getRouterToNaptSwitch()) {
170 if (dpnId.equals(routerToNaptSwitch.getPrimarySwitchId())) {
171 Routers router = NatUtil.getRoutersFromConfigDS(dataBroker, routerToNaptSwitch.getRouterName());
172 releaseCentralizedSwitch(router);
173 switchWeightsMap.remove(dpnId);
174 scheduleCentralizedSwitch(router);
179 switchWeightsMap.remove(dpnId);
184 public static NaptSwitches getNaptSwitches(DataBroker dataBroker) {
185 InstanceIdentifier<NaptSwitches> id = InstanceIdentifier.builder(NaptSwitches.class).build();
186 return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
187 LogicalDatastoreType.CONFIGURATION, id).orNull();
190 private BigInteger getSwitchWithLowestWeight() {
191 int lowestWeight = Integer.MAX_VALUE;
192 BigInteger nextSwitchId = BigInteger.valueOf(0);
193 for (BigInteger dpnId : switchWeightsMap.keySet()) {
194 if (lowestWeight > switchWeightsMap.get(dpnId)) {
195 lowestWeight = switchWeightsMap.get(dpnId);
196 nextSwitchId = dpnId;
202 private InstanceIdentifier<RouterToNaptSwitch> getNaptSwitchesIdentifier(String routerName) {
203 return InstanceIdentifier.builder(NaptSwitches.class)
204 .child(RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerName)).build();
207 private InstanceIdentifier<Subnetmap> getSubnetMapIdentifier(Uuid subnetId) {
208 return InstanceIdentifier.builder(Subnetmaps.class).child(Subnetmap.class,
209 new SubnetmapKey(subnetId)).build();
213 public boolean getCentralizedSwitch(String routerName) {
214 // TODO Auto-generated method stub
218 public static List<Uuid> getUpdatedSubnetIds(
219 List<Uuid> updatedSubnetIds,
220 List<Uuid> currentSubnetIds) {
221 if (updatedSubnetIds == null) {
224 List<Uuid> newSubnetIds = new ArrayList<>(updatedSubnetIds);
225 if (currentSubnetIds == null) {
228 List<Uuid> origSubnetIds = new ArrayList<>(currentSubnetIds);
229 for (Iterator<Uuid> iterator = newSubnetIds.iterator(); iterator.hasNext();) {
230 Uuid updatedSubnetId = iterator.next();
231 for (Uuid currentSubnetId : origSubnetIds) {
232 if (updatedSubnetId.getValue().equals(currentSubnetId.getValue())) {