/** * batadv_v_ogm_orig_get() - retrieve and possibly create an originator node * @bat_priv: the bat priv with all the mesh interface information * @addr: the address of the originator * * Return: the orig_node corresponding to the specified address. If such an * object does not exist, it is allocated here. In case of allocation failure * returns NULL.
*/ struct batadv_orig_node *batadv_v_ogm_orig_get(struct batadv_priv *bat_priv, const u8 *addr)
{ struct batadv_orig_node *orig_node; int hash_added;
orig_node = batadv_orig_hash_find(bat_priv, addr); if (orig_node) return orig_node;
orig_node = batadv_orig_node_new(bat_priv, addr); if (!orig_node) return NULL;
kref_get(&orig_node->refcount);
hash_added = batadv_hash_add(bat_priv->orig_hash, batadv_compare_orig,
batadv_choose_orig, orig_node,
&orig_node->hash_entry); if (hash_added != 0) { /* remove refcnt for newly created orig_node and hash entry */
batadv_orig_node_put(orig_node);
batadv_orig_node_put(orig_node);
orig_node = NULL;
}
return orig_node;
}
/** * batadv_v_ogm_start_queue_timer() - restart the OGM aggregation timer * @hard_iface: the interface to use to send the OGM
*/ staticvoid batadv_v_ogm_start_queue_timer(struct batadv_hard_iface *hard_iface)
{ unsignedint msecs = BATADV_MAX_AGGREGATION_MS * 1000;
/** * batadv_v_ogm_start_timer() - restart the OGM sending timer * @bat_priv: the bat priv with all the mesh interface information
*/ staticvoid batadv_v_ogm_start_timer(struct batadv_priv *bat_priv)
{ unsignedlong msecs; /* this function may be invoked in different contexts (ogm rescheduling * or hard_iface activation), but the work timer should not be reset
*/ if (delayed_work_pending(&bat_priv->bat_v.ogm_wq)) return;
/** * batadv_v_ogm_send_to_if() - send a batman ogm using a given interface * @skb: the OGM to send * @hard_iface: the interface to use to send the OGM
*/ staticvoid batadv_v_ogm_send_to_if(struct sk_buff *skb, struct batadv_hard_iface *hard_iface)
{ struct batadv_priv *bat_priv = netdev_priv(hard_iface->mesh_iface);
if (hard_iface->if_status != BATADV_IF_ACTIVE) {
kfree_skb(skb); return;
}
/** * batadv_v_ogm_queue_left() - check if given OGM still fits aggregation queue * @skb: the OGM to check * @hard_iface: the interface to use to send the OGM * * Caller needs to hold the hard_iface->bat_v.aggr_list.lock. * * Return: True, if the given OGMv2 packet still fits, false otherwise.
*/ staticbool batadv_v_ogm_queue_left(struct sk_buff *skb, struct batadv_hard_iface *hard_iface)
{ unsignedint max = min_t(unsignedint, hard_iface->net_dev->mtu,
BATADV_MAX_AGGREGATION_BYTES); unsignedint ogm_len = batadv_v_ogm_len(skb);
/** * batadv_v_ogm_aggr_list_free - free all elements in an aggregation queue * @hard_iface: the interface holding the aggregation queue * * Empties the OGMv2 aggregation queue and frees all the skbs it contains. * * Caller needs to hold the hard_iface->bat_v.aggr_list.lock.
*/ staticvoid batadv_v_ogm_aggr_list_free(struct batadv_hard_iface *hard_iface)
{
lockdep_assert_held(&hard_iface->bat_v.aggr_list.lock);
/** * batadv_v_ogm_aggr_send() - flush & send aggregation queue * @hard_iface: the interface with the aggregation queue to flush * * Aggregates all OGMv2 packets currently in the aggregation queue into a * single OGMv2 packet and transmits this aggregate. * * The aggregation queue is empty after this call. * * Caller needs to hold the hard_iface->bat_v.aggr_list.lock.
*/ staticvoid batadv_v_ogm_aggr_send(struct batadv_hard_iface *hard_iface)
{ unsignedint aggr_len = hard_iface->bat_v.aggr_len; struct sk_buff *skb_aggr; unsignedint ogm_len; struct sk_buff *skb;
/** * batadv_v_ogm_queue_on_if() - queue a batman ogm on a given interface * @skb: the OGM to queue * @hard_iface: the interface to queue the OGM on
*/ staticvoid batadv_v_ogm_queue_on_if(struct sk_buff *skb, struct batadv_hard_iface *hard_iface)
{ struct batadv_priv *bat_priv = netdev_priv(hard_iface->mesh_iface);
if (!atomic_read(&bat_priv->aggregated_ogms)) {
batadv_v_ogm_send_to_if(skb, hard_iface); return;
}
spin_lock_bh(&hard_iface->bat_v.aggr_list.lock); if (!batadv_v_ogm_queue_left(skb, hard_iface))
batadv_v_ogm_aggr_send(hard_iface);
/** * batadv_v_ogm_send_meshif() - periodic worker broadcasting the own OGM * @bat_priv: the bat priv with all the mesh interface information
*/ staticvoid batadv_v_ogm_send_meshif(struct batadv_priv *bat_priv)
{ struct batadv_hard_iface *hard_iface; struct batadv_ogm2_packet *ogm_packet; struct sk_buff *skb, *skb_tmp; unsignedchar *ogm_buff; struct list_head *iter; int ogm_buff_len;
u16 tvlv_len = 0; int ret;
if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING) goto out;
ogm_buff = bat_priv->bat_v.ogm_buff;
ogm_buff_len = bat_priv->bat_v.ogm_buff_len; /* tt changes have to be committed before the tvlv data is * appended as it may alter the tt tvlv container
*/
batadv_tt_local_commit_changes(bat_priv);
tvlv_len = batadv_tvlv_container_ogm_append(bat_priv, &ogm_buff,
&ogm_buff_len,
BATADV_OGM2_HLEN);
/* broadcast on every interface */
rcu_read_lock();
netdev_for_each_lower_private_rcu(bat_priv->mesh_iface, hard_iface, iter) { if (!kref_get_unless_zero(&hard_iface->refcount)) continue;
ret = batadv_hardif_no_broadcast(hard_iface, NULL, NULL); if (ret) { char *type;
switch (ret) { case BATADV_HARDIF_BCAST_NORECIPIENT:
type = "no neighbor"; break; case BATADV_HARDIF_BCAST_DUPFWD:
type = "single neighbor is source"; break; case BATADV_HARDIF_BCAST_DUPORIG:
type = "single neighbor is originator"; break; default:
type = "unknown";
}
batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "OGM2 from ourselves on %s suppressed: %s\n",
hard_iface->net_dev->name, type);
/** * batadv_v_ogm_iface_enable() - prepare an interface for B.A.T.M.A.N. V * @hard_iface: the interface to prepare * * Takes care of scheduling its own OGM sending routine for this interface. * * Return: 0 on success or a negative error code otherwise
*/ int batadv_v_ogm_iface_enable(struct batadv_hard_iface *hard_iface)
{ struct batadv_priv *bat_priv = netdev_priv(hard_iface->mesh_iface);
/** * batadv_v_ogm_iface_disable() - release OGM interface private resources * @hard_iface: interface for which the resources have to be released
*/ void batadv_v_ogm_iface_disable(struct batadv_hard_iface *hard_iface)
{
cancel_delayed_work_sync(&hard_iface->bat_v.aggr_wq);
/** * batadv_v_forward_penalty() - apply a penalty to the throughput metric * forwarded with B.A.T.M.A.N. V OGMs * @bat_priv: the bat priv with all the mesh interface information * @if_incoming: the interface where the OGM has been received * @if_outgoing: the interface where the OGM has to be forwarded to * @throughput: the current throughput * * Apply a penalty on the current throughput metric value based on the * characteristic of the interface where the OGM has been received. * * Initially the per hardif hop penalty is applied to the throughput. After * that the return value is then computed as follows: * - throughput * 50% if the incoming and outgoing interface are the * same WiFi interface and the throughput is above * 1MBit/s * - throughput if the outgoing interface is the default * interface (i.e. this OGM is processed for the * internal table and not forwarded) * - throughput * node hop penalty otherwise * * Return: the penalised throughput metric.
*/ static u32 batadv_v_forward_penalty(struct batadv_priv *bat_priv, struct batadv_hard_iface *if_incoming, struct batadv_hard_iface *if_outgoing,
u32 throughput)
{ int if_hop_penalty = atomic_read(&if_incoming->hop_penalty); int hop_penalty = atomic_read(&bat_priv->hop_penalty); int hop_penalty_max = BATADV_TQ_MAX_VALUE;
/* Apply per hardif hop penalty */
throughput = throughput * (hop_penalty_max - if_hop_penalty) /
hop_penalty_max;
/* Don't apply hop penalty in default originator table. */ if (if_outgoing == BATADV_IF_DEFAULT) return throughput;
/* Forwarding on the same WiFi interface cuts the throughput in half * due to the store & forward characteristics of WIFI. * Very low throughput values are the exception.
*/ if (throughput > 10 &&
if_incoming == if_outgoing &&
!(if_incoming->bat_v.flags & BATADV_FULL_DUPLEX)) return throughput / 2;
/* hop penalty of 255 equals 100% */ return throughput * (hop_penalty_max - hop_penalty) / hop_penalty_max;
}
/** * batadv_v_ogm_forward() - check conditions and forward an OGM to the given * outgoing interface * @bat_priv: the bat priv with all the mesh interface information * @ogm_received: previously received OGM to be forwarded * @orig_node: the originator which has been updated * @neigh_node: the neigh_node through with the OGM has been received * @if_incoming: the interface on which this OGM was received on * @if_outgoing: the interface to which the OGM has to be forwarded to * * Forward an OGM to an interface after having altered the throughput metric and * the TTL value contained in it. The original OGM isn't modified.
*/ staticvoid batadv_v_ogm_forward(struct batadv_priv *bat_priv, conststruct batadv_ogm2_packet *ogm_received, struct batadv_orig_node *orig_node, struct batadv_neigh_node *neigh_node, struct batadv_hard_iface *if_incoming, struct batadv_hard_iface *if_outgoing)
{ struct batadv_neigh_ifinfo *neigh_ifinfo = NULL; struct batadv_orig_ifinfo *orig_ifinfo = NULL; struct batadv_neigh_node *router = NULL; struct batadv_ogm2_packet *ogm_forward; unsignedchar *skb_buff; struct sk_buff *skb;
size_t packet_len;
u16 tvlv_len;
/* only forward for specific interfaces, not for the default one. */ if (if_outgoing == BATADV_IF_DEFAULT) goto out;
orig_ifinfo = batadv_orig_ifinfo_new(orig_node, if_outgoing); if (!orig_ifinfo) goto out;
/** * batadv_v_ogm_metric_update() - update route metric based on OGM * @bat_priv: the bat priv with all the mesh interface information * @ogm2: OGM2 structure * @orig_node: Originator structure for which the OGM has been received * @neigh_node: the neigh_node through with the OGM has been received * @if_incoming: the interface where this packet was received * @if_outgoing: the interface for which the packet should be considered * * Return: * 1 if the OGM is new, * 0 if it is not new but valid, * <0 on error (e.g. old OGM)
*/ staticint batadv_v_ogm_metric_update(struct batadv_priv *bat_priv, conststruct batadv_ogm2_packet *ogm2, struct batadv_orig_node *orig_node, struct batadv_neigh_node *neigh_node, struct batadv_hard_iface *if_incoming, struct batadv_hard_iface *if_outgoing)
{ struct batadv_orig_ifinfo *orig_ifinfo; struct batadv_neigh_ifinfo *neigh_ifinfo = NULL; bool protection_started = false; int ret = -EINVAL;
u32 path_throughput;
s32 seq_diff;
orig_ifinfo = batadv_orig_ifinfo_new(orig_node, if_outgoing); if (!orig_ifinfo) goto out;
if (!hlist_empty(&orig_node->neigh_list) &&
batadv_window_protected(bat_priv, seq_diff,
BATADV_OGM_MAX_AGE,
&orig_ifinfo->batman_seqno_reset,
&protection_started)) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "Drop packet: packet within window protection time from %pM\n",
ogm2->orig);
batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "Last reset: %ld, %ld\n",
orig_ifinfo->batman_seqno_reset, jiffies); goto out;
}
/* drop packets with old seqnos, however accept the first packet after * a host has been rebooted.
*/ if (seq_diff < 0 && !protection_started) goto out;
if (seq_diff > 0 || protection_started)
ret = 1; else
ret = 0;
out:
batadv_orig_ifinfo_put(orig_ifinfo);
batadv_neigh_ifinfo_put(neigh_ifinfo);
return ret;
}
/** * batadv_v_ogm_route_update() - update routes based on OGM * @bat_priv: the bat priv with all the mesh interface information * @ethhdr: the Ethernet header of the OGM2 * @ogm2: OGM2 structure * @orig_node: Originator structure for which the OGM has been received * @neigh_node: the neigh_node through with the OGM has been received * @if_incoming: the interface where this packet was received * @if_outgoing: the interface for which the packet should be considered * * Return: true if the packet should be forwarded, false otherwise
*/ staticbool batadv_v_ogm_route_update(struct batadv_priv *bat_priv, conststruct ethhdr *ethhdr, conststruct batadv_ogm2_packet *ogm2, struct batadv_orig_node *orig_node, struct batadv_neigh_node *neigh_node, struct batadv_hard_iface *if_incoming, struct batadv_hard_iface *if_outgoing)
{ struct batadv_neigh_node *router = NULL; struct batadv_orig_node *orig_neigh_node; struct batadv_neigh_node *orig_neigh_router = NULL; struct batadv_neigh_ifinfo *router_ifinfo = NULL, *neigh_ifinfo = NULL;
u32 router_throughput, neigh_throughput;
u32 router_last_seqno;
u32 neigh_last_seqno;
s32 neigh_seq_diff; bool forward = false;
orig_neigh_node = batadv_v_ogm_orig_get(bat_priv, ethhdr->h_source); if (!orig_neigh_node) goto out;
/* drop packet if sender is not a direct neighbor and if we * don't route towards it
*/
router = batadv_orig_router_get(orig_node, if_outgoing); if (router && router->orig_node != orig_node && !orig_neigh_router) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "Drop packet: OGM via unknown neighbor!\n"); goto out;
}
/* Mark the OGM to be considered for forwarding, and update routes * if needed.
*/
forward = true;
batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "Searching and updating originator entry of received packet\n");
/* if this neighbor already is our next hop there is nothing * to change
*/ if (router == neigh_node) goto out;
/* don't consider neighbours with worse throughput. * also switch route if this seqno is BATADV_V_MAX_ORIGDIFF newer than * the last received seqno from our best next hop.
*/ if (router) {
router_ifinfo = batadv_neigh_ifinfo_get(router, if_outgoing);
neigh_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing);
/* if these are not allocated, something is wrong. */ if (!router_ifinfo || !neigh_ifinfo) goto out;
/** * batadv_v_ogm_process_per_outif() - process a batman v OGM for an outgoing if * @bat_priv: the bat priv with all the mesh interface information * @ethhdr: the Ethernet header of the OGM2 * @ogm2: OGM2 structure * @orig_node: Originator structure for which the OGM has been received * @neigh_node: the neigh_node through with the OGM has been received * @if_incoming: the interface where this packet was received * @if_outgoing: the interface for which the packet should be considered
*/ staticvoid
batadv_v_ogm_process_per_outif(struct batadv_priv *bat_priv, conststruct ethhdr *ethhdr, conststruct batadv_ogm2_packet *ogm2, struct batadv_orig_node *orig_node, struct batadv_neigh_node *neigh_node, struct batadv_hard_iface *if_incoming, struct batadv_hard_iface *if_outgoing)
{ int seqno_age; bool forward;
/* first, update the metric with according sanity checks */
seqno_age = batadv_v_ogm_metric_update(bat_priv, ogm2, orig_node,
neigh_node, if_incoming,
if_outgoing);
/* outdated sequence numbers are to be discarded */ if (seqno_age < 0) return;
/* only unknown & newer OGMs contain TVLVs we are interested in */ if (seqno_age > 0 && if_outgoing == BATADV_IF_DEFAULT)
batadv_tvlv_containers_process(bat_priv, BATADV_OGM2, orig_node,
NULL,
(unsignedchar *)(ogm2 + 1),
ntohs(ogm2->tvlv_len));
/* if the metric update went through, update routes if needed */
forward = batadv_v_ogm_route_update(bat_priv, ethhdr, ogm2, orig_node,
neigh_node, if_incoming,
if_outgoing);
/* if the routes have been processed correctly, check and forward */ if (forward)
batadv_v_ogm_forward(bat_priv, ogm2, orig_node, neigh_node,
if_incoming, if_outgoing);
}
/** * batadv_v_ogm_aggr_packet() - checks if there is another OGM aggregated * @buff_pos: current position in the skb * @packet_len: total length of the skb * @ogm2_packet: potential OGM2 in buffer * * Return: true if there is enough space for another OGM, false otherwise.
*/ staticbool
batadv_v_ogm_aggr_packet(int buff_pos, int packet_len, conststruct batadv_ogm2_packet *ogm2_packet)
{ int next_buff_pos = 0;
/* check if there is enough space for the header */
next_buff_pos += buff_pos + sizeof(*ogm2_packet); if (next_buff_pos > packet_len) returnfalse;
/* check if there is enough space for the optional TVLV */
next_buff_pos += ntohs(ogm2_packet->tvlv_len);
return next_buff_pos <= packet_len;
}
/** * batadv_v_ogm_process() - process an incoming batman v OGM * @skb: the skb containing the OGM * @ogm_offset: offset to the OGM which should be processed (for aggregates) * @if_incoming: the interface where this packet was received
*/ staticvoid batadv_v_ogm_process(conststruct sk_buff *skb, int ogm_offset, struct batadv_hard_iface *if_incoming)
{ struct batadv_priv *bat_priv = netdev_priv(if_incoming->mesh_iface); struct ethhdr *ethhdr; struct batadv_orig_node *orig_node = NULL; struct batadv_hardif_neigh_node *hardif_neigh = NULL; struct batadv_neigh_node *neigh_node = NULL; struct batadv_hard_iface *hard_iface; struct batadv_ogm2_packet *ogm_packet;
u32 ogm_throughput, link_throughput, path_throughput; struct list_head *iter; int ret;
if (batadv_is_my_mac(bat_priv, ogm_packet->orig)) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "Drop packet: originator packet from ourself\n"); return;
}
/* If the throughput metric is 0, immediately drop the packet. No need * to create orig_node / neigh_node for an unusable route.
*/ if (ogm_throughput == 0) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "Drop packet: originator packet with throughput metric of 0\n"); return;
}
/* require ELP packets be to received from this neighbor first */
hardif_neigh = batadv_hardif_neigh_get(if_incoming, ethhdr->h_source); if (!hardif_neigh) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "Drop packet: OGM via unknown neighbor!\n"); goto out;
}
orig_node = batadv_v_ogm_orig_get(bat_priv, ogm_packet->orig); if (!orig_node) goto out;
neigh_node = batadv_neigh_node_get_or_create(orig_node, if_incoming,
ethhdr->h_source); if (!neigh_node) goto out;
/* Update the received throughput metric to match the link * characteristic: * - If this OGM traveled one hop so far (emitted by single hop * neighbor) the path throughput metric equals the link throughput. * - For OGMs traversing more than hop the path throughput metric is * the smaller of the path throughput and the link throughput.
*/
link_throughput = ewma_throughput_read(&hardif_neigh->bat_v.throughput);
path_throughput = min_t(u32, link_throughput, ogm_throughput);
ogm_packet->throughput = htonl(path_throughput);
rcu_read_lock();
netdev_for_each_lower_private_rcu(bat_priv->mesh_iface, hard_iface, iter) { if (hard_iface->if_status != BATADV_IF_ACTIVE) continue;
if (!kref_get_unless_zero(&hard_iface->refcount)) continue;
ret = batadv_hardif_no_broadcast(hard_iface,
ogm_packet->orig,
hardif_neigh->orig);
if (ret) { char *type;
switch (ret) { case BATADV_HARDIF_BCAST_NORECIPIENT:
type = "no neighbor"; break; case BATADV_HARDIF_BCAST_DUPFWD:
type = "single neighbor is source"; break; case BATADV_HARDIF_BCAST_DUPORIG:
type = "single neighbor is originator"; break; default:
type = "unknown";
}
batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "OGM2 packet from %pM on %s suppressed: %s\n",
ogm_packet->orig, hard_iface->net_dev->name,
type);
/** * batadv_v_ogm_packet_recv() - OGM2 receiving handler * @skb: the received OGM * @if_incoming: the interface where this OGM has been received * * Return: NET_RX_SUCCESS and consume the skb on success or returns NET_RX_DROP * (without freeing the skb) on failure
*/ int batadv_v_ogm_packet_recv(struct sk_buff *skb, struct batadv_hard_iface *if_incoming)
{ struct batadv_priv *bat_priv = netdev_priv(if_incoming->mesh_iface); struct batadv_ogm2_packet *ogm_packet; struct ethhdr *ethhdr; int ogm_offset;
u8 *packet_pos; int ret = NET_RX_DROP;
/* did we receive a OGM2 packet on an interface that does not have * B.A.T.M.A.N. V enabled ?
*/ if (strcmp(bat_priv->algo_ops->name, "BATMAN_V") != 0) goto free_skb;
if (!batadv_check_management_packet(skb, if_incoming, BATADV_OGM2_HLEN)) goto free_skb;
ethhdr = eth_hdr(skb); if (batadv_is_my_mac(bat_priv, ethhdr->h_source)) goto free_skb;
free_skb: if (ret == NET_RX_SUCCESS)
consume_skb(skb); else
kfree_skb(skb);
return ret;
}
/** * batadv_v_ogm_init() - initialise the OGM2 engine * @bat_priv: the bat priv with all the mesh interface information * * Return: 0 on success or a negative error code in case of failure
*/ int batadv_v_ogm_init(struct batadv_priv *bat_priv)
{ struct batadv_ogm2_packet *ogm_packet; unsignedchar *ogm_buff;
u32 random_seqno;
/** * batadv_v_ogm_free() - free OGM private resources * @bat_priv: the bat priv with all the mesh interface information
*/ void batadv_v_ogm_free(struct batadv_priv *bat_priv)
{
cancel_delayed_work_sync(&bat_priv->bat_v.ogm_wq);
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.29Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.