blob: 98f6d3c1ff96c78c8fde4f9dea91710be5f67475 [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 Tseng5479fb82017-09-01 17:24:57 -070020import java.util.Collections;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070021import java.util.Dictionary;
Yi Tseng5479fb82017-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;
26import java.util.stream.Stream;
27
Yi Tseng7a38f9a2017-06-09 14:36:40 -070028import org.apache.felix.scr.annotations.Activate;
29import org.apache.felix.scr.annotations.Component;
30import org.apache.felix.scr.annotations.Deactivate;
31import org.apache.felix.scr.annotations.Modified;
32import org.apache.felix.scr.annotations.Property;
33import org.apache.felix.scr.annotations.Reference;
34import org.apache.felix.scr.annotations.ReferenceCardinality;
35import org.apache.felix.scr.annotations.Service;
36import org.onlab.packet.ARP;
37import org.onlab.packet.DHCP;
38import org.onlab.packet.DHCP6;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070039import org.onlab.packet.Ethernet;
Yi Tseng4ec727d2017-08-31 11:21:00 -070040import org.onlab.packet.IPacket;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070041import org.onlab.packet.IPv4;
Yi Tseng4ec727d2017-08-31 11:21:00 -070042import org.onlab.packet.IPv6;
43import org.onlab.packet.Ip4Address;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070044import org.onlab.packet.MacAddress;
45import org.onlab.packet.TpPort;
46import org.onlab.packet.UDP;
47import org.onlab.packet.VlanId;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070048import org.onlab.util.Tools;
49import org.onosproject.cfg.ComponentConfigService;
50import org.onosproject.core.ApplicationId;
51import org.onosproject.core.CoreService;
Yi Tseng51301292017-07-28 13:02:59 -070052import org.onosproject.dhcprelay.api.DhcpHandler;
53import org.onosproject.dhcprelay.api.DhcpRelayService;
Yi Tsenge72fbb52017-08-02 15:03:31 -070054import org.onosproject.dhcprelay.config.DefaultDhcpRelayConfig;
Yi Tseng4ec727d2017-08-31 11:21:00 -070055import org.onosproject.dhcprelay.config.DhcpServerConfig;
Yi Tseng5479fb82017-09-01 17:24:57 -070056import org.onosproject.dhcprelay.config.IgnoreDhcpConfig;
Yi Tsenge72fbb52017-08-02 15:03:31 -070057import org.onosproject.dhcprelay.config.IndirectDhcpRelayConfig;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070058import org.onosproject.dhcprelay.store.DhcpRecord;
59import org.onosproject.dhcprelay.store.DhcpRelayStore;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070060import org.onosproject.net.ConnectPoint;
Yi Tseng4ec727d2017-08-31 11:21:00 -070061import org.onosproject.net.DeviceId;
62import org.onosproject.net.Host;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070063import org.onosproject.net.HostId;
Yi Tseng4ec727d2017-08-31 11:21:00 -070064import org.onosproject.net.config.Config;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070065import org.onosproject.net.config.ConfigFactory;
66import org.onosproject.net.config.NetworkConfigEvent;
67import org.onosproject.net.config.NetworkConfigListener;
68import org.onosproject.net.config.NetworkConfigRegistry;
69import org.onosproject.net.flow.DefaultTrafficSelector;
70import org.onosproject.net.flow.DefaultTrafficTreatment;
71import org.onosproject.net.flow.TrafficSelector;
72import org.onosproject.net.flow.TrafficTreatment;
Yi Tseng4ec727d2017-08-31 11:21:00 -070073import org.onosproject.net.flow.criteria.Criterion;
74import org.onosproject.net.flow.criteria.UdpPortCriterion;
75import org.onosproject.net.flowobjective.DefaultForwardingObjective;
76import org.onosproject.net.flowobjective.FlowObjectiveService;
77import org.onosproject.net.flowobjective.ForwardingObjective;
78import org.onosproject.net.flowobjective.Objective;
79import org.onosproject.net.flowobjective.ObjectiveContext;
80import org.onosproject.net.flowobjective.ObjectiveError;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070081import org.onosproject.net.host.HostService;
Yi Tseng4ec727d2017-08-31 11:21:00 -070082import org.onosproject.net.intf.Interface;
83import org.onosproject.net.intf.InterfaceService;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070084import org.onosproject.net.packet.DefaultOutboundPacket;
85import org.onosproject.net.packet.OutboundPacket;
86import org.onosproject.net.packet.PacketContext;
87import org.onosproject.net.packet.PacketPriority;
88import org.onosproject.net.packet.PacketProcessor;
89import org.onosproject.net.packet.PacketService;
90import org.onosproject.net.provider.ProviderId;
91import org.osgi.service.component.ComponentContext;
92import org.slf4j.Logger;
93import org.slf4j.LoggerFactory;
94
Yi Tseng4ec727d2017-08-31 11:21:00 -070095import com.google.common.collect.HashMultimap;
96import com.google.common.collect.ImmutableList;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070097import com.google.common.collect.ImmutableSet;
Yi Tseng4ec727d2017-08-31 11:21:00 -070098import com.google.common.collect.Multimap;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070099
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700100import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
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 Tsenge72fbb52017-08-02 15:03:31 -0700107 public static final String DHCP_RELAY_APP = "org.onosproject.dhcprelay";
Yi Tseng51301292017-07-28 13:02:59 -0700108 public static final ProviderId PROVIDER_ID = new ProviderId("host", DHCP_RELAY_APP);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700109 public static final String HOST_LOCATION_PROVIDER =
110 "org.onosproject.provider.host.impl.HostLocationProvider";
Yi Tseng325af8c2017-09-01 16:02:56 -0700111 public static final String ROUTE_STORE_IMPL =
112 "org.onosproject.routeservice.store.RouteStoreImpl";
Yi Tseng5479fb82017-09-01 17:24:57 -0700113 private static final TrafficSelector DHCP_SERVER_SELECTOR = DefaultTrafficSelector.builder()
114 .matchEthType(Ethernet.TYPE_IPV4)
115 .matchIPProtocol(IPv4.PROTOCOL_UDP)
116 .matchUdpDst(TpPort.tpPort(UDP.DHCP_SERVER_PORT))
117 .build();
118 private static final TrafficSelector DHCP_CLIENT_SELECTOR = DefaultTrafficSelector.builder()
119 .matchEthType(Ethernet.TYPE_IPV4)
120 .matchIPProtocol(IPv4.PROTOCOL_UDP)
121 .matchUdpDst(TpPort.tpPort(UDP.DHCP_CLIENT_PORT))
122 .build();
123 private static final TrafficSelector DHCP6_SERVER_SELECTOR = DefaultTrafficSelector.builder()
124 .matchEthType(Ethernet.TYPE_IPV6)
125 .matchIPProtocol(IPv4.PROTOCOL_UDP)
126 .matchUdpDst(TpPort.tpPort(UDP.DHCP_V6_SERVER_PORT))
127 .build();
128 private static final TrafficSelector DHCP6_CLIENT_SELECTOR = DefaultTrafficSelector.builder()
129 .matchEthType(Ethernet.TYPE_IPV6)
130 .matchIPProtocol(IPv4.PROTOCOL_UDP)
131 .matchUdpDst(TpPort.tpPort(UDP.DHCP_V6_CLIENT_PORT))
132 .build();
133 static final List<TrafficSelector> DHCP_SELECTORS = ImmutableList.of(
134 DHCP_SERVER_SELECTOR,
135 DHCP_CLIENT_SELECTOR,
136 DHCP6_SERVER_SELECTOR,
137 DHCP6_CLIENT_SELECTOR
138 );
139 private static final TrafficSelector ARP_SELECTOR = DefaultTrafficSelector.builder()
140 .matchEthType(Ethernet.TYPE_ARP)
141 .build();
142 private static final int IGNORE_CONTROL_PRIORITY = PacketPriority.CONTROL.priorityValue() + 1000;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700143 private final Logger log = LoggerFactory.getLogger(getClass());
144 private final InternalConfigListener cfgListener = new InternalConfigListener();
145
146 private final Set<ConfigFactory> factories = ImmutableSet.of(
Yi Tsenge72fbb52017-08-02 15:03:31 -0700147 new ConfigFactory<ApplicationId, DefaultDhcpRelayConfig>(APP_SUBJECT_FACTORY,
148 DefaultDhcpRelayConfig.class,
149 DefaultDhcpRelayConfig.KEY,
150 true) {
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700151 @Override
Yi Tsenge72fbb52017-08-02 15:03:31 -0700152 public DefaultDhcpRelayConfig createConfig() {
153 return new DefaultDhcpRelayConfig();
154 }
155 },
156 new ConfigFactory<ApplicationId, IndirectDhcpRelayConfig>(APP_SUBJECT_FACTORY,
157 IndirectDhcpRelayConfig.class,
158 IndirectDhcpRelayConfig.KEY,
159 true) {
160 @Override
161 public IndirectDhcpRelayConfig createConfig() {
162 return new IndirectDhcpRelayConfig();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700163 }
Yi Tseng5479fb82017-09-01 17:24:57 -0700164 },
165 new ConfigFactory<ApplicationId, IgnoreDhcpConfig>(APP_SUBJECT_FACTORY,
166 IgnoreDhcpConfig.class,
167 IgnoreDhcpConfig.KEY,
168 true) {
169 @Override
170 public IgnoreDhcpConfig createConfig() {
171 return new IgnoreDhcpConfig();
172 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700173 }
174 );
175
176 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
177 protected NetworkConfigRegistry cfgService;
178
179 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
180 protected CoreService coreService;
181
182 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
183 protected PacketService packetService;
184
185 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
186 protected HostService hostService;
187
188 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700189 protected InterfaceService interfaceService;
190
191 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
192 protected DhcpRelayStore dhcpRelayStore;
193
194 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
195 protected ComponentConfigService compCfgService;
196
Yi Tseng5479fb82017-09-01 17:24:57 -0700197 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
198 protected FlowObjectiveService flowObjectiveService;
199
Yi Tseng51301292017-07-28 13:02:59 -0700200 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY,
201 target = "(version=4)")
202 protected DhcpHandler v4Handler;
203
204 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY,
205 target = "(version=6)")
206 protected DhcpHandler v6Handler;
207
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700208 @Property(name = "arpEnabled", boolValue = true,
Yi Tseng51301292017-07-28 13:02:59 -0700209 label = "Enable Address resolution protocol")
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700210 protected boolean arpEnabled = true;
211
Yi Tseng5479fb82017-09-01 17:24:57 -0700212 protected Multimap<DeviceId, VlanId> ignoredVlans = HashMultimap.create();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700213 private DhcpRelayPacketProcessor dhcpRelayPacketProcessor = new DhcpRelayPacketProcessor();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700214 private ApplicationId appId;
215
216 @Activate
217 protected void activate(ComponentContext context) {
218 //start the dhcp relay agent
219 appId = coreService.registerApplication(DHCP_RELAY_APP);
220
221 cfgService.addListener(cfgListener);
222 factories.forEach(cfgService::registerConfigFactory);
223 //update the dhcp server configuration.
224 updateConfig();
Yi Tseng51301292017-07-28 13:02:59 -0700225
226 //add the packet processor
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700227 packetService.addProcessor(dhcpRelayPacketProcessor, PacketProcessor.director(0));
Yi Tseng51301292017-07-28 13:02:59 -0700228
229 // listen host event for dhcp server or the gateway
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700230 requestDhcpPackets();
231 modified(context);
232
233 // disable dhcp from host location provider
234 compCfgService.preSetProperty(HOST_LOCATION_PROVIDER,
235 "useDhcp", Boolean.FALSE.toString());
Yi Tseng325af8c2017-09-01 16:02:56 -0700236 // Enable distribute route store
237 compCfgService.preSetProperty(ROUTE_STORE_IMPL,
238 "distributed", Boolean.TRUE.toString());
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700239 compCfgService.registerProperties(getClass());
240 log.info("DHCP-RELAY Started");
241 }
242
243 @Deactivate
244 protected void deactivate() {
245 cfgService.removeListener(cfgListener);
246 factories.forEach(cfgService::unregisterConfigFactory);
247 packetService.removeProcessor(dhcpRelayPacketProcessor);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700248 cancelDhcpPackets();
249 cancelArpPackets();
Yi Tseng51301292017-07-28 13:02:59 -0700250
Yi Tsengdfa8ee22017-08-07 12:45:01 -0700251 compCfgService.unregisterProperties(getClass(), false);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700252 log.info("DHCP-RELAY Stopped");
253 }
254
255 @Modified
256 protected void modified(ComponentContext context) {
257 Dictionary<?, ?> properties = context.getProperties();
258 Boolean flag;
259
260 flag = Tools.isPropertyEnabled(properties, "arpEnabled");
261 if (flag != null) {
262 arpEnabled = flag;
263 log.info("Address resolution protocol is {}",
264 arpEnabled ? "enabled" : "disabled");
265 }
266
267 if (arpEnabled) {
268 requestArpPackets();
269 } else {
270 cancelArpPackets();
271 }
272 }
273
Yi Tsenge72fbb52017-08-02 15:03:31 -0700274 /**
275 * Updates DHCP relay app configuration.
276 */
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700277 private void updateConfig() {
Yi Tsenge72fbb52017-08-02 15:03:31 -0700278 DefaultDhcpRelayConfig defaultConfig =
279 cfgService.getConfig(appId, DefaultDhcpRelayConfig.class);
280 IndirectDhcpRelayConfig indirectConfig =
281 cfgService.getConfig(appId, IndirectDhcpRelayConfig.class);
Yi Tseng5479fb82017-09-01 17:24:57 -0700282 IgnoreDhcpConfig ignoreDhcpConfig =
283 cfgService.getConfig(appId, IgnoreDhcpConfig.class);
Yi Tsenge72fbb52017-08-02 15:03:31 -0700284
285 if (defaultConfig != null) {
286 updateConfig(defaultConfig);
287 }
Yi Tsenge72fbb52017-08-02 15:03:31 -0700288 if (indirectConfig != null) {
289 updateConfig(indirectConfig);
290 }
Yi Tseng5479fb82017-09-01 17:24:57 -0700291 if (ignoreDhcpConfig != null) {
292 updateConfig(ignoreDhcpConfig);
293 }
Yi Tsenge72fbb52017-08-02 15:03:31 -0700294 }
295
296 /**
297 * Updates DHCP relay app configuration with given configuration.
298 *
299 * @param config the configuration ot update
300 */
Yi Tseng5479fb82017-09-01 17:24:57 -0700301 protected void updateConfig(Config config) {
Yi Tsenge72fbb52017-08-02 15:03:31 -0700302 if (config instanceof IndirectDhcpRelayConfig) {
303 IndirectDhcpRelayConfig indirectConfig = (IndirectDhcpRelayConfig) config;
304 v4Handler.setIndirectDhcpServerConfigs(indirectConfig.dhcpServerConfigs());
305 v6Handler.setIndirectDhcpServerConfigs(indirectConfig.dhcpServerConfigs());
Yi Tseng4fa05832017-08-17 13:08:31 -0700306 } else if (config instanceof DefaultDhcpRelayConfig) {
307 DefaultDhcpRelayConfig defaultConfig = (DefaultDhcpRelayConfig) config;
308 v4Handler.setDefaultDhcpServerConfigs(defaultConfig.dhcpServerConfigs());
309 v6Handler.setDefaultDhcpServerConfigs(defaultConfig.dhcpServerConfigs());
Yi Tsenge72fbb52017-08-02 15:03:31 -0700310 }
Yi Tseng5479fb82017-09-01 17:24:57 -0700311 if (config instanceof IgnoreDhcpConfig) {
312 addIgnoreVlanRules((IgnoreDhcpConfig) config);
313 }
314 }
315
316 protected void removeConfig(Config config) {
317 if (config instanceof IndirectDhcpRelayConfig) {
318 v4Handler.setIndirectDhcpServerConfigs(Collections.emptyList());
319 v6Handler.setIndirectDhcpServerConfigs(Collections.emptyList());
320 } else if (config instanceof DefaultDhcpRelayConfig) {
321 v4Handler.setDefaultDhcpServerConfigs(Collections.emptyList());
322 v6Handler.setDefaultDhcpServerConfigs(Collections.emptyList());
323 }
324 if (config instanceof IgnoreDhcpConfig) {
325 ignoredVlans.forEach(this::removeIgnoreVlanRule);
326 ignoredVlans.clear();
327 }
328 }
329
330 private void addIgnoreVlanRules(IgnoreDhcpConfig config) {
331 config.ignoredVlans().forEach((deviceId, vlanId) -> {
332 if (ignoredVlans.get(deviceId).contains(vlanId)) {
333 // don't need to process if it already ignored
334 return;
335 }
336 installIgnoreVlanRule(deviceId, vlanId);
337 ignoredVlans.put(deviceId, vlanId);
338 });
339
340 Multimap<DeviceId, VlanId> removedVlans = HashMultimap.create();
341 ignoredVlans.forEach((deviceId, vlanId) -> {
342 if (!config.ignoredVlans().get(deviceId).contains(vlanId)) {
343 // not contains in new config, remove it
344 removeIgnoreVlanRule(deviceId, vlanId);
345 removedVlans.put(deviceId, vlanId);
346
347 }
348 });
349 removedVlans.forEach(ignoredVlans::remove);
350 }
351
352 private void installIgnoreVlanRule(DeviceId deviceId, VlanId vlanId) {
353 TrafficTreatment dropTreatment = DefaultTrafficTreatment.emptyTreatment();
354 dropTreatment.clearedDeferred();
355 DHCP_SELECTORS.forEach(trafficSelector -> {
356 UdpPortCriterion udpDst = (UdpPortCriterion) trafficSelector.getCriterion(Criterion.Type.UDP_DST);
357 TrafficSelector selector = DefaultTrafficSelector.builder(trafficSelector)
358 .matchVlanId(vlanId)
359 .build();
360
361 ForwardingObjective fwd = DefaultForwardingObjective.builder()
362 .withFlag(ForwardingObjective.Flag.VERSATILE)
363 .withSelector(selector)
364 .withPriority(IGNORE_CONTROL_PRIORITY)
365 .withTreatment(dropTreatment)
366 .fromApp(appId)
367 .add(new ObjectiveContext() {
368 @Override
369 public void onSuccess(Objective objective) {
370 log.info("Vlan id {} from device {} ignored (UDP port {})",
371 vlanId, deviceId, udpDst.udpPort().toInt());
372 }
373
374 @Override
375 public void onError(Objective objective, ObjectiveError error) {
376 log.warn("Can't ignore vlan id {} from device {} due to {}",
377 vlanId, deviceId, error);
378 }
379 });
380 flowObjectiveService.apply(deviceId, fwd);
381 });
382 }
383
384 private void removeIgnoreVlanRule(DeviceId deviceId, VlanId vlanId) {
385 TrafficTreatment dropTreatment = DefaultTrafficTreatment.emptyTreatment();
386 dropTreatment.clearedDeferred();
387 DHCP_SELECTORS.forEach(trafficSelector -> {
388 UdpPortCriterion udpDst = (UdpPortCriterion) trafficSelector.getCriterion(Criterion.Type.UDP_DST);
389 TrafficSelector selector = DefaultTrafficSelector.builder(trafficSelector)
390 .matchVlanId(vlanId)
391 .build();
392
393 ForwardingObjective fwd = DefaultForwardingObjective.builder()
394 .withFlag(ForwardingObjective.Flag.VERSATILE)
395 .withSelector(selector)
396 .withPriority(IGNORE_CONTROL_PRIORITY)
397 .withTreatment(dropTreatment)
398 .fromApp(appId)
399 .remove(new ObjectiveContext() {
400 @Override
401 public void onSuccess(Objective objective) {
402 log.info("Vlan id {} from device {} ignore rule removed (UDP port {})",
403 vlanId, deviceId, udpDst.udpPort().toInt());
404 }
405
406 @Override
407 public void onError(Objective objective, ObjectiveError error) {
408 log.warn("Can't remove ignore rule of vlan id {} from device {} due to {}",
409 vlanId, deviceId, error);
410 }
411 });
412 flowObjectiveService.apply(deviceId, fwd);
413 });
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700414 }
415
416 /**
417 * Request DHCP packet in via PacketService.
418 */
419 private void requestDhcpPackets() {
Yi Tseng5479fb82017-09-01 17:24:57 -0700420 DHCP_SELECTORS.forEach(trafficSelector -> {
421 packetService.requestPackets(trafficSelector, PacketPriority.CONTROL, appId);
422 });
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700423 }
424
425 /**
426 * Cancel requested DHCP packets in via packet service.
427 */
428 private void cancelDhcpPackets() {
Yi Tseng5479fb82017-09-01 17:24:57 -0700429 DHCP_SELECTORS.forEach(trafficSelector -> {
430 packetService.cancelPackets(trafficSelector, PacketPriority.CONTROL, appId);
431 });
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700432 }
433
434 /**
435 * Request ARP packet in via PacketService.
436 */
437 private void requestArpPackets() {
Yi Tseng5479fb82017-09-01 17:24:57 -0700438 packetService.requestPackets(ARP_SELECTOR, PacketPriority.CONTROL, appId);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700439 }
440
441 /**
442 * Cancel requested ARP packets in via packet service.
443 */
444 private void cancelArpPackets() {
Yi Tseng5479fb82017-09-01 17:24:57 -0700445 packetService.cancelPackets(ARP_SELECTOR, PacketPriority.CONTROL, appId);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700446 }
447
448 @Override
449 public Optional<DhcpRecord> getDhcpRecord(HostId hostId) {
450 return dhcpRelayStore.getDhcpRecord(hostId);
451 }
452
453 @Override
454 public Collection<DhcpRecord> getDhcpRecords() {
455 return dhcpRelayStore.getDhcpRecords();
456 }
457
Yi Tseng13a41a12017-07-26 13:45:01 -0700458 @Override
459 public Optional<MacAddress> getDhcpServerMacAddress() {
Yi Tseng4ec727d2017-08-31 11:21:00 -0700460 // TODO: depreated it
461 DefaultDhcpRelayConfig config = cfgService.getConfig(appId, DefaultDhcpRelayConfig.class);
462 DhcpServerConfig serverConfig = config.dhcpServerConfigs().get(0);
463 Ip4Address serverip = serverConfig.getDhcpServerIp4().get();
464 return hostService.getHostsByIp(serverip)
465 .stream()
466 .map(Host::mac)
467 .findFirst();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700468 }
469
470 /**
471 * Gets DHCP data from a packet.
472 *
473 * @param packet the packet
474 * @return the DHCP data; empty if it is not a DHCP packet
475 */
476 private Optional<DHCP> findDhcp(Ethernet packet) {
477 return Stream.of(packet)
478 .filter(Objects::nonNull)
479 .map(Ethernet::getPayload)
480 .filter(p -> p instanceof IPv4)
481 .map(IPacket::getPayload)
482 .filter(Objects::nonNull)
483 .filter(p -> p instanceof UDP)
484 .map(IPacket::getPayload)
485 .filter(Objects::nonNull)
486 .filter(p -> p instanceof DHCP)
487 .map(p -> (DHCP) p)
488 .findFirst();
489 }
490
491 /**
492 * Gets DHCPv6 data from a packet.
493 *
494 * @param packet the packet
495 * @return the DHCPv6 data; empty if it is not a DHCPv6 packet
496 */
497 private Optional<DHCP6> findDhcp6(Ethernet packet) {
498 return Stream.of(packet)
499 .filter(Objects::nonNull)
500 .map(Ethernet::getPayload)
501 .filter(p -> p instanceof IPv6)
502 .map(IPacket::getPayload)
503 .filter(Objects::nonNull)
504 .filter(p -> p instanceof UDP)
505 .map(IPacket::getPayload)
506 .filter(Objects::nonNull)
507 .filter(p -> p instanceof DHCP6)
508 .map(p -> (DHCP6) p)
509 .findFirst();
510 }
511
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700512
513 private class DhcpRelayPacketProcessor implements PacketProcessor {
514
515 @Override
516 public void process(PacketContext context) {
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700517 // process the packet and get the payload
518 Ethernet packet = context.inPacket().parsed();
519 if (packet == null) {
520 return;
521 }
522
523 findDhcp(packet).ifPresent(dhcpPayload -> {
Yi Tseng51301292017-07-28 13:02:59 -0700524 v4Handler.processDhcpPacket(context, dhcpPayload);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700525 });
526
527 findDhcp6(packet).ifPresent(dhcp6Payload -> {
Yi Tseng51301292017-07-28 13:02:59 -0700528 v6Handler.processDhcpPacket(context, dhcp6Payload);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700529 });
530
531 if (packet.getEtherType() == Ethernet.TYPE_ARP && arpEnabled) {
532 ARP arpPacket = (ARP) packet.getPayload();
533 VlanId vlanId = VlanId.vlanId(packet.getVlanID());
534 Set<Interface> interfaces = interfaceService.
535 getInterfacesByPort(context.inPacket().receivedFrom());
536 //ignore the packets if dhcp server interface is not configured on onos.
537 if (interfaces.isEmpty()) {
538 log.warn("server virtual interface not configured");
539 return;
540 }
541 if ((arpPacket.getOpCode() != ARP.OP_REQUEST)) {
542 // handle request only
543 return;
544 }
545 MacAddress interfaceMac = interfaces.stream()
546 .filter(iface -> iface.vlan().equals(vlanId))
547 .map(Interface::mac)
548 .filter(mac -> !mac.equals(MacAddress.NONE))
549 .findFirst()
Yi Tseng51301292017-07-28 13:02:59 -0700550 .orElse(MacAddress.ONOS);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700551 if (interfaceMac == null) {
552 // can't find interface mac address
553 return;
554 }
555 processArpPacket(context, packet, interfaceMac);
556 }
557 }
558
559 /**
560 * Processes the ARP Payload and initiates a reply to the client.
561 *
562 * @param context the packet context
563 * @param packet the ethernet payload
564 * @param replyMac mac address to be replied
565 */
566 private void processArpPacket(PacketContext context, Ethernet packet, MacAddress replyMac) {
567 ARP arpPacket = (ARP) packet.getPayload();
568 ARP arpReply = (ARP) arpPacket.clone();
569 arpReply.setOpCode(ARP.OP_REPLY);
570
571 arpReply.setTargetProtocolAddress(arpPacket.getSenderProtocolAddress());
572 arpReply.setTargetHardwareAddress(arpPacket.getSenderHardwareAddress());
573 arpReply.setSenderProtocolAddress(arpPacket.getTargetProtocolAddress());
574 arpReply.setSenderHardwareAddress(replyMac.toBytes());
575
576 // Ethernet Frame.
577 Ethernet ethReply = new Ethernet();
578 ethReply.setSourceMACAddress(replyMac.toBytes());
579 ethReply.setDestinationMACAddress(packet.getSourceMAC());
580 ethReply.setEtherType(Ethernet.TYPE_ARP);
581 ethReply.setVlanID(packet.getVlanID());
582 ethReply.setPayload(arpReply);
583
584 ConnectPoint targetPort = context.inPacket().receivedFrom();
585 TrafficTreatment t = DefaultTrafficTreatment.builder()
586 .setOutput(targetPort.port()).build();
587 OutboundPacket o = new DefaultOutboundPacket(
588 targetPort.deviceId(), t, ByteBuffer.wrap(ethReply.serialize()));
589 if (log.isTraceEnabled()) {
590 log.trace("Relaying ARP packet {} to {}", packet, targetPort);
591 }
592 packetService.emit(o);
593 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700594 }
595
596 /**
597 * Listener for network config events.
598 */
599 private class InternalConfigListener implements NetworkConfigListener {
600 @Override
601 public void event(NetworkConfigEvent event) {
Yi Tseng5479fb82017-09-01 17:24:57 -0700602 switch (event.type()) {
603 case CONFIG_UPDATED:
604 case CONFIG_ADDED:
605 event.config().ifPresent(config -> {
606 updateConfig(config);
607 log.info("{} updated", config.getClass().getSimpleName());
608 });
609 break;
610 case CONFIG_REMOVED:
611 event.prevConfig().ifPresent(config -> {
612 removeConfig(config);
613 log.info("{} removed", config.getClass().getSimpleName());
614 });
615 break;
616 default:
617 log.warn("Unsupported event type {}", event.type());
618 break;
Yi Tsenge72fbb52017-08-02 15:03:31 -0700619 }
Yi Tseng5479fb82017-09-01 17:24:57 -0700620
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700621 }
622 }
623}