반응형

 


작성일: 2024년 8월 7일

 

 

Ubuntu 22.04, Ubuntu 24.04에서 부팅 시간이 긴 현상

Ubuntu를 설치하고, 부팅할 때 아래와 같이 Network 설정 화면에서 오랜 시간 대기하는 경우가 있다.

 

A start job is running for wait for network to be configured

 

일단, Ubuntu OS가 부팅되면 root 계정으로 아래와 같이 설정을 수정하고 reboot하면, 빠르게 부팅될 것이다.

 

##
## Network connection을 기다라지 않기 위해 아래와 같이 
## systemd-networkd-wait-online.service 서비스를 비활성화한다.
##
$  systemctl disable systemd-networkd-wait-online.service

##
## 다른 서비스에 의해서 systemd-networkd-wait-online.service 서비스가 활성화되는 것을 막기 위해
## 아래와 같이 systemd-networkd-wait-online.service 서비스를 masking한다.
##
$  systemctl mask systemd-networkd-wait-online.service

 

 

참고: 
  DHCP 설정 Off는 위 이슈와 관련은 없지만, 0.1초라도 부팅 시간을 줄이고자 한다면 DHCP를 off하는 것이 좋다.
  (물론, DHCP를 사용할 일이 없을 때만~~~)
##
## DHCP로 IP address 설정할 필요가 없다면, DHCP 기능을 끈다.
##
$  cat /etc/netplan/00-installer-config.yaml

... 중간 생략 ...

    enp7s0:
      dhcp4: false
      
... 중간 생략 ...

$

 


 

 

 

 

 

 

 

##
## 채용 관련 글
##
제가 일하고 있는 기업 부설연구소에서 저와 같이 연구/개발할 동료를 찾고 있습니다.
(이곳은 개인 블로그라서 기업 이름은 기재하지 않겠습니다. E-mail로 문의주시면 자세한 정보를 공유하겠습니다.)

근무지 위치:
  서울시 서초구 서초동, 3호선 남부터미널역 근처 (전철역 출구에서 회사 입구까지 도보로 328m)
필요한 지식 (아래 내용 중에서 70% 정도를 미리 알고 있다면 빠르게 협업할 수 있음):
  - 운영체제 (학부 3~4학년 때, 컴퓨터공학 운영체제 과목에서 배운 지식 수준):
    예를 들어, Processor, Process 생성(Fork)/종료, Memory, 동시성, 병렬처리, OS kernel driver  
  - Linux OS에서 IPC 구현이 가능
    예를 들어, MSGQ, SHM, Named PIPE 등 활용하여 Process간 Comm.하는 기능 구현이 가능하면 됨. 
  - Algorithm(C언어, C++ 언어로 구현 가능해야 함)
    예를 들어, Hashtable, B-Tree, Qsort 정도를 C 또는 C++로 구현할 수 있을 정도 
  - Network 패킷 처리 지식(Layer 2 ~ 4, Layer 7)
    예를 들어, DHCP Server/Client의 주요 Feature를 구현할 정도의 능력이 있으면 됨.
  - Netfilter, eBPF 등 (IP packet hooking, ethernet packet 처리, UDP/TCP packet 처리)
  - IETF RFC 문서를 잘 읽고 이해하는 능력 ^^
  # 위에 열거한 내용 외에도 제가 여기 블로그에 적은 내용들이 대부분 업무하면서 관련이 있는 주제를 기록한 것이라서
  # 이 블로그에 있는 내용들을 잘 알고 있다면, 저희 연구소에 와서 연구/개발 업무를 수행함에 있어서 어려움이 없을 겁니다.
회사에서 사용하는 프로그래밍 언어:
  - 프로그래밍 언어: C, C++, Go
    (참고: 아직 연구소 동료들이 Rust를 사용하진 않습니다만, 새 언어로써 Rust를 사용하는 것을 고려하는 중)
근무 시간:
  - 출근: 8~10시 사이에서 자유롭게 선택
  - 퇴근: 8시간 근무 후 퇴근 (오후 5시 ~ 7시 사이)
  - 야근 여부: 거의 없음 (내 경우, 올해 상반기 6개월간 7시 이후에 퇴근한 경우가 2회 있었음)
  - 회식 여부: 자유 (1년에 2회 정도 회식하는데, 본인이 집에 가고 싶으면 회식에 안 감. 왜 참석 안 하는지 묻지도 않음)
