コード例 #1
0
ファイル: lex.c プロジェクト: l8huang/ovs
/* Returns the effective format for 'token', that is, the format in which it
 * should actually be printed.  This is ordinarily the same as 'token->format',
 * but it's always possible that someone sets up a token with a format that
 * won't work for a value, e.g. 'token->value' is wider than 32 bits but the
 * format is LEX_F_IPV4.  (The lexer itself won't do that; this is an attempt
 * to avoid confusion in the future.) */
static enum lex_format
lex_token_get_format(const struct lex_token *token)
{
    size_t n_zeros = lex_token_n_zeros(token->format);
    return (is_all_zeros(&token->value, n_zeros)
            && (token->type != LEX_T_MASKED_INTEGER
                || is_all_zeros(&token->mask, n_zeros))
            ? token->format
            : LEX_F_HEXADECIMAL);
}
コード例 #2
0
ファイル: robot.cpp プロジェクト: stephentu/cs184-ikrobot
vec& LinkedTreeRobot::getQDot(const vec& desired, vec& qdot, vec& axes) {
  vec P(3 * _numEffectors);
  getEffectorPositions(P); // position of the effectors currently

  vec F = clamp(desired - P, 0.5);

  mat J;
  computeJacobian(desired, J, axes);

  mat Jc;
  //cout << "++ Going to compute constraint jacobian ++" << endl;
  computeConstraintJacobian(desired, axes, Jc);
  //cout << "++ Finished computed constraint jacobian ++" << endl;
  //cout << "Jc:" << endl << Jc << endl;

  vec ga = trans(J) * F;
  //cout << "ga:" << endl << ga << endl;

  vec gc;
  if (Jc.n_elem == 0 || is_all_zeros(Jc)) // no constraints, or all constraints OK
    gc.zeros(ga.n_elem);
  else {
    vec b = -Jc * ga;
    //cout << "b:" << endl << b << endl;
    
    mat JcT = trans(Jc);

    mat A = Jc * JcT;
    //cout << "A:" << endl << A << endl;

    vec d;
    mat U, V;
    if (!svd(U, d, V, A))
      cerr << "could not compute SVD" << endl;

    //cout << "U:" << endl << U << endl;
    //cout << "V:" << endl << V << endl;
    //cout << "d:" << endl << d << endl;

    //vec lambda = V * inv(D) * trans(U) * b; // too naive

    vec utb = trans(U) * b;

    vec dinv_ut_b(d.n_elem);
    dinv_ut_b.zeros();

    for (size_t d_idx = 0; d_idx < d.n_elem; d_idx++) {
      double elem = d[d_idx];
      if (!double_equals(elem, 0.0))
        dinv_ut_b[d_idx] = 1.0 / elem * utb[d_idx];
    }

    gc = JcT * (V * dinv_ut_b); // Jc^T * lambda
  }

  qdot = ga + gc; // qdot
  return qdot;
}
コード例 #3
0
ファイル: copy.c プロジェクト: tcharding/self_learning
int
main(int argc, char *argv[])
{
	int inputFd, outputFd, openFlags;
	mode_t filePerms;
	ssize_t numRead;
	char buf[BUF_SIZE];

	if (argc != 3 || strcmp(argv[1], "--help") == 0)
		usageErr("%s old-file new-file\n", argv[0]);

	/* Open input and output files */

	inputFd = open(argv[1], O_RDONLY);
	if (inputFd == -1)
		errExit("opening file %s", argv[1]);

	openFlags = O_CREAT | O_WRONLY | O_TRUNC;
	filePerms = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP |
                S_IROTH | S_IWOTH;      /* rw-rw-rw- */
	outputFd = open(argv[2], openFlags, filePerms);
	if (outputFd == -1)
		errExit("opening file %s", argv[2]);

	/* Transfer data until we encounter end of input or an error */

	while ((numRead = read(inputFd, buf, BUF_SIZE)) > 0) {
		if (is_all_zeros(buf, numRead))
			continue;
		if (write(outputFd, buf, numRead) != numRead)
			fatal("couldn't write whole buffer");
		if (numRead == -1)
			errExit("read");
	}

	if (close(inputFd) == -1)
		errExit("close input");
	if (close(outputFd) == -1)
		errExit("close output");

	exit(EXIT_SUCCESS);
}
コード例 #4
0
ファイル: debugfs.c プロジェクト: lumag/linux
static int wil_bf_debugfs_show(struct seq_file *s, void *data)
{
	int rc;
	int i;
	struct wil6210_priv *wil = s->private;
	struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
	struct wmi_notify_req_cmd cmd = {
		.interval_usec = 0,
	};
	struct {
		struct wmi_cmd_hdr wmi;
		struct wmi_notify_req_done_event evt;
	} __packed reply;

	for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
		u32 status;

		cmd.cid = i;
		rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, vif->mid,
			      &cmd, sizeof(cmd),
			      WMI_NOTIFY_REQ_DONE_EVENTID, &reply,
			      sizeof(reply), 20);
		/* if reply is all-0, ignore this CID */
		if (rc || is_all_zeros(&reply.evt, sizeof(reply.evt)))
			continue;

		status = le32_to_cpu(reply.evt.status);
		seq_printf(s, "CID %d {\n"
			   "  TSF = 0x%016llx\n"
			   "  TxMCS = %2d TxTpt = %4d\n"
			   "  SQI = %4d\n"
			   "  RSSI = %4d\n"
			   "  Status = 0x%08x %s\n"
			   "  Sectors(rx:tx) my %2d:%2d peer %2d:%2d\n"
			   "  Goodput(rx:tx) %4d:%4d\n"
			   "}\n",
			   i,
			   le64_to_cpu(reply.evt.tsf),
			   le16_to_cpu(reply.evt.bf_mcs),
			   le32_to_cpu(reply.evt.tx_tpt),
			   reply.evt.sqi,
			   reply.evt.rssi,
			   status, wil_bfstatus_str(status),
			   le16_to_cpu(reply.evt.my_rx_sector),
			   le16_to_cpu(reply.evt.my_tx_sector),
			   le16_to_cpu(reply.evt.other_rx_sector),
			   le16_to_cpu(reply.evt.other_tx_sector),
			   le32_to_cpu(reply.evt.rx_goodput),
			   le32_to_cpu(reply.evt.tx_goodput));
	}
	return 0;
}

