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.netvirt.natservice.internal;
10 import com.google.common.base.Optional;
11 import java.math.BigInteger;
12 import java.util.HashMap;
13 import java.util.List;
16 import java.util.TreeSet;
17 import javax.annotation.Nonnull;
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.common.api.data.LogicalDatastoreType;
22 import org.opendaylight.genius.mdsalutil.MDSALUtil;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.NaptSwitches;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitch;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchBuilder;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
27 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
32 public class NAPTSwitchSelector {
33 private static final Logger LOG = LoggerFactory.getLogger(NAPTSwitchSelector.class);
34 private final DataBroker dataBroker;
37 public NAPTSwitchSelector(final DataBroker dataBroker) {
38 this.dataBroker = dataBroker;
41 BigInteger selectNewNAPTSwitch(String routerName) {
42 LOG.info("selectNewNAPTSwitch : Select a new NAPT switch for router {}", routerName);
43 Map<BigInteger, Integer> naptSwitchWeights = constructNAPTSwitches();
44 List<BigInteger> routerSwitches = getDpnsForVpn(routerName);
45 if (routerSwitches.isEmpty()) {
46 LOG.warn("selectNewNAPTSwitch : Delaying NAPT switch selection due to no dpns scenario for router {}",
48 return BigInteger.ZERO;
51 Set<SwitchWeight> switchWeights = new TreeSet<>();
52 for (BigInteger dpn : routerSwitches) {
53 if (naptSwitchWeights.get(dpn) != null) {
54 switchWeights.add(new SwitchWeight(dpn, naptSwitchWeights.get(dpn)));
56 switchWeights.add(new SwitchWeight(dpn, 0));
60 BigInteger primarySwitch;
62 if (!switchWeights.isEmpty()) {
64 LOG.debug("selectNewNAPTSwitch : Current switch weights for router {} - {}", routerName, switchWeights);
66 RouterToNaptSwitchBuilder routerToNaptSwitchBuilder =
67 new RouterToNaptSwitchBuilder().setRouterName(routerName);
68 SwitchWeight firstSwitchWeight = switchWeights.iterator().next();
69 primarySwitch = firstSwitchWeight.getSwitch();
70 RouterToNaptSwitch id = routerToNaptSwitchBuilder.setPrimarySwitchId(primarySwitch).build();
72 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
73 getNaptSwitchesIdentifier(routerName), id);
75 LOG.debug("selectNewNAPTSwitch : successful addition of RouterToNaptSwitch to napt-switches container");
78 primarySwitch = BigInteger.ZERO;
80 LOG.debug("selectNewNAPTSwitch : switchWeights empty, primarySwitch: {} ", primarySwitch);
85 private Map<BigInteger, Integer> constructNAPTSwitches() {
86 Optional<NaptSwitches> optNaptSwitches =
87 MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, getNaptSwitchesIdentifier());
88 Map<BigInteger, Integer> switchWeights = new HashMap<>();
90 if (optNaptSwitches.isPresent()) {
91 NaptSwitches naptSwitches = optNaptSwitches.get();
93 for (RouterToNaptSwitch naptSwitch : naptSwitches.nonnullRouterToNaptSwitch()) {
94 BigInteger primarySwitch = naptSwitch.getPrimarySwitchId();
96 Integer weight = switchWeights.get(primarySwitch);
98 switchWeights.put(primarySwitch, 1);
100 switchWeights.put(primarySwitch, ++weight);
104 return switchWeights;
107 private InstanceIdentifier<NaptSwitches> getNaptSwitchesIdentifier() {
108 return InstanceIdentifier.create(NaptSwitches.class);
111 private InstanceIdentifier<RouterToNaptSwitch> getNaptSwitchesIdentifier(String routerName) {
112 return InstanceIdentifier.builder(NaptSwitches.class)
113 .child(RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerName)).build();
117 public List<BigInteger> getDpnsForVpn(String routerName) {
118 LOG.debug("getDpnsForVpn: called for RouterName {}", routerName);
119 long bgpVpnId = NatUtil.getBgpVpnId(dataBroker, routerName);
121 if (bgpVpnId != NatConstants.INVALID_ID) {
122 return NatUtil.getDpnsForRouter(dataBroker, routerName);
124 return NatUtil.getDpnsForRouter(dataBroker, routerName);
127 private static class SwitchWeight implements Comparable<SwitchWeight> {
128 private final BigInteger swich;
131 SwitchWeight(BigInteger swich, int weight) {
133 this.weight = weight;
137 public int hashCode() {
138 final int prime = 31;
140 result = prime * result + (swich == null ? 0 : swich.hashCode());
145 public boolean equals(Object obj) {
152 if (getClass() != obj.getClass()) {
155 SwitchWeight other = (SwitchWeight) obj;
157 if (other.swich != null) {
160 } else if (!swich.equals(other.swich)) {
166 public BigInteger getSwitch() {
170 public int getWeight() {
174 public void incrementWeight() {
179 public int compareTo(@Nonnull SwitchWeight switchWeight) {
180 return weight - switchWeight.getWeight();