diff options
Diffstat (limited to 'src/gb/gprs_ns2_fr.c')
-rw-r--r-- | src/gb/gprs_ns2_fr.c | 206 |
1 files changed, 60 insertions, 146 deletions
diff --git a/src/gb/gprs_ns2_fr.c b/src/gb/gprs_ns2_fr.c index 84f37846..f6bee39c 100644 --- a/src/gb/gprs_ns2_fr.c +++ b/src/gb/gprs_ns2_fr.c @@ -55,13 +55,10 @@ #include <osmocom/core/timer.h> #include <osmocom/core/talloc.h> #include <osmocom/gprs/gprs_ns2.h> +#include <osmocom/core/netdev.h> #include <osmocom/gprs/protocol/gsm_08_16.h> #include <osmocom/gprs/protocol/gsm_08_18.h> -#ifdef ENABLE_LIBMNL -#include <osmocom/core/mnl.h> -#endif - #include "config.h" #include "common_vty.h" #include "gprs_ns2_internal.h" @@ -83,11 +80,6 @@ /* nanoseconds per bit (504) */ #define BIT_DURATION_NS (1000000000 / SUPERCHANNEL_LINERATE) -struct gre_hdr { - uint16_t flags; - uint16_t ptype; -} __attribute__ ((packed)); - static void free_bind(struct gprs_ns2_vc_bind *bind); static int fr_dlci_rx_cb(void *cb_data, struct msgb *msg); @@ -97,11 +89,12 @@ struct gprs_ns2_vc_driver vc_driver_fr = { }; struct priv_bind { + struct osmo_netdev *netdev; char netif[IFNAMSIZ]; struct osmo_fr_link *link; int ifindex; bool if_running; - /* backlog queue for AF_PACKET / ENOBUFS handling (see OS#4993) */ + /* backlog queue for AF_PACKET / ENOBUFS handling (see OS#4995) */ struct { /* file-descriptor for AF_PACKET socket */ struct osmo_fd ofd; @@ -177,6 +170,7 @@ static void free_bind(struct gprs_ns2_vc_bind *bind) } msgb_free(priv->backlog.lmi_msg); + osmo_netdev_free(priv->netdev); osmo_fr_link_free(priv->link); osmo_fd_close(&priv->backlog.ofd); talloc_free(priv); @@ -256,13 +250,13 @@ static int fr_netif_ofd_cb(struct osmo_fd *bfd, uint32_t what) if (!(what & OSMO_FD_READ)) return 0; - msg = msgb_alloc(NS_ALLOC_SIZE, "Gb/NS/FR/GRE Rx"); + msg = msgb_alloc(NS_ALLOC_SIZE, "Gb/NS/FR Rx"); if (!msg) return -ENOMEM; rc = recvfrom(bfd->fd, msg->data, NS_ALLOC_SIZE, 0, (struct sockaddr *)&sll, &sll_len); if (rc < 0) { - LOGBIND(bind, LOGL_ERROR, "recv error %s during NS-FR-GRE recv\n", strerror(errno)); + LOGBIND(bind, LOGL_ERROR, "recv error %s during NS-FR recv\n", strerror(errno)); goto out_err; } else if (rc == 0) { goto out_err; @@ -338,16 +332,26 @@ int gprs_ns2_is_fr_bind(struct gprs_ns2_vc_bind *bind) static int fr_vc_sendmsg(struct gprs_ns2_vc *nsvc, struct msgb *msg) { struct priv_vc *vcpriv = nsvc->priv; + unsigned int vc_len = msgb_length(msg); + int rc; msg->dst = vcpriv->dlc; - return osmo_fr_tx_dlc(msg); + rc = osmo_fr_tx_dlc(msg); + if (OSMO_LIKELY(rc >= 0)) { + RATE_CTR_INC_NS(nsvc, NS_CTR_PKTS_OUT); + RATE_CTR_ADD_NS(nsvc, NS_CTR_BYTES_OUT, vc_len); + } else { + RATE_CTR_INC_NS(nsvc, NS_CTR_PKTS_OUT_DROP); + RATE_CTR_ADD_NS(nsvc, NS_CTR_BYTES_OUT_DROP, vc_len); + } + return rc; } static void enqueue_at_head(struct gprs_ns2_vc_bind *bind, struct msgb *msg) { struct priv_bind *priv = bind->priv; llist_add(&msg->list, &priv->backlog.list); - osmo_stat_item_inc(bind->statg->items[NS2_BIND_STAT_BACKLOG_LEN], 1); + osmo_stat_item_inc(osmo_stat_item_group_get_item(bind->statg, NS2_BIND_STAT_BACKLOG_LEN), 1); osmo_timer_schedule(&priv->backlog.timer, 0, priv->backlog.retry_us); } @@ -355,7 +359,7 @@ static void enqueue_at_tail(struct gprs_ns2_vc_bind *bind, struct msgb *msg) { struct priv_bind *priv = bind->priv; llist_add_tail(&msg->list, &priv->backlog.list); - osmo_stat_item_inc(bind->statg->items[NS2_BIND_STAT_BACKLOG_LEN], 1); + osmo_stat_item_inc(osmo_stat_item_group_get_item(bind->statg, NS2_BIND_STAT_BACKLOG_LEN), 1); osmo_timer_schedule(&priv->backlog.timer, 0, priv->backlog.retry_us); } @@ -439,7 +443,7 @@ static void fr_backlog_timer_cb(void *data) llist_add(&msg->list, &priv->backlog.list); break; } - osmo_stat_item_dec(bind->statg->items[NS2_BIND_STAT_BACKLOG_LEN], 1); + osmo_stat_item_dec(osmo_stat_item_group_get_item(bind->statg, NS2_BIND_STAT_BACKLOG_LEN), 1); } restart_timer: @@ -520,60 +524,14 @@ static int open_socket(int ifindex, const struct gprs_ns2_vc_bind *nsbind) return fd; } -#ifdef ENABLE_LIBMNL - -#include <osmocom/core/mnl.h> -#include <linux/if_link.h> -#include <linux/rtnetlink.h> - -#ifndef ARPHRD_FRAD -#define ARPHRD_FRAD 770 -#endif - -/* validate the netlink attributes */ -static int data_attr_cb(const struct nlattr *attr, void *data) -{ - const struct nlattr **tb = data; - int type = mnl_attr_get_type(attr); - - if (mnl_attr_type_valid(attr, IFLA_MAX) < 0) - return MNL_CB_OK; - - switch (type) { - case IFLA_MTU: - if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) - return MNL_CB_ERROR; - break; - case IFLA_IFNAME: - if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0) - return MNL_CB_ERROR; - break; - } - tb[type] = attr; - return MNL_CB_OK; -} - -/* find the bind for the netdev (if any) */ -static struct gprs_ns2_vc_bind *bind4netdev(struct gprs_ns2_inst *nsi, const char *ifname) -{ - struct gprs_ns2_vc_bind *bind; - - llist_for_each_entry(bind, &nsi->binding, list) { - struct priv_bind *bpriv = bind->priv; - if (!strcmp(bpriv->netif, ifname)) - return bind; - } - - return NULL; -} - -static void link_state_change(struct gprs_ns2_vc_bind *bind, bool if_running) +static int gprs_n2_fr_ifupdown_ind_cb(struct osmo_netdev *netdev, bool if_running) { + struct gprs_ns2_vc_bind *bind = osmo_netdev_get_priv_data(netdev); struct priv_bind *bpriv = bind->priv; struct msgb *msg, *msg2; if (bpriv->if_running == if_running) - return; + return 0; LOGBIND(bind, LOGL_NOTICE, "FR net-device '%s': Physical link state changed: %s\n", bpriv->netif, if_running ? "UP" : "DOWN"); @@ -594,89 +552,36 @@ static void link_state_change(struct gprs_ns2_vc_bind *bind, bool if_running) } bpriv->if_running = if_running; + return 0; } -static void mtu_change(struct gprs_ns2_vc_bind *bind, uint32_t mtu) +static int gprs_n2_fr_mtu_chg_cb(struct osmo_netdev *netdev, uint32_t new_mtu) { + struct gprs_ns2_vc_bind *bind = osmo_netdev_get_priv_data(netdev); struct priv_bind *bpriv = bind->priv; struct gprs_ns2_nse *nse; - if (mtu == bind->mtu) - return; + /* 2 byte DLCI header */ + if (new_mtu <= 2) + return 0; + new_mtu -= 2; + + if (new_mtu == bind->mtu) + return 0; LOGBIND(bind, LOGL_INFO, "MTU changed from %d to %d.\n", - bind->mtu, mtu); + bind->mtu + 2, new_mtu + 2); - /* 2 byte DLCI header */ - bind->mtu = mtu - 2; + bind->mtu = new_mtu; if (!bpriv->if_running) - return; + return 0; llist_for_each_entry(nse, &bind->nsi->nse, list) { ns2_nse_update_mtu(nse); } + return 0; } -/* handle a single netlink message received via libmnl */ -static int linkmon_mnl_cb(const struct nlmsghdr *nlh, void *data) -{ - struct osmo_mnl *omnl = data; - struct gprs_ns2_vc_bind *bind; - struct nlattr *tb[IFLA_MAX+1] = {}; - struct ifinfomsg *ifm = mnl_nlmsg_get_payload(nlh); - struct gprs_ns2_inst *nsi; - const char *ifname; - bool if_running; - - OSMO_ASSERT(omnl); - OSMO_ASSERT(ifm); - - nsi = omnl->priv; - - if (ifm->ifi_type != ARPHRD_FRAD) - return MNL_CB_OK; - - mnl_attr_parse(nlh, sizeof(*ifm), data_attr_cb, tb); - - if (!tb[IFLA_IFNAME]) - return MNL_CB_OK; - ifname = mnl_attr_get_str(tb[IFLA_IFNAME]); - if_running = !!(ifm->ifi_flags & IFF_RUNNING); - - bind = bind4netdev(nsi, ifname); - if (!bind) - return MNL_CB_OK; - - if (tb[IFLA_MTU]) { - mtu_change(bind, mnl_attr_get_u32(tb[IFLA_MTU])); - } - - link_state_change(bind, if_running); - - return MNL_CB_OK; -} - -/* trigger one initial dump of all link information */ -static void linkmon_initial_dump(struct osmo_mnl *omnl) -{ - char buf[MNL_SOCKET_BUFFER_SIZE]; - struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf); - struct rtgenmsg *rt; - - nlh->nlmsg_type = RTM_GETLINK; - nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; - nlh->nlmsg_seq = time(NULL); - rt = mnl_nlmsg_put_extra_header(nlh, sizeof(struct rtgenmsg)); - rt->rtgen_family = AF_PACKET; - - if (mnl_socket_sendto(omnl->mnls, nlh, nlh->nlmsg_len) < 0) { - LOGP(DLNS, LOGL_ERROR, "linkmon: Cannot send rtnetlink message: %s\n", strerror(errno)); - } - - /* the response[s] will be handled just like the events */ -} -#endif /* LIBMNL */ - static int set_ifupdown(const char *netif, bool up) { int sock, rc; @@ -855,16 +760,31 @@ int gprs_ns2_fr_bind(struct gprs_ns2_inst *nsi, goto err_fr; } + priv->netdev = osmo_netdev_alloc(bind, name); + if (!priv->netdev) { + rc = -ENOENT; + goto err_fr; + } + osmo_netdev_set_priv_data(priv->netdev, bind); + osmo_netdev_set_ifupdown_ind_cb(priv->netdev, gprs_n2_fr_ifupdown_ind_cb); + osmo_netdev_set_mtu_chg_cb(priv->netdev, gprs_n2_fr_mtu_chg_cb); + rc = osmo_netdev_set_ifindex(priv->netdev, priv->ifindex); + if (rc < 0) + goto err_free_netdev; + rc = osmo_netdev_register(priv->netdev); + if (rc < 0) + goto err_free_netdev; + /* set protocol frame relay and lmi */ rc = setup_device(priv->netif, bind); if(rc < 0) { LOGBIND(bind, LOGL_ERROR, "Failed to setup the interface %s for frame relay and lmi\n", netif); - goto err_fr; + goto err_free_netdev; } rc = open_socket(priv->ifindex, bind); if (rc < 0) - goto err_fr; + goto err_free_netdev; priv->backlog.retry_us = 2500; /* start with some non-zero value; this corrsponds to 496 bytes */ osmo_timer_setup(&priv->backlog.timer, fr_backlog_timer_cb, bind); osmo_fd_setup(&priv->backlog.ofd, rc, OSMO_FD_READ, fr_netif_ofd_cb, bind, 0); @@ -872,16 +792,6 @@ int gprs_ns2_fr_bind(struct gprs_ns2_inst *nsi, if (rc < 0) goto err_fd; -#ifdef ENABLE_LIBMNL - if (!nsi->linkmon_mnl) - nsi->linkmon_mnl = osmo_mnl_init(nsi, NETLINK_ROUTE, RTMGRP_LINK, linkmon_mnl_cb, nsi); - - /* we get a new full dump after every bind. which is a bit excessive. But that's just once - * at start-up, so we can get away with it */ - if (nsi->linkmon_mnl) - linkmon_initial_dump(nsi->linkmon_mnl); -#endif - if (result) *result = bind; @@ -889,6 +799,9 @@ int gprs_ns2_fr_bind(struct gprs_ns2_inst *nsi, err_fd: close(priv->backlog.ofd.fd); +err_free_netdev: + osmo_netdev_free(priv->netdev); + priv->netdev = NULL; err_fr: osmo_fr_link_free(fr_link); priv->link = NULL; @@ -976,8 +889,9 @@ struct gprs_ns2_vc *gprs_ns2_fr_connect(struct gprs_ns2_vc_bind *bind, goto err; } - snprintf(idbuf, sizeof(idbuf), "%s-%s-DLCI%u-NSE%05u-NSVC%05u", gprs_ns2_lltype_str(nse->ll), - bpriv->netif, dlci, nse->nsei, nsvci); + snprintf(idbuf, sizeof(idbuf), "NSE%05u-NSVC%05u-%s-%s-DLCI%u", nse->nsei, nsvci, + gprs_ns2_lltype_str(nse->ll), bpriv->netif, dlci); + osmo_identifier_sanitize_buf(idbuf, NULL, '_'); nsvc = ns2_vc_alloc(bind, nse, true, GPRS_NS2_VC_MODE_BLOCKRESET, idbuf); if (!nsvc) goto err; |