Changeset View
Changeset View
Standalone View
Standalone View
sys/netgraph/ng_bridge.c
Show First 20 Lines • Show All 128 Lines • ▼ Show 20 Lines | struct ng_bridge_private { | ||||
unsigned int persistent : 1, /* can exist w/o hooks */ | unsigned int persistent : 1, /* can exist w/o hooks */ | ||||
sendUnknown : 1;/* links receive unknowns by default */ | sendUnknown : 1;/* links receive unknowns by default */ | ||||
struct callout timer; /* one second periodic timer */ | struct callout timer; /* one second periodic timer */ | ||||
}; | }; | ||||
typedef struct ng_bridge_private *priv_p; | typedef struct ng_bridge_private *priv_p; | ||||
typedef struct ng_bridge_private const *priv_cp; /* read only access */ | typedef struct ng_bridge_private const *priv_cp; /* read only access */ | ||||
/* Information about a host, stored in a hash table entry */ | /* Information about a host, stored in a hash table entry */ | ||||
struct ng_bridge_hent { | struct ng_bridge_host { | ||||
struct ng_bridge_host host; /* actual host info */ | u_char addr[6]; /* ethernet address */ | ||||
kp: ETHER_ADDR_LEN | |||||
Done Inline ActionsYes, you are right. But not as as part of this change, please. donner: Yes, you are right. But not as as part of this change, please.
Fixing this old code is a long… | |||||
SLIST_ENTRY(ng_bridge_hent) next; /* next entry in bucket */ | link_p link; /* link where addr can be found */ | ||||
u_int16_t age; /* seconds ago entry was created */ | |||||
Done Inline ActionsThat tops out at 18 hours or so. Is that enough? kp: That tops out at 18 hours or so. Is that enough?
It may be better to use u_int32_t here. | |||||
Done Inline ActionsThis is existing code and there is a code path to prevent an overflow of this value. There is no benefit in any longer time frame. The interesting interval is about 10 to 300 seconds. Anything longer is only for eye candy. donner: This is existing code and there is a code path to prevent an overflow of this value. There is… | |||||
u_int16_t staleness; /* seconds ago host last heard from */ | |||||
SLIST_ENTRY(ng_bridge_host) next; /* next entry in bucket */ | |||||
}; | }; | ||||
/* Hash table bucket declaration */ | /* Hash table bucket declaration */ | ||||
SLIST_HEAD(ng_bridge_bucket, ng_bridge_hent); | SLIST_HEAD(ng_bridge_bucket, ng_bridge_host); | ||||
/* Netgraph node methods */ | /* Netgraph node methods */ | ||||
static ng_constructor_t ng_bridge_constructor; | static ng_constructor_t ng_bridge_constructor; | ||||
static ng_rcvmsg_t ng_bridge_rcvmsg; | static ng_rcvmsg_t ng_bridge_rcvmsg; | ||||
static ng_shutdown_t ng_bridge_shutdown; | static ng_shutdown_t ng_bridge_shutdown; | ||||
static ng_newhook_t ng_bridge_newhook; | static ng_newhook_t ng_bridge_newhook; | ||||
static ng_rcvdata_t ng_bridge_rcvdata; | static ng_rcvdata_t ng_bridge_rcvdata; | ||||
static ng_disconnect_t ng_bridge_disconnect; | static ng_disconnect_t ng_bridge_disconnect; | ||||
▲ Show 20 Lines • Show All 410 Lines • ▼ Show 20 Lines | #undef FETCH | ||||
} | } | ||||
if (msg->header.cmd != NGM_BRIDGE_GET_STATS) | if (msg->header.cmd != NGM_BRIDGE_GET_STATS) | ||||
ng_bridge_clear_link_stats(&link->stats); | ng_bridge_clear_link_stats(&link->stats); | ||||
break; | break; | ||||
} | } | ||||
case NGM_BRIDGE_GET_TABLE: | case NGM_BRIDGE_GET_TABLE: | ||||
{ | { | ||||
struct ng_bridge_host_ary *ary; | struct ng_bridge_host_ary *ary; | ||||
struct ng_bridge_hent *hent; | struct ng_bridge_host *host; | ||||
int i = 0, bucket; | int i = 0, bucket; | ||||
NG_MKRESPONSE(resp, msg, sizeof(*ary) | NG_MKRESPONSE(resp, msg, sizeof(*ary) | ||||
+ (priv->numHosts * sizeof(*ary->hosts)), M_NOWAIT); | + (priv->numHosts * sizeof(*ary->hosts)), M_NOWAIT); | ||||
if (resp == NULL) { | if (resp == NULL) { | ||||
error = ENOMEM; | error = ENOMEM; | ||||
break; | break; | ||||
} | } | ||||
ary = (struct ng_bridge_host_ary *)resp->data; | ary = (struct ng_bridge_host_ary *)resp->data; | ||||
ary->numHosts = priv->numHosts; | ary->numHosts = priv->numHosts; | ||||
for (bucket = 0; bucket < priv->numBuckets; bucket++) { | for (bucket = 0; bucket < priv->numBuckets; bucket++) { | ||||
SLIST_FOREACH(hent, &priv->tab[bucket], next) { | SLIST_FOREACH(host, &priv->tab[bucket], next) { | ||||
memcpy(ary->hosts[i].addr, | memcpy(ary->hosts[i].addr, | ||||
hent->host.addr, | host->addr, | ||||
sizeof(ary->hosts[i].addr)); | sizeof(ary->hosts[i].addr)); | ||||
ary->hosts[i].age = hent->host.age; | ary->hosts[i].age = host->age; | ||||
ary->hosts[i].staleness = hent->host.staleness; | ary->hosts[i].staleness = host->staleness; | ||||
strncpy(ary->hosts[i].hook, | strncpy(ary->hosts[i].hook, | ||||
NG_HOOK_NAME(hent->host.link->hook), | NG_HOOK_NAME(host->link->hook), | ||||
sizeof(ary->hosts[i].hook)); | sizeof(ary->hosts[i].hook)); | ||||
i++; | i++; | ||||
} | } | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
case NGM_BRIDGE_SET_PERSISTENT: | case NGM_BRIDGE_SET_PERSISTENT: | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 322 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Find a host entry in the table. | * Find a host entry in the table. | ||||
*/ | */ | ||||
static struct ng_bridge_host * | static struct ng_bridge_host * | ||||
ng_bridge_get(priv_cp priv, const u_char *addr) | ng_bridge_get(priv_cp priv, const u_char *addr) | ||||
{ | { | ||||
const int bucket = HASH(addr, priv->hashMask); | const int bucket = HASH(addr, priv->hashMask); | ||||
struct ng_bridge_hent *hent; | struct ng_bridge_host *host; | ||||
SLIST_FOREACH(hent, &priv->tab[bucket], next) { | SLIST_FOREACH(host, &priv->tab[bucket], next) { | ||||
if (ETHER_EQUAL(hent->host.addr, addr)) | if (ETHER_EQUAL(host->addr, addr)) | ||||
return (&hent->host); | return (host); | ||||
} | } | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
/* | /* | ||||
* Add a new host entry to the table. This assumes the host doesn't | * Add a new host entry to the table. This assumes the host doesn't | ||||
* already exist in the table. Returns 1 on success, 0 if there | * already exist in the table. Returns 1 on success, 0 if there | ||||
* was a memory allocation failure. | * was a memory allocation failure. | ||||
*/ | */ | ||||
static int | static int | ||||
ng_bridge_put(priv_p priv, const u_char *addr, link_p link) | ng_bridge_put(priv_p priv, const u_char *addr, link_p link) | ||||
{ | { | ||||
const int bucket = HASH(addr, priv->hashMask); | const int bucket = HASH(addr, priv->hashMask); | ||||
struct ng_bridge_hent *hent; | struct ng_bridge_host *host; | ||||
#ifdef INVARIANTS | #ifdef INVARIANTS | ||||
/* Assert that entry does not already exist in hashtable */ | /* Assert that entry does not already exist in hashtable */ | ||||
SLIST_FOREACH(hent, &priv->tab[bucket], next) { | SLIST_FOREACH(host, &priv->tab[bucket], next) { | ||||
KASSERT(!ETHER_EQUAL(hent->host.addr, addr), | KASSERT(!ETHER_EQUAL(host->addr, addr), | ||||
("%s: entry %6D exists in table", __func__, addr, ":")); | ("%s: entry %6D exists in table", __func__, addr, ":")); | ||||
} | } | ||||
#endif | #endif | ||||
/* Allocate and initialize new hashtable entry */ | /* Allocate and initialize new hashtable entry */ | ||||
hent = malloc(sizeof(*hent), M_NETGRAPH_BRIDGE, M_NOWAIT); | host = malloc(sizeof(*host), M_NETGRAPH_BRIDGE, M_NOWAIT); | ||||
if (hent == NULL) | if (host == NULL) | ||||
return (0); | return (0); | ||||
bcopy(addr, hent->host.addr, ETHER_ADDR_LEN); | bcopy(addr, host->addr, ETHER_ADDR_LEN); | ||||
hent->host.link = link; | host->link = link; | ||||
hent->host.staleness = 0; | host->staleness = 0; | ||||
hent->host.age = 0; | host->age = 0; | ||||
/* Add new element to hash bucket */ | /* Add new element to hash bucket */ | ||||
SLIST_INSERT_HEAD(&priv->tab[bucket], hent, next); | SLIST_INSERT_HEAD(&priv->tab[bucket], host, next); | ||||
priv->numHosts++; | priv->numHosts++; | ||||
/* Resize table if necessary */ | /* Resize table if necessary */ | ||||
ng_bridge_rehash(priv); | ng_bridge_rehash(priv); | ||||
return (1); | return (1); | ||||
} | } | ||||
/* | /* | ||||
Show All 28 Lines | ng_bridge_rehash(priv_p priv) | ||||
if (newTab == NULL) | if (newTab == NULL) | ||||
return; | return; | ||||
/* Move all entries from old table to new table */ | /* Move all entries from old table to new table */ | ||||
for (oldBucket = 0; oldBucket < priv->numBuckets; oldBucket++) { | for (oldBucket = 0; oldBucket < priv->numBuckets; oldBucket++) { | ||||
struct ng_bridge_bucket *const oldList = &priv->tab[oldBucket]; | struct ng_bridge_bucket *const oldList = &priv->tab[oldBucket]; | ||||
while (!SLIST_EMPTY(oldList)) { | while (!SLIST_EMPTY(oldList)) { | ||||
struct ng_bridge_hent *const hent | struct ng_bridge_host *const host | ||||
= SLIST_FIRST(oldList); | = SLIST_FIRST(oldList); | ||||
SLIST_REMOVE_HEAD(oldList, next); | SLIST_REMOVE_HEAD(oldList, next); | ||||
newBucket = HASH(hent->host.addr, newMask); | newBucket = HASH(host->addr, newMask); | ||||
SLIST_INSERT_HEAD(&newTab[newBucket], hent, next); | SLIST_INSERT_HEAD(&newTab[newBucket], host, next); | ||||
} | } | ||||
} | } | ||||
/* Replace old table with new one */ | /* Replace old table with new one */ | ||||
if (priv->conf.debugLevel >= 3) { | if (priv->conf.debugLevel >= 3) { | ||||
log(LOG_INFO, "ng_bridge: %s: table size %d -> %d\n", | log(LOG_INFO, "ng_bridge: %s: table size %d -> %d\n", | ||||
ng_bridge_nodename(priv->node), | ng_bridge_nodename(priv->node), | ||||
priv->numBuckets, newNumBuckets); | priv->numBuckets, newNumBuckets); | ||||
Show All 14 Lines | |||||
* If linkNum == -1, then remove all hosts in the table. | * If linkNum == -1, then remove all hosts in the table. | ||||
*/ | */ | ||||
static void | static void | ||||
ng_bridge_remove_hosts(priv_p priv, link_p link) | ng_bridge_remove_hosts(priv_p priv, link_p link) | ||||
{ | { | ||||
int bucket; | int bucket; | ||||
for (bucket = 0; bucket < priv->numBuckets; bucket++) { | for (bucket = 0; bucket < priv->numBuckets; bucket++) { | ||||
struct ng_bridge_hent **hptr = &SLIST_FIRST(&priv->tab[bucket]); | struct ng_bridge_host **hptr = &SLIST_FIRST(&priv->tab[bucket]); | ||||
while (*hptr != NULL) { | while (*hptr != NULL) { | ||||
struct ng_bridge_hent *const hent = *hptr; | struct ng_bridge_host *const host = *hptr; | ||||
if (link == NULL || hent->host.link == link) { | if (link == NULL || host->link == link) { | ||||
*hptr = SLIST_NEXT(hent, next); | *hptr = SLIST_NEXT(host, next); | ||||
free(hent, M_NETGRAPH_BRIDGE); | free(host, M_NETGRAPH_BRIDGE); | ||||
priv->numHosts--; | priv->numHosts--; | ||||
} else | } else | ||||
hptr = &SLIST_NEXT(hent, next); | hptr = &SLIST_NEXT(host, next); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Handle our once-per-second timeout event. We do two things: | * Handle our once-per-second timeout event. We do two things: | ||||
* we decrement link->loopCount for those links being muted due to | * we decrement link->loopCount for those links being muted due to | ||||
* a detected loopback condition, and we remove any hosts from | * a detected loopback condition, and we remove any hosts from | ||||
Show All 24 Lines | |||||
{ | { | ||||
const priv_p priv = NG_NODE_PRIVATE(node); | const priv_p priv = NG_NODE_PRIVATE(node); | ||||
int bucket; | int bucket; | ||||
int counter = 0; | int counter = 0; | ||||
hook_p ret; | hook_p ret; | ||||
/* Update host time counters and remove stale entries */ | /* Update host time counters and remove stale entries */ | ||||
for (bucket = 0; bucket < priv->numBuckets; bucket++) { | for (bucket = 0; bucket < priv->numBuckets; bucket++) { | ||||
struct ng_bridge_hent **hptr = &SLIST_FIRST(&priv->tab[bucket]); | struct ng_bridge_host **hptr = &SLIST_FIRST(&priv->tab[bucket]); | ||||
while (*hptr != NULL) { | while (*hptr != NULL) { | ||||
struct ng_bridge_hent *const hent = *hptr; | struct ng_bridge_host *const host = *hptr; | ||||
/* Remove hosts we haven't heard from in a while */ | /* Remove hosts we haven't heard from in a while */ | ||||
if (++hent->host.staleness >= priv->conf.maxStaleness) { | if (++host->staleness >= priv->conf.maxStaleness) { | ||||
*hptr = SLIST_NEXT(hent, next); | *hptr = SLIST_NEXT(host, next); | ||||
free(hent, M_NETGRAPH_BRIDGE); | free(host, M_NETGRAPH_BRIDGE); | ||||
priv->numHosts--; | priv->numHosts--; | ||||
} else { | } else { | ||||
if (hent->host.age < 0xffff) | if (host->age < 0xffff) | ||||
hent->host.age++; | host->age++; | ||||
hptr = &SLIST_NEXT(hent, next); | hptr = &SLIST_NEXT(host, next); | ||||
counter++; | counter++; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
KASSERT(priv->numHosts == counter, | KASSERT(priv->numHosts == counter, | ||||
("%s: hosts: %d != %d", __func__, priv->numHosts, counter)); | ("%s: hosts: %d != %d", __func__, priv->numHosts, counter)); | ||||
/* Decrease table size if necessary */ | /* Decrease table size if necessary */ | ||||
Show All 26 Lines |
ETHER_ADDR_LEN