void test_lagopus_match_and_action(void) { struct action_list action_list; struct dpmgr *my_dpmgr; struct bridge *bridge; struct table *table; struct action *action; struct ofp_action_output *action_set; struct port nport, *port; struct lagopus_packet pkt; OS_MBUF *m; /* setup bridge and port */ my_dpmgr = dpmgr_alloc(); dpmgr_bridge_add(my_dpmgr, "br0", 0); nport.type = LAGOPUS_PORT_TYPE_NULL; /* for test */ nport.ifindex = 0; nport.ofp_port.hw_addr[0] = 1; dpmgr_port_add(my_dpmgr, &nport); nport.ifindex = 1; dpmgr_port_add(my_dpmgr, &nport); dpmgr_bridge_port_add(my_dpmgr, "br0", 0, 1); dpmgr_bridge_port_add(my_dpmgr, "br0", 1, 2); bridge = dpmgr_bridge_lookup(my_dpmgr, "br0"); TEST_ASSERT_NOT_NULL(bridge); flowdb_switch_mode_set(bridge->flowdb, SWITCH_MODE_OPENFLOW); table = table_get(bridge->flowdb, 0); table->userdata = new_flowinfo_eth_type(); TAILQ_INIT(&action_list); action = calloc(1, sizeof(*action) + 64); action_set = (struct ofp_action_output *)&action->ofpat; action_set->type = OFPAT_OUTPUT; lagopus_set_action_function(action); TAILQ_INSERT_TAIL(&action_list, action, entry); m = calloc(1, sizeof(*m)); TEST_ASSERT_NOT_NULL_MESSAGE(m, "calloc error."); m->data = &m->dat[128]; m->refcnt = 2; port = port_lookup(bridge->ports, 1); TEST_ASSERT_NOT_NULL(port); lagopus_set_in_port(&pkt, port); TEST_ASSERT_EQUAL(pkt.in_port, port); TEST_ASSERT_EQUAL(pkt.in_port->bridge, bridge); pkt.table_id = 0; lagopus_packet_init(&pkt, m); lagopus_match_and_action(&pkt); TEST_ASSERT_EQUAL_MESSAGE(m->refcnt, 1, "match_and_action refcnt error."); free(m); dpmgr_free(my_dpmgr); }
struct flowinfo * new_flowinfo_metadata_mask(void) { struct flowinfo *self; self = calloc(1, sizeof(struct flowinfo)); if (self != NULL) { self->nflow = 0; self->nnext = 0; self->next = malloc(1); self->misc = new_flowinfo_eth_type(); self->add_func = add_flow_metadata_mask; self->del_func = del_flow_metadata_mask; self->match_func = match_flow_metadata_mask; self->find_func = find_flow_metadata_mask; self->destroy_func = destroy_flowinfo_metadata_mask; } return self; }
void test_lagopus_find_flow(void) { datastore_bridge_info_t info; struct bridge *bridge; struct port *port; struct port nport; struct lagopus_packet *pkt; struct table *table; struct flow *flow; OS_MBUF *m; /* setup bridge and port */ memset(&info, 0, sizeof(info)); info.fail_mode = DATASTORE_BRIDGE_FAIL_MODE_SECURE; TEST_ASSERT_EQUAL(dp_bridge_create("br0", &info), LAGOPUS_RESULT_OK); TEST_ASSERT_EQUAL(dp_port_create("port0"), LAGOPUS_RESULT_OK); TEST_ASSERT_EQUAL(dp_port_create("port1"), LAGOPUS_RESULT_OK); TEST_ASSERT_EQUAL(dp_bridge_port_set("br0", "port0", 1), LAGOPUS_RESULT_OK); TEST_ASSERT_EQUAL(dp_bridge_port_set("br0", "port1", 2), LAGOPUS_RESULT_OK); pkt = alloc_lagopus_packet(); TEST_ASSERT_NOT_NULL_MESSAGE(pkt, "lagopus_alloc_packet error."); m = pkt->mbuf; OS_M_APPEND(m, 64); m->refcnt = 2; bridge = dp_bridge_lookup("br0"); TEST_ASSERT_NOT_NULL(bridge); lagopus_packet_init(pkt, m, port_lookup(&bridge->ports, 1)); table = flowdb_get_table(pkt->in_port->bridge->flowdb, 0); table->userdata = new_flowinfo_eth_type(); flow = lagopus_find_flow(pkt, table); TEST_ASSERT_EQUAL_MESSAGE(table->lookup_count, 0, "lookup_count(misc) error."); TEST_ASSERT_NULL_MESSAGE(flow, "flow(misc) error."); OS_MTOD(m, uint8_t *)[14] = 0x08; OS_MTOD(m, uint8_t *)[15] = 0x06; lagopus_packet_init(pkt, m, &port); flow = lagopus_find_flow(pkt, table); TEST_ASSERT_EQUAL_MESSAGE(table->lookup_count, 0, "lookup_count(arp) error."); TEST_ASSERT_NULL_MESSAGE(flow, "flow(arp) error."); OS_MTOD(m, uint8_t *)[14] = 0x08; OS_MTOD(m, uint8_t *)[15] = 0x00; lagopus_packet_init(pkt, m, port_lookup(&bridge->ports, 1)); flow = lagopus_find_flow(pkt, table); TEST_ASSERT_EQUAL_MESSAGE(table->lookup_count, 0, "lookup_count(ipv4) error."); TEST_ASSERT_NULL_MESSAGE(flow, "flow(ipv4) error."); OS_MTOD(m, uint8_t *)[14] = 0x86; OS_MTOD(m, uint8_t *)[15] = 0xdd; OS_MTOD(m, uint8_t *)[20] = IPPROTO_TCP; lagopus_packet_init(pkt, m, port_lookup(&bridge->ports, 1)); flow = lagopus_find_flow(pkt, table); TEST_ASSERT_EQUAL_MESSAGE(table->lookup_count, 0, "lookup_count(ipv6) error."); TEST_ASSERT_NULL_MESSAGE(flow, "flow(ipv6) error."); OS_MTOD(m, uint8_t *)[14] = 0x88; OS_MTOD(m, uint8_t *)[15] = 0x47; lagopus_packet_init(pkt, m, port_lookup(&bridge->ports, 1)); flow = lagopus_find_flow(pkt, table); TEST_ASSERT_EQUAL_MESSAGE(table->lookup_count, 0, "lookup_count(mpls) error."); TEST_ASSERT_NULL_MESSAGE(flow, "flow(mpls) error."); OS_MTOD(m, uint8_t *)[14] = 0x88; OS_MTOD(m, uint8_t *)[15] = 0x48; lagopus_packet_init(pkt, m, port_lookup(&bridge->ports, 1)); flow = lagopus_find_flow(pkt, table); TEST_ASSERT_EQUAL_MESSAGE(table->lookup_count, 0, "lookup_count(mpls-mc) error."); TEST_ASSERT_NULL_MESSAGE(flow, "flow(mpls-mc) error."); OS_MTOD(m, uint8_t *)[14] = 0x88; OS_MTOD(m, uint8_t *)[15] = 0xe7; lagopus_packet_init(pkt, m, port_lookup(&bridge->ports, 1)); flow = lagopus_find_flow(pkt, table); TEST_ASSERT_EQUAL_MESSAGE(table->lookup_count, 0, "lookup_count(pbb) error."); TEST_ASSERT_NULL_MESSAGE(flow, "flow(pbb) error."); }
static struct flow * match_flow_metadata_mask(struct flowinfo *self, struct lagopus_packet *pkt, int32_t *pri) { struct flowinfo *flowinfo; struct flow *flow[self->nnext], *matched, *alt_flow; struct flow mismatched = { .priority = 0, .flags = 0, .idle_timeout = 0, .hard_timeout = 0, .match_list = {NULL, NULL}, .instruction_list = {NULL, NULL}, .field_bits = 0 }; unsigned int i; matched = &mismatched; //#pragma omp parallel for for (i = 0; i < self->nnext; i++) { flowinfo = self->next[i]; flow[i] = flowinfo->match_func(flowinfo, pkt, pri); } for (i = 0; i < self->nnext; i++) { if (flow[i] != NULL && flow[i]->priority > matched->priority) { matched = flow[i]; } } alt_flow = self->misc->match_func(self->misc, pkt, pri); if (alt_flow != NULL) { matched = alt_flow; } if (matched == &mismatched) { matched = NULL; } return matched; } static struct flow * find_flow_metadata_mask(struct flowinfo *self, struct flow *flow) { struct flowinfo *flowinfo; uint64_t metadata, mask; lagopus_result_t rv; unsigned int i; rv = get_match_metadata(&flow->match_list, &metadata, &mask); if (rv == LAGOPUS_RESULT_OK) { rv = LAGOPUS_RESULT_NOT_FOUND; for (i = 0; i < self->nnext; i++) { if (self->next[i]->userdata == mask) { flowinfo = self->next[i]; rv = LAGOPUS_RESULT_OK; break; } } if (rv == LAGOPUS_RESULT_NOT_FOUND) { return NULL; } } else { flowinfo = self->misc; } return flowinfo->find_func(flowinfo, flow); } static lagopus_result_t add_flow_metadata(struct flowinfo *self, struct flow *flow) { struct flowinfo *flowinfo; uint64_t metadata, mask; lagopus_result_t rv; rv = get_match_metadata(&flow->match_list, &metadata, &mask); if (rv == LAGOPUS_RESULT_OK) { rv = lagopus_hashmap_find_no_lock(&self->hashmap, (void *)metadata, (void *)&flowinfo); if (rv != LAGOPUS_RESULT_OK) { void *val; flowinfo = new_flowinfo_eth_type(); val = flowinfo; rv = lagopus_hashmap_add_no_lock(&self->hashmap, (void *)metadata, (void *)&val, false); if (rv != LAGOPUS_RESULT_OK) { goto out; } } rv = flowinfo->add_func(flowinfo, flow); if (rv == LAGOPUS_RESULT_OK) { self->nflow++; } } out: return rv; } static lagopus_result_t del_flow_metadata(struct flowinfo *self, struct flow *flow) { uint64_t metadata, mask; lagopus_result_t rv; rv = get_match_metadata(&flow->match_list, &metadata, &mask); if (rv == LAGOPUS_RESULT_OK) { struct flowinfo *flowinfo; rv = lagopus_hashmap_find_no_lock(&self->hashmap, (void *)metadata, (void *)&flowinfo); if (rv == LAGOPUS_RESULT_OK) { rv = flowinfo->del_func(flowinfo, flow); } if (rv == LAGOPUS_RESULT_OK) { self->nflow--; } } return rv; }
void test_match_flow_mpls(void) { struct lagopus_packet pkt; struct flowinfo *flowinfo; struct flow *flow; struct port port; OS_MBUF *m; int32_t prio; int i, nflow; /* prepare packet */ pkt.in_port = &port; m = calloc(1, sizeof(*m)); TEST_ASSERT_NOT_NULL_MESSAGE(m, "calloc error."); m->data = &m->dat[128]; OS_M_PKTLEN(m) = 64; /* prepare flow table */ test_flow[0] = allocate_test_flow(10 * sizeof(struct match)); test_flow[0]->priority = 3; add_match(&test_flow[0]->match_list, 2, OFPXMT_OFB_ETH_TYPE << 1, 0x88, 0x47); add_match(&test_flow[0]->match_list, 4, OFPXMT_OFB_MPLS_LABEL << 1, 0x00, 0x00, 0x00, 0x01); test_flow[1] = allocate_test_flow(10 * sizeof(struct match)); test_flow[1]->priority = 2; FLOW_ADD_PORT_MATCH(test_flow[1], 2); test_flow[2] = allocate_test_flow(10 * sizeof(struct match)); test_flow[2]->priority = 1; FLOW_ADD_PORT_MATCH(test_flow[2], 3); /* create flowinfo */ flowinfo = new_flowinfo_eth_type(); nflow = sizeof(test_flow) / sizeof(test_flow[0]); for (i = 0; i < nflow; i++) { flowinfo->add_func(flowinfo, test_flow[i]); } /* test */ prio = 0; m->data[12] = 0x88; m->data[13] = 0x47; m->data[14] = 0xff; m->data[15] = 0xff; m->data[16] = 0xff; m->data[17] = 0xff; lagopus_packet_init(&pkt, m); flow = flowinfo->match_func(flowinfo, &pkt, &prio); TEST_ASSERT_NULL_MESSAGE(flow, "match_flow_mpls mismatch error"); m->data[14] = 0x00; m->data[15] = 0x00; m->data[16] = 0x1f; m->data[17] = 0xff; flow = flowinfo->match_func(flowinfo, &pkt, &prio); TEST_ASSERT_EQUAL_MESSAGE(flow, test_flow[0], "match_flow_mpls match flow error."); TEST_ASSERT_EQUAL_MESSAGE(prio, 3, "match_flow_mpls match prio error."); }