반응형

작성일: 2023년 10월 25일

 

내가 참고했던 문서:  https://semaphoreci.com/blog/prometheus-grafana-kubernetes-helm

 

Helm chart를 사용하면, 키보드로 명령을 몇 줄 입력하면 모든 설치 및 구성이 끝난다.

내가 수행했던 명령을 캡쳐했다. 아래 예제를 따라하면 잘 설치된다.

 

/home/sejong/chart/prometheus# helm install -n almighty prometheus ./

NAME: prometheus
LAST DEPLOYED: Wed Oct 25 18:01:27 2023
NAMESPACE: almighty
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
The Prometheus server can be accessed via port 80 on the following DNS name from within your cluster:
prometheus-server.almighty.svc.cluster.local


Get the Prometheus server URL by running these commands in the same shell:
  export POD_NAME=$(kubectl get pods --namespace almighty -l "app.kubernetes.io/name=prometheus,app.kubernetes.io/instance=prometheus" -o jsonpath="{.items[0].metadata.name}")
  kubectl --namespace almighty port-forward $POD_NAME 9090


The Prometheus alertmanager can be accessed via port 9093 on the following DNS name from within your cluster:
prometheus-alertmanager.almighty.svc.cluster.local


Get the Alertmanager URL by running these commands in the same shell:
  export POD_NAME=$(kubectl get pods --namespace almighty -l "app.kubernetes.io/name=alertmanager,app.kubernetes.io/instance=prometheus" -o jsonpath="{.items[0].metadata.name}")
  kubectl --namespace almighty port-forward $POD_NAME 9093
#################################################################################
######   WARNING: Pod Security Policy has been disabled by default since    #####
######            it deprecated after k8s 1.25+. use                        #####
######            (index .Values "prometheus-node-exporter" "rbac"          #####
###### .          "pspEnabled") with (index .Values                         #####
######            "prometheus-node-exporter" "rbac" "pspAnnotations")       #####
######            in case you still need it.                                #####
#################################################################################


The Prometheus PushGateway can be accessed via port 9091 on the following DNS name from within your cluster:
prometheus-prometheus-pushgateway.almighty.svc.cluster.local


Get the PushGateway URL by running these commands in the same shell:
  export POD_NAME=$(kubectl get pods --namespace almighty -l "app=prometheus-pushgateway,component=pushgateway" -o jsonpath="{.items[0].metadata.name}")
  kubectl --namespace almighty port-forward $POD_NAME 9091

For more information on running Prometheus, visit:
https://prometheus.io/

/home/sejong/WorkSpace/chart/prometheus#


---



/home/sejong/chart/grafana# helm install -n almighty grafana ./

NAME: grafana
LAST DEPLOYED: Wed Oct 25 18:37:27 2023
NAMESPACE: almighty
STATUS: deployed
REVISION: 1
NOTES:
1. Get your 'admin' user password by running:

   kubectl get secret --namespace almighty grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo


2. The Grafana server can be accessed via port 80 on the following DNS name from within your cluster:

   grafana.almighty.svc.cluster.local

   Get the Grafana URL to visit by running these commands in the same shell:
     export POD_NAME=$(kubectl get pods --namespace almighty -l "app.kubernetes.io/name=grafana,app.kubernetes.io/instance=grafana" -o jsonpath="{.items[0].metadata.name}")
     kubectl --namespace almighty port-forward $POD_NAME 3000

3. Login with the password from step 1 and the username: admin

/home/sejong/WorkSpace/chart/grafana#


---


## Grafana admin 계정 암호 찾기

$  kubectl get secret --namespace almighty grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo
gxq5MbMBa2w5qkqpvkaYGU5T8bJDOTag9ayy5kxi

 

 

Helm chart가 잘 만들어져 있어서 큰 노력없이 클러스터 구축이 끝났다.

Helm chart를 만든 분께 감사하다는 말을 전하고 싶다.

반응형

 


 

작성일: 2023년 10월 10일

 

패킷 보내기 (Send a packet)

예제 코드

/**
 * How to build
 *  $  gcc send-raw-packet.c -o send-raw-packet
 *
 * How to run
 *  $ ./send-raw-packet
 *    or
 *  $ ./send-raw-packet  eth0
 */

#include <arpa/inet.h>
#include <linux/if_packet.h>
#include <linux/ip.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/ether.h>
#include <errno.h>


