blob: 6c27ea842a5ab87a3f7e61e247f808207ace981b [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
2 * Copyright 2014 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
tomea961ff2014-10-01 12:45:15 -070016package org.onlab.onos.store.trivial.impl;
tom7869ad92014-09-09 14:32:08 -070017
tom093340b2014-10-10 00:15:36 -070018import com.google.common.collect.HashMultimap;
19import com.google.common.collect.ImmutableSet;
20import com.google.common.collect.Multimap;
21import com.google.common.collect.Sets;
tom5bcc9462014-09-19 10:11:31 -070022import org.apache.felix.scr.annotations.Activate;
23import org.apache.felix.scr.annotations.Component;
24import org.apache.felix.scr.annotations.Deactivate;
25import org.apache.felix.scr.annotations.Service;
tom093340b2014-10-10 00:15:36 -070026import org.onlab.onos.net.Annotations;
tom7869ad92014-09-09 14:32:08 -070027import org.onlab.onos.net.ConnectPoint;
Ayaka Koshibee5652752014-09-10 23:27:34 -070028import org.onlab.onos.net.DefaultHost;
tom7869ad92014-09-09 14:32:08 -070029import org.onlab.onos.net.DeviceId;
30import org.onlab.onos.net.Host;
31import org.onlab.onos.net.HostId;
tom093340b2014-10-10 00:15:36 -070032import org.onlab.onos.net.HostLocation;
tom7869ad92014-09-09 14:32:08 -070033import org.onlab.onos.net.host.HostDescription;
34import org.onlab.onos.net.host.HostEvent;
tom5bcc9462014-09-19 10:11:31 -070035import org.onlab.onos.net.host.HostStore;
tomf80c9722014-09-24 14:49:18 -070036import org.onlab.onos.net.host.HostStoreDelegate;
Pavlin Radoslavov76b0ae22014-10-27 15:33:19 -070037import org.onlab.onos.net.host.InterfaceIpAddress;
Jonathan Hartac60c082014-09-23 08:55:17 -070038import org.onlab.onos.net.host.PortAddresses;
tom7869ad92014-09-09 14:32:08 -070039import org.onlab.onos.net.provider.ProviderId;
tomf80c9722014-09-24 14:49:18 -070040import org.onlab.onos.store.AbstractStore;
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -070041import org.onlab.packet.IpAddress;
Ayaka Koshibea9c199f2014-09-16 16:21:40 -070042import org.onlab.packet.MacAddress;
43import org.onlab.packet.VlanId;
Jonathan Hartac60c082014-09-23 08:55:17 -070044import org.slf4j.Logger;
tom7869ad92014-09-09 14:32:08 -070045
tom093340b2014-10-10 00:15:36 -070046import java.util.HashSet;
47import java.util.Map;
48import java.util.Set;
49import java.util.concurrent.ConcurrentHashMap;
50
51import static org.onlab.onos.net.host.HostEvent.Type.*;
52import static org.slf4j.LoggerFactory.getLogger;
Ayaka Koshibee5652752014-09-10 23:27:34 -070053
Yuta HIGUCHIa2639152014-10-14 15:08:10 -070054// TODO: multi-provider, annotation not supported.
tom7869ad92014-09-09 14:32:08 -070055/**
56 * Manages inventory of end-station hosts using trivial in-memory
57 * implementation.
58 */
tom5bcc9462014-09-19 10:11:31 -070059@Component(immediate = true)
60@Service
tomf80c9722014-09-24 14:49:18 -070061public class SimpleHostStore
62 extends AbstractStore<HostEvent, HostStoreDelegate>
63 implements HostStore {
tom7869ad92014-09-09 14:32:08 -070064
tom5bcc9462014-09-19 10:11:31 -070065 private final Logger log = getLogger(getClass());
66
67 // Host inventory
tom093340b2014-10-10 00:15:36 -070068 private final Map<HostId, StoredHost> hosts = new ConcurrentHashMap<>(2000000, 0.75f, 16);
tom7869ad92014-09-09 14:32:08 -070069
tom5bcc9462014-09-19 10:11:31 -070070 // Hosts tracked by their location
Ayaka Koshibee5652752014-09-10 23:27:34 -070071 private final Multimap<ConnectPoint, Host> locations = HashMultimap.create();
tome615ee42014-09-11 10:52:10 -070072
Jonathan Hart43c182c2014-09-23 11:13:42 -070073 private final Map<ConnectPoint, PortAddresses> portAddresses =
74 new ConcurrentHashMap<>();
75
tom5bcc9462014-09-19 10:11:31 -070076 @Activate
77 public void activate() {
78 log.info("Started");
79 }
80
81 @Deactivate
82 public void deactivate() {
83 log.info("Stopped");
84 }
85
86 @Override
87 public HostEvent createOrUpdateHost(ProviderId providerId, HostId hostId,
88 HostDescription hostDescription) {
tom093340b2014-10-10 00:15:36 -070089 StoredHost host = hosts.get(hostId);
Ayaka Koshibee5652752014-09-10 23:27:34 -070090 if (host == null) {
91 return createHost(providerId, hostId, hostDescription);
92 }
93 return updateHost(providerId, host, hostDescription);
94 }
95
96 // creates a new host and sends HOST_ADDED
97 private HostEvent createHost(ProviderId providerId, HostId hostId,
toma56d5fe2014-09-17 11:05:47 -070098 HostDescription descr) {
tom093340b2014-10-10 00:15:36 -070099 StoredHost newhost = new StoredHost(providerId, hostId,
100 descr.hwAddress(),
101 descr.vlan(),
102 descr.location(),
Yuta HIGUCHI5fa3dc02014-10-15 17:08:13 -0700103 ImmutableSet.copyOf(descr.ipAddress()));
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700104 synchronized (this) {
Ayaka Koshibee5652752014-09-10 23:27:34 -0700105 hosts.put(hostId, newhost);
106 locations.put(descr.location(), newhost);
107 }
108 return new HostEvent(HOST_ADDED, newhost);
109 }
110
111 // checks for type of update to host, sends appropriate event
tom093340b2014-10-10 00:15:36 -0700112 private HostEvent updateHost(ProviderId providerId, StoredHost host,
toma56d5fe2014-09-17 11:05:47 -0700113 HostDescription descr) {
Ayaka Koshibee5652752014-09-10 23:27:34 -0700114 HostEvent event;
toma56d5fe2014-09-17 11:05:47 -0700115 if (!host.location().equals(descr.location())) {
tom093340b2014-10-10 00:15:36 -0700116 host.setLocation(descr.location());
117 return new HostEvent(HOST_MOVED, host);
118 }
toma56d5fe2014-09-17 11:05:47 -0700119
Yuta HIGUCHI5fa3dc02014-10-15 17:08:13 -0700120 if (host.ipAddresses().containsAll(descr.ipAddress())) {
Ayaka Koshibe1a100982014-09-13 19:32:19 -0700121 return null;
Ayaka Koshibee5652752014-09-10 23:27:34 -0700122 }
tom093340b2014-10-10 00:15:36 -0700123
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700124 Set<IpAddress> addresses = new HashSet<>(host.ipAddresses());
Yuta HIGUCHI5fa3dc02014-10-15 17:08:13 -0700125 addresses.addAll(descr.ipAddress());
tom093340b2014-10-10 00:15:36 -0700126 StoredHost updated = new StoredHost(providerId, host.id(),
127 host.mac(), host.vlan(),
128 descr.location(), addresses);
129 event = new HostEvent(HOST_UPDATED, updated);
Ayaka Koshibee5652752014-09-10 23:27:34 -0700130 synchronized (this) {
131 hosts.put(host.id(), updated);
132 locations.remove(host.location(), host);
133 locations.put(updated.location(), updated);
134 }
135 return event;
tom7869ad92014-09-09 14:32:08 -0700136 }
137
tom5bcc9462014-09-19 10:11:31 -0700138 @Override
139 public HostEvent removeHost(HostId hostId) {
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700140 synchronized (this) {
Ayaka Koshibee5652752014-09-10 23:27:34 -0700141 Host host = hosts.remove(hostId);
142 if (host != null) {
143 locations.remove((host.location()), host);
144 return new HostEvent(HOST_REMOVED, host);
145 }
146 return null;
147 }
tom7869ad92014-09-09 14:32:08 -0700148 }
149
tom5bcc9462014-09-19 10:11:31 -0700150 @Override
151 public int getHostCount() {
tom7869ad92014-09-09 14:32:08 -0700152 return hosts.size();
153 }
154
tom5bcc9462014-09-19 10:11:31 -0700155 @Override
156 public Iterable<Host> getHosts() {
tom093340b2014-10-10 00:15:36 -0700157 return ImmutableSet.<Host>copyOf(hosts.values());
tom7869ad92014-09-09 14:32:08 -0700158 }
159
tom5bcc9462014-09-19 10:11:31 -0700160 @Override
161 public Host getHost(HostId hostId) {
Ayaka Koshibee5652752014-09-10 23:27:34 -0700162 return hosts.get(hostId);
tom7869ad92014-09-09 14:32:08 -0700163 }
164
tom5bcc9462014-09-19 10:11:31 -0700165 @Override
166 public Set<Host> getHosts(VlanId vlanId) {
toma56d5fe2014-09-17 11:05:47 -0700167 Set<Host> vlanset = new HashSet<>();
Ayaka Koshibee5652752014-09-10 23:27:34 -0700168 for (Host h : hosts.values()) {
Ayaka Koshibe04a1a4e2014-09-11 14:31:29 -0700169 if (h.vlan().equals(vlanId)) {
Ayaka Koshibee5652752014-09-10 23:27:34 -0700170 vlanset.add(h);
171 }
172 }
173 return vlanset;
tom7869ad92014-09-09 14:32:08 -0700174 }
175
tom5bcc9462014-09-19 10:11:31 -0700176 @Override
177 public Set<Host> getHosts(MacAddress mac) {
Ayaka Koshibee5652752014-09-10 23:27:34 -0700178 Set<Host> macset = new HashSet<>();
179 for (Host h : hosts.values()) {
180 if (h.mac().equals(mac)) {
181 macset.add(h);
182 }
183 }
184 return macset;
tom7869ad92014-09-09 14:32:08 -0700185 }
186
tom5bcc9462014-09-19 10:11:31 -0700187 @Override
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700188 public Set<Host> getHosts(IpAddress ip) {
Ayaka Koshibee5652752014-09-10 23:27:34 -0700189 Set<Host> ipset = new HashSet<>();
190 for (Host h : hosts.values()) {
191 if (h.ipAddresses().contains(ip)) {
192 ipset.add(h);
193 }
194 }
195 return ipset;
tom7869ad92014-09-09 14:32:08 -0700196 }
197
tom5bcc9462014-09-19 10:11:31 -0700198 @Override
199 public Set<Host> getConnectedHosts(ConnectPoint connectPoint) {
Ayaka Koshibee5652752014-09-10 23:27:34 -0700200 return ImmutableSet.copyOf(locations.get(connectPoint));
tom7869ad92014-09-09 14:32:08 -0700201 }
202
tom5bcc9462014-09-19 10:11:31 -0700203 @Override
tom7869ad92014-09-09 14:32:08 -0700204 public Set<Host> getConnectedHosts(DeviceId deviceId) {
Ayaka Koshibee5652752014-09-10 23:27:34 -0700205 Set<Host> hostset = new HashSet<>();
206 for (ConnectPoint p : locations.keySet()) {
207 if (p.deviceId().equals(deviceId)) {
208 hostset.addAll(locations.get(p));
209 }
210 }
211 return hostset;
tom7869ad92014-09-09 14:32:08 -0700212 }
213
Jonathan Hartac60c082014-09-23 08:55:17 -0700214 @Override
215 public void updateAddressBindings(PortAddresses addresses) {
Jonathan Hartc884f1b2014-09-24 11:53:33 -0700216 synchronized (portAddresses) {
217 PortAddresses existing = portAddresses.get(addresses.connectPoint());
218 if (existing == null) {
219 portAddresses.put(addresses.connectPoint(), addresses);
220 } else {
Pavlin Radoslavov76b0ae22014-10-27 15:33:19 -0700221 Set<InterfaceIpAddress> union =
222 Sets.union(existing.ipAddresses(),
223 addresses.ipAddresses()).immutableCopy();
Jonathan Hartc884f1b2014-09-24 11:53:33 -0700224
225 MacAddress newMac = (addresses.mac() == null) ? existing.mac()
226 : addresses.mac();
227
228 PortAddresses newAddresses =
229 new PortAddresses(addresses.connectPoint(), union, newMac);
230
231 portAddresses.put(newAddresses.connectPoint(), newAddresses);
232 }
233 }
Jonathan Hartac60c082014-09-23 08:55:17 -0700234 }
235
236 @Override
Jonathan Hart09585c62014-09-23 16:58:04 -0700237 public void removeAddressBindings(PortAddresses addresses) {
Jonathan Hartc884f1b2014-09-24 11:53:33 -0700238 synchronized (portAddresses) {
239 PortAddresses existing = portAddresses.get(addresses.connectPoint());
240 if (existing != null) {
Pavlin Radoslavov76b0ae22014-10-27 15:33:19 -0700241 Set<InterfaceIpAddress> difference =
242 Sets.difference(existing.ipAddresses(),
243 addresses.ipAddresses()).immutableCopy();
Jonathan Hart09585c62014-09-23 16:58:04 -0700244
Jonathan Hartc884f1b2014-09-24 11:53:33 -0700245 // If they removed the existing mac, set the new mac to null.
246 // Otherwise, keep the existing mac.
247 MacAddress newMac = existing.mac();
248 if (addresses.mac() != null && addresses.mac().equals(existing.mac())) {
249 newMac = null;
250 }
251
252 PortAddresses newAddresses =
253 new PortAddresses(addresses.connectPoint(), difference, newMac);
254
255 portAddresses.put(newAddresses.connectPoint(), newAddresses);
256 }
257 }
Jonathan Hart09585c62014-09-23 16:58:04 -0700258 }
259
260 @Override
261 public void clearAddressBindings(ConnectPoint connectPoint) {
Jonathan Hartc884f1b2014-09-24 11:53:33 -0700262 synchronized (portAddresses) {
263 portAddresses.remove(connectPoint);
264 }
Jonathan Hartac60c082014-09-23 08:55:17 -0700265 }
266
267 @Override
268 public Set<PortAddresses> getAddressBindings() {
Jonathan Hartc884f1b2014-09-24 11:53:33 -0700269 synchronized (portAddresses) {
270 return new HashSet<>(portAddresses.values());
271 }
Jonathan Hartac60c082014-09-23 08:55:17 -0700272 }
273
274 @Override
275 public PortAddresses getAddressBindingsForPort(ConnectPoint connectPoint) {
Jonathan Hartc884f1b2014-09-24 11:53:33 -0700276 PortAddresses addresses;
277
278 synchronized (portAddresses) {
279 addresses = portAddresses.get(connectPoint);
280 }
281
282 if (addresses == null) {
283 addresses = new PortAddresses(connectPoint, null, null);
284 }
285
286 return addresses;
Jonathan Hartac60c082014-09-23 08:55:17 -0700287 }
288
tom093340b2014-10-10 00:15:36 -0700289 // Auxiliary extension to allow location to mutate.
Yuta HIGUCHIe5ca93b2014-10-23 09:49:00 -0700290 private static final class StoredHost extends DefaultHost {
tom093340b2014-10-10 00:15:36 -0700291 private HostLocation location;
292
293 /**
294 * Creates an end-station host using the supplied information.
295 *
296 * @param providerId provider identity
297 * @param id host identifier
298 * @param mac host MAC address
299 * @param vlan host VLAN identifier
300 * @param location host location
301 * @param ips host IP addresses
302 * @param annotations optional key/value annotations
303 */
304 public StoredHost(ProviderId providerId, HostId id,
305 MacAddress mac, VlanId vlan, HostLocation location,
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700306 Set<IpAddress> ips, Annotations... annotations) {
tom093340b2014-10-10 00:15:36 -0700307 super(providerId, id, mac, vlan, location, ips, annotations);
308 this.location = location;
309 }
310
311 void setLocation(HostLocation location) {
312 this.location = location;
313 }
314
315 @Override
316 public HostLocation location() {
317 return location;
318 }
319 }
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700320}