static int wil_bf_seq_open(struct inode *inode, struct file *file)
{
	return single_open(file, wil_bf_debugfs_show, inode->i_private);
}

static const struct file_operations fops_bf = {
	.open		= wil_bf_seq_open,
	.release	= single_release,
	.read		= seq_read,
	.llseek		= seq_lseek,
};

/*---------temp------------*/
static void print_temp(struct seq_file *s, const char *prefix, u32 t)
{
	switch (t) {
	case 0:
	case ~(u32)0:
		seq_printf(s, "%s N/A\n", prefix);
	break;
	default:
		seq_printf(s, "%s %d.%03d\n", prefix, t / 1000, t % 1000);
		break;
	}
}

static int wil_temp_debugfs_show(struct seq_file *s, void *data)
{
	struct wil6210_priv *wil = s->private;
	u32 t_m, t_r;
	int rc = wmi_get_temperature(wil, &t_m, &t_r);

	if (rc) {
		seq_puts(s, "Failed\n");
		return 0;
	}

	print_temp(s, "T_mac   =", t_m);
	print_temp(s, "T_radio =", t_r);

	return 0;
}

static int wil_temp_seq_open(struct inode *inode, struct file *file)
{
	return single_open(file, wil_temp_debugfs_show, inode->i_private);
}

static const struct file_operations fops_temp = {
	.open		= wil_temp_seq_open,
	.release	= single_release,
	.read		= seq_read,
	.llseek		= seq_lseek,
};

/*---------freq------------*/
static int wil_freq_debugfs_show(struct seq_file *s, void *data)
{
	struct wil6210_priv *wil = s->private;
	struct wireless_dev *wdev = wil->main_ndev->ieee80211_ptr;
	u16 freq = wdev->chandef.chan ? wdev->chandef.chan->center_freq : 0;

	seq_printf(s, "Freq = %d\n", freq);

	return 0;
}

static int wil_freq_seq_open(struct inode *inode, struct file *file)
{
	return single_open(file, wil_freq_debugfs_show, inode->i_private);
}

static const struct file_operations fops_freq = {
	.open		= wil_freq_seq_open,
	.release	= single_release,
	.read		= seq_read,
	.llseek		= seq_lseek,
};

/*---------link------------*/
static int wil_link_debugfs_show(struct seq_file *s, void *data)
{
	struct wil6210_priv *wil = s->private;
	struct station_info sinfo;
	int i, rc;

	for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
		struct wil_sta_info *p = &wil->sta[i];
		char *status = "unknown";
		struct wil6210_vif *vif;
		u8 mid;

		switch (p->status) {
		case wil_sta_unused:
			status = "unused   ";
			break;
		case wil_sta_conn_pending:
			status = "pending  ";
			break;
		case wil_sta_connected:
			status = "connected";
			break;
		}
		mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX;
		seq_printf(s, "[%d][MID %d] %pM %s\n",
			   i, mid, p->addr, status);

		if (p->status != wil_sta_connected)
			continue;

		vif = (mid < wil->max_vifs) ? wil->vifs[mid] : NULL;
		if (vif) {
			rc = wil_cid_fill_sinfo(vif, i, &sinfo);
			if (rc)
				return rc;

			seq_printf(s, "  Tx_mcs = %d\n", sinfo.txrate.mcs);
			seq_printf(s, "  Rx_mcs = %d\n", sinfo.rxrate.mcs);
			seq_printf(s, "  SQ     = %d\n", sinfo.signal);
		} else {
			seq_puts(s, "  INVALID MID\n");
		}
	}

	return 0;
}

static int wil_link_seq_open(struct inode *inode, struct file *file)
{
	return single_open(file, wil_link_debugfs_show, inode->i_private);
}

static const struct file_operations fops_link = {
	.open		= wil_link_seq_open,
	.release	= single_release,
	.read		= seq_read,
	.llseek		= seq_lseek,
};

/*---------info------------*/
static int wil_info_debugfs_show(struct seq_file *s, void *data)
{
	struct wil6210_priv *wil = s->private;
	struct net_device *ndev = wil->main_ndev;
	int is_ac = power_supply_is_system_supplied();
	int rx = atomic_xchg(&wil->isr_count_rx, 0);
	int tx = atomic_xchg(&wil->isr_count_tx, 0);
	static ulong rxf_old, txf_old;
	ulong rxf = ndev->stats.rx_packets;
	ulong txf = ndev->stats.tx_packets;
	unsigned int i;

	/* >0 : AC; 0 : battery; <0 : error */
	seq_printf(s, "AC powered : %d\n", is_ac);
	seq_printf(s, "Rx irqs:packets : %8d : %8ld\n", rx, rxf - rxf_old);
	seq_printf(s, "Tx irqs:packets : %8d : %8ld\n", tx, txf - txf_old);
	rxf_old = rxf;
	txf_old = txf;

#define CHECK_QSTATE(x) (state & BIT(__QUEUE_STATE_ ## x)) ? \
	" " __stringify(x) : ""

	for (i = 0; i < ndev->num_tx_queues; i++) {
		struct netdev_queue *txq = netdev_get_tx_queue(ndev, i);
		unsigned long state = txq->state;

		seq_printf(s, "Tx queue[%i] state : 0x%lx%s%s%s\n", i, state,
			   CHECK_QSTATE(DRV_XOFF),
			   CHECK_QSTATE(STACK_XOFF),
			   CHECK_QSTATE(FROZEN)
			  );
	}
#undef CHECK_QSTATE
	return 0;
}

static int wil_info_seq_open(struct inode *inode, struct file *file)
{
	return single_open(file, wil_info_debugfs_show, inode->i_private);
}

static const struct file_operations fops_info = {
	.open		= wil_info_seq_open,
	.release	= single_release,
	.read		= seq_read,
	.llseek		= seq_lseek,
};

