Skip to content

Commit

Permalink
rt: Add monitor option
Browse files Browse the repository at this point in the history
rt --monitor can be used to get route creations and deletions in
live. They are broadcasted on Netlink by the vrouter kernel module.
Only routes of type AF_INET and AF_INET6 are fully printed while
routes of type AF_BRIDGE are not generated yet.

The output format is 'jsonline' to be easily parsed by external
tools.

This is an example of the output:
{"operation":"add","family":"AF_INET","vrf_id":2,"prefix":32,"address":"20.1.1.254","nh":12,"flags":{"label_valid":false, "arp_proxy":true, "arp_trap":true, "arp_flood":false}}

Change-Id: I8cb8556f1c4adda0bb0ef10f98fc38702b2942c4
Closes-bug: #1650316
  • Loading branch information
Antoine Eiche committed Dec 7, 2017
1 parent 7e1320e commit 12b9b49
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 26 deletions.
8 changes: 5 additions & 3 deletions include/nl_util.h
Expand Up @@ -63,7 +63,7 @@ struct nl_client {
int cl_socket_domain;
int cl_socket_type;
int cl_socket_proto;
int (*cl_recvmsg)(struct nl_client *);
int (*cl_recvmsg)(struct nl_client *, bool);
struct sockaddr *cl_sa;
uint32_t cl_sa_len;
};
Expand Down Expand Up @@ -115,9 +115,10 @@ extern void nl_free_client(struct nl_client *cl);
extern int nl_socket(struct nl_client *, int, int , int);
extern int nl_connect(struct nl_client *, uint32_t, uint16_t);
extern int nl_sendmsg(struct nl_client *);
extern int nl_client_datagram_recvmsg(struct nl_client *);
extern int nl_client_stream_recvmsg(struct nl_client *);
extern int nl_client_datagram_recvmsg(struct nl_client *, bool);
extern int nl_client_stream_recvmsg(struct nl_client *, bool);
extern int nl_recvmsg(struct nl_client *);
extern int nl_recvmsg_waitall(struct nl_client *);
extern struct nl_response *nl_parse_reply(struct nl_client *);
extern struct nl_response *nl_parse_gen_nh(struct nl_client *);
extern struct nl_response *nl_parse_gen_mpls(struct nl_client *);
Expand Down Expand Up @@ -173,6 +174,7 @@ extern bool vr_valid_mac_address(const char *);
extern char *vr_proto_string(unsigned short);

extern int vr_recvmsg(struct nl_client *cl, bool dump);
extern int vr_recvmsg_waitall(struct nl_client *cl, bool dump);
extern int vr_sendmsg(struct nl_client *, void *, char *);
extern struct nl_client *vr_get_nl_client(int);

Expand Down
2 changes: 2 additions & 0 deletions linux/vr_genetlink.c
Expand Up @@ -45,6 +45,8 @@ struct genl_family vrouter_genl_family = {
#endif /* Linux 4.10.0 */
};

/* This becomes the group id 0x4 since group id allocation starts at */
/* 0x4 and it is the only group for this family */
struct genl_multicast_group vrouter_genl_groups[] = {
{ .name = "VRouterGroup" },
};
Expand Down
40 changes: 35 additions & 5 deletions utils/nl_util.c
Expand Up @@ -21,6 +21,7 @@
#include <linux/genetlink.h>
#include <linux/sockios.h>
#include <linux/dcbnl.h>
#include <linux/socket.h>
#endif

#include <stdint.h>
Expand All @@ -31,7 +32,13 @@
#include "vr_genetlink.h"
#include "vr_os.h"

/* This is defined in linux kernel headers (linux/socket.h) */
#if !defined(SOL_NETLINK)
#define SOL_NETLINK 270
#endif

#define VROUTER_GENETLINK_FAMILY_NAME "vrouter"
#define VROUTER_GENETLINK_VROUTER_GROUP_ID 0x4
#define GENL_ID_VROUTER (NLMSG_MIN_TYPE + 0x10)

