From 96a0d3408594ee2db90a7e50f8942ea71fe2e2bc Mon Sep 17 00:00:00 2001 From: Taras Lemkin Date: Mon, 26 Mar 2018 14:52:58 +0000 Subject: [PATCH] CORD-2870: Bypass DHCP leasequery without learning routes. Changes: * Add configuration flag to disable old leasequery routing/learning flow * Route leasequery (v4 and v6) responses to an originator * Fix NPE and BufferOverflow exceptions in Dhcp6LeaseQueryOption * Make Dhcp4/Dhcp6HandlerUtil classes static * Fix codestyle issues Change-Id: Ic9e527d73a226e7f1f544dab9fb98398b85c5460 --- .../dhcprelay/Dhcp4HandlerImpl.java | 463 +++++++++++------- .../dhcprelay/Dhcp4HandlerUtil.java | 32 +- .../dhcprelay/Dhcp6HandlerImpl.java | 240 ++++----- .../dhcprelay/Dhcp6HandlerUtil.java | 110 ++--- .../dhcprelay/DhcpRelayManager.java | 8 +- .../onosproject/dhcprelay/InternalPacket.java | 52 ++ .../packet/dhcp/Dhcp6LeaseQueryOption.java | 13 +- 7 files changed, 531 insertions(+), 387 deletions(-) create mode 100644 apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/InternalPacket.java diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp4HandlerImpl.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp4HandlerImpl.java index 26643fc017..424b628d3b 100644 --- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp4HandlerImpl.java +++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp4HandlerImpl.java @@ -26,6 +26,7 @@ import com.google.common.collect.Sets; import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Deactivate; +import org.apache.felix.scr.annotations.Modified; import org.apache.felix.scr.annotations.Property; import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.ReferenceCardinality; @@ -43,6 +44,8 @@ import org.onlab.packet.VlanId; import org.onlab.packet.dhcp.CircuitId; import org.onlab.packet.dhcp.DhcpOption; import org.onlab.packet.dhcp.DhcpRelayAgentOption; +import org.onlab.util.Tools; +import org.onosproject.cfg.ComponentConfigService; import org.onosproject.core.ApplicationId; import org.onosproject.core.CoreService; import org.onosproject.dhcprelay.api.DhcpHandler; @@ -88,14 +91,16 @@ import org.onosproject.net.packet.DefaultOutboundPacket; import org.onosproject.net.packet.OutboundPacket; import org.onosproject.net.packet.PacketContext; import org.onosproject.net.packet.PacketService; +import org.osgi.service.component.ComponentContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.nio.ByteBuffer; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.Dictionary; import java.util.List; -import java.util.ArrayList; import java.util.Optional; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; @@ -115,7 +120,6 @@ import static org.onlab.util.Tools.groupedThreads; import static org.onosproject.net.flowobjective.Objective.Operation.ADD; import static org.onosproject.net.flowobjective.Objective.Operation.REMOVE; -import org.onosproject.dhcprelay.Dhcp4HandlerUtil.InternalPacket; @Component @Service @@ -126,6 +130,8 @@ public class Dhcp4HandlerImpl implements DhcpHandler, HostProvider { private static final String BROADCAST_IP = "255.255.255.255"; private static final int IGNORE_CONTROL_PRIORITY = PacketPriority.CONTROL.priorityValue() + 1000; + private static final String LQ_ROUTE_PROPERTY_NAME = "learnRouteFromLeasequery"; + private static final TrafficSelector CLIENT_SERVER_SELECTOR = DefaultTrafficSelector.builder() .matchEthType(Ethernet.TYPE_IPV4) .matchIPProtocol(IPv4.PROTOCOL_UDP) @@ -173,6 +179,9 @@ public class Dhcp4HandlerImpl implements DhcpHandler, HostProvider { @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected FlowObjectiveService flowObjectiveService; + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ComponentConfigService cfgService; + protected HostProviderService providerService; protected ApplicationId appId; protected Multimap ignoredVlans = Multimaps.synchronizedMultimap(HashMultimap.create()); @@ -180,13 +189,18 @@ public class Dhcp4HandlerImpl implements DhcpHandler, HostProvider { private List defaultServerInfoList = new CopyOnWriteArrayList<>(); private List indirectServerInfoList = new CopyOnWriteArrayList<>(); - private Dhcp4HandlerUtil dhcp4HandlerUtil = new Dhcp4HandlerUtil(); + + @Property(name = Dhcp4HandlerImpl.LQ_ROUTE_PROPERTY_NAME, boolValue = false, + label = "Enable learning routing information from LQ") + private Boolean learnRouteFromLeasequery = Boolean.TRUE; private Executor hostEventExecutor = newSingleThreadExecutor( groupedThreads("dhcp4-event-host", "%d", log)); @Activate - protected void activate() { + protected void activate(ComponentContext context) { + cfgService.registerProperties(getClass()); + modified(context); appId = coreService.registerApplication(DHCP_V4_RELAY_APP); hostService.addListener(hostListener); providerService = providerRegistry.register(this); @@ -194,6 +208,7 @@ public class Dhcp4HandlerImpl implements DhcpHandler, HostProvider { @Deactivate protected void deactivate() { + cfgService.unregisterProperties(getClass(), false); providerRegistry.unregister(this); hostService.removeListener(hostListener); defaultServerInfoList.forEach(this::stopMonitoringIps); @@ -202,6 +217,18 @@ public class Dhcp4HandlerImpl implements DhcpHandler, HostProvider { indirectServerInfoList.clear(); } + @Modified + protected void modified(ComponentContext context) { + Dictionary properties = context.getProperties(); + Boolean flag; + flag = Tools.isPropertyEnabled(properties, Dhcp4HandlerImpl.LQ_ROUTE_PROPERTY_NAME); + if (flag != null) { + learnRouteFromLeasequery = flag; + log.info("Learning routes from DHCP leasequery is {}", + learnRouteFromLeasequery ? "enabled" : "disabled"); + } + } + private void stopMonitoringIps(DhcpServerInfo serverInfo) { serverInfo.getDhcpGatewayIp4().ifPresent(gatewayIp -> { hostService.stopMonitoringIp(gatewayIp); @@ -302,7 +329,7 @@ public class Dhcp4HandlerImpl implements DhcpHandler, HostProvider { // Create new server info according to the config serverInfoList.clear(); for (DhcpServerConfig serverConfig : configs) { - log.info("// Create new server info according to the config"); + log.debug("Create new server info according to the config"); DhcpServerInfo newServerInfo = new DhcpServerInfo(serverConfig, DhcpServerInfo.Version.DHCP_V4); checkState(newServerInfo.getDhcpServerConnectPoint().isPresent(), @@ -384,9 +411,9 @@ public class Dhcp4HandlerImpl implements DhcpHandler, HostProvider { break; case DHCPOFFER: //reply to dhcp client. - Ethernet ethernetPacketOffer = processDhcpPacketFromServer(context, packet); + InternalPacket ethernetPacketOffer = processDhcpPacketFromServer(context, packet); if (ethernetPacketOffer != null) { - writeResponseDhcpRecord(ethernetPacketOffer, dhcpPayload); + writeResponseDhcpRecord(ethernetPacketOffer.getPacket(), dhcpPayload); sendResponseToClient(ethernetPacketOffer, dhcpPayload); } break; @@ -405,10 +432,10 @@ public class Dhcp4HandlerImpl implements DhcpHandler, HostProvider { break; case DHCPACK: // reply to dhcp client. - Ethernet ethernetPacketAck = processDhcpPacketFromServer(context, packet); + InternalPacket ethernetPacketAck = processDhcpPacketFromServer(context, packet); if (ethernetPacketAck != null) { - writeResponseDhcpRecord(ethernetPacketAck, dhcpPayload); - handleDhcpAck(ethernetPacketAck, dhcpPayload); + writeResponseDhcpRecord(ethernetPacketAck.getPacket(), dhcpPayload); + handleDhcpAck(ethernetPacketAck.getPacket(), dhcpPayload); sendResponseToClient(ethernetPacketAck, dhcpPayload); } break; @@ -520,151 +547,171 @@ public class Dhcp4HandlerImpl implements DhcpHandler, HostProvider { private void handleLeaseQueryActivateMsg(Ethernet packet, DHCP dhcpPayload) { log.debug("LQ: Got DHCPLEASEACTIVE packet!"); - // TODO: release the ip address from client - MacAddress clientMacAddress = MacAddress.valueOf(dhcpPayload.getClientHardwareAddress()); - VlanId vlanId = VlanId.vlanId(packet.getVlanID()); - HostId hostId = HostId.hostId(clientMacAddress, vlanId); - DhcpRecord record = dhcpRelayStore.getDhcpRecord(hostId).orElse(null); + if (learnRouteFromLeasequery) { + // TODO: release the ip address from client + MacAddress clientMacAddress = MacAddress.valueOf(dhcpPayload.getClientHardwareAddress()); + VlanId vlanId = VlanId.vlanId(packet.getVlanID()); + HostId hostId = HostId.hostId(clientMacAddress, vlanId); + DhcpRecord record = dhcpRelayStore.getDhcpRecord(hostId).orElse(null); - if (record == null) { - log.warn("Can't find record for host {} when processing DHCPLEASEACTIVE", hostId); - return; + if (record == null) { + log.warn("Can't find record for host {} when processing DHCPLEASEACTIVE", hostId); + return; + } + + // need to update routes + log.debug("Lease Query for Client results in DHCPLEASEACTIVE - route needs to be modified"); + // get current route + // find the ip of that client with the DhcpRelay store + + Ip4Address clientIP = record.ip4Address().orElse(null); + log.debug("LQ: IP of host is " + clientIP.getIp4Address()); + + MacAddress nextHopMac = record.nextHop().orElse(null); + log.debug("LQ: MAC of resulting *OLD* NH for that host is " + nextHopMac.toString()); + + // find the new NH by looking at the src MAC of the dhcp request + // from the LQ store + MacAddress newNextHopMac = record.nextHopTemp().orElse(null); + log.debug("LQ: MAC of resulting *NEW* NH for that host is " + newNextHopMac.toString()); + + log.debug("LQ: updating dhcp relay record with new NH"); + record.nextHop(newNextHopMac); + + // find the next hop IP from its mac + HostId gwHostId = HostId.hostId(newNextHopMac, vlanId); + Host gwHost = hostService.getHost(gwHostId); + + if (gwHost == null) { + log.warn("Can't find gateway for new NH host " + gwHostId); + return; + } + + Ip4Address nextHopIp = gwHost.ipAddresses() + .stream() + .filter(IpAddress::isIp4) + .map(IpAddress::getIp4Address) + .findFirst() + .orElse(null); + + if (nextHopIp == null) { + log.warn("Can't find IP address of gateway " + gwHost); + return; + } + + log.debug("LQ: *NEW* NH IP for host is " + nextHopIp.getIp4Address()); + Route route = new Route(Route.Source.DHCP, clientIP.toIpPrefix(), nextHopIp); + routeStore.updateRoute(route); } - // need to update routes - log.debug("Lease Query for Client results in DHCPLEASEACTIVE - route needs to be modified"); - // get current route - // find the ip of that client with the DhcpRelay store - - Ip4Address clientIP = record.ip4Address().orElse(null); - log.debug("LQ: IP of host is " + clientIP.getIp4Address()); - - MacAddress nextHopMac = record.nextHop().orElse(null); - log.debug("LQ: MAC of resulting *OLD* NH for that host is " + nextHopMac.toString()); - - // find the new NH by looking at the src MAC of the dhcp request - // from the LQ store - MacAddress newNextHopMac = record.nextHopTemp().orElse(null); - log.debug("LQ: MAC of resulting *NEW* NH for that host is " + newNextHopMac.toString()); - - log.debug("LQ: updating dhcp relay record with new NH"); - record.nextHop(newNextHopMac); - - // find the next hop IP from its mac - HostId gwHostId = HostId.hostId(newNextHopMac, vlanId); - Host gwHost = hostService.getHost(gwHostId); - - if (gwHost == null) { - log.warn("Can't find gateway for new NH host " + gwHostId); - return; - } - - Ip4Address nextHopIp = gwHost.ipAddresses() - .stream() - .filter(IpAddress::isIp4) - .map(IpAddress::getIp4Address) - .findFirst() - .orElse(null); - - if (nextHopIp == null) { - log.warn("Can't find IP address of gateway " + gwHost); - return; - } - - log.debug("LQ: *NEW* NH IP for host is " + nextHopIp.getIp4Address()); - Route route = new Route(Route.Source.DHCP, clientIP.toIpPrefix(), nextHopIp); - routeStore.updateRoute(route); - // and forward to client - Ethernet ethernetPacket = processLeaseQueryFromServer(packet); + InternalPacket ethernetPacket = processLeaseQueryFromServer(packet); if (ethernetPacket != null) { sendResponseToClient(ethernetPacket, dhcpPayload); } } - /** - * - */ private void handleLeaseQueryMsg(PacketContext context, Ethernet packet, DHCP dhcpPayload) { - log.debug("LQ: Got DHCPLEASEQUERY packet!"); - MacAddress clientMacAddress = MacAddress.valueOf(dhcpPayload.getClientHardwareAddress()); - log.debug("LQ: got DHCPLEASEQUERY with MAC " + clientMacAddress.toString()); - // add the client mac (hostid) of this request to a store (the entry will be removed with - // the reply sent to the originator) - VlanId vlanId = VlanId.vlanId(packet.getVlanID()); - HostId hId = HostId.hostId(clientMacAddress, vlanId); - DhcpRecord record = dhcpRelayStore.getDhcpRecord(hId).orElse(null); - if (record != null) { - //new NH is to be taken from src mac of LQ packet - MacAddress newNextHop = packet.getSourceMAC(); - record.nextHopTemp(newNextHop); - record.ip4Status(dhcpPayload.getPacketType()); - record.updateLastSeen(); + // If this flag is enabled we expect that DHCPLEASEQUERY-ies are sent from an access concentrator + // where queried client is connected to. Otherwise, DHCPLEASEQUERY source may be a separate connected agent + if (learnRouteFromLeasequery) { + log.debug("LQ: Got DHCPLEASEQUERY packet!"); + MacAddress clientMacAddress = MacAddress.valueOf(dhcpPayload.getClientHardwareAddress()); + log.debug("LQ: got DHCPLEASEQUERY with MAC " + clientMacAddress.toString()); + // add the client mac (hostid) of this request to a store (the entry will be removed with + // the reply sent to the originator) + VlanId vlanId = VlanId.vlanId(packet.getVlanID()); + HostId hId = HostId.hostId(clientMacAddress, vlanId); + DhcpRecord record = dhcpRelayStore.getDhcpRecord(hId).orElse(null); + if (record != null) { + //new NH is to be taken from src mac of LQ packet + MacAddress newNextHop = packet.getSourceMAC(); + record.nextHopTemp(newNextHop); + record.ip4Status(dhcpPayload.getPacketType()); + record.updateLastSeen(); + + // do a basic routing of the packet (this is unicast routing + // not a relay operation like for other broadcast dhcp packets + List ethernetPacketRequest = processLeaseQueryFromAgent(context, packet); + // and forward to server + for (InternalPacket internalPacket : ethernetPacketRequest) { + log.debug("LeaseQueryMsg forward to server"); + forwardPacket(internalPacket); + } + } else { + log.warn("LQ: Error! - DHCP relay record for that client not found - ignoring LQ!"); + } + } else { + log.debug("LQ: Got DHCPLEASEQUERY packet!"); + + int giaddr = dhcpPayload.getGatewayIPAddress(); + + log.debug("DHCPLEASEQUERY giaddr: {} ({}). Originators connectPoint: {}", giaddr, + Ip4Address.valueOf(giaddr), context.inPacket().receivedFrom()); // do a basic routing of the packet (this is unicast routing // not a relay operation like for other broadcast dhcp packets List ethernetPacketRequest = processLeaseQueryFromAgent(context, packet); // and forward to server for (InternalPacket internalPacket : ethernetPacketRequest) { - log.debug("LeaseQueryMsg forward to server"); + log.trace("LeaseQueryMsg forward to server connected to {}", internalPacket.getDestLocation()); forwardPacket(internalPacket); } - } else { - log.warn("LQ: Error! - DHCP relay record for that client not found - ignoring LQ!"); } } private void handleLeaseQueryUnknown(Ethernet packet, DHCP dhcpPayload) { log.debug("Lease Query for Client results in DHCPLEASEUNASSIGNED or " + "DHCPLEASEUNKNOWN - removing route & forwarding reply to originator"); - MacAddress clientMacAddress = MacAddress.valueOf(dhcpPayload.getClientHardwareAddress()); - VlanId vlanId = VlanId.vlanId(packet.getVlanID()); - HostId hostId = HostId.hostId(clientMacAddress, vlanId); - DhcpRecord record = dhcpRelayStore.getDhcpRecord(hostId).orElse(null); + if (learnRouteFromLeasequery) { + MacAddress clientMacAddress = MacAddress.valueOf(dhcpPayload.getClientHardwareAddress()); + VlanId vlanId = VlanId.vlanId(packet.getVlanID()); + HostId hostId = HostId.hostId(clientMacAddress, vlanId); + DhcpRecord record = dhcpRelayStore.getDhcpRecord(hostId).orElse(null); - if (record == null) { - log.warn("Can't find record for host {} when handling LQ UNKNOWN/UNASSIGNED message", hostId); - return; + if (record == null) { + log.warn("Can't find record for host {} when handling LQ UNKNOWN/UNASSIGNED message", hostId); + return; + } + + Ip4Address clientIP = record.ip4Address().orElse(null); + log.debug("LQ: IP of host is " + clientIP.getIp4Address()); + + // find the new NH by looking at the src MAC of the dhcp request + // from the LQ store + MacAddress nextHopMac = record.nextHop().orElse(null); + log.debug("LQ: MAC of resulting *Existing* NH for that route is " + nextHopMac.toString()); + + // find the next hop IP from its mac + HostId gwHostId = HostId.hostId(nextHopMac, vlanId); + Host gwHost = hostService.getHost(gwHostId); + + if (gwHost == null) { + log.warn("Can't find gateway for new NH host " + gwHostId); + return; + } + + Ip4Address nextHopIp = gwHost.ipAddresses() + .stream() + .filter(IpAddress::isIp4) + .map(IpAddress::getIp4Address) + .findFirst() + .orElse(null); + + if (nextHopIp == null) { + log.warn("Can't find IP address of gateway {}", gwHost); + return; + } + + log.debug("LQ: *Existing* NH IP for host is " + nextHopIp.getIp4Address() + " removing route for it"); + Route route = new Route(Route.Source.DHCP, clientIP.toIpPrefix(), nextHopIp); + routeStore.removeRoute(route); + + // remove from temp store + dhcpRelayStore.removeDhcpRecord(hostId); } - - Ip4Address clientIP = record.ip4Address().orElse(null); - log.debug("LQ: IP of host is " + clientIP.getIp4Address()); - - // find the new NH by looking at the src MAC of the dhcp request - // from the LQ store - MacAddress nextHopMac = record.nextHop().orElse(null); - log.debug("LQ: MAC of resulting *Existing* NH for that route is " + nextHopMac.toString()); - - // find the next hop IP from its mac - HostId gwHostId = HostId.hostId(nextHopMac, vlanId); - Host gwHost = hostService.getHost(gwHostId); - - if (gwHost == null) { - log.warn("Can't find gateway for new NH host " + gwHostId); - return; - } - - Ip4Address nextHopIp = gwHost.ipAddresses() - .stream() - .filter(IpAddress::isIp4) - .map(IpAddress::getIp4Address) - .findFirst() - .orElse(null); - - if (nextHopIp == null) { - log.warn("Can't find IP address of gateway {}", gwHost); - return; - } - - log.debug("LQ: *Existing* NH IP for host is " + nextHopIp.getIp4Address() + " removing route for it"); - Route route = new Route(Route.Source.DHCP, clientIP.toIpPrefix(), nextHopIp); - routeStore.removeRoute(route); - - // remove from temp store - dhcpRelayStore.removeDhcpRecord(hostId); - // and forward to client - Ethernet ethernetPacket = processLeaseQueryFromServer(packet); + InternalPacket ethernetPacket = processLeaseQueryFromServer(packet); if (ethernetPacket != null) { sendResponseToClient(ethernetPacket, dhcpPayload); } @@ -683,7 +730,7 @@ public class Dhcp4HandlerImpl implements DhcpHandler, HostProvider { ConnectPoint receivedFrom = context.inPacket().receivedFrom(); DeviceId receivedFromDevice = receivedFrom.deviceId(); Ip4Address relayAgentIp = null; - relayAgentIp = dhcp4HandlerUtil.getRelayAgentIPv4Address(clientInterfaces); + relayAgentIp = Dhcp4HandlerUtil.getRelayAgentIPv4Address(clientInterfaces); MacAddress relayAgentMac = clientInterfaces.iterator().next().mac(); if (relayAgentIp == null || relayAgentMac == null) { log.warn("Missing DHCP relay agent interface Ipv4 addr config for " @@ -724,7 +771,7 @@ public class Dhcp4HandlerImpl implements DhcpHandler, HostProvider { ConnectPoint clientConnectionPoint = context.inPacket().receivedFrom(); VlanId vlanIdInUse = VlanId.vlanId(ethernetPacket.getVlanID()); Interface clientInterface = interfaceService.getInterfacesByPort(clientConnectionPoint) - .stream().filter(iface -> dhcp4HandlerUtil.interfaceContainsVlan(iface, vlanIdInUse)) + .stream().filter(iface -> Dhcp4HandlerUtil.interfaceContainsVlan(iface, vlanIdInUse)) .findFirst() .orElse(null); @@ -735,9 +782,9 @@ public class Dhcp4HandlerImpl implements DhcpHandler, HostProvider { for (DhcpServerInfo serverInfo : copyServerInfoList) { etherReply = (Ethernet) ethernetPacket.clone(); - ipv4Packet = (IPv4) etherReply.getPayload(); - udpPacket = (UDP) ipv4Packet.getPayload(); - dhcpPacket = (DHCP) udpPacket.getPayload(); + ipv4Packet = (IPv4) etherReply.getPayload(); + udpPacket = (UDP) ipv4Packet.getPayload(); + dhcpPacket = (DHCP) udpPacket.getPayload(); if (!checkDhcpServerConnPt(directConnFlag, serverInfo)) { log.warn("Can't get server connect point, ignore"); continue; @@ -850,8 +897,9 @@ public class Dhcp4HandlerImpl implements DhcpHandler, HostProvider { ipv4Packet.setPayload(udpPacket); ipv4Packet.setTtl((byte) 64); etherReply.setPayload(ipv4Packet); - InternalPacket internalPacket = new Dhcp4HandlerUtil().new InternalPacket(etherReply, + InternalPacket internalPacket = InternalPacket.internalPacket(etherReply, serverInfo.getDhcpServerConnectPoint().get()); + internalPackets.add(internalPacket); } return internalPackets; @@ -898,9 +946,6 @@ public class Dhcp4HandlerImpl implements DhcpHandler, HostProvider { boolean directConnFlag = directlyConnected(dhcpPacket); // Multi DHCP Start - ConnectPoint clientConnectionPoint = context.inPacket().receivedFrom(); - VlanId vlanIdInUse = VlanId.vlanId(ethernetPacket.getVlanID()); - List internalPackets = new ArrayList<>(); List serverInfoList = findValidServerInfo(directConnFlag); List copyServerInfoList = new ArrayList<>(serverInfoList); @@ -947,27 +992,28 @@ public class Dhcp4HandlerImpl implements DhcpHandler, HostProvider { if (newServerInfo.getDhcpConnectVlan().isPresent()) { etherReply.setVlanID(serverInfo.getDhcpConnectVlan().get().toShort()); } - relayAgentIp = newServerInfo.getRelayAgentIp4(receivedFromDevice).orElse(null); - // Sets relay agent IP - int effectiveRelayAgentIp = relayAgentIp != null ? - relayAgentIp.toInt() : clientInterfaceIp.toInt(); - dhcpPacket.setGatewayIPAddress(effectiveRelayAgentIp); - } else { - if (!newServerInfo.getDhcpServerIp4().isPresent()) { - //do nothing - } else if (!newServerInfo.getDhcpConnectMac().isPresent()) { - continue; - } else { + if (learnRouteFromLeasequery) { relayAgentIp = newServerInfo.getRelayAgentIp4(receivedFromDevice).orElse(null); // Sets relay agent IP int effectiveRelayAgentIp = relayAgentIp != null ? relayAgentIp.toInt() : clientInterfaceIp.toInt(); dhcpPacket.setGatewayIPAddress(effectiveRelayAgentIp); + } + } else { + if (!newServerInfo.getDhcpServerIp4().isPresent()) { + //do nothing + } else if (!newServerInfo.getDhcpConnectMac().isPresent()) { + continue; + } else if (learnRouteFromLeasequery) { + relayAgentIp = newServerInfo.getRelayAgentIp4(receivedFromDevice).orElse(null); + // Sets relay agent IP + int effectiveRelayAgentIp = relayAgentIp != null ? + relayAgentIp.toInt() : clientInterfaceIp.toInt(); dhcpPacket.setGatewayIPAddress(effectiveRelayAgentIp); - log.info("Relay Agent IP {}", relayAgentIp); + log.debug("Relay Agent IP {}", relayAgentIp); } - log.info("In Direct"); + log.trace("Indirect"); } // Remove broadcast flag @@ -981,12 +1027,14 @@ public class Dhcp4HandlerImpl implements DhcpHandler, HostProvider { ipv4Packet.setPayload(udpPacket); ipv4Packet.setTtl((byte) 64); etherReply.setPayload(ipv4Packet); + udpPacket.resetChecksum(); ////return etherReply; - Dhcp4HandlerUtil.InternalPacket internalPacket = new Dhcp4HandlerUtil().new InternalPacket(etherReply, + InternalPacket internalPacket = InternalPacket.internalPacket(etherReply, newServerInfo.getDhcpServerConnectPoint().get()); + internalPackets.add(internalPacket); } - log.warn("num of processLeaseQueryFromAgent packets to send is{}", internalPackets.size()); + log.debug("num of processLeaseQueryFromAgent packets to send is: {}", internalPackets.size()); return internalPackets; } @@ -1066,7 +1114,7 @@ public class Dhcp4HandlerImpl implements DhcpHandler, HostProvider { * @param ethernetPacket the original packet comes from server * @return new packet which will send to the client */ - private Ethernet processDhcpPacketFromServer(PacketContext context, Ethernet ethernetPacket) { + private InternalPacket processDhcpPacketFromServer(PacketContext context, Ethernet ethernetPacket) { // get dhcp header. Ethernet etherReply = (Ethernet) ethernetPacket.clone(); IPv4 ipv4Packet = (IPv4) etherReply.getPayload(); @@ -1090,7 +1138,7 @@ public class Dhcp4HandlerImpl implements DhcpHandler, HostProvider { log.warn("Cannot find server info"); return null; } else { - if (dhcp4HandlerUtil.isServerIpEmpty(foundServerInfo)) { + if (Dhcp4HandlerUtil.isServerIpEmpty(foundServerInfo)) { log.warn("Cannot find server info's ipaddress"); return null; } @@ -1160,7 +1208,7 @@ public class Dhcp4HandlerImpl implements DhcpHandler, HostProvider { udpPacket.setPayload(dhcpPayload); ipv4Packet.setPayload(udpPacket); etherReply.setPayload(ipv4Packet); - return etherReply; + return InternalPacket.internalPacket(etherReply, clientInterface.connectPoint()); } /** @@ -1169,7 +1217,7 @@ public class Dhcp4HandlerImpl implements DhcpHandler, HostProvider { * @param ethernetPacket the original packet comes from server * @return new packet which will send to the client */ - private Ethernet processLeaseQueryFromServer(Ethernet ethernetPacket) { + private InternalPacket processLeaseQueryFromServer(Ethernet ethernetPacket) { // get dhcp header. Ethernet etherReply = (Ethernet) ethernetPacket.clone(); IPv4 ipv4Packet = (IPv4) etherReply.getPayload(); @@ -1178,7 +1226,33 @@ public class Dhcp4HandlerImpl implements DhcpHandler, HostProvider { // determine the vlanId of the client host - note that this vlan id // could be different from the vlan in the packet from the server - Interface clientInterface = getClientInterface(ethernetPacket, dhcpPayload).orElse(null); + Interface clientInterface = null; + MacAddress destinationMac = MacAddress.valueOf(dhcpPayload.getClientHardwareAddress()); + + if (!learnRouteFromLeasequery) { + int giaddr = ipv4Packet.getDestinationAddress(); + IpAddress destinationAddress = Ip4Address.valueOf(giaddr); + log.debug("DHCPLEASEQUERYRESP giaddr: {}({})", giaddr, destinationAddress); + + Host destinationHost = hostService.getHostsByIp(destinationAddress).stream().findFirst().orElse(null); + if (destinationHost != null) { + destinationMac = destinationHost.mac(); + log.trace("DHCPLEASEQUERYRESP destination mac is: {}", destinationMac); + ConnectPoint destinationLocation = destinationHost.location(); + log.trace("Lookup for client interface by destination location {}", destinationLocation); + clientInterface = interfaceService.getInterfacesByPort(destinationLocation) + .stream() + .filter(iface -> interfaceContainsVlan(iface, VlanId.vlanId(etherReply.getVlanID()))) + .findFirst() + .orElse(null); + log.trace("Found Host {} by ip {}", destinationHost, destinationAddress); + log.debug("DHCPLEASEQUERYRESP Client interface: {}", + (clientInterface != null ? clientInterface : "not resolved")); + + } + } else { + clientInterface = getClientInterface(ethernetPacket, dhcpPayload).orElse(null); + } if (clientInterface == null) { log.warn("Cannot find the interface for the DHCP {}", dhcpPayload); @@ -1197,31 +1271,40 @@ public class Dhcp4HandlerImpl implements DhcpHandler, HostProvider { etherReply.setVlanID(vlanId.toShort()); etherReply.setSourceMACAddress(clientInterface.mac()); - if (!directlyConnected(dhcpPayload)) { + if (!directlyConnected(dhcpPayload) && learnRouteFromLeasequery) { // if client is indirectly connected, try use next hop mac address MacAddress macAddress = MacAddress.valueOf(dhcpPayload.getClientHardwareAddress()); HostId hostId = HostId.hostId(macAddress, vlanId); DhcpRecord record = dhcpRelayStore.getDhcpRecord(hostId).orElse(null); if (record != null) { // if next hop can be found, use mac address of next hop - record.nextHop().ifPresent(etherReply::setDestinationMACAddress); + Optional nextHop = record.nextHopTemp(); + if (!nextHop.isPresent()) { + nextHop = record.nextHop(); + } + nextHop.ifPresent(etherReply::setDestinationMACAddress); } else { // otherwise, discard the packet log.warn("Can't find record for host id {}, discard packet", hostId); return null; } } else { - etherReply.setDestinationMACAddress(dhcpPayload.getClientHardwareAddress()); + etherReply.setDestinationMACAddress(destinationMac); } - // default is client port udpPacket.setSourcePort(UDP.DHCP_SERVER_PORT); - udpPacket.setDestinationPort(UDP.DHCP_CLIENT_PORT); + if (directlyConnected(dhcpPayload)) { + udpPacket.setDestinationPort(UDP.DHCP_CLIENT_PORT); + } else { + udpPacket.setDestinationPort(UDP.DHCP_SERVER_PORT); + } udpPacket.setPayload(dhcpPayload); ipv4Packet.setPayload(udpPacket); etherReply.setPayload(ipv4Packet); - return etherReply; + udpPacket.resetChecksum(); + + return InternalPacket.internalPacket(etherReply, clientInterface.connectPoint()); } /** * Extracts VLAN ID from relay agent option. @@ -1274,6 +1357,17 @@ public class Dhcp4HandlerImpl implements DhcpHandler, HostProvider { return ethernet; } + private boolean isDhcpPacketLeasequery(DHCP dhcpPacket) { + switch (dhcpPacket.getPacketType()) { + case DHCPLEASEACTIVE: + case DHCPLEASEQUERY: + case DHCPLEASEUNASSIGNED: + case DHCPLEASEUNKNOWN: + return true; + default: + return false; + } + } /** * Check if the host is directly connected to the network or not. @@ -1282,6 +1376,11 @@ public class Dhcp4HandlerImpl implements DhcpHandler, HostProvider { * @return true if the host is directly connected to the network; false otherwise */ private boolean directlyConnected(DHCP dhcpPayload) { + // leasequery is always indirect + if (isDhcpPacketLeasequery(dhcpPayload)) { + return false; + } + DhcpRelayAgentOption relayAgentOption = (DhcpRelayAgentOption) dhcpPayload.getOption(OptionCode_CircuitID); @@ -1445,31 +1544,30 @@ public class Dhcp4HandlerImpl implements DhcpHandler, HostProvider { /** * Send the response DHCP to the requester host. * - * @param ethPacket the packet + * @param thePacket the packet * @param dhcpPayload the DHCP data */ - private void sendResponseToClient(Ethernet ethPacket, DHCP dhcpPayload) { - Optional outInterface = getClientInterface(ethPacket, dhcpPayload); + private void sendResponseToClient(InternalPacket thePacket, DHCP dhcpPayload) { + checkNotNull(thePacket, "Nothing to send"); + checkNotNull(thePacket.getPacket(), "Packet to send must not be empty"); + checkNotNull(thePacket.getDestLocation(), "Packet destination not be empty"); + + Ethernet ethPacket = thePacket.getPacket(); if (directlyConnected(dhcpPayload)) { ethPacket = removeRelayAgentOption(ethPacket); } - if (!outInterface.isPresent()) { - log.warn("Can't find output interface for client, ignore"); - return; - } - Interface outIface = outInterface.get(); + TrafficTreatment treatment = DefaultTrafficTreatment.builder() - .setOutput(outIface.connectPoint().port()) + .setOutput(thePacket.getDestLocation().port()) .build(); OutboundPacket o = new DefaultOutboundPacket( - outIface.connectPoint().deviceId(), + thePacket.getDestLocation().deviceId(), treatment, ByteBuffer.wrap(ethPacket.serialize())); if (log.isTraceEnabled()) { - log.trace("Relaying packet to DHCP client {} via {}, vlan {}", + log.trace("Relaying packet to DHCP client {} via {}", ethPacket, - outIface.connectPoint(), - outIface.vlan()); + thePacket.getDestLocation()); } packetService.emit(o); } @@ -1798,7 +1896,7 @@ public class Dhcp4HandlerImpl implements DhcpHandler, HostProvider { if (dhcpServerConnectPoint != null && dhcpConnectVlan != null) { serverInterface = interfaceService.getInterfacesByPort(dhcpServerConnectPoint) .stream() - .filter(iface -> dhcp4HandlerUtil.interfaceContainsVlan(iface, dhcpConnectVlan)) + .filter(iface -> Dhcp4HandlerUtil.interfaceContainsVlan(iface, dhcpConnectVlan)) .findFirst() .orElse(null); } else { @@ -1812,15 +1910,15 @@ public class Dhcp4HandlerImpl implements DhcpHandler, HostProvider { //forward the packet to ConnectPoint where the DHCP server is attached. private void forwardPacket(InternalPacket packet) { //send Packetout to dhcp server connectpoint. - if (packet.destLocation != null) { + if (packet.getDestLocation() != null) { TrafficTreatment t = DefaultTrafficTreatment.builder() - .setOutput(packet.destLocation.port()).build(); + .setOutput(packet.getDestLocation().port()).build(); OutboundPacket o = new DefaultOutboundPacket( - packet.destLocation.deviceId(), t, ByteBuffer.wrap(packet.packet.serialize())); + packet.getDestLocation().deviceId(), t, ByteBuffer.wrap(packet.getPacket().serialize())); if (log.isTraceEnabled()) { - log.trace("Relaying packet to destination {}", packet.destLocation); + log.trace("Relaying packet to destination {}", packet.getDestLocation()); } - log.debug("packetService.emit(o) to port {}", packet.destLocation); + log.debug("packetService.emit(o) to port {}", packet.getDestLocation()); packetService.emit(o); } } @@ -1842,5 +1940,4 @@ public class Dhcp4HandlerImpl implements DhcpHandler, HostProvider { } return foundServerInfo; } - } diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp4HandlerUtil.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp4HandlerUtil.java index 077c6ca509..a88bda806e 100644 --- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp4HandlerUtil.java +++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp4HandlerUtil.java @@ -18,12 +18,8 @@ package org.onosproject.dhcprelay; import org.onlab.packet.Ip4Address; import org.onlab.packet.VlanId; - -import org.onlab.packet.Ethernet; - import org.onlab.util.HexString; import org.onosproject.dhcprelay.api.DhcpServerInfo; -import org.onosproject.net.ConnectPoint; import org.onosproject.net.host.InterfaceIpAddress; import org.onosproject.net.intf.Interface; @@ -31,10 +27,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Set; -public class Dhcp4HandlerUtil { +public final class Dhcp4HandlerUtil { + private static final Logger log = LoggerFactory.getLogger(Dhcp4HandlerUtil.class); - - private final Logger log = LoggerFactory.getLogger(getClass()); + private Dhcp4HandlerUtil() { + } /** * Returns the first v4 interface ip out of a set of interfaces or null. @@ -42,7 +39,7 @@ public class Dhcp4HandlerUtil { * @param intfs set of interfaces * @return Ip4Address / null if not present */ - public Ip4Address getRelayAgentIPv4Address(Set intfs) { + public static Ip4Address getRelayAgentIPv4Address(Set intfs) { for (Interface intf : intfs) { for (InterfaceIpAddress ip : intf.ipAddressesList()) { Ip4Address relayAgentIp = ip.ipAddress().getIp4Address(); @@ -61,7 +58,7 @@ public class Dhcp4HandlerUtil { * @param vlanId the vlan id * @return true if the Interface contains the vlan id */ - public boolean interfaceContainsVlan(Interface iface, VlanId vlanId) { + public static boolean interfaceContainsVlan(Interface iface, VlanId vlanId) { if (vlanId.equals(VlanId.NONE)) { // untagged packet, check if vlan untagged or vlan native is not NONE return !iface.vlanUntagged().equals(VlanId.NONE) || @@ -77,7 +74,7 @@ public class Dhcp4HandlerUtil { * @param serverInfo server info to check * @return true if server info has v6 ip address; false otherwise */ - public boolean isServerIpEmpty(DhcpServerInfo serverInfo) { + public static boolean isServerIpEmpty(DhcpServerInfo serverInfo) { if (!serverInfo.getDhcpServerIp4().isPresent()) { log.warn("DhcpServerIp not available, use default DhcpServerIp {}", HexString.toHexString(serverInfo.getDhcpServerIp4().get().toOctets())); @@ -85,20 +82,5 @@ public class Dhcp4HandlerUtil { } return false; } - - - /** - * the new class the contains Ethernet packet and destination port. - */ - public class InternalPacket { - Ethernet packet; - ConnectPoint destLocation; - public InternalPacket(Ethernet newPacket, ConnectPoint newLocation) { - packet = newPacket; - destLocation = newLocation; - } - } - - } diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerImpl.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerImpl.java index e60cad8dfc..73ddc5f888 100644 --- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerImpl.java +++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerImpl.java @@ -20,11 +20,12 @@ import com.google.common.collect.HashMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; import com.google.common.collect.Multimaps; -import org.apache.felix.scr.annotations.Activate; -import org.apache.felix.scr.annotations.Deactivate; import com.google.common.collect.Sets; import com.google.common.collect.ImmutableSet; +import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Deactivate; +import org.apache.felix.scr.annotations.Modified; import org.apache.felix.scr.annotations.Property; import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.ReferenceCardinality; @@ -54,6 +55,8 @@ import org.onlab.packet.dhcp.Dhcp6ClientIdOption; import org.onlab.packet.dhcp.Dhcp6Duid; import org.onlab.packet.DHCP6.MsgType; import org.onlab.util.HexString; +import org.onlab.util.Tools; +import org.onosproject.cfg.ComponentConfigService; import org.onosproject.core.ApplicationId; import org.onosproject.core.CoreService; import org.onosproject.dhcprelay.api.DhcpHandler; @@ -83,7 +86,6 @@ import org.onosproject.net.host.HostProviderService; import org.onosproject.net.host.HostService; import org.onosproject.net.host.DefaultHostDescription; import org.onosproject.net.host.HostDescription; -import org.onosproject.net.host.InterfaceIpAddress; import org.onosproject.net.host.HostListener; import org.onosproject.net.host.HostEvent; import org.onosproject.net.intf.Interface; @@ -101,17 +103,18 @@ import org.onosproject.net.packet.DefaultOutboundPacket; import org.onosproject.net.packet.OutboundPacket; import org.onosproject.net.packet.PacketContext; import org.onosproject.net.packet.PacketService; +import org.osgi.service.component.ComponentContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.onosproject.net.flow.DefaultTrafficTreatment; import org.onosproject.net.flow.TrafficTreatment; -import org.onosproject.dhcprelay.Dhcp6HandlerUtil.InternalPacket; import java.nio.ByteBuffer; -import java.util.List; +import java.util.ArrayList; import java.util.Collection; +import java.util.Dictionary; +import java.util.List; import java.util.Optional; import java.util.Set; -import java.util.ArrayList; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicInteger; @@ -132,6 +135,7 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider { public static final ProviderId PROVIDER_ID = new ProviderId("dhcp6", DHCP_V6_RELAY_APP); private static final int IGNORE_CONTROL_PRIORITY = PacketPriority.CONTROL.priorityValue() + 1000; private String gCount = "global"; + private static final String LQ_ROUTE_PROPERTY_NAME = "learnRouteFromLeasequery"; private static final TrafficSelector CLIENT_SERVER_SELECTOR = DefaultTrafficSelector.builder() .matchEthType(Ethernet.TYPE_IPV6) .matchIPProtocol(IPv6.PROTOCOL_UDP) @@ -194,12 +198,18 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider { @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected FlowObjectiveService flowObjectiveService; + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ComponentConfigService cfgService; + + @Property(name = Dhcp6HandlerImpl.LQ_ROUTE_PROPERTY_NAME, boolValue = false, + label = "Enable learning routing information from LQ") + private Boolean learnRouteFromLeasequery = Boolean.TRUE; + protected HostProviderService providerService; protected ApplicationId appId; protected Multimap ignoredVlans = Multimaps.synchronizedMultimap(HashMultimap.create()); private InternalHostListener hostListener = new InternalHostListener(); private Boolean dhcpFpmEnabled = false; - private Dhcp6HandlerUtil dhcp6HandlerUtil = new Dhcp6HandlerUtil(); private List defaultServerInfoList = new CopyOnWriteArrayList<>(); private List indirectServerInfoList = new CopyOnWriteArrayList<>(); @@ -236,7 +246,9 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider { DHCP6.MsgType.LEASEQUERY_REPLY.value()); @Activate - protected void activate() { + protected void activate(ComponentContext context) { + cfgService.registerProperties(getClass()); + modified(context); appId = coreService.registerApplication(DHCP_V6_RELAY_APP); providerService = providerRegistry.register(this); hostService.addListener(hostListener); @@ -244,6 +256,7 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider { @Deactivate protected void deactivate() { + cfgService.unregisterProperties(getClass(), false); providerRegistry.unregister(this); hostService.removeListener(hostListener); defaultServerInfoList.forEach(this::stopMonitoringIps); @@ -252,6 +265,18 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider { indirectServerInfoList.clear(); } + @Modified + protected void modified(ComponentContext context) { + Dictionary properties = context.getProperties(); + Boolean flag; + flag = Tools.isPropertyEnabled(properties, Dhcp6HandlerImpl.LQ_ROUTE_PROPERTY_NAME); + if (flag != null) { + learnRouteFromLeasequery = flag; + log.info("Learning routes from DHCP leasequery is {}", + learnRouteFromLeasequery ? "enabled" : "disabled"); + } + } + private void stopMonitoringIps(DhcpServerInfo serverInfo) { serverInfo.getDhcpGatewayIp6().ifPresent(gatewayIp -> { hostService.stopMonitoringIp(gatewayIp); @@ -307,7 +332,7 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider { public DhcpRecord getDhcpRelayRecordFor(Ip6Address clientAddress) { - Collection records = dhcpRelayStore.getDhcpRecords(); + Collection records = dhcpRelayStore.getDhcpRecords(); DhcpRecord dr = null; for (DhcpRecord e:records) { if (e.ip6Address().isPresent()) { @@ -478,7 +503,7 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider { ConnectPoint inPort = context.inPacket().receivedFrom(); if (inPort == null) { - log.warn("incomming ConnectPoint is null"); + log.warn("incoming ConnectPoint is null"); } Set receivingInterfaces = interfaceService.getInterfacesByPort(inPort); //ignore the packets if dhcp client interface is not configured on onos. @@ -488,20 +513,21 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider { } if (msgTypeVal == DHCP6.MsgType.LEASEQUERY.value()) { - List ethernetClientPacket = - processLQ6PacketFromClient(context, receivedPacket, receivingInterfaces, dhcp6Payload); - for (InternalPacket internalPacket : ethernetClientPacket) { + List ethernetClientPackets = + learnRouteFromLeasequery ? + processLQ6PacketFromClient(context, receivedPacket, receivingInterfaces, dhcp6Payload) : + processDhcp6ForwardOnly(context, receivedPacket, receivingInterfaces, dhcp6Payload); + for (InternalPacket internalPacket : ethernetClientPackets) { forwardPacket(internalPacket); } - } else if (msgTypeVal == DHCP6.MsgType.LEASEQUERY_REPLY.value()) { - + } else if (msgTypeVal == DHCP6.MsgType.LEASEQUERY_REPLY.value() && learnRouteFromLeasequery) { IPv6 clientIpv6 = (IPv6) receivedPacket.getPayload(); UDP clientUdp = (UDP) clientIpv6.getPayload(); DHCP6 clientDhcp6 = (DHCP6) clientUdp.getPayload(); - Interface serverInterface = dhcp6HandlerUtil.directlyConnected(clientDhcp6) ? + Interface serverInterface = Dhcp6HandlerUtil.directlyConnected(clientDhcp6) ? getServerInterface() : getIndirectServerInterface(); InternalPacket ethernetPacketReply = - dhcp6HandlerUtil.processLQ6PacketFromServer( + Dhcp6HandlerUtil.processLQ6PacketFromServer( defaultServerInfoList, indirectServerInfoList, serverInterface, interfaceService, hostService, @@ -510,24 +536,21 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider { forwardPacket(ethernetPacketReply); } handleLeaseQuery6ReplyMsg(context, dhcp6Payload); - } else { - if (MSG_TYPE_FROM_CLIENT.contains(msgTypeVal)) { - - List 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); + } else if (MSG_TYPE_FROM_CLIENT.contains(msgTypeVal)) { + List 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 {}, {}", receivedPacket, dhcp6Payload); + InternalPacket ethernetPacketReply = + processDhcp6PacketFromServer(context, receivedPacket, receivingInterfaces); + if (ethernetPacketReply != null) { + forwardPacket(ethernetPacketReply); + } + } else { + log.warn("Not so fast, packet type {} not supported yet", msgTypeVal); } } @@ -553,16 +576,21 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider { //forward the packet to ConnectPoint where the DHCP server is attached. private void forwardPacket(InternalPacket packet) { //send Packetout to dhcp server connectpoint. - if (packet.destLocation != null) { + if (packet.getDestLocation() != null) { TrafficTreatment t = DefaultTrafficTreatment.builder() - .setOutput(packet.destLocation.port()).build(); + .setOutput(packet.getDestLocation().port()).build(); OutboundPacket o = new DefaultOutboundPacket( - packet.destLocation.deviceId(), t, ByteBuffer.wrap(packet.packet.serialize())); - if (log.isTraceEnabled()) { - log.trace("Relaying packet to destination {}", packet.destLocation); - } + packet.getDestLocation().deviceId(), t, ByteBuffer.wrap(packet.getPacket().serialize())); packetService.emit(o); - } // if + if (log.isTraceEnabled()) { + IPv6 ip6 = (IPv6) packet.getPacket().getPayload(); + UDP udp = (UDP) ip6.getPayload(); + DHCP6 dhcp6 = (DHCP6) udp.getPayload(); + log.trace("Relaying packet to destination {} eth: {} dhcp: {}", + packet.getDestLocation(), packet.getPacket(), dhcp6); + } + + } } /** @@ -683,7 +711,7 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider { .findFirst() .orElse(null); } else { - DHCP6 leafDhcp = dhcp6HandlerUtil.getDhcp6Leaf(dhcp6Payload); + DHCP6 leafDhcp = Dhcp6HandlerUtil.getDhcp6Leaf(dhcp6Payload); clientIdOption = leafDhcp.getOptions() .stream() .filter(opt -> opt instanceof Dhcp6ClientIdOption) @@ -740,7 +768,7 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider { record = record.clone(); } - Boolean isMsgRelease = dhcp6HandlerUtil.isDhcp6Release(dhcp6Packet); + Boolean isMsgRelease = Dhcp6HandlerUtil.isDhcp6Release(dhcp6Packet); IpAddressInfo ipInfo; PdPrefixInfo pdInfo = null; if (directConnFlag) { @@ -767,7 +795,7 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider { return; } - DHCP6 leafDhcp = dhcp6HandlerUtil.getDhcp6Leaf(dhcp6Packet); + DHCP6 leafDhcp = Dhcp6HandlerUtil.getDhcp6Leaf(dhcp6Packet); ipInfo = extractIpAddress(leafDhcp); if (ipInfo == null) { log.debug("ip is null"); @@ -822,7 +850,7 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider { } if (record != null) { - record.getV6Counters().incrementCounter(dhcp6HandlerUtil.getMsgTypeStr(leafMsgType)); + record.getV6Counters().incrementCounter(Dhcp6HandlerUtil.getMsgTypeStr(leafMsgType)); record.addLocation(new HostLocation(location, System.currentTimeMillis())); record.ip6Status(DHCP6.MsgType.getType(leafMsgType)); record.setDirectlyConnected(directConnFlag); @@ -837,7 +865,7 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider { try { recordSemaphore.acquire(); try { - dhcpRelayCountersStore.incrementCounter(gCount, dhcp6HandlerUtil.getMsgTypeStr(leafMsgType)); + dhcpRelayCountersStore.incrementCounter(gCount, Dhcp6HandlerUtil.getMsgTypeStr(leafMsgType)); } finally { // calling release() after a successful acquire() recordSemaphore.release(); @@ -856,13 +884,12 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider { * @param embeddedDhcp6 the dhcp6 payload within relay * @param srcMac client gw/host macAddress * @param clientInterface client interface - * @param dhcpServerIp6Address DHCP server IP */ private void addHostOrRoute(boolean directConnFlag, ConnectPoint location, DHCP6 dhcp6Relay, DHCP6 embeddedDhcp6, MacAddress srcMac, Interface clientInterface) { log.debug("addHostOrRoute entered."); VlanId vlanId = clientInterface.vlan(); - Boolean isMsgReply = dhcp6HandlerUtil.isDhcp6Reply(dhcp6Relay); + Boolean isMsgReply = Dhcp6HandlerUtil.isDhcp6Reply(dhcp6Relay); MacAddress leafClientMac; Byte leafMsgType; @@ -931,7 +958,7 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider { return; } - DHCP6 leafDhcp = dhcp6HandlerUtil.getDhcp6Leaf(embeddedDhcp6); + DHCP6 leafDhcp = Dhcp6HandlerUtil.getDhcp6Leaf(embeddedDhcp6); ipInfo = extractIpAddress(leafDhcp); if (ipInfo == null) { log.debug("ip is null"); @@ -988,7 +1015,7 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider { } } - record.getV6Counters().incrementCounter(dhcp6HandlerUtil.getMsgTypeStr(leafMsgType)); + record.getV6Counters().incrementCounter(Dhcp6HandlerUtil.getMsgTypeStr(leafMsgType)); record.ip6Status(DHCP6.MsgType.getType(leafMsgType)); record.setDirectlyConnected(directConnFlag); record.updateLastSeen(); @@ -997,7 +1024,7 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider { try { recordSemaphore.acquire(); try { - dhcpRelayCountersStore.incrementCounter(gCount, dhcp6HandlerUtil.getMsgTypeStr(leafMsgType)); + dhcpRelayCountersStore.incrementCounter(gCount, Dhcp6HandlerUtil.getMsgTypeStr(leafMsgType)); } finally { // calling release() after a successful acquire() recordSemaphore.release(); @@ -1007,6 +1034,28 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider { } } + private List processDhcp6ForwardOnly(PacketContext context, + Ethernet clientPacket, + Set clientInterfaces, + DHCP6 dhcpPacket) { + ConnectPoint inPort = context.inPacket().receivedFrom(); + log.trace("Got DHCPv6 on port {}", inPort); + boolean directConnFlag = Dhcp6HandlerUtil.directlyConnected(dhcpPacket); + + List internalPackets = new ArrayList<>(); + List serverInfoList = findValidServerInfo(directConnFlag); + + for (DhcpServerInfo dhcpServer : serverInfoList) { + Ethernet newPacket = Dhcp6HandlerUtil.buildDhcp6PacketFromClient(context, + clientPacket, clientInterfaces, dhcpServer, getServerInterface(dhcpServer)); + log.trace("Built packet for server {} : {}", dhcpServer, newPacket); + internalPackets.add(InternalPacket.internalPacket(newPacket, + dhcpServer.getDhcpServerConnectPoint().get())); + } + + return internalPackets; + } + private List processLQ6PacketFromClient(PacketContext context, Ethernet clientPacket, Set clientInterfaces, @@ -1048,27 +1097,18 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider { 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); - + boolean directConnFlag = Dhcp6HandlerUtil.directlyConnected(clientDhcp6); List internalPackets = new ArrayList<>(); List serverInfoList = findValidServerInfo(directConnFlag); List copyServerInfoList = new ArrayList(serverInfoList); for (DhcpServerInfo serverInfo : copyServerInfoList) { - if (!dhcp6HandlerUtil.checkDhcpServerConnPt(directConnFlag, serverInfo)) { + if (!Dhcp6HandlerUtil.checkDhcpServerConnPt(directConnFlag, serverInfo)) { log.warn("Can't get server connect point, ignore"); continue; } @@ -1077,14 +1117,11 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider { 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) { @@ -1094,7 +1131,7 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider { etherRouted.setSourceMACAddress(macFacingServer); etherRouted.setDestinationMACAddress(newServerInfo.getDhcpConnectMac().get()); InternalPacket internalPacket = - new Dhcp6HandlerUtil().new InternalPacket(etherRouted, + InternalPacket.internalPacket(etherRouted, serverInfo.getDhcpServerConnectPoint().get()); internalPackets.add(internalPacket); log.debug("Sending LQ to DHCP server {}", newServerInfo.getDhcpServerIp6()); @@ -1115,8 +1152,7 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider { Ethernet clientPacket, Set clientInterfaces) { ConnectPoint receivedFrom = context.inPacket().receivedFrom(); - DeviceId receivedFromDevice = receivedFrom.deviceId(); - Ip6Address relayAgentIp = dhcp6HandlerUtil.getRelayAgentIPv6Address(clientInterfaces); + Ip6Address relayAgentIp = Dhcp6HandlerUtil.getRelayAgentIPv6Address(clientInterfaces); MacAddress relayAgentMac = clientInterfaces.iterator().next().mac(); if (relayAgentIp == null || relayAgentMac == null) { log.warn("Missing DHCP relay agent interface Ipv6 addr config for " @@ -1130,12 +1166,12 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider { UDP clientUdp = (UDP) clientIpv6.getPayload(); DHCP6 clientDhcp6 = (DHCP6) clientUdp.getPayload(); - boolean directConnFlag = dhcp6HandlerUtil.directlyConnected(clientDhcp6); + 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)) + .stream().filter(iface -> Dhcp6HandlerUtil.interfaceContainsVlan(iface, vlanIdInUse)) .findFirst() .orElse(null); @@ -1144,7 +1180,7 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider { List copyServerInfoList = new ArrayList(serverInfoList); for (DhcpServerInfo serverInfo : copyServerInfoList) { - if (!dhcp6HandlerUtil.checkDhcpServerConnPt(directConnFlag, serverInfo)) { + if (!Dhcp6HandlerUtil.checkDhcpServerConnPt(directConnFlag, serverInfo)) { log.warn("Can't get server connect point, ignore"); continue; } @@ -1160,12 +1196,12 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider { continue; } - Ethernet etherReply = dhcp6HandlerUtil.buildDhcp6PacketFromClient(context, clientPacket, + Ethernet etherReply = Dhcp6HandlerUtil.buildDhcp6PacketFromClient(context, clientPacket, clientInterfaces, newServerInfo, serverInterface); removeHostOrRoute(directConnFlag, clientConnectionPoint, clientDhcp6, clientPacket, clientIpv6, clientInterface); - InternalPacket internalPacket = new Dhcp6HandlerUtil().new InternalPacket(etherReply, + InternalPacket internalPacket = InternalPacket.internalPacket(etherReply, serverInfo.getDhcpServerConnectPoint().get()); internalPackets.add(internalPacket); } @@ -1189,7 +1225,7 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider { IPv6 ipv6Packet = (IPv6) etherReply.getPayload(); UDP udpPacket = (UDP) ipv6Packet.getPayload(); DHCP6 dhcp6Relay = (DHCP6) udpPacket.getPayload(); - Boolean directConnFlag = dhcp6HandlerUtil.directlyConnected(dhcp6Relay); + Boolean directConnFlag = Dhcp6HandlerUtil.directlyConnected(dhcp6Relay); DHCP6 embeddedDhcp6 = dhcp6Relay.getOptions().stream() .filter(opt -> opt instanceof Dhcp6RelayOption) @@ -1205,7 +1241,7 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider { dhcpRelayCountersStore.incrementCounter(gCount, DhcpRelayCounters.NO_SERVER_INFO); return null; } else { - if (dhcp6HandlerUtil.isServerIpEmpty(foundServerInfo)) { + if (Dhcp6HandlerUtil.isServerIpEmpty(foundServerInfo)) { log.warn("Cannot find server info's ipaddress"); dhcpRelayCountersStore.incrementCounter(gCount, DhcpRelayCounters.NO_SERVER_IP6ADDR); return null; @@ -1228,7 +1264,7 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider { ConnectPoint clientConnectionPoint = ConnectPoint.deviceConnectPoint(clientConnectionPointStr); VlanId vlanIdInUse = VlanId.vlanId(interfaceIdOption.getVlanId()); Interface clientInterface = interfaceService.getInterfacesByPort(clientConnectionPoint) - .stream().filter(iface -> dhcp6HandlerUtil.interfaceContainsVlan(iface, vlanIdInUse)) + .stream().filter(iface -> Dhcp6HandlerUtil.interfaceContainsVlan(iface, vlanIdInUse)) .findFirst().orElse(null); if (clientInterface == null) { log.warn("Cannot get client interface for from packet, abort... vlan {}", vlanIdInUse.toString()); @@ -1274,30 +1310,23 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider { } else { udpPacket.setDestinationPort(UDP.DHCP_V6_SERVER_PORT); } - // add host or route - addHostOrRoute(directConnFlag, clientConnectionPoint, dhcp6Relay, embeddedDhcp6, - clientMac, clientInterface); + boolean hostOrRouteAllowed = learnRouteFromLeasequery || + Dhcp6HandlerUtil.getDhcp6LeafMessageType(dhcp6Relay) != MsgType.LEASEQUERY_REPLY; + log.debug("Can add host or route: {}", hostOrRouteAllowed); + + if (hostOrRouteAllowed) { + // add host or route + addHostOrRoute(directConnFlag, clientConnectionPoint, dhcp6Relay, embeddedDhcp6, + clientMac, clientInterface); + } + udpPacket.setPayload(embeddedDhcp6); udpPacket.resetChecksum(); ipv6Packet.setPayload(udpPacket); etherReply.setPayload(ipv6Packet); - 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 intfs) { - for (Interface intf : intfs) { - for (InterfaceIpAddress ip : intf.ipAddressesList()) { - Ip6Address relayAgentIp = ip.ipAddress().getIp6Address(); - if (relayAgentIp != null) { - return relayAgentIp; - } - } - } - return null; + return InternalPacket.internalPacket(etherReply, clientConnectionPoint); } @Override @@ -1476,23 +1505,6 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider { } } - /** - * Returns the first interface ip from interface. - * - * @param iface interface of one connect point - * @return the first interface IP; null if not exists an IP address in - * these interfaces - */ - private Ip6Address getFirstIpFromInterface(Interface iface) { - checkNotNull(iface, "Interface can't be null"); - return iface.ipAddressesList().stream() - .map(InterfaceIpAddress::ipAddress) - .filter(IpAddress::isIp6) - .map(IpAddress::getIp6Address) - .findFirst() - .orElse(null); - } - /** * Gets Interface facing to the server for default host. * @@ -1516,7 +1528,7 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider { } return interfaceService.getInterfacesByPort(dhcpServerConnectPoint) .stream() - .filter(iface -> dhcp6HandlerUtil.interfaceContainsVlan(iface, dhcpConnectVlan)) + .filter(iface -> Dhcp6HandlerUtil.interfaceContainsVlan(iface, dhcpConnectVlan)) .findFirst() .orElse(null); } @@ -1546,7 +1558,7 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider { } return interfaceService.getInterfacesByPort(indirectDhcpServerConnectPoint) .stream() - .filter(iface -> dhcp6HandlerUtil.interfaceContainsVlan(iface, indirectDhcpConnectVlan)) + .filter(iface -> Dhcp6HandlerUtil.interfaceContainsVlan(iface, indirectDhcpConnectVlan)) .findFirst() .orElse(null); } @@ -1615,7 +1627,7 @@ public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider { if (dhcpServerConnectPoint != null && dhcpConnectVlan != null) { serverInterface = interfaceService.getInterfacesByPort(dhcpServerConnectPoint) .stream() - .filter(iface -> dhcp6HandlerUtil.interfaceContainsVlan(iface, dhcpConnectVlan)) + .filter(iface -> Dhcp6HandlerUtil.interfaceContainsVlan(iface, dhcpConnectVlan)) .findFirst() .orElse(null); } else { diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerUtil.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerUtil.java index dac5aacea8..d059158586 100644 --- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerUtil.java +++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerUtil.java @@ -52,14 +52,16 @@ import org.onosproject.net.HostLocation; import static com.google.common.base.Preconditions.checkNotNull; +public final class Dhcp6HandlerUtil { + private static final Logger log = LoggerFactory.getLogger(Dhcp6HandlerUtil.class); -public class Dhcp6HandlerUtil { + private Dhcp6HandlerUtil() { + } - private final Logger log = LoggerFactory.getLogger(getClass()); // Returns the first v6 interface ip out of a set of interfaces or null. // Checks all interfaces, and ignores v6 interface ips - public Ip6Address getRelayAgentIPv6Address(Set intfs) { + public static Ip6Address getRelayAgentIPv6Address(Set intfs) { for (Interface intf : intfs) { for (InterfaceIpAddress ip : intf.ipAddressesList()) { Ip6Address relayAgentIp = ip.ipAddress().getIp6Address(); @@ -71,6 +73,22 @@ public class Dhcp6HandlerUtil { return null; } + /** + * Returns the first interface ip from interface. + * + * @param iface interface of one connect point + * @return the first interface IP; null if not exists an IP address in + * these interfaces + */ + private static Ip6Address getFirstIpFromInterface(Interface iface) { + checkNotNull(iface, "Interface can't be null"); + return iface.ipAddressesList().stream() + .map(InterfaceIpAddress::ipAddress) + .filter(IpAddress::isIp6) + .map(IpAddress::getIp6Address) + .findFirst() + .orElse(null); + } /** * * process the LQ reply packet from dhcp server. @@ -85,7 +103,7 @@ public class Dhcp6HandlerUtil { * @param recevingInterfaces set of server side interfaces * @return a packet ready to be sent to relevant output interface */ - public InternalPacket processLQ6PacketFromServer( + public static InternalPacket processLQ6PacketFromServer( List defaultServerInfoList, List indirectServerInfoList, Interface serverInterface, @@ -141,14 +159,14 @@ public class Dhcp6HandlerUtil { if ((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); + 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); + inPort, indirectDhcpServerConnectPoint); return null; } @@ -180,9 +198,6 @@ public class Dhcp6HandlerUtil { 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); @@ -190,23 +205,7 @@ public class Dhcp6HandlerUtil { ipv6Packet.setPayload(udpPacket); etherReply.setPayload(ipv6Packet); - return new Dhcp6HandlerUtil().new InternalPacket(etherReply, clientConnectionPoint); - } - /** - * Returns the first interface ip from interface. - * - * @param iface interface of one connect point - * @return the first interface IP; null if not exists an IP address in - * these interfaces - */ - public Ip6Address getFirstIpFromInterface(Interface iface) { - checkNotNull(iface, "Interface can't be null"); - return iface.ipAddressesList().stream() - .map(InterfaceIpAddress::ipAddress) - .filter(IpAddress::isIp6) - .map(IpAddress::getIp6Address) - .findFirst() - .orElse(null); + return InternalPacket.internalPacket(etherReply, clientConnectionPoint); } /** @@ -215,7 +214,7 @@ public class Dhcp6HandlerUtil { * @param dhcp6 dhcp6 relay-reply or relay-foward * @return dhcp6Packet dhcp6 packet extracted from relay-message */ - public DHCP6 dhcp6PacketFromRelayPacket(DHCP6 dhcp6) { + public static DHCP6 dhcp6PacketFromRelayPacket(DHCP6 dhcp6) { // extract the relay message if exist DHCP6 dhcp6Payload = dhcp6.getOptions().stream() @@ -239,7 +238,7 @@ public class Dhcp6HandlerUtil { * @param relayPacket dhcp6 relay packet * @return leafPacket non-relay dhcp6 packet */ - public DHCP6 getDhcp6Leaf(DHCP6 relayPacket) { + public static DHCP6 getDhcp6Leaf(DHCP6 relayPacket) { DHCP6 dhcp6Parent = relayPacket; DHCP6 dhcp6Child = null; @@ -263,13 +262,25 @@ public class Dhcp6HandlerUtil { return dhcp6Child; } + /** + * Determine DHCP message type (direct DHCPv6 or wrapped into relay messages). + * + * @param relayPacket {@link DHCP6} packet to be parsed + * @return {@link DHCP6.MsgType} contained message type of dhcpv6 packet/relay-message + */ + public static DHCP6.MsgType getDhcp6LeafMessageType(DHCP6 relayPacket) { + checkNotNull(relayPacket); + DHCP6 dhcp6Child = getDhcp6Leaf(relayPacket); + return DHCP6.MsgType.getType(dhcp6Child != null ? dhcp6Child.getMsgType() : relayPacket.getMsgType()); + } + /** * check if DHCP6 relay-reply is reply. * * @param relayPacket dhcp6 relay-reply * @return boolean relay-reply contains ack */ - public boolean isDhcp6Reply(DHCP6 relayPacket) { + public static boolean isDhcp6Reply(DHCP6 relayPacket) { DHCP6 leafDhcp6 = getDhcp6Leaf(relayPacket); if (leafDhcp6 != null) { if (leafDhcp6.getMsgType() == DHCP6.MsgType.REPLY.value()) { @@ -291,7 +302,7 @@ public class Dhcp6HandlerUtil { * @param dhcp6Payload dhcp6 packet * @return boolean dhcp6 contains release */ - public boolean isDhcp6Release(DHCP6 dhcp6Payload) { + public static boolean isDhcp6Release(DHCP6 dhcp6Payload) { if (dhcp6Payload.getMsgType() == DHCP6.MsgType.RELEASE.value()) { log.debug("isDhcp6Release true."); return true; // must be directly connected @@ -319,7 +330,7 @@ public class Dhcp6HandlerUtil { * @param msgTypeVal msgType byte of dhcp6 packet * @return String string value of dhcp6 msg type */ - public String getMsgTypeStr(byte msgTypeVal) { + public static String getMsgTypeStr(byte msgTypeVal) { MsgType msgType = DHCP6.MsgType.getType(msgTypeVal); return DHCP6.MsgType.getMsgTypeStr(msgType); } @@ -331,7 +342,7 @@ public class Dhcp6HandlerUtil { * @param dhcp6Packet dhcp6 packet * @return String string value of dhcp6 leaf packet msg type */ - public String findLeafMsgType(boolean directConnFlag, DHCP6 dhcp6Packet) { + public static String findLeafMsgType(boolean directConnFlag, DHCP6 dhcp6Packet) { if (directConnFlag) { return getMsgTypeStr(dhcp6Packet.getMsgType()); } else { @@ -351,7 +362,7 @@ public class Dhcp6HandlerUtil { * @param vlanId the vlan id * @return true if the Interface contains the vlan id */ - public boolean interfaceContainsVlan(Interface iface, VlanId vlanId) { + public static boolean interfaceContainsVlan(Interface iface, VlanId vlanId) { if (vlanId.equals(VlanId.NONE)) { // untagged packet, check if vlan untagged or vlan native is not NONE return !iface.vlanUntagged().equals(VlanId.NONE) || @@ -361,27 +372,13 @@ public class Dhcp6HandlerUtil { return iface.vlanTagged().contains(vlanId); } - /** - * the new class the contains Ethernet packet and destination port. - */ - public class InternalPacket { - Ethernet packet; - ConnectPoint destLocation; - public InternalPacket(Ethernet newPacket, ConnectPoint newLocation) { - packet = newPacket; - destLocation = newLocation; - } - void setLocation(ConnectPoint newLocation) { - destLocation = newLocation; - } - } /** * Check if the host is directly connected to the network or not. * * @param dhcp6Payload the dhcp6 payload * @return true if the host is directly connected to the network; false otherwise */ - public boolean directlyConnected(DHCP6 dhcp6Payload) { + public static boolean directlyConnected(DHCP6 dhcp6Payload) { log.debug("directlyConnected enters"); if (dhcp6Payload.getMsgType() == DHCP6.MsgType.LEASEQUERY.value() || @@ -405,7 +402,8 @@ public class Dhcp6HandlerUtil { return false; } else { // relay-reply - if (dhcp6Payload2.getMsgType() != DHCP6.MsgType.RELAY_REPL.value()) { + if (dhcp6Payload2.getMsgType() != DHCP6.MsgType.RELAY_REPL.value() + && dhcp6Payload2.getMsgType() != MsgType.LEASEQUERY_REPLY.value()) { log.debug("directlyConnected true. 2nd MsgType {}", dhcp6Payload2.getMsgType()); return true; // must be directly connected } else { @@ -425,7 +423,7 @@ public class Dhcp6HandlerUtil { * @param serverInfo server info to check * @return true if server info has v6 ip address; false otherwise */ - public boolean isServerIpEmpty(DhcpServerInfo serverInfo) { + public static boolean isServerIpEmpty(DhcpServerInfo serverInfo) { if (!serverInfo.getDhcpServerIp6().isPresent()) { log.warn("DhcpServerIp not available, use default DhcpServerIp {}", HexString.toHexString(serverInfo.getDhcpServerIp6().get().toOctets())); @@ -434,7 +432,7 @@ public class Dhcp6HandlerUtil { return false; } - private boolean isConnectMacEmpty(DhcpServerInfo serverInfo, Set clientInterfaces) { + private static boolean isConnectMacEmpty(DhcpServerInfo serverInfo, Set clientInterfaces) { if (!serverInfo.getDhcpConnectMac().isPresent()) { log.warn("DHCP6 {} not yet resolved .. Aborting DHCP " + "packet processing from client on port: {}", @@ -446,7 +444,7 @@ public class Dhcp6HandlerUtil { return false; } - private boolean isRelayAgentIpFromCfgEmpty(DhcpServerInfo serverInfo, DeviceId receivedFromDevice) { + private static boolean isRelayAgentIpFromCfgEmpty(DhcpServerInfo serverInfo, DeviceId receivedFromDevice) { if (!serverInfo.getRelayAgentIp6(receivedFromDevice).isPresent()) { log.warn("indirect connection: relayAgentIp NOT availale from config file! Use dynamic."); return true; @@ -454,7 +452,7 @@ public class Dhcp6HandlerUtil { return false; } - private Dhcp6Option getInterfaceIdIdOption(PacketContext context, Ethernet clientPacket) { + private static Dhcp6Option getInterfaceIdIdOption(PacketContext context, Ethernet clientPacket) { String inPortString = "-" + context.inPacket().receivedFrom().toString() + ":"; Dhcp6Option interfaceId = new Dhcp6Option(); interfaceId.setCode(DHCP6.OptionCode.INTERFACE_ID.value()); @@ -482,7 +480,7 @@ public class Dhcp6HandlerUtil { return interfaceId; } - private void addDhcp6OptionsFromClient(List options, byte[] dhcp6PacketByte, + private static void addDhcp6OptionsFromClient(List options, byte[] dhcp6PacketByte, PacketContext context, Ethernet clientPacket) { Dhcp6Option relayMessage = new Dhcp6Option(); relayMessage.setCode(DHCP6.OptionCode.RELAY_MSG.value()); @@ -504,7 +502,7 @@ public class Dhcp6HandlerUtil { * @param serverInterface target server interface * @return ethernet packet with dhcp6 packet info */ - public Ethernet buildDhcp6PacketFromClient(PacketContext context, Ethernet clientPacket, + public static Ethernet buildDhcp6PacketFromClient(PacketContext context, Ethernet clientPacket, Set clientInterfaces, DhcpServerInfo serverInfo, Interface serverInterface) { ConnectPoint receivedFrom = context.inPacket().receivedFrom(); @@ -604,7 +602,7 @@ public class Dhcp6HandlerUtil { * @param serverInfo server to check its connect point * @return boolean true if serverInfo is found; false otherwise */ - public boolean checkDhcpServerConnPt(boolean directConnFlag, + public static boolean checkDhcpServerConnPt(boolean directConnFlag, DhcpServerInfo serverInfo) { if (serverInfo.getDhcpServerConnectPoint() == null) { log.warn("DHCP6 server connect point for {} connPt {}", diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayManager.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayManager.java index f2c1b87909..f2ca330c08 100644 --- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayManager.java +++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayManager.java @@ -56,15 +56,15 @@ import org.onosproject.dhcprelay.api.DhcpHandler; import org.onosproject.dhcprelay.api.DhcpRelayService; import org.onosproject.dhcprelay.api.DhcpServerInfo; import org.onosproject.dhcprelay.config.DefaultDhcpRelayConfig; -import org.onosproject.dhcprelay.config.IgnoreDhcpConfig; -import org.onosproject.dhcprelay.config.IndirectDhcpRelayConfig; +import org.onosproject.dhcprelay.config.DhcpServerConfig; import org.onosproject.dhcprelay.config.EnableDhcpFpmConfig; +import org.onosproject.dhcprelay.config.IndirectDhcpRelayConfig; +import org.onosproject.dhcprelay.config.IgnoreDhcpConfig; import org.onosproject.dhcprelay.store.DhcpRecord; import org.onosproject.dhcprelay.store.DhcpRelayStore; import org.onosproject.dhcprelay.store.DhcpFpmPrefixStore; import org.onosproject.routing.fpm.api.FpmRecord; import org.onosproject.net.Device; -import org.onosproject.dhcprelay.config.DhcpServerConfig; import org.onosproject.net.Host; import org.onosproject.net.config.Config; import org.onosproject.net.device.DeviceEvent; @@ -206,7 +206,6 @@ public class DhcpRelayManager implements DhcpRelayService { label = "Enable DhcpRelay Fpm") protected boolean dhcpFpmEnabled = false; - private ScheduledExecutorService timerExecutor; protected DeviceListener deviceListener = new InternalDeviceListener(); @@ -321,7 +320,6 @@ public class DhcpRelayManager implements DhcpRelayService { } v6Handler.setDhcpFpmEnabled(dhcpFpmEnabled); } - } private static List buildClientDhcpSelectors() { diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/InternalPacket.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/InternalPacket.java new file mode 100644 index 0000000000..70d4ae28fd --- /dev/null +++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/InternalPacket.java @@ -0,0 +1,52 @@ +/* + * 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.onosproject.dhcprelay; + +import org.onlab.packet.Ethernet; +import org.onosproject.net.ConnectPoint; + +/** + * Container for Ethernet packet and destination port. + */ +final class InternalPacket { + private Ethernet packet; + private ConnectPoint destLocation; + + private InternalPacket(Ethernet newPacket, ConnectPoint newLocation) { + packet = newPacket; + destLocation = newLocation; + } + + public Ethernet getPacket() { + return packet; + } + + public ConnectPoint getDestLocation() { + return destLocation; + } + + /** + * Build {@link InternalPacket} object instance. + * + * @param newPacket {@link Ethernet} packet to be sent + * @param newLocation {@link ConnectPoint} packet destination + * @return new instance of {@link InternalPacket} class + */ + public static InternalPacket internalPacket(Ethernet newPacket, ConnectPoint newLocation) { + return new InternalPacket(newPacket, newLocation); + } +} diff --git a/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6LeaseQueryOption.java b/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6LeaseQueryOption.java index 5bcc8bad77..baa2e6eb82 100644 --- a/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6LeaseQueryOption.java +++ b/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6LeaseQueryOption.java @@ -36,9 +36,11 @@ public final class Dhcp6LeaseQueryOption extends Dhcp6Option { //public short QueryType; public Ip6Address linkAddress; private List options; + public byte queryType; public Dhcp6LeaseQueryOption(Dhcp6Option dhcp6Option) { super(dhcp6Option); + options = Lists.newArrayList(); } @Override @@ -66,10 +68,10 @@ public final class Dhcp6LeaseQueryOption extends Dhcp6Option { Dhcp6LeaseQueryOption lQ6Option = new Dhcp6LeaseQueryOption(dhcp6Option); byte[] optionData = lQ6Option.getData(); - if (optionData.length >= 61) { // 61 is LQ option length + 4 header + if (optionData.length >= DEFAULT_LEN) { ByteBuffer bb = ByteBuffer.wrap(optionData); // fetch the Query type - just pop the byte from the byte buffer for subsequent parsing... - bb.get(); + lQ6Option.queryType = bb.get(); byte[] ipv6Addr = new byte[16]; bb.get(ipv6Addr); lQ6Option.linkAddress = Ip6Address.valueOf(ipv6Addr); @@ -108,10 +110,13 @@ public final class Dhcp6LeaseQueryOption extends Dhcp6Option { @Override public byte[] serialize() { - ByteBuffer bb = ByteBuffer.allocate(this.getLength() + Dhcp6Option.DEFAULT_LEN); + byte[] serializedPayload = payload.serialize(); + + ByteBuffer bb = ByteBuffer.allocate(serializedPayload.length + Dhcp6Option.DEFAULT_LEN); bb.putShort(getCode()); bb.putShort(getLength()); - bb.put(payload.serialize()); + bb.put(serializedPayload); + return bb.array(); }