/*---------recovery------------*/
/* mode = [manual|auto]
 * state = [idle|pending|running]
 */
static ssize_t wil_read_file_recovery(struct file *file, char __user *user_buf,
				      size_t count, loff_t *ppos)
{
	struct wil6210_priv *wil = file->private_data;
	char buf[80];
	int n;
	static const char * const sstate[] = {"idle", "pending", "running"};

	n = snprintf(buf, sizeof(buf), "mode = %s\nstate = %s\n",
		     no_fw_recovery ? "manual" : "auto",
		     sstate[wil->recovery_state]);

	n = min_t(int, n, sizeof(buf));

	return simple_read_from_buffer(user_buf, count, ppos,
				       buf, n);
}

static ssize_t wil_write_file_recovery(struct file *file,
				       const char __user *buf_,
				       size_t count, loff_t *ppos)
{
	struct wil6210_priv *wil = file->private_data;
	static const char run_command[] = "run";
	char buf[sizeof(run_command) + 1]; /* to detect "runx" */
	ssize_t rc;

	if (wil->recovery_state != fw_recovery_pending) {
		wil_err(wil, "No recovery pending\n");
		return -EINVAL;
	}

	if (*ppos != 0) {
		wil_err(wil, "Offset [%d]\n", (int)*ppos);
		return -EINVAL;
	}

	if (count > sizeof(buf)) {
		wil_err(wil, "Input too long, len = %d\n", (int)count);
		return -EINVAL;
	}

	rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, buf_, count);
	if (rc < 0)
		return rc;

	buf[rc] = '\0';
	if (0 == strcmp(buf, run_command))
		wil_set_recovery_state(wil, fw_recovery_running);
	else
		wil_err(wil, "Bad recovery command \"%s\"\n", buf);

	return rc;
}

static const struct file_operations fops_recovery = {
	.read = wil_read_file_recovery,
	.write = wil_write_file_recovery,
	.open  = simple_open,
};

/*---------Station matrix------------*/
static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r)
{
	int i;
	u16 index = ((r->head_seq_num - r->ssn) & 0xfff) % r->buf_size;
	unsigned long long drop_dup = r->drop_dup, drop_old = r->drop_old;

	seq_printf(s, "([%2d] %3d TU) 0x%03x [", r->buf_size, r->timeout,
		   r->head_seq_num);
	for (i = 0; i < r->buf_size; i++) {
		if (i == index)
			seq_printf(s, "%c", r->reorder_buf[i] ? 'O' : '|');
		else
			seq_printf(s, "%c", r->reorder_buf[i] ? '*' : '_');
	}
	seq_printf(s,
		   "] total %llu drop %llu (dup %llu + old %llu) last 0x%03x\n",
		   r->total, drop_dup + drop_old, drop_dup, drop_old,
		   r->ssn_last_drop);
}
コード例 #5
0
ファイル: learn.c プロジェクト: Altiscale/ovs
/* Composes 'fm' so that executing it will implement 'learn' given that the
 * packet being processed has 'flow' as its flow.
 *
 * Uses 'ofpacts' to store the flow mod's actions.  The caller must initialize
 * 'ofpacts' and retains ownership of it.  'fm->ofpacts' will point into the
 * 'ofpacts' buffer.
 *
 * The caller has to actually execute 'fm'. */
void
learn_execute(const struct ofpact_learn *learn, const struct flow *flow,
              struct ofputil_flow_mod *fm, struct ofpbuf *ofpacts)
{
    const struct ofpact_learn_spec *spec;

    match_init_catchall(&fm->match);
    fm->priority = learn->priority;
    fm->cookie = htonll(0);
    fm->cookie_mask = htonll(0);
    fm->new_cookie = learn->cookie;
    fm->modify_cookie = fm->new_cookie != OVS_BE64_MAX;
    fm->table_id = learn->table_id;
    fm->command = OFPFC_MODIFY_STRICT;
    fm->idle_timeout = learn->idle_timeout;
    fm->hard_timeout = learn->hard_timeout;
    fm->importance = 0;
    fm->buffer_id = UINT32_MAX;
    fm->out_port = OFPP_NONE;
    fm->flags = 0;
    if (learn->flags & NX_LEARN_F_SEND_FLOW_REM) {
        fm->flags |= OFPUTIL_FF_SEND_FLOW_REM;
    }
    fm->ofpacts = NULL;
    fm->ofpacts_len = 0;
    fm->delete_reason = OFPRR_DELETE;

    if (learn->fin_idle_timeout || learn->fin_hard_timeout) {
        struct ofpact_fin_timeout *oft;

        oft = ofpact_put_FIN_TIMEOUT(ofpacts);
        oft->fin_idle_timeout = learn->fin_idle_timeout;
        oft->fin_hard_timeout = learn->fin_hard_timeout;
    }

    for (spec = learn->specs; spec < &learn->specs[learn->n_specs]; spec++) {
        struct ofpact_set_field *sf;
        union mf_subvalue value;

        if (spec->src_type == NX_LEARN_SRC_FIELD) {
            mf_read_subfield(&spec->src, flow, &value);
        } else {
            value = spec->src_imm;
        }

        switch (spec->dst_type) {
        case NX_LEARN_DST_MATCH:
            mf_write_subfield(&spec->dst, &value, &fm->match);
            break;

        case NX_LEARN_DST_LOAD:
            sf = ofpact_put_reg_load(ofpacts);
            sf->field = spec->dst.field;
            bitwise_copy(&value, sizeof value, 0,
                         &sf->value, spec->dst.field->n_bytes, spec->dst.ofs,
                         spec->n_bits);
            bitwise_one(&sf->mask, spec->dst.field->n_bytes, spec->dst.ofs,
                        spec->n_bits);
            break;

        case NX_LEARN_DST_OUTPUT:
            if (spec->n_bits <= 16
                || is_all_zeros(value.u8, sizeof value - 2)) {
                ovs_be16 *last_be16 = &value.be16[ARRAY_SIZE(value.be16) - 1];
                ofp_port_t port = u16_to_ofp(ntohs(*last_be16));

                if (ofp_to_u16(port) < ofp_to_u16(OFPP_MAX)
                    || port == OFPP_IN_PORT
                    || port == OFPP_FLOOD
                    || port == OFPP_LOCAL
                    || port == OFPP_ALL) {
                    ofpact_put_OUTPUT(ofpacts)->port = port;
                }
            }
            break;
        }
    }
    ofpact_pad(ofpacts);

