pespin has uploaded this change for review. ( https://gerrit.osmocom.org/c/libosmo-abis/+/38983?usp=email )
Change subject: WIP: ipaccess: Conver BSC OML & RSL link to use stream_srv ......................................................................
WIP: ipaccess: Conver BSC OML & RSL link to use stream_srv
This in turn allows running BSC Abis interfaces through io-uring backend, which should provide performance improvements when used.
TODO: Re-introduce the sign.delay Tx timer to fix issues with ancient nanoBTS.
TODO: Get rid of ipaccess_fd_cb() in osmo-bsc.git ipaccess-config by implementing its own e1i_line ipaccess driver there (due to many peculiarities: tcp/ipa cli instead of srv, different OML port).
Related: SYS#7063 Related: OS#5755 Related: OS#5756 Change-Id: Idf241c8f2fdb86d090d4132a9b316b7236402232 --- M include/osmocom/abis/ipaccess.h M src/input/ipaccess.c 2 files changed, 270 insertions(+), 333 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/libosmo-abis refs/changes/83/38983/1
diff --git a/include/osmocom/abis/ipaccess.h b/include/osmocom/abis/ipaccess.h index b1fe2c9..dbf8a64 100644 --- a/include/osmocom/abis/ipaccess.h +++ b/include/osmocom/abis/ipaccess.h @@ -5,6 +5,7 @@ #include <osmocom/gsm/protocol/ipaccess.h>
/* quick solution to get openBSC's ipaccess tools working. */ -extern int ipaccess_fd_cb(struct osmo_fd *bfd, unsigned int what); +// TODO: get rid of this.... used by osmo-bsc.git ipaccess-proxy and ipacess-config... +//extern int ipaccess_fd_cb(struct osmo_fd *bfd, unsigned int what);
#endif /* _OSMO_ABIS_IPACCESS_H */ diff --git a/src/input/ipaccess.c b/src/input/ipaccess.c index af6e39d..2a58de5 100644 --- a/src/input/ipaccess.c +++ b/src/input/ipaccess.c @@ -90,73 +90,20 @@ } }
-static int ipaccess_drop(struct osmo_fd *bfd, struct e1inp_line *line) -{ - int ret = 1; - struct e1inp_ts *e1i_ts = ipaccess_line_ts(bfd, line); - e1inp_line_get2(line, __func__); - - ipaccess_keepalive_fsm_cleanup(e1i_ts); - - /* Error case: we did not see any ID_RESP yet for this socket. */ - if (bfd->fd != -1) { - LOGPITS(e1i_ts, DLINP, LOGL_NOTICE, "Forcing socket shutdown\n"); - osmo_fd_unregister(bfd); - close(bfd->fd); - bfd->fd = -1; - switch (line->ops->cfg.ipa.role) { - case E1INP_LINE_R_BSC: - /* This is BSC code, ipaccess_drop() is only called for - accepted() sockets, hence the bfd holds a reference to - e1inp_line in ->data that needs to be released */ - OSMO_ASSERT(bfd->data == line); - bfd->data = NULL; - e1inp_line_put2(line, "ipa_bfd"); - break; - case E1INP_LINE_R_BTS: - /* BTS code: bfd->data contains pointer to struct - * ipa_client_conn. Leave it alive so it reconnects. - */ - break; - default: - break; - } - ret = -ENOENT; - } else { - LOGPITS(e1i_ts, DLINP, LOGL_ERROR, - "Forcing socket shutdown with no signal link set\n"); - } - - msgb_free(e1i_ts->pending_msg); - e1i_ts->pending_msg = NULL; - - /* e1inp_sign_link_destroy releases the socket descriptors for us. */ - if (line->ops->sign_link_down) - line->ops->sign_link_down(line); - - e1inp_line_put2(line, __func__); - return ret; -} - static void ipa_bsc_keepalive_write_server_cb(struct osmo_fsm_inst *fi, void *conn, struct msgb *msg) { - struct osmo_fd *bfd = (struct osmo_fd *)conn; - write(bfd->fd, msg->data, msg->len); - msgb_free(msg); + struct osmo_stream_srv *srv = (struct osmo_stream_srv *)conn; + osmo_stream_srv_send(srv, msg); }
static int ipa_bsc_keepalive_timeout_cb(struct osmo_fsm_inst *fi, void *data) { - struct osmo_fd *bfd = (struct osmo_fd *)data; - - if (bfd->fd == -1) - return 1; - - ipaccess_drop(bfd, (struct e1inp_line *)bfd->data); + struct osmo_stream_srv *srv = (struct osmo_stream_srv *)data; + osmo_stream_srv_destroy(srv); return 1; }
-static void ipaccess_bsc_keepalive_fsm_alloc(struct e1inp_ts *e1i_ts, struct osmo_fd *bfd, const char *id) +static void ipaccess_bsc_keepalive_fsm_alloc(struct e1inp_ts *e1i_ts, struct osmo_stream_srv *conn, const char *id) { struct e1inp_line *line = e1i_ts->line; struct osmo_fsm_inst *ka_fsm; @@ -165,7 +112,7 @@ if (!line->ipa_kap) return;
- ka_fsm = ipa_generic_conn_alloc_keepalive_fsm(tall_ipa_ctx, bfd, line->ipa_kap, id); + ka_fsm = ipa_generic_conn_alloc_keepalive_fsm(conn, conn, line->ipa_kap, id); e1i_ts->driver.ipaccess.ka_fsm = ka_fsm; if (!ka_fsm) { LOGPITS(e1i_ts, DLINP, LOGL_ERROR, "Failed to allocate IPA keepalive FSM\n"); @@ -250,22 +197,37 @@ return cli; }
-/* Returns -1 on error, and 0 or 1 on success. If -1 or 1 is returned, line has - * been released and should not be used anymore by the caller. */ -static int ipaccess_rcvmsg(struct e1inp_line *line, struct msgb *msg, - struct osmo_fd *bfd) +static inline struct osmo_stream_srv *ipaccess_bts_e1i_ts_stream_srv(const struct e1inp_ts *e1i_ts) { + OSMO_ASSERT(e1i_ts); + struct osmo_stream_srv *conn = e1i_ts->driver.ipaccess.fd.data; + /* conn may be NULL here, if we are called by user during sign_link_up() + * and hence before we finished to internally move the ipaccess conn under + * the proper final line/ts object. + */ + return conn; +} + +static int ipaccess_bsc_write_cb(struct e1inp_ts *e1i_ts); + +/* Returns -1 on error, and 0 or 1 on success. If -1 or 1 is returned, line has + * been released and should not be used anymore by the caller. + * msg is always freed upon return. + */ +static int ipaccess_bsc_rcvmsg(struct osmo_stream_srv *conn, struct msgb *msg) +{ + struct e1inp_ts *e1i_ts = osmo_stream_srv_get_data(conn); + struct e1inp_line *line = e1i_ts->line; + struct osmo_fd *bfd = &e1i_ts->driver.ipaccess.fd; struct tlv_parsed tlvp; uint8_t msg_type = *(msg->l2h); struct ipaccess_unit unit_data = {}; struct e1inp_sign_link *sign_link; char *unitid; int len, ret; - struct e1inp_ts *e1i_ts; struct osmo_fsm_inst *ka_fsm;
/* peek the pong for our keepalive fsm */ - e1i_ts = ipaccess_line_ts(bfd, line); ka_fsm = e1i_ts->driver.ipaccess.ka_fsm; if (ka_fsm && msg_type == IPAC_MSGT_PONG) ipa_keepalive_fsm_pong_received(ka_fsm); @@ -278,7 +240,7 @@ goto err; case 1: /* this is an IPA control message, skip further processing */ - return 0; + goto ret_skip; case 0: /* this is not an IPA control message, continue */ break; @@ -329,17 +291,16 @@ goto err; }
- ipaccess_bsc_keepalive_fsm_alloc(e1i_ts, bfd, "oml_bsc_to_bts"); + ipaccess_bsc_keepalive_fsm_alloc(e1i_ts, conn, "oml_bsc_to_bts");
} else if (bfd->priv_nr == E1INP_SIGN_RSL) { - struct e1inp_ts *ts; + struct e1inp_ts *new_ts; struct osmo_fd *newbfd; struct e1inp_line *new_line; char tcp_stat_name[64];
sign_link = - line->ops->sign_link_up(&unit_data, line, - E1INP_SIGN_RSL); + line->ops->sign_link_up(&unit_data, line, E1INP_SIGN_RSL); if (sign_link == NULL) { LOGPIL(line, DLINP, LOGL_ERROR, "Unable to set signal link, closing socket.\n"); goto err; @@ -352,37 +313,35 @@ if (new_line == line) { LOGPIL(line, DLINP, LOGL_ERROR, "Fix your BSC, you should use the " "E1 line used by the OML link for your RSL link.\n"); - return 0; + goto ret_skip; } + + /* Attach srv_conn to new line+ts: */ e1inp_line_get2(new_line, "ipa_bfd"); - ts = e1inp_line_ipa_rsl_ts(new_line, unit_data.trx_id); - newbfd = &ts->driver.ipaccess.fd; + new_ts = e1inp_line_ipa_rsl_ts(new_line, unit_data.trx_id); + newbfd = &new_ts->driver.ipaccess.fd; OSMO_ASSERT(newbfd != bfd); + osmo_fd_setup(newbfd, bfd->fd, 0, NULL, conn, E1INP_SIGN_RSL + unit_data.trx_id); + osmo_stream_srv_set_data(conn, new_ts);
- /* preserve 'newbfd->when' flags potentially set by sign_link_up() */ - osmo_fd_setup(newbfd, bfd->fd, newbfd->when | bfd->when, bfd->cb, - new_line, E1INP_SIGN_RSL + unit_data.trx_id); - - - /* now we can release the dummy RSL line (old temporary bfd). */ - osmo_fd_unregister(bfd); + /* Now we can release the old temporar ydummy RSL line+ts: */ bfd->fd = -1; - /* bfd->data holds a reference to line, drop it */ - OSMO_ASSERT(bfd->data == line); + /* conn holds a reference to old line, drop it */ + OSMO_ASSERT(bfd->data == conn); bfd->data = NULL; e1inp_line_put2(line, "ipa_bfd");
- ret = osmo_fd_register(newbfd); - if (ret < 0) { - LOGPITS(ts, DLINP, LOGL_ERROR, "could not register FD\n"); - goto err; - } snprintf(tcp_stat_name, sizeof(tcp_stat_name), "site.%u.bts.%u.ipa-rsl.%u", unit_data.site_id, unit_data.bts_id, unit_data.trx_id); osmo_stats_tcp_osmo_fd_register(newbfd, tcp_stat_name);
- e1i_ts = ipaccess_line_ts(newbfd, new_line); - ipaccess_bsc_keepalive_fsm_alloc(e1i_ts, newbfd, "rsl_bsc_to_bts"); + ipaccess_bsc_keepalive_fsm_alloc(new_ts, conn, "rsl_bsc_to_bts"); + + /* Now that we attached the srv_conn to the e1ts, transmit packets which may been enqueued + * by user during sign_link_up() and which were delayed due to no srv_conn found: */ + ipaccess_bsc_write_cb(new_ts); + /* Conn is not freed here, so we need to free msgb. */ + msgb_free(msg); return 1; } break; @@ -390,86 +349,14 @@ LOGPIL(line, DLINP, LOGL_ERROR, "Unknown IPA message type\n"); goto err; } + +ret_skip: + msgb_free(msg); return 0; err: - if (bfd->fd != -1) { - osmo_fd_unregister(bfd); - close(bfd->fd); - bfd->fd = -1; - /* This is a BSC accepted socket, bfd->data holds a reference to line, drop it */ - OSMO_ASSERT(bfd->data == line); - bfd->data = NULL; - e1inp_line_put2(line, "ipa_bfd"); - } - return -1; -} - -/* Returns -EBADF if bfd cannot be used by the caller anymore after return. */ -static int handle_ts1_read(struct osmo_fd *bfd) -{ - struct e1inp_line *line = bfd->data; - unsigned int ts_nr = bfd->priv_nr; - struct e1inp_ts *e1i_ts; - struct e1inp_sign_link *link; - struct ipaccess_head *hh; - struct msgb *msg = NULL; - int ret, rc; - - e1i_ts = ipaccess_line_ts(bfd, line); - ret = ipa_msg_recv_buffered(bfd->fd, &msg, &e1i_ts->pending_msg); - if (ret < 0) { - if (ret == -EAGAIN) - return 0; - LOGPITS(e1i_ts, DLINP, LOGL_NOTICE, "Sign link problems, closing socket. Reason: %s\n", - strerror(-ret)); - goto err; - } else if (ret == 0) { - LOGPITS(e1i_ts, DLINP, LOGL_NOTICE, "Sign link vanished, dead socket\n"); - goto err; - } - LOGPITS(e1i_ts, DLMI, LOGL_DEBUG, "RX %u: %s\n", ts_nr, osmo_hexdump(msgb_l2(msg), msgb_l2len(msg))); - - hh = (struct ipaccess_head *) msg->data; - if (hh->proto == IPAC_PROTO_IPACCESS) { - ret = ipaccess_rcvmsg(line, msg, bfd); - /* BIG FAT WARNING: bfd might no longer exist here (ret != 0), - * since ipaccess_rcvmsg() might have free'd it !!! */ - msgb_free(msg); - return ret != 0 ? -EBADF : 0; - } else if (e1i_ts->type == E1INP_TS_TYPE_NONE) { - /* this sign link is not know yet.. complain. */ - LOGPITS(e1i_ts, DLINP, LOGL_ERROR, "Timeslot is not configured.\n"); - goto err_msg; - } - - link = e1inp_lookup_sign_link(e1i_ts, hh->proto, 0); - if (!link) { - LOGPITS(e1i_ts, DLINP, LOGL_ERROR, "no matching signalling link for hh->proto=0x%02x\n", hh->proto); - goto err_msg; - } - msg->dst = link; - - /* XXX better use e1inp_ts_rx? */ - if (!e1i_ts->line->ops->sign_link) { - LOGPITS(e1i_ts, DLINP, LOGL_ERROR, "Fix your application, no action set for signalling messages.\n"); - goto err_msg; - } - rc = e1i_ts->line->ops->sign_link(msg); - if (rc < 0) { - /* Don't close the signalling link if the upper layers report - * an error, that's too strict. BTW, the signalling layer is - * resposible for releasing the message. - */ - LOGPITS(e1i_ts, DLINP, LOGL_ERROR, "Bad signalling message, sign_link returned error: %s.\n", - strerror(-rc)); - } - - return rc; -err_msg: msgb_free(msg); -err: - ipaccess_drop(bfd, line); - return -EBADF; + osmo_stream_srv_destroy(conn); + return -1; }
static void ipaccess_close(struct e1inp_sign_link *sign_link) @@ -479,6 +366,7 @@ struct e1inp_line *line = e1i_ts->line; struct osmo_fsm_inst *ka_fsm = e1i_ts->driver.ipaccess.ka_fsm; struct osmo_stream_cli *cli; + struct osmo_stream_srv *conn;
/* depending on caller the fsm might be dead */ if (ka_fsm) @@ -495,19 +383,24 @@ bfd->fd = -1; /* Compatibility with older implementations */ break; case E1INP_LINE_R_BSC: - default: - if (bfd->fd != -1) { - osmo_fd_unregister(bfd); - close(bfd->fd); - bfd->fd = -1; - /* If The bfd holds a reference to e1inp_line in ->data (BSC - * accepted() sockets), then release it */ - if (bfd->data == line) { - bfd->data = NULL; - e1inp_line_put2(line, "ipa_bfd"); - } + /* conn may be NULL here, if we are called by user during sign_link_up() + * ballback and hence before we finished to internally move the ipaccess conn + * under the proper final line/ts object: + */ + conn = ipaccess_bts_e1i_ts_stream_srv(e1i_ts); + if (conn) { + osmo_stream_srv_destroy(conn); + } else { + LOGPITS(e1i_ts, DLINP, LOGL_DEBUG, + "ipaccess_close() on ts with no srv_conn, " + "probably called during sign_link_up() or sign_link_down() user cb.\n"); } break; + default: + LOGPITS(e1i_ts, DLINP, LOGL_ERROR, + "ipaccess_close() for line with unknown role %d\n", + line->ops->cfg.ipa.role); + break; } }
@@ -562,6 +455,55 @@ return rc; }
+static int ipaccess_bsc_send_msg(struct e1inp_ts *e1i_ts, + struct e1inp_sign_link *sign_link, + struct osmo_stream_srv *conn, + struct msgb *msg) +{ + switch (sign_link->type) { + case E1INP_SIGN_OML: + case E1INP_SIGN_RSL: + case E1INP_SIGN_OSMO: + break; + default: + msgb_free(msg); + return -EINVAL; + } + + msg->l2h = msg->data; + ipa_prepend_header(msg, sign_link->tei); + + LOGPITS(e1i_ts, DLMI, LOGL_DEBUG, "TX: %s\n", osmo_hexdump(msg->l2h, msgb_l2len(msg))); + osmo_stream_srv_send(conn, msg); + return 0; +} + +/* msg was enqueued in sign_link->tx_list. + * Pop it from that list, submit it to osmo_stream_srv. */ +static int ipaccess_bsc_write_cb(struct e1inp_ts *e1i_ts) +{ + int rc = 0; + struct osmo_stream_srv *srv = ipaccess_bts_e1i_ts_stream_srv(e1i_ts); + + /* conn may be NULL here, if we are called by user during sign_link_up() + * ballback and hence before we finished to internally move the ipaccess conn + * under the proper final line/ts object: + */ + if (!srv) { + LOGPITS(e1i_ts, DLMI, LOGL_DEBUG, "Delaying Tx on ts with no srv_conn\n"); + return -ENODEV; + } + + /* get the next msg for this timeslot */ + while (e1i_ts_has_pending_tx_msgs(e1i_ts)) { + struct e1inp_sign_link *sign_link = NULL; + struct msgb *msg; + msg = e1inp_tx_ts(e1i_ts, &sign_link); + rc |= ipaccess_bsc_send_msg(e1i_ts, sign_link, srv, msg); + } + return rc; +} + static int ts_want_write(struct e1inp_ts *e1i_ts) { enum e1inp_line_role role = E1INP_LINE_R_NONE; @@ -576,118 +518,92 @@ /* msg was enqueued in sign_link->tx_list. * Pop it from that list, submit it to osmo_stream_cli: */ return ipaccess_bts_write_cb(e1i_ts); - case E1INP_LINE_R_NONE: case E1INP_LINE_R_BSC: + /* msg was enqueued in sign_link->tx_list. + * Pop it from that list, submit it to osmo_stream_cli: */ + return ipaccess_bsc_write_cb(e1i_ts); + case E1INP_LINE_R_NONE: default: - osmo_fd_write_enable(&e1i_ts->driver.ipaccess.fd); - /* ipaccess_fd_cb will be called from main loop and tx the msgb. */ + LOGPITS(e1i_ts, DLMI, LOGL_ERROR, "want_write for ts with unknown role %d!\n", role); return 0; } }
-static void timeout_ts1_write(void *data) +static int ipaccess_bsc_conn_read_cb(struct osmo_stream_srv *conn, int res, struct msgb *msg) { - struct e1inp_ts *e1i_ts = (struct e1inp_ts *)data; + enum ipaccess_proto ipa_proto = osmo_ipa_msgb_cb_proto(msg); + struct e1inp_ts *e1i_ts = osmo_stream_srv_get_data(conn); + struct e1inp_sign_link *link; + int ret, rc;
- /* trigger write of ts1, due to tx delay timer */ - if (e1i_ts_has_pending_tx_msgs(e1i_ts)) - ts_want_write(e1i_ts); -} - -static int __handle_ts1_write(struct osmo_fd *bfd, struct e1inp_line *line) -{ - unsigned int ts_nr = bfd->priv_nr; - struct e1inp_ts *e1i_ts; - struct e1inp_sign_link *sign_link; - struct msgb *msg; - int ret; - - e1i_ts = ipaccess_line_ts(bfd, line); - - /* get the next msg for this timeslot */ - msg = e1inp_tx_ts(e1i_ts, &sign_link); - if (!msg) { - /* no message after tx delay timer */ - osmo_fd_write_disable(bfd); - return 0; - } - - switch (sign_link->type) { - case E1INP_SIGN_OML: - case E1INP_SIGN_RSL: - case E1INP_SIGN_OSMO: - break; - default: - /* leave WRITE flag enabled, come back for more msg */ - ret = -EINVAL; - goto out; - } - - msg->l2h = msg->data; - ipa_prepend_header(msg, sign_link->tei); - - LOGPITS(e1i_ts, DLMI, LOGL_DEBUG, "TX %u: %s\n", ts_nr, - osmo_hexdump(msg->l2h, msgb_l2len(msg))); - - ret = send(bfd->fd, msg->data, msg->len, 0); - if (ret != msg->len) { - LOGPITS(e1i_ts, DLINP, LOGL_ERROR, "failed to send A-bis IPA signalling " - "message. Reason: %s\n", strerror(errno)); + if (res <= 0) { + LOGPITS(e1i_ts, DLINP, LOGL_NOTICE, "failed reading from socket: %d\n", res); goto err; }
- /* this is some ancient code that apparently exists to slow down writes towards - * some even more ancient nanoBTS 900 units. See git commit - * d49fc5ae24fc9d44d2b284392ab619cc7a69a876 of openbsc.git (now osmo-bsc.git) */ - if (e1i_ts->sign.delay) { - osmo_fd_write_disable(bfd); - /* set tx delay timer for next event */ - osmo_timer_setup(&e1i_ts->sign.tx_timer, timeout_ts1_write, e1i_ts); - osmo_timer_schedule(&e1i_ts->sign.tx_timer, 0, e1i_ts->sign.delay); - } else { -out: - if (!e1i_ts_has_pending_tx_msgs(e1i_ts)) - osmo_fd_write_disable(bfd); + LOGPITS(e1i_ts, DLMI, LOGL_DEBUG, "RX: %s\n", osmo_hexdump(msgb_l2(msg), msgb_l2len(msg))); + + if (ipa_proto == IPAC_PROTO_IPACCESS) { + ret = ipaccess_bsc_rcvmsg(conn, msg); + /* BIG FAT WARNING: bfd might no longer exist here (ret != 0), + * since ipaccess_rcvmsg() might have free'd it !!! */ + return ret != 0 ? -EBADF : 0; } - msgb_free(msg); - return ret; -err: - ipaccess_drop(bfd, line); - msgb_free(msg); - return ret; -} + if (e1i_ts->type == E1INP_TS_TYPE_NONE) { + /* this sign link is not know yet.. complain. */ + LOGPITS(e1i_ts, DLINP, LOGL_ERROR, "Timeslot is not configured.\n"); + goto err; + }
-static int handle_ts1_write(struct osmo_fd *bfd) -{ - struct e1inp_line *line = bfd->data; + link = e1inp_lookup_sign_link(e1i_ts, ipa_proto, 0); + if (!link) { + LOGPITS(e1i_ts, DLINP, LOGL_ERROR, "no matching signalling link for ipa_proto=0x%02x\n", ipa_proto); + goto err; + } + msg->dst = link;
- return __handle_ts1_write(bfd, line); -} - - -/* callback from select.c in case one of the fd's can be read/written */ -int ipaccess_fd_cb(struct osmo_fd *bfd, unsigned int what) -{ - int rc = 0; - - if (what & OSMO_FD_READ) - rc = handle_ts1_read(bfd); - if (rc != -EBADF && (what & OSMO_FD_WRITE)) - rc = handle_ts1_write(bfd); + /* XXX better use e1inp_ts_rx? */ + if (!e1i_ts->line->ops->sign_link) { + LOGPITS(e1i_ts, DLINP, LOGL_ERROR, "Fix your application, no action set for signalling messages.\n"); + goto err; + } + rc = e1i_ts->line->ops->sign_link(msg); + if (rc < 0) { + /* Don't close the signalling link if the upper layers report + * an error, that's too strict. BTW, the signalling layer is + * resposible for releasing the message. + */ + LOGPITS(e1i_ts, DLINP, LOGL_ERROR, "Bad signalling message, sign_link returned error: %s.\n", + strerror(-rc)); + }
return rc; +err: + msgb_free(msg); + osmo_stream_srv_destroy(conn); + return 0; }
-static int ipaccess_line_update(struct e1inp_line *line); +static int ipaccess_bsc_conn_closed_cb(struct osmo_stream_srv *conn) +{ + struct e1inp_ts *e1i_ts = osmo_stream_srv_get_data(conn); + struct e1inp_line *line = e1i_ts->line; + struct osmo_fd *bfd = &e1i_ts->driver.ipaccess.fd; + e1inp_line_get2(line, __func__); + e1inp_line_put2(line, "ipa_bfd");
-struct e1inp_driver ipaccess_driver = { - .name = "ipa", - .want_write = ts_want_write, - .line_update = ipaccess_line_update, - .close = ipaccess_close, - .default_delay = 0, - .has_keepalive = 1, -}; + osmo_stats_tcp_osmo_fd_unregister(bfd); + ipaccess_keepalive_fsm_cleanup(e1i_ts); + + osmo_stream_srv_set_data(conn, NULL); + bfd->fd = -1; + bfd->data = NULL; + + if (line->ops->sign_link_down) + line->ops->sign_link_down(line); + e1inp_line_put2(line, __func__); + return 0; +}
static void update_fd_settings(struct e1inp_line *line, int fd) { @@ -741,16 +657,19 @@ }
/* callback of the OML listening filedescriptor */ -static int ipaccess_bsc_oml_cb(struct ipa_server_link *link, int fd) +static int ipaccess_bsc_oml_accept_cb(struct osmo_stream_srv_link *link, int fd) { int ret; int i; + struct e1inp_line *srv_link_line = osmo_stream_srv_link_get_data(link); struct e1inp_line *line; + struct osmo_stream_srv *conn; struct e1inp_ts *e1i_ts; struct osmo_fd *bfd; + char conn_name[128];
/* clone virtual E1 line for this new OML link. */ - line = e1inp_line_clone(tall_ipa_ctx, link->line, "ipa_bfd"); + line = e1inp_line_clone(tall_ipa_ctx, srv_link_line, "ipa_bfd"); if (line == NULL) { LOGP(DLINP, LOGL_ERROR, "could not clone E1 line\n"); return -ENOMEM; @@ -765,45 +684,48 @@
e1i_ts = e1inp_line_ipa_oml_ts(line);
+ snprintf(conn_name, sizeof(conn_name), "ts-%u-%u-oml", line->num, e1i_ts->num); + conn = osmo_stream_srv_create2(link, link, fd, e1i_ts); + OSMO_ASSERT(conn); + osmo_stream_srv_set_name(conn, conn_name); + osmo_stream_srv_set_read_cb(conn, ipaccess_bsc_conn_read_cb); + osmo_stream_srv_set_closed_cb(conn, ipaccess_bsc_conn_closed_cb); + osmo_stream_srv_set_segmentation_cb(conn, osmo_ipa_segmentation_cb); + + /* We use bfd->fd in here for osmo_stats_tcp, and bfd->data to access osmo_stream_srv from e1i_ts. */ bfd = &e1i_ts->driver.ipaccess.fd; - osmo_fd_setup(bfd, fd, OSMO_FD_READ, ipaccess_fd_cb, line, E1INP_SIGN_OML); - ret = osmo_fd_register(bfd); - if (ret < 0) { - LOGPITS(e1i_ts, DLINP, LOGL_ERROR, "could not register FD\n"); - goto err_line; - } + osmo_fd_setup(bfd, fd, 0, NULL, conn, E1INP_SIGN_OML); osmo_stats_tcp_osmo_fd_register(bfd, "ipa-oml");
- update_fd_settings(line, bfd->fd); + update_fd_settings(line, fd);
/* Request ID. FIXME: request LOCATION, HW/SW VErsion, Unit Name, Serno */ - ret = ipa_ccm_send_id_req(bfd->fd); + /* PESPIN: TODO: use osmo_stream_srv_send() instead */ + ret = ipa_ccm_send_id_req(fd); if (ret < 0) { LOGPITS(e1i_ts, DLINP, LOGL_ERROR, "could not send ID REQ. Reason: %s\n", strerror(errno)); goto err_socket; } - return ret; + return 0;
err_socket: - osmo_fd_unregister(bfd); -err_line: - close(bfd->fd); - bfd->fd = -1; - bfd->data = NULL; - e1inp_line_put2(line, "ipa_bfd"); - return ret; + osmo_stream_srv_destroy(conn); + return 0; }
-static int ipaccess_bsc_rsl_cb(struct ipa_server_link *link, int fd) +static int ipaccess_bsc_rsl_accept_cb(struct osmo_stream_srv_link *link, int fd) { + struct e1inp_line *srv_link_line = osmo_stream_srv_link_get_data(link); struct e1inp_line *line; + struct osmo_stream_srv *conn; struct e1inp_ts *e1i_ts; struct osmo_fd *bfd; int i, ret; + char conn_name[128];
/* We don't know yet which OML link to associate it with. Thus, we * allocate a temporary E1 line until we have received ID. */ - line = e1inp_line_clone(tall_ipa_ctx, link->line, "ipa_bfd"); + line = e1inp_line_clone(tall_ipa_ctx, srv_link_line, "ipa_bfd"); if (line == NULL) { LOGP(DLINP, LOGL_ERROR, "could not clone E1 line\n"); return -ENOMEM; @@ -812,38 +734,38 @@ for (i = 0; i < ARRAY_SIZE(line->ts); ++i) line->ts[i].driver.ipaccess.fd.fd = -1;
- /* we need this to initialize this in case to avoid crashes in case + /* we need to initialize this in case to avoid crashes in case * that the socket is closed before we've seen an ID_RESP. */ e1inp_ts_config_sign(e1inp_line_ipa_oml_ts(line), line);
e1i_ts = e1inp_line_ipa_rsl_ts(line, 0);
+ snprintf(conn_name, sizeof(conn_name), "ts-%u-%u-rsl", line->num, e1i_ts->num); + conn = osmo_stream_srv_create2(link, link, fd, e1i_ts); + OSMO_ASSERT(conn); + osmo_stream_srv_set_name(conn, conn_name); + osmo_stream_srv_set_read_cb(conn, ipaccess_bsc_conn_read_cb); + osmo_stream_srv_set_closed_cb(conn, ipaccess_bsc_conn_closed_cb); + osmo_stream_srv_set_segmentation_cb(conn, osmo_ipa_segmentation_cb); + + /* We use bfd->fd in here for osmo_stats_tcp, and bfd->data to access osmo_stream_srv from e1i_ts. */ bfd = &e1i_ts->driver.ipaccess.fd; - osmo_fd_setup(bfd, fd, OSMO_FD_READ, ipaccess_fd_cb, line, E1INP_SIGN_RSL); - ret = osmo_fd_register(bfd); - if (ret < 0) { - LOGPITS(e1i_ts, DLINP, LOGL_ERROR, "could not register FD\n"); - goto err_line; - } + osmo_fd_setup(bfd, fd, 0, NULL, conn, E1INP_SIGN_RSL); osmo_stats_tcp_osmo_fd_register(bfd, "ipa-rsl");
/* Request ID. FIXME: request LOCATION, HW/SW VErsion, Unit Name, Serno */ - ret = ipa_ccm_send_id_req(bfd->fd); + /* PESPIN: TODO: use osmo_stream_srv_send() instead */ + ret = ipa_ccm_send_id_req(fd); if (ret < 0) { LOGPITS(e1i_ts, DLINP, LOGL_ERROR, "could not send ID REQ. Reason: %s\n", strerror(errno)); goto err_socket; } - update_fd_settings(line, bfd->fd); - return ret; + update_fd_settings(line, fd); + return 0;
err_socket: - osmo_fd_unregister(bfd); -err_line: - close(bfd->fd); - bfd->fd = -1; - bfd->data = NULL; - e1inp_line_put2(line, "ipa_bfd"); - return ret; + osmo_stream_srv_destroy(conn); + return 0; }
int ipaccess_bts_handle_ccm(struct ipa_client_conn *link, @@ -1100,38 +1022,43 @@ /* We only initialize this line once. */ if (il->line_already_initialized) return 0; - struct ipa_server_link *oml_link, *rsl_link; + struct osmo_stream_srv_link *oml_link, *rsl_link; const char *ipa = e1inp_ipa_get_bind_addr();
LOGPIL(line, DLINP, LOGL_NOTICE, "enabling ipaccess BSC mode on %s " "with OML %u and RSL %u TCP ports\n", ipa, IPA_TCP_PORT_OML, IPA_TCP_PORT_RSL);
- oml_link = ipa_server_link_create(tall_ipa_ctx, line, ipa, - IPA_TCP_PORT_OML, - ipaccess_bsc_oml_cb, NULL); - if (oml_link == NULL) { - LOGPIL(line, DLINP, LOGL_ERROR, "cannot create OML BSC link: %s\n", strerror(errno)); - return -ENOMEM; - } - oml_link->dscp = g_e1inp_ipaccess_pars.oml.dscp; - oml_link->priority = g_e1inp_ipaccess_pars.oml.priority; - if (ipa_server_link_open(oml_link) < 0) { - LOGPIL(line, DLINP, LOGL_ERROR, "cannot open OML BSC link: %s\n", strerror(errno)); - ipa_server_link_destroy(oml_link); + oml_link = osmo_stream_srv_link_create(tall_ipa_ctx); + OSMO_ASSERT(oml_link); + osmo_stream_srv_link_set_proto(oml_link, IPPROTO_TCP); + osmo_stream_srv_link_set_addr(oml_link, ipa); + osmo_stream_srv_link_set_port(oml_link, IPA_TCP_PORT_OML); + osmo_stream_srv_link_set_data(oml_link, line); + osmo_stream_srv_link_set_nodelay(oml_link, true); + osmo_stream_srv_link_set_priority(oml_link, g_e1inp_ipaccess_pars.oml.dscp); + osmo_stream_srv_link_set_ip_dscp(oml_link, g_e1inp_ipaccess_pars.oml.priority); + osmo_stream_srv_link_set_accept_cb(oml_link, ipaccess_bsc_oml_accept_cb); + + if (osmo_stream_srv_link_open(oml_link)) { + LOGPIL(line, DLINP, LOGL_ERROR, "cannot open OML BTS link: %s\n", strerror(errno)); + osmo_stream_srv_link_destroy(oml_link); return -EIO; } - rsl_link = ipa_server_link_create(tall_ipa_ctx, line, ipa, - IPA_TCP_PORT_RSL, - ipaccess_bsc_rsl_cb, NULL); - if (rsl_link == NULL) { - LOGPIL(line, DLINP, LOGL_ERROR, "cannot create RSL BSC link: %s\n", strerror(errno)); - return -ENOMEM; - } - rsl_link->dscp = g_e1inp_ipaccess_pars.rsl.dscp; - rsl_link->priority = g_e1inp_ipaccess_pars.rsl.priority; - if (ipa_server_link_open(rsl_link) < 0) { - LOGPIL(line, DLINP, LOGL_ERROR, "cannot open RSL BSC link: %s\n", strerror(errno)); - ipa_server_link_destroy(rsl_link); + + rsl_link = osmo_stream_srv_link_create(tall_ipa_ctx); + OSMO_ASSERT(rsl_link); + osmo_stream_srv_link_set_proto(rsl_link, IPPROTO_TCP); + osmo_stream_srv_link_set_addr(rsl_link, ipa); + osmo_stream_srv_link_set_port(rsl_link, IPA_TCP_PORT_RSL); + osmo_stream_srv_link_set_data(rsl_link, line); + osmo_stream_srv_link_set_nodelay(rsl_link, true); + osmo_stream_srv_link_set_priority(rsl_link, g_e1inp_ipaccess_pars.rsl.dscp); + osmo_stream_srv_link_set_ip_dscp(rsl_link, g_e1inp_ipaccess_pars.rsl.priority); + osmo_stream_srv_link_set_accept_cb(rsl_link, ipaccess_bsc_rsl_accept_cb); + + if (osmo_stream_srv_link_open(rsl_link)) { + LOGPIL(line, DLINP, LOGL_ERROR, "cannot open RSL BTS link: %s\n", strerror(errno)); + osmo_stream_srv_link_destroy(rsl_link); return -EIO; } ret = 0; @@ -1299,6 +1226,15 @@ return 0; }
+struct e1inp_driver ipaccess_driver = { + .name = "ipa", + .want_write = ts_want_write, + .line_update = ipaccess_line_update, + .close = ipaccess_close, + .default_delay = 0, + .has_keepalive = 1, +}; + void e1inp_ipaccess_init(void) { tall_ipa_ctx = talloc_named_const(libosmo_abis_ctx, 1, "ipa");