extern struct nl_response *nl_parse_gen(struct nl_client *);
Expand Down Expand Up @@ -542,6 +549,9 @@ nl_socket(struct nl_client *cl, int domain, int type, int protocol)
int
nl_connect(struct nl_client *cl, uint32_t ip, uint16_t port)
{
int group = VROUTER_GENETLINK_VROUTER_GROUP_ID;
int ret;

if (cl->cl_socket_domain == AF_NETLINK) {
struct sockaddr_nl *sa = malloc(sizeof(struct sockaddr_nl));

Expand All @@ -554,7 +564,18 @@ nl_connect(struct nl_client *cl, uint32_t ip, uint16_t port)
cl->cl_sa = (struct sockaddr *)sa;
cl->cl_sa_len = sizeof(*sa);

return bind(cl->cl_sock, cl->cl_sa, cl->cl_sa_len);
ret = bind(cl->cl_sock, cl->cl_sa, cl->cl_sa_len);
if (ret < 0) {
return ret;
}

/* We join the vrouter netlink broadcast group */
ret = setsockopt(cl->cl_sock, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &group, sizeof(group));
if (ret < 0) {
return ret;
}

return 0;
}

if (cl->cl_socket_domain == AF_INET) {
Expand All @@ -577,7 +598,7 @@ nl_connect(struct nl_client *cl, uint32_t ip, uint16_t port)
}

int
nl_client_datagram_recvmsg(struct nl_client *cl)
nl_client_datagram_recvmsg(struct nl_client *cl, bool msg_wait)
{
int ret;
struct msghdr msg;
Expand All @@ -594,7 +615,10 @@ nl_client_datagram_recvmsg(struct nl_client *cl)

cl->cl_buf_offset = 0;

ret = recvmsg(cl->cl_sock, &msg, MSG_DONTWAIT);
if (msg_wait)
ret = recvmsg(cl->cl_sock, &msg, MSG_WAITALL);
else
ret = recvmsg(cl->cl_sock, &msg, MSG_DONTWAIT);
if (ret < 0) {
return ret;
}
Expand All @@ -607,7 +631,7 @@ nl_client_datagram_recvmsg(struct nl_client *cl)
}

int
nl_client_stream_recvmsg(struct nl_client *cl) {
nl_client_stream_recvmsg(struct nl_client *cl, bool msg_wait) {
int ret;
struct msghdr msg;
struct iovec iov;
Expand Down Expand Up @@ -652,7 +676,13 @@ nl_client_stream_recvmsg(struct nl_client *cl) {
int
nl_recvmsg(struct nl_client *cl)
{
return cl->cl_recvmsg(cl);
return cl->cl_recvmsg(cl, false);
}

int
nl_recvmsg_waitall(struct nl_client *cl)
{
return cl->cl_recvmsg(cl, true);
}

int
Expand Down
110 changes: 94 additions & 16 deletions utils/rt.c
Expand Up @@ -49,7 +49,7 @@ static bool cmd_proxy_set = false;
static bool cmd_trap_set = false;
static bool cmd_flood_set = false;

static int cmd_set, dump_set, get_set;
static int cmd_set, dump_set, get_set, monitor_set;
static int family_set, help_set, vrf_set;
static int cust_flags;

Expand All @@ -68,6 +68,8 @@ static uint32_t cmd_replace_plen = 0xFFFFFFFF;
static char cmd_dst_mac[6];
static bool dump_pending;

static int monitor = 0;

static void Usage(void);
static void usage_internal(void);

Expand Down Expand Up @@ -200,6 +202,59 @@ vr_bridge_print_route(uint8_t *mac, unsigned int index,
return;
}

static void
vr_print_route_json(vr_route_req *rt)
{
char addr[INET6_ADDRSTRLEN];

printf("{");
printf("\"operation\":");
if (rt->h_op == SANDESH_OP_ADD)
printf("\"add\"");
else if (rt->h_op == SANDESH_OP_DEL)
printf("\"delete\"");
else
printf("\"unknown\"");

printf(",\"family\":");
if (rt->rtr_family == AF_INET)
printf("\"AF_INET\"");
else if (rt->rtr_family == AF_INET6)
printf("\"AF_INET6\"");
else if (rt->rtr_family == AF_BRIDGE)
printf("\"AF_BRIDGE\"");
else
printf("\"unknown\"");

if ((rt->rtr_family == AF_INET) ||
(rt->rtr_family == AF_INET6)) {
printf(",\"vrf_id\":%d", rt->rtr_vrf_id);

if (rt->rtr_prefix_size) {
inet_ntop(rt->rtr_family, rt->rtr_prefix, addr, sizeof(addr));
printf(",\"prefix\":%d", rt->rtr_prefix_len);
printf(",\"address\":\"%s\"", addr);
printf(",\"nh_id\":%d", rt->rtr_nh_id);
}

printf(",\"flags\":{\"label_valid\":%s, \"arp_proxy\":%s, \"arp_trap\":%s, \"arp_flood\":%s}",
rt->rtr_label_flags & VR_RT_LABEL_VALID_FLAG ? "true" : "false",
rt->rtr_label_flags & VR_RT_ARP_PROXY_FLAG ? "true" : "false",
rt->rtr_label_flags & VR_RT_ARP_TRAP_FLAG ? "true" : "false",
rt->rtr_label_flags & VR_RT_ARP_FLOOD_FLAG ? "true" : "false");

if (rt->rtr_label_flags & VR_RT_LABEL_VALID_FLAG)
printf(",\"label\":%d", rt->rtr_label);

if (rt->rtr_mac_size) {
printf(",\"mac_address\":\"%s\"", ether_ntoa((struct ether_addr *)(rt->rtr_mac)));
printf(",\"mac_index\":%d", rt->rtr_index);
}
}
printf("}\n");
fflush(stdout);
}

static void
route_req_process(void *s_req)
{
Expand All @@ -208,6 +263,11 @@ route_req_process(void *s_req)
char flags[32];
vr_route_req *rt = (vr_route_req *)s_req;

if (monitor) {
vr_print_route_json(rt);
return;
}

if ((rt->rtr_family == AF_INET) ||
(rt->rtr_family == AF_INET6)) {
memcpy(rt_marker, rt->rtr_prefix, RT_IP_ADDR_SIZE(rt->rtr_family));
Expand Down Expand Up @@ -489,11 +549,14 @@ usage_internal()
static void
validate_options(void)
{
unsigned int set = dump_set + family_set + cmd_set + help_set;
unsigned int set = dump_set + family_set + cmd_set + help_set + monitor_set;

char addr[INET6_ADDRSTRLEN];
struct ether_addr *eth;

if (monitor)
return;

if (cmd_op < 0)
goto usage;

Expand Down Expand Up @@ -609,6 +672,7 @@ validate_options(void)
enum opt_flow_index {
COMMAND_OPT_INDEX,
DUMP_OPT_INDEX,
MONITOR_OPT_INDEX,
FAMILY_OPT_INDEX,
GET_OPT_INDEX,
VRF_OPT_INDEX,
Expand All @@ -617,26 +681,29 @@ enum opt_flow_index {
};

static struct option long_options[] = {
[COMMAND_OPT_INDEX] = {"cmd", no_argument, &cmd_set, 1},
[DUMP_OPT_INDEX] = {"dump", required_argument, &dump_set, 1},
[FAMILY_OPT_INDEX] = {"family", required_argument, &family_set, 1},
[GET_OPT_INDEX] = {"get", required_argument, &get_set, 1},
[VRF_OPT_INDEX] = {"vrf", required_argument, &vrf_set, 1},
[HELP_OPT_INDEX] = {"help", no_argument, &help_set, 1},
[MAX_OPT_INDEX] = { NULL, 0, 0, 0},
[COMMAND_OPT_INDEX] = {"cmd", no_argument, &cmd_set, 1},
[DUMP_OPT_INDEX] = {"dump", required_argument, &dump_set, 1},
[MONITOR_OPT_INDEX] = {"monitor", no_argument, &monitor_set, 1},
[FAMILY_OPT_INDEX] = {"family", required_argument, &family_set, 1},
[GET_OPT_INDEX] = {"get", required_argument, &get_set, 1},
[VRF_OPT_INDEX] = {"vrf", required_argument, &vrf_set, 1},
[HELP_OPT_INDEX] = {"help", no_argument, &help_set, 1},
[MAX_OPT_INDEX] = { NULL, 0, 0, 0},
};

static void
Usage(void)
{
printf("Usage: rt --dump <vrf_id> [--family <inet|inet6|bridge>]>\n");
printf(" rt --get <address/plen> --vrf <id> [--family <inet|inet6>]\n");
printf(" rt --help\n");
printf("Usage: rt --dump <vrf_id> [--family <inet|inet6|bridge>]>\n");
printf(" rt --get <address/plen> --vrf <id> [--family <inet|inet6>]\n");
printf(" rt --monitor\n");
printf(" rt --help\n");
printf("\n");
printf("--dump Dumps the routing table corresponding to vrf_id\n");
printf("--family Optional family specification to --dump command\n");
printf(" Specification should be one of \"inet\" or \"bridge\"\n");
printf("--help Prints this help message\n");
printf("--dump Dumps the routing table corresponding to vrf_id\n");
printf("--family Optional family specification to --dump command\n");
printf(" Specification should be one of \"inet\" or \"bridge\"\n");
printf("--monitor Watch for netlink broadcasted messages\n");
printf("--help Prints this help message\n");

exit(1);
}
Expand Down Expand Up @@ -682,6 +749,10 @@ parse_long_opts(int opt_flow_index, char *opt_arg)
cmd_vrf_id = strtoul(opt_arg, NULL, 0);
break;

case MONITOR_OPT_INDEX:
monitor = 1;
break;

case HELP_OPT_INDEX:
default:
Usage();
Expand Down Expand Up @@ -816,6 +887,13 @@ main(int argc, char *argv[])
exit(1);
}

if (monitor)
while (1) {
ret = vr_recvmsg_waitall(cl, false);
if (ret == -1)
exit(1);
}

if (cmd_family_id == AF_BRIDGE) {
if (cmd_op == SANDESH_OP_DUMP || cmd_op == SANDESH_OP_GET) {
ret = vr_bridge_table_setup(cl);
Expand Down
21 changes: 19 additions & 2 deletions utils/vr_util.c
Expand Up @@ -202,15 +202,20 @@ vr_proto_string(unsigned short proto)

/* send and receive */
int
vr_recvmsg(struct nl_client *cl, bool dump)
vr_recvmsg_generic(struct nl_client *cl, bool dump, bool msg_wait)
{
int ret = 0;
bool pending = true;
struct nl_response *resp;
struct nlmsghdr *nlh;

while (pending) {
if ((ret = nl_recvmsg(cl)) > 0) {
if (msg_wait) {
ret = nl_recvmsg_waitall(cl);
} else {
ret = nl_recvmsg(cl);
}
if (ret > 0) {
if (dump) {
pending = true;
} else {
Expand All @@ -236,6 +241,18 @@ vr_recvmsg(struct nl_client *cl, bool dump)
return ret;
}

int
vr_recvmsg(struct nl_client *cl, bool dump)
{
return vr_recvmsg_generic(cl, dump, false);
}

int
vr_recvmsg_waitall(struct nl_client *cl, bool dump)
{
return vr_recvmsg_generic(cl, dump, true);
}

int
vr_sendmsg(struct nl_client *cl, void *request,
char *request_string)
Expand Down

0 comments on commit 12b9b49

Please sign in to comment.