iproute2 - 协议地址管理
一、命令模式:
ip [ OPTIONS ] OBJECT [ COMMAND [ ARGUMENTS ]]
选项不变
OBJECT 对象为 addr
缩写形式: address, addr, a
参数: add, delete, flush, show (list)
1. 查看当前IP地址
命令简写: show, list, lst, sh, ls, l, 空
参数:
dev NAME (default) --- 接口名称.
scope SCOPE_VAL --- 只显示本域名称.
to PREFIX --- 只显示本前缀名称.
label PATTERN --- list only addresses with labels matching the PATTERN. PATTERN is the usual shell regexp style pattern.
primary / secondary --- list only primary (or secondary) addresses.
dynamic / permanent --- (IPv6 only) list only addresses installed due to stateless address configuration or list only the permanent (not dynamic) addresses.
tentative --- (IPv6 only) list only addresses, which did not pass duplicate address detection。
deprecated --- (IPv6 only) list only deprecated addresses.
添加IP地址
Abbreviations: add, a
Arguments:
dev NAME --- name of the device to which we add the address
local ADDRESS (default) --- address of the interface.
二、全局变量
static struct link_filter filter;
// ip_common.h 头文件
struct link_filter {
int ifindex; // 接口序列号
int family; // 协议
int oneline; // 一行显示
int showqueue;
inet_prefix pfx;
int scope, scopemask;
int flags, flagmask;
int up;
char *label;
int flushed;
char *flushb;
int flushp;
int flushe;
int group;
int master;
char *kind;
char *slave_kind;
};
// libnetlink.h 头文件中定义结点
struct nlmsg_list { struct nlmsg_list *next; struct nlmsghdr h; };
struct nlmsg_chain { struct nlmsg_list *head; struct nlmsg_list *tail; };
// netlink.h 头文件中
struct nlmsghdr { __u32 nlmsg_len; /* Length of message including header */ __u16 nlmsg_type; /* Message content */ __u16 nlmsg_flags; /* Additional flags */ __u32 nlmsg_seq; /* Sequence number */ __u32 nlmsg_pid; /* Sending process port ID */ };
// if_addr.h struct ifaddrmsg { __u8 ifa_family; __u8 ifa_prefixlen; /* The prefix length */ __u8 ifa_flags; /* Flags */ __u8 ifa_scope; /* Address scope */ __u32 ifa_index; /* Link index */ };
文件 ipaddress.c 中函数 do_ipaddr
int do_ipaddr(int argc, char **argv) { if (argc < 1) return ipaddr_list_flush_or_save(0, NULL, IPADD_LIST); if (matches(*argv, "add") == 0) return ipaddr_modify(RTM_NEWADDR, NLM_F_CREATE|NLM_F_EXCL, argc-1, argv+1); if (matches(*argv, "change") == 0 || strcmp(*argv, "chg") == 0) return ipaddr_modify(RTM_NEWADDR, NLM_F_REPLACE, argc-1, argv+1); if (matches(*argv, "replace") == 0) return ipaddr_modify(RTM_NEWADDR, NLM_F_CREATE|NLM_F_REPLACE, argc-1, argv+1); if (matches(*argv, "delete") == 0) return ipaddr_modify(RTM_DELADDR, 0, argc-1, argv+1); if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0 || matches(*argv, "lst") == 0) return ipaddr_list_flush_or_save(argc-1, argv+1, IPADD_LIST); if (matches(*argv, "flush") == 0) return ipaddr_list_flush_or_save(argc-1, argv+1, IPADD_FLUSH); if (matches(*argv, "save") == 0) return ipaddr_list_flush_or_save(argc-1, argv+1, IPADD_SAVE); if (matches(*argv, "showdump") == 0) return ipaddr_showdump(); if (matches(*argv, "restore") == 0) return ipaddr_restore(); if (matches(*argv, "help") == 0) usage(); fprintf(stderr, "Command \"%s\" is unknown, try \"ip address help\".\n", *argv); exit(-1); }
形式参数:
argc = 8 ,
*argv[] = {
"add",
"127.0.0.1/8",
"dev",
"lo",
"brd",
"+",
"scope",
"host"
}
执行流程
如果 argc 参数个数小于1, ipaddr_list_flush_or_save(0, NULL, IPADD_LIST) 函数
如果 argv 是 add, 调用 ipaddr_modify(RTM_NEWADDR, NLM_F_CREATE|NLM_F_EXCL, argc-1, argv+1);
如果 argv 是 change, 调用 ipaddr_modify(RTM_NEWADDR, NLM_F_REPLACE, argc-1, argv+1);
如果 argv 是 replace, 调用 ipaddr_modify(RTM_NEWADDR, NLM_F_CREATE|NLM_F_REPLACE, argc-1, argv+1);
如果 argv 是 delete, 调用 ipaddr_modify(RTM_DELADDR, 0, argc-1, argv+1);
如果 argv 是 list , 调用 ipaddr_list_flush_or_save(argc-1, argv+1, IPADD_LIST);
如果 argv 是 flush , 调用 ipaddr_list_flush_or_save(argc-1, argv+1, IPADD_FLUSH)
如果 argv 是 save, 调用 ipaddr_list_flush_or_save(argc-1, argv+1, IPADD_SAVE)
如果 argv 是 showdump , 调用 ipaddr_showdump() 函数
如果 argv 是 restore , 调用 ipaddr_restore() 函数
如果 argv 是
argc = 0, char **argv = NULL, action = IPADDR_LIST
argc = argc - 1, char **argv = argv+1, action = IPADD_LIST
argc = argc - 1, char **argv = argv+1, action = IPADD_FLUSH
argc = argc - 1, char **argv = argv+1, action = IPADD_SAVE
// 成功返回0, 失败返回-1
static int ipaddr_list_flush_or_save(int argc, char **argv, int action) { struct nlmsg_chain linfo = { NULL, NULL}; struct nlmsg_chain _ainfo = { NULL, NULL}, *ainfo = NULL; struct nlmsg_list *l; char *filter_dev = NULL; int no_link = 0;
// 第一步:初始化全局变量 filter ipaddr_reset_filter(oneline, 0); filter.showqueue = 1; filter.family = preferred_family; filter.group = -1;
// 如果action为IPADD_FLUSH, 判断后面参数是否合法 if (action == IPADD_FLUSH) { if (argc <= 0) { fprintf(stderr, "Flush requires arguments.\n"); return -1; } if (filter.family == AF_PACKET) { fprintf(stderr, "Cannot flush link addresses.\n"); return -1; } }
// 如果参数个数大于0
如果是 to 参数
如果是 scope
如果是 up
如果是 label
如果是 group
如果是 master
如果是 vrf
如果是 type
如果是 dev
如果是
while (argc > 0) { if (strcmp(*argv, "to") == 0) { NEXT_ARG(); get_prefix(&filter.pfx, *argv, filter.family); if (filter.family == AF_UNSPEC) filter.family = filter.pfx.family; } else if (strcmp(*argv, "scope") == 0) { unsigned int scope = 0; NEXT_ARG(); filter.scopemask = -1; if (rtnl_rtscope_a2n(&scope, *argv)) { if (strcmp(*argv, "all") != 0) invarg("invalid \"scope\"\n", *argv); scope = RT_SCOPE_NOWHERE; filter.scopemask = 0; } filter.scope = scope; } else if (strcmp(*argv, "up") == 0) { filter.up = 1; } else if (get_filter(*argv) == 0) { } else if (strcmp(*argv, "label") == 0) { NEXT_ARG(); filter.label = *argv; } else if (strcmp(*argv, "group") == 0) { NEXT_ARG(); if (rtnl_group_a2n(&filter.group, *argv)) invarg("Invalid \"group\" value\n", *argv); } else if (strcmp(*argv, "master") == 0) { int ifindex; NEXT_ARG(); ifindex = ll_name_to_index(*argv); if (!ifindex) invarg("Device does not exist\n", *argv); filter.master = ifindex; } else if (strcmp(*argv, "vrf") == 0) { int ifindex; NEXT_ARG(); ifindex = ll_name_to_index(*argv); if (!ifindex) invarg("Not a valid VRF name\n", *argv); if (!name_is_vrf(*argv)) invarg("Not a valid VRF name\n", *argv); filter.master = ifindex; } else if (strcmp(*argv, "type") == 0) { int soff; NEXT_ARG(); soff = strlen(*argv) - strlen("_slave"); if (!strcmp(*argv + soff, "_slave")) { (*argv)[soff] = '\0'; filter.slave_kind = *argv; } else { filter.kind = *argv; } } else { if (strcmp(*argv, "dev") == 0) NEXT_ARG(); else if (matches(*argv, "help") == 0) usage(); if (filter_dev) duparg2("dev", *argv); filter_dev = *argv; } argv++; argc--; }
// filter_dev 是指针数组 if (filter_dev) { filter.ifindex = ll_name_to_index(filter_dev); if (filter.ifindex <= 0) { fprintf(stderr, "Device \"%s\" does not exist.\n", filter_dev); return -1; } } if (action == IPADD_FLUSH) return ipaddr_flush(); if (action == IPADD_SAVE) { if (ipadd_save_prep()) exit(1); if (rtnl_wilddump_request(&rth, preferred_family, RTM_GETADDR) < 0) { perror("Cannot send dump request"); exit(1); } if (rtnl_dump_filter(&rth, save_nlmsg, stdout) < 0) { fprintf(stderr, "Save terminated\n"); exit(1); } exit(0); }
// 整形参数 json 参数在utils.h 头文件中定义
new_json_obj(json); /* * If only filter_dev present and none of the other * link filters are present, use RTM_GETLINK to get * the link device */ if (filter_dev && filter.group == -1 && do_link == 1) { if (iplink_get(0, filter_dev, RTEXT_FILTER_VF) < 0) { perror("Cannot send link get request"); delete_json_obj(); exit(1); } delete_json_obj(); exit(0); } if (filter.family != AF_PACKET) { ainfo = &_ainfo; if (filter.oneline) no_link = 1; } if (ip_linkaddr_list(filter.family, iplink_filter_req, &linfo, ainfo) != 0) goto out;
// 如果协议不是 AF_PACKET if (filter.family != AF_PACKET) ipaddr_filter(&linfo, ainfo);
// 以链表的形式打印 for (l = linfo.head; l; l = l->next) { int res = 0; struct ifinfomsg *ifi = NLMSG_DATA(&l->h); open_json_object(NULL); if (brief) { if (print_linkinfo_brief(NULL, &l->h, stdout, NULL) == 0) if (filter.family != AF_PACKET) print_selected_addrinfo(ifi, ainfo->head, stdout); } else if (no_link || (res = print_linkinfo(NULL, &l->h, stdout)) >= 0) { if (filter.family != AF_PACKET) print_selected_addrinfo(ifi, ainfo->head, stdout); if (res > 0 && !do_link && show_stats) print_link_stats(stdout, &l->h); } close_json_object(); } fflush(stdout); out: if (ainfo) free_nlmsg_chain(ainfo); free_nlmsg_chain(&linfo); delete_json_obj(); return 0; }
static void ipaddr_filter(struct nlmsg_chain *linfo, struct nlmsg_chain *ainfo) { struct nlmsg_list *l, **lp; lp = &linfo->head; // 头结点lp
while ((l = *lp) != NULL) { int ok = 0; int missing_net_address = 1; struct ifinfomsg *ifi = NLMSG_DATA(&l->h); struct nlmsg_list *a; for (a = ainfo->head; a; a = a->next) { struct nlmsghdr *n = &a->h; struct ifaddrmsg *ifa = NLMSG_DATA(n); struct rtattr *tb[IFA_MAX + 1]; unsigned int ifa_flags; if (ifa->ifa_index != ifi->ifi_index) continue; missing_net_address = 0; if (filter.family && filter.family != ifa->ifa_family) continue; if ((filter.scope^ifa->ifa_scope)&filter.scopemask) continue; parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(n)); ifa_flags = get_ifa_flags(ifa, tb[IFA_FLAGS]); if ((filter.flags ^ ifa_flags) & filter.flagmask) continue; if (filter.pfx.family || filter.label) { if (!tb[IFA_LOCAL]) tb[IFA_LOCAL] = tb[IFA_ADDRESS]; if (filter.pfx.family && tb[IFA_LOCAL]) { inet_prefix dst = { .family = ifa->ifa_family }; memcpy(&dst.data, RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_LOCAL])); if (inet_addr_match(&dst, &filter.pfx, filter.pfx.bitlen)) continue; } if (filter.label) { SPRINT_BUF(b1); const char *label; if (tb[IFA_LABEL]) label = RTA_DATA(tb[IFA_LABEL]); else label = ll_idx_n2a(ifa->ifa_index, b1); if (fnmatch(filter.label, label, 0) != 0) continue; } } ok = 1; break; } if (missing_net_address && (filter.family == AF_UNSPEC || filter.family == AF_PACKET)) ok = 1; if (!ok) { *lp = l->next; free(l); } else lp = &l->next; } }
int cmd = RTM_NEWADDR, int flags = NLM_F_CREATE|NLM_F_EXCL, argc-1, argv+1
int cmd = RTM_NEWADDR, int flags = NLM_F_REPLACE, argc-1, argv+1
int cmd = RTM_NEWADDR, int flags = NLM_F_CREATE | NLM_F_REPLACE, argc-1, argv+1
int cmd = RTM_DELADDR, int flags = 0, argc-1, argv+1
static int ipaddr_modify(int cmd, int flags, int argc, char **argv) { struct { struct nlmsghdr n; struct ifaddrmsg ifa; char buf[256]; } req = { .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)), .n.nlmsg_flags = NLM_F_REQUEST | flags, .n.nlmsg_type = cmd, .ifa.ifa_family = preferred_family, }; char *d = NULL; char *l = NULL; char *lcl_arg = NULL; char *valid_lftp = NULL; char *preferred_lftp = NULL; inet_prefix lcl = {}; inet_prefix peer; int local_len = 0; int peer_len = 0; int brd_len = 0; int any_len = 0; int scoped = 0; __u32 preferred_lft = INFINITY_LIFE_TIME; __u32 valid_lft = INFINITY_LIFE_TIME; unsigned int ifa_flags = 0; while (argc > 0) { if (strcmp(*argv, "peer") == 0 || strcmp(*argv, "remote") == 0) { NEXT_ARG(); if (peer_len) duparg("peer", *argv); get_prefix(&peer, *argv, req.ifa.ifa_family); peer_len = peer.bytelen; if (req.ifa.ifa_family == AF_UNSPEC) req.ifa.ifa_family = peer.family; addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &peer.data, peer.bytelen); req.ifa.ifa_prefixlen = peer.bitlen; } else if (matches(*argv, "broadcast") == 0 || strcmp(*argv, "brd") == 0) { inet_prefix addr; NEXT_ARG(); if (brd_len) duparg("broadcast", *argv); if (strcmp(*argv, "+") == 0) brd_len = -1; else if (strcmp(*argv, "-") == 0) brd_len = -2; else { get_addr(&addr, *argv, req.ifa.ifa_family); if (req.ifa.ifa_family == AF_UNSPEC) req.ifa.ifa_family = addr.family; addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &addr.data, addr.bytelen); brd_len = addr.bytelen; } } else if (strcmp(*argv, "anycast") == 0) { inet_prefix addr; NEXT_ARG(); if (any_len) duparg("anycast", *argv); get_addr(&addr, *argv, req.ifa.ifa_family); if (req.ifa.ifa_family == AF_UNSPEC) req.ifa.ifa_family = addr.family; addattr_l(&req.n, sizeof(req), IFA_ANYCAST, &addr.data, addr.bytelen); any_len = addr.bytelen; } else if (strcmp(*argv, "scope") == 0) { unsigned int scope = 0; NEXT_ARG(); if (rtnl_rtscope_a2n(&scope, *argv)) invarg("invalid scope value.", *argv); req.ifa.ifa_scope = scope; scoped = 1; } else if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); d = *argv; } else if (strcmp(*argv, "label") == 0) { NEXT_ARG(); l = *argv; addattr_l(&req.n, sizeof(req), IFA_LABEL, l, strlen(l)+1); } else if (matches(*argv, "valid_lft") == 0) { if (valid_lftp) duparg("valid_lft", *argv); NEXT_ARG(); valid_lftp = *argv; if (set_lifetime(&valid_lft, *argv)) invarg("valid_lft value", *argv); } else if (matches(*argv, "preferred_lft") == 0) { if (preferred_lftp) duparg("preferred_lft", *argv); NEXT_ARG(); preferred_lftp = *argv; if (set_lifetime(&preferred_lft, *argv)) invarg("preferred_lft value", *argv); } else if (strcmp(*argv, "home") == 0) { ifa_flags |= IFA_F_HOMEADDRESS; } else if (strcmp(*argv, "nodad") == 0) { ifa_flags |= IFA_F_NODAD; } else if (strcmp(*argv, "mngtmpaddr") == 0) { ifa_flags |= IFA_F_MANAGETEMPADDR; } else if (strcmp(*argv, "noprefixroute") == 0) { ifa_flags |= IFA_F_NOPREFIXROUTE; } else if (strcmp(*argv, "autojoin") == 0) { ifa_flags |= IFA_F_MCAUTOJOIN; } else { if (strcmp(*argv, "local") == 0) NEXT_ARG(); if (matches(*argv, "help") == 0) usage(); if (local_len) duparg2("local", *argv); lcl_arg = *argv; get_prefix(&lcl, *argv, req.ifa.ifa_family); if (req.ifa.ifa_family == AF_UNSPEC) req.ifa.ifa_family = lcl.family; addattr_l(&req.n, sizeof(req), IFA_LOCAL, &lcl.data, lcl.bytelen); local_len = lcl.bytelen; } argc--; argv++; } if (ifa_flags <= 0xff) req.ifa.ifa_flags = ifa_flags; else addattr32(&req.n, sizeof(req), IFA_FLAGS, ifa_flags); if (d == NULL) { fprintf(stderr, "Not enough information: \"dev\" argument is required.\n"); return -1; } if (l && matches(d, l) != 0) { fprintf(stderr, "\"dev\" (%s) must match \"label\" (%s).\n", d, l); return -1; } if (peer_len == 0 && local_len) { if (cmd == RTM_DELADDR && lcl.family == AF_INET && !(lcl.flags & PREFIXLEN_SPECIFIED)) { fprintf(stderr, "Warning: Executing wildcard deletion to stay compatible with old scripts.\n" " Explicitly specify the prefix length (%s/%d) to avoid this warning.\n" " This special behaviour is likely to disappear in further releases,\n" " fix your scripts!\n", lcl_arg, local_len*8); } else { peer = lcl; addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &lcl.data, lcl.bytelen); } } if (req.ifa.ifa_prefixlen == 0) req.ifa.ifa_prefixlen = lcl.bitlen; if (brd_len < 0 && cmd != RTM_DELADDR) { inet_prefix brd; int i; if (req.ifa.ifa_family != AF_INET) { fprintf(stderr, "Broadcast can be set only for IPv4 addresses\n"); return -1; } brd = peer; if (brd.bitlen <= 30) { for (i = 31; i >= brd.bitlen; i--) { if (brd_len == -1) brd.data[0] |= htonl(1<<(31-i)); else brd.data[0] &= ~htonl(1<<(31-i)); } addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &brd.data, brd.bytelen); brd_len = brd.bytelen; } } if (!scoped && cmd != RTM_DELADDR) req.ifa.ifa_scope = default_scope(&lcl); if ((req.ifa.ifa_index = ll_name_to_index(d)) == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", d); return -1; } if (valid_lftp || preferred_lftp) { struct ifa_cacheinfo cinfo = {}; if (!valid_lft) { fprintf(stderr, "valid_lft is zero\n"); return -1; } if (valid_lft < preferred_lft) { fprintf(stderr, "preferred_lft is greater than valid_lft\n"); return -1; } cinfo.ifa_prefered = preferred_lft; cinfo.ifa_valid = valid_lft; addattr_l(&req.n, sizeof(req), IFA_CACHEINFO, &cinfo, sizeof(cinfo)); } if ((ifa_flags & IFA_F_MCAUTOJOIN) && !ipaddr_is_multicast(&lcl)) { fprintf(stderr, "autojoin needs multicast address\n"); return -1; } if (rtnl_talk(&rth, &req.n, NULL, 0) < 0) return -2; return 0; }

浙公网安备 33010602011771号