blob: f4a20e24e0bfa56ea1d5ef37bccf5a9e288a67dd [file] [log] [blame]
Amir Vadaid57639a2016-12-02 13:25:15 +02001/*
2 * m_tunnel_key.c ip tunnel manipulation 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: Amir Vadai <amir@vadai.me>
10 */
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <unistd.h>
15#include <string.h>
16#include <linux/if_ether.h>
17#include "utils.h"
18#include "rt_names.h"
19#include "tc_util.h"
20#include <linux/tc_act/tc_tunnel_key.h>
21
22static void explain(void)
23{
24 fprintf(stderr, "Usage: tunnel_key unset\n");
25 fprintf(stderr, " tunnel_key set id TUNNELID src_ip IP dst_ip IP\n");
26}
27
28static void usage(void)
29{
30 explain();
31 exit(-1);
32}
33
34static int tunnel_key_parse_ip_addr(const char *str, int addr4_type,
35 int addr6_type, struct nlmsghdr *n)
36{
37 inet_prefix addr;
38 int ret;
39
40 ret = get_addr(&addr, str, AF_UNSPEC);
41 if (ret)
42 return ret;
43
44 addattr_l(n, MAX_MSG, addr.family == AF_INET ? addr4_type : addr6_type,
45 addr.data, addr.bytelen);
46
47 return 0;
48}
49
50static int tunnel_key_parse_key_id(const char *str, int type,
51 struct nlmsghdr *n)
52{
53 __be32 key_id;
54 int ret;
55
56 ret = get_be32(&key_id, str, 10);
57 if (!ret)
58 addattr32(n, MAX_MSG, type, key_id);
59
60 return ret;
61}
62
63static int parse_tunnel_key(struct action_util *a, int *argc_p, char ***argv_p,
64 int tca_id, struct nlmsghdr *n)
65{
66 struct tc_tunnel_key parm = { .action = TC_ACT_PIPE };
67 char **argv = *argv_p;
68 int argc = *argc_p;
69 struct rtattr *tail;
70 int action = 0;
71 int ret;
72 int has_src_ip = 0;
73 int has_dst_ip = 0;
74 int has_key_id = 0;
75
76 if (matches(*argv, "tunnel_key") != 0)
77 return -1;
78
79 tail = NLMSG_TAIL(n);
80 addattr_l(n, MAX_MSG, tca_id, NULL, 0);
81
82 NEXT_ARG();
83
84 while (argc > 0) {
85 if (matches(*argv, "unset") == 0) {
86 if (action) {
87 fprintf(stderr, "unexpected \"%s\" - action already specified\n",
88 *argv);
89 explain();
90 return -1;
91 }
92 action = TCA_TUNNEL_KEY_ACT_RELEASE;
93 } else if (matches(*argv, "set") == 0) {
94 if (action) {
95 fprintf(stderr, "unexpected \"%s\" - action already specified\n",
96 *argv);
97 explain();
98 return -1;
99 }
100 action = TCA_TUNNEL_KEY_ACT_SET;
101 } else if (matches(*argv, "src_ip") == 0) {
102 NEXT_ARG();
103 ret = tunnel_key_parse_ip_addr(*argv,
104 TCA_TUNNEL_KEY_ENC_IPV4_SRC,
105 TCA_TUNNEL_KEY_ENC_IPV6_SRC,
106 n);
107 if (ret < 0) {
108 fprintf(stderr, "Illegal \"src_ip\"\n");
109 return -1;
110 }
111 has_src_ip = 1;
112 } else if (matches(*argv, "dst_ip") == 0) {
113 NEXT_ARG();
114 ret = tunnel_key_parse_ip_addr(*argv,
115 TCA_TUNNEL_KEY_ENC_IPV4_DST,
116 TCA_TUNNEL_KEY_ENC_IPV6_DST,
117 n);
118 if (ret < 0) {
119 fprintf(stderr, "Illegal \"dst_ip\"\n");
120 return -1;
121 }
122 has_dst_ip = 1;
123 } else if (matches(*argv, "id") == 0) {
124 NEXT_ARG();
125 ret = tunnel_key_parse_key_id(*argv, TCA_TUNNEL_KEY_ENC_KEY_ID, n);
126 if (ret < 0) {
127 fprintf(stderr, "Illegal \"id\"\n");
128 return -1;
129 }
130 has_key_id = 1;
131 } else if (matches(*argv, "help") == 0) {
132 usage();
133 } else {
134 break;
135 }
136 NEXT_ARG_FWD();
137 }
138
139 if (argc && !action_a2n(*argv, &parm.action, false))
140 NEXT_ARG_FWD();
141
142 if (argc) {
143 if (matches(*argv, "index") == 0) {
144 NEXT_ARG();
145 if (get_u32(&parm.index, *argv, 10)) {
146 fprintf(stderr, "tunnel_key: Illegal \"index\"\n");
147 return -1;
148 }
149
150 NEXT_ARG_FWD();
151 }
152 }
153
154 if (action == TCA_TUNNEL_KEY_ACT_SET &&
155 (!has_src_ip || !has_dst_ip || !has_key_id)) {
156 fprintf(stderr, "set needs tunnel_key parameters\n");
157 explain();
158 return -1;
159 }
160
161 parm.t_action = action;
162 addattr_l(n, MAX_MSG, TCA_TUNNEL_KEY_PARMS, &parm, sizeof(parm));
163 tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
164
165 *argc_p = argc;
166 *argv_p = argv;
167
168 return 0;
169}
170
171static void tunnel_key_print_ip_addr(FILE *f, const char *name,
172 struct rtattr *attr)
173{
174 int family;
175 size_t len;
176
177 if (!attr)
178 return;
179
180 len = RTA_PAYLOAD(attr);
181
182 if (len == 4)
183 family = AF_INET;
184 else if (len == 16)
185 family = AF_INET6;
186 else
187 return;
188
189 fprintf(f, "\n\t%s %s", name, rt_addr_n2a_rta(family, attr));
190}
191
192static void tunnel_key_print_key_id(FILE *f, const char *name,
193 struct rtattr *attr)
194{
195 if (!attr)
196 return;
197 fprintf(f, "\n\t%s %d", name, rta_getattr_be32(attr));
198}
199
200static int print_tunnel_key(struct action_util *au, FILE *f, struct rtattr *arg)
201{
202 struct rtattr *tb[TCA_TUNNEL_KEY_MAX + 1];
203 struct tc_tunnel_key *parm;
204
205 if (!arg)
206 return -1;
207
208 parse_rtattr_nested(tb, TCA_TUNNEL_KEY_MAX, arg);
209
210 if (!tb[TCA_TUNNEL_KEY_PARMS]) {
211 fprintf(f, "[NULL tunnel_key parameters]");
212 return -1;
213 }
214 parm = RTA_DATA(tb[TCA_TUNNEL_KEY_PARMS]);
215
216 fprintf(f, "tunnel_key");
217
218 switch (parm->t_action) {
219 case TCA_TUNNEL_KEY_ACT_RELEASE:
220 fprintf(f, " unset");
221 break;
222 case TCA_TUNNEL_KEY_ACT_SET:
223 fprintf(f, " set");
224 tunnel_key_print_ip_addr(f, "src_ip",
225 tb[TCA_TUNNEL_KEY_ENC_IPV4_SRC]);
226 tunnel_key_print_ip_addr(f, "dst_ip",
227 tb[TCA_TUNNEL_KEY_ENC_IPV4_DST]);
228 tunnel_key_print_ip_addr(f, "src_ip",
229 tb[TCA_TUNNEL_KEY_ENC_IPV6_SRC]);
230 tunnel_key_print_ip_addr(f, "dst_ip",
231 tb[TCA_TUNNEL_KEY_ENC_IPV6_DST]);
232 tunnel_key_print_key_id(f, "key_id",
233 tb[TCA_TUNNEL_KEY_ENC_KEY_ID]);
234 break;
235 }
236 fprintf(f, " %s", action_n2a(parm->action));
237
238 fprintf(f, "\n\tindex %d ref %d bind %d", parm->index, parm->refcnt,
239 parm->bindcnt);
240
241 if (show_stats) {
242 if (tb[TCA_TUNNEL_KEY_TM]) {
243 struct tcf_t *tm = RTA_DATA(tb[TCA_TUNNEL_KEY_TM]);
244
245 print_tm(f, tm);
246 }
247 }
248
249 fprintf(f, "\n ");
250
251 return 0;
252}
253
254struct action_util tunnel_key_action_util = {
255 .id = "tunnel_key",
256 .parse_aopt = parse_tunnel_key,
257 .print_aopt = print_tunnel_key,
258};