From 437d0d22ab42d4101157b48a75fa844e7039e326 Mon Sep 17 00:00:00 2001 From: Jarno Rajahalme Date: Mon, 24 Mar 2014 09:17:01 -0700 Subject: [PATCH] lib/ofpbuf: Compact This patch shrinks the struct ofpbuf from 104 to 48 bytes on 64-bit systems, or from 52 to 36 bytes on 32-bit systems (counting in the 'l7' removal from an earlier patch). This may help contribute to cache efficiency, and will speed up initializing, copying and manipulating ofpbufs. This is potentially important for the DPDK datapath, but the rest of the code base may also see a little benefit. Changes are: - Remove 'l7' pointer (previous patch). - Use offsets instead of layer pointers for l2_5, l3, and l4 using 'l2' as basis. Usually 'data' is the same as 'l2', but this is not always the case (e.g., when parsing or constructing a packet), so it can not be easily used as the offset basis. Also, packet parsing is faster if we do not need to maintain the offsets each time we pull data from the ofpbuf. - Use uint32_t for 'allocated' and 'size', as 2^32 is enough even for largest possible messages/packets. - Use packed enum for 'source'. - Rearrange to avoid unnecessary padding. - Remove 'private_p', which was used only in two cases, both of which had the invariant ('l2' == 'data'), so we can temporarily use 'l2' as a private pointer. Signed-off-by: Jarno Rajahalme Signed-off-by: Ben Pfaff --- lib/cfm.c | 5 +- lib/flow.c | 82 ++++++++++++---------- lib/lacp.c | 3 +- lib/netlink.c | 2 +- lib/nx-match.c | 4 +- lib/odp-execute.c | 2 +- lib/ofp-actions.c | 4 +- lib/ofp-msgs.c | 9 +-- lib/ofp-print.c | 6 +- lib/ofp-util.c | 48 ++++++------- lib/ofpbuf.c | 72 ++++++++++++------- lib/ofpbuf.h | 75 ++++++++++++++++---- lib/packets.c | 137 ++++++++++++++----------------------- lib/pcap-file.c | 2 +- lib/rconn.c | 13 +++- lib/stp.c | 2 +- lib/util.h | 1 + ofproto/ofproto-dpif.c | 9 ++- ofproto/ofproto-provider.h | 4 +- tests/test-netflow.c | 2 +- tests/test-odp.c | 2 +- tests/test-stp.c | 2 +- utilities/ovs-ofctl.c | 10 +-- 23 files changed, 278 insertions(+), 218 deletions(-) diff --git a/lib/cfm.c b/lib/cfm.c index 48556cf1a..dcdaa0ea6 100644 --- a/lib/cfm.c +++ b/lib/cfm.c @@ -557,7 +557,7 @@ cfm_compose_ccm(struct cfm *cfm, struct ofpbuf *packet, eth_push_vlan(packet, htons(ETH_TYPE_VLAN), htons(tci)); } - ccm = packet->l3; + ccm = ofpbuf_get_l3(packet); ccm->mdlevel_version = 0; ccm->opcode = CCM_OPCODE; ccm->tlv_offset = 70; @@ -719,7 +719,8 @@ cfm_process_heartbeat(struct cfm *cfm, const struct ofpbuf *p) ovs_mutex_lock(&mutex); eth = p->l2; - ccm = ofpbuf_at(p, (uint8_t *)p->l3 - (uint8_t *)p->data, CCM_ACCEPT_LEN); + ccm = ofpbuf_at(p, (uint8_t *)ofpbuf_get_l3(p) - (uint8_t *)p->data, + CCM_ACCEPT_LEN); if (!ccm) { VLOG_INFO_RL(&rl, "%s: Received an unparseable 802.1ag CCM heartbeat.", diff --git a/lib/flow.c b/lib/flow.c index 4e8cc0e07..314c1c768 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -338,18 +338,20 @@ invalid: /* Initializes 'flow' members from 'packet' and 'md' * - * Initializes 'packet' header pointers as follows: + * Initializes 'packet' header l2 pointer to the start of the Ethernet + * header, and the layer offsets as follows: * - * - packet->l2 to the start of the Ethernet header. + * - packet->l2_5_ofs to the start of the MPLS shim header, or UINT16_MAX + * when there is no MPLS shim header. * - * - packet->l2_5 to the start of the MPLS shim header. - * - * - packet->l3 to just past the Ethernet header, or just past the + * - packet->l3_ofs to just past the Ethernet header, or just past the * vlan_header if one is present, to the first byte of the payload of the - * Ethernet frame. + * Ethernet frame. UINT16_MAX if the frame is too short to contain an + * Ethernet header. * - * - packet->l4 to just past the IPv4 header, if one is present and has a - * correct length, and otherwise NULL. + * - packet->l4_ofs to just past the IPv4 header, if one is present and + * has at least the content used for the fields of interest for the flow, + * otherwise UINT16_MAX. */ void flow_extract(struct ofpbuf *packet, const struct pkt_metadata *md, @@ -370,9 +372,9 @@ flow_extract(struct ofpbuf *packet, const struct pkt_metadata *md, } packet->l2 = b.data; - packet->l2_5 = NULL; - packet->l3 = NULL; - packet->l4 = NULL; + ofpbuf_set_l2_5(packet, NULL); + ofpbuf_set_l3(packet, NULL); + ofpbuf_set_l4(packet, NULL); if (b.size < sizeof *eth) { return; @@ -392,16 +394,16 @@ flow_extract(struct ofpbuf *packet, const struct pkt_metadata *md, /* Parse mpls, copy l3 ttl. */ if (eth_type_mpls(flow->dl_type)) { - packet->l2_5 = b.data; + ofpbuf_set_l2_5(packet, b.data); parse_mpls(&b, flow); } /* Network layer. */ - packet->l3 = b.data; + ofpbuf_set_l3(packet, b.data); if (flow->dl_type == htons(ETH_TYPE_IP)) { const struct ip_header *nh = pull_ip(&b); if (nh) { - packet->l4 = b.data; + ofpbuf_set_l4(packet, b.data); flow->nw_src = get_16aligned_be32(&nh->ip_src); flow->nw_dst = get_16aligned_be32(&nh->ip_dst); @@ -437,7 +439,7 @@ flow_extract(struct ofpbuf *packet, const struct pkt_metadata *md, return; } - packet->l4 = b.data; + ofpbuf_set_l4(packet, b.data); if (flow->nw_proto == IPPROTO_TCP) { parse_tcp(&b, flow); } else if (flow->nw_proto == IPPROTO_UDP) { @@ -1237,45 +1239,48 @@ flow_set_mpls_lse(struct flow *flow, int idx, ovs_be32 lse) flow->mpls_lse[idx] = lse; } -static uint8_t * +static size_t flow_compose_l4(struct ofpbuf *b, const struct flow *flow) { + size_t l4_len = 0; + if (!(flow->nw_frag & FLOW_NW_FRAG_ANY) || !(flow->nw_frag & FLOW_NW_FRAG_LATER)) { if (flow->nw_proto == IPPROTO_TCP) { struct tcp_header *tcp; - tcp = ofpbuf_put_zeros(b, sizeof *tcp); + l4_len = sizeof *tcp; + tcp = ofpbuf_put_zeros(b, l4_len); tcp->tcp_src = flow->tp_src; tcp->tcp_dst = flow->tp_dst; tcp->tcp_ctl = TCP_CTL(ntohs(flow->tcp_flags), 5); - return ofpbuf_tail(b); } else if (flow->nw_proto == IPPROTO_UDP) { struct udp_header *udp; - udp = ofpbuf_put_zeros(b, sizeof *udp); + l4_len = sizeof *udp; + udp = ofpbuf_put_zeros(b, l4_len); udp->udp_src = flow->tp_src; udp->udp_dst = flow->tp_dst; - return ofpbuf_tail(b); } else if (flow->nw_proto == IPPROTO_SCTP) { struct sctp_header *sctp; - sctp = ofpbuf_put_zeros(b, sizeof *sctp); + l4_len = sizeof *sctp; + sctp = ofpbuf_put_zeros(b, l4_len); sctp->sctp_src = flow->tp_src; sctp->sctp_dst = flow->tp_dst; - return ofpbuf_tail(b); } else if (flow->nw_proto == IPPROTO_ICMP) { struct icmp_header *icmp; - icmp = ofpbuf_put_zeros(b, sizeof *icmp); + l4_len = sizeof *icmp; + icmp = ofpbuf_put_zeros(b, l4_len); icmp->icmp_type = ntohs(flow->tp_src); icmp->icmp_code = ntohs(flow->tp_dst); icmp->icmp_csum = csum(icmp, ICMP_HEADER_LEN); - return ofpbuf_tail(b); } else if (flow->nw_proto == IPPROTO_ICMPV6) { struct icmp6_hdr *icmp; - icmp = ofpbuf_put_zeros(b, sizeof *icmp); + l4_len = sizeof *icmp; + icmp = ofpbuf_put_zeros(b, l4_len); icmp->icmp6_type = ntohs(flow->tp_src); icmp->icmp6_code = ntohs(flow->tp_dst); @@ -1285,16 +1290,19 @@ flow_compose_l4(struct ofpbuf *b, const struct flow *flow) struct in6_addr *nd_target; struct nd_opt_hdr *nd_opt; + l4_len += sizeof *nd_target; nd_target = ofpbuf_put_zeros(b, sizeof *nd_target); *nd_target = flow->nd_target; if (!eth_addr_is_zero(flow->arp_sha)) { + l4_len += 8; nd_opt = ofpbuf_put_zeros(b, 8); nd_opt->nd_opt_len = 1; nd_opt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; memcpy(nd_opt + 1, flow->arp_sha, ETH_ADDR_LEN); } if (!eth_addr_is_zero(flow->arp_tha)) { + l4_len += 8; nd_opt = ofpbuf_put_zeros(b, 8); nd_opt->nd_opt_len = 1; nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR; @@ -1303,10 +1311,9 @@ flow_compose_l4(struct ofpbuf *b, const struct flow *flow) } icmp->icmp6_cksum = (OVS_FORCE uint16_t) csum(icmp, (char *)ofpbuf_tail(b) - (char *)icmp); - return ofpbuf_tail(b); } } - return NULL; + return l4_len; } /* Puts into 'b' a packet that flow_extract() would parse as having the given @@ -1318,6 +1325,8 @@ flow_compose_l4(struct ofpbuf *b, const struct flow *flow) void flow_compose(struct ofpbuf *b, const struct flow *flow) { + size_t l4_len; + /* eth_compose() sets l3 pointer and makes sure it is 32-bit aligned. */ eth_compose(b, flow->dl_dst, flow->dl_src, ntohs(flow->dl_type), 0); if (flow->dl_type == htons(FLOW_DL_TYPE_NONE)) { @@ -1348,16 +1357,14 @@ flow_compose(struct ofpbuf *b, const struct flow *flow) } } - b->l4 = ofpbuf_tail(b); + ofpbuf_set_l4(b, ofpbuf_tail(b)); - flow_compose_l4(b, flow); + l4_len = flow_compose_l4(b, flow); - ip->ip_tot_len = htons((uint8_t *) b->data + b->size - - (uint8_t *) b->l3); + ip->ip_tot_len = htons(b->l4_ofs - b->l3_ofs + l4_len); ip->ip_csum = csum(ip, sizeof *ip); } else if (flow->dl_type == htons(ETH_TYPE_IPV6)) { struct ovs_16aligned_ip6_hdr *nh; - uint8_t *l7; nh = ofpbuf_put_zeros(b, sizeof *nh); put_16aligned_be32(&nh->ip6_flow, htonl(6 << 28) | @@ -1368,16 +1375,17 @@ flow_compose(struct ofpbuf *b, const struct flow *flow) memcpy(&nh->ip6_src, &flow->ipv6_src, sizeof(nh->ip6_src)); memcpy(&nh->ip6_dst, &flow->ipv6_dst, sizeof(nh->ip6_dst)); - b->l4 = ofpbuf_tail(b); + ofpbuf_set_l4(b, ofpbuf_tail(b)); - l7 = flow_compose_l4(b, flow); + l4_len = flow_compose_l4(b, flow); - nh->ip6_plen = l7 ? htons(l7 - (uint8_t *) b->l4) : htons(0); + nh->ip6_plen = htons(l4_len); } else if (flow->dl_type == htons(ETH_TYPE_ARP) || flow->dl_type == htons(ETH_TYPE_RARP)) { struct arp_eth_header *arp; - b->l3 = arp = ofpbuf_put_zeros(b, sizeof *arp); + arp = ofpbuf_put_zeros(b, sizeof *arp); + ofpbuf_set_l3(b, arp); arp->ar_hrd = htons(1); arp->ar_pro = htons(ETH_TYPE_IP); arp->ar_hln = ETH_ADDR_LEN; @@ -1396,7 +1404,7 @@ flow_compose(struct ofpbuf *b, const struct flow *flow) if (eth_type_mpls(flow->dl_type)) { int n; - b->l2_5 = b->l3; + b->l2_5_ofs = b->l3_ofs; for (n = 1; n < FLOW_MAX_MPLS_LABELS; n++) { if (flow->mpls_lse[n - 1] & htonl(MPLS_BOS_MASK)) { break; diff --git a/lib/lacp.c b/lib/lacp.c index cbe2259f4..711d7ec12 100644 --- a/lib/lacp.c +++ b/lib/lacp.c @@ -181,7 +181,8 @@ parse_lacp_packet(const struct ofpbuf *b) { const struct lacp_pdu *pdu; - pdu = ofpbuf_at(b, (uint8_t *)b->l3 - (uint8_t *)b->data, LACP_PDU_LEN); + pdu = ofpbuf_at(b, (uint8_t *)ofpbuf_get_l3(b) - (uint8_t *)b->data, + LACP_PDU_LEN); if (pdu && pdu->subtype == 1 && pdu->actor_type == 1 && pdu->actor_len == 20 diff --git a/lib/netlink.c b/lib/netlink.c index 3f479bef8..96abe46dd 100644 --- a/lib/netlink.c +++ b/lib/netlink.c @@ -66,7 +66,7 @@ nl_msg_nlmsgerr(const struct ofpbuf *msg, int *errorp) struct nlmsgerr *err = ofpbuf_at(msg, NLMSG_HDRLEN, sizeof *err); int code = EPROTO; if (!err) { - VLOG_ERR_RL(&rl, "received invalid nlmsgerr (%"PRIuSIZE"d bytes < %"PRIuSIZE"d)", + VLOG_ERR_RL(&rl, "received invalid nlmsgerr (%"PRIu32"d bytes < %"PRIuSIZE"d)", msg->size, NLMSG_HDRLEN + sizeof *err); } else if (err->error <= 0 && err->error > INT_MIN) { code = -err->error; diff --git a/lib/nx-match.c b/lib/nx-match.c index fe6d80f7f..cd3bf0854 100644 --- a/lib/nx-match.c +++ b/lib/nx-match.c @@ -215,7 +215,7 @@ nx_pull_match__(struct ofpbuf *b, unsigned int match_len, bool strict, if (!p) { VLOG_DBG_RL(&rl, "nx_match length %u, rounded up to a " "multiple of 8, is longer than space in message (max " - "length %"PRIuSIZE")", match_len, b->size); + "length %"PRIu32")", match_len, b->size); return OFPERR_OFPBMC_BAD_LEN; } } @@ -272,7 +272,7 @@ oxm_pull_match__(struct ofpbuf *b, bool strict, struct match *match) if (!p) { VLOG_DBG_RL(&rl, "oxm length %u, rounded up to a " "multiple of 8, is longer than space in message (max " - "length %"PRIuSIZE")", match_len, b->size); + "length %"PRIu32")", match_len, b->size); return OFPERR_OFPBMC_BAD_LEN; } diff --git a/lib/odp-execute.c b/lib/odp-execute.c index 6e04816a5..e5aa0ce50 100644 --- a/lib/odp-execute.c +++ b/lib/odp-execute.c @@ -51,7 +51,7 @@ odp_set_tunnel_action(const struct nlattr *a, struct flow_tnl *tun_key) static void set_arp(struct ofpbuf *packet, const struct ovs_key_arp *arp_key) { - struct arp_eth_header *arp = packet->l3; + struct arp_eth_header *arp = ofpbuf_get_l3(packet); arp->ar_op = arp_key->arp_op; memcpy(arp->ar_sha, arp_key->arp_sha, ETH_ADDR_LEN); diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c index d552f9cfc..23d89d307 100644 --- a/lib/ofp-actions.c +++ b/lib/ofp-actions.c @@ -710,7 +710,7 @@ ofpacts_pull_openflow_actions(struct ofpbuf *openflow, actions = ofpbuf_try_pull(openflow, actions_len); if (actions == NULL) { VLOG_WARN_RL(&rl, "OpenFlow message actions length %u exceeds " - "remaining message length (%"PRIuSIZE")", + "remaining message length (%"PRIu32")", actions_len, openflow->size); return OFPERR_OFPBRC_BAD_LEN; } @@ -1768,7 +1768,7 @@ ofpacts_pull_openflow_instructions(struct ofpbuf *openflow, instructions = ofpbuf_try_pull(openflow, instructions_len); if (instructions == NULL) { VLOG_WARN_RL(&rl, "OpenFlow message instructions length %u exceeds " - "remaining message length (%"PRIuSIZE")", + "remaining message length (%"PRIu32")", instructions_len, openflow->size); error = OFPERR_OFPBIC_BAD_LEN; goto exit; diff --git a/lib/ofp-msgs.c b/lib/ofp-msgs.c index 092741fd7..677d359ed 100644 --- a/lib/ofp-msgs.c +++ b/lib/ofp-msgs.c @@ -399,7 +399,8 @@ ofpraw_pull(enum ofpraw *rawp, struct ofpbuf *msg) enum ofpraw raw; /* Set default outputs. */ - msg->l2 = msg->l3 = msg->data; + msg->l2 = msg->data; + ofpbuf_set_l3(msg, msg->data); *rawp = 0; len = msg->size; @@ -416,7 +417,7 @@ ofpraw_pull(enum ofpraw *rawp, struct ofpbuf *msg) info = raw_info_get(raw); instance = raw_instance_get(info, hdrs.version); msg->l2 = ofpbuf_pull(msg, instance->hdrs_len); - msg->l3 = msg->data; + ofpbuf_set_l3(msg, msg->data); min_len = instance->hdrs_len + info->min_body; switch (info->extra_multiple) { @@ -664,7 +665,7 @@ ofpraw_put__(enum ofpraw raw, uint8_t version, ovs_be32 xid, ofpbuf_prealloc_tailroom(buf, (instance->hdrs_len + info->min_body + extra_tailroom)); buf->l2 = ofpbuf_put_uninit(buf, instance->hdrs_len); - buf->l3 = ofpbuf_tail(buf); + ofpbuf_set_l3(buf, ofpbuf_tail(buf)); oh = buf->l2; oh->version = version; @@ -893,7 +894,7 @@ ofpmp_reserve(struct list *replies, size_t len) next = ofpbuf_new(MAX(1024, hdrs_len + len)); ofpbuf_put(next, msg->data, hdrs_len); next->l2 = next->data; - next->l3 = ofpbuf_tail(next); + ofpbuf_set_l3(next, ofpbuf_tail(next)); list_push_back(replies, &next->list_node); *ofpmp_flags__(msg->data) |= htons(OFPSF_REPLY_MORE); diff --git a/lib/ofp-print.c b/lib/ofp-print.c index 599dc322b..b88d1e7de 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -71,13 +71,13 @@ ofp_packet_to_string(const void *data, size_t len) l4_size = ofpbuf_get_l4_size(&buf); if (flow.nw_proto == IPPROTO_TCP && l4_size >= TCP_HEADER_LEN) { - struct tcp_header *th = buf.l4; + struct tcp_header *th = ofpbuf_get_l4(&buf); ds_put_format(&ds, " tcp_csum:%"PRIx16, ntohs(th->tcp_csum)); } else if (flow.nw_proto == IPPROTO_UDP && l4_size >= UDP_HEADER_LEN) { - struct udp_header *uh = buf.l4; + struct udp_header *uh = ofpbuf_get_l4(&buf); ds_put_format(&ds, " udp_csum:%"PRIx16, ntohs(uh->udp_csum)); } else if (flow.nw_proto == IPPROTO_SCTP && l4_size >= SCTP_HEADER_LEN) { - struct sctp_header *sh = buf.l4; + struct sctp_header *sh = ofpbuf_get_l4(&buf); ds_put_format(&ds, " sctp_csum:%"PRIx32, ntohl(sh->sctp_csum)); } diff --git a/lib/ofp-util.c b/lib/ofp-util.c index 8e81c0130..d0002d516 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -1929,7 +1929,7 @@ ofputil_decode_meter_config(struct ofpbuf *msg, omc = ofpbuf_try_pull(msg, sizeof *omc); if (!omc) { VLOG_WARN_RL(&bad_ofmsg_rl, - "OFPMP_METER_CONFIG reply has %"PRIuSIZE" leftover bytes at end", + "OFPMP_METER_CONFIG reply has %"PRIu32" leftover bytes at end", msg->size); return OFPERR_OFPBRC_BAD_LEN; } @@ -2005,7 +2005,7 @@ ofputil_decode_meter_stats(struct ofpbuf *msg, oms = ofpbuf_try_pull(msg, sizeof *oms); if (!oms) { VLOG_WARN_RL(&bad_ofmsg_rl, - "OFPMP_METER reply has %"PRIuSIZE" leftover bytes at end", + "OFPMP_METER reply has %"PRIu32" leftover bytes at end", msg->size); return OFPERR_OFPBRC_BAD_LEN; } @@ -2176,7 +2176,7 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm, nfm->command = ofputil_tid_command(fm, protocol); nfm->cookie = fm->new_cookie; match_len = nx_put_match(msg, &fm->match, fm->cookie, fm->cookie_mask); - nfm = msg->l3; + nfm = ofpbuf_get_l3(msg); nfm->idle_timeout = htons(fm->idle_timeout); nfm->hard_timeout = htons(fm->hard_timeout); nfm->priority = htons(fm->priority); @@ -2396,7 +2396,7 @@ ofputil_append_queue_get_config_reply(struct ofpbuf *reply, struct ofp12_packet_queue *opq12; ovs_be32 port; - qgcr11 = reply->l3; + qgcr11 = ofpbuf_get_l3(reply); port = qgcr11->port; opq12 = ofpbuf_put_zeros(reply, sizeof *opq12); @@ -2636,7 +2636,7 @@ ofputil_encode_flow_stats_request(const struct ofputil_flow_stats_request *fsr, match_len = nx_put_match(msg, &fsr->match, fsr->cookie, fsr->cookie_mask); - nfsr = msg->l3; + nfsr = ofpbuf_get_l3(msg); nfsr->out_port = htons(ofp_to_u16(fsr->out_port)); nfsr->match_len = htons(match_len); nfsr->table_id = fsr->table_id; @@ -2698,7 +2698,7 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs, ofs = ofpbuf_try_pull(msg, sizeof *ofs); if (!ofs) { - VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_FLOW reply has %"PRIuSIZE" leftover " + VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_FLOW reply has %"PRIu32" leftover " "bytes at end", msg->size); return EINVAL; } @@ -2748,7 +2748,7 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs, ofs = ofpbuf_try_pull(msg, sizeof *ofs); if (!ofs) { - VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_FLOW reply has %"PRIuSIZE" leftover " + VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_FLOW reply has %"PRIu32" leftover " "bytes at end", msg->size); return EINVAL; } @@ -2784,7 +2784,7 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs, nfs = ofpbuf_try_pull(msg, sizeof *nfs); if (!nfs) { - VLOG_WARN_RL(&bad_ofmsg_rl, "NXST_FLOW reply has %"PRIuSIZE" leftover " + VLOG_WARN_RL(&bad_ofmsg_rl, "NXST_FLOW reply has %"PRIu32" leftover " "bytes at end", msg->size); return EINVAL; } @@ -2982,7 +2982,7 @@ ofputil_decode_aggregate_stats_reply(struct ofputil_aggregate_stats *stats, ofpbuf_use_const(&msg, reply, ntohs(reply->length)); ofpraw_pull_assert(&msg); - asr = msg.l3; + asr = ofpbuf_get_l3(&msg); stats->packet_count = ntohll(get_32aligned_be64(&asr->packet_count)); stats->byte_count = ntohll(get_32aligned_be64(&asr->byte_count)); stats->flow_count = ntohl(asr->flow_count); @@ -3134,7 +3134,7 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr, nfr = ofpbuf_put_zeros(msg, sizeof *nfr); match_len = nx_put_match(msg, &fr->match, 0, 0); - nfr = msg->l3; + nfr = ofpbuf_get_l3(msg); nfr->cookie = fr->cookie; nfr->priority = htons(fr->priority); nfr->reason = fr->reason; @@ -3346,7 +3346,7 @@ ofputil_encode_nx_packet_in(const struct ofputil_packet_in *pin) ofpbuf_put_zeros(packet, 2); ofpbuf_put(packet, pin->packet, pin->packet_len); - npi = packet->l3; + npi = ofpbuf_get_l3(packet); npi->buffer_id = htonl(pin->buffer_id); npi->total_len = htons(pin->total_len); npi->reason = pin->reason; @@ -3410,7 +3410,7 @@ ofputil_encode_ofp12_packet_in(const struct ofputil_packet_in *pin, ofpbuf_put_zeros(packet, 2); ofpbuf_put(packet, pin->packet, pin->packet_len); - opi = packet->l3; + opi = ofpbuf_get_l3(packet); opi->pi.buffer_id = htonl(pin->buffer_id); opi->pi.total_len = htons(pin->total_len); opi->pi.reason = pin->reason; @@ -4629,7 +4629,7 @@ ofputil_decode_role_message(const struct ofp_header *oh, if (raw == OFPRAW_OFPT12_ROLE_REQUEST || raw == OFPRAW_OFPT12_ROLE_REPLY) { - const struct ofp12_role_request *orr = b.l3; + const struct ofp12_role_request *orr = ofpbuf_get_l3(&b); if (orr->role != htonl(OFPCR12_ROLE_NOCHANGE) && orr->role != htonl(OFPCR12_ROLE_EQUAL) && @@ -4650,7 +4650,7 @@ ofputil_decode_role_message(const struct ofp_header *oh, } } else if (raw == OFPRAW_NXT_ROLE_REQUEST || raw == OFPRAW_NXT_ROLE_REPLY) { - const struct nx_role_request *nrr = b.l3; + const struct nx_role_request *nrr = ofpbuf_get_l3(&b); BUILD_ASSERT(NX_ROLE_OTHER + 1 == OFPCR12_ROLE_EQUAL); BUILD_ASSERT(NX_ROLE_MASTER + 1 == OFPCR12_ROLE_MASTER); @@ -4739,7 +4739,7 @@ ofputil_decode_role_status(const struct ofp_header *oh, raw = ofpraw_pull_assert(&b); ovs_assert(raw == OFPRAW_OFPT14_ROLE_STATUS); - r = b.l3; + r = ofpbuf_get_l3(&b); if (r->role != htonl(OFPCR12_ROLE_NOCHANGE) && r->role != htonl(OFPCR12_ROLE_EQUAL) && r->role != htonl(OFPCR12_ROLE_MASTER) && @@ -4953,7 +4953,7 @@ ofputil_decode_flow_monitor_request(struct ofputil_flow_monitor_request *rq, nfmr = ofpbuf_try_pull(msg, sizeof *nfmr); if (!nfmr) { - VLOG_WARN_RL(&bad_ofmsg_rl, "NXST_FLOW_MONITOR request has %"PRIuSIZE" " + VLOG_WARN_RL(&bad_ofmsg_rl, "NXST_FLOW_MONITOR request has %"PRIu32" " "leftover bytes at end", msg->size); return OFPERR_OFPBRC_BAD_LEN; } @@ -5107,7 +5107,7 @@ ofputil_decode_flow_update(struct ofputil_flow_update *update, } bad_len: - VLOG_WARN_RL(&bad_ofmsg_rl, "NXST_FLOW_MONITOR reply has %"PRIuSIZE" " + VLOG_WARN_RL(&bad_ofmsg_rl, "NXST_FLOW_MONITOR reply has %"PRIu32" " "leftover bytes at end", msg->size); return OFPERR_OFPBRC_BAD_LEN; } @@ -5211,7 +5211,7 @@ ofputil_encode_packet_out(const struct ofputil_packet_out *po, ofpacts_put_openflow_actions(po->ofpacts, po->ofpacts_len, msg, ofp_version); - opo = msg->l3; + opo = ofpbuf_get_l3(msg); opo->buffer_id = htonl(po->buffer_id); opo->in_port = htons(ofp_to_u16(po->in_port)); opo->actions_len = htons(msg->size - actions_ofs); @@ -5229,7 +5229,7 @@ ofputil_encode_packet_out(const struct ofputil_packet_out *po, ofpbuf_put_zeros(msg, sizeof *opo); len = ofpacts_put_openflow_actions(po->ofpacts, po->ofpacts_len, msg, ofp_version); - opo = msg->l3; + opo = ofpbuf_get_l3(msg); opo->buffer_id = htonl(po->buffer_id); opo->in_port = ofputil_port_to_ofp11(po->in_port); opo->actions_len = htons(len); @@ -6164,7 +6164,7 @@ ofputil_decode_port_stats(struct ofputil_port_stats *ps, struct ofpbuf *msg) } bad_len: - VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_PORT reply has %"PRIuSIZE" leftover " + VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_PORT reply has %"PRIu32" leftover " "bytes at end", msg->size); return OFPERR_OFPBRC_BAD_LEN; } @@ -6483,7 +6483,7 @@ ofputil_decode_group_stats_reply(struct ofpbuf *msg, } if (!ogs11) { - VLOG_WARN_RL(&bad_ofmsg_rl, "%s reply has %"PRIuSIZE" leftover bytes at end", + VLOG_WARN_RL(&bad_ofmsg_rl, "%s reply has %"PRIu32" leftover bytes at end", ofpraw_get_name(raw), msg->size); return OFPERR_OFPBRC_BAD_LEN; } @@ -6502,7 +6502,7 @@ ofputil_decode_group_stats_reply(struct ofpbuf *msg, gs->n_buckets = (length - base_len) / sizeof *obc; obc = ofpbuf_try_pull(msg, gs->n_buckets * sizeof *obc); if (!obc) { - VLOG_WARN_RL(&bad_ofmsg_rl, "%s reply has %"PRIuSIZE" leftover bytes at end", + VLOG_WARN_RL(&bad_ofmsg_rl, "%s reply has %"PRIu32" leftover bytes at end", ofpraw_get_name(raw), msg->size); return OFPERR_OFPBRC_BAD_LEN; } @@ -6641,7 +6641,7 @@ ofputil_decode_group_desc_reply(struct ofputil_group_desc *gd, ogds = ofpbuf_try_pull(msg, sizeof *ogds); if (!ogds) { - VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST11_GROUP_DESC reply has %"PRIuSIZE" " + VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST11_GROUP_DESC reply has %"PRIu32" " "leftover bytes at end", msg->size); return OFPERR_OFPBRC_BAD_LEN; } @@ -6972,7 +6972,7 @@ ofputil_decode_queue_stats(struct ofputil_queue_stats *qs, struct ofpbuf *msg) } bad_len: - VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_QUEUE reply has %"PRIuSIZE" leftover " + VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_QUEUE reply has %"PRIu32" leftover " "bytes at end", msg->size); return OFPERR_OFPBRC_BAD_LEN; } diff --git a/lib/ofpbuf.c b/lib/ofpbuf.c index 9f22836ad..56e1ec6ca 100644 --- a/lib/ofpbuf.c +++ b/lib/ofpbuf.c @@ -30,9 +30,9 @@ ofpbuf_use__(struct ofpbuf *b, void *base, size_t allocated, b->allocated = allocated; b->source = source; b->size = 0; - b->l2 = b->l2_5 = b->l3 = b->l4 = NULL; + b->l2 = NULL; + b->l2_5_ofs = b->l3_ofs = b->l4_ofs = UINT16_MAX; list_poison(&b->list_node); - b->private_p = NULL; } /* Initializes 'b' as an empty ofpbuf that contains the 'allocated' bytes of @@ -164,24 +164,17 @@ struct ofpbuf * ofpbuf_clone_with_headroom(const struct ofpbuf *buffer, size_t headroom) { struct ofpbuf *new_buffer; - uintptr_t data_delta; new_buffer = ofpbuf_clone_data_with_headroom(buffer->data, buffer->size, headroom); - data_delta = (char *) new_buffer->data - (char *) buffer->data; - if (buffer->l2) { + uintptr_t data_delta = (char *)new_buffer->data - (char *)buffer->data; + new_buffer->l2 = (char *) buffer->l2 + data_delta; } - if (buffer->l2_5) { - new_buffer->l2_5 = (char *) buffer->l2_5 + data_delta; - } - if (buffer->l3) { - new_buffer->l3 = (char *) buffer->l3 + data_delta; - } - if (buffer->l4) { - new_buffer->l4 = (char *) buffer->l4 + data_delta; - } + new_buffer->l2_5_ofs = buffer->l2_5_ofs; + new_buffer->l3_ofs = buffer->l3_ofs; + new_buffer->l4_ofs = buffer->l4_ofs; return new_buffer; } @@ -263,19 +256,11 @@ ofpbuf_resize__(struct ofpbuf *b, size_t new_headroom, size_t new_tailroom) new_data = (char *) new_base + new_headroom; if (b->data != new_data) { uintptr_t data_delta = (char *) new_data - (char *) b->data; + b->data = new_data; if (b->l2) { b->l2 = (char *) b->l2 + data_delta; } - if (b->l2_5) { - b->l2_5 = (char *) b->l2_5 + data_delta; - } - if (b->l3) { - b->l3 = (char *) b->l3 + data_delta; - } - if (b->l4) { - b->l4 = (char *) b->l4 + data_delta; - } } } @@ -491,7 +476,7 @@ ofpbuf_to_string(const struct ofpbuf *b, size_t maxbytes) struct ds s; ds_init(&s); - ds_put_format(&s, "size=%"PRIuSIZE", allocated=%"PRIuSIZE", head=%"PRIuSIZE", tail=%"PRIuSIZE"\n", + ds_put_format(&s, "size=%"PRIu32", allocated=%"PRIu32", head=%"PRIuSIZE", tail=%"PRIuSIZE"\n", b->size, b->allocated, ofpbuf_headroom(b), ofpbuf_tailroom(b)); ds_put_hex_dump(&s, b->data, MIN(b->size, maxbytes), 0, false); @@ -510,3 +495,42 @@ ofpbuf_list_delete(struct list *list) ofpbuf_delete(b); } } + +static inline void +ofpbuf_adjust_layer_offset(uint16_t *offset, int increment) +{ + if (*offset != UINT16_MAX) { + *offset += increment; + } +} + +/* Adjust the size of the l2_5 portion of the ofpbuf, updating the l2 + * pointer and the layer offsets. The caller is responsible for + * modifying the contents. */ +void * +ofpbuf_resize_l2_5(struct ofpbuf *b, int increment) +{ + if (increment >= 0) { + ofpbuf_push_uninit(b, increment); + } else { + ofpbuf_pull(b, -increment); + } + + b->l2 = b->data; + /* Adjust layer offsets after l2_5. */ + ofpbuf_adjust_layer_offset(&b->l3_ofs, increment); + ofpbuf_adjust_layer_offset(&b->l4_ofs, increment); + + return b->l2; +} + +/* Adjust the size of the l2 portion of the ofpbuf, updating the l2 + * pointer and the layer offsets. The caller is responsible for + * modifying the contents. */ +void * +ofpbuf_resize_l2(struct ofpbuf *b, int increment) +{ + ofpbuf_resize_l2_5(b, increment); + ofpbuf_adjust_layer_offset(&b->l2_5_ofs, increment); + return b->l2; +} diff --git a/lib/ofpbuf.h b/lib/ofpbuf.h index bda514d89..8d1cb111e 100644 --- a/lib/ofpbuf.h +++ b/lib/ofpbuf.h @@ -27,7 +27,7 @@ extern "C" { #endif -enum ofpbuf_source { +enum OVS_PACKED_ENUM ofpbuf_source { OFPBUF_MALLOC, /* Obtained via malloc(). */ OFPBUF_STACK, /* Un-movable stack space or static buffer. */ OFPBUF_STUB, /* Starts on stack, may expand into heap. */ @@ -39,21 +39,35 @@ enum ofpbuf_source { * as necessary if it grows too large for the available memory. */ struct ofpbuf { void *base; /* First byte of allocated space. */ - size_t allocated; /* Number of bytes allocated. */ - enum ofpbuf_source source; /* Source of memory allocated as 'base'. */ - + uint32_t allocated; /* Number of bytes allocated. */ + uint32_t size; /* Number of bytes in use. */ void *data; /* First byte actually in use. */ - size_t size; /* Number of bytes in use. */ void *l2; /* Link-level header. */ - void *l2_5; /* MPLS label stack */ - void *l3; /* Network-level header. */ - void *l4; /* Transport-level header. */ - + uint16_t l2_5_ofs; /* MPLS label stack offset from l2, or + * UINT16_MAX */ + uint16_t l3_ofs; /* Network-level header offset from l2, or + * UINT16_MAX. */ + uint16_t l4_ofs; /* Transport-level header offset from l2, or + UINT16_MAX. */ + enum ofpbuf_source source; /* Source of memory allocated as 'base'. */ struct list list_node; /* Private list element for use by owner. */ - void *private_p; /* Private pointer for use by owner. */ }; +void * ofpbuf_resize_l2(struct ofpbuf *, int increment); +void * ofpbuf_resize_l2_5(struct ofpbuf *, int increment); +static inline void * ofpbuf_get_l2_5(const struct ofpbuf *); +static inline void ofpbuf_set_l2_5(struct ofpbuf *, void *); +static inline void * ofpbuf_get_l3(const struct ofpbuf *); +static inline void ofpbuf_set_l3(struct ofpbuf *, void *); +static inline void * ofpbuf_get_l4(const struct ofpbuf *); +static inline void ofpbuf_set_l4(struct ofpbuf *, void *); +static inline size_t ofpbuf_get_l4_size(const struct ofpbuf *); +static inline const void *ofpbuf_get_tcp_payload(const struct ofpbuf *); +static inline const void *ofpbuf_get_udp_payload(const struct ofpbuf *); +static inline const void *ofpbuf_get_sctp_payload(const struct ofpbuf *); +static inline const void *ofpbuf_get_icmp_payload(const struct ofpbuf *); + void ofpbuf_use(struct ofpbuf *, void *, size_t); void ofpbuf_use_stack(struct ofpbuf *, void *, size_t); void ofpbuf_use_stub(struct ofpbuf *, void *, size_t); @@ -212,9 +226,40 @@ static inline bool ofpbuf_equal(const struct ofpbuf *a, const struct ofpbuf *b) return a->size == b->size && memcmp(a->data, b->data, a->size) == 0; } +static inline void * ofpbuf_get_l2_5(const struct ofpbuf *b) +{ + return b->l2_5_ofs != UINT16_MAX ? (char *)b->l2 + b->l2_5_ofs : NULL; +} + +static inline void ofpbuf_set_l2_5(struct ofpbuf *b, void *l2_5) +{ + b->l2_5_ofs = l2_5 ? (char *)l2_5 - (char *)b->l2 : UINT16_MAX; +} + +static inline void * ofpbuf_get_l3(const struct ofpbuf *b) +{ + return b->l3_ofs != UINT16_MAX ? (char *)b->l2 + b->l3_ofs : NULL; +} + +static inline void ofpbuf_set_l3(struct ofpbuf *b, void *l3) +{ + b->l3_ofs = l3 ? (char *)l3 - (char *)b->l2 : UINT16_MAX; +} + +static inline void * ofpbuf_get_l4(const struct ofpbuf *b) +{ + return b->l4_ofs != UINT16_MAX ? (char *)b->l2 + b->l4_ofs : NULL; +} + +static inline void ofpbuf_set_l4(struct ofpbuf *b, void *l4) +{ + b->l4_ofs = l4 ? (char *)l4 - (char *)b->l2 : UINT16_MAX; +} + static inline size_t ofpbuf_get_l4_size(const struct ofpbuf *b) { - return b->l4 ? (const char *)ofpbuf_tail(b) - (const char *)b->l4 : 0; + return b->l4_ofs != UINT16_MAX + ? (const char *)ofpbuf_tail(b) - (const char *)ofpbuf_get_l4(b) : 0; } static inline const void *ofpbuf_get_tcp_payload(const struct ofpbuf *b) @@ -222,7 +267,7 @@ static inline const void *ofpbuf_get_tcp_payload(const struct ofpbuf *b) size_t l4_size = ofpbuf_get_l4_size(b); if (OVS_LIKELY(l4_size >= TCP_HEADER_LEN)) { - struct tcp_header *tcp = b->l4; + struct tcp_header *tcp = ofpbuf_get_l4(b); int tcp_len = TCP_OFFSET(tcp->tcp_ctl) * 4; if (OVS_LIKELY(tcp_len >= TCP_HEADER_LEN && tcp_len <= l4_size)) { @@ -235,19 +280,19 @@ static inline const void *ofpbuf_get_tcp_payload(const struct ofpbuf *b) static inline const void *ofpbuf_get_udp_payload(const struct ofpbuf *b) { return OVS_LIKELY(ofpbuf_get_l4_size(b) >= UDP_HEADER_LEN) - ? (const char *)b->l4 + UDP_HEADER_LEN : NULL; + ? (const char *)ofpbuf_get_l4(b) + UDP_HEADER_LEN : NULL; } static inline const void *ofpbuf_get_sctp_payload(const struct ofpbuf *b) { return OVS_LIKELY(ofpbuf_get_l4_size(b) >= SCTP_HEADER_LEN) - ? (const char *)b->l4 + SCTP_HEADER_LEN : NULL; + ? (const char *)ofpbuf_get_l4(b) + SCTP_HEADER_LEN : NULL; } static inline const void *ofpbuf_get_icmp_payload(const struct ofpbuf *b) { return OVS_LIKELY(ofpbuf_get_l4_size(b) >= ICMP_HEADER_LEN) - ? (const char *)b->l4 + ICMP_HEADER_LEN : NULL; + ? (const char *)ofpbuf_get_l4(b) + ICMP_HEADER_LEN : NULL; } #ifdef __cplusplus diff --git a/lib/packets.c b/lib/packets.c index f8edb0205..3366089c1 100644 --- a/lib/packets.c +++ b/lib/packets.c @@ -173,25 +173,18 @@ compose_rarp(struct ofpbuf *b, const uint8_t eth_src[ETH_ADDR_LEN]) /* Insert VLAN header according to given TCI. Packet passed must be Ethernet * packet. Ignores the CFI bit of 'tci' using 0 instead. * - * Also sets 'packet->l2' to point to the new Ethernet header. */ + * Also sets 'packet->l2' to point to the new Ethernet header and adjusts + * the layer offsets accordingly. */ void eth_push_vlan(struct ofpbuf *packet, ovs_be16 tpid, ovs_be16 tci) { - struct eth_header *eh = packet->data; struct vlan_eth_header *veh; /* Insert new 802.1Q header. */ - struct vlan_eth_header tmp; - memcpy(tmp.veth_dst, eh->eth_dst, ETH_ADDR_LEN); - memcpy(tmp.veth_src, eh->eth_src, ETH_ADDR_LEN); - tmp.veth_type = tpid; - tmp.veth_tci = tci & htons(~VLAN_CFI); - tmp.veth_next_type = eh->eth_type; - - veh = ofpbuf_push_uninit(packet, VLAN_HEADER_LEN); - memcpy(veh, &tmp, sizeof tmp); - - packet->l2 = packet->data; + veh = ofpbuf_resize_l2(packet, VLAN_HEADER_LEN); + memmove(veh, (char *)veh + VLAN_HEADER_LEN, 2 * ETH_ADDR_LEN); + veh->veth_type = tpid; + veh->veth_tci = tci & htons(~VLAN_CFI); } /* Removes outermost VLAN header (if any is present) from 'packet'. @@ -202,17 +195,12 @@ void eth_pop_vlan(struct ofpbuf *packet) { struct vlan_eth_header *veh = packet->l2; + if (packet->size >= sizeof *veh && veh->veth_type == htons(ETH_TYPE_VLAN)) { - struct eth_header tmp; - memcpy(tmp.eth_dst, veh->veth_dst, ETH_ADDR_LEN); - memcpy(tmp.eth_src, veh->veth_src, ETH_ADDR_LEN); - tmp.eth_type = veh->veth_next_type; - - ofpbuf_pull(packet, VLAN_HEADER_LEN); - packet->l2 = (char*)packet->l2 + VLAN_HEADER_LEN; - memcpy(packet->data, &tmp, sizeof tmp); + memmove((char *)veh + VLAN_HEADER_LEN, veh, 2 * ETH_ADDR_LEN); + ofpbuf_resize_l2(packet, -VLAN_HEADER_LEN); } } @@ -220,12 +208,14 @@ eth_pop_vlan(struct ofpbuf *packet) static void set_ethertype(struct ofpbuf *packet, ovs_be16 eth_type) { - struct eth_header *eh = packet->data; + struct eth_header *eh = packet->l2; if (eh->eth_type == htons(ETH_TYPE_VLAN)) { ovs_be16 *p; + char *l2_5 = ofpbuf_get_l2_5(packet); + p = ALIGNED_CAST(ovs_be16 *, - (char *)(packet->l2_5 ? packet->l2_5 : packet->l3) - 2); + (l2_5 ? l2_5 : (char *)ofpbuf_get_l3(packet)) - 2); *p = eth_type; } else { eh->eth_type = eth_type; @@ -234,7 +224,7 @@ set_ethertype(struct ofpbuf *packet, ovs_be16 eth_type) static bool is_mpls(struct ofpbuf *packet) { - return packet->l2_5 != NULL; + return packet->l2_5_ofs != UINT16_MAX; } /* Set time to live (TTL) of an MPLS label stack entry (LSE). */ @@ -283,34 +273,14 @@ set_mpls_lse_values(uint8_t ttl, uint8_t tc, uint8_t bos, ovs_be32 label) return lse; } -/* Push an new MPLS stack entry onto the MPLS stack and adjust 'packet->l2' and - * 'packet->l2_5' accordingly. The new entry will be the outermost entry on - * the stack. - * - * Previous to calling this function, 'packet->l2_5' must be set; if the MPLS - * label to be pushed will be the first label in 'packet', then it should be - * the same as 'packet->l3'. */ -static void -push_mpls_lse(struct ofpbuf *packet, struct mpls_hdr *mh) -{ - char * header; - size_t len; - header = ofpbuf_push_uninit(packet, MPLS_HLEN); - len = (char *)packet->l2_5 - (char *)packet->l2; - memmove(header, packet->l2, len); - memcpy(header + len, mh, sizeof *mh); - packet->l2 = (char*)packet->l2 - MPLS_HLEN; - packet->l2_5 = (char*)packet->l2_5 - MPLS_HLEN; -} - /* Set MPLS label stack entry to outermost MPLS header.*/ void set_mpls_lse(struct ofpbuf *packet, ovs_be32 mpls_lse) { - struct mpls_hdr *mh = packet->l2_5; - /* Packet type should be MPLS to set label stack entry. */ if (is_mpls(packet)) { + struct mpls_hdr *mh = ofpbuf_get_l2_5(packet); + /* Update mpls label stack entry. */ mh->mpls_lse = mpls_lse; } @@ -322,22 +292,25 @@ set_mpls_lse(struct ofpbuf *packet, ovs_be32 mpls_lse) void push_mpls(struct ofpbuf *packet, ovs_be16 ethtype, ovs_be32 lse) { - struct mpls_hdr mh; + char * header; + size_t len; if (!eth_type_mpls(ethtype)) { return; } - set_ethertype(packet, ethtype); - if (!is_mpls(packet)) { - /* Set MPLS label stack entry. */ - packet->l2_5 = packet->l3; + /* Set MPLS label stack offset. */ + packet->l2_5_ofs = packet->l3_ofs; } + set_ethertype(packet, ethtype); + /* Push new MPLS shim header onto packet. */ - mh.mpls_lse = lse; - push_mpls_lse(packet, &mh); + len = packet->l2_5_ofs; + header = ofpbuf_resize_l2_5(packet, MPLS_HLEN); + memmove(header, header + MPLS_HLEN, len); + memcpy(header + len, &lse, sizeof lse); } /* If 'packet' is an MPLS packet, removes its outermost MPLS label stack entry. @@ -347,23 +320,17 @@ push_mpls(struct ofpbuf *packet, ovs_be16 ethtype, ovs_be32 lse) void pop_mpls(struct ofpbuf *packet, ovs_be16 ethtype) { - struct mpls_hdr *mh = NULL; - if (is_mpls(packet)) { - size_t len; - mh = packet->l2_5; - len = (char*)packet->l2_5 - (char*)packet->l2; + struct mpls_hdr *mh = ofpbuf_get_l2_5(packet); + size_t len = packet->l2_5_ofs; + set_ethertype(packet, ethtype); if (mh->mpls_lse & htonl(MPLS_BOS_MASK)) { - packet->l2_5 = NULL; - } else { - packet->l2_5 = (char*)packet->l2_5 + MPLS_HLEN; + ofpbuf_set_l2_5(packet, NULL); } /* Shift the l2 header forward. */ memmove((char*)packet->data + MPLS_HLEN, packet->data, len); - packet->size -= MPLS_HLEN; - packet->data = (char*)packet->data + MPLS_HLEN; - packet->l2 = (char*)packet->l2 + MPLS_HLEN; + ofpbuf_resize_l2_5(packet, -MPLS_HLEN); } } @@ -578,7 +545,7 @@ ipv6_is_cidr(const struct in6_addr *netmask) /* Populates 'b' with an Ethernet II packet headed with the given 'eth_dst', * 'eth_src' and 'eth_type' parameters. A payload of 'size' bytes is allocated * in 'b' and returned. This payload may be populated with appropriate - * information by the caller. Sets 'b''s 'l2' and 'l3' pointers to the + * information by the caller. Sets 'b''s 'l2' pointer and 'l3' offset to the * Ethernet header and payload respectively. Aligns b->l3 on a 32-bit * boundary. * @@ -606,7 +573,7 @@ eth_compose(struct ofpbuf *b, const uint8_t eth_dst[ETH_ADDR_LEN], eth->eth_type = htons(eth_type); b->l2 = eth; - b->l3 = data; + ofpbuf_set_l3(b, data); return data; } @@ -615,16 +582,16 @@ static void packet_set_ipv4_addr(struct ofpbuf *packet, ovs_16aligned_be32 *addr, ovs_be32 new_addr) { - struct ip_header *nh = packet->l3; + struct ip_header *nh = ofpbuf_get_l3(packet); ovs_be32 old_addr = get_16aligned_be32(addr); size_t l4_size = ofpbuf_get_l4_size(packet); if (nh->ip_proto == IPPROTO_TCP && l4_size >= TCP_HEADER_LEN) { - struct tcp_header *th = packet->l4; + struct tcp_header *th = ofpbuf_get_l4(packet); th->tcp_csum = recalc_csum32(th->tcp_csum, old_addr, new_addr); } else if (nh->ip_proto == IPPROTO_UDP && l4_size >= UDP_HEADER_LEN ) { - struct udp_header *uh = packet->l4; + struct udp_header *uh = ofpbuf_get_l4(packet); if (uh->udp_csum) { uh->udp_csum = recalc_csum32(uh->udp_csum, old_addr, new_addr); @@ -640,7 +607,7 @@ packet_set_ipv4_addr(struct ofpbuf *packet, /* Returns true, if packet contains at least one routing header where * segements_left > 0. * - * This function assumes that L3 and L4 markers are set in the packet. */ + * This function assumes that L3 and L4 offsets are set in the packet. */ static bool packet_rh_present(struct ofpbuf *packet) { @@ -648,9 +615,9 @@ packet_rh_present(struct ofpbuf *packet) int nexthdr; size_t len; size_t remaining; - uint8_t *data = packet->l3; + uint8_t *data = ofpbuf_get_l3(packet); - remaining = (uint8_t *)packet->l4 - (uint8_t *)packet->l3; + remaining = packet->l4_ofs - packet->l3_ofs; if (remaining < sizeof *nh) { return false; @@ -729,11 +696,11 @@ packet_update_csum128(struct ofpbuf *packet, uint8_t proto, size_t l4_size = ofpbuf_get_l4_size(packet); if (proto == IPPROTO_TCP && l4_size >= TCP_HEADER_LEN) { - struct tcp_header *th = packet->l4; + struct tcp_header *th = ofpbuf_get_l4(packet); th->tcp_csum = recalc_csum128(th->tcp_csum, addr, new_addr); } else if (proto == IPPROTO_UDP && l4_size >= UDP_HEADER_LEN) { - struct udp_header *uh = packet->l4; + struct udp_header *uh = ofpbuf_get_l4(packet); if (uh->udp_csum) { uh->udp_csum = recalc_csum128(uh->udp_csum, addr, new_addr); @@ -779,7 +746,7 @@ void packet_set_ipv4(struct ofpbuf *packet, ovs_be32 src, ovs_be32 dst, uint8_t tos, uint8_t ttl) { - struct ip_header *nh = packet->l3; + struct ip_header *nh = ofpbuf_get_l3(packet); if (get_16aligned_be32(&nh->ip_src) != src) { packet_set_ipv4_addr(packet, &nh->ip_src, src); @@ -809,13 +776,13 @@ packet_set_ipv4(struct ofpbuf *packet, ovs_be32 src, ovs_be32 dst, /* Modifies the IPv6 header fields of 'packet' to be consistent with 'src', * 'dst', 'traffic class', and 'next hop'. Updates 'packet''s L4 checksums as * appropriate. 'packet' must contain a valid IPv6 packet with correctly - * populated l[347] markers. */ + * populated l[34] offsets. */ void packet_set_ipv6(struct ofpbuf *packet, uint8_t proto, const ovs_be32 src[4], const ovs_be32 dst[4], uint8_t key_tc, ovs_be32 key_fl, uint8_t key_hl) { - struct ovs_16aligned_ip6_hdr *nh = packet->l3; + struct ovs_16aligned_ip6_hdr *nh = ofpbuf_get_l3(packet); if (memcmp(&nh->ip6_src, src, sizeof(ovs_be32[4]))) { packet_set_ipv6_addr(packet, proto, nh->ip6_src.be32, src, true); @@ -844,11 +811,11 @@ packet_set_port(ovs_be16 *port, ovs_be16 new_port, ovs_be16 *csum) /* Sets the TCP source and destination port ('src' and 'dst' respectively) of * the TCP header contained in 'packet'. 'packet' must be a valid TCP packet - * with its l4 marker properly populated. */ + * with its l4 offset properly populated. */ void packet_set_tcp_port(struct ofpbuf *packet, ovs_be16 src, ovs_be16 dst) { - struct tcp_header *th = packet->l4; + struct tcp_header *th = ofpbuf_get_l4(packet); packet_set_port(&th->tcp_src, src, &th->tcp_csum); packet_set_port(&th->tcp_dst, dst, &th->tcp_csum); @@ -856,11 +823,11 @@ packet_set_tcp_port(struct ofpbuf *packet, ovs_be16 src, ovs_be16 dst) /* Sets the UDP source and destination port ('src' and 'dst' respectively) of * the UDP header contained in 'packet'. 'packet' must be a valid UDP packet - * with its l4 marker properly populated. */ + * with its l4 offset properly populated. */ void packet_set_udp_port(struct ofpbuf *packet, ovs_be16 src, ovs_be16 dst) { - struct udp_header *uh = packet->l4; + struct udp_header *uh = ofpbuf_get_l4(packet); if (uh->udp_csum) { packet_set_port(&uh->udp_src, src, &uh->udp_csum); @@ -877,22 +844,22 @@ packet_set_udp_port(struct ofpbuf *packet, ovs_be16 src, ovs_be16 dst) /* Sets the SCTP source and destination port ('src' and 'dst' respectively) of * the SCTP header contained in 'packet'. 'packet' must be a valid SCTP packet - * with its l4 marker properly populated. */ + * with its l4 offset properly populated. */ void packet_set_sctp_port(struct ofpbuf *packet, ovs_be16 src, ovs_be16 dst) { - struct sctp_header *sh = packet->l4; + struct sctp_header *sh = ofpbuf_get_l4(packet); ovs_be32 old_csum, old_correct_csum, new_csum; uint16_t tp_len = packet->size - ((uint8_t*)sh - (uint8_t*)packet->data); old_csum = sh->sctp_csum; sh->sctp_csum = 0; - old_correct_csum = crc32c(packet->l4, tp_len); + old_correct_csum = crc32c((void *)sh, tp_len); sh->sctp_src = src; sh->sctp_dst = dst; - new_csum = crc32c(packet->l4, tp_len); + new_csum = crc32c((void *)sh, tp_len); sh->sctp_csum = old_csum ^ old_correct_csum ^ new_csum; } diff --git a/lib/pcap-file.c b/lib/pcap-file.c index b449eff8b..a92e7d3c4 100644 --- a/lib/pcap-file.c +++ b/lib/pcap-file.c @@ -310,7 +310,7 @@ tcp_reader_run(struct tcp_reader *r, const struct flow *flow, || !l7) { return NULL; } - tcp = packet->l4; + tcp = ofpbuf_get_l4(packet); flags = TCP_FLAGS(tcp->tcp_ctl); l7_length = (char *) ofpbuf_tail(packet) - l7; seq = ntohl(get_16aligned_be32(&tcp->tcp_seq)); diff --git a/lib/rconn.c b/lib/rconn.c index 72688ba8d..a5368d563 100644 --- a/lib/rconn.c +++ b/lib/rconn.c @@ -716,10 +716,15 @@ rconn_send__(struct rconn *rc, struct ofpbuf *b, if (rconn_is_connected(rc)) { COVERAGE_INC(rconn_queued); copy_to_monitor(rc, b); - b->private_p = counter; + if (counter) { rconn_packet_counter_inc(counter, b->size); } + + /* Use 'l2' as a private pointer while 'b' is in txq. */ + ovs_assert(b->l2 == b->data); + b->l2 = counter; + list_push_back(&rc->txq, &b->list_node); /* If the queue was empty before we added 'b', try to send some @@ -1103,16 +1108,18 @@ try_send(struct rconn *rc) { struct ofpbuf *msg = ofpbuf_from_list(rc->txq.next); unsigned int n_bytes = msg->size; - struct rconn_packet_counter *counter = msg->private_p; + struct rconn_packet_counter *counter = msg->l2; int retval; /* Eagerly remove 'msg' from the txq. We can't remove it from the list * after sending, if sending is successful, because it is then owned by the * vconn, which might have freed it already. */ list_remove(&msg->list_node); + msg->l2 = msg->data; /* Restore 'l2'. */ retval = vconn_send(rc->vconn, msg); if (retval) { + msg->l2 = counter; /* 'l2' is a private pointer while msg is in txq. */ list_push_front(&rc->txq, &msg->list_node); if (retval != EAGAIN) { report_error(rc, retval); @@ -1205,7 +1212,7 @@ flush_queue(struct rconn *rc) } while (!list_is_empty(&rc->txq)) { struct ofpbuf *b = ofpbuf_from_list(list_pop_front(&rc->txq)); - struct rconn_packet_counter *counter = b->private_p; + struct rconn_packet_counter *counter = b->l2; if (counter) { rconn_packet_counter_dec(counter, b->size); } diff --git a/lib/stp.c b/lib/stp.c index c5aec57d2..78dacb388 100644 --- a/lib/stp.c +++ b/lib/stp.c @@ -1537,7 +1537,7 @@ stp_send_bpdu(struct stp_port *p, const void *bpdu, size_t bpdu_size) pkt = ofpbuf_new(ETH_HEADER_LEN + LLC_HEADER_LEN + bpdu_size); pkt->l2 = eth = ofpbuf_put_zeros(pkt, sizeof *eth); llc = ofpbuf_put_zeros(pkt, sizeof *llc); - pkt->l3 = ofpbuf_put(pkt, bpdu, bpdu_size); + ofpbuf_set_l3(pkt, ofpbuf_put(pkt, bpdu, bpdu_size)); /* 802.2 header. */ memcpy(eth->eth_dst, eth_addr_stp, ETH_ADDR_LEN); diff --git a/lib/util.h b/lib/util.h index 13ff58ece..1bbcee27b 100644 --- a/lib/util.h +++ b/lib/util.h @@ -17,6 +17,7 @@ #ifndef UTIL_H #define UTIL_H 1 +#include #include #include #include diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 87a61f7e3..7172cb216 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -2419,7 +2419,9 @@ bundle_send_learning_packets(struct ofbundle *bundle) learning_packet = bond_compose_learning_packet(bundle->bond, e->mac, e->vlan, &port_void); - learning_packet->private_p = port_void; + /* Temporarily use l2 as a private pointer (see below). */ + ovs_assert(learning_packet->l2 == learning_packet->data); + learning_packet->l2 = port_void; list_push_back(&packets, &learning_packet->list_node); } } @@ -2428,8 +2430,11 @@ bundle_send_learning_packets(struct ofbundle *bundle) error = n_packets = n_errors = 0; LIST_FOR_EACH (learning_packet, list_node, &packets) { int ret; + void *port_void = learning_packet->l2; - ret = ofproto_dpif_send_packet(learning_packet->private_p, learning_packet); + /* Restore l2. */ + learning_packet->l2 = learning_packet->data; + ret = ofproto_dpif_send_packet(port_void, learning_packet); if (ret) { error = ret; n_errors++; diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h index 8c11aff82..a7bf4df4f 100644 --- a/ofproto/ofproto-provider.h +++ b/ofproto/ofproto-provider.h @@ -1299,8 +1299,8 @@ struct ofproto_class { * information in 'flow' is extracted from 'packet', except for * flow->tunnel and flow->in_port, which are assigned the correct values * for the incoming packet. The register values are zeroed. 'packet''s - * header pointers (e.g. packet->l3) are appropriately initialized. - * packet->l3 is aligned on a 32-bit boundary. + * header pointers and offsets (e.g. packet->l3) are appropriately + * initialized. packet->l3 is aligned on a 32-bit boundary. * * The implementation should add the statistics for 'packet' into 'rule'. * diff --git a/tests/test-netflow.c b/tests/test-netflow.c index b6c3109d0..392c6ec76 100644 --- a/tests/test-netflow.c +++ b/tests/test-netflow.c @@ -162,7 +162,7 @@ print_netflow(struct ofpbuf *buf) } if (buf->size) { - printf("%"PRIuSIZE" extra bytes after last record\n", buf->size); + printf("%"PRIu32" extra bytes after last record\n", buf->size); } } diff --git a/tests/test-odp.c b/tests/test-odp.c index a27bf7f7b..d41db8480 100644 --- a/tests/test-odp.c +++ b/tests/test-odp.c @@ -78,7 +78,7 @@ parse_keys(bool wc_keys) odp_flow_key_from_flow(&odp_key, &flow, flow.in_port.odp_port); if (odp_key.size > ODPUTIL_FLOW_KEY_BYTES) { - printf ("too long: %"PRIuSIZE" > %d\n", + printf ("too long: %"PRIu32" > %d\n", odp_key.size, ODPUTIL_FLOW_KEY_BYTES); exit_code = 1; } diff --git a/tests/test-stp.c b/tests/test-stp.c index be1b3959f..9d17745c8 100644 --- a/tests/test-stp.c +++ b/tests/test-stp.c @@ -92,7 +92,7 @@ send_bpdu(struct ofpbuf *pkt, int port_no, void *b_) assert(port_no < b->n_ports); lan = b->ports[port_no]; if (lan) { - const void *data = pkt->l3; + const void *data = ofpbuf_get_l3(pkt); size_t size = (char *) ofpbuf_tail(pkt) - (char *) data; int i; diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c index bd3d5a684..12942471e 100644 --- a/utilities/ovs-ofctl.c +++ b/utilities/ovs-ofctl.c @@ -1963,13 +1963,13 @@ ofctl_ping(int argc, char *argv[]) if (ofptype_pull(&type, reply) || type != OFPTYPE_ECHO_REPLY || reply->size != payload - || memcmp(request->l3, reply->l3, payload)) { + || memcmp(ofpbuf_get_l3(request), ofpbuf_get_l3(reply), payload)) { printf("Reply does not match request. Request:\n"); ofp_print(stdout, request, request->size, verbosity + 2); printf("Reply:\n"); ofp_print(stdout, reply, reply->size, verbosity + 2); } - printf("%"PRIuSIZE" bytes from %s: xid=%08"PRIx32" time=%.1f ms\n", + printf("%"PRIu32" bytes from %s: xid=%08"PRIx32" time=%.1f ms\n", reply->size, argv[1], ntohl(rpy_hdr->xid), (1000*(double)(end.tv_sec - start.tv_sec)) + (.001*(end.tv_usec - start.tv_usec))); @@ -2981,7 +2981,7 @@ ofctl_parse_ofp10_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) ovs_fatal(0, "Trailing garbage in hex data"); } if (match_expout.size != sizeof(struct ofp10_match)) { - ovs_fatal(0, "Input is %"PRIuSIZE" bytes, expected %"PRIuSIZE, + ovs_fatal(0, "Input is %"PRIu32" bytes, expected %"PRIuSIZE, match_expout.size, sizeof(struct ofp10_match)); } @@ -2996,7 +2996,7 @@ ofctl_parse_ofp10_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) ovs_fatal(0, "Trailing garbage in hex data"); } if (match_in.size != sizeof(struct ofp10_match)) { - ovs_fatal(0, "Input is %"PRIuSIZE" bytes, expected %"PRIuSIZE, + ovs_fatal(0, "Input is %"PRIu32" bytes, expected %"PRIuSIZE, match_in.size, sizeof(struct ofp10_match)); } @@ -3045,7 +3045,7 @@ ofctl_parse_ofp11_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) ovs_fatal(0, "Trailing garbage in hex data"); } if (match_in.size != sizeof(struct ofp11_match)) { - ovs_fatal(0, "Input is %"PRIuSIZE" bytes, expected %"PRIuSIZE, + ovs_fatal(0, "Input is %"PRIu32" bytes, expected %"PRIuSIZE, match_in.size, sizeof(struct ofp11_match)); } -- 2.43.0