blob: 1cd9764e7553d185c3d83b8d5acd0b8f65414e73 [file] [log] [blame]
Yi Tseng7a38f9a2017-06-09 14:36:40 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Yi Tseng7a38f9a2017-06-09 14:36:40 -07003 *
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 */
16package org.onosproject.dhcprelay;
17
18import java.nio.ByteBuffer;
19import java.util.Collection;
Yi Tseng5479fb82017-09-01 17:24:57 -070020import java.util.Collections;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070021import java.util.Dictionary;
Yi Tseng5479fb82017-09-01 17:24:57 -070022import java.util.List;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070023import java.util.Objects;
24import java.util.Optional;
25import java.util.Set;
Yi Tseng7da339e2017-10-23 19:39:39 -070026import java.util.stream.Collectors;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070027import java.util.stream.Stream;
28
Yi Tseng7da339e2017-10-23 19:39:39 -070029import com.google.common.collect.ImmutableList;
30import com.google.common.collect.Streams;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070031import org.apache.felix.scr.annotations.Activate;
32import org.apache.felix.scr.annotations.Component;
33import org.apache.felix.scr.annotations.Deactivate;
34import org.apache.felix.scr.annotations.Modified;
35import org.apache.felix.scr.annotations.Property;
36import org.apache.felix.scr.annotations.Reference;
37import org.apache.felix.scr.annotations.ReferenceCardinality;
38import org.apache.felix.scr.annotations.Service;
39import org.onlab.packet.ARP;
40import org.onlab.packet.DHCP;
41import org.onlab.packet.DHCP6;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070042import org.onlab.packet.Ethernet;
Yi Tseng4ec727d2017-08-31 11:21:00 -070043import org.onlab.packet.IPacket;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070044import org.onlab.packet.IPv4;
Yi Tseng4ec727d2017-08-31 11:21:00 -070045import org.onlab.packet.IPv6;
46import org.onlab.packet.Ip4Address;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070047import org.onlab.packet.MacAddress;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070048import org.onlab.packet.UDP;
49import org.onlab.packet.VlanId;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070050import org.onlab.util.Tools;
51import org.onosproject.cfg.ComponentConfigService;
52import org.onosproject.core.ApplicationId;
53import org.onosproject.core.CoreService;
Yi Tseng51301292017-07-28 13:02:59 -070054import org.onosproject.dhcprelay.api.DhcpHandler;
55import org.onosproject.dhcprelay.api.DhcpRelayService;
Yi Tseng2fe8f3f2017-09-07 16:22:51 -070056import org.onosproject.dhcprelay.api.DhcpServerInfo;
Yi Tsenge72fbb52017-08-02 15:03:31 -070057import org.onosproject.dhcprelay.config.DefaultDhcpRelayConfig;
Yi Tseng4ec727d2017-08-31 11:21:00 -070058import org.onosproject.dhcprelay.config.DhcpServerConfig;
Yi Tseng5479fb82017-09-01 17:24:57 -070059import org.onosproject.dhcprelay.config.IgnoreDhcpConfig;
Yi Tsenge72fbb52017-08-02 15:03:31 -070060import org.onosproject.dhcprelay.config.IndirectDhcpRelayConfig;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070061import org.onosproject.dhcprelay.store.DhcpRecord;
62import org.onosproject.dhcprelay.store.DhcpRelayStore;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070063import org.onosproject.net.ConnectPoint;
Yi Tseng76365d82017-09-12 15:55:17 -070064import org.onosproject.net.Device;
Yi Tseng4ec727d2017-08-31 11:21:00 -070065import org.onosproject.net.Host;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070066import org.onosproject.net.HostId;
Yi Tseng4ec727d2017-08-31 11:21:00 -070067import org.onosproject.net.config.Config;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070068import org.onosproject.net.config.ConfigFactory;
69import org.onosproject.net.config.NetworkConfigEvent;
70import org.onosproject.net.config.NetworkConfigListener;
71import org.onosproject.net.config.NetworkConfigRegistry;
72import org.onosproject.net.flow.DefaultTrafficSelector;
73import org.onosproject.net.flow.DefaultTrafficTreatment;
74import org.onosproject.net.flow.TrafficSelector;
75import org.onosproject.net.flow.TrafficTreatment;
Yi Tseng76365d82017-09-12 15:55:17 -070076import org.onosproject.net.device.DeviceEvent;
77import org.onosproject.net.device.DeviceListener;
78import org.onosproject.net.device.DeviceService;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070079import org.onosproject.net.host.HostService;
Yi Tseng4ec727d2017-08-31 11:21:00 -070080import org.onosproject.net.intf.Interface;
81import org.onosproject.net.intf.InterfaceService;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070082import org.onosproject.net.packet.DefaultOutboundPacket;
83import org.onosproject.net.packet.OutboundPacket;
84import org.onosproject.net.packet.PacketContext;
85import org.onosproject.net.packet.PacketPriority;
86import org.onosproject.net.packet.PacketProcessor;
87import org.onosproject.net.packet.PacketService;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070088import org.osgi.service.component.ComponentContext;
89import org.slf4j.Logger;
90import org.slf4j.LoggerFactory;
91
92import com.google.common.collect.ImmutableSet;
93
Yi Tseng7a38f9a2017-06-09 14:36:40 -070094import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
Yi Tseng76365d82017-09-12 15:55:17 -070095
Yi Tseng7a38f9a2017-06-09 14:36:40 -070096/**
97 * DHCP Relay Agent Application Component.
98 */
99@Component(immediate = true)
100@Service
101public class DhcpRelayManager implements DhcpRelayService {
Yi Tsenge72fbb52017-08-02 15:03:31 -0700102 public static final String DHCP_RELAY_APP = "org.onosproject.dhcprelay";
Yi Tseng325af8c2017-09-01 16:02:56 -0700103 public static final String ROUTE_STORE_IMPL =
104 "org.onosproject.routeservice.store.RouteStoreImpl";
Yi Tseng7da339e2017-10-23 19:39:39 -0700105
Yi Tseng5479fb82017-09-01 17:24:57 -0700106 private static final TrafficSelector ARP_SELECTOR = DefaultTrafficSelector.builder()
107 .matchEthType(Ethernet.TYPE_ARP)
108 .build();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700109 private final Logger log = LoggerFactory.getLogger(getClass());
110 private final InternalConfigListener cfgListener = new InternalConfigListener();
111
112 private final Set<ConfigFactory> factories = ImmutableSet.of(
Yi Tsenge72fbb52017-08-02 15:03:31 -0700113 new ConfigFactory<ApplicationId, DefaultDhcpRelayConfig>(APP_SUBJECT_FACTORY,
114 DefaultDhcpRelayConfig.class,
115 DefaultDhcpRelayConfig.KEY,
116 true) {
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700117 @Override
Yi Tsenge72fbb52017-08-02 15:03:31 -0700118 public DefaultDhcpRelayConfig createConfig() {
119 return new DefaultDhcpRelayConfig();
120 }
121 },
122 new ConfigFactory<ApplicationId, IndirectDhcpRelayConfig>(APP_SUBJECT_FACTORY,
123 IndirectDhcpRelayConfig.class,
124 IndirectDhcpRelayConfig.KEY,
125 true) {
126 @Override
127 public IndirectDhcpRelayConfig createConfig() {
128 return new IndirectDhcpRelayConfig();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700129 }
Yi Tseng5479fb82017-09-01 17:24:57 -0700130 },
131 new ConfigFactory<ApplicationId, IgnoreDhcpConfig>(APP_SUBJECT_FACTORY,
132 IgnoreDhcpConfig.class,
133 IgnoreDhcpConfig.KEY,
134 true) {
135 @Override
136 public IgnoreDhcpConfig createConfig() {
137 return new IgnoreDhcpConfig();
138 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700139 }
140 );
141
142 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
143 protected NetworkConfigRegistry cfgService;
144
145 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
146 protected CoreService coreService;
147
148 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
149 protected PacketService packetService;
150
151 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
152 protected HostService hostService;
153
154 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700155 protected InterfaceService interfaceService;
156
157 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
158 protected DhcpRelayStore dhcpRelayStore;
159
160 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
161 protected ComponentConfigService compCfgService;
162
Yi Tseng5479fb82017-09-01 17:24:57 -0700163 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Yi Tseng76365d82017-09-12 15:55:17 -0700164 protected DeviceService deviceService;
165
Yi Tseng51301292017-07-28 13:02:59 -0700166 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY,
Yi Tseng76365d82017-09-12 15:55:17 -0700167 target = "(version=4)")
Yi Tseng51301292017-07-28 13:02:59 -0700168 protected DhcpHandler v4Handler;
169
170 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY,
Yi Tseng76365d82017-09-12 15:55:17 -0700171 target = "(version=6)")
Yi Tseng51301292017-07-28 13:02:59 -0700172 protected DhcpHandler v6Handler;
173
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700174 @Property(name = "arpEnabled", boolValue = true,
Yi Tseng76365d82017-09-12 15:55:17 -0700175 label = "Enable Address resolution protocol")
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700176 protected boolean arpEnabled = true;
177
Yi Tseng76365d82017-09-12 15:55:17 -0700178 protected DeviceListener deviceListener = new InternalDeviceListener();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700179 private DhcpRelayPacketProcessor dhcpRelayPacketProcessor = new DhcpRelayPacketProcessor();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700180 private ApplicationId appId;
181
182 @Activate
183 protected void activate(ComponentContext context) {
184 //start the dhcp relay agent
185 appId = coreService.registerApplication(DHCP_RELAY_APP);
186
187 cfgService.addListener(cfgListener);
188 factories.forEach(cfgService::registerConfigFactory);
189 //update the dhcp server configuration.
190 updateConfig();
Yi Tseng51301292017-07-28 13:02:59 -0700191
192 //add the packet processor
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700193 packetService.addProcessor(dhcpRelayPacketProcessor, PacketProcessor.director(0));
Yi Tseng51301292017-07-28 13:02:59 -0700194
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700195 modified(context);
196
Yi Tseng325af8c2017-09-01 16:02:56 -0700197 // Enable distribute route store
198 compCfgService.preSetProperty(ROUTE_STORE_IMPL,
199 "distributed", Boolean.TRUE.toString());
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700200 compCfgService.registerProperties(getClass());
Yi Tseng76365d82017-09-12 15:55:17 -0700201
202 deviceService.addListener(deviceListener);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700203 log.info("DHCP-RELAY Started");
204 }
205
206 @Deactivate
207 protected void deactivate() {
208 cfgService.removeListener(cfgListener);
209 factories.forEach(cfgService::unregisterConfigFactory);
210 packetService.removeProcessor(dhcpRelayPacketProcessor);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700211 cancelArpPackets();
Yi Tsengdfa8ee22017-08-07 12:45:01 -0700212 compCfgService.unregisterProperties(getClass(), false);
Yi Tseng76365d82017-09-12 15:55:17 -0700213 deviceService.removeListener(deviceListener);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700214 log.info("DHCP-RELAY Stopped");
215 }
216
217 @Modified
218 protected void modified(ComponentContext context) {
219 Dictionary<?, ?> properties = context.getProperties();
220 Boolean flag;
221
222 flag = Tools.isPropertyEnabled(properties, "arpEnabled");
223 if (flag != null) {
224 arpEnabled = flag;
225 log.info("Address resolution protocol is {}",
226 arpEnabled ? "enabled" : "disabled");
227 }
228
229 if (arpEnabled) {
230 requestArpPackets();
231 } else {
232 cancelArpPackets();
233 }
234 }
235
Yi Tseng7da339e2017-10-23 19:39:39 -0700236 private static List<TrafficSelector> buildClientDhcpSelectors() {
237 return Streams.concat(Dhcp4HandlerImpl.DHCP_SELECTORS.stream(),
238 Dhcp6HandlerImpl.DHCP_SELECTORS.stream())
239 .collect(Collectors.toList());
240 }
241
Yi Tsenge72fbb52017-08-02 15:03:31 -0700242 /**
243 * Updates DHCP relay app configuration.
244 */
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700245 private void updateConfig() {
Yi Tsenge72fbb52017-08-02 15:03:31 -0700246 DefaultDhcpRelayConfig defaultConfig =
247 cfgService.getConfig(appId, DefaultDhcpRelayConfig.class);
248 IndirectDhcpRelayConfig indirectConfig =
249 cfgService.getConfig(appId, IndirectDhcpRelayConfig.class);
Yi Tseng5479fb82017-09-01 17:24:57 -0700250 IgnoreDhcpConfig ignoreDhcpConfig =
251 cfgService.getConfig(appId, IgnoreDhcpConfig.class);
Yi Tsenge72fbb52017-08-02 15:03:31 -0700252
253 if (defaultConfig != null) {
254 updateConfig(defaultConfig);
255 }
Yi Tsenge72fbb52017-08-02 15:03:31 -0700256 if (indirectConfig != null) {
257 updateConfig(indirectConfig);
258 }
Yi Tseng5479fb82017-09-01 17:24:57 -0700259 if (ignoreDhcpConfig != null) {
260 updateConfig(ignoreDhcpConfig);
261 }
Yi Tsenge72fbb52017-08-02 15:03:31 -0700262 }
263
264 /**
265 * Updates DHCP relay app configuration with given configuration.
266 *
267 * @param config the configuration ot update
268 */
Yi Tseng5479fb82017-09-01 17:24:57 -0700269 protected void updateConfig(Config config) {
Yi Tsenge72fbb52017-08-02 15:03:31 -0700270 if (config instanceof IndirectDhcpRelayConfig) {
271 IndirectDhcpRelayConfig indirectConfig = (IndirectDhcpRelayConfig) config;
272 v4Handler.setIndirectDhcpServerConfigs(indirectConfig.dhcpServerConfigs());
273 v6Handler.setIndirectDhcpServerConfigs(indirectConfig.dhcpServerConfigs());
Yi Tseng4fa05832017-08-17 13:08:31 -0700274 } else if (config instanceof DefaultDhcpRelayConfig) {
275 DefaultDhcpRelayConfig defaultConfig = (DefaultDhcpRelayConfig) config;
276 v4Handler.setDefaultDhcpServerConfigs(defaultConfig.dhcpServerConfigs());
277 v6Handler.setDefaultDhcpServerConfigs(defaultConfig.dhcpServerConfigs());
Yi Tsenge72fbb52017-08-02 15:03:31 -0700278 }
Yi Tseng5479fb82017-09-01 17:24:57 -0700279 if (config instanceof IgnoreDhcpConfig) {
Yi Tseng7da339e2017-10-23 19:39:39 -0700280 v4Handler.updateIgnoreVlanConfig((IgnoreDhcpConfig) config);
281 v6Handler.updateIgnoreVlanConfig((IgnoreDhcpConfig) config);
Yi Tseng5479fb82017-09-01 17:24:57 -0700282 }
283 }
284
285 protected void removeConfig(Config config) {
286 if (config instanceof IndirectDhcpRelayConfig) {
287 v4Handler.setIndirectDhcpServerConfigs(Collections.emptyList());
288 v6Handler.setIndirectDhcpServerConfigs(Collections.emptyList());
289 } else if (config instanceof DefaultDhcpRelayConfig) {
290 v4Handler.setDefaultDhcpServerConfigs(Collections.emptyList());
291 v6Handler.setDefaultDhcpServerConfigs(Collections.emptyList());
292 }
293 if (config instanceof IgnoreDhcpConfig) {
Yi Tseng7da339e2017-10-23 19:39:39 -0700294 v4Handler.updateIgnoreVlanConfig(null);
295 v6Handler.updateIgnoreVlanConfig(null);
Yi Tseng5479fb82017-09-01 17:24:57 -0700296 }
297 }
298
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700299 /**
300 * Request ARP packet in via PacketService.
301 */
302 private void requestArpPackets() {
Yi Tseng5479fb82017-09-01 17:24:57 -0700303 packetService.requestPackets(ARP_SELECTOR, PacketPriority.CONTROL, appId);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700304 }
305
306 /**
307 * Cancel requested ARP packets in via packet service.
308 */
309 private void cancelArpPackets() {
Yi Tseng5479fb82017-09-01 17:24:57 -0700310 packetService.cancelPackets(ARP_SELECTOR, PacketPriority.CONTROL, appId);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700311 }
312
313 @Override
314 public Optional<DhcpRecord> getDhcpRecord(HostId hostId) {
315 return dhcpRelayStore.getDhcpRecord(hostId);
316 }
317
318 @Override
319 public Collection<DhcpRecord> getDhcpRecords() {
320 return dhcpRelayStore.getDhcpRecords();
321 }
322
Yi Tseng13a41a12017-07-26 13:45:01 -0700323 @Override
324 public Optional<MacAddress> getDhcpServerMacAddress() {
Yi Tseng4ec727d2017-08-31 11:21:00 -0700325 // TODO: depreated it
326 DefaultDhcpRelayConfig config = cfgService.getConfig(appId, DefaultDhcpRelayConfig.class);
327 DhcpServerConfig serverConfig = config.dhcpServerConfigs().get(0);
328 Ip4Address serverip = serverConfig.getDhcpServerIp4().get();
329 return hostService.getHostsByIp(serverip)
330 .stream()
331 .map(Host::mac)
332 .findFirst();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700333 }
334
Yi Tseng2fe8f3f2017-09-07 16:22:51 -0700335 @Override
336 public List<DhcpServerInfo> getDefaultDhcpServerInfoList() {
337 return ImmutableList.<DhcpServerInfo>builder()
338 .addAll(v4Handler.getDefaultDhcpServerInfoList())
339 .addAll(v6Handler.getDefaultDhcpServerInfoList())
340 .build();
341 }
342
343 @Override
344 public List<DhcpServerInfo> getIndirectDhcpServerInfoList() {
345 return ImmutableList.<DhcpServerInfo>builder()
346 .addAll(v4Handler.getIndirectDhcpServerInfoList())
347 .addAll(v6Handler.getIndirectDhcpServerInfoList())
348 .build();
349 }
350
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700351 /**
352 * Gets DHCP data from a packet.
353 *
354 * @param packet the packet
355 * @return the DHCP data; empty if it is not a DHCP packet
356 */
357 private Optional<DHCP> findDhcp(Ethernet packet) {
358 return Stream.of(packet)
359 .filter(Objects::nonNull)
360 .map(Ethernet::getPayload)
361 .filter(p -> p instanceof IPv4)
362 .map(IPacket::getPayload)
363 .filter(Objects::nonNull)
364 .filter(p -> p instanceof UDP)
365 .map(IPacket::getPayload)
366 .filter(Objects::nonNull)
367 .filter(p -> p instanceof DHCP)
368 .map(p -> (DHCP) p)
369 .findFirst();
370 }
371
372 /**
373 * Gets DHCPv6 data from a packet.
374 *
375 * @param packet the packet
376 * @return the DHCPv6 data; empty if it is not a DHCPv6 packet
377 */
378 private Optional<DHCP6> findDhcp6(Ethernet packet) {
379 return Stream.of(packet)
380 .filter(Objects::nonNull)
381 .map(Ethernet::getPayload)
382 .filter(p -> p instanceof IPv6)
383 .map(IPacket::getPayload)
384 .filter(Objects::nonNull)
385 .filter(p -> p instanceof UDP)
386 .map(IPacket::getPayload)
387 .filter(Objects::nonNull)
388 .filter(p -> p instanceof DHCP6)
389 .map(p -> (DHCP6) p)
390 .findFirst();
391 }
392
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700393
394 private class DhcpRelayPacketProcessor implements PacketProcessor {
395
396 @Override
397 public void process(PacketContext context) {
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700398 // process the packet and get the payload
399 Ethernet packet = context.inPacket().parsed();
400 if (packet == null) {
401 return;
402 }
403
404 findDhcp(packet).ifPresent(dhcpPayload -> {
Yi Tseng51301292017-07-28 13:02:59 -0700405 v4Handler.processDhcpPacket(context, dhcpPayload);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700406 });
407
408 findDhcp6(packet).ifPresent(dhcp6Payload -> {
Yi Tseng51301292017-07-28 13:02:59 -0700409 v6Handler.processDhcpPacket(context, dhcp6Payload);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700410 });
411
412 if (packet.getEtherType() == Ethernet.TYPE_ARP && arpEnabled) {
413 ARP arpPacket = (ARP) packet.getPayload();
414 VlanId vlanId = VlanId.vlanId(packet.getVlanID());
415 Set<Interface> interfaces = interfaceService.
416 getInterfacesByPort(context.inPacket().receivedFrom());
417 //ignore the packets if dhcp server interface is not configured on onos.
418 if (interfaces.isEmpty()) {
419 log.warn("server virtual interface not configured");
420 return;
421 }
422 if ((arpPacket.getOpCode() != ARP.OP_REQUEST)) {
423 // handle request only
424 return;
425 }
426 MacAddress interfaceMac = interfaces.stream()
427 .filter(iface -> iface.vlan().equals(vlanId))
428 .map(Interface::mac)
429 .filter(mac -> !mac.equals(MacAddress.NONE))
430 .findFirst()
Yi Tseng51301292017-07-28 13:02:59 -0700431 .orElse(MacAddress.ONOS);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700432 if (interfaceMac == null) {
433 // can't find interface mac address
434 return;
435 }
436 processArpPacket(context, packet, interfaceMac);
437 }
438 }
439
440 /**
441 * Processes the ARP Payload and initiates a reply to the client.
442 *
443 * @param context the packet context
444 * @param packet the ethernet payload
445 * @param replyMac mac address to be replied
446 */
447 private void processArpPacket(PacketContext context, Ethernet packet, MacAddress replyMac) {
448 ARP arpPacket = (ARP) packet.getPayload();
449 ARP arpReply = (ARP) arpPacket.clone();
450 arpReply.setOpCode(ARP.OP_REPLY);
451
452 arpReply.setTargetProtocolAddress(arpPacket.getSenderProtocolAddress());
453 arpReply.setTargetHardwareAddress(arpPacket.getSenderHardwareAddress());
454 arpReply.setSenderProtocolAddress(arpPacket.getTargetProtocolAddress());
455 arpReply.setSenderHardwareAddress(replyMac.toBytes());
456
457 // Ethernet Frame.
458 Ethernet ethReply = new Ethernet();
459 ethReply.setSourceMACAddress(replyMac.toBytes());
460 ethReply.setDestinationMACAddress(packet.getSourceMAC());
461 ethReply.setEtherType(Ethernet.TYPE_ARP);
462 ethReply.setVlanID(packet.getVlanID());
463 ethReply.setPayload(arpReply);
464
465 ConnectPoint targetPort = context.inPacket().receivedFrom();
466 TrafficTreatment t = DefaultTrafficTreatment.builder()
467 .setOutput(targetPort.port()).build();
468 OutboundPacket o = new DefaultOutboundPacket(
469 targetPort.deviceId(), t, ByteBuffer.wrap(ethReply.serialize()));
470 if (log.isTraceEnabled()) {
471 log.trace("Relaying ARP packet {} to {}", packet, targetPort);
472 }
473 packetService.emit(o);
474 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700475 }
476
477 /**
478 * Listener for network config events.
479 */
480 private class InternalConfigListener implements NetworkConfigListener {
481 @Override
482 public void event(NetworkConfigEvent event) {
Yi Tseng5479fb82017-09-01 17:24:57 -0700483 switch (event.type()) {
484 case CONFIG_UPDATED:
485 case CONFIG_ADDED:
486 event.config().ifPresent(config -> {
487 updateConfig(config);
488 log.info("{} updated", config.getClass().getSimpleName());
489 });
490 break;
491 case CONFIG_REMOVED:
492 event.prevConfig().ifPresent(config -> {
493 removeConfig(config);
494 log.info("{} removed", config.getClass().getSimpleName());
495 });
496 break;
497 default:
498 log.warn("Unsupported event type {}", event.type());
499 break;
Yi Tsenge72fbb52017-08-02 15:03:31 -0700500 }
Charles Chan91b371b2018-01-03 16:26:32 -0800501 }
Yi Tseng5479fb82017-09-01 17:24:57 -0700502
Charles Chan91b371b2018-01-03 16:26:32 -0800503 @Override
504 public boolean isRelevant(NetworkConfigEvent event) {
505 if (event.configClass().equals(DefaultDhcpRelayConfig.class) ||
506 event.configClass().equals(IndirectDhcpRelayConfig.class) ||
507 event.configClass().equals(IgnoreDhcpConfig.class)) {
508 return true;
509 }
510 log.debug("Ignore irrelevant event class {}", event.configClass().getName());
511 return false;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700512 }
513 }
Yi Tseng76365d82017-09-12 15:55:17 -0700514
515 private class InternalDeviceListener implements DeviceListener {
516
517 @Override
518 public void event(DeviceEvent event) {
519 Device device = event.subject();
520 switch (event.type()) {
521 case DEVICE_ADDED:
Yi Tseng7da339e2017-10-23 19:39:39 -0700522 updateIgnoreVlanConfigs();
Yi Tseng76365d82017-09-12 15:55:17 -0700523 break;
524 case DEVICE_AVAILABILITY_CHANGED:
525 deviceAvailabilityChanged(device);
Yi Tseng76365d82017-09-12 15:55:17 -0700526 default:
527 break;
528 }
529 }
530
531 private void deviceAvailabilityChanged(Device device) {
532 if (deviceService.isAvailable(device.id())) {
Yi Tseng7da339e2017-10-23 19:39:39 -0700533 updateIgnoreVlanConfigs();
Saurav Dasba7eb1a2017-12-13 16:19:35 -0800534 } else {
535 removeIgnoreVlanState();
Yi Tseng76365d82017-09-12 15:55:17 -0700536 }
537 }
538
Yi Tseng7da339e2017-10-23 19:39:39 -0700539 private void updateIgnoreVlanConfigs() {
Yi Tseng76365d82017-09-12 15:55:17 -0700540 IgnoreDhcpConfig config = cfgService.getConfig(appId, IgnoreDhcpConfig.class);
Yi Tseng7da339e2017-10-23 19:39:39 -0700541 v4Handler.updateIgnoreVlanConfig(config);
542 v6Handler.updateIgnoreVlanConfig(config);
Yi Tseng76365d82017-09-12 15:55:17 -0700543 }
Saurav Dasba7eb1a2017-12-13 16:19:35 -0800544
545 private void removeIgnoreVlanState() {
546 IgnoreDhcpConfig config = cfgService.getConfig(appId, IgnoreDhcpConfig.class);
547 v4Handler.removeIgnoreVlanState(config);
548 v6Handler.removeIgnoreVlanState(config);
549 }
Yi Tseng76365d82017-09-12 15:55:17 -0700550 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700551}