diff options
author | Holger Hans Peter Freyther <zecke@selfish.org> | 2011-01-20 21:11:13 +0100 |
---|---|---|
committer | Holger Hans Peter Freyther <zecke@selfish.org> | 2011-01-20 23:36:18 +0100 |
commit | 3472eb53f1d5b7857247489d95e39f688039e401 (patch) | |
tree | ba370c9b875a6e7707a1ea18bf420f9982ec7eb7 | |
parent | 050577a088f6e8cfd02dca82fe47b4b34b53ae4e (diff) |
mtp: Allow to run multiple links through the same socketmultiple-linksets-2
The UDP socket will be shared between multiple links, the
snmp session will be also shared between multiple links on
the same hardware.
-rw-r--r-- | include/bsc_data.h | 22 | ||||
-rw-r--r-- | src/link_udp.c | 88 | ||||
-rw-r--r-- | src/links.c | 12 |
3 files changed, 88 insertions, 34 deletions
diff --git a/include/bsc_data.h b/include/bsc_data.h index 758932f..587afec 100644 --- a/include/bsc_data.h +++ b/include/bsc_data.h @@ -40,19 +40,27 @@ struct bsc_data; struct snmp_mtp_session; +struct mtp_udp_data { + struct write_queue write_queue; + struct snmp_mtp_session *session; + + struct llist_head links; +}; + struct mtp_udp_link { /* subclass */ struct mtp_link base; /* UDP specific stuff */ struct bsc_data *bsc; - struct write_queue write_queue; - struct sockaddr_in remote; - struct snmp_mtp_session *session; int link_index; int reset_timeout; -}; + struct sockaddr_in remote; + + struct mtp_udp_data *data; + struct llist_head entry; +}; struct bsc_data { /* MSC */ @@ -88,6 +96,9 @@ struct bsc_data { /* mgcp messgaes */ struct write_queue mgcp_agent; + /* udp code */ + struct mtp_udp_data udp_data; + int dpc; int opc; int sccp_opc; @@ -129,7 +140,8 @@ void update_con_state(struct mtp_link_set *link, int rc, struct sccp_parse_resul unsigned int sls_for_src_ref(struct sccp_source_reference *ref); /* udp init */ -int link_udp_init(struct mtp_udp_link *data, int src_port, const char *dest_ip, int port); +int link_global_init(struct mtp_udp_data *data, int src_port); +int link_udp_init(struct mtp_udp_link *data, const char *dest_ip, int port); int link_init(struct bsc_data *bsc); int link_shutdown_all(struct mtp_link_set *); int link_reset_all(struct mtp_link_set *); diff --git a/src/link_udp.c b/src/link_udp.c index 7e0b94b..04dcec8 100644 --- a/src/link_udp.c +++ b/src/link_udp.c @@ -35,12 +35,30 @@ #include <string.h> #include <unistd.h> +static struct mtp_udp_link *find_link(struct mtp_udp_data *data, uint16_t link_index) +{ + struct mtp_udp_link *lnk; + + llist_for_each_entry(lnk, &data->links, entry) + if (lnk->link_index == link_index) + return lnk; + + return NULL; +} + + static int udp_write_cb(struct bsc_fd *fd, struct msgb *msg) { + struct mtp_udp_data *data; struct mtp_udp_link *link; int rc; - link = fd->data; + data = fd->data; + link = find_link(data, msg->cb[0]); + if (!link) { + LOGP(DINP, LOGL_ERROR, "Failed to find link with %lu\n", msg->cb[0]); + return -1; + } LOGP(DINP, LOGL_DEBUG, "Sending MSU: %s\n", hexdump(msg->data, msg->len)); if (link->base.pcap_fd >= 0) @@ -59,6 +77,7 @@ static int udp_write_cb(struct bsc_fd *fd, struct msgb *msg) static int udp_read_cb(struct bsc_fd *fd) { + struct mtp_udp_data *data; struct mtp_link *link; struct udp_data_hdr *hdr; struct msgb *msg; @@ -72,7 +91,7 @@ static int udp_read_cb(struct bsc_fd *fd) } - link = (struct mtp_link *) fd->data; + data = (struct mtp_udp_data *) fd->data; rc = read(fd->fd, msg->data, 2096); if (rc < sizeof(*hdr)) { LOGP(DINP, LOGL_ERROR, "Failed to read at least size of the header: %d\n", rc); @@ -80,6 +99,16 @@ static int udp_read_cb(struct bsc_fd *fd) goto exit; } + hdr = (struct udp_data_hdr *) msgb_put(msg, sizeof(*hdr)); + link = (struct mtp_link *) find_link(data, ntohs(hdr->data_link_index)); + + if (!link) { + LOGP(DINP, LOGL_ERROR, "No link registered for %d\n", + ntohs(hdr->data_link_index)); + goto exit; + } + + /* throw away data as the link is down */ if (link->set->available == 0) { LOGP(DINP, LOGL_ERROR, "The link is down. Not forwarding.\n"); @@ -87,8 +116,6 @@ static int udp_read_cb(struct bsc_fd *fd) goto exit; } - hdr = (struct udp_data_hdr *) msgb_put(msg, sizeof(*hdr)); - if (hdr->data_type == UDP_DATA_RETR_COMPL || hdr->data_type == UDP_DATA_RETR_IMPOS) { LOGP(DINP, LOGL_ERROR, "Link retrieval done. Restarting the link.\n"); mtp_link_failure(link); @@ -129,7 +156,7 @@ static void do_start(void *_data) { struct mtp_udp_link *link = (struct mtp_udp_link *) _data; - snmp_mtp_activate(link->session, link->link_index); + snmp_mtp_activate(link->data->session, link->link_index); mtp_link_up(&link->base); } @@ -142,7 +169,7 @@ static int udp_link_reset(struct mtp_link *link) LOGP(DINP, LOGL_NOTICE, "Will restart SLTM transmission in %d seconds.\n", ulnk->reset_timeout); - snmp_mtp_deactivate(ulnk->session, ulnk->link_index); + snmp_mtp_deactivate(ulnk->data->session, ulnk->link_index); mtp_link_down(link); /* restart the link in 90 seconds... to force a timeout on the BSC */ @@ -166,7 +193,9 @@ static int udp_link_write(struct mtp_link *link, struct msgb *msg) hdr->user_context = 0; hdr->data_length = htonl(msgb_l2len(msg)); - if (write_queue_enqueue(&ulnk->write_queue, msg) != 0) { + msg->cb[0] = ulnk->link_index; + + if (write_queue_enqueue(&ulnk->data->write_queue, msg) != 0) { LOGP(DINP, LOGL_ERROR, "Failed to enqueue msg.\n"); msgb_free(msg); return -1; @@ -182,14 +211,8 @@ static int udp_link_start(struct mtp_link *link) return 0; } -int link_udp_init(struct mtp_udp_link *link, int src_port, const char *remote, int remote_port) +int link_udp_init(struct mtp_udp_link *link, const char *remote, int port) { - struct sockaddr_in addr; - int fd; - int on; - - write_queue_init(&link->write_queue, 100); - /* function table */ link->base.shutdown = udp_link_dummy; link->base.clear_queue = udp_link_dummy; @@ -198,13 +221,33 @@ int link_udp_init(struct mtp_udp_link *link, int src_port, const char *remote, i link->base.start = udp_link_start; link->base.write = udp_link_write; + /* prepare the remote */ + memset(&link->remote, 0, sizeof(link->remote)); + link->remote.sin_family = AF_INET; + link->remote.sin_port = htons(port); + inet_aton(remote, &link->remote.sin_addr); + + /* add it to the list of udp connections */ + llist_add(&link->entry, &link->data->links); + return 0; +} + +int link_global_init(struct mtp_udp_data *data, int src_port) +{ + struct sockaddr_in addr; + int fd; + int on; + + INIT_LLIST_HEAD(&data->links); + write_queue_init(&data->write_queue, 100); + /* socket creation */ - link->write_queue.bfd.data = link; - link->write_queue.bfd.when = BSC_FD_READ; - link->write_queue.read_cb = udp_read_cb; - link->write_queue.write_cb = udp_write_cb; + data->write_queue.bfd.data = data; + data->write_queue.bfd.when = BSC_FD_READ; + data->write_queue.read_cb = udp_read_cb; + data->write_queue.write_cb = udp_write_cb; - link->write_queue.bfd.fd = fd = socket(AF_INET, SOCK_DGRAM, 0); + data->write_queue.bfd.fd = fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { LOGP(DINP, LOGL_ERROR, "Failed to create UDP socket.\n"); return -1; @@ -225,12 +268,7 @@ int link_udp_init(struct mtp_udp_link *link, int src_port, const char *remote, i } /* now connect the socket to the remote */ - memset(&link->remote, 0, sizeof(link->remote)); - link->remote.sin_family = AF_INET; - link->remote.sin_port = htons(remote_port); - inet_aton(remote, &link->remote.sin_addr); - - if (bsc_register_fd(&link->write_queue.bfd) != 0) { + if (bsc_register_fd(&data->write_queue.bfd) != 0) { LOGP(DINP, LOGL_ERROR, "Failed to register BFD.\n"); close(fd); return -1; diff --git a/src/links.c b/src/links.c index 6374afd..bf282b6 100644 --- a/src/links.c +++ b/src/links.c @@ -114,6 +114,7 @@ int link_init(struct bsc_data *bsc) lnk = talloc_zero(bsc->link_set, struct mtp_udp_link); lnk->base.pcap_fd = bsc->pcap_fd; lnk->bsc = bsc; + lnk->data = &bsc->udp_data; lnk->link_index = 1; lnk->reset_timeout = bsc->udp_reset_timeout; mtp_link_set_add_link(bsc->link_set, (struct mtp_link *) lnk); @@ -126,12 +127,15 @@ int link_init(struct bsc_data *bsc) LOGP(DINP, LOGL_NOTICE, "Using UDP MTP mode.\n"); /* setup SNMP first, it is blocking */ - lnk->session = snmp_mtp_session_create(bsc->udp_ip); - if (!lnk->session) + bsc->udp_data.session = snmp_mtp_session_create(bsc->udp_ip); + if (!bsc->udp_data.session) + return -1; + + if (link_global_init(&bsc->udp_data, bsc->src_port) != 0) return -1; /* now connect to the transport */ - if (link_udp_init(lnk, bsc->src_port, bsc->udp_ip, bsc->udp_port) != 0) + if (link_udp_init(lnk, bsc->udp_ip, bsc->udp_port) != 0) return -1; /* @@ -140,7 +144,7 @@ int link_init(struct bsc_data *bsc) * SLTM and it begins a reset. Then we will take it up * again and do the usual business. */ - snmp_mtp_deactivate(lnk->session, + snmp_mtp_deactivate(lnk->data->session, lnk->link_index); bsc->start_timer.cb = start_rest; bsc->start_timer.data = &bsc; |