• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * ipila.c	ILA (Identifier Locator Addressing) support
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:	Tom Herbert <tom@herbertland.com>
10  */
11 
12 #include <netdb.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <net/if.h>
17 #include <linux/ila.h>
18 #include <linux/genetlink.h>
19 #include <linux/ip.h>
20 #include <arpa/inet.h>
21 
22 #include "libgenl.h"
23 #include "utils.h"
24 #include "ip_common.h"
25 
usage(void)26 static void usage(void)
27 {
28 	fprintf(stderr, "Usage: ip ila add loc_match LOCATOR_MATCH "
29 		"loc LOCATOR [ dev DEV ]\n");
30 	fprintf(stderr, "       ip ila del loc_match LOCATOR_MATCH "
31 		"[ loc LOCATOR ] [ dev DEV ]\n");
32 	fprintf(stderr, "       ip ila list\n");
33 	fprintf(stderr, "\n");
34 
35 	exit(-1);
36 }
37 
38 /* netlink socket */
39 static struct rtnl_handle genl_rth = { .fd = -1 };
40 static int genl_family = -1;
41 
42 #define ILA_REQUEST(_req, _bufsiz, _cmd, _flags)	\
43 	GENL_REQUEST(_req, _bufsiz, genl_family, 0,	\
44 		     ILA_GENL_VERSION, _cmd, _flags)
45 
46 #define ILA_RTA(g) ((struct rtattr *)(((char *)(g)) +	\
47 	NLMSG_ALIGN(sizeof(struct genlmsghdr))))
48 
49 #define ADDR_BUF_SIZE sizeof("xxxx:xxxx:xxxx:xxxx")
50 
print_addr64(__u64 addr,char * buff,size_t len)51 static int print_addr64(__u64 addr, char *buff, size_t len)
52 {
53 	__u16 *words = (__u16 *)&addr;
54 	__u16 v;
55 	int i, ret;
56 	size_t written = 0;
57 	char *sep = ":";
58 
59 	for (i = 0; i < 4; i++) {
60 		v = ntohs(words[i]);
61 
62 		if (i == 3)
63 			sep = "";
64 
65 		ret = snprintf(&buff[written], len - written, "%x%s", v, sep);
66 		if (ret < 0)
67 			return ret;
68 
69 		written += ret;
70 	}
71 
72 	return written;
73 }
74 
print_ila_locid(FILE * fp,int attr,struct rtattr * tb[],int space)75 static void print_ila_locid(FILE *fp, int attr, struct rtattr *tb[], int space)
76 {
77 	char abuf[256];
78 	size_t blen;
79 	int i;
80 
81 	if (tb[attr]) {
82 		blen = print_addr64(rta_getattr_u32(tb[attr]),
83 				    abuf, sizeof(abuf));
84 		fprintf(fp, "%s", abuf);
85 	} else {
86 		fprintf(fp, "-");
87 		blen = 1;
88 	}
89 
90 	for (i = 0; i < space - blen; i++)
91 		fprintf(fp, " ");
92 }
93 
print_ila_mapping(const struct sockaddr_nl * who,struct nlmsghdr * n,void * arg)94 static int print_ila_mapping(const struct sockaddr_nl *who,
95 			     struct nlmsghdr *n, void *arg)
96 {
97 	FILE *fp = (FILE *)arg;
98 	struct genlmsghdr *ghdr;
99 	struct rtattr *tb[ILA_ATTR_MAX + 1];
100 	int len = n->nlmsg_len;
101 
102 	if (n->nlmsg_type != genl_family)
103 		return 0;
104 
105 	len -= NLMSG_LENGTH(GENL_HDRLEN);
106 	if (len < 0)
107 		return -1;
108 
109 	ghdr = NLMSG_DATA(n);
110 	parse_rtattr(tb, ILA_ATTR_MAX, (void *) ghdr + GENL_HDRLEN, len);
111 
112 	print_ila_locid(fp, ILA_ATTR_LOCATOR_MATCH, tb, ADDR_BUF_SIZE);
113 	print_ila_locid(fp, ILA_ATTR_LOCATOR, tb, ADDR_BUF_SIZE);
114 
115 	if (tb[ILA_ATTR_IFINDEX])
116 		fprintf(fp, "%s", ll_index_to_name(rta_getattr_u32(tb[ILA_ATTR_IFINDEX])));
117 	else
118 		fprintf(fp, "-");
119 	fprintf(fp, "\n");
120 
121 	return 0;
122 }
123 
124 #define NLMSG_BUF_SIZE 4096
125 
do_list(int argc,char ** argv)126 static int do_list(int argc, char **argv)
127 {
128 	ILA_REQUEST(req, 1024, ILA_CMD_GET, NLM_F_REQUEST | NLM_F_DUMP);
129 
130 	if (argc > 0) {
131 		fprintf(stderr, "\"ip ila show\" does not take "
132 			"any arguments.\n");
133 		return -1;
134 	}
135 
136 	if (rtnl_send(&genl_rth, (void *)&req, req.n.nlmsg_len) < 0) {
137 		perror("Cannot send dump request");
138 		exit(1);
139 	}
140 
141 	if (rtnl_dump_filter(&genl_rth, print_ila_mapping, stdout) < 0) {
142 		fprintf(stderr, "Dump terminated\n");
143 		return 1;
144 	}
145 
146 	return 0;
147 }
148 
ila_parse_opt(int argc,char ** argv,struct nlmsghdr * n,bool adding)149 static int ila_parse_opt(int argc, char **argv, struct nlmsghdr *n,
150 			 bool adding)
151 {
152 	__u64 locator = 0;
153 	__u64 locator_match = 0;
154 	int ifindex = 0;
155 	bool loc_set = false;
156 	bool loc_match_set = false;
157 	bool ifindex_set = false;
158 
159 	while (argc > 0) {
160 		if (!matches(*argv, "loc")) {
161 			NEXT_ARG();
162 
163 			if (get_addr64(&locator, *argv) < 0) {
164 				fprintf(stderr, "Bad locator: %s\n", *argv);
165 				return -1;
166 			}
167 			loc_set = true;
168 		} else if (!matches(*argv, "loc_match")) {
169 			NEXT_ARG();
170 
171 			if (get_addr64(&locator_match, *argv) < 0) {
172 				fprintf(stderr, "Bad locator to match: %s\n",
173 					*argv);
174 				return -1;
175 			}
176 			loc_match_set = true;
177 		} else if (!matches(*argv, "dev")) {
178 			NEXT_ARG();
179 
180 			ifindex = ll_name_to_index(*argv);
181 			if (ifindex == 0) {
182 				fprintf(stderr, "No such interface: %s\n",
183 					*argv);
184 				return -1;
185 			}
186 			ifindex_set = true;
187 		} else {
188 			usage();
189 			return -1;
190 		}
191 		argc--, argv++;
192 	}
193 
194 	if (adding) {
195 		if (!loc_set) {
196 			fprintf(stderr, "ila: missing locator\n");
197 			return -1;
198 		}
199 		if (!loc_match_set) {
200 			fprintf(stderr, "ila: missing locator0match\n");
201 			return -1;
202 		}
203 	}
204 
205 	if (loc_match_set)
206 		addattr64(n, 1024, ILA_ATTR_LOCATOR_MATCH, locator_match);
207 
208 	if (loc_set)
209 		addattr64(n, 1024, ILA_ATTR_LOCATOR, locator);
210 
211 	if (ifindex_set)
212 		addattr32(n, 1024, ILA_ATTR_IFINDEX, ifindex);
213 
214 	return 0;
215 }
216 
do_add(int argc,char ** argv)217 static int do_add(int argc, char **argv)
218 {
219 	ILA_REQUEST(req, 1024, ILA_CMD_ADD, NLM_F_REQUEST);
220 
221 	ila_parse_opt(argc, argv, &req.n, true);
222 
223 	if (rtnl_talk(&genl_rth, &req.n, NULL, 0) < 0)
224 		return -2;
225 
226 	return 0;
227 }
228 
do_del(int argc,char ** argv)229 static int do_del(int argc, char **argv)
230 {
231 	ILA_REQUEST(req, 1024, ILA_CMD_DEL, NLM_F_REQUEST);
232 
233 	ila_parse_opt(argc, argv, &req.n, false);
234 
235 	if (rtnl_talk(&genl_rth, &req.n, NULL, 0) < 0)
236 		return -2;
237 
238 	return 0;
239 }
240 
do_ipila(int argc,char ** argv)241 int do_ipila(int argc, char **argv)
242 {
243 	if (argc < 1)
244 		usage();
245 
246 	if (matches(*argv, "help") == 0)
247 		usage();
248 
249 	if (genl_init_handle(&genl_rth, ILA_GENL_NAME, &genl_family))
250 		exit(1);
251 
252 	if (matches(*argv, "add") == 0)
253 		return do_add(argc-1, argv+1);
254 	if (matches(*argv, "delete") == 0)
255 		return do_del(argc-1, argv+1);
256 	if (matches(*argv, "list") == 0)
257 		return do_list(argc-1, argv+1);
258 
259 	fprintf(stderr, "Command \"%s\" is unknown, try \"ip ila help\".\n",
260 		*argv);
261 	exit(-1);
262 }
263