hotplug脚本调用

hotplug脚本调用

hotplug调用流程

最终调用hotplug脚本在netifd interface-event.c:

    char *eventnames[] = {"ifdown", "ifup", "ifupdate"};
    setenv("ACTION", eventnames[event], 1);
    setenv("INTERFACE", ifname, 1);
    if (device)
        setenv("DEVICE", device, 1);
    argv[0] = hotplug_cmd_path;
    argv[1] = "iface";
    argv[2] = NULL;
    execvp(argv[0], argv);
    exit(127);

netifd’s cycle appears to be:

  1. Start some proto-specific mechanism for acquiring interface configuration. For DHCP this is driven by proto-shell.c, which spawns /lib/netifd/proto/dhcp.sh, which is a thin wrapper around udhcpc. udhcpc is long-lived and set up to call back into /lib/netifd/dhcp.script for dhcp events:
      833 root      1488 S    udhcpc -p /var/run/udhcpc-eth1.pid -s /lib/netifd/dhcp.script -f -t 0 -i eth1 -C
     
  2. dhcp.script packages variables from udhcpc into json and end up doing ‘ubus call network.interface notify_proto ’. This in turn is handled by netifd in proto-shell.c, in proto_shell_notify. Action is 0, which leads into proto_shell_update_link.

  3. proto_shell_update_link delivers an event to the interface through state->proto.proto_event (interface_proto_cb), which calls interface_event, which leads to the snippet above, calling into /sbin/hotplug-call with ACTION=ifupdate.

代码实现

内核

代码路径:linux/drivers/net/raeth/raether.c
内核,网口down/up 在raether.c中监测寄存器来判断网口的插拔,当出现WAN口插拔事件之后,向udhcpc发送信号release/renew

#if defined(CONFIG_RALINK_MT7621) || defined(CONFIG_ARCH_MT7623)
    fp = filp_open("/var/run/udhcpc-eth1.pid", O_RDONLY, 0);
#else
    fp = filp_open("/var/run/udhcpc-eth0.2.pid", O_RDONLY, 0);
#endif
    if (IS_ERR(fp))
        return;

    if (fp->f_op && fp->f_op->read) {
        if (fp->f_op->read(fp, pid, 8, &fp->f_pos) > 0) {
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35)
        p = pid_task(find_get_pid(simple_strtoul(pid, NULL, 10)),  PIDTYPE_PID);
#else
        p = find_task_by_pid(simple_strtoul(pid, NULL, 10));
#endif

        if (NULL != p) {
            send_sig(SIGUSR2, p, 0);
            send_sig(SIGUSR1, p, 0);
        }
        }

udhcp

代码路径:package/utils/busybox/src/networking/udhcp/dhcp.c
udhcp接受到SIGUSR2和SIGUSR1之后的处理

case SIGUSR2:
    perform_release(server_addr, requested_ip);
    timeout = INT_MAX;
    continue;

在perform_release函数中调用了脚本dhcp.script

udhcp_run_script(NULL, "deconfig");

netifd

代码路径:/package/network/config/netifd
被udcp调用的dhcp.script脚本中有:

deconfig_interface() {
    proto_init_update "*" 0
    proto_send_update "$INTERFACE"
}

case "$1" in
    deconfig)
        deconfig_interface
    ;;
    renew|bound)
        setup_interface
    ;;
esac

其中proto_init_update proto_send_update在netifd-proto.sh
代码路径:/package/network/config/netifd/src/scripts/netifd-proto.sh

proto_send_update() {
    local interface="$1"

    proto_close_nested
    json_add_boolean keep "$PROTO_KEEP"
    _proto_push_array "ipaddr" "$PROTO_IPADDR" _proto_push_ipv4_addr
    _proto_push_array "ip6addr" "$PROTO_IP6ADDR" _proto_push_ipv6_addr
    _proto_push_array "routes" "$PROTO_ROUTE" _proto_push_route
    _proto_push_array "routes6" "$PROTO_ROUTE6" _proto_push_route
    _proto_push_array "ip6prefix" "$PROTO_PREFIX6" _proto_push_string
    _proto_push_array "dns" "$PROTO_DNS" _proto_push_string
    _proto_push_array "dns_search" "$PROTO_DNS_SEARCH" _proto_push_string
    _proto_notify "$interface"
}
_proto_notify() {
    local interface="$1"
    local options="$2"
    json_add_string "interface" "$interface"
    ubus $options call network.interface notify_proto "$(json_dump)"
}

在ubus.c中注册了notify_proto

    { .name = "notify_proto", .handler = netifd_iface_notify_proto },

在src/proto-shell.c
proto_shell_notify函数action=0

    switch(blobmsg_get_u32(tb[NOTIFY_ACTION])) {
    case 0:
        return proto_shell_update_link(state, attr, tb);
    if (!keep)
        state->proto.proto_event(&state->proto, IFPEV_UP);

interface.c中interface_set_proto_state函数

    state->proto_event = interface_proto_cb;
    state->iface = iface;

在回调函数interface_proto_cb函数中

    switch (ev) {
    case IFPEV_UP:
        if (iface->state != IFS_SETUP) {
            interface_event(iface, IFEV_UPDATE);
            return;
        }

        if (!iface->l3_dev.dev)
            interface_set_l3_dev(iface, iface->main_dev.dev);

        interface_ip_set_enabled(&iface->config_ip, true);
        system_flush_routes();
        iface->state = IFS_UP;
        iface->start_time = system_get_rtime();
        interface_event(iface, IFEV_UP);
        netifd_log_message(L_NOTICE, "Interface '%s' is now up\n", iface->name);
        break;

调用interface_even函数

    struct interface_user *dep, *tmp;
    struct device *adev = NULL;
    list_for_each_entry_safe(dep, tmp, &iface->users, list)
        dep->cb(dep, iface, ev);

    list_for_each_entry_safe(dep, tmp, &iface_all_users, list)
        dep->cb(dep, iface, ev);

interface_even.c/run_cmd函数

static const char * const eventnames[] = {"ifdown", "ifup", "ifupdate"};

setenv("ACTION", eventnames[event], 1);
setenv("INTERFACE", ifname, 1);
if (device)
    setenv("DEVICE", device, 1);

....

argv[0] = hotplug_cmd_path;
argv[1] = "iface";
argv[2] = NULL;
execvp(argv[0], argv);
exit(127);

其中的变量定义如下:

char *hotplug_cmd_path = DEFAULT_HOTPLUG_PATH;

#define DEFAULT_HOTPLUG_PATH    "/sbin/hotplug-call"

hotplug-call脚本

代码路径:/package/base-files/files/sbin/hotplug-call

[ \! -z "$1" -a -d /etc/hotplug.d/$1 ] && {
    for script in $(ls /etc/hotplug.d/$1/* 2>&-); do (
        [ -f $script ] && . $script
    ); done
}

将/etc/hotplug.d/iface下的脚本都执行一遍

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值