blob: f2c1b87909a9717f3a34bcb583183c6b76c218db [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;
Yi Tseng51f1be92017-09-01 17:24:57 -070059import org.onosproject.dhcprelay.config.IgnoreDhcpConfig;
Yi Tseng483ac6f2017-08-02 15:03:31 -070060import org.onosproject.dhcprelay.config.IndirectDhcpRelayConfig;
Kalhee Kimba366062017-11-07 16:32:09 +000061import org.onosproject.dhcprelay.config.EnableDhcpFpmConfig;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070062import org.onosproject.dhcprelay.store.DhcpRecord;
63import org.onosproject.dhcprelay.store.DhcpRelayStore;
Kalhee Kimba366062017-11-07 16:32:09 +000064import org.onosproject.dhcprelay.store.DhcpFpmPrefixStore;
65import org.onosproject.routing.fpm.api.FpmRecord;
Yi Tseng127ffe52017-09-12 15:55:17 -070066import org.onosproject.net.Device;
Yi Tseng4f2a0462017-08-31 11:21:00 -070067import org.onosproject.dhcprelay.config.DhcpServerConfig;
68import 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
210 private ScheduledExecutorService timerExecutor;
211
Yi Tseng127ffe52017-09-12 15:55:17 -0700212 protected DeviceListener deviceListener = new InternalDeviceListener();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700213 private DhcpRelayPacketProcessor dhcpRelayPacketProcessor = new DhcpRelayPacketProcessor();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700214 private ApplicationId appId;
215
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000216 /**
217 * One second timer.
218 */
219 class Dhcp6Timer implements Runnable {
220 @Override
221 public void run() {
222 v6Handler.timeTick();
223 }
224 };
Kalhee Kimba366062017-11-07 16:32:09 +0000225
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700226 @Activate
227 protected void activate(ComponentContext context) {
228 //start the dhcp relay agent
229 appId = coreService.registerApplication(DHCP_RELAY_APP);
230
231 cfgService.addListener(cfgListener);
232 factories.forEach(cfgService::registerConfigFactory);
233 //update the dhcp server configuration.
234 updateConfig();
Yi Tseng51301292017-07-28 13:02:59 -0700235
236 //add the packet processor
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700237 packetService.addProcessor(dhcpRelayPacketProcessor, PacketProcessor.director(0));
Yi Tseng51301292017-07-28 13:02:59 -0700238
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000239 timerExecutor = Executors.newScheduledThreadPool(1,
240 groupedThreads("dhcpRelay",
241 "config-reloader-%d", log));
242 timerExecutor.scheduleAtFixedRate(new Dhcp6Timer(),
243 0,
244 dhcpPollInterval,
245 TimeUnit.SECONDS);
246
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700247 modified(context);
248
Yi Tseng06799d62017-09-01 16:02:56 -0700249 // Enable distribute route store
250 compCfgService.preSetProperty(ROUTE_STORE_IMPL,
Kalhee Kimba366062017-11-07 16:32:09 +0000251 "distributed", Boolean.TRUE.toString());
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700252 compCfgService.registerProperties(getClass());
Yi Tseng127ffe52017-09-12 15:55:17 -0700253
254 deviceService.addListener(deviceListener);
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000255
256
257
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700258 log.info("DHCP-RELAY Started");
259 }
260
261 @Deactivate
262 protected void deactivate() {
263 cfgService.removeListener(cfgListener);
264 factories.forEach(cfgService::unregisterConfigFactory);
265 packetService.removeProcessor(dhcpRelayPacketProcessor);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700266 cancelArpPackets();
Yi Tsengdfa8ee22017-08-07 12:45:01 -0700267 compCfgService.unregisterProperties(getClass(), false);
Yi Tseng127ffe52017-09-12 15:55:17 -0700268 deviceService.removeListener(deviceListener);
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000269 timerExecutor.shutdown();
270
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700271 log.info("DHCP-RELAY Stopped");
272 }
273
274 @Modified
275 protected void modified(ComponentContext context) {
276 Dictionary<?, ?> properties = context.getProperties();
277 Boolean flag;
278
279 flag = Tools.isPropertyEnabled(properties, "arpEnabled");
280 if (flag != null) {
281 arpEnabled = flag;
282 log.info("Address resolution protocol is {}",
Kalhee Kimba366062017-11-07 16:32:09 +0000283 arpEnabled ? "enabled" : "disabled");
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700284 }
285
286 if (arpEnabled) {
287 requestArpPackets();
288 } else {
289 cancelArpPackets();
290 }
Kalhee Kimba366062017-11-07 16:32:09 +0000291
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000292 int intervalVal = Tools.getIntegerProperty(properties, "dhcpPollInterval");
293 log.info("DhcpRelay poll interval new {} old {}", intervalVal, dhcpPollInterval);
294 if (intervalVal != dhcpPollInterval) {
295 timerExecutor.shutdown();
296 dhcpPollInterval = intervalVal;
297 timerExecutor = Executors.newScheduledThreadPool(1,
298 groupedThreads("dhcpRelay",
299 "config-reloader-%d", log));
300 timerExecutor.scheduleAtFixedRate(new Dhcp6Timer(),
301 0,
302 dhcpPollInterval > 1 ? dhcpPollInterval : 1,
303 TimeUnit.SECONDS);
304 v6Handler.setDhcp6PollInterval(dhcpPollInterval);
305 }
306
Kalhee Kimba366062017-11-07 16:32:09 +0000307 flag = Tools.isPropertyEnabled(properties, "dhcpFpmEnabled");
308 if (flag != null) {
309 boolean oldValue = dhcpFpmEnabled;
310 dhcpFpmEnabled = flag;
311 log.info("DhcpRelay FPM is {}",
312 dhcpFpmEnabled ? "enabled" : "disabled");
313
314 if (dhcpFpmEnabled && !oldValue) {
315 log.info("Dhcp Fpm is enabled.");
316 processDhcpFpmRoutes(true);
317 }
318 if (!dhcpFpmEnabled && oldValue) {
319 log.info("Dhcp Fpm is disabled.");
320 processDhcpFpmRoutes(false);
321 }
322 v6Handler.setDhcpFpmEnabled(dhcpFpmEnabled);
323 }
324
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700325 }
326
Yi Tseng525ff402017-10-23 19:39:39 -0700327 private static List<TrafficSelector> buildClientDhcpSelectors() {
328 return Streams.concat(Dhcp4HandlerImpl.DHCP_SELECTORS.stream(),
329 Dhcp6HandlerImpl.DHCP_SELECTORS.stream())
330 .collect(Collectors.toList());
331 }
332
Yi Tseng483ac6f2017-08-02 15:03:31 -0700333 /**
334 * Updates DHCP relay app configuration.
335 */
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700336 private void updateConfig() {
Yi Tseng483ac6f2017-08-02 15:03:31 -0700337 DefaultDhcpRelayConfig defaultConfig =
338 cfgService.getConfig(appId, DefaultDhcpRelayConfig.class);
339 IndirectDhcpRelayConfig indirectConfig =
340 cfgService.getConfig(appId, IndirectDhcpRelayConfig.class);
Yi Tseng51f1be92017-09-01 17:24:57 -0700341 IgnoreDhcpConfig ignoreDhcpConfig =
342 cfgService.getConfig(appId, IgnoreDhcpConfig.class);
Yi Tseng483ac6f2017-08-02 15:03:31 -0700343
344 if (defaultConfig != null) {
345 updateConfig(defaultConfig);
346 }
Yi Tseng483ac6f2017-08-02 15:03:31 -0700347 if (indirectConfig != null) {
348 updateConfig(indirectConfig);
349 }
Yi Tseng51f1be92017-09-01 17:24:57 -0700350 if (ignoreDhcpConfig != null) {
351 updateConfig(ignoreDhcpConfig);
352 }
Yi Tseng483ac6f2017-08-02 15:03:31 -0700353 }
354
355 /**
356 * Updates DHCP relay app configuration with given configuration.
357 *
358 * @param config the configuration ot update
359 */
Yi Tseng51f1be92017-09-01 17:24:57 -0700360 protected void updateConfig(Config config) {
Yi Tseng483ac6f2017-08-02 15:03:31 -0700361 if (config instanceof IndirectDhcpRelayConfig) {
362 IndirectDhcpRelayConfig indirectConfig = (IndirectDhcpRelayConfig) config;
363 v4Handler.setIndirectDhcpServerConfigs(indirectConfig.dhcpServerConfigs());
364 v6Handler.setIndirectDhcpServerConfigs(indirectConfig.dhcpServerConfigs());
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700365 } else if (config instanceof DefaultDhcpRelayConfig) {
366 DefaultDhcpRelayConfig defaultConfig = (DefaultDhcpRelayConfig) config;
367 v4Handler.setDefaultDhcpServerConfigs(defaultConfig.dhcpServerConfigs());
368 v6Handler.setDefaultDhcpServerConfigs(defaultConfig.dhcpServerConfigs());
Yi Tseng483ac6f2017-08-02 15:03:31 -0700369 }
Yi Tseng51f1be92017-09-01 17:24:57 -0700370 if (config instanceof IgnoreDhcpConfig) {
Yi Tseng525ff402017-10-23 19:39:39 -0700371 v4Handler.updateIgnoreVlanConfig((IgnoreDhcpConfig) config);
372 v6Handler.updateIgnoreVlanConfig((IgnoreDhcpConfig) config);
Yi Tseng51f1be92017-09-01 17:24:57 -0700373 }
374 }
375
376 protected void removeConfig(Config config) {
377 if (config instanceof IndirectDhcpRelayConfig) {
378 v4Handler.setIndirectDhcpServerConfigs(Collections.emptyList());
379 v6Handler.setIndirectDhcpServerConfigs(Collections.emptyList());
380 } else if (config instanceof DefaultDhcpRelayConfig) {
381 v4Handler.setDefaultDhcpServerConfigs(Collections.emptyList());
382 v6Handler.setDefaultDhcpServerConfigs(Collections.emptyList());
383 }
384 if (config instanceof IgnoreDhcpConfig) {
Yi Tseng525ff402017-10-23 19:39:39 -0700385 v4Handler.updateIgnoreVlanConfig(null);
386 v6Handler.updateIgnoreVlanConfig(null);
Yi Tseng51f1be92017-09-01 17:24:57 -0700387 }
388 }
389
Kalhee Kimba366062017-11-07 16:32:09 +0000390 private void processDhcpFpmRoutes(Boolean add) {
391 // needs to restore/remove fpm
392 }
393
394 public boolean isDhcpFpmEnabled() {
395 return dhcpFpmEnabled;
396 }
397
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700398 /**
399 * Request ARP packet in via PacketService.
400 */
401 private void requestArpPackets() {
Yi Tseng51f1be92017-09-01 17:24:57 -0700402 packetService.requestPackets(ARP_SELECTOR, PacketPriority.CONTROL, appId);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700403 }
404
405 /**
406 * Cancel requested ARP packets in via packet service.
407 */
408 private void cancelArpPackets() {
Yi Tseng51f1be92017-09-01 17:24:57 -0700409 packetService.cancelPackets(ARP_SELECTOR, PacketPriority.CONTROL, appId);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700410 }
411
412 @Override
413 public Optional<DhcpRecord> getDhcpRecord(HostId hostId) {
414 return dhcpRelayStore.getDhcpRecord(hostId);
415 }
416
417 @Override
418 public Collection<DhcpRecord> getDhcpRecords() {
419 return dhcpRelayStore.getDhcpRecords();
420 }
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000421 @Override
422 public void updateDhcpRecord(HostId hostId, DhcpRecord dhcpRecord) {
423 dhcpRelayStore.updateDhcpRecord(hostId, dhcpRecord);
424 }
Yi Tseng13a41a12017-07-26 13:45:01 -0700425 @Override
426 public Optional<MacAddress> getDhcpServerMacAddress() {
Yi Tseng4f2a0462017-08-31 11:21:00 -0700427 // TODO: depreated it
428 DefaultDhcpRelayConfig config = cfgService.getConfig(appId, DefaultDhcpRelayConfig.class);
429 DhcpServerConfig serverConfig = config.dhcpServerConfigs().get(0);
430 Ip4Address serverip = serverConfig.getDhcpServerIp4().get();
431 return hostService.getHostsByIp(serverip)
432 .stream()
433 .map(Host::mac)
434 .findFirst();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700435 }
436
Yi Tseng919b2df2017-09-07 16:22:51 -0700437 @Override
438 public List<DhcpServerInfo> getDefaultDhcpServerInfoList() {
439 return ImmutableList.<DhcpServerInfo>builder()
440 .addAll(v4Handler.getDefaultDhcpServerInfoList())
441 .addAll(v6Handler.getDefaultDhcpServerInfoList())
442 .build();
443 }
444
445 @Override
446 public List<DhcpServerInfo> getIndirectDhcpServerInfoList() {
447 return ImmutableList.<DhcpServerInfo>builder()
448 .addAll(v4Handler.getIndirectDhcpServerInfoList())
449 .addAll(v6Handler.getIndirectDhcpServerInfoList())
450 .build();
451 }
452
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700453 /**
454 * Gets DHCP data from a packet.
455 *
456 * @param packet the packet
457 * @return the DHCP data; empty if it is not a DHCP packet
458 */
459 private Optional<DHCP> findDhcp(Ethernet packet) {
460 return Stream.of(packet)
461 .filter(Objects::nonNull)
462 .map(Ethernet::getPayload)
463 .filter(p -> p instanceof IPv4)
464 .map(IPacket::getPayload)
465 .filter(Objects::nonNull)
466 .filter(p -> p instanceof UDP)
467 .map(IPacket::getPayload)
468 .filter(Objects::nonNull)
469 .filter(p -> p instanceof DHCP)
470 .map(p -> (DHCP) p)
471 .findFirst();
472 }
473
474 /**
475 * Gets DHCPv6 data from a packet.
476 *
477 * @param packet the packet
478 * @return the DHCPv6 data; empty if it is not a DHCPv6 packet
479 */
480 private Optional<DHCP6> findDhcp6(Ethernet packet) {
481 return Stream.of(packet)
482 .filter(Objects::nonNull)
483 .map(Ethernet::getPayload)
484 .filter(p -> p instanceof IPv6)
485 .map(IPacket::getPayload)
486 .filter(Objects::nonNull)
487 .filter(p -> p instanceof UDP)
488 .map(IPacket::getPayload)
489 .filter(Objects::nonNull)
490 .filter(p -> p instanceof DHCP6)
491 .map(p -> (DHCP6) p)
492 .findFirst();
493 }
494
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700495
496 private class DhcpRelayPacketProcessor implements PacketProcessor {
497
498 @Override
499 public void process(PacketContext context) {
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700500 // process the packet and get the payload
501 Ethernet packet = context.inPacket().parsed();
502 if (packet == null) {
503 return;
504 }
505
506 findDhcp(packet).ifPresent(dhcpPayload -> {
Yi Tseng51301292017-07-28 13:02:59 -0700507 v4Handler.processDhcpPacket(context, dhcpPayload);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700508 });
509
510 findDhcp6(packet).ifPresent(dhcp6Payload -> {
Yi Tseng51301292017-07-28 13:02:59 -0700511 v6Handler.processDhcpPacket(context, dhcp6Payload);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700512 });
513
514 if (packet.getEtherType() == Ethernet.TYPE_ARP && arpEnabled) {
515 ARP arpPacket = (ARP) packet.getPayload();
516 VlanId vlanId = VlanId.vlanId(packet.getVlanID());
517 Set<Interface> interfaces = interfaceService.
518 getInterfacesByPort(context.inPacket().receivedFrom());
519 //ignore the packets if dhcp server interface is not configured on onos.
520 if (interfaces.isEmpty()) {
521 log.warn("server virtual interface not configured");
522 return;
523 }
524 if ((arpPacket.getOpCode() != ARP.OP_REQUEST)) {
525 // handle request only
526 return;
527 }
528 MacAddress interfaceMac = interfaces.stream()
529 .filter(iface -> iface.vlan().equals(vlanId))
530 .map(Interface::mac)
531 .filter(mac -> !mac.equals(MacAddress.NONE))
532 .findFirst()
Yi Tseng51301292017-07-28 13:02:59 -0700533 .orElse(MacAddress.ONOS);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700534 if (interfaceMac == null) {
535 // can't find interface mac address
536 return;
537 }
538 processArpPacket(context, packet, interfaceMac);
539 }
540 }
541
542 /**
543 * Processes the ARP Payload and initiates a reply to the client.
544 *
545 * @param context the packet context
546 * @param packet the ethernet payload
547 * @param replyMac mac address to be replied
548 */
549 private void processArpPacket(PacketContext context, Ethernet packet, MacAddress replyMac) {
550 ARP arpPacket = (ARP) packet.getPayload();
Ray Milkeyf0c47612017-09-28 11:29:38 -0700551 ARP arpReply = arpPacket.duplicate();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700552 arpReply.setOpCode(ARP.OP_REPLY);
553
554 arpReply.setTargetProtocolAddress(arpPacket.getSenderProtocolAddress());
555 arpReply.setTargetHardwareAddress(arpPacket.getSenderHardwareAddress());
556 arpReply.setSenderProtocolAddress(arpPacket.getTargetProtocolAddress());
557 arpReply.setSenderHardwareAddress(replyMac.toBytes());
558
559 // Ethernet Frame.
560 Ethernet ethReply = new Ethernet();
561 ethReply.setSourceMACAddress(replyMac.toBytes());
562 ethReply.setDestinationMACAddress(packet.getSourceMAC());
563 ethReply.setEtherType(Ethernet.TYPE_ARP);
564 ethReply.setVlanID(packet.getVlanID());
565 ethReply.setPayload(arpReply);
566
567 ConnectPoint targetPort = context.inPacket().receivedFrom();
568 TrafficTreatment t = DefaultTrafficTreatment.builder()
569 .setOutput(targetPort.port()).build();
570 OutboundPacket o = new DefaultOutboundPacket(
571 targetPort.deviceId(), t, ByteBuffer.wrap(ethReply.serialize()));
572 if (log.isTraceEnabled()) {
573 log.trace("Relaying ARP packet {} to {}", packet, targetPort);
574 }
575 packetService.emit(o);
576 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700577 }
578
579 /**
580 * Listener for network config events.
581 */
582 private class InternalConfigListener implements NetworkConfigListener {
583 @Override
584 public void event(NetworkConfigEvent event) {
Yi Tseng51f1be92017-09-01 17:24:57 -0700585 switch (event.type()) {
586 case CONFIG_UPDATED:
587 case CONFIG_ADDED:
588 event.config().ifPresent(config -> {
589 updateConfig(config);
590 log.info("{} updated", config.getClass().getSimpleName());
591 });
592 break;
593 case CONFIG_REMOVED:
594 event.prevConfig().ifPresent(config -> {
595 removeConfig(config);
596 log.info("{} removed", config.getClass().getSimpleName());
597 });
598 break;
Charles Chan10b2fee2018-04-21 00:44:29 -0700599 case CONFIG_REGISTERED:
600 case CONFIG_UNREGISTERED:
601 break;
Yi Tseng51f1be92017-09-01 17:24:57 -0700602 default:
603 log.warn("Unsupported event type {}", event.type());
604 break;
Yi Tseng483ac6f2017-08-02 15:03:31 -0700605 }
Charles Chan50443e82018-01-03 16:26:32 -0800606 }
Yi Tseng51f1be92017-09-01 17:24:57 -0700607
Charles Chan50443e82018-01-03 16:26:32 -0800608 @Override
609 public boolean isRelevant(NetworkConfigEvent event) {
610 if (event.configClass().equals(DefaultDhcpRelayConfig.class) ||
611 event.configClass().equals(IndirectDhcpRelayConfig.class) ||
612 event.configClass().equals(IgnoreDhcpConfig.class)) {
613 return true;
614 }
615 log.debug("Ignore irrelevant event class {}", event.configClass().getName());
616 return false;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700617 }
618 }
Yi Tseng127ffe52017-09-12 15:55:17 -0700619
620 private class InternalDeviceListener implements DeviceListener {
621
622 @Override
623 public void event(DeviceEvent event) {
624 Device device = event.subject();
625 switch (event.type()) {
626 case DEVICE_ADDED:
Yi Tseng525ff402017-10-23 19:39:39 -0700627 updateIgnoreVlanConfigs();
Yi Tseng127ffe52017-09-12 15:55:17 -0700628 break;
629 case DEVICE_AVAILABILITY_CHANGED:
630 deviceAvailabilityChanged(device);
Ray Milkeyd6a67c32018-02-02 10:30:35 -0800631 break;
Yi Tseng127ffe52017-09-12 15:55:17 -0700632 default:
633 break;
634 }
635 }
636
637 private void deviceAvailabilityChanged(Device device) {
638 if (deviceService.isAvailable(device.id())) {
Yi Tseng525ff402017-10-23 19:39:39 -0700639 updateIgnoreVlanConfigs();
Saurav Dasb805f1a2017-12-13 16:19:35 -0800640 } else {
641 removeIgnoreVlanState();
Yi Tseng127ffe52017-09-12 15:55:17 -0700642 }
643 }
644
Yi Tseng525ff402017-10-23 19:39:39 -0700645 private void updateIgnoreVlanConfigs() {
Yi Tseng127ffe52017-09-12 15:55:17 -0700646 IgnoreDhcpConfig config = cfgService.getConfig(appId, IgnoreDhcpConfig.class);
Yi Tseng525ff402017-10-23 19:39:39 -0700647 v4Handler.updateIgnoreVlanConfig(config);
648 v6Handler.updateIgnoreVlanConfig(config);
Yi Tseng127ffe52017-09-12 15:55:17 -0700649 }
Saurav Dasb805f1a2017-12-13 16:19:35 -0800650
651 private void removeIgnoreVlanState() {
652 IgnoreDhcpConfig config = cfgService.getConfig(appId, IgnoreDhcpConfig.class);
653 v4Handler.removeIgnoreVlanState(config);
654 v6Handler.removeIgnoreVlanState(config);
655 }
Yi Tseng127ffe52017-09-12 15:55:17 -0700656 }
Kalhee Kimba366062017-11-07 16:32:09 +0000657
658
659
660 public Optional<FpmRecord> getFpmRecord(IpPrefix prefix) {
661 return dhcpFpmPrefixStore.getFpmRecord(prefix);
662 }
663
664 public Collection<FpmRecord> getFpmRecords() {
665 return dhcpFpmPrefixStore.getFpmRecords();
666 }
667
668 @Override
669 public void addFpmRecord(IpPrefix prefix, FpmRecord fpmRecord) {
670 dhcpFpmPrefixStore.addFpmRecord(prefix, fpmRecord);
671 }
672
673 @Override
674 public Optional<FpmRecord> removeFpmRecord(IpPrefix prefix) {
675 return dhcpFpmPrefixStore.removeFpmRecord(prefix);
676 }
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000677
678
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700679}