xref: /freebsd/sys/netinet/in_fib.c (revision fedeb08b6a58e708e1153224d37ad26bdc1062a2)
165ff3638SAlexander V. Chernikov /*-
265ff3638SAlexander V. Chernikov  * Copyright (c) 2015
365ff3638SAlexander V. Chernikov  * 	Alexander V. Chernikov <melifaro@FreeBSD.org>
465ff3638SAlexander V. Chernikov  *
565ff3638SAlexander V. Chernikov  * Redistribution and use in source and binary forms, with or without
665ff3638SAlexander V. Chernikov  * modification, are permitted provided that the following conditions
765ff3638SAlexander V. Chernikov  * are met:
865ff3638SAlexander V. Chernikov  * 1. Redistributions of source code must retain the above copyright
965ff3638SAlexander V. Chernikov  *    notice, this list of conditions and the following disclaimer.
1065ff3638SAlexander V. Chernikov  * 2. Redistributions in binary form must reproduce the above copyright
1165ff3638SAlexander V. Chernikov  *    notice, this list of conditions and the following disclaimer in the
1265ff3638SAlexander V. Chernikov  *    documentation and/or other materials provided with the distribution.
13fbbd9655SWarner Losh  * 3. Neither the name of the University nor the names of its contributors
1465ff3638SAlexander V. Chernikov  *    may be used to endorse or promote products derived from this software
1565ff3638SAlexander V. Chernikov  *    without specific prior written permission.
1665ff3638SAlexander V. Chernikov  *
1765ff3638SAlexander V. Chernikov  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1865ff3638SAlexander V. Chernikov  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1965ff3638SAlexander V. Chernikov  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2065ff3638SAlexander V. Chernikov  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2165ff3638SAlexander V. Chernikov  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2265ff3638SAlexander V. Chernikov  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2365ff3638SAlexander V. Chernikov  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2465ff3638SAlexander V. Chernikov  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2565ff3638SAlexander V. Chernikov  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2665ff3638SAlexander V. Chernikov  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2765ff3638SAlexander V. Chernikov  * SUCH DAMAGE.
2865ff3638SAlexander V. Chernikov  */
2965ff3638SAlexander V. Chernikov 
3065ff3638SAlexander V. Chernikov #include <sys/cdefs.h>
3165ff3638SAlexander V. Chernikov __FBSDID("$FreeBSD$");
3265ff3638SAlexander V. Chernikov 
3365ff3638SAlexander V. Chernikov #include "opt_inet.h"
3465ff3638SAlexander V. Chernikov #include "opt_route.h"
3565ff3638SAlexander V. Chernikov 
3665ff3638SAlexander V. Chernikov #include <sys/param.h>
3765ff3638SAlexander V. Chernikov #include <sys/systm.h>
3865ff3638SAlexander V. Chernikov #include <sys/lock.h>
3920efcfc6SAndrey V. Elsukov #include <sys/rmlock.h>
4065ff3638SAlexander V. Chernikov #include <sys/malloc.h>
4165ff3638SAlexander V. Chernikov #include <sys/mbuf.h>
4265ff3638SAlexander V. Chernikov #include <sys/socket.h>
4365ff3638SAlexander V. Chernikov #include <sys/sysctl.h>
4465ff3638SAlexander V. Chernikov #include <sys/kernel.h>
4565ff3638SAlexander V. Chernikov 
4665ff3638SAlexander V. Chernikov #include <net/if.h>
4765ff3638SAlexander V. Chernikov #include <net/if_var.h>
4865ff3638SAlexander V. Chernikov #include <net/if_dl.h>
4965ff3638SAlexander V. Chernikov #include <net/route.h>
50*fedeb08bSAlexander V. Chernikov #include <net/route/route_ctl.h>
51e7d8af4fSAlexander V. Chernikov #include <net/route/route_var.h>
52a6663252SAlexander V. Chernikov #include <net/route/nhop.h>
5365ff3638SAlexander V. Chernikov #include <net/vnet.h>
5465ff3638SAlexander V. Chernikov 
5565ff3638SAlexander V. Chernikov #include <netinet/in.h>
5665ff3638SAlexander V. Chernikov #include <netinet/in_var.h>
5765ff3638SAlexander V. Chernikov #include <netinet/in_fib.h>
5865ff3638SAlexander V. Chernikov 
5965ff3638SAlexander V. Chernikov #ifdef INET
60983066f0SAlexander V. Chernikov 
61983066f0SAlexander V. Chernikov /* Verify struct route compatiblity */
62983066f0SAlexander V. Chernikov /* Assert 'struct route_in' is compatible with 'struct route' */
63983066f0SAlexander V. Chernikov CHK_STRUCT_ROUTE_COMPAT(struct route_in, ro_dst4);
6465ff3638SAlexander V. Chernikov 
65a6663252SAlexander V. Chernikov /*
66a6663252SAlexander V. Chernikov  * Looks up path in fib @fibnum specified by @dst.
67a6663252SAlexander V. Chernikov  * Returns path nexthop on success. Nexthop is safe to use
68a6663252SAlexander V. Chernikov  *  within the current network epoch. If longer lifetime is required,
69a6663252SAlexander V. Chernikov  *  one needs to pass NHR_REF as a flag. This will return referenced
70a6663252SAlexander V. Chernikov  *  nexthop.
71a6663252SAlexander V. Chernikov  */
72a6663252SAlexander V. Chernikov struct nhop_object *
73a6663252SAlexander V. Chernikov fib4_lookup(uint32_t fibnum, struct in_addr dst, uint32_t scopeid,
74a6663252SAlexander V. Chernikov     uint32_t flags, uint32_t flowid)
75a6663252SAlexander V. Chernikov {
76a6663252SAlexander V. Chernikov 	RIB_RLOCK_TRACKER;
77a6663252SAlexander V. Chernikov 	struct rib_head *rh;
78a6663252SAlexander V. Chernikov 	struct radix_node *rn;
79a6663252SAlexander V. Chernikov 	struct nhop_object *nh;
80a6663252SAlexander V. Chernikov 
81a6663252SAlexander V. Chernikov 	KASSERT((fibnum < rt_numfibs), ("fib4_lookup: bad fibnum"));
82a6663252SAlexander V. Chernikov 	rh = rt_tables_get_rnh(fibnum, AF_INET);
83a6663252SAlexander V. Chernikov 	if (rh == NULL)
84a6663252SAlexander V. Chernikov 		return (NULL);
85a6663252SAlexander V. Chernikov 
86a6663252SAlexander V. Chernikov 	/* Prepare lookup key */
87a6663252SAlexander V. Chernikov 	struct sockaddr_in sin4;
88a6663252SAlexander V. Chernikov 	memset(&sin4, 0, sizeof(sin4));
89a6663252SAlexander V. Chernikov 	sin4.sin_family = AF_INET;
90a6663252SAlexander V. Chernikov 	sin4.sin_len = sizeof(struct sockaddr_in);
91a6663252SAlexander V. Chernikov 	sin4.sin_addr = dst;
92a6663252SAlexander V. Chernikov 
93a6663252SAlexander V. Chernikov 	nh = NULL;
94a6663252SAlexander V. Chernikov 	RIB_RLOCK(rh);
95a6663252SAlexander V. Chernikov 	rn = rh->rnh_matchaddr((void *)&sin4, &rh->head);
96a6663252SAlexander V. Chernikov 	if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) {
97*fedeb08bSAlexander V. Chernikov 		nh = nhop_select((RNTORT(rn))->rt_nhop, flowid);
98a6663252SAlexander V. Chernikov 		/* Ensure route & ifp is UP */
99a6663252SAlexander V. Chernikov 		if (RT_LINK_IS_UP(nh->nh_ifp)) {
100a6663252SAlexander V. Chernikov 			if (flags & NHR_REF)
101a6663252SAlexander V. Chernikov 				nhop_ref_object(nh);
102a6663252SAlexander V. Chernikov 			RIB_RUNLOCK(rh);
103a6663252SAlexander V. Chernikov 			return (nh);
104a6663252SAlexander V. Chernikov 		}
105a6663252SAlexander V. Chernikov 	}
106a6663252SAlexander V. Chernikov 	RIB_RUNLOCK(rh);
107a6663252SAlexander V. Chernikov 
108a6663252SAlexander V. Chernikov 	RTSTAT_INC(rts_unreach);
109a6663252SAlexander V. Chernikov 	return (NULL);
110a6663252SAlexander V. Chernikov }
111a6663252SAlexander V. Chernikov 
112a6663252SAlexander V. Chernikov inline static int
113*fedeb08bSAlexander V. Chernikov check_urpf_nhop(const struct nhop_object *nh, uint32_t flags,
114a6663252SAlexander V. Chernikov     const struct ifnet *src_if)
115a6663252SAlexander V. Chernikov {
116a6663252SAlexander V. Chernikov 
117a6663252SAlexander V. Chernikov 	if (src_if != NULL && nh->nh_aifp == src_if) {
118a6663252SAlexander V. Chernikov 		return (1);
119a6663252SAlexander V. Chernikov 	}
120a6663252SAlexander V. Chernikov 	if (src_if == NULL) {
121a6663252SAlexander V. Chernikov 		if ((flags & NHR_NODEFAULT) == 0)
122a6663252SAlexander V. Chernikov 			return (1);
123a6663252SAlexander V. Chernikov 		else if ((nh->nh_flags & NHF_DEFAULT) == 0)
124a6663252SAlexander V. Chernikov 			return (1);
125a6663252SAlexander V. Chernikov 	}
126a6663252SAlexander V. Chernikov 
127a6663252SAlexander V. Chernikov 	return (0);
128a6663252SAlexander V. Chernikov }
129a6663252SAlexander V. Chernikov 
130*fedeb08bSAlexander V. Chernikov static int
131*fedeb08bSAlexander V. Chernikov check_urpf(struct nhop_object *nh, uint32_t flags,
132a6663252SAlexander V. Chernikov     const struct ifnet *src_if)
133a6663252SAlexander V. Chernikov {
134*fedeb08bSAlexander V. Chernikov #ifdef ROUTE_MPATH
135*fedeb08bSAlexander V. Chernikov 	if (NH_IS_NHGRP(nh)) {
136*fedeb08bSAlexander V. Chernikov 		struct weightened_nhop *wn;
137*fedeb08bSAlexander V. Chernikov 		uint32_t num_nhops;
138*fedeb08bSAlexander V. Chernikov 		wn = nhgrp_get_nhops((struct nhgrp_object *)nh, &num_nhops);
139*fedeb08bSAlexander V. Chernikov 			for (int i = 0; i < num_nhops; i++) {
140*fedeb08bSAlexander V. Chernikov 				if (check_urpf_nhop(wn[i].nh, flags, src_if) != 0)
141a6663252SAlexander V. Chernikov 				return (1);
142a6663252SAlexander V. Chernikov 		}
143a6663252SAlexander V. Chernikov 		return (0);
144*fedeb08bSAlexander V. Chernikov 	} else
145a6663252SAlexander V. Chernikov #endif
146*fedeb08bSAlexander V. Chernikov 		return (check_urpf_nhop(nh, flags, src_if));
147*fedeb08bSAlexander V. Chernikov }
148a6663252SAlexander V. Chernikov 
149a6663252SAlexander V. Chernikov /*
150a6663252SAlexander V. Chernikov  * Performs reverse path forwarding lookup.
151a6663252SAlexander V. Chernikov  * If @src_if is non-zero, verifies that at least 1 path goes via
152a6663252SAlexander V. Chernikov  *   this interface.
153a6663252SAlexander V. Chernikov  * If @src_if is zero, verifies that route exist.
154a6663252SAlexander V. Chernikov  * if @flags contains NHR_NOTDEFAULT, do not consider default route.
155a6663252SAlexander V. Chernikov  *
156a6663252SAlexander V. Chernikov  * Returns 1 if route matching conditions is found, 0 otherwise.
157a6663252SAlexander V. Chernikov  */
158a6663252SAlexander V. Chernikov int
159a6663252SAlexander V. Chernikov fib4_check_urpf(uint32_t fibnum, struct in_addr dst, uint32_t scopeid,
160a6663252SAlexander V. Chernikov   uint32_t flags, const struct ifnet *src_if)
161a6663252SAlexander V. Chernikov {
162a6663252SAlexander V. Chernikov 	RIB_RLOCK_TRACKER;
163a6663252SAlexander V. Chernikov 	struct rib_head *rh;
164a6663252SAlexander V. Chernikov 	struct radix_node *rn;
165a6663252SAlexander V. Chernikov 	int ret;
166a6663252SAlexander V. Chernikov 
167a6663252SAlexander V. Chernikov 	KASSERT((fibnum < rt_numfibs), ("fib4_check_urpf: bad fibnum"));
168a6663252SAlexander V. Chernikov 	rh = rt_tables_get_rnh(fibnum, AF_INET);
169a6663252SAlexander V. Chernikov 	if (rh == NULL)
170a6663252SAlexander V. Chernikov 		return (0);
171a6663252SAlexander V. Chernikov 
172a6663252SAlexander V. Chernikov 	/* Prepare lookup key */
173a6663252SAlexander V. Chernikov 	struct sockaddr_in sin4;
174a6663252SAlexander V. Chernikov 	memset(&sin4, 0, sizeof(sin4));
175a6663252SAlexander V. Chernikov 	sin4.sin_len = sizeof(struct sockaddr_in);
176a6663252SAlexander V. Chernikov 	sin4.sin_addr = dst;
177a6663252SAlexander V. Chernikov 
178a6663252SAlexander V. Chernikov 	RIB_RLOCK(rh);
179a6663252SAlexander V. Chernikov 	rn = rh->rnh_matchaddr((void *)&sin4, &rh->head);
180a6663252SAlexander V. Chernikov 	if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) {
181*fedeb08bSAlexander V. Chernikov 		ret = check_urpf(RNTORT(rn)->rt_nhop, flags, src_if);
182a6663252SAlexander V. Chernikov 		RIB_RUNLOCK(rh);
183a6663252SAlexander V. Chernikov 		return (ret);
184a6663252SAlexander V. Chernikov 	}
185a6663252SAlexander V. Chernikov 	RIB_RUNLOCK(rh);
186a6663252SAlexander V. Chernikov 
187a6663252SAlexander V. Chernikov 	return (0);
188a6663252SAlexander V. Chernikov }
189a6663252SAlexander V. Chernikov 
19055f57ca9SAlexander V. Chernikov struct nhop_object *
19155f57ca9SAlexander V. Chernikov fib4_lookup_debugnet(uint32_t fibnum, struct in_addr dst, uint32_t scopeid,
19255f57ca9SAlexander V. Chernikov     uint32_t flags)
19355f57ca9SAlexander V. Chernikov {
19455f57ca9SAlexander V. Chernikov 	struct rib_head *rh;
19555f57ca9SAlexander V. Chernikov 	struct radix_node *rn;
19655f57ca9SAlexander V. Chernikov 	struct nhop_object *nh;
19755f57ca9SAlexander V. Chernikov 
19855f57ca9SAlexander V. Chernikov 	KASSERT((fibnum < rt_numfibs), ("fib4_lookup_debugnet: bad fibnum"));
19955f57ca9SAlexander V. Chernikov 	rh = rt_tables_get_rnh(fibnum, AF_INET);
20055f57ca9SAlexander V. Chernikov 	if (rh == NULL)
20155f57ca9SAlexander V. Chernikov 		return (NULL);
20255f57ca9SAlexander V. Chernikov 
20355f57ca9SAlexander V. Chernikov 	/* Prepare lookup key */
20455f57ca9SAlexander V. Chernikov 	struct sockaddr_in sin4;
20555f57ca9SAlexander V. Chernikov 	memset(&sin4, 0, sizeof(sin4));
20655f57ca9SAlexander V. Chernikov 	sin4.sin_family = AF_INET;
20755f57ca9SAlexander V. Chernikov 	sin4.sin_len = sizeof(struct sockaddr_in);
20855f57ca9SAlexander V. Chernikov 	sin4.sin_addr = dst;
20955f57ca9SAlexander V. Chernikov 
21055f57ca9SAlexander V. Chernikov 	nh = NULL;
21155f57ca9SAlexander V. Chernikov 	/* unlocked lookup */
21255f57ca9SAlexander V. Chernikov 	rn = rh->rnh_matchaddr((void *)&sin4, &rh->head);
21355f57ca9SAlexander V. Chernikov 	if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) {
214*fedeb08bSAlexander V. Chernikov 		nh = nhop_select((RNTORT(rn))->rt_nhop, 0);
21555f57ca9SAlexander V. Chernikov 		/* Ensure route & ifp is UP */
21655f57ca9SAlexander V. Chernikov 		if (RT_LINK_IS_UP(nh->nh_ifp)) {
21755f57ca9SAlexander V. Chernikov 			if (flags & NHR_REF)
21855f57ca9SAlexander V. Chernikov 				nhop_ref_object(nh);
21955f57ca9SAlexander V. Chernikov 			return (nh);
22055f57ca9SAlexander V. Chernikov 		}
22155f57ca9SAlexander V. Chernikov 	}
22255f57ca9SAlexander V. Chernikov 
22355f57ca9SAlexander V. Chernikov 	return (NULL);
22455f57ca9SAlexander V. Chernikov }
22555f57ca9SAlexander V. Chernikov 
22665ff3638SAlexander V. Chernikov #endif
227