1 //  $Id$
2 // Copyright (c) 2001,2002                        RIPE NCC
3 //
4 // All Rights Reserved
5 //
6 // Permission to use, copy, modify, and distribute this software and its
7 // documentation for any purpose and without fee is hereby granted,
8 // provided that the above copyright notice appear in all copies and that
9 // both that copyright notice and this permission notice appear in
10 // supporting documentation, and that the name of the author not be
11 // used in advertising or publicity pertaining to distribution of the
12 // software without specific, written prior permission.
13 //
14 // THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15 // ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
16 // AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
17 // DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
18 // AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19 // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 //
21 //
22 //  Copyright (c) 1994 by the University of Southern California
23 //  All rights reserved.
24 //
25 //    Permission is hereby granted, free of charge, to any person obtaining a copy
26 //    of this software and associated documentation files (the "Software"), to deal
27 //    in the Software without restriction, including without limitation the rights
28 //    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
29 //    copies of the Software, and to permit persons to whom the Software is
30 //    furnished to do so, subject to the following conditions:
31 //
32 //    The above copyright notice and this permission notice shall be included in
33 //    all copies or substantial portions of the Software.
34 //
35 //    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
36 //    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
37 //    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
38 //    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
39 //    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
40 //    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
41 //    THE SOFTWARE.
42 //
43 //  Questions concerning this software should be directed to
44 //  irrtoolset@cs.usc.edu.
45 //
46 //  Author(s): Cengiz Alaettinoglu <cengiz@ISI.EDU>
47 
48 #include "config.h"
49 #include <cstring>
50 #include <iostream>
51 #include <sstream>
52 #include <iomanip>
53 #include <cctype>
54 #include "normalform/NE.hh"
55 #include "rtconfig.hh"
56 #include "f_cisco.hh"
57 #include "rpsl/schema.hh"
58 
59 using namespace std;
60 
61 #define EXPORT 0
62 #define IMPORT 1
63 
64 char CiscoConfig::mapName[80] = "MyMap";
65 char CiscoConfig::mapNameFormat[80] = "MyMap_%d_%d";
66 bool CiscoConfig::forcedInboundMatchIP = true;
67 bool CiscoConfig::useAclCaches = true;
68 bool CiscoConfig::compressAcls = true;
69 bool CiscoConfig::usePrefixLists = false;
70 bool CiscoConfig::eliminateDupMapParts = false;
71 bool CiscoConfig::forceTilda = false;
72 bool CiscoConfig::emptyLists = false;
73 bool CiscoConfig::peerTemplates = false;
74 int  CiscoConfig::mapIncrements = 1;
75 int  CiscoConfig::mapCount = 1;
76 int  CiscoConfig::mapNumbersStartAt = 1;
77 bool CiscoConfig::firstCommunityList = true;
78 bool CiscoConfig::printRouteMap = true;
79 ostringstream delayoutput;
80 
81 //////////////////////////// caches ////////////////////////////////
82 
83 AccessListManager<regexp_nf>         aspathMgr(50);
84 AccessListManager<SetOfPrefix>       prefixMgr(150);
85 AccessListManager<SetOfIPv6Prefix>   ipv6prefixMgr(150);
86 AccessListManager<SetOfPrefix>       pktFilterMgr(150);
87 AccessListManager<SetOfIPv6Prefix>   ipv6pktFilterMgr(150);
88 AccessListManager<FilterOfCommunity> communityMgr(50);
89 
90 /// access-list and prefix-list names
91 char ipv6_acl[6] = "ipv6-";
92 char ipv6_pl[8] = "ipv6-pl";
93 
ones(unsigned char from,unsigned char to)94 unsigned int ones(unsigned char from, unsigned char to)
95 {
96   unsigned int result = 0;
97   for (int i = 32 - to; i <= 32 - from; i++) result |= (1L << i);
98   return result;
99 }
100 
returnPermitOrDeny(bool allow_flag)101 const char *CiscoConfig::returnPermitOrDeny(bool allow_flag) {
102    if (allow_flag)
103       return " permit ";
104    else
105       return " deny ";
106 }
107 
printRoutes(SetOfIPv6Prefix & nets)108 ListOf2Ints *CiscoConfig::printRoutes(SetOfIPv6Prefix& nets) {
109    if (usePrefixLists)
110       return printPrefixList(nets);
111 
112    // return the access list number if something is printed
113    ListOf2Ints *result;
114 
115    if (nets.universal())
116       return NULL;
117 
118    // check to see if we already printed an identical access list,
119    if (useAclCaches && (result = ipv6prefixMgr.search(nets)))
120       return result;
121 
122    result = ipv6prefixMgr.add(nets);
123    int aclID = ipv6prefixMgr.newID();
124    result->add(aclID, aclID);
125 
126    int allow_flag = 1;
127    if (nets.negated())
128       allow_flag = 0;
129 
130    // clear this access list
131    cout << "!\nno ipv6 access-list " << ipv6_acl << aclID << "\n";
132 
133    // no compressed acls
134 
135 /*   if (compressAcls) {
136       IPv6RadixSet::SortedPrefixRangeIterator itr(&nets.members);
137       ipv6_addt_t addr;
138       u_int leng;
139       u_int start;
140       u_int end;
141       char buffer[256];
142 
143       for (bool ok = itr.first(addr, leng, start, end);
144 	   ok;
145 	   ok = itr.next(addr, leng, start, end)) {
146 	   cout << "ipv6 access-list " << aclID;
147 	    if (allow_flag)
148 	      cout << " permit ";
149 	    else
150 	      cout << " deny ";
151 
152 	    cout << ipv62hex(&addr, buffer) << "   ";
153 	    cout << ipv62hex(buffer, ones(leng + 1, end)) << "   ";
154 	      << "\n";
155       }
156    } else {
157    */
158       IPv6RadixSet::SortedPrefixIterator itr(&nets.members);
159       ipv6_addr_t addr;
160       u_int leng;
161       char buffer[256];
162 
163       for (bool ok = itr.first(addr, leng);
164 	   ok;
165 	   ok = itr.next(addr, leng)) {
166 	 cout << "ipv6 access-list " << ipv6_acl << aclID << returnPermitOrDeny(allow_flag);
167 	 cout << ipv62hex(&addr, buffer) << "/" << leng << " any\n";
168       }
169   // }
170 
171    // terminate the access list
172    cout << "ipv6 access-list " << ipv6_acl << aclID << returnPermitOrDeny(!allow_flag) << "any any" << endl;
173 
174    return result;
175 }
176 
printRoutes(SetOfPrefix & nets)177 ListOf2Ints *CiscoConfig::printRoutes(SetOfPrefix& nets) {
178    if (usePrefixLists)
179       return printPrefixList(nets);
180 
181    // return the access list number if something is printed
182    ListOf2Ints *result;
183 
184    if (nets.universal())
185       return NULL;
186 
187    // check to see if we already printed an identical access list,
188    if (useAclCaches && (result = prefixMgr.search(nets)))
189       return result;
190 
191    result = prefixMgr.add(nets);
192    int aclID = prefixMgr.newID();
193    result->add(aclID, aclID);
194 
195    int allow_flag = 1;
196    if (nets.negated())
197       allow_flag = 0;
198 
199    // clear this access list
200    cout << "!\nno access-list " << aclID << "\n";
201 
202    if (compressAcls) {
203       RadixSet::SortedPrefixRangeIterator itr(&nets.members);
204       u_int addr;
205       u_int leng;
206       u_int start;
207       u_int end;
208       char buffer[64];
209 
210       for (bool ok = itr.first(addr, leng, start, end);
211 	   ok;
212 	   ok = itr.next(addr, leng, start, end)) {
213 	 cout << "access-list " << aclID << returnPermitOrDeny(allow_flag) << "ip ";
214 
215 	 /* need to look at WeeSan's code */
216 	 cout << int2quad(buffer, addr) << "   ";
217 	 cout << int2quad(buffer, ones(leng + 1, end)) << "   ";
218 	 cout << int2quad(buffer, masks[start]) << "   ";
219 	 cout << int2quad(buffer, ones(start + 1, end))
220 	      << "\n";
221       }
222    } else {
223       RadixSet::SortedPrefixIterator itr(&nets.members);
224       u_int addr;
225       u_int leng;
226       char buffer[64];
227 
228       for (bool ok = itr.first(addr, leng);
229 	   ok;
230 	   ok = itr.next(addr, leng)) {
231 	 cout << "access-list " << aclID << returnPermitOrDeny(allow_flag) << "ip ";
232 
233 	 cout << int2quad(buffer, addr) << "   0.0.0.0   ";
234 	 cout << int2quad(buffer, masks[leng]) << "   0.0.0.0\n";
235       }
236    }
237 
238    // terminate the access list
239    cout << "access-list " << aclID  << returnPermitOrDeny(!allow_flag)
240         << "ip 0.0.0.0 255.255.255.255 0.0.0.0 255.255.255.255\n";
241 
242    return result;
243 }
244 
printPrefixList(SetOfIPv6Prefix & nets)245 ListOf2Ints *CiscoConfig::printPrefixList(SetOfIPv6Prefix& nets) {
246 
247    // return the access list number if something is printed
248    ListOf2Ints *result;
249 
250    if (nets.universal())
251       return NULL;
252 
253    // check to see if we already printed an identical access list,
254    if (useAclCaches && (result = ipv6prefixMgr.search(nets)))
255       return result;
256 
257    result = ipv6prefixMgr.add(nets);
258    int aclID = ipv6prefixMgr.newID();
259    result->add(aclID, aclID);
260 
261    int allow_flag = 1;
262    if (nets.negated())
263       allow_flag = 0;
264 
265    // clear this prefix list
266    cout << "!\nno ipv6 prefix-list " << ipv6_pl << aclID << "\n";
267 
268    IPv6RadixSet::SortedPrefixRangeIterator itr(&nets.members);
269    ipv6_addr_t addr;
270    u_int leng;
271    u_int start;
272    u_int end;
273    char buffer[256];
274 
275    for (bool ok = itr.first(addr, leng, start, end);
276 	ok;
277 	ok = itr.next(addr, leng, start, end)) {
278       cout << "ipv6 prefix-list " << ipv6_pl << aclID << returnPermitOrDeny(allow_flag);
279       cout << ipv62hex(&addr, buffer) << "/" << leng;
280       if (start != leng)
281 	      cout << " ge " << start;
282       if (end != leng)
283 	      cout << " le " << end;
284       cout << "\n";
285    }
286 
287    cout << "ipv6 prefix-list " << ipv6_pl << aclID << returnPermitOrDeny(!allow_flag) << "::/0 le 128" << endl;
288 
289    return result;
290 
291 }
292 
printPrefixList(SetOfPrefix & nets)293 ListOf2Ints *CiscoConfig::printPrefixList(SetOfPrefix& nets) {
294    // return the access list number if something is printed
295    ListOf2Ints *result;
296 
297    if (nets.universal())
298       return NULL;
299 
300    // check to see if we already printed an identical access list,
301    if (useAclCaches && (result = prefixMgr.search(nets)))
302       return result;
303 
304    result = prefixMgr.add(nets);
305    int aclID = prefixMgr.newID();
306    result->add(aclID, aclID);
307 
308    int allow_flag = 1;
309    if (nets.negated())
310       allow_flag = 0;
311 
312    // clear this access list
313    cout << "!\nno ip prefix-list pl" << aclID << "\n";
314 
315    RadixSet::SortedPrefixRangeIterator itr(&nets.members);
316    u_int addr;
317    u_int leng;
318    u_int start;
319    u_int end;
320    char buffer[64];
321 
322    for (bool ok = itr.first(addr, leng, start, end);
323 	ok;
324 	ok = itr.next(addr, leng, start, end)) {
325       cout << "ip prefix-list pl" << aclID << returnPermitOrDeny(allow_flag);
326 
327       /* need to look at WeeSan's code */
328       cout << int2quad(buffer, addr) << "/" << leng;
329       if (start != leng)
330 	 cout << " ge " << start;
331       if (end != leng)
332 	 cout << " le " << end;
333       cout << "\n";
334    }
335 
336    // terminate the access list
337    cout << "ip prefix-list pl" << aclID << returnPermitOrDeny(!allow_flag) << "0.0.0.0/0 le 32\n";
338 
339    return result;
340 }
printCommunities(FilterOfCommunity & cm)341 ListOf2Ints *CiscoConfig::printCommunities(FilterOfCommunity& cm) {
342    // return the access list numbers if something is printed
343    ListOf2Ints *result;
344 
345    if (cm.is_universal())
346       return 0;
347 
348    // check to see if we already printed an identical access list,
349    if (useAclCaches && (result = communityMgr.search(cm)))
350       return result;
351 
352    result = communityMgr.add(cm);
353    int aclID;
354 
355    if (firstCommunityList) {
356       firstCommunityList = false;
357       cout << "!\nip bgp-community new-format\n";
358    }
359 
360    // now print the communities
361    // first print the conjuncts which are only positive contains
362    CommunityConjunct *cc;
363    bool first_time = true;
364    for (cc = cm.conjuncts.head(); cc; cc = cm.conjuncts.next(cc)) {
365       if (cc->pe->isEmpty() && cc->n->isEmpty() && cc->ne.isEmpty()
366           && ! cc->p->isEmpty()) {
367          if (first_time) {
368             first_time = false;
369             // clear this access list
370             aclID = communityMgr.newID();
371             result->add(aclID, aclID);
372             cout << "!\nno ip community-list " << aclID << "\n";
373          }
374          cout << "ip community-list " << aclID << " permit ";
375          for (Pix pi = cc->p->first(); pi; cc->p->next(pi)) {
376             CiscoConfig::printCommunity(cout, (*cc->p)(pi));
377             cout << " ";
378          }
379          cout << "\n";
380       }
381    }
382 
383    for (cc = cm.conjuncts.head(); cc; cc = cm.conjuncts.next(cc)) {
384       if (cc->pe->isEmpty() && cc->n->isEmpty() && cc->ne.isEmpty()
385           && ! cc->p->isEmpty()) // this case is done above
386          continue;
387 
388       // clear this access list
389       aclID = communityMgr.newID();
390       cout << "!\nno ip community-list " << aclID << "\n";
391 
392       if (! cc->pe->isEmpty()) {
393          cout << "ip community-list " << aclID << " permit ";
394          for (Pix pi = cc->pe->first(); pi; cc->pe->next(pi)) {
395             CiscoConfig::printCommunity(cout, (*cc->pe)(pi));
396             cout << " ";
397          }
398          cout << "\n";
399          result->add(aclID, aclID, 1);
400          continue; // if pe is non-empty then p, n, ne are all empty
401       }
402 
403       // TGG
404       // ne needs an exact match too. Each element of cc
405       // requires its own (exactly matched) community list
406       //
407       CommunitySet *cs;
408       for (cs = cc->ne.head(); cs; cs = cc->ne.next(cs)) {
409 	 cout << "ip community-list " << aclID << " deny ";
410 	 for (Pix pi = cs->first(); pi; cs->next(pi)) {
411             CiscoConfig::printCommunity(cout, (*cs)(pi));
412             cout << " ";
413 	 }
414 	 cout << "\n";
415 	 result->add(aclID, aclID, 1);
416 	 if (!(cc->p->isEmpty()) ||
417 	     !(cc->n->isEmpty()) ||
418 	     cc->ne.next(cs)) {
419             aclID = communityMgr.newID();
420             cout << "!\nno ip community-list " << aclID << "\n";
421 	 }
422       }
423 
424       // TGG
425       // if there will not follow at least one positive match,
426       // and an ne was encountered, then we must add a community
427       // list that will match anything
428       //
429       if (cc->pe->isEmpty() && cc->p->isEmpty() && cc->n->isEmpty()) {
430         aclID = communityMgr.newID();
431         cout << "!\nno ip community-list " << aclID << "\n";
432         cout << "ip community-list " << aclID << " permit internet\n";
433 	result->add(aclID, aclID);
434 	continue;
435       }
436 
437       Pix pi;
438       for (pi = cc->n->first(); pi; cc->n->next(pi)) {
439          cout << "ip community-list " << aclID << " deny ";
440          CiscoConfig::printCommunity(cout, (*cc->n)(pi));
441          cout << "\n";
442       }
443 
444       if (! cc->p->isEmpty()) {
445          cout << "ip community-list " << aclID << " permit ";
446          for (pi = cc->p->first(); pi; cc->p->next(pi)) {
447             CiscoConfig::printCommunity(cout, (*cc->p)(pi));
448             cout << " ";
449          }
450          cout << "\n";
451       }
452 
453       // TGG
454       // don't do this for ne's, only for n's
455       if (cc->p->isEmpty() && !cc->n->isEmpty())
456          cout << "ip community-list " << aclID << " permit internet\n";
457 
458       result->add(aclID, aclID);
459    }
460 
461    return result;
462 }
463 
printREASno(ostream & out,const RangeList & no)464 void CiscoConfig::printREASno(ostream& out, const RangeList &no) {
465    RangeList::Range *pi;
466    int first = 1;
467    int put_par = 0;
468 
469    if (no.universal())
470       out << "(_[0-9]+)";
471    else {
472       out << "_";
473       pi = no.ranges.head();
474       put_par = ! no.ranges.isSingleton() || pi->high != pi->low || inTilda;
475       if (put_par) {
476 	 if (reSplittable) {
477 	    if (inTilda)
478 	       out << "&";
479 	    else
480 	       out << "@";
481 	 } else {
482 	    out << "(";
483          }
484       }
485 
486       for (; pi; pi = no.ranges.next(pi)) {
487 	 for (int i = pi->low; i <= pi->high; ++i) {
488 	    if (!first)
489 	       out << "|";
490 	    else
491 	       first = 0;
492 	    out << i;
493 	 }
494       }
495 
496       if (put_par)
497          out << ")";
498    }
499 }
500 
printRE_(ostream & os,const regexp & r)501 int CiscoConfig::printRE_(ostream& os, const regexp& r) {
502    static bool inAlternate = false;
503    int flag = 0;
504 
505    if (typeid(r) == typeid(regexp_or)) {
506       bool save = inAlternate;
507 
508       if (!inAlternate) {
509 	 inAlternate = true;
510 	 os << "(";
511       }
512 
513       flag = CiscoConfig::printRE_(os, *((regexp_or &) r).left);
514       os << "|";
515       flag &= CiscoConfig::printRE_(os, *((regexp_or &) r).right);
516 
517       inAlternate = save;
518       if (!inAlternate)
519 	 os  << ")";
520       return flag;
521    }
522 
523    inAlternate = false;
524 
525    if (typeid(r) == typeid(regexp_bol)) {
526       os << "^";
527       return flag;
528    }
529 
530    if (typeid(r) == typeid(regexp_eol)) {
531       os << "$";
532       return 1;
533    }
534 
535    if (typeid(r) == typeid(regexp_symbol)) {
536       CiscoConfig::printREASno(os, ((regexp_symbol &) r).asnumbers);
537       return flag;
538    }
539 
540    if (typeid(r) == typeid(regexp_star)) {
541       bool save = reSplittable;
542       reSplittable = forceTilda;
543       hasTilda = forceTilda;
544       inTilda = forceTilda;
545       os << "(";
546       flag = CiscoConfig::printRE_(os, *((regexp_star &) r).left);
547       os << ")*";
548       reSplittable = save;
549       return flag;
550    }
551 
552    if (typeid(r) == typeid(regexp_plus)) {
553       bool save = reSplittable;
554       reSplittable = forceTilda;
555       hasTilda = forceTilda;
556       inTilda = forceTilda;
557       os << "(";
558       flag = CiscoConfig::printRE_(os, *((regexp_plus &) r).left);
559       os << ")+";
560       reSplittable = save;
561       return flag;
562    }
563 
564    if (typeid(r) == typeid(regexp_tildastar)) {
565       hasTilda = true;
566       inTilda = true;
567       os << "(";
568       flag = CiscoConfig::printRE_(os, *((regexp_star &) r).left);
569       os << ")*";
570       inTilda = false;
571       return flag;
572    }
573 
574    if (typeid(r) == typeid(regexp_tildaplus)) {
575       hasTilda = true;
576       inTilda = true;
577       os << "(";
578       flag = CiscoConfig::printRE_(os, *((regexp_plus &) r).left);
579       os << ")+";
580       inTilda = false;
581       return flag;
582    }
583 
584    if (typeid(r) == typeid(regexp_question)) {
585       os << "(";
586       flag = CiscoConfig::printRE_(os, *((regexp_question &) r).left);
587       os << ")?";
588       return flag;
589    }
590 
591    if (typeid(r) == typeid(regexp_cat)) {
592       CiscoConfig::printRE_(os, *((regexp_cat &) r).left);
593       flag = CiscoConfig::printRE_(os, *((regexp_cat &) r).right);
594       return flag;
595    }
596 
597    assert(1);
598    os << "REGEXP_UNKNOWN";
599    return flag;
600 }
601 
printRE(ostream & s,const regexp & r,int aclID,bool permit)602 void CiscoConfig::printRE(ostream &s,
603 		          const regexp &r,
604 			  int aclID,
605 			  bool permit){
606    ostringstream out;
607    out << "ip as-path access-list "
608        << aclID
609        << (permit ? " permit " : " deny ");
610    reSplittable = true;
611    hasTilda = false;
612    inTilda = false;
613    if (!CiscoConfig::printRE_(out, r)) // true if the expression was missing $
614       out << "_";
615    out << endl;
616 
617    int lineLen = out.str().length();
618 
619    // for string.h, we need to ensure that p is a char *, not const char *
620    char *p = strdup(out.str().c_str());
621 
622    if (lineLen < 240 && ! hasTilda) {
623       for (char *q = strchr(p, '@'); q; q = strchr(q, '@'))
624          *q = '(';
625       s << p;
626    } else { // need to split into multiple lines
627       if (hasTilda) {
628          for (char *q = strchr(p, '@'); q; q = strchr(q, '@'))
629             *q = '(';
630          for (char *q = strchr(p, '&'); q; q = strchr(q, '&'))
631             *q = '@';
632       }
633 
634       char *q, *q2;
635       char *r = NULL;
636       int size = 0;
637       for (q = strchr(p, '@'); q; q = strchr(q, '@')) {
638          q2 = strchr(q, ')');
639          if (q2 - q > size) {
640             r = q;
641             size = q2 - q;
642          }
643          *q = '(';
644          q = q2;
645       }
646       if (!r) {
647          s << out.str();
648          cerr << "Warning: ip as-path access-list is too long for cisco to handle" << endl;
649       } else {
650          char *r2;
651 	 int inc;
652 	 if (hasTilda) {
653 	     inc = 1;
654 	 } else {
655 	     if (240 - lineLen + size > 5) {
656 	         inc = 240 - lineLen + size;
657 	     } else {
658 	         inc = 5;
659 	     }
660 	 }
661 	 q = strchr(r, ')') + 1;
662 	 *r = 0;
663 	 r++;
664 	 while (r < q) {
665 	    r2 = r + inc;
666 	    if (r2 > q - 2)
667 	       r2 = q - 1;
668 	    else
669 	       while (*r2 != '|' && r2 < q - 1)
670 		  r2++;
671 	    *r2 = 0;
672 	    s << p << "(" << r << ")" << q;
673 	    r = r2 + 1;
674 	 }
675       }
676    }
677    free(p);
678 }
679 
printASPaths(regexp_nf & path)680 ListOf2Ints* CiscoConfig::printASPaths(regexp_nf& path) {
681 // return the access list number if something is printed
682    ListOf2Ints *result;
683 
684    if (path.is_universal())
685       return NULL;
686 
687    // check to see if we already printed an identical access list
688    if (useAclCaches && (result = aspathMgr.search(path)))
689       return result;
690 
691    result = aspathMgr.add(path);
692    int aclID;
693 
694    regexp_nf::RegexpConjunct *rc;
695    regexp_nf::RegexpConjunct::ReInt *ri;
696    regexp_nf::RegexpConjunct::ReInt *positive_ri = NULL;
697    int sno = 0;
698 
699    // we will print as few access lists as necessary, often more than one
700    // to minimize the number of access lists generated, we will do 3 passes
701    // pass 1: RegexpConjuncts w/ one positive as path and no negative
702    // pass 2: RegexpConjuncts w/ one or zero positive as path and negatives
703    // pass 3: rest
704 
705    bool needNewAcl = true;
706    int pass1_found = 0;
707    for (rc = path.rclist.head(); rc; rc = path.rclist.next(rc)) {
708       ri = rc->regexs.head();
709       if (rc->regexs.isSingleton() && !ri->negated) {
710 	 pass1_found = 1;
711 	 if (needNewAcl) {
712 	    needNewAcl = false;
713 	    aclID = aspathMgr.newID();
714             cout << "!\nno ip as-path access-list  " << aclID << "\n";
715          }
716          CiscoConfig::printRE(cout, *ri->re, aclID, true);
717 	 rc->mark = 1;
718       } else
719 	 rc->mark = 0;
720    }
721 
722    // pass 2
723    int pass2_found = 0;
724    for (rc = path.rclist.head(); rc; rc = path.rclist.next(rc)) {
725       if (rc->mark) // done in pass 1, skip
726 	 continue;
727 
728       int found = 0;
729       for (ri = rc->regexs.head(); ri; ri = rc->regexs.next(ri)) {
730 	 if (!ri->negated)
731 	    found++;
732 	 if (found > 1)
733 	    break;
734       }
735       if (found <= 1) { // really found
736 	 pass2_found = 1;
737 	 rc->mark = 1;
738 	 if (needNewAcl) {
739 	    aclID = aspathMgr.newID();
740 	    cout << "!\nno ip as-path access-list  " << aclID << "\n";
741 	 }
742 	 for (ri = rc->regexs.head(); ri; ri = rc->regexs.next(ri)) {
743 	    if (!ri->negated)
744 	       positive_ri = ri;
745 	    else {
746 	       CiscoConfig::printRE(cout, *ri->re, aclID, false);
747 	    }
748 	 }
749 	 if (positive_ri) {
750 	    CiscoConfig::printRE(cout, *positive_ri->re, aclID, true);
751 	 } else {
752 	    cout << "ip as-path access-list " << aclID
753 		 << " permit .*\n";
754 	 }
755 	 result->add(aclID, aclID);
756 	 needNewAcl = true;
757      }
758    }
759 
760    if (pass1_found && !pass2_found) {
761       result->add(aclID, aclID);
762    }
763 
764    // pass 3
765    for (rc = path.rclist.head(); rc; rc = path.rclist.next(rc)) {
766       if (rc->mark) // done in pass 1 or 2, skip
767 	 continue;
768 
769       aclID = aspathMgr.newID();
770       cout << "!\nno ip as-path access-list  " << aclID << "\n";
771 
772       // print negative ones all in one access list
773       sno = aclID;
774       for (ri = rc->regexs.head(); ri; ri = rc->regexs.next(ri)) {
775 	 if (ri->negated) {
776 	    CiscoConfig::printRE(cout, *ri->re, aclID, false);
777 	 }
778       }
779       // print positives ones each in its own access list, except first
780       int first = 1;
781       for (ri = rc->regexs.head(); ri; ri = rc->regexs.next(ri)) {
782 	 if (!ri->negated) {
783 	    if (first)
784 	       first = 0;
785 	    else {
786 	       aclID = aspathMgr.newID();
787 	       cout << "!\nno ip as-path access-list  " << aclID << "\n";
788  	    }
789 	    CiscoConfig::printRE(cout, *ri->re, aclID, true);
790 	 }
791       }
792 
793       if (first) { // no positive one found
794 	 cout << "ip as-path access-list " << aclID
795 	      << " permit .*\n";
796       }
797 
798       result->add(sno, aclID);
799    }
800 
801    return result;
802 }
803 
printCommunity(ostream & os,unsigned int i)804 inline void CiscoConfig::printCommunity(ostream &os, unsigned int i) {
805    if (i == COMMUNITY_INTERNET)
806       os << "internet";
807    else if (i == COMMUNITY_NO_EXPORT)
808       os << "no-export";
809    else if (i == COMMUNITY_NO_EXPORT_SUBCONFED)
810       os << "no-export-subconfed";
811    else if (i == COMMUNITY_NO_ADVERTISE)
812       os << "no-advertise";
813    else {
814       int high = i >> 16;
815       int low  = i & 0xFFFF;
816       if (high == 0xFFFF)
817 	 os << i;
818       else
819 	 os << high << ":" << low;
820    }
821 }
822 
printCommunityList(ostream & os,ItemList * args)823 void CiscoConfig::printCommunityList(ostream &os, ItemList *args) {
824    for (Item *cmnty = args->head(); cmnty; cmnty = args->next(cmnty)) {
825       os << " ";
826 
827       if (typeid(*cmnty) == typeid(ItemINT)) {
828 	 printCommunity(os, ((ItemINT *) cmnty)->i);
829 	 continue;
830       }
831 
832       if (typeid(*cmnty) == typeid(ItemWORD)) {
833 	 if (!strcasecmp(((ItemWORD *)cmnty)->word, "no_advertise"))
834 	    printCommunity(os, COMMUNITY_NO_ADVERTISE);
835 	 else if (!strcasecmp(((ItemWORD *)cmnty)->word, "no_export"))
836 	    printCommunity(os, COMMUNITY_NO_EXPORT);
837 	 else if (!strcasecmp(((ItemWORD *)cmnty)->word,"no_export_subconfed"))
838 	    printCommunity(os, COMMUNITY_NO_EXPORT_SUBCONFED);
839 	 else
840 	    printCommunity(os, COMMUNITY_INTERNET);
841 	 continue;
842       }
843 
844       if (typeid(*cmnty) == typeid(ItemList)) {
845 	 int high = ((ItemINT *) ((ItemList *) cmnty)->head())->i;
846 	 int low  = ((ItemINT *) ((ItemList *) cmnty)->tail())->i;
847 	 printCommunity(os, (high << 16) + low);
848 	 continue;
849       }
850    }
851 }
852 
printCommunitySetList(ostream & os,ItemList * args)853 int CiscoConfig::printCommunitySetList(ostream &os, ItemList *args) {
854 
855    int aclID = communityMgr.newID();
856    os << "!\nno ip community-list " << aclID << "\n";
857    os << "ip community-list " << aclID << " permit ";
858    CiscoConfig::printCommunityList(os, args);
859    os << "\n!\n";
860 
861 return aclID;
862 }
863 
864 
printActions(ostream & os,PolicyActionList * actions,ItemAFI * afi)865 void CiscoConfig::printActions(ostream &os, PolicyActionList *actions, ItemAFI *afi) {
866 #define UNIMPLEMENTED_METHOD \
867    cerr << "Warning: unimplemented method " \
868 	<< actn->rp_attr->name << "." << actn->rp_method->name << endl
869 
870    PolicyAction *actn;
871    for (actn = actions->head(); actn; actn = actions->next(actn)) {
872       if (actn->rp_attr == dctn_rp_pref) {
873 	 if (actn->rp_method == dctn_rp_pref_set) {
874 	    int pref = ((ItemINT *) actn->args->head())->i;
875 	    os << " set local-preference " << (preferenceCeiling-pref) << "\n";
876 	 } else
877 	    UNIMPLEMENTED_METHOD;
878 	 continue;
879       }
880 
881       if (actn->rp_attr == dctn_rp_nhop) {
882 	 if (actn->rp_method == dctn_rp_nhop_set) {
883 
884       if (afi->is_ipv4() && (typeid(*(actn->args->head())) == typeid(ItemIPV4))) {
885         char buffer[32];
886         IPAddr *ip = ((ItemIPV4 *) actn->args->head())->ipv4;
887         ip->get_text(buffer);
888         os << " set ip next-hop " << buffer << "\n";
889       } else if (afi->is_ipv6() && (typeid(*(actn->args->head())) == typeid(ItemIPV6))) {
890         char buffer[50];
891         IPv6Addr *ip = ((ItemIPV6 *) actn->args->head())->ipv6;
892         ip->get_text(buffer);
893         os << " set ipv6 next-hop " << buffer << "\n";
894       } else {
895         cout << "Warning: next-hop address family doesn't match protocol address family, ignoring next-hop..." << endl;
896       }
897 	 } else
898 	    UNIMPLEMENTED_METHOD;
899 	 continue;
900       }
901 
902       if (actn->rp_attr == dctn_rp_dpa) {
903 	 if (actn->rp_method == dctn_rp_dpa_set) {
904 	    int dpa = ((ItemINT *) actn->args->head())->i;
905 	    os << " set dpa " << dpa << "\n";
906 	 } else
907 	    UNIMPLEMENTED_METHOD;
908 	 continue;
909       }
910 
911       if (actn->rp_attr == dctn_rp_med) {
912 	 if (actn->rp_method == dctn_rp_med_set) {
913 	    Item *item = actn->args->head();
914 	    if (typeid(*item) == typeid(ItemINT))
915 	       os << " set metric " << ((ItemINT *) item)->i << "\n";
916 	    else
917 	       os << " set metric-type internal\n";
918 	 } else
919 	    UNIMPLEMENTED_METHOD;
920 	 continue;
921       }
922 
923       if (actn->rp_attr == dctn_rp_community) {
924 	 if (actn->rp_method == dctn_rp_community_setop) {
925 	    os << " set community ";
926 	    printCommunityList(os, (ItemList *) actn->args->head());
927 	    os << "\n";
928 	 } else if (actn->rp_method == dctn_rp_community_appendop) {
929 	    os << " set community ";
930 	    printCommunityList(os, (ItemList *) actn->args->head());
931 	    os << " additive\n";
932 	 } else if (actn->rp_method == dctn_rp_community_append) {
933 	    os << " set community ";
934 	    printCommunityList(os, actn->args);
935 	    os << " additive\n";
936          } else if (actn->rp_method == dctn_rp_community_delete) {
937             int commlist = printCommunitySetList(delayoutput, actn->args);
938             os << " set comm-list " << commlist << " delete\n";
939 	 } else
940 	    UNIMPLEMENTED_METHOD;
941 	 continue;
942       }
943 
944       if (actn->rp_attr == dctn_rp_aspath) {
945 	 if (actn->rp_method == dctn_rp_aspath_prepend) {
946 	    os << " set as-path prepend ";
947 	    for (Item *plnd = actn->args->head();
948 		 plnd;
949 		 plnd = actn->args->next(plnd))
950 	       os << ((ItemASNO *) plnd)->asno << " ";
951 	    os << "\n";
952 	 } else
953 	    UNIMPLEMENTED_METHOD;
954 	 continue;
955       }
956 
957       cerr << "Warning: unimplemented attribute "
958 	   << *actn->rp_attr << endl;
959    }
960 
961    os << "exit\n"; // exit route map config mode
962    os << delayoutput.str();
963    delayoutput.str("");
964 
965 }
966 
print(NormalExpression * ne,PolicyActionList * actn,int import_flag,ItemAFI * afi)967 int CiscoConfig::print(NormalExpression *ne,
968 		       PolicyActionList *actn,
969 		       int import_flag,
970 		       ItemAFI *afi) {
971    int last = 0;
972    static ListOf2Ints empty_list(1);
973 
974    Debug(Channel(DBG_RTC_CISCO) << "# ne: " << *ne << "\n");
975 
976    // modified by katie@ripe.net to handle any/not any expr
977    // for prefix filters, cisco only
978 
979    if (ne->is_any() != NEITHER)
980 	cerr << "Warning: filter \"" << mapName << "\" matches ANY/NOT ANY" << endl;
981 
982    if (ne->isEmpty())
983    {
984 	if (ne->singleton_flag == -1)
985 	{
986 		if (emptyLists)
987 		{
988 			// generate an empty filter; no afi means ipv4
989       if (!afi || (afi && afi->is_ipv4())) {
990         FilterOfPrefix *fltr = (FilterOfPrefix *) new SetOfPrefix;
991         NormalTerm *nt = new NormalTerm;
992         nt->prfx_set = *fltr;
993         nt->make_universal(NormalTerm::PRFX);
994         *ne += nt;
995       } else {
996         FilterOfIPv6Prefix *fltr = (FilterOfIPv6Prefix *) new SetOfIPv6Prefix;
997         NormalTerm *nt = new NormalTerm;
998         nt->ipv6_prfx_set = *fltr;
999         nt->make_universal(NormalTerm::IPV6_PRFX);
1000         *ne += nt;
1001       }
1002 		}
1003 	}
1004 	else
1005 		return last;
1006    }
1007    if (ne->is_universal())
1008    {
1009 	if (ne->singleton_flag == -1)
1010 	{
1011 		if (emptyLists)
1012 		{
1013 			// generate empty filter and negate to enable 'permit'
1014       if (!afi || (afi && afi->is_ipv4())) {
1015         FilterOfPrefix *fltr = (FilterOfPrefix *) new SetOfPrefix;
1016         fltr->not_ = true;
1017         ne->first()->prfx_set = *fltr;
1018       } else {
1019         FilterOfIPv6Prefix *fltr = (FilterOfIPv6Prefix *) new SetOfIPv6Prefix;
1020         fltr->not_ = true;
1021         ne->first()->ipv6_prfx_set = *fltr;
1022       }
1023 		}
1024 	}
1025 	else
1026 		last = 1;
1027    }
1028 
1029    bool needToPrintNoRouteMap = false;
1030    if (strcmp(mapName, lastMapName)) {
1031       strcpy(lastMapName, mapName);
1032       needToPrintNoRouteMap = true;
1033       routeMapID = mapNumbersStartAt;
1034    }
1035    routeMapGenerated = true;
1036    prefixListGenerated = false;
1037 
1038    for (NormalTerm *nt = ne->first(); nt; nt = ne->next()) {
1039       // only ipv4 OR ipv6 list gets printed in every loop
1040       ListOf2Ints *prfx_acls   = printRoutes(nt->prfx_set);
1041       ListOf2Ints *ipv6_prfx_acls   = printRoutes(nt->ipv6_prfx_set);
1042       ListOf2Ints *aspath_acls = printASPaths(nt->as_path);
1043       ListOf2Ints *comm_acls   = printCommunities(nt->community);
1044 
1045       if (prfx_acls && !ipv6_prfx_acls) {
1046 	      prefixListGenerated = true;
1047         ipv6_prfx_acls = &empty_list;
1048         distributeListNo = prfx_acls->head()->start;
1049       } else if (!prfx_acls && ipv6_prfx_acls) {
1050 	      prefixListGenerated = true;
1051         prfx_acls = &empty_list;
1052         distributeListNo = ipv6_prfx_acls->head()->start;
1053       } else {
1054         prfx_acls = &empty_list;
1055         ipv6_prfx_acls = &empty_list;
1056       }
1057 
1058       if (!aspath_acls)
1059 	      aspath_acls = &empty_list;
1060       if (!comm_acls)
1061 	      comm_acls = &empty_list;
1062 
1063       ListNodeOf2Ints *asp, *cmp, *prp;
1064       int i;
1065 
1066       if (printRouteMap) {
1067 	      if (needToPrintNoRouteMap) {
1068 	         cout << "!\nno route-map " << mapName << "\n";
1069 	         needToPrintNoRouteMap = false;
1070 	      }
1071 
1072 	    for (asp = aspath_acls->head(); asp; asp = aspath_acls->next(asp)) {
1073 	      for (cmp = comm_acls->head(); cmp; cmp = comm_acls->next(cmp)) {
1074 	        cout << "!\nroute-map " << mapName
1075 		      << " permit " << routeMapID << "\n";
1076 	        routeMapID += mapIncrements;
1077 	        for (i = asp->start; i <= asp->end; i++)
1078       		  cout << " match as-path " << i << "\n";
1079 	        for (i = cmp->start; i <= cmp->end; i++)
1080 		        cout << " match community " << i
1081 		        << (cmp->flag ? " exact\n" : "\n");
1082 	       if (!import_flag || forcedInboundMatchIP) {
1083 		       for (prp = prfx_acls->head(); prp; prp =prfx_acls->next(prp)) {
1084 		         for (i = prp->start; i <= prp->end; i++) {
1085 			         if (usePrefixLists)
1086 			           cout << " match ip address prefix-list pl"
1087 				         << i <<"\n";
1088 			         else
1089 			         cout << " match ip address " << i << "\n";
1090                }
1091            }
1092            if (afi->is_ipv6()) {
1093              for (prp = ipv6_prfx_acls->head(); prp; prp =ipv6_prfx_acls->next(prp)) {
1094                for (i = prp->start; i <= prp->end; i++) {
1095                  if (usePrefixLists)
1096                    cout << " match ipv6 address prefix-list " << ipv6_pl
1097                    << i <<"\n";
1098                  else
1099                    cout << " match ipv6 address " << ipv6_acl << i << "\n";
1100                }
1101              }
1102            }
1103            CiscoConfig::printActions(cout, actn, afi);
1104          }
1105 	      }
1106 	    }
1107     }
1108   }
1109 
1110 
1111    return last;
1112 }
1113 
1114 // Reimplemented to handle different afi's
printNeighbor(int import,ASt asno,ASt peerAS,char * neighbor,bool peerGroup,ItemAFI * peer_afi,ItemAFI * filter_afi)1115 bool CiscoConfig::printNeighbor(int import,
1116 				ASt asno,
1117 				ASt peerAS,
1118 				char *neighbor,
1119 				bool peerGroup,
1120 				ItemAFI *peer_afi,
1121 				ItemAFI *filter_afi) {
1122    bool afi_activate = false;
1123 
1124    if (! printRouteMap)
1125       return false;
1126 
1127    if (!peerGroup && (!filter_afi->is_default() || !peer_afi->is_default()))
1128       afi_activate = true;
1129 
1130    const char *indent = (afi_activate) ? " " : "";
1131    const char *direction = (import == IMPORT) ? "in" : "out";
1132 
1133    if (!routeMapGenerated && (!import || ! prefixListGenerated)) {
1134       // yes we are conciously printing an "not any" policy
1135       cout << "!\nno route-map " << mapName << "\n";
1136       cout << "!\nroute-map " << mapName << " deny " << mapNumbersStartAt << "\n";
1137       routeMapGenerated = true;
1138    }
1139 
1140    // create bgp process
1141    cout << "!\nrouter bgp " << asno << "\n!\n";
1142 
1143    if (peerGroup && CiscoConfig::peerTemplates) {
1144      cout << "template peer-policy " << neighbor <<"\n";
1145      if (routeMapGenerated)
1146        cout << " route-map " << mapName << " " << direction << "\n";
1147      cout << " remove-private-as\n";
1148      cout << "exit-peer-policy\n!\n";
1149    } else if (peerGroup && !CiscoConfig::peerTemplates) {
1150      cout << " neighbor " << neighbor << " peer-group\n";
1151    } else {
1152      cout << " neighbor "   << neighbor << " remote-as " << peerAS << "\n";
1153    }
1154 
1155    if (afi_activate ) {
1156      if (strcmp(filter_afi->name(),"ipv6") == 0) {
1157        cout << " address-family " << "ipv4" << endl;
1158        cout << indent <<" no neighbor " << neighbor << " activate\n";
1159        cout << " address-family " << "ipv6 unicast" << endl;
1160        cout << indent <<" neighbor " << neighbor << " activate\n";
1161        cout << " address-family " << "ipv6 multicast" << endl;
1162        cout << indent <<" neighbor " << neighbor << " activate\n";
1163      } else if (strcmp(filter_afi->name(),"ipv6.unicast") == 0) {
1164        cout << " address-family " << "ipv4" << endl;
1165        cout << indent <<" no neighbor " << neighbor << " activate\n";
1166        cout << " address-family " << "ipv6 unicast" << endl;
1167        cout << indent <<" neighbor " << neighbor << " activate\n";
1168      } else if (strcmp(filter_afi->name(),"ipv4.multicast") == 0) {
1169        cout << " address-family " << "ipv4 multicast" << endl;
1170        cout << indent <<" neighbor " << neighbor << " activate\n";
1171      } else if (strcmp(filter_afi->name(),"ipv6.multicast") == 0) {
1172        cout << " address-family " << "ipv4" << endl;
1173        cout << indent <<" no neighbor " << neighbor << " activate\n";
1174        cout << " address-family " << "ipv6 multicast" << endl;
1175        cout << indent <<" neighbor " << neighbor << " activate\n";
1176      } else if (strcmp(filter_afi->name(),"ipv4.unicast") == 0) {
1177        cout << " address-family " << "ipv4 unicast" << endl;
1178        cout << indent <<" neighbor " << neighbor << " activate\n";
1179      }
1180      // ought to handle afi any too, but that's not just done by naming it here
1181    }
1182 
1183    if (routeMapGenerated && !peerGroup)
1184       cout << indent << " neighbor " << neighbor
1185 	   << " route-map " << mapName << " " << direction << "\n";
1186 
1187    if (import && ! forcedInboundMatchIP && prefixListGenerated) {
1188       if (usePrefixLists)
1189 	 cout << indent << " neighbor " << neighbor
1190 	      << " prefix-list pl" << distributeListNo << " in\n";
1191       else
1192 	 cout << indent << " neighbor " << neighbor
1193 	      << " distribute-list " << distributeListNo << " in\n";
1194    }
1195 
1196    if (afi_activate)
1197       cout << " exit\n"; // exit address-family config mode
1198    cout << "!\n";
1199 
1200    if (!peerGroup)
1201    cout << "exit\n" ; // exit neighbor config mode explicitly if not peer group
1202 
1203    return true;
1204 }
1205 
exportP(ASt asno,MPPrefix * addr,ASt peerAS,MPPrefix * peer_addr)1206 void CiscoConfig::exportP(ASt asno, MPPrefix *addr,
1207 			 ASt peerAS, MPPrefix *peer_addr) {
1208 
1209    // get the aut-num object
1210    const AutNum *autnum = irr->getAutNum(asno);
1211 
1212    if (!autnum) {
1213       cerr << "Error: no object for AS" << asno << endl;
1214       return;
1215     }
1216 
1217    // get matching export & mp-export attributes
1218    AutNumSelector<AttrExport> itr(autnum, "export",
1219                                   NULL, peerAS, peer_addr, addr);
1220    AutNumSelector<AttrExport> itr1(autnum, "mp-export",
1221           NULL, peerAS, peer_addr, addr);
1222 
1223    List<FilterAction> *common_list = itr.get_fa_list();
1224    common_list->splice(*(itr1.get_fa_list()));
1225 
1226    FilterAction *fa = common_list->head();
1227    if (! fa) {
1228      printPolicyWarning(asno, addr, peerAS, peer_addr, "export/mp-export");
1229      return;
1230    }
1231    ItemList *afi_list = itr.get_afi_list();
1232    afi_list->merge(*(itr1.get_afi_list()));
1233 
1234    if (afi_list->isEmpty()) {
1235      cout << "Warning: No AFI resulted from policy" << endl;
1236    }
1237 
1238    NormalExpression *ne;
1239    NormalExpression done;
1240    int last = 0;
1241 
1242    for (Item *afi = afi_list->head(); afi; afi = afi_list->next(afi)) {
1243      // Made asno part of the map name if it's not changed by users
1244      sprintf(mapName, mapNameFormat, peerAS, mapCount++);
1245 
1246      for (fa = common_list->head(); fa && !last; fa = common_list->next(fa)) {
1247        ne = NormalExpression::evaluate(new FilterAFI((ItemAFI *) afi->dup(), fa->filter), peerAS);
1248 
1249        if (eliminateDupMapParts) {
1250                NormalExpression ne2(*ne);
1251          NormalExpression done2(done);
1252          done2.do_not();
1253          ne2.do_and(done2);
1254 
1255            if (! ne2.isEmpty()) {
1256            last = print(ne, fa->action, EXPORT, (ItemAFI *) afi);
1257          }
1258 
1259                done.do_or(*ne);
1260        } else {
1261                  last = print(ne, fa->action, EXPORT, (ItemAFI *) afi);
1262        }
1263 
1264        delete ne;
1265      }
1266 
1267      // peer_afi should be afi of peer IPs, filter_afi is the one specified in filter
1268      ItemAFI *peer_afi = new ItemAFI(peer_addr->get_afi());
1269      printNeighbor(EXPORT, asno, peerAS, peer_addr->get_ip_text(), false, (ItemAFI *) peer_afi, (ItemAFI *) afi);
1270 
1271      routeMapGenerated = false;
1272      prefixListGenerated = false;
1273   }
1274 }
1275 
importP(ASt asno,MPPrefix * addr,ASt peerAS,MPPrefix * peer_addr)1276 void CiscoConfig::importP(ASt asno, MPPrefix *addr,
1277        ASt peerAS, MPPrefix *peer_addr) {
1278 
1279    // get the aut-num object
1280    const AutNum *autnum = irr->getAutNum(asno);
1281 
1282    if (!autnum) {
1283       cerr << "Error: no object for AS" << asno << endl;
1284       return;
1285     }
1286 
1287    // get matching import & mp-import attributes
1288    AutNumSelector<AttrImport> itr(autnum, "import",
1289 				  NULL, peerAS, peer_addr, addr);
1290    AutNumSelector<AttrImport> itr1(autnum, "mp-import",
1291           NULL, peerAS, peer_addr, addr);
1292 
1293    List<FilterAction> *common_list = itr.get_fa_list();
1294    common_list->splice(*(itr1.get_fa_list()));
1295 
1296    FilterAction *fa = common_list->head();
1297    if (! fa) {
1298      printPolicyWarning(asno, addr, peerAS, peer_addr, "import/mp-import");
1299      return;
1300    }
1301    ItemList *afi_list = itr.get_afi_list();
1302    afi_list->merge(*(itr1.get_afi_list()));
1303 
1304    if (afi_list->isEmpty()) {
1305      cout << "Warning: No AFI resulted from policy" << endl;
1306    }
1307 
1308    NormalExpression *ne;
1309    NormalExpression done;
1310    int last = 0;
1311 
1312    for (Item *afi = afi_list->head(); afi; afi = afi_list->next(afi)) {
1313      // Made asno part of the map name if it's not changed by users
1314      sprintf(mapName, mapNameFormat, peerAS, mapCount++);
1315 
1316      for (fa = common_list->head(); fa && !last; fa = common_list->next(fa)) {
1317        ne = NormalExpression::evaluate(new FilterAFI((ItemAFI *) afi->dup(), fa->filter), peerAS);
1318 
1319        if (eliminateDupMapParts) {
1320 	       NormalExpression ne2(*ne);
1321       	 NormalExpression done2(done);
1322       	 done2.do_not();
1323       	 ne2.do_and(done2);
1324 
1325      	   if (! ne2.isEmpty()) {
1326       	   last = print(ne, fa->action, IMPORT, (ItemAFI *) afi);
1327          }
1328 
1329 	       done.do_or(*ne);
1330        } else {
1331 	         last = print(ne, fa->action, IMPORT, (ItemAFI *) afi);
1332        }
1333 
1334        delete ne;
1335      }
1336 
1337      // peer_afi should be afi of peer IPs, filter_afi is the one specified in filter
1338      ItemAFI *peer_afi = new ItemAFI(peer_addr->get_afi());
1339      printNeighbor(IMPORT, asno, peerAS, peer_addr->get_ip_text(), false, (ItemAFI *) peer_afi, (ItemAFI *) afi);
1340 
1341      routeMapGenerated = false;
1342      prefixListGenerated = false;
1343   }
1344 }
1345 
static2bgp(ASt asno,MPPrefix * addr)1346 void CiscoConfig::static2bgp(ASt asno, MPPrefix *addr) {
1347 
1348    // get the aut-num object
1349    const AutNum *autnum = irr->getAutNum(asno);
1350 
1351    if (!autnum) {
1352       cerr << "Error: no object for AS" << asno << endl;
1353       return;
1354    }
1355 
1356    // get matching import attributes
1357    AutNumSelector<AttrImport> itr(autnum, "import",
1358 				  NULL, asno, addr, addr, "STATIC");
1359    AutNumSelector<AttrImport> itr1(autnum, "mp-import",
1360           NULL, asno, addr, addr, "STATIC");
1361 
1362    List<FilterAction> *common_list = itr.get_fa_list();
1363    common_list->splice(*(itr1.get_fa_list()));
1364 
1365    const FilterAction *fa = common_list->head();
1366    if (! fa)
1367       cerr << "Warning: AS" << asno
1368 	   << " has no static2bgp policy for AS" << asno << endl;
1369 
1370    NormalExpression *ne;
1371    NormalExpression done;
1372    int last = 0;
1373 
1374    ItemList *afi_list = itr.get_afi_list();
1375    afi_list->merge(*(itr1.get_afi_list()));
1376 
1377    for (Item *afi = afi_list->head(); afi; afi = afi_list->next(afi)) {
1378      // Made asno part of the map name if it's not changed by users
1379      sprintf(mapName, mapNameFormat, asno, mapCount++);
1380 
1381      for (; fa; fa = common_list->next(fa)) {
1382         ne = NormalExpression::evaluate(new FilterAFI((ItemAFI *) afi->dup(), fa->filter), asno);
1383 
1384       if (eliminateDupMapParts) {
1385 	      NormalExpression ne2(*ne);
1386 	      NormalExpression done2(done);
1387       	done2.do_not();
1388 	      ne2.do_and(done2);
1389 
1390 	      if (! ne2.isEmpty())
1391 	        last = print(ne, fa->action, EXPORT, (ItemAFI *) afi);
1392 
1393 	      done.do_or(*ne);
1394       } else
1395 	      last = print(ne, fa->action, EXPORT, (ItemAFI *) afi);
1396 
1397       delete ne;
1398     }
1399     cout << "router bgp " << asno << "\n!\n";
1400     bool afi_activate = false;
1401     if (!((ItemAFI *) afi)->is_default())
1402       afi_activate = true;
1403     const char *indent = (afi_activate) ? " " : "";
1404     if (routeMapGenerated) {
1405       if (afi_activate)
1406          cout << " address-family " << *afi << endl;
1407       cout << indent << " redistribute static route-map " << mapName << "\n";
1408       if (afi_activate)
1409          cout << " exit\n!\n" << endl;
1410     }
1411     routeMapGenerated = false;
1412     prefixListGenerated = false;
1413 
1414    }
1415 }
1416 
deflt(ASt asno,ASt peerAS)1417 void CiscoConfig::deflt(ASt asno, ASt peerAS) {
1418    // get the aut-num object
1419    const AutNum *autnum = irr->getAutNum(asno);
1420 
1421    if (!autnum) {
1422       cerr << "Error: no object for AS" << asno << endl;
1423       return;
1424     }
1425 
1426    // get matching default attributes
1427    AutNumDefaultIterator itr(autnum, peerAS);
1428    const AttrDefault *deflt = itr.first();
1429    if (! deflt) {
1430       cerr << "Warning: AS" << asno
1431            << " has no default policy for AS" << peerAS << endl;
1432       return;
1433    }
1434 
1435    cout << "!\n";
1436 
1437    NormalExpression *ne;
1438    int last = 0;
1439    for (; deflt && !last; deflt = itr.next()) {
1440       ne = NormalExpression::evaluate(deflt->filter, peerAS);
1441 
1442       if (ne->is_universal()) {
1443          cout << "ip default-network 0.0.0.0\n";
1444       } else {
1445          RadixSet::SortedPrefixIterator itr(&(ne->first()->prfx_set.members));
1446          u_int addr;
1447          u_int leng;
1448          char buffer[64];
1449 
1450          for (bool ok = itr.first(addr, leng);
1451               ok;
1452               ok = itr.next(addr, leng)) {
1453             cout << "ip default-network "
1454                  << int2quad(buffer, addr)
1455                  << "\n";
1456          }
1457       }
1458    }
1459 }
1460 
networks(ASt asno)1461 void CiscoConfig::networks(ASt asno) {
1462    const MPPrefixRanges *nets = irr->expandAS(asno);
1463    MPPrefixRanges::const_iterator p;
1464    static char buffer[128];
1465 
1466    if (nets) {
1467      cout << "!\n";
1468      for (p = nets->begin(); p != nets->end(); ++p) {
1469        if (p->ipv4) {
1470          cout << "network " << p->ipv4->get_ip_text()
1471             << " mask " << int2quad(buffer, p->ipv4->get_mask())
1472             << "\n";
1473        }
1474      }
1475    }
1476 }
1477 
IPv6networks(ASt asno)1478 void CiscoConfig::IPv6networks(ASt asno) {
1479    const MPPrefixRanges *nets = irr->expandAS(asno);
1480    MPPrefixRanges::const_iterator p;
1481 
1482    if (nets) {
1483      cout << "!\n";
1484      bool afi_activate = true;
1485      for (p = nets->begin(); p != nets->end(); ++p) {
1486        if (p->ipv6) {
1487          if (afi_activate) {
1488            cout << "address-family ipv6" << endl; /// unicast/multicast?
1489            afi_activate = false;
1490          }
1491          cout << " network " << p->ipv6->get_ip_text()
1492               << " mask " << p->ipv6->get_mask()
1493               << "\n";
1494        }
1495      }
1496      if (!afi_activate)
1497         cout << "exit\n";
1498    }
1499 }
1500 
printPacketFilter(SetOfPrefix & set)1501 int CiscoConfig::printPacketFilter(SetOfPrefix &set) {
1502    RadixSet::SortedPrefixIterator itr(&set.members);
1503    u_int addr;
1504    u_int leng;
1505    char buffer[64];
1506    bool allow_flag = ! set.negated();
1507    ListOf2Ints *result;
1508 
1509    // check to see if we already printed an identical access list,
1510    if (useAclCaches && (result = pktFilterMgr.search(set)))
1511       return result->head()->start;
1512 
1513    result = pktFilterMgr.add(set);
1514    int aclID = prefixMgr.newID();
1515    result->add(aclID, aclID);
1516 
1517    cout << "!\nno access-list " << aclID << "\n";
1518 
1519    for (bool ok = itr.first(addr, leng); ok; ok = itr.next(addr, leng)) {
1520       if (!addr && !leng) // skip 0.0.0.0/0
1521 	 continue;
1522 
1523       cout << "access-list " << aclID << returnPermitOrDeny(allow_flag) << "ip ";
1524 
1525       cout << int2quad(buffer, addr) << " ";
1526       cout << int2quad(buffer, ~masks[leng]) << " any \n";
1527    }
1528 
1529    if (set.universal()) // handle 0.0.0.0/0
1530      allow_flag = false;
1531 
1532    cout << "access-list " << aclID << returnPermitOrDeny(!allow_flag) << "ip any any" << endl;
1533 
1534    return aclID;
1535 }
1536 
printPacketFilter(SetOfIPv6Prefix & set)1537 int CiscoConfig::printPacketFilter(SetOfIPv6Prefix &set) {
1538    IPv6RadixSet::SortedPrefixIterator itr(&set.members);
1539    ipv6_addr_t addr;
1540    u_int leng;
1541    ipv6_addr_t rngs;
1542    char buffer[256];
1543    bool allow_flag = ! set.negated();
1544    ListOf2Ints *result;
1545 
1546    // check to see if we already printed an identical access list,
1547    if (useAclCaches && (result = ipv6pktFilterMgr.search(set)))
1548       return result->head()->start;
1549 
1550    result = ipv6pktFilterMgr.add(set);
1551    int aclID = ipv6prefixMgr.newID();
1552    result->add(aclID, aclID);
1553 
1554    cout << "!\nno ipv6 access-list " << ipv6_acl << aclID << "\n";
1555 
1556    for (bool ok = itr.first(addr, leng); ok; ok = itr.next(addr, leng)) {
1557       if (!addr && !leng)
1558         continue;
1559 
1560       cout << "ipv6 access-list " << ipv6_acl << aclID << returnPermitOrDeny(allow_flag) << "ip ";
1561 
1562       cout << ipv62hex(&addr, buffer) << " ";
1563       cout << ipv62hex(&(addr.getmask(leng)), buffer) << " any \n";
1564    }
1565 
1566    if (set.universal()) // handle ::/0
1567      allow_flag = false;
1568 
1569    cout << "ipv6 access-list " << ipv6_acl << aclID << returnPermitOrDeny(!allow_flag) << "ip any any" << endl;
1570 
1571    return aclID;
1572 }
1573 
1574 
inboundPacketFilter(char * ifname,ASt as,MPPrefix * addr,ASt peerAS,MPPrefix * peerAddr)1575 void CiscoConfig::inboundPacketFilter(char *ifname, ASt as, MPPrefix* addr,
1576 			       ASt peerAS, MPPrefix* peerAddr) {
1577    int import = IMPORT;
1578    const char *rpsltag = (import == IMPORT) ? "import" : "export";
1579    const char *mp_rpsltag = (import == IMPORT) ? "mp-import" : "mp-export";
1580    const char *direction = (import == IMPORT) ? " in" : " out";
1581 
1582    // get the aut-num object
1583    const AutNum *autnum = irr->getAutNum(as);
1584 
1585    if (!autnum) {
1586       cerr << "Error: no object for AS" << as << endl;
1587       return;
1588     }
1589 
1590    // get matching import & mp-import attributes
1591    AutNumSelector<AttrImport> itr(autnum, rpsltag, NULL, peerAS, peerAddr, addr);
1592    AutNumSelector<AttrImport> itr1(autnum, mp_rpsltag, NULL, peerAS, peerAddr, addr);
1593 
1594    List<FilterAction> *common_list = itr.get_fa_list();
1595    common_list->splice(*(itr1.get_fa_list()));
1596 
1597    FilterAction *fa = common_list->head();
1598    if (! fa) {
1599      printPolicyWarning(as, addr, peerAS, peerAddr, mp_rpsltag);
1600      return;
1601    }
1602    ItemList *afi_list = itr.get_afi_list();
1603    afi_list->merge(*(itr1.get_afi_list()));
1604    int last = 0;
1605    SetOfPrefix set;
1606    SetOfIPv6Prefix ipv6_set;
1607 
1608    for (fa = common_list->head(); fa && !last; fa = common_list->next(fa)) {
1609      NormalExpression *ne = NormalExpression::evaluate(new FilterAFI(afi_list,fa->filter), peerAS);
1610      for (NormalTerm *nt = ne->first(); nt; nt = ne->next()) { //either v4 or v6
1611        if (nt->ipv6_prfx_set.universal())
1612          set |= nt->prfx_set;
1613        else
1614          ipv6_set |= nt->ipv6_prfx_set;
1615      }
1616    }
1617 
1618    int aclid;
1619    int ipv6_aclid;
1620 
1621    if (!set.isEmpty())
1622       aclid = printPacketFilter(set);
1623    if (!ipv6_set.isEmpty())
1624       ipv6_aclid = printPacketFilter(ipv6_set);
1625 
1626    if (!set.isEmpty())
1627      cout << "\n!\ninterface " << ifname << "\n ip access-group " << aclid << direction << endl;
1628 
1629    if (!ipv6_set.isEmpty()) {
1630      cout << "address family ipv6" << endl;
1631      cout << " interface " << ifname << "\n ipv6 access-group " << ipv6_acl << ipv6_aclid << direction << endl;
1632      cout << "exit" << endl;
1633    }
1634 }
1635 
outboundPacketFilter(char * ifname,ASt as,MPPrefix * addr,ASt peerAS,MPPrefix * peerAddr)1636 void CiscoConfig::outboundPacketFilter(char *ifname, ASt as, MPPrefix* addr,
1637 				       ASt peerAS, MPPrefix* peerAddr) {
1638    int import = EXPORT;
1639    const char *rpsltag = (import == IMPORT) ? "import" : "export";
1640    const char *mp_rpsltag = (import == IMPORT) ? "mp-import" : "mp-export";
1641    const char *direction = (import == IMPORT) ? " in" : " out";
1642 
1643    // get the aut-num object
1644    const AutNum *autnum = irr->getAutNum(as);
1645 
1646    if (!autnum) {
1647       cerr << "Error: no object for AS" << as << endl;
1648       return;
1649     }
1650 
1651    // get matching import & mp-import attributes
1652    AutNumSelector<AttrExport> itr(autnum, rpsltag, NULL, peerAS, peerAddr, addr);
1653    AutNumSelector<AttrExport> itr1(autnum, mp_rpsltag, NULL, peerAS, peerAddr, addr);
1654 
1655    List<FilterAction> *common_list = itr.get_fa_list();
1656    common_list->splice(*(itr1.get_fa_list()));
1657 
1658    FilterAction *fa = common_list->head();
1659    if (! fa) {
1660      printPolicyWarning(as, addr, peerAS, peerAddr, mp_rpsltag);
1661      return;
1662    }
1663    ItemList *afi_list = itr.get_afi_list();
1664    afi_list->merge(*(itr1.get_afi_list()));
1665    int last = 0;
1666    SetOfPrefix set;
1667    SetOfIPv6Prefix ipv6_set;
1668 
1669    for (fa = common_list->head(); fa && !last; fa = common_list->next(fa)) {
1670      NormalExpression *ne = NormalExpression::evaluate(new FilterAFI(afi_list,fa->filter), peerAS);
1671      for (NormalTerm *nt = ne->first(); nt; nt = ne->next()) { //either v4 or v6
1672        if (nt->ipv6_prfx_set.universal())
1673          set |= nt->prfx_set;
1674        else
1675          ipv6_set |= nt->ipv6_prfx_set;
1676      }
1677    }
1678 
1679    int aclid;
1680    int ipv6_aclid;
1681 
1682    if (!set.isEmpty())
1683       aclid = printPacketFilter(set);
1684    if (!ipv6_set.isEmpty())
1685       ipv6_aclid = printPacketFilter(ipv6_set);
1686 
1687    if (!set.isEmpty())
1688      cout << "\n!\ninterface " << ifname << "\n ip access-group " << aclid << direction << endl;
1689 
1690    if (!ipv6_set.isEmpty()) {
1691      cout << "address family ipv6" << endl;
1692      cout << " interface " << ifname << "\n ipv6 access-group " << ipv6_acl << ipv6_aclid << direction << endl;
1693      cout << "exit" << endl;
1694    }
1695 }
1696 
importGroup(ASt asno,char * pset)1697 void CiscoConfig::importGroup(ASt asno, char * pset) {
1698    int import = IMPORT;
1699    // get the aut-num object
1700    const AutNum *autnum = irr->getAutNum(asno);
1701    const char *rpsltag = (import == IMPORT) ? "import" : "export";
1702    const char *mp_rpsltag = (import == IMPORT) ? "mp-import" : "mp-export";
1703 
1704    if (!autnum) {
1705       cerr << "Error: no object for AS" << asno << endl;
1706       return;
1707     }
1708 
1709    SymID psetID = symbols.symID(pset);
1710    // get matching import attributes
1711    AutNumSelector<AttrImport> itr(autnum, rpsltag, psetID, ~0, NULL, NULL);
1712    AutNumSelector<AttrImport> itr1(autnum, mp_rpsltag, psetID, ~0, NULL, NULL);
1713 
1714    List<FilterAction> *common_list = itr.get_fa_list();
1715    common_list->splice(*(itr1.get_fa_list()));
1716 
1717    FilterAction *fa = common_list->head();
1718    if (! fa) {
1719      cerr << "Warning: AS" << asno << " has no " << rpsltag << "/" << mp_rpsltag
1720           << " policy for " << pset << endl;
1721      return;
1722    }
1723 
1724    ItemList *afi_list = itr.get_afi_list();
1725    afi_list->merge(*(itr1.get_afi_list()));
1726 
1727    NormalExpression *ne;
1728    int last = 0;
1729 
1730    for (Item *afi = afi_list->head(); afi; afi = afi_list->next(afi)) {
1731      // Made asno part of the map name if it's not changed by users
1732      sprintf(mapName, mapNameFormat, asno, mapCount++);
1733      for (fa = common_list->head(); fa && !last; fa = common_list->next(fa)) {
1734        ne = NormalExpression::evaluate(new FilterAFI((ItemAFI *) afi->dup(), fa->filter), ~0);
1735        last = print(ne, fa->action, import, (ItemAFI *) afi);;
1736        delete ne;
1737      }
1738    }
1739    // afi is ignored here
1740    printNeighbor(import, asno, 0, pset, true, NULL, NULL);
1741 
1742    const PeeringSet *prngSet = irr->getPeeringSet(psetID);
1743    if (prngSet) {
1744      AutNumPeeringIterator aut_itr(autnum);
1745 
1746      for (Item *afi = afi_list->head(); afi; afi = afi_list->next(afi)) {
1747        bool afi_activate = false;
1748        ItemAFI *iafi = (ItemAFI *)afi;
1749        if (!iafi->is_default())
1750          afi_activate = true;
1751        const char *indent = (afi_activate) ? " " : "";
1752 
1753        cout << " address-family " << iafi->name_afi() << " " << iafi->name_safi() << endl;
1754        for (AttrIterator<AttrPeering> itr(prngSet, "peering"); itr; itr++) {
1755          if (typeid(*itr()->peering->peerRtrs) == typeid(FilterRouter)
1756               && typeid(*itr()->peering->peerASes) == typeid(FilterASNO))
1757            cout << " neighbor " << *itr()->peering->peerRtrs
1758                 << " remote-as " << ((FilterASNO *)itr()->peering->peerASes)->asno << endl;
1759          if (typeid(*itr()->peering->peerRtrs) == typeid(FilterRouter)
1760               && typeid(*itr()->peering->peerASes) == typeid(FilterASNO)) {
1761            if (afi_activate)
1762              cout << indent << " neighbor " << *itr()->peering->peerRtrs << " activate\n";
1763            if (!CiscoConfig::peerTemplates)
1764              cout << indent << " neighbor " << *itr()->peering->peerRtrs << " peer-group " << pset << "\n";
1765            if (CiscoConfig::peerTemplates)
1766              cout << indent << " neighbor " << *itr()->peering->peerRtrs  << " inherit peer-policy " << pset << "\n";
1767          }
1768        }
1769 
1770        cout << " address-family ipv6 unicast" << endl;
1771        for (AttrIterator<AttrPeering> itr(prngSet, "mp-peering"); itr; itr++) {
1772          if (typeid(*itr()->peering->peerRtrs) == typeid(FilterRouter)
1773               && typeid(*itr()->peering->peerASes) == typeid(FilterASNO)) {
1774            if (afi_activate)
1775              cout << indent << " neighbor " << *itr()->peering->peerRtrs << " activate\n";
1776            if (!CiscoConfig::peerTemplates)
1777              cout << indent << " neighbor " << *itr()->peering->peerRtrs << " peer-group " << pset << "\n";
1778            if (CiscoConfig::peerTemplates)
1779            cout << indent << " neighbor " << *itr()->peering->peerRtrs  << " inherit peer-policy " << pset << "\n";
1780          }
1781        }
1782 
1783        if (afi_activate)
1784           cout << " exit\n!\n";
1785      }
1786      cout << "exit\n!\n";
1787    }
1788 
1789    routeMapGenerated = false;
1790    prefixListGenerated = false;
1791 }
1792 
exportGroup(ASt asno,char * pset)1793 void CiscoConfig::exportGroup(ASt asno, char * pset) {
1794    int import = EXPORT;
1795    // get the aut-num object
1796    const AutNum *autnum = irr->getAutNum(asno);
1797    const char *rpsltag = (import == IMPORT) ? "import" : "export";
1798    const char *mp_rpsltag = (import == IMPORT) ? "mp-import" : "mp-export";
1799 
1800    if (!autnum) {
1801       cerr << "Error: no object for AS" << asno << endl;
1802       return;
1803     }
1804 
1805    SymID psetID = symbols.symID(pset);
1806    // get matching import attributes
1807    AutNumSelector<AttrExport> itr(autnum, rpsltag, psetID, ~0, NULL, NULL);
1808    AutNumSelector<AttrExport> itr1(autnum, mp_rpsltag, psetID, ~0, NULL, NULL);
1809 
1810    List<FilterAction> *common_list = itr.get_fa_list();
1811    common_list->splice(*(itr1.get_fa_list()));
1812 
1813    FilterAction *fa = common_list->head();
1814    if (! fa) {
1815      cerr << "Warning: AS" << asno << " has no " << rpsltag << "/" << mp_rpsltag
1816           << " policy for " << pset << endl;
1817      return;
1818    }
1819 
1820    ItemList *afi_list = itr.get_afi_list();
1821    afi_list->merge(*(itr1.get_afi_list()));
1822 
1823    NormalExpression *ne;
1824    int last = 0;
1825 
1826    for (Item *afi = afi_list->head(); afi; afi = afi_list->next(afi)) {
1827      // Made asno part of the map name if it's not changed by users
1828      sprintf(mapName, mapNameFormat, asno, mapCount++);
1829      for (fa = common_list->head(); fa && !last; fa = common_list->next(fa)) {
1830        ne = NormalExpression::evaluate(new FilterAFI((ItemAFI *) afi->dup(), fa->filter), ~0);
1831        last = print(ne, fa->action, import, (ItemAFI *) afi);;
1832        delete ne;
1833      }
1834    }
1835    // afi is ignored here
1836    printNeighbor(import, asno, 0, pset, true, NULL, NULL);
1837 
1838    const PeeringSet *prngSet = irr->getPeeringSet(psetID);
1839    if (prngSet) {
1840      AutNumPeeringIterator aut_itr(autnum);
1841 
1842      for (Item *afi = afi_list->head(); afi; afi = afi_list->next(afi)) {
1843        bool afi_activate = false;
1844        ItemAFI *iafi = (ItemAFI *)afi;
1845        if (!iafi->is_default())
1846          afi_activate = true;
1847        const char *indent = (afi_activate) ? " " : "";
1848        cout << " address-family " << iafi->name_afi() << " " << iafi->name_safi() << endl;
1849 
1850        for (AttrIterator<AttrPeering> itr(prngSet, "peering"); itr; itr++) {
1851          if (typeid(*itr()->peering->peerRtrs) == typeid(FilterRouter)
1852             && typeid(*itr()->peering->peerASes) == typeid(FilterASNO)) {
1853            cout << " neighbor " << *itr()->peering->peerRtrs
1854                 << " remote-as " << ((FilterASNO *)itr()->peering->peerASes)->asno << endl;
1855          }
1856          if (typeid(*itr()->peering->peerRtrs) == typeid(FilterRouter)
1857               && typeid(*itr()->peering->peerASes) == typeid(FilterASNO)) {
1858            if (afi_activate)
1859              cout << indent << " neighbor " << *itr()->peering->peerRtrs << " activate\n";
1860            if (!CiscoConfig::peerTemplates)
1861              cout << indent << " neighbor " << *itr()->peering->peerRtrs << " peer-group " << pset << "\n";
1862            if (CiscoConfig::peerTemplates)
1863              cout << indent << " neighbor " << *itr()->peering->peerRtrs  << " inherit peer-policy " << pset << "\n";
1864          }
1865        }
1866 
1867        cout << " address-family ipv6 unicast" << endl;
1868        for (AttrIterator<AttrPeering> itr(prngSet, "mp-peering"); itr; itr++) {
1869          if (typeid(*itr()->peering->peerRtrs) == typeid(FilterRouter)
1870             && typeid(*itr()->peering->peerASes) == typeid(FilterASNO)) {
1871            cout << " neighbor " << *itr()->peering->peerRtrs
1872                 << " remote-as " << ((FilterASNO *)itr()->peering->peerASes)->asno << endl;
1873          }
1874          if (typeid(*itr()->peering->peerRtrs) == typeid(FilterRouter)
1875               && typeid(*itr()->peering->peerASes) == typeid(FilterASNO)) {
1876            if (afi_activate)
1877              cout << indent << " neighbor " << *itr()->peering->peerRtrs << " activate\n";
1878            if (!CiscoConfig::peerTemplates)
1879              cout << indent << " neighbor " << *itr()->peering->peerRtrs << " peer-group " << pset << "\n";
1880            if (CiscoConfig::peerTemplates)
1881            cout << indent << " neighbor " << *itr()->peering->peerRtrs  << " inherit peer-policy " << pset << "\n";
1882          }
1883        }
1884 
1885        if (afi_activate)
1886           cout << " exit\n!\n";
1887      }
1888      cout << "exit\n!\n";
1889    }
1890 
1891    routeMapGenerated = false;
1892    prefixListGenerated = false;
1893 }
1894