LINUX.ORG.RU

Утекает память.

 ,


0

1

Привет.
Пишу модуль для ядра, который пока просто будет пересылать все приходящие пакеты.
Столкнулся с проблемой, что утекает память, хотя неясно, где и в чем причина. И почему-то откусывается mac-уровень, приходится его дополнительно пушить.

//INCLUDES//////////////////////////////////////////////////////////////


#include <linux/module.h>
#include <linux/version.h>
#include <linux/byteorder/generic.h>
#include <linux/netdevice.h>
#include <net/protocol.h>
#include <net/pkt_sched.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/skbuff.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/file.h>
#include <asm/uaccess.h>


#include <net/udp.h>
#include <linux/string.h>
#include <linux/fs.h>
#include <asm/segment.h>
#include <linux/buffer_head.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/syscalls.h>
#include <linux/file.h>
#include <linux/fcntl.h>
#include <asm/uaccess.h>
#include <net/inet_sock.h>
#include <linux/inet.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/dirent.h>
#include <linux/types.h>
#include <linux/in.h>
#include <net/sock.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <linux/if_arp.h>
#include <asm/unaligned.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/ip.h>
#include <linux/tcp.h>

//ABOUT/////////////////////////////////////////////////////////////////

MODULE_AUTHOR("");
MODULE_DESCRIPTION("");
MODULE_LICENSE("GPL");
MODULE_VERSION("0.0.1");

//DEFINES///////////////////////////////////////////////////////////////

//SYSCALLS//////////////////////////////////////////////////////////////

//PROTOTYPES/////////////////////////////////////////////////////////////
int new_hook_func(struct sk_buff *skb, struct device *dv, struct packet_type *pt);

//GLOBALS///////////////////////////////////////////////////////////////
static struct packet_type my_packet_type;
static char *dev = "eth0";
struct net_dev *d;

//INIT//////////////////////////////////////////////////////////////////
static int __init init(void)
{
	printk(KERN_ALERT "module init");
	d = dev_get_by_name(&init_net, dev);
	my_packet_type.type = htons(ETH_P_ALL); 
	my_packet_type.func = new_hook_func;
	my_packet_type.dev = d;
	dev_add_pack(&my_packet_type);
	return 0;
}

//EXIT//////////////////////////////////////////////////////////////////
static void __exit exit(void)
{
	dev_remove_pack(&my_packet_type);
	printk(KERN_ALERT "module exit");
}

////////////////////////////////////////////////////////////////////////

module_init(init);
module_exit(exit);

////////////////////////////////////////////////////////////////////////


//CORE//////////////////////////////////////////////////////////////////


int new_hook_func(struct sk_buff *skb, struct device *dv, struct packet_type *pt)
{
	struct iphdr *ip;
	ip = (struct iphdr*)skb_network_header(skb);
	if(skb->pkt_type != PACKET_OUTGOING)
	{
		if(ip->version == 4 && ip->protocol == IPPROTO_ICMP)
		{
			struct sk_buff *my_skb = 0;
			//copy incoming skb
			my_skb = skb_copy_expand(skb, 16, 16, GFP_ATOMIC);
			//get eth header
		        struct ethhdr *eth = eth_hdr(my_skb);
			//push ethernet layer to skb
		        eth = (struct ethhdr*) skb_push(my_skb, ETH_HLEN);
			//set packet type to outgoing
		        skb->pkt_type = PACKET_OUTGOING;
			//send skb struct
		        dev_queue_xmit(my_skb);
//			kfree_skb(my_skb);
//			kfree_skb(skb);
//			kfree(eth);
		}
	}
//	kfree(ip);
    	return NF_ACCEPT;
}
dev_queue_xmit(), по идее, сам очищает структуру skb. Структуры заголовков(ip, eth) освобождать kfree не получается: получаю панику. В чужих примерах кода эти структуры тоже не очищаются.
Помогите, пожалуйста, избавиться от утекающей памяти.

Deleted

Ответ на: комментарий от Deleted

skb_network_header

