blob: 9362156ace9ffdf474a893513918889e391dd3d2 [file] [log] [blame]
alshabib339a3d92014-09-26 17:54:32 -07001package org.onlab.onos.store.host.impl;
2
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;
alshabib339a3d92014-09-26 17:54:32 -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;
alshabib339a3d92014-09-26 17:54:32 -070012import org.onlab.onos.net.ConnectPoint;
13import org.onlab.onos.net.DefaultHost;
14import 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;
alshabib339a3d92014-09-26 17:54:32 -070018import org.onlab.onos.net.host.HostDescription;
19import org.onlab.onos.net.host.HostEvent;
20import org.onlab.onos.net.host.HostStore;
21import org.onlab.onos.net.host.HostStoreDelegate;
22import org.onlab.onos.net.host.PortAddresses;
23import org.onlab.onos.net.provider.ProviderId;
24import org.onlab.onos.store.AbstractStore;
25import org.onlab.packet.IpPrefix;
26import org.onlab.packet.MacAddress;
27import org.onlab.packet.VlanId;
28import org.slf4j.Logger;
29
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;
alshabib339a3d92014-09-26 17:54:32 -070037
38/**
39 * Manages inventory of end-station hosts using trivial in-memory
40 * implementation.
41 */
42//FIXME: I LIE I AM NOT DISTRIBUTED
43@Component(immediate = true)
44@Service
45public class DistributedHostStore
tom093340b2014-10-10 00:15:36 -070046 extends AbstractStore<HostEvent, HostStoreDelegate>
47 implements HostStore {
alshabib339a3d92014-09-26 17:54:32 -070048
49 private final Logger log = getLogger(getClass());
50
51 // Host inventory
tom093340b2014-10-10 00:15:36 -070052 private final Map<HostId, StoredHost> hosts = new ConcurrentHashMap<>(2000000, 0.75f, 16);
alshabib339a3d92014-09-26 17:54:32 -070053
54 // Hosts tracked by their location
55 private final Multimap<ConnectPoint, Host> locations = HashMultimap.create();
56
57 private final Map<ConnectPoint, PortAddresses> portAddresses =
58 new ConcurrentHashMap<>();
59
60 @Activate
61 public void activate() {
62 log.info("Started");
63 }
64
65 @Deactivate
66 public void deactivate() {
67 log.info("Stopped");
68 }
69
70 @Override
71 public HostEvent createOrUpdateHost(ProviderId providerId, HostId hostId,
tom093340b2014-10-10 00:15:36 -070072 HostDescription hostDescription) {
73 StoredHost host = hosts.get(hostId);
alshabib339a3d92014-09-26 17:54:32 -070074 if (host == null) {
75 return createHost(providerId, hostId, hostDescription);
76 }
77 return updateHost(providerId, host, hostDescription);
78 }
79
80 // creates a new host and sends HOST_ADDED
81 private HostEvent createHost(ProviderId providerId, HostId hostId,
tom093340b2014-10-10 00:15:36 -070082 HostDescription descr) {
83 StoredHost newhost = new StoredHost(providerId, hostId,
84 descr.hwAddress(),
85 descr.vlan(),
86 descr.location(),
87 ImmutableSet.of(descr.ipAddress()));
alshabib339a3d92014-09-26 17:54:32 -070088 synchronized (this) {
89 hosts.put(hostId, newhost);
90 locations.put(descr.location(), newhost);
91 }
92 return new HostEvent(HOST_ADDED, newhost);
93 }
94
95 // checks for type of update to host, sends appropriate event
tom093340b2014-10-10 00:15:36 -070096 private HostEvent updateHost(ProviderId providerId, StoredHost host,
97 HostDescription descr) {
alshabib339a3d92014-09-26 17:54:32 -070098 HostEvent event;
99 if (!host.location().equals(descr.location())) {
tom093340b2014-10-10 00:15:36 -0700100 host.setLocation(descr.location());
101 return new HostEvent(HOST_MOVED, host);
102 }
alshabib339a3d92014-09-26 17:54:32 -0700103
tom093340b2014-10-10 00:15:36 -0700104 if (host.ipAddresses().contains(descr.ipAddress())) {
alshabib339a3d92014-09-26 17:54:32 -0700105 return null;
106 }
tom093340b2014-10-10 00:15:36 -0700107
108 Set<IpPrefix> addresses = new HashSet<>(host.ipAddresses());
109 addresses.add(descr.ipAddress());
110 StoredHost updated = new StoredHost(providerId, host.id(),
111 host.mac(), host.vlan(),
112 descr.location(), addresses);
113 event = new HostEvent(HOST_UPDATED, updated);
alshabib339a3d92014-09-26 17:54:32 -0700114 synchronized (this) {
115 hosts.put(host.id(), updated);
116 locations.remove(host.location(), host);
117 locations.put(updated.location(), updated);
118 }
119 return event;
120 }
121
122 @Override
123 public HostEvent removeHost(HostId hostId) {
124 synchronized (this) {
125 Host host = hosts.remove(hostId);
126 if (host != null) {
127 locations.remove((host.location()), host);
128 return new HostEvent(HOST_REMOVED, host);
129 }
130 return null;
131 }
132 }
133
134 @Override
135 public int getHostCount() {
136 return hosts.size();
137 }
138
139 @Override
140 public Iterable<Host> getHosts() {
tom093340b2014-10-10 00:15:36 -0700141 return ImmutableSet.<Host>copyOf(hosts.values());
alshabib339a3d92014-09-26 17:54:32 -0700142 }
143
144 @Override
145 public Host getHost(HostId hostId) {
146 return hosts.get(hostId);
147 }
148
149 @Override
150 public Set<Host> getHosts(VlanId vlanId) {
151 Set<Host> vlanset = new HashSet<>();
152 for (Host h : hosts.values()) {
153 if (h.vlan().equals(vlanId)) {
154 vlanset.add(h);
155 }
156 }
157 return vlanset;
158 }
159
160 @Override
161 public Set<Host> getHosts(MacAddress mac) {
162 Set<Host> macset = new HashSet<>();
163 for (Host h : hosts.values()) {
164 if (h.mac().equals(mac)) {
165 macset.add(h);
166 }
167 }
168 return macset;
169 }
170
171 @Override
172 public Set<Host> getHosts(IpPrefix ip) {
173 Set<Host> ipset = new HashSet<>();
174 for (Host h : hosts.values()) {
175 if (h.ipAddresses().contains(ip)) {
176 ipset.add(h);
177 }
178 }
179 return ipset;
180 }
181
182 @Override
183 public Set<Host> getConnectedHosts(ConnectPoint connectPoint) {
184 return ImmutableSet.copyOf(locations.get(connectPoint));
185 }
186
187 @Override
188 public Set<Host> getConnectedHosts(DeviceId deviceId) {
189 Set<Host> hostset = new HashSet<>();
190 for (ConnectPoint p : locations.keySet()) {
191 if (p.deviceId().equals(deviceId)) {
192 hostset.addAll(locations.get(p));
193 }
194 }
195 return hostset;
196 }
197
198 @Override
199 public void updateAddressBindings(PortAddresses addresses) {
200 synchronized (portAddresses) {
201 PortAddresses existing = portAddresses.get(addresses.connectPoint());
202 if (existing == null) {
203 portAddresses.put(addresses.connectPoint(), addresses);
204 } else {
205 Set<IpPrefix> union = Sets.union(existing.ips(), addresses.ips())
206 .immutableCopy();
207
208 MacAddress newMac = (addresses.mac() == null) ? existing.mac()
209 : addresses.mac();
210
211 PortAddresses newAddresses =
212 new PortAddresses(addresses.connectPoint(), union, newMac);
213
214 portAddresses.put(newAddresses.connectPoint(), newAddresses);
215 }
216 }
217 }
218
219 @Override
220 public void removeAddressBindings(PortAddresses addresses) {
221 synchronized (portAddresses) {
222 PortAddresses existing = portAddresses.get(addresses.connectPoint());
223 if (existing != null) {
224 Set<IpPrefix> difference =
225 Sets.difference(existing.ips(), addresses.ips()).immutableCopy();
226
227 // If they removed the existing mac, set the new mac to null.
228 // Otherwise, keep the existing mac.
229 MacAddress newMac = existing.mac();
230 if (addresses.mac() != null && addresses.mac().equals(existing.mac())) {
231 newMac = null;
232 }
233
234 PortAddresses newAddresses =
235 new PortAddresses(addresses.connectPoint(), difference, newMac);
236
237 portAddresses.put(newAddresses.connectPoint(), newAddresses);
238 }
239 }
240 }
241
242 @Override
243 public void clearAddressBindings(ConnectPoint connectPoint) {
244 synchronized (portAddresses) {
245 portAddresses.remove(connectPoint);
246 }
247 }
248
249 @Override
250 public Set<PortAddresses> getAddressBindings() {
251 synchronized (portAddresses) {
252 return new HashSet<>(portAddresses.values());
253 }
254 }
255
256 @Override
257 public PortAddresses getAddressBindingsForPort(ConnectPoint connectPoint) {
258 PortAddresses addresses;
259
260 synchronized (portAddresses) {
261 addresses = portAddresses.get(connectPoint);
262 }
263
264 if (addresses == null) {
265 addresses = new PortAddresses(connectPoint, null, null);
266 }
267
268 return addresses;
269 }
270
tom093340b2014-10-10 00:15:36 -0700271 // Auxiliary extension to allow location to mutate.
272 private class StoredHost extends DefaultHost {
273 private HostLocation location;
274
275 /**
276 * Creates an end-station host using the supplied information.
277 *
278 * @param providerId provider identity
279 * @param id host identifier
280 * @param mac host MAC address
281 * @param vlan host VLAN identifier
282 * @param location host location
283 * @param ips host IP addresses
284 * @param annotations optional key/value annotations
285 */
286 public StoredHost(ProviderId providerId, HostId id,
287 MacAddress mac, VlanId vlan, HostLocation location,
288 Set<IpPrefix> ips, Annotations... annotations) {
289 super(providerId, id, mac, vlan, location, ips, annotations);
290 this.location = location;
291 }
292
293 void setLocation(HostLocation location) {
294 this.location = location;
295 }
296
297 @Override
298 public HostLocation location() {
299 return location;
300 }
301 }
alshabib339a3d92014-09-26 17:54:32 -0700302}