Skip to content

Commit

Permalink
iPXE
Browse files Browse the repository at this point in the history
  • Loading branch information
LorenzoBianconi committed Nov 27, 2019
1 parent b24353d commit b947375
Show file tree
Hide file tree
Showing 8 changed files with 58 additions and 19 deletions.
35 changes: 31 additions & 4 deletions ovn/controller/pinctrl.c
Expand Up @@ -1121,9 +1121,34 @@ pinctrl_handle_put_dhcp_opts(
*| 4 Bytes padding | 1 Byte (option end 0xFF ) | 4 Bytes padding|
* --------------------------------------------------------------
*/
/* compute opt len */
unsigned char *ptr = (unsigned char *)userdata->data;
unsigned char *buf = xmalloc(userdata->size);
uint16_t len = 0, opt_len = 0;
char file[128] = {};

while (len < userdata->size) {
int cur_len = ptr[len + 2];
uint16_t code;

memcpy(&code, &ptr[len], 2);
switch (code) {
case 300: /* DHCP_OPT_FILENAME*/
memcpy(file, &ptr[len + 3], MIN(cur_len, sizeof(file)));
break;
default:
/* code < 255 */
buf[opt_len] = code;
memcpy(buf + 1 + opt_len, &ptr[len + 2], cur_len + 1);
opt_len += 2 + cur_len;
break;
}
len += 3 + cur_len;
}

uint16_t new_l4_size = UDP_HEADER_LEN + DHCP_HEADER_LEN + 16;
if (msg_type != DHCP_MSG_NAK) {
new_l4_size += userdata->size;
new_l4_size += opt_len;
}
size_t new_packet_size = pkt_in->l4_ofs + new_l4_size;

Expand All @@ -1149,11 +1174,12 @@ pinctrl_handle_put_dhcp_opts(
&pkt_out, dp_packet_pull(pkt_in, DHCP_HEADER_LEN), DHCP_HEADER_LEN);
dhcp_data->op = DHCP_OP_REPLY;
dhcp_data->yiaddr = (msg_type == DHCP_MSG_NAK) ? 0 : *offer_ip;
memcpy(dhcp_data->file, file, sizeof(dhcp_data->file));
dp_packet_put(&pkt_out, &magic_cookie, sizeof(ovs_be32));

uint16_t out_dhcp_opts_size = 12;
if (msg_type != DHCP_MSG_NAK) {
out_dhcp_opts_size += userdata->size;
out_dhcp_opts_size += opt_len;
}
uint8_t *out_dhcp_opts = dp_packet_put_zeros(&pkt_out,
out_dhcp_opts_size);
Expand All @@ -1164,8 +1190,8 @@ pinctrl_handle_put_dhcp_opts(
out_dhcp_opts += 3;

if (msg_type != DHCP_MSG_NAK) {
memcpy(out_dhcp_opts, userdata->data, userdata->size);
out_dhcp_opts += userdata->size;
memcpy(out_dhcp_opts, buf, opt_len);
out_dhcp_opts += opt_len;
}

/* Padding */
Expand Down Expand Up @@ -1194,6 +1220,7 @@ pinctrl_handle_put_dhcp_opts(
ETH_ADDR_ARGS(l2->eth_src), IP_ARGS(*offer_ip));

success = 1;
free(buf);
exit:
if (!ofperr) {
union mf_subvalue sv;
Expand Down
20 changes: 10 additions & 10 deletions ovn/lib/actions.c
Expand Up @@ -1857,23 +1857,23 @@ static void
encode_put_dhcpv4_option(const struct ovnact_gen_option *o,
struct ofpbuf *ofpacts)
{
uint8_t *opt_header = ofpbuf_put_zeros(ofpacts, 2);
opt_header[0] = o->option->code;
uint8_t *opt_header = ofpbuf_put_zeros(ofpacts, 3);

memcpy(opt_header, &o->option->code, 2);
const union expr_constant *c = o->value.values;
size_t n_values = o->value.n_values;
if (!strcmp(o->option->type, "bool") ||
!strcmp(o->option->type, "uint8")) {
opt_header[1] = 1;
opt_header[2] = 1;
ofpbuf_put(ofpacts, &c->value.u8_val, 1);
} else if (!strcmp(o->option->type, "uint16")) {
opt_header[1] = 2;
opt_header[2] = 2;
ofpbuf_put(ofpacts, &c->value.be16_int, 2);
} else if (!strcmp(o->option->type, "uint32")) {
opt_header[1] = 4;
opt_header[2] = 4;
ofpbuf_put(ofpacts, &c->value.be32_int, 4);
} else if (!strcmp(o->option->type, "ipv4")) {
opt_header[1] = n_values * sizeof(ovs_be32);
opt_header[2] = n_values * sizeof(ovs_be32);
for (size_t i = 0; i < n_values; i++) {
ofpbuf_put(ofpacts, &c[i].value.ipv4, sizeof(ovs_be32));
}
Expand All @@ -1882,7 +1882,7 @@ encode_put_dhcpv4_option(const struct ovnact_gen_option *o,
if (no_of_routes % 2) {
no_of_routes -= 1;
}
opt_header[1] = 0;
opt_header[2] = 0;

/* Calculating the length of this option first because when
* we call ofpbuf_put, it might reallocate the buffer if the
Expand All @@ -1894,7 +1894,7 @@ encode_put_dhcpv4_option(const struct ovnact_gen_option *o,
if (c[i].masked) {
plen = (uint8_t) ip_count_cidr_bits(c[i].mask.ipv4);
}
opt_header[1] += (1 + DIV_ROUND_UP(plen, 8) + sizeof(ovs_be32));
opt_header[2] += (1 + DIV_ROUND_UP(plen, 8) + sizeof(ovs_be32));
}

/* Copied from RFC 3442. Please refer to this RFC for the format of
Expand Down Expand Up @@ -1924,8 +1924,8 @@ encode_put_dhcpv4_option(const struct ovnact_gen_option *o,
sizeof(ovs_be32));
}
} else if (!strcmp(o->option->type, "str")) {
opt_header[1] = strlen(c->string);
ofpbuf_put(ofpacts, c->string, opt_header[1]);
opt_header[2] = strlen(c->string);
ofpbuf_put(ofpacts, c->string, opt_header[2]);
}
}

Expand Down
2 changes: 2 additions & 0 deletions ovn/lib/ovn-l7.h
Expand Up @@ -77,6 +77,8 @@ struct gen_opts_map {
#define DHCP_OPT_PATH_PREFIX DHCP_OPTION("path_prefix", 210, "str")
#define DHCP_OPT_TFTP_SERVER_ADDRESS \
DHCP_OPTION("tftp_server_address", 150, "ipv4")
/* fixed DHCP header */
#define DHCP_OPT_FILENAME DHCP_OPTION("file", 300, "str")

static inline uint32_t
gen_opt_hash(char *opt_name)
Expand Down
1 change: 1 addition & 0 deletions ovn/northd/ovn-northd.c
Expand Up @@ -8935,6 +8935,7 @@ static struct gen_opts_map supported_dhcp_opts[] = {
DHCP_OPT_PATH_PREFIX,
DHCP_OPT_TFTP_SERVER_ADDRESS,
DHCP_OPT_DOMAIN_NAME,
DHCP_OPT_FILENAME,
};

static struct gen_opts_map supported_dhcpv6_opts[] = {
Expand Down
8 changes: 8 additions & 0 deletions ovn/ovn-nb.xml
Expand Up @@ -2474,6 +2474,14 @@
resolving hostnames via the Domain Name System.
</p>
</column>

<column name="options" key="file">
<p>
</p>
Boot file name, null terminated string; "generic" name or null
in DHCPDISCOVER, fully qualified directory-path name in
DHCPOFFER.
</column>
</group>
</group>

Expand Down
4 changes: 2 additions & 2 deletions ovn/ovn-sb.ovsschema
@@ -1,7 +1,7 @@
{
"name": "OVN_Southbound",
"version": "2.5.0",
"cksum": "1257419092 20387",
"cksum": "2388820355 20388",
"tables": {
"SB_Global": {
"columns": {
Expand Down Expand Up @@ -209,7 +209,7 @@
"name": {"type": "string"},
"code": {
"type": {"key": {"type": "integer",
"minInteger": 0, "maxInteger": 254}}},
"minInteger": 0, "maxInteger": 1000}}},
"type": {
"type": {"key": {
"type": "string",
Expand Down
6 changes: 3 additions & 3 deletions tests/ovn.at
Expand Up @@ -1129,13 +1129,13 @@ put_arp(inport, arp.spa, arp.sha);

# put_dhcp_opts
reg1[0] = put_dhcp_opts(offerip = 1.2.3.4, router = 10.0.0.1);
encodes as controller(userdata=00.00.00.02.00.00.00.00.00.01.de.10.00.00.00.40.01.02.03.04.03.04.0a.00.00.01,pause)
encodes as controller(userdata=00.00.00.02.00.00.00.00.00.01.de.10.00.00.00.40.01.02.03.04.03.00.04.0a.00.00.01,pause)
reg2[5] = put_dhcp_opts(offerip=10.0.0.4,router=10.0.0.1,netmask=255.255.254.0,mtu=1400,domain_name="ovn.org",wpad="https://example.org",bootfile_name="https://127.0.0.1/boot.ipxe",path_prefix="/tftpboot");
formats as reg2[5] = put_dhcp_opts(offerip = 10.0.0.4, router = 10.0.0.1, netmask = 255.255.254.0, mtu = 1400, domain_name = "ovn.org", wpad = "https://example.org", bootfile_name = "https://127.0.0.1/boot.ipxe", path_prefix = "/tftpboot");
encodes as controller(userdata=00.00.00.02.00.00.00.00.00.01.de.10.00.00.00.25.0a.00.00.04.03.04.0a.00.00.01.01.04.ff.ff.fe.00.1a.02.05.78.0f.07.6f.76.6e.2e.6f.72.67.fc.13.68.74.74.70.73.3a.2f.2f.65.78.61.6d.70.6c.65.2e.6f.72.67.43.1b.68.74.74.70.73.3a.2f.2f.31.32.37.2e.30.2e.30.2e.31.2f.62.6f.6f.74.2e.69.70.78.65.d2.09.2f.74.66.74.70.62.6f.6f.74,pause)
encodes as controller(userdata=00.00.00.02.00.00.00.00.00.01.de.10.00.00.00.25.0a.00.00.04.03.00.04.0a.00.00.01.01.00.04.ff.ff.fe.00.1a.00.02.05.78.0f.00.07.6f.76.6e.2e.6f.72.67.fc.00.13.68.74.74.70.73.3a.2f.2f.65.78.61.6d.70.6c.65.2e.6f.72.67.43.00.1b.68.74.74.70.73.3a.2f.2f.31.32.37.2e.30.2e.30.2e.31.2f.62.6f.6f.74.2e.69.70.78.65.d2.00.09.2f.74.66.74.70.62.6f.6f.74,pause)
reg0[15] = put_dhcp_opts(offerip=10.0.0.4,router=10.0.0.1,netmask=255.255.255.0,mtu=1400,ip_forward_enable=1,default_ttl=121,dns_server={8.8.8.8,7.7.7.7},classless_static_route={30.0.0.0/24,10.0.0.4,40.0.0.0/16,10.0.0.6,0.0.0.0/0,10.0.0.1},ethernet_encap=1,router_discovery=0,tftp_server_address={10.0.0.4,10.0.0.5});
formats as reg0[15] = put_dhcp_opts(offerip = 10.0.0.4, router = 10.0.0.1, netmask = 255.255.255.0, mtu = 1400, ip_forward_enable = 1, default_ttl = 121, dns_server = {8.8.8.8, 7.7.7.7}, classless_static_route = {30.0.0.0/24, 10.0.0.4, 40.0.0.0/16, 10.0.0.6, 0.0.0.0/0, 10.0.0.1}, ethernet_encap = 1, router_discovery = 0, tftp_server_address = {10.0.0.4, 10.0.0.5});
encodes as controller(userdata=00.00.00.02.00.00.00.00.00.01.de.10.00.00.00.6f.0a.00.00.04.03.04.0a.00.00.01.01.04.ff.ff.ff.00.1a.02.05.78.13.01.01.17.01.79.06.08.08.08.08.08.07.07.07.07.79.14.18.1e.00.00.0a.00.00.04.10.28.00.0a.00.00.06.00.0a.00.00.01.24.01.01.1f.01.00.96.08.0a.00.00.04.0a.00.00.05,pause)
encodes as controller(userdata=00.00.00.02.00.00.00.00.00.01.de.10.00.00.00.6f.0a.00.00.04.03.00.04.0a.00.00.01.01.00.04.ff.ff.ff.00.1a.00.02.05.78.13.00.01.01.17.00.01.79.06.00.08.08.08.08.08.07.07.07.07.79.00.14.18.1e.00.00.0a.00.00.04.10.28.00.0a.00.00.06.00.0a.00.00.01.24.00.01.01.1f.00.01.00.96.00.08.0a.00.00.04.0a.00.00.05,pause)

reg1[0..1] = put_dhcp_opts(offerip = 1.2.3.4, router = 10.0.0.1);
Cannot use 2-bit field reg1[0..1] where 1-bit field is required.
Expand Down
1 change: 1 addition & 0 deletions tests/test-ovn.c
Expand Up @@ -187,6 +187,7 @@ create_gen_opts(struct hmap *dhcp_opts, struct hmap *dhcpv6_opts,
dhcp_opt_add(dhcp_opts, "bootfile_name", 67, "str");
dhcp_opt_add(dhcp_opts, "path_prefix", 210, "str");
dhcp_opt_add(dhcp_opts, "tftp_server_address", 150, "ipv4");
dhcp_opt_add(dhcp_opts, "file", 300, "str");

/* DHCPv6 options. */
hmap_init(dhcpv6_opts);
Expand Down

0 comments on commit b947375

Please sign in to comment.