Simplify filling sockaddr_dl structure for if_resolvemulti()

callback providers. link_init_sdl() function can be used to
fill most of the parameters. Use caller stack instead of
allocation / freing memory for each request. Do not drop support
for extra-long (probably non-existing) link-layer protocols by
introducing link_alloc_sdl() (used by if_resolvemulti() callback)
and link_free_sdl() (used by caller).
Since this change breaks KBI, MFC requires slightly different approach
(link_init_sdl() auto-allocating buffer if necessary to handle cases
 with unmodified if_resolvemulti() callers).

MFC after:	2 weeks
This commit is contained in:
Alexander V. Chernikov 2014-01-18 23:24:51 +00:00
parent e06674ffd2
commit 95fbe4d0cc
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=260870
9 changed files with 63 additions and 96 deletions

View File

@ -522,11 +522,7 @@ lacp_port_create(struct lagg_port *lgp)
boolean_t active = TRUE; /* XXX should be configurable */
boolean_t fast = FALSE; /* XXX should be configurable */
bzero((char *)&sdl, sizeof(sdl));
sdl.sdl_len = sizeof(sdl);
sdl.sdl_family = AF_LINK;
sdl.sdl_index = ifp->if_index;
sdl.sdl_type = IFT_ETHER;
link_init_sdl(ifp, (struct sockaddr *)&sdl, IFT_ETHER);
sdl.sdl_alen = ETHER_ADDR_LEN;
bcopy(&ethermulticastaddr_slowprotocols,

View File

@ -1888,6 +1888,38 @@ link_rtrequest(int cmd, struct rtentry *rt, struct rt_addrinfo *info)
}
}
struct sockaddr_dl *
link_alloc_sdl(size_t size, int flags)
{
return (malloc(size, M_TEMP, flags));
}
void
link_free_sdl(struct sockaddr *sa)
{
free(sa, M_TEMP);
}
/*
* Fills in given sdl with interface basic info.
* Returns pointer to filled sdl.
*/
struct sockaddr_dl *
link_init_sdl(struct ifnet *ifp, struct sockaddr *paddr, u_char iftype)
{
struct sockaddr_dl *sdl;
sdl = (struct sockaddr_dl *)paddr;
memset(sdl, 0, sizeof(struct sockaddr_dl));
sdl->sdl_len = sizeof(struct sockaddr_dl);
sdl->sdl_family = AF_LINK;
sdl->sdl_index = ifp->if_index;
sdl->sdl_type = iftype;
return (sdl);
}
/*
* Mark an interface down and notify protocols of
* the transition.
@ -2938,6 +2970,7 @@ if_addmulti(struct ifnet *ifp, struct sockaddr *sa,
{
struct ifmultiaddr *ifma, *ll_ifma;
struct sockaddr *llsa;
struct sockaddr_dl sdl;
int error;
/*
@ -2957,12 +2990,18 @@ if_addmulti(struct ifnet *ifp, struct sockaddr *sa,
/*
* The address isn't already present; resolve the protocol address
* into a link layer address, and then look that up, bump its
* refcount or allocate an ifma for that also. If 'llsa' was
* returned, we will need to free it later.
* refcount or allocate an ifma for that also.
* Most link layer resolving functions returns address data which
* fits inside default sockaddr_dl structure. However callback
* can allocate another sockaddr structure, in that case we need to
* free it later.
*/
llsa = NULL;
ll_ifma = NULL;
if (ifp->if_resolvemulti != NULL) {
/* Provide called function with buffer size information */
sdl.sdl_len = sizeof(sdl);
llsa = (struct sockaddr *)&sdl;
error = ifp->if_resolvemulti(ifp, &llsa, sa);
if (error)
goto unlock_out;
@ -3026,14 +3065,14 @@ if_addmulti(struct ifnet *ifp, struct sockaddr *sa,
(void) (*ifp->if_ioctl)(ifp, SIOCADDMULTI, 0);
}
if (llsa != NULL)
free(llsa, M_IFMADDR);
if ((llsa != NULL) && (llsa != (struct sockaddr *)&sdl))
link_free_sdl(llsa);
return (0);
free_llsa_out:
if (llsa != NULL)
free(llsa, M_IFMADDR);
if ((llsa != NULL) && (llsa != (struct sockaddr *)&sdl))
link_free_sdl(llsa);
unlock_out:
IF_ADDR_WUNLOCK(ifp);

View File

@ -786,14 +786,7 @@ arc_resolvemulti(struct ifnet *ifp, struct sockaddr **llsa,
sin = (struct sockaddr_in *)sa;
if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
return EADDRNOTAVAIL;
sdl = malloc(sizeof *sdl, M_IFMADDR,
M_NOWAIT | M_ZERO);
if (sdl == NULL)
return ENOMEM;
sdl->sdl_len = sizeof *sdl;
sdl->sdl_family = AF_LINK;
sdl->sdl_index = ifp->if_index;
sdl->sdl_type = IFT_ARCNET;
sdl = link_init_sdl(ifp, *llsa, IFT_ETHER);
sdl->sdl_alen = ARC_ADDR_LEN;
*LLADDR(sdl) = 0;
*llsa = (struct sockaddr *)sdl;
@ -814,14 +807,7 @@ arc_resolvemulti(struct ifnet *ifp, struct sockaddr **llsa,
}
if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
return EADDRNOTAVAIL;
sdl = malloc(sizeof *sdl, M_IFMADDR,
M_NOWAIT | M_ZERO);
if (sdl == NULL)
return ENOMEM;
sdl->sdl_len = sizeof *sdl;
sdl->sdl_family = AF_LINK;
sdl->sdl_index = ifp->if_index;
sdl->sdl_type = IFT_ARCNET;
sdl = link_init_sdl(ifp, *llsa, IFT_ETHER);
sdl->sdl_alen = ARC_ADDR_LEN;
*LLADDR(sdl) = 0;
*llsa = (struct sockaddr *)sdl;

View File

@ -69,6 +69,12 @@ struct sockaddr_dl {
#define LLADDR(s) ((caddr_t)((s)->sdl_data + (s)->sdl_nlen))
#define LLINDEX(s) ((s)->sdl_index)
struct ifnet;
struct sockaddr_dl *link_alloc_sdl(size_t, int);
void link_free_sdl(struct sockaddr *sa);
struct sockaddr_dl *link_init_sdl(struct ifnet *, struct sockaddr *, u_char);
#ifndef _KERNEL
#include <sys/cdefs.h>

View File

@ -1168,14 +1168,7 @@ ether_resolvemulti(struct ifnet *ifp, struct sockaddr **llsa,
sin = (struct sockaddr_in *)sa;
if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
return EADDRNOTAVAIL;
sdl = malloc(sizeof *sdl, M_IFMADDR,
M_NOWAIT|M_ZERO);
if (sdl == NULL)
return ENOMEM;
sdl->sdl_len = sizeof *sdl;
sdl->sdl_family = AF_LINK;
sdl->sdl_index = ifp->if_index;
sdl->sdl_type = IFT_ETHER;
sdl = link_init_sdl(ifp, *llsa, IFT_ETHER);
sdl->sdl_alen = ETHER_ADDR_LEN;
e_addr = LLADDR(sdl);
ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr);
@ -1197,14 +1190,7 @@ ether_resolvemulti(struct ifnet *ifp, struct sockaddr **llsa,
}
if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
return EADDRNOTAVAIL;
sdl = malloc(sizeof *sdl, M_IFMADDR,
M_NOWAIT|M_ZERO);
if (sdl == NULL)
return (ENOMEM);
sdl->sdl_len = sizeof *sdl;
sdl->sdl_family = AF_LINK;
sdl->sdl_index = ifp->if_index;
sdl->sdl_type = IFT_ETHER;
sdl = link_init_sdl(ifp, *llsa, IFT_ETHER);
sdl->sdl_alen = ETHER_ADDR_LEN;
e_addr = LLADDR(sdl);
ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr);

View File

@ -729,14 +729,7 @@ fddi_resolvemulti(ifp, llsa, sa)
sin = (struct sockaddr_in *)sa;
if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
return (EADDRNOTAVAIL);
sdl = malloc(sizeof *sdl, M_IFMADDR,
M_NOWAIT | M_ZERO);
if (sdl == NULL)
return (ENOMEM);
sdl->sdl_len = sizeof *sdl;
sdl->sdl_family = AF_LINK;
sdl->sdl_index = ifp->if_index;
sdl->sdl_type = IFT_FDDI;
sdl = link_init_sdl(ifp, *llsa, IFT_FDDI);
sdl->sdl_nlen = 0;
sdl->sdl_alen = FDDI_ADDR_LEN;
sdl->sdl_slen = 0;
@ -760,14 +753,7 @@ fddi_resolvemulti(ifp, llsa, sa)
}
if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
return (EADDRNOTAVAIL);
sdl = malloc(sizeof *sdl, M_IFMADDR,
M_NOWAIT | M_ZERO);
if (sdl == NULL)
return (ENOMEM);
sdl->sdl_len = sizeof *sdl;
sdl->sdl_family = AF_LINK;
sdl->sdl_index = ifp->if_index;
sdl->sdl_type = IFT_FDDI;
sdl = link_init_sdl(ifp, *llsa, IFT_FDDI);
sdl->sdl_nlen = 0;
sdl->sdl_alen = FDDI_ADDR_LEN;
sdl->sdl_slen = 0;

View File

@ -721,14 +721,7 @@ iso88025_resolvemulti (ifp, llsa, sa)
if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
return (EADDRNOTAVAIL);
}
sdl = malloc(sizeof *sdl, M_IFMADDR,
M_NOWAIT|M_ZERO);
if (sdl == NULL)
return (ENOMEM);
sdl->sdl_len = sizeof *sdl;
sdl->sdl_family = AF_LINK;
sdl->sdl_index = ifp->if_index;
sdl->sdl_type = IFT_ISO88025;
sdl = link_init_sdl(ifp, *llsa, IFT_ISO88025);
sdl->sdl_alen = ISO88025_ADDR_LEN;
e_addr = LLADDR(sdl);
ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr);
@ -751,14 +744,7 @@ iso88025_resolvemulti (ifp, llsa, sa)
if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
return (EADDRNOTAVAIL);
}
sdl = malloc(sizeof *sdl, M_IFMADDR,
M_NOWAIT|M_ZERO);
if (sdl == NULL)
return (ENOMEM);
sdl->sdl_len = sizeof *sdl;
sdl->sdl_family = AF_LINK;
sdl->sdl_index = ifp->if_index;
sdl->sdl_type = IFT_ISO88025;
sdl = link_init_sdl(ifp, *llsa, IFT_ISO88025);
sdl->sdl_alen = ISO88025_ADDR_LEN;
e_addr = LLADDR(sdl);
ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr);

