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 26static 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 */ 39static struct rtnl_handle genl_rth = { .fd = -1 }; 40static 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 51static 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 75static 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 94static 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 126static 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 149static 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 217static 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 229static 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 241int 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