// FIXME: MY_DEST_MACX 값은 각자 테스트 환경이 맞게 수정해서 사용.
#define MY_DEST_MAC0	0x52
#define MY_DEST_MAC1	0x54
#define MY_DEST_MAC2	0x00
#define MY_DEST_MAC3	0xcf
#define MY_DEST_MAC4	0xab
#define MY_DEST_MAC5	0x76

// FIXME: DEFAULT_IF 값은 각자 테스트 환경이 맞게 수정해서 사용.
#define DEFAULT_IF	"enp7s0"

#define BUF_SIZ		1024


int main(int argc, char *argv[])
{
	int                  sockfd;
	int                  tx_len = 0;
	char                 sendbuf[BUF_SIZ];
	char                 ifName[IFNAMSIZ];
	struct ifreq         if_idx;
	struct ifreq         if_mac;
	struct ether_header  *eh = (struct ether_header *) sendbuf;
	struct iphdr         *iph = (struct iphdr *) (sendbuf + sizeof(struct ether_header));
	struct sockaddr_ll   socket_address;

	// Network interface name 지정하기 (예: eth0)
	if (argc > 1)
	{
		strcpy(ifName, argv[1]);
	}
	else
	{
		strcpy(ifName, DEFAULT_IF);
	}

	// RAW socket 사용을 위한 File descriptor 생성하기
	if ((sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW)) == -1)
	{
		printf("socket() error: %d (%s)\n", errno, strerror(errno));
		return 0;
	}

	// Network interface의 index 값 구하기
	memset(&if_idx, 0, sizeof(struct ifreq));
	strncpy(if_idx.ifr_name, ifName, IFNAMSIZ-1);
	if (ioctl(sockfd, SIOCGIFINDEX, &if_idx) < 0)
	{
		printf("ioctl(SIOCGIFINDEX, %s) error: %d (%s)\n", ifName, errno, strerror(errno));
		return 0;
	}

	// Network interface의 MAC address 구하기
	memset(&if_mac, 0, sizeof(struct ifreq));
	strncpy(if_mac.ifr_name, ifName, IFNAMSIZ-1);
	if (ioctl(sockfd, SIOCGIFHWADDR, &if_mac) < 0)
	{
		printf("ioctl(SIOCGIFHWADDR, %s) error: %d (%s)\n", ifName, errno, strerror(errno));
		return 0;
	}

	// Ehternet header 구성하기 (참고: sendbuf pointer가 eh 주소를 pointing)
	memset(sendbuf, 0, BUF_SIZ);
	/*
	 * ioctl() 함수를 이용해서 얻은 'enp7s0' NIC에 대한 MAC Address 값을
	 * ethernet header 구조체의 ether_shost 변수에 복사한다.
	 */
	printf("( %s )  MAC address = ", ifName);
	for (int idx = 0; idx < 6; idx++)
	{
		eh->ether_shost[idx] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[idx];
		printf("%02x", eh->ether_shost[idx]);
		if (idx < 5)
		{
			printf(":");
		}
	}
	printf("\n");

	/*
	 * 일반적으로 NIC port의 MAC address를 ethernet frame의 source address로 사용하지만
	 * Ethernet packet 전송 테스트를 위해서 가짜 Source MAC address를 만들었다.
	 */
	eh->ether_shost[3] = 0x01;
	eh->ether_shost[4] = 0x02;
	eh->ether_shost[5] = 0x03;

	// Ethernet frame - Destination host MAC address
	eh->ether_dhost[0] = MY_DEST_MAC0;
	eh->ether_dhost[1] = MY_DEST_MAC1;
	eh->ether_dhost[2] = MY_DEST_MAC2;
	eh->ether_dhost[3] = MY_DEST_MAC3;
	eh->ether_dhost[4] = MY_DEST_MAC4;
	eh->ether_dhost[5] = MY_DEST_MAC5;

	// Ethertype:  Internet Protocol (0x0800)
	eh->ether_type = htons(ETH_P_IP);
	tx_len += sizeof(struct ether_header);

	// FIXME: IP Header
	//   각자 테스트 환경에 맞게 iph 변수를 수정하여 사용하기
  	iph->ihl = 20 >> 2;  // NOTE: (20 >> 2) * 4 = 20 bytes (IHL은 4 byte 단위로 해석되기 때문)
	iph->version = 4;
	iph->protocol = IPPROTO_IP;
	iph->saddr = inet_addr("10.1.1.10");
	iph->daddr = inet_addr("10.1.1.11");
	iph->tot_len = 46 + 32;

	tx_len += sizeof(struct iphdr);

	/* Payload (Packet data) */
	for (char idx = 0; idx < 32; idx++)
	{
		sendbuf[tx_len++] = idx;
	}

	/* Index of the network device */
	socket_address.sll_ifindex = if_idx.ifr_ifindex;
	/* Address length*/
	socket_address.sll_halen = ETH_ALEN;
	/* Destination MAC */
	socket_address.sll_addr[0] = MY_DEST_MAC0;
	socket_address.sll_addr[1] = MY_DEST_MAC1;
	socket_address.sll_addr[2] = MY_DEST_MAC2;
	socket_address.sll_addr[3] = MY_DEST_MAC3;
	socket_address.sll_addr[4] = MY_DEST_MAC4;
	socket_address.sll_addr[5] = MY_DEST_MAC5;

	/* Send packet */
	if (sendto(sockfd, sendbuf, tx_len, 0, (struct sockaddr*)&socket_address, sizeof(struct sockaddr_ll)) < 0)
	    printf("Send failed\n");

	return 0;
}

 

 