외근 여부:
  - 신규 프로젝트 멤버 -> 외근 전혀 하지 않음 (나는 신규 프로젝트만 참여해서 지난 1년 동안 한번도 외근 없었음)
  - 상용 프로젝트 멤버 -> 1년에 5회 미만 정도로 외근
팀 워크샵 여부:
  - 팀 워크샵 자체를 진행하지 않음. (워크샵 참석하는 거 싫어하는 개발자 환영 ^^)
연락처:
  - "sejong.jeonjo@gmail.com"  # 궁금한 점은 이 연락처로 문의주세요.
  - 블로그 비밀 댓글 (제가 하루에 한번씩 댓글 확인하고 있음)
원하는 인재상:
  - 우리 부설연구소는 "긴 호흡으로 프로젝트를 진행"하기 때문에 최소 2년간 한 가지 주제를 꾸준하게 연구/개발할 수 있는 개발자를 원함.
  - 우리 부설연구소는 자주적으로 연구 주제를 찾아서 업무를 하기 때문에 능동적으로 생각하고 행동하는 동료를 원함.
  - 차분하게 연구 주제에 몰입하고, 해법을 찾는 것을 즐기는 사람.
내가 느끼는 우리 연구소의 장점:
  - 갑/을 관계가 없음. (제가 근무하고 있는 연구소는 SI업종이 아니라서 갑/을 회사 개념이 없음)
  - 연구소 자체적으로 연구 주제를 발굴하고 시스템을 개발하기 때문에 개발 일정에 대한 스트레스가 적음
  - 빌딩 전체를 우리 회사가 사용하므로 분위기가 산만하지 않음.
  - 근처에 예술의전당, 우면산 둘레길이 있어서 점심 시간에 산책하기 좋음 ^^
  - 연구소 동료들 매너가 Good (2년간 일하면서 한번도 감정에 스크레치 생기거나 얼굴 붉히며 싸운 적 없음 ^^)

 

 

반응형

 


 

테스트한 날짜:  2024년 2월 20일
테스트에 사용한 OS: Ubuntu 22.04

 

Linux 장비를 PPTP Client로 사용하기 위한 방법

Client 입장에서 Linux PC를 PPTP 서버와 GRE Tunnel을 생성하는 방법이다.

 

전제 조건:
    아래 PPTP Client 예제를 수행하기 전에 PPTP 서버가 이미 구성되어 있어야 한다. 
    IPTIME 같은 인터넷 공유기에 PPTP 서버 기능이 있으니까, 쉽게 테스트하려면 IPTIME 공유기를 이용하는 것이 좋다.

 

잠깐 !!
Linux 장비(Ubuntu 22.04)에 PPTP Server를 구축할 계획이라면, 아래 문서를 참고하기 !

 

       https://andrewpage.tistory.com/361

 

##########################################################
## Client Linux OS에서 아래의 명령을 수행
##########################################################

##########################################################
## pptp 관련 패키지를 설치한다.
##########################################################
$  sudo apt install pptp-linux


##########################################################
## /etc/ppp/options 파일을 편집한다.
##########################################################
$  cat  /etc/ppp/options

lock
noauth
nobsdcomp
nodeflate
refuse-pap
refuse-eap
refuse-chap
refuse-mschap
mtu 1400

$

##########################################################
## /etc/ppp/chap-secrets 파일을 편집한다.
##########################################################
$  cat  /etc/ppp/chap-secrets

sejong  PPTP  "my-password" *

$

##########################################################
##  /etc/ppp/peers/sejong 파일을 편집한다.
##########################################################
$  cat  /etc/ppp/peers/sejong

pty "pptp 55.123.12.123 --nolaunchpppd"
name sejong
remotename PPTP
file /etc/ppp/options
ipparam sejong




##########################################################
## << 참고:  이 작업은 필요한 경우만 할 것 !!! >>
##
## 이 내용은 꼭 필요한 것은 아닌데, ppp0 tunnel port가 생성되고 IP address가 설정되고 나서
## static routing table에 추가하고 싶은 내용이 있다면, 
## 아래와 같이 ip-up 파일에 route 명령을 추가한다. 
## (이렇게 하는 것이 정석적 방법인지는 모르겠다.  일단, 나는 이렇게 사용하고 있다.)
##########################################################
$  cat  /etc/ppp/ip-up

