Beispiel #1
0
static int fill_ematch_sequence(struct nl_msg *msg, struct nl_list_head *list)
{
	struct rtnl_ematch *e;

	nl_list_for_each_entry(e, list, e_list) {
		struct tcf_ematch_hdr match = {
			.matchid = e->e_id,
			.kind = e->e_kind,
			.flags = e->e_flags,
		};
		struct nlattr *attr;
		int err = 0;

		if (!(attr = nla_nest_start(msg, e->e_index + 1)))
			return -NLE_NOMEM;

		if (nlmsg_append(msg, &match, sizeof(match), 0) < 0)
			return -NLE_NOMEM;

		if (e->e_ops->eo_fill)
			err = e->e_ops->eo_fill(e, msg);
		else if (e->e_flags & TCF_EM_SIMPLE)
			err = nlmsg_append(msg, e->e_data, 4, 0);
		else if (e->e_datalen > 0)
			err = nlmsg_append(msg, e->e_data, e->e_datalen, 0);

		NL_DBG(3, "msg %p: added ematch [%d] id=%d kind=%d flags=%d\n",
			  msg, e->e_index, match.matchid, match.kind, match.flags);

		if (err < 0)
			return -NLE_NOMEM;

		nla_nest_end(msg, attr);
	}

	nl_list_for_each_entry(e, list, e_list) {
		if (e->e_kind == TCF_EM_CONTAINER &&
		    fill_ematch_sequence(msg, &e->e_childs) < 0)
			return -NLE_NOMEM;
	}

	return 0;
}

int rtnl_ematch_fill_attr(struct nl_msg *msg, int attrid,
			  struct rtnl_ematch_tree *tree)
{
	struct tcf_ematch_tree_hdr thdr = {
		.progid = tree->et_progid,
	};
	struct nlattr *list, *topattr;
	int err, index = 0;

	/* Assign index number to each ematch to allow for references
	 * to be made while constructing the sequence of matches. */
	err = update_container_index(&tree->et_list, &index);
	if (err < 0)
		return err;

	if (!(topattr = nla_nest_start(msg, attrid)))
		goto nla_put_failure;

	thdr.nmatches = index;
	NLA_PUT(msg, TCA_EMATCH_TREE_HDR, sizeof(thdr), &thdr);

	if (!(list = nla_nest_start(msg, TCA_EMATCH_TREE_LIST)))
		goto nla_put_failure;

	if (fill_ematch_sequence(msg, &tree->et_list) < 0)
		goto nla_put_failure;

	nla_nest_end(msg, list);

	nla_nest_end(msg, topattr);

	return 0;

nla_put_failure:
	return -NLE_NOMEM;
}

/** @} */

extern int ematch_parse(void *, char **, struct nl_list_head *);

int rtnl_ematch_parse_expr(const char *expr, char **errp,
			   struct rtnl_ematch_tree **result)
{
	struct rtnl_ematch_tree *tree;
	YY_BUFFER_STATE buf = NULL;
	yyscan_t scanner = NULL;
	int err;

	NL_DBG(2, "Parsing ematch expression \"%s\"\n", expr);

	if (!(tree = rtnl_ematch_tree_alloc(RTNL_EMATCH_PROGID)))
		return -NLE_FAILURE;

	if ((err = ematch_lex_init(&scanner)) < 0) {
		err = -NLE_FAILURE;
		goto errout;
	}

	buf = ematch__scan_string(expr, scanner);

	if ((err = ematch_parse(scanner, errp, &tree->et_list)) != 0) {
		ematch__delete_buffer(buf, scanner);
		err = -NLE_PARSE_ERR;
		goto errout;
	}

	ematch_lex_destroy(scanner);
	*result = tree;

	return 0;

errout:
	if (scanner)
		ematch_lex_destroy(scanner);

	rtnl_ematch_tree_free(tree);

	return err;
}

static const char *layer_txt[] = {
	[TCF_LAYER_LINK]	= "eth",
	[TCF_LAYER_NETWORK]	= "ip",
	[TCF_LAYER_TRANSPORT]	= "tcp",
};

