/* Returns true if the fields in *packet matches the flow entry in *flow_match */ bool packet_match(struct ofl_match *flow_match, struct ofl_match *packet, struct ofl_exp *exp){ struct ofl_match_tlv *f; struct ofl_match_tlv *packet_f; bool has_mask; int field_len; int packet_header; uint8_t *flow_val, *flow_mask= NULL; uint8_t *packet_val; if (flow_match->header.length == 0) return true; /* Loop over the flow entry's match fields */ HMAP_FOR_EACH(f, struct ofl_match_tlv, hmap_node, &flow_match->match_fields) { /* Check presence of match field in packet */ has_mask = OXM_HASMASK(f->header); packet_header = f->header; switch (OXM_VENDOR(f->header)) { case(OFPXMC_OPENFLOW_BASIC): field_len = OXM_LENGTH(f->header); flow_val = f->value; if (has_mask) { /* Clear the has_mask bit and divide the field_len by two in the packet field header */ field_len /= 2; packet_header &= 0xfffffe00; packet_header |= field_len; flow_mask = f->value + field_len; } break; case(OFPXMC_EXPERIMENTER): if (exp == NULL || exp->field == NULL || exp->field->match == 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(f, &packet_header, &field_len, &flow_val, &flow_mask); break; default: break; } /* Lookup the packet header */ packet_f = oxm_match_lookup(packet_header, packet); if (!packet_f) { if (f->header==OXM_OF_VLAN_VID && *((uint16_t *) f->value)==OFPVID_NONE) { /* There is no VLAN tag, as required */ continue; } return false; } /* Compare the flow and packet field values, considering the mask, if any */ switch (OXM_VENDOR(f->header)) { case(OFPXMC_OPENFLOW_BASIC): packet_val = packet_f->value; break; case(OFPXMC_EXPERIMENTER): if (exp == NULL || exp->field == NULL || exp->field->compare == NULL) { VLOG_WARN(LOG_MODULE,"Received match is experimental, but no callback was given."); ofl_error(OFPET_BAD_MATCH, OFPBMC_BAD_TYPE); } exp->field->compare(f, packet_f, &packet_val); break; default: break; } switch (field_len) { case 1: if (has_mask) { if (!match_mask8(flow_val, flow_mask, packet_val)) return false; } else { if (!match_8(flow_val, packet_val)) return false; } break; case 2: switch (packet_header) { case OXM_OF_VLAN_VID: { /* Special handling for VLAN ID */ uint16_t flow_vlan_id = *((uint16_t*) flow_val); if (flow_vlan_id == OFPVID_NONE) { /* Packet has a VLAN tag when none should be there */ return false; } else if (flow_vlan_id == OFPVID_PRESENT) { /* Any VLAN ID is acceptable. No further checks */ } else { /* Check the VLAN ID */ flow_vlan_id &= VLAN_VID_MASK; if (has_mask){ if (!match_mask16((uint8_t*) &flow_vlan_id, flow_mask, packet_val)){ return false; } } else { if (!match_16((uint8_t*) &flow_vlan_id, packet_val)){ return false; } } } break; } case OXM_OF_IPV6_EXTHDR: { /* Special handling for IPv6 Extension header */ uint16_t flow_eh = *((uint16_t *) flow_val); uint16_t packet_eh = *((uint16_t *) packet_val); if ((flow_eh & packet_eh) != flow_eh) { /* The packet doesn't have all extension headers specified in the flow */ return false; } break; } default: if (has_mask) { if (!match_mask16(flow_val, flow_mask, packet_val)) return false; } else { if (!match_16(flow_val, packet_val)) return false; } break; } break; case 3: if (has_mask) { if (!match_mask24(flow_val, flow_mask, packet_val)) return false; } else { if (!match_24(flow_val, packet_val)) return false; } break; case 4: if (has_mask) { if (!match_mask32(flow_val, flow_mask, packet_val)) return false; } else { if (!match_32(flow_val, packet_val)) return false; } break; case 6: if (has_mask) { if (!match_mask48(flow_val, flow_mask, packet_val)) return false; } else { if (!match_48(flow_val, packet_val)) return false; } break; case 8: if (has_mask) { if (!match_mask64(flow_val, flow_mask, packet_val)) return false; } else { if (!match_64(flow_val, packet_val)) return false; } break; case 16: if (has_mask) { if (!match_mask128(flow_val, flow_mask, packet_val)) return false; } else { if (!match_128(flow_val, packet_val)) return false; } break; default: /* Should never happen */ break; } } /* If we get here, all match fields in the flow entry matched the packet */ return true; }
/* Returns true if the fields in *packet matches the flow entry in *flow_match */ bool packet_match(struct ofl_match *flow_match, struct ofl_match *packet) { struct ofl_match_tlv *f; struct ofl_match_tlv *packet_f; bool has_mask; int field_len; int packet_header; uint8_t *flow_val, *flow_mask=0; uint8_t *packet_val; if (flow_match->header.length == 0) { return true; } /* Loop over the flow entry's match fields */ HMAP_FOR_EACH(f, struct ofl_match_tlv, hmap_node, &flow_match->match_fields) { /* Check presence of match field in packet */ has_mask = OXM_HASMASK(f->header); field_len = OXM_LENGTH(f->header); packet_header = f->header; flow_val = f->value; if (has_mask) { /* Clear the has_mask bit and divide the field_len by two in the packet field header */ field_len /= 2; packet_header &= 0xfffffe00; packet_header |= field_len; flow_mask = f->value + field_len; } char *f_str = ofl_structs_oxm_tlv_to_string(f); free(f_str); /* Lookup the packet header */ packet_f = oxm_match_lookup(packet_header, packet); if (!packet_f) { if (f->header==OXM_OF_VLAN_VID && *((uint16_t *) f->value)==OFPVID_NONE) { /* There is no VLAN tag, as required */ continue; } return false; } /* Compare the flow and packet field values, considering the mask, if any */ packet_val = packet_f->value; switch (field_len) { case 1: if (has_mask) { if (!match_mask8(flow_val, flow_mask, packet_val)) return false; } else { if (!match_8(flow_val, packet_val)) return false; } break; case 2: switch (packet_header) { case OXM_OF_VLAN_VID: { /* Special handling for VLAN ID */ uint16_t flow_vlan_id = *((uint16_t *) flow_val); if (flow_vlan_id == OFPVID_NONE) { /* Packet has a VLAN tag when none should be there */ return false; } else if (flow_vlan_id == OFPVID_PRESENT) { /* Any VLAN ID is acceptable. No further checks */ } else { /* Check the VLAN ID */ if (!match_16(flow_val, packet_val)) return false; } break; } case OXM_OF_IPV6_EXTHDR: { /* Special handling for IPv6 Extension header */ uint16_t flow_eh = *((uint16_t *) flow_val); uint16_t packet_eh = *((uint16_t *) packet_val); if ((flow_eh & packet_eh) != flow_eh) { /* The packet doesn't have all extension headers specified in the flow */ return false; } break; } default: if (has_mask) { if (!match_mask16(flow_val, flow_mask, packet_val)) return false; } else { if (!match_16(flow_val, packet_val)) return false; } break; } break; case 4: if (has_mask) { if (!match_mask32(flow_val, flow_mask, packet_val)) return false; } else { if (!match_32(flow_val, packet_val)) return false; } break; case 6: if (has_mask) { if (!match_mask48(flow_val, flow_mask, packet_val)) return false; } else { if (!match_48(flow_val, packet_val)) return false; } break; case 8: if (has_mask) { if (!match_mask64(flow_val, flow_mask, packet_val)) return false; } else { if (!match_64(flow_val, packet_val)) return false; } break; case 16: if (has_mask) { if (!match_mask128(flow_val, flow_mask, packet_val)) return false; } else { if (!match_128(flow_val, packet_val)) return false; } break; default: /* Should never happen */ break; } } /* If we get here, all match fields in the flow entry matched the packet */ return true; }