首页 > 其他分享 >udhcpc如何绑定网络接口

udhcpc如何绑定网络接口

时间:2022-08-16 21:12:10浏览次数:57  
标签:netifd proto 绑定 json handler notify interface udhcpc 网络接口

udhcpc如何绑定网络接口

https://kysonlok.gitbook.io/blog/openwrt/how_does_udhcpc_work

 

Introduce OpenWrt 缺省控制 DHCP 的进程如下:
  •   udhcpc - DHCP IPV4 client
  •   odhcp6c - DHCP IPV6 client
  •   DNSmasq - DHCP IPV4 server
  •   odhcpd - DHCP IPV6 server
使用 ps 命令查看 udhcpc 运行参数情况:   # ps -w | grep udhcpc   udhcpc 运行的参数类似这样:   2339 root 1204 S udhcpc -p /var/run/udhcpc-eth0.2.pid -s /lib/netifd/dhcp.script -f -t 0 -i eth0.2 -x hostname GL-MT300N-V   2674 root 1204 S udhcpc -p /var/run/udhcpc-apcli0.pid -s /lib/netifd/dhcp.script -f -t 0 -i apcli0 -C -O 121   对于我的路由器,当前系统 apcli0 和 eth0.2 网络接口使用了 DHCP 协议,当有 DHCP 事件被触发,会执行 /lib/netifd/dhcp.script 脚本。   Udhcpc startup 通过 grep 搜索,发现启动 udhcpc 的代码在 /lib/netifd/proto/dhcp.sh 脚本中,proto_dhcp_setup 函数代码段:   proto_run_command "$config" udhcpc \   -p /var/run/udhcpc-$iface.pid \   -s /lib/netifd/dhcp.script \   -f -t 0 -i "$iface" \   ${ipaddr:+-r $ipaddr} \   ${hostname:+-x "hostname:$hostname"} \   ${vendorid:+-V "$vendorid"} \   $clientid $broadcast $release $dhcpopts   这里调用了 proto_run_command 函数,同样地,搜索到它是 /lib/netifd/netifd-proto.sh 提供的脚本 api,代码段:   proto_run_command() {   local interface="$1"; shift     json_init   json_add_int action 1   json_add_array command   while [ $# -gt 0 ]; do   json_add_string "" "$1"   shift   done   json_close_array   [ -n "$_EXPORT_VARS" ] && {   json_add_array env   for var in $_EXPORT_VARS; do   eval "json_add_string \"\" \"\${$var}\""   done   json_close_array   }   _proto_notify "$interface"   }   proto_run_command 函数就是初始化了json object,往 json object 添加了 string 类型的 action 和 array 类型的 command 字段,把传进来的参数全部填充到 command array中,最后调用了_proto_notify。 _proto_notify 函数代码段:   _proto_notify() {   local interface="$1"   local options="$2"   json_add_string "interface" "$interface"   ubus $options call network.interface notify_proto "$(json_dump)"   }   由此可以看出,最终使用 ubus 把 json 格式的内容发送到 ubusd 处理,network.interface 对象的 notify_proto 方法。 我们可以通过命令行查看 network.interface 对象注册了哪些方法以及怎么使用:   # ubus -v list network.interface   notify_proto 方法在背后做了哪些工作呢?我们可以通过 netifd 源码来寻找答案。notify_proto 的定义在 ubus.c 文件中,netifd 源码:   # git clone git://git.openwrt.org/project/netifd.git     static struct ubus_method iface_object_methods[] = {   { .name = "up", .handler = netifd_handle_up },   { .name = "down", .handler = netifd_handle_down },   { .name = "renew", .handler = netifd_handle_renew },   { .name = "status", .handler = netifd_handle_status },   { .name = "prepare", .handler = netifd_handle_iface_prepare },   { .name = "dump", .handler = netifd_handle_dump },   UBUS_METHOD("add_device", netifd_iface_handle_device, dev_link_policy ),   UBUS_METHOD("remove_device", netifd_iface_handle_device, dev_link_policy ),   { .name = "notify_proto", .handler = netifd_iface_notify_proto },   { .name = "remove", .handler = netifd_iface_remove },   { .name = "set_data", .handler = netifd_handle_set_data },   };   通过跟踪代码,调用顺序大致是这样:   netifd_iface_notify_proto --–>   iface->proto->notify --->   回调的注册:   state->proto.notify = proto_shell_notify; --->   proto_shell_run_command --->   netifd_start_process --->   创建子进程调用execvp执行脚本命令   至此,我们可以知道,刚开始分析的 udhcpc 作为脚本 api proto_run_command 的传入参数,最终通过 ubus 通讯,由 netifd 执行 execvp 带起 udhcpc。   Example 以重新获取 wan 口的 ip 地址为例演示上面的过程,/lib/netifd/proto/dhcp.sh 的 proto_dhcp_renew 函数可以重新租约 ip 地址,proto_dhcp_renew 函数代码段:   proto_dhcp_renew() {   local interface="$1"   # SIGUSR1 forces udhcpc to renew its lease   local sigusr1="$(kill -l SIGUSR1)"   [ -n "$sigusr1" ] && proto_kill_command "$interface" $sigusr1   }   proto_dhcp_renew 函数需要接收一个 interface( wan | wan6 | lan | wwan | ... ) 参数,重新租约 wan 口的 ip:   proto_dhcp_renew "wan"   注意:这里只是为了演示过程,实际上不能直接调用的。 proto_dhcp_renew 调用了 proto_kill_command,代码段:   _proto_notify() {   local interface="$1"   local options="$2"   json_add_string "interface" "$interface"   ubus $options call network.interface notify_proto "$(json_dump)"   }     proto_kill_command() {   local interface="$1"; shift     json_init   json_add_int action 2   [ -n "$1" ] && json_add_int signal "$1"   _proto_notify "$interface"   }   前面分析可知,这里是构造了一个 json 格式消息,然后通过调用 _proto_notify 把消息发送到 ubusd 处理,这里的 json_dump 内容为:   {   "interface": "wan",   "action": 2,   "signal": 16   }   proto_dhcp_renew "wan" 其实等价于命令行执行:   # ubus call network.interface notify_proto '{"action":2,"signal":16,"interface":"wan"}'     Troubleshoot 前面提到入口在 /lib/netifd/proto/dhcp.sh 脚本,我们分析一下这个脚本是怎样被执行的? netifd 主程序是 main.c,netifd 在启动的时候,调用了 proto_shell_init 函数。proto_shell_init 的实现代码以及分析注释:   void proto_shell_init(void)   {   /* 获取 /lib/netifd/proto 文件描述符 */   proto_fd = netifd_open_subdir("proto");   if (proto_fd < 0)   return;     netifd_init_script_handlers(proto_fd, proto_shell_add_handler);   }   netifd_init_script_handlers 的实现代码:   void netifd_init_script_handlers(int dir_fd, script_dump_cb cb)   {   glob_t g;   int i, prev_fd;     prev_fd = netifd_dir_push(dir_fd);   if (glob("./*.sh", 0, NULL, &g))   return;     for (i = 0; i < g.gl_pathc; i++)   netifd_parse_script_handler(g.gl_pathv[i], cb);   netifd_dir_pop(prev_fd);     globfree(&g);   }   netifd_parse_script_handler 函数执行 /lib/netifd/proto 目录下的所有.sh文件,dump 作为传入参数。对于dhcp.sh,在脚本执行:   init_proto "dump"   add_protocol dhcp   其中,init_proto 和 add_protocol 为 netifd-proto.sh 的函数接口。   add_protocol --->   proto_dhcp_init_config   并且构造一个 json 格式消息作为返回,netifd 的 netifd_parse_script_handler 函数将执行 dhcp.sh 脚本的返回值封装成 json 对象。   netifd_init_script_handlers --->   netifd_parse_script_handler --->   netifd_init_script_handler -->   proto_shell_add_handler --->   add_proto_handler --->   avl_insert   proto_shell_add_handlernetifd_init_script_handlers 注册的回调函数,在 netifd_init_script_handler 被调用。proto_shell_add_handler 函数把 json 解析到 struct proto_handler 对应的成员变量中,然后把它插入到 avl 树中。

 

