Beispiel #1
0
static void delete_cb(struct nl_object *obj, void *arg)
{
	struct rtnl_qdisc *qdisc = nl_object_priv(obj);
	struct nl_dump_params params = {
		.dp_type = NL_DUMP_LINE,
		.dp_fd = stdout,
	};
	int err;

	/* Ignore default qdiscs, unable to delete */
	if (rtnl_tc_get_handle((struct rtnl_tc *) qdisc) == 0)
		return;

	if (interactive && !nl_cli_confirm(obj, &params, default_yes))
		return;

	if ((err = rtnl_qdisc_delete(sock, qdisc)) < 0)
		nl_cli_fatal(err, "Unable to delete qdisc: %s\n", nl_geterror(err));

	if (!quiet) {
		printf("Deleted ");
		nl_object_dump(obj, &params);
	}

	deleted++;
}
Beispiel #2
0
static int include_cb(struct nl_object *obj, struct nl_parser_param *p)
{
	struct nl_cache_assoc *ca = p->pp_arg;
	struct nl_cache_ops *ops = ca->ca_cache->c_ops;

	NL_DBG(2, "Including object %p into cache %p\n", obj, ca->ca_cache);
#ifdef NL_DEBUG
	if (nl_debug >= 4)
		nl_object_dump(obj, &nl_debug_dp);
#endif

	if (ops->co_event_filter)
		if (ops->co_event_filter(ca->ca_cache, obj) != NL_OK)
			return 0;

	if (ops->co_include_event)
		return ops->co_include_event(ca->ca_cache, obj, ca->ca_change,
					     ca->ca_change_v2,
					     ca->ca_change_data);
	else {
		if (ca->ca_change_v2)
			return nl_cache_include_v2(ca->ca_cache, obj, ca->ca_change_v2, ca->ca_change_data);
		else
			return nl_cache_include(ca->ca_cache, obj, ca->ca_change, ca->ca_change_data);
	}

}
Beispiel #3
0
int nl_cli_confirm(struct nl_object *obj, struct nl_dump_params *params,
		   int default_yes)
{
	nl_object_dump(obj, params);

	for (;;) {
		char buf[32] = { 0 };
		int answer;

		printf("Delete? (%c/%c) ",
			default_yes ? 'Y' : 'y',
			default_yes ? 'n' : 'N');

		if (!fgets(buf, sizeof(buf), stdin)) {
			fprintf(stderr, "Error while reading\n.");
			continue;
		}

		switch ((answer = tolower(buf[0]))) {
		case '\n':
			answer = default_yes ? 'y' : 'n';
		case 'y':
		case 'n':
			return answer == 'y';
		}

		fprintf(stderr, "Invalid input, try again.\n");
	}

	return 0;

}
Beispiel #4
0
static void print_link(struct nl_object *obj, void *arg)
{
	struct rtnl_link *link = (struct rtnl_link *) obj;
	struct rtnl_qdisc *qdisc;

	ifindex = rtnl_link_get_ifindex(link);
	dump_params.dp_prefix = 0;
	nl_object_dump(obj, &dump_params);

	class_cache = rtnl_class_alloc_cache(nl_handle, ifindex);
	if (!class_cache)
		return;

	qdisc = rtnl_qdisc_get_by_parent(qdisc_cache, ifindex, TC_H_ROOT);
	if (qdisc) {
		print_qdisc((struct nl_object *) qdisc, (void *) 2);
		rtnl_qdisc_put(qdisc);
	}

	qdisc = rtnl_qdisc_get_by_parent(qdisc_cache, ifindex, 0);
	if (qdisc) {
		print_qdisc((struct nl_object *) qdisc, (void *) 2);
		rtnl_qdisc_put(qdisc);
	}

	qdisc = rtnl_qdisc_get_by_parent(qdisc_cache, ifindex, TC_H_INGRESS);
	if (qdisc) {
		print_qdisc((struct nl_object *) qdisc, (void *) 2);
		rtnl_qdisc_put(qdisc);
	}

	nl_cache_free(class_cache);
}
static void list_class(struct nl_object *obj, void *arg)
{
	struct rtnl_tc *tc = nl_object_priv(obj);
	nl_object_dump(obj, &params);

	list_classes(rtnl_tc_get_ifindex(tc), rtnl_tc_get_handle(tc));
	list_qdiscs(rtnl_tc_get_ifindex(tc), rtnl_tc_get_handle(tc));
}
static void change_cb(struct nl_cache *cache, struct nl_object *obj,
		      int action, void *data)
{
	if (action == NL_ACT_NEW)
		printf("NEW ");
	else if (action == NL_ACT_DEL)
		printf("DEL ");
	else if (action == NL_ACT_CHANGE)
		printf("CHANGE ");

	nl_object_dump(obj, &dp);
}
Beispiel #7
0
void TNl::Dump(const std::string &prefix, void *obj) {
    std::stringstream ss;
    struct nl_dump_params dp = {};

    dp.dp_type = debug ? NL_DUMP_STATS : NL_DUMP_LINE;
    dp.dp_data = &ss;
    dp.dp_cb = [](struct nl_dump_params *dp, char *buf) {
            auto ss = (std::stringstream *)dp->dp_data;
            *ss << std::string(buf);
    };
    nl_object_dump(OBJ_CAST(obj), &dp);

    L() << "netlink " << prefix << " " << ss.str() << std::endl;
}
Beispiel #8
0
std::ostream &operator<<(std::ostream &stream, struct nl_object *n) {
  if (n == nullptr) {
    stream << "<nullptr>";
    return stream;
  }

  if (VLOG_IS_ON(3)) {
    stream << "(nl_obj=" << static_cast<const void *>(n) << ") ";
    p.dp_type = NL_DUMP_DETAILS;
  }

  nl_object_dump(n, &p);
  stream << buf.data();
  return stream;
}
static void list_qdisc(struct nl_object *obj, void *arg)
{
	struct rtnl_qdisc *qdisc = nl_object_priv(obj);
	struct rtnl_tc *tc = (struct rtnl_tc *) qdisc;

	nl_object_dump(obj, &params);

	list_cls(rtnl_tc_get_ifindex(tc), rtnl_tc_get_handle(tc));

	if (rtnl_tc_get_parent(tc) == TC_H_ROOT) {
		list_cls(rtnl_tc_get_ifindex(tc), TC_H_ROOT);
		list_classes(rtnl_tc_get_ifindex(tc), TC_H_ROOT);
	}

	list_classes(rtnl_tc_get_ifindex(tc), rtnl_tc_get_handle(tc));
}
static void change_cb(struct nl_cache *cache, struct nl_object *obj,
		      int action)
{
	struct nl_dump_params dp = {
		.dp_type = NL_DUMP_LINE,
		.dp_fd = stdout,
	};

	if (action == NL_ACT_NEW)
		printf("NEW ");
	else if (action == NL_ACT_DEL)
		printf("DEL ");
	else if (action == NL_ACT_CHANGE)
		printf("CHANGE ");

	nl_object_dump(obj, &dp);
}
Beispiel #11
0
int nl_cli_confirm(struct nl_object *obj, struct nl_dump_params *params,
		   int default_yes)
{
	int answer;

	nl_object_dump(obj, params);
	printf("Delete? (%c/%c) ",
		default_yes ? 'Y' : 'y',
		default_yes ? 'n' : 'N');

	do {
		answer = tolower(getchar());
		if (answer == '\n')
			answer = default_yes ? 'y' : 'n';
	} while (answer != 'y' && answer != 'n');

	return answer == 'y';
}
Beispiel #12
0
static void print_qdisc(struct nl_object *obj, void *arg)
{
	struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) obj;
	struct nl_cache *cls_cache;
	uint32_t parent = rtnl_tc_get_handle((struct rtnl_tc *) qdisc);

	params.dp_prefix = (int)(long) arg;
	nl_object_dump(obj, &params);

	print_tc_childs(TC_CAST(qdisc), arg + 2);

	if (rtnl_cls_alloc_cache(sock, ifindex, parent, &cls_cache) < 0)
		return;

	params.dp_prefix = (int)(long) arg + 2;
	nl_cache_dump(cls_cache, &params);
	nl_cache_free(cls_cache);
}
Beispiel #13
0
static void print_qdisc(struct nl_object *obj, void *arg)
{
	struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) obj;
	struct nl_cache *cls_cache;
	uint32_t parent = rtnl_qdisc_get_handle(qdisc);

	dump_params.dp_prefix = (int) arg;
	nl_object_dump(obj, &dump_params);

	rtnl_qdisc_foreach_child(qdisc, class_cache, &print_class, arg + 2);

	cls_cache = rtnl_cls_alloc_cache(nl_handle, ifindex, parent);
	if (!cls_cache)
		return;

	dump_params.dp_prefix = (int) arg + 2;
	nl_cache_dump(cls_cache, &dump_params);
	nl_cache_free(cls_cache);
}
static void change_cb(struct nl_cache *cache, struct nl_object *obj,
		      int action)
{
	struct nfnl_ct *ct = (struct nfnl_ct *) obj;
	static struct nl_addr *hack = NULL;

	if (!hack)
		hack = nl_addr_parse("194.88.212.233", AF_INET);

	if (!nl_addr_cmp(hack, nfnl_ct_get_src(ct, 1)) ||
	    !nl_addr_cmp(hack, nfnl_ct_get_dst(ct, 1))) {
		struct nl_dump_params dp = {
			.dp_type = NL_DUMP_LINE,
			.dp_fd = stdout,
		};

		printf("UPDATE ");
		nl_object_dump(obj, &dp);
	}
}
static void delete_cb(struct nl_object *obj, void *arg)
{
	struct rtnl_route *route = (struct rtnl_route *) obj;
	struct nl_dump_params params = {
		.dp_type = NL_DUMP_LINE,
		.dp_fd = stdout,
	};
	int err;

	if (interactive && !nl_cli_confirm(obj, &params, default_yes))
		return;

	if ((err = rtnl_route_delete(sock, route, 0)) < 0)
		nl_cli_fatal(err, "Unable to delete route: %s", nl_geterror(err));

	if (!quiet) {
		printf("Deleted ");
		nl_object_dump(obj, &params);
	}

	deleted++;
}
Beispiel #16
0
static void print_class(struct nl_object *obj, void *arg)
{
	struct rtnl_qdisc *leaf;
	struct rtnl_class *class = (struct rtnl_class *) obj;
	struct nl_cache *cls_cache;
	uint32_t parent = rtnl_tc_get_handle((struct rtnl_tc *) class);

	params.dp_prefix = (int)(long) arg;
	nl_object_dump(obj, &params);

	leaf = rtnl_class_leaf_qdisc(class, qdisc_cache);
	if (leaf)
		print_qdisc((struct nl_object *) leaf, arg + 2);

	print_tc_childs(TC_CAST(class), arg + 2);

	if (rtnl_cls_alloc_cache(sock, ifindex, parent, &cls_cache) < 0)
		return;

	params.dp_prefix = (int)(long) arg + 2;
	nl_cache_dump(cls_cache, &params);
	nl_cache_free(cls_cache);
}
Beispiel #17
0
static void obj_input(struct nl_object *obj, void *arg)
{
	struct nl_dump_params dp = {
		.dp_type = NL_DUMP_STATS,
		.dp_fd = stdout,
		.dp_dump_msgtype = 1,
	};

	nl_object_dump(obj, &dp);
}

