|
@@ -0,0 +1,411 @@
|
|
|
+log syslog all;
|
|
|
+
|
|
|
+/* Definitionen fuer die Bitarithmetik der Schleifenverhinderungsmechanik */
|
|
|
+
|
|
|
+define OSPF_tag_sourcebits = 5; /* ld(32) */
|
|
|
+define OSPF_tag_pathbits = 32 - OSPF_tag_sourcebits;
|
|
|
+define OSPF_tag_pathvalue_div = 32 ; /* 2 ^ OSPF_tag_sourcebits */
|
|
|
+
|
|
|
+function fn_tag_to_source (int tagbits) {
|
|
|
+ return tagbits - ((tagbits / OSPF_tag_pathvalue_div) * OSPF_tag_pathvalue_div);
|
|
|
+}
|
|
|
+
|
|
|
+function fn_tag_to_path (int tagbits) {
|
|
|
+ return tagbits / OSPF_tag_pathvalue_div;
|
|
|
+}
|
|
|
+
|
|
|
+function fn_power_of_2 (int n) {
|
|
|
+ # awk 'BEGIN { for ( i=0 ; i < 32 ; i++ ) print "\t\t" i ": return " 2^i ";" }'
|
|
|
+ case n {
|
|
|
+ 0: return 1;
|
|
|
+ 1: return 2;
|
|
|
+ 2: return 4;
|
|
|
+ 3: return 8;
|
|
|
+ 4: return 16;
|
|
|
+ 5: return 32;
|
|
|
+ 6: return 64;
|
|
|
+ 7: return 128;
|
|
|
+ 8: return 256;
|
|
|
+ 9: return 512;
|
|
|
+ 10: return 1024;
|
|
|
+ 11: return 2048;
|
|
|
+ 12: return 4096;
|
|
|
+ 13: return 8192;
|
|
|
+ 14: return 16384;
|
|
|
+ 15: return 32768;
|
|
|
+ 16: return 65536;
|
|
|
+ 17: return 131072;
|
|
|
+ 18: return 262144;
|
|
|
+ 19: return 524288;
|
|
|
+ 20: return 1048576;
|
|
|
+ 21: return 2097152;
|
|
|
+ 22: return 4194304;
|
|
|
+ 23: return 8388608;
|
|
|
+ 24: return 16777216;
|
|
|
+ 25: return 33554432;
|
|
|
+ 26: return 67108864;
|
|
|
+ 27: return 134217728;
|
|
|
+ 28: return 268435456;
|
|
|
+ 29: return 536870912;
|
|
|
+ 30: return 1073741824;
|
|
|
+ 31: return 2147483648;
|
|
|
+ else: return 0;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function fn_instance_to_tagbit (int inst) {
|
|
|
+ return fn_power_of_2(OSPF_tag_sourcebits - 1 + inst);
|
|
|
+}
|
|
|
+
|
|
|
+function fn_instancebit_is_set_in_ospf_tag (int inst)
|
|
|
+int instpathbits;
|
|
|
+{
|
|
|
+ instpathbits = fn_tag_to_path(ospf_tag) / fn_power_of_2(inst-1);
|
|
|
+ return (instpathbits / 2) * 2 != instpathbits;
|
|
|
+}
|
|
|
+
|
|
|
+function fn_reentrybit_is_set_in_ospf_tag() {
|
|
|
+ return fn_instancebit_is_set_in_ospf_tag(fn_tag_to_source(ospf_tag));
|
|
|
+}
|
|
|
+
|
|
|
+function fn_set_reentrybit_in_ospf_tag() {
|
|
|
+ ospf_tag = ospf_tag + fn_instance_to_tagbit(fn_tag_to_source(ospf_tag));
|
|
|
+}
|
|
|
+
|
|
|
+include "/usr/local/etc/bird.local.conf";
|
|
|
+
|
|
|
+/* Dort muss mindestens Folgendes definiert werden (Beispiel):
|
|
|
+
|
|
|
+router id 91.204.4.242;
|
|
|
+
|
|
|
+function fn_is_local_ospf_instance (int inst) {
|
|
|
+ case inst {
|
|
|
+ 1: return true;
|
|
|
+ 2: return true;
|
|
|
+ else: return false;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function fn_any_local_instancebit_is_set_in_ospf_tag () {
|
|
|
+ return fn_instancebit_is_set_in_ospf_tag(1) ||
|
|
|
+ fn_instancebit_is_set_in_ospf_tag(2);
|
|
|
+}
|
|
|
+
|
|
|
+define Unrouted_local = [ 192.168.1.0/24+, 192.168.84.0/24+ ];
|
|
|
+*/
|
|
|
+
|
|
|
+define Babel_WLAN_metric_base = 1000;
|
|
|
+define Babel_WLAN_metric_inactive = 999;
|
|
|
+define OSPF_metric2_max = 16777215;
|
|
|
+define OSPF_preference_local = 160; /* > OSPF default = 150 */
|
|
|
+
|
|
|
+define HOT = 0;
|
|
|
+define BEST = 1;
|
|
|
+define COLD = 2;
|
|
|
+
|
|
|
+##### Definitionen fuer alle bekannten IGP Instanzen:
|
|
|
+
|
|
|
+include "/usr/local/etc/bird.inst.conf";
|
|
|
+
|
|
|
+# Dort muss mindestens Folgendes definiert werden:
|
|
|
+#define potato_ospf1 = BEST; [... et al. ...]
|
|
|
+#function fn_instance_to_potato (int inst) -> int (HOT, ...)
|
|
|
+#function fn_proto_to_instance (string from_proto) -> int (1, 2, ...)
|
|
|
+#function fn_instance_to_bgpospf (int inst) -> string ("bgpXospfX")
|
|
|
+
|
|
|
+/* XXX zwecks Einrechnung der Babel Metrik, gehoert hier aber nicht hin: */
|
|
|
+function fn_a_Babel_WLAN_routes () {
|
|
|
+ return ifname = "tap9";
|
|
|
+ };
|
|
|
+
|
|
|
+/* Bausteine fuer Filter. Namenskonventionen:
|
|
|
+ f_... Filter (accept/reject)
|
|
|
+ fn_... Funktion
|
|
|
+ ..._a_... true => accept
|
|
|
+ ..._r_... true => reject
|
|
|
+ ..._am_... true => accept + modify
|
|
|
+*/
|
|
|
+
|
|
|
+function fn_a_Routed () {
|
|
|
+ return net ~ Routed;
|
|
|
+ };
|
|
|
+
|
|
|
+filter f_a_Routed {
|
|
|
+ if fn_a_Routed()
|
|
|
+ then accept;
|
|
|
+ else reject "Routed";
|
|
|
+ };
|
|
|
+
|
|
|
+function fn_r_Unrouted () {
|
|
|
+ return ! (net ~ Unrouted_global || net ~ Unrouted_local);
|
|
|
+ };
|
|
|
+
|
|
|
+filter f_r_Unrouted {
|
|
|
+ if fn_r_Unrouted()
|
|
|
+ then accept;
|
|
|
+ else reject "Unrouted";
|
|
|
+ };
|
|
|
+
|
|
|
+function fn_a_acceptable_routes () {
|
|
|
+ return fn_r_Unrouted() && fn_a_Routed();
|
|
|
+}
|
|
|
+
|
|
|
+/* Einrechnung der Babel Metrik: */
|
|
|
+function fn_include_Babel_WLAN_routes () {
|
|
|
+ case gw {
|
|
|
+ include "/var/run/bird.babeld.conf";
|
|
|
+ else: ospf_metric1 = ospf_metric1 + Babel_WLAN_metric_base + Babel_WLAN_metric_inactive;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function fn_debug_ospf_route (string str)
|
|
|
+{
|
|
|
+ print str, " ", net, " ^", scope, " *", source,
|
|
|
+ " !", from, " :", gw, " (", preference, ") ",
|
|
|
+ igp_metric, "/", ospf_metric1, "/", ospf_metric2,
|
|
|
+ " [", ospf_tag, "]";
|
|
|
+ # Fuehrt zu:
|
|
|
+ # bird: filters, line 169: Can't operate with values of incompatible types
|
|
|
+ #" [", fn_tag_to_source(ospf_tag), "|", fn_tag_to_path(ospf_tag), "]";
|
|
|
+}
|
|
|
+
|
|
|
+function fn_debug_ospf_route_before (string str)
|
|
|
+{
|
|
|
+ printn str; fn_debug_ospf_route("?");
|
|
|
+}
|
|
|
+
|
|
|
+function fn_debug_ospf_route_after (string str)
|
|
|
+{
|
|
|
+ printn str; fn_debug_ospf_route("!");
|
|
|
+}
|
|
|
+
|
|
|
+function fn_am_local_to_ospf_table () {
|
|
|
+ if ! (proto ~ "ospf*") &&
|
|
|
+ fn_a_acceptable_routes()
|
|
|
+ then if ifname ~ "lo0"
|
|
|
+ then return false;
|
|
|
+ else { if preference < OSPF_preference_local
|
|
|
+ then preference = OSPF_preference_local;
|
|
|
+ return true; }
|
|
|
+ else return false;
|
|
|
+}
|
|
|
+
|
|
|
+function fn_am_local_to_ospf_export () {
|
|
|
+ if ! (proto ~ "*ospf*") &&
|
|
|
+ fn_a_acceptable_routes()
|
|
|
+ then { if ifname ~ "lo0"
|
|
|
+ then return false;
|
|
|
+ else # geroutete loopback Adressen auch per OSPF stubnet!
|
|
|
+ if ifname ~ "lo*"
|
|
|
+ then ospf_metric1 = 1;
|
|
|
+ else ospf_metric1 = 10;
|
|
|
+ ospf_metric2 = 0;
|
|
|
+ return true; }
|
|
|
+ else return false;
|
|
|
+}
|
|
|
+
|
|
|
+function fn_import_ospf_master (int from_instance) {
|
|
|
+ if ! fn_a_acceptable_routes()
|
|
|
+ then return false;
|
|
|
+ # Schleifenvermeidung: routes mit tags von OSPF-Instanzen,
|
|
|
+ # an denen dieser Router teilnimmt, sind schonmal hier
|
|
|
+ # durchgelaufen, und zwar mit tag = 0, d.h. ohne Uebergang
|
|
|
+ # zwischen OSPF-Instanzen. (Evtl. Ausnahme: Partitionierung
|
|
|
+ # der source Instanz, sodass die urspruengliche route nicht
|
|
|
+ # mit source = 0 hier ankam, sondern nur per Transit.)
|
|
|
+ else if ospf_tag != 0
|
|
|
+ then {
|
|
|
+ if fn_instance_to_potato(from_instance) = HOT
|
|
|
+ # TBD || fn_instance_to_transit(from_instance) = false
|
|
|
+ then # kein Transit durch hot potato Instanzen
|
|
|
+ return false;
|
|
|
+ else if fn_is_local_ospf_instance(fn_tag_to_source(ospf_tag)) ||
|
|
|
+ fn_any_local_instancebit_is_set_in_ospf_tag()
|
|
|
+ then # re-entry
|
|
|
+ if ! fn_reentrybit_is_set_in_ospf_tag()
|
|
|
+ then # wg. counting-to-infinity
|
|
|
+ fn_set_reentrybit_in_ospf_tag();
|
|
|
+ }
|
|
|
+ case from_instance {
|
|
|
+ /* XXX zwecks Einrechnung der Babel Metrik, gehoert hier aber nicht hin: */
|
|
|
+ # metric mittels /var/run/bird.babeld.conf (hoch)setzen:
|
|
|
+ 2: fn_include_Babel_WLAN_routes();
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+function fn_import_master_ospf (string from_proto) {
|
|
|
+ return proto = from_proto;
|
|
|
+}
|
|
|
+
|
|
|
+/* Funktioniert nicht als Funktion, aber als Filter,
|
|
|
+ s. protocol pipe master2ospfX in bird.instX.conf.
|
|
|
+ Grumpf:-(bird 1.5.0)
|
|
|
+function fn_export_master_ospf () {
|
|
|
+ if proto ~ "ospf*"
|
|
|
+ then return false;
|
|
|
+ else return fn_am_local_to_ospf_table();
|
|
|
+}
|
|
|
+*/
|
|
|
+
|
|
|
+function fn_am_master_to_bgpospf (int dest_instance)
|
|
|
+int from_instance;
|
|
|
+{
|
|
|
+ if fn_a_acceptable_routes()
|
|
|
+ then { from_instance = fn_proto_to_instance(proto);
|
|
|
+ if ospf_tag = 0 # (lokale Route, keine Transitroute)
|
|
|
+ then { # route entstammt einer IGP Instanz, an der dieser
|
|
|
+ # router teilnimmt. Beim Uebergang in eine andere
|
|
|
+ # IGP Instanz muss diese route, die gerade ein
|
|
|
+ # lokales IGP verlaesst, mit dem tag dieser Instanz
|
|
|
+ # versehen werden. Kommt die route dann spaeter
|
|
|
+ # per transit wieder zur Urprungs-Instanz zurueck,
|
|
|
+ # kann sie dank des tags als Rundlauefer erkannt
|
|
|
+ # und entsprechend schleifenbehandelt werden.
|
|
|
+ ospf_tag = from_instance;
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ else if fn_instance_to_potato(from_instance) = HOT
|
|
|
+ # TBD || fn_instance_to_transit(from_instance) = false
|
|
|
+ then # kein Transit durch HOT Instanzen wg. Verlust der ursprünglichen Metrik
|
|
|
+ return false;
|
|
|
+ else { if fn_reentrybit_is_set_in_ospf_tag() &&
|
|
|
+ fn_instancebit_is_set_in_ospf_tag(dest_instance)
|
|
|
+ then # kein counting-to-infinity
|
|
|
+ return false;
|
|
|
+ # Transit-IGP, aus dem die Route gerade kommt, in die Route "einkerben"
|
|
|
+ if ! fn_instancebit_is_set_in_ospf_tag(from_instance)
|
|
|
+ then ospf_tag = ospf_tag + fn_instance_to_tagbit(from_instance);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else return false;
|
|
|
+}
|
|
|
+
|
|
|
+function fn_export_master_bgpospf (string dest_proto)
|
|
|
+int dest_instance;
|
|
|
+{
|
|
|
+ dest_instance = fn_proto_to_instance(dest_proto);
|
|
|
+ printn "master2bgp"; fn_debug_ospf_route_before(dest_proto);
|
|
|
+ if proto ~ "ospf*" &&
|
|
|
+ proto != dest_proto &&
|
|
|
+ fn_am_master_to_bgpospf(dest_instance)
|
|
|
+ then { printn "master2bgp"; fn_debug_ospf_route_after(dest_proto);
|
|
|
+ bgp_local_pref = preference;
|
|
|
+ bgp_path.prepend(ospf_tag);
|
|
|
+ # optimal:
|
|
|
+ # -> E1 mit metric1 = Summe
|
|
|
+ # hot potato ("closest exit"):
|
|
|
+ # -> E1 mit metric1 = 0, # geht nicht: metric2 = Summe
|
|
|
+ # retour: automatisch mit mit metric1 = Summe, metric2 = 0
|
|
|
+ # cold potato ("best exit", RFC4451):
|
|
|
+ # -> E2 mit metric2 = Summe
|
|
|
+ # ?: wie geht retour E2 -> E1, d.h. wie funktioniert
|
|
|
+ # eine Unterscheidung von ursprünglichen E2 routes?
|
|
|
+ # flag im ospf_tag?
|
|
|
+ if # XXX geht nicht: ospf_metric2 = 16777235
|
|
|
+ ospf_metric2 = OSPF_metric2_max
|
|
|
+ then
|
|
|
+ bgp_med = ospf_metric1;
|
|
|
+ else
|
|
|
+ bgp_med = ospf_metric2 + ospf_metric1;
|
|
|
+ # zZ unbenutzt, erscheint im show all als [ASXi]/[ASXe]
|
|
|
+ if ospf_tag != 0
|
|
|
+ then
|
|
|
+ if fn_reentrybit_is_set_in_ospf_tag()
|
|
|
+ then
|
|
|
+ bgp_origin = 2;
|
|
|
+ else
|
|
|
+ bgp_origin = 1;
|
|
|
+ else
|
|
|
+ bgp_origin = 0;
|
|
|
+ accept;
|
|
|
+ }
|
|
|
+ else reject;
|
|
|
+}
|
|
|
+
|
|
|
+function fn_import_bgpospf ()
|
|
|
+{
|
|
|
+ preference = bgp_local_pref;
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+function fn_export_ospf (int dest_instance)
|
|
|
+string proto_bgpospf;
|
|
|
+int potato_ospf;
|
|
|
+{
|
|
|
+ proto_bgpospf = fn_instance_to_bgpospf(dest_instance);
|
|
|
+ potato_ospf = fn_instance_to_potato(dest_instance);
|
|
|
+ printn "export-", dest_instance; fn_debug_ospf_route_before("");
|
|
|
+ if fn_am_local_to_ospf_export()
|
|
|
+ then return true;
|
|
|
+ else if proto = proto_bgpospf
|
|
|
+ then { ospf_tag = bgp_path.first;
|
|
|
+ # optimal:
|
|
|
+ # -> E1 mit metric1 = Summe
|
|
|
+ # hot potato ("closest exit"):
|
|
|
+ # -> E1 mit metric1 = 0, metric2 = Summe
|
|
|
+ # retour: automatisch mit mit metric1 = Summe, metric2 = 0
|
|
|
+ # cold potato ("best exit", RFC4451):
|
|
|
+ # -> E2 mit metric2 = Summe
|
|
|
+ # ?: wie geht retour E2 -> E1, d.h. wie funktioniert
|
|
|
+ # eine Unterscheidung von ursprünglichen E2 routes?
|
|
|
+ # also flag im ospf_tag kodieren?
|
|
|
+ # !: nein, keine E2 routen als E2 durchlassen,
|
|
|
+ # weil das jede Instanz selbst entscheiden soll,
|
|
|
+ # also nur bei cold potato auf E2 setzen (lassen)
|
|
|
+ #
|
|
|
+ if potato_ospf = BEST
|
|
|
+ then {
|
|
|
+ # igp_metric = bgp_med;
|
|
|
+ # bgp_med = 0;
|
|
|
+ # scope = SCOPE_ORGANIZATION;
|
|
|
+ ospf_metric1 = bgp_med;
|
|
|
+ }
|
|
|
+ else if potato_ospf = HOT
|
|
|
+ then {
|
|
|
+ # geht nicht, wird beim Setzen von
|
|
|
+ # von ospf_metric1 genichtet:
|
|
|
+ # ospf_metric2 = bgp_med;
|
|
|
+ ospf_metric1 = 0;
|
|
|
+ # XXX instance mit hot potato
|
|
|
+ # XXX darf kein Transit sein!
|
|
|
+ # XXX => keine tag routes exportieren
|
|
|
+ }
|
|
|
+ else if potato_ospf = COLD
|
|
|
+ then ospf_metric2 = bgp_med;
|
|
|
+ printn "export-", dest_instance; fn_debug_ospf_route_after("");
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ else return false;
|
|
|
+}
|
|
|
+
|
|
|
+protocol device {
|
|
|
+ scan time 10;
|
|
|
+}
|
|
|
+
|
|
|
+/* wg. BSD: */
|
|
|
+protocol direct {
|
|
|
+}
|
|
|
+
|
|
|
+protocol kernel kernel0 {
|
|
|
+ learn on;
|
|
|
+ scan time 5;
|
|
|
+ import filter f_r_Unrouted;
|
|
|
+ export filter f_r_Unrouted;
|
|
|
+}
|
|
|
+
|
|
|
+/* XXX zwecks Einrechnung der Babel Metrik, gehoert hier aber nicht hin: */
|
|
|
+table fib4table;
|
|
|
+protocol kernel kernel4 {
|
|
|
+ description "babel FIB 4";
|
|
|
+ kernel table 4;
|
|
|
+ table fib4table;
|
|
|
+ learn on;
|
|
|
+ scan time 10;
|
|
|
+}
|
|
|
+
|
|
|
+##### Definition der IGP Instanzen, an denen dieser Router teilnimmt:
|
|
|
+
|
|
|
+include "/usr/local/etc/bird.inst.local.conf";
|