+}
+
+static void
+parse_udp(struct ofpbuf *packet, struct ofpbuf *b, struct flow *flow)
+{
+ const struct udp_header *udp = pull_udp(b);
+ if (udp) {
+ flow->tp_src = udp->udp_src;
+ flow->tp_dst = udp->udp_dst;
+ packet->l7 = b->data;
+ }
+}
+
+static bool
+parse_icmpv6(struct ofpbuf *b, struct flow *flow)
+{
+ const struct icmp6_hdr *icmp = pull_icmpv6(b);
+
+ if (!icmp) {
+ return false;
+ }
+
+ /* The ICMPv6 type and code fields use the 16-bit transport port
+ * fields, so we need to store them in 16-bit network byte order. */
+ flow->icmp_type = htons(icmp->icmp6_type);
+ flow->icmp_code = htons(icmp->icmp6_code);
+
+ if (icmp->icmp6_code == 0 &&
+ (icmp->icmp6_type == ND_NEIGHBOR_SOLICIT ||
+ icmp->icmp6_type == ND_NEIGHBOR_ADVERT)) {
+ const struct in6_addr *nd_target;
+
+ nd_target = ofpbuf_try_pull(b, sizeof *nd_target);
+ if (!nd_target) {
+ return false;
+ }
+ flow->nd_target = *nd_target;
+
+ while (b->size >= 8) {
+ /* The minimum size of an option is 8 bytes, which also is
+ * the size of Ethernet link-layer options. */
+ const struct nd_opt_hdr *nd_opt = b->data;
+ int opt_len = nd_opt->nd_opt_len * 8;
+
+ if (!opt_len || opt_len > b->size) {
+ goto invalid;
+ }
+
+ /* Store the link layer address if the appropriate option is
+ * provided. It is considered an error if the same link
+ * layer option is specified twice. */
+ if (nd_opt->nd_opt_type == ND_OPT_SOURCE_LINKADDR
+ && opt_len == 8) {
+ if (eth_addr_is_zero(flow->arp_sha)) {
+ memcpy(flow->arp_sha, nd_opt + 1, ETH_ADDR_LEN);
+ } else {
+ goto invalid;
+ }
+ } else if (nd_opt->nd_opt_type == ND_OPT_TARGET_LINKADDR
+ && opt_len == 8) {
+ if (eth_addr_is_zero(flow->arp_tha)) {
+ memcpy(flow->arp_tha, nd_opt + 1, ETH_ADDR_LEN);
+ } else {
+ goto invalid;
+ }
+ }
+
+ if (!ofpbuf_try_pull(b, opt_len)) {
+ goto invalid;
+ }
+ }
+ }
+
+ return true;
+
+invalid:
+ memset(&flow->nd_target, 0, sizeof(flow->nd_target));
+ memset(flow->arp_sha, 0, sizeof(flow->arp_sha));
+ memset(flow->arp_tha, 0, sizeof(flow->arp_tha));
+
+ return false;