diff --git a/daemon/main.c b/daemon/main.c index 8d8663332..43c1440f2 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -287,7 +287,8 @@ static void if_add_alias(intf_config_q *q, const str *name, const char *alias) { static bool if_add(intf_config_q *q, struct ifaddrs *ifas, const str *name, const char *address, const char *adv_addr, - unsigned int port_min, unsigned int port_max) + unsigned int port_min, unsigned int port_max, + GList *exclud) { GQueue addrs = G_QUEUE_INIT; @@ -338,6 +339,7 @@ static bool if_add(intf_config_q *q, struct ifaddrs *ifas, const str *name, ifa->advertised_address.type = ifa->local_address.type; ifa->port_min = port_min; ifa->port_max = port_max; + ifa->exclude_ports = exclud; // handle "base:suffix" separation for round-robin selection ifa->name_rr_spec = ifa->name; @@ -384,12 +386,26 @@ static void add_if_from_config(const char *name, charp_ht ht, struct interface_c die("Invalid 'port-max' for interface '%s'", name); } + GList *exclud = NULL; + p = t_hash_table_lookup(ht, "exclude-ports"); + if (p) { + str s = STR(p); + str t; + while (str_token_sep(&t, &s, ';')) { + int pn = str_to_i(&t, 0); + if (!pn) + die("Invalid port in 'exclude-ports': '" STR_FORMAT "'", STR_FMT(&t)); + + exclud = g_list_prepend(exclud, GUINT_TO_POINTER(pn)); + } + } + const char *orig_name = name; char *n2 = t_hash_table_lookup(ht, "name"); if (n2) name = n2; - if (!if_add(icca->icq, icca->ifas, STR_PTR(name), address, adv_addr, port_min, port_max)) + if (!if_add(icca->icq, icca->ifas, STR_PTR(name), address, adv_addr, port_min, port_max, exclud)) die("Failed to parse interface information '%s' from config file", orig_name); } @@ -421,7 +437,7 @@ static bool if_addr_parse(intf_config_q *q, char *s, struct ifaddrs *ifas) { if (c) *c++ = 0; - return if_add(q, ifas, &name, s, c, rtpe_config.port_min, rtpe_config.port_max); + return if_add(q, ifas, &name, s, c, rtpe_config.port_min, rtpe_config.port_max, NULL); } diff --git a/daemon/media_socket.c b/daemon/media_socket.c index 83cf763ae..c20362547 100644 --- a/daemon/media_socket.c +++ b/daemon/media_socket.c @@ -835,6 +835,17 @@ static void __interface_append(struct intf_config *ifa, sockfamily_t *fam, bool /* pre-fill the range of used ports */ __append_free_ports_to_int(spec); + for (GList *l = ifa->exclude_ports; l; l = l->next) { + unsigned int port = GPOINTER_TO_UINT(l->data); + if (port > 65535) + continue; + ports_list *ll = spec->port_pool.free_ports[port]; + if (ll) { + reserve_port(&spec->port_pool, ll); + t_list_free(ll); + } + } + t_hash_table_insert(__intf_spec_addr_type_hash, &spec->local_address, spec); } else { diff --git a/docs/rtpengine.md b/docs/rtpengine.md index d0cea1879..d91f27333 100644 --- a/docs/rtpengine.md +++ b/docs/rtpengine.md @@ -1695,10 +1695,12 @@ default name extracted from the name of the config section. Non-alias interfaces support the additional option __advertised__ to set the advertised address, as well as __port-min__ and __port-max__ to set a port -range different from the global setting. Note that all interfaces sharing a -single IP address must use the same port range. Round-robin interface usage is -supported in the same way as described above, i.e. by using a colon and a -suffix as part of the interface name. +range different from the global setting, and __exclude-ports__ taking a list of +semicolon-separated port numbers to exclude individual ports from the port +range. Note that all interfaces sharing a single IP address must use the same +port range. Round-robin interface usage is supported in the same way as +described above, i.e. by using a colon and a suffix as part of the interface +name. Interface sections are processed in order, and as such the first one listed becomes the default interface. If both legacy syntax and new configuration-file @@ -1741,6 +1743,7 @@ A complete example: address = enp35s0 port-min = 10000 port-max = 59999 + exclude-ports = 20000; 20001; 20002 # Create an alias interface "virt" pointing to "external". [interface-virt] @@ -1750,6 +1753,7 @@ A complete example: # by referring to the interface "rr". [interface-rr:0] address = enp5p0 + exclude-ports = 29999 [interface-rr:1] address = enp15p0 diff --git a/etc/rtpengine.conf b/etc/rtpengine.conf index ac4737aa5..a960cda28 100644 --- a/etc/rtpengine.conf +++ b/etc/rtpengine.conf @@ -185,6 +185,7 @@ address = any # name = default # port-min = 30000 # port-max = 39999 +# exclude-ports = 31111 ; 32222 ; 33333 [rtpengine-testing] table = -1 diff --git a/include/media_socket.h b/include/media_socket.h index 1ee808e04..cfd45b030 100644 --- a/include/media_socket.h +++ b/include/media_socket.h @@ -115,6 +115,7 @@ struct intf_config { struct intf_address local_address; struct intf_address advertised_address; unsigned int port_min, port_max; + GList *exclude_ports; }; struct intf_spec { struct intf_address local_address;