}
 EXPORT_SYMBOL(__skb_flow_get_ports);
 
-enum flow_dissect_ret {
-       FLOW_DISSECT_RET_OUT_GOOD,
-       FLOW_DISSECT_RET_OUT_BAD,
-       FLOW_DISSECT_RET_OUT_PROTO_AGAIN,
-};
-
 static enum flow_dissect_ret
 __skb_flow_dissect_mpls(const struct sk_buff *skb,
                        struct flow_dissector *flow_dissector,
        if (flags & FLOW_DISSECTOR_F_STOP_AT_ENCAP)
                return FLOW_DISSECT_RET_OUT_GOOD;
 
-       return FLOW_DISSECT_RET_OUT_PROTO_AGAIN;
+       return FLOW_DISSECT_RET_PROTO_AGAIN;
 }
 
 static void
        struct flow_dissector_key_icmp *key_icmp;
        struct flow_dissector_key_tags *key_tags;
        struct flow_dissector_key_vlan *key_vlan;
+       enum flow_dissect_ret fdret;
        bool skip_vlan = false;
        u8 ip_proto = 0;
        bool ret;
        }
 
 proto_again:
+       fdret = FLOW_DISSECT_RET_CONTINUE;
+
        switch (proto) {
        case htons(ETH_P_IP): {
                const struct iphdr *iph;
                struct iphdr _iph;
-ip:
+
                iph = __skb_header_pointer(skb, nhoff, sizeof(_iph), data, hlen, &_iph);
-               if (!iph || iph->ihl < 5)
-                       goto out_bad;
+               if (!iph || iph->ihl < 5) {
+                       fdret = FLOW_DISSECT_RET_OUT_BAD;
+                       break;
+               }
+
                nhoff += iph->ihl * 4;
 
                ip_proto = iph->protocol;
                        key_control->flags |= FLOW_DIS_IS_FRAGMENT;
 
                        if (iph->frag_off & htons(IP_OFFSET)) {
-                               goto out_good;
+                               fdret = FLOW_DISSECT_RET_OUT_GOOD;
+                               break;
                        } else {
                                key_control->flags |= FLOW_DIS_FIRST_FRAG;
-                               if (!(flags & FLOW_DISSECTOR_F_PARSE_1ST_FRAG))
-                                       goto out_good;
+                               if (!(flags &
+                                     FLOW_DISSECTOR_F_PARSE_1ST_FRAG)) {
+                                       fdret = FLOW_DISSECT_RET_OUT_GOOD;
+                                       break;
+                               }
                        }
                }
 
                __skb_flow_dissect_ipv4(skb, flow_dissector,
                                        target_container, data, iph);
 
-               if (flags & FLOW_DISSECTOR_F_STOP_AT_L3)
-                       goto out_good;
+               if (flags & FLOW_DISSECTOR_F_STOP_AT_L3) {
+                       fdret = FLOW_DISSECT_RET_OUT_GOOD;
+                       break;
+               }
 
                break;
        }
                const struct ipv6hdr *iph;
                struct ipv6hdr _iph;
 
-ipv6:
                iph = __skb_header_pointer(skb, nhoff, sizeof(_iph), data, hlen, &_iph);
-               if (!iph)
-                       goto out_bad;
+               if (!iph) {
+                       fdret = FLOW_DISSECT_RET_OUT_BAD;
+                       break;
+               }
 
                ip_proto = iph->nexthdr;
                nhoff += sizeof(struct ipv6hdr);
                                                                     target_container);
                                key_tags->flow_label = ntohl(flow_label);
                        }
-                       if (flags & FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL)
-                               goto out_good;
+                       if (flags & FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL) {
+                               fdret = FLOW_DISSECT_RET_OUT_GOOD;
+                               break;
+                       }
                }
 
                __skb_flow_dissect_ipv6(skb, flow_dissector,
                                        target_container, data, iph);
 
                if (flags & FLOW_DISSECTOR_F_STOP_AT_L3)
-                       goto out_good;
+                       fdret = FLOW_DISSECT_RET_OUT_GOOD;
 
                break;
        }
                if (!vlan_tag_present || eth_type_vlan(skb->protocol)) {
                        vlan = __skb_header_pointer(skb, nhoff, sizeof(_vlan),
                                                    data, hlen, &_vlan);
-                       if (!vlan)
-                               goto out_bad;
+                       if (!vlan) {
+                               fdret = FLOW_DISSECT_RET_OUT_BAD;
+                               break;
+                       }
+
                        proto = vlan->h_vlan_encapsulated_proto;
                        nhoff += sizeof(*vlan);
-                       if (skip_vlan)
-                               goto proto_again;
+                       if (skip_vlan) {
+                               fdret = FLOW_DISSECT_RET_PROTO_AGAIN;
+                               break;
+                       }
                }
 
                skip_vlan = true;
                        }
                }
 
