예제 #1
0
uint32_t match_pid_lookup(void)
{
	FILE *fd = fopen(MATCHLIB_PID_FILE, "r");
	uint32_t pid;
	int err;

	if (!fd) {
		MAT_LOG(ERR, "no hardware support, daemon is not listening\n");
		return 0;
	}

	err = fscanf(fd, "%" SCNu32 "", &pid);
	if (err < 0) {
		MAT_LOG(ERR, "Error: pid not found\n");
		return 0;
	}

	fclose(fd);
	return pid;
}
예제 #2
0
struct net_mat_hdr_node *match_nl_get_hdr_graph(struct nl_sock *nsd,
						uint32_t pid,
						unsigned int ifindex,
						int family)
{
	uint8_t cmd = NET_MAT_TABLE_CMD_GET_HDR_GRAPH;
	struct net_mat_hdr_node *hdr_nodes = NULL;
	struct match_msg *msg;

	msg = match_nl_get_msg(nsd, cmd, pid, ifindex, family);

	if (msg) {
		struct nlmsghdr *nlh = msg->msg;
		struct nlattr *tb[NET_MAT_MAX+1];
		int err;

		err = genlmsg_parse(nlh, 0, tb,
				    NET_MAT_MAX, match_get_tables_policy);
		if (err < 0) {
			MAT_LOG(ERR, "Warning: unable to parse get header graph msg\n");
			goto out;
		}

		if (match_nl_table_cmd_to_type(stdout, true,
					      NET_MAT_HEADER_GRAPH, tb))
			goto out;

		if (tb[NET_MAT_HEADER_GRAPH])
			match_get_hdrs_graph(stdout, verbose,
					    tb[NET_MAT_HEADER_GRAPH],
					    &hdr_nodes);
	}
	match_nl_free_msg(msg);
	return hdr_nodes;
out:
	match_nl_free_msg(msg);
	return NULL;
}
예제 #3
0
static int matchd_create_pid(void)
{
	pid_t pid = getpid();
	char buf[1024];
	int err, fd;
	ssize_t ret;
	char pidfile[1024] = MATCHLIB_PID_FILE;
	struct flock fl = { .l_type = F_WRLCK,
			    .l_whence = SEEK_SET,
			    .l_start = 0,
			    .l_len = 0};

	errno = 0;
	fd = open(pidfile, O_CLOEXEC | O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
	if (fd < 0) {
		perror("Cannot create pidfile\n");
		return errno;
	}

	errno = 0;
	err = fcntl(fd, F_SETLKW, &fl);
	if (err) {
		perror("Error setting F_SETLKW\n");
		close(fd);
		return errno;
	}

	errno = 0;
	err = ftruncate(fd, 0);
	if (err) {
		perror("ftruncate pidfile error\n");
		close(fd);
		return errno;
	}

	snprintf(buf, sizeof(buf), "%ld\n", (long) pid);
	errno = 0;
	ret = write(fd, buf, strlen(buf));
	if (ret < 0) {
		perror("Write pidfile error\n");
		close(fd);
		return errno;
	}

	close(fd);
	return 0;
}

static void matchd_int_handler(int sig __unused)
{
	MAT_LOG(DEBUG, "\nmatchd exiting...\n");

	matchd_uninit();

	if (remove(MATCHLIB_PID_FILE)) {
		MAT_LOG(ERR, "Cannot remove %s, exiting anyway\n",
		        MATCHLIB_PID_FILE);
	}

	exit(0);
}
예제 #4
0
static void matchd_usage(void)
{
	MAT_LOG(ERR, "matchd [-b backend] [-f family_id] [-h] [-l] [-s] [-v[v]]\n");
	MAT_LOG(ERR, "Options:\n");
	MAT_LOG(ERR, "  -b backend    name of backend to load (default: %s)\n", DEFAULT_BACKEND_NAME);
	MAT_LOG(ERR, "  -d            run as a daemon\n");
	MAT_LOG(ERR, "  -f family_id  netlink family id\n");
	MAT_LOG(ERR, "  -h            display this help and exit\n");
	MAT_LOG(ERR, "  -l            list available backends and exit\n");
	MAT_LOG(ERR, "  -s            add all ports to default vlan (ies_pipeline only)\n");
	MAT_LOG(ERR, "  -v            be verbose (enable info messages)\n");
	MAT_LOG(ERR, "  -vv           be very verbose (enable info+debug messages)\n");
	MAT_LOG(ERR, "  --version     display Match interface version and exit\n");
}
예제 #5
0
int main(int argc, char **argv)
{
	struct nl_sock *nsd;
	int family = NET_MAT_DFLT_FAMILY;
	struct sockaddr_nl dest_addr;
	unsigned char *buf;
	int rc = EXIT_SUCCESS;
	int err, opt;
	const char *backend = NULL;
	struct switch_args sw_args;
	struct sigaction sig_act;
	int verbose = 0;
	int opt_index = 0;
	static struct option long_options[] = {
		{ "version", no_argument, NULL, 0 },
		{ 0, 0, 0, 0}
	};

	memset(&sw_args, 0, sizeof(sw_args));

	while ((opt = getopt_long(argc, argv, "b:f:vhls", long_options,
	                          &opt_index)) != -1) {
		switch (opt) {
		case 0:
			if (!strcmp(long_options[opt_index].name, "version")) {
				printf("Match Version: %s\n", match_version());
				exit(0);
			}
			break;
		case 'b':
			backend = optarg;
			break;
		case 'f':
			family = atoi(optarg);
			break;
		case 'h':
			matchd_usage();
			exit(-1);
		case 'l':
			match_backend_list_all();
			exit(0);
		case 's':
			sw_args.single_vlan = true;
			break;
		case 'v':
			++verbose;
			break;
		default:
			matchd_usage();
			exit(-1);
		}
	}

	if (verbose > 1)
		mat_setlogmask(MAT_LOG_UPTO(MAT_LOG_DEBUG));
	else if (verbose > 0)
		mat_setlogmask(MAT_LOG_UPTO(MAT_LOG_INFO));
	else
		mat_setlogmask(MAT_LOG_UPTO(MAT_LOG_ERR));

	nsd = nl_socket_alloc();
	nl_socket_set_local_port(nsd, (uint32_t)getpid());
	nl_connect(nsd, NETLINK_GENERIC);

	if (backend == NULL)
		backend = DEFAULT_BACKEND_NAME;

	rc = matchd_init(nsd, family, backend, &sw_args);
	if (rc) {
		MAT_LOG(ERR, "Error: cannot init matchd\n");
		exit(-1);
	}

	err = matchd_create_pid();
	if (err) {
		MAT_LOG(ERR, "matchd create pid failed\n");
		exit(-1);
	}

	sig_act.sa_handler = matchd_int_handler;
	sigaction(SIGINT, &sig_act, NULL);
	sigaction(SIGTERM, &sig_act, NULL);

	while (1) {
		MAT_LOG(DEBUG, "Waiting for message\n");
		rc = nl_recv(nsd, &dest_addr, &buf, NULL);
		if(rc <= 0) {
			printf("%s:receive error on netlink socket:%d\n",
				__func__, errno);
			rc = EXIT_FAILURE;
			break;
		}
		/*printf("%s:recvfrom received %d bytes from pid %d\n",
			__func__, rc, dest_addr.nl_pid); */

		err = matchd_rx_process((struct nlmsghdr *)buf);
		if (err < 0)
			MAT_LOG(ERR, "%s: Warning: parsing error\n",
					__func__);

		free(buf);
	}
	
	matchd_uninit();

	nl_close(nsd);
	nl_socket_free(nsd);
	return rc;
}
예제 #6
0
struct match_msg *match_nl_alloc_msg(uint8_t type, uint32_t pid,
				   int flags, int size, int family)
{
	struct match_msg *msg;
	static uint32_t seq = 0;

	msg = (struct match_msg *) malloc(sizeof(struct match_msg));
	if (!msg)
		return NULL;

	msg->nlbuf = nlmsg_alloc();

	msg->msg = genlmsg_put(msg->nlbuf, 0, seq, family, (int)size, flags,
			       type, NET_MAT_GENL_VERSION);

	msg->seq = seq++;

	if (pid) {
		struct nl_msg *nl_msg = msg->nlbuf;
		struct sockaddr_nl nladdr = {
			.nl_family = AF_NETLINK,
			.nl_pid = pid,
			.nl_groups = 0,
		};

		nlmsg_set_dst(nl_msg, &nladdr);
	}
	return msg;
}

struct match_msg *match_nl_get_msg(struct nl_sock *nsd, uint8_t cmd, uint32_t pid,
				 unsigned int ifindex, int family)
{
	struct match_msg *msg;
	sigset_t bs;
	int err;

	msg = match_nl_alloc_msg(cmd, pid, NLM_F_REQUEST|NLM_F_ACK, 0, family);
	if (!msg) {
		MAT_LOG(ERR, "Error: Allocation failure\n");
		return NULL;
	}

	nla_put_u32(msg->nlbuf,
		    NET_MAT_IDENTIFIER_TYPE,
		    NET_MAT_IDENTIFIER_IFINDEX);
	nla_put_u32(msg->nlbuf, NET_MAT_IDENTIFIER, ifindex);

	nl_send_auto(nsd, msg->nlbuf);
	match_nl_free_msg(msg);

	sigemptyset(&bs);
	sigaddset(&bs, SIGINT);
	sigprocmask(SIG_UNBLOCK, &bs, NULL);

	msg = match_nl_recv_msg(nsd, &err);
	sigprocmask(SIG_BLOCK, &bs, NULL);
	return msg;
}

static int match_nl_get_port(struct nl_sock *nsd, uint32_t pid,
			unsigned int ifindex, int family, uint8_t cmd,
			struct net_mat_port *ports,
			uint32_t *port_id, uint32_t *glort)
{
	struct net_mat_port *port_query = NULL;
	struct match_msg *msg;
	sigset_t bs;
	int err;

	msg = match_nl_alloc_msg(cmd, pid, NLM_F_REQUEST|NLM_F_ACK, 0, family);
	if (!msg) {
		MAT_LOG(ERR, "Error: Allocation failure\n");
		return -ENOMEM;
	}

	if (nla_put_u32(msg->nlbuf,
			NET_MAT_IDENTIFIER_TYPE,
			NET_MAT_IDENTIFIER_IFINDEX) ||
	    nla_put_u32(msg->nlbuf, NET_MAT_IDENTIFIER, ifindex)) {
		match_nl_free_msg(msg);
		return -EMSGSIZE;
	}

	err = match_put_ports(msg->nlbuf, ports);
	if (err) {
		match_nl_free_msg(msg);
		return -EMSGSIZE;
	}

	nl_send_auto(nsd, msg->nlbuf);
	match_nl_free_msg(msg);

	sigemptyset(&bs);
	sigaddset(&bs, SIGINT);
	sigprocmask(SIG_UNBLOCK, &bs, NULL);

	msg = match_nl_recv_msg(nsd, &err);

	if (msg) {
		struct nlmsghdr *nlh = msg->msg;
		struct nlattr *tb[NET_MAT_MAX+1];
		int err;

		err = genlmsg_parse(nlh, 0, tb,
				    NET_MAT_MAX, match_get_tables_policy);
		if (err < 0) {
			MAT_LOG(ERR, "Warning: unable to parse pci to lport msg\n");
			match_nl_free_msg(msg);
			return -EINVAL;
		}

		if (match_nl_table_cmd_to_type(stdout, true, NET_MAT_PORTS, tb)) {
			match_nl_free_msg(msg);
			return -EINVAL;
		}

		if (tb[NET_MAT_PORTS]) {
			err = match_get_ports(stdout, verbose,
					     tb[NET_MAT_PORTS], &port_query);
			if (err) {
				match_nl_free_msg(msg);
				return -EINVAL;
			}
		}

		if (!port_query) {
			match_nl_free_msg(msg);
			return -EINVAL;
		}

		if (cmd == NET_MAT_PORT_CMD_GET_LPORT)
			*port_id = port_query[0].port_id;
		else if (cmd == NET_MAT_PORT_CMD_GET_PHYS_PORT)
			*port_id = port_query[0].port_phys_id;

		if (glort)
			*glort = port_query[0].glort;
	}

	match_nl_free_msg(msg);
	free(port_query);
	return 0;
}

int match_nl_pci_lport(struct nl_sock *nsd, uint32_t pid,
		      unsigned int ifindex, int family,
		      uint8_t bus, uint8_t device, uint8_t function,
		      uint32_t *lport, uint32_t *glort)
{
	struct net_mat_port port = {.pci = {0},
	                            .port_id = NET_MAT_PORT_ID_UNSPEC,
				    .mac_addr = 0, .port_phys_id = 0};
	struct net_mat_port ports[2] = {{0}, {0}};
	int err;

	ports[0] = ports[1] = port;

	ports[0].pci.bus = bus;
	ports[0].pci.device = device;
	ports[0].pci.function = function;

	err = match_nl_get_port(nsd, pid, ifindex, family,
			NET_MAT_PORT_CMD_GET_LPORT, ports, lport, glort);

	return err;
}

int match_nl_mac_lport(struct nl_sock *nsd, uint32_t pid,
		     unsigned int ifindex, int family,
		     uint64_t mac, uint32_t *lport,
		     uint32_t *glort)
{
	struct net_mat_port port = {.pci = {0},
	                            .port_id = NET_MAT_PORT_ID_UNSPEC,
				    .mac_addr = 0, .port_phys_id = 0};
	struct net_mat_port ports[2] = {{0}, {0}};
	int err;

	ports[0] = ports[1] = port;

	ports[0].mac_addr = mac;

	err = match_nl_get_port(nsd, pid, ifindex, family,
			NET_MAT_PORT_CMD_GET_LPORT, ports, lport, glort);

	return err;
}

int match_nl_lport_to_phys_port(struct nl_sock *nsd, uint32_t pid,
				unsigned int ifindex, int family,
				uint32_t lport, uint32_t *phys_port,
				uint32_t *glort)
{
	struct net_mat_port port = {.pci = {0},
	                            .port_id = NET_MAT_PORT_ID_UNSPEC,
				    .mac_addr = 0, .port_phys_id = 0};
	struct net_mat_port ports[2] = {{0}, {0}};
	int err;

	ports[0] = ports[1] = port;

	ports[0].port_id = lport;

	err = match_nl_get_port(nsd, pid, ifindex, family,
			NET_MAT_PORT_CMD_GET_PHYS_PORT,
			ports, phys_port, glort);

	return err;
}
예제 #7
0
static void match_nl_handle_error(struct nlmsgerr *errmsg)
{
	MAT_LOG(ERR, "Error processing request: %s\n",
		strerror(errmsg->error));
}
예제 #8
0
struct net_mat_port *match_nl_get_ports(struct nl_sock *nsd, uint32_t pid,
                      unsigned int ifindex, int family, uint32_t min, uint32_t max)
{
	uint8_t cmd = NET_MAT_PORT_CMD_GET_PORTS;
	struct nlattr *tb[NET_MAT_MAX+1];
	struct net_mat_port *port = NULL;
	struct match_msg *msg;
	struct nlmsghdr *nlh;
	struct nlattr *ports;
	sigset_t bs;
	int err = 0;

	msg = match_nl_alloc_msg(cmd, pid, NLM_F_REQUEST|NLM_F_ACK, 0, family);
	if (!msg) {
		MAT_LOG(ERR, "Error: Allocation failure\n");
		return NULL;
	}

	if (nla_put_u32(msg->nlbuf,
                        NET_MAT_IDENTIFIER_TYPE,
                        NET_MAT_IDENTIFIER_IFINDEX) ||
		nla_put_u32(msg->nlbuf, NET_MAT_IDENTIFIER, ifindex)) {
		MAT_LOG(ERR, "Error: Identifier put failed\n");
		goto out;
	}
	err = match_put_rule_error(msg->nlbuf, NET_MAT_RULES_ERROR_CONT_LOG);
	if (err)
		goto out;

	ports = nla_nest_start(msg->nlbuf, NET_MAT_PORTS);
	if (!ports) {
		MAT_LOG(ERR, "Error: get_port attributes failed\n");
		goto out;
	}
	if (min) {
		err = nla_put_u32(msg->nlbuf, NET_MAT_PORT_MIN_INDEX,
                                min);
		if (err)
			goto out;
	}
	if (max) {
		err = nla_put_u32(msg->nlbuf, NET_MAT_PORT_MAX_INDEX,
                                max);
		if (err)
			goto out;
	}
	nla_nest_end(msg->nlbuf, ports);
	nl_send_auto(nsd, msg->nlbuf);
	match_nl_free_msg(msg);

	/* message sent handle recv */
	sigemptyset(&bs);
	sigaddset(&bs, SIGINT);
	sigprocmask(SIG_UNBLOCK, &bs, NULL);

	msg = match_nl_recv_msg(nsd, &err);
	sigprocmask(SIG_BLOCK, &bs, NULL);
	if (msg) {
		nlh = msg->msg;
		err = genlmsg_parse(nlh, 0, tb, NET_MAT_MAX, match_get_tables_policy);
		if (err < 0) {
			MAT_LOG(ERR, "Warning: unable to parse get rules msg\n");
			goto out;
		}

		if (match_nl_table_cmd_to_type(stdout, true,
                                              NET_MAT_PORTS, tb))
                        goto out;

		if (tb[NET_MAT_PORTS]) {
			err = match_get_ports(stdout, verbose, tb[NET_MAT_PORTS], &port);
			if (err)
				goto out;
		}
	}
	match_nl_free_msg(msg);
	return port;
out:
	match_nl_free_msg(msg);
	return NULL;
}
예제 #9
0
int match_nl_set_port(struct nl_sock *nsd, uint32_t pid,
				unsigned int ifindex, int family,
				struct net_mat_port *port)
{
	uint8_t cmd = NET_MAT_PORT_CMD_SET_PORTS;
	struct nlattr *tb[NET_MAT_MAX+1];
	struct nlattr *nest, *nest1;
	struct nlmsghdr *nlh;
	struct match_msg *msg;
	sigset_t bs;
	int err = 0;

	msg = match_nl_alloc_msg(cmd, pid, NLM_F_REQUEST|NLM_F_ACK, 0, family);
	if (!msg) {
		MAT_LOG(ERR, "Error: Allocation failure\n");
		return -ENOMSG;
	}

	if (nla_put_u32(msg->nlbuf,
			NET_MAT_IDENTIFIER_TYPE,
			NET_MAT_IDENTIFIER_IFINDEX) ||
	    nla_put_u32(msg->nlbuf, NET_MAT_IDENTIFIER, ifindex)) {
		MAT_LOG(ERR, "Error: Identifier put failed\n");
		match_nl_free_msg(msg);
		return -EMSGSIZE;
	}

	nest = nla_nest_start(msg->nlbuf, NET_MAT_PORTS);
	if (!nest) {
		match_nl_free_msg(msg);
		return -EMSGSIZE;
	}
	nest1 = nla_nest_start(msg->nlbuf, NET_MAT_PORTS);
	match_put_port(msg->nlbuf, port);
	nla_nest_end(msg->nlbuf, nest1);
	nla_nest_end(msg->nlbuf, nest);
	nl_send_auto(nsd, msg->nlbuf);
	match_nl_free_msg(msg);

	sigemptyset(&bs);
	sigaddset(&bs, SIGINT);
	sigprocmask(SIG_UNBLOCK, &bs, NULL);

	msg = match_nl_recv_msg(nsd, &err);
	sigprocmask(SIG_BLOCK, &bs, NULL);

	if (!msg)
		return -EINVAL;

	nlh = msg->msg;
	err = genlmsg_parse(nlh, 0, tb, NET_MAT_MAX, match_get_tables_policy);
	if (err < 0) {
		MAT_LOG(ERR, "Warning: unable to parse set port msg\n");
		match_nl_free_msg(msg);
		return err;
	}

	err = match_nl_table_cmd_to_type(stdout, true, 0, tb);
	if (err) {
		match_nl_free_msg(msg);
		return err;
	}

	if (tb[NET_MAT_PORTS]) {
		MAT_LOG(ERR, "Failed to set:\n");
		match_get_ports(stdout, verbose, tb[NET_MAT_PORTS], NULL);
		match_nl_free_msg(msg);
		return -EINVAL;
	}
	match_nl_free_msg(msg);
	return 0;
}
예제 #10
0
int match_nl_set_del_rules(struct nl_sock *nsd, uint32_t pid,
		      unsigned int ifindex, int family,
		      struct net_mat_rule *rule, uint8_t cmd)
{
	struct nlattr *tb[NET_MAT_MAX+1];
	struct match_msg *msg;
	struct nlmsghdr *nlh;
	struct nlattr *rules;
	sigset_t bs;
	int err = 0;

	pp_rule(stdout, true, rule);

	msg = match_nl_alloc_msg(cmd, pid, NLM_F_REQUEST|NLM_F_ACK, 0, family);
	if (!msg) {
		MAT_LOG(ERR, "Error: Allocation failure\n");
		return -ENOMSG;
	}

	if (nla_put_u32(msg->nlbuf,
			NET_MAT_IDENTIFIER_TYPE,
			NET_MAT_IDENTIFIER_IFINDEX) ||
	    nla_put_u32(msg->nlbuf, NET_MAT_IDENTIFIER, ifindex)) {
		MAT_LOG(ERR, "Error: Identifier put failed\n");
		match_nl_free_msg(msg);
		return -EMSGSIZE;
	}

	err = match_put_rule_error(msg->nlbuf, NET_MAT_RULES_ERROR_CONT_LOG);
	if (err) {
		match_nl_free_msg(msg);
		return err;
	}

	rules = nla_nest_start(msg->nlbuf, NET_MAT_RULES);
	if (!rules) {
		match_nl_free_msg(msg);
		return -EMSGSIZE;
	}
	match_put_rule(msg->nlbuf, rule);
	nla_nest_end(msg->nlbuf, rules);

	nl_send_auto(nsd, msg->nlbuf);
	match_nl_free_msg(msg);

	/* message sent handle recv */
	sigemptyset(&bs);
	sigaddset(&bs, SIGINT);
	sigprocmask(SIG_UNBLOCK, &bs, NULL);

	msg = match_nl_recv_msg(nsd, &err);
	sigprocmask(SIG_BLOCK, &bs, NULL);

	if (!msg)
		return -EINVAL;

	nlh = msg->msg;
	err = genlmsg_parse(nlh, 0, tb, NET_MAT_MAX, match_get_tables_policy);
	if (err < 0) {
		MAT_LOG(ERR, "Warning: unable to parse set rules msg\n");
		match_nl_free_msg(msg);
		return err;
	}

	err = match_nl_table_cmd_to_type(stdout, true, 0, tb);
	if (err) {
		match_nl_free_msg(msg);
		return err;
	}

	if (tb[NET_MAT_RULES]) {
		MAT_LOG(ERR, "Failed to set:\n");
		match_get_rules(stdout, verbose, tb[NET_MAT_RULES], NULL);
		match_nl_free_msg(msg);
		return -EINVAL;
	}
	match_nl_free_msg(msg);
	return 0;
}
예제 #11
0
static inline int bpf_map_update_elem(__u32 fd, void *key, void *value)
{
	union bpf_attr attr = {.map_type = 0}; /* initialize to zero */

	attr.map_fd = fd;
	attr.key = bpf_ptr_to_u64(key);
	attr.value = bpf_ptr_to_u64(value);

	return syscall(__NR_bpf, BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr));
}