============ End

 

 

标签:netifd,proto,绑定,json,handler,notify,interface,udhcpc,网络接口
From: https://www.cnblogs.com/lsgxeva/p/16592996.html

相关文章

  • Taurus.MVC 微服务框架 入门开发教程:项目部署:2、让Kestrel支持绑定多个域名转发,替代Ng
    系列目录:本系列分为项目集成、项目部署、架构演进三个方向,后续会根据情况调整文章目录。本系列第一篇:Taurus.MVCV3.0.3微服务开源框架发布:让.NET架构在大并发的演......
  • Chapter 08 - RaiseMan (C# 实现 + Cell-based tableview绑定)
    这个代码主要展示如何绑定ArrayController到Cell-basedTableview。在发代码前,需要注意几点。1.Person为自定义的class,但是一定要Register为PersonModel。格式{自定义c......
  • Vue项目中select下来选项绑定国际化语言
    1.当切换语言的时候,想要响应式地更新下拉选项,关键点是用$t(item.label)取得语言。注意item.label左右是不带引号的,否则会当作原字符串输出。<el-selectv-mo......
  • vue2 绑定数组,变化无法更新view的解决方法
    vue绑定数组,更新数组的内容时,view没有更新,多数是因为直接给数组內的数据赋值了,如:this.student[i].name="JackFung";这样做vue是不会触发视图更新的。根据vue的官方文......
  • 多网卡绑定之team
    多网卡绑定之teamCloud研习社 Cloud研习社 2022-08-0907:33 发表于山东收录于合集#一站式教程119个#Linux122个#计算机网络11个#云计算29个#linux46个......
  • vue双向绑定原理分析
    1.vue双向绑定原理vue.js则是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应......
  • VUE学习-表单输入绑定
    表单输入绑定v-model可以用v-model指令在表单<input>、<textarea>及<select>元素上创建双向数据绑定。v-model会忽略所有表单元素的value、checked、selecteda......