aboutsummaryrefslogtreecommitdiffstats
path: root/src/vnet
diff options
context:
space:
mode:
authorMatus Fabian <matfabia@cisco.com>2018-11-19 04:25:32 -0800
committerOle Trøan <otroan@employees.org>2018-11-22 06:31:53 +0000
commitb4515b4be4ead1ea5d0af205989cf313272e8770 (patch)
tree8a87c5c74cd8583690bdcf612727a2b4f4136cf2 /src/vnet
parent19ca78fbd7567c676beefc2b511dfdcd9f20201a (diff)
Add RFC5424 syslog protocol support (VPP-1139)
Syslog protocol logging transport event messages across network over UDP protocol based on RFC5426. Change-Id: Ica74b40bcc2e6d0fbd41e9bf78e76395fbabab3c Signed-off-by: Matus Fabian <matfabia@cisco.com>
Diffstat (limited to 'src/vnet')
-rw-r--r--src/vnet/CMakeLists.txt17
-rw-r--r--src/vnet/syslog/dir.dox18
-rw-r--r--src/vnet/syslog/sylog_doc.md65
-rw-r--r--src/vnet/syslog/syslog.api119
-rw-r--r--src/vnet/syslog/syslog.c646
-rw-r--r--src/vnet/syslog/syslog.h225
-rw-r--r--src/vnet/syslog/syslog_api.c243
-rw-r--r--src/vnet/syslog/syslog_udp.c72
-rw-r--r--src/vnet/syslog/syslog_udp.h36
-rw-r--r--src/vnet/vnet_all_api_h.h1
10 files changed, 1442 insertions, 0 deletions
diff --git a/src/vnet/CMakeLists.txt b/src/vnet/CMakeLists.txt
index ac448e268b6..290a4eeacc9 100644
--- a/src/vnet/CMakeLists.txt
+++ b/src/vnet/CMakeLists.txt
@@ -1355,6 +1355,23 @@ list(APPEND VNET_HEADERS
list(APPEND VNET_API_FILES bier/bier.api)
##############################################################################
+# SYSLOG
+##############################################################################
+
+list (APPEND VNET_SOURCES
+ syslog/syslog_api.c
+ syslog/syslog_udp.c
+ syslog/syslog.c
+)
+
+list(APPEND VNET_HEADERS
+ syslog/syslog_udp.h
+ syslog/syslog.h
+)
+
+list(APPEND VNET_API_FILES syslog/syslog.api)
+
+##############################################################################
# VNET Library
##############################################################################
diff --git a/src/vnet/syslog/dir.dox b/src/vnet/syslog/dir.dox
new file mode 100644
index 00000000000..ea64053e1df
--- /dev/null
+++ b/src/vnet/syslog/dir.dox
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2018 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ @dir
+ @brief RFC5424 syslog protocol implementation
+*/
diff --git a/src/vnet/syslog/sylog_doc.md b/src/vnet/syslog/sylog_doc.md
new file mode 100644
index 00000000000..0b48d4db573
--- /dev/null
+++ b/src/vnet/syslog/sylog_doc.md
@@ -0,0 +1,65 @@
+# Syslog protocol support {#syslog_doc}
+
+VPP provides [RFC5424](https://tools.ietf.org/html/rfc5424) syslog protocol
+logging, which is used to transport event messages across network. VPP
+currently suports UDP transport based on
+[RFC5426](https://tools.ietf.org/html/rfc5426).
+
+The syslog message has the following format:
+* header
+* structured data
+* free-form message
+
+The header contains, priority, version, timestamp, hostname, application,
+process id and message id. It is followed by structured data, which provides
+a mechanism to express event data in easily parsable format. Structured data
+can contain zero, one or multiple structured data elements. Structured data
+element contains name-value pairs. Structured data can by followed by free-form
+message.
+
+Following example explains how to use the internal APIs to genrate syslog
+message:
+```{.c}
+ #include <vnet/syslog/syslog.h>
+
+ ...
+
+ syslog_msg_t syslog_msg;
+
+ /* Check if syslog logging is enabled */
+ if (!syslog_is_enabled ())
+ return;
+
+ /* Severity filer test */
+ if (syslog_severity_filter_block (severity))
+ return;
+
+ /* Initialize syslog message header */
+ syslog_msg_init (&syslog_msg, facility, severity, "NAT", "SADD");
+
+ /* Create structured data element */
+ syslog_msg_sd_init (&syslog_msg, "nsess");
+ /* Add structured data element parameters (name-value pairs) */
+ syslog_msg_add_sd_param (&syslog_msg, "SSUBIX", "%d", ssubix);
+ syslog_msg_add_sd_param (&syslog_msg, "SVLAN", "%d", svlan);
+ syslog_msg_add_sd_param (&syslog_msg, "IATYP", "IPv4");
+ syslog_msg_add_sd_param (&syslog_msg, "ISADDR", "%U",
+ format_ip4_address, isaddr);
+ syslog_msg_add_sd_param (&syslog_msg, "ISPORT", "%d", isport);
+ syslog_msg_add_sd_param (&syslog_msg, "XATYP", "IPv4");
+ syslog_msg_add_sd_param (&syslog_msg, "XSADDR", "%U",
+ format_ip4_address, xsaddr);
+ syslog_msg_add_sd_param (&syslog_msg, "XSPORT", "%d", xsport);
+ syslog_msg_add_sd_param (&syslog_msg, "PROTO", "%d", proto);
+
+ /* Send syslog message */
+ syslog_msg_send (&syslog_msg);
+```
+
+Example above produces following syslog message:
+ <134>1 2018-11-12T11:25:30.252715Z 172.16.4.1 NAT 5901 SADD [nsess SSUBIX="0" SVLAN="0" IATYP="IPv4" ISADDR="172.16.1.2" ISPORT="6303" XATYP="IPv4" XSADDR="10.0.0.3" XSPORT="16253" PROTO="6"]
+
+To add free-form message use:
+```{.c}
+ syslog_msg_add_msg (&syslog_msg, "event log entry");
+```
diff --git a/src/vnet/syslog/syslog.api b/src/vnet/syslog/syslog.api
new file mode 100644
index 00000000000..3ba5d69cc41
--- /dev/null
+++ b/src/vnet/syslog/syslog.api
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2018 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+option version = "1.0.0";
+import "vnet/ip/ip_types.api";
+
+enum syslog_severity
+{
+ SYSLOG_API_SEVERITY_EMERG = 0,
+ SYSLOG_API_SEVERITY_ALERT = 1,
+ SYSLOG_API_SEVERITY_CRIT = 2,
+ SYSLOG_API_SEVERITY_ERR = 3,
+ SYSLOG_API_SEVERITY_WARN = 4,
+ SYSLOG_API_SEVERITY_NOTICE = 5,
+ SYSLOG_API_SEVERITY_INFO = 6,
+ SYSLOG_API_SEVERITY_DBG = 7,
+};
+
+/** \brief Set syslog sender configuration
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param src_address - IPv4 address of syslog sender (source)
+ @param collector_address - IPv4 address of syslog collector (destination)
+ @param collector_port - UDP port of syslog colector (destination)
+ @param vrf_id - VRF/FIB table ID
+ @param max_msg_size - maximum message length
+*/
+autoreply define syslog_set_sender
+{
+ u32 client_index;
+ u32 context;
+ vl_api_ip4_address_t src_address;
+ vl_api_ip4_address_t collector_address;
+ u16 collector_port;
+ u32 vrf_id;
+ u32 max_msg_size;
+};
+
+/** \brief Get syslog sender configuration
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+*/
+define syslog_get_sender
+{
+ u32 client_index;
+ u32 context;
+};
+
+/** \brief Get syslog sender configuration reply
+ @param context - sender context, to match reply w/ request
+ @param retval - return code for the request
+ @param src_address - IPv4 address of syslog sender (source)
+ @param collector_address - IPv4 address of syslog collector (destination)
+ @param collector_port - UDP port of syslog colector (destination)
+ @param vrf_id - VRF/FIB table ID
+ @param max_msg_size - maximum message length
+*/
+define syslog_get_sender_reply
+{
+ u32 context;
+ i32 retval;
+ vl_api_ip4_address_t src_address;
+ vl_api_ip4_address_t collector_address;
+ u16 collector_port;
+ u32 vrf_id;
+ u32 max_msg_size;
+};
+
+/** \brief Set syslog filter
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param severity - severity filter (specified severity and greater match)
+*/
+autoreply define syslog_set_filter
+{
+ u32 client_index;
+ u32 context;
+ vl_api_syslog_severity_t severity;
+ };
+
+/** \brief Get syslog filter
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+*/
+define syslog_get_filter
+{
+ u32 client_index;
+ u32 context;
+};
+
+/** \brief Get syslog filter reply
+ @param context - sender context, to match reply w/ request
+ @param retval - return code for the request
+ @param severity - severity filter (specified severity and greater match)
+*/
+define syslog_get_filter_reply
+{
+ u32 context;
+ i32 retval;
+ vl_api_syslog_severity_t severity;
+};
+
+/*
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vnet/syslog/syslog.c b/src/vnet/syslog/syslog.c
new file mode 100644
index 00000000000..1cffe03d768
--- /dev/null
+++ b/src/vnet/syslog/syslog.c
@@ -0,0 +1,646 @@
+/*
+ * Copyright (c) 2018 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @file RFC5424 syslog protocol implementation
+ */
+
+#include <unistd.h>
+#include <vnet/fib/fib_table.h>
+#include <vnet/ip/format.h>
+#include <vnet/syslog/syslog.h>
+#include <vnet/syslog/syslog_udp.h>
+
+#define SYSLOG_VERSION "1"
+#define NILVALUE "-"
+#define DEFAULT_UDP_PORT 514
+#define DEFAULT_MAX_MSG_SIZE 480
+
+#define encode_priority(f, p) ((f << 3) | p)
+
+syslog_main_t syslog_main;
+
+/* format timestamp RFC5424 6.2.3. */
+static u8 *
+format_syslog_timestamp (u8 * s, va_list * args)
+{
+ f64 timestamp = va_arg (*args, f64);
+ struct tm *tm;
+ word msec;
+
+ time_t t = timestamp;
+ tm = gmtime (&t);
+ msec = 1e6 * (timestamp - t);
+ return format (s, "%4d-%02d-%02dT%02d:%02d:%02d.%06dZ", 1900 + tm->tm_year,
+ 1 + tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min,
+ tm->tm_sec, msec);
+}
+
+/* format header RFC5424 6.2. */
+static u8 *
+format_syslog_header (u8 * s, va_list * args)
+{
+ syslog_main_t *sm = &syslog_main;
+ syslog_header_t *h = va_arg (*args, syslog_header_t *);
+ u32 pri = encode_priority (h->facility, h->severity);
+
+ return format (s, "<%d>%s %U %U %s %d %s", pri, SYSLOG_VERSION,
+ format_syslog_timestamp, h->timestamp + sm->time_offset,
+ format_ip4_address, &sm->src_address,
+ h->app_name ? h->app_name : NILVALUE, sm->procid,
+ h->msgid ? h->msgid : NILVALUE);
+}
+
+/* format strucured data elements RFC5424 6.3. */
+static u8 *
+format_syslog_structured_data (u8 * s, va_list * args)
+{
+ u8 **sds = va_arg (*args, u8 **);
+ int i;
+
+ if (vec_len (sds))
+ {
+ for (i = 0; i < vec_len (sds); i++)
+ s = format (s, "[%s]", sds[i]);
+ }
+ /* if zero structured data elemts field must contain NILVALUE */
+ else
+ s = format (s, "%s", NILVALUE);
+
+ return s;
+}
+
+static u8 *
+format_syslog_msg (u8 * s, va_list * args)
+{
+ syslog_msg_t *m = va_arg (*args, syslog_msg_t *);
+
+ s =
+ format (s, "%U %U", format_syslog_header, &m->header,
+ format_syslog_structured_data, m->structured_data);
+ /* free-form message is optional */
+ if (m->msg)
+ s = format (s, " %s", m->msg);
+
+ return s;
+}
+
+void
+syslog_msg_sd_init (syslog_msg_t * syslog_msg, char *sd_id)
+{
+ u8 *sd;
+
+ sd = format (0, "%s", sd_id);
+ vec_add1 (syslog_msg->structured_data, sd);
+ syslog_msg->curr_sd_index++;
+}
+
+void
+syslog_msg_add_sd_param (syslog_msg_t * syslog_msg, char *name, char *fmt,
+ ...)
+{
+ va_list va;
+ u8 *value;
+
+ va_start (va, fmt);
+ value = va_format (0, fmt, &va);
+ va_end (va);
+ vec_terminate_c_string (value);
+
+ syslog_msg->structured_data[syslog_msg->curr_sd_index] =
+ format (syslog_msg->structured_data[syslog_msg->curr_sd_index],
+ " %s=\"%s\"", name, value);
+ vec_free (value);
+}
+
+void
+syslog_msg_add_msg (syslog_msg_t * syslog_msg, char *fmt, ...)
+{
+ va_list va;
+ u8 *msg;
+
+ va_start (va, fmt);
+ msg = va_format (0, fmt, &va);
+ va_end (va);
+ vec_terminate_c_string (msg);
+
+ syslog_msg->msg = msg;
+}
+
+void
+syslog_msg_init (syslog_msg_t * syslog_msg, syslog_facility_t facility,
+ syslog_severity_t severity, char *app_name, char *msgid)
+{
+ syslog_main_t *sm = &syslog_main;
+ vlib_main_t *vm = sm->vlib_main;
+
+ syslog_msg->header.facility = facility;
+ syslog_msg->header.severity = severity;
+ syslog_msg->header.timestamp = vlib_time_now (vm);
+ syslog_msg->header.app_name = app_name;
+ syslog_msg->header.msgid = msgid;
+ syslog_msg->structured_data = 0;
+ syslog_msg->curr_sd_index = ~0;
+ syslog_msg->msg = 0;
+}
+
+int
+syslog_msg_send (syslog_msg_t * syslog_msg)
+{
+ syslog_main_t *sm = &syslog_main;
+ vlib_main_t *vm = sm->vlib_main;
+ u32 bi, msg_len, *to_next;
+ u8 *tmp;
+ vlib_buffer_t *b;
+ vlib_buffer_free_list_t *fl;
+ vlib_frame_t *f;
+ int i;
+
+ if (vlib_buffer_alloc (vm, &bi, 1) != 1)
+ return -1;
+
+ b = vlib_get_buffer (vm, bi);
+ clib_memset (vnet_buffer (b), 0, sizeof (*vnet_buffer (b)));
+ fl = vlib_buffer_get_free_list (vm, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
+ vlib_buffer_init_for_free_list (b, fl);
+ VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b);
+
+ /* one message per UDP datagram RFC5426 3.1. */
+ tmp = format (0, "%U", format_syslog_msg, syslog_msg);
+ msg_len = vec_len (tmp) - (vec_c_string_is_terminated (tmp) ? 1 : 0);
+ msg_len = msg_len < sm->max_msg_size ? msg_len : sm->max_msg_size;
+ clib_memcpy_fast (b->data, tmp, msg_len);
+ b->current_length = msg_len;
+ vec_free (tmp);
+
+ vec_free (syslog_msg->msg);
+ for (i = 0; i < vec_len (syslog_msg->structured_data); i++)
+ vec_free (syslog_msg->structured_data[i]);
+ vec_free (syslog_msg->structured_data);
+
+ syslog_add_udp_transport (vm, bi);
+
+ f = vlib_get_frame_to_node (vm, sm->ip4_lookup_node_index);
+ to_next = vlib_frame_vector_args (f);
+ to_next[0] = bi;
+ f->n_vectors = 1;
+ vlib_put_frame_to_node (vm, sm->ip4_lookup_node_index, f);
+
+ return 0;
+}
+
+static uword
+unformat_syslog_facility (unformat_input_t * input, va_list * args)
+{
+ u32 *r = va_arg (*args, u32 *);
+
+ if (0);
+#define _(v,f,s) else if (unformat (input, s)) *r = SYSLOG_FACILITY_##f;
+ foreach_syslog_facility
+#undef _
+ else
+ return 0;
+
+ return 1;
+}
+
+static uword
+unformat_syslog_severity (unformat_input_t * input, va_list * args)
+{
+ u32 *r = va_arg (*args, u32 *);
+
+ if (0);
+#define _(v,f,s) else if (unformat (input, s)) *r = SYSLOG_SEVERITY_##f;
+ foreach_syslog_severity
+#undef _
+ else
+ return 0;
+
+ return 1;
+}
+
+static u8 *
+format_syslog_severity (u8 * s, va_list * args)
+{
+ u32 i = va_arg (*args, u32);
+ u8 *t = 0;
+
+ switch (i)
+ {
+#define _(v,f,str) case SYSLOG_SEVERITY_##f: t = (u8 *) str; break;
+ foreach_syslog_severity
+#undef _
+ default:
+ return format (s, "unknown");
+ }
+
+ return format (s, "%s", t);
+}
+
+vnet_api_error_t
+set_syslog_sender (ip4_address_t * collector, u16 collector_port,
+ ip4_address_t * src, u32 vrf_id, u32 max_msg_size)
+{
+ syslog_main_t *sm = &syslog_main;
+ u32 fib_index;
+
+ if (max_msg_size < DEFAULT_MAX_MSG_SIZE)
+ return VNET_API_ERROR_INVALID_VALUE;
+
+ if (collector->as_u32 == 0 || collector_port == 0 || src->as_u32 == 0)
+ return VNET_API_ERROR_INVALID_VALUE;
+
+ if (vrf_id == ~0)
+ {
+ fib_index = ~0;
+ }
+ else
+ {
+ fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
+ if (fib_index == ~0)
+ return VNET_API_ERROR_NO_SUCH_FIB;
+ }
+
+ sm->fib_index = fib_index;
+
+ sm->collector.as_u32 = collector->as_u32;
+ sm->collector_port = (u16) collector_port;
+ sm->src_address.as_u32 = src->as_u32;
+ sm->max_msg_size = max_msg_size;
+
+ return 0;
+}
+
+static clib_error_t *
+set_syslog_sender_command_fn (vlib_main_t * vm, unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ unformat_input_t _line_input, *line_input = &_line_input;
+ ip4_address_t collector, src;
+ u32 collector_port = DEFAULT_UDP_PORT;
+ u32 vrf_id = ~0;
+ u32 max_msg_size = DEFAULT_MAX_MSG_SIZE;
+ clib_error_t *ret = 0;
+
+ collector.as_u32 = 0;
+ src.as_u32 = 0;
+
+ /* Get a line of input. */
+ if (!unformat_user (input, unformat_line_input, line_input))
+ return 0;
+
+ while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat
+ (line_input, "collector %U", unformat_ip4_address, &collector))
+ ;
+ else if (unformat (line_input, "port %u", &collector_port))
+ ;
+ else if (unformat (line_input, "src %U", unformat_ip4_address, &src))
+ ;
+ else if (unformat (line_input, "vrf-id %u", &vrf_id))
+ ;
+ else if (unformat (line_input, "max-msg-size %u", &max_msg_size))
+ ;
+ else
+ {
+ ret = clib_error_return (0, "Unknown input `%U'",
+ format_unformat_error, line_input);
+ goto done;
+ }
+ }
+
+ if (collector.as_u32 == 0)
+ {
+ ret = clib_error_return (0, "collector address required");
+ goto done;
+ }
+
+ if (src.as_u32 == 0)
+ {
+ ret = clib_error_return (0, "src address required");
+ goto done;
+ }
+
+ if (max_msg_size < DEFAULT_MAX_MSG_SIZE)
+ {
+ ret =
+ clib_error_return (0, "too small max-msg-size value, minimum is %u",
+ DEFAULT_MAX_MSG_SIZE);
+ goto done;
+ }
+
+ vnet_api_error_t rv =
+ set_syslog_sender (&collector, collector_port, &src, vrf_id,
+ max_msg_size);
+
+ if (rv)
+ ret =
+ clib_error_return (0, "set syslog sender failed rv=%d:%U", (int) rv,
+ format_vnet_api_errno, rv);
+
+done:
+ unformat_free (line_input);
+ return ret;
+}
+
+static clib_error_t *
+show_syslog_sender_command_fn (vlib_main_t * vm, unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ syslog_main_t *sm = &syslog_main;
+ u32 vrf_id = ~0;
+
+ if (sm->fib_index != ~0)
+ vrf_id = fib_table_get_table_id (sm->fib_index, FIB_PROTOCOL_IP4);
+
+ if (syslog_is_enabled ())
+ vlib_cli_output (vm, "collector %U:%u, src address %U, VRF ID %d, "
+ "max-msg-size %u",
+ format_ip4_address, &sm->collector, sm->collector_port,
+ format_ip4_address, &sm->src_address,
+ vrf_id, sm->max_msg_size);
+ else
+ vlib_cli_output (vm, "syslog sender is disabled");
+
+ return 0;
+}
+
+static clib_error_t *
+test_syslog_command_fn (vlib_main_t * vm, unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ unformat_input_t _line_input, *line_input = &_line_input;
+ syslog_msg_t syslog_msg;
+ syslog_facility_t facility;
+ syslog_severity_t severity;
+ clib_error_t *ret = 0;
+ u8 *app_name = 0, *msgid = 0, *sd_id = 0, *param_name = 0, *param_value = 0;
+
+ if (!syslog_is_enabled ())
+ return 0;
+
+ /* Get a line of input. */
+ if (!unformat_user (input, unformat_line_input, line_input))
+ return 0;
+
+ if (unformat (line_input, "%U", unformat_syslog_facility, &facility))
+ {
+ if (unformat (line_input, "%U", unformat_syslog_severity, &severity))
+ {
+ if (syslog_severity_filter_block (severity))
+ goto done;
+
+ if (unformat (line_input, "%s", &app_name))
+ {
+ if (unformat (line_input, "%s", &msgid))
+ {
+ syslog_msg_init (&syslog_msg, facility, severity,
+ (char *) app_name, (char *) msgid);
+ while (unformat (line_input, "sd-id %s", &sd_id))
+ {
+ syslog_msg_sd_init (&syslog_msg, (char *) sd_id);
+ while (unformat
+ (line_input, "sd-param %s %s", &param_name,
+ &param_value))
+ {
+ syslog_msg_add_sd_param (&syslog_msg,
+ (char *) param_name,
+ (char *) param_value);
+ vec_free (param_name);
+ vec_free (param_value);
+ }
+ vec_free (sd_id);
+ }
+ if (unformat_check_input (line_input) !=
+ UNFORMAT_END_OF_INPUT)
+ syslog_msg_add_msg (&syslog_msg, "%U",
+ format_unformat_input, line_input);
+ syslog_msg_send (&syslog_msg);
+ }
+ else
+ {
+ ret =
+ clib_error_return (0, "Unknown input `%U'",
+ format_unformat_error, line_input);
+ goto done;
+ }
+ }
+ else
+ {
+ ret =
+ clib_error_return (0, "Unknown input `%U'",
+ format_unformat_error, line_input);
+ goto done;
+ }
+ }
+ else
+ {
+ ret =
+ clib_error_return (0, "Unknown input `%U'", format_unformat_error,
+ line_input);
+ goto done;
+ }
+ }
+ else
+ {
+ ret =
+ clib_error_return (0, "Unknown input `%U'", format_unformat_error,
+ line_input);
+ goto done;
+ }
+
+done:
+ vec_free (app_name);
+ vec_free (msgid);
+ unformat_free (line_input);
+ return ret;
+}
+
+static clib_error_t *
+set_syslog_filter_command_fn (vlib_main_t * vm, unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ unformat_input_t _line_input, *line_input = &_line_input;
+ syslog_main_t *sm = &syslog_main;
+ clib_error_t *ret = 0;
+
+ /* Get a line of input. */
+ if (!unformat_user (input, unformat_line_input, line_input))
+ return 0;
+
+ while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat
+ (line_input, "severity %U", unformat_syslog_severity,
+ &sm->severity_filter))
+ ;
+ else
+ {
+ ret = clib_error_return (0, "Unknown input `%U'",
+ format_unformat_error, line_input);
+ goto done;
+ }
+ }
+
+done:
+ unformat_free (line_input);
+ return ret;
+}
+
+static clib_error_t *
+show_syslog_filter_command_fn (vlib_main_t * vm, unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ syslog_main_t *sm = &syslog_main;
+
+ vlib_cli_output (vm, "severity-filter: %U", format_syslog_severity,
+ sm->severity_filter);
+
+ return 0;
+}
+
+/* *INDENT-OFF* */
+/*?
+ * Set syslog sender configuration.
+ *
+ * @cliexpar
+ * @parblock
+ *
+ * Example of how to configure syslog sender:
+ * @cliexcmd{set syslog sender collector 10.10.10.10 port 514 src 172.16.2.2}
+ * @endparblock
+?*/
+VLIB_CLI_COMMAND (set_syslog_sender_command, static) = {
+ .path = "set syslog sender",
+ .short_help = "set syslog sender "
+ "collector <ip4-address> [port <port>] "
+ "src <ip4-address> [vrf-id <vrf-id>] "
+ "[max-msg-size <max-msg-size>]",
+ .function = set_syslog_sender_command_fn,
+};
+
+/*?
+ * Show syslog sender configuration.
+ *
+ * @cliexpar
+ * @parblock
+ *
+ * Example of how to display syslog sender configuration:
+ * @cliexstart{show syslog sender}
+ * collector 10.10.10.10:514, src address 172.16.2.2, VRF ID 0, max-msg-size 480
+ * @cliexend
+ * @endparblock
+?*/
+VLIB_CLI_COMMAND (show_syslog_sender_command, static) = {
+ .path = "show syslog sender",
+ .short_help = "show syslog sender",
+ .function = show_syslog_sender_command_fn,
+};
+
+/*?
+ * This command generate test syslog message.
+ *
+ * @cliexpar
+ * @parblock
+ *
+ * Example of how to generate following syslog message
+ * '<em><180>1 2018-11-07T11:36:41.231759Z 172.16.1.1 test 10484 testMsg
+ * [exampleSDID@32473 eventID="1011" eventSource="App" iut="3"]
+ * this is message</em>'
+ * @cliexcmd{test syslog local6 warning test testMsg sd-id <!--
+ * --> exampleSDID@32473 sd-param eventID 1011 sd-param eventSource App <!--
+ * --> sd-param iut 3 this is message}
+ * @endparblock
+?*/
+VLIB_CLI_COMMAND (test_syslog_command, static) = {
+ .path = "test syslog",
+ .short_help = "test syslog <facility> <severity> <app-name> <msgid> "
+ "[sd-id <sd-id> sd-param <name> <value>] [<message]",
+ .function = test_syslog_command_fn,
+};
+
+/*?
+ * Set syslog severity filter, specified severity and greater match.
+ *
+ * @cliexpar
+ * @parblock
+ *
+ * Example of how to configure syslog severity filter:
+ * @cliexcmd{set syslog filter severity warning}
+ * @endparblock
+?*/
+VLIB_CLI_COMMAND (set_syslog_filter_command, static) = {
+ .path = "set syslog filter",
+ .short_help = "set syslog filter severity <severity>",
+ .function = set_syslog_filter_command_fn,
+};
+
+/*?
+ * Show syslog severity filter.
+ *
+ * @cliexpar
+ * @parblock
+ *
+ * Example of how to display syslog severity filter:
+ * @cliexstart{show syslog filter}
+ * severity-filter: warning
+ * @cliexend
+ * @endparblock
+?*/
+VLIB_CLI_COMMAND (show_syslog_filter_command, static) = {
+ .path = "show syslog filter",
+ .short_help = "show syslog filter",
+ .function = show_syslog_filter_command_fn,
+};
+/* *INDENT-ON* */
+
+static clib_error_t *
+syslog_init (vlib_main_t * vm)
+{
+ syslog_main_t *sm = &syslog_main;
+ f64 vlib_time_0 = vlib_time_now (vm);
+ struct timeval timeval_0;
+ vlib_node_t *ip4_lookup_node;
+
+ sm->vlib_main = vm;
+ sm->vnet_main = vnet_get_main ();
+
+ sm->procid = getpid ();
+ gettimeofday (&timeval_0, 0);
+ sm->time_offset =
+ (f64) timeval_0.tv_sec + (((f64) timeval_0.tv_usec) * 1e-6) - vlib_time_0;
+
+ sm->collector.as_u32 = 0;
+ sm->src_address.as_u32 = 0;
+ sm->collector_port = DEFAULT_UDP_PORT;
+ sm->max_msg_size = DEFAULT_MAX_MSG_SIZE;
+ sm->fib_index = ~0;
+ sm->severity_filter = SYSLOG_SEVERITY_INFORMATIONAL;
+
+ ip4_lookup_node = vlib_get_node_by_name (vm, (u8 *) "ip4-lookup");
+ sm->ip4_lookup_node_index = ip4_lookup_node->index;
+
+ return 0;
+}
+
+VLIB_INIT_FUNCTION (syslog_init);
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vnet/syslog/syslog.h b/src/vnet/syslog/syslog.h
new file mode 100644
index 00000000000..ed915877518
--- /dev/null
+++ b/src/vnet/syslog/syslog.h
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2018 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @file RFC5424 syslog protocol declarations
+ */
+#ifndef __included_syslog_h__
+#define __included_syslog_h__
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vnet/ip/ip4_packet.h>
+
+/* syslog message facilities */
+#define foreach_syslog_facility \
+ _(0, KERNEL, "kernel") \
+ _(1, USER_LEVEL, "user-level") \
+ _(2, MAIL_SYSTEM, "mail-system") \
+ _(3, SYSTEM_DAEMONS, "system-daemons") \
+ _(4, SEC_AUTH, "security-authorization") \
+ _(5, SYSLOGD, "syslogd") \
+ _(6, LINE_PRINTER, "line-printer") \
+ _(7, NETWORK_NEWS, "network-news") \
+ _(8, UUCP, "uucp") \
+ _(9, CLOCK, "clock-daemon") \
+ _(11, FTP, "ftp-daemon") \
+ _(12, NTP, "ntp-subsystem") \
+ _(13, LOG_AUDIT, "log-audit") \
+ _(14, LOG_ALERT, "log-alert") \
+ _(16, LOCAL0, "local0") \
+ _(17, LOCAL1, "local1") \
+ _(18, LOCAL2, "local2") \
+ _(19, LOCAL3, "local3") \
+ _(20, LOCAL4, "local4") \
+ _(21, LOCAL5, "local5") \
+ _(22, LOCAL6, "local6") \
+ _(23, LOCAL7, "local7")
+
+typedef enum
+{
+#define _(v, N, s) SYSLOG_FACILITY_##N = v,
+ foreach_syslog_facility
+#undef _
+} syslog_facility_t;
+
+/* syslog message severities */
+#define foreach_syslog_severity \
+ _(0, EMERGENCY, "emergency") \
+ _(1, ALERT, "alert") \
+ _(2, CRITICAL, "critical") \
+ _(3, ERROR, "error") \
+ _(4, WARNING, "warning") \
+ _(5, NOTICE, "notice") \
+ _(6, INFORMATIONAL, "informational") \
+ _(7, DEBUG, "debug")
+
+typedef enum
+{
+#define _(v, N, s) SYSLOG_SEVERITY_##N = v,
+ foreach_syslog_severity
+#undef _
+} syslog_severity_t;
+
+/** syslog header */
+typedef struct
+{
+ /** facility value, part of priority */
+ syslog_facility_t facility;
+
+ /** severity value, part of priority */
+ syslog_severity_t severity;
+
+ /** message timestamp */
+ f64 timestamp;
+
+ /** application that originated the message RFC5424 6.2.5. */
+ char *app_name;
+
+ /** identify the type of message RFC5424 6.2.7. */
+ char *msgid;
+} syslog_header_t;
+
+/** syslog message */
+typedef struct
+{
+ /** header */
+ syslog_header_t header;
+
+ /** structured data RFC5424 6.3. */
+ u8 **structured_data;
+ u32 curr_sd_index;
+
+ /** free-form message RFC5424 6.4. */
+ u8 *msg;
+} syslog_msg_t;
+
+typedef struct
+{
+ /** process ID RFC5424 6.2.6. */
+ u32 procid;
+
+ /** time offset */
+ f64 time_offset;
+
+ /** IPv4 address of remote host (destination) */
+ ip4_address_t collector;
+
+ /** UDP port number of remote host (destination) */
+ u16 collector_port;
+
+ /** IPv4 address of sender (source) */
+ ip4_address_t src_address;
+
+ /** FIB table index */
+ u32 fib_index;
+
+ /** message size limit */
+ u32 max_msg_size;
+
+ /** severity filter (specified severity and greater match) */
+ syslog_severity_t severity_filter;
+
+ /** ip4-lookup node index */
+ u32 ip4_lookup_node_index;
+
+ /** convenience variables */
+ vlib_main_t *vlib_main;
+ vnet_main_t *vnet_main;
+} syslog_main_t;
+
+extern syslog_main_t syslog_main;
+
+/**
+ * @brief Initialize syslog message header
+ *
+ * @param facility facility value
+ * @param severity severity level
+ * @param app_name application that originated message RFC424 6.2.5. (optional)
+ * @param msgid identify the type of message RFC5424 6.2.7. (optional)
+ */
+void syslog_msg_init (syslog_msg_t * syslog_msg, syslog_facility_t facility,
+ syslog_severity_t severity, char *app_name,
+ char *msgid);
+/**
+ * @brief Initialize structured data element
+ *
+ * @param sd_id structured data element name RFC5424 6.3.2.
+ */
+void syslog_msg_sd_init (syslog_msg_t * syslog_msg, char *sd_id);
+
+/**
+ * @brief Add structured data elemnt parameter name-value pair RFC5424 6.3.3.
+ */
+void syslog_msg_add_sd_param (syslog_msg_t * syslog_msg, char *name,
+ char *fmt, ...);
+
+/**
+ * @brief Add free-form message RFC5424 6.4.
+ */
+void syslog_msg_add_msg (syslog_msg_t * syslog_msg, char *fmt, ...);
+
+/**
+ * @brief Send syslog message
+ */
+int syslog_msg_send (syslog_msg_t * syslog_msg);
+
+/**
+ * @brief Set syslog sender configuration
+ *
+ * @param collector IPv4 address of syslog collector (destination)
+ * @param collector_port UDP port of syslog colector (destination)
+ * @param src IPv4 address of syslog sender (source)
+ * @param vrf_id VRF/FIB table ID
+ * @param max_msg_size maximum message length
+ */
+vnet_api_error_t set_syslog_sender (ip4_address_t * collector,
+ u16 collector_port, ip4_address_t * src,
+ u32 vrf_id, u32 max_msg_size);
+
+/**
+ * @brief Check if syslog logging is enabled
+ *
+ * @return 1 if syslog logging is enabled, 0 otherwise
+ */
+always_inline int
+syslog_is_enabled (void)
+{
+ syslog_main_t *sm = &syslog_main;
+
+ return sm->collector.as_u32 ? 1 : 0;
+}
+
+/**
+ * @brief Severity filter test
+ *
+ * @return 1 if message with specified severity is not selected to be logged
+ */
+always_inline int
+syslog_severity_filter_block (syslog_severity_t s)
+{
+ syslog_main_t *sm = &syslog_main;
+
+ return (sm->severity_filter < s);
+}
+
+#endif /* __included_syslog_h__ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vnet/syslog/syslog_api.c b/src/vnet/syslog/syslog_api.c
new file mode 100644
index 00000000000..8f94c72b291
--- /dev/null
+++ b/src/vnet/syslog/syslog_api.c
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2018 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vnet/vnet.h>
+#include <vlibmemory/api.h>
+
+#include <vnet/interface.h>
+#include <vnet/api_errno.h>
+
+#include <vnet/fib/fib_table.h>
+#include <vnet/syslog/syslog.h>
+
+#include <vnet/vnet_msg_enum.h>
+
+#define vl_typedefs /* define message structures */
+#include <vnet/vnet_all_api_h.h>
+#undef vl_typedefs
+
+#define vl_endianfun /* define message structures */
+#include <vnet/vnet_all_api_h.h>
+#undef vl_endianfun
+
+/* instantiate all the print functions we know about */
+#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
+#define vl_printfun
+#include <vnet/vnet_all_api_h.h>
+#undef vl_printfun
+
+#include <vlibapi/api_helper_macros.h>
+
+#define foreach_vpe_api_msg \
+_(SYSLOG_SET_SENDER, syslog_set_sender) \
+_(SYSLOG_GET_SENDER, syslog_get_sender) \
+_(SYSLOG_SET_FILTER, syslog_set_filter) \
+_(SYSLOG_GET_FILTER, syslog_get_filter)
+
+static int
+syslog_severity_decode (vl_api_syslog_severity_t v, syslog_severity_t * s)
+{
+ v = ntohl (v);
+ int rv = 0;
+
+ switch (v)
+ {
+ case SYSLOG_API_SEVERITY_EMERG:
+ *s = SYSLOG_SEVERITY_EMERGENCY;
+ break;
+ case SYSLOG_API_SEVERITY_ALERT:
+ *s = SYSLOG_SEVERITY_ALERT;
+ break;
+ case SYSLOG_API_SEVERITY_CRIT:
+ *s = SYSLOG_SEVERITY_CRITICAL;
+ break;
+ case SYSLOG_API_SEVERITY_ERR:
+ *s = SYSLOG_SEVERITY_ERROR;
+ break;
+ case SYSLOG_API_SEVERITY_WARN:
+ *s = SYSLOG_SEVERITY_WARNING;
+ break;
+ case SYSLOG_API_SEVERITY_NOTICE:
+ *s = SYSLOG_SEVERITY_NOTICE;
+ break;
+ case SYSLOG_API_SEVERITY_INFO:
+ *s = SYSLOG_SEVERITY_INFORMATIONAL;
+ break;
+ case SYSLOG_API_SEVERITY_DBG:
+ *s = SYSLOG_SEVERITY_DEBUG;
+ break;
+ default:
+ rv = VNET_API_ERROR_INVALID_VALUE;
+ }
+
+ return rv;
+}
+
+static int
+syslog_severity_encode (syslog_severity_t v, vl_api_syslog_severity_t * s)
+{
+ int rv = 0;
+ switch (v)
+ {
+ case SYSLOG_SEVERITY_EMERGENCY:
+ *s = SYSLOG_API_SEVERITY_EMERG;
+ break;
+ case SYSLOG_SEVERITY_ALERT:
+ *s = SYSLOG_API_SEVERITY_ALERT;
+ break;
+ case SYSLOG_SEVERITY_CRITICAL:
+ *s = SYSLOG_API_SEVERITY_CRIT;
+ break;
+ case SYSLOG_SEVERITY_ERROR:
+ *s = SYSLOG_API_SEVERITY_ERR;
+ break;
+ case SYSLOG_SEVERITY_WARNING:
+ *s = SYSLOG_API_SEVERITY_WARN;
+ break;
+ case SYSLOG_SEVERITY_NOTICE:
+ *s = SYSLOG_API_SEVERITY_NOTICE;
+ break;
+ case SYSLOG_SEVERITY_INFORMATIONAL:
+ *s = SYSLOG_API_SEVERITY_INFO;
+ break;
+ case SYSLOG_SEVERITY_DEBUG:
+ *s = SYSLOG_API_SEVERITY_DBG;
+ break;
+ default:
+ rv = VNET_API_ERROR_INVALID_VALUE;
+ }
+
+ *s = htonl (*s);
+ return rv;
+}
+
+static void
+vl_api_syslog_set_sender_t_handler (vl_api_syslog_set_sender_t * mp)
+{
+ vl_api_syslog_set_sender_reply_t *rmp;
+ ip4_address_t collector, src;
+
+ clib_memcpy (&collector, &mp->collector_address, sizeof (collector));
+ clib_memcpy (&src, &mp->src_address, sizeof (src));
+
+ int rv = set_syslog_sender (&collector, ntohs (mp->collector_port), &src,
+ ntohl (mp->vrf_id), ntohl (mp->max_msg_size));
+
+ REPLY_MACRO (VL_API_SYSLOG_SET_SENDER_REPLY);
+}
+
+static void
+vl_api_syslog_get_sender_t_handler (vl_api_syslog_get_sender_t * mp)
+{
+ int rv = 0;
+ vl_api_syslog_get_sender_reply_t *rmp;
+ syslog_main_t *sm = &syslog_main;
+ u32 vrf_id;
+
+ /* *INDENT-OFF* */
+ REPLY_MACRO2 (VL_API_SYSLOG_GET_SENDER_REPLY,
+ ({
+ clib_memcpy (rmp->collector_address.address, &(sm->collector),
+ sizeof(ip4_address_t));
+ clib_memcpy (rmp->src_address.address, &(sm->src_address),
+ sizeof(ip4_address_t));
+ rmp->collector_port = htons (sm->collector_port);
+ if (sm->fib_index == ~0)
+ vrf_id = ~0;
+ else
+ vrf_id = htonl (fib_table_get_table_id (sm->fib_index, FIB_PROTOCOL_IP4));
+ rmp->vrf_id = vrf_id;
+ rmp->max_msg_size = htonl (sm->max_msg_size);
+ }))
+ /* *INDENT-ON* */
+}
+
+static void
+vl_api_syslog_set_filter_t_handler (vl_api_syslog_set_filter_t * mp)
+{
+ vl_api_syslog_set_filter_reply_t *rmp;
+ syslog_main_t *sm = &syslog_main;
+ int rv = 0;
+ syslog_severity_t s;
+
+ rv = syslog_severity_decode (mp->severity, &s);
+ if (rv)
+ goto send_reply;
+
+ sm->severity_filter = s;
+
+send_reply:
+ REPLY_MACRO (VL_API_SYSLOG_SET_FILTER_REPLY);
+}
+
+static void
+vl_api_syslog_get_filter_t_handler (vl_api_syslog_get_filter_t * mp)
+{
+ int rv = 0;
+ vl_api_syslog_get_filter_reply_t *rmp;
+ syslog_main_t *sm = &syslog_main;
+
+ /* *INDENT-OFF* */
+ REPLY_MACRO2 (VL_API_SYSLOG_GET_FILTER_REPLY,
+ ({
+ rv = syslog_severity_encode (sm->severity_filter, &rmp->severity);
+ }))
+ /* *INDENT-ON* */
+}
+
+#define vl_msg_name_crc_list
+#include <vnet/vnet_all_api_h.h>
+#undef vl_msg_name_crc_list
+
+static void
+setup_message_id_table (api_main_t * am)
+{
+#define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
+ foreach_vl_msg_name_crc_syslog;
+#undef _
+}
+
+static clib_error_t *
+syslog_api_hookup (vlib_main_t * vm)
+{
+ api_main_t *am = &api_main;
+
+#define _(N,n) \
+ vl_msg_api_set_handlers(VL_API_##N, #n, \
+ vl_api_##n##_t_handler, \
+ vl_noop_handler, \
+ vl_api_##n##_t_endian, \
+ vl_api_##n##_t_print, \
+ sizeof(vl_api_##n##_t), 1);
+ foreach_vpe_api_msg;
+#undef _
+
+ /*
+ * Set up the (msg_name, crc, message-id) table
+ */
+ setup_message_id_table (am);
+
+ return 0;
+}
+
+VLIB_API_INIT_FUNCTION (syslog_api_hookup);
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vnet/syslog/syslog_udp.c b/src/vnet/syslog/syslog_udp.c
new file mode 100644
index 00000000000..f4fa1d0baf5
--- /dev/null
+++ b/src/vnet/syslog/syslog_udp.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2018 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @file syslog protocol UDP transport layer implementation (RFC5426)
+ */
+
+#include <vnet/syslog/syslog_udp.h>
+#include <vnet/ip/ip4.h>
+#include <vnet/udp/udp_packet.h>
+
+void
+syslog_add_udp_transport (vlib_main_t * vm, u32 bi)
+{
+ syslog_main_t *sm = &syslog_main;
+ vlib_buffer_t *b = vlib_get_buffer (vm, bi);
+ ip4_header_t *ip;
+ udp_header_t *udp;
+
+ vlib_buffer_advance (b, -(sizeof (ip4_header_t) + sizeof (udp_header_t)));
+
+ b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
+ vnet_buffer (b)->sw_if_index[VLIB_RX] = 0;
+ vnet_buffer (b)->sw_if_index[VLIB_TX] = sm->fib_index;
+
+ ip = vlib_buffer_get_current (b);
+ clib_memset (ip, 0, sizeof (*ip));
+ udp = (udp_header_t *) (ip + 1);
+ clib_memset (udp, 0, sizeof (*udp));
+
+ ip->ip_version_and_header_length = 0x45;
+ ip->flags_and_fragment_offset =
+ clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT);
+ ip->ttl = 255;
+ ip->protocol = IP_PROTOCOL_UDP;
+ ip->src_address.as_u32 = sm->src_address.as_u32;
+ ip->dst_address.as_u32 = sm->collector.as_u32;
+
+ udp->src_port = udp->dst_port = clib_host_to_net_u16 (sm->collector_port);
+
+ const u16 ip_length = vlib_buffer_length_in_chain (vm, b);
+ ip->length = clib_host_to_net_u16 (ip_length);
+ ip->checksum = ip4_header_checksum (ip);
+
+ const u16 udp_length = ip_length - (sizeof (ip4_header_t));
+ udp->length = clib_host_to_net_u16 (udp_length);
+ /* RFC5426 3.6. */
+ udp->checksum = ip4_tcp_udp_compute_checksum (vm, b, ip);
+ if (udp->checksum == 0)
+ udp->checksum = 0xffff;
+
+ b->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vnet/syslog/syslog_udp.h b/src/vnet/syslog/syslog_udp.h
new file mode 100644
index 00000000000..008fed70d19
--- /dev/null
+++ b/src/vnet/syslog/syslog_udp.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2018 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @file syslog protocol UDP transport layer declaration (RFC5426)
+ */
+#ifndef __included_syslog_udp_h__
+#define __included_syslog_udp_h__
+
+#include <vnet/syslog/syslog.h>
+
+/**
+ * @brief Add UDP/IP transport layer by prepending it to existing data
+ */
+void syslog_add_udp_transport (vlib_main_t * vm, u32 bi);
+
+#endif /* __included_syslog_udp_h__ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vnet/vnet_all_api_h.h b/src/vnet/vnet_all_api_h.h
index 157006b2643..927bcab9e92 100644
--- a/src/vnet/vnet_all_api_h.h
+++ b/src/vnet/vnet_all_api_h.h
@@ -76,6 +76,7 @@
#include <vnet/dhcp/dhcp6_ia_na_client_cp.api.h>
#include <vnet/devices/pipe/pipe.api.h>
#include <vnet/vxlan-gbp/vxlan_gbp.api.h>
+#include <vnet/syslog/syslog.api.h>
/*
* fd.io coding-style-patch-verification: ON