static inline int bpf_map_delete_elem(__u32 fd, void *key)
{
	union bpf_attr attr = {.map_type = 0}; /* initialize to zero */

	attr.map_fd = fd;
	attr.key = bpf_ptr_to_u64(key);

	return syscall(__NR_bpf, BPF_MAP_DELETE_ELEM, &attr, sizeof(attr));
}
#else
static inline int bpf_map_update_elem(__u32 fd __unused, void *key __unused, void *value __unused)
{
	return 0;
}

static inline int bpf_map_delete_elem(__u32 fd __unused, void *key __unused)
{
	return 0;
}
#endif

/* table cache is used to have a software representation of the maps
 * data structure. This allows reads to avoid going to kernel via
 * syscalls to rebuild the rules. Trading memory for ease of use here.
 */
__u8 *table_cache[BPF_MATCH_MAX_TABLES];
struct bpf_elf_map table_aux[BPF_MATCH_MAX_TABLES];
int table_fds[BPF_MATCH_MAX_TABLES];

static int bpf_pipeline_open(void *arg __unused)
{
	struct sockaddr_un bpf_addr;
	int err, fd;
	long unsigned int i, num_fds;
	struct bpf_map_aux aux = {0};
	struct bpf_map_set_msg bpf_msg;
	ssize_t ret;
	char filename[1024];

 	memset(&bpf_msg, 0, sizeof (struct bpf_map_set_msg));

	fd = socket(AF_UNIX, SOCK_DGRAM, 0);
	if (fd < 0) {
		MAT_LOG(ERR, "bpf af_unix socket failed: abort!\n");
		exit(-1);
	}

	memset(&bpf_addr, 0, sizeof(bpf_addr));
	bpf_addr.sun_family = AF_UNIX;

	for (i = 100; i < 200; i++) {
		sprintf(filename, "%s%lu", bpf_filename, i);
		strncpy(bpf_addr.sun_path, filename, sizeof bpf_addr.sun_path);

		err = bind(fd, (struct sockaddr *)&bpf_addr, sizeof bpf_addr);
		if (err < 0) {
			MAT_LOG(ERR, "bpf bind socket %s failed(%i): continue!\n", filename, err); 
			continue;
		}

		printf("%s: using filename: %s\n", __func__, filename);
		break;
	}

	if (err) {
		MAT_LOG(ERR, "last bpf bind socket %s failed(%i): abort!\n", filename, err); 
		exit(-1);
	}

	for (i = 0; i < BPF_MATCH_MAX_TABLES; i += num_fds) {
		struct cmsghdr *cmsg;

		bpf_msg.iov.iov_base = &bpf_msg.aux;	
		bpf_msg.iov.iov_len = sizeof bpf_msg.aux;

		bpf_msg.hdr.msg_iov = &bpf_msg.iov;
		bpf_msg.hdr.msg_iovlen = 1;

		bpf_msg.hdr.msg_control = &bpf_msg.msg_buf;
		bpf_msg.hdr.msg_controllen = (10 * sizeof(int)); //(sizeof (int));

		cmsg = CMSG_FIRSTHDR(&bpf_msg.hdr);
		cmsg->cmsg_len = bpf_msg.hdr.msg_controllen;
		cmsg->cmsg_level = SOL_SOCKET;
		cmsg->cmsg_type = SCM_RIGHTS;

		printf("%s: waiting for filter (tbd replace with fuse)\n", __func__);

		ret = recvmsg(fd, &bpf_msg.hdr, 0);
		if (ret <= 0)
			break;
		printf("%s: received maps (%lu)\n", __func__, ret);

		cmsg = CMSG_FIRSTHDR(&bpf_msg.hdr);

		num_fds = (cmsg->cmsg_len - sizeof(*cmsg)) / sizeof(int);
		assert(num_fds < BPF_MATCH_MAX_TABLES);

		memcpy(&fds[i], CMSG_DATA(cmsg), sizeof(int) * num_fds);
		memcpy(&aux.ent[i], &bpf_msg.aux.ent[i], sizeof(bpf_msg.aux.ent[0]) * num_fds);
		memcpy(&aux, &bpf_msg.aux, offsetof(struct bpf_map_aux, ent));

		printf("%s: i %lu num_fds %lu num_ent %i\n", __func__, i, num_fds, aux.num_ent);
		if ((i + num_fds) == (long unsigned) (aux.num_ent <= 0 ? 0 : aux.num_ent))
			break;
	}

	for (i = 0; i < BPF_MATCH_MAX_TABLES; i++) {
		const char *unknown = "Unknown-Table";
		const char *str_label = unknown;
		int j;

		for (j = 0; j < BPF_MAX_TABLES; j++) {
			if (bpf_table_list[j]->uid == aux.ent[i].id) {
				int index = bpf_table_list[j]->uid;

				str_label = bpf_table_list[j]->name;

				/* If the table_id is larger then the max table this is a code
				 * generator bug most likely in bpf_match.h or the actual bpf
				 * program being loaded. In this case do a hard abort and let
				 * the user sort the mess out.
				 */
				assert(aux.ent[i].id < BPF_MATCH_MAX_TABLES);
				table_cache[index] = calloc(aux.ent[i].max_elem, aux.ent[i].size_key);
				table_aux[index] = aux.ent[i];
				table_fds[index] = fds[i];
				break;
			}
		}

		printf("%s: @ %lu:fd(%i)\n", __func__, i, fds[i]);
		printf("\t label: %u -> %s\n", aux.ent[i].id, str_label);
		printf("\t type: %u\n", aux.ent[i].type);
		printf("\t max_elem: %u\n", aux.ent[i].max_elem);
		printf("\t key_size: %u\n", aux.ent[i].size_key);
		printf("\t size val: %u\n", aux.ent[i].size_value);
	}

	return 0;
}

static void bpf_pipeline_close(void)
{
	int i;

	for (i = 0; i < BPF_MATCH_MAX_TABLES; i++)
		free(table_cache[i]);

	return;
}

static void bpf_pipeline_get_rule_counters(struct net_mat_rule *rule __unused)
{
	MAT_LOG(ERR, "bpf get_counters unsupported\n");
	return;
}

static struct net_mat_tbl *bpf_get_table(__u32 table)
{
	int i;

	for (i = 0; bpf_table_list[i]; i++) {
		if (bpf_table_list[i]->uid == table)
			return bpf_table_list[i];
	}

	return NULL;
}