sysctl与devlink总结

整体概述

由于自己水平和精力有限,本篇博文只涉及如何使用的问题,不涉及讲解原理,如果有朋友对如何创建命令的原理感兴趣,可以自己进行探讨。

sysctl概述

在FreeBSD系统上,设备通信和控制主要通过sysctl和ioctl接口,也就是在用户层(shell)配置的方式,进行对底层驱动参数的一个设置。
具体使用方式例如:
sysctl -A : 通过此命令查看系统当中都有那些可以配置的参数。
比如输入sysctl -A命令后有以下输出,
a.b.c : 1
a.b.c是一种二进制的表示方式,1代表某个参数的值,当然也可以是字符类型或者结构体等。具体的后面遇到代码再讲解。
随后,如果我们输入sysctl a.b.c命令是查看该参数的值,
而sysctl a.b.c=2是将此参数的值进行修改,如果你看到有
0 -> 2的输出就代表值从0修改为了2,已经成功修改了。

sysctl的创建

freebsd提供了以下的宏供我们创建sysctl

#include <sys/types.h>
#include <sys/sysctl.h>

struct sysctl_oid *
SYSCTL_ADD_OID(struct sysctl_ctx_list *ctx,
struct sysctl_oid_list *parent, int number, const char *name,int kind, void *arg1, int arg2, int (*handler) (SYSCTL_HANDLER_ARGS),const char *format, const char *descr);
 
struct sysctl_oid *
SYSCTL_ADD_NODE(struct sysctl_ctx_list *ctx,
struct sysctl_oid_list *parent, int number, const char *name,int access, int (*handler) (SYSCTL_HANDLER_ARGS), const char *descr);

struct sysctl_oid *
SYSCTL_ADD_STRING(struct sysctl_ctx_list *ctx,struct sysctl_oid_list *parent, int number, const char *name,int access, char *arg, int len, const char *descr);

struct sysctl_oid *
SYSCTL_ADD_INT(struct sysctl_ctx_list *ctx,
struct sysctl_oid_list *parent, int number, const char *name,int access, int *arg, int len, const char *descr);

struct sysctl_oid *
SYSCTL_ADD_UINT(struct sysctl_ctx_list *ctx,
struct sysctl_oid_list *parent, int number, const char *name,int access, unsigned int *arg, int len, const char *descr);

struct sysctl_oid *
SYSCTL_ADD_LONG(struct sysctl_ctx_list *ctx,
struct sysctl_oid_list *parent, int number, const char *name,int access, long *arg, const char *descr);

struct sysctl_oid *
SYSCTL_ADD_ULONG(struct sysctl_ctx_list *ctx,
struct sysctl_oid_list *parent, int number, const char *name,int access, unsigned long *arg, const char *descr);

struct sysctl_oid *
SYSCTL_ADD_OPAQUE(struct sysctl_ctx_list *ctx,
struct sysctl_oid_list *parent, int number, const char *name,int access, void *arg, int len, const char *format,const char *descr);

struct sysctl_oid *
SYSCTL_ADD_STRUCT(struct sysctl_ctx_list *ctx,
struct sysctl_oid_list *parent, int number, const char *name,int access, void *arg, STRUCT_NAME, const char *descr);

struct sysctl_oid *
SYSCTL_ADD_PROC(struct sysctl_ctx_list *ctx,struct sysctl_oid_list *parent, int number, const char *name,int access, void *arg, int len,int (*handler) (SYSCTL_HANDLER_ARGS), const char *format,
const char *descr);

SYSCTL_ADD_OID 宏将创建一个能处理任意数据类型的 sysctl。如果调用成功,宏 将返回一个指向该 sysctl 的指针,否则返回 NULL。 其他 SYSCTL_ADD_* 宏都是 SYSCTL_ADD_OID 的变种,用于创建能处理特殊数据类型变量的 sysctl。这些宏的解释如下:

