Kalhee Kim | 495c9b2 | 2017-11-07 16:32:09 +0000 | [diff] [blame] | 1 | /* |
| 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 | package org.onosproject.dhcprelay; |
| 18 | |
| 19 | import org.onlab.packet.BasePacket; |
| 20 | import org.onlab.packet.DHCP6; |
| 21 | import org.onlab.packet.DHCP6.MsgType; |
| 22 | import org.onlab.packet.Ip6Address; |
| 23 | import org.onlab.packet.IpAddress; |
| 24 | import org.onlab.packet.VlanId; |
| 25 | import org.onlab.packet.dhcp.Dhcp6RelayOption; |
| 26 | import org.onlab.packet.dhcp.Dhcp6Option; |
| 27 | |
| 28 | import org.onlab.packet.Ethernet; |
| 29 | import org.onlab.packet.IPv6; |
| 30 | import org.onlab.packet.MacAddress; |
| 31 | import org.onlab.packet.UDP; |
| 32 | |
| 33 | import org.onlab.util.HexString; |
| 34 | import org.onosproject.dhcprelay.api.DhcpServerInfo; |
Kalhee Kim | d94ceea | 2017-11-29 19:03:02 +0000 | [diff] [blame^] | 35 | import org.onosproject.dhcprelay.store.DhcpRelayCounters; |
Kalhee Kim | 495c9b2 | 2017-11-07 16:32:09 +0000 | [diff] [blame] | 36 | import org.onosproject.net.ConnectPoint; |
| 37 | import org.onosproject.net.host.InterfaceIpAddress; |
| 38 | import org.onosproject.net.intf.Interface; |
| 39 | import org.onosproject.net.packet.PacketContext; |
| 40 | import org.onosproject.net.DeviceId; |
| 41 | |
| 42 | import org.slf4j.Logger; |
| 43 | import org.slf4j.LoggerFactory; |
| 44 | import java.util.Set; |
| 45 | import java.util.List; |
| 46 | import java.util.ArrayList; |
| 47 | |
| 48 | |
| 49 | |
| 50 | import static com.google.common.base.Preconditions.checkNotNull; |
| 51 | |
| 52 | |
| 53 | |
| 54 | public class Dhcp6HandlerUtil { |
| 55 | |
| 56 | private final Logger log = LoggerFactory.getLogger(getClass()); |
| 57 | // Returns the first v6 interface ip out of a set of interfaces or null. |
| 58 | // Checks all interfaces, and ignores v6 interface ips |
| 59 | public Ip6Address getRelayAgentIPv6Address(Set<Interface> intfs) { |
| 60 | for (Interface intf : intfs) { |
| 61 | for (InterfaceIpAddress ip : intf.ipAddressesList()) { |
| 62 | Ip6Address relayAgentIp = ip.ipAddress().getIp6Address(); |
| 63 | if (relayAgentIp != null) { |
| 64 | return relayAgentIp; |
| 65 | } |
| 66 | } |
| 67 | } |
| 68 | return null; |
| 69 | } |
| 70 | |
| 71 | /** |
| 72 | * Returns the first interface ip from interface. |
| 73 | * |
| 74 | * @param iface interface of one connect point |
| 75 | * @return the first interface IP; null if not exists an IP address in |
| 76 | * these interfaces |
| 77 | */ |
| 78 | public Ip6Address getFirstIpFromInterface(Interface iface) { |
| 79 | checkNotNull(iface, "Interface can't be null"); |
| 80 | return iface.ipAddressesList().stream() |
| 81 | .map(InterfaceIpAddress::ipAddress) |
| 82 | .filter(IpAddress::isIp6) |
| 83 | .map(IpAddress::getIp6Address) |
| 84 | .findFirst() |
| 85 | .orElse(null); |
| 86 | } |
| 87 | |
| 88 | /** |
| 89 | * extract DHCP6 payload from dhcp6 relay message within relay-forwrd/reply. |
| 90 | * |
| 91 | * @param dhcp6 dhcp6 relay-reply or relay-foward |
| 92 | * @return dhcp6Packet dhcp6 packet extracted from relay-message |
| 93 | */ |
| 94 | public DHCP6 dhcp6PacketFromRelayPacket(DHCP6 dhcp6) { |
| 95 | |
| 96 | // extract the relay message if exist |
| 97 | DHCP6 dhcp6Payload = dhcp6.getOptions().stream() |
| 98 | .filter(opt -> opt instanceof Dhcp6RelayOption) |
| 99 | .map(BasePacket::getPayload) |
| 100 | .map(pld -> (DHCP6) pld) |
| 101 | .findFirst() |
| 102 | .orElse(null); |
| 103 | if (dhcp6Payload == null) { |
| 104 | // Can't find dhcp payload |
| 105 | log.debug("Can't find dhcp6 payload from relay message"); |
| 106 | } else { |
| 107 | log.debug("dhcp6 payload found from relay message {}", dhcp6Payload); |
| 108 | } |
| 109 | return dhcp6Payload; |
| 110 | } |
| 111 | |
| 112 | /** |
| 113 | * find the leaf DHCP6 packet from multi-level relay packet. |
| 114 | * |
| 115 | * @param relayPacket dhcp6 relay packet |
| 116 | * @return leafPacket non-relay dhcp6 packet |
| 117 | */ |
| 118 | public DHCP6 getDhcp6Leaf(DHCP6 relayPacket) { |
| 119 | DHCP6 dhcp6Parent = relayPacket; |
| 120 | DHCP6 dhcp6Child = null; |
| 121 | |
| 122 | log.debug("getDhcp6Leaf entered."); |
| 123 | while (dhcp6Parent != null) { |
| 124 | dhcp6Child = dhcp6PacketFromRelayPacket(dhcp6Parent); |
| 125 | if (dhcp6Child != null) { |
| 126 | if (dhcp6Child.getMsgType() != DHCP6.MsgType.RELAY_FORW.value() && |
| 127 | dhcp6Child.getMsgType() != DHCP6.MsgType.RELAY_REPL.value()) { |
| 128 | log.debug("leaf dhcp6 packet found."); |
| 129 | break; |
| 130 | } else { |
| 131 | // found another relay, go for another loop |
| 132 | dhcp6Parent = dhcp6Child; |
| 133 | } |
| 134 | } else { |
| 135 | log.debug("Expected dhcp6 within relay pkt, but no dhcp6 leaf found."); |
| 136 | break; |
| 137 | } |
| 138 | } |
| 139 | return dhcp6Child; |
| 140 | } |
| 141 | |
| 142 | /** |
| 143 | * check if DHCP6 relay-reply is reply. |
| 144 | * |
| 145 | * @param relayPacket dhcp6 relay-reply |
| 146 | * @return boolean relay-reply contains ack |
| 147 | */ |
| 148 | public boolean isDhcp6Reply(DHCP6 relayPacket) { |
| 149 | DHCP6 leafDhcp6 = getDhcp6Leaf(relayPacket); |
| 150 | if (leafDhcp6 != null) { |
| 151 | if (leafDhcp6.getMsgType() == DHCP6.MsgType.REPLY.value()) { |
| 152 | log.debug("isDhcp6Reply true."); |
| 153 | return true; // must be directly connected |
| 154 | } else { |
| 155 | log.debug("isDhcp6Reply false. leaf dhcp6 is not replay. MsgType {}", leafDhcp6.getMsgType()); |
| 156 | } |
| 157 | } else { |
| 158 | log.debug("isDhcp6Reply false. Expected dhcp6 within relay pkt but not found."); |
| 159 | } |
| 160 | log.debug("isDhcp6Reply false."); |
| 161 | return false; |
| 162 | } |
| 163 | |
| 164 | /** |
| 165 | * check if DHCP6 is release or relay-forward contains release. |
| 166 | * |
| 167 | * @param dhcp6Payload dhcp6 packet |
| 168 | * @return boolean dhcp6 contains release |
| 169 | */ |
| 170 | public boolean isDhcp6Release(DHCP6 dhcp6Payload) { |
| 171 | if (dhcp6Payload.getMsgType() == DHCP6.MsgType.RELEASE.value()) { |
| 172 | log.debug("isDhcp6Release true."); |
| 173 | return true; // must be directly connected |
| 174 | } else { |
| 175 | DHCP6 dhcp6Leaf = getDhcp6Leaf(dhcp6Payload); |
| 176 | if (dhcp6Leaf != null) { |
| 177 | if (dhcp6Leaf.getMsgType() == DHCP6.MsgType.RELEASE.value()) { |
| 178 | log.debug("isDhcp6Release true. indirectlry connected"); |
| 179 | return true; |
| 180 | } else { |
| 181 | log.debug("leaf dhcp6 is not release. MsgType {}", dhcp6Leaf.getMsgType()); |
| 182 | return false; |
| 183 | } |
| 184 | } else { |
| 185 | log.debug("isDhcp6Release false. dhcp6 is niether relay nor release."); |
| 186 | return false; |
| 187 | } |
| 188 | } |
| 189 | } |
| 190 | |
| 191 | |
| 192 | /** |
| 193 | * convert dhcp6 msgType to String. |
| 194 | * |
| 195 | * @param msgTypeVal msgType byte of dhcp6 packet |
| 196 | * @return String string value of dhcp6 msg type |
| 197 | */ |
| 198 | public String getMsgTypeStr(byte msgTypeVal) { |
| 199 | MsgType msgType = DHCP6.MsgType.getType(msgTypeVal); |
| 200 | return DHCP6.MsgType.getMsgTypeStr(msgType); |
| 201 | } |
| 202 | |
| 203 | /** |
| 204 | * find the string of dhcp6 leaf packets's msg type. |
| 205 | * |
| 206 | * @param directConnFlag boolean value indicating direct/indirect connection |
| 207 | * @param dhcp6Packet dhcp6 packet |
| 208 | * @return String string value of dhcp6 leaf packet msg type |
| 209 | */ |
| 210 | public String findLeafMsgType(boolean directConnFlag, DHCP6 dhcp6Packet) { |
| 211 | if (directConnFlag) { |
| 212 | return getMsgTypeStr(dhcp6Packet.getMsgType()); |
| 213 | } else { |
| 214 | DHCP6 leafDhcp = getDhcp6Leaf(dhcp6Packet); |
| 215 | if (leafDhcp != null) { |
| 216 | return getMsgTypeStr(leafDhcp.getMsgType()); |
| 217 | } else { |
Kalhee Kim | d94ceea | 2017-11-29 19:03:02 +0000 | [diff] [blame^] | 218 | return DhcpRelayCounters.INVALID_PACKET; |
Kalhee Kim | 495c9b2 | 2017-11-07 16:32:09 +0000 | [diff] [blame] | 219 | } |
| 220 | } |
| 221 | } |
| 222 | |
| 223 | /** |
| 224 | * Determind if an Interface contains a vlan id. |
| 225 | * |
| 226 | * @param iface the Interface |
| 227 | * @param vlanId the vlan id |
| 228 | * @return true if the Interface contains the vlan id |
| 229 | */ |
| 230 | public boolean interfaceContainsVlan(Interface iface, VlanId vlanId) { |
| 231 | if (vlanId.equals(VlanId.NONE)) { |
| 232 | // untagged packet, check if vlan untagged or vlan native is not NONE |
| 233 | return !iface.vlanUntagged().equals(VlanId.NONE) || |
| 234 | !iface.vlanNative().equals(VlanId.NONE); |
| 235 | } |
| 236 | // tagged packet, check if the interface contains the vlan |
| 237 | return iface.vlanTagged().contains(vlanId); |
| 238 | } |
| 239 | |
| 240 | /** |
| 241 | * the new class the contains Ethernet packet and destination port. |
| 242 | */ |
| 243 | public class InternalPacket { |
| 244 | Ethernet packet; |
| 245 | ConnectPoint destLocation; |
| 246 | public InternalPacket(Ethernet newPacket, ConnectPoint newLocation) { |
| 247 | packet = newPacket; |
| 248 | destLocation = newLocation; |
| 249 | } |
| 250 | void setLocation(ConnectPoint newLocation) { |
| 251 | destLocation = newLocation; |
| 252 | } |
| 253 | } |
| 254 | /** |
| 255 | * Check if the host is directly connected to the network or not. |
| 256 | * |
| 257 | * @param dhcp6Payload the dhcp6 payload |
| 258 | * @return true if the host is directly connected to the network; false otherwise |
| 259 | */ |
| 260 | public boolean directlyConnected(DHCP6 dhcp6Payload) { |
| 261 | log.debug("directlyConnected enters"); |
| 262 | |
| 263 | if (dhcp6Payload.getMsgType() != DHCP6.MsgType.RELAY_FORW.value() && |
| 264 | dhcp6Payload.getMsgType() != DHCP6.MsgType.RELAY_REPL.value()) { |
| 265 | log.debug("directlyConnected true. MsgType {}", dhcp6Payload.getMsgType()); |
| 266 | |
| 267 | return true; |
| 268 | } |
| 269 | // Regardless of relay-forward or relay-replay, check if we see another relay message |
| 270 | DHCP6 dhcp6Payload2 = dhcp6PacketFromRelayPacket(dhcp6Payload); |
| 271 | if (dhcp6Payload2 != null) { |
| 272 | if (dhcp6Payload.getMsgType() == DHCP6.MsgType.RELAY_FORW.value()) { |
| 273 | log.debug("directlyConnected false. 1st realy-foward, 2nd MsgType {}", dhcp6Payload2.getMsgType()); |
| 274 | return false; |
| 275 | } else { |
| 276 | // relay-reply |
| 277 | if (dhcp6Payload2.getMsgType() != DHCP6.MsgType.RELAY_REPL.value()) { |
| 278 | log.debug("directlyConnected true. 2nd MsgType {}", dhcp6Payload2.getMsgType()); |
| 279 | return true; // must be directly connected |
| 280 | } else { |
| 281 | log.debug("directlyConnected false. 1st relay-reply, 2nd relay-reply MsgType {}", |
| 282 | dhcp6Payload2.getMsgType()); |
| 283 | return false; // must be indirectly connected |
| 284 | } |
| 285 | } |
| 286 | } else { |
| 287 | log.debug("directlyConnected true."); |
| 288 | return true; |
| 289 | } |
| 290 | } |
| 291 | /** |
| 292 | * Check if a given server info has v6 ipaddress. |
| 293 | * |
| 294 | * @param serverInfo server info to check |
| 295 | * @return true if server info has v6 ip address; false otherwise |
| 296 | */ |
| 297 | public boolean isServerIpEmpty(DhcpServerInfo serverInfo) { |
| 298 | if (!serverInfo.getDhcpServerIp6().isPresent()) { |
| 299 | log.warn("DhcpServerIp not available, use default DhcpServerIp {}", |
| 300 | HexString.toHexString(serverInfo.getDhcpServerIp6().get().toOctets())); |
| 301 | return true; |
| 302 | } |
| 303 | return false; |
| 304 | } |
| 305 | |
| 306 | private boolean isConnectMacEmpty(DhcpServerInfo serverInfo, Set<Interface> clientInterfaces) { |
| 307 | if (!serverInfo.getDhcpConnectMac().isPresent()) { |
| 308 | log.warn("DHCP6 {} not yet resolved .. Aborting DHCP " |
| 309 | + "packet processing from client on port: {}", |
| 310 | !serverInfo.getDhcpGatewayIp6().isPresent() ? "server IP " + serverInfo.getDhcpServerIp6() |
| 311 | : "gateway IP " + serverInfo.getDhcpGatewayIp6(), |
| 312 | clientInterfaces.iterator().next().connectPoint()); |
| 313 | return true; |
| 314 | } |
| 315 | return false; |
| 316 | } |
| 317 | |
| 318 | private boolean isRelayAgentIpFromCfgEmpty(DhcpServerInfo serverInfo, DeviceId receivedFromDevice) { |
| 319 | if (!serverInfo.getRelayAgentIp6(receivedFromDevice).isPresent()) { |
| 320 | log.warn("indirect connection: relayAgentIp NOT availale from config file! Use dynamic."); |
| 321 | return true; |
| 322 | } |
| 323 | return false; |
| 324 | } |
| 325 | |
| 326 | private Dhcp6Option getInterfaceIdIdOption(PacketContext context, Ethernet clientPacket) { |
| 327 | String inPortString = "-" + context.inPacket().receivedFrom().toString() + ":"; |
| 328 | Dhcp6Option interfaceId = new Dhcp6Option(); |
| 329 | interfaceId.setCode(DHCP6.OptionCode.INTERFACE_ID.value()); |
| 330 | byte[] clientSoureMacBytes = clientPacket.getSourceMACAddress(); |
| 331 | byte[] inPortStringBytes = inPortString.getBytes(); |
| 332 | byte[] vlanIdBytes = new byte[2]; |
| 333 | vlanIdBytes[0] = (byte) (clientPacket.getVlanID() & 0xff); |
| 334 | vlanIdBytes[1] = (byte) ((clientPacket.getVlanID() >> 8) & 0xff); |
| 335 | byte[] interfaceIdBytes = new byte[clientSoureMacBytes.length + |
| 336 | inPortStringBytes.length + vlanIdBytes.length]; |
| 337 | log.debug("Length: interfaceIdBytes {} clientSoureMacBytes {} inPortStringBytes {} vlan {}", |
| 338 | interfaceIdBytes.length, clientSoureMacBytes.length, inPortStringBytes.length, |
| 339 | vlanIdBytes.length); |
| 340 | |
| 341 | System.arraycopy(clientSoureMacBytes, 0, interfaceIdBytes, 0, clientSoureMacBytes.length); |
| 342 | System.arraycopy(inPortStringBytes, 0, interfaceIdBytes, clientSoureMacBytes.length, |
| 343 | inPortStringBytes.length); |
| 344 | System.arraycopy(vlanIdBytes, 0, interfaceIdBytes, |
| 345 | clientSoureMacBytes.length + inPortStringBytes.length, |
| 346 | vlanIdBytes.length); |
| 347 | interfaceId.setData(interfaceIdBytes); |
| 348 | interfaceId.setLength((short) interfaceIdBytes.length); |
| 349 | log.debug("interfaceId write srcMac {} portString {}", |
| 350 | HexString.toHexString(clientSoureMacBytes, ":"), inPortString); |
| 351 | return interfaceId; |
| 352 | } |
| 353 | |
| 354 | private void addDhcp6OptionsFromClient(List<Dhcp6Option> options, byte[] dhcp6PacketByte, |
| 355 | PacketContext context, Ethernet clientPacket) { |
| 356 | Dhcp6Option relayMessage = new Dhcp6Option(); |
| 357 | relayMessage.setCode(DHCP6.OptionCode.RELAY_MSG.value()); |
| 358 | relayMessage.setLength((short) dhcp6PacketByte.length); |
| 359 | relayMessage.setData(dhcp6PacketByte); |
| 360 | options.add(relayMessage); |
| 361 | // create interfaceId option |
| 362 | Dhcp6Option interfaceId = getInterfaceIdIdOption(context, clientPacket); |
| 363 | options.add(interfaceId); |
| 364 | } |
| 365 | |
| 366 | /** |
| 367 | * build the DHCP6 solicit/request packet with gatewayip. |
| 368 | * |
| 369 | * @param context packet context |
| 370 | * @param clientPacket client ethernet packet |
| 371 | * @param clientInterfaces set of client side interfaces |
| 372 | * @param serverInfo target server which a packet is generated for |
| 373 | * @param serverInterface target server interface |
| 374 | * @return ethernet packet with dhcp6 packet info |
| 375 | */ |
| 376 | public Ethernet buildDhcp6PacketFromClient(PacketContext context, Ethernet clientPacket, |
| 377 | Set<Interface> clientInterfaces, DhcpServerInfo serverInfo, |
| 378 | Interface serverInterface) { |
| 379 | ConnectPoint receivedFrom = context.inPacket().receivedFrom(); |
| 380 | DeviceId receivedFromDevice = receivedFrom.deviceId(); |
| 381 | |
| 382 | Ip6Address relayAgentIp = getRelayAgentIPv6Address(clientInterfaces); |
| 383 | MacAddress relayAgentMac = clientInterfaces.iterator().next().mac(); |
| 384 | if (relayAgentIp == null || relayAgentMac == null) { |
| 385 | log.warn("Missing DHCP relay agent interface Ipv6 addr config for " |
| 386 | + "packet from client on port: {}. Aborting packet processing", |
| 387 | clientInterfaces.iterator().next().connectPoint()); |
| 388 | return null; |
| 389 | } |
| 390 | IPv6 clientIpv6 = (IPv6) clientPacket.getPayload(); |
| 391 | UDP clientUdp = (UDP) clientIpv6.getPayload(); |
| 392 | DHCP6 clientDhcp6 = (DHCP6) clientUdp.getPayload(); |
| 393 | boolean directConnFlag = directlyConnected(clientDhcp6); |
| 394 | |
| 395 | Ip6Address serverIpFacing = getFirstIpFromInterface(serverInterface); |
| 396 | if (serverIpFacing == null || serverInterface.mac() == null) { |
| 397 | log.warn("No IP v6 address for server Interface {}", serverInterface); |
| 398 | return null; |
| 399 | } |
| 400 | |
| 401 | Ethernet etherReply = clientPacket.duplicate(); |
| 402 | etherReply.setSourceMACAddress(serverInterface.mac()); |
| 403 | |
| 404 | // set default info and replace with indirect if available later on. |
| 405 | if (serverInfo.getDhcpConnectMac().isPresent()) { |
| 406 | etherReply.setDestinationMACAddress(serverInfo.getDhcpConnectMac().get()); |
| 407 | } |
| 408 | if (serverInfo.getDhcpConnectVlan().isPresent()) { |
| 409 | etherReply.setVlanID(serverInfo.getDhcpConnectVlan().get().toShort()); |
| 410 | } |
| 411 | IPv6 ipv6Packet = (IPv6) etherReply.getPayload(); |
| 412 | byte[] peerAddress = clientIpv6.getSourceAddress(); |
| 413 | ipv6Packet.setSourceAddress(serverIpFacing.toOctets()); |
| 414 | ipv6Packet.setDestinationAddress(serverInfo.getDhcpServerIp6().get().toOctets()); |
| 415 | UDP udpPacket = (UDP) ipv6Packet.getPayload(); |
| 416 | udpPacket.setSourcePort(UDP.DHCP_V6_SERVER_PORT); |
| 417 | DHCP6 dhcp6Packet = (DHCP6) udpPacket.getPayload(); |
| 418 | byte[] dhcp6PacketByte = dhcp6Packet.serialize(); |
| 419 | |
| 420 | DHCP6 dhcp6Relay = new DHCP6(); |
| 421 | |
| 422 | dhcp6Relay.setMsgType(DHCP6.MsgType.RELAY_FORW.value()); |
| 423 | |
| 424 | if (directConnFlag) { |
| 425 | dhcp6Relay.setLinkAddress(relayAgentIp.toOctets()); |
| 426 | } else { |
| 427 | if (isServerIpEmpty(serverInfo)) { |
| 428 | log.warn("indirect DhcpServerIp empty... use default server "); |
| 429 | } else { |
| 430 | // Indirect case, replace destination to indirect dhcp server if exist |
| 431 | // Check if mac is obtained for valid server ip |
| 432 | if (isConnectMacEmpty(serverInfo, clientInterfaces)) { |
| 433 | log.warn("indirect Dhcp ConnectMac empty ..."); |
| 434 | return null; |
| 435 | } |
| 436 | etherReply.setDestinationMACAddress(serverInfo.getDhcpConnectMac().get()); |
| 437 | etherReply.setVlanID(serverInfo.getDhcpConnectVlan().get().toShort()); |
| 438 | ipv6Packet.setDestinationAddress(serverInfo.getDhcpServerIp6().get().toOctets()); |
| 439 | } |
| 440 | if (isRelayAgentIpFromCfgEmpty(serverInfo, receivedFromDevice)) { |
| 441 | dhcp6Relay.setLinkAddress(relayAgentIp.toOctets()); |
| 442 | log.debug("indirect connection: relayAgentIp NOT availale from config file! Use dynamic. {}", |
| 443 | HexString.toHexString(relayAgentIp.toOctets(), ":")); |
| 444 | } else { |
| 445 | dhcp6Relay.setLinkAddress(serverInfo.getRelayAgentIp6(receivedFromDevice).get().toOctets()); |
| 446 | } |
| 447 | } |
| 448 | // peer address: address of the client or relay agent from which the message to be relayed was received. |
| 449 | dhcp6Relay.setPeerAddress(peerAddress); |
| 450 | // directly connected case, hop count is zero; otherwise, hop count + 1 |
| 451 | if (directConnFlag) { |
| 452 | dhcp6Relay.setHopCount((byte) 0); |
| 453 | } else { |
| 454 | dhcp6Relay.setHopCount((byte) (dhcp6Packet.getHopCount() + 1)); |
| 455 | } |
| 456 | |
| 457 | List<Dhcp6Option> options = new ArrayList<>(); |
| 458 | addDhcp6OptionsFromClient(options, dhcp6PacketByte, context, clientPacket); |
| 459 | dhcp6Relay.setOptions(options); |
| 460 | udpPacket.setPayload(dhcp6Relay); |
| 461 | udpPacket.resetChecksum(); |
| 462 | ipv6Packet.setPayload(udpPacket); |
| 463 | ipv6Packet.setHopLimit((byte) 64); |
| 464 | etherReply.setPayload(ipv6Packet); |
| 465 | |
| 466 | return etherReply; |
| 467 | } |
| 468 | |
| 469 | /** |
| 470 | * build the DHCP6 solicit/request packet with gatewayip. |
| 471 | * |
| 472 | * @param directConnFlag flag indicating if packet is from direct client or not |
| 473 | * @param serverInfo server to check its connect point |
| 474 | * @return boolean true if serverInfo is found; false otherwise |
| 475 | */ |
| 476 | public boolean checkDhcpServerConnPt(boolean directConnFlag, |
| 477 | DhcpServerInfo serverInfo) { |
| 478 | if (serverInfo.getDhcpServerConnectPoint() == null) { |
| 479 | log.warn("DHCP6 server connect point for {} connPt {}", |
| 480 | directConnFlag ? "direct" : "indirect", serverInfo.getDhcpServerConnectPoint()); |
| 481 | return false; |
| 482 | } |
| 483 | return true; |
| 484 | } |
| 485 | } |