1*65ff3638SAlexander V. Chernikov /*- 2*65ff3638SAlexander V. Chernikov * Copyright (c) 2015 3*65ff3638SAlexander V. Chernikov * Alexander V. Chernikov <melifaro@FreeBSD.org> 4*65ff3638SAlexander V. Chernikov * 5*65ff3638SAlexander V. Chernikov * Redistribution and use in source and binary forms, with or without 6*65ff3638SAlexander V. Chernikov * modification, are permitted provided that the following conditions 7*65ff3638SAlexander V. Chernikov * are met: 8*65ff3638SAlexander V. Chernikov * 1. Redistributions of source code must retain the above copyright 9*65ff3638SAlexander V. Chernikov * notice, this list of conditions and the following disclaimer. 10*65ff3638SAlexander V. Chernikov * 2. Redistributions in binary form must reproduce the above copyright 11*65ff3638SAlexander V. Chernikov * notice, this list of conditions and the following disclaimer in the 12*65ff3638SAlexander V. Chernikov * documentation and/or other materials provided with the distribution. 13*65ff3638SAlexander V. Chernikov * 4. Neither the name of the University nor the names of its contributors 14*65ff3638SAlexander V. Chernikov * may be used to endorse or promote products derived from this software 15*65ff3638SAlexander V. Chernikov * without specific prior written permission. 16*65ff3638SAlexander V. Chernikov * 17*65ff3638SAlexander V. Chernikov * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18*65ff3638SAlexander V. Chernikov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19*65ff3638SAlexander V. Chernikov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20*65ff3638SAlexander V. Chernikov * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21*65ff3638SAlexander V. Chernikov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22*65ff3638SAlexander V. Chernikov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23*65ff3638SAlexander V. Chernikov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24*65ff3638SAlexander V. Chernikov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25*65ff3638SAlexander V. Chernikov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26*65ff3638SAlexander V. Chernikov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27*65ff3638SAlexander V. Chernikov * SUCH DAMAGE. 28*65ff3638SAlexander V. Chernikov */ 29*65ff3638SAlexander V. Chernikov 30*65ff3638SAlexander V. Chernikov #include <sys/cdefs.h> 31*65ff3638SAlexander V. Chernikov __FBSDID("$FreeBSD$"); 32*65ff3638SAlexander V. Chernikov 33*65ff3638SAlexander V. Chernikov #include "opt_inet.h" 34*65ff3638SAlexander V. Chernikov #include "opt_route.h" 35*65ff3638SAlexander V. Chernikov #include "opt_mpath.h" 36*65ff3638SAlexander V. Chernikov 37*65ff3638SAlexander V. Chernikov #include <sys/param.h> 38*65ff3638SAlexander V. Chernikov #include <sys/systm.h> 39*65ff3638SAlexander V. Chernikov #include <sys/lock.h> 40*65ff3638SAlexander V. Chernikov #include <sys/rwlock.h> 41*65ff3638SAlexander V. Chernikov #include <sys/malloc.h> 42*65ff3638SAlexander V. Chernikov #include <sys/mbuf.h> 43*65ff3638SAlexander V. Chernikov #include <sys/socket.h> 44*65ff3638SAlexander V. Chernikov #include <sys/sysctl.h> 45*65ff3638SAlexander V. Chernikov #include <sys/kernel.h> 46*65ff3638SAlexander V. Chernikov 47*65ff3638SAlexander V. Chernikov #include <net/if.h> 48*65ff3638SAlexander V. Chernikov #include <net/if_var.h> 49*65ff3638SAlexander V. Chernikov #include <net/if_dl.h> 50*65ff3638SAlexander V. Chernikov #include <net/route.h> 51*65ff3638SAlexander V. Chernikov #include <net/vnet.h> 52*65ff3638SAlexander V. Chernikov 53*65ff3638SAlexander V. Chernikov #ifdef RADIX_MPATH 54*65ff3638SAlexander V. Chernikov #include <net/radix_mpath.h> 55*65ff3638SAlexander V. Chernikov #endif 56*65ff3638SAlexander V. Chernikov 57*65ff3638SAlexander V. Chernikov #include <netinet/in.h> 58*65ff3638SAlexander V. Chernikov #include <netinet/in_var.h> 59*65ff3638SAlexander V. Chernikov #include <netinet/in_fib.h> 60*65ff3638SAlexander V. Chernikov 61*65ff3638SAlexander V. Chernikov #ifdef INET 62*65ff3638SAlexander V. Chernikov static void fib4_rte_to_nh_basic(struct rtentry *rte, struct in_addr dst, 63*65ff3638SAlexander V. Chernikov uint32_t flags, struct nhop4_basic *pnh4); 64*65ff3638SAlexander V. Chernikov static void fib4_rte_to_nh_extended(struct rtentry *rte, struct in_addr dst, 65*65ff3638SAlexander V. Chernikov uint32_t flags, struct nhop4_extended *pnh4); 66*65ff3638SAlexander V. Chernikov 67*65ff3638SAlexander V. Chernikov #define RNTORT(p) ((struct rtentry *)(p)) 68*65ff3638SAlexander V. Chernikov 69*65ff3638SAlexander V. Chernikov static void 70*65ff3638SAlexander V. Chernikov fib4_rte_to_nh_basic(struct rtentry *rte, struct in_addr dst, 71*65ff3638SAlexander V. Chernikov uint32_t flags, struct nhop4_basic *pnh4) 72*65ff3638SAlexander V. Chernikov { 73*65ff3638SAlexander V. Chernikov struct sockaddr_in *gw; 74*65ff3638SAlexander V. Chernikov 75*65ff3638SAlexander V. Chernikov if ((flags & NHR_IFAIF) != 0) 76*65ff3638SAlexander V. Chernikov pnh4->nh_ifp = rte->rt_ifa->ifa_ifp; 77*65ff3638SAlexander V. Chernikov else 78*65ff3638SAlexander V. Chernikov pnh4->nh_ifp = rte->rt_ifp; 79*65ff3638SAlexander V. Chernikov pnh4->nh_mtu = min(rte->rt_mtu, rte->rt_ifp->if_mtu); 80*65ff3638SAlexander V. Chernikov if (rte->rt_flags & RTF_GATEWAY) { 81*65ff3638SAlexander V. Chernikov gw = (struct sockaddr_in *)rte->rt_gateway; 82*65ff3638SAlexander V. Chernikov pnh4->nh_addr = gw->sin_addr; 83*65ff3638SAlexander V. Chernikov } else 84*65ff3638SAlexander V. Chernikov pnh4->nh_addr = dst; 85*65ff3638SAlexander V. Chernikov /* Set flags */ 86*65ff3638SAlexander V. Chernikov pnh4->nh_flags = fib_rte_to_nh_flags(rte->rt_flags); 87*65ff3638SAlexander V. Chernikov gw = (struct sockaddr_in *)rt_key(rte); 88*65ff3638SAlexander V. Chernikov if (gw->sin_addr.s_addr == 0) 89*65ff3638SAlexander V. Chernikov pnh4->nh_flags |= NHF_DEFAULT; 90*65ff3638SAlexander V. Chernikov /* TODO: Handle RTF_BROADCAST here */ 91*65ff3638SAlexander V. Chernikov } 92*65ff3638SAlexander V. Chernikov 93*65ff3638SAlexander V. Chernikov static void 94*65ff3638SAlexander V. Chernikov fib4_rte_to_nh_extended(struct rtentry *rte, struct in_addr dst, 95*65ff3638SAlexander V. Chernikov uint32_t flags, struct nhop4_extended *pnh4) 96*65ff3638SAlexander V. Chernikov { 97*65ff3638SAlexander V. Chernikov struct sockaddr_in *gw; 98*65ff3638SAlexander V. Chernikov struct in_ifaddr *ia; 99*65ff3638SAlexander V. Chernikov 100*65ff3638SAlexander V. Chernikov pnh4->nh_ifp = rte->rt_ifa->ifa_ifp; 101*65ff3638SAlexander V. Chernikov pnh4->nh_mtu = min(rte->rt_mtu, rte->rt_ifp->if_mtu); 102*65ff3638SAlexander V. Chernikov if (rte->rt_flags & RTF_GATEWAY) { 103*65ff3638SAlexander V. Chernikov gw = (struct sockaddr_in *)rte->rt_gateway; 104*65ff3638SAlexander V. Chernikov pnh4->nh_addr = gw->sin_addr; 105*65ff3638SAlexander V. Chernikov } else 106*65ff3638SAlexander V. Chernikov pnh4->nh_addr = dst; 107*65ff3638SAlexander V. Chernikov /* Set flags */ 108*65ff3638SAlexander V. Chernikov pnh4->nh_flags = fib_rte_to_nh_flags(rte->rt_flags); 109*65ff3638SAlexander V. Chernikov gw = (struct sockaddr_in *)rt_key(rte); 110*65ff3638SAlexander V. Chernikov if (gw->sin_addr.s_addr == 0) 111*65ff3638SAlexander V. Chernikov pnh4->nh_flags |= NHF_DEFAULT; 112*65ff3638SAlexander V. Chernikov /* XXX: Set RTF_BROADCAST if GW address is broadcast */ 113*65ff3638SAlexander V. Chernikov 114*65ff3638SAlexander V. Chernikov ia = ifatoia(rte->rt_ifa); 115*65ff3638SAlexander V. Chernikov pnh4->nh_src = IA_SIN(ia)->sin_addr; 116*65ff3638SAlexander V. Chernikov } 117*65ff3638SAlexander V. Chernikov 118*65ff3638SAlexander V. Chernikov /* 119*65ff3638SAlexander V. Chernikov * Performs IPv4 route table lookup on @dst. Returns 0 on success. 120*65ff3638SAlexander V. Chernikov * Stores nexthop info provided @pnh4 structure. 121*65ff3638SAlexander V. Chernikov * Note that 122*65ff3638SAlexander V. Chernikov * - nh_ifp cannot be safely dereferenced 123*65ff3638SAlexander V. Chernikov * - nh_ifp represents logical transmit interface (rt_ifp) (e.g. if 124*65ff3638SAlexander V. Chernikov * looking up address on interface "ix0" pointer to "lo0" interface 125*65ff3638SAlexander V. Chernikov * will be returned instead of "ix0") 126*65ff3638SAlexander V. Chernikov * - nh_ifp represents "address" interface if NHR_IFAIF flag is passed 127*65ff3638SAlexander V. Chernikov * - howewer mtu from "transmit" interface will be returned. 128*65ff3638SAlexander V. Chernikov */ 129*65ff3638SAlexander V. Chernikov int 130*65ff3638SAlexander V. Chernikov fib4_lookup_nh_basic(uint32_t fibnum, struct in_addr dst, uint32_t flags, 131*65ff3638SAlexander V. Chernikov uint32_t flowid, struct nhop4_basic *pnh4) 132*65ff3638SAlexander V. Chernikov { 133*65ff3638SAlexander V. Chernikov struct radix_node_head *rh; 134*65ff3638SAlexander V. Chernikov struct radix_node *rn; 135*65ff3638SAlexander V. Chernikov struct sockaddr_in sin; 136*65ff3638SAlexander V. Chernikov struct rtentry *rte; 137*65ff3638SAlexander V. Chernikov 138*65ff3638SAlexander V. Chernikov KASSERT((fibnum < rt_numfibs), ("fib4_lookup_nh_basic: bad fibnum")); 139*65ff3638SAlexander V. Chernikov rh = rt_tables_get_rnh(fibnum, AF_INET); 140*65ff3638SAlexander V. Chernikov if (rh == NULL) 141*65ff3638SAlexander V. Chernikov return (ENOENT); 142*65ff3638SAlexander V. Chernikov 143*65ff3638SAlexander V. Chernikov /* Prepare lookup key */ 144*65ff3638SAlexander V. Chernikov memset(&sin, 0, sizeof(sin)); 145*65ff3638SAlexander V. Chernikov sin.sin_len = sizeof(struct sockaddr_in); 146*65ff3638SAlexander V. Chernikov sin.sin_addr = dst; 147*65ff3638SAlexander V. Chernikov 148*65ff3638SAlexander V. Chernikov RADIX_NODE_HEAD_RLOCK(rh); 149*65ff3638SAlexander V. Chernikov rn = rh->rnh_matchaddr((void *)&sin, rh); 150*65ff3638SAlexander V. Chernikov if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) { 151*65ff3638SAlexander V. Chernikov rte = RNTORT(rn); 152*65ff3638SAlexander V. Chernikov /* Ensure route & ifp is UP */ 153*65ff3638SAlexander V. Chernikov if (RT_LINK_IS_UP(rte->rt_ifp)) { 154*65ff3638SAlexander V. Chernikov fib4_rte_to_nh_basic(rte, dst, flags, pnh4); 155*65ff3638SAlexander V. Chernikov RADIX_NODE_HEAD_RUNLOCK(rh); 156*65ff3638SAlexander V. Chernikov 157*65ff3638SAlexander V. Chernikov return (0); 158*65ff3638SAlexander V. Chernikov } 159*65ff3638SAlexander V. Chernikov } 160*65ff3638SAlexander V. Chernikov RADIX_NODE_HEAD_RUNLOCK(rh); 161*65ff3638SAlexander V. Chernikov 162*65ff3638SAlexander V. Chernikov return (ENOENT); 163*65ff3638SAlexander V. Chernikov } 164*65ff3638SAlexander V. Chernikov 165*65ff3638SAlexander V. Chernikov /* 166*65ff3638SAlexander V. Chernikov * Performs IPv4 route table lookup on @dst. Returns 0 on success. 167*65ff3638SAlexander V. Chernikov * Stores extende nexthop info provided @pnh4 structure. 168*65ff3638SAlexander V. Chernikov * Note that 169*65ff3638SAlexander V. Chernikov * - nh_ifp cannot be safely dereferenced unless NHR_REF is specified. 170*65ff3638SAlexander V. Chernikov * - in that case you need to call fib4_free_nh_ext() 171*65ff3638SAlexander V. Chernikov * - nh_ifp represents logical transmit interface (rt_ifp) (e.g. if 172*65ff3638SAlexander V. Chernikov * looking up address of interface "ix0" pointer to "lo0" interface 173*65ff3638SAlexander V. Chernikov * will be returned instead of "ix0") 174*65ff3638SAlexander V. Chernikov * - nh_ifp represents "address" interface if NHR_IFAIF flag is passed 175*65ff3638SAlexander V. Chernikov * - howewer mtu from "transmit" interface will be returned. 176*65ff3638SAlexander V. Chernikov */ 177*65ff3638SAlexander V. Chernikov int 178*65ff3638SAlexander V. Chernikov fib4_lookup_nh_ext(uint32_t fibnum, struct in_addr dst, uint32_t flowid, 179*65ff3638SAlexander V. Chernikov uint32_t flags, struct nhop4_extended *pnh4) 180*65ff3638SAlexander V. Chernikov { 181*65ff3638SAlexander V. Chernikov struct radix_node_head *rh; 182*65ff3638SAlexander V. Chernikov struct radix_node *rn; 183*65ff3638SAlexander V. Chernikov struct sockaddr_in sin; 184*65ff3638SAlexander V. Chernikov struct rtentry *rte; 185*65ff3638SAlexander V. Chernikov 186*65ff3638SAlexander V. Chernikov KASSERT((fibnum < rt_numfibs), ("fib4_lookup_nh_ext: bad fibnum")); 187*65ff3638SAlexander V. Chernikov rh = rt_tables_get_rnh(fibnum, AF_INET); 188*65ff3638SAlexander V. Chernikov if (rh == NULL) 189*65ff3638SAlexander V. Chernikov return (ENOENT); 190*65ff3638SAlexander V. Chernikov 191*65ff3638SAlexander V. Chernikov /* Prepare lookup key */ 192*65ff3638SAlexander V. Chernikov memset(&sin, 0, sizeof(sin)); 193*65ff3638SAlexander V. Chernikov sin.sin_len = sizeof(struct sockaddr_in); 194*65ff3638SAlexander V. Chernikov sin.sin_addr = dst; 195*65ff3638SAlexander V. Chernikov 196*65ff3638SAlexander V. Chernikov RADIX_NODE_HEAD_RLOCK(rh); 197*65ff3638SAlexander V. Chernikov rn = rh->rnh_matchaddr((void *)&sin, rh); 198*65ff3638SAlexander V. Chernikov if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) { 199*65ff3638SAlexander V. Chernikov rte = RNTORT(rn); 200*65ff3638SAlexander V. Chernikov /* Ensure route & ifp is UP */ 201*65ff3638SAlexander V. Chernikov if (RT_LINK_IS_UP(rte->rt_ifp)) { 202*65ff3638SAlexander V. Chernikov fib4_rte_to_nh_extended(rte, dst, flags, pnh4); 203*65ff3638SAlexander V. Chernikov if ((flags & NHR_REF) != 0) { 204*65ff3638SAlexander V. Chernikov /* TODO: lwref on egress ifp's ? */ 205*65ff3638SAlexander V. Chernikov } 206*65ff3638SAlexander V. Chernikov RADIX_NODE_HEAD_RUNLOCK(rh); 207*65ff3638SAlexander V. Chernikov 208*65ff3638SAlexander V. Chernikov return (0); 209*65ff3638SAlexander V. Chernikov } 210*65ff3638SAlexander V. Chernikov } 211*65ff3638SAlexander V. Chernikov RADIX_NODE_HEAD_RUNLOCK(rh); 212*65ff3638SAlexander V. Chernikov 213*65ff3638SAlexander V. Chernikov return (ENOENT); 214*65ff3638SAlexander V. Chernikov } 215*65ff3638SAlexander V. Chernikov 216*65ff3638SAlexander V. Chernikov void 217*65ff3638SAlexander V. Chernikov fib4_free_nh_ext(uint32_t fibnum, struct nhop4_extended *pnh4) 218*65ff3638SAlexander V. Chernikov { 219*65ff3638SAlexander V. Chernikov 220*65ff3638SAlexander V. Chernikov } 221*65ff3638SAlexander V. Chernikov 222*65ff3638SAlexander V. Chernikov #endif 223