blob: 09853fdc736624436861fe16bcc0b4b482204df1 [file] [log] [blame]
Ayaka Koshibea7f044e2014-09-23 16:56:20 -07001package org.onlab.onos.net.trivial.impl;
2
3import static org.slf4j.LoggerFactory.getLogger;
4
5import java.util.Collections;
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -07006import java.util.HashMap;
Ayaka Koshibe406d0102014-09-24 16:08:12 -07007import java.util.HashSet;
8import java.util.Map;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -07009import java.util.Set;
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -070010import java.util.concurrent.atomic.AtomicInteger;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070011
12import org.apache.felix.scr.annotations.Activate;
13import org.apache.felix.scr.annotations.Component;
14import org.apache.felix.scr.annotations.Deactivate;
15import org.apache.felix.scr.annotations.Service;
16import org.onlab.onos.cluster.ControllerNode;
17import org.onlab.onos.cluster.DefaultControllerNode;
18import org.onlab.onos.cluster.MastershipEvent;
19import org.onlab.onos.cluster.MastershipStore;
tomf80c9722014-09-24 14:49:18 -070020import org.onlab.onos.cluster.MastershipStoreDelegate;
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -070021import org.onlab.onos.cluster.MastershipTerm;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070022import org.onlab.onos.cluster.NodeId;
23import org.onlab.onos.net.DeviceId;
24import org.onlab.onos.net.MastershipRole;
tomf80c9722014-09-24 14:49:18 -070025import org.onlab.onos.store.AbstractStore;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070026import org.onlab.packet.IpPrefix;
27import org.slf4j.Logger;
28
29import static org.onlab.onos.cluster.MastershipEvent.Type.*;
30
31/**
32 * Manages inventory of controller mastership over devices using
Ayaka Koshibe406d0102014-09-24 16:08:12 -070033 * trivial, non-distributed in-memory structures implementation.
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070034 */
35@Component(immediate = true)
36@Service
tomf80c9722014-09-24 14:49:18 -070037public class SimpleMastershipStore
38 extends AbstractStore<MastershipEvent, MastershipStoreDelegate>
39 implements MastershipStore {
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070040
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070041 private final Logger log = getLogger(getClass());
42
Ayaka Koshibe406d0102014-09-24 16:08:12 -070043 public static final IpPrefix LOCALHOST = IpPrefix.valueOf("127.0.0.1");
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070044
Ayaka Koshibe406d0102014-09-24 16:08:12 -070045 private ControllerNode instance =
46 new DefaultControllerNode(new NodeId("local"), LOCALHOST);
47
48 //devices mapped to their masters, to emulate multiple nodes
Ayaka Koshibe3de43ca2014-09-26 16:40:23 -070049 protected final Map<DeviceId, NodeId> masterMap = new HashMap<>();
Ayaka Koshibe971a38a2014-09-30 11:56:23 -070050 //emulate backups with pile of nodes
51 protected final Set<NodeId> backups = new HashSet<>();
Ayaka Koshibed9f693e2014-09-29 18:04:54 -070052 //terms
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -070053 protected final Map<DeviceId, AtomicInteger> termMap = new HashMap<>();
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070054
55 @Activate
56 public void activate() {
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070057 log.info("Started");
58 }
59
60 @Deactivate
61 public void deactivate() {
62 log.info("Stopped");
63 }
64
65 @Override
Ayaka Koshibe406d0102014-09-24 16:08:12 -070066 public MastershipEvent setMaster(NodeId nodeId, DeviceId deviceId) {
Ayaka Koshibe971a38a2014-09-30 11:56:23 -070067 MastershipRole role = getRole(nodeId, deviceId);
Ayaka Koshibe406d0102014-09-24 16:08:12 -070068
Ayaka Koshibe971a38a2014-09-30 11:56:23 -070069 synchronized (this) {
70 switch (role) {
71 case MASTER:
72 return null;
73 case STANDBY:
Ayaka Koshibed9f693e2014-09-29 18:04:54 -070074 masterMap.put(deviceId, nodeId);
Ayaka Koshibed9f693e2014-09-29 18:04:54 -070075 termMap.get(deviceId).incrementAndGet();
Ayaka Koshibe971a38a2014-09-30 11:56:23 -070076 backups.add(nodeId);
77 break;
78 case NONE:
79 masterMap.put(deviceId, nodeId);
80 termMap.put(deviceId, new AtomicInteger());
81 backups.add(nodeId);
82 break;
83 default:
84 log.warn("unknown Mastership Role {}", role);
85 return null;
Ayaka Koshibed9f693e2014-09-29 18:04:54 -070086 }
Ayaka Koshibe406d0102014-09-24 16:08:12 -070087 }
Ayaka Koshibed9f693e2014-09-29 18:04:54 -070088
Ayaka Koshibed9f693e2014-09-29 18:04:54 -070089 return new MastershipEvent(MASTER_CHANGED, deviceId, nodeId);
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070090 }
91
92 @Override
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070093 public NodeId getMaster(DeviceId deviceId) {
Ayaka Koshibe406d0102014-09-24 16:08:12 -070094 return masterMap.get(deviceId);
Ayaka Koshibea7f044e2014-09-23 16:56:20 -070095 }
96
97 @Override
98 public Set<DeviceId> getDevices(NodeId nodeId) {
Ayaka Koshibe406d0102014-09-24 16:08:12 -070099 Set<DeviceId> ids = new HashSet<>();
100 for (Map.Entry<DeviceId, NodeId> d : masterMap.entrySet()) {
101 if (d.getValue().equals(nodeId)) {
102 ids.add(d.getKey());
103 }
104 }
105 return Collections.unmodifiableSet(ids);
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700106 }
107
108 @Override
tomb41d1ac2014-09-24 01:51:24 -0700109 public MastershipRole requestRole(DeviceId deviceId) {
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700110 //query+possible reelection
111 NodeId node = instance.id();
112 MastershipRole role = getRole(node, deviceId);
113
114 switch (role) {
115 case MASTER:
116 break;
117 case STANDBY:
118 synchronized (this) {
119 //try to "re-elect", since we're really not distributed
120 NodeId rel = reelect(node);
121 if (rel == null) {
122 masterMap.put(deviceId, node);
123 termMap.put(deviceId, new AtomicInteger());
124 role = MastershipRole.MASTER;
125 }
126 backups.add(node);
127 }
128 break;
129 case NONE:
130 //first to get to it, say we are master
131 synchronized (this) {
132 masterMap.put(deviceId, node);
133 termMap.put(deviceId, new AtomicInteger());
134 backups.add(node);
135 role = MastershipRole.MASTER;
136 }
137 break;
138 default:
139 log.warn("unknown Mastership Role {}", role);
140 }
141 return role;
tomb41d1ac2014-09-24 01:51:24 -0700142 }
143
144 @Override
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700145 public MastershipRole getRole(NodeId nodeId, DeviceId deviceId) {
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700146 //just query
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700147 NodeId current = masterMap.get(deviceId);
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700148 MastershipRole role;
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700149
150 if (current == null) {
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700151 //degenerate case - only node is its own backup
152 if (backups.contains(nodeId)) {
153 role = MastershipRole.STANDBY;
154 } else {
155 role = MastershipRole.NONE;
Ayaka Koshibe406d0102014-09-24 16:08:12 -0700156 }
157 } else {
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700158 if (current.equals(nodeId)) {
159 role = MastershipRole.MASTER;
160 } else {
161 role = MastershipRole.STANDBY;
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700162 }
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700163 }
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700164 return role;
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700165 }
166
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -0700167 @Override
168 public MastershipTerm getTermFor(DeviceId deviceId) {
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700169 if ((masterMap.get(deviceId) == null) ||
170 (termMap.get(deviceId) == null)) {
Ayaka Koshibeb70d34b2014-09-25 15:43:01 -0700171 return null;
172 }
173 return MastershipTerm.of(
174 masterMap.get(deviceId), termMap.get(deviceId).get());
175 }
176
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700177 @Override
178 public MastershipEvent unsetMaster(NodeId nodeId, DeviceId deviceId) {
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700179 MastershipRole role = getRole(nodeId, deviceId);
180 synchronized (this) {
181 switch (role) {
182 case MASTER:
183 NodeId backup = reelect(nodeId);
184 if (backup == null) {
185 masterMap.remove(deviceId);
186 } else {
187 masterMap.put(deviceId, backup);
188 termMap.get(deviceId).incrementAndGet();
189 return new MastershipEvent(MASTER_CHANGED, deviceId, backup);
190 }
191 case STANDBY:
192 case NONE:
193 if (!termMap.containsKey(deviceId)) {
194 termMap.put(deviceId, new AtomicInteger());
195 }
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700196 backups.add(nodeId);
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700197 break;
198 default:
199 log.warn("unknown Mastership Role {}", role);
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700200 }
201 }
202 return null;
203 }
204
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700205 //dumbly selects next-available node that's not the current one
206 //emulate leader election
207 private NodeId reelect(NodeId nodeId) {
208 NodeId backup = null;
209 for (NodeId n : backups) {
210 if (!n.equals(nodeId)) {
211 backup = n;
212 break;
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700213 }
214 }
Ayaka Koshibe971a38a2014-09-30 11:56:23 -0700215 return backup;
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700216 }
217
Ayaka Koshibea7f044e2014-09-23 16:56:20 -0700218}