Commit bfb4a404 authored by Leigh Stoller's avatar Leigh Stoller

Add ACK support to clear the next_boot_path fields. Currently this

is implemented in netdisk (command line mode). If netdisk succeeds,
it will send an ACK packet to bootinfo which causes it to clear the
next_boot_path field in the database so that the next reboot falls
back to def_boot.
parent ba8b3516
......@@ -55,6 +55,8 @@ main()
signal(SIGHUP, onhup);
while (1) {
int ack = 0;
if ((mlen = recvfrom(sock, &boot_info, sizeof(boot_info),
0, (struct sockaddr *)&client, &length))
< 0) {
......@@ -62,23 +64,33 @@ main()
exit(1);
}
if (boot_info.opcode != BIOPCODE_BOOTWHAT_REQUEST) {
switch (boot_info.opcode) {
case BIOPCODE_BOOTWHAT_REQUEST:
syslog(LOG_INFO, "%s: REQUEST",
inet_ntoa(client.sin_addr));
err = query_bootinfo_db(client.sin_addr, boot_whatp);
break;
case BIOPCODE_BOOTWHAT_ACK:
syslog(LOG_INFO, "%s: ACK",
inet_ntoa(client.sin_addr));
ack_bootinfo_db(client.sin_addr, boot_whatp);
continue;
default:
syslog(LOG_INFO, "%s: invalid packet",
inet_ntoa(client.sin_addr));
continue;
}
syslog(LOG_INFO, "%s: REQUEST", inet_ntoa(client.sin_addr));
boot_info.opcode = BIOPCODE_BOOTWHAT_REPLY;
err = query_bootinfo_db(client.sin_addr, boot_whatp);
if (err) {
syslog(LOG_INFO, "%s: FAIL: no valid entry",
inet_ntoa(client.sin_addr));
boot_info.status = BISTAT_FAIL;
} else {
log_bootwhat(client.sin_addr, boot_whatp);
boot_info.status = BISTAT_SUCCESS;
}
boot_info.opcode = BIOPCODE_BOOTWHAT_REPLY;
client.sin_family = AF_INET;
client.sin_port = htons(BOOTWHAT_SRCPORT);
if (sendto(sock, (char *)&boot_info, sizeof(boot_info), 0,
......
......@@ -11,7 +11,8 @@
static char dbname[] = "tbdb";
static char dbquery[] =
"select n.next_boot_path, n.next_boot_cmd_line, n.def_boot_image_id, "
"d.img_desc, p.partition, n.def_boot_cmd_line, d.img_path from nodes "
"d.img_desc, p.partition, n.def_boot_cmd_line, "
"n.def_boot_path from nodes "
"as n left join partitions as p on n.node_id=p.node_id and "
"n.def_boot_image_id=p.image_id left join disk_images as d on "
"p.image_id=d.image_id left join interfaces as i on "
......@@ -96,7 +97,6 @@ query_bootinfo_db(struct in_addr ipaddr, boot_what_t *info)
row = mysql_fetch_row(res);
#if 1
/*
* First element is next_boot_path. If set, assume it is a
* multiboot kernel.
......@@ -112,30 +112,128 @@ query_bootinfo_db(struct in_addr ipaddr, boot_what_t *info)
mysql_free_result(res);
return 0;
}
#endif
/* Fifth element (row[4]) should have the partition number */
if (row[4] == 0 || row[4][0] == '\0') {
/*
* There is either a partition number or default boot path.
* The default boot path overrides the partition.
*/
if (row[6] != 0 && row[6][0] != '\0') {
info->type = BIBOOTWHAT_TYPE_MB;
info->what.mb.tftp_ip.s_addr = 0;
strncpy(info->what.mb.filename, row[6], MAX_BOOT_PATH-1);
}
else if (row[4] != 0 && row[4][0] != '\0') {
info->type = BIBOOTWHAT_TYPE_PART;
info->what.partition = atoi(row[4]);
}
else {
syslog(LOG_ERR, "%s: null query result for IP %s!",
dbname, inet_ntoa(ipaddr));
mysql_free_result(res);
return 1;
}
/*
* Just 45000 lines of code later, we have the 32 bits of info
* we wanted!
*/
part = atoi(row[4]);
mysql_free_result(res);
info->type = BIBOOTWHAT_TYPE_PART;
info->what.partition = part;
if (row[5] != 0 && row[5][0] != '\0')
strncpy(info->cmdline, row[5], MAX_BOOT_CMDLINE-1);
else
info->cmdline[0] = 0; /* Must zero first byte! */
/*
* Just 45040 lines of code later, we are done.
*/
mysql_free_result(res);
return 0;
}
int
ack_bootinfo_db(struct in_addr ipaddr, boot_what_t *info)
{
char querybuf[1024];
int n, nrows, ncols, part;
MYSQL db;
MYSQL_RES *res;
MYSQL_ROW row;
n = snprintf(querybuf, sizeof querybuf,
"select i.node_id,n.next_boot_path,n.next_boot_cmd_line "
"from nodes as n left join interfaces as i on "
"i.node_id=n.node_id where i.IP = '%s'",
inet_ntoa(ipaddr));
if (n > sizeof querybuf) {
syslog(LOG_ERR, "query too long for buffer");
return 1;
}
mysql_init(&db);
if (mysql_real_connect(&db, 0, 0, 0, dbname, 0, 0, 0) == 0) {
syslog(LOG_ERR, "%s: connect failed: %s",
dbname, mysql_error(&db));
return 1;
}
if (mysql_real_query(&db, querybuf, n) != 0) {
syslog(LOG_ERR, "%s: query failed: %s",
dbname, mysql_error(&db));
mysql_close(&db);
return 1;
}
res = mysql_store_result(&db);
if (res == 0) {
syslog(LOG_ERR, "%s: store_result failed: %s",
dbname, mysql_error(&db));
mysql_close(&db);
return 1;
}
nrows = (int)mysql_num_rows(res);
switch (nrows) {
case 0:
syslog(LOG_ERR, "%s: no entry for host %s",
dbname, inet_ntoa(ipaddr));
mysql_free_result(res);
return 1;
case 1:
break;
default:
syslog(LOG_ERR, "%s: %d entries for IP %s, using first",
dbname, nrows, inet_ntoa(ipaddr));
break;
}
row = mysql_fetch_row(res);
if (row[1] == 0 || row[1][0] == '\0') {
/* Nothing to do */
mysql_free_result(res);
mysql_close(&db);
return 1;
}
/*
* Update the database to reflect that the boot has been done.
*/
n = snprintf(querybuf, sizeof querybuf,
"update nodes set next_boot_path='',"
"next_boot_cmd_line='' where node_id='%s'",
row[0]);
mysql_free_result(res);
if (n > sizeof querybuf) {
syslog(LOG_ERR, "query too long for buffer");
mysql_close(&db);
return 1;
}
if (mysql_real_query(&db, querybuf, n) != 0) {
syslog(LOG_ERR, "%s: query failed: %s",
dbname, mysql_error(&db));
mysql_close(&db);
return 1;
}
syslog(LOG_INFO, "%s: next_boot_path cleared", inet_ntoa(ipaddr));
mysql_close(&db);
return 0;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment