// $Id: f_bcc.cc,v 4.10 2002/05/16 13:42:49 katie Exp $ // Copyright (c) 2001,2002 RIPE NCC // // All Rights Reserved // // Permission to use, copy, modify, and distribute this software and its // documentation for any purpose and without fee is hereby granted, // provided that the above copyright notice appear in all copies and that // both that copyright notice and this permission notice appear in // supporting documentation, and that the name of the author not be // used in advertising or publicity pertaining to distribution of the // software without specific, written prior permission. // // THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING // ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL // AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY // DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN // AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. // // // Copyright (c) 1994 by the University of Southern California // All rights reserved. // // Permission to use, copy, modify, and distribute this software and its // documentation in source and binary forms for lawful non-commercial // purposes and without fee is hereby granted, provided that the above // copyright notice appear in all copies and that both the copyright // notice and this permission notice appear in supporting documentation, // and that any documentation, advertising materials, and other materials // related to such distribution and use acknowledge that the software was // developed by the University of Southern California, Information // Sciences Institute. The name of the USC may not be used to endorse or // promote products derived from this software without specific prior // written permission. // // THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY // REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY // PURPOSE. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR // IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, // TITLE, AND NON-INFRINGEMENT. // // IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY // SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT, TORT, // OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH, THE USE // OR PERFORMANCE OF THIS SOFTWARE. // // Questions concerning this software should be directed to // ratoolset@isi.edu. // // f_bcc.cc : This program reads the input template file, connects to an IRRd // to get the required data and outputs a neat router configuration // file (BGP4 policies) for the Bay Routers. Most of the RPSL // specification can be understood by this program. // // Author(s): Cengiz Alaettinoglu // // Srivathsan Sri // Joe marzot // Based on f_cisco.cc, to add BayRS BCC support to RtConfig // // Comment : I have tried to briefly explain what certain variables and // functions do. And I have left out a lot of them. If anyone // knows about the rest, please let me know. Also feel free to // modify/rectify my current explanations too. // ////////////////////////////////////////////////////////////////////////// #include "config.h" #include #include #include #include #include #include "normalform/NE.hh" #include "irr/irr.hh" #include "irr/autnum.hh" #include "RtConfig.hh" #include "f_bcc.hh" #include "rpsl/schema.hh" #define DBG_BCC 7 #define EXPORT 0 #define IMPORT 1 char BccConfig::mapName[80] = "MyMap"; char BccConfig::mapNameFormat[80] = "MyMap_%d_%d"; bool BccConfig::forcedInboundMatchIP = true; bool BccConfig::useAclCaches = true; bool BccConfig::usePrefixLists = false; int BccConfig::mapIncrements = 1; int BccConfig::mapCount = 1; int BccConfig::mapNumbersStartAt = 1; bool BccConfig::firstCommunityList = true; bool BccConfig::printRouteMap = true; int BccConfig::bcc_version = 310; // default to 3.10 (BayRS 12.00), well not // used yet in this version int BccConfig::bcc_max_preference = 1000; // default to 1000 (count down from here) int BccConfig::bcc_max_prefixes = 66; // default to 66 (SiteManager restriction is // 66 prefixes per policy, restricted // to less than 200 prefixes per policy) // flags to influence the advertise list in EXPORT. BCC behaviour: // no advertise list: announce summarized natural networks only // (class A,B or C) // advertise list = network 255.255.255.255 mask 255.255.255.255 : // announce all networks classless (as learned from IGP and // EGP. int BccConfig::bcc_force_back = 0; // default to not use 'back' unless necessary int BccConfig::bcc_advertise_nets = 0; // default no advertise nets according RADB int BccConfig::bcc_advertise_all = 0; // 0 (default): to not advertise subnets // 1: advertise 255.255.255.255/32 (see above) static unsigned int ones(unsigned char from, unsigned char to) { unsigned int result = 0; for (int i = 32 - to; i <= 32 - from; i++) result |= (1L << i); return result; } //////////////////////////////////////////////////////////////////////////////// // FUNCTION NAME: printRoutes // // FUNCTIONALITY: This function gets the appropriate data from print() and prints // the policies. // // SINGNIFICANT VARIABLES: // itrp and *itrpp: An instance of the SortedPrefixRangeIterator class. // nets : A prefix filter (an instance of SetOfPrefix). // prefix & suffix : These are prepended or appended to the prefixes printed // depending on the other parameters. Prefix may take values // "Advertise" or "network" and suffix may take "Match exact" // or "Match Range". // // SIGNIFICANT FUNCTIONS: // // LAST MODIFIED: 13th Sep 1999. // /////////////////////////////////////////////////////////////////////////////// ListOf2Ints *BccConfig::printRoutes(RadixSet::SortedPrefixRangeIterator **itrpp, SetOfPrefix& nets, char *prefix, char *suffix) { // return the access list number if something is printed ListOf2Ints *result; int count = 0 ; if (nets.universal()) return NULL; result = prefixMgr.add(nets); int aclID = prefixMgr.newID(); result->add(aclID, aclID); int allow_flag = 1; if (nets.negated()) allow_flag = 0; RadixSet::SortedPrefixRangeIterator *itrp; u_int addr; u_int leng; u_int start; u_int end; char buffer[64]; bool ok = false; if (itrpp == NULL || *itrpp == NULL) { itrp = new RadixSet::SortedPrefixRangeIterator(&nets.members); ok = itrp->first(addr, leng, start, end); } else { itrp = *itrpp; ok = itrp->next(addr, leng, start, end); } while (ok) { cout <<" "<< prefix << " address " ; /* need to look at WeeSan's code */ cout << int2quad(buffer, addr) << " "; cout << "mask" << " "; cout << int2quad(buffer, masks[start]) << " " << suffix; cout << "\n"; if (bcc_force_back) cout << " back\n"; if (++count >= bcc_max_prefixes) break; ok = itrp->next(addr, leng, start, end); } if (ok && count >= bcc_max_prefixes) { if (itrpp) *itrpp = itrp; // to remember the current position of iterator. } else { if (itrpp) *itrpp = NULL; } return result; } //////////////////////////////////////////////////////////////////////////////// // FUNCTION NAME: print // // FUNCTIONALITY: This function makes decision on what to be printed out as policies. // It will prepend and append specific terms to the "to be obtained & // printed" prefixes according to functions it is invoked by. It also // takes care about the maximum number of prefixes per policy and // splits them properly. // // SIGNIFICANT VARIABLES: // ne : A normal expression is the disjunctive normal form of the normal // terms.Each normal term may have several policy filters. // asno: Autonomous System number // peerAS: The AS to which another AS talks to (usually by BGP4 & a TCP connection). // policy_split_counter: Keeps track of the number of times the same policy has been // splitted according to bcc_max_prefixes and appropriately gives a unique // name me to each of the split policy. // // SIGNIFICANT FUNCTIONS: // ne->first() & ne->next() : These functions returns the first and the next normal terms // present in that normal expression. // // printRoutes(): This function actually prints the policies. // // LAST MODIFIED: 13th Sep 1999. // //////////////////////////////////////////////////////////////////////////////// int BccConfig::print(NormalExpression *ne, PolicyActionList *actn, ASt asno, ASt peerAS, IPAddr *peer_addr, int import_flag) { int last = 0, med = -5, pref = 0, dpa = 0; // INITIALIZE PROPERLY - TBD static ListOf2Ints empty_list(1); NormalTerm *nt = ne->first(); bool allow_flag = !nt->prfx_set.negated(); int policy_split_counter = 0; //int length = ne->length(); regexp_nf& path = nt->as_path; SetOfPrefix& nets = nt->prfx_set; char *prefix = ""; char *suffix = ""; RadixSet::SortedPrefixRangeIterator *next_itrp,*cur_itrp, itr(&nets.members); u_int addr; u_int leng; u_int start; u_int end; int no_of_prefixes = 0; // This loop finds the number of prefixes in a particular policy. for (bool ok = itr.first(addr, leng, start, end); ok; ok = itr.next(addr, leng, start, end)) { no_of_prefixes++ ; } Debug(Channel(DBG_BCC) << "# ne: " << *ne << "\n"); if (ne->isEmpty()) return last; if (ne->is_universal()) last = 1; bool needToPrintNoRouteMap = false; if (strcmp(mapName, lastMapName)) { strcpy(lastMapName, mapName); needToPrintNoRouteMap = true; routeMapID = mapNumbersStartAt; } routeMapGenerated = true; prefixListGenerated = false; next_itrp = NULL; for (NormalTerm *nt = ne->first(); nt; nt = ne->next()) { do { cur_itrp = next_itrp; if (import_flag) { if (!nets.universal()) { cout << " accept polname Accept"; if (!allow_flag || (path.is_universal() && nt->prfx_set.universal())) { cout << "Default"; } else cout << peerAS; if (no_of_prefixes > bcc_max_prefixes) { policy_split_counter++; cout << "_" << policy_split_counter; } cout << "\n action accept\n"; cout << " match\n"; if (allow_flag) { prefix = "network"; suffix = "match Range"; } else { // ok, we must add an Ignore list cout << " back\n"; cout << " accept polname Ignore" << asno; if (no_of_prefixes > bcc_max_prefixes) { policy_split_counter++; cout << "_" << policy_split_counter; } cout << "\n action ignore\n"; cout << " precedence " << bcc_max_preference << "\n"; cout << " match\n"; cout << " as asnumber "<< asno + 2 <<"\n"; if (bcc_force_back) cout << " back\n"; prefix = "network"; suffix = "match Exact"; } if (peer_addr->get_text()) { // if other than 0.0.0.0 add config statement //int2quad(buffer, Prefask_map(peer_addr).get_prefix()); cout << " peer address " << peer_addr->get_text() << "\n"; if (bcc_force_back) cout << " back\n"; } if (!bcc_force_back) // this one is needed if we skipped cout << " back\n"; // them for the lists above cout << " back\n"; // to close 'match' } } else { // Export cout << " announce polname Announce"; regexp_nf& path = nt->as_path; // new if (!allow_flag || (path.is_universal() && nt->prfx_set.universal())) { cout << "Default"; } else cout << " AS" << peerAS; //if (nt->prfx_set.length() > bcc_max_prefixes) { if (no_of_prefixes > bcc_max_prefixes) { policy_split_counter++; cout << "_" << policy_split_counter; } cout << "\n action announce\n"; cout << " match\n"; if (allow_flag) { if (! nets.isEmpty() && ! nets.universal()) { prefix = "network"; suffix = "match Exact"; } } if (!allow_flag) { // ok, we must add an Ignore list cout << " announce polname Ignore" << asno; //if (nt->prfx_set.length() > bcc_max_prefixes) { if (no_of_prefixes > bcc_max_prefixes) { policy_split_counter++; cout << "_" << policy_split_counter; } cout << "\n action ignore\n"; cout << " match\n"; cout << " as "<< asno + 2 <<"\n"; if (! nets.isEmpty() && ! nets.universal()) { prefix = "network"; suffix = "match Exact"; cout << "\n network & match exact set for ignore list\n"; } cout << " outbound-as asnumber " << asno + 2 << "\n"; if (bcc_force_back) cout << " back\n"; if (peer_addr->get_text()) { // if other than 0.0.0.0 add config statement //int2quad(buffer, Prefask_map(peer_addr).get_prefix()); cout << " outbound-peer address " << peer_addr->get_text() << "\n"; if (bcc_force_back) cout << " back\n"; } } // end of (!allow_flag) } // end of export ListOf2Ints *prfx_acls = printRoutes(&next_itrp,nt->prfx_set, prefix, suffix); if (!import_flag && !strcmp(prefix,"network") && !strcmp(suffix,"match Exact")) { if (bcc_force_back) cout << " back\n"; cout << " outbound-as asnumber " << peerAS << "\n"; if (peer_addr->get_text()) { // if other than 0.0.0.0 add config statement //int2quad(buffer, Prefask_map(peer_addr).get_prefix()); cout << " outbound-peer address " << peer_addr->get_text() << "\n"; if (bcc_force_back) cout << " back\n"; } if (!bcc_force_back) // this one is needed if we skipped cout << " back\n"; // them for the lists above cout << " back\n"; if (med > -1 || bcc_advertise_all || bcc_advertise_nets) cout << " modify\n"; if (bcc_advertise_nets) { if (!nt->prfx_set.isEmpty() && !nt->prfx_set.universal()) { prefix = "advertise"; suffix = ""; next_itrp = cur_itrp; printRoutes(&next_itrp,nt->prfx_set, prefix, suffix); //new } } if (bcc_advertise_all) { cout << " advertise address 255.255.255.255 mask 255.255.255.255\n"; if (bcc_force_back) cout << " back\n"; } if (med > -1 || bcc_advertise_all || bcc_advertise_nets) cout << " back\n"; cout << " back\n"; } // end of if } while (next_itrp); } // end of big for loop if (!import_flag) { cout << " back\n"; cout << "back\n"; } return last; } //////////////////////////////////////////////////////////////////////////////// // FUNCTION NAME: export // // FUNCTIONALITY: Checks if the ASes are present and have export policies and if // so, invokes the print() with appropriate parameters. // // SIGNIFICANT VARIABLES: // autnum : AutNum Object has contact info and routing policy of that AS. // fa : An instance of FilterAction class. // // SIGNIFICANT FUNCTIONS: // getAutNum(): Retrieves the AutNum object for the specified AS number. // // LAST MODIFIED: 13th Sep 1999. // /////////////////////////////////////////////////////////////////////////////// void BccConfig::exportP(ASt asno, IPAddr *addr, ASt peerAS, IPAddr *peer_addr) { // Made asno part of the map name if it's not changed by users sprintf(mapName, mapNameFormat, asno, mapCount++); // get the aut-num object const AutNum *autnum = irr->getAutNum(asno); if (!autnum) { cerr << "Error: no object for AS" << asno << endl; return; } // get matching export attributes AutNumSelector itr(autnum, "export", NULL, peerAS, peer_addr, addr); const FilterAction *fa = itr.first(); if (! fa) { printPolicyWarning(asno, addr, peerAS, peer_addr, "export"); return; } // below is newly added cout << "ip\n" << " bgp\n" << " local-as " << asno << "\n"; if (addr->get_text() && peer_addr->get_text()) { cout << " peer local " << addr->get_text() << " remote "; cout << peer_addr->get_text() << " as " << peerAS << "\n" << " back\n"; } NormalExpression *ne; int last = 0; for (; fa && !last; fa = itr.next()) { ne = NormalExpression::evaluate(fa->filter, peerAS); last = print(ne, fa->action, asno, peerAS, peer_addr,EXPORT); delete ne; } routeMapGenerated = false; prefixListGenerated = false; } //////////////////////////////////////////////////////////////////////////////// // FUNCTION NAME: import // // FUNCTIONALITY: Checks if the ASes are present and have import policies and if // so, invokes the print() with appropriate parameters. // // SIGNIFICANT VARIABLES: // autnum : AutNum Object has contact info and routing policy of that AS. // fa : An instance of FilterAction class. // // SIGNIFICANT FUNCTIONS: // getAutNum(): Retrieves the AutNum object for the specified AS number. // // LAST MODIFIED: 13th Sep 1999. // /////////////////////////////////////////////////////////////////////////////// void BccConfig::importP(ASt asno, IPAddr *addr, ASt peerAS, IPAddr *peer_addr) { // Made asno part of the map name if it's not changed by users sprintf(mapName, mapNameFormat, asno, mapCount++); // get the aut-num object const AutNum *autnum = irr->getAutNum(asno); if (!autnum) { cerr << "Error: no object for AS" << asno << endl; return; } int preAclID = prefixMgr.lastID(); // get matching import attributes AutNumSelector itr(autnum, "import", NULL, peerAS, peer_addr, addr); const FilterAction *fa = itr.first(); if (! fa) { printPolicyWarning(asno, addr, peerAS, peer_addr, "import"); return; } cout << "ip\n" << " bgp\n" << " local-as " << asno << "\n"; if (addr->get_text() && peer_addr->get_text()) { cout << " peer local " << addr->get_text() << " remote "; cout << peer_addr->get_text() << " as " << peerAS << "\n" << " back\n"; } NormalExpression *ne; int last = 0; for (; fa && !last; fa = itr.next()) { ne = NormalExpression::evaluate(fa->filter, peerAS); last = print(ne, fa->action, asno, peerAS, peer_addr, IMPORT); delete ne; } int postAclID = prefixMgr.lastID(); routeMapGenerated = false; prefixListGenerated = false; cout << " back\nback\n#\n"; } //////////////////////////////////////////////////////////////////////////////// // FUNCTION NAME: deflt // // FUNCTIONALITY: Checks if the ASes are present and have default policies and if // so, invokes the print() with appropriate parameters. // // SIGNIFICANT VARIABLES: // autnum : AutNum Object has contact info and routing policy of that AS. // // SIGNIFICANT FUNCTIONS: // getAutNum(): Retrieves the AutNum object for the specified AS number. // // LAST MODIFIED: 13th Sep 1999. // /////////////////////////////////////////////////////////////////////////////// void BccConfig::deflt(ASt asno, ASt peerAS) { // get the aut-num object const AutNum *autnum = irr->getAutNum(asno); if (!autnum) { cerr << "Error: no object for AS" << asno << endl; return; } // get matching default attributes // Modified by wlee // AutNumIterator itr(autnum, "default", peerAS); AutNumDefaultIterator itr(autnum, peerAS); const AttrDefault *deflt = itr.first(); if (! deflt) { cerr << "Warning: AS" << asno << " has no default policy for AS" << peerAS << endl; return; } cout << "ip\n" << " bgp\n" << " local-as " << asno << "\n"; cout << " accept polname InjectDefault\n" << " action accept\n" << " match\n" << " as asnumber " << peerAS << "\n" << " back\n" << " back\n" << " modify\n"; NormalExpression *ne; int last = 0; char buffer[128]; for (; deflt && !last; deflt = itr.next()) { ne = NormalExpression::evaluate(deflt->filter, peerAS); if (ne->is_universal()) { cout << " inject address 0.0.0.0 mask 0.0.0.0\n"; if (bcc_force_back) cout << " back\n"; } else { NormalTerm *nt = ne->first(); RadixSet::SortedPrefixIterator itr(&(ne->first()->prfx_set.members)); u_int addr; u_int leng; char buffer[64]; for (bool ok = itr.first(addr, leng); ok; ok = itr.next(addr, leng)) { cout << " inject address " << int2quad(buffer, addr) << "\n"; if (bcc_force_back) cout << " back\n"; } } if (! bcc_force_back) cout << " back\n"; } cout << " back\n" << " back\n" << " back\n" << "back\n"; cout << "#\n"; }