Java tutorial
/* * Copyright 2015, 2017 Ericsson India Global Services Pvt Ltd. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.netvirt.dhcpservice; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.math.BigInteger; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import org.apache.commons.net.util.SubnetUtils; import org.apache.commons.net.util.SubnetUtils.SubnetInfo; import org.opendaylight.controller.liblldp.EtherTypes; import org.opendaylight.controller.liblldp.NetUtils; import org.opendaylight.controller.liblldp.PacketException; import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo; import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager; import org.opendaylight.genius.mdsalutil.MDSALUtil; import org.opendaylight.genius.mdsalutil.MetaDataUtil; import org.opendaylight.genius.mdsalutil.NwConstants; import org.opendaylight.genius.mdsalutil.packet.Ethernet; import org.opendaylight.genius.mdsalutil.packet.IEEE8021Q; import org.opendaylight.genius.mdsalutil.packet.IPProtocols; import org.opendaylight.genius.mdsalutil.packet.IPv4; import org.opendaylight.genius.mdsalutil.packet.UDP; import org.opendaylight.netvirt.dhcpservice.api.DHCP; import org.opendaylight.netvirt.dhcpservice.api.DHCPConstants; import org.opendaylight.netvirt.dhcpservice.api.DHCPUtils; import org.opendaylight.netvirt.dhcpservice.api.DhcpMConstants; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetInterfaceFromIfIndexInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetInterfaceFromIfIndexInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetInterfaceFromIfIndexOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp_allocation_pool.rev161214.dhcp_allocation_pool.network.AllocationPool; import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps; import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port; import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnet.attributes.HostRoutes; import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet; import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketInReason; import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingListener; import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService; import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived; import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.SendToController; import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.config.rev150710.DhcpserviceConfig; import org.opendaylight.yangtools.yang.common.RpcResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class DhcpPktHandler implements PacketProcessingListener { private static final Logger LOG = LoggerFactory.getLogger(DhcpPktHandler.class); private final DhcpManager dhcpMgr; private final OdlInterfaceRpcService interfaceManagerRpc; private final PacketProcessingService pktService; private final DhcpExternalTunnelManager dhcpExternalTunnelManager; private final IInterfaceManager interfaceManager; private final DhcpserviceConfig config; private final DhcpAllocationPoolManager dhcpAllocationPoolMgr; public DhcpPktHandler(final DhcpManager dhcpManager, final DhcpExternalTunnelManager dhcpExternalTunnelManager, final OdlInterfaceRpcService interfaceManagerRpc, final PacketProcessingService pktService, final IInterfaceManager interfaceManager, final DhcpserviceConfig config, final DhcpAllocationPoolManager dhcpAllocationPoolMgr) { this.interfaceManagerRpc = interfaceManagerRpc; this.pktService = pktService; this.dhcpExternalTunnelManager = dhcpExternalTunnelManager; this.dhcpMgr = dhcpManager; this.interfaceManager = interfaceManager; this.config = config; this.dhcpAllocationPoolMgr = dhcpAllocationPoolMgr; } //TODO: Handle this in a separate thread @Override public void onPacketReceived(PacketReceived packet) { if (!config.isControllerDhcpEnabled()) { return; } Class<? extends PacketInReason> pktInReason = packet.getPacketInReason(); short tableId = packet.getTableId().getValue(); if ((tableId == NwConstants.DHCP_TABLE || tableId == NwConstants.DHCP_TABLE_EXTERNAL_TUNNEL) && isPktInReasonSendtoCtrl(pktInReason)) { byte[] inPayload = packet.getPayload(); Ethernet ethPkt = new Ethernet(); try { ethPkt.deserialize(inPayload, 0, inPayload.length * NetUtils.NumBitsInAByte); } catch (PacketException e) { LOG.warn("Failed to decode DHCP Packet.", e); LOG.trace("Received packet {}", packet); return; } DHCP pktIn; pktIn = getDhcpPktIn(ethPkt); if (pktIn != null) { LOG.trace("DHCPPkt received: {}", pktIn); LOG.trace("Received Packet: {}", packet); BigInteger metadata = packet.getMatch().getMetadata().getMetadata(); long portTag = MetaDataUtil.getLportFromMetadata(metadata).intValue(); String macAddress = DHCPUtils.byteArrayToString(ethPkt.getSourceMACAddress()); BigInteger tunnelId = packet.getMatch().getTunnel() == null ? null : packet.getMatch().getTunnel().getTunnelId(); String interfaceName = getInterfaceNameFromTag(portTag); InterfaceInfo interfaceInfo = interfaceManager .getInterfaceInfoFromOperationalDataStore(interfaceName); if (interfaceInfo == null) { LOG.error("Failed to get interface info for interface name {}", interfaceName); return; } DHCP replyPkt = handleDhcpPacket(pktIn, interfaceName, macAddress, tunnelId); byte[] pktOut = getDhcpPacketOut(replyPkt, ethPkt, interfaceInfo.getMacAddress()); sendPacketOut(pktOut, interfaceInfo.getDpId(), interfaceName, tunnelId); } } } private void sendPacketOut(byte[] pktOut, BigInteger dpnId, String interfaceName, BigInteger tunnelId) { List<Action> action = getEgressAction(interfaceName, tunnelId); TransmitPacketInput output = MDSALUtil.getPacketOut(action, pktOut, dpnId); LOG.trace("Transmitting packet: {}", output); this.pktService.transmitPacket(output); } private DHCP handleDhcpPacket(DHCP dhcpPkt, String interfaceName, String macAddress, BigInteger tunnelId) { LOG.trace("DHCP pkt rcvd {}", dhcpPkt); byte msgType = dhcpPkt.getMsgType(); Port port; if (tunnelId != null) { port = dhcpExternalTunnelManager.readVniMacToPortCache(tunnelId, macAddress); } else { port = getNeutronPort(interfaceName); } DhcpInfo dhcpInfo = null; if (port != null) { dhcpInfo = handleDhcpNeutronPacket(msgType, port); } else if (config.isDhcpDynamicAllocationPoolEnabled()) { dhcpInfo = handleDhcpAllocationPoolPacket(msgType, dhcpPkt, interfaceName, macAddress); } DHCP reply = null; if (dhcpInfo != null) { if (msgType == DHCPConstants.MSG_DISCOVER) { reply = getReplyToDiscover(dhcpPkt, dhcpInfo); } else if (msgType == DHCPConstants.MSG_REQUEST) { reply = getReplyToRequest(dhcpPkt, dhcpInfo); } } return reply; } private DhcpInfo handleDhcpNeutronPacket(byte msgType, Port port) { if (msgType == DHCPConstants.MSG_DECLINE) { LOG.trace("DHCPDECLINE received"); return null; } else if (msgType == DHCPConstants.MSG_RELEASE) { LOG.trace("DHCPRELEASE received"); return null; } return getDhcpInfoFromNeutronPort(port); } private DhcpInfo handleDhcpAllocationPoolPacket(byte msgType, DHCP dhcpPkt, String interfaceName, String macAddress) { String networkId = dhcpAllocationPoolMgr.getNetworkByPort(interfaceName); AllocationPool pool = (networkId != null) ? dhcpAllocationPoolMgr.getAllocationPoolByNetwork(networkId) : null; if (networkId == null || pool == null) { LOG.warn("No Dhcp Allocation Pool was found for interface: {}", interfaceName); return null; } switch (msgType) { case DHCPConstants.MSG_DISCOVER: case DHCPConstants.MSG_REQUEST: // FIXME: requested ip is currently ignored in moment of allocation return getDhcpInfoFromAllocationPool(networkId, pool, macAddress); case DHCPConstants.MSG_RELEASE: dhcpAllocationPoolMgr.releaseIpAllocation(networkId, pool, macAddress); break; default: break; } return null; } private DhcpInfo getDhcpInfoFromNeutronPort(Port port) { Subnet subnet = getNeutronSubnet(port); DhcpInfo dhcpInfo = getDhcpInfo(port, subnet); LOG.trace("NeutronPort: {} \n NeutronSubnet: {}, dhcpInfo{}", port, subnet, dhcpInfo); return dhcpInfo; } private DhcpInfo getDhcpInfoFromAllocationPool(String networkId, AllocationPool pool, String macAddress) { IpAddress allocatedIp = dhcpAllocationPoolMgr.getIpAllocation(networkId, pool, macAddress); DhcpInfo dhcpInfo = getApDhcpInfo(pool, allocatedIp); LOG.info("AllocationPoolNetwork: {}, dhcpInfo {}", networkId, dhcpInfo); return dhcpInfo; } private DhcpInfo getDhcpInfo(Port port, Subnet subnet) { DhcpInfo dhcpInfo = null; if (port != null && subnet != null) { String clientIp = getIpv4Address(port); String serverIp = null; if (isIpv4Address(subnet.getGatewayIp())) { serverIp = subnet.getGatewayIp().getIpv4Address().getValue(); } if (clientIp != null && serverIp != null) { List<IpAddress> dnsServers = subnet.getDnsNameservers(); dhcpInfo = new DhcpInfo(); dhcpInfo.setClientIp(clientIp).setServerIp(serverIp) .setCidr(String.valueOf(subnet.getCidr().getValue())).setHostRoutes(subnet.getHostRoutes()) .setDnsServersIpAddrs(dnsServers).setGatewayIp(serverIp); } } return dhcpInfo; } private DhcpInfo getApDhcpInfo(AllocationPool ap, IpAddress allocatedIp) { DhcpInfo dhcpInfo = null; String clientIp = String.valueOf(allocatedIp.getValue()); String serverIp = String.valueOf(ap.getGateway().getValue()); if (clientIp != null && serverIp != null) { List<IpAddress> dnsServers = ap.getDnsServers(); dhcpInfo = new DhcpInfo(); dhcpInfo.setClientIp(clientIp).setServerIp(serverIp).setCidr(String.valueOf(ap.getSubnet().getValue())) .setHostRoutes(Collections.emptyList()).setDnsServersIpAddrs(dnsServers).setGatewayIp(serverIp); } return dhcpInfo; } /* TODO: * getIpv4Address and isIpv4Address * Many other modules use/need similar methods. Should * be refactored to a common NeutronUtils module. * */ private String getIpv4Address(Port port) { for (FixedIps fixedIp : port.getFixedIps()) { if (isIpv4Address(fixedIp.getIpAddress())) { return fixedIp.getIpAddress().getIpv4Address().getValue(); } } return null; } private boolean isIpv4Address(IpAddress ip) { return ip.getIpv4Address() != null; } private Subnet getNeutronSubnet(Port port) { return dhcpMgr.getNeutronSubnet(port); } private Port getNeutronPort(String interfaceName) { return dhcpMgr.getNeutronPort(interfaceName); } private DHCP getDhcpPktIn(Ethernet actualEthernetPacket) { Ethernet ethPkt = actualEthernetPacket; if (ethPkt.getEtherType() == (short) NwConstants.ETHTYPE_802_1Q) { ethPkt = (Ethernet) ethPkt.getPayload(); } // Currently only IPv4 is supported if (ethPkt.getPayload() instanceof IPv4) { IPv4 ipPkt = (IPv4) ethPkt.getPayload(); if (ipPkt.getPayload() instanceof UDP) { UDP udpPkt = (UDP) ipPkt.getPayload(); if (udpPkt.getSourcePort() == DhcpMConstants.DHCP_CLIENT_PORT && udpPkt.getDestinationPort() == DhcpMConstants.DHCP_SERVER_PORT) { LOG.trace("Matched DHCP_CLIENT_PORT and DHCP_SERVER_PORT"); byte[] rawDhcpPayload = udpPkt.getRawPayload(); DHCP reply = new DHCP(); try { reply.deserialize(rawDhcpPayload, 0, rawDhcpPayload.length); } catch (PacketException e) { LOG.warn("Failed to deserialize DHCP pkt"); LOG.trace("Reason for failure", e); return null; } return reply; } } } return null; } DHCP getReplyToDiscover(DHCP dhcpPkt, DhcpInfo dhcpInfo) { DHCP reply = new DHCP(); reply.setOp(DHCPConstants.BOOTREPLY); reply.setHtype(dhcpPkt.getHtype()); reply.setHlen(dhcpPkt.getHlen()); reply.setHops((byte) 0); reply.setXid(dhcpPkt.getXid()); reply.setSecs((short) 0); reply.setYiaddr(dhcpInfo.getClientIp()); reply.setSiaddr(dhcpInfo.getServerIp()); reply.setFlags(dhcpPkt.getFlags()); reply.setGiaddr(dhcpPkt.getGiaddr()); reply.setChaddr(dhcpPkt.getChaddr()); reply.setMsgType(DHCPConstants.MSG_OFFER); if (dhcpPkt.containsOption(DHCPConstants.OPT_PARAMETER_REQUEST_LIST)) { setParameterListOptions(dhcpPkt, reply, dhcpInfo); } setCommonOptions(reply, dhcpInfo); return reply; } DHCP getReplyToRequest(DHCP dhcpPkt, DhcpInfo dhcpInfo) { boolean sendAck = false; byte[] requestedIp = null; DHCP reply = new DHCP(); reply.setOp(DHCPConstants.BOOTREPLY); reply.setHtype(dhcpPkt.getHtype()); reply.setHlen(dhcpPkt.getHlen()); reply.setHops((byte) 0); reply.setXid(dhcpPkt.getXid()); reply.setSecs((short) 0); reply.setFlags(dhcpPkt.getFlags()); reply.setGiaddr(dhcpPkt.getGiaddr()); reply.setChaddr(dhcpPkt.getChaddr()); byte[] allocatedIp = DHCPUtils.strAddrToByteArray(dhcpInfo.getClientIp()); if (Arrays.equals(allocatedIp, dhcpPkt.getCiaddr())) { //This means a renew request sendAck = true; } else { requestedIp = dhcpPkt.getOptionBytes(DHCPConstants.OPT_REQUESTED_ADDRESS); sendAck = Arrays.equals(allocatedIp, requestedIp); } if (sendAck) { reply.setCiaddr(dhcpPkt.getCiaddr()); reply.setYiaddr(dhcpInfo.getClientIp()); reply.setSiaddr(dhcpInfo.getServerIp()); reply.setMsgType(DHCPConstants.MSG_ACK); if (dhcpPkt.containsOption(DHCPConstants.OPT_PARAMETER_REQUEST_LIST)) { setParameterListOptions(dhcpPkt, reply, dhcpInfo); } } else { reply.setMsgType(DHCPConstants.MSG_NAK); } setCommonOptions(reply, dhcpInfo); return reply; } protected byte[] getDhcpPacketOut(DHCP reply, Ethernet etherPkt, String phyAddrees) { if (reply == null) { /* * DECLINE or RELEASE don't result in reply packet */ return null; } LOG.trace("Sending DHCP Pkt {}", reply); InetAddress serverIp = reply.getOptionInetAddr(DHCPConstants.OPT_SERVER_IDENTIFIER); // create UDP pkt UDP udpPkt = new UDP(); byte[] rawPkt; try { rawPkt = reply.serialize(); } catch (PacketException e) { LOG.warn("Failed to serialize packet", e); return null; } udpPkt.setRawPayload(rawPkt); udpPkt.setDestinationPort(DhcpMConstants.DHCP_CLIENT_PORT); udpPkt.setSourcePort(DhcpMConstants.DHCP_SERVER_PORT); udpPkt.setLength((short) (rawPkt.length + 8)); //Create IP Pkt try { rawPkt = udpPkt.serialize(); } catch (PacketException e) { LOG.warn("Failed to serialize packet", e); return null; } short checkSum = 0; boolean computeUdpChecksum = true; if (computeUdpChecksum) { checkSum = computeChecksum(rawPkt, serverIp.getAddress(), NetUtils.intToByteArray4(DhcpMConstants.BCAST_IP)); } udpPkt.setChecksum(checkSum); IPv4 ip4Reply = new IPv4(); ip4Reply.setPayload(udpPkt); ip4Reply.setProtocol(IPProtocols.UDP.byteValue()); ip4Reply.setSourceAddress(serverIp); ip4Reply.setDestinationAddress(DhcpMConstants.BCAST_IP); ip4Reply.setTotalLength((short) (rawPkt.length + 20)); ip4Reply.setTtl((byte) 32); // create Ethernet Frame Ethernet ether = new Ethernet(); if (etherPkt.getEtherType() == (short) NwConstants.ETHTYPE_802_1Q) { IEEE8021Q vlanPacket = (IEEE8021Q) etherPkt.getPayload(); IEEE8021Q vlanTagged = new IEEE8021Q(); vlanTagged.setCFI(vlanPacket.getCfi()); vlanTagged.setPriority(vlanPacket.getPriority()); vlanTagged.setVlanId(vlanPacket.getVlanId()); vlanTagged.setPayload(ip4Reply); vlanTagged.setEtherType(EtherTypes.IPv4.shortValue()); ether.setPayload(vlanTagged); ether.setEtherType((short) NwConstants.ETHTYPE_802_1Q); } else { ether.setEtherType(EtherTypes.IPv4.shortValue()); ether.setPayload(ip4Reply); } ether.setSourceMACAddress(getServerMacAddress(phyAddrees)); ether.setDestinationMACAddress(etherPkt.getSourceMACAddress()); try { rawPkt = ether.serialize(); } catch (PacketException e) { LOG.warn("Failed to serialize ethernet reply", e); return null; } return rawPkt; } private byte[] getServerMacAddress(String phyAddress) { // Should we return ControllerMac instead? return DHCPUtils.strMacAddrtoByteArray(phyAddress); } public short computeChecksum(byte[] inData, byte[] srcAddr, byte[] destAddr) { int sum = 0; int carry = 0; int wordData; int index; for (index = 0; index < inData.length - 1; index = index + 2) { // Skip, if the current bytes are checkSum bytes wordData = (inData[index] << 8 & 0xFF00) + (inData[index + 1] & 0xFF); sum = sum + wordData; } if (index < inData.length) { wordData = (inData[index] << 8 & 0xFF00) + (0 & 0xFF); sum = sum + wordData; } for (index = 0; index < 4; index = index + 2) { wordData = (srcAddr[index] << 8 & 0xFF00) + (srcAddr[index + 1] & 0xFF); sum = sum + wordData; } for (index = 0; index < 4; index = index + 2) { wordData = (destAddr[index] << 8 & 0xFF00) + (destAddr[index + 1] & 0xFF); sum = sum + wordData; } sum = sum + 17 + inData.length; while (sum >> 16 != 0) { carry = sum >> 16; sum = (sum & 0xFFFF) + carry; } short checkSum = (short) ~((short) sum & 0xFFFF); if (checkSum == 0) { checkSum = (short) 0xffff; } return checkSum; } private void setCommonOptions(DHCP pkt, DhcpInfo dhcpInfo) { String gwIp = dhcpInfo.getGatewayIp(); if (pkt.getMsgType() != DHCPConstants.MSG_NAK) { setNonNakOptions(pkt, dhcpInfo); } try { /* * setParameterListOptions may have initialized some of these * options to maintain order. If we can't fill them, unset to avoid * sending wrong information in reply. */ if (gwIp != null) { pkt.setOptionInetAddr(DHCPConstants.OPT_SERVER_IDENTIFIER, gwIp); } else { pkt.unsetOption(DHCPConstants.OPT_SERVER_IDENTIFIER); } } catch (UnknownHostException e) { LOG.warn("Failed to set option", e); } } private void setNonNakOptions(DHCP pkt, DhcpInfo dhcpInfo) { pkt.setOptionInt(DHCPConstants.OPT_LEASE_TIME, dhcpMgr.getDhcpLeaseTime()); if (dhcpMgr.getDhcpDefDomain() != null) { pkt.setOptionString(DHCPConstants.OPT_DOMAIN_NAME, dhcpMgr.getDhcpDefDomain()); } if (dhcpMgr.getDhcpLeaseTime() > 0) { pkt.setOptionInt(DHCPConstants.OPT_REBINDING_TIME, dhcpMgr.getDhcpRebindingTime()); pkt.setOptionInt(DHCPConstants.OPT_RENEWAL_TIME, dhcpMgr.getDhcpRenewalTime()); } SubnetUtils util = null; SubnetInfo info = null; util = new SubnetUtils(dhcpInfo.getCidr()); info = util.getInfo(); String gwIp = dhcpInfo.getGatewayIp(); List<String> dnServers = dhcpInfo.getDnsServers(); try { /* * setParameterListOptions may have initialized some of these * options to maintain order. If we can't fill them, unset to avoid * sending wrong information in reply. */ if (gwIp != null) { pkt.setOptionInetAddr(DHCPConstants.OPT_ROUTERS, gwIp); } else { pkt.unsetOption(DHCPConstants.OPT_ROUTERS); } if (info != null) { pkt.setOptionInetAddr(DHCPConstants.OPT_SUBNET_MASK, info.getNetmask()); pkt.setOptionInetAddr(DHCPConstants.OPT_BROADCAST_ADDRESS, info.getBroadcastAddress()); } else { pkt.unsetOption(DHCPConstants.OPT_SUBNET_MASK); pkt.unsetOption(DHCPConstants.OPT_BROADCAST_ADDRESS); } if (dnServers != null && dnServers.size() > 0) { pkt.setOptionStrAddrs(DHCPConstants.OPT_DOMAIN_NAME_SERVERS, dnServers); } else { pkt.unsetOption(DHCPConstants.OPT_DOMAIN_NAME_SERVERS); } } catch (UnknownHostException e) { // TODO Auto-generated catch block LOG.warn("Failed to set option", e); } } private void setParameterListOptions(DHCP req, DHCP reply, DhcpInfo dhcpInfo) { byte[] paramList = req.getOptionBytes(DHCPConstants.OPT_PARAMETER_REQUEST_LIST); for (byte element : paramList) { switch (element) { case DHCPConstants.OPT_SUBNET_MASK: case DHCPConstants.OPT_ROUTERS: case DHCPConstants.OPT_SERVER_IDENTIFIER: case DHCPConstants.OPT_DOMAIN_NAME_SERVERS: case DHCPConstants.OPT_BROADCAST_ADDRESS: case DHCPConstants.OPT_LEASE_TIME: case DHCPConstants.OPT_RENEWAL_TIME: case DHCPConstants.OPT_REBINDING_TIME: /* These values will be filled in setCommonOptions * Setting these just to preserve order as * specified in PARAMETER_REQUEST_LIST. */ reply.setOptionInt(element, 0); break; case DHCPConstants.OPT_DOMAIN_NAME: reply.setOptionString(element, " "); break; case DHCPConstants.OPT_CLASSLESS_ROUTE: setOptionClasslessRoute(reply, dhcpInfo); break; default: LOG.trace("DHCP Option code {} not supported yet", element); break; } } } private void setOptionClasslessRoute(DHCP reply, DhcpInfo dhcpInfo) { List<HostRoutes> hostRoutes = dhcpInfo.getHostRoutes(); if (hostRoutes == null) { //we can't set this option, so return return; } ByteArrayOutputStream result = new ByteArrayOutputStream(); for (HostRoutes hostRoute : hostRoutes) { if (hostRoute.getNexthop().getIpv4Address() == null || hostRoute.getDestination().getIpv4Prefix() == null) { // we only deal with IPv4 addresses return; } String router = hostRoute.getNexthop().getIpv4Address().getValue(); String dest = hostRoute.getDestination().getIpv4Prefix().getValue(); try { result.write(convertToClasslessRouteOption(dest, router)); } catch (IOException | NullPointerException e) { LOG.trace("Exception {}", e.getMessage()); } } if (result.size() > 0) { reply.setOptionBytes(DHCPConstants.OPT_CLASSLESS_ROUTE, result.toByteArray()); } } protected byte[] convertToClasslessRouteOption(String dest, String router) { ByteArrayOutputStream byteArray = new ByteArrayOutputStream(); if (dest == null || router == null) { return null; } //get prefix Short prefix = null; String[] parts = dest.split("/"); if (parts.length < 2) { prefix = (short) 0; } else { prefix = Short.valueOf(parts[1]); } byteArray.write(prefix.byteValue()); SubnetUtils util = new SubnetUtils(dest); SubnetInfo info = util.getInfo(); String strNetAddr = info.getNetworkAddress(); try { byte[] netAddr = InetAddress.getByName(strNetAddr).getAddress(); //Strip any trailing 0s from netAddr for (int i = 0; i < netAddr.length; i++) { if (netAddr[i] != 0) { byteArray.write(netAddr, i, 1); } } byteArray.write(InetAddress.getByName(router).getAddress()); } catch (IOException e) { return null; } return byteArray.toByteArray(); } private boolean isPktInReasonSendtoCtrl(Class<? extends PacketInReason> pktInReason) { return pktInReason == SendToController.class; } private String getInterfaceNameFromTag(long portTag) { String interfaceName = null; GetInterfaceFromIfIndexInput input = new GetInterfaceFromIfIndexInputBuilder().setIfIndex((int) portTag) .build(); Future<RpcResult<GetInterfaceFromIfIndexOutput>> futureOutput = interfaceManagerRpc .getInterfaceFromIfIndex(input); try { GetInterfaceFromIfIndexOutput output = futureOutput.get().getResult(); interfaceName = output.getInterfaceName(); } catch (InterruptedException | ExecutionException e) { LOG.error("Error while retrieving the interfaceName from tag using getInterfaceFromIfIndex RPC"); } LOG.trace("Returning interfaceName {} for tag {} form getInterfaceNameFromTag", interfaceName, portTag); return interfaceName; } private List<Action> getEgressAction(String interfaceName, BigInteger tunnelId) { List<Action> actions = null; try { GetEgressActionsForInterfaceInputBuilder egressAction = new GetEgressActionsForInterfaceInputBuilder() .setIntfName(interfaceName); if (tunnelId != null) { egressAction.setTunnelKey(tunnelId.longValue()); } Future<RpcResult<GetEgressActionsForInterfaceOutput>> result = interfaceManagerRpc .getEgressActionsForInterface(egressAction.build()); RpcResult<GetEgressActionsForInterfaceOutput> rpcResult = result.get(); if (!rpcResult.isSuccessful()) { LOG.warn("RPC Call to Get egress actions for interface {} returned with Errors {}", interfaceName, rpcResult.getErrors()); } else { actions = rpcResult.getResult().getAction(); } } catch (InterruptedException | ExecutionException e) { LOG.warn("Exception when egress actions for interface {}", interfaceName, e); } return actions; } }