blob: 116f8e41ab912c2d86dc3d8f38198195e84a9d61 [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 Tseng2fe8f3f2017-09-07 16:22:51 -070055import org.onosproject.dhcprelay.api.DhcpServerInfo;
Yi Tsenge72fbb52017-08-02 15:03:31 -070056import org.onosproject.dhcprelay.config.DefaultDhcpRelayConfig;
Yi Tseng4ec727d2017-08-31 11:21:00 -070057import org.onosproject.dhcprelay.config.DhcpServerConfig;
Yi Tseng5479fb82017-09-01 17:24:57 -070058import org.onosproject.dhcprelay.config.IgnoreDhcpConfig;
Yi Tsenge72fbb52017-08-02 15:03:31 -070059import org.onosproject.dhcprelay.config.IndirectDhcpRelayConfig;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070060import org.onosproject.dhcprelay.store.DhcpRecord;
61import org.onosproject.dhcprelay.store.DhcpRelayStore;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070062import org.onosproject.net.ConnectPoint;
Yi Tseng76365d82017-09-12 15:55:17 -070063import org.onosproject.net.Device;
Yi Tseng4ec727d2017-08-31 11:21:00 -070064import org.onosproject.net.DeviceId;
65import org.onosproject.net.Host;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070066import org.onosproject.net.HostId;
Yi Tseng4ec727d2017-08-31 11:21:00 -070067import org.onosproject.net.config.Config;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070068import org.onosproject.net.config.ConfigFactory;
69import org.onosproject.net.config.NetworkConfigEvent;
70import org.onosproject.net.config.NetworkConfigListener;
71import org.onosproject.net.config.NetworkConfigRegistry;
72import org.onosproject.net.flow.DefaultTrafficSelector;
73import org.onosproject.net.flow.DefaultTrafficTreatment;
74import org.onosproject.net.flow.TrafficSelector;
75import org.onosproject.net.flow.TrafficTreatment;
Yi Tseng76365d82017-09-12 15:55:17 -070076import org.onosproject.net.behaviour.Pipeliner;
77import org.onosproject.net.device.DeviceEvent;
78import org.onosproject.net.device.DeviceListener;
79import org.onosproject.net.device.DeviceService;
Yi Tseng4ec727d2017-08-31 11:21:00 -070080import org.onosproject.net.flow.criteria.Criterion;
81import org.onosproject.net.flow.criteria.UdpPortCriterion;
82import org.onosproject.net.flowobjective.DefaultForwardingObjective;
83import org.onosproject.net.flowobjective.FlowObjectiveService;
84import org.onosproject.net.flowobjective.ForwardingObjective;
85import org.onosproject.net.flowobjective.Objective;
86import org.onosproject.net.flowobjective.ObjectiveContext;
87import org.onosproject.net.flowobjective.ObjectiveError;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070088import org.onosproject.net.host.HostService;
Yi Tseng4ec727d2017-08-31 11:21:00 -070089import org.onosproject.net.intf.Interface;
90import org.onosproject.net.intf.InterfaceService;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070091import org.onosproject.net.packet.DefaultOutboundPacket;
92import org.onosproject.net.packet.OutboundPacket;
93import org.onosproject.net.packet.PacketContext;
94import org.onosproject.net.packet.PacketPriority;
95import org.onosproject.net.packet.PacketProcessor;
96import org.onosproject.net.packet.PacketService;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070097import org.osgi.service.component.ComponentContext;
98import org.slf4j.Logger;
99import org.slf4j.LoggerFactory;
100
Yi Tseng4ec727d2017-08-31 11:21:00 -0700101import com.google.common.collect.HashMultimap;
102import com.google.common.collect.ImmutableList;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700103import com.google.common.collect.ImmutableSet;
Yi Tseng4ec727d2017-08-31 11:21:00 -0700104import com.google.common.collect.Multimap;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700105
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700106import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
Yi Tseng76365d82017-09-12 15:55:17 -0700107import static org.onosproject.net.flowobjective.Objective.Operation.ADD;
108import static org.onosproject.net.flowobjective.Objective.Operation.REMOVE;
109
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700110/**
111 * DHCP Relay Agent Application Component.
112 */
113@Component(immediate = true)
114@Service
115public class DhcpRelayManager implements DhcpRelayService {
Yi Tsenge72fbb52017-08-02 15:03:31 -0700116 public static final String DHCP_RELAY_APP = "org.onosproject.dhcprelay";
Yi Tseng325af8c2017-09-01 16:02:56 -0700117 public static final String ROUTE_STORE_IMPL =
118 "org.onosproject.routeservice.store.RouteStoreImpl";
Yi Tseng5479fb82017-09-01 17:24:57 -0700119 private static final TrafficSelector DHCP_SERVER_SELECTOR = DefaultTrafficSelector.builder()
120 .matchEthType(Ethernet.TYPE_IPV4)
121 .matchIPProtocol(IPv4.PROTOCOL_UDP)
122 .matchUdpDst(TpPort.tpPort(UDP.DHCP_SERVER_PORT))
123 .build();
124 private static final TrafficSelector DHCP_CLIENT_SELECTOR = DefaultTrafficSelector.builder()
125 .matchEthType(Ethernet.TYPE_IPV4)
126 .matchIPProtocol(IPv4.PROTOCOL_UDP)
127 .matchUdpDst(TpPort.tpPort(UDP.DHCP_CLIENT_PORT))
128 .build();
129 private static final TrafficSelector DHCP6_SERVER_SELECTOR = DefaultTrafficSelector.builder()
130 .matchEthType(Ethernet.TYPE_IPV6)
131 .matchIPProtocol(IPv4.PROTOCOL_UDP)
132 .matchUdpDst(TpPort.tpPort(UDP.DHCP_V6_SERVER_PORT))
133 .build();
134 private static final TrafficSelector DHCP6_CLIENT_SELECTOR = DefaultTrafficSelector.builder()
135 .matchEthType(Ethernet.TYPE_IPV6)
136 .matchIPProtocol(IPv4.PROTOCOL_UDP)
137 .matchUdpDst(TpPort.tpPort(UDP.DHCP_V6_CLIENT_PORT))
138 .build();
139 static final List<TrafficSelector> DHCP_SELECTORS = ImmutableList.of(
140 DHCP_SERVER_SELECTOR,
141 DHCP_CLIENT_SELECTOR,
142 DHCP6_SERVER_SELECTOR,
143 DHCP6_CLIENT_SELECTOR
144 );
145 private static final TrafficSelector ARP_SELECTOR = DefaultTrafficSelector.builder()
146 .matchEthType(Ethernet.TYPE_ARP)
147 .build();
148 private static final int IGNORE_CONTROL_PRIORITY = PacketPriority.CONTROL.priorityValue() + 1000;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700149 private final Logger log = LoggerFactory.getLogger(getClass());
150 private final InternalConfigListener cfgListener = new InternalConfigListener();
151
152 private final Set<ConfigFactory> factories = ImmutableSet.of(
Yi Tsenge72fbb52017-08-02 15:03:31 -0700153 new ConfigFactory<ApplicationId, DefaultDhcpRelayConfig>(APP_SUBJECT_FACTORY,
154 DefaultDhcpRelayConfig.class,
155 DefaultDhcpRelayConfig.KEY,
156 true) {
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700157 @Override
Yi Tsenge72fbb52017-08-02 15:03:31 -0700158 public DefaultDhcpRelayConfig createConfig() {
159 return new DefaultDhcpRelayConfig();
160 }
161 },
162 new ConfigFactory<ApplicationId, IndirectDhcpRelayConfig>(APP_SUBJECT_FACTORY,
163 IndirectDhcpRelayConfig.class,
164 IndirectDhcpRelayConfig.KEY,
165 true) {
166 @Override
167 public IndirectDhcpRelayConfig createConfig() {
168 return new IndirectDhcpRelayConfig();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700169 }
Yi Tseng5479fb82017-09-01 17:24:57 -0700170 },
171 new ConfigFactory<ApplicationId, IgnoreDhcpConfig>(APP_SUBJECT_FACTORY,
172 IgnoreDhcpConfig.class,
173 IgnoreDhcpConfig.KEY,
174 true) {
175 @Override
176 public IgnoreDhcpConfig createConfig() {
177 return new IgnoreDhcpConfig();
178 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700179 }
180 );
181
182 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
183 protected NetworkConfigRegistry cfgService;
184
185 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
186 protected CoreService coreService;
187
188 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
189 protected PacketService packetService;
190
191 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
192 protected HostService hostService;
193
194 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700195 protected InterfaceService interfaceService;
196
197 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
198 protected DhcpRelayStore dhcpRelayStore;
199
200 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
201 protected ComponentConfigService compCfgService;
202
Yi Tseng5479fb82017-09-01 17:24:57 -0700203 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
204 protected FlowObjectiveService flowObjectiveService;
205
Yi Tseng76365d82017-09-12 15:55:17 -0700206 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
207 protected DeviceService deviceService;
208
Yi Tseng51301292017-07-28 13:02:59 -0700209 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY,
Yi Tseng76365d82017-09-12 15:55:17 -0700210 target = "(version=4)")
Yi Tseng51301292017-07-28 13:02:59 -0700211 protected DhcpHandler v4Handler;
212
213 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY,
Yi Tseng76365d82017-09-12 15:55:17 -0700214 target = "(version=6)")
Yi Tseng51301292017-07-28 13:02:59 -0700215 protected DhcpHandler v6Handler;
216
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700217 @Property(name = "arpEnabled", boolValue = true,
Yi Tseng76365d82017-09-12 15:55:17 -0700218 label = "Enable Address resolution protocol")
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700219 protected boolean arpEnabled = true;
220
Yi Tseng5479fb82017-09-01 17:24:57 -0700221 protected Multimap<DeviceId, VlanId> ignoredVlans = HashMultimap.create();
Yi Tseng76365d82017-09-12 15:55:17 -0700222 protected DeviceListener deviceListener = new InternalDeviceListener();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700223 private DhcpRelayPacketProcessor dhcpRelayPacketProcessor = new DhcpRelayPacketProcessor();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700224 private ApplicationId appId;
225
226 @Activate
227 protected void activate(ComponentContext context) {
228 //start the dhcp relay agent
229 appId = coreService.registerApplication(DHCP_RELAY_APP);
230
231 cfgService.addListener(cfgListener);
232 factories.forEach(cfgService::registerConfigFactory);
233 //update the dhcp server configuration.
234 updateConfig();
Yi Tseng51301292017-07-28 13:02:59 -0700235
236 //add the packet processor
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700237 packetService.addProcessor(dhcpRelayPacketProcessor, PacketProcessor.director(0));
Yi Tseng51301292017-07-28 13:02:59 -0700238
239 // listen host event for dhcp server or the gateway
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700240 requestDhcpPackets();
241 modified(context);
242
Yi Tseng325af8c2017-09-01 16:02:56 -0700243 // Enable distribute route store
244 compCfgService.preSetProperty(ROUTE_STORE_IMPL,
245 "distributed", Boolean.TRUE.toString());
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700246 compCfgService.registerProperties(getClass());
Yi Tseng76365d82017-09-12 15:55:17 -0700247
248 deviceService.addListener(deviceListener);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700249 log.info("DHCP-RELAY Started");
250 }
251
252 @Deactivate
253 protected void deactivate() {
254 cfgService.removeListener(cfgListener);
255 factories.forEach(cfgService::unregisterConfigFactory);
256 packetService.removeProcessor(dhcpRelayPacketProcessor);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700257 cancelDhcpPackets();
258 cancelArpPackets();
Yi Tsengdfa8ee22017-08-07 12:45:01 -0700259 compCfgService.unregisterProperties(getClass(), false);
Yi Tseng76365d82017-09-12 15:55:17 -0700260 deviceService.removeListener(deviceListener);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700261 log.info("DHCP-RELAY Stopped");
262 }
263
264 @Modified
265 protected void modified(ComponentContext context) {
266 Dictionary<?, ?> properties = context.getProperties();
267 Boolean flag;
268
269 flag = Tools.isPropertyEnabled(properties, "arpEnabled");
270 if (flag != null) {
271 arpEnabled = flag;
272 log.info("Address resolution protocol is {}",
273 arpEnabled ? "enabled" : "disabled");
274 }
275
276 if (arpEnabled) {
277 requestArpPackets();
278 } else {
279 cancelArpPackets();
280 }
281 }
282
Yi Tsenge72fbb52017-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 Tsenge72fbb52017-08-02 15:03:31 -0700287 DefaultDhcpRelayConfig defaultConfig =
288 cfgService.getConfig(appId, DefaultDhcpRelayConfig.class);
289 IndirectDhcpRelayConfig indirectConfig =
290 cfgService.getConfig(appId, IndirectDhcpRelayConfig.class);
Yi Tseng5479fb82017-09-01 17:24:57 -0700291 IgnoreDhcpConfig ignoreDhcpConfig =
292 cfgService.getConfig(appId, IgnoreDhcpConfig.class);
Yi Tsenge72fbb52017-08-02 15:03:31 -0700293
294 if (defaultConfig != null) {
295 updateConfig(defaultConfig);
296 }
Yi Tsenge72fbb52017-08-02 15:03:31 -0700297 if (indirectConfig != null) {
298 updateConfig(indirectConfig);
299 }
Yi Tseng5479fb82017-09-01 17:24:57 -0700300 if (ignoreDhcpConfig != null) {
301 updateConfig(ignoreDhcpConfig);
302 }
Yi Tsenge72fbb52017-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 Tseng5479fb82017-09-01 17:24:57 -0700310 protected void updateConfig(Config config) {
Yi Tsenge72fbb52017-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 Tseng4fa05832017-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 Tsenge72fbb52017-08-02 15:03:31 -0700319 }
Yi Tseng5479fb82017-09-01 17:24:57 -0700320 if (config instanceof IgnoreDhcpConfig) {
Yi Tseng76365d82017-09-12 15:55:17 -0700321 updateIgnoreVlanRules((IgnoreDhcpConfig) config);
Yi Tseng5479fb82017-09-01 17:24:57 -0700322 }
323 }
324
325 protected void removeConfig(Config config) {
326 if (config instanceof IndirectDhcpRelayConfig) {
327 v4Handler.setIndirectDhcpServerConfigs(Collections.emptyList());
328 v6Handler.setIndirectDhcpServerConfigs(Collections.emptyList());
329 } else if (config instanceof DefaultDhcpRelayConfig) {
330 v4Handler.setDefaultDhcpServerConfigs(Collections.emptyList());
331 v6Handler.setDefaultDhcpServerConfigs(Collections.emptyList());
332 }
333 if (config instanceof IgnoreDhcpConfig) {
Yi Tseng76365d82017-09-12 15:55:17 -0700334 ignoredVlans.forEach(((deviceId, vlanId) -> {
335 processIgnoreVlanRule(deviceId, vlanId, REMOVE);
336 }));
Yi Tseng5479fb82017-09-01 17:24:57 -0700337 }
338 }
339
Yi Tseng76365d82017-09-12 15:55:17 -0700340 private void updateIgnoreVlanRules(IgnoreDhcpConfig config) {
Yi Tseng5479fb82017-09-01 17:24:57 -0700341 config.ignoredVlans().forEach((deviceId, vlanId) -> {
342 if (ignoredVlans.get(deviceId).contains(vlanId)) {
343 // don't need to process if it already ignored
344 return;
345 }
Yi Tseng76365d82017-09-12 15:55:17 -0700346 processIgnoreVlanRule(deviceId, vlanId, ADD);
Yi Tseng5479fb82017-09-01 17:24:57 -0700347 });
348
Yi Tseng5479fb82017-09-01 17:24:57 -0700349 ignoredVlans.forEach((deviceId, vlanId) -> {
350 if (!config.ignoredVlans().get(deviceId).contains(vlanId)) {
351 // not contains in new config, remove it
Yi Tseng76365d82017-09-12 15:55:17 -0700352 processIgnoreVlanRule(deviceId, vlanId, REMOVE);
Yi Tseng5479fb82017-09-01 17:24:57 -0700353 }
354 });
Yi Tseng5479fb82017-09-01 17:24:57 -0700355 }
356
Yi Tseng76365d82017-09-12 15:55:17 -0700357 /**
358 * Process the ignore rules.
359 *
360 * @param deviceId the device id
361 * @param vlanId the vlan to be ignored
362 * @param op the operation, ADD to install; REMOVE to uninstall rules
363 */
364 private void processIgnoreVlanRule(DeviceId deviceId, VlanId vlanId, Objective.Operation op) {
Yi Tseng5479fb82017-09-01 17:24:57 -0700365 TrafficTreatment dropTreatment = DefaultTrafficTreatment.emptyTreatment();
366 dropTreatment.clearedDeferred();
Yi Tseng76365d82017-09-12 15:55:17 -0700367 AtomicInteger installedCount = new AtomicInteger(DHCP_SELECTORS.size());
Yi Tseng5479fb82017-09-01 17:24:57 -0700368 DHCP_SELECTORS.forEach(trafficSelector -> {
369 UdpPortCriterion udpDst = (UdpPortCriterion) trafficSelector.getCriterion(Criterion.Type.UDP_DST);
Yi Tseng76365d82017-09-12 15:55:17 -0700370 int udpDstPort = udpDst.udpPort().toInt();
Yi Tseng5479fb82017-09-01 17:24:57 -0700371 TrafficSelector selector = DefaultTrafficSelector.builder(trafficSelector)
372 .matchVlanId(vlanId)
373 .build();
374
Yi Tseng76365d82017-09-12 15:55:17 -0700375 ForwardingObjective.Builder builder = DefaultForwardingObjective.builder()
Yi Tseng5479fb82017-09-01 17:24:57 -0700376 .withFlag(ForwardingObjective.Flag.VERSATILE)
377 .withSelector(selector)
378 .withPriority(IGNORE_CONTROL_PRIORITY)
379 .withTreatment(dropTreatment)
Yi Tseng76365d82017-09-12 15:55:17 -0700380 .fromApp(appId);
Yi Tseng5479fb82017-09-01 17:24:57 -0700381
Yi Tseng5479fb82017-09-01 17:24:57 -0700382
Yi Tseng76365d82017-09-12 15:55:17 -0700383 ObjectiveContext objectiveContext = new ObjectiveContext() {
384 @Override
385 public void onSuccess(Objective objective) {
386 log.info("Ignore rule {} (Vlan id {}, device {}, UDP dst {})",
387 op, vlanId, deviceId, udpDstPort);
388 int countDown = installedCount.decrementAndGet();
389 if (countDown != 0) {
390 return;
391 }
392 switch (op) {
393 case ADD:
Yi Tseng5479fb82017-09-01 17:24:57 -0700394
Yi Tseng76365d82017-09-12 15:55:17 -0700395 ignoredVlans.put(deviceId, vlanId);
396 break;
397 case REMOVE:
398 ignoredVlans.remove(deviceId, vlanId);
399 break;
400 default:
401 log.warn("Unsupported objective operation {}", op);
402 break;
403 }
404 }
Yi Tseng5479fb82017-09-01 17:24:57 -0700405
Yi Tseng76365d82017-09-12 15:55:17 -0700406 @Override
407 public void onError(Objective objective, ObjectiveError error) {
408 log.warn("Can't {} ignore rule (vlan id {}, udp dst {}, device {}) due to {}",
409 op, vlanId, udpDstPort, deviceId, error);
410 }
411 };
412
413 ForwardingObjective fwd;
414 switch (op) {
415 case ADD:
416 fwd = builder.add(objectiveContext);
417 break;
418 case REMOVE:
419 fwd = builder.remove(objectiveContext);
420 break;
421 default:
422 log.warn("Unsupported objective operation {}", op);
423 return;
424 }
425
426 Device device = deviceService.getDevice(deviceId);
427 if (device == null || !device.is(Pipeliner.class)) {
428 log.warn("Device {} is not available now, wait until device is available", deviceId);
429 return;
430 }
Yi Tseng5479fb82017-09-01 17:24:57 -0700431 flowObjectiveService.apply(deviceId, fwd);
432 });
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700433 }
434
435 /**
436 * Request DHCP packet in via PacketService.
437 */
438 private void requestDhcpPackets() {
Yi Tseng5479fb82017-09-01 17:24:57 -0700439 DHCP_SELECTORS.forEach(trafficSelector -> {
440 packetService.requestPackets(trafficSelector, PacketPriority.CONTROL, appId);
441 });
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700442 }
443
444 /**
445 * Cancel requested DHCP packets in via packet service.
446 */
447 private void cancelDhcpPackets() {
Yi Tseng5479fb82017-09-01 17:24:57 -0700448 DHCP_SELECTORS.forEach(trafficSelector -> {
449 packetService.cancelPackets(trafficSelector, PacketPriority.CONTROL, appId);
450 });
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700451 }
452
453 /**
454 * Request ARP packet in via PacketService.
455 */
456 private void requestArpPackets() {
Yi Tseng5479fb82017-09-01 17:24:57 -0700457 packetService.requestPackets(ARP_SELECTOR, PacketPriority.CONTROL, appId);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700458 }
459
460 /**
461 * Cancel requested ARP packets in via packet service.
462 */
463 private void cancelArpPackets() {
Yi Tseng5479fb82017-09-01 17:24:57 -0700464 packetService.cancelPackets(ARP_SELECTOR, PacketPriority.CONTROL, appId);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700465 }
466
467 @Override
468 public Optional<DhcpRecord> getDhcpRecord(HostId hostId) {
469 return dhcpRelayStore.getDhcpRecord(hostId);
470 }
471
472 @Override
473 public Collection<DhcpRecord> getDhcpRecords() {
474 return dhcpRelayStore.getDhcpRecords();
475 }
476
Yi Tseng13a41a12017-07-26 13:45:01 -0700477 @Override
478 public Optional<MacAddress> getDhcpServerMacAddress() {
Yi Tseng4ec727d2017-08-31 11:21:00 -0700479 // TODO: depreated it
480 DefaultDhcpRelayConfig config = cfgService.getConfig(appId, DefaultDhcpRelayConfig.class);
481 DhcpServerConfig serverConfig = config.dhcpServerConfigs().get(0);
482 Ip4Address serverip = serverConfig.getDhcpServerIp4().get();
483 return hostService.getHostsByIp(serverip)
484 .stream()
485 .map(Host::mac)
486 .findFirst();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700487 }
488
Yi Tseng2fe8f3f2017-09-07 16:22:51 -0700489 @Override
490 public List<DhcpServerInfo> getDefaultDhcpServerInfoList() {
491 return ImmutableList.<DhcpServerInfo>builder()
492 .addAll(v4Handler.getDefaultDhcpServerInfoList())
493 .addAll(v6Handler.getDefaultDhcpServerInfoList())
494 .build();
495 }
496
497 @Override
498 public List<DhcpServerInfo> getIndirectDhcpServerInfoList() {
499 return ImmutableList.<DhcpServerInfo>builder()
500 .addAll(v4Handler.getIndirectDhcpServerInfoList())
501 .addAll(v6Handler.getIndirectDhcpServerInfoList())
502 .build();
503 }
504
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700505 /**
506 * Gets DHCP data from a packet.
507 *
508 * @param packet the packet
509 * @return the DHCP data; empty if it is not a DHCP packet
510 */
511 private Optional<DHCP> findDhcp(Ethernet packet) {
512 return Stream.of(packet)
513 .filter(Objects::nonNull)
514 .map(Ethernet::getPayload)
515 .filter(p -> p instanceof IPv4)
516 .map(IPacket::getPayload)
517 .filter(Objects::nonNull)
518 .filter(p -> p instanceof UDP)
519 .map(IPacket::getPayload)
520 .filter(Objects::nonNull)
521 .filter(p -> p instanceof DHCP)
522 .map(p -> (DHCP) p)
523 .findFirst();
524 }
525
526 /**
527 * Gets DHCPv6 data from a packet.
528 *
529 * @param packet the packet
530 * @return the DHCPv6 data; empty if it is not a DHCPv6 packet
531 */
532 private Optional<DHCP6> findDhcp6(Ethernet packet) {
533 return Stream.of(packet)
534 .filter(Objects::nonNull)
535 .map(Ethernet::getPayload)
536 .filter(p -> p instanceof IPv6)
537 .map(IPacket::getPayload)
538 .filter(Objects::nonNull)
539 .filter(p -> p instanceof UDP)
540 .map(IPacket::getPayload)
541 .filter(Objects::nonNull)
542 .filter(p -> p instanceof DHCP6)
543 .map(p -> (DHCP6) p)
544 .findFirst();
545 }
546
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700547
548 private class DhcpRelayPacketProcessor implements PacketProcessor {
549
550 @Override
551 public void process(PacketContext context) {
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700552 // process the packet and get the payload
553 Ethernet packet = context.inPacket().parsed();
554 if (packet == null) {
555 return;
556 }
557
558 findDhcp(packet).ifPresent(dhcpPayload -> {
Yi Tseng51301292017-07-28 13:02:59 -0700559 v4Handler.processDhcpPacket(context, dhcpPayload);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700560 });
561
562 findDhcp6(packet).ifPresent(dhcp6Payload -> {
Yi Tseng51301292017-07-28 13:02:59 -0700563 v6Handler.processDhcpPacket(context, dhcp6Payload);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700564 });
565
566 if (packet.getEtherType() == Ethernet.TYPE_ARP && arpEnabled) {
567 ARP arpPacket = (ARP) packet.getPayload();
568 VlanId vlanId = VlanId.vlanId(packet.getVlanID());
569 Set<Interface> interfaces = interfaceService.
570 getInterfacesByPort(context.inPacket().receivedFrom());
571 //ignore the packets if dhcp server interface is not configured on onos.
572 if (interfaces.isEmpty()) {
573 log.warn("server virtual interface not configured");
574 return;
575 }
576 if ((arpPacket.getOpCode() != ARP.OP_REQUEST)) {
577 // handle request only
578 return;
579 }
580 MacAddress interfaceMac = interfaces.stream()
581 .filter(iface -> iface.vlan().equals(vlanId))
582 .map(Interface::mac)
583 .filter(mac -> !mac.equals(MacAddress.NONE))
584 .findFirst()
Yi Tseng51301292017-07-28 13:02:59 -0700585 .orElse(MacAddress.ONOS);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700586 if (interfaceMac == null) {
587 // can't find interface mac address
588 return;
589 }
590 processArpPacket(context, packet, interfaceMac);
591 }
592 }
593
594 /**
595 * Processes the ARP Payload and initiates a reply to the client.
596 *
597 * @param context the packet context
598 * @param packet the ethernet payload
599 * @param replyMac mac address to be replied
600 */
601 private void processArpPacket(PacketContext context, Ethernet packet, MacAddress replyMac) {
602 ARP arpPacket = (ARP) packet.getPayload();
603 ARP arpReply = (ARP) arpPacket.clone();
604 arpReply.setOpCode(ARP.OP_REPLY);
605
606 arpReply.setTargetProtocolAddress(arpPacket.getSenderProtocolAddress());
607 arpReply.setTargetHardwareAddress(arpPacket.getSenderHardwareAddress());
608 arpReply.setSenderProtocolAddress(arpPacket.getTargetProtocolAddress());
609 arpReply.setSenderHardwareAddress(replyMac.toBytes());
610
611 // Ethernet Frame.
612 Ethernet ethReply = new Ethernet();
613 ethReply.setSourceMACAddress(replyMac.toBytes());
614 ethReply.setDestinationMACAddress(packet.getSourceMAC());
615 ethReply.setEtherType(Ethernet.TYPE_ARP);
616 ethReply.setVlanID(packet.getVlanID());
617 ethReply.setPayload(arpReply);
618
619 ConnectPoint targetPort = context.inPacket().receivedFrom();
620 TrafficTreatment t = DefaultTrafficTreatment.builder()
621 .setOutput(targetPort.port()).build();
622 OutboundPacket o = new DefaultOutboundPacket(
623 targetPort.deviceId(), t, ByteBuffer.wrap(ethReply.serialize()));
624 if (log.isTraceEnabled()) {
625 log.trace("Relaying ARP packet {} to {}", packet, targetPort);
626 }
627 packetService.emit(o);
628 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700629 }
630
631 /**
632 * Listener for network config events.
633 */
634 private class InternalConfigListener implements NetworkConfigListener {
635 @Override
636 public void event(NetworkConfigEvent event) {
Yi Tseng5479fb82017-09-01 17:24:57 -0700637 switch (event.type()) {
638 case CONFIG_UPDATED:
639 case CONFIG_ADDED:
640 event.config().ifPresent(config -> {
641 updateConfig(config);
642 log.info("{} updated", config.getClass().getSimpleName());
643 });
644 break;
645 case CONFIG_REMOVED:
646 event.prevConfig().ifPresent(config -> {
647 removeConfig(config);
648 log.info("{} removed", config.getClass().getSimpleName());
649 });
650 break;
651 default:
652 log.warn("Unsupported event type {}", event.type());
653 break;
Yi Tsenge72fbb52017-08-02 15:03:31 -0700654 }
Yi Tseng5479fb82017-09-01 17:24:57 -0700655
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700656 }
657 }
Yi Tseng76365d82017-09-12 15:55:17 -0700658
659 private class InternalDeviceListener implements DeviceListener {
660
661 @Override
662 public void event(DeviceEvent event) {
663 Device device = event.subject();
664 switch (event.type()) {
665 case DEVICE_ADDED:
666 deviceAdd(device.id());
667 break;
668 case DEVICE_REMOVED:
669 ignoredVlans.removeAll(device.id());
670 break;
671 case DEVICE_AVAILABILITY_CHANGED:
672 deviceAvailabilityChanged(device);
673
674 default:
675 break;
676 }
677 }
678
679 private void deviceAvailabilityChanged(Device device) {
680 if (deviceService.isAvailable(device.id())) {
681 deviceAdd(device.id());
682 } else {
683 ignoredVlans.removeAll(device.id());
684 }
685 }
686
687 private void deviceAdd(DeviceId deviceId) {
688 IgnoreDhcpConfig config = cfgService.getConfig(appId, IgnoreDhcpConfig.class);
Charles Chan8e8e72c2017-09-13 20:00:05 -0700689 if (config == null) {
690 log.debug("No ignoreVlan config found for {}. Do nothing.", deviceId);
691 return;
692 }
693
Yi Tseng76365d82017-09-12 15:55:17 -0700694 Collection<VlanId> vlanIds = config.ignoredVlans().get(deviceId);
695 vlanIds.forEach(vlanId -> {
696 processIgnoreVlanRule(deviceId, vlanId, ADD);
697 });
698 }
699 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700700}