Skip to content

Commit

Permalink
Re-arrange net_* files efficiently
Browse files Browse the repository at this point in the history
Moved common functionality between net_*.c files into net.c.
Moved the handle_*_resp() calls for route, arp & if into handle_net_resp()
Added new tests/IF directory for interface statistics.

Signed-off-by: Anjali Kulkarni <[email protected]>
  • Loading branch information
anjalidk committed Feb 9, 2024
1 parent 48f5f73 commit 52635c2
Show file tree
Hide file tree
Showing 13 changed files with 498 additions and 660 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
CC = gcc
CFLAGS = -g -Wall -Werror -fPIC -std=gnu99
DEPS = resource.h resource_impl.h resmem.h resnet.h resproc.h resvm.h rescpu.h resfs.h stat.h
OBJ = resource.o resmem.o resnet.o resproc.o reskern.o resvm.o rescpu.o resfs.o net_if.o net_route.o net_arp.o stat.o resmem_cg.o
DEPS = resource.h resource_impl.h resmem.h resnet.h resproc.h resvm.h rescpu.h resfs.h stat.h net.h
OBJ = resource.o resmem.o resnet.o resproc.o reskern.o resvm.o rescpu.o resfs.o net_if.o net_route.o net_arp.o stat.o resmem_cg.o net.o
TEST = test
RM = rm -rf
CP = cp
Expand Down
372 changes: 372 additions & 0 deletions net.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,372 @@
#ifndef _RESOURCE_H
#include "resource.h"
#endif
#include <net/if.h>
#include <sys/socket.h>
#include <linux/rtnetlink.h>
#include <linux/if_link.h>
#include <linux/if_arp.h>
#include <linux/types.h>

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <strings.h>
#include <errno.h>
#include <string.h>
#include "resource_impl.h"
#include "net.h"

static int count, ecount;

int connect_netlink(int groups)
{
struct sockaddr_nl nl_saddr;
int err, net_sock;

net_sock = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
if (net_sock == -1) {
err = errno;
eprintf("Error in socket(), errno %d\n", err);
return -err;
}
bzero(&nl_saddr, sizeof(nl_saddr));
nl_saddr.nl_family = AF_NETLINK;
if (groups)
nl_saddr.nl_groups = RTMGRP_NEIGH;

err = bind(net_sock, (struct sockaddr *)&nl_saddr, sizeof(nl_saddr));
if (err == -1) {
err = errno;
eprintf("Error in bind(), errno %d\n", err);
close(net_sock);
return -err;
}
return net_sock;
}

int get_net_len(int net_sock)
{
int recvl, err;
struct msghdr msg;
struct iovec iov;
struct sockaddr_nl nladdr;

memset(&msg, 0, sizeof(msg));
memset(&iov, 0, sizeof(iov));

msg.msg_name = &nladdr;
msg.msg_namelen = sizeof(nladdr);
iov.iov_base = NULL;
iov.iov_len = 0;

msg.msg_iov = &iov;
msg.msg_iovlen = 1;

recvl = recvmsg(net_sock, &msg, MSG_PEEK | MSG_TRUNC);
if (recvl < 0) {
err = errno;
eprintf("Error in get length recvmsg(), errno %d\n", err);
return -err;
}
#ifdef PRINTLOGS
printf("received len %d\n",recvl);
#endif
return recvl;
}

static inline int get_max_net(int net_type, int len)
{
int header_size, net_sz;

switch(net_type) {
case NET_ROUTE:
net_sz = sizeof(struct rtmsg);
break;
case NET_ARP:
net_sz = sizeof(struct ndmsg);
break;
case NET_IF:
net_sz = (sizeof(struct if_stats_msg)) +
(sizeof(struct rtnl_link_stats64));
break;
}
header_size = (sizeof(struct nlmsghdr)) + net_sz;
return (len/header_size);
}

