Skip to content

Commit

Permalink
statd: add more ethtool counters to op datastore
Browse files Browse the repository at this point in the history
Add counters from Ethtool groups to the operational datastore. The
mapping from Linux / Ethtool to YANG is described in the included
document eth-counters.md.

Signed-off-by: Richard Alpe <richard@bit42.se>
  • Loading branch information
rical committed Oct 31, 2023
1 parent 941fc31 commit c5feac5
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 35 deletions.
2 changes: 1 addition & 1 deletion board/netconf/rootfs/lib/infix/cli-pretty
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ class Iface:
if frame:
print(f"")
for key, val in frame.items():
print(f"eth-{key:<{16}}: {val}")
print(f"eth-{key:<{25}}: {val}")


def find_iface(_ifaces, name):
Expand Down
31 changes: 31 additions & 0 deletions doc/eth-counters.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# YANG to Ethtool Mapping
This column contains the mapping between YANG and Linux / Ethtool counters.

```
┌─────────────────────────────────┬──────────────────────────────────┐
│ YANG │ Linux / Ethtool │
├─────────────────────────────────┼──────────────────────────────────┤
│ out-frames │ FramesTransmittedOK │
├─────────────────────────────────┼──────────────────────────────────┤
│ out-multicast-frames │ MulticastFramesXmittedOK │
├─────────────────────────────────┼──────────────────────────────────┤
│ out-broadcast-frames │ BroadcastFramesXmittedOK │
├─────────────────────────────────┼──────────────────────────────────┤
│ in-total-frames │ FramesReceivedOK, │
│ │ FrameCheckSequenceErrors │
│ │ FramesLostDueToIntMACRcvError │
│ │ AlignmentErrors │
│ │ etherStatsOversizePkts │
│ │ etherStatsJabbers │
├─────────────────────────────────┼──────────────────────────────────┤
│ in-frames │ FramesReceivedOK │
├─────────────────────────────────┼──────────────────────────────────┤
│ in-multicast-frames │ MulticastFramesReceivedOK │
├─────────────────────────────────┼──────────────────────────────────┤
│ in-broadcast-frames │ BroadcastFramesReceivedOK │
├─────────────────────────────────┼──────────────────────────────────┤
│ in-error-undersize-frames │ undersize_pkts │
├─────────────────────────────────┼──────────────────────────────────┤
│ in-error-fcs-frames │ FrameCheckSequenceErrors │
└─────────────────────────────────┴──────────────────────────────────┘
```
144 changes: 110 additions & 34 deletions src/statd/iface-ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,75 +17,151 @@ static json_t *json_get_ethtool(const char *ifname)
return json_get_output(cmd);
}

/* We print errors here, but don't return them */
static void ly_add_lld(const struct ly_ctx *ctx, struct lyd_node *node, char *xpath,
json_t *json, const char *yang, const char *ethtool)
{
json_t *j_val;
int err;

j_val = json_object_get(json, ethtool);
if (!j_val)
return;

if (!json_is_integer(j_val)) {
ERROR("Error, expecting integer value for '%s'\n", ethtool);
return;
}

err = lydx_new_path(ctx, &node, xpath, (char *)yang, "%lld",
json_integer_value(j_val));
if (err)
ERROR("Error, adding ethtool '%s' to data tree, libyang error %d", yang, err);
}

static uint64_t json_get_lld(json_t *json, int *found, const char *name)
{
json_t *j_val;

j_val = json_object_get(json, name);
if (!j_val)
return 0;

if (!json_is_integer(j_val)) {
ERROR("Error, expecting integer value for '%s'\n", name);
return 0;
}

(*found)++;

return json_integer_value(j_val);
}

static void ly_add_in_tot_frames(const struct ly_ctx *ctx, struct lyd_node *node,
char *xpath, json_t *j_mac, json_t *j_rmon)
{
char *yang = "in-total-frames";
long long int tot = 0;
int found = 0;
int err;

tot += json_get_lld(j_mac, &found, "FramesReceivedOK");
tot += json_get_lld(j_mac, &found, "FrameCheckSequenceErrors");
tot += json_get_lld(j_mac, &found, "FramesLostDueToIntMACRcvError");
tot += json_get_lld(j_mac, &found, "AlignmentErrors");
tot += json_get_lld(j_rmon, &found, "etherStatsOversizePkts");
tot += json_get_lld(j_rmon, &found, "etherStatsJabbers");

/* Don't add 0 counters for missing data (missing != 0) */
if (!found)
return;

err = lydx_new_path(ctx, &node, xpath, yang, "%lld", tot);
if (err)
ERROR("Error, adding ethtool '%s', libyang error %d", yang, err);
}

