2 * Copyright (c) 2016 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.vpnservice.natservice.internal;
10 import java.math.BigInteger;
11 import java.util.ArrayList;
12 import java.util.Collections;
13 import java.util.Comparator;
14 import java.util.HashMap;
15 import java.util.Iterator;
16 import java.util.List;
19 import java.util.TreeSet;
21 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
22 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
23 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstanceOpData;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ExtRouters;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.NaptSwitches;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.NaptSwitchesBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitch;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitchBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
34 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
38 import com.google.common.base.Optional;
40 public class NAPTSwitchSelector {
41 private static final Logger LOG = LoggerFactory.getLogger(NAPTSwitchSelector.class);
43 private DataBroker dataBroker;
44 public NAPTSwitchSelector(DataBroker dataBroker) {
45 this.dataBroker = dataBroker;
48 BigInteger selectNewNAPTSwitch(String routerName) {
49 LOG.info("NAT Service : Select a new NAPT switch for router {}", routerName);
50 Map<BigInteger, Integer> naptSwitchWeights = constructNAPTSwitches();
51 List<BigInteger> routerSwitches = getDpnsForVpn(routerName);
52 if(routerSwitches == null || routerSwitches.isEmpty()) {
53 LOG.debug("NAT Service : No switches are part of router {}", routerName);
54 LOG.error("NAT Service : NAPT SWITCH SELECTION STOPPED DUE TO NO DPNS SCENARIO FOR ROUTER {}", routerName);
55 return BigInteger.ZERO;
58 Set<SwitchWeight> switchWeights = new TreeSet<>();
59 for(BigInteger dpn : routerSwitches) {
60 if(naptSwitchWeights.get(dpn) != null) {
61 switchWeights.add(new SwitchWeight(dpn, naptSwitchWeights.get(dpn)));
63 switchWeights.add(new SwitchWeight(dpn, 0));
67 BigInteger primarySwitch;
69 if(!switchWeights.isEmpty()) {
71 LOG.debug("NAT Service : Current switch weights for router {} - {}", routerName, switchWeights);
73 Iterator<SwitchWeight> it = switchWeights.iterator();
74 RouterToNaptSwitchBuilder routerToNaptSwitchBuilder = new RouterToNaptSwitchBuilder().setRouterName(routerName);
75 if ( switchWeights.size() == 1 )
77 SwitchWeight singleSwitchWeight = null;
78 while(it.hasNext() ) {
79 singleSwitchWeight = it.next();
81 primarySwitch = singleSwitchWeight.getSwitch();
82 RouterToNaptSwitch id = routerToNaptSwitchBuilder.setPrimarySwitchId(primarySwitch).build();
84 MDSALUtil.syncWrite( dataBroker, LogicalDatastoreType.OPERATIONAL, getNaptSwitchesIdentifier(routerName), id);
86 LOG.debug( "NAT Service : successful addition of RouterToNaptSwitch to napt-switches container for single switch" );
91 SwitchWeight firstSwitchWeight = null;
92 while(it.hasNext() ) {
93 firstSwitchWeight = it.next();
95 primarySwitch = firstSwitchWeight.getSwitch();
96 RouterToNaptSwitch id = routerToNaptSwitchBuilder.setPrimarySwitchId(primarySwitch).build();
98 MDSALUtil.syncWrite( dataBroker, LogicalDatastoreType.OPERATIONAL, getNaptSwitchesIdentifier(routerName), id);
100 LOG.debug( "NAT Service : successful addition of RouterToNaptSwitch to napt-switches container");
101 return primarySwitch;
105 primarySwitch = BigInteger.ZERO;
107 LOG.debug("NAT Service : switchWeights empty, primarySwitch: {} ", primarySwitch);
108 return primarySwitch;
114 private Map<BigInteger, Integer> constructNAPTSwitches() {
115 Optional<NaptSwitches> optNaptSwitches = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, getNaptSwitchesIdentifier());
116 Map<BigInteger, Integer> switchWeights = new HashMap<>();
118 if(optNaptSwitches.isPresent()) {
119 NaptSwitches naptSwitches = optNaptSwitches.get();
120 List<RouterToNaptSwitch> routerToNaptSwitches = naptSwitches.getRouterToNaptSwitch();
122 for(RouterToNaptSwitch naptSwitch : routerToNaptSwitches) {
123 BigInteger primarySwitch = naptSwitch.getPrimarySwitchId();
125 Integer weight = switchWeights.get(primarySwitch);
127 switchWeights.put(primarySwitch, 1);
129 switchWeights.put(primarySwitch, ++weight);
133 return switchWeights;
136 private InstanceIdentifier<NaptSwitches> getNaptSwitchesIdentifier() {
137 return InstanceIdentifier.create(NaptSwitches.class);
140 private InstanceIdentifier<RouterToNaptSwitch> getNaptSwitchesIdentifier(String routerName) {
141 return InstanceIdentifier.builder(NaptSwitches.class).child(RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerName)).build();
144 public List<BigInteger> getDpnsForVpn(String routerName ) {
145 LOG.debug( "NAT Service : getVpnToDpnList called for RouterName {}", routerName );
146 long bgpVpnId = NatUtil.getBgpVpnId(dataBroker, routerName);
147 if(bgpVpnId != NatConstants.INVALID_ID){
148 return NatUtil.getDpnsForRouter(dataBroker, routerName);
150 InstanceIdentifier<VpnInstanceOpDataEntry> id = InstanceIdentifier.builder(VpnInstanceOpData.class)
151 .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(routerName))
154 List<BigInteger> dpnsInVpn = new ArrayList<>();
155 Optional<VpnInstanceOpDataEntry> vpnInstanceOpData = NatUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
157 if(vpnInstanceOpData.isPresent()) {
158 LOG.debug( "NAT Service : getVpnToDpnList able to fetch vpnInstanceOpData" );
159 VpnInstanceOpDataEntry vpnInstanceOpDataEntry = vpnInstanceOpData.get();
160 List<VpnToDpnList> vpnDpnList = vpnInstanceOpDataEntry.getVpnToDpnList();
161 if(vpnDpnList != null) {
162 for(VpnToDpnList vpnToDpn: vpnDpnList) {
163 dpnsInVpn.add(vpnToDpn.getDpnId());
168 if(dpnsInVpn == null || dpnsInVpn.isEmpty()) {
169 LOG.debug("NAT Service : Unable to get the switches for the router {} from the VPNInstanceOpData", routerName);
170 dpnsInVpn = NatUtil.getDpnsForRouter(dataBroker, routerName);
171 if(dpnsInVpn == null || dpnsInVpn.isEmpty()){
172 LOG.debug("NAT Service : No switches are part of router {}", routerName);
177 LOG.debug( "NAT Service : getVpnToDpnList returning vpnDpnList {}", dpnsInVpn);
183 private static class SwitchWeight implements Comparable<SwitchWeight>
185 private BigInteger swich;
188 public SwitchWeight( BigInteger swich, int weight )
191 this.weight = weight;
195 public int hashCode() {
196 final int prime = 31;
198 result = prime * result + ((swich == null) ? 0 : swich.hashCode());
203 public boolean equals(Object obj) {
208 if (getClass() != obj.getClass())
210 SwitchWeight other = (SwitchWeight) obj;
212 if (other.swich != null)
214 } else if (!swich.equals(other.swich))
219 public BigInteger getSwitch() {
223 public int getWeight() {
227 public void incrementWeight() {
232 public int compareTo(SwitchWeight o) {
233 return o.getWeight() - weight;