1 /*
2 * Copyright (c) 2018 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <logging/log.h>
8 LOG_MODULE_REGISTER(log_backend_net, CONFIG_LOG_DEFAULT_LEVEL);
9
10 #include <logging/log_backend.h>
11 #include <logging/log_core.h>
12 #include <logging/log_output.h>
13 #include <logging/log_msg.h>
14 #include <net/net_pkt.h>
15 #include <net/net_context.h>
16
17 /* Set this to 1 if you want to see what is being sent to server */
18 #define DEBUG_PRINTING 0
19
20 #if DEBUG_PRINTING
21 #define DBG(fmt, ...) printk(fmt, ##__VA_ARGS__)
22 #else
23 #define DBG(fmt, ...)
24 #endif
25
26 #if defined(CONFIG_NET_IPV6) || CONFIG_NET_HOSTNAME_ENABLE
27 #define MAX_HOSTNAME_LEN NET_IPV6_ADDR_LEN
28 #else
29 #define MAX_HOSTNAME_LEN NET_IPV4_ADDR_LEN
30 #endif
31
32 static char dev_hostname[MAX_HOSTNAME_LEN + 1];
33
34 static uint8_t output_buf[CONFIG_LOG_BACKEND_NET_MAX_BUF_SIZE];
35 static bool net_init_done;
36 struct sockaddr server_addr;
37 static bool panic_mode;
38
39 const struct log_backend *log_backend_net_get(void);
40
41 NET_PKT_SLAB_DEFINE(syslog_tx_pkts, CONFIG_LOG_BACKEND_NET_MAX_BUF);
42 NET_PKT_DATA_POOL_DEFINE(syslog_tx_bufs,
43 ROUND_UP(CONFIG_LOG_BACKEND_NET_MAX_BUF_SIZE /
44 CONFIG_NET_BUF_DATA_SIZE, 1) *
45 CONFIG_LOG_BACKEND_NET_MAX_BUF);
46
get_tx_slab(void)47 static struct k_mem_slab *get_tx_slab(void)
48 {
49 return &syslog_tx_pkts;
50 }
51
get_data_pool(void)52 struct net_buf_pool *get_data_pool(void)
53 {
54 return &syslog_tx_bufs;
55 }
56
line_out(uint8_t * data,size_t length,void * output_ctx)57 static int line_out(uint8_t *data, size_t length, void *output_ctx)
58 {
59 struct net_context *ctx = (struct net_context *)output_ctx;
60 int ret = -ENOMEM;
61
62 if (ctx == NULL) {
63 return length;
64 }
65
66 ret = net_context_send(ctx, data, length, NULL, K_NO_WAIT, NULL);
67 if (ret < 0) {
68 goto fail;
69 }
70
71 DBG(data);
72 fail:
73 return length;
74 }
75
76 LOG_OUTPUT_DEFINE(log_output_net, line_out, output_buf, sizeof(output_buf));
77
do_net_init(void)78 static int do_net_init(void)
79 {
80 struct sockaddr *local_addr = NULL;
81 struct sockaddr_in6 local_addr6;
82 struct sockaddr_in local_addr4;
83 socklen_t server_addr_len;
84 struct net_context *ctx;
85 int ret;
86
87 if (IS_ENABLED(CONFIG_NET_IPV4) && server_addr.sa_family == AF_INET) {
88 local_addr = (struct sockaddr *)&local_addr4;
89 server_addr_len = sizeof(struct sockaddr_in);
90 local_addr4.sin_port = 0U;
91 }
92
93 if (IS_ENABLED(CONFIG_NET_IPV6) && server_addr.sa_family == AF_INET6) {
94 local_addr = (struct sockaddr *)&local_addr6;
95 server_addr_len = sizeof(struct sockaddr_in6);
96 local_addr6.sin6_port = 0U;
97 }
98
99 if (local_addr == NULL) {
100 DBG("Server address unknown\n");
101 return -EINVAL;
102 }
103
104 local_addr->sa_family = server_addr.sa_family;
105
106 ret = net_context_get(server_addr.sa_family, SOCK_DGRAM, IPPROTO_UDP,
107 &ctx);
108 if (ret < 0) {
109 DBG("Cannot get context (%d)\n", ret);
110 return ret;
111 }
112
113 if (IS_ENABLED(CONFIG_NET_HOSTNAME_ENABLE)) {
114 (void)strncpy(dev_hostname, net_hostname_get(), MAX_HOSTNAME_LEN);
115
116 } else if (IS_ENABLED(CONFIG_NET_IPV6) &&
117 server_addr.sa_family == AF_INET6) {
118 const struct in6_addr *src;
119
120 src = net_if_ipv6_select_src_addr(
121 NULL, &net_sin6(&server_addr)->sin6_addr);
122 if (src) {
123 net_addr_ntop(AF_INET6, src, dev_hostname,
124 MAX_HOSTNAME_LEN);
125
126 net_ipaddr_copy(&local_addr6.sin6_addr, src);
127 } else {
128 goto unknown;
129 }
130
131 } else if (IS_ENABLED(CONFIG_NET_IPV4) &&
132 server_addr.sa_family == AF_INET) {
133 const struct in_addr *src;
134
135 src = net_if_ipv4_select_src_addr(
136 NULL, &net_sin(&server_addr)->sin_addr);
137
138 if (src) {
139 net_addr_ntop(AF_INET, src, dev_hostname,
140 MAX_HOSTNAME_LEN);
141
142 net_ipaddr_copy(&local_addr4.sin_addr, src);
143 } else {
144 goto unknown;
145 }
146
147 } else {
148 unknown:
149 DBG("Cannot setup local context\n");
150 return -EINVAL;
151 }
152
153 ret = net_context_bind(ctx, local_addr, server_addr_len);
154 if (ret < 0) {
155 DBG("Cannot bind context (%d)\n", ret);
156 return ret;
157 }
158
159 (void)net_context_connect(ctx, &server_addr, server_addr_len,
160 NULL, K_NO_WAIT, NULL);
161
162 /* We do not care about return value for this UDP connect call that
163 * basically does nothing. Calling the connect is only useful so that
164 * we can see the syslog connection in net-shell.
165 */
166
167 net_context_setup_pools(ctx, get_tx_slab, get_data_pool);
168
169 log_output_ctx_set(&log_output_net, ctx);
170 log_output_hostname_set(&log_output_net, dev_hostname);
171
172 return 0;
173 }
174
send_output(const struct log_backend * const backend,struct log_msg * msg)175 static void send_output(const struct log_backend *const backend,
176 struct log_msg *msg)
177 {
178 if (panic_mode) {
179 return;
180 }
181
182 if (!net_init_done && do_net_init() == 0) {
183 net_init_done = true;
184 }
185
186 log_msg_get(msg);
187
188 log_output_msg_process(&log_output_net, msg,
189 LOG_OUTPUT_FLAG_FORMAT_SYSLOG |
190 LOG_OUTPUT_FLAG_TIMESTAMP |
191 (IS_ENABLED(CONFIG_LOG_BACKEND_NET_SYST_ENABLE) ?
192 LOG_OUTPUT_FLAG_FORMAT_SYST : 0));
193
194 log_msg_put(msg);
195 }
196
process(const struct log_backend * const backend,union log_msg2_generic * msg)197 static void process(const struct log_backend *const backend,
198 union log_msg2_generic *msg)
199 {
200 uint32_t flags = LOG_OUTPUT_FLAG_FORMAT_SYSLOG | LOG_OUTPUT_FLAG_TIMESTAMP;
201
202 if (panic_mode) {
203 return;
204 }
205
206 if (!net_init_done && do_net_init() == 0) {
207 net_init_done = true;
208 }
209
210 log_output_msg2_process(&log_output_net, &msg->log, flags);
211 }
212
init_net(struct log_backend const * const backend)213 static void init_net(struct log_backend const *const backend)
214 {
215 ARG_UNUSED(backend);
216 int ret;
217
218 net_sin(&server_addr)->sin_port = htons(514);
219
220 ret = net_ipaddr_parse(CONFIG_LOG_BACKEND_NET_SERVER,
221 sizeof(CONFIG_LOG_BACKEND_NET_SERVER) - 1,
222 &server_addr);
223 if (ret == 0) {
224 LOG_ERR("Cannot configure syslog server address");
225 return;
226 }
227
228 log_backend_deactivate(log_backend_net_get());
229 }
230
panic(struct log_backend const * const backend)231 static void panic(struct log_backend const *const backend)
232 {
233 panic_mode = true;
234 }
235
sync_string(const struct log_backend * const backend,struct log_msg_ids src_level,uint32_t timestamp,const char * fmt,va_list ap)236 static void sync_string(const struct log_backend *const backend,
237 struct log_msg_ids src_level, uint32_t timestamp,
238 const char *fmt, va_list ap)
239 {
240 uint32_t flags = LOG_OUTPUT_FLAG_LEVEL | LOG_OUTPUT_FLAG_FORMAT_SYSLOG |
241 LOG_OUTPUT_FLAG_TIMESTAMP |
242 (IS_ENABLED(CONFIG_LOG_BACKEND_NET_SYST_ENABLE) ?
243 LOG_OUTPUT_FLAG_FORMAT_SYST : 0);
244 uint32_t key;
245
246 if (!net_init_done && do_net_init() == 0) {
247 net_init_done = true;
248 }
249
250 key = irq_lock();
251 log_output_string(&log_output_net, src_level,
252 timestamp, fmt, ap, flags);
253 irq_unlock(key);
254 }
255
256 const struct log_backend_api log_backend_net_api = {
257 .panic = panic,
258 .init = init_net,
259 .process = IS_ENABLED(CONFIG_LOG2) ? process : NULL,
260 .put = IS_ENABLED(CONFIG_LOG_MODE_DEFERRED) ? send_output : NULL,
261 .put_sync_string = IS_ENABLED(CONFIG_LOG_MODE_IMMEDIATE) ?
262 sync_string : NULL,
263 /* Currently we do not send hexdumps over network to remote server
264 * in CONFIG_LOG_IMMEDIATE mode. This is just to save resources,
265 * this can be revisited if needed.
266 */
267 .put_sync_hexdump = NULL,
268 };
269
270 /* Note that the backend can be activated only after we have networking
271 * subsystem ready so we must not start it immediately.
272 */
273 LOG_BACKEND_DEFINE(log_backend_net, log_backend_net_api,
274 IS_ENABLED(CONFIG_LOG_BACKEND_NET_AUTOSTART));
275
log_backend_net_get(void)276 const struct log_backend *log_backend_net_get(void)
277 {
278 return &log_backend_net;
279 }
280