aboutsummaryrefslogtreecommitdiffstats
path: root/src/gb/gprs_ns2_fr.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gb/gprs_ns2_fr.c')
-rw-r--r--src/gb/gprs_ns2_fr.c206
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;