Switch to JDT annotations for Nullable and NonNull
[netvirt.git] / natservice / impl / src / main / java / org / opendaylight / netvirt / natservice / internal / NAPTSwitchSelector.java
1 /*
2  * Copyright (c) 2016, 2017 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.netvirt.natservice.internal;
9
10 import com.google.common.base.Optional;
11 import java.math.BigInteger;
12 import java.util.HashMap;
13 import java.util.List;
14 import java.util.Map;
15 import java.util.Set;
16 import java.util.TreeSet;
17 import javax.inject.Inject;
18 import javax.inject.Singleton;
19 import org.eclipse.jdt.annotation.NonNull;
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;
30
31 @Singleton
32 public class NAPTSwitchSelector {
33     private static final Logger LOG = LoggerFactory.getLogger(NAPTSwitchSelector.class);
34     private final DataBroker dataBroker;
35
36     @Inject
37     public NAPTSwitchSelector(final DataBroker dataBroker) {
38         this.dataBroker = dataBroker;
39     }
40
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 {}",
47                     routerName);
48             return BigInteger.ZERO;
49         }
50
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)));
55             } else {
56                 switchWeights.add(new SwitchWeight(dpn, 0));
57             }
58         }
59
60         BigInteger primarySwitch;
61
62         if (!switchWeights.isEmpty()) {
63
64             LOG.debug("selectNewNAPTSwitch : Current switch weights for router {} - {}", routerName, switchWeights);
65
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();
71
72             MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
73                 getNaptSwitchesIdentifier(routerName), id);
74
75             LOG.debug("selectNewNAPTSwitch : successful addition of RouterToNaptSwitch to napt-switches container");
76             return primarySwitch;
77         } else {
78             primarySwitch = BigInteger.ZERO;
79
80             LOG.debug("selectNewNAPTSwitch : switchWeights empty, primarySwitch: {} ", primarySwitch);
81             return primarySwitch;
82         }
83     }
84
85     private Map<BigInteger, Integer> constructNAPTSwitches() {
86         Optional<NaptSwitches> optNaptSwitches =
87             MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, getNaptSwitchesIdentifier());
88         Map<BigInteger, Integer> switchWeights = new HashMap<>();
89
90         if (optNaptSwitches.isPresent()) {
91             NaptSwitches naptSwitches = optNaptSwitches.get();
92
93             for (RouterToNaptSwitch naptSwitch : naptSwitches.nonnullRouterToNaptSwitch()) {
94                 BigInteger primarySwitch = naptSwitch.getPrimarySwitchId();
95                 //update weight
96                 Integer weight = switchWeights.get(primarySwitch);
97                 if (weight == null) {
98                     switchWeights.put(primarySwitch, 1);
99                 } else {
100                     switchWeights.put(primarySwitch, ++weight);
101                 }
102             }
103         }
104         return switchWeights;
105     }
106
107     private InstanceIdentifier<NaptSwitches> getNaptSwitchesIdentifier() {
108         return InstanceIdentifier.create(NaptSwitches.class);
109     }
110
111     private InstanceIdentifier<RouterToNaptSwitch> getNaptSwitchesIdentifier(String routerName) {
112         return InstanceIdentifier.builder(NaptSwitches.class)
113             .child(RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerName)).build();
114     }
115
116     @NonNull
117     public List<BigInteger> getDpnsForVpn(String routerName) {
118         LOG.debug("getDpnsForVpn: called for RouterName {}", routerName);
119         long bgpVpnId = NatUtil.getBgpVpnId(dataBroker, routerName);
120         // TODO Why?
121         if (bgpVpnId != NatConstants.INVALID_ID) {
122             return NatUtil.getDpnsForRouter(dataBroker, routerName);
123         }
124         return NatUtil.getDpnsForRouter(dataBroker, routerName);
125     }
126
127     private static class SwitchWeight implements Comparable<SwitchWeight> {
128         private final BigInteger swich;
129         private int weight;
130
131         SwitchWeight(BigInteger swich, int weight) {
132             this.swich = swich;
133             this.weight = weight;
134         }
135
136         @Override
137         public int hashCode() {
138             final int prime = 31;
139             int result = 1;
140             result = prime * result + (swich == null ? 0 : swich.hashCode());
141             return result;
142         }
143
144         @Override
145         public boolean equals(Object obj) {
146             if (this == obj) {
147                 return true;
148             }
149             if (obj == null) {
150                 return false;
151             }
152             if (getClass() != obj.getClass()) {
153                 return false;
154             }
155             SwitchWeight other = (SwitchWeight) obj;
156             if (swich == null) {
157                 if (other.swich != null) {
158                     return false;
159                 }
160             } else if (!swich.equals(other.swich)) {
161                 return false;
162             }
163             return true;
164         }
165
166         public BigInteger getSwitch() {
167             return swich;
168         }
169
170         public int getWeight() {
171             return weight;
172         }
173
174         public void incrementWeight() {
175             ++weight;
176         }
177
178         @Override
179         public int compareTo(@NonNull SwitchWeight switchWeight) {
180             return weight - switchWeight.getWeight();
181         }
182     }
183 }