static int event_input(struct nl_msg *msg, void *arg)
{
	if (nl_msg_parse(msg, &obj_input, NULL) < 0)
		fprintf(stderr, "<<EVENT>> Unknown message type\n");

	/* Exit nl_recvmsgs_def() and return to the main select() */
	return NL_STOP;
}

int main(int argc, char *argv[])
{
	struct nl_sock *nf_sock;
	struct nl_sock *rt_sock;
        struct nl_cache *link_cache;
	struct nfnl_log *log;
	enum nfnl_log_copy_mode copy_mode;
	uint32_t copy_range;
	int err;
	int family;

	nf_sock = nl_cli_alloc_socket();
	nl_socket_disable_seq_check(nf_sock);
	nl_socket_modify_cb(nf_sock, NL_CB_VALID, NL_CB_CUSTOM, event_input, NULL);

	if ((argc > 1 && !strcasecmp(argv[1], "-h")) || argc < 3) {
		printf("Usage: nf-log family group [ copy_mode ] "
		       "[copy_range] \n");
		return 2;
	}

	nl_cli_connect(nf_sock, NETLINK_NETFILTER);

	family = nl_str2af(argv[1]);
	if (family == AF_UNSPEC)
		nl_cli_fatal(NLE_INVAL, "Unknown family \"%s\": %s",
			     argv[1], nl_geterror(family));

	nfnl_log_pf_unbind(nf_sock, family);
	if ((err = nfnl_log_pf_bind(nf_sock, family)) < 0)
		nl_cli_fatal(err, "Unable to bind logger: %s",
			     nl_geterror(err));

	log = alloc_log();
	nfnl_log_set_group(log, atoi(argv[2]));

	copy_mode = NFNL_LOG_COPY_META;
	if (argc > 3) {
		copy_mode = nfnl_log_str2copy_mode(argv[3]);
		if (copy_mode < 0)
			nl_cli_fatal(copy_mode,
				     "Unable to parse copy mode \"%s\": %s",
				     argv[3], nl_geterror(copy_mode));
	}
	nfnl_log_set_copy_mode(log, copy_mode);

	copy_range = 0xFFFF;
	if (argc > 4)
		copy_mode = atoi(argv[4]);
	nfnl_log_set_copy_range(log, copy_range);

	if ((err = nfnl_log_create(nf_sock, log)) < 0)
		nl_cli_fatal(err, "Unable to bind instance: %s",
			     nl_geterror(err));

	{
		struct nl_dump_params dp = {
			.dp_type = NL_DUMP_STATS,
			.dp_fd = stdout,
			.dp_dump_msgtype = 1,
		};

		printf("log params: ");
		nl_object_dump((struct nl_object *) log, &dp);
	}

	rt_sock = nl_cli_alloc_socket();
	nl_cli_connect(rt_sock, NETLINK_ROUTE);
	link_cache = nl_cli_link_alloc_cache(rt_sock);

	while (1) {
		fd_set rfds;
		int nffd, rtfd, maxfd, retval;

		FD_ZERO(&rfds);

		maxfd = nffd = nl_socket_get_fd(nf_sock);
		FD_SET(nffd, &rfds);

		rtfd = nl_socket_get_fd(rt_sock);
		FD_SET(rtfd, &rfds);
		if (maxfd < rtfd)
			maxfd = rtfd;

		/* wait for an incoming message on the netlink nf_socket */
		retval = select(maxfd+1, &rfds, NULL, NULL, NULL);

		if (retval) {
			if (FD_ISSET(nffd, &rfds))
				nl_recvmsgs_default(nf_sock);
			if (FD_ISSET(rtfd, &rfds))
				nl_recvmsgs_default(rt_sock);
		}
	}

	return 0;
}
Beispiel #18
0
static void obj_input(struct nl_object *obj, void *arg)
{
	struct nfnl_queue_msg *msg = (struct nfnl_queue_msg *) obj;
	struct nl_dump_params dp = {
		.dp_type = NL_DUMP_STATS,
		.dp_fd = stdout,
		.dp_dump_msgtype = 1,
	};

	nfnl_queue_msg_set_verdict(msg, NF_ACCEPT);
	nl_object_dump(obj, &dp);
	nfnl_queue_msg_send_verdict(nf_sock, msg);
}

