반응형

 

작성일: 2024년 2월 21일

 

PPTP, L2TP 같은 터널링을 사용할 수 없는 상황에서

방화벽 건너편의 네트워크에 접속할 일이 발생하면, SSH Port Forwarding을 임시방편으로 사용하는 것도 좋다.

물론 전제 조건이 있다.

  - SSH 접속할 수 있도록 방화벽 허용 규칙
     또는
  - DNAT Rule
     또는
  - 공유기의 Port Forward Rule이 미리 설정되어 있어야 한다.

 

즉, 원격 Network에 SSH 접속 만큼은 가능한 환경이라는 가정하에 아래 설명을 봐야 한다.

간단하게 한번 훑어보고 실습 환경으로 가보자.

 

SSH Tunneling에는 3가지가 있다.

  - Local Port Forwarding (Local Tunneling)

  - Remote Port Forwarding

  - Dynamic Port Forwarding

 

각 Tunneling 방식에 대해서는 아래 구체적으로 설명하기로 한다.

 

우선 접속할 대상 Network의 SSH 서버의 설정을 수정해야 한다.

SSH Server Config 설정

$ sudo -s

$ vim /etc/ssh/sshd_config

... 중간 생략 ...
AllowTcpForwarding yes     # <-- yes로 변경
GatewayPorts yes           # <-- yes로 변경
... 중간 생략 ...

$ systemctl restart sshd

 

 

준비 작업 끝 !

예시를 들어서, Local Tunneling에 관해서 설명해보면 이렇다.

 

SSH Local Port Forwarding (Local Tunneling)

아래 그림과 같이 집에 있는 내 맥북 PC에서 회사에 있는 VNC 서버에 접근해보겠다.

 

SSH 터널링 (Local Port Forwarding 방식)

 

위 네트워크 구성도를 참고하여 내 PC(맥북)에서 아래의 명령을 수행한다.

(위 구성도와 아래 명령에 있는 IP Address 값을 매핑해서 보면, 아래 명령의 의미를 이해할 수 있다)

$  ssh  -L 5900:10.1.1.3:5900  root@10.1.1.2

 

그리고 내 PC(맥북)에서 RealVNC Viewer 또는 TigerVNC Viewer에 새 연결 정보를 설정해야 하는데,

주소를 localhost (또는 127.0.0.1)으로 입력해야 한다. (아래 화면을 참고)

 

 

위와 같이 VNC Server의 주소를 설정하고, 접속 버튼을 누르면 

VNC 접속 요청 트래픽은 아래 순서로 흘러간다.

 

  1)  내 맥북 PC VNC Client

  2)  localhost의 ssh client (192.168.1.5:5900)

  3)  사무실의 ssh server (10.1.1.2)

  4)  VNC Server (10.1.1.3:5900)

 

원하는 VNC 접속 성공 !!

 

 


 

 

SSH Remote Port Forwarding

이번에는 완전 반대의 경우를 생각해보자.

사무실 쪽에서 SSH 서버 접속을 허용하지 않아서 Local Tunneling이 안 되는 경우라면, 

사무실에 있는 누군가(나의 친한 동료)가 내 집에 있는 내 맥북에 SSH Tunneling을 요청해주어야 한다.

물론 내 맥북이 Public network에 노출되어야 한다.

이런 방식을 Remote Tunneling이라고 한다. 

 

SSH 터널링 (Remote Port Forwarding 방식)

 

사무실에서 나의 동료가 회사 Linux 서버에서 아래와 명령을 실행해준다.

$  ssh  -R  34343:10.1.1.2:5900  sejong@192.168.1.5 -p 20022

 

그러면 위 명령 때문에 내 맥북 PC에는 TCP Listening port 34343가 생성된다.

## 집에 있는 내 맥북 PC에서 명령을 실행한 결과

$  netstat -anp | grep LISTEN
... 중간 생략 ...
tcp    0    0 0.0.0.0:34343       0.0.0.0:*         LISTEN      -
... 중간 생략 ...

 

이제 내 맥북에서 VNC Viewer를 이용해서 아래 화면과 같이 설정하고 회사 Network로 접속해보자.

VNC Server 주소는 localhost 또는 127.0.0.1 으로 설정하면 된다.

 

위와 같이 VNC Server의 주소를 설정하고, 접속 버튼을 누르면

VNC 접속 요청 트래픽은 아래 순서로 흘러간다.

 

  1)  내 맥북 PC VNC Client

  2)  localhost의 ssh client (192.168.1.5:5900)

  3)  사무실의 ssh server (10.1.1.2)

  4)  VNC Server (10.1.1.3:5900)

 

원하는 VNC 접속 성공 !!

 

 


 

반응형

 


 

작성일: 2023년 12월 12일

 

 

Juniper Switch를 원격에서 제어할 수 있는 API를 찾아보니 아래와 같은 것들이 있었다.

- Python PKG (Juniper가 공식적으로 개발 및 배포하고 Example이 다양하게 많아서 사용하기 좋았다.)

