Instead of always allocating both IPv6 and IPv4 address information to every network interface, allow more fine grained address configuration. So it is possible to have IPv6 or IPv4 only network interfaces. This commit introduces two new config options: CONFIG_NET_IF_MAX_IPV4_COUNT and CONFIG_NET_IF_MAX_IPV6_COUNT which tell how many IP address information structs are allocated statically. At runtime when network interface is setup, it is then possible to attach this IP address info struct to a specific network interface. This can save considerable amount of memory as the IP address information struct can be quite large (depends on how many IP addresses user configures in the system). Note that the value of CONFIG_NET_IF_MAX_IPV4_COUNT and CONFIG_NET_IF_MAX_IPV6_COUNT should reflect the estimated number of network interfaces in the system. So if if CONFIG_NET_IF_MAX_IPV6_COUNT is set to 1 and there are two network interfaces that need IPv6 addresses, then the system will not be able to setup IPv6 addresses to the second network interface in this case. This scenario might be just fine if the second network interface is IPv4 only. The net_if.c will print a warning during startup if mismatch about the counts and the actual number of network interface is detected. Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
231 lines
5.2 KiB
C
231 lines
5.2 KiB
C
/*
|
|
* Copyright (c) 2018 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <logging/sys_log.h>
|
|
|
|
#include <net/net_pkt.h>
|
|
#include <net/net_context.h>
|
|
|
|
/* Set this to 1 if you want to see what is being sent to server */
|
|
#define DEBUG_PRINTING 0
|
|
|
|
static struct net_context *ctx;
|
|
static struct sockaddr server_addr;
|
|
|
|
/* FIXME: As there is no way to figure out these values in the hook
|
|
* function, use some pre-defined values. Change this to use the
|
|
* real facility and severity of the logging call when that info is
|
|
* available.
|
|
*/
|
|
static const int facility = 16; /* local0 */
|
|
static const int severity = 6; /* info */
|
|
|
|
#define DATE_EPOCH "1970-01-01T00:00:00.000000-00:00"
|
|
static char date[sizeof(DATE_EPOCH)];
|
|
|
|
#if defined(CONFIG_NET_IPV6) || CONFIG_NET_HOSTNAME_ENABLE
|
|
#define MAX_HOSTNAME_LEN NET_IPV6_ADDR_LEN
|
|
#else
|
|
#define MAX_HOSTNAME_LEN NET_IPV4_ADDR_LEN
|
|
#endif
|
|
|
|
static char hostname[MAX_HOSTNAME_LEN + 1];
|
|
|
|
NET_PKT_SLAB_DEFINE(syslog_tx_pkts, CONFIG_SYS_LOG_BACKEND_NET_MAX_BUF);
|
|
NET_BUF_POOL_DEFINE(syslog_tx_bufs, CONFIG_SYS_LOG_BACKEND_NET_MAX_BUF,
|
|
CONFIG_SYS_LOG_BACKEND_NET_MAX_BUF_SIZE,
|
|
CONFIG_NET_BUF_USER_DATA_SIZE, NULL);
|
|
|
|
static struct k_mem_slab *get_tx_slab(void)
|
|
{
|
|
return &syslog_tx_pkts;
|
|
}
|
|
|
|
struct net_buf_pool *get_data_pool(void)
|
|
{
|
|
return &syslog_tx_bufs;
|
|
}
|
|
|
|
static void fill_header(struct net_buf *buf)
|
|
{
|
|
snprintk(net_buf_tail(buf),
|
|
net_buf_tailroom(buf),
|
|
"<%d>1 %s %s - - - - ",
|
|
facility * 8 + severity,
|
|
date,
|
|
hostname);
|
|
|
|
net_buf_add(buf, strlen(buf->data));
|
|
}
|
|
|
|
static void syslog_hook_net(const char *fmt, ...)
|
|
{
|
|
struct net_pkt *pkt;
|
|
struct net_buf *frag;
|
|
u8_t *ptr;
|
|
va_list vargs;
|
|
int ret;
|
|
|
|
pkt = net_pkt_get_tx(ctx, K_NO_WAIT);
|
|
if (!pkt) {
|
|
return;
|
|
}
|
|
|
|
frag = net_pkt_get_data(ctx, K_NO_WAIT);
|
|
if (!frag) {
|
|
net_pkt_unref(pkt);
|
|
return;
|
|
}
|
|
|
|
net_pkt_frag_add(pkt, frag);
|
|
|
|
fill_header(frag);
|
|
|
|
va_start(vargs, fmt);
|
|
|
|
ptr = net_buf_tail(frag);
|
|
|
|
ret = vsnprintk(ptr, (net_buf_tailroom(frag) - 1), fmt, vargs);
|
|
if (ret < 0) {
|
|
net_pkt_unref(pkt);
|
|
return;
|
|
}
|
|
|
|
va_end(vargs);
|
|
|
|
if (ret > 0 && ptr[ret - 1] == '\n') {
|
|
/* No need to send \n to peer so strip it away */
|
|
ret--;
|
|
}
|
|
|
|
net_buf_add(frag, ret);
|
|
|
|
#if DEBUG_PRINTING
|
|
{
|
|
static u32_t count;
|
|
|
|
printk("%d:%s", ++count, frag->data);
|
|
}
|
|
#endif
|
|
ret = net_context_send(pkt, NULL, K_NO_WAIT, NULL, NULL);
|
|
if (ret < 0) {
|
|
net_pkt_unref(pkt);
|
|
}
|
|
}
|
|
|
|
void syslog_net_hook_install(void)
|
|
{
|
|
#if defined(CONFIG_NET_IPV6)
|
|
struct sockaddr_in6 local_addr6 = {
|
|
.sin6_family = AF_INET6,
|
|
.sin6_port = 0,
|
|
};
|
|
#endif
|
|
#if defined(CONFIG_NET_IPV4)
|
|
struct sockaddr_in local_addr4 = {
|
|
.sin_family = AF_INET,
|
|
.sin_port = 0,
|
|
};
|
|
#endif
|
|
struct sockaddr *local_addr = NULL;
|
|
socklen_t local_addr_len = 0;
|
|
socklen_t server_addr_len = 0;
|
|
int ret;
|
|
|
|
net_sin(&server_addr)->sin_port = htons(514);
|
|
|
|
ret = net_ipaddr_parse(CONFIG_SYS_LOG_BACKEND_NET_SERVER,
|
|
sizeof(CONFIG_SYS_LOG_BACKEND_NET_SERVER) - 1,
|
|
&server_addr);
|
|
if (!ret) {
|
|
SYS_LOG_ERR("Cannot configure syslog server address");
|
|
return;
|
|
}
|
|
|
|
#if defined(CONFIG_NET_IPV4)
|
|
if (server_addr.sa_family == AF_INET) {
|
|
local_addr = (struct sockaddr *)&local_addr4;
|
|
local_addr_len = sizeof(struct sockaddr_in);
|
|
server_addr_len = sizeof(struct sockaddr_in);
|
|
}
|
|
#endif
|
|
|
|
#if defined(CONFIG_NET_IPV6)
|
|
if (server_addr.sa_family == AF_INET6) {
|
|
local_addr = (struct sockaddr *)&local_addr6;
|
|
local_addr_len = sizeof(struct sockaddr_in6);
|
|
server_addr_len = sizeof(struct sockaddr_in6);
|
|
}
|
|
#endif
|
|
|
|
ret = net_context_get(server_addr.sa_family, SOCK_DGRAM, IPPROTO_UDP,
|
|
&ctx);
|
|
if (ret < 0) {
|
|
SYS_LOG_ERR("Cannot get context (%d)", ret);
|
|
return;
|
|
}
|
|
|
|
#if CONFIG_NET_HOSTNAME_ENABLE
|
|
memcpy(hostname, net_hostname_get(), MAX_HOSTNAME_LEN);
|
|
#else /* CONFIG_NET_HOSTNAME_ENABLE */
|
|
if (server_addr.sa_family == AF_INET6) {
|
|
#if defined(CONFIG_NET_IPV6)
|
|
const struct in6_addr *src;
|
|
|
|
src = net_if_ipv6_select_src_addr(
|
|
NULL, &net_sin6(&server_addr)->sin6_addr);
|
|
if (src) {
|
|
net_addr_ntop(AF_INET6, src, hostname,
|
|
MAX_HOSTNAME_LEN);
|
|
|
|
net_ipaddr_copy(&local_addr6.sin6_addr, src);
|
|
} else {
|
|
goto unknown;
|
|
}
|
|
#else
|
|
goto unknown;
|
|
#endif
|
|
} else if (server_addr.sa_family == AF_INET) {
|
|
#if defined(CONFIG_NET_IPV4)
|
|
/* FIXME: instead of taking the first IPv4 address of an
|
|
* interface, take the proper one according to routing
|
|
*/
|
|
struct net_if_ipv4 *ipv4 =
|
|
net_if_get_default()->config.ip.ipv4;
|
|
|
|
net_ipaddr_copy(&local_addr4.sin_addr,
|
|
&ipv4->unicast[0].address.in_addr);
|
|
|
|
net_addr_ntop(AF_INET, &local_addr4.sin_addr, hostname,
|
|
MAX_HOSTNAME_LEN);
|
|
#else
|
|
goto unknown;
|
|
#endif
|
|
} else {
|
|
unknown:
|
|
strncpy(hostname, "zephyr", MAX_HOSTNAME_LEN);
|
|
}
|
|
#endif /* CONFIG_NET_HOSTNAME_ENABLE */
|
|
|
|
ret = net_context_bind(ctx, local_addr, local_addr_len);
|
|
if (ret < 0) {
|
|
SYS_LOG_ERR("Cannot bind context (%d)", ret);
|
|
return;
|
|
}
|
|
|
|
ret = net_context_connect(ctx, &server_addr, server_addr_len,
|
|
NULL, K_NO_WAIT, NULL);
|
|
|
|
/* We do not care about return value for this UDP connect call that
|
|
* basically does nothing. Calling the connect is only useful so that
|
|
* we can see the syslog connection in net-shell.
|
|
*/
|
|
|
|
net_context_setup_pools(ctx, get_tx_slab, get_data_pool);
|
|
|
|
syslog_hook_install(syslog_hook_net);
|
|
}
|