char *rtnl_ematch_offset2txt(uint8_t layer, uint16_t offset, char *buf, size_t len)
{
	snprintf(buf, len, "%s+%u",
		 (layer <= TCF_LAYER_MAX) ? layer_txt[layer] : "?",
		 offset);

	return buf;
}

static const char *operand_txt[] = {
	[TCF_EM_OPND_EQ] = "=",
	[TCF_EM_OPND_LT] = "<",
	[TCF_EM_OPND_GT] = ">",
};

char *rtnl_ematch_opnd2txt(uint8_t opnd, char *buf, size_t len)
{
	snprintf(buf, len, "%s",
		opnd < ARRAY_SIZE(operand_txt) ? operand_txt[opnd] : "?");

	return buf;
}
Beispiel #2
0
int parse_ematch(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n)
{
	begin_argc = ematch_argc = *argc_p;
	begin_argv = ematch_argv = *argv_p;

	if (ematch_parse()) {
		int err = em_parse_error(EINVAL, NULL, NULL, NULL,
		    "Parse error");
		free_ematch_err();
		return err;
	}

	free_ematch_err();

	/* undo look ahead by parser */
	ematch_argc++;
	ematch_argv--;

	if (ematch_root) {
		struct rtattr *tail, *tail_list;

		struct tcf_ematch_tree_hdr hdr = {
			.nmatches = flatten_tree(ematch_root, ematch_root),
			.progid = TCF_EM_PROG_TC
		};

		tail = NLMSG_TAIL(n);
		addattr_l(n, MAX_MSG, tca_id, NULL, 0);
		addattr_l(n, MAX_MSG, TCA_EMATCH_TREE_HDR, &hdr, sizeof(hdr));

		tail_list = NLMSG_TAIL(n);
		addattr_l(n, MAX_MSG, TCA_EMATCH_TREE_LIST, NULL, 0);

		if (parse_tree(n, ematch_root) < 0)
			return -1;

		tail_list->rta_len = (void*) NLMSG_TAIL(n) - (void*) tail_list;
		tail->rta_len = (void*) NLMSG_TAIL(n) - (void*) tail;
	}

	*argc_p = ematch_argc;
	*argv_p = ematch_argv;

	return 0;
}

static int print_ematch_seq(FILE *fd, struct rtattr **tb, int start,
			    int prefix)
{
	int n, i = start;
	struct tcf_ematch_hdr *hdr;
	int dlen;
	void *data;

	for (;;) {
		if (tb[i] == NULL)
			return -1;

		dlen = RTA_PAYLOAD(tb[i]) - sizeof(*hdr);
		data = (void *) RTA_DATA(tb[i]) + sizeof(*hdr);

		if (dlen < 0)
			return -1;

		hdr = RTA_DATA(tb[i]);

		if (hdr->flags & TCF_EM_INVERT)
			fprintf(fd, "NOT ");

		if (hdr->kind == 0) {
			__u32 ref;

			if (dlen < sizeof(__u32))
				return -1;

			ref = *(__u32 *) data;
			fprintf(fd, "(\n");
			for (n = 0; n <= prefix; n++)
				fprintf(fd, "  ");
			if (print_ematch_seq(fd, tb, ref + 1, prefix + 1) < 0)
				return -1;
			for (n = 0; n < prefix; n++)
				fprintf(fd, "  ");
			fprintf(fd, ") ");

		} else {
			struct ematch_util *e;

			e = get_ematch_kind_num(hdr->kind);
			if (e == NULL)
				fprintf(fd, "[unknown ematch %d]\n",
				    hdr->kind);
			else {
				fprintf(fd, "%s(", e->kind);
				if (e->print_eopt(fd, hdr, data, dlen) < 0)
					return -1;
				fprintf(fd, ")\n");
			}
			if (hdr->flags & TCF_EM_REL_MASK)
				for (n = 0; n < prefix; n++)
					fprintf(fd, "  ");
		}

		switch (hdr->flags & TCF_EM_REL_MASK) {
			case TCF_EM_REL_AND:
				fprintf(fd, "AND ");
				break;

			case TCF_EM_REL_OR:
				fprintf(fd, "OR ");
				break;

			default:
				return 0;
		}

		i++;
	}

	return 0;
}