- Ansible Module (Juniper가 공시적으로 배포하지만, 실전에서 사용하기에는 Example이 부족했다)

- SNMP (Juniper가 SNMP 서비스를 제공하지만, 제약이 많다)

- NET-CONF (업계 표준이니까 제공해주지만, 쌩코딩해서 사용하기에는 시간적으로 부담이 된다)

 

구현 시간을 아끼고, 예제도 많은 Python PKG를 선택해서 개발하기로 마음을 굳혔다.

그리고 나중에 시간이 생기면 Ansible playbook을 작성해서 조금 더 추상화해볼 계획이다.


 

 

참고:

아래의 예제는 [ Junos PyEX 개발자 가이드 ] 문서 중에서 업무에 필요한 부분만 추려서 실습하고 작성한 것이다.

시간이 넉넉한 사람은 아래 개발자 가이드를 다 읽어보고 Junos PyEX를 사용하고,

시간이 넉넉하지 않은 사람은 아래 요약된 실습 내용만 따라하면 된다.

https://www.juniper.net/documentation/kr/ko/software/junos-pyez/junos-pyez-developer/index.html

 

 

 

준비 작업 / Juniper Switch 장비 설정 작업

Client 장비의 Junos PyEX가 접근할 수 있도록 Juniper Switch에서는 [ SSH 서비스, NETCONF, Junos XML API ]를 활성화(Enable)해야 한다.

설명은 거창하지만, 아래의 예제 명령을 한줄 입력해주면 끝이다.

 

> configure         // 설정 모드로 진입하기 위한 명령을 입력

Entering configuration mode
Users currently editing the configuration:
... 중간 생략 ...

myuser# set netconf ssh   // NETCONF-over-SSH 서비스를 활성화하는 명령을 입력

myuser# commit            // 위에서 변경한 내용을 시스템에 반영하기 위한 명령을 입력

 

 

Junos PyEX 패키지(jnpr.junos)의 각 모듈에 대한 설명

Module Description
device Junos 디바이스를 표현하는 클래스를 정의하고, Device spec 및 상태를 조회할 수 있는 기능을 지원한다.
command CLI, vty 명령을 지원한다. 
표 형태의 View 출력 Form을 지원한다.
exception Exception handling
factory 사용자가 지정한 형태의 Table, View 출력이 가능하도록 한다.
  예: loadyaml() 함수
facts Device에 대한 정보를 추출하기 위한 Object
op RPC 응답의 XML 출력을 Filtering
resources ... 설명 생략 ...
transport ... 설명 생략 ...
utils Configuration utility, Shell utility, Software installation, Security utility, etc ...

 

준비 작업 / Client 장비에 Python 패키지 설치 작업

내가 사용한 OS: Ubuntu 22.04

 

Juniper Switch를 관리할 Client 장비(Ubuntu 22.04)에서 아래 명령을 수행하여 Junos PyEX 패키지를 설치한다.

$ sudo pip3 install junos-eznc

 

작업 끝. (너무 간단하다 ^^)

 

[ 예제 1 ]  네트워크 포트 Up & Down 예제 프로그램

아래 예제는 Juniper Switch(10.1.1.2) 장치에 접속해서 Giga Ethernet을 Down & Up 상태로 변경하고

Port 상태를 조회하는 기능을 수행한다.

 

아래와 같이 Python 예제 코드를 작성한다.

from jnpr.junos import Device
from jnpr.junos.utils.config import Config
from jnpr.junos.op.ethport import EthPortTable
import time


with Device(host='10.1.1.2', user='myadmin', password='mypasswd') as dev:
    ## 포트 상태를 Up/Down 상태로 변경하기
    with Config(dev, mode='ephemeral') as cu:
        cu.load('set interfaces ge-0/0/8 disable', format='set')      # Port Down 상태로 변경
        #cu.load('delete interfaces ge-0/0/8 disable', format='set')  # Port Up 상태로 변경
        cu.commit()

    time.sleep(5)   ## Config를 commit하고도 2~3초 정도 지나야 Port state 값이 반영되므로 5초 정도 sleep 한다.
    
    ## 전체 포트 상태 정보를 가져오기
    eths = EthPortTable(dev)
    eths.get()
    for item in eths:
        print ("{}: {}".format(item.name, item.oper))

    # 1개 포트 정보만 가져오기
    eths.get("ge-0/0/8")
    # 포트 정보의 모든 컬럼의 내용을 보고 싶다면...
    print(eths.values())
    for item in eths:
        print ("name: {}  operating state: {}  admin state: {}  mac: {}  mtu: {}".format(item.name, item.oper, item.admin, item.macaddr, item.mtu))

 

 

위에서 작성한 Python 예제 코드를 아래와 같이 실행한다.

$  python3 my_example_1.py