    fm->ofpacts = ofpbuf_data(ofpacts);
    fm->ofpacts_len = ofpbuf_size(ofpacts);
}
コード例 #6
0
ファイル: learn.c プロジェクト: yamt/openvswitch
/* Converts 'nal' into a "struct ofpact_learn" and appends that struct to
 * 'ofpacts'.  Returns 0 if successful, otherwise an OFPERR_*. */
enum ofperr
learn_from_openflow(const struct nx_action_learn *nal, struct ofpbuf *ofpacts)
{
    struct ofpact_learn *learn;
    const void *p, *end;

    if (nal->pad) {
        return OFPERR_OFPBAC_BAD_ARGUMENT;
    }

    learn = ofpact_put_LEARN(ofpacts);

    learn->idle_timeout = ntohs(nal->idle_timeout);
    learn->hard_timeout = ntohs(nal->hard_timeout);
    learn->priority = ntohs(nal->priority);
    learn->cookie = ntohll(nal->cookie);
    learn->flags = ntohs(nal->flags);
    learn->table_id = nal->table_id;
    learn->fin_idle_timeout = ntohs(nal->fin_idle_timeout);
    learn->fin_hard_timeout = ntohs(nal->fin_hard_timeout);

    if (learn->flags & ~OFPFF_SEND_FLOW_REM || learn->table_id == 0xff) {
        return OFPERR_OFPBAC_BAD_ARGUMENT;
    }

    end = (char *) nal + ntohs(nal->len);
    for (p = nal + 1; p != end; ) {
        struct ofpact_learn_spec *spec;
        uint16_t header = ntohs(get_be16(&p));

        if (!header) {
            break;
        }

        spec = ofpbuf_put_zeros(ofpacts, sizeof *spec);
        learn = ofpacts->l2;
        learn->n_specs++;

        spec->src_type = header & NX_LEARN_SRC_MASK;
        spec->dst_type = header & NX_LEARN_DST_MASK;
        spec->n_bits = header & NX_LEARN_N_BITS_MASK;

        /* Check for valid src and dst type combination. */
        if (spec->dst_type == NX_LEARN_DST_MATCH ||
                spec->dst_type == NX_LEARN_DST_LOAD ||
                (spec->dst_type == NX_LEARN_DST_OUTPUT &&
                 spec->src_type == NX_LEARN_SRC_FIELD)) {
            /* OK. */
        } else {
            return OFPERR_OFPBAC_BAD_ARGUMENT;
        }

        /* Check that the arguments don't overrun the end of the action. */
        if ((char *) end - (char *) p < learn_min_len(header)) {
            return OFPERR_OFPBAC_BAD_LEN;
        }

        /* Get the source. */
        if (spec->src_type == NX_LEARN_SRC_FIELD) {
            get_subfield(spec->n_bits, &p, &spec->src);
        } else {
            int p_bytes = 2 * DIV_ROUND_UP(spec->n_bits, 16);

            bitwise_copy(p, p_bytes, 0,
                         &spec->src_imm, sizeof spec->src_imm, 0,
                         spec->n_bits);
            p = (const uint8_t *) p + p_bytes;
        }

        /* Get the destination. */
        if (spec->dst_type == NX_LEARN_DST_MATCH ||
                spec->dst_type == NX_LEARN_DST_LOAD) {
            get_subfield(spec->n_bits, &p, &spec->dst);
        }
    }
    ofpact_update_len(ofpacts, &learn->ofpact);

    if (!is_all_zeros(p, (char *) end - (char *) p)) {
        return OFPERR_OFPBAC_BAD_ARGUMENT;
    }

    return 0;
}
コード例 #7
0
ファイル: learn.c プロジェクト: yamt/openvswitch
/* Composes 'fm' so that executing it will implement 'learn' given that the
 * packet being processed has 'flow' as its flow.
 *
 * Uses 'ofpacts' to store the flow mod's actions.  The caller must initialize
 * 'ofpacts' and retains ownership of it.  'fm->ofpacts' will point into the
 * 'ofpacts' buffer.
 *
 * The caller has to actually execute 'fm'. */
void
learn_execute(const struct ofpact_learn *learn, const struct flow *flow,
              struct ofputil_flow_mod *fm, struct ofpbuf *ofpacts)
{
    const struct ofpact_learn_spec *spec;

    match_init_catchall(&fm->match);
    fm->priority = learn->priority;
    fm->cookie = htonll(0);
    fm->cookie_mask = htonll(0);
    fm->new_cookie = htonll(learn->cookie);
    fm->table_id = learn->table_id;
    fm->command = OFPFC_MODIFY_STRICT;
    fm->idle_timeout = learn->idle_timeout;
    fm->hard_timeout = learn->hard_timeout;
    fm->buffer_id = UINT32_MAX;
    fm->out_port = OFPP_NONE;
    fm->flags = learn->flags;
    fm->ofpacts = NULL;
    fm->ofpacts_len = 0;

    if (learn->fin_idle_timeout || learn->fin_hard_timeout) {
        struct ofpact_fin_timeout *oft;

        oft = ofpact_put_FIN_TIMEOUT(ofpacts);
        oft->fin_idle_timeout = learn->fin_idle_timeout;
        oft->fin_hard_timeout = learn->fin_hard_timeout;
    }

