static bool append_oxm_match_ipv6_addr( oxm_matches *matches, oxm_match_header header, struct in6_addr addr, struct in6_addr mask ) { assert( matches != NULL ); uint8_t length = OXM_LENGTH( header ); oxm_match_header *buf = xmalloc( sizeof( oxm_match_header ) + length ); *buf = header; void *p = ( char * ) buf + sizeof( oxm_match_header ); memcpy( p, &addr, sizeof( struct in6_addr ) ); if ( OXM_HASMASK( header ) ) { p = ( char * ) p + sizeof( struct in6_addr ); memcpy( p, &mask, sizeof( struct in6_addr ) ); } return append_oxm_match( matches, buf ); }
/* Two flow matches overlap if there exists a packet which both match structures match on. * Conversely, two flow matches do not overlap if they share at least one match field with * incompatible value/mask fields that can't match any packet. */ bool match_std_overlap(struct ofl_match *a, struct ofl_match *b, struct ofl_exp *exp) { uint64_t all_mask[2] = {~0L, ~0L}; struct ofl_match_tlv *f_a; struct ofl_match_tlv *f_b; int header, header_m; int field_len; uint8_t *val_a, *mask_a; uint8_t *val_b, *mask_b; /* Loop through the match fields in flow entry a */ HMAP_FOR_EACH(f_a, struct ofl_match_tlv, hmap_node, &a->match_fields) { val_a = f_a->value; switch (OXM_VENDOR(f_a->header)) { case (OFPXMC_OPENFLOW_BASIC): field_len = OXM_LENGTH(f_a->header); if (OXM_HASMASK(f_a->header)) { field_len /= 2; header = (f_a->header & 0xfffffe00) | field_len; header_m = f_a->header; mask_a = f_a->value + field_len; } else { header = f_a->header; header_m = (f_a->header & 0xfffffe00) | 0x100 | (field_len << 1); /* Set a dummy mask with all bits set to 0 (valid) */ mask_a = (uint8_t *) all_mask; } break; case (OFPXMC_EXPERIMENTER): if (exp == NULL || exp->field == NULL || exp->field->overlap_a == NULL) { VLOG_WARN(LOG_MODULE,"Received match is experimental, but no callback was given."); ofl_error(OFPET_BAD_MATCH, OFPBMC_BAD_TYPE); } exp->field->overlap_a(f_a, &field_len, &val_a, &mask_a, &header, &header_m, all_mask); break; default: break; } /*switch class*/ /* Check presence of corresponding match field in flow entry b * Need to check for both masked and non-masked field */ f_b = oxm_match_lookup(header, b); if (!f_b) f_b = oxm_match_lookup(header_m, b); if (f_b) { switch (OXM_VENDOR(f_b->header)) { case (OFPXMC_OPENFLOW_BASIC): val_b = f_b->value; if (OXM_HASMASK(f_b->header)) { mask_b = f_b->value + field_len; } else { /* Set a dummy mask with all bits set to 0 (valid) */ mask_b = (uint8_t *) all_mask; } break; case (OFPXMC_EXPERIMENTER): if (exp == NULL || exp->field == NULL || exp->field->overlap_b == NULL) { VLOG_WARN(LOG_MODULE,"Received match is experimental, but no callback was given."); ofl_error(OFPET_BAD_MATCH, OFPBMC_BAD_TYPE); } exp->field->overlap_b(f_b, &field_len, &val_b, &mask_b, all_mask); break; default: break; } /*switch class*/ switch (field_len) { case 1: if (incompatible_8(val_a, val_b, mask_a, mask_b)) { return false; } break; case 2: if (incompatible_16(val_a, val_b, mask_a, mask_b)) { return false; } break; case 4: if (incompatible_32(val_a, val_b, mask_a, mask_b)) { return false; } break; case 6: if (incompatible_48(val_a, val_b, mask_a, mask_b)) { return false; } break; case 8: if (incompatible_64(val_a, val_b, mask_a, mask_b)) { return false; } break; case 16: if (incompatible_128(val_a, val_b, mask_a, mask_b)) { return false; } break; default: /* Should never happen */ break; } /* switch (field_len) */ } /* if (f_b) */ } /* HMAP_FOR_EACH */ /* If we get here, none of the common match fields in a and b were found incompatible. * The flow entries overlap */ return true; }
/* 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; }
/* Two matches strictly match if their wildcard fields are the same, and all the * non-wildcarded fields match on the same exact values. * NOTE: Handling of bitmasked fields is not specified. In this implementation * masked fields are checked for equality, and only unmasked bits are compared * in the field. */ bool match_std_strict(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; uint8_t oxm_field; bool has_mask; /* Both matches all wildcarded */ if(!a->header.length && !b->header.length ) return true; /* If the matches differ in length, there is no reason to compare */ if (a->header.length != b->header.length) return false; /* Loop through the flow_mod match fields */ 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 */ oxm_field = OXM_FIELD(flow_mod_match->header); 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_val + field_len; flow_entry_mask = flow_entry_val + 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 (!strict_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 (!strict_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 (!strict_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) { /* Quick and dirty fix for IP addresses matching TODO: Matching needs a huge refactoring */ if (oxm_field == OFPXMT_OFB_IPV4_SRC || oxm_field == OFPXMT_OFB_IPV4_DST || oxm_field == OFPXMT_OFB_ARP_SPA || oxm_field == OFPXMT_OFB_ARP_TPA) { if (!strict_mask_ip(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)){ return false; } } if (!strict_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 (!strict_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 (!strict_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 (!strict_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_mod were equal to the ones in flow entry */ /* There can't be more fields in the flow entry as the lengths are the same */ 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_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; }
void ofl_structs_oxm_tlv_print(FILE *stream, struct ofl_match_tlv *f) { uint8_t field = OXM_FIELD(f->header); switch (field) { case OFPXMT_OFB_IN_PORT: fprintf(stream, "in_port=\"%d\"", *((uint32_t*) f->value)); break; case OFPXMT_OFB_IN_PHY_PORT: fprintf(stream, "in_phy_port=\"%d\"", *((uint32_t*) f->value)); break; case OFPXMT_OFB_VLAN_VID: { uint16_t v = *((uint16_t *) f->value); if (v == OFPVID_NONE) fprintf(stream, "vlan_vid= none"); else if (v == OFPVID_PRESENT && OXM_HASMASK(f->header)) fprintf(stream, "vlan_vid= any"); else fprintf(stream, "vlan_vid=\"%d\"",v & VLAN_VID_MASK); break; } case OFPXMT_OFB_VLAN_PCP: fprintf(stream, "vlan_pcp=\"%d\"", *f->value & 0x7); break; case OFPXMT_OFB_ETH_TYPE: fprintf(stream, "eth_type=\"0x%x\"", *((uint16_t *) f->value)); break; case OFPXMT_OFB_TCP_SRC: fprintf(stream, "tcp_src=\"%d\"", *((uint16_t*) f->value)); break; case OFPXMT_OFB_TCP_DST: fprintf(stream, "tcp_dst=\"%d\"", *((uint16_t*) f->value)); break; case OFPXMT_OFB_UDP_SRC: fprintf(stream, "udp_src=\"%d\"", *((uint16_t*) f->value)); break; case OFPXMT_OFB_UDP_DST: fprintf(stream, "udp_dst=\"%d\"", *((uint16_t*) f->value)); break; case OFPXMT_OFB_SCTP_SRC: fprintf(stream, "sctp_src=\"%d\"", *((uint16_t*) f->value)); break; case OFPXMT_OFB_SCTP_DST: fprintf(stream, "sctp_dst=\"%d\"", *((uint16_t*) f->value)); break; case OFPXMT_OFB_ETH_SRC: fprintf(stream, "eth_src=\""ETH_ADDR_FMT"\"", ETH_ADDR_ARGS(f->value)); if (OXM_HASMASK(f->header)) { fprintf(stream, ", eth_src_mask=\""ETH_ADDR_FMT"\"", ETH_ADDR_ARGS(f->value + 6)); } break; case OFPXMT_OFB_ETH_DST: fprintf(stream, "eth_dst=\""ETH_ADDR_FMT"\"", ETH_ADDR_ARGS(f->value)); if (OXM_HASMASK(f->header)) { fprintf(stream, ", eth_dst_mask=\""ETH_ADDR_FMT"\"", ETH_ADDR_ARGS(f->value + 6)); } break; case OFPXMT_OFB_IPV4_DST: fprintf(stream, "ipv4_dst=\""IP_FMT"\"", IP_ARGS(f->value)); if (OXM_HASMASK(f->header)) { fprintf(stream, ", ipv4_dst_mask=\""IP_FMT"\"", IP_ARGS(f->value + 4)); } break; case OFPXMT_OFB_IPV4_SRC: fprintf(stream, "ipv4_src=\""IP_FMT"\"", IP_ARGS(f->value)); if (OXM_HASMASK(f->header)) { fprintf(stream, ", ipv4_src_mask=\""IP_FMT"\"", IP_ARGS(f->value + 4)); } break; case OFPXMT_OFB_IP_PROTO: fprintf(stream, "ip_proto=\"%d\"", *f->value); break; case OFPXMT_OFB_IP_DSCP: fprintf(stream, "ip_dscp=\"%d\"", *f->value & 0x3f); break; case OFPXMT_OFB_IP_ECN: fprintf(stream, "ip_ecn=\"%d\"", *f->value & 0x3); break; case OFPXMT_OFB_ICMPV4_TYPE: fprintf(stream, "icmpv4_type= \"%d\"", *f->value); break; case OFPXMT_OFB_ICMPV4_CODE: fprintf(stream, "icmpv4_code=\"%d\"", *f->value); break; case OFPXMT_OFB_ARP_SHA: fprintf(stream, "arp_sha=\""ETH_ADDR_FMT"\"", ETH_ADDR_ARGS(f->value)); if (OXM_HASMASK(f->header)) { fprintf(stream, ", arp_sha_mask=\""ETH_ADDR_FMT"\"", ETH_ADDR_ARGS(f->value + 6)); } break; case OFPXMT_OFB_ARP_THA: fprintf(stream, "arp_tha=\""ETH_ADDR_FMT"\"", ETH_ADDR_ARGS(f->value)); if (OXM_HASMASK(f->header)) { fprintf(stream, ", arp_tha_mask=\""ETH_ADDR_FMT"\"", ETH_ADDR_ARGS(f->value + 6)); } break; case OFPXMT_OFB_ARP_SPA: fprintf(stream, "arp_spa=\""IP_FMT"\"", IP_ARGS(f->value)); if (OXM_HASMASK(f->header)) { fprintf(stream, ", arp_sha_mask=\""IP_FMT"\"", IP_ARGS(f->value + 4)); } break; case OFPXMT_OFB_ARP_TPA: fprintf(stream, "arp_tpa=\""IP_FMT"\"", IP_ARGS(f->value)); if (OXM_HASMASK(f->header)) { fprintf(stream, ", arp_tpa_mask=\""IP_FMT"\"", IP_ARGS(f->value + 4)); } break; case OFPXMT_OFB_ARP_OP: fprintf(stream, "arp_op=\"0x%x\"", *((uint16_t*) f->value)); break; case OFPXMT_OFB_IPV6_SRC: { char addr_str[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, f->value, addr_str, INET6_ADDRSTRLEN); fprintf(stream, "nw_src_ipv6=\"%s\"", addr_str); if (OXM_HASMASK(f->header)) { inet_ntop(AF_INET6, f->value + 16, addr_str, INET6_ADDRSTRLEN); fprintf(stream, ", nw_src_ipv6_mask=\"%s\"", addr_str); } break; } case OFPXMT_OFB_IPV6_DST: { char addr_str[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, f->value, addr_str, INET6_ADDRSTRLEN); fprintf(stream, "nw_dst_ipv6=\"%s\"", addr_str); if (OXM_HASMASK(f->header)) { inet_ntop(AF_INET6, f->value + 16, addr_str, INET6_ADDRSTRLEN); fprintf(stream, ", nw_dst_ipv6_mask=\"%s\"", addr_str); } break; } case OFPXMT_OFB_IPV6_ND_TARGET: { char addr_str[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, f->value, addr_str, INET6_ADDRSTRLEN); fprintf(stream, "ipv6_nd_target=\"%s\"", addr_str); break; } case OFPXMT_OFB_IPV6_ND_SLL: fprintf(stream, "ipv6_nd_sll=\""ETH_ADDR_FMT"\"", ETH_ADDR_ARGS(f->value)); break; case OFPXMT_OFB_IPV6_ND_TLL: fprintf(stream, "ipv6_nd_tll=\""ETH_ADDR_FMT"\"", ETH_ADDR_ARGS(f->value)); break; case OFPXMT_OFB_IPV6_FLABEL: fprintf(stream, "ipv6_flow_label=\"%d\"", *((uint32_t*) f->value) & 0x000fffff); if (OXM_HASMASK(f->header)) { fprintf(stream, ", ipv6_flow_label_mask=\"%d\"", *((uint32_t*) (f->value+4))); } break; case OFPXMT_OFB_ICMPV6_TYPE: fprintf(stream, "icmpv6_type=\"%d\"", *f->value); break; case OFPXMT_OFB_ICMPV6_CODE: fprintf(stream, "icmpv6_code=\"%d\"", *f->value); break; case OFPXMT_OFB_MPLS_LABEL: fprintf(stream, "mpls_label=\"%d\"",((uint32_t) *f->value) & 0x000fffff); break; case OFPXMT_OFB_MPLS_TC: fprintf(stream, "mpls_tc=\"%d\"", *f->value & 0x3); break; case OFPXMT_OFB_MPLS_BOS: fprintf(stream, "mpls_bos=\"%d\"", *f->value & 0xfe); break; case OFPXMT_OFB_METADATA: fprintf(stream, "metadata=\"0x%llx\"", *((uint64_t*) f->value)); if (OXM_HASMASK(f->header)) { fprintf(stream, ", metadata_mask=\"0x%llx\"", *((uint64_t*)(f->value+8))); } break; case OFPXMT_OFB_PBB_ISID : fprintf(stream, "pbb_isid=\"%d\"", *((uint32_t*) f->value)); if (OXM_HASMASK(f->header)) { fprintf(stream, ", pbb_isid_mask=\"%d\"", *((uint32_t*)(f->value+4))); } break; case OFPXMT_OFB_TUNNEL_ID: fprintf(stream, "tunnel_id=\"%lld\"", *((uint64_t*) f->value)); if (OXM_HASMASK(f->header)) { fprintf(stream, ", tunnel_id_mask=\"%lld\"", *((uint64_t*)(f->value+8))); } break; case OFPXMT_OFB_IPV6_EXTHDR: fprintf(stream, "ext_hdr=\""); ofl_ipv6_ext_hdr_print(stream, *((uint16_t*) f->value)); fprintf(stream, "\""); if (OXM_HASMASK(f->header)) { fprintf(stream, ", ext_hdr_mask=\"0x%x\"", *((uint16_t*)(f->value+4))); } break; default: fprintf(stream, "unknown type %d", field); } }
void print_oxm_tlv(FILE *stream, struct ofl_match_tlv *f, size_t *size){ if (f->header == OXM_OF_IN_PORT){ fprintf(stream, "in_port=%d",*((uint32_t*) f->value)); *size -= 8; if (*size > 4) fprintf(stream, ", "); } else if (f->header == OXM_OF_IN_PHY_PORT){ fprintf(stream, "in_phy_port=%d",*((uint32_t*) f->value)); *size -= 8; if (*size > 4) fprintf(stream, ", "); } else if (f->header == OXM_OF_VLAN_VID){ if ((uint16_t) *f->value == OFPVID_NONE) fprintf(stream, "vlan_vid= none"); else if ((uint16_t) *f->value == OFPVID_PRESENT) fprintf(stream, "vlan_vid= present"); else fprintf(stream, "vlan_vid= %d",*((uint16_t*) f->value)); *size -= 6; if (*size > 4) fprintf(stream, ", "); } else if (f->header == OXM_OF_VLAN_PCP){ fprintf(stream, "vlan_pcp= %d", *f->value & 0x7); *size -= 5; if (*size > 4) fprintf(stream, ", "); } else if (f->header == OXM_OF_ETH_TYPE){ uint16_t *v = (uint16_t *) f->value; fprintf(stream, "eth_type=0x"); fprintf(stream,"%x", *v); *size -= 6; if (*size > 4) fprintf(stream, ", "); } else if (f->header == OXM_OF_TCP_SRC){ fprintf(stream, "tcp_src=%d",*((uint16_t*) f->value)); *size -= 6; if (*size > 4) fprintf(stream, ", "); } else if (f->header == OXM_OF_TCP_DST){ fprintf(stream, "tcp_dst=%d",*((uint16_t*) f->value)); *size -= 6; if (*size > 4) fprintf(stream, ", "); } else if (f->header == OXM_OF_UDP_SRC){ fprintf(stream, "udp_src=%d",*((uint16_t*) f->value)); *size -= 6; if (*size > 4) fprintf(stream, ", "); } else if (f->header == OXM_OF_UDP_DST){ fprintf(stream, "udp_dst=%d",*((uint16_t*) f->value)); *size -= 6; if (*size > 4) fprintf(stream, ", "); } else if (f->header == OXM_OF_SCTP_SRC){ fprintf(stream, "sctp_src=%d",*((uint16_t*) f->value)); *size -= 6; if (*size > 4) fprintf(stream, ", "); } else if (f->header == OXM_OF_SCTP_DST){ fprintf(stream, "sctp_dst=%d",*((uint16_t*) f->value)); *size -= 6; if (*size > 4) fprintf(stream, ", "); } else if (f->header == OXM_OF_ETH_SRC || f->header == OXM_OF_ETH_SRC_W){ fprintf(stream, "eth_src=\""ETH_ADDR_FMT"\"", ETH_ADDR_ARGS(f->value)); *size -= 10; if (OXM_HASMASK(f->header)){ *size -= 6; fprintf(stream, "eth_src_mask=\""ETH_ADDR_FMT"\"", ETH_ADDR_ARGS(f->value + 6)); } if (*size > 4) fprintf(stream, ", "); } else if (f->header == OXM_OF_ETH_DST || f->header == OXM_OF_ETH_DST_W){ fprintf(stream, "eth_dst=\""ETH_ADDR_FMT"\"", ETH_ADDR_ARGS(f->value)); *size -= 10; if (OXM_HASMASK(f->header)){ *size -= 6; fprintf(stream, "eth_dst_mask=\""ETH_ADDR_FMT"\"", ETH_ADDR_ARGS(f->value + 6)); } if (*size > 4) fprintf(stream, ", "); } else if (f->header == OXM_OF_IPV4_SRC || f->header == OXM_OF_IPV4_SRC_W){ fprintf(stream, "ipv4_src=\""IP_FMT"\"",IP_ARGS(f->value)); *size -= 8; if (OXM_HASMASK(f->header)){ *size -= 4; fprintf(stream, "ipv4_src_mask=\""IP_FMT"\"",IP_ARGS(f->value + 4)); } if (*size > 4) fprintf(stream, ", "); } else if (f->header == OXM_OF_IP_PROTO){ fprintf(stream, "ip_proto= %d", *f->value); *size -= 5; if (*size > 4) fprintf(stream, ", "); } else if (f->header == OXM_OF_IP_DSCP){ fprintf(stream, "ip_dscp= %d", *f->value & 0x3f); *size -= 5; if (*size > 4) fprintf(stream, ", "); } else if (f->header == OXM_OF_IP_ECN){ fprintf(stream, "ip_ecn= %d", *f->value & 0x3); *size -= 5; if (*size > 4) fprintf(stream, ", "); } else if (f->header == OXM_OF_ICMPV4_TYPE){ fprintf(stream, "icmpv4_type= %d", *f->value); *size -= 5; if (*size > 4) fprintf(stream, ", "); } else if (f->header == OXM_OF_ICMPV4_CODE){ fprintf(stream, "icmpv4_code= %d", *f->value); *size -= 5; if (*size > 4) fprintf(stream, ", "); } else if (f->header == OXM_OF_IPV4_DST || f->header == OXM_OF_IPV4_DST_W){ fprintf(stream, "ipv4_dst=\""IP_FMT"\"",IP_ARGS(f->value)); *size -= 8; if (OXM_HASMASK(f->header)){ *size -= 4; fprintf(stream, "ipv4_dst_mask=\""IP_FMT"\"",IP_ARGS(f->value + 4)); } if (*size > 4) fprintf(stream, ", "); } else if (f->header == OXM_OF_ARP_SPA || f->header == OXM_OF_ARP_SPA_W ){ fprintf(stream, "arp_sha=\""IP_FMT"\"",IP_ARGS(f->value)); *size -= 8; if (OXM_HASMASK(f->header)){ *size -= 4; fprintf(stream, "arp_sha_mask=\""IP_FMT"\"",IP_ARGS(f->value + 4)); } if (*size > 4) fprintf(stream, ", "); } else if (f->header == OXM_OF_ARP_TPA || f->header == OXM_OF_ARP_TPA_W){ fprintf(stream, "arp_tpa=\""IP_FMT"\"",IP_ARGS(f->value)); *size -= 8; if (OXM_HASMASK(f->header)){ *size -= 4; fprintf(stream, "arp_tpa_mask=\""IP_FMT"\"",IP_ARGS(f->value + 4)); } if (*size > 4) fprintf(stream, ", "); } else if (f->header == OXM_OF_ARP_OP){ uint16_t *v = (uint16_t *) f->value; fprintf(stream, "arp_op=0x"); fprintf(stream,"%x", *v); *size -= 6; if (*size > 4) fprintf(stream, ", "); } else if (f->header == OXM_OF_IPV6_SRC || f->header == OXM_OF_IPV6_SRC_W ){ char addr_str[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, f->value, addr_str, INET6_ADDRSTRLEN); *size -= 20; fprintf(stream, "nw_src_ipv6=\"%s\"", addr_str); if (OXM_HASMASK(f->header)){ *size -= 16; inet_ntop(AF_INET6, f->value + 16, addr_str, INET6_ADDRSTRLEN); fprintf(stream, "nw_src_ipv6_mask=\"%s\"", addr_str); } if (*size > 4) fprintf(stream, ", "); } else if (f->header == OXM_OF_IPV6_DST || f->header == OXM_OF_IPV6_DST_W){ char addr_str[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, f->value, addr_str, INET6_ADDRSTRLEN); *size -= 20; fprintf(stream, "nw_dst_ipv6=\"%s\"", addr_str); if (OXM_HASMASK(f->header)){ *size -= 16; inet_ntop(AF_INET6, f->value + 16, addr_str, INET6_ADDRSTRLEN); fprintf(stream, "nw_dst_ipv6_mask=\"%s\"", addr_str); } if (*size > 4) fprintf(stream, ", "); } else if (f->header == OXM_OF_IPV6_ND_TARGET){ char addr_str[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, f->value, addr_str, INET6_ADDRSTRLEN); *size -= 20; fprintf(stream, "ipv6_nd_target=\"%s\"", addr_str); if (*size > 4) fprintf(stream, ", "); } else if (f->header == OXM_OF_IPV6_ND_SLL){ fprintf(stream, "ipv6_nd_sll=\""ETH_ADDR_FMT"\"", ETH_ADDR_ARGS(f->value)); *size -= 10; if (*size > 4) fprintf(stream, ", "); } else if (f->header == OXM_OF_IPV6_ND_TLL){ fprintf(stream, "ipv6_nd_tll=\""ETH_ADDR_FMT"\"", ETH_ADDR_ARGS(f->value)); *size -= 10; if (*size > 4) fprintf(stream, ", "); } else if (f->header == OXM_OF_IPV6_FLABEL){ uint32_t mask = 0xfffff; fprintf(stream, "ipv6_flow_label=%x",((uint32_t) *f->value) & mask ); *size -= 8; if (*size > 4) fprintf(stream, ", "); } else if (f->header == OXM_OF_ICMPV6_TYPE){ fprintf(stream, "icmpv6_type= %d", *f->value); *size -= 5; if (*size > 4) fprintf(stream, ", "); } else if (f->header == OXM_OF_ICMPV6_CODE){ fprintf(stream, "icmpv6_code= %d", *f->value); *size -= 5; if (*size > 4) fprintf(stream, ", "); } else if (f->header == OXM_OF_MPLS_LABEL){ uint32_t mask = 0xfffff; fprintf(stream, "mpls_label=%x",((uint32_t) *f->value) & mask ); *size -= 8; if (*size > 4) fprintf(stream, ", "); } else if (f->header == OXM_OF_MPLS_TC){ fprintf(stream, "mpls_tc= %d", *f->value & 0x3); *size -= 5; if (*size > 4) fprintf(stream, ", "); } else if (f->header == OXM_OF_METADATA || f->header == OXM_OF_METADATA_W){ fprintf(stream, "metadata= %lld", (uint64_t) *f->value); *size -= 12; if (OXM_HASMASK(f->header)){ fprintf(stream, "metadata_mask= %lld", (uint64_t) *(f->value + 8)); *size -= 8; } if (*size > 4) fprintf(stream, ", "); } }
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 match_std_overlap(struct ofl_match *a, struct ofl_match *b) { uint64_t all_mask[2] = {0, 0}; struct ofl_match_tlv *f_a; struct ofl_match_tlv *f_b; int header, header_m; int field_len; uint8_t *val_a, *mask_a; uint8_t *val_b, *mask_b; /* Loop through the match fields in flow entry a */ HMAP_FOR_EACH(f_a, struct ofl_match_tlv, hmap_node, &a->match_fields) { field_len = OXM_LENGTH(f_a->header); val_a = f_a->value; if (OXM_HASMASK(f_a->header)) { field_len /= 2; header = (f_a->header & 0xfffffe00) | field_len; header_m = f_a->header; mask_a = f_a->value + field_len; } else { header = f_a->header; header_m = (f_a->header & 0xfffffe00) | 0x100 | (field_len << 1); /* Set a dummy mask with all bits set to 0 (valid) */ mask_a = (uint8_t *) all_mask; } /* Check presence of corresponding match field in flow entry b * Need to check for both masked and non-masked field */ f_b = oxm_match_lookup(header, b); if (!f_b) f_b = oxm_match_lookup(header_m, b); if (f_b) { val_b = f_b->value; if (OXM_HASMASK(f_b->header)) { mask_b = f_b->value + field_len; } else { /* Set a dummy mask with all bits set to 0 (valid) */ mask_b = (uint8_t *) all_mask; } switch (field_len) { case 1: if (incompatible_8(val_a, val_b, mask_a, mask_b)) { return false; } break; case 2: if (incompatible_16(val_a, val_b, mask_a, mask_b)) { return false; } break; case 4: if (incompatible_32(val_a, val_b, mask_a, mask_b)) { return false; } break; case 6: if (incompatible_48(val_a, val_b, mask_a, mask_b)) { return false; } break; case 8: if (incompatible_64(val_a, val_b, mask_a, mask_b)) { return false; } break; case 16: if (incompatible_128(val_a, val_b, mask_a, mask_b)) { return false; } break; default: /* Should never happen */ break; } /* switch (field_len) */ } /* if (f_b) */ } /* HMAP_FOR_EACH */ /* If we get here, none of the common match fields in a and b were found incompatible. * The flow entries overlap */ return true; }
/* 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; }
/* Two matches strictly match if their wildcard fields are the same, and all the * non-wildcarded fields match on the same exact values. * NOTE: Handling of bitmasked fields is not specified. In this implementation * masked fields are checked for equality, and only unmasked bits are compared * in the field. */ bool match_std_strict(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; /* Both matches all wildcarded */ if(!a->header.length && !b->header.length ) return true; /* If the matches differ in length, there is no reason to compare */ if (a->header.length != b->header.length) return false; /* Loop through the flow_mod match fields */ 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 (!strict_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 (!strict_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 (!strict_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 (!strict_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 (!strict_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 (!strict_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_mod were equal to the ones in flow entry */ /* There can't be more fields in the flow entry as the lengths are the same */ 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; }
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; }
void print_oxm_tlv(FILE *stream, struct ofl_match_tlv *f, size_t *size){ uint8_t field = OXM_FIELD(f->header); if (field == OFPXMT_OFB_IN_PORT){ fprintf(stream, "in_port=\"%d\"",*((uint32_t*) f->value)); *size -= 8; if (*size > 4) fprintf(stream, ", "); } else if (field == OFPXMT_OFB_IN_PHY_PORT){ fprintf(stream, "in_phy_port=\"%d\"",*((uint32_t*) f->value)); *size -= 8; if (*size > 4) fprintf(stream, ", "); } else if (field == OFPXMT_OFB_VLAN_VID){ uint16_t *v = (uint16_t *) f->value; if (*v == OFPVID_NONE) fprintf(stream, "vlan_vid= none"); else if (*v == OFPVID_PRESENT && OXM_HASMASK(f->header)) fprintf(stream, "vlan_vid= any"); else fprintf(stream, "vlan_vid=\"%d\"",*v & VLAN_VID_MASK); *size -= 6; if (*size > 4) fprintf(stream, ", "); } else if (field == OFPXMT_OFB_VLAN_PCP){ fprintf(stream, "vlan_pcp=\"%d\"", *f->value & 0x7); *size -= 5; if (*size > 4) fprintf(stream, ", "); } else if (field == OFPXMT_OFB_ETH_TYPE){ uint16_t *v = (uint16_t *) f->value; fprintf(stream, "eth_type="); fprintf(stream,"\"0x%x\"", *v); *size -= 6; if (*size > 4) fprintf(stream, ", "); } else if (field == OFPXMT_OFB_TCP_SRC){ fprintf(stream, "tcp_src=\"%d\"",*((uint16_t*) f->value)); *size -= 6; if (*size > 4) fprintf(stream, ", "); } else if (field == OFPXMT_OFB_TCP_DST){ fprintf(stream, "tcp_dst=\"%d\"",*((uint16_t*) f->value)); *size -= 6; if (*size > 4) fprintf(stream, ", "); } else if (field == OFPXMT_OFB_UDP_SRC){ fprintf(stream, "udp_src=\"%d\"",*((uint16_t*) f->value)); *size -= 6; if (*size > 4) fprintf(stream, ", "); } else if (field == OFPXMT_OFB_UDP_DST){ fprintf(stream, "udp_dst=\"%d\"",*((uint16_t*) f->value)); *size -= 6; if (*size > 4) fprintf(stream, ", "); } else if (field == OFPXMT_OFB_SCTP_SRC){ fprintf(stream, "sctp_src=\"%d\"",*((uint16_t*) f->value)); *size -= 6; if (*size > 4) fprintf(stream, ", "); } else if (field == OFPXMT_OFB_SCTP_DST){ fprintf(stream, "sctp_dst=\"%d\"",*((uint16_t*) f->value)); *size -= 6; if (*size > 4) fprintf(stream, ", "); } else if (field == OFPXMT_OFB_ETH_SRC){ fprintf(stream, "eth_src=\""ETH_ADDR_FMT"\"", ETH_ADDR_ARGS(f->value)); *size -= 10; if (OXM_HASMASK(f->header)){ *size -= 6; fprintf(stream, ", eth_src_mask=\""ETH_ADDR_FMT"\"", ETH_ADDR_ARGS(f->value + 6)); } if (*size > 4) fprintf(stream, ", "); } else if (field == OFPXMT_OFB_ETH_DST){ fprintf(stream, "eth_dst=\""ETH_ADDR_FMT"\"", ETH_ADDR_ARGS(f->value)); *size -= 10; if (OXM_HASMASK(f->header)){ *size -= 6; fprintf(stream, ", eth_dst_mask=\""ETH_ADDR_FMT"\"", ETH_ADDR_ARGS(f->value + 6)); } if (*size > 4) fprintf(stream, ", "); } else if (field == OFPXMT_OFB_IPV4_DST){ fprintf(stream, "ipv4_dst=\""IP_FMT"\"",IP_ARGS(f->value)); *size -= 8; if (OXM_HASMASK(f->header)){ *size -= 4; fprintf(stream, ", ipv4_dst_mask=\""IP_FMT"\"",IP_ARGS(f->value + 4)); } if (*size > 4) fprintf(stream, ", "); } else if (field == OFPXMT_OFB_IPV4_SRC){ fprintf(stream, "ipv4_src=\""IP_FMT"\"",IP_ARGS(f->value)); *size -= 8; if (OXM_HASMASK(f->header)){ *size -= 4; fprintf(stream, ", ipv4_src_mask=\""IP_FMT"\"",IP_ARGS(f->value + 4)); } if (*size > 4) fprintf(stream, ", "); } else if (field == OFPXMT_OFB_IP_PROTO){ fprintf(stream, "ip_proto=\"%d\"", *f->value); *size -= 5; if (*size > 4) fprintf(stream, ", "); } else if (field == OFPXMT_OFB_IP_DSCP){ fprintf(stream, "ip_dscp=\"%d\"", *f->value & 0x3f); *size -= 5; if (*size > 4) fprintf(stream, ", "); } else if (field == OFPXMT_OFB_IP_ECN){ fprintf(stream, "ip_ecn=\"%d\"", *f->value & 0x3); *size -= 5; if (*size > 4) fprintf(stream, ", "); } else if (field == OFPXMT_OFB_ICMPV4_TYPE){ fprintf(stream, "icmpv4_type= \"%d\"", *f->value); *size -= 5; if (*size > 4) fprintf(stream, ", "); } else if (field == OFPXMT_OFB_ICMPV4_CODE){ fprintf(stream, "icmpv4_code=\"%d\"", *f->value); *size -= 5; if (*size > 4) fprintf(stream, ", "); } else if (field == OFPXMT_OFB_ARP_SHA){ fprintf(stream, "arp_sha=\""ETH_ADDR_FMT"\"", ETH_ADDR_ARGS(f->value)); *size -= 10; if (OXM_HASMASK(f->header)){ *size -= 6; fprintf(stream, ", arp_sha_mask=\""ETH_ADDR_FMT"\"", ETH_ADDR_ARGS(f->value + 6)); } if (*size > 4) fprintf(stream, ", "); } else if (field == OFPXMT_OFB_ARP_THA){ fprintf(stream, "arp_tha=\""ETH_ADDR_FMT"\"", ETH_ADDR_ARGS(f->value)); *size -= 10; if (OXM_HASMASK(f->header)){ *size -= 6; fprintf(stream, ", arp_tha_mask=\""ETH_ADDR_FMT"\"", ETH_ADDR_ARGS(f->value + 6)); } if (*size > 4) fprintf(stream, ", "); } else if (field == OFPXMT_OFB_ARP_SPA){ fprintf(stream, "arp_spa=\""IP_FMT"\"",IP_ARGS(f->value)); *size -= 8; if (OXM_HASMASK(f->header)){ *size -= 4; fprintf(stream, ", arp_sha_mask=\""IP_FMT"\"",IP_ARGS(f->value + 4)); } if (*size > 4) fprintf(stream, ", "); } else if (field == OFPXMT_OFB_ARP_TPA){ fprintf(stream, "arp_tpa=\""IP_FMT"\"",IP_ARGS(f->value)); *size -= 8; if (OXM_HASMASK(f->header)){ *size -= 4; fprintf(stream, ", arp_tpa_mask=\""IP_FMT"\"",IP_ARGS(f->value + 4)); } if (*size > 4) fprintf(stream, ", "); } else if (field == OFPXMT_OFB_ARP_OP){ uint16_t *v = (uint16_t *) f->value; fprintf(stream, "arp_op=\"0x"); fprintf(stream,"%x\"", *v); *size -= 6; if (*size > 4) fprintf(stream, ", "); } else if (field == OFPXMT_OFB_IPV6_SRC){ char addr_str[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, f->value, addr_str, INET6_ADDRSTRLEN); *size -= 20; fprintf(stream, "nw_src_ipv6=\"%s\"", addr_str); if (OXM_HASMASK(f->header)){ *size -= 16; inet_ntop(AF_INET6, f->value + 16, addr_str, INET6_ADDRSTRLEN); fprintf(stream, ", nw_src_ipv6_mask=\"%s\"", addr_str); } if (*size > 4) fprintf(stream, ", "); } else if (field == OFPXMT_OFB_IPV6_DST){ char addr_str[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, f->value, addr_str, INET6_ADDRSTRLEN); *size -= 20; fprintf(stream, "nw_dst_ipv6=\"%s\"", addr_str); if (OXM_HASMASK(f->header)){ *size -= 16; inet_ntop(AF_INET6, f->value + 16, addr_str, INET6_ADDRSTRLEN); fprintf(stream, ", nw_dst_ipv6_mask=\"%s\"", addr_str); } if (*size > 4) fprintf(stream, ", "); } else if (field == OFPXMT_OFB_IPV6_ND_TARGET){ char addr_str[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, f->value, addr_str, INET6_ADDRSTRLEN); *size -= 20; fprintf(stream, "ipv6_nd_target=\"%s\"", addr_str); if (*size > 4) fprintf(stream, ", "); } else if (field == OFPXMT_OFB_IPV6_ND_SLL){ fprintf(stream, "ipv6_nd_sll=\""ETH_ADDR_FMT"\"", ETH_ADDR_ARGS(f->value)); *size -= 10; if (*size > 4) fprintf(stream, ", "); } else if (field == OFPXMT_OFB_IPV6_ND_TLL){ fprintf(stream, "ipv6_nd_tll=\""ETH_ADDR_FMT"\"", ETH_ADDR_ARGS(f->value)); *size -= 10; if (*size > 4) fprintf(stream, ", "); } else if (field == OFPXMT_OFB_IPV6_FLABEL){ uint32_t mask = 0x000fffff; *size -= 8; fprintf(stream, "ipv6_flow_label=\"%d\"",*((uint32_t*) f->value) & mask ); if (OXM_HASMASK(f->header)){ uint8_t *flabel_mask = (uint8_t*) f->value + 4; *size -= 4; fprintf(stream, ", ipv6_flow_label_mask=\"%d\"",*((uint32_t*)flabel_mask)); } if (*size > 4) fprintf(stream, ", "); } else if (field == OFPXMT_OFB_ICMPV6_TYPE){ fprintf(stream, "icmpv6_type=\"%d\"", *f->value); *size -= 5; if (*size > 4) fprintf(stream, ", "); } else if (field == OFPXMT_OFB_ICMPV6_CODE){ fprintf(stream, "icmpv6_code=\"%d\"", *f->value); *size -= 5; if (*size > 4) fprintf(stream, ", "); } else if (field == OFPXMT_OFB_MPLS_LABEL){ uint32_t mask = 0xfffff; fprintf(stream, "mpls_label=\"%d\"",((uint32_t) *f->value) & mask ); *size -= 8; if (*size > 4) fprintf(stream, ", "); } else if (field == OFPXMT_OFB_MPLS_TC){ fprintf(stream, "mpls_tc=\"%d\"", *f->value & 0x3); *size -= 5; if (*size > 4) fprintf(stream, ", "); } else if (field == OFPXMT_OFB_MPLS_BOS){ fprintf(stream, "mpls_bos=\"%d\"", *f->value & 0xfe); *size -= 5; if (*size > 4) fprintf(stream, ", "); } else if (field == OFPXMT_OFB_METADATA){ fprintf(stream, "metadata=\"%lld\"", *((uint64_t*) f->value)); *size -= 12; if (OXM_HASMASK(f->header)){ fprintf(stream, ", metadata_mask=\"%lld\"", *((uint64_t*) f->value+ 8 )); *size -= 8; } if (*size > 4) fprintf(stream, ", "); } else if (field == OFPXMT_OFB_PBB_ISID ){ fprintf(stream, "pbb_isid=\"%d\"",*((uint32_t*) f->value)); *size -= 8; if (OXM_HASMASK(f->header)){ fprintf(stream, ", pbb_isid_mask=\"%d\"", *((uint32_t*) f->value +4)); *size -= 4; } if (*size > 4) fprintf(stream, ", "); } else if (field == OFPXMT_OFB_TUNNEL_ID){ fprintf(stream, "tunnel_id=\"%lld\"", *((uint64_t*) f->value)); *size -= 12; if (OXM_HASMASK(f->header)){ fprintf(stream, ", tunnel_id_mask=\"%lld\"", *((uint64_t*) f->value+ 8 )); *size -= 8; } if (*size > 4) fprintf(stream, ", "); } else if (field == OFPXMT_OFB_IPV6_EXTHDR){ fprintf(stream, "ext_hdr=\\"); ofl_ipv6_ext_hdr_print(stream, *((uint16_t*) f->value) ); *size -= 6; if (OXM_HASMASK(f->header)){ *size -= 2; fprintf(stream, ", ext_hdr_mask=\"0x%x\"",*((uint16_t*) f->value + 4)); } if (*size > 4) fprintf(stream, ", "); } }