SYSCTL_ADD_NODE 创建一个新结点(或类别),该类别可以有子类
SYSCTL_ADD_STRING创建一个处理空结尾(null-terminated)字符串的新sysctl
SYSCTL_ADD_INT创建一个处理整型变量的新sysctl
SYSCTL_ADD_UINT创建一个处理无符号整型变量的新sysctl
SYSCTL_ADD_LONG创建一个处理长整型变量的新 sysctl
SYSCTL_ADD_ULONG创建一个处理无符号长整型变量的新 sysctl
SYSCTL_ADD_OPAQUE创建一个处理一块数据的新sysctl,所处理的数据类型可调整,大小通过参数len指定
SYSCTL_ADD_STRUCT创建一个处理结构体的新sysctl
SYSCTL_ADD_PROC创建一个能使用函数来处理其读写请求的新 sysctl,该“处理函数”通常 用于在导入或导出前处理相应数据

参数的意义如下:
在这里插入图片描述

sysctl例程感性认识

我们通过一个例程对怎么创建sysctl配置命令的有一个感性认识。如下
my_sysctl.c

#include<sys/param.h>
#include<sys/module.h>
#include<sys/kernel.h>
#include<sys/systm.h>
#include<sys/sysctl.h>

static struct sysctl_ctx_list clist;
static struct sysctl_oid *poid;

static int i = 10;
static long j = 20;
static const char *c = "hello init";

static int
sysctl_procedure(SYSCTL_HANDLER_ARGS)
{
    const char *buf = "sysctl_procedure call";
    return sysctl_handle_string(oidp, buf, strlen(buf), req);
}

static int
sysctl_modevent(module_t mod_unused, int event, void *arg __unused)
{
    int error = 0;
    switch (event) {
    case MOD_LOAD:
        sysctl_ctx_init(&clist);

        /*SYSCTL_STATIC_CHILDREN里面的参数为空,那么top为顶层节点*/
        poid = SYSCTL_ADD_NODE(&clist, SYSCTL_STATIC_CHILDREN(/*top name*/), OID_AUTO,
        "top", CTLFLAG_RW, 0, "tree top");
        if (poid == NULL) {
            printf("SYSCTL_ADD_NODE failed\n");
            return EINVAL;
        }

        /*这里注意第二个参数,poid是上一个函数(SYSCTL_ADD_NODE)的返回值,所以有top.long -> 20*/
        SYSCTL_ADD_LONG(&clist, SYSCTL_CHILDREN(poid), OID_AUTO,
        "long", CTLFLAG_RW, &j, 0, "creat long leaf");

        /*top.int -> 10*/
        SYSCTL_ADD_INT(&clist, SYSCTL_CHILDREN(poid), OID_AUTO,
        "int", CTLFLAG_RW, &i, 0, "creat int leaf");

        /*这里也创建了一个节点,使用的是top为父节点,所以有top.node*/
        poid = SYSCTL_ADD_NODE(&clist, SYSCTL_STATIC_CHILDREN(poid), OID_AUTO,
        "node", CTLFLAG_RW, 0, "tree node");
        if (poid == NULL) {
            printf("SYSCTL_ADD_NODE failed\n");
            return EINVAL;
        }

        /*top.node.proc -> sysctl_procedure call*/
        SYSCTL_ADD_PROC(&clist, SYSCTL_CHILDREN(poid), OID_AUTO,
        "proc", CTLFLAG_RD, 0, 0, sysctl_procedure, "A", "creat proc leaf");

       /*这里创建了一个新的节点,所以有_debug.top, 这里没有显示指定poid, 可以设定连接到哪一个父节点上去*/
        poid = SYSCTL_ADD_NODE(&clist, SYSCTL_STATIC_CHILDREN(_debug), OID_AUTO,
        "top", CTLFLAG_RW, 0, "tree node");
        if(poid == NULL) {
            printf("SYSCTL_ADD_NODE failed\n");
            return EINVAL;
        }

        /*_debug.top.string -> c*/
        SYSCTL_ADD_STRING(&clist, SYSCTL_CHILDREN(poid), OID_AUTO,
        "string", CTLFLAG_RD, c, 0, "new string leaf");

        printf("module loaded\n");
        break;
    case MOD_UNLOAD:
        if (sysctl_ctx_free(&clist)) {
            printf("sysctl_ctx_free failed.\n");
            return -1;
        }
        printf("module unloaded\n");
        break;
    default:
        error = -1;
        break;
     }
    return error;
}

