通过打开 kernel 的 menuconfig 的SCTP_DBG_MSG
选项可以输出sctp的debug日志。
但是debug消息输出较多,如果没有不需要定位sctp问题时最好能关闭debug日志。现有一需求,能在不更换kernel的情况下控制sctp debug是否开启。
记录下在/proc/sys/net/sctp下添加一配置文件以实现配置日志是否输出的功能。
首先看下SCTP_DBG_MSG
是如何控制日志是否输出的:
kernel\include\net\sctp\sctp.h
/* Print debugging messages. */
#if SCTP_DEBUG
extern int sctp_debug_flag;
#define SCTP_DEBUG_PRINTK(fmt, args...) \
do { \
if (sctp_debug_flag) \
printk(KERN_DEBUG pr_fmt(fmt), ##args); \
} while (0)
#define SCTP_DEBUG_PRINTK_CONT(fmt, args...) \
do { \
if (sctp_debug_flag) \
pr_cont(fmt, ##args); \
} while (0)
#define SCTP_DEBUG_PRINTK_IPADDR(fmt_lead, fmt_trail, \
args_lead, addr, args_trail...) \
do { \
const union sctp_addr *_addr = (addr); \
if (sctp_debug_flag) { \
if (_addr->sa.sa_family == AF_INET6) { \
printk(KERN_DEBUG \
pr_fmt(fmt_lead "%pI6" fmt_trail), \
args_lead, \
&_addr->v6.sin6_addr, \
args_trail); \
} else { \
printk(KERN_DEBUG \
pr_fmt(fmt_lead "%pI4" fmt_trail), \
args_lead, \
&_addr->v4.sin_addr.s_addr, \
args_trail); \
} \
} \
} while (0)
#define SCTP_ENABLE_DEBUG { sctp_debug_flag = 1; }
#define SCTP_DISABLE_DEBUG { sctp_debug_flag = 0; }
#define SCTP_ASSERT(expr, str, func) \
if (!(expr)) { \
SCTP_DEBUG_PRINTK("Assertion Failed: %s(%s) at %s:%s:%d\n", \
str, (#expr), __FILE__, __func__, __LINE__); \
func; \
}
#else /* SCTP_DEBUG */
#define SCTP_DEBUG_PRINTK(whatever...)
#define SCTP_DEBUG_PRINTK_CONT(fmt, args...)
#define SCTP_DEBUG_PRINTK_IPADDR(whatever...)
#define SCTP_ENABLE_DEBUG
#define SCTP_DISABLE_DEBUG
#define SCTP_ASSERT(expr, str, func)
#endif /* SCTP_DEBUG */
可以看出如果SCTP_DEBUG
宏的值不为0的话就会将输出函数替换为printk
,如果为0的话则这些函数为空。
值得注意的是将输出函数替换为printk
时会先判断一下变量sctp_debug_flag
。
if (sctp_debug_flag)
printk(KERN_DEBUG pr_fmt(fmt), ##args);
这个变量会在定义时赋值为1
kernel\net\sctp\debug.c
#if SCTP_DEBUG
int sctp_debug_flag = 1; /* Initially enable DEBUG */
#endif /* SCTP_DEBUG */
那么如果只要将修改sctp_debug_flag
的值就可实现开关debug日志的输出。
我们知道,内核和用户空间之间是隔离的,而常见的交互方法是通过/proc /sys等vfs。搜了一下,发现sctp在/proc/sys/net/sctp/下有专门的目录,里面已经放了一些配置选项了,而且有些配置和我们的需求很像,都是通过一个文件配置一个变量。
这些配置文件的实现方法:
LINUX\opensource\kernel\net\sctp\sysctl.c
static ctl_table sctp_net_table[] = {
{
.procname = "rto_initial",
.data = &init_net.sctp.rto_initial,
.maxlen = sizeof(unsigned int),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
.extra1 = &one,
.extra2 = &timer_max
},
{
.procname = "rto_min",
.data = &init_net.sctp.rto_min,
.maxlen = sizeof(unsigned int),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
.extra1 = &one,
.extra2 = &timer_max
},
{
.procname = "rto_max",
.data = &init_net.sctp.rto_max,
.maxlen = sizeof(unsigned int),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
.extra1 = &one,
.extra2 = &timer_max
},
{
.procname = "rto_alpha_exp_divisor",
.data = &init_net.sctp.rto_alpha,
.maxlen = sizeof(int),
.mode = 0444,
.proc_handler = proc_dointvec,
},
{
.procname = "rto_beta_exp_divisor",
.data = &init_net.sctp.rto_beta,
.maxlen = sizeof(int),
.mode = 0444,
.proc_handler = proc_dointvec,
},
{
.procname = "max_burst",
.data = &init_net.sctp.max_burst,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
.extra1 = &zero,
.extra2 = &int_max
},
{
.procname = "cookie_preserve_enable",
.data = &init_net.sctp.cookie_preserve_enable,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec,
},
{
.procname = "cookie_hmac_alg",
.maxlen = 8,
.mode = 0644,
.proc_handler = proc_sctp_do_hmac_alg,
},
{
.procname = "valid_cookie_life",
.data = &init_net.sctp.valid_cookie_life,
.maxlen = sizeof(unsigned int),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
.extra1 = &one,
.extra2 = &timer_max
},
{
.procname = "sack_timeout",
.data = &init_net.sctp.sack_timeout,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
.extra1 = &sack_timer_min,
.extra2 = &sack_timer_max,
},
{
.procname = "hb_interval",
.data = &init_net.sctp.hb_interval,
.maxlen = sizeof(unsigned int),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
.extra1 = &one,
.extra2 = &timer_max
},
{
.procname = "association_max_retrans",
.data = &init_net.sctp.max_retrans_association,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
.extra1 = &one,
.extra2 = &int_max
},
{
.procname = "path_max_retrans",
.data = &init_net.sctp.max_retrans_path,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
.extra1 = &one,
.extra2 = &int_max
},
{
.procname = "max_init_retransmits",
.data = &init_net.sctp.max_retrans_init,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
.extra1 = &one,
.extra2 = &int_max
},
{
.procname = "pf_retrans",
.data = &init_net.sctp.pf_retrans,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
.extra1 = &zero,
.extra2 = &int_max
},
{
.procname = "sndbuf_policy",
.data = &init_net.sctp.sndbuf_policy,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec,
},
{
.procname = "rcvbuf_policy",
.data = &init_net.sctp.rcvbuf_policy,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec,
},
{
.procname = "default_auto_asconf",
.data = &init_net.sctp.default_auto_asconf,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec,
},
{
.procname = "addip_enable",
.data = &init_net.sctp.addip_enable,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec,
},
{
.procname = "addip_noauth_enable",
.data = &init_net.sctp.addip_noauth,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec,
},
{
.procname = "prsctp_enable",
.data = &init_net.sctp.prsctp_enable,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec,
},
{
.procname = "auth_enable",
.data = &init_net.sctp.auth_enable,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_sctp_do_auth,
},
{
.procname = "addr_scope_policy",
.data = &init_net.sctp.scope_policy,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
.extra1 = &zero,
.extra2 = &addr_scope_max,
},
{
.procname = "rwnd_update_shift",
.data = &init_net.sctp.rwnd_upd_shift,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec_minmax,
.extra1 = &one,
.extra2 = &rwnd_scale_max,
},
{
.procname = "max_autoclose",
.data = &init_net.sctp.max_autoclose,
.maxlen = sizeof(unsigned long),
.mode = 0644,
.proc_handler = &proc_doulongvec_minmax,
.extra1 = &max_autoclose_min,
.extra2 = &max_autoclose_max,
},
{ /* sentinel */ }
};
以prsctp_enable
为例
.procname 文件名
.data 要修改的变量
.maxlen 变量大小
.mode 文件权限
.proc_handler 接口函数
仿照这个格式,添加我们自己的结构:
{
.procname = "sctp_debug_print_enable",
.data = &sctp_debug_flag,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec,
},
编译运行后果然生成了 /proc/sys/net/sctp/sctp_debug_print_enable 文件
使用方法
打开debug输出 echo 0 > /proc/sys/net/sctp/sctp_debug_print_enable
关闭debug输出 echo 1 > /proc/sys/net/sctp/sctp_debug_print_enable
查看debug状态 cat /proc/sys/net/sctp/sctp_debug_print_enable