Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ribsync Proof of concept #4

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@

OUT=netmap-fwd
OBJS=arp.o cleanup.o cli.o config.o ether.o event.o icmp.o if.o inet.o
OBJS+=ip.o net.o netmap.o netmap-fwd.o radix.o util.o
OBJS+=ip.o net.o netmap.o netmap-fwd.o radix.o util.o ribsync.o
INCLUDES=arp.h cleanup.h cli.h config.h counters.h ether.h event.h icmp.h
INCLUDES+=if.h inet.h ip.h net.h netmap.h radix.h util.h
INCLUDES+=if.h inet.h ip.h net.h netmap.h radix.h util.h ribsync.h

LDFLAGS=-L/usr/local/lib -levent -lutil -lucl
CCFLAGS=-O2 -fPIC -g -Wall -Wshadow -Wcast-qual -Wcast-align -Wwrite-strings
Expand Down
4 changes: 2 additions & 2 deletions cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
#include "util.h"

#define CMDMAXSZ 64
#define MAXCLIBUF 4096
#define MAXCLIBUF 16777216

/* CLI client data. */
struct cli {
Expand Down Expand Up @@ -500,7 +500,7 @@ cli_ev_read(struct cli *cli)
int more;
ssize_t i, len;

if (cli->resid == MAXCLIBUF) {
if (cli->resid >= MAXCLIBUF) {
DPRINTF(
"dropping cli connection - unsupported cli command (%d)\n",
cli->fd);
Expand Down
95 changes: 95 additions & 0 deletions inet.c
Original file line number Diff line number Diff line change
Expand Up @@ -680,3 +680,98 @@ inet_cli_route(struct cli *cli, struct cli_args *args)

return (err);
}

/*
* Calculate prefix length of a netmask passed as a sockaddr ipv4 structure
*/
static int
calc_masklen_ipv4(struct sockaddr_in *addr)
{
int prefixLength = 0;
uint32_t m = ntohl( *(uint32_t*) &addr->sin_addr);
while (m & 0x80000000) {
prefixLength++;
m = m << 1;
}

if(prefixLength == 0) {
// This is a /32 - host
return 32;
}
return prefixLength;
}

int
inet_route_add_ipv4(
struct sockaddr_in addr_net,
struct sockaddr_in addr_mask,
struct sockaddr_in addr_gw,
int flags)
{
struct inet *inet;
inet = &g_inet;
struct inet_rtentry *rt;
struct radix_node *rn;

if (calc_masklen_ipv4(&addr_mask) < 32) {
addr_net.sin_addr.s_addr &= addr_mask.sin_addr.s_addr;
}

rn = inet->rnh->rnh_matchaddr( &addr_gw, inet->rnh);
if (rn == NULL || (rn->rn_flags & RNF_ROOT) != 0) {
if(rn == NULL) {
printf("\n[DBG]-add- rn is null\n");
}
printf("\n[WARN]-add- Network is unreachable\n");
return -1;
}

rt = (struct inet_rtentry *)rn;
if (inet_addroute(&addr_net, &addr_gw, &addr_mask, flags, rt->nmif) != 0) {
printf ("\n[WARN]-add- Cannot add route..(allready in table?)\n");
return -1;
}
printf("\t -OK-\n");
return 0;
}

int
inet_route_del_ipv4(
struct sockaddr_in addr_net,
struct sockaddr_in addr_mask,
struct sockaddr_in addr_gw, int flags)
{

struct inet *inet;
inet = &g_inet;
struct inet_rtentry *rt;
struct radix_node *rn;

if ( calc_masklen_ipv4(&addr_mask) < 32) {
addr_net.sin_addr.s_addr &= addr_mask.sin_addr.s_addr;
}

rn = inet->rnh->rnh_lookup(&addr_net, &addr_mask, inet->rnh);
if (rn == NULL || (rn->rn_flags & RNF_ROOT) != 0){
printf( "\n[WARN]-del- Route has not been found\n");
return -1;
}

rt = (struct inet_rtentry *)rn;
/* Check if the gateway address matches. */
if ( rt->gw.sin_addr.s_addr != addr_gw.sin_addr.s_addr) {
printf( "\n[WARN]-del- Route has not been found (gw not match)\n\n");
return -1;
}

rn = inet->rnh->rnh_deladdr(&addr_net, &addr_mask, inet->rnh);
if (rn == NULL) {
printf( "\n[WARN]-del- Route could not be deleted\n");
return -1;
}

rt = (struct inet_rtentry *)rn;
free(rt);
printf("\t -OK-\n");
return 0;
}
3 changes: 3 additions & 0 deletions inet.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,6 @@ void inet_addr_if_free(struct nm_if *);
struct inet_addr *inet_get_if_addr(struct nm_if *);
struct inet_addr *inet_our_addr(struct in_addr *);
struct inet_addr *inet_our_broadcast(struct in_addr *);

int inet_route_add_ipv4( struct sockaddr_in, struct sockaddr_in, struct sockaddr_in, int);
int inet_route_del_ipv4( struct sockaddr_in, struct sockaddr_in, struct sockaddr_in, int);
8 changes: 8 additions & 0 deletions netmap-fwd.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
#include "event.h"
#include "if.h"
#include "inet.h"
#include "ribsync.h"
#include "util.h"

#ifndef PREFIX
Expand Down Expand Up @@ -129,6 +130,7 @@ main(int argc, char **argv)
printf("error: cannot initialize the inet data structures.\n");
exit(1);
}
ribsync_init();

while (argc > 0) {
ifn = argv[0];
Expand Down Expand Up @@ -161,6 +163,12 @@ main(int argc, char **argv)
cleanup();
exit(1);
}
if (ribsync_open() == -1) {
printf("cannot open the kernel PF_ROUTE socket.\n");
cleanup();
exit(1);
}

event_base_dispatch(ev_get_base());
cleanup();

Expand Down
189 changes: 189 additions & 0 deletions ribsync.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
#include <sys/param.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/route.h>

#include <net/if_dl.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "cleanup.h"
#include "cli.h"
#include "event.h"
#include "inet.h"
#include "ribsync.h"

union rtsocket_msg {
char buf[1024];
struct rt_msghdr rtm;
struct if_msghdr ifm;
struct ifa_msghdr ifam;
struct if_announcemsghdr ifann;
};

static int
ribsync_cli_stats(struct cli *cli, struct cli_args *args)
{
const char *p;

if (1 == args->args) {
p = "RIBSYNC STATISTICS\n";
if (cli_obuf_append(cli, p, strlen(p)) == -1)
return (-1);
}

return (0);
}

int
ribsync_init(void)
{
/* Register the ribsync cli command. */
cli_cmd_add("ribsync", "ribsync - monitors kernel routing table\n", ribsync_cli_stats, NULL);

// cleanup_add(ribsync_cleanup, NULL);
return 0;
}

void
dump_sockaddr_in(struct sockaddr_in *addr)
{
printf(" sin_family: %d \n",addr->sin_family);
printf(" sin_addr: %s\n",inet_ntoa(addr->sin_addr));
}

struct sockaddr_route {
struct sockaddr_in route_dst;
struct sockaddr_in route_mask;
struct sockaddr_in route_gw;
int route_flasgs;
};

static struct sockaddr_route
parse_rt_addr(const union rtsocket_msg *msg_data, size_t len, int addrs_mask, size_t ppos)
{
size_t i=0;
int maskvec[] = {RTA_DST, RTA_GATEWAY, RTA_NETMASK, RTA_GENMASK, RTA_IFP, RTA_IFA, RTA_AUTHOR, RTA_BRD};

struct sockaddr_route rt_addr;
while (ppos < len && i < sizeof(maskvec)/sizeof(maskvec[0])) {

if (addrs_mask & maskvec[i]) {
const struct sockaddr *sa = (const struct sockaddr *)((const char *)msg_data + ppos);

if ( maskvec[i] == RTA_DST) {
rt_addr.route_dst = *(const struct sockaddr_in*)sa;

}else if ( maskvec[i] == RTA_GATEWAY) {
rt_addr.route_gw = *(const struct sockaddr_in*)sa;

}else if ( maskvec[i] == RTA_NETMASK) {
rt_addr.route_mask = *(const struct sockaddr_in*)sa;
}

// jump to next socketaddr struct
size_t diff = sa->sa_len;
if (!diff) {
diff = sizeof(long);
}
ppos += diff;
if (diff & (sizeof(long) - 1)) {
ppos += sizeof(long) - (diff & (sizeof(long) - 1));
}
}
i++;
}

printf("%s", inet_ntoa(rt_addr.route_dst.sin_addr));
printf("/%s", inet_ntoa(rt_addr.route_mask.sin_addr));
printf(" -> %s", inet_ntoa(rt_addr.route_gw.sin_addr));

return rt_addr;
}

static void
ribsync_ev_data(evutil_socket_t socket, short event, void *data)
{
union rtsocket_msg recv_data;
struct sockaddr_route rt_addr;

recv_data.rtm.rtm_msglen = 4;

int r1 = recv(socket, &recv_data, sizeof(recv_data), 0);
if (-1 == r1) {
printf("[EE] pf_socket recv error");
return;
}

if (r1 < 4 || r1 < recv_data.rtm.rtm_msglen) {
printf("SHORT READ (have %d want %hu), SKIPPING.\n", r1, recv_data.rtm.rtm_msglen);
return;
}

if ( 0 != recv_data.rtm.rtm_errno ) {
printf("Route message contains errors(%d), SKIPPING.\n", recv_data.rtm.rtm_errno);
return;
}

/*printf("Received %d bytes. Version %d, Type %#x, Len %d\n", r1,
recv_data.rtm.rtm_version,
recv_data.rtm.rtm_type,
recv_data.rtm.rtm_msglen
);*/

int rt_status=0;
switch (recv_data.rtm.rtm_type) {
case RTM_ADD:
printf("Add route: ");
rt_addr = parse_rt_addr(&recv_data, r1,recv_data.rtm.rtm_addrs, sizeof(struct rt_msghdr));
rt_status = inet_route_add_ipv4(rt_addr.route_dst, rt_addr.route_mask, rt_addr.route_gw, recv_data.rtm.rtm_flags);
break;
case RTM_DELETE:
printf("Del route: ");
rt_addr = parse_rt_addr(&recv_data, r1,recv_data.rtm.rtm_addrs, sizeof(struct rt_msghdr));
rt_status = inet_route_del_ipv4(rt_addr.route_dst, rt_addr.route_mask, rt_addr.route_gw, recv_data.rtm.rtm_flags);

break;
// case RTM_CHANGE:
// case RTM_NEWADDR:
// case RTM_DELADDR:
// case RTM_IFINFO:
// case RTM_IFANNOUNCE:
}
if( -1 == rt_status) {
printf("[DBG] Route dst\n");
dump_sockaddr_in(&rt_addr.route_dst);

printf("[DBG] Route netmask\n");
dump_sockaddr_in(&rt_addr.route_mask);

printf("[DBG] Route gateway\n");
dump_sockaddr_in(&rt_addr.route_gw);
printf("\n");
}
fflush(stdout);
}

int ribsync_open(void)
{
int rt_socket = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
if (-1 == rt_socket) {
return -1;
}

fd_set fds;
FD_ZERO(&fds);
FD_SET(rt_socket, &fds);

// Setup the event for pf_route socket.
struct event *ev;
ev = event_new(ev_get_base(), rt_socket, EV_READ | EV_PERSIST, ribsync_ev_data, NULL);
event_add(ev, NULL);

return 0;
}
6 changes: 6 additions & 0 deletions ribsync.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#ifndef __RIB_SYNC__
#define __RIB_SYNC__
int ribsync_init(void);
int ribsync_open(void);

#endif
4 changes: 3 additions & 1 deletion util.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@

#include "util.h"

#define MAXBUFSZ (BUFSZ * 1024)
// default was 256 * 1024 which is enough fo 70 routes
// 256 * 131072 should be enough for more than ~1.1 mil
#define MAXBUFSZ (BUFSZ * 131072)

int
dprintf(const char *fmt, ...)
Expand Down