u16 l3_proto; /* protocol specified in the template */
 };
 
+/* SparX-5 VCAP fragment types:
+ * 0 = no fragment, 1 = initial fragment,
+ * 2 = suspicious fragment, 3 = valid follow-up fragment
+ */
+enum {                   /* key / mask */
+       FRAG_NOT   = 0x03, /* 0 / 3 */
+       FRAG_SOME  = 0x11, /* 1 / 1 */
+       FRAG_FIRST = 0x13, /* 1 / 3 */
+       FRAG_LATER = 0x33, /* 3 / 3 */
+       FRAG_INVAL = 0xff, /* invalid */
+};
+
+/* Flower fragment flag to VCAP fragment type mapping */
+static const u8 sparx5_vcap_frag_map[4][4] = {           /* is_frag */
+       { FRAG_INVAL, FRAG_INVAL, FRAG_INVAL, FRAG_FIRST }, /* 0/0 */
+       { FRAG_NOT,   FRAG_NOT,   FRAG_INVAL, FRAG_INVAL }, /* 0/1 */
+       { FRAG_INVAL, FRAG_INVAL, FRAG_INVAL, FRAG_INVAL }, /* 1/0 */
+       { FRAG_SOME,  FRAG_LATER, FRAG_INVAL, FRAG_FIRST }  /* 1/1 */
+       /* 0/0        0/1         1/0         1/1 <-- first_frag */
+};
+
 static int
 sparx5_tc_flower_es0_tpid(struct vcap_tc_flower_parse_usage *st)
 {
        flow_rule_match_control(st->frule, &mt);
 
        if (mt.mask->flags) {
-               if (mt.mask->flags & FLOW_DIS_FIRST_FRAG) {
-                       if (mt.key->flags & FLOW_DIS_FIRST_FRAG) {
-                               value = 1; /* initial fragment */
-                               mask = 0x3;
-                       } else {
-                               if (mt.mask->flags & FLOW_DIS_IS_FRAGMENT) {
-                                       value = 3; /* follow up fragment */
-                                       mask = 0x3;
-                               } else {
-                                       value = 0; /* no fragment */
-                                       mask = 0x3;
-                               }
-                       }
-               } else {
-                       if (mt.mask->flags & FLOW_DIS_IS_FRAGMENT) {
-                               value = 3; /* follow up fragment */
-                               mask = 0x3;
-                       } else {
-                               value = 0; /* no fragment */
-                               mask = 0x3;
-                       }
+               u8 is_frag_key = !!(mt.key->flags & FLOW_DIS_IS_FRAGMENT);
+               u8 is_frag_mask = !!(mt.mask->flags & FLOW_DIS_IS_FRAGMENT);
+               u8 is_frag_idx = (is_frag_key << 1) | is_frag_mask;
+
+               u8 first_frag_key = !!(mt.key->flags & FLOW_DIS_FIRST_FRAG);
+               u8 first_frag_mask = !!(mt.mask->flags & FLOW_DIS_FIRST_FRAG);
+               u8 first_frag_idx = (first_frag_key << 1) | first_frag_mask;
+
+               /* Lookup verdict based on the 2 + 2 input bits */
+               u8 vdt = sparx5_vcap_frag_map[is_frag_idx][first_frag_idx];
+
+               if (vdt == FRAG_INVAL) {
+                       NL_SET_ERR_MSG_MOD(st->fco->common.extack,
+                                          "Match on invalid fragment flag combination");
+                       return -EINVAL;
                }
 
+               /* Extract VCAP fragment key and mask from verdict */
+               value = (vdt >> 4) & 0x3;
+               mask = vdt & 0x3;
+
                err = vcap_rule_add_key_u32(st->vrule,
                                            VCAP_KF_L3_FRAGMENT_TYPE,
                                            value, mask);