ge-0/0/0: down
ge-0/0/1: down
ge-0/0/2: down
ge-0/0/3: down
ge-0/0/4: down
ge-0/0/5: down
ge-0/0/6: down
ge-0/0/7: down
ge-0/0/8: up         <-- 내가 변경한 포트의 상태
ge-0/0/9: down
ge-0/0/10: down
ge-0/0/11: down
ge-0/0/12: down
ge-0/0/13: down
ge-0/0/14: down
ge-0/0/15: down
ge-0/0/16: down
ge-0/0/17: down
ge-0/0/18: down
ge-0/0/19: down
ge-0/0/20: down
ge-0/0/21: down
ge-0/0/22: down
ge-0/0/23: up

[[('oper', 'up'), ('admin', 'up'), ('description', None), ('mtu', 1514), ('link_mode', 'Full-duplex'), ('macaddr', '60:c7:8d:a3:78:74'), ('rx_bytes', '2124'), ('rx_packets', '24'), ('tx_bytes', '586755785'), ('tx_packets', '7013363'), ('running', True), ('present', True)]]

name: ge-0/0/8  operating state: up  admin state: up  mac: 60:c3:8a:a3:78:74  mtu: 1514

$

 

 

 


 

[ 예제 2 ]  Juniper Switch의 VLAN 별, 포트 별 Learning된 MAC Address List를 조회

아래 예제는 Juniper Switch(10.1.1.2) 장치에 접속해서 Juniper Switch가 MAC Learning한 결과물을 조회한다.

Learning된 MAC Address를 각각의 VLAN 별, 포트별로 표현된다.

 

조회 결과물이 XML이기 때문에 XML 데이터 포맷을 처리하기 위한 Python 패키지가 필요한다.

$ pip install xmltodict

 

 

아래와 같이 Python 예제 코드를 작성한다.

import pprint
import xmltodict
from xml.etree import ElementTree
from jnpr.junos import Device
from jnpr.junos.op.ethernetswitchingtable import EthernetSwitchingTable


with Device(host='10.1.1.2', user='myadmin', password='mypasswd') as dev:
    eth_table = dev.rpc.get_ethernet_switching_table_information()
    dict_eth_table = xmltodict.parse(ElementTree.tostring(eth_table, method="xml"))
    pprint.pprint(dict_eth_table, indent=2)

 

 

위에서 작성한 Python 예제 코드를 아래와 같이 실행한다.

$  python3  my_example_2.py

{ 'l2ng-l2ald-rtb-macdb':
    { 'l2ng-l2ald-mac-entry-vlan':
        { '@style': 'brief-rtb',
            'l2ng-l2-mac-routing-instance': 'default-switch',
            'l2ng-l2-vlan-id': '100',
            'l2ng-mac-entry': [
                { 'l2ng-l2-mac-address': '00:03:51:17:07:14',
                  'l2ng-l2-mac-age': '-',
                  'l2ng-l2-mac-flags': 'D',
                  'l2ng-l2-mac-fwd-next-hop': '0',
                  'l2ng-l2-mac-logical-interface': 'ge-0/0/23.0',
                  'l2ng-l2-mac-rtr-id': '0',
                  'l2ng-l2-mac-vlan-name': 'vlan-100'},
                { 'l2ng-l2-mac-address': '00:03:51:20:02:e2',
                  'l2ng-l2-mac-age': '-',
                  'l2ng-l2-mac-flags': 'D',
                  'l2ng-l2-mac-fwd-next-hop': '0',
                  'l2ng-l2-mac-logical-interface': 'ge-0/0/23.0',
                  'l2ng-l2-mac-rtr-id': '0',
                  'l2ng-l2-mac-vlan-name': 'vlan-100'},

                ... 중간 생략 ...

                { 'l2ng-l2-mac-address': 'fc:34:51:b6:35:eb',
                  'l2ng-l2-mac-age': '-',
                  'l2ng-l2-mac-flags': 'D',
                  'l2ng-l2-mac-fwd-next-hop': '0',
                  'l2ng-l2-mac-logical-interface': 'ge-0/0/23.0',
                  'l2ng-l2-mac-rtr-id': '0',
                  'l2ng-l2-mac-vlan-name': 'vlan-100'},
                { 'l2ng-l2-mac-address': 'fc:34:51:e1:35:ea',
                  'l2ng-l2-mac-age': '-',
                  'l2ng-l2-mac-flags': 'D',
                  'l2ng-l2-mac-fwd-next-hop': '0',
                  'l2ng-l2-mac-logical-interface': 'ge-0/0/23.0',
                  'l2ng-l2-mac-rtr-id': '0',
                  'l2ng-l2-mac-vlan-name': 'vlan-100'}
            ],
            'learnt-mac-count': '59',
            'mac-count-global': '59'
        }
    }
}

$

 

 


 

[ 예제 3 ]  Juniper Switch의  장치 정보, Spec 등 조회

아래 예제는 Juniper Switch(10.1.1.2) 장치에 접속해서 Juniper Switch의 장치 정보 및 Spec을 조회한다. (아래 항목을 참고)

- Switch model name

- Switch status

- 기동하여 운영되고 있는 시간 (up time)

