From ad8f042c319ce4af5fd3ab711849a72025eea3e8 Mon Sep 17 00:00:00 2001 From: Eric Wild Date: Wed, 10 Jul 2019 18:10:31 +0200 Subject: add ipa ping/pong keepalive for OML/RSL links between bts and bsc Patch-by: ewild, osmith Change-Id: I30e3bd601e55355aaf738ee2f2c44c1ec2c46c6a Depends: (libosmo-abis) Ie453fdee8bfd7fc1a3f1ed67ef0331f0abb1d59b --- TODO-RELEASE | 1 + include/osmocom/abis/e1_input.h | 7 +- src/e1_input_vty.c | 49 ++++++++++- src/input/ipaccess.c | 174 ++++++++++++++++++++++++++++++++++++---- 4 files changed, 214 insertions(+), 17 deletions(-) diff --git a/TODO-RELEASE b/TODO-RELEASE index d0852fc..e2f62ef 100644 --- a/TODO-RELEASE +++ b/TODO-RELEASE @@ -7,3 +7,4 @@ # If any interfaces have been added since the last public release: c:r:a + 1. # If any interfaces have been removed or changed since the last public release: c:r:0. #library what description / commit summary line +libosmo-abis API change major: add parameter to struct e1inp_line diff --git a/include/osmocom/abis/e1_input.h b/include/osmocom/abis/e1_input.h index 00b4aaa..4362f50 100644 --- a/include/osmocom/abis/e1_input.h +++ b/include/osmocom/abis/e1_input.h @@ -123,6 +123,8 @@ struct e1inp_ts { struct { /* ip.access driver has one fd for each ts */ struct osmo_fd fd; + /* ipa keep-alive */ + struct osmo_fsm_inst* ka_fsm; } ipaccess; struct { /* DAHDI driver has one fd for each ts */ @@ -197,11 +199,14 @@ struct e1inp_line { char *sock_path; struct rate_ctr_group *rate_ctr; - /* keepalive configuration */ + /* tcp keepalive configuration */ int keepalive_num_probes; /* 0: disable, num, or E1INP_USE_DEFAULT */ int keepalive_idle_timeout; /* secs, or E1INP_USE_DEFAULT */ int keepalive_probe_interval; /* secs or E1INP_USE_DEFAULT */ + /* ipa ping/pong keepalive params */ + struct ipa_keepalive_params *ipa_kap; + /* array of timestlots */ struct e1inp_ts ts[NUM_E1_TS]; unsigned int num_ts; diff --git a/src/e1_input_vty.c b/src/e1_input_vty.c index a1943e6..3aa8f3e 100644 --- a/src/e1_input_vty.c +++ b/src/e1_input_vty.c @@ -38,6 +38,7 @@ #include #include +#include /* CONFIG */ @@ -169,6 +170,47 @@ DEFUN(cfg_e1line_no_keepalive, cfg_e1_line_no_keepalive_cmd, return set_keepalive_params(vty, atoi(argv[0]), 0, 0, 0); } +#define IPAKEEPALIVE_HELP "Enable IPA PING/PONG keep-alive\n" +static int set_ipa_keepalive_params(struct vty *vty, int e1_nr, int interval, int wait_for_resp) +{ + struct e1inp_line *line = e1inp_line_find(e1_nr); + + if (!line) { + vty_out(vty, "%% Line %d doesn't exist%s", e1_nr, VTY_NEWLINE); + return CMD_WARNING; + } + + if (strcmp(line->driver->name, "ipa") != 0) { + vty_out(vty, "%% Line %d doesn't use the ipa driver%s", e1_nr, VTY_NEWLINE); + return CMD_WARNING; + } + + TALLOC_FREE(line->ipa_kap); + if (interval) { + line->ipa_kap = talloc_zero(line, struct ipa_keepalive_params); + line->ipa_kap->wait_for_resp = wait_for_resp; + line->ipa_kap->interval = interval; + } + + return CMD_SUCCESS; +} + +DEFUN(cfg_e1line_ipa_keepalive, cfg_e1_line_ipa_keepalive_cmd, + "e1_line <0-255> ipa-keepalive <1-300> <1-300>", + E1_LINE_HELP IPAKEEPALIVE_HELP + "Idle interval in seconds before probes are sent\n" + "Time to wait for PONG response\n") +{ + return set_ipa_keepalive_params(vty, atoi(argv[0]), atoi(argv[1]), atoi(argv[2])); +} + +DEFUN(cfg_e1line_no_ipa_keepalive, cfg_e1_line_no_ipa_keepalive_cmd, + "no e1_line <0-255> ipa-keepalive", + NO_STR E1_LINE_HELP IPAKEEPALIVE_HELP) +{ + return set_ipa_keepalive_params(vty, atoi(argv[0]), 0, 0); +} + DEFUN(cfg_e1line_name, cfg_e1_line_name_cmd, "e1_line <0-255> name .LINE", E1_LINE_HELP "Set name for this line\n" "Human readable name\n") @@ -242,7 +284,10 @@ static int e1inp_config_write(struct vty *vty) line->keepalive_num_probes, line->keepalive_probe_interval, VTY_NEWLINE); - + if (line->ipa_kap) + vty_out(vty, " e1_line %u ipa-keepalive %d %d%s", line->num, + line->ipa_kap->interval, line->ipa_kap->wait_for_resp, + VTY_NEWLINE); } const char *ipa_bind = e1inp_ipa_get_bind_addr(); @@ -398,6 +443,8 @@ int e1inp_vty_init(void) install_element(L_E1INP_NODE, &cfg_e1_line_keepalive_cmd); install_element(L_E1INP_NODE, &cfg_e1_line_keepalive_params_cmd); install_element(L_E1INP_NODE, &cfg_e1_line_no_keepalive_cmd); + install_element(L_E1INP_NODE, &cfg_e1_line_ipa_keepalive_cmd); + install_element(L_E1INP_NODE, &cfg_e1_line_no_ipa_keepalive_cmd); install_element(L_E1INP_NODE, &cfg_ipa_bind_cmd); diff --git a/src/input/ipaccess.c b/src/input/ipaccess.c index 9eff2f1..c689193 100644 --- a/src/input/ipaccess.c +++ b/src/input/ipaccess.c @@ -59,14 +59,25 @@ static void *tall_ipa_ctx; #define DEFAULT_TCP_KEEPALIVE_INTERVAL 3 #define DEFAULT_TCP_KEEPALIVE_RETRY_COUNT 10 -static int ipaccess_drop(struct osmo_fd *bfd, struct e1inp_line *line) +static inline struct e1inp_ts *ipaccess_line_ts(struct osmo_fd *bfd, struct e1inp_line *line) { - int ret = 1; - struct e1inp_ts *e1i_ts; if (bfd->priv_nr == E1INP_SIGN_OML) - e1i_ts = e1inp_line_ipa_oml_ts(line); + return e1inp_line_ipa_oml_ts(line); else - e1i_ts = e1inp_line_ipa_rsl_ts(line, bfd->priv_nr - E1INP_SIGN_RSL); + return e1inp_line_ipa_rsl_ts(line, bfd->priv_nr - E1INP_SIGN_RSL); +} + +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); + struct osmo_fsm_inst** ka_fsm; + + ka_fsm = &e1i_ts->driver.ipaccess.ka_fsm; + if (*ka_fsm) { + ipa_keepalive_fsm_stop(*ka_fsm); + *ka_fsm = NULL; + } /* Error case: we did not see any ID_RESP yet for this socket. */ if (bfd->fd != -1) { @@ -87,6 +98,24 @@ static int ipaccess_drop(struct osmo_fd *bfd, struct e1inp_line *line) 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); +} + +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); + return 1; +} + /* 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, @@ -98,6 +127,12 @@ static int ipaccess_rcvmsg(struct e1inp_line *line, struct msgb *msg, struct e1inp_sign_link *sign_link; char *unitid; int len, ret; + struct osmo_fsm_inst** ka_fsm; + + /* peek the pong for our keepalive fsm */ + ka_fsm = &ipaccess_line_ts(bfd, line)->driver.ipaccess.ka_fsm; + if (*ka_fsm && msg_type == IPAC_MSGT_PONG) + ipa_keepalive_fsm_pong_received(*ka_fsm); /* Handle IPA PING, PONG and ID_ACK messages. */ ret = ipa_ccm_rcvmsg_base(msg, bfd); @@ -165,9 +200,23 @@ static int ipaccess_rcvmsg(struct e1inp_line *line, struct msgb *msg, "closing socket.\n"); goto err; } + + if (*ka_fsm) { + osmo_fsm_inst_free(*ka_fsm); + *ka_fsm = NULL; + } + if (line->ipa_kap) { + *ka_fsm = ipa_generic_conn_alloc_keepalive_fsm(tall_ipa_ctx, bfd, line->ipa_kap, + "oml_bsc_to_bts"); + if (*ka_fsm) { + ipa_keepalive_fsm_set_timeout_cb(*ka_fsm, ipa_bsc_keepalive_timeout_cb); + ipa_keepalive_fsm_set_send_cb(*ka_fsm, ipa_bsc_keepalive_write_server_cb); + ipa_keepalive_fsm_start(*ka_fsm); + } + } } else if (bfd->priv_nr == E1INP_SIGN_RSL) { struct e1inp_ts *ts; - struct osmo_fd *newbfd; + struct osmo_fd *newbfd; struct e1inp_line *new_line; sign_link = @@ -209,6 +258,21 @@ static int ipaccess_rcvmsg(struct e1inp_line *line, struct msgb *msg, } /* now we can release the dummy RSL line. */ e1inp_line_put(line); + + ka_fsm = &ipaccess_line_ts(newbfd, new_line)->driver.ipaccess.ka_fsm; + if (*ka_fsm) { + osmo_fsm_inst_free(*ka_fsm); + *ka_fsm = NULL; + } + if (new_line->ipa_kap) { + *ka_fsm = ipa_generic_conn_alloc_keepalive_fsm(tall_ipa_ctx, newbfd, new_line->ipa_kap, + "rsl_bsc_to_bts"); + if (*ka_fsm) { + ipa_keepalive_fsm_set_timeout_cb(*ka_fsm, ipa_bsc_keepalive_timeout_cb); + ipa_keepalive_fsm_set_send_cb(*ka_fsm, ipa_bsc_keepalive_write_server_cb); + ipa_keepalive_fsm_start(*ka_fsm); + } + } return 1; } break; @@ -237,6 +301,8 @@ static int handle_ts1_read(struct osmo_fd *bfd) struct ipaccess_head *hh; struct msgb *msg = NULL; int ret, rc; + struct osmo_fsm_inst** ka_fsm = &ipaccess_line_ts(bfd, line)->driver.ipaccess.ka_fsm; + if (bfd->priv_nr == E1INP_SIGN_OML) e1i_ts = e1inp_line_ipa_oml_ts(line); @@ -297,6 +363,10 @@ static int handle_ts1_read(struct osmo_fd *bfd) err_msg: msgb_free(msg); err: + if (*ka_fsm) { + osmo_fsm_inst_free(*ka_fsm); + *ka_fsm = NULL; + } ipaccess_drop(bfd, line); return -EBADF; } @@ -312,6 +382,17 @@ static void ipaccess_close(struct e1inp_sign_link *sign_link) { struct e1inp_ts *e1i_ts = sign_link->ts; struct osmo_fd *bfd = &e1i_ts->driver.ipaccess.fd; + struct e1inp_line *line = e1i_ts->line; + + /* line might not exist if != bsc||bts */ + if (line) { + /* depending on caller the fsm might be dead */ + struct osmo_fsm_inst* ka_fsm = ipaccess_line_ts(bfd, line)->driver.ipaccess.ka_fsm; + if (ka_fsm) + ipa_keepalive_fsm_stop(ka_fsm); + + } + return e1inp_close_socket(e1i_ts, sign_link, bfd); } @@ -330,12 +411,10 @@ static int __handle_ts1_write(struct osmo_fd *bfd, struct e1inp_line *line) struct e1inp_sign_link *sign_link; struct msgb *msg; int ret; + struct osmo_fsm_inst** ka_fsm; - if (bfd->priv_nr == E1INP_SIGN_OML) - e1i_ts = e1inp_line_ipa_oml_ts(line); - else - e1i_ts = e1inp_line_ipa_rsl_ts(line, bfd->priv_nr - E1INP_SIGN_RSL); - + e1i_ts = ipaccess_line_ts(bfd, line); + ka_fsm = &e1i_ts->driver.ipaccess.ka_fsm; bfd->when &= ~BSC_FD_WRITE; /* get the next msg for this timeslot */ @@ -378,6 +457,10 @@ out: msgb_free(msg); return ret; err: + if (*ka_fsm) { + osmo_fsm_inst_free(*ka_fsm); + ka_fsm = NULL; + } ipaccess_drop(bfd, line); msgb_free(msg); return ret; @@ -683,11 +766,14 @@ static struct msgb *ipa_bts_id_ack(void) static void ipaccess_bts_updown_cb(struct ipa_client_conn *link, int up) { struct e1inp_line *line = link->line; + struct osmo_fsm_inst *ka_fsm = ipaccess_line_ts(link->ofd, line)->driver.ipaccess.ka_fsm; - if (up) { - update_fd_settings(line, link->ofd->fd); - return; - } + if (up) { + update_fd_settings(line, link->ofd->fd); + if (ka_fsm && line->ipa_kap) + ipa_keepalive_fsm_start(ka_fsm); + return; + } if (line->ops->sign_link_down) line->ops->sign_link_down(line); @@ -701,10 +787,19 @@ int ipaccess_bts_handle_ccm(struct ipa_client_conn *link, struct ipaccess_head *hh = (struct ipaccess_head *) msg->data; struct msgb *rmsg; int ret = 0; + /* line might not exist if != bsc||bts */ + struct e1inp_line *line = link->line; /* special handling for IPA CCM. */ if (hh->proto == IPAC_PROTO_IPACCESS) { uint8_t msg_type = *(msg->l2h); + struct osmo_fsm_inst* ka_fsm = NULL; + + /* peek the pong for our keepalive fsm */ + if (line && msg_type == IPAC_MSGT_PONG) { + ka_fsm = ipaccess_line_ts(link->ofd, line)->driver.ipaccess.ka_fsm; + ipa_keepalive_fsm_pong_received(ka_fsm); + } /* ping, pong and acknowledgment cases. */ ret = ipa_ccm_rcvmsg_bts_base(msg, link->ofd); @@ -833,6 +928,22 @@ struct ipaccess_line { bool line_already_initialized; }; +static void ipa_bts_keepalive_write_client_cb(struct osmo_fsm_inst *fi, void *conn, struct msgb *msg) { + struct ipa_client_conn *link = (struct ipa_client_conn *)conn; + int ret = 0; + + ret = ipa_send(link->ofd->fd, msg->data, msg->len); + if (ret != msg->len) { + LOGP(DLINP, LOGL_ERROR, "cannot send message. Reason: %s\n", strerror(errno)); + } + msgb_free(msg); +} + +static int ipa_bts_keepalive_timeout_cb(struct osmo_fsm_inst *fi, void *conn) { + ipaccess_bts_updown_cb(conn, false); + return 1; +} + static int ipaccess_line_update(struct e1inp_line *line) { int ret = -ENOENT; @@ -895,6 +1006,8 @@ static int ipaccess_line_update(struct e1inp_line *line) } case E1INP_LINE_R_BTS: { struct ipa_client_conn *link; + struct e1inp_ts *e1i_ts; + struct osmo_fsm_inst **ka_fsm; LOGP(DLINP, LOGL_NOTICE, "enabling ipaccess BTS mode, " "OML connecting to %s:%u\n", line->ops->cfg.ipa.addr, @@ -922,6 +1035,21 @@ static int ipaccess_line_update(struct e1inp_line *line) ipa_client_conn_destroy(link); return -EIO; } + + e1i_ts = e1inp_line_ipa_oml_ts(line); + ka_fsm = &e1i_ts->driver.ipaccess.ka_fsm; + if (*ka_fsm) { + osmo_fsm_inst_free(*ka_fsm); + *ka_fsm = NULL; + } + if (line->ipa_kap) { + *ka_fsm = ipa_client_conn_alloc_keepalive_fsm(link, line->ipa_kap, "oml_bts_to_bsc"); + if (*ka_fsm) { + ipa_keepalive_fsm_set_timeout_cb(*ka_fsm, ipa_bts_keepalive_timeout_cb); + ipa_keepalive_fsm_set_send_cb(*ka_fsm, ipa_bts_keepalive_write_client_cb); + } + } + ret = 0; break; } @@ -944,6 +1072,8 @@ int e1inp_ipa_bts_rsl_connect_n(struct e1inp_line *line, uint8_t trx_nr) { struct ipa_client_conn *rsl_link; + struct e1inp_ts *e1i_ts = e1inp_line_ipa_rsl_ts(line, trx_nr); + struct osmo_fsm_inst** ka_fsm; if (E1INP_SIGN_RSL+trx_nr-1 >= NUM_E1_TS) { LOGP(DLINP, LOGL_ERROR, "cannot create RSL BTS link: " @@ -972,6 +1102,20 @@ int e1inp_ipa_bts_rsl_connect_n(struct e1inp_line *line, ipa_client_conn_destroy(rsl_link); return -EIO; } + + ka_fsm = &e1i_ts->driver.ipaccess.ka_fsm; + if (*ka_fsm) { + osmo_fsm_inst_free(*ka_fsm); + *ka_fsm = NULL; + } + if (line->ipa_kap) { + *ka_fsm = ipa_client_conn_alloc_keepalive_fsm(rsl_link, line->ipa_kap, "rsl_bts_to_bsc"); + if (*ka_fsm) { + ipa_keepalive_fsm_set_timeout_cb(*ka_fsm, ipa_bts_keepalive_timeout_cb); + ipa_keepalive_fsm_set_send_cb(*ka_fsm, ipa_bts_keepalive_write_client_cb); + } + } + return 0; } -- cgit v1.2.3