[CS300 #142] 물리 계층과 이더넷 — 비트가 선을 타고 프레임이 되기까지
컴퓨터공학 300 주제 시리즈의 142번째 글이다. 전체 지도는 여기.
한 줄 요약
물리 계층은 비트를 전기·빛·전파 신호로 바꿔 보내고, 이더넷은 그 비트들을 “누가 누구에게 보내는 몇 바이트짜리 덩어리”인 프레임으로 묶는다.
왜 필요한가
상위 계층 장애처럼 보이는 문제의 상당수가 아래에서 시작한다. 케이블 불량으로 CRC 오류가 쌓이면 TCP 는 재전송을 반복하고, 응용에서는 “가끔 느리다”로만 보인다. 링크 속도가 협상에 실패해 1Gb/s 포트가 100Mb/s 로 붙어 있으면 백업이 열 배 느려진다. 이런 문제는 앱 로그를 아무리 봐도 안 보인다. 프레임 구조와 링크 상태를 읽을 줄 알아야 보인다.
핵심 개념
물리 계층이 하는 일
물리 계층은 비트 0 과 1 을 매체에 맞는 신호로 바꾼다. 결정할 것은 대략 다음과 같다.
- 매체: 구리 꼬임쌍선(UTP), 광섬유, 무선.
- 부호화(line coding): 비트를 전압 레벨이나 빛의 세기 패턴으로 바꾸는 규칙. 수신 쪽이 클럭을 복원할 수 있도록 0·1 이 너무 오래 같은 값으로 이어지지 않게 설계한다.
- 속도와 이중 방식: 반이중(half-duplex)은 한 번에 한쪽만, 전이중(full-duplex)은 양방향 동시 송수신이다.
- 자동 협상(auto-negotiation): 두 장비가 링크를 올릴 때 서로 지원하는 속도와 이중 방식을 맞춘다.
이더넷 표준(IEEE 802.3)은 물리 계층과 데이터 링크 계층의 MAC 부분을 함께 정의한다. 그래서 “이더넷”은 케이블 규격 이름이기도 하고 프레임 형식 이름이기도 하다.
이더넷 프레임 구조
| 프리앰블 7 | SFD 1 | 목적지 MAC 6 | 출발지 MAC 6 | EtherType/길이 2 | 페이로드 46~1500 | FCS 4 |
<-- 물리 계층이 붙이는 동기 신호 --> <-------------- 흔히 "프레임"이라 부르는 부분 ------------------->
- 프리앰블과 SFD(Start Frame Delimiter)는 수신 쪽이 비트 동기를 잡고 프레임 시작을 알아채는 데 쓴다.
- 목적지 MAC 이 먼저 온다. 스위치가 6바이트만 읽고 바로 전달 방향을 정할 수 있게 한 배치다.
- EtherType/길이 필드는 값이 0x0600(1536) 이상이면 상위 프로토콜 종류(EtherType), 1500 이하이면 페이로드 길이로 해석한다. 오늘날 IP 트래픽은 거의 모두 EtherType 방식(RFC 894 가 정한 “Ethernet II” 형식)을 쓴다. 대표 값은 IPv4 0x0800, ARP 0x0806, IPv6 0x86DD, VLAN 태그 0x8100 이다.
- 페이로드 최소 46바이트: 짧으면 패딩을 채운다. 그래서 목적지 MAC 부터 FCS 까지 최소 64바이트가 된다.
- 페이로드 최대 1500바이트: 이것이 이더넷 MTU 다. 헤더 14 + 1500 + FCS 4 = 1518바이트가 VLAN 태그 없는 최대 프레임이다. 802.1Q VLAN 태그가 붙으면 4바이트 늘어난다.
- FCS(Frame Check Sequence)는 CRC-32 값이다. 수신 쪽이 다시 계산해 다르면 프레임을 조용히 버린다. 이더넷은 오류를 고치지 않는다. 재전송은 TCP 같은 상위 계층 몫이다.
공유 매체에서 스위치로
초기 이더넷은 동축 케이블 하나를 여럿이 나눠 썼다. 동시에 보내면 신호가 충돌하므로 CSMA/CD(먼저 듣고, 충돌을 감지하면 무작위로 기다렸다 재시도)를 썼다. 최소 프레임 크기 64바이트도 “충돌이 생기면 송신이 끝나기 전에 알아챌 수 있도록” 정한 값이다.
오늘날 유선 이더넷은 대부분 스위치에 일대일로 연결된 전이중 링크다. 송신과 수신 경로가 분리되어 있으니 충돌 자체가 없고, CSMA/CD 는 사실상 쓰이지 않는다. 다만 프레임 형식과 최소·최대 크기는 호환을 위해 그대로 남았다.
스위치는 들어오는 프레임의 출발지 MAC 을 보고 “이 주소는 이 포트 뒤에 있다”를 표로 배운다(MAC 학습). 목적지 MAC 이 표에 있으면 그 포트로만 보내고, 없거나 브로드캐스트면 모든 포트로 뿌린다(flooding).
오버헤드 계산
선 위에는 프레임 말고도 프리앰블+SFD 8바이트와 프레임 사이 최소 간격(IFG) 12바이트에 해당하는 시간이 더 쓰인다. 그래서 작은 패킷을 많이 보내면 실제 유효 처리량이 크게 떨어진다.
직접 해 보기
프레임을 만들고 FCS 를 붙인 뒤, 페이로드 크기별 효율을 계산해 보자. 이더넷의 CRC-32 는 zlib 이 쓰는 CRC-32 와 같은 다항식이다. MAC 은 문서용 주소(RFC 7042)를 쓴다.
import struct, zlib
def build_frame(dst, src, ethertype, payload):
if len(payload) < 46: # 최소 페이로드 패딩
payload = payload + b"\x00" * (46 - len(payload))
hdr = bytes.fromhex(dst) + bytes.fromhex(src) + struct.pack("!H", ethertype)
body = hdr + payload
fcs = struct.pack("<I", zlib.crc32(body)) # 이더넷은 FCS 를 하위 바이트부터 보낸다
return body + fcs
def check_frame(frame):
body, fcs = frame[:-4], frame[-4:]
return struct.pack("<I", zlib.crc32(body)) == fcs
f = build_frame("00005e005302", "00005e005301", 0x0800, b"hello")
print("프레임 길이:", len(f)) # 64
print("FCS 정상:", check_frame(f))
broken = bytearray(f); broken[20] ^= 0x01 # 비트 하나 뒤집기
print("비트 1개 손상 후 FCS 정상:", check_frame(bytes(broken)))
# 선 위의 효율: 프리앰블+SFD 8 + IFG 12 바이트까지 포함
for p in (46, 512, 1500):
on_wire = 14 + p + 4 + 8 + 12
print(f"페이로드 {p:4d}B -> 효율 {p / on_wire * 100:5.1f}%")
# 1Gb/s 에서 최소 프레임을 최대로 보낼 때의 초당 프레임 수
print("1Gb/s 최소 프레임 pps:", round(1e9 / ((64 + 20) * 8)))
프레임 길이: 64
FCS 정상: True
비트 1개 손상 후 FCS 정상: False
페이로드 46B -> 효율 54.8%
페이로드 512B -> 효율 93.1%
페이로드 1500B -> 효율 97.5%
1Gb/s 최소 프레임 pps: 1488095
5바이트 “hello” 가 64바이트 프레임이 됐다. 그리고 작은 패킷만 보내면 회선의 절반 가까이가 헤더와 간격에 쓰인다. 1Gb/s 링크에서 최소 크기 프레임은 초당 약 149만 개가 한계다. 네트워크 장비 사양서의 “pps” 수치가 중요한 이유다.
현업에서는
- 리눅스에서
ethtool <인터페이스>로 협상된 속도와 이중 방식을,ethtool -S나ip -s link로 CRC 오류·드롭 카운터를 본다. CRC 오류가 늘고 있다면 케이블·커넥터·포트부터 바꿔 본다. - 오래된 노트북을 홈랩 노드로 쓰면 내장 NIC 가 100Mb/s 짜리인 경우가 있다. 노드 간 복제나 이미지 풀이 유난히 느리면 링크 속도부터 확인한다.
- 오버레이 네트워크(VXLAN 등)나 VPN 을 쓰면 캡슐화 헤더만큼 MTU 가 줄어든다. 1500 을 그대로 두면 큰 패킷만 사라지는 이상한 장애가 난다. 이 이야기는 158번 글(VPN 과 터널링)에서 다시 다룬다.
- 데이터센터에서는 MTU 를 9000바이트 안팎으로 키운 점보 프레임을 쓰기도 한다. 경로 위 모든 장비가 같은 값을 지원해야 한다.
확인 문제
- EtherType/길이 필드 값이 0x86DD 이면 수신 쪽은 이것을 어떻게 해석하는가?
- 이더넷 프레임의 최소 크기가 64바이트인 이유를 CSMA/CD 와 연결해 설명하라.
- FCS 검사에 실패한 프레임은 어떻게 처리되는가? 재전송은 누가 하는가?
- 스위치가 처음 보는 목적지 MAC 으로 가는 프레임을 받으면 어떻게 하는가?
- 페이로드가 1500바이트일 때 선 위 효율이 100%가 아닌 이유 세 가지를 들라.
풀이
- 0x0600 이상이므로 EtherType 으로 해석하고, 0x86DD 는 IPv6 이므로 페이로드를 IPv6 패킷으로 넘긴다.
- 반이중 공유 매체에서 송신자가 프레임을 다 보내기 전에 충돌을 감지할 수 있어야 했기 때문에, 최소 송신 시간을 보장하도록 최소 크기를 정했다.
- 조용히 버린다. 이더넷은 재전송하지 않으며, 필요하면 TCP 같은 상위 계층이 재전송한다.
- 들어온 포트를 뺀 모든 포트로 내보낸다(flooding). 이후 응답 프레임의 출발지 MAC 을 보고 위치를 학습한다.
- 이더넷 헤더 14바이트, FCS 4바이트, 프리앰블+SFD 8바이트, 프레임 간 간격 12바이트가 추가로 선을 점유하기 때문이다.
더 읽을거리 (References)
- IEEE Std 802.3, IEEE Standard for Ethernet (서지 정보)
- RFC 894, A Standard for the Transmission of IP Datagrams over Ethernet Networks: https://www.rfc-editor.org/rfc/rfc894.html
- IANA, IEEE 802 Numbers (EtherType 목록): https://www.iana.org/assignments/ieee-802-numbers/ieee-802-numbers.xhtml
- ethtool(8) 매뉴얼: https://manpages.debian.org/bookworm/ethtool/ethtool.8.en.html