The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netinet/in_fib.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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/fib_algo.h>
   53 #include <net/route/nhop.h>
   54 #include <net/toeplitz.h>
   55 #include <net/vnet.h>
   56 
   57 #include <netinet/in.h>
   58 #include <netinet/in_var.h>
   59 #include <netinet/in_fib.h>
   60 
   61 #ifdef INET
   62 
   63 /* Verify struct route compatibility */
   64 /* Assert 'struct route_in' is compatible with 'struct route' */
   65 CHK_STRUCT_ROUTE_COMPAT(struct route_in, ro_dst4);
   66 
   67 #ifdef FIB_ALGO
   68 VNET_DEFINE(struct fib_dp *, inet_dp);
   69 #endif
   70 
   71 #ifdef ROUTE_MPATH
   72 struct _hash_5tuple_ipv4 {
   73         struct in_addr src;
   74         struct in_addr dst;
   75         unsigned short src_port;
   76         unsigned short dst_port;
   77         char proto;
   78         char spare[3];
   79 };
   80 _Static_assert(sizeof(struct _hash_5tuple_ipv4) == 16,
   81     "_hash_5tuple_ipv4 size is wrong");
   82 
   83 uint32_t
   84 fib4_calc_software_hash(struct in_addr src, struct in_addr dst,
   85     unsigned short src_port, unsigned short dst_port, char proto,
   86     uint32_t *phashtype)
   87 {
   88         struct _hash_5tuple_ipv4 data;
   89 
   90         data.src = src;
   91         data.dst = dst;
   92         data.src_port = src_port;
   93         data.dst_port = dst_port;
   94         data.proto = proto;
   95         data.spare[0] = data.spare[1] = data.spare[2] = 0;
   96 
   97         *phashtype = M_HASHTYPE_OPAQUE;
   98 
   99         return (toeplitz_hash(MPATH_ENTROPY_KEY_LEN, mpath_entropy_key,
  100           sizeof(data), (uint8_t *)&data));
  101 }
  102 #endif
  103 
  104 /*
  105  * Looks up path in fib @fibnum specified by @dst.
  106  * Returns path nexthop on success. Nexthop is safe to use
  107  *  within the current network epoch. If longer lifetime is required,
  108  *  one needs to pass NHR_REF as a flag. This will return referenced
  109  *  nexthop.
  110  */
  111 #ifdef FIB_ALGO
  112 struct nhop_object *
  113 fib4_lookup(uint32_t fibnum, struct in_addr dst, uint32_t scopeid,
  114     uint32_t flags, uint32_t flowid)
  115 {
  116         struct nhop_object *nh;
  117         struct fib_dp *dp = &V_inet_dp[fibnum];
  118         struct flm_lookup_key key = {.addr4 = dst };
  119 
  120         nh = dp->f(dp->arg, key, scopeid);
  121         if (nh != NULL) {
  122                 nh = nhop_select(nh, flowid);
  123                 /* Ensure route & ifp is UP */
  124                 if (RT_LINK_IS_UP(nh->nh_ifp)) {
  125                         if (flags & NHR_REF)
  126                                 nhop_ref_object(nh);
  127                         return (nh);
  128                 }
  129         }
  130         RTSTAT_INC(rts_unreach);
  131         return (NULL);
  132 }
  133 #else
  134 struct nhop_object *
  135 fib4_lookup(uint32_t fibnum, struct in_addr dst, uint32_t scopeid,
  136     uint32_t flags, uint32_t flowid)
  137 {
  138         RIB_RLOCK_TRACKER;
  139         struct rib_head *rh;
  140         struct radix_node *rn;
  141         struct nhop_object *nh;
  142 
  143         KASSERT((fibnum < rt_numfibs), ("fib4_lookup: bad fibnum"));
  144         rh = rt_tables_get_rnh(fibnum, AF_INET);
  145         if (rh == NULL)
  146                 return (NULL);
  147 
  148         /* Prepare lookup key */
  149         struct sockaddr_in sin4 = {
  150                 .sin_family = AF_INET,
  151                 .sin_len = sizeof(struct sockaddr_in),
  152                 .sin_addr = dst,
  153         };
  154 
  155         nh = NULL;
  156         RIB_RLOCK(rh);
  157         rn = rh->rnh_matchaddr((void *)&sin4, &rh->head);
  158         if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) {
  159                 nh = nhop_select((RNTORT(rn))->rt_nhop, flowid);
  160                 /* Ensure route & ifp is UP */
  161                 if (RT_LINK_IS_UP(nh->nh_ifp)) {
  162                         if (flags & NHR_REF)
  163                                 nhop_ref_object(nh);
  164                         RIB_RUNLOCK(rh);
  165                         return (nh);
  166                 }
  167         }
  168         RIB_RUNLOCK(rh);
  169 
  170         RTSTAT_INC(rts_unreach);
  171         return (NULL);
  172 }
  173 #endif
  174 
  175 inline static int
  176 check_urpf_nhop(const struct nhop_object *nh, uint32_t flags,
  177     const struct ifnet *src_if)
  178 {
  179 
  180         if (src_if != NULL && nh->nh_aifp == src_if) {
  181                 return (1);
  182         }
  183         if (src_if == NULL) {
  184                 if ((flags & NHR_NODEFAULT) == 0)
  185                         return (1);
  186                 else if ((nh->nh_flags & NHF_DEFAULT) == 0)
  187                         return (1);
  188         }
  189 
  190         return (0);
  191 }
  192 
  193 static int
  194 check_urpf(struct nhop_object *nh, uint32_t flags,
  195     const struct ifnet *src_if)
  196 {
  197 #ifdef ROUTE_MPATH
  198         if (NH_IS_NHGRP(nh)) {
  199                 const struct weightened_nhop *wn;
  200                 uint32_t num_nhops;
  201                 wn = nhgrp_get_nhops((struct nhgrp_object *)nh, &num_nhops);
  202                         for (int i = 0; i < num_nhops; i++) {
  203                                 if (check_urpf_nhop(wn[i].nh, flags, src_if) != 0)
  204                                 return (1);
  205                 }
  206                 return (0);
  207         } else
  208 #endif
  209                 return (check_urpf_nhop(nh, flags, src_if));
  210 }
  211 
  212 #ifndef FIB_ALGO
  213 static struct nhop_object *
  214 lookup_nhop(uint32_t fibnum, struct in_addr dst, uint32_t scopeid)
  215 {
  216         RIB_RLOCK_TRACKER;
  217         struct rib_head *rh;
  218         struct radix_node *rn;
  219         struct nhop_object *nh;
  220 
  221         KASSERT((fibnum < rt_numfibs), ("fib4_check_urpf: bad fibnum"));
  222         rh = rt_tables_get_rnh(fibnum, AF_INET);
  223         if (rh == NULL)
  224                 return (NULL);
  225 
  226         /* Prepare lookup key */
  227         struct sockaddr_in sin4;
  228         memset(&sin4, 0, sizeof(sin4));
  229         sin4.sin_len = sizeof(struct sockaddr_in);
  230         sin4.sin_addr = dst;
  231 
  232         nh = NULL;
  233         RIB_RLOCK(rh);
  234         rn = rh->rnh_matchaddr((void *)&sin4, &rh->head);
  235         if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0))
  236                 nh = RNTORT(rn)->rt_nhop;
  237         RIB_RUNLOCK(rh);
  238 
  239         return (nh);
  240 }
  241 #endif
  242 
  243 /*
  244  * Performs reverse path forwarding lookup.
  245  * If @src_if is non-zero, verifies that at least 1 path goes via
  246  *   this interface.
  247  * If @src_if is zero, verifies that route exist.
  248  * if @flags contains NHR_NOTDEFAULT, do not consider default route.
  249  *
  250  * Returns 1 if route matching conditions is found, 0 otherwise.
  251  */
  252 int
  253 fib4_check_urpf(uint32_t fibnum, struct in_addr dst, uint32_t scopeid,
  254   uint32_t flags, const struct ifnet *src_if)
  255 {
  256         struct nhop_object *nh;
  257 #ifdef FIB_ALGO
  258         struct fib_dp *dp = &V_inet_dp[fibnum];
  259         struct flm_lookup_key key = {.addr4 = dst };
  260 
  261         nh = dp->f(dp->arg, key, scopeid);
  262 #else
  263         nh = lookup_nhop(fibnum, dst, scopeid);
  264 #endif
  265         if (nh != NULL)
  266                 return (check_urpf(nh, flags, src_if));
  267 
  268         return (0);
  269 }
  270 
  271 /*
  272  * Function returning prefix match data along with the nexthop data.
  273  * Intended to be used by the control plane code.
  274  * Supported flags:
  275  *  NHR_UNLOCKED: do not lock radix during lookup.
  276  * Returns pointer to rtentry and raw nexthop in @rnd. Both rtentry
  277  *  and nexthop are safe to use within current epoch. Note:
  278  * Note: rnd_nhop can actually be the nexthop group.
  279  */
  280 struct rtentry *
  281 fib4_lookup_rt(uint32_t fibnum, struct in_addr dst, uint32_t scopeid,
  282     uint32_t flags, struct route_nhop_data *rnd)
  283 {
  284         RIB_RLOCK_TRACKER;
  285         struct rib_head *rh;
  286         struct radix_node *rn;
  287         struct rtentry *rt;
  288 
  289         KASSERT((fibnum < rt_numfibs), ("fib4_lookup_rt: bad fibnum"));
  290         rh = rt_tables_get_rnh(fibnum, AF_INET);
  291         if (rh == NULL)
  292                 return (NULL);
  293 
  294         /* Prepare lookup key */
  295         struct sockaddr_in sin4 = {
  296                 .sin_family = AF_INET,
  297                 .sin_len = sizeof(struct sockaddr_in),
  298                 .sin_addr = dst,
  299         };
  300 
  301         rt = NULL;
  302         if (!(flags & NHR_UNLOCKED))
  303                 RIB_RLOCK(rh);
  304         rn = rh->rnh_matchaddr((void *)&sin4, &rh->head);
  305         if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) {
  306                 rt = (struct rtentry *)rn;
  307                 rnd->rnd_nhop = rt->rt_nhop;
  308                 rnd->rnd_weight = rt->rt_weight;
  309         }
  310         if (!(flags & NHR_UNLOCKED))
  311                 RIB_RUNLOCK(rh);
  312 
  313         return (rt);
  314 }
  315 
  316 struct nhop_object *
  317 fib4_lookup_debugnet(uint32_t fibnum, struct in_addr dst, uint32_t scopeid,
  318     uint32_t flags)
  319 {
  320         struct rtentry *rt;
  321         struct route_nhop_data rnd;
  322 
  323         rt = fib4_lookup_rt(fibnum, dst, scopeid, NHR_UNLOCKED, &rnd);
  324         if (rt != NULL) {
  325                 struct nhop_object *nh = nhop_select(rnd.rnd_nhop, 0);
  326                 /* Ensure route & ifp is UP */
  327                 if (RT_LINK_IS_UP(nh->nh_ifp))
  328                         return (nh);
  329         }
  330 
  331         return (NULL);
  332 }
  333 
  334 #endif

Cache object: 0598e02fb40c585a0f2d99e66703ff58


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.