From: David Ahern <hidden> Date: 2016-06-27 18:51:09
Currently the syntax for VRF related commands is rather kludgy and
inconsistent from one subcommand to another. This set adds support
for the VRF keyword to the link, address, neigh, and route commands
to improve the user experience listing data associated with vrfs,
modifying routes or doing a route lookup.
v2
- rebased to top of tree
- all checkpatch warnings are usage lines. The change in these
patches is consistent with existing code for usage lines
David Ahern (6):
ip vrf: Add name_is_vrf
ip link/addr: Add support for vrf keyword
ip neigh: Add support for keyword
ip route: Change type mask to bitmask
ip vrf: Add ipvrf_get_table
ip route: Add support for vrf keyword
ip/ip_common.h | 3 ++
ip/ipaddress.c | 12 +++++-
ip/iplink.c | 15 ++++++-
ip/iplink_vrf.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ip/ipneigh.c | 14 ++++++-
ip/iproute.c | 43 ++++++++++++++++----
6 files changed, 195 insertions(+), 11 deletions(-)
--
2.1.4
From: David Ahern <hidden> Date: 2016-06-27 18:51:10
Add name_is_vrf function to determine if given name corresponds to a
VRF device.
Signed-off-by: David Ahern <redacted>
---
ip/ip_common.h | 2 ++
ip/iplink_vrf.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 55 insertions(+)
From: David Ahern <hidden> Date: 2016-06-27 18:51:11
Add vrf keyword to 'ip neigh' commands. Allows listing neighbor
entries for all links associated with a given VRF.
Signed-off-by: David Ahern <redacted>
---
ip/ipneigh.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
@@ -48,7 +48,8 @@ static void usage(void){fprintf(stderr,"Usage: ip neigh { add | del | change | replace }\n"" { ADDR [ lladdr LLADDR ] [ nud STATE ] | proxy ADDR } [ dev DEV ]\n");-fprintf(stderr," ip neigh { show | flush } [ proxy ] [ to PREFIX ] [ dev DEV ] [ nud STATE ]\n\n");+fprintf(stderr," ip neigh { show | flush } [ proxy ] [ to PREFIX ] [ dev DEV ] [ nud STATE ]\n");+fprintf(stderr," [ vrf NAME ]\n\n");fprintf(stderr,"STATE := { permanent | noarp | stale | reachable | none |\n"" incomplete | delay | probe | failed }\n");exit(-1);
@@ -385,6 +386,17 @@ static int do_show_or_flush(int argc, char **argv, int flush)invarg("Device does not exist\n",*argv);addattr32(&req.n,sizeof(req),NDA_MASTER,ifindex);filter.master=ifindex;+}elseif(strcmp(*argv,"vrf")==0){+intifindex;++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);+addattr32(&req.n,sizeof(req),NDA_MASTER,ifindex);+filter.master=ifindex;}elseif(strcmp(*argv,"unused")==0){filter.unused_only=1;}elseif(strcmp(*argv,"nud")==0){
From: David Ahern <hidden> Date: 2016-06-27 18:51:11
Add vrf keyword to 'ip link' and 'ip addr' commands (common list code).
Allows:
1. Adding a link to a VRF
$ ip link set NAME vrf NAME
Removing a link from a VRF still uses 'ip link set NAME nomaster'
2. Showing links associated with a VRF:
$ ip link show vrf NAME
3. List addresses associated with links in a VRF
$ ip -br addr show vrf red
Signed-off-by: David Ahern <redacted>
---
ip/ipaddress.c | 12 +++++++++++-
ip/iplink.c | 15 +++++++++++++--
2 files changed, 24 insertions(+), 3 deletions(-)
@@ -79,7 +79,7 @@ static void usage(void)fprintf(stderr," [ to PREFIX ] [ FLAG-LIST ] [ label LABEL ] [up]\n");fprintf(stderr," ip address [ show [ dev IFNAME ] [ scope SCOPE-ID ] [ master DEVICE ]\n");fprintf(stderr," [ type TYPE ] [ to PREFIX ] [ FLAG-LIST ]\n");-fprintf(stderr," [ label LABEL ] [up] ]\n");+fprintf(stderr," [ label LABEL ] [up] [ vrf NAME ] ]\n");fprintf(stderr," ip address {showdump|restore}\n");fprintf(stderr,"IFADDR := PREFIX | ADDR peer PREFIX\n");fprintf(stderr," [ broadcast ADDR ] [ anycast ADDR ]\n");
@@ -1620,6 +1620,16 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action)if(!ifindex)invarg("Device does not exist\n",*argv);filter.master=ifindex;+}elseif(strcmp(*argv,"vrf")==0){+intifindex;++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;}elseif(strcmp(*argv,"type")==0){NEXT_ARG();filter.kind=*argv;
@@ -82,11 +82,11 @@ void iplink_usage(void)fprintf(stderr," [ query_rss { on | off} ]\n");fprintf(stderr," [ state { auto | enable | disable} ] ]\n");fprintf(stderr," [ trust { on | off} ] ]\n");-fprintf(stderr," [ master DEVICE ]\n");+fprintf(stderr," [ master DEVICE ][ vrf NAME ]\n");fprintf(stderr," [ nomaster ]\n");fprintf(stderr," [ addrgenmode { eui64 | none | stable_secret | random } ]\n");fprintf(stderr," [ protodown { on | off } ]\n");-fprintf(stderr," ip link show [ DEVICE | group GROUP ] [up] [master DEV] [type TYPE]\n");+fprintf(stderr," ip link show [ DEVICE | group GROUP ] [up] [master DEV] [vrf NAME] [type TYPE]\n");if(iplink_have_newlink()){fprintf(stderr," ip link help [ TYPE ]\n");
@@ -603,6 +603,17 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,invarg("Device does not exist\n",*argv);addattr_l(&req->n,sizeof(*req),IFLA_MASTER,&ifindex,4);+}elseif(strcmp(*argv,"vrf")==0){+intifindex;++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);+addattr_l(&req->n,sizeof(*req),IFLA_MASTER,+&ifindex,sizeof(ifindex));}elseif(matches(*argv,"nomaster")==0){intifindex=0;
From: David Ahern <hidden> Date: 2016-06-27 18:51:12
Allow option to select multiple route types to show or exlude
specific route types.
Signed-off-by: David Ahern <redacted>
---
ip/iproute.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
@@ -1433,10 +1435,9 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action)inttype;NEXT_ARG();-filter.typemask=-1;if(rtnl_rtntype_a2n(&type,*argv))invarg("node type value is invalid\n",*argv);-filter.type=type;+filter.typemask=(1<<type);}elseif(strcmp(*argv,"dev")==0||strcmp(*argv,"oif")==0){NEXT_ARG();
From: David Ahern <hidden> Date: 2016-06-27 18:51:13
Add ipvrf_get_table to lookup table id for device name. Returns 0
on any error or if name is not a VRF device.
Signed-off-by: David Ahern <redacted>
---
ip/ip_common.h | 1 +
ip/iplink_vrf.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 67 insertions(+)
@@ -97,6 +97,72 @@ struct link_util vrf_slave_link_util = {.slave=true,};+/* returns table id if name is a VRF device */+__u32ipvrf_get_table(char*name)+{+struct{+structnlmsghdrn;+structifinfomsgi;+charbuf[1024];+}req={+.n={+.nlmsg_len=NLMSG_LENGTH(sizeof(structifinfomsg)),+.nlmsg_flags=NLM_F_REQUEST,+.nlmsg_type=RTM_GETLINK,+},+.i={+.ifi_family=preferred_family,+},+};+struct{+structnlmsghdrn;+charbuf[8192];+}answer;+structrtattr*tb[IFLA_MAX+1];+structrtattr*li[IFLA_INFO_MAX+1];+structrtattr*vrf_attr[IFLA_VRF_MAX+1];+structifinfomsg*ifi;+__u32tb_id=0;+intlen;++addattr_l(&req.n,sizeof(req),IFLA_IFNAME,name,strlen(name)+1);++if(rtnl_talk(&rth,&req.n,&answer.n,sizeof(answer))<0)+gotoerr;++ifi=NLMSG_DATA(&answer.n);+len=answer.n.nlmsg_len-NLMSG_LENGTH(sizeof(*ifi));+if(len<0){+fprintf(stderr,"BUG: Invalid response to link query.\n");+gotoerr;+}++parse_rtattr(tb,IFLA_MAX,IFLA_RTA(ifi),len);++if(!tb[IFLA_LINKINFO])+gotoerr;++parse_rtattr_nested(li,IFLA_INFO_MAX,tb[IFLA_LINKINFO]);++if(!li[IFLA_INFO_KIND]||!li[IFLA_INFO_DATA])+gotoerr;++if(strcmp(RTA_DATA(li[IFLA_INFO_KIND]),"vrf"))+gotoerr;++parse_rtattr_nested(vrf_attr,IFLA_VRF_MAX,li[IFLA_INFO_DATA]);+if(vrf_attr[IFLA_VRF_TABLE])+tb_id=rta_getattr_u32(vrf_attr[IFLA_VRF_TABLE]);++if(!tb_id)+fprintf(stderr,"BUG: VRF %s is missing table id\n",name);++returntb_id;++err:+return0;+}+boolname_is_vrf(char*name){struct{
From: David Ahern <hidden> Date: 2016-06-27 18:51:15
Add vrf keyword to 'ip route' commands. Allows:
1. Users can list routes by VRF name:
$ ip route show vrf NAME
VRF tables have all routes including local and broadcast routes.
The VRF keyword filters LOCAL and BROADCAST routes; to see all
routes the table option can be used. Or to see local routes only
for a VRF:
$ ip route show vrf NAME type local
2. Add or delete a route for a VRF:
$ ip route {add|delete} vrf NAME <route spec>
3. Do a route lookup for a VRF:
$ ip route get vrf NAME ADDRESS
Signed-off-by: David Ahern <redacted>
---
ip/iproute.c | 32 ++++++++++++++++++++++++++++++--
1 file changed, 30 insertions(+), 2 deletions(-)
@@ -67,10 +67,10 @@ static void usage(void)fprintf(stderr," ip route showdump\n");fprintf(stderr," ip route get ADDRESS [ from ADDRESS iif STRING ]\n");fprintf(stderr," [ oif STRING ] [ tos TOS ]\n");-fprintf(stderr," [ mark NUMBER ]\n");+fprintf(stderr," [ mark NUMBER ] [ vrf NAME ]\n");fprintf(stderr," ip route { add | del | change | append | replace } ROUTE\n");fprintf(stderr,"SELECTOR := [ root PREFIX ] [ match PREFIX ] [ exact PREFIX ]\n");-fprintf(stderr," [ table TABLE_ID ] [ proto RTPROTO ]\n");+fprintf(stderr," [ table TABLE_ID ] [ vrf NAME ] [ proto RTPROTO ]\n");fprintf(stderr," [ type TYPE ] [ scope SCOPE ]\n");fprintf(stderr,"ROUTE := NODE_SPEC [ INFO_SPEC ]\n");fprintf(stderr,"NODE_SPEC := [ TYPE ] PREFIX [ tos TOS ]\n");
@@ -1141,6 +1141,20 @@ static int iproute_modify(int cmd, unsigned int flags, int argc, char **argv)addattr32(&req.n,sizeof(req),RTA_TABLE,tid);}table_ok=1;+}elseif(matches(*argv,"vrf")==0){+__u32tid;++NEXT_ARG();+tid=ipvrf_get_table(*argv);+if(tid==0)+invarg("Invalid VRF\n",*argv);+if(tid<256)+req.r.rtm_table=tid;+else{+req.r.rtm_table=RT_TABLE_UNSPEC;+addattr32(&req.n,sizeof(req),RTA_TABLE,tid);+}+table_ok=1;}elseif(strcmp(*argv,"dev")==0||strcmp(*argv,"oif")==0){NEXT_ARG();
@@ -1395,6 +1409,15 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action)}}elsefilter.tb=tid;+}elseif(matches(*argv,"vrf")==0){+__u32tid;++NEXT_ARG();+tid=ipvrf_get_table(*argv);+if(tid==0)+invarg("Invalid VRF\n",*argv);+filter.tb=tid;+filter.typemask=~(1<<RTN_LOCAL|1<<RTN_BROADCAST);}elseif(matches(*argv,"cached")==0||matches(*argv,"cloned")==0){filter.cloned=1;
From: Stephen Hemminger <stephen@networkplumber.org> Date: 2016-06-29 15:16:10
On Mon, 27 Jun 2016 11:50:55 -0700
David Ahern [off-list ref] wrote:
Currently the syntax for VRF related commands is rather kludgy and
inconsistent from one subcommand to another. This set adds support
for the VRF keyword to the link, address, neigh, and route commands
to improve the user experience listing data associated with vrfs,
modifying routes or doing a route lookup.
v2
- rebased to top of tree
- all checkpatch warnings are usage lines. The change in these
patches is consistent with existing code for usage lines
Does this break current user scripts?
It seems this method will cause lots of additional netlink requests
to check if device is a vrf. Won't this impact users with 1000's of devices?
Just return false instead of all these goto's?
Also you might want to give some indication of error.
Any failure and the user gets the message "not a VRF". The reason can be
the device is not a VRF or the device does not exist but that's the same
thing in this case:
$ ./ip link show vrf foo
Error: argument "foo" is wrong: Not a valid VRF name
$ ./ip link show vrf eth1
Error: argument "eth1" is wrong: Not a valid VRF name
From: David Ahern <hidden> Date: 2016-06-29 17:06:12
On 6/29/16 9:07 AM, Stephen Hemminger wrote:
On Mon, 27 Jun 2016 11:50:55 -0700
David Ahern [off-list ref] wrote:
quoted
Currently the syntax for VRF related commands is rather kludgy and
inconsistent from one subcommand to another. This set adds support
for the VRF keyword to the link, address, neigh, and route commands
to improve the user experience listing data associated with vrfs,
modifying routes or doing a route lookup.
v2
- rebased to top of tree
- all checkpatch warnings are usage lines. The change in these
patches is consistent with existing code for usage lines
Does this break current user scripts?
I don't see how it can. Existing syntax is not touched so if a user
wants to run:
$ ip link show master red
$ ip ro sh table 1001
it still works. Using the vrf keyword just makes for a more natural syntax:
$ ip link show vrf red
$ ip ro sh vrf red
in this case I don't have to lookup what table device red is associated
with ip learns it and shows that table.
It seems this method will cause lots of additional netlink requests
to check if device is a vrf. Won't this impact users with 1000's of devices?
It only adds 1 GETLINK request if the vrf keyword is used. The lookup
verifies the name is actually a VRF. It's really no different than the
ll_name_to_index lookups used when processing the command line
(ll_name_to_index relies on a cache or an ioctl, if_nametoindex).