normal/main: Search for specific config files for netboot
This patch implements a search for a specific configuration when the config file is on a remoteserver. It uses the following order: 1) DHCP client UUID option. 2) MAC address (in lower case hexadecimal with dash separators); 3) IP (in upper case hexadecimal) or IPv6; 4) The original grub.cfg file. This procedure is similar to what is used by pxelinux and yaboot: http://www.syslinux.org/wiki/index.php/PXELINUX#config It is enabled by default but can be disabled by setting the environment variable "feature_net_search_cfg" to "n" in an embedded configuration. Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=873406 Signed-off-by: Paulo Flabiano Smorigo <pfsmorigo@br.ibm.com> Signed-off-by: Javier Martinez Canillas <javierm@redhat.com> Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
This commit is contained in:
parent
febc761e67
commit
cb2f15c544
3 changed files with 155 additions and 4 deletions
|
@ -1735,6 +1735,137 @@ grub_net_restore_hw (void)
|
||||||
return GRUB_ERR_NONE;
|
return GRUB_ERR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
grub_err_t
|
||||||
|
grub_net_search_config_file (char *config)
|
||||||
|
{
|
||||||
|
grub_size_t config_len;
|
||||||
|
char *suffix;
|
||||||
|
|
||||||
|
auto int search_through (grub_size_t num_tries, grub_size_t slice_size);
|
||||||
|
int search_through (grub_size_t num_tries, grub_size_t slice_size)
|
||||||
|
{
|
||||||
|
while (num_tries-- > 0)
|
||||||
|
{
|
||||||
|
grub_file_t file;
|
||||||
|
|
||||||
|
grub_dprintf ("net", "attempt to fetch config %s\n", config);
|
||||||
|
|
||||||
|
file = grub_file_open (config, GRUB_FILE_TYPE_CONFIG);
|
||||||
|
|
||||||
|
if (file)
|
||||||
|
{
|
||||||
|
grub_file_close (file);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (grub_errno == GRUB_ERR_IO)
|
||||||
|
grub_errno = GRUB_ERR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (grub_strlen (suffix) < slice_size)
|
||||||
|
break;
|
||||||
|
|
||||||
|
config[grub_strlen (config) - slice_size] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
config_len = grub_strlen (config);
|
||||||
|
config[config_len] = '-';
|
||||||
|
suffix = config + config_len + 1;
|
||||||
|
|
||||||
|
struct grub_net_network_level_interface *inf;
|
||||||
|
FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
|
||||||
|
{
|
||||||
|
/* By the Client UUID. */
|
||||||
|
char *ptr;
|
||||||
|
int client_uuid_len;
|
||||||
|
char *client_uuid_var;
|
||||||
|
const char *client_uuid;
|
||||||
|
|
||||||
|
client_uuid_len = sizeof ("net_") + grub_strlen (inf->name) +
|
||||||
|
sizeof ("_clientuuid") + 1;
|
||||||
|
|
||||||
|
client_uuid_var = grub_zalloc (client_uuid_len);
|
||||||
|
if (!client_uuid_var)
|
||||||
|
return grub_errno;
|
||||||
|
|
||||||
|
grub_snprintf (client_uuid_var, client_uuid_len,
|
||||||
|
"net_%s_clientuuid", inf->name);
|
||||||
|
|
||||||
|
client_uuid = grub_env_get (client_uuid_var);
|
||||||
|
grub_free (client_uuid_var);
|
||||||
|
|
||||||
|
if (client_uuid)
|
||||||
|
{
|
||||||
|
grub_strcpy (suffix, client_uuid);
|
||||||
|
if (search_through (1, 0) == 0)
|
||||||
|
return GRUB_ERR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* By the MAC address. */
|
||||||
|
|
||||||
|
/* Add ethernet type */
|
||||||
|
grub_strcpy (suffix, "01-");
|
||||||
|
|
||||||
|
grub_net_hwaddr_to_str (&inf->hwaddress, suffix + 3);
|
||||||
|
|
||||||
|
for (ptr = suffix; *ptr; ptr++)
|
||||||
|
if (*ptr == ':')
|
||||||
|
*ptr = '-';
|
||||||
|
|
||||||
|
if (search_through (1, 0) == 0)
|
||||||
|
return GRUB_ERR_NONE;
|
||||||
|
|
||||||
|
/* By IP address */
|
||||||
|
|
||||||
|
switch ((&inf->address)->type)
|
||||||
|
{
|
||||||
|
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4:
|
||||||
|
{
|
||||||
|
grub_uint32_t n = grub_be_to_cpu32 ((&inf->address)->ipv4);
|
||||||
|
|
||||||
|
grub_snprintf (suffix, GRUB_NET_MAX_STR_ADDR_LEN, "%02X%02X%02X%02X", \
|
||||||
|
((n >> 24) & 0xff), ((n >> 16) & 0xff), \
|
||||||
|
((n >> 8) & 0xff), ((n >> 0) & 0xff));
|
||||||
|
|
||||||
|
if (search_through (8, 1) == 0)
|
||||||
|
return GRUB_ERR_NONE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6:
|
||||||
|
{
|
||||||
|
char buf[GRUB_NET_MAX_STR_ADDR_LEN];
|
||||||
|
struct grub_net_network_level_address base;
|
||||||
|
base.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
|
||||||
|
grub_memcpy (&base.ipv6, ((&inf->address)->ipv6), 16);
|
||||||
|
grub_net_addr_to_str (&base, buf);
|
||||||
|
|
||||||
|
for (ptr = buf; *ptr; ptr++)
|
||||||
|
if (*ptr == ':')
|
||||||
|
*ptr = '-';
|
||||||
|
|
||||||
|
grub_snprintf (suffix, GRUB_NET_MAX_STR_ADDR_LEN, "%s", buf);
|
||||||
|
if (search_through (1, 0) == 0)
|
||||||
|
return GRUB_ERR_NONE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV:
|
||||||
|
return grub_error (GRUB_ERR_BUG, "shouldn't reach here");
|
||||||
|
default:
|
||||||
|
return grub_error (GRUB_ERR_BUG,
|
||||||
|
"unsupported address type %d", (&inf->address)->type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove the remaining minus sign at the end. */
|
||||||
|
config[config_len] = '\0';
|
||||||
|
|
||||||
|
return GRUB_ERR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
static struct grub_preboot *fini_hnd;
|
static struct grub_preboot *fini_hnd;
|
||||||
|
|
||||||
static grub_command_t cmd_addaddr, cmd_deladdr, cmd_addroute, cmd_delroute;
|
static grub_command_t cmd_addaddr, cmd_deladdr, cmd_addroute, cmd_delroute;
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <grub/kernel.h>
|
#include <grub/kernel.h>
|
||||||
|
#include <grub/net.h>
|
||||||
#include <grub/normal.h>
|
#include <grub/normal.h>
|
||||||
#include <grub/dl.h>
|
#include <grub/dl.h>
|
||||||
#include <grub/misc.h>
|
#include <grub/misc.h>
|
||||||
|
@ -324,10 +325,27 @@ grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)),
|
||||||
prefix = grub_env_get ("prefix");
|
prefix = grub_env_get ("prefix");
|
||||||
if (prefix)
|
if (prefix)
|
||||||
{
|
{
|
||||||
config = grub_xasprintf ("%s/grub.cfg", prefix);
|
grub_size_t config_len;
|
||||||
if (! config)
|
int disable_net_search = 0;
|
||||||
|
const char *net_search_cfg;
|
||||||
|
|
||||||
|
config_len = grub_strlen (prefix) +
|
||||||
|
sizeof ("/grub.cfg-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX");
|
||||||
|
config = grub_malloc (config_len);
|
||||||
|
|
||||||
|
if (!config)
|
||||||
goto quit;
|
goto quit;
|
||||||
|
|
||||||
|
grub_snprintf (config, config_len, "%s/grub.cfg", prefix);
|
||||||
|
|
||||||
|
net_search_cfg = grub_env_get ("feature_net_search_cfg");
|
||||||
|
if (net_search_cfg && net_search_cfg[0] == 'n')
|
||||||
|
disable_net_search = 1;
|
||||||
|
|
||||||
|
if (grub_strncmp (prefix + 1, "tftp", sizeof ("tftp") - 1) == 0 &&
|
||||||
|
!disable_net_search)
|
||||||
|
grub_net_search_config_file (config);
|
||||||
|
|
||||||
grub_enter_normal_mode (config);
|
grub_enter_normal_mode (config);
|
||||||
grub_free (config);
|
grub_free (config);
|
||||||
}
|
}
|
||||||
|
|
|
@ -569,6 +569,8 @@ grub_net_add_dns_server (const struct grub_net_network_level_address *s);
|
||||||
void
|
void
|
||||||
grub_net_remove_dns_server (const struct grub_net_network_level_address *s);
|
grub_net_remove_dns_server (const struct grub_net_network_level_address *s);
|
||||||
|
|
||||||
|
grub_err_t
|
||||||
|
grub_net_search_config_file (char *config);
|
||||||
|
|
||||||
extern char *grub_net_default_server;
|
extern char *grub_net_default_server;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue