L2 Switch를 만들고 싶습니다.

cjy1126의 이미지

http://www.f-net.co.kr/index.html?node=02020105&sub=2#2

이 제품과 비슷한 기능을 가진 L2 Switch를 만들려고 합니다.

이 L2 Switch를 구현하려는 컴퓨터는 Linux 2.4.24에 랜카드가 5개 있습니다.

제가 생각하는 구성도는 2가지입니다.

1번째 구성도입니다.


             Router
               |
            Firewall
               |      +--- NIDS
           L2 Switch --                  << 이 L2 Switch를 구현하려 합니다.
               |      +--- NIDS
               |
               |
              Host                       << 서비스를하는 서버가 될수도 있고, 일반 클라이언트가 될수도 있습니다.

패킷의 흐름입니다.

Route -> Firewall -> L2 Switch ---> Host
                         |
                         ---------> NIDS

L2 Switch에서 Host에 패킷을 흘리면서 동시에 한대의 NIDS에 패킷을 보내줍니다.

NIDS의 선택은 NIDS의 리소스상태, 트래픽을보고 부하가 적은것으로 선택합니다.

2번째 구성도 입니다.

             Router
               |
            Firewall
               |      +--- IPS
           L2 Switch --                  << 이 L2 Switch를 구현하려 합니다.
               |      +--- IPS
               |
               |
              Host                       << 서비스를하는 서버가 될수도 있고, 일반 클라이언트가 될수도 있습니다.

패킷의 흐름입니다.

Route -> Firewall -> L2 Switch -> IPS -> Host

1. L2 Switch에서 Firewall쪽에 있는 랜카드에서 받은 패킷이면 한대의 IPS로 패킷을 전송합니다.

2. IPS를 통과한 패킷은 다시 L2 Switch로 들어옵니다.

3. L2 Switch는 IPS와 연결된 랜카드에서 온 패킷(안전한 패킷)임을 알고로 Host로 패킷을 전송합니다.

IPS의 선택은 NIDS와 동일한 방법을 사용합니다.

가능하면 옵션을줘서 2가지가 다 되게하려고 합니다.

http://open-source.arkoon.net/kernel/kernel_net.png

일단 ip계층을 통과안시키는 허브의 역할을 하기위해서 netif_rx함수에서 패킷을 잡고, 이 패킷을 dev_queue_xmit함수로 보내려합니다.

현재 TEST하는 구성도입니다.

              | 203.227.xxx.246
            Route
              | 192.168.100.1
              |
              | 192.168.100.11
          Firewall
              | 192.168.100.12
              |
              | 192.168.100.25 (eth0)
          L2 Switch
              | 203.227.xxx.248
              |
              | 203.227.xxx.243
            Host A


1. 203.227.xxx.243의 default gw은 203.227.xxx.248로 잡았습니다.

2. Host A에서 Firewall의 IP인 192.168.100.12로 ping을 쏩니다.

3. L2 Switch는 받은 패킷의 source MAC이 Host A의 MAC이면 그 패킷의 정보를 수정한후 dev_queue_xmit으로 보냅니다.

    수정하는 정보: 1. skb->mac.ethernet->h_dest (192.168.100.12의 MAC로)
               2. skb->dev = dev_get_by_name("eth0"); (패킷을 쏠 device를 192.168.100.25의 device pointer로)

원래 dev.c의 netif_rx

int netif_rx(struct sk_buff *skb)
{
	int this_cpu = smp_processor_id();
	struct softnet_data *queue;
	unsigned long flags;

	if (skb->stamp.tv_sec == 0)
		do_gettimeofday(&skb->stamp);

	/* The code is rearranged so that the path is the most
	   short when CPU is congested, but is still operating.
	 */
	queue = &softnet_data[this_cpu];

	local_irq_save(flags);

	netdev_rx_stat[this_cpu].total++;
	if (queue->input_pkt_queue.qlen <= netdev_max_backlog) {
		if (queue->input_pkt_queue.qlen) {
			if (queue->throttle)
				goto drop;

enqueue:
			dev_hold(skb->dev);
			__skb_queue_tail(&queue->input_pkt_queue,skb);
			local_irq_restore(flags);
#ifndef OFFLINE_SAMPLE
			get_sample_stats(this_cpu);
#endif
			return queue->cng_level;
		}

		if (queue->throttle) {
			queue->throttle = 0;
#ifdef CONFIG_NET_HW_FLOWCONTROL
			if (atomic_dec_and_test(&netdev_dropping))
				netdev_wakeup();
#endif
		}

		netif_rx_schedule(&queue->blog_dev);
		goto enqueue;
	}

	if (queue->throttle == 0) {
		queue->throttle = 1;
		netdev_rx_stat[this_cpu].throttled++;
#ifdef CONFIG_NET_HW_FLOWCONTROL
		atomic_inc(&netdev_dropping);
#endif
	}

drop:
	netdev_rx_stat[this_cpu].dropped++;
	local_irq_restore(flags);

	kfree_skb(skb);
	return NET_RX_DROP;
}

