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>
This commit is contained in:
@ -11,3 +11,4 @@ Programming notes for developers.
|
||||
- @subpage acl_multicore
|
||||
- @subpage acl_lookup_context
|
||||
- @subpage libmemif_doc
|
||||
- @subpage syslog_doc
|
||||
|
@ -1354,6 +1354,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
|
||||
##############################################################################
|
||||
|
18
src/vnet/syslog/dir.dox
Normal file
18
src/vnet/syslog/dir.dox
Normal file
@ -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
|
||||
*/
|
65
src/vnet/syslog/sylog_doc.md
Normal file
65
src/vnet/syslog/sylog_doc.md
Normal file
@ -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");
|
||||
```
|
119
src/vnet/syslog/syslog.api
Normal file
119
src/vnet/syslog/syslog.api
Normal file
@ -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:
|
||||
*/
|
646
src/vnet/syslog/syslog.c
Normal file
646
src/vnet/syslog/syslog.c
Normal file
File diff suppressed because it is too large
Load Diff
225
src/vnet/syslog/syslog.h
Normal file
225
src/vnet/syslog/syslog.h
Normal file
@ -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:
|
||||
*/
|
243
src/vnet/syslog/syslog_api.c
Normal file
243
src/vnet/syslog/syslog_api.c
Normal file
@ -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:
|
||||
*/
|
72
src/vnet/syslog/syslog_udp.c
Normal file
72
src/vnet/syslog/syslog_udp.c
Normal file
@ -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:
|
||||
*/
|
36
src/vnet/syslog/syslog_udp.h
Normal file
36
src/vnet/syslog/syslog_udp.h
Normal file
@ -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:
|
||||
*/
|
@ -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
|
||||
|
@ -73,7 +73,7 @@ PYTHON_EXTRA_DEPENDS=
|
||||
endif
|
||||
|
||||
PYTHON_VENV_PATH=$(VPP_PYTHON_PREFIX)/virtualenv
|
||||
PYTHON_DEPENDS=$(PYTHON_EXTRA_DEPENDS) psutil faulthandler six scapy==2.4.0 pexpect cryptography subprocess32 cffi git+https://github.com/vpp-dev/py-lispnetworking
|
||||
PYTHON_DEPENDS=$(PYTHON_EXTRA_DEPENDS) psutil faulthandler six scapy==2.4.0 pexpect cryptography subprocess32 cffi syslog-rfc5424-parser git+https://github.com/vpp-dev/py-lispnetworking
|
||||
SCAPY_SOURCE=$(shell find $(PYTHON_VENV_PATH) -name site-packages)
|
||||
BUILD_COV_DIR=$(BR)/test-cov
|
||||
|
||||
|
196
test/test_syslog.py
Normal file
196
test/test_syslog.py
Normal file
@ -0,0 +1,196 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from framework import VppTestCase, VppTestRunner
|
||||
from util import ppp
|
||||
from scapy.packet import Raw
|
||||
from scapy.layers.inet import IP, UDP
|
||||
from vpp_papi_provider import SYSLOG_SEVERITY
|
||||
from syslog_rfc5424_parser import SyslogMessage, ParseError
|
||||
from syslog_rfc5424_parser.constants import SyslogFacility, SyslogSeverity
|
||||
|
||||
|
||||
class TestSyslog(VppTestCase):
|
||||
""" Syslog Protocol Test Cases """
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestSyslog, cls).setUpClass()
|
||||
|
||||
try:
|
||||
cls.create_pg_interfaces(range(1))
|
||||
cls.pg0.admin_up()
|
||||
cls.pg0.config_ip4()
|
||||
cls.pg0.resolve_arp()
|
||||
|
||||
except Exception:
|
||||
super(TestSyslog, cls).tearDownClass()
|
||||
raise
|
||||
|
||||
def syslog_generate(self, facility, severity, appname, msgid, sd=None,
|
||||
msg=None):
|
||||
"""
|
||||
Generate syslog message
|
||||
|
||||
:param facility: facility value
|
||||
:param severity: severity level
|
||||
:param appname: application name that originate message
|
||||
:param msgid: message indetifier
|
||||
:param sd: structured data (optional)
|
||||
:param msg: free-form message (optional)
|
||||
"""
|
||||
facility_str = ['kernel', 'user-level', 'mail-system',
|
||||
'system-daemons', 'security-authorization', 'syslogd',
|
||||
'line-printer', 'network-news', 'uucp', 'clock-daemon',
|
||||
'', 'ftp-daemon', 'ntp-subsystem', 'log-audit',
|
||||
'log-alert', '', 'local0', 'local1', 'local2',
|
||||
'local3', 'local4', 'local5', 'local6', 'local7']
|
||||
|
||||
severity_str = ['emergency', 'alert', 'critical', 'error', 'warning',
|
||||
'notice', 'informational', 'debug']
|
||||
|
||||
cli_str = "test syslog %s %s %s %s" % (facility_str[facility],
|
||||
severity_str[severity],
|
||||
appname,
|
||||
msgid)
|
||||
if sd is not None:
|
||||
for sd_id, sd_params in sd.items():
|
||||
cli_str += " sd-id %s" % (sd_id)
|
||||
for name, value in sd_params.items():
|
||||
cli_str += " sd-param %s %s" % (name, value)
|
||||
if msg is not None:
|
||||
cli_str += " %s" % (msg)
|
||||
self.vapi.cli(cli_str)
|
||||
|
||||
def syslog_verify(self, data, facility, severity, appname, msgid, sd=None,
|
||||
msg=None):
|
||||
"""
|
||||
Verify syslog message
|
||||
|
||||
:param data: syslog message
|
||||
:param facility: facility value
|
||||
:param severity: severity level
|
||||
:param appname: application name that originate message
|
||||
:param msgid: message indetifier
|
||||
:param sd: structured data (optional)
|
||||
:param msg: free-form message (optional)
|
||||
"""
|
||||
message = data.decode('utf-8')
|
||||
if sd is None:
|
||||
sd = {}
|
||||
try:
|
||||
message = SyslogMessage.parse(message)
|
||||
self.assertEqual(message.facility, facility)
|
||||
self.assertEqual(message.severity, severity)
|
||||
self.assertEqual(message.appname, appname)
|
||||
self.assertEqual(message.msgid, msgid)
|
||||
self.assertEqual(message.msg, msg)
|
||||
self.assertEqual(message.sd, sd)
|
||||
self.assertEqual(message.version, 1)
|
||||
self.assertEqual(message.hostname, self.pg0.local_ip4)
|
||||
except ParseError as e:
|
||||
self.logger.error(e)
|
||||
|
||||
def test_syslog(self):
|
||||
""" Syslog Protocol test """
|
||||
self.vapi.syslog_set_sender(self.pg0.remote_ip4n, self.pg0.local_ip4n)
|
||||
config = self.vapi.syslog_get_sender()
|
||||
self.assertEqual(config.collector_address.address,
|
||||
self.pg0.remote_ip4n)
|
||||
self.assertEqual(config.collector_port, 514)
|
||||
self.assertEqual(config.src_address.address, self.pg0.local_ip4n)
|
||||
self.assertEqual(config.vrf_id, 0)
|
||||
self.assertEqual(config.max_msg_size, 480)
|
||||
|
||||
appname = 'test'
|
||||
msgid = 'testMsg'
|
||||
msg = 'this is message'
|
||||
sd1 = {'exampleSDID@32473': {'iut': '3',
|
||||
'eventSource': 'App',
|
||||
'eventID': '1011'}}
|
||||
sd2 = {'exampleSDID@32473': {'iut': '3',
|
||||
'eventSource': 'App',
|
||||
'eventID': '1011'},
|
||||
'examplePriority@32473': {'class': 'high'}}
|
||||
|
||||
self.pg_enable_capture(self.pg_interfaces)
|
||||
self.syslog_generate(SyslogFacility.local7,
|
||||
SyslogSeverity.info,
|
||||
appname,
|
||||
msgid,
|
||||
None,
|
||||
msg)
|
||||
capture = self.pg0.get_capture(1)
|
||||
try:
|
||||
self.assertEqual(capture[0][IP].src, self.pg0.local_ip4)
|
||||
self.assertEqual(capture[0][IP].dst, self.pg0.remote_ip4)
|
||||
self.assertEqual(capture[0][UDP].dport, 514)
|
||||
self.assert_packet_checksums_valid(capture[0], False)
|
||||
except:
|
||||
self.logger.error(ppp("invalid packet:", capture[0]))
|
||||
raise
|
||||
self.syslog_verify(capture[0][Raw].load,
|
||||
SyslogFacility.local7,
|
||||
SyslogSeverity.info,
|
||||
appname,
|
||||
msgid,
|
||||
None,
|
||||
msg)
|
||||
|
||||
self.pg_enable_capture(self.pg_interfaces)
|
||||
self.vapi.syslog_set_filter(SYSLOG_SEVERITY.WARN)
|
||||
filter = self.vapi.syslog_get_filter()
|
||||
self.assertEqual(filter.severity, SYSLOG_SEVERITY.WARN)
|
||||
self.syslog_generate(SyslogFacility.local7,
|
||||
SyslogSeverity.info,
|
||||
appname,
|
||||
msgid,
|
||||
None,
|
||||
msg)
|
||||
self.pg0.assert_nothing_captured()
|
||||
|
||||
self.pg_enable_capture(self.pg_interfaces)
|
||||
self.syslog_generate(SyslogFacility.local6,
|
||||
SyslogSeverity.warning,
|
||||
appname,
|
||||
msgid,
|
||||
sd1,
|
||||
msg)
|
||||
capture = self.pg0.get_capture(1)
|
||||
self.syslog_verify(capture[0][Raw].load,
|
||||
SyslogFacility.local6,
|
||||
SyslogSeverity.warning,
|
||||
appname,
|
||||
msgid,
|
||||
sd1,
|
||||
msg)
|
||||
|
||||
self.vapi.syslog_set_sender(self.pg0.remote_ip4n,
|
||||
self.pg0.local_ip4n,
|
||||
collector_port=12345)
|
||||
config = self.vapi.syslog_get_sender()
|
||||
self.assertEqual(config.collector_port, 12345)
|
||||
|
||||
self.pg_enable_capture(self.pg_interfaces)
|
||||
self.syslog_generate(SyslogFacility.local5,
|
||||
SyslogSeverity.err,
|
||||
appname,
|
||||
msgid,
|
||||
sd2,
|
||||
None)
|
||||
capture = self.pg0.get_capture(1)
|
||||
try:
|
||||
self.assertEqual(capture[0][UDP].dport, 12345)
|
||||
except:
|
||||
self.logger.error(ppp("invalid packet:", capture[0]))
|
||||
raise
|
||||
self.syslog_verify(capture[0][Raw].load,
|
||||
SyslogFacility.local5,
|
||||
SyslogSeverity.err,
|
||||
appname,
|
||||
msgid,
|
||||
sd2,
|
||||
None)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main(testRunner=VppTestRunner)
|
@ -44,6 +44,17 @@ class QOS_SOURCE:
|
||||
IP = 3
|
||||
|
||||
|
||||
class SYSLOG_SEVERITY:
|
||||
EMERG = 0
|
||||
ALERT = 1
|
||||
CRIT = 2
|
||||
ERR = 3
|
||||
WARN = 4
|
||||
NOTICE = 5
|
||||
INFO = 6
|
||||
DBG = 7
|
||||
|
||||
|
||||
class UnexpectedApiReturnValueError(Exception):
|
||||
""" exception raised when the API return value is unexpected """
|
||||
pass
|
||||
@ -4026,3 +4037,42 @@ class VppPapiProvider(object):
|
||||
|
||||
def svs_dump(self):
|
||||
return self.api(self.papi.svs_dump, {})
|
||||
|
||||
def syslog_set_sender(
|
||||
self,
|
||||
collector,
|
||||
src,
|
||||
collector_port=514,
|
||||
vrf_id=0,
|
||||
max_msg_size=480):
|
||||
"""Set syslog sender configuration
|
||||
|
||||
:param collector: colector IP address
|
||||
:param src: source IP address
|
||||
:param collector_port: collector UDP port (Default value = 514)
|
||||
:param vrf_id: VRF id (Default value = 0)
|
||||
:param max_msg_size: maximum message length (Default value = 480)
|
||||
"""
|
||||
return self.api(self.papi.syslog_set_sender,
|
||||
{'collector_address': {
|
||||
'address': collector},
|
||||
'src_address': {
|
||||
'address': src},
|
||||
'collector_port': collector_port,
|
||||
'vrf_id': vrf_id,
|
||||
'max_msg_size': max_msg_size})
|
||||
|
||||
def syslog_get_sender(self):
|
||||
"""Return syslog sender configuration"""
|
||||
return self.api(self.papi.syslog_get_sender, {})
|
||||
|
||||
def syslog_set_filter(self, severity):
|
||||
"""Set syslog filter parameters
|
||||
|
||||
:param severity: severity filter (specified severity and greater match)
|
||||
"""
|
||||
return self.api(self.papi.syslog_set_filter, {'severity': severity})
|
||||
|
||||
def syslog_get_filter(self):
|
||||
"""Return syslog filter parameters"""
|
||||
return self.api(self.papi.syslog_get_filter, {})
|
||||
|
Reference in New Issue
Block a user