... (중간 생략) ...
ip route add 192.168.0.0/24 dev ppp0    # <-- 나는 이 내용을 추가했다.

$


##########################################################
## 이제 설정 작업은 모두 끝났다. pon 명령을 실행하면 잘 동작할 것이다. ^^
##########################################################

##########################################################
## 위에서 설정한 파일을 이용하여 PPTP 서버와 GRE 터널을 만든다.
## 참고로 pon 명령은 "ppp on"을 줄인 말이다.
##########################################################
$  pon  sejong  debug  dump  logfd 2  nodetach

...
...
local  IP address 192.168.0.220
remote IP address 192.168.0.1
Script /etc/ppp/ip-up started (pid 14290)
Script /etc/ppp/ip-up finished (pid 14290), status = 0x0

 

참고로, 위 pon 명령을 수행하면 명령행 prompt가 출력되지 않는다.
왜냐하면 pon 명령이 백그라운드로 동작하는 것이 아니기 때문에 pod 명령을 수행한 터미널은 이 상태로 두고,
다른 터미널을 하나 더 열어서 작업해야 한다.
새 터미널에서 아래와 같이 VPN 서버 쪽으로 ping을 보내본다.

 

$  ping 192.168.0.1

ing 192.168.0.1 -c 1
PING 192.168.0.1 (192.168.0.1) 56(84) bytes of data.
64 bytes from 192.168.0.1: icmp_seq=1 ttl=64 time=4.45 ms

--- 192.168.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 4.448/4.448/4.448/0.000 ms

$

 

 


 

PPTP 및 GRE Tunnel 설정 관련 문서

 

 

PPTP Client - ArchWiki

pptpclient is a program implementing the Microsoft PPTP protocol. As such, it can be used to connect to a Microsoft VPN network (or any PPTP-based VPN) provided by a school or workplace. Installation Install the pptpclient package. Configure To configure p

wiki.archlinux.org

 

 


 

반응형

 

 

Ubuntu OS를 설치한 후, Network 구성을 바꿀 때 nmtui, netplan, nm-connection-editor 등 CLI 명령을 사용하면 쉽게 network 구성을 설정할 수 있다.

 

nmtui 명령

메모: 지금은 바빠서 설명을 생략.  나중에 내용을 추가할 것 !!
$ nmtui

Text Terminal에서 위 명령을 수행하면, 아래와 같이 동일 Text Terminal에서 TUI가 뜬다.

nmtui 시작 화면

 

 

netplan 명령

길게 설명하는 것보다는 아래 예시를 보고 이해하고 따라하는 것이 좋을 듯 ~~~

 

 

Case A:
만약 Gnome Desktop GUI의 [ Settings ] - [ Network ] - [ Wired ] 화면에서 설정하고 싶으면,
아래와 같이 renderer를 NetworkManager로 지정하고 아무것도 설정하지 않으면 된다.
그러면 NetworkManager가 알아서 Physical Network Device를 찾아서 Profiling할 것이다.

 

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

network:
    renderer: NetworkManager
    version: 2
    
$  netplan  apply

 

Case B:
만약 Gnome Desktop GUI의 [ Settings ] - [ Network ] - [ Wired ] 화면에서 설정한 값을 무시하고
설정 파일에 있는 Network Config를 적용하고 싶다면, 
아래와 같이 renderer를 networkd 로 지정한다. 그런 후에 원하는 설정을 추가한다.
$  cat  /etc/netplan/00-installer-config.yaml

network:
    renderer: networkd
    version: 2
    ethernets:
        enp4s0:
            addresses:
                - 0.0.0.0/32
        br-ex:
            addresses:
                - 10.1.3.166/24
            nameservers:
                addresses: [8.8.8.8, 8.8.4.4]
            routes:
                - to: default
                  via: 10.1.3.1
        br-ex:                  
            dhcp4: true
 
$  netplan apply

## 설정 파일(YAML)에 에러가 없으면, 아무것도 출력하지 않는다.

$

 

 

 

nm-connection-editor 명령

SSH로 접속한 Text Terminal에서는 실행하면 안 되고, 원격 데스크탑(Remote Desktop)으로 접속했거나 Console Monitor를 사용한 경우에만 nm-connection-editor가 동작한다.

 