바꾼 netif_rx

int netif_rx(struct sk_buff *skb)
{
	int this_cpu = smp_processor_id();
	struct softnet_data *queue;
	unsigned long flags;

	struct ethhdr temp;           

	temp.h_source[0] = 0x00;        /*제가 test로 접속하는 컴퓨터의 MAC주소입니다.*/
	temp.h_source[1] = 0x03;
	temp.h_source[2] = 0x47;
	temp.h_source[3] = 0xe0;
	temp.h_source[4] = 0xb2;
	temp.h_source[5] = 0x2c;
	
	if (skb->stamp.tv_sec == 0)
		do_gettimeofday(&skb->stamp);

	/* The code is rearranged so that the path is the most
	   short when CPU is congested, but is still operating.
	 */
	queue = &softnet_data[this_cpu];

	local_irq_save(flags);

	netdev_rx_stat[this_cpu].total++;

	if(!memcmp(temp.h_source, skb->mac.ethernet->h_source, 6))             /*받은 패킷이 제가 보낸 패킷이면*/
	{
		printk("######### TEST #########\n");

		skb->mac.ethernet->h_dest[0] = 0x00;     /*패킷의 목적지 MAC에 192.168.100.12의 MAC 을 넣습니다.*/
		skb->mac.ethernet->h_dest[1] = 0x01;
		skb->mac.ethernet->h_dest[2] = 0x03;
		skb->mac.ethernet->h_dest[3] = 0x45;
		skb->mac.ethernet->h_dest[4] = 0x61;
		skb->mac.ethernet->h_dest[5] = 0xd4;

		skb->dev = dev_get_by_name("eth0"); /*192.168.100.12와 붙어있는 device...
                                           즉 192.168.100.25인 eth0의 포인터를 대입합니다. */
		return dev_queue_xmit(skb);
	}
/* 이 밑의 소스는 안건드렸습니다. */
	if (queue->input_pkt_queue.qlen <= netdev_max_backlog) {
		if (queue->input_pkt_queue.qlen) {
			if (queue->throttle)
				goto drop;

enqueue:
			dev_hold(skb->dev);
			__skb_queue_tail(&queue->input_pkt_queue,skb);
			local_irq_restore(flags);
#ifndef OFFLINE_SAMPLE
			get_sample_stats(this_cpu);
#endif
			return queue->cng_level;
		}

		if (queue->throttle) {
			queue->throttle = 0;
#ifdef CONFIG_NET_HW_FLOWCONTROL
			if (atomic_dec_and_test(&netdev_dropping))
				netdev_wakeup();
#endif
		}

		netif_rx_schedule(&queue->blog_dev);
		goto enqueue;
	}

	if (queue->throttle == 0) {
		queue->throttle = 1;
		netdev_rx_stat[this_cpu].throttled++;
#ifdef CONFIG_NET_HW_FLOWCONTROL
		atomic_inc(&netdev_dropping);
#endif
	}

drop:
	netdev_rx_stat[this_cpu].dropped++;
	local_irq_restore(flags);

	kfree_skb(skb);
	return NET_RX_DROP;
}

원래 dev.c의 dev_queue_xmit

