Add Osmux IPv6 support

A new osmux bind-ip-v6 VTY command is added, similar to what's already
available for RTP. This way the user can decide whether to support IPv4,
IPv6 or both types of IP versions.

Both IP sockets are by default disabled, and must be explicitly enabled
by setting the bind-ip in the VTY configuration.

Change-Id: I446cd7da217e9f4a74995d7784ae55dcc60a29b7
This commit is contained in:
Pau Espin 2022-10-04 16:49:41 +02:00
parent e56ec4a146
commit 70c03f5e44
6 changed files with 99 additions and 42 deletions

View File

@ -160,7 +160,8 @@ struct mgcp_config {
/* Osmux usage policy: */
enum osmux_usage osmux_use;
/* addr to bind the server to */
char osmux_addr[INET6_ADDRSTRLEN];
char *osmux_addr_v4;
char *osmux_addr_v6;
/* The BSC-NAT may ask for enabling osmux on demand. This tells us if
* the osmux socket is already initialized.
*/

View File

@ -157,7 +157,7 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
struct mgcp_rtp_state *state,
struct mgcp_rtp_end *rtp_end,
struct osmo_sockaddr *addr, struct msgb *msg);
void mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn);
int mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn);
/* payload processing default functions */
int mgcp_rtp_processing_default(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end,

View File

@ -81,12 +81,13 @@ bool mgcp_rtp_end_remote_addr_available(const struct mgcp_rtp_end *rtp_end)
/*! Determine the local rtp bind IP-address.
* \param[out] addr caller provided memory to store the resulting IP-Address.
* \param[in] endp mgcp endpoint, that holds a copy of the VTY parameters.
* \ returns 0 on success, -1 if no local address could be provided.
*
* The local bind IP-address is automatically selected by probing the
* IP-Address of the interface that is pointing towards the remote IP-Address,
* if no remote IP-Address is known yet, the statically configured
* IP-Addresses are used as fallback. */
void mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn)
int mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn)
{
struct mgcp_endpoint *endp;
@ -99,12 +100,30 @@ void mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn)
/* Osmux: No smart IP addresses allocation is supported yet. Simply
* return the one set in VTY config: */
if (mgcp_conn_rtp_is_osmux(conn)) {
bind_addr = conn->conn->endp->trunk->cfg->osmux_addr;
LOGPCONN(conn->conn, DRTP, LOGL_DEBUG,
"using configured osmux bind ip as local bind ip %s\n",
if (rem_addr_set) {
/* Match IP version with what was requested from remote: */
bind_addr = conn->end.addr.u.sa.sa_family == AF_INET6 ?
conn->conn->endp->trunk->cfg->osmux_addr_v6 :
conn->conn->endp->trunk->cfg->osmux_addr_v4;
} else {
/* Choose any of the bind addresses, preferring v6 over v4 if available: */
bind_addr = conn->conn->endp->trunk->cfg->osmux_addr_v6;
if (!bind_addr)
bind_addr = conn->conn->endp->trunk->cfg->osmux_addr_v4;
}
if (!bind_addr) {
LOGPCONN(conn->conn, DOSMUX, LOGL_ERROR,
"Unable to locate local Osmux address, check your configuration! v4=%u v6=%u remote_known=%s\n",
!!conn->conn->endp->trunk->cfg->osmux_addr_v4,
!!conn->conn->endp->trunk->cfg->osmux_addr_v6,
rem_addr_set ? osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf) : "no");
return -1;
}
LOGPCONN(conn->conn, DOSMUX, LOGL_DEBUG,
"Using configured osmux bind ip as local bind ip %s\n",
bind_addr);
osmo_strlcpy(addr, bind_addr, INET6_ADDRSTRLEN);
return;
return 0;
}
/* Try probing the local IP-Address */
@ -117,7 +136,7 @@ void mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn)
LOGPCONN(conn->conn, DRTP, LOGL_DEBUG,
"selected local rtp bind ip %s by probing using remote ip %s\n",
addr, osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf));
return;
return 0;
}
}
@ -147,6 +166,7 @@ void mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn)
"using mgcp bind ip as local rtp bind ip: %s\n", bind_addr);
}
osmo_strlcpy(addr, bind_addr, INET6_ADDRSTRLEN);
return 0;
}
/* This does not need to be a precision timestamp and

View File

@ -30,7 +30,8 @@
#include <osmocom/mgcp/mgcp_endp.h>
#include <osmocom/mgcp/mgcp_trunk.h>
static struct osmo_fd osmux_fd;
static struct osmo_fd osmux_fd_v4;
static struct osmo_fd osmux_fd_v6;
static LLIST_HEAD(osmux_handle_list);
@ -76,20 +77,22 @@ static void osmux_deliver_cb(struct msgb *batch_msg, void *data)
{
struct osmux_handle *handle = data;
socklen_t dest_len;
int rc;
struct mgcp_trunk *trunk = (struct mgcp_trunk *)osmux_fd.data;
int rc, fd;
struct mgcp_trunk *trunk = (struct mgcp_trunk *)osmux_fd_v4.data;
struct rate_ctr_group *all_osmux_stats = trunk->ratectr.all_osmux_conn_stats;
switch (handle->rem_addr.u.sa.sa_family) {
case AF_INET6:
dest_len = sizeof(handle->rem_addr.u.sin6);
fd = osmux_fd_v6.fd;
break;
case AF_INET:
default:
dest_len = sizeof(handle->rem_addr.u.sin);
fd = osmux_fd_v4.fd;
break;
}
rc = sendto(osmux_fd.fd, batch_msg->data, batch_msg->len, 0,
rc = sendto(fd, batch_msg->data, batch_msg->len, 0,
(struct sockaddr *)&handle->rem_addr.u.sa, dest_len);
if (rc < 0) {
char errbuf[129];
@ -187,11 +190,6 @@ osmux_handle_find_or_create(struct mgcp_conn_rtp *conn, const struct osmo_sockad
{
struct osmux_handle *h;
if (rem_addr->u.sa.sa_family != AF_INET) {
LOGP(DOSMUX, LOGL_DEBUG, "IPv6 not supported in osmux yet!\n");
return NULL;
}
h = osmux_handle_find_get(rem_addr);
if (h != NULL)
return h->in;
@ -450,27 +448,46 @@ int osmux_init(int role, struct mgcp_trunk *trunk)
/* So far we only support running on one trunk: */
OSMO_ASSERT(trunk == mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID));
osmo_fd_setup(&osmux_fd, -1, OSMO_FD_READ, osmux_read_fd_cb, trunk, 0);
osmo_fd_setup(&osmux_fd_v4, -1, OSMO_FD_READ, osmux_read_fd_cb, trunk, 0);
osmo_fd_setup(&osmux_fd_v6, -1, OSMO_FD_READ, osmux_read_fd_cb, trunk, 0);
ret = mgcp_create_bind(cfg->osmux_addr, &osmux_fd, cfg->osmux_port,
cfg->endp_dscp, cfg->endp_priority);
if (ret < 0) {
LOGP(DOSMUX, LOGL_ERROR, "cannot bind OSMUX socket to %s:%u\n",
cfg->osmux_addr, cfg->osmux_port);
return ret;
if (cfg->osmux_addr_v4) {
ret = mgcp_create_bind(cfg->osmux_addr_v4, &osmux_fd_v4, cfg->osmux_port,
cfg->endp_dscp, cfg->endp_priority);
if (ret < 0) {
LOGP(DOSMUX, LOGL_ERROR, "Cannot bind OSMUX IPv4 socket to %s:%u\n",
cfg->osmux_addr_v4, cfg->osmux_port);
return ret;
}
ret = osmo_fd_register(&osmux_fd_v4);
if (ret < 0) {
LOGP(DOSMUX, LOGL_ERROR, "Cannot register OSMUX IPv4 socket %s\n",
osmo_sock_get_name2(osmux_fd_v4.fd));
return ret;
}
LOGP(DOSMUX, LOGL_INFO, "OSMUX IPv4 socket listening on %s\n",
osmo_sock_get_name2(osmux_fd_v4.fd));
}
if (cfg->osmux_addr_v6) {
ret = mgcp_create_bind(cfg->osmux_addr_v6, &osmux_fd_v6, cfg->osmux_port,
cfg->endp_dscp, cfg->endp_priority);
if (ret < 0) {
LOGP(DOSMUX, LOGL_ERROR, "Cannot bind OSMUX IPv6 socket to %s:%u\n",
cfg->osmux_addr_v6, cfg->osmux_port);
return ret;
}
ret = osmo_fd_register(&osmux_fd);
if (ret < 0) {
LOGP(DOSMUX, LOGL_ERROR, "cannot register OSMUX socket %s\n",
osmo_sock_get_name2(osmux_fd.fd));
return ret;
ret = osmo_fd_register(&osmux_fd_v6);
if (ret < 0) {
LOGP(DOSMUX, LOGL_ERROR, "Cannot register OSMUX IPv6 socket %s\n",
osmo_sock_get_name2(osmux_fd_v6.fd));
return ret;
}
LOGP(DOSMUX, LOGL_INFO, "OSMUX IPv6 socket listening on %s\n",
osmo_sock_get_name2(osmux_fd_v6.fd));
}
cfg->osmux_initialized = true;
LOGP(DOSMUX, LOGL_INFO, "OSMUX socket listening on %s\n",
osmo_sock_get_name2(osmux_fd.fd));
return 0;
}
@ -647,7 +664,7 @@ int osmux_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf),
osmo_sockaddr_port(&conn->end.addr.u.sa), conn->osmux.remote_cid);
return mgcp_udp_send(osmux_fd.fd, &conn->end.addr, (char *)osmuxh, buf_len);
return mgcp_udp_send(osmux_fd_v4.fd, &conn->end.addr, (char *)osmuxh, buf_len);
}
/* bsc-nat allocates/releases the Osmux circuit ID. +7 to round up to 8 bit boundary. */

