Max has uploaded this change for review. ( https://gerrit.osmocom.org/12710


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

Add ping probe support

If liboping is available during ./configure than 'ping XXX' entries will
be supported 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, 278 insertions(+), 1 deletion(-)



  git pull ssh://gerrit.osmocom.org:29418/osmo-sysmon refs/changes/10/12710/1

diff --git a/configure.ac b/configure.ac
index 734ac99..be60a8e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -111,6 +111,9 @@
    AC_SUBST([COVERAGE_LDFLAGS])
 fi

+PKG_CHECK_MODULES(LIBOPING, liboping, found_oping=yes, [AC_DEFINE([NO_OPING], 
[1], [Don't use liboping])])
+AM_CONDITIONAL(HAVE_OPING, test "$found_oping" = yes)
+
 AC_ARG_ENABLE(profile,
                [AS_HELP_STRING([--enable-profile], [Compile with profiling 
support enabled], )],
                [profile=$enableval], [profile="no"])
diff --git a/src/Makefile.am b/src/Makefile.am
index 412337b..2e5f260 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -37,6 +37,12 @@
        osysmon_main.c \
        $(NULL)

+if HAVE_OPING
+osmo_sysmon_SOURCES += osysmon_ping.c
+osmo_sysmon_LDADD += $(LIBOPING_LIBS)
+osmo_sysmon_CFLAGS = $(AM_CFLAGS) $(LIBOPING_CFLAGS)
+endif
+
 osmo_ctrl_client_SOURCES = \
        simple_ctrl.c \
        osmo-ctrl-client.c \
diff --git a/src/osysmon.h b/src/osysmon.h
index 735b11e..8b17972 100644
--- a/src/osysmon.h
+++ b/src/osysmon.h
@@ -6,9 +6,11 @@

 #include <stdbool.h>

+#include "config.h"
 #include "value_node.h"

 struct rtnl_client_state;
+struct ping_state;

 struct osysmon_state {
        struct rtnl_client_state *rcs;
@@ -18,6 +20,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 +31,7 @@
        CTRL_CLIENT_NODE = _LAST_OSMOVTY_NODE + 1,
        CTRL_CLIENT_GETVAR_NODE,
        NETDEV_NODE,
+       PING_NODE,
 };


@@ -42,5 +46,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..96dfa69 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,9 @@
        osysmon_sysinfo_init();
        osysmon_ctrl_init();
        osysmon_rtnl_init();
+#ifndef NO_OPING
+       ping_init = osysmon_ping_init();
+#endif
        osysmon_file_init();

        rc = vty_read_config_file(cmdline_opts.config_file, NULL);
@@ -233,6 +236,10 @@
                osysmon_sysinfo_poll(root);
                osysmon_ctrl_poll(root);
                osysmon_rtnl_poll(root);
+#ifndef NO_OPING
+               if (ping_init == 0)
+                       osysmon_ping_poll(root);
+#endif
                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..eaa3d1b
--- /dev/null
+++ b/src/osysmon_ping.c
@@ -0,0 +1,254 @@
+/* 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;
+};
+
+/* Workaround for liboping issue https://github.com/octo/liboping/issues/43 */
+static int add_host(pingobj_t *pinger, const char *host)
+{
+       int num_host = ping_iterator_count(pinger),
+                 rc = ping_host_add(pinger, host);
+
+       if (rc < 0) {
+               if (num_host != ping_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",
+                       ping_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",
+                       ping_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 = ping_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: newchange
Gerrit-Change-Id: Ife32540b532fb54368f63c78fb7837b84d4e8c76
Gerrit-Change-Number: 12710
Gerrit-PatchSet: 1
Gerrit-Owner: Max <[email protected]>

Reply via email to