dhcp协议就不在这里多介绍了,主要想说下dhcp客户端设置端口ip地址的流程。
客户端执行的命令是:(关于dhcp客户端如何被执行的可以参考上一篇文章)
root@BDCOM:~# ps -w | grep udh
1761 root 1484 S udhcpc -p /var/run/udhcpc-eth0.2.pid -s /lib/netifd/dhcp.script -f -t 0 -i eth0.2 -V 3830d84fd8bc77bf -C
udhcpc源码在busybox-1.23.0\networking\udhcp内
从udhcpc_main函数开始一直找到下面的函数
在REQUESTING状态接收到DHCPACK
udhcp_run_script(&packet, state == REQUESTING ? "bound" : "renew");
static void udhcp_run_script(struct dhcp_packet *packet, const char *name)
{
char **envp, **curr;
char *argv[3];
envp = fill_envp(packet);//把需要设置的参数传入环境变量中
/* call script */
log1("Executing %s %s", client_config.script, name);
argv[0] = (char*) client_config.script;
argv[1] = (char*) name;
argv[2] = NULL;
spawn_and_wait(argv);
for (curr = envp; *curr; curr++) {
log2(" %s", *curr);
bb_unsetenv_and_free(*curr);
}
free(envp);
}
在这里执行dhcp.script脚本,参数为bound或是renew
在脚本处调用的是setup_interface
case "$1" in
deconfig)
deconfig_interface
;;
renew|bound)
setup_interface
;;
esac
setup_interface () {
proto_init_update "*" 1
proto_add_ipv4_address "$ip" "${subnet:-255.255.255.0}"
# TODO: apply $broadcast
logger -t udhcpc "AP IP:\"$ip\" Mask:\"$subnet\""
for i in $router; do
proto_add_ipv4_route 0.0.0.0 0 "$i"
done
# CIDR STATIC ROUTES (rfc3442)
[ -n "$staticroutes" ] && set_classless_routes $staticroutes
[ -n "$msstaticroutes" ] && set_classless_routes $msstaticroutes
for dns in $dns; do
proto_add_dns_server "$dns"
done
for domain in $domain; do
proto_add_dns_search "$domain"
done
proto_add_data
[ -n "$ZONE" ] && json_add_string zone "$ZONE"
proto_close_data
proto_send_update "$INTERFACE"
...
proto_init_update() {
local ifname="$1"
local up="$2"
local external="$3"
PROTO_KEEP=0
PROTO_INIT=1
PROTO_TUNNEL_OPEN=
PROTO_IPADDR=
PROTO_IP6ADDR=
PROTO_ROUTE=
PROTO_ROUTE6=
PROTO_PREFIX6=
PROTO_DNS=
PROTO_DNS_SEARCH=
json_init
json_add_int action 0
[ -n "$ifname" -a "*" != "$ifname" ] && json_add_string "ifname" "$ifname"
json_add_boolean "link-up" "$up"
[ -n "$3" ] && json_add_boolean "address-external" "$external"
}
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命令,找到netifd模块的ubus.c文件
static struct ubus_method iface_object_methods[] = {
{ .name = "lds", .handler = netifd_handle_down },
{ .name = "up", .handler = netifd_handle_up },
{ .name = "down", .handler = netifd_handle_down },
{ .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 },
};
static int
netifd_iface_notify_proto(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
struct interface *iface;
iface = container_of(obj, struct interface, ubus);
if (!iface->proto || !iface->proto->notify)
return UBUS_STATUS_NOT_SUPPORTED;
return iface->proto->notify(iface->proto, msg);//proto_shell_notify
}
static int
proto_shell_notify(struct interface_proto_state *proto, struct blob_attr *attr)
{
struct proto_shell_state *state;
struct blob_attr *tb[__NOTIFY_LAST];
state = container_of(proto, struct proto_shell_state, proto);
blobmsg_parse(notify_attr, __NOTIFY_LAST, tb, blob_data(attr), blob_len(attr));
if (!tb[NOTIFY_ACTION])
return UBUS_STATUS_INVALID_ARGUMENT;
switch(blobmsg_get_u32(tb[NOTIFY_ACTION])) {
case 0://json_add_int action 0设置
return proto_shell_update_link(state, attr, tb);
case 1:
return proto_shell_run_command(state, tb);
case 2:
return proto_shell_kill_command(state, tb);
case 3:
return proto_shell_notify_error(state, tb);
case 4:
return proto_shell_block_restart(state, tb);
case 5:
return proto_shell_set_available(state, tb);
case 6:
return proto_shell_add_host_dependency(state, tb);
case 7:
return proto_shell_setup_failed(state);
default:
return UBUS_STATUS_INVALID_ARGUMENT;
}
}
static int
proto_shell_update_link(struct proto_shell_state *state, struct blob_attr *data, struct blob_attr **tb)
{
struct interface *iface = state->proto.iface;
struct blob_attr *cur;
struct device *dev;
const char *devname;
int dev_create = 1;
bool addr_ext = false;
bool keep = false;
bool up;
if (state->sm == S_TEARDOWN || state->sm == S_SETUP_ABORT)
return UBUS_STATUS_PERMISSION_DENIED;
if (!tb[NOTIFY_LINK_UP])
return UBUS_STATUS_INVALID_ARGUMENT;
up = blobmsg_get_bool(tb[NOTIFY_LINK_UP]);
if (!up) {
state->proto.proto_event(&state->proto, IFPEV_LINK_LOST);
return 0;
}
if ((cur = tb[NOTIFY_KEEP]) != NULL)
keep = blobmsg_get_bool(cur);
if ((cur = tb[NOTIFY_ADDR_EXT]) != NULL) {
addr_ext = blobmsg_get_bool(cur);
if (addr_ext)
dev_create = 2;
}
if (iface->state != IFS_UP || !iface->l3_dev.dev)
keep = false;
if (!keep) {
dev = iface->main_dev.dev;
if (tb[NOTIFY_IFNAME]) {
keep = false;
devname = blobmsg_data(tb[NOTIFY_IFNAME]);
if (tb[NOTIFY_TUNNEL])
dev = proto_shell_create_tunnel(devname, tb[NOTIFY_TUNNEL]);
else
dev = device_get(devname, dev_create);
}
if (!dev)
return UBUS_STATUS_INVALID_ARGUMENT;
interface_set_l3_dev(iface, dev);
if (device_claim(&iface->l3_dev) < 0)
return UBUS_STATUS_UNKNOWN_ERROR;
device_set_present(dev, true);
interface_update_start(iface);
}
proto_apply_ip_settings(iface, data, addr_ext);
if ((cur = tb[NOTIFY_ROUTES]) != NULL)
proto_shell_parse_route_list(state->proto.iface, cur, false);
if ((cur = tb[NOTIFY_ROUTES6]) != NULL)
proto_shell_parse_route_list(state->proto.iface, cur, true);
if ((cur = tb[NOTIFY_DNS]))
interface_add_dns_server_list(&iface->proto_ip, cur);
if ((cur = tb[NOTIFY_DNS_SEARCH]))
interface_add_dns_search_list(&iface->proto_ip, cur);
if ((cur = tb[NOTIFY_DATA]))
proto_shell_parse_data(state->proto.iface, cur);
interface_update_complete(state->proto.iface);
if (!keep)
state->proto.proto_event(&state->proto, IFPEV_UP);
state->sm = S_IDLE;
return 0;
}
int
proto_apply_ip_settings(struct interface *iface, struct blob_attr *attr, bool ext)
{
struct blob_attr *tb[__OPT_MAX];
struct blob_attr *cur;
int n_v4 = 0, n_v6 = 0;
blobmsg_parse(proto_ip_attributes, __OPT_MAX, tb, blob_data(attr), blob_len(attr));
if ((cur = tb[OPT_IPADDR]))
n_v4 = parse_address_list(iface, cur, false, ext);
if ((cur = tb[OPT_IP6ADDR]))
n_v6 = parse_address_list(iface, cur, true, ext);
if ((cur = tb[OPT_IP6PREFIX]))
if (parse_prefix_list(iface, cur) < 0)
goto out;
if (n_v4 < 0 || n_v6 < 0)
goto out;
if ((cur = tb[OPT_GATEWAY])) {
if (n_v4 && !parse_gateway_option(iface, cur, false))
goto out;
}
if ((cur = tb[OPT_IP6GW])) {
if (n_v6 && !parse_gateway_option(iface, cur, true))
goto out;
}
return 0;
out:
return -1;
}
static int
parse_address_list(struct interface *iface, struct blob_attr *attr, bool v6,
bool ext)
{
struct device_addr *addr;
struct blob_attr *cur;
int n_addr = 0;
int rem;
blobmsg_for_each_attr(cur, attr, rem) {
addr = parse_address_item(cur, v6, ext);
if (!addr)
return -1;
n_addr++;
vlist_add(&iface->proto_ip.addr, &addr->node, &addr->flags);
}
return n_addr;
}
来看下netifd的interface.h结构
struct interface {
struct vlist_node node;
struct list_head hotplug_list;
enum interface_event hotplug_ev;
const char *name;
const char *ifname;
bool available;
bool autostart;
bool config_autostart;
bool device_config;
bool enabled;
bool link_state;
bool force_link;
bool dynamic;
time_t start_time;
enum interface_state state;
enum interface_config_state config_state;
enum interface_update_flags updated;
struct list_head users;
const char *parent_ifname;
struct interface_user parent_iface;
/* main interface that the interface is bound to */
struct device_user main_dev;
struct device_user ext_dev;
/* interface that layer 3 communication will go through */
struct device_user l3_dev;
struct blob_attr *config;
/* primary protocol state */
const struct proto_handler *proto_handler;
struct interface_proto_state *proto;
struct interface_ip_settings proto_ip;
struct interface_ip_settings config_ip;
struct vlist_tree host_routes;
int metric;
unsigned int ip4table;
unsigned int ip6table;
/* IPv6 assignment parameters */
uint8_t assignment_length;
int32_t assignment_hint;
struct list_head assignment_classes;
/* errors/warnings while trying to bring up the interface */
struct list_head errors;
/* extra data provided by protocol handlers or modules */
struct avl_tree data;
struct uloop_timeout remove_timer;
struct ubus_object ubus;
};
端口的初始化
static void
__interface_ip_init(struct interface_ip_settings *ip, struct interface *iface)
{
ip->iface = iface;
ip->enabled = true;
vlist_simple_init(&ip->dns_search, struct dns_search_domain, node);
vlist_simple_init(&ip->dns_servers, struct dns_server, node);
vlist_init(&ip->route, route_cmp, interface_update_proto_route);
vlist_init(&ip->addr, addr_cmp, interface_update_proto_addr);
vlist_init(&ip->prefix, prefix_cmp, interface_update_prefix);
}
void
interface_ip_init(struct interface *iface)
{
__interface_ip_init(&iface->proto_ip, iface);
__interface_ip_init(&iface->config_ip, iface);
vlist_init(&iface->host_routes, route_cmp, interface_update_host_route);
}
当每次增删减地址时都会执行回调函数interface_update_proto_addr
static void
interface_update_proto_addr(struct vlist_tree *tree,
struct vlist_node *node_new,
struct vlist_node *node_old)
{
struct interface_ip_settings *ip;
struct interface *iface;
struct device *dev;
struct device_addr *a_new = NULL, *a_old = NULL;
bool replace = false;
bool keep = false;
bool v6 = false;
ip = container_of(tree, struct interface_ip_settings, addr);
iface = ip->iface;
dev = iface->l3_dev.dev;
if (!node_new || !node_old)
iface->updated |= IUF_ADDRESS;
if (node_new) {
a_new = container_of(node_new, struct device_addr, node);
if ((a_new->flags & DEVADDR_FAMILY) == DEVADDR_INET4 &&
!a_new->broadcast) {
uint32_t mask = ~0;
uint32_t *a = (uint32_t *) &a_new->addr;
mask >>= a_new->mask;
a_new->broadcast = *a | htonl(mask);
}
}
if (node_old)
a_old = container_of(node_old, struct device_addr, node);
if (a_new && a_old) {
keep = true;
if (a_old->flags != a_new->flags || a_old->failed)
keep = false;
if (a_old->valid_until != a_new->valid_until ||
a_old->preferred_until != a_new->preferred_until)
replace = true;
if ((a_new->flags & DEVADDR_FAMILY) == DEVADDR_INET4 &&
a_new->broadcast != a_old->broadcast)
keep = false;
}
if (node_old) {
if (!(a_old->flags & DEVADDR_EXTERNAL) && a_old->enabled && !keep) {
interface_handle_subnet_route(iface, a_old, false);
if ((a_old->flags & DEVADDR_FAMILY) == DEVADDR_INET6)
v6 = true;
unsigned int table = (v6) ? iface->ip6table : iface->ip4table;
//This is needed for source routing to work correctly. If a device
//has two connections to a network using the same subnet, adding
//only the network-rule will cause packets to be routed through the
//first matching network (source IP matches both masks).
if (table) {
set_ip_source_policy(false, v6, IPRULE_PRIORITY_ADDR, &a_old->addr,
(v6) ? 128 : 32, table, NULL, NULL);
set_ip_source_policy(false, v6, IPRULE_PRIORITY_NW, &a_old->addr,
a_old->mask, table, NULL, NULL);
}
system_del_address(dev, a_old);
}
free(a_old->pclass);
free(a_old);
}
if (node_new) {
a_new->enabled = true;
if (!(a_new->flags & DEVADDR_EXTERNAL) && (!keep || replace)) {
if (system_add_address(dev, a_new))
a_new->failed = true;
if (!keep) {
if ((a_new->flags & DEVADDR_FAMILY) == DEVADDR_INET6)
v6 = true;
unsigned int table = (v6) ? iface->ip6table : iface->ip4table;
if (table) {
set_ip_source_policy(true, v6, IPRULE_PRIORITY_ADDR, &a_new->addr,
(v6) ? 128 : 32, table, NULL, NULL);
set_ip_source_policy(true, v6, IPRULE_PRIORITY_NW, &a_new->addr,
a_new->mask, table, NULL, NULL);
}
}
if ((a_new->flags & DEVADDR_OFFLINK) || iface->metric)
interface_handle_subnet_route(iface, a_new, true);
}
}
}
int system_add_address(struct device *dev, struct device_addr *addr)
{
return system_addr(dev, addr, RTM_NEWADDR);
}
static int system_addr(struct device *dev, struct device_addr *addr, int cmd)
{
bool v4 = ((addr->flags & DEVADDR_FAMILY) == DEVADDR_INET4);
int alen = v4 ? 4 : 16;
unsigned int flags = 0;
struct ifaddrmsg ifa = {
.ifa_family = (alen == 4) ? AF_INET : AF_INET6,
.ifa_prefixlen = addr->mask,
.ifa_index = dev->ifindex,
};
struct nl_msg *msg;
if (cmd == RTM_NEWADDR)
flags |= NLM_F_CREATE | NLM_F_REPLACE;
msg = nlmsg_alloc_simple(cmd, flags);
if (!msg)
return -1;
nlmsg_append(msg, &ifa, sizeof(ifa), 0);
nla_put(msg, IFA_LOCAL, alen, &addr->addr);
if (v4) {
if (addr->broadcast)
nla_put_u32(msg, IFA_BROADCAST, addr->broadcast);
if (addr->point_to_point)
nla_put_u32(msg, IFA_ADDRESS, addr->point_to_point);
} else {
time_t now = system_get_rtime();
struct ifa_cacheinfo cinfo = {0xffffffffU, 0xffffffffU, 0, 0};
if (addr->preferred_until) {
int64_t preferred = addr->preferred_until - now;
if (preferred < 0)
preferred = 0;
else if (preferred > UINT32_MAX)
preferred = UINT32_MAX;
cinfo.ifa_prefered = preferred;
}
if (addr->valid_until) {
int64_t valid = addr->valid_until - now;
if (valid <= 0)
return -1;
else if (valid > UINT32_MAX)
valid = UINT32_MAX;
cinfo.ifa_valid = valid;
}
nla_put(msg, IFA_CACHEINFO, sizeof(cinfo), &cinfo);
}
return system_rtnl_call(msg);
}
通知内核完成ip设置