nm-connection-editor 시작 화면

 

 

게시물 작성자: sejong.jeonjo@gmail.com

 

 

 

반응형

Go Language로 특정 Process의 CPU, Memory 사용량을 계산하고 싶다면,

아래의 코드를 Build해서 사용하면 된다.

 

참고: Linux, MacOS, Unix, Windows 모두 동작하는 코드임.

 

 

// Filename: proc_usage.go

package main

import (
	"errors"
	"fmt"
	"io/ioutil"
	"math"
	"os/exec"
	"path"
	"runtime"
	"strconv"
	"strings"
	"sync"
)

const (
	statTypePS   = "ps"
	statTypeProc = "proc"
)

// SysInfo will record cpu and memory data
type SysInfo struct {
	CPU    float64
	Memory float64
}

// Stat will store CPU time struct
type Stat struct {
	utime  float64
	stime  float64
	cutime float64
	cstime float64
	start  float64
	rss    float64
	uptime float64
}

type fn func(int) (*SysInfo, error)

var fnMap map[string]fn
var platform string
var history map[int]Stat
var historyLock sync.Mutex
var eol string

// Linux platform
var clkTck float64 = 100    // default
var pageSize float64 = 4096 // default

func init() {
	platform = runtime.GOOS
	if eol = "\n"; strings.Index(platform, "win") == 0 {
		platform = "win"
		eol = "\r\n"
	}
	history = make(map[int]Stat)
	fnMap = make(map[string]fn)
	fnMap["darwin"] = wrapper("ps")
	fnMap["sunos"] = wrapper("ps")
	fnMap["freebsd"] = wrapper("ps")
	fnMap["openbsd"] = wrapper("proc")
	fnMap["aix"] = wrapper("ps")
	fnMap["linux"] = wrapper("proc")
	fnMap["netbsd"] = wrapper("proc")
	fnMap["win"] = wrapper("win")

	if platform == "linux" || platform == "netbsd" || platform == "openbsd" {
		initProc()
	}
}

func initProc() {
	clkTckStdout, err := exec.Command("getconf", "CLK_TCK").Output()
	if err == nil {
		clkTck = parseFloat(formatStdOut(clkTckStdout, 0)[0])
	}

	pageSizeStdout, err := exec.Command("getconf", "PAGESIZE").Output()
	if err == nil {
		pageSize = parseFloat(formatStdOut(pageSizeStdout, 0)[0])
	}

}

func wrapper(statType string) func(pid int) (*SysInfo, error) {
	return func(pid int) (*SysInfo, error) {
		return stat(pid, statType)
	}
}

func formatStdOut(stdout []byte, userfulIndex int) []string {
	infoArr := strings.Split(string(stdout), eol)[userfulIndex]
	ret := strings.Fields(infoArr)
	return ret
}

func parseFloat(val string) float64 {
	floatVal, _ := strconv.ParseFloat(val, 64)
	return floatVal
}

func statFromPS(pid int) (*SysInfo, error) {
	sysInfo := &SysInfo{}
	args := "-o pcpu,rss -p"
	if platform == "aix" {
		args = "-o pcpu,rssize -p"
	}
	stdout, _ := exec.Command("ps", args, strconv.Itoa(pid)).Output()
	ret := formatStdOut(stdout, 1)
	if len(ret) == 0 {
		return sysInfo, errors.New("Can't find process with this PID: " + strconv.Itoa(pid))
	}
	sysInfo.CPU = parseFloat(ret[0])
	sysInfo.Memory = parseFloat(ret[1]) * 1024
	return sysInfo, nil
}

