R&D/VRouter

KVM 과 Dynamips 간 통신

sunshout 2009. 4. 17. 16:13
개요: KVM에서 지원하는 네트워크 바인딩 옵션과 Dynamips에서 지원하는 바인딩 옵션이 달라서 두개를 연결하기 위해서 KVM의 소스코드를 수정하였다. 이는 기존의 QEMU 와 Dynamips 간 코드를 바탕으로 KVM 소스코드를 업데이트 형식을 사용하였다.

1. 여기서 중요한 것은 kvm 소스코드를 통해서 커널이 KVM 을 지원하도록 새로 컴파일을 해야한다.
2. 다음으로 새로 컴파일된 kvm 소스코드를 바탕으로 kvm-userspace 프로그램을 컴파일하고 설치 하여야 한다.


옵션은 Dynamips와 통일성을 같기 위해

kvm -net socket 옵션 (Language : text)
-net socket,udp=[sport]:[daddr]:[dport]

sport: Source port
daddr: Destination Address
dport: Destination port

(예제)
-net,nic,vlan=1,macaddr=00:00:00:00:00:01,model=i82559er -net socket,vlan=1,udp=10000:127.0.0.1:10001

실행 예제(Xeon 서버, 64 bit)

(라우터 1)
# /usr/local/bin/qemu-system-x86_64 -no-acpi -m 256 -nographic olive-base.img -k en-us -net nic,vlan=2,model=i82559er -net socket,vlan=2,udp=10000:127.0.0.1:10001
(라우터 2)
#dynamips c7200.bin -p 0:C7200-IO-FE -s 0:0:udp:10001:127.0.0.1:10000

사용자 삽입 이미지

위에 그림은 시스코 라우터의 FastEthernet 0/0 에서 10.1.1.3/24 IP를 설정한 것이고
아래 그림은 주니퍼 라우터에 fxp0.0 에 10.1.1.2/24 IP를 설정 한 화면이다.

사용자 삽입 이미지

위와 같은 설정이 되고 나면 두 라우터 간 Ping 을 때려 본다.

사용자 삽입 이미지

주니퍼 라우터에서 시스코 라우터를 Ping을 하니까 간다.

다음은 실제 서버에 UDP 소켓이 정말로 존재하는지를 보자.

사용자 삽입 이미지
위 그림을 보면 UDP 소켓 중에 10000번과 10001 번 소켓이 생성되어 있음을 알 수 있다.

dynamips 는 UDP인데 ESTABLISHED 상태로 있고 주니퍼는 Listen 상태로만 있다.(?)
이건 고민 해봐야 할듯... (혹시 시스코가 생성한 소켓으로만 통신하나?)



이렇게 하고 두대의 라우터간 IP를 설정하니 통신이 된다. 혹시 안되면 Mac address가 중복이 아닌지 체크.

코드 수정 부분

kvm-userpace/qemu/net.c 수정파일 (Language : c)
--- kvm-userspace/qemu/net.c    2009-04-17 16:14:38.000000000 +0900
+++ kvm.org/kvm-userspace/qemu/net.c    2009-04-17 14:30:51.000000000 +0900
@@ -1708,7 +1708,87 @@
     return 0;

}
+static int net_socket_udp_send(void *opaque)
+{
+  NetSocketState *s = opaque;
+  uint8_t buf[4096];
int size;
+  size = recvfrom(s->fd, buf, sizeof(buf), 0, NULL, NULL);
+
if (size > 0)
+   qemu_send_packet(s->vc, buf, size);
+}
+
+static int net_socket_udp_receive(void *opaque, const uint8_t *buf, int size)
+{
+  NetSocketState *s = opaque;
int res;
+  res = sendto(s->fd, buf, size, 0, (struct sockaddr *)&s->dgram_dst,
+            sizeof(s->dgram_dst));
+}

+
+/* UDP socket init */
+static int net_socket_udp_init(VLANState *vlan,
+         const char *model,
+         const char *name,
+         const char *host_str)
+{
+  NetSocketState *s;
int fd;
struct sockaddr_in receiver;
int ret;

int a,b,c,d; /* IP addr: a.b.c.d */
int sport, dport;
char daddr[20];

+  s = qemu_mallocz(sizeof(NetSocketState));
if (!s)
+    return -1;
+  s->fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (s->fd < 0) {
+    perror("socket");
+    return -1;
}
+
/* config parse */
printf("%s\n",host_str);
+  sscanf(host_str,"%d:%d.%d.%d.%d:%d",&sport,&a,&b,&c,&d,&dport);
+  sprintf(daddr,"%d.%d.%d.%d",a,b,c,d);
+
if ( (a,b,c,d) < 0 || (a,b,c,d) > 255) {
+   fprintf(stderr,"Illegal IP address : udp=[sport]:[IP address]:[dport]\n");
+   return -1;
}                       
printf("sport = %d, daddr = %s, dport = %d\n",sport, daddr, dport);

+
+  receiver.sin_family = AF_INET;
+  receiver.sin_addr.s_addr = INADDR_ANY;
+  receiver.sin_port = htons(sport);

+  ret = bind(s->fd, (struct sockaddr *)&receiver, sizeof(receiver));
if (ret < 0) {
+   perror("bind");
+   return -1;
}
+
+  memset((char*)&s->dgram_dst, sizeof(s->dgram_dst), 0);
+  s->dgram_dst.sin_family = AF_INET;
+  s->dgram_dst.sin_port = htons(dport);
+  inet_aton(daddr, &s->dgram_dst.sin_addr);
+
+  s->vc = qemu_new_vlan_client(vlan, model, name, net_socket_udp_receive, NULL, s);
+  qemu_set_fd_handler(s->fd, net_socket_udp_send, NULL, s);
+
+  snprintf(s->vc->info_str, sizeof(s->vc->info_str), "udp: %i->%s:%i",
+         sport,daddr,dport);
+
return 0;
+}

+
/* find or alloc a new VLAN */
VLANState *qemu_find_vlan(int id)
{
@@ -1920,6 +2000,8 @@
             ret = net_socket_connect_init(vlan, device, name, buf);
         } else if (get_param_value(buf, sizeof(buf), "mcast", p) > 0) {
             ret = net_socket_mcast_init(vlan, device, name, buf);
+   } else if (get_param_value(buf, sizeof(buf), "udp", p) > 0) {
+     ret = net_socket_udp_init(vlan, device, name, buf);
         } else {
             fprintf(stderr, "Unknown socket options: %s\n", p);
             return -1;