osmo-msc/include/osmocom/msc/gtphub.h

524 lines
18 KiB
C
Raw Normal View History

/* GTP Hub Implementation */
/* (C) 2015 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
* All Rights Reserved
*
* Author: Neels Hofmeyr
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stdint.h>
#include <sys/socket.h>
#include <osmocom/core/select.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/msc/gprs_sgsn.h>
/* support */
/* TODO move to osmocom/core/socket.c ? */
#include <netdb.h> /* for IPPROTO_* etc */
struct osmo_sockaddr {
struct sockaddr_storage a;
socklen_t l;
};
/* TODO move to osmocom/core/socket.c ? */
/*! \brief Initialize a sockaddr
* \param[out] addr Valid osmo_sockaddr pointer to write result to
* \param[in] family Address Family like AF_INET, AF_INET6, AF_UNSPEC
* \param[in] type Socket type like SOCK_DGRAM, SOCK_STREAM
* \param[in] proto Protocol like IPPROTO_TCP, IPPROTO_UDP
* \param[in] host Remote host name or IP address in string form
* \param[in] port Remote port number in host byte order
* \returns 0 on success, otherwise an error code (from getaddrinfo()).
*
* Copy the first result from a getaddrinfo() call with the given parameters to
* *addr and *addr_len. On error, do not change *addr and return nonzero.
*/
int osmo_sockaddr_init(struct osmo_sockaddr *addr,
uint16_t family, uint16_t type, uint8_t proto,
const char *host, uint16_t port);
/* Conveniently pass AF_UNSPEC, SOCK_DGRAM and IPPROTO_UDP to
* osmo_sockaddr_init(). */
static inline int osmo_sockaddr_init_udp(struct osmo_sockaddr *addr,
const char *host, uint16_t port)
{
return osmo_sockaddr_init(addr, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP,
host, port);
}
/*! \brief convert sockaddr to human readable string.
* \param[out] addr_str Valid pointer to a buffer of length addr_str_len.
* \param[in] addr_str_len Size of buffer addr_str points at.
* \param[out] port_str Valid pointer to a buffer of length port_str_len.
* \param[in] port_str_len Size of buffer port_str points at.
* \param[in] addr Binary representation as returned by osmo_sockaddr_init().
* \param[in] flags flags as passed to getnameinfo().
* \returns 0 on success, an error code on error.
*
* Return the IPv4 or IPv6 address string and the port (a.k.a. service) string
* representations of the given struct osmo_sockaddr in two caller provided
* char buffers. Flags of (NI_NUMERICHOST | NI_NUMERICSERV) return numeric
* address and port. Either one of addr_str or port_str may be NULL, in which
* case nothing is returned there.
*
* See also osmo_sockaddr_to_str() (less flexible, but much more convenient). */
int osmo_sockaddr_to_strs(char *addr_str, size_t addr_str_len,
char *port_str, size_t port_str_len,
const struct osmo_sockaddr *addr,
int flags);
/*! \brief concatenate the parts returned by osmo_sockaddr_to_strs().
* \param[in] addr Binary representation as returned by osmo_sockaddr_init().
* \param[in] buf A buffer to use for string operations.
* \param[in] buf_len Length of the buffer.
* \returns Address string (in buffer).
*
* Compose a string of the numeric IP-address and port represented by *addr of
* the form "<ip-addr> port <port>". The returned string is valid until the
* next invocation of this function.
*/
const char *osmo_sockaddr_to_strb(const struct osmo_sockaddr *addr,
char *buf, size_t buf_len);
/*! \brief conveniently return osmo_sockaddr_to_strb() in a static buffer.
* \param[in] addr Binary representation as returned by osmo_sockaddr_init().
* \returns Address string in static buffer.
*
* See osmo_sockaddr_to_strb().
*
* Note: only one osmo_sockaddr_to_str() call will work per print/log
* statement. For two or more, use osmo_sockaddr_to_strb() with a separate
* buffer each.
*/
const char *osmo_sockaddr_to_str(const struct osmo_sockaddr *addr);
/*! \brief compare two osmo_sockaddr.
* \param[in] a The first address to compare.
* \param[in] b The other address to compare.
* \returns 0 if equal, otherwise -1 or 1.
*/
int osmo_sockaddr_cmp(const struct osmo_sockaddr *a,
const struct osmo_sockaddr *b);
/*! \brief Overwrite *dst with *src.
* Like memcpy(), but copy only the valid bytes. */
void osmo_sockaddr_copy(struct osmo_sockaddr *dst,
const struct osmo_sockaddr *src);
/* general */
enum gtphub_plane_idx {
GTPH_PLANE_CTRL = 0,
GTPH_PLANE_USER = 1,
GTPH_PLANE_N
};
gtphub: track tunnels explicitly. So far, gtphub worked perfectly by only tracking single TEIs ... for probably most uses. But a Ctrl plane tunnel may have expired despite a still active corresponding User plane tunnel. The User plane would continue to work indefinitely, but if any Ctrl messages followed after more than six hours of Ctrl silence, they would have been dropped due to an expired TEI mapping. We want to - combine expiry of a user TEI with its ctrl TEI. (done in this patch) - upon delete PDP context, remove both user and ctrl TEI mappings. (future) - when a peer indicates a restart counter bump, invalidate its tunnels. (future) To facilitate these, track tunnels, complete with both SGSN's and GGSN's address, original and replaced TEIs, all for both user and ctrl plane, in a single struct. A single expiry entry handles the entire tunnel, instead of previously four separate expiries for each endpoint identifier. Add the concept of a "side", being either GGSN or SGSN, to index tunnel endpoint structs, and so on. Track the originating side in the gtp_packet_desc. Add header_tei_rx: set_tei() overwrites header_tei, but the originally received header TEI is still needed to match a Create PDP Context Response up with its Request (and for logging). Adjust the test suite to expect tunnel listing strings instead of TEI mappings, with a bonus of making it a lot easier to grok, and including the IP addresses. Add regression test for refreshing tunnel expiry upon use. Note: the current implementation is as slow as can possibly be, iterating all the tunnels all the time. Optimizations are kept for a future commit, on purpose. BTW, the sequence number mapping/unmapping structures remain unchanged. Sponsored-by: On-Waves ehi
2015-11-24 12:31:06 +00:00
enum gtphub_side_idx {
GTPH_SIDE_SGSN = 0,
GTPH_SIDE_GGSN = 1,
gtphub: track tunnels explicitly. So far, gtphub worked perfectly by only tracking single TEIs ... for probably most uses. But a Ctrl plane tunnel may have expired despite a still active corresponding User plane tunnel. The User plane would continue to work indefinitely, but if any Ctrl messages followed after more than six hours of Ctrl silence, they would have been dropped due to an expired TEI mapping. We want to - combine expiry of a user TEI with its ctrl TEI. (done in this patch) - upon delete PDP context, remove both user and ctrl TEI mappings. (future) - when a peer indicates a restart counter bump, invalidate its tunnels. (future) To facilitate these, track tunnels, complete with both SGSN's and GGSN's address, original and replaced TEIs, all for both user and ctrl plane, in a single struct. A single expiry entry handles the entire tunnel, instead of previously four separate expiries for each endpoint identifier. Add the concept of a "side", being either GGSN or SGSN, to index tunnel endpoint structs, and so on. Track the originating side in the gtp_packet_desc. Add header_tei_rx: set_tei() overwrites header_tei, but the originally received header TEI is still needed to match a Create PDP Context Response up with its Request (and for logging). Adjust the test suite to expect tunnel listing strings instead of TEI mappings, with a bonus of making it a lot easier to grok, and including the IP addresses. Add regression test for refreshing tunnel expiry upon use. Note: the current implementation is as slow as can possibly be, iterating all the tunnels all the time. Optimizations are kept for a future commit, on purpose. BTW, the sequence number mapping/unmapping structures remain unchanged. Sponsored-by: On-Waves ehi
2015-11-24 12:31:06 +00:00
GTPH_SIDE_N
};
#define for_each_side(I) for (I = 0; I < GTPH_SIDE_N; I++)
#define for_each_plane(I) for (I = 0; I < GTPH_PLANE_N; I++)
#define for_each_side_and_plane(I,J) for_each_side(I) for_each_plane(J)
gtphub: track tunnels explicitly. So far, gtphub worked perfectly by only tracking single TEIs ... for probably most uses. But a Ctrl plane tunnel may have expired despite a still active corresponding User plane tunnel. The User plane would continue to work indefinitely, but if any Ctrl messages followed after more than six hours of Ctrl silence, they would have been dropped due to an expired TEI mapping. We want to - combine expiry of a user TEI with its ctrl TEI. (done in this patch) - upon delete PDP context, remove both user and ctrl TEI mappings. (future) - when a peer indicates a restart counter bump, invalidate its tunnels. (future) To facilitate these, track tunnels, complete with both SGSN's and GGSN's address, original and replaced TEIs, all for both user and ctrl plane, in a single struct. A single expiry entry handles the entire tunnel, instead of previously four separate expiries for each endpoint identifier. Add the concept of a "side", being either GGSN or SGSN, to index tunnel endpoint structs, and so on. Track the originating side in the gtp_packet_desc. Add header_tei_rx: set_tei() overwrites header_tei, but the originally received header TEI is still needed to match a Create PDP Context Response up with its Request (and for logging). Adjust the test suite to expect tunnel listing strings instead of TEI mappings, with a bonus of making it a lot easier to grok, and including the IP addresses. Add regression test for refreshing tunnel expiry upon use. Note: the current implementation is as slow as can possibly be, iterating all the tunnels all the time. Optimizations are kept for a future commit, on purpose. BTW, the sequence number mapping/unmapping structures remain unchanged. Sponsored-by: On-Waves ehi
2015-11-24 12:31:06 +00:00
static inline int other_side_idx(int side_idx)
{
return (side_idx + 1) & 1;
}
extern const char* const gtphub_plane_idx_names[GTPH_PLANE_N];
extern const uint16_t gtphub_plane_idx_default_port[GTPH_PLANE_N];
extern const char* const gtphub_side_idx_names[GTPH_SIDE_N];
/* A host address in the form that is expected in the 7.7.32 GSN Address IE.
* len is either 4 (IPv4) or 16 (IPv6), any other value is invalid. If no
* address is set, len shall be 0. */
struct gsn_addr {
uint16_t len;
uint8_t buf[16];
};
void gsn_addr_copy(struct gsn_addr *gsna, const struct gsn_addr *src);
int gsn_addr_from_str(struct gsn_addr *gsna, const char *numeric_addr_str);
/* Return gsna in numeric string form, in a static buffer. */
const char *gsn_addr_to_str(const struct gsn_addr *gsna);
/* note: strbuf_len doesn't need to be larger than INET6_ADDRSTRLEN + 1. */
const char *gsn_addr_to_strb(const struct gsn_addr *gsna,
char *strbuf, int strbuf_len);
/* Return 1 on match, zero otherwise. */
int gsn_addr_same(const struct gsn_addr *a, const struct gsn_addr *b);
/* Decode sa to gsna. Return 0 on success. If port is non-NULL, the port number
* from sa is also returned. */
int gsn_addr_from_sockaddr(struct gsn_addr *gsna, uint16_t *port,
const struct osmo_sockaddr *sa);
/* expiry */
struct expiring_item;
typedef void (*del_cb_t)(struct expiring_item *);
struct expiring_item {
struct llist_head entry;
time_t expiry;
del_cb_t del_cb;
};
struct expiry {
int expiry_in_seconds;
struct llist_head items;
};
/* Initialize an expiry queue. */
void expiry_init(struct expiry *exq, int expiry_in_seconds);
/* Add a new mapping, or restart the expiry timeout for an already listed
* mapping. */
void expiry_add(struct expiry *exq, struct expiring_item *item, time_t now);
/* Initialize to all-empty; must be called before using the item in any way. */
void expiring_item_init(struct expiring_item *item);
/* Remove the given item from its expiry queue, and call item->del_cb, if set.
* This sets item->del_cb to NULL and is harmless when run a second time on the
* same item, so the del_cb may choose to call this function, too, to allow
* deleting items from several code paths. */
void expiring_item_del(struct expiring_item *item);
/* Carry out due expiry of mappings. Must be invoked regularly.
* 'now' is the current clock count in seconds and must correspond to the clock
* count passed to nr_map_add(). A monotonous clock counter should be used. */
int expiry_tick(struct expiry *exq, time_t now);
/* Expire all items. */
void expiry_clear(struct expiry *exq);
/* number map */
/* A number map assigns a "random" mapped number to each user provided number.
* If the same number is requested multiple times, the same mapped number is
* returned.
*
* Number maps plug into possibly shared pools and expiry queues, for example:
*
* mapA -----------+-> pool1 <-+-- mapB
* {10->1, 11->5} | {1, 2, 3, ...} | {10->2, 11->3}
* | |
* | |
* /-> \-> expiry1 <-/
* | (30 seconds)
* |
* mapC -------+-----> pool2 <-+-- mapD
* {10->1, 11->3} {1, 2, 3, ...} | {10->2, 11->5}
* |
* expiry2 <-/
* (60 seconds)
*
* A map contains mappings ("10->1"). Each map needs a number pool, which can
* be shared with other maps. Each new mapping receives a number from the pool,
* which is then unavailable to any other map using the same pool.
*
* A map may point at an expiry queue, in which case all mappings added to it
* are also appended to the expiry queue (using a separate llist entry in the
* mapping). Any number of maps may submit to the same expiry queue, if they
* desire the same expiry timeout. An expiry queue stores the mappings in
* chronological order, so that expiry checking is needed only from the start
* of the queue; hence only mappings with identical expiry timeout can be added
* to the same expiry queue. Upon expiry, a mapping is dropped from the map it
* was submitted at. expiry_tick() needs to be called regularly for each expiry
* queue.
*
* A nr_mapping can be embedded in a larger struct: each mapping can have a
* distinct destructor (del_cb), and each del_cb can figure out the container
* struct's address and free that upon expiry or manual deletion. So in expiry
* queues (and even maps), mappings of different container types can be mixed.
* This can help to drastically reduce the amount of unnecessary visits during
* expiry checking, for the case that no expiry is pending. An expiry queue
* always knows which mappings to expire next, because they are right at the
* start of its list.
*
* Mapping allocation and a del_cb are provided by the caller. If del_cb is
* NULL, no deallocation will be done (allowing statically allocated entries).
*/
typedef unsigned int nr_t;
/* Generator for unused numbers. So far this counts upwards from zero, but the
* implementation may change in the future. Treat this like an opaque struct.
* If this becomes random, the tests need to be fixed. */
struct nr_pool {
nr_t last_nr;
nr_t nr_min;
nr_t nr_max;
};
struct nr_mapping {
struct llist_head entry;
struct expiring_item expiry_entry;
void *origin;
nr_t orig;
nr_t repl;
};
struct nr_map {
struct nr_pool *pool; /* multiple nr_maps can share a nr_pool. */
struct expiry *add_items_to_expiry;
struct llist_head mappings;
};
void nr_pool_init(struct nr_pool *pool, nr_t nr_min, nr_t nr_max);
/* Return the next unused number from the nr_pool. */
nr_t nr_pool_next(struct nr_pool *pool);
/* Initialize the nr_mapping to zero/empty values. */
void nr_mapping_init(struct nr_mapping *mapping);
/* Remove the given mapping from its parent map and expiry queue, and call
* mapping->del_cb, if set. */
void nr_mapping_del(struct nr_mapping *mapping);
/* Initialize an (already allocated) nr_map, and set the map's number pool.
* Multiple nr_map instances may use the same nr_pool. Set the nr_map's expiry
* queue to exq, so that all added mappings are automatically expired after the
* time configured in exq. exq may be NULL to disable automatic expiry. */
void nr_map_init(struct nr_map *map, struct nr_pool *pool,
struct expiry *exq);
/* Add a new entry to the map. mapping->orig, mapping->origin and
* mapping->del_cb must be set before calling this function. The remaining
* fields of *mapping will be overwritten. mapping->repl is set to the next
* available mapped number from map->pool. 'now' is the current clock count in
* seconds; if no map->expiry is used, just pass 0 for 'now'. */
void nr_map_add(struct nr_map *map, struct nr_mapping *mapping,
time_t now);
/* Restart the timeout for the given mapping. mapping must be a member of map.
*/
void nr_map_refresh(struct nr_map *map, struct nr_mapping *mapping,
time_t now);
/* Return a known mapping from nr_orig and the given origin. If nr_orig is
* unknown, return NULL. */
struct nr_mapping *nr_map_get(const struct nr_map *map,
void *origin, nr_t nr_orig);
/* Return a known mapping to nr_repl. If nr_repl is unknown, return NULL. */
struct nr_mapping *nr_map_get_inv(const struct nr_map *map, nr_t nr_repl);
/* Remove all mappings from map. */
void nr_map_clear(struct nr_map *map);
/* Return 1 if map has no entries, 0 otherwise. */
int nr_map_empty(const struct nr_map *map);
/* config */
static const int GTPH_EXPIRE_QUICKLY_SECS = 30; /* TODO is there a spec for this? */
static const int GTPH_EXPIRE_SLOWLY_MINUTES = 6 * 60; /* TODO is there a spec for this? */
struct gtphub_cfg_addr {
const char *addr_str;
uint16_t port;
};
struct gtphub_cfg_bind {
struct gtphub_cfg_addr bind;
};
struct gtphub_cfg {
struct gtphub_cfg_bind to_gsns[GTPH_SIDE_N][GTPH_PLANE_N];
struct gtphub_cfg_addr proxy[GTPH_SIDE_N][GTPH_PLANE_N];
int sgsn_use_sender; /* Use sender, not GSN addr IE with std ports */
};
/* state */
struct gtphub_peer {
struct llist_head entry;
struct llist_head addresses; /* Alternatives, not load balancing. */
struct nr_pool seq_pool;
struct nr_map seq_map;
};
struct gtphub_peer_addr {
struct llist_head entry;
struct gtphub_peer *peer;
struct gsn_addr addr;
struct llist_head ports;
};
struct gtphub_peer_port {
struct llist_head entry;
struct gtphub_peer_addr *peer_addr;
uint16_t port;
unsigned int ref_count; /* references from other peers' seq_maps */
struct osmo_sockaddr sa; /* a "cache" for (peer_addr->addr, port) */
int last_restart_count; /* 0..255 = valid, all else means unknown */
struct rate_ctr_group *counters_io;
};
gtphub: track tunnels explicitly. So far, gtphub worked perfectly by only tracking single TEIs ... for probably most uses. But a Ctrl plane tunnel may have expired despite a still active corresponding User plane tunnel. The User plane would continue to work indefinitely, but if any Ctrl messages followed after more than six hours of Ctrl silence, they would have been dropped due to an expired TEI mapping. We want to - combine expiry of a user TEI with its ctrl TEI. (done in this patch) - upon delete PDP context, remove both user and ctrl TEI mappings. (future) - when a peer indicates a restart counter bump, invalidate its tunnels. (future) To facilitate these, track tunnels, complete with both SGSN's and GGSN's address, original and replaced TEIs, all for both user and ctrl plane, in a single struct. A single expiry entry handles the entire tunnel, instead of previously four separate expiries for each endpoint identifier. Add the concept of a "side", being either GGSN or SGSN, to index tunnel endpoint structs, and so on. Track the originating side in the gtp_packet_desc. Add header_tei_rx: set_tei() overwrites header_tei, but the originally received header TEI is still needed to match a Create PDP Context Response up with its Request (and for logging). Adjust the test suite to expect tunnel listing strings instead of TEI mappings, with a bonus of making it a lot easier to grok, and including the IP addresses. Add regression test for refreshing tunnel expiry upon use. Note: the current implementation is as slow as can possibly be, iterating all the tunnels all the time. Optimizations are kept for a future commit, on purpose. BTW, the sequence number mapping/unmapping structures remain unchanged. Sponsored-by: On-Waves ehi
2015-11-24 12:31:06 +00:00
struct gtphub_tunnel_endpoint {
struct gtphub_peer_port *peer;
uint32_t tei_orig; /* from/to peer */
struct rate_ctr_group *counters_io;
gtphub: track tunnels explicitly. So far, gtphub worked perfectly by only tracking single TEIs ... for probably most uses. But a Ctrl plane tunnel may have expired despite a still active corresponding User plane tunnel. The User plane would continue to work indefinitely, but if any Ctrl messages followed after more than six hours of Ctrl silence, they would have been dropped due to an expired TEI mapping. We want to - combine expiry of a user TEI with its ctrl TEI. (done in this patch) - upon delete PDP context, remove both user and ctrl TEI mappings. (future) - when a peer indicates a restart counter bump, invalidate its tunnels. (future) To facilitate these, track tunnels, complete with both SGSN's and GGSN's address, original and replaced TEIs, all for both user and ctrl plane, in a single struct. A single expiry entry handles the entire tunnel, instead of previously four separate expiries for each endpoint identifier. Add the concept of a "side", being either GGSN or SGSN, to index tunnel endpoint structs, and so on. Track the originating side in the gtp_packet_desc. Add header_tei_rx: set_tei() overwrites header_tei, but the originally received header TEI is still needed to match a Create PDP Context Response up with its Request (and for logging). Adjust the test suite to expect tunnel listing strings instead of TEI mappings, with a bonus of making it a lot easier to grok, and including the IP addresses. Add regression test for refreshing tunnel expiry upon use. Note: the current implementation is as slow as can possibly be, iterating all the tunnels all the time. Optimizations are kept for a future commit, on purpose. BTW, the sequence number mapping/unmapping structures remain unchanged. Sponsored-by: On-Waves ehi
2015-11-24 12:31:06 +00:00
};
struct gtphub_tunnel {
struct llist_head entry;
struct expiring_item expiry_entry;
uint32_t tei_repl; /* unique TEI to replace peers' TEIs */
gtphub: track tunnels explicitly. So far, gtphub worked perfectly by only tracking single TEIs ... for probably most uses. But a Ctrl plane tunnel may have expired despite a still active corresponding User plane tunnel. The User plane would continue to work indefinitely, but if any Ctrl messages followed after more than six hours of Ctrl silence, they would have been dropped due to an expired TEI mapping. We want to - combine expiry of a user TEI with its ctrl TEI. (done in this patch) - upon delete PDP context, remove both user and ctrl TEI mappings. (future) - when a peer indicates a restart counter bump, invalidate its tunnels. (future) To facilitate these, track tunnels, complete with both SGSN's and GGSN's address, original and replaced TEIs, all for both user and ctrl plane, in a single struct. A single expiry entry handles the entire tunnel, instead of previously four separate expiries for each endpoint identifier. Add the concept of a "side", being either GGSN or SGSN, to index tunnel endpoint structs, and so on. Track the originating side in the gtp_packet_desc. Add header_tei_rx: set_tei() overwrites header_tei, but the originally received header TEI is still needed to match a Create PDP Context Response up with its Request (and for logging). Adjust the test suite to expect tunnel listing strings instead of TEI mappings, with a bonus of making it a lot easier to grok, and including the IP addresses. Add regression test for refreshing tunnel expiry upon use. Note: the current implementation is as slow as can possibly be, iterating all the tunnels all the time. Optimizations are kept for a future commit, on purpose. BTW, the sequence number mapping/unmapping structures remain unchanged. Sponsored-by: On-Waves ehi
2015-11-24 12:31:06 +00:00
struct gtphub_tunnel_endpoint endpoint[GTPH_SIDE_N][GTPH_PLANE_N];
};
struct gtphub_bind {
struct gsn_addr local_addr;
uint16_t local_port;
struct osmo_fd ofd;
/* list of struct gtphub_peer */
struct llist_head peers;
const char *label; /* For logging */
struct rate_ctr_group *counters_io;
};
struct gtphub_resolved_ggsn {
struct llist_head entry;
struct expiring_item expiry_entry;
/* The APN OI, the Operator Identifier, is the combined address,
* including parts of the IMSI and APN NI, and ending with ".gprs". */
char apn_oi_str[GSM_APN_LENGTH];
/* Which address and port we resolved that to. */
struct gtphub_peer_port *peer;
};
struct gtphub {
struct gtphub_bind to_gsns[GTPH_SIDE_N][GTPH_PLANE_N];
/* pointers to an entry of to_gsns[s][p].peers */
struct gtphub_peer_port *proxy[GTPH_SIDE_N][GTPH_PLANE_N];
/* The TEI numbers will simply wrap and be reused, which will work out
* in practice. Problems would arise if one given peer maintained the
* same TEI for a time long enough for the TEI nr map to wrap an entire
* uint32_t; if a new TEI were mapped every second, this would take
* more than 100 years (in which a single given TEI must not time out)
* to cause a problem. */
struct nr_pool tei_pool;
gtphub: track tunnels explicitly. So far, gtphub worked perfectly by only tracking single TEIs ... for probably most uses. But a Ctrl plane tunnel may have expired despite a still active corresponding User plane tunnel. The User plane would continue to work indefinitely, but if any Ctrl messages followed after more than six hours of Ctrl silence, they would have been dropped due to an expired TEI mapping. We want to - combine expiry of a user TEI with its ctrl TEI. (done in this patch) - upon delete PDP context, remove both user and ctrl TEI mappings. (future) - when a peer indicates a restart counter bump, invalidate its tunnels. (future) To facilitate these, track tunnels, complete with both SGSN's and GGSN's address, original and replaced TEIs, all for both user and ctrl plane, in a single struct. A single expiry entry handles the entire tunnel, instead of previously four separate expiries for each endpoint identifier. Add the concept of a "side", being either GGSN or SGSN, to index tunnel endpoint structs, and so on. Track the originating side in the gtp_packet_desc. Add header_tei_rx: set_tei() overwrites header_tei, but the originally received header TEI is still needed to match a Create PDP Context Response up with its Request (and for logging). Adjust the test suite to expect tunnel listing strings instead of TEI mappings, with a bonus of making it a lot easier to grok, and including the IP addresses. Add regression test for refreshing tunnel expiry upon use. Note: the current implementation is as slow as can possibly be, iterating all the tunnels all the time. Optimizations are kept for a future commit, on purpose. BTW, the sequence number mapping/unmapping structures remain unchanged. Sponsored-by: On-Waves ehi
2015-11-24 12:31:06 +00:00
struct llist_head tunnels; /* struct gtphub_tunnel */
struct llist_head pending_deletes; /* opaque (gtphub.c) */
gtphub: track tunnels explicitly. So far, gtphub worked perfectly by only tracking single TEIs ... for probably most uses. But a Ctrl plane tunnel may have expired despite a still active corresponding User plane tunnel. The User plane would continue to work indefinitely, but if any Ctrl messages followed after more than six hours of Ctrl silence, they would have been dropped due to an expired TEI mapping. We want to - combine expiry of a user TEI with its ctrl TEI. (done in this patch) - upon delete PDP context, remove both user and ctrl TEI mappings. (future) - when a peer indicates a restart counter bump, invalidate its tunnels. (future) To facilitate these, track tunnels, complete with both SGSN's and GGSN's address, original and replaced TEIs, all for both user and ctrl plane, in a single struct. A single expiry entry handles the entire tunnel, instead of previously four separate expiries for each endpoint identifier. Add the concept of a "side", being either GGSN or SGSN, to index tunnel endpoint structs, and so on. Track the originating side in the gtp_packet_desc. Add header_tei_rx: set_tei() overwrites header_tei, but the originally received header TEI is still needed to match a Create PDP Context Response up with its Request (and for logging). Adjust the test suite to expect tunnel listing strings instead of TEI mappings, with a bonus of making it a lot easier to grok, and including the IP addresses. Add regression test for refreshing tunnel expiry upon use. Note: the current implementation is as slow as can possibly be, iterating all the tunnels all the time. Optimizations are kept for a future commit, on purpose. BTW, the sequence number mapping/unmapping structures remain unchanged. Sponsored-by: On-Waves ehi
2015-11-24 12:31:06 +00:00
struct llist_head ggsn_lookups; /* opaque (gtphub_ares.c) */
struct llist_head resolved_ggsns; /* struct gtphub_resolved_ggsn */
struct osmo_timer_list gc_timer;
struct expiry expire_quickly;
struct expiry expire_slowly;
uint8_t restart_counter;
int sgsn_use_sender;
};
struct gtp_packet_desc;
/* api */
int gtphub_vty_init(struct gtphub *global_hub, struct gtphub_cfg *global_cfg);
int gtphub_cfg_read(struct gtphub_cfg *cfg, const char *config_file);
/* Initialize and start gtphub: bind to ports, run expiry timers. */
int gtphub_start(struct gtphub *hub, struct gtphub_cfg *cfg,
uint8_t restart_counter);
/* Close all sockets, expire all maps and peers and free all allocations. The
* struct is then unusable, unless gtphub_start() is run on it again. */
void gtphub_stop(struct gtphub *hub);
time_t gtphub_now(void);
/* Remove expired items, empty peers, ... */
void gtphub_gc(struct gtphub *hub, time_t now);
/* Return the string of the first address for this peer. */
const char *gtphub_peer_str(struct gtphub_peer *peer);
gtphub: track tunnels explicitly. So far, gtphub worked perfectly by only tracking single TEIs ... for probably most uses. But a Ctrl plane tunnel may have expired despite a still active corresponding User plane tunnel. The User plane would continue to work indefinitely, but if any Ctrl messages followed after more than six hours of Ctrl silence, they would have been dropped due to an expired TEI mapping. We want to - combine expiry of a user TEI with its ctrl TEI. (done in this patch) - upon delete PDP context, remove both user and ctrl TEI mappings. (future) - when a peer indicates a restart counter bump, invalidate its tunnels. (future) To facilitate these, track tunnels, complete with both SGSN's and GGSN's address, original and replaced TEIs, all for both user and ctrl plane, in a single struct. A single expiry entry handles the entire tunnel, instead of previously four separate expiries for each endpoint identifier. Add the concept of a "side", being either GGSN or SGSN, to index tunnel endpoint structs, and so on. Track the originating side in the gtp_packet_desc. Add header_tei_rx: set_tei() overwrites header_tei, but the originally received header TEI is still needed to match a Create PDP Context Response up with its Request (and for logging). Adjust the test suite to expect tunnel listing strings instead of TEI mappings, with a bonus of making it a lot easier to grok, and including the IP addresses. Add regression test for refreshing tunnel expiry upon use. Note: the current implementation is as slow as can possibly be, iterating all the tunnels all the time. Optimizations are kept for a future commit, on purpose. BTW, the sequence number mapping/unmapping structures remain unchanged. Sponsored-by: On-Waves ehi
2015-11-24 12:31:06 +00:00
/* Return a human readable description of tun in a static buffer. */
const char *gtphub_tunnel_str(struct gtphub_tunnel *tun);
/* Return 1 if all of tun's endpoints are fully established, 0 otherwise. */
int gtphub_tunnel_complete(struct gtphub_tunnel *tun);
int gtphub_handle_buf(struct gtphub *hub,
unsigned int side_idx,
unsigned int port_idx,
const struct osmo_sockaddr *from_addr,
uint8_t *buf,
size_t received,
time_t now,
uint8_t **reply_buf,
struct osmo_fd **to_ofd,
struct osmo_sockaddr *to_addr);
struct gtphub_peer_port *gtphub_port_have(struct gtphub *hub,
struct gtphub_bind *bind,
const struct gsn_addr *addr,
uint16_t port);
struct gtphub_peer_port *gtphub_port_find_sa(const struct gtphub_bind *bind,
const struct osmo_sockaddr *addr);
void gtphub_resolved_ggsn(struct gtphub *hub, const char *apn_oi_str,
struct gsn_addr *resolved_addr,
time_t now);
const char *gtphub_port_str(struct gtphub_peer_port *port);
int gtphub_write(const struct osmo_fd *to,
const struct osmo_sockaddr *to_addr,
const uint8_t *buf, size_t buf_len);