| 1 | /*- |
| 2 | * Copyright (c) 2015-2016 |
| 3 | * 	Alexander V. Chernikov <melifaro@FreeBSD.org> |
| 4 | * |
| 5 | * Redistribution and use in source and binary forms, with or without |
| 6 | * modification, are permitted provided that the following conditions |
| 7 | * are met: |
| 8 | * 1. Redistributions of source code must retain the above copyright |
| 9 | * notice, this list of conditions and the following disclaimer. |
| 10 | * 2. Redistributions in binary form must reproduce the above copyright |
| 11 | * notice, this list of conditions and the following disclaimer in the |
| 12 | * documentation and/or other materials provided with the distribution. |
| 13 | * 3. Neither the name of the University nor the names of its contributors |
| 14 | * may be used to endorse or promote products derived from this software |
| 15 | * without specific prior written permission. |
| 16 | * |
| 17 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
| 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
| 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 27 | * SUCH DAMAGE. |
| 28 | */ |
| 29 | |
| 30 | #ifndef _NET_ROUTE_VAR_H_ |
| 31 | #define _NET_ROUTE_VAR_H_ |
| 32 | |
| 33 | #ifndef RNF_NORMAL |
| 34 | #include <net/radix.h> |
| 35 | #endif |
| 36 | #include <sys/ck.h> |
| 37 | #include <sys/epoch.h> |
| 38 | #include <netinet/in.h>		/* struct sockaddr_in */ |
| 39 | #include <sys/counter.h> |
| 40 | #include <net/route/nhop.h> |
| 41 | |
| 42 | struct nh_control; |
| 43 | /* Sets prefix-specific nexthop flags (NHF_DEFAULT, RTF/NHF_HOST, RTF_BROADCAST,..) */ |
| 44 | typedef int rnh_set_nh_pfxflags_f_t(u_int fibnum, const struct sockaddr *addr, |
| 45 | 	const struct sockaddr *mask, struct nhop_object *nh); |
| 46 | /* Fills in family-specific details that are not yet set up (mtu, nhop type, ..) */ |
| 47 | typedef int rnh_augment_nh_f_t(u_int fibnum, struct nhop_object *nh); |
| 48 | |
| 49 | struct rib_head { |
| 50 | 	struct radix_head	head; |
| 51 | 	rn_matchaddr_f_t	*rnh_matchaddr;	/* longest match for sockaddr */ |
| 52 | 	rn_addaddr_f_t		*rnh_addaddr;	/* add based on sockaddr*/ |
| 53 | 	rn_deladdr_f_t		*rnh_deladdr;	/* remove based on sockaddr */ |
| 54 | 	rn_lookup_f_t		*rnh_lookup;	/* exact match for sockaddr */ |
| 55 | 	rn_walktree_t		*rnh_walktree;	/* traverse tree */ |
| 56 | 	rn_walktree_from_t	*rnh_walktree_from; /* traverse tree below a */ |
| 57 | 	rnh_set_nh_pfxflags_f_t	*rnh_set_nh_pfxflags;	/* hook to alter record prior to insertion */ |
| 58 | 	rt_gen_t		rnh_gen;	/* datapath generation counter */ |
| 59 | 	int			rnh_multipath;	/* multipath capable ? */ |
| 60 | 	struct radix_node	rnh_nodes[3];	/* empty tree for common case */ |
| 61 | 	struct rmlock		rib_lock;	/* config/data path lock */ |
| 62 | 	struct radix_mask_head	rmhead;		/* masks radix head */ |
| 63 | 	struct vnet		*rib_vnet;	/* vnet pointer */ |
| 64 | 	int			rib_family;	/* AF of the rtable */ |
| 65 | 	u_int			rib_fibnum;	/* fib number */ |
| 66 | 	struct callout		expire_callout;	/* Callout for expiring dynamic routes */ |
| 67 | 	time_t			next_expire;	/* Next expire run ts */ |
| 68 | 	uint32_t		rnh_prefixes;	/* Number of prefixes */ |
| 69 | 	rt_gen_t		rnh_gen_rib;	/* fib algo: rib generation counter */ |
| 70 | 	uint32_t		rib_dying:1;	/* rib is detaching */ |
| 71 | 	uint32_t		rib_algo_fixed:1;/* fixed algorithm */ |
| 72 | 	uint32_t		rib_algo_init:1;/* algo init done */ |
| 73 | 	struct nh_control	*nh_control;	/* nexthop subsystem data */ |
| 74 | 	rnh_augment_nh_f_t	*rnh_augment_nh;/* hook to alter nexthop prior to insertion */ |
| 75 | 	CK_STAILQ_HEAD(, rib_subscription)	rnh_subscribers;/* notification subscribers */ |
| 76 | }; |
| 77 | |
| 78 | #define	RIB_RLOCK_TRACKER	struct rm_priotracker _rib_tracker |
| 79 | #define	RIB_LOCK_INIT(rh)	rm_init_flags(&(rh)->rib_lock, "rib head lock", RM_DUPOK) |
| 80 | #define	RIB_LOCK_DESTROY(rh)	rm_destroy(&(rh)->rib_lock) |
| 81 | #define	RIB_RLOCK(rh)		rm_rlock(&(rh)->rib_lock, &_rib_tracker) |
| 82 | #define	RIB_RUNLOCK(rh)		rm_runlock(&(rh)->rib_lock, &_rib_tracker) |
| 83 | #define	RIB_WLOCK(rh)		rm_wlock(&(rh)->rib_lock) |
| 84 | #define	RIB_WUNLOCK(rh)		rm_wunlock(&(rh)->rib_lock) |
| 85 | #define	RIB_LOCK_ASSERT(rh)	rm_assert(&(rh)->rib_lock, RA_LOCKED) |
| 86 | #define	RIB_WLOCK_ASSERT(rh)	rm_assert(&(rh)->rib_lock, RA_WLOCKED) |
| 87 | |
| 88 | /* Constants */ |
| 89 | #define	RIB_MAX_RETRIES	3 |
| 90 | #define	RT_MAXFIBS	UINT16_MAX |
| 91 | #define	RIB_MAX_MPATH_WIDTH	64 |
| 92 | |
| 93 | /* Macro for verifying fields in af-specific 'struct route' structures */ |
| 94 | #define CHK_STRUCT_FIELD_GENERIC(_s1, _f1, _s2, _f2)			\ |
| 95 | _Static_assert(sizeof(((_s1 *)0)->_f1) == sizeof(((_s2 *)0)->_f2),	\ |
| 96 | 		"Fields " #_f1 " and " #_f2 " size differs");		\ |
| 97 | _Static_assert(__offsetof(_s1, _f1) == __offsetof(_s2, _f2),		\ |
| 98 | 		"Fields " #_f1 " and " #_f2 " offset differs"); |
| 99 | |
| 100 | #define _CHK_ROUTE_FIELD(_route_new, _field) \ |
| 101 | 	CHK_STRUCT_FIELD_GENERIC(struct route, _field, _route_new, _field) |
| 102 | |
| 103 | #define CHK_STRUCT_ROUTE_FIELDS(_route_new)	\ |
| 104 | 	_CHK_ROUTE_FIELD(_route_new, ro_nh)	\ |
| 105 | 	_CHK_ROUTE_FIELD(_route_new, ro_lle)	\ |
| 106 | 	_CHK_ROUTE_FIELD(_route_new, ro_prepend)\ |
| 107 | 	_CHK_ROUTE_FIELD(_route_new, ro_plen)	\ |
| 108 | 	_CHK_ROUTE_FIELD(_route_new, ro_flags)	\ |
| 109 | 	_CHK_ROUTE_FIELD(_route_new, ro_mtu)	\ |
| 110 | 	_CHK_ROUTE_FIELD(_route_new, spare) |
| 111 | |
| 112 | #define CHK_STRUCT_ROUTE_COMPAT(_ro_new, _dst_new)				\ |
| 113 | CHK_STRUCT_ROUTE_FIELDS(_ro_new);						\ |
| 114 | _Static_assert(__offsetof(struct route, ro_dst) == __offsetof(_ro_new, _dst_new),\ |
| 115 | 		"ro_dst and " #_dst_new " are at different offset") |
| 116 | |
| 117 | static inline void |
| 118 | rib_bump_gen(struct rib_head *rnh) |
| 119 | { |
| 120 | #ifdef FIB_ALGO |
| 121 | 	rnh->rnh_gen_rib++; |
| 122 | #else |
| 123 | 	rnh->rnh_gen++; |
| 124 | #endif |
| 125 | } |
| 126 | |
| 127 | struct rib_head *rt_tables_get_rnh(uint32_t table, sa_family_t family); |
| 128 | int rt_getifa_fib(struct rt_addrinfo *info, u_int fibnum); |
| 129 | struct rib_cmd_info; |
| 130 | |
| 131 | VNET_PCPUSTAT_DECLARE(struct rtstat, rtstat); |
| 132 | #define	RTSTAT_ADD(name, val)	\ |
| 133 | 	VNET_PCPUSTAT_ADD(struct rtstat, rtstat, name, (val)) |
| 134 | #define	RTSTAT_INC(name)	RTSTAT_ADD(name, 1) |
| 135 | |
| 136 | /* |
| 137 | * Convert a 'struct radix_node *' to a 'struct rtentry *'. |
| 138 | * The operation can be done safely (in this code) because a |
| 139 | * 'struct rtentry' starts with two 'struct radix_node''s, the first |
| 140 | * one representing leaf nodes in the routing tree, which is |
| 141 | * what the code in radix.c passes us as a 'struct radix_node'. |
| 142 | * |
| 143 | * But because there are a lot of assumptions in this conversion, |
| 144 | * do not cast explicitly, but always use the macro below. |
| 145 | */ |
| 146 | #define RNTORT(p)	((struct rtentry *)(p)) |
| 147 | |
| 148 | struct rtentry { |
| 149 | 	struct	radix_node rt_nodes[2];	/* tree glue, and other values */ |
| 150 | 	/* |
| 151 | 	 * XXX struct rtentry must begin with a struct radix_node (or two!) |
| 152 | 	 * because the code does some casts of a 'struct radix_node *' |
| 153 | 	 * to a 'struct rtentry *' |
| 154 | 	 */ |
| 155 | #define	rt_key(r)	(*((struct sockaddr **)(&(r)->rt_nodes->rn_key))) |
| 156 | #define	rt_mask(r)	(*((struct sockaddr **)(&(r)->rt_nodes->rn_mask))) |
| 157 | #define	rt_key_const(r)		(*((const struct sockaddr * const *)(&(r)->rt_nodes->rn_key))) |
| 158 | #define	rt_mask_const(r)	(*((const struct sockaddr * const *)(&(r)->rt_nodes->rn_mask))) |
| 159 | |
| 160 | 	/* |
| 161 | 	 * 2 radix_node structurs above consists of 2x6 pointers, leaving |
| 162 | 	 * 4 pointers (32 bytes) of the second cache line on amd64. |
| 163 | 	 * |
| 164 | 	 */ |
| 165 | 	struct nhop_object	*rt_nhop;	/* nexthop data */ |
| 166 | 	union { |
| 167 | 		/* |
| 168 | 		 * Destination address storage. |
| 169 | 		 * sizeof(struct sockaddr_in6) == 28, however |
| 170 | 		 * the dataplane-relevant part (e.g. address) lies |
| 171 | 		 * at offset 8..24, making the address not crossing |
| 172 | 		 * cacheline boundary. |
| 173 | 		 */ |
| 174 | 		struct sockaddr_in	rt_dst4; |
| 175 | 		struct sockaddr_in6	rt_dst6; |
| 176 | 		struct sockaddr		rt_dst; |
| 177 | 		char			rt_dstb[28]; |
| 178 | 	}; |
| 179 | |
| 180 | 	int		rte_flags;	/* up/down?, host/net */ |
| 181 | 	u_long		rt_weight;	/* absolute weight */ |
| 182 | 	struct rtentry	*rt_chain;	/* pointer to next rtentry to delete */ |
| 183 | 	struct epoch_context	rt_epoch_ctx;	/* net epoch tracker */ |
| 184 | }; |
| 185 | |
| 186 | /* |
| 187 | * With the split between the routing entry and the nexthop, |
| 188 | * rt_flags has to be split between these 2 entries. As rtentry |
| 189 | * mostly contains prefix data and is thought to be generic enough |
| 190 | * so one can transparently change the nexthop pointer w/o requiring |
| 191 | * any other rtentry changes, most of rt_flags shifts to the particular nexthop. |
| 192 | * / |
| 193 | * |
| 194 | * RTF_UP: rtentry, as an indication that it is linked. |
| 195 | * RTF_HOST: rtentry, nhop. The latter indication is needed for the datapath |
| 196 | * RTF_DYNAMIC: nhop, to make rtentry generic. |
| 197 | * RTF_MODIFIED: nhop, to make rtentry generic. (legacy) |
| 198 | * -- "native" path (nhop) properties: |
| 199 | * RTF_GATEWAY, RTF_STATIC, RTF_PROTO1, RTF_PROTO2, RTF_PROTO3, RTF_FIXEDMTU, |
| 200 | * RTF_PINNED, RTF_REJECT, RTF_BLACKHOLE, RTF_BROADCAST |
| 201 | */ |
| 202 | |
| 203 | /* rtentry rt flag mask */ |
| 204 | #define	RTE_RT_FLAG_MASK	(RTF_UP | RTF_HOST) |
| 205 | |
| 206 | /* route_temporal.c */ |
| 207 | void tmproutes_update(struct rib_head *rnh, struct rtentry *rt, struct nhop_object *nh); |
| 208 | void tmproutes_init(struct rib_head *rh); |
| 209 | void tmproutes_destroy(struct rib_head *rh); |
| 210 | |
| 211 | /* route_ctl.c */ |
| 212 | struct route_nhop_data; |
| 213 | int change_route(struct rib_head *rnh, struct rtentry *rt, |
| 214 | struct route_nhop_data *rnd, struct rib_cmd_info *rc); |
| 215 | int change_route_conditional(struct rib_head *rnh, struct rtentry *rt, |
| 216 | struct route_nhop_data *nhd_orig, struct route_nhop_data *nhd_new, |
| 217 | struct rib_cmd_info *rc); |
| 218 | struct rtentry *lookup_prefix(struct rib_head *rnh, |
| 219 | const struct rt_addrinfo *info, struct route_nhop_data *rnd); |
| 220 | struct rtentry *lookup_prefix_rt(struct rib_head *rnh, const struct rtentry *rt, |
| 221 | struct route_nhop_data *rnd); |
| 222 | int rib_copy_route(struct rtentry *rt, const struct route_nhop_data *rnd_src, |
| 223 | struct rib_head *rh_dst, struct rib_cmd_info *rc); |
| 224 | |
| 225 | bool nhop_can_multipath(const struct nhop_object *nh); |
| 226 | bool match_nhop_gw(const struct nhop_object *nh, const struct sockaddr *gw); |
| 227 | int check_info_match_nhop(const struct rt_addrinfo *info, |
| 228 | const struct rtentry *rt, const struct nhop_object *nh); |
| 229 | bool rib_can_4o6_nhop(void); |
| 230 | |
| 231 | /* route_rtentry.c */ |
| 232 | void vnet_rtzone_init(void); |
| 233 | void vnet_rtzone_destroy(void); |
| 234 | void rt_free(struct rtentry *rt); |
| 235 | void rt_free_immediate(struct rtentry *rt); |
| 236 | struct rtentry *rt_alloc(struct rib_head *rnh, const struct sockaddr *dst, |
| 237 | struct sockaddr *netmask); |
| 238 | |
| 239 | /* subscriptions */ |
| 240 | void rib_init_subscriptions(struct rib_head *rnh); |
| 241 | void rib_destroy_subscriptions(struct rib_head *rnh); |
| 242 | |
| 243 | /* route_ifaddrs.c */ |
| 244 | void rib_copy_kernel_routes(struct rib_head *rh_src, struct rib_head *rh_dst); |
| 245 | |
| 246 | /* Nexhops */ |
| 247 | void nhops_init(void); |
| 248 | int nhops_init_rib(struct rib_head *rh); |
| 249 | void nhops_destroy_rib(struct rib_head *rh); |
| 250 | void nhop_ref_object(struct nhop_object *nh); |
| 251 | int nhop_try_ref_object(struct nhop_object *nh); |
| 252 | void nhop_ref_any(struct nhop_object *nh); |
| 253 | void nhop_free_any(struct nhop_object *nh); |
| 254 | struct nhop_object *nhop_get_nhop_internal(struct rib_head *rnh, |
| 255 | struct nhop_object *nh, int *perror); |
| 256 | |
| 257 | bool nhop_check_gateway(int upper_family, int neigh_family); |
| 258 | |
| 259 | int nhop_create_from_info(struct rib_head *rnh, struct rt_addrinfo *info, |
| 260 | struct nhop_object **nh_ret); |
| 261 | int nhop_create_from_nhop(struct rib_head *rnh, const struct nhop_object *nh_orig, |
| 262 | struct rt_addrinfo *info, struct nhop_object **pnh_priv); |
| 263 | |
| 264 | void nhops_update_ifmtu(struct rib_head *rh, struct ifnet *ifp, uint32_t mtu); |
| 265 | int nhops_dump_sysctl(struct rib_head *rh, struct sysctl_req *w); |
| 266 | |
| 267 | /* MULTIPATH */ |
| 268 | #define	MPF_MULTIPATH	0x08	/* need to be consistent with NHF_MULTIPATH */ |
| 269 | |
| 270 | struct nhgrp_object { |
| 271 | 	uint16_t		nhg_flags;	/* nexthop group flags */ |
| 272 | 	uint8_t			nhg_size;	/* dataplain group size */ |
| 273 | 	uint8_t			spare; |
| 274 | 	struct nhop_object	*nhops[0];	/* nhops */ |
| 275 | }; |
| 276 | |
| 277 | static inline struct nhop_object * |
| 278 | nhop_select(struct nhop_object *nh, uint32_t flowid) |
| 279 | { |
| 280 | |
| 281 | #ifdef ROUTE_MPATH |
| 282 | 	if (NH_IS_NHGRP(nh)) { |
| 283 | 		struct nhgrp_object *nhg = (struct nhgrp_object *)nh; |
| 284 | 		nh = nhg->nhops[flowid % nhg->nhg_size]; |
| 285 | 	} |
| 286 | #endif |
| 287 | 	return (nh); |
| 288 | } |
| 289 | |
| 290 | |
| 291 | struct weightened_nhop; |
| 292 | |
| 293 | /* mpath_ctl.c */ |
| 294 | int add_route_mpath(struct rib_head *rnh, struct rt_addrinfo *info, |
| 295 | struct rtentry *rt, struct route_nhop_data *rnd_add, |
| 296 | struct route_nhop_data *rnd_orig, struct rib_cmd_info *rc); |
| 297 | |
| 298 | /* nhgrp.c */ |
| 299 | int nhgrp_ctl_init(struct nh_control *ctl); |
| 300 | void nhgrp_ctl_free(struct nh_control *ctl); |
| 301 | void nhgrp_ctl_unlink_all(struct nh_control *ctl); |
| 302 | |
| 303 | |
| 304 | /* nhgrp_ctl.c */ |
| 305 | int nhgrp_dump_sysctl(struct rib_head *rh, struct sysctl_req *w); |
| 306 | |
| 307 | int nhgrp_get_filtered_group(struct rib_head *rh, const struct rtentry *rt, |
| 308 | const struct nhgrp_object *src, rib_filter_f_t flt_func, void *flt_data, |
| 309 | struct route_nhop_data *rnd); |
| 310 | int nhgrp_get_addition_group(struct rib_head *rnh, |
| 311 | struct route_nhop_data *rnd_orig, struct route_nhop_data *rnd_add, |
| 312 | struct route_nhop_data *rnd_new); |
| 313 | |
| 314 | void nhgrp_ref_object(struct nhgrp_object *nhg); |
| 315 | uint32_t nhgrp_get_idx(const struct nhgrp_object *nhg); |
| 316 | void nhgrp_free(struct nhgrp_object *nhg); |
| 317 | |
| 318 | /* rtsock */ |
| 319 | int rtsock_routemsg(int cmd, struct rtentry *rt, struct nhop_object *nh, |
| 320 | int fibnum); |
| 321 | int rtsock_routemsg_info(int cmd, struct rt_addrinfo *info, int fibnum); |
| 322 | int rtsock_addrmsg(int cmd, struct ifaddr *ifa, int fibnum); |
| 323 | |
| 324 | |
| 325 | /* lookup_framework.c */ |
| 326 | void fib_grow_rtables(uint32_t new_num_tables); |
| 327 | void fib_setup_family(int family, uint32_t num_tables); |
| 328 | void fib_destroy_rib(struct rib_head *rh); |
| 329 | void vnet_fib_init(void); |
| 330 | void vnet_fib_destroy(void); |
| 331 | |
| 332 | /* Entropy data used for outbound hashing */ |
| 333 | #define MPATH_ENTROPY_KEY_LEN	40 |
| 334 | extern uint8_t mpath_entropy_key[MPATH_ENTROPY_KEY_LEN]; |
| 335 | |
| 336 | #endif |