Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package ubridge for openSUSE:Factory checked in at 2026-09-08 16:54:03 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/ubridge (Old) and /work/SRC/openSUSE:Factory/.ubridge.new.1265 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "ubridge" Tue Sep 8 16:54:03 2026 rev:8 rq:1376085 version:1.2.3 Changes: -------- --- /work/SRC/openSUSE:Factory/ubridge/ubridge.changes 2026-09-04 12:39:44.426173544 +0200 +++ /work/SRC/openSUSE:Factory/.ubridge.new.1265/ubridge.changes 2026-09-08 16:55:05.486415127 +0200 @@ -1,0 +2,6 @@ +Sun Sep 6 16:36:58 UTC 2026 - Martin Hauke <[email protected]> + +- Update to version 1.2.3 + * feat: Add TAP carrier control support. + +------------------------------------------------------------------- Old: ---- ubridge-1.2.2.tar.gz New: ---- ubridge-1.2.3.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ ubridge.spec ++++++ --- /var/tmp/diff_new_pack.W5QtSu/_old 2026-09-08 16:55:06.268447376 +0200 +++ /var/tmp/diff_new_pack.W5QtSu/_new 2026-09-08 16:55:06.271447499 +0200 @@ -17,7 +17,7 @@ Name: ubridge -Version: 1.2.2 +Version: 1.2.3 Release: 0 Summary: Bridging between UDP tunnels, Ethernet and TAP interfaces License: GPL-3.0-only ++++++ ubridge-1.2.2.tar.gz -> ubridge-1.2.3.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ubridge-1.2.2/README.md new/ubridge-1.2.3/README.md --- old/ubridge-1.2.2/README.md 2026-08-31 12:02:31.000000000 +0200 +++ new/ubridge-1.2.3/README.md 2026-09-04 20:17:34.000000000 +0200 @@ -120,7 +120,8 @@ 101 start_capture (min/max args: 2/3) 101 add_nio_linux_raw (min/max args: 2/2) 101 add_nio_ethernet (min/max args: 2/2) -101 add_nio_tap (min/max args: 2/2) +101 set_nio_tap_carrier (min/max args: 2/2) +101 add_nio_tap (min/max args: 2/3) 101 add_nio_unix (min/max args: 3/3) 101 delete_nio_udp (min/max args: 4/4) 101 remove_nio_udp (min/max args: 4/4) @@ -234,14 +235,24 @@ 100-NIO UNIX added to bridge 'br0' ``` -- **bridge add_nio_tap** *\<bridge_name\>* *\<tap_device\>*: - Add a TAP NIO to a bridge. TAP devices require root access. +- **bridge add_nio_tap** *\<bridge_name\>* *\<tap_device\>* *[on|off]*: + Add a TAP NIO to a bridge. TAP devices require root access. The optional + state controls the initial carrier state and defaults to `on`. ``` {.bash} bridge add_nio_tap br0 tap0 100-NIO TAP added to bridge 'br0' ``` +- **bridge set_nio_tap_carrier** *\<bridge_name\>* *\<on|off\>*: + Change the carrier state of a TAP NIO without changing its administrative + state. This can be used to emulate plugging or unplugging a cable. + +``` {.bash} +bridge set_nio_tap_carrier br0 off +100-TAP carrier set off on bridge 'br0' +``` + - **bridge add_nio_ethernet** *\<bridge_name\>* *\<eth_device\>*: Add a generic Ethernet NIO to a bridge, using PCAP (0.9.4 and greater). It requires root access. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ubridge-1.2.2/src/hypervisor_bridge.c new/ubridge-1.2.3/src/hypervisor_bridge.c --- old/ubridge-1.2.2/src/hypervisor_bridge.c 2026-08-31 12:02:31.000000000 +0200 +++ new/ubridge-1.2.3/src/hypervisor_bridge.c 2026-09-04 20:17:34.000000000 +0200 @@ -426,6 +426,7 @@ static int cmd_add_nio_tap(hypervisor_conn_t *conn, int argc, char *argv[]) { + int carrier = TRUE; nio_t *nio; bridge_t *bridge; @@ -435,7 +436,18 @@ return (-1); } - nio = create_nio_tap(argv[1]); + if (argc == 3) { + if (!strcmp(argv[2], "on")) + carrier = TRUE; + else if (!strcmp(argv[2], "off")) + carrier = FALSE; + else { + hypervisor_send_reply(conn, HSC_ERR_INV_PARAM, 1, "invalid TAP carrier state '%s'", argv[2]); + return (-1); + } + } + + nio = create_nio_tap_with_carrier(argv[1], carrier); if (!nio) { hypervisor_send_reply(conn, HSC_ERR_CREATE, 1, "unable to create NIO TAP for bridge '%s'", argv[0]); return (-1); @@ -452,6 +464,47 @@ return (0); } +static int cmd_set_nio_tap_carrier(hypervisor_conn_t *conn, int argc, char *argv[]) +{ + int carrier; + nio_t *nio = NULL; + bridge_t *bridge; + + bridge = find_bridge(argv[0]); + if (bridge == NULL) { + hypervisor_send_reply(conn, HSC_ERR_NOT_FOUND, 1, "bridge '%s' doesn't exist", argv[0]); + return (-1); + } + + if (!strcmp(argv[1], "on")) + carrier = TRUE; + else if (!strcmp(argv[1], "off")) + carrier = FALSE; + else { + hypervisor_send_reply(conn, HSC_ERR_INV_PARAM, 1, "invalid TAP carrier state '%s'", argv[1]); + return (-1); + } + + if (bridge->source_nio && bridge->source_nio->type == NIO_TYPE_TAP) + nio = bridge->source_nio; + else if (bridge->destination_nio && bridge->destination_nio->type == NIO_TYPE_TAP) + nio = bridge->destination_nio; + + if (nio == NULL) { + hypervisor_send_reply(conn, HSC_ERR_NOT_FOUND, 1, "bridge '%s' has no TAP NIO", argv[0]); + return (-1); + } + + if (nio_tap_set_carrier(nio, carrier) < 0) { + hypervisor_send_reply(conn, HSC_ERR_CREATE, 1, "unable to set TAP carrier %s on bridge '%s': %s", + argv[1], argv[0], strerror(errno)); + return (-1); + } + + hypervisor_send_reply(conn, HSC_INFO_OK, 1, "TAP carrier set %s on bridge '%s'", argv[1], argv[0]); + return (0); +} + static int cmd_add_nio_ethernet(hypervisor_conn_t *conn, int argc, char *argv[]) { nio_t *nio; @@ -697,7 +750,8 @@ { "remove_nio_udp", 4, 4, cmd_delete_nio_udp, NULL }, /* kept for compatibility */ { "delete_nio_udp", 4, 4, cmd_delete_nio_udp, NULL }, { "add_nio_unix", 3, 3, cmd_add_nio_unix, NULL }, - { "add_nio_tap", 2, 2, cmd_add_nio_tap, NULL }, + { "add_nio_tap", 2, 3, cmd_add_nio_tap, NULL }, + { "set_nio_tap_carrier", 2, 2, cmd_set_nio_tap_carrier, NULL }, { "add_nio_ethernet", 2, 2, cmd_add_nio_ethernet, NULL }, { "add_nio_linux_raw", 2, 2, cmd_add_nio_linux_raw, NULL }, { "start_capture", 2, 3, cmd_start_capture_bridge, NULL }, @@ -722,4 +776,3 @@ hypervisor_register_cmd_array(module, bridge_cmd_array); return(0); } - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ubridge-1.2.2/src/nio_tap.c new/ubridge-1.2.3/src/nio_tap.c --- old/ubridge-1.2.2/src/nio_tap.c 2026-08-31 12:02:31.000000000 +0200 +++ new/ubridge-1.2.3/src/nio_tap.c 2026-09-04 20:17:34.000000000 +0200 @@ -34,7 +34,7 @@ /* Open a TAP device */ -static int nio_tap_open(char *tap_devname) +static int nio_tap_open(char *tap_devname, int carrier) { struct ifreq ifr; int err, fd; @@ -66,6 +66,10 @@ memset(&ifr,0,sizeof(ifr)); ifr.ifr_flags = IFF_TAP | IFF_NO_PI; +#ifdef IFF_NO_CARRIER + if (!carrier) + ifr.ifr_flags |= IFF_NO_CARRIER; +#endif if (*tap_devname) strncpy(ifr.ifr_name, tap_devname, IFNAMSIZ); @@ -76,6 +80,13 @@ strcpy(tap_devname, ifr.ifr_name); } + + if (!carrier && ioctl(fd, TUNSETCARRIER, &carrier) < 0) { + err = errno; + close(fd); + errno = err; + return(-1); + } return(fd); } @@ -96,7 +107,7 @@ } /* Create a new NIO TAP */ -nio_t *create_nio_tap(char *tap_name) +nio_t *create_nio_tap_with_carrier(char *tap_name, int carrier) { nio_tap_t *nio_tap; nio_t *nio; @@ -113,7 +124,7 @@ } memset(nio_tap, 0, sizeof(*nio_tap)); - nio_tap->fd = nio_tap_open(tap_name); + nio_tap->fd = nio_tap_open(tap_name, carrier); if (nio_tap->fd == -1) { fprintf(stderr,"create_nio_tap: unable to open TAP device %s (%s)\n", tap_name, strerror(errno)); @@ -128,3 +139,19 @@ nio->dptr = &nio->u.nio_tap; return nio; } + +nio_t *create_nio_tap(char *tap_name) +{ + return create_nio_tap_with_carrier(tap_name, TRUE); +} + +int nio_tap_set_carrier(nio_t *nio, int carrier) +{ + if (nio == NULL || nio->type != NIO_TYPE_TAP) { + errno = EINVAL; + return(-1); + } + + carrier = carrier ? 1 : 0; + return ioctl(nio->u.nio_tap.fd, TUNSETCARRIER, &carrier); +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ubridge-1.2.2/src/nio_tap.h new/ubridge-1.2.3/src/nio_tap.h --- old/ubridge-1.2.2/src/nio_tap.h 2026-08-31 12:02:31.000000000 +0200 +++ new/ubridge-1.2.3/src/nio_tap.h 2026-09-04 20:17:34.000000000 +0200 @@ -24,5 +24,7 @@ #include "nio.h" nio_t *create_nio_tap(char *tap_name); +nio_t *create_nio_tap_with_carrier(char *tap_name, int carrier); +int nio_tap_set_carrier(nio_t *nio, int carrier); #endif /* !NIO_TAP_H_ */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ubridge-1.2.2/src/ubridge.h new/ubridge-1.2.3/src/ubridge.h --- old/ubridge-1.2.2/src/ubridge.h 2026-08-31 12:02:31.000000000 +0200 +++ new/ubridge-1.2.3/src/ubridge.h 2026-09-04 20:17:34.000000000 +0200 @@ -31,7 +31,7 @@ #include "packet_filter.h" #define NAME "ubridge" -#define VERSION "1.2.2" +#define VERSION "1.2.3" #define CONFIG_FILE "ubridge.ini" #ifndef FALSE diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ubridge-1.2.2/tests/tap/run_all.py new/ubridge-1.2.3/tests/tap/run_all.py --- old/ubridge-1.2.2/tests/tap/run_all.py 2026-08-31 12:02:31.000000000 +0200 +++ new/ubridge-1.2.3/tests/tap/run_all.py 2026-09-04 20:17:34.000000000 +0200 @@ -4,6 +4,7 @@ SUITES = [ "test_basic", + "test_carrier", ] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ubridge-1.2.2/tests/tap/test_carrier.py new/ubridge-1.2.3/tests/tap/test_carrier.py --- old/ubridge-1.2.2/tests/tap/test_carrier.py 1970-01-01 01:00:00.000000000 +0100 +++ new/ubridge-1.2.3/tests/tap/test_carrier.py 2026-09-04 20:17:34.000000000 +0200 @@ -0,0 +1,77 @@ +"""Regression tests for TAP carrier control. Requires CAP_NET_ADMIN.""" + +import os +import subprocess +import sys + +sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "brctl")) +from common import Ubridge, Results # noqa: E402 + +PORT = 13031 +BRIDGE = "carrier-test" +TAP = "ubcarrier0" +DEFAULT_BRIDGE = "carrier-default-test" +DEFAULT_TAP = "ubcarrier1" + + +def _ip(*args): + return subprocess.run(["ip"] + list(args), capture_output=True, text=True) + + +def _carrier_for(tap=TAP): + try: + with open("/sys/class/net/%s/carrier" % tap, encoding="ascii") as stream: + return stream.read().strip() + except OSError: + return None + + +def main(): + r = Results() + + with Ubridge(port=PORT) as ub: + c = ub.connect() + try: + r.check("create bridge", c.code("bridge create %s" % BRIDGE) == "100") + r.check("set carrier without TAP rejected", + c.code("bridge set_nio_tap_carrier %s off" % BRIDGE) == "214") + r.check("invalid initial state rejected", + c.code("bridge add_nio_tap %s %s invalid" % (BRIDGE, TAP)) == "204") + r.check("add TAP with carrier off", + c.code("bridge add_nio_tap %s %s off" % (BRIDGE, TAP)) == "100") + r.check("bring TAP administratively up", + c.code("link set %s up" % TAP) == "100") + carrier = _carrier_for() + r.check("initial carrier is off", carrier == "0", "carrier=%r" % carrier) + r.check("set carrier on", + c.code("bridge set_nio_tap_carrier %s on" % BRIDGE) == "100") + carrier = _carrier_for() + r.check("carrier is on", carrier == "1", "carrier=%r" % carrier) + r.check("set carrier off", + c.code("bridge set_nio_tap_carrier %s off" % BRIDGE) == "100") + carrier = _carrier_for() + r.check("carrier is off", carrier == "0", "carrier=%r" % carrier) + r.check("invalid state rejected", + c.code("bridge set_nio_tap_carrier %s invalid" % BRIDGE) == "204") + + r.check("create default bridge", + c.code("bridge create %s" % DEFAULT_BRIDGE) == "100") + r.check("legacy add TAP defaults carrier on", + c.code("bridge add_nio_tap %s %s" % (DEFAULT_BRIDGE, DEFAULT_TAP)) == "100") + r.check("bring default TAP administratively up", + c.code("link set %s up" % DEFAULT_TAP) == "100") + default_carrier = _carrier_for(DEFAULT_TAP) + r.check("default carrier is on", default_carrier == "1", + "carrier=%r" % default_carrier) + finally: + c.send("bridge delete %s" % BRIDGE) + c.send("bridge delete %s" % DEFAULT_BRIDGE) + c.close() + _ip("link", "delete", TAP) + _ip("link", "delete", DEFAULT_TAP) + + return 0 if r.summary() else 1 + + +if __name__ == "__main__": + raise SystemExit(main())
