bool match_std_nonstrict(struct ofl_match_standard *a, struct ofl_match_standard *b) { return nonstrict_wild32(a->in_port, b->in_port, a->wildcards, b->wildcards, OFPFW_IN_PORT) && nonstrict_dladdr(a->dl_src, b->dl_src, a->dl_src_mask, b->dl_src_mask) && nonstrict_dladdr(a->dl_dst, b->dl_dst, a->dl_dst_mask, b->dl_dst_mask) && nonstrict_dlvlan(a->dl_vlan, b->dl_vlan, a->wildcards, b->wildcards) && nonstrict_dlvpcp(a->dl_vlan, a->dl_vlan_pcp, b->dl_vlan, b->dl_vlan_pcp, a->wildcards, b->wildcards) && nonstrict_wild16(a->dl_type, b->dl_type, a->wildcards, b->wildcards, OFPFW_DL_TYPE) && nonstrict_wild8 (a->nw_tos, b->nw_tos, a->wildcards, b->wildcards, OFPFW_NW_TOS) && nonstrict_wild8 (a->nw_proto, b->nw_proto, a->wildcards, b->wildcards, OFPFW_NW_PROTO) && nonstrict_mask32(a->nw_src, b->nw_src, a->nw_src_mask, b->nw_src_mask) && nonstrict_mask32(a->nw_dst, b->nw_dst, a->nw_dst_mask, b->nw_dst_mask) && nonstrict_wild16(a->tp_src, b->tp_src, a->wildcards, b->wildcards, OFPFW_TP_SRC) && nonstrict_wild16(a->tp_dst, b->tp_dst, a->wildcards, b->wildcards, OFPFW_TP_DST) && nonstrict_wild32(a->mpls_label, b->mpls_label, a->wildcards, b->wildcards, OFPFW_MPLS_LABEL) && nonstrict_wild8 (a->mpls_tc, b->mpls_tc, a->wildcards, b->wildcards, OFPFW_MPLS_TC) && nonstrict_mask64(a->metadata, b->metadata, a->metadata_mask, b->metadata_mask); }
/* Flow entry (a) matches flow entry (b) non-strictly if (a) matches whenever (b) matches. * Thus, flow (a) must not have more match fields than (b) and all match fields in (a) must * be equal or narrower in (b). * NOTE: Handling of bitmasked fields is not specified. In this implementation * a masked field of (a) matches the field of (b) if all masked bits of (b) are * also masked in (a), and for each unmasked bits of (b) , the bit is either * masked in (a), or is set to the same value in both matches. * */ bool match_std_nonstrict(struct ofl_match *a, struct ofl_match *b, struct ofl_exp *exp) { struct ofl_match_tlv *flow_mod_match; struct ofl_match_tlv *flow_entry_match; int field_len; uint8_t *flow_mod_val, *flow_mod_mask=0; uint8_t *flow_entry_val, *flow_entry_mask=0; bool has_mask; /* Flow a is fully wildcarded */ if (!a->header.length) return true; /* Loop through the match fields in flow entry a */ HMAP_FOR_EACH(flow_mod_match, struct ofl_match_tlv, hmap_node, &a->match_fields) { /* Check presence of match field in flow entry */ flow_entry_match = oxm_match_lookup(flow_mod_match->header, b); if (!flow_entry_match) { return false; } /* At this point match length and has_mask are equal */ has_mask = OXM_HASMASK(flow_mod_match->header); flow_mod_val = flow_mod_match->value; flow_entry_val = flow_entry_match->value; switch (OXM_VENDOR(flow_mod_match->header)) { case (OFPXMC_OPENFLOW_BASIC): field_len = OXM_LENGTH(flow_mod_match->header); if (has_mask) { field_len /= 2; flow_mod_mask = flow_mod_match->value + field_len; flow_entry_mask = flow_entry_match->value + field_len; } break; case (OFPXMC_EXPERIMENTER): if (exp == NULL || exp->field == NULL || exp->field->match_std == NULL) { VLOG_WARN(LOG_MODULE,"Received match is experimental, but no callback was given."); ofl_error(OFPET_BAD_MATCH, OFPBMC_BAD_TYPE); } exp->field->match_std(flow_mod_match, flow_entry_match, &field_len, &flow_mod_val, &flow_entry_val, &flow_mod_mask, &flow_entry_mask); break; default: break; } switch (field_len) { case 1: if (has_mask) { if (!nonstrict_mask8(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) return false; } else { if (!match_8(flow_mod_val, flow_entry_val)) return false; } break; case 2: if (has_mask) { if (!nonstrict_mask16(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) return false; } else { if (!match_16(flow_mod_val, flow_entry_val)) return false; } break; case 3: if (has_mask) { if (!nonstrict_mask24(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) return false; } else { if (!match_24(flow_mod_val, flow_entry_val)) return false; } break; case 4: if (has_mask) { if (!nonstrict_mask32(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) return false; } else { if (!match_32(flow_mod_val, flow_entry_val)) return false; } break; case 6: if (has_mask) { if (!nonstrict_mask48(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) return false; } else { if (!match_48(flow_mod_val, flow_entry_val)) return false; } break; case 8: if (has_mask) { if (!nonstrict_mask64(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) return false; } else { if (!match_64(flow_mod_val, flow_entry_val)) return false; } break; case 16: if (has_mask) { if (!nonstrict_mask128(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) return false; } else { if (!match_128(flow_mod_val, flow_entry_val)) return false; } break; default: /* Should never happen */ break; } /* switch (field_len) */ } /* HMAP_FOR_EACH */ /* If we get here, all match fields in flow a were equal or wider than the ones in b */ /* It doesn't matter if there are further fields in b */ return true; }
static inline bool nonstrict_mask48(uint8_t *a, uint8_t *b, uint8_t *am, uint8_t *bm) { return nonstrict_mask32(a, b, am, bm) && nonstrict_mask16(a+4, b+4, am+4, bm+4); }
bool match_std_nonstrict(struct ofl_match *a, struct ofl_match *b) { struct ofl_match_tlv *flow_mod_match; struct ofl_match_tlv *flow_entry_match; bool ret = false; /*Matches all flows */ if(!a->header.length ) return true; /* Loop through the match fields */ HMAP_FOR_EACH(flow_mod_match, struct ofl_match_tlv, hmap_node, &a->match_fields){ /* Check if the field is present in the flow entry */ HMAP_FOR_EACH_WITH_HASH(flow_entry_match, struct ofl_match_tlv, hmap_node, hash_int(flow_mod_match->header, 0), &b->match_fields){ int field_len = OXM_LENGTH(flow_mod_match->header); bool has_mask; /* Check if both fields have or not a mask */ if ( (OXM_HASMASK(flow_mod_match->header) && !OXM_HASMASK(flow_entry_match->header)) || (!OXM_HASMASK(flow_mod_match->header) && OXM_HASMASK(flow_entry_match->header))){ return false; } ret = true; has_mask = OXM_HASMASK(flow_mod_match->header); switch (field_len){ case (sizeof(uint8_t)):{ if (has_mask){ if (nonstrict_mask8(flow_mod_match->value, flow_entry_match->value + field_len, flow_entry_match->value,flow_entry_match->value + field_len) == 0){ return false; } } else if (matches_8(flow_mod_match->value, flow_entry_match->value) == 0){ return false; } break; } case (sizeof(uint16_t)):{ if (has_mask){ if (nonstrict_mask16(flow_mod_match->value,flow_entry_match->value + field_len, flow_entry_match->value,flow_entry_match->value + field_len) == 0){ return false; } } else if (matches_16(flow_mod_match->value, flow_entry_match->value) == 0){ return false; } break; } case (sizeof(uint32_t)):{ if (has_mask){ if (nonstrict_mask32(flow_mod_match->value,flow_entry_match->value + field_len, flow_entry_match->value,flow_entry_match->value + field_len) ){ return false; } } else if (matches_32(flow_mod_match->value, flow_entry_match->value) == 0){ return false; } break; } case (ETH_ADDR_LEN):{ if (has_mask){ if (nonstrict_ethaddr(flow_mod_match->value,flow_entry_match->value + field_len, flow_entry_match->value,flow_entry_match->value + field_len) == 0){ return false; } } else if (eth_match(flow_mod_match->value, flow_entry_match->value) == 0){ return false; } break; } case (sizeof(uint64_t)):{ if (has_mask) { if (nonstrict_mask64(flow_mod_match->value,flow_entry_match->value + field_len, flow_entry_match->value,flow_entry_match->value + field_len) == 0){ return false; } } else if (matches_64(flow_mod_match->value, flow_entry_match->value) == 0){ return false; } break; } case (16):{ if (has_mask){ if (nonstrict_ipv6(flow_mod_match->value,flow_entry_match->value + field_len, flow_entry_match->value,flow_entry_match->value + field_len)== 0){ return false; } } else if (ipv6_match(flow_mod_match->value, flow_entry_match->value) == 0){ return false; } break; } } } if (!ret) return ret; else ret = false; } return true; }
static inline bool nonstrict_ethaddr(uint8_t *a, uint8_t *b, uint8_t *am, uint8_t *bm) { return nonstrict_mask32(a, b, am, bm) && nonstrict_mask16(a, b, am, bm); }
/* Flow entry (a) matches flow entry (b) non-strictly if (a) matches whenever (b) matches. * Thus, flow (a) must not have more match fields than (b) and all match fields in (a) must * be equal or narrower in (b). * NOTE: Handling of bitmasked fields is not specified. In this implementation * a masked field of (a) matches the field of (b) if all masked bits of (b) are * also masked in (a), and for each unmasked bits of (b) , the bit is either * masked in (a), or is set to the same value in both matches. * */ bool match_std_nonstrict(struct ofl_match *a, struct ofl_match *b) { struct ofl_match_tlv *flow_mod_match; struct ofl_match_tlv *flow_entry_match; int field_len; uint8_t *flow_mod_val, *flow_mod_mask=0; uint8_t *flow_entry_val, *flow_entry_mask=0; bool has_mask; /* Flow a is fully wildcarded */ if (!a->header.length) return true; /* Loop through the match fields in flow entry a */ HMAP_FOR_EACH(flow_mod_match, struct ofl_match_tlv, hmap_node, &a->match_fields) { /* Check presence of match field in flow entry */ flow_entry_match = oxm_match_lookup(flow_mod_match->header, b); if (!flow_entry_match) { return false; } /* At this point match length and has_mask are equal */ has_mask = OXM_HASMASK(flow_mod_match->header); field_len = OXM_LENGTH(flow_mod_match->header); flow_mod_val = flow_mod_match->value; flow_entry_val = flow_entry_match->value; if (has_mask) { field_len /= 2; flow_mod_mask = flow_mod_match->value + field_len; flow_entry_mask = flow_entry_match->value + field_len; } switch (field_len) { case 1: if (has_mask) { if (!nonstrict_mask8(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) return false; } else { if (!match_8(flow_mod_val, flow_entry_val)) return false; } break; case 2: if (has_mask) { if (!nonstrict_mask16(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) return false; } else { if (!match_16(flow_mod_val, flow_entry_val)) return false; } break; case 4: if (has_mask) { if (!nonstrict_mask32(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) return false; } else { if (!match_32(flow_mod_val, flow_entry_val)) return false; } break; case 6: if (has_mask) { if (!nonstrict_mask48(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) return false; } else { if (!match_48(flow_mod_val, flow_entry_val)) return false; } break; case 8: if (has_mask) { if (!nonstrict_mask64(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) return false; } else { if (!match_64(flow_mod_val, flow_entry_val)) return false; } break; case 16: if (has_mask) { if (!nonstrict_mask128(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) return false; } else { if (!match_128(flow_mod_val, flow_entry_val)) return false; } break; default: /* Should never happen */ break; } /* switch (field_len) */ } /* HMAP_FOR_EACH */ /* If we get here, all match fields in flow a were equal or wider than the ones in b */ /* It doesn't matter if there are further fields in b */ return true; }
static inline bool nonstrict_dladdr(uint8_t *a, uint8_t *b, uint8_t *am, uint8_t *bm) { return nonstrict_mask32(*((uint32_t *)a), *((uint32_t *)b), *((uint32_t *)am), *((uint32_t *)bm)) && nonstrict_mask16(*((uint16_t *)(a+4)), *((uint16_t *)(b+4)), *((uint16_t *)(am+4)), *((uint16_t *)(bm+4))); }