blob: 7c3d2ecc32c47bf40785083903a3833037c917be [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;
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -080025import org.onosproject.core.ApplicationId;
26import org.onosproject.core.CoreService;
Brian O'Connorabafb502014-12-02 22:26:20 -080027import org.onosproject.net.ConnectPoint;
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -080028import org.onosproject.net.Device;
Brian O'Connorabafb502014-12-02 22:26:20 -080029import org.onosproject.net.Host;
30import org.onosproject.net.HostId;
31import org.onosproject.net.HostLocation;
32import org.onosproject.net.device.DeviceEvent;
33import org.onosproject.net.device.DeviceListener;
34import org.onosproject.net.device.DeviceService;
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -080035import org.onosproject.net.flow.DefaultFlowRule;
36import org.onosproject.net.flow.DefaultTrafficSelector;
37import org.onosproject.net.flow.DefaultTrafficTreatment;
38import org.onosproject.net.flow.FlowRule;
39import org.onosproject.net.flow.FlowRuleService;
40import org.onosproject.net.flow.TrafficSelector;
41import org.onosproject.net.flow.TrafficTreatment;
Brian O'Connorabafb502014-12-02 22:26:20 -080042import org.onosproject.net.host.DefaultHostDescription;
43import org.onosproject.net.host.HostDescription;
44import org.onosproject.net.host.HostProvider;
45import org.onosproject.net.host.HostProviderRegistry;
46import org.onosproject.net.host.HostProviderService;
47import org.onosproject.net.host.HostService;
48import org.onosproject.net.packet.PacketContext;
49import org.onosproject.net.packet.PacketProcessor;
50import org.onosproject.net.packet.PacketService;
51import org.onosproject.net.provider.AbstractProvider;
52import org.onosproject.net.provider.ProviderId;
53import org.onosproject.net.topology.Topology;
54import org.onosproject.net.topology.TopologyService;
alshabibe1cf87d2014-10-17 09:23:50 -070055import org.onlab.packet.ARP;
56import org.onlab.packet.Ethernet;
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -070057import org.onlab.packet.IpAddress;
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +080058import org.onlab.packet.IPacket;
59import org.onlab.packet.IPv6;
Charles M.C. Chanea5aa472015-01-03 13:40:39 +080060import org.onlab.packet.ndp.NeighborAdvertisement;
61import org.onlab.packet.ndp.NeighborSolicitation;
alshabibe1cf87d2014-10-17 09:23:50 -070062import org.onlab.packet.VlanId;
Thomas Vachuska33601602014-11-19 03:32:15 -080063import org.osgi.service.component.ComponentContext;
alshabibe1cf87d2014-10-17 09:23:50 -070064import org.slf4j.Logger;
65
Thomas Vachuska33601602014-11-19 03:32:15 -080066import java.util.Dictionary;
67import java.util.Set;
68
69import static org.slf4j.LoggerFactory.getLogger;
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
203 VlanId vlan = VlanId.vlanId(eth.getVlanID());
204 ConnectPoint heardOn = context.inPacket().receivedFrom();
205
206 // If this is not an edge port, bail out.
207 Topology topology = topologyService.currentTopology();
208 if (topologyService.isInfrastructure(topology, heardOn)) {
209 return;
210 }
211
212 HostLocation hloc = new HostLocation(heardOn, System.currentTimeMillis());
213
214 HostId hid = HostId.hostId(eth.getSourceMAC(), vlan);
215
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800216 // ARP: possible new hosts, update both location and IP
alshabibe1cf87d2014-10-17 09:23:50 -0700217 if (eth.getEtherType() == Ethernet.TYPE_ARP) {
218 ARP arp = (ARP) eth.getPayload();
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800219 IpAddress ip = IpAddress.valueOf(IpAddress.Version.INET, arp.getSenderProtocolAddress());
alshabibe1cf87d2014-10-17 09:23:50 -0700220 HostDescription hdescr =
221 new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc, ip);
222 providerService.hostDetected(hid, hdescr);
223
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800224 // IPv4: update location only
alshabibe1cf87d2014-10-17 09:23:50 -0700225 } else if (eth.getEtherType() == Ethernet.TYPE_IPV4) {
alshabibe1cf87d2014-10-17 09:23:50 -0700226 HostDescription hdescr =
227 new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc);
228 providerService.hostDetected(hid, hdescr);
229
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800230 // NeighborAdvertisement and NeighborSolicitation: possible new hosts, update both location and IP
231 // IPv6: update location only
232 } else if (eth.getEtherType() == Ethernet.TYPE_IPV6) {
233 IpAddress ip = null;
234 IPv6 ipv6 = (IPv6) eth.getPayload();
235
236 IPacket iPkt = ipv6;
237 while (iPkt != null) {
238 if (iPkt instanceof NeighborAdvertisement || iPkt instanceof NeighborSolicitation) {
239 IpAddress sourceAddress =
240 IpAddress.valueOf(IpAddress.Version.INET6, ipv6.getSourceAddress());
241 // Ignore DAD packets, in which source address is all zeros.
242 if (!sourceAddress.isZero()) {
243 ip = sourceAddress;
244 break;
245 }
246 }
247 iPkt = iPkt.getPayload();
248 }
249 HostDescription hdescr = (ip == null) ?
250 new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc) :
251 new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc, ip);
252 providerService.hostDetected(hid, hdescr);
alshabibe1cf87d2014-10-17 09:23:50 -0700253 }
254 }
255 }
Thomas Vachuska33601602014-11-19 03:32:15 -0800256
257 // Auxiliary listener to device events.
258 private class InternalDeviceListener implements DeviceListener {
259 @Override
260 public void event(DeviceEvent event) {
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -0800261 Device device = event.subject();
262 switch (event.type()) {
263 case DEVICE_ADDED:
264 pushRules(device);
265 break;
266 case DEVICE_AVAILABILITY_CHANGED:
267 if (hostRemovalEnabled &&
268 !deviceService.isAvailable(device.id())) {
269 removeHosts(hostService.getConnectedHosts(device.id()));
Thomas Vachuska33601602014-11-19 03:32:15 -0800270 }
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -0800271 break;
272 case DEVICE_SUSPENDED:
273 case DEVICE_UPDATED:
274 // Nothing to do?
275 break;
276 case DEVICE_REMOVED:
277 if (hostRemovalEnabled) {
278 removeHosts(hostService.getConnectedHosts(device.id()));
279 }
280 break;
281 case PORT_ADDED:
282 break;
283 case PORT_UPDATED:
284 if (hostRemovalEnabled) {
285 ConnectPoint point =
286 new ConnectPoint(device.id(), event.port().number());
287 removeHosts(hostService.getConnectedHosts(point));
288 }
289 break;
290 case PORT_REMOVED:
291 // Nothing to do?
292 break;
293 default:
294 break;
Thomas Vachuska33601602014-11-19 03:32:15 -0800295 }
296 }
297 }
298
299 // Signals host vanish for all specified hosts.
300 private void removeHosts(Set<Host> hosts) {
301 for (Host host : hosts) {
302 providerService.hostVanished(host.id());
303 }
304 }
305
alshabibe1cf87d2014-10-17 09:23:50 -0700306}