func statFromProc(pid int) (*SysInfo, error) {
	sysInfo := &SysInfo{}
	uptimeFileBytes, err := ioutil.ReadFile(path.Join("/proc", "uptime"))
	if err != nil {
		return nil, err
	}
	uptime := parseFloat(strings.Split(string(uptimeFileBytes), " ")[0])

	procStatFileBytes, err := ioutil.ReadFile(path.Join("/proc", strconv.Itoa(pid), "stat"))
	if err != nil {
		return nil, err
	}
	splitAfter := strings.SplitAfter(string(procStatFileBytes), ")")

	if len(splitAfter) == 0 || len(splitAfter) == 1 {
		return sysInfo, errors.New("Can't find process with this PID: " + strconv.Itoa(pid))
	}
	infos := strings.Split(splitAfter[1], " ")
	stat := &Stat{
		utime:  parseFloat(infos[12]),
		stime:  parseFloat(infos[13]),
		cutime: parseFloat(infos[14]),
		cstime: parseFloat(infos[15]),
		start:  parseFloat(infos[20]) / clkTck,
		rss:    parseFloat(infos[22]),
		uptime: uptime,
	}

	_stime := 0.0
	_utime := 0.0

	historyLock.Lock()
	defer historyLock.Unlock()

	_history := history[pid]

	if _history.stime != 0 {
		_stime = _history.stime
	}

	if _history.utime != 0 {
		_utime = _history.utime
	}
	total := stat.stime - _stime + stat.utime - _utime
	total = total / clkTck

	seconds := stat.start - uptime
	if _history.uptime != 0 {
		seconds = uptime - _history.uptime
	}

	seconds = math.Abs(seconds)
	if seconds == 0 {
		seconds = 1
	}

	history[pid] = *stat
	sysInfo.CPU = (total / seconds) * 100
	sysInfo.Memory = stat.rss * pageSize
	return sysInfo, nil
}

func stat(pid int, statType string) (*SysInfo, error) {
	switch statType {
	case statTypePS:
		return statFromPS(pid)
	case statTypeProc:
		return statFromProc(pid)
	default:
		return nil, fmt.Errorf("Unsupported OS %s", runtime.GOOS)
	}
}

// GetStat will return current system CPU and memory data
func GetStat(pid int) (*SysInfo, error) {
	sysInfo, err := fnMap[platform](pid)
	return sysInfo, err
}

 

 

 

// Filename: main.go

package main

import (
    "os"
    "fmt"
    "time"
    "strconv"
)

func main() {
    myPid, _ := strconv.Atoi(os.Args[1])

    for i:= 0; i < 100; i++ {
        sysInfo, _ := GetStat(myPid)
        fmt.Println("CPU Usage     :", sysInfo.CPU)
        fmt.Println("Mem Usage(RSS):", sysInfo.Memory)
        time.Sleep(5 * time.Second)
    }
}

 

위와 같이 Go source code를 모두 작성했다면, 아래처럼 build하고 실행하면 된다.

 

$ go mod init andrew.space/proc_usage
go: creating new go.mod: module andrew.space/proc_usage
go: to add module requirements and sums:
	go mod tidy
    
$ go mod tidy

$ go build

$ ./proc_usage 4314
CPU Usage     : 52.92167225853122
Mem Usage(RSS): 2.018664448e+09
CPU Usage     : 39.800000000000004
Mem Usage(RSS): 2.018664448e+09
CPU Usage     : 47.30538922366738
Mem Usage(RSS): 2.018664448e+09
...
...

 

top 명령으로 본 것과 결과가 동일했다.

반응형
작성일: 2025년 5월 5일

 

 

시스템 알람을 발생시키는 테스트를 하거나 Kubernetes의 Horizontal Pod Autoscaler 기능 테스트를 할 때,

CPU 부하를 발생시키는 명령 도구가 있으면 편하다.

아래와 같이 설치하고 테스트하면 된다. (설명은 생략하고, 그냥 따라해보자~)

 

 

##
## 설치
##

$ yum install -y stress

$ stress --help
...

##
## 30초 동안 3000ms의 CPU 과부하를 유발하기.
##
$ stress --cpu 3 --timeout 30s

##
## 500MB의 메모리 과부하를 유발하기
##  --vm : Worker 개수
##  --vm-hang : malloc 실행 후 free하기 전까지 sleep할 시간(초)
##
$ stress --vm 1 --vm-bytes 500M --vm-hang 1

 

 

또는 아래와 같은 명령 예시를 따라해도 비슷한 효과를 얻을 수 있다.

$ yum install -y stress-ng

## CPU 사용률 70%를 유지하고자 할 경우
$ stress-ng  --cpu 1  --cpu-load 70%  --timeout 10m  --metrics  --times  --verify

 

 

블로그 작성자: sejong.jeonjo@gmail.com

 

 

반응형

 

작성일: 2024년 2월 16일

 

프로그래밍을 하다보면, 시간 값으로 "1697180099.123" 이런 형태의 값을 많이 보게된다.