    for (spec = learn->specs; spec < &learn->specs[learn->n_specs]; spec++) {
        union mf_subvalue value;
        int chunk, ofs;

        if (spec->src_type == NX_LEARN_SRC_FIELD) {
            mf_read_subfield(&spec->src, flow, &value);
        } else {
            value = spec->src_imm;
        }

        switch (spec->dst_type) {
        case NX_LEARN_DST_MATCH:
            mf_write_subfield(&spec->dst, &value, &fm->match);
            break;

        case NX_LEARN_DST_LOAD:
            for (ofs = 0; ofs < spec->n_bits; ofs += chunk) {
                struct ofpact_reg_load *load;

                chunk = MIN(spec->n_bits - ofs, 64);

                load = ofpact_put_REG_LOAD(ofpacts);
                load->dst.field = spec->dst.field;
                load->dst.ofs = spec->dst.ofs + ofs;
                load->dst.n_bits = chunk;
                bitwise_copy(&value, sizeof value, ofs,
                             &load->subvalue, sizeof load->subvalue, 0,
                             chunk);
            }
            break;

        case NX_LEARN_DST_OUTPUT:
            if (spec->n_bits <= 16
                    || is_all_zeros(value.u8, sizeof value - 2)) {
                ofp_port_t port = u16_to_ofp(ntohs(value.be16[7]));

                if (ofp_to_u16(port) < ofp_to_u16(OFPP_MAX)
                        || port == OFPP_IN_PORT
                        || port == OFPP_FLOOD
                        || port == OFPP_LOCAL
                        || port == OFPP_ALL) {
                    ofpact_put_OUTPUT(ofpacts)->port = port;
                }
            }
            break;
        }
    }
    ofpact_pad(ofpacts);