- Switch 장비 이중화 정보 (Master, Member, FWDD 등)

- FQDN (domain name)

- Switch 장치의 Hostname

- JunOS 정보 (os name, version)

- etc

 

 

아래와 같이 Python 예제 코드를 작성한다.

from pprint import pprint
from jnpr.junos import Device
from jnpr.junos import Device

with Device(host='10.1.1.2', user='myuser', password='mypasswd1234' ) as dev:
    pprint(dev.facts)
    pprint(dev.facts['version'])
    pprint(dev.facts['switch_style'])

 

 

위에서 작성한 Python 예제 코드를 아래와 같이 실행한다.

$  python3  my_example_3.py

{'2RE': False,
 'HOME': '/var/home/admin',
 'RE0': {'last_reboot_reason': '0x1:power cycle/failure',
         'mastership_state': 'master',
         'model': 'RE-EX2300-24T',
         'status': 'OK',
         'up_time': '6 days, 23 hours, 50 minutes, 36 seconds'},
 'RE1': None,
 'RE_hw_mi': False,
 'current_re': ['master',
                'node',
                'fwdd',
                'member',
                'pfem',
                're0',
                'fpc0',
                'localre'],
                
... 중간 생략 ...

 'version': '20.4R3-S2.6',
 'version_info': junos.version_info(major=(20, 4), type=R, minor=3-S2, build=6),
 'virtual': False}
'20.4R3-S2.6'
'VLAN_L2NG'

$

 

 


 

[ 예제 4 ]  Juniper Switch의  Shell 명령, CLI 명령을 원격으로 실행

아래 예제는 Juniper Switch(10.1.1.2) 장치에 접속해서 Juniper Switch의 shell 명령(CLI 명령)을 실행하는 코드이다.

 

아래와 같이 Python 예제 코드를 작성한다.

from jnpr.junos import Device
from jnpr.junos.utils.start_shell import StartShell


dev = Device(host='10.1.1.2', user='myadmin', password='mypasswd1234' )

ss = StartShell(dev)
ss.open()

version = ss.run('cli -c "show version | no-more"')
print(version)

ether_tbl = ss.run('cli -c "show ethernet-switching table interface ge-0/0/23 | no-more"')
print(ether_tbl)

ss.close()

 

 

위에서 작성한 Python 예제 코드를 아래와 같이 실행한다.

$  python3  my_example_4.py

True, 'cli -c "show version | no-more"\r\r\n
 fpc0:\r\n
 --------------------------------------------------------------------------\r\n
 Model: ex2300-24t\r\n
 Junos: 20.4R3-S2.6\r\n
 JUNOS OS Kernel 32-bit  [20211117.c779bdc_builder_stable_11-204ab]\r\n
... 중간 생략 ...
 '
)


(True, 'cli -c "show ethernet-switching table interface ge-0/0/23 | no-more"\r\r\n\r\n
 MAC database for interface ge-0/0/23\r\n\r\n
 MAC database for interface ge-0/0/23.0\r\n\r\n
 MAC flags (S - static MAC, D - dynamic MAC, L - locally learned, P - Persistent static, C - Control MAC\r\n
           SE - statistics enabled, NM - non configured MAC, R - remote PE MAC, O - ovsdb MAC)\r\n\r\n\r\n
 Ethernet switching table : 61 entries, 61 learned\r\n
 Vlan                MAC                 MAC         Age    Logical                NH        RTR \r\n
 name                address             flags              interface              Index     ID\r\n
 default             00:03:5a:17:07:14   D             -   ge-0/0/23.0            0         0       \r\n
 default             00:03:5a:20:02:e2   D             -   ge-0/0/23.0            0         0       \r\n
... 중간 생략 ...
 default             fc:34:5a:e1:35:ea   D             -   ge-0/0/23.0            0         0       \r\n% '
)

$

 

 

 

 

 

 

 

 

참고 문서

Junos PyEX 파이썬 패키지를 사용하여 Juniper Switch 구성 정보를 가져오기

Junos PyEX 파이썬 패키지를 사용하여 출력 내용을 구조화하기 (출력할 컬럼을 선별하여 요약본 만들기)

 

 

 

 

 


 

반응형

 


작성일: 2025년 3월 28일

 

나는 Spirent, Ixia 같은 성능 계측기 회사의 계측 장비를 빌려서 성능 측정을 해오고 있었는데, 
공신력을 따지는 성능 측정 보고서가 필요한 경우가 아니라면, Open source code로 구현된 계측기도 쓸만할 것 같다는 생각이 들었다.
그래서 이것저것 찾아보다가 CISCO TRex 프로젝트가 눈에 들어왔다.

 

 

Cisco TRex 간단하게 살펴보기

- Intel DPDK를 사용

     주의: Poll Mode로 NIC에 있는 Data를 Fetch하기 때문에 특정  CPU Core 자원을 100% 다 사용한다.

             이런 이유로 TRex가 전용으로 사용할 CPU Core가 별도로 있어야 한다.