패킷 받기 (Receive a packet)

예제 코드

/**
 * How to build
 *  $  gcc recv-raw-packet.c -o recv-raw-packet
 *
 * How to run
 *  $ ./recv-raw-packet
 *    or
 *  $ ./recv-raw-packet  eth0
 */

#include <unistd.h>
#include <arpa/inet.h>
#include <linux/if_packet.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/ether.h>
#include <errno.h>

#define ETHER_TYPE	0x0800

#define DEFAULT_IF	"enp7s0"
#define BUF_SIZ		1024

int main(int argc, char *argv[])
{
	char sender[INET6_ADDRSTRLEN];
	int sockfd, ret;
	int sockopt;
	ssize_t pktbytes;
	struct ifreq ifopts;	// To set promiscuous mode
	struct ifreq if_ip;	    // To get IP address of this host NIC
	struct sockaddr_storage peer_addr;
	uint8_t buf[BUF_SIZ];
	char ifName[IFNAMSIZ];

	// Network interface name 지정하기 (예: eth0)
	if (argc > 1)
	{
		strcpy(ifName, argv[1]);
	}
	else
	{
		strcpy(ifName, DEFAULT_IF);
	}

	// Ethernet + IP + UDP header
	struct ether_header *eh = (struct ether_header *) buf;
	struct iphdr *iph = (struct iphdr *) (buf + sizeof(struct ether_header));
	struct udphdr *udph = (struct udphdr *) (buf + sizeof(struct iphdr) + sizeof(struct ether_header));

	if ((sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETHER_TYPE))) == -1)
	{
		printf("socket(PF_PACKET, SOCK_RAW, ETHER_TYPE) error: %d (%s)\n", errno, strerror(errno));
		return -1;
	}

	// Set interface to promiscuous mode
	strncpy(ifopts.ifr_name, ifName, IFNAMSIZ-1);
	ioctl(sockfd, SIOCGIFFLAGS, &ifopts);
	ifopts.ifr_flags |= IFF_PROMISC;
	ioctl(sockfd, SIOCSIFFLAGS, &ifopts);
	if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof sockopt) == -1) {
		printf("setsockopt(SO_REUSEADDR) error: %d (%s)\n", errno, strerror(errno));
		close(sockfd);
		exit(0);
	}

	// Bind to device
	if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, ifName, IFNAMSIZ-1) == -1)	{
		printf("setsockopt(SO_BINDTODEVICE, %s) error: %d (%s)\n", ifName, errno, strerror(errno));
		close(sockfd);
		exit(0);
	}

