Support to specify BootFileName and ServerName in DHCP Option
Change-Id: I0b1cc4af29db933e22b42f999c56a2189a967b97
diff --git a/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/api/Constants.java b/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/api/Constants.java
index 4410d70..897f473 100644
--- a/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/api/Constants.java
+++ b/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/api/Constants.java
@@ -60,6 +60,7 @@
public static final String PCI_VENDOR_INFO = "pci_vendor_info";
public static final String DIRECT = "direct";
+ public static final String BAREMETAL = "baremetal";
public static final String PCISLOT = "pci_slot";
public static final String ANNOTATION_NETWORK_ID = "networkId";
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingDhcpHandler.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingDhcpHandler.java
index 19551ea..adc6bad 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingDhcpHandler.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingDhcpHandler.java
@@ -56,6 +56,7 @@
import org.openstack4j.model.network.Network;
import org.openstack4j.model.network.Port;
import org.openstack4j.model.network.Subnet;
+import org.openstack4j.openstack.networking.domain.NeutronPort;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
@@ -80,16 +81,21 @@
import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_END;
import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_LeaseTime;
import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_MessageType;
+import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_RequestedParameters;
import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_RouterAddress;
import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_SubnetMask;
import static org.onlab.packet.DHCP.MsgType.DHCPACK;
import static org.onlab.packet.DHCP.MsgType.DHCPOFFER;
import static org.onlab.util.Tools.groupedThreads;
+import static org.onosproject.openstacknetworking.api.Constants.BAREMETAL;
import static org.onosproject.openstacknetworking.api.Constants.DHCP_TABLE;
import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_DHCP_RULE;
import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.DHCP_SERVER_MAC;
import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.DHCP_SERVER_MAC_DEFAULT;
import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getBroadcastAddr;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getDhcpFullBootFileName;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getDhcpServerName;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getDhcpStaticBootFileName;
import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
import static org.slf4j.LoggerFactory.getLogger;
@@ -124,6 +130,9 @@
private static final int DHCP_OPTION_DNS_LENGTH = 8;
private static final int DHCP_OPTION_MTU_LENGTH = 2;
+ private static final byte DHCP_OPTION_SERVER_NAME_CODE = (byte) 66;
+ private static final byte DHCP_OPTION_BOOT_FILE_NAME_CODE = (byte) 67;
+
@Reference(cardinality = ReferenceCardinality.MANDATORY)
protected CoreService coreService;
@@ -341,7 +350,7 @@
dhcpRequest,
packetType,
Ip4Address.valueOf(fixedIp.getIpAddress()),
- osSubnet);
+ (NeutronPort) port, osSubnet);
udpReply.setPayload(dhcpReply);
ipv4Reply.setPayload(udpReply);
@@ -368,7 +377,7 @@
}
private DHCP buildDhcpReply(DHCP request, byte msgType, Ip4Address yourIp,
- Subnet osSubnet) {
+ NeutronPort port, Subnet osSubnet) {
Ip4Address gatewayIp = clusterService.getLocalNode().ip().getIp4Address();
int subnetPrefixLen = IpPrefix.valueOf(osSubnet.getCidr()).prefixLength();
@@ -416,6 +425,12 @@
options.add(doRouterAddr(osSubnet));
}
+ // sets TFTP and bootfilename for PXE boot
+ if (BAREMETAL.equalsIgnoreCase(port.getvNicType())) {
+ options.add(doTftp(port));
+ options.add(doBootfileName(request, port));
+ }
+
// end option
options.add(doEnd());
@@ -512,6 +527,39 @@
return option;
}
+ private DhcpOption doTftp(NeutronPort port) {
+ String serverName = getDhcpServerName(port);
+ log.info("DHCP server name : {}", serverName);
+
+ DhcpOption option = new DhcpOption();
+ option.setCode(DHCP_OPTION_SERVER_NAME_CODE);
+ option.setLength((byte) serverName.length());
+ option.setData(serverName.getBytes());
+
+ return option;
+ }
+
+ private DhcpOption doBootfileName(DHCP request, NeutronPort port) {
+ String bootStaticFileName = getDhcpStaticBootFileName(port);
+ String bootFullFileName = getDhcpFullBootFileName(port);
+
+ DhcpOption option = new DhcpOption();
+ option.setCode(DHCP_OPTION_BOOT_FILE_NAME_CODE);
+
+ DhcpOption requestOption = request.getOption(OptionCode_RequestedParameters);
+ if (requestOption.getLength() > 30) {
+ log.info("DHCP static boot file name {}", bootStaticFileName);
+ option.setLength((byte) bootStaticFileName.length());
+ option.setData(bootStaticFileName.getBytes());
+ } else {
+ log.info("DHCP full boot file path {}", bootFullFileName);
+ option.setLength((byte) bootFullFileName.length());
+ option.setData(bootFullFileName.getBytes());
+ }
+
+ return option;
+ }
+
private DhcpOption doClasslessSr(Subnet osSubnet) {
DhcpOption option = new DhcpOption();
option.setCode(OptionCode_Classless_Static_Route.getValue());
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtil.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtil.java
index ff53f1b..cb78448 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtil.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtil.java
@@ -20,6 +20,7 @@
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.base.Charsets;
import com.google.common.base.Strings;
@@ -95,6 +96,7 @@
import org.openstack4j.model.network.SecurityGroup;
import org.openstack4j.model.network.Subnet;
import org.openstack4j.openstack.OSFactory;
+import org.openstack4j.openstack.networking.domain.NeutronPort;
import org.openstack4j.openstack.networking.domain.NeutronRouterInterface;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -1470,6 +1472,53 @@
}
/**
+ * Obtains the DHCP server name from option.
+ *
+ * @param port neutron port
+ * @return server name
+ */
+ public static String getDhcpServerName(NeutronPort port) {
+ return getDhcpOptionValue(port, "server-ip-address");
+ }
+
+ /**
+ * Obtains the DHCP static boot file name from option.
+ *
+ * @param port neutron port
+ * @return DHCP static boot file name
+ */
+ public static String getDhcpStaticBootFileName(NeutronPort port) {
+ return getDhcpOptionValue(port, "tag:!ipxe,67");
+ }
+
+ /**
+ * Obtains the DHCP full boot file name from option.
+ *
+ * @param port neutron port
+ * @return DHCP full boot file name
+ */
+ public static String getDhcpFullBootFileName(NeutronPort port) {
+ return getDhcpOptionValue(port, "tag:ipxe,67");
+ }
+
+ private static String getDhcpOptionValue(NeutronPort port, String optionNameStr) {
+ ObjectNode node = modelEntityToJson(port, NeutronPort.class);
+
+ if (node != null) {
+ JsonNode portJson = node.get("port");
+ ArrayNode options = (ArrayNode) portJson.get("extra_dhcp_opts");
+ for (JsonNode option : options) {
+ String optionName = option.get("optName").asText();
+ if (StringUtils.equals(optionName, optionNameStr)) {
+ return option.get("optValue").asText();
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
* Builds up and a complete endpoint URL from gateway node.
*
* @param node gateway node