- Stateful 통신(예: TCP HTTP HTTPS DNS 등 Request & Response 방식), Stateless 통신(예: 단방향 UDP 통신) 모두 지원
- Open source
- TRex를 사용하면 개발자는 다양한 유형의 트래픽을 생성하고 결과로 수신되는 데이터를 분석
- 데이터 분석은 MAC 및 IP 수준에서 수행 (Network Layer 2~3를 처리하는 DUT에 대한 성능 측정이 목적이다.)
- DUT는 L3 Switch(IP Router) 또는 L4 이상의 IP network 처리 장치라고 가정
- Linux 환경에서 작동 (나는 Ubuntu 22.04에서 테스트했음)

 

 

TRex 설치 및 테스트 환경 구성

TRex와 DUT로 사용할 Linux 장비 구축

OS & HW:

  - OS: Ubuntu 22.04

  - Intel(R) Xeon(R) CPU E5-2640 v3 @ 2.60GHz (16 cores)

  - Memory 128GB

TRex 설치 파일을 Download

$  mkdir -p  /opt/trex
$  cd  /opt/trex
$  wget  --no-check-certificate  https://trex-tgn.cisco.com/trex/release/v3.06.tar.gz
$  tar -xfz  v3.06.tar.gz
$  ls -F 
 v3.06/
$  cd  v3.06

 

주의: 
아래 웹 페이지에서 TRex 최신 버전을 확인하고 다운로드하기.
https://trex-tgn.cisco.com/trex/release/

 

TRex가 사용할 NIC 설정

테스트 네트워크는 아래 그림과 같다.

2개의 Linux 장비 중에서 왼쪽 장비는 TRex를 설치하고, 오른쪽 장비는 DUT로 사용할 것이다.

DUT는 Linux에 static ip routing을 설정하여 간단한 Router 동작만 하게 할 것이다.

 

 

아래 예시처럼 똑같이 따라하면 된다.

$  ./dpdk_setup_ports.py -i

By default, IP based configuration file will be created. Do you want to use MAC based config? (y/N) N
+----+------+---------+-------------------+------------------------------------------------+-----------------+----------+----------+
| ID | NUMA |   PCI   |        MAC        |                      Name                      |     Driver      | Linux IF |  Active  |
+====+======+=========+===================+================================================+=================+==========+==========+
| 0  | 0    | 03:00.0 | 08:33:73:01:6b:98 | 82580 Gigabit Network Connection               | igb             | eth2     |          |
+----+------+---------+-------------------+------------------------------------------------+-----------------+----------+----------+
| 1  | 0    | 03:00.1 | 08:33:73:01:6b:99 | 82580 Gigabit Network Connection               | igb             | eth3     |          |
+----+------+---------+-------------------+------------------------------------------------+-----------------+----------+----------+
...
... 중간 생략 ...
...
+----+------+---------+-------------------+------------------------------------------------+-----------------+----------+----------+
| 14 | 1    | 88:00.0 | 08:33:73:08:3b:2a | 82599ES 10-Gigabit SFI/SFP+ Network Connection | uio_pci_generic |          |          |
+----+------+---------+-------------------+------------------------------------------------+-----------------+----------+----------+
| 15 | 1    | 88:00.1 | 08:33:73:08:3b:2b | 82599ES 10-Gigabit SFI/SFP+ Network Connection | uio_pci_generic |          |          |
+----+------+---------+-------------------+------------------------------------------------+-----------------+----------+----------+
| 16 | 1    | 8a:00.0 | 08:33:73:08:3b:2c | 82599ES 10-Gigabit SFI/SFP+ Network Connection | ixgbe           | eth16    |          |
+----+------+---------+-------------------+------------------------------------------------+-----------------+----------+----------+
| 17 | 1    | 8a:00.1 | 08:33:73:08:3b:2d | 82599ES 10-Gigabit SFI/SFP+ Network Connection | ixgbe           | eth17    |          |
+----+------+---------+-------------------+------------------------------------------------+-----------------+----------+----------+
Please choose an even number of interfaces from the list above, either by ID, PCI or Linux IF
Stateful will use order of interfaces: Client1 Server1 Client2 Server2 etc. for flows.
Stateless can be in any order.
For performance, try to choose each pair of interfaces to be on the same NUMA.
Enter list of interfaces separated by space (for example: 1 3) : 14 15

For interface 14, assuming loopback to its dual interface 15.
Putting IP 1.1.1.1, default gw 2.2.2.2 Change it?(y/N) N
For interface 15, assuming loopback to its dual interface 14.
Putting IP 2.2.2.2, default gw 1.1.1.1 Change it?(y/N) N
Print preview of generated config? (Y/n) Y

... 출력 내용 생략 ...

$  vi /etc/trex_cfg.yaml

### Config file generated by dpdk_setup_ports.py ###