static void ly_add_in_err_oz_frames(const struct ly_ctx *ctx, struct lyd_node *node,
char *xpath, json_t *j_rmon)
{
char *yang = "in-error-oversize-frames";
long long int tot = 0;
int found = 0;
int err;

tot += json_get_lld(j_rmon, &found, "etherStatsOversizePkts");
tot += json_get_lld(j_rmon, &found, "etherStatsJabbers");

/* Don't add 0 counters for missing data (missing != 0) */
if (!found)
return;

err = lydx_new_path(ctx, &node, xpath, yang, "%lld", tot);
if (err)
ERROR("Error, adding ethtool '%s', libyang error %d", yang, err);
}

static int ly_add_eth_stats(const struct ly_ctx *ctx, struct lyd_node **parent,
const char *ifname, json_t *j_iface)
{
struct {
const char *ethtool;
char *yang;

} map[] = {
{"FramesTransmittedOK", "out-frames"},
{"FramesReceivedOK", "in-frames"},
};
json_t *j_mac;
json_t *j_val;
char xpath_base[XPATH_BASE_MAX] = {};
char xpath[XPATH_MAX] = {};
struct lyd_node *frame_node = NULL;
struct lyd_node *stat_node = NULL;
struct lyd_node *eth_node = NULL;
size_t i;
struct lyd_node *frame = NULL;
struct lyd_node *stat = NULL;
struct lyd_node *eth = NULL;
json_t *j_mac;
json_t *j_rmon;
int err;

j_mac = json_object_get(j_iface, "eth-mac");
if (!j_mac)
return SR_ERR_OK;

j_rmon = json_object_get(j_iface, "rmon");
if (!j_rmon)
return SR_ERR_OK;

snprintf(xpath_base, sizeof(xpath_base),
"%s/interface[name='%s']/ieee802-ethernet-interface:ethernet",
XPATH_IFACE_BASE, ifname);

err = lyd_new_path(*parent, ctx, xpath_base, NULL, 0, &eth_node);
err = lyd_new_path(*parent, ctx, xpath_base, NULL, 0, &eth);
if (err) {
ERROR("Failed adding 'eth' node (%s), libyang error %d: %s",
xpath_base, err, ly_errmsg(ctx));
return SR_ERR_LY;
}

snprintf(xpath, sizeof(xpath), "%s/statistics", xpath_base);
err = lyd_new_path(eth_node, ctx, xpath, NULL, 0, &stat_node);
err = lyd_new_path(eth, ctx, xpath, NULL, 0, &stat);
if (err) {
ERROR("Failed adding 'stat' node (%s), libyang error %d: %s",
xpath, err, ly_errmsg(ctx));
return SR_ERR_LY;
}

snprintf(xpath, sizeof(xpath), "%s/statistics/frame", xpath_base);
err = lyd_new_path(stat_node, ctx, xpath, NULL, 0, &frame_node);
err = lyd_new_path(stat, ctx, xpath, NULL, 0, &frame);
if (err) {
ERROR("Failed adding 'frame' node (%s), libyang error %d: %s",
xpath, err, ly_errmsg(ctx));
return SR_ERR_LY;
}

for (i = 0; i < sizeof(map) / sizeof(map[0]); i++) {
j_val = json_object_get(j_mac, map[i].ethtool);
if (!j_val)
continue;

if (!json_is_integer(j_val)) {
ERROR("Error, expecting integer value for '%s'\n", map[i].ethtool);
return SR_ERR_SYS;
}
err = lydx_new_path(ctx, &frame_node, xpath, map[i].yang,
"%lld", json_integer_value(j_val));
if (err) {
ERROR("Error, adding ethtool '%s' to data tree, libyang error %d",
map[i].yang, err);
return SR_ERR_LY;
}
}
ly_add_lld(ctx, frame, xpath, j_mac, "out-frames", "FramesTransmittedOK");
ly_add_lld(ctx, frame, xpath, j_mac, "out-multicast-frames", "MulticastFramesXmittedOK");
ly_add_lld(ctx, frame, xpath, j_mac, "out-broadcast-frames", "BroadcastFramesXmittedOK");
ly_add_lld(ctx, frame, xpath, j_mac, "in-frames", "FramesReceivedOK");
ly_add_lld(ctx, frame, xpath, j_mac, "in-multicast-frames", "MulticastFramesReceivedOK");
ly_add_lld(ctx, frame, xpath, j_mac, "in-broadcast-frames", "BroadcastFramesReceivedOK");
ly_add_lld(ctx, frame, xpath, j_mac, "in-error-fcs-frames", "FrameCheckSequenceErrors");
ly_add_lld(ctx, frame, xpath, j_mac, "in-error-undersize-frames", "undersize_pkts");

ly_add_lld(ctx, frame, xpath, j_mac, "in-error-mac-internal-frames",
"FramesLostDueToIntMACRcvError");

ly_add_in_tot_frames(ctx, frame, xpath, j_mac, j_rmon);
ly_add_in_err_oz_frames(ctx, frame, xpath, j_rmon);

return SR_ERR_OK;
}
Expand Down

0 comments on commit c5feac5

Please sign in to comment.