repeat:
	printf("\nWaiting to recvfrom...\n");
	pktbytes = recvfrom(sockfd, buf, BUF_SIZ, 0, NULL, NULL);
	printf("  Got packet %lu bytes\n", pktbytes);

	printf("Destination  MAC address = ");
	for (int idx = 0; idx < 6; idx++)
	{
		printf("%02x", eh->ether_dhost[idx]);
		if (idx < 5)
		{
			printf(":");
		}
	}
	printf("\n");

	// Get source IP
	((struct sockaddr_in *)&peer_addr)->sin_addr.s_addr = iph->saddr;
	inet_ntop(AF_INET, &((struct sockaddr_in*)&peer_addr)->sin_addr, sender, sizeof sender);

	// Look up my device IP addr
	memset(&if_ip, 0, sizeof(struct ifreq));
	strncpy(if_ip.ifr_name, ifName, IFNAMSIZ-1);
	if (ioctl(sockfd, SIOCGIFADDR, &if_ip) >= 0) {
		printf("Source IP: %s\n My IP: %s\n", sender,
				inet_ntoa(((struct sockaddr_in *)&if_ip.ifr_addr)->sin_addr));
		// Ignore if I sent it
		if (strcmp(sender, inet_ntoa(((struct sockaddr_in *)&if_ip.ifr_addr)->sin_addr)) == 0)	{
			printf("but I sent it :(\n");
			ret = -1;
			goto done;
		}
	}

	/* UDP payload length */
	ret = ntohs(udph->len) - sizeof(struct udphdr);

	/* Print packet */
	printf("\tData:");
	for (int idx = 0; idx < pktbytes; idx++)
	{
		printf("%02x ", buf[idx]);
	}
	printf("\n");

done:
	goto repeat;

	close(sockfd);
	return ret;
}

 

 

 

 

 


 

반응형

작성일: 2023년 9월 25일

 

파이썬으로 작성된 패킷 조작 라이브러리.

https://scapy.net/

 

 

 

 

Scopy - README.MD

https://github.com/secdev/scapy

 

Tutorial

https://scapy.readthedocs.io/en/latest/usage.html#interactive-tutorial

 

Scopy in 15 minutes

https://github.com/secdev/scapy/blob/master/doc/notebooks/Scapy%20in%2015%20minutes.ipynb

 

HTTP/2 Tutorial

https://github.com/secdev/scapy/blob/master/doc/notebooks/HTTP_2_Tuto.ipynb

 

Demo

https://scapy.readthedocs.io/en/latest/introduction.html#quick-demo

 

 

 

 

 

 


 

반응형

 


작성일: 2023년 9월 23일

 

 

 

Private VLAN 개념 설명 및 Switch 설정 실습 (YouTube 영상)

https://www.youtube.com/watch?v=ZS80DM_-f5Y 

(이 영상에서 개념과 일반적인 Use Case에 대한 실습을 모두 다루기 때문에 이 영상을 보면서 이해가 되었다면, 아래 스터디 자료는 안 봐도 된다)

 

 

Private VLAN(PVLAN) on CISCO iOS Switch (예제 따라하기)

https://networklessons.com/switching/private-vlan-pvlan-cisco-catalyst-switch

(만약 CISCO Catalyst 제품을 사용하는 경우라면, 이 문서의 예제를 따라할 것)

 

Private VLAN 설정 실습 (가장 단순한 구조에 대한 실습)

https://packetlife.net/blog/2010/aug/30/basic-private-vlan-configuration/

 

 

 

 

Private VLAN 설정 실습 (전형적인 구조에 대한 실습)

https://www.internetworks.in/2023/07/what-is-private-vlan-how-to-configure.html

 

 

 

Configure Isolated Private VLANs on Catalyst Switches

https://www.cisco.com/c/en/us/support/docs/lan-switching/private-vlans-pvlans-promiscuous-isolated-community/40781-194.html  (English Document)

 

https://www.cisco.com/c/ko_kr/support/docs/lan-switching/private-vlans-pvlans-promiscuous-isolated-community/40781-194.html  (한글 문서)

 

 

https://ipwithease.com/private-vlan-configuration-scenrio/

 

 

 

Secondary VLAN Trunk Ports and Promiscuous Access Ports on PVLANs

https://www.juniper.net/documentation/en_US/release-independent/nce/topics/concept/private-vlans-isolated-trunks-qfx-series.html

 

 

VM + OVS(Open vSwitch) + L2 Switch 조합으로 PVLAN 실습

https://cwiki.apache.org/confluence/display/CLOUDSTACK/PVLAN+for+isolation+within+a+VLAN

https://docs.oracle.com/cd/E53394_01/html/E54788/gotxb.html

 

 

 

 

 


 

