257480b8ab
* Remove &ifpp from ip6_output() in favor of ri->ri_nh_info * Provide different wrappers to in6_selectsrc: Currently it is used by 2 differenct type of customers: - socket-based one, which all are unsure about provided address scope and - in-kernel ones (ND code mostly), which don't have any sockets, options, crededentials, etc. So, we provide two different wrappers to in6_selectsrc() returning select source. * Make different versions of selectroute(): Currenly selectroute() is used in two scenarios: - SAS, via in6_selecsrc() -> in6_selectif() -> selectroute() - output, via in6_output -> wrapper -> selectroute() Provide different versions for each customer: - fib6_lookup_nh_basic()-based in6_selectif() which is capable of returning interface only, without MTU/NHOP/L2 calculations - full-blown fib6_selectroute() with cached route/multipath/ MTU/L2 * Stop using routing table for link-local address lookups * Add in6_ifawithifp_lla() to make for-us check faster for link-local * Add in6_splitscope / in6_setllascope for faster embed/deembed scopes
199 lines
5.0 KiB
C
199 lines
5.0 KiB
C
/*-
|
|
* Copyright (c) 2012 Chelsio Communications, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <sys/cdefs.h>
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
#include "opt_inet.h"
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/types.h>
|
|
#include <sys/mbuf.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/socketvar.h>
|
|
#include <sys/sockopt.h>
|
|
#include <net/if.h>
|
|
#include <net/if_var.h>
|
|
#include <net/route.h>
|
|
#include <netinet/in.h>
|
|
#include <netinet/in_pcb.h>
|
|
#include <netinet/tcp.h>
|
|
#include <netinet/tcp_var.h>
|
|
#include <netinet/tcp_offload.h>
|
|
#include <net/rt_nhops.h>
|
|
#define TCPOUTFLAGS
|
|
#include <netinet/tcp_fsm.h>
|
|
#include <netinet/toecore.h>
|
|
#include <netinet6/scope6_var.h>
|
|
|
|
int registered_toedevs;
|
|
|
|
/*
|
|
* Provide an opportunity for a TOE driver to offload.
|
|
*/
|
|
int
|
|
tcp_offload_connect(struct socket *so, struct sockaddr *nam)
|
|
{
|
|
struct ifnet *ifp;
|
|
struct toedev *tod;
|
|
struct nhopu_extended nhu_ext;
|
|
int af, error = EOPNOTSUPP;
|
|
int fibnum;
|
|
|
|
INP_WLOCK_ASSERT(sotoinpcb(so));
|
|
KASSERT(nam->sa_family == AF_INET || nam->sa_family == AF_INET6,
|
|
("%s: called with sa_family %d", __func__, nam->sa_family));
|
|
|
|
if (registered_toedevs == 0)
|
|
return (error);
|
|
|
|
af = nam->sa_family;
|
|
fibnum = so->so_fibnum;
|
|
ifp = NULL;
|
|
|
|
/* TODO: Multipath */
|
|
if (af == AF_INET) {
|
|
if (fib4_lookup_nh_ext(fibnum,
|
|
((struct sockaddr_in *)nam)->sin_addr,
|
|
0, NHOP_LOOKUP_REF, &nhu_ext.u.nh4) != 0)
|
|
return (EHOSTUNREACH);
|
|
|
|
ifp = nhu_ext.u.nh4.nh_ifp;
|
|
if ((ifp->if_capenable & IFCAP_TOE4) == 0)
|
|
goto done;
|
|
} else if (af == AF_INET6) {
|
|
struct sockaddr_in6 *sin6;
|
|
struct in6_addr dst;
|
|
uint32_t scopeid;
|
|
|
|
sin6 = (struct sockaddr_in6 *)nam;
|
|
in6_splitscope(&sin6->sin6_addr, &dst, &scopeid);
|
|
|
|
if (fib6_lookup_nh_ext(fibnum, &dst, scopeid,
|
|
0, NHOP_LOOKUP_REF, &nhu_ext.u.nh6) != 0)
|
|
return (EHOSTUNREACH);
|
|
|
|
ifp = nhu_ext.u.nh6.nh_ifp;
|
|
if ((ifp->if_capenable & IFCAP_TOE6) == 0)
|
|
goto done;
|
|
}
|
|
|
|
tod = TOEDEV(ifp);
|
|
if (tod != NULL)
|
|
error = tod->tod_connect(tod, so, &nhu_ext, nam);
|
|
done:
|
|
fib_free_nh_ext(fibnum, &nhu_ext);
|
|
return (error);
|
|
}
|
|
|
|
void
|
|
tcp_offload_listen_start(struct tcpcb *tp)
|
|
{
|
|
|
|
INP_WLOCK_ASSERT(tp->t_inpcb);
|
|
|
|
EVENTHANDLER_INVOKE(tcp_offload_listen_start, tp);
|
|
}
|
|
|
|
void
|
|
tcp_offload_listen_stop(struct tcpcb *tp)
|
|
{
|
|
|
|
INP_WLOCK_ASSERT(tp->t_inpcb);
|
|
|
|
EVENTHANDLER_INVOKE(tcp_offload_listen_stop, tp);
|
|
}
|
|
|
|
void
|
|
tcp_offload_input(struct tcpcb *tp, struct mbuf *m)
|
|
{
|
|
struct toedev *tod = tp->tod;
|
|
|
|
KASSERT(tod != NULL, ("%s: tp->tod is NULL, tp %p", __func__, tp));
|
|
INP_WLOCK_ASSERT(tp->t_inpcb);
|
|
|
|
tod->tod_input(tod, tp, m);
|
|
}
|
|
|
|
int
|
|
tcp_offload_output(struct tcpcb *tp)
|
|
{
|
|
struct toedev *tod = tp->tod;
|
|
int error, flags;
|
|
|
|
KASSERT(tod != NULL, ("%s: tp->tod is NULL, tp %p", __func__, tp));
|
|
INP_WLOCK_ASSERT(tp->t_inpcb);
|
|
|
|
flags = tcp_outflags[tp->t_state];
|
|
|
|
if (flags & TH_RST) {
|
|
/* XXX: avoid repeated calls like we do for FIN */
|
|
error = tod->tod_send_rst(tod, tp);
|
|
} else if ((flags & TH_FIN || tp->t_flags & TF_NEEDFIN) &&
|
|
(tp->t_flags & TF_SENTFIN) == 0) {
|
|
error = tod->tod_send_fin(tod, tp);
|
|
if (error == 0)
|
|
tp->t_flags |= TF_SENTFIN;
|
|
} else
|
|
error = tod->tod_output(tod, tp);
|
|
|
|
return (error);
|
|
}
|
|
|
|
void
|
|
tcp_offload_rcvd(struct tcpcb *tp)
|
|
{
|
|
struct toedev *tod = tp->tod;
|
|
|
|
KASSERT(tod != NULL, ("%s: tp->tod is NULL, tp %p", __func__, tp));
|
|
INP_WLOCK_ASSERT(tp->t_inpcb);
|
|
|
|
tod->tod_rcvd(tod, tp);
|
|
}
|
|
|
|
void
|
|
tcp_offload_ctloutput(struct tcpcb *tp, int sopt_dir, int sopt_name)
|
|
{
|
|
struct toedev *tod = tp->tod;
|
|
|
|
KASSERT(tod != NULL, ("%s: tp->tod is NULL, tp %p", __func__, tp));
|
|
INP_WLOCK_ASSERT(tp->t_inpcb);
|
|
|
|
tod->tod_ctloutput(tod, tp, sopt_dir, sopt_name);
|
|
}
|
|
|
|
void
|
|
tcp_offload_detach(struct tcpcb *tp)
|
|
{
|
|
struct toedev *tod = tp->tod;
|
|
|
|
KASSERT(tod != NULL, ("%s: tp->tod is NULL, tp %p", __func__, tp));
|
|
INP_WLOCK_ASSERT(tp->t_inpcb);
|
|
|
|
tod->tod_pcb_detach(tod, tp);
|
|
}
|