blob: 67ed0506718fe45335ae3f08057b5849e2adb8c7 [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;
Jonathan Hartac60c082014-09-23 08:55:17 -070022import org.onlab.onos.net.host.PortAddresses;
tom7869ad92014-09-09 14:32:08 -070023import org.onlab.onos.net.provider.ProviderId;
tomf80c9722014-09-24 14:49:18 -070024import org.onlab.onos.store.AbstractStore;
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -070025import org.onlab.packet.IpPrefix;
Ayaka Koshibea9c199f2014-09-16 16:21:40 -070026import org.onlab.packet.MacAddress;
27import org.onlab.packet.VlanId;
Jonathan Hartac60c082014-09-23 08:55:17 -070028import org.slf4j.Logger;
tom7869ad92014-09-09 14:32:08 -070029
tom093340b2014-10-10 00:15:36 -070030import java.util.HashSet;
31import java.util.Map;
32import java.util.Set;
33import java.util.concurrent.ConcurrentHashMap;
34
35import static org.onlab.onos.net.host.HostEvent.Type.*;
36import static org.slf4j.LoggerFactory.getLogger;
Ayaka Koshibee5652752014-09-10 23:27:34 -070037
tom7869ad92014-09-09 14:32:08 -070038/**
39 * Manages inventory of end-station hosts using trivial in-memory
40 * implementation.
41 */
tom5bcc9462014-09-19 10:11:31 -070042@Component(immediate = true)
43@Service
tomf80c9722014-09-24 14:49:18 -070044public class SimpleHostStore
45 extends AbstractStore<HostEvent, HostStoreDelegate>
46 implements HostStore {
tom7869ad92014-09-09 14:32:08 -070047
tom5bcc9462014-09-19 10:11:31 -070048 private final Logger log = getLogger(getClass());
49
50 // Host inventory
tom093340b2014-10-10 00:15:36 -070051 private final Map<HostId, StoredHost> hosts = new ConcurrentHashMap<>(2000000, 0.75f, 16);
tom7869ad92014-09-09 14:32:08 -070052
tom5bcc9462014-09-19 10:11:31 -070053 // Hosts tracked by their location
Ayaka Koshibee5652752014-09-10 23:27:34 -070054 private final Multimap<ConnectPoint, Host> locations = HashMultimap.create();
tome615ee42014-09-11 10:52:10 -070055
Jonathan Hart43c182c2014-09-23 11:13:42 -070056 private final Map<ConnectPoint, PortAddresses> portAddresses =
57 new ConcurrentHashMap<>();
58
tom5bcc9462014-09-19 10:11:31 -070059 @Activate
60 public void activate() {
61 log.info("Started");
62 }
63
64 @Deactivate
65 public void deactivate() {
66 log.info("Stopped");
67 }
68
69 @Override
70 public HostEvent createOrUpdateHost(ProviderId providerId, HostId hostId,
71 HostDescription hostDescription) {
tom093340b2014-10-10 00:15:36 -070072 StoredHost host = hosts.get(hostId);
Ayaka Koshibee5652752014-09-10 23:27:34 -070073 if (host == null) {
74 return createHost(providerId, hostId, hostDescription);
75 }
76 return updateHost(providerId, host, hostDescription);
77 }
78
79 // creates a new host and sends HOST_ADDED
80 private HostEvent createHost(ProviderId providerId, HostId hostId,
toma56d5fe2014-09-17 11:05:47 -070081 HostDescription descr) {
tom093340b2014-10-10 00:15:36 -070082 StoredHost newhost = new StoredHost(providerId, hostId,
83 descr.hwAddress(),
84 descr.vlan(),
85 descr.location(),
86 ImmutableSet.of(descr.ipAddress()));
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070087 synchronized (this) {
Ayaka Koshibee5652752014-09-10 23:27:34 -070088 hosts.put(hostId, newhost);
89 locations.put(descr.location(), newhost);
90 }
91 return new HostEvent(HOST_ADDED, newhost);
92 }
93
94 // checks for type of update to host, sends appropriate event
tom093340b2014-10-10 00:15:36 -070095 private HostEvent updateHost(ProviderId providerId, StoredHost host,
toma56d5fe2014-09-17 11:05:47 -070096 HostDescription descr) {
Ayaka Koshibee5652752014-09-10 23:27:34 -070097 HostEvent event;
toma56d5fe2014-09-17 11:05:47 -070098 if (!host.location().equals(descr.location())) {
tom093340b2014-10-10 00:15:36 -070099 host.setLocation(descr.location());
100 return new HostEvent(HOST_MOVED, host);
101 }
toma56d5fe2014-09-17 11:05:47 -0700102
tom093340b2014-10-10 00:15:36 -0700103 if (host.ipAddresses().contains(descr.ipAddress())) {
Ayaka Koshibe1a100982014-09-13 19:32:19 -0700104 return null;
Ayaka Koshibee5652752014-09-10 23:27:34 -0700105 }
tom093340b2014-10-10 00:15:36 -0700106
107 Set<IpPrefix> addresses = new HashSet<>(host.ipAddresses());
108 addresses.add(descr.ipAddress());
109 StoredHost updated = new StoredHost(providerId, host.id(),
110 host.mac(), host.vlan(),
111 descr.location(), addresses);
112 event = new HostEvent(HOST_UPDATED, updated);
Ayaka Koshibee5652752014-09-10 23:27:34 -0700113 synchronized (this) {
114 hosts.put(host.id(), updated);
115 locations.remove(host.location(), host);
116 locations.put(updated.location(), updated);
117 }
118 return event;
tom7869ad92014-09-09 14:32:08 -0700119 }
120
tom5bcc9462014-09-19 10:11:31 -0700121 @Override
122 public HostEvent removeHost(HostId hostId) {
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700123 synchronized (this) {
Ayaka Koshibee5652752014-09-10 23:27:34 -0700124 Host host = hosts.remove(hostId);
125 if (host != null) {
126 locations.remove((host.location()), host);
127 return new HostEvent(HOST_REMOVED, host);
128 }
129 return null;
130 }
tom7869ad92014-09-09 14:32:08 -0700131 }
132
tom5bcc9462014-09-19 10:11:31 -0700133 @Override
134 public int getHostCount() {
tom7869ad92014-09-09 14:32:08 -0700135 return hosts.size();
136 }
137
tom5bcc9462014-09-19 10:11:31 -0700138 @Override
139 public Iterable<Host> getHosts() {
tom093340b2014-10-10 00:15:36 -0700140 return ImmutableSet.<Host>copyOf(hosts.values());
tom7869ad92014-09-09 14:32:08 -0700141 }
142
tom5bcc9462014-09-19 10:11:31 -0700143 @Override
144 public Host getHost(HostId hostId) {
Ayaka Koshibee5652752014-09-10 23:27:34 -0700145 return hosts.get(hostId);
tom7869ad92014-09-09 14:32:08 -0700146 }
147
tom5bcc9462014-09-19 10:11:31 -0700148 @Override
149 public Set<Host> getHosts(VlanId vlanId) {
toma56d5fe2014-09-17 11:05:47 -0700150 Set<Host> vlanset = new HashSet<>();
Ayaka Koshibee5652752014-09-10 23:27:34 -0700151 for (Host h : hosts.values()) {
Ayaka Koshibe04a1a4e2014-09-11 14:31:29 -0700152 if (h.vlan().equals(vlanId)) {
Ayaka Koshibee5652752014-09-10 23:27:34 -0700153 vlanset.add(h);
154 }
155 }
156 return vlanset;
tom7869ad92014-09-09 14:32:08 -0700157 }
158
tom5bcc9462014-09-19 10:11:31 -0700159 @Override
160 public Set<Host> getHosts(MacAddress mac) {
Ayaka Koshibee5652752014-09-10 23:27:34 -0700161 Set<Host> macset = new HashSet<>();
162 for (Host h : hosts.values()) {
163 if (h.mac().equals(mac)) {
164 macset.add(h);
165 }
166 }
167 return macset;
tom7869ad92014-09-09 14:32:08 -0700168 }
169
tom5bcc9462014-09-19 10:11:31 -0700170 @Override
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700171 public Set<Host> getHosts(IpPrefix ip) {
Ayaka Koshibee5652752014-09-10 23:27:34 -0700172 Set<Host> ipset = new HashSet<>();
173 for (Host h : hosts.values()) {
174 if (h.ipAddresses().contains(ip)) {
175 ipset.add(h);
176 }
177 }
178 return ipset;
tom7869ad92014-09-09 14:32:08 -0700179 }
180
tom5bcc9462014-09-19 10:11:31 -0700181 @Override
182 public Set<Host> getConnectedHosts(ConnectPoint connectPoint) {
Ayaka Koshibee5652752014-09-10 23:27:34 -0700183 return ImmutableSet.copyOf(locations.get(connectPoint));
tom7869ad92014-09-09 14:32:08 -0700184 }
185
tom5bcc9462014-09-19 10:11:31 -0700186 @Override
tom7869ad92014-09-09 14:32:08 -0700187 public Set<Host> getConnectedHosts(DeviceId deviceId) {
Ayaka Koshibee5652752014-09-10 23:27:34 -0700188 Set<Host> hostset = new HashSet<>();
189 for (ConnectPoint p : locations.keySet()) {
190 if (p.deviceId().equals(deviceId)) {
191 hostset.addAll(locations.get(p));
192 }
193 }
194 return hostset;
tom7869ad92014-09-09 14:32:08 -0700195 }
196
Jonathan Hartac60c082014-09-23 08:55:17 -0700197 @Override
198 public void updateAddressBindings(PortAddresses addresses) {
Jonathan Hartc884f1b2014-09-24 11:53:33 -0700199 synchronized (portAddresses) {
200 PortAddresses existing = portAddresses.get(addresses.connectPoint());
201 if (existing == null) {
202 portAddresses.put(addresses.connectPoint(), addresses);
203 } else {
204 Set<IpPrefix> union = Sets.union(existing.ips(), addresses.ips())
205 .immutableCopy();
206
207 MacAddress newMac = (addresses.mac() == null) ? existing.mac()
208 : addresses.mac();
209
210 PortAddresses newAddresses =
211 new PortAddresses(addresses.connectPoint(), union, newMac);
212
213 portAddresses.put(newAddresses.connectPoint(), newAddresses);
214 }
215 }
Jonathan Hartac60c082014-09-23 08:55:17 -0700216 }
217
218 @Override
Jonathan Hart09585c62014-09-23 16:58:04 -0700219 public void removeAddressBindings(PortAddresses addresses) {
Jonathan Hartc884f1b2014-09-24 11:53:33 -0700220 synchronized (portAddresses) {
221 PortAddresses existing = portAddresses.get(addresses.connectPoint());
222 if (existing != null) {
223 Set<IpPrefix> difference =
224 Sets.difference(existing.ips(), addresses.ips()).immutableCopy();
Jonathan Hart09585c62014-09-23 16:58:04 -0700225
Jonathan Hartc884f1b2014-09-24 11:53:33 -0700226 // If they removed the existing mac, set the new mac to null.
227 // Otherwise, keep the existing mac.
228 MacAddress newMac = existing.mac();
229 if (addresses.mac() != null && addresses.mac().equals(existing.mac())) {
230 newMac = null;
231 }
232
233 PortAddresses newAddresses =
234 new PortAddresses(addresses.connectPoint(), difference, newMac);
235
236 portAddresses.put(newAddresses.connectPoint(), newAddresses);
237 }
238 }
Jonathan Hart09585c62014-09-23 16:58:04 -0700239 }
240
241 @Override
242 public void clearAddressBindings(ConnectPoint connectPoint) {
Jonathan Hartc884f1b2014-09-24 11:53:33 -0700243 synchronized (portAddresses) {
244 portAddresses.remove(connectPoint);
245 }
Jonathan Hartac60c082014-09-23 08:55:17 -0700246 }
247
248 @Override
249 public Set<PortAddresses> getAddressBindings() {
Jonathan Hartc884f1b2014-09-24 11:53:33 -0700250 synchronized (portAddresses) {
251 return new HashSet<>(portAddresses.values());
252 }
Jonathan Hartac60c082014-09-23 08:55:17 -0700253 }
254
255 @Override
256 public PortAddresses getAddressBindingsForPort(ConnectPoint connectPoint) {
Jonathan Hartc884f1b2014-09-24 11:53:33 -0700257 PortAddresses addresses;
258
259 synchronized (portAddresses) {
260 addresses = portAddresses.get(connectPoint);
261 }
262
263 if (addresses == null) {
264 addresses = new PortAddresses(connectPoint, null, null);
265 }
266
267 return addresses;
Jonathan Hartac60c082014-09-23 08:55:17 -0700268 }
269
tom093340b2014-10-10 00:15:36 -0700270 // Auxiliary extension to allow location to mutate.
271 private class StoredHost extends DefaultHost {
272 private HostLocation location;
273
274 /**
275 * Creates an end-station host using the supplied information.
276 *
277 * @param providerId provider identity
278 * @param id host identifier
279 * @param mac host MAC address
280 * @param vlan host VLAN identifier
281 * @param location host location
282 * @param ips host IP addresses
283 * @param annotations optional key/value annotations
284 */
285 public StoredHost(ProviderId providerId, HostId id,
286 MacAddress mac, VlanId vlan, HostLocation location,
287 Set<IpPrefix> ips, Annotations... annotations) {
288 super(providerId, id, mac, vlan, location, ips, annotations);
289 this.location = location;
290 }
291
292 void setLocation(HostLocation location) {
293 this.location = location;
294 }
295
296 @Override
297 public HostLocation location() {
298 return location;
299 }
300 }
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700301}