PUNT socket: External control plane processes connected via UNIX domain sockets.

An external (to VPP) process can register (over the VPP binary API) to
receive control plane packets over a UNIX domain socket. The packets are
prepended with a packet descriptor containing meta-data (if_index of
interface, etc).

Currently only UDP is supported.

The socket supports sending of packets/frames as well.
The sent packet is prepended with a descriptor, telling VPP to
route the packet (via ip4-lookup, ip6-lookup) or as an pre-formed
Ethernet frame that is sent directly to interface-output.

The intended use case for this is for an external DHCP client or
a RIP implementation.

New configuration option:

punt { socket <socket path> }

To register use the punt_socket API message.

TODO:
  - Add support for pre-routing. I.e send L3 packet to given
    TX interface, but do ARP/ND (ip[46]-rewrite)
  - Add test scripts
  - Support for abstract names (starting with \0)
  - Add rate limiting (COP)
  - Support for other protocols, e.g. IPv6 ND

Change-Id: I4a0afc8020deebb3d9d74686dde694ee5bcb8d0f
Signed-off-by: Ole Troan <ot@cisco.com>
This commit is contained in:
Ole Troan
2017-05-16 14:59:29 +02:00
committed by Damjan Marion
parent 809bc74b5b
commit f7a55ad74c
5 changed files with 652 additions and 11 deletions

File diff suppressed because it is too large Load Diff

View File

@ -20,6 +20,7 @@
#ifndef included_punt_h
#define included_punt_h
#include <sys/un.h>
typedef enum
{
#define punt_error(n,s) PUNT_ERROR_##n,
@ -30,9 +31,56 @@ typedef enum
clib_error_t *vnet_punt_add_del (vlib_main_t * vm, u8 ipv,
u8 protocol, u16 port, int is_add);
u8 protocol, u16 port, bool is_add);
clib_error_t *vnet_punt_socket_add (vlib_main_t * vm, u32 header_version,
bool is_ip4, u8 protocol, u16 port,
char *client_pathname);
clib_error_t *vnet_punt_socket_del (vlib_main_t * vm, bool is_ip4,
u8 l4_protocol, u16 port);
char *vnet_punt_get_server_pathname (void);
#endif /* included_punt_h */
enum punt_action_e
{
PUNT_L2 = 0,
PUNT_IP4_ROUTED,
PUNT_IP6_ROUTED,
};
/*
* Packet descriptor header. Version 1
* If this header changes, the version must also change to notify clients.
*/
#define PUNT_PACKETDESC_VERSION 1
typedef struct __attribute__ ((packed))
{
u32 sw_if_index; /* RX or TX interface */
enum punt_action_e action;
} punt_packetdesc_t;
/*
* Client registration
*/
typedef struct
{
u16 port;
struct sockaddr_un caddr;
} punt_client_t;
typedef struct
{
int socket_fd;
char sun_path[sizeof (struct sockaddr_un)];
punt_client_t *clients_by_dst_port4;
punt_client_t *clients_by_dst_port6;
u32 unix_file_index;
bool is_configured;
vlib_node_t *interface_output_node;
u32 *ready_fds;
u32 *rx_buffers;
} punt_main_t;
extern punt_main_t punt_main;
#endif
/*
* fd.io coding-style-patch-verification: ON

View File

@ -17,3 +17,11 @@
punt_error (NONE, "no error")
punt_error (UDP_PORT, "udp port punt")
punt_error (SOCKET_RX, "Socket RX")
punt_error (SOCKET_TX, "Socket TX")
punt_error (SOCKET_RX_ERROR, "Socket RX error")
punt_error (SOCKET_TX_ERROR, "Socket TX error")
punt_error (NOBUFFER, "buffer allocation failure")
punt_error (READV, "socket read failure")
punt_error (ACTION, "invalid packet descriptor")

View File

@ -144,6 +144,8 @@ _(IP_SOURCE_AND_PORT_RANGE_CHECK_INTERFACE_ADD_DEL, \
ip_source_and_port_range_check_interface_add_del) \
_(DELETE_SUBIF, delete_subif) \
_(PUNT, punt) \
_(PUNT_SOCKET_REGISTER, punt_socket_register) \
_(PUNT_SOCKET_DEREGISTER, punt_socket_deregister) \
_(FEATURE_ENABLE_DISABLE, feature_enable_disable)
#define QUOTE_(x) #x
@ -1940,6 +1942,68 @@ vl_api_punt_t_handler (vl_api_punt_t * mp)
REPLY_MACRO (VL_API_PUNT_REPLY);
}
static void
vl_api_punt_socket_register_t_handler (vl_api_punt_socket_register_t * mp)
{
vl_api_punt_socket_register_reply_t *rmp;
vlib_main_t *vm = vlib_get_main ();
int rv = 0;
clib_error_t *error;
unix_shared_memory_queue_t *q;
u32 handle;
error = vnet_punt_socket_add (vm, ntohl (mp->header_version),
mp->is_ip4, mp->l4_protocol,
ntohs (mp->l4_port), (char *) mp->pathname);
if (error)
{
rv = -1;
clib_error_report (error);
}
q = vl_api_client_index_to_input_queue (mp->client_index);
if (!q)
return;
rmp = vl_msg_api_alloc (sizeof (*rmp));
rmp->_vl_msg_id = htons (VL_API_PUNT_SOCKET_REGISTER_REPLY);
rmp->context = mp->context;
rmp->retval = htonl (rv);
char *p = vnet_punt_get_server_pathname ();
/* Abstract pathnames start with \0 */
memcpy ((char *) rmp->pathname, p, sizeof (rmp->pathname));
vl_msg_api_send_shmem (q, (u8 *) & rmp);
}
static void
vl_api_punt_socket_deregister_t_handler (vl_api_punt_socket_deregister_t * mp)
{
vl_api_punt_socket_deregister_reply_t *rmp;
vlib_main_t *vm = vlib_get_main ();
int rv = 0;
clib_error_t *error;
unix_shared_memory_queue_t *q;
u32 handle;
error = vnet_punt_socket_del (vm, mp->is_ip4, mp->l4_protocol,
ntohs (mp->l4_port));
if (error)
{
rv = -1;
clib_error_report (error);
}
q = vl_api_client_index_to_input_queue (mp->client_index);
if (!q)
return;
rmp = vl_msg_api_alloc (sizeof (*rmp));
rmp->_vl_msg_id = htons (VL_API_PUNT_SOCKET_DEREGISTER_REPLY);
rmp->context = mp->context;
rmp->retval = htonl (rv);
vl_msg_api_send_shmem (q, (u8 *) & rmp);
}
static void
vl_api_feature_enable_disable_t_handler (vl_api_feature_enable_disable_t * mp)
{

View File

@ -991,6 +991,39 @@ autoreply define punt {
u16 l4_port;
};
/** \brief Punt traffic to the host via socket
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@param header_version - expected meta data header version (currently 1)
@param is_ip4 - L3 protocol 1 - IPv4, 0 - IPv6
@param l4_protocol - L4 protocol to be punted, only UDP (0x11) is supported
@param l4_port - TCP/UDP port to be punted
*/
define punt_socket_register {
u32 client_index;
u32 context;
u32 header_version;
u8 is_ip4;
u8 l4_protocol;
u16 l4_port;
u8 pathname[64];
};
define punt_socket_register_reply
{
u32 context;
i32 retval;
u8 pathname[64];
};
autoreply define punt_socket_deregister {
u32 client_index;
u32 context;
u8 is_ip4;
u8 l4_protocol;
u16 l4_port;
};
/** \brief Feature path enable/disable request
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request