- version: 2
  interfaces: ['88:00.0', '88:00.1']
  port_info:
      - ip: 16.0.0.253                ## 내가 수정한 부분.  TRex client side IP address.
        default_gw: 16.0.0.254        ## 내가 수정한 부분.  DUT IP address.
      - ip: 48.0.0.253                ## 내가 수정한 부분.  TRex server side IP address.
        default_gw: 48.0.0.254        ## 내가 수정한 부분.  DUT IP address.

  platform:
      master_thread_id: 0
      latency_thread_id: 1
      dual_if:
        - socket: 1
          threads: [8,9,10,11,12,13,14,15,24,25,26,27,28,29,30,31]

$

 

위 port_info 항목에서 설정한 network 대역에 대해서 간략하게 설명하면,

- Client host가 사용할 IP address range:  16.0.0.0 ~ 16.0.0.127   (16.0.0.0/25)

- Server host가 사용할 IP address range: 48.0.0.0 ~ 48.0.0.127 (48.0.0.0/25)

- Client host가 사용할 gateway address: 16.0.0.254

- Server host가 사용할 gateway address: 48.0.0.254

 

 

DUT 장비에서 설정할 내용

DUT 장비에서 아래와 같이 ip_forward에 관해 설정한다.

##
## Linux OS가 IP packet을 forward할 수 있도록 ip_forward를 enable 시킨다.
##
sysctl -w net.ipv4.ip_forward=1
# or
# echo 1 > /proc/sys/net/ipv4/ip_forward

 

DUT 장비에서 Network port를 설정한다.

$  vi  /etc/netplan/00-installer-config.yaml

network:
  version: 2
  ethernets:
    eth0:
      addresses:
        - 16.0.0.254/25
      routes:
        - to: 16.0.0.0/25
          via: 16.0.0.253
    eth1:
      addresses:
        - 48.0.0.254/25
      routes:
        - to: 48.0.0.0/25
          via: 48.0.0.253
... 중간 생략 ...

$ netplan apply
위 network 설정에 대한 부연 설명:
 - TRex의 client 및 server가 emulation하는 IP address(16.0.0.0/25)가 DUT와 동일한 IP network이면 안 된다.
 - 아마도 TRex를 구현할 때, (IP address + MAC address)를 Mapping하여 Host를 emulation하면 computing cost 및 MAC learning에 대한 load가 커지기 때문에 MAC address를 과감하게 생략하고 L3 switch 뒤에 Host 장치가 있다고 가정하고 TRex를 구현한게 아닌가 싶다. (나의 상상력에 의한 추정) 

 

 

 

 


 

 

테스트를 위한 준비 작업은 끝 !!

아래 글은 실제로 TCP, UDP 패킷을 생성하여 성능 테스트 방법이다.

복잡한 입력 내용은 없고, 아래 예제 CLI 명령을 복붙(Copy & Paste)하면 땡 !!

 

 


 

 

Stateful Networking Test (TCP, HTTP)

TRex로 사용할 Linux 장비에 SSH 터미널을 미리 2개 접속해놓고 사용하는 것이 좋다.

[ Terminal A  -  TRex 서버 프로그램 구동용 ]

$  ./t-rex-64  -i  --astf

The ports are bound/configured.
Starting  TRex v3.04 please wait  ...
 set driver name net_ixgbe
 driver capability  : TCP_UDP_OFFLOAD  TSO  LRO
 set dpdk queues mode to RSS_DROP_QUE_FILTER
 Number of ports found: 2
zmq publisher at: tcp://*:4500
 wait 1 sec .
port : 0
------------
link         :  link : Link Up - speed 10000 Mbps - full-duplex
promiscuous  : 0
port : 1
------------
link         :  link : Link Up - speed 10000 Mbps - full-duplex
promiscuous  : 0
 number of ports         : 2
 max cores for 2 ports   : 1
 tx queues per port      : 3
 -------------------------------
RX core uses TX queue number 2 on all ports
 core, c-port, c-queue, s-port, s-queue, lat-queue
 ------------------------------------------
 1        0      0       1       0      0
 -------------------------------


-Per port stats table
      ports |               0 |               1
 -----------------------------------------------------------------------------------------
   opackets |               0 |               0
     obytes |               0 |               0
   ipackets |               0 |               0
     ibytes |               0 |               0
    ierrors |               0 |               0
    oerrors |               0 |               0
      Tx Bw |       0.00  bps |       0.00  bps

-Global stats enabled
 Cpu Utilization : 0.0  %
 Platform_factor : 1.0
 Total-Tx        :       0.00  bps
 Total-Rx        :       0.00  bps
 Total-PPS       :       0.00  pps
 Total-CPS       :       0.00  cps

 Expected-PPS    :       0.00  pps
 Expected-CPS    :       0.00  cps
 Expected-L7-BPS :       0.00  bps

 Active-flows    :        0  Clients :        0   Socket-util : 0.0000 %
 Open-flows      :        0  Servers :        0   Socket :        0 Socket/Clients :  -nan
 drop-rate       :       0.00  bps
 current time    : 2.8 sec
 test duration   : 0.0 sec
 
 ##
 ## 이 터미널은 계속 출력용으로 사용되고, 사용자 입력을 받을 수 없다.
 ##

 

