b7fd7d311e6b3b510337c1039212034c06ff2286
[vpnservice.git] / natservice / natservice-impl / src / main / java / org / opendaylight / vpnservice / natservice / internal / NAPTSwitchSelector.java
1 /*
2  * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.vpnservice.natservice.internal;
9
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;
17 import java.util.Map;
18 import java.util.Set;
19 import java.util.TreeSet;
20
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.yangtools.yang.binding.InstanceIdentifier;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 import com.google.common.base.Optional;
38
39 public class NAPTSwitchSelector {
40     private static final Logger LOG = LoggerFactory.getLogger(NAPTSwitchSelector.class);
41
42     private DataBroker dataBroker;
43     public NAPTSwitchSelector(DataBroker dataBroker) {
44         this.dataBroker = dataBroker;
45     }
46
47     BigInteger selectNewNAPTSwitch(String routerName) {
48         LOG.info("NAT Service : Select a new NAPT switch for router {}", routerName);
49         Map<BigInteger, Integer> naptSwitchWeights = constructNAPTSwitches();
50         List<BigInteger> routerSwitches = getDpnsForVpn(routerName);
51         if(routerSwitches.isEmpty()) {
52             LOG.debug("NAT Service : No dpns that are part of router {}", routerName);
53             LOG.warn("NAT Service : NAPT switch selection stopped due to no dpns scenario for router {}", routerName);
54             return BigInteger.ZERO;
55         }
56
57         Set<SwitchWeight> switchWeights = new TreeSet<>();
58         for(BigInteger dpn : routerSwitches) {
59             if(naptSwitchWeights.get(dpn) != null) {
60                 switchWeights.add(new SwitchWeight(dpn, naptSwitchWeights.get(dpn)));
61             } else {
62                 switchWeights.add(new SwitchWeight(dpn, 0));
63             }
64         }
65
66         BigInteger primarySwitch;
67
68         if(!switchWeights.isEmpty()) {
69
70             LOG.debug("NAT Service : Current switch weights for router {} - {}", routerName, switchWeights);
71
72             Iterator<SwitchWeight> it = switchWeights.iterator();
73             List<RouterToNaptSwitch> routerToNaptSwitchList = new ArrayList<>();
74             RouterToNaptSwitchBuilder routerToNaptSwitchBuilder = new RouterToNaptSwitchBuilder().setRouterName(routerName);
75             if ( switchWeights.size() == 1 )
76             {
77                 SwitchWeight singleSwitchWeight = null;
78                 while(it.hasNext() ) {
79                     singleSwitchWeight = it.next();
80                 }
81                 primarySwitch = singleSwitchWeight.getSwitch();
82                 routerToNaptSwitchBuilder.setPrimarySwitchId(primarySwitch);
83                 routerToNaptSwitchList.add(routerToNaptSwitchBuilder.build());
84                 NaptSwitches naptSwitches = new NaptSwitchesBuilder().setRouterToNaptSwitch(routerToNaptSwitchList).build();
85                 MDSALUtil.syncWrite( dataBroker, LogicalDatastoreType.OPERATIONAL, getNaptSwitchesIdentifier(), naptSwitches);
86
87                 LOG.debug( "NAT Service : successful addition of RouterToNaptSwitch to napt-switches container for single switch" );
88                 return primarySwitch;
89             }
90             else
91             {
92                 SwitchWeight firstSwitchWeight = null;
93                 while(it.hasNext() ) {
94                     firstSwitchWeight = it.next();
95                 }
96                 primarySwitch = firstSwitchWeight.getSwitch();
97                 routerToNaptSwitchBuilder.setPrimarySwitchId(primarySwitch);
98                 routerToNaptSwitchList.add(routerToNaptSwitchBuilder.build());
99                 NaptSwitches naptSwitches = new NaptSwitchesBuilder().setRouterToNaptSwitch(routerToNaptSwitchList).build();
100                 MDSALUtil.syncWrite( dataBroker, LogicalDatastoreType.OPERATIONAL, getNaptSwitchesIdentifier(), naptSwitches);
101
102                 LOG.debug( "NAT Service : successful addition of RouterToNaptSwitch to napt-switches container");
103                 return primarySwitch;
104             }
105         } else {
106
107                 primarySwitch = BigInteger.ZERO;
108
109                 LOG.debug("NAT Service : switchWeights empty, primarySwitch: {} ", primarySwitch);
110                 return primarySwitch;
111         }
112
113
114     }
115
116     private Map<BigInteger, Integer> constructNAPTSwitches() {
117         Optional<NaptSwitches> optNaptSwitches = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, getNaptSwitchesIdentifier());
118         Map<BigInteger, Integer> switchWeights = new HashMap<>();
119
120         if(optNaptSwitches.isPresent()) {
121             NaptSwitches naptSwitches = optNaptSwitches.get();
122             List<RouterToNaptSwitch> routerToNaptSwitches = naptSwitches.getRouterToNaptSwitch();
123
124             for(RouterToNaptSwitch naptSwitch : routerToNaptSwitches) {
125                 BigInteger primarySwitch = naptSwitch.getPrimarySwitchId();
126                 //update weight
127                 Integer weight = switchWeights.get(primarySwitch);
128                 if(weight == null) {
129                     switchWeights.put(primarySwitch, 1);
130                 } else {
131                     switchWeights.put(primarySwitch, ++weight);
132                 }
133             }
134         }
135         return switchWeights;
136     }
137
138     private InstanceIdentifier<NaptSwitches> getNaptSwitchesIdentifier() {
139         return InstanceIdentifier.create(NaptSwitches.class);
140     }
141
142     public List<BigInteger> getDpnsForVpn(String routerName ) {
143         LOG.debug( "getVpnToDpnList called for RouterName {}", routerName );
144
145         InstanceIdentifier<VpnInstanceOpDataEntry> id = InstanceIdentifier.builder(VpnInstanceOpData.class)
146                 .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(routerName))
147                 .build();
148
149         List<BigInteger> dpnsInVpn = new ArrayList<>();
150         Optional<VpnInstanceOpDataEntry> vpnInstanceOpData = NatUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
151
152         if(vpnInstanceOpData.isPresent()) {
153             LOG.debug( "NATService : getVpnToDpnList able to fetch vpnInstanceOpData" );
154             VpnInstanceOpDataEntry vpnInstanceOpDataEntry = vpnInstanceOpData.get();
155             List<VpnToDpnList> vpnDpnList = vpnInstanceOpDataEntry.getVpnToDpnList();
156             if(vpnDpnList != null) {
157                 for(VpnToDpnList vpnToDpn: vpnDpnList) {
158                     dpnsInVpn.add(vpnToDpn.getDpnId());
159                 }
160             }
161         }
162
163         LOG.debug( "getVpnToDpnList returning vpnDpnList {}", dpnsInVpn);
164         return dpnsInVpn;
165     }
166
167     private static class SwitchWeight implements Comparable<SwitchWeight>
168     {
169         private BigInteger swich;
170         private int weight;
171
172         public SwitchWeight( BigInteger swich, int weight )
173         {
174             this.swich = swich;
175             this.weight = weight;
176         }
177
178         @Override
179         public int hashCode() {
180             final int prime = 31;
181             int result = 1;
182             result = prime * result + ((swich == null) ? 0 : swich.hashCode());
183             return result;
184         }
185
186         @Override
187         public boolean equals(Object obj) {
188             if (this == obj)
189                 return true;
190             if (obj == null)
191                 return false;
192             if (getClass() != obj.getClass())
193                 return false;
194             SwitchWeight other = (SwitchWeight) obj;
195             if (swich == null) {
196                 if (other.swich != null)
197                     return false;
198             } else if (!swich.equals(other.swich))
199                 return false;
200             return true;
201         }
202
203         public BigInteger getSwitch() {
204             return swich;
205         }
206
207         public int getWeight() { 
208             return weight;
209         }
210
211         public void incrementWeight() {
212             ++ weight;
213         }
214
215         @Override
216         public int compareTo(SwitchWeight o) {
217             return o.getWeight() - weight;
218         }
219     }
220 }