이런 형태의 시간 값을 unix time 또는 epoch time이라고 한다.

 

1970년 1월 1일 0시 0분 0초를 Unix epoch라고 정의한다.

그리고 이 Unix epoch 이후부터 흐른 시간(초)를 표현한 것이 unix time(epoch time)이다.

 

그런데 이 Unix time은 컴퓨터가 다루기 좋은 형태일 뿐, 사람은 이 숫자(unix time)를 봐도 몇월 며칠 몇시인지 알 수 없다.

이럴 때 편하게 unix time을 우리가 읽을 수 있는 날짜 형태로 바꾸어는 웹 페이지가 있다.

아래 웹 페이지에서 unix time을 입력하면 사람이 읽기 좋은 형태로 바꾸어준다. 그 반대의 경우가 제공한다.

 

 

Epoch Converter

Convert Unix Timestamps (and many other date formats) to regular dates.

www.epochconverter.com

 

또는 Linux 명령어 중에 date 명령으로도 쉽게 날짜 형태를 바꿀 수 있다.

 

$  date -d @1657180059
Thu 07 Jul 2022 04:47:39 PM KST

$  date --date=@0
Thu 01 Jan 1970 09:00:02 AM KST

 

반응형

 

 

구성 환경

 

Host OS: Ubuntu

Hypervisor: KVM

VM(Guest): CentOS, Ubuntu, CoreOS 등 (Linux 계열)

 

 

우선 아래의 Web Docs를 보고 설정 및 테스트해보고, 잘 동작하면 여기에 테스트한 내용을 기록할 예정이다.

 

https://help.ubuntu.com/community/KVM%20-%20Using%20Hugepages

 

KVM - Using Hugepages - Community Help Wiki

Introduction The computer memory is divided in pages. The standard page size on most systems is 4KB. To keep track on what information is stored in which page, the system uses a page table. Searching in this page table is (in computer terms) a time costly

help.ubuntu.com

 

 

블로그 작성자: sejong.jeonjo@gmail.com

 

반응형

 

 

Host OS가 Ubuntu 20.04이고, 이 Host에 KVM을 설치했다.

그리고 이 KVM에서 PCI passthrough를 사용하는 방법을 정리해봤다.

 

 

참고: 이론적인 내용은 아래 블로그가 아주 쉽게 설명하고 있다.

https://www.nepirity.com/blog/kvm-gpu-passthrough/

 

KVM 기반의 GPU Passthrough 환경 - 네피리티

KVM 기반의 GPU Passthrough 환경 KVM 기반의 Hypervisor 에서 하드웨어 장치를 직접 Virtual Machine에게 할당하는 PassThrough 를 소개하고 환경 설정 방법에 대해서 설명드리도록 하겠습니다. PCI Passthrough는 NIC,

www.nepirity.com

 

 

 

 

PCI passthrough 사용을 위한 Host OS 설정

 

PCI passthrough를 사용하기 위해 아래 명령과 같이 Host OS를 설정한다.

 

##
## Grub 설정
##

$  cat /etc/default/grub

... 중간 생략 ...

GRUB_CMDLINE_LINUX_DEFAULT="quiet splash intel_iommu=on intel_iommu=igfx_off iommu=pt vfio-pci.ids=8086:1572"

... 중간 생략 ...

$  reboot

...
...
...


##
## Host OS가 Booting 되면, 아래와 같이 PCI에 관한 로그를 확인한다. "iommu=pt" 설정 확인
##

$  dmesg | grep -i vfio
[    0.000000] Command line: BOOT_IMAGE=/vmlinuz-5.4.0-94-generic root=UUID=7824a9ea-e59b-4796-9e23-75e3d909a001 ro quiet splash intel_iommu=on intel_iommu=igfx_off iommu=pt vfio-pci.ids=8086:1572 vt.handoff=7
[    4.136218] Kernel command line: BOOT_IMAGE=/vmlinuz-5.4.0-94-generic root=UUID=7824a9ea-e59b-4796-9e23-75e3d909a001 ro quiet splash intel_iommu=on intel_iommu=igfx_off iommu=pt vfio-pci.ids=8086:1572 vt.handoff=7
[   10.734658] VFIO - User Level meta-driver version: 0.3
[   10.814142] vfio_pci: add [8086:1572[ffffffff:ffffffff]] class 0x000000/00000000

