Skip to content

Commit 0dbea11

Browse files
Daniel Zahkakuba-moo
authored andcommitted
samples: add PSP sample with dump and notification modes
Add a sample binary that demonstrates PSP netlink usage: - Default mode: dumps all PSP devices on the system - With --ntf flag: subscribes to PSP netlink multicast groups and listens for device notifications (dev-add, dev-del, dev-change) Signed-off-by: Daniel Zahka <daniel.zahka@gmail.com>
1 parent 9d7f524 commit 0dbea11

File tree

1 file changed

+161
-0
lines changed

1 file changed

+161
-0
lines changed

samples/psp.cpp

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
#include <psp-user.hpp>
3+
#include <ynl.hpp>
4+
5+
#include <cstring>
6+
#include <iostream>
7+
#include <linux/psp.h>
8+
#include <poll.h>
9+
#include <signal.h>
10+
11+
static volatile bool running = true;
12+
13+
static void signal_handler(int sig) {
14+
(void)sig;
15+
running = false;
16+
}
17+
18+
static void print_dev(const ynl_cpp::psp_dev_get_rsp& dev) {
19+
if (dev.id.has_value()) {
20+
std::cout << "id=" << dev.id.value();
21+
}
22+
if (dev.ifindex.has_value()) {
23+
std::cout << " ifindex=" << dev.ifindex.value();
24+
}
25+
if (dev.psp_versions_cap.has_value()) {
26+
std::cout << " versions_cap=0x" << std::hex << dev.psp_versions_cap.value()
27+
<< std::dec;
28+
}
29+
if (dev.psp_versions_ena.has_value()) {
30+
std::cout << " versions_ena=0x" << std::hex << dev.psp_versions_ena.value()
31+
<< std::dec;
32+
}
33+
std::cout << std::endl;
34+
}
35+
36+
static void print_dev_notification(
37+
const char* event_type,
38+
const ynl_cpp::psp_dev_get_rsp& dev) {
39+
std::cout << event_type << ": ";
40+
print_dev(dev);
41+
}
42+
43+
static int do_dump(ynl_cpp::ynl_socket& ys) {
44+
auto devs = ynl_cpp::psp_dev_get_dump(ys);
45+
if (!devs) {
46+
std::cerr << "Failed to dump PSP devices" << std::endl;
47+
return -1;
48+
}
49+
50+
if (devs->objs.empty()) {
51+
std::cout << "No PSP devices found" << std::endl;
52+
return 0;
53+
}
54+
55+
for (const auto& dev : devs->objs) {
56+
print_dev(dev);
57+
}
58+
return 0;
59+
}
60+
61+
static int do_ntf(ynl_cpp::ynl_socket& ys) {
62+
signal(SIGINT, signal_handler);
63+
signal(SIGTERM, signal_handler);
64+
65+
struct ynl_sock* sock = static_cast<struct ynl_sock*>(ys);
66+
if (ynl_subscribe(sock, PSP_MCGRP_MGMT) < 0) {
67+
std::cerr << "Failed to subscribe to mgmt multicast group: " << sock->err.msg
68+
<< std::endl;
69+
return -1;
70+
}
71+
72+
std::cout << "Listening for PSP notifications (Ctrl+C to exit)..."
73+
<< std::endl;
74+
75+
int fd = ynl_socket_get_fd(sock);
76+
77+
while (running) {
78+
struct pollfd pfd = {
79+
.fd = fd,
80+
.events = POLLIN,
81+
.revents = 0,
82+
};
83+
84+
int ret = poll(&pfd, 1, 1000);
85+
if (ret < 0) {
86+
if (errno == EINTR) {
87+
continue;
88+
}
89+
std::cerr << "poll() failed: " << strerror(errno) << std::endl;
90+
break;
91+
}
92+
93+
if (ret == 0) {
94+
continue;
95+
}
96+
97+
if (pfd.revents & POLLIN) {
98+
ret = ynl_ntf_check(sock);
99+
if (ret < 0) {
100+
std::cerr << "Error checking notifications: " << sock->err.msg
101+
<< std::endl;
102+
continue;
103+
}
104+
105+
while (ynl_has_ntf(sock)) {
106+
struct ynl_ntf_base_type* ntf = ynl_ntf_dequeue(sock);
107+
if (!ntf) {
108+
break;
109+
}
110+
111+
const auto* dev =
112+
reinterpret_cast<const ynl_cpp::psp_dev_get_rsp*>(ntf->data);
113+
114+
switch (ntf->cmd) {
115+
case PSP_CMD_DEV_ADD_NTF:
116+
print_dev_notification("DEV_ADD", *dev);
117+
break;
118+
case PSP_CMD_DEV_DEL_NTF:
119+
print_dev_notification("DEV_DEL", *dev);
120+
break;
121+
case PSP_CMD_DEV_CHANGE_NTF:
122+
print_dev_notification("DEV_CHANGE", *dev);
123+
break;
124+
default:
125+
std::cout << "Unknown notification cmd=" << (int)ntf->cmd
126+
<< std::endl;
127+
break;
128+
}
129+
130+
ynl_ntf_free(ntf);
131+
}
132+
}
133+
}
134+
135+
return 0;
136+
}
137+
138+
int main(int argc, char* argv[]) {
139+
bool ntf_mode = false;
140+
141+
for (int i = 1; i < argc; i++) {
142+
if (std::strcmp(argv[i], "--ntf") == 0) {
143+
ntf_mode = true;
144+
}
145+
}
146+
147+
ynl_error yerr;
148+
ynl_cpp::ynl_socket ys(ynl_cpp::get_ynl_psp_family(), &yerr);
149+
if (!ys) {
150+
std::cerr << "Failed to open PSP netlink socket: " << yerr.msg << std::endl;
151+
std::cerr << "(This requires a kernel with PSP support and a PSP device)"
152+
<< std::endl;
153+
return -1;
154+
}
155+
156+
if (ntf_mode) {
157+
return do_ntf(ys);
158+
} else {
159+
return do_dump(ys);
160+
}
161+
}

0 commit comments

Comments
 (0)