blob: ffe6c41654a5b201687084e515d397457dddd7de [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07002 * Copyright 2014 Open Networking Laboratory
Thomas Vachuska781d18b2014-10-27 10:31:25 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * 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
Thomas Vachuska781d18b2014-10-27 10:31:25 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * 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.
Thomas Vachuska781d18b2014-10-27 10:31:25 -070015 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.provider.host.impl;
alshabibe1cf87d2014-10-17 09:23:50 -070017
18import org.apache.felix.scr.annotations.Activate;
19import org.apache.felix.scr.annotations.Component;
20import org.apache.felix.scr.annotations.Deactivate;
Thomas Vachuska33601602014-11-19 03:32:15 -080021import org.apache.felix.scr.annotations.Modified;
22import org.apache.felix.scr.annotations.Property;
alshabibe1cf87d2014-10-17 09:23:50 -070023import org.apache.felix.scr.annotations.Reference;
24import org.apache.felix.scr.annotations.ReferenceCardinality;
Brian O'Connorabafb502014-12-02 22:26:20 -080025import org.onosproject.net.ConnectPoint;
26import org.onosproject.net.DeviceId;
27import org.onosproject.net.Host;
28import org.onosproject.net.HostId;
29import org.onosproject.net.HostLocation;
30import org.onosproject.net.device.DeviceEvent;
31import org.onosproject.net.device.DeviceListener;
32import org.onosproject.net.device.DeviceService;
33import org.onosproject.net.host.DefaultHostDescription;
34import org.onosproject.net.host.HostDescription;
35import org.onosproject.net.host.HostProvider;
36import org.onosproject.net.host.HostProviderRegistry;
37import org.onosproject.net.host.HostProviderService;
38import org.onosproject.net.host.HostService;
39import org.onosproject.net.packet.PacketContext;
40import org.onosproject.net.packet.PacketProcessor;
41import org.onosproject.net.packet.PacketService;
42import org.onosproject.net.provider.AbstractProvider;
43import org.onosproject.net.provider.ProviderId;
44import org.onosproject.net.topology.Topology;
45import org.onosproject.net.topology.TopologyService;
alshabibe1cf87d2014-10-17 09:23:50 -070046import org.onlab.packet.ARP;
47import org.onlab.packet.Ethernet;
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -070048import org.onlab.packet.IpAddress;
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +080049import org.onlab.packet.IPacket;
50import org.onlab.packet.IPv6;
Charles M.C. Chanea5aa472015-01-03 13:40:39 +080051import org.onlab.packet.ndp.NeighborAdvertisement;
52import org.onlab.packet.ndp.NeighborSolicitation;
alshabibe1cf87d2014-10-17 09:23:50 -070053import org.onlab.packet.VlanId;
Thomas Vachuska33601602014-11-19 03:32:15 -080054import org.osgi.service.component.ComponentContext;
alshabibe1cf87d2014-10-17 09:23:50 -070055import org.slf4j.Logger;
56
Thomas Vachuska33601602014-11-19 03:32:15 -080057import java.util.Dictionary;
58import java.util.Set;
59
60import static org.slf4j.LoggerFactory.getLogger;
61
alshabibe1cf87d2014-10-17 09:23:50 -070062/**
63 * Provider which uses an OpenFlow controller to detect network
64 * end-station hosts.
65 */
66@Component(immediate = true)
67public class HostLocationProvider extends AbstractProvider implements HostProvider {
68
69 private final Logger log = getLogger(getClass());
70
71 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
72 protected HostProviderRegistry providerRegistry;
73
74 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
75 protected PacketService pktService;
76
77 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
78 protected TopologyService topologyService;
79
Thomas Vachuska33601602014-11-19 03:32:15 -080080 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
81 protected HostService hostService;
82
83 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
84 protected DeviceService deviceService;
85
alshabibe1cf87d2014-10-17 09:23:50 -070086 private HostProviderService providerService;
87
88 private final InternalHostProvider processor = new InternalHostProvider();
Thomas Vachuska33601602014-11-19 03:32:15 -080089 private final DeviceListener deviceListener = new InternalDeviceListener();
90
91 @Property(name = "hostRemovalEnabled", boolValue = true,
92 label = "Enable host removal on port/device down events")
93 private boolean hostRemovalEnabled = true;
alshabibe1cf87d2014-10-17 09:23:50 -070094
95
96 /**
97 * Creates an OpenFlow host provider.
98 */
99 public HostLocationProvider() {
Brian O'Connorabafb502014-12-02 22:26:20 -0800100 super(new ProviderId("of", "org.onosproject.provider.host"));
alshabibe1cf87d2014-10-17 09:23:50 -0700101 }
102
103 @Activate
Thomas Vachuska33601602014-11-19 03:32:15 -0800104 public void activate(ComponentContext context) {
105 modified(context);
alshabibe1cf87d2014-10-17 09:23:50 -0700106 providerService = providerRegistry.register(this);
107 pktService.addProcessor(processor, 1);
Thomas Vachuska33601602014-11-19 03:32:15 -0800108 deviceService.addListener(deviceListener);
alshabibe1cf87d2014-10-17 09:23:50 -0700109 log.info("Started");
110 }
111
112 @Deactivate
113 public void deactivate() {
114 providerRegistry.unregister(this);
115 pktService.removeProcessor(processor);
alshabibbfc6b722014-11-29 12:53:48 -0800116 deviceService.removeListener(deviceListener);
alshabibe1cf87d2014-10-17 09:23:50 -0700117 providerService = null;
118 log.info("Stopped");
119 }
120
Thomas Vachuska33601602014-11-19 03:32:15 -0800121 @Modified
122 public void modified(ComponentContext context) {
123 Dictionary properties = context.getProperties();
124 try {
125 String flag = (String) properties.get("hostRemovalEnabled");
126 if (flag != null) {
127 hostRemovalEnabled = flag.equals("true");
128 }
129 } catch (Exception e) {
130 hostRemovalEnabled = true;
131 }
132 log.info("Host removal is {}", hostRemovalEnabled ? "enabled" : "disabled");
133 }
134
alshabibe1cf87d2014-10-17 09:23:50 -0700135 @Override
136 public void triggerProbe(Host host) {
137 log.info("Triggering probe on device {}", host);
138 }
139
140 private class InternalHostProvider implements PacketProcessor {
141
142 @Override
143 public void process(PacketContext context) {
alshabib4a179dc2014-10-17 17:17:01 -0700144 if (context == null) {
145 return;
146 }
alshabibe1cf87d2014-10-17 09:23:50 -0700147 Ethernet eth = context.inPacket().parsed();
148
149 VlanId vlan = VlanId.vlanId(eth.getVlanID());
150 ConnectPoint heardOn = context.inPacket().receivedFrom();
151
152 // If this is not an edge port, bail out.
153 Topology topology = topologyService.currentTopology();
154 if (topologyService.isInfrastructure(topology, heardOn)) {
155 return;
156 }
157
158 HostLocation hloc = new HostLocation(heardOn, System.currentTimeMillis());
159
160 HostId hid = HostId.hostId(eth.getSourceMAC(), vlan);
161
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800162 // ARP: possible new hosts, update both location and IP
alshabibe1cf87d2014-10-17 09:23:50 -0700163 if (eth.getEtherType() == Ethernet.TYPE_ARP) {
164 ARP arp = (ARP) eth.getPayload();
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800165 IpAddress ip = IpAddress.valueOf(IpAddress.Version.INET, arp.getSenderProtocolAddress());
alshabibe1cf87d2014-10-17 09:23:50 -0700166 HostDescription hdescr =
167 new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc, ip);
168 providerService.hostDetected(hid, hdescr);
169
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800170 // IPv4: update location only
alshabibe1cf87d2014-10-17 09:23:50 -0700171 } else if (eth.getEtherType() == Ethernet.TYPE_IPV4) {
alshabibe1cf87d2014-10-17 09:23:50 -0700172 HostDescription hdescr =
173 new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc);
174 providerService.hostDetected(hid, hdescr);
175
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800176 // NeighborAdvertisement and NeighborSolicitation: possible new hosts, update both location and IP
177 // IPv6: update location only
178 } else if (eth.getEtherType() == Ethernet.TYPE_IPV6) {
179 IpAddress ip = null;
180 IPv6 ipv6 = (IPv6) eth.getPayload();
181
182 IPacket iPkt = ipv6;
183 while (iPkt != null) {
184 if (iPkt instanceof NeighborAdvertisement || iPkt instanceof NeighborSolicitation) {
185 IpAddress sourceAddress =
186 IpAddress.valueOf(IpAddress.Version.INET6, ipv6.getSourceAddress());
187 // Ignore DAD packets, in which source address is all zeros.
188 if (!sourceAddress.isZero()) {
189 ip = sourceAddress;
190 break;
191 }
192 }
193 iPkt = iPkt.getPayload();
194 }
195 HostDescription hdescr = (ip == null) ?
196 new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc) :
197 new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc, ip);
198 providerService.hostDetected(hid, hdescr);
alshabibe1cf87d2014-10-17 09:23:50 -0700199 }
200 }
201 }
Thomas Vachuska33601602014-11-19 03:32:15 -0800202
203 // Auxiliary listener to device events.
204 private class InternalDeviceListener implements DeviceListener {
205 @Override
206 public void event(DeviceEvent event) {
207 if (!hostRemovalEnabled) {
208 return;
209 }
210
211 DeviceEvent.Type type = event.type();
212 DeviceId deviceId = event.subject().id();
213 if (type == DeviceEvent.Type.PORT_UPDATED) {
214 ConnectPoint point = new ConnectPoint(deviceId, event.port().number());
215 removeHosts(hostService.getConnectedHosts(point));
216
217 } else if (type == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED) {
218 if (!deviceService.isAvailable(deviceId)) {
219 removeHosts(hostService.getConnectedHosts(deviceId));
220 }
221
222 } else if (type == DeviceEvent.Type.DEVICE_REMOVED) {
223 removeHosts(hostService.getConnectedHosts(deviceId));
224 }
225 }
226 }
227
228 // Signals host vanish for all specified hosts.
229 private void removeHosts(Set<Host> hosts) {
230 for (Host host : hosts) {
231 providerService.hostVanished(host.id());
232 }
233 }
234
alshabibe1cf87d2014-10-17 09:23:50 -0700235}