blob: 3bb7f4e2044749d3bd8dfec57e92e107a6e616b6 [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
Yi Tseng51f1be92017-09-01 17:24:57 -070018import com.google.common.collect.ImmutableList;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070019import com.google.common.collect.ImmutableSet;
Yi Tseng525ff402017-10-23 19:39:39 -070020import com.google.common.collect.Streams;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070021import org.onlab.packet.ARP;
22import org.onlab.packet.DHCP;
23import org.onlab.packet.DHCP6;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070024import org.onlab.packet.Ethernet;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070025import org.onlab.packet.IPacket;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070026import org.onlab.packet.IPv4;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070027import org.onlab.packet.IPv6;
Yi Tseng4f2a0462017-08-31 11:21:00 -070028import org.onlab.packet.Ip4Address;
Kalhee Kimba366062017-11-07 16:32:09 +000029import org.onlab.packet.IpPrefix;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070030import org.onlab.packet.MacAddress;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070031import org.onlab.packet.UDP;
32import org.onlab.packet.VlanId;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070033import org.onlab.util.Tools;
34import org.onosproject.cfg.ComponentConfigService;
35import org.onosproject.core.ApplicationId;
36import org.onosproject.core.CoreService;
Yi Tseng51301292017-07-28 13:02:59 -070037import org.onosproject.dhcprelay.api.DhcpHandler;
38import org.onosproject.dhcprelay.api.DhcpRelayService;
Yi Tseng919b2df2017-09-07 16:22:51 -070039import org.onosproject.dhcprelay.api.DhcpServerInfo;
Yi Tseng483ac6f2017-08-02 15:03:31 -070040import org.onosproject.dhcprelay.config.DefaultDhcpRelayConfig;
Taras Lemkin96a0d342018-03-26 14:52:58 +000041import org.onosproject.dhcprelay.config.DhcpServerConfig;
Kalhee Kimba366062017-11-07 16:32:09 +000042import org.onosproject.dhcprelay.config.EnableDhcpFpmConfig;
Taras Lemkin96a0d342018-03-26 14:52:58 +000043import org.onosproject.dhcprelay.config.IgnoreDhcpConfig;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070044import org.onosproject.dhcprelay.config.IndirectDhcpRelayConfig;
45import org.onosproject.dhcprelay.store.DhcpFpmPrefixStore;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070046import org.onosproject.dhcprelay.store.DhcpRecord;
47import org.onosproject.dhcprelay.store.DhcpRelayStore;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070048import org.onosproject.net.ConnectPoint;
Yi Tseng127ffe52017-09-12 15:55:17 -070049import org.onosproject.net.Device;
Yi Tseng4f2a0462017-08-31 11:21:00 -070050import org.onosproject.net.Host;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070051import org.onosproject.net.HostId;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070052import org.onosproject.net.config.Config;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070053import org.onosproject.net.config.ConfigFactory;
54import org.onosproject.net.config.NetworkConfigEvent;
55import org.onosproject.net.config.NetworkConfigListener;
56import org.onosproject.net.config.NetworkConfigRegistry;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070057import org.onosproject.net.device.DeviceEvent;
58import org.onosproject.net.device.DeviceListener;
59import org.onosproject.net.device.DeviceService;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070060import org.onosproject.net.flow.DefaultTrafficSelector;
61import org.onosproject.net.flow.DefaultTrafficTreatment;
62import org.onosproject.net.flow.TrafficSelector;
63import org.onosproject.net.flow.TrafficTreatment;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070064import org.onosproject.net.host.HostService;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070065import org.onosproject.net.intf.Interface;
66import org.onosproject.net.intf.InterfaceService;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070067import org.onosproject.net.packet.DefaultOutboundPacket;
68import org.onosproject.net.packet.OutboundPacket;
69import org.onosproject.net.packet.PacketContext;
70import org.onosproject.net.packet.PacketPriority;
71import org.onosproject.net.packet.PacketProcessor;
72import org.onosproject.net.packet.PacketService;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070073import org.onosproject.routing.fpm.api.FpmRecord;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070074import org.osgi.service.component.ComponentContext;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070075import org.osgi.service.component.annotations.Activate;
76import org.osgi.service.component.annotations.Component;
77import org.osgi.service.component.annotations.Deactivate;
78import org.osgi.service.component.annotations.Modified;
79import org.osgi.service.component.annotations.Reference;
80import org.osgi.service.component.annotations.ReferenceCardinality;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070081import org.slf4j.Logger;
82import org.slf4j.LoggerFactory;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070083
84import java.nio.ByteBuffer;
85import java.util.Collection;
86import java.util.Collections;
87import java.util.Dictionary;
88import java.util.List;
89import java.util.Objects;
90import java.util.Optional;
91import java.util.Set;
Kalhee Kimd94ceea2017-11-29 19:03:02 +000092import java.util.concurrent.Executors;
93import java.util.concurrent.ScheduledExecutorService;
94import java.util.concurrent.TimeUnit;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070095import java.util.stream.Collectors;
96import java.util.stream.Stream;
97
Kalhee Kimd94ceea2017-11-29 19:03:02 +000098import static org.onlab.util.Tools.groupedThreads;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070099import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
Yi Tseng127ffe52017-09-12 15:55:17 -0700100
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700101/**
102 * DHCP Relay Agent Application Component.
103 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700104@Component(immediate = true, service = DhcpRelayService.class)
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700105public class DhcpRelayManager implements DhcpRelayService {
Yi Tseng483ac6f2017-08-02 15:03:31 -0700106 public static final String DHCP_RELAY_APP = "org.onosproject.dhcprelay";
Yi Tseng06799d62017-09-01 16:02:56 -0700107 public static final String ROUTE_STORE_IMPL =
108 "org.onosproject.routeservice.store.RouteStoreImpl";
Yi Tseng525ff402017-10-23 19:39:39 -0700109
Yi Tseng51f1be92017-09-01 17:24:57 -0700110 private static final TrafficSelector ARP_SELECTOR = DefaultTrafficSelector.builder()
111 .matchEthType(Ethernet.TYPE_ARP)
112 .build();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700113 private final Logger log = LoggerFactory.getLogger(getClass());
114 private final InternalConfigListener cfgListener = new InternalConfigListener();
115
116 private final Set<ConfigFactory> factories = ImmutableSet.of(
Yi Tseng483ac6f2017-08-02 15:03:31 -0700117 new ConfigFactory<ApplicationId, DefaultDhcpRelayConfig>(APP_SUBJECT_FACTORY,
Kalhee Kimba366062017-11-07 16:32:09 +0000118 DefaultDhcpRelayConfig.class,
119 DefaultDhcpRelayConfig.KEY,
120 true) {
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700121 @Override
Yi Tseng483ac6f2017-08-02 15:03:31 -0700122 public DefaultDhcpRelayConfig createConfig() {
123 return new DefaultDhcpRelayConfig();
124 }
125 },
126 new ConfigFactory<ApplicationId, IndirectDhcpRelayConfig>(APP_SUBJECT_FACTORY,
Kalhee Kimba366062017-11-07 16:32:09 +0000127 IndirectDhcpRelayConfig.class,
128 IndirectDhcpRelayConfig.KEY,
129 true) {
Yi Tseng483ac6f2017-08-02 15:03:31 -0700130 @Override
131 public IndirectDhcpRelayConfig createConfig() {
132 return new IndirectDhcpRelayConfig();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700133 }
Yi Tseng51f1be92017-09-01 17:24:57 -0700134 },
135 new ConfigFactory<ApplicationId, IgnoreDhcpConfig>(APP_SUBJECT_FACTORY,
Kalhee Kimba366062017-11-07 16:32:09 +0000136 IgnoreDhcpConfig.class,
137 IgnoreDhcpConfig.KEY,
138 true) {
Yi Tseng51f1be92017-09-01 17:24:57 -0700139 @Override
140 public IgnoreDhcpConfig createConfig() {
141 return new IgnoreDhcpConfig();
142 }
Kalhee Kimba366062017-11-07 16:32:09 +0000143 },
144 new ConfigFactory<ApplicationId, EnableDhcpFpmConfig>(APP_SUBJECT_FACTORY,
145 EnableDhcpFpmConfig.class,
146 EnableDhcpFpmConfig.KEY,
147 false) {
148 @Override
149 public EnableDhcpFpmConfig createConfig() {
150 return new EnableDhcpFpmConfig();
151 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700152 }
153 );
154
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000155
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700156 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700157 protected NetworkConfigRegistry cfgService;
158
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700159 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700160 protected CoreService coreService;
161
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700162 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700163 protected PacketService packetService;
164
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700165 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700166 protected HostService hostService;
167
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700168 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700169 protected InterfaceService interfaceService;
170
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700171 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700172 protected DhcpRelayStore dhcpRelayStore;
173
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700174 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700175 protected ComponentConfigService compCfgService;
176
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700177 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tseng127ffe52017-09-12 15:55:17 -0700178 protected DeviceService deviceService;
179
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700180 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Kalhee Kimba366062017-11-07 16:32:09 +0000181 protected DhcpFpmPrefixStore dhcpFpmPrefixStore;
182
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700183 @Reference(cardinality = ReferenceCardinality.MANDATORY,
Yi Tseng127ffe52017-09-12 15:55:17 -0700184 target = "(version=4)")
Yi Tseng51301292017-07-28 13:02:59 -0700185 protected DhcpHandler v4Handler;
186
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700187 @Reference(cardinality = ReferenceCardinality.MANDATORY,
Yi Tseng127ffe52017-09-12 15:55:17 -0700188 target = "(version=6)")
Yi Tseng51301292017-07-28 13:02:59 -0700189 protected DhcpHandler v6Handler;
190
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700191 //@Property(name = "arpEnabled", boolValue = true,
192 // label = "Enable Address resolution protocol")
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700193 protected boolean arpEnabled = true;
194
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700195 //@Property(name = "dhcpPollInterval", intValue = 24 * 3600,
196 // label = "dhcp relay poll interval")
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000197 protected int dhcpPollInterval = 24 * 3600;
198
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700199 //@Property(name = "dhcpFpmEnabled", boolValue = false,
200 // label = "Enable DhcpRelay Fpm")
Kalhee Kimba366062017-11-07 16:32:09 +0000201 protected boolean dhcpFpmEnabled = false;
202
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000203 private ScheduledExecutorService timerExecutor;
204
Yi Tseng127ffe52017-09-12 15:55:17 -0700205 protected DeviceListener deviceListener = new InternalDeviceListener();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700206 private DhcpRelayPacketProcessor dhcpRelayPacketProcessor = new DhcpRelayPacketProcessor();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700207 private ApplicationId appId;
208
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000209 /**
210 * One second timer.
211 */
212 class Dhcp6Timer implements Runnable {
213 @Override
214 public void run() {
215 v6Handler.timeTick();
216 }
217 };
Kalhee Kimba366062017-11-07 16:32:09 +0000218
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700219 @Activate
220 protected void activate(ComponentContext context) {
221 //start the dhcp relay agent
222 appId = coreService.registerApplication(DHCP_RELAY_APP);
223
224 cfgService.addListener(cfgListener);
225 factories.forEach(cfgService::registerConfigFactory);
226 //update the dhcp server configuration.
227 updateConfig();
Yi Tseng51301292017-07-28 13:02:59 -0700228
229 //add the packet processor
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700230 packetService.addProcessor(dhcpRelayPacketProcessor, PacketProcessor.director(0));
Yi Tseng51301292017-07-28 13:02:59 -0700231
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000232 timerExecutor = Executors.newScheduledThreadPool(1,
233 groupedThreads("dhcpRelay",
234 "config-reloader-%d", log));
235 timerExecutor.scheduleAtFixedRate(new Dhcp6Timer(),
236 0,
237 dhcpPollInterval,
238 TimeUnit.SECONDS);
239
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700240 modified(context);
241
Yi Tseng06799d62017-09-01 16:02:56 -0700242 // Enable distribute route store
243 compCfgService.preSetProperty(ROUTE_STORE_IMPL,
Kalhee Kimba366062017-11-07 16:32:09 +0000244 "distributed", Boolean.TRUE.toString());
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700245 compCfgService.registerProperties(getClass());
Yi Tseng127ffe52017-09-12 15:55:17 -0700246
247 deviceService.addListener(deviceListener);
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000248
249
250
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700251 log.info("DHCP-RELAY Started");
252 }
253
254 @Deactivate
255 protected void deactivate() {
256 cfgService.removeListener(cfgListener);
257 factories.forEach(cfgService::unregisterConfigFactory);
258 packetService.removeProcessor(dhcpRelayPacketProcessor);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700259 cancelArpPackets();
Yi Tsengdfa8ee22017-08-07 12:45:01 -0700260 compCfgService.unregisterProperties(getClass(), false);
Yi Tseng127ffe52017-09-12 15:55:17 -0700261 deviceService.removeListener(deviceListener);
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000262 timerExecutor.shutdown();
263
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700264 log.info("DHCP-RELAY Stopped");
265 }
266
267 @Modified
268 protected void modified(ComponentContext context) {
269 Dictionary<?, ?> properties = context.getProperties();
270 Boolean flag;
271
272 flag = Tools.isPropertyEnabled(properties, "arpEnabled");
273 if (flag != null) {
274 arpEnabled = flag;
275 log.info("Address resolution protocol is {}",
Kalhee Kimba366062017-11-07 16:32:09 +0000276 arpEnabled ? "enabled" : "disabled");
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700277 }
278
279 if (arpEnabled) {
280 requestArpPackets();
281 } else {
282 cancelArpPackets();
283 }
Kalhee Kimba366062017-11-07 16:32:09 +0000284
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000285 int intervalVal = Tools.getIntegerProperty(properties, "dhcpPollInterval");
286 log.info("DhcpRelay poll interval new {} old {}", intervalVal, dhcpPollInterval);
287 if (intervalVal != dhcpPollInterval) {
288 timerExecutor.shutdown();
289 dhcpPollInterval = intervalVal;
290 timerExecutor = Executors.newScheduledThreadPool(1,
291 groupedThreads("dhcpRelay",
292 "config-reloader-%d", log));
293 timerExecutor.scheduleAtFixedRate(new Dhcp6Timer(),
294 0,
295 dhcpPollInterval > 1 ? dhcpPollInterval : 1,
296 TimeUnit.SECONDS);
297 v6Handler.setDhcp6PollInterval(dhcpPollInterval);
298 }
299
Kalhee Kimba366062017-11-07 16:32:09 +0000300 flag = Tools.isPropertyEnabled(properties, "dhcpFpmEnabled");
301 if (flag != null) {
302 boolean oldValue = dhcpFpmEnabled;
303 dhcpFpmEnabled = flag;
304 log.info("DhcpRelay FPM is {}",
305 dhcpFpmEnabled ? "enabled" : "disabled");
306
307 if (dhcpFpmEnabled && !oldValue) {
308 log.info("Dhcp Fpm is enabled.");
309 processDhcpFpmRoutes(true);
310 }
311 if (!dhcpFpmEnabled && oldValue) {
312 log.info("Dhcp Fpm is disabled.");
313 processDhcpFpmRoutes(false);
314 }
315 v6Handler.setDhcpFpmEnabled(dhcpFpmEnabled);
316 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700317 }
318
Yi Tseng525ff402017-10-23 19:39:39 -0700319 private static List<TrafficSelector> buildClientDhcpSelectors() {
320 return Streams.concat(Dhcp4HandlerImpl.DHCP_SELECTORS.stream(),
321 Dhcp6HandlerImpl.DHCP_SELECTORS.stream())
322 .collect(Collectors.toList());
323 }
324
Yi Tseng483ac6f2017-08-02 15:03:31 -0700325 /**
326 * Updates DHCP relay app configuration.
327 */
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700328 private void updateConfig() {
Yi Tseng483ac6f2017-08-02 15:03:31 -0700329 DefaultDhcpRelayConfig defaultConfig =
330 cfgService.getConfig(appId, DefaultDhcpRelayConfig.class);
331 IndirectDhcpRelayConfig indirectConfig =
332 cfgService.getConfig(appId, IndirectDhcpRelayConfig.class);
Yi Tseng51f1be92017-09-01 17:24:57 -0700333 IgnoreDhcpConfig ignoreDhcpConfig =
334 cfgService.getConfig(appId, IgnoreDhcpConfig.class);
Yi Tseng483ac6f2017-08-02 15:03:31 -0700335
336 if (defaultConfig != null) {
337 updateConfig(defaultConfig);
338 }
Yi Tseng483ac6f2017-08-02 15:03:31 -0700339 if (indirectConfig != null) {
340 updateConfig(indirectConfig);
341 }
Yi Tseng51f1be92017-09-01 17:24:57 -0700342 if (ignoreDhcpConfig != null) {
343 updateConfig(ignoreDhcpConfig);
344 }
Yi Tseng483ac6f2017-08-02 15:03:31 -0700345 }
346
347 /**
348 * Updates DHCP relay app configuration with given configuration.
349 *
350 * @param config the configuration ot update
351 */
Yi Tseng51f1be92017-09-01 17:24:57 -0700352 protected void updateConfig(Config config) {
Yi Tseng483ac6f2017-08-02 15:03:31 -0700353 if (config instanceof IndirectDhcpRelayConfig) {
354 IndirectDhcpRelayConfig indirectConfig = (IndirectDhcpRelayConfig) config;
355 v4Handler.setIndirectDhcpServerConfigs(indirectConfig.dhcpServerConfigs());
356 v6Handler.setIndirectDhcpServerConfigs(indirectConfig.dhcpServerConfigs());
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700357 } else if (config instanceof DefaultDhcpRelayConfig) {
358 DefaultDhcpRelayConfig defaultConfig = (DefaultDhcpRelayConfig) config;
359 v4Handler.setDefaultDhcpServerConfigs(defaultConfig.dhcpServerConfigs());
360 v6Handler.setDefaultDhcpServerConfigs(defaultConfig.dhcpServerConfigs());
Yi Tseng483ac6f2017-08-02 15:03:31 -0700361 }
Yi Tseng51f1be92017-09-01 17:24:57 -0700362 if (config instanceof IgnoreDhcpConfig) {
Yi Tseng525ff402017-10-23 19:39:39 -0700363 v4Handler.updateIgnoreVlanConfig((IgnoreDhcpConfig) config);
364 v6Handler.updateIgnoreVlanConfig((IgnoreDhcpConfig) config);
Yi Tseng51f1be92017-09-01 17:24:57 -0700365 }
366 }
367
368 protected void removeConfig(Config config) {
369 if (config instanceof IndirectDhcpRelayConfig) {
370 v4Handler.setIndirectDhcpServerConfigs(Collections.emptyList());
371 v6Handler.setIndirectDhcpServerConfigs(Collections.emptyList());
372 } else if (config instanceof DefaultDhcpRelayConfig) {
373 v4Handler.setDefaultDhcpServerConfigs(Collections.emptyList());
374 v6Handler.setDefaultDhcpServerConfigs(Collections.emptyList());
375 }
376 if (config instanceof IgnoreDhcpConfig) {
Yi Tseng525ff402017-10-23 19:39:39 -0700377 v4Handler.updateIgnoreVlanConfig(null);
378 v6Handler.updateIgnoreVlanConfig(null);
Yi Tseng51f1be92017-09-01 17:24:57 -0700379 }
380 }
381
Kalhee Kimba366062017-11-07 16:32:09 +0000382 private void processDhcpFpmRoutes(Boolean add) {
383 // needs to restore/remove fpm
384 }
385
386 public boolean isDhcpFpmEnabled() {
387 return dhcpFpmEnabled;
388 }
389
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700390 /**
391 * Request ARP packet in via PacketService.
392 */
393 private void requestArpPackets() {
Yi Tseng51f1be92017-09-01 17:24:57 -0700394 packetService.requestPackets(ARP_SELECTOR, PacketPriority.CONTROL, appId);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700395 }
396
397 /**
398 * Cancel requested ARP packets in via packet service.
399 */
400 private void cancelArpPackets() {
Yi Tseng51f1be92017-09-01 17:24:57 -0700401 packetService.cancelPackets(ARP_SELECTOR, PacketPriority.CONTROL, appId);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700402 }
403
404 @Override
405 public Optional<DhcpRecord> getDhcpRecord(HostId hostId) {
406 return dhcpRelayStore.getDhcpRecord(hostId);
407 }
408
409 @Override
410 public Collection<DhcpRecord> getDhcpRecords() {
411 return dhcpRelayStore.getDhcpRecords();
412 }
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000413 @Override
414 public void updateDhcpRecord(HostId hostId, DhcpRecord dhcpRecord) {
415 dhcpRelayStore.updateDhcpRecord(hostId, dhcpRecord);
416 }
Yi Tseng13a41a12017-07-26 13:45:01 -0700417 @Override
418 public Optional<MacAddress> getDhcpServerMacAddress() {
Yi Tseng4f2a0462017-08-31 11:21:00 -0700419 // TODO: depreated it
420 DefaultDhcpRelayConfig config = cfgService.getConfig(appId, DefaultDhcpRelayConfig.class);
421 DhcpServerConfig serverConfig = config.dhcpServerConfigs().get(0);
422 Ip4Address serverip = serverConfig.getDhcpServerIp4().get();
423 return hostService.getHostsByIp(serverip)
424 .stream()
425 .map(Host::mac)
426 .findFirst();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700427 }
428
Yi Tseng919b2df2017-09-07 16:22:51 -0700429 @Override
430 public List<DhcpServerInfo> getDefaultDhcpServerInfoList() {
431 return ImmutableList.<DhcpServerInfo>builder()
432 .addAll(v4Handler.getDefaultDhcpServerInfoList())
433 .addAll(v6Handler.getDefaultDhcpServerInfoList())
434 .build();
435 }
436
437 @Override
438 public List<DhcpServerInfo> getIndirectDhcpServerInfoList() {
439 return ImmutableList.<DhcpServerInfo>builder()
440 .addAll(v4Handler.getIndirectDhcpServerInfoList())
441 .addAll(v6Handler.getIndirectDhcpServerInfoList())
442 .build();
443 }
444
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700445 /**
446 * Gets DHCP data from a packet.
447 *
448 * @param packet the packet
449 * @return the DHCP data; empty if it is not a DHCP packet
450 */
451 private Optional<DHCP> findDhcp(Ethernet packet) {
452 return Stream.of(packet)
453 .filter(Objects::nonNull)
454 .map(Ethernet::getPayload)
455 .filter(p -> p instanceof IPv4)
456 .map(IPacket::getPayload)
457 .filter(Objects::nonNull)
458 .filter(p -> p instanceof UDP)
459 .map(IPacket::getPayload)
460 .filter(Objects::nonNull)
461 .filter(p -> p instanceof DHCP)
462 .map(p -> (DHCP) p)
463 .findFirst();
464 }
465
466 /**
467 * Gets DHCPv6 data from a packet.
468 *
469 * @param packet the packet
470 * @return the DHCPv6 data; empty if it is not a DHCPv6 packet
471 */
472 private Optional<DHCP6> findDhcp6(Ethernet packet) {
473 return Stream.of(packet)
474 .filter(Objects::nonNull)
475 .map(Ethernet::getPayload)
476 .filter(p -> p instanceof IPv6)
477 .map(IPacket::getPayload)
478 .filter(Objects::nonNull)
479 .filter(p -> p instanceof UDP)
480 .map(IPacket::getPayload)
481 .filter(Objects::nonNull)
482 .filter(p -> p instanceof DHCP6)
483 .map(p -> (DHCP6) p)
484 .findFirst();
485 }
486
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700487
488 private class DhcpRelayPacketProcessor implements PacketProcessor {
489
490 @Override
491 public void process(PacketContext context) {
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700492 // process the packet and get the payload
493 Ethernet packet = context.inPacket().parsed();
494 if (packet == null) {
495 return;
496 }
497
498 findDhcp(packet).ifPresent(dhcpPayload -> {
Yi Tseng51301292017-07-28 13:02:59 -0700499 v4Handler.processDhcpPacket(context, dhcpPayload);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700500 });
501
502 findDhcp6(packet).ifPresent(dhcp6Payload -> {
Yi Tseng51301292017-07-28 13:02:59 -0700503 v6Handler.processDhcpPacket(context, dhcp6Payload);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700504 });
505
506 if (packet.getEtherType() == Ethernet.TYPE_ARP && arpEnabled) {
507 ARP arpPacket = (ARP) packet.getPayload();
508 VlanId vlanId = VlanId.vlanId(packet.getVlanID());
509 Set<Interface> interfaces = interfaceService.
510 getInterfacesByPort(context.inPacket().receivedFrom());
511 //ignore the packets if dhcp server interface is not configured on onos.
512 if (interfaces.isEmpty()) {
513 log.warn("server virtual interface not configured");
514 return;
515 }
516 if ((arpPacket.getOpCode() != ARP.OP_REQUEST)) {
517 // handle request only
518 return;
519 }
520 MacAddress interfaceMac = interfaces.stream()
521 .filter(iface -> iface.vlan().equals(vlanId))
522 .map(Interface::mac)
523 .filter(mac -> !mac.equals(MacAddress.NONE))
524 .findFirst()
Yi Tseng51301292017-07-28 13:02:59 -0700525 .orElse(MacAddress.ONOS);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700526 if (interfaceMac == null) {
527 // can't find interface mac address
528 return;
529 }
530 processArpPacket(context, packet, interfaceMac);
531 }
532 }
533
534 /**
535 * Processes the ARP Payload and initiates a reply to the client.
536 *
537 * @param context the packet context
538 * @param packet the ethernet payload
539 * @param replyMac mac address to be replied
540 */
541 private void processArpPacket(PacketContext context, Ethernet packet, MacAddress replyMac) {
542 ARP arpPacket = (ARP) packet.getPayload();
Ray Milkeyf0c47612017-09-28 11:29:38 -0700543 ARP arpReply = arpPacket.duplicate();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700544 arpReply.setOpCode(ARP.OP_REPLY);
545
546 arpReply.setTargetProtocolAddress(arpPacket.getSenderProtocolAddress());
547 arpReply.setTargetHardwareAddress(arpPacket.getSenderHardwareAddress());
548 arpReply.setSenderProtocolAddress(arpPacket.getTargetProtocolAddress());
549 arpReply.setSenderHardwareAddress(replyMac.toBytes());
550
551 // Ethernet Frame.
552 Ethernet ethReply = new Ethernet();
553 ethReply.setSourceMACAddress(replyMac.toBytes());
554 ethReply.setDestinationMACAddress(packet.getSourceMAC());
555 ethReply.setEtherType(Ethernet.TYPE_ARP);
556 ethReply.setVlanID(packet.getVlanID());
557 ethReply.setPayload(arpReply);
558
559 ConnectPoint targetPort = context.inPacket().receivedFrom();
560 TrafficTreatment t = DefaultTrafficTreatment.builder()
561 .setOutput(targetPort.port()).build();
562 OutboundPacket o = new DefaultOutboundPacket(
563 targetPort.deviceId(), t, ByteBuffer.wrap(ethReply.serialize()));
564 if (log.isTraceEnabled()) {
565 log.trace("Relaying ARP packet {} to {}", packet, targetPort);
566 }
567 packetService.emit(o);
568 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700569 }
570
571 /**
572 * Listener for network config events.
573 */
574 private class InternalConfigListener implements NetworkConfigListener {
575 @Override
576 public void event(NetworkConfigEvent event) {
Yi Tseng51f1be92017-09-01 17:24:57 -0700577 switch (event.type()) {
578 case CONFIG_UPDATED:
579 case CONFIG_ADDED:
580 event.config().ifPresent(config -> {
581 updateConfig(config);
582 log.info("{} updated", config.getClass().getSimpleName());
583 });
584 break;
585 case CONFIG_REMOVED:
586 event.prevConfig().ifPresent(config -> {
587 removeConfig(config);
588 log.info("{} removed", config.getClass().getSimpleName());
589 });
590 break;
Charles Chan10b2fee2018-04-21 00:44:29 -0700591 case CONFIG_REGISTERED:
592 case CONFIG_UNREGISTERED:
593 break;
Yi Tseng51f1be92017-09-01 17:24:57 -0700594 default:
595 log.warn("Unsupported event type {}", event.type());
596 break;
Yi Tseng483ac6f2017-08-02 15:03:31 -0700597 }
Charles Chan50443e82018-01-03 16:26:32 -0800598 }
Yi Tseng51f1be92017-09-01 17:24:57 -0700599
Charles Chan50443e82018-01-03 16:26:32 -0800600 @Override
601 public boolean isRelevant(NetworkConfigEvent event) {
602 if (event.configClass().equals(DefaultDhcpRelayConfig.class) ||
603 event.configClass().equals(IndirectDhcpRelayConfig.class) ||
604 event.configClass().equals(IgnoreDhcpConfig.class)) {
605 return true;
606 }
607 log.debug("Ignore irrelevant event class {}", event.configClass().getName());
608 return false;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700609 }
610 }
Yi Tseng127ffe52017-09-12 15:55:17 -0700611
612 private class InternalDeviceListener implements DeviceListener {
613
614 @Override
615 public void event(DeviceEvent event) {
616 Device device = event.subject();
617 switch (event.type()) {
618 case DEVICE_ADDED:
Yi Tseng525ff402017-10-23 19:39:39 -0700619 updateIgnoreVlanConfigs();
Yi Tseng127ffe52017-09-12 15:55:17 -0700620 break;
621 case DEVICE_AVAILABILITY_CHANGED:
622 deviceAvailabilityChanged(device);
Ray Milkeyd6a67c32018-02-02 10:30:35 -0800623 break;
Yi Tseng127ffe52017-09-12 15:55:17 -0700624 default:
625 break;
626 }
627 }
628
629 private void deviceAvailabilityChanged(Device device) {
630 if (deviceService.isAvailable(device.id())) {
Yi Tseng525ff402017-10-23 19:39:39 -0700631 updateIgnoreVlanConfigs();
Saurav Dasb805f1a2017-12-13 16:19:35 -0800632 } else {
633 removeIgnoreVlanState();
Yi Tseng127ffe52017-09-12 15:55:17 -0700634 }
635 }
636
Yi Tseng525ff402017-10-23 19:39:39 -0700637 private void updateIgnoreVlanConfigs() {
Yi Tseng127ffe52017-09-12 15:55:17 -0700638 IgnoreDhcpConfig config = cfgService.getConfig(appId, IgnoreDhcpConfig.class);
Yi Tseng525ff402017-10-23 19:39:39 -0700639 v4Handler.updateIgnoreVlanConfig(config);
640 v6Handler.updateIgnoreVlanConfig(config);
Yi Tseng127ffe52017-09-12 15:55:17 -0700641 }
Saurav Dasb805f1a2017-12-13 16:19:35 -0800642
643 private void removeIgnoreVlanState() {
644 IgnoreDhcpConfig config = cfgService.getConfig(appId, IgnoreDhcpConfig.class);
645 v4Handler.removeIgnoreVlanState(config);
646 v6Handler.removeIgnoreVlanState(config);
647 }
Yi Tseng127ffe52017-09-12 15:55:17 -0700648 }
Kalhee Kimba366062017-11-07 16:32:09 +0000649
650
651
652 public Optional<FpmRecord> getFpmRecord(IpPrefix prefix) {
653 return dhcpFpmPrefixStore.getFpmRecord(prefix);
654 }
655
656 public Collection<FpmRecord> getFpmRecords() {
657 return dhcpFpmPrefixStore.getFpmRecords();
658 }
659
660 @Override
661 public void addFpmRecord(IpPrefix prefix, FpmRecord fpmRecord) {
662 dhcpFpmPrefixStore.addFpmRecord(prefix, fpmRecord);
663 }
664
665 @Override
666 public Optional<FpmRecord> removeFpmRecord(IpPrefix prefix) {
667 return dhcpFpmPrefixStore.removeFpmRecord(prefix);
668 }
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000669
670
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700671}