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 void rtnl_route_nh_dump(struct rtnl_nexthop *nh, struct nl_dump_params *dp)
00170 {
00171 switch (dp->dp_type) {
00172 case NL_DUMP_LINE:
00173 nh_dump_line(nh, dp);
00174 break;
00175
00176 case NL_DUMP_DETAILS:
00177 case NL_DUMP_STATS:
00178 if (dp->dp_ivar == NH_DUMP_FROM_DETAILS)
00179 nh_dump_details(nh, dp);
00180 break;
00181
00182 default:
00183 break;
00184 }
00185 }
00186
00187
00188
00189
00190
00191
00192 void rtnl_route_nh_set_weight(struct rtnl_nexthop *nh, uint8_t weight)
00193 {
00194 nh->rtnh_weight = weight;
00195 nh->ce_mask |= NH_ATTR_WEIGHT;
00196 }
00197
00198 uint8_t rtnl_route_nh_get_weight(struct rtnl_nexthop *nh)
00199 {
00200 return nh->rtnh_weight;
00201 }
00202
00203 void rtnl_route_nh_set_ifindex(struct rtnl_nexthop *nh, int ifindex)
00204 {
00205 nh->rtnh_ifindex = ifindex;
00206 nh->ce_mask |= NH_ATTR_IFINDEX;
00207 }
00208
00209 int rtnl_route_nh_get_ifindex(struct rtnl_nexthop *nh)
00210 {
00211 return nh->rtnh_ifindex;
00212 }
00213
00214 void rtnl_route_nh_set_gateway(struct rtnl_nexthop *nh, struct nl_addr *addr)
00215 {
00216 struct nl_addr *old = nh->rtnh_gateway;
00217
00218 if (addr) {
00219 nh->rtnh_gateway = nl_addr_get(addr);
00220 nh->ce_mask |= NH_ATTR_GATEWAY;
00221 } else {
00222 nh->ce_mask &= ~NH_ATTR_GATEWAY;
00223 nh->rtnh_gateway = NULL;
00224 }
00225
00226 if (old)
00227 nl_addr_put(old);
00228 }
00229
00230 struct nl_addr *rtnl_route_nh_get_gateway(struct rtnl_nexthop *nh)
00231 {
00232 return nh->rtnh_gateway;
00233 }
00234
00235 void rtnl_route_nh_set_flags(struct rtnl_nexthop *nh, unsigned int flags)
00236 {
00237 nh->rtnh_flag_mask |= flags;
00238 nh->rtnh_flags |= flags;
00239 nh->ce_mask |= NH_ATTR_FLAGS;
00240 }
00241
00242 void rtnl_route_nh_unset_flags(struct rtnl_nexthop *nh, unsigned int flags)
00243 {
00244 nh->rtnh_flag_mask |= flags;
00245 nh->rtnh_flags &= ~flags;
00246 nh->ce_mask |= NH_ATTR_FLAGS;
00247 }
00248
00249 unsigned int rtnl_route_nh_get_flags(struct rtnl_nexthop *nh)
00250 {
00251 return nh->rtnh_flags;
00252 }
00253
00254 void rtnl_route_nh_set_realms(struct rtnl_nexthop *nh, uint32_t realms)
00255 {
00256 nh->rtnh_realms = realms;
00257 nh->ce_mask |= NH_ATTR_REALMS;
00258 }
00259
00260 uint32_t rtnl_route_nh_get_realms(struct rtnl_nexthop *nh)
00261 {
00262 return nh->rtnh_realms;
00263 }
00264
00265
00266
00267
00268
00269
00270
00271
00272 static const struct trans_tbl nh_flags[] = {
00273 __ADD(RTNH_F_DEAD, dead)
00274 __ADD(RTNH_F_PERVASIVE, pervasive)
00275 __ADD(RTNH_F_ONLINK, onlink)
00276 };
00277
00278 char *rtnl_route_nh_flags2str(int flags, char *buf, size_t len)
00279 {
00280 return __flags2str(flags, buf, len, nh_flags, ARRAY_SIZE(nh_flags));
00281 }
00282
00283 int rtnl_route_nh_str2flags(const char *name)
00284 {
00285 return __str2flags(name, nh_flags, ARRAY_SIZE(nh_flags));
00286 }
00287
00288
00289
00290