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