static int event_input(struct nl_msg *msg, void *arg)
{
	if (nl_msg_parse(msg, &obj_input, NULL) < 0)
		fprintf(stderr, "<<EVENT>> Unknown message type\n");

	/* Exit nl_recvmsgs_def() and return to the main select() */
	return NL_STOP;
}

int main(int argc, char *argv[])
{
	struct nl_sock *rt_sock;
	struct nl_cache *link_cache;
	struct nfnl_queue *queue;
	enum nfnl_queue_copy_mode copy_mode;
	uint32_t copy_range;
	int err = 1;
	int family;

	nf_sock = nfnl_queue_socket_alloc();
	if (nf_sock == NULL)
		nl_cli_fatal(ENOBUFS, "Unable to allocate netlink socket");

	nl_socket_disable_seq_check(nf_sock);
	nl_socket_modify_cb(nf_sock, NL_CB_VALID, NL_CB_CUSTOM, event_input, NULL);

	if ((argc > 1 && !strcasecmp(argv[1], "-h")) || argc < 3) {
		printf("Usage: nf-queue family group [ copy_mode ] "
		       "[ copy_range ]\n");
		printf("family: [ inet | inet6 | ... ] \n");
		printf("group: the --queue-num arg that you gave to iptables\n");
		printf("copy_mode: [ none | meta | packet ] \n");
		return 2;
	}

	nl_cli_connect(nf_sock, NETLINK_NETFILTER);

	if ((family = nl_str2af(argv[1])) == AF_UNSPEC)
		nl_cli_fatal(NLE_INVAL, "Unknown family \"%s\"", argv[1]);

	nfnl_queue_pf_unbind(nf_sock, family);
	if ((err = nfnl_queue_pf_bind(nf_sock, family)) < 0)
		nl_cli_fatal(err, "Unable to bind logger: %s",
			     nl_geterror(err));

	queue = alloc_queue();
	nfnl_queue_set_group(queue, atoi(argv[2]));

	copy_mode = NFNL_QUEUE_COPY_PACKET;
	if (argc > 3) {
		copy_mode = nfnl_queue_str2copy_mode(argv[3]);
		if (copy_mode < 0)
			nl_cli_fatal(copy_mode,
				     "Unable to parse copy mode \"%s\": %s",
				     argv[3], nl_geterror(copy_mode));
	}
	nfnl_queue_set_copy_mode(queue, copy_mode);

	copy_range = 0xFFFF;
	if (argc > 4)
		copy_range = atoi(argv[4]);
	nfnl_queue_set_copy_range(queue, copy_range);

	if ((err = nfnl_queue_create(nf_sock, queue)) < 0)
		nl_cli_fatal(err, "Unable to bind queue: %s", nl_geterror(err));

	rt_sock = nl_cli_alloc_socket();
	nl_cli_connect(rt_sock, NETLINK_ROUTE);
	link_cache = nl_cli_link_alloc_cache(rt_sock);

	nl_socket_set_buffer_size(nf_sock, 1024*127, 1024*127);

	while (1) {
		fd_set rfds;
		int nffd, rtfd, maxfd, retval;

		FD_ZERO(&rfds);

		maxfd = nffd = nl_socket_get_fd(nf_sock);
		FD_SET(nffd, &rfds);

		rtfd = nl_socket_get_fd(rt_sock);
		FD_SET(rtfd, &rfds);
		if (maxfd < rtfd)
			maxfd = rtfd;

		/* wait for an incoming message on the netlink socket */
		retval = select(maxfd+1, &rfds, NULL, NULL, NULL);

		if (retval) {
			if (FD_ISSET(nffd, &rfds))
				nl_recvmsgs_default(nf_sock);
			if (FD_ISSET(rtfd, &rfds))
				nl_recvmsgs_default(rt_sock);
		}
	}

	return 0;
}
Beispiel #19
0
static void obj_input(struct nl_object *obj, void *arg)
{
	struct nfnl_queue_msg *msg = (struct nfnl_queue_msg *) obj;
	struct nl_dump_params dp = {
		.dp_type = NL_DUMP_STATS,
		.dp_fd = stdout,
		.dp_dump_msgtype = 1,
	};

	nfnl_queue_msg_set_verdict(msg, NF_ACCEPT);
	nl_object_dump(obj, &dp);
	nfnl_queue_msg_send_verdict(nfnlh, msg);
}

static int event_input(struct nl_msg *msg, void *arg)
{
	if (nl_msg_parse(msg, &obj_input, NULL) < 0)
		fprintf(stderr, "<<EVENT>> Unknown message type\n");

	/* Exit nl_recvmsgs_def() and return to the main select() */
	return NL_STOP;
}

