aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Zammit <damien@zamaudio.com>2022-09-09 09:42:48 +0000
committerSamuel Thibault <samuel.thibault@ens-lyon.org>2022-09-11 19:10:14 +0200
commitb43d6d6f4617cf045ef1a5443568360df6cef328 (patch)
tree5a83d5debdcc9e665eab196675108cc3db3d183f
parentda8d2ba4b61a7d6b25f5b2215447795f2b9badf9 (diff)
downloadhurd-b43d6d6f4617cf045ef1a5443568360df6cef328.tar.gz
hurd-b43d6d6f4617cf045ef1a5443568360df6cef328.tar.bz2
hurd-b43d6d6f4617cf045ef1a5443568360df6cef328.zip
Add new RPC for pfinet network routes
Message-Id: <20220909094234.517165-1-damien@zamaudio.com>
-rw-r--r--hurd/pfinet.defs9
-rw-r--r--pfinet/iioctl-ops.c1
-rw-r--r--pfinet/linux-src/include/net/ip_fib.h2
-rw-r--r--pfinet/linux-src/net/ipv4/fib_hash.c80
-rw-r--r--pfinet/pfinet-ops.c88
-rw-r--r--pfinet/pfinet.h5
-rw-r--r--pfinet/route.h42
7 files changed, 223 insertions, 4 deletions
diff --git a/hurd/pfinet.defs b/hurd/pfinet.defs
index ec0b03e3..81f7c194 100644
--- a/hurd/pfinet.defs
+++ b/hurd/pfinet.defs
@@ -37,3 +37,12 @@ routine pfinet_siocgifconf (
amount: vm_size_t;
out buf: data_t, dealloc
);
+
+/* Return the routing table as a sequence of ifrtreq_t structs.
+ The maximum number of routes returned can be given in AMOUNT.
+ But if AMOUNT is -1, all routes will be returned up to MAX_ROUTES. */
+routine pfinet_getroutes (
+ port: io_t;
+ amount: vm_size_t;
+ out routes: data_t, dealloc[]
+);
diff --git a/pfinet/iioctl-ops.c b/pfinet/iioctl-ops.c
index b128242b..adf7bd82 100644
--- a/pfinet/iioctl-ops.c
+++ b/pfinet/iioctl-ops.c
@@ -104,6 +104,7 @@ prepare_rt_req(struct rt_req *req, struct device *dev, in_addr_t dst, in_addr_t
req->rtm.rtm_type = RTN_UNICAST;
req->rtm.rtm_protocol = RTPROT_BOOT;
req->rtm.rtm_dst_len = inet_mask_len(mask);
+ req->rtm.rtm_table = RT_TABLE_MAIN;
return 0;
}
diff --git a/pfinet/linux-src/include/net/ip_fib.h b/pfinet/linux-src/include/net/ip_fib.h
index 60338945..faf13c64 100644
--- a/pfinet/linux-src/include/net/ip_fib.h
+++ b/pfinet/linux-src/include/net/ip_fib.h
@@ -17,6 +17,7 @@
#define _NET_IP_FIB_H
#include <linux/config.h>
+#include "route.h"
struct kern_rta
{
@@ -223,6 +224,7 @@ extern u32 __fib_res_prefsrc(struct fib_result *res);
/* Exported by fib_hash.c */
extern struct fib_table *fib_hash_init(int id);
+int fn_hash_get_routes(struct fib_table *tb, ifrtreq_t *routes, int first, int count);
#ifdef CONFIG_IP_MULTIPLE_TABLES
/* Exported by fib_rules.c */
diff --git a/pfinet/linux-src/net/ipv4/fib_hash.c b/pfinet/linux-src/net/ipv4/fib_hash.c
index 074a3687..495f1682 100644
--- a/pfinet/linux-src/net/ipv4/fib_hash.c
+++ b/pfinet/linux-src/net/ipv4/fib_hash.c
@@ -883,3 +883,83 @@ __initfunc(struct fib_table * fib_hash_init(int id))
memset(tb->tb_data, 0, sizeof(struct fn_hash));
return tb;
}
+
+static void
+fib_node_get_route(int type, int dead, struct fib_info *fi, u32 prefix, u32 mask, ifrtreq_t *r)
+{
+ int len;
+ static unsigned type2flags[RTN_MAX+1] = {
+ [RTN_UNREACHABLE] = RTF_REJECT,
+ [RTN_PROHIBIT] = RTF_REJECT
+ };
+ unsigned flags;
+
+ flags = type2flags[type];
+
+ if (fi && fi->fib_nh->nh_gw)
+ flags |= RTF_GATEWAY;
+ if (mask == 0xFFFFFFFF)
+ flags |= RTF_HOST;
+ if (!dead)
+ flags |= RTF_UP;
+
+
+ if (fi && fi->fib_dev) {
+ snprintf (r->ifname, IFNAMSIZ, "%s", fi->fib_dev->name);
+ } else {
+ r->ifname[0] = '*';
+ r->ifname[1] = '\0';
+ }
+
+ r->rt_dest = prefix;
+ r->rt_flags = flags;
+ r->rt_mask = mask;
+
+ if (fi) {
+ r->rt_gateway = fi->fib_nh->nh_gw;
+ r->rt_metric = fi->fib_priority;
+ r->rt_mtu = fi->fib_mtu;
+ r->rt_window = fi->fib_window;
+ r->rt_irtt = fi->fib_rtt;
+ }
+}
+
+int
+fn_hash_get_routes(struct fib_table *tb, ifrtreq_t *routes, int first, int count)
+{
+ struct fn_hash *table = (struct fn_hash*)tb->tb_data;
+ struct fn_zone *fz;
+ int pos = 0;
+ int n = 0;
+
+ for (fz=table->fn_zone_list; fz; fz = fz->fz_next) {
+ int i;
+ struct fib_node *f;
+ int maxslot = fz->fz_divisor;
+ struct fib_node **fp = fz->fz_hash;
+
+ if (fz->fz_nent == 0)
+ continue;
+
+ if (pos + fz->fz_nent <= first) {
+ pos += fz->fz_nent;
+ continue;
+ }
+
+ for (i=0; i < maxslot; i++, fp++) {
+ for (f = *fp; f; f = f->fn_next) {
+ if (++pos <= first)
+ continue;
+ fib_node_get_route(f->fn_type,
+ f->fn_state & FN_S_ZOMBIE,
+ FIB_INFO(f),
+ fz_prefix(f->fn_key, fz),
+ FZ_MASK(fz), routes);
+ routes++;
+ if (++n >= count)
+ return n;
+ }
+ }
+ }
+ return n;
+}
diff --git a/pfinet/pfinet-ops.c b/pfinet/pfinet-ops.c
index 5db66978..9722e0e3 100644
--- a/pfinet/pfinet-ops.c
+++ b/pfinet/pfinet-ops.c
@@ -22,6 +22,13 @@
#include <linux/netdevice.h>
#include <linux/notifier.h>
+#include <linux/inetdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/ip.h>
+#include <net/route.h>
+#include <net/sock.h>
+#include <net/ip_fib.h>
+#include <net/addrconf.h>
#include "pfinet_S.h"
#include <netinet/in.h>
@@ -32,7 +39,8 @@
#include <sys/mman.h>
#include <sys/ioctl.h>
-#include <net/if.h>
+
+#define MAX_ROUTES 255
extern int dev_ifconf(char *arg);
@@ -91,3 +99,81 @@ S_pfinet_siocgifconf (io_t port,
pthread_mutex_unlock (&global_lock);
return err;
}
+
+int
+get_routing_table(int start, int count, ifrtreq_t *routes)
+{
+ struct fib_table *tb;
+
+ if (!routes)
+ return 0;
+
+ if ((tb = fib_get_table(RT_TABLE_MAIN)) == NULL)
+ return 0;
+
+ return fn_hash_get_routes(tb, routes, start, count);
+}
+
+
+/* Return the routing table as a series of ifrtreq_t structs
+ in routes, but don't return more then AMOUNT number of them.
+ If AMOUNT is -1, we get the full table. */
+error_t
+S_pfinet_getroutes (io_t port,
+ vm_size_t amount,
+ data_t *routes,
+ mach_msg_type_number_t *len,
+ boolean_t *dealloc_data)
+{
+ error_t err = 0;
+ ifrtreq_t rs[MAX_ROUTES];
+ int n;
+ ifrtreq_t *rtable;
+
+ pthread_mutex_lock (&global_lock);
+
+ if (dealloc_data)
+ *dealloc_data = FALSE;
+
+ if (amount == (vm_size_t) -1)
+ {
+ /* Get all of them, and return the number we got. */
+ n = get_routing_table (0, MAX_ROUTES, rs);
+ amount = n;
+ }
+ else
+ n = amount;
+
+ if (amount > 0)
+ {
+ /* Possibly allocate a new buffer. */
+ if (*len < amount * sizeof(ifrtreq_t))
+ {
+ rtable = (ifrtreq_t *) mmap (0, amount * sizeof(ifrtreq_t), PROT_READ|PROT_WRITE,
+ MAP_ANON, 0, 0);
+ if (dealloc_data)
+ *dealloc_data = TRUE;
+ }
+ else
+ rtable = (ifrtreq_t *)*routes;
+
+ n = get_routing_table (0, n, rtable);
+ if (amount > n)
+ memset(&rtable[n], 0, (amount - n) * sizeof(ifrtreq_t));
+ }
+
+ if (rtable == MAP_FAILED)
+ {
+ /* Should use errno here, but glue headers #undef errno */
+ err = ENOMEM;
+ *len = 0;
+ }
+ else
+ {
+ *len = n * sizeof(ifrtreq_t);
+ *routes = (char *)rtable;
+ }
+
+ pthread_mutex_unlock (&global_lock);
+ return err;
+}
diff --git a/pfinet/pfinet.h b/pfinet/pfinet.h
index d08779bf..f8a1dd8d 100644
--- a/pfinet/pfinet.h
+++ b/pfinet/pfinet.h
@@ -29,6 +29,7 @@
#include <sys/mman.h>
#include <sys/socket.h>
#include <pthread.h>
+#include "route.h"
extern pthread_mutex_t global_lock;
extern pthread_mutex_t net_bh_lock;
@@ -77,9 +78,7 @@ error_t make_sockaddr_port (struct socket *, int,
void init_devices (void);
void *net_bh_worker (void *);
void init_time (void);
-void ip_rt_add (short, u_long, u_long, u_long, struct device *,
- u_short, u_long);
-void ip_rt_del (u_long, struct device *);
+int get_routing_table(int start, int count, ifrtreq_t *routes);
struct sock;
error_t tcp_tiocinq (struct sock *sk, mach_msg_type_number_t *amount);
diff --git a/pfinet/route.h b/pfinet/route.h
new file mode 100644
index 00000000..00beb6c1
--- /dev/null
+++ b/pfinet/route.h
@@ -0,0 +1,42 @@
+/*
+ Copyright (C) 2022 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef ROUTE_H_
+#define ROUTE_H_
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+
+typedef struct ifrtreq {
+ char ifname[IFNAMSIZ];
+ in_addr_t rt_dest;
+ in_addr_t rt_mask;
+ in_addr_t rt_gateway;
+ int rt_flags;
+ int rt_metric;
+ int rt_mtu;
+ int rt_window;
+ int rt_irtt;
+ int rt_tos;
+ int rt_class;
+} ifrtreq_t;
+
+#endif