libnl  3.2.3
/build/buildd/libnl3-3.2.3/lib/route/link/inet6.c
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 }