int main(int argc, char *argv[])
{
	struct nl_handle *rtnlh;
	struct nl_cache *link_cache;
	struct nfnl_queue *queue;
	enum nfnl_queue_copy_mode copy_mode;
	uint32_t copy_range;
	int err = 1;
	int family;

	if (nltool_init(argc, argv) < 0)
		return -1;

	nfnlh = nltool_alloc_handle();
	if (nfnlh == NULL)
		return -1;

	nl_disable_sequence_check(nfnlh);

	nl_socket_modify_cb(nfnlh, NL_CB_VALID, NL_CB_CUSTOM, event_input, NULL);

	if ((argc > 1 && !strcasecmp(argv[1], "-h")) || argc < 3) {
		printf("Usage: nf-queue family group [ copy_mode ] "
		       "[ copy_range ]\n");
		return 2;
	}

	if (nfnl_connect(nfnlh) < 0) {
		fprintf(stderr, "%s\n", nl_geterror());
		goto errout;
	}

	family = nl_str2af(argv[1]);
	if (family == AF_UNSPEC) {
		fprintf(stderr, "Unknown family: %s\n", argv[1]);
		goto errout;
	}

	nfnl_queue_pf_unbind(nfnlh, family);
	if (nfnl_queue_pf_bind(nfnlh, family) < 0) {
		fprintf(stderr, "%s\n", nl_geterror());
		goto errout;
	}

	queue = nfnl_queue_alloc();
	if (queue == NULL) {
		fprintf(stderr, "%s\n", nl_geterror());
		goto errout;
	}

	nfnl_queue_set_group(queue, atoi(argv[2]));

	copy_mode = NFNL_QUEUE_COPY_PACKET;
	if (argc > 3) {
		copy_mode = nfnl_queue_str2copy_mode(argv[3]);
		if (copy_mode < 0) {
			fprintf(stderr, "%s\n", nl_geterror());
			goto errout;
		}
	}
	nfnl_queue_set_copy_mode(queue, copy_mode);

	copy_range = 0xFFFF;
	if (argc > 4)
		copy_range = atoi(argv[4]);
	nfnl_queue_set_copy_range(queue, copy_range);

	if (nfnl_queue_create(nfnlh, queue) < 0) {
		fprintf(stderr, "%s\n", nl_geterror());
		goto errout;
	}

	rtnlh = nltool_alloc_handle();
	if (rtnlh == NULL) {
		goto errout_close;
	}

	if (nl_connect(rtnlh, NETLINK_ROUTE) < 0) {
		fprintf(stderr, "%s\n", nl_geterror());
		goto errout;
	}

	if ((link_cache = rtnl_link_alloc_cache(rtnlh)) == NULL) {
		fprintf(stderr, "%s\n", nl_geterror());
		goto errout_close;
	}

	nl_cache_mngt_provide(link_cache);

	while (1) {
		fd_set rfds;
		int nffd, rtfd, maxfd, retval;

		FD_ZERO(&rfds);

		maxfd = nffd = nl_socket_get_fd(nfnlh);
		FD_SET(nffd, &rfds);

		rtfd = nl_socket_get_fd(rtnlh);
		FD_SET(rtfd, &rfds);
		if (maxfd < rtfd)
			maxfd = rtfd;

		/* wait for an incoming message on the netlink socket */
		retval = select(maxfd+1, &rfds, NULL, NULL, NULL);

		if (retval) {
			if (FD_ISSET(nffd, &rfds))
				nl_recvmsgs_default(nfnlh);
			if (FD_ISSET(rtfd, &rfds))
				nl_recvmsgs_default(rtnlh);
		}
	}

	nl_cache_mngt_unprovide(link_cache);
	nl_cache_free(link_cache);

	nfnl_queue_put(queue);

	nl_close(rtnlh);
	nl_handle_destroy(rtnlh);
errout_close:
	nl_close(nfnlh);
	nl_handle_destroy(nfnlh);
errout:
	return err;
}
Beispiel #20
0
int main(int argc, char *argv[])
{
	struct nl_sock *sock;
	struct rtnl_route *route;
	struct nl_dump_params dp = {
		.dp_type = NL_DUMP_LINE,
		.dp_fd = stdout,
	};
	int err = 1;

	sock = nl_cli_alloc_socket();
	nl_cli_connect(sock, NETLINK_ROUTE);
	link_cache = nl_cli_link_alloc_cache(sock);
	route_cache = nl_cli_route_alloc_cache(sock, 0);
	route = nl_cli_route_alloc();

	for (;;) {
		int c, optidx = 0;
		enum {
			ARG_FAMILY = 257,
			ARG_SRC = 258,
			ARG_IIF,
			ARG_PREF_SRC,
			ARG_METRICS,
			ARG_PRIORITY,
			ARG_SCOPE,
			ARG_PROTOCOL,
			ARG_TYPE,
		};
		static struct option long_opts[] = {
			{ "quiet", 0, 0, 'q' },
			{ "help", 0, 0, 'h' },
			{ "version", 0, 0, 'v' },
			{ "dst", 1, 0, 'd' },
			{ "nexthop", 1, 0, 'n' },
			{ "table", 1, 0, 't' },
			{ "family", 1, 0, ARG_FAMILY },
			{ "src", 1, 0, ARG_SRC },
			{ "iif", 1, 0, ARG_IIF },
			{ "pref-src", 1, 0, ARG_PREF_SRC },
			{ "metrics", 1, 0, ARG_METRICS },
			{ "priority", 1, 0, ARG_PRIORITY },
			{ "scope", 1, 0, ARG_SCOPE },
			{ "protocol", 1, 0, ARG_PROTOCOL },
			{ "type", 1, 0, ARG_TYPE },
			{ 0, 0, 0, 0 }
		};

		c = getopt_long(argc, argv, "qhvd:n:t:", long_opts, &optidx);
		if (c == -1)
			break;

		switch (c) {
		case 'q': quiet = 1; break;
		case 'h': print_usage(); break;
		case 'v': nl_cli_print_version(); break;
		case 'd': nl_cli_route_parse_dst(route, optarg); break;
		case 'n': nl_cli_route_parse_nexthop(route, optarg, link_cache); break;
		case 't': nl_cli_route_parse_table(route, optarg); break;
		case ARG_FAMILY: nl_cli_route_parse_family(route, optarg); break;
		case ARG_SRC: nl_cli_route_parse_src(route, optarg); break;
		case ARG_IIF: nl_cli_route_parse_iif(route, optarg, link_cache); break;
		case ARG_PREF_SRC: nl_cli_route_parse_pref_src(route, optarg); break;
		case ARG_METRICS: nl_cli_route_parse_metric(route, optarg); break;
		case ARG_PRIORITY: nl_cli_route_parse_prio(route, optarg); break;
		case ARG_SCOPE: nl_cli_route_parse_scope(route, optarg); break;
		case ARG_PROTOCOL: nl_cli_route_parse_protocol(route, optarg); break;
		case ARG_TYPE: nl_cli_route_parse_type(route, optarg); break;
		}
	}

	if ((err = rtnl_route_add(sock, route, NLM_F_EXCL)) < 0)
		nl_cli_fatal(err, "Unable to add route: %s", nl_geterror(err));

	if (!quiet) {
		printf("Added ");
		nl_object_dump(OBJ_CAST(route), &dp);
	}

	return 0;
}
int main(int argc, char *argv[])
{
	struct nl_sock *sock;
	struct rtnl_cls *cls;
	struct nl_cache *link_cache;
	struct rtnl_cls_ops *ops;
	struct cls_module *mod;
	struct nl_dump_params dp = {
		.dp_type = NL_DUMP_DETAILS,
		.dp_fd = stdout,
	};
	char *kind;
	int err, nlflags = NLM_F_CREATE;
 
	sock = nlt_alloc_socket();
	nlt_connect(sock, NETLINK_ROUTE);
	link_cache = nlt_alloc_link_cache(sock);
	cls = nlt_alloc_cls();

	for (;;) {
		int c, optidx = 0;
		enum {
			ARG_PROTO = 257,
			ARG_PRIO = 258,
			ARG_ID,
		};
		static struct option long_opts[] = {
			{ "quiet", 0, 0, 'q' },
			{ "help", 0, 0, 'h' },
			{ "version", 0, 0, 'v' },
			{ "dev", 1, 0, 'd' },
			{ "parent", 1, 0, 'p' },
			{ "proto", 1, 0, ARG_PROTO },
			{ "prio", 1, 0, ARG_PRIO },
			{ "id", 1, 0, ARG_ID },
			{ 0, 0, 0, 0 }
		};
	
		c = getopt_long(argc, argv, "+qhva:d:", long_opts, &optidx);
		if (c == -1)
			break;

		switch (c) {
		case '?': exit(NLE_INVAL);
		case 'q': quiet = 1; break;
		case 'h': print_usage(); break;
		case 'v': nlt_print_version(); break;
		case 'd': parse_dev(cls, link_cache, optarg); break;
		case 'p': parse_parent(cls, optarg); break;
		case ARG_PRIO: parse_prio(cls, optarg); break;
		case ARG_ID: parse_handle(cls, optarg); break;
		case ARG_PROTO: parse_proto(cls, optarg); break;
		}
 	}

	if (optind >= argc) {
		print_usage();
		fatal(EINVAL, "Missing classifier type");
	}

	kind = argv[optind++];
	if ((err = rtnl_cls_set_kind(cls, kind)) < 0)
		fatal(ENOENT, "Unknown classifier type \"%s\".", kind);
	
	ops = rtnl_cls_get_ops(cls);
	if (!(mod = lookup_cls_mod(ops)))
		fatal(ENOTSUP, "Classifier type \"%s\" not supported.", kind);

	mod->parse_argv(cls, argc, argv);

	printf("Adding ");
	nl_object_dump(OBJ_CAST(cls), &dp);

	if ((err = rtnl_cls_add(sock, cls, nlflags)) < 0)
		fatal(err, "Unable to add classifier: %s", nl_geterror(err));

	if (!quiet) {
		printf("Added ");
		nl_object_dump(OBJ_CAST(cls), &dp);
 	}

	return 0;
}
Beispiel #22
0
int main(int argc, char *argv[])
{
	struct nl_sock *sock;
	struct rtnl_cls *cls;
	struct rtnl_tc *tc;
	struct nl_cache *link_cache;
	struct nl_dump_params dp = {
		.dp_type = NL_DUMP_DETAILS,
		.dp_fd = stdout,
	};
	struct nl_cli_tc_module *tm;
	struct rtnl_tc_ops *ops;
	int err, flags = NLM_F_CREATE | NLM_F_EXCL;
	char *kind, *id = NULL;
 
	sock = nl_cli_alloc_socket();
	nl_cli_connect(sock, NETLINK_ROUTE);

	link_cache = nl_cli_link_alloc_cache(sock);

 	cls = nl_cli_cls_alloc();
	tc = (struct rtnl_tc *) cls;
 
	for (;;) {
		int c, optidx = 0;
		enum {
			ARG_UPDATE = 257,
			ARG_UPDATE_ONLY = 258,
			ARG_MTU,
			ARG_MPU,
			ARG_OVERHEAD,
			ARG_LINKTYPE,
			ARG_PROTO,
			ARG_PRIO,
		};
		static struct option long_opts[] = {
			{ "quiet", 0, 0, 'q' },
			{ "help", 0, 0, 'h' },
			{ "version", 0, 0, 'v' },
			{ "dev", 1, 0, 'd' },
			{ "parent", 1, 0, 'p' },
			{ "id", 1, 0, 'i' },
			{ "proto", 1, 0, ARG_PROTO },
			{ "prio", 1, 0, ARG_PRIO },
			{ "update", 0, 0, ARG_UPDATE },
			{ "update-only", 0, 0, ARG_UPDATE_ONLY },
			{ "mtu", 1, 0, ARG_MTU },
			{ "mpu", 1, 0, ARG_MPU },
			{ "overhead", 1, 0, ARG_OVERHEAD },
			{ "linktype", 1, 0, ARG_LINKTYPE },
			{ 0, 0, 0, 0 }
		};
	
		c = getopt_long(argc, argv, "+qhvd:p:i:",
				long_opts, &optidx);
		if (c == -1)
			break;

		switch (c) {
		case 'q': quiet = 1; break;
		case 'h': print_usage(); break;
		case 'v': nl_cli_print_version(); break;
		case 'd': nl_cli_tc_parse_dev(tc, link_cache, optarg); break;
		case 'p': nl_cli_tc_parse_parent(tc, optarg); break;
		case 'i': id = strdup(optarg); break;
		case ARG_UPDATE: flags = NLM_F_CREATE; break;
		case ARG_UPDATE_ONLY: flags = 0; break;
		case ARG_MTU: nl_cli_tc_parse_mtu(tc, optarg); break;
		case ARG_MPU: nl_cli_tc_parse_mpu(tc, optarg); break;
		case ARG_OVERHEAD: nl_cli_tc_parse_overhead(tc, optarg); break;
		case ARG_LINKTYPE: nl_cli_tc_parse_linktype(tc, optarg); break;
		case ARG_PROTO: nl_cli_cls_parse_proto(cls, optarg); break;
		case ARG_PRIO:
			rtnl_cls_set_prio(cls, nl_cli_parse_u32(optarg));
			break;
		}
 	}

	if (optind >= argc)
		print_usage();

	if (!rtnl_tc_get_ifindex(tc))
		nl_cli_fatal(EINVAL, "You must specify a network device (--dev=XXX)");

	if (!rtnl_tc_get_parent(tc))
		nl_cli_fatal(EINVAL, "You must specify a parent (--parent=XXX)");

	if (id) {
		nl_cli_tc_parse_handle(tc, id, 1);
		free(id);
	}

	kind = argv[optind++];
	rtnl_tc_set_kind(tc, kind);

	if (!(ops = rtnl_tc_get_ops(tc)))
		nl_cli_fatal(ENOENT, "Unknown classifier \"%s\".", kind);

	if (!(tm = nl_cli_tc_lookup(ops)))
		nl_cli_fatal(ENOTSUP, "Classifier type \"%s\" not supported.", kind);

	tm->tm_parse_argv(tc, argc, argv);

	if (!quiet) {
		printf("Adding ");
		nl_object_dump(OBJ_CAST(cls), &dp);
 	}

	if ((err = rtnl_cls_add(sock, cls, flags)) < 0)
		nl_cli_fatal(EINVAL, "Unable to add classifier: %s", nl_geterror(err));

	return 0;
}
Beispiel #23
0
int main(int argc, char *argv[])
{
	struct nl_sock *sock;
	struct nfnl_ct *ct;
	struct nl_dump_params params = {
		.dp_type = NL_DUMP_LINE,
		.dp_fd = stdout,
	};
	int err, nlflags = NLM_F_CREATE;

	ct = nl_cli_ct_alloc();

	for (;;) {
		int c, optidx = 0;
		enum {
			ARG_ORIG_SRC = 257,
			ARG_ORIG_SPORT = 258,
			ARG_ORIG_DST,
			ARG_ORIG_DPORT,
			ARG_REPLY_SRC,
			ARG_REPLY_SPORT,
			ARG_REPLY_DST,
			ARG_REPLY_DPORT,
			ARG_MARK,
			ARG_TIMEOUT,
			ARG_STATUS,
			ARG_ZONE,
		};
		static struct option long_opts[] = {
			{ "quiet", 0, 0, 'q' },
			{ "help", 0, 0, 'h' },
			{ "version", 0, 0, 'v' },
			{ "proto", 1, 0, 'p' },
			{ "orig-src", 1, 0, ARG_ORIG_SRC },
			{ "orig-sport", 1, 0, ARG_ORIG_SPORT },
			{ "orig-dst", 1, 0, ARG_ORIG_DST },
			{ "orig-dport", 1, 0, ARG_ORIG_DPORT },
			{ "reply-src", 1, 0, ARG_REPLY_SRC },
			{ "reply-sport", 1, 0, ARG_REPLY_SPORT },
			{ "reply-dst", 1, 0, ARG_REPLY_DST },
			{ "reply-dport", 1, 0, ARG_REPLY_DPORT },
			{ "family", 1, 0, 'F' },
			{ "mark", 1, 0, ARG_MARK },
			{ "timeout", 1, 0, ARG_TIMEOUT },
			{ "status", 1, 0, ARG_STATUS },
			{ "zone", 1, 0, ARG_ZONE },
			{ 0, 0, 0, 0 }
		};

		c = getopt_long(argc, argv, "46q:hv:p:F:", long_opts, &optidx);
		if (c == -1)
			break;

		switch (c) {
		case '?': exit(NLE_INVAL);
		case 'q': quiet = 1; break;
		case '4': nfnl_ct_set_family(ct, AF_INET); break;
		case '6': nfnl_ct_set_family(ct, AF_INET6); break;
		case 'h': print_usage(); break;
		case 'v': nl_cli_print_version(); break;
		case 'p': nl_cli_ct_parse_protocol(ct, optarg); break;
		case ARG_ORIG_SRC: nl_cli_ct_parse_src(ct, 0, optarg); break;
		case ARG_ORIG_SPORT: nl_cli_ct_parse_src_port(ct, 0, optarg); break;
		case ARG_ORIG_DST: nl_cli_ct_parse_dst(ct, 0, optarg); break;
		case ARG_ORIG_DPORT: nl_cli_ct_parse_dst_port(ct, 0, optarg); break;
		case ARG_REPLY_SRC: nl_cli_ct_parse_src(ct, 1, optarg); break;
		case ARG_REPLY_SPORT: nl_cli_ct_parse_src_port(ct, 1, optarg); break;
		case ARG_REPLY_DST: nl_cli_ct_parse_dst(ct, 1, optarg); break;
		case ARG_REPLY_DPORT: nl_cli_ct_parse_dst_port(ct, 1, optarg); break;
		case 'F': nl_cli_ct_parse_family(ct, optarg); break;
		case ARG_MARK: nl_cli_ct_parse_mark(ct, optarg); break;
		case ARG_TIMEOUT: nl_cli_ct_parse_timeout(ct, optarg); break;
		case ARG_STATUS: nl_cli_ct_parse_status(ct, optarg); break;
		case ARG_ZONE: nl_cli_ct_parse_zone(ct, optarg); break;
		}
	}

	if (!quiet) {
		printf("Adding ");
		nl_object_dump(OBJ_CAST(ct), &params);
	}

	sock = nl_cli_alloc_socket();
	nl_cli_connect(sock, NETLINK_NETFILTER);

	if ((err = nfnl_ct_add(sock, ct, nlflags)) < 0)
		nl_cli_fatal(err, "Unable to add conntrack: %s", nl_geterror(err));

	if (!quiet) {
		printf("Added ");
		nl_object_dump(OBJ_CAST(ct), &params);
	}

	return 0;
}
Beispiel #24
0
int main(int argc, char *argv[])
{
	struct nl_sock *sock;
	struct nl_dect_cluster *cl;
	struct nl_dect_ari *pari;
	struct nl_dump_params params = {
		.dp_type = NL_DUMP_LINE,
		.dp_fd = stdout,
	};
	int err;

	sock = nl_cli_alloc_socket();
	nl_cli_connect(sock, NETLINK_DECT);
	cl = nl_dect_cluster_alloc();
	pari = (void *)nl_dect_cluster_get_pari(cl);

	for (;;) {
		int c, optidx = 0;
		enum {
			ARG_NAME = 257,
			ARG_MODE,
			ARG_EMC,
			ARG_FPN,
		};
		static struct option long_opts[] = {
			{ "name",		1, 0, ARG_NAME },
			{ "mode",		1, 0, ARG_MODE },
			{ "emc",		1, 0, ARG_EMC },
			{ "fpn",		1, 0, ARG_FPN },
			{ 0, 0, 0, 0 }
		};

		c = getopt_long(argc, argv, "qhvd:n:t:", long_opts, &optidx);
		if (c == -1)
			break;

		switch (c) {
		case 'v': nl_cli_print_version(); break;
		case ARG_NAME:
			nl_dect_cluster_set_name(cl, strdup(optarg));
			break;
		case ARG_MODE:
			nl_dect_cluster_set_mode(cl, atoi(optarg));
			break;
		case ARG_EMC:
			nl_dect_ari_set_emc(pari, strtoul(optarg, NULL, 16));
			break;
		case ARG_FPN:
			nl_dect_ari_set_fpn(pari, strtoul(optarg, NULL, 16));
			break;
		}
	}

	err = nl_dect_cluster_delete(sock, cl, 0);
	if (err < 0)
		nl_cli_fatal(err, "Unable to delete cluster: %s", nl_geterror(err));

	printf("Deleted: ");
	nl_object_dump(OBJ_CAST(cl), &params);
	return 0;
}
Beispiel #25
0
int main(int argc, char *argv[])
{
	struct nl_sock *sock;
	struct nfnl_exp *exp;
	struct nl_dump_params params = {
		.dp_type = NL_DUMP_LINE,
		.dp_fd = stdout,
	};
	int err, nlflags = NLM_F_CREATE;

	exp = nl_cli_exp_alloc();

	for (;;) {
		int c, optidx = 0;
		enum {
			ARG_MARK = 270,
			ARG_TCP_STATE = 271,
			ARG_EXPECT_PROTO,
			ARG_EXPECT_SRC,
			ARG_EXPECT_SPORT,
			ARG_EXPECT_DST,
			ARG_EXPECT_DPORT,
			ARG_MASTER_PROTO,
			ARG_MASTER_SRC,
			ARG_MASTER_SPORT,
			ARG_MASTER_DST,
			ARG_MASTER_DPORT,
			ARG_MASK_PROTO,
			ARG_MASK_SRC,
			ARG_MASK_SPORT,
			ARG_MASK_DST,
			ARG_MASK_DPORT,
			ARG_NAT_PROTO,
			ARG_NAT_SRC,
			ARG_NAT_SPORT,
			ARG_NAT_DST,
			ARG_NAT_DPORT,
			ARG_NAT_DIR,
			ARG_TIMEOUT,
			ARG_HELPER_NAME,
			ARG_REPLACE,
			ARG_FLAGS,
		};
		static struct option long_opts[] = {
			{ "replace", 1, 0, ARG_REPLACE },
			{ "quiet", 0, 0, 'q' },
			{ "help", 0, 0, 'h' },
			{ "version", 0, 0, 'v' },
			{ "id", 1, 0, 'i' },
			{ "expect-proto", 1, 0, ARG_EXPECT_PROTO },
			{ "expect-src", 1, 0, ARG_EXPECT_SRC },
			{ "expect-sport", 1, 0, ARG_EXPECT_SPORT },
			{ "expect-dst", 1, 0, ARG_EXPECT_DST },
			{ "expect-dport", 1, 0, ARG_EXPECT_DPORT },
			{ "master-proto", 1, 0, ARG_MASTER_PROTO },
			{ "master-src", 1, 0, ARG_MASTER_SRC },
			{ "master-sport", 1, 0, ARG_MASTER_SPORT },
			{ "master-dst", 1, 0, ARG_MASTER_DST },
			{ "master-dport", 1, 0, ARG_MASTER_DPORT },
			{ "mask-proto", 1, 0, ARG_MASK_PROTO },
			{ "mask-src", 1, 0, ARG_MASK_SRC },
			{ "mask-sport", 1, 0, ARG_MASK_SPORT },
			{ "mask-dst", 1, 0, ARG_MASK_DST },
			{ "mask-dport", 1, 0, ARG_MASK_DPORT },
			{ "nat-proto", 1, 0, ARG_NAT_PROTO },
			{ "nat-src", 1, 0, ARG_NAT_SRC },
			{ "nat-sport", 1, 0, ARG_NAT_SPORT },
			{ "nat-dst", 1, 0, ARG_NAT_DST },
			{ "nat-dport", 1, 0, ARG_NAT_DPORT },
			{ "nat-dir", 1, 0, ARG_NAT_DIR },
			{ "family", 1, 0, 'F' },
			{ "timeout", 1, 0, ARG_TIMEOUT },
			{ "helper", 1, 0, ARG_HELPER_NAME },
			{ "flags", 1, 0, ARG_FLAGS},
			{ 0, 0, 0, 0 }
		};

		c = getopt_long(argc, argv, "46f:hvi:p:F:", long_opts, &optidx);
		if (c == -1)
			break;

		switch (c) {
		case '?': exit(NLE_INVAL);
		case ARG_REPLACE: nlflags |= NLM_F_REPLACE; break;
		case 'q': quiet = 1; break;
		case '4': nfnl_exp_set_family(exp, AF_INET); break;
		case '6': nfnl_exp_set_family(exp, AF_INET6); break;
		case 'h': print_usage(); break;
		case 'v': nl_cli_print_version(); break;
		case 'i': nl_cli_exp_parse_id(exp, optarg); break;
		case ARG_EXPECT_PROTO: nl_cli_exp_parse_l4protonum(exp, NFNL_EXP_TUPLE_EXPECT, optarg); break;
		case ARG_EXPECT_SRC: nl_cli_exp_parse_src(exp, NFNL_EXP_TUPLE_EXPECT, optarg); break;
		case ARG_EXPECT_SPORT: nl_cli_exp_parse_src_port(exp, NFNL_EXP_TUPLE_EXPECT, optarg); break;
		case ARG_EXPECT_DST: nl_cli_exp_parse_dst(exp, NFNL_EXP_TUPLE_EXPECT, optarg); break;
		case ARG_EXPECT_DPORT: nl_cli_exp_parse_dst_port(exp, NFNL_EXP_TUPLE_EXPECT, optarg); break;
		case ARG_MASTER_PROTO: nl_cli_exp_parse_l4protonum(exp, NFNL_EXP_TUPLE_MASTER, optarg); break;
		case ARG_MASTER_SRC: nl_cli_exp_parse_src(exp, NFNL_EXP_TUPLE_MASTER, optarg); break;
		case ARG_MASTER_SPORT: nl_cli_exp_parse_src_port(exp, NFNL_EXP_TUPLE_MASTER, optarg); break;
		case ARG_MASTER_DST: nl_cli_exp_parse_dst(exp, NFNL_EXP_TUPLE_MASTER, optarg); break;
		case ARG_MASTER_DPORT: nl_cli_exp_parse_dst_port(exp, NFNL_EXP_TUPLE_MASTER, optarg); break;
		case ARG_MASK_PROTO: nl_cli_exp_parse_l4protonum(exp, NFNL_EXP_TUPLE_MASK, optarg); break;
		case ARG_MASK_SRC: nl_cli_exp_parse_src(exp, NFNL_EXP_TUPLE_MASK, optarg); break;
		case ARG_MASK_SPORT: nl_cli_exp_parse_src_port(exp, NFNL_EXP_TUPLE_MASK, optarg); break;
		case ARG_MASK_DST: nl_cli_exp_parse_dst(exp, NFNL_EXP_TUPLE_MASK, optarg); break;
		case ARG_MASK_DPORT: nl_cli_exp_parse_dst_port(exp, NFNL_EXP_TUPLE_MASK, optarg); break;
		case ARG_NAT_PROTO: nl_cli_exp_parse_l4protonum(exp, NFNL_EXP_TUPLE_NAT, optarg); break;
		case ARG_NAT_SRC: nl_cli_exp_parse_src(exp, NFNL_EXP_TUPLE_NAT, optarg); break;
		case ARG_NAT_SPORT: nl_cli_exp_parse_src_port(exp, NFNL_EXP_TUPLE_NAT, optarg); break;
		case ARG_NAT_DST: nl_cli_exp_parse_dst(exp, NFNL_EXP_TUPLE_NAT, optarg); break;
		case ARG_NAT_DPORT: nl_cli_exp_parse_dst_port(exp, NFNL_EXP_TUPLE_NAT, optarg); break;
		case ARG_NAT_DIR: nl_cli_exp_parse_nat_dir(exp, optarg); break;
		case 'F': nl_cli_exp_parse_family(exp, optarg); break;
		case ARG_TIMEOUT: nl_cli_exp_parse_timeout(exp, optarg); break;
		case ARG_HELPER_NAME: nl_cli_exp_parse_helper_name(exp, optarg); break;
		case ARG_FLAGS: nl_cli_exp_parse_flags(exp, optarg); break;
		}
	}

	sock = nl_cli_alloc_socket();
	nl_cli_connect(sock, NETLINK_NETFILTER);

	if ((err = nfnl_exp_add(sock, exp, nlflags)) < 0)
		nl_cli_fatal(err, "Unable to add expectation: %s", nl_geterror(err));

	if (!quiet) {
		printf("Added ");
		nl_object_dump(OBJ_CAST(exp), &params);
	}

	return 0;
}
void NetlinkManager::netlinkRouteUpdated(
    struct nl_cache* /*cache*/,
    struct nl_object* obj,
    int nlOperation,
    void* data) {
  NetlinkManager* nlm = static_cast<NetlinkManager*>(data);
  std::string operation = nlm->nlOperationToStr(nlOperation);
  if (operation == "unknown") {
    VLOG(1) << "Ignoring an unknown route update";
    return;
  }

  VLOG(2) << "Received a " << operation << " netlink route update message";
  struct rtnl_route* route = (struct rtnl_route*)obj;

  if (rtnl_route_get_type(route) != RTN_UNICAST) {
    VLOG(1) << "Ignoring non-unicast route update";
    return;
  }

  struct nl_addr* nlDst = rtnl_route_get_dst(route);
  const uint8_t ipLen = nl_addr_get_prefixlen(nlDst);
  char strDst[ipLen];
  nl_addr2str(nlDst, strDst, ipLen);

  int numNexthops = rtnl_route_get_nnexthops(route);
  if (!numNexthops) {
    VLOG(0) << "Could not find next hop for route update for " << strDst;
    struct nl_dump_params dumpParams = initDumpParams();
    nl_object_dump((nl_object*)route, &dumpParams);
    return;
  }

  std::vector<BinaryAddress> nexthops;
  {
    std::lock_guard<std::mutex> lock(nlm->interfacesMutex_);
    nexthops = getNextHops(route, ipLen, nlm->monitoredInterfaces_);
  }

  if (nexthops.empty()) {
    VLOG(1) << operation << " Route update for " << strDst
            << " has no valid nexthop";
    return;
  }

  if (FLAGS_debug) {
    VLOG(1) << "Got " << operation << " route update for " << strDst;
    return;
  }

  switch (nlOperation) {
    case NL_ACT_NEW: {
      nlm->addRouteViaFbossThrift(nlDst, nexthops);
      break;
    }
    case NL_ACT_DEL: {
      nlm->deleteRouteViaFbossThrift(nlDst);
      break;
    }
    case NL_ACT_CHANGE: {
      VLOG(2) << "Not updating state due to unimplemented"
              << "NL_ACT_CHANGE netlink operation";
      break;
    }
    default: {
      VLOG(0) << "Not updating state due to unknown netlink operation "
              << std::to_string(nlOperation);
      break; /* NL_ACT_??? */
    }
  }
  return;
}
static void obj_input(struct nl_object *obj, void *arg)
{
	struct nl_dump_params dp = {
		.dp_type = NL_DUMP_STATS,
		.dp_fd = stdout,
		.dp_dump_msgtype = 1,
	};

	nl_object_dump(obj, &dp);
}