int dev_queue_xmit(struct sk_buff *skb)
{
	struct net_device *dev = skb->dev;
	struct Qdisc  *q;

	if (skb_shinfo(skb)->frag_list &&
	    !(dev->features&NETIF_F_FRAGLIST) &&
	    skb_linearize(skb, GFP_ATOMIC) != 0) {
		kfree_skb(skb);
		return -ENOMEM;
	}

	/* Fragmented skb is linearized if device does not support SG,
	 * or if at least one of fragments is in highmem and device
	 * does not support DMA from it.
	 */
	if (skb_shinfo(skb)->nr_frags &&
	    (!(dev->features&NETIF_F_SG) || illegal_highdma(dev, skb)) &&
	    skb_linearize(skb, GFP_ATOMIC) != 0) {
		kfree_skb(skb);
		return -ENOMEM;
	}

	/* If packet is not checksummed and device does not support
	 * checksumming for this protocol, complete checksumming here.
	 */
	if (skb->ip_summed == CHECKSUM_HW &&
	    (!(dev->features&(NETIF_F_HW_CSUM|NETIF_F_NO_CSUM)) &&
	     (!(dev->features&NETIF_F_IP_CSUM) ||
	      skb->protocol != htons(ETH_P_IP)))) {
		if ((skb = skb_checksum_help(skb)) == NULL)
			return -ENOMEM;
	}

	/* Grab device queue */
	spin_lock_bh(&dev->queue_lock);
	q = dev->qdisc;
	if (q->enqueue) {
		int ret = q->enqueue(skb, q);

		qdisc_run(dev);

		spin_unlock_bh(&dev->queue_lock);
		return ret == NET_XMIT_BYPASS ? NET_XMIT_SUCCESS : ret;
	}

	/* The device has no queue. Common case for software devices:
	   loopback, all the sorts of tunnels...

	   Really, it is unlikely that xmit_lock protection is necessary here.
	   (f.e. loopback and IP tunnels are clean ignoring statistics counters.)
	   However, it is possible, that they rely on protection
	   made by us here.

	   Check this and shot the lock. It is not prone from deadlocks.
	   Either shot noqueue qdisc, it is even simpler 8)
	 */
	if (dev->flags&IFF_UP) {
		int cpu = smp_processor_id();

		if (dev->xmit_lock_owner != cpu) {
			spin_unlock(&dev->queue_lock);
			spin_lock(&dev->xmit_lock);
			dev->xmit_lock_owner = cpu;

			if (!netif_queue_stopped(dev)) {
				if (netdev_nit)
					dev_queue_xmit_nit(skb,dev);

				if (dev->hard_start_xmit(skb, dev) == 0) {
					dev->xmit_lock_owner = -1;
					spin_unlock_bh(&dev->xmit_lock);
					return 0;
				}
			}
			dev->xmit_lock_owner = -1;
			spin_unlock_bh(&dev->xmit_lock);
			if (net_ratelimit())
				printk(KERN_CRIT "Virtual device %s asks to queue packet!\n", dev->name);
			kfree_skb(skb);
			return -ENETDOWN;
		} else {
			/* Recursion is detected! It is possible, unfortunately */
			if (net_ratelimit())
				printk(KERN_CRIT "Dead loop on virtual device %s, fix it urgently!\n", dev->name);
		}
	}
	spin_unlock_bh(&dev->queue_lock);

	kfree_skb(skb);
	return -ENETDOWN;
}

제가 바꾼 dev_queue_xmit

int dev_queue_xmit(struct sk_buff *skb)
{
	struct net_device *dev = skb->dev;

	/* Grab device queue */
	spin_lock_bh(&dev->queue_lock);

	dev->hard_start_xmit(skb, dev);
	spin_unlock_bh(&dev->xmit_lock);
	return 0;
}

여기까지가 제가한 방법입니다.

제가 이상하게 생각하거나 혹은, 이상하게 구현하는 부분에대해서 조언부탁드립니다.(TEST 구성도의 IP는 오늘 /16이나 /32로 subnet 할것입니다.)

혹시 MAC을 이용한 LoadBalance, L2 Layer 관련자료가 있으시면 도움 부탁드리겠습니다.

참조한 책은 "리눅스 매니아를 위한 커널 프로그래밍", "Linux Programming Bible" 이고, 사이트는 열거도 못하겠네요.(너무 많이 들어가서, 저도 어디를 갔었는지 -_-;;; 찾다보면 전에 본곳이고...)

커널 프로그래밍이 처음이라서 똑같아도 난감한데, 2.4.20부터 소스가 바뀌었다던데... 권수호님의 책과 다른부분이 꽤 있네요 ㅜ.ㅜ

cjy1126의 이미지

계속 커널 패닉이 나네요.

커널 패닉이나면서 나오는 메세지를 읽을줄 몰라서... 조금씩 고쳐서 다시 컴파일하면서 찾아가네요.

5시간동안 커널 컴파일만 30번넘었네요 ㅜ.ㅜ

혹시 netif_rx와 dev_queue_xmit 분석된곳이 없나요?

FAST_ROUTE처럼 그냥 return dev_queue_xmit(skb); 이렇게 한거거든요.

dev_queue_xmit에서 dev->hard_start_xmit을 이용해서 device에 skb를 전달해서 패킷을 전송하는게 아닌가요?

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.