반응형

작성일: 2023년 9월 20일

 

 

 

Client 장비에 network port가 여러개 있는 경우, 특정 network port를 지정하여 IP 패킷을 전송하고 싶을 때가 있다.

이럴 때, source IP address를 binding하면 특정 network port를 통해 IP 패킷이 전송된다.

참고:
  일반적으로 Target IP address로 가기 위한 routing path 및 network port는 
  OS에 있는 Routing table을 통해서 자동으로 결정된다.
  그러나 Target IP address로 가기 위한 routing path가 1개가 아닌 2개 이상인 경우에는
  어느 network port를 통해서 IP 패킷이 나갈지 예측하기 어렵다.  
package main

import (
    "fmt"
    "io/ioutil"
    "net"
    "net/http"
    "time"
)


func main() {
##
## NOTE:  14.33.80.179를 Source IP address로 지정한다. (즉, Source IP address binding)
##
    localAddr, err := net.ResolveIPAddr("ip", "14.33.80.179")
    if err != nil {
        panic(err)
    }

    localTCPAddr := net.TCPAddr{
        IP: localAddr.IP,
    }

    d := net.Dialer{
        LocalAddr: &localTCPAddr,
        Timeout:   30 * time.Second,
        KeepAlive: 30 * time.Second,
    }

    tr := &http.Transport{
        Proxy:               http.ProxyFromEnvironment,
        Dial:                d.Dial,
        TLSHandshakeTimeout: 10 * time.Second,
    }

    webclient := &http.Client{Transport: tr}

    // Use NewRequest so we can change the UserAgent string in the header
    req, err := http.NewRequest("GET", "https://www.naver.com", nil)
    if err != nil {
        panic(err)
    }

    res, err := webclient.Do(req)
    if err != nil {
        panic(err)
    }

    fmt.Println("DEBUG", res)
    defer res.Body.Close()

    content, err := ioutil.ReadAll(res.Body)
    if err != nil {
        panic(err)
    }
    fmt.Printf("%s", string(content))
}

 

 

 

 


 

반응형

 

작성일: 2023년 9월 19일

 

NETCONF Python 예제 코드 

https://github.com/ncclient/ncclient/tree/master/examples

https://github.com/ncclient/ncclient/blob/master/examples/base/nc08.py  (Interface 설정 및 Activate)

https://github.com/aristanetworks/openmgmt/tree/main/src/ncclient  (Aristanetworks 예제)

https://developer.cisco.com/codeexchange/github/repo/ncclient/ncclient/  (CISCO 개발자 페이지)

 

NETCONF Python 예제 코드

https://blog.wimwauters.com/networkprogrammability/2020-03-30-netconf_python_part1/

https://blog.wimwauters.com/networkprogrammability/2020-03-31_netconf_python_part2/

 

 

NETCONF Golang 예제 코드

https://github.com/Juniper/go-netconf/tree/master/examples

 

 

NETCONF C++ 예제 코드

https://github.com/CESNET/libnetconf2/tree/master/examples

 

 

RESTCONF Postman 예제 코드

https://blog.wimwauters.com/networkprogrammability/2020-04-02_restconf_introduction_part1/

https://blog.wimwauters.com/networkprogrammability/2020-04-03_restconf_introduction_part2/

 

 

RESTCONF Python 예제  코드

https://blog.wimwauters.com/networkprogrammability/2020-04-04_restconf_python/

 

 

 

 

 

 

 


 

반응형

 


작성일: 2025년 3월 14일

 

 

수백 페이지 분량의 PDF 문서를 읽다보면, 특정 페이지 몇 장만 골라서 저장하고 싶을 때가 있다.

PDF 편집기 같은 유료 프로그램이 있다면, 원하는대로 편집해서 저장할 수 있지만

돈을 지출하지 않고 PDF 문서에서 몇 페이지만 추출하여 저장하고 싶다면,

인쇄 버튼을 누르고 추출하고 싶은 페이지 번호만 입력하고, PDF 문서로 출력하기를 선택하면 된다.

 

내 느낌인지는 모르겠지만, 이렇게 PDF 문서를 "PDF 문서로 저장"하면 약간 품질이 떨어지는 것 같다. ^^

 

 

또 다른 방법: Python script로 특정 페이지만 골라서 새 PDF 파일에 저장하기

