24 #include <netlink-private/netlink.h>
25 #include <netlink-private/genl.h>
26 #include <netlink/netlink.h>
27 #include <netlink/attr.h>
28 #include <netlink/utils.h>
29 #include <netlink/object.h>
30 #include <netlink/openvswitch/openvswitch.h>
31 #include <netlink/genl/genl.h>
32 #include <netlink/genl/mngt.h>
33 #include <linux/openvswitch.h>
39 char dp_name[IFNAMSIZ];
41 uint32_t dp_upcall_pid;
42 uint64_t dp_stats[OVS_DP_STAT_MAX+1];
45 #define DP_ATTR_NAME (1 << 0)
46 #define DP_ATTR_IFINDEX (1 << 1)
47 #define DP_ATTR_UPCALL_PID (1 << 2)
48 #define DP_ATTR_STATS (1 << 3)
50 static struct nl_cache_ops ovs_dp_cache_ops;
51 static struct nl_object_ops ovs_dp_obj_ops;
55 static struct nla_policy ovs_dp_policy[OVS_DP_ATTR_MAX+1] = {
57 [OVS_DP_ATTR_UPCALL_PID]= { .type =
NLA_U32 },
58 [OVS_DP_ATTR_STATS] = { .minlen =
sizeof(
struct ovs_dp_stats) },
61 static int ovs_dp_msg_parser(
struct nl_cache_ops *ops,
struct genl_cmd *cmd,
64 struct nl_parser_param *pp = arg;
65 struct ovs_header *hdr = info->
userhdr;
74 if (!info->
attrs[OVS_DP_ATTR_NAME]) {
75 err = -NLE_MISSING_ATTR;
79 dp->ce_msgtype = info->
nlh->nlmsg_type;
84 if (info->
attrs[OVS_DP_ATTR_UPCALL_PID]) {
89 if (info->
attrs[OVS_DP_ATTR_STATS]) {
90 struct ovs_dp_stats st;
94 dp->dp_stats[OVS_DP_STAT_HIT] = st.n_hit;
95 dp->dp_stats[OVS_DP_STAT_MISSED] = st.n_missed;
96 dp->dp_stats[OVS_DP_STAT_LOST] = st.n_lost;
97 dp->dp_stats[OVS_DP_STAT_FLOWS] = st.n_flows;
98 dp->ce_mask |= DP_ATTR_STATS;
101 err = pp->pp_cb(OBJ_CAST(dp), pp);
111 struct genlmsghdr genl_hdr;
112 struct ovs_header ovs_hdr;
116 static int ovs_dp_request_update(
struct nl_cache *cache,
struct nl_sock *sk)
118 struct request_hdr hdr = { };
121 if ((err = genl_resolve_id(&ovs_dp_ops)) < 0)
124 hdr.genl_hdr.cmd = OVS_DP_CMD_GET;
125 hdr.genl_hdr.version = OVS_DATAPATH_VERSION;
130 static void ovs_dp_dump_line(
struct nl_object *obj,
struct nl_dump_params *p)
134 nl_dump_line(p,
"%s ", dp->dp_name);
136 if (dp->ce_mask & DP_ATTR_IFINDEX)
137 nl_dump(p,
"ifindex %u ", dp->dp_ifindex);
139 if (dp->ce_mask & DP_ATTR_UPCALL_PID)
140 nl_dump(p,
"upcall-pid %u ", dp->dp_upcall_pid);
145 static void ovs_dp_dump_stats(
struct nl_object *obj,
struct nl_dump_params *p)
149 ovs_dp_dump_line(obj, p);
151 nl_dump_line(p,
" Stats: hit missed lost flows\n");
152 nl_dump_line(p,
" %10" PRIu64
" %10" PRIu64
" %10" PRIu64
" %10" PRIu64
"\n",
153 dp->dp_stats[OVS_DP_STAT_HIT],
154 dp->dp_stats[OVS_DP_STAT_MISSED],
155 dp->dp_stats[OVS_DP_STAT_LOST],
156 dp->dp_stats[OVS_DP_STAT_FLOWS]);
159 static int ovs_dp_compare(
struct nl_object *_a,
struct nl_object *_b,
160 uint32_t attrs,
int flags)
166 #define DP_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, DP_ATTR_##ATTR, a, b, EXPR)
168 diff |= DP_DIFF(NAME, strcmp(a->dp_name, b->dp_name));
169 diff |= DP_DIFF(IFINDEX, a->dp_ifindex != b->dp_ifindex);
170 diff |= DP_DIFF(UPCALL_PID, a->dp_upcall_pid != b->dp_upcall_pid);
197 struct nl_cache *cache;
231 if (cache->c_ops != &ovs_dp_cache_ops)
234 nl_list_for_each_entry(dp, &cache->c_items, ce_list) {
235 if (!strcmp(name, dp->dp_name)) {
261 int ovs_dp_get_kernel(
struct nl_sock *sk,
int ifindex,
const char *name,
264 struct nl_msg *msg = NULL;
265 struct nl_object *obj;
268 if ((err = ovs_dp_build_get_request(ifindex, name, &msg)) < 0)
276 if ((err =
nl_pickup(sk, link_msg_parser, &obj)) < 0)
280 *result = (
struct ovs_dp *) obj;
292 static int build_ovs_dp_msg(
int cmd,
const struct ovs_dp *dp,
int flags,
293 struct nl_msg **result)
296 struct ovs_header *hdr;
301 if (!(dp->ce_mask & (DP_ATTR_NAME | DP_ATTR_UPCALL_PID))) {
302 APPBUG(
"name or upcall-PID must be provided");
303 return -NLE_MISSING_ATTR;
308 if (!(dp->ce_mask & (DP_ATTR_NAME | DP_ATTR_IFINDEX))) {
309 APPBUG(
"name or interface index must be provided");
310 return -NLE_MISSING_ATTR;
315 if ((err = genl_resolve_id(&ovs_dp_ops)) < 0)
322 sizeof(*hdr), flags, cmd, OVS_DATAPATH_VERSION);
328 if (dp->ce_mask & DP_ATTR_NAME &&
332 if (cmd == OVS_DP_CMD_NEW) {
333 if (dp->ce_mask & DP_ATTR_UPCALL_PID &&
334 nla_put_u32(msg, OVS_DP_ATTR_UPCALL_PID, dp->dp_upcall_pid) < 0)
365 struct nl_msg **result)
367 return build_ovs_dp_msg(OVS_DP_CMD_NEW, dp, flags, result);
415 struct nl_msg **result)
417 return build_ovs_dp_msg(OVS_DP_CMD_DEL, dp, flags, result);
487 strncpy(dp->dp_name, name,
sizeof(dp->dp_name) - 1);
488 dp->ce_mask |= DP_ATTR_NAME;
500 return dp->ce_mask & DP_ATTR_NAME ? dp->dp_name : NULL;
512 dp->dp_ifindex = ifindex;
513 dp->ce_mask |= DP_ATTR_IFINDEX;
526 return dp->dp_ifindex;
538 dp->dp_upcall_pid = pid;
539 dp->ce_mask |= DP_ATTR_UPCALL_PID;
552 return dp->dp_upcall_pid;
571 if (
id > OVS_DP_STAT_MAX)
574 return dp->dp_stats[id];
589 const uint64_t value)
591 if (
id > OVS_DP_STAT_MAX)
594 dp->dp_stats[id] = value;
600 static const struct trans_tbl dp_stats[] = {
601 __ADD(OVS_DP_STAT_HIT, hit)
602 __ADD(OVS_DP_STAT_MISSED, missed)
603 __ADD(OVS_DP_STAT_LOST, lost)
604 __ADD(OVS_DP_STAT_FLOWS, flows)
617 return __type2str(st, buf, len, dp_stats, ARRAY_SIZE(dp_stats));
628 return __str2type(name, dp_stats, ARRAY_SIZE(dp_stats));
633 static struct nl_object_ops ovs_dp_obj_ops = {
634 .oo_name =
"openvswitch/datapath",
635 .oo_size =
sizeof(
struct ovs_dp),
640 .oo_compare = ovs_dp_compare,
641 .oo_id_attrs = DP_ATTR_NAME,
644 static struct genl_cmd ovs_dp_cmds[] = {
646 .
c_id = OVS_DP_CMD_NEW,
647 .c_name =
"NEW_DATAPATH" ,
648 .c_maxattr = OVS_DP_ATTR_MAX,
649 .c_attr_policy = ovs_dp_policy,
650 .c_msg_parser = ovs_dp_msg_parser,
653 .c_id = OVS_DP_CMD_DEL,
654 .c_name =
"DEL_DATAPATH" ,
657 .c_id = OVS_DP_CMD_GET,
658 .c_name =
"GET_DATAPATH" ,
659 .c_maxattr = OVS_DP_ATTR_MAX,
660 .c_attr_policy = ovs_dp_policy,
661 .c_msg_parser = ovs_dp_msg_parser,
664 .c_id = OVS_DP_CMD_SET,
665 .c_name =
"SET_DATAPATH" ,
669 static struct genl_ops ovs_dp_ops = {
671 .o_ncmds = ARRAY_SIZE(ovs_dp_cmds),
674 static struct nl_cache_ops ovs_dp_cache_ops = {
675 .co_name =
"openvswitch/datapath",
676 .co_hdrsize = GENL_HDRSIZE(
sizeof(
struct ovs_header)),
677 .co_msgtypes = GENL_FAMILY(GENL_ID_GENERATE,
"ovs_datapath"),
678 .co_genl = &ovs_dp_ops,
679 .co_protocol = NETLINK_GENERIC,
680 .co_request_update = ovs_dp_request_update,
681 .co_obj_ops = &ovs_dp_obj_ops,
684 static void __init ovs_datapath_init(
void)
690 static void __exit ovs_datapath_exit(
void)