mirror of
https://github.com/opennetworkinglab/onos.git
synced 2025-10-16 18:02:05 +02:00
DHCPv6 Lease Query
Change-Id: I842deb7a09400504bec239fe49d2a627f00756c1
This commit is contained in:
parent
b29144d350
commit
a21c0ca852
@ -39,8 +39,11 @@ import org.onlab.packet.MacAddress;
|
|||||||
import org.onlab.packet.TpPort;
|
import org.onlab.packet.TpPort;
|
||||||
import org.onlab.packet.UDP;
|
import org.onlab.packet.UDP;
|
||||||
import org.onlab.packet.VlanId;
|
import org.onlab.packet.VlanId;
|
||||||
|
import org.onlab.packet.dhcp.Dhcp6ClientDataOption;
|
||||||
|
import org.onlab.packet.dhcp.Dhcp6LeaseQueryOption;
|
||||||
import org.onlab.packet.dhcp.Dhcp6RelayOption;
|
import org.onlab.packet.dhcp.Dhcp6RelayOption;
|
||||||
import org.onlab.packet.dhcp.Dhcp6InterfaceIdOption;
|
import org.onlab.packet.dhcp.Dhcp6InterfaceIdOption;
|
||||||
|
import org.onlab.packet.dhcp.Dhcp6Option;
|
||||||
import org.onlab.packet.dhcp.Dhcp6IaNaOption;
|
import org.onlab.packet.dhcp.Dhcp6IaNaOption;
|
||||||
import org.onlab.packet.dhcp.Dhcp6IaTaOption;
|
import org.onlab.packet.dhcp.Dhcp6IaTaOption;
|
||||||
import org.onlab.packet.dhcp.Dhcp6IaPdOption;
|
import org.onlab.packet.dhcp.Dhcp6IaPdOption;
|
||||||
@ -102,8 +105,6 @@ import org.slf4j.LoggerFactory;
|
|||||||
import org.onosproject.net.flow.DefaultTrafficTreatment;
|
import org.onosproject.net.flow.DefaultTrafficTreatment;
|
||||||
import org.onosproject.net.flow.TrafficTreatment;
|
import org.onosproject.net.flow.TrafficTreatment;
|
||||||
import org.onosproject.dhcprelay.Dhcp6HandlerUtil.InternalPacket;
|
import org.onosproject.dhcprelay.Dhcp6HandlerUtil.InternalPacket;
|
||||||
|
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@ -117,6 +118,7 @@ import static org.onosproject.net.flowobjective.Objective.Operation.ADD;
|
|||||||
import static org.onosproject.net.flowobjective.Objective.Operation.REMOVE;
|
import static org.onosproject.net.flowobjective.Objective.Operation.REMOVE;
|
||||||
import java.util.concurrent.Semaphore;
|
import java.util.concurrent.Semaphore;
|
||||||
|
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@Service
|
@Service
|
||||||
@Property(name = "version", value = "6")
|
@Property(name = "version", value = "6")
|
||||||
@ -139,9 +141,18 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider {
|
|||||||
.matchUdpSrc(TpPort.tpPort(UDP.DHCP_V6_SERVER_PORT))
|
.matchUdpSrc(TpPort.tpPort(UDP.DHCP_V6_SERVER_PORT))
|
||||||
.matchUdpDst(TpPort.tpPort(UDP.DHCP_V6_SERVER_PORT))
|
.matchUdpDst(TpPort.tpPort(UDP.DHCP_V6_SERVER_PORT))
|
||||||
.build();
|
.build();
|
||||||
|
// lease query reply is from server to client (no relay in between) - so we need to
|
||||||
|
// catch that scenario also ..
|
||||||
|
private static final TrafficSelector LEASE_QUERY_RESPONSE_SELECTOR = DefaultTrafficSelector.builder()
|
||||||
|
.matchEthType(Ethernet.TYPE_IPV6)
|
||||||
|
.matchIPProtocol(IPv6.PROTOCOL_UDP)
|
||||||
|
.matchUdpSrc(TpPort.tpPort(UDP.DHCP_V6_SERVER_PORT))
|
||||||
|
.matchUdpDst(TpPort.tpPort(UDP.DHCP_V6_CLIENT_PORT))
|
||||||
|
.build();
|
||||||
static final Set<TrafficSelector> DHCP_SELECTORS = ImmutableSet.of(
|
static final Set<TrafficSelector> DHCP_SELECTORS = ImmutableSet.of(
|
||||||
CLIENT_SERVER_SELECTOR,
|
CLIENT_SERVER_SELECTOR,
|
||||||
SERVER_RELAY_SELECTOR
|
SERVER_RELAY_SELECTOR,
|
||||||
|
LEASE_QUERY_RESPONSE_SELECTOR
|
||||||
);
|
);
|
||||||
private static Logger log = LoggerFactory.getLogger(Dhcp6HandlerImpl.class);
|
private static Logger log = LoggerFactory.getLogger(Dhcp6HandlerImpl.class);
|
||||||
|
|
||||||
@ -182,11 +193,8 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider {
|
|||||||
protected ApplicationId appId;
|
protected ApplicationId appId;
|
||||||
protected Multimap<DeviceId, VlanId> ignoredVlans = HashMultimap.create();
|
protected Multimap<DeviceId, VlanId> ignoredVlans = HashMultimap.create();
|
||||||
private InternalHostListener hostListener = new InternalHostListener();
|
private InternalHostListener hostListener = new InternalHostListener();
|
||||||
|
|
||||||
private Boolean dhcpFpmEnabled = false;
|
private Boolean dhcpFpmEnabled = false;
|
||||||
|
|
||||||
private Dhcp6HandlerUtil dhcp6HandlerUtil = new Dhcp6HandlerUtil();
|
private Dhcp6HandlerUtil dhcp6HandlerUtil = new Dhcp6HandlerUtil();
|
||||||
|
|
||||||
private List<DhcpServerInfo> defaultServerInfoList = Lists.newArrayList();
|
private List<DhcpServerInfo> defaultServerInfoList = Lists.newArrayList();
|
||||||
private List<DhcpServerInfo> indirectServerInfoList = Lists.newArrayList();
|
private List<DhcpServerInfo> indirectServerInfoList = Lists.newArrayList();
|
||||||
private class IpAddressInfo {
|
private class IpAddressInfo {
|
||||||
@ -211,10 +219,12 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider {
|
|||||||
DHCP6.MsgType.RELEASE.value(),
|
DHCP6.MsgType.RELEASE.value(),
|
||||||
DHCP6.MsgType.DECLINE.value(),
|
DHCP6.MsgType.DECLINE.value(),
|
||||||
DHCP6.MsgType.CONFIRM.value(),
|
DHCP6.MsgType.CONFIRM.value(),
|
||||||
DHCP6.MsgType.RELAY_FORW.value());
|
DHCP6.MsgType.RELAY_FORW.value(),
|
||||||
|
DHCP6.MsgType.LEASEQUERY.value());
|
||||||
// SERVER message types
|
// SERVER message types
|
||||||
public static final Set<Byte> MSG_TYPE_FROM_SERVER =
|
public static final Set<Byte> MSG_TYPE_FROM_SERVER =
|
||||||
ImmutableSet.of(DHCP6.MsgType.RELAY_REPL.value());
|
ImmutableSet.of(DHCP6.MsgType.RELAY_REPL.value(),
|
||||||
|
DHCP6.MsgType.LEASEQUERY_REPLY.value());
|
||||||
|
|
||||||
@Activate
|
@Activate
|
||||||
protected void activate() {
|
protected void activate() {
|
||||||
@ -267,7 +277,6 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider {
|
|||||||
}
|
}
|
||||||
processIgnoreVlanRule(deviceId, vlanId, ADD);
|
processIgnoreVlanRule(deviceId, vlanId, ADD);
|
||||||
});
|
});
|
||||||
|
|
||||||
ignoredVlans.forEach((deviceId, vlanId) -> {
|
ignoredVlans.forEach((deviceId, vlanId) -> {
|
||||||
if (!config.ignoredVlans().get(deviceId).contains(vlanId)) {
|
if (!config.ignoredVlans().get(deviceId).contains(vlanId)) {
|
||||||
// not contains in new config, remove it
|
// not contains in new config, remove it
|
||||||
@ -287,6 +296,160 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DhcpRecord getDhcpRelayRecordFor(Ip6Address clientAddress) {
|
||||||
|
|
||||||
|
Collection<DhcpRecord> records = dhcpRelayStore.getDhcpRecords();
|
||||||
|
DhcpRecord dr = null;
|
||||||
|
for (DhcpRecord e:records) {
|
||||||
|
if (e.ip6Address().isPresent()) {
|
||||||
|
if (e.ip6Address().get().equals(clientAddress)) {
|
||||||
|
dr = e;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MacAddress findNextHopMacForIp6FromRelayStore(Ip6Address clientAddress,
|
||||||
|
MacAddress clientMacAddress, VlanId vlanID) {
|
||||||
|
|
||||||
|
DhcpRecord dr = getDhcpRelayRecordFor(clientAddress);
|
||||||
|
|
||||||
|
if (dr != null) {
|
||||||
|
Optional<MacAddress> nextHopTempMac = dr.nextHopTemp();
|
||||||
|
if (nextHopTempMac.isPresent()) {
|
||||||
|
log.info("findNextHopForIp6FromRelayStore " + clientAddress + " got mac " + nextHopTempMac.toString());
|
||||||
|
return nextHopTempMac.get();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.warn("findNextHopMacForIp6FromRelayStore could NOT find next hop for " + clientAddress);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Ip6Address findNextHopIp6FromRelayStore(Ip6Address clientAddress) {
|
||||||
|
|
||||||
|
DhcpRecord dr = getDhcpRelayRecordFor(clientAddress);
|
||||||
|
if (dr != null) {
|
||||||
|
Optional<MacAddress> nextHopMac = dr.nextHop();
|
||||||
|
if (nextHopMac.isPresent()) {
|
||||||
|
// find the local ip6 from the host store
|
||||||
|
HostId gwHostId = HostId.hostId(nextHopMac.get(), dr.vlanId());
|
||||||
|
Host gwHost = hostService.getHost(gwHostId);
|
||||||
|
if (gwHost == null) {
|
||||||
|
log.warn("Can't find next hop host ID {}", gwHostId);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Ip6Address nextHopIp = gwHost.ipAddresses()
|
||||||
|
.stream()
|
||||||
|
.filter(IpAddress::isIp6)
|
||||||
|
.filter(IpAddress::isLinkLocal)
|
||||||
|
.map(IpAddress::getIp6Address)
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
|
||||||
|
log.info("findNextHopIp6FromRelayStore " + clientAddress + " got mac " +
|
||||||
|
nextHopMac.toString() + " ip6 " + nextHopIp);
|
||||||
|
return nextHopIp;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.warn("findNextHopIp6FromRelayStore could NOT find next hop for " + clientAddress);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setPotentialNextHopForIp6InRelayStore(Ip6Address clientAddress,
|
||||||
|
VlanId vlanId, MacAddress nh) {
|
||||||
|
DhcpRecord dr = getDhcpRelayRecordFor(clientAddress);
|
||||||
|
if (dr != null) {
|
||||||
|
dr.nextHopTemp(nh);
|
||||||
|
log.debug("LQ6 potential NH mac " + nh.toString() + " UPDATED in RelayRecord client " + clientAddress);
|
||||||
|
} else {
|
||||||
|
log.warn("LQ6 potential NH mac" + nh.toString() +
|
||||||
|
" NOT FOUND in RelayRecord for client - LQ rejected" + clientAddress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleLeaseQuery6ReplyMsg(PacketContext context, DHCP6 dhcp6Payload) {
|
||||||
|
ConnectPoint inPort = context.inPacket().receivedFrom();
|
||||||
|
log.info("Got LQV6-REPLY on port {}", inPort);
|
||||||
|
List<Dhcp6Option> lopt = dhcp6Payload.getOptions();
|
||||||
|
log.info("Options list: {}", lopt);
|
||||||
|
// find out if this lease is known is
|
||||||
|
Dhcp6ClientDataOption clientDataOption = dhcp6Payload.getOptions()
|
||||||
|
.stream()
|
||||||
|
.filter(opt -> opt instanceof Dhcp6ClientDataOption)
|
||||||
|
.map(pld -> (Dhcp6ClientDataOption) pld)
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
|
||||||
|
if (clientDataOption == null) {
|
||||||
|
log.warn("clientDataOption option is not present, " +
|
||||||
|
"lease is UNKNOWN - not adding any new route...");
|
||||||
|
} else {
|
||||||
|
Dhcp6IaAddressOption aiAddressOption = clientDataOption.getOptions()
|
||||||
|
.stream()
|
||||||
|
.filter(opt -> opt instanceof Dhcp6IaAddressOption)
|
||||||
|
.map(pld -> (Dhcp6IaAddressOption) pld)
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
|
||||||
|
Dhcp6ClientIdOption clientIdOption = clientDataOption.getOptions()
|
||||||
|
.stream()
|
||||||
|
.filter(opt -> opt instanceof Dhcp6ClientIdOption)
|
||||||
|
.map(pld -> (Dhcp6ClientIdOption) pld)
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
|
||||||
|
if (aiAddressOption == null) {
|
||||||
|
log.warn("clientDataOption from DHCP server does not " +
|
||||||
|
"contains Dhcp6IaAddressOption for the client - giving up...");
|
||||||
|
} else {
|
||||||
|
Ip6Address clientAddress = aiAddressOption.getIp6Address();
|
||||||
|
MacAddress clientMacAddress = MacAddress.valueOf(clientIdOption.getDuid().getLinkLayerAddress());
|
||||||
|
Ethernet packet = context.inPacket().parsed();
|
||||||
|
VlanId vlanId = VlanId.vlanId(packet.getVlanID());
|
||||||
|
MacAddress potentialNextHopMac =
|
||||||
|
findNextHopMacForIp6FromRelayStore(clientAddress, clientMacAddress, vlanId);
|
||||||
|
|
||||||
|
if (potentialNextHopMac == null) {
|
||||||
|
log.warn("Can't find next hop host mac for client {} mac:{}/{}",
|
||||||
|
clientAddress, clientMacAddress, vlanId);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
log.info("Next hop mac for {}/{}/{} is {}", clientAddress,
|
||||||
|
clientMacAddress, vlanId, potentialNextHopMac.toString());
|
||||||
|
}
|
||||||
|
// search the next hop in the hosts store
|
||||||
|
HostId gwHostId = HostId.hostId(potentialNextHopMac, vlanId);
|
||||||
|
Host gwHost = hostService.getHost(gwHostId);
|
||||||
|
if (gwHost == null) {
|
||||||
|
log.warn("Can't find next hop host ID {}", gwHostId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Ip6Address nextHopIp = gwHost.ipAddresses()
|
||||||
|
.stream()
|
||||||
|
.filter(IpAddress::isIp6)
|
||||||
|
.filter(IpAddress::isLinkLocal)
|
||||||
|
.map(IpAddress::getIp6Address)
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
if (nextHopIp == null) {
|
||||||
|
log.warn("Can't find IP6 address of next hop {}", gwHost);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
log.info("client " + clientAddress + " is known !");
|
||||||
|
Route routeForIP6 = new Route(Route.Source.STATIC, clientAddress.toIpPrefix(), nextHopIp);
|
||||||
|
log.debug("updating route of Client for indirectly connected.");
|
||||||
|
log.debug("client ip: " + clientAddress + ", next hop ip6: " + nextHopIp);
|
||||||
|
routeStore.updateRoute(routeForIP6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void processDhcpPacket(PacketContext context, BasePacket payload) {
|
public void processDhcpPacket(PacketContext context, BasePacket payload) {
|
||||||
checkNotNull(payload, "DHCP6 payload can't be null");
|
checkNotNull(payload, "DHCP6 payload can't be null");
|
||||||
@ -295,7 +458,8 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider {
|
|||||||
Ethernet receivedPacket = context.inPacket().parsed();
|
Ethernet receivedPacket = context.inPacket().parsed();
|
||||||
|
|
||||||
if (!configured()) {
|
if (!configured()) {
|
||||||
log.warn("Missing DHCP6 relay server config. Abort packet processing dhcp6 payload {}", dhcp6Payload);
|
log.warn("Missing DHCP6 relay server config. " +
|
||||||
|
"Abort packet processing dhcp6 payload {}", dhcp6Payload);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
byte msgTypeVal = dhcp6Payload.getMsgType();
|
byte msgTypeVal = dhcp6Payload.getMsgType();
|
||||||
@ -314,22 +478,47 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MSG_TYPE_FROM_CLIENT.contains(msgTypeVal)) {
|
if (msgTypeVal == DHCP6.MsgType.LEASEQUERY.value()) {
|
||||||
|
|
||||||
List<InternalPacket> ethernetClientPacket =
|
List<InternalPacket> ethernetClientPacket =
|
||||||
processDhcp6PacketFromClient(context, receivedPacket, receivingInterfaces);
|
processLQ6PacketFromClient(context, receivedPacket, receivingInterfaces, dhcp6Payload);
|
||||||
for (InternalPacket internalPacket : ethernetClientPacket) {
|
for (InternalPacket internalPacket : ethernetClientPacket) {
|
||||||
forwardPacket(internalPacket);
|
forwardPacket(internalPacket);
|
||||||
}
|
}
|
||||||
} else if (MSG_TYPE_FROM_SERVER.contains(msgTypeVal)) {
|
} else if (msgTypeVal == DHCP6.MsgType.LEASEQUERY_REPLY.value()) {
|
||||||
log.debug("calling processDhcp6PacketFromServer with RELAY_REPL {}", msgTypeVal);
|
|
||||||
|
IPv6 clientIpv6 = (IPv6) receivedPacket.getPayload();
|
||||||
|
UDP clientUdp = (UDP) clientIpv6.getPayload();
|
||||||
|
DHCP6 clientDhcp6 = (DHCP6) clientUdp.getPayload();
|
||||||
|
Interface serverInterface = dhcp6HandlerUtil.directlyConnected(clientDhcp6) ?
|
||||||
|
getServerInterface() : getIndirectServerInterface();
|
||||||
InternalPacket ethernetPacketReply =
|
InternalPacket ethernetPacketReply =
|
||||||
processDhcp6PacketFromServer(context, receivedPacket, receivingInterfaces);
|
dhcp6HandlerUtil.processLQ6PacketFromServer(
|
||||||
|
defaultServerInfoList, indirectServerInfoList,
|
||||||
|
serverInterface, interfaceService,
|
||||||
|
hostService,
|
||||||
|
context, receivedPacket, receivingInterfaces);
|
||||||
if (ethernetPacketReply != null) {
|
if (ethernetPacketReply != null) {
|
||||||
forwardPacket(ethernetPacketReply);
|
forwardPacket(ethernetPacketReply);
|
||||||
}
|
}
|
||||||
|
handleLeaseQuery6ReplyMsg(context, dhcp6Payload);
|
||||||
} else {
|
} else {
|
||||||
log.warn("Not so fast, packet type {} not supported yet", msgTypeVal);
|
if (MSG_TYPE_FROM_CLIENT.contains(msgTypeVal)) {
|
||||||
|
|
||||||
|
List<InternalPacket> ethernetClientPacket =
|
||||||
|
processDhcp6PacketFromClient(context, receivedPacket, receivingInterfaces);
|
||||||
|
for (InternalPacket internalPacket : ethernetClientPacket) {
|
||||||
|
forwardPacket(internalPacket);
|
||||||
|
}
|
||||||
|
} else if (MSG_TYPE_FROM_SERVER.contains(msgTypeVal)) {
|
||||||
|
log.debug("calling processDhcp6PacketFromServer with RELAY_REPL {}", msgTypeVal);
|
||||||
|
InternalPacket ethernetPacketReply =
|
||||||
|
processDhcp6PacketFromServer(context, receivedPacket, receivingInterfaces);
|
||||||
|
if (ethernetPacketReply != null) {
|
||||||
|
forwardPacket(ethernetPacketReply);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.warn("Not so fast, packet type {} not supported yet", msgTypeVal);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -352,8 +541,6 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider {
|
|||||||
// Do nothing here
|
// Do nothing here
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//forward the packet to ConnectPoint where the DHCP server is attached.
|
//forward the packet to ConnectPoint where the DHCP server is attached.
|
||||||
private void forwardPacket(InternalPacket packet) {
|
private void forwardPacket(InternalPacket packet) {
|
||||||
//send Packetout to dhcp server connectpoint.
|
//send Packetout to dhcp server connectpoint.
|
||||||
@ -369,9 +556,6 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider {
|
|||||||
} // if
|
} // if
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* extract from dhcp6 packet client ipv6 address of given by dhcp server.
|
* extract from dhcp6 packet client ipv6 address of given by dhcp server.
|
||||||
*
|
*
|
||||||
@ -422,6 +606,7 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider {
|
|||||||
}
|
}
|
||||||
return ipInfo;
|
return ipInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* extract from dhcp6 packet Prefix prefix provided by dhcp server.
|
* extract from dhcp6 packet Prefix prefix provided by dhcp server.
|
||||||
*
|
*
|
||||||
@ -500,6 +685,7 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider {
|
|||||||
|
|
||||||
return clientIdOption;
|
return clientIdOption;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* remove host or route and update dhcp relay record attributes.
|
* remove host or route and update dhcp relay record attributes.
|
||||||
*
|
*
|
||||||
@ -661,6 +847,7 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider {
|
|||||||
* @param embeddedDhcp6 the dhcp6 payload within relay
|
* @param embeddedDhcp6 the dhcp6 payload within relay
|
||||||
* @param srcMac client gw/host macAddress
|
* @param srcMac client gw/host macAddress
|
||||||
* @param clientInterface client interface
|
* @param clientInterface client interface
|
||||||
|
* @param dhcpServerIp6Address DHCP server IP
|
||||||
*/
|
*/
|
||||||
private void addHostOrRoute(boolean directConnFlag, ConnectPoint location, DHCP6 dhcp6Relay,
|
private void addHostOrRoute(boolean directConnFlag, ConnectPoint location, DHCP6 dhcp6Relay,
|
||||||
DHCP6 embeddedDhcp6, MacAddress srcMac, Interface clientInterface) {
|
DHCP6 embeddedDhcp6, MacAddress srcMac, Interface clientInterface) {
|
||||||
@ -774,11 +961,11 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider {
|
|||||||
if (leafMsgType == DHCP6.MsgType.REPLY.value()) {
|
if (leafMsgType == DHCP6.MsgType.REPLY.value()) {
|
||||||
if (ipInfo != null) {
|
if (ipInfo != null) {
|
||||||
log.debug("IP6 address is being stored into dhcp-relay store.");
|
log.debug("IP6 address is being stored into dhcp-relay store.");
|
||||||
log.debug("IP6 address {}", HexString.toHexString(ipInfo.ip6Address.toOctets(), ":"));
|
log.debug("Client IP6 address {}", HexString.toHexString(ipInfo.ip6Address.toOctets(), ":"));
|
||||||
record.ip6Address(ipInfo.ip6Address);
|
record.ip6Address(ipInfo.ip6Address);
|
||||||
record.updateAddrPrefTime(ipInfo.prefTime);
|
record.updateAddrPrefTime(ipInfo.prefTime);
|
||||||
record.updateLastIp6Update();
|
record.updateLastIp6Update();
|
||||||
} else {
|
} else {
|
||||||
log.debug("IP6 address is not returned from server. Maybe only PD is returned.");
|
log.debug("IP6 address is not returned from server. Maybe only PD is returned.");
|
||||||
}
|
}
|
||||||
if (pdInfo != null) {
|
if (pdInfo != null) {
|
||||||
@ -811,6 +998,103 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<InternalPacket> processLQ6PacketFromClient(PacketContext context,
|
||||||
|
Ethernet clientPacket,
|
||||||
|
Set<Interface> clientInterfaces,
|
||||||
|
DHCP6 dhcp6Payload) {
|
||||||
|
ConnectPoint inPort = context.inPacket().receivedFrom();
|
||||||
|
log.info("Got LQ-REQUEST V6 on port {}", inPort);
|
||||||
|
List<Dhcp6Option> lopt = dhcp6Payload.getOptions();
|
||||||
|
log.info("Options list: {}", lopt);
|
||||||
|
Dhcp6LeaseQueryOption lqoption = dhcp6Payload.getOptions()
|
||||||
|
.stream()
|
||||||
|
.filter(opt -> opt instanceof Dhcp6LeaseQueryOption)
|
||||||
|
.map(pld -> (Dhcp6LeaseQueryOption) pld)
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
|
||||||
|
if (lqoption == null) {
|
||||||
|
// Can't find dhcp payload
|
||||||
|
log.warn("Can't find dhcp6 lease query message - aborting");
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
log.info("dhcp6 lqv6 options found: {}", lqoption);
|
||||||
|
}
|
||||||
|
log.warn("LQv6 for " + lqoption.linkAddress.toString() + " comes from " + inPort.toString());
|
||||||
|
Ethernet packet = context.inPacket().parsed();
|
||||||
|
Ip6Address clientAddress = lqoption.linkAddress;
|
||||||
|
IPv6 ipv6Packet = (IPv6) packet.getPayload();
|
||||||
|
Ip6Address nextHopIp = findNextHopIp6FromRelayStore(clientAddress);
|
||||||
|
|
||||||
|
// 1. only if there is a route to remove - remove it
|
||||||
|
if (nextHopIp != null) {
|
||||||
|
Route routeForIP6 = new Route(Route.Source.STATIC, clientAddress.toIpPrefix(), nextHopIp);
|
||||||
|
log.debug("Removing route of Client " + clientAddress +
|
||||||
|
" for indirectly connected - next hop ip6 " + nextHopIp);
|
||||||
|
routeStore.removeRoute(routeForIP6);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. note the potential NH this packet came from in case it's a known lease
|
||||||
|
// this NH will then be used to build the route
|
||||||
|
MacAddress potentialNH = packet.getSourceMAC();
|
||||||
|
VlanId vlanId = VlanId.vlanId(packet.getVlanID());
|
||||||
|
setPotentialNextHopForIp6InRelayStore(clientAddress, vlanId, potentialNH);
|
||||||
|
|
||||||
|
// 3. route this LQ6 to all relevant servers
|
||||||
|
IPv6 clientIpv6 = (IPv6) clientPacket.getPayload();
|
||||||
|
UDP clientUdp = (UDP) clientIpv6.getPayload();
|
||||||
|
DHCP6 clientDhcp6 = (DHCP6) clientUdp.getPayload();
|
||||||
|
|
||||||
|
boolean directConnFlag = dhcp6HandlerUtil.directlyConnected(clientDhcp6);
|
||||||
|
|
||||||
|
ConnectPoint clientConnectionPoint = context.inPacket().receivedFrom();
|
||||||
|
VlanId vlanIdInUse = VlanId.vlanId(clientPacket.getVlanID());
|
||||||
|
Interface clientInterface = interfaceService.getInterfacesByPort(clientConnectionPoint)
|
||||||
|
.stream().filter(iface -> dhcp6HandlerUtil.interfaceContainsVlan(iface, vlanIdInUse))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
|
||||||
|
List<InternalPacket> internalPackets = new ArrayList<>();
|
||||||
|
List<DhcpServerInfo> serverInfoList = findValidServerInfo(directConnFlag);
|
||||||
|
List<DhcpServerInfo> copyServerInfoList = new ArrayList<DhcpServerInfo>(serverInfoList);
|
||||||
|
|
||||||
|
for (DhcpServerInfo serverInfo : copyServerInfoList) {
|
||||||
|
if (!dhcp6HandlerUtil.checkDhcpServerConnPt(directConnFlag, serverInfo)) {
|
||||||
|
log.warn("Can't get server connect point, ignore");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
DhcpServerInfo newServerInfo = getHostInfoForServerInfo(serverInfo, serverInfoList);
|
||||||
|
if (newServerInfo == null) {
|
||||||
|
log.warn("Can't get server interface with host info resolved, ignore");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Interface serverInterface = getServerInterface(newServerInfo);
|
||||||
|
if (serverInterface == null) {
|
||||||
|
log.warn("Can't get server interface, ignore");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Ethernet etherRouted = (Ethernet) clientPacket.clone();
|
||||||
|
MacAddress macFacingServer = serverInterface.mac();
|
||||||
|
if (macFacingServer == null) {
|
||||||
|
log.warn("No MAC address for server Interface {}", serverInterface);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
etherRouted.setSourceMACAddress(macFacingServer);
|
||||||
|
etherRouted.setDestinationMACAddress(newServerInfo.getDhcpConnectMac().get());
|
||||||
|
InternalPacket internalPacket =
|
||||||
|
new Dhcp6HandlerUtil().new InternalPacket(etherRouted,
|
||||||
|
serverInfo.getDhcpServerConnectPoint().get());
|
||||||
|
internalPackets.add(internalPacket);
|
||||||
|
log.debug("Sending LQ to DHCP server {}", newServerInfo.getDhcpServerIp6());
|
||||||
|
}
|
||||||
|
log.debug("num of client packets to send is{}", internalPackets.size());
|
||||||
|
|
||||||
|
return internalPackets;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* build the DHCP6 solicit/request packet with gatewayip.
|
* build the DHCP6 solicit/request packet with gatewayip.
|
||||||
*
|
*
|
||||||
@ -980,7 +1264,9 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider {
|
|||||||
udpPacket.setDestinationPort(UDP.DHCP_V6_SERVER_PORT);
|
udpPacket.setDestinationPort(UDP.DHCP_V6_SERVER_PORT);
|
||||||
}
|
}
|
||||||
// add host or route
|
// add host or route
|
||||||
addHostOrRoute(directConnFlag, clientConnectionPoint, dhcp6Relay, embeddedDhcp6, clientMac, clientInterface);
|
addHostOrRoute(directConnFlag, clientConnectionPoint, dhcp6Relay, embeddedDhcp6,
|
||||||
|
clientMac, clientInterface);
|
||||||
|
|
||||||
|
|
||||||
udpPacket.setPayload(embeddedDhcp6);
|
udpPacket.setPayload(embeddedDhcp6);
|
||||||
udpPacket.resetChecksum();
|
udpPacket.resetChecksum();
|
||||||
@ -989,6 +1275,19 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider {
|
|||||||
return new Dhcp6HandlerUtil().new InternalPacket(etherReply, clientConnectionPoint);
|
return new Dhcp6HandlerUtil().new InternalPacket(etherReply, clientConnectionPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns the first v6 interface ip out of a set of interfaces or null.
|
||||||
|
// Checks all interfaces, and ignores v6 interface ips
|
||||||
|
private Ip6Address getRelayAgentIPv6Address(Set<Interface> intfs) {
|
||||||
|
for (Interface intf : intfs) {
|
||||||
|
for (InterfaceIpAddress ip : intf.ipAddressesList()) {
|
||||||
|
Ip6Address relayAgentIp = ip.ipAddress().getIp6Address();
|
||||||
|
if (relayAgentIp != null) {
|
||||||
|
return relayAgentIp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setDhcpFpmEnabled(Boolean enabled) {
|
public void setDhcpFpmEnabled(Boolean enabled) {
|
||||||
@ -1131,7 +1430,6 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle host removed.
|
* Handle host removed.
|
||||||
* If the host is DHCP server or gateway, unset connect mac and vlan.
|
* If the host is DHCP server or gateway, unset connect mac and vlan.
|
||||||
@ -1181,6 +1479,65 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider {
|
|||||||
.findFirst()
|
.findFirst()
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets Interface facing to the server for default host.
|
||||||
|
*
|
||||||
|
* @return the Interface facing to the server; null if not found
|
||||||
|
*/
|
||||||
|
private Interface getServerInterface() {
|
||||||
|
DhcpServerInfo serverInfo;
|
||||||
|
ConnectPoint dhcpServerConnectPoint;
|
||||||
|
VlanId dhcpConnectVlan;
|
||||||
|
|
||||||
|
if (!defaultServerInfoList.isEmpty()) {
|
||||||
|
serverInfo = defaultServerInfoList.get(0);
|
||||||
|
dhcpServerConnectPoint = serverInfo.getDhcpServerConnectPoint().orElse(null);
|
||||||
|
dhcpConnectVlan = serverInfo.getDhcpConnectVlan().orElse(null);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (dhcpServerConnectPoint == null || dhcpConnectVlan == null) {
|
||||||
|
log.info("Default DHCP server {} not resolve yet", serverInfo.getDhcpGatewayIp6());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return interfaceService.getInterfacesByPort(dhcpServerConnectPoint)
|
||||||
|
.stream()
|
||||||
|
.filter(iface -> dhcp6HandlerUtil.interfaceContainsVlan(iface, dhcpConnectVlan))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets Interface facing to the server for indirect hosts.
|
||||||
|
* Use default server Interface if indirect server not configured.
|
||||||
|
*
|
||||||
|
* @return the Interface facing to the server; null if not found
|
||||||
|
*/
|
||||||
|
private Interface getIndirectServerInterface() {
|
||||||
|
DhcpServerInfo serverInfo;
|
||||||
|
|
||||||
|
ConnectPoint indirectDhcpServerConnectPoint;
|
||||||
|
VlanId indirectDhcpConnectVlan;
|
||||||
|
|
||||||
|
if (!indirectServerInfoList.isEmpty()) {
|
||||||
|
serverInfo = indirectServerInfoList.get(0);
|
||||||
|
indirectDhcpServerConnectPoint = serverInfo.getDhcpServerConnectPoint().orElse(null);
|
||||||
|
indirectDhcpConnectVlan = serverInfo.getDhcpConnectVlan().orElse(null);
|
||||||
|
} else {
|
||||||
|
return getServerInterface();
|
||||||
|
}
|
||||||
|
if (indirectDhcpServerConnectPoint == null || indirectDhcpConnectVlan == null) {
|
||||||
|
log.info("Indirect DHCP server {} not resolve yet", serverInfo.getDhcpGatewayIp6());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return interfaceService.getInterfacesByPort(indirectDhcpServerConnectPoint)
|
||||||
|
.stream()
|
||||||
|
.filter(iface -> dhcp6HandlerUtil.interfaceContainsVlan(iface, indirectDhcpConnectVlan))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if serverInfo's host info (mac and vlan) is filled in; if not, fills in.
|
* Checks if serverInfo's host info (mac and vlan) is filled in; if not, fills in.
|
||||||
*
|
*
|
||||||
@ -1256,15 +1613,16 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider {
|
|||||||
return serverInterface;
|
return serverInterface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void requestDhcpPacket(Ip6Address serverIp) {
|
private void requestDhcpPacket(Ip6Address serverIp) {
|
||||||
requestServerDhcpPacket(serverIp);
|
requestServerDhcpPacket(serverIp);
|
||||||
requestClientDhcpPacket(serverIp);
|
requestClientDhcpPacket(serverIp);
|
||||||
|
requestServerLQPacket(serverIp);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cancelDhcpPacket(Ip6Address serverIp) {
|
private void cancelDhcpPacket(Ip6Address serverIp) {
|
||||||
cancelServerDhcpPacket(serverIp);
|
cancelServerDhcpPacket(serverIp);
|
||||||
cancelClientDhcpPacket(serverIp);
|
cancelClientDhcpPacket(serverIp);
|
||||||
|
cancelServerLQPacket(serverIp);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cancelServerDhcpPacket(Ip6Address serverIp) {
|
private void cancelServerDhcpPacket(Ip6Address serverIp) {
|
||||||
@ -1277,6 +1635,16 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider {
|
|||||||
appId);
|
appId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void cancelServerLQPacket(Ip6Address serverIp) {
|
||||||
|
TrafficSelector serverSelector =
|
||||||
|
DefaultTrafficSelector.builder(LEASE_QUERY_RESPONSE_SELECTOR)
|
||||||
|
.matchIPv6Src(serverIp.toIpPrefix())
|
||||||
|
.build();
|
||||||
|
packetService.cancelPackets(serverSelector,
|
||||||
|
PacketPriority.CONTROL,
|
||||||
|
appId);
|
||||||
|
}
|
||||||
|
|
||||||
private void requestServerDhcpPacket(Ip6Address serverIp) {
|
private void requestServerDhcpPacket(Ip6Address serverIp) {
|
||||||
TrafficSelector serverSelector =
|
TrafficSelector serverSelector =
|
||||||
DefaultTrafficSelector.builder(SERVER_RELAY_SELECTOR)
|
DefaultTrafficSelector.builder(SERVER_RELAY_SELECTOR)
|
||||||
@ -1287,6 +1655,16 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider {
|
|||||||
appId);
|
appId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void requestServerLQPacket(Ip6Address serverIp) {
|
||||||
|
TrafficSelector serverSelector =
|
||||||
|
DefaultTrafficSelector.builder(LEASE_QUERY_RESPONSE_SELECTOR)
|
||||||
|
.matchIPv6Src(serverIp.toIpPrefix())
|
||||||
|
.build();
|
||||||
|
packetService.requestPackets(serverSelector,
|
||||||
|
PacketPriority.CONTROL,
|
||||||
|
appId);
|
||||||
|
}
|
||||||
|
|
||||||
private void cancelClientDhcpPacket(Ip6Address serverIp) {
|
private void cancelClientDhcpPacket(Ip6Address serverIp) {
|
||||||
// Packet comes from relay
|
// Packet comes from relay
|
||||||
TrafficSelector indirectClientSelector =
|
TrafficSelector indirectClientSelector =
|
||||||
@ -1419,6 +1797,7 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider {
|
|||||||
flowObjectiveService.apply(deviceId, fwd);
|
flowObjectiveService.apply(deviceId, fwd);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find first ipaddress for a given Host info i.e. mac and vlan.
|
* Find first ipaddress for a given Host info i.e. mac and vlan.
|
||||||
*
|
*
|
||||||
@ -1481,6 +1860,7 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider {
|
|||||||
}
|
}
|
||||||
return foundServerInfo;
|
return foundServerInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the dhcp6 lease expiry poll interval value.
|
* Set the dhcp6 lease expiry poll interval value.
|
||||||
*
|
*
|
||||||
|
@ -44,8 +44,11 @@ import org.slf4j.LoggerFactory;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import org.onosproject.net.intf.InterfaceService;
|
||||||
|
|
||||||
|
import org.onosproject.net.Host;
|
||||||
|
import org.onosproject.net.host.HostService;
|
||||||
|
import org.onosproject.net.HostLocation;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
@ -68,6 +71,127 @@ public class Dhcp6HandlerUtil {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* process the LQ reply packet from dhcp server.
|
||||||
|
*
|
||||||
|
* @param defaultServerInfoList default server list
|
||||||
|
* @param indirectServerInfoList default indirect server list
|
||||||
|
* @param serverInterface server interface
|
||||||
|
* @param interfaceService interface service
|
||||||
|
* @param hostService host service
|
||||||
|
* @param context packet context
|
||||||
|
* @param receivedPacket server ethernet packet
|
||||||
|
* @param recevingInterfaces set of server side interfaces
|
||||||
|
* @return a packet ready to be sent to relevant output interface
|
||||||
|
*/
|
||||||
|
public InternalPacket processLQ6PacketFromServer(
|
||||||
|
List<DhcpServerInfo> defaultServerInfoList,
|
||||||
|
List<DhcpServerInfo> indirectServerInfoList,
|
||||||
|
Interface serverInterface,
|
||||||
|
InterfaceService interfaceService,
|
||||||
|
HostService hostService,
|
||||||
|
PacketContext context,
|
||||||
|
Ethernet receivedPacket, Set<Interface> recevingInterfaces) {
|
||||||
|
// get dhcp6 header.
|
||||||
|
Ethernet etherReply = (Ethernet) receivedPacket.clone();
|
||||||
|
IPv6 ipv6Packet = (IPv6) etherReply.getPayload();
|
||||||
|
UDP udpPacket = (UDP) ipv6Packet.getPayload();
|
||||||
|
DHCP6 lq6Reply = (DHCP6) udpPacket.getPayload();
|
||||||
|
|
||||||
|
// TODO: refactor
|
||||||
|
ConnectPoint receivedFrom = context.inPacket().receivedFrom();
|
||||||
|
DeviceId receivedFromDevice = receivedFrom.deviceId();
|
||||||
|
DhcpServerInfo serverInfo;
|
||||||
|
Ip6Address dhcpServerIp = null;
|
||||||
|
ConnectPoint dhcpServerConnectPoint = null;
|
||||||
|
MacAddress dhcpConnectMac = null;
|
||||||
|
VlanId dhcpConnectVlan = null;
|
||||||
|
Ip6Address dhcpGatewayIp = null;
|
||||||
|
|
||||||
|
// todo: refactor
|
||||||
|
Ip6Address indirectDhcpServerIp = null;
|
||||||
|
ConnectPoint indirectDhcpServerConnectPoint = null;
|
||||||
|
MacAddress indirectDhcpConnectMac = null;
|
||||||
|
VlanId indirectDhcpConnectVlan = null;
|
||||||
|
Ip6Address indirectDhcpGatewayIp = null;
|
||||||
|
Ip6Address indirectRelayAgentIpFromCfg = null;
|
||||||
|
|
||||||
|
if (!defaultServerInfoList.isEmpty()) {
|
||||||
|
serverInfo = defaultServerInfoList.get(0);
|
||||||
|
dhcpConnectMac = serverInfo.getDhcpConnectMac().orElse(null);
|
||||||
|
dhcpGatewayIp = serverInfo.getDhcpGatewayIp6().orElse(null);
|
||||||
|
dhcpServerIp = serverInfo.getDhcpServerIp6().orElse(null);
|
||||||
|
dhcpServerConnectPoint = serverInfo.getDhcpServerConnectPoint().orElse(null);
|
||||||
|
dhcpConnectVlan = serverInfo.getDhcpConnectVlan().orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!indirectServerInfoList.isEmpty()) {
|
||||||
|
serverInfo = indirectServerInfoList.get(0);
|
||||||
|
indirectDhcpConnectMac = serverInfo.getDhcpConnectMac().orElse(null);
|
||||||
|
indirectDhcpGatewayIp = serverInfo.getDhcpGatewayIp6().orElse(null);
|
||||||
|
indirectDhcpServerIp = serverInfo.getDhcpServerIp6().orElse(null);
|
||||||
|
indirectDhcpServerConnectPoint = serverInfo.getDhcpServerConnectPoint().orElse(null);
|
||||||
|
indirectDhcpConnectVlan = serverInfo.getDhcpConnectVlan().orElse(null);
|
||||||
|
indirectRelayAgentIpFromCfg = serverInfo.getRelayAgentIp6(receivedFromDevice).orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
Boolean directConnFlag = directlyConnected(lq6Reply);
|
||||||
|
ConnectPoint inPort = context.inPacket().receivedFrom();
|
||||||
|
if ((directConnFlag || (!directConnFlag && indirectDhcpServerIp == null))
|
||||||
|
&& !inPort.equals(dhcpServerConnectPoint)) {
|
||||||
|
log.warn("Receiving port {} is not the same as server connect point {} for direct or indirect-null",
|
||||||
|
inPort, dhcpServerConnectPoint);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!directConnFlag && indirectDhcpServerIp != null &&
|
||||||
|
!inPort.equals(indirectDhcpServerConnectPoint)) {
|
||||||
|
log.warn("Receiving port {} is not the same as server connect point {} for indirect",
|
||||||
|
inPort, indirectDhcpServerConnectPoint);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Ip6Address nextHopIP = Ip6Address.valueOf(ipv6Packet.getDestinationAddress());
|
||||||
|
// use hosts store to find out the next hop mac and connection point
|
||||||
|
Set<Host> hosts = hostService.getHostsByIp(nextHopIP);
|
||||||
|
Host host;
|
||||||
|
if (!hosts.isEmpty()) {
|
||||||
|
host = hosts.iterator().next();
|
||||||
|
} else {
|
||||||
|
log.warn("Host {} is not in store", nextHopIP);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
HostLocation hl = host.location();
|
||||||
|
String clientConnectionPointStr = hl.toString(); // iterator().next());
|
||||||
|
ConnectPoint clientConnectionPoint = ConnectPoint.deviceConnectPoint(clientConnectionPointStr);
|
||||||
|
|
||||||
|
|
||||||
|
VlanId originalPacketVlanId = VlanId.vlanId(etherReply.getVlanID());
|
||||||
|
Interface iface;
|
||||||
|
iface = interfaceService.getInterfacesByPort(clientConnectionPoint)
|
||||||
|
.stream()
|
||||||
|
.filter(iface1 -> interfaceContainsVlan(iface1, originalPacketVlanId))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
|
||||||
|
etherReply.setSourceMACAddress(iface.mac());
|
||||||
|
etherReply.setDestinationMACAddress(host.mac());
|
||||||
|
|
||||||
|
|
||||||
|
// add host or route
|
||||||
|
//addHostOrRoute(directConnFlag, clientConnectionPoint, lq6Reply, embeddedDhcp6, clientMac, clientInterface);
|
||||||
|
// workaround for a bug where core sends src port as 547 (server)
|
||||||
|
udpPacket.setDestinationPort(UDP.DHCP_V6_SERVER_PORT);
|
||||||
|
udpPacket.setPayload(lq6Reply);
|
||||||
|
udpPacket.resetChecksum();
|
||||||
|
ipv6Packet.setPayload(udpPacket);
|
||||||
|
etherReply.setPayload(ipv6Packet);
|
||||||
|
|
||||||
|
return new Dhcp6HandlerUtil().new InternalPacket(etherReply, clientConnectionPoint);
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Returns the first interface ip from interface.
|
* Returns the first interface ip from interface.
|
||||||
*
|
*
|
||||||
@ -258,7 +382,14 @@ public class Dhcp6HandlerUtil {
|
|||||||
* @return true if the host is directly connected to the network; false otherwise
|
* @return true if the host is directly connected to the network; false otherwise
|
||||||
*/
|
*/
|
||||||
public boolean directlyConnected(DHCP6 dhcp6Payload) {
|
public boolean directlyConnected(DHCP6 dhcp6Payload) {
|
||||||
|
|
||||||
log.debug("directlyConnected enters");
|
log.debug("directlyConnected enters");
|
||||||
|
if (dhcp6Payload.getMsgType() == DHCP6.MsgType.LEASEQUERY.value() ||
|
||||||
|
dhcp6Payload.getMsgType() == DHCP6.MsgType.LEASEQUERY_REPLY.value()) {
|
||||||
|
log.debug("directlyConnected false. MsgType {}", dhcp6Payload.getMsgType());
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (dhcp6Payload.getMsgType() != DHCP6.MsgType.RELAY_FORW.value() &&
|
if (dhcp6Payload.getMsgType() != DHCP6.MsgType.RELAY_FORW.value() &&
|
||||||
dhcp6Payload.getMsgType() != DHCP6.MsgType.RELAY_REPL.value()) {
|
dhcp6Payload.getMsgType() != DHCP6.MsgType.RELAY_REPL.value()) {
|
||||||
|
@ -53,7 +53,6 @@ public class DhcpRecord {
|
|||||||
private IpPrefix pdPrefix;
|
private IpPrefix pdPrefix;
|
||||||
private DHCP6.MsgType ip6Status;
|
private DHCP6.MsgType ip6Status;
|
||||||
|
|
||||||
|
|
||||||
private long lastSeen;
|
private long lastSeen;
|
||||||
private long lastIp6Update;
|
private long lastIp6Update;
|
||||||
private long lastPdUpdate;
|
private long lastPdUpdate;
|
||||||
@ -418,7 +417,6 @@ public class DhcpRecord {
|
|||||||
newRecord.addrPrefTime = addrPrefTime;
|
newRecord.addrPrefTime = addrPrefTime;
|
||||||
newRecord.pdPrefTime = pdPrefTime;
|
newRecord.pdPrefTime = pdPrefTime;
|
||||||
newRecord.v6Counters = v6Counters;
|
newRecord.v6Counters = v6Counters;
|
||||||
|
|
||||||
return newRecord;
|
return newRecord;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,11 +19,13 @@ package org.onlab.packet;
|
|||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
import org.onlab.packet.dhcp.Dhcp6ClientDataOption;
|
||||||
import org.onlab.packet.dhcp.Dhcp6ClientIdOption;
|
import org.onlab.packet.dhcp.Dhcp6ClientIdOption;
|
||||||
import org.onlab.packet.dhcp.Dhcp6IaAddressOption;
|
import org.onlab.packet.dhcp.Dhcp6IaAddressOption;
|
||||||
import org.onlab.packet.dhcp.Dhcp6IaNaOption;
|
import org.onlab.packet.dhcp.Dhcp6IaNaOption;
|
||||||
import org.onlab.packet.dhcp.Dhcp6IaTaOption;
|
import org.onlab.packet.dhcp.Dhcp6IaTaOption;
|
||||||
import org.onlab.packet.dhcp.Dhcp6IaPdOption;
|
import org.onlab.packet.dhcp.Dhcp6IaPdOption;
|
||||||
|
import org.onlab.packet.dhcp.Dhcp6LeaseQueryOption;
|
||||||
import org.onlab.packet.dhcp.Dhcp6Option;
|
import org.onlab.packet.dhcp.Dhcp6Option;
|
||||||
import org.onlab.packet.dhcp.Dhcp6RelayOption;
|
import org.onlab.packet.dhcp.Dhcp6RelayOption;
|
||||||
import org.onlab.packet.dhcp.Dhcp6InterfaceIdOption;
|
import org.onlab.packet.dhcp.Dhcp6InterfaceIdOption;
|
||||||
@ -60,7 +62,12 @@ public class DHCP6 extends BasePacket {
|
|||||||
// Relay message types
|
// Relay message types
|
||||||
public static final Set<Byte> RELAY_MSG_TYPES =
|
public static final Set<Byte> RELAY_MSG_TYPES =
|
||||||
ImmutableSet.of(MsgType.RELAY_FORW.value,
|
ImmutableSet.of(MsgType.RELAY_FORW.value,
|
||||||
MsgType.RELAY_REPL.value);
|
MsgType.RELAY_REPL.value
|
||||||
|
);
|
||||||
|
public static final Set<Byte> LEASEQUERY_MSG_TYPES =
|
||||||
|
ImmutableSet.of(MsgType.LEASEQUERY.value,
|
||||||
|
MsgType.LEASEQUERY_REPLY.value
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DHCPv6 message type.
|
* DHCPv6 message type.
|
||||||
@ -70,7 +77,8 @@ public class DHCP6 extends BasePacket {
|
|||||||
CONFIRM((byte) 4), RENEW((byte) 5), REBIND((byte) 6),
|
CONFIRM((byte) 4), RENEW((byte) 5), REBIND((byte) 6),
|
||||||
REPLY((byte) 7), RELEASE((byte) 8), DECLINE((byte) 9),
|
REPLY((byte) 7), RELEASE((byte) 8), DECLINE((byte) 9),
|
||||||
RECONFIGURE((byte) 10), INFORMATION_REQUEST((byte) 11),
|
RECONFIGURE((byte) 10), INFORMATION_REQUEST((byte) 11),
|
||||||
RELAY_FORW((byte) 12), RELAY_REPL((byte) 13);
|
RELAY_FORW((byte) 12), RELAY_REPL((byte) 13), LEASEQUERY((byte) 14),
|
||||||
|
LEASEQUERY_REPLY((byte) 15);
|
||||||
|
|
||||||
protected byte value;
|
protected byte value;
|
||||||
MsgType(final byte value) {
|
MsgType(final byte value) {
|
||||||
@ -107,6 +115,10 @@ public class DHCP6 extends BasePacket {
|
|||||||
return RELAY_FORW;
|
return RELAY_FORW;
|
||||||
case 13:
|
case 13:
|
||||||
return RELAY_REPL;
|
return RELAY_REPL;
|
||||||
|
case 14:
|
||||||
|
return LEASEQUERY;
|
||||||
|
case 15:
|
||||||
|
return LEASEQUERY_REPLY;
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -155,7 +167,8 @@ public class DHCP6 extends BasePacket {
|
|||||||
STATUS_CODE((short) 13), RAPID_COMMIT((short) 14), USER_CLASS((short) 15),
|
STATUS_CODE((short) 13), RAPID_COMMIT((short) 14), USER_CLASS((short) 15),
|
||||||
VENDOR_CLASS((short) 16), VENDOR_OPTS((short) 17), INTERFACE_ID((short) 18),
|
VENDOR_CLASS((short) 16), VENDOR_OPTS((short) 17), INTERFACE_ID((short) 18),
|
||||||
RECONF_MSG((short) 19), RECONF_ACCEPT((short) 20), IA_PD((short) 25), IAPREFIX((short) 26),
|
RECONF_MSG((short) 19), RECONF_ACCEPT((short) 20), IA_PD((short) 25), IAPREFIX((short) 26),
|
||||||
SUBSCRIBER_ID((short) 38);
|
SUBSCRIBER_ID((short) 38), OPTION_ERO((short) 43), LEASE_QUERY((short) 44),
|
||||||
|
CLIENT_DATA((short) 45), CLIENT_LT((short) 48);
|
||||||
|
|
||||||
protected short value;
|
protected short value;
|
||||||
OptionCode(final short value) {
|
OptionCode(final short value) {
|
||||||
@ -175,6 +188,8 @@ public class DHCP6 extends BasePacket {
|
|||||||
.put(OptionCode.CLIENTID.value, Dhcp6ClientIdOption.deserializer())
|
.put(OptionCode.CLIENTID.value, Dhcp6ClientIdOption.deserializer())
|
||||||
.put(OptionCode.IA_PD.value, Dhcp6IaPdOption.deserializer())
|
.put(OptionCode.IA_PD.value, Dhcp6IaPdOption.deserializer())
|
||||||
.put(OptionCode.INTERFACE_ID.value, Dhcp6InterfaceIdOption.deserializer())
|
.put(OptionCode.INTERFACE_ID.value, Dhcp6InterfaceIdOption.deserializer())
|
||||||
|
.put(OptionCode.LEASE_QUERY.value, Dhcp6LeaseQueryOption.deserializer())
|
||||||
|
.put(OptionCode.CLIENT_DATA.value, Dhcp6ClientDataOption.deserializer())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// general field
|
// general field
|
||||||
|
@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017-present Open Networking Foundation
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.onlab.packet.dhcp;
|
||||||
|
|
||||||
|
import org.onlab.packet.DHCP6;
|
||||||
|
import org.onlab.packet.DeserializationException;
|
||||||
|
import org.onlab.packet.Deserializer;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public final class Dhcp6CLTOption extends Dhcp6Option {
|
||||||
|
public static final int DEFAULT_LEN = 4;
|
||||||
|
private int clt; // client last transaction time
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public short getCode() {
|
||||||
|
return DHCP6.OptionCode.CLIENT_LT.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public short getLength() {
|
||||||
|
return (short) (DEFAULT_LEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets Client Last Transaction Time.
|
||||||
|
*
|
||||||
|
* @return Client Last Transaction Time
|
||||||
|
*/
|
||||||
|
public int getClt() {
|
||||||
|
return clt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets Identity Association ID.
|
||||||
|
*
|
||||||
|
* @param clt the Client Last Transaction Time.
|
||||||
|
*/
|
||||||
|
public void setClt(int clt) {
|
||||||
|
this.clt = clt;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default constructor.
|
||||||
|
*/
|
||||||
|
public Dhcp6CLTOption() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a DHCPv6 Client Last Transaction Time option.
|
||||||
|
*
|
||||||
|
* @param dhcp6Option the DHCPv6 option
|
||||||
|
*/
|
||||||
|
public Dhcp6CLTOption(Dhcp6Option dhcp6Option) {
|
||||||
|
super(dhcp6Option);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets deserializer.
|
||||||
|
*
|
||||||
|
* @return the deserializer
|
||||||
|
*/
|
||||||
|
public static Deserializer<Dhcp6Option> deserializer() {
|
||||||
|
return (data, offset, length) -> {
|
||||||
|
Dhcp6Option dhcp6Option =
|
||||||
|
Dhcp6Option.deserializer().deserialize(data, offset, length);
|
||||||
|
if (dhcp6Option.getLength() < DEFAULT_LEN) {
|
||||||
|
throw new DeserializationException("Invalid CLT option data");
|
||||||
|
}
|
||||||
|
Dhcp6CLTOption cltOption = new Dhcp6CLTOption(dhcp6Option);
|
||||||
|
byte[] optionData = cltOption.getData();
|
||||||
|
ByteBuffer bb = ByteBuffer.wrap(optionData);
|
||||||
|
cltOption.clt = bb.getInt();
|
||||||
|
|
||||||
|
return cltOption;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] serialize() {
|
||||||
|
int payloadLen = DEFAULT_LEN;
|
||||||
|
int len = Dhcp6Option.DEFAULT_LEN + payloadLen;
|
||||||
|
ByteBuffer bb = ByteBuffer.allocate(len);
|
||||||
|
bb.putShort(DHCP6.OptionCode.CLIENT_LT.value());
|
||||||
|
bb.putShort((short) payloadLen);
|
||||||
|
bb.putInt(clt);
|
||||||
|
return bb.array();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return getToStringHelper()
|
||||||
|
.add("clt", clt)
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(super.hashCode(), clt);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!(obj instanceof Dhcp6CLTOption)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!super.equals(obj)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final Dhcp6CLTOption other = (Dhcp6CLTOption) obj;
|
||||||
|
|
||||||
|
return Objects.equals(getCode(), other.getCode()) &&
|
||||||
|
Objects.equals(getLength(), other.getLength()) &&
|
||||||
|
Objects.equals(clt, other.clt);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,161 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017-present Open Networking Foundation
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.onlab.packet.dhcp;
|
||||||
|
|
||||||
|
import com.google.common.base.MoreObjects;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import org.onlab.packet.DHCP6;
|
||||||
|
import org.onlab.packet.DeserializationException;
|
||||||
|
import org.onlab.packet.Deserializer;
|
||||||
|
import org.onlab.packet.Ip6Address;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DHCPv6 Client Data Option.
|
||||||
|
*/
|
||||||
|
public final class Dhcp6ClientDataOption extends Dhcp6Option {
|
||||||
|
private List<Dhcp6Option> options;
|
||||||
|
private Ip6Address clientIaAddress;
|
||||||
|
public static final int DEFAULT_LEN = 1 + 16;
|
||||||
|
|
||||||
|
public Dhcp6ClientDataOption(Dhcp6Option dhcp6Option) {
|
||||||
|
super(dhcp6Option);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public short getCode() {
|
||||||
|
return DHCP6.OptionCode.CLIENT_DATA.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public short getLength() {
|
||||||
|
//return (short) (DEFAULT_LEN + options.stream()
|
||||||
|
// .mapToInt(opt -> (int) opt.getLength() + Dhcp6Option.DEFAULT_LEN)
|
||||||
|
// .sum());
|
||||||
|
return (short) payload.serialize().length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getData() {
|
||||||
|
return payload.serialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Dhcp6Option> getOptions() {
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Ip6Address getIaAddress() {
|
||||||
|
return clientIaAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Deserializer<Dhcp6Option> deserializer() {
|
||||||
|
return (data, offset, length) -> {
|
||||||
|
Dhcp6Option dhcp6Option = Dhcp6Option.deserializer().deserialize(data, offset, length);
|
||||||
|
Dhcp6ClientDataOption clientData = new Dhcp6ClientDataOption(dhcp6Option);
|
||||||
|
|
||||||
|
if (dhcp6Option.getLength() < DEFAULT_LEN) {
|
||||||
|
throw new DeserializationException("Invalid length of Client Id option");
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] optionData = clientData.getData();
|
||||||
|
|
||||||
|
clientData.options = Lists.newArrayList();
|
||||||
|
|
||||||
|
ByteBuffer bb = ByteBuffer.wrap(optionData);
|
||||||
|
|
||||||
|
while (bb.remaining() >= Dhcp6Option.DEFAULT_LEN) {
|
||||||
|
Dhcp6Option option;
|
||||||
|
ByteBuffer optByteBuffer = ByteBuffer.wrap(optionData,
|
||||||
|
bb.position(),
|
||||||
|
optionData.length - bb.position());
|
||||||
|
short code = optByteBuffer.getShort();
|
||||||
|
short len = optByteBuffer.getShort();
|
||||||
|
int optLen = UNSIGNED_SHORT_MASK & len;
|
||||||
|
byte[] subOptData = new byte[Dhcp6Option.DEFAULT_LEN + optLen];
|
||||||
|
bb.get(subOptData);
|
||||||
|
|
||||||
|
// TODO: put more sub-options?
|
||||||
|
if (code == DHCP6.OptionCode.IAADDR.value()) {
|
||||||
|
option = Dhcp6IaAddressOption.deserializer()
|
||||||
|
.deserialize(subOptData, 0, subOptData.length);
|
||||||
|
clientData.clientIaAddress = ((Dhcp6IaAddressOption) option).getIp6Address();
|
||||||
|
} else if (code == DHCP6.OptionCode.CLIENTID.value()) {
|
||||||
|
option = Dhcp6ClientIdOption.deserializer()
|
||||||
|
.deserialize(subOptData, 0, subOptData.length);
|
||||||
|
} else if (code == DHCP6.OptionCode.CLIENT_LT.value()) {
|
||||||
|
option = Dhcp6CLTOption.deserializer()
|
||||||
|
.deserialize(subOptData, 0, subOptData.length);
|
||||||
|
} else {
|
||||||
|
option = Dhcp6Option.deserializer()
|
||||||
|
.deserialize(subOptData, 0, subOptData.length);
|
||||||
|
}
|
||||||
|
clientData.options.add(option);
|
||||||
|
}
|
||||||
|
return clientData;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] serialize() {
|
||||||
|
ByteBuffer bb = ByteBuffer.allocate(this.getLength() + Dhcp6Option.DEFAULT_LEN);
|
||||||
|
bb.putShort(getCode());
|
||||||
|
bb.putShort(getLength());
|
||||||
|
bb.put(payload.serialize());
|
||||||
|
return bb.array();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return MoreObjects.toStringHelper(getClass())
|
||||||
|
.add("code", getCode())
|
||||||
|
.add("length", getLength())
|
||||||
|
.add("clientAddr", getIaAddress())
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(super.hashCode(), clientIaAddress, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!(obj instanceof Dhcp6ClientDataOption)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!super.equals(obj)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final Dhcp6ClientDataOption other = (Dhcp6ClientDataOption) obj;
|
||||||
|
|
||||||
|
return Objects.equals(getCode(), other.getCode()) &&
|
||||||
|
Objects.equals(getLength(), other.getLength()) &&
|
||||||
|
Objects.equals(clientIaAddress, other.clientIaAddress) &&
|
||||||
|
Objects.equals(options, other.options);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,153 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017-present Open Networking Foundation
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.onlab.packet.dhcp;
|
||||||
|
|
||||||
|
import com.google.common.base.MoreObjects;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import org.onlab.packet.DHCP6;
|
||||||
|
import org.onlab.packet.Deserializer;
|
||||||
|
import org.onlab.packet.Ip6Address;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DHCPv6 Lease Query Option.
|
||||||
|
*/
|
||||||
|
public final class Dhcp6LeaseQueryOption extends Dhcp6Option {
|
||||||
|
|
||||||
|
public static final int DEFAULT_LEN = 1 + 16;
|
||||||
|
//public short QueryType;
|
||||||
|
public Ip6Address linkAddress;
|
||||||
|
private List<Dhcp6Option> options;
|
||||||
|
|
||||||
|
public Dhcp6LeaseQueryOption(Dhcp6Option dhcp6Option) {
|
||||||
|
super(dhcp6Option);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public short getCode() {
|
||||||
|
return DHCP6.OptionCode.LEASE_QUERY.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public short getLength() {
|
||||||
|
//return (short) payload.serialize().length;
|
||||||
|
return (short) (DEFAULT_LEN + options.stream()
|
||||||
|
.mapToInt(opt -> (int) opt.getLength() + Dhcp6Option.DEFAULT_LEN)
|
||||||
|
.sum());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getData() {
|
||||||
|
return payload.serialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static Deserializer<Dhcp6Option> deserializer() {
|
||||||
|
return (data, offset, length) -> {
|
||||||
|
Dhcp6Option dhcp6Option = Dhcp6Option.deserializer().deserialize(data, offset, length);
|
||||||
|
Dhcp6LeaseQueryOption lQ6Option = new Dhcp6LeaseQueryOption(dhcp6Option);
|
||||||
|
|
||||||
|
byte[] optionData = lQ6Option.getData();
|
||||||
|
if (optionData.length >= 61) { // 61 is LQ option length + 4 header
|
||||||
|
ByteBuffer bb = ByteBuffer.wrap(optionData);
|
||||||
|
// fetch the Query type - just pop the byte from the byte buffer for subsequent parsing...
|
||||||
|
bb.get();
|
||||||
|
byte[] ipv6Addr = new byte[16];
|
||||||
|
bb.get(ipv6Addr);
|
||||||
|
lQ6Option.linkAddress = Ip6Address.valueOf(ipv6Addr);
|
||||||
|
//int optionsLen = dhcp6Option.getLength() - 1 - 16; // query type (1) + link address (16)
|
||||||
|
|
||||||
|
lQ6Option.options = Lists.newArrayList();
|
||||||
|
|
||||||
|
while (bb.remaining() >= Dhcp6Option.DEFAULT_LEN) {
|
||||||
|
Dhcp6Option option;
|
||||||
|
ByteBuffer optByteBuffer = ByteBuffer.wrap(optionData,
|
||||||
|
bb.position(),
|
||||||
|
optionData.length - bb.position());
|
||||||
|
short code = optByteBuffer.getShort();
|
||||||
|
short len = optByteBuffer.getShort();
|
||||||
|
int optLen = UNSIGNED_SHORT_MASK & len;
|
||||||
|
byte[] subOptData = new byte[Dhcp6Option.DEFAULT_LEN + optLen];
|
||||||
|
bb.get(subOptData);
|
||||||
|
|
||||||
|
// TODO: put more sub-options?
|
||||||
|
if (code == DHCP6.OptionCode.IAADDR.value()) {
|
||||||
|
option = Dhcp6IaAddressOption.deserializer()
|
||||||
|
.deserialize(subOptData, 0, subOptData.length);
|
||||||
|
} else if (code == DHCP6.OptionCode.ORO.value()) {
|
||||||
|
option = Dhcp6Option.deserializer()
|
||||||
|
.deserialize(subOptData, 0, subOptData.length);
|
||||||
|
} else {
|
||||||
|
option = Dhcp6Option.deserializer()
|
||||||
|
.deserialize(subOptData, 0, subOptData.length);
|
||||||
|
}
|
||||||
|
lQ6Option.options.add(option);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lQ6Option;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] serialize() {
|
||||||
|
ByteBuffer bb = ByteBuffer.allocate(this.getLength() + Dhcp6Option.DEFAULT_LEN);
|
||||||
|
bb.putShort(getCode());
|
||||||
|
bb.putShort(getLength());
|
||||||
|
bb.put(payload.serialize());
|
||||||
|
return bb.array();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return MoreObjects.toStringHelper(getClass())
|
||||||
|
.add("code", getCode())
|
||||||
|
.add("length", getLength())
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(super.hashCode(), linkAddress, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!(obj instanceof Dhcp6LeaseQueryOption)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!super.equals(obj)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final Dhcp6LeaseQueryOption other = (Dhcp6LeaseQueryOption) obj;
|
||||||
|
|
||||||
|
return Objects.equals(getCode(), other.getCode()) &&
|
||||||
|
Objects.equals(getLength(), other.getLength()) &&
|
||||||
|
Objects.equals(linkAddress, other.linkAddress) &&
|
||||||
|
Objects.equals(options, other.options);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user