    fm->ofpacts = ofpacts->data;
    fm->ofpacts_len = ofpacts->size;
}
コード例 #8
0
ファイル: cryptio.cpp プロジェクト: bailey27/cppcryptfs
int
read_block(CryptContext *con, HANDLE hfile, BYTE *inputbuf, int bytesinbuf, int *bytes_consumed, const unsigned char *fileid, unsigned long long block, unsigned char *ptbuf, void *openssl_crypt_context)
{
	static_assert(BLOCK_IV_LEN == BLOCK_SIV_LEN, "BLOCK_IV_LEN != BLOCK_SIV_LEN.");
	static_assert(BLOCK_SIV_LEN == BLOCK_TAG_LEN, "BLOCK_SIV_LEN != BLOCK_TAG_LEN.");

	long long offset = FILE_HEADER_LEN + block*CIPHER_BS;

	OVERLAPPED ov;

	if (hfile != INVALID_HANDLE_VALUE) {
		SetOverlapped(&ov, offset);
	}

	unsigned long long be_block = MakeBigEndian(block);

	unsigned char auth_data[sizeof(be_block) + FILE_ID_LEN];

	memcpy(auth_data, &be_block, sizeof(be_block));

	memcpy(auth_data + sizeof(be_block), fileid, FILE_ID_LEN);

	unsigned char buf[CIPHER_BS];

	DWORD nread = 0;

	if (hfile == INVALID_HANDLE_VALUE && inputbuf) {
		int to_consume = min(CIPHER_BS, bytesinbuf);
		if (bytes_consumed != NULL)
			*bytes_consumed = to_consume;
		nread = to_consume;
	} else {
		if (!ReadFile(hfile, buf, sizeof(buf), &nread, &ov)) {
			DWORD error = GetLastError();
			if (error == ERROR_HANDLE_EOF) {
				return 0;
			} else {
				return -1;
			}
		}
	}

	if (nread == 0)
		return 0;

	if (nread <= CIPHER_BLOCK_OVERHEAD) {
		SetLastError(ERROR_INVALID_DATA);
		return -1;
	}

	int ptlen;
	
	if (con->GetConfig()->m_AESSIV) {
		ptlen = decrypt_siv((inputbuf ? inputbuf : buf) + BLOCK_IV_LEN + BLOCK_SIV_LEN, nread - BLOCK_IV_LEN - BLOCK_SIV_LEN, auth_data, sizeof(auth_data), 
			(inputbuf ? inputbuf : buf) + BLOCK_IV_LEN, (inputbuf ? inputbuf : buf), ptbuf, &con->m_siv);	
	} else {
		ptlen = decrypt((inputbuf ? inputbuf : buf) + BLOCK_IV_LEN, nread - BLOCK_IV_LEN - BLOCK_TAG_LEN, auth_data, sizeof(auth_data),
			(inputbuf ? inputbuf : buf) + nread - BLOCK_TAG_LEN, con->GetConfig()->GetGcmContentKey(), (inputbuf ? inputbuf : buf), ptbuf, openssl_crypt_context);
	}

	if (ptlen < 0) {  // return all zeros for un-authenticated blocks (might exist if file was resized without writing)

		// if we read all zeros, then it is (probably) really from a hole in the file

		if (is_all_zeros(inputbuf ? inputbuf : buf, nread)) {
			memset(ptbuf, 0, nread - (BLOCK_IV_LEN + BLOCK_TAG_LEN));
			return nread - (BLOCK_IV_LEN + BLOCK_TAG_LEN);
		} else {
			// if there are any non-zero bytes, then there is definitely corrupted data, so return an error
			SetLastError(ERROR_DATA_CHECKSUM_ERROR);
			return -1;
		}
	
	}

	return ptlen;
}
コード例 #9
0
ファイル: learn.c プロジェクト: asteven/openvswitch
void
learn_format(const struct nx_action_learn *learn, struct ds *s)
{
    struct cls_rule rule;
    const void *p, *end;

    cls_rule_init_catchall(&rule, 0);

    ds_put_format(s, "learn(table=%"PRIu8, learn->table_id);
    if (learn->idle_timeout != htons(OFP_FLOW_PERMANENT)) {
        ds_put_format(s, ",idle_timeout=%"PRIu16, ntohs(learn->idle_timeout));
    }
    if (learn->hard_timeout != htons(OFP_FLOW_PERMANENT)) {
        ds_put_format(s, ",hard_timeout=%"PRIu16, ntohs(learn->hard_timeout));
    }
    if (learn->fin_idle_timeout) {
        ds_put_format(s, ",fin_idle_timeout=%"PRIu16,
                      ntohs(learn->fin_idle_timeout));
    }
    if (learn->fin_hard_timeout) {
        ds_put_format(s, ",fin_hard_timeout=%"PRIu16,
                      ntohs(learn->fin_hard_timeout));
    }
    if (learn->priority != htons(OFP_DEFAULT_PRIORITY)) {
        ds_put_format(s, ",priority=%"PRIu16, ntohs(learn->priority));
    }
    if (learn->flags & htons(OFPFF_SEND_FLOW_REM)) {
        ds_put_cstr(s, ",OFPFF_SEND_FLOW_REM");
    }
    if (learn->flags & htons(~OFPFF_SEND_FLOW_REM)) {
        ds_put_format(s, ",***flags=%"PRIu16"***",
                      ntohs(learn->flags) & ~OFPFF_SEND_FLOW_REM);
    }
    if (learn->cookie != htonll(0)) {
        ds_put_format(s, ",cookie=0x%"PRIx64, ntohll(learn->cookie));
    }
    if (learn->pad != 0) {
        ds_put_cstr(s, ",***nonzero pad***");
    }

    end = (char *) learn + ntohs(learn->len);
    for (p = learn + 1; 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;
        struct mf_subfield src;
        const uint8_t *src_value;
        int src_value_bytes;

        int dst_type = header & NX_LEARN_DST_MASK;
        struct mf_subfield dst;

        enum ofperr error;
        int i;

        if (!header) {
            break;
        }

        error = learn_check_header(header, (char *) end - (char *) p);
        if (error == OFPERR_OFPBAC_BAD_ARGUMENT) {
            ds_put_format(s, ",***bad flow_mod_spec header %"PRIx16"***)",
                          header);
            return;
        } else if (error == OFPERR_OFPBAC_BAD_LEN) {
            ds_put_format(s, ",***flow_mod_spec at offset %td is %u bytes "
                          "long but only %td bytes are left***)",
                          (char *) p - (char *) (learn + 1) - 2,
                          learn_min_len(header) + 2,
                          (char *) end - (char *) p + 2);
            return;
        }
        assert(!error);

        /* Get the source. */
        if (src_type == NX_LEARN_SRC_FIELD) {
            get_subfield(n_bits, &p, &src);
            src_value_bytes = 0;
            src_value = NULL;
        } else {
            src.field = NULL;
            src.ofs = 0;
            src.n_bits = 0;
            src_value_bytes = 2 * DIV_ROUND_UP(n_bits, 16);
            src_value = p;
            p = (const void *) ((const uint8_t *) p + src_value_bytes);
        }

        /* Get the destination. */
        if (dst_type == NX_LEARN_DST_MATCH || dst_type == NX_LEARN_DST_LOAD) {
            get_subfield(n_bits, &p, &dst);
        } else {
            dst.field = NULL;
            dst.ofs = 0;
            dst.n_bits = 0;
        }

        ds_put_char(s, ',');

        switch (src_type | dst_type) {
        case NX_LEARN_SRC_IMMEDIATE | NX_LEARN_DST_MATCH:
            if (dst.field && dst.ofs == 0 && n_bits == dst.field->n_bits) {
                union mf_value value;
                uint8_t *bytes = (uint8_t *) &value;

                if (src_value_bytes > dst.field->n_bytes) {
                    /* The destination field is an odd number of bytes, which
                     * got rounded up to a multiple of 2 to be put into the
                     * learning action.  Skip over the leading byte, which
                     * should be zero anyway.  Otherwise the memcpy() below
                     * will overrun the start of 'value'. */
                    int diff = src_value_bytes - dst.field->n_bytes;
                    src_value += diff;
                    src_value_bytes -= diff;
                }

                memset(&value, 0, sizeof value);
                memcpy(&bytes[dst.field->n_bytes - src_value_bytes],
                       src_value, src_value_bytes);
                ds_put_format(s, "%s=", dst.field->name);
                mf_format(dst.field, &value, NULL, s);
            } else {
                mf_format_subfield(&dst, s);
                ds_put_cstr(s, "=0x");
                for (i = 0; i < src_value_bytes; i++) {
                    ds_put_format(s, "%02"PRIx8, src_value[i]);
                }
            }
            break;

        case NX_LEARN_SRC_FIELD | NX_LEARN_DST_MATCH:
            mf_format_subfield(&dst, s);
            if (src.field != dst.field || src.ofs != dst.ofs) {
                ds_put_char(s, '=');
                mf_format_subfield(&src, s);
            }
            break;

        case NX_LEARN_SRC_IMMEDIATE | NX_LEARN_DST_LOAD:
            ds_put_cstr(s, "load:0x");
            for (i = 0; i < src_value_bytes; i++) {
                ds_put_format(s, "%02"PRIx8, src_value[i]);
            }
            ds_put_cstr(s, "->");
            mf_format_subfield(&dst, s);
            break;

        case NX_LEARN_SRC_FIELD | NX_LEARN_DST_LOAD:
            ds_put_cstr(s, "load:");
            mf_format_subfield(&src, s);
            ds_put_cstr(s, "->");
            mf_format_subfield(&dst, s);
            break;

        case NX_LEARN_SRC_FIELD | NX_LEARN_DST_OUTPUT:
            ds_put_cstr(s, "output:");
            mf_format_subfield(&src, s);
            break;
        }
    }
    if (!is_all_zeros(p, (char *) end - (char *) p)) {
        ds_put_cstr(s, ",***nonzero trailer***");
    }
    ds_put_char(s, ')');
}
コード例 #10
0
ファイル: learn.c プロジェクト: asteven/openvswitch
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);
}
コード例 #11
0
ファイル: learn.c プロジェクト: asteven/openvswitch
/* Checks that 'learn' (which must be at least 'sizeof *learn' bytes long) is a
 * valid action on 'flow'. */
