1*de1e4e89SAndroid Build Coastguard Worker /* iplink_vrf.c VRF device support
2*de1e4e89SAndroid Build Coastguard Worker *
3*de1e4e89SAndroid Build Coastguard Worker * This program is free software; you can redistribute it and/or
4*de1e4e89SAndroid Build Coastguard Worker * modify it under the terms of the GNU General Public License
5*de1e4e89SAndroid Build Coastguard Worker * as published by the Free Software Foundation; either version
6*de1e4e89SAndroid Build Coastguard Worker * 2 of the License, or (at your option) any later version.
7*de1e4e89SAndroid Build Coastguard Worker *
8*de1e4e89SAndroid Build Coastguard Worker * Authors: Shrijeet Mukherjee <[email protected]>
9*de1e4e89SAndroid Build Coastguard Worker */
10*de1e4e89SAndroid Build Coastguard Worker
11*de1e4e89SAndroid Build Coastguard Worker #include <stdio.h>
12*de1e4e89SAndroid Build Coastguard Worker #include <stdlib.h>
13*de1e4e89SAndroid Build Coastguard Worker #include <string.h>
14*de1e4e89SAndroid Build Coastguard Worker #include <sys/socket.h>
15*de1e4e89SAndroid Build Coastguard Worker #include <linux/if_link.h>
16*de1e4e89SAndroid Build Coastguard Worker #include <errno.h>
17*de1e4e89SAndroid Build Coastguard Worker
18*de1e4e89SAndroid Build Coastguard Worker #include "rt_names.h"
19*de1e4e89SAndroid Build Coastguard Worker #include "utils.h"
20*de1e4e89SAndroid Build Coastguard Worker #include "ip_common.h"
21*de1e4e89SAndroid Build Coastguard Worker
vrf_explain(FILE * f)22*de1e4e89SAndroid Build Coastguard Worker static void vrf_explain(FILE *f)
23*de1e4e89SAndroid Build Coastguard Worker {
24*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "Usage: ... vrf table TABLEID\n");
25*de1e4e89SAndroid Build Coastguard Worker }
26*de1e4e89SAndroid Build Coastguard Worker
explain(void)27*de1e4e89SAndroid Build Coastguard Worker static void explain(void)
28*de1e4e89SAndroid Build Coastguard Worker {
29*de1e4e89SAndroid Build Coastguard Worker vrf_explain(stderr);
30*de1e4e89SAndroid Build Coastguard Worker }
31*de1e4e89SAndroid Build Coastguard Worker
vrf_parse_opt(struct link_util * lu,int argc,char ** argv,struct nlmsghdr * n)32*de1e4e89SAndroid Build Coastguard Worker static int vrf_parse_opt(struct link_util *lu, int argc, char **argv,
33*de1e4e89SAndroid Build Coastguard Worker struct nlmsghdr *n)
34*de1e4e89SAndroid Build Coastguard Worker {
35*de1e4e89SAndroid Build Coastguard Worker while (argc > 0) {
36*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "table") == 0) {
37*de1e4e89SAndroid Build Coastguard Worker __u32 table;
38*de1e4e89SAndroid Build Coastguard Worker
39*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
40*de1e4e89SAndroid Build Coastguard Worker
41*de1e4e89SAndroid Build Coastguard Worker if (rtnl_rttable_a2n(&table, *argv))
42*de1e4e89SAndroid Build Coastguard Worker invarg("invalid table ID\n", *argv);
43*de1e4e89SAndroid Build Coastguard Worker addattr32(n, 1024, IFLA_VRF_TABLE, table);
44*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "help") == 0) {
45*de1e4e89SAndroid Build Coastguard Worker explain();
46*de1e4e89SAndroid Build Coastguard Worker return -1;
47*de1e4e89SAndroid Build Coastguard Worker } else {
48*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "vrf: unknown option \"%s\"?\n",
49*de1e4e89SAndroid Build Coastguard Worker *argv);
50*de1e4e89SAndroid Build Coastguard Worker explain();
51*de1e4e89SAndroid Build Coastguard Worker return -1;
52*de1e4e89SAndroid Build Coastguard Worker }
53*de1e4e89SAndroid Build Coastguard Worker argc--, argv++;
54*de1e4e89SAndroid Build Coastguard Worker }
55*de1e4e89SAndroid Build Coastguard Worker
56*de1e4e89SAndroid Build Coastguard Worker return 0;
57*de1e4e89SAndroid Build Coastguard Worker }
58*de1e4e89SAndroid Build Coastguard Worker
vrf_print_opt(struct link_util * lu,FILE * f,struct rtattr * tb[])59*de1e4e89SAndroid Build Coastguard Worker static void vrf_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
60*de1e4e89SAndroid Build Coastguard Worker {
61*de1e4e89SAndroid Build Coastguard Worker if (!tb)
62*de1e4e89SAndroid Build Coastguard Worker return;
63*de1e4e89SAndroid Build Coastguard Worker
64*de1e4e89SAndroid Build Coastguard Worker if (tb[IFLA_VRF_TABLE])
65*de1e4e89SAndroid Build Coastguard Worker print_uint(PRINT_ANY,
66*de1e4e89SAndroid Build Coastguard Worker "table",
67*de1e4e89SAndroid Build Coastguard Worker "table %u ",
68*de1e4e89SAndroid Build Coastguard Worker rta_getattr_u32(tb[IFLA_VRF_TABLE]));
69*de1e4e89SAndroid Build Coastguard Worker }
70*de1e4e89SAndroid Build Coastguard Worker
vrf_slave_print_opt(struct link_util * lu,FILE * f,struct rtattr * tb[])71*de1e4e89SAndroid Build Coastguard Worker static void vrf_slave_print_opt(struct link_util *lu, FILE *f,
72*de1e4e89SAndroid Build Coastguard Worker struct rtattr *tb[])
73*de1e4e89SAndroid Build Coastguard Worker {
74*de1e4e89SAndroid Build Coastguard Worker if (!tb)
75*de1e4e89SAndroid Build Coastguard Worker return;
76*de1e4e89SAndroid Build Coastguard Worker
77*de1e4e89SAndroid Build Coastguard Worker if (tb[IFLA_VRF_PORT_TABLE]) {
78*de1e4e89SAndroid Build Coastguard Worker print_uint(PRINT_ANY,
79*de1e4e89SAndroid Build Coastguard Worker "table",
80*de1e4e89SAndroid Build Coastguard Worker "table %u ",
81*de1e4e89SAndroid Build Coastguard Worker rta_getattr_u32(tb[IFLA_VRF_PORT_TABLE]));
82*de1e4e89SAndroid Build Coastguard Worker }
83*de1e4e89SAndroid Build Coastguard Worker }
84*de1e4e89SAndroid Build Coastguard Worker
vrf_print_help(struct link_util * lu,int argc,char ** argv,FILE * f)85*de1e4e89SAndroid Build Coastguard Worker static void vrf_print_help(struct link_util *lu, int argc, char **argv,
86*de1e4e89SAndroid Build Coastguard Worker FILE *f)
87*de1e4e89SAndroid Build Coastguard Worker {
88*de1e4e89SAndroid Build Coastguard Worker vrf_explain(f);
89*de1e4e89SAndroid Build Coastguard Worker }
90*de1e4e89SAndroid Build Coastguard Worker
91*de1e4e89SAndroid Build Coastguard Worker struct link_util vrf_link_util = {
92*de1e4e89SAndroid Build Coastguard Worker .id = "vrf",
93*de1e4e89SAndroid Build Coastguard Worker .maxattr = IFLA_VRF_MAX,
94*de1e4e89SAndroid Build Coastguard Worker .parse_opt = vrf_parse_opt,
95*de1e4e89SAndroid Build Coastguard Worker .print_opt = vrf_print_opt,
96*de1e4e89SAndroid Build Coastguard Worker .print_help = vrf_print_help,
97*de1e4e89SAndroid Build Coastguard Worker };
98*de1e4e89SAndroid Build Coastguard Worker
99*de1e4e89SAndroid Build Coastguard Worker struct link_util vrf_slave_link_util = {
100*de1e4e89SAndroid Build Coastguard Worker .id = "vrf_slave",
101*de1e4e89SAndroid Build Coastguard Worker .maxattr = IFLA_VRF_PORT_MAX,
102*de1e4e89SAndroid Build Coastguard Worker .print_opt = vrf_slave_print_opt,
103*de1e4e89SAndroid Build Coastguard Worker };
104*de1e4e89SAndroid Build Coastguard Worker
105*de1e4e89SAndroid Build Coastguard Worker /* returns table id if name is a VRF device */
ipvrf_get_table(const char * name)106*de1e4e89SAndroid Build Coastguard Worker __u32 ipvrf_get_table(const char *name)
107*de1e4e89SAndroid Build Coastguard Worker {
108*de1e4e89SAndroid Build Coastguard Worker struct {
109*de1e4e89SAndroid Build Coastguard Worker struct nlmsghdr n;
110*de1e4e89SAndroid Build Coastguard Worker struct ifinfomsg i;
111*de1e4e89SAndroid Build Coastguard Worker char buf[1024];
112*de1e4e89SAndroid Build Coastguard Worker } req = {
113*de1e4e89SAndroid Build Coastguard Worker .n = {
114*de1e4e89SAndroid Build Coastguard Worker .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
115*de1e4e89SAndroid Build Coastguard Worker .nlmsg_flags = NLM_F_REQUEST,
116*de1e4e89SAndroid Build Coastguard Worker .nlmsg_type = RTM_GETLINK,
117*de1e4e89SAndroid Build Coastguard Worker },
118*de1e4e89SAndroid Build Coastguard Worker .i = {
119*de1e4e89SAndroid Build Coastguard Worker .ifi_family = preferred_family,
120*de1e4e89SAndroid Build Coastguard Worker },
121*de1e4e89SAndroid Build Coastguard Worker };
122*de1e4e89SAndroid Build Coastguard Worker struct {
123*de1e4e89SAndroid Build Coastguard Worker struct nlmsghdr n;
124*de1e4e89SAndroid Build Coastguard Worker char buf[8192];
125*de1e4e89SAndroid Build Coastguard Worker } answer;
126*de1e4e89SAndroid Build Coastguard Worker struct rtattr *tb[IFLA_MAX+1];
127*de1e4e89SAndroid Build Coastguard Worker struct rtattr *li[IFLA_INFO_MAX+1];
128*de1e4e89SAndroid Build Coastguard Worker struct rtattr *vrf_attr[IFLA_VRF_MAX + 1];
129*de1e4e89SAndroid Build Coastguard Worker struct ifinfomsg *ifi;
130*de1e4e89SAndroid Build Coastguard Worker __u32 tb_id = 0;
131*de1e4e89SAndroid Build Coastguard Worker int len;
132*de1e4e89SAndroid Build Coastguard Worker
133*de1e4e89SAndroid Build Coastguard Worker addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name, strlen(name) + 1);
134*de1e4e89SAndroid Build Coastguard Worker
135*de1e4e89SAndroid Build Coastguard Worker if (rtnl_talk_suppress_rtnl_errmsg(&rth, &req.n,
136*de1e4e89SAndroid Build Coastguard Worker &answer.n, sizeof(answer)) < 0) {
137*de1e4e89SAndroid Build Coastguard Worker /* special case "default" vrf to be the main table */
138*de1e4e89SAndroid Build Coastguard Worker if (errno == ENODEV && !strcmp(name, "default"))
139*de1e4e89SAndroid Build Coastguard Worker if (rtnl_rttable_a2n(&tb_id, "main"))
140*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr,
141*de1e4e89SAndroid Build Coastguard Worker "BUG: RTTable \"main\" not found.\n");
142*de1e4e89SAndroid Build Coastguard Worker
143*de1e4e89SAndroid Build Coastguard Worker return tb_id;
144*de1e4e89SAndroid Build Coastguard Worker }
145*de1e4e89SAndroid Build Coastguard Worker
146*de1e4e89SAndroid Build Coastguard Worker ifi = NLMSG_DATA(&answer.n);
147*de1e4e89SAndroid Build Coastguard Worker len = answer.n.nlmsg_len - NLMSG_LENGTH(sizeof(*ifi));
148*de1e4e89SAndroid Build Coastguard Worker if (len < 0) {
149*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "BUG: Invalid response to link query.\n");
150*de1e4e89SAndroid Build Coastguard Worker return 0;
151*de1e4e89SAndroid Build Coastguard Worker }
152*de1e4e89SAndroid Build Coastguard Worker
153*de1e4e89SAndroid Build Coastguard Worker parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
154*de1e4e89SAndroid Build Coastguard Worker
155*de1e4e89SAndroid Build Coastguard Worker if (!tb[IFLA_LINKINFO])
156*de1e4e89SAndroid Build Coastguard Worker return 0;
157*de1e4e89SAndroid Build Coastguard Worker
158*de1e4e89SAndroid Build Coastguard Worker parse_rtattr_nested(li, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
159*de1e4e89SAndroid Build Coastguard Worker
160*de1e4e89SAndroid Build Coastguard Worker if (!li[IFLA_INFO_KIND] || !li[IFLA_INFO_DATA])
161*de1e4e89SAndroid Build Coastguard Worker return 0;
162*de1e4e89SAndroid Build Coastguard Worker
163*de1e4e89SAndroid Build Coastguard Worker if (strcmp(RTA_DATA(li[IFLA_INFO_KIND]), "vrf"))
164*de1e4e89SAndroid Build Coastguard Worker return 0;
165*de1e4e89SAndroid Build Coastguard Worker
166*de1e4e89SAndroid Build Coastguard Worker parse_rtattr_nested(vrf_attr, IFLA_VRF_MAX, li[IFLA_INFO_DATA]);
167*de1e4e89SAndroid Build Coastguard Worker if (vrf_attr[IFLA_VRF_TABLE])
168*de1e4e89SAndroid Build Coastguard Worker tb_id = rta_getattr_u32(vrf_attr[IFLA_VRF_TABLE]);
169*de1e4e89SAndroid Build Coastguard Worker
170*de1e4e89SAndroid Build Coastguard Worker if (!tb_id)
171*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "BUG: VRF %s is missing table id\n", name);
172*de1e4e89SAndroid Build Coastguard Worker
173*de1e4e89SAndroid Build Coastguard Worker return tb_id;
174*de1e4e89SAndroid Build Coastguard Worker }
175*de1e4e89SAndroid Build Coastguard Worker
name_is_vrf(const char * name)176*de1e4e89SAndroid Build Coastguard Worker int name_is_vrf(const char *name)
177*de1e4e89SAndroid Build Coastguard Worker {
178*de1e4e89SAndroid Build Coastguard Worker struct {
179*de1e4e89SAndroid Build Coastguard Worker struct nlmsghdr n;
180*de1e4e89SAndroid Build Coastguard Worker struct ifinfomsg i;
181*de1e4e89SAndroid Build Coastguard Worker char buf[1024];
182*de1e4e89SAndroid Build Coastguard Worker } req = {
183*de1e4e89SAndroid Build Coastguard Worker .n = {
184*de1e4e89SAndroid Build Coastguard Worker .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
185*de1e4e89SAndroid Build Coastguard Worker .nlmsg_flags = NLM_F_REQUEST,
186*de1e4e89SAndroid Build Coastguard Worker .nlmsg_type = RTM_GETLINK,
187*de1e4e89SAndroid Build Coastguard Worker },
188*de1e4e89SAndroid Build Coastguard Worker .i = {
189*de1e4e89SAndroid Build Coastguard Worker .ifi_family = preferred_family,
190*de1e4e89SAndroid Build Coastguard Worker },
191*de1e4e89SAndroid Build Coastguard Worker };
192*de1e4e89SAndroid Build Coastguard Worker struct {
193*de1e4e89SAndroid Build Coastguard Worker struct nlmsghdr n;
194*de1e4e89SAndroid Build Coastguard Worker char buf[8192];
195*de1e4e89SAndroid Build Coastguard Worker } answer;
196*de1e4e89SAndroid Build Coastguard Worker struct rtattr *tb[IFLA_MAX+1];
197*de1e4e89SAndroid Build Coastguard Worker struct rtattr *li[IFLA_INFO_MAX+1];
198*de1e4e89SAndroid Build Coastguard Worker struct ifinfomsg *ifi;
199*de1e4e89SAndroid Build Coastguard Worker int len;
200*de1e4e89SAndroid Build Coastguard Worker
201*de1e4e89SAndroid Build Coastguard Worker addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name, strlen(name) + 1);
202*de1e4e89SAndroid Build Coastguard Worker
203*de1e4e89SAndroid Build Coastguard Worker if (rtnl_talk_suppress_rtnl_errmsg(&rth, &req.n,
204*de1e4e89SAndroid Build Coastguard Worker &answer.n, sizeof(answer)) < 0)
205*de1e4e89SAndroid Build Coastguard Worker return 0;
206*de1e4e89SAndroid Build Coastguard Worker
207*de1e4e89SAndroid Build Coastguard Worker ifi = NLMSG_DATA(&answer.n);
208*de1e4e89SAndroid Build Coastguard Worker len = answer.n.nlmsg_len - NLMSG_LENGTH(sizeof(*ifi));
209*de1e4e89SAndroid Build Coastguard Worker if (len < 0) {
210*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "BUG: Invalid response to link query.\n");
211*de1e4e89SAndroid Build Coastguard Worker return 0;
212*de1e4e89SAndroid Build Coastguard Worker }
213*de1e4e89SAndroid Build Coastguard Worker
214*de1e4e89SAndroid Build Coastguard Worker parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
215*de1e4e89SAndroid Build Coastguard Worker
216*de1e4e89SAndroid Build Coastguard Worker if (!tb[IFLA_LINKINFO])
217*de1e4e89SAndroid Build Coastguard Worker return 0;
218*de1e4e89SAndroid Build Coastguard Worker
219*de1e4e89SAndroid Build Coastguard Worker parse_rtattr_nested(li, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
220*de1e4e89SAndroid Build Coastguard Worker
221*de1e4e89SAndroid Build Coastguard Worker if (!li[IFLA_INFO_KIND])
222*de1e4e89SAndroid Build Coastguard Worker return 0;
223*de1e4e89SAndroid Build Coastguard Worker
224*de1e4e89SAndroid Build Coastguard Worker if (strcmp(RTA_DATA(li[IFLA_INFO_KIND]), "vrf"))
225*de1e4e89SAndroid Build Coastguard Worker return 0;
226*de1e4e89SAndroid Build Coastguard Worker
227*de1e4e89SAndroid Build Coastguard Worker return ifi->ifi_index;
228*de1e4e89SAndroid Build Coastguard Worker }
229