blob: 1fd3e6490a85b763d8da4665c8f1c73bbc89b5a4 [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;
Yi Tseng76365d82017-09-12 15:55:17 -070026import java.util.concurrent.atomic.AtomicInteger;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070027import java.util.stream.Stream;
28
Yi Tseng7a38f9a2017-06-09 14:36:40 -070029import org.apache.felix.scr.annotations.Activate;
30import org.apache.felix.scr.annotations.Component;
31import org.apache.felix.scr.annotations.Deactivate;
32import org.apache.felix.scr.annotations.Modified;
33import org.apache.felix.scr.annotations.Property;
34import org.apache.felix.scr.annotations.Reference;
35import org.apache.felix.scr.annotations.ReferenceCardinality;
36import org.apache.felix.scr.annotations.Service;
37import org.onlab.packet.ARP;
38import org.onlab.packet.DHCP;
39import org.onlab.packet.DHCP6;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070040import org.onlab.packet.Ethernet;
Yi Tseng4ec727d2017-08-31 11:21:00 -070041import org.onlab.packet.IPacket;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070042import org.onlab.packet.IPv4;
Yi Tseng4ec727d2017-08-31 11:21:00 -070043import org.onlab.packet.IPv6;
44import org.onlab.packet.Ip4Address;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070045import org.onlab.packet.MacAddress;
46import org.onlab.packet.TpPort;
47import org.onlab.packet.UDP;
48import org.onlab.packet.VlanId;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070049import org.onlab.util.Tools;
50import org.onosproject.cfg.ComponentConfigService;
51import org.onosproject.core.ApplicationId;
52import org.onosproject.core.CoreService;
Yi Tseng51301292017-07-28 13:02:59 -070053import org.onosproject.dhcprelay.api.DhcpHandler;
54import org.onosproject.dhcprelay.api.DhcpRelayService;
Yi Tsenge72fbb52017-08-02 15:03:31 -070055import org.onosproject.dhcprelay.config.DefaultDhcpRelayConfig;
Yi Tseng4ec727d2017-08-31 11:21:00 -070056import org.onosproject.dhcprelay.config.DhcpServerConfig;
Yi Tseng5479fb82017-09-01 17:24:57 -070057import org.onosproject.dhcprelay.config.IgnoreDhcpConfig;
Yi Tsenge72fbb52017-08-02 15:03:31 -070058import org.onosproject.dhcprelay.config.IndirectDhcpRelayConfig;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070059import org.onosproject.dhcprelay.store.DhcpRecord;
60import org.onosproject.dhcprelay.store.DhcpRelayStore;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070061import org.onosproject.net.ConnectPoint;
Yi Tseng76365d82017-09-12 15:55:17 -070062import org.onosproject.net.Device;
Yi Tseng4ec727d2017-08-31 11:21:00 -070063import org.onosproject.net.DeviceId;
64import org.onosproject.net.Host;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070065import org.onosproject.net.HostId;
Yi Tseng4ec727d2017-08-31 11:21:00 -070066import org.onosproject.net.config.Config;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070067import org.onosproject.net.config.ConfigFactory;
68import org.onosproject.net.config.NetworkConfigEvent;
69import org.onosproject.net.config.NetworkConfigListener;
70import org.onosproject.net.config.NetworkConfigRegistry;
71import org.onosproject.net.flow.DefaultTrafficSelector;
72import org.onosproject.net.flow.DefaultTrafficTreatment;
73import org.onosproject.net.flow.TrafficSelector;
74import org.onosproject.net.flow.TrafficTreatment;
Yi Tseng76365d82017-09-12 15:55:17 -070075import org.onosproject.net.behaviour.Pipeliner;
76import org.onosproject.net.device.DeviceEvent;
77import org.onosproject.net.device.DeviceListener;
78import org.onosproject.net.device.DeviceService;
Yi Tseng4ec727d2017-08-31 11:21:00 -070079import org.onosproject.net.flow.criteria.Criterion;
80import org.onosproject.net.flow.criteria.UdpPortCriterion;
81import org.onosproject.net.flowobjective.DefaultForwardingObjective;
82import org.onosproject.net.flowobjective.FlowObjectiveService;
83import org.onosproject.net.flowobjective.ForwardingObjective;
84import org.onosproject.net.flowobjective.Objective;
85import org.onosproject.net.flowobjective.ObjectiveContext;
86import org.onosproject.net.flowobjective.ObjectiveError;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070087import org.onosproject.net.host.HostService;
Yi Tseng4ec727d2017-08-31 11:21:00 -070088import org.onosproject.net.intf.Interface;
89import org.onosproject.net.intf.InterfaceService;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070090import org.onosproject.net.packet.DefaultOutboundPacket;
91import org.onosproject.net.packet.OutboundPacket;
92import org.onosproject.net.packet.PacketContext;
93import org.onosproject.net.packet.PacketPriority;
94import org.onosproject.net.packet.PacketProcessor;
95import org.onosproject.net.packet.PacketService;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070096import org.osgi.service.component.ComponentContext;
97import org.slf4j.Logger;
98import org.slf4j.LoggerFactory;
99
Yi Tseng4ec727d2017-08-31 11:21:00 -0700100import com.google.common.collect.HashMultimap;
101import com.google.common.collect.ImmutableList;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700102import com.google.common.collect.ImmutableSet;
Yi Tseng4ec727d2017-08-31 11:21:00 -0700103import com.google.common.collect.Multimap;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700104
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700105import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
Yi Tseng76365d82017-09-12 15:55:17 -0700106import static org.onosproject.net.flowobjective.Objective.Operation.ADD;
107import static org.onosproject.net.flowobjective.Objective.Operation.REMOVE;
108
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700109/**
110 * DHCP Relay Agent Application Component.
111 */
112@Component(immediate = true)
113@Service
114public class DhcpRelayManager implements DhcpRelayService {
Yi Tsenge72fbb52017-08-02 15:03:31 -0700115 public static final String DHCP_RELAY_APP = "org.onosproject.dhcprelay";
Yi Tseng325af8c2017-09-01 16:02:56 -0700116 public static final String ROUTE_STORE_IMPL =
117 "org.onosproject.routeservice.store.RouteStoreImpl";
Yi Tseng5479fb82017-09-01 17:24:57 -0700118 private static final TrafficSelector DHCP_SERVER_SELECTOR = DefaultTrafficSelector.builder()
119 .matchEthType(Ethernet.TYPE_IPV4)
120 .matchIPProtocol(IPv4.PROTOCOL_UDP)
121 .matchUdpDst(TpPort.tpPort(UDP.DHCP_SERVER_PORT))
122 .build();
123 private static final TrafficSelector DHCP_CLIENT_SELECTOR = DefaultTrafficSelector.builder()
124 .matchEthType(Ethernet.TYPE_IPV4)
125 .matchIPProtocol(IPv4.PROTOCOL_UDP)
126 .matchUdpDst(TpPort.tpPort(UDP.DHCP_CLIENT_PORT))
127 .build();
128 private static final TrafficSelector DHCP6_SERVER_SELECTOR = DefaultTrafficSelector.builder()
129 .matchEthType(Ethernet.TYPE_IPV6)
130 .matchIPProtocol(IPv4.PROTOCOL_UDP)
131 .matchUdpDst(TpPort.tpPort(UDP.DHCP_V6_SERVER_PORT))
132 .build();
133 private static final TrafficSelector DHCP6_CLIENT_SELECTOR = DefaultTrafficSelector.builder()
134 .matchEthType(Ethernet.TYPE_IPV6)
135 .matchIPProtocol(IPv4.PROTOCOL_UDP)
136 .matchUdpDst(TpPort.tpPort(UDP.DHCP_V6_CLIENT_PORT))
137 .build();
138 static final List<TrafficSelector> DHCP_SELECTORS = ImmutableList.of(
139 DHCP_SERVER_SELECTOR,
140 DHCP_CLIENT_SELECTOR,
141 DHCP6_SERVER_SELECTOR,
142 DHCP6_CLIENT_SELECTOR
143 );
144 private static final TrafficSelector ARP_SELECTOR = DefaultTrafficSelector.builder()
145 .matchEthType(Ethernet.TYPE_ARP)
146 .build();
147 private static final int IGNORE_CONTROL_PRIORITY = PacketPriority.CONTROL.priorityValue() + 1000;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700148 private final Logger log = LoggerFactory.getLogger(getClass());
149 private final InternalConfigListener cfgListener = new InternalConfigListener();
150
151 private final Set<ConfigFactory> factories = ImmutableSet.of(
Yi Tsenge72fbb52017-08-02 15:03:31 -0700152 new ConfigFactory<ApplicationId, DefaultDhcpRelayConfig>(APP_SUBJECT_FACTORY,
153 DefaultDhcpRelayConfig.class,
154 DefaultDhcpRelayConfig.KEY,
155 true) {
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700156 @Override
Yi Tsenge72fbb52017-08-02 15:03:31 -0700157 public DefaultDhcpRelayConfig createConfig() {
158 return new DefaultDhcpRelayConfig();
159 }
160 },
161 new ConfigFactory<ApplicationId, IndirectDhcpRelayConfig>(APP_SUBJECT_FACTORY,
162 IndirectDhcpRelayConfig.class,
163 IndirectDhcpRelayConfig.KEY,
164 true) {
165 @Override
166 public IndirectDhcpRelayConfig createConfig() {
167 return new IndirectDhcpRelayConfig();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700168 }
Yi Tseng5479fb82017-09-01 17:24:57 -0700169 },
170 new ConfigFactory<ApplicationId, IgnoreDhcpConfig>(APP_SUBJECT_FACTORY,
171 IgnoreDhcpConfig.class,
172 IgnoreDhcpConfig.KEY,
173 true) {
174 @Override
175 public IgnoreDhcpConfig createConfig() {
176 return new IgnoreDhcpConfig();
177 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700178 }
179 );
180
181 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
182 protected NetworkConfigRegistry cfgService;
183
184 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
185 protected CoreService coreService;
186
187 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
188 protected PacketService packetService;
189
190 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
191 protected HostService hostService;
192
193 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700194 protected InterfaceService interfaceService;
195
196 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
197 protected DhcpRelayStore dhcpRelayStore;
198
199 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
200 protected ComponentConfigService compCfgService;
201
Yi Tseng5479fb82017-09-01 17:24:57 -0700202 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
203 protected FlowObjectiveService flowObjectiveService;
204
Yi Tseng76365d82017-09-12 15:55:17 -0700205 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
206 protected DeviceService deviceService;
207
Yi Tseng51301292017-07-28 13:02:59 -0700208 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY,
Yi Tseng76365d82017-09-12 15:55:17 -0700209 target = "(version=4)")
Yi Tseng51301292017-07-28 13:02:59 -0700210 protected DhcpHandler v4Handler;
211
212 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY,
Yi Tseng76365d82017-09-12 15:55:17 -0700213 target = "(version=6)")
Yi Tseng51301292017-07-28 13:02:59 -0700214 protected DhcpHandler v6Handler;
215
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700216 @Property(name = "arpEnabled", boolValue = true,
Yi Tseng76365d82017-09-12 15:55:17 -0700217 label = "Enable Address resolution protocol")
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700218 protected boolean arpEnabled = true;
219
Yi Tseng5479fb82017-09-01 17:24:57 -0700220 protected Multimap<DeviceId, VlanId> ignoredVlans = HashMultimap.create();
Yi Tseng76365d82017-09-12 15:55:17 -0700221 protected DeviceListener deviceListener = new InternalDeviceListener();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700222 private DhcpRelayPacketProcessor dhcpRelayPacketProcessor = new DhcpRelayPacketProcessor();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700223 private ApplicationId appId;
224
225 @Activate
226 protected void activate(ComponentContext context) {
227 //start the dhcp relay agent
228 appId = coreService.registerApplication(DHCP_RELAY_APP);
229
230 cfgService.addListener(cfgListener);
231 factories.forEach(cfgService::registerConfigFactory);
232 //update the dhcp server configuration.
233 updateConfig();
Yi Tseng51301292017-07-28 13:02:59 -0700234
235 //add the packet processor
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700236 packetService.addProcessor(dhcpRelayPacketProcessor, PacketProcessor.director(0));
Yi Tseng51301292017-07-28 13:02:59 -0700237
238 // listen host event for dhcp server or the gateway
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700239 requestDhcpPackets();
240 modified(context);
241
Yi Tseng325af8c2017-09-01 16:02:56 -0700242 // Enable distribute route store
243 compCfgService.preSetProperty(ROUTE_STORE_IMPL,
244 "distributed", Boolean.TRUE.toString());
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700245 compCfgService.registerProperties(getClass());
Yi Tseng76365d82017-09-12 15:55:17 -0700246
247 deviceService.addListener(deviceListener);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700248 log.info("DHCP-RELAY Started");
249 }
250
251 @Deactivate
252 protected void deactivate() {
253 cfgService.removeListener(cfgListener);
254 factories.forEach(cfgService::unregisterConfigFactory);
255 packetService.removeProcessor(dhcpRelayPacketProcessor);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700256 cancelDhcpPackets();
257 cancelArpPackets();
Yi Tsengdfa8ee22017-08-07 12:45:01 -0700258 compCfgService.unregisterProperties(getClass(), false);
Yi Tseng76365d82017-09-12 15:55:17 -0700259 deviceService.removeListener(deviceListener);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700260 log.info("DHCP-RELAY Stopped");
261 }
262
263 @Modified
264 protected void modified(ComponentContext context) {
265 Dictionary<?, ?> properties = context.getProperties();
266 Boolean flag;
267
268 flag = Tools.isPropertyEnabled(properties, "arpEnabled");
269 if (flag != null) {
270 arpEnabled = flag;
271 log.info("Address resolution protocol is {}",
272 arpEnabled ? "enabled" : "disabled");
273 }
274
275 if (arpEnabled) {
276 requestArpPackets();
277 } else {
278 cancelArpPackets();
279 }
280 }
281
Yi Tsenge72fbb52017-08-02 15:03:31 -0700282 /**
283 * Updates DHCP relay app configuration.
284 */
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700285 private void updateConfig() {
Yi Tsenge72fbb52017-08-02 15:03:31 -0700286 DefaultDhcpRelayConfig defaultConfig =
287 cfgService.getConfig(appId, DefaultDhcpRelayConfig.class);
288 IndirectDhcpRelayConfig indirectConfig =
289 cfgService.getConfig(appId, IndirectDhcpRelayConfig.class);
Yi Tseng5479fb82017-09-01 17:24:57 -0700290 IgnoreDhcpConfig ignoreDhcpConfig =
291 cfgService.getConfig(appId, IgnoreDhcpConfig.class);
Yi Tsenge72fbb52017-08-02 15:03:31 -0700292
293 if (defaultConfig != null) {
294 updateConfig(defaultConfig);
295 }
Yi Tsenge72fbb52017-08-02 15:03:31 -0700296 if (indirectConfig != null) {
297 updateConfig(indirectConfig);
298 }
Yi Tseng5479fb82017-09-01 17:24:57 -0700299 if (ignoreDhcpConfig != null) {
300 updateConfig(ignoreDhcpConfig);
301 }
Yi Tsenge72fbb52017-08-02 15:03:31 -0700302 }
303
304 /**
305 * Updates DHCP relay app configuration with given configuration.
306 *
307 * @param config the configuration ot update
308 */
Yi Tseng5479fb82017-09-01 17:24:57 -0700309 protected void updateConfig(Config config) {
Yi Tsenge72fbb52017-08-02 15:03:31 -0700310 if (config instanceof IndirectDhcpRelayConfig) {
311 IndirectDhcpRelayConfig indirectConfig = (IndirectDhcpRelayConfig) config;
312 v4Handler.setIndirectDhcpServerConfigs(indirectConfig.dhcpServerConfigs());
313 v6Handler.setIndirectDhcpServerConfigs(indirectConfig.dhcpServerConfigs());
Yi Tseng4fa05832017-08-17 13:08:31 -0700314 } else if (config instanceof DefaultDhcpRelayConfig) {
315 DefaultDhcpRelayConfig defaultConfig = (DefaultDhcpRelayConfig) config;
316 v4Handler.setDefaultDhcpServerConfigs(defaultConfig.dhcpServerConfigs());
317 v6Handler.setDefaultDhcpServerConfigs(defaultConfig.dhcpServerConfigs());
Yi Tsenge72fbb52017-08-02 15:03:31 -0700318 }
Yi Tseng5479fb82017-09-01 17:24:57 -0700319 if (config instanceof IgnoreDhcpConfig) {
Yi Tseng76365d82017-09-12 15:55:17 -0700320 updateIgnoreVlanRules((IgnoreDhcpConfig) config);
Yi Tseng5479fb82017-09-01 17:24:57 -0700321 }
322 }
323
324 protected void removeConfig(Config config) {
325 if (config instanceof IndirectDhcpRelayConfig) {
326 v4Handler.setIndirectDhcpServerConfigs(Collections.emptyList());
327 v6Handler.setIndirectDhcpServerConfigs(Collections.emptyList());
328 } else if (config instanceof DefaultDhcpRelayConfig) {
329 v4Handler.setDefaultDhcpServerConfigs(Collections.emptyList());
330 v6Handler.setDefaultDhcpServerConfigs(Collections.emptyList());
331 }
332 if (config instanceof IgnoreDhcpConfig) {
Yi Tseng76365d82017-09-12 15:55:17 -0700333 ignoredVlans.forEach(((deviceId, vlanId) -> {
334 processIgnoreVlanRule(deviceId, vlanId, REMOVE);
335 }));
Yi Tseng5479fb82017-09-01 17:24:57 -0700336 }
337 }
338
Yi Tseng76365d82017-09-12 15:55:17 -0700339 private void updateIgnoreVlanRules(IgnoreDhcpConfig config) {
Yi Tseng5479fb82017-09-01 17:24:57 -0700340 config.ignoredVlans().forEach((deviceId, vlanId) -> {
341 if (ignoredVlans.get(deviceId).contains(vlanId)) {
342 // don't need to process if it already ignored
343 return;
344 }
Yi Tseng76365d82017-09-12 15:55:17 -0700345 processIgnoreVlanRule(deviceId, vlanId, ADD);
Yi Tseng5479fb82017-09-01 17:24:57 -0700346 });
347
Yi Tseng5479fb82017-09-01 17:24:57 -0700348 ignoredVlans.forEach((deviceId, vlanId) -> {
349 if (!config.ignoredVlans().get(deviceId).contains(vlanId)) {
350 // not contains in new config, remove it
Yi Tseng76365d82017-09-12 15:55:17 -0700351 processIgnoreVlanRule(deviceId, vlanId, REMOVE);
Yi Tseng5479fb82017-09-01 17:24:57 -0700352 }
353 });
Yi Tseng5479fb82017-09-01 17:24:57 -0700354 }
355
Yi Tseng76365d82017-09-12 15:55:17 -0700356 /**
357 * Process the ignore rules.
358 *
359 * @param deviceId the device id
360 * @param vlanId the vlan to be ignored
361 * @param op the operation, ADD to install; REMOVE to uninstall rules
362 */
363 private void processIgnoreVlanRule(DeviceId deviceId, VlanId vlanId, Objective.Operation op) {
Yi Tseng5479fb82017-09-01 17:24:57 -0700364 TrafficTreatment dropTreatment = DefaultTrafficTreatment.emptyTreatment();
365 dropTreatment.clearedDeferred();
Yi Tseng76365d82017-09-12 15:55:17 -0700366 AtomicInteger installedCount = new AtomicInteger(DHCP_SELECTORS.size());
Yi Tseng5479fb82017-09-01 17:24:57 -0700367 DHCP_SELECTORS.forEach(trafficSelector -> {
368 UdpPortCriterion udpDst = (UdpPortCriterion) trafficSelector.getCriterion(Criterion.Type.UDP_DST);
Yi Tseng76365d82017-09-12 15:55:17 -0700369 int udpDstPort = udpDst.udpPort().toInt();
Yi Tseng5479fb82017-09-01 17:24:57 -0700370 TrafficSelector selector = DefaultTrafficSelector.builder(trafficSelector)
371 .matchVlanId(vlanId)
372 .build();
373
Yi Tseng76365d82017-09-12 15:55:17 -0700374 ForwardingObjective.Builder builder = DefaultForwardingObjective.builder()
Yi Tseng5479fb82017-09-01 17:24:57 -0700375 .withFlag(ForwardingObjective.Flag.VERSATILE)
376 .withSelector(selector)
377 .withPriority(IGNORE_CONTROL_PRIORITY)
378 .withTreatment(dropTreatment)
Yi Tseng76365d82017-09-12 15:55:17 -0700379 .fromApp(appId);
Yi Tseng5479fb82017-09-01 17:24:57 -0700380
Yi Tseng5479fb82017-09-01 17:24:57 -0700381
Yi Tseng76365d82017-09-12 15:55:17 -0700382 ObjectiveContext objectiveContext = new ObjectiveContext() {
383 @Override
384 public void onSuccess(Objective objective) {
385 log.info("Ignore rule {} (Vlan id {}, device {}, UDP dst {})",
386 op, vlanId, deviceId, udpDstPort);
387 int countDown = installedCount.decrementAndGet();
388 if (countDown != 0) {
389 return;
390 }
391 switch (op) {
392 case ADD:
Yi Tseng5479fb82017-09-01 17:24:57 -0700393
Yi Tseng76365d82017-09-12 15:55:17 -0700394 ignoredVlans.put(deviceId, vlanId);
395 break;
396 case REMOVE:
397 ignoredVlans.remove(deviceId, vlanId);
398 break;
399 default:
400 log.warn("Unsupported objective operation {}", op);
401 break;
402 }
403 }
Yi Tseng5479fb82017-09-01 17:24:57 -0700404
Yi Tseng76365d82017-09-12 15:55:17 -0700405 @Override
406 public void onError(Objective objective, ObjectiveError error) {
407 log.warn("Can't {} ignore rule (vlan id {}, udp dst {}, device {}) due to {}",
408 op, vlanId, udpDstPort, deviceId, error);
409 }
410 };
411
412 ForwardingObjective fwd;
413 switch (op) {
414 case ADD:
415 fwd = builder.add(objectiveContext);
416 break;
417 case REMOVE:
418 fwd = builder.remove(objectiveContext);
419 break;
420 default:
421 log.warn("Unsupported objective operation {}", op);
422 return;
423 }
424
425 Device device = deviceService.getDevice(deviceId);
426 if (device == null || !device.is(Pipeliner.class)) {
427 log.warn("Device {} is not available now, wait until device is available", deviceId);
428 return;
429 }
Yi Tseng5479fb82017-09-01 17:24:57 -0700430 flowObjectiveService.apply(deviceId, fwd);
431 });
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700432 }
433
434 /**
435 * Request DHCP packet in via PacketService.
436 */
437 private void requestDhcpPackets() {
Yi Tseng5479fb82017-09-01 17:24:57 -0700438 DHCP_SELECTORS.forEach(trafficSelector -> {
439 packetService.requestPackets(trafficSelector, PacketPriority.CONTROL, appId);
440 });
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700441 }
442
443 /**
444 * Cancel requested DHCP packets in via packet service.
445 */
446 private void cancelDhcpPackets() {
Yi Tseng5479fb82017-09-01 17:24:57 -0700447 DHCP_SELECTORS.forEach(trafficSelector -> {
448 packetService.cancelPackets(trafficSelector, PacketPriority.CONTROL, appId);
449 });
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700450 }
451
452 /**
453 * Request ARP packet in via PacketService.
454 */
455 private void requestArpPackets() {
Yi Tseng5479fb82017-09-01 17:24:57 -0700456 packetService.requestPackets(ARP_SELECTOR, PacketPriority.CONTROL, appId);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700457 }
458
459 /**
460 * Cancel requested ARP packets in via packet service.
461 */
462 private void cancelArpPackets() {
Yi Tseng5479fb82017-09-01 17:24:57 -0700463 packetService.cancelPackets(ARP_SELECTOR, PacketPriority.CONTROL, appId);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700464 }
465
466 @Override
467 public Optional<DhcpRecord> getDhcpRecord(HostId hostId) {
468 return dhcpRelayStore.getDhcpRecord(hostId);
469 }
470
471 @Override
472 public Collection<DhcpRecord> getDhcpRecords() {
473 return dhcpRelayStore.getDhcpRecords();
474 }
475
Yi Tseng13a41a12017-07-26 13:45:01 -0700476 @Override
477 public Optional<MacAddress> getDhcpServerMacAddress() {
Yi Tseng4ec727d2017-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
488 /**
489 * Gets DHCP data from a packet.
490 *
491 * @param packet the packet
492 * @return the DHCP data; empty if it is not a DHCP packet
493 */
494 private Optional<DHCP> findDhcp(Ethernet packet) {
495 return Stream.of(packet)
496 .filter(Objects::nonNull)
497 .map(Ethernet::getPayload)
498 .filter(p -> p instanceof IPv4)
499 .map(IPacket::getPayload)
500 .filter(Objects::nonNull)
501 .filter(p -> p instanceof UDP)
502 .map(IPacket::getPayload)
503 .filter(Objects::nonNull)
504 .filter(p -> p instanceof DHCP)
505 .map(p -> (DHCP) p)
506 .findFirst();
507 }
508
509 /**
510 * Gets DHCPv6 data from a packet.
511 *
512 * @param packet the packet
513 * @return the DHCPv6 data; empty if it is not a DHCPv6 packet
514 */
515 private Optional<DHCP6> findDhcp6(Ethernet packet) {
516 return Stream.of(packet)
517 .filter(Objects::nonNull)
518 .map(Ethernet::getPayload)
519 .filter(p -> p instanceof IPv6)
520 .map(IPacket::getPayload)
521 .filter(Objects::nonNull)
522 .filter(p -> p instanceof UDP)
523 .map(IPacket::getPayload)
524 .filter(Objects::nonNull)
525 .filter(p -> p instanceof DHCP6)
526 .map(p -> (DHCP6) p)
527 .findFirst();
528 }
529
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700530
531 private class DhcpRelayPacketProcessor implements PacketProcessor {
532
533 @Override
534 public void process(PacketContext context) {
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700535 // process the packet and get the payload
536 Ethernet packet = context.inPacket().parsed();
537 if (packet == null) {
538 return;
539 }
540
541 findDhcp(packet).ifPresent(dhcpPayload -> {
Yi Tseng51301292017-07-28 13:02:59 -0700542 v4Handler.processDhcpPacket(context, dhcpPayload);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700543 });
544
545 findDhcp6(packet).ifPresent(dhcp6Payload -> {
Yi Tseng51301292017-07-28 13:02:59 -0700546 v6Handler.processDhcpPacket(context, dhcp6Payload);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700547 });
548
549 if (packet.getEtherType() == Ethernet.TYPE_ARP && arpEnabled) {
550 ARP arpPacket = (ARP) packet.getPayload();
551 VlanId vlanId = VlanId.vlanId(packet.getVlanID());
552 Set<Interface> interfaces = interfaceService.
553 getInterfacesByPort(context.inPacket().receivedFrom());
554 //ignore the packets if dhcp server interface is not configured on onos.
555 if (interfaces.isEmpty()) {
556 log.warn("server virtual interface not configured");
557 return;
558 }
559 if ((arpPacket.getOpCode() != ARP.OP_REQUEST)) {
560 // handle request only
561 return;
562 }
563 MacAddress interfaceMac = interfaces.stream()
564 .filter(iface -> iface.vlan().equals(vlanId))
565 .map(Interface::mac)
566 .filter(mac -> !mac.equals(MacAddress.NONE))
567 .findFirst()
Yi Tseng51301292017-07-28 13:02:59 -0700568 .orElse(MacAddress.ONOS);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700569 if (interfaceMac == null) {
570 // can't find interface mac address
571 return;
572 }
573 processArpPacket(context, packet, interfaceMac);
574 }
575 }
576
577 /**
578 * Processes the ARP Payload and initiates a reply to the client.
579 *
580 * @param context the packet context
581 * @param packet the ethernet payload
582 * @param replyMac mac address to be replied
583 */
584 private void processArpPacket(PacketContext context, Ethernet packet, MacAddress replyMac) {
585 ARP arpPacket = (ARP) packet.getPayload();
586 ARP arpReply = (ARP) arpPacket.clone();
587 arpReply.setOpCode(ARP.OP_REPLY);
588
589 arpReply.setTargetProtocolAddress(arpPacket.getSenderProtocolAddress());
590 arpReply.setTargetHardwareAddress(arpPacket.getSenderHardwareAddress());
591 arpReply.setSenderProtocolAddress(arpPacket.getTargetProtocolAddress());
592 arpReply.setSenderHardwareAddress(replyMac.toBytes());
593
594 // Ethernet Frame.
595 Ethernet ethReply = new Ethernet();
596 ethReply.setSourceMACAddress(replyMac.toBytes());
597 ethReply.setDestinationMACAddress(packet.getSourceMAC());
598 ethReply.setEtherType(Ethernet.TYPE_ARP);
599 ethReply.setVlanID(packet.getVlanID());
600 ethReply.setPayload(arpReply);
601
602 ConnectPoint targetPort = context.inPacket().receivedFrom();
603 TrafficTreatment t = DefaultTrafficTreatment.builder()
604 .setOutput(targetPort.port()).build();
605 OutboundPacket o = new DefaultOutboundPacket(
606 targetPort.deviceId(), t, ByteBuffer.wrap(ethReply.serialize()));
607 if (log.isTraceEnabled()) {
608 log.trace("Relaying ARP packet {} to {}", packet, targetPort);
609 }
610 packetService.emit(o);
611 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700612 }
613
614 /**
615 * Listener for network config events.
616 */
617 private class InternalConfigListener implements NetworkConfigListener {
618 @Override
619 public void event(NetworkConfigEvent event) {
Yi Tseng5479fb82017-09-01 17:24:57 -0700620 switch (event.type()) {
621 case CONFIG_UPDATED:
622 case CONFIG_ADDED:
623 event.config().ifPresent(config -> {
624 updateConfig(config);
625 log.info("{} updated", config.getClass().getSimpleName());
626 });
627 break;
628 case CONFIG_REMOVED:
629 event.prevConfig().ifPresent(config -> {
630 removeConfig(config);
631 log.info("{} removed", config.getClass().getSimpleName());
632 });
633 break;
634 default:
635 log.warn("Unsupported event type {}", event.type());
636 break;
Yi Tsenge72fbb52017-08-02 15:03:31 -0700637 }
Yi Tseng5479fb82017-09-01 17:24:57 -0700638
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700639 }
640 }
Yi Tseng76365d82017-09-12 15:55:17 -0700641
642 private class InternalDeviceListener implements DeviceListener {
643
644 @Override
645 public void event(DeviceEvent event) {
646 Device device = event.subject();
647 switch (event.type()) {
648 case DEVICE_ADDED:
649 deviceAdd(device.id());
650 break;
651 case DEVICE_REMOVED:
652 ignoredVlans.removeAll(device.id());
653 break;
654 case DEVICE_AVAILABILITY_CHANGED:
655 deviceAvailabilityChanged(device);
656
657 default:
658 break;
659 }
660 }
661
662 private void deviceAvailabilityChanged(Device device) {
663 if (deviceService.isAvailable(device.id())) {
664 deviceAdd(device.id());
665 } else {
666 ignoredVlans.removeAll(device.id());
667 }
668 }
669
670 private void deviceAdd(DeviceId deviceId) {
671 IgnoreDhcpConfig config = cfgService.getConfig(appId, IgnoreDhcpConfig.class);
672 Collection<VlanId> vlanIds = config.ignoredVlans().get(deviceId);
673 vlanIds.forEach(vlanId -> {
674 processIgnoreVlanRule(deviceId, vlanId, ADD);
675 });
676 }
677 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700678}