/* Perform name match against the schema. Result is stored in * match_type. */ void cnode_schema_match(struct cnode *schema, char *name, enum match_type *match_type) { switch (schema->type) { case CNODE_TYPE_KEYWORD: keyword_match(name, schema->name, match_type); break; case CNODE_TYPE_WORD: word_match(name, match_type); break; case CNODE_TYPE_IPV4: ipv4_match(name, match_type); break; case CNODE_TYPE_IPV4_PREFIX: ipv4_prefix_match(name, match_type); break; case CNODE_TYPE_IPV6: ipv6_match(name, match_type); break; case CNODE_TYPE_IPV6_PREFIX: ipv6_prefix_match(name, match_type); break; case CNODE_TYPE_MAC: mac_address_match(name, match_type); break; case CNODE_TYPE_RANGE: range_match(name, schema, match_type); break; default: *match_type = NONE_MATCH; break; } }
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; }
bool packet_match(struct ofl_match *flow_match, struct ofl_match *packet){ struct ofl_match_tlv *f; struct packet_fields *packet_f; bool ret = false; if (flow_match->header.length == 0){ return true; } /* Loop through the match fields */ HMAP_FOR_EACH(f, struct ofl_match_tlv, hmap_node, &flow_match->match_fields){ /* Check if the field is present in the packet */ // HMAP_FOR_EACH_WITH_HASH(packet_f, struct packet_fields, hmap_node, hash_int(f->header, 0), &packet->match_fields){ HMAP_FOR_EACH(packet_f, struct packet_fields, hmap_node, &packet->match_fields){ if (OXM_TYPE(f->header) == OXM_TYPE(packet_f->header)) { int field_len = OXM_LENGTH(f->header); bool has_mask = OXM_HASMASK(f->header); ret = true; if (has_mask) { field_len = field_len/2; } switch (field_len){ case (sizeof(uint8_t)):{ if (has_mask){ if (pkt_mask8(f->value,f->value + field_len, packet_f->value) == 0){ return false; } } else if (matches_8(f->value, packet_f->value) == 0){ return false; } break; } case (sizeof(uint16_t)):{ if (OXM_TYPE(f->header) == OXM_TYPE(OXM_OF_VLAN_VID)) { if (*((uint16_t*)f->value) == OFPVID_NONE) return false; // we have vlan tag when we expect none else if (*((uint16_t*)f->value) == OFPVID_PRESENT && has_mask) break; // this is the case where each vlan is a match else *((uint16_t*)f->value) &= VLAN_VID_MASK; // remove CFI bit } if (OXM_TYPE(f->header) == OXM_TYPE(OXM_OF_IPV6_EXTHDR)){ if (ipv6_eh_match(f->value, packet_f->value) == 0) { return false; } } else if (has_mask){ if (pkt_mask16(f->value,f->value+ field_len, packet_f->value) == 0){ return false; } } else { if (pkt_match_16(f->value, packet_f->value) == 0){ return false; } } break; } case (sizeof(uint32_t)):{ if (has_mask){ if (OXM_TYPE(f->header) == OXM_TYPE(OXM_OF_IPV4_DST) || OXM_TYPE(f->header) == OXM_TYPE(OXM_OF_IPV4_SRC) || OXM_TYPE(f->header) == OXM_TYPE(OXM_OF_ARP_SPA) || OXM_TYPE(f->header) == OXM_TYPE(OXM_OF_ARP_TPA)){ if (matches_mask32(f->value,f->value + field_len, packet_f->value) == 0){ return false; } } else if (pkt_mask32(f->value,f->value + field_len, packet_f->value) == 0){ return false; } } else if (OXM_TYPE(f->header) == OXM_TYPE(OXM_OF_IPV4_DST) || OXM_TYPE(f->header) == OXM_TYPE(OXM_OF_IPV4_SRC) ||OXM_TYPE(f->header) == OXM_TYPE(OXM_OF_ARP_SPA) || OXM_TYPE(f->header) == OXM_TYPE(OXM_OF_ARP_TPA)){ if (matches_32(f->value, packet_f->value) == 0){ return false; } } else { if (pkt_match_32(f->value, packet_f->value) == 0){ return false; } } break; } case (ETH_ADDR_LEN):{ if (has_mask){ if (eth_mask(f->value,f->value + field_len, packet_f->value) == 0){ return false; } } else if (eth_match(f->value, packet_f->value) == 0){ return false; } break; } case (sizeof(uint64_t)):{ if (has_mask) { if (pkt_mask64(f->value,f->value + field_len, packet_f->value) == 0){ return false; } } else if (matches_64(f->value, packet_f->value) == 0){ return false; } break; } case (16):{ if (has_mask){ if (ipv6_mask(f->value,f->value + field_len, packet_f->value) == 0){ return false; } } else if (ipv6_match(f->value, packet_f->value) == 0){ return false; } break; } } // end of switch case } // end of if (OXM_TYPE(f->header) == OXM_TYPE(packet_f->header)) } // end of packet_match loop if (OXM_TYPE(f->header) == OXM_TYPE(OXM_OF_VLAN_VID)) if (*((uint16_t*)f->value) == OFPVID_NONE) ret = true; // in case the packet has no vlan and this is what was expected if (!ret) return ret; else ret = false; } // end of flow_match loop return true; }
bool packet_match(struct ofl_match *flow_match, struct ofl_match *packet){ struct ofl_match_tlv *f; struct packet_fields *packet_f; bool ret = false; if (flow_match->header.length == 0){ return true; } /*TODO: Possible combinations of VLAN_ID and masks */ HMAP_FOR_EACH_WITH_HASH(f, struct ofl_match_tlv, hmap_node,hash_int(OXM_OF_VLAN_VID, 0), &flow_match->match_fields){ uint16_t *matchv = (uint16_t*) f->value; /* Check if the field is present in the packet */ HMAP_FOR_EACH_WITH_HASH(packet_f, struct packet_fields, hmap_node, hash_int(OXM_OF_VLAN_VID, 0), &packet->match_fields){ /* Do not match packets with a VLAN Tag */ if (*matchv == OFPVID_NONE && !OXM_HASMASK(f->header)) return false; ret = true; } if ((*matchv == OFPVID_PRESENT) & (OXM_HASMASK(f->header))){ uint16_t *maskv = (uint16_t*) f->value + 2; if (*maskv == OFPVID_PRESENT && !ret ) return false; } } /* Loop through the match fields */ HMAP_FOR_EACH(f, struct ofl_match_tlv, hmap_node, &flow_match->match_fields){ /* Check if the field is present in the packet */ HMAP_FOR_EACH_WITH_HASH(packet_f, struct packet_fields, hmap_node, hash_int(f->header, 0), &packet->match_fields){ int field_len = OXM_LENGTH(f->header); bool has_mask = OXM_HASMASK(f->header); ret = true; switch (field_len){ case (sizeof(uint8_t)):{ if (has_mask){ if (pkt_mask8(f->value,f->value + field_len, packet_f->value) == 0){ return false; } } else if (matches_8(f->value, packet_f->value) == 0){ return false; } break; } case (sizeof(uint16_t)):{ if (has_mask){ if (pkt_mask16(f->value,f->value+ field_len, packet_f->value) == 0){ return false; } } else { if (pkt_match_16(f->value, packet_f->value) == 0){ return false; } } break; } case (sizeof(uint32_t)):{ if (has_mask){ if (f->header == OXM_OF_IPV4_DST || f->header == OXM_OF_IPV4_SRC ||f->header == OXM_OF_ARP_SPA || f->header == OXM_OF_ARP_TPA){ if (matches_mask32(f->value,f->value + field_len, packet_f->value) == 0){ return false; } } else if (pkt_mask32(f->value,f->value + field_len, packet_f->value) == 0){ return false; } } else if (f->header == OXM_OF_IPV4_DST || f->header == OXM_OF_IPV4_SRC ||f->header == OXM_OF_ARP_SPA || f->header == OXM_OF_ARP_TPA){ if (matches_32(f->value, packet_f->value) == 0){ return false; } } else if (pkt_match_32(f->value, packet_f->value) == 0){ return false; } break; } case (ETH_ADDR_LEN):{ if (has_mask){ if (eth_mask(f->value,f->value + field_len, packet_f->value) == 0){ return false; } } else if (eth_match(f->value, packet_f->value) == 0){ return false; } break; } case (sizeof(uint64_t)):{ if (has_mask) { if (pkt_mask64(f->value,f->value + field_len, packet_f->value) == 0){ return false; } } else if (matches_64(f->value, packet_f->value) == 0){ return false; } break; } case (16):{ if (has_mask){ if (ipv6_mask(f->value,f->value + field_len, packet_f->value) == 0){ return false; } } else if (ipv6_match(f->value, packet_f->value) == 0){ return false; } break; } } } if (!ret) return ret; else ret = false; } return true; }
struct cnode * cnode_match(struct cnode *cnode, char *name) { uint32_t i; struct cnode *child; enum match_type type; if (cnode == NULL) { return NULL; } for (i = 0; i < vector_max(cnode->v); i++) { if ((child = vector_slot(cnode->v, i)) != NULL) { switch (child->type) { case CNODE_TYPE_KEYWORD: if (strcmp(child->name, name) == 0) { return child; } break; case CNODE_TYPE_WORD: return child; break; case CNODE_TYPE_IPV4: ipv4_match(name, &type); if (type == IPV4_MATCH) { return child; } break; case CNODE_TYPE_IPV4_PREFIX: ipv4_prefix_match(name, &type); if (type == IPV4_PREFIX_MATCH) { return child; } break; case CNODE_TYPE_IPV6: ipv6_match(name, &type); if (type == IPV6_MATCH) { return child; } break; case CNODE_TYPE_IPV6_PREFIX: ipv6_prefix_match(name, &type); if (type == IPV6_PREFIX_MATCH) { return child; } break; case CNODE_TYPE_MAC: mac_address_match(name, &type); if (type == MAC_ADDRESS_MATCH) { return child; } break; case CNODE_TYPE_RANGE: range_match(name, child, &type); if (type == RANGE_MATCH) { return child; } break; default: break; } } } return NULL; }