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-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