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 (at) 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 37 struct 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 50 struct 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 75 void rtnl_route_nh_free(struct rtnl_nexthop *nh) 76 { 77 nl_addr_put(nh->rtnh_gateway); 78 free(nh); 79 } 80 81 /** @} */ 82 83 int 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 107 static 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 133 static 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 169 static 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 } 205 void 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 232 void 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 238 uint8_t rtnl_route_nh_get_weight(struct rtnl_nexthop *nh) 239 { 240 return nh->rtnh_weight; 241 } 242 243 void 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 249 int rtnl_route_nh_get_ifindex(struct rtnl_nexthop *nh) 250 { 251 return nh->rtnh_ifindex; 252 } 253 254 void 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 270 struct nl_addr *rtnl_route_nh_get_gateway(struct rtnl_nexthop *nh) 271 { 272 return nh->rtnh_gateway; 273 } 274 275 void 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 282 void 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 289 unsigned int rtnl_route_nh_get_flags(struct rtnl_nexthop *nh) 290 { 291 return nh->rtnh_flags; 292 } 293 294 void 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 300 uint32_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 312 static 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 318 char *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 323 int rtnl_route_nh_str2flags(const char *name) 324 { 325 return __str2flags(name, nh_flags, ARRAY_SIZE(nh_flags)); 326 } 327 328 /** @} */ 329 330 /** @} */ 331