]>
git.proxmox.com Git - mirror_iproute2.git/blob - ip/ipfou.c
2 * ipfou.c FOU (foo over UDP) support
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.
9 * Authors: Tom Herbert <therbert@google.com>
17 #include <linux/fou.h>
18 #include <linux/genetlink.h>
20 #include <arpa/inet.h>
24 #include "ip_common.h"
25 #include "json_print.h"
27 static void usage(void)
30 "Usage: ip fou add port PORT { ipproto PROTO | gue }\n"
31 " [ local IFADDR ] [ peer IFADDR ]\n"
32 " [ peer_port PORT ] [ dev IFNAME ]\n"
33 " ip fou del port PORT [ local IFADDR ]\n"
34 " [ peer IFADDR ] [ peer_port PORT ]\n"
38 "Where: PROTO { ipproto-name | 1..255 }\n"
39 " PORT { 1..65535 }\n"
40 " IFADDR { addr }\n");
46 static struct rtnl_handle genl_rth
= { .fd
= -1 };
47 static int genl_family
= -1;
49 #define FOU_REQUEST(_req, _bufsiz, _cmd, _flags) \
50 GENL_REQUEST(_req, _bufsiz, genl_family, 0, \
51 FOU_GENL_VERSION, _cmd, _flags)
53 static int fou_parse_opt(int argc
, char **argv
, struct nlmsghdr
*n
,
56 const char *local
= NULL
, *peer
= NULL
;
57 __u16 port
, peer_port
= 0;
58 __u8 family
= preferred_family
;
65 if (preferred_family
== AF_UNSPEC
) {
70 if (!matches(*argv
, "port")) {
73 if (get_be16(&port
, *argv
, 0) || port
== 0)
74 invarg("invalid port", *argv
);
76 } else if (!matches(*argv
, "ipproto")) {
77 struct protoent
*servptr
;
81 servptr
= getprotobyname(*argv
);
83 ipproto
= servptr
->p_proto
;
84 else if (get_u8(&ipproto
, *argv
, 0) || ipproto
== 0)
85 invarg("invalid ipproto", *argv
);
87 } else if (!matches(*argv
, "gue")) {
89 } else if (!matches(*argv
, "-6")) {
91 } else if (!matches(*argv
, "local")) {
95 } else if (!matches(*argv
, "peer")) {
99 } else if (!matches(*argv
, "peer_port")) {
102 if (get_be16(&peer_port
, *argv
, 0) || peer_port
== 0)
103 invarg("invalid peer port", *argv
);
104 } else if (!matches(*argv
, "dev")) {
111 if (check_ifname(ifname
)) {
112 fprintf(stderr
, "fou: invalid device name\n");
116 index
= ll_name_to_index(ifname
);
119 fprintf(stderr
, "fou: unknown device name\n");
124 , "fou: unknown command \"%s\"?\n", *argv
);
132 fprintf(stderr
, "fou: missing port\n");
136 if (!ipproto_set
&& !gue_set
&& adding
) {
137 fprintf(stderr
, "fou: must set ipproto or gue\n");
141 if (ipproto_set
&& gue_set
) {
142 fprintf(stderr
, "fou: cannot set ipproto and gue\n");
146 if ((peer_port
&& !peer
) || (peer
&& !peer_port
)) {
147 fprintf(stderr
, "fou: both peer and peer port must be set\n");
151 type
= gue_set
? FOU_ENCAP_GUE
: FOU_ENCAP_DIRECT
;
153 addattr16(n
, 1024, FOU_ATTR_PORT
, port
);
154 addattr8(n
, 1024, FOU_ATTR_TYPE
, type
);
155 addattr8(n
, 1024, FOU_ATTR_AF
, family
);
158 addattr8(n
, 1024, FOU_ATTR_IPPROTO
, ipproto
);
161 inet_prefix local_addr
;
162 __u8 attr_type
= family
== AF_INET
? FOU_ATTR_LOCAL_V4
:
165 if (get_addr(&local_addr
, local
, family
)) {
166 fprintf(stderr
, "fou: parsing local address failed\n");
169 addattr_l(n
, 1024, attr_type
, &local_addr
.data
,
174 inet_prefix peer_addr
;
175 __u8 attr_type
= family
== AF_INET
? FOU_ATTR_PEER_V4
:
178 if (get_addr(&peer_addr
, peer
, family
)) {
179 fprintf(stderr
, "fou: parsing peer address failed\n");
182 addattr_l(n
, 1024, attr_type
, &peer_addr
.data
,
186 addattr16(n
, 1024, FOU_ATTR_PEER_PORT
, peer_port
);
190 addattr32(n
, 1024, FOU_ATTR_IFINDEX
, index
);
195 static int do_add(int argc
, char **argv
)
197 FOU_REQUEST(req
, 1024, FOU_CMD_ADD
, NLM_F_REQUEST
);
199 fou_parse_opt(argc
, argv
, &req
.n
, true);
201 if (rtnl_talk(&genl_rth
, &req
.n
, NULL
) < 0)
207 static int do_del(int argc
, char **argv
)
209 FOU_REQUEST(req
, 1024, FOU_CMD_DEL
, NLM_F_REQUEST
);
211 fou_parse_opt(argc
, argv
, &req
.n
, false);
213 if (rtnl_talk(&genl_rth
, &req
.n
, NULL
) < 0)
219 static int print_fou_mapping(struct nlmsghdr
*n
, void *arg
)
221 __u8 family
= AF_INET
, local_attr_type
, peer_attr_type
, byte_len
;
222 struct rtattr
*tb
[FOU_ATTR_MAX
+ 1];
223 __u8 empty_buf
[16] = {0};
224 struct genlmsghdr
*ghdr
;
225 int len
= n
->nlmsg_len
;
227 if (n
->nlmsg_type
!= genl_family
)
230 len
-= NLMSG_LENGTH(GENL_HDRLEN
);
234 ghdr
= NLMSG_DATA(n
);
235 parse_rtattr(tb
, FOU_ATTR_MAX
, (void *) ghdr
+ GENL_HDRLEN
, len
);
237 open_json_object(NULL
);
238 if (tb
[FOU_ATTR_PORT
])
239 print_uint(PRINT_ANY
, "port", "port %u",
240 ntohs(rta_getattr_u16(tb
[FOU_ATTR_PORT
])));
242 if (tb
[FOU_ATTR_TYPE
] &&
243 rta_getattr_u8(tb
[FOU_ATTR_TYPE
]) == FOU_ENCAP_GUE
)
244 print_null(PRINT_ANY
, "gue", " gue", NULL
);
245 else if (tb
[FOU_ATTR_IPPROTO
])
246 print_uint(PRINT_ANY
, "ipproto",
247 " ipproto %u", rta_getattr_u8(tb
[FOU_ATTR_IPPROTO
]));
249 if (tb
[FOU_ATTR_AF
]) {
250 family
= rta_getattr_u8(tb
[FOU_ATTR_AF
]);
252 print_string(PRINT_JSON
, "family", NULL
,
253 family_name(family
));
255 if (family
== AF_INET6
)
256 print_string(PRINT_FP
, NULL
,
260 local_attr_type
= family
== AF_INET
? FOU_ATTR_LOCAL_V4
:
262 peer_attr_type
= family
== AF_INET
? FOU_ATTR_PEER_V4
:
264 byte_len
= af_bit_len(family
) / 8;
266 if (tb
[local_attr_type
] && memcmp(RTA_DATA(tb
[local_attr_type
]),
267 empty_buf
, byte_len
)) {
268 print_string(PRINT_ANY
, "local", " local %s",
269 format_host_rta(family
, tb
[local_attr_type
]));
272 if (tb
[peer_attr_type
] && memcmp(RTA_DATA(tb
[peer_attr_type
]),
273 empty_buf
, byte_len
)) {
274 print_string(PRINT_ANY
, "peer", " peer %s",
275 format_host_rta(family
, tb
[peer_attr_type
]));
278 if (tb
[FOU_ATTR_PEER_PORT
]) {
279 __u16 p_port
= ntohs(rta_getattr_u16(tb
[FOU_ATTR_PEER_PORT
]));
282 print_uint(PRINT_ANY
, "peer_port", " peer_port %u",
287 if (tb
[FOU_ATTR_IFINDEX
]) {
288 int index
= rta_getattr_s32(tb
[FOU_ATTR_IFINDEX
]);
293 ifname
= ll_index_to_name(index
);
296 print_string(PRINT_ANY
, "dev", " dev %s",
301 print_string(PRINT_FP
, NULL
, "\n", NULL
);
307 static int do_show(int argc
, char **argv
)
309 FOU_REQUEST(req
, 4096, FOU_CMD_GET
, NLM_F_REQUEST
| NLM_F_DUMP
);
313 "\"ip fou show\" does not take any arguments.\n");
317 if (rtnl_send(&genl_rth
, &req
.n
, req
.n
.nlmsg_len
) < 0) {
318 perror("Cannot send show request");
323 if (rtnl_dump_filter(&genl_rth
, print_fou_mapping
, stdout
) < 0) {
324 fprintf(stderr
, "Dump terminated\n");
333 int do_ipfou(int argc
, char **argv
)
338 if (matches(*argv
, "help") == 0)
341 if (genl_init_handle(&genl_rth
, FOU_GENL_NAME
, &genl_family
))
344 if (matches(*argv
, "add") == 0)
345 return do_add(argc
-1, argv
+1);
346 if (matches(*argv
, "delete") == 0)
347 return do_del(argc
-1, argv
+1);
348 if (matches(*argv
, "show") == 0)
349 return do_show(argc
-1, argv
+1);
352 "Command \"%s\" is unknown, try \"ip fou help\".\n", *argv
);