if (iplink_have_newlink()) {
fprintf(stderr,
"Usage: ip link add [link DEV] [ name ] NAME\n"
- " [ txqueuelen PACKETS ]\n"
- " [ address LLADDR ]\n"
- " [ broadcast LLADDR ]\n"
- " [ mtu MTU ] [index IDX ]\n"
- " [ numtxqueues QUEUE_COUNT ]\n"
- " [ numrxqueues QUEUE_COUNT ]\n"
- " type TYPE [ ARGS ]\n"
+ " [ txqueuelen PACKETS ]\n"
+ " [ address LLADDR ]\n"
+ " [ broadcast LLADDR ]\n"
+ " [ mtu MTU ] [index IDX ]\n"
+ " [ numtxqueues QUEUE_COUNT ]\n"
+ " [ numrxqueues QUEUE_COUNT ]\n"
+ " type TYPE [ ARGS ]\n"
"\n"
- " ip link delete { DEVICE | dev DEVICE | group DEVGROUP } type TYPE [ ARGS ]\n"
+ " ip link delete { DEVICE | dev DEVICE | group DEVGROUP } type TYPE [ ARGS ]\n"
"\n"
- " ip link set { DEVICE | dev DEVICE | group DEVGROUP }\n"
- " [ { up | down } ]\n"
- " [ type TYPE ARGS ]\n");
+ " ip link set { DEVICE | dev DEVICE | group DEVGROUP }\n"
+ " [ { up | down } ]\n"
+ " [ type TYPE ARGS ]\n");
} else
fprintf(stderr,
"Usage: ip link set DEVICE [ { up | down } ]\n");
fprintf(stderr,
- " [ arp { on | off } ]\n"
- " [ dynamic { on | off } ]\n"
- " [ multicast { on | off } ]\n"
- " [ allmulticast { on | off } ]\n"
- " [ promisc { on | off } ]\n"
- " [ trailers { on | off } ]\n"
- " [ carrier { on | off } ]\n"
- " [ txqueuelen PACKETS ]\n"
- " [ name NEWNAME ]\n"
- " [ address LLADDR ]\n"
- " [ broadcast LLADDR ]\n"
- " [ mtu MTU ]\n"
- " [ netns { PID | NAME } ]\n"
- " [ link-netns NAME | link-netnsid ID ]\n"
- " [ alias NAME ]\n"
- " [ vf NUM [ mac LLADDR ]\n"
- " [ vlan VLANID [ qos VLAN-QOS ] [ proto VLAN-PROTO ] ]\n"
- " [ rate TXRATE ]\n"
- " [ max_tx_rate TXRATE ]\n"
- " [ min_tx_rate TXRATE ]\n"
- " [ spoofchk { on | off} ]\n"
- " [ query_rss { on | off} ]\n"
- " [ state { auto | enable | disable} ] ]\n"
- " [ trust { on | off} ] ]\n"
- " [ node_guid { eui64 } ]\n"
- " [ port_guid { eui64 } ]\n"
- " [ xdp { off |\n"
+ " [ arp { on | off } ]\n"
+ " [ dynamic { on | off } ]\n"
+ " [ multicast { on | off } ]\n"
+ " [ allmulticast { on | off } ]\n"
+ " [ promisc { on | off } ]\n"
+ " [ trailers { on | off } ]\n"
+ " [ carrier { on | off } ]\n"
+ " [ txqueuelen PACKETS ]\n"
+ " [ name NEWNAME ]\n"
+ " [ address LLADDR ]\n"
+ " [ broadcast LLADDR ]\n"
+ " [ mtu MTU ]\n"
+ " [ netns { PID | NAME } ]\n"
+ " [ link-netns NAME | link-netnsid ID ]\n"
+ " [ alias NAME ]\n"
+ " [ vf NUM [ mac LLADDR ]\n"
+ " [ vlan VLANID [ qos VLAN-QOS ] [ proto VLAN-PROTO ] ]\n"
+ " [ rate TXRATE ]\n"
+ " [ max_tx_rate TXRATE ]\n"
+ " [ min_tx_rate TXRATE ]\n"
+ " [ spoofchk { on | off} ]\n"
+ " [ query_rss { on | off} ]\n"
+ " [ state { auto | enable | disable} ] ]\n"
+ " [ trust { on | off} ] ]\n"
+ " [ node_guid { eui64 } ]\n"
+ " [ port_guid { eui64 } ]\n"
+ " [ { xdp | xdpgeneric | xdpdrv | xdpoffload } { off |\n"
" object FILE [ section NAME ] [ verbose ] |\n"
" pinned FILE } ]\n"
- " [ master DEVICE ][ vrf NAME ]\n"
- " [ nomaster ]\n"
- " [ addrgenmode { eui64 | none | stable_secret | random } ]\n"
- " [ protodown { on | off } ]\n"
- " [ gso_max_size BYTES ] | [ gso_max_segs PACKETS ]\n"
+ " [ master DEVICE ][ vrf NAME ]\n"
+ " [ nomaster ]\n"
+ " [ addrgenmode { eui64 | none | stable_secret | random } ]\n"
+ " [ protodown { on | off } ]\n"
+ " [ gso_max_size BYTES ] | [ gso_max_segs PACKETS ]\n"
"\n"
- " ip link show [ DEVICE | group GROUP ] [up] [master DEV] [vrf NAME] [type TYPE]\n");
-
- fprintf(stderr, "\n ip link xstats type TYPE [ ARGS ]\n");
- fprintf(stderr, "\n ip link afstats [ dev DEVICE ]\n");
+ " ip link show [ DEVICE | group GROUP ] [up] [master DEV] [vrf NAME] [type TYPE]\n"
+ "\n"
+ " ip link xstats type TYPE [ ARGS ]\n"
+ "\n"
+ " ip link afstats [ dev DEVICE ]\n"
+ " ip link property add dev DEVICE [ altname NAME .. ]\n"
+ " ip link property del dev DEVICE [ altname NAME .. ]\n");
if (iplink_have_newlink()) {
fprintf(stderr,
"\n"
- " ip link help [ TYPE ]\n"
+ " ip link help [ TYPE ]\n"
"\n"
"TYPE := { vlan | veth | vcan | vxcan | dummy | ifb | macvlan | macvtap |\n"
- " bridge | bond | team | ipoib | ip6tnl | ipip | sit | vxlan |\n"
- " gre | gretap | erspan | ip6gre | ip6gretap | ip6erspan |\n"
- " vti | nlmon | team_slave | bond_slave | bridge_slave |\n"
- " ipvlan | ipvtap | geneve | vrf | macsec | netdevsim | rmnet }\n");
+ " bridge | bond | team | ipoib | ip6tnl | ipip | sit | vxlan |\n"
+ " gre | gretap | erspan | ip6gre | ip6gretap | ip6erspan |\n"
+ " vti | nlmon | team_slave | bond_slave | bridge_slave |\n"
+ " ipvlan | ipvtap | geneve | vrf | macsec | netdevsim | rmnet |\n"
+ " xfrm }\n");
}
exit(-1);
}
NEXT_ARG();
if (dev != name)
duparg2("dev", *argv);
- if (check_ifname(*argv))
+ if (check_altifname(*argv))
invarg("\"dev\" not a valid ifname", *argv);
dev = *argv;
}
else if (!strcmp(name, dev))
name = dev;
- if (dev && addr_len) {
+ if (dev && addr_len &&
+ !(req->n.nlmsg_flags & NLM_F_CREATE)) {
int halen = nl_get_ll_addr_len(dev);
if (halen >= 0 && halen != addr_len) {
if (rtnl_talk(&rth, &req.n, NULL) < 0)
return -2;
+ /* remove device from cache; next use can refresh with new data */
+ ll_drop_by_index(req.i.ifi_index);
+
return 0;
}
-int iplink_get(unsigned int flags, char *name, __u32 filt_mask)
+int iplink_get(char *name, __u32 filt_mask)
{
struct iplink_req req = {
.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
- .n.nlmsg_flags = NLM_F_REQUEST | flags,
+ .n.nlmsg_flags = NLM_F_REQUEST,
.n.nlmsg_type = RTM_GETLINK,
.i.ifi_family = preferred_family,
};
if (name) {
addattr_l(&req.n, sizeof(req),
- IFLA_IFNAME, name, strlen(name) + 1);
+ !check_ifname(name) ? IFLA_IFNAME : IFLA_ALT_IFNAME,
+ name, strlen(name) + 1);
}
addattr32(&req.n, sizeof(req), IFLA_EXT_MASK, filt_mask);
return 0;
}
+static int iplink_prop_mod(int argc, char **argv, struct iplink_req *req)
+{
+ struct rtattr *proplist;
+ char *dev = NULL;
+ char *name;
+
+ proplist = addattr_nest(&req->n, sizeof(*req),
+ IFLA_PROP_LIST | NLA_F_NESTED);
+
+ while (argc > 0) {
+ if (matches(*argv, "altname") == 0) {
+ NEXT_ARG();
+ if (check_altifname(*argv))
+ invarg("not a valid altname", *argv);
+ name = *argv;
+ addattr_l(&req->n, sizeof(*req), IFLA_ALT_IFNAME,
+ name, strlen(name) + 1);
+ } else if (matches(*argv, "help") == 0) {
+ usage();
+ } else {
+ if (strcmp(*argv, "dev") == 0)
+ NEXT_ARG();
+ if (dev)
+ duparg2("dev", *argv);
+ if (check_altifname(*argv))
+ invarg("\"dev\" not a valid ifname", *argv);
+ dev = *argv;
+ }
+ argv++; argc--;
+ }
+ addattr_nest_end(&req->n, proplist);
+
+ if (!dev) {
+ fprintf(stderr, "Not enough of information: \"dev\" argument is required.\n");
+ exit(-1);
+ }
+
+ req->i.ifi_index = ll_name_to_index(dev);
+ if (!req->i.ifi_index)
+ return nodev(dev);
+
+ if (rtnl_talk(&rth, &req->n, NULL) < 0)
+ return -2;
+
+ return 0;
+}
+
+static int iplink_prop(int argc, char **argv)
+{
+ struct iplink_req req = {
+ .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
+ .n.nlmsg_flags = NLM_F_REQUEST,
+ .i.ifi_family = preferred_family,
+ };
+
+ if (argc <= 0) {
+ usage();
+ exit(-1);
+ }
+
+ if (matches(*argv, "add") == 0) {
+ req.n.nlmsg_flags |= NLM_F_EXCL | NLM_F_CREATE | NLM_F_APPEND;
+ req.n.nlmsg_type = RTM_NEWLINKPROP;
+ } else if (matches(*argv, "del") == 0) {
+ req.n.nlmsg_type = RTM_DELLINKPROP;
+ } else if (matches(*argv, "help") == 0) {
+ usage();
+ } else {
+ fprintf(stderr, "Operator required\n");
+ exit(-1);
+ }
+ return iplink_prop_mod(argc - 1, argv + 1, &req);
+}
+
static void do_help(int argc, char **argv)
{
struct link_util *lu = NULL;
return 0;
}
+ if (matches(*argv, "property") == 0)
+ return iplink_prop(argc-1, argv+1);
+
if (matches(*argv, "help") == 0) {
do_help(argc-1, argv+1);
return 0;