Home | History | Annotate | Download | only in route
      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