enum ofperr
learn_check(const struct nx_action_learn *learn, const struct flow *flow)
{
    struct cls_rule rule;
    const void *p, *end;

    cls_rule_init_catchall(&rule, 0);

    if (learn->flags & ~htons(OFPFF_SEND_FLOW_REM)
        || learn->pad
        || learn->table_id == 0xff) {
        return OFPERR_OFPBAC_BAD_ARGUMENT;
    }

    end = (char *) learn + ntohs(learn->len);
    for (p = learn + 1; 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;

        enum ofperr error;
        uint64_t value;

        if (!header) {
            break;
        }

        error = learn_check_header(header, (char *) end - (char *) p);
        if (error) {
            return error;
        }

        /* Check the source. */
        if (src_type == NX_LEARN_SRC_FIELD) {
            struct mf_subfield src;

            get_subfield(n_bits, &p, &src);
            error = mf_check_src(&src, flow);
            if (error) {
                return error;
            }
            value = 0;
        } else {
            value = get_bits(n_bits, &p);
        }

        /* Check the destination. */
        if (dst_type == NX_LEARN_DST_MATCH || dst_type == NX_LEARN_DST_LOAD) {
            struct mf_subfield dst;

            get_subfield(n_bits, &p, &dst);
            error = (dst_type == NX_LEARN_DST_LOAD
                     ? mf_check_dst(&dst, &rule.flow)
                     : mf_check_src(&dst, &rule.flow));
            if (error) {
                return error;
            }

            if (dst_type == NX_LEARN_DST_MATCH
                && src_type == NX_LEARN_SRC_IMMEDIATE) {
                if (n_bits <= 64) {
                    mf_set_subfield(&dst, value, &rule);
                } else {
                    /* We're only setting subfields to allow us to check
                     * prerequisites.  No prerequisite depends on the value of
                     * a field that is wider than 64 bits.  So just skip
                     * setting it entirely. */
                    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
                }
            }
        }
    }
    if (!is_all_zeros(p, (char *) end - (char *) p)) {
        return OFPERR_OFPBAC_BAD_ARGUMENT;
    }

    return 0;
}
コード例 #12
0
ファイル: learn.c プロジェクト: Grim-lock/ovs
/* Composes 'fm' so that executing it will implement 'learn' given that the
 * packet being processed has 'flow' as its flow.
 *
 * Uses 'ofpacts' to store the flow mod's actions.  The caller must initialize
 * 'ofpacts' and retains ownership of it.  'fm->ofpacts' will point into the
 * 'ofpacts' buffer.
 *
 * The caller has to actually execute 'fm'. */
void
learn_execute(const struct ofpact_learn *learn, const struct flow *flow,
              struct ofputil_flow_mod *fm, struct ofpbuf *ofpacts)
{
    const struct ofpact_learn_spec *spec;

    match_init_catchall(&fm->match);
    fm->priority = learn->priority;
    fm->cookie = htonll(0);
    fm->cookie_mask = htonll(0);
    fm->new_cookie = learn->cookie;
    fm->modify_cookie = fm->new_cookie != OVS_BE64_MAX;
    fm->table_id = learn->table_id;
    fm->command = OFPFC_MODIFY_STRICT;
    fm->idle_timeout = learn->idle_timeout;
    fm->hard_timeout = learn->hard_timeout;
    fm->importance = 0;
    fm->buffer_id = UINT32_MAX;
    fm->out_port = OFPP_NONE;
    fm->ofpacts_tlv_bitmap = 0;
    fm->flags = 0;
    if (learn->flags & NX_LEARN_F_SEND_FLOW_REM) {
        fm->flags |= OFPUTIL_FF_SEND_FLOW_REM;
    }
    fm->ofpacts = NULL;
    fm->ofpacts_len = 0;

    if (learn->fin_idle_timeout || learn->fin_hard_timeout) {
        struct ofpact_fin_timeout *oft;

        oft = ofpact_put_FIN_TIMEOUT(ofpacts);
        oft->fin_idle_timeout = learn->fin_idle_timeout;
        oft->fin_hard_timeout = learn->fin_hard_timeout;
    }

    OFPACT_LEARN_SPEC_FOR_EACH (spec, learn) {
        struct ofpact_set_field *sf;
        union mf_subvalue value;

        if (spec->src_type == NX_LEARN_SRC_FIELD) {
            mf_read_subfield(&spec->src, flow, &value);
        } else {
            mf_subvalue_from_value(&spec->dst, &value,
                                   ofpact_learn_spec_imm(spec));
        }

        switch (spec->dst_type) {
        case NX_LEARN_DST_MATCH:
            mf_write_subfield(&spec->dst, &value, &fm->match);
            match_add_ethernet_prereq(&fm->match, spec->dst.field);
            mf_vl_mff_set_tlv_bitmap(
                spec->dst.field, &fm->match.flow.tunnel.metadata.present.map);
            break;

        case NX_LEARN_DST_LOAD:
            sf = ofpact_put_reg_load(ofpacts, spec->dst.field, NULL, NULL);
            bitwise_copy(&value, sizeof value, 0,
                         sf->value, spec->dst.field->n_bytes, spec->dst.ofs,
                         spec->n_bits);
            bitwise_one(ofpact_set_field_mask(sf), spec->dst.field->n_bytes,
                        spec->dst.ofs, spec->n_bits);
            mf_vl_mff_set_tlv_bitmap(spec->dst.field, &fm->ofpacts_tlv_bitmap);
            break;

        case NX_LEARN_DST_OUTPUT:
            if (spec->n_bits <= 16
                || is_all_zeros(value.u8, sizeof value - 2)) {
                ofp_port_t port = u16_to_ofp(ntohll(value.integer));

                if (ofp_to_u16(port) < ofp_to_u16(OFPP_MAX)
                    || port == OFPP_IN_PORT
                    || port == OFPP_FLOOD
                    || port == OFPP_LOCAL
                    || port == OFPP_ALL) {
                    ofpact_put_OUTPUT(ofpacts)->port = port;
                }
            }
            break;
        }
    }