static int event_input(struct nl_msg *msg, void *arg)
{
	if (nl_msg_parse(msg, &obj_input, NULL) < 0)
		fprintf(stderr, "<<EVENT>> Unknown message type\n");

	/* Exit nl_recvmsgs_def() and return to the main select() */
	return NL_STOP;
}

int main(int argc, char *argv[])
{
	struct nl_handle *nlh;
	int err = 1;
	int i, idx;

	static const struct {
		enum nfnetlink_groups gr_id;
		const char* gr_name;
	} known_groups[] = {
		{ NFNLGRP_CONNTRACK_NEW, "ct-new" },
		{ NFNLGRP_CONNTRACK_UPDATE, "ct-update" },
		{ NFNLGRP_CONNTRACK_DESTROY, "ct-destroy" },
		{ NFNLGRP_NONE, NULL }
	};

	if (nltool_init(argc, argv) < 0)
		return -1;

	nlh = nltool_alloc_handle();
	if (nlh == NULL)
		return -1;

	nl_disable_sequence_check(nlh);

	nl_socket_modify_cb(nlh, NL_CB_VALID, NL_CB_CUSTOM, event_input, NULL);

	if (argc > 1 && !strcasecmp(argv[1], "-h")) {
		printf("Usage: nf-monitor [<groups>]\n");

		printf("Known groups:");
		for (i = 0; known_groups[i].gr_id != NFNLGRP_NONE; i++)
			printf(" %s", known_groups[i].gr_name);
		printf("\n");
		return 2;
	}

	if (nfnl_connect(nlh) < 0) {
		fprintf(stderr, "%s\n", nl_geterror());
		goto errout;
	}

	for (idx = 1; argc > idx; idx++) {
		for (i = 0; known_groups[i].gr_id != NFNLGRP_NONE; i++) {
			if (!strcmp(argv[idx], known_groups[i].gr_name)) {

				if (nl_socket_add_membership(nlh, known_groups[i].gr_id) < 0) {
					fprintf(stderr, "%s: %s\n", argv[idx], nl_geterror());
					goto errout;
				}

				break;
			}
		}
		if (known_groups[i].gr_id == NFNLGRP_NONE)
			fprintf(stderr, "Warning: Unknown group: %s\n", argv[idx]);
	}

	while (1) {
		fd_set rfds;
		int fd, retval;

		fd = nl_socket_get_fd(nlh);

		FD_ZERO(&rfds);
		FD_SET(fd, &rfds);
		/* wait for an incoming message on the netlink socket */
		retval = select(fd+1, &rfds, NULL, NULL, NULL);

		if (retval) {
			/* FD_ISSET(fd, &rfds) will be true */
			nl_recvmsgs_default(nlh);
		}
	}

	nl_close(nlh);
errout:
	return err;
}