blob: 2ba8702689653f042820c1b976c6974194c3555b [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 Sahota66b01292019-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;
Harshada Chaundkar8c28a992019-05-30 16:27:29 +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 Chaundkar8c28a992019-05-30 16:27:29 +000053
54import 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 Lemkin41785912018-03-26 14:52:58 +000063import org.onosproject.dhcprelay.config.DhcpServerConfig;
Kalhee Kimba366062017-11-07 16:32:09 +000064import org.onosproject.dhcprelay.config.EnableDhcpFpmConfig;
Harshada Chaundkar8c28a992019-05-30 16:27:29 +000065import org.onosproject.dhcprelay.config.HostAutoRelearnConfig;
Taras Lemkin41785912018-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 Chaundkar8c28a992019-05-30 16:27:29 +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;
piera8dd99f2019-06-07 14:47:37 +020074import org.onosproject.net.DeviceId;
Yi Tseng4f2a0462017-08-31 11:21:00 -070075import org.onosproject.net.Host;
Yi Tseng483ac6f2017-08-02 15:03:31 -070076import org.onosproject.net.config.Config;
Yi Tseng127ffe52017-09-12 15:55:17 -070077import org.onosproject.net.device.DeviceEvent;
78import org.onosproject.net.device.DeviceListener;
79import org.onosproject.net.device.DeviceService;
Ray Milkeyfacf2862017-08-03 11:58:29 -070080import org.onosproject.net.intf.Interface;
81import org.onosproject.net.intf.InterfaceService;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070082import org.onosproject.net.ConnectPoint;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070083import org.onosproject.net.HostId;
Harshada Chaundkar8c28a992019-05-30 16:27:29 +000084import org.onosproject.net.HostLocation;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070085import org.onosproject.net.config.ConfigFactory;
86import org.onosproject.net.config.NetworkConfigEvent;
87import org.onosproject.net.config.NetworkConfigListener;
88import org.onosproject.net.config.NetworkConfigRegistry;
89import org.onosproject.net.flow.DefaultTrafficSelector;
90import org.onosproject.net.flow.DefaultTrafficTreatment;
91import org.onosproject.net.flow.TrafficSelector;
92import org.onosproject.net.flow.TrafficTreatment;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070093import org.onosproject.net.host.HostService;
Harshada Chaundkar8c28a992019-05-30 16:27:29 +000094import org.onosproject.net.Port;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070095import org.onosproject.net.packet.DefaultOutboundPacket;
96import org.onosproject.net.packet.OutboundPacket;
97import org.onosproject.net.packet.PacketContext;
98import org.onosproject.net.packet.PacketPriority;
99import org.onosproject.net.packet.PacketProcessor;
100import org.onosproject.net.packet.PacketService;
Kalhee Kimba366062017-11-07 16:32:09 +0000101
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700102import org.osgi.service.component.ComponentContext;
103import org.slf4j.Logger;
104import org.slf4j.LoggerFactory;
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000105import java.util.concurrent.Executors;
Ruchi Sahota66b01292019-03-01 16:56:07 +0000106import java.util.concurrent.ExecutorService;
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000107import java.util.concurrent.ScheduledExecutorService;
108import java.util.concurrent.TimeUnit;
Harshada Chaundkar8c28a992019-05-30 16:27:29 +0000109import java.util.concurrent.CopyOnWriteArraySet;
110
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000111import static org.onlab.util.Tools.groupedThreads;
Ruchi Sahota66b01292019-03-01 16:56:07 +0000112import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700113import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
Yi Tseng127ffe52017-09-12 15:55:17 -0700114
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700115/**
116 * DHCP Relay Agent Application Component.
117 */
118@Component(immediate = true)
119@Service
120public class DhcpRelayManager implements DhcpRelayService {
Yi Tseng483ac6f2017-08-02 15:03:31 -0700121 public static final String DHCP_RELAY_APP = "org.onosproject.dhcprelay";
Charles Chanba06a3c2019-01-23 15:03:17 -0800122 public static final String ROUTE_STORE_IMPL = "org.onosproject.routeservice.store.RouteStoreImpl";
Charles Chanba06a3c2019-01-23 15:03:17 -0800123 private static final int DEFAULT_POOL_SIZE = 32;
Yi Tseng525ff402017-10-23 19:39:39 -0700124
Yi Tseng51f1be92017-09-01 17:24:57 -0700125 private static final TrafficSelector ARP_SELECTOR = DefaultTrafficSelector.builder()
126 .matchEthType(Ethernet.TYPE_ARP)
127 .build();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700128 private final Logger log = LoggerFactory.getLogger(getClass());
129 private final InternalConfigListener cfgListener = new InternalConfigListener();
piera8dd99f2019-06-07 14:47:37 +0200130 private CopyOnWriteArraySet<DeviceId> hostAutoRelearnEnabledDevices = new CopyOnWriteArraySet<DeviceId>();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700131
132 private final Set<ConfigFactory> factories = ImmutableSet.of(
Yi Tseng483ac6f2017-08-02 15:03:31 -0700133 new ConfigFactory<ApplicationId, DefaultDhcpRelayConfig>(APP_SUBJECT_FACTORY,
Kalhee Kimba366062017-11-07 16:32:09 +0000134 DefaultDhcpRelayConfig.class,
135 DefaultDhcpRelayConfig.KEY,
136 true) {
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700137 @Override
Yi Tseng483ac6f2017-08-02 15:03:31 -0700138 public DefaultDhcpRelayConfig createConfig() {
139 return new DefaultDhcpRelayConfig();
140 }
141 },
142 new ConfigFactory<ApplicationId, IndirectDhcpRelayConfig>(APP_SUBJECT_FACTORY,
Kalhee Kimba366062017-11-07 16:32:09 +0000143 IndirectDhcpRelayConfig.class,
144 IndirectDhcpRelayConfig.KEY,
145 true) {
Yi Tseng483ac6f2017-08-02 15:03:31 -0700146 @Override
147 public IndirectDhcpRelayConfig createConfig() {
148 return new IndirectDhcpRelayConfig();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700149 }
Yi Tseng51f1be92017-09-01 17:24:57 -0700150 },
151 new ConfigFactory<ApplicationId, IgnoreDhcpConfig>(APP_SUBJECT_FACTORY,
Kalhee Kimba366062017-11-07 16:32:09 +0000152 IgnoreDhcpConfig.class,
153 IgnoreDhcpConfig.KEY,
154 true) {
Yi Tseng51f1be92017-09-01 17:24:57 -0700155 @Override
156 public IgnoreDhcpConfig createConfig() {
157 return new IgnoreDhcpConfig();
158 }
Kalhee Kimba366062017-11-07 16:32:09 +0000159 },
160 new ConfigFactory<ApplicationId, EnableDhcpFpmConfig>(APP_SUBJECT_FACTORY,
161 EnableDhcpFpmConfig.class,
162 EnableDhcpFpmConfig.KEY,
163 false) {
164 @Override
165 public EnableDhcpFpmConfig createConfig() {
166 return new EnableDhcpFpmConfig();
167 }
Harshada Chaundkar8c28a992019-05-30 16:27:29 +0000168 },
169 new ConfigFactory<ApplicationId, HostAutoRelearnConfig>(APP_SUBJECT_FACTORY,
170 HostAutoRelearnConfig.class,
171 HostAutoRelearnConfig.KEY,
172 true) {
173 @Override
174 public HostAutoRelearnConfig createConfig() {
175 return new HostAutoRelearnConfig();
176 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700177 }
178 );
179
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000180
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700181 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
182 protected NetworkConfigRegistry cfgService;
183
184 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Harshada Chaundkar8c28a992019-05-30 16:27:29 +0000185 protected MastershipService mastershipService;
186
187 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700188 protected CoreService coreService;
189
190 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
191 protected PacketService packetService;
192
193 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
194 protected HostService hostService;
195
196 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700197 protected InterfaceService interfaceService;
198
199 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
200 protected DhcpRelayStore dhcpRelayStore;
201
202 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
203 protected ComponentConfigService compCfgService;
204
Yi Tseng51f1be92017-09-01 17:24:57 -0700205 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Yi Tseng127ffe52017-09-12 15:55:17 -0700206 protected DeviceService deviceService;
207
Kalhee Kimba366062017-11-07 16:32:09 +0000208 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
209 protected DhcpFpmPrefixStore dhcpFpmPrefixStore;
210
Yi Tseng51301292017-07-28 13:02:59 -0700211 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY,
Yi Tseng127ffe52017-09-12 15:55:17 -0700212 target = "(version=4)")
Yi Tseng51301292017-07-28 13:02:59 -0700213 protected DhcpHandler v4Handler;
214
215 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY,
Yi Tseng127ffe52017-09-12 15:55:17 -0700216 target = "(version=6)")
Yi Tseng51301292017-07-28 13:02:59 -0700217 protected DhcpHandler v6Handler;
218
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700219 @Property(name = "arpEnabled", boolValue = true,
Yi Tseng127ffe52017-09-12 15:55:17 -0700220 label = "Enable Address resolution protocol")
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700221 protected boolean arpEnabled = true;
222
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000223 @Property(name = "dhcpPollInterval", intValue = 24 * 3600,
224 label = "dhcp relay poll interval")
225 protected int dhcpPollInterval = 24 * 3600;
226
Kalhee Kimba366062017-11-07 16:32:09 +0000227 @Property(name = "dhcpFpmEnabled", boolValue = false,
228 label = "Enable DhcpRelay Fpm")
229 protected boolean dhcpFpmEnabled = false;
230
Harshada Chaundkar8c28a992019-05-30 16:27:29 +0000231 @Property(name = "dhcpHostRelearnProbeInterval", intValue = 500,
232 label = "dhcp host relearn probe interval in millis")
233 protected int dhcpHostRelearnProbeInterval = 500;
234
235 @Property(name = "dhcpHostRelearnProbeCount", intValue = 3,
236 label = "dhcp host relearn probe count")
237 protected int dhcpHostRelearnProbeCount = 3;
238
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000239 private ScheduledExecutorService timerExecutor;
Harshada Chaundkar8c28a992019-05-30 16:27:29 +0000240 private ScheduledExecutorService executorService = null;
Ruchi Sahota66b01292019-03-01 16:56:07 +0000241 protected ExecutorService devEventExecutor;
Charles Chanba06a3c2019-01-23 15:03:17 -0800242 private ExecutorService packetExecutor;
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000243
Yi Tseng127ffe52017-09-12 15:55:17 -0700244 protected DeviceListener deviceListener = new InternalDeviceListener();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700245 private DhcpRelayPacketProcessor dhcpRelayPacketProcessor = new DhcpRelayPacketProcessor();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700246 private ApplicationId appId;
247
Harshada Chaundkar8c28a992019-05-30 16:27:29 +0000248 private static final int POOL_SIZE = 10;
249 private static final int HOST_PROBE_INIT_DELAY = 500;
250
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000251 /**
252 * One second timer.
253 */
254 class Dhcp6Timer implements Runnable {
255 @Override
256 public void run() {
257 v6Handler.timeTick();
258 }
259 };
Kalhee Kimba366062017-11-07 16:32:09 +0000260
Harshada Chaundkar8c28a992019-05-30 16:27:29 +0000261
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700262 @Activate
263 protected void activate(ComponentContext context) {
264 //start the dhcp relay agent
265 appId = coreService.registerApplication(DHCP_RELAY_APP);
266
267 cfgService.addListener(cfgListener);
268 factories.forEach(cfgService::registerConfigFactory);
269 //update the dhcp server configuration.
270 updateConfig();
Yi Tseng51301292017-07-28 13:02:59 -0700271
272 //add the packet processor
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700273 packetService.addProcessor(dhcpRelayPacketProcessor, PacketProcessor.director(0));
Yi Tseng51301292017-07-28 13:02:59 -0700274
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000275 timerExecutor = Executors.newScheduledThreadPool(1,
Charles Chanba06a3c2019-01-23 15:03:17 -0800276 groupedThreads("onos/dhcprelay", "config-reloader-%d", log));
277 timerExecutor.scheduleAtFixedRate(new Dhcp6Timer(), 0, dhcpPollInterval, TimeUnit.SECONDS);
278 packetExecutor = Executors.newFixedThreadPool(DEFAULT_POOL_SIZE,
279 groupedThreads("onos/dhcprelay", "packet-%d", log));
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000280
Ruchi Sahota66b01292019-03-01 16:56:07 +0000281 devEventExecutor = newSingleThreadScheduledExecutor(
282 groupedThreads("onos/dhcprelay-dev-events", "events-%d", log));
283
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700284 modified(context);
285
Yi Tseng06799d62017-09-01 16:02:56 -0700286 // Enable distribute route store
287 compCfgService.preSetProperty(ROUTE_STORE_IMPL,
Kalhee Kimba366062017-11-07 16:32:09 +0000288 "distributed", Boolean.TRUE.toString());
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700289 compCfgService.registerProperties(getClass());
Yi Tseng127ffe52017-09-12 15:55:17 -0700290
Harshada Chaundkar8c28a992019-05-30 16:27:29 +0000291 executorService = Executors.newScheduledThreadPool(POOL_SIZE);
292
Yi Tseng127ffe52017-09-12 15:55:17 -0700293 deviceService.addListener(deviceListener);
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000294
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700295 log.info("DHCP-RELAY Started");
296 }
297
298 @Deactivate
299 protected void deactivate() {
300 cfgService.removeListener(cfgListener);
301 factories.forEach(cfgService::unregisterConfigFactory);
302 packetService.removeProcessor(dhcpRelayPacketProcessor);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700303 cancelArpPackets();
Yi Tsengdfa8ee22017-08-07 12:45:01 -0700304 compCfgService.unregisterProperties(getClass(), false);
Yi Tseng127ffe52017-09-12 15:55:17 -0700305 deviceService.removeListener(deviceListener);
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000306 timerExecutor.shutdown();
Ruchi Sahota66b01292019-03-01 16:56:07 +0000307 devEventExecutor.shutdownNow();
308 devEventExecutor = null;
Charles Chanba06a3c2019-01-23 15:03:17 -0800309 packetExecutor.shutdown();
310 timerExecutor = null;
311 packetExecutor = null;
Harshada Chaundkar8c28a992019-05-30 16:27:29 +0000312 executorService.shutdown();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700313 log.info("DHCP-RELAY Stopped");
314 }
315
316 @Modified
317 protected void modified(ComponentContext context) {
318 Dictionary<?, ?> properties = context.getProperties();
319 Boolean flag;
320
321 flag = Tools.isPropertyEnabled(properties, "arpEnabled");
322 if (flag != null) {
323 arpEnabled = flag;
324 log.info("Address resolution protocol is {}",
Kalhee Kimba366062017-11-07 16:32:09 +0000325 arpEnabled ? "enabled" : "disabled");
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700326 }
327
328 if (arpEnabled) {
329 requestArpPackets();
330 } else {
331 cancelArpPackets();
332 }
Kalhee Kimba366062017-11-07 16:32:09 +0000333
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000334 int intervalVal = Tools.getIntegerProperty(properties, "dhcpPollInterval");
335 log.info("DhcpRelay poll interval new {} old {}", intervalVal, dhcpPollInterval);
336 if (intervalVal != dhcpPollInterval) {
337 timerExecutor.shutdown();
338 dhcpPollInterval = intervalVal;
339 timerExecutor = Executors.newScheduledThreadPool(1,
340 groupedThreads("dhcpRelay",
341 "config-reloader-%d", log));
342 timerExecutor.scheduleAtFixedRate(new Dhcp6Timer(),
343 0,
344 dhcpPollInterval > 1 ? dhcpPollInterval : 1,
345 TimeUnit.SECONDS);
346 v6Handler.setDhcp6PollInterval(dhcpPollInterval);
347 }
348
Kalhee Kimba366062017-11-07 16:32:09 +0000349 flag = Tools.isPropertyEnabled(properties, "dhcpFpmEnabled");
350 if (flag != null) {
351 boolean oldValue = dhcpFpmEnabled;
352 dhcpFpmEnabled = flag;
353 log.info("DhcpRelay FPM is {}",
354 dhcpFpmEnabled ? "enabled" : "disabled");
355
356 if (dhcpFpmEnabled && !oldValue) {
357 log.info("Dhcp Fpm is enabled.");
358 processDhcpFpmRoutes(true);
359 }
360 if (!dhcpFpmEnabled && oldValue) {
361 log.info("Dhcp Fpm is disabled.");
362 processDhcpFpmRoutes(false);
363 }
364 v6Handler.setDhcpFpmEnabled(dhcpFpmEnabled);
365 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700366 }
367
Yi Tseng525ff402017-10-23 19:39:39 -0700368 private static List<TrafficSelector> buildClientDhcpSelectors() {
369 return Streams.concat(Dhcp4HandlerImpl.DHCP_SELECTORS.stream(),
370 Dhcp6HandlerImpl.DHCP_SELECTORS.stream())
371 .collect(Collectors.toList());
372 }
373
Yi Tseng483ac6f2017-08-02 15:03:31 -0700374 /**
375 * Updates DHCP relay app configuration.
376 */
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700377 private void updateConfig() {
Yi Tseng483ac6f2017-08-02 15:03:31 -0700378 DefaultDhcpRelayConfig defaultConfig =
379 cfgService.getConfig(appId, DefaultDhcpRelayConfig.class);
380 IndirectDhcpRelayConfig indirectConfig =
381 cfgService.getConfig(appId, IndirectDhcpRelayConfig.class);
Yi Tseng51f1be92017-09-01 17:24:57 -0700382 IgnoreDhcpConfig ignoreDhcpConfig =
383 cfgService.getConfig(appId, IgnoreDhcpConfig.class);
Harshada Chaundkar8c28a992019-05-30 16:27:29 +0000384 HostAutoRelearnConfig hostAutoRelearnConfig =
385 cfgService.getConfig(appId, HostAutoRelearnConfig.class);
Yi Tseng483ac6f2017-08-02 15:03:31 -0700386
387 if (defaultConfig != null) {
388 updateConfig(defaultConfig);
389 }
Yi Tseng483ac6f2017-08-02 15:03:31 -0700390 if (indirectConfig != null) {
391 updateConfig(indirectConfig);
392 }
Yi Tseng51f1be92017-09-01 17:24:57 -0700393 if (ignoreDhcpConfig != null) {
394 updateConfig(ignoreDhcpConfig);
395 }
Harshada Chaundkar8c28a992019-05-30 16:27:29 +0000396 if (hostAutoRelearnConfig != null) {
397 updateConfig(hostAutoRelearnConfig);
398 }
Yi Tseng483ac6f2017-08-02 15:03:31 -0700399 }
400
401 /**
402 * Updates DHCP relay app configuration with given configuration.
403 *
404 * @param config the configuration ot update
405 */
Yi Tseng51f1be92017-09-01 17:24:57 -0700406 protected void updateConfig(Config config) {
Yi Tseng483ac6f2017-08-02 15:03:31 -0700407 if (config instanceof IndirectDhcpRelayConfig) {
408 IndirectDhcpRelayConfig indirectConfig = (IndirectDhcpRelayConfig) config;
409 v4Handler.setIndirectDhcpServerConfigs(indirectConfig.dhcpServerConfigs());
410 v6Handler.setIndirectDhcpServerConfigs(indirectConfig.dhcpServerConfigs());
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700411 } else if (config instanceof DefaultDhcpRelayConfig) {
412 DefaultDhcpRelayConfig defaultConfig = (DefaultDhcpRelayConfig) config;
413 v4Handler.setDefaultDhcpServerConfigs(defaultConfig.dhcpServerConfigs());
414 v6Handler.setDefaultDhcpServerConfigs(defaultConfig.dhcpServerConfigs());
Yi Tseng483ac6f2017-08-02 15:03:31 -0700415 }
Yi Tseng51f1be92017-09-01 17:24:57 -0700416 if (config instanceof IgnoreDhcpConfig) {
Yi Tseng525ff402017-10-23 19:39:39 -0700417 v4Handler.updateIgnoreVlanConfig((IgnoreDhcpConfig) config);
418 v6Handler.updateIgnoreVlanConfig((IgnoreDhcpConfig) config);
Yi Tseng51f1be92017-09-01 17:24:57 -0700419 }
Harshada Chaundkar8c28a992019-05-30 16:27:29 +0000420 if (config instanceof HostAutoRelearnConfig) {
421 setHostAutoRelearnConfig((HostAutoRelearnConfig) config);
422 }
Yi Tseng51f1be92017-09-01 17:24:57 -0700423 }
424
425 protected void removeConfig(Config config) {
426 if (config instanceof IndirectDhcpRelayConfig) {
427 v4Handler.setIndirectDhcpServerConfigs(Collections.emptyList());
428 v6Handler.setIndirectDhcpServerConfigs(Collections.emptyList());
429 } else if (config instanceof DefaultDhcpRelayConfig) {
430 v4Handler.setDefaultDhcpServerConfigs(Collections.emptyList());
431 v6Handler.setDefaultDhcpServerConfigs(Collections.emptyList());
432 }
433 if (config instanceof IgnoreDhcpConfig) {
Yi Tseng525ff402017-10-23 19:39:39 -0700434 v4Handler.updateIgnoreVlanConfig(null);
435 v6Handler.updateIgnoreVlanConfig(null);
Yi Tseng51f1be92017-09-01 17:24:57 -0700436 }
437 }
438
Kalhee Kimba366062017-11-07 16:32:09 +0000439 private void processDhcpFpmRoutes(Boolean add) {
440 // needs to restore/remove fpm
441 }
442
443 public boolean isDhcpFpmEnabled() {
444 return dhcpFpmEnabled;
445 }
446
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700447 /**
448 * Request ARP packet in via PacketService.
449 */
450 private void requestArpPackets() {
Yi Tseng51f1be92017-09-01 17:24:57 -0700451 packetService.requestPackets(ARP_SELECTOR, PacketPriority.CONTROL, appId);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700452 }
453
454 /**
455 * Cancel requested ARP packets in via packet service.
456 */
457 private void cancelArpPackets() {
Yi Tseng51f1be92017-09-01 17:24:57 -0700458 packetService.cancelPackets(ARP_SELECTOR, PacketPriority.CONTROL, appId);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700459 }
460
461 @Override
462 public Optional<DhcpRecord> getDhcpRecord(HostId hostId) {
463 return dhcpRelayStore.getDhcpRecord(hostId);
464 }
465
466 @Override
467 public Collection<DhcpRecord> getDhcpRecords() {
468 return dhcpRelayStore.getDhcpRecords();
469 }
Harshada Chaundkar8c28a992019-05-30 16:27:29 +0000470
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000471 @Override
472 public void updateDhcpRecord(HostId hostId, DhcpRecord dhcpRecord) {
473 dhcpRelayStore.updateDhcpRecord(hostId, dhcpRecord);
474 }
Harshada Chaundkar8c28a992019-05-30 16:27:29 +0000475
Yi Tseng13a41a12017-07-26 13:45:01 -0700476 @Override
477 public Optional<MacAddress> getDhcpServerMacAddress() {
Yi Tseng4f2a0462017-08-31 11:21:00 -0700478 // TODO: depreated it
479 DefaultDhcpRelayConfig config = cfgService.getConfig(appId, DefaultDhcpRelayConfig.class);
480 DhcpServerConfig serverConfig = config.dhcpServerConfigs().get(0);
481 Ip4Address serverip = serverConfig.getDhcpServerIp4().get();
482 return hostService.getHostsByIp(serverip)
483 .stream()
484 .map(Host::mac)
485 .findFirst();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700486 }
487
Yi Tseng919b2df2017-09-07 16:22:51 -0700488 @Override
489 public List<DhcpServerInfo> getDefaultDhcpServerInfoList() {
490 return ImmutableList.<DhcpServerInfo>builder()
491 .addAll(v4Handler.getDefaultDhcpServerInfoList())
492 .addAll(v6Handler.getDefaultDhcpServerInfoList())
493 .build();
494 }
495
496 @Override
497 public List<DhcpServerInfo> getIndirectDhcpServerInfoList() {
498 return ImmutableList.<DhcpServerInfo>builder()
499 .addAll(v4Handler.getIndirectDhcpServerInfoList())
500 .addAll(v6Handler.getIndirectDhcpServerInfoList())
501 .build();
502 }
503
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700504 /**
505 * Gets DHCP data from a packet.
506 *
507 * @param packet the packet
508 * @return the DHCP data; empty if it is not a DHCP packet
509 */
510 private Optional<DHCP> findDhcp(Ethernet packet) {
511 return Stream.of(packet)
512 .filter(Objects::nonNull)
513 .map(Ethernet::getPayload)
514 .filter(p -> p instanceof IPv4)
515 .map(IPacket::getPayload)
516 .filter(Objects::nonNull)
517 .filter(p -> p instanceof UDP)
518 .map(IPacket::getPayload)
519 .filter(Objects::nonNull)
520 .filter(p -> p instanceof DHCP)
521 .map(p -> (DHCP) p)
522 .findFirst();
523 }
524
525 /**
526 * Gets DHCPv6 data from a packet.
527 *
528 * @param packet the packet
529 * @return the DHCPv6 data; empty if it is not a DHCPv6 packet
530 */
531 private Optional<DHCP6> findDhcp6(Ethernet packet) {
532 return Stream.of(packet)
533 .filter(Objects::nonNull)
534 .map(Ethernet::getPayload)
535 .filter(p -> p instanceof IPv6)
536 .map(IPacket::getPayload)
537 .filter(Objects::nonNull)
538 .filter(p -> p instanceof UDP)
539 .map(IPacket::getPayload)
540 .filter(Objects::nonNull)
541 .filter(p -> p instanceof DHCP6)
542 .map(p -> (DHCP6) p)
543 .findFirst();
544 }
545
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700546
547 private class DhcpRelayPacketProcessor implements PacketProcessor {
Harshada Chaundkar8c28a992019-05-30 16:27:29 +0000548
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700549 @Override
550 public void process(PacketContext context) {
Charles Chanba06a3c2019-01-23 15:03:17 -0800551 packetExecutor.execute(() -> processInternal(context));
552 }
553
554 private void processInternal(PacketContext context) {
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700555 // process the packet and get the payload
556 Ethernet packet = context.inPacket().parsed();
557 if (packet == null) {
558 return;
559 }
560
561 findDhcp(packet).ifPresent(dhcpPayload -> {
Yi Tseng51301292017-07-28 13:02:59 -0700562 v4Handler.processDhcpPacket(context, dhcpPayload);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700563 });
564
565 findDhcp6(packet).ifPresent(dhcp6Payload -> {
Yi Tseng51301292017-07-28 13:02:59 -0700566 v6Handler.processDhcpPacket(context, dhcp6Payload);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700567 });
568
569 if (packet.getEtherType() == Ethernet.TYPE_ARP && arpEnabled) {
570 ARP arpPacket = (ARP) packet.getPayload();
571 VlanId vlanId = VlanId.vlanId(packet.getVlanID());
572 Set<Interface> interfaces = interfaceService.
573 getInterfacesByPort(context.inPacket().receivedFrom());
574 //ignore the packets if dhcp server interface is not configured on onos.
575 if (interfaces.isEmpty()) {
576 log.warn("server virtual interface not configured");
577 return;
578 }
579 if ((arpPacket.getOpCode() != ARP.OP_REQUEST)) {
580 // handle request only
581 return;
582 }
583 MacAddress interfaceMac = interfaces.stream()
584 .filter(iface -> iface.vlan().equals(vlanId))
585 .map(Interface::mac)
586 .filter(mac -> !mac.equals(MacAddress.NONE))
587 .findFirst()
Yi Tseng51301292017-07-28 13:02:59 -0700588 .orElse(MacAddress.ONOS);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700589 if (interfaceMac == null) {
590 // can't find interface mac address
591 return;
592 }
593 processArpPacket(context, packet, interfaceMac);
594 }
595 }
596
597 /**
598 * Processes the ARP Payload and initiates a reply to the client.
599 *
600 * @param context the packet context
601 * @param packet the ethernet payload
602 * @param replyMac mac address to be replied
603 */
604 private void processArpPacket(PacketContext context, Ethernet packet, MacAddress replyMac) {
605 ARP arpPacket = (ARP) packet.getPayload();
Ray Milkeyf0c47612017-09-28 11:29:38 -0700606 ARP arpReply = arpPacket.duplicate();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700607 arpReply.setOpCode(ARP.OP_REPLY);
608
609 arpReply.setTargetProtocolAddress(arpPacket.getSenderProtocolAddress());
610 arpReply.setTargetHardwareAddress(arpPacket.getSenderHardwareAddress());
611 arpReply.setSenderProtocolAddress(arpPacket.getTargetProtocolAddress());
612 arpReply.setSenderHardwareAddress(replyMac.toBytes());
613
614 // Ethernet Frame.
615 Ethernet ethReply = new Ethernet();
616 ethReply.setSourceMACAddress(replyMac.toBytes());
617 ethReply.setDestinationMACAddress(packet.getSourceMAC());
618 ethReply.setEtherType(Ethernet.TYPE_ARP);
619 ethReply.setVlanID(packet.getVlanID());
620 ethReply.setPayload(arpReply);
621
622 ConnectPoint targetPort = context.inPacket().receivedFrom();
623 TrafficTreatment t = DefaultTrafficTreatment.builder()
624 .setOutput(targetPort.port()).build();
625 OutboundPacket o = new DefaultOutboundPacket(
626 targetPort.deviceId(), t, ByteBuffer.wrap(ethReply.serialize()));
627 if (log.isTraceEnabled()) {
628 log.trace("Relaying ARP packet {} to {}", packet, targetPort);
629 }
630 packetService.emit(o);
631 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700632 }
633
634 /**
635 * Listener for network config events.
636 */
637 private class InternalConfigListener implements NetworkConfigListener {
638 @Override
639 public void event(NetworkConfigEvent event) {
Yi Tseng51f1be92017-09-01 17:24:57 -0700640 switch (event.type()) {
641 case CONFIG_UPDATED:
642 case CONFIG_ADDED:
643 event.config().ifPresent(config -> {
644 updateConfig(config);
645 log.info("{} updated", config.getClass().getSimpleName());
646 });
647 break;
648 case CONFIG_REMOVED:
649 event.prevConfig().ifPresent(config -> {
650 removeConfig(config);
651 log.info("{} removed", config.getClass().getSimpleName());
652 });
653 break;
Charles Chane437a802018-04-21 00:44:29 -0700654 case CONFIG_REGISTERED:
655 case CONFIG_UNREGISTERED:
656 break;
Yi Tseng51f1be92017-09-01 17:24:57 -0700657 default:
658 log.warn("Unsupported event type {}", event.type());
659 break;
Yi Tseng483ac6f2017-08-02 15:03:31 -0700660 }
Charles Chan50443e82018-01-03 16:26:32 -0800661 }
Yi Tseng51f1be92017-09-01 17:24:57 -0700662
Charles Chan50443e82018-01-03 16:26:32 -0800663 @Override
664 public boolean isRelevant(NetworkConfigEvent event) {
665 if (event.configClass().equals(DefaultDhcpRelayConfig.class) ||
666 event.configClass().equals(IndirectDhcpRelayConfig.class) ||
Harshada Chaundkar8c28a992019-05-30 16:27:29 +0000667 event.configClass().equals(IgnoreDhcpConfig.class) ||
668 event.configClass().equals(HostAutoRelearnConfig.class)) {
Charles Chan50443e82018-01-03 16:26:32 -0800669 return true;
670 }
671 log.debug("Ignore irrelevant event class {}", event.configClass().getName());
672 return false;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700673 }
674 }
Yi Tseng127ffe52017-09-12 15:55:17 -0700675
676 private class InternalDeviceListener implements DeviceListener {
677
678 @Override
679 public void event(DeviceEvent event) {
Ruchi Sahota66b01292019-03-01 16:56:07 +0000680 if (devEventExecutor != null) {
Harshada Chaundkar8c28a992019-05-30 16:27:29 +0000681 final Device device = event.subject();
Yi Tseng127ffe52017-09-12 15:55:17 -0700682 switch (event.type()) {
683 case DEVICE_ADDED:
Ruchi Sahota66b01292019-03-01 16:56:07 +0000684 devEventExecutor.execute(this::updateIgnoreVlanConfigs);
Yi Tseng127ffe52017-09-12 15:55:17 -0700685 break;
686 case DEVICE_AVAILABILITY_CHANGED:
Ruchi Sahota66b01292019-03-01 16:56:07 +0000687 devEventExecutor.execute(() -> deviceAvailabilityChanged(device));
Ray Milkeyd6a67c32018-02-02 10:30:35 -0800688 break;
Harshada Chaundkar8c28a992019-05-30 16:27:29 +0000689 case PORT_UPDATED:
690 Port port = event.port();
691 devEventExecutor.execute(() -> portUpdatedEventHandler(device, port));
692 break;
Yi Tseng127ffe52017-09-12 15:55:17 -0700693 default:
694 break;
695 }
Ruchi Sahota66b01292019-03-01 16:56:07 +0000696 }
Yi Tseng127ffe52017-09-12 15:55:17 -0700697 }
698
Harshada Chaundkar8c28a992019-05-30 16:27:29 +0000699 private void portUpdatedEventHandler(Device device, Port port) {
700 if (!mastershipService.isLocalMaster(device.id())) {
701 log.warn("This instance is not the master for the device {}", device.id());
702 return;
703 }
704 if (hostAutoRelearnEnabledDevices.contains(device.id()) && port.isEnabled()) {
705 ConnectPoint cp = new ConnectPoint(device.id(), port.number());
706 HostLocation hostLocation = new HostLocation(cp, 0);
707 Set<DhcpRecord> records = dhcpRelayStore.getDhcpRecords()
708 .stream()
709 .filter(i -> i.directlyConnected())
710 .filter(i -> i.locations().contains(hostLocation))
711 .collect(Collectors.toSet());
712
713 for (DhcpRecord i : records) {
714 //found a dhcprecord matching the connect point of the port event
715 log.debug("portUpdatedEventHandler:DHCP record {}, sending msg on CP {} Mac {} Vlan{} DeviceId {}",
716 i, cp, i.macAddress(), i.vlanId(), device.id());
717 if (i.ip4Address().isPresent()) {
718 log.warn("Sending host relearn probe for v4 not supported for Mac {} Vlan{} ip {}",
719 i.macAddress(), i.vlanId(), i.ip4Address());
720 } else if (i.ip6Address().isPresent()) {
721 sendHostRelearnProbe(cp, i.macAddress(), i.vlanId(), i.ip6Address());
722 }
723 }
724 }
725 }
726
Yi Tseng127ffe52017-09-12 15:55:17 -0700727 private void deviceAvailabilityChanged(Device device) {
728 if (deviceService.isAvailable(device.id())) {
Yi Tseng525ff402017-10-23 19:39:39 -0700729 updateIgnoreVlanConfigs();
Saurav Dasb805f1a2017-12-13 16:19:35 -0800730 } else {
731 removeIgnoreVlanState();
Yi Tseng127ffe52017-09-12 15:55:17 -0700732 }
733 }
734
Yi Tseng525ff402017-10-23 19:39:39 -0700735 private void updateIgnoreVlanConfigs() {
Yi Tseng127ffe52017-09-12 15:55:17 -0700736 IgnoreDhcpConfig config = cfgService.getConfig(appId, IgnoreDhcpConfig.class);
Yi Tseng525ff402017-10-23 19:39:39 -0700737 v4Handler.updateIgnoreVlanConfig(config);
738 v6Handler.updateIgnoreVlanConfig(config);
Yi Tseng127ffe52017-09-12 15:55:17 -0700739 }
Saurav Dasb805f1a2017-12-13 16:19:35 -0800740
741 private void removeIgnoreVlanState() {
742 IgnoreDhcpConfig config = cfgService.getConfig(appId, IgnoreDhcpConfig.class);
743 v4Handler.removeIgnoreVlanState(config);
744 v6Handler.removeIgnoreVlanState(config);
745 }
Yi Tseng127ffe52017-09-12 15:55:17 -0700746 }
Kalhee Kimba366062017-11-07 16:32:09 +0000747
Harshada Chaundkar8c28a992019-05-30 16:27:29 +0000748 private void setHostAutoRelearnConfig(HostAutoRelearnConfig config) {
749 hostAutoRelearnEnabledDevices.clear();
750 if (config == null) {
751 return;
752 }
753 hostAutoRelearnEnabledDevices.addAll(config.hostAutoRelearnEnabledDevices());
754 }
755
756 // Packet transmission class.
757 private class PktTransmitter implements Runnable {
758
759 MacAddress mac;
760 VlanId vlanId;
761 Ip6Address ipv6Address;
762 ConnectPoint connectPoint;
763 PktTransmitter(MacAddress mac, VlanId vlanId, Ip6Address ipv6Address, ConnectPoint connectPoint) {
764 this.mac = mac;
765 this.vlanId = vlanId;
766 this.ipv6Address = ipv6Address;
767 this.connectPoint = connectPoint;
768 }
769
770 @Override
771 public void run() {
772 log.debug("Host Relearn probe packet transmission activated for Mac {} Vlan {} Ip {} ConnectPt {}",
773 mac, vlanId, ipv6Address, connectPoint);
774 if (mac == null || vlanId == null || ipv6Address == null || connectPoint == null) {
775 return;
776 }
777
778 Interface senderInterface = interfaceService.getInterfacesByPort(connectPoint)
779 .stream().filter(iface -> Dhcp6HandlerUtil.interfaceContainsVlan(iface, vlanId))
780 .findFirst().orElse(null);
781 if (senderInterface == null) {
782 log.warn("Cannot get sender interface for from packet, abort... vlan {}", vlanId.toString());
piera8dd99f2019-06-07 14:47:37 +0200783 return;
Harshada Chaundkar8c28a992019-05-30 16:27:29 +0000784 }
785 MacAddress senderMacAddress = senderInterface.mac();
786 byte[] senderIpAddress = IPv6.getLinkLocalAddress(senderMacAddress.toBytes());
787 byte[] destIp = IPv6.getSolicitNodeAddress(ipv6Address.toOctets());
788
789 Ethernet ethernet = NeighborSolicitation.buildNdpSolicit(
790 this.ipv6Address,
791 Ip6Address.valueOf(senderIpAddress),
792 Ip6Address.valueOf(destIp), //destip
793 senderMacAddress,
794 this.mac,
795 this.vlanId);
796 sendHostRelearnProbeToConnectPoint(ethernet, connectPoint);
797
798 log.debug("Host Relearn Probe transmission completed.");
799 }
800 }
801
802 //Create packet and schedule transmitter thread.
803 private void sendHostRelearnProbe(ConnectPoint connectPoint, MacAddress mac, VlanId vlanId,
804 Optional<Ip6Address> ipv6Address) {
805 PktTransmitter nsTransmitter = new PktTransmitter(mac, vlanId, ipv6Address.get(), connectPoint);
806 executorService.schedule(nsTransmitter, HOST_PROBE_INIT_DELAY, TimeUnit.MILLISECONDS);
807 }
808
809 // Send Host Relearn Probe packets to ConnectPoint
810 private void sendHostRelearnProbeToConnectPoint(Ethernet nsPacket, ConnectPoint connectPoint) {
811 TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(connectPoint.port()).build();
812 OutboundPacket outboundPacket = new DefaultOutboundPacket(connectPoint.deviceId(),
813 treatment, ByteBuffer.wrap(nsPacket.serialize()));
814 int counter = 0;
815 try {
816 while (counter < dhcpHostRelearnProbeCount) {
817 packetService.emit(outboundPacket);
818 counter++;
819 Thread.sleep(dhcpHostRelearnProbeInterval);
820 }
821 } catch (Exception e) {
822 log.error("Exception while emmiting packet {}", e.getMessage(), e);
823 }
824 }
Kalhee Kimba366062017-11-07 16:32:09 +0000825
826
827 public Optional<FpmRecord> getFpmRecord(IpPrefix prefix) {
828 return dhcpFpmPrefixStore.getFpmRecord(prefix);
829 }
830
831 public Collection<FpmRecord> getFpmRecords() {
832 return dhcpFpmPrefixStore.getFpmRecords();
833 }
834
835 @Override
836 public void addFpmRecord(IpPrefix prefix, FpmRecord fpmRecord) {
837 dhcpFpmPrefixStore.addFpmRecord(prefix, fpmRecord);
838 }
839
840 @Override
841 public Optional<FpmRecord> removeFpmRecord(IpPrefix prefix) {
842 return dhcpFpmPrefixStore.removeFpmRecord(prefix);
843 }
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000844
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700845}