[ Terminal B - 사용자 명령 입력용 ]

$ ./trex-console

... 중간 생략 ...

Type 'help' or '?' for supported actions

trex> stats --ps
Port Status

     port       |          0           |          1
----------------+----------------------+---------------------
driver          |      net_ixgbe       |      net_ixgbe
description     |  82599ES 10-Gigabit  |  82599ES 10-Gigabit
link status     |          UP          |          UP
link speed      |       10 Gb/s        |       10 Gb/s
port status     |         IDLE         |         IDLE
promiscuous     |         off          |         off
multicast       |         off          |         off
flow ctrl       |         none         |         none
vxlan fs        |          -           |          -
--              |                      |
layer mode      |         IPv4         |         IPv4
src IPv4        |      16.0.0.253      |      48.0.0.253
IPv6            |         off          |         off
src MAC         |  08:33:73:08:3b:2a   |  08:33:73:08:3b:2b
---             |                      |
Destination     |      16.0.0.254      |      48.0.0.254
ARP Resolution  |  00:87:33:72:a8:9c   |  00:87:33:72:a8:9d
----            |                      |
VLAN            |          -           |          -
-----           |                      |
PCI Address     |     0000:88:00.0     |     0000:88:00.1
NUMA Node       |          1           |          1
RX Filter Mode  |    hardware match    |    hardware match
RX Queueing     |         off          |         off
Grat ARP        |  every 120 seconds   |  every 120 seconds
------          |                      |

trex> start  -f astf/http_simple.py  -m 2  -d 10   ## 10초 동안 테스트 수행

trex> tui

tui> Global Statistics

connection   : localhost, Port 4501                       total_tx_L2  : 0 bps
version      : ASTF @ v3.04                               total_tx_L1  : 0 bps
cpu_util.    : 0.0% @ 1 cores (1 per dual port)           total_rx     : 0 bps
rx_cpu_util. : 0.0% / 0 pps                               total_pps    : 0 pps
async_util.  : 0% / 38.44 bps                             drop_rate    : 0 bps
total_cps.   : 0 cps                                      queue_full   : 0 pkts

Port Statistics

   port    |         0         |         1         |       total
-----------+-------------------+-------------------+------------------
owner      |              root |              root |
link       |                UP |                UP |
state      |            LOADED |            LOADED |
speed      |           10 Gb/s |           10 Gb/s |
CPU util.  |              0.0% |              0.0% |
--         |                   |                   |
Tx bps L2  |             0 bps |             0 bps |             0 bps
Tx bps L1  |             0 bps |             0 bps |             0 bps
Tx pps     |             0 pps |             0 pps |             0 pps
Line Util. |               0 % |               0 % |
---        |                   |                   |
Rx bps     |             0 bps |             0 bps |             0 bps
Rx pps     |             0 pps |             0 pps |             0 pps
----       |                   |                   |
opackets   |               343 |              1401 |              1744
ipackets   |              1401 |               343 |              1744
obytes     |             38396 |           1895776 |           1934172
ibytes     |           1895776 |             38396 |           1934172
tx-pkts    |          343 pkts |         1.4 Kpkts |        1.74 Kpkts
rx-pkts    |         1.4 Kpkts |          343 pkts |        1.74 Kpkts
tx-bytes   |           38.4 KB |            1.9 MB |           1.93 MB
rx-bytes   |            1.9 MB |           38.4 KB |           1.93 MB
-----      |                   |                   |
oerrors    |                 0 |                 0 |                 0
ierrors    |                 0 |                 0 |                 0

status:  -

Press 'ESC' for navigation panel...
status: [OK]

tui> stop

trex> exit

$

 

위 터미널 내용을 Image로 캡처하면, 아래 모양처럼 보인다.

 

 

위에서 사용한 astf/http_simple.py 스크립트 외에 내가 테스트하면서 유용하다고 생각했던 스크립트들을 열거하면 아래와 같다.

##
## 서로 다른 내용의 여러 개 PCAP을 동시에 Play할 때는 아래 스크립트를 사용한다.
##
trex>  start  -f astf/http_by_l7_percent.py  -m 100  -d 30
... 출력 내용 생략 ...


##
## Interative mode의 CLI가 아닌 경우도 지원한다.
##
$ ./t-rex-64 --astf -f astf/http_simple_cc.py   -m 300mbps  -d 30

 

 

Stateful Networking Test (UDP Request & Response)

TCP/HTTP 테스트랑 터미널 구성이나 CLI 명령 입력이 비슷하기 때문에 [ Terminal B ]에 입력하는 내용만 설명하겠다.

[ Terminal B - 사용자 명령 입력용 ]

##
## UDP로 1개의 요청 메시지를 보내고, 1개의 응답 메시지를 받는 경우.
##
trex>  start  -f astf/udp1.py  -m 10000  -d 30


