diff options
-rw-r--r-- | ripd/ChangeLog | 4 | ||||
-rw-r--r-- | ripd/Makefile.am | 2 | ||||
-rw-r--r-- | ripd/rip_interface.c | 237 | ||||
-rw-r--r-- | ripd/rip_routemap.c | 273 | ||||
-rw-r--r-- | ripd/rip_zebra.c | 42 | ||||
-rw-r--r-- | ripd/ripd.c | 280 | ||||
-rw-r--r-- | ripd/ripd.h | 15 |
7 files changed, 742 insertions, 111 deletions
diff --git a/ripd/ChangeLog b/ripd/ChangeLog index 49501693..c80338dd 100644 --- a/ripd/ChangeLog +++ b/ripd/ChangeLog @@ -1,3 +1,7 @@ +2003-05-25 Vincent Jardin <vjardin@wanadoo.fr> + + * 6Wind patch merge. + 2003-04-19 Hasso Tepper <hasso@estpak.ee> * rip_routemap.c: sync daemon's route-map commands to have same diff --git a/ripd/Makefile.am b/ripd/Makefile.am index fd254851..df9a0af5 100644 --- a/ripd/Makefile.am +++ b/ripd/Makefile.am @@ -17,7 +17,7 @@ noinst_HEADERS = \ ripd_SOURCES = \ rip_main.c $(librip_a_SOURCES) -ripd_LDADD = ../lib/libzebra.a +ripd_LDADD = -L../lib -lzebra sysconf_DATA = ripd.conf.sample diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c index 23c9cb0b..8ec96ae1 100644 --- a/ripd/rip_interface.c +++ b/ripd/rip_interface.c @@ -43,6 +43,10 @@ void rip_enable_apply (struct interface *); void rip_passive_interface_apply (struct interface *); int rip_if_down(struct interface *ifp); +int rip_enable_if_lookup (char *ifname); +int rip_enable_network_lookup2 (struct connected *connected); +void rip_enable_apply_all (); + struct message ri_version_msg[] = { @@ -122,7 +126,7 @@ rip_interface_new () Relay or SMDS is enabled, the default value for split-horizon is off. But currently Zebra does detect Frame Relay or SMDS interface. So all interface is set to split horizon. */ - ri->split_horizon_default = 1; + ri->split_horizon_default = RIP_SPLIT_HORIZON; ri->split_horizon = ri->split_horizon_default; return ri; @@ -226,10 +230,8 @@ rip_request_interface_send (struct interface *ifp, u_char version) to.sin_port = htons (RIP_PORT_DEFAULT); to.sin_addr = p->prefix; -#if 0 if (IS_RIP_DEBUG_EVENT) zlog_info ("SEND request to %s", inet_ntoa (to.sin_addr)); -#endif /* 0 */ rip_request_send (&to, ifp, version); } @@ -466,6 +468,9 @@ rip_interface_add (int command, struct zclient *zclient, zebra_size_t length) /* rip_request_neighbor_all (); */ + /* Check interface routemap. */ + rip_if_rmap_update_interface (ifp); + return 0; } @@ -554,8 +559,8 @@ rip_interface_reset () ri->key_chain = NULL; } - ri->split_horizon = 0; - ri->split_horizon_default = 0; + ri->split_horizon = RIP_NO_SPLIT_HORIZON; + ri->split_horizon_default = RIP_NO_SPLIT_HORIZON; ri->list[RIP_FILTER_IN] = NULL; ri->list[RIP_FILTER_OUT] = NULL; @@ -644,6 +649,34 @@ rip_if_down_all () } } +static void +rip_apply_address_add (struct connected *ifc) { + struct prefix_ipv4 address; + struct prefix *p; + + if (!rip) + return; + + if (! if_is_up(ifc->ifp)) + return; + + p = ifc->address; + + memset (&address, 0, sizeof (address)); + address.family = p->family; + address.prefix = p->u.prefix4; + address.prefixlen = p->prefixlen; + apply_mask_ipv4(&address); + + /* Check if this interface is RIP enabled or not + or Check if this address's prefix is RIP enabled */ + if ((rip_enable_if_lookup(ifc->ifp->name) >= 0) || + (rip_enable_network_lookup2(ifc) >= 0)) + rip_redistribute_add(ZEBRA_ROUTE_CONNECT, RIP_ROUTE_INTERFACE, + &address, ifc->ifp->ifindex, NULL); + +} + int rip_interface_address_add (int command, struct zclient *zclient, zebra_size_t length) @@ -663,9 +696,9 @@ rip_interface_address_add (int command, struct zclient *zclient, if (IS_RIP_DEBUG_ZEBRA) zlog_info ("connected address %s/%d is added", inet_ntoa (p->u.prefix4), p->prefixlen); - - /* Check is this interface is RIP enabled or not.*/ - rip_enable_apply (ifc->ifp); + + /* Check if this prefix needs to be redistributed */ + rip_apply_address_add(ifc); #ifdef HAVE_SNMP rip_ifaddr_add (ifc->ifp, ifc); @@ -675,6 +708,29 @@ rip_interface_address_add (int command, struct zclient *zclient, return 0; } +static void +rip_apply_address_del (struct connected *ifc) { + struct prefix_ipv4 address; + struct prefix *p; + + if (!rip) + return; + + if (! if_is_up(ifc->ifp)) + return; + + p = ifc->address; + + memset (&address, 0, sizeof (address)); + address.family = p->family; + address.prefix = p->u.prefix4; + address.prefixlen = p->prefixlen; + apply_mask_ipv4(&address); + + rip_redistribute_delete(ZEBRA_ROUTE_CONNECT, RIP_ROUTE_INTERFACE, + &address, ifc->ifp->ifindex); +} + int rip_interface_address_delete (int command, struct zclient *zclient, zebra_size_t length) @@ -698,8 +754,9 @@ rip_interface_address_delete (int command, struct zclient *zclient, rip_ifaddr_delete (ifc->ifp, ifc); #endif /* HAVE_SNMP */ - /* Check if this interface is RIP enabled or not.*/ - rip_enable_apply (ifc->ifp); + /* Chech wether this prefix needs to be removed */ + rip_apply_address_del(ifc); + } connected_free (ifc); @@ -710,8 +767,10 @@ rip_interface_address_delete (int command, struct zclient *zclient, } /* Check interface is enabled by network statement. */ +/* Check wether the interface has at least a connected prefix that + * is within the ripng_enable_network table. */ int -rip_enable_network_lookup (struct interface *ifp) +rip_enable_network_lookup_if (struct interface *ifp) { struct listnode *nn; struct connected *connected; @@ -743,6 +802,34 @@ rip_enable_network_lookup (struct interface *ifp) return -1; } +/* Check wether connected is within the ripng_enable_network table. */ +int +rip_enable_network_lookup2 (struct connected *connected) +{ + struct prefix_ipv4 address; + struct prefix *p; + + p = connected->address; + + if (p->family == AF_INET) { + struct route_node *node; + + address.family = p->family; + address.prefix = p->u.prefix4; + address.prefixlen = IPV4_MAX_BITLEN; + + /* LPM on p->family, p->u.prefix4/IPV4_MAX_BITLEN within rip_enable_network */ + node = route_node_match (rip_enable_network, + (struct prefix *)&address); + + if (node) { + route_unlock_node (node); + return 1; + } + } + + return -1; +} /* Add RIP enable network. */ int rip_enable_network_add (struct prefix *p) @@ -759,6 +846,9 @@ rip_enable_network_add (struct prefix *p) else node->info = "enabled"; + /* XXX: One should find a better solution than a generic one */ + rip_enable_apply_all(); + return 1; } @@ -779,6 +869,9 @@ rip_enable_network_delete (struct prefix *p) /* Unlock lookup lock. */ route_unlock_node (node); + /* XXX: One should find a better solution than a generic one */ + rip_enable_apply_all (); + return 1; } return -1; @@ -810,6 +903,8 @@ rip_enable_if_add (char *ifname) vector_set (rip_enable_interface, strdup (ifname)); + rip_enable_apply_all(); /* TODOVJ */ + return 1; } @@ -828,6 +923,8 @@ rip_enable_if_delete (char *ifname) free (str); vector_unset (rip_enable_interface, index); + rip_enable_apply_all(); /* TODOVJ */ + return 1; } @@ -883,10 +980,13 @@ rip_connect_set (struct interface *ifp, int set) address.prefixlen = p->prefixlen; apply_mask_ipv4 (&address); - if (set) - rip_redistribute_add (ZEBRA_ROUTE_CONNECT, RIP_ROUTE_INTERFACE, - &address, connected->ifp->ifindex, NULL); - else + if (set) { + /* Check once more wether this prefix is within a "network IF_OR_PREF" one */ + if ((rip_enable_if_lookup(connected->ifp->name) >= 0) || + (rip_enable_network_lookup2(connected) >= 0)) + rip_redistribute_add (ZEBRA_ROUTE_CONNECT, RIP_ROUTE_INTERFACE, + &address, connected->ifp->ifindex, NULL); + } else { rip_redistribute_delete (ZEBRA_ROUTE_CONNECT, RIP_ROUTE_INTERFACE, &address, connected->ifp->ifindex); @@ -905,16 +1005,13 @@ rip_enable_apply (struct interface *ifp) struct rip_interface *ri = NULL; /* Check interface. */ - if (if_is_loopback (ifp)) - return; - if (! if_is_operative (ifp)) return; ri = ifp->info; /* Check network configuration. */ - ret = rip_enable_network_lookup (ifp); + ret = rip_enable_network_lookup_if (ifp); /* If the interface is matched. */ if (ret > 0) @@ -939,7 +1036,6 @@ rip_enable_apply (struct interface *ifp) /* Update running status of the interface. */ if (ri->enable_network || ri->enable_interface) { - if (! ri->running) { if (IS_RIP_DEBUG_EVENT) zlog_info ("turn on %s", ifp->name); @@ -955,13 +1051,11 @@ rip_enable_apply (struct interface *ifp) { if (ri->running) { - if (IS_RIP_DEBUG_EVENT) - zlog_info ("turn off %s", ifp->name); - - /* Might as well clean up the route table as well */ + /* Might as well clean up the route table as well + * rip_if_down sets to 0 ri->running, and displays "turn off %s" + **/ rip_if_down(ifp); - ri->running = 0; rip_connect_set (ifp, 0); } } @@ -1181,8 +1275,6 @@ DEFUN (rip_network, return CMD_WARNING; } - rip_enable_apply_all (); - return CMD_SUCCESS; } @@ -1212,8 +1304,6 @@ DEFUN (no_rip_network, return CMD_WARNING; } - rip_enable_apply_all (); - return CMD_SUCCESS; } @@ -1661,10 +1751,15 @@ ALIAS (no_ip_rip_authentication_key_chain, "Authentication key-chain\n" "name of key-chain\n") -DEFUN (rip_split_horizon, - rip_split_horizon_cmd, - "ip split-horizon", +/* CHANGED: ip rip split-horizon + Cisco and Zebra's command is + ip split-horizon + */ +DEFUN (ip_rip_split_horizon, + ip_rip_split_horizon_cmd, + "ip rip split-horizon", IP_STR + "Routing Information Protocol\n" "Perform split horizon\n") { struct interface *ifp; @@ -1673,15 +1768,38 @@ DEFUN (rip_split_horizon, ifp = vty->index; ri = ifp->info; - ri->split_horizon = 1; + ri->split_horizon = RIP_SPLIT_HORIZON; return CMD_SUCCESS; } -DEFUN (no_rip_split_horizon, - no_rip_split_horizon_cmd, - "no ip split-horizon", +DEFUN (ip_rip_split_horizon_poisoned_reverse, + ip_rip_split_horizon_poisoned_reverse_cmd, + "ip rip split-horizon poisoned-reverse", + IP_STR + "Routing Information Protocol\n" + "Perform split horizon\n" + "With poisoned-reverse\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = vty->index; + ri = ifp->info; + + ri->split_horizon = RIP_SPLIT_HORIZON_POISONED_REVERSE; + return CMD_SUCCESS; +} + +/* CHANGED: no ip rip split-horizon + Cisco and Zebra's command is + no ip split-horizon + */ +DEFUN (no_ip_rip_split_horizon, + no_ip_rip_split_horizon_cmd, + "no ip rip split-horizon", NO_STR IP_STR + "Routing Information Protocol\n" "Perform split horizon\n") { struct interface *ifp; @@ -1690,10 +1808,19 @@ DEFUN (no_rip_split_horizon, ifp = vty->index; ri = ifp->info; - ri->split_horizon = 0; + ri->split_horizon = RIP_NO_SPLIT_HORIZON; return CMD_SUCCESS; } +ALIAS (no_ip_rip_split_horizon, + no_ip_rip_split_horizon_poisoned_reverse_cmd, + "no ip rip split-horizon poisoned-reverse", + NO_STR + IP_STR + "Routing Information Protocol\n" + "Perform split horizon\n" + "With poisoned-reverse\n") + DEFUN (rip_passive_interface, rip_passive_interface_cmd, "passive-interface IFNAME", @@ -1727,6 +1854,18 @@ rip_interface_config_write (struct vty *vty) ifp = getdata (node); ri = ifp->info; + /* Do not display the interface if there is no + * configuration about it. + **/ + if ((!ifp->desc) && + (ri->split_horizon == ri->split_horizon_default) && + (ri->ri_send == RI_RIP_UNSPEC) && + (ri->ri_receive == RI_RIP_UNSPEC) && + (ri->auth_type != RIP_AUTH_MD5) && + (!ri->auth_str) && + (!ri->key_chain) ) + continue; + vty_out (vty, "interface %s%s", ifp->name, VTY_NEWLINE); @@ -1737,10 +1876,19 @@ rip_interface_config_write (struct vty *vty) /* Split horizon. */ if (ri->split_horizon != ri->split_horizon_default) { - if (ri->split_horizon) - vty_out (vty, " ip split-horizon%s", VTY_NEWLINE); - else - vty_out (vty, " no ip split-horizon%s", VTY_NEWLINE); + switch (ri->split_horizon) { + case RIP_SPLIT_HORIZON: + vty_out (vty, " ip rip split-horizon%s", VTY_NEWLINE); + break; + case RIP_SPLIT_HORIZON_POISONED_REVERSE: + vty_out (vty, " ip rip split-horizon poisoned-reverse%s", + VTY_NEWLINE); + break; + case RIP_NO_SPLIT_HORIZON: + default: + vty_out (vty, " no ip rip split-horizon%s", VTY_NEWLINE); + break; + } } /* RIP version setting. */ @@ -1837,6 +1985,7 @@ int rip_interface_delete_hook (struct interface *ifp) { XFREE (MTYPE_RIP_INTERFACE, ifp->info); + ifp->info = NULL; return 0; } @@ -1897,6 +2046,8 @@ rip_if_init () install_element (INTERFACE_NODE, &no_ip_rip_authentication_string_cmd); install_element (INTERFACE_NODE, &no_ip_rip_authentication_string2_cmd); - install_element (INTERFACE_NODE, &rip_split_horizon_cmd); - install_element (INTERFACE_NODE, &no_rip_split_horizon_cmd); + install_element (INTERFACE_NODE, &ip_rip_split_horizon_cmd); + install_element (INTERFACE_NODE, &ip_rip_split_horizon_poisoned_reverse_cmd); + install_element (INTERFACE_NODE, &no_ip_rip_split_horizon_cmd); + install_element (INTERFACE_NODE, &no_ip_rip_split_horizon_poisoned_reverse_cmd); } diff --git a/ripd/rip_routemap.c b/ripd/rip_routemap.c index 8262f508..b354a896 100644 --- a/ripd/rip_routemap.c +++ b/ripd/rip_routemap.c @@ -31,6 +31,18 @@ #include "plist.h" #include "ripd/ripd.h" + +struct rip_metric_modifier +{ + enum + { + metric_increment, + metric_decrement, + metric_absolute + } type; + + u_char metric; +}; /* Add rip route map rule. */ int @@ -439,6 +451,57 @@ struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = route_match_ip_address_prefix_list_compile, route_match_ip_address_prefix_list_free }; + +/* `match tag TAG' */ +/* Match function return 1 if match is success else return zero. */ +route_map_result_t +route_match_tag (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + u_short *tag; + struct rip_info *rinfo; + + if (type == RMAP_RIP) + { + tag = rule; + rinfo = object; + + /* The information stored by rinfo is host ordered. */ + if (rinfo->tag == *tag) + return RMAP_MATCH; + else + return RMAP_NOMATCH; + } + return RMAP_NOMATCH; +} + +/* Route map `match tag' match statement. `arg' is TAG value */ +void * +route_match_tag_compile (char *arg) +{ + u_short *tag; + + tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short)); + *tag = atoi (arg); + + return tag; +} + +/* Free route map's compiled `match tag' value. */ +void +route_match_tag_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for tag matching. */ +struct route_map_rule_cmd route_match_tag_cmd = +{ + "tag", + route_match_tag, + route_match_tag_compile, + route_match_tag_free +}; /* `set metric METRIC' */ @@ -447,17 +510,26 @@ route_map_result_t route_set_metric (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { - u_int32_t *metric; - struct rip_info *rinfo; - if (type == RMAP_RIP) { - /* Fetch routemap's rule information. */ - metric = rule; + struct rip_metric_modifier *mod; + struct rip_info *rinfo; + + mod = rule; rinfo = object; - - /* Set metric out value. */ - rinfo->metric_out = *metric; + + if (mod->type == metric_increment) + rinfo->metric_out += mod->metric; + else if (mod->type == metric_decrement) + rinfo->metric_out -= mod->metric; + else if (mod->type == metric_absolute) + rinfo->metric_out = mod->metric; + + if (rinfo->metric_out < 1) + rinfo->metric_out = 1; + if (rinfo->metric_out > RIP_METRIC_INFINITY) + rinfo->metric_out = RIP_METRIC_INFINITY; + rinfo->metric_set = 1; } return RMAP_OKAY; @@ -467,22 +539,51 @@ route_set_metric (void *rule, struct prefix *prefix, void * route_set_metric_compile (char *arg) { - u_int32_t *metric; + int len; + char *pnt; + int type; + long metric; + char *endptr = NULL; + struct rip_metric_modifier *mod; - metric = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); - *metric = atoi (arg); + len = strlen (arg); + pnt = arg; - return metric; + if (len == 0) + return NULL; -#if 0 - /* To make it consistent to other daemon, metric check is commented - out.*/ - if (*metric >= 0 && *metric <= 16) - return metric; + /* Examine first character. */ + if (arg[0] == '+') + { + type = metric_increment; + pnt++; + } + else if (arg[0] == '-') + { + type = metric_decrement; + pnt++; + } + else + type = metric_absolute; - XFREE (MTYPE_ROUTE_MAP_COMPILED, metric); - return NULL; -#endif /* 0 */ + /* Check beginning with digit string. */ + if (*pnt < '0' || *pnt > '9') + return NULL; + + /* Convert string to integer. */ + metric = strtol (pnt, &endptr, 10); + + if (metric == LONG_MAX || *endptr != '\0') + return NULL; + if (metric < 0 || metric > RIP_METRIC_INFINITY) + return NULL; + + mod = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, + sizeof (struct rip_metric_modifier)); + mod->type = type; + mod->metric = metric; + + return mod; } /* Free route map's compiled `set metric' value. */ @@ -560,6 +661,58 @@ struct route_map_rule_cmd route_set_ip_nexthop_cmd = route_set_ip_nexthop_compile, route_set_ip_nexthop_free }; + +/* `set tag TAG' */ + +/* Set tag to object. ojbect must be pointer to struct attr. */ +route_map_result_t +route_set_tag (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + u_short *tag; + struct rip_info *rinfo; + + if(type == RMAP_RIP) + { + /* Fetch routemap's rule information. */ + tag = rule; + rinfo = object; + + /* Set next hop value. */ + rinfo->tag_out = *tag; + } + + return RMAP_OKAY; +} + +/* Route map `tag' compile function. Given string is converted + to u_short. */ +void * +route_set_tag_compile (char *arg) +{ + u_short *tag; + + tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short)); + *tag = atoi (arg); + + return tag; +} + +/* Free route map's compiled `ip nexthop' value. */ +void +route_set_tag_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for tag set. */ +struct route_map_rule_cmd route_set_tag_cmd = +{ + "tag", + route_set_tag, + route_set_tag_compile, + route_set_tag_free +}; #define MATCH_STR "Match values from routing table\n" #define SET_STR "Set values in destination routing protocol\n" @@ -777,14 +930,46 @@ ALIAS (no_match_ip_address_prefix_list, "Match entries of prefix-lists\n" "IP prefix-list name\n") +DEFUN (match_tag, + match_tag_cmd, + "match tag <0-65535>", + MATCH_STR + "Match tag of route\n" + "Metric value\n") +{ + return rip_route_match_add (vty, vty->index, "tag", argv[0]); +} + +DEFUN (no_match_tag, + no_match_tag_cmd, + "no match tag", + NO_STR + MATCH_STR + "Match tag of route\n") +{ + if (argc == 0) + return rip_route_match_delete (vty, vty->index, "tag", NULL); + + return rip_route_match_delete (vty, vty->index, "tag", argv[0]); +} + +ALIAS (no_match_tag, + no_match_tag_val_cmd, + "no match tag <0-65535>", + NO_STR + MATCH_STR + "Match tag of route\n" + "Metric value\n") + /* set functions */ DEFUN (set_metric, set_metric_cmd, - "set metric <0-4294967295>", + "set metric (<0-4294967295>|<+/-metric>)", SET_STR "Metric value for destination routing protocol\n" - "Metric value\n") + "Metric value\n" + "Add or subtract metric\n") { return rip_route_set_add (vty, vty->index, "metric", argv[0]); } @@ -804,11 +989,12 @@ DEFUN (no_set_metric, ALIAS (no_set_metric, no_set_metric_val_cmd, - "no set metric <0-4294967295>", + "no set metric (<0-4294967295>|<+/-metric>)", NO_STR SET_STR "Metric value for destination routing protocol\n" - "Metric value\n") + "Metric value\n" + "Add or subtract metric\n") DEFUN (set_ip_nexthop, set_ip_nexthop_cmd, @@ -854,6 +1040,37 @@ ALIAS (no_set_ip_nexthop, "Next hop address\n" "IP address of next hop\n") +DEFUN (set_tag, + set_tag_cmd, + "set tag <0-65535>", + SET_STR + "Tag value for routing protocol\n" + "Tag value\n") +{ + return rip_route_set_add (vty, vty->index, "tag", argv[0]); +} + +DEFUN (no_set_tag, + no_set_tag_cmd, + "no set tag", + NO_STR + SET_STR + "Tag value for routing protocol\n") +{ + if (argc == 0) + return rip_route_set_delete (vty, vty->index, "tag", NULL); + + return rip_route_set_delete (vty, vty->index, "tag", argv[0]); +} + +ALIAS (no_set_tag, + no_set_tag_val_cmd, + "no set tag <0-65535>", + NO_STR + SET_STR + "Tag value for routing protocol\n" + "Tag value\n") + void rip_route_map_reset () { @@ -875,9 +1092,11 @@ rip_route_map_init () route_map_install_match (&route_match_ip_next_hop_prefix_list_cmd); route_map_install_match (&route_match_ip_address_cmd); route_map_install_match (&route_match_ip_address_prefix_list_cmd); + route_map_install_match (&route_match_tag_cmd); route_map_install_set (&route_set_metric_cmd); route_map_install_set (&route_set_ip_nexthop_cmd); + route_map_install_set (&route_set_tag_cmd); install_element (RMAP_NODE, &match_metric_cmd); install_element (RMAP_NODE, &no_match_metric_cmd); @@ -897,6 +1116,9 @@ rip_route_map_init () install_element (RMAP_NODE, &match_ip_address_prefix_list_cmd); install_element (RMAP_NODE, &no_match_ip_address_prefix_list_cmd); install_element (RMAP_NODE, &no_match_ip_address_prefix_list_val_cmd); + install_element (RMAP_NODE, &match_tag_cmd); + install_element (RMAP_NODE, &no_match_tag_cmd); + install_element (RMAP_NODE, &no_match_tag_val_cmd); install_element (RMAP_NODE, &set_metric_cmd); install_element (RMAP_NODE, &no_set_metric_cmd); @@ -904,4 +1126,7 @@ rip_route_map_init () install_element (RMAP_NODE, &set_ip_nexthop_cmd); install_element (RMAP_NODE, &no_set_ip_nexthop_cmd); install_element (RMAP_NODE, &no_set_ip_nexthop_val_cmd); + install_element (RMAP_NODE, &set_tag_cmd); + install_element (RMAP_NODE, &no_set_tag_cmd); + install_element (RMAP_NODE, &no_set_tag_val_cmd); } diff --git a/ripd/rip_zebra.c b/ripd/rip_zebra.c index b6caf3b0..67d7b8bf 100644 --- a/ripd/rip_zebra.c +++ b/ripd/rip_zebra.c @@ -502,6 +502,43 @@ DEFUN (no_rip_redistribute_type_metric, return CMD_WARNING; } +DEFUN (rip_redistribute_type_metric_routemap, + rip_redistribute_type_metric_routemap_cmd, + "redistribute (kernel|connected|static|ospf|bgp) metric <0-16> route-map WORD", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Open Shortest Path First (OSPF)\n" + "Border Gateway Protocol (BGP)\n" + "Metric\n" + "Metric value\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + int i; + int metric; + + metric = atoi (argv[1]); + + for (i = 0; redist_type[i].str; i++) { + if (strncmp(redist_type[i].str, argv[0], + redist_type[i].str_min_len) == 0) + { + rip_redistribute_metric_set (redist_type[i].type, metric); + rip_routemap_set (redist_type[i].type, argv[2]); + zclient_redistribute_set (zclient, redist_type[i].type); + return CMD_SUCCESS; + } + } + + vty_out(vty, "Invalid type %s%s", argv[0], + VTY_NEWLINE); + + return CMD_WARNING; +} + + DEFUN (no_rip_redistribute_type_metric_routemap, no_rip_redistribute_type_metric_routemap_cmd, "no redistribute (kernel|connected|static|ospf|bgp) metric <0-16> route-map WORD", @@ -559,7 +596,7 @@ DEFUN (rip_default_information_originate, rip->default_information = 1; - rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0, NULL); + rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_DEFAULT, &p, 0, NULL); } return CMD_SUCCESS; @@ -581,7 +618,7 @@ DEFUN (no_rip_default_information_originate, rip->default_information = 0; - rip_redistribute_delete (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0); + rip_redistribute_delete (ZEBRA_ROUTE_RIP, RIP_ROUTE_DEFAULT, &p, 0); } return CMD_SUCCESS; @@ -682,6 +719,7 @@ rip_zclient_init () install_element (RIP_NODE, &rip_redistribute_type_cmd); install_element (RIP_NODE, &rip_redistribute_type_routemap_cmd); install_element (RIP_NODE, &rip_redistribute_type_metric_cmd); + install_element (RIP_NODE, &rip_redistribute_type_metric_routemap_cmd); install_element (RIP_NODE, &no_rip_redistribute_type_cmd); install_element (RIP_NODE, &no_rip_redistribute_type_routemap_cmd); install_element (RIP_NODE, &no_rip_redistribute_type_metric_cmd); diff --git a/ripd/ripd.c b/ripd/ripd.c index 62ebd47c..c5d45536 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -32,6 +32,7 @@ #include "filter.h" #include "sockunion.h" #include "routemap.h" +#include "if_rmap.h" #include "plist.h" #include "distribute.h" #include "md5-gnu.h" @@ -404,6 +405,40 @@ rip_rte_process (struct rte *rte, struct sockaddr_in *from, if (ret < 0) return; + /* Modify entry according to the interface routemap. */ + if (ri->routemap[RIP_FILTER_IN]) + { + int ret; + struct rip_info newinfo; + + memset (&newinfo, 0, sizeof (newinfo)); + newinfo.type = ZEBRA_ROUTE_RIP; + newinfo.sub_type = RIP_ROUTE_RTE; + newinfo.nexthop= rte->nexthop; + newinfo.from = from->sin_addr; + newinfo.ifindex= ifp->ifindex; + newinfo.metric = rte->metric; + newinfo.metric_out = rte->metric; /* XXX */ + newinfo.tag = ntohs(rte->tag); /* XXX */ + + /* The object should be of the type of rip_info */ + ret = route_map_apply (ri->routemap[RIP_FILTER_IN], + (struct prefix *)&p, RMAP_RIP, &newinfo); + + if (ret == RMAP_DENYMATCH) + { + if (IS_RIP_DEBUG_PACKET) + zlog_info ("RIP %s/%d is filtered by route-map in", + inet_ntoa (p.prefix), p.prefixlen); + return; + } + + /* Get back the object */ + rte->nexthop = newinfo.nexthop_out; + rte->tag = htons(newinfo.tag_out); /* XXX */ + rte->metric = newinfo.metric_out; /* XXX: the routemap uses the metric_out field */ + } + /* Once the entry has been validated, update the metric by adding the cost of the network on wich the message arrived. If the result is greater than infinity, use infinity @@ -425,11 +460,11 @@ rip_rte_process (struct rte *rte, struct sockaddr_in *from, else nexthop = &rte->nexthop; - /* Check nexthop address. */ + /* Check if nexthop address is myself, then do nothing. */ if (rip_nexthop_check (nexthop) < 0) { if (IS_RIP_DEBUG_PACKET) - zlog_info ("Nexthop address %s is invalid", inet_ntoa (*nexthop)); + zlog_info ("Nexthop address %s is myself", inet_ntoa (*nexthop)); return; } @@ -448,7 +483,8 @@ rip_rte_process (struct rte *rte, struct sockaddr_in *from, /* Local static route. */ if (rinfo->type == ZEBRA_ROUTE_RIP - && rinfo->sub_type == RIP_ROUTE_STATIC + && ((rinfo->sub_type == RIP_ROUTE_STATIC) || + (rinfo->sub_type == RIP_ROUTE_DEFAULT)) && rinfo->metric != RIP_METRIC_INFINITY) return; } @@ -514,7 +550,8 @@ rip_rte_process (struct rte *rte, struct sockaddr_in *from, to the address of the router from which the datagram came. If this datagram is from the same router as the existing route, reinitialize the timeout. */ - same = IPV4_ADDR_SAME (&rinfo->from, &from->sin_addr); + same = (IPV4_ADDR_SAME (&rinfo->from, &from->sin_addr) + && (rinfo->ifindex == ifp->ifindex)); if (same) rip_timeout_update (rinfo); @@ -522,9 +559,10 @@ rip_rte_process (struct rte *rte, struct sockaddr_in *from, /* Next, compare the metrics. If the datagram is from the same router as the existing route, and the new metric is different than the old one; or, if the new metric is lower than the old - one; do the following actions: */ + one, or if the tag has been changed; do the following actions: */ if ((same && rinfo->metric != rte->metric) || - rte->metric < rinfo->metric) + (rte->metric < rinfo->metric) || + (same && (rinfo->metric == rte->metric) && ntohs(rte->tag) != rinfo->tag)) { /* - Adopt the route from the datagram. That is, put the new metric in, and adjust the next hop address (if @@ -1275,9 +1313,11 @@ rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p, /* Manually configured RIP route check. */ if (rinfo->type == ZEBRA_ROUTE_RIP - && rinfo->sub_type == RIP_ROUTE_STATIC) + && ((rinfo->sub_type == RIP_ROUTE_STATIC) || + (rinfo->sub_type == RIP_ROUTE_DEFAULT)) ) { - if (type != ZEBRA_ROUTE_RIP || sub_type != RIP_ROUTE_STATIC) + if (type != ZEBRA_ROUTE_RIP || ((sub_type != RIP_ROUTE_STATIC) && + (sub_type != RIP_ROUTE_DEFAULT))) { route_unlock_node (rp); return; @@ -1312,6 +1352,18 @@ rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p, rinfo->flags |= RIP_RTF_CHANGED; + if (IS_RIP_DEBUG_EVENT) { + if (!nexthop) + zlog_info ("Redistribute new prefix %s/%d on the interface %s", + inet_ntoa(p->prefix), p->prefixlen, + ifindex2ifname(ifindex)); + else + zlog_info ("Redistribute new prefix %s/%d with nexthop %s on the interface %s", + inet_ntoa(p->prefix), p->prefixlen, inet_ntoa(rinfo->nexthop), + ifindex2ifname(ifindex)); + } + + rip_event (RIP_TRIGGERED_UPDATE, 0); } @@ -1345,6 +1397,11 @@ rip_redistribute_delete (int type, int sub_type, struct prefix_ipv4 *p, RIP_TIMER_OFF (rinfo->t_timeout); rinfo->flags |= RIP_RTF_CHANGED; + if (IS_RIP_DEBUG_EVENT) + zlog_info ("Poisone %s/%d on the interface %s with an infinity metric [delete]", + inet_ntoa(p->prefix), p->prefixlen, + ifindex2ifname(ifindex)); + rip_event (RIP_TRIGGERED_UPDATE, 0); } } @@ -1362,7 +1419,14 @@ rip_request_process (struct rip_packet *packet, int size, struct rip_info *rinfo; struct rip_interface *ri; + /* Does not reponse to the requests on the loopback interfaces */ + if (if_is_loopback (ifp)) + return; + + /* Check RIPng process is enabled on this interface. */ ri = ifp->info; + if (! ri->running) + return; /* When passive interface is specified, suppress responses */ if (ri->passive) @@ -1907,7 +1971,7 @@ rip_write_rte (int num, struct stream *s, struct prefix_ipv4 *p, masklen2ip (p->prefixlen, &mask); stream_putw (s, AF_INET); - stream_putw (s, rinfo->tag); + stream_putw (s, rinfo->tag_out); stream_put_ipv4 (s, p->prefix.s_addr); stream_put_ipv4 (s, mask.s_addr); stream_put_ipv4 (s, rinfo->nexthop_out.s_addr); @@ -2054,7 +2118,7 @@ rip_output_process (struct interface *ifp, struct prefix *ifaddr, /* Split horizon. */ /* if (split_horizon == rip_split_horizon) */ - if (ri->split_horizon) + if (ri->split_horizon == RIP_SPLIT_HORIZON) { /* We perform split horizon for RIP and connected route. */ if ((rinfo->type == ZEBRA_ROUTE_RIP || @@ -2067,23 +2131,36 @@ rip_output_process (struct interface *ifp, struct prefix *ifaddr, rinfo->metric_set = 0; rinfo->nexthop_out.s_addr = 0; rinfo->metric_out = rinfo->metric; + rinfo->tag_out = rinfo->tag; rinfo->ifindex_out = ifp->ifindex; - /* In order to avoid some local loops, if the RIP route has a - nexthop via this interface, keep the nexthop, otherwise set - it to 0. The nexthop should not be propagated beyond the - local broadcast/multicast area in order to avoid an IGP - multi-level recursive look-up. For RIP and connected - route, we don't set next hop value automatically. For - settting next hop to those routes, please use - route-map. */ - - if (rinfo->type != ZEBRA_ROUTE_RIP - && rinfo->type != ZEBRA_ROUTE_CONNECT - && rinfo->ifindex == ifp->ifindex) + /* In order to avoid some local loops, + * if the RIP route has a nexthop via this interface, keep the nexthop, + * otherwise set it to 0. The nexthop should not be propagated + * beyond the local broadcast/multicast area in order + * to avoid an IGP multi-level recursive look-up. + * see (4.4) + */ + if (rinfo->ifindex == ifp->ifindex) rinfo->nexthop_out = rinfo->nexthop; + + /* Interface route-map */ + if (ri->routemap[RIP_FILTER_OUT]) + { + ret = route_map_apply (ri->routemap[RIP_FILTER_OUT], + (struct prefix *) p, RMAP_RIP, + rinfo); + + if (ret == RMAP_DENYMATCH) + { + if (IS_RIP_DEBUG_PACKET) + zlog_info ("RIP %s/%d is filtered by route-map out", + inet_ntoa (p->prefix), p->prefixlen); + continue; + } + } - /* Apply route map - continue, if deny */ + /* Apply redistribute route map - continue, if deny */ if (rip->route_map[rinfo->type].name && rinfo->sub_type != RIP_ROUTE_INTERFACE) { @@ -2125,7 +2202,17 @@ rip_output_process (struct interface *ifp, struct prefix *ifaddr, if (rinfo->metric_out > RIP_METRIC_INFINITY) rinfo->metric_out = RIP_METRIC_INFINITY; - + + /* Perform split-horizon with poisoned reverse + * for RIP and connected routes. + **/ + if (ri->split_horizon == RIP_SPLIT_HORIZON_POISONED_REVERSE) { + if ((rinfo->type == ZEBRA_ROUTE_RIP || + rinfo->type == ZEBRA_ROUTE_CONNECT) && + rinfo->ifindex == ifp->ifindex) + rinfo->metric_out = RIP_METRIC_INFINITY; + } + /* Write RTE to the stream. */ num = rip_write_rte (num, s, p, version, rinfo, to ? NULL : ifp); if (num == rtemax) @@ -2419,6 +2506,14 @@ rip_redistribute_withdraw (int type) RIP_TIMER_OFF (rinfo->t_timeout); rinfo->flags |= RIP_RTF_CHANGED; + if (IS_RIP_DEBUG_EVENT) { + struct prefix_ipv4 *p = (struct prefix_ipv4 *) &rp->p; + + zlog_info ("Poisone %s/%d on the interface %s with an infinity metric [withdraw]", + inet_ntoa(p->prefix), p->prefixlen, + ifindex2ifname(rinfo->ifindex)); + } + rip_event (RIP_TRIGGERED_UPDATE, 0); } } @@ -2775,6 +2870,17 @@ DEFUN (no_rip_timers, return CMD_SUCCESS; } + +ALIAS (no_rip_timers, + no_rip_timers_val_cmd, + "no timers basic <0-65535> <0-65535> <0-65535>", + NO_STR + "Adjust routing timers\n" + "Basic routing protocol update timers\n" + "Routing table update timer value in second. Default is 30.\n" + "Routing information timeout timer. Default is 180.\n" + "Garbage collection timer. Default is 120.\n") + struct route_table *rip_distance_table; @@ -3109,11 +3215,12 @@ DEFUN (show_ip_rip, if (! rip) return CMD_SUCCESS; - vty_out (vty, "Codes: R - RIP, C - connected, O - OSPF, B - BGP%s" - " (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s" + vty_out (vty, "Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP%s" + "Sub-codes:%s" + " (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s" " (i) - interface%s%s" - " Network Next Hop Metric From Time%s", - VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + " Network Next Hop Metric From Tag Time%s", + VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); for (np = route_top (rip->table); np; np = route_next (np)) if ((rinfo = np->info) != NULL) @@ -3126,7 +3233,7 @@ DEFUN (show_ip_rip, rip_route_type_print (rinfo->sub_type), inet_ntoa (np->p.u.prefix4), np->p.prefixlen); - len = 24 - len; + len = 21 - len; if (len > 0) vty_out (vty, "%*s", len, " "); @@ -3142,15 +3249,20 @@ DEFUN (show_ip_rip, (rinfo->sub_type == RIP_ROUTE_RTE)) { vty_out (vty, "%-15s ", inet_ntoa (rinfo->from)); + vty_out (vty, "%3d ", rinfo->tag); rip_vty_out_uptime (vty, rinfo); } else if (rinfo->metric == RIP_METRIC_INFINITY) { vty_out (vty, "self "); + vty_out (vty, "%3d ", rinfo->tag); rip_vty_out_uptime (vty, rinfo); } else - vty_out (vty, "self"); + { + vty_out (vty, "self "); + vty_out (vty, "%3d", rinfo->tag); + } vty_out (vty, "%s", VTY_NEWLINE); } @@ -3168,11 +3280,13 @@ rip_next_thread_timer (struct thread *thread) return thread->u.sands.tv_sec - timer_now.tv_sec; } -DEFUN (show_ip_protocols_rip, - show_ip_protocols_rip_cmd, - "show ip protocols", +/* Vincent: formerly, it was show_ip_protocols_rip: "show ip protocols" */ +DEFUN (show_ip_rip_status, + show_ip_rip_status_cmd, + "show ip rip status", SHOW_STR IP_STR + "Show RIP routes\n" "IP routing protocol process parameters and statistics\n") { listnode node; @@ -3307,6 +3421,9 @@ config_write_rip (struct vty *vty) /* Distribute configuration. */ write += config_write_distribute (vty); + /* Interface routemap configuration */ + write += config_write_if_rmap (vty); + /* Distance configuration. */ if (rip->distance) vty_out (vty, " distance %d%s", rip->distance, VTY_NEWLINE); @@ -3538,6 +3655,83 @@ rip_reset () rip_zclient_reset (); } +void +rip_if_rmap_update (struct if_rmap *if_rmap) +{ + struct interface *ifp; + struct rip_interface *ri; + struct route_map *rmap; + + ifp = if_lookup_by_name (if_rmap->ifname); + if (ifp == NULL) + return; + + ri = ifp->info; + + if (if_rmap->routemap[IF_RMAP_IN]) + { + rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_IN]); + if (rmap) + ri->routemap[IF_RMAP_IN] = rmap; + else + ri->routemap[IF_RMAP_IN] = NULL; + } + else + ri->routemap[RIP_FILTER_IN] = NULL; + + if (if_rmap->routemap[IF_RMAP_OUT]) + { + rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_OUT]); + if (rmap) + ri->routemap[IF_RMAP_OUT] = rmap; + else + ri->routemap[IF_RMAP_OUT] = NULL; + } + else + ri->routemap[RIP_FILTER_OUT] = NULL; +} + +void +rip_if_rmap_update_interface (struct interface *ifp) +{ + struct if_rmap *if_rmap; + + if_rmap = if_rmap_lookup (ifp->name); + if (if_rmap) + rip_if_rmap_update (if_rmap); +} + +void +rip_routemap_update_redistribute (void) +{ + int i; + + if (rip) + { + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + { + if (rip->route_map[i].name) + rip->route_map[i].map = + route_map_lookup_by_name (rip->route_map[i].name); + } + } +} + +void +rip_routemap_update () +{ + struct interface *ifp; + listnode node; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + rip_if_rmap_update_interface (ifp); + } + + rip_routemap_update_redistribute (); +} + /* Allocate new rip structure and set default value. */ void rip_init () @@ -3550,9 +3744,9 @@ rip_init () /* Install rip commands. */ install_element (VIEW_NODE, &show_ip_rip_cmd); - install_element (VIEW_NODE, &show_ip_protocols_rip_cmd); + install_element (VIEW_NODE, &show_ip_rip_status_cmd); install_element (ENABLE_NODE, &show_ip_rip_cmd); - install_element (ENABLE_NODE, &show_ip_protocols_rip_cmd); + install_element (ENABLE_NODE, &show_ip_rip_status_cmd); install_element (CONFIG_NODE, &router_rip_cmd); install_element (CONFIG_NODE, &no_router_rip_cmd); @@ -3565,6 +3759,7 @@ rip_init () install_element (RIP_NODE, &no_rip_default_metric_val_cmd); install_element (RIP_NODE, &rip_timers_cmd); install_element (RIP_NODE, &no_rip_timers_cmd); + install_element (RIP_NODE, &no_rip_timers_val_cmd); install_element (RIP_NODE, &rip_route_cmd); install_element (RIP_NODE, &no_rip_route_cmd); install_element (RIP_NODE, &rip_distance_cmd); @@ -3577,10 +3772,6 @@ rip_init () /* Debug related init. */ rip_debug_init (); - /* Filter related init. */ - rip_route_map_init (); - rip_offset_init (); - /* SNMP init. */ #ifdef HAVE_SNMP rip_snmp_init (); @@ -3601,6 +3792,17 @@ rip_init () distribute_list_add_hook (rip_distribute_update); distribute_list_delete_hook (rip_distribute_update); + /* Route-map */ + rip_route_map_init (); + rip_offset_init (); + + route_map_add_hook (rip_routemap_update); + route_map_delete_hook (rip_routemap_update); + + if_rmap_init (RIP_NODE); + if_rmap_hook_add (rip_if_rmap_update); + if_rmap_hook_delete (rip_if_rmap_update); + /* Distance control. */ rip_distance_table = route_table_init (); } diff --git a/ripd/ripd.h b/ripd/ripd.h index 112e1cbf..260ea469 100644 --- a/ripd/ripd.h +++ b/ripd/ripd.h @@ -199,6 +199,7 @@ struct rip_info struct in_addr nexthop_out; u_char metric_set; u_int32_t metric_out; + u_short tag_out; unsigned int ifindex_out; struct route_node *rp; @@ -211,6 +212,12 @@ struct rip_info #endif /* NEW_RIP_TABLE */ }; +typedef enum { + RIP_NO_SPLIT_HORIZON = 0, + RIP_SPLIT_HORIZON, + RIP_SPLIT_HORIZON_POISONED_REVERSE +} split_horizon_policy_t; + /* RIP specific interface configuration. */ struct rip_interface { @@ -239,8 +246,8 @@ struct rip_interface char *key_chain; /* Split horizon flag. */ - int split_horizon; - int split_horizon_default; + split_horizon_policy_t split_horizon; + split_horizon_policy_t split_horizon_default; /* For filter type slot. */ #define RIP_FILTER_IN 0 @@ -253,6 +260,9 @@ struct rip_interface /* Prefix-list. */ struct prefix_list *prefix[RIP_FILTER_MAX]; + /* Route-map. */ + struct route_map *routemap[RIP_FILTER_MAX]; + /* Wake up thread. */ struct thread *t_wakeup; @@ -369,6 +379,7 @@ void rip_zebra_ipv4_add (struct prefix_ipv4 *, struct in_addr *, u_int32_t, u_ch void rip_zebra_ipv4_delete (struct prefix_ipv4 *, struct in_addr *, u_int32_t); void rip_interface_multicast_set (int, struct interface *); void rip_distribute_update_interface (struct interface *); +void rip_if_rmap_update_interface (struct interface *); int config_write_rip_network (struct vty *, int); int config_write_rip_offset_list (struct vty *); |