// $Id: f_gated.cc,v 4.10 2002/05/16 13:43:13 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. // // Author(s): Cengiz Alaettinoglu #include "config.h" #include #include #include #include #include "normalform/NE.hh" #include "irr/irr.hh" #include "irr/autnum.hh" #include "RtConfig.hh" #include "f_gated.hh" #include "rpsl/schema.hh" #define DBG_GATED 7 void GatedConfig::printASPath(FilterOfASPath &re) { regexp *reg = re.re->construct(); RangeList::prefix_str = ""; cout << "<" << *reg << ">"; delete reg; // ideally, we could just do: // cout << *re.re; // but re.re may have ^ or $, the gated does not have // more work than it deserves ... } void GatedConfig::printActions(PolicyActionList *actions) { #define UNIMPLEMENTED_METHOD \ cerr << "Warning: unimplemented method " \ << actn->rp_attr->name << "." << actn->rp_method->name << endl int pref = -1; int dpa = -1; int med = -1; PolicyAction *actn; for (actn = actions->head(); actn; actn = actions->next(actn)) { if (actn->rp_attr == dctn_rp_pref) { if (actn->rp_method == dctn_rp_pref_set) { pref = ((ItemINT *) actn->args->head())->i; } else UNIMPLEMENTED_METHOD; continue; } if (actn->rp_attr == dctn_rp_dpa) { if (actn->rp_method == dctn_rp_dpa_set) { dpa = ((ItemINT *) actn->args->head())->i; } else UNIMPLEMENTED_METHOD; continue; } if (actn->rp_attr == dctn_rp_med) { if (actn->rp_method == dctn_rp_med_set) { Item *item = actn->args->head(); if (typeid(*item) == typeid(ItemINT)) med = ((ItemINT *) item)->i; else UNIMPLEMENTED_METHOD; } else UNIMPLEMENTED_METHOD; continue; } if (actn->rp_attr == dctn_rp_community) { if (actn->rp_method == dctn_rp_community_setop) { UNIMPLEMENTED_METHOD; } else if (actn->rp_method == dctn_rp_community_appendop) { UNIMPLEMENTED_METHOD; } else if (actn->rp_method == dctn_rp_community_append) { UNIMPLEMENTED_METHOD; } else UNIMPLEMENTED_METHOD; continue; } if (actn->rp_attr == dctn_rp_aspath) { if (actn->rp_method == dctn_rp_aspath_prepend) { UNIMPLEMENTED_METHOD; } else UNIMPLEMENTED_METHOD; continue; } cerr << "Warning: unimplemented attribute " << *actn->rp_attr << endl; } if (pref != -1) cout << " preference " << normalizePref(pref) << " "; if (med != -1) cout << " metric " << med << " "; if (dpa != -1) cout << " DPA " << dpa << " "; } void GatedConfig::printRoutes(SetOfPrefix &nets, PolicyActionList *action, int import_flag) { static char buffer[128]; if (nets.isEmpty()) return; RadixSet::SortedPrefixIterator itr(&nets.members); u_int addr; u_int leng; for (bool ok = itr.first(addr, leng); ok; ok = itr.next(addr, leng)) { if (!import_flag) cout << " "; cout << " " << int2quad(buffer, addr) << " masklen " << leng << " exact"; if (action) { printActions(action); cout << ";\n"; } else cout << "\trestrict;\n"; } } void GatedConfig::printRoutes(int include, List &rlist, int import_flag) { SetOfPrefix nets_covered; PolicyActionList *allAction = (PolicyActionList *) NULL; SetOfPrefix prfx; Result *r; for (r = rlist.head(); r; r = rlist.next(r), include >>= 1) if (include & 1) { prfx = *r->prfx_set(); ~nets_covered; prfx &= nets_covered; ~nets_covered; if (!prfx.isEmpty()) { nets_covered |= prfx; if (! allAction && (nets_covered.negated() || nets_covered.universal())) allAction = r->action; else printRoutes(prfx, r->action, import_flag); } } if (! import_flag) cout << " "; if (! allAction) cout << " all restrict;\n"; else { if (nets_covered.negated()) { ~nets_covered; printRoutes(nets_covered, NULL, import_flag); } cout << " all "; printActions(allAction); cout << ";\n"; } } // Gated first looks for an aspath match. If it finds one, it checks prefixes // associated with that aspath. If no prefix matches, gated stops the search. // There may be a later aspath that also matches with a matching prefix // as well. There is no way to continue the search after an aspath match. // the only work around is the following: // with n (as-path expression, netlist, action) triplets // we have to generate 2^n-1 gated import statements // one for each possible aspath intersection combinations. void GatedConfig::normalize(List &result, List &rlist) { f_gated_node *node, *nptr, *nptr2; unsigned int fill; unsigned int i; Result *r; int last = 0; for (i = 1, r = rlist.head(); r; r = rlist.next(r), i <<= 1) { for (nptr = result.head(); nptr; nptr = result.next(nptr)) if (r->as_path() && nptr->as_path == *r->as_path()) break; if (nptr) nptr->contains |= i; else { node = new f_gated_node; node->as_path = *r->as_path(); node->contains = i; result.append(node); } Debug(Channel(DBG_GATED) << hex << i << "\n"); } for (nptr = result.head(); nptr; nptr = result.next(nptr)) { for (fill = 0, i = 1, r = rlist.head(); r; r = rlist.next(r), fill |= i, i <<= 1) { Debug(Channel(DBG_GATED) << nptr->contains << " " << i << " "); if (!(nptr->contains & i) && !(nptr->contains & fill)) { node = new f_gated_node; node->as_path = nptr->as_path; node->as_path &= *r->as_path(); if (!node->as_path.isEmpty()) { node->contains = nptr->contains | i; result.append(node); Debug(Channel(DBG_GATED) << hex << node->contains); } else delete node; } Debug(Channel(DBG_GATED) << "\n"); } } FilterOfASPath as_path_covered, tmp_as_path; for (nptr = result.tail(), last = 0; nptr && !last; nptr = nptr2) { nptr2 = result.prev(nptr); if (!nptr->as_path.is_universal()) { tmp_as_path = as_path_covered; ~tmp_as_path; nptr->as_path &= tmp_as_path; } if (nptr->as_path.isEmpty()) { result.remove(nptr); } else { tmp_as_path = nptr->as_path; as_path_covered |= tmp_as_path; last = as_path_covered.is_universal(); } } for (nptr = nptr2; nptr && last; nptr = result.prev(nptr)) result.remove(nptr); } void GatedConfig::importP(ASt asno, IPAddr *addr, ASt peerAS, IPAddr *peer_addr) { static unsigned int lastImportingASNo = 0; // get the aut-num object const AutNum *autnum = irr->getAutNum(asno); if (!autnum) { cerr << "Error: no object for AS" << asno << endl; return; } if (lastImportingASNo != asno) { fillPrefMap(autnum); lastImportingASNo = asno; } AutNumSelector itr(autnum, "import", NULL, peerAS, peer_addr, addr); const FilterAction *fa = itr.first(); if (! fa) { printPolicyWarning(asno, addr, peerAS, peer_addr, "import"); return; } // for each import policy // make rlist contain a list of (ne, action) pairs // that will be imported List rlist; NormalExpression *ne; int last = 0; for (fa = itr.first(); fa && !last; fa = itr.next()) { ne = NormalExpression::evaluate(fa->filter, peerAS); if (ne->isEmpty()) { delete ne; continue; } for (NormalTerm *nt = ne->first(); nt; nt = ne->next()) { Result *r = new Result; r->ne = new NormalExpression; *(r->ne) += new NormalTerm(*nt); r->action = (PolicyActionList *) fa->action->dup(); rlist.append(r); } if (ne->is_universal()) { delete ne; break; } delete ne; } if (rlist.size() > 32) { cerr << "Error: expression is too complicated for gated, contains more than 32 (as-path expression, netlist, pref) triplets, which may cause billions of gated import/export statements..." << endl; rlist.clear(); return; } List result; normalize(result, rlist); f_gated_node *nptr; for (nptr = result.tail(); nptr; nptr = result.prev(nptr)) { cout << "import proto bgp "; if (result.isSingleton() && nptr->as_path.is_universal()) cout << "as " << peerAS << " {\n"; else { cout << "aspath "; printASPath(nptr->as_path); cout << " origin any {\n"; } printRoutes(nptr->contains, rlist, 1); cout << "};\n\n"; } result.clear(); rlist.clear(); } void GatedConfig::exportP(ASt asno, IPAddr *addr, ASt peerAS, IPAddr *peer_addr) { // get the aut-num object const AutNum *autnum = irr->getAutNum(asno); if (!autnum) { cerr << "Error: no object for AS" << asno << endl; return; } AutNumSelector itr(autnum, "export", NULL, peerAS, peer_addr, addr); const FilterAction *fa = itr.first(); if (! fa) { printPolicyWarning(asno, addr, peerAS, peer_addr, "export"); return; } // for each import policy // make rlist contain a list of (ne, action) pairs // that will be imported List rlist; NormalExpression *ne; int last = 0; for (fa = itr.first(); fa && !last; fa = itr.next()) { ne = NormalExpression::evaluate(fa->filter, peerAS); if (ne->isEmpty()) { delete ne; continue; } for (NormalTerm *nt = ne->first(); nt; nt = ne->next()) { Result *r = new Result; r->ne = new NormalExpression; *(r->ne) += new NormalTerm(*nt); r->action = (PolicyActionList *) fa->action->dup(); rlist.append(r); } if (ne->is_universal()) { delete ne; break; } delete ne; } if (rlist.size() > 32) { cerr << "Error: expression is too complicated for gated, contains more than 32 (as-path expression, netlist, pref) triplets, which may cause billions of gated import/export statements..." << endl; rlist.clear(); return; } List result; normalize(result, rlist); f_gated_node *nptr; for (nptr = result.tail(); nptr; nptr = result.prev(nptr)) { cout << " proto bgp "; if (result.isSingleton() && nptr->as_path.is_universal()) cout << "aspath .* origin any {\n"; else { cout << "aspath "; printASPath(nptr->as_path); cout << " origin any {\n"; } printRoutes(nptr->contains, rlist, 0); cout << " };\n\n"; } result.clear(); rlist.clear(); } int GatedConfig::normalizePref(int pref) { for (int i = 0; prefMap[i] != -1 && i < 256; ++i) if (prefMap[i] == pref) return i; return 255; } void GatedConfig::fillPrefMap(const AutNum *an) { prefMap[0] = -1; // walk over all imports of an AttrIterator itr(an, "import"); const AttrImport *import; const AttrProtocol *prot=schema.searchProtocol("BGP4"); for (import = itr.first(); import; import = itr.next()) if (import->fromProt == prot && import->intoProt == prot) _fillPrefMap(import->policy); } void GatedConfig::_fillPrefMap(PolicyExpr *policy) { if (typeid(*policy) == typeid(PolicyTerm)) { for (ListIterator pf(*(PolicyTerm *) policy); pf; ++pf) for (ListIterator pa(*pf->peeringActionList); pa; ++pa) for (ListIterator actn(*pa->action); actn; ++actn) if (actn->rp_attr == dctn_rp_pref && actn->rp_method == dctn_rp_pref_set) _fillPrefMap(((ItemINT *) actn->args->head())->i); } else if (typeid(*policy) == typeid(PolicyRefine)) { _fillPrefMap(((PolicyRefine *) policy)->left); _fillPrefMap(((PolicyRefine *) policy)->right); } else if (typeid(*policy) == typeid(PolicyExcept)) { _fillPrefMap(((PolicyExcept *) policy)->left); _fillPrefMap(((PolicyExcept *) policy)->right); } } void GatedConfig::_fillPrefMap(int pref) { int i; for (i = 0; prefMap[i] <= pref && prefMap[i] != -1 && i < 256; ++i) if (prefMap[i] == pref) return; if (prefMap[i] != -1 && prefMap[i] > pref) { for (; prefMap[i] != -1 && i < 256; ++i) { int save = prefMap[i]; prefMap[i] = pref; pref = save; } } if (i < 255) { prefMap[i] = pref; prefMap[i+1] = -1; } else { prefMap[255] = -1; cerr << "Warning: more than 255 distinct preferences with gated/RSd." << endl; } }