00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <netlink-local.h>
00019 #include <netlink/netlink.h>
00020 #include <netlink/utils.h>
00021 #include <netlink/route/rtnl.h>
00022 #include <netlink/route/route.h>
00023
00024
00025 #define NH_ATTR_FLAGS 0x000001
00026 #define NH_ATTR_WEIGHT 0x000002
00027 #define NH_ATTR_IFINDEX 0x000004
00028 #define NH_ATTR_GATEWAY 0x000008
00029 #define NH_ATTR_REALMS 0x000010
00030
00031
00032
00033
00034
00035
00036
00037 struct rtnl_nexthop *rtnl_route_nh_alloc(void)
00038 {
00039 struct rtnl_nexthop *nh;
00040
00041 nh = calloc(1, sizeof(*nh));
00042 if (!nh)
00043 return NULL;
00044
00045 nl_init_list_head(&nh->rtnh_list);
00046
00047 return nh;
00048 }
00049
00050 struct rtnl_nexthop *rtnl_route_nh_clone(struct rtnl_nexthop *src)
00051 {
00052 struct rtnl_nexthop *nh;
00053
00054 nh = rtnl_route_nh_alloc();
00055 if (!nh)
00056 return NULL;
00057
00058 nh->rtnh_flags = src->rtnh_flags;
00059 nh->rtnh_flag_mask = src->rtnh_flag_mask;
00060 nh->rtnh_weight = src->rtnh_weight;
00061 nh->rtnh_ifindex = src->rtnh_ifindex;
00062 nh->ce_mask = src->ce_mask;
00063
00064 if (src->rtnh_gateway) {
00065 nh->rtnh_gateway = nl_addr_clone(src->rtnh_gateway);
00066 if (!nh->rtnh_gateway) {
00067 free(nh);
00068 return NULL;
00069 }
00070 }
00071
00072 return nh;
00073 }
00074
00075 void rtnl_route_nh_free(struct rtnl_nexthop *nh)
00076 {
00077 nl_addr_put(nh->rtnh_gateway);
00078 free(nh);
00079 }
00080
00081
00082
00083 int rtnl_route_nh_compare(struct rtnl_nexthop *a, struct rtnl_nexthop *b,
00084 uint32_t attrs, int loose)
00085 {
00086 int diff = 0;
00087
00088 #define NH_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, NH_ATTR_##ATTR, a, b, EXPR)
00089
00090 diff |= NH_DIFF(IFINDEX, a->rtnh_ifindex != b->rtnh_ifindex);
00091 diff |= NH_DIFF(WEIGHT, a->rtnh_weight != b->rtnh_weight);
00092 diff |= NH_DIFF(REALMS, a->rtnh_realms != b->rtnh_realms);
00093 diff |= NH_DIFF(GATEWAY, nl_addr_cmp(a->rtnh_gateway,
00094 b->rtnh_gateway));
00095
00096 if (loose)
00097 diff |= NH_DIFF(FLAGS,
00098 (a->rtnh_flags ^ b->rtnh_flags) & b->rtnh_flag_mask);
00099 else
00100 diff |= NH_DIFF(FLAGS, a->rtnh_flags != b->rtnh_flags);
00101
00102 #undef NH_DIFF
00103
00104 return diff;
00105 }
00106
00107 static void nh_dump_line(struct rtnl_nexthop *nh, struct nl_dump_params *dp)
00108 {
00109 struct nl_cache *link_cache;
00110 char buf[128];
00111
00112 link_cache = nl_cache_mngt_require("route/link");
00113
00114 nl_dump(dp, "via");
00115
00116 if (nh->ce_mask & NH_ATTR_GATEWAY)
00117 nl_dump(dp, " %s", nl_addr2str(nh->rtnh_gateway,
00118 buf, sizeof(buf)));
00119
00120 if(nh->ce_mask & NH_ATTR_IFINDEX) {
00121 if (link_cache) {
00122 nl_dump(dp, " dev %s",
00123 rtnl_link_i2name(link_cache,
00124 nh->rtnh_ifindex,
00125 buf, sizeof(buf)));
00126 } else
00127 nl_dump(dp, " dev %d", nh->rtnh_ifindex);
00128 }
00129
00130 nl_dump(dp, " ");
00131 }
00132
00133 static void nh_dump_details(struct rtnl_nexthop *nh, struct nl_dump_params *dp)
00134 {
00135 struct nl_cache *link_cache;
00136 char buf[128];
00137
00138 link_cache = nl_cache_mngt_require("route/link");
00139
00140 nl_dump(dp, "nexthop");
00141
00142 if (nh->ce_mask & NH_ATTR_GATEWAY)
00143 nl_dump(dp, " via %s", nl_addr2str(nh->rtnh_gateway,
00144 buf, sizeof(buf)));
00145
00146 if(nh->ce_mask & NH_ATTR_IFINDEX) {
00147 if (link_cache) {
00148 nl_dump(dp, " dev %s",
00149 rtnl_link_i2name(link_cache,
00150 nh->rtnh_ifindex,
00151 buf, sizeof(buf)));
00152 } else
00153 nl_dump(dp, " dev %d", nh->rtnh_ifindex);
00154 }
00155
00156 if (nh->ce_mask & NH_ATTR_WEIGHT)
00157 nl_dump(dp, " weight %u", nh->rtnh_weight);
00158
00159 if (nh->ce_mask & NH_ATTR_REALMS)
00160 nl_dump(dp, " realm %04x:%04x",
00161 RTNL_REALM_FROM(nh->rtnh_realms),
00162 RTNL_REALM_TO(nh->rtnh_realms));
00163
00164 if (nh->ce_mask & NH_ATTR_FLAGS)
00165 nl_dump(dp, " <%s>", rtnl_route_nh_flags2str(nh->rtnh_flags,
00166 buf, sizeof(buf)));
00167 }
00168
00169 static void nh_dump_env(struct rtnl_nexthop *nh, struct nl_dump_params *dp)
00170 {
00171 struct nl_cache *link_cache;
00172 char buf[128];
00173
00174 link_cache = nl_cache_mngt_require("route/link");
00175
00176 if (nh->ce_mask & NH_ATTR_GATEWAY)
00177 nl_dump_line(dp, "ROUTE_NH%d_VIA=%s\n", dp->dp_ivar,
00178 nl_addr2str(nh->rtnh_gateway, buf, sizeof(buf)));
00179
00180 if(nh->ce_mask & NH_ATTR_IFINDEX) {
00181 if (link_cache) {
00182 nl_dump_line(dp, "ROUTE_NH%d_DEV=%s\n", dp->dp_ivar,
00183 rtnl_link_i2name(link_cache,
00184 nh->rtnh_ifindex,
00185 buf, sizeof(buf)));
00186 } else
00187 nl_dump_line(dp, "ROUTE_NH%d_DEV=%d\n", dp->dp_ivar,
00188 nh->rtnh_ifindex);
00189 }
00190
00191 if (nh->ce_mask & NH_ATTR_WEIGHT)
00192 nl_dump_line(dp, "ROUTE_NH%d_WEIGHT=%u\n", dp->dp_ivar,
00193 nh->rtnh_weight);
00194
00195 if (nh->ce_mask & NH_ATTR_REALMS)
00196 nl_dump_line(dp, "ROUTE_NH%d_REALM=%04x:%04x\n", dp->dp_ivar,
00197 RTNL_REALM_FROM(nh->rtnh_realms),
00198 RTNL_REALM_TO(nh->rtnh_realms));
00199
00200 if (nh->ce_mask & NH_ATTR_FLAGS)
00201 nl_dump_line(dp, "ROUTE_NH%d_FLAGS=<%s>\n", dp->dp_ivar,
00202 rtnl_route_nh_flags2str(nh->rtnh_flags,
00203 buf, sizeof(buf)));
00204 }
00205 void rtnl_route_nh_dump(struct rtnl_nexthop *nh, struct nl_dump_params *dp)
00206 {
00207 switch (dp->dp_type) {
00208 case NL_DUMP_LINE:
00209 nh_dump_line(nh, dp);
00210 break;
00211
00212 case NL_DUMP_DETAILS:
00213 case NL_DUMP_STATS:
00214 if (dp->dp_ivar == NH_DUMP_FROM_DETAILS)
00215 nh_dump_details(nh, dp);
00216 break;
00217
00218 case NL_DUMP_ENV:
00219 nh_dump_env(nh, dp);
00220 break;
00221
00222 default:
00223 break;
00224 }
00225 }
00226
00227
00228
00229
00230
00231
00232 void rtnl_route_nh_set_weight(struct rtnl_nexthop *nh, uint8_t weight)
00233 {
00234 nh->rtnh_weight = weight;
00235 nh->ce_mask |= NH_ATTR_WEIGHT;
00236 }
00237
00238 uint8_t rtnl_route_nh_get_weight(struct rtnl_nexthop *nh)
00239 {
00240 return nh->rtnh_weight;
00241 }
00242
00243 void rtnl_route_nh_set_ifindex(struct rtnl_nexthop *nh, int ifindex)
00244 {
00245 nh->rtnh_ifindex = ifindex;
00246 nh->ce_mask |= NH_ATTR_IFINDEX;
00247 }
00248
00249 int rtnl_route_nh_get_ifindex(struct rtnl_nexthop *nh)
00250 {
00251 return nh->rtnh_ifindex;
00252 }
00253
00254 void rtnl_route_nh_set_gateway(struct rtnl_nexthop *nh, struct nl_addr *addr)
00255 {
00256 struct nl_addr *old = nh->rtnh_gateway;
00257
00258 if (addr) {
00259 nh->rtnh_gateway = nl_addr_get(addr);
00260 nh->ce_mask |= NH_ATTR_GATEWAY;
00261 } else {
00262 nh->ce_mask &= ~NH_ATTR_GATEWAY;
00263 nh->rtnh_gateway = NULL;
00264 }
00265
00266 if (old)
00267 nl_addr_put(old);
00268 }
00269
00270 struct nl_addr *rtnl_route_nh_get_gateway(struct rtnl_nexthop *nh)
00271 {
00272 return nh->rtnh_gateway;
00273 }
00274
00275 void rtnl_route_nh_set_flags(struct rtnl_nexthop *nh, unsigned int flags)
00276 {
00277 nh->rtnh_flag_mask |= flags;
00278 nh->rtnh_flags |= flags;
00279 nh->ce_mask |= NH_ATTR_FLAGS;
00280 }
00281
00282 void rtnl_route_nh_unset_flags(struct rtnl_nexthop *nh, unsigned int flags)
00283 {
00284 nh->rtnh_flag_mask |= flags;
00285 nh->rtnh_flags &= ~flags;
00286 nh->ce_mask |= NH_ATTR_FLAGS;
00287 }
00288
00289 unsigned int rtnl_route_nh_get_flags(struct rtnl_nexthop *nh)
00290 {
00291 return nh->rtnh_flags;
00292 }
00293
00294 void rtnl_route_nh_set_realms(struct rtnl_nexthop *nh, uint32_t realms)
00295 {
00296 nh->rtnh_realms = realms;
00297 nh->ce_mask |= NH_ATTR_REALMS;
00298 }
00299
00300 uint32_t rtnl_route_nh_get_realms(struct rtnl_nexthop *nh)
00301 {
00302 return nh->rtnh_realms;
00303 }
00304
00305
00306
00307
00308
00309
00310
00311
00312 static struct trans_tbl nh_flags[] = {
00313 __ADD(RTNH_F_DEAD, dead)
00314 __ADD(RTNH_F_PERVASIVE, pervasive)
00315 __ADD(RTNH_F_ONLINK, onlink)
00316 };
00317
00318 char *rtnl_route_nh_flags2str(int flags, char *buf, size_t len)
00319 {
00320 return __flags2str(flags, buf, len, nh_flags, ARRAY_SIZE(nh_flags));
00321 }
00322
00323 int rtnl_route_nh_str2flags(const char *name)
00324 {
00325 return __str2flags(name, nh_flags, ARRAY_SIZE(nh_flags));
00326 }
00327
00328
00329
00330