跳转至

Openwrt

openwrt编译笔记

用到的仓库:

https://github.com/coolsnowwolf/lede

https://github.com/kenzok8/openwrt-packages

x86软路由openwrt折腾笔记

安装

机器是J1900软路由,64位的CPU,下载镜象:https://downloads.openwrt.org/releases/21.02.3/targets/x86/64/

generic-ext4-combined-efi.img.gz解压出来,用Etcher之类的工具写到软路由硬盘上,想办法进到Shell,我用的VGA视频输出(机器留了个COM口,但是懒得自己做转换线)

设置/etc/config/network中的LAN/WAN口,自己先试着插插网线看看ethX和物理端口的对应关系(先用ifconfig ethX up把网口都拉起来,插网线会看到log的):

config device
    option name 'br-lan'
    option type 'bridge'
    list ports 'eth0'
    list ports 'eth1'
    list ports 'eth2'

config interface 'lan'
    option proto 'static'
    option ipaddr '192.168.1.1'
    option netmask '255.255.255.0'
    option ip6assign '60'
    option device 'br-lan'

config interface 'wan'
    option device 'eth3'
    option proto 'dhcp'

config interface 'wan6'
    option device 'eth3'
    option proto 'dhcpv6'

配置好之后重启网络/etc/init.d/network restart,插网线到LAN口,应该能访问web配置界面了。

换源

$ cat /etc/opkg/distfeeds.conf
src/gz openwrt_core https://mirrors.ustc.edu.cn/openwrt/releases/21.02.3/targets/x86/64/packages
src/gz openwrt_base https://mirrors.ustc.edu.cn/openwrt/releases/21.02.3/packages/x86_64/base
src/gz openwrt_luci https://mirrors.ustc.edu.cn/openwrt/releases/21.02.3/packages/x86_64/luci
src/gz openwrt_packages https://mirrors.ustc.edu.cn/openwrt/releases/21.02.3/packages/x86_64/packages
src/gz openwrt_routing https://mirrors.ustc.edu.cn/openwrt/releases/21.02.3/packages/x86_64/routing
src/gz openwrt_telephony https://mirrors.ustc.edu.cn/openwrt/releases/21.02.3/packages/x86_64/telephony

自己编译软件包

为了能自己编译软件,先下载sdk,比如openwrt-sdk-21.02.3-x86-64_gcc-8.4.0_musl.Linux-x86_64.tar.xz,解压

添加第三方软件源,修改./feeds.conf.default,更新软件:

$ ./scripts/feeds update clean
$ ./scripts/feeds update -a
$ ./scripts/feeds install -a

更新完之后,再执行make menuconfig,就能看到软件列表了。

UCI

文档:https://openwrt.org/docs/guide-user/base-system/uci

UCI是openwrt的配置接口

一个uci配置文件例子/etc/config/sys

config app
    option workmode 'rtsp'

命令行get/set:

$ uci get sys.@app[0].workmode
rtsp
$ uci set sys.@app[0].workmode='uvc'

openwrt的工具

block-mounthttp://git.openwrt.org/project/fstools.git提供的block工具,和blkid命令差不多:

# block info
/dev/loop0: UUID="4d6fe5a0-de0c-4945-9c91-8284225b7295" LABEL="rootfs_data" VERSION="1.13" MOUNT="/overlay" TYPE="f2fs"
/dev/sda1: UUID="84173db5-fa99-e35a-95c6-28613cc79ea9" LABEL="kernel" VERSION="1.0" MOUNT="/boot" TYPE="ext4"
/dev/sda2: UUID="5bdbe408-d6fc5cf7-c1c9f393-d4ff4ca9" VERSION="4.0" MOUNT="/rom" TYPE="squashfs"

openwrt启动过程

文档:

Procd system init and daemon management

Preinit and Root Mount and Firstboot Scripts

大致启动流程,Linux Kernel启动sbin/init:

  • init启动/etc/inittab->/etc/init.d/rcS->/etc/rc.d/S*
  • init启动procd

Linux的0号进程启动/sbin/init

Linux Kernel的init/main.c中执行/sbin/init,openwrt的init程序实现在procd.git仓库中的initd目录下:

-> initd/main.c, main()
-> initd/init.c, preinit()
    - fork()执行/etc/preinit脚本
    - fork()执行procd

/etc/preinitshell脚本的行为

#!/bin/sh
# Copyright (C) 2006-2016 OpenWrt.org
# Copyright (C) 2010 Vertical Communications

# 解读:PREINIT环境变量不存在时执行/sbin/init进程
[ -z "$PREINIT" ] && exec /sbin/init

export PATH="/usr/sbin:/usr/bin:/sbin:/bin"
export DBGLVL=7

. /lib/functions.sh
. /lib/functions/preinit.sh
. /lib/functions/system.sh

boot_hook_init preinit_essential
boot_hook_init preinit_main
boot_hook_init failsafe
boot_hook_init initramfs
boot_hook_init preinit_mount_root

for pi_source_file in /lib/preinit/*; do
    . $pi_source_file
done

boot_run_hook preinit_essential

pi_mount_skip_next=false
pi_jffs2_mount_success=false
pi_failsafe_net_message=false

boot_run_hook preinit_main

procd进程的行为

状态由state.c管理,与初始化有关的状态为:

  • early:设备相关初始化

  • watchdog_init()

  • hotplug("/etc/hotplug.json")
  • procd_coldplug() 冷启动设备,在这函数里面切换到下一个状态

  • ubus:启动ubusd

  • watchdog_init(0)

  • set_stdio("console")

  • procd_connect_ubus() 里面在uloop里创建了个timer,定时连接ubus,连接上ubus后切换到下一个状态

  • service_start_early("ubus", ubus_cmd, p?"ubus":NULL, p?"ubus":NULL) 将/sbin/ubus作为一个服务启动

  • init:

  • procd_inittab()

  • procd_inittab_run("respawn")
  • procd_inittab_run("askconsole")
  • procd_inittab_run("askfirst")
  • procd_inittab_run("sysinit")
  • ulog_open(ULOG_SYSLOG, LOG_DAEMON, "procd"); 输出log到syslog

Tips:

调试时为了方便,可以把log.h里的DEBUG宏换成:

#define DEBUG(level, fmt, ...)   ulog(LOG_NOTICE, fmt, ## __VA_ARGS__)

coldplug.c里会挂载

mount("devtmpfs", "/dev", "devtmpfs", MS_NOSUID, 0);