Changeset View
Standalone View
sys/netinet6/in6.c
Show First 20 Lines • Show All 98 Lines • ▼ Show 20 Lines | |||||
#include <net/if_llatbl.h> | #include <net/if_llatbl.h> | ||||
#include <netinet/if_ether.h> | #include <netinet/if_ether.h> | ||||
#include <netinet/in_systm.h> | #include <netinet/in_systm.h> | ||||
#include <netinet/ip.h> | #include <netinet/ip.h> | ||||
#include <netinet/in_pcb.h> | #include <netinet/in_pcb.h> | ||||
#include <netinet/ip_carp.h> | #include <netinet/ip_carp.h> | ||||
#include <netinet/ip6.h> | #include <netinet/ip6.h> | ||||
#include <netinet/icmp6.h> | |||||
#include <netinet6/ip6_var.h> | #include <netinet6/ip6_var.h> | ||||
#include <netinet6/nd6.h> | #include <netinet6/nd6.h> | ||||
#include <netinet6/mld6_var.h> | #include <netinet6/mld6_var.h> | ||||
#include <netinet6/ip6_mroute.h> | #include <netinet6/ip6_mroute.h> | ||||
#include <netinet6/in6_ifattach.h> | #include <netinet6/in6_ifattach.h> | ||||
#include <netinet6/scope6_var.h> | #include <netinet6/scope6_var.h> | ||||
#include <netinet6/in6_fib.h> | #include <netinet6/in6_fib.h> | ||||
#include <netinet6/in6_pcb.h> | #include <netinet6/in6_pcb.h> | ||||
/* | /* | ||||
* struct in6_ifreq and struct ifreq must be type punnable for common members | * struct in6_ifreq and struct ifreq must be type punnable for common members | ||||
* of ifr_ifru to allow accessors to be shared. | * of ifr_ifru to allow accessors to be shared. | ||||
*/ | */ | ||||
_Static_assert(offsetof(struct in6_ifreq, ifr_ifru) == | _Static_assert(offsetof(struct in6_ifreq, ifr_ifru) == | ||||
offsetof(struct ifreq, ifr_ifru), | offsetof(struct ifreq, ifr_ifru), | ||||
"struct in6_ifreq and struct ifreq are not type punnable"); | "struct in6_ifreq and struct ifreq are not type punnable"); | ||||
static int in6_llt_max_entries = 2048; | |||||
donner: 2048 is only suitable for small environments. Given privacy extension and crypto addresses (i.e. | |||||
bzAuthorUnsubmitted Done Inline ActionsFor and end-node? If you are a router you might want tune other things as well but then it pretty much does depend on your customer size. Remember this one is per interface. Say if you are a DC router and your average customer has 1 machine with a handful of static IP addresses, even 2k on a VLAN interface is probably way too big. bz: For and end-node? If you are a router you might want tune other things as well but then it… | |||||
donnerUnsubmitted Not Done Inline ActionsYes, I use FreeBSD for routing, not as a desktop or end node. donner: Yes, I use FreeBSD for routing, not as a desktop or end node.
YMMV, please feel free to ignore… | |||||
kbowlingUnsubmitted Not Done Inline ActionsI would suggest doubling to 4k, I can think of a particular user that has some flat VLANs in a big chassis switch pair and will have a few entries per host. kbowling: I would suggest doubling to 4k, I can think of a particular user that has some flat VLANs in a… | |||||
bzAuthorUnsubmitted Done Inline ActionsAnd all these addresses on all these hosts always talk to all of the others? bz: And all these addresses on all these hosts always talk to all of the others? | |||||
kbowlingUnsubmitted Not Done Inline ActionsThis is lossy memory for me, maybe @shurd can poke around at some machines in DAL kbowling: This is lossy memory for me, maybe @shurd can poke around at some machines in DAL | |||||
donnerUnsubmitted Not Done Inline ActionsND is multicast. You might receive ND messages from others and learn (like gratious arp). Simply assume a not so intelligent switch. Consider cryptographically generated addresses or privacy extensions (up to a new address per destination and or connection) donner: ND is multicast. You might receive ND messages from others and learn (like gratious arp). | |||||
bzAuthorUnsubmitted Done Inline ActionsOk, I guess the answer will be to scale this based on memory then. As your tiny IoT device is going to run the same code as your super-huge-server in your server-farm. And while the later probably has resources to deal with 4k or 16k or 128k, the former may still keel over in rows very quickly. bz: Ok, I guess the answer will be to scale this based on memory then. As your tiny IoT device is… | |||||
VNET_DECLARE(int, icmp6_nodeinfo_oldmcprefix); | VNET_DECLARE(int, icmp6_nodeinfo_oldmcprefix); | ||||
#define V_icmp6_nodeinfo_oldmcprefix VNET(icmp6_nodeinfo_oldmcprefix) | #define V_icmp6_nodeinfo_oldmcprefix VNET(icmp6_nodeinfo_oldmcprefix) | ||||
/* | /* | ||||
* Definitions of some costant IP6 addresses. | * Definitions of some costant IP6 addresses. | ||||
*/ | */ | ||||
const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; | const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; | ||||
const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; | const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; | ||||
Show All 26 Lines | |||||
static int in6_update_ifa_internal(struct ifnet *, struct in6_aliasreq *, | static int in6_update_ifa_internal(struct ifnet *, struct in6_aliasreq *, | ||||
struct in6_ifaddr *, int, int); | struct in6_ifaddr *, int, int); | ||||
static int in6_broadcast_ifa(struct ifnet *, struct in6_aliasreq *, | static int in6_broadcast_ifa(struct ifnet *, struct in6_aliasreq *, | ||||
struct in6_ifaddr *, int); | struct in6_ifaddr *, int); | ||||
#define ifa2ia6(ifa) ((struct in6_ifaddr *)(ifa)) | #define ifa2ia6(ifa) ((struct in6_ifaddr *)(ifa)) | ||||
#define ia62ifa(ia6) (&((ia6)->ia_ifa)) | #define ia62ifa(ia6) (&((ia6)->ia_ifa)) | ||||
SYSCTL_DECL(_net_inet6_icmp6); | |||||
SYSCTL_INT(_net_inet6_icmp6, OID_AUTO, in6_llt_max_entries, | |||||
CTLFLAG_RW, &in6_llt_max_entries, 0, | |||||
"Maximum number of IPv6 neighbour entries per interface. " | |||||
"0 accept unlimited."); | |||||
void | void | ||||
in6_newaddrmsg(struct in6_ifaddr *ia, int cmd) | in6_newaddrmsg(struct in6_ifaddr *ia, int cmd) | ||||
{ | { | ||||
struct sockaddr_dl gateway; | struct sockaddr_dl gateway; | ||||
struct sockaddr_in6 mask, addr; | struct sockaddr_in6 mask, addr; | ||||
Not Done Inline ActionsI was under impression that physmem reflects the amount of physical memory in bytes (so effectively we end up with 16k for >4M). Am I missing something? Sorry for responding for that late, but would it be possible to outline the logic as a comment here? melifaro: I was under impression that `physmem` reflects the amount of physical memory in bytes (so… | |||||
struct rtentry rt; | struct rtentry rt; | ||||
int fibnum; | int fibnum; | ||||
/* | /* | ||||
* initialize for rtmsg generation | * initialize for rtmsg generation | ||||
*/ | */ | ||||
bzero(&gateway, sizeof(gateway)); | bzero(&gateway, sizeof(gateway)); | ||||
gateway.sdl_len = sizeof(gateway); | gateway.sdl_len = sizeof(gateway); | ||||
▲ Show 20 Lines • Show All 2,221 Lines • ▼ Show 20 Lines | #endif | ||||
/* Store state in rmx_weight value */ | /* Store state in rmx_weight value */ | ||||
ndpc.rtm.rtm_rmx.rmx_state = lle->ln_state; | ndpc.rtm.rtm_rmx.rmx_state = lle->ln_state; | ||||
ndpc.rtm.rtm_index = ifp->if_index; | ndpc.rtm.rtm_index = ifp->if_index; | ||||
error = SYSCTL_OUT(wr, &ndpc, sizeof(ndpc)); | error = SYSCTL_OUT(wr, &ndpc, sizeof(ndpc)); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | |||||
* We are overloading the if_llatbl base functions in order to check limits | |||||
* of maximum number of table entries. | |||||
* The functions return: 0 if the entry was (un)linked already and nothing | |||||
* changed, 1 if the entry was added/removed to/from the table, and -1 on | |||||
* error (e.g., not being able to add the entry due to limits reached). | |||||
* While the "unlink" operation should always succeed, callers of | |||||
* lltable_link_entry() need to check for errors and handle them. | |||||
*/ | |||||
static int | |||||
in6_htable_link_entry(struct lltable *llt, struct llentry *lle) | |||||
{ | |||||
int count; | |||||
if (in6_llt_max_entries > 0 && | |||||
llt->llt_entries >= in6_llt_max_entries) { | |||||
ICMP6STAT_INC(icp6s_overflownndp); | |||||
return (-1); | |||||
} | |||||
count = htable_link_entry(llt, lle); | |||||
donnerUnsubmitted Done Inline Actionscount is misleading, "added" seems enhance the casual reader's understanding. Count reads like a total value. donner: count is misleading, "added" seems enhance the casual reader's understanding. Count reads like… | |||||
if (count >= 0) | |||||
donnerUnsubmitted Done Inline ActionsEither add unconditionally or only if > 0 donner: Either add unconditionally or only if > 0
| |||||
llt->llt_entries += count; | |||||
Not Done Inline ActionsGive llt_entries has been added to the llt_table, would it be possible to move accounting to the core llt functions? Similar problem (though less severe) exists in IPv4 world as well. melifaro: Give `llt_entries` has been added to the llt_table, would it be possible to move accounting to… | |||||
Done Inline ActionsOK. What if I update the patch, move the logic into the base functions (no longer needing to have IPv6 special functions), add the maximum where I put the llt_spare spare field and make the SYSCTL a proc function which on write loops over the tables of the given protocol family and updates the table limits (I'd love to think about an improved, pro-active expiry mechanism in the future but not complicate things now in the first pass). Does that sound better? bz: OK. What if I update the patch, move the logic into the base functions (no longer needing to… | |||||
Not Done Inline ActionsCertainly, sounds awesome! melifaro: Certainly, sounds awesome! | |||||
return (count); | |||||
} | |||||
static int | |||||
in6_htable_unlink_entry(struct llentry *lle) | |||||
{ | |||||
struct lltable *llt; | |||||
int count; | |||||
llt = lle->lle_tbl; | |||||
KASSERT(llt->llt_entries > 0, ("%s: lltable %p (%s) entries %d <= 0", | |||||
__func__, llt, llt->llt_ifp->if_xname, llt->llt_entries)); | |||||
count = htable_unlink_entry(lle); | |||||
if (count >= 0) | |||||
llt->llt_entries -= count; | |||||
return (count); | |||||
} | |||||
static struct lltable * | static struct lltable * | ||||
in6_lltattach(struct ifnet *ifp) | in6_lltattach(struct ifnet *ifp) | ||||
{ | { | ||||
struct lltable *llt; | struct lltable *llt; | ||||
llt = lltable_allocate_htbl(IN6_LLTBL_DEFAULT_HSIZE); | llt = lltable_allocate_htbl(IN6_LLTBL_DEFAULT_HSIZE); | ||||
llt->llt_af = AF_INET6; | llt->llt_af = AF_INET6; | ||||
llt->llt_ifp = ifp; | llt->llt_ifp = ifp; | ||||
llt->llt_lookup = in6_lltable_lookup; | llt->llt_lookup = in6_lltable_lookup; | ||||
llt->llt_alloc_entry = in6_lltable_alloc; | llt->llt_alloc_entry = in6_lltable_alloc; | ||||
llt->llt_delete_entry = in6_lltable_delete_entry; | llt->llt_delete_entry = in6_lltable_delete_entry; | ||||
llt->llt_dump_entry = in6_lltable_dump_entry; | llt->llt_dump_entry = in6_lltable_dump_entry; | ||||
llt->llt_hash = in6_lltable_hash; | llt->llt_hash = in6_lltable_hash; | ||||
llt->llt_fill_sa_entry = in6_lltable_fill_sa_entry; | llt->llt_fill_sa_entry = in6_lltable_fill_sa_entry; | ||||
llt->llt_free_entry = in6_lltable_free_entry; | llt->llt_free_entry = in6_lltable_free_entry; | ||||
llt->llt_match_prefix = in6_lltable_match_prefix; | llt->llt_match_prefix = in6_lltable_match_prefix; | ||||
llt->llt_mark_used = in6_lltable_mark_used; | llt->llt_mark_used = in6_lltable_mark_used; | ||||
llt->llt_link_entry = in6_htable_link_entry; | |||||
llt->llt_unlink_entry = in6_htable_unlink_entry; | |||||
lltable_link(llt); | lltable_link(llt); | ||||
return (llt); | return (llt); | ||||
} | } | ||||
void * | void * | ||||
in6_domifattach(struct ifnet *ifp) | in6_domifattach(struct ifnet *ifp) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 117 Lines • Show Last 20 Lines |
2048 is only suitable for small environments. Given privacy extension and crypto addresses (i.e. SeND), only a handful nodes are sufficient to reach this limit.
In larger environment (i.e. carrier networks or university lans) the limit is easily reached directly.
So I'd like to see a limit of 16k or more for the first try to limit it from the former "unlimited".