From 0aabccc0a849346fe45838b293add0ef79a71b07 Mon Sep 17 00:00:00 2001 From: Dinesh G Dutt Date: Tue, 15 Sep 2015 23:48:00 -0700 Subject: [PATCH] Zebra: Add IPv6 protocol filtering support & Setting Src of IPv6 routes Ticket: Reviewed By: CCR-3335 Testing Done: bgpsmoke, ENHE tests etc. Add support for filtering routes from upper layer protocols to zebra via route-maps for IPv6. The same functionality already existed for IPv4. In addition, add support for setting source of routes via IPv6 protocol map. Signed-off-by: Dinesh G Dutt Reviewed-by: Donald Sharp Reviewed-by: Vivek Venkataraman Reviewed-by: Vipin Kumar --- lib/if.c | 35 ++++++-- lib/if.h | 4 +- ospfd/ospf_packet.c | 2 +- ripd/rip_snmp.c | 2 +- ripd/ripd.c | 8 +- zebra/redistribute.c | 27 ------ zebra/redistribute.h | 2 - zebra/rib.h | 1 + zebra/rt_netlink.c | 150 +++++++++++++++++++++++-------- zebra/zebra_rib.c | 33 ++++++- zebra/zebra_routemap.c | 194 +++++++++++++++++++++++++++++++++++------ 11 files changed, 345 insertions(+), 113 deletions(-) diff --git a/lib/if.c b/lib/if.c index 0e88c601f7..3003e4c2f4 100644 --- a/lib/if.c +++ b/lib/if.c @@ -257,7 +257,7 @@ if_lookup_by_name_len(const char *name, size_t namelen) /* Lookup interface by IPv4 address. */ struct interface * -if_lookup_exact_address (struct in_addr src) +if_lookup_exact_address (void *src, int family) { struct listnode *node; struct listnode *cnode; @@ -271,11 +271,19 @@ if_lookup_exact_address (struct in_addr src) { p = c->address; - if (p && p->family == AF_INET) + if (p && (p->family == family)) { - if (IPV4_ADDR_SAME (&p->u.prefix4, &src)) - return ifp; - } + if (family == AF_INET) + { + if (IPV4_ADDR_SAME (&p->u.prefix4, (struct in_addr *)src)) + return ifp; + } + else if (family == AF_INET6) + { + if (IPV6_ADDR_SAME (&p->u.prefix4, (struct in6_addr *)src)) + return ifp; + } + } } } return NULL; @@ -283,7 +291,7 @@ if_lookup_exact_address (struct in_addr src) /* Lookup interface by IPv4 address. */ struct interface * -if_lookup_address (struct in_addr src) +if_lookup_address (void *matchaddr, int family) { struct listnode *node; struct prefix addr; @@ -293,9 +301,18 @@ if_lookup_address (struct in_addr src) struct connected *c; struct interface *match; - addr.family = AF_INET; - addr.u.prefix4 = src; - addr.prefixlen = IPV4_MAX_BITLEN; + if (family == AF_INET) + { + addr.family = AF_INET; + addr.u.prefix4 = *((struct in_addr *)matchaddr); + addr.prefixlen = IPV4_MAX_BITLEN; + } + else if (family == AF_INET6) + { + addr.family = AF_INET6; + addr.u.prefix6 = *((struct in6_addr *)matchaddr); + addr.prefixlen = IPV6_MAX_BITLEN; + } match = NULL; diff --git a/lib/if.h b/lib/if.h index 8014fb56cd..6d4ca2f77e 100644 --- a/lib/if.h +++ b/lib/if.h @@ -266,8 +266,8 @@ struct nbr_connected extern int if_cmp_func (struct interface *, struct interface *); extern struct interface *if_create (const char *name, int namelen); extern struct interface *if_lookup_by_index (unsigned int); -extern struct interface *if_lookup_exact_address (struct in_addr); -extern struct interface *if_lookup_address (struct in_addr); +extern struct interface *if_lookup_exact_address (void *matchaddr, int family); +extern struct interface *if_lookup_address (void *matchaddr, int family); extern struct interface *if_lookup_prefix (struct prefix *prefix); extern struct connected *if_anchor_lookup_by_address (struct in_addr src); diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index 5d2e82d8b7..468810e8a3 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -2811,7 +2811,7 @@ ospf_read (struct thread *thread) /* Handle cases where the platform does not support retrieving the ifindex, and also platforms (such as Solaris 8) that claim to support ifindex retrieval but do not. */ - ifp = if_lookup_address (iph->ip_src); + ifp = if_lookup_address ((void *)&iph->ip_src, AF_INET); if (ifp == NULL) return 0; diff --git a/ripd/rip_snmp.c b/ripd/rip_snmp.c index 2df815b03f..9d4e60dbb1 100644 --- a/ripd/rip_snmp.c +++ b/ripd/rip_snmp.c @@ -255,7 +255,7 @@ rip2IfLookup (struct variable *v, oid name[], size_t *length, oid2in_addr (name + v->namelen, sizeof (struct in_addr), addr); - return if_lookup_exact_address (*addr); + return if_lookup_exact_address ((void *)addr, AF_INET); } else { diff --git a/ripd/ripd.c b/ripd/ripd.c index ee7dfc3cba..fc5b65a0c5 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -1125,7 +1125,7 @@ rip_response_process (struct rip_packet *packet, int size, /* The datagram's IPv4 source address should be checked to see whether the datagram is from a valid neighbor; the source of the datagram must be on a directly connected network (RFC2453 - Sec. 3.9.2) */ - if (if_lookup_address(from->sin_addr) == NULL) + if (if_lookup_address((void *)&from->sin_addr, AF_INET) == NULL) { zlog_info ("This datagram doesn't came from a valid neighbor: %s", inet_ntoa (from->sin_addr)); @@ -1211,7 +1211,7 @@ rip_response_process (struct rip_packet *packet, int size, continue; } - if (! if_lookup_address (rte->nexthop)) + if (! if_lookup_address ((void *)&rte->nexthop, AF_INET)) { struct route_node *rn; struct rip_info *rinfo; @@ -1843,7 +1843,7 @@ rip_read (struct thread *t) } /* Which interface is this packet comes from. */ - ifp = if_lookup_address (from.sin_addr); + ifp = if_lookup_address ((void *)&from.sin_addr, AF_INET); /* RIP packet received */ if (IS_RIP_DEBUG_EVENT) @@ -2525,7 +2525,7 @@ rip_update_process (int route_type) { p = (struct prefix_ipv4 *) &rp->p; - ifp = if_lookup_address (p->prefix); + ifp = if_lookup_address ((void *)&p->prefix, AF_INET); if (! ifp) { zlog_warn ("Neighbor %s doesnt have connected interface!", diff --git a/zebra/redistribute.c b/zebra/redistribute.c index 6dfb455f41..0f4cf95217 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -62,33 +62,6 @@ is_zebra_import_table_enabled(afi_t afi, u_int32_t table_id) return 0; } -int -zebra_check_addr (struct prefix *p) -{ - if (p->family == AF_INET) - { - u_int32_t addr; - - addr = p->u.prefix4.s_addr; - addr = ntohl (addr); - - if (IPV4_NET127 (addr) - || IN_CLASSD (addr) - || IPV4_LINKLOCAL(addr)) - return 0; - } -#ifdef HAVE_IPV6 - if (p->family == AF_INET6) - { - if (IN6_IS_ADDR_LOOPBACK (&p->u.prefix6)) - return 0; - if (IN6_IS_ADDR_LINKLOCAL(&p->u.prefix6)) - return 0; - } -#endif /* HAVE_IPV6 */ - return 1; -} - static int is_default (struct prefix *p) { diff --git a/zebra/redistribute.h b/zebra/redistribute.h index a4f321979d..3ee6b9cd4d 100644 --- a/zebra/redistribute.h +++ b/zebra/redistribute.h @@ -46,8 +46,6 @@ extern void zebra_interface_address_add_update (struct interface *, struct connected *); extern void zebra_interface_address_delete_update (struct interface *, struct connected *c); -extern int zebra_check_addr (struct prefix *); - extern int zebra_import_table (afi_t afi, u_int32_t table_id, u_int32_t metric, int add); diff --git a/zebra/rib.h b/zebra/rib.h index 45daad0fed..7d9e2f7770 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -393,6 +393,7 @@ extern struct route_table *vrf_other_route_table (afi_t afi, u_int32_t table_id, u_int32_t vrf_id); extern int is_zebra_valid_kernel_table(u_int32_t table_id); extern int is_zebra_main_routing_table(u_int32_t table_id); +extern int zebra_check_addr (struct prefix *p); /* NOTE: * All rib_add_ipv[46]* functions will not just add prefix into RIB, but diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 99c4ab54f8..e0124dcb49 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1513,12 +1513,15 @@ _netlink_route_build_singlepath( addattr_l (nlmsg, req_size, RTA_GATEWAY, &nexthop->gate.ipv4, bytelen); - if (nexthop->rmap_src.ipv4.s_addr && (cmd == RTM_NEWROUTE)) - addattr_l (nlmsg, req_size, RTA_PREFSRC, - &nexthop->rmap_src.ipv4, bytelen); - else if (nexthop->src.ipv4.s_addr && (cmd == RTM_NEWROUTE)) - addattr_l (nlmsg, req_size, RTA_PREFSRC, - &nexthop->src.ipv4, bytelen); + if (cmd == RTM_NEWROUTE) + { + if (nexthop->rmap_src.ipv4.s_addr) + addattr_l (nlmsg, req_size, RTA_PREFSRC, + &nexthop->rmap_src.ipv4, bytelen); + else if (nexthop->src.ipv4.s_addr) + addattr_l (nlmsg, req_size, RTA_PREFSRC, + &nexthop->src.ipv4, bytelen); + } if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("netlink_route_multipath() (%s): " @@ -1535,6 +1538,16 @@ _netlink_route_build_singlepath( addattr_l (nlmsg, req_size, RTA_GATEWAY, &nexthop->gate.ipv6, bytelen); + if (cmd == RTM_NEWROUTE) + { + if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6)) + addattr_l (nlmsg, req_size, RTA_PREFSRC, + &nexthop->rmap_src.ipv6, bytelen); + else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->src.ipv6)) + addattr_l (nlmsg, req_size, RTA_PREFSRC, + &nexthop->src.ipv6, bytelen); + } + if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("netlink_route_multipath() (%s): " "nexthop via %s if %u", @@ -1549,12 +1562,15 @@ _netlink_route_build_singlepath( { addattr32 (nlmsg, req_size, RTA_OIF, nexthop->ifindex); - if (nexthop->rmap_src.ipv4.s_addr && (cmd == RTM_NEWROUTE)) - addattr_l (nlmsg, req_size, RTA_PREFSRC, - &nexthop->rmap_src.ipv4, bytelen); - else if (nexthop->src.ipv4.s_addr && (cmd == RTM_NEWROUTE)) - addattr_l (nlmsg, req_size, RTA_PREFSRC, - &nexthop->src.ipv4, bytelen); + if (cmd == RTM_NEWROUTE) + { + if (nexthop->rmap_src.ipv4.s_addr) + addattr_l (nlmsg, req_size, RTA_PREFSRC, + &nexthop->rmap_src.ipv4, bytelen); + else if (nexthop->src.ipv4.s_addr) + addattr_l (nlmsg, req_size, RTA_PREFSRC, + &nexthop->src.ipv4, bytelen); + } if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("netlink_route_multipath() (%s): " @@ -1566,6 +1582,16 @@ _netlink_route_build_singlepath( { addattr32 (nlmsg, req_size, RTA_OIF, nexthop->ifindex); + if (cmd == RTM_NEWROUTE) + { + if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6)) + addattr_l (nlmsg, req_size, RTA_PREFSRC, + &nexthop->rmap_src.ipv6, bytelen); + else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->src.ipv6)) + addattr_l (nlmsg, req_size, RTA_PREFSRC, + &nexthop->src.ipv6, bytelen); + } + if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("netlink_route_multipath() (%s): " "nexthop via if %u", routedesc, nexthop->ifindex); @@ -1657,6 +1683,12 @@ _netlink_route_build_multipath( rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY, &nexthop->gate.ipv6, bytelen); rtnh->rtnh_len += sizeof (struct rtattr) + bytelen; + + if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6)) + *src = &nexthop->rmap_src; + else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->src.ipv6)) + *src = &nexthop->src; + if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("netlink_route_multipath() (%s): " "nexthop via %s if %u", @@ -1860,19 +1892,34 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, { if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) { - /* This only works for IPv4 now */ if (!setsrc) { - if (nexthop->rmap_src.ipv4.s_addr != 0) - { - src.ipv4 = nexthop->rmap_src.ipv4; - setsrc = 1; - } - else if (nexthop->src.ipv4.s_addr != 0) - { - src.ipv4 = nexthop->src.ipv4; - setsrc = 1; - } + if (family == AF_INET) + { + if (nexthop->rmap_src.ipv4.s_addr != 0) + { + src.ipv4 = nexthop->rmap_src.ipv4; + setsrc = 1; + } + else if (nexthop->src.ipv4.s_addr != 0) + { + src.ipv4 = nexthop->src.ipv4; + setsrc = 1; + } + } + else if (family == AF_INET6) + { + if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6)) + { + src.ipv6 = nexthop->rmap_src.ipv6; + setsrc = 1; + } + else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->src.ipv6)) + { + src.ipv6 = nexthop->src.ipv6; + setsrc = 1; + } + } } continue; } @@ -1897,7 +1944,12 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, } } if (setsrc && (cmd == RTM_NEWROUTE)) - addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src.ipv4, bytelen); + { + if (family == AF_INET) + addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src.ipv4, bytelen); + else if (family == AF_INET6) + addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src.ipv6, bytelen); + } } else { @@ -1921,16 +1973,32 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, /* This only works for IPv4 now */ if (!setsrc) { - if (nexthop->rmap_src.ipv4.s_addr != 0) - { - src.ipv4 = nexthop->rmap_src.ipv4; - setsrc = 1; - } - else if (nexthop->src.ipv4.s_addr != 0) - { - src.ipv4 = nexthop->src.ipv4; - setsrc = 1; - } + if (family == AF_INET) + { + if (nexthop->rmap_src.ipv4.s_addr != 0) + { + src.ipv4 = nexthop->rmap_src.ipv4; + setsrc = 1; + } + else if (nexthop->src.ipv4.s_addr != 0) + { + src.ipv4 = nexthop->src.ipv4; + setsrc = 1; + } + } + else if (family == AF_INET6) + { + if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6)) + { + src.ipv6 = nexthop->rmap_src.ipv6; + setsrc = 1; + } + else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->src.ipv6)) + { + src.ipv6 = nexthop->src.ipv6; + setsrc = 1; + } + } } continue; } @@ -1954,13 +2022,23 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, if (!setsrc && src1) { - src.ipv4 = src1->ipv4; + if (family == AF_INET) + src.ipv4 = src1->ipv4; + else if (family == AF_INET6) + src.ipv6 = src1->ipv6; + setsrc = 1; } } } if (setsrc && (cmd == RTM_NEWROUTE)) - addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src.ipv4, bytelen); + { + if (family == AF_INET) + addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src.ipv4, bytelen); + else if (family == AF_INET6) + addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src.ipv6, bytelen); + zlog_debug("Setting source"); + } if (rta->rta_len > RTA_LENGTH (0)) addattr_l (&req.n, NL_PKT_BUF_SIZE, RTA_MULTIPATH, RTA_DATA (rta), diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 83ae03eb1f..261aed156f 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -231,6 +231,33 @@ is_zebra_main_routing_table(u_int32_t table_id) return 0; } +int +zebra_check_addr (struct prefix *p) +{ + if (p->family == AF_INET) + { + u_int32_t addr; + + addr = p->u.prefix4.s_addr; + addr = ntohl (addr); + + if (IPV4_NET127 (addr) + || IN_CLASSD (addr) + || IPV4_LINKLOCAL(addr)) + return 0; + } +#ifdef HAVE_IPV6 + if (p->family == AF_INET6) + { + if (IN6_IS_ADDR_LOOPBACK (&p->u.prefix6)) + return 0; + if (IN6_IS_ADDR_LINKLOCAL(&p->u.prefix6)) + return 0; + } +#endif /* HAVE_IPV6 */ + return 1; +} + /* Add nexthop to the end of a nexthop list. */ static void _nexthop_add (struct nexthop **target, struct nexthop *nexthop) @@ -1298,7 +1325,6 @@ nexthop_active_check (struct route_node *rn, struct rib *rib, } UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); } - return CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); } @@ -1336,7 +1362,10 @@ nexthop_active_update (struct route_node *rn, struct rib *rib, int set) prev_index != nexthop->ifindex || ((nexthop->type >= NEXTHOP_TYPE_IFINDEX && nexthop->type < NEXTHOP_TYPE_IPV6) && - prev_src.ipv4.s_addr != nexthop->rmap_src.ipv4.s_addr)) + prev_src.ipv4.s_addr != nexthop->rmap_src.ipv4.s_addr) || + ((nexthop->type >= NEXTHOP_TYPE_IPV6 && + nexthop->type < NEXTHOP_TYPE_BLACKHOLE) && + !(IPV6_ADDR_SAME (&prev_src.ipv6, &nexthop->rmap_src.ipv6)))) { SET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED); SET_FLAG (rib->status, RIB_ENTRY_NEXTHOPS_CHANGED); diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index 6648b8a4d5..a6ba643728 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -648,32 +648,57 @@ DEFUN (no_match_source_protocol, DEFUN (set_src, set_src_cmd, - "set src A.B.C.D", + "set src (A.B.C.D|X:X::X:X)", SET_STR "src address for route\n" "src address\n") { - struct in_addr src; - struct interface *pif; + union g_addr src; + struct interface *pif = NULL; + int family; + struct prefix p; - if (inet_pton(AF_INET, argv[0], &src) <= 0) + if (inet_pton(AF_INET, argv[0], &src.ipv4) != 1) + { + if (inet_pton(AF_INET6, argv[0], &src.ipv6) != 1) + { + vty_out (vty, "%% not a valid IPv4/v6 address%s", VTY_NEWLINE); + return CMD_WARNING; + } + + p.family = family = AF_INET6; + p.u.prefix6 = src.ipv6; + p.prefixlen = IPV6_MAX_BITLEN; + } + else + { + p.family = family = AF_INET; + p.u.prefix4 = src.ipv4; + p.prefixlen = IPV4_MAX_BITLEN; + } + + if (!zebra_check_addr(&p)) + { + vty_out (vty, "%% not a valid source IPv4/v6 address%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (family == AF_INET) + pif = if_lookup_exact_address ((void *)&src.ipv4, AF_INET); + else if (family == AF_INET6) + pif = if_lookup_exact_address ((void *)&src.ipv6, AF_INET6); + + if (!pif) { vty_out (vty, "%% not a local address%s", VTY_NEWLINE); return CMD_WARNING; } - - pif = if_lookup_exact_address (src); - if (!pif) - { - vty_out (vty, "%% not a local address%s", VTY_NEWLINE); - return CMD_WARNING; - } return zebra_route_set_add (vty, vty->index, "src", argv[0]); } DEFUN (no_set_src, no_set_src_cmd, - "no set src", + "no set src {A.B.C.D|X:X::X:X}", NO_STR SET_STR "Source address for route\n") @@ -684,14 +709,6 @@ DEFUN (no_set_src, return zebra_route_set_delete (vty, vty->index, "src", argv[0]); } -ALIAS (no_set_src, - no_set_src_val_cmd, - "no set src (A.B.C.D)", - NO_STR - SET_STR - "src address for route\n" - "src address\n") - DEFUN (zebra_route_map_timer, zebra_route_map_timer_cmd, "zebra route-map delay-timer <0-600>", @@ -822,6 +839,112 @@ DEFUN (show_ip_protocol, return CMD_SUCCESS; } +DEFUN (ipv6_protocol, + ipv6_protocol_cmd, + "ipv6 protocol " QUAGGA_IP6_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP", + IP6_STR + "Filter IPv6 routing info exchanged between zebra and protocol\n" + QUAGGA_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA + "Route map name\n") +{ + int i; + u_int32_t table_id; + + if (strcasecmp(argv[0], "any") == 0) + i = ZEBRA_ROUTE_MAX; + else + i = proto_name2num(argv[0]); + if (i < 0) + { + vty_out (vty, "invalid protocol name \"%s\"%s", argv[0] ? argv[0] : "", + VTY_NEWLINE); + return CMD_WARNING; + } + if (proto_rm[AFI_IP6][i]) + { + if (strcmp(proto_rm[AFI_IP6][i], argv[1]) == 0) + return CMD_SUCCESS; + + XFREE (MTYPE_ROUTE_MAP_NAME, proto_rm[AFI_IP6][i]); + } + proto_rm[AFI_IP6][i] = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[1]); + rib_update(); + return CMD_SUCCESS; +} + +DEFUN (no_ipv6_protocol, + no_ipv6_protocol_cmd, + "no ipv6 protocol " QUAGGA_IP6_PROTOCOL_MAP_STR_ZEBRA, + NO_STR + IP6_STR + "Stop filtering IPv6 routing info between zebra and protocol\n" + QUAGGA_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA + "Protocol from which to stop filtering routes\n") +{ + int i; + u_int32_t table_id; + + if (strcasecmp(argv[0], "any") == 0) + i = ZEBRA_ROUTE_MAX; + else + i = proto_name2num(argv[0]); + if (i < 0) + { + vty_out (vty, "invalid protocol name \"%s\"%s", argv[0] ? argv[0] : "", + VTY_NEWLINE); + return CMD_WARNING; + } + if (!proto_rm[AFI_IP6][i]) + return CMD_SUCCESS; + + if ((argc == 2 && strcmp(argv[1], proto_rm[AFI_IP6][i]) == 0) || + (argc < 2)) + { + XFREE (MTYPE_ROUTE_MAP_NAME, proto_rm[AFI_IP6][i]); + proto_rm[AFI_IP6][i] = NULL; + rib_update(); + } + return CMD_SUCCESS; +} + +ALIAS (no_ipv6_protocol, + no_ipv6_protocol_val_cmd, + "no ipv6 protocol " QUAGGA_IP6_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP", + NO_STR + IP6_STR + "Stop filtering IPv6 routing info between zebra and protocol\n" + QUAGGA_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA + "route map name") + +DEFUN (show_ipv6_protocol, + show_ipv6_protocol_cmd, + "show ipv6 protocol", + SHOW_STR + IP6_STR + "IPv6 protocol filtering status\n") +{ + int i; + + vty_out(vty, "Protocol : route-map %s", VTY_NEWLINE); + vty_out(vty, "------------------------%s", VTY_NEWLINE); + for (i=0;i