]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netinet/in_fib.c
Update OpenZFS to 2.0.0-rc3-gfc5966
[FreeBSD/FreeBSD.git] / sys / netinet / in_fib.c
1 /*-
2  * Copyright (c) 2015
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 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include "opt_inet.h"
34 #include "opt_route.h"
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/lock.h>
39 #include <sys/rmlock.h>
40 #include <sys/malloc.h>
41 #include <sys/mbuf.h>
42 #include <sys/socket.h>
43 #include <sys/sysctl.h>
44 #include <sys/kernel.h>
45
46 #include <net/if.h>
47 #include <net/if_var.h>
48 #include <net/if_dl.h>
49 #include <net/route.h>
50 #include <net/route/route_ctl.h>
51 #include <net/route/route_var.h>
52 #include <net/route/nhop.h>
53 #include <net/vnet.h>
54
55 #include <netinet/in.h>
56 #include <netinet/in_var.h>
57 #include <netinet/in_fib.h>
58
59 #ifdef INET
60
61 /* Verify struct route compatiblity */
62 /* Assert 'struct route_in' is compatible with 'struct route' */
63 CHK_STRUCT_ROUTE_COMPAT(struct route_in, ro_dst4);
64
65 /*
66  * Looks up path in fib @fibnum specified by @dst.
67  * Returns path nexthop on success. Nexthop is safe to use
68  *  within the current network epoch. If longer lifetime is required,
69  *  one needs to pass NHR_REF as a flag. This will return referenced
70  *  nexthop.
71  */
72 struct nhop_object *
73 fib4_lookup(uint32_t fibnum, struct in_addr dst, uint32_t scopeid,
74     uint32_t flags, uint32_t flowid)
75 {
76         RIB_RLOCK_TRACKER;
77         struct rib_head *rh;
78         struct radix_node *rn;
79         struct nhop_object *nh;
80
81         KASSERT((fibnum < rt_numfibs), ("fib4_lookup: bad fibnum"));
82         rh = rt_tables_get_rnh(fibnum, AF_INET);
83         if (rh == NULL)
84                 return (NULL);
85
86         /* Prepare lookup key */
87         struct sockaddr_in sin4;
88         memset(&sin4, 0, sizeof(sin4));
89         sin4.sin_family = AF_INET;
90         sin4.sin_len = sizeof(struct sockaddr_in);
91         sin4.sin_addr = dst;
92
93         nh = NULL;
94         RIB_RLOCK(rh);
95         rn = rh->rnh_matchaddr((void *)&sin4, &rh->head);
96         if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) {
97                 nh = nhop_select((RNTORT(rn))->rt_nhop, flowid);
98                 /* Ensure route & ifp is UP */
99                 if (RT_LINK_IS_UP(nh->nh_ifp)) {
100                         if (flags & NHR_REF)
101                                 nhop_ref_object(nh);
102                         RIB_RUNLOCK(rh);
103                         return (nh);
104                 }
105         }
106         RIB_RUNLOCK(rh);
107
108         RTSTAT_INC(rts_unreach);
109         return (NULL);
110 }
111
112 inline static int
113 check_urpf_nhop(const struct nhop_object *nh, uint32_t flags,
114     const struct ifnet *src_if)
115 {
116
117         if (src_if != NULL && nh->nh_aifp == src_if) {
118                 return (1);
119         }
120         if (src_if == NULL) {
121                 if ((flags & NHR_NODEFAULT) == 0)
122                         return (1);
123                 else if ((nh->nh_flags & NHF_DEFAULT) == 0)
124                         return (1);
125         }
126
127         return (0);
128 }
129
130 static int
131 check_urpf(struct nhop_object *nh, uint32_t flags,
132     const struct ifnet *src_if)
133 {
134 #ifdef ROUTE_MPATH
135         if (NH_IS_NHGRP(nh)) {
136                 struct weightened_nhop *wn;
137                 uint32_t num_nhops;
138                 wn = nhgrp_get_nhops((struct nhgrp_object *)nh, &num_nhops);
139                         for (int i = 0; i < num_nhops; i++) {
140                                 if (check_urpf_nhop(wn[i].nh, flags, src_if) != 0)
141                                 return (1);
142                 }
143                 return (0);
144         } else
145 #endif
146                 return (check_urpf_nhop(nh, flags, src_if));
147 }
148
149 /*
150  * Performs reverse path forwarding lookup.
151  * If @src_if is non-zero, verifies that at least 1 path goes via
152  *   this interface.
153  * If @src_if is zero, verifies that route exist.
154  * if @flags contains NHR_NOTDEFAULT, do not consider default route.
155  *
156  * Returns 1 if route matching conditions is found, 0 otherwise.
157  */
158 int
159 fib4_check_urpf(uint32_t fibnum, struct in_addr dst, uint32_t scopeid,
160   uint32_t flags, const struct ifnet *src_if)
161 {
162         RIB_RLOCK_TRACKER;
163         struct rib_head *rh;
164         struct radix_node *rn;
165         int ret;
166
167         KASSERT((fibnum < rt_numfibs), ("fib4_check_urpf: bad fibnum"));
168         rh = rt_tables_get_rnh(fibnum, AF_INET);
169         if (rh == NULL)
170                 return (0);
171
172         /* Prepare lookup key */
173         struct sockaddr_in sin4;
174         memset(&sin4, 0, sizeof(sin4));
175         sin4.sin_len = sizeof(struct sockaddr_in);
176         sin4.sin_addr = dst;
177
178         RIB_RLOCK(rh);
179         rn = rh->rnh_matchaddr((void *)&sin4, &rh->head);
180         if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) {
181                 ret = check_urpf(RNTORT(rn)->rt_nhop, flags, src_if);
182                 RIB_RUNLOCK(rh);
183                 return (ret);
184         }
185         RIB_RUNLOCK(rh);
186
187         return (0);
188 }
189
190 struct nhop_object *
191 fib4_lookup_debugnet(uint32_t fibnum, struct in_addr dst, uint32_t scopeid,
192     uint32_t flags)
193 {
194         struct rib_head *rh;
195         struct radix_node *rn;
196         struct nhop_object *nh;
197
198         KASSERT((fibnum < rt_numfibs), ("fib4_lookup_debugnet: bad fibnum"));
199         rh = rt_tables_get_rnh(fibnum, AF_INET);
200         if (rh == NULL)
201                 return (NULL);
202
203         /* Prepare lookup key */
204         struct sockaddr_in sin4;
205         memset(&sin4, 0, sizeof(sin4));
206         sin4.sin_family = AF_INET;
207         sin4.sin_len = sizeof(struct sockaddr_in);
208         sin4.sin_addr = dst;
209
210         nh = NULL;
211         /* unlocked lookup */
212         rn = rh->rnh_matchaddr((void *)&sin4, &rh->head);
213         if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) {
214                 nh = nhop_select((RNTORT(rn))->rt_nhop, 0);
215                 /* Ensure route & ifp is UP */
216                 if (RT_LINK_IS_UP(nh->nh_ifp)) {
217                         if (flags & NHR_REF)
218                                 nhop_ref_object(nh);
219                         return (nh);
220                 }
221         }
222
223         return (NULL);
224 }
225
226 #endif