gateway_client.c 13.5 KB
Newer Older
1
/*
2
 * Copyright (C) 2009-2011 B.A.T.M.A.N. contributors:
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 *
 * Marek Lindner
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of version 2 of the GNU General Public
 * License as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA
 *
 */

#include "main.h"
#include "gateway_client.h"
#include "gateway_common.h"
#include "hard-interface.h"
26
#include "originator.h"
27 28 29 30 31
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/udp.h>
#include <linux/if_vlan.h>

32
static void gw_node_free_ref(struct gw_node *gw_node)
33
{
34
	if (atomic_dec_and_test(&gw_node->refcount))
35
		kfree_rcu(gw_node, rcu);
36 37
}

38
static struct gw_node *gw_get_selected_gw_node(struct bat_priv *bat_priv)
39
{
40
	struct gw_node *gw_node;
41

42
	rcu_read_lock();
43 44
	gw_node = rcu_dereference(bat_priv->curr_gw);
	if (!gw_node)
45
		goto out;
46

47 48
	if (!atomic_inc_not_zero(&gw_node->refcount))
		gw_node = NULL;
49

50 51
out:
	rcu_read_unlock();
52
	return gw_node;
53 54
}

55
struct orig_node *gw_get_selected_orig(struct bat_priv *bat_priv)
56
{
57
	struct gw_node *gw_node;
58
	struct orig_node *orig_node = NULL;
59

60 61 62 63 64 65 66 67 68 69 70
	gw_node = gw_get_selected_gw_node(bat_priv);
	if (!gw_node)
		goto out;

	rcu_read_lock();
	orig_node = gw_node->orig_node;
	if (!orig_node)
		goto unlock;

	if (!atomic_inc_not_zero(&orig_node->refcount))
		orig_node = NULL;
71

72 73 74
unlock:
	rcu_read_unlock();
out:
75
	if (gw_node)
76
		gw_node_free_ref(gw_node);
77
	return orig_node;
78 79
}

80
static void gw_select(struct bat_priv *bat_priv, struct gw_node *new_gw_node)
81
{
82
	struct gw_node *curr_gw_node;
83

84 85
	spin_lock_bh(&bat_priv->gw_list_lock);

86 87
	if (new_gw_node && !atomic_inc_not_zero(&new_gw_node->refcount))
		new_gw_node = NULL;
88

89
	curr_gw_node = bat_priv->curr_gw;
90
	rcu_assign_pointer(bat_priv->curr_gw, new_gw_node);
91 92 93

	if (curr_gw_node)
		gw_node_free_ref(curr_gw_node);
94 95 96 97 98 99 100

	spin_unlock_bh(&bat_priv->gw_list_lock);
}

void gw_deselect(struct bat_priv *bat_priv)
{
	gw_select(bat_priv, NULL);
101 102 103 104 105
}

void gw_election(struct bat_priv *bat_priv)
{
	struct hlist_node *node;
106
	struct gw_node *gw_node, *curr_gw = NULL, *curr_gw_tmp = NULL;
107
	struct neigh_node *router;
108 109 110 111 112 113 114 115 116 117 118 119 120
	uint8_t max_tq = 0;
	uint32_t max_gw_factor = 0, tmp_gw_factor = 0;
	int down, up;

	/**
	 * The batman daemon checks here if we already passed a full originator
	 * cycle in order to make sure we don't choose the first gateway we
	 * hear about. This check is based on the daemon's uptime which we
	 * don't have.
	 **/
	if (atomic_read(&bat_priv->gw_mode) != GW_MODE_CLIENT)
		return;

121
	curr_gw = gw_get_selected_gw_node(bat_priv);
122
	if (curr_gw)
123
		goto out;
124

125
	rcu_read_lock();
126
	if (hlist_empty(&bat_priv->gw_list)) {
127 128 129 130 131
		bat_dbg(DBG_BATMAN, bat_priv,
			"Removing selected gateway - "
			"no gateway in range\n");
		gw_deselect(bat_priv);
		goto unlock;
132 133 134
	}

	hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) {
135
		if (gw_node->deleted)
136 137
			continue;

138 139
		router = orig_node_get_router(gw_node->orig_node);
		if (!router)
140 141 142 143 144 145 146
			continue;

		switch (atomic_read(&bat_priv->gw_sel_class)) {
		case 1: /* fast connection */
			gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags,
					     &down, &up);

147
			tmp_gw_factor = (router->tq_avg * router->tq_avg *
148 149 150 151 152 153
					 down * 100 * 100) /
					 (TQ_LOCAL_WINDOW_SIZE *
					 TQ_LOCAL_WINDOW_SIZE * 64);

			if ((tmp_gw_factor > max_gw_factor) ||
			    ((tmp_gw_factor == max_gw_factor) &&
154
			     (router->tq_avg > max_tq)))
155 156 157 158 159 160 161 162 163 164 165
				curr_gw_tmp = gw_node;
			break;

		default: /**
			  * 2:  stable connection (use best statistic)
			  * 3:  fast-switch (use best statistic but change as
			  *     soon as a better gateway appears)
			  * XX: late-switch (use best statistic but change as
			  *     soon as a better gateway appears which has
			  *     $routing_class more tq points)
			  **/
166
			if (router->tq_avg > max_tq)
167 168 169 170
				curr_gw_tmp = gw_node;
			break;
		}

