blob: 0aa050d7413dae4acd9146439df5cbbe5ed2530d [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
Jonathan Harte8600eb2015-01-12 10:30:45 -080018import static org.slf4j.LoggerFactory.getLogger;
19
20import java.util.Dictionary;
21import java.util.Set;
22
alshabibe1cf87d2014-10-17 09:23:50 -070023import org.apache.felix.scr.annotations.Activate;
24import org.apache.felix.scr.annotations.Component;
25import org.apache.felix.scr.annotations.Deactivate;
Thomas Vachuska33601602014-11-19 03:32:15 -080026import org.apache.felix.scr.annotations.Modified;
27import org.apache.felix.scr.annotations.Property;
alshabibe1cf87d2014-10-17 09:23:50 -070028import org.apache.felix.scr.annotations.Reference;
29import org.apache.felix.scr.annotations.ReferenceCardinality;
Jonathan Harte8600eb2015-01-12 10:30:45 -080030import org.onlab.packet.ARP;
31import org.onlab.packet.Ethernet;
32import org.onlab.packet.IPacket;
33import org.onlab.packet.IPv6;
34import org.onlab.packet.IpAddress;
35import org.onlab.packet.VlanId;
36import org.onlab.packet.ndp.NeighborAdvertisement;
37import org.onlab.packet.ndp.NeighborSolicitation;
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -080038import org.onosproject.core.ApplicationId;
39import org.onosproject.core.CoreService;
Brian O'Connorabafb502014-12-02 22:26:20 -080040import org.onosproject.net.ConnectPoint;
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -080041import org.onosproject.net.Device;
Brian O'Connorabafb502014-12-02 22:26:20 -080042import org.onosproject.net.Host;
43import org.onosproject.net.HostId;
44import org.onosproject.net.HostLocation;
45import org.onosproject.net.device.DeviceEvent;
46import org.onosproject.net.device.DeviceListener;
47import org.onosproject.net.device.DeviceService;
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -080048import org.onosproject.net.flow.DefaultFlowRule;
49import org.onosproject.net.flow.DefaultTrafficSelector;
50import org.onosproject.net.flow.DefaultTrafficTreatment;
51import org.onosproject.net.flow.FlowRule;
52import org.onosproject.net.flow.FlowRuleService;
53import org.onosproject.net.flow.TrafficSelector;
54import org.onosproject.net.flow.TrafficTreatment;
Brian O'Connorabafb502014-12-02 22:26:20 -080055import org.onosproject.net.host.DefaultHostDescription;
56import org.onosproject.net.host.HostDescription;
57import org.onosproject.net.host.HostProvider;
58import org.onosproject.net.host.HostProviderRegistry;
59import org.onosproject.net.host.HostProviderService;
60import org.onosproject.net.host.HostService;
61import org.onosproject.net.packet.PacketContext;
62import org.onosproject.net.packet.PacketProcessor;
63import org.onosproject.net.packet.PacketService;
64import org.onosproject.net.provider.AbstractProvider;
65import org.onosproject.net.provider.ProviderId;
66import org.onosproject.net.topology.Topology;
67import org.onosproject.net.topology.TopologyService;
Thomas Vachuska33601602014-11-19 03:32:15 -080068import org.osgi.service.component.ComponentContext;
alshabibe1cf87d2014-10-17 09:23:50 -070069import org.slf4j.Logger;
70
alshabibe1cf87d2014-10-17 09:23:50 -070071/**
72 * Provider which uses an OpenFlow controller to detect network
73 * end-station hosts.
74 */
75@Component(immediate = true)
76public class HostLocationProvider extends AbstractProvider implements HostProvider {
77
78 private final Logger log = getLogger(getClass());
79
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -080080 private static final int FLOW_RULE_PRIORITY = 40000;
81
82 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
83 protected CoreService coreService;
84
85 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
86 protected FlowRuleService flowRuleService;
87
alshabibe1cf87d2014-10-17 09:23:50 -070088 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
89 protected HostProviderRegistry providerRegistry;
90
91 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
92 protected PacketService pktService;
93
94 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
95 protected TopologyService topologyService;
96
Thomas Vachuska33601602014-11-19 03:32:15 -080097 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
98 protected HostService hostService;
99
100 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
101 protected DeviceService deviceService;
102
alshabibe1cf87d2014-10-17 09:23:50 -0700103 private HostProviderService providerService;
104
105 private final InternalHostProvider processor = new InternalHostProvider();
Thomas Vachuska33601602014-11-19 03:32:15 -0800106 private final DeviceListener deviceListener = new InternalDeviceListener();
107
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -0800108 private ApplicationId appId;
109
Thomas Vachuska33601602014-11-19 03:32:15 -0800110 @Property(name = "hostRemovalEnabled", boolValue = true,
111 label = "Enable host removal on port/device down events")
112 private boolean hostRemovalEnabled = true;
alshabibe1cf87d2014-10-17 09:23:50 -0700113
114
115 /**
116 * Creates an OpenFlow host provider.
117 */
118 public HostLocationProvider() {
Brian O'Connorabafb502014-12-02 22:26:20 -0800119 super(new ProviderId("of", "org.onosproject.provider.host"));
alshabibe1cf87d2014-10-17 09:23:50 -0700120 }
121
122 @Activate
Thomas Vachuska33601602014-11-19 03:32:15 -0800123 public void activate(ComponentContext context) {
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -0800124 appId =
125 coreService.registerApplication("org.onosproject.provider.host");
126
Thomas Vachuska33601602014-11-19 03:32:15 -0800127 modified(context);
alshabibe1cf87d2014-10-17 09:23:50 -0700128 providerService = providerRegistry.register(this);
129 pktService.addProcessor(processor, 1);
Thomas Vachuska33601602014-11-19 03:32:15 -0800130 deviceService.addListener(deviceListener);
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -0800131 pushRules();
132
alshabibe1cf87d2014-10-17 09:23:50 -0700133 log.info("Started");
134 }
135
136 @Deactivate
137 public void deactivate() {
138 providerRegistry.unregister(this);
139 pktService.removeProcessor(processor);
alshabibbfc6b722014-11-29 12:53:48 -0800140 deviceService.removeListener(deviceListener);
alshabibe1cf87d2014-10-17 09:23:50 -0700141 providerService = null;
142 log.info("Stopped");
143 }
144
Thomas Vachuska33601602014-11-19 03:32:15 -0800145 @Modified
146 public void modified(ComponentContext context) {
147 Dictionary properties = context.getProperties();
148 try {
149 String flag = (String) properties.get("hostRemovalEnabled");
150 if (flag != null) {
151 hostRemovalEnabled = flag.equals("true");
152 }
153 } catch (Exception e) {
154 hostRemovalEnabled = true;
155 }
156 log.info("Host removal is {}", hostRemovalEnabled ? "enabled" : "disabled");
157 }
158
alshabibe1cf87d2014-10-17 09:23:50 -0700159 @Override
160 public void triggerProbe(Host host) {
161 log.info("Triggering probe on device {}", host);
162 }
163
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -0800164 /**
165 * Pushes flow rules to all devices.
166 */
167 private void pushRules() {
168 for (Device device : deviceService.getDevices()) {
169 pushRules(device);
170 }
171 }
172
173 /**
174 * Pushes flow rules to the device to receive control packets that need
175 * to be processed.
176 *
177 * @param device the device to push the rules to
178 */
179 private synchronized void pushRules(Device device) {
180 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
181 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
182
183 // Get all ARP packets
184 sbuilder.matchEthType(Ethernet.TYPE_ARP);
185 tbuilder.punt();
186 FlowRule flowArp =
187 new DefaultFlowRule(device.id(),
188 sbuilder.build(), tbuilder.build(),
189 FLOW_RULE_PRIORITY, appId, 0, true);
190
191 flowRuleService.applyFlowRules(flowArp);
192 }
193
alshabibe1cf87d2014-10-17 09:23:50 -0700194 private class InternalHostProvider implements PacketProcessor {
195
196 @Override
197 public void process(PacketContext context) {
alshabib4a179dc2014-10-17 17:17:01 -0700198 if (context == null) {
199 return;
200 }
alshabibe1cf87d2014-10-17 09:23:50 -0700201 Ethernet eth = context.inPacket().parsed();
202
Jonathan Harte8600eb2015-01-12 10:30:45 -0800203 if (eth == null) {
204 return;
205 }
206
alshabibe1cf87d2014-10-17 09:23:50 -0700207 VlanId vlan = VlanId.vlanId(eth.getVlanID());
208 ConnectPoint heardOn = context.inPacket().receivedFrom();
209
210 // If this is not an edge port, bail out.
211 Topology topology = topologyService.currentTopology();
212 if (topologyService.isInfrastructure(topology, heardOn)) {
213 return;
214 }
215
216 HostLocation hloc = new HostLocation(heardOn, System.currentTimeMillis());
217
218 HostId hid = HostId.hostId(eth.getSourceMAC(), vlan);
219
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800220 // ARP: possible new hosts, update both location and IP
alshabibe1cf87d2014-10-17 09:23:50 -0700221 if (eth.getEtherType() == Ethernet.TYPE_ARP) {
222 ARP arp = (ARP) eth.getPayload();
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800223 IpAddress ip = IpAddress.valueOf(IpAddress.Version.INET, arp.getSenderProtocolAddress());
alshabibe1cf87d2014-10-17 09:23:50 -0700224 HostDescription hdescr =
225 new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc, ip);
226 providerService.hostDetected(hid, hdescr);
227
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800228 // IPv4: update location only
alshabibe1cf87d2014-10-17 09:23:50 -0700229 } else if (eth.getEtherType() == Ethernet.TYPE_IPV4) {
alshabibe1cf87d2014-10-17 09:23:50 -0700230 HostDescription hdescr =
231 new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc);
232 providerService.hostDetected(hid, hdescr);
233
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800234 // NeighborAdvertisement and NeighborSolicitation: possible new hosts, update both location and IP
235 // IPv6: update location only
236 } else if (eth.getEtherType() == Ethernet.TYPE_IPV6) {
237 IpAddress ip = null;
238 IPv6 ipv6 = (IPv6) eth.getPayload();
239
240 IPacket iPkt = ipv6;
241 while (iPkt != null) {
242 if (iPkt instanceof NeighborAdvertisement || iPkt instanceof NeighborSolicitation) {
243 IpAddress sourceAddress =
244 IpAddress.valueOf(IpAddress.Version.INET6, ipv6.getSourceAddress());
245 // Ignore DAD packets, in which source address is all zeros.
246 if (!sourceAddress.isZero()) {
247 ip = sourceAddress;
248 break;
249 }
250 }
251 iPkt = iPkt.getPayload();
252 }
253 HostDescription hdescr = (ip == null) ?
254 new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc) :
255 new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc, ip);
256 providerService.hostDetected(hid, hdescr);
alshabibe1cf87d2014-10-17 09:23:50 -0700257 }
258 }
259 }
Thomas Vachuska33601602014-11-19 03:32:15 -0800260
261 // Auxiliary listener to device events.
262 private class InternalDeviceListener implements DeviceListener {
263 @Override
264 public void event(DeviceEvent event) {
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -0800265 Device device = event.subject();
266 switch (event.type()) {
267 case DEVICE_ADDED:
268 pushRules(device);
269 break;
270 case DEVICE_AVAILABILITY_CHANGED:
271 if (hostRemovalEnabled &&
272 !deviceService.isAvailable(device.id())) {
273 removeHosts(hostService.getConnectedHosts(device.id()));
Thomas Vachuska33601602014-11-19 03:32:15 -0800274 }
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -0800275 break;
276 case DEVICE_SUSPENDED:
277 case DEVICE_UPDATED:
278 // Nothing to do?
279 break;
280 case DEVICE_REMOVED:
281 if (hostRemovalEnabled) {
282 removeHosts(hostService.getConnectedHosts(device.id()));
283 }
284 break;
285 case PORT_ADDED:
286 break;
287 case PORT_UPDATED:
288 if (hostRemovalEnabled) {
289 ConnectPoint point =
290 new ConnectPoint(device.id(), event.port().number());
291 removeHosts(hostService.getConnectedHosts(point));
292 }
293 break;
294 case PORT_REMOVED:
295 // Nothing to do?
296 break;
297 default:
298 break;
Thomas Vachuska33601602014-11-19 03:32:15 -0800299 }
300 }
301 }
302
303 // Signals host vanish for all specified hosts.
304 private void removeHosts(Set<Host> hosts) {
305 for (Host host : hosts) {
306 providerService.hostVanished(host.id());
307 }
308 }
309
alshabibe1cf87d2014-10-17 09:23:50 -0700310}