Max has submitted this change and it was merged. ( 
https://gerrit.osmocom.org/12710 )

Change subject: Add ping probe support
......................................................................

Add ping probe support

Use liboping (new dependency) to add 'ping XXX' entries support in .cfg
file, where XXX can be either IP address or FQDN.

Sample output:
...
  ping
    ya.ru
      IP: 2a02:6b8::2:242
      dropped: 3/3
    8.8.8.8
      IP: 8.8.8.8
      dropped: 0/3
      latency: 20.4 ms
      TTL: 120
...

N. B: to gather actual ping statistic we have to be able to send ICMP
requests (have enough privileges to work with RAW sockets).

Related: SYS#2655
Change-Id: Ife32540b532fb54368f63c78fb7837b84d4e8c76
---
M configure.ac
M src/Makefile.am
M src/osysmon.h
M src/osysmon_main.c
A src/osysmon_ping.c
5 files changed, 281 insertions(+), 2 deletions(-)

Approvals:
  Jenkins Builder: Verified
  osmith: Looks good to me, approved



diff --git a/configure.ac b/configure.ac
index 734ac99..d98de89 100644
--- a/configure.ac
+++ b/configure.ac
@@ -43,6 +43,8 @@
 PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 0.11.0)
 PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 0.11.0)
 PKG_CHECK_MODULES(LIBMNL, libmnl)
+dnl FIXME: bump to 1.10.0 once it's available on build slaves and remove 
workaround from osysmon_ping.c
+PKG_CHECK_MODULES(LIBOPING, liboping >= 1.9.0)

 dnl checks for header files
 AC_HEADER_STDC
diff --git a/src/Makefile.am b/src/Makefile.am
index cb85da2..d0d6a22 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -24,11 +24,12 @@
 libintern_la_SOURCES = simple_ctrl.c
 libintern_la_LIBADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS)

-osmo_sysmon_CFLAGS = $(LIBMNL_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(AM_CFLAGS)
+osmo_sysmon_CFLAGS = $(LIBMNL_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOPING_CFLAGS) 
$(AM_CFLAGS)

 osmo_sysmon_LDADD = $(LDADD) \
        $(LIBOSMOVTY_LIBS) \
        $(LIBMNL_LIBS) \
+       $(LIBOPING_LIBS) \
        $(NULL)

 osmo_sysmon_SOURCES = \
@@ -37,6 +38,7 @@
        osysmon_sysinfo.c \
        osysmon_rtnl.c \
        osysmon_file.c \
+       osysmon_ping.c \
        osysmon_main.c \
        $(NULL)

diff --git a/src/osysmon.h b/src/osysmon.h
index 735b11e..df8bf8d 100644
--- a/src/osysmon.h
+++ b/src/osysmon.h
@@ -9,6 +9,7 @@
 #include "value_node.h"

 struct rtnl_client_state;
+struct ping_state;

 struct osysmon_state {
        struct rtnl_client_state *rcs;
@@ -18,6 +19,7 @@
        struct llist_head netdevs;
        /* list of 'struct osysmon_file' */
        struct llist_head files;
+       struct ping_state *pings;
 };

 extern struct osysmon_state *g_oss;
@@ -28,6 +30,7 @@
        CTRL_CLIENT_NODE = _LAST_OSMOVTY_NODE + 1,
        CTRL_CLIENT_GETVAR_NODE,
        NETDEV_NODE,
+       PING_NODE,
 };


@@ -42,5 +45,8 @@
 int osysmon_sysinfo_init();
 int osysmon_sysinfo_poll(struct value_node *parent);

+int osysmon_ping_init();
+int osysmon_ping_poll(struct value_node *parent);
+
 int osysmon_file_init();
 int osysmon_file_poll(struct value_node *parent);
