Attached is a patch to add a number of features to bgpd, and fix a couple of bugs. It applies cleanly against 0.89 and has a couple of patches I already sent to the list included (table-map (with a couple of fixes for the implicit withdraw issue, I raised with Kunihiro), and the Collision detection patch). Its a large patch but adds several features that I needed before I could start using Zebra seriously. Any issues please send to the mailing list. This patch addes: o table-map RIB filtering o set table for putting routes into particular kernel tables o Community regular expressions o Community stripping o bgp enfore-first-as o Community matching fix o Collision detection issue Documentation on what these do: table-map route-map-name ------------------------ Applies a route-map to routes being passed to the Zebra daemon. Useful if trying to avoid having every route in the kernel routing tables, or if you want different routes to go into different tables. eg: router bgp 1234 table-map FIB-FILTER ip as-path access-list NATIONAL permit _4321_ route-map FIB-FILTER match as-path NATIONAL set table 20 set-table NN ------------ Used in a route-map to set the routing table to be used for the route. This is handled as an "internal" attibute, so can be set on incoming route-maps or a table-map. It is not passed on to other BGP speakers. See example above. ip community-list NN|NAME regexp ----------------------------- Community-lists have been extended to allow the matching of communities based on a regular expression. Each community is tested against the regular expression, and if any communty is matched, then the permit or deny action is performed. For example, if a route has the following communities: BGP routing table entry for 9.20.0.0/17 Paths: (1 available, best #1, table Default-IP-Routing-Table) (65001) 1234 4321 6789 10.1.1.1 from 10.2.1.4 (10.2.1.4) Origin IGP, metric 0, localpref 100, valid, confed-external, best Community: 1234:2010 1234:2011 1234:2014 1234:3002 1234:3004 Last update: Sat Oct 28 18:18:43 2000 The following regular expression would match the route: ip community-list TEST permit (1234|4321):201. because 1234:2010 matches. Regular expressions can be used in the same list as normal communities: ! Accept route if it has both 1234:1001 and 1234:1002 ! Reject if it has 1234:1 follow by anything else. ! Accept everything else ip community-list TEST permit 1234:1001 1234:1002 ip community-list TEST deny 1234:1.* ip community-list TEST permit .* set community-delete NN|NAME ---------------------------- When used in a route-map, this allows communities to be deleted from a route. It takes a community list and any permitted community which matches is deleted from the route. Deny statements in the community list are ignored. The following config fragment deletes communities 1234:1001 and 1234:2 followed by anything from a route: ip community-list TEST permit 1234:1001 ip community-list TEST permit 1234:2.* route-map STRIP-COMMUNITIES permit 10 set community-delete TEST bgp enforce-first-as -------------------- Force EBGP peers to pass routes that start with the neighbor AS. A useful sanity check on EBGP peers, but not so useful if getting routes via a route-server. Its a global BGP configuration option (as thats how Cisco's do it), but I am mulling the merits of turning it off on a per-peer basis. Thoughts? Fixes ----- o Community matching was broken - (trying to match 1234:1001 1234:1003 against 1234:1001 1234:1002 1234:1003 would fail when it shouldn't). o Possible connect collision detect FSM issue. NB. I need to apply the community deleting and matching to the extended community code, but I've not had a chance yet. Rick diff -c -r zebra-0.89/bgpd/bgp_aspath.c zebra-0.89-rap/bgpd/bgp_aspath.c *** zebra-0.89/bgpd/bgp_aspath.c Mon Oct 2 23:19:25 2000 --- zebra-0.89-rap/bgpd/bgp_aspath.c Sat Oct 28 16:15:37 2000 *************** *** 440,445 **** --- 440,474 ---- return 0; } + /* + ** AS path first as check. + ** If aspath starts with asno then return 1. + ** NOTE - Only to be used for EBGP Paths + */ + int + aspath_firstas_check (struct aspath *aspath, as_t asno) + { + caddr_t pnt; + struct assegment *assegment; + + if (aspath == NULL) + return 0; + + pnt = aspath->data; + assegment = (struct assegment *) pnt; + + if (!assegment) + return 0; + + if (assegment->type != AS_SEQUENCE) + return 0; + + if (assegment->asval[0] == htons(asno)) + return 1; + + return 0; + } + /* Merge as1 to as2. as2 should be uninterned aspath. */ struct aspath * aspath_merge (struct aspath *as1, struct aspath *as2) diff -c -r zebra-0.89/bgpd/bgp_aspath.h zebra-0.89-rap/bgpd/bgp_aspath.h *** zebra-0.89/bgpd/bgp_aspath.h Mon Oct 2 23:19:25 2000 --- zebra-0.89-rap/bgpd/bgp_aspath.h Mon Oct 23 15:47:11 2000 *************** *** 77,81 **** --- 77,82 ---- void aspath_print_all_vty (struct vty *); unsigned int aspath_key_make (struct aspath *); int aspath_loop_check (struct aspath *, as_t); + int aspath_firstas_check (struct aspath *, as_t); #endif /* _ZEBRA_BGP_ASPATH_H */ diff -c -r zebra-0.89/bgpd/bgp_attr.c zebra-0.89-rap/bgpd/bgp_attr.c *** zebra-0.89/bgpd/bgp_attr.c Fri Sep 29 05:57:19 2000 --- zebra-0.89-rap/bgpd/bgp_attr.c Mon Oct 23 15:46:13 2000 *************** *** 560,565 **** --- 560,582 ---- } } + if (bgp != NULL && CHECK_FLAG(bgp->config, BGP_CONFIG_ENFORCE_FIRST_AS)) + { + if(peer_sort (peer) == BGP_PEER_EBGP && + !aspath_firstas_check(attr->aspath, peer->as)) + { + zlog (peer->log, LOG_ERR, + "%s: Incorrect first AS (not %d) and enforce-first-as is enabled", + peer->host, + peer->as); + + bgp_notify_send (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_MAL_AS_PATH); + } + } + + /* Forward pointer. */ stream_forward (peer->ibuf, length); diff -c -r zebra-0.89/bgpd/bgp_attr.h zebra-0.89-rap/bgpd/bgp_attr.h *** zebra-0.89/bgpd/bgp_attr.h Tue Aug 15 03:30:22 2000 --- zebra-0.89-rap/bgpd/bgp_attr.h Fri Oct 20 01:10:18 2000 *************** *** 51,56 **** --- 51,59 ---- /* Flag of attribute is set or not. */ u_int32_t flag; + /* Flag for internal attributes */ + u_int32_t i_flag; + /* Attributes. */ u_char origin; struct in_addr nexthop; *************** *** 82,87 **** --- 85,93 ---- /* Invalid. */ u_char invalid; + + /* Table */ + u_char table; }; #define ATTR_FLAG_BIT(X) (1 << ((X) - 1)) diff -c -r zebra-0.89/bgpd/bgp_clist.c zebra-0.89-rap/bgpd/bgp_clist.c *** zebra-0.89/bgpd/bgp_clist.c Fri Sep 8 12:55:54 2000 --- zebra-0.89-rap/bgpd/bgp_clist.c Sat Oct 28 16:18:50 2000 *************** *** 30,35 **** --- 30,37 ---- #include "bgpd/bgpd.h" #include "bgpd/bgp_community.h" #include "bgpd/bgp_clist.h" + #include "bgpd/bgp_aspath.h" + #include "bgpd/bgp_regex.h" enum community_entry_type { *************** *** 37,42 **** --- 39,50 ---- COMMUNITY_PERMIT }; + enum community_entry_style + { + COMMUNITY_LIST, + COMMUNITY_REGEXP, + }; + struct community_list_list { struct community_list *head; *************** *** 56,62 **** --- 64,74 ---- enum community_entry_type type; + enum community_entry_style style; + struct community *com; + char *regexp; + regex_t *reg; }; static struct community_list_master community_list_master = *************** *** 80,85 **** --- 92,103 ---- { if (entry->com) community_free (entry->com); + if (entry->regexp) + { + XFREE (MTYPE_COMMUNITY_REGEXP, entry->regexp); + bgp_regex_free (entry->reg); + } + XFREE (MTYPE_COMMUNITY_ENTRY, entry); } *************** *** 91,96 **** --- 109,115 ---- entry = community_entry_new (); entry->com = com; entry->type = type; + entry->style = COMMUNITY_LIST; return entry; } *************** *** 234,241 **** struct community_entry *entry; for (entry = list->head; entry; entry = entry->next) ! if (community_cmp (entry->com, com)) ! return entry; return NULL; } --- 253,273 ---- struct community_entry *entry; for (entry = list->head; entry; entry = entry->next) ! if (entry->style == COMMUNITY_LIST) ! if (community_cmp (entry->com, com)) ! return entry; ! return NULL; ! } ! struct community_entry * ! community_entry_regexp_lookup (struct community_list *list, ! char *str, enum community_entry_type type) ! { ! struct community_entry *entry; ! ! for (entry = list->head; entry; entry = entry->next) ! if (entry->style == COMMUNITY_REGEXP) ! if (strcmp (entry->regexp, str) == 0) ! return entry; return NULL; } *************** *** 313,325 **** } int community_list_match (struct community *com, struct community_list *list) { struct community_entry *entry; for (entry = list->head; entry; entry = entry->next) ! if (community_match (com, entry->com)) ! return 1; return 0; } --- 345,436 ---- } int + community_match_regexp (struct community_entry *entry, + struct community *com) + { + int i; + char c[12]; + + + for (i = 0; i < com->size; i++) + { + sprintf(c, "%d:%d", + ((ntohl (com_nthval (com, i))) >> 16) & 0xFFFF, + (ntohl (com_nthval (com, i))) & 0xFFFF); + + if (regexec (entry->reg, c, 0, NULL, 0) == 0) + return 1; + } + return 0; + } + + struct community * + community_delete_regexp (struct community *com, regex_t *reg) + { + int i; + char c[12]; + + i = 0; + while (i < com->size) + { + sprintf(c, "%d:%d", + ((ntohl (com_nthval (com, i))) >> 16) & 0xFFFF, + (ntohl (com_nthval (com, i))) & 0xFFFF); + + if (regexec (reg, c, 0, NULL, 0) == 0) + { + /* Matched - delete! */ + community_del_val (com, com_nthval (com, i)); + } + else + i++; + } + + return com; + } + + /* Delete all permitted communities in the list from com1 */ + struct community * + community_list_delete_entries (struct community *com1, struct community_list *list) + { + struct community_entry *entry; + + for (entry = list->head; entry; entry = entry->next) + { + if (entry->style == COMMUNITY_LIST) + { + if (entry->type == COMMUNITY_PERMIT) + community_delete (com1, entry->com); + } + else if (entry->style == COMMUNITY_REGEXP) + { + if (entry->type == COMMUNITY_PERMIT) + community_delete_regexp (com1, entry->reg); + } + } + + return com1; + } + + int community_list_match (struct community *com, struct community_list *list) { struct community_entry *entry; for (entry = list->head; entry; entry = entry->next) ! { ! if (entry->style == COMMUNITY_LIST) ! { ! if (community_match (com, entry->com)) ! return 1; ! } ! else if (entry->style == COMMUNITY_REGEXP) ! { ! if (community_match_regexp (entry, com)) ! return 1; ! } ! } ! return 0; } *************** *** 369,377 **** for (entry = list->head; entry; entry = entry->next) { ! if (entry->type == new->type ! && community_cmp (entry->com, new->com)) ! return 1; } return 0; } --- 480,497 ---- for (entry = list->head; entry; entry = entry->next) { ! if (entry->style == COMMUNITY_LIST) ! { ! if (entry->type == new->type ! && community_cmp (entry->com, new->com)) ! return 1; ! } ! else if (entry->style == COMMUNITY_REGEXP) ! { ! if (entry->type == new->type ! && (strcmp(entry->regexp, new->regexp) == 0)) ! return 1; ! } } return 0; } *************** *** 390,395 **** --- 510,516 ---- struct community_list *list; struct community *com; struct buffer *b; + regex_t *regex; int i; char *str; int first = 0; *************** *** 421,437 **** buffer_free (b); com = community_str2com (str); ! if (! com) { ! vty_out (vty, "Community-list malformed: %s%s", str, ! VTY_NEWLINE); free (str); - return CMD_WARNING; } ! ! entry = community_entry_make (com, type); ! ! free (str); /* Install new community list to the community_list. */ list = community_list_get (argv[0]); --- 542,572 ---- buffer_free (b); com = community_str2com (str); ! if (com) { ! entry = community_entry_make (com, type); free (str); } ! else ! { ! regex = bgp_regcomp (str); ! if (regex) ! { ! entry = community_entry_new (); ! entry->reg = regex; ! entry->regexp = XSTRDUP (MTYPE_COMMUNITY_REGEXP, str); ! entry->type = type; ! entry->style = COMMUNITY_REGEXP; ! free(str); ! } ! else ! { ! vty_out (vty, "Community-list malformed: %s%s", str, ! VTY_NEWLINE); ! free (str); ! return CMD_WARNING; ! } ! } /* Install new community list to the community_list. */ list = community_list_get (argv[0]); *************** *** 460,465 **** --- 595,601 ---- struct community_list *list; struct community *com; struct buffer *b; + regex_t *regex; int i; char *str; int first = 0; *************** *** 500,516 **** buffer_free (b); com = community_str2com (str); ! free (str); ! ! if (! com) { ! vty_out (vty, "Community-list malformed: %s%s", str, ! VTY_NEWLINE); ! return CMD_WARNING; } ! ! entry = community_entry_lookup (list, com, type); ! if (entry == NULL) { vty_out (vty, "Can't find specified community list.%s", --- 636,663 ---- buffer_free (b); com = community_str2com (str); ! if (com) { ! free (str); ! entry = community_entry_lookup (list, com, type); } ! else ! { ! regex = bgp_regcomp (str); ! if (regex) ! { ! entry = community_entry_regexp_lookup (list, str, type); ! free(str); ! } ! else ! { ! vty_out (vty, "Community-list malformed: %s%s", str, ! VTY_NEWLINE); ! free (str); ! return CMD_WARNING; ! } ! } ! if (entry == NULL) { vty_out (vty, "Can't find specified community list.%s", *************** *** 556,564 **** for (list = community_list_master.num.head; list; list = list->next) for (entry = list->head; entry; entry = entry->next) { ! vty_out (vty, "ip community-list %s %s%s%s", ! list->name, community_type_str (entry->type), ! community_print (entry->com), VTY_NEWLINE); write++; } --- 703,715 ---- for (list = community_list_master.num.head; list; list = list->next) for (entry = list->head; entry; entry = entry->next) { ! vty_out (vty, "ip community-list %s %s%s%s%s", ! list->name, ! community_type_str (entry->type), ! entry->style == COMMUNITY_LIST ? "" : " ", ! entry->style == COMMUNITY_LIST ! ? community_print (entry->com) ! : entry->regexp, VTY_NEWLINE); write++; } *************** *** 566,574 **** for (list = community_list_master.str.head; list; list = list->next) for (entry = list->head; entry; entry = entry->next) { ! vty_out (vty, "ip community-list %s %s%s%s", ! list->name, community_type_str (entry->type), ! community_print (entry->com), VTY_NEWLINE); write++; } --- 717,729 ---- for (list = community_list_master.str.head; list; list = list->next) for (entry = list->head; entry; entry = entry->next) { ! vty_out (vty, "ip community-list %s %s%s%s%s", ! list->name, ! community_type_str (entry->type), ! entry->style == COMMUNITY_LIST ? "" : " ", ! entry->style == COMMUNITY_LIST ! ? community_print (entry->com) ! : entry->regexp, VTY_NEWLINE); write++; } diff -c -r zebra-0.89/bgpd/bgp_clist.h zebra-0.89-rap/bgpd/bgp_clist.h *** zebra-0.89/bgpd/bgp_clist.h Fri Sep 8 12:55:54 2000 --- zebra-0.89-rap/bgpd/bgp_clist.h Wed Oct 25 00:03:58 2000 *************** *** 41,44 **** --- 41,45 ---- struct community_list *community_list_lookup (char *); int community_list_match (struct community *, struct community_list *); int community_list_match_exact (struct community *, struct community_list *); + struct community *community_list_delete_entries (struct community *, struct community_list *); void community_list_init (); diff -c -r zebra-0.89/bgpd/bgp_community.c zebra-0.89-rap/bgpd/bgp_community.c *** zebra-0.89/bgpd/bgp_community.c Mon Sep 11 06:45:07 2000 --- zebra-0.89-rap/bgpd/bgp_community.c Sat Oct 28 16:43:00 2000 *************** *** 62,67 **** --- 62,118 ---- com_lastval (com) = htonl (val); } + /* Delete one community */ + void + community_del_val (struct community *com, u_int32_t val) + { + int i = 0; + int c = 0; + + if (!com->val) + return; + + while(i < com->size) + { + if(com->val[i] == val) + { + c = com->size -i -1; + if (c > 0) + { + memcpy(&com->val[i], &com->val[i+1], c * sizeof(val)); + } + com->size--; + if (com->size > 0) + com->val = XREALLOC (MTYPE_COMMUNITY_VAL, com->val, com_length (com)); + else + { + XFREE (MTYPE_COMMUNITY_VAL, com->val); + com->val = NULL; + } + + return; + } + + i++; + } + } + + /* Delete all communities listed in com2 from com1 */ + struct community * + community_delete (struct community *com1, struct community *com2) + { + int i = 0; + + while(i < com2->size) + { + community_del_val (com1, com2->val[i]); + i++; + } + + return com1; + } + + /* Callback function from qsort(). */ int community_compare (const void *a1, const void *a2) *************** *** 265,279 **** int community_match (struct community *com1, struct community *com2) { ! int i; if (com1->size < com2->size) return 0; for (i = 0; i <= com1->size - com2->size; i++) if (memcmp (com1->val + i, com2->val, com2->size * 4) == 0) return 1; ! return 0; } /* If two aspath have same value then return 1 else return 0. This --- 316,346 ---- int community_match (struct community *com1, struct community *com2) { ! int i = 0; ! int j = 0; if (com1->size < com2->size) return 0; + #ifdef BORKED for (i = 0; i <= com1->size - com2->size; i++) if (memcmp (com1->val + i, com2->val, com2->size * 4) == 0) return 1; ! #endif ! ! /* Every community on com2 needs to be on com1 for this to match */ ! while (i < com1->size && j < com2->size) ! { ! if (com1->val[i] == com2->val[j]) ! j++; ! ! i++; ! } ! ! if (j == com2->size) ! return 1; ! else ! return 0; } /* If two aspath have same value then return 1 else return 0. This *************** *** 302,307 **** --- 369,375 ---- return com1; } + /* Initialize comminity related hash. */ void diff -c -r zebra-0.89/bgpd/bgp_community.h zebra-0.89-rap/bgpd/bgp_community.h *** zebra-0.89/bgpd/bgp_community.h Mon Sep 11 06:51:33 2000 --- zebra-0.89-rap/bgpd/bgp_community.h Sat Oct 28 16:18:01 2000 *************** *** 57,62 **** --- 57,64 ---- int community_match (struct community *, struct community *); int community_cmp (struct community *, struct community *); struct community *community_merge (struct community *, struct community *); + struct community *community_delete (struct community *, struct community *); struct community *community_dup (struct community *); int community_include (struct community *, u_int32_t); + void community_del_val (struct community *, u_int32_t); #endif /* _ZEBRA_BGP_COMMUNITY_H */ diff -c -r zebra-0.89/bgpd/bgp_packet.c zebra-0.89-rap/bgpd/bgp_packet.c *** zebra-0.89/bgpd/bgp_packet.c Wed Sep 27 04:49:55 2000 --- zebra-0.89-rap/bgpd/bgp_packet.c Sun Oct 22 18:24:24 2000 *************** *** 695,703 **** /* Hack part. */ if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) { ! if (realpeer->status != Active) { ! zlog_info ("%s [Event] peer's status is not Active", realpeer->host); return -1; } --- 695,704 ---- /* Hack part. */ if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) { ! if (realpeer->status != Active && realpeer->status != Connect) { ! zlog_info ("%s [Event] peer's status is not Active or Connect", ! realpeer->host); return -1; } diff -c -r zebra-0.89/bgpd/bgp_route.c zebra-0.89-rap/bgpd/bgp_route.c *** zebra-0.89/bgpd/bgp_route.c Mon Oct 2 23:19:25 2000 --- zebra-0.89-rap/bgpd/bgp_route.c Fri Oct 20 01:15:33 2000 *************** *** 54,60 **** /* For bgp_zebra.c */ void bgp_zebra_announce (struct prefix *, struct bgp_info *, struct bgp *); ! void bgp_zebra_withdraw (struct prefix *, struct bgp_info *); #define DISTRIBUTE_IN_NAME(F) ((F)->dlist[BGP_FILTER_IN].name) #define DISTRIBUTE_IN_V4(F) ((F)->dlist[BGP_FILTER_IN].v4) --- 54,60 ---- /* For bgp_zebra.c */ void bgp_zebra_announce (struct prefix *, struct bgp_info *, struct bgp *); ! void bgp_zebra_withdraw (struct prefix *, struct bgp_info *, struct bgp *); #define DISTRIBUTE_IN_NAME(F) ((F)->dlist[BGP_FILTER_IN].name) #define DISTRIBUTE_IN_V4(F) ((F)->dlist[BGP_FILTER_IN].v4) *************** *** 440,446 **** if (ri->selected && ri->type == ZEBRA_ROUTE_BGP && ri->sub_type == BGP_ROUTE_NORMAL) ! bgp_zebra_withdraw (&rn->p, ri); table = bgp->rib[AFI_IP6][SAFI_UNICAST]; --- 440,446 ---- if (ri->selected && ri->type == ZEBRA_ROUTE_BGP && ri->sub_type == BGP_ROUTE_NORMAL) ! bgp_zebra_withdraw (&rn->p, ri, bgp); table = bgp->rib[AFI_IP6][SAFI_UNICAST]; *************** *** 449,455 **** if (ri->selected && ri->type == ZEBRA_ROUTE_BGP && ri->sub_type == BGP_ROUTE_NORMAL) ! bgp_zebra_withdraw (&rn->p, ri); } } --- 449,455 ---- if (ri->selected && ri->type == ZEBRA_ROUTE_BGP && ri->sub_type == BGP_ROUTE_NORMAL) ! bgp_zebra_withdraw (&rn->p, ri, bgp); } } *************** *** 1149,1155 **** if (old_select && old_select->type == ZEBRA_ROUTE_BGP && old_select->sub_type == BGP_ROUTE_NORMAL) ! bgp_zebra_withdraw (p, old_select); } } return 0; --- 1149,1155 ---- if (old_select && old_select->type == ZEBRA_ROUTE_BGP && old_select->sub_type == BGP_ROUTE_NORMAL) ! bgp_zebra_withdraw (p, old_select, bgp); } } return 0; *************** *** 3331,3336 **** --- 3331,3341 ---- if (binfo->selected) vty_out (vty, ", best"); + if (attr->i_flag & ATTR_FLAG_BIT(BGP_INT_ATTR_TABLE)) + { + vty_out (vty, " (Table %d)", attr->table); + } + vty_out (vty, "%s", VTY_NEWLINE); /* Line 4 display Community */ diff -c -r zebra-0.89/bgpd/bgp_routemap.c zebra-0.89-rap/bgpd/bgp_routemap.c *** zebra-0.89/bgpd/bgp_routemap.c Tue Sep 26 22:00:01 2000 --- zebra-0.89-rap/bgpd/bgp_routemap.c Sat Oct 28 16:16:15 2000 *************** *** 90,95 **** --- 90,96 ---- origin : Done tag : (This will not be implemented by bgpd) weight : Done + table : Done o mrt extension *************** *** 948,953 **** --- 949,1022 ---- route_set_community_additive_free, }; + /* `set community-delete COMMUNITY' */ + + /* For community set mechanism. */ + route_map_result_t + route_set_community_delete (void *rule, struct prefix *prefix, route_map_object_t type, void *object) + { + struct community_list *list; + struct community *merge; + struct community *old_com; + struct community *new_com; + struct bgp_info *bgp_info; + + if(type == RMAP_BGP) + { + if (!rule) + return RMAP_OKAY; + + bgp_info = object; + list = community_list_lookup (rule); + + old_com = bgp_info->attr->community; + + if (list && old_com) + { + merge = community_list_delete_entries (community_dup (old_com), list); + new_com = community_uniq_sort (merge); + community_free (merge); + + if (new_com->size == 0) + { + bgp_info->attr->community = NULL; + bgp_info->attr->flag &= ~ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES); + community_free (new_com); + } + else + { + bgp_info->attr->community = new_com; + bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES); + } + } + } + + return RMAP_OKAY; + } + + /* Compile function for set community. */ + void * + route_set_community_delete_compile (char *arg) + { + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); + } + + /* Free function for set community. */ + void + route_set_community_delete_free (void *rule) + { + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); + } + + /* Set community rule structure. */ + struct route_map_rule_cmd route_set_community_delete_cmd = + { + "community-delete", + route_set_community_delete, + route_set_community_delete_compile, + route_set_community_delete_free, + }; + /* "community set none". */ route_map_result_t route_set_community_none (void *rule, struct prefix *prefix, *************** *** 1262,1267 **** --- 1331,1392 ---- route_set_aggregator_as_free, }; + route_map_result_t + route_set_table (void *rule, struct prefix *prefix, route_map_object_t type, void *object) + { + u_int32_t *table; + struct bgp_info *bgp_info; + + if(type == RMAP_BGP){ + /* Fetch routemap's rule information. */ + table = rule; + bgp_info = object; + + /* Set local preference value. */ + bgp_info->attr->i_flag |= ATTR_FLAG_BIT (BGP_INT_ATTR_TABLE); + bgp_info->attr->table = *table; + } + + return RMAP_OKAY; + } + + /* set local preference compilation. */ + void * + route_set_table_compile (char *arg) + { + u_int32_t *table; + char *endptr = NULL; + + /* Local preference value shoud be integer. */ + if (! all_digit (arg)) + return NULL; + + table = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); + *table = strtoul (arg, &endptr, 10); + if (*endptr != '\0' || *table > 255) + { + XFREE (MTYPE_ROUTE_MAP_COMPILED, table); + return NULL; + } + return table; + } + + /* Free route map's local preference value. */ + void + route_set_table_free (void *rule) + { + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); + } + + /* Set local preference rule structure. */ + struct route_map_rule_cmd route_set_table_cmd = + { + "table", + route_set_table, + route_set_table_compile, + route_set_table_free, + }; + #ifdef HAVE_IPV6 /* `match ipv6 address IP_ACCESS_LIST' */ *************** *** 1792,1797 **** --- 1917,1935 ---- #endif /* HAVE_IPV6 */ } } + + /* Table Map route-maps */ + NEWLIST_LOOP (bgp_list, bgp, nn) + { + if (bgp->tmap[AFI_IP].name) + bgp->tmap[AFI_IP].map = + route_map_lookup_by_name (bgp->tmap[AFI_IP].name); + #ifdef HAVE_IPV6 + if (bgp->tmap[AFI_IP6].name) + bgp->tmap[AFI_IP6].map = + route_map_lookup_by_name (bgp->tmap[AFI_IP6].name); + #endif /* HAVE_IPV6 */ + } } DEFUN (match_ip_address, *************** *** 2150,2155 **** --- 2288,2324 ---- "BGP local preference path attribute\n" "Preference value\n") + DEFUN (set_table, + set_table_cmd, + "set table <0-255>", + SET_STR + "Kernel Table in which to install route\n" + "Table number\n") + { + return bgp_route_set_add (vty, vty->index, "table", argv[0]); + } + + DEFUN (no_set_table, + no_set_table_cmd, + "no set table", + NO_STR + SET_STR + "Kernel Table in which to install route\n") + { + if (argc == 0) + return bgp_route_set_delete (vty, vty->index, "table", NULL); + + return bgp_route_set_delete (vty, vty->index, "table", argv[0]); + } + + ALIAS (no_set_table, + no_set_table_val_cmd, + "no set table <0-255>", + NO_STR + SET_STR + "Kernel Table in which to install route\n" + "Table Number\n") + DEFUN (set_weight, set_weight_cmd, "set weight <0-4294967295>", *************** *** 2423,2428 **** --- 2592,2628 ---- { return bgp_route_set_delete (vty, vty->index, "community none", NULL); } + DEFUN (set_community_delete, + set_community_delete_cmd, + "set community-delete WORD", + SET_STR + "BGP community attribute (Delete from the existing community)\n" + "Community list (Permitted communities are deleted)\n") + { + return bgp_route_set_add (vty, vty->index, "community-delete", argv[0]); + } + + DEFUN (no_set_community_delete, + no_set_community_delete_cmd, + "no set community-delete", + NO_STR + SET_STR + "BGP community attribute (Delete from existing community)\n") + { + if (argc == 0) + return bgp_route_set_delete (vty, vty->index, "community-delete", NULL); + + return bgp_route_set_delete (vty, vty->index, "community-delete", argv[0]); + } + + ALIAS (no_set_community_delete, + no_set_community_delete_val_cmd, + "no set community-delete WORD", + NO_STR + SET_STR + "BGP community attribute (Delete from the existing community)\n" + "Community list\n") + DEFUN (set_ecommunity_rt, set_ecommunity_rt_cmd, *************** *** 2965,2970 **** --- 3165,3171 ---- route_map_install_set (&route_set_ip_nexthop_cmd); route_map_install_set (&route_set_local_pref_cmd); + route_map_install_set (&route_set_table_cmd); route_map_install_set (&route_set_weight_cmd); route_map_install_set (&route_set_metric_cmd); route_map_install_set (&route_set_aspath_prepend_cmd); *************** *** 2973,2978 **** --- 3174,3180 ---- route_map_install_set (&route_set_aggregator_as_cmd); route_map_install_set (&route_set_community_cmd); route_map_install_set (&route_set_community_additive_cmd); + route_map_install_set (&route_set_community_delete_cmd); route_map_install_set (&route_set_community_none_cmd); route_map_install_set (&route_set_nlri_cmd); route_map_install_set (&route_set_vpnv4_nexthop_cmd); *************** *** 3004,3009 **** --- 3206,3214 ---- install_element (RMAP_NODE, &set_local_pref_cmd); install_element (RMAP_NODE, &no_set_local_pref_cmd); install_element (RMAP_NODE, &no_set_local_pref_val_cmd); + install_element (RMAP_NODE, &set_table_cmd); + install_element (RMAP_NODE, &no_set_table_cmd); + install_element (RMAP_NODE, &no_set_table_val_cmd); install_element (RMAP_NODE, &set_weight_cmd); install_element (RMAP_NODE, &no_set_weight_cmd); install_element (RMAP_NODE, &no_set_weight_val_cmd); *************** *** 3030,3035 **** --- 3235,3243 ---- install_element (RMAP_NODE, &set_community_additive_cmd); install_element (RMAP_NODE, &no_set_community_additive_cmd); install_element (RMAP_NODE, &no_set_community_additive_val_cmd); + install_element (RMAP_NODE, &set_community_delete_cmd); + install_element (RMAP_NODE, &no_set_community_delete_cmd); + install_element (RMAP_NODE, &no_set_community_delete_val_cmd); install_element (RMAP_NODE, &set_community_none_cmd); install_element (RMAP_NODE, &no_set_community_none_cmd); install_element (RMAP_NODE, &set_ecommunity_rt_cmd); diff -c -r zebra-0.89/bgpd/bgp_zebra.c zebra-0.89-rap/bgpd/bgp_zebra.c *** zebra-0.89/bgpd/bgp_zebra.c Mon Sep 11 07:26:44 2000 --- zebra-0.89-rap/bgpd/bgp_zebra.c Sat Oct 28 16:11:53 2000 *************** *** 40,45 **** --- 40,46 ---- int bgp_interface_delete (int, struct zclient *, zebra_size_t); int bgp_interface_address_add (int, struct zclient *, zebra_size_t); int bgp_interface_address_delete (int, struct zclient *, zebra_size_t); + void bgp_zebra_withdraw (struct prefix *, struct bgp_info *, struct bgp *); /* All information about zebra. */ static struct zclient *zclient = NULL; *************** *** 387,392 **** --- 388,436 ---- bgp_redistribute_withdraw (bgp, afi, type); } + void + bgp_tmap_set (struct bgp *bgp, afi_t afi, char *map) + { + if ( bgp->tmap[afi].name != NULL) + { + free(bgp->tmap[afi].name); + } + + bgp->tmap[afi].name = strdup(map); + bgp->tmap[afi].map = route_map_lookup_by_name(map); + } + + void + bgp_tmap_unset (struct bgp *bgp, afi_t afi) + { + bgp->tmap[afi].map = NULL; + if ( bgp->tmap[afi].name != NULL) + { + free(bgp->tmap[afi].name); + } + } + + DEFUN (bgp_table_map, + bgp_table_map_cmd, + "table-map WORD", + "Filter routes to the zebrad\n" + "route-map name\n") + { + bgp_tmap_set (vty->index, AFI_IP, argv[0]); + return CMD_SUCCESS; + } + + DEFUN (no_bgp_table_map, + no_bgp_table_map_cmd, + "no table-map [WORD]", + NO_STR + "Filter routes to the zebrad\n" + "route-map name\n") + { + bgp_tmap_unset (vty->index, AFI_IP); + return CMD_SUCCESS; + } + DEFUN (bgp_redistribute_kernel, bgp_redistribute_kernel_cmd, "redistribute kernel", *************** *** 618,623 **** --- 662,690 ---- } #ifdef HAVE_IPV6 + DEFUN (ipv6_bgp_table_map, + ipv6_bgp_table_map_cmd, + "table-map WORD", + "Filter routes to the zebrad\n" + "route-map name\n") + { + struct bgp *bgp = vty->index; + + bgp_tmap_set (vty->index, AFI_IP6, argv[0]); + return CMD_SUCCESS; + } + + DEFUN (no_ipv6_bgp_table_map, + no_ipv6_bgp_table_map_cmd, + "no table-map [WORD]", + NO_STR + "Filter routes to the zebrad\n" + "route-map name\n") + { + bgp_tmap_unset (vty->index, AFI_IP6); + return CMD_SUCCESS; + } + DEFUN (ipv6_bgp_redistribute_kernel, ipv6_bgp_redistribute_kernel_cmd, "ipv6 bgp redistribute kernel", *************** *** 1176,1200 **** { struct zapi_ipv4 api; struct in_addr *nexthop; ! api.flags = flags; ! nexthop = &info->attr->nexthop; api.type = ZEBRA_ROUTE_BGP; api.message = 0; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 1; api.nexthop = &nexthop; SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); ! api.metric = info->attr->med; ! ! distance = bgp_distance_apply (p, info, bgp); ! if (distance) { SET_FLAG (api.message, ZAPI_MESSAGE_DISTANCE); api.distance = distance; } zapi_ipv4_add (zclient, (struct prefix_ipv4 *) p, &api); } #ifdef HAVE_IPV6 --- 1243,1294 ---- { struct zapi_ipv4 api; struct in_addr *nexthop; + struct bgp_info info2; + struct attr new; ! /* Duplicate the attributes */ ! new = *info->attr; ! info2.peer = info->peer; ! info2.attr = &new; ! ! if (bgp->tmap[AFI_IP].map != NULL) { ! if (route_map_apply (bgp->tmap[AFI_IP].map, p, ! RMAP_BGP, &info2) != RMAP_MATCH) ! { ! /* ! ** This is the best path we have now, but it failed the ! ** table-map, so withdraw the route from zebra ! */ ! bgp_zebra_withdraw (p, info, bgp); ! return; ! } ! } + api.flags = flags; + nexthop = &info2.attr->nexthop; + api.type = ZEBRA_ROUTE_BGP; api.message = 0; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 1; api.nexthop = &nexthop; SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); ! api.metric = info2.attr->med; ! ! distance = bgp_distance_apply (p, &info2, bgp); ! if (distance) { SET_FLAG (api.message, ZAPI_MESSAGE_DISTANCE); api.distance = distance; } + + if (info2.attr->i_flag & ATTR_FLAG_BIT (BGP_INT_ATTR_TABLE)) + { + SET_FLAG (api.message, ZAPI_MESSAGE_TABLE); + api.table = info2.attr->table; + } + zapi_ipv4_add (zclient, (struct prefix_ipv4 *) p, &api); } #ifdef HAVE_IPV6 *************** *** 1204,1231 **** unsigned int ifindex; struct in6_addr *nexthop; struct zapi_ipv6 api; ifindex = 0; nexthop = NULL; /* Only global address nexthop exists. */ ! if (info->attr->mp_nexthop_len == 16) ! nexthop = &info->attr->mp_nexthop_global; /* If both global and link-local address present. */ ! if (info->attr->mp_nexthop_len == 32) { ! nexthop = &info->attr->mp_nexthop_local; ! if (info->peer->nexthop.ifp) ! ifindex = info->peer->nexthop.ifp->ifindex; } if (nexthop == NULL) return; if (IN6_IS_ADDR_LINKLOCAL (nexthop) && ! ifindex) ! if (info->peer->ifname) ! ifindex = if_nametoindex (info->peer->ifname); /* Make Zebra API structure. */ api.flags = flags; --- 1298,1341 ---- unsigned int ifindex; struct in6_addr *nexthop; struct zapi_ipv6 api; + struct bgp_info info2; + struct attr new; + + /* Duplicate the attributes */ + new = *info->attr; + info2.peer = info->peer; + info2.attr = &new; + + if (bgp->tmap[AFI_IP6].map != NULL) { + if (route_map_apply (bgp->tmap[AFI_IP6].map, p, + RMAP_BGP, &info2) != RMAP_MATCH) + { + bgp_zebra_withdraw (p, info, bgp); + return; + } + } ifindex = 0; nexthop = NULL; /* Only global address nexthop exists. */ ! if (info2.attr->mp_nexthop_len == 16) ! nexthop = &info2.attr->mp_nexthop_global; /* If both global and link-local address present. */ ! if (info2.attr->mp_nexthop_len == 32) { ! nexthop = &info2.attr->mp_nexthop_local; ! if (info2.peer->nexthop.ifp) ! ifindex = info2.peer->nexthop.ifp->ifindex; } if (nexthop == NULL) return; if (IN6_IS_ADDR_LINKLOCAL (nexthop) && ! ifindex) ! if (info2.peer->ifname) ! ifindex = if_nametoindex (info2.peer->ifname); /* Make Zebra API structure. */ api.flags = flags; *************** *** 1238,1244 **** api.ifindex_num = 1; api.ifindex = &ifindex; SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); ! api.metric = info->attr->med; zapi_ipv6_add (zclient, (struct prefix_ipv6 *) p, &api); } --- 1348,1360 ---- api.ifindex_num = 1; api.ifindex = &ifindex; SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); ! api.metric = info2.attr->med; ! ! if (info2.attr->i_flag & ATTR_FLAG_BIT (BGP_INT_ATTR_TABLE)) ! { ! SET_FLAG (api.message, ZAPI_MESSAGE_TABLE); ! api.table = info2.attr->table; ! } zapi_ipv6_add (zclient, (struct prefix_ipv6 *) p, &api); } *************** *** 1246,1252 **** } void ! bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info) { int flags; struct peer *peer; --- 1362,1368 ---- } void ! bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, struct bgp *bgp) { int flags; struct peer *peer; *************** *** 1285,1290 **** --- 1401,1412 ---- SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = info->attr->med; + if (info->attr->i_flag & ATTR_FLAG_BIT (BGP_INT_ATTR_TABLE)) + { + SET_FLAG (api.message, ZAPI_MESSAGE_TABLE); + api.table = info->attr->table; + } + zapi_ipv4_delete (zclient, (struct prefix_ipv4 *) p, &api); } #ifdef HAVE_IPV6 *************** *** 1303,1311 **** nexthop = &info->attr->mp_nexthop_global; /* If both global and link-local address present. */ ! if (info->attr->mp_nexthop_len == 32) { ! nexthop = &info->attr->mp_nexthop_local; if (info->peer->nexthop.ifp) ifindex = info->peer->nexthop.ifp->ifindex; } --- 1425,1433 ---- nexthop = &info->attr->mp_nexthop_global; /* If both global and link-local address present. */ ! if (info2.attr->mp_nexthop_len == 32) { ! nexthop = &info->ttr->mp_nexthop_local; if (info->peer->nexthop.ifp) ifindex = info->peer->nexthop.ifp->ifindex; } *************** *** 1329,1334 **** --- 1451,1462 ---- SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = info->attr->med; + if (info->attr->i_flag & ATTR_FLAG_BIT (BGP_INT_ATTR_TABLE)) + { + SET_FLAG (api.message, ZAPI_MESSAGE_TABLE); + api.table = info->attr->table; + } + zapi_ipv6_delete (zclient, (struct prefix_ipv6 *) p, &api); } #endif /* HAVE_IPV6 */ *************** *** 1466,1471 **** --- 1594,1601 ---- install_element (ZEBRA_NODE, &redistribute_bgp_cmd); install_element (ZEBRA_NODE, &no_redistribute_bgp_cmd); + install_element (BGP_NODE, &bgp_table_map_cmd); + install_element (BGP_NODE, &no_bgp_table_map_cmd); install_element (BGP_NODE, &bgp_redistribute_kernel_cmd); install_element (BGP_NODE, &bgp_redistribute_kernel_routemap_cmd); install_element (BGP_NODE, &no_bgp_redistribute_kernel_cmd); *************** *** 1488,1493 **** --- 1618,1625 ---- install_element (BGP_NODE, &no_bgp_redistribute_ospf_routemap_cmd); #ifdef HAVE_IPV6 + install_element (BGP_NODE, &ipv6_bgp_table_map_cmd); + install_element (BGP_NODE, &no_ipv6_bgp_table_map_cmd); install_element (BGP_NODE, &ipv6_bgp_redistribute_kernel_cmd); install_element (BGP_NODE, &ipv6_bgp_redistribute_kernel_routemap_cmd); install_element (BGP_NODE, &no_ipv6_bgp_redistribute_kernel_cmd); diff -c -r zebra-0.89/bgpd/bgpd.c zebra-0.89-rap/bgpd/bgpd.c *** zebra-0.89/bgpd/bgpd.c Mon Oct 2 23:19:25 2000 --- zebra-0.89-rap/bgpd/bgpd.c Mon Oct 23 16:16:40 2000 *************** *** 842,847 **** --- 842,875 ---- return CMD_SUCCESS; } + /* "bgp enforce-first-as" configuration. */ + DEFUN (bgp_enforce_first_as, + bgp_enforce_first_as_cmd, + "bgp enforce-first-as", + "BGP specific commands\n" + "Enforce EBGP peers send paths with their AS first\n") + { + struct bgp *bgp; + + bgp = vty->index; + SET_FLAG (bgp->config, BGP_CONFIG_ENFORCE_FIRST_AS); + return CMD_SUCCESS; + } + + DEFUN (no_bgp_enforce_first_as, + no_bgp_enforce_first_as_cmd, + "no bgp enforce-first-as", + NO_STR + "BGP specific commands\n" + "Enforce EBGP peers send paths with their AS first\n") + { + struct bgp *bgp; + + bgp = vty->index; + UNSET_FLAG (bgp->config, BGP_CONFIG_ENFORCE_FIRST_AS); + return CMD_SUCCESS; + } + /* "bgp bestpath med" configuration. */ DEFUN (bgp_bestpath_med, bgp_bestpath_med_cmd, *************** *** 7427,7432 **** --- 7455,7464 ---- vty_out (vty, " bgp router-id %s%s", inet_ntoa (bgp->id), VTY_NEWLINE); + if (bgp->tmap[AFI_IP].name != NULL) + vty_out (vty, " table-map %s%s", bgp->tmap[AFI_IP].name, + VTY_NEWLINE); + /* BGP configuration. */ if (CHECK_FLAG (bgp->config, BGP_CONFIG_ALWAYS_COMPARE_MED)) vty_out (vty, " bgp always-compare-med%s", VTY_NEWLINE); *************** *** 7463,7468 **** --- 7495,7503 ---- } } + if (CHECK_FLAG (bgp->config, BGP_CONFIG_ENFORCE_FIRST_AS)) + vty_out (vty, " bgp enforce-first-as%s", VTY_NEWLINE); + /* BGP deterministic-med */ if (CHECK_FLAG (bgp->config, BGP_CONFIG_DETERMINISTIC_MED)) vty_out (vty, " bgp deterministic-med%s", VTY_NEWLINE); *************** *** 7516,7521 **** --- 7551,7560 ---- /* IPv6 neighbor configuration. */ /* vty_out (vty, "!%s", VTY_NEWLINE); */ + if (bgp->tmap[AFI_IP6].name != NULL) + vty_out (vty, " ipv6 table-map %s%s", bgp->tmap[AFI_IP6].name, + VTY_NEWLINE); + /* IPv6 BGP redistribute configuration. */ bgp_config_write_redistribute (vty, bgp, AFI_IP6); *************** *** 7601,7606 **** --- 7640,7649 ---- /* "bgp deterministic-med" commands */ install_element (BGP_NODE, &bgp_deterministic_med_cmd); install_element (BGP_NODE, &no_bgp_deterministic_med_cmd); + + /* "bgp enforce-first-as" commands */ + install_element (BGP_NODE, &bgp_enforce_first_as_cmd); + install_element (BGP_NODE, &no_bgp_enforce_first_as_cmd); /* "bgp bestpath med" commands */ install_element (BGP_NODE, &bgp_bestpath_med_cmd); diff -c -r zebra-0.89/bgpd/bgpd.h zebra-0.89-rap/bgpd/bgpd.h *** zebra-0.89/bgpd/bgpd.h Mon Oct 2 23:19:25 2000 --- zebra-0.89-rap/bgpd/bgpd.h Sat Oct 28 15:42:52 2000 *************** *** 92,99 **** --- 92,107 ---- #define BGP_CONFIG_MED_CONFED 0x040 #define BGP_CONFIG_NO_DEFAULT_IPV4 0x080 #define BGP_CONFIG_NO_CLIENT_TO_CLIENT 0x100 + #define BGP_CONFIG_ENFORCE_FIRST_AS 0x200 u_int16_t config; + /* Table Map */ + struct + { + char *name; + struct route_map *map; + } tmap[AFI_MAX]; + /* BGP identifier. */ struct in_addr id; *************** *** 418,423 **** --- 426,434 ---- #define BGP_ATTR_MP_REACH_NLRI 14 #define BGP_ATTR_MP_UNREACH_NLRI 15 #define BGP_ATTR_EXT_COMMUNITIES 16 + + /* Internal attributes */ + #define BGP_INT_ATTR_TABLE 1 /* BGP Update ORIGIN */ #define BGP_ORIGIN_IGP 0 diff -c -r zebra-0.89/lib/memory.h zebra-0.89-rap/lib/memory.h *** zebra-0.89/lib/memory.h Sat Sep 23 01:27:27 2000 --- zebra-0.89-rap/lib/memory.h Tue Oct 24 03:39:03 2000 *************** *** 47,52 **** --- 47,53 ---- MTYPE_AS_PATH, MTYPE_COMMUNITY, MTYPE_COMMUNITY_VAL, + MTYPE_COMMUNITY_REGEXP, MTYPE_ECOMMUNITY, MTYPE_ECOMMUNITY_VAL, MTYPE_CLUSTER, diff -c -r zebra-0.89/lib/zclient.c zebra-0.89-rap/lib/zclient.c *** zebra-0.89/lib/zclient.c Mon Sep 11 02:12:08 2000 --- zebra-0.89-rap/lib/zclient.c Fri Oct 13 02:32:33 2000 *************** *** 292,297 **** --- 292,299 ---- stream_putc (s, api->distance); if (CHECK_FLAG (api->message, ZAPI_MESSAGE_METRIC)) stream_putl (s, api->metric); + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_TABLE)) + stream_putc (s, api->table); /* Put length at the first point of the stream. */ stream_putw_at (s, 0, stream_get_endp (s)); *************** *** 342,347 **** --- 344,351 ---- stream_putc (s, api->distance); if (CHECK_FLAG (api->message, ZAPI_MESSAGE_METRIC)) stream_putl (s, api->metric); + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_TABLE)) + stream_putl (s, api->table); /* Put length at the first point of the stream. */ stream_putw_at (s, 0, stream_get_endp (s)); diff -c -r zebra-0.89/lib/zclient.h zebra-0.89-rap/lib/zclient.h *** zebra-0.89/lib/zclient.h Mon Sep 11 02:12:48 2000 --- zebra-0.89-rap/lib/zclient.h Fri Oct 13 02:32:36 2000 *************** *** 79,84 **** --- 79,85 ---- #define ZAPI_MESSAGE_IFINDEX 0x02 #define ZAPI_MESSAGE_DISTANCE 0x04 #define ZAPI_MESSAGE_METRIC 0x08 + #define ZAPI_MESSAGE_TABLE 0x10 /* Zebra IPv4 route message API. */ struct zapi_ipv4 *************** *** 98,103 **** --- 99,106 ---- u_char distance; u_int32_t metric; + + u_char table; }; int diff -c -r zebra-0.89/zebra/rib.c zebra-0.89-rap/zebra/rib.c *** zebra-0.89/zebra/rib.c Thu Sep 21 21:22:14 2000 --- zebra-0.89-rap/zebra/rib.c Fri Oct 20 01:00:55 2000 *************** *** 468,475 **** { if (IS_RIB_FIB (rp)) fib = rp; ! if ((rp->type == type) && ! (IPV4_ADDR_SAME (&rp->u.gate4, &rib->u.gate4))) same = rp; } --- 468,474 ---- { if (IS_RIB_FIB (rp)) fib = rp; ! if (rp->type == type) same = rp; } *************** *** 928,934 **** VTY_NEWLINE); vty_out (vty, " Route type \"%s\"", route_info[rib->type].str_long, VTY_NEWLINE); ! vty_out (vty, ", distance %d, metric %d%s", rib->distance, rib->metric, VTY_NEWLINE); if (rib->type == ZEBRA_ROUTE_CONNECT) --- 927,934 ---- VTY_NEWLINE); vty_out (vty, " Route type \"%s\"", route_info[rib->type].str_long, VTY_NEWLINE); ! vty_out (vty, ", distance %d, metric %d, table %d%s", rib->distance, ! rib->metric, rib->table, VTY_NEWLINE); if (rib->type == ZEBRA_ROUTE_CONNECT) diff -c -r zebra-0.89/zebra/zserv.c zebra-0.89-rap/zebra/zserv.c *** zebra-0.89/zebra/zserv.c Fri Sep 8 00:22:25 2000 --- zebra-0.89-rap/zebra/zserv.c Fri Oct 13 02:33:04 2000 *************** *** 513,518 **** --- 513,519 ---- struct in_addr nexthop; unsigned long ifindex; struct prefix_ipv4 p; + int table = client->rtm_table; s = client->ibuf; ifindex = 0; *************** *** 550,557 **** api.metric = stream_getl (s); else api.metric = 0; ! rib_add_ipv4 (api.type, api.flags, &p, &nexthop, ifindex, client->rtm_table, api.metric, api.distance); } --- 551,563 ---- api.metric = stream_getl (s); else api.metric = 0; + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TABLE)) + { + api.table = stream_getc (s); + table = api.table; + } ! rib_add_ipv4 (api.type, api.flags, &p, &nexthop, ifindex, table, api.metric, api.distance); } *************** *** 565,570 **** --- 571,577 ---- struct in_addr nexthop; unsigned long ifindex; struct prefix_ipv4 p; + int table = rtm_table_default; s = client->ibuf; ifindex = 0; *************** *** 602,610 **** api.metric = stream_getl (s); else api.metric = 0; ! rib_delete_ipv4 (api.type, api.flags, &p, &nexthop, ifindex, ! client->rtm_table); } /* Nexthop lookup for IPv4. */ --- 609,621 ---- api.metric = stream_getl (s); else api.metric = 0; + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TABLE)) + { + api.table = stream_getc (s); + table = api.table; + } ! rib_delete_ipv4 (api.type, api.flags, &p, &nexthop, ifindex, table); } /* Nexthop lookup for IPv4. */ *************** *** 668,673 **** --- 679,686 ---- api.metric = stream_getl (s); else api.metric = 0; + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TABLE)) + api.table = stream_getc (s); if (IN6_IS_ADDR_UNSPECIFIED (&nexthop)) rib_add_ipv6 (api.type, api.flags, &p, NULL, ifindex, 0); *************** *** 722,728 **** api.metric = stream_getl (s); else api.metric = 0; ! if (IN6_IS_ADDR_UNSPECIFIED (&nexthop)) rib_delete_ipv6 (api.type, api.flags, &p, NULL, ifindex, 0); else --- 735,743 ---- api.metric = stream_getl (s); else api.metric = 0; ! if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TABLE)) ! api.table = stream_getc (s); ! if (IN6_IS_ADDR_UNSPECIFIED (&nexthop)) rib_delete_ipv6 (api.type, api.flags, &p, NULL, ifindex, 0); else diff -c -r zebra-0.89/AUTHORS zebra-0.89-rap/AUTHORS *** zebra-0.89/AUTHORS Tue Aug 31 16:53:31 1999 --- zebra-0.89-rap/AUTHORS Sat Oct 28 16:49:16 2000 *************** *** 2,4 **** --- 2,5 ---- Toshiaki Takada Yasuhiro Ohara Alex D. Zinin + Rick Payne