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";