Merge "openr2(5/6): added cli command -- mfcr2 destroy link <index>" into 16

This commit is contained in:
George Joseph 2019-07-23 18:43:13 -05:00 committed by Gerrit Code Review
commit d2a2131447
1 changed files with 187 additions and 24 deletions

View File

@ -749,6 +749,7 @@ struct dahdi_mfcr2 {
openr2_context_t *protocol_context; /*!< OpenR2 context handle */
struct dahdi_pvt *pvts[SIG_MFCR2_MAX_CHANNELS]; /*!< Member channel pvt structs */
int numchans; /*!< Number of channels in this R2 block */
int live_chans; /*!< Number of unremoved channels in this R2 block */
int nodev; /*!< Link disconnected? */
struct dahdi_mfcr2_conf conf; /*!< Configuration used to setup this pseudo-link */
};
@ -758,6 +759,8 @@ struct r2link_entry {
AST_LIST_ENTRY(r2link_entry) list;
};
static AST_LIST_HEAD_STATIC(r2links, r2link_entry);
static struct r2links nodev_r2links = AST_LIST_HEAD_INIT_VALUE;
/* how many r2links have been malloc'd */
static int r2links_count = 0;
@ -3548,6 +3551,21 @@ static void handle_clear_alarms(struct dahdi_pvt *p)
}
#ifdef HAVE_OPENR2
static void mfcr2_queue_for_destruction(const struct dahdi_pvt *p)
{
const struct dahdi_mfcr2 *r2link = p->mfcr2;
struct r2link_entry *cur;
AST_LIST_LOCK(&r2links);
AST_LIST_TRAVERSE_SAFE_BEGIN(&r2links, cur, list) {
if (r2link == &cur->mfcr2) {
ast_debug(3, "MFC/R2 channel %d queued for destruction\n", p->channel);
AST_LIST_MOVE_CURRENT(&nodev_r2links, list);
break;
}
}
AST_LIST_TRAVERSE_SAFE_END;
AST_LIST_UNLOCK(&r2links);
}
static int dahdi_r2_answer(struct dahdi_pvt *p)
{
@ -3633,6 +3651,9 @@ static void dahdi_r2_on_hardware_alarm(openr2_chan_t *r2chan, int alarm)
p->inalarm = alarm ? 1 : 0;
if (p->inalarm) {
res = get_alarms(p);
if (res == DAHDI_ALARM_NOTOPEN) {
mfcr2_queue_for_destruction(p);
}
handle_alarms(p, res);
} else {
handle_clear_alarms(p);
@ -5490,6 +5511,49 @@ static void dahdi_unlink_ss7_pvt(struct dahdi_pvt *pvt)
}
#endif /* defined(HAVE_SS7) */
#if defined(HAVE_OPENR2)
/*!
* \internal
* \brief Unlink the channel interface from the MFC/R2 private pointer array.
*
* \param pvt chan_dahdi private interface structure to unlink.
*
* \return Nothing
*/
static void dahdi_unlink_mfcr2_pvt(struct dahdi_pvt *pvt)
{
unsigned idx;
struct dahdi_mfcr2 *mfcr2;
int should_destroy_link = 0;
ast_mutex_lock(&pvt->lock);
if (pvt->r2chan) {
ast_debug(1, "Disable MFC/R2 channel %d read\n", pvt->channel);
openr2_chan_disable_read(pvt->r2chan);
}
mfcr2 = pvt->mfcr2;
if (mfcr2) {
for (idx = 0; idx < mfcr2->numchans; ++idx) {
if (mfcr2->pvts[idx] == pvt) {
ast_debug(1, "Removing MFC/R2 channel %d from the mfcr2 link\n", pvt->channel);
mfcr2->pvts[idx] = NULL;
mfcr2->live_chans--;
break;
}
}
if (!mfcr2->live_chans) {
ast_debug(1, "MFC/R2 link is now empty\n");
should_destroy_link = 1;
}
}
ast_mutex_unlock(&pvt->lock);
if (should_destroy_link) {
ast_debug(1, "MFC/R2 link is now empty\n");
mfcr2_queue_for_destruction(pvt);
}
}
#endif /* defined(HAVE_OPENR2) */
static struct dahdi_pvt *find_next_iface_in_span(struct dahdi_pvt *cur)
{
if (cur->next && cur->next->span == cur->span) {
@ -5518,6 +5582,9 @@ static void destroy_dahdi_pvt(struct dahdi_pvt *pvt)
#endif /* defined(HAVE_PRI) */
#if defined(HAVE_SS7)
dahdi_unlink_ss7_pvt(p);
#endif /* defined(HAVE_SS7) */
#if defined(HAVE_OPENR2)
dahdi_unlink_mfcr2_pvt(p);
#endif /* defined(HAVE_SS7) */
switch (pvt->which_iflist) {
case DAHDI_IFLIST_NONE:
@ -11032,6 +11099,40 @@ static void dahdi_destroy_channel_range(int start, int end)
}
}
#ifdef HAVE_OPENR2
static void dahdi_r2_destroy_nodev(void)
{
struct r2link_entry *cur;
AST_LIST_LOCK(&nodev_r2links);
AST_LIST_TRAVERSE_SAFE_BEGIN(&nodev_r2links, cur, list) {
int i;
struct dahdi_mfcr2 *r2 = &cur->mfcr2;
ast_debug(3, "About to destroy %d DAHDI channels of MFC/R2 link.\n", r2->numchans);
for (i = 0; i < r2->numchans; i++) {
int channel;
struct dahdi_pvt *pvt = r2->pvts[i];
if (!pvt) {
continue;
}
channel = pvt->channel;
ast_debug(3, "About to destroy B-channel %d.\n", channel);
dahdi_destroy_channel_range(channel, channel);
}
ast_debug(3, "Destroying R2 link\n");
AST_LIST_REMOVE(&nodev_r2links, cur, list);
if (r2->r2master != AST_PTHREADT_NULL) {
pthread_cancel(r2->r2master);
pthread_join(r2->r2master, NULL);
r2->r2master = AST_PTHREADT_NULL;
openr2_context_delete(r2->protocol_context);
}
ast_free(cur);
}
AST_LIST_TRAVERSE_SAFE_END;
AST_LIST_UNLOCK(&nodev_r2links);
}
#endif
static int setup_dahdi(int reload);
static int setup_dahdi_int(int reload, struct dahdi_chan_conf *default_conf, struct dahdi_chan_conf *base_conf, struct dahdi_chan_conf *conf);
@ -11655,6 +11756,9 @@ static void *do_monitor(void *data)
}
ast_mutex_unlock(&iflock);
release_doomed_pris();
#ifdef HAVE_OPENR2
dahdi_r2_destroy_nodev();
#endif
}
/* Never reached */
pthread_cleanup_pop(1);
@ -11841,21 +11945,17 @@ static struct dahdi_ss7 * ss7_resolve_linkset(int linkset)
static void dahdi_r2_destroy_links(void)
{
struct r2link_entry *cur;
/* Queue everything for removal */
AST_LIST_LOCK(&r2links);
AST_LIST_TRAVERSE_SAFE_BEGIN(&r2links, cur, list) {
struct dahdi_mfcr2 *r2 = &cur->mfcr2;
ast_debug(3, "Destroying R2 link\n");
AST_LIST_REMOVE(&r2links, cur, list);
if (r2->r2master != AST_PTHREADT_NULL) {
pthread_cancel(r2->r2master);
pthread_join(r2->r2master, NULL);
openr2_context_delete(r2->protocol_context);
}
ast_free(cur);
ast_debug(3, "MFC/R2 link #%d queued for destruction\n", cur->mfcr2.index);
AST_LIST_MOVE_CURRENT(&nodev_r2links, list);
}
AST_LIST_TRAVERSE_SAFE_END;
AST_LIST_UNLOCK(&r2links);
r2links_count = 0;
/* Now destroy properly */
dahdi_r2_destroy_nodev();
}
/* This is an artificial convenient capacity, to keep at most a full E1 of channels in a single thread */
@ -12189,6 +12289,7 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
destroy_dahdi_pvt(tmp);
return NULL;
}
r2_link->live_chans++;
tmp->mfcr2 = r2_link;
if (conf->mfcr2.call_files) {
openr2_chan_enable_call_files(tmp->r2chan);
@ -13757,6 +13858,8 @@ static void dahdi_ss7_error(struct ss7 *ss7, char *s)
static void *mfcr2_monitor(void *data)
{
struct dahdi_mfcr2 *mfcr2 = data;
struct dahdi_pvt *pvt;
/* we should be using pthread_key_create
and allocate pollers dynamically.
I think do_monitor() could be leaking, since it
@ -13773,8 +13876,12 @@ static void *mfcr2_monitor(void *data)
/* now that we're ready to get calls, unblock our side and
get current line state */
for (i = 0; i < mfcr2->numchans; i++) {
openr2_chan_set_idle(mfcr2->pvts[i]->r2chan);
openr2_chan_handle_cas(mfcr2->pvts[i]->r2chan);
pvt = mfcr2->pvts[i];
if (!pvt) {
continue;
}
openr2_chan_set_idle(pvt->r2chan);
openr2_chan_handle_cas(pvt->r2chan);
}
while (1) {
/* we trust here that the mfcr2 channel list will not ever change once
@ -13783,20 +13890,24 @@ static void *mfcr2_monitor(void *data)
for (i = 0; i < mfcr2->numchans; i++) {
pollers[i].revents = 0;
pollers[i].events = 0;
if (mfcr2->pvts[i]->owner) {
pvt = mfcr2->pvts[i];
if (!pvt) {
continue;
}
if (pvt->owner) {
continue;
}
if (mfcr2->nodev) {
continue;
}
if (!mfcr2->pvts[i]->r2chan) {
ast_debug(1, "Wow, no r2chan on channel %d\n", mfcr2->pvts[i]->channel);
if (!pvt->r2chan) {
ast_debug(1, "Wow, no r2chan on channel %d\n", pvt->channel);
quit_loop = 1;
break;
}
openr2_chan_enable_read(mfcr2->pvts[i]->r2chan);
openr2_chan_enable_read(pvt->r2chan);
pollers[i].events = POLLIN | POLLPRI;
pollers[i].fd = mfcr2->pvts[i]->subs[SUB_REAL].dfd;
pollers[i].fd = pvt->subs[SUB_REAL].dfd;
pollsize++;
}
if (quit_loop) {
@ -13823,8 +13934,12 @@ static void *mfcr2_monitor(void *data)
/* do we want to allow to cancel while processing events? */
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
for (i = 0; i < mfcr2->numchans; i++) {
pvt = mfcr2->pvts[i];
if (!pvt) {
continue;
}
if (pollers[i].revents & POLLPRI || pollers[i].revents & POLLIN) {
openr2_chan_process_event(mfcr2->pvts[i]->r2chan);
openr2_chan_process_event(pvt->r2chan);
}
}
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
@ -15128,6 +15243,51 @@ static char *handle_mfcr2_show_links(struct ast_cli_entry *e, int cmd, struct as
return CLI_SUCCESS;
}
static char *handle_mfcr2_destroy_link(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
int res;
int wanted_link_index;
int found_link = 0;
struct r2link_entry *cur = NULL;
switch (cmd) {
case CLI_INIT:
e->command = "mfcr2 destroy link";
e->usage =
"Usage: mfcr2 destroy link <index-number>\n"
" Destorys D-channel of link and its B-channels.\n"
" DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
if (a->argc < 4) {
return CLI_SHOWUSAGE;
}
res = sscanf(a->argv[3], "%30d", &wanted_link_index);
if ((res != 1) || wanted_link_index < 1) {
ast_cli(a->fd,
"Invalid link index '%s'. Should be a positive number\n", a->argv[3]);
return CLI_SUCCESS;
}
AST_LIST_LOCK(&r2links);
AST_LIST_TRAVERSE_SAFE_BEGIN(&r2links, cur, list) {
struct dahdi_mfcr2 *mfcr2 = &cur->mfcr2;
if (wanted_link_index == mfcr2->index) {
AST_LIST_MOVE_CURRENT(&nodev_r2links, list);
r2links_count--;
break;
}
}
AST_LIST_TRAVERSE_SAFE_END;
AST_LIST_UNLOCK(&r2links);
if (! found_link) {
ast_cli(a->fd, "No link found with index %d.\n", wanted_link_index);
return CLI_FAILURE;
}
return CLI_SUCCESS;
}
static struct ast_cli_entry dahdi_mfcr2_cli[] = {
AST_CLI_DEFINE(handle_mfcr2_version, "Show OpenR2 library version"),
AST_CLI_DEFINE(handle_mfcr2_show_variants, "Show supported MFC/R2 variants"),
@ -15137,6 +15297,7 @@ static struct ast_cli_entry dahdi_mfcr2_cli[] = {
AST_CLI_DEFINE(handle_mfcr2_call_files, "Enable/Disable MFC/R2 call files"),
AST_CLI_DEFINE(handle_mfcr2_set_idle, "Reset MFC/R2 channel forcing it to IDLE"),
AST_CLI_DEFINE(handle_mfcr2_set_blocked, "Reset MFC/R2 channel forcing it to BLOCKED"),
AST_CLI_DEFINE(handle_mfcr2_destroy_link, "Destroy given MFC/R2 link"),
};
#endif /* HAVE_OPENR2 */
@ -19444,13 +19605,15 @@ static int setup_dahdi_int(int reload, struct dahdi_chan_conf *default_conf, str
AST_LIST_LOCK(&r2links);
AST_LIST_TRAVERSE(&r2links, cur, list) {
struct dahdi_mfcr2 *r2 = &cur->mfcr2;
if (ast_pthread_create(&r2->r2master, NULL, mfcr2_monitor, r2)) {
ast_log(LOG_ERROR, "Unable to start R2 monitor on channel group %d\n", x + 1);
return -1;
} else {
ast_verb(2, "Starting R2 monitor on channel group %d\n", x + 1);
if (r2->r2master == AST_PTHREADT_NULL) {
if (ast_pthread_create(&r2->r2master, NULL, mfcr2_monitor, r2)) {
ast_log(LOG_ERROR, "Unable to start R2 monitor on channel group %d\n", x + 1);
return -1;
} else {
ast_verb(2, "Starting R2 monitor on channel group %d\n", x + 1);
}
x++;
}
x++;
}
AST_LIST_UNLOCK(&r2links);
}