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-private/netlink.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_safe("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 if (link_cache) 133 nl_cache_put(link_cache); 134 } 135 136 static void nh_dump_details(struct rtnl_nexthop *nh, struct nl_dump_params *dp) 137 { 138 struct nl_cache *link_cache; 139 char buf[128]; 140 141 link_cache = nl_cache_mngt_require_safe("route/link"); 142 143 nl_dump(dp, "nexthop"); 144 145 if (nh->ce_mask & NH_ATTR_GATEWAY) 146 nl_dump(dp, " via %s", nl_addr2str(nh->rtnh_gateway, 147 buf, sizeof(buf))); 148 149 if(nh->ce_mask & NH_ATTR_IFINDEX) { 150 if (link_cache) { 151 nl_dump(dp, " dev %s", 152 rtnl_link_i2name(link_cache, 153 nh->rtnh_ifindex, 154 buf, sizeof(buf))); 155 } else 156 nl_dump(dp, " dev %d", nh->rtnh_ifindex); 157 } 158 159 if (nh->ce_mask & NH_ATTR_WEIGHT) 160 nl_dump(dp, " weight %u", nh->rtnh_weight); 161 162 if (nh->ce_mask & NH_ATTR_REALMS) 163 nl_dump(dp, " realm %04x:%04x", 164 RTNL_REALM_FROM(nh->rtnh_realms), 165 RTNL_REALM_TO(nh->rtnh_realms)); 166 167 if (nh->ce_mask & NH_ATTR_FLAGS) 168 nl_dump(dp, " <%s>", rtnl_route_nh_flags2str(nh->rtnh_flags, 169 buf, sizeof(buf))); 170 171 if (link_cache) 172 nl_cache_put(link_cache); 173 } 174 175 void rtnl_route_nh_dump(struct rtnl_nexthop *nh, struct nl_dump_params *dp) 176 { 177 switch (dp->dp_type) { 178 case NL_DUMP_LINE: 179 nh_dump_line(nh, dp); 180 break; 181 182 case NL_DUMP_DETAILS: 183 case NL_DUMP_STATS: 184 if (dp->dp_ivar == NH_DUMP_FROM_DETAILS) 185 nh_dump_details(nh, dp); 186 break; 187 188 default: 189 break; 190 } 191 } 192 193 /** 194 * @name Attributes 195 * @{ 196 */ 197 198 void rtnl_route_nh_set_weight(struct rtnl_nexthop *nh, uint8_t weight) 199 { 200 nh->rtnh_weight = weight; 201 nh->ce_mask |= NH_ATTR_WEIGHT; 202 } 203 204 uint8_t rtnl_route_nh_get_weight(struct rtnl_nexthop *nh) 205 { 206 return nh->rtnh_weight; 207 } 208 209 void rtnl_route_nh_set_ifindex(struct rtnl_nexthop *nh, int ifindex) 210 { 211 nh->rtnh_ifindex = ifindex; 212 nh->ce_mask |= NH_ATTR_IFINDEX; 213 } 214 215 int rtnl_route_nh_get_ifindex(struct rtnl_nexthop *nh) 216 { 217 return nh->rtnh_ifindex; 218 } 219 220 /* FIXME: Convert to return an int */ 221 void rtnl_route_nh_set_gateway(struct rtnl_nexthop *nh, struct nl_addr *addr) 222 { 223 struct nl_addr *old = nh->rtnh_gateway; 224 225 if (addr) { 226 nh->rtnh_gateway = nl_addr_get(addr); 227 nh->ce_mask |= NH_ATTR_GATEWAY; 228 } else { 229 nh->ce_mask &= ~NH_ATTR_GATEWAY; 230 nh->rtnh_gateway = NULL; 231 } 232 233 if (old) 234 nl_addr_put(old); 235 } 236 237 struct nl_addr *rtnl_route_nh_get_gateway(struct rtnl_nexthop *nh) 238 { 239 return nh->rtnh_gateway; 240 } 241 242 void rtnl_route_nh_set_flags(struct rtnl_nexthop *nh, unsigned int flags) 243 { 244 nh->rtnh_flag_mask |= flags; 245 nh->rtnh_flags |= flags; 246 nh->ce_mask |= NH_ATTR_FLAGS; 247 } 248 249 void rtnl_route_nh_unset_flags(struct rtnl_nexthop *nh, unsigned int flags) 250 { 251 nh->rtnh_flag_mask |= flags; 252 nh->rtnh_flags &= ~flags; 253 nh->ce_mask |= NH_ATTR_FLAGS; 254 } 255 256 unsigned int rtnl_route_nh_get_flags(struct rtnl_nexthop *nh) 257 { 258 return nh->rtnh_flags; 259 } 260 261 void rtnl_route_nh_set_realms(struct rtnl_nexthop *nh, uint32_t realms) 262 { 263 nh->rtnh_realms = realms; 264 nh->ce_mask |= NH_ATTR_REALMS; 265 } 266 267 uint32_t rtnl_route_nh_get_realms(struct rtnl_nexthop *nh) 268 { 269 return nh->rtnh_realms; 270 } 271 272 /** @} */ 273 274 /** 275 * @name Nexthop Flags Translations 276 * @{ 277 */ 278 279 static const struct trans_tbl nh_flags[] = { 280 __ADD(RTNH_F_DEAD, dead) 281 __ADD(RTNH_F_PERVASIVE, pervasive) 282 __ADD(RTNH_F_ONLINK, onlink) 283 }; 284 285 char *rtnl_route_nh_flags2str(int flags, char *buf, size_t len) 286 { 287 return __flags2str(flags, buf, len, nh_flags, ARRAY_SIZE(nh_flags)); 288 } 289 290 int rtnl_route_nh_str2flags(const char *name) 291 { 292 return __str2flags(name, nh_flags, ARRAY_SIZE(nh_flags)); 293 } 294 295 /** @} */ 296 297 /** @} */ 298