Browse Source

MT#55283 Add inbound-peer, outbound-peer and peer flags for automatic interface selection

Introduce three new NG protocol flags that automatically select the matching
configured rtpengine interface based on the system's routing table:

- inbound-peer=<ip>: resolves to interface for inbound (from) direction
- outbound-peer=<ip>: resolves to interface for outbound (to) direction
- peer=<ip> resolves to interface when only one interface is required

When these flags are used, the system:
- Uses a temporary UDP socket to determine the local address assigned by routing
- Finds the first configured rtpengine interface matching that local address
- Uses that interface for the media stream

This allows dynamic interface selection based on network topology without
requiring explicit interface names in the signaling.

Closes #2033

Change-Id: I211806b9cef9d028fdb689d90ea3fe627bdf5d0d
pull/2035/head
Matteo Brancaleoni 1 week ago
committed by Richard Fuchs
parent
commit
e9fd1f89e3
4 changed files with 92 additions and 1 deletions
  1. +20
    -0
      daemon/call_interfaces.c
  2. +48
    -1
      daemon/media_socket.c
  3. +23
    -0
      docs/ng_control_protocol.md
  4. +1
    -0
      include/media_socket.h

+ 20
- 0
daemon/call_interfaces.c View File

@ -1619,6 +1619,17 @@ static void call_ng_flags_freqs(const ng_parser_t *parser, parser_arg value, sdp
}
}
static void call_ng_flags_peer_address(const str *peer_ip, str *direction, const char *direction_text) {
const str *resolved = resolve_interface_from_peer_ip(peer_ip);
if (resolved) {
*direction = *resolved;
ilog(LOG_DEBUG, "%s peer " STR_FORMAT " resolved to interface " STR_FORMAT,
direction_text, STR_FMT(peer_ip), STR_FMT(resolved));
}
else
ilog(LOG_WARN, "Failed to resolve %s peer address " STR_FORMAT, direction_text, STR_FMT(peer_ip));
}
static void call_ng_received_from_string(sdp_ng_flags *flags, str *s) {
flags->received_from_family = STR_NULL;
flags->received_from_address = *s;
@ -1964,6 +1975,9 @@ void call_ng_main_flags(const ng_parser_t *parser, str *key, parser_arg value, h
case CSH_LOOKUP("from-interface"):
out->direction[0] = s;
break;
case CSH_LOOKUP("inbound-peer"):
call_ng_flags_peer_address(&s, &out->direction[0], "Inbound");
break;
case CSH_LOOKUP("from-label"):
case CSH_LOOKUP("label"):
out->label = s;
@ -2047,6 +2061,9 @@ void call_ng_main_flags(const ng_parser_t *parser, str *key, parser_arg value, h
case CSH_LOOKUP("interface"):
out->interface = s;
break;
case CSH_LOOKUP("peer"):
call_ng_flags_peer_address(&s, &out->interface, "Interface");
break;
case CSH_LOOKUP("instance"):
out->instance = s;
break;
@ -2312,6 +2329,9 @@ void call_ng_main_flags(const ng_parser_t *parser, str *key, parser_arg value, h
case CSH_LOOKUP("to-interface"):
out->direction[1] = s;
break;
case CSH_LOOKUP("outbound-peer"):
call_ng_flags_peer_address(&s, &out->direction[1], "Outbound");
break;
case CSH_LOOKUP("to-label"):
out->to_label = s;
break;


+ 48
- 1
daemon/media_socket.c View File

@ -45,7 +45,6 @@
#define MAX_RECV_LOOP_STRIKES 5
#endif
TYPED_GQUEUE(logical_intf, struct logical_intf)
struct intf_key {
@ -4115,3 +4114,51 @@ struct interface_stats_block *interface_sampled_rate_stats_get(struct interface_
ret->last_run = rtpe_now;
return &ret->stats;
}
/* Resolve peer IP address to interface name via routing lookup.
* Returns pointer to interface name (valid for lifetime of interface config) or NULL on error.
*/
const str *resolve_interface_from_peer_ip(const str *peer_ip) {
if (!peer_ip || !peer_ip->s || !peer_ip->len) {
ilog(LOG_ERR, "Empty peer IP address");
return NULL;
}
sockaddr_t target;
if (!sockaddr_parse_any_str(&target, peer_ip)) {
ilog(LOG_ERR, "Invalid peer IP address: " STR_FORMAT ": %s",
STR_FMT(peer_ip), strerror(errno));
return NULL;
}
/* create probe socket and connect to target.
* port 9 (discard) is used as dummy - actual port doesn't affect routing */
socket_t sock;
ZERO(sock);
endpoint_t ep = { .address = target, .port = 9 };
if (!connect_socket(&sock, SOCK_DGRAM, &ep)) {
ilog(LOG_ERR, "Failed to create probe socket for peer IP: %s",
strerror(errno));
return NULL;
}
/* get local address assigned by kernel routing */
if (!socket_getsockname(&sock)) {
close_socket(&sock);
ilog(LOG_ERR, "getsockname failed for peer IP: %s", strerror(errno));
return NULL;
}
sockaddr_t local_addr = sock.local.address;
close_socket(&sock);
/* find first matching interface (loop preserves config ordering) */
for (__auto_type l = all_local_interfaces.head; l; l = l->next) {
struct local_intf *lif = l->data;
if (sockaddr_eq(&local_addr, &lif->spec->local_address.addr))
return &lif->logical->name;
}
ilog(LOG_ERR, "No configured interface found for peer-resolved address %s",
sockaddr_print_buf(&local_addr));
return NULL;
}

+ 23
- 0
docs/ng_control_protocol.md View File

@ -381,6 +381,14 @@ Optionally included keys are:
"received from" direction of this message. Identical to setting the first
`direction=` value.
* `inbound-peer`
Contains an IP address (IPv4 or IPv6) of the peer from which media will be
received. RTPengine performs a routing table lookup to determine which local
interface would be used to reach this peer, and uses that interface for the
inbound direction. Equivalent to setting `from-interface` with the resolved
interface name.
* `frequency` or `frequencies`
Sets the tone frequency or frequencies for `DTMF-security=tone` in Hertz.
@ -457,6 +465,13 @@ Optionally included keys are:
`interface` option is used instead of `direction` where only one interface is required (e.g. outside
of an offer/answer scenario), for example in the `publish` or `subscribe request` commands.
* `peer`
Contains an IP address (IPv4 or IPv6) of a peer. RTPengine performs a routing
table lookup to determine which local interface would be used to reach this peer,
and uses that interface for the call. Equivalent to setting `interface` with the
resolved interface name.
* `label` or `from-label`
A custom free-form string which *rtpengine* remembers for this participating endpoint and reports
@ -797,6 +812,14 @@ Optionally included keys are:
"going to" direction of this message. Identical to setting the second
`direction=` value.
* `outbound-peer`
Contains an IP address (IPv4 or IPv6) of the peer to which media will be
sent. RTPengine performs a routing table lookup to determine which local
interface would be used to reach this peer, and uses that interface for the
outbound direction. Equivalent to setting `to-interface` with the resolved
interface name.
* `to-label`
Commands that allow selection of two call participants (e.g. `block


+ 1
- 0
include/media_socket.h View File

@ -389,6 +389,7 @@ struct local_intf *get_interface_address(const struct logical_intf *lif, sockfam
struct local_intf *get_any_interface_address(const struct logical_intf *lif, sockfamily_t *fam);
void interfaces_exclude_port(endpoint_t *);
bool is_local_endpoint(const struct intf_address *addr, unsigned int port);
const str *resolve_interface_from_peer_ip(const str *peer_ip);
struct socket_port_link get_specific_port(unsigned int port,
struct intf_spec *spec, const str *label);


Loading…
Cancel
Save