static int parse_layer3_packet_by_proto(struct packet *packet, u16 proto, u8 *header_start, u8 *packet_end, char **error) { u8 *p = header_start; if (proto == ETHERTYPE_IP) { struct ipv4 *ip = NULL; /* Examine IPv4 header. */ if (p + sizeof(struct ipv4) > packet_end) { asprintf(error, "IPv4 header overflows packet"); goto error_out; } /* Look at the IP version number, which is in the first 4 bits * of both IPv4 and IPv6 packets. */ ip = (struct ipv4 *)p; if (ip->version == 4) { return parse_ipv4(packet, p, packet_end, error); } else { asprintf(error, "Bad IP version for ETHERTYPE_IP"); goto error_out; } } else if (proto == ETHERTYPE_IPV6) { struct ipv6 *ip = NULL; /* Examine IPv6 header. */ if (p + sizeof(struct ipv6) > packet_end) { asprintf(error, "IPv6 header overflows packet"); goto error_out; } /* Look at the IP version number, which is in the first 4 bits * of both IPv4 and IPv6 packets. */ ip = (struct ipv6 *)p; if (ip->version == 6) { return parse_ipv6(packet, p, packet_end, error); } else { asprintf(error, "Bad IP version for ETHERTYPE_IPV6"); goto error_out; } } else if ((proto == ETHERTYPE_MPLS_UC) || (proto == ETHERTYPE_MPLS_MC)) { return parse_mpls(packet, p, packet_end, error); } else { return PACKET_UNKNOWN_L4; } error_out: return PACKET_BAD; }
/* Initializes 'flow' members from 'packet', 'skb_priority', 'tnl', and * 'ofp_in_port'. * * Initializes 'packet' header pointers as follows: * * - packet->l2 to the start of the Ethernet header. * * - packet->l2_5 to the start of the MPLS shim header. * * - packet->l3 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. * * - packet->l4 to just past the IPv4 header, if one is present and has a * correct length, and otherwise NULL. * * - packet->l7 to just past the TCP or UDP or ICMP header, if one is * present and has a correct length, and otherwise NULL. */ void flow_extract(struct ofpbuf *packet, uint32_t skb_priority, uint32_t skb_mark, const struct flow_tnl *tnl, uint16_t ofp_in_port, struct flow *flow) { struct ofpbuf b = *packet; struct eth_header *eth; COVERAGE_INC(flow_extract); memset(flow, 0, sizeof *flow); if (tnl) { ovs_assert(tnl != &flow->tunnel); flow->tunnel = *tnl; } flow->in_port = ofp_in_port; flow->skb_priority = skb_priority; flow->skb_mark = skb_mark; packet->l2 = b.data; packet->l2_5 = NULL; packet->l3 = NULL; packet->l4 = NULL; packet->l7 = NULL; if (b.size < sizeof *eth) { return; } /* Link layer. */ eth = b.data; memcpy(flow->dl_src, eth->eth_src, ETH_ADDR_LEN); memcpy(flow->dl_dst, eth->eth_dst, ETH_ADDR_LEN); /* dl_type, vlan_tci. */ ofpbuf_pull(&b, ETH_ADDR_LEN * 2); if (eth->eth_type == htons(ETH_TYPE_VLAN)) { parse_vlan(&b, flow); } flow->dl_type = parse_ethertype(&b); /* Parse mpls, copy l3 ttl. */ if (eth_type_mpls(flow->dl_type)) { packet->l2_5 = b.data; parse_mpls(&b, flow); } packet->l3 = b.data; flow_extract_l3_onwards(packet, flow, flow->dl_type); }
/* Initializes 'flow' members from 'packet', 'skb_priority', 'tnl', and * 'in_port'. * * Initializes 'packet' header pointers as follows: * * - packet->l2 to the start of the Ethernet header. * * - packet->l2_5 to the start of the MPLS shim header. * * - packet->l3 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. * * - packet->l4 to just past the IPv4 header, if one is present and has a * correct length, and otherwise NULL. * * - packet->l7 to just past the TCP/UDP/SCTP/ICMP header, if one is * present and has a correct length, and otherwise NULL. */ void flow_extract(struct ofpbuf *packet, uint32_t skb_priority, uint32_t pkt_mark, const struct flow_tnl *tnl, const union flow_in_port *in_port, struct flow *flow) { struct ofpbuf b = *packet; struct eth_header *eth; COVERAGE_INC(flow_extract); memset(flow, 0, sizeof *flow); if (tnl) { ovs_assert(tnl != &flow->tunnel); flow->tunnel = *tnl; } if (in_port) { flow->in_port = *in_port; } flow->skb_priority = skb_priority; flow->pkt_mark = pkt_mark; packet->l2 = b.data; packet->l2_5 = NULL; packet->l3 = NULL; packet->l4 = NULL; packet->l7 = NULL; if (b.size < sizeof *eth) { return; } /* Link layer. */ eth = b.data; memcpy(flow->dl_src, eth->eth_src, ETH_ADDR_LEN); memcpy(flow->dl_dst, eth->eth_dst, ETH_ADDR_LEN); /* dl_type, vlan_tci. */ ofpbuf_pull(&b, ETH_ADDR_LEN * 2); if (eth->eth_type == htons(ETH_TYPE_VLAN)) { parse_vlan(&b, flow); } flow->dl_type = parse_ethertype(&b); /* Parse mpls, copy l3 ttl. */ if (eth_type_mpls(flow->dl_type)) { packet->l2_5 = b.data; parse_mpls(&b, flow); } /* Network layer. */ packet->l3 = b.data; if (flow->dl_type == htons(ETH_TYPE_IP)) { const struct ip_header *nh = pull_ip(&b); if (nh) { packet->l4 = b.data; flow->nw_src = get_16aligned_be32(&nh->ip_src); flow->nw_dst = get_16aligned_be32(&nh->ip_dst); flow->nw_proto = nh->ip_proto; flow->nw_tos = nh->ip_tos; if (IP_IS_FRAGMENT(nh->ip_frag_off)) { flow->nw_frag = FLOW_NW_FRAG_ANY; if (nh->ip_frag_off & htons(IP_FRAG_OFF_MASK)) { flow->nw_frag |= FLOW_NW_FRAG_LATER; } } flow->nw_ttl = nh->ip_ttl; if (!(nh->ip_frag_off & htons(IP_FRAG_OFF_MASK))) { if (flow->nw_proto == IPPROTO_TCP) { parse_tcp(packet, &b, flow); } else if (flow->nw_proto == IPPROTO_UDP) { parse_udp(packet, &b, flow); } else if (flow->nw_proto == IPPROTO_SCTP) { parse_sctp(packet, &b, flow); } else if (flow->nw_proto == IPPROTO_ICMP) { const struct icmp_header *icmp = pull_icmp(&b); if (icmp) { flow->tp_src = htons(icmp->icmp_type); flow->tp_dst = htons(icmp->icmp_code); packet->l7 = b.data; } } } } } else if (flow->dl_type == htons(ETH_TYPE_IPV6)) { if (parse_ipv6(&b, flow)) { return; } packet->l4 = b.data; if (flow->nw_proto == IPPROTO_TCP) { parse_tcp(packet, &b, flow); } else if (flow->nw_proto == IPPROTO_UDP) { parse_udp(packet, &b, flow); } else if (flow->nw_proto == IPPROTO_SCTP) { parse_sctp(packet, &b, flow); } else if (flow->nw_proto == IPPROTO_ICMPV6) { if (parse_icmpv6(&b, flow)) { packet->l7 = b.data; } } } else if (flow->dl_type == htons(ETH_TYPE_ARP) || flow->dl_type == htons(ETH_TYPE_RARP)) { const struct arp_eth_header *arp = pull_arp(&b); if (arp && arp->ar_hrd == htons(1) && arp->ar_pro == htons(ETH_TYPE_IP) && arp->ar_hln == ETH_ADDR_LEN && arp->ar_pln == 4) { /* We only match on the lower 8 bits of the opcode. */ if (ntohs(arp->ar_op) <= 0xff) { flow->nw_proto = ntohs(arp->ar_op); } flow->nw_src = get_16aligned_be32(&arp->ar_spa); flow->nw_dst = get_16aligned_be32(&arp->ar_tpa); memcpy(flow->arp_sha, arp->ar_sha, ETH_ADDR_LEN); memcpy(flow->arp_tha, arp->ar_tha, ETH_ADDR_LEN); } } }