682911ccc18544e42654c46d0744ac67500ddbcd
[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.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;
37
38 import com.google.common.base.Optional;
39
40 public class NAPTSwitchSelector {
41     private static final Logger LOG = LoggerFactory.getLogger(NAPTSwitchSelector.class);
42
43     private DataBroker dataBroker;
44     public NAPTSwitchSelector(DataBroker dataBroker) {
45         this.dataBroker = dataBroker;
46     }
47
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;
56         }
57
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)));
62             } else {
63                 switchWeights.add(new SwitchWeight(dpn, 0));
64             }
65         }
66
67         BigInteger primarySwitch;
68
69         if(!switchWeights.isEmpty()) {
70
71             LOG.debug("NAT Service : Current switch weights for router {} - {}", routerName, switchWeights);
72
73             Iterator<SwitchWeight> it = switchWeights.iterator();
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                 RouterToNaptSwitch id = routerToNaptSwitchBuilder.setPrimarySwitchId(primarySwitch).build();
83                 
84                 MDSALUtil.syncWrite( dataBroker, LogicalDatastoreType.OPERATIONAL, getNaptSwitchesIdentifier(routerName), id);
85
86                 LOG.debug( "NAT Service : successful addition of RouterToNaptSwitch to napt-switches container for single switch" );
87                 return primarySwitch;
88             }
89             else
90             {
91                 SwitchWeight firstSwitchWeight = null;
92                 while(it.hasNext() ) {
93                     firstSwitchWeight = it.next();
94                 }
95                 primarySwitch = firstSwitchWeight.getSwitch();
96                 RouterToNaptSwitch id = routerToNaptSwitchBuilder.setPrimarySwitchId(primarySwitch).build();
97                 
98                 MDSALUtil.syncWrite( dataBroker, LogicalDatastoreType.OPERATIONAL, getNaptSwitchesIdentifier(routerName), id);
99
100                 LOG.debug( "NAT Service : successful addition of RouterToNaptSwitch to napt-switches container");
101                 return primarySwitch;
102             }
103         } else {
104
105                 primarySwitch = BigInteger.ZERO;
106
107                 LOG.debug("NAT Service : switchWeights empty, primarySwitch: {} ", primarySwitch);
108                 return primarySwitch;
109         }
110
111
112     }
113
114     private Map<BigInteger, Integer> constructNAPTSwitches() {
115         Optional<NaptSwitches> optNaptSwitches = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, getNaptSwitchesIdentifier());
116         Map<BigInteger, Integer> switchWeights = new HashMap<>();
117
118         if(optNaptSwitches.isPresent()) {
119             NaptSwitches naptSwitches = optNaptSwitches.get();
120             List<RouterToNaptSwitch> routerToNaptSwitches = naptSwitches.getRouterToNaptSwitch();
121
122             for(RouterToNaptSwitch naptSwitch : routerToNaptSwitches) {
123                 BigInteger primarySwitch = naptSwitch.getPrimarySwitchId();
124                 //update weight
125                 Integer weight = switchWeights.get(primarySwitch);
126                 if(weight == null) {
127                     switchWeights.put(primarySwitch, 1);
128                 } else {
129                     switchWeights.put(primarySwitch, ++weight);
130                 }
131             }
132         }
133         return switchWeights;
134     }
135
136     private InstanceIdentifier<NaptSwitches> getNaptSwitchesIdentifier() {
137         return InstanceIdentifier.create(NaptSwitches.class);
138     }
139
140     private InstanceIdentifier<RouterToNaptSwitch> getNaptSwitchesIdentifier(String routerName) {
141         return InstanceIdentifier.builder(NaptSwitches.class).child(RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerName)).build();
142     }
143
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);
149         }
150         InstanceIdentifier<VpnInstanceOpDataEntry> id = InstanceIdentifier.builder(VpnInstanceOpData.class)
151                 .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(routerName))
152                 .build();
153
154         List<BigInteger> dpnsInVpn = new ArrayList<>();
155         Optional<VpnInstanceOpDataEntry> vpnInstanceOpData = NatUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
156
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());
164                 }
165             }
166         }
167
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);
173                 return dpnsInVpn;
174             }
175         }
176
177         LOG.debug( "NAT Service : getVpnToDpnList returning vpnDpnList {}", dpnsInVpn);
178         return dpnsInVpn;
179
180
181     }
182
183     private static class SwitchWeight implements Comparable<SwitchWeight>
184     {
185         private BigInteger swich;
186         private int weight;
187
188         public SwitchWeight( BigInteger swich, int weight )
189         {
190             this.swich = swich;
191             this.weight = weight;
192         }
193
194         @Override
195         public int hashCode() {
196             final int prime = 31;
197             int result = 1;
198             result = prime * result + ((swich == null) ? 0 : swich.hashCode());
199             return result;
200         }
201
202         @Override
203         public boolean equals(Object obj) {
204             if (this == obj)
205                 return true;
206             if (obj == null)
207                 return false;
208             if (getClass() != obj.getClass())
209                 return false;
210             SwitchWeight other = (SwitchWeight) obj;
211             if (swich == null) {
212                 if (other.swich != null)
213                     return false;
214             } else if (!swich.equals(other.swich))
215                 return false;
216             return true;
217         }
218
219         public BigInteger getSwitch() {
220             return swich;
221         }
222
223         public int getWeight() { 
224             return weight;
225         }
226
227         public void incrementWeight() {
228             ++ weight;
229         }
230
231         @Override
232         public int compareTo(SwitchWeight o) {
233             return o.getWeight() - weight;
234         }
235     }
236 }