mirror of
https://gitlab.labs.nic.cz/labs/bird.git
synced 2024-05-11 16:54:54 +00:00
Explicit definition structures of route attributes
Changes in internal API: * Every route attribute must be defined as struct ea_class somewhere. * Registration of route attributes known at startup must be done by ea_register_init() from protocol build functions. * Every attribute has now its symbol registered in a global symbol table defined as SYM_ATTRIBUTE * All attribute ID's are dynamically allocated. * Attribute value custom formatting hook is defined in the ea_class. * Attribute names are the same for display and filters, always prefixed by protocol name. Also added some unit testing code for filters with route attributes.
This commit is contained in:
@@ -34,38 +34,6 @@ static inline struct ifa * kif_get_primary_ip(struct iface *i UNUSED) { return N
|
||||
|
||||
#define KRT_ALLOW_MERGE_PATHS 1
|
||||
|
||||
#define EA_KRT_PREFSRC EA_CODE(PROTOCOL_KERNEL, 0x10)
|
||||
#define EA_KRT_REALM EA_CODE(PROTOCOL_KERNEL, 0x11)
|
||||
#define EA_KRT_SCOPE EA_CODE(PROTOCOL_KERNEL, 0x12)
|
||||
|
||||
|
||||
#define KRT_METRICS_MAX 0x10 /* RTAX_QUICKACK+1 */
|
||||
#define KRT_METRICS_OFFSET 0x20 /* Offset of EA_KRT_* vs RTAX_* */
|
||||
|
||||
#define KRT_FEATURES_MAX 4
|
||||
|
||||
/*
|
||||
* Following attributes are parts of RTA_METRICS kernel route attribute, their
|
||||
* ids must be consistent with their RTAX_* constants (+ KRT_METRICS_OFFSET)
|
||||
*/
|
||||
#define EA_KRT_METRICS EA_CODE(PROTOCOL_KERNEL, 0x20) /* Dummy one */
|
||||
#define EA_KRT_LOCK EA_CODE(PROTOCOL_KERNEL, 0x21)
|
||||
#define EA_KRT_MTU EA_CODE(PROTOCOL_KERNEL, 0x22)
|
||||
#define EA_KRT_WINDOW EA_CODE(PROTOCOL_KERNEL, 0x23)
|
||||
#define EA_KRT_RTT EA_CODE(PROTOCOL_KERNEL, 0x24)
|
||||
#define EA_KRT_RTTVAR EA_CODE(PROTOCOL_KERNEL, 0x25)
|
||||
#define EA_KRT_SSTRESH EA_CODE(PROTOCOL_KERNEL, 0x26)
|
||||
#define EA_KRT_CWND EA_CODE(PROTOCOL_KERNEL, 0x27)
|
||||
#define EA_KRT_ADVMSS EA_CODE(PROTOCOL_KERNEL, 0x28)
|
||||
#define EA_KRT_REORDERING EA_CODE(PROTOCOL_KERNEL, 0x29)
|
||||
#define EA_KRT_HOPLIMIT EA_CODE(PROTOCOL_KERNEL, 0x2a)
|
||||
#define EA_KRT_INITCWND EA_CODE(PROTOCOL_KERNEL, 0x2b)
|
||||
#define EA_KRT_FEATURES EA_CODE(PROTOCOL_KERNEL, 0x2c)
|
||||
#define EA_KRT_RTO_MIN EA_CODE(PROTOCOL_KERNEL, 0x2d)
|
||||
#define EA_KRT_INITRWND EA_CODE(PROTOCOL_KERNEL, 0x2e)
|
||||
#define EA_KRT_QUICKACK EA_CODE(PROTOCOL_KERNEL, 0x2f)
|
||||
|
||||
|
||||
struct krt_params {
|
||||
u32 table_id; /* Kernel table ID we sync with */
|
||||
u32 metric; /* Kernel metric used for all routes */
|
||||
|
@@ -28,39 +28,22 @@ kern_sys_item:
|
||||
| NETLINK RX BUFFER expr { THIS_KRT->sys.netlink_rx_buffer = $4; }
|
||||
;
|
||||
|
||||
dynamic_attr: KRT_PREFSRC { $$ = f_new_dynamic_attr(T_IP, EA_KRT_PREFSRC); } ;
|
||||
dynamic_attr: KRT_REALM { $$ = f_new_dynamic_attr(T_INT, EA_KRT_REALM); } ;
|
||||
dynamic_attr: KRT_SCOPE { $$ = f_new_dynamic_attr(T_INT, EA_KRT_SCOPE); } ;
|
||||
|
||||
dynamic_attr: KRT_MTU { $$ = f_new_dynamic_attr(T_INT, EA_KRT_MTU); } ;
|
||||
dynamic_attr: KRT_WINDOW { $$ = f_new_dynamic_attr(T_INT, EA_KRT_WINDOW); } ;
|
||||
dynamic_attr: KRT_RTT { $$ = f_new_dynamic_attr(T_INT, EA_KRT_RTT); } ;
|
||||
dynamic_attr: KRT_RTTVAR { $$ = f_new_dynamic_attr(T_INT, EA_KRT_RTTVAR); } ;
|
||||
dynamic_attr: KRT_SSTRESH { $$ = f_new_dynamic_attr(T_INT, EA_KRT_SSTRESH); } ;
|
||||
dynamic_attr: KRT_CWND { $$ = f_new_dynamic_attr(T_INT, EA_KRT_CWND); } ;
|
||||
dynamic_attr: KRT_ADVMSS { $$ = f_new_dynamic_attr(T_INT, EA_KRT_ADVMSS); } ;
|
||||
dynamic_attr: KRT_REORDERING { $$ = f_new_dynamic_attr(T_INT, EA_KRT_REORDERING); } ;
|
||||
dynamic_attr: KRT_HOPLIMIT { $$ = f_new_dynamic_attr(T_INT, EA_KRT_HOPLIMIT); } ;
|
||||
dynamic_attr: KRT_INITCWND { $$ = f_new_dynamic_attr(T_INT, EA_KRT_INITCWND); } ;
|
||||
dynamic_attr: KRT_RTO_MIN { $$ = f_new_dynamic_attr(T_INT, EA_KRT_RTO_MIN); } ;
|
||||
dynamic_attr: KRT_INITRWND { $$ = f_new_dynamic_attr(T_INT, EA_KRT_INITRWND); } ;
|
||||
dynamic_attr: KRT_QUICKACK { $$ = f_new_dynamic_attr(T_INT, EA_KRT_QUICKACK); } ;
|
||||
|
||||
/* Bits of EA_KRT_LOCK, based on RTAX_* constants */
|
||||
|
||||
attr_bit: KRT_LOCK_MTU { $$ = f_new_dynamic_attr_bit(2, EA_KRT_LOCK); } ;
|
||||
attr_bit: KRT_LOCK_WINDOW { $$ = f_new_dynamic_attr_bit(3, EA_KRT_LOCK); } ;
|
||||
attr_bit: KRT_LOCK_RTT { $$ = f_new_dynamic_attr_bit(4, EA_KRT_LOCK); } ;
|
||||
attr_bit: KRT_LOCK_RTTVAR { $$ = f_new_dynamic_attr_bit(5, EA_KRT_LOCK); } ;
|
||||
attr_bit: KRT_LOCK_SSTRESH { $$ = f_new_dynamic_attr_bit(6, EA_KRT_LOCK); } ;
|
||||
attr_bit: KRT_LOCK_CWND { $$ = f_new_dynamic_attr_bit(7, EA_KRT_LOCK); } ;
|
||||
attr_bit: KRT_LOCK_ADVMSS { $$ = f_new_dynamic_attr_bit(8, EA_KRT_LOCK); } ;
|
||||
attr_bit: KRT_LOCK_REORDERING { $$ = f_new_dynamic_attr_bit(9, EA_KRT_LOCK); } ;
|
||||
attr_bit: KRT_LOCK_HOPLIMIT { $$ = f_new_dynamic_attr_bit(10, EA_KRT_LOCK); } ;
|
||||
attr_bit: KRT_LOCK_RTO_MIN { $$ = f_new_dynamic_attr_bit(13, EA_KRT_LOCK); } ;
|
||||
attr_bit: KRT_LOCK_MTU { $$ = f_new_dynamic_attr_bit(2, "krt_lock"); } ;
|
||||
attr_bit: KRT_LOCK_WINDOW { $$ = f_new_dynamic_attr_bit(3, "krt_lock"); } ;
|
||||
attr_bit: KRT_LOCK_RTT { $$ = f_new_dynamic_attr_bit(4, "krt_lock"); } ;
|
||||
attr_bit: KRT_LOCK_RTTVAR { $$ = f_new_dynamic_attr_bit(5, "krt_lock"); } ;
|
||||
attr_bit: KRT_LOCK_SSTRESH { $$ = f_new_dynamic_attr_bit(6, "krt_lock"); } ;
|
||||
attr_bit: KRT_LOCK_CWND { $$ = f_new_dynamic_attr_bit(7, "krt_lock"); } ;
|
||||
attr_bit: KRT_LOCK_ADVMSS { $$ = f_new_dynamic_attr_bit(8, "krt_lock"); } ;
|
||||
attr_bit: KRT_LOCK_REORDERING { $$ = f_new_dynamic_attr_bit(9, "krt_lock"); } ;
|
||||
attr_bit: KRT_LOCK_HOPLIMIT { $$ = f_new_dynamic_attr_bit(10, "krt_lock"); } ;
|
||||
attr_bit: KRT_LOCK_RTO_MIN { $$ = f_new_dynamic_attr_bit(13, "krt_lock"); } ;
|
||||
|
||||
attr_bit: KRT_FEATURE_ECN { $$ = f_new_dynamic_attr_bit(0, EA_KRT_FEATURES); } ;
|
||||
attr_bit: KRT_FEATURE_ALLFRAG { $$ = f_new_dynamic_attr_bit(3, EA_KRT_FEATURES); } ;
|
||||
/* Bits of EA_KRT_FEATURES */
|
||||
attr_bit: KRT_FEATURE_ECN { $$ = f_new_dynamic_attr_bit(0, "krt_features"); } ;
|
||||
attr_bit: KRT_FEATURE_ALLFRAG { $$ = f_new_dynamic_attr_bit(3, "krt_features"); } ;
|
||||
|
||||
|
||||
CF_CODE
|
||||
|
@@ -26,6 +26,7 @@
|
||||
#include "lib/socket.h"
|
||||
#include "lib/string.h"
|
||||
#include "lib/hash.h"
|
||||
#include "lib/macro.h"
|
||||
#include "conf/conf.h"
|
||||
|
||||
#include <asm/types.h>
|
||||
@@ -121,6 +122,101 @@ struct nl_parse_state
|
||||
u32 rta_flow; /* Used during parsing */
|
||||
};
|
||||
|
||||
/*
|
||||
* Netlink eattr definitions
|
||||
*/
|
||||
|
||||
#define KRT_METRICS_MAX ARRAY_SIZE(ea_krt_metrics)
|
||||
#define KRT_FEATURES_MAX 4
|
||||
|
||||
static void krt_bitfield_format(const eattr *e, byte *buf, uint buflen);
|
||||
|
||||
static struct ea_class
|
||||
ea_krt_prefsrc = {
|
||||
.name = "krt_prefsrc",
|
||||
.type = T_IP,
|
||||
},
|
||||
ea_krt_realm = {
|
||||
.name = "krt_realm",
|
||||
.type = T_INT,
|
||||
},
|
||||
ea_krt_scope = {
|
||||
.name = "krt_scope",
|
||||
.type = T_INT,
|
||||
};
|
||||
|
||||
static struct ea_class ea_krt_metrics[] = {
|
||||
[RTAX_LOCK] = {
|
||||
.name = "krt_lock",
|
||||
.type = T_INT,
|
||||
.format = krt_bitfield_format,
|
||||
},
|
||||
[RTAX_FEATURES] = {
|
||||
.name = "krt_features",
|
||||
.type = T_INT,
|
||||
.format = krt_bitfield_format,
|
||||
},
|
||||
#define KRT_METRIC_INT(_rtax, _name) [_rtax] = { .name = _name, .type = T_INT }
|
||||
KRT_METRIC_INT(RTAX_MTU, "krt_mtu"),
|
||||
KRT_METRIC_INT(RTAX_WINDOW, "krt_window"),
|
||||
KRT_METRIC_INT(RTAX_RTT, "krt_rtt"),
|
||||
KRT_METRIC_INT(RTAX_RTTVAR, "krt_rttvar"),
|
||||
KRT_METRIC_INT(RTAX_SSTHRESH, "krt_sstresh"),
|
||||
KRT_METRIC_INT(RTAX_CWND, "krt_cwnd"),
|
||||
KRT_METRIC_INT(RTAX_ADVMSS, "krt_advmss"),
|
||||
KRT_METRIC_INT(RTAX_REORDERING, "krt_reordering"),
|
||||
KRT_METRIC_INT(RTAX_HOPLIMIT, "krt_hoplimit"),
|
||||
KRT_METRIC_INT(RTAX_INITCWND, "krt_initcwnd"),
|
||||
KRT_METRIC_INT(RTAX_RTO_MIN, "krt_rto_min"),
|
||||
KRT_METRIC_INT(RTAX_INITRWND, "krt_initrwnd"),
|
||||
KRT_METRIC_INT(RTAX_QUICKACK, "krt_quickack"),
|
||||
#undef KRT_METRIC_INT
|
||||
};
|
||||
|
||||
static const char *krt_metrics_names[KRT_METRICS_MAX] = {
|
||||
NULL, "lock", "mtu", "window", "rtt", "rttvar", "sstresh", "cwnd", "advmss",
|
||||
"reordering", "hoplimit", "initcwnd", "features", "rto_min", "initrwnd", "quickack"
|
||||
};
|
||||
|
||||
static const char *krt_features_names[KRT_FEATURES_MAX] = {
|
||||
"ecn", NULL, NULL, "allfrag"
|
||||
};
|
||||
|
||||
static void
|
||||
krt_bitfield_format(const eattr *a, byte *buf, uint buflen)
|
||||
{
|
||||
if (a->id == ea_krt_metrics[RTAX_LOCK].id)
|
||||
ea_format_bitfield(a, buf, buflen, krt_metrics_names, 2, KRT_METRICS_MAX);
|
||||
else if (a->id == ea_krt_metrics[RTAX_FEATURES].id)
|
||||
ea_format_bitfield(a, buf, buflen, krt_features_names, 0, KRT_FEATURES_MAX);
|
||||
}
|
||||
|
||||
static void
|
||||
nl_ea_register(void)
|
||||
{
|
||||
EA_REGISTER_ALL(
|
||||
&ea_krt_prefsrc,
|
||||
&ea_krt_realm,
|
||||
&ea_krt_scope
|
||||
);
|
||||
|
||||
for (uint i = 0; i < KRT_METRICS_MAX; i++)
|
||||
{
|
||||
if (!ea_krt_metrics[i].name)
|
||||
ea_krt_metrics[i] = (struct ea_class) {
|
||||
.name = mb_sprintf(&root_pool, "krt_metric_%d", i),
|
||||
.type = T_INT,
|
||||
};
|
||||
|
||||
ea_register_init(&ea_krt_metrics[i]);
|
||||
}
|
||||
|
||||
for (uint i = 1; i < KRT_METRICS_MAX; i++)
|
||||
ASSERT_DIE(ea_krt_metrics[i].id == ea_krt_metrics[0].id + i);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Synchronous Netlink interface
|
||||
*/
|
||||
@@ -734,7 +830,7 @@ static void
|
||||
nl_add_multipath(struct nlmsghdr *h, uint bufsize, struct nexthop *nh, int af, ea_list *eattrs)
|
||||
{
|
||||
struct rtattr *a = nl_open_attr(h, bufsize, RTA_MULTIPATH);
|
||||
eattr *flow = ea_find(eattrs, EA_KRT_REALM);
|
||||
eattr *flow = ea_find(eattrs, &ea_krt_realm);
|
||||
|
||||
for (; nh; nh = nh->next)
|
||||
{
|
||||
@@ -1399,7 +1495,7 @@ nl_send_route(struct krt_proto *p, rte *e, int op, int dest, struct nexthop *nh)
|
||||
priority = 0;
|
||||
else if (KRT_CF->sys.metric)
|
||||
priority = KRT_CF->sys.metric;
|
||||
else if ((op != NL_OP_DELETE) && (ea = ea_find(eattrs, EA_KRT_METRIC)))
|
||||
else if ((op != NL_OP_DELETE) && (ea = ea_find(eattrs, &ea_krt_metric)))
|
||||
priority = ea->u.data;
|
||||
|
||||
if (priority)
|
||||
@@ -1412,15 +1508,15 @@ nl_send_route(struct krt_proto *p, rte *e, int op, int dest, struct nexthop *nh)
|
||||
/* Default scope is LINK for device routes, UNIVERSE otherwise */
|
||||
if (p->af == AF_MPLS)
|
||||
r->r.rtm_scope = RT_SCOPE_UNIVERSE;
|
||||
else if (ea = ea_find(eattrs, EA_KRT_SCOPE))
|
||||
else if (ea = ea_find(eattrs, &ea_krt_scope))
|
||||
r->r.rtm_scope = ea->u.data;
|
||||
else
|
||||
r->r.rtm_scope = (dest == RTD_UNICAST && ipa_zero(nh->gw)) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE;
|
||||
|
||||
if (ea = ea_find(eattrs, EA_KRT_PREFSRC))
|
||||
if (ea = ea_find(eattrs, &ea_krt_prefsrc))
|
||||
nl_add_attr_ipa(&r->h, rsize, RTA_PREFSRC, *(ip_addr *)ea->u.ptr->data);
|
||||
|
||||
if (ea = ea_find(eattrs, EA_KRT_REALM))
|
||||
if (ea = ea_find(eattrs, &ea_krt_realm))
|
||||
nl_add_attr_u32(&r->h, rsize, RTA_FLOW, ea->u.data);
|
||||
|
||||
|
||||
@@ -1428,9 +1524,9 @@ nl_send_route(struct krt_proto *p, rte *e, int op, int dest, struct nexthop *nh)
|
||||
metrics[0] = 0;
|
||||
|
||||
struct ea_walk_state ews = { .eattrs = eattrs };
|
||||
while (ea = ea_walk(&ews, EA_KRT_METRICS, KRT_METRICS_MAX))
|
||||
while (ea = ea_walk(&ews, ea_krt_metrics[0].id, KRT_METRICS_MAX))
|
||||
{
|
||||
int id = ea->id - EA_KRT_METRICS;
|
||||
int id = ea->id - ea_krt_metrics[0].id;
|
||||
metrics[0] |= 1 << id;
|
||||
metrics[id] = ea->u.data;
|
||||
}
|
||||
@@ -1581,21 +1677,15 @@ nl_announce_route(struct nl_parse_state *s)
|
||||
rte *e = rte_get_temp(s->attrs, s->proto->p.main_source);
|
||||
e->net = s->net;
|
||||
|
||||
EA_LOCAL_LIST(2) ea0 = {
|
||||
EA_LOCAL_LIST(2) ea = {
|
||||
.l = { .count = 2, .next = e->attrs->eattrs },
|
||||
.a[0] = (eattr) {
|
||||
.id = EA_KRT_SOURCE,
|
||||
.type = T_INT,
|
||||
.u.data = s->krt_proto,
|
||||
},
|
||||
.a[1] = (eattr) {
|
||||
.id = EA_KRT_METRIC,
|
||||
.type = T_INT,
|
||||
.u.data = s->krt_metric,
|
||||
.a = {
|
||||
EA_LITERAL_EMBEDDED(&ea_krt_source, 0, s->krt_proto),
|
||||
EA_LITERAL_EMBEDDED(&ea_krt_metric, 0, s->krt_metric),
|
||||
},
|
||||
};
|
||||
|
||||
e->attrs->eattrs = &ea0.l;
|
||||
e->attrs->eattrs = &ea.l;
|
||||
|
||||
if (s->scan)
|
||||
krt_got_route(s->proto, e, s->krt_src);
|
||||
@@ -1867,20 +1957,20 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
|
||||
|
||||
if (i->rtm_scope != def_scope)
|
||||
ea_set_attr(&ra->eattrs,
|
||||
EA_LITERAL_EMBEDDED(EA_KRT_SCOPE, T_INT, 0, i->rtm_scope));
|
||||
EA_LITERAL_EMBEDDED(&ea_krt_scope, 0, i->rtm_scope));
|
||||
|
||||
if (a[RTA_PREFSRC])
|
||||
{
|
||||
ip_addr ps = rta_get_ipa(a[RTA_PREFSRC]);
|
||||
{
|
||||
ip_addr ps = rta_get_ipa(a[RTA_PREFSRC]);
|
||||
|
||||
ea_set_attr(&ra->eattrs,
|
||||
EA_LITERAL_STORE_ADATA(EA_KRT_PREFSRC, T_IP, 0, &ps, sizeof(ps)));
|
||||
}
|
||||
ea_set_attr(&ra->eattrs,
|
||||
EA_LITERAL_STORE_ADATA(&ea_krt_prefsrc, 0, &ps, sizeof(ps)));
|
||||
}
|
||||
|
||||
/* Can be set per-route or per-nexthop */
|
||||
if (s->rta_flow)
|
||||
ea_set_attr(&ra->eattrs,
|
||||
EA_LITERAL_EMBEDDED(EA_KRT_REALM, T_INT, 0, s->rta_flow));
|
||||
EA_LITERAL_EMBEDDED(&ea_krt_realm, 0, s->rta_flow));
|
||||
|
||||
if (a[RTA_METRICS])
|
||||
{
|
||||
@@ -1891,11 +1981,10 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
|
||||
return;
|
||||
}
|
||||
|
||||
for (int t = 1; t < KRT_METRICS_MAX; t++)
|
||||
for (uint t = 1; t < KRT_METRICS_MAX; t++)
|
||||
if (metrics[0] & (1 << t))
|
||||
ea_set_attr(&ra->eattrs,
|
||||
EA_LITERAL_EMBEDDED(EA_CODE(PROTOCOL_KERNEL, KRT_METRICS_OFFSET + t),
|
||||
T_INT, 0, metrics[t]));
|
||||
EA_LITERAL_EMBEDDED(&ea_krt_metrics[t], 0, metrics[t]));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2133,6 +2222,8 @@ krt_sys_io_init(void)
|
||||
{
|
||||
nl_linpool = lp_new_default(krt_pool);
|
||||
HASH_INIT(nl_table_map, krt_pool, 6);
|
||||
|
||||
nl_ea_register();
|
||||
}
|
||||
|
||||
int
|
||||
@@ -2186,56 +2277,6 @@ krt_sys_copy_config(struct krt_config *d, struct krt_config *s)
|
||||
d->sys.metric = s->sys.metric;
|
||||
}
|
||||
|
||||
static const char *krt_metrics_names[KRT_METRICS_MAX] = {
|
||||
NULL, "lock", "mtu", "window", "rtt", "rttvar", "sstresh", "cwnd", "advmss",
|
||||
"reordering", "hoplimit", "initcwnd", "features", "rto_min", "initrwnd", "quickack"
|
||||
};
|
||||
|
||||
static const char *krt_features_names[KRT_FEATURES_MAX] = {
|
||||
"ecn", NULL, NULL, "allfrag"
|
||||
};
|
||||
|
||||
int
|
||||
krt_sys_get_attr(const eattr *a, byte *buf, int buflen UNUSED)
|
||||
{
|
||||
switch (a->id)
|
||||
{
|
||||
case EA_KRT_PREFSRC:
|
||||
bsprintf(buf, "prefsrc");
|
||||
return GA_NAME;
|
||||
|
||||
case EA_KRT_REALM:
|
||||
bsprintf(buf, "realm");
|
||||
return GA_NAME;
|
||||
|
||||
case EA_KRT_SCOPE:
|
||||
bsprintf(buf, "scope");
|
||||
return GA_NAME;
|
||||
|
||||
case EA_KRT_LOCK:
|
||||
buf += bsprintf(buf, "lock:");
|
||||
ea_format_bitfield(a, buf, buflen, krt_metrics_names, 2, KRT_METRICS_MAX);
|
||||
return GA_FULL;
|
||||
|
||||
case EA_KRT_FEATURES:
|
||||
buf += bsprintf(buf, "features:");
|
||||
ea_format_bitfield(a, buf, buflen, krt_features_names, 0, KRT_FEATURES_MAX);
|
||||
return GA_FULL;
|
||||
|
||||
default:;
|
||||
int id = (int)EA_ID(a->id) - KRT_METRICS_OFFSET;
|
||||
if (id > 0 && id < KRT_METRICS_MAX)
|
||||
{
|
||||
bsprintf(buf, "%s", krt_metrics_names[id]);
|
||||
return GA_NAME;
|
||||
}
|
||||
|
||||
return GA_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
kif_sys_start(struct kif_proto *p UNUSED)
|
||||
{
|
||||
|
Reference in New Issue
Block a user