From 7a4c37e8b673328dda59cec11ab9dce66c22a312 Mon Sep 17 00:00:00 2001 From: Dimitri Staessens Date: Wed, 4 Mar 2026 21:26:43 +0100 Subject: ouroboros: Add IRM wrapper Add ouroboros.irm module wrapping the Ouroboros IRM C API, providing Python interfaces for IPCP lifecycle (create, destroy, bootstrap, enroll, connect), name management (create, destroy, register, list), and program/process binding. Split the monolithic CFFI build into separate _ouroboros_dev_cffi and _ouroboros_irm_cffi modules, each linking only its required library. Also includes: - ouroboros.cli module with higher-level wrappers mirroring CLI tools - FRCT flag support (set/get) in the Flow API - FlowPeer event type in FEventType - QoS defaults updated to match ouroboros source - Bug fixes: flow_set_snd_timeout typo, flow_set_flags calling convention, FlowSet name mangling, fqueue_type return type - .gitignore, copyright updates, version bump to 0.23.0 --- ffi/fccntl_wrap.h | 21 +++- ffi/irm_wrap.h | 90 +++++++++++++ ffi/pyouroboros_build.py | 137 -------------------- ffi/pyouroboros_build_dev.py | 151 ++++++++++++++++++++++ ffi/pyouroboros_build_irm.py | 291 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 550 insertions(+), 140 deletions(-) create mode 100644 ffi/irm_wrap.h delete mode 100644 ffi/pyouroboros_build.py create mode 100644 ffi/pyouroboros_build_dev.py create mode 100644 ffi/pyouroboros_build_irm.py (limited to 'ffi') diff --git a/ffi/fccntl_wrap.h b/ffi/fccntl_wrap.h index ab227ea..f9a137e 100644 --- a/ffi/fccntl_wrap.h +++ b/ffi/fccntl_wrap.h @@ -1,10 +1,10 @@ /* - * Ouroboros - Copyright (C) 2016 - 2020 + * Ouroboros - Copyright (C) 2016 - 2026 * * An fccntl wrapper * - * Dimitri Staessens - * Sander Vrijders + * Dimitri Staessens + * Sander Vrijders * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -71,3 +71,18 @@ int flow_get_flags(int fd) return (int) flags; } + +int flow_set_frct_flags(int fd, uint16_t flags) +{ + return fccntl(fd, FRCTSFLAGS, flags); +} + +int flow_get_frct_flags(int fd) +{ + uint16_t flags; + + if (fccntl(fd, FRCTGFLAGS, &flags)) + return -EPERM; + + return (int) flags; +} diff --git a/ffi/irm_wrap.h b/ffi/irm_wrap.h new file mode 100644 index 0000000..23b64a0 --- /dev/null +++ b/ffi/irm_wrap.h @@ -0,0 +1,90 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2026 + * + * An IRM wrapper for Python bindings + * + * Dimitri Staessens + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., http://www.fsf.org/about/contact/. + */ + +#include +#include +#include +#include + +static int ipcp_config_udp4_set_ip(struct ipcp_config * conf, + const char * ip_str) +{ + return inet_pton(AF_INET, ip_str, &conf->udp4.ip_addr) == 1 ? 0 : -1; +} + +static int ipcp_config_udp4_set_dns(struct ipcp_config * conf, + const char * dns_str) +{ + return inet_pton(AF_INET, dns_str, &conf->udp4.dns_addr) == 1 ? 0 : -1; +} + +static int ipcp_config_udp6_set_ip(struct ipcp_config * conf, + const char * ip_str) +{ + return inet_pton(AF_INET6, ip_str, &conf->udp6.ip_addr) == 1 ? 0 : -1; +} + +static int ipcp_config_udp6_set_dns(struct ipcp_config * conf, + const char * dns_str) +{ + return inet_pton(AF_INET6, dns_str, &conf->udp6.dns_addr) == 1 ? 0 : -1; +} + +static void ipcp_config_init_uni(struct ipcp_config * conf, + uint8_t addr_size, uint8_t eid_size, + uint8_t max_ttl, + enum pol_link_state ls_pol, + long t_recalc, long t_update, long t_timeo, + enum pol_dir dir_pol, + uint32_t dht_alpha, uint32_t dht_k, + uint32_t dht_t_expire, uint32_t dht_t_refresh, + uint32_t dht_t_replicate, + enum pol_addr_auth addr_auth, + enum pol_cong_avoid cong_avoid) +{ + memset(conf, 0, sizeof(*conf)); + conf->type = IPCP_UNICAST; + conf->unicast.dt.addr_size = addr_size; + conf->unicast.dt.eid_size = eid_size; + conf->unicast.dt.max_ttl = max_ttl; + conf->unicast.dt.routing.pol = ROUTING_LINK_STATE; + conf->unicast.dt.routing.ls.pol = ls_pol; + conf->unicast.dt.routing.ls.t_recalc = t_recalc; + conf->unicast.dt.routing.ls.t_update = t_update; + conf->unicast.dt.routing.ls.t_timeo = t_timeo; + conf->unicast.dir.pol = dir_pol; + conf->unicast.dir.dht.params.alpha = dht_alpha; + conf->unicast.dir.dht.params.k = dht_k; + conf->unicast.dir.dht.params.t_expire = dht_t_expire; + conf->unicast.dir.dht.params.t_refresh = dht_t_refresh; + conf->unicast.dir.dht.params.t_replicate = dht_t_replicate; + conf->unicast.addr_auth_type = addr_auth; + conf->unicast.cong_avoid = cong_avoid; +} + +static void ipcp_config_init_eth(struct ipcp_config * conf, + const char * dev, + uint16_t ethertype) +{ + memset(conf, 0, sizeof(*conf)); + strncpy(conf->eth.dev, dev, DEV_NAME_SIZE); + conf->eth.ethertype = ethertype; +} diff --git a/ffi/pyouroboros_build.py b/ffi/pyouroboros_build.py deleted file mode 100644 index a7a6a0d..0000000 --- a/ffi/pyouroboros_build.py +++ /dev/null @@ -1,137 +0,0 @@ -# -# Ouroboros - Copyright (C) 2016 - 2020 -# -# Python API for applications -# -# Dimitri Staessens -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public License -# version 2.1 as published by the Free Software Foundation. -# -# This library 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 -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., http://www.fsf.org/about/contact/. -# - -from cffi import FFI - -ffibuilder: FFI = FFI() - -ffibuilder.cdef(""" -/* OUROBOROS QOS.H */ -typedef struct qos_spec { - uint32_t delay; /* In ms */ - uint64_t bandwidth; /* In bits/s */ - uint8_t availability; /* Class of 9s */ - uint32_t loss; /* Packet loss */ - uint32_t ber; /* Bit error rate, errors per billion bits */ - uint8_t in_order; /* In-order delivery, enables FRCT */ - uint32_t max_gap; /* In ms */ - uint32_t timeout; /* Timeout in ms */ -} qosspec_t; - -/* OUROBOROS DEV.H */ -/* Returns flow descriptor, qs updates to supplied QoS. */ -int flow_alloc(const char * dst_name, - qosspec_t * qs, - const struct timespec * timeo); - -/* Returns flow descriptor, qs updates to supplied QoS. */ -int flow_accept(qosspec_t * qs, - const struct timespec * timeo); - -/* Returns flow descriptor, qs updates to supplied QoS. */ -int flow_join(const char * bc, - const struct timespec * timeo); - -int flow_dealloc(int fd); - -ssize_t flow_write(int fd, - const void * buf, - size_t count); - -ssize_t flow_read(int fd, - void * buf, - size_t count); - -/*OUROBOROS FCCNTL.H, VIA WRAPPER */ -int flow_set_snd_timeout(int fd, struct timespec * ts); - -int flow_set_rcv_timeout(int fd, struct timespec * ts); - -int flow_get_snd_timeout(int fd, struct timespec * ts); - -int flow_get_rcv_timeout(int fd, struct timespec * ts); - -int flow_get_qos(int fd, qosspec_t * qs); - -int flow_get_rx_qlen(int fd, size_t * sz); - -int flow_get_tx_qlen(int fd, size_t * sz); - -int flow_set_flags(int fd, uint32_t flags); - -int flow_get_flags(int fd); - -/*OUROBOROS FQUEUE.H */ -enum fqtype { - FLOW_PKT = (1 << 0), - FLOW_DOWN = (1 << 1), - FLOW_UP = (1 << 2), - FLOW_ALLOC = (1 << 3), - FLOW_DEALLOC = (1 << 4) -}; - -struct flow_set; - -struct fqueue; - -typedef struct flow_set fset_t; -typedef struct fqueue fqueue_t; - -fset_t * fset_create(void); - -void fset_destroy(fset_t * set); - -fqueue_t * fqueue_create(void); - -void fqueue_destroy(struct fqueue * fq); - -void fset_zero(fset_t * set); - -int fset_add(fset_t * set, - int fd); - -bool fset_has(const fset_t * set, - int fd); - -void fset_del(fset_t * set, - int fd); - -int fqueue_next(fqueue_t * fq); - -int fqueue_type(fqueue_t * fq); - -ssize_t fevent(fset_t * set, - fqueue_t * fq, - const struct timespec * timeo); -""") - -ffibuilder.set_source("_ouroboros_cffi", - """ -#include "ouroboros/qos.h" -#include "ouroboros/dev.h" -#include "fccntl_wrap.h" -#include "ouroboros/fqueue.h" - """, - libraries=['ouroboros-dev'], - extra_compile_args=["-I./ffi/"]) - -if __name__ == "__main__": - ffibuilder.compile(verbose=True) diff --git a/ffi/pyouroboros_build_dev.py b/ffi/pyouroboros_build_dev.py new file mode 100644 index 0000000..751b492 --- /dev/null +++ b/ffi/pyouroboros_build_dev.py @@ -0,0 +1,151 @@ +# +# Ouroboros - Copyright (C) 2016 - 2026 +# +# Python API for Ouroboros +# +# Dimitri Staessens +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# version 2.1 as published by the Free Software Foundation. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., http://www.fsf.org/about/contact/. +# + +from cffi import FFI + +ffibuilder: FFI = FFI() + +ffibuilder.cdef(""" +/* System types */ +typedef long... time_t; + +struct timespec { + time_t tv_sec; + long tv_nsec; + ...; +}; + +/* OUROBOROS QOS.H */ +typedef struct qos_spec { + uint32_t delay; + uint64_t bandwidth; + uint8_t availability; + uint32_t loss; + uint32_t ber; + uint8_t in_order; + uint32_t max_gap; + uint32_t timeout; /* Timeout in ms */ +} qosspec_t; + +/* OUROBOROS DEV.H */ +/* Returns flow descriptor, qs updates to supplied QoS. */ +int flow_alloc(const char * dst_name, + qosspec_t * qs, + const struct timespec * timeo); + +/* Returns flow descriptor, qs updates to supplied QoS. */ +int flow_accept(qosspec_t * qs, + const struct timespec * timeo); + +/* Returns flow descriptor. */ +int flow_join(const char * bc, + const struct timespec * timeo); + +int flow_dealloc(int fd); + +ssize_t flow_write(int fd, + const void * buf, + size_t count); + +ssize_t flow_read(int fd, + void * buf, + size_t count); + +/* OUROBOROS FCCNTL.H, VIA WRAPPER */ +int flow_set_snd_timeout(int fd, struct timespec * ts); + +int flow_set_rcv_timeout(int fd, struct timespec * ts); + +int flow_get_snd_timeout(int fd, struct timespec * ts); + +int flow_get_rcv_timeout(int fd, struct timespec * ts); + +int flow_get_qos(int fd, qosspec_t * qs); + +int flow_get_rx_qlen(int fd, size_t * sz); + +int flow_get_tx_qlen(int fd, size_t * sz); + +int flow_set_flags(int fd, uint32_t flags); + +int flow_get_flags(int fd); + +int flow_set_frct_flags(int fd, uint16_t flags); + +int flow_get_frct_flags(int fd); + +/* OUROBOROS FQUEUE.H */ +enum fqtype { + FLOW_PKT = ..., + FLOW_DOWN = ..., + FLOW_UP = ..., + FLOW_ALLOC = ..., + FLOW_DEALLOC = ..., + FLOW_PEER = ... +}; + +struct flow_set; + +struct fqueue; + +typedef struct flow_set fset_t; +typedef struct fqueue fqueue_t; + +fset_t * fset_create(void); + +void fset_destroy(fset_t * set); + +fqueue_t * fqueue_create(void); + +void fqueue_destroy(struct fqueue * fq); + +void fset_zero(fset_t * set); + +int fset_add(fset_t * set, + int fd); + +bool fset_has(const fset_t * set, + int fd); + +void fset_del(fset_t * set, + int fd); + +int fqueue_next(fqueue_t * fq); + +enum fqtype fqueue_type(fqueue_t * fq); + +ssize_t fevent(fset_t * set, + fqueue_t * fq, + const struct timespec * timeo); +""") + +ffibuilder.set_source("_ouroboros_dev_cffi", + """ +#include "ouroboros/qos.h" +#include "ouroboros/dev.h" +#include "fccntl_wrap.h" +#include "ouroboros/fqueue.h" + """, + libraries=['ouroboros-dev'], + extra_compile_args=["-I./ffi/"]) + +if __name__ == "__main__": + ffibuilder.compile(verbose=True) diff --git a/ffi/pyouroboros_build_irm.py b/ffi/pyouroboros_build_irm.py new file mode 100644 index 0000000..e29287e --- /dev/null +++ b/ffi/pyouroboros_build_irm.py @@ -0,0 +1,291 @@ +# +# Ouroboros - Copyright (C) 2016 - 2026 +# +# Python API for Ouroboros +# +# Dimitri Staessens +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# version 2.1 as published by the Free Software Foundation. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., http://www.fsf.org/about/contact/. +# + +from cffi import FFI + +ffibuilder: FFI = FFI() + +ffibuilder.cdef(""" +/* System types */ +typedef int... pid_t; +typedef long... time_t; + +struct timespec { + time_t tv_sec; + long tv_nsec; + ...; +}; + +/* Network types */ +struct in_addr { ...; }; +struct in6_addr { ...; }; + +/* OUROBOROS QOS.H */ +typedef struct qos_spec { + uint32_t delay; + uint64_t bandwidth; + uint8_t availability; + uint32_t loss; + uint32_t ber; + uint8_t in_order; + uint32_t max_gap; + uint32_t timeout; /* Timeout in ms */ +} qosspec_t; + +/* OUROBOROS IPCP.H */ +enum ipcp_type { + IPCP_LOCAL = ..., + IPCP_UNICAST = ..., + IPCP_BROADCAST = ..., + IPCP_ETH_LLC = ..., + IPCP_ETH_DIX = ..., + IPCP_UDP4 = ..., + IPCP_UDP6 = ..., + IPCP_INVALID = ... +}; + +/* Unicast IPCP policies */ +enum pol_addr_auth { + ADDR_AUTH_FLAT_RANDOM = ..., + ADDR_AUTH_INVALID = ... +}; + +enum pol_link_state { + LS_SIMPLE = ..., + LS_LFA = ..., + LS_ECMP = ..., + LS_INVALID = ... +}; + +struct ls_config { + enum pol_link_state pol; + time_t t_recalc; + time_t t_update; + time_t t_timeo; +}; + +enum pol_routing { + ROUTING_LINK_STATE = ..., + ROUTING_INVALID = ... +}; + +struct routing_config { + enum pol_routing pol; + union { + struct ls_config ls; + }; +}; + +enum pol_cong_avoid { + CA_NONE = ..., + CA_MB_ECN = ..., + CA_INVALID = ... +}; + +struct dt_config { + struct { + uint8_t addr_size; + uint8_t eid_size; + uint8_t max_ttl; + }; + struct routing_config routing; +}; + +enum pol_dir { + DIR_DHT = ..., + DIR_INVALID = ... +}; + +enum pol_dir_hash { + DIR_HASH_SHA3_224 = ..., + DIR_HASH_SHA3_256 = ..., + DIR_HASH_SHA3_384 = ..., + DIR_HASH_SHA3_512 = ..., + DIR_HASH_INVALID = ... +}; + +struct dir_dht_config { + struct { + uint32_t alpha; + uint32_t k; + uint32_t t_expire; + uint32_t t_refresh; + uint32_t t_replicate; + } params; + uint64_t peer; +}; + +struct dir_config { + enum pol_dir pol; + union { + struct dir_dht_config dht; + }; +}; + +struct uni_config { + struct dt_config dt; + struct dir_config dir; + enum pol_addr_auth addr_auth_type; + enum pol_cong_avoid cong_avoid; +}; + +struct eth_config { + char dev[256]; /* DEV_NAME_SIZE + 1 */ + uint16_t ethertype; +}; + +struct udp4_config { + struct in_addr ip_addr; + struct in_addr dns_addr; + uint16_t port; +}; + +struct udp6_config { + struct in6_addr ip_addr; + struct in6_addr dns_addr; + uint16_t port; +}; + +struct layer_info { + char name[256]; /* LAYER_NAME_SIZE + 1 */ + enum pol_dir_hash dir_hash_algo; +}; + +struct ipcp_config { + struct layer_info layer_info; + enum ipcp_type type; + + union { + struct uni_config unicast; + struct udp4_config udp4; + struct udp6_config udp6; + struct eth_config eth; + }; +}; + +/* OUROBOROS NAME.H */ +#define BIND_AUTO ... + +enum pol_balance { + LB_RR = ..., + LB_SPILL = ..., + LB_INVALID = ... +}; + +struct name_sec_paths { + char enc[512]; /* NAME_PATH_SIZE + 1 */ + char key[512]; /* NAME_PATH_SIZE + 1 */ + char crt[512]; /* NAME_PATH_SIZE + 1 */ +}; + +struct name_info { + char name[256]; /* NAME_SIZE + 1 */ + enum pol_balance pol_lb; + + struct name_sec_paths s; + struct name_sec_paths c; +}; + +/* OUROBOROS IRM.H */ + +struct ipcp_list_info { + pid_t pid; + enum ipcp_type type; + char name[255]; /* NAME_SIZE */ + char layer[255]; /* LAYER_NAME_SIZE */ +}; + +pid_t irm_create_ipcp(const char * name, + enum ipcp_type type); + +int irm_destroy_ipcp(pid_t pid); + +ssize_t irm_list_ipcps(struct ipcp_list_info ** ipcps); + +int irm_enroll_ipcp(pid_t pid, + const char * dst); + +int irm_bootstrap_ipcp(pid_t pid, + const struct ipcp_config * conf); + +int irm_connect_ipcp(pid_t pid, + const char * component, + const char * dst, + qosspec_t qs); + +int irm_disconnect_ipcp(pid_t pid, + const char * component, + const char * dst); + +int irm_bind_program(const char * prog, + const char * name, + uint16_t opts, + int argc, + char ** argv); + +int irm_unbind_program(const char * progr, + const char * name); + +int irm_bind_process(pid_t pid, + const char * name); + +int irm_unbind_process(pid_t pid, + const char * name); + +int irm_create_name(struct name_info * info); + +int irm_destroy_name(const char * name); + +ssize_t irm_list_names(struct name_info ** names); + +int irm_reg_name(const char * name, + pid_t pid); + +int irm_unreg_name(const char * name, + pid_t pid); + +/* IRM WRAPPER HELPERS */ +int ipcp_config_udp4_set_ip(struct ipcp_config * conf, + const char * ip_str); + +int ipcp_config_udp4_set_dns(struct ipcp_config * conf, + const char * dns_str); + +int ipcp_config_udp6_set_ip(struct ipcp_config * conf, + const char * ip_str); + +int ipcp_config_udp6_set_dns(struct ipcp_config * conf, + const char * dns_str); + +/* libc */ +void free(void *ptr); +""") + +ffibuilder.set_source("_ouroboros_irm_cffi", + """ +#include "ouroboros/qos.h" +#include "irm_wrap.h" + """, + libraries=['ouroboros-irm'], + extra_compile_args=["-I./ffi/"]) + +if __name__ == "__main__": + ffibuilder.compile(verbose=True) -- cgit v1.2.3