libnl 3.0
|
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 if (tb[IFLA_INET6_STATS]) { 00076 uint64_t *cnt = nla_data(tb[IFLA_INET6_STATS]); 00077 int i; 00078 00079 for (i = 1; i < __IPSTATS_MIB_MAX; i++) 00080 rtnl_link_set_stat(link, RTNL_LINK_IP6_INPKTS + i - 1, 00081 cnt[i]); 00082 } 00083 00084 if (tb[IFLA_INET6_ICMP6STATS]) { 00085 uint64_t *cnt = nla_data(tb[IFLA_INET6_ICMP6STATS]); 00086 int i; 00087 00088 for (i = 1; i < __ICMP6_MIB_MAX; i++) 00089 rtnl_link_set_stat(link, RTNL_LINK_ICMP6_INMSGS + i - 1, 00090 cnt[i]); 00091 } 00092 00093 return 0; 00094 } 00095 00096 /* These live in include/net/if_inet6.h and should be moved to include/linux */ 00097 #define IF_RA_OTHERCONF 0x80 00098 #define IF_RA_MANAGED 0x40 00099 #define IF_RA_RCVD 0x20 00100 #define IF_RS_SENT 0x10 00101 #define IF_READY 0x80000000 00102 00103 static const struct trans_tbl inet6_flags[] = { 00104 __ADD(IF_RA_OTHERCONF, ra_otherconf) 00105 __ADD(IF_RA_MANAGED, ra_managed) 00106 __ADD(IF_RA_RCVD, ra_rcvd) 00107 __ADD(IF_RS_SENT, rs_sent) 00108 __ADD(IF_READY, ready) 00109 }; 00110 00111 static char *inet6_flags2str(int flags, char *buf, size_t len) 00112 { 00113 return __flags2str(flags, buf, len, inet6_flags, 00114 ARRAY_SIZE(inet6_flags)); 00115 } 00116 00117 static const struct trans_tbl inet6_devconf[] = { 00118 __ADD(DEVCONF_FORWARDING, forwarding) 00119 __ADD(DEVCONF_HOPLIMIT, hoplimit) 00120 __ADD(DEVCONF_MTU6, mtu6) 00121 __ADD(DEVCONF_ACCEPT_RA, accept_ra) 00122 __ADD(DEVCONF_ACCEPT_REDIRECTS, accept_redirects) 00123 __ADD(DEVCONF_AUTOCONF, autoconf) 00124 __ADD(DEVCONF_DAD_TRANSMITS, dad_transmits) 00125 __ADD(DEVCONF_RTR_SOLICITS, rtr_solicits) 00126 __ADD(DEVCONF_RTR_SOLICIT_INTERVAL, rtr_solicit_interval) 00127 __ADD(DEVCONF_RTR_SOLICIT_DELAY, rtr_solicit_delay) 00128 __ADD(DEVCONF_USE_TEMPADDR, use_tempaddr) 00129 __ADD(DEVCONF_TEMP_VALID_LFT, temp_valid_lft) 00130 __ADD(DEVCONF_TEMP_PREFERED_LFT, temp_prefered_lft) 00131 __ADD(DEVCONF_REGEN_MAX_RETRY, regen_max_retry) 00132 __ADD(DEVCONF_MAX_DESYNC_FACTOR, max_desync_factor) 00133 __ADD(DEVCONF_MAX_ADDRESSES, max_addresses) 00134 __ADD(DEVCONF_FORCE_MLD_VERSION, force_mld_version) 00135 __ADD(DEVCONF_ACCEPT_RA_DEFRTR, accept_ra_defrtr) 00136 __ADD(DEVCONF_ACCEPT_RA_PINFO, accept_ra_pinfo) 00137 __ADD(DEVCONF_ACCEPT_RA_RTR_PREF, accept_ra_rtr_pref) 00138 __ADD(DEVCONF_RTR_PROBE_INTERVAL, rtr_probe_interval) 00139 __ADD(DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN, accept_ra_rt_info) 00140 __ADD(DEVCONF_PROXY_NDP, proxy_ndp) 00141 __ADD(DEVCONF_OPTIMISTIC_DAD, optimistic_dad) 00142 __ADD(DEVCONF_ACCEPT_SOURCE_ROUTE, accept_source_route) 00143 __ADD(DEVCONF_MC_FORWARDING, mc_forwarding) 00144 __ADD(DEVCONF_DISABLE_IPV6, disable_ipv6) 00145 __ADD(DEVCONF_ACCEPT_DAD, accept_dad) 00146 __ADD(DEVCONF_FORCE_TLLAO, force_tllao) 00147 }; 00148 00149 static char *inet6_devconf2str(int type, char *buf, size_t len) 00150 { 00151 return __type2str(type, buf, len, inet6_devconf, 00152 ARRAY_SIZE(inet6_devconf)); 00153 } 00154 00155 00156 static void inet6_dump_details(struct rtnl_link *link, 00157 struct nl_dump_params *p, void *data) 00158 { 00159 struct inet6_data *i6 = data; 00160 char buf[64], buf2[64]; 00161 int i, n = 0; 00162 00163 nl_dump_line(p, " ipv6 max-reasm-len %s", 00164 nl_size2str(i6->i6_cacheinfo.max_reasm_len, buf, sizeof(buf))); 00165 00166 nl_dump(p, " <%s>\n", 00167 inet6_flags2str(i6->i6_flags, buf, sizeof(buf))); 00168 00169 00170 nl_dump_line(p, " create-stamp %.2fs reachable-time %s", 00171 (double) i6->i6_cacheinfo.tstamp / 100., 00172 nl_msec2str(i6->i6_cacheinfo.reachable_time, buf, sizeof(buf))); 00173 00174 nl_dump(p, " retrans-time %s\n", 00175 nl_msec2str(i6->i6_cacheinfo.retrans_time, buf, sizeof(buf))); 00176 00177 nl_dump_line(p, " devconf:\n"); 00178 nl_dump_line(p, " "); 00179 00180 for (i = 0; i < DEVCONF_MAX; i++) { 00181 uint32_t value = i6->i6_conf[i]; 00182 int x, offset; 00183 00184 switch (i) { 00185 case DEVCONF_TEMP_VALID_LFT: 00186 case DEVCONF_TEMP_PREFERED_LFT: 00187 nl_msec2str((uint64_t) value * 1000., buf2, sizeof(buf2)); 00188 break; 00189 00190 case DEVCONF_RTR_PROBE_INTERVAL: 00191 case DEVCONF_RTR_SOLICIT_INTERVAL: 00192 case DEVCONF_RTR_SOLICIT_DELAY: 00193 nl_msec2str(value, buf2, sizeof(buf2)); 00194 break; 00195 00196 default: 00197 snprintf(buf2, sizeof(buf2), "%u", value); 00198 break; 00199 00200 } 00201 00202 inet6_devconf2str(i, buf, sizeof(buf)); 00203 00204 offset = 23 - strlen(buf2); 00205 if (offset < 0) 00206 offset = 0; 00207 00208 for (x = strlen(buf); x < offset; x++) 00209 buf[x] = ' '; 00210 00211 strncpy(&buf[offset], buf2, strlen(buf2)); 00212 00213 nl_dump_line(p, "%s", buf); 00214 00215 if (++n == 3) { 00216 nl_dump(p, "\n"); 00217 nl_dump_line(p, " "); 00218 n = 0; 00219 } else 00220 nl_dump(p, " "); 00221 } 00222 00223 if (n != 0) 00224 nl_dump(p, "\n"); 00225 } 00226 00227 static void inet6_dump_stats(struct rtnl_link *link, 00228 struct nl_dump_params *p, void *data) 00229 { 00230 double octets; 00231 char *octetsUnit; 00232 00233 nl_dump(p, " IPv6: InPkts InOctets " 00234 " InDiscards InDelivers\n"); 00235 nl_dump(p, " %18llu ", link->l_stats[RTNL_LINK_IP6_INPKTS]); 00236 00237 octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_INOCTETS], 00238 &octetsUnit); 00239 if (octets) 00240 nl_dump(p, "%14.2f %3s ", octets, octetsUnit); 00241 else 00242 nl_dump(p, "%16llu B ", 0); 00243 00244 nl_dump(p, "%18llu %18llu\n", 00245 link->l_stats[RTNL_LINK_IP6_INDISCARDS], 00246 link->l_stats[RTNL_LINK_IP6_INDELIVERS]); 00247 00248 nl_dump(p, " OutPkts OutOctets " 00249 " OutDiscards OutForwards\n"); 00250 00251 nl_dump(p, " %18llu ", link->l_stats[RTNL_LINK_IP6_OUTPKTS]); 00252 00253 octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_OUTOCTETS], 00254 &octetsUnit); 00255 if (octets) 00256 nl_dump(p, "%14.2f %3s ", octets, octetsUnit); 00257 else 00258 nl_dump(p, "%16llu B ", 0); 00259 00260 nl_dump(p, "%18llu %18llu\n", 00261 link->l_stats[RTNL_LINK_IP6_OUTDISCARDS], 00262 link->l_stats[RTNL_LINK_IP6_OUTFORWDATAGRAMS]); 00263 00264 nl_dump(p, " InMcastPkts InMcastOctets " 00265 " InBcastPkts InBcastOctests\n"); 00266 00267 nl_dump(p, " %18llu ", link->l_stats[RTNL_LINK_IP6_INMCASTPKTS]); 00268 00269 octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_INMCASTOCTETS], 00270 &octetsUnit); 00271 if (octets) 00272 nl_dump(p, "%14.2f %3s ", octets, octetsUnit); 00273 else 00274 nl_dump(p, "%16llu B ", 0); 00275 00276 nl_dump(p, "%18llu ", link->l_stats[RTNL_LINK_IP6_INBCASTPKTS]); 00277 octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_INBCASTOCTETS], 00278 &octetsUnit); 00279 if (octets) 00280 nl_dump(p, "%14.2f %3s\n", octets, octetsUnit); 00281 else 00282 nl_dump(p, "%16llu B\n", 0); 00283 00284 nl_dump(p, " OutMcastPkts OutMcastOctets " 00285 " OutBcastPkts OutBcastOctests\n"); 00286 00287 nl_dump(p, " %18llu ", link->l_stats[RTNL_LINK_IP6_OUTMCASTPKTS]); 00288 00289 octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_OUTMCASTOCTETS], 00290 &octetsUnit); 00291 if (octets) 00292 nl_dump(p, "%14.2f %3s ", octets, octetsUnit); 00293 else 00294 nl_dump(p, "%16llu B ", 0); 00295 00296 nl_dump(p, "%18llu ", link->l_stats[RTNL_LINK_IP6_OUTBCASTPKTS]); 00297 octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_OUTBCASTOCTETS], 00298 &octetsUnit); 00299 if (octets) 00300 nl_dump(p, "%14.2f %3s\n", octets, octetsUnit); 00301 else 00302 nl_dump(p, "%16llu B\n", 0); 00303 00304 nl_dump(p, " ReasmOKs ReasmFails " 00305 " ReasmReqds ReasmTimeout\n"); 00306 nl_dump(p, " %18llu %18llu %18llu %18llu\n", 00307 link->l_stats[RTNL_LINK_IP6_REASMOKS], 00308 link->l_stats[RTNL_LINK_IP6_REASMFAILS], 00309 link->l_stats[RTNL_LINK_IP6_REASMREQDS], 00310 link->l_stats[RTNL_LINK_IP6_REASMTIMEOUT]); 00311 00312 nl_dump(p, " FragOKs FragFails " 00313 " FragCreates\n"); 00314 nl_dump(p, " %18llu %18llu %18llu\n", 00315 link->l_stats[RTNL_LINK_IP6_FRAGOKS], 00316 link->l_stats[RTNL_LINK_IP6_FRAGFAILS], 00317 link->l_stats[RTNL_LINK_IP6_FRAGCREATES]); 00318 00319 nl_dump(p, " InHdrErrors InTooBigErrors " 00320 " InNoRoutes InAddrErrors\n"); 00321 nl_dump(p, " %18llu %18llu %18llu %18llu\n", 00322 link->l_stats[RTNL_LINK_IP6_INHDRERRORS], 00323 link->l_stats[RTNL_LINK_IP6_INTOOBIGERRORS], 00324 link->l_stats[RTNL_LINK_IP6_INNOROUTES], 00325 link->l_stats[RTNL_LINK_IP6_INADDRERRORS]); 00326 00327 nl_dump(p, " InUnknownProtos InTruncatedPkts " 00328 " OutNoRoutes\n"); 00329 nl_dump(p, " %18llu %18llu %18llu\n", 00330 link->l_stats[RTNL_LINK_IP6_INUNKNOWNPROTOS], 00331 link->l_stats[RTNL_LINK_IP6_INTRUNCATEDPKTS], 00332 link->l_stats[RTNL_LINK_IP6_OUTNOROUTES]); 00333 00334 nl_dump(p, " ICMPv6: InMsgs InErrors " 00335 " OutMsgs OutErrors\n"); 00336 nl_dump(p, " %18llu %18llu %18llu %18llu\n", 00337 link->l_stats[RTNL_LINK_ICMP6_INMSGS], 00338 link->l_stats[RTNL_LINK_ICMP6_INERRORS], 00339 link->l_stats[RTNL_LINK_ICMP6_OUTMSGS], 00340 link->l_stats[RTNL_LINK_ICMP6_OUTERRORS]); 00341 } 00342 00343 static const struct nla_policy protinfo_policy = { 00344 .type = NLA_NESTED, 00345 }; 00346 00347 static struct rtnl_link_af_ops inet6_ops = { 00348 .ao_family = AF_INET6, 00349 .ao_alloc = &inet6_alloc, 00350 .ao_clone = &inet6_clone, 00351 .ao_free = &inet6_free, 00352 .ao_parse_protinfo = &inet6_parse_protinfo, 00353 .ao_parse_af = &inet6_parse_protinfo, 00354 .ao_dump[NL_DUMP_DETAILS] = &inet6_dump_details, 00355 .ao_dump[NL_DUMP_STATS] = &inet6_dump_stats, 00356 .ao_protinfo_policy = &protinfo_policy, 00357 }; 00358 00359 static void __init inet6_init(void) 00360 { 00361 rtnl_link_af_register(&inet6_ops); 00362 } 00363 00364 static void __exit inet6_exit(void) 00365 { 00366 rtnl_link_af_unregister(&inet6_ops); 00367 }