-               goto proto_again;
+               fdret = FLOW_DISSECT_RET_PROTO_AGAIN;
+               break;
        }
        case htons(ETH_P_PPP_SES): {
                struct {
                        __be16 proto;
                } *hdr, _hdr;
                hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hlen, &_hdr);
-               if (!hdr)
-                       goto out_bad;
+               if (!hdr) {
+                       fdret = FLOW_DISSECT_RET_OUT_BAD;
+                       break;
+               }
+
                proto = hdr->proto;
                nhoff += PPPOE_SES_HLEN;
                switch (proto) {
                case htons(PPP_IP):
-                       goto ip;
+                       proto = htons(ETH_P_IP);
+                       fdret = FLOW_DISSECT_RET_PROTO_AGAIN;
+                       break;
                case htons(PPP_IPV6):
-                       goto ipv6;
+                       proto = htons(ETH_P_IPV6);
+                       fdret = FLOW_DISSECT_RET_PROTO_AGAIN;
+                       break;
                default:
-                       goto out_bad;
+                       fdret = FLOW_DISSECT_RET_OUT_BAD;
+                       break;
                }
+               break;
        }
        case htons(ETH_P_TIPC): {
                struct {
                        __be32 srcnode;
                } *hdr, _hdr;
                hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hlen, &_hdr);
-               if (!hdr)
-                       goto out_bad;
+               if (!hdr) {
+                       fdret = FLOW_DISSECT_RET_OUT_BAD;
+                       break;
+               }
 
                if (dissector_uses_key(flow_dissector,
                                       FLOW_DISSECTOR_KEY_TIPC_ADDRS)) {
                        key_addrs->tipcaddrs.srcnode = hdr->srcnode;
                        key_control->addr_type = FLOW_DISSECTOR_KEY_TIPC_ADDRS;
                }
-               goto out_good;
+               fdret = FLOW_DISSECT_RET_OUT_GOOD;
+               break;
        }
 
        case htons(ETH_P_MPLS_UC):
        case htons(ETH_P_MPLS_MC):
-mpls:
-               switch (__skb_flow_dissect_mpls(skb, flow_dissector,
+               fdret = __skb_flow_dissect_mpls(skb, flow_dissector,
                                                target_container, data,
-                                               nhoff, hlen)) {
-               case FLOW_DISSECT_RET_OUT_GOOD:
-                       goto out_good;
-               case FLOW_DISSECT_RET_OUT_BAD:
-               default:
-                       goto out_bad;
-               }
+                                               nhoff, hlen);
+               break;
        case htons(ETH_P_FCOE):
-               if ((hlen - nhoff) < FCOE_HEADER_LEN)
-                       goto out_bad;
+               if ((hlen - nhoff) < FCOE_HEADER_LEN) {
+                       fdret = FLOW_DISSECT_RET_OUT_BAD;
+                       break;
+               }
 
                nhoff += FCOE_HEADER_LEN;
-               goto out_good;
+               fdret = FLOW_DISSECT_RET_OUT_GOOD;
+               break;
 
        case htons(ETH_P_ARP):
        case htons(ETH_P_RARP):
-               switch (__skb_flow_dissect_arp(skb, flow_dissector,
+               fdret = __skb_flow_dissect_arp(skb, flow_dissector,
                                               target_container, data,
-                                              nhoff, hlen)) {
-               case FLOW_DISSECT_RET_OUT_GOOD:
-                       goto out_good;
-               case FLOW_DISSECT_RET_OUT_BAD:
-               default:
-                       goto out_bad;
-               }
+                                              nhoff, hlen);
+               break;
+
+       default:
+               fdret = FLOW_DISSECT_RET_OUT_BAD;
+               break;
+       }
+
+       /* Process result of proto processing */
+       switch (fdret) {
+       case FLOW_DISSECT_RET_OUT_GOOD:
+               goto out_good;
+       case FLOW_DISSECT_RET_PROTO_AGAIN:
+               goto proto_again;
+       case FLOW_DISSECT_RET_CONTINUE:
+       case FLOW_DISSECT_RET_IPPROTO_AGAIN:
+               break;
+       case FLOW_DISSECT_RET_OUT_BAD:
        default:
                goto out_bad;
        }
 
 ip_proto_again:
+       fdret = FLOW_DISSECT_RET_CONTINUE;
+
        switch (ip_proto) {
        case IPPROTO_GRE:
-               switch (__skb_flow_dissect_gre(skb, key_control, flow_dissector,
+               fdret = __skb_flow_dissect_gre(skb, key_control, flow_dissector,
                                               target_container, data,
-                                              &proto, &nhoff, &hlen, flags)) {
-               case FLOW_DISSECT_RET_OUT_GOOD:
-                       goto out_good;
-               case FLOW_DISSECT_RET_OUT_BAD:
-                       goto out_bad;
-               case FLOW_DISSECT_RET_OUT_PROTO_AGAIN:
-                       goto proto_again;
-               }
+                                              &proto, &nhoff, &hlen, flags);
+               break;
+
        case NEXTHDR_HOP:
        case NEXTHDR_ROUTING:
        case NEXTHDR_DEST: {
 
                opthdr = __skb_header_pointer(skb, nhoff, sizeof(_opthdr),
                                              data, hlen, &_opthdr);
-               if (!opthdr)
-                       goto out_bad;
+               if (!opthdr) {
+                       fdret = FLOW_DISSECT_RET_OUT_BAD;
+                       break;
+               }
 
                ip_proto = opthdr[0];
                nhoff += (opthdr[1] + 1) << 3;
 
-               goto ip_proto_again;
+               fdret = FLOW_DISSECT_RET_IPPROTO_AGAIN;
+               break;
        }
        case NEXTHDR_FRAGMENT: {
                struct frag_hdr _fh, *fh;
                fh = __skb_header_pointer(skb, nhoff, sizeof(_fh),
                                          data, hlen, &_fh);
 
-               if (!fh)
-                       goto out_bad;
+               if (!fh) {
+                       fdret = FLOW_DISSECT_RET_OUT_BAD;
+                       break;
+               }
 
                key_control->flags |= FLOW_DIS_IS_FRAGMENT;
 
 
                if (!(fh->frag_off & htons(IP6_OFFSET))) {
                        key_control->flags |= FLOW_DIS_FIRST_FRAG;
-                       if (flags & FLOW_DISSECTOR_F_PARSE_1ST_FRAG)
-                               goto ip_proto_again;
+                       if (flags & FLOW_DISSECTOR_F_PARSE_1ST_FRAG) {
+                               fdret = FLOW_DISSECT_RET_IPPROTO_AGAIN;
+                               break;
+                       }
                }
-               goto out_good;
+
+               fdret = FLOW_DISSECT_RET_OUT_GOOD;
+               break;
        }
        case IPPROTO_IPIP:
                proto = htons(ETH_P_IP);
 
                key_control->flags |= FLOW_DIS_ENCAPSULATION;
-               if (flags & FLOW_DISSECTOR_F_STOP_AT_ENCAP)
-                       goto out_good;
+               if (flags & FLOW_DISSECTOR_F_STOP_AT_ENCAP) {
+                       fdret = FLOW_DISSECT_RET_OUT_GOOD;
+                       break;
+               }
+
+               fdret = FLOW_DISSECT_RET_PROTO_AGAIN;
+               break;
 
-               goto ip;
        case IPPROTO_IPV6:
                proto = htons(ETH_P_IPV6);
 
                key_control->flags |= FLOW_DIS_ENCAPSULATION;
-               if (flags & FLOW_DISSECTOR_F_STOP_AT_ENCAP)
-                       goto out_good;
+               if (flags & FLOW_DISSECTOR_F_STOP_AT_ENCAP) {
+                       fdret = FLOW_DISSECT_RET_OUT_GOOD;
+                       break;
+               }
+
+               fdret = FLOW_DISSECT_RET_PROTO_AGAIN;
+               break;
+
 
-               goto ipv6;
        case IPPROTO_MPLS:
                proto = htons(ETH_P_MPLS_UC);
-               goto mpls;
+               fdret = FLOW_DISSECT_RET_PROTO_AGAIN;
+               break;
+
        case IPPROTO_TCP:
                __skb_flow_dissect_tcp(skb, flow_dissector, target_container,
                                       data, nhoff, hlen);
                break;
+
        default:
                break;
        }
                key_icmp->icmp = skb_flow_get_be16(skb, nhoff, data, hlen);
        }
 
+       /* Process result of IP proto processing */
+       switch (fdret) {
+       case FLOW_DISSECT_RET_PROTO_AGAIN:
+               goto proto_again;
+       case FLOW_DISSECT_RET_IPPROTO_AGAIN:
+               goto ip_proto_again;
+       case FLOW_DISSECT_RET_OUT_GOOD:
+       case FLOW_DISSECT_RET_CONTINUE:
+               break;
+       case FLOW_DISSECT_RET_OUT_BAD:
+       default:
+               goto out_bad;
+       }
+
 out_good:
        ret = true;