libnl 1.1
lib/route/route_obj.c
00001 /*
00002  * lib/route/route_obj.c        Route Object
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) 2003-2006 Thomas Graf <tgraf@suug.ch>
00010  */
00011 
00012 /**
00013  * @ingroup route
00014  * @defgroup route_obj Route Object
00015  *
00016  * @par Attributes
00017  * @code
00018  * Name                                           Default
00019  * -------------------------------------------------------------
00020  * routing table                                  RT_TABLE_MAIN
00021  * scope                                          RT_SCOPE_NOWHERE
00022  * tos                                            0
00023  * realms                                         0
00024  * protocol                                       RTPROT_STATIC
00025  * prio                                           0
00026  * family                                         AF_UNSPEC
00027  * type                                           RTN_UNICAST
00028  * oif                                            RTNL_LINK_NOT_FOUND
00029  * iif                                            NULL
00030  * mpalgo                                         IP_MP_ALG_NONE
00031  * @endcode
00032  *
00033  * @{
00034  */
00035 
00036 #include <netlink-local.h>
00037 #include <netlink/netlink.h>
00038 #include <netlink/cache.h>
00039 #include <netlink/utils.h>
00040 #include <netlink/data.h>
00041 #include <netlink/route/rtnl.h>
00042 #include <netlink/route/route.h>
00043 #include <netlink/route/link.h>
00044 
00045 /** @cond SKIP */
00046 #define ROUTE_ATTR_FAMILY    0x000001
00047 #define ROUTE_ATTR_TOS       0x000002
00048 #define ROUTE_ATTR_TABLE     0x000004
00049 #define ROUTE_ATTR_PROTOCOL  0x000008
00050 #define ROUTE_ATTR_SCOPE     0x000010
00051 #define ROUTE_ATTR_TYPE      0x000020
00052 #define ROUTE_ATTR_FLAGS     0x000040
00053 #define ROUTE_ATTR_DST       0x000080
00054 #define ROUTE_ATTR_SRC       0x000100
00055 #define ROUTE_ATTR_IIF       0x000200
00056 #define ROUTE_ATTR_OIF       0x000400
00057 #define ROUTE_ATTR_GATEWAY   0x000800
00058 #define ROUTE_ATTR_PRIO      0x001000
00059 #define ROUTE_ATTR_PREF_SRC  0x002000
00060 #define ROUTE_ATTR_METRICS   0x004000
00061 #define ROUTE_ATTR_MULTIPATH 0x008000
00062 #define ROUTE_ATTR_REALMS    0x010000
00063 #define ROUTE_ATTR_CACHEINFO 0x020000
00064 #define ROUTE_ATTR_MP_ALGO   0x040000
00065 /** @endcond */
00066 
00067 static int route_dump_brief(struct nl_object *a, struct nl_dump_params *p);
00068 
00069 static void route_constructor(struct nl_object *c)
00070 {
00071         struct rtnl_route *r = (struct rtnl_route *) c;
00072 
00073         nl_init_list_head(&r->rt_nexthops);
00074 }
00075 
00076 static void route_free_data(struct nl_object *c)
00077 {
00078         struct rtnl_route *r = (struct rtnl_route *) c;
00079         struct rtnl_nexthop *nh, *tmp;
00080 
00081         if (r == NULL)
00082                 return;
00083 
00084         nl_addr_put(r->rt_dst);
00085         nl_addr_put(r->rt_src);
00086         nl_addr_put(r->rt_gateway);
00087         nl_addr_put(r->rt_pref_src);
00088 
00089         nl_list_for_each_entry_safe(nh, tmp, &r->rt_nexthops, rtnh_list) {
00090                 rtnl_route_remove_nexthop(nh);
00091                 rtnl_route_nh_free(nh);
00092         }
00093 }
00094 
00095 static int route_clone(struct nl_object *_dst, struct nl_object *_src)
00096 {
00097         struct rtnl_route *dst = (struct rtnl_route *) _dst;
00098         struct rtnl_route *src = (struct rtnl_route *) _src;
00099         struct rtnl_nexthop *nh, *new;
00100 
00101         if (src->rt_dst)
00102                 if (!(dst->rt_dst = nl_addr_clone(src->rt_dst)))
00103                         goto errout;
00104 
00105         if (src->rt_src)
00106                 if (!(dst->rt_src = nl_addr_clone(src->rt_src)))
00107                         goto errout;
00108 
00109         if (src->rt_gateway)
00110                 if (!(dst->rt_gateway = nl_addr_clone(src->rt_gateway)))
00111                         goto errout;
00112         
00113         if (src->rt_pref_src)
00114                 if (!(dst->rt_pref_src = nl_addr_clone(src->rt_pref_src)))
00115                         goto errout;
00116 
00117         nl_init_list_head(&dst->rt_nexthops);
00118         nl_list_for_each_entry(nh, &src->rt_nexthops, rtnh_list) {
00119                 new = rtnl_route_nh_clone(nh);
00120                 if (!new)
00121                         goto errout;
00122 
00123                 rtnl_route_add_nexthop(dst, new);
00124         }
00125 
00126         return 0;
00127 errout:
00128         return nl_get_errno();
00129 }
00130 
00131 static int route_dump_brief(struct nl_object *a, struct nl_dump_params *p)
00132 {
00133         struct rtnl_route *r = (struct rtnl_route *) a;
00134         struct nl_cache *link_cache;
00135         char buf[64];
00136 
00137         link_cache = nl_cache_mngt_require("route/link");
00138 
00139         if (!(r->ce_mask & ROUTE_ATTR_DST) ||
00140             nl_addr_get_len(r->rt_dst) == 0)
00141                 dp_dump(p, "default ");
00142         else
00143                 dp_dump(p, "%s ", nl_addr2str(r->rt_dst, buf, sizeof(buf)));
00144 
00145         if (r->ce_mask & ROUTE_ATTR_OIF) {
00146                 if (link_cache)
00147                         dp_dump(p, "dev %s ",
00148                                 rtnl_link_i2name(link_cache, r->rt_oif,
00149                                                  buf, sizeof(buf)));
00150                 else
00151                         dp_dump(p, "dev %d ", r->rt_oif);
00152         }
00153 
00154         if (r->ce_mask & ROUTE_ATTR_GATEWAY)
00155                 dp_dump(p, "via %s ", nl_addr2str(r->rt_gateway, buf,
00156                                                   sizeof(buf)));
00157         else if (r->ce_mask & ROUTE_ATTR_MULTIPATH)
00158                 dp_dump(p, "via nexthops ");
00159 
00160         if (r->ce_mask & ROUTE_ATTR_SCOPE)
00161                 dp_dump(p, "scope %s ",
00162                         rtnl_scope2str(r->rt_scope, buf, sizeof(buf)));
00163 
00164         if (r->ce_mask & ROUTE_ATTR_FLAGS && r->rt_flags) {
00165                 int flags = r->rt_flags;
00166 
00167                 dp_dump(p, "<");
00168                 
00169 #define PRINT_FLAG(f) if (flags & RTNH_F_##f) { \
00170                 flags &= ~RTNH_F_##f; dp_dump(p, #f "%s", flags ? "," : ""); }
00171                 PRINT_FLAG(DEAD);
00172                 PRINT_FLAG(ONLINK);
00173                 PRINT_FLAG(PERVASIVE);
00174 #undef PRINT_FLAG
00175 
00176 #define PRINT_FLAG(f) if (flags & RTM_F_##f) { \
00177                 flags &= ~RTM_F_##f; dp_dump(p, #f "%s", flags ? "," : ""); }
00178                 PRINT_FLAG(NOTIFY);
00179                 PRINT_FLAG(CLONED);
00180                 PRINT_FLAG(EQUALIZE);
00181                 PRINT_FLAG(PREFIX);
00182 #undef PRINT_FLAG
00183 
00184                 dp_dump(p, ">");
00185         }
00186 
00187         dp_dump(p, "\n");
00188 
00189         return 1;
00190 }
00191 
00192 static int route_dump_full(struct nl_object *a, struct nl_dump_params *p)
00193 {
00194         struct rtnl_route *r = (struct rtnl_route *) a;
00195         struct nl_cache *link_cache;
00196         char buf[128];
00197         int i, line;
00198 
00199         link_cache = nl_cache_mngt_require("route/link");
00200         line = route_dump_brief(a, p);
00201 
00202         if (r->ce_mask & ROUTE_ATTR_MULTIPATH) {
00203                 struct rtnl_nexthop *nh;
00204 
00205                 nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) {
00206                         dp_dump_line(p, line++, "  via ");
00207 
00208                         if (nh->rtnh_mask & NEXTHOP_HAS_GATEWAY)
00209                                 dp_dump(p, "%s ",
00210                                         nl_addr2str(nh->rtnh_gateway,
00211                                                     buf, sizeof(buf)));
00212                         if (link_cache) {
00213                                 dp_dump(p, "dev %s ",
00214                                         rtnl_link_i2name(link_cache,
00215                                                          nh->rtnh_ifindex,
00216                                                          buf, sizeof(buf)));
00217                         } else
00218                                 dp_dump(p, "dev %d ", nh->rtnh_ifindex);
00219 
00220                         dp_dump(p, "weight %u <%s>\n", nh->rtnh_weight,
00221                                 rtnl_route_nh_flags2str(nh->rtnh_flags,
00222                                                         buf, sizeof(buf)));
00223                 }
00224         }
00225 
00226         dp_dump_line(p, line++, "  ");
00227 
00228         if (r->ce_mask & ROUTE_ATTR_PREF_SRC)
00229                 dp_dump(p, "preferred-src %s ",
00230                         nl_addr2str(r->rt_pref_src, buf, sizeof(buf)));
00231 
00232         if (r->ce_mask & ROUTE_ATTR_TABLE)
00233                 dp_dump(p, "table %s ",
00234                         rtnl_route_table2str(r->rt_table, buf, sizeof(buf)));
00235 
00236         if (r->ce_mask & ROUTE_ATTR_TYPE)
00237                 dp_dump(p, "type %s ",
00238                         nl_rtntype2str(r->rt_type, buf, sizeof(buf)));
00239 
00240         if (r->ce_mask & ROUTE_ATTR_PRIO)
00241                 dp_dump(p, "metric %#x ", r->rt_prio);
00242 
00243         if (r->ce_mask & ROUTE_ATTR_FAMILY)
00244                 dp_dump(p, "family %s ",
00245                         nl_af2str(r->rt_family, buf, sizeof(buf)));
00246 
00247         if (r->ce_mask & ROUTE_ATTR_PROTOCOL)
00248                 dp_dump(p, "protocol %s ",
00249                         rtnl_route_proto2str(r->rt_protocol, buf, sizeof(buf)));
00250 
00251         dp_dump(p, "\n");
00252 
00253         if ((r->ce_mask & (ROUTE_ATTR_IIF | ROUTE_ATTR_SRC | ROUTE_ATTR_TOS |
00254                            ROUTE_ATTR_REALMS)) || 
00255             ((r->ce_mask & ROUTE_ATTR_CACHEINFO) &&
00256              r->rt_cacheinfo.rtci_error)) {
00257                 dp_dump_line(p, line++, "  ");
00258 
00259                 if (r->ce_mask & ROUTE_ATTR_IIF)
00260                         dp_dump(p, "iif %s ", r->rt_iif);
00261 
00262                 if (r->ce_mask & ROUTE_ATTR_SRC)
00263                         dp_dump(p, "src %s ",
00264                                 nl_addr2str(r->rt_src, buf, sizeof(buf)));
00265 
00266                 if (r->ce_mask & ROUTE_ATTR_TOS)
00267                         dp_dump(p, "tos %#x ", r->rt_tos);
00268 
00269                 if (r->ce_mask & ROUTE_ATTR_REALMS)
00270                         dp_dump(p, "realm %04x:%04x ",
00271                                 RTNL_REALM_FROM(r->rt_realms),
00272                                 RTNL_REALM_TO(r->rt_realms));
00273 
00274                 if ((r->ce_mask & ROUTE_ATTR_CACHEINFO) &&
00275                     r->rt_cacheinfo.rtci_error)
00276                         dp_dump(p, "error %d (%s) ", r->rt_cacheinfo.rtci_error,
00277                                 strerror(-r->rt_cacheinfo.rtci_error));
00278 
00279                 dp_dump(p, "\n");
00280         }
00281 
00282         if (r->ce_mask & ROUTE_ATTR_METRICS) {
00283                 dp_dump_line(p, line++, "  ");
00284                 for (i = 0; i < RTAX_MAX; i++)
00285                         if (r->rt_metrics_mask & (1 << i))
00286                                 dp_dump(p, "%s %u ",
00287                                         rtnl_route_metric2str(i+1,
00288                                                               buf, sizeof(buf)),
00289                                         r->rt_metrics[i]);
00290                 dp_dump(p, "\n");
00291         }
00292 
00293         return line;
00294 }
00295 
00296 static int route_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
00297 {
00298         struct rtnl_route *route = (struct rtnl_route *) obj;
00299         int line;
00300 
00301         line = route_dump_full(obj, p);
00302 
00303         if (route->ce_mask & ROUTE_ATTR_CACHEINFO) {
00304                 struct rtnl_rtcacheinfo *ci = &route->rt_cacheinfo;
00305                 dp_dump_line(p, line++, "  used %u refcnt %u ",
00306                              ci->rtci_used, ci->rtci_clntref);
00307                 dp_dump_line(p, line++, "last-use %us expires %us\n",
00308                              ci->rtci_last_use / nl_get_hz(),
00309                              ci->rtci_expires / nl_get_hz());
00310         }
00311 
00312         return line;
00313 }
00314 
00315 static int route_dump_xml(struct nl_object *obj, struct nl_dump_params *p)
00316 {
00317         struct rtnl_route *route = (struct rtnl_route *) obj;
00318         char buf[128];
00319         int line = 0;
00320         
00321         dp_dump_line(p, line++, "<route>\n");
00322         dp_dump_line(p, line++, "  <family>%s</family>\n",
00323                      nl_af2str(route->rt_family, buf, sizeof(buf)));
00324 
00325         if (route->ce_mask & ROUTE_ATTR_DST)
00326                 dp_dump_line(p, line++, "  <dst>%s</dst>\n",
00327                              nl_addr2str(route->rt_dst, buf, sizeof(buf)));
00328 
00329         if (route->ce_mask & ROUTE_ATTR_SRC)
00330                 dp_dump_line(p, line++, "  <src>%s</src>\n",
00331                              nl_addr2str(route->rt_src, buf, sizeof(buf)));
00332 
00333         if (route->ce_mask & ROUTE_ATTR_GATEWAY)
00334                 dp_dump_line(p, line++, "  <gateway>%s</gateway>\n",
00335                              nl_addr2str(route->rt_gateway, buf, sizeof(buf)));
00336 
00337         if (route->ce_mask & ROUTE_ATTR_PREF_SRC)
00338                 dp_dump_line(p, line++, "  <prefsrc>%s</prefsrc>\n",
00339                              nl_addr2str(route->rt_pref_src, buf, sizeof(buf)));
00340 
00341         if (route->ce_mask & ROUTE_ATTR_IIF)
00342                 dp_dump_line(p, line++, "  <iif>%s</iif>\n", route->rt_iif);
00343 
00344         if (route->ce_mask & ROUTE_ATTR_REALMS)
00345                 dp_dump_line(p, line++, "  <realms>%u</realms>\n",
00346                              route->rt_realms);
00347 
00348         if (route->ce_mask & ROUTE_ATTR_TOS)
00349                 dp_dump_line(p, line++, "  <tos>%u</tos>\n", route->rt_tos);
00350 
00351         if (route->ce_mask & ROUTE_ATTR_TABLE)
00352                 dp_dump_line(p, line++, "  <table>%u</table>\n",
00353                              route->rt_table);
00354 
00355         if (route->ce_mask & ROUTE_ATTR_SCOPE)
00356                 dp_dump_line(p, line++, "  <scope>%s</scope>\n",
00357                              rtnl_scope2str(route->rt_scope, buf, sizeof(buf)));
00358 
00359         if (route->ce_mask & ROUTE_ATTR_PRIO)
00360                 dp_dump_line(p, line++, "  <metric>%u</metric>\n",
00361                              route->rt_prio);
00362 
00363         if (route->ce_mask & ROUTE_ATTR_OIF) {
00364                 struct nl_cache *link_cache;
00365         
00366                 link_cache = nl_cache_mngt_require("route/link");
00367                 if (link_cache)
00368                         dp_dump_line(p, line++, "  <oif>%s</oif>\n",
00369                                      rtnl_link_i2name(link_cache,
00370                                                       route->rt_oif,
00371                                                       buf, sizeof(buf)));
00372                 else
00373                         dp_dump_line(p, line++, "  <oif>%u</oif>\n",
00374                                      route->rt_oif);
00375         }
00376 
00377         if (route->ce_mask & ROUTE_ATTR_TYPE)
00378                 dp_dump_line(p, line++, "  <type>%s</type>\n",
00379                              nl_rtntype2str(route->rt_type, buf, sizeof(buf)));
00380 
00381         dp_dump_line(p, line++, "</route>\n");
00382 
00383 #if 0
00384         uint8_t                 rt_protocol;
00385         uint32_t                rt_flags;
00386         uint32_t                rt_metrics[RTAX_MAX];
00387         uint32_t                rt_metrics_mask;
00388         struct rtnl_nexthop *   rt_nexthops;
00389         struct rtnl_rtcacheinfo rt_cacheinfo;
00390         uint32_t                rt_mp_algo;
00391 
00392 #endif
00393 
00394         return line;
00395 }
00396 
00397 static int route_dump_env(struct nl_object *obj, struct nl_dump_params *p)
00398 {
00399         struct rtnl_route *route = (struct rtnl_route *) obj;
00400         char buf[128];
00401         int line = 0;
00402 
00403         dp_dump_line(p, line++, "ROUTE_FAMILY=%s\n",
00404                      nl_af2str(route->rt_family, buf, sizeof(buf)));
00405 
00406         if (route->ce_mask & ROUTE_ATTR_DST)
00407                 dp_dump_line(p, line++, "ROUTE_DST=%s\n",
00408                              nl_addr2str(route->rt_dst, buf, sizeof(buf)));
00409 
00410         if (route->ce_mask & ROUTE_ATTR_SRC)
00411                 dp_dump_line(p, line++, "ROUTE_SRC=%s\n",
00412                              nl_addr2str(route->rt_src, buf, sizeof(buf)));
00413 
00414         if (route->ce_mask & ROUTE_ATTR_GATEWAY)
00415                 dp_dump_line(p, line++, "ROUTE_GATEWAY=%s\n",
00416                              nl_addr2str(route->rt_gateway, buf, sizeof(buf)));
00417 
00418         if (route->ce_mask & ROUTE_ATTR_PREF_SRC)
00419                 dp_dump_line(p, line++, "ROUTE_PREFSRC=%s\n",
00420                              nl_addr2str(route->rt_pref_src, buf, sizeof(buf)));
00421 
00422         if (route->ce_mask & ROUTE_ATTR_IIF)
00423                 dp_dump_line(p, line++, "ROUTE_IIF=%s\n", route->rt_iif);
00424 
00425         if (route->ce_mask & ROUTE_ATTR_REALMS)
00426                 dp_dump_line(p, line++, "ROUTE_REALM=%u\n",
00427                              route->rt_realms);
00428 
00429         if (route->ce_mask & ROUTE_ATTR_TOS)
00430                 dp_dump_line(p, line++, "ROUTE_TOS=%u\n", route->rt_tos);
00431 
00432         if (route->ce_mask & ROUTE_ATTR_TABLE)
00433                 dp_dump_line(p, line++, "ROUTE_TABLE=%u\n",
00434                              route->rt_table);
00435 
00436         if (route->ce_mask & ROUTE_ATTR_SCOPE)
00437                 dp_dump_line(p, line++, "ROUTE_SCOPE=%s\n",
00438                              rtnl_scope2str(route->rt_scope, buf, sizeof(buf)));
00439 
00440         if (route->ce_mask & ROUTE_ATTR_PRIO)
00441                 dp_dump_line(p, line++, "ROUTE_METRIC=%u\n",
00442                              route->rt_prio);
00443 
00444         if (route->ce_mask & ROUTE_ATTR_OIF) {
00445                 struct nl_cache *link_cache;
00446 
00447                 dp_dump_line(p, line++, "ROUTE_OIF_IFINDEX=%u\n",
00448                              route->rt_oif);
00449 
00450                 link_cache = nl_cache_mngt_require("route/link");
00451                 if (link_cache)
00452                         dp_dump_line(p, line++, "ROUTE_OIF_IFNAME=%s\n",
00453                                      rtnl_link_i2name(link_cache,
00454                                                       route->rt_oif,
00455                                                       buf, sizeof(buf)));
00456         }
00457 
00458         if (route->ce_mask & ROUTE_ATTR_TYPE)
00459                 dp_dump_line(p, line++, "ROUTE_TYPE=%s\n",
00460                              nl_rtntype2str(route->rt_type, buf, sizeof(buf)));
00461 
00462         return line;
00463 }
00464 
00465 static int route_compare(struct nl_object *_a, struct nl_object *_b,
00466                         uint32_t attrs, int flags)
00467 {
00468         struct rtnl_route *a = (struct rtnl_route *) _a;
00469         struct rtnl_route *b = (struct rtnl_route *) _b;
00470         int diff = 0;
00471 
00472 #define ROUTE_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ROUTE_ATTR_##ATTR, a, b, EXPR)
00473 
00474         diff |= ROUTE_DIFF(FAMILY,      a->rt_family != b->rt_family);
00475         diff |= ROUTE_DIFF(TOS,         a->rt_tos != b->rt_tos);
00476         diff |= ROUTE_DIFF(TABLE,       a->rt_table != b->rt_table);
00477         diff |= ROUTE_DIFF(PROTOCOL,    a->rt_protocol != b->rt_protocol);
00478         diff |= ROUTE_DIFF(SCOPE,       a->rt_scope != b->rt_scope);
00479         diff |= ROUTE_DIFF(TYPE,        a->rt_type != b->rt_type);
00480         diff |= ROUTE_DIFF(OIF,         a->rt_oif != b->rt_oif);
00481         diff |= ROUTE_DIFF(PRIO,        a->rt_prio != b->rt_prio);
00482         diff |= ROUTE_DIFF(REALMS,      a->rt_realms != b->rt_realms);
00483         diff |= ROUTE_DIFF(MP_ALGO,     a->rt_mp_algo != b->rt_mp_algo);
00484         diff |= ROUTE_DIFF(DST,         nl_addr_cmp(a->rt_dst, b->rt_dst));
00485         diff |= ROUTE_DIFF(SRC,         nl_addr_cmp(a->rt_src, b->rt_src));
00486         diff |= ROUTE_DIFF(IIF,         strcmp(a->rt_iif, b->rt_iif));
00487         diff |= ROUTE_DIFF(PREF_SRC,    nl_addr_cmp(a->rt_pref_src,
00488                                                     b->rt_pref_src));
00489         diff |= ROUTE_DIFF(GATEWAY,     nl_addr_cmp(a->rt_gateway,
00490                                                     b->rt_gateway));
00491 
00492         /* FIXME: Compare metrics, multipath config */
00493 
00494         if (flags & LOOSE_FLAG_COMPARISON)
00495                 diff |= ROUTE_DIFF(FLAGS,
00496                           (a->rt_flags ^ b->rt_flags) & b->rt_flag_mask);
00497         else
00498                 diff |= ROUTE_DIFF(FLAGS, a->rt_flags != b->rt_flags);
00499         
00500 #undef ROUTE_DIFF
00501 
00502         return diff;
00503 }
00504 
00505 static struct trans_tbl route_attrs[] = {
00506         __ADD(ROUTE_ATTR_FAMILY, family)
00507         __ADD(ROUTE_ATTR_TOS, tos)
00508         __ADD(ROUTE_ATTR_TABLE, table)
00509         __ADD(ROUTE_ATTR_PROTOCOL, protocol)
00510         __ADD(ROUTE_ATTR_SCOPE, scope)
00511         __ADD(ROUTE_ATTR_TYPE, type)
00512         __ADD(ROUTE_ATTR_FLAGS, flags)
00513         __ADD(ROUTE_ATTR_DST, dst)
00514         __ADD(ROUTE_ATTR_SRC, src)
00515         __ADD(ROUTE_ATTR_IIF, iif)
00516         __ADD(ROUTE_ATTR_OIF, oif)
00517         __ADD(ROUTE_ATTR_GATEWAY, gateway)
00518         __ADD(ROUTE_ATTR_PRIO, prio)
00519         __ADD(ROUTE_ATTR_PREF_SRC, pref_src)
00520         __ADD(ROUTE_ATTR_METRICS, metrics)
00521         __ADD(ROUTE_ATTR_MULTIPATH, multipath)
00522         __ADD(ROUTE_ATTR_REALMS, realms)
00523         __ADD(ROUTE_ATTR_CACHEINFO, cacheinfo)
00524         __ADD(ROUTE_ATTR_MP_ALGO, mp_algo)
00525 };
00526 
00527 static char *route_attrs2str(int attrs, char *buf, size_t len)
00528 {
00529         return __flags2str(attrs, buf, len, route_attrs,
00530                            ARRAY_SIZE(route_attrs));
00531 }
00532 
00533 /**
00534  * @name Allocation/Freeing
00535  * @{
00536  */
00537 
00538 struct rtnl_route *rtnl_route_alloc(void)
00539 {
00540         return (struct rtnl_route *) nl_object_alloc(&route_obj_ops);
00541 }
00542 
00543 void rtnl_route_get(struct rtnl_route *route)
00544 {
00545         nl_object_get((struct nl_object *) route);
00546 }
00547 
00548 void rtnl_route_put(struct rtnl_route *route)
00549 {
00550         nl_object_put((struct nl_object *) route);
00551 }
00552 
00553 /** @} */
00554 
00555 /**
00556  * @name Attributes
00557  * @{
00558  */
00559 
00560 void rtnl_route_set_table(struct rtnl_route *route, int table)
00561 {
00562         route->rt_table = table;
00563         route->ce_mask |= ROUTE_ATTR_TABLE;
00564 }
00565 
00566 int rtnl_route_get_table(struct rtnl_route *route)
00567 {
00568         if (route->ce_mask & ROUTE_ATTR_TABLE)
00569                 return route->rt_table;
00570         else
00571                 return RT_TABLE_MAIN;
00572 }
00573 
00574 void rtnl_route_set_scope(struct rtnl_route *route, int scope)
00575 {
00576         route->rt_scope = scope;
00577         route->ce_mask |= ROUTE_ATTR_SCOPE;
00578 }
00579 
00580 int rtnl_route_get_scope(struct rtnl_route *route)
00581 {
00582         if (route->ce_mask & ROUTE_ATTR_SCOPE)
00583                 return route->rt_scope;
00584         else
00585                 return RT_SCOPE_NOWHERE;
00586 }
00587 
00588 void rtnl_route_set_tos(struct rtnl_route *route, int tos)
00589 {
00590         route->rt_tos = tos;
00591         route->ce_mask |= ROUTE_ATTR_TOS;
00592 }
00593 
00594 int rtnl_route_get_tos(struct rtnl_route *route)
00595 {
00596         return route->rt_tos;
00597 }
00598 
00599 void rtnl_route_set_realms(struct rtnl_route *route, realm_t realms)
00600 {
00601         route->rt_realms = realms;
00602         route->ce_mask |= ROUTE_ATTR_REALMS;
00603 }
00604 
00605 realm_t rtnl_route_get_realms(struct rtnl_route *route)
00606 {
00607         return route->rt_realms;
00608 }
00609 
00610 void rtnl_route_set_protocol(struct rtnl_route *route, int proto)
00611 {
00612         route->rt_protocol = proto;
00613         route->ce_mask |= ROUTE_ATTR_PROTOCOL;
00614 }
00615 
00616 int rtnl_route_get_protocol(struct rtnl_route *route)
00617 {
00618         if (route->ce_mask & ROUTE_ATTR_PROTOCOL)
00619                 return route->rt_protocol;
00620         else
00621                 return RTPROT_STATIC;
00622 }
00623 
00624 void rtnl_route_set_prio(struct rtnl_route *route, int prio)
00625 {
00626         route->rt_prio = prio;
00627         route->ce_mask |= ROUTE_ATTR_PRIO;
00628 }
00629 
00630 int rtnl_route_get_prio(struct rtnl_route *route)
00631 {
00632         return route->rt_prio;
00633 }
00634 
00635 void rtnl_route_set_family(struct rtnl_route *route, int family)
00636 {
00637         route->rt_family = family;
00638         route->ce_mask |= ROUTE_ATTR_FAMILY;
00639 }
00640 
00641 int rtnl_route_get_family(struct rtnl_route *route)
00642 {
00643         if (route->ce_mask & ROUTE_ATTR_FAMILY)
00644                 return route->rt_family;
00645         else
00646                 return AF_UNSPEC;
00647 }
00648 
00649 int rtnl_route_set_dst(struct rtnl_route *route, struct nl_addr *addr)
00650 {
00651         if (route->ce_mask & ROUTE_ATTR_FAMILY) {
00652                 if (addr->a_family != route->rt_family)
00653                         return nl_error(EINVAL, "Address family mismatch");
00654         } else
00655                 route->rt_family = addr->a_family;
00656 
00657         if (route->rt_dst)
00658                 nl_addr_put(route->rt_dst);
00659 
00660         nl_addr_get(addr);
00661         route->rt_dst = addr;
00662         
00663         route->ce_mask |= (ROUTE_ATTR_DST | ROUTE_ATTR_FAMILY);
00664 
00665         return 0;
00666 }
00667 
00668 struct nl_addr *rtnl_route_get_dst(struct rtnl_route *route)
00669 {
00670         return route->rt_dst;
00671 }
00672 
00673 int rtnl_route_get_dst_len(struct rtnl_route *route)
00674 {
00675         if (route->ce_mask & ROUTE_ATTR_DST)
00676                 return nl_addr_get_prefixlen(route->rt_dst);
00677         else
00678                 return 0;
00679 }
00680 
00681 int rtnl_route_set_src(struct rtnl_route *route, struct nl_addr *addr)
00682 {
00683         if (route->ce_mask & ROUTE_ATTR_FAMILY) {
00684                 if (addr->a_family != route->rt_family)
00685                         return nl_error(EINVAL, "Address family mismatch");
00686         } else
00687                 route->rt_family = addr->a_family;
00688 
00689         if (route->rt_src)
00690                 nl_addr_put(route->rt_src);
00691 
00692         nl_addr_get(addr);
00693         route->rt_src = addr;
00694         route->ce_mask |= (ROUTE_ATTR_SRC | ROUTE_ATTR_FAMILY);
00695 
00696         return 0;
00697 }
00698 
00699 struct nl_addr *rtnl_route_get_src(struct rtnl_route *route)
00700 {
00701         return route->rt_src;
00702 }
00703 
00704 int rtnl_route_get_src_len(struct rtnl_route *route)
00705 {
00706         if (route->ce_mask & ROUTE_ATTR_SRC)
00707                 return nl_addr_get_prefixlen(route->rt_src);
00708         else
00709                 return 0;
00710 }
00711 
00712 int rtnl_route_set_gateway(struct rtnl_route *route, struct nl_addr *addr)
00713 {
00714         if (route->ce_mask & ROUTE_ATTR_FAMILY) {
00715                 if (addr->a_family != route->rt_family)
00716                         return nl_error(EINVAL, "Address family mismatch");
00717         } else
00718                 route->rt_family = addr->a_family;
00719 
00720         if (route->rt_gateway)
00721                 nl_addr_put(route->rt_gateway);
00722 
00723         nl_addr_get(addr);
00724         route->rt_gateway = addr;
00725         route->ce_mask |= (ROUTE_ATTR_GATEWAY | ROUTE_ATTR_FAMILY);
00726 
00727         return 0;
00728 }
00729 
00730 struct nl_addr *rtnl_route_get_gateway(struct rtnl_route *route)
00731 {
00732         return route->rt_gateway;
00733 }
00734 
00735 void rtnl_route_set_type(struct rtnl_route *route, int type)
00736 {
00737         route->rt_type = type;
00738         route->ce_mask |= ROUTE_ATTR_TYPE;
00739 }
00740 
00741 int rtnl_route_get_type(struct rtnl_route *route)
00742 {
00743         if (route->ce_mask & ROUTE_ATTR_TYPE)
00744                 return route->rt_type;
00745         else
00746                 return RTN_UNICAST;
00747 }
00748 
00749 void rtnl_route_set_flags(struct rtnl_route *route, unsigned int flags)
00750 {
00751         route->rt_flag_mask |= flags;
00752         route->rt_flags |= flags;
00753         route->ce_mask |= ROUTE_ATTR_FLAGS;
00754 }
00755 
00756 void rtnl_route_unset_flags(struct rtnl_route *route, unsigned int flags)
00757 {
00758         route->rt_flag_mask |= flags;
00759         route->rt_flags &= ~flags;
00760         route->ce_mask |= ROUTE_ATTR_FLAGS;
00761 }
00762 
00763 unsigned int rtnl_route_get_flags(struct rtnl_route *route)
00764 {
00765         return route->rt_flags;
00766 }
00767 
00768 int rtnl_route_set_metric(struct rtnl_route *route, int metric, uint32_t value)
00769 {
00770         if (metric > RTAX_MAX || metric < 1)
00771                 return nl_error(EINVAL, "Metric out of range (1..%d)",
00772                     RTAX_MAX);
00773 
00774         route->rt_metrics[metric - 1] = value;
00775         route->rt_metrics_mask |= (1 << (metric - 1));
00776 
00777         return 0;
00778 }
00779 
00780 int rtnl_route_unset_metric(struct rtnl_route *route, int metric)
00781 {
00782         if (metric > RTAX_MAX || metric < 1)
00783                 return nl_error(EINVAL, "Metric out of range (1..%d)",
00784                     RTAX_MAX);
00785 
00786         route->rt_metrics_mask &= ~(1 << (metric - 1));
00787 
00788         return 0;
00789 }
00790 
00791 unsigned int rtnl_route_get_metric(struct rtnl_route *route, int metric)
00792 {
00793         if (metric > RTAX_MAX || metric < 1)
00794                 return UINT_MAX;
00795 
00796         if (!(route->rt_metrics_mask & (1 << (metric - 1))))
00797                 return UINT_MAX;
00798 
00799         return route->rt_metrics[metric - 1];
00800 }
00801 
00802 int rtnl_route_set_pref_src(struct rtnl_route *route, struct nl_addr *addr)
00803 {
00804         if (route->ce_mask & ROUTE_ATTR_FAMILY) {
00805                 if (addr->a_family != route->rt_family)
00806                         return nl_error(EINVAL, "Address family mismatch");
00807         } else
00808                 route->rt_family = addr->a_family;
00809 
00810         if (route->rt_pref_src)
00811                 nl_addr_put(route->rt_pref_src);
00812 
00813         nl_addr_get(addr);
00814         route->rt_pref_src = addr;
00815         route->ce_mask |= (ROUTE_ATTR_PREF_SRC | ROUTE_ATTR_FAMILY);
00816 
00817         return 0;
00818 }
00819 
00820 struct nl_addr *rtnl_route_get_pref_src(struct rtnl_route *route)
00821 {
00822         return route->rt_pref_src;
00823 }
00824 
00825 void rtnl_route_set_oif(struct rtnl_route *route, int ifindex)
00826 {
00827         route->rt_oif = ifindex;
00828         route->ce_mask |= ROUTE_ATTR_OIF;
00829 }
00830 
00831 int rtnl_route_get_oif(struct rtnl_route *route)
00832 {
00833         if (route->ce_mask & ROUTE_ATTR_OIF)
00834                 return route->rt_oif;
00835         else
00836                 return RTNL_LINK_NOT_FOUND;
00837 }
00838 
00839 void rtnl_route_set_iif(struct rtnl_route *route, const char *name)
00840 {
00841         strncpy(route->rt_iif, name, sizeof(route->rt_iif) - 1);
00842         route->ce_mask |= ROUTE_ATTR_IIF;
00843 }
00844 
00845 char *rtnl_route_get_iif(struct rtnl_route *route)
00846 {
00847         if (route->ce_mask & ROUTE_ATTR_IIF)
00848                 return route->rt_iif;
00849         else
00850                 return NULL;
00851 }
00852 
00853 void rtnl_route_add_nexthop(struct rtnl_route *route, struct rtnl_nexthop *nh)
00854 {
00855         nl_list_add_tail(&nh->rtnh_list, &route->rt_nexthops);
00856         route->ce_mask |= ROUTE_ATTR_MULTIPATH;
00857 }
00858 
00859 void rtnl_route_remove_nexthop(struct rtnl_nexthop *nh)
00860 {
00861         nl_list_del(&nh->rtnh_list);
00862 }
00863 
00864 struct nl_list_head *rtnl_route_get_nexthops(struct rtnl_route *route)
00865 {
00866         return &route->rt_nexthops;
00867 }
00868 
00869 void rtnl_route_set_cacheinfo(struct rtnl_route *route,
00870                               struct rtnl_rtcacheinfo *ci)
00871 {
00872         memcpy(&route->rt_cacheinfo, ci, sizeof(*ci));
00873         route->ce_mask |= ROUTE_ATTR_CACHEINFO;
00874 }
00875 
00876 uint32_t rtnl_route_get_mp_algo(struct rtnl_route *route)
00877 {
00878         if (route->ce_mask & ROUTE_ATTR_MP_ALGO)
00879                 return route->rt_mp_algo;
00880         else
00881                 return IP_MP_ALG_NONE;
00882 }
00883 
00884 void rtnl_route_set_mp_algo(struct rtnl_route *route, uint32_t algo)
00885 {
00886         route->rt_mp_algo = algo;
00887         route->ce_mask |= ROUTE_ATTR_MP_ALGO;
00888 }
00889 
00890 /** @} */
00891 
00892 struct nl_object_ops route_obj_ops = {
00893         .oo_name                = "route/route",
00894         .oo_size                = sizeof(struct rtnl_route),
00895         .oo_constructor         = route_constructor,
00896         .oo_free_data           = route_free_data,
00897         .oo_clone               = route_clone,
00898         .oo_dump[NL_DUMP_BRIEF] = route_dump_brief,
00899         .oo_dump[NL_DUMP_FULL]  = route_dump_full,
00900         .oo_dump[NL_DUMP_STATS] = route_dump_stats,
00901         .oo_dump[NL_DUMP_XML]   = route_dump_xml,
00902         .oo_dump[NL_DUMP_ENV]   = route_dump_env,
00903         .oo_compare             = route_compare,
00904         .oo_attrs2str           = route_attrs2str,
00905         .oo_id_attrs            = (ROUTE_ATTR_FAMILY | ROUTE_ATTR_TOS |
00906                                    ROUTE_ATTR_TABLE | ROUTE_ATTR_DST),
00907 };
00908 
00909 /** @} */