View File

@ -1067,7 +1067,10 @@ mgcp_header_done:
/* Find a local address for conn based on policy and initial SDP remote
information, then find a free port for it */
mgcp_get_local_addr(conn->end.local_addr, conn);
if (mgcp_get_local_addr(conn->end.local_addr, conn) < 0) {
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_BIND_PORT));
goto error2;
}
if (allocate_port(endp, conn) != 0) {
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_BIND_PORT));
goto error2;
@ -1279,7 +1282,10 @@ mgcp_header_done:
to update our announced IP addr and re-bind our local end. This can
happen for instance if MGW initially provided an IPv4 during CRCX
ACK, and now MDCX tells us the remote has an IPv6 address. */
mgcp_get_local_addr(new_local_addr, conn);
if (mgcp_get_local_addr(new_local_addr, conn) < 0) {
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_BIND_PORT));
goto error3;
}
if (strcmp(new_local_addr, conn->end.local_addr)) {
osmo_strlcpy(conn->end.local_addr, new_local_addr, sizeof(conn->end.local_addr));
mgcp_free_rtp_port(&conn->end);
@ -1627,7 +1633,6 @@ struct mgcp_config *mgcp_config_alloc(void)
cfg->source_port = 2427;
osmo_strlcpy(cfg->source_addr, "0.0.0.0", sizeof(cfg->source_addr));
osmo_strlcpy(cfg->osmux_addr, "0.0.0.0", sizeof(cfg->osmux_addr));
cfg->rtp_processing_cb = &mgcp_rtp_processing_default;
cfg->setup_rtp_processing_cb = &mgcp_setup_rtp_processing_default;

View File

@ -142,8 +142,12 @@ static int config_write_mgcp(struct vty *vty)
break;
}
if (g_cfg->osmux_use != OSMUX_USAGE_OFF) {
vty_out(vty, " osmux bind-ip %s%s",
g_cfg->osmux_addr, VTY_NEWLINE);
if (g_cfg->osmux_addr_v4)
vty_out(vty, " osmux bind-ip %s%s",
g_cfg->osmux_addr_v4, VTY_NEWLINE);
if (g_cfg->osmux_addr_v6)
vty_out(vty, " osmux bind-ip-v6 %s%s",
g_cfg->osmux_addr_v6, VTY_NEWLINE);
vty_out(vty, " osmux batch-factor %d%s",
g_cfg->osmux_batch, VTY_NEWLINE);
vty_out(vty, " osmux batch-size %u%s",
@ -1584,12 +1588,21 @@ DEFUN(cfg_mgcp_osmux,
DEFUN(cfg_mgcp_osmux_ip,
cfg_mgcp_osmux_ip_cmd,
"osmux bind-ip " VTY_IPV46_CMD,
"osmux bind-ip " VTY_IPV4_CMD,
OSMUX_STR IP_STR
"IPv4 Address to bind to\n")
{
osmo_talloc_replace_string(g_cfg, &g_cfg->osmux_addr_v4, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_mgcp_osmux_ip_v6,
cfg_mgcp_osmux_ip_v6_cmd,
"osmux bind-ip-v6 " VTY_IPV6_CMD,
OSMUX_STR IP_STR
"IPv4 Address to bind to\n"
"IPv6 Address to bind to\n")
{
osmo_strlcpy(g_cfg->osmux_addr, argv[0], sizeof(g_cfg->osmux_addr));
osmo_talloc_replace_string(g_cfg, &g_cfg->osmux_addr_v6, argv[0]);
return CMD_SUCCESS;
}
@ -1718,6 +1731,7 @@ int mgcp_vty_init(void)
install_element(MGCP_NODE, &cfg_mgcp_no_sdp_payload_send_name_cmd);
install_element(MGCP_NODE, &cfg_mgcp_osmux_cmd);
install_element(MGCP_NODE, &cfg_mgcp_osmux_ip_cmd);
install_element(MGCP_NODE, &cfg_mgcp_osmux_ip_v6_cmd);
install_element(MGCP_NODE, &cfg_mgcp_osmux_batch_factor_cmd);
install_element(MGCP_NODE, &cfg_mgcp_osmux_batch_size_cmd);
install_element(MGCP_NODE, &cfg_mgcp_osmux_port_cmd);