summaryrefslogtreecommitdiffstats
path: root/netlink/netlink.h
blob: 1274a3b8cec070fca415f1df3848c55465edfebb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/*
 * netlink.h - common interface for all netlink code
 *
 * Declarations of data structures, global data and helpers for netlink code
 */

#ifndef ETHTOOL_NETLINK_INT_H__
#define ETHTOOL_NETLINK_INT_H__

#include <libmnl/libmnl.h>
#include <linux/netlink.h>
#include <linux/genetlink.h>
#include <linux/ethtool_netlink.h>
#include "nlsock.h"

#define WILDCARD_DEVNAME "*"
#define CMDMASK_WORDS DIV_ROUND_UP(__ETHTOOL_MSG_KERNEL_CNT, 32)

enum link_mode_class {
	LM_CLASS_UNKNOWN,
	LM_CLASS_REAL,
	LM_CLASS_AUTONEG,
	LM_CLASS_PORT,
	LM_CLASS_PAUSE,
	LM_CLASS_FEC,
};

struct nl_op_info {
	uint32_t		op_flags;
	uint32_t		hdr_flags;
	uint8_t			hdr_policy_loaded:1;
};

struct nl_context {
	struct cmd_context	*ctx;
	void			*cmd_private;
	const char		*devname;
	bool			is_dump;
	int			exit_code;
	unsigned int		suppress_nlerr;
	uint16_t		ethnl_fam;
	uint32_t		ethnl_mongrp;
	struct nl_op_info	*ops_info;
	struct nl_socket	*ethnl_socket;
	struct nl_socket	*ethnl2_socket;
	struct nl_socket	*rtnl_socket;
	bool			is_monitor;
	uint32_t		filter_cmds[CMDMASK_WORDS];
	const char		*filter_devname;
	bool			no_banner;
	const char		*cmd;
	const char		*param;
	char			**argp;
	unsigned int		argc;
	bool			ioctl_fallback;
	bool			wildcard_unsupported;
};

struct attr_tb_info {
	const struct nlattr **tb;
	unsigned int max_type;
};

#define DECLARE_ATTR_TB_INFO(tbl) \
	struct attr_tb_info tbl ## _info = { (tbl), (MNL_ARRAY_SIZE(tbl) - 1) }

int nomsg_reply_cb(const struct nlmsghdr *nlhdr, void *data);
int attr_cb(const struct nlattr *attr, void *data);

int netlink_init(struct cmd_context *ctx);
bool netlink_cmd_check(struct cmd_context *ctx, unsigned int cmd,
		       bool allow_wildcard);
const char *get_dev_name(const struct nlattr *nest);
int get_dev_info(const struct nlattr *nest, int *ifindex, char *ifname);
u32 get_stats_flag(struct nl_context *nlctx, unsigned int nlcmd,
		   unsigned int hdrattr);

int linkmodes_reply_cb(const struct nlmsghdr *nlhdr, void *data);
int linkinfo_reply_cb(const struct nlmsghdr *nlhdr, void *data);
int wol_reply_cb(const struct nlmsghdr *nlhdr, void *data);
int debug_reply_cb(const struct nlmsghdr *nlhdr, void *data);
int features_reply_cb(const struct nlmsghdr *nlhdr, void *data);
int privflags_reply_cb(const struct nlmsghdr *nlhdr, void *data);
int rings_reply_cb(const struct nlmsghdr *nlhdr, void *data);
int channels_reply_cb(const struct nlmsghdr *nlhdr, void *data);
int coalesce_reply_cb(const struct nlmsghdr *nlhdr, void *data);
int pause_reply_cb(const struct nlmsghdr *nlhdr, void *data);
int eee_reply_cb(const struct nlmsghdr *nlhdr, void *data);
int cable_test_reply_cb(const struct nlmsghdr *nlhdr, void *data);
int cable_test_ntf_cb(const struct nlmsghdr *nlhdr, void *data);
int cable_test_tdr_reply_cb(const struct nlmsghdr *nlhdr, void *data);
int cable_test_tdr_ntf_cb(const struct nlmsghdr *nlhdr, void *data);
int fec_reply_cb(const struct nlmsghdr *nlhdr, void *data);
int module_reply_cb(const struct nlmsghdr *nlhdr, void *data);

/* dump helpers */

int dump_link_modes(struct nl_context *nlctx, const struct nlattr *bitset,
		    bool mask, unsigned int class, const char *before,
		    const char *between, const char *after,
		    const char *if_none);

static inline void show_u32(const char *key,
			    const char *fmt,
			    const struct nlattr *attr)
{
	if (is_json_context()) {
		if (attr)
			print_uint(PRINT_JSON, key, NULL,
				   mnl_attr_get_u32(attr));
	} else {
		if (attr)
			printf("%s%u\n", fmt, mnl_attr_get_u32(attr));
		else
			printf("%sn/a\n", fmt);
	}
}

static inline const char *u8_to_bool(const uint8_t *val)
{
	if (val)
		return *val ? "on" : "off";
	else
		return "n/a";
}

static inline void show_bool_val(const char *key, const char *fmt, uint8_t *val)
{
	if (is_json_context()) {
		if (val)
			print_bool(PRINT_JSON, key, NULL, *val);
	} else {
		print_string(PRINT_FP, NULL, fmt, u8_to_bool(val));
	}
}

static inline void show_bool(const char *key, const char *fmt,
			     const struct nlattr *attr)
{
	show_bool_val(key, fmt, attr ? mnl_attr_get_payload(attr) : NULL);
}

static inline void show_cr(void)
{
	if (!is_json_context())
		putchar('\n');
}

/* misc */

static inline void copy_devname(char *dst, const char *src)
{
	strncpy(dst, src, ALTIFNAMSIZ);
	dst[ALTIFNAMSIZ - 1] = '\0';
}

static inline bool dev_ok(const struct nl_context *nlctx)
{
	return !nlctx->filter_devname ||
	       (nlctx->devname &&
		!strcmp(nlctx->devname, nlctx->filter_devname));
}

static inline int netlink_init_ethnl2_socket(struct nl_context *nlctx)
{
	if (nlctx->ethnl2_socket)
		return 0;
	return nlsock_init(nlctx, &nlctx->ethnl2_socket, NETLINK_GENERIC);
}

static inline int netlink_init_rtnl_socket(struct nl_context *nlctx)
{
	if (nlctx->rtnl_socket)
		return 0;
	return nlsock_init(nlctx, &nlctx->rtnl_socket, NETLINK_ROUTE);
}

#endif /* ETHTOOL_NETLINK_INT_H__ */