]> git.proxmox.com Git - mirror_iproute2.git/blob - ip/link_vti.c
ip/tunnel: Unify setup and accept zero address for local/remote endpoints
[mirror_iproute2.git] / ip / link_vti.c
1 /*
2 * link_vti.c VTI driver module
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * Authors: Herbert Xu <herbert@gondor.apana.org.au>
10 * Saurabh Mohan <saurabh.mohan@vyatta.com> Modified link_gre.c for VTI
11 */
12
13 #include <string.h>
14 #include <net/if.h>
15 #include <sys/types.h>
16 #include <sys/socket.h>
17 #include <arpa/inet.h>
18
19 #include <linux/ip.h>
20 #include <linux/if_tunnel.h>
21 #include "rt_names.h"
22 #include "utils.h"
23 #include "ip_common.h"
24 #include "tunnel.h"
25
26
27 static void print_usage(FILE *f)
28 {
29 fprintf(f,
30 "Usage: ... vti [ remote ADDR ]\n"
31 " [ local ADDR ]\n"
32 " [ [i|o]key KEY ]\n"
33 " [ dev PHYS_DEV ]\n"
34 " [ fwmark MARK ]\n"
35 "\n"
36 "Where: ADDR := { IP_ADDRESS }\n"
37 " KEY := { DOTTED_QUAD | NUMBER }\n"
38 " MARK := { 0x0..0xffffffff }\n"
39 );
40 }
41
42 static void usage(void) __attribute__((noreturn));
43 static void usage(void)
44 {
45 print_usage(stderr);
46 exit(-1);
47 }
48
49 static int vti_parse_opt(struct link_util *lu, int argc, char **argv,
50 struct nlmsghdr *n)
51 {
52 struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1);
53 struct {
54 struct nlmsghdr n;
55 struct ifinfomsg i;
56 } req = {
57 .n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)),
58 .n.nlmsg_flags = NLM_F_REQUEST,
59 .n.nlmsg_type = RTM_GETLINK,
60 .i.ifi_family = preferred_family,
61 .i.ifi_index = ifi->ifi_index,
62 };
63 struct nlmsghdr *answer = NULL;
64 struct rtattr *tb[IFLA_MAX + 1];
65 struct rtattr *linkinfo[IFLA_INFO_MAX+1];
66 struct rtattr *vtiinfo[IFLA_VTI_MAX + 1];
67 unsigned int ikey = 0;
68 unsigned int okey = 0;
69 unsigned int saddr = 0;
70 unsigned int daddr = 0;
71 unsigned int link = 0;
72 unsigned int fwmark = 0;
73 int len;
74
75 if (!(n->nlmsg_flags & NLM_F_CREATE)) {
76 if (rtnl_talk(&rth, &req.n, &answer) < 0) {
77 get_failed:
78 fprintf(stderr,
79 "Failed to get existing tunnel info.\n");
80 free(answer);
81 return -1;
82 }
83
84 len = answer->nlmsg_len;
85 len -= NLMSG_LENGTH(sizeof(*ifi));
86 if (len < 0)
87 goto get_failed;
88
89 parse_rtattr(tb, IFLA_MAX, IFLA_RTA(NLMSG_DATA(answer)), len);
90
91 if (!tb[IFLA_LINKINFO])
92 goto get_failed;
93
94 parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
95
96 if (!linkinfo[IFLA_INFO_DATA])
97 goto get_failed;
98
99 parse_rtattr_nested(vtiinfo, IFLA_VTI_MAX,
100 linkinfo[IFLA_INFO_DATA]);
101
102 if (vtiinfo[IFLA_VTI_IKEY])
103 ikey = rta_getattr_u32(vtiinfo[IFLA_VTI_IKEY]);
104
105 if (vtiinfo[IFLA_VTI_OKEY])
106 okey = rta_getattr_u32(vtiinfo[IFLA_VTI_OKEY]);
107
108 if (vtiinfo[IFLA_VTI_LOCAL])
109 saddr = rta_getattr_u32(vtiinfo[IFLA_VTI_LOCAL]);
110
111 if (vtiinfo[IFLA_VTI_REMOTE])
112 daddr = rta_getattr_u32(vtiinfo[IFLA_VTI_REMOTE]);
113
114 if (vtiinfo[IFLA_VTI_LINK])
115 link = rta_getattr_u8(vtiinfo[IFLA_VTI_LINK]);
116
117 if (vtiinfo[IFLA_VTI_FWMARK])
118 fwmark = rta_getattr_u32(vtiinfo[IFLA_VTI_FWMARK]);
119
120 free(answer);
121 }
122
123 while (argc > 0) {
124 if (!matches(*argv, "key")) {
125 unsigned int uval;
126
127 NEXT_ARG();
128 if (strchr(*argv, '.'))
129 uval = get_addr32(*argv);
130 else {
131 if (get_unsigned(&uval, *argv, 0) < 0) {
132 fprintf(stderr,
133 "Invalid value for \"key\": \"%s\"; it should be an unsigned integer\n", *argv);
134 exit(-1);
135 }
136 uval = htonl(uval);
137 }
138
139 ikey = okey = uval;
140 } else if (!matches(*argv, "ikey")) {
141 unsigned int uval;
142
143 NEXT_ARG();
144 if (strchr(*argv, '.'))
145 uval = get_addr32(*argv);
146 else {
147 if (get_unsigned(&uval, *argv, 0) < 0) {
148 fprintf(stderr, "invalid value for \"ikey\": \"%s\"; it should be an unsigned integer\n", *argv);
149 exit(-1);
150 }
151 uval = htonl(uval);
152 }
153 ikey = uval;
154 } else if (!matches(*argv, "okey")) {
155 unsigned int uval;
156
157 NEXT_ARG();
158 if (strchr(*argv, '.'))
159 uval = get_addr32(*argv);
160 else {
161 if (get_unsigned(&uval, *argv, 0) < 0) {
162 fprintf(stderr, "invalid value for \"okey\": \"%s\"; it should be an unsigned integer\n", *argv);
163 exit(-1);
164 }
165 uval = htonl(uval);
166 }
167 okey = uval;
168 } else if (!matches(*argv, "remote")) {
169 NEXT_ARG();
170 daddr = get_addr32(*argv);
171 } else if (!matches(*argv, "local")) {
172 NEXT_ARG();
173 saddr = get_addr32(*argv);
174 } else if (!matches(*argv, "dev")) {
175 NEXT_ARG();
176 link = if_nametoindex(*argv);
177 if (link == 0) {
178 fprintf(stderr, "Cannot find device \"%s\"\n",
179 *argv);
180 exit(-1);
181 }
182 } else if (strcmp(*argv, "fwmark") == 0) {
183 NEXT_ARG();
184 if (get_u32(&fwmark, *argv, 0))
185 invarg("invalid fwmark\n", *argv);
186 } else
187 usage();
188 argc--; argv++;
189 }
190
191 addattr32(n, 1024, IFLA_VTI_IKEY, ikey);
192 addattr32(n, 1024, IFLA_VTI_OKEY, okey);
193 addattr_l(n, 1024, IFLA_VTI_LOCAL, &saddr, 4);
194 addattr_l(n, 1024, IFLA_VTI_REMOTE, &daddr, 4);
195 addattr32(n, 1024, IFLA_VTI_FWMARK, fwmark);
196 if (link)
197 addattr32(n, 1024, IFLA_VTI_LINK, link);
198
199 return 0;
200 }
201
202 static void vti_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
203 {
204 const char *local = "any";
205 const char *remote = "any";
206 __u32 key;
207 unsigned int link;
208 char s2[IFNAMSIZ];
209
210 if (!tb)
211 return;
212
213 if (tb[IFLA_VTI_REMOTE]) {
214 unsigned int addr = rta_getattr_u32(tb[IFLA_VTI_REMOTE]);
215
216 if (addr)
217 remote = format_host(AF_INET, 4, &addr);
218 }
219
220 print_string(PRINT_ANY, "remote", "remote %s ", remote);
221
222 if (tb[IFLA_VTI_LOCAL]) {
223 unsigned int addr = rta_getattr_u32(tb[IFLA_VTI_LOCAL]);
224
225 if (addr)
226 local = format_host(AF_INET, 4, &addr);
227 }
228
229 print_string(PRINT_ANY, "local", "local %s ", local);
230
231 if (tb[IFLA_VTI_LINK] &&
232 (link = rta_getattr_u32(tb[IFLA_VTI_LINK]))) {
233 const char *n = if_indextoname(link, s2);
234
235 if (n)
236 print_string(PRINT_ANY, "link", "dev %s ", n);
237 else
238 print_uint(PRINT_ANY, "link_index", "dev %u ", link);
239 }
240
241 if (tb[IFLA_VTI_IKEY] &&
242 (key = rta_getattr_u32(tb[IFLA_VTI_IKEY])))
243 print_0xhex(PRINT_ANY, "ikey", "ikey %#x ", ntohl(key));
244
245
246 if (tb[IFLA_VTI_OKEY] &&
247 (key = rta_getattr_u32(tb[IFLA_VTI_OKEY])))
248 print_0xhex(PRINT_ANY, "okey", "okey %#x ", ntohl(key));
249
250 if (tb[IFLA_VTI_FWMARK]) {
251 __u32 fwmark = rta_getattr_u32(tb[IFLA_VTI_FWMARK]);
252
253 if (fwmark) {
254 SPRINT_BUF(b1);
255
256 snprintf(b1, sizeof(b1), "0x%x", fwmark);
257 print_string(PRINT_ANY, "fwmark", "fwmark %s ", s2);
258 }
259 }
260 }
261
262 static void vti_print_help(struct link_util *lu, int argc, char **argv,
263 FILE *f)
264 {
265 print_usage(f);
266 }
267
268 struct link_util vti_link_util = {
269 .id = "vti",
270 .maxattr = IFLA_VTI_MAX,
271 .parse_opt = vti_parse_opt,
272 .print_opt = vti_print_opt,
273 .print_help = vti_print_help,
274 };