blob: 27d59d969b175fa1c110b83d70aa2ca957dedd4a [file] [log] [blame]
Yi Tseng51301292017-07-28 13:02:59 -07001/*
2 * Copyright 2017-present Open Networking Foundation
3 *
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 *
16 */
17
18package org.onosproject.dhcprelay;
19
Kalhee Kim45fede42017-09-05 19:05:06 +000020import org.apache.felix.scr.annotations.Activate;
21import org.apache.felix.scr.annotations.Deactivate;
22import com.google.common.base.MoreObjects;
23import com.google.common.collect.Sets;
24import com.google.common.collect.ImmutableSet;
Yi Tseng51301292017-07-28 13:02:59 -070025import org.apache.felix.scr.annotations.Component;
26import org.apache.felix.scr.annotations.Property;
Kalhee Kim45fede42017-09-05 19:05:06 +000027import org.apache.felix.scr.annotations.Reference;
28import org.apache.felix.scr.annotations.ReferenceCardinality;
Yi Tseng51301292017-07-28 13:02:59 -070029import org.apache.felix.scr.annotations.Service;
30import org.onlab.packet.BasePacket;
Kalhee Kim45fede42017-09-05 19:05:06 +000031import org.onlab.packet.DHCP6;
32import org.onlab.packet.IPv6;
33import org.onlab.packet.Ethernet;
34import org.onlab.packet.Ip6Address;
Yi Tseng51301292017-07-28 13:02:59 -070035import org.onlab.packet.IpAddress;
Kalhee Kim45fede42017-09-05 19:05:06 +000036import org.onlab.packet.IpPrefix;
Yi Tseng51301292017-07-28 13:02:59 -070037import org.onlab.packet.MacAddress;
Kalhee Kim45fede42017-09-05 19:05:06 +000038import org.onlab.packet.UDP;
Yi Tseng51301292017-07-28 13:02:59 -070039import org.onlab.packet.VlanId;
Kalhee Kim45fede42017-09-05 19:05:06 +000040import org.onlab.packet.dhcp.Dhcp6RelayOption;
41import org.onlab.packet.dhcp.Dhcp6InterfaceIdOption;
42import org.onlab.packet.dhcp.Dhcp6Option;
43import org.onlab.packet.dhcp.Dhcp6IaNaOption;
44import org.onlab.packet.dhcp.Dhcp6IaTaOption;
45import org.onlab.packet.dhcp.Dhcp6IaPdOption;
46import org.onlab.packet.dhcp.Dhcp6IaAddressOption;
47import org.onlab.packet.dhcp.Dhcp6IaPrefixOption;
48import org.onlab.util.HexString;
Yi Tseng51301292017-07-28 13:02:59 -070049import org.onosproject.dhcprelay.api.DhcpHandler;
Kalhee Kim45fede42017-09-05 19:05:06 +000050import org.onosproject.dhcprelay.store.DhcpRelayStore;
51import org.onosproject.net.host.HostStore;
52import org.onosproject.net.host.HostService;
53import org.onosproject.net.host.DefaultHostDescription;
54import org.onosproject.net.host.HostDescription;
55import org.onosproject.net.host.InterfaceIpAddress;
56import org.onosproject.net.host.HostListener;
57import org.onosproject.net.host.HostEvent;
58import org.onosproject.net.intf.Interface;
59import org.onosproject.net.intf.InterfaceService;
60import org.onosproject.routeservice.Route;
61import org.onosproject.routeservice.RouteStore;
Yi Tseng483ac6f2017-08-02 15:03:31 -070062import org.onosproject.dhcprelay.config.DhcpServerConfig;
Yi Tseng51301292017-07-28 13:02:59 -070063import org.onosproject.net.ConnectPoint;
Kalhee Kim45fede42017-09-05 19:05:06 +000064import org.onosproject.net.Host;
65import org.onosproject.net.HostId;
66import org.onosproject.net.HostLocation;
67import org.onosproject.net.packet.DefaultOutboundPacket;
68import org.onosproject.net.packet.OutboundPacket;
Yi Tseng51301292017-07-28 13:02:59 -070069import org.onosproject.net.packet.PacketContext;
Kalhee Kim45fede42017-09-05 19:05:06 +000070import org.onosproject.net.packet.PacketService;
71import org.slf4j.Logger;
72import org.slf4j.LoggerFactory;
73import org.onosproject.net.flow.DefaultTrafficTreatment;
74import org.onosproject.net.flow.TrafficTreatment;
Yi Tseng51301292017-07-28 13:02:59 -070075
Kalhee Kim45fede42017-09-05 19:05:06 +000076
77import java.nio.ByteBuffer;
78import java.util.List;
Yi Tseng483ac6f2017-08-02 15:03:31 -070079import java.util.Collection;
Yi Tseng51301292017-07-28 13:02:59 -070080import java.util.Optional;
Kalhee Kim45fede42017-09-05 19:05:06 +000081import java.util.Set;
82import java.util.ArrayList;
83
84
85import static com.google.common.base.Preconditions.checkNotNull;
86import static com.google.common.base.Preconditions.checkState;
Yi Tseng51301292017-07-28 13:02:59 -070087
88@Component
89@Service
90@Property(name = "version", value = "6")
91public class Dhcp6HandlerImpl implements DhcpHandler {
Kalhee Kim45fede42017-09-05 19:05:06 +000092 private static Logger log = LoggerFactory.getLogger(Dhcp6HandlerImpl.class);
Yi Tseng51301292017-07-28 13:02:59 -070093
Kalhee Kim45fede42017-09-05 19:05:06 +000094 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
95 protected DhcpRelayStore dhcpRelayStore;
Yi Tseng51301292017-07-28 13:02:59 -070096
Kalhee Kim45fede42017-09-05 19:05:06 +000097 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
98 protected PacketService packetService;
99
100 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
101 protected HostStore hostStore;
102
103 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
104 protected RouteStore routeStore;
105
106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
107 protected InterfaceService interfaceService;
108
109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
110 protected HostService hostService;
111
112 private InternalHostListener hostListener = new InternalHostListener();
113
114 private Ip6Address dhcpServerIp = null;
115 // dhcp server may be connected directly to the SDN network or
116 // via an external gateway. When connected directly, the dhcpConnectPoint, dhcpConnectMac,
117 // and dhcpConnectVlan refer to the server. When connected via the gateway, they refer
118 // to the gateway.
119 private ConnectPoint dhcpServerConnectPoint = null;
120 private MacAddress dhcpConnectMac = null;
121 private VlanId dhcpConnectVlan = null;
122 private Ip6Address dhcpGatewayIp = null;
123 private Ip6Address relayAgentIpFromCfg = null;
124
125 private Ip6Address indirectDhcpServerIp = null;
126 private ConnectPoint indirectDhcpServerConnectPoint = null;
127 private MacAddress indirectDhcpConnectMac = null;
128 private VlanId indirectDhcpConnectVlan = null;
129 private Ip6Address indirectDhcpGatewayIp = null;
130 private Ip6Address indirectRelayAgentIpFromCfg = null;
131
132
133 // CLIENT message types
134 public static final Set<Byte> MSG_TYPE_FROM_CLIENT =
135 ImmutableSet.of(DHCP6.MsgType.SOLICIT.value(),
136 DHCP6.MsgType.REQUEST.value(),
137 DHCP6.MsgType.REBIND.value(),
138 DHCP6.MsgType.RENEW.value(),
139 DHCP6.MsgType.RELEASE.value(),
140 DHCP6.MsgType.DECLINE.value(),
141 DHCP6.MsgType.CONFIRM.value(),
142 DHCP6.MsgType.RELAY_FORW.value());
143 // SERVER message types
144 public static final Set<Byte> MSG_TYPE_FROM_SERVER =
145 ImmutableSet.of(DHCP6.MsgType.RELAY_REPL.value());
146
147 @Activate
148 protected void activate() {
149 hostService.addListener(hostListener);
Yi Tseng51301292017-07-28 13:02:59 -0700150 }
151
Kalhee Kim45fede42017-09-05 19:05:06 +0000152 @Deactivate
153 protected void deactivate() {
154 hostService.removeListener(hostListener);
155 this.dhcpConnectMac = null;
156 this.dhcpConnectVlan = null;
157
158 if (dhcpGatewayIp != null) {
159 hostService.stopMonitoringIp(dhcpGatewayIp);
160 } else if (dhcpServerIp != null) {
161 hostService.stopMonitoringIp(dhcpServerIp);
162 }
Yi Tseng51301292017-07-28 13:02:59 -0700163 }
164
Yi Tseng51301292017-07-28 13:02:59 -0700165
166 @Override
Kalhee Kim45fede42017-09-05 19:05:06 +0000167 public void setDhcpServerIp(IpAddress dhcpServerIp) {
168 checkNotNull(dhcpServerIp, "DHCP server IP can't be null");
169 checkState(dhcpServerIp.isIp6(), "Invalid server IP for DHCPv6 relay handler");
170 this.dhcpServerIp = dhcpServerIp.getIp6Address();
Yi Tseng51301292017-07-28 13:02:59 -0700171 }
172
173 @Override
174 public void setDhcpServerConnectPoint(ConnectPoint dhcpServerConnectPoint) {
Kalhee Kim45fede42017-09-05 19:05:06 +0000175 checkNotNull(dhcpServerConnectPoint, "Server connect point can't null");
176 this.dhcpServerConnectPoint = dhcpServerConnectPoint;
Yi Tseng51301292017-07-28 13:02:59 -0700177 }
178
179 @Override
Kalhee Kim45fede42017-09-05 19:05:06 +0000180 public void setDhcpConnectMac(MacAddress dhcpConnectMac) {
181 this.dhcpConnectMac = dhcpConnectMac;
182 }
Yi Tseng51301292017-07-28 13:02:59 -0700183
Kalhee Kim45fede42017-09-05 19:05:06 +0000184 @Override
185 public void setDhcpConnectVlan(VlanId dhcpConnectVlan) {
186 this.dhcpConnectVlan = dhcpConnectVlan;
187 }
188
189 @Override
190 public void setDhcpGatewayIp(IpAddress dhcpGatewayIp) {
191 if (dhcpGatewayIp != null) {
192 checkState(dhcpGatewayIp.isIp6(), "Invalid gateway IP for DHCPv6 relay handler");
193 this.dhcpGatewayIp = dhcpGatewayIp.getIp6Address();
194 } else {
195 // removes gateway config
196 this.dhcpGatewayIp = null;
197 }
198 }
199 @Override
200 public Optional<IpAddress> getDhcpServerIp() {
201 return Optional.ofNullable(dhcpServerIp);
202 }
203
204 @Override
205 public Optional<IpAddress> getDhcpGatewayIp() {
206 return Optional.ofNullable(dhcpGatewayIp);
207 }
208
209 @Override
210 public Optional<MacAddress> getDhcpConnectMac() {
211 return Optional.ofNullable(dhcpConnectMac);
212 }
213
214 // Indirect DHCP server
215
216 public void setIndirectDhcpServerIp(IpAddress dhcpServerIp) {
217 checkNotNull(dhcpServerIp, "DHCP indirect server IP can't be null");
218 checkState(dhcpServerIp.isIp6(), "Invalid indirect server IP for DHCPv6 relay handler");
219 this.indirectDhcpServerIp = dhcpServerIp.getIp6Address();
220 }
221
222
223 public void setIndirectDhcpServerConnectPoint(ConnectPoint dhcpServerConnectPoint) {
224 checkNotNull(dhcpServerConnectPoint, "Indirect Server connect point can't null");
225 this.indirectDhcpServerConnectPoint = dhcpServerConnectPoint;
226 }
227
228
229 public void setIndirectDhcpConnectMac(MacAddress dhcpConnectMac) {
230 this.indirectDhcpConnectMac = dhcpConnectMac;
231 }
232
233
234 public void setIndirectDhcpConnectVlan(VlanId dhcpConnectVlan) {
235 this.indirectDhcpConnectVlan = dhcpConnectVlan;
236 }
237
238
239 public void setIndirectDhcpGatewayIp(IpAddress dhcpGatewayIp) {
240 if (dhcpGatewayIp != null) {
241 checkState(dhcpGatewayIp.isIp6(), "Invalid indirect gateway IP for DHCPv6 relay handler");
242 this.indirectDhcpGatewayIp = dhcpGatewayIp.getIp6Address();
243 } else {
244 // removes gateway config
245 this.indirectDhcpGatewayIp = null;
246 }
247 }
248
249 public Optional<IpAddress> getIndirectDhcpServerIp() {
250 return Optional.ofNullable(indirectDhcpServerIp);
251 }
252
253
254 public Optional<IpAddress> getIndirectDhcpGatewayIp() {
255 return Optional.ofNullable(indirectDhcpGatewayIp);
256 }
257
258
259 public Optional<MacAddress> getIndirectDhcpConnectMac() {
260 return Optional.ofNullable(indirectDhcpConnectMac);
261 }
262
263
264 @Override
265 public void processDhcpPacket(PacketContext context, BasePacket payload) {
266 checkNotNull(payload, "DHCP6 payload can't be null");
267 checkState(payload instanceof DHCP6, "Payload is not a DHCP6");
268 DHCP6 dhcp6Payload = (DHCP6) payload;
269 Ethernet receivedPacket = context.inPacket().parsed();
270
271 if (!configured()) {
272 log.warn("Missing DHCP6 relay server config. Abort packet processing");
273 log.warn("dhcp6 payload {}", dhcp6Payload);
274
275 return;
276 }
277
278 byte msgType = dhcp6Payload.getMsgType();
279 log.warn("msgType is {}", msgType);
280
281 ConnectPoint inPort = context.inPacket().receivedFrom();
282 if (inPort == null) {
283 log.warn("incommin ConnectPoint is null");
284 }
285 Set<Interface> receivingInterfaces = interfaceService.getInterfacesByPort(inPort);
286 //ignore the packets if dhcp client interface is not configured on onos.
287 if (receivingInterfaces.isEmpty()) {
288 log.warn("Virtual interface is not configured on {}", inPort);
289 return;
290 }
291
292
293 if (MSG_TYPE_FROM_CLIENT.contains(msgType)) {
294
295 InternalPacket ethernetClientPacket =
296 processDhcp6PacketFromClient(context, receivedPacket, receivingInterfaces);
297 if (ethernetClientPacket != null) {
298 forwardPacket(ethernetClientPacket);
299 }
300
301 } else if (MSG_TYPE_FROM_SERVER.contains(msgType)) {
302 log.warn("calling processDhcp6PacketFromServer with RELAY_REPL", msgType);
303 InternalPacket ethernetPacketReply =
304 processDhcp6PacketFromServer(context, receivedPacket, receivingInterfaces);
305 if (ethernetPacketReply != null) {
306 forwardPacket(ethernetPacketReply);
307 }
308 } else {
309 log.warn("Not so fast, packet type {} not supported yet", msgType);
310 }
311 }
312
313
314 /**
315 * Checks if this app has been configured.
316 *
317 * @return true if all information we need have been initialized
318 */
319 public boolean configured() {
320 log.warn("dhcpServerConnectPoint {} dhcpServerIp {}",
321 this.dhcpServerConnectPoint, this.dhcpServerIp);
322 return this.dhcpServerConnectPoint != null && this.dhcpServerIp != null;
323 }
324
325 // the new class the contains Ethernet packet and destination port, kind of like adding
326 // internal header to the packet
327 private class InternalPacket {
328 Ethernet packet;
329 ConnectPoint destLocation;
330 public InternalPacket(Ethernet newPacket, ConnectPoint newLocation) {
331 packet = newPacket;
332 destLocation = newLocation;
333 }
334 void setLocation(ConnectPoint newLocation) {
335 destLocation = newLocation;
336 }
337 }
338
339 //forward the packet to ConnectPoint where the DHCP server is attached.
340 private void forwardPacket(InternalPacket packet) {
341 //send Packetout to dhcp server connectpoint.
342 if (packet.destLocation != null) {
343 TrafficTreatment t = DefaultTrafficTreatment.builder()
344 .setOutput(packet.destLocation.port()).build();
345 OutboundPacket o = new DefaultOutboundPacket(
346 packet.destLocation.deviceId(), t, ByteBuffer.wrap(packet.packet.serialize()));
347 if (log.isTraceEnabled()) {
348 log.trace("Relaying packet to destination {}", packet.destLocation);
349 }
350 packetService.emit(o);
351 } // if
352 }
353
354 /**
355 * Check if the host is directly connected to the network or not.
356 *
357 * @param dhcp6Payload the dhcp6 payload
358 * @return true if the host is directly connected to the network; false otherwise
359 */
360 private boolean directlyConnected(DHCP6 dhcp6Payload) {
361 log.debug("directlyConnected enters");
362
363 if (dhcp6Payload.getMsgType() != DHCP6.MsgType.RELAY_FORW.value() &&
364 dhcp6Payload.getMsgType() != DHCP6.MsgType.RELAY_REPL.value()) {
365 log.debug("directlyConnected true. MsgType {}", dhcp6Payload.getMsgType());
366
367 return true;
368 }
369
370 // Regardless of relay-forward or relay-replay, check if we see another relay message
371 DHCP6 dhcp6Payload2 = dhcp6PacketFromRelayPacket(dhcp6Payload);
372 if (dhcp6Payload2 != null) {
373 if (dhcp6Payload.getMsgType() == DHCP6.MsgType.RELAY_FORW.value()) {
374 log.debug("directlyConnected false. 1st realy-foward, 2nd MsgType {}", dhcp6Payload2.getMsgType());
375 return false;
376 } else {
377 // relay-reply
378 if (dhcp6Payload2.getMsgType() != DHCP6.MsgType.RELAY_REPL.value()) {
379 log.debug("directlyConnected true. 2nd MsgType {}", dhcp6Payload2.getMsgType());
380 return true; // must be directly connected
381 } else {
382 log.debug("directlyConnected false. 1st relay-reply, 2nd relay-reply MsgType {}",
383 dhcp6Payload2.getMsgType());
384 return false; // must be indirectly connected
385 }
386 }
387 } else {
388 log.warn("directlyConnected true.");
389 return true;
390 }
391 }
392
393 /**
394 * extract DHCP6 payload from dhcp6 relay message within relay-forwrd/reply.
395 *
396 * @param dhcp6 dhcp6 relay-reply or relay-foward
397 * @return dhcp6Packet dhcp6 packet extracted from relay-message
398 */
399 private DHCP6 dhcp6PacketFromRelayPacket(DHCP6 dhcp6) {
400 log.debug("dhcp6PacketFromRelayPacket enters. dhcp6 {}", dhcp6);
401
402 // extract the relay message if exist
403 DHCP6 dhcp6Payload = dhcp6.getOptions().stream()
404 .filter(opt -> opt instanceof Dhcp6RelayOption)
405 .map(BasePacket::getPayload)
406 .map(pld -> (DHCP6) pld)
407 .findFirst()
408 .orElse(null);
409
410
411 if (dhcp6Payload == null) {
412 // Can't find dhcp payload
413 log.debug("Can't find dhcp6 payload from relay message");
414 } else {
415 log.debug("dhcp6 payload found from relay message {}", dhcp6Payload);
416 }
417
418 return dhcp6Payload;
419 }
420
421 /**
422 * find the leaf DHCP6 packet from multi-level relay packet.
423 *
424 * @param relayPacket dhcp6 relay packet
425 * @return leafPacket non-relay dhcp6 packet
426 */
427 private DHCP6 getDhcp6Leaf(DHCP6 relayPacket) {
428 DHCP6 dhcp6Parent = relayPacket;
429 DHCP6 dhcp6Child = null;
430
431 log.debug("getDhcp6Leaf entered.");
432 while (dhcp6Parent != null) {
433 dhcp6Child = dhcp6PacketFromRelayPacket(dhcp6Parent);
434
435 if (dhcp6Child != null) {
436 if (dhcp6Child.getMsgType() != DHCP6.MsgType.RELAY_FORW.value() &&
437 dhcp6Child.getMsgType() != DHCP6.MsgType.RELAY_REPL.value()) {
438 log.debug("leaf dhcp6 packet found.");
439 break;
440 } else {
441 // found another relay
442 // go for another loop
443 dhcp6Parent = dhcp6Child;
444 }
445 } else {
446 log.warn("malformed pkt! Expected dhcp6 within relay pkt, but no dhcp6 leaf found.");
447 break;
448 }
449 }
450 return dhcp6Child;
451 }
452
453 /**
454 * check if DHCP6 relay-reply is reply.
455 *
456 * @param relayPacket dhcp6 relay-reply
457 * @return boolean relay-reply contains ack
458 */
459 private boolean isDhcp6Reply(DHCP6 relayPacket) {
460 log.debug("isDhcp6Reply entered.");
461
462 DHCP6 leafDhcp6 = getDhcp6Leaf(relayPacket);
463
464 if (leafDhcp6 != null) {
465 if (leafDhcp6.getMsgType() == DHCP6.MsgType.REPLY.value()) {
466 log.debug("isDhcp6Reply true.");
467 return true; // must be directly connected
468 } else {
469 log.debug("isDhcp6Reply false. leaf dhcp6 is not replay. MsgType {}", leafDhcp6.getMsgType());
470 }
471 } else {
472 log.debug("isDhcp6Reply false. Expected dhcp6 within relay pkt but not found.");
473 }
474 log.debug("isDhcp6Reply false.");
475 return false;
476 }
477
478 /**
479 * check if DHCP6 is release or relay-forward contains release.
480 *
481 * @param dhcp6Payload dhcp6 packet
482 * @return boolean dhcp6 contains release
483 */
484 private boolean isDhcp6Release(DHCP6 dhcp6Payload) {
485
486 log.debug("isDhcp6Release entered.");
487
488 if (dhcp6Payload.getMsgType() == DHCP6.MsgType.RELEASE.value()) {
489 log.debug("isDhcp6Release true.");
490 return true; // must be directly connected
491 } else {
492 DHCP6 dhcp6Leaf = getDhcp6Leaf(dhcp6Payload);
493 if (dhcp6Leaf != null) {
494 if (dhcp6Leaf.getMsgType() == DHCP6.MsgType.RELEASE.value()) {
495 log.debug("isDhcp6Release true. indirectlry connected");
496 return true;
497 } else {
498 log.debug("leaf dhcp6 is not release. MsgType {}", dhcp6Leaf.getMsgType());
499 return false;
500 }
501 } else {
502 log.debug("isDhcp6Release false. dhcp6 is niether relay nor release.");
503 return false;
504 }
505 }
506 }
507
508 /**
509 * extract from dhcp6 packet client ipv6 address of given by dhcp server.
510 *
511 * @param dhcp6 the dhcp6 packet
512 * @return Ip6Address Ip6Address given by dhcp server, or null if not exists
513 */
514 private Ip6Address extractIpAddress(DHCP6 dhcp6) {
515 Ip6Address ip = null;
516
517 log.debug("extractIpAddress enters dhcp6 {}.", dhcp6);
518 // Extract IPv6 address from IA NA ot IA TA option
519 Optional<Dhcp6IaNaOption> iaNaOption = dhcp6.getOptions()
520 .stream()
521 .filter(opt -> opt instanceof Dhcp6IaNaOption)
522 .map(opt -> (Dhcp6IaNaOption) opt)
523 .findFirst();
524 Optional<Dhcp6IaTaOption> iaTaOption = dhcp6.getOptions()
525 .stream()
526 .filter(opt -> opt instanceof Dhcp6IaTaOption)
527 .map(opt -> (Dhcp6IaTaOption) opt)
528 .findFirst();
529 Optional<Dhcp6IaAddressOption> iaAddressOption;
530 if (iaNaOption.isPresent()) {
531 log.debug("Found IPv6 address from iaNaOption {}", iaNaOption);
532
533 iaAddressOption = iaNaOption.get().getOptions().stream()
534 .filter(opt -> opt instanceof Dhcp6IaAddressOption)
535 .map(opt -> (Dhcp6IaAddressOption) opt)
536 .findFirst();
537 } else if (iaTaOption.isPresent()) {
538 log.debug("Found IPv6 address from iaTaOption {}", iaTaOption);
539
540 iaAddressOption = iaTaOption.get().getOptions().stream()
541 .filter(opt -> opt instanceof Dhcp6IaAddressOption)
542 .map(opt -> (Dhcp6IaAddressOption) opt)
543 .findFirst();
544 } else {
545 iaAddressOption = Optional.empty();
546 }
547 if (iaAddressOption.isPresent()) {
548 ip = iaAddressOption.get().getIp6Address();
549 log.debug("Found IPv6 address from iaAddressOption {}", iaAddressOption);
550
551
552 } else {
553 log.debug("Can't find IPv6 address from DHCPv6 {}", dhcp6);
554 }
555
556 return ip;
557 }
558 /**
559 * extract from dhcp6 packet Prefix prefix provided by dhcp server.
560 *
561 * @param dhcp6 the dhcp6 payload
562 * @return IpPrefix Prefix Delegation prefix, or null if not exists.
563 */
564 private IpPrefix extractPrefix(DHCP6 dhcp6) {
565 log.warn("extractPrefix enters {}", dhcp6);
566
567 // extract prefix
568 IpPrefix prefixPrefix = null;
569
570 Ip6Address prefixAddress = null;
571
572 // Extract IPv6 prefix from IA PD option
573 Optional<Dhcp6IaPdOption> iaPdOption = dhcp6.getOptions()
574 .stream()
575 .filter(opt -> opt instanceof Dhcp6IaPdOption)
576 .map(opt -> (Dhcp6IaPdOption) opt)
577 .findFirst();
578
579 Optional<Dhcp6IaPrefixOption> iaPrefixOption;
580 if (iaPdOption.isPresent()) {
581 log.warn("IA_PD option found {}", iaPdOption);
582
583 iaPrefixOption = iaPdOption.get().getOptions().stream()
584 .filter(opt -> opt instanceof Dhcp6IaPrefixOption)
585 .map(opt -> (Dhcp6IaPrefixOption) opt)
586 .findFirst();
587 } else {
588 log.warn("IA_PD option NOT found");
589
590 iaPrefixOption = Optional.empty();
591 }
592 if (iaPrefixOption.isPresent()) {
593 log.warn("IAPrefix Option within IA_PD option found {}", iaPrefixOption);
594
595 prefixAddress = iaPrefixOption.get().getIp6Prefix();
596 int prefixLen = (int) iaPrefixOption.get().getPrefixLength();
597 log.warn("Prefix length is {} bits", prefixLen);
598 prefixPrefix = IpPrefix.valueOf(prefixAddress, prefixLen);
599
600 } else {
601 log.warn("Can't find IPv6 prefix from DHCPv6 {}", dhcp6);
602 }
603
604 return prefixPrefix;
605 }
606
607 /**
608 * remove host or route.
609 *
610 * @param directConnFlag flag to show that packet is from directly connected client
611 * @param dhcp6Packet the dhcp6 payload
612 * @param clientPacket client's ethernet packet
613 * @param clientIpv6 client's Ipv6 packet
614 * @param clientInterfaces set of client interfaces
615 */
616 private void removeHostOrRoute(boolean directConnFlag, DHCP6 dhcp6Packet,
617 Ethernet clientPacket, IPv6 clientIpv6,
618 Set<Interface> clientInterfaces) {
619 log.debug("extractPrefix enters {}", dhcp6Packet);
620 // add host or route
621 if (isDhcp6Release(dhcp6Packet)) {
622 IpAddress ip = null;
623 if (directConnFlag) {
624 // Add to host store if it is connected to network directly
625 ip = extractIpAddress(dhcp6Packet);
626 if (ip != null) {
627 VlanId vlanId = clientInterfaces.iterator().next().vlan();
628 MacAddress clientMac = clientPacket.getSourceMAC();
629 HostId hostId = HostId.hostId(clientMac, vlanId);
630 log.debug("remove Host {} ip for directly connected.", hostId.toString());
631
632 log.debug("client mac {} client vlan {}", HexString.toHexString(clientMac.toBytes(), ":"), vlanId);
633
634
635 // Remove host's ip of when dhcp release msg is received
636 hostStore.removeIp(hostId, ip);
637 } else {
638 log.debug("ipAddress not found. Do not add Host for directly connected.");
639 }
640 } else {
641 // Remove from route store if it is not connected to network directly
642 IpAddress nextHopIp = IpAddress.valueOf(IpAddress.Version.INET6, clientIpv6.getSourceAddress());
643
644 DHCP6 leafDhcp = getDhcp6Leaf(dhcp6Packet);
645 ip = extractIpAddress(leafDhcp);
646 if (ip == null) {
647 log.debug("ip is null");
648 } else {
649 Route routeForIP = new Route(Route.Source.STATIC, ip.toIpPrefix(), nextHopIp);
650 log.debug("removing route of 128 address for indirectly connected.");
651 log.debug("128 ip {}, nexthop {}", HexString.toHexString(ip.toOctets(), ":"),
652 HexString.toHexString(nextHopIp.toOctets(), ":"));
653 routeStore.removeRoute(routeForIP);
654 }
655
656 IpPrefix ipPrefix = extractPrefix(leafDhcp);
657 if (ipPrefix == null) {
658 log.debug("ipPrefix is null ");
659 } else {
660 Route routeForPrefix = new Route(Route.Source.STATIC, ipPrefix, nextHopIp);
661 log.debug("removing route of PD for indirectly connected.");
662 log.debug("pd ip {}, nexthop {}", HexString.toHexString(ipPrefix.address().toOctets(), ":"),
663 HexString.toHexString(nextHopIp.toOctets(), ":"));
664
665 routeStore.removeRoute(routeForPrefix);
666 }
667 }
668 }
669 }
670
671 /**
672 * add host or route.
673 *
674 * @param directConnFlag flag to show that packet is from directly connected client
675 * @param dhcp6Relay the dhcp6 payload
676 * @param embeddedDhcp6 client's ethernet packetthe dhcp6 payload within relay
677 * @param clientMac client macAddress
678 * @param clientInterfaces set of client interfaces
679 */
680 private void addHostOrRoute(boolean directConnFlag, DHCP6 dhcp6Relay,
681 DHCP6 embeddedDhcp6,
682 MacAddress clientMac,
683 Set<Interface> clientInterfaces) {
684 log.debug("addHostOrRoute entered.");
685 // add host or route
686 if (isDhcp6Reply(dhcp6Relay)) {
687 IpAddress ip = null;
688 if (directConnFlag) {
689 // Add to host store if it connect to network directly
690 ip = extractIpAddress(embeddedDhcp6);
691 if (ip != null) {
692 Set<IpAddress> ips = Sets.newHashSet(ip);
693 VlanId vlanId = clientInterfaces.iterator().next().vlan();
694 HostId hostId = HostId.hostId(clientMac, vlanId);
695 HostLocation hostLocation = new HostLocation(clientInterfaces.iterator().next().connectPoint(),
696 System.currentTimeMillis());
697 HostDescription desc = new DefaultHostDescription(clientMac, vlanId,
698 hostLocation, ips);
699 log.debug("adding Host for directly connected.");
700 log.debug("client mac {} client vlan {} hostlocation {}",
701 HexString.toHexString(clientMac.toBytes(), ":"),
702 vlanId, hostLocation.toString());
703
704 // Replace the ip when dhcp server give the host new ip address
705 hostStore.createOrUpdateHost(DhcpRelayManager.PROVIDER_ID, hostId, desc, true);
706 } else {
707 log.warn("ipAddress not found. Do not add Host for directly connected.");
708 }
709 } else {
710 // Add to route store if it does not connect to network directly
711 IpAddress nextHopIp = IpAddress.valueOf(IpAddress.Version.INET6, dhcp6Relay.getPeerAddress());
712
713 DHCP6 leafDhcp = getDhcp6Leaf(embeddedDhcp6);
714 ip = extractIpAddress(leafDhcp);
715 if (ip == null) {
716 log.warn("ip is null");
717 } else {
718 Route routeForIP = new Route(Route.Source.STATIC, ip.toIpPrefix(), nextHopIp);
719 log.warn("adding Route of 128 address for indirectly connected.");
720 routeStore.updateRoute(routeForIP);
721 }
722
723 IpPrefix ipPrefix = extractPrefix(leafDhcp);
724 if (ipPrefix == null) {
725 log.warn("ipPrefix is null ");
726 } else {
727 Route routeForPrefix = new Route(Route.Source.STATIC, ipPrefix, nextHopIp);
728 log.warn("adding Route of PD for indirectly connected.");
729 routeStore.updateRoute(routeForPrefix);
730 }
731 }
732 }
733 }
734
735 /**
736 *
737 * build the DHCP6 solicit/request packet with gatewayip.
738 *
739 * @param context packet context
740 * @param clientPacket client ethernet packet
741 * @param clientInterfaces set of client side interfaces
742 */
743 private InternalPacket processDhcp6PacketFromClient(PacketContext context,
744 Ethernet clientPacket, Set<Interface> clientInterfaces) {
745 Ip6Address relayAgentIp = getRelayAgentIPv6Address(clientInterfaces);
746 MacAddress relayAgentMac = clientInterfaces.iterator().next().mac();
747 if (relayAgentIp == null || relayAgentMac == null) {
748 log.warn("Missing DHCP relay agent interface Ipv6 addr config for "
749 + "packet from client on port: {}. Aborting packet processing",
750 clientInterfaces.iterator().next().connectPoint());
751 return null;
752 }
753
754 // get dhcp6 header.
755
756 IPv6 clientIpv6 = (IPv6) clientPacket.getPayload();
757 UDP clientUdp = (UDP) clientIpv6.getPayload();
758 DHCP6 clientDhcp6 = (DHCP6) clientUdp.getPayload();
759
760 boolean directConnFlag = directlyConnected(clientDhcp6);
761
762 Ethernet etherReply = (Ethernet) clientPacket.clone();
763 etherReply.setSourceMACAddress(relayAgentMac);
764
765 if (directConnFlag && this.dhcpConnectMac == null) {
766 log.warn("DHCP6 {} not yet resolved .. Aborting DHCP "
767 + "packet processing from client on port: {}",
768 (this.dhcpGatewayIp == null) ? "server IP " + this.dhcpServerIp
769 : "gateway IP " + this.dhcpGatewayIp,
770 clientInterfaces.iterator().next().connectPoint());
771
772 return null;
773 }
774
775 if (!directConnFlag && this.indirectDhcpConnectMac == null) {
776 log.warn("DHCP6 {} not yet resolved .. Aborting DHCP "
777 + "packet processing from client on port: {}",
778 (this.indirectDhcpGatewayIp == null) ? "server IP " + this.indirectDhcpServerIp
779 : "gateway IP " + this.indirectDhcpGatewayIp,
780 clientInterfaces.iterator().next().connectPoint());
781
782 return null;
783
784 }
785
786 if (this.dhcpServerConnectPoint == null) {
787 log.warn("DHCP6 server connection point is not set up yet");
788 return null;
789 }
790
791 etherReply.setDestinationMACAddress(directConnFlag ? this.dhcpConnectMac : this.indirectDhcpConnectMac);
792 etherReply.setVlanID(directConnFlag ? this.dhcpConnectVlan.toShort() : this.indirectDhcpConnectVlan.toShort());
793
794 IPv6 ipv6Packet = (IPv6) etherReply.getPayload();
795 byte[] peerAddress = clientIpv6.getSourceAddress();
796 ipv6Packet.setSourceAddress(relayAgentIp.toOctets());
797 ipv6Packet.setDestinationAddress(directConnFlag ? this.dhcpServerIp.toOctets() :
798 this.indirectDhcpServerIp.toOctets());
799
800 UDP udpPacket = (UDP) ipv6Packet.getPayload();
801 udpPacket.setSourcePort(UDP.DHCP_V6_SERVER_PORT);
802 DHCP6 dhcp6Packet = (DHCP6) udpPacket.getPayload();
803 byte[] dhcp6PacketByte = dhcp6Packet.serialize();
804
805 // notify onos and quagga to release PD
806 //releasePD(dhcp6Packet);
807
808 removeHostOrRoute(directConnFlag, dhcp6Packet, clientPacket, clientIpv6, clientInterfaces);
809
810 DHCP6 dhcp6Relay = new DHCP6();
811 dhcp6Relay.setMsgType(DHCP6.MsgType.RELAY_FORW.value());
812 // link address: server uses the address to identify the link on which the client
813 // is located.
814 if (directConnFlag) {
815 dhcp6Relay.setLinkAddress(relayAgentIp.toOctets());
816 log.debug("direct connection: relayAgentIp obtained dynamically {}",
817 HexString.toHexString(relayAgentIp.toOctets(), ":"));
818
819 } else {
820 if (this.indirectRelayAgentIpFromCfg == null) {
821 dhcp6Relay.setLinkAddress(relayAgentIp.toOctets());
822 log.warn("indirect connection: relayAgentIp NOT availale from config file! {}",
823 HexString.toHexString(relayAgentIp.toOctets(), ":"));
824
825 } else {
826 dhcp6Relay.setLinkAddress(this.indirectRelayAgentIpFromCfg.toOctets());
827 log.debug("indirect connection: relayAgentIp from config file is available! {}",
828 HexString.toHexString(this.indirectRelayAgentIpFromCfg.toOctets(), ":"));
829 }
830 }
831
832 // peer address: address of the client or relay agent from which
833 // the message to be relayed was received.
834 dhcp6Relay.setPeerAddress(peerAddress);
835 List<Dhcp6Option> options = new ArrayList<Dhcp6Option>();
836
837 // directly connected case, hop count is zero
838 // otherwise, hop count + 1
839 if (directConnFlag) {
840 dhcp6Relay.setHopCount((byte) 0);
841 } else {
842 dhcp6Relay.setHopCount((byte) (dhcp6Packet.getHopCount() + 1));
843 }
844
845 // create relay message option
846 Dhcp6Option relayMessage = new Dhcp6Option();
847 relayMessage.setCode(DHCP6.OptionCode.RELAY_MSG.value());
848 relayMessage.setLength((short) dhcp6PacketByte.length);
849 relayMessage.setData(dhcp6PacketByte);
850 options.add(relayMessage);
851
852 // create interfaceId option
853 String inPortString = "-" + context.inPacket().receivedFrom().toString();
854 Dhcp6Option interfaceId = new Dhcp6Option();
855 interfaceId.setCode(DHCP6.OptionCode.INTERFACE_ID.value());
856 byte[] clientSoureMacBytes = clientPacket.getSourceMACAddress();
857 byte[] inPortStringBytes = inPortString.getBytes();
858 byte[] interfaceIdBytes = new byte[clientSoureMacBytes.length + inPortStringBytes.length];
859 log.debug("Length: interfaceIdBytes {} clientSoureMacBytes {} inPortStringBytes {} ",
860 interfaceIdBytes.length, clientSoureMacBytes.length, inPortStringBytes.length);
861
862 System.arraycopy(clientSoureMacBytes, 0, interfaceIdBytes, 0, clientSoureMacBytes.length);
863 System.arraycopy(inPortStringBytes, 0, interfaceIdBytes, clientSoureMacBytes.length, inPortStringBytes.length);
864
865 interfaceId.setData(interfaceIdBytes);
866 interfaceId.setLength((short) interfaceIdBytes.length);
867
868 options.add(interfaceId);
869
870 log.debug("interfaceId write srcMac {} portString {}",
871 HexString.toHexString(clientSoureMacBytes, ":"), inPortString);
872 dhcp6Relay.setOptions(options);
873 //dhcp6Packet.setPayload(dhcp6Relay);
874 //udpPacket.setPayload(dhcp6Packet);
875 udpPacket.setPayload(dhcp6Relay);
876 udpPacket.resetChecksum();
877 ipv6Packet.setPayload(udpPacket);
878 etherReply.setPayload(ipv6Packet);
879
880
881 return new InternalPacket(etherReply, this.dhcpServerConnectPoint);
882 }
883
884 /**
885 *
886 * process the DHCP6 relay-reply packet from dhcp server.
887 *
888 * @param context packet context
889 * @param receivedPacket server ethernet packet
890 * @param recevingInterfaces set of server side interfaces
891 */
892 private InternalPacket processDhcp6PacketFromServer(PacketContext context,
893 Ethernet receivedPacket, Set<Interface> recevingInterfaces) {
894 ConnectPoint inPort = context.inPacket().receivedFrom();
895 if (!inPort.equals(this.dhcpServerConnectPoint)) {
896 log.warn("Receiving port {} is not the same as server port {}",
897 inPort, this.dhcpServerConnectPoint);
898 return null;
899 }
900 // get dhcp6 header.
901 Ethernet etherReply = (Ethernet) receivedPacket.clone();
902 IPv6 ipv6Packet = (IPv6) etherReply.getPayload();
903 UDP udpPacket = (UDP) ipv6Packet.getPayload();
904 DHCP6 dhcp6Relay = (DHCP6) udpPacket.getPayload();
905
906 Boolean directConnFlag = directlyConnected(dhcp6Relay);
907
908 Dhcp6InterfaceIdOption interfaceIdOption = dhcp6Relay.getOptions().stream()
909 .filter(opt -> opt instanceof Dhcp6InterfaceIdOption)
910 .map(opt -> (Dhcp6InterfaceIdOption) opt)
911 .findFirst()
912 .orElse(null);
913
914 if (interfaceIdOption == null) {
915 log.warn("Interface Id option is not present, abort packet...");
916 return null;
917 }
918
919 MacAddress peerMac = interfaceIdOption.getMacAddress();
920 String clientConnectionPointStr = new String(interfaceIdOption.getInPort());
921
922 ConnectPoint clientConnectionPoint = ConnectPoint.deviceConnectPoint(clientConnectionPointStr);
923
924 Set<Interface> clientInterfaces = interfaceService.getInterfacesByPort(clientConnectionPoint);
925 if (clientInterfaces.isEmpty()) {
926 log.warn("Can not get client interface from packet, abort..");
927 return null;
928 }
929 MacAddress relayAgentMac = clientInterfaces.iterator().next().mac();
930 if (relayAgentMac == null) {
931 log.warn("Can not get interface mac, abort packet..");
932 return null;
933 }
934 etherReply.setSourceMACAddress(relayAgentMac);
935
936 // find destMac
937 MacAddress clientMac = null;
938 Set<Host> clients = hostService.getHostsByIp(Ip6Address.valueOf(dhcp6Relay.getPeerAddress()));
939 if (clients.isEmpty()) {
940 log.warn("There's no host found for this address {}",
941 HexString.toHexString(dhcp6Relay.getPeerAddress(), ":"));
942 log.warn("Let's look up interfaceId {}", HexString.toHexString(peerMac.toBytes(), ":"));
943 clientMac = peerMac;
944 } else {
945 clientMac = clients.iterator().next().mac();
946 if (clientMac == null) {
947 log.warn("No client mac address found, abort packet...");
948 return null;
949 }
950 log.warn("Client mac address found from getHostByIp");
951
952 }
953 etherReply.setDestinationMACAddress(clientMac);
954
955 // ip header
956 ipv6Packet.setSourceAddress(dhcp6Relay.getLinkAddress());
957 ipv6Packet.setDestinationAddress(dhcp6Relay.getPeerAddress());
958 // udp header
959 udpPacket.setSourcePort(UDP.DHCP_V6_SERVER_PORT);
960 if (directConnFlag) {
961 udpPacket.setDestinationPort(UDP.DHCP_V6_CLIENT_PORT);
962 } else {
963 udpPacket.setDestinationPort(UDP.DHCP_V6_SERVER_PORT);
964 }
965
966 DHCP6 embeddedDhcp6 = dhcp6Relay.getOptions().stream()
967 .filter(opt -> opt instanceof Dhcp6RelayOption)
968 .map(BasePacket::getPayload)
969 .map(pld -> (DHCP6) pld)
970 .findFirst()
971 .orElse(null);
972
973
974 // add host or route
975 addHostOrRoute(directConnFlag, dhcp6Relay, embeddedDhcp6, clientMac, clientInterfaces);
976
977 udpPacket.setPayload(embeddedDhcp6);
978 udpPacket.resetChecksum();
979 ipv6Packet.setPayload(udpPacket);
980 etherReply.setPayload(ipv6Packet);
981
982 return new InternalPacket(etherReply, clientConnectionPoint);
983 }
984
985 // Returns the first v4 interface ip out of a set of interfaces or null.
986 // Checks all interfaces, and ignores v6 interface ips
987 private Ip6Address getRelayAgentIPv6Address(Set<Interface> intfs) {
988 for (Interface intf : intfs) {
989 for (InterfaceIpAddress ip : intf.ipAddressesList()) {
990 Ip6Address relayAgentIp = ip.ipAddress().getIp6Address();
991 if (relayAgentIp != null) {
992 return relayAgentIp;
993 }
994 }
995 }
996 return null;
Yi Tseng51301292017-07-28 13:02:59 -0700997 }
Yi Tseng483ac6f2017-08-02 15:03:31 -0700998
999 @Override
1000 public void setDefaultDhcpServerConfigs(Collection<DhcpServerConfig> configs) {
Kalhee Kim45fede42017-09-05 19:05:06 +00001001 if (configs.size() == 0) {
1002 // no config to update
1003 return;
1004 }
1005
1006 // TODO: currently we pick up first DHCP server config.
1007 // Will use other server configs in the future for HA.
1008 DhcpServerConfig serverConfig = configs.iterator().next();
1009 if (!serverConfig.getDhcpServerConnectPoint().isPresent()) {
1010 log.warn("Connect point not exists");
1011 return;
1012 }
1013 if (!serverConfig.getDhcpServerIp6().isPresent()) {
1014 log.warn("IP of DHCP6 server not exists");
1015 return;
1016 }
1017 Ip6Address oldServerIp = this.dhcpServerIp;
1018 Ip6Address oldGatewayIp = this.dhcpGatewayIp;
1019
1020 // stop monitoring gateway or server
1021 if (oldGatewayIp != null) {
1022 hostService.stopMonitoringIp(oldGatewayIp);
1023 } else if (oldServerIp != null) {
1024 hostService.stopMonitoringIp(oldServerIp);
1025 }
1026
1027 this.dhcpServerConnectPoint = serverConfig.getDhcpServerConnectPoint().get();
1028 this.dhcpServerIp = serverConfig.getDhcpServerIp6().get();
1029 this.dhcpGatewayIp = serverConfig.getDhcpGatewayIp6().orElse(null);
1030 this.relayAgentIpFromCfg = serverConfig.getRelayAgentIp6().orElse(null);
1031
1032
1033 // reset server mac and vlan
1034 this.dhcpConnectMac = null;
1035 this.dhcpConnectVlan = null;
1036
1037 log.info("DHCP6 server connect point: " + this.dhcpServerConnectPoint);
1038 log.info("DHCP6 server IP: " + this.dhcpServerIp);
1039
1040 IpAddress ipToProbe = MoreObjects.firstNonNull(this.dhcpGatewayIp, this.dhcpServerIp);
1041 String hostToProbe = this.dhcpGatewayIp != null ? "gateway" : "DHCP6 server";
1042
1043 if (ipToProbe == null) {
1044 log.warn("Server IP6 not set, can't probe it");
1045 return;
1046 }
1047
1048 log.info("Probing to resolve {} IP6 {}", hostToProbe, ipToProbe);
1049 hostService.startMonitoringIp(ipToProbe);
1050
1051 Set<Host> hosts = hostService.getHostsByIp(ipToProbe);
1052 if (!hosts.isEmpty()) {
1053 Host host = hosts.iterator().next();
1054 this.dhcpConnectVlan = host.vlan();
1055 this.dhcpConnectMac = host.mac();
1056 }
Yi Tseng483ac6f2017-08-02 15:03:31 -07001057
1058 }
1059
1060 @Override
1061 public void setIndirectDhcpServerConfigs(Collection<DhcpServerConfig> configs) {
Kalhee Kim45fede42017-09-05 19:05:06 +00001062 if (configs.size() == 0) {
1063 // no config to update
1064 return;
1065 }
Yi Tseng483ac6f2017-08-02 15:03:31 -07001066
Kalhee Kim45fede42017-09-05 19:05:06 +00001067 // TODO: currently we pick up Second DHCP server config for indirect.
1068 // Will use other server configs in the future for HA.
1069 DhcpServerConfig serverConfig = configs.iterator().next();
1070 checkState(serverConfig.getDhcpServerConnectPoint().isPresent(),
1071 "Connect point not exists");
1072 checkState(serverConfig.getDhcpServerIp6().isPresent(),
1073 "IP of DHCP6 server not exists");
1074 Ip6Address oldServerIp = this.indirectDhcpServerIp;
1075 Ip6Address oldGatewayIp = this.indirectDhcpGatewayIp;
1076
1077 // stop monitoring gateway or server
1078 if (oldGatewayIp != null) {
1079 hostService.stopMonitoringIp(oldGatewayIp);
1080 } else if (oldServerIp != null) {
1081 hostService.stopMonitoringIp(oldServerIp);
1082 }
1083
1084 this.indirectDhcpServerConnectPoint = serverConfig.getDhcpServerConnectPoint().get();
1085 this.indirectDhcpServerIp = serverConfig.getDhcpServerIp6().get();
1086 this.indirectDhcpGatewayIp = serverConfig.getDhcpGatewayIp6().orElse(null);
1087 this.indirectRelayAgentIpFromCfg = serverConfig.getRelayAgentIp6().orElse(null);
1088
1089
1090 // reset server mac and vlan
1091 this.indirectDhcpConnectMac = null;
1092 this.indirectDhcpConnectVlan = null;
1093
1094 log.info("DHCP6 server connect point: " + this.indirectDhcpServerConnectPoint);
1095 log.info("DHCP6 server IP: " + this.indirectDhcpServerIp);
1096
1097 IpAddress ipToProbe = MoreObjects.firstNonNull(this.indirectDhcpGatewayIp, this.indirectDhcpServerIp);
1098 String hostToProbe = this.indirectDhcpGatewayIp != null ? "gateway" : "DHCP6 server";
1099
1100 if (ipToProbe == null) {
1101 log.warn("Server IP6 not set, can't probe it");
1102 return;
1103 }
1104
1105 log.info("Probing to resolve {} IP6 {}", hostToProbe, ipToProbe);
1106 hostService.startMonitoringIp(ipToProbe);
1107
1108 Set<Host> hosts = hostService.getHostsByIp(ipToProbe);
1109 if (!hosts.isEmpty()) {
1110 Host host = hosts.iterator().next();
1111 this.indirectDhcpConnectVlan = host.vlan();
1112 this.indirectDhcpConnectMac = host.mac();
1113 }
1114 }
1115
1116 class InternalHostListener implements HostListener {
1117 @Override
1118 public void event(HostEvent event) {
1119 switch (event.type()) {
1120 case HOST_ADDED:
1121 case HOST_UPDATED:
1122 hostUpdated(event.subject());
1123 break;
1124 case HOST_REMOVED:
1125 hostRemoved(event.subject());
1126 break;
1127 case HOST_MOVED:
1128 hostMoved(event.subject());
1129 break;
1130 default:
1131 break;
1132 }
1133 }
1134 }
1135
1136 /**
1137 * Handle host move.
1138 * If the host DHCP server or gateway and it moved to the location different
1139 * to user configured, unsets the connect mac and vlan
1140 *
1141 * @param host the host
1142 */
1143 private void hostMoved(Host host) {
1144 if (this.dhcpServerConnectPoint == null && this.indirectDhcpServerConnectPoint == null) {
1145 return;
1146 }
1147 if (this.dhcpGatewayIp != null) {
1148 if (host.ipAddresses().contains(this.dhcpGatewayIp) &&
1149 !host.locations().contains(this.dhcpServerConnectPoint)) {
1150 this.dhcpConnectMac = null;
1151 this.dhcpConnectVlan = null;
1152 }
1153 }
1154 if (this.dhcpServerIp != null) {
1155 if (host.ipAddresses().contains(this.dhcpServerIp) &&
1156 !host.locations().contains(this.dhcpServerConnectPoint)) {
1157 this.dhcpConnectMac = null;
1158 this.dhcpConnectVlan = null;
1159 }
1160 }
1161 if (this.indirectDhcpGatewayIp != null) {
1162 if (host.ipAddresses().contains(this.indirectDhcpGatewayIp) &&
1163 !host.locations().contains(this.indirectDhcpServerConnectPoint)) {
1164 this.indirectDhcpConnectMac = null;
1165 this.indirectDhcpConnectVlan = null;
1166 }
1167 }
1168 if (this.indirectDhcpServerIp != null) {
1169 if (host.ipAddresses().contains(this.indirectDhcpServerIp) &&
1170 !host.locations().contains(this.indirectDhcpServerConnectPoint)) {
1171 this.indirectDhcpConnectMac = null;
1172 this.indirectDhcpConnectVlan = null;
1173 }
1174 }
1175 }
1176
1177 /**
1178 * Handle host updated.
1179 * If the host is DHCP server or gateway, update connect mac and vlan.
1180 *
1181 * @param host the host
1182 */
1183 private void hostUpdated(Host host) {
1184 if (this.dhcpGatewayIp != null) {
1185 if (host.ipAddresses().contains(this.dhcpGatewayIp)) {
1186 this.dhcpConnectMac = host.mac();
1187 this.dhcpConnectVlan = host.vlan();
1188 }
1189 }
1190 if (this.dhcpServerIp != null) {
1191 if (host.ipAddresses().contains(this.dhcpServerIp)) {
1192 this.dhcpConnectMac = host.mac();
1193 this.dhcpConnectVlan = host.vlan();
1194 }
1195 }
1196 if (this.indirectDhcpGatewayIp != null) {
1197 if (host.ipAddresses().contains(this.indirectDhcpGatewayIp)) {
1198 this.indirectDhcpConnectMac = host.mac();
1199 this.indirectDhcpConnectVlan = host.vlan();
1200 }
1201 }
1202 if (this.indirectDhcpServerIp != null) {
1203 if (host.ipAddresses().contains(this.indirectDhcpServerIp)) {
1204 this.indirectDhcpConnectMac = host.mac();
1205 this.indirectDhcpConnectVlan = host.vlan();
1206 }
1207 }
1208 }
1209
1210 /**
1211 * Handle host removed.
1212 * If the host is DHCP server or gateway, unset connect mac and vlan.
1213 *
1214 * @param host the host
1215 */
1216 private void hostRemoved(Host host) {
1217 if (this.dhcpGatewayIp != null) {
1218 if (host.ipAddresses().contains(this.dhcpGatewayIp)) {
1219 this.dhcpConnectMac = null;
1220 this.dhcpConnectVlan = null;
1221 }
1222 //return;
1223 }
1224 if (this.dhcpServerIp != null) {
1225 if (host.ipAddresses().contains(this.dhcpServerIp)) {
1226 this.dhcpConnectMac = null;
1227 this.dhcpConnectVlan = null;
1228 }
1229 }
1230 if (this.indirectDhcpGatewayIp != null) {
1231 if (host.ipAddresses().contains(this.indirectDhcpGatewayIp)) {
1232 this.indirectDhcpConnectMac = null;
1233 this.indirectDhcpConnectVlan = null;
1234 }
1235 //return;
1236 }
1237 if (this.indirectDhcpServerIp != null) {
1238 if (host.ipAddresses().contains(this.indirectDhcpServerIp)) {
1239 this.indirectDhcpConnectMac = null;
1240 this.indirectDhcpConnectVlan = null;
1241 }
1242 }
Yi Tseng483ac6f2017-08-02 15:03:31 -07001243 }
Yi Tseng51301292017-07-28 13:02:59 -07001244}