I have the following code to unregister and register sip conntrack from kernel 3.18
static void __nf_conntrack_sip_fini(void)
{
int i, j;
for (i = 0; i < ports_c; i++) {
for (j = 0; j < ARRAY_SIZE(sip[i]); j++) {
if (sip[i][j].me == NULL)
continue;
nf_conntrack_helper_unregister(&sip[i][j]);
}
}
memset(sip, 0, sizeof(sip));
}
static int __nf_conntrack_sip_init(void)
{
int i, j, ret;
if (ports_c == 0)
ports[ports_c++] = SIP_PORT;
for (i = 0; i < ports_c; i++) {
memset(&sip[i], 0, sizeof(sip[i]));
sip[i][0].tuple.src.l3num = AF_INET;
sip[i][0].tuple.dst.protonum = IPPROTO_UDP;
sip[i][0].help = sip_help_udp;
sip[i][1].tuple.src.l3num = AF_INET;
sip[i][1].tuple.dst.protonum = IPPROTO_TCP;
sip[i][1].help = sip_help_tcp;
sip[i][2].tuple.src.l3num = AF_INET6;
sip[i][2].tuple.dst.protonum = IPPROTO_UDP;
sip[i][2].help = sip_help_udp;
sip[i][3].tuple.src.l3num = AF_INET6;
sip[i][3].tuple.dst.protonum = IPPROTO_TCP;
sip[i][3].help = sip_help_tcp;
for (j = 0; j < ARRAY_SIZE(sip[i]); j++) {
sip[i][j].data_len = sizeof(struct nf_ct_sip_master);
sip[i][j].tuple.src.u.udp.port = htons(ports[i]);
sip[i][j].expect_policy = sip_exp_policy;
sip[i][j].expect_class_max = SIP_EXPECT_MAX;
sip[i][j].me = THIS_MODULE;
if (ports[i] == SIP_PORT)
sprintf(sip[i][j].name, "sip");
else
sprintf(sip[i][j].name, "sip-%u", i);
pr_debug("port #%u: %u\n", i, ports[i]);
ret = nf_conntrack_helper_register(&sip[i][j]);
if (ret) {
printk(KERN_ERR "nf_ct_sip: failed to register"
" helper for pf: %u port: %u i=%d\n",
sip[i][j].tuple.src.l3num, ports[i], i);
__nf_conntrack_sip_fini();
return ret;
}
}
}
return 0;
}
I developed the following code to restart the registred sip conntrack with the same first port
static void nf_conntrack_sip_restart(void)
{
//here ports[] = {5060, 0}
__nf_conntrack_sip_fini();
memcpy(ports,newports,sizeof(ports));
//here ports[] = {5060, 5555}
__nf_conntrack_sip_init(); // <---- It fails
}
when I trigger this restart function from the user space the register of the new ports array fails
If I use other ports, then it works:
static void nf_conntrack_sip_restart(void)
{
//here ports[] = {5060, 0}
__nf_conntrack_sip_fini();
memcpy(ports,newports,sizeof(ports));
//here ports[] = {5061, 5555}
__nf_conntrack_sip_init(); // <---- It works
}
What I m missing?
Here after the whole source code of the nf_conntrack_sip.c file with my modifications: http://vpaste.net/PgUVD
To see my modifications you can make diff with origin source code of linux 3.18
The
nf_conntrack_helper_register
function fails because of duplicated entry in connection tracking table, and its return code could be 0 or -EEXIST according to its implementation in 3.18. However I didn't see any problem with your code snip, could you check other places in your code where you might insert a duplicatenf_conntrack_helper
?You cannot call a modules
init
andexit
functions directly and expect them to work without first making sure the module is no longer used in any way.The
init
andexit
functions are called in a particular way ie they're safe to make a lot of assumptions about what locks are held etc before they're called. Your code is bypassing all of this and assuming that if called directly they'll work. This is not the case.If you look at
delete_module
it's non trivial, it's preparing to unload your module and this checks if your module is being used. Lets assume your code is currently servicing a request, you really don't want your module and it's associated data structures to vanish while running ie undefined behavior almost certainly resulting in a kernel panic or something much worse...The following is a short synopsis of what the kernel does before it calls the exit routine
module_lock
, wait until it can get it.init
orexit
routine.exit
function.mutex_lock
At this point we have the following comment
Your code is not doing any of the 6 steps listed above. This is the source of delete module on a 3.16 kernel which I suspect is identical to 3.18...
Near the end it runs your exit function but only after it makes sure that no one is actually using it etc. To be able to call the functions the way you want you need to understand loading and unloading modules.
I see you've edited the question and it's now clear where the code came from
It would have helped if you'd mentioned that that you'd cut and paste the
init
andexit
functions from nf_conntrack_sip. It would likely have saved a lot of people a lot of time wondering why it didn't work.