blob: 4aedc83c457719568598483b0be6ed6e3cf79e7c [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;
Yi Tseng525ff402017-10-23 19:39:39 -070030import com.google.common.collect.Streams;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070031import org.apache.felix.scr.annotations.Activate;
32import org.apache.felix.scr.annotations.Component;
33import org.apache.felix.scr.annotations.Deactivate;
34import org.apache.felix.scr.annotations.Modified;
35import org.apache.felix.scr.annotations.Property;
36import org.apache.felix.scr.annotations.Reference;
37import org.apache.felix.scr.annotations.ReferenceCardinality;
38import org.apache.felix.scr.annotations.Service;
39import org.onlab.packet.ARP;
40import org.onlab.packet.DHCP;
41import org.onlab.packet.DHCP6;
42import org.onlab.packet.IPacket;
43import org.onlab.packet.IPv6;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070044import org.onlab.packet.Ethernet;
45import org.onlab.packet.IPv4;
Yi Tseng4f2a0462017-08-31 11:21:00 -070046import org.onlab.packet.Ip4Address;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070047import org.onlab.packet.MacAddress;
Kalhee Kimba366062017-11-07 16:32:09 +000048import org.onlab.packet.IpPrefix;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070049import org.onlab.packet.UDP;
50import org.onlab.packet.VlanId;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070051import org.onlab.util.Tools;
52import org.onosproject.cfg.ComponentConfigService;
53import org.onosproject.core.ApplicationId;
54import org.onosproject.core.CoreService;
Yi Tseng51301292017-07-28 13:02:59 -070055import org.onosproject.dhcprelay.api.DhcpHandler;
56import org.onosproject.dhcprelay.api.DhcpRelayService;
Yi Tseng919b2df2017-09-07 16:22:51 -070057import org.onosproject.dhcprelay.api.DhcpServerInfo;
Yi Tseng483ac6f2017-08-02 15:03:31 -070058import org.onosproject.dhcprelay.config.DefaultDhcpRelayConfig;
Yi Tseng51f1be92017-09-01 17:24:57 -070059import org.onosproject.dhcprelay.config.IgnoreDhcpConfig;
Yi Tseng483ac6f2017-08-02 15:03:31 -070060import org.onosproject.dhcprelay.config.IndirectDhcpRelayConfig;
Kalhee Kimba366062017-11-07 16:32:09 +000061import org.onosproject.dhcprelay.config.EnableDhcpFpmConfig;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070062import org.onosproject.dhcprelay.store.DhcpRecord;
63import org.onosproject.dhcprelay.store.DhcpRelayStore;
Kalhee Kimba366062017-11-07 16:32:09 +000064import org.onosproject.dhcprelay.store.DhcpFpmPrefixStore;
65import org.onosproject.routing.fpm.api.FpmRecord;
Yi Tseng127ffe52017-09-12 15:55:17 -070066import org.onosproject.net.Device;
Yi Tseng4f2a0462017-08-31 11:21:00 -070067import org.onosproject.dhcprelay.config.DhcpServerConfig;
68import org.onosproject.net.Host;
Yi Tseng483ac6f2017-08-02 15:03:31 -070069import org.onosproject.net.config.Config;
Yi Tseng127ffe52017-09-12 15:55:17 -070070import org.onosproject.net.device.DeviceEvent;
71import org.onosproject.net.device.DeviceListener;
72import org.onosproject.net.device.DeviceService;
Ray Milkeyfacf2862017-08-03 11:58:29 -070073import org.onosproject.net.intf.Interface;
74import org.onosproject.net.intf.InterfaceService;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070075import org.onosproject.net.ConnectPoint;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070076import org.onosproject.net.HostId;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070077import org.onosproject.net.config.ConfigFactory;
78import org.onosproject.net.config.NetworkConfigEvent;
79import org.onosproject.net.config.NetworkConfigListener;
80import org.onosproject.net.config.NetworkConfigRegistry;
81import org.onosproject.net.flow.DefaultTrafficSelector;
82import org.onosproject.net.flow.DefaultTrafficTreatment;
83import org.onosproject.net.flow.TrafficSelector;
84import org.onosproject.net.flow.TrafficTreatment;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070085import org.onosproject.net.host.HostService;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070086import org.onosproject.net.packet.DefaultOutboundPacket;
87import org.onosproject.net.packet.OutboundPacket;
88import org.onosproject.net.packet.PacketContext;
89import org.onosproject.net.packet.PacketPriority;
90import org.onosproject.net.packet.PacketProcessor;
91import org.onosproject.net.packet.PacketService;
Kalhee Kimba366062017-11-07 16:32:09 +000092
Yi Tseng7a38f9a2017-06-09 14:36:40 -070093import org.osgi.service.component.ComponentContext;
94import org.slf4j.Logger;
95import org.slf4j.LoggerFactory;
96
97import com.google.common.collect.ImmutableSet;
98
Yi Tseng7a38f9a2017-06-09 14:36:40 -070099import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
Yi Tseng127ffe52017-09-12 15:55:17 -0700100
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700101/**
102 * DHCP Relay Agent Application Component.
103 */
104@Component(immediate = true)
105@Service
106public class DhcpRelayManager implements DhcpRelayService {
Yi Tseng483ac6f2017-08-02 15:03:31 -0700107 public static final String DHCP_RELAY_APP = "org.onosproject.dhcprelay";
Yi Tseng06799d62017-09-01 16:02:56 -0700108 public static final String ROUTE_STORE_IMPL =
109 "org.onosproject.routeservice.store.RouteStoreImpl";
Yi Tseng525ff402017-10-23 19:39:39 -0700110
Yi Tseng51f1be92017-09-01 17:24:57 -0700111 private static final TrafficSelector ARP_SELECTOR = DefaultTrafficSelector.builder()
112 .matchEthType(Ethernet.TYPE_ARP)
113 .build();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700114 private final Logger log = LoggerFactory.getLogger(getClass());
115 private final InternalConfigListener cfgListener = new InternalConfigListener();
116
117 private final Set<ConfigFactory> factories = ImmutableSet.of(
Yi Tseng483ac6f2017-08-02 15:03:31 -0700118 new ConfigFactory<ApplicationId, DefaultDhcpRelayConfig>(APP_SUBJECT_FACTORY,
Kalhee Kimba366062017-11-07 16:32:09 +0000119 DefaultDhcpRelayConfig.class,
120 DefaultDhcpRelayConfig.KEY,
121 true) {
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700122 @Override
Yi Tseng483ac6f2017-08-02 15:03:31 -0700123 public DefaultDhcpRelayConfig createConfig() {
124 return new DefaultDhcpRelayConfig();
125 }
126 },
127 new ConfigFactory<ApplicationId, IndirectDhcpRelayConfig>(APP_SUBJECT_FACTORY,
Kalhee Kimba366062017-11-07 16:32:09 +0000128 IndirectDhcpRelayConfig.class,
129 IndirectDhcpRelayConfig.KEY,
130 true) {
Yi Tseng483ac6f2017-08-02 15:03:31 -0700131 @Override
132 public IndirectDhcpRelayConfig createConfig() {
133 return new IndirectDhcpRelayConfig();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700134 }
Yi Tseng51f1be92017-09-01 17:24:57 -0700135 },
136 new ConfigFactory<ApplicationId, IgnoreDhcpConfig>(APP_SUBJECT_FACTORY,
Kalhee Kimba366062017-11-07 16:32:09 +0000137 IgnoreDhcpConfig.class,
138 IgnoreDhcpConfig.KEY,
139 true) {
Yi Tseng51f1be92017-09-01 17:24:57 -0700140 @Override
141 public IgnoreDhcpConfig createConfig() {
142 return new IgnoreDhcpConfig();
143 }
Kalhee Kimba366062017-11-07 16:32:09 +0000144 },
145 new ConfigFactory<ApplicationId, EnableDhcpFpmConfig>(APP_SUBJECT_FACTORY,
146 EnableDhcpFpmConfig.class,
147 EnableDhcpFpmConfig.KEY,
148 false) {
149 @Override
150 public EnableDhcpFpmConfig createConfig() {
151 return new EnableDhcpFpmConfig();
152 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700153 }
154 );
155
156 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
157 protected NetworkConfigRegistry cfgService;
158
159 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
160 protected CoreService coreService;
161
162 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
163 protected PacketService packetService;
164
165 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
166 protected HostService hostService;
167
168 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700169 protected InterfaceService interfaceService;
170
171 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
172 protected DhcpRelayStore dhcpRelayStore;
173
174 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
175 protected ComponentConfigService compCfgService;
176
Yi Tseng51f1be92017-09-01 17:24:57 -0700177 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Yi Tseng127ffe52017-09-12 15:55:17 -0700178 protected DeviceService deviceService;
179
Kalhee Kimba366062017-11-07 16:32:09 +0000180 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
181 protected DhcpFpmPrefixStore dhcpFpmPrefixStore;
182
Yi Tseng51301292017-07-28 13:02:59 -0700183 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY,
Yi Tseng127ffe52017-09-12 15:55:17 -0700184 target = "(version=4)")
Yi Tseng51301292017-07-28 13:02:59 -0700185 protected DhcpHandler v4Handler;
186
187 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY,
Yi Tseng127ffe52017-09-12 15:55:17 -0700188 target = "(version=6)")
Yi Tseng51301292017-07-28 13:02:59 -0700189 protected DhcpHandler v6Handler;
190
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700191 @Property(name = "arpEnabled", boolValue = true,
Yi Tseng127ffe52017-09-12 15:55:17 -0700192 label = "Enable Address resolution protocol")
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700193 protected boolean arpEnabled = true;
194
Kalhee Kimba366062017-11-07 16:32:09 +0000195 @Property(name = "dhcpFpmEnabled", boolValue = false,
196 label = "Enable DhcpRelay Fpm")
197 protected boolean dhcpFpmEnabled = false;
198
Yi Tseng127ffe52017-09-12 15:55:17 -0700199 protected DeviceListener deviceListener = new InternalDeviceListener();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700200 private DhcpRelayPacketProcessor dhcpRelayPacketProcessor = new DhcpRelayPacketProcessor();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700201 private ApplicationId appId;
202
Kalhee Kimba366062017-11-07 16:32:09 +0000203
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700204 @Activate
205 protected void activate(ComponentContext context) {
206 //start the dhcp relay agent
207 appId = coreService.registerApplication(DHCP_RELAY_APP);
208
209 cfgService.addListener(cfgListener);
210 factories.forEach(cfgService::registerConfigFactory);
211 //update the dhcp server configuration.
212 updateConfig();
Yi Tseng51301292017-07-28 13:02:59 -0700213
214 //add the packet processor
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700215 packetService.addProcessor(dhcpRelayPacketProcessor, PacketProcessor.director(0));
Yi Tseng51301292017-07-28 13:02:59 -0700216
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700217 modified(context);
218
Yi Tseng06799d62017-09-01 16:02:56 -0700219 // Enable distribute route store
220 compCfgService.preSetProperty(ROUTE_STORE_IMPL,
Kalhee Kimba366062017-11-07 16:32:09 +0000221 "distributed", Boolean.TRUE.toString());
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700222 compCfgService.registerProperties(getClass());
Yi Tseng127ffe52017-09-12 15:55:17 -0700223
224 deviceService.addListener(deviceListener);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700225 log.info("DHCP-RELAY Started");
226 }
227
228 @Deactivate
229 protected void deactivate() {
230 cfgService.removeListener(cfgListener);
231 factories.forEach(cfgService::unregisterConfigFactory);
232 packetService.removeProcessor(dhcpRelayPacketProcessor);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700233 cancelArpPackets();
Yi Tsengdfa8ee22017-08-07 12:45:01 -0700234 compCfgService.unregisterProperties(getClass(), false);
Yi Tseng127ffe52017-09-12 15:55:17 -0700235 deviceService.removeListener(deviceListener);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700236 log.info("DHCP-RELAY Stopped");
237 }
238
239 @Modified
240 protected void modified(ComponentContext context) {
241 Dictionary<?, ?> properties = context.getProperties();
242 Boolean flag;
243
244 flag = Tools.isPropertyEnabled(properties, "arpEnabled");
245 if (flag != null) {
246 arpEnabled = flag;
247 log.info("Address resolution protocol is {}",
Kalhee Kimba366062017-11-07 16:32:09 +0000248 arpEnabled ? "enabled" : "disabled");
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700249 }
250
251 if (arpEnabled) {
252 requestArpPackets();
253 } else {
254 cancelArpPackets();
255 }
Kalhee Kimba366062017-11-07 16:32:09 +0000256
257 flag = Tools.isPropertyEnabled(properties, "dhcpFpmEnabled");
258 if (flag != null) {
259 boolean oldValue = dhcpFpmEnabled;
260 dhcpFpmEnabled = flag;
261 log.info("DhcpRelay FPM is {}",
262 dhcpFpmEnabled ? "enabled" : "disabled");
263
264 if (dhcpFpmEnabled && !oldValue) {
265 log.info("Dhcp Fpm is enabled.");
266 processDhcpFpmRoutes(true);
267 }
268 if (!dhcpFpmEnabled && oldValue) {
269 log.info("Dhcp Fpm is disabled.");
270 processDhcpFpmRoutes(false);
271 }
272 v6Handler.setDhcpFpmEnabled(dhcpFpmEnabled);
273 }
274
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700275 }
276
Yi Tseng525ff402017-10-23 19:39:39 -0700277 private static List<TrafficSelector> buildClientDhcpSelectors() {
278 return Streams.concat(Dhcp4HandlerImpl.DHCP_SELECTORS.stream(),
279 Dhcp6HandlerImpl.DHCP_SELECTORS.stream())
280 .collect(Collectors.toList());
281 }
282
Yi Tseng483ac6f2017-08-02 15:03:31 -0700283 /**
284 * Updates DHCP relay app configuration.
285 */
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700286 private void updateConfig() {
Yi Tseng483ac6f2017-08-02 15:03:31 -0700287 DefaultDhcpRelayConfig defaultConfig =
288 cfgService.getConfig(appId, DefaultDhcpRelayConfig.class);
289 IndirectDhcpRelayConfig indirectConfig =
290 cfgService.getConfig(appId, IndirectDhcpRelayConfig.class);
Yi Tseng51f1be92017-09-01 17:24:57 -0700291 IgnoreDhcpConfig ignoreDhcpConfig =
292 cfgService.getConfig(appId, IgnoreDhcpConfig.class);
Yi Tseng483ac6f2017-08-02 15:03:31 -0700293
294 if (defaultConfig != null) {
295 updateConfig(defaultConfig);
296 }
Yi Tseng483ac6f2017-08-02 15:03:31 -0700297 if (indirectConfig != null) {
298 updateConfig(indirectConfig);
299 }
Yi Tseng51f1be92017-09-01 17:24:57 -0700300 if (ignoreDhcpConfig != null) {
301 updateConfig(ignoreDhcpConfig);
302 }
Yi Tseng483ac6f2017-08-02 15:03:31 -0700303 }
304
305 /**
306 * Updates DHCP relay app configuration with given configuration.
307 *
308 * @param config the configuration ot update
309 */
Yi Tseng51f1be92017-09-01 17:24:57 -0700310 protected void updateConfig(Config config) {
Yi Tseng483ac6f2017-08-02 15:03:31 -0700311 if (config instanceof IndirectDhcpRelayConfig) {
312 IndirectDhcpRelayConfig indirectConfig = (IndirectDhcpRelayConfig) config;
313 v4Handler.setIndirectDhcpServerConfigs(indirectConfig.dhcpServerConfigs());
314 v6Handler.setIndirectDhcpServerConfigs(indirectConfig.dhcpServerConfigs());
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700315 } else if (config instanceof DefaultDhcpRelayConfig) {
316 DefaultDhcpRelayConfig defaultConfig = (DefaultDhcpRelayConfig) config;
317 v4Handler.setDefaultDhcpServerConfigs(defaultConfig.dhcpServerConfigs());
318 v6Handler.setDefaultDhcpServerConfigs(defaultConfig.dhcpServerConfigs());
Yi Tseng483ac6f2017-08-02 15:03:31 -0700319 }
Yi Tseng51f1be92017-09-01 17:24:57 -0700320 if (config instanceof IgnoreDhcpConfig) {
Yi Tseng525ff402017-10-23 19:39:39 -0700321 v4Handler.updateIgnoreVlanConfig((IgnoreDhcpConfig) config);
322 v6Handler.updateIgnoreVlanConfig((IgnoreDhcpConfig) config);
Yi Tseng51f1be92017-09-01 17:24:57 -0700323 }
324 }
325
326 protected void removeConfig(Config config) {
327 if (config instanceof IndirectDhcpRelayConfig) {
328 v4Handler.setIndirectDhcpServerConfigs(Collections.emptyList());
329 v6Handler.setIndirectDhcpServerConfigs(Collections.emptyList());
330 } else if (config instanceof DefaultDhcpRelayConfig) {
331 v4Handler.setDefaultDhcpServerConfigs(Collections.emptyList());
332 v6Handler.setDefaultDhcpServerConfigs(Collections.emptyList());
333 }
334 if (config instanceof IgnoreDhcpConfig) {
Yi Tseng525ff402017-10-23 19:39:39 -0700335 v4Handler.updateIgnoreVlanConfig(null);
336 v6Handler.updateIgnoreVlanConfig(null);
Yi Tseng51f1be92017-09-01 17:24:57 -0700337 }
338 }
339
Kalhee Kimba366062017-11-07 16:32:09 +0000340 private void processDhcpFpmRoutes(Boolean add) {
341 // needs to restore/remove fpm
342 }
343
344 public boolean isDhcpFpmEnabled() {
345 return dhcpFpmEnabled;
346 }
347
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700348 /**
349 * Request ARP packet in via PacketService.
350 */
351 private void requestArpPackets() {
Yi Tseng51f1be92017-09-01 17:24:57 -0700352 packetService.requestPackets(ARP_SELECTOR, PacketPriority.CONTROL, appId);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700353 }
354
355 /**
356 * Cancel requested ARP packets in via packet service.
357 */
358 private void cancelArpPackets() {
Yi Tseng51f1be92017-09-01 17:24:57 -0700359 packetService.cancelPackets(ARP_SELECTOR, PacketPriority.CONTROL, appId);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700360 }
361
362 @Override
363 public Optional<DhcpRecord> getDhcpRecord(HostId hostId) {
364 return dhcpRelayStore.getDhcpRecord(hostId);
365 }
366
367 @Override
368 public Collection<DhcpRecord> getDhcpRecords() {
369 return dhcpRelayStore.getDhcpRecords();
370 }
371
Yi Tseng13a41a12017-07-26 13:45:01 -0700372 @Override
373 public Optional<MacAddress> getDhcpServerMacAddress() {
Yi Tseng4f2a0462017-08-31 11:21:00 -0700374 // TODO: depreated it
375 DefaultDhcpRelayConfig config = cfgService.getConfig(appId, DefaultDhcpRelayConfig.class);
376 DhcpServerConfig serverConfig = config.dhcpServerConfigs().get(0);
377 Ip4Address serverip = serverConfig.getDhcpServerIp4().get();
378 return hostService.getHostsByIp(serverip)
379 .stream()
380 .map(Host::mac)
381 .findFirst();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700382 }
383
Yi Tseng919b2df2017-09-07 16:22:51 -0700384 @Override
385 public List<DhcpServerInfo> getDefaultDhcpServerInfoList() {
386 return ImmutableList.<DhcpServerInfo>builder()
387 .addAll(v4Handler.getDefaultDhcpServerInfoList())
388 .addAll(v6Handler.getDefaultDhcpServerInfoList())
389 .build();
390 }
391
392 @Override
393 public List<DhcpServerInfo> getIndirectDhcpServerInfoList() {
394 return ImmutableList.<DhcpServerInfo>builder()
395 .addAll(v4Handler.getIndirectDhcpServerInfoList())
396 .addAll(v6Handler.getIndirectDhcpServerInfoList())
397 .build();
398 }
399
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700400 /**
401 * Gets DHCP data from a packet.
402 *
403 * @param packet the packet
404 * @return the DHCP data; empty if it is not a DHCP packet
405 */
406 private Optional<DHCP> findDhcp(Ethernet packet) {
407 return Stream.of(packet)
408 .filter(Objects::nonNull)
409 .map(Ethernet::getPayload)
410 .filter(p -> p instanceof IPv4)
411 .map(IPacket::getPayload)
412 .filter(Objects::nonNull)
413 .filter(p -> p instanceof UDP)
414 .map(IPacket::getPayload)
415 .filter(Objects::nonNull)
416 .filter(p -> p instanceof DHCP)
417 .map(p -> (DHCP) p)
418 .findFirst();
419 }
420
421 /**
422 * Gets DHCPv6 data from a packet.
423 *
424 * @param packet the packet
425 * @return the DHCPv6 data; empty if it is not a DHCPv6 packet
426 */
427 private Optional<DHCP6> findDhcp6(Ethernet packet) {
428 return Stream.of(packet)
429 .filter(Objects::nonNull)
430 .map(Ethernet::getPayload)
431 .filter(p -> p instanceof IPv6)
432 .map(IPacket::getPayload)
433 .filter(Objects::nonNull)
434 .filter(p -> p instanceof UDP)
435 .map(IPacket::getPayload)
436 .filter(Objects::nonNull)
437 .filter(p -> p instanceof DHCP6)
438 .map(p -> (DHCP6) p)
439 .findFirst();
440 }
441
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700442
443 private class DhcpRelayPacketProcessor implements PacketProcessor {
444
445 @Override
446 public void process(PacketContext context) {
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700447 // process the packet and get the payload
448 Ethernet packet = context.inPacket().parsed();
449 if (packet == null) {
450 return;
451 }
452
453 findDhcp(packet).ifPresent(dhcpPayload -> {
Yi Tseng51301292017-07-28 13:02:59 -0700454 v4Handler.processDhcpPacket(context, dhcpPayload);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700455 });
456
457 findDhcp6(packet).ifPresent(dhcp6Payload -> {
Yi Tseng51301292017-07-28 13:02:59 -0700458 v6Handler.processDhcpPacket(context, dhcp6Payload);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700459 });
460
461 if (packet.getEtherType() == Ethernet.TYPE_ARP && arpEnabled) {
462 ARP arpPacket = (ARP) packet.getPayload();
463 VlanId vlanId = VlanId.vlanId(packet.getVlanID());
464 Set<Interface> interfaces = interfaceService.
465 getInterfacesByPort(context.inPacket().receivedFrom());
466 //ignore the packets if dhcp server interface is not configured on onos.
467 if (interfaces.isEmpty()) {
468 log.warn("server virtual interface not configured");
469 return;
470 }
471 if ((arpPacket.getOpCode() != ARP.OP_REQUEST)) {
472 // handle request only
473 return;
474 }
475 MacAddress interfaceMac = interfaces.stream()
476 .filter(iface -> iface.vlan().equals(vlanId))
477 .map(Interface::mac)
478 .filter(mac -> !mac.equals(MacAddress.NONE))
479 .findFirst()
Yi Tseng51301292017-07-28 13:02:59 -0700480 .orElse(MacAddress.ONOS);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700481 if (interfaceMac == null) {
482 // can't find interface mac address
483 return;
484 }
485 processArpPacket(context, packet, interfaceMac);
486 }
487 }
488
489 /**
490 * Processes the ARP Payload and initiates a reply to the client.
491 *
492 * @param context the packet context
493 * @param packet the ethernet payload
494 * @param replyMac mac address to be replied
495 */
496 private void processArpPacket(PacketContext context, Ethernet packet, MacAddress replyMac) {
497 ARP arpPacket = (ARP) packet.getPayload();
Ray Milkeyf0c47612017-09-28 11:29:38 -0700498 ARP arpReply = arpPacket.duplicate();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700499 arpReply.setOpCode(ARP.OP_REPLY);
500
501 arpReply.setTargetProtocolAddress(arpPacket.getSenderProtocolAddress());
502 arpReply.setTargetHardwareAddress(arpPacket.getSenderHardwareAddress());
503 arpReply.setSenderProtocolAddress(arpPacket.getTargetProtocolAddress());
504 arpReply.setSenderHardwareAddress(replyMac.toBytes());
505
506 // Ethernet Frame.
507 Ethernet ethReply = new Ethernet();
508 ethReply.setSourceMACAddress(replyMac.toBytes());
509 ethReply.setDestinationMACAddress(packet.getSourceMAC());
510 ethReply.setEtherType(Ethernet.TYPE_ARP);
511 ethReply.setVlanID(packet.getVlanID());
512 ethReply.setPayload(arpReply);
513
514 ConnectPoint targetPort = context.inPacket().receivedFrom();
515 TrafficTreatment t = DefaultTrafficTreatment.builder()
516 .setOutput(targetPort.port()).build();
517 OutboundPacket o = new DefaultOutboundPacket(
518 targetPort.deviceId(), t, ByteBuffer.wrap(ethReply.serialize()));
519 if (log.isTraceEnabled()) {
520 log.trace("Relaying ARP packet {} to {}", packet, targetPort);
521 }
522 packetService.emit(o);
523 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700524 }
525
526 /**
527 * Listener for network config events.
528 */
529 private class InternalConfigListener implements NetworkConfigListener {
530 @Override
531 public void event(NetworkConfigEvent event) {
Yi Tseng51f1be92017-09-01 17:24:57 -0700532 switch (event.type()) {
533 case CONFIG_UPDATED:
534 case CONFIG_ADDED:
535 event.config().ifPresent(config -> {
536 updateConfig(config);
537 log.info("{} updated", config.getClass().getSimpleName());
538 });
539 break;
540 case CONFIG_REMOVED:
541 event.prevConfig().ifPresent(config -> {
542 removeConfig(config);
543 log.info("{} removed", config.getClass().getSimpleName());
544 });
545 break;
546 default:
547 log.warn("Unsupported event type {}", event.type());
548 break;
Yi Tseng483ac6f2017-08-02 15:03:31 -0700549 }
Yi Tseng51f1be92017-09-01 17:24:57 -0700550
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700551 }
552 }
Yi Tseng127ffe52017-09-12 15:55:17 -0700553
554 private class InternalDeviceListener implements DeviceListener {
555
556 @Override
557 public void event(DeviceEvent event) {
558 Device device = event.subject();
559 switch (event.type()) {
560 case DEVICE_ADDED:
Yi Tseng525ff402017-10-23 19:39:39 -0700561 updateIgnoreVlanConfigs();
Yi Tseng127ffe52017-09-12 15:55:17 -0700562 break;
563 case DEVICE_AVAILABILITY_CHANGED:
564 deviceAvailabilityChanged(device);
Yi Tseng127ffe52017-09-12 15:55:17 -0700565 default:
566 break;
567 }
568 }
569
570 private void deviceAvailabilityChanged(Device device) {
571 if (deviceService.isAvailable(device.id())) {
Yi Tseng525ff402017-10-23 19:39:39 -0700572 updateIgnoreVlanConfigs();
Saurav Dasfa9004b2017-12-13 16:19:35 -0800573 } else {
574 removeIgnoreVlanState();
Yi Tseng127ffe52017-09-12 15:55:17 -0700575 }
576 }
577
Yi Tseng525ff402017-10-23 19:39:39 -0700578 private void updateIgnoreVlanConfigs() {
Yi Tseng127ffe52017-09-12 15:55:17 -0700579 IgnoreDhcpConfig config = cfgService.getConfig(appId, IgnoreDhcpConfig.class);
Yi Tseng525ff402017-10-23 19:39:39 -0700580 v4Handler.updateIgnoreVlanConfig(config);
581 v6Handler.updateIgnoreVlanConfig(config);
Yi Tseng127ffe52017-09-12 15:55:17 -0700582 }
Saurav Dasfa9004b2017-12-13 16:19:35 -0800583
584 private void removeIgnoreVlanState() {
585 IgnoreDhcpConfig config = cfgService.getConfig(appId, IgnoreDhcpConfig.class);
586 v4Handler.removeIgnoreVlanState(config);
587 v6Handler.removeIgnoreVlanState(config);
588 }
Yi Tseng127ffe52017-09-12 15:55:17 -0700589 }
Kalhee Kimba366062017-11-07 16:32:09 +0000590
591
592
593 public Optional<FpmRecord> getFpmRecord(IpPrefix prefix) {
594 return dhcpFpmPrefixStore.getFpmRecord(prefix);
595 }
596
597 public Collection<FpmRecord> getFpmRecords() {
598 return dhcpFpmPrefixStore.getFpmRecords();
599 }
600
601 @Override
602 public void addFpmRecord(IpPrefix prefix, FpmRecord fpmRecord) {
603 dhcpFpmPrefixStore.addFpmRecord(prefix, fpmRecord);
604 }
605
606 @Override
607 public Optional<FpmRecord> removeFpmRecord(IpPrefix prefix) {
608 return dhcpFpmPrefixStore.removeFpmRecord(prefix);
609 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700610}