static struct ip_header * pull_ip(struct ofpbuf *packet) { if (packet->size >= IP_HEADER_LEN) { struct ip_header *ip = packet->data; int ip_len = IP_IHL(ip->ip_ihl_ver) * 4; if (ip_len >= IP_HEADER_LEN && packet->size >= ip_len) { return ofpbuf_pull(packet, ip_len); } } return NULL; }
void * netdev_tnl_ip_extract_tnl_md(struct dp_packet *packet, struct flow_tnl *tnl, unsigned int *hlen) { void *nh; struct ip_header *ip; struct ovs_16aligned_ip6_hdr *ip6; void *l4; int l3_size; nh = dp_packet_l3(packet); ip = nh; ip6 = nh; l4 = dp_packet_l4(packet); if (!nh || !l4) { return NULL; } *hlen = sizeof(struct eth_header); l3_size = dp_packet_size(packet) - ((char *)nh - (char *)dp_packet_data(packet)); if (IP_VER(ip->ip_ihl_ver) == 4) { ovs_be32 ip_src, ip_dst; if (csum(ip, IP_IHL(ip->ip_ihl_ver) * 4)) { VLOG_WARN_RL(&err_rl, "ip packet has invalid checksum"); return NULL; } if (ntohs(ip->ip_tot_len) > l3_size) { VLOG_WARN_RL(&err_rl, "ip packet is truncated (IP length %d, actual %d)", ntohs(ip->ip_tot_len), l3_size); return NULL; } if (IP_IHL(ip->ip_ihl_ver) * 4 > sizeof(struct ip_header)) { VLOG_WARN_RL(&err_rl, "ip options not supported on tunnel packets " "(%d bytes)", IP_IHL(ip->ip_ihl_ver) * 4); return NULL; } ip_src = get_16aligned_be32(&ip->ip_src); ip_dst = get_16aligned_be32(&ip->ip_dst); tnl->ip_src = ip_src; tnl->ip_dst = ip_dst; tnl->ip_tos = ip->ip_tos; tnl->ip_ttl = ip->ip_ttl; *hlen += IP_HEADER_LEN; } else if (IP_VER(ip->ip_ihl_ver) == 6) { ovs_be32 tc_flow = get_16aligned_be32(&ip6->ip6_flow); memcpy(tnl->ipv6_src.s6_addr, ip6->ip6_src.be16, sizeof ip6->ip6_src); memcpy(tnl->ipv6_dst.s6_addr, ip6->ip6_dst.be16, sizeof ip6->ip6_dst); tnl->ip_tos = ntohl(tc_flow) >> 20; tnl->ip_ttl = ip6->ip6_hlim; *hlen += IPV6_HEADER_LEN; } else {