View File

@ -1214,12 +1214,8 @@ lagg_ether_cmdmulti(struct lagg_port *lp, int set)
LAGG_WLOCK_ASSERT(sc);
bzero((char *)&sdl, sizeof(sdl));
sdl.sdl_len = sizeof(sdl);
sdl.sdl_family = AF_LINK;
sdl.sdl_type = IFT_ETHER;
link_init_sdl(ifp, (struct sockaddr *)&sdl, IFT_ETHER);
sdl.sdl_alen = ETHER_ADDR_LEN;
sdl.sdl_index = ifp->if_index;
if (set) {
TAILQ_FOREACH(ifma, &scifp->if_multiaddrs, ifma_link) {

View File

@ -1490,14 +1490,7 @@ ipoib_resolvemulti(struct ifnet *ifp, struct sockaddr **llsa,
sin = (struct sockaddr_in *)sa;
if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
return EADDRNOTAVAIL;
sdl = malloc(sizeof *sdl, M_IFMADDR,
M_NOWAIT|M_ZERO);
if (sdl == NULL)
return ENOMEM;
sdl->sdl_len = sizeof *sdl;
sdl->sdl_family = AF_LINK;
sdl->sdl_index = ifp->if_index;
sdl->sdl_type = IFT_INFINIBAND;
sdl = link_init_sdl(ifp, *llsa, IFT_INFINIBAND);
sdl->sdl_alen = INFINIBAND_ALEN;
e_addr = LLADDR(sdl);
ip_ib_mc_map(sin->sin_addr.s_addr, ifp->if_broadcastaddr,
@ -1517,14 +1510,7 @@ ipoib_resolvemulti(struct ifnet *ifp, struct sockaddr **llsa,
return EADDRNOTAVAIL;
if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
return EADDRNOTAVAIL;
sdl = malloc(sizeof *sdl, M_IFMADDR,
M_NOWAIT|M_ZERO);
if (sdl == NULL)
return (ENOMEM);
sdl->sdl_len = sizeof *sdl;
sdl->sdl_family = AF_LINK;
sdl->sdl_index = ifp->if_index;
sdl->sdl_type = IFT_INFINIBAND;
sdl = link_init_sdl(ifp, *llsa, IFT_INFINIBAND);
sdl->sdl_alen = INFINIBAND_ALEN;
e_addr = LLADDR(sdl);
ipv6_ib_mc_map(&sin6->sin6_addr, ifp->if_broadcastaddr, e_addr);