1291993Smelifaro/*- 2291993Smelifaro * Copyright (c) 2015 3291993Smelifaro * Alexander V. Chernikov <melifaro@FreeBSD.org> 4291993Smelifaro * 5291993Smelifaro * Redistribution and use in source and binary forms, with or without 6291993Smelifaro * modification, are permitted provided that the following conditions 7291993Smelifaro * are met: 8291993Smelifaro * 1. Redistributions of source code must retain the above copyright 9291993Smelifaro * notice, this list of conditions and the following disclaimer. 10291993Smelifaro * 2. Redistributions in binary form must reproduce the above copyright 11291993Smelifaro * notice, this list of conditions and the following disclaimer in the 12291993Smelifaro * documentation and/or other materials provided with the distribution. 13291993Smelifaro * 4. Neither the name of the University nor the names of its contributors 14291993Smelifaro * may be used to endorse or promote products derived from this software 15291993Smelifaro * without specific prior written permission. 16291993Smelifaro * 17291993Smelifaro * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18291993Smelifaro * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19291993Smelifaro * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20291993Smelifaro * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21291993Smelifaro * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22291993Smelifaro * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23291993Smelifaro * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24291993Smelifaro * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25291993Smelifaro * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26291993Smelifaro * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27291993Smelifaro * SUCH DAMAGE. 28291993Smelifaro */ 29291993Smelifaro 30291993Smelifaro#include <sys/cdefs.h> 31291993Smelifaro__FBSDID("$FreeBSD$"); 32291993Smelifaro 33291993Smelifaro#include "opt_inet.h" 34291993Smelifaro#include "opt_inet6.h" 35291993Smelifaro#include "opt_route.h" 36291993Smelifaro#include "opt_mpath.h" 37291993Smelifaro 38291993Smelifaro#include <sys/param.h> 39291993Smelifaro#include <sys/systm.h> 40291993Smelifaro#include <sys/lock.h> 41291993Smelifaro#include <sys/rwlock.h> 42291993Smelifaro#include <sys/malloc.h> 43291993Smelifaro#include <sys/mbuf.h> 44291993Smelifaro#include <sys/socket.h> 45291993Smelifaro#include <sys/sysctl.h> 46291993Smelifaro#include <sys/kernel.h> 47291993Smelifaro 48291993Smelifaro#include <net/if.h> 49291993Smelifaro#include <net/if_var.h> 50291993Smelifaro#include <net/if_dl.h> 51291993Smelifaro#include <net/route.h> 52294706Smelifaro#include <net/route_var.h> 53291993Smelifaro#include <net/vnet.h> 54291993Smelifaro 55291993Smelifaro#ifdef RADIX_MPATH 56291993Smelifaro#include <net/radix_mpath.h> 57291993Smelifaro#endif 58291993Smelifaro 59291993Smelifaro#include <netinet/in.h> 60291993Smelifaro#include <netinet/in_var.h> 61291993Smelifaro#include <netinet/ip_mroute.h> 62291993Smelifaro#include <netinet/ip6.h> 63291993Smelifaro#include <netinet6/in6_fib.h> 64291993Smelifaro#include <netinet6/in6_var.h> 65291993Smelifaro#include <netinet6/nd6.h> 66291993Smelifaro#include <netinet6/scope6_var.h> 67291993Smelifaro 68291993Smelifaro#include <net/if_types.h> 69291993Smelifaro 70291993Smelifaro#ifdef INET6 71291993Smelifarostatic void fib6_rte_to_nh_extended(struct rtentry *rte, 72291993Smelifaro const struct in6_addr *dst, uint32_t flags, struct nhop6_extended *pnh6); 73291993Smelifarostatic void fib6_rte_to_nh_basic(struct rtentry *rte, const struct in6_addr *dst, 74291993Smelifaro uint32_t flags, struct nhop6_basic *pnh6); 75291993Smelifarostatic struct ifnet *fib6_get_ifaifp(struct rtentry *rte); 76291993Smelifaro#define RNTORT(p) ((struct rtentry *)(p)) 77291993Smelifaro 78291993Smelifaro/* 79291993Smelifaro * Gets real interface for the @rte. 80291993Smelifaro * Returns rt_ifp for !IFF_LOOPBACK routers. 81291993Smelifaro * Extracts "real" address interface from interface address 82291993Smelifaro * loopback routes. 83291993Smelifaro */ 84291993Smelifarostatic struct ifnet * 85291993Smelifarofib6_get_ifaifp(struct rtentry *rte) 86291993Smelifaro{ 87291993Smelifaro struct ifnet *ifp; 88291993Smelifaro struct sockaddr_dl *sdl; 89291993Smelifaro 90291993Smelifaro ifp = rte->rt_ifp; 91291993Smelifaro if ((ifp->if_flags & IFF_LOOPBACK) && 92291993Smelifaro rte->rt_gateway->sa_family == AF_LINK) { 93291993Smelifaro sdl = (struct sockaddr_dl *)rte->rt_gateway; 94291993Smelifaro return (ifnet_byindex(sdl->sdl_index)); 95291993Smelifaro } 96291993Smelifaro 97291993Smelifaro return (ifp); 98291993Smelifaro} 99291993Smelifaro 100291993Smelifarostatic void 101291993Smelifarofib6_rte_to_nh_basic(struct rtentry *rte, const struct in6_addr *dst, 102291993Smelifaro uint32_t flags, struct nhop6_basic *pnh6) 103291993Smelifaro{ 104291993Smelifaro struct sockaddr_in6 *gw; 105291993Smelifaro 106291993Smelifaro /* Do explicit nexthop zero unless we're copying it */ 107291993Smelifaro memset(pnh6, 0, sizeof(*pnh6)); 108291993Smelifaro 109291993Smelifaro if ((flags & NHR_IFAIF) != 0) 110291993Smelifaro pnh6->nh_ifp = fib6_get_ifaifp(rte); 111291993Smelifaro else 112291993Smelifaro pnh6->nh_ifp = rte->rt_ifp; 113291993Smelifaro 114291993Smelifaro pnh6->nh_mtu = min(rte->rt_mtu, IN6_LINKMTU(rte->rt_ifp)); 115291993Smelifaro if (rte->rt_flags & RTF_GATEWAY) { 116291993Smelifaro gw = (struct sockaddr_in6 *)rte->rt_gateway; 117291993Smelifaro pnh6->nh_addr = gw->sin6_addr; 118291993Smelifaro in6_clearscope(&pnh6->nh_addr); 119291993Smelifaro } else 120291993Smelifaro pnh6->nh_addr = *dst; 121291993Smelifaro /* Set flags */ 122291993Smelifaro pnh6->nh_flags = fib_rte_to_nh_flags(rte->rt_flags); 123291993Smelifaro gw = (struct sockaddr_in6 *)rt_key(rte); 124291993Smelifaro if (IN6_IS_ADDR_UNSPECIFIED(&gw->sin6_addr)) 125291993Smelifaro pnh6->nh_flags |= NHF_DEFAULT; 126291993Smelifaro} 127291993Smelifaro 128291993Smelifarostatic void 129291993Smelifarofib6_rte_to_nh_extended(struct rtentry *rte, const struct in6_addr *dst, 130291993Smelifaro uint32_t flags, struct nhop6_extended *pnh6) 131291993Smelifaro{ 132291993Smelifaro struct sockaddr_in6 *gw; 133291993Smelifaro 134291993Smelifaro /* Do explicit nexthop zero unless we're copying it */ 135291993Smelifaro memset(pnh6, 0, sizeof(*pnh6)); 136291993Smelifaro 137291993Smelifaro if ((flags & NHR_IFAIF) != 0) 138291993Smelifaro pnh6->nh_ifp = fib6_get_ifaifp(rte); 139291993Smelifaro else 140291993Smelifaro pnh6->nh_ifp = rte->rt_ifp; 141291993Smelifaro 142291993Smelifaro pnh6->nh_mtu = min(rte->rt_mtu, IN6_LINKMTU(rte->rt_ifp)); 143291993Smelifaro if (rte->rt_flags & RTF_GATEWAY) { 144291993Smelifaro gw = (struct sockaddr_in6 *)rte->rt_gateway; 145291993Smelifaro pnh6->nh_addr = gw->sin6_addr; 146291993Smelifaro in6_clearscope(&pnh6->nh_addr); 147291993Smelifaro } else 148291993Smelifaro pnh6->nh_addr = *dst; 149291993Smelifaro /* Set flags */ 150291993Smelifaro pnh6->nh_flags = fib_rte_to_nh_flags(rte->rt_flags); 151291993Smelifaro gw = (struct sockaddr_in6 *)rt_key(rte); 152291993Smelifaro if (IN6_IS_ADDR_UNSPECIFIED(&gw->sin6_addr)) 153291993Smelifaro pnh6->nh_flags |= NHF_DEFAULT; 154291993Smelifaro} 155291993Smelifaro 156291993Smelifaro/* 157291993Smelifaro * Performs IPv6 route table lookup on @dst. Returns 0 on success. 158291993Smelifaro * Stores basic nexthop info into provided @pnh6 structure. 159291993Smelifaro * Note that 160291993Smelifaro * - nh_ifp represents logical transmit interface (rt_ifp) by default 161291993Smelifaro * - nh_ifp represents "address" interface if NHR_IFAIF flag is passed 162291993Smelifaro * - mtu from logical transmit interface will be returned. 163291993Smelifaro * - nh_ifp cannot be safely dereferenced 164291993Smelifaro * - nh_ifp represents rt_ifp (e.g. if looking up address on 165291993Smelifaro * interface "ix0" pointer to "ix0" interface will be returned instead 166291993Smelifaro * of "lo0") 167291993Smelifaro * - howewer mtu from "transmit" interface will be returned. 168292015Smelifaro * - scope will be embedded in nh_addr 169291993Smelifaro */ 170291993Smelifaroint 171291993Smelifarofib6_lookup_nh_basic(uint32_t fibnum, const struct in6_addr *dst, uint32_t scopeid, 172291993Smelifaro uint32_t flags, uint32_t flowid, struct nhop6_basic *pnh6) 173291993Smelifaro{ 174294706Smelifaro struct rib_head *rh; 175291993Smelifaro struct radix_node *rn; 176291993Smelifaro struct sockaddr_in6 sin6; 177291993Smelifaro struct rtentry *rte; 178291993Smelifaro 179291993Smelifaro KASSERT((fibnum < rt_numfibs), ("fib6_lookup_nh_basic: bad fibnum")); 180291993Smelifaro rh = rt_tables_get_rnh(fibnum, AF_INET6); 181291993Smelifaro if (rh == NULL) 182291993Smelifaro return (ENOENT); 183291993Smelifaro 184291993Smelifaro /* Prepare lookup key */ 185291993Smelifaro memset(&sin6, 0, sizeof(sin6)); 186291993Smelifaro sin6.sin6_addr = *dst; 187292015Smelifaro sin6.sin6_len = sizeof(struct sockaddr_in6); 188291993Smelifaro /* Assume scopeid is valid and embed it directly */ 189291993Smelifaro if (IN6_IS_SCOPE_LINKLOCAL(dst)) 190291993Smelifaro sin6.sin6_addr.s6_addr16[1] = htons(scopeid & 0xffff); 191291993Smelifaro 192294706Smelifaro RIB_RLOCK(rh); 193294706Smelifaro rn = rh->rnh_matchaddr((void *)&sin6, &rh->head); 194291993Smelifaro if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) { 195291993Smelifaro rte = RNTORT(rn); 196291993Smelifaro /* Ensure route & ifp is UP */ 197291993Smelifaro if (RT_LINK_IS_UP(rte->rt_ifp)) { 198292015Smelifaro fib6_rte_to_nh_basic(rte, &sin6.sin6_addr, flags, pnh6); 199294706Smelifaro RIB_RUNLOCK(rh); 200291993Smelifaro return (0); 201291993Smelifaro } 202291993Smelifaro } 203294706Smelifaro RIB_RUNLOCK(rh); 204291993Smelifaro 205291993Smelifaro return (ENOENT); 206291993Smelifaro} 207291993Smelifaro 208291993Smelifaro/* 209291993Smelifaro * Performs IPv6 route table lookup on @dst. Returns 0 on success. 210291993Smelifaro * Stores extended nexthop info into provided @pnh6 structure. 211291993Smelifaro * Note that 212291993Smelifaro * - nh_ifp cannot be safely dereferenced unless NHR_REF is specified. 213291993Smelifaro * - in that case you need to call fib6_free_nh_ext() 214291993Smelifaro * - nh_ifp represents logical transmit interface (rt_ifp) by default 215291993Smelifaro * - nh_ifp represents "address" interface if NHR_IFAIF flag is passed 216291993Smelifaro * - mtu from logical transmit interface will be returned. 217292015Smelifaro * - scope will be embedded in nh_addr 218291993Smelifaro */ 219291993Smelifaroint 220291993Smelifarofib6_lookup_nh_ext(uint32_t fibnum, const struct in6_addr *dst,uint32_t scopeid, 221291993Smelifaro uint32_t flags, uint32_t flowid, struct nhop6_extended *pnh6) 222291993Smelifaro{ 223294706Smelifaro struct rib_head *rh; 224291993Smelifaro struct radix_node *rn; 225291993Smelifaro struct sockaddr_in6 sin6; 226291993Smelifaro struct rtentry *rte; 227291993Smelifaro 228291993Smelifaro KASSERT((fibnum < rt_numfibs), ("fib6_lookup_nh_ext: bad fibnum")); 229291993Smelifaro rh = rt_tables_get_rnh(fibnum, AF_INET6); 230291993Smelifaro if (rh == NULL) 231291993Smelifaro return (ENOENT); 232291993Smelifaro 233291993Smelifaro /* Prepare lookup key */ 234291993Smelifaro memset(&sin6, 0, sizeof(sin6)); 235291993Smelifaro sin6.sin6_len = sizeof(struct sockaddr_in6); 236291993Smelifaro sin6.sin6_addr = *dst; 237291993Smelifaro /* Assume scopeid is valid and embed it directly */ 238291993Smelifaro if (IN6_IS_SCOPE_LINKLOCAL(dst)) 239291993Smelifaro sin6.sin6_addr.s6_addr16[1] = htons(scopeid & 0xffff); 240291993Smelifaro 241294706Smelifaro RIB_RLOCK(rh); 242294706Smelifaro rn = rh->rnh_matchaddr((void *)&sin6, &rh->head); 243291993Smelifaro if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) { 244291993Smelifaro rte = RNTORT(rn); 245293657Smelifaro#ifdef RADIX_MPATH 246293657Smelifaro rte = rt_mpath_select(rte, flowid); 247293657Smelifaro if (rte == NULL) { 248294706Smelifaro RIB_RUNLOCK(rh); 249293657Smelifaro return (ENOENT); 250293657Smelifaro } 251293657Smelifaro#endif 252291993Smelifaro /* Ensure route & ifp is UP */ 253291993Smelifaro if (RT_LINK_IS_UP(rte->rt_ifp)) { 254292015Smelifaro fib6_rte_to_nh_extended(rte, &sin6.sin6_addr, flags, 255292015Smelifaro pnh6); 256291993Smelifaro if ((flags & NHR_REF) != 0) { 257291993Smelifaro /* TODO: Do lwref on egress ifp's */ 258291993Smelifaro } 259294706Smelifaro RIB_RUNLOCK(rh); 260291993Smelifaro 261291993Smelifaro return (0); 262291993Smelifaro } 263291993Smelifaro } 264294706Smelifaro RIB_RUNLOCK(rh); 265291993Smelifaro 266291993Smelifaro return (ENOENT); 267291993Smelifaro} 268291993Smelifaro 269291993Smelifarovoid 270291993Smelifarofib6_free_nh_ext(uint32_t fibnum, struct nhop6_extended *pnh6) 271291993Smelifaro{ 272291993Smelifaro 273291993Smelifaro} 274291993Smelifaro 275291993Smelifaro#endif 276291993Smelifaro 277