blob: 08ba908016fde4472a8571aff263aad0df85310c [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;
Ruchi Sahota38b22912019-03-01 16:56:07 +000030import com.google.common.collect.ImmutableSet;
Yi Tseng525ff402017-10-23 19:39:39 -070031import com.google.common.collect.Streams;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070032import org.apache.felix.scr.annotations.Activate;
33import org.apache.felix.scr.annotations.Component;
34import org.apache.felix.scr.annotations.Deactivate;
35import org.apache.felix.scr.annotations.Modified;
36import org.apache.felix.scr.annotations.Property;
37import org.apache.felix.scr.annotations.Reference;
38import org.apache.felix.scr.annotations.ReferenceCardinality;
39import org.apache.felix.scr.annotations.Service;
40import org.onlab.packet.ARP;
41import org.onlab.packet.DHCP;
42import org.onlab.packet.DHCP6;
43import org.onlab.packet.IPacket;
44import org.onlab.packet.IPv6;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070045import org.onlab.packet.Ethernet;
46import org.onlab.packet.IPv4;
Yi Tseng4f2a0462017-08-31 11:21:00 -070047import org.onlab.packet.Ip4Address;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070048import org.onlab.packet.MacAddress;
Kalhee Kimba366062017-11-07 16:32:09 +000049import org.onlab.packet.IpPrefix;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070050import org.onlab.packet.UDP;
51import org.onlab.packet.VlanId;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070052import org.onlab.util.Tools;
53import org.onosproject.cfg.ComponentConfigService;
54import org.onosproject.core.ApplicationId;
55import org.onosproject.core.CoreService;
Yi Tseng51301292017-07-28 13:02:59 -070056import org.onosproject.dhcprelay.api.DhcpHandler;
57import org.onosproject.dhcprelay.api.DhcpRelayService;
Yi Tseng919b2df2017-09-07 16:22:51 -070058import org.onosproject.dhcprelay.api.DhcpServerInfo;
Yi Tseng483ac6f2017-08-02 15:03:31 -070059import org.onosproject.dhcprelay.config.DefaultDhcpRelayConfig;
Taras Lemkin96a0d342018-03-26 14:52:58 +000060import org.onosproject.dhcprelay.config.DhcpServerConfig;
Kalhee Kimba366062017-11-07 16:32:09 +000061import org.onosproject.dhcprelay.config.EnableDhcpFpmConfig;
Taras Lemkin96a0d342018-03-26 14:52:58 +000062import org.onosproject.dhcprelay.config.IndirectDhcpRelayConfig;
63import org.onosproject.dhcprelay.config.IgnoreDhcpConfig;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070064import org.onosproject.dhcprelay.store.DhcpRecord;
65import org.onosproject.dhcprelay.store.DhcpRelayStore;
Kalhee Kimba366062017-11-07 16:32:09 +000066import org.onosproject.dhcprelay.store.DhcpFpmPrefixStore;
67import org.onosproject.routing.fpm.api.FpmRecord;
Yi Tseng127ffe52017-09-12 15:55:17 -070068import org.onosproject.net.Device;
Yi Tseng4f2a0462017-08-31 11:21:00 -070069import org.onosproject.net.Host;
Yi Tseng483ac6f2017-08-02 15:03:31 -070070import org.onosproject.net.config.Config;
Yi Tseng127ffe52017-09-12 15:55:17 -070071import org.onosproject.net.device.DeviceEvent;
72import org.onosproject.net.device.DeviceListener;
73import org.onosproject.net.device.DeviceService;
Ray Milkeyfacf2862017-08-03 11:58:29 -070074import org.onosproject.net.intf.Interface;
75import org.onosproject.net.intf.InterfaceService;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070076import org.onosproject.net.ConnectPoint;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070077import org.onosproject.net.HostId;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070078import org.onosproject.net.config.ConfigFactory;
79import org.onosproject.net.config.NetworkConfigEvent;
80import org.onosproject.net.config.NetworkConfigListener;
81import org.onosproject.net.config.NetworkConfigRegistry;
82import org.onosproject.net.flow.DefaultTrafficSelector;
83import org.onosproject.net.flow.DefaultTrafficTreatment;
84import org.onosproject.net.flow.TrafficSelector;
85import org.onosproject.net.flow.TrafficTreatment;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070086import org.onosproject.net.host.HostService;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070087import org.onosproject.net.packet.DefaultOutboundPacket;
88import org.onosproject.net.packet.OutboundPacket;
89import org.onosproject.net.packet.PacketContext;
90import org.onosproject.net.packet.PacketPriority;
91import org.onosproject.net.packet.PacketProcessor;
92import org.onosproject.net.packet.PacketService;
Kalhee Kimba366062017-11-07 16:32:09 +000093
Yi Tseng7a38f9a2017-06-09 14:36:40 -070094import org.osgi.service.component.ComponentContext;
95import org.slf4j.Logger;
96import org.slf4j.LoggerFactory;
Kalhee Kimd94ceea2017-11-29 19:03:02 +000097import java.util.concurrent.Executors;
Ruchi Sahota38b22912019-03-01 16:56:07 +000098import java.util.concurrent.ExecutorService;
Kalhee Kimd94ceea2017-11-29 19:03:02 +000099import java.util.concurrent.ScheduledExecutorService;
100import java.util.concurrent.TimeUnit;
101import static org.onlab.util.Tools.groupedThreads;
Ruchi Sahota38b22912019-03-01 16:56:07 +0000102import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700103import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
Yi Tseng127ffe52017-09-12 15:55:17 -0700104
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700105/**
106 * DHCP Relay Agent Application Component.
107 */
108@Component(immediate = true)
109@Service
110public class DhcpRelayManager implements DhcpRelayService {
Yi Tseng483ac6f2017-08-02 15:03:31 -0700111 public static final String DHCP_RELAY_APP = "org.onosproject.dhcprelay";
Charles Chan8d4ddc42019-01-23 15:03:17 -0800112 public static final String ROUTE_STORE_IMPL = "org.onosproject.routeservice.store.RouteStoreImpl";
113
114 private static final int DEFAULT_POOL_SIZE = 32;
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;
Ruchi Sahota38b22912019-03-01 16:56:07 +0000210 protected ExecutorService devEventExecutor;
Charles Chan8d4ddc42019-01-23 15:03:17 -0800211 private ExecutorService packetExecutor;
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000212
Yi Tseng127ffe52017-09-12 15:55:17 -0700213 protected DeviceListener deviceListener = new InternalDeviceListener();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700214 private DhcpRelayPacketProcessor dhcpRelayPacketProcessor = new DhcpRelayPacketProcessor();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700215 private ApplicationId appId;
216
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000217 /**
218 * One second timer.
219 */
220 class Dhcp6Timer implements Runnable {
221 @Override
222 public void run() {
223 v6Handler.timeTick();
224 }
225 };
Kalhee Kimba366062017-11-07 16:32:09 +0000226
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700227 @Activate
228 protected void activate(ComponentContext context) {
229 //start the dhcp relay agent
230 appId = coreService.registerApplication(DHCP_RELAY_APP);
231
232 cfgService.addListener(cfgListener);
233 factories.forEach(cfgService::registerConfigFactory);
234 //update the dhcp server configuration.
235 updateConfig();
Yi Tseng51301292017-07-28 13:02:59 -0700236
237 //add the packet processor
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700238 packetService.addProcessor(dhcpRelayPacketProcessor, PacketProcessor.director(0));
Yi Tseng51301292017-07-28 13:02:59 -0700239
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000240 timerExecutor = Executors.newScheduledThreadPool(1,
Charles Chan8d4ddc42019-01-23 15:03:17 -0800241 groupedThreads("onos/dhcprelay", "config-reloader-%d", log));
242 timerExecutor.scheduleAtFixedRate(new Dhcp6Timer(), 0, dhcpPollInterval, TimeUnit.SECONDS);
243 packetExecutor = Executors.newFixedThreadPool(DEFAULT_POOL_SIZE,
244 groupedThreads("onos/dhcprelay", "packet-%d", log));
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000245
Ruchi Sahota38b22912019-03-01 16:56:07 +0000246 devEventExecutor = newSingleThreadScheduledExecutor(
247 groupedThreads("onos/dhcprelay-dev-events", "events-%d", log));
248
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700249 modified(context);
250
Yi Tseng06799d62017-09-01 16:02:56 -0700251 // Enable distribute route store
252 compCfgService.preSetProperty(ROUTE_STORE_IMPL,
Kalhee Kimba366062017-11-07 16:32:09 +0000253 "distributed", Boolean.TRUE.toString());
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700254 compCfgService.registerProperties(getClass());
Yi Tseng127ffe52017-09-12 15:55:17 -0700255
256 deviceService.addListener(deviceListener);
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000257
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();
Ruchi Sahota38b22912019-03-01 16:56:07 +0000270 devEventExecutor.shutdownNow();
271 devEventExecutor = null;
Charles Chan8d4ddc42019-01-23 15:03:17 -0800272 packetExecutor.shutdown();
273 timerExecutor = null;
274 packetExecutor = null;
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000275
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700276 log.info("DHCP-RELAY Stopped");
277 }
278
279 @Modified
280 protected void modified(ComponentContext context) {
281 Dictionary<?, ?> properties = context.getProperties();
282 Boolean flag;
283
284 flag = Tools.isPropertyEnabled(properties, "arpEnabled");
285 if (flag != null) {
286 arpEnabled = flag;
287 log.info("Address resolution protocol is {}",
Kalhee Kimba366062017-11-07 16:32:09 +0000288 arpEnabled ? "enabled" : "disabled");
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700289 }
290
291 if (arpEnabled) {
292 requestArpPackets();
293 } else {
294 cancelArpPackets();
295 }
Kalhee Kimba366062017-11-07 16:32:09 +0000296
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000297 int intervalVal = Tools.getIntegerProperty(properties, "dhcpPollInterval");
298 log.info("DhcpRelay poll interval new {} old {}", intervalVal, dhcpPollInterval);
299 if (intervalVal != dhcpPollInterval) {
300 timerExecutor.shutdown();
301 dhcpPollInterval = intervalVal;
302 timerExecutor = Executors.newScheduledThreadPool(1,
303 groupedThreads("dhcpRelay",
304 "config-reloader-%d", log));
305 timerExecutor.scheduleAtFixedRate(new Dhcp6Timer(),
306 0,
307 dhcpPollInterval > 1 ? dhcpPollInterval : 1,
308 TimeUnit.SECONDS);
309 v6Handler.setDhcp6PollInterval(dhcpPollInterval);
310 }
311
Kalhee Kimba366062017-11-07 16:32:09 +0000312 flag = Tools.isPropertyEnabled(properties, "dhcpFpmEnabled");
313 if (flag != null) {
314 boolean oldValue = dhcpFpmEnabled;
315 dhcpFpmEnabled = flag;
316 log.info("DhcpRelay FPM is {}",
317 dhcpFpmEnabled ? "enabled" : "disabled");
318
319 if (dhcpFpmEnabled && !oldValue) {
320 log.info("Dhcp Fpm is enabled.");
321 processDhcpFpmRoutes(true);
322 }
323 if (!dhcpFpmEnabled && oldValue) {
324 log.info("Dhcp Fpm is disabled.");
325 processDhcpFpmRoutes(false);
326 }
327 v6Handler.setDhcpFpmEnabled(dhcpFpmEnabled);
328 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700329 }
330
Yi Tseng525ff402017-10-23 19:39:39 -0700331 private static List<TrafficSelector> buildClientDhcpSelectors() {
332 return Streams.concat(Dhcp4HandlerImpl.DHCP_SELECTORS.stream(),
333 Dhcp6HandlerImpl.DHCP_SELECTORS.stream())
334 .collect(Collectors.toList());
335 }
336
Yi Tseng483ac6f2017-08-02 15:03:31 -0700337 /**
338 * Updates DHCP relay app configuration.
339 */
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700340 private void updateConfig() {
Yi Tseng483ac6f2017-08-02 15:03:31 -0700341 DefaultDhcpRelayConfig defaultConfig =
342 cfgService.getConfig(appId, DefaultDhcpRelayConfig.class);
343 IndirectDhcpRelayConfig indirectConfig =
344 cfgService.getConfig(appId, IndirectDhcpRelayConfig.class);
Yi Tseng51f1be92017-09-01 17:24:57 -0700345 IgnoreDhcpConfig ignoreDhcpConfig =
346 cfgService.getConfig(appId, IgnoreDhcpConfig.class);
Yi Tseng483ac6f2017-08-02 15:03:31 -0700347
348 if (defaultConfig != null) {
349 updateConfig(defaultConfig);
350 }
Yi Tseng483ac6f2017-08-02 15:03:31 -0700351 if (indirectConfig != null) {
352 updateConfig(indirectConfig);
353 }
Yi Tseng51f1be92017-09-01 17:24:57 -0700354 if (ignoreDhcpConfig != null) {
355 updateConfig(ignoreDhcpConfig);
356 }
Yi Tseng483ac6f2017-08-02 15:03:31 -0700357 }
358
359 /**
360 * Updates DHCP relay app configuration with given configuration.
361 *
362 * @param config the configuration ot update
363 */
Yi Tseng51f1be92017-09-01 17:24:57 -0700364 protected void updateConfig(Config config) {
Yi Tseng483ac6f2017-08-02 15:03:31 -0700365 if (config instanceof IndirectDhcpRelayConfig) {
366 IndirectDhcpRelayConfig indirectConfig = (IndirectDhcpRelayConfig) config;
367 v4Handler.setIndirectDhcpServerConfigs(indirectConfig.dhcpServerConfigs());
368 v6Handler.setIndirectDhcpServerConfigs(indirectConfig.dhcpServerConfigs());
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700369 } else if (config instanceof DefaultDhcpRelayConfig) {
370 DefaultDhcpRelayConfig defaultConfig = (DefaultDhcpRelayConfig) config;
371 v4Handler.setDefaultDhcpServerConfigs(defaultConfig.dhcpServerConfigs());
372 v6Handler.setDefaultDhcpServerConfigs(defaultConfig.dhcpServerConfigs());
Yi Tseng483ac6f2017-08-02 15:03:31 -0700373 }
Yi Tseng51f1be92017-09-01 17:24:57 -0700374 if (config instanceof IgnoreDhcpConfig) {
Yi Tseng525ff402017-10-23 19:39:39 -0700375 v4Handler.updateIgnoreVlanConfig((IgnoreDhcpConfig) config);
376 v6Handler.updateIgnoreVlanConfig((IgnoreDhcpConfig) config);
Yi Tseng51f1be92017-09-01 17:24:57 -0700377 }
378 }
379
380 protected void removeConfig(Config config) {
381 if (config instanceof IndirectDhcpRelayConfig) {
382 v4Handler.setIndirectDhcpServerConfigs(Collections.emptyList());
383 v6Handler.setIndirectDhcpServerConfigs(Collections.emptyList());
384 } else if (config instanceof DefaultDhcpRelayConfig) {
385 v4Handler.setDefaultDhcpServerConfigs(Collections.emptyList());
386 v6Handler.setDefaultDhcpServerConfigs(Collections.emptyList());
387 }
388 if (config instanceof IgnoreDhcpConfig) {
Yi Tseng525ff402017-10-23 19:39:39 -0700389 v4Handler.updateIgnoreVlanConfig(null);
390 v6Handler.updateIgnoreVlanConfig(null);
Yi Tseng51f1be92017-09-01 17:24:57 -0700391 }
392 }
393
Kalhee Kimba366062017-11-07 16:32:09 +0000394 private void processDhcpFpmRoutes(Boolean add) {
395 // needs to restore/remove fpm
396 }
397
398 public boolean isDhcpFpmEnabled() {
399 return dhcpFpmEnabled;
400 }
401
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700402 /**
403 * Request ARP packet in via PacketService.
404 */
405 private void requestArpPackets() {
Yi Tseng51f1be92017-09-01 17:24:57 -0700406 packetService.requestPackets(ARP_SELECTOR, PacketPriority.CONTROL, appId);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700407 }
408
409 /**
410 * Cancel requested ARP packets in via packet service.
411 */
412 private void cancelArpPackets() {
Yi Tseng51f1be92017-09-01 17:24:57 -0700413 packetService.cancelPackets(ARP_SELECTOR, PacketPriority.CONTROL, appId);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700414 }
415
416 @Override
417 public Optional<DhcpRecord> getDhcpRecord(HostId hostId) {
418 return dhcpRelayStore.getDhcpRecord(hostId);
419 }
420
421 @Override
422 public Collection<DhcpRecord> getDhcpRecords() {
423 return dhcpRelayStore.getDhcpRecords();
424 }
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000425 @Override
426 public void updateDhcpRecord(HostId hostId, DhcpRecord dhcpRecord) {
427 dhcpRelayStore.updateDhcpRecord(hostId, dhcpRecord);
428 }
Yi Tseng13a41a12017-07-26 13:45:01 -0700429 @Override
430 public Optional<MacAddress> getDhcpServerMacAddress() {
Yi Tseng4f2a0462017-08-31 11:21:00 -0700431 // TODO: depreated it
432 DefaultDhcpRelayConfig config = cfgService.getConfig(appId, DefaultDhcpRelayConfig.class);
433 DhcpServerConfig serverConfig = config.dhcpServerConfigs().get(0);
434 Ip4Address serverip = serverConfig.getDhcpServerIp4().get();
435 return hostService.getHostsByIp(serverip)
436 .stream()
437 .map(Host::mac)
438 .findFirst();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700439 }
440
Yi Tseng919b2df2017-09-07 16:22:51 -0700441 @Override
442 public List<DhcpServerInfo> getDefaultDhcpServerInfoList() {
443 return ImmutableList.<DhcpServerInfo>builder()
444 .addAll(v4Handler.getDefaultDhcpServerInfoList())
445 .addAll(v6Handler.getDefaultDhcpServerInfoList())
446 .build();
447 }
448
449 @Override
450 public List<DhcpServerInfo> getIndirectDhcpServerInfoList() {
451 return ImmutableList.<DhcpServerInfo>builder()
452 .addAll(v4Handler.getIndirectDhcpServerInfoList())
453 .addAll(v6Handler.getIndirectDhcpServerInfoList())
454 .build();
455 }
456
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700457 /**
458 * Gets DHCP data from a packet.
459 *
460 * @param packet the packet
461 * @return the DHCP data; empty if it is not a DHCP packet
462 */
463 private Optional<DHCP> findDhcp(Ethernet packet) {
464 return Stream.of(packet)
465 .filter(Objects::nonNull)
466 .map(Ethernet::getPayload)
467 .filter(p -> p instanceof IPv4)
468 .map(IPacket::getPayload)
469 .filter(Objects::nonNull)
470 .filter(p -> p instanceof UDP)
471 .map(IPacket::getPayload)
472 .filter(Objects::nonNull)
473 .filter(p -> p instanceof DHCP)
474 .map(p -> (DHCP) p)
475 .findFirst();
476 }
477
478 /**
479 * Gets DHCPv6 data from a packet.
480 *
481 * @param packet the packet
482 * @return the DHCPv6 data; empty if it is not a DHCPv6 packet
483 */
484 private Optional<DHCP6> findDhcp6(Ethernet packet) {
485 return Stream.of(packet)
486 .filter(Objects::nonNull)
487 .map(Ethernet::getPayload)
488 .filter(p -> p instanceof IPv6)
489 .map(IPacket::getPayload)
490 .filter(Objects::nonNull)
491 .filter(p -> p instanceof UDP)
492 .map(IPacket::getPayload)
493 .filter(Objects::nonNull)
494 .filter(p -> p instanceof DHCP6)
495 .map(p -> (DHCP6) p)
496 .findFirst();
497 }
498
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700499
500 private class DhcpRelayPacketProcessor implements PacketProcessor {
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700501 @Override
502 public void process(PacketContext context) {
Charles Chan8d4ddc42019-01-23 15:03:17 -0800503 packetExecutor.execute(() -> processInternal(context));
504 }
505
506 private void processInternal(PacketContext context) {
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700507 // process the packet and get the payload
508 Ethernet packet = context.inPacket().parsed();
509 if (packet == null) {
510 return;
511 }
512
513 findDhcp(packet).ifPresent(dhcpPayload -> {
Yi Tseng51301292017-07-28 13:02:59 -0700514 v4Handler.processDhcpPacket(context, dhcpPayload);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700515 });
516
517 findDhcp6(packet).ifPresent(dhcp6Payload -> {
Yi Tseng51301292017-07-28 13:02:59 -0700518 v6Handler.processDhcpPacket(context, dhcp6Payload);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700519 });
520
521 if (packet.getEtherType() == Ethernet.TYPE_ARP && arpEnabled) {
522 ARP arpPacket = (ARP) packet.getPayload();
523 VlanId vlanId = VlanId.vlanId(packet.getVlanID());
524 Set<Interface> interfaces = interfaceService.
525 getInterfacesByPort(context.inPacket().receivedFrom());
526 //ignore the packets if dhcp server interface is not configured on onos.
527 if (interfaces.isEmpty()) {
528 log.warn("server virtual interface not configured");
529 return;
530 }
531 if ((arpPacket.getOpCode() != ARP.OP_REQUEST)) {
532 // handle request only
533 return;
534 }
535 MacAddress interfaceMac = interfaces.stream()
536 .filter(iface -> iface.vlan().equals(vlanId))
537 .map(Interface::mac)
538 .filter(mac -> !mac.equals(MacAddress.NONE))
539 .findFirst()
Yi Tseng51301292017-07-28 13:02:59 -0700540 .orElse(MacAddress.ONOS);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700541 if (interfaceMac == null) {
542 // can't find interface mac address
543 return;
544 }
545 processArpPacket(context, packet, interfaceMac);
546 }
547 }
548
549 /**
550 * Processes the ARP Payload and initiates a reply to the client.
551 *
552 * @param context the packet context
553 * @param packet the ethernet payload
554 * @param replyMac mac address to be replied
555 */
556 private void processArpPacket(PacketContext context, Ethernet packet, MacAddress replyMac) {
557 ARP arpPacket = (ARP) packet.getPayload();
Ray Milkeyf0c47612017-09-28 11:29:38 -0700558 ARP arpReply = arpPacket.duplicate();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700559 arpReply.setOpCode(ARP.OP_REPLY);
560
561 arpReply.setTargetProtocolAddress(arpPacket.getSenderProtocolAddress());
562 arpReply.setTargetHardwareAddress(arpPacket.getSenderHardwareAddress());
563 arpReply.setSenderProtocolAddress(arpPacket.getTargetProtocolAddress());
564 arpReply.setSenderHardwareAddress(replyMac.toBytes());
565
566 // Ethernet Frame.
567 Ethernet ethReply = new Ethernet();
568 ethReply.setSourceMACAddress(replyMac.toBytes());
569 ethReply.setDestinationMACAddress(packet.getSourceMAC());
570 ethReply.setEtherType(Ethernet.TYPE_ARP);
571 ethReply.setVlanID(packet.getVlanID());
572 ethReply.setPayload(arpReply);
573
574 ConnectPoint targetPort = context.inPacket().receivedFrom();
575 TrafficTreatment t = DefaultTrafficTreatment.builder()
576 .setOutput(targetPort.port()).build();
577 OutboundPacket o = new DefaultOutboundPacket(
578 targetPort.deviceId(), t, ByteBuffer.wrap(ethReply.serialize()));
579 if (log.isTraceEnabled()) {
580 log.trace("Relaying ARP packet {} to {}", packet, targetPort);
581 }
582 packetService.emit(o);
583 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700584 }
585
586 /**
587 * Listener for network config events.
588 */
589 private class InternalConfigListener implements NetworkConfigListener {
590 @Override
591 public void event(NetworkConfigEvent event) {
Yi Tseng51f1be92017-09-01 17:24:57 -0700592 switch (event.type()) {
593 case CONFIG_UPDATED:
594 case CONFIG_ADDED:
595 event.config().ifPresent(config -> {
596 updateConfig(config);
597 log.info("{} updated", config.getClass().getSimpleName());
598 });
599 break;
600 case CONFIG_REMOVED:
601 event.prevConfig().ifPresent(config -> {
602 removeConfig(config);
603 log.info("{} removed", config.getClass().getSimpleName());
604 });
605 break;
Charles Chan10b2fee2018-04-21 00:44:29 -0700606 case CONFIG_REGISTERED:
607 case CONFIG_UNREGISTERED:
608 break;
Yi Tseng51f1be92017-09-01 17:24:57 -0700609 default:
610 log.warn("Unsupported event type {}", event.type());
611 break;
Yi Tseng483ac6f2017-08-02 15:03:31 -0700612 }
Charles Chan50443e82018-01-03 16:26:32 -0800613 }
Yi Tseng51f1be92017-09-01 17:24:57 -0700614
Charles Chan50443e82018-01-03 16:26:32 -0800615 @Override
616 public boolean isRelevant(NetworkConfigEvent event) {
617 if (event.configClass().equals(DefaultDhcpRelayConfig.class) ||
618 event.configClass().equals(IndirectDhcpRelayConfig.class) ||
619 event.configClass().equals(IgnoreDhcpConfig.class)) {
620 return true;
621 }
622 log.debug("Ignore irrelevant event class {}", event.configClass().getName());
623 return false;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700624 }
625 }
Yi Tseng127ffe52017-09-12 15:55:17 -0700626
627 private class InternalDeviceListener implements DeviceListener {
628
629 @Override
630 public void event(DeviceEvent event) {
Ruchi Sahota38b22912019-03-01 16:56:07 +0000631 if (devEventExecutor != null) {
Yi Tseng127ffe52017-09-12 15:55:17 -0700632 Device device = event.subject();
633 switch (event.type()) {
634 case DEVICE_ADDED:
Ruchi Sahota38b22912019-03-01 16:56:07 +0000635 devEventExecutor.execute(this::updateIgnoreVlanConfigs);
Yi Tseng127ffe52017-09-12 15:55:17 -0700636 break;
637 case DEVICE_AVAILABILITY_CHANGED:
Ruchi Sahota38b22912019-03-01 16:56:07 +0000638 devEventExecutor.execute(() -> deviceAvailabilityChanged(device));
Ray Milkeyd6a67c32018-02-02 10:30:35 -0800639 break;
Yi Tseng127ffe52017-09-12 15:55:17 -0700640 default:
641 break;
642 }
Ruchi Sahota38b22912019-03-01 16:56:07 +0000643 }
Yi Tseng127ffe52017-09-12 15:55:17 -0700644 }
645
646 private void deviceAvailabilityChanged(Device device) {
647 if (deviceService.isAvailable(device.id())) {
Yi Tseng525ff402017-10-23 19:39:39 -0700648 updateIgnoreVlanConfigs();
Saurav Dasb805f1a2017-12-13 16:19:35 -0800649 } else {
650 removeIgnoreVlanState();
Yi Tseng127ffe52017-09-12 15:55:17 -0700651 }
652 }
653
Yi Tseng525ff402017-10-23 19:39:39 -0700654 private void updateIgnoreVlanConfigs() {
Yi Tseng127ffe52017-09-12 15:55:17 -0700655 IgnoreDhcpConfig config = cfgService.getConfig(appId, IgnoreDhcpConfig.class);
Yi Tseng525ff402017-10-23 19:39:39 -0700656 v4Handler.updateIgnoreVlanConfig(config);
657 v6Handler.updateIgnoreVlanConfig(config);
Yi Tseng127ffe52017-09-12 15:55:17 -0700658 }
Saurav Dasb805f1a2017-12-13 16:19:35 -0800659
660 private void removeIgnoreVlanState() {
661 IgnoreDhcpConfig config = cfgService.getConfig(appId, IgnoreDhcpConfig.class);
662 v4Handler.removeIgnoreVlanState(config);
663 v6Handler.removeIgnoreVlanState(config);
664 }
Yi Tseng127ffe52017-09-12 15:55:17 -0700665 }
Kalhee Kimba366062017-11-07 16:32:09 +0000666
667
668
669 public Optional<FpmRecord> getFpmRecord(IpPrefix prefix) {
670 return dhcpFpmPrefixStore.getFpmRecord(prefix);
671 }
672
673 public Collection<FpmRecord> getFpmRecords() {
674 return dhcpFpmPrefixStore.getFpmRecords();
675 }
676
677 @Override
678 public void addFpmRecord(IpPrefix prefix, FpmRecord fpmRecord) {
679 dhcpFpmPrefixStore.addFpmRecord(prefix, fpmRecord);
680 }
681
682 @Override
683 public Optional<FpmRecord> removeFpmRecord(IpPrefix prefix) {
684 return dhcpFpmPrefixStore.removeFpmRecord(prefix);
685 }
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000686
687
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700688}