blob: f2ca330c082334b760c5724a5a22a1f590705d57 [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 Tseng51f1be92017-09-01 17:24:57 -070020import java.util.Collections;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070021import java.util.Dictionary;
Yi Tseng51f1be92017-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 Tseng525ff402017-10-23 19:39:39 -070026import java.util.stream.Collectors;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070027import java.util.stream.Stream;
28
Yi Tseng51f1be92017-09-01 17:24:57 -070029import com.google.common.collect.ImmutableList;
Yi Tseng525ff402017-10-23 19:39:39 -070030import 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;
42import org.onlab.packet.IPacket;
43import org.onlab.packet.IPv6;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070044import org.onlab.packet.Ethernet;
45import org.onlab.packet.IPv4;
Yi Tseng4f2a0462017-08-31 11:21:00 -070046import org.onlab.packet.Ip4Address;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070047import org.onlab.packet.MacAddress;
Kalhee Kimba366062017-11-07 16:32:09 +000048import org.onlab.packet.IpPrefix;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070049import org.onlab.packet.UDP;
50import org.onlab.packet.VlanId;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070051import org.onlab.util.Tools;
52import org.onosproject.cfg.ComponentConfigService;
53import org.onosproject.core.ApplicationId;
54import org.onosproject.core.CoreService;
Yi Tseng51301292017-07-28 13:02:59 -070055import org.onosproject.dhcprelay.api.DhcpHandler;
56import org.onosproject.dhcprelay.api.DhcpRelayService;
Yi Tseng919b2df2017-09-07 16:22:51 -070057import org.onosproject.dhcprelay.api.DhcpServerInfo;
Yi Tseng483ac6f2017-08-02 15:03:31 -070058import org.onosproject.dhcprelay.config.DefaultDhcpRelayConfig;
Taras Lemkin96a0d342018-03-26 14:52:58 +000059import org.onosproject.dhcprelay.config.DhcpServerConfig;
Kalhee Kimba366062017-11-07 16:32:09 +000060import org.onosproject.dhcprelay.config.EnableDhcpFpmConfig;
Taras Lemkin96a0d342018-03-26 14:52:58 +000061import org.onosproject.dhcprelay.config.IndirectDhcpRelayConfig;
62import org.onosproject.dhcprelay.config.IgnoreDhcpConfig;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070063import org.onosproject.dhcprelay.store.DhcpRecord;
64import org.onosproject.dhcprelay.store.DhcpRelayStore;
Kalhee Kimba366062017-11-07 16:32:09 +000065import org.onosproject.dhcprelay.store.DhcpFpmPrefixStore;
66import org.onosproject.routing.fpm.api.FpmRecord;
Yi Tseng127ffe52017-09-12 15:55:17 -070067import org.onosproject.net.Device;
Yi Tseng4f2a0462017-08-31 11:21:00 -070068import org.onosproject.net.Host;
Yi Tseng483ac6f2017-08-02 15:03:31 -070069import org.onosproject.net.config.Config;
Yi Tseng127ffe52017-09-12 15:55:17 -070070import org.onosproject.net.device.DeviceEvent;
71import org.onosproject.net.device.DeviceListener;
72import org.onosproject.net.device.DeviceService;
Ray Milkeyfacf2862017-08-03 11:58:29 -070073import org.onosproject.net.intf.Interface;
74import org.onosproject.net.intf.InterfaceService;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070075import org.onosproject.net.ConnectPoint;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070076import org.onosproject.net.HostId;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070077import org.onosproject.net.config.ConfigFactory;
78import org.onosproject.net.config.NetworkConfigEvent;
79import org.onosproject.net.config.NetworkConfigListener;
80import org.onosproject.net.config.NetworkConfigRegistry;
81import org.onosproject.net.flow.DefaultTrafficSelector;
82import org.onosproject.net.flow.DefaultTrafficTreatment;
83import org.onosproject.net.flow.TrafficSelector;
84import org.onosproject.net.flow.TrafficTreatment;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070085import org.onosproject.net.host.HostService;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070086import org.onosproject.net.packet.DefaultOutboundPacket;
87import org.onosproject.net.packet.OutboundPacket;
88import org.onosproject.net.packet.PacketContext;
89import org.onosproject.net.packet.PacketPriority;
90import org.onosproject.net.packet.PacketProcessor;
91import org.onosproject.net.packet.PacketService;
Kalhee Kimba366062017-11-07 16:32:09 +000092
Yi Tseng7a38f9a2017-06-09 14:36:40 -070093import org.osgi.service.component.ComponentContext;
94import org.slf4j.Logger;
95import org.slf4j.LoggerFactory;
Kalhee Kimd94ceea2017-11-29 19:03:02 +000096import java.util.concurrent.Executors;
97import java.util.concurrent.ScheduledExecutorService;
98import java.util.concurrent.TimeUnit;
99import static org.onlab.util.Tools.groupedThreads;
100
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700101
102import com.google.common.collect.ImmutableSet;
103
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700104import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
Yi Tseng127ffe52017-09-12 15:55:17 -0700105
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700106/**
107 * DHCP Relay Agent Application Component.
108 */
109@Component(immediate = true)
110@Service
111public class DhcpRelayManager implements DhcpRelayService {
Yi Tseng483ac6f2017-08-02 15:03:31 -0700112 public static final String DHCP_RELAY_APP = "org.onosproject.dhcprelay";
Yi Tseng06799d62017-09-01 16:02:56 -0700113 public static final String ROUTE_STORE_IMPL =
114 "org.onosproject.routeservice.store.RouteStoreImpl";
Yi Tseng525ff402017-10-23 19:39:39 -0700115
Yi Tseng51f1be92017-09-01 17:24:57 -0700116 private static final TrafficSelector ARP_SELECTOR = DefaultTrafficSelector.builder()
117 .matchEthType(Ethernet.TYPE_ARP)
118 .build();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700119 private final Logger log = LoggerFactory.getLogger(getClass());
120 private final InternalConfigListener cfgListener = new InternalConfigListener();
121
122 private final Set<ConfigFactory> factories = ImmutableSet.of(
Yi Tseng483ac6f2017-08-02 15:03:31 -0700123 new ConfigFactory<ApplicationId, DefaultDhcpRelayConfig>(APP_SUBJECT_FACTORY,
Kalhee Kimba366062017-11-07 16:32:09 +0000124 DefaultDhcpRelayConfig.class,
125 DefaultDhcpRelayConfig.KEY,
126 true) {
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700127 @Override
Yi Tseng483ac6f2017-08-02 15:03:31 -0700128 public DefaultDhcpRelayConfig createConfig() {
129 return new DefaultDhcpRelayConfig();
130 }
131 },
132 new ConfigFactory<ApplicationId, IndirectDhcpRelayConfig>(APP_SUBJECT_FACTORY,
Kalhee Kimba366062017-11-07 16:32:09 +0000133 IndirectDhcpRelayConfig.class,
134 IndirectDhcpRelayConfig.KEY,
135 true) {
Yi Tseng483ac6f2017-08-02 15:03:31 -0700136 @Override
137 public IndirectDhcpRelayConfig createConfig() {
138 return new IndirectDhcpRelayConfig();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700139 }
Yi Tseng51f1be92017-09-01 17:24:57 -0700140 },
141 new ConfigFactory<ApplicationId, IgnoreDhcpConfig>(APP_SUBJECT_FACTORY,
Kalhee Kimba366062017-11-07 16:32:09 +0000142 IgnoreDhcpConfig.class,
143 IgnoreDhcpConfig.KEY,
144 true) {
Yi Tseng51f1be92017-09-01 17:24:57 -0700145 @Override
146 public IgnoreDhcpConfig createConfig() {
147 return new IgnoreDhcpConfig();
148 }
Kalhee Kimba366062017-11-07 16:32:09 +0000149 },
150 new ConfigFactory<ApplicationId, EnableDhcpFpmConfig>(APP_SUBJECT_FACTORY,
151 EnableDhcpFpmConfig.class,
152 EnableDhcpFpmConfig.KEY,
153 false) {
154 @Override
155 public EnableDhcpFpmConfig createConfig() {
156 return new EnableDhcpFpmConfig();
157 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700158 }
159 );
160
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000161
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700162 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
163 protected NetworkConfigRegistry cfgService;
164
165 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
166 protected CoreService coreService;
167
168 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
169 protected PacketService packetService;
170
171 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
172 protected HostService hostService;
173
174 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700175 protected InterfaceService interfaceService;
176
177 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
178 protected DhcpRelayStore dhcpRelayStore;
179
180 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
181 protected ComponentConfigService compCfgService;
182
Yi Tseng51f1be92017-09-01 17:24:57 -0700183 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Yi Tseng127ffe52017-09-12 15:55:17 -0700184 protected DeviceService deviceService;
185
Kalhee Kimba366062017-11-07 16:32:09 +0000186 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
187 protected DhcpFpmPrefixStore dhcpFpmPrefixStore;
188
Yi Tseng51301292017-07-28 13:02:59 -0700189 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY,
Yi Tseng127ffe52017-09-12 15:55:17 -0700190 target = "(version=4)")
Yi Tseng51301292017-07-28 13:02:59 -0700191 protected DhcpHandler v4Handler;
192
193 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY,
Yi Tseng127ffe52017-09-12 15:55:17 -0700194 target = "(version=6)")
Yi Tseng51301292017-07-28 13:02:59 -0700195 protected DhcpHandler v6Handler;
196
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700197 @Property(name = "arpEnabled", boolValue = true,
Yi Tseng127ffe52017-09-12 15:55:17 -0700198 label = "Enable Address resolution protocol")
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700199 protected boolean arpEnabled = true;
200
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000201 @Property(name = "dhcpPollInterval", intValue = 24 * 3600,
202 label = "dhcp relay poll interval")
203 protected int dhcpPollInterval = 24 * 3600;
204
Kalhee Kimba366062017-11-07 16:32:09 +0000205 @Property(name = "dhcpFpmEnabled", boolValue = false,
206 label = "Enable DhcpRelay Fpm")
207 protected boolean dhcpFpmEnabled = false;
208
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000209 private ScheduledExecutorService timerExecutor;
210
Yi Tseng127ffe52017-09-12 15:55:17 -0700211 protected DeviceListener deviceListener = new InternalDeviceListener();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700212 private DhcpRelayPacketProcessor dhcpRelayPacketProcessor = new DhcpRelayPacketProcessor();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700213 private ApplicationId appId;
214
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000215 /**
216 * One second timer.
217 */
218 class Dhcp6Timer implements Runnable {
219 @Override
220 public void run() {
221 v6Handler.timeTick();
222 }
223 };
Kalhee Kimba366062017-11-07 16:32:09 +0000224
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700225 @Activate
226 protected void activate(ComponentContext context) {
227 //start the dhcp relay agent
228 appId = coreService.registerApplication(DHCP_RELAY_APP);
229
230 cfgService.addListener(cfgListener);
231 factories.forEach(cfgService::registerConfigFactory);
232 //update the dhcp server configuration.
233 updateConfig();
Yi Tseng51301292017-07-28 13:02:59 -0700234
235 //add the packet processor
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700236 packetService.addProcessor(dhcpRelayPacketProcessor, PacketProcessor.director(0));
Yi Tseng51301292017-07-28 13:02:59 -0700237
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000238 timerExecutor = Executors.newScheduledThreadPool(1,
239 groupedThreads("dhcpRelay",
240 "config-reloader-%d", log));
241 timerExecutor.scheduleAtFixedRate(new Dhcp6Timer(),
242 0,
243 dhcpPollInterval,
244 TimeUnit.SECONDS);
245
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700246 modified(context);
247
Yi Tseng06799d62017-09-01 16:02:56 -0700248 // Enable distribute route store
249 compCfgService.preSetProperty(ROUTE_STORE_IMPL,
Kalhee Kimba366062017-11-07 16:32:09 +0000250 "distributed", Boolean.TRUE.toString());
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700251 compCfgService.registerProperties(getClass());
Yi Tseng127ffe52017-09-12 15:55:17 -0700252
253 deviceService.addListener(deviceListener);
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000254
255
256
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700257 log.info("DHCP-RELAY Started");
258 }
259
260 @Deactivate
261 protected void deactivate() {
262 cfgService.removeListener(cfgListener);
263 factories.forEach(cfgService::unregisterConfigFactory);
264 packetService.removeProcessor(dhcpRelayPacketProcessor);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700265 cancelArpPackets();
Yi Tsengdfa8ee22017-08-07 12:45:01 -0700266 compCfgService.unregisterProperties(getClass(), false);
Yi Tseng127ffe52017-09-12 15:55:17 -0700267 deviceService.removeListener(deviceListener);
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000268 timerExecutor.shutdown();
269
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700270 log.info("DHCP-RELAY Stopped");
271 }
272
273 @Modified
274 protected void modified(ComponentContext context) {
275 Dictionary<?, ?> properties = context.getProperties();
276 Boolean flag;
277
278 flag = Tools.isPropertyEnabled(properties, "arpEnabled");
279 if (flag != null) {
280 arpEnabled = flag;
281 log.info("Address resolution protocol is {}",
Kalhee Kimba366062017-11-07 16:32:09 +0000282 arpEnabled ? "enabled" : "disabled");
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700283 }
284
285 if (arpEnabled) {
286 requestArpPackets();
287 } else {
288 cancelArpPackets();
289 }
Kalhee Kimba366062017-11-07 16:32:09 +0000290
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000291 int intervalVal = Tools.getIntegerProperty(properties, "dhcpPollInterval");
292 log.info("DhcpRelay poll interval new {} old {}", intervalVal, dhcpPollInterval);
293 if (intervalVal != dhcpPollInterval) {
294 timerExecutor.shutdown();
295 dhcpPollInterval = intervalVal;
296 timerExecutor = Executors.newScheduledThreadPool(1,
297 groupedThreads("dhcpRelay",
298 "config-reloader-%d", log));
299 timerExecutor.scheduleAtFixedRate(new Dhcp6Timer(),
300 0,
301 dhcpPollInterval > 1 ? dhcpPollInterval : 1,
302 TimeUnit.SECONDS);
303 v6Handler.setDhcp6PollInterval(dhcpPollInterval);
304 }
305
Kalhee Kimba366062017-11-07 16:32:09 +0000306 flag = Tools.isPropertyEnabled(properties, "dhcpFpmEnabled");
307 if (flag != null) {
308 boolean oldValue = dhcpFpmEnabled;
309 dhcpFpmEnabled = flag;
310 log.info("DhcpRelay FPM is {}",
311 dhcpFpmEnabled ? "enabled" : "disabled");
312
313 if (dhcpFpmEnabled && !oldValue) {
314 log.info("Dhcp Fpm is enabled.");
315 processDhcpFpmRoutes(true);
316 }
317 if (!dhcpFpmEnabled && oldValue) {
318 log.info("Dhcp Fpm is disabled.");
319 processDhcpFpmRoutes(false);
320 }
321 v6Handler.setDhcpFpmEnabled(dhcpFpmEnabled);
322 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700323 }
324
Yi Tseng525ff402017-10-23 19:39:39 -0700325 private static List<TrafficSelector> buildClientDhcpSelectors() {
326 return Streams.concat(Dhcp4HandlerImpl.DHCP_SELECTORS.stream(),
327 Dhcp6HandlerImpl.DHCP_SELECTORS.stream())
328 .collect(Collectors.toList());
329 }
330
Yi Tseng483ac6f2017-08-02 15:03:31 -0700331 /**
332 * Updates DHCP relay app configuration.
333 */
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700334 private void updateConfig() {
Yi Tseng483ac6f2017-08-02 15:03:31 -0700335 DefaultDhcpRelayConfig defaultConfig =
336 cfgService.getConfig(appId, DefaultDhcpRelayConfig.class);
337 IndirectDhcpRelayConfig indirectConfig =
338 cfgService.getConfig(appId, IndirectDhcpRelayConfig.class);
Yi Tseng51f1be92017-09-01 17:24:57 -0700339 IgnoreDhcpConfig ignoreDhcpConfig =
340 cfgService.getConfig(appId, IgnoreDhcpConfig.class);
Yi Tseng483ac6f2017-08-02 15:03:31 -0700341
342 if (defaultConfig != null) {
343 updateConfig(defaultConfig);
344 }
Yi Tseng483ac6f2017-08-02 15:03:31 -0700345 if (indirectConfig != null) {
346 updateConfig(indirectConfig);
347 }
Yi Tseng51f1be92017-09-01 17:24:57 -0700348 if (ignoreDhcpConfig != null) {
349 updateConfig(ignoreDhcpConfig);
350 }
Yi Tseng483ac6f2017-08-02 15:03:31 -0700351 }
352
353 /**
354 * Updates DHCP relay app configuration with given configuration.
355 *
356 * @param config the configuration ot update
357 */
Yi Tseng51f1be92017-09-01 17:24:57 -0700358 protected void updateConfig(Config config) {
Yi Tseng483ac6f2017-08-02 15:03:31 -0700359 if (config instanceof IndirectDhcpRelayConfig) {
360 IndirectDhcpRelayConfig indirectConfig = (IndirectDhcpRelayConfig) config;
361 v4Handler.setIndirectDhcpServerConfigs(indirectConfig.dhcpServerConfigs());
362 v6Handler.setIndirectDhcpServerConfigs(indirectConfig.dhcpServerConfigs());
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700363 } else if (config instanceof DefaultDhcpRelayConfig) {
364 DefaultDhcpRelayConfig defaultConfig = (DefaultDhcpRelayConfig) config;
365 v4Handler.setDefaultDhcpServerConfigs(defaultConfig.dhcpServerConfigs());
366 v6Handler.setDefaultDhcpServerConfigs(defaultConfig.dhcpServerConfigs());
Yi Tseng483ac6f2017-08-02 15:03:31 -0700367 }
Yi Tseng51f1be92017-09-01 17:24:57 -0700368 if (config instanceof IgnoreDhcpConfig) {
Yi Tseng525ff402017-10-23 19:39:39 -0700369 v4Handler.updateIgnoreVlanConfig((IgnoreDhcpConfig) config);
370 v6Handler.updateIgnoreVlanConfig((IgnoreDhcpConfig) config);
Yi Tseng51f1be92017-09-01 17:24:57 -0700371 }
372 }
373
374 protected void removeConfig(Config config) {
375 if (config instanceof IndirectDhcpRelayConfig) {
376 v4Handler.setIndirectDhcpServerConfigs(Collections.emptyList());
377 v6Handler.setIndirectDhcpServerConfigs(Collections.emptyList());
378 } else if (config instanceof DefaultDhcpRelayConfig) {
379 v4Handler.setDefaultDhcpServerConfigs(Collections.emptyList());
380 v6Handler.setDefaultDhcpServerConfigs(Collections.emptyList());
381 }
382 if (config instanceof IgnoreDhcpConfig) {
Yi Tseng525ff402017-10-23 19:39:39 -0700383 v4Handler.updateIgnoreVlanConfig(null);
384 v6Handler.updateIgnoreVlanConfig(null);
Yi Tseng51f1be92017-09-01 17:24:57 -0700385 }
386 }
387
Kalhee Kimba366062017-11-07 16:32:09 +0000388 private void processDhcpFpmRoutes(Boolean add) {
389 // needs to restore/remove fpm
390 }
391
392 public boolean isDhcpFpmEnabled() {
393 return dhcpFpmEnabled;
394 }
395
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700396 /**
397 * Request ARP packet in via PacketService.
398 */
399 private void requestArpPackets() {
Yi Tseng51f1be92017-09-01 17:24:57 -0700400 packetService.requestPackets(ARP_SELECTOR, PacketPriority.CONTROL, appId);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700401 }
402
403 /**
404 * Cancel requested ARP packets in via packet service.
405 */
406 private void cancelArpPackets() {
Yi Tseng51f1be92017-09-01 17:24:57 -0700407 packetService.cancelPackets(ARP_SELECTOR, PacketPriority.CONTROL, appId);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700408 }
409
410 @Override
411 public Optional<DhcpRecord> getDhcpRecord(HostId hostId) {
412 return dhcpRelayStore.getDhcpRecord(hostId);
413 }
414
415 @Override
416 public Collection<DhcpRecord> getDhcpRecords() {
417 return dhcpRelayStore.getDhcpRecords();
418 }
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000419 @Override
420 public void updateDhcpRecord(HostId hostId, DhcpRecord dhcpRecord) {
421 dhcpRelayStore.updateDhcpRecord(hostId, dhcpRecord);
422 }
Yi Tseng13a41a12017-07-26 13:45:01 -0700423 @Override
424 public Optional<MacAddress> getDhcpServerMacAddress() {
Yi Tseng4f2a0462017-08-31 11:21:00 -0700425 // TODO: depreated it
426 DefaultDhcpRelayConfig config = cfgService.getConfig(appId, DefaultDhcpRelayConfig.class);
427 DhcpServerConfig serverConfig = config.dhcpServerConfigs().get(0);
428 Ip4Address serverip = serverConfig.getDhcpServerIp4().get();
429 return hostService.getHostsByIp(serverip)
430 .stream()
431 .map(Host::mac)
432 .findFirst();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700433 }
434
Yi Tseng919b2df2017-09-07 16:22:51 -0700435 @Override
436 public List<DhcpServerInfo> getDefaultDhcpServerInfoList() {
437 return ImmutableList.<DhcpServerInfo>builder()
438 .addAll(v4Handler.getDefaultDhcpServerInfoList())
439 .addAll(v6Handler.getDefaultDhcpServerInfoList())
440 .build();
441 }
442
443 @Override
444 public List<DhcpServerInfo> getIndirectDhcpServerInfoList() {
445 return ImmutableList.<DhcpServerInfo>builder()
446 .addAll(v4Handler.getIndirectDhcpServerInfoList())
447 .addAll(v6Handler.getIndirectDhcpServerInfoList())
448 .build();
449 }
450
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700451 /**
452 * Gets DHCP data from a packet.
453 *
454 * @param packet the packet
455 * @return the DHCP data; empty if it is not a DHCP packet
456 */
457 private Optional<DHCP> findDhcp(Ethernet packet) {
458 return Stream.of(packet)
459 .filter(Objects::nonNull)
460 .map(Ethernet::getPayload)
461 .filter(p -> p instanceof IPv4)
462 .map(IPacket::getPayload)
463 .filter(Objects::nonNull)
464 .filter(p -> p instanceof UDP)
465 .map(IPacket::getPayload)
466 .filter(Objects::nonNull)
467 .filter(p -> p instanceof DHCP)
468 .map(p -> (DHCP) p)
469 .findFirst();
470 }
471
472 /**
473 * Gets DHCPv6 data from a packet.
474 *
475 * @param packet the packet
476 * @return the DHCPv6 data; empty if it is not a DHCPv6 packet
477 */
478 private Optional<DHCP6> findDhcp6(Ethernet packet) {
479 return Stream.of(packet)
480 .filter(Objects::nonNull)
481 .map(Ethernet::getPayload)
482 .filter(p -> p instanceof IPv6)
483 .map(IPacket::getPayload)
484 .filter(Objects::nonNull)
485 .filter(p -> p instanceof UDP)
486 .map(IPacket::getPayload)
487 .filter(Objects::nonNull)
488 .filter(p -> p instanceof DHCP6)
489 .map(p -> (DHCP6) p)
490 .findFirst();
491 }
492
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700493
494 private class DhcpRelayPacketProcessor implements PacketProcessor {
495
496 @Override
497 public void process(PacketContext context) {
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700498 // process the packet and get the payload
499 Ethernet packet = context.inPacket().parsed();
500 if (packet == null) {
501 return;
502 }
503
504 findDhcp(packet).ifPresent(dhcpPayload -> {
Yi Tseng51301292017-07-28 13:02:59 -0700505 v4Handler.processDhcpPacket(context, dhcpPayload);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700506 });
507
508 findDhcp6(packet).ifPresent(dhcp6Payload -> {
Yi Tseng51301292017-07-28 13:02:59 -0700509 v6Handler.processDhcpPacket(context, dhcp6Payload);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700510 });
511
512 if (packet.getEtherType() == Ethernet.TYPE_ARP && arpEnabled) {
513 ARP arpPacket = (ARP) packet.getPayload();
514 VlanId vlanId = VlanId.vlanId(packet.getVlanID());
515 Set<Interface> interfaces = interfaceService.
516 getInterfacesByPort(context.inPacket().receivedFrom());
517 //ignore the packets if dhcp server interface is not configured on onos.
518 if (interfaces.isEmpty()) {
519 log.warn("server virtual interface not configured");
520 return;
521 }
522 if ((arpPacket.getOpCode() != ARP.OP_REQUEST)) {
523 // handle request only
524 return;
525 }
526 MacAddress interfaceMac = interfaces.stream()
527 .filter(iface -> iface.vlan().equals(vlanId))
528 .map(Interface::mac)
529 .filter(mac -> !mac.equals(MacAddress.NONE))
530 .findFirst()
Yi Tseng51301292017-07-28 13:02:59 -0700531 .orElse(MacAddress.ONOS);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700532 if (interfaceMac == null) {
533 // can't find interface mac address
534 return;
535 }
536 processArpPacket(context, packet, interfaceMac);
537 }
538 }
539
540 /**
541 * Processes the ARP Payload and initiates a reply to the client.
542 *
543 * @param context the packet context
544 * @param packet the ethernet payload
545 * @param replyMac mac address to be replied
546 */
547 private void processArpPacket(PacketContext context, Ethernet packet, MacAddress replyMac) {
548 ARP arpPacket = (ARP) packet.getPayload();
Ray Milkeyf0c47612017-09-28 11:29:38 -0700549 ARP arpReply = arpPacket.duplicate();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700550 arpReply.setOpCode(ARP.OP_REPLY);
551
552 arpReply.setTargetProtocolAddress(arpPacket.getSenderProtocolAddress());
553 arpReply.setTargetHardwareAddress(arpPacket.getSenderHardwareAddress());
554 arpReply.setSenderProtocolAddress(arpPacket.getTargetProtocolAddress());
555 arpReply.setSenderHardwareAddress(replyMac.toBytes());
556
557 // Ethernet Frame.
558 Ethernet ethReply = new Ethernet();
559 ethReply.setSourceMACAddress(replyMac.toBytes());
560 ethReply.setDestinationMACAddress(packet.getSourceMAC());
561 ethReply.setEtherType(Ethernet.TYPE_ARP);
562 ethReply.setVlanID(packet.getVlanID());
563 ethReply.setPayload(arpReply);
564
565 ConnectPoint targetPort = context.inPacket().receivedFrom();
566 TrafficTreatment t = DefaultTrafficTreatment.builder()
567 .setOutput(targetPort.port()).build();
568 OutboundPacket o = new DefaultOutboundPacket(
569 targetPort.deviceId(), t, ByteBuffer.wrap(ethReply.serialize()));
570 if (log.isTraceEnabled()) {
571 log.trace("Relaying ARP packet {} to {}", packet, targetPort);
572 }
573 packetService.emit(o);
574 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700575 }
576
577 /**
578 * Listener for network config events.
579 */
580 private class InternalConfigListener implements NetworkConfigListener {
581 @Override
582 public void event(NetworkConfigEvent event) {
Yi Tseng51f1be92017-09-01 17:24:57 -0700583 switch (event.type()) {
584 case CONFIG_UPDATED:
585 case CONFIG_ADDED:
586 event.config().ifPresent(config -> {
587 updateConfig(config);
588 log.info("{} updated", config.getClass().getSimpleName());
589 });
590 break;
591 case CONFIG_REMOVED:
592 event.prevConfig().ifPresent(config -> {
593 removeConfig(config);
594 log.info("{} removed", config.getClass().getSimpleName());
595 });
596 break;
Charles Chan10b2fee2018-04-21 00:44:29 -0700597 case CONFIG_REGISTERED:
598 case CONFIG_UNREGISTERED:
599 break;
Yi Tseng51f1be92017-09-01 17:24:57 -0700600 default:
601 log.warn("Unsupported event type {}", event.type());
602 break;
Yi Tseng483ac6f2017-08-02 15:03:31 -0700603 }
Charles Chan50443e82018-01-03 16:26:32 -0800604 }
Yi Tseng51f1be92017-09-01 17:24:57 -0700605
Charles Chan50443e82018-01-03 16:26:32 -0800606 @Override
607 public boolean isRelevant(NetworkConfigEvent event) {
608 if (event.configClass().equals(DefaultDhcpRelayConfig.class) ||
609 event.configClass().equals(IndirectDhcpRelayConfig.class) ||
610 event.configClass().equals(IgnoreDhcpConfig.class)) {
611 return true;
612 }
613 log.debug("Ignore irrelevant event class {}", event.configClass().getName());
614 return false;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700615 }
616 }
Yi Tseng127ffe52017-09-12 15:55:17 -0700617
618 private class InternalDeviceListener implements DeviceListener {
619
620 @Override
621 public void event(DeviceEvent event) {
622 Device device = event.subject();
623 switch (event.type()) {
624 case DEVICE_ADDED:
Yi Tseng525ff402017-10-23 19:39:39 -0700625 updateIgnoreVlanConfigs();
Yi Tseng127ffe52017-09-12 15:55:17 -0700626 break;
627 case DEVICE_AVAILABILITY_CHANGED:
628 deviceAvailabilityChanged(device);
Ray Milkeyd6a67c32018-02-02 10:30:35 -0800629 break;
Yi Tseng127ffe52017-09-12 15:55:17 -0700630 default:
631 break;
632 }
633 }
634
635 private void deviceAvailabilityChanged(Device device) {
636 if (deviceService.isAvailable(device.id())) {
Yi Tseng525ff402017-10-23 19:39:39 -0700637 updateIgnoreVlanConfigs();
Saurav Dasb805f1a2017-12-13 16:19:35 -0800638 } else {
639 removeIgnoreVlanState();
Yi Tseng127ffe52017-09-12 15:55:17 -0700640 }
641 }
642
Yi Tseng525ff402017-10-23 19:39:39 -0700643 private void updateIgnoreVlanConfigs() {
Yi Tseng127ffe52017-09-12 15:55:17 -0700644 IgnoreDhcpConfig config = cfgService.getConfig(appId, IgnoreDhcpConfig.class);
Yi Tseng525ff402017-10-23 19:39:39 -0700645 v4Handler.updateIgnoreVlanConfig(config);
646 v6Handler.updateIgnoreVlanConfig(config);
Yi Tseng127ffe52017-09-12 15:55:17 -0700647 }
Saurav Dasb805f1a2017-12-13 16:19:35 -0800648
649 private void removeIgnoreVlanState() {
650 IgnoreDhcpConfig config = cfgService.getConfig(appId, IgnoreDhcpConfig.class);
651 v4Handler.removeIgnoreVlanState(config);
652 v6Handler.removeIgnoreVlanState(config);
653 }
Yi Tseng127ffe52017-09-12 15:55:17 -0700654 }
Kalhee Kimba366062017-11-07 16:32:09 +0000655
656
657
658 public Optional<FpmRecord> getFpmRecord(IpPrefix prefix) {
659 return dhcpFpmPrefixStore.getFpmRecord(prefix);
660 }
661
662 public Collection<FpmRecord> getFpmRecords() {
663 return dhcpFpmPrefixStore.getFpmRecords();
664 }
665
666 @Override
667 public void addFpmRecord(IpPrefix prefix, FpmRecord fpmRecord) {
668 dhcpFpmPrefixStore.addFpmRecord(prefix, fpmRecord);
669 }
670
671 @Override
672 public Optional<FpmRecord> removeFpmRecord(IpPrefix prefix) {
673 return dhcpFpmPrefixStore.removeFpmRecord(prefix);
674 }
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000675
676
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700677}