...
...
...


$  lspci -k

... 중간 생략 ...

12:00.0 Ethernet controller: Intel Corporation Ethernet Controller X710 for 10GbE SFP+ (rev 02)
        Subsystem: Hewlett-Packard Company Ethernet 10Gb 2-port 562SFP+ Adapter
        Kernel driver in use: vfio-pci
        Kernel modules: i40e
12:00.1 Ethernet controller: Intel Corporation Ethernet Controller X710 for 10GbE SFP+ (rev 02)
        Subsystem: Hewlett-Packard Company Ethernet 10Gb 562SFP+ Adapter
        Kernel driver in use: vfio-pci
        Kernel modules: i40e

... 중간 생략 ...

$

 

 

PCI passthrough 사용을 위한 KVM 설정

 

##
## PCI passthrough할 NIC이 x710 드라이버를 사용한다고 가정하고
## 아래 설정 절차를 진행했다.
##

$  lspci | grep -i x710
12:00.0 Ethernet controller: Intel Corporation Ethernet Controller X710 for 10GbE SFP+ (rev 02)
12:00.1 Ethernet controller: Intel Corporation Ethernet Controller X710 for 10GbE SFP+ (rev 02)
af:00.0 Ethernet controller: Intel Corporation Ethernet Controller X710 for 10GbE SFP+ (rev 02)
af:00.1 Ethernet controller: Intel Corporation Ethernet Controller X710 for 10GbE SFP+ (rev 02)
$

##
## 위 출력된 내용 중에서 왼쪽 컬럼의 
##  12:00.0 
##  12:00.1
##  af:00.0
##  af:00.1
## 이 값을 이용하여 아래와 같이 KVM이 관리하는 device list를 확인한다.
##
##  참고:
##    nodedev-list로 출력된 device들은 모든 VM에서 공유해서 사용하는 device이므로
##    특정 VM에서 PCI device를 독점적으로 점유하려면, 아래 device를 KVM에서 detach하고
##    특정 VM의 HW에 아래 PCI device를 추가해주어야 PCI passthrough 효과를 얻을 수 있다.
##

$  virsh nodedev-list | grep 12_00
pci_0000_12_00_0
pci_0000_12_00_1
$  virsh nodedev-list | grep af_00
pci_0000_af_00_0
pci_0000_af_00_1
$

##
## PCI 슬롯 번호로 host에 등록된 PCI장비의 이름을 확인후 이 이름을 바탕으로 device 상제 정보를 확인한다.
## 아래 출력 내용 중에서 bus, slot, function 번호 확인 => KVM에서 VM의 device 추가할 때 필요하다.
##



root@bmt:~# virsh nodedev-dumpxml pci_0000_12_00_0
<device>
  <name>pci_0000_12_00_0</name>
  <path>/sys/devices/pci0000:11/0000:11:00.0/0000:12:00.0</path>
  <parent>pci_0000_11_00_0</parent>
  <driver>
    <name>vfio-pci</name>
  </driver>
  <capability type='pci'>
    <class>0x020000</class>
    <domain>0</domain>
    <bus>18</bus>
    <slot>0</slot>
    <function>0</function>
    <product id='0x1572'>Ethernet Controller X710 for 10GbE SFP+</product>
    <vendor id='0x8086'>Intel Corporation</vendor>
    <capability type='virt_functions' maxCount='64'/>
    <iommuGroup number='38'>
      <address domain='0x0000' bus='0x12' slot='0x00' function='0x0'/>
    </iommuGroup>
    <numa node='0'/>
    <pci-express>
      <link validity='cap' port='0' speed='8' width='8'/>
      <link validity='sta' speed='8' width='8'/>
    </pci-express>
  </capability>
</device>


