blob: d01862c66e1239879cbbb64f8f27fc97232e118e [file] [log] [blame]
tomea961ff2014-10-01 12:45:15 -07001package org.onlab.onos.store.trivial.impl;
tom7869ad92014-09-09 14:32:08 -07002
tom093340b2014-10-10 00:15:36 -07003import com.google.common.collect.HashMultimap;
4import com.google.common.collect.ImmutableSet;
5import com.google.common.collect.Multimap;
6import com.google.common.collect.Sets;
tom5bcc9462014-09-19 10:11:31 -07007import org.apache.felix.scr.annotations.Activate;
8import org.apache.felix.scr.annotations.Component;
9import org.apache.felix.scr.annotations.Deactivate;
10import org.apache.felix.scr.annotations.Service;
tom093340b2014-10-10 00:15:36 -070011import org.onlab.onos.net.Annotations;
tom7869ad92014-09-09 14:32:08 -070012import org.onlab.onos.net.ConnectPoint;
Ayaka Koshibee5652752014-09-10 23:27:34 -070013import org.onlab.onos.net.DefaultHost;
tom7869ad92014-09-09 14:32:08 -070014import org.onlab.onos.net.DeviceId;
15import org.onlab.onos.net.Host;
16import org.onlab.onos.net.HostId;
tom093340b2014-10-10 00:15:36 -070017import org.onlab.onos.net.HostLocation;
tom7869ad92014-09-09 14:32:08 -070018import org.onlab.onos.net.host.HostDescription;
19import org.onlab.onos.net.host.HostEvent;
tom5bcc9462014-09-19 10:11:31 -070020import org.onlab.onos.net.host.HostStore;
tomf80c9722014-09-24 14:49:18 -070021import org.onlab.onos.net.host.HostStoreDelegate;
Pavlin Radoslavov76b0ae22014-10-27 15:33:19 -070022import org.onlab.onos.net.host.InterfaceIpAddress;
Jonathan Hartac60c082014-09-23 08:55:17 -070023import org.onlab.onos.net.host.PortAddresses;
tom7869ad92014-09-09 14:32:08 -070024import org.onlab.onos.net.provider.ProviderId;
tomf80c9722014-09-24 14:49:18 -070025import org.onlab.onos.store.AbstractStore;
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -070026import org.onlab.packet.IpAddress;
Ayaka Koshibea9c199f2014-09-16 16:21:40 -070027import org.onlab.packet.MacAddress;
28import org.onlab.packet.VlanId;
Jonathan Hartac60c082014-09-23 08:55:17 -070029import org.slf4j.Logger;
tom7869ad92014-09-09 14:32:08 -070030
tom093340b2014-10-10 00:15:36 -070031import java.util.HashSet;
32import java.util.Map;
33import java.util.Set;
34import java.util.concurrent.ConcurrentHashMap;
35
36import static org.onlab.onos.net.host.HostEvent.Type.*;
37import static org.slf4j.LoggerFactory.getLogger;
Ayaka Koshibee5652752014-09-10 23:27:34 -070038
Yuta HIGUCHIa2639152014-10-14 15:08:10 -070039// TODO: multi-provider, annotation not supported.
tom7869ad92014-09-09 14:32:08 -070040/**
41 * Manages inventory of end-station hosts using trivial in-memory
42 * implementation.
43 */
tom5bcc9462014-09-19 10:11:31 -070044@Component(immediate = true)
45@Service
tomf80c9722014-09-24 14:49:18 -070046public class SimpleHostStore
47 extends AbstractStore<HostEvent, HostStoreDelegate>
48 implements HostStore {
tom7869ad92014-09-09 14:32:08 -070049
tom5bcc9462014-09-19 10:11:31 -070050 private final Logger log = getLogger(getClass());
51
52 // Host inventory
tom093340b2014-10-10 00:15:36 -070053 private final Map<HostId, StoredHost> hosts = new ConcurrentHashMap<>(2000000, 0.75f, 16);
tom7869ad92014-09-09 14:32:08 -070054
tom5bcc9462014-09-19 10:11:31 -070055 // Hosts tracked by their location
Ayaka Koshibee5652752014-09-10 23:27:34 -070056 private final Multimap<ConnectPoint, Host> locations = HashMultimap.create();
tome615ee42014-09-11 10:52:10 -070057
Jonathan Hart43c182c2014-09-23 11:13:42 -070058 private final Map<ConnectPoint, PortAddresses> portAddresses =
59 new ConcurrentHashMap<>();
60
tom5bcc9462014-09-19 10:11:31 -070061 @Activate
62 public void activate() {
63 log.info("Started");
64 }
65
66 @Deactivate
67 public void deactivate() {
68 log.info("Stopped");
69 }
70
71 @Override
72 public HostEvent createOrUpdateHost(ProviderId providerId, HostId hostId,
73 HostDescription hostDescription) {
tom093340b2014-10-10 00:15:36 -070074 StoredHost host = hosts.get(hostId);
Ayaka Koshibee5652752014-09-10 23:27:34 -070075 if (host == null) {
76 return createHost(providerId, hostId, hostDescription);
77 }
78 return updateHost(providerId, host, hostDescription);
79 }
80
81 // creates a new host and sends HOST_ADDED
82 private HostEvent createHost(ProviderId providerId, HostId hostId,
toma56d5fe2014-09-17 11:05:47 -070083 HostDescription descr) {
tom093340b2014-10-10 00:15:36 -070084 StoredHost newhost = new StoredHost(providerId, hostId,
85 descr.hwAddress(),
86 descr.vlan(),
87 descr.location(),
Yuta HIGUCHI5fa3dc02014-10-15 17:08:13 -070088 ImmutableSet.copyOf(descr.ipAddress()));
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070089 synchronized (this) {
Ayaka Koshibee5652752014-09-10 23:27:34 -070090 hosts.put(hostId, newhost);
91 locations.put(descr.location(), newhost);
92 }
93 return new HostEvent(HOST_ADDED, newhost);
94 }
95
96 // checks for type of update to host, sends appropriate event
tom093340b2014-10-10 00:15:36 -070097 private HostEvent updateHost(ProviderId providerId, StoredHost host,
toma56d5fe2014-09-17 11:05:47 -070098 HostDescription descr) {
Ayaka Koshibee5652752014-09-10 23:27:34 -070099 HostEvent event;
toma56d5fe2014-09-17 11:05:47 -0700100 if (!host.location().equals(descr.location())) {
tom093340b2014-10-10 00:15:36 -0700101 host.setLocation(descr.location());
102 return new HostEvent(HOST_MOVED, host);
103 }
toma56d5fe2014-09-17 11:05:47 -0700104
Yuta HIGUCHI5fa3dc02014-10-15 17:08:13 -0700105 if (host.ipAddresses().containsAll(descr.ipAddress())) {
Ayaka Koshibe1a100982014-09-13 19:32:19 -0700106 return null;
Ayaka Koshibee5652752014-09-10 23:27:34 -0700107 }
tom093340b2014-10-10 00:15:36 -0700108
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700109 Set<IpAddress> addresses = new HashSet<>(host.ipAddresses());
Yuta HIGUCHI5fa3dc02014-10-15 17:08:13 -0700110 addresses.addAll(descr.ipAddress());
tom093340b2014-10-10 00:15:36 -0700111 StoredHost updated = new StoredHost(providerId, host.id(),
112 host.mac(), host.vlan(),
113 descr.location(), addresses);
114 event = new HostEvent(HOST_UPDATED, updated);
Ayaka Koshibee5652752014-09-10 23:27:34 -0700115 synchronized (this) {
116 hosts.put(host.id(), updated);
117 locations.remove(host.location(), host);
118 locations.put(updated.location(), updated);
119 }
120 return event;
tom7869ad92014-09-09 14:32:08 -0700121 }
122
tom5bcc9462014-09-19 10:11:31 -0700123 @Override
124 public HostEvent removeHost(HostId hostId) {
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700125 synchronized (this) {
Ayaka Koshibee5652752014-09-10 23:27:34 -0700126 Host host = hosts.remove(hostId);
127 if (host != null) {
128 locations.remove((host.location()), host);
129 return new HostEvent(HOST_REMOVED, host);
130 }
131 return null;
132 }
tom7869ad92014-09-09 14:32:08 -0700133 }
134
tom5bcc9462014-09-19 10:11:31 -0700135 @Override
136 public int getHostCount() {
tom7869ad92014-09-09 14:32:08 -0700137 return hosts.size();
138 }
139
tom5bcc9462014-09-19 10:11:31 -0700140 @Override
141 public Iterable<Host> getHosts() {
tom093340b2014-10-10 00:15:36 -0700142 return ImmutableSet.<Host>copyOf(hosts.values());
tom7869ad92014-09-09 14:32:08 -0700143 }
144
tom5bcc9462014-09-19 10:11:31 -0700145 @Override
146 public Host getHost(HostId hostId) {
Ayaka Koshibee5652752014-09-10 23:27:34 -0700147 return hosts.get(hostId);
tom7869ad92014-09-09 14:32:08 -0700148 }
149
tom5bcc9462014-09-19 10:11:31 -0700150 @Override
151 public Set<Host> getHosts(VlanId vlanId) {
toma56d5fe2014-09-17 11:05:47 -0700152 Set<Host> vlanset = new HashSet<>();
Ayaka Koshibee5652752014-09-10 23:27:34 -0700153 for (Host h : hosts.values()) {
Ayaka Koshibe04a1a4e2014-09-11 14:31:29 -0700154 if (h.vlan().equals(vlanId)) {
Ayaka Koshibee5652752014-09-10 23:27:34 -0700155 vlanset.add(h);
156 }
157 }
158 return vlanset;
tom7869ad92014-09-09 14:32:08 -0700159 }
160
tom5bcc9462014-09-19 10:11:31 -0700161 @Override
162 public Set<Host> getHosts(MacAddress mac) {
Ayaka Koshibee5652752014-09-10 23:27:34 -0700163 Set<Host> macset = new HashSet<>();
164 for (Host h : hosts.values()) {
165 if (h.mac().equals(mac)) {
166 macset.add(h);
167 }
168 }
169 return macset;
tom7869ad92014-09-09 14:32:08 -0700170 }
171
tom5bcc9462014-09-19 10:11:31 -0700172 @Override
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700173 public Set<Host> getHosts(IpAddress ip) {
Ayaka Koshibee5652752014-09-10 23:27:34 -0700174 Set<Host> ipset = new HashSet<>();
175 for (Host h : hosts.values()) {
176 if (h.ipAddresses().contains(ip)) {
177 ipset.add(h);
178 }
179 }
180 return ipset;
tom7869ad92014-09-09 14:32:08 -0700181 }
182
tom5bcc9462014-09-19 10:11:31 -0700183 @Override
184 public Set<Host> getConnectedHosts(ConnectPoint connectPoint) {
Ayaka Koshibee5652752014-09-10 23:27:34 -0700185 return ImmutableSet.copyOf(locations.get(connectPoint));
tom7869ad92014-09-09 14:32:08 -0700186 }
187
tom5bcc9462014-09-19 10:11:31 -0700188 @Override
tom7869ad92014-09-09 14:32:08 -0700189 public Set<Host> getConnectedHosts(DeviceId deviceId) {
Ayaka Koshibee5652752014-09-10 23:27:34 -0700190 Set<Host> hostset = new HashSet<>();
191 for (ConnectPoint p : locations.keySet()) {
192 if (p.deviceId().equals(deviceId)) {
193 hostset.addAll(locations.get(p));
194 }
195 }
196 return hostset;
tom7869ad92014-09-09 14:32:08 -0700197 }
198
Jonathan Hartac60c082014-09-23 08:55:17 -0700199 @Override
200 public void updateAddressBindings(PortAddresses addresses) {
Jonathan Hartc884f1b2014-09-24 11:53:33 -0700201 synchronized (portAddresses) {
202 PortAddresses existing = portAddresses.get(addresses.connectPoint());
203 if (existing == null) {
204 portAddresses.put(addresses.connectPoint(), addresses);
205 } else {
Pavlin Radoslavov76b0ae22014-10-27 15:33:19 -0700206 Set<InterfaceIpAddress> union =
207 Sets.union(existing.ipAddresses(),
208 addresses.ipAddresses()).immutableCopy();
Jonathan Hartc884f1b2014-09-24 11:53:33 -0700209
210 MacAddress newMac = (addresses.mac() == null) ? existing.mac()
211 : addresses.mac();
212
213 PortAddresses newAddresses =
214 new PortAddresses(addresses.connectPoint(), union, newMac);
215
216 portAddresses.put(newAddresses.connectPoint(), newAddresses);
217 }
218 }
Jonathan Hartac60c082014-09-23 08:55:17 -0700219 }
220
221 @Override
Jonathan Hart09585c62014-09-23 16:58:04 -0700222 public void removeAddressBindings(PortAddresses addresses) {
Jonathan Hartc884f1b2014-09-24 11:53:33 -0700223 synchronized (portAddresses) {
224 PortAddresses existing = portAddresses.get(addresses.connectPoint());
225 if (existing != null) {
Pavlin Radoslavov76b0ae22014-10-27 15:33:19 -0700226 Set<InterfaceIpAddress> difference =
227 Sets.difference(existing.ipAddresses(),
228 addresses.ipAddresses()).immutableCopy();
Jonathan Hart09585c62014-09-23 16:58:04 -0700229
Jonathan Hartc884f1b2014-09-24 11:53:33 -0700230 // If they removed the existing mac, set the new mac to null.
231 // Otherwise, keep the existing mac.
232 MacAddress newMac = existing.mac();
233 if (addresses.mac() != null && addresses.mac().equals(existing.mac())) {
234 newMac = null;
235 }
236
237 PortAddresses newAddresses =
238 new PortAddresses(addresses.connectPoint(), difference, newMac);
239
240 portAddresses.put(newAddresses.connectPoint(), newAddresses);
241 }
242 }
Jonathan Hart09585c62014-09-23 16:58:04 -0700243 }
244
245 @Override
246 public void clearAddressBindings(ConnectPoint connectPoint) {
Jonathan Hartc884f1b2014-09-24 11:53:33 -0700247 synchronized (portAddresses) {
248 portAddresses.remove(connectPoint);
249 }
Jonathan Hartac60c082014-09-23 08:55:17 -0700250 }
251
252 @Override
253 public Set<PortAddresses> getAddressBindings() {
Jonathan Hartc884f1b2014-09-24 11:53:33 -0700254 synchronized (portAddresses) {
255 return new HashSet<>(portAddresses.values());
256 }
Jonathan Hartac60c082014-09-23 08:55:17 -0700257 }
258
259 @Override
260 public PortAddresses getAddressBindingsForPort(ConnectPoint connectPoint) {
Jonathan Hartc884f1b2014-09-24 11:53:33 -0700261 PortAddresses addresses;
262
263 synchronized (portAddresses) {
264 addresses = portAddresses.get(connectPoint);
265 }
266
267 if (addresses == null) {
268 addresses = new PortAddresses(connectPoint, null, null);
269 }
270
271 return addresses;
Jonathan Hartac60c082014-09-23 08:55:17 -0700272 }
273
tom093340b2014-10-10 00:15:36 -0700274 // Auxiliary extension to allow location to mutate.
Yuta HIGUCHIe5ca93b2014-10-23 09:49:00 -0700275 private static final class StoredHost extends DefaultHost {
tom093340b2014-10-10 00:15:36 -0700276 private HostLocation location;
277
278 /**
279 * Creates an end-station host using the supplied information.
280 *
281 * @param providerId provider identity
282 * @param id host identifier
283 * @param mac host MAC address
284 * @param vlan host VLAN identifier
285 * @param location host location
286 * @param ips host IP addresses
287 * @param annotations optional key/value annotations
288 */
289 public StoredHost(ProviderId providerId, HostId id,
290 MacAddress mac, VlanId vlan, HostLocation location,
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700291 Set<IpAddress> ips, Annotations... annotations) {
tom093340b2014-10-10 00:15:36 -0700292 super(providerId, id, mac, vlan, location, ips, annotations);
293 this.location = location;
294 }
295
296 void setLocation(HostLocation location) {
297 this.location = location;
298 }
299
300 @Override
301 public HostLocation location() {
302 return location;
303 }
304 }
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700305}