static moduledata_t sysctl_mod = {
    "sysctl_modevent",
    sysctl_modevent,
    NULL
};
DECLARE_MODULE(sysctl_modevent, sysctl_mod, SI_SUB_EXEC, SI_ORDER_ANY);

makefile:

SRCS=my_sysctl.c
KMOD=my_sysctl

.include <bsd.kmod.mk>

在上面的例程当中注意看注释,这里有一点比较疑惑的地方就是根据参考链接的说明在使用SYSCTL_STATIC_CHILDREN时如果传递的参数为空,我是编译错误的,创建不了顶层节点,这里先不管它了,实际工作当中我们应该不会创建顶层节点,而是在顶层节点的基础上进行的追加。

假设上面的代码如果不会编译错误的话,那么在kldload my_sysctl.ko以后,使用sysctl -A命令时,应该会有如下字样的出现

top.long : 10
top.int : 20
top.node.proc:sysctl_procedure call
debug.top.string : hello init

注意上面的初始值。

动态创建sysctl宏总结

SYSCTL_STATIC_CHILDREN 宏

原型如下:

#include<sys/types.h>
#include<sys/sysctl.h>

struct sysctl_oid_list *
SYSCTL_STATIC_CHILDREN(struct sysctl_oid_list OID_NAME);

我们在追加节点时,可以通过使用SYSCTL_STATIC_CHILDREN或者SYSCTL_CHILDREN,进行对父节点的连接,在使用SYSCTL_STATIC_CHILDREN时,传递的参数是父节点的名称,比如现在系统有一个dev名称的父节点,我们可以传递_dev,这里必须要待下划线,如果要创建一个顶层的节点,那么传递的参数要为空(这点我没想明白,编译出错了)。

SYSCTL_CHILDREN宏

原型

#include <sys/sysctl.h>
#include <sys/types.h>
struct sysctl_oid_list *
SYSCTL_CHILDREN(struct sysctl_oid *oidp);

一般在使用SYSCTL_ADD_系列的宏追加节点时,传递的都是SYSCTL_CHILDREN。

sysctl接口的简单使用

例如我们想在系统当中增加一个对内存缓冲区控制的参数。

static int
sysctl_set_buffer_size(SYSCTL_HANDLER_ARGS)
{
    int error = 0;
    /*假设echo_message->buffer_size是我们要设置的参数*/
    int size = echo_message->buffer_size;
    /*这里size是命令行设置下来的参数*/
    error = sysctl_handle_int(oidp, &size, 0, req);
    if (error || !req->newptr || echo_message->buffer_size == size)
        return (error);
    //.....省略其它处理步骤
    //最后会有这个赋值当中,系统当中都是这样做的,如果我们设置成功了,那么会有提示,比如0 -> 5表示我们把值从0修改为了5.
    echo_message->buffer_size = size;
   //....
 return (error);
}

稍微总结一下,一般在工作当中最佳sysctl节点的步骤,先调用sysctl_ctx_init进行初始化,然后调用ADD系列的宏进行命令的追加,当然如果要进入某个函数当中,需要使用PORC宏,
最后就是调用sysctl_ctx_free函数进行释放了,这个是对简单的整数值的设置。如果有对结构体进行设置,使用相应的宏应该就可以了。

参考文章:
1:添加链接描述
2:添加链接描述
3:添加链接描述

devlink概述

这个命令的设置比较简单,参考下系统当中的其它源代码应该没啥问题。具体的命令含义以及使用方法可以参考:
添加链接描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值