diff --git a/src/osysmon_main.c b/src/osysmon_main.c
index 82df61f..eb4f50b 100644
--- a/src/osysmon_main.c
+++ b/src/osysmon_main.c
@@ -193,7 +193,7 @@

 int main(int argc, char **argv)
 {
-       int rc;
+       int rc, ping_init;

        osmo_init_logging2(NULL, &log_info);

@@ -207,6 +207,7 @@
        osysmon_sysinfo_init();
        osysmon_ctrl_init();
        osysmon_rtnl_init();
+       ping_init = osysmon_ping_init();
        osysmon_file_init();

        rc = vty_read_config_file(cmdline_opts.config_file, NULL);
@@ -233,6 +234,10 @@
                osysmon_sysinfo_poll(root);
                osysmon_ctrl_poll(root);
                osysmon_rtnl_poll(root);
+
+               if (ping_init == 0)
+                       osysmon_ping_poll(root);
+
                osysmon_file_poll(root);

                display_update(root);
diff --git a/src/osysmon_ping.c b/src/osysmon_ping.c
new file mode 100644
index 0000000..f736798
--- /dev/null
+++ b/src/osysmon_ping.c
@@ -0,0 +1,264 @@
+/* Simple Osmocom System Monitor (osysmon): Support for ping probe */
+
+/* (C) 2018 by sysmocom - s.f.m.c. GmbH.
+ * Author: Max Suraev
+ * All Rights Reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA  02110-1301, USA.
+ */
+
+#include <stdbool.h>
+#include <errno.h>
+
+#include <oping.h>
+
+#include <osmocom/core/utils.h>
+#include <osmocom/vty/vty.h>
+#include <osmocom/vty/command.h>
+
+#include "osysmon.h"
+#include "value_node.h"
+
+/***********************************************************************
+ * Data model
+ ***********************************************************************/
+
+#define BUFLEN 128
+
+struct ping_state {
+       pingobj_t *ping_handle;
+};
+
+/* FIXME: replace with ping_iterator_count() once we bump requirements to 
liboping 1.10.0+ */
+static unsigned iterator_count(pingobj_t *p)
+{
+       unsigned count = 0;
+       pingobj_iter_t *iter;
+       for (iter = ping_iterator_get(p); iter; iter = ping_iterator_next(iter))
+               count++;
+       return count;
+}
+
+/* Workaround for liboping issue https://github.com/octo/liboping/issues/43 */
+static int add_host(pingobj_t *pinger, const char *host)
+{
+       int num_host = iterator_count(pinger),
+               rc = ping_host_add(pinger, host);
+
+       if (rc < 0) {
+               if (num_host != iterator_count(pinger))
+                       ping_host_remove(pinger, host);
+       }
+
+       return rc;
+}
+
+
+static bool add_drop(pingobj_iter_t *iter, struct value_node *vn_host)
+{
+       char *s = NULL;
+       uint32_t drop, seq;
+       size_t len = sizeof(drop);
+       int rc = ping_iterator_get_info(iter, PING_INFO_DROPPED, &drop, &len);
+       if (rc)
+               return false;
+
+       len = sizeof(seq);
+       rc = ping_iterator_get_info(iter, PING_INFO_SEQUENCE, &seq, &len);
+       if (rc)
+               return false;
+
+       osmo_talloc_asprintf(vn_host, s, "%u/%u", drop, seq);
+       value_node_add(vn_host, "dropped", s);
+
+       return true;
+}
+
+static bool add_ttl(pingobj_iter_t *iter, struct value_node *vn_host)
+{
+       int ttl, rc;
+       size_t len = sizeof(ttl);
+
+       rc = ping_iterator_get_info(iter, PING_INFO_RECV_TTL, &ttl, &len);
+       if (rc)
+               return false;
+
+       if (ttl > -1) {
+               char *s = NULL;
+               osmo_talloc_asprintf(vn_host, s, "%d", ttl);
+               value_node_add(vn_host, "TTL", s);
+       }
+
+       return true;
+}
+
+static bool add_latency(pingobj_iter_t *iter, struct value_node *vn_host)
+{
+       double latency;
+       size_t len = sizeof(latency);
+       int rc = ping_iterator_get_info(iter, PING_INFO_LATENCY, &latency, 
&len);
+       if (rc)
+               return false;
+
+       if (latency > -1) {
+               char *s = NULL;
+               osmo_talloc_asprintf(vn_host, s, "%.1lf ms", latency);
+               value_node_add(vn_host, "latency", s);
+       }
+
+       return true;
+}
+
+
+/***********************************************************************
+ * VTY
+ ***********************************************************************/
+
+static struct cmd_node ping_node = {
+       PING_NODE,
+       "%s(config-ping)# ",
+       1,
+};
+
+int osysmon_ping_go_parent(struct vty *vty)
+{
+       switch (vty->node) {
+       case PING_NODE:
+               vty->node = CONFIG_NODE;
+               vty->index = NULL;
+               break;
+       default:
+               break;
+       }
+       return vty->node;
+}
+
+#define PING_STR "Configure a host to be monitored/pinged\n"
+
+DEFUN(cfg_ping, cfg_ping_cmd,
+      "ping HOST",
+      PING_STR "Name of the host to ping\n")
+{
+       int rc = add_host(g_oss->pings->ping_handle, argv[0]);
+       if (rc < 0) {
+               vty_out(vty, "[%d] Couldn't add pinger for %s: %s%s",
+                       iterator_count(g_oss->pings->ping_handle), argv[0],
+                       ping_get_error(g_oss->pings->ping_handle), VTY_NEWLINE);
+
+               return CMD_WARNING;
+       }
+
+       return CMD_SUCCESS;
+}
+
+DEFUN(cfg_no_ping, cfg_no_ping_cmd,
+      "no ping HOST",
+      NO_STR PING_STR "Name of the host to ping\n")
+{
+       int rc = ping_host_remove(g_oss->pings->ping_handle, argv[0]);
+       if (rc < 0) {
+               vty_out(vty, "[%d] Couldn't remove %s pinger: %s%s",
+                       iterator_count(g_oss->pings->ping_handle), argv[0],
+                       ping_get_error(g_oss->pings->ping_handle), VTY_NEWLINE);
+
+               return CMD_WARNING;
+       }
+
+       return CMD_SUCCESS;
+}
+
+static int config_write_ping(struct vty *vty)
+{
+       char buf[BUFLEN];
+       pingobj_iter_t *iter;
+       for (iter = ping_iterator_get(g_oss->pings->ping_handle); iter; iter = 
ping_iterator_next(iter)) {
+               size_t len = BUFLEN;
+               /* hostname as it was supplied via vty 'ping' entry */
+               if (ping_iterator_get_info(iter, PING_INFO_USERNAME, buf, &len))
+                       return CMD_WARNING;
+
+               vty_out(vty, "ping %s%s", buf, VTY_NEWLINE);
+       }
+
+       return CMD_SUCCESS;
+}
+
+
+/***********************************************************************
+ * Runtime Code
+ ***********************************************************************/
+
+/* called once on startup before config file parsing */
+int osysmon_ping_init()
+{
+       install_element(CONFIG_NODE, &cfg_ping_cmd);
+       install_element(CONFIG_NODE, &cfg_no_ping_cmd);
+       install_node(&ping_node, config_write_ping);
+
+       g_oss->pings = talloc_zero(NULL, struct ping_state);
+       if (!g_oss->pings)
+               return -ENOMEM;
+
+       g_oss->pings->ping_handle = ping_construct();
+
+       if (g_oss->pings->ping_handle)
+               return 0;
+
+       return -EINVAL;
+}
+
+/* called periodically */
+int osysmon_ping_poll(struct value_node *parent)
+{
+       char buf[BUFLEN];
+       struct value_node *vn_host;
+       int num_host = iterator_count(g_oss->pings->ping_handle);
+       pingobj_iter_t *iter;
+       struct value_node *vn_ping = value_node_add(parent, "ping", NULL);
+       if (!vn_ping)
+               return -ENOMEM;
+
+       for (iter = ping_iterator_get(g_oss->pings->ping_handle); iter; iter = 
ping_iterator_next(iter)) {
+               size_t len = BUFLEN;
+               int rc = ping_iterator_get_info(iter, PING_INFO_USERNAME, buf, 
&len);
+               if (rc)
+                       return -EINVAL;
+
+               vn_host = value_node_find_or_add(vn_ping, 
talloc_strdup(vn_ping, buf));
+               if (!vn_host)
+                       return -ENOMEM;
+
+               len = BUFLEN; /* IP address is looked up on-call, even 40 bytes 
should be enough */
+               rc = ping_iterator_get_info(iter, PING_INFO_ADDRESS, buf, &len);
+               if (rc)
+                       return -EINVAL;
+
+               value_node_add(vn_host, "IP", buf);
+
+               add_drop(iter, vn_host);
+
+               /* Parameters below might be absent from output depending on 
the host reachability: */
+               add_latency(iter, vn_host);
+               add_ttl(iter, vn_host);
+       }
+
+       if (num_host)
+               return ping_send(g_oss->pings->ping_handle);
+
+       return 0;
+}

--
To view, visit https://gerrit.osmocom.org/12710
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings

Gerrit-Project: osmo-sysmon
Gerrit-Branch: master
Gerrit-MessageType: merged
Gerrit-Change-Id: Ife32540b532fb54368f63c78fb7837b84d4e8c76
Gerrit-Change-Number: 12710
Gerrit-PatchSet: 10
Gerrit-Owner: Max <[email protected]>
Gerrit-Reviewer: Harald Welte <[email protected]>
Gerrit-Reviewer: Jenkins Builder (1000002)
Gerrit-Reviewer: Max <[email protected]>
Gerrit-Reviewer: Pau Espin Pedrol <[email protected]>
Gerrit-Reviewer: daniel <[email protected]>
Gerrit-Reviewer: osmith <[email protected]>

Reply via email to