Commit 387ee5d2be for qemu.org
commit 387ee5d2be300b104c317aa7f86a4c24652c6f3e
Author: Peter Maydell <peter.maydell@linaro.org>
Date: Thu Feb 12 14:09:13 2026 +0000
hw/net/rocker: Don't keep pointer to h_proto as uint16_t* in OfDpaFlowPktFields
In rocker_of_dpa.c we assume that the h_proto field in an eth_header
struct is aligned, and we copy its address into a uint16_t* in the
OfDpaFlowPktFields struct which we then dereference later. This
isn't a safe assumption; it will also result in compilation failures
with gcc if we mark the eth_header struct as QEMU_PACKED because gcc
will not let you take the address of an unaligned struct field.
Make the h_proto field in OfDpaFlowPktFields a void*, and make all
the places where we previously read through that pointer instead use
a new accessor function which allows for the possible lack of
alignment.
(Compare commit 5814c084679
"hw/net/virtio-net.c: Don't assume IP length field is aligned"
which fixed a similar problem elsewhere for an ip_header field.)
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
Message-ID: <20260212140917.1443253-2-peter.maydell@linaro.org>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
diff --git a/hw/net/rocker/rocker_of_dpa.c b/hw/net/rocker/rocker_of_dpa.c
index 16b9bc7a4b..814f19afc5 100644
--- a/hw/net/rocker/rocker_of_dpa.c
+++ b/hw/net/rocker/rocker_of_dpa.c
@@ -143,7 +143,7 @@ typedef struct of_dpa_flow {
typedef struct of_dpa_flow_pkt_fields {
uint32_t tunnel_id;
struct eth_header *ethhdr;
- uint16_t *h_proto;
+ void *h_proto; /* pointer to unaligned uint16_t data */
struct vlan_header *vlanhdr;
struct ip_header *ipv4hdr;
struct ip6_header *ipv6hdr;
@@ -196,6 +196,11 @@ typedef struct of_dpa_group {
};
} OfDpaGroup;
+static uint16_t of_dpa_flow_pkt_h_proto(const OfDpaFlowPktFields *fields)
+{
+ return lduw_he_p(fields->h_proto);
+}
+
static int of_dpa_mask2prefix(uint32_t mask)
{
return 32 - ctz32(ntohl(mask));
@@ -395,7 +400,7 @@ static void of_dpa_flow_pkt_parse(OfDpaFlowContext *fc,
fields->ethhdr = iov->iov_base;
fields->h_proto = &fields->ethhdr->h_proto;
- if (ntohs(*fields->h_proto) == ETH_P_VLAN) {
+ if (ntohs(of_dpa_flow_pkt_h_proto(fields) == ETH_P_VLAN)) {
sofar += sizeof(struct vlan_header);
if (iov->iov_len < sofar) {
DPRINTF("flow_pkt_parse underrun on vlan_header\n");
@@ -405,7 +410,7 @@ static void of_dpa_flow_pkt_parse(OfDpaFlowContext *fc,
fields->h_proto = &fields->vlanhdr->h_proto;
}
- switch (ntohs(*fields->h_proto)) {
+ switch (ntohs(of_dpa_flow_pkt_h_proto(fields))) {
case ETH_P_IP:
sofar += sizeof(struct ip_header);
if (iov->iov_len < sofar) {
@@ -547,7 +552,7 @@ static void of_dpa_term_mac_build_match(OfDpaFlowContext *fc,
{
match->value.tbl_id = ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC;
match->value.in_pport = fc->in_pport;
- match->value.eth.type = *fc->fields.h_proto;
+ match->value.eth.type = of_dpa_flow_pkt_h_proto(&fc->fields);
match->value.eth.vlan_id = fc->fields.vlanhdr->h_tci;
memcpy(match->value.eth.dst.a, fc->fields.ethhdr->h_dest,
sizeof(match->value.eth.dst.a));
@@ -643,7 +648,7 @@ static void of_dpa_unicast_routing_build_match(OfDpaFlowContext *fc,
OfDpaFlowMatch *match)
{
match->value.tbl_id = ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING;
- match->value.eth.type = *fc->fields.h_proto;
+ match->value.eth.type = of_dpa_flow_pkt_h_proto(&fc->fields);
if (fc->fields.ipv4hdr) {
match->value.ipv4.addr.dst = fc->fields.ipv4hdr->ip_dst;
}
@@ -672,7 +677,7 @@ of_dpa_multicast_routing_build_match(OfDpaFlowContext *fc,
OfDpaFlowMatch *match)
{
match->value.tbl_id = ROCKER_OF_DPA_TABLE_ID_MULTICAST_ROUTING;
- match->value.eth.type = *fc->fields.h_proto;
+ match->value.eth.type = of_dpa_flow_pkt_h_proto(&fc->fields);
match->value.eth.vlan_id = fc->fields.vlanhdr->h_tci;
if (fc->fields.ipv4hdr) {
match->value.ipv4.addr.src = fc->fields.ipv4hdr->ip_src;
@@ -713,7 +718,7 @@ static void of_dpa_acl_build_match(OfDpaFlowContext *fc,
sizeof(match->value.eth.src.a));
memcpy(match->value.eth.dst.a, fc->fields.ethhdr->h_dest,
sizeof(match->value.eth.dst.a));
- match->value.eth.type = *fc->fields.h_proto;
+ match->value.eth.type = of_dpa_flow_pkt_h_proto(&fc->fields);
match->value.eth.vlan_id = fc->fields.vlanhdr->h_tci;
match->value.width = FLOW_KEY_WIDTH(eth.type);
if (fc->fields.ipv4hdr) {