171 172
		if (router->tq_avg > max_tq)
			max_tq = router->tq_avg;
173 174 175

		if (tmp_gw_factor > max_gw_factor)
			max_gw_factor = tmp_gw_factor;
176 177

		neigh_node_free_ref(router);
178 179
	}

180
	if (curr_gw != curr_gw_tmp) {
181 182
		router = orig_node_get_router(curr_gw_tmp->orig_node);
		if (!router)
183
			goto unlock;
184

185
		if ((curr_gw) && (!curr_gw_tmp))
186 187 188
			bat_dbg(DBG_BATMAN, bat_priv,
				"Removing selected gateway - "
				"no gateway in range\n");
189
		else if ((!curr_gw) && (curr_gw_tmp))
190 191 192 193 194
			bat_dbg(DBG_BATMAN, bat_priv,
				"Adding route to gateway %pM "
				"(gw_flags: %i, tq: %i)\n",
				curr_gw_tmp->orig_node->orig,
				curr_gw_tmp->orig_node->gw_flags,
195
				router->tq_avg);
196 197 198 199 200 201
		else
			bat_dbg(DBG_BATMAN, bat_priv,
				"Changing route to gateway %pM "
				"(gw_flags: %i, tq: %i)\n",
				curr_gw_tmp->orig_node->orig,
				curr_gw_tmp->orig_node->gw_flags,
202
				router->tq_avg);
203

204
		neigh_node_free_ref(router);
205
		gw_select(bat_priv, curr_gw_tmp);
206 207
	}

208
unlock:
209
	rcu_read_unlock();
210 211 212
out:
	if (curr_gw)
		gw_node_free_ref(curr_gw);
213 214 215 216
}

void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node)
{
217
	struct orig_node *curr_gw_orig;
218
	struct neigh_node *router_gw = NULL, *router_orig = NULL;
219 220
	uint8_t gw_tq_avg, orig_tq_avg;

221
	curr_gw_orig = gw_get_selected_orig(bat_priv);
222 223
	if (!curr_gw_orig)
		goto deselect;
224

225 226 227
	router_gw = orig_node_get_router(curr_gw_orig);
	if (!router_gw)
		goto deselect;
228 229

	/* this node already is the gateway */
230
	if (curr_gw_orig == orig_node)
231
		goto out;
232

233 234 235
	router_orig = orig_node_get_router(orig_node);
	if (!router_orig)
		goto out;
236

237 238
	gw_tq_avg = router_gw->tq_avg;
	orig_tq_avg = router_orig->tq_avg;
239 240 241

	/* the TQ value has to be better */
	if (orig_tq_avg < gw_tq_avg)
242
		goto out;
243 244 245 246 247 248 249

	/**
	 * if the routing class is greater than 3 the value tells us how much
	 * greater the TQ value of the new gateway must be
	 **/
	if ((atomic_read(&bat_priv->gw_sel_class) > 3) &&
	    (orig_tq_avg - gw_tq_avg < atomic_read(&bat_priv->gw_sel_class)))
250
		goto out;
251 252 253 254 255 256 257 258

	bat_dbg(DBG_BATMAN, bat_priv,
		"Restarting gateway selection: better gateway found (tq curr: "
		"%i, tq new: %i)\n",
		gw_tq_avg, orig_tq_avg);

deselect:
	gw_deselect(bat_priv);
259
out:
260 261
	if (curr_gw_orig)
		orig_node_free_ref(curr_gw_orig);
262 263 264 265
	if (router_gw)
		neigh_node_free_ref(router_gw);
	if (router_orig)
		neigh_node_free_ref(router_orig);
266

267
	return;
268 269 270 271 272 273 274 275
}

static void gw_node_add(struct bat_priv *bat_priv,
			struct orig_node *orig_node, uint8_t new_gwflags)
{
	struct gw_node *gw_node;
	int down, up;

276
	gw_node = kzalloc(sizeof(struct gw_node), GFP_ATOMIC);
277 278 279 280 281
	if (!gw_node)
		return;

	INIT_HLIST_NODE(&gw_node->list);
	gw_node->orig_node = orig_node;
282
	atomic_set(&gw_node->refcount, 1);
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301

