X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fpackets.c;h=003e5540de207ca33251c76e1c3f7e7239075203;hb=bdd534291ff72077390f7b1745c4443ad3833d99;hp=36b468905f992dee57eb02185cea49dd78ae2a31;hpb=7c457c334539957702a5f09f6fd893975bcef568;p=sliver-openvswitch.git diff --git a/lib/packets.c b/lib/packets.c index 36b468905..003e5540d 100644 --- a/lib/packets.c +++ b/lib/packets.c @@ -130,8 +130,7 @@ eth_addr_is_reserved(const uint8_t ea[ETH_ADDR_LEN]) bool eth_addr_from_string(const char *s, uint8_t ea[ETH_ADDR_LEN]) { - if (sscanf(s, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(ea)) - == ETH_ADDR_SCAN_COUNT) { + if (ovs_scan(s, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(ea))) { return true; } else { memset(ea, 0, ETH_ADDR_LEN); @@ -152,9 +151,9 @@ compose_rarp(struct ofpbuf *b, const uint8_t eth_src[ETH_ADDR_LEN]) struct arp_eth_header *arp; ofpbuf_clear(b); - ofpbuf_prealloc_tailroom(b, ETH_HEADER_LEN + VLAN_HEADER_LEN + ofpbuf_prealloc_tailroom(b, 2 + ETH_HEADER_LEN + VLAN_HEADER_LEN + ARP_ETH_HEADER_LEN); - ofpbuf_reserve(b, VLAN_HEADER_LEN); + ofpbuf_reserve(b, 2 + VLAN_HEADER_LEN); eth = ofpbuf_put_uninit(b, sizeof *eth); memcpy(eth->eth_dst, eth_addr_broadcast, ETH_ADDR_LEN); memcpy(eth->eth_src, eth_src, ETH_ADDR_LEN); @@ -177,7 +176,7 @@ compose_rarp(struct ofpbuf *b, const uint8_t eth_src[ETH_ADDR_LEN]) * * Also sets 'packet->l2' to point to the new Ethernet header. */ void -eth_push_vlan(struct ofpbuf *packet, ovs_be16 tci) +eth_push_vlan(struct ofpbuf *packet, ovs_be16 tpid, ovs_be16 tci) { struct eth_header *eh = packet->data; struct vlan_eth_header *veh; @@ -186,7 +185,7 @@ eth_push_vlan(struct ofpbuf *packet, ovs_be16 tci) 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 = htons(ETH_TYPE_VLAN); + tmp.veth_type = tpid; tmp.veth_tci = tci & htons(~VLAN_CFI); tmp.veth_next_type = eh->eth_type; @@ -218,32 +217,6 @@ eth_pop_vlan(struct ofpbuf *packet) } } -/* Return depth of mpls stack. - * - * 'packet->l2_5' should initially point to 'packet''s outer-most MPLS header - * or may be NULL if there are no MPLS headers. */ -uint16_t -eth_mpls_depth(const struct ofpbuf *packet) -{ - struct mpls_hdr *mh = packet->l2_5; - uint16_t depth; - - if (!mh) { - return 0; - } - - depth = 0; - while (packet->size >= ((char *)mh - (char *)packet->data) + sizeof *mh) { - depth++; - if (mh->mpls_lse & htonl(MPLS_BOS_MASK)) { - break; - } - mh++; - } - - return depth; -} - /* Set ethertype of the packet. */ void set_ethertype(struct ofpbuf *packet, ovs_be16 eth_type) @@ -396,13 +369,16 @@ pop_mpls(struct ofpbuf *packet, ovs_be16 ethtype) /* Converts hex digits in 'hex' to an Ethernet packet in '*packetp'. The * caller must free '*packetp'. On success, returns NULL. On failure, returns - * an error message and stores NULL in '*packetp'. */ + * an error message and stores NULL in '*packetp'. + * + * Aligns the L3 header of '*packetp' on a 32-bit boundary. */ const char * eth_from_hex(const char *hex, struct ofpbuf **packetp) { struct ofpbuf *packet; - packet = *packetp = ofpbuf_new(strlen(hex) / 2); + /* Use 2 bytes of headroom to 32-bit align the L3 header. */ + packet = *packetp = ofpbuf_new_with_headroom(strlen(hex) / 2, 2); if (ofpbuf_put_hex(packet, hex, NULL)[0] != '\0') { ofpbuf_delete(packet); @@ -449,14 +425,14 @@ eth_addr_bitand(const uint8_t src[ETH_ADDR_LEN], int ip_count_cidr_bits(ovs_be32 netmask) { - return 32 - ctz(ntohl(netmask)); + return 32 - ctz32(ntohl(netmask)); } void ip_format_masked(ovs_be32 ip, ovs_be32 mask, struct ds *s) { ds_put_format(s, IP_FMT, IP_ARGS(ip)); - if (mask != htonl(UINT32_MAX)) { + if (mask != OVS_BE32_MAX) { if (ip_is_cidr(mask)) { ds_put_format(s, "/%d", ip_count_cidr_bits(mask)); } else { @@ -603,7 +579,8 @@ ipv6_is_cidr(const struct in6_addr *netmask) * '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 - * Ethernet header and payload respectively. + * Ethernet header and payload respectively. Aligns b->l3 on a 32-bit + * boundary. * * The returned packet has enough headroom to insert an 802.1Q VLAN header if * desired. */ @@ -617,8 +594,10 @@ eth_compose(struct ofpbuf *b, const uint8_t eth_dst[ETH_ADDR_LEN], ofpbuf_clear(b); - ofpbuf_prealloc_tailroom(b, ETH_HEADER_LEN + VLAN_HEADER_LEN + size); - ofpbuf_reserve(b, VLAN_HEADER_LEN); + /* The magic 2 here ensures that the L3 header (when it is added later) + * will be 32-bit aligned. */ + ofpbuf_prealloc_tailroom(b, 2 + ETH_HEADER_LEN + VLAN_HEADER_LEN + size); + ofpbuf_reserve(b, 2 + VLAN_HEADER_LEN); eth = ofpbuf_put_uninit(b, ETH_HEADER_LEN); data = ofpbuf_put_uninit(b, size); @@ -664,7 +643,7 @@ packet_set_ipv4_addr(struct ofpbuf *packet, static bool packet_rh_present(struct ofpbuf *packet) { - const struct ip6_hdr *nh; + const struct ovs_16aligned_ip6_hdr *nh; int nexthdr; size_t len; size_t remaining; @@ -675,7 +654,7 @@ packet_rh_present(struct ofpbuf *packet) if (remaining < sizeof *nh) { return false; } - nh = ALIGNED_CAST(struct ip6_hdr *, data); + nh = ALIGNED_CAST(struct ovs_16aligned_ip6_hdr *, data); data += sizeof *nh; remaining -= sizeof *nh; nexthdr = nh->ip6_nxt; @@ -711,8 +690,8 @@ packet_rh_present(struct ofpbuf *packet) nexthdr = ext_hdr->ip6e_nxt; len = (ext_hdr->ip6e_len + 2) * 4; } else if (nexthdr == IPPROTO_FRAGMENT) { - const struct ip6_frag *frag_hdr = ALIGNED_CAST(struct ip6_frag *, - data); + const struct ovs_16aligned_ip6_frag *frag_hdr + = ALIGNED_CAST(struct ovs_16aligned_ip6_frag *, data); nexthdr = frag_hdr->ip6f_nxt; len = sizeof *frag_hdr; @@ -744,7 +723,7 @@ packet_rh_present(struct ofpbuf *packet) static void packet_update_csum128(struct ofpbuf *packet, uint8_t proto, - ovs_be32 addr[4], const ovs_be32 new_addr[4]) + ovs_16aligned_be32 addr[4], const ovs_be32 new_addr[4]) { if (proto == IPPROTO_TCP && packet->l7) { struct tcp_header *th = packet->l4; @@ -764,25 +743,29 @@ packet_update_csum128(struct ofpbuf *packet, uint8_t proto, static void packet_set_ipv6_addr(struct ofpbuf *packet, uint8_t proto, - struct in6_addr *addr, const ovs_be32 new_addr[4], + ovs_16aligned_be32 addr[4], const ovs_be32 new_addr[4], bool recalculate_csum) { if (recalculate_csum) { - packet_update_csum128(packet, proto, (ovs_be32 *)addr, new_addr); + packet_update_csum128(packet, proto, addr, new_addr); } - memcpy(addr, new_addr, sizeof(*addr)); + memcpy(addr, new_addr, sizeof(ovs_be32[4])); } static void -packet_set_ipv6_flow_label(ovs_be32 *flow_label, ovs_be32 flow_key) +packet_set_ipv6_flow_label(ovs_16aligned_be32 *flow_label, ovs_be32 flow_key) { - *flow_label = (*flow_label & htonl(~IPV6_LABEL_MASK)) | flow_key; + ovs_be32 old_label = get_16aligned_be32(flow_label); + ovs_be32 new_label = (old_label & htonl(~IPV6_LABEL_MASK)) | flow_key; + put_16aligned_be32(flow_label, new_label); } static void -packet_set_ipv6_tc(ovs_be32 *flow_label, uint8_t tc) +packet_set_ipv6_tc(ovs_16aligned_be32 *flow_label, uint8_t tc) { - *flow_label = (*flow_label & htonl(0xF00FFFFF)) | htonl(tc << 20); + ovs_be32 old_label = get_16aligned_be32(flow_label); + ovs_be32 new_label = (old_label & htonl(0xF00FFFFF)) | htonl(tc << 20); + put_16aligned_be32(flow_label, new_label); } /* Modifies the IPv4 header fields of 'packet' to be consistent with 'src', @@ -829,14 +812,14 @@ 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 ip6_hdr *nh = packet->l3; + struct ovs_16aligned_ip6_hdr *nh = packet->l3; if (memcmp(&nh->ip6_src, src, sizeof(ovs_be32[4]))) { - packet_set_ipv6_addr(packet, proto, &nh->ip6_src, src, true); + packet_set_ipv6_addr(packet, proto, nh->ip6_src.be32, src, true); } if (memcmp(&nh->ip6_dst, dst, sizeof(ovs_be32[4]))) { - packet_set_ipv6_addr(packet, proto, &nh->ip6_dst, dst, + packet_set_ipv6_addr(packet, proto, nh->ip6_dst.be32, dst, !packet_rh_present(packet)); } @@ -914,7 +897,7 @@ packet_set_sctp_port(struct ofpbuf *packet, ovs_be16 src, ovs_be16 dst) * * 'flow' must be the flow corresponding to 'packet' and 'packet''s header * pointers must be properly initialized (e.g. with flow_extract()). */ -uint8_t +uint16_t packet_get_tcp_flags(const struct ofpbuf *packet, const struct flow *flow) { if (dl_type_is_ip_any(flow->dl_type) && @@ -926,11 +909,44 @@ packet_get_tcp_flags(const struct ofpbuf *packet, const struct flow *flow) } } +const char * +packet_tcp_flag_to_string(uint32_t flag) +{ + switch (flag) { + case TCP_FIN: + return "fin"; + case TCP_SYN: + return "syn"; + case TCP_RST: + return "rst"; + case TCP_PSH: + return "psh"; + case TCP_ACK: + return "ack"; + case TCP_URG: + return "urg"; + case TCP_ECE: + return "ece"; + case TCP_CWR: + return "cwr"; + case TCP_NS: + return "ns"; + case 0x200: + return "[200]"; + case 0x400: + return "[400]"; + case 0x800: + return "[800]"; + default: + return NULL; + } +} + /* Appends a string representation of the TCP flags value 'tcp_flags' * (e.g. obtained via packet_get_tcp_flags() or TCP_FLAGS) to 's', in the * format used by tcpdump. */ void -packet_format_tcp_flags(struct ds *s, uint8_t tcp_flags) +packet_format_tcp_flags(struct ds *s, uint16_t tcp_flags) { if (!tcp_flags) { ds_put_cstr(s, "none"); @@ -955,10 +971,22 @@ packet_format_tcp_flags(struct ds *s, uint8_t tcp_flags) if (tcp_flags & TCP_ACK) { ds_put_char(s, '.'); } - if (tcp_flags & 0x40) { - ds_put_cstr(s, "[40]"); + if (tcp_flags & TCP_ECE) { + ds_put_cstr(s, "E"); + } + if (tcp_flags & TCP_CWR) { + ds_put_cstr(s, "C"); + } + if (tcp_flags & TCP_NS) { + ds_put_cstr(s, "N"); + } + if (tcp_flags & 0x200) { + ds_put_cstr(s, "[200]"); + } + if (tcp_flags & 0x400) { + ds_put_cstr(s, "[400]"); } - if (tcp_flags & 0x80) { - ds_put_cstr(s, "[80]"); + if (tcp_flags & 0x800) { + ds_put_cstr(s, "[800]"); } }