я про то, что действительно ли эта функция выделяет память чтобы её освобождать, иначе если это всеголишь смещение от skb, то skb должен отчищать тот кто выделил

visual ★★★ ()
Ответ на: комментарий от visual

Да, согласен.
Поэкспериментировал: закомментил все тело хука, оставил только return, память все равно течет.

Deleted ()

Более того, при разных кодах возврата: 0(NET_RX_ACCEPT) или 1(NET_RX_DROP) ничего не происходит. Пакеты продолжают приниматься.

Deleted ()
Ответ на: комментарий от Deleted

Ну это… я вряд ли тебе помогу. Но у меня есть предложение комментировать строчки до тех пор, пока перестанет текти, а потом смотреть, что получилось.

post-factum ★★★★★ ()
Ответ на: комментарий от post-factum

я практически на 100% уверен, что память перестанет утекать, когда я закоменчу строчку, регистрирующую хук. Завтра это проверю. Может, насоветуешь, куда можно написать/обратиться? Был на канале kernel и kernelnewbie, безрезультатно.

Deleted ()

Я не совсем понял ваши действия с skb_push. Вы получаете указатель (eth) на область памяти, но ничего туда не пишите.

skb_copy_expand() хорошо бы вызывать не с «16, 16», а с sizeof(). Но это мелочи.

kfree_skb(skb), вроде, нужно делать в любом случае, не только для PACKET_OUTGOING. kfree_skb(my_skb) делать не нужно.

mky ★★★★★ ()

kfree(my_skb) надо оставить. И d на exit освободить.

Это насколько я помню как их писать (леть пять уже хуки не писал).

Delirium_veritas ()
Ответ на: комментарий от mky

С утечкой памяти разобрался: надо освобождать skb, my_skb трогать не нужно.
skb_push приходится вызывать для того, чтобы в исходящем пакете появился второй уровень, почему происходит так - не знаю. Насчет указателя на eth: до этого там были отладочные штуки, не все удалил.
Осталась проблема: пакеты не дропаются в зависимости от кода возврата. Перепробовал кучу разных, все равно идут.

Deleted ()
Ответ на: комментарий от Chubakur

У меня 2 метра рамы свободной, когда воткнул модуль, оно достаточно скоро вылетело по оом. Потом я начал жмакать быстро free и увидел, что память тает, даже когда не должна.

Deleted ()
Ответ на: комментарий от bk_

Проблему с утечкой памяти пофиксил. Почему модуль плюет на коды возврата - нет. Буду завтра с работы, выложу сюда код.

Deleted ()
Ответ на: комментарий от Deleted

Я не особо знаю ядро и исходники смотреть лень. Раньше на код возврата функции, регестрируемой через dev_add_pack(), ядру было совершенно пофиг. Если вам нужен фильтр, который сообщает NF_ACCEPT или NF_DROP, то он создаётся через nf_register_hook().

mky ★★★★★ ()
Ответ на: комментарий от mky

Да, но это уже нетфильтр. Должна же быть возможность дропать произвольный пакет. Видимо, и сейчас ядру пофигу на этот код возврата, придется оставлять нетфильтр. Спасибо за помощь.

Deleted ()
Ответ на: комментарий от Deleted

Я от бессоницы немного посмотрел инет и исходники ядра. В общем, получается, что при вызове вашей функции из __netif_receive_skb() -> deliver_skb() она получает shared skb, то есть перед вызовом делается atomic_inc(&skb->users), а free_skb(skb) просто уменьшает этот счётчик, то есть skb фактически не освобождается.

В реализации ip-протокола в функции ip_rcv, которая аналогично вашей регестрируется через dev_add_pack в файле kernel-source/net/ipv4/af_inet.c, буфер skb превращается в обычный через skb = skb_share_check(skb, GFP_ATOMIC). И, видимо, для такого буфера kfree_skb(skb) означает DROP пакета.

http://www.ecsl.cs.sunysb.edu/elibrary/linux/network/iprecv.pdf

mky ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.