	spin_lock_bh(&bat_priv->gw_list_lock);
	hlist_add_head_rcu(&gw_node->list, &bat_priv->gw_list);
	spin_unlock_bh(&bat_priv->gw_list_lock);

	gw_bandwidth_to_kbit(new_gwflags, &down, &up);
	bat_dbg(DBG_BATMAN, bat_priv,
		"Found new gateway %pM -> gw_class: %i - %i%s/%i%s\n",
		orig_node->orig, new_gwflags,
		(down > 2048 ? down / 1024 : down),
		(down > 2048 ? "MBit" : "KBit"),
		(up > 2048 ? up / 1024 : up),
		(up > 2048 ? "MBit" : "KBit"));
}

void gw_node_update(struct bat_priv *bat_priv,
		    struct orig_node *orig_node, uint8_t new_gwflags)
{
	struct hlist_node *node;
302 303
	struct gw_node *gw_node, *curr_gw;

304 305 306 307 308 309
	/**
	 * Note: We don't need a NULL check here, since curr_gw never gets
	 * dereferenced. If curr_gw is NULL we also should not exit as we may
	 * have this gateway in our list (duplication check!) even though we
	 * have no currently selected gateway.
	 */
310
	curr_gw = gw_get_selected_gw_node(bat_priv);
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330

	rcu_read_lock();
	hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) {
		if (gw_node->orig_node != orig_node)
			continue;

		bat_dbg(DBG_BATMAN, bat_priv,
			"Gateway class of originator %pM changed from "
			"%i to %i\n",
			orig_node->orig, gw_node->orig_node->gw_flags,
			new_gwflags);

		gw_node->deleted = 0;

		if (new_gwflags == 0) {
			gw_node->deleted = jiffies;
			bat_dbg(DBG_BATMAN, bat_priv,
				"Gateway %pM removed from gateway list\n",
				orig_node->orig);

331 332
			if (gw_node == curr_gw)
				goto deselect;
333 334
		}

335
		goto unlock;
336 337 338
	}

	if (new_gwflags == 0)
339
		goto unlock;
340 341

	gw_node_add(bat_priv, orig_node, new_gwflags);
342 343 344 345 346 347
	goto unlock;

deselect:
	gw_deselect(bat_priv);
unlock:
	rcu_read_unlock();
348

349 350
	if (curr_gw)
		gw_node_free_ref(curr_gw);
351 352 353 354 355 356 357 358 359
}

void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node)
{
	return gw_node_update(bat_priv, orig_node, 0);
}

void gw_node_purge(struct bat_priv *bat_priv)
{
360
	struct gw_node *gw_node, *curr_gw;
361 362
	struct hlist_node *node, *node_tmp;
	unsigned long timeout = 2 * PURGE_TIMEOUT * HZ;
363 364 365
	char do_deselect = 0;

	curr_gw = gw_get_selected_gw_node(bat_priv);
366 367 368 369 370 371 372 373 374 375

	spin_lock_bh(&bat_priv->gw_list_lock);

	hlist_for_each_entry_safe(gw_node, node, node_tmp,
				  &bat_priv->gw_list, list) {
		if (((!gw_node->deleted) ||
		     (time_before(jiffies, gw_node->deleted + timeout))) &&
		    atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE)
			continue;

376 377
		if (curr_gw == gw_node)
			do_deselect = 1;
378 379

		hlist_del_rcu(&gw_node->list);
380
		gw_node_free_ref(gw_node);
381 382 383
	}

	spin_unlock_bh(&bat_priv->gw_list_lock);
384 385 386 387 388 389 390

	/* gw_deselect() needs to acquire the gw_list_lock */
	if (do_deselect)
		gw_deselect(bat_priv);

	if (curr_gw)
		gw_node_free_ref(curr_gw);
391 392
}

393 394 395
/**
 * fails if orig_node has no router
 */
396 397 398
static int _write_buffer_text(struct bat_priv *bat_priv,
			      struct seq_file *seq, struct gw_node *gw_node)
{
399
	struct gw_node *curr_gw;
400 401
	struct neigh_node *router;
	int down, up, ret = -1;
402 403 404

	gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, &down, &up);

405 406 407
	router = orig_node_get_router(gw_node->orig_node);
	if (!router)
		goto out;
408

409
	curr_gw = gw_get_selected_gw_node(bat_priv);
410 411

	ret = seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %3i - %i%s/%i%s\n",
412 413 414 415 416 417 418 419 420
			 (curr_gw == gw_node ? "=>" : "  "),
			 gw_node->orig_node->orig,
			 router->tq_avg, router->addr,
			 router->if_incoming->net_dev->name,
			 gw_node->orig_node->gw_flags,
			 (down > 2048 ? down / 1024 : down),
			 (down > 2048 ? "MBit" : "KBit"),
			 (up > 2048 ? up / 1024 : up),
			 (up > 2048 ? "MBit" : "KBit"));