root@bmt:~# virsh nodedev-dumpxml pci_0000_12_00_1
<device>
  <name>pci_0000_12_00_1</name>
  <path>/sys/devices/pci0000:11/0000:11:00.0/0000:12:00.1</path>
  <parent>pci_0000_11_00_0</parent>
  <driver>
    <name>vfio-pci</name>
  </driver>
  <capability type='pci'>
    <class>0x020000</class>
    <domain>0</domain>
    <bus>18</bus>
    <slot>0</slot>
    <function>1</function>
    <product id='0x1572'>Ethernet Controller X710 for 10GbE SFP+</product>
    <vendor id='0x8086'>Intel Corporation</vendor>
    <capability type='virt_functions' maxCount='64'/>
    <iommuGroup number='39'>
      <address domain='0x0000' bus='0x12' slot='0x00' function='0x1'/>
    </iommuGroup>
    <numa node='0'/>
    <pci-express>
      <link validity='cap' port='0' speed='8' width='8'/>
      <link validity='sta' speed='8' width='8'/>
    </pci-express>
  </capability>
</device>


root@bmt:~# virsh nodedev-dumpxml pci_0000_af_00_0
<device>
  <name>pci_0000_af_00_0</name>
  <path>/sys/devices/pci0000:ae/0000:ae:00.0/0000:af:00.0</path>
  <parent>pci_0000_ae_00_0</parent>
  <driver>
    <name>vfio-pci</name>
  </driver>
  <capability type='pci'>
    <class>0x020000</class>
    <domain>0</domain>
    <bus>175</bus>
    <slot>0</slot>
    <function>0</function>
    <product id='0x1572'>Ethernet Controller X710 for 10GbE SFP+</product>
    <vendor id='0x8086'>Intel Corporation</vendor>
    <capability type='virt_functions' maxCount='64'/>
    <iommuGroup number='151'>
      <address domain='0x0000' bus='0xaf' slot='0x00' function='0x0'/>
    </iommuGroup>
    <pci-express>
      <link validity='cap' port='0' speed='8' width='8'/>
      <link validity='sta' speed='8' width='8'/>
    </pci-express>
  </capability>
</device>


root@bmt:~# virsh nodedev-dumpxml pci_0000_af_00_1
<device>
  <name>pci_0000_af_00_1</name>
  <path>/sys/devices/pci0000:ae/0000:ae:00.0/0000:af:00.1</path>
  <parent>pci_0000_ae_00_0</parent>
  <driver>
    <name>vfio-pci</name>
  </driver>
  <capability type='pci'>
    <class>0x020000</class>
    <domain>0</domain>
    <bus>175</bus>
    <slot>0</slot>
    <function>1</function>
    <product id='0x1572'>Ethernet Controller X710 for 10GbE SFP+</product>
    <vendor id='0x8086'>Intel Corporation</vendor>
    <capability type='virt_functions' maxCount='64'/>
    <iommuGroup number='152'>
      <address domain='0x0000' bus='0xaf' slot='0x00' function='0x1'/>
    </iommuGroup>
    <pci-express>
      <link validity='cap' port='0' speed='8' width='8'/>
      <link validity='sta' speed='8' width='8'/>
    </pci-express>
  </capability>
</device>


##
## Host에서 위의 PCI Device를 detach한다.
##   참고: Host에 Attach된 nodedev는 VM에 Mount가 불가능하여 Detach해야 한다.
##        즉, 특정 VM에서만 위 PCI 장치를 전용해서 사용해야 하기 때문에
##        다수의 VM이 위 PCI 장비를 공유하지 못하도록 싹을 뽑아 버린다고 생각하면 된다.
##

$  virsh nodedev-detach pci_0000_12_00_0
Device pci_0000_12_00_0 detached

$  virsh nodedev-detach pci_0000_12_00_1
Device pci_0000_12_00_1 detached

 

위와 같이 KVM에서 Host 머신의 PCI 장치를 Detach했으면, 아래 KVM Virtual Manager 화면에서

특정 Virtual Machine 의 설정 화면을 열어본다.

그리고 이 Virtual Machine에 PCI Device를 추가한다. (아래 화면의 설정 순서를 따라할 것!!!) 

 

 

KVM Virt-Manager 에서 특정 VM의 HW 설정

 

위 설정 화면에서 [Finish] 버튼을 누르면, 아래 화면처럼 새로 추가한 PCI 장치 정보를 볼 수 있다.

 

 

VM의 HW 목록 및 설정 정보를 확인

 

 

 

위와 같이 Virtual Machine이 설정된 후에 VM 내부에서는 SR-IOV 구성까지 해야 NIC에 여러 VF를 생성하고, Application Process가 VF를 사용할 수 있을 것이다. (이후 과정에 나중에 테스트하면서 다시 기록할 생각이다) 

 

 

+ Recent posts