1 /* 2 * Copyright (C)2006 USAGI/WIDE Project 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, see <http://www.gnu.org/licenses>. 16 */ 17 /* 18 * split from ip_tunnel.c 19 */ 20 /* 21 * Author: 22 * Masahide NAKAMURA @USAGI 23 */ 24 25 #include <stdio.h> 26 #include <string.h> 27 #include <unistd.h> 28 #include <errno.h> 29 #include <sys/types.h> 30 #include <sys/socket.h> 31 #include <sys/ioctl.h> 32 #include <netinet/in.h> 33 #include <linux/if.h> 34 #include <linux/ip.h> 35 #include <linux/if_tunnel.h> 36 37 #include "utils.h" 38 #include "tunnel.h" 39 40 const char *tnl_strproto(__u8 proto) 41 { 42 static char buf[16]; 43 44 switch (proto) { 45 case IPPROTO_IPIP: 46 strcpy(buf, "ip"); 47 break; 48 case IPPROTO_GRE: 49 strcpy(buf, "gre"); 50 break; 51 case IPPROTO_IPV6: 52 strcpy(buf, "ipv6"); 53 break; 54 case IPPROTO_ESP: 55 strcpy(buf, "esp"); 56 break; 57 case IPPROTO_MPLS: 58 strcpy(buf, "mpls"); 59 break; 60 case 0: 61 strcpy(buf, "any"); 62 break; 63 default: 64 strcpy(buf, "unknown"); 65 break; 66 } 67 68 return buf; 69 } 70 71 int tnl_get_ioctl(const char *basedev, void *p) 72 { 73 struct ifreq ifr; 74 int fd; 75 int err; 76 77 strncpy(ifr.ifr_name, basedev, IFNAMSIZ); 78 ifr.ifr_ifru.ifru_data = (void *)p; 79 80 fd = socket(preferred_family, SOCK_DGRAM, 0); 81 if (fd < 0) { 82 fprintf(stderr, "create socket failed: %s\n", strerror(errno)); 83 return -1; 84 } 85 86 err = ioctl(fd, SIOCGETTUNNEL, &ifr); 87 if (err) 88 fprintf(stderr, "get tunnel \"%s\" failed: %s\n", basedev, 89 strerror(errno)); 90 91 close(fd); 92 return err; 93 } 94 95 int tnl_add_ioctl(int cmd, const char *basedev, const char *name, void *p) 96 { 97 struct ifreq ifr; 98 int fd; 99 int err; 100 101 if (cmd == SIOCCHGTUNNEL && name[0]) 102 strncpy(ifr.ifr_name, name, IFNAMSIZ); 103 else 104 strncpy(ifr.ifr_name, basedev, IFNAMSIZ); 105 ifr.ifr_ifru.ifru_data = p; 106 107 fd = socket(preferred_family, SOCK_DGRAM, 0); 108 if (fd < 0) { 109 fprintf(stderr, "create socket failed: %s\n", strerror(errno)); 110 return -1; 111 } 112 113 err = ioctl(fd, cmd, &ifr); 114 if (err) 115 fprintf(stderr, "add tunnel \"%s\" failed: %s\n", ifr.ifr_name, 116 strerror(errno)); 117 close(fd); 118 return err; 119 } 120 121 int tnl_del_ioctl(const char *basedev, const char *name, void *p) 122 { 123 struct ifreq ifr; 124 int fd; 125 int err; 126 127 if (name[0]) 128 strncpy(ifr.ifr_name, name, IFNAMSIZ); 129 else 130 strncpy(ifr.ifr_name, basedev, IFNAMSIZ); 131 132 ifr.ifr_ifru.ifru_data = p; 133 134 fd = socket(preferred_family, SOCK_DGRAM, 0); 135 if (fd < 0) { 136 fprintf(stderr, "create socket failed: %s\n", strerror(errno)); 137 return -1; 138 } 139 140 err = ioctl(fd, SIOCDELTUNNEL, &ifr); 141 if (err) 142 fprintf(stderr, "delete tunnel \"%s\" failed: %s\n", 143 ifr.ifr_name, strerror(errno)); 144 close(fd); 145 return err; 146 } 147 148 static int tnl_gen_ioctl(int cmd, const char *name, 149 void *p, int skiperr) 150 { 151 struct ifreq ifr; 152 int fd; 153 int err; 154 155 strncpy(ifr.ifr_name, name, IFNAMSIZ); 156 ifr.ifr_ifru.ifru_data = p; 157 158 fd = socket(preferred_family, SOCK_DGRAM, 0); 159 if (fd < 0) { 160 fprintf(stderr, "create socket failed: %s\n", strerror(errno)); 161 return -1; 162 } 163 164 err = ioctl(fd, cmd, &ifr); 165 if (err && errno != skiperr) 166 fprintf(stderr, "%s: ioctl %x failed: %s\n", name, 167 cmd, strerror(errno)); 168 close(fd); 169 return err; 170 } 171 172 int tnl_prl_ioctl(int cmd, const char *name, void *p) 173 { 174 return tnl_gen_ioctl(cmd, name, p, -1); 175 } 176 177 int tnl_6rd_ioctl(int cmd, const char *name, void *p) 178 { 179 return tnl_gen_ioctl(cmd, name, p, -1); 180 } 181 182 int tnl_ioctl_get_6rd(const char *name, void *p) 183 { 184 return tnl_gen_ioctl(SIOCGET6RD, name, p, EINVAL); 185 } 186 187 __be32 tnl_parse_key(const char *name, const char *key) 188 { 189 unsigned int uval; 190 191 if (strchr(key, '.')) 192 return get_addr32(key); 193 194 if (get_unsigned(&uval, key, 0) < 0) { 195 fprintf(stderr, "invalid value for \"%s\": \"%s\";", name, key); 196 fprintf(stderr, " it should be an unsigned integer\n"); 197 exit(-1); 198 } 199 return htonl(uval); 200 } 201 202 /* tnl_print_stats - print tunnel statistics 203 * 204 * @buf - tunnel interface's line in /proc/net/dev, 205 * starting past the interface name and following colon 206 */ 207 void tnl_print_stats(const char *buf) 208 { 209 unsigned long rx_bytes, rx_packets, rx_errs, rx_drops, 210 rx_fifo, rx_frame, 211 tx_bytes, tx_packets, tx_errs, tx_drops, 212 tx_fifo, tx_colls, tx_carrier, rx_multi; 213 214 if (sscanf(buf, "%lu%lu%lu%lu%lu%lu%lu%*d%lu%lu%lu%lu%lu%lu%lu", 215 &rx_bytes, &rx_packets, &rx_errs, &rx_drops, 216 &rx_fifo, &rx_frame, &rx_multi, 217 &tx_bytes, &tx_packets, &tx_errs, &tx_drops, 218 &tx_fifo, &tx_colls, &tx_carrier) != 14) 219 return; 220 221 printf("%s", _SL_); 222 printf("RX: Packets Bytes Errors CsumErrs OutOfSeq Mcasts%s", _SL_); 223 printf(" %-10ld %-12ld %-6ld %-8ld %-8ld %-8ld%s", 224 rx_packets, rx_bytes, rx_errs, rx_frame, rx_fifo, rx_multi, _SL_); 225 printf("TX: Packets Bytes Errors DeadLoop NoRoute NoBufs%s", _SL_); 226 printf(" %-10ld %-12ld %-6ld %-8ld %-8ld %-6ld", 227 tx_packets, tx_bytes, tx_errs, tx_colls, tx_carrier, tx_drops); 228 } 229