void bundle_to_nxast(const struct ofpact_bundle *bundle, struct ofpbuf *openflow) { int slaves_len = ROUND_UP(2 * bundle->n_slaves, OFP_ACTION_ALIGN); struct nx_action_bundle *nab; ovs_be16 *slaves; size_t i; nab = (bundle->dst.field ? ofputil_put_NXAST_BUNDLE_LOAD(openflow) : ofputil_put_NXAST_BUNDLE(openflow)); nab->len = htons(ntohs(nab->len) + slaves_len); nab->algorithm = htons(bundle->algorithm); nab->fields = htons(bundle->fields); nab->basis = htons(bundle->basis); nab->slave_type = htonl(NXM_OF_IN_PORT); nab->n_slaves = htons(bundle->n_slaves); if (bundle->dst.field) { nab->ofs_nbits = nxm_encode_ofs_nbits(bundle->dst.ofs, bundle->dst.n_bits); nab->dst = htonl(bundle->dst.field->nxm_header); } slaves = ofpbuf_put_zeros(openflow, slaves_len); for (i = 0; i < bundle->n_slaves; i++) { slaves[i] = htons(ofp_to_u16(bundle->slaves[i])); } }
void multipath_parse(struct nx_action_multipath *mp, const char *s_) { char *s = xstrdup(s_); char *save_ptr = NULL; char *fields, *basis, *algorithm, *n_links_str, *arg, *dst_s; struct mf_subfield dst; int n_links; fields = strtok_r(s, ", ", &save_ptr); basis = strtok_r(NULL, ", ", &save_ptr); algorithm = strtok_r(NULL, ", ", &save_ptr); n_links_str = strtok_r(NULL, ", ", &save_ptr); arg = strtok_r(NULL, ", ", &save_ptr); dst_s = strtok_r(NULL, ", ", &save_ptr); if (!dst_s) { ovs_fatal(0, "%s: not enough arguments to multipath action", s_); } ofputil_init_NXAST_MULTIPATH(mp); if (!strcasecmp(fields, "eth_src")) { mp->fields = htons(NX_HASH_FIELDS_ETH_SRC); } else if (!strcasecmp(fields, "symmetric_l4")) { mp->fields = htons(NX_HASH_FIELDS_SYMMETRIC_L4); } else { ovs_fatal(0, "%s: unknown fields `%s'", s_, fields); } mp->basis = htons(atoi(basis)); if (!strcasecmp(algorithm, "modulo_n")) { mp->algorithm = htons(NX_MP_ALG_MODULO_N); } else if (!strcasecmp(algorithm, "hash_threshold")) { mp->algorithm = htons(NX_MP_ALG_HASH_THRESHOLD); } else if (!strcasecmp(algorithm, "hrw")) { mp->algorithm = htons(NX_MP_ALG_HRW); } else if (!strcasecmp(algorithm, "iter_hash")) { mp->algorithm = htons(NX_MP_ALG_ITER_HASH); } else { ovs_fatal(0, "%s: unknown algorithm `%s'", s_, algorithm); } n_links = atoi(n_links_str); if (n_links < 1 || n_links > 65536) { ovs_fatal(0, "%s: n_links %d is not in valid range 1 to 65536", s_, n_links); } mp->max_link = htons(n_links - 1); mp->arg = htonl(atoi(arg)); mf_parse_subfield(&dst, dst_s); if (dst.n_bits < 16 && n_links > (1u << dst.n_bits)) { ovs_fatal(0, "%s: %d-bit destination field has %u possible values, " "less than specified n_links %d", s_, dst.n_bits, 1u << dst.n_bits, n_links); } mp->ofs_nbits = nxm_encode_ofs_nbits(dst.ofs, dst.n_bits); mp->dst = htonl(dst.field->nxm_header); free(s); }
/* Converts 'mp' into an OpenFlow NXAST_MULTIPATH action, which it appends to * 'openflow'. */ void multipath_to_nxast(const struct ofpact_multipath *mp, struct ofpbuf *openflow) { struct nx_action_multipath *nam = ofputil_put_NXAST_MULTIPATH(openflow); nam->fields = htons(mp->fields); nam->basis = htons(mp->basis); nam->algorithm = htons(mp->algorithm); nam->max_link = htons(mp->max_link); nam->arg = htonl(mp->arg); nam->ofs_nbits = nxm_encode_ofs_nbits(mp->dst.ofs, mp->dst.n_bits); nam->dst = htonl(mp->dst.field->nxm_header); }
static void parse_output(struct ofpbuf *b, char *arg) { if (strchr(arg, '[')) { struct nx_action_output_reg *naor; int ofs, n_bits; uint32_t src; nxm_parse_field_bits(arg, &src, &ofs, &n_bits); naor = ofputil_put_NXAST_OUTPUT_REG(b); naor->ofs_nbits = nxm_encode_ofs_nbits(ofs, n_bits); naor->src = htonl(src); naor->max_len = htons(UINT16_MAX); } else { put_output_action(b, str_to_u32(arg)); } }
void learn_execute(const struct nx_action_learn *learn, const struct flow *flow, struct ofputil_flow_mod *fm) { const void *p, *end; struct ofpbuf actions; cls_rule_init_catchall(&fm->cr, ntohs(learn->priority)); fm->cookie = htonll(0); fm->cookie_mask = htonll(0); fm->new_cookie = learn->cookie; fm->table_id = learn->table_id; fm->command = OFPFC_MODIFY_STRICT; fm->idle_timeout = ntohs(learn->idle_timeout); fm->hard_timeout = ntohs(learn->hard_timeout); fm->buffer_id = UINT32_MAX; fm->out_port = OFPP_NONE; fm->flags = ntohs(learn->flags) & OFPFF_SEND_FLOW_REM; fm->actions = NULL; fm->n_actions = 0; ofpbuf_init(&actions, 64); if (learn->fin_idle_timeout || learn->fin_hard_timeout) { struct nx_action_fin_timeout *naft; naft = ofputil_put_NXAST_FIN_TIMEOUT(&actions); naft->fin_idle_timeout = learn->fin_idle_timeout; naft->fin_hard_timeout = learn->fin_hard_timeout; } for (p = learn + 1, end = (char *) learn + ntohs(learn->len); p != end; ) { uint16_t header = ntohs(get_be16(&p)); int n_bits = header & NX_LEARN_N_BITS_MASK; int src_type = header & NX_LEARN_SRC_MASK; int dst_type = header & NX_LEARN_DST_MASK; union mf_subvalue value; struct mf_subfield dst; int chunk, ofs; if (!header) { break; } if (src_type == NX_LEARN_SRC_FIELD) { struct mf_subfield src; get_subfield(n_bits, &p, &src); mf_read_subfield(&src, flow, &value); } else { int p_bytes = 2 * DIV_ROUND_UP(n_bits, 16); memset(&value, 0, sizeof value); bitwise_copy(p, p_bytes, 0, &value, sizeof value, 0, n_bits); p = (const uint8_t *) p + p_bytes; } switch (dst_type) { case NX_LEARN_DST_MATCH: get_subfield(n_bits, &p, &dst); mf_write_subfield(&dst, &value, &fm->cr); break; case NX_LEARN_DST_LOAD: get_subfield(n_bits, &p, &dst); for (ofs = 0; ofs < n_bits; ofs += chunk) { struct nx_action_reg_load *load; chunk = MIN(n_bits - ofs, 64); load = ofputil_put_NXAST_REG_LOAD(&actions); load->ofs_nbits = nxm_encode_ofs_nbits(dst.ofs + ofs, chunk); load->dst = htonl(dst.field->nxm_header); bitwise_copy(&value, sizeof value, ofs, &load->value, sizeof load->value, 0, chunk); } break; case NX_LEARN_DST_OUTPUT: if (n_bits <= 16 || is_all_zeros(value.u8, sizeof value - 2)) { ofputil_put_OFPAT10_OUTPUT(&actions)->port = value.be16[7]; } break; } } fm->actions = ofpbuf_steal_data(&actions); fm->n_actions = actions.size / sizeof(struct ofp_action_header); }
/* Helper for bundle_parse and bundle_parse_load. */ static void bundle_parse__(struct ofpbuf *b, const char *s, char **save_ptr, const char *fields, const char *basis, const char *algorithm, const char *slave_type, const char *dst, const char *slave_delim) { enum ofputil_action_code code; struct nx_action_bundle *nab; uint16_t n_slaves; if (!slave_delim) { ovs_fatal(0, "%s: not enough arguments to bundle action", s); } if (strcasecmp(slave_delim, "slaves")) { ovs_fatal(0, "%s: missing slave delimiter, expected `slaves' got `%s'", s, slave_delim); } code = dst ? OFPUTIL_NXAST_BUNDLE_LOAD : OFPUTIL_NXAST_BUNDLE; b->l2 = ofputil_put_action(code, b); n_slaves = 0; for (;;) { ovs_be16 slave_be; char *slave; slave = strtok_r(NULL, ", ", save_ptr); if (!slave || n_slaves >= BUNDLE_MAX_SLAVES) { break; } slave_be = htons(atoi(slave)); ofpbuf_put(b, &slave_be, sizeof slave_be); n_slaves++; } /* Slaves array must be multiple of 8 bytes long. */ if (b->size % 8) { ofpbuf_put_zeros(b, 8 - (b->size % 8)); } nab = b->l2; nab->len = htons(b->size - ((char *) b->l2 - (char *) b->data)); nab->n_slaves = htons(n_slaves); nab->basis = htons(atoi(basis)); if (!strcasecmp(fields, "eth_src")) { nab->fields = htons(NX_HASH_FIELDS_ETH_SRC); } else if (!strcasecmp(fields, "symmetric_l4")) { nab->fields = htons(NX_HASH_FIELDS_SYMMETRIC_L4); } else { ovs_fatal(0, "%s: unknown fields `%s'", s, fields); } if (!strcasecmp(algorithm, "active_backup")) { nab->algorithm = htons(NX_BD_ALG_ACTIVE_BACKUP); } else if (!strcasecmp(algorithm, "hrw")) { nab->algorithm = htons(NX_BD_ALG_HRW); } else { ovs_fatal(0, "%s: unknown algorithm `%s'", s, algorithm); } if (!strcasecmp(slave_type, "ofport")) { nab->slave_type = htonl(NXM_OF_IN_PORT); } else { ovs_fatal(0, "%s: unknown slave_type `%s'", s, slave_type); } if (dst) { uint32_t reg; int ofs, n_bits; nxm_parse_field_bits(dst, ®, &ofs, &n_bits); nab->dst = htonl(reg); nab->ofs_nbits = nxm_encode_ofs_nbits(ofs, n_bits); } b->l2 = NULL; }
void learn_execute(const struct nx_action_learn *learn, const struct flow *flow, struct ofputil_flow_mod *fm) { const void *p, *end; struct ofpbuf actions; cls_rule_init_catchall(&fm->cr, ntohs(learn->priority)); fm->cookie = learn->cookie; fm->table_id = learn->table_id; fm->command = OFPFC_MODIFY_STRICT; fm->idle_timeout = ntohs(learn->idle_timeout); fm->hard_timeout = ntohs(learn->hard_timeout); fm->buffer_id = UINT32_MAX; fm->out_port = OFPP_NONE; fm->flags = ntohs(learn->flags) & OFPFF_SEND_FLOW_REM; fm->actions = NULL; fm->n_actions = 0; ofpbuf_init(&actions, 64); for (p = learn + 1, end = (char *) learn + ntohs(learn->len); p != end; ) { uint16_t header = ntohs(get_be16(&p)); int n_bits = header & NX_LEARN_N_BITS_MASK; int src_type = header & NX_LEARN_SRC_MASK; int dst_type = header & NX_LEARN_DST_MASK; uint64_t value; struct nx_action_reg_load *load; ovs_be32 dst_field; int dst_ofs; if (!header) { break; } if (src_type == NX_LEARN_SRC_FIELD) { ovs_be32 src_field = get_be32(&p); int src_ofs = ntohs(get_be16(&p)); value = nxm_read_field_bits(src_field, nxm_encode_ofs_nbits(src_ofs, n_bits), flow); } else { value = get_bits(n_bits, &p); } switch (dst_type) { case NX_LEARN_DST_MATCH: dst_field = get_be32(&p); dst_ofs = ntohs(get_be16(&p)); mf_set_subfield(mf_from_nxm_header(ntohl(dst_field)), value, dst_ofs, n_bits, &fm->cr); break; case NX_LEARN_DST_LOAD: dst_field = get_be32(&p); dst_ofs = ntohs(get_be16(&p)); load = ofputil_put_NXAST_REG_LOAD(&actions); load->ofs_nbits = nxm_encode_ofs_nbits(dst_ofs, n_bits); load->dst = dst_field; load->value = htonll(value); break; case NX_LEARN_DST_OUTPUT: ofputil_put_OFPAT_OUTPUT(&actions)->port = htons(value); break; } } fm->actions = ofpbuf_steal_data(&actions); fm->n_actions = actions.size / sizeof(struct ofp_action_header); }