struct list_res res_walk_parents (const struct res *out, const struct hs *hs, int in_port, array_t* out_arr) { struct res *curr_res = (struct res*) out; struct list_res currq = {0}; // set up initial result to start inversion struct hs int_hs; hs_isect_arr (&int_hs, &out->hs, out_arr); list_append (&currq, res_extend (out, &int_hs, out->port, true)); struct res *cur; while (curr_res) { if (curr_res->rules.cur) { for (int i = curr_res->rules.cur - 1; i >= 0; i--) { struct list_res nextq = {0}; struct res_rule r = curr_res->rules.arr[i]; while ((cur = currq.head)) { list_pop (&currq); struct list_res tmp = rule_inv_apply (r.tf_tf, r.tf_rule, cur, false); list_concat (&nextq, &tmp); res_free (cur); } // for each current result from rule inversion currq = nextq; } // for each rule } else return currq; // set (hs,port) which the inverted (hs,port) results must intersect struct res *parent = curr_res->parent; struct hs *next_hs = hs_create (curr_res->hs.len); int next_port; if (parent) { hs_copy (next_hs, &parent->hs); next_port = parent->port; } else { hs_copy (next_hs, hs); next_port = in_port; } // Intersect the results in `currq` with the target (hs,port) struct list_res nextq = {0}; while ((cur = currq.head)) { list_pop (&currq); struct hs *new_hs = hs_isect_a (&cur->hs, next_hs); if (cur->port == next_port && new_hs) list_append (&nextq, res_extend (cur, new_hs, next_port, false)); else res_free (cur); } currq = nextq; curr_res = parent; } return currq; }
struct list_res reachability (const struct hs *hs, uint32_t port, const uint32_t *out, int nout) { struct res *in = res_create (data_file->stages + 1); struct list_res res = {0}; hs_copy (&in->hs, hs); in->port = port; list_append (&queues[ntf_get_sw (in->port)], in); int n = data_file->ntfs - 1; struct tdata data[n]; memset (data, 0, sizeof data); g_out = out; g_nout = nout; for (int i = 0; i < n; i++) { struct tdata *p = &data[i]; p->sw = i; pthread_create (&p->tid, NULL, reach_thread, p); } for (int i = 0; i < n; i++) { pthread_join (data[i].tid, NULL); list_concat (&res, &data[i].res); } return res; }
struct hs * hs_copy_a (const struct hs *hs) { struct hs *res = xmalloc (sizeof *res); hs_copy (res, hs); return res; }
void app_add_in (const struct hs *hs, uint32_t port) { struct res *in = res_create (data_file->stages + 1); hs_copy (&in->hs, hs); in->port = port; list_append (&queues[ntf_get_sw (in->port)], in); }
void hs_minus (struct hs *a, const struct hs *b) { assert (a->len == b->len); struct hs tmp; hs_copy (&tmp, b); hs_cmpl (&tmp); hs_isect (a, &tmp); hs_destroy (&tmp); hs_compact (a); }
struct res * res_extend (const struct res *src, const struct hs *hs, uint32_t port, bool append) { struct res *res = res_create (src->rules.n); if (hs) hs_copy (&res->hs, hs); res->port = port; if (append) { res->rules.cur = src->rules.cur; memcpy (res->rules.arr, src->rules.arr, res->rules.cur * sizeof *res->rules.arr); } return res; }
static bool port_append_res (struct list_res *res, const struct rule *r, const struct tf *tf, const struct res *in, int32_t ports, bool append, const struct hs *hs, bool inv_remove_deps) { /* Create new result containing headerspace `hs` for each port in `ports`. */ bool used_hs = false; struct hs *new_hs; uint32_t n, x; const uint32_t *a; if (ports > 0) { n = 1; x = ports; a = &x; } else { const struct ports *p = PORTS (tf, ports); n = p->n; a = p->arr; } for (int i = 0; i < n; i++) { if (a[i] == in->port) continue; if (inv_remove_deps) { /* For inversion, also remove dependencies for each input port of the inverted rule. */ new_hs = hs_create (hs->len); hs_copy (new_hs, hs); if (r->deps) deps_diff_inv (new_hs, a[i], DEPS (tf, r->deps), tf); if (!hs_compact_m (new_hs, r->mask ? DATA_ARR (r->mask) : NULL)) { hs_destroy(new_hs); continue; } } else new_hs = (struct hs*) hs; // now *new_hs has the latest hs at this port struct res *tmp; if (! inv_remove_deps) { if (used_hs) tmp = res_extend (in, hs, a[i], append); else { tmp = res_extend (in, NULL, a[i], append); tmp->hs = *hs; used_hs = true; } } else { tmp = res_extend (in, NULL, a[i], append); tmp->hs = *new_hs; } res_rule_add (tmp, tf, r->idx, r); list_append (res, tmp); } return used_hs; }
static struct list_res rule_apply (const struct rule *r, const struct tf *tf, const struct res *in, bool append, uint32_t *app, int *napp) { struct list_res res = {0}; if (!r->out) app_add (r->idx, app, napp); if (!r->out || r->out == in->port) return res; struct hs hs; if (!r->match) hs_copy (&hs, &in->hs); else { if (!hs_isect_arr (&hs, &in->hs, DATA_ARR (r->match))) return res; if (r->deps) deps_diff (&hs, in->port, DEPS (tf, r->deps), tf, app, *napp); if (!hs_compact_m (&hs, r->mask ? DATA_ARR (r->mask) : NULL)) { hs_destroy (&hs); return res; } if (r->mask) hs_rewrite (&hs, DATA_ARR (r->mask), DATA_ARR (r->rewrite)); } bool used_hs = false; uint32_t n, x; const uint32_t *a; if (r->out > 0) { n = 1; x = r->out; a = &x; } else { const struct ports *p = PORTS (tf, r->out); n = p->n; a = p->arr; } for (int i = 0; i < n; i++) { if (a[i] == in->port) continue; struct res *tmp; if (used_hs) tmp = res_extend (in, &hs, a[i], append); else { tmp = res_extend (in, NULL, a[i], append); tmp->hs = hs; used_hs = true; } res_rule_add (tmp, tf, r->idx); list_append (&res, tmp); } if (res.head) app_add (r->idx, app, napp); if (!used_hs) hs_destroy (&hs); return res; }
struct list_res rule_inv_apply (const struct tf *tf, const struct rule *r, const struct res *in, bool append) { /* Given a rule `r` in a tf `tf`, apply the inverse of `r` on the input (headerspace,port) `in`. */ struct list_res res = {0}; // prune cases where rule outport doesn't include the current port if (r->out > 0 && r->out != in->port) return res; if (r->out < 0 && !port_match(in->port, r->out, tf)) return res; if (!r->out) return res; // set up inverse match and rewrite arrays array_t *inv_rw=0, *inv_mat=0; if (r->mask) { // rewrite rule inv_mat = rule_set_inv_mat (r, in->hs.len); inv_rw = rule_set_inv_rw (r, in->hs.len); } else { // fwding and topology rules if (r->match) inv_mat = array_copy (DATA_ARR (r->match), in->hs.len); } struct hs hs; if (!r->match) hs_copy (&hs, &in->hs); // topology rule else { // fwding and rewrite rules if (!hs_isect_arr (&hs, &in->hs, inv_mat)) return res; if (r->mask) hs_rewrite (&hs, DATA_ARR (r->mask), inv_rw); } // there is a new hs result corresponding to each rule inport bool used_hs = port_append_res (&res, r, tf, in, r->in, append, &hs, true); if (inv_rw) array_free (inv_rw); if (inv_mat) array_free (inv_mat); if (!used_hs) hs_destroy (&hs); return res; }
static struct list_res rule_apply (const struct rule *r, const struct tf *tf, const struct res *in, bool append, uint32_t *app, int *napp) { struct list_res res = {0}; if (!r->out) app_add (r->idx, app, napp); if (!r->out || r->out == in->port) return res; struct hs hs; if (!r->match) hs_copy (&hs, &in->hs); else { if (!hs_isect_arr (&hs, &in->hs, DATA_ARR (r->match))) return res; if (r->deps) deps_diff (&hs, in->port, DEPS (tf, r->deps), tf, app, *napp); if (!hs_compact_m (&hs, r->mask ? DATA_ARR (r->mask) : NULL)) { hs_destroy (&hs); return res; } if (r->mask) hs_rewrite (&hs, DATA_ARR (r->mask), DATA_ARR (r->rewrite)); } bool used_hs = port_append_res (&res, r, tf, in, r->out, append, &hs, false); if (res.head) app_add (r->idx, app, napp); if (!used_hs) hs_destroy (&hs); return res; }