Allow broadcast packets to be sent directly instead of via the MST.
authorGuus Sliepen <guus@tinc-vpn.org>
Sun, 15 Apr 2012 23:57:25 +0000 (01:57 +0200)
committerGuus Sliepen <guus@tinc-vpn.org>
Sun, 15 Apr 2012 23:57:25 +0000 (01:57 +0200)
When the "Broadcast = direct" option is used, broadcast packets are not sent
and forwarded via the Minimum Spanning Tree to all nodes, but are sent directly
to all nodes that can be reached in one hop.

One use for this is to allow running ad-hoc routing protocols, such as OLSR, on
top of tinc.

doc/tinc.conf.5.in
doc/tinc.texi
src/net_packet.c
src/net_setup.c
src/route.c
src/route.h

index 560ae4799e9d2f4c422455a456316c563deff3b6..b49e3de6b0ed87882791a2eaac4028e0affe1e3f 100644 (file)
@@ -159,8 +159,25 @@ It is possible to bind only to a single interface with this variable.
 .Pp
 This option may not work on all platforms.
 
-.It Va Broadcast Li = yes | no Po yes Pc Bq experimental
-When disabled, tinc will drop all broadcast and multicast packets, in both router and switch mode.
+.It Va Broadcast Li = no | mst | direct Po mst Pc Bq experimental
+This option selects the way broadcast packets are sent to other daemons.
+NOTE: all nodes in a VPN must use the same
+.Va Broadcast
+mode, otherwise routing loops can form.
+
+.Bl -tag -width indent
+.It no
+Broadcast packets are never sent to other nodes.
+
+.It mst
+Broadcast packets are sent and forwarded via the VPN's Minimum Spanning Tree.
+This ensures broadcast packets reach all nodes.
+
+.It direct
+Broadcast packets are sent directly to all nodes that can be reached directly.
+Broadcast packets received from other nodes are never forwarded.
+If the IndirectData option is also set, broadcast packets will only be sent to nodes which we have a meta connection to.
+.El
 
 .It Va ConnectTo Li = Ar name
 Specifies which other tinc daemon to connect to on startup.
index 84e3495c96115e58ed84d885d4cb6590a2a29b9e..d7776826f9d0fdb93df8f5427ddbed48dc87a655 100644 (file)
@@ -778,8 +778,23 @@ variable.
 This option may not work on all platforms.
 
 @cindex Broadcast
-@item Broadcast = <yes | no> (yes) [experimental]
-When disabled, tinc will drop all broadcast and multicast packets, in both router and switch mode.
+@item Broadcast = <no | mst | direct> (mst) [experimental]
+This option selects the way broadcast packets are sent to other daemons.
+@emph{NOTE: all nodes in a VPN must use the same Broadcast mode, otherwise routing loops can form.}
+
+@table @asis
+@item no
+Broadcast packets are never sent to other nodes.
+
+@item mst
+Broadcast packets are sent and forwarded via the VPN's Minimum Spanning Tree.
+This ensures broadcast packets reach all nodes.
+
+@item direct
+Broadcast packets are sent directly to all nodes that can be reached directly.
+Broadcast packets received from other nodes are never forwarded.
+If the IndirectData option is also set, broadcast packets will only be sent to nodes which we have a meta connection to.
+@end table
 
 @cindex ConnectTo
 @item ConnectTo = <@var{name}>