아래의 python script를 실행하면 된다.

import PyPDF2

with open("origin.pdf", "rb") as origin_pdf_file:
    pdf_reader = PyPDF2.PdfReader(origin_pdf_file)
    pdf_writer = PyPDF2.PdfWriter()
    ## 아래 코드 중에 '1, 3, 5' 부분을 본인이 추출하기를 원하는 페이지 번호로 지정할 것!
    for page_num in [1, 3, 5]:  # 추출할 페이지 번호 (0부터 시작)
        page = pdf_reader.pages[page_num]
        pdf_writer.add_page(page)

    with open("new.pdf", "wb") as new_pdf:
        pdf_writer.write(new_pdf)

 

 

아래와 같이 명령을 실행한다.

$ pip3 install PyPDF2

$ python3 pdf-extract.py

 

위 명령을 실행하고 나면, 'new.pdf' 파일이 생성될 것이고

이   'new.pdf' 파일을 PDF Reader로 열어서 확인해보면 된다.

반응형

 


 

작성일: 2023년 9월 15일

 

South Carolina 대학의 'Open Virtual Switch Lab Series' 문서를 바탕으로 내가 실습한 내용을 이곳에 정리함.
( Network namespace 개념부터 차곡차곡 쌓아 올리면서 Open vSwitch Use Case를 설명하기 때문에 공부하는 사람에게 많은 도움이 된다 )

참고 문서:
    [ 링크 클릭 ]  OVS 실습 문서 (Open Virtual Switch Lab Series, 2021년 09월 30일)
    [ 링크 클릭 ]  OVS 개념 및 구성 소개 [ Link ]

 

 

 

 


 

 

Linux namespaces 간 Networking 위해 Open vSwitch 구성

원본:

OVS - Linux namespace and Open vSwitch.pdf
2.13MB

 

 

 

[개념 그림] Open vSwitch와 각 Namespace 간 Networking

 

아래 그림을 기반으로 Open vSwitch와 Namespace를 구성하여 테스트한다.

위 그림에 묘사된 것과 같이 Network를 구성하기 위해 아래 명령을 작성했다. (따라해보면 위 그림과 똑같은 Network 만들어진다)

 

## root namespace에 존재하는 모든 network interface를 조회
$ ip link

## 네임스페이스 my-ns-a, my-ns-b 를 생성
$ ip netns add my-ns-a
$ ip netns add my-ns-b

## Linux kernel에 존재하는 모든 namespace 조회
$ ip netns
my-ns-b
my-ns-a

## 'my-ns-a' 네임스페이스에 존재하는 network interface 조회
$ ip netns exec my-ns-a ip link
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

## 가상 스위치 'sw1'를 생성
$ ovs-vsctl add-br sw1

## root namespace에 존재하는 network interface를 조회
$ ip link
... 중간 생략 ...
47: ovs-system: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 86:3d:02:69:23:4f brd ff:ff:ff:ff:ff:ff
48: sw1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 16:68:07:5d:c0:40 brd ff:ff:ff:ff:ff:ff

## Open vSwitch에 namespace를 연결하기
##  1) veth peer 생성하기
$ ip link add my-ns-a-eth0 type veth peer name sw1-eth1

$ ip link add my-ns-b-eth0 type veth peer name sw1-eth2

$ ip link
... 중간 생략 ...
47: ovs-system: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 86:3d:02:69:23:4f brd ff:ff:ff:ff:ff:ff
48: sw1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 16:68:07:5d:c0:40 brd ff:ff:ff:ff:ff:ff
51: sw1-eth1@my-ns-a-eth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether be:01:52:6f:4b:58 brd ff:ff:ff:ff:ff:ff
52: my-ns-a-eth0@sw1-eth1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 96:24:a4:bf:78:f3 brd ff:ff:ff:ff:ff:ff
53: sw1-eth2@my-ns-b-eth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 46:d4:ad:57:18:20 brd ff:ff:ff:ff:ff:ff
54: my-ns-b-eth0@sw1-eth2: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 2a:78:4d:57:db:37 brd ff:ff:ff:ff:ff:ff

##  2) veth peer를 각각의 namepace에 연결하기 (Attaching to namespaces)
$ ip link set my-ns-a-eth0 netns my-ns-a

