diff options
author | Damien Zammit <damien@zamaudio.com> | 2022-09-09 09:42:48 +0000 |
---|---|---|
committer | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2022-09-11 19:10:14 +0200 |
commit | b43d6d6f4617cf045ef1a5443568360df6cef328 (patch) | |
tree | 5a83d5debdcc9e665eab196675108cc3db3d183f | |
parent | da8d2ba4b61a7d6b25f5b2215447795f2b9badf9 (diff) | |
download | hurd-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.defs | 9 | ||||
-rw-r--r-- | pfinet/iioctl-ops.c | 1 | ||||
-rw-r--r-- | pfinet/linux-src/include/net/ip_fib.h | 2 | ||||
-rw-r--r-- | pfinet/linux-src/net/ipv4/fib_hash.c | 80 | ||||
-rw-r--r-- | pfinet/pfinet-ops.c | 88 | ||||
-rw-r--r-- | pfinet/pfinet.h | 5 | ||||
-rw-r--r-- | pfinet/route.h | 42 |
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 |