blob: ea230a41e3460d643f581f26cf667b1e5f1658ac [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 Sahota196a9ca2019-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;
Anjali K Kf3963f12019-04-16 19:27:30 +000048import org.onlab.packet.Ip6Address;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070049import org.onlab.packet.MacAddress;
Kalhee Kimba366062017-11-07 16:32:09 +000050import org.onlab.packet.IpPrefix;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070051import org.onlab.packet.UDP;
52import org.onlab.packet.VlanId;
Harshada Chaundkar669bdf62019-05-28 21:12:05 +000053
Anjali K Kf3963f12019-04-16 19:27:30 +000054import org.onlab.packet.ndp.NeighborSolicitation;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070055import org.onlab.util.Tools;
56import org.onosproject.cfg.ComponentConfigService;
57import org.onosproject.core.ApplicationId;
58import org.onosproject.core.CoreService;
Yi Tseng51301292017-07-28 13:02:59 -070059import org.onosproject.dhcprelay.api.DhcpHandler;
60import org.onosproject.dhcprelay.api.DhcpRelayService;
Yi Tseng919b2df2017-09-07 16:22:51 -070061import org.onosproject.dhcprelay.api.DhcpServerInfo;
Yi Tseng483ac6f2017-08-02 15:03:31 -070062import org.onosproject.dhcprelay.config.DefaultDhcpRelayConfig;
Taras Lemkin371ac5e2018-03-26 14:52:58 +000063import org.onosproject.dhcprelay.config.DhcpServerConfig;
Kalhee Kimba366062017-11-07 16:32:09 +000064import org.onosproject.dhcprelay.config.EnableDhcpFpmConfig;
Anjali K Kf3963f12019-04-16 19:27:30 +000065import org.onosproject.dhcprelay.config.HostAutoRelearnConfig;
Taras Lemkin371ac5e2018-03-26 14:52:58 +000066import org.onosproject.dhcprelay.config.IndirectDhcpRelayConfig;
67import org.onosproject.dhcprelay.config.IgnoreDhcpConfig;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070068import org.onosproject.dhcprelay.store.DhcpRecord;
69import org.onosproject.dhcprelay.store.DhcpRelayStore;
Kalhee Kimba366062017-11-07 16:32:09 +000070import org.onosproject.dhcprelay.store.DhcpFpmPrefixStore;
Harshada Chaundkar669bdf62019-05-28 21:12:05 +000071import org.onosproject.mastership.MastershipService;
Kalhee Kimba366062017-11-07 16:32:09 +000072import org.onosproject.routing.fpm.api.FpmRecord;
Yi Tseng127ffe52017-09-12 15:55:17 -070073import org.onosproject.net.Device;
Yi Tseng4f2a0462017-08-31 11:21:00 -070074import org.onosproject.net.Host;
Yi Tseng483ac6f2017-08-02 15:03:31 -070075import org.onosproject.net.config.Config;
Yi Tseng127ffe52017-09-12 15:55:17 -070076import org.onosproject.net.device.DeviceEvent;
77import org.onosproject.net.device.DeviceListener;
78import org.onosproject.net.device.DeviceService;
Ray Milkeyfacf2862017-08-03 11:58:29 -070079import org.onosproject.net.intf.Interface;
80import org.onosproject.net.intf.InterfaceService;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070081import org.onosproject.net.ConnectPoint;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070082import org.onosproject.net.HostId;
Anjali K Kf3963f12019-04-16 19:27:30 +000083import org.onosproject.net.HostLocation;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070084import org.onosproject.net.config.ConfigFactory;
85import org.onosproject.net.config.NetworkConfigEvent;
86import org.onosproject.net.config.NetworkConfigListener;
87import org.onosproject.net.config.NetworkConfigRegistry;
88import org.onosproject.net.flow.DefaultTrafficSelector;
89import org.onosproject.net.flow.DefaultTrafficTreatment;
90import org.onosproject.net.flow.TrafficSelector;
91import org.onosproject.net.flow.TrafficTreatment;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070092import org.onosproject.net.host.HostService;
Anjali K Kf3963f12019-04-16 19:27:30 +000093import org.onosproject.net.Port;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070094import org.onosproject.net.packet.DefaultOutboundPacket;
95import org.onosproject.net.packet.OutboundPacket;
96import org.onosproject.net.packet.PacketContext;
97import org.onosproject.net.packet.PacketPriority;
98import org.onosproject.net.packet.PacketProcessor;
99import org.onosproject.net.packet.PacketService;
Kalhee Kimba366062017-11-07 16:32:09 +0000100
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700101import org.osgi.service.component.ComponentContext;
102import org.slf4j.Logger;
103import org.slf4j.LoggerFactory;
Kalhee Kime5bb7092017-11-29 19:03:02 +0000104import java.util.concurrent.Executors;
Ruchi Sahota196a9ca2019-03-01 16:56:07 +0000105import java.util.concurrent.ExecutorService;
Kalhee Kime5bb7092017-11-29 19:03:02 +0000106import java.util.concurrent.ScheduledExecutorService;
107import java.util.concurrent.TimeUnit;
Anjali K Kf3963f12019-04-16 19:27:30 +0000108import java.util.concurrent.CopyOnWriteArraySet;
109
Kalhee Kime5bb7092017-11-29 19:03:02 +0000110import static org.onlab.util.Tools.groupedThreads;
Ruchi Sahota196a9ca2019-03-01 16:56:07 +0000111import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700112import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
Yi Tseng127ffe52017-09-12 15:55:17 -0700113
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700114/**
115 * DHCP Relay Agent Application Component.
116 */
117@Component(immediate = true)
118@Service
119public class DhcpRelayManager implements DhcpRelayService {
Yi Tseng483ac6f2017-08-02 15:03:31 -0700120 public static final String DHCP_RELAY_APP = "org.onosproject.dhcprelay";
Charles Chanc1daa8f2019-01-23 15:03:17 -0800121 public static final String ROUTE_STORE_IMPL = "org.onosproject.routeservice.store.RouteStoreImpl";
Charles Chanc1daa8f2019-01-23 15:03:17 -0800122 private static final int DEFAULT_POOL_SIZE = 32;
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();
Anjali K Kf3963f12019-04-16 19:27:30 +0000129 protected CopyOnWriteArraySet hostAutoRelearnEnabledDevices = new CopyOnWriteArraySet();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700130
131 private final Set<ConfigFactory> factories = ImmutableSet.of(
Yi Tseng483ac6f2017-08-02 15:03:31 -0700132 new ConfigFactory<ApplicationId, DefaultDhcpRelayConfig>(APP_SUBJECT_FACTORY,
Kalhee Kimba366062017-11-07 16:32:09 +0000133 DefaultDhcpRelayConfig.class,
134 DefaultDhcpRelayConfig.KEY,
135 true) {
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700136 @Override
Yi Tseng483ac6f2017-08-02 15:03:31 -0700137 public DefaultDhcpRelayConfig createConfig() {
138 return new DefaultDhcpRelayConfig();
139 }
140 },
141 new ConfigFactory<ApplicationId, IndirectDhcpRelayConfig>(APP_SUBJECT_FACTORY,
Kalhee Kimba366062017-11-07 16:32:09 +0000142 IndirectDhcpRelayConfig.class,
143 IndirectDhcpRelayConfig.KEY,
144 true) {
Yi Tseng483ac6f2017-08-02 15:03:31 -0700145 @Override
146 public IndirectDhcpRelayConfig createConfig() {
147 return new IndirectDhcpRelayConfig();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700148 }
Yi Tseng51f1be92017-09-01 17:24:57 -0700149 },
150 new ConfigFactory<ApplicationId, IgnoreDhcpConfig>(APP_SUBJECT_FACTORY,
Kalhee Kimba366062017-11-07 16:32:09 +0000151 IgnoreDhcpConfig.class,
152 IgnoreDhcpConfig.KEY,
153 true) {
Yi Tseng51f1be92017-09-01 17:24:57 -0700154 @Override
155 public IgnoreDhcpConfig createConfig() {
156 return new IgnoreDhcpConfig();
157 }
Kalhee Kimba366062017-11-07 16:32:09 +0000158 },
159 new ConfigFactory<ApplicationId, EnableDhcpFpmConfig>(APP_SUBJECT_FACTORY,
160 EnableDhcpFpmConfig.class,
161 EnableDhcpFpmConfig.KEY,
162 false) {
163 @Override
164 public EnableDhcpFpmConfig createConfig() {
165 return new EnableDhcpFpmConfig();
166 }
Anjali K Kf3963f12019-04-16 19:27:30 +0000167 },
168 new ConfigFactory<ApplicationId, HostAutoRelearnConfig>(APP_SUBJECT_FACTORY,
169 HostAutoRelearnConfig.class,
170 HostAutoRelearnConfig.KEY,
171 true) {
172 @Override
173 public HostAutoRelearnConfig createConfig() {
174 return new HostAutoRelearnConfig();
175 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700176 }
177 );
178
Kalhee Kime5bb7092017-11-29 19:03:02 +0000179
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700180 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
181 protected NetworkConfigRegistry cfgService;
182
183 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Harshada Chaundkar669bdf62019-05-28 21:12:05 +0000184 protected MastershipService mastershipService;
185
186 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700187 protected CoreService coreService;
188
189 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
190 protected PacketService packetService;
191
192 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
193 protected HostService hostService;
194
195 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700196 protected InterfaceService interfaceService;
197
198 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
199 protected DhcpRelayStore dhcpRelayStore;
200
201 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
202 protected ComponentConfigService compCfgService;
203
Yi Tseng51f1be92017-09-01 17:24:57 -0700204 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Yi Tseng127ffe52017-09-12 15:55:17 -0700205 protected DeviceService deviceService;
206
Kalhee Kimba366062017-11-07 16:32:09 +0000207 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
208 protected DhcpFpmPrefixStore dhcpFpmPrefixStore;
209
Yi Tseng51301292017-07-28 13:02:59 -0700210 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY,
Yi Tseng127ffe52017-09-12 15:55:17 -0700211 target = "(version=4)")
Yi Tseng51301292017-07-28 13:02:59 -0700212 protected DhcpHandler v4Handler;
213
214 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY,
Yi Tseng127ffe52017-09-12 15:55:17 -0700215 target = "(version=6)")
Yi Tseng51301292017-07-28 13:02:59 -0700216 protected DhcpHandler v6Handler;
217
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700218 @Property(name = "arpEnabled", boolValue = true,
Yi Tseng127ffe52017-09-12 15:55:17 -0700219 label = "Enable Address resolution protocol")
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700220 protected boolean arpEnabled = true;
221
Kalhee Kime5bb7092017-11-29 19:03:02 +0000222 @Property(name = "dhcpPollInterval", intValue = 24 * 3600,
223 label = "dhcp relay poll interval")
224 protected int dhcpPollInterval = 24 * 3600;
225
Kalhee Kimba366062017-11-07 16:32:09 +0000226 @Property(name = "dhcpFpmEnabled", boolValue = false,
227 label = "Enable DhcpRelay Fpm")
228 protected boolean dhcpFpmEnabled = false;
229
Anjali K Kf3963f12019-04-16 19:27:30 +0000230 @Property(name = "dhcpHostRelearnProbeInterval", intValue = 500,
231 label = "dhcp host relearn probe interval in millis")
232 protected int dhcpHostRelearnProbeInterval = 500;
233
234 @Property(name = "dhcpHostRelearnProbeCount", intValue = 3,
235 label = "dhcp host relearn probe count")
236 protected int dhcpHostRelearnProbeCount = 3;
237
Kalhee Kime5bb7092017-11-29 19:03:02 +0000238 private ScheduledExecutorService timerExecutor;
Anjali K Kf3963f12019-04-16 19:27:30 +0000239 private ScheduledExecutorService executorService = null;
Ruchi Sahota196a9ca2019-03-01 16:56:07 +0000240 protected ExecutorService devEventExecutor;
Charles Chanc1daa8f2019-01-23 15:03:17 -0800241 private ExecutorService packetExecutor;
Kalhee Kime5bb7092017-11-29 19:03:02 +0000242
Yi Tseng127ffe52017-09-12 15:55:17 -0700243 protected DeviceListener deviceListener = new InternalDeviceListener();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700244 private DhcpRelayPacketProcessor dhcpRelayPacketProcessor = new DhcpRelayPacketProcessor();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700245 private ApplicationId appId;
246
Anjali K Kf3963f12019-04-16 19:27:30 +0000247 private static final int POOL_SIZE = 10;
248 private static final int HOST_PROBE_INIT_DELAY = 500;
249
Kalhee Kime5bb7092017-11-29 19:03:02 +0000250 /**
251 * One second timer.
252 */
253 class Dhcp6Timer implements Runnable {
254 @Override
255 public void run() {
256 v6Handler.timeTick();
257 }
258 };
Kalhee Kimba366062017-11-07 16:32:09 +0000259
Anjali K Kf3963f12019-04-16 19:27:30 +0000260
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700261 @Activate
262 protected void activate(ComponentContext context) {
263 //start the dhcp relay agent
264 appId = coreService.registerApplication(DHCP_RELAY_APP);
265
266 cfgService.addListener(cfgListener);
267 factories.forEach(cfgService::registerConfigFactory);
268 //update the dhcp server configuration.
269 updateConfig();
Yi Tseng51301292017-07-28 13:02:59 -0700270
271 //add the packet processor
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700272 packetService.addProcessor(dhcpRelayPacketProcessor, PacketProcessor.director(0));
Yi Tseng51301292017-07-28 13:02:59 -0700273
Kalhee Kime5bb7092017-11-29 19:03:02 +0000274 timerExecutor = Executors.newScheduledThreadPool(1,
Charles Chanc1daa8f2019-01-23 15:03:17 -0800275 groupedThreads("onos/dhcprelay", "config-reloader-%d", log));
276 timerExecutor.scheduleAtFixedRate(new Dhcp6Timer(), 0, dhcpPollInterval, TimeUnit.SECONDS);
277 packetExecutor = Executors.newFixedThreadPool(DEFAULT_POOL_SIZE,
278 groupedThreads("onos/dhcprelay", "packet-%d", log));
Kalhee Kime5bb7092017-11-29 19:03:02 +0000279
Ruchi Sahota196a9ca2019-03-01 16:56:07 +0000280 devEventExecutor = newSingleThreadScheduledExecutor(
281 groupedThreads("onos/dhcprelay-dev-events", "events-%d", log));
282
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700283 modified(context);
284
Yi Tseng06799d62017-09-01 16:02:56 -0700285 // Enable distribute route store
286 compCfgService.preSetProperty(ROUTE_STORE_IMPL,
Kalhee Kimba366062017-11-07 16:32:09 +0000287 "distributed", Boolean.TRUE.toString());
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700288 compCfgService.registerProperties(getClass());
Yi Tseng127ffe52017-09-12 15:55:17 -0700289
Anjali K Kf3963f12019-04-16 19:27:30 +0000290 executorService = Executors.newScheduledThreadPool(POOL_SIZE);
291
Yi Tseng127ffe52017-09-12 15:55:17 -0700292 deviceService.addListener(deviceListener);
Kalhee Kime5bb7092017-11-29 19:03:02 +0000293
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700294 log.info("DHCP-RELAY Started");
295 }
296
297 @Deactivate
298 protected void deactivate() {
299 cfgService.removeListener(cfgListener);
300 factories.forEach(cfgService::unregisterConfigFactory);
301 packetService.removeProcessor(dhcpRelayPacketProcessor);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700302 cancelArpPackets();
Yi Tsengdfa8ee22017-08-07 12:45:01 -0700303 compCfgService.unregisterProperties(getClass(), false);
Yi Tseng127ffe52017-09-12 15:55:17 -0700304 deviceService.removeListener(deviceListener);
Kalhee Kime5bb7092017-11-29 19:03:02 +0000305 timerExecutor.shutdown();
Ruchi Sahota196a9ca2019-03-01 16:56:07 +0000306 devEventExecutor.shutdownNow();
307 devEventExecutor = null;
Charles Chanc1daa8f2019-01-23 15:03:17 -0800308 packetExecutor.shutdown();
309 timerExecutor = null;
310 packetExecutor = null;
Anjali K Kf3963f12019-04-16 19:27:30 +0000311 executorService.shutdown();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700312 log.info("DHCP-RELAY Stopped");
313 }
314
315 @Modified
316 protected void modified(ComponentContext context) {
317 Dictionary<?, ?> properties = context.getProperties();
318 Boolean flag;
319
320 flag = Tools.isPropertyEnabled(properties, "arpEnabled");
321 if (flag != null) {
322 arpEnabled = flag;
323 log.info("Address resolution protocol is {}",
Kalhee Kimba366062017-11-07 16:32:09 +0000324 arpEnabled ? "enabled" : "disabled");
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700325 }
326
327 if (arpEnabled) {
328 requestArpPackets();
329 } else {
330 cancelArpPackets();
331 }
Kalhee Kimba366062017-11-07 16:32:09 +0000332
Kalhee Kime5bb7092017-11-29 19:03:02 +0000333 int intervalVal = Tools.getIntegerProperty(properties, "dhcpPollInterval");
334 log.info("DhcpRelay poll interval new {} old {}", intervalVal, dhcpPollInterval);
335 if (intervalVal != dhcpPollInterval) {
336 timerExecutor.shutdown();
337 dhcpPollInterval = intervalVal;
338 timerExecutor = Executors.newScheduledThreadPool(1,
339 groupedThreads("dhcpRelay",
340 "config-reloader-%d", log));
341 timerExecutor.scheduleAtFixedRate(new Dhcp6Timer(),
342 0,
343 dhcpPollInterval > 1 ? dhcpPollInterval : 1,
344 TimeUnit.SECONDS);
345 v6Handler.setDhcp6PollInterval(dhcpPollInterval);
346 }
347
Kalhee Kimba366062017-11-07 16:32:09 +0000348 flag = Tools.isPropertyEnabled(properties, "dhcpFpmEnabled");
349 if (flag != null) {
350 boolean oldValue = dhcpFpmEnabled;
351 dhcpFpmEnabled = flag;
352 log.info("DhcpRelay FPM is {}",
353 dhcpFpmEnabled ? "enabled" : "disabled");
354
355 if (dhcpFpmEnabled && !oldValue) {
356 log.info("Dhcp Fpm is enabled.");
357 processDhcpFpmRoutes(true);
358 }
359 if (!dhcpFpmEnabled && oldValue) {
360 log.info("Dhcp Fpm is disabled.");
361 processDhcpFpmRoutes(false);
362 }
363 v6Handler.setDhcpFpmEnabled(dhcpFpmEnabled);
364 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700365 }
366
Yi Tseng525ff402017-10-23 19:39:39 -0700367 private static List<TrafficSelector> buildClientDhcpSelectors() {
368 return Streams.concat(Dhcp4HandlerImpl.DHCP_SELECTORS.stream(),
369 Dhcp6HandlerImpl.DHCP_SELECTORS.stream())
370 .collect(Collectors.toList());
371 }
372
Yi Tseng483ac6f2017-08-02 15:03:31 -0700373 /**
374 * Updates DHCP relay app configuration.
375 */
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700376 private void updateConfig() {
Yi Tseng483ac6f2017-08-02 15:03:31 -0700377 DefaultDhcpRelayConfig defaultConfig =
378 cfgService.getConfig(appId, DefaultDhcpRelayConfig.class);
379 IndirectDhcpRelayConfig indirectConfig =
380 cfgService.getConfig(appId, IndirectDhcpRelayConfig.class);
Yi Tseng51f1be92017-09-01 17:24:57 -0700381 IgnoreDhcpConfig ignoreDhcpConfig =
382 cfgService.getConfig(appId, IgnoreDhcpConfig.class);
Anjali K Kf3963f12019-04-16 19:27:30 +0000383 HostAutoRelearnConfig hostAutoRelearnConfig =
384 cfgService.getConfig(appId, HostAutoRelearnConfig.class);
Yi Tseng483ac6f2017-08-02 15:03:31 -0700385
386 if (defaultConfig != null) {
387 updateConfig(defaultConfig);
388 }
Yi Tseng483ac6f2017-08-02 15:03:31 -0700389 if (indirectConfig != null) {
390 updateConfig(indirectConfig);
391 }
Yi Tseng51f1be92017-09-01 17:24:57 -0700392 if (ignoreDhcpConfig != null) {
393 updateConfig(ignoreDhcpConfig);
394 }
Anjali K Kf3963f12019-04-16 19:27:30 +0000395 if (hostAutoRelearnConfig != null) {
396 updateConfig(hostAutoRelearnConfig);
397 }
Yi Tseng483ac6f2017-08-02 15:03:31 -0700398 }
399
400 /**
401 * Updates DHCP relay app configuration with given configuration.
402 *
403 * @param config the configuration ot update
404 */
Yi Tseng51f1be92017-09-01 17:24:57 -0700405 protected void updateConfig(Config config) {
Yi Tseng483ac6f2017-08-02 15:03:31 -0700406 if (config instanceof IndirectDhcpRelayConfig) {
407 IndirectDhcpRelayConfig indirectConfig = (IndirectDhcpRelayConfig) config;
408 v4Handler.setIndirectDhcpServerConfigs(indirectConfig.dhcpServerConfigs());
409 v6Handler.setIndirectDhcpServerConfigs(indirectConfig.dhcpServerConfigs());
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700410 } else if (config instanceof DefaultDhcpRelayConfig) {
411 DefaultDhcpRelayConfig defaultConfig = (DefaultDhcpRelayConfig) config;
412 v4Handler.setDefaultDhcpServerConfigs(defaultConfig.dhcpServerConfigs());
413 v6Handler.setDefaultDhcpServerConfigs(defaultConfig.dhcpServerConfigs());
Yi Tseng483ac6f2017-08-02 15:03:31 -0700414 }
Yi Tseng51f1be92017-09-01 17:24:57 -0700415 if (config instanceof IgnoreDhcpConfig) {
Yi Tseng525ff402017-10-23 19:39:39 -0700416 v4Handler.updateIgnoreVlanConfig((IgnoreDhcpConfig) config);
417 v6Handler.updateIgnoreVlanConfig((IgnoreDhcpConfig) config);
Yi Tseng51f1be92017-09-01 17:24:57 -0700418 }
Anjali K Kf3963f12019-04-16 19:27:30 +0000419 if (config instanceof HostAutoRelearnConfig) {
420 setHostAutoRelearnConfig((HostAutoRelearnConfig) config);
421 }
Yi Tseng51f1be92017-09-01 17:24:57 -0700422 }
423
424 protected void removeConfig(Config config) {
425 if (config instanceof IndirectDhcpRelayConfig) {
426 v4Handler.setIndirectDhcpServerConfigs(Collections.emptyList());
427 v6Handler.setIndirectDhcpServerConfigs(Collections.emptyList());
428 } else if (config instanceof DefaultDhcpRelayConfig) {
429 v4Handler.setDefaultDhcpServerConfigs(Collections.emptyList());
430 v6Handler.setDefaultDhcpServerConfigs(Collections.emptyList());
431 }
432 if (config instanceof IgnoreDhcpConfig) {
Yi Tseng525ff402017-10-23 19:39:39 -0700433 v4Handler.updateIgnoreVlanConfig(null);
434 v6Handler.updateIgnoreVlanConfig(null);
Yi Tseng51f1be92017-09-01 17:24:57 -0700435 }
436 }
437
Kalhee Kimba366062017-11-07 16:32:09 +0000438 private void processDhcpFpmRoutes(Boolean add) {
439 // needs to restore/remove fpm
440 }
441
442 public boolean isDhcpFpmEnabled() {
443 return dhcpFpmEnabled;
444 }
445
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700446 /**
447 * Request ARP packet in via PacketService.
448 */
449 private void requestArpPackets() {
Yi Tseng51f1be92017-09-01 17:24:57 -0700450 packetService.requestPackets(ARP_SELECTOR, PacketPriority.CONTROL, appId);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700451 }
452
453 /**
454 * Cancel requested ARP packets in via packet service.
455 */
456 private void cancelArpPackets() {
Yi Tseng51f1be92017-09-01 17:24:57 -0700457 packetService.cancelPackets(ARP_SELECTOR, PacketPriority.CONTROL, appId);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700458 }
459
460 @Override
461 public Optional<DhcpRecord> getDhcpRecord(HostId hostId) {
462 return dhcpRelayStore.getDhcpRecord(hostId);
463 }
464
465 @Override
466 public Collection<DhcpRecord> getDhcpRecords() {
467 return dhcpRelayStore.getDhcpRecords();
468 }
Anjali K Kf3963f12019-04-16 19:27:30 +0000469
Kalhee Kime5bb7092017-11-29 19:03:02 +0000470 @Override
471 public void updateDhcpRecord(HostId hostId, DhcpRecord dhcpRecord) {
472 dhcpRelayStore.updateDhcpRecord(hostId, dhcpRecord);
473 }
Anjali K Kf3963f12019-04-16 19:27:30 +0000474
Yi Tseng13a41a12017-07-26 13:45:01 -0700475 @Override
476 public Optional<MacAddress> getDhcpServerMacAddress() {
Yi Tseng4f2a0462017-08-31 11:21:00 -0700477 // TODO: depreated it
478 DefaultDhcpRelayConfig config = cfgService.getConfig(appId, DefaultDhcpRelayConfig.class);
479 DhcpServerConfig serverConfig = config.dhcpServerConfigs().get(0);
480 Ip4Address serverip = serverConfig.getDhcpServerIp4().get();
481 return hostService.getHostsByIp(serverip)
482 .stream()
483 .map(Host::mac)
484 .findFirst();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700485 }
486
Yi Tseng919b2df2017-09-07 16:22:51 -0700487 @Override
488 public List<DhcpServerInfo> getDefaultDhcpServerInfoList() {
489 return ImmutableList.<DhcpServerInfo>builder()
490 .addAll(v4Handler.getDefaultDhcpServerInfoList())
491 .addAll(v6Handler.getDefaultDhcpServerInfoList())
492 .build();
493 }
494
495 @Override
496 public List<DhcpServerInfo> getIndirectDhcpServerInfoList() {
497 return ImmutableList.<DhcpServerInfo>builder()
498 .addAll(v4Handler.getIndirectDhcpServerInfoList())
499 .addAll(v6Handler.getIndirectDhcpServerInfoList())
500 .build();
501 }
502
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700503 /**
504 * Gets DHCP data from a packet.
505 *
506 * @param packet the packet
507 * @return the DHCP data; empty if it is not a DHCP packet
508 */
509 private Optional<DHCP> findDhcp(Ethernet packet) {
510 return Stream.of(packet)
511 .filter(Objects::nonNull)
512 .map(Ethernet::getPayload)
513 .filter(p -> p instanceof IPv4)
514 .map(IPacket::getPayload)
515 .filter(Objects::nonNull)
516 .filter(p -> p instanceof UDP)
517 .map(IPacket::getPayload)
518 .filter(Objects::nonNull)
519 .filter(p -> p instanceof DHCP)
520 .map(p -> (DHCP) p)
521 .findFirst();
522 }
523
524 /**
525 * Gets DHCPv6 data from a packet.
526 *
527 * @param packet the packet
528 * @return the DHCPv6 data; empty if it is not a DHCPv6 packet
529 */
530 private Optional<DHCP6> findDhcp6(Ethernet packet) {
531 return Stream.of(packet)
532 .filter(Objects::nonNull)
533 .map(Ethernet::getPayload)
534 .filter(p -> p instanceof IPv6)
535 .map(IPacket::getPayload)
536 .filter(Objects::nonNull)
537 .filter(p -> p instanceof UDP)
538 .map(IPacket::getPayload)
539 .filter(Objects::nonNull)
540 .filter(p -> p instanceof DHCP6)
541 .map(p -> (DHCP6) p)
542 .findFirst();
543 }
544
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700545
546 private class DhcpRelayPacketProcessor implements PacketProcessor {
Anjali K Kf3963f12019-04-16 19:27:30 +0000547
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700548 @Override
549 public void process(PacketContext context) {
Charles Chanc1daa8f2019-01-23 15:03:17 -0800550 packetExecutor.execute(() -> processInternal(context));
551 }
552
553 private void processInternal(PacketContext context) {
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700554 // process the packet and get the payload
555 Ethernet packet = context.inPacket().parsed();
556 if (packet == null) {
557 return;
558 }
559
560 findDhcp(packet).ifPresent(dhcpPayload -> {
Yi Tseng51301292017-07-28 13:02:59 -0700561 v4Handler.processDhcpPacket(context, dhcpPayload);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700562 });
563
564 findDhcp6(packet).ifPresent(dhcp6Payload -> {
Yi Tseng51301292017-07-28 13:02:59 -0700565 v6Handler.processDhcpPacket(context, dhcp6Payload);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700566 });
567
568 if (packet.getEtherType() == Ethernet.TYPE_ARP && arpEnabled) {
569 ARP arpPacket = (ARP) packet.getPayload();
570 VlanId vlanId = VlanId.vlanId(packet.getVlanID());
571 Set<Interface> interfaces = interfaceService.
572 getInterfacesByPort(context.inPacket().receivedFrom());
573 //ignore the packets if dhcp server interface is not configured on onos.
574 if (interfaces.isEmpty()) {
575 log.warn("server virtual interface not configured");
576 return;
577 }
578 if ((arpPacket.getOpCode() != ARP.OP_REQUEST)) {
579 // handle request only
580 return;
581 }
582 MacAddress interfaceMac = interfaces.stream()
583 .filter(iface -> iface.vlan().equals(vlanId))
584 .map(Interface::mac)
585 .filter(mac -> !mac.equals(MacAddress.NONE))
586 .findFirst()
Yi Tseng51301292017-07-28 13:02:59 -0700587 .orElse(MacAddress.ONOS);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700588 if (interfaceMac == null) {
589 // can't find interface mac address
590 return;
591 }
592 processArpPacket(context, packet, interfaceMac);
593 }
594 }
595
596 /**
597 * Processes the ARP Payload and initiates a reply to the client.
598 *
599 * @param context the packet context
600 * @param packet the ethernet payload
601 * @param replyMac mac address to be replied
602 */
603 private void processArpPacket(PacketContext context, Ethernet packet, MacAddress replyMac) {
604 ARP arpPacket = (ARP) packet.getPayload();
Ray Milkeyf0c47612017-09-28 11:29:38 -0700605 ARP arpReply = arpPacket.duplicate();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700606 arpReply.setOpCode(ARP.OP_REPLY);
607
608 arpReply.setTargetProtocolAddress(arpPacket.getSenderProtocolAddress());
609 arpReply.setTargetHardwareAddress(arpPacket.getSenderHardwareAddress());
610 arpReply.setSenderProtocolAddress(arpPacket.getTargetProtocolAddress());
611 arpReply.setSenderHardwareAddress(replyMac.toBytes());
612
613 // Ethernet Frame.
614 Ethernet ethReply = new Ethernet();
615 ethReply.setSourceMACAddress(replyMac.toBytes());
616 ethReply.setDestinationMACAddress(packet.getSourceMAC());
617 ethReply.setEtherType(Ethernet.TYPE_ARP);
618 ethReply.setVlanID(packet.getVlanID());
619 ethReply.setPayload(arpReply);
620
621 ConnectPoint targetPort = context.inPacket().receivedFrom();
622 TrafficTreatment t = DefaultTrafficTreatment.builder()
623 .setOutput(targetPort.port()).build();
624 OutboundPacket o = new DefaultOutboundPacket(
625 targetPort.deviceId(), t, ByteBuffer.wrap(ethReply.serialize()));
626 if (log.isTraceEnabled()) {
627 log.trace("Relaying ARP packet {} to {}", packet, targetPort);
628 }
629 packetService.emit(o);
630 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700631 }
632
633 /**
634 * Listener for network config events.
635 */
636 private class InternalConfigListener implements NetworkConfigListener {
637 @Override
638 public void event(NetworkConfigEvent event) {
Yi Tseng51f1be92017-09-01 17:24:57 -0700639 switch (event.type()) {
640 case CONFIG_UPDATED:
641 case CONFIG_ADDED:
642 event.config().ifPresent(config -> {
643 updateConfig(config);
644 log.info("{} updated", config.getClass().getSimpleName());
645 });
646 break;
647 case CONFIG_REMOVED:
648 event.prevConfig().ifPresent(config -> {
649 removeConfig(config);
650 log.info("{} removed", config.getClass().getSimpleName());
651 });
652 break;
Charles Chan6be77d82018-04-21 00:44:29 -0700653 case CONFIG_REGISTERED:
654 case CONFIG_UNREGISTERED:
655 break;
Yi Tseng51f1be92017-09-01 17:24:57 -0700656 default:
657 log.warn("Unsupported event type {}", event.type());
658 break;
Yi Tseng483ac6f2017-08-02 15:03:31 -0700659 }
Charles Chan285cb772018-01-03 16:26:32 -0800660 }
Yi Tseng51f1be92017-09-01 17:24:57 -0700661
Charles Chan285cb772018-01-03 16:26:32 -0800662 @Override
663 public boolean isRelevant(NetworkConfigEvent event) {
664 if (event.configClass().equals(DefaultDhcpRelayConfig.class) ||
665 event.configClass().equals(IndirectDhcpRelayConfig.class) ||
Anjali K Kf3963f12019-04-16 19:27:30 +0000666 event.configClass().equals(IgnoreDhcpConfig.class) ||
667 event.configClass().equals(HostAutoRelearnConfig.class)) {
Charles Chan285cb772018-01-03 16:26:32 -0800668 return true;
669 }
670 log.debug("Ignore irrelevant event class {}", event.configClass().getName());
671 return false;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700672 }
673 }
Yi Tseng127ffe52017-09-12 15:55:17 -0700674
675 private class InternalDeviceListener implements DeviceListener {
676
677 @Override
678 public void event(DeviceEvent event) {
Ruchi Sahota196a9ca2019-03-01 16:56:07 +0000679 if (devEventExecutor != null) {
Anjali K Kf3963f12019-04-16 19:27:30 +0000680 final Device device = event.subject();
Yi Tseng127ffe52017-09-12 15:55:17 -0700681 switch (event.type()) {
682 case DEVICE_ADDED:
Ruchi Sahota196a9ca2019-03-01 16:56:07 +0000683 devEventExecutor.execute(this::updateIgnoreVlanConfigs);
Yi Tseng127ffe52017-09-12 15:55:17 -0700684 break;
685 case DEVICE_AVAILABILITY_CHANGED:
Ruchi Sahota196a9ca2019-03-01 16:56:07 +0000686 devEventExecutor.execute(() -> deviceAvailabilityChanged(device));
687 break;
Anjali K Kf3963f12019-04-16 19:27:30 +0000688 case PORT_UPDATED:
689 Port port = event.port();
690 devEventExecutor.execute(() -> portUpdatedEventHandler(device, port));
691 break;
Yi Tseng127ffe52017-09-12 15:55:17 -0700692 default:
693 break;
694 }
Ruchi Sahota196a9ca2019-03-01 16:56:07 +0000695 }
Yi Tseng127ffe52017-09-12 15:55:17 -0700696 }
697
Anjali K Kf3963f12019-04-16 19:27:30 +0000698 private void portUpdatedEventHandler(Device device, Port port) {
Harshada Chaundkar669bdf62019-05-28 21:12:05 +0000699 if (!mastershipService.isLocalMaster(device.id())) {
700 log.warn("This instance is not the master for the device {}", device.id());
701 return;
702 }
Anjali K Kf3963f12019-04-16 19:27:30 +0000703 if (hostAutoRelearnEnabledDevices.contains(device.id()) && port.isEnabled()) {
704 ConnectPoint cp = new ConnectPoint(device.id(), port.number());
705 HostLocation hostLocation = new HostLocation(cp, 0);
706 Set<DhcpRecord> records = dhcpRelayStore.getDhcpRecords()
707 .stream()
708 .filter(i -> i.directlyConnected())
709 .filter(i -> i.locations().contains(hostLocation))
710 .collect(Collectors.toSet());
711
712 for (DhcpRecord i : records) {
713 //found a dhcprecord matching the connect point of the port event
Harshada Chaundkar669bdf62019-05-28 21:12:05 +0000714 log.debug("portUpdatedEventHandler:DHCP record {}, sending msg on CP {} Mac {} Vlan{} DeviceId {}",
715 i, cp, i.macAddress(), i.vlanId(), device.id());
Anjali K Kf3963f12019-04-16 19:27:30 +0000716 if (i.ip4Address().isPresent()) {
717 log.warn("Sending host relearn probe for v4 not supported for Mac {} Vlan{} ip {}",
718 i.macAddress(), i.vlanId(), i.ip4Address());
719 } else if (i.ip6Address().isPresent()) {
720 sendHostRelearnProbe(cp, i.macAddress(), i.vlanId(), i.ip6Address());
721 }
722 }
723 }
724 }
725
Yi Tseng127ffe52017-09-12 15:55:17 -0700726 private void deviceAvailabilityChanged(Device device) {
727 if (deviceService.isAvailable(device.id())) {
Yi Tseng525ff402017-10-23 19:39:39 -0700728 updateIgnoreVlanConfigs();
Saurav Dasfa9004b2017-12-13 16:19:35 -0800729 } else {
730 removeIgnoreVlanState();
Yi Tseng127ffe52017-09-12 15:55:17 -0700731 }
732 }
733
Yi Tseng525ff402017-10-23 19:39:39 -0700734 private void updateIgnoreVlanConfigs() {
Yi Tseng127ffe52017-09-12 15:55:17 -0700735 IgnoreDhcpConfig config = cfgService.getConfig(appId, IgnoreDhcpConfig.class);
Yi Tseng525ff402017-10-23 19:39:39 -0700736 v4Handler.updateIgnoreVlanConfig(config);
737 v6Handler.updateIgnoreVlanConfig(config);
Yi Tseng127ffe52017-09-12 15:55:17 -0700738 }
Saurav Dasfa9004b2017-12-13 16:19:35 -0800739
740 private void removeIgnoreVlanState() {
741 IgnoreDhcpConfig config = cfgService.getConfig(appId, IgnoreDhcpConfig.class);
742 v4Handler.removeIgnoreVlanState(config);
743 v6Handler.removeIgnoreVlanState(config);
744 }
Yi Tseng127ffe52017-09-12 15:55:17 -0700745 }
Kalhee Kimba366062017-11-07 16:32:09 +0000746
Anjali K Kf3963f12019-04-16 19:27:30 +0000747 private void setHostAutoRelearnConfig(HostAutoRelearnConfig config) {
748 hostAutoRelearnEnabledDevices.clear();
749 if (config == null) {
750 return;
751 }
752 hostAutoRelearnEnabledDevices.addAll(config.hostAutoRelearnEnabledDevices());
753 }
754
755 // Packet transmission class.
756 private class PktTransmitter implements Runnable {
757
758 MacAddress mac;
759 VlanId vlanId;
760 Ip6Address ipv6Address;
761 ConnectPoint connectPoint;
Anjali K Kf3963f12019-04-16 19:27:30 +0000762 PktTransmitter(MacAddress mac, VlanId vlanId, Ip6Address ipv6Address, ConnectPoint connectPoint) {
763 this.mac = mac;
764 this.vlanId = vlanId;
765 this.ipv6Address = ipv6Address;
766 this.connectPoint = connectPoint;
767 }
768
769 @Override
770 public void run() {
771 log.debug("Host Relearn probe packet transmission activated for Mac {} Vlan {} Ip {} ConnectPt {}",
772 mac, vlanId, ipv6Address, connectPoint);
773 if (mac == null || vlanId == null || ipv6Address == null || connectPoint == null) {
774 return;
775 }
776
Harshada Chaundkar669bdf62019-05-28 21:12:05 +0000777 Interface senderInterface = interfaceService.getInterfacesByPort(connectPoint)
778 .stream().filter(iface -> Dhcp6HandlerUtil.interfaceContainsVlan(iface, vlanId))
779 .findFirst().orElse(null);
780 if (senderInterface == null) {
781 log.warn("Cannot get sender interface for from packet, abort... vlan {}", vlanId.toString());
782 }
783 MacAddress senderMacAddress = senderInterface.mac();
784 byte[] senderIpAddress = IPv6.getLinkLocalAddress(senderMacAddress.toBytes());
785 byte[] destIp = IPv6.getSolicitNodeAddress(ipv6Address.toOctets());
786
Anjali K Kf3963f12019-04-16 19:27:30 +0000787 Ethernet ethernet = NeighborSolicitation.buildNdpSolicit(
788 this.ipv6Address,
789 Ip6Address.valueOf(senderIpAddress),
Harshada Chaundkar669bdf62019-05-28 21:12:05 +0000790 Ip6Address.valueOf(destIp), //destip
791 senderMacAddress,
Anjali K Kf3963f12019-04-16 19:27:30 +0000792 this.mac,
793 this.vlanId);
Anjali K Kf3963f12019-04-16 19:27:30 +0000794 sendHostRelearnProbeToConnectPoint(ethernet, connectPoint);
795
796 log.debug("Host Relearn Probe transmission completed.");
797 }
798 }
799
800 //Create packet and schedule transmitter thread.
801 private void sendHostRelearnProbe(ConnectPoint connectPoint, MacAddress mac, VlanId vlanId,
802 Optional<Ip6Address> ipv6Address) {
803 PktTransmitter nsTransmitter = new PktTransmitter(mac, vlanId, ipv6Address.get(), connectPoint);
804 executorService.schedule(nsTransmitter, HOST_PROBE_INIT_DELAY, TimeUnit.MILLISECONDS);
805 }
806
807 // Send Host Relearn Probe packets to ConnectPoint
808 private void sendHostRelearnProbeToConnectPoint(Ethernet nsPacket, ConnectPoint connectPoint) {
809 TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(connectPoint.port()).build();
810 OutboundPacket outboundPacket = new DefaultOutboundPacket(connectPoint.deviceId(),
811 treatment, ByteBuffer.wrap(nsPacket.serialize()));
812 int counter = 0;
813 try {
814 while (counter < dhcpHostRelearnProbeCount) {
815 packetService.emit(outboundPacket);
816 counter++;
817 Thread.sleep(dhcpHostRelearnProbeInterval);
818 }
819 } catch (Exception e) {
820 log.error("Exception while emmiting packet {}", e.getMessage(), e);
821 }
822 }
Kalhee Kimba366062017-11-07 16:32:09 +0000823
824
825 public Optional<FpmRecord> getFpmRecord(IpPrefix prefix) {
826 return dhcpFpmPrefixStore.getFpmRecord(prefix);
827 }
828
829 public Collection<FpmRecord> getFpmRecords() {
830 return dhcpFpmPrefixStore.getFpmRecords();
831 }
832
833 @Override
834 public void addFpmRecord(IpPrefix prefix, FpmRecord fpmRecord) {
835 dhcpFpmPrefixStore.addFpmRecord(prefix, fpmRecord);
836 }
837
838 @Override
839 public Optional<FpmRecord> removeFpmRecord(IpPrefix prefix) {
840 return dhcpFpmPrefixStore.removeFpmRecord(prefix);
841 }
Kalhee Kime5bb7092017-11-29 19:03:02 +0000842
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700843}