Hi, A bug fix, performance improvement and a new feature for pppoe(8); and a performance improvement for ppp(8).
pppoe(8): - Under load my low power atom-based router kept hitting the "usleep(100000);" case in pppoe which seemed to throw LCP echos off causing line drops, this is now gone and the line doesn't drop. - select() replaced for kqueue()/kevent() calls in pppoe's client loop. - RFC 4638 support added to pppoe's client mode for negotiating 1500 byte mtu with the server. ppp(8) - A very quick and dirty drop-in kqueue()/kevent() replacement for select() in the main loop. It works for me, works well with the above pppoe mods, you'll flame. Suggestions would be welcome. Can anyone test this with dialup? Some background for these changes: Faster broadband got rolled out here; all was working on ADSL 2+ (with random but tolerable line drops during bittorrent downloads). Upgraded to VDSL (here in the UK BT are rolling out fibre to a roadside cabinet...) which is provided as a PPPoE mode. Line now drops were happening under normal usage so I investigated... Once all that was fixed I thought I'd add support for the larger MTU. I probably wouldn't have needed to rewrite the select() calls as kqueue()/kevent() if I had a faster computer acting as a router. pppoe(4) seems to cause panics and wasn't setting up IPv6 properly for me - sorry I've not investigated that further. Diffs and dmesg follow. -- ben diff -r pppoe/client.c pppoe.kqueue/client.c 49a50 > #include <sys/event.h> 58a60 > u_int16_t nego_mtu_pado, nego_mtu_pads; 83,84c85,92 < fd_set *fdsp = NULL; < int r = 0, max, oldmax = 0; --- > int kq = -1; > int r = 0; > int nchanges = 0; > struct kevent eventlist[2]; > int pppfd_set = 0; > int bfd_idx = -1; > int pppfd_idx = -1; > int i = 0; 85a94,100 > kq = kqueue(); > if (kq < 0) > return -1; > > EV_SET(eventlist + nchanges, bfd, EVFILT_READ, EV_ADD, 0, 0, NULL); > ++nchanges; > 88a104 > nego_mtu_pado = nego_mtu_pads = PPPOE_MTU; 91c107,108 < if (r <= 0) --- > if (r <= 0) { > close(kq); 92a110 > } 95,107c113,119 < max = bfd; < if (pppfd >= 0 && pppfd >= max) < max = pppfd; < max++; < < if (max > oldmax) { < if (fdsp != NULL) < free(fdsp); < fdsp = (fd_set *)calloc(howmany(max, NFDBITS), < sizeof(fd_mask)); < if (fdsp == NULL) { < r = -1; < break; --- > if (pppfd < 0) { > pppfd_set = 0; > } else { > if (!pppfd_set) { > EV_SET(eventlist + nchanges, pppfd, > EVFILT_READ, EV_ADD, 0, 0, NULL); > ++nchanges; > pppfd_set = 1; 109d120 < oldmax = max; 111d121 < bzero(fdsp, howmany(max, NFDBITS) * sizeof(fd_mask)); 113,115c123,129 < if (pppfd >= 0) < FD_SET(pppfd, fdsp); < FD_SET(bfd, fdsp); --- > r = kevent(kq, eventlist, nchanges, eventlist, 2, NULL); > nchanges = 0; > if (r <= 0) { > if (timer_hit()) > timer_clr(); > break; > } 117,122c131,137 < r = select(max, fdsp, NULL, NULL, NULL); < if (r < 0) { < if (errno == EINTR) { < if (timer_hit()) < timer_clr(); < break; --- > bfd_idx = -1; > pppfd_idx = -1; > for (i = 0; i < r; ++i) { > if (eventlist[i].ident == bfd) { > bfd_idx = i; > } else if (eventlist[i].ident == pppfd) { > pppfd_idx = i; 124d138 < break; 126,128c140,144 < if (FD_ISSET(bfd, fdsp)) { < r = getpackets(bfd, srvname, sysname, myea, &rmea); < if (r <= 0) --- > > if (bfd_idx >= 0) { > u_short flags = eventlist[bfd_idx].flags; > if (flags & EV_EOF || flags & EV_ERROR) { > r = -1; 129a146,149 > } > r = getpackets(bfd, srvname, sysname, myea, &rmea); > if (r <= 0) > break; 131,133c151,157 < if (pppfd >= 0 && FD_ISSET(pppfd, fdsp)) { < r = ppp_to_bpf(bfd, pppfd, myea, &rmea, < client_sessionid); --- > if (pppfd >= 0 && pppfd_idx >= 0) { > u_short flags = eventlist[pppfd_idx].flags; > if (flags & EV_EOF || flags & EV_ERROR) { > r = -1; > break; > } > r = ppp_to_bpf(bfd, pppfd, myea, &rmea, > client_sessionid); 144,146c168 < if (fdsp != NULL) < free(fdsp); < --- > close(kq); 153c175 < struct iovec iov[10]; --- > struct iovec iov[12]; 158c180 < struct pppoe_tag thost, tserv; --- > struct pppoe_tag thost, tserv, tmaxpayload; 159a182 > u_int16_t maxpayload; 198a222,234 > /* ppp-max-payload tag (optional) */ > if (rfc_4638_mtu > PPPOE_MTU) { > tmaxpayload.type = htons(PPPOE_TAG_PPP_MAX_PAYLOAD); > tmaxpayload.len = htons(sizeof(maxpayload)); > tmaxpayload.val = (u_int8_t*) &maxpayload; > maxpayload = htons(rfc_4638_mtu); > iov[i].iov_base = &tmaxpayload; > iov[i++].iov_len = sizeof(tmaxpayload.len) + > sizeof(tmaxpayload.type); > iov[i].iov_base = &maxpayload; > iov[i++].iov_len = sizeof(maxpayload); > ph.len += sizeof(tmaxpayload.len) + sizeof(tmaxpayload.type) + > sizeof(maxpayload); > } > 211c247 < struct iovec iov[12]; --- > struct iovec iov[14]; 213c249,250 < struct pppoe_tag hutag, svtag; --- > struct pppoe_tag hutag, svtag, mptag; > u_int16_t maxpayload = htons(nego_mtu_pado); 253a291,301 > /* PPP-Max-Payload */ > if (nego_mtu_pado > PPPOE_MTU) { > mptag.type = htons(PPPOE_TAG_PPP_MAX_PAYLOAD); > mptag.len = htons(sizeof(maxpayload)); > iov[idx].iov_base = &mptag; > iov[idx++].iov_len = sizeof(mptag.type) + sizeof(mptag.len); > iov[idx].iov_base = &maxpayload; > iov[idx++].iov_len = sizeof(maxpayload); > ph->len += sizeof(mptag.type) + sizeof(mptag.len) + > sizeof(maxpayload); > } > 372,373c420 < usleep(100000); < continue; --- > goto next; 415a463,472 > if (rfc_4638_mtu > PPPOE_MTU) { > n = tag_lookup(&tl, PPPOE_TAG_PPP_MAX_PAYLOAD, 0); > if (n != NULL) { > nego_mtu_pado = ntohs(*((u_int16_t*)n->val)); > if (nego_mtu_pado < PPPOE_MTU) { > nego_mtu_pado = PPPOE_MTU; > } > } > } > 470a528,536 > > n = tag_lookup(&tl, PPPOE_TAG_PPP_MAX_PAYLOAD, 0); > if (n != NULL && n->len == sizeof(nego_mtu_pads)) { > nego_mtu_pads = ntohs(*((u_int16_t*)n->val)); > if (nego_mtu_pads < PPPOE_MTU || > nego_mtu_pads > rfc_4638_mtu) { > nego_mtu_pads = PPPOE_MTU; > } > } diff -r pppoe/common.c pppoe.kqueue/common.c 146c146 < pktbuf = (u_int8_t *)malloc(PPPOE_MTU); --- > pktbuf = (u_int8_t *)malloc(rfc_4638_mtu); 154c154 < iov[1].iov_len = PPPOE_MTU; --- > iov[1].iov_len = rfc_4638_mtu; diff -r pppoe/pppoe.8 pppoe.kqueue/pppoe.8 28c28 < .Dd $Mdocdate: November 17 2007 $ --- > .Dd $Mdocdate: March 27 2011 $ 39a40 > .Op Fl m Ar mtu 69a71,78 > .It Fl m Ar mtu > Attempt to negotiate > a higher mtu, using RFC 4638. It is your responsibility to ensure that the > ethernet > .Ar interface > works and is configured with an mtu at least 8 bytes > greater than this value. > This option is only used in client mode. 225a235,239 > .Rs > .%R RFC 4638 > .%T Accommodating a Maximum Transit Unit/Maximum Receive Unit (MTU/MRU) > Greater Than 1492 in the Point-to-Point Protocol over Ethernet (PPPoE) > .%A P. Arberg, et al. > .Re 246a261,263 > is not currently used by the server code. > The > .Ar mtu diff -r pppoe/pppoe.c pppoe.kqueue/pppoe.c 54a55 > u_int16_t rfc_4638_mtu = PPPOE_MTU; 81c82 < while ((c = getopt(argc, argv, "svi:n:p:")) != -1) { --- > while ((c = getopt(argc, argv, "svm:i:n:p:")) != -1) { 113a115,119 > case 'm': > rfc_4638_mtu = (u_int16_t) atoi(optarg); > if (rfc_4638_mtu < PPPOE_MTU) > rfc_4638_mtu = PPPOE_MTU; > break; 127a134,137 > > if (smode) { > rfc_4638_mtu = PPPOE_MTU; > } diff -r pppoe/pppoe.h pppoe.kqueue/pppoe.h 78a79 > #define PPPOE_TAG_PPP_MAX_PAYLOAD 0x0120 /* RFC 4638 PPP-Max-Payload */ 82a84 > extern u_int16_t rfc_4638_mtu; This really is an ugly way of changing this program but actually makes a significant improvement on my low end system: diff -r ppp/ppp/main.c ppp.kqueue/ppp/main.c 50a51,52 > #include <sys/types.h> > #include <sys/event.h> 536,537c538,541 < fd_set *rfds, *wfds, *efds; < int i, nfds, nothing_done; --- > int kq; > struct kevent *changelist, *pevent; > fd_set *rfds, *wfds, *efds; > int i, nfds, nfds_done, nothing_done, x, nchanges, maxnchanges, neret; 539,542c543,546 < if ((rfds = mkfdset()) == NULL) { < log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); < return; < } --- > nfds_done = 0; > nchanges = 0; > maxnchanges = getdtablesize(); > changelist = malloc(maxnchanges * sizeof(struct kevent)); 544,548c548,553 < if ((wfds = mkfdset()) == NULL) { < log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); < free(rfds); < return; < } --- > kq = kqueue(); > if (kq < 0) { > log_Printf(LogERROR, "DoLoop: Cannot create kqueue\n"); > free(changelist); > return; > } 550,555c555,560 < if ((efds = mkfdset()) == NULL) { < log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); < free(rfds); < free(wfds); < return; < } --- > if ((rfds = mkfdset()) == NULL) { > log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); > free(changelist); > close(kq); > return; > } 556a562,578 > if ((wfds = mkfdset()) == NULL) { > log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); > free(changelist); > close(kq); > free(rfds); > return; > } > > if ((efds = mkfdset()) == NULL) { > log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); > free(changelist); > close(kq); > free(rfds); > free(wfds); > return; > } > 573a596,617 > /* Quick and dirty way to convert a complicated use of > * select into a quicker call to kevent(2) > */ > nfds_done = nfds > nfds_done ? nfds : nfds_done; > for (x = 0; x < nfds; ++x) { > int r = 0, w = 0; > if (FD_ISSET(x, rfds)) { > EV_SET(changelist + nchanges, x, EVFILT_READ, > EV_ADD|EV_ONESHOT, 0, 0, 0); > ++nchanges; > r = 1; > } > if (FD_ISSET(x, wfds)) { > EV_SET(changelist + nchanges, x, EVFILT_WRITE, > EV_ADD|EV_ONESHOT, 0, 0, 0); > ++nchanges; > w = 1; > } > if (!r && !w && FD_ISSET(x, efds)) { > EV_SET(changelist + nchanges, x, EVFILT_READ, > EV_ADD|EV_ONESHOT, 0, 0, 0); > ++nchanges; > } > } > 585c629,630 < i = select(nfds, rfds, wfds, efds, NULL); --- > i = neret = kevent(kq, changelist, nchanges, changelist, maxnchanges, > NULL); > nchanges = 0; 587,590c632,635 < if (i < 0 && errno != EINTR) { < log_Printf(LogERROR, "DoLoop: select(): %s\n", strerror(errno)); < if (log_IsKept(LogTIMER)) { < struct timeval t; --- > if (i < 0 && errno != EINTR) { > log_Printf(LogERROR, "DoLoop: select(): %s\n", strerror(errno)); > break; > } 592,623c637,653 < for (i = 0; i <= nfds; i++) { < if (FD_ISSET(i, rfds)) { < log_Printf(LogTIMER, "Read set contains %d\n", i); < FD_CLR(i, rfds); < t.tv_sec = t.tv_usec = 0; < if (select(nfds, rfds, wfds, efds, &t) != -1) { < log_Printf(LogTIMER, "The culprit !\n"); < break; < } < } < if (FD_ISSET(i, wfds)) { < log_Printf(LogTIMER, "Write set contains %d\n", i); < FD_CLR(i, wfds); < t.tv_sec = t.tv_usec = 0; < if (select(nfds, rfds, wfds, efds, &t) != -1) { < log_Printf(LogTIMER, "The culprit !\n"); < break; < } < } < if (FD_ISSET(i, efds)) { < log_Printf(LogTIMER, "Error set contains %d\n", i); < FD_CLR(i, efds); < t.tv_sec = t.tv_usec = 0; < if (select(nfds, rfds, wfds, efds, &t) != -1) { < log_Printf(LogTIMER, "The culprit !\n"); < break; < } < } < } < } < break; < } --- > zerofdset(rfds); > zerofdset(wfds); > zerofdset(efds); > if (neret > 0) { > for (x = 0, pevent = changelist; x < neret; ++x, ++pevent) { > if (pevent->filter == EVFILT_READ) { > if (pevent->flags & EV_ERROR) { > FD_SET(pevent->ident, efds); > } else if (pevent->data > 0) { > FD_SET(pevent->ident, rfds); } > } > else if (pevent->filter == EVFILT_WRITE) { > if (pevent->flags & EV_ERROR) { > FD_SET(pevent->ident, efds); > } else if (pevent->data > 0) { > FD_SET(pevent->ident, wfds); } > } > } > } 625c655 < log_Printf(LogTIMER, "Select returns %d\n", i); --- > /* Note: select() error vs read/write diagnostics removed */ 626a657,658 > log_Printf(LogTIMER, "kevent returns %d\n", i); > 665,669c697 < struct timeval t; < < t.tv_sec = 0; < t.tv_usec = 100000; < select(0, NULL, NULL, NULL, &t); --- > usleep(1); 673a702,706 > free(changelist); > close(kq); > free(rfds); > free(wfds); > free(efds); OpenBSD 4.8 (GENERIC.MP) #335: Mon Aug 16 09:09:20 MDT 2010 dera...@amd64.openbsd.org:/usr/src/sys/arch/amd64/compile/GENERIC.MP real mem = 3216900096 (3067MB) avail mem = 3117449216 (2973MB) mainbus0 at root bios0 at mainbus0: SMBIOS rev. 2.4 @ 0xf0100 (37 entries) bios0: vendor Award Software International, Inc. version "F3" date 08/25/2010 bios0: Gigabyte Technology Co., Ltd. D525TUD acpi0 at bios0: rev 0 acpi0: sleep states S0 S1 S4 S5 acpi0: tables DSDT FACP HPET MCFG TAMG APIC acpi0: wakeup devices PEX0(S5) PEX1(S5) PEX2(S5) PEX3(S5) PEX4(S5) PEX5(S5) HUB0(S5) UAR1(S1) UAR2(S1) USB0(S1) USB1(S1) USB2(S1) USB3(S1) USBE(S1) AZAL(S5) PCI0(S5) acpitimer0 at acpi0: 3579545 Hz, 24 bits acpihpet0 at acpi0: 14318179 Hz acpimadt0 at acpi0 addr 0xfee00000: PC-AT compat cpu0 at mainbus0: apid 0 (boot processor) cpu0: Intel(R) Atom(TM) CPU D525 @ 1.80GHz, 1800.18 MHz cpu0: FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,DS,ACPI,MMX,FXSR,SSE,SSE2,SS,HTT,TM,SBF,SSE3,MWAIT,DS-CPL,TM2,SSSE3,CX16,xTPR,PDCM,MOVBE,NXE,LONG cpu0: 512KB 64b/line 8-way L2 cache cpu0: apic clock running at 199MHz cpu1 at mainbus0: apid 2 (application processor) cpu1: Intel(R) Atom(TM) CPU D525 @ 1.80GHz, 1799.96 MHz cpu1: FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,DS,ACPI,MMX,FXSR,SSE,SSE2,SS,HTT,TM,SBF,SSE3,MWAIT,DS-CPL,TM2,SSSE3,CX16,xTPR,PDCM,MOVBE,NXE,LONG cpu1: 512KB 64b/line 8-way L2 cache cpu2 at mainbus0: apid 3 (application processor) cpu2: Intel(R) Atom(TM) CPU D525 @ 1.80GHz, 1799.96 MHz cpu2: FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,DS,ACPI,MMX,FXSR,SSE,SSE2,SS,HTT,TM,SBF,SSE3,MWAIT,DS-CPL,TM2,SSSE3,CX16,xTPR,PDCM,MOVBE,NXE,LONG cpu2: 512KB 64b/line 8-way L2 cache cpu3 at mainbus0: apid 1 (application processor) cpu3: Intel(R) Atom(TM) CPU D525 @ 1.80GHz, 1799.96 MHz cpu3: FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,DS,ACPI,MMX,FXSR,SSE,SSE2,SS,HTT,TM,SBF,SSE3,MWAIT,DS-CPL,TM2,SSSE3,CX16,xTPR,PDCM,MOVBE,NXE,LONG cpu3: 512KB 64b/line 8-way L2 cache ioapic0 at mainbus0: apid 2 pa 0xfec00000, version 20, 24 pins ioapic0: misconfigured as apic 0, remapped to apid 2 acpiprt0 at acpi0: bus 0 (PCI0) acpiprt1 at acpi0: bus 1 (PEX0) acpiprt2 at acpi0: bus 2 (PEX1) acpiprt3 at acpi0: bus -1 (PEX2) acpiprt4 at acpi0: bus -1 (PEX3) acpiprt5 at acpi0: bus -1 (PEX4) acpiprt6 at acpi0: bus -1 (PEX5) acpiprt7 at acpi0: bus 3 (HUB0) acpicpu0 at acpi0 acpicpu1 at acpi0 acpicpu2 at acpi0 acpicpu3 at acpi0 acpibtn0 at acpi0: PWRB pci0 at mainbus0 bus 0 pchb0 at pci0 dev 0 function 0 "Intel Pineview DMI" rev 0x02 vga1 at pci0 dev 2 function 0 "Intel Pineview Video" rev 0x02 wsdisplay0 at vga1 mux 1: console (80x25, vt100 emulation) wsdisplay0: screen 1-5 added (80x25, vt100 emulation) intagp0 at vga1 agp0 at intagp0: aperture at 0xd0000000, size 0x10000000 inteldrm0 at vga1: apic 2 int 16 (irq 5) drm0 at inteldrm0 ppb0 at pci0 dev 28 function 0 "Intel 82801GB PCIE" rev 0x02: apic 2 int 16 (irq 5) pci1 at ppb0 bus 1 re0 at pci1 dev 0 function 0 "Realtek 8168" rev 0x06: RTL8168E/8111E (0x2c00), apic 2 int 16 (irq 5), address 1c:6f:65:5d:04:a7 rgephy0 at re0 phy 7: RTL8169S/8110S PHY, rev. 4 ppb1 at pci0 dev 28 function 1 "Intel 82801GB PCIE" rev 0x02: apic 2 int 17 (irq 10) pci2 at ppb1 bus 2 jmb0 at pci2 dev 0 function 0 "JMicron JMB363 IDE/SATA" rev 0x02 ahci0 at jmb0: apic 2 int 17 (irq 10), AHCI 1.0 scsibus0 at ahci0: 32 targets jmb1 at pci2 dev 0 function 1 "JMicron JMB363 IDE/SATA" rev 0x02 pciide0 at jmb1: DMA, channel 0 wired to native-PCI, channel 1 wired to native-PCI pciide0: using apic 2 int 18 (irq 11) for native-PCI interrupt pciide0: channel 0 disabled (no drives) pciide0: channel 1 disabled (no drives) uhci0 at pci0 dev 29 function 0 "Intel 82801GB USB" rev 0x02: apic 2 int 23 (irq 3) uhci1 at pci0 dev 29 function 1 "Intel 82801GB USB" rev 0x02: apic 2 int 19 (irq 12) uhci2 at pci0 dev 29 function 2 "Intel 82801GB USB" rev 0x02: apic 2 int 18 (irq 11) uhci3 at pci0 dev 29 function 3 "Intel 82801GB USB" rev 0x02: apic 2 int 16 (irq 5) ehci0 at pci0 dev 29 function 7 "Intel 82801GB USB" rev 0x02: apic 2 int 23 (irq 3) usb0 at ehci0: USB revision 2.0 uhub0 at usb0 "Intel EHCI root hub" rev 2.00/1.00 addr 1 ppb2 at pci0 dev 30 function 0 "Intel 82801BAM Hub-to-PCI" rev 0xe2 pci3 at ppb2 bus 3 em0 at pci3 dev 0 function 0 "Intel PRO/1000GT (82541GI)" rev 0x05: apic 2 int 20 (irq 7), address 00:1b:21:91:b2:15 pcib0 at pci0 dev 31 function 0 "Intel Tigerpoint LPC" rev 0x02 ahci1 at pci0 dev 31 function 2 "Intel 82801GR AHCI" rev 0x02: apic 2 int 19 (irq 12), AHCI 1.1 scsibus1 at ahci1: 32 targets sd0 at scsibus1 targ 0 lun 0: <ATA, OCZ-VERTEX2, 1.27> SCSI3 0/direct fixed sd0: 57241MB, 512 bytes/sec, 117231408 sec total cd0 at scsibus1 targ 1 lun 0: <Optiarc, DVD RW AD-7700S, 1.03> ATAPI 5/cdrom removable ichiic0 at pci0 dev 31 function 3 "Intel 82801GB SMBus" rev 0x02: apic 2 int 19 (irq 12) iic0 at ichiic0 spdmem0 at iic0 addr 0x50: 2GB DDR3 SDRAM PC3-10600 spdmem1 at iic0 addr 0x51: 2GB DDR3 SDRAM PC3-10600 usb1 at uhci0: USB revision 1.0 uhub1 at usb1 "Intel UHCI root hub" rev 1.00/1.00 addr 1 usb2 at uhci1: USB revision 1.0 uhub2 at usb2 "Intel UHCI root hub" rev 1.00/1.00 addr 1 usb3 at uhci2: USB revision 1.0 uhub3 at usb3 "Intel UHCI root hub" rev 1.00/1.00 addr 1 usb4 at uhci3: USB revision 1.0 uhub4 at usb4 "Intel UHCI root hub" rev 1.00/1.00 addr 1 isa0 at pcib0 isadma0 at isa0 pckbc0 at isa0 port 0x60/5 pckbd0 at pckbc0 (kbd slot) pckbc0: using irq 1 for kbd slot wskbd0 at pckbd0: console keyboard, using wsdisplay0 pcppi0 at isa0 port 0x61 spkr0 at pcppi0 it0 at isa0 port 0x2e/2: IT8720F rev 8, EC port 0x290 mtrr: Pentium Pro MTRR support axe0 at uhub0 port 7 configuration 1 interface 0 "ASIX Electronics AX88772a" rev 2.00/0.01 addr 2 axe0: AX88772, address 00:60:6e:00:03:73 ukphy0 at axe0 phy 16: Generic IEEE 802.3u media interface, rev. 1: OUI 0x000ec6, model 0x0006 softraid0 at root root on sd0a swap on sd0b dump on sd0b