Changeset View
Changeset View
Standalone View
Standalone View
sys/net/route/route_ctl.c
- This file was added.
/*- | |||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD | |||||
* | |||||
* Copyright (c) 2020 Alexander V. Chernikov | |||||
* | |||||
* 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. | |||||
* | |||||
* $FreeBSD$ | |||||
*/ | |||||
#include "opt_inet.h" | |||||
#include "opt_inet6.h" | |||||
#include <sys/param.h> | |||||
#include <sys/systm.h> | |||||
#include <sys/malloc.h> | |||||
#include <sys/mbuf.h> | |||||
#include <sys/socket.h> | |||||
#include <sys/sysctl.h> | |||||
#include <sys/syslog.h> | |||||
#include <sys/kernel.h> | |||||
#include <sys/lock.h> | |||||
#include <sys/rmlock.h> | |||||
#include <net/if.h> | |||||
#include <net/if_var.h> | |||||
#include <net/if_dl.h> | |||||
#include <net/vnet.h> | |||||
#include <net/route.h> | |||||
#include <net/route_var.h> | |||||
#include <net/route/nhop_utils.h> | |||||
#include <net/route/nhop.h> | |||||
#include <net/route/nhop_var.h> | |||||
#include <net/route/shared.h> | |||||
#include <netinet/in.h> | |||||
#include <vm/uma.h> | |||||
/* | |||||
* This file contains control plane routing tables functions. | |||||
* | |||||
* All functions assumes they are called in net epoch. | |||||
*/ | |||||
static void set_req_mtu(const struct rt_addrinfo *info, struct nhop_request *req); | |||||
static void fill_nh_request(struct rib_head *rnh, struct rt_addrinfo *info, | |||||
struct nhop_request *nh_req); | |||||
static void fill_nh_request_from_nhop(const struct nhop_object *nh, | |||||
struct sockaddr_storage *gw_storage, struct nhop_request *nh_req); | |||||
/* | |||||
* Sets @nh_req mtu data based on the @info data. | |||||
*/ | |||||
static void | |||||
set_req_mtu(const struct rt_addrinfo *info, struct nhop_request *nh_req) | |||||
{ | |||||
if (info->rti_mflags & RTV_MTU) { | |||||
if (info->rti_rmx->rmx_mtu != 0) { | |||||
/* | |||||
* MTU was explicitly provided by user. | |||||
* Keep it. | |||||
*/ | |||||
nh_req->rt_flags |= RTF_FIXEDMTU; | |||||
} else { | |||||
/* | |||||
* User explicitly sets MTU to 0. | |||||
* Assume rollback to default. | |||||
*/ | |||||
nh_req->rt_flags &= ~RTF_FIXEDMTU; | |||||
} | |||||
nh_req->mtu = info->rti_rmx->rmx_mtu; | |||||
} | |||||
} | |||||
/* | |||||
* Fills @nh_req based on the data provided in @info. | |||||
*/ | |||||
static void | |||||
fill_nh_request(struct rib_head *rnh, struct rt_addrinfo *info, | |||||
struct nhop_request *nh_req) | |||||
{ | |||||
bzero(nh_req, sizeof(struct nhop_request)); | |||||
nh_req->ifp = info->rti_ifa->ifa_ifp; | |||||
nh_req->ifa = info->rti_ifa; | |||||
nh_req->gw = info->rti_info[RTAX_GATEWAY]; | |||||
nh_req->family = info->rti_info[RTAX_DST]->sa_family; | |||||
nh_req->rt_flags = info->rti_flags; // fill original rt flags | |||||
nh_req->nh_type = 0; // hook responsibility to set nhop type | |||||
set_req_mtu(info, nh_req); | |||||
} | |||||
/* | |||||
* Fill @nh_req based on the real @nh. | |||||
*/ | |||||
static void | |||||
fill_nh_request_from_nhop(const struct nhop_object *nh, | |||||
struct sockaddr_storage *gw_storage, struct nhop_request *nh_req) | |||||
{ | |||||
memset(nh_req, 0, sizeof(struct nhop_request)); | |||||
nh_req->ifp = nh->nh_ifp; | |||||
ae: It would be better use something one - memset or bzero :) | |||||
nh_req->ifa = nh->nh_ifa; | |||||
nh_req->family = nh->nh_priv->nh_family; | |||||
nh_req->mtu = nh->nh_mtu; | |||||
nh_req->rt_flags = nh->nh_priv->rt_flags; | |||||
nh_req->nh_type = nh->nh_priv->nh_type; | |||||
if (nh_req->rt_flags & RTF_GATEWAY) { | |||||
/* Assume size is already validated */ | |||||
memcpy(gw_storage, &nh->gw4_sa, nh->gw4_sa.sin_len); | |||||
} else { | |||||
Done Inline ActionsIMHO, using gw_sa and sa_len is preferable. It mean address family independence. ae: IMHO, using gw_sa and sa_len is preferable. It mean address family independence. | |||||
/* Nhop value is largerly ignored, set some random bits */ | |||||
gw_storage->ss_len = 0; | |||||
} | |||||
nh_req->gw = (struct sockaddr *)gw_storage; | |||||
} | |||||
/* | |||||
* Update @nh_req request data based on the parameters supplied in @info. | |||||
* This is a helper function to support route changes. | |||||
* | |||||
* It limits the changes that can be done to the route to the following: | |||||
* 1) all combination of gateway changes (gw, interface, blackhole/reject) | |||||
* 2) route flags (FLAG[123],STATIC,BLACKHOLE,REJECT) | |||||
* 3) route MTU | |||||
* | |||||
* Assumes nh_req gw pointer has sockaddr_storage-sized pointer supplied | |||||
* | |||||
* Returns: | |||||
* 0 on success | |||||
*/ | |||||
static int | |||||
alter_nh_request(struct rt_addrinfo *info, u_int fibnum, struct nhop_request *nh_req) | |||||
{ | |||||
/* Update MTU if set in the request*/ | |||||
set_req_mtu(info, nh_req); | |||||
/* XXX: allow only one of BLACKHOLE,REJECT,GATEWAY */ | |||||
/* Allow some flags (FLAG1,STATIC,BLACKHOLE,REJECT) to be toggled on change. */ | |||||
nh_req->rt_flags &= ~RTF_FMASK; | |||||
nh_req->rt_flags |= info->rti_flags & RTF_FMASK; | |||||
/* Consider gateway change */ | |||||
struct sockaddr *info_gw = info->rti_info[RTAX_GATEWAY]; | |||||
if (info_gw != NULL) { | |||||
nh_req->gw = info_gw; | |||||
/* Update RTF_GATEWAY flag status */ | |||||
nh_req->rt_flags &= ~RTF_GATEWAY; | |||||
nh_req->rt_flags |= (RTF_GATEWAY & info->rti_flags); | |||||
} | |||||
if (info->rti_ifa != NULL) | |||||
nh_req->ifa = info->rti_ifa; | |||||
if (info->rti_ifp != NULL) | |||||
nh_req->ifp = info->rti_ifp; | |||||
return (0); | |||||
} | |||||
/* | |||||
* Creates a new nexthop based on the information in @info. | |||||
* | |||||
* Returns: | |||||
* 0 on success, filling @nh_ret with the desired nexthop object ptr | |||||
* errno otherwise | |||||
*/ | |||||
int | |||||
create_nhop_from_info(struct rib_head *rnh, struct rt_addrinfo *info, | |||||
struct nhop_object **nh_ret) | |||||
{ | |||||
struct sockaddr *gateway, *dst, *netmask; | |||||
struct nhop_request nh_req; | |||||
int error; | |||||
fill_nh_request(rnh, info, &nh_req); | |||||
/* Give the protocols chance to augment the request data */ | |||||
dst = info->rti_info[RTAX_DST]; | |||||
netmask = info->rti_info[RTAX_NETMASK]; | |||||
gateway = info->rti_info[RTAX_GATEWAY]; | |||||
if (rnh->rnh_preadd != NULL) { | |||||
error = rnh->rnh_preadd(rnh->rib_fibnum, dst, netmask, &nh_req); | |||||
if (error != 0) | |||||
return (error); | |||||
} | |||||
*nh_ret = nhop_get(rnh, &nh_req); | |||||
if (*nh_ret == NULL) { | |||||
DPRINTF("failed to get the nexthop from req"); | |||||
return (ENOBUFS); | |||||
} | |||||
return (0); | |||||
} | |||||
/* | |||||
* Creates new nexthop based on @nh_old and augmentation data from @info. | |||||
* Helper function used in the route changes, please see | |||||
* alter_nh_request() comments for more details. | |||||
* | |||||
* Returns: | |||||
* 0 on success, filling @nh_ret with the desired nexthop object | |||||
* errno otherwise | |||||
*/ | |||||
int | |||||
create_nhop_from_nhop(struct rib_head *rnh, const struct nhop_object *nh_old, | |||||
struct rt_addrinfo *info, struct nhop_object **nh_ret) | |||||
{ | |||||
struct nhop_request nh_req; | |||||
struct sockaddr_storage gw_storage; | |||||
int error; | |||||
/* Start with copying data from original nexthop */ | |||||
fill_nh_request_from_nhop(nh_old, &gw_storage, &nh_req); | |||||
/* return ifa/ifp referenced */ | |||||
error = alter_nh_request(info, rnh->rib_fibnum, &nh_req); | |||||
if (error != 0) | |||||
return (error); | |||||
/* Give protocol chance to alter the nexthop request */ | |||||
if (rnh->rnh_preadd != NULL) { | |||||
error = rnh->rnh_preadd(rnh->rib_fibnum, info->rti_info[RTAX_DST], | |||||
info->rti_info[RTAX_NETMASK], &nh_req); | |||||
if (error != 0) { | |||||
DPRINTF("failed to create nhop: prehook returned %d", | |||||
error); | |||||
return (error); | |||||
} | |||||
} | |||||
*nh_ret = nhop_get(rnh, &nh_req); | |||||
if (*nh_ret == NULL) { | |||||
DPRINTF("failed to create nhop: nhop_get() failed"); | |||||
return (EAGAIN); | |||||
} | |||||
return (0); | |||||
} | |||||
It would be better use something one - memset or bzero :)