libnl
3.2.3
|
00001 /* 00002 * lib/route/link/inet6.c AF_INET6 link operations 00003 * 00004 * This library is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU Lesser General Public 00006 * License as published by the Free Software Foundation version 2.1 00007 * of the License. 00008 * 00009 * Copyright (c) 2010 Thomas Graf <tgraf@suug.ch> 00010 */ 00011 00012 #include <netlink-local.h> 00013 #include <netlink/netlink.h> 00014 #include <netlink/attr.h> 00015 #include <netlink/route/rtnl.h> 00016 #include <netlink/route/link/api.h> 00017 00018 struct inet6_data 00019 { 00020 uint32_t i6_flags; 00021 struct ifla_cacheinfo i6_cacheinfo; 00022 uint32_t i6_conf[DEVCONF_MAX]; 00023 }; 00024 00025 static void *inet6_alloc(struct rtnl_link *link) 00026 { 00027 return calloc(1, sizeof(struct inet6_data)); 00028 } 00029 00030 static void *inet6_clone(struct rtnl_link *link, void *data) 00031 { 00032 struct inet6_data *i6; 00033 00034 if ((i6 = inet6_alloc(link))) 00035 memcpy(i6, data, sizeof(*i6)); 00036 00037 return i6; 00038 } 00039 00040 static void inet6_free(struct rtnl_link *link, void *data) 00041 { 00042 free(data); 00043 } 00044 00045 static struct nla_policy inet6_policy[IFLA_INET6_MAX+1] = { 00046 [IFLA_INET6_FLAGS] = { .type = NLA_U32 }, 00047 [IFLA_INET6_CACHEINFO] = { .minlen = sizeof(struct ifla_cacheinfo) }, 00048 [IFLA_INET6_CONF] = { .minlen = DEVCONF_MAX * 4 }, 00049 [IFLA_INET6_STATS] = { .minlen = __IPSTATS_MIB_MAX * 8 }, 00050 [IFLA_INET6_ICMP6STATS] = { .minlen = __ICMP6_MIB_MAX * 8 }, 00051 }; 00052 00053 static int inet6_parse_protinfo(struct rtnl_link *link, struct nlattr *attr, 00054 void *data) 00055 { 00056 struct inet6_data *i6 = data; 00057 struct nlattr *tb[IFLA_INET6_MAX+1]; 00058 int err; 00059 00060 err = nla_parse_nested(tb, IFLA_INET6_MAX, attr, inet6_policy); 00061 if (err < 0) 00062 return err; 00063 00064 if (tb[IFLA_INET6_FLAGS]) 00065 i6->i6_flags = nla_get_u32(tb[IFLA_INET6_FLAGS]); 00066 00067 if (tb[IFLA_INET6_CACHEINFO]) 00068 nla_memcpy(&i6->i6_cacheinfo, tb[IFLA_INET6_CACHEINFO], 00069 sizeof(i6->i6_cacheinfo)); 00070 00071 if (tb[IFLA_INET6_CONF]) 00072 nla_memcpy(&i6->i6_conf, tb[IFLA_INET6_CONF], 00073 sizeof(i6->i6_conf)); 00074 00075 /* 00076 * Due to 32bit data alignment, these addresses must be copied to an 00077 * aligned location prior to access. 00078 */ 00079 if (tb[IFLA_INET6_STATS]) { 00080 unsigned char *cnt = nla_data(tb[IFLA_INET6_STATS]); 00081 uint64_t stat; 00082 int i; 00083 00084 for (i = 1; i < __IPSTATS_MIB_MAX; i++) { 00085 memcpy(&stat, &cnt[i * sizeof(stat)], sizeof(stat)); 00086 rtnl_link_set_stat(link, RTNL_LINK_IP6_INPKTS + i - 1, 00087 stat); 00088 } 00089 } 00090 00091 if (tb[IFLA_INET6_ICMP6STATS]) { 00092 unsigned char *cnt = nla_data(tb[IFLA_INET6_ICMP6STATS]); 00093 uint64_t stat; 00094 int i; 00095 00096 for (i = 1; i < __ICMP6_MIB_MAX; i++) { 00097 memcpy(&stat, &cnt[i * sizeof(stat)], sizeof(stat)); 00098 rtnl_link_set_stat(link, RTNL_LINK_ICMP6_INMSGS + i - 1, 00099 stat); 00100 } 00101 } 00102 00103 return 0; 00104 } 00105 00106 /* These live in include/net/if_inet6.h and should be moved to include/linux */ 00107 #define IF_RA_OTHERCONF 0x80 00108 #define IF_RA_MANAGED 0x40 00109 #define IF_RA_RCVD 0x20 00110 #define IF_RS_SENT 0x10 00111 #define IF_READY 0x80000000 00112 00113 static const struct trans_tbl inet6_flags[] = { 00114 __ADD(IF_RA_OTHERCONF, ra_otherconf) 00115 __ADD(IF_RA_MANAGED, ra_managed) 00116 __ADD(IF_RA_RCVD, ra_rcvd) 00117 __ADD(IF_RS_SENT, rs_sent) 00118 __ADD(IF_READY, ready) 00119 }; 00120 00121 static char *inet6_flags2str(int flags, char *buf, size_t len) 00122 { 00123 return __flags2str(flags, buf, len, inet6_flags, 00124 ARRAY_SIZE(inet6_flags)); 00125 } 00126 00127 static const struct trans_tbl inet6_devconf[] = { 00128 __ADD(DEVCONF_FORWARDING, forwarding) 00129 __ADD(DEVCONF_HOPLIMIT, hoplimit) 00130 __ADD(DEVCONF_MTU6, mtu6) 00131 __ADD(DEVCONF_ACCEPT_RA, accept_ra) 00132 __ADD(DEVCONF_ACCEPT_REDIRECTS, accept_redirects) 00133 __ADD(DEVCONF_AUTOCONF, autoconf) 00134 __ADD(DEVCONF_DAD_TRANSMITS, dad_transmits) 00135 __ADD(DEVCONF_RTR_SOLICITS, rtr_solicits) 00136 __ADD(DEVCONF_RTR_SOLICIT_INTERVAL, rtr_solicit_interval) 00137 __ADD(DEVCONF_RTR_SOLICIT_DELAY, rtr_solicit_delay) 00138 __ADD(DEVCONF_USE_TEMPADDR, use_tempaddr) 00139 __ADD(DEVCONF_TEMP_VALID_LFT, temp_valid_lft) 00140 __ADD(DEVCONF_TEMP_PREFERED_LFT, temp_prefered_lft) 00141 __ADD(DEVCONF_REGEN_MAX_RETRY, regen_max_retry) 00142 __ADD(DEVCONF_MAX_DESYNC_FACTOR, max_desync_factor) 00143 __ADD(DEVCONF_MAX_ADDRESSES, max_addresses) 00144 __ADD(DEVCONF_FORCE_MLD_VERSION, force_mld_version) 00145 __ADD(DEVCONF_ACCEPT_RA_DEFRTR, accept_ra_defrtr) 00146 __ADD(DEVCONF_ACCEPT_RA_PINFO, accept_ra_pinfo) 00147 __ADD(DEVCONF_ACCEPT_RA_RTR_PREF, accept_ra_rtr_pref) 00148 __ADD(DEVCONF_RTR_PROBE_INTERVAL, rtr_probe_interval) 00149 __ADD(DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN, accept_ra_rt_info) 00150 __ADD(DEVCONF_PROXY_NDP, proxy_ndp) 00151 __ADD(DEVCONF_OPTIMISTIC_DAD, optimistic_dad) 00152 __ADD(DEVCONF_ACCEPT_SOURCE_ROUTE, accept_source_route) 00153 __ADD(DEVCONF_MC_FORWARDING, mc_forwarding) 00154 __ADD(DEVCONF_DISABLE_IPV6, disable_ipv6) 00155 __ADD(DEVCONF_ACCEPT_DAD, accept_dad) 00156 __ADD(DEVCONF_FORCE_TLLAO, force_tllao) 00157 }; 00158 00159 static char *inet6_devconf2str(int type, char *buf, size_t len) 00160 { 00161 return __type2str(type, buf, len, inet6_devconf, 00162 ARRAY_SIZE(inet6_devconf)); 00163 } 00164 00165 00166 static void inet6_dump_details(struct rtnl_link *link, 00167 struct nl_dump_params *p, void *data) 00168 { 00169 struct inet6_data *i6 = data; 00170 char buf[64], buf2[64]; 00171 int i, n = 0; 00172 00173 nl_dump_line(p, " ipv6 max-reasm-len %s", 00174 nl_size2str(i6->i6_cacheinfo.max_reasm_len, buf, sizeof(buf))); 00175 00176 nl_dump(p, " <%s>\n", 00177 inet6_flags2str(i6->i6_flags, buf, sizeof(buf))); 00178 00179 00180 nl_dump_line(p, " create-stamp %.2fs reachable-time %s", 00181 (double) i6->i6_cacheinfo.tstamp / 100., 00182 nl_msec2str(i6->i6_cacheinfo.reachable_time, buf, sizeof(buf))); 00183 00184 nl_dump(p, " retrans-time %s\n", 00185 nl_msec2str(i6->i6_cacheinfo.retrans_time, buf, sizeof(buf))); 00186 00187 nl_dump_line(p, " devconf:\n"); 00188 nl_dump_line(p, " "); 00189 00190 for (i = 0; i < DEVCONF_MAX; i++) { 00191 uint32_t value = i6->i6_conf[i]; 00192 int x, offset; 00193 00194 switch (i) { 00195 case DEVCONF_TEMP_VALID_LFT: 00196 case DEVCONF_TEMP_PREFERED_LFT: 00197 nl_msec2str((uint64_t) value * 1000., buf2, sizeof(buf2)); 00198 break; 00199 00200 case DEVCONF_RTR_PROBE_INTERVAL: 00201 case DEVCONF_RTR_SOLICIT_INTERVAL: 00202 case DEVCONF_RTR_SOLICIT_DELAY: 00203 nl_msec2str(value, buf2, sizeof(buf2)); 00204 break; 00205 00206 default: 00207 snprintf(buf2, sizeof(buf2), "%u", value); 00208 break; 00209 00210 } 00211 00212 inet6_devconf2str(i, buf, sizeof(buf)); 00213 00214 offset = 23 - strlen(buf2); 00215 if (offset < 0) 00216 offset = 0; 00217 00218 for (x = strlen(buf); x < offset; x++) 00219 buf[x] = ' '; 00220 00221 strncpy(&buf[offset], buf2, strlen(buf2)); 00222 00223 nl_dump_line(p, "%s", buf); 00224 00225 if (++n == 3) { 00226 nl_dump(p, "\n"); 00227 nl_dump_line(p, " "); 00228 n = 0; 00229 } else 00230 nl_dump(p, " "); 00231 } 00232 00233 if (n != 0) 00234 nl_dump(p, "\n"); 00235 } 00236 00237 static void inet6_dump_stats(struct rtnl_link *link, 00238 struct nl_dump_params *p, void *data) 00239 { 00240 double octets; 00241 char *octetsUnit; 00242 00243 nl_dump(p, " IPv6: InPkts InOctets " 00244 " InDiscards InDelivers\n"); 00245 nl_dump(p, " %18llu ", link->l_stats[RTNL_LINK_IP6_INPKTS]); 00246 00247 octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_INOCTETS], 00248 &octetsUnit); 00249 if (octets) 00250 nl_dump(p, "%14.2f %3s ", octets, octetsUnit); 00251 else 00252 nl_dump(p, "%16llu B ", 0); 00253 00254 nl_dump(p, "%18llu %18llu\n", 00255 link->l_stats[RTNL_LINK_IP6_INDISCARDS], 00256 link->l_stats[RTNL_LINK_IP6_INDELIVERS]); 00257 00258 nl_dump(p, " OutPkts OutOctets " 00259 " OutDiscards OutForwards\n"); 00260 00261 nl_dump(p, " %18llu ", link->l_stats[RTNL_LINK_IP6_OUTPKTS]); 00262 00263 octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_OUTOCTETS], 00264 &octetsUnit); 00265 if (octets) 00266 nl_dump(p, "%14.2f %3s ", octets, octetsUnit); 00267 else 00268 nl_dump(p, "%16llu B ", 0); 00269 00270 nl_dump(p, "%18llu %18llu\n", 00271 link->l_stats[RTNL_LINK_IP6_OUTDISCARDS], 00272 link->l_stats[RTNL_LINK_IP6_OUTFORWDATAGRAMS]); 00273 00274 nl_dump(p, " InMcastPkts InMcastOctets " 00275 " InBcastPkts InBcastOctests\n"); 00276 00277 nl_dump(p, " %18llu ", link->l_stats[RTNL_LINK_IP6_INMCASTPKTS]); 00278 00279 octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_INMCASTOCTETS], 00280 &octetsUnit); 00281 if (octets) 00282 nl_dump(p, "%14.2f %3s ", octets, octetsUnit); 00283 else 00284 nl_dump(p, "%16llu B ", 0); 00285 00286 nl_dump(p, "%18llu ", link->l_stats[RTNL_LINK_IP6_INBCASTPKTS]); 00287 octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_INBCASTOCTETS], 00288 &octetsUnit); 00289 if (octets) 00290 nl_dump(p, "%14.2f %3s\n", octets, octetsUnit); 00291 else 00292 nl_dump(p, "%16llu B\n", 0); 00293 00294 nl_dump(p, " OutMcastPkts OutMcastOctets " 00295 " OutBcastPkts OutBcastOctests\n"); 00296 00297 nl_dump(p, " %18llu ", link->l_stats[RTNL_LINK_IP6_OUTMCASTPKTS]); 00298 00299 octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_OUTMCASTOCTETS], 00300 &octetsUnit); 00301 if (octets) 00302 nl_dump(p, "%14.2f %3s ", octets, octetsUnit); 00303 else 00304 nl_dump(p, "%16llu B ", 0); 00305 00306 nl_dump(p, "%18llu ", link->l_stats[RTNL_LINK_IP6_OUTBCASTPKTS]); 00307 octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_OUTBCASTOCTETS], 00308 &octetsUnit); 00309 if (octets) 00310 nl_dump(p, "%14.2f %3s\n", octets, octetsUnit); 00311 else 00312 nl_dump(p, "%16llu B\n", 0); 00313 00314 nl_dump(p, " ReasmOKs ReasmFails " 00315 " ReasmReqds ReasmTimeout\n"); 00316 nl_dump(p, " %18llu %18llu %18llu %18llu\n", 00317 link->l_stats[RTNL_LINK_IP6_REASMOKS], 00318 link->l_stats[RTNL_LINK_IP6_REASMFAILS], 00319 link->l_stats[RTNL_LINK_IP6_REASMREQDS], 00320 link->l_stats[RTNL_LINK_IP6_REASMTIMEOUT]); 00321 00322 nl_dump(p, " FragOKs FragFails " 00323 " FragCreates\n"); 00324 nl_dump(p, " %18llu %18llu %18llu\n", 00325 link->l_stats[RTNL_LINK_IP6_FRAGOKS], 00326 link->l_stats[RTNL_LINK_IP6_FRAGFAILS], 00327 link->l_stats[RTNL_LINK_IP6_FRAGCREATES]); 00328 00329 nl_dump(p, " InHdrErrors InTooBigErrors " 00330 " InNoRoutes InAddrErrors\n"); 00331 nl_dump(p, " %18llu %18llu %18llu %18llu\n", 00332 link->l_stats[RTNL_LINK_IP6_INHDRERRORS], 00333 link->l_stats[RTNL_LINK_IP6_INTOOBIGERRORS], 00334 link->l_stats[RTNL_LINK_IP6_INNOROUTES], 00335 link->l_stats[RTNL_LINK_IP6_INADDRERRORS]); 00336 00337 nl_dump(p, " InUnknownProtos InTruncatedPkts " 00338 " OutNoRoutes\n"); 00339 nl_dump(p, " %18llu %18llu %18llu\n", 00340 link->l_stats[RTNL_LINK_IP6_INUNKNOWNPROTOS], 00341 link->l_stats[RTNL_LINK_IP6_INTRUNCATEDPKTS], 00342 link->l_stats[RTNL_LINK_IP6_OUTNOROUTES]); 00343 00344 nl_dump(p, " ICMPv6: InMsgs InErrors " 00345 " OutMsgs OutErrors\n"); 00346 nl_dump(p, " %18llu %18llu %18llu %18llu\n", 00347 link->l_stats[RTNL_LINK_ICMP6_INMSGS], 00348 link->l_stats[RTNL_LINK_ICMP6_INERRORS], 00349 link->l_stats[RTNL_LINK_ICMP6_OUTMSGS], 00350 link->l_stats[RTNL_LINK_ICMP6_OUTERRORS]); 00351 } 00352 00353 static const struct nla_policy protinfo_policy = { 00354 .type = NLA_NESTED, 00355 }; 00356 00357 static struct rtnl_link_af_ops inet6_ops = { 00358 .ao_family = AF_INET6, 00359 .ao_alloc = &inet6_alloc, 00360 .ao_clone = &inet6_clone, 00361 .ao_free = &inet6_free, 00362 .ao_parse_protinfo = &inet6_parse_protinfo, 00363 .ao_parse_af = &inet6_parse_protinfo, 00364 .ao_dump[NL_DUMP_DETAILS] = &inet6_dump_details, 00365 .ao_dump[NL_DUMP_STATS] = &inet6_dump_stats, 00366 .ao_protinfo_policy = &protinfo_policy, 00367 }; 00368 00369 static void __init inet6_init(void) 00370 { 00371 rtnl_link_af_register(&inet6_ops); 00372 } 00373 00374 static void __exit inet6_exit(void) 00375 { 00376 rtnl_link_af_unregister(&inet6_ops); 00377 }