421

422
	neigh_node_free_ref(router);
423 424
	if (curr_gw)
		gw_node_free_ref(curr_gw);
425
out:
426
	return ret;
427 428 429 430 431 432
}

int gw_client_seq_print_text(struct seq_file *seq, void *offset)
{
	struct net_device *net_dev = (struct net_device *)seq->private;
	struct bat_priv *bat_priv = netdev_priv(net_dev);
433
	struct hard_iface *primary_if;
434 435
	struct gw_node *gw_node;
	struct hlist_node *node;
436
	int gw_count = 0, ret = 0;
437

438 439 440 441 442 443
	primary_if = primary_if_get_selected(bat_priv);
	if (!primary_if) {
		ret = seq_printf(seq, "BATMAN mesh %s disabled - please "
				 "specify interfaces to enable it\n",
				 net_dev->name);
		goto out;
444 445
	}

446 447 448 449 450
	if (primary_if->if_status != IF_ACTIVE) {
		ret = seq_printf(seq, "BATMAN mesh %s disabled - "
				 "primary interface not active\n",
				 net_dev->name);
		goto out;
451 452 453 454 455 456
	}

	seq_printf(seq, "      %-12s (%s/%i) %17s [%10s]: gw_class ... "
		   "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n",
		   "Gateway", "#", TQ_MAX_VALUE, "Nexthop",
		   "outgoingIF", SOURCE_VERSION, REVISION_VERSION_STR,
457 458
		   primary_if->net_dev->name,
		   primary_if->net_dev->dev_addr, net_dev->name);
459 460 461 462 463 464

	rcu_read_lock();
	hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) {
		if (gw_node->deleted)
			continue;

465 466
		/* fails if orig_node has no router */
		if (_write_buffer_text(bat_priv, seq, gw_node) < 0)
467 468 469 470 471 472 473 474 475
			continue;

		gw_count++;
	}
	rcu_read_unlock();

	if (gw_count == 0)
		seq_printf(seq, "No gateways in range ...\n");

476 477 478 479
out:
	if (primary_if)
		hardif_free_ref(primary_if);
	return ret;
480 481 482 483 484 485 486 487
}

int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
{
	struct ethhdr *ethhdr;
	struct iphdr *iphdr;
	struct ipv6hdr *ipv6hdr;
	struct udphdr *udphdr;
488
	struct gw_node *curr_gw;
489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552
	unsigned int header_len = 0;

	if (atomic_read(&bat_priv->gw_mode) == GW_MODE_OFF)
		return 0;

	/* check for ethernet header */
	if (!pskb_may_pull(skb, header_len + ETH_HLEN))
		return 0;
	ethhdr = (struct ethhdr *)skb->data;
	header_len += ETH_HLEN;

	/* check for initial vlan header */
	if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) {
		if (!pskb_may_pull(skb, header_len + VLAN_HLEN))
			return 0;
		ethhdr = (struct ethhdr *)(skb->data + VLAN_HLEN);
		header_len += VLAN_HLEN;
	}

	/* check for ip header */
	switch (ntohs(ethhdr->h_proto)) {
	case ETH_P_IP:
		if (!pskb_may_pull(skb, header_len + sizeof(struct iphdr)))
			return 0;
		iphdr = (struct iphdr *)(skb->data + header_len);
		header_len += iphdr->ihl * 4;

		/* check for udp header */
		if (iphdr->protocol != IPPROTO_UDP)
			return 0;

		break;
	case ETH_P_IPV6:
		if (!pskb_may_pull(skb, header_len + sizeof(struct ipv6hdr)))
			return 0;
		ipv6hdr = (struct ipv6hdr *)(skb->data + header_len);
		header_len += sizeof(struct ipv6hdr);

		/* check for udp header */
		if (ipv6hdr->nexthdr != IPPROTO_UDP)
			return 0;

		break;
	default:
		return 0;
	}

	if (!pskb_may_pull(skb, header_len + sizeof(struct udphdr)))
		return 0;
	udphdr = (struct udphdr *)(skb->data + header_len);
	header_len += sizeof(struct udphdr);

	/* check for bootp port */
	if ((ntohs(ethhdr->h_proto) == ETH_P_IP) &&
	     (ntohs(udphdr->dest) != 67))
		return 0;

	if ((ntohs(ethhdr->h_proto) == ETH_P_IPV6) &&
	    (ntohs(udphdr->dest) != 547))
		return 0;

	if (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER)
		return -1;

553 554
	curr_gw = gw_get_selected_gw_node(bat_priv);
	if (!curr_gw)
555 556
		return 0;

557 558
	if (curr_gw)
		gw_node_free_ref(curr_gw);
559 560
	return 1;
}