@samitouri / QOSamiQemu / commits / 387ee5d2be

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>

Peter Maydell committed Feb 12, 2026 at 14:09 UTC 387ee5d2be300b104c317aa7f86a4c24652c6f3e
1 file changed +12 -7
hw/net/rocker/rocker_of_dpa.c
+12 -7
@@ -143,7 +143,7 @@ typedef struct of_dpa_flow {
143 typedef struct of_dpa_flow_pkt_fields {
144 uint32_t tunnel_id;
145 struct eth_header *ethhdr;
146 - uint16_t *h_proto;
146 + void *h_proto; /* pointer to unaligned uint16_t data */
147 struct vlan_header *vlanhdr;
148 struct ip_header *ipv4hdr;
149 struct ip6_header *ipv6hdr;
@@ -196,6 +196,11 @@ typedef struct of_dpa_group {
196 };
197 } OfDpaGroup;
198
199 +static uint16_t of_dpa_flow_pkt_h_proto(const OfDpaFlowPktFields *fields)
200 +{
201 + return lduw_he_p(fields->h_proto);
202 +}
203 +
204 static int of_dpa_mask2prefix(uint32_t mask)
205 {
206 return 32 - ctz32(ntohl(mask));
@@ -395,7 +400,7 @@ static void of_dpa_flow_pkt_parse(OfDpaFlowContext *fc,
400 fields->ethhdr = iov->iov_base;
401 fields->h_proto = &fields->ethhdr->h_proto;
402
398 - if (ntohs(*fields->h_proto) == ETH_P_VLAN) {
403 + if (ntohs(of_dpa_flow_pkt_h_proto(fields) == ETH_P_VLAN)) {
404 sofar += sizeof(struct vlan_header);
405 if (iov->iov_len < sofar) {
406 DPRINTF("flow_pkt_parse underrun on vlan_header\n");
@@ -405,7 +410,7 @@ static void of_dpa_flow_pkt_parse(OfDpaFlowContext *fc,
410 fields->h_proto = &fields->vlanhdr->h_proto;
411 }
412
408 - switch (ntohs(*fields->h_proto)) {
413 + switch (ntohs(of_dpa_flow_pkt_h_proto(fields))) {
414 case ETH_P_IP:
415 sofar += sizeof(struct ip_header);
416 if (iov->iov_len < sofar) {
@@ -547,7 +552,7 @@ static void of_dpa_term_mac_build_match(OfDpaFlowContext *fc,
552 {
553 match->value.tbl_id = ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC;
554 match->value.in_pport = fc->in_pport;
550 - match->value.eth.type = *fc->fields.h_proto;
555 + match->value.eth.type = of_dpa_flow_pkt_h_proto(&fc->fields);
556 match->value.eth.vlan_id = fc->fields.vlanhdr->h_tci;
557 memcpy(match->value.eth.dst.a, fc->fields.ethhdr->h_dest,
558 sizeof(match->value.eth.dst.a));
@@ -643,7 +648,7 @@ static void of_dpa_unicast_routing_build_match(OfDpaFlowContext *fc,
648 OfDpaFlowMatch *match)
649 {
650 match->value.tbl_id = ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING;
646 - match->value.eth.type = *fc->fields.h_proto;
651 + match->value.eth.type = of_dpa_flow_pkt_h_proto(&fc->fields);
652 if (fc->fields.ipv4hdr) {
653 match->value.ipv4.addr.dst = fc->fields.ipv4hdr->ip_dst;
654 }
@@ -672,7 +677,7 @@ of_dpa_multicast_routing_build_match(OfDpaFlowContext *fc,
677 OfDpaFlowMatch *match)
678 {
679 match->value.tbl_id = ROCKER_OF_DPA_TABLE_ID_MULTICAST_ROUTING;
675 - match->value.eth.type = *fc->fields.h_proto;
680 + match->value.eth.type = of_dpa_flow_pkt_h_proto(&fc->fields);
681 match->value.eth.vlan_id = fc->fields.vlanhdr->h_tci;
682 if (fc->fields.ipv4hdr) {
683 match->value.ipv4.addr.src = fc->fields.ipv4hdr->ip_src;
@@ -713,7 +718,7 @@ static void of_dpa_acl_build_match(OfDpaFlowContext *fc,
718 sizeof(match->value.eth.src.a));
719 memcpy(match->value.eth.dst.a, fc->fields.ethhdr->h_dest,
720 sizeof(match->value.eth.dst.a));
716 - match->value.eth.type = *fc->fields.h_proto;
721 + match->value.eth.type = of_dpa_flow_pkt_h_proto(&fc->fields);
722 match->value.eth.vlan_id = fc->fields.vlanhdr->h_tci;
723 match->value.width = FLOW_KEY_WIDTH(eth.type);
724 if (fc->fields.ipv4hdr) {