    fm->ofpacts = ofpacts->data;
    fm->ofpacts_len = ofpacts->size;
}
コード例 #13
0
ファイル: bundle.c プロジェクト: MohanaPriya26/ovs-reviews
/* Checks that 'nab' specifies a bundle action which is supported by this
 * bundle module.  Uses the 'max_ports' parameter to validate each port using
 * ofputil_check_output_port().  Returns 0 if 'nab' is supported, otherwise an
 * OFPERR_* error code. */
enum ofperr
bundle_from_openflow(const struct nx_action_bundle *nab,
                     struct ofpbuf *ofpacts)
{
    static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
    struct ofpact_bundle *bundle;
    uint16_t subtype;
    uint32_t slave_type;
    size_t slaves_size, i;
    enum ofperr error;

    bundle = ofpact_put_BUNDLE(ofpacts);

    subtype = ntohs(nab->subtype);
    bundle->n_slaves = ntohs(nab->n_slaves);
    bundle->basis = ntohs(nab->basis);
    bundle->fields = ntohs(nab->fields);
    bundle->algorithm = ntohs(nab->algorithm);
    slave_type = ntohl(nab->slave_type);
    slaves_size = ntohs(nab->len) - sizeof *nab;

    error = OFPERR_OFPBAC_BAD_ARGUMENT;
    if (!flow_hash_fields_valid(bundle->fields)) {
        VLOG_WARN_RL(&rl, "unsupported fields %d", (int) bundle->fields);
    } else if (bundle->n_slaves > BUNDLE_MAX_SLAVES) {
        VLOG_WARN_RL(&rl, "too may slaves");
    } else if (bundle->algorithm != NX_BD_ALG_HRW
               && bundle->algorithm != NX_BD_ALG_ACTIVE_BACKUP) {
        VLOG_WARN_RL(&rl, "unsupported algorithm %d", (int) bundle->algorithm);
    } else if (slave_type != NXM_OF_IN_PORT) {
        VLOG_WARN_RL(&rl, "unsupported slave type %"PRIu16, slave_type);
    } else {
        error = 0;
    }

    if (!is_all_zeros(nab->zero, sizeof nab->zero)) {
        VLOG_WARN_RL(&rl, "reserved field is nonzero");
        error = OFPERR_OFPBAC_BAD_ARGUMENT;
    }

    if (subtype == NXAST_BUNDLE && (nab->ofs_nbits || nab->dst)) {
        VLOG_WARN_RL(&rl, "bundle action has nonzero reserved fields");
        error = OFPERR_OFPBAC_BAD_ARGUMENT;
    }

    if (subtype == NXAST_BUNDLE_LOAD) {
        bundle->dst.field = mf_from_nxm_header(ntohl(nab->dst));
        bundle->dst.ofs = nxm_decode_ofs(nab->ofs_nbits);
        bundle->dst.n_bits = nxm_decode_n_bits(nab->ofs_nbits);

        if (bundle->dst.n_bits < 16) {
            VLOG_WARN_RL(&rl, "bundle_load action requires at least 16 bit "
                         "destination.");
            error = OFPERR_OFPBAC_BAD_ARGUMENT;
        }
    }

    if (slaves_size < bundle->n_slaves * sizeof(ovs_be16)) {
        VLOG_WARN_RL(&rl, "Nicira action %"PRIu16" only has %"PRIuSIZE" bytes "
                     "allocated for slaves.  %"PRIuSIZE" bytes are required for "
                     "%"PRIu16" slaves.", subtype, slaves_size,
                     bundle->n_slaves * sizeof(ovs_be16), bundle->n_slaves);
        error = OFPERR_OFPBAC_BAD_LEN;
    }

    for (i = 0; i < bundle->n_slaves; i++) {
        uint16_t ofp_port = ntohs(((ovs_be16 *)(nab + 1))[i]);
        ofpbuf_put(ofpacts, &ofp_port, sizeof ofp_port);
    }

    bundle = ofpacts->l2;
    ofpact_update_len(ofpacts, &bundle->ofpact);

    if (!error) {
        error = bundle_check(bundle, OFPP_MAX, NULL);
    }
    return error;
}
コード例 #14
0
/* Checks that 'learn' (which must be at least 'sizeof *learn' bytes long) is a
 * valid action on 'flow'. */
int
learn_check(const struct nx_action_learn *learn, const struct flow *flow)
{
    struct cls_rule rule;
    const void *p, *end;

    cls_rule_init_catchall(&rule, 0);

    if (learn->flags & ~htons(OFPFF_SEND_FLOW_REM)
        || !is_all_zeros(learn->pad, sizeof learn->pad)
        || learn->table_id == 0xff) {
        return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT);
    }

    end = (char *) learn + ntohs(learn->len);
    for (p = learn + 1; 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;
        int error;

        if (!header) {
            break;
        }

        error = learn_check_header(header, (char *) end - (char *) p);
        if (error) {
            return error;
        }

        /* Check the source. */
        if (src_type == NX_LEARN_SRC_FIELD) {
            ovs_be32 src_field = get_be32(&p);
            int src_ofs = ntohs(get_be16(&p));

            error = nxm_src_check(src_field, src_ofs, n_bits, flow);
            if (error) {
                return error;
            }
            value = 0;
        } else {
            value = get_bits(n_bits, &p);
        }

        /* Check the destination. */
        if (dst_type == NX_LEARN_DST_MATCH || dst_type == NX_LEARN_DST_LOAD) {
            ovs_be32 dst_field = get_be32(&p);
            int dst_ofs = ntohs(get_be16(&p));
            int error;

            error = (dst_type == NX_LEARN_DST_LOAD
                     ? nxm_dst_check(dst_field, dst_ofs, n_bits, &rule.flow)
                     : nxm_src_check(dst_field, dst_ofs, n_bits, &rule.flow));
            if (error) {
                return error;
            }

            if (dst_type == NX_LEARN_DST_MATCH
                && src_type == NX_LEARN_SRC_IMMEDIATE) {
                mf_set_subfield(mf_from_nxm_header(ntohl(dst_field)), value,
                                dst_ofs, n_bits, &rule);
            }
        }
    }
    if (!is_all_zeros(p, (char *) end - (char *) p)) {
        return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT);
    }

    return 0;
}