နားလည်ထားရမယ့် အချက်
Host တိုင်းမှာ address တစ်ခုစီ hardcode လုပ်ထားတဲ့နည်းက လက်တွေ့မှာ မခံပါဘူး။ Network တွေ renumber လုပ်ရတယ်၊ laptop တွေက subnet တစ်ခုကနေ တစ်ခုကို ရွှေ့သွားတယ်၊ ပြီးတော့ လူနှစ်ယောက်က machine နှစ်လုံးမှာ address တူတူ ရိုက်ထည့်လိုက်ရင် application layer ကနေ ဘယ်သူမှ debug လုပ်လို့ မရတဲ့ conflict တစ်ခု ဖြစ်လာတယ်။ DHCP က address ခွဲဝေမှုကို network ကိုယ်တိုင်ဆီ ရွှေ့လိုက်တာမို့ host တစ်ခုဟာ ဘာမှမသိဘဲ ရောက်လာပြီး configure ပြီးသား ဖြစ်သွားတယ်။
အဲဒီ exchange ကို DORA လို့ ခေါ်တယ်။ Client မှာ IP မရှိသေးလို့ ဘယ်သူ့ကိုမှ တိုက်ရိုက် address လုပ်လို့ မရသေးတဲ့အတွက် DISCOVER ကို broadcast လုပ်တယ်။ Segment ပေါ်က DHCP server မှန်သမျှက address တစ်ခုကို OFFER နဲ့ ပြန်ဖြေနိုင်တယ်။ Client က တစ်ခုကို ရွေးပြီး REQUEST ပို့တယ် — ဒီနေရာမှာပဲ လူတွေ အံ့သြတတ်တယ် — REQUEST ဟာ unicast မဟုတ်ဘဲ broadcast ဖြစ်တယ်၊ client က ဘယ် server ကို လိုချင်လဲ အတိအကျ သိနေပြီးသားတောင်မှ။ Broadcast လုပ်ရတဲ့ အကြောင်းရင်းက offer တွေ အများကြီး ရှိခဲ့နိုင်လို့ပါပဲ။ Segment ပေါ်က server တိုင်းက REQUEST ကို ကြားရပြီး ဘယ်သူ့ address ကို ရွေးလိုက်လဲ မြင်ရတယ်၊ ပြီးတော့ မရွေးခံရသူတွေက သူတို့ ယာယီ ဖယ်ထားခဲ့တဲ့ address တွေကို ပြန်လွှတ်ပေးတယ်။ Unicast REQUEST ဆိုရင် ကျန် server တွေဟာ timeout မဖြစ်မချင်း တစ္ဆေ reservation တွေကို ကိုင်ထားပြီး pool တွေကို တိတ်တဆိတ် ခန်းခြောက်စေမယ်။ နောက်ဆုံးမှာ ရွေးခံရတဲ့ server က ACK ပို့တယ်၊ ဒါက lease ကို တကယ် အသက်ဝင်စေတဲ့ အဆင့် ဖြစ်တယ်။
Lease ဆိုတာ အချိန်ကန့်သတ်ချက်တစ်ခု ဖြစ်ပြီး လက်ဆောင် မဟုတ်ဘူး။ T1 — lease ရဲ့ ၅၀ ရာခိုင်နှုန်း — မှာ client က သူ့ကိုယ်ပိုင် server ဆီ renewal ကို unicast ပို့တယ်။ မအောင်မြင်ရင် T2 — ၈၇.၅ ရာခိုင်နှုန်း — မှာ အဲဒီ server ကို လက်လျှော့ပြီး မည်သူမဆိုဆီ rebind ကို broadcast လုပ်တယ်။ နှစ်ခုလုံး ကျရှုံးမှသာ address ကို စွန့်လွှတ်တယ်။
ပြီးတော့ address တစ်ခုတည်းက အသုံးမဝင်ဘူး။ ဒီ exchange အတွင်းမှာပဲ subnet mask, default gateway နဲ့ DNS resolver တွေကိုပါ သယ်ဆောင်လာတယ်။ Host တစ်ခုမှာ IP ရှိပေမယ့် ဘာမှ မရောက်ဘူးဆိုရင် DHCP ပေးထားတဲ့ gateway မှားနေတာက address မှားနေတာထက် များစွာ ဖြစ်နိုင်ခြေ ပိုများတယ်။
THE DORA EXCHANGE WITH TWO SERVERS
----------------------------------
Client (no IP yet) Server A Server B
| | |
|--D-- DISCOVER (bcast) -->| |
|--D-- same broadcast -----|------------------>|
| | |
|<-O-- OFFER .100 ---------| |
|<-O-- OFFER .240 ---------|-------------------|
| | |
| [ client picks A's offer ] |
| | |
|--R-- REQUEST .100 ------>| |
|--R-- ...still a BROADCAST|------------------>|
| | |
| | B hears it lost |
| | and returns |
| | .240 to its pool|
| | |
|<-A-- ACK .100 + mask ----| |
| + gateway + DNS | |
v v v
Why is REQUEST a broadcast?
So the LOSING servers learn they lost. Unicast would leave
B holding a phantom reservation on .240 until it timed out.
Lease timers (lease = 3600s):
T1 = 50% = 1800s renew unicast to Server A
T2 = 87.5% = 3150s rebind broadcast to anyone
T = 100% = 3600s address released, back to DISCOVERလက်တွေ့ scenario နဲ့ ချိတ်ကြည့်မယ်
အဖြစ်များတဲ့ support ticket တစ်ခု — 'ရုံးထဲက လူတချို့ internet မရဘူး၊ တချို့ကတော့ ရတယ်၊ ပြီးတော့ မနက်တိုင်း ပြောင်းနေတယ်' ။ ဒီလို ရံဖန်ရံခါ ဖြစ်တဲ့ pattern ဟာ access point ချွတ်ယွင်းနေတာရဲ့ လက္ခဏာ မဟုတ်ဘဲ pool သေးလွန်းနေတာရဲ့ လက္ခဏာ ဖြစ်တယ်။
ဒီလို လုပ်ပါ။ ပထမ၊ ထိခိုက်ခံရတဲ့ machine မှာ address တစ်ခုများ ရှိရဲ့လား စစ်ပါ။ Windows မှာ 169.254.x.x address ဒါမှမဟုတ် Linux မှာ address လုံးဝ မရှိခြင်းက DISCOVER ဟာ အသုံးဝင်တဲ့ OFFER တစ်ခုမှ မရခဲ့ဘူးလို့ ဆိုလိုတယ် — client က ခေါ်နေပေမယ့် ဘယ်သူမှ မဖြေဘူး — ဒါက pool ကုန်နေတာ ဒါမှမဟုတ် DHCP relay က router boundary ကို ဖြတ်ပြီး broadcast မလွှင့်ပေးနေတာ ဖြစ်တယ်။ Broadcast တွေက router ကို မဖြတ်နိုင်လို့ server နဲ့ VLAN မတူတဲ့ client တစ်ခုအတွက် relay agent တစ်ခု လိုအပ်တယ်၊ ပြီးတော့ ဒါကို မေ့ကျန်ခြင်းဟာ 'DHCP က ထပ်ခိုးတစ်ခုမှာ ရပြီး နောက်တစ်ခုမှာ မရဘူး' ရဲ့ classic အကြောင်းရင်း ဖြစ်တယ်။
ဒုတိယ၊ lease time ကို device အရေအတွက်နဲ့ ယှဉ်ကြည့်ပါ။ Usable address ၁၀၀ ရှိတဲ့ /24 တစ်ခုနဲ့ ၈ နာရီ lease တစ်ခုဟာ လူ ၁၀၀ ကို ဝန်ဆောင်မှုပေးနိုင်တာထက် အများကြီး နည်းတယ် — phone တွေက associate လုပ်၊ lease ယူ၊ ပြီးရင် ထွက်သွားကြတယ် — အဲဒီ device တစ်ခုစီက ထွက်သွားပြီးနောက် ၈ နာရီ ကြာအောင် address တစ်ခုကို ကိုင်ထားတယ်။ Guest network တစ်ခုမှာ lease ကို တိုစေခြင်းဟာ များသောအားဖြင့် ဖြေရှင်းချက် တစ်ခုလုံး ဖြစ်တယ်။
အောက်က simulation က ဒါကို လက်တွေ့ ပြပေးတယ် — address လေးခု pool, client ငါးယောက်, ပြီးတော့ lease တစ်ခု သက်တမ်းကုန်တဲ့ အခိုက်မှာ အဲဒီ address ဟာ ငြင်းပယ်ခံရတဲ့ client ဆီ ပြန်ရောက်သွားတယ်။
အတူတူ စမ်းရေးကြည့်မယ်
import ipaddress
# A small DHCP scope, the kind a home router or a lab VLAN would have.
POOL_START = ipaddress.IPv4Address("192.168.10.100")
POOL_END = ipaddress.IPv4Address("192.168.10.103") # deliberately tiny
LEASE_SECONDS = 3600
# Everything DHCP hands over BESIDES the address. Forgetting that these
# come from DHCP too is why a "wrong gateway" bug looks like a DNS bug.
OPTIONS = {
"subnet_mask": "255.255.255.0",
"router": "192.168.10.1",
"dns": "192.168.10.1, 1.1.1.1",
}
class Scope:
def __init__(self, start, end):
self.addresses = [ipaddress.IPv4Address(int(start) + i)
for i in range(int(end) - int(start) + 1)]
self.leases = {} # address -> (mac, expires_at)
def free(self, now):
taken = {a for a, (_, exp) in self.leases.items() if exp > now}
return [a for a in self.addresses if a not in taken]
def offer(self, mac, now):
# Same client asking again gets the SAME address back if it can.
for addr, (owner, exp) in self.leases.items():
if owner == mac and exp > now:
return addr
available = self.free(now)
return available[0] if available else None
def ack(self, mac, addr, now):
self.leases[addr] = (mac, now + LEASE_SECONDS)
return now + LEASE_SECONDS
scope = Scope(POOL_START, POOL_END)
CLOCK = 0 # hardcoded virtual clock in seconds; no wall-clock calls
clients = ["aa:00:01", "aa:00:02", "aa:00:03", "aa:00:04", "aa:00:05"]
print("scope 192.168.10.100-192.168.10.103 lease " +
str(LEASE_SECONDS) + "s")
print("")
for mac in clients:
offered = scope.offer(mac, CLOCK)
if offered is None:
print(mac + " DISCOVER -> no OFFER (pool exhausted)")
continue
expires = scope.ack(mac, offered, CLOCK)
print(mac + " DISCOVER -> OFFER " + str(offered) +
" -> REQUEST -> ACK expires t=" + str(expires))
print("")
print("gateway=" + OPTIONS["router"] + " mask=" + OPTIONS["subnet_mask"])
print("dns=" + OPTIONS["dns"])
print("")
# T1 is 50% of the lease: the client unicasts a renewal to its server.
# T2 is 87.5%: it gives up on that server and broadcasts to anyone.
print("T1 (renew, unicast) at t=" + str(LEASE_SECONDS // 2))
print("T2 (rebind, bcast) at t=" + str(LEASE_SECONDS * 7 // 8))
print("")
# Now let the first lease expire and watch the address get recycled.
CLOCK = 4000
print("at t=" + str(CLOCK) + " free addresses: " +
str(len(scope.free(CLOCK))))
print("aa:00:05 DISCOVER -> OFFER " + str(scope.offer("aa:00:05", CLOCK)))scope 192.168.10.100-192.168.10.103 lease 3600s
aa:00:01 DISCOVER -> OFFER 192.168.10.100 -> REQUEST -> ACK expires t=3600
aa:00:02 DISCOVER -> OFFER 192.168.10.101 -> REQUEST -> ACK expires t=3600
aa:00:03 DISCOVER -> OFFER 192.168.10.102 -> REQUEST -> ACK expires t=3600
aa:00:04 DISCOVER -> OFFER 192.168.10.103 -> REQUEST -> ACK expires t=3600
aa:00:05 DISCOVER -> no OFFER (pool exhausted)
gateway=192.168.10.1 mask=255.255.255.0
dns=192.168.10.1, 1.1.1.1
T1 (renew, unicast) at t=1800
T2 (rebind, bcast) at t=3150
at t=4000 free addresses: 4
aa:00:05 DISCOVER -> OFFER 192.168.10.100၅ မိနစ် စမ်းကြည့်
LEASE_SECONDS ကို 600 လို့ ပြောင်းပြီး ဒုတိယ CLOCK ကို 700 လို့ ပြောင်းကြည့်ပါ — client ငါးယောက်လုံး address ရသွားလား? ပြီးရင် client တစ်ယောက်တည်းက DISCOVER နှစ်ကြိမ် ပို့တဲ့အခါ address တူတူ ပြန်ရမလား စမ်းကြည့်ပြီး၊ ဒီ 'sticky' အပြုအမူဟာ ဘာကြောင့် အသုံးဝင်လဲ ရှင်းပြပါ။
သတိလေးတစ်ချက်
DHCP က router ကို ဖြတ်ပြီး အလုပ်လုပ်မယ်လို့ မျှော်လင့်ခြင်း — DISCOVER က broadcast ဖြစ်လို့ server နဲ့ subnet မတူတဲ့ client တစ်ခုအတွက် relay agent တစ်ခု လိုအပ်တယ်။
Pool size ကို လူဦးရေနဲ့ တွက်ခြင်း — device အရေအတွက်နဲ့ lease length နဲ့ တွက်ရမယ်၊ ခဏတာ associate လုပ်သွားတဲ့ phone တွေက ထွက်သွားပြီးတောင် lease တစ်ခုလုံး address ကို ကိုင်ထားတယ်။
RFC 2131 - Dynamic Host Configuration Protocol — Computer Networking