static inline int sz_net(int net_type)
{
switch(net_type) {
case NET_ROUTE:
return (sizeof(struct rt_info));
case NET_ARP:
return (sizeof(struct arp_info));
case NET_IF:
return (sizeof(struct ifstats));
}
return 0;
}

char net_file[3][20] = {"./route_info.txt",
"./arp_info.txt",
"./if_info.txt"};

static inline bool check_family_type(unsigned int family, unsigned int type)
{
if (family == AF_INET || family == AF_INET6) {
if ((type == RTN_BROADCAST) ||
(type == RTN_MULTICAST) ||
(type == RTN_LOCAL)) {
return true;
}
return false;
} else {
return true;
}
}

int handle_net_resp(int net_type, int net_sock, void **out)
{
int recvl, len, max_net, net_size;
int netind = 0, total_net_size = 0, ret = 0;
struct iovec iov;
struct msghdr msg;
struct nlmsghdr *r;
struct nlmsgerr *nlmsg_err;
struct sockaddr_nl nladdr;
void *ntwrks = NULL;
struct rtmsg *rt;
struct rtattr *at[RTA_MAX + 1];
struct rt_info *iroutes = NULL;
struct ndmsg *nd_msg;
struct rtattr *at_arp[NDA_MAX + 1], *rta;
struct arp_info *iarps = NULL;
struct if_stats_msg *ifsm;
struct rtattr *at_if[IFLA_STATS_MAX+1], *rta_if;
struct ifstats *ifs = NULL;

#ifdef TESTING
FILE *fp;
fp = fopen(net_file[net_type], "w");
if (!fp) {
eprintf("Error opening file %s with errno: %d",
net_file[net_type], errno);
return -1;
}
#endif

memset(&msg, 0, sizeof(msg));
msg.msg_name = &nladdr;
msg.msg_namelen = sizeof(nladdr);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;

while(1) {
len = get_net_len(net_sock);
if (len < 0) {
if (ntwrks)
free(ntwrks);
ret = len;
goto out;
}
char *buf = (char *)malloc(len);
if (!buf) {
if (ntwrks)
free(ntwrks);
ret = -ENOMEM;
goto out;
}
memset(&iov, 0, sizeof(iov));
iov.iov_base = buf;
iov.iov_len = len;
max_net = get_max_net(net_type, len);
net_size = max_net * sz_net(net_type);
total_net_size += net_size;

void *tmp = realloc(ntwrks, total_net_size);
if (!tmp) {
if (ntwrks)
free(ntwrks);
free(buf);
ret = -ENOMEM;
goto out;
}
ntwrks = tmp;

switch(net_type) {
case NET_ROUTE:
iroutes = (struct rt_info *)ntwrks + netind;
break;
case NET_ARP:
iarps = (struct arp_info *)ntwrks + netind;
break;
case NET_IF:
ifs = (struct ifstats *)ntwrks + netind;
break;
}

recvl = recvmsg(net_sock, &msg, 0);
if (recvl < 0) {
ret = -errno;
free(ntwrks);
free(buf);
eprintf("Error in resp recvmsg(), errno %d\n", -ret);
goto out;
}
r = (struct nlmsghdr *) buf;
#ifdef PRINTLOGS
printf("recvmsg len %d\n", recvl);
printf("r->nlmsg_type is %d\n", r->nlmsg_type);
#endif
while (NLMSG_OK(r, recvl)) {
if (r->nlmsg_type == NLMSG_ERROR) {
nlmsg_err = (struct nlmsgerr *)NLMSG_DATA(r);
eprintf("NLMSG_ERROR error: %d\n",
nlmsg_err->error);
ecount++;
free(buf);
free(ntwrks);
ret = -(nlmsg_err->error);
goto out;
} else if (r->nlmsg_type == NLMSG_DONE) {
#ifdef PRINTLOGS
printf("DONE\n");
#endif
free(buf);
switch(net_type) {
case NET_ROUTE:
*(struct rt_info **)out =
(struct rt_info *)ntwrks;
break;
case NET_ARP:
*(struct arp_info **)out =
(struct arp_info *)ntwrks;
break;
case NET_IF:
*(struct ifstats **)out =
(struct ifstats *)ntwrks;
break;
}
ret = netind;
goto out;
}
len = r->nlmsg_len;
switch (net_type) {
case NET_ROUTE:
rt = (struct rtmsg *)NLMSG_DATA(r);
len -= NLMSG_LENGTH(sizeof(*rt));
if (len < 0) {
eprintf("nlmsg_len incorrect");
free(buf);
free(ntwrks);
ret = -EINVAL;
goto out;
}
#ifdef PRINTLOGS
print_rt(rt);
printf("len after sub %lu is %d\n",
sizeof(*rt), len);
#endif
parse_rt_attr(at, RTM_RTA(rt), len);
if (check_family_type(rt->rtm_family,
rt->rtm_type)) {
r = NLMSG_NEXT(r, recvl);
continue;
}
get_rt_attr(at, iroutes, rt);
#ifdef TESTING
print_rt_info(iroutes, fp);
#endif
iroutes++;
netind++;
break;
case NET_ARP:
nd_msg = (struct ndmsg *)NLMSG_DATA(r);
len -= NLMSG_LENGTH(sizeof(*nd_msg));
if (len < 0) {
eprintf("nlmsg_len incorrect");
free(buf);
free(ntwrks);
ret = -EINVAL;
goto out;
}
#ifdef PRINTLOGS
print_arp(nd_msg);
printf("len after sub %lu is %d\n",
sizeof(*nd_msg), len);
#endif
rta = ((struct rtattr *) (((char *) (nd_msg)) + NLMSG_ALIGN(sizeof(struct ndmsg))));
parse_arp_attr(at_arp, rta, len);
if (check_family_type(nd_msg->ndm_family,
nd_msg->ndm_type)) {
r = NLMSG_NEXT(r, recvl);
continue;
}
#ifdef TESTING
get_arp_attr(at_arp, iarps, nd_msg, fp);
#else
get_arp_attr(at_arp, iarps, nd_msg);
#endif
iarps++;
netind++;
break;
case NET_IF:
ifsm = NLMSG_DATA(r);
len -= NLMSG_LENGTH(sizeof(*ifsm));
if (len < 0) {
eprintf("nlmsg_len incorrect");
free(buf);
free(ntwrks);
ret = -EINVAL;
goto out;
}
#ifdef PRINTLOGS
printf("ifindex is %d\n", ifsm->ifindex);
printf("len after sub %lu is %d\n",
sizeof(*ifsm), len);
#endif
rta_if = ((struct rtattr *)(((char *)(ifsm)) + NLMSG_ALIGN(sizeof(struct if_stats_msg))));
parse_if_attr(at_if, rta_if, len);
memcpy(&ifs->st64,
RTA_DATA(at_if[IFLA_STATS_LINK_64]),
sizeof(*ifs));
#ifdef TESTING
//print_if_info(ifsm, ifs, fp);
#endif
print_if(ifsm, ifs);
ifs++;
netind++;
break;
}
r = NLMSG_NEXT(r, recvl);
count++;
}
free(buf);
#ifdef PRINTLOGS
printf("No. of routes/arp/if: %d\n",netind);
#endif
}
switch(net_type) {
case NET_ROUTE:
*(struct rt_info **)out =
(struct rt_info *)ntwrks;
break;
case NET_ARP:
*(struct arp_info **)out =
(struct arp_info *)ntwrks;
break;
case NET_IF:
*(struct ifstats **)out =
(struct ifstats *)ntwrks;
break;
}
ret = netind;
out:
#ifdef TESTING
if (fp)
fclose(fp);
#endif
return ret;
}
Loading

0 comments on commit 52635c2

Please sign in to comment.