blob: bb5a7940822972d3975b6847523e5fc39990aabb [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;
Ray Milkey687c00c2018-10-31 10:18:41 -070099import static org.onosproject.dhcprelay.OsgiPropertyConstants.ARP_ENABLED;
100import static org.onosproject.dhcprelay.OsgiPropertyConstants.ARP_ENABLED_DEFAULT;
101import static org.onosproject.dhcprelay.OsgiPropertyConstants.DHCP_FPM_ENABLED;
102import static org.onosproject.dhcprelay.OsgiPropertyConstants.DHCP_FPM_ENABLED_DEFAULT;
103import static org.onosproject.dhcprelay.OsgiPropertyConstants.DHCP_POLL_INTERVAL;
104import static org.onosproject.dhcprelay.OsgiPropertyConstants.DHCP_POLL_INTERVAL_DEFAULT;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700105import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
Yi Tseng127ffe52017-09-12 15:55:17 -0700106
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700107/**
108 * DHCP Relay Agent Application Component.
109 */
Ray Milkey687c00c2018-10-31 10:18:41 -0700110@Component(
111 immediate = true,
112 service = DhcpRelayService.class,
113 property = {
114 ARP_ENABLED + ":Boolean=" + ARP_ENABLED_DEFAULT,
115 DHCP_POLL_INTERVAL + ":Integer=" + DHCP_POLL_INTERVAL_DEFAULT,
116 DHCP_FPM_ENABLED + ":Boolean=" + DHCP_FPM_ENABLED_DEFAULT
117 }
118)
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700119public class DhcpRelayManager implements DhcpRelayService {
Yi Tseng483ac6f2017-08-02 15:03:31 -0700120 public static final String DHCP_RELAY_APP = "org.onosproject.dhcprelay";
Yi Tseng06799d62017-09-01 16:02:56 -0700121 public static final String ROUTE_STORE_IMPL =
122 "org.onosproject.routeservice.store.RouteStoreImpl";
Yi Tseng525ff402017-10-23 19:39:39 -0700123
Yi Tseng51f1be92017-09-01 17:24:57 -0700124 private static final TrafficSelector ARP_SELECTOR = DefaultTrafficSelector.builder()
125 .matchEthType(Ethernet.TYPE_ARP)
126 .build();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700127 private final Logger log = LoggerFactory.getLogger(getClass());
128 private final InternalConfigListener cfgListener = new InternalConfigListener();
129
130 private final Set<ConfigFactory> factories = ImmutableSet.of(
Yi Tseng483ac6f2017-08-02 15:03:31 -0700131 new ConfigFactory<ApplicationId, DefaultDhcpRelayConfig>(APP_SUBJECT_FACTORY,
Kalhee Kimba366062017-11-07 16:32:09 +0000132 DefaultDhcpRelayConfig.class,
133 DefaultDhcpRelayConfig.KEY,
134 true) {
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700135 @Override
Yi Tseng483ac6f2017-08-02 15:03:31 -0700136 public DefaultDhcpRelayConfig createConfig() {
137 return new DefaultDhcpRelayConfig();
138 }
139 },
140 new ConfigFactory<ApplicationId, IndirectDhcpRelayConfig>(APP_SUBJECT_FACTORY,
Kalhee Kimba366062017-11-07 16:32:09 +0000141 IndirectDhcpRelayConfig.class,
142 IndirectDhcpRelayConfig.KEY,
143 true) {
Yi Tseng483ac6f2017-08-02 15:03:31 -0700144 @Override
145 public IndirectDhcpRelayConfig createConfig() {
146 return new IndirectDhcpRelayConfig();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700147 }
Yi Tseng51f1be92017-09-01 17:24:57 -0700148 },
149 new ConfigFactory<ApplicationId, IgnoreDhcpConfig>(APP_SUBJECT_FACTORY,
Kalhee Kimba366062017-11-07 16:32:09 +0000150 IgnoreDhcpConfig.class,
151 IgnoreDhcpConfig.KEY,
152 true) {
Yi Tseng51f1be92017-09-01 17:24:57 -0700153 @Override
154 public IgnoreDhcpConfig createConfig() {
155 return new IgnoreDhcpConfig();
156 }
Kalhee Kimba366062017-11-07 16:32:09 +0000157 },
158 new ConfigFactory<ApplicationId, EnableDhcpFpmConfig>(APP_SUBJECT_FACTORY,
159 EnableDhcpFpmConfig.class,
160 EnableDhcpFpmConfig.KEY,
161 false) {
162 @Override
163 public EnableDhcpFpmConfig createConfig() {
164 return new EnableDhcpFpmConfig();
165 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700166 }
167 );
168
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000169
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700170 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700171 protected NetworkConfigRegistry cfgService;
172
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700173 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700174 protected CoreService coreService;
175
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700176 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700177 protected PacketService packetService;
178
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700179 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700180 protected HostService hostService;
181
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700182 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700183 protected InterfaceService interfaceService;
184
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700185 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700186 protected DhcpRelayStore dhcpRelayStore;
187
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700188 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700189 protected ComponentConfigService compCfgService;
190
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700191 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tseng127ffe52017-09-12 15:55:17 -0700192 protected DeviceService deviceService;
193
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700194 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Kalhee Kimba366062017-11-07 16:32:09 +0000195 protected DhcpFpmPrefixStore dhcpFpmPrefixStore;
196
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700197 @Reference(cardinality = ReferenceCardinality.MANDATORY,
Yi Tseng127ffe52017-09-12 15:55:17 -0700198 target = "(version=4)")
Yi Tseng51301292017-07-28 13:02:59 -0700199 protected DhcpHandler v4Handler;
200
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700201 @Reference(cardinality = ReferenceCardinality.MANDATORY,
Yi Tseng127ffe52017-09-12 15:55:17 -0700202 target = "(version=6)")
Yi Tseng51301292017-07-28 13:02:59 -0700203 protected DhcpHandler v6Handler;
204
Ray Milkey687c00c2018-10-31 10:18:41 -0700205 /** Enable Address resolution protocol. */
206 protected boolean arpEnabled = ARP_ENABLED_DEFAULT;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700207
Ray Milkey687c00c2018-10-31 10:18:41 -0700208 /** dhcp relay poll interval. */
209 protected int dhcpPollInterval = DHCP_POLL_INTERVAL_DEFAULT;
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000210
Ray Milkey687c00c2018-10-31 10:18:41 -0700211 /** Enable DhcpRelay Fpm. */
212 protected boolean dhcpFpmEnabled = DHCP_FPM_ENABLED_DEFAULT;
Kalhee Kimba366062017-11-07 16:32:09 +0000213
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000214 private ScheduledExecutorService timerExecutor;
215
Yi Tseng127ffe52017-09-12 15:55:17 -0700216 protected DeviceListener deviceListener = new InternalDeviceListener();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700217 private DhcpRelayPacketProcessor dhcpRelayPacketProcessor = new DhcpRelayPacketProcessor();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700218 private ApplicationId appId;
219
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000220 /**
221 * One second timer.
222 */
223 class Dhcp6Timer implements Runnable {
224 @Override
225 public void run() {
226 v6Handler.timeTick();
227 }
228 };
Kalhee Kimba366062017-11-07 16:32:09 +0000229
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700230 @Activate
231 protected void activate(ComponentContext context) {
232 //start the dhcp relay agent
233 appId = coreService.registerApplication(DHCP_RELAY_APP);
234
235 cfgService.addListener(cfgListener);
236 factories.forEach(cfgService::registerConfigFactory);
237 //update the dhcp server configuration.
238 updateConfig();
Yi Tseng51301292017-07-28 13:02:59 -0700239
240 //add the packet processor
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700241 packetService.addProcessor(dhcpRelayPacketProcessor, PacketProcessor.director(0));
Yi Tseng51301292017-07-28 13:02:59 -0700242
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000243 timerExecutor = Executors.newScheduledThreadPool(1,
244 groupedThreads("dhcpRelay",
245 "config-reloader-%d", log));
246 timerExecutor.scheduleAtFixedRate(new Dhcp6Timer(),
247 0,
248 dhcpPollInterval,
249 TimeUnit.SECONDS);
250
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700251 modified(context);
252
Yi Tseng06799d62017-09-01 16:02:56 -0700253 // Enable distribute route store
254 compCfgService.preSetProperty(ROUTE_STORE_IMPL,
Kalhee Kimba366062017-11-07 16:32:09 +0000255 "distributed", Boolean.TRUE.toString());
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700256 compCfgService.registerProperties(getClass());
Yi Tseng127ffe52017-09-12 15:55:17 -0700257
258 deviceService.addListener(deviceListener);
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000259
260
261
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700262 log.info("DHCP-RELAY Started");
263 }
264
265 @Deactivate
266 protected void deactivate() {
267 cfgService.removeListener(cfgListener);
268 factories.forEach(cfgService::unregisterConfigFactory);
269 packetService.removeProcessor(dhcpRelayPacketProcessor);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700270 cancelArpPackets();
Yi Tsengdfa8ee22017-08-07 12:45:01 -0700271 compCfgService.unregisterProperties(getClass(), false);
Yi Tseng127ffe52017-09-12 15:55:17 -0700272 deviceService.removeListener(deviceListener);
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000273 timerExecutor.shutdown();
274
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700275 log.info("DHCP-RELAY Stopped");
276 }
277
278 @Modified
279 protected void modified(ComponentContext context) {
280 Dictionary<?, ?> properties = context.getProperties();
281 Boolean flag;
282
Ray Milkey687c00c2018-10-31 10:18:41 -0700283 flag = Tools.isPropertyEnabled(properties, ARP_ENABLED);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700284 if (flag != null) {
285 arpEnabled = flag;
286 log.info("Address resolution protocol is {}",
Kalhee Kimba366062017-11-07 16:32:09 +0000287 arpEnabled ? "enabled" : "disabled");
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700288 }
289
290 if (arpEnabled) {
291 requestArpPackets();
292 } else {
293 cancelArpPackets();
294 }
Kalhee Kimba366062017-11-07 16:32:09 +0000295
Ray Milkey687c00c2018-10-31 10:18:41 -0700296 int intervalVal = Tools.getIntegerProperty(properties, DHCP_POLL_INTERVAL);
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000297 log.info("DhcpRelay poll interval new {} old {}", intervalVal, dhcpPollInterval);
298 if (intervalVal != dhcpPollInterval) {
299 timerExecutor.shutdown();
300 dhcpPollInterval = intervalVal;
301 timerExecutor = Executors.newScheduledThreadPool(1,
302 groupedThreads("dhcpRelay",
303 "config-reloader-%d", log));
304 timerExecutor.scheduleAtFixedRate(new Dhcp6Timer(),
305 0,
306 dhcpPollInterval > 1 ? dhcpPollInterval : 1,
307 TimeUnit.SECONDS);
308 v6Handler.setDhcp6PollInterval(dhcpPollInterval);
309 }
310
Ray Milkey687c00c2018-10-31 10:18:41 -0700311 flag = Tools.isPropertyEnabled(properties, DHCP_FPM_ENABLED);
Kalhee Kimba366062017-11-07 16:32:09 +0000312 if (flag != null) {
313 boolean oldValue = dhcpFpmEnabled;
314 dhcpFpmEnabled = flag;
315 log.info("DhcpRelay FPM is {}",
316 dhcpFpmEnabled ? "enabled" : "disabled");
317
318 if (dhcpFpmEnabled && !oldValue) {
319 log.info("Dhcp Fpm is enabled.");
320 processDhcpFpmRoutes(true);
321 }
322 if (!dhcpFpmEnabled && oldValue) {
323 log.info("Dhcp Fpm is disabled.");
324 processDhcpFpmRoutes(false);
325 }
326 v6Handler.setDhcpFpmEnabled(dhcpFpmEnabled);
327 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700328 }
329
Yi Tseng525ff402017-10-23 19:39:39 -0700330 private static List<TrafficSelector> buildClientDhcpSelectors() {
331 return Streams.concat(Dhcp4HandlerImpl.DHCP_SELECTORS.stream(),
332 Dhcp6HandlerImpl.DHCP_SELECTORS.stream())
333 .collect(Collectors.toList());
334 }
335
Yi Tseng483ac6f2017-08-02 15:03:31 -0700336 /**
337 * Updates DHCP relay app configuration.
338 */
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700339 private void updateConfig() {
Yi Tseng483ac6f2017-08-02 15:03:31 -0700340 DefaultDhcpRelayConfig defaultConfig =
341 cfgService.getConfig(appId, DefaultDhcpRelayConfig.class);
342 IndirectDhcpRelayConfig indirectConfig =
343 cfgService.getConfig(appId, IndirectDhcpRelayConfig.class);
Yi Tseng51f1be92017-09-01 17:24:57 -0700344 IgnoreDhcpConfig ignoreDhcpConfig =
345 cfgService.getConfig(appId, IgnoreDhcpConfig.class);
Yi Tseng483ac6f2017-08-02 15:03:31 -0700346
347 if (defaultConfig != null) {
348 updateConfig(defaultConfig);
349 }
Yi Tseng483ac6f2017-08-02 15:03:31 -0700350 if (indirectConfig != null) {
351 updateConfig(indirectConfig);
352 }
Yi Tseng51f1be92017-09-01 17:24:57 -0700353 if (ignoreDhcpConfig != null) {
354 updateConfig(ignoreDhcpConfig);
355 }
Yi Tseng483ac6f2017-08-02 15:03:31 -0700356 }
357
358 /**
359 * Updates DHCP relay app configuration with given configuration.
360 *
361 * @param config the configuration ot update
362 */
Yi Tseng51f1be92017-09-01 17:24:57 -0700363 protected void updateConfig(Config config) {
Yi Tseng483ac6f2017-08-02 15:03:31 -0700364 if (config instanceof IndirectDhcpRelayConfig) {
365 IndirectDhcpRelayConfig indirectConfig = (IndirectDhcpRelayConfig) config;
366 v4Handler.setIndirectDhcpServerConfigs(indirectConfig.dhcpServerConfigs());
367 v6Handler.setIndirectDhcpServerConfigs(indirectConfig.dhcpServerConfigs());
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700368 } else if (config instanceof DefaultDhcpRelayConfig) {
369 DefaultDhcpRelayConfig defaultConfig = (DefaultDhcpRelayConfig) config;
370 v4Handler.setDefaultDhcpServerConfigs(defaultConfig.dhcpServerConfigs());
371 v6Handler.setDefaultDhcpServerConfigs(defaultConfig.dhcpServerConfigs());
Yi Tseng483ac6f2017-08-02 15:03:31 -0700372 }
Yi Tseng51f1be92017-09-01 17:24:57 -0700373 if (config instanceof IgnoreDhcpConfig) {
Yi Tseng525ff402017-10-23 19:39:39 -0700374 v4Handler.updateIgnoreVlanConfig((IgnoreDhcpConfig) config);
375 v6Handler.updateIgnoreVlanConfig((IgnoreDhcpConfig) config);
Yi Tseng51f1be92017-09-01 17:24:57 -0700376 }
377 }
378
379 protected void removeConfig(Config config) {
380 if (config instanceof IndirectDhcpRelayConfig) {
381 v4Handler.setIndirectDhcpServerConfigs(Collections.emptyList());
382 v6Handler.setIndirectDhcpServerConfigs(Collections.emptyList());
383 } else if (config instanceof DefaultDhcpRelayConfig) {
384 v4Handler.setDefaultDhcpServerConfigs(Collections.emptyList());
385 v6Handler.setDefaultDhcpServerConfigs(Collections.emptyList());
386 }
387 if (config instanceof IgnoreDhcpConfig) {
Yi Tseng525ff402017-10-23 19:39:39 -0700388 v4Handler.updateIgnoreVlanConfig(null);
389 v6Handler.updateIgnoreVlanConfig(null);
Yi Tseng51f1be92017-09-01 17:24:57 -0700390 }
391 }
392
Kalhee Kimba366062017-11-07 16:32:09 +0000393 private void processDhcpFpmRoutes(Boolean add) {
394 // needs to restore/remove fpm
395 }
396
397 public boolean isDhcpFpmEnabled() {
398 return dhcpFpmEnabled;
399 }
400
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700401 /**
402 * Request ARP packet in via PacketService.
403 */
404 private void requestArpPackets() {
Yi Tseng51f1be92017-09-01 17:24:57 -0700405 packetService.requestPackets(ARP_SELECTOR, PacketPriority.CONTROL, appId);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700406 }
407
408 /**
409 * Cancel requested ARP packets in via packet service.
410 */
411 private void cancelArpPackets() {
Yi Tseng51f1be92017-09-01 17:24:57 -0700412 packetService.cancelPackets(ARP_SELECTOR, PacketPriority.CONTROL, appId);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700413 }
414
415 @Override
416 public Optional<DhcpRecord> getDhcpRecord(HostId hostId) {
417 return dhcpRelayStore.getDhcpRecord(hostId);
418 }
419
420 @Override
421 public Collection<DhcpRecord> getDhcpRecords() {
422 return dhcpRelayStore.getDhcpRecords();
423 }
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000424 @Override
425 public void updateDhcpRecord(HostId hostId, DhcpRecord dhcpRecord) {
426 dhcpRelayStore.updateDhcpRecord(hostId, dhcpRecord);
427 }
Yi Tseng13a41a12017-07-26 13:45:01 -0700428 @Override
429 public Optional<MacAddress> getDhcpServerMacAddress() {
Yi Tseng4f2a0462017-08-31 11:21:00 -0700430 // TODO: depreated it
431 DefaultDhcpRelayConfig config = cfgService.getConfig(appId, DefaultDhcpRelayConfig.class);
432 DhcpServerConfig serverConfig = config.dhcpServerConfigs().get(0);
433 Ip4Address serverip = serverConfig.getDhcpServerIp4().get();
434 return hostService.getHostsByIp(serverip)
435 .stream()
436 .map(Host::mac)
437 .findFirst();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700438 }
439
Yi Tseng919b2df2017-09-07 16:22:51 -0700440 @Override
441 public List<DhcpServerInfo> getDefaultDhcpServerInfoList() {
442 return ImmutableList.<DhcpServerInfo>builder()
443 .addAll(v4Handler.getDefaultDhcpServerInfoList())
444 .addAll(v6Handler.getDefaultDhcpServerInfoList())
445 .build();
446 }
447
448 @Override
449 public List<DhcpServerInfo> getIndirectDhcpServerInfoList() {
450 return ImmutableList.<DhcpServerInfo>builder()
451 .addAll(v4Handler.getIndirectDhcpServerInfoList())
452 .addAll(v6Handler.getIndirectDhcpServerInfoList())
453 .build();
454 }
455
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700456 /**
457 * Gets DHCP data from a packet.
458 *
459 * @param packet the packet
460 * @return the DHCP data; empty if it is not a DHCP packet
461 */
462 private Optional<DHCP> findDhcp(Ethernet packet) {
463 return Stream.of(packet)
464 .filter(Objects::nonNull)
465 .map(Ethernet::getPayload)
466 .filter(p -> p instanceof IPv4)
467 .map(IPacket::getPayload)
468 .filter(Objects::nonNull)
469 .filter(p -> p instanceof UDP)
470 .map(IPacket::getPayload)
471 .filter(Objects::nonNull)
472 .filter(p -> p instanceof DHCP)
473 .map(p -> (DHCP) p)
474 .findFirst();
475 }
476
477 /**
478 * Gets DHCPv6 data from a packet.
479 *
480 * @param packet the packet
481 * @return the DHCPv6 data; empty if it is not a DHCPv6 packet
482 */
483 private Optional<DHCP6> findDhcp6(Ethernet packet) {
484 return Stream.of(packet)
485 .filter(Objects::nonNull)
486 .map(Ethernet::getPayload)
487 .filter(p -> p instanceof IPv6)
488 .map(IPacket::getPayload)
489 .filter(Objects::nonNull)
490 .filter(p -> p instanceof UDP)
491 .map(IPacket::getPayload)
492 .filter(Objects::nonNull)
493 .filter(p -> p instanceof DHCP6)
494 .map(p -> (DHCP6) p)
495 .findFirst();
496 }
497
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700498
499 private class DhcpRelayPacketProcessor implements PacketProcessor {
500
501 @Override
502 public void process(PacketContext context) {
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700503 // process the packet and get the payload
504 Ethernet packet = context.inPacket().parsed();
505 if (packet == null) {
506 return;
507 }
508
509 findDhcp(packet).ifPresent(dhcpPayload -> {
Yi Tseng51301292017-07-28 13:02:59 -0700510 v4Handler.processDhcpPacket(context, dhcpPayload);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700511 });
512
513 findDhcp6(packet).ifPresent(dhcp6Payload -> {
Yi Tseng51301292017-07-28 13:02:59 -0700514 v6Handler.processDhcpPacket(context, dhcp6Payload);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700515 });
516
517 if (packet.getEtherType() == Ethernet.TYPE_ARP && arpEnabled) {
518 ARP arpPacket = (ARP) packet.getPayload();
519 VlanId vlanId = VlanId.vlanId(packet.getVlanID());
520 Set<Interface> interfaces = interfaceService.
521 getInterfacesByPort(context.inPacket().receivedFrom());
522 //ignore the packets if dhcp server interface is not configured on onos.
523 if (interfaces.isEmpty()) {
524 log.warn("server virtual interface not configured");
525 return;
526 }
527 if ((arpPacket.getOpCode() != ARP.OP_REQUEST)) {
528 // handle request only
529 return;
530 }
531 MacAddress interfaceMac = interfaces.stream()
532 .filter(iface -> iface.vlan().equals(vlanId))
533 .map(Interface::mac)
534 .filter(mac -> !mac.equals(MacAddress.NONE))
535 .findFirst()
Yi Tseng51301292017-07-28 13:02:59 -0700536 .orElse(MacAddress.ONOS);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700537 if (interfaceMac == null) {
538 // can't find interface mac address
539 return;
540 }
541 processArpPacket(context, packet, interfaceMac);
542 }
543 }
544
545 /**
546 * Processes the ARP Payload and initiates a reply to the client.
547 *
548 * @param context the packet context
549 * @param packet the ethernet payload
550 * @param replyMac mac address to be replied
551 */
552 private void processArpPacket(PacketContext context, Ethernet packet, MacAddress replyMac) {
553 ARP arpPacket = (ARP) packet.getPayload();
Ray Milkeyf0c47612017-09-28 11:29:38 -0700554 ARP arpReply = arpPacket.duplicate();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700555 arpReply.setOpCode(ARP.OP_REPLY);
556
557 arpReply.setTargetProtocolAddress(arpPacket.getSenderProtocolAddress());
558 arpReply.setTargetHardwareAddress(arpPacket.getSenderHardwareAddress());
559 arpReply.setSenderProtocolAddress(arpPacket.getTargetProtocolAddress());
560 arpReply.setSenderHardwareAddress(replyMac.toBytes());
561
562 // Ethernet Frame.
563 Ethernet ethReply = new Ethernet();
564 ethReply.setSourceMACAddress(replyMac.toBytes());
565 ethReply.setDestinationMACAddress(packet.getSourceMAC());
566 ethReply.setEtherType(Ethernet.TYPE_ARP);
567 ethReply.setVlanID(packet.getVlanID());
568 ethReply.setPayload(arpReply);
569
570 ConnectPoint targetPort = context.inPacket().receivedFrom();
571 TrafficTreatment t = DefaultTrafficTreatment.builder()
572 .setOutput(targetPort.port()).build();
573 OutboundPacket o = new DefaultOutboundPacket(
574 targetPort.deviceId(), t, ByteBuffer.wrap(ethReply.serialize()));
575 if (log.isTraceEnabled()) {
576 log.trace("Relaying ARP packet {} to {}", packet, targetPort);
577 }
578 packetService.emit(o);
579 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700580 }
581
582 /**
583 * Listener for network config events.
584 */
585 private class InternalConfigListener implements NetworkConfigListener {
586 @Override
587 public void event(NetworkConfigEvent event) {
Yi Tseng51f1be92017-09-01 17:24:57 -0700588 switch (event.type()) {
589 case CONFIG_UPDATED:
590 case CONFIG_ADDED:
591 event.config().ifPresent(config -> {
592 updateConfig(config);
593 log.info("{} updated", config.getClass().getSimpleName());
594 });
595 break;
596 case CONFIG_REMOVED:
597 event.prevConfig().ifPresent(config -> {
598 removeConfig(config);
599 log.info("{} removed", config.getClass().getSimpleName());
600 });
601 break;
Charles Chan10b2fee2018-04-21 00:44:29 -0700602 case CONFIG_REGISTERED:
603 case CONFIG_UNREGISTERED:
604 break;
Yi Tseng51f1be92017-09-01 17:24:57 -0700605 default:
606 log.warn("Unsupported event type {}", event.type());
607 break;
Yi Tseng483ac6f2017-08-02 15:03:31 -0700608 }
Charles Chan50443e82018-01-03 16:26:32 -0800609 }
Yi Tseng51f1be92017-09-01 17:24:57 -0700610
Charles Chan50443e82018-01-03 16:26:32 -0800611 @Override
612 public boolean isRelevant(NetworkConfigEvent event) {
613 if (event.configClass().equals(DefaultDhcpRelayConfig.class) ||
614 event.configClass().equals(IndirectDhcpRelayConfig.class) ||
615 event.configClass().equals(IgnoreDhcpConfig.class)) {
616 return true;
617 }
618 log.debug("Ignore irrelevant event class {}", event.configClass().getName());
619 return false;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700620 }
621 }
Yi Tseng127ffe52017-09-12 15:55:17 -0700622
623 private class InternalDeviceListener implements DeviceListener {
624
625 @Override
626 public void event(DeviceEvent event) {
627 Device device = event.subject();
628 switch (event.type()) {
629 case DEVICE_ADDED:
Yi Tseng525ff402017-10-23 19:39:39 -0700630 updateIgnoreVlanConfigs();
Yi Tseng127ffe52017-09-12 15:55:17 -0700631 break;
632 case DEVICE_AVAILABILITY_CHANGED:
633 deviceAvailabilityChanged(device);
Ray Milkeyd6a67c32018-02-02 10:30:35 -0800634 break;
Yi Tseng127ffe52017-09-12 15:55:17 -0700635 default:
636 break;
637 }
638 }
639
640 private void deviceAvailabilityChanged(Device device) {
641 if (deviceService.isAvailable(device.id())) {
Yi Tseng525ff402017-10-23 19:39:39 -0700642 updateIgnoreVlanConfigs();
Saurav Dasb805f1a2017-12-13 16:19:35 -0800643 } else {
644 removeIgnoreVlanState();
Yi Tseng127ffe52017-09-12 15:55:17 -0700645 }
646 }
647
Yi Tseng525ff402017-10-23 19:39:39 -0700648 private void updateIgnoreVlanConfigs() {
Yi Tseng127ffe52017-09-12 15:55:17 -0700649 IgnoreDhcpConfig config = cfgService.getConfig(appId, IgnoreDhcpConfig.class);
Yi Tseng525ff402017-10-23 19:39:39 -0700650 v4Handler.updateIgnoreVlanConfig(config);
651 v6Handler.updateIgnoreVlanConfig(config);
Yi Tseng127ffe52017-09-12 15:55:17 -0700652 }
Saurav Dasb805f1a2017-12-13 16:19:35 -0800653
654 private void removeIgnoreVlanState() {
655 IgnoreDhcpConfig config = cfgService.getConfig(appId, IgnoreDhcpConfig.class);
656 v4Handler.removeIgnoreVlanState(config);
657 v6Handler.removeIgnoreVlanState(config);
658 }
Yi Tseng127ffe52017-09-12 15:55:17 -0700659 }
Kalhee Kimba366062017-11-07 16:32:09 +0000660
661
662
663 public Optional<FpmRecord> getFpmRecord(IpPrefix prefix) {
664 return dhcpFpmPrefixStore.getFpmRecord(prefix);
665 }
666
667 public Collection<FpmRecord> getFpmRecords() {
668 return dhcpFpmPrefixStore.getFpmRecords();
669 }
670
671 @Override
672 public void addFpmRecord(IpPrefix prefix, FpmRecord fpmRecord) {
673 dhcpFpmPrefixStore.addFpmRecord(prefix, fpmRecord);
674 }
675
676 @Override
677 public Optional<FpmRecord> removeFpmRecord(IpPrefix prefix) {
678 return dhcpFpmPrefixStore.removeFpmRecord(prefix);
679 }
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000680
681
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700682}