##
## SIP/UDP 요청 메시지를 보내고, 응답 메시지를 받는 경우.
##
trex>  start  -f astf/udp_sip.py  -m 1000000  -d 5


##
## DNS/UDP 요청 메시지를 보내고, 응답 메시지를 받는 경우.
##
trex>  start  -f astf/udp_topo_traffic.py  -m 30000  -d 10

 

 

Stateless Networking Test (UDP One-Way Direction)

단방향으로 UDP 패킷만 보내는 경우에는 아래와 같이 명령을 수행한다. (Spirent C1 계측기와 유사한 동작)

[ Terminal A  -  TRex 서버 프로그램 구동용 ]

$  ./t-rex-64 -i --stl --no-scapy-server

... 출력 내용 생략 ...

 

[ Terminal B - 사용자 명령 입력용 ]

$  ./trex-console

trex>  portattr -a --prom on
... 출력 내용 생략 ...


trex>  stats --ps
... 출력 내용 생략 ...


trex>  start -f stl/udp_1pkt_src_ip_split.py  -m 9809mbps -d 15
... 출력 내용 생략 ...


trex>  start -f stl/bench.py -m 10kbps -d 5
... 출력 내용 생략 ...


trex>  start -f stl/udp_multi_simple_list_test.py -m 10kbps -d 5
... 출력 내용 생략 ...


trex>  start -f stl/udp_1pkt_simple.py -m 10kbps -d 5
... 출력 내용 생략 ...


trex>  streams -a      
... 출력 내용 생략 ...

 

 

 

 

Concurrent Connection Test (CC 테스트, 동시 접속 과부하 테스트)

HTTP 세션이 오래 유지되도록 하면서 서버 장비 또는 L4 ~ L7 Network 장비의 Memory 부하를 끌어올리는 테스트를 하고자 한다면,

아래의 설정과 명령을 따라 수행하면 된다.

(테스트 절차가 위에서 했던 테스트와 비슷하므로 자세한 설명은 생략한다.)

 

우선 TRex 설정 값부터 조정해야 한다.

trex_cfg.yaml 파일에서 dp_flows 항목의 값을 적당히 높여준다.

물론 TRex가 돌아가는 장비(HW)의 Memory가 충분한지 먼저 확인하고 적절하게 값을 높여서 설정한다.

$  vim  /etc/trex_cfg.yaml
- version: 2
  memroy:
    ## 30GB --> 15,000,000 flows  (이 값을 참고하여 필요한 만큼 값을 올린다)
    dp_flows: 15000000
... 중간 생략 ...

$  cd $TREX_ROOT
$  ./t-rex-64  -i  --astf

 

그리고 아래와 같이 python 스크립트를 수행한다.

$  ./trex-console

trex> start  -f astf/http_high_active_flows.py  -m 1000  -t delay=10000000

## 유용한 옵션 값을 제시하면 아래와 같다.
##   아래 옵션으로 실행하면,
##     CC  : 500,000 ~ 550,000
##     CPS : 40,000
##     BPS : 300Mbps
##     CPU : 50%
tui> start  -f astf/http_high_active_flows.py  -m 50000  -t delay=10000000


##   아래 옵션으로 실행하면,
##     CC  : 1,000,000    # 위 명령보다 delay를 2배 늘리면, CC도 2배 늘어난다.
##     CPS : 40,000
##     BPS : 320Mbps
##     CPU : 50%
tui> start  -f astf/http_high_active_flows.py  -m 50000  -t delay=20000000

 

참고:  -m 옵션의 값을 처음에는 작게 설정해서 테스트하고, 테스트 결과를 보면서 -m 옵션 값을 2~10배씩 올려가면서 테스트한다.

 

 




 

 

 

 

참고 문서 (내가 읽어보고 괜찮다고 느낀 순서로 정렬)

문서 이름 문서 URL
TRex - Use Case (TCP, UDP)
(참고: 깊은 이해 없이 따라하기 좋음)
https://promwad.com/news/cisco-trex-traffic-generator
TRex - 최초 구성 설정 방법 https://github.com/cisco-system-traffic-generator/trex-core/blob/master/doc/trex_config.asciidoc
TRex 사용 매뉴얼 https://trex-tgn.cisco.com/trex/doc/trex_manual.html
TRex PKG 릴리즈 리스트 (버전별) https://trex-tgn.cisco.com/trex/release/
TRex - Use Case (UDP) https://satishdotpatel.github.io/trex-load-generator/
TRex Stateless support https://trex-tgn.cisco.com/trex/doc/trex_stateless.html
TRex Advance stateful support
  (TCP, HTTP 테스트할 때 도움이 됨) 
https://trex-tgn.cisco.com/trex/doc/trex_astf.html
TRex GUI https://github.com/cisco-system-traffic-generator/trex-stateless-gui

 

 

 

 


 

반응형

 


 

작성일: 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월 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/

 

 

 

 

 

 

 


 

반응형

 


 

작성일: 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