index b11949a2048309b9006f47b41b33b26618a9d798..43c8ce20204db886b4b7ab2ece7afdd68c9f4b4c 100644 (file)
@@ -584,24 +584,50 @@ void send_packet(const node_t *n, vpn_packet_t *packet) {
 void broadcast_packet(const node_t *from, vpn_packet_t *packet) {
        avl_node_t *node;
        connection_t *c;
+       node_t *n;
+
+       // Always give ourself a copy of the packet.
+       if(from != myself)
+               send_packet(myself, packet);
+
+       // In TunnelServer mode, do not forward broadcast packets.
+        // The MST might not be valid and create loops.
+       if(tunnelserver || broadcast_mode == BMODE_NONE)
+               return;
 
        ifdebug(TRAFFIC) logger(LOG_INFO, "Broadcasting packet of %d bytes from %s (%s)",
                           packet->len, from->name, from->hostname);
 
-       if(from != myself) {
-               send_packet(myself, packet);
+       switch(broadcast_mode) {
+               // In MST mode, broadcast packets travel via the Minimum Spanning Tree.
+               // This guarantees all nodes receive the broadcast packet, and
+               // usually distributes the sending of broadcast packets over all nodes.
+               case BMODE_MST:
+                       for(node = connection_tree->head; node; node = node->next) {
+                               c = node->data;
 
-               // In TunnelServer mode, do not forward broadcast packets.
-                // The MST might not be valid and create loops.
-               if(tunnelserver)
-                       return;
-       }
+                               if(c->status.active && c->status.mst && c != from->nexthop->connection)
+                                       send_packet(c->node, packet);
+                       }
+                       break;
+
+               // In direct mode, we send copies to each node we know of.
+               // However, this only reaches nodes that can be reached in a single hop.
+               // We don't have enough information to forward broadcast packets in this case.
+               case BMODE_DIRECT:
+                       if(from != myself)
+                               break;
+
+                       for(node = node_udp_tree->head; node; node = node->next) {
+                               n = node->data;
 
-       for(node = connection_tree->head; node; node = node->next) {
-               c = node->data;
+                               if(n->status.reachable && ((n->via == myself && n->nexthop == n) || n->via == n))
+                                       send_packet(c->node, packet);
+                       }
+                       break;
 
-               if(c->status.active && c->status.mst && c != from->nexthop->connection)
-                       send_packet(c->node, packet);
+               default:
+                       break;
        }
 }
 
index a179228be7f5075f0bfcd2e23e257a768e76602c..b8e17da9bbbdf4c8dc32b20ed18d18310921c46d 100644 (file)
@@ -429,7 +429,19 @@ static bool setup_myself(void) {
 
        get_config_bool(lookup_config(config_tree, "PriorityInheritance"), &priorityinheritance);
        get_config_bool(lookup_config(config_tree, "DecrementTTL"), &decrement_ttl);
-       get_config_bool(lookup_config(config_tree, "Broadcast"), &broadcast);
+       if(get_config_string(lookup_config(config_tree, "Broadcast"), &mode)) {
+               if(!strcasecmp(mode, "no"))
+                       broadcast_mode = BMODE_NONE;
+               else if(!strcasecmp(mode, "yes") || !strcasecmp(mode, "mst"))
+                       broadcast_mode = BMODE_MST;
+               else if(!strcasecmp(mode, "direct"))
+                       broadcast_mode = BMODE_DIRECT;
+               else {
+                       logger(LOG_ERR, "Invalid broadcast mode!");
+                       return false;
+               }
+               free(mode);
+       }
 
 #if !defined(SOL_IP) || !defined(IP_TOS)
        if(priorityinheritance)
index 6eadb888162980633a2813e0da199092c61987ff..74ad9a3469d335fa13e7472c0d3c5b13ef734834 100644 (file)
 
 rmode_t routing_mode = RMODE_ROUTER;
 fmode_t forwarding_mode = FMODE_INTERNAL;
+bmode_t broadcast_mode = BMODE_MST;
 bool decrement_ttl = false;
 bool directonly = false;
 bool priorityinheritance = false;
 int macexpire = 600;
 bool overwrite_mac = false;
-bool broadcast = true;
 mac_t mymac = {{0xFE, 0xFD, 0, 0, 0, 0}};
 
 /* Sizes of various headers */
@@ -430,7 +430,7 @@ static void route_ipv4(node_t *source, vpn_packet_t *packet) {
        if(!checklength(source, packet, ether_size + ip_size))
                return;
 
-       if(broadcast && (((packet->data[30] & 0xf0) == 0xe0) || (
+       if(broadcast_mode && (((packet->data[30] & 0xf0) == 0xe0) || (
                        packet->data[30] == 255 &&
                        packet->data[31] == 255 &&
                        packet->data[32] == 255 &&
@@ -727,7 +727,7 @@ static void route_ipv6(node_t *source, vpn_packet_t *packet) {
                return;
        }
 
-       if(broadcast && packet->data[38] == 255)
+       if(broadcast_mode && packet->data[38] == 255)
                broadcast_packet(source, packet);
        else
                route_ipv6_unicast(source, packet);
@@ -817,8 +817,7 @@ static void route_mac(node_t *source, vpn_packet_t *packet) {
        subnet = lookup_subnet_mac(NULL, &dest);
 
        if(!subnet) {
-               if(broadcast)
-                       broadcast_packet(source, packet);
+               broadcast_packet(source, packet);
                return;
        }
 
index 5622feb2fb40ea6c2df8abed9bd1c68d27e363de..7b45e76a686df0ba90a93543c601dbd9b5e81eca 100644 (file)
@@ -36,12 +36,18 @@ typedef enum fmode_t {
        FMODE_KERNEL,
 } fmode_t;
 
+typedef enum bmode_t {
+       BMODE_NONE = 0,
+       BMODE_MST,
+       BMODE_DIRECT,
+} bmode_t;
+
 extern rmode_t routing_mode;
 extern fmode_t forwarding_mode;
+extern bmode_t broadcast_mode;
 extern bool decrement_ttl;
 extern bool directonly;
 extern bool overwrite_mac;
-extern bool broadcast;
 extern bool priorityinheritance;
 extern int macexpire;