1/* 2 * lib/route/nexthop.c Routing Nexthop 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation version 2.1 7 * of the License. 8 * 9 * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> 10 */ 11 12/** 13 * @ingroup route_obj 14 * @defgroup nexthop Nexthop 15 * @{ 16 */ 17 18#include <netlink-local.h> 19#include <netlink/netlink.h> 20#include <netlink/utils.h> 21#include <netlink/route/rtnl.h> 22#include <netlink/route/route.h> 23 24/** @cond SKIP */ 25#define NH_ATTR_FLAGS 0x000001 26#define NH_ATTR_WEIGHT 0x000002 27#define NH_ATTR_IFINDEX 0x000004 28#define NH_ATTR_GATEWAY 0x000008 29#define NH_ATTR_REALMS 0x000010 30/** @endcond */ 31 32/** 33 * @name Allocation/Freeing 34 * @{ 35 */ 36 37struct rtnl_nexthop *rtnl_route_nh_alloc(void) 38{ 39 struct rtnl_nexthop *nh; 40 41 nh = calloc(1, sizeof(*nh)); 42 if (!nh) 43 return NULL; 44 45 nl_init_list_head(&nh->rtnh_list); 46 47 return nh; 48} 49 50struct rtnl_nexthop *rtnl_route_nh_clone(struct rtnl_nexthop *src) 51{ 52 struct rtnl_nexthop *nh; 53 54 nh = rtnl_route_nh_alloc(); 55 if (!nh) 56 return NULL; 57 58 nh->rtnh_flags = src->rtnh_flags; 59 nh->rtnh_flag_mask = src->rtnh_flag_mask; 60 nh->rtnh_weight = src->rtnh_weight; 61 nh->rtnh_ifindex = src->rtnh_ifindex; 62 nh->ce_mask = src->ce_mask; 63 64 if (src->rtnh_gateway) { 65 nh->rtnh_gateway = nl_addr_clone(src->rtnh_gateway); 66 if (!nh->rtnh_gateway) { 67 free(nh); 68 return NULL; 69 } 70 } 71 72 return nh; 73} 74 75void rtnl_route_nh_free(struct rtnl_nexthop *nh) 76{ 77 nl_addr_put(nh->rtnh_gateway); 78 free(nh); 79} 80 81/** @} */ 82 83int rtnl_route_nh_compare(struct rtnl_nexthop *a, struct rtnl_nexthop *b, 84 uint32_t attrs, int loose) 85{ 86 int diff = 0; 87 88#define NH_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, NH_ATTR_##ATTR, a, b, EXPR) 89 90 diff |= NH_DIFF(IFINDEX, a->rtnh_ifindex != b->rtnh_ifindex); 91 diff |= NH_DIFF(WEIGHT, a->rtnh_weight != b->rtnh_weight); 92 diff |= NH_DIFF(REALMS, a->rtnh_realms != b->rtnh_realms); 93 diff |= NH_DIFF(GATEWAY, nl_addr_cmp(a->rtnh_gateway, 94 b->rtnh_gateway)); 95 96 if (loose) 97 diff |= NH_DIFF(FLAGS, 98 (a->rtnh_flags ^ b->rtnh_flags) & b->rtnh_flag_mask); 99 else 100 diff |= NH_DIFF(FLAGS, a->rtnh_flags != b->rtnh_flags); 101 102#undef NH_DIFF 103 104 return diff; 105} 106 107static void nh_dump_line(struct rtnl_nexthop *nh, struct nl_dump_params *dp) 108{ 109 struct nl_cache *link_cache; 110 char buf[128]; 111 112 link_cache = nl_cache_mngt_require("route/link"); 113 114 nl_dump(dp, "via"); 115 116 if (nh->ce_mask & NH_ATTR_GATEWAY) 117 nl_dump(dp, " %s", nl_addr2str(nh->rtnh_gateway, 118 buf, sizeof(buf))); 119 120 if(nh->ce_mask & NH_ATTR_IFINDEX) { 121 if (link_cache) { 122 nl_dump(dp, " dev %s", 123 rtnl_link_i2name(link_cache, 124 nh->rtnh_ifindex, 125 buf, sizeof(buf))); 126 } else 127 nl_dump(dp, " dev %d", nh->rtnh_ifindex); 128 } 129 130 nl_dump(dp, " "); 131} 132 133static void nh_dump_details(struct rtnl_nexthop *nh, struct nl_dump_params *dp) 134{ 135 struct nl_cache *link_cache; 136 char buf[128]; 137 138 link_cache = nl_cache_mngt_require("route/link"); 139 140 nl_dump(dp, "nexthop"); 141 142 if (nh->ce_mask & NH_ATTR_GATEWAY) 143 nl_dump(dp, " via %s", nl_addr2str(nh->rtnh_gateway, 144 buf, sizeof(buf))); 145 146 if(nh->ce_mask & NH_ATTR_IFINDEX) { 147 if (link_cache) { 148 nl_dump(dp, " dev %s", 149 rtnl_link_i2name(link_cache, 150 nh->rtnh_ifindex, 151 buf, sizeof(buf))); 152 } else 153 nl_dump(dp, " dev %d", nh->rtnh_ifindex); 154 } 155 156 if (nh->ce_mask & NH_ATTR_WEIGHT) 157 nl_dump(dp, " weight %u", nh->rtnh_weight); 158 159 if (nh->ce_mask & NH_ATTR_REALMS) 160 nl_dump(dp, " realm %04x:%04x", 161 RTNL_REALM_FROM(nh->rtnh_realms), 162 RTNL_REALM_TO(nh->rtnh_realms)); 163 164 if (nh->ce_mask & NH_ATTR_FLAGS) 165 nl_dump(dp, " <%s>", rtnl_route_nh_flags2str(nh->rtnh_flags, 166 buf, sizeof(buf))); 167} 168 169static void nh_dump_env(struct rtnl_nexthop *nh, struct nl_dump_params *dp) 170{ 171 struct nl_cache *link_cache; 172 char buf[128]; 173 174 link_cache = nl_cache_mngt_require("route/link"); 175 176 if (nh->ce_mask & NH_ATTR_GATEWAY) 177 nl_dump_line(dp, "ROUTE_NH%d_VIA=%s\n", dp->dp_ivar, 178 nl_addr2str(nh->rtnh_gateway, buf, sizeof(buf))); 179 180 if(nh->ce_mask & NH_ATTR_IFINDEX) { 181 if (link_cache) { 182 nl_dump_line(dp, "ROUTE_NH%d_DEV=%s\n", dp->dp_ivar, 183 rtnl_link_i2name(link_cache, 184 nh->rtnh_ifindex, 185 buf, sizeof(buf))); 186 } else 187 nl_dump_line(dp, "ROUTE_NH%d_DEV=%d\n", dp->dp_ivar, 188 nh->rtnh_ifindex); 189 } 190 191 if (nh->ce_mask & NH_ATTR_WEIGHT) 192 nl_dump_line(dp, "ROUTE_NH%d_WEIGHT=%u\n", dp->dp_ivar, 193 nh->rtnh_weight); 194 195 if (nh->ce_mask & NH_ATTR_REALMS) 196 nl_dump_line(dp, "ROUTE_NH%d_REALM=%04x:%04x\n", dp->dp_ivar, 197 RTNL_REALM_FROM(nh->rtnh_realms), 198 RTNL_REALM_TO(nh->rtnh_realms)); 199 200 if (nh->ce_mask & NH_ATTR_FLAGS) 201 nl_dump_line(dp, "ROUTE_NH%d_FLAGS=<%s>\n", dp->dp_ivar, 202 rtnl_route_nh_flags2str(nh->rtnh_flags, 203 buf, sizeof(buf))); 204} 205void rtnl_route_nh_dump(struct rtnl_nexthop *nh, struct nl_dump_params *dp) 206{ 207 switch (dp->dp_type) { 208 case NL_DUMP_LINE: 209 nh_dump_line(nh, dp); 210 break; 211 212 case NL_DUMP_DETAILS: 213 case NL_DUMP_STATS: 214 if (dp->dp_ivar == NH_DUMP_FROM_DETAILS) 215 nh_dump_details(nh, dp); 216 break; 217 218 case NL_DUMP_ENV: 219 nh_dump_env(nh, dp); 220 break; 221 222 default: 223 break; 224 } 225} 226 227/** 228 * @name Attributes 229 * @{ 230 */ 231 232void rtnl_route_nh_set_weight(struct rtnl_nexthop *nh, uint8_t weight) 233{ 234 nh->rtnh_weight = weight; 235 nh->ce_mask |= NH_ATTR_WEIGHT; 236} 237 238uint8_t rtnl_route_nh_get_weight(struct rtnl_nexthop *nh) 239{ 240 return nh->rtnh_weight; 241} 242 243void rtnl_route_nh_set_ifindex(struct rtnl_nexthop *nh, int ifindex) 244{ 245 nh->rtnh_ifindex = ifindex; 246 nh->ce_mask |= NH_ATTR_IFINDEX; 247} 248 249int rtnl_route_nh_get_ifindex(struct rtnl_nexthop *nh) 250{ 251 return nh->rtnh_ifindex; 252} 253 254void rtnl_route_nh_set_gateway(struct rtnl_nexthop *nh, struct nl_addr *addr) 255{ 256 struct nl_addr *old = nh->rtnh_gateway; 257 258 if (addr) { 259 nh->rtnh_gateway = nl_addr_get(addr); 260 nh->ce_mask |= NH_ATTR_GATEWAY; 261 } else { 262 nh->ce_mask &= ~NH_ATTR_GATEWAY; 263 nh->rtnh_gateway = NULL; 264 } 265 266 if (old) 267 nl_addr_put(old); 268} 269 270struct nl_addr *rtnl_route_nh_get_gateway(struct rtnl_nexthop *nh) 271{ 272 return nh->rtnh_gateway; 273} 274 275void rtnl_route_nh_set_flags(struct rtnl_nexthop *nh, unsigned int flags) 276{ 277 nh->rtnh_flag_mask |= flags; 278 nh->rtnh_flags |= flags; 279 nh->ce_mask |= NH_ATTR_FLAGS; 280} 281 282void rtnl_route_nh_unset_flags(struct rtnl_nexthop *nh, unsigned int flags) 283{ 284 nh->rtnh_flag_mask |= flags; 285 nh->rtnh_flags &= ~flags; 286 nh->ce_mask |= NH_ATTR_FLAGS; 287} 288 289unsigned int rtnl_route_nh_get_flags(struct rtnl_nexthop *nh) 290{ 291 return nh->rtnh_flags; 292} 293 294void rtnl_route_nh_set_realms(struct rtnl_nexthop *nh, uint32_t realms) 295{ 296 nh->rtnh_realms = realms; 297 nh->ce_mask |= NH_ATTR_REALMS; 298} 299 300uint32_t rtnl_route_nh_get_realms(struct rtnl_nexthop *nh) 301{ 302 return nh->rtnh_realms; 303} 304 305/** @} */ 306 307/** 308 * @name Nexthop Flags Translations 309 * @{ 310 */ 311 312static struct trans_tbl nh_flags[] = { 313 __ADD(RTNH_F_DEAD, dead) 314 __ADD(RTNH_F_PERVASIVE, pervasive) 315 __ADD(RTNH_F_ONLINK, onlink) 316}; 317 318char *rtnl_route_nh_flags2str(int flags, char *buf, size_t len) 319{ 320 return __flags2str(flags, buf, len, nh_flags, ARRAY_SIZE(nh_flags)); 321} 322 323int rtnl_route_nh_str2flags(const char *name) 324{ 325 return __str2flags(name, nh_flags, ARRAY_SIZE(nh_flags)); 326} 327 328/** @} */ 329 330/** @} */ 331