$ ip link set my-ns-b-eth0 netns my-ns-b

$ ip netns exec my-ns-a ip link
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
52: my-ns-a-eth0@if51: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 96:24:a4:bf:78:f3 brd ff:ff:ff:ff:ff:ff link-netnsid 0

$ ip netns exec my-ns-b ip link
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
54: my-ns-b-eth0@if53: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 2a:78:4d:57:db:37 brd ff:ff:ff:ff:ff:ff link-netnsid 0


##  3) 가상 스위치 sw1에 veth peer를 연결하기 (Attaching veth peer to switch sw1) 
$ ovs-vsctl add-port sw1 sw1-eth1

$ ovs-vsctl show
...
    Bridge sw1
        Port sw1
            Interface sw1
                type: internal
        Port sw1-eth1
            Interface sw1-eth1
...

$ ovs-vsctl add-port sw1 sw1-eth2

$ ovs-vsctl show
...
    Bridge sw1
        Port sw1
            Interface sw1
                type: internal
        Port sw1-eth2
            Interface sw1-eth2
        Port sw1-eth1
            Interface sw1-eth1
...


## 가상 스위치의 network port를 activate 하기. (Turning up the network port)
$ ip link set sw1-eth1 up

$ ip link set sw1-eth2 up

$ ip link 
...
51: sw1-eth1@if52: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master ovs-system state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether be:01:52:6f:4b:58 brd ff:ff:ff:ff:ff:ff link-netns my-ns-a
53: sw1-eth2@if54: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master ovs-system state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 46:d4:ad:57:18:20 brd ff:ff:ff:ff:ff:ff link-netns my-ns-b
...

## 각각의 namespace에 IP address를 할당하기
$ ip netns exec my-ns-a ip link set dev my-ns-a-eth0 up

$ ip netns exec my-ns-b ip link set dev my-ns-b-eth0 up

$ ip netns exec my-ns-a ip address add 192.168.1.10/24 dev my-ns-a-eth0

$ ip netns exec my-ns-b ip address add 192.168.1.20/24 dev my-ns-b-eth0

## 설정 정보 확인하기
$ ip netns exec my-ns-a ip addr
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
52: my-ns-a-eth0@if51: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 96:24:a4:bf:78:f3 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 192.168.1.10/24 scope global my-ns-a-eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::9424:a4ff:febf:78f3/64 scope link
       valid_lft forever preferred_lft forever

$ ip netns exec my-ns-b ip addr
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
54: my-ns-b-eth0@if53: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 2a:78:4d:57:db:37 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 192.168.1.20/24 scope global my-ns-b-eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::2878:4dff:fe57:db37/64 scope link
       valid_lft forever preferred_lft forever

## namespace 'my-ns-a'의 routing table 확인하기
$ ip netns exec my-ns-a ip route
192.168.1.0/24 dev my-ns-a-eth0 proto kernel scope link src 192.168.1.10

## namespace 'my-ns-b'의 routing table 확인하기
$ ip netns exec my-ns-b ip route
192.168.1.0/24 dev my-ns-b-eth0 proto kernel scope link src 192.168.1.20

## namespace 'my-ns-a'에서 bash shell 시작하기
$ ip netns exec my-ns-a bash

$ ifconfig
my-ns-a-eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.1.10  netmask 255.255.255.0  broadcast 0.0.0.0
        inet6 fe80::9424:a4ff:febf:78f3  prefixlen 64  scopeid 0x20<link>
        ether 96:24:a4:bf:78:f3  txqueuelen 1000  (Ethernet)
        RX packets 86  bytes 21517 (21.5 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 13  bytes 1006 (1.0 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

$ ping 192.168.1.20 -c 2
PING 192.168.1.20 (192.168.1.20) 56(84) bytes of data.
64 bytes from 192.168.1.20: icmp_seq=1 ttl=64 time=0.088 ms
64 bytes from 192.168.1.20: icmp_seq=2 ttl=64 time=0.079 ms

--- 192.168.1.20 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1007ms
rtt min/avg/max/mdev = 0.079/0.083/0.088/0.004 ms

$ traceroute 192.168.1.20
traceroute to 192.168.1.20 (192.168.1.20), 64 hops max
  1   192.168.1.20  0.452ms  0.003ms  0.002ms

 

 

 


 

+ Recent posts