summaryrefslogtreecommitdiffstats
path: root/qemu/fsdev/Makefile.objs
blob: 1b120a4a7d4714d14440d5f1353d30fb196e2c1a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy)
# Lots of the fsdev/9pcode is pulled in by vl.c via qemu_fsdev_add.
# only pull in the actual virtio-9p device if we also enabled virtio.
common-obj-y = qemu-fsdev.o 9p-marshal.o 9p-iov-marshal.o
else
common-obj-y = qemu-fsdev-dummy.o
endif
common-obj-y += qemu-fsdev-opts.o

# Toplevel always builds this; targets without virtio will put it in
# common-obj-y
common-obj-$(CONFIG_ALL) += qemu-fsdev-dummy.o
l { color: #ae81ff } /* Literal */ .highlight .n { color: #f8f8f2 } /* Name */ .highlight .o { color: #f92672 } /* Operator */ .highlight .p { color: #f8f8f2 } /* Punctuation */ .highlight .ch { color: #75715e } /* Comment.Hashbang */ .highlight .cm { color: #75715e } /* Comment.Multiline */ .highlight .cp { color: #75715e } /* Comment.Preproc */ .highlight .cpf { color: #75715e } /* Comment.PreprocFile */ .highlight .c1 { color: #75715e } /* Comment.Single */ .highlight .cs { color: #75715e } /* Comment.Special */ .highlight .gd { color: #f92672 } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .gi { color: #a6e22e } /* Generic.Inserted */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #75715e } /* Generic.Subheading */ .highlight .kc { color: #66d9ef } /* Keyword.Constant */ .highlight .kd { color: #66d9ef } /* Keyword.Declaration */ .highlight .kn { color: #f92672 } /* Keyword.Namespace */ .highlight .kp { color: #66d9ef } /* Keyword.Pseudo */ .highlight .kr { color: #66d9ef } /* Keyword.Reserved */ .highlight .kt { color: #66d9ef } /* Keyword.Type */ .highlight .ld { color: #e6db74 } /* Literal.Date */ .highlight .m { color: #ae81ff } /* Literal.Number */ .highlight .s { color: #e6db74 } /* Literal.String */ .highlight .na { color: #a6e22e } /* Name.Attribute */ .highlight .nb { color: #f8f8f2 } /* Name.Builtin */ .highlight .nc { color: #a6e22e } /* Name.Class */ .highlight .no { color: #66d9ef } /* Name.Constant */ .highlight .nd { color: #a6e22e } /* Name.Decorator */ .highlight .ni { color: #f8f8f2 } /* Name.Entity */ .highlight .ne { color: #a6e22e } /* Name.Exception */ .highlight .nf { color: #a6e22e } /* Name.Function */ .highlight .nl { color: #f8f8f2 } /* Name.Label */ .highlight .nn { color: #f8f8f2 } /* Name.Namespace */ .highlight .nx { color: #a6e22e } /* Name.Other */ .highlight .py { color: #f8f8f2 } /* Name.Property */ .highlight .nt { color: #f92672 } /* Name.Tag */ .highlight .nv { color: #f8f8f2 } /* Name.Variable */ .highlight .ow { color: #f92672 } /* Operator.Word */ .highlight .w { color: #f8f8f2 } /* Text.Whitespace */ .highlight .mb { color: #ae81ff } /* Literal.Number.Bin */ .highlight .mf { color: #ae81ff } /* Literal.Number.Float */ .highlight .mh { color: #ae81ff } /* Literal.Number.Hex */ .highlight .mi { color: #ae81ff } /* Literal.Number.Integer */ .highlight .mo { color: #ae81ff } /* Literal.Number.Oct */ .highlight .sa { color: #e6db74 } /* Literal.String.Affix */ .highlight .sb { color: #e6db74 } /* Literal.String.Backtick */ .highlight .sc { color: #e6db74 } /* Literal.String.Char */ .highlight .dl { color: #e6db74 } /* Literal.String.Delimiter */ .highlight .sd { color: #e6db74 } /* Literal.String.Doc */ .highlight .s2 { color: #e6db74 } /* Literal.String.Double */ .highlight .se { color: #ae81ff } /* Literal.String.Escape */ .highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */ .highlight .si { color: #e6db74 } /* Literal.String.Interpol */ .highlight .sx { color: #e6db74 } /* Literal.String.Other */ .highlight .sr { color: #e6db74 } /* Literal.String.Regex */ .highlight .s1 { color: #e6db74 } /* Literal.String.Single */ .highlight .ss { color: #e6db74 } /* Literal.String.Symbol */ .highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #a6e22e } /* Name.Function.Magic */ .highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */ .highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */ .highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */ .highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */ .highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */ } @media (prefers-color-scheme: light) { .highlight .hll { background-color: #ffffcc } .highlight .c { color: #888888 } /* Comment */ .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ .highlight .k { color: #008800; font-weight: bold } /* Keyword */ .highlight .ch { color: #888888 } /* Comment.Hashbang */ .highlight .cm { color: #888888 } /* Comment.Multiline */ .highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */ .highlight .cpf { color: #888888 } /* Comment.PreprocFile */ .highlight .c1 { color: #888888 } /* Comment.Single */ .highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */ .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .gr { color: #aa0000 } /* Generic.Error */ .highlight .gh { color: #333333 } /* Generic.Heading */ .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */ }
/*
// Copyright (c) 2010-2017 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
*/

#include <rte_mbuf.h>
#include <rte_acl.h>
#include <rte_ip.h>
#include <rte_cycles.h>
#include <rte_version.h>

#include "prox_lua.h"
#include "prox_lua_types.h"

#include "log.h"
#include "quit.h"
#include "parse_utils.h"
#include "ip_subnet.h"
#include "handle_acl.h"
#include "acl_field_def.h"
#include "task_init.h"
#include "task_base.h"
#include "lconf.h"
#include "prefetch.h"
#include "etypes.h"
#include "prox_compat.h"
#include "handle_sched.h"

struct task_acl {
	struct task_base base;
	struct rte_acl_ctx *context;
	const uint8_t *ptuples[64];

	uint32_t       n_rules;
	uint32_t       n_max_rules;

	void           *field_defs;
	size_t         field_defs_size;
	uint32_t       n_field_defs;
	struct rte_sched_port *sched_port;
};

static void set_tc(struct task_base *tbase, struct rte_mbuf *mbuf, uint32_t tc)
{
	struct task_acl *task = (struct task_acl *)tbase;
#if RTE_VERSION >= RTE_VERSION_NUM(1,8,0,0)
	uint32_t subport, pipe, traffic_class, queue;
	enum prox_rte_color color;

	prox_rte_sched_port_pkt_read_tree_path(task->sched_port, mbuf, &subport, &pipe, &traffic_class, &queue);
	color = rte_sched_port_pkt_read_color(mbuf);

	prox_rte_sched_port_pkt_write(task->sched_port, mbuf, subport, pipe, tc, queue, color);
#else
	struct rte_sched_port_hierarchy *sched =
		(struct rte_sched_port_hierarchy *) &mbuf->pkt.hash.sched;
	sched->traffic_class = tc;
#endif
}

static int handle_acl_bulk(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts)
{
	struct task_acl *task = (struct task_acl *)tbase;
	uint32_t results[64];
	uint8_t out[MAX_PKT_BURST];
	uint16_t j;

#ifdef PROX_PREFETCH_OFFSET
	for (j = 0; j < PROX_PREFETCH_OFFSET && j < n_pkts; ++j) {
		PREFETCH0(mbufs[j]);
	}
	for (j = 1; j < PROX_PREFETCH_OFFSET && j < n_pkts; ++j) {
		PREFETCH0(rte_pktmbuf_mtod(mbufs[j - 1], void *));
	}
#endif
	for (j = 0; j + PREFETCH_OFFSET < n_pkts; ++j) {
#ifdef PROX_PREFETCH_OFFSET
		PREFETCH0(mbufs[j + PREFETCH_OFFSET]);
		PREFETCH0(rte_pktmbuf_mtod(mbufs[j + PREFETCH_OFFSET - 1], void *));
#endif
		/* TODO: detect version_ihl != 0x45. Extract relevant
		   fields of that packet and point ptuples[j] to the
		   extracted verion. Note that this is very unlikely. */
		task->ptuples[j] = rte_pktmbuf_mtod(mbufs[j], uint8_t *);
	}
#ifdef PROX_PREFETCH_OFFSET
	PREFETCH0(rte_pktmbuf_mtod(mbufs[n_pkts - 1], void *));
	for (; j < n_pkts; ++j) {
		task->ptuples[j] = rte_pktmbuf_mtod(mbufs[j], uint8_t *);
	}
#endif

	rte_acl_classify(task->context, (const uint8_t **)task->ptuples, results, n_pkts, 1);

	for (uint8_t i = 0; i < n_pkts; ++i) {
		switch (results[i]) {
		default:
		case ACL_NOT_SET:
		case ACL_DROP:
			out[i] = OUT_DISCARD;
			break;
		case ACL_ALLOW:
			out[i] = 0;
			// __attribute__ ((fallthrough));
		case ACL_RATE_LIMIT:
			set_tc(tbase, mbufs[i], 3);
			break;
		};
	}

	return task->base.tx_pkt(&task->base, mbufs, n_pkts, out);
}

static void acl_msg(struct task_base *tbase, void **data, uint16_t n_msgs)
{
	struct task_acl *task = (struct task_acl *)tbase;
	struct acl4_rule **new_rules = (struct acl4_rule **)data;
	uint16_t i;

	for (i = 0; i < n_msgs; ++i) {
		if (task->n_rules == task->n_max_rules) {
			plog_err("Failed to add %d rule%s (already at maximum number of rules (%d))",
				n_msgs - i, (n_msgs - i)? "s" : "", task->n_max_rules);
			break;
		}

		new_rules[i]->data.priority = ++task->n_rules;
		rte_acl_add_rules(task->context, (struct rte_acl_rule*) new_rules[i], 1);
	}

	/* No need to rebuild if no rules have been added */
	if (!i) {
		return ;
	}

	struct rte_acl_config acl_build_param;
	/* Perform builds */
	acl_build_param.num_categories = 1;

	acl_build_param.num_fields = task->n_field_defs;
	rte_memcpy(&acl_build_param.defs, task->field_defs, task->field_defs_size);

	int ret;
	PROX_PANIC((ret = rte_acl_build(task->context, &acl_build_param)),
		   "Failed to build ACL trie (%d)\n", ret);
}

static void init_task_acl(struct task_base *tbase, struct task_args *targ)
{
	struct task_acl *task = (struct task_acl *)tbase;
	int use_qinq = targ->flags & TASK_ARG_QINQ_ACL;

	char name[PATH_MAX];
	struct rte_acl_param acl_param;

	/* Create ACL contexts */
	snprintf(name, sizeof(name), "acl-%d-%d", targ->lconf->id, targ->task);

	if (use_qinq) {
		task->n_field_defs    = RTE_DIM(pkt_qinq_ipv4_udp_defs);
		task->field_defs      = pkt_qinq_ipv4_udp_defs;
		task->field_defs_size = sizeof(pkt_qinq_ipv4_udp_defs);
	} else {
		task->n_field_defs    = RTE_DIM(pkt_eth_ipv4_udp_defs);
		task->field_defs      = pkt_eth_ipv4_udp_defs;
		task->field_defs_size = sizeof(pkt_eth_ipv4_udp_defs);
	}

	acl_param.name = name;
	acl_param.socket_id = rte_lcore_to_socket_id(targ->lconf->id);
	acl_param.rule_size = RTE_ACL_RULE_SZ(task->n_field_defs);
	acl_param.max_rule_num = targ->n_max_rules;

	task->n_max_rules = targ->n_max_rules;
	task->context = rte_acl_create(&acl_param);

	PROX_PANIC(task->context == NULL, "Failed to create ACL context\n");
	uint32_t free_rules = targ->n_max_rules;

	PROX_PANIC(!strcmp(targ->rules, ""), "No rule specified for ACL\n");

	int ret = lua_to_rules(prox_lua(), GLOBAL, targ->rules, task->context, &free_rules, use_qinq, targ->qinq_tag);
	PROX_PANIC(ret, "Failed to read rules from config:\n%s\n", get_lua_to_errors());
	task->n_rules = targ->n_max_rules - free_rules;

	plog_info("Configured %d rules\n", task->n_rules);

	if (task->n_rules) {
		struct rte_acl_config acl_build_param;
		/* Perform builds */
		acl_build_param.num_categories = 1;
#if RTE_VERSION >= RTE_VERSION_NUM(2,1,0,0)
		acl_build_param.max_size = 0;
#endif

		acl_build_param.num_fields = task->n_field_defs;
		rte_memcpy(&acl_build_param.defs, task->field_defs, task->field_defs_size);

		plog_info("Building trie structure\n");
		PROX_PANIC(rte_acl_build(task->context, &acl_build_param),
			   "Failed to build ACL trie\n");
	}

	targ->lconf->ctrl_timeout = freq_to_tsc(targ->ctrl_freq);
	targ->lconf->ctrl_func_m[targ->task] = acl_msg;

	// If rate limiting is used tc will be set, sched_port must be initialized, and tc will be used by a following policing or qos task
	int rc = init_port_sched(&task->sched_port, targ);

	// ACL can be used to accept/drop packets and/or to set rate limiting. If using rate limiting, then sched_port must be defined
	// TODO: check whether rate limiting is configured, and, if yes, check that QoS or policing task configures the qos_conf.params.
	if (rc)
		plog_info("Did not find any QoS or Policing task to transmit to => setting tc will not work\n");
}

int str_to_rule(struct acl4_rule *rule, char** fields, int n_rules, int use_qinq)
{
	uint32_t svlan, svlan_mask;
	uint32_t cvlan, cvlan_mask;

	uint32_t ip_proto, ip_proto_mask;

	struct ip4_subnet ip_src;
	struct ip4_subnet ip_dst;

	uint32_t sport_lo, sport_hi;
	uint32_t dport_lo, dport_hi;

	enum acl_action class = ACL_NOT_SET;
	char class_str[24];

	PROX_PANIC(parse_int_mask(&svlan, &svlan_mask, fields[0]), "Error parsing svlan: %s\n", get_parse_err());
	PROX_PANIC(parse_int_mask(&cvlan, &cvlan_mask, fields[1]), "Error parsing cvlan: %s\n", get_parse_err());
	PROX_PANIC(parse_int_mask(&ip_proto, &ip_proto_mask, fields[2]), "Error parsing ip protocol: %s\n", get_parse_err());
	PROX_PANIC(parse_ip4_cidr(&ip_src, fields[3]), "Error parsing source IP subnet: %s\n", get_parse_err());
	PROX_PANIC(parse_ip4_cidr(&ip_dst, fields[4]), "Error parsing dest IP subnet: %s\n", get_parse_err());

	PROX_PANIC(parse_range(&sport_lo, &sport_hi, fields[5]), "Error parsing source port range: %s\n", get_parse_err());
	PROX_PANIC(parse_range(&dport_lo, &dport_hi, fields[6]), "Error parsing destination port range: %s\n", get_parse_err());

	PROX_PANIC(parse_str(class_str, fields[7], sizeof(class_str)), "Error parsing action: %s\n", get_parse_err());

	if (!strcmp(class_str, "drop")) {
		class = ACL_DROP;
	}
	else if (!strcmp(class_str, "allow")) {
		class = ACL_ALLOW;
	}
	else if (!strcmp(class_str, "rate limit")) {
		class = ACL_RATE_LIMIT;
	}
	else {
		plog_err("unknown class type: %s\n", class_str);
	}

	rule->data.userdata = class; /* allow, drop or ratelimit */
	rule->data.category_mask = 1;
	rule->data.priority = n_rules;

	/* Configuration for rules is done in little-endian so no bswap is needed here.. */

	rule->fields[0].value.u8 = ip_proto;
	rule->fields[0].mask_range.u8 = ip_proto_mask;
	rule->fields[1].value.u32 = ip_src.ip;
	rule->fields[1].mask_range.u32 = ip_src.prefix;

	rule->fields[2].value.u32 = ip_dst.ip;
	rule->fields[2].mask_range.u32 = ip_dst.prefix;

	rule->fields[3].value.u16 = sport_lo;
	rule->fields[3].mask_range.u16 = sport_hi;

	rule->fields[4].value.u16 = dport_lo;
	rule->fields[4].mask_range.u16 = dport_hi;

	if (use_qinq) {
		rule->fields[5].value.u16 = rte_bswap16(ETYPE_8021ad);
		rule->fields[5].mask_range.u16 = 0xffff;

		/* To mask out the TCI and only keep the VID, the mask should be 0x0fff */
		rule->fields[6].value.u16 = svlan;
		rule->fields[6].mask_range.u16 = svlan_mask;

		rule->fields[7].value.u16 = rte_bswap16(ETYPE_VLAN);
		rule->fields[7].mask_range.u16 = 0xffff;

		rule->fields[8].value.u16 = cvlan;
		rule->fields[8].mask_range.u16 = cvlan_mask;
	}
	else {
		/* Reuse first ethertype from vlan to check if packet is IPv4 packet */
		rule->fields[5].value.u16 =  rte_bswap16(ETYPE_IPv4);
		rule->fields[5].mask_range.u16 = 0xffff;

		/* Other fields are ignored */
		rule->fields[6].value.u16 = 0;
		rule->fields[6].mask_range.u16 = 0;
		rule->fields[7].value.u16 = 0;
		rule->fields[7].mask_range.u16 = 0;
		rule->fields[8].value.u16 = 0;
		rule->fields[8].mask_range.u16 = 0;
	}
	return 0;
}

static struct task_init task_init_acl = {
	.mode_str = "acl",
	.init = init_task_acl,
	.handle = handle_acl_bulk,
	.size = sizeof(struct task_acl)
};

__attribute__((constructor)) static void reg_task_acl(void)
{
	reg_task(&task_init_acl);
}