summaryrefslogtreecommitdiff
path: root/ripngd
diff options
context:
space:
mode:
Diffstat (limited to 'ripngd')
-rw-r--r--ripngd/Makefile.am4
-rw-r--r--ripngd/ripng_debug.c3
-rw-r--r--ripngd/ripng_debug.h1
-rw-r--r--ripngd/ripng_interface.c548
-rw-r--r--ripngd/ripng_main.c30
-rw-r--r--ripngd/ripng_nexthop.c216
-rw-r--r--ripngd/ripng_nexthop.h62
-rw-r--r--ripngd/ripng_offset.c417
-rw-r--r--ripngd/ripng_peer.c220
-rw-r--r--ripngd/ripng_route.c1
-rw-r--r--ripngd/ripng_route.h6
-rw-r--r--ripngd/ripng_routemap.c619
-rw-r--r--ripngd/ripng_zebra.c711
-rw-r--r--ripngd/ripngd.c1200
-rw-r--r--ripngd/ripngd.h112
15 files changed, 3113 insertions, 1037 deletions
diff --git a/ripngd/Makefile.am b/ripngd/Makefile.am
index 2835aa24..66f64838 100644
--- a/ripngd/Makefile.am
+++ b/ripngd/Makefile.am
@@ -9,7 +9,7 @@ sbin_PROGRAMS = ripngd
libripng_a_SOURCES = \
ripng_interface.c ripngd.c ripng_zebra.c ripng_route.c ripng_debug.c \
- ripng_routemap.c
+ ripng_routemap.c ripng_offset.c ripng_peer.c ripng_nexthop.c
noinst_HEADERS = \
ripng_debug.h ripng_route.h ripngd.h
@@ -17,7 +17,7 @@ noinst_HEADERS = \
ripngd_SOURCES = \
ripng_main.c $(libripng_a_SOURCES)
-ripngd_LDADD = ../lib/libzebra.a
+ripngd_LDADD = -L../lib -lzebra
sysconf_DATA = ripngd.conf.sample
diff --git a/ripngd/ripng_debug.c b/ripngd/ripng_debug.c
index 51314bc2..2cff3d01 100644
--- a/ripngd/ripng_debug.c
+++ b/ripngd/ripng_debug.c
@@ -207,7 +207,8 @@ DEFUN (no_debug_ripng_zebra,
struct cmd_node debug_node =
{
DEBUG_NODE,
- "" /* Debug node has no interface. */
+ "", /* Debug node has no interface. */
+ 1 /* VTYSH */
};
int
diff --git a/ripngd/ripng_debug.h b/ripngd/ripng_debug.h
index 6713a151..617a07de 100644
--- a/ripngd/ripng_debug.h
+++ b/ripngd/ripng_debug.h
@@ -48,5 +48,6 @@ extern unsigned long ripng_debug_packet;
extern unsigned long ripng_debug_zebra;
void ripng_debug_init ();
+void ripng_debug_reset ();
#endif /* _ZEBRA_RIPNG_DEBUG_H */
diff --git a/ripngd/ripng_interface.c b/ripngd/ripng_interface.c
index 369c3d6f..b4299eb0 100644
--- a/ripngd/ripng_interface.c
+++ b/ripngd/ripng_interface.c
@@ -49,6 +49,9 @@
/* Static utility function. */
static void ripng_enable_apply (struct interface *);
static void ripng_passive_interface_apply (struct interface *);
+int ripng_enable_if_lookup (char *ifname);
+int ripng_enable_network_lookup2 (struct connected *connected);
+void ripng_enable_apply_all ();
/* Join to the all rip routers multicast group. */
int
@@ -57,19 +60,23 @@ ripng_multicast_join (struct interface *ifp)
int ret;
struct ipv6_mreq mreq;
- memset (&mreq, 0, sizeof (mreq));
- inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr);
- mreq.ipv6mr_interface = ifp->ifindex;
+ if (if_is_up (ifp) && if_is_multicast (ifp)) {
+ memset (&mreq, 0, sizeof (mreq));
+ inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr);
+ mreq.ipv6mr_interface = ifp->ifindex;
- ret = setsockopt (ripng->sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
- (char *) &mreq, sizeof (mreq));
- if (ret < 0)
- zlog_warn ("can't setsockopt IPV6_JOIN_GROUP: %s", strerror (errno));
+ ret = setsockopt (ripng->sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
+ (char *) &mreq, sizeof (mreq));
+ if (ret < 0)
+ zlog_warn ("can't setsockopt IPV6_JOIN_GROUP: %s", strerror (errno));
- if (IS_RIPNG_DEBUG_EVENT)
- zlog_info ("RIPng %s join to all-rip-routers multicast group", ifp->name);
+ if (IS_RIPNG_DEBUG_EVENT)
+ zlog_info ("RIPng %s join to all-rip-routers multicast group", ifp->name);
- return ret;
+ if (ret < 0)
+ return -1;
+ }
+ return 0;
}
/* Leave from the all rip routers multicast group. */
@@ -79,20 +86,46 @@ ripng_multicast_leave (struct interface *ifp)
int ret;
struct ipv6_mreq mreq;
- memset (&mreq, 0, sizeof (mreq));
- inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr);
- mreq.ipv6mr_interface = ifp->ifindex;
+ if (if_is_up (ifp) && if_is_multicast (ifp)) {
+ memset (&mreq, 0, sizeof (mreq));
+ inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr);
+ mreq.ipv6mr_interface = ifp->ifindex;
- ret = setsockopt (ripng->sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
- (char *) &mreq, sizeof (mreq));
- if (ret < 0)
- zlog_warn ("can't setsockopt IPV6_LEAVE_GROUP: %s\n", strerror (errno));
+ ret = setsockopt (ripng->sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
+ (char *) &mreq, sizeof (mreq));
+ if (ret < 0)
+ zlog_warn ("can't setsockopt IPV6_LEAVE_GROUP: %s\n", strerror (errno));
+
+ if (IS_RIPNG_DEBUG_EVENT)
+ zlog_info ("RIPng %s leave from all-rip-routers multicast group",
+ ifp->name);
+
+ if (ret < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+/* How many link local IPv6 address could be used on the interface ? */
+int
+ripng_if_ipv6_lladdress_check (struct interface *ifp)
+{
+ struct listnode *nn;
+ struct connected *connected;
+ int count = 0;
+
+ for (nn = listhead (ifp->connected); nn; nextnode (nn))
+ if ((connected = getdata (nn)) != NULL) {
+ struct prefix *p;
+ p = connected->address;
- if (IS_RIPNG_DEBUG_EVENT)
- zlog_info ("RIPng %s leave from all-rip-routers multicast group",
- ifp->name);
+ if ((p->family == AF_INET6) &&
+ IN6_IS_ADDR_LINKLOCAL (&p->u.prefix6))
+ count++;
+ }
- return ret;
+ return count;
}
/* Check max mtu size. */
@@ -120,7 +153,7 @@ ripng_if_down (struct interface *ifp)
struct ripng_info *rinfo;
struct ripng_interface *ri;
- if (ripng->table)
+ if (ripng)
{
for (rp = route_top (ripng->table); rp; rp = route_next (rp))
if ((rinfo = rp->info) != NULL)
@@ -134,18 +167,17 @@ ripng_if_down (struct interface *ifp)
&rinfo->nexthop,
rinfo->ifindex);
- RIPNG_TIMER_OFF (rinfo->t_timeout);
- RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
-
- rp->info = NULL;
- route_unlock_node (rp);
-
- ripng_info_free (rinfo);
+ ripng_redistribute_delete (rinfo->type, rinfo->sub_type,
+ (struct prefix_ipv6 *)&rp->p,
+ rinfo->ifindex);
}
else
{
- /* All redistributed routes got through this interface. */
- if (rinfo->ifindex == ifp->ifindex)
+ /* All redistributed routes got through this interface,
+ * but the static and system ones are kept. */
+ if ((rinfo->ifindex == ifp->ifindex) &&
+ (rinfo->type != ZEBRA_ROUTE_STATIC) &&
+ (rinfo->type != ZEBRA_ROUTE_SYSTEM))
ripng_redistribute_delete (rinfo->type, rinfo->sub_type,
(struct prefix_ipv6 *) &rp->p,
rinfo->ifindex);
@@ -155,7 +187,7 @@ ripng_if_down (struct interface *ifp)
ri = ifp->info;
- if (ripng && ri->running)
+ if (ri->running)
{
if (IS_RIPNG_DEBUG_EVENT)
zlog_info ("turn off %s", ifp->name);
@@ -251,16 +283,121 @@ int
ripng_interface_delete (int command, struct zclient *zclient,
zebra_size_t length)
{
+ struct interface *ifp;
+ struct stream *s;
+
+ s = zclient->ibuf;
+ /* zebra_interface_state_read() updates interface structure in iflist */
+ ifp = zebra_interface_state_read(s);
+
+ if (ifp == NULL)
+ return 0;
+
+ if (if_is_up (ifp)) {
+ ripng_if_down(ifp);
+ }
+
+ zlog_info("interface delete %s index %d flags %ld metric %d mtu %d",
+ ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu);
+
+ /* To support pseudo interface do not free interface structure. */
+ /* if_delete(ifp); */
+
return 0;
}
+void
+ripng_interface_clean ()
+{
+ listnode node;
+ struct interface *ifp;
+ struct ripng_interface *ri;
+
+ for (node = listhead (iflist); node; nextnode (node))
+ {
+ ifp = getdata (node);
+ ri = ifp->info;
+
+ ri->enable_network = 0;
+ ri->enable_interface = 0;
+ ri->running = 0;
+
+ if (ri->t_wakeup)
+ {
+ thread_cancel (ri->t_wakeup);
+ ri->t_wakeup = NULL;
+ }
+ }
+}
+
+void
+ripng_interface_reset () {
+ listnode node;
+ struct interface *ifp;
+ struct ripng_interface *ri;
+
+ for (node = listhead (iflist); node; nextnode (node))
+ {
+ ifp = getdata (node);
+ ri = ifp->info;
+
+ ri->enable_network = 0;
+ ri->enable_interface = 0;
+ ri->running = 0;
+
+ ri->split_horizon = RIPNG_NO_SPLIT_HORIZON;
+ ri->split_horizon_default = RIPNG_NO_SPLIT_HORIZON;
+
+ ri->list[RIPNG_FILTER_IN] = NULL;
+ ri->list[RIPNG_FILTER_OUT] = NULL;
+
+ ri->prefix[RIPNG_FILTER_IN] = NULL;
+ ri->prefix[RIPNG_FILTER_OUT] = NULL;
+
+ if (ri->t_wakeup)
+ {
+ thread_cancel (ri->t_wakeup);
+ ri->t_wakeup = NULL;
+ }
+
+ ri->passive = 0;
+ }
+}
+
+static void
+ripng_apply_address_add (struct connected *ifc) {
+ struct prefix_ipv6 address;
+ struct prefix *p;
+
+ if (!ripng)
+ return;
+
+ if (! if_is_up(ifc->ifp))
+ return;
+
+ p = ifc->address;
+
+ memset (&address, 0, sizeof (address));
+ address.family = p->family;
+ address.prefix = p->u.prefix6;
+ address.prefixlen = p->prefixlen;
+ apply_mask_ipv6(&address);
+
+ /* Check if this interface is RIP enabled or not
+ or Check if this address's prefix is RIP enabled */
+ if ((ripng_enable_if_lookup(ifc->ifp->name) >= 0) ||
+ (ripng_enable_network_lookup2(ifc) >= 0))
+ ripng_redistribute_add(ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE,
+ &address, ifc->ifp->ifindex, NULL);
+
+}
+
int
ripng_interface_address_add (int command, struct zclient *zclient,
zebra_size_t length)
{
struct connected *c;
struct prefix *p;
- char buf[INET6_ADDRSTRLEN];
c = zebra_interface_address_add_read (zclient->ibuf);
@@ -273,16 +410,56 @@ ripng_interface_address_add (int command, struct zclient *zclient,
{
if (IS_RIPNG_DEBUG_ZEBRA)
zlog_info ("RIPng connected address %s/%d add",
- inet_ntop (AF_INET6, &p->u.prefix6, buf, INET6_ADDRSTRLEN),
+ inet6_ntop(&p->u.prefix6),
p->prefixlen);
- /* Check is this interface is RIP enabled or not.*/
- ripng_enable_apply (c->ifp);
+ /* Check is this prefix needs to be redistributed. */
+ ripng_apply_address_add(c);
+
+ /* Let's try once again whether the interface could be activated */
+ if (c->ifp) {
+ struct ripng_interface *ri = c->ifp->info;
+
+ if (!ri->running) {
+ /* Check if this interface is RIP enabled or not.*/
+ ripng_enable_apply (c->ifp);
+
+ /* Apply distribute list to the interface. */
+ ripng_distribute_update_interface (c->ifp);
+
+ /* Check interface routemap. */
+ ripng_if_rmap_update_interface (c->ifp);
+ }
+ }
+
}
return 0;
}
+static void
+ripng_apply_address_del (struct connected *ifc) {
+ struct prefix_ipv6 address;
+ struct prefix *p;
+
+ if (!ripng)
+ return;
+
+ if (! if_is_up(ifc->ifp))
+ return;
+
+ p = ifc->address;
+
+ memset (&address, 0, sizeof (address));
+ address.family = p->family;
+ address.prefix = p->u.prefix6;
+ address.prefixlen = p->prefixlen;
+ apply_mask_ipv6(&address);
+
+ ripng_redistribute_delete(ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE,
+ &address, ifc->ifp->ifindex);
+}
+
int
ripng_interface_address_delete (int command, struct zclient *zclient,
zebra_size_t length)
@@ -305,8 +482,8 @@ ripng_interface_address_delete (int command, struct zclient *zclient,
INET6_ADDRSTRLEN),
p->prefixlen);
- /* Check is this interface is RIP enabled or not.*/
- ripng_enable_apply (ifc->ifp);
+ /* Check wether this prefix needs to be removed. */
+ ripng_apply_address_del(ifc);
}
connected_free (ifc);
}
@@ -321,11 +498,14 @@ vector ripng_enable_if;
struct route_table *ripng_enable_network;
/* Lookup RIPng enable network. */
+/* Check wether the interface has at least a connected prefix that
+ * is within the ripng_enable_network table. */
int
-ripng_enable_network_lookup (struct interface *ifp)
+ripng_enable_network_lookup_if (struct interface *ifp)
{
listnode listnode;
struct connected *connected;
+ struct prefix_ipv6 address;
for (listnode = listhead (ifp->connected); listnode; nextnode (listnode))
if ((connected = getdata (listnode)) != NULL)
@@ -337,7 +517,12 @@ ripng_enable_network_lookup (struct interface *ifp)
if (p->family == AF_INET6)
{
- node = route_node_match (ripng_enable_network, p);
+ address.family = AF_INET6;
+ address.prefix = p->u.prefix6;
+ address.prefixlen = IPV6_MAX_BITLEN;
+
+ node = route_node_match (ripng_enable_network,
+ (struct prefix *)&address);
if (node)
{
route_unlock_node (node);
@@ -348,6 +533,35 @@ ripng_enable_network_lookup (struct interface *ifp)
return -1;
}
+/* Check wether connected is within the ripng_enable_network table. */
+int
+ripng_enable_network_lookup2 (struct connected *connected)
+{
+ struct prefix_ipv6 address;
+ struct prefix *p;
+
+ p = connected->address;
+
+ if (p->family == AF_INET6) {
+ struct route_node *node;
+
+ address.family = p->family;
+ address.prefix = p->u.prefix6;
+ address.prefixlen = IPV6_MAX_BITLEN;
+
+ /* LPM on p->family, p->u.prefix6/IPV6_MAX_BITLEN within ripng_enable_network */
+ node = route_node_match (ripng_enable_network,
+ (struct prefix *)&address);
+
+ if (node) {
+ route_unlock_node (node);
+ return 1;
+ }
+ }
+
+ return -1;
+}
+
/* Add RIPng enable network. */
int
ripng_enable_network_add (struct prefix *p)
@@ -364,6 +578,9 @@ ripng_enable_network_add (struct prefix *p)
else
node->info = "enabled";
+ /* XXX: One should find a better solution than a generic one */
+ ripng_enable_apply_all();
+
return 1;
}
@@ -415,6 +632,8 @@ ripng_enable_if_add (char *ifname)
vector_set (ripng_enable_if, strdup (ifname));
+ ripng_enable_apply_all();
+
return 1;
}
@@ -433,6 +652,8 @@ ripng_enable_if_delete (char *ifname)
free (str);
vector_unset (ripng_enable_if, index);
+ ripng_enable_apply_all();
+
return 1;
}
@@ -450,7 +671,13 @@ ripng_interface_wakeup (struct thread *t)
ri->t_wakeup = NULL;
/* Join to multicast group. */
- ripng_multicast_join (ifp);
+ if (ripng_multicast_join (ifp) < 0) {
+ zlog_err ("multicast join failed, interface %s not running", ifp->name);
+ return 0;
+ }
+
+ /* Set running flag. */
+ ri->running = 1;
/* Send RIP request to the interface. */
ripng_request (ifp);
@@ -458,6 +685,44 @@ ripng_interface_wakeup (struct thread *t)
return 0;
}
+int ripng_redistribute_check (int);
+
+void
+ripng_connect_set (struct interface *ifp, int set)
+{
+ struct listnode *nn;
+ struct connected *connected;
+ struct prefix_ipv6 address;
+
+ for (nn = listhead (ifp->connected); nn; nextnode (nn))
+ if ((connected = getdata (nn)) != NULL) {
+ struct prefix *p;
+ p = connected->address;
+
+ if (p->family != AF_INET6)
+ continue;
+
+ address.family = AF_INET6;
+ address.prefix = p->u.prefix6;
+ address.prefixlen = p->prefixlen;
+ apply_mask_ipv6 (&address);
+
+ if (set) {
+ /* Check once more wether this prefix is within a "network IF_OR_PREF" one */
+ if ((ripng_enable_if_lookup(connected->ifp->name) >= 0) ||
+ (ripng_enable_network_lookup2(connected) >= 0))
+ ripng_redistribute_add (ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE,
+ &address, connected->ifp->ifindex, NULL);
+ } else {
+ ripng_redistribute_delete (ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE,
+ &address, connected->ifp->ifindex);
+ if (ripng_redistribute_check (ZEBRA_ROUTE_CONNECT))
+ ripng_redistribute_add (ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_REDISTRIBUTE,
+ &address, connected->ifp->ifindex, NULL);
+ }
+ }
+}
+
/* Check RIPng is enabed on this interface. */
void
ripng_enable_apply (struct interface *ifp)
@@ -466,16 +731,13 @@ ripng_enable_apply (struct interface *ifp)
struct ripng_interface *ri = NULL;
/* Check interface. */
- if (if_is_loopback (ifp))
- return;
-
if (! if_is_up (ifp))
return;
ri = ifp->info;
- /* Check network configuration. */
- ret = ripng_enable_network_lookup (ifp);
+ /* Is this interface a candidate for RIPng ? */
+ ret = ripng_enable_network_lookup_if (ifp);
/* If the interface is matched. */
if (ret > 0)
@@ -490,10 +752,18 @@ ripng_enable_apply (struct interface *ifp)
else
ri->enable_interface = 0;
+ /* any candidate interface MUST have a link-local IPv6 address */
+ if ((! ripng_if_ipv6_lladdress_check (ifp)) &&
+ (ri->enable_network || ri->enable_interface)) {
+ ri->enable_network = 0;
+ ri->enable_interface = 0;
+ zlog_warn("Interface %s does not have any link-local address",
+ ifp->name);
+ }
+
/* Update running status of the interface. */
if (ri->enable_network || ri->enable_interface)
{
- if (! ri->running)
{
if (IS_RIPNG_DEBUG_EVENT)
zlog_info ("RIPng turn on %s", ifp->name);
@@ -502,34 +772,26 @@ ripng_enable_apply (struct interface *ifp)
if (! ri->t_wakeup)
ri->t_wakeup = thread_add_timer (master, ripng_interface_wakeup,
ifp, 1);
-#if 0
- /* Join to multicast group. */
- ripng_multicast_join (ifp);
- /* Send RIP request to the interface. */
- ripng_request (ifp);
-#endif /* 0 */
-
- ri->running = 1;
+ ripng_connect_set (ifp, 1);
}
}
else
{
if (ri->running)
{
- if (IS_RIPNG_DEBUG_EVENT)
- zlog_info ("RIPng turn off %s", ifp->name);
-
- /* Leave from multicast group. */
- ripng_multicast_leave (ifp);
+ /* Might as well clean up the route table as well
+ * ripng_if_down sets to 0 ri->running, and displays "turn off %s"
+ **/
+ ripng_if_down(ifp);
- ri->running = 0;
+ ripng_connect_set (ifp, 0);
}
}
}
/* Set distribute list to all interfaces. */
-static void
+void
ripng_enable_apply_all ()
{
struct interface *ifp;
@@ -542,6 +804,29 @@ ripng_enable_apply_all ()
}
}
+/* Clear all network and neighbor configuration */
+void
+ripng_clean_network ()
+{
+ int i;
+ char *str;
+ struct route_node *rn;
+
+ /* ripng_enable_network */
+ for (rn = route_top (ripng_enable_network); rn; rn = route_next (rn))
+ if (rn->info) {
+ rn->info = NULL;
+ route_unlock_node(rn);
+ }
+
+ /* ripng_enable_if */
+ for (i = 0; i < vector_max (ripng_enable_if); i++)
+ if ((str = vector_slot (ripng_enable_if, i)) != NULL) {
+ free (str);
+ vector_slot (ripng_enable_if, i) = NULL;
+ }
+}
+
/* Vector to store passive-interface name. */
vector Vripng_passive_interface;
@@ -638,10 +923,9 @@ ripng_passive_interface_clean (void)
/* Write RIPng enable network and interface to the vty. */
int
-ripng_network_write (struct vty *vty)
+ripng_network_write (struct vty *vty, int config_mode)
{
int i;
- char *str;
char *ifname;
struct route_node *node;
char buf[BUFSIZ];
@@ -651,7 +935,8 @@ ripng_network_write (struct vty *vty)
if (node->info)
{
struct prefix *p = &node->p;
- vty_out (vty, " network %s/%d%s",
+ vty_out (vty, "%s%s/%d%s",
+ config_mode ? " network " : " ",
inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
p->prefixlen,
VTY_NEWLINE);
@@ -660,14 +945,17 @@ ripng_network_write (struct vty *vty)
/* Write enable interface. */
for (i = 0; i < vector_max (ripng_enable_if); i++)
- if ((str = vector_slot (ripng_enable_if, i)) != NULL)
- vty_out (vty, " network %s%s", str,
+ if ((ifname = vector_slot (ripng_enable_if, i)) != NULL)
+ vty_out (vty, "%s%s%s",
+ config_mode ? " network " : " ",
+ ifname,
VTY_NEWLINE);
/* Write passive interface. */
- for (i = 0; i < vector_max (Vripng_passive_interface); i++)
- if ((ifname = vector_slot (Vripng_passive_interface, i)) != NULL)
- vty_out (vty, " passive-interface %s%s", ifname, VTY_NEWLINE);
+ if (config_mode)
+ for (i = 0; i < vector_max (Vripng_passive_interface); i++)
+ if ((ifname = vector_slot (Vripng_passive_interface, i)) != NULL)
+ vty_out (vty, " passive-interface %s%s", ifname, VTY_NEWLINE);
return 0;
}
@@ -697,8 +985,6 @@ DEFUN (ripng_network,
return CMD_WARNING;
}
- ripng_enable_apply_all ();
-
return CMD_SUCCESS;
}
@@ -728,11 +1014,71 @@ DEFUN (no_ripng_network,
return CMD_WARNING;
}
- ripng_enable_apply_all ();
+ return CMD_SUCCESS;
+}
+
+DEFUN (ipv6_ripng_split_horizon,
+ ipv6_ripng_split_horizon_cmd,
+ "ipv6 ripng split-horizon",
+ IPV6_STR
+ "Routing Information Protocol\n"
+ "Perform split horizon\n")
+{
+ struct interface *ifp;
+ struct ripng_interface *ri;
+
+ ifp = vty->index;
+ ri = ifp->info;
+
+ ri->split_horizon = RIPNG_SPLIT_HORIZON;
+ return CMD_SUCCESS;
+}
+
+DEFUN (ipv6_ripng_split_horizon_poisoned_reverse,
+ ipv6_ripng_split_horizon_poisoned_reverse_cmd,
+ "ipv6 ripng split-horizon poisoned-reverse",
+ IPV6_STR
+ "Routing Information Protocol\n"
+ "Perform split horizon\n"
+ "With poisoned-reverse\n")
+{
+ struct interface *ifp;
+ struct ripng_interface *ri;
+
+ ifp = vty->index;
+ ri = ifp->info;
+
+ ri->split_horizon = RIPNG_SPLIT_HORIZON_POISONED_REVERSE;
+ return CMD_SUCCESS;
+}
+DEFUN (no_ipv6_ripng_split_horizon,
+ no_ipv6_ripng_split_horizon_cmd,
+ "no ipv6 ripng split-horizon",
+ NO_STR
+ IPV6_STR
+ "Routing Information Protocol\n"
+ "Perform split horizon\n")
+{
+ struct interface *ifp;
+ struct ripng_interface *ri;
+
+ ifp = vty->index;
+ ri = ifp->info;
+
+ ri->split_horizon = RIPNG_NO_SPLIT_HORIZON;
return CMD_SUCCESS;
}
+ALIAS (no_ipv6_ripng_split_horizon,
+ no_ipv6_ripng_split_horizon_poisoned_reverse_cmd,
+ "no ipv6 ripng split-horizon poisoned-reverse",
+ NO_STR
+ IPV6_STR
+ "Routing Information Protocol\n"
+ "Perform split horizon\n"
+ "With poisoned-reverse\n")
+
DEFUN (ripng_passive_interface,
ripng_passive_interface_cmd,
"passive-interface IFNAME",
@@ -757,6 +1103,14 @@ ri_new ()
{
struct ripng_interface *ri;
ri = XCALLOC (MTYPE_IF, sizeof (struct ripng_interface));
+
+ /* Set default split-horizon behavior. If the interface is Frame
+ 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 = RIPNG_SPLIT_HORIZON;
+ ri->split_horizon = ri->split_horizon_default;
+
return ri;
}
@@ -767,6 +1121,15 @@ ripng_if_new_hook (struct interface *ifp)
return 0;
}
+/* Called when interface structure deleted. */
+int
+ripng_if_delete_hook (struct interface *ifp)
+{
+ XFREE (MTYPE_IF, ifp->info);
+ ifp->info = NULL;
+ return 0;
+}
+
/* Configuration write function for ripngd. */
int
interface_config_write (struct vty *vty)
@@ -781,12 +1144,37 @@ 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))
+ continue;
+
vty_out (vty, "interface %s%s", ifp->name,
VTY_NEWLINE);
if (ifp->desc)
vty_out (vty, " description %s%s", ifp->desc,
VTY_NEWLINE);
+ /* Split horizon. */
+ if (ri->split_horizon != ri->split_horizon_default)
+ {
+ switch (ri->split_horizon) {
+ case RIPNG_SPLIT_HORIZON:
+ vty_out (vty, " ipv6 ripng split-horizon%s", VTY_NEWLINE);
+ break;
+ case RIPNG_SPLIT_HORIZON_POISONED_REVERSE:
+ vty_out (vty, " ipv6 ripng split-horizon poisoned-reverse%s",
+ VTY_NEWLINE);
+ break;
+ case RIPNG_NO_SPLIT_HORIZON:
+ default:
+ vty_out (vty, " no ipv6 ripng split-horizon%s", VTY_NEWLINE);
+ break;
+ }
+ }
+
vty_out (vty, "!%s", VTY_NEWLINE);
write++;
@@ -799,6 +1187,7 @@ struct cmd_node interface_node =
{
INTERFACE_NODE,
"%s(config-if)# ",
+ 1 /* VTYSH */
};
/* Initialization of interface. */
@@ -808,6 +1197,7 @@ ripng_if_init ()
/* Interface initialize. */
iflist = list_new ();
if_add_hook (IF_NEW_HOOK, ripng_if_new_hook);
+ if_add_hook (IF_DELETE_HOOK, ripng_if_delete_hook);
/* RIPng enable network init. */
ripng_enable_network = route_table_init ();
@@ -820,12 +1210,11 @@ ripng_if_init ()
/* Install interface node. */
install_node (&interface_node, interface_config_write);
-
+
+ /* Install commands. */
install_element (CONFIG_NODE, &interface_cmd);
install_element (CONFIG_NODE, &no_interface_cmd);
- install_element (INTERFACE_NODE, &config_end_cmd);
- install_element (INTERFACE_NODE, &config_exit_cmd);
- install_element (INTERFACE_NODE, &config_help_cmd);
+ install_default (INTERFACE_NODE);
install_element (INTERFACE_NODE, &interface_desc_cmd);
install_element (INTERFACE_NODE, &no_interface_desc_cmd);
@@ -833,4 +1222,9 @@ ripng_if_init ()
install_element (RIPNG_NODE, &no_ripng_network_cmd);
install_element (RIPNG_NODE, &ripng_passive_interface_cmd);
install_element (RIPNG_NODE, &no_ripng_passive_interface_cmd);
+
+ install_element (INTERFACE_NODE, &ipv6_ripng_split_horizon_cmd);
+ install_element (INTERFACE_NODE, &ipv6_ripng_split_horizon_poisoned_reverse_cmd);
+ install_element (INTERFACE_NODE, &no_ipv6_ripng_split_horizon_cmd);
+ install_element (INTERFACE_NODE, &no_ipv6_ripng_split_horizon_poisoned_reverse_cmd);
}
diff --git a/ripngd/ripng_main.c b/ripngd/ripng_main.c
index 3a7ed4a0..44c38762 100644
--- a/ripngd/ripng_main.c
+++ b/ripngd/ripng_main.c
@@ -27,6 +27,7 @@
#include "vector.h"
#include "vty.h"
#include "command.h"
+#include "memory.h"
#include "thread.h"
#include "log.h"
#include "prefix.h"
@@ -37,6 +38,7 @@
/* Configuration filename and directory. */
char config_current[] = RIPNG_DEFAULT_CONFIG;
char config_default[] = SYSCONFDIR RIPNG_DEFAULT_CONFIG;
+char *config_file = NULL;
/* RIPngd options. */
struct option longopts[] =
@@ -58,6 +60,12 @@ struct option longopts[] =
/* Route retain mode flag. */
int retain_mode = 0;
+/* RIPng VTY bind address. */
+char *vty_addr = NULL;
+
+/* RIPng VTY connection port. */
+int vty_port = RIPNG_VTY_PORT;
+
/* Master of threads. */
struct thread_master *master;
@@ -93,17 +101,27 @@ Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS);
void
sighup (int sig)
{
- zlog (NULL, LOG_INFO, "SIGHUP received");
+ zlog_info ("SIGHUP received");
+ ripng_clean ();
+ ripng_reset ();
+ zlog_info ("Terminating on signal");
+
+ /* Reload config file. */
+ vty_read_config (config_file, config_current, config_default);
+ /* Create VTY's socket */
+ vty_serv_sock (vty_addr, vty_port, RIPNG_VTYSH_PATH);
+
+ /* Try to return to normal operation. */
}
/* SIGINT handler. */
void
sigint (int sig)
{
- zlog (NULL, LOG_INFO, "Terminating on signal");
+ zlog_info ("Terminating on signal");
if (! retain_mode)
- ripng_terminate ();
+ ripng_clean ();
exit (0);
}
@@ -154,10 +172,8 @@ int
main (int argc, char **argv)
{
char *p;
- char *vty_addr = NULL;
int vty_port = RIPNG_VTY_PORT;
int daemon_mode = 0;
- char *config_file = NULL;
char *progname;
struct thread thread;
@@ -231,10 +247,14 @@ main (int argc, char **argv)
signal_init ();
cmd_init (1);
vty_init ();
+ memory_init ();
/* RIPngd inits. */
ripng_init ();
zebra_init ();
+ ripng_peer_init ();
+
+ /* Sort all installed commands. */
sort_node ();
/* Get configuration file. */
diff --git a/ripngd/ripng_nexthop.c b/ripngd/ripng_nexthop.c
new file mode 100644
index 00000000..2c5d45cd
--- /dev/null
+++ b/ripngd/ripng_nexthop.c
@@ -0,0 +1,216 @@
+/* RIPngd Zebra
+ * Copyright (C) 2002 6WIND <vincent.jardin@6wind.com>
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+/* This file is required in order to support properly the RIPng nexthop
+ * feature.
+ */
+
+#include <zebra.h>
+
+/* For struct udphdr. */
+#include <netinet/udp.h>
+
+#include "linklist.h"
+#include "stream.h"
+#include "log.h"
+#include "memory.h"
+#include "vty.h"
+#include "if.h"
+#include "prefix.h"
+
+#include "ripngd/ripngd.h"
+#include "ripngd/ripng_debug.h"
+#include "ripngd/ripng_nexthop.h"
+
+#define DEBUG 1
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+
+struct ripng_rte_data {
+ struct prefix_ipv6 *p;
+ struct ripng_info *rinfo;
+ struct ripng_aggregate *aggregate;
+};
+
+void _ripng_rte_del(struct ripng_rte_data *A);
+int _ripng_rte_cmp(struct ripng_rte_data *A, struct ripng_rte_data *B);
+
+#define METRIC_OUT(a) \
+ (a->rinfo ? a->rinfo->metric_out : a->aggregate->metric_out)
+#define NEXTHOP_OUT(a) \
+ (a->rinfo ? a->rinfo->nexthop_out : a->aggregate->nexthop_out)
+#define TAG_OUT(a) \
+ (a->rinfo ? a->rinfo->tag_out : a->aggregate->tag_out)
+
+struct list *
+ripng_rte_new(void) {
+ struct list *rte;
+
+ rte = list_new();
+ rte->cmp = (int (*)(void *, void *)) _ripng_rte_cmp;
+ rte->del = (void (*)(void *)) _ripng_rte_del;
+
+ return rte;
+}
+
+void
+ripng_rte_free(struct list *ripng_rte_list) {
+ list_delete(ripng_rte_list);
+}
+
+/* Delete RTE */
+void
+_ripng_rte_del(struct ripng_rte_data *A) {
+ XFREE(MTYPE_RIPNG_RTE_DATA, A);
+}
+
+/* Compare RTE:
+ * return + if A > B
+ * 0 if A = B
+ * - if A < B
+ */
+int
+_ripng_rte_cmp(struct ripng_rte_data *A, struct ripng_rte_data *B) {
+ return addr6_cmp(&NEXTHOP_OUT(A), &NEXTHOP_OUT(B));
+}
+
+/* Add routing table entry */
+void
+ripng_rte_add(struct list *ripng_rte_list, struct prefix_ipv6 *p,
+ struct ripng_info *rinfo, struct ripng_aggregate *aggregate) {
+
+ struct ripng_rte_data *data;
+
+ /* At least one should not be null */
+ assert(!rinfo || !aggregate);
+
+ data = XMALLOC(MTYPE_RIPNG_RTE_DATA, sizeof(*data));
+ data->p = p;
+ data->rinfo = rinfo;
+ data->aggregate = aggregate;
+
+ listnode_add_sort(ripng_rte_list, data);
+}
+
+/* Send the RTE with the nexthop support
+ */
+void
+ripng_rte_send(struct list *ripng_rte_list, struct interface *ifp,
+ struct sockaddr_in6 *to) {
+
+ struct ripng_rte_data *data;
+ struct listnode * nn;
+
+ struct in6_addr last_nexthop;
+ struct in6_addr myself_nexthop;
+
+ struct stream *s;
+ int num;
+ int mtu;
+ int rtemax;
+ int ret;
+
+ /* Most of the time, there is no nexthop */
+ memset(&last_nexthop, 0, sizeof(last_nexthop));
+
+ /* Use myself_nexthop if the nexthop is not a link-local address, because
+ * we remain a right path without beeing the optimal one.
+ */
+ memset(&myself_nexthop, 0, sizeof(myself_nexthop));
+
+ /* Output stream get from ripng structre. XXX this should be
+ interface structure. */
+ s = ripng->obuf;
+
+ /* Reset stream and RTE counter. */
+ stream_reset (s);
+ num = 0;
+
+ mtu = ifp->mtu;
+ if (mtu < 0)
+ mtu = IFMINMTU;
+
+ rtemax = (min (mtu, RIPNG_MAX_PACKET_SIZE) -
+ IPV6_HDRLEN -
+ sizeof (struct udphdr) -
+ sizeof (struct ripng_packet) +
+ sizeof (struct rte)) / sizeof (struct rte);
+
+ LIST_LOOP(ripng_rte_list, data, nn) {
+
+ /* (2.1) Next hop support */
+ if (!IPV6_ADDR_SAME(&last_nexthop, &NEXTHOP_OUT(data))) {
+
+ /* A nexthop entry should be at least followed by 1 RTE */
+ if (num == (rtemax-1)) {
+ ret = ripng_send_packet (STREAM_DATA (s), stream_get_endp (s),
+ to, ifp);
+
+ if (ret >= 0 && IS_RIPNG_DEBUG_SEND)
+ ripng_packet_dump((struct ripng_packet *)STREAM_DATA (s),
+ stream_get_endp(s), "SEND");
+ num = 0;
+ stream_reset (s);
+ }
+
+ /* Add the nexthop (2.1) */
+
+ /* If the received next hop address is not a link-local address,
+ * it should be treated as 0:0:0:0:0:0:0:0.
+ */
+ if (!IN6_IS_ADDR_LINKLOCAL(&NEXTHOP_OUT(data)))
+ last_nexthop = myself_nexthop;
+ else
+ last_nexthop = NEXTHOP_OUT(data);
+
+ num = ripng_write_rte(num, s, NULL, &last_nexthop, 0, RIPNG_METRIC_NEXTHOP);
+ } else {
+ /* Rewrite the nexthop for each new packet */
+ if ((num == 0) && !IPV6_ADDR_SAME(&last_nexthop, &myself_nexthop))
+ num = ripng_write_rte(num, s, NULL, &last_nexthop, 0, RIPNG_METRIC_NEXTHOP);
+ }
+ num = ripng_write_rte(num, s, data->p, NULL,
+ TAG_OUT(data), METRIC_OUT(data));
+
+ if (num == rtemax) {
+ ret = ripng_send_packet (STREAM_DATA (s), stream_get_endp (s),
+ to, ifp);
+
+ if (ret >= 0 && IS_RIPNG_DEBUG_SEND)
+ ripng_packet_dump((struct ripng_packet *)STREAM_DATA (s),
+ stream_get_endp(s), "SEND");
+ num = 0;
+ stream_reset (s);
+ }
+ }
+
+ /* If unwritten RTE exist, flush it. */
+ if (num != 0) {
+ ret = ripng_send_packet (STREAM_DATA (s), stream_get_endp (s),
+ to, ifp);
+
+ if (ret >= 0 && IS_RIPNG_DEBUG_SEND)
+ ripng_packet_dump ((struct ripng_packet *)STREAM_DATA (s),
+ stream_get_endp (s), "SEND");
+ num = 0;
+ stream_reset (s);
+ }
+}
diff --git a/ripngd/ripng_nexthop.h b/ripngd/ripng_nexthop.h
new file mode 100644
index 00000000..5c778f5e
--- /dev/null
+++ b/ripngd/ripng_nexthop.h
@@ -0,0 +1,62 @@
+/* RIPng nexthop support
+ * Copyright (C) 6WIND Vincent Jardin <vincent.jardin@6wind.com>
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_RIPNG_RIPNG_NEXTHOP_H
+#define _ZEBRA_RIPNG_RIPNG_NEXTHOP_H
+
+#include <zebra.h>
+#include "linklist.h"
+#include "ripngd/ripng_route.h"
+#include "ripngd/ripngd.h"
+
+struct list * ripng_rte_new(void);
+void ripng_rte_free(struct list *ripng_rte_list);
+void ripng_rte_add(struct list *ripng_rte_list, struct prefix_ipv6 *p,
+ struct ripng_info *rinfo, struct ripng_aggregate *aggregate);
+void ripng_rte_send(struct list *ripng_rte_list, struct interface *ifp,
+ struct sockaddr_in6 *to);
+
+/***
+ * 1 if A > B
+ * 0 if A = B
+ * -1 if A < B
+ **/
+static inline int
+addr6_cmp(struct in6_addr *A, struct in6_addr *B) {
+#define a(i) A->s6_addr32[i]
+#define b(i) B->s6_addr32[i]
+
+ if (a(3) > b(3))
+ return 1;
+ else if ((a(3) == b(3)) && (a(2) > b(2)))
+ return 1;
+ else if ((a(3) == b(3)) && (a(2) == b(2)) && (a(1) > b(1)))
+ return 1;
+ else if ((a(3) == b(3)) && (a(2) == b(2)) && (a(1) == b(1)) && (a(0) > b(0)))
+ return 1;
+
+ if ((a(3) == b(3)) && (a(2) == b(2)) && (a(1) == b(1)) && (a(0) == b(0)))
+ return 0;
+
+ return -1;
+}
+
+#endif /* _ZEBRA_RIPNG_RIPNG_NEXTHOP_H */
diff --git a/ripngd/ripng_offset.c b/ripngd/ripng_offset.c
new file mode 100644
index 00000000..ab3c4601
--- /dev/null
+++ b/ripngd/ripng_offset.c
@@ -0,0 +1,417 @@
+/* RIPng offset-list
+ * Copyright (C) 2000 Kunihiro Ishiguro <kunihiro@zebra.org>
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+ /* RIPng support by Vincent Jardin <vincent.jardin@6wind.com>
+ * Copyright (C) 2002 6WIND
+ */
+
+#include <zebra.h>
+
+#include "if.h"
+#include "prefix.h"
+#include "filter.h"
+#include "command.h"
+#include "linklist.h"
+#include "memory.h"
+
+#define RIPNG_OFFSET_LIST_IN 0
+#define RIPNG_OFFSET_LIST_OUT 1
+#define RIPNG_OFFSET_LIST_MAX 2
+
+struct ripng_offset_list
+{
+ char *ifname;
+
+ struct
+ {
+ char *alist_name;
+ /* struct access_list *alist; */
+ int metric;
+ } direct[RIPNG_OFFSET_LIST_MAX];
+};
+
+static struct list *ripng_offset_list_master;
+
+int
+strcmp_safe (char *s1, char *s2)
+{
+ if (s1 == NULL && s2 == NULL)
+ return 0;
+ if (s1 == NULL)
+ return -1;
+ if (s2 == NULL)
+ return 1;
+ return strcmp (s1, s2);
+}
+
+struct ripng_offset_list *
+ripng_offset_list_new ()
+{
+ struct ripng_offset_list *new;
+
+ new = XCALLOC (MTYPE_RIPNG_OFFSET_LIST, sizeof (struct ripng_offset_list));
+ return new;
+}
+
+void
+ripng_offset_list_free (struct ripng_offset_list *offset)
+{
+ XFREE (MTYPE_RIPNG_OFFSET_LIST, offset);
+}
+
+struct ripng_offset_list *
+ripng_offset_list_lookup (char *ifname)
+{
+ struct ripng_offset_list *offset;
+ struct listnode *nn;
+
+ LIST_LOOP (ripng_offset_list_master, offset, nn)
+ {
+ if (strcmp_safe (offset->ifname, ifname) == 0)
+ return offset;
+ }
+ return NULL;
+}
+
+struct ripng_offset_list *
+ripng_offset_list_get (char *ifname)
+{
+ struct ripng_offset_list *offset;
+
+ offset = ripng_offset_list_lookup (ifname);
+ if (offset)
+ return offset;
+
+ offset = ripng_offset_list_new ();
+ if (ifname)
+ offset->ifname = strdup (ifname);
+ listnode_add_sort (ripng_offset_list_master, offset);
+
+ return offset;
+}
+
+int
+ripng_offset_list_set (struct vty *vty, char *alist, char *direct_str,
+ char *metric_str, char *ifname)
+{
+ int direct;
+ int metric;
+ struct ripng_offset_list *offset;
+
+ /* Check direction. */
+ if (strncmp (direct_str, "i", 1) == 0)
+ direct = RIPNG_OFFSET_LIST_IN;
+ else if (strncmp (direct_str, "o", 1) == 0)
+ direct = RIPNG_OFFSET_LIST_OUT;
+ else
+ {
+ vty_out (vty, "Invalid direction: %s%s", direct_str, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* Check metric. */
+ metric = atoi (metric_str);
+ if (metric < 0 || metric > 16)
+ {
+ vty_out (vty, "Invalid metric: %s%s", metric_str, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* Get offset-list structure with interface name. */
+ offset = ripng_offset_list_get (ifname);
+
+ if (offset->direct[direct].alist_name)
+ free (offset->direct[direct].alist_name);
+ offset->direct[direct].alist_name = strdup (alist);
+ offset->direct[direct].metric = metric;
+
+ return CMD_SUCCESS;
+}
+
+int
+ripng_offset_list_unset (struct vty *vty, char *alist, char *direct_str,
+ char *metric_str, char *ifname)
+{
+ int direct;
+ int metric;
+ struct ripng_offset_list *offset;
+
+ /* Check direction. */
+ if (strncmp (direct_str, "i", 1) == 0)
+ direct = RIPNG_OFFSET_LIST_IN;
+ else if (strncmp (direct_str, "o", 1) == 0)
+ direct = RIPNG_OFFSET_LIST_OUT;
+ else
+ {
+ vty_out (vty, "Invalid direction: %s%s", direct_str, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* Check metric. */
+ metric = atoi (metric_str);
+ if (metric < 0 || metric > 16)
+ {
+ vty_out (vty, "Invalid metric: %s%s", metric_str, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* Get offset-list structure with interface name. */
+ offset = ripng_offset_list_lookup (ifname);
+
+ if (offset)
+ {
+ if (offset->direct[direct].alist_name)
+ free (offset->direct[direct].alist_name);
+ offset->direct[direct].alist_name = NULL;
+
+ if (offset->direct[RIPNG_OFFSET_LIST_IN].alist_name == NULL &&
+ offset->direct[RIPNG_OFFSET_LIST_OUT].alist_name == NULL)
+ {
+ listnode_delete (ripng_offset_list_master, offset);
+ if (offset->ifname)
+ free (offset->ifname);
+ ripng_offset_list_free (offset);
+ }
+ }
+ else
+ {
+ vty_out (vty, "Can't find offset-list%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ return CMD_SUCCESS;
+}
+
+#define OFFSET_LIST_IN_NAME(O) ((O)->direct[RIPNG_OFFSET_LIST_IN].alist_name)
+#define OFFSET_LIST_IN_METRIC(O) ((O)->direct[RIPNG_OFFSET_LIST_IN].metric)
+
+#define OFFSET_LIST_OUT_NAME(O) ((O)->direct[RIPNG_OFFSET_LIST_OUT].alist_name)
+#define OFFSET_LIST_OUT_METRIC(O) ((O)->direct[RIPNG_OFFSET_LIST_OUT].metric)
+
+/* If metric is modifed return 1. */
+int
+ripng_offset_list_apply_in (struct prefix_ipv6 *p, struct interface *ifp,
+ u_char *metric)
+{
+ struct ripng_offset_list *offset;
+ struct access_list *alist;
+
+ /* Look up offset-list with interface name. */
+ offset = ripng_offset_list_lookup (ifp->name);
+ if (offset && OFFSET_LIST_IN_NAME (offset))
+ {
+ alist = access_list_lookup (AFI_IP6, OFFSET_LIST_IN_NAME (offset));
+
+ if (alist
+ && access_list_apply (alist, (struct prefix *)p) == FILTER_PERMIT)
+ {
+ *metric += OFFSET_LIST_IN_METRIC (offset);
+ return 1;
+ }
+ return 0;
+ }
+ /* Look up offset-list without interface name. */
+ offset = ripng_offset_list_lookup (NULL);
+ if (offset && OFFSET_LIST_IN_NAME (offset))
+ {
+ alist = access_list_lookup (AFI_IP6, OFFSET_LIST_IN_NAME (offset));
+
+ if (alist
+ && access_list_apply (alist, (struct prefix *)p) == FILTER_PERMIT)
+ {
+ *metric += OFFSET_LIST_IN_METRIC (offset);
+ return 1;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+/* If metric is modifed return 1. */
+int
+ripng_offset_list_apply_out (struct prefix_ipv6 *p, struct interface *ifp,
+ u_char *metric)
+{
+ struct ripng_offset_list *offset;
+ struct access_list *alist;
+
+ /* Look up offset-list with interface name. */
+ offset = ripng_offset_list_lookup (ifp->name);
+ if (offset && OFFSET_LIST_OUT_NAME (offset))
+ {
+ alist = access_list_lookup (AFI_IP6, OFFSET_LIST_OUT_NAME (offset));
+
+ if (alist
+ && access_list_apply (alist, (struct prefix *)p) == FILTER_PERMIT)
+ {
+ *metric += OFFSET_LIST_OUT_METRIC (offset);
+ return 1;
+ }
+ return 0;
+ }
+
+ /* Look up offset-list without interface name. */
+ offset = ripng_offset_list_lookup (NULL);
+ if (offset && OFFSET_LIST_OUT_NAME (offset))
+ {
+ alist = access_list_lookup (AFI_IP6, OFFSET_LIST_OUT_NAME (offset));
+
+ if (alist
+ && access_list_apply (alist, (struct prefix *)p) == FILTER_PERMIT)
+ {
+ *metric += OFFSET_LIST_OUT_METRIC (offset);
+ return 1;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+DEFUN (ripng_offset_list,
+ ripng_offset_list_cmd,
+ "offset-list WORD (in|out) <0-16>",
+ "Modify RIPng metric\n"
+ "Access-list name\n"
+ "For incoming updates\n"
+ "For outgoing updates\n"
+ "Metric value\n")
+{
+ return ripng_offset_list_set (vty, argv[0], argv[1], argv[2], NULL);
+}
+
+DEFUN (ripng_offset_list_ifname,
+ ripng_offset_list_ifname_cmd,
+ "offset-list WORD (in|out) <0-16> IFNAME",
+ "Modify RIPng metric\n"
+ "Access-list name\n"
+ "For incoming updates\n"
+ "For outgoing updates\n"
+ "Metric value\n"
+ "Interface to match\n")
+{
+ return ripng_offset_list_set (vty, argv[0], argv[1], argv[2], argv[3]);
+}
+
+DEFUN (no_ripng_offset_list,
+ no_ripng_offset_list_cmd,
+ "no offset-list WORD (in|out) <0-16>",
+ NO_STR
+ "Modify RIPng metric\n"
+ "Access-list name\n"
+ "For incoming updates\n"
+ "For outgoing updates\n"
+ "Metric value\n")
+{
+ return ripng_offset_list_unset (vty, argv[0], argv[1], argv[2], NULL);
+}
+
+DEFUN (no_ripng_offset_list_ifname,
+ no_ripng_offset_list_ifname_cmd,
+ "no offset-list WORD (in|out) <0-16> IFNAME",
+ NO_STR
+ "Modify RIPng metric\n"
+ "Access-list name\n"
+ "For incoming updates\n"
+ "For outgoing updates\n"
+ "Metric value\n"
+ "Interface to match\n")
+{
+ return ripng_offset_list_unset (vty, argv[0], argv[1], argv[2], argv[3]);
+}
+
+int
+offset_list_cmp (struct ripng_offset_list *o1, struct ripng_offset_list *o2)
+{
+ return strcmp_safe (o1->ifname, o2->ifname);
+}
+
+void
+offset_list_del (struct ripng_offset_list *offset)
+{
+ if (OFFSET_LIST_IN_NAME (offset))
+ free (OFFSET_LIST_IN_NAME (offset));
+ if (OFFSET_LIST_OUT_NAME (offset))
+ free (OFFSET_LIST_OUT_NAME (offset));
+ if (offset->ifname)
+ free (offset->ifname);
+ ripng_offset_list_free (offset);
+}
+
+void
+ripng_offset_init ()
+{
+ ripng_offset_list_master = list_new ();
+ ripng_offset_list_master->cmp = (int (*)(void *, void *)) offset_list_cmp;
+ ripng_offset_list_master->del = (void (*)(void *)) offset_list_del;
+
+ install_element (RIPNG_NODE, &ripng_offset_list_cmd);
+ install_element (RIPNG_NODE, &ripng_offset_list_ifname_cmd);
+ install_element (RIPNG_NODE, &no_ripng_offset_list_cmd);
+ install_element (RIPNG_NODE, &no_ripng_offset_list_ifname_cmd);
+}
+
+void
+ripng_offset_clean ()
+{
+ list_delete (ripng_offset_list_master);
+
+ ripng_offset_list_master = list_new ();
+ ripng_offset_list_master->cmp = (int (*)(void *, void *)) offset_list_cmp;
+ ripng_offset_list_master->del = (void (*)(void *)) offset_list_del;
+}
+
+int
+config_write_ripng_offset_list (struct vty *vty)
+{
+ struct listnode *nn;
+ struct ripng_offset_list *offset;
+
+ LIST_LOOP (ripng_offset_list_master, offset, nn)
+ {
+ if (! offset->ifname)
+ {
+ if (offset->direct[RIPNG_OFFSET_LIST_IN].alist_name)
+ vty_out (vty, " offset-list %s in %d%s",
+ offset->direct[RIPNG_OFFSET_LIST_IN].alist_name,
+ offset->direct[RIPNG_OFFSET_LIST_IN].metric,
+ VTY_NEWLINE);
+ if (offset->direct[RIPNG_OFFSET_LIST_OUT].alist_name)
+ vty_out (vty, " offset-list %s out %d%s",
+ offset->direct[RIPNG_OFFSET_LIST_OUT].alist_name,
+ offset->direct[RIPNG_OFFSET_LIST_OUT].metric,
+ VTY_NEWLINE);
+ }
+ else
+ {
+ if (offset->direct[RIPNG_OFFSET_LIST_IN].alist_name)
+ vty_out (vty, " offset-list %s in %d %s%s",
+ offset->direct[RIPNG_OFFSET_LIST_IN].alist_name,
+ offset->direct[RIPNG_OFFSET_LIST_IN].metric,
+ offset->ifname, VTY_NEWLINE);
+ if (offset->direct[RIPNG_OFFSET_LIST_OUT].alist_name)
+ vty_out (vty, " offset-list %s out %d %s%s",
+ offset->direct[RIPNG_OFFSET_LIST_OUT].alist_name,
+ offset->direct[RIPNG_OFFSET_LIST_OUT].metric,
+ offset->ifname, VTY_NEWLINE);
+ }
+ }
+
+ return 0;
+}
diff --git a/ripngd/ripng_peer.c b/ripngd/ripng_peer.c
new file mode 100644
index 00000000..b9af930c
--- /dev/null
+++ b/ripngd/ripng_peer.c
@@ -0,0 +1,220 @@
+/* RIPng peer support
+ * Copyright (C) 2000 Kunihiro Ishiguro <kunihiro@zebra.org>
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+/* RIPng support added by Vincent Jardin <vincent.jardin@6wind.com>
+ * Copyright (C) 2002 6WIND
+ */
+
+#include <zebra.h>
+
+#include "if.h"
+#include "prefix.h"
+#include "command.h"
+#include "linklist.h"
+#include "thread.h"
+#include "memory.h"
+
+#include "ripngd/ripngd.h"
+#include "ripngd/ripng_nexthop.h"
+
+
+/* Linked list of RIPng peer. */
+struct list *peer_list;
+
+struct ripng_peer *
+ripng_peer_new ()
+{
+ struct ripng_peer *new;
+
+ new = XMALLOC (MTYPE_RIPNG_PEER, sizeof (struct ripng_peer));
+ memset (new, 0, sizeof (struct ripng_peer));
+ return new;
+}
+
+void
+ripng_peer_free (struct ripng_peer *peer)
+{
+ XFREE (MTYPE_RIPNG_PEER, peer);
+}
+
+struct ripng_peer *
+ripng_peer_lookup (struct in6_addr *addr)
+{
+ struct ripng_peer *peer;
+ struct listnode *nn;
+
+ LIST_LOOP (peer_list, peer, nn)
+ {
+ if (IPV6_ADDR_SAME (&peer->addr, addr))
+ return peer;
+ }
+ return NULL;
+}
+
+struct ripng_peer *
+ripng_peer_lookup_next (struct in6_addr *addr)
+{
+ struct ripng_peer *peer;
+ struct listnode *nn;
+
+ LIST_LOOP (peer_list, peer, nn)
+ {
+ if (addr6_cmp(&peer->addr, addr) > 0)
+ return peer;
+ }
+ return NULL;
+}
+
+/* RIPng peer is timeout.
+ * Garbage collector.
+ **/
+int
+ripng_peer_timeout (struct thread *t)
+{
+ struct ripng_peer *peer;
+
+ peer = THREAD_ARG (t);
+ listnode_delete (peer_list, peer);
+ ripng_peer_free (peer);
+
+ return 0;
+}
+
+/* Get RIPng peer. At the same time update timeout thread. */
+struct ripng_peer *
+ripng_peer_get (struct in6_addr *addr)
+{
+ struct ripng_peer *peer;
+
+ peer = ripng_peer_lookup (addr);
+
+ if (peer)
+ {
+ if (peer->t_timeout)
+ thread_cancel (peer->t_timeout);
+ }
+ else
+ {
+ peer = ripng_peer_new ();
+ peer->addr = *addr; /* XXX */
+ listnode_add_sort (peer_list, peer);
+ }
+
+ /* Update timeout thread. */
+ peer->t_timeout = thread_add_timer (master, ripng_peer_timeout, peer,
+ RIPNG_PEER_TIMER_DEFAULT);
+
+ /* Last update time set. */
+ time (&peer->uptime);
+
+ return peer;
+}
+
+void
+ripng_peer_update (struct sockaddr_in6 *from, u_char version)
+{
+ struct ripng_peer *peer;
+ peer = ripng_peer_get (&from->sin6_addr);
+ peer->version = version;
+}
+
+void
+ripng_peer_bad_route (struct sockaddr_in6 *from)
+{
+ struct ripng_peer *peer;
+ peer = ripng_peer_get (&from->sin6_addr);
+ peer->recv_badroutes++;
+}
+
+void
+ripng_peer_bad_packet (struct sockaddr_in6 *from)
+{
+ struct ripng_peer *peer;
+ peer = ripng_peer_get (&from->sin6_addr);
+ peer->recv_badpackets++;
+}
+
+/* Display peer uptime. */
+char *
+ripng_peer_uptime (struct ripng_peer *peer, char *buf, size_t len)
+{
+ time_t uptime;
+ struct tm *tm;
+
+ /* If there is no connection has been done before print `never'. */
+ if (peer->uptime == 0)
+ {
+ snprintf (buf, len, "never ");
+ return buf;
+ }
+
+ /* Get current time. */
+ uptime = time (NULL);
+ uptime -= peer->uptime;
+ tm = gmtime (&uptime);
+
+ /* Making formatted timer strings. */
+#define ONE_DAY_SECOND 60*60*24
+#define ONE_WEEK_SECOND 60*60*24*7
+
+ if (uptime < ONE_DAY_SECOND)
+ snprintf (buf, len, "%02d:%02d:%02d",
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+ else if (uptime < ONE_WEEK_SECOND)
+ snprintf (buf, len, "%dd%02dh%02dm",
+ tm->tm_yday, tm->tm_hour, tm->tm_min);
+ else
+ snprintf (buf, len, "%02dw%dd%02dh",
+ tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour);
+ return buf;
+}
+
+void
+ripng_peer_display (struct vty *vty)
+{
+ struct ripng_peer *peer;
+ struct listnode *nn;
+#define RIPNG_UPTIME_LEN 25
+ char timebuf[RIPNG_UPTIME_LEN];
+
+ LIST_LOOP (peer_list, peer, nn)
+ {
+ vty_out (vty, " %s %s%14s %10d %10d %10d %s%s", inet6_ntop (&peer->addr),
+ VTY_NEWLINE, " ",
+ peer->recv_badpackets, peer->recv_badroutes,
+ ZEBRA_RIPNG_DISTANCE_DEFAULT,
+ ripng_peer_uptime (peer, timebuf, RIPNG_UPTIME_LEN),
+ VTY_NEWLINE);
+ }
+}
+
+int
+ripng_peer_list_cmp (struct ripng_peer *p1, struct ripng_peer *p2)
+{
+ return addr6_cmp(&p1->addr, &p2->addr) > 0;
+}
+
+void
+ripng_peer_init ()
+{
+ peer_list = list_new ();
+ peer_list->cmp = (int (*)(void *, void *)) ripng_peer_list_cmp;
+}
diff --git a/ripngd/ripng_route.c b/ripngd/ripng_route.c
index 27475f05..9c3c4f99 100644
--- a/ripngd/ripng_route.c
+++ b/ripngd/ripng_route.c
@@ -26,6 +26,7 @@
#include "table.h"
#include "memory.h"
#include "if.h"
+#include "vty.h"
#include "ripngd/ripngd.h"
#include "ripngd/ripng_route.h"
diff --git a/ripngd/ripng_route.h b/ripngd/ripng_route.h
index 283d8268..db53f148 100644
--- a/ripngd/ripng_route.h
+++ b/ripngd/ripng_route.h
@@ -36,6 +36,12 @@ struct ripng_aggregate
/* Tag field of RIPng packet.*/
u_short tag;
+
+ /* Route-map futures - this variables can be changed. */
+ struct in6_addr nexthop_out;
+ u_char metric_set;
+ u_char metric_out;
+ u_short tag_out;
};
void
diff --git a/ripngd/ripng_routemap.c b/ripngd/ripng_routemap.c
index 832f17c9..0bd7e448 100644
--- a/ripngd/ripng_routemap.c
+++ b/ripngd/ripng_routemap.c
@@ -26,11 +26,175 @@
#include "prefix.h"
#include "routemap.h"
#include "command.h"
+#include "sockunion.h"
#include "ripngd/ripngd.h"
-#if 0
+struct rip_metric_modifier
+{
+ enum
+ {
+ metric_increment,
+ metric_decrement,
+ metric_absolute
+ } type;
+
+ u_char metric;
+};
+
+
+int
+ripng_route_match_add (struct vty *vty, struct route_map_index *index,
+ char *command, char *arg)
+{
+ int ret;
+
+ ret = route_map_add_match (index, command, arg);
+ if (ret)
+ {
+ switch (ret)
+ {
+ case RMAP_RULE_MISSING:
+ vty_out (vty, "Can't find rule.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ break;
+ case RMAP_COMPILE_ERROR:
+ vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ break;
+ }
+ }
+ return CMD_SUCCESS;
+}
+
+int
+ripng_route_match_delete (struct vty *vty, struct route_map_index *index,
+ char *command, char *arg)
+{
+ int ret;
+
+ ret = route_map_delete_match (index, command, arg);
+ if (ret)
+ {
+ switch (ret)
+ {
+ case RMAP_RULE_MISSING:
+ vty_out (vty, "Can't find rule.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ break;
+ case RMAP_COMPILE_ERROR:
+ vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ break;
+ }
+ }
+ return CMD_SUCCESS;
+}
+
+int
+ripng_route_set_add (struct vty *vty, struct route_map_index *index,
+ char *command, char *arg)
+{
+ int ret;
+
+ ret = route_map_add_set (index, command, arg);
+ if (ret)
+ {
+ switch (ret)
+ {
+ case RMAP_RULE_MISSING:
+ vty_out (vty, "Can't find rule.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ break;
+ case RMAP_COMPILE_ERROR:
+ vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ break;
+ }
+ }
+ return CMD_SUCCESS;
+}
+
+int
+ripng_route_set_delete (struct vty *vty, struct route_map_index *index,
+ char *command, char *arg)
+{
+ int ret;
+
+ ret = route_map_delete_set (index, command, arg);
+ if (ret)
+ {
+ switch (ret)
+ {
+ case RMAP_RULE_MISSING:
+ vty_out (vty, "Can't find rule.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ break;
+ case RMAP_COMPILE_ERROR:
+ vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ break;
+ }
+ }
+ return CMD_SUCCESS;
+}
+
+/* `match metric METRIC' */
+/* Match function return 1 if match is success else return zero. */
+route_map_result_t
+route_match_metric (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ u_int32_t *metric;
+ struct ripng_info *rinfo;
+
+ if (type == RMAP_RIPNG)
+ {
+ metric = rule;
+ rinfo = object;
+
+ if (rinfo->metric == *metric)
+ return RMAP_MATCH;
+ else
+ return RMAP_NOMATCH;
+ }
+ return RMAP_NOMATCH;
+}
+
+/* Route map `match metric' match statement. `arg' is METRIC value */
+void *
+route_match_metric_compile (char *arg)
+{
+ u_int32_t *metric;
+
+ metric = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t));
+ *metric = atoi (arg);
+
+ if(*metric > 0)
+ return metric;
+
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, metric);
+ return NULL;
+}
+
+/* Free route map's compiled `match metric' value. */
+void
+route_match_metric_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for metric matching. */
+struct route_map_rule_cmd route_match_metric_cmd =
+{
+ "metric",
+ route_match_metric,
+ route_match_metric_compile,
+ route_match_metric_free
+};
+
/* `match interface IFNAME' */
+/* Match function return 1 if match is success else return zero. */
route_map_result_t
route_match_interface (void *rule, struct prefix *prefix,
route_map_object_t type, void *object)
@@ -39,24 +203,25 @@ route_match_interface (void *rule, struct prefix *prefix,
struct interface *ifp;
char *ifname;
- if (type == ROUTE_MAP_RIPNG)
+ if (type == RMAP_RIPNG)
{
ifname = rule;
ifp = if_lookup_by_name(ifname);
if (!ifp)
- return RM_NOMATCH;
+ return RMAP_NOMATCH;
rinfo = object;
if (rinfo->ifindex == ifp->ifindex)
- return RM_MATCH;
+ return RMAP_MATCH;
else
- return RM_NOMATCH;
+ return RMAP_NOMATCH;
}
- return RM_NOMATCH;
+ return RMAP_NOMATCH;
}
+/* Route map `match interface' match statement. `arg' is IFNAME value */
void *
route_match_interface_compile (char *arg)
{
@@ -76,20 +241,61 @@ struct route_map_rule_cmd route_match_interface_cmd =
route_match_interface_compile,
route_match_interface_free
};
-#endif /* 0 */
-
-struct rip_metric_modifier
+
+/* `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)
{
- enum
- {
- metric_increment,
- metric_decrement,
- metric_absolute
- } type;
+ u_short *tag;
+ struct ripng_info *rinfo;
- u_char metric;
+ if (type == RMAP_RIPNG)
+ {
+ 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' */
+/* Set metric to attribute. */
route_map_result_t
route_set_metric (void *rule, struct prefix *prefix,
route_map_object_t type, void *object)
@@ -103,22 +309,23 @@ route_set_metric (void *rule, struct prefix *prefix,
rinfo = object;
if (mod->type == metric_increment)
- rinfo->metric += mod->metric;
+ rinfo->metric_out += mod->metric;
else if (mod->type == metric_decrement)
- rinfo->metric -= mod->metric;
+ rinfo->metric_out-= mod->metric;
else if (mod->type == metric_absolute)
- rinfo->metric = mod->metric;
+ rinfo->metric_out = mod->metric;
- if (rinfo->metric < 1)
- rinfo->metric = 1;
- if (rinfo->metric > RIPNG_METRIC_INFINITY)
- rinfo->metric = RIPNG_METRIC_INFINITY;
+ if (rinfo->metric_out < 1)
+ rinfo->metric_out = 1;
+ if (rinfo->metric_out > RIPNG_METRIC_INFINITY)
+ rinfo->metric_out = RIPNG_METRIC_INFINITY;
rinfo->metric_set = 1;
}
return RMAP_OKAY;
}
+/* set metric compilation. */
void *
route_set_metric_compile (char *arg)
{
@@ -171,6 +378,7 @@ route_set_metric_compile (char *arg)
return mod;
}
+/* Free route map's compiled `set metric' value. */
void
route_set_metric_free (void *rule)
{
@@ -184,109 +392,158 @@ struct route_map_rule_cmd route_set_metric_cmd =
route_set_metric_compile,
route_set_metric_free,
};
-
-int
-ripng_route_match_add (struct vty *vty, struct route_map_index *index,
- char *command, char *arg)
+
+/* `set ipv6 next-hop local IP_ADDRESS' */
+
+/* Set nexthop to object. ojbect must be pointer to struct attr. */
+route_map_result_t
+route_set_ipv6_nexthop_local (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
{
- int ret;
+ struct in6_addr *address;
+ struct ripng_info *rinfo;
- ret = route_map_add_match (index, command, arg);
- if (ret)
+ if(type == RMAP_RIPNG)
{
- switch (ret)
- {
- case RMAP_RULE_MISSING:
- vty_out (vty, "Can't find rule.%s", VTY_NEWLINE);
- return CMD_WARNING;
- break;
- case RMAP_COMPILE_ERROR:
- vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE);
- return CMD_WARNING;
- break;
- }
+ /* Fetch routemap's rule information. */
+ address = rule;
+ rinfo = object;
+
+ /* Set next hop value. */
+ rinfo->nexthop_out = *address;
}
- return CMD_SUCCESS;
+
+ return RMAP_OKAY;
}
-int
-ripng_route_match_delete (struct vty *vty, struct route_map_index *index,
- char *command, char *arg)
+/* Route map `ipv6 nexthop local' compile function. Given string is converted
+ to struct in6_addr structure. */
+void *
+route_set_ipv6_nexthop_local_compile (char *arg)
{
int ret;
+ struct in6_addr *address;
- ret = route_map_delete_match (index, command, arg);
- if (ret)
+ address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in_addr));
+
+ ret = inet_pton (AF_INET6, arg, address);
+
+ if (ret == 0)
{
- switch (ret)
- {
- case RMAP_RULE_MISSING:
- vty_out (vty, "Can't find rule.%s", VTY_NEWLINE);
- return CMD_WARNING;
- break;
- case RMAP_COMPILE_ERROR:
- vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE);
- return CMD_WARNING;
- break;
- }
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, address);
+ return NULL;
}
- return CMD_SUCCESS;
+
+ return address;
}
-int
-ripng_route_set_add (struct vty *vty, struct route_map_index *index,
- char *command, char *arg)
+/* Free route map's compiled `ipv6 nexthop local' value. */
+void
+route_set_ipv6_nexthop_local_free (void *rule)
{
- int ret;
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
- ret = route_map_add_set (index, command, arg);
- if (ret)
+/* Route map commands for ipv6 nexthop local set. */
+struct route_map_rule_cmd route_set_ipv6_nexthop_local_cmd =
+{
+ "ipv6 next-hop local",
+ route_set_ipv6_nexthop_local,
+ route_set_ipv6_nexthop_local_compile,
+ route_set_ipv6_nexthop_local_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 ripng_info *rinfo;
+
+ if(type == RMAP_RIPNG)
{
- switch (ret)
- {
- case RMAP_RULE_MISSING:
- vty_out (vty, "Can't find rule.%s", VTY_NEWLINE);
- return CMD_WARNING;
- break;
- case RMAP_COMPILE_ERROR:
- vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE);
- return CMD_WARNING;
- break;
- }
+ /* Fetch routemap's rule information. */
+ tag = rule;
+ rinfo = object;
+
+ /* Set next hop value. */
+ rinfo->tag_out = *tag;
}
- return CMD_SUCCESS;
+
+ return RMAP_OKAY;
}
-int
-ripng_route_set_delete (struct vty *vty, struct route_map_index *index,
- char *command, char *arg)
+/* Route map `tag' compile function. Given string is converted
+ to u_short. */
+void *
+route_set_tag_compile (char *arg)
{
- int ret;
+ u_short *tag;
- ret = route_map_delete_set (index, command, arg);
- if (ret)
- {
- switch (ret)
- {
- case RMAP_RULE_MISSING:
- vty_out (vty, "Can't find rule.%s", VTY_NEWLINE);
- return CMD_WARNING;
- break;
- case RMAP_COMPILE_ERROR:
- vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE);
- return CMD_WARNING;
- break;
- }
- }
- return CMD_SUCCESS;
+ 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
+};
-#if 0
+#define MATCH_STR "Match values from routing table\n"
+#define SET_STR "Set values in destination routing protocol\n"
+
+DEFUN (match_metric,
+ match_metric_cmd,
+ "match metric <0-4294967295>",
+ MATCH_STR
+ "Match metric of route\n"
+ "Metric value\n")
+{
+ return ripng_route_match_add (vty, vty->index, "metric", argv[0]);
+}
+
+DEFUN (no_match_metric,
+ no_match_metric_cmd,
+ "no match metric",
+ NO_STR
+ MATCH_STR
+ "Match metric of route\n")
+{
+ if (argc == 0)
+ return ripng_route_match_delete (vty, vty->index, "metric", NULL);
+
+ return ripng_route_match_delete (vty, vty->index, "metric", argv[0]);
+}
+
+ALIAS (no_match_metric,
+ no_match_metric_val_cmd,
+ "no match metric <0-4294967295>",
+ NO_STR
+ MATCH_STR
+ "Match metric of route\n"
+ "Metric value\n")
+
DEFUN (match_interface,
match_interface_cmd,
"match interface WORD",
- "Match value\n"
- "Interface\n"
+ MATCH_STR
+ "Match first hop interface of route\n"
"Interface name\n")
{
return ripng_route_match_add (vty, vty->index, "interface", argv[0]);
@@ -294,22 +551,64 @@ DEFUN (match_interface,
DEFUN (no_match_interface,
no_match_interface_cmd,
+ "no match interface",
+ NO_STR
+ MATCH_STR
+ "Match first hop interface of route\n")
+{
+ if (argc == 0)
+ return ripng_route_match_delete (vty, vty->index, "interface", NULL);
+
+ return ripng_route_match_delete (vty, vty->index, "interface", argv[0]);
+}
+
+ALIAS (no_match_interface,
+ no_match_interface_val_cmd,
"no match interface WORD",
NO_STR
- "Match value\n"
- "Interface\n"
+ MATCH_STR
+ "Match first hop interface of route\n"
"Interface name\n")
+
+DEFUN (match_tag,
+ match_tag_cmd,
+ "match tag <0-65535>",
+ MATCH_STR
+ "Match tag of route\n"
+ "Metric value\n")
{
- return ripng_route_match_delete (vty, vty->index, "interface", argv[0]);
+ return ripng_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 ripng_route_match_delete (vty, vty->index, "tag", NULL);
+
+ return ripng_route_match_delete (vty, vty->index, "tag", argv[0]);
}
-#endif /* 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 value\n"
- "Metric\n"
- "METRIC value\n")
+ "Metric value for destination routing protocol\n"
+ "Metric value\n")
{
return ripng_route_set_add (vty, vty->index, "metric", argv[0]);
}
@@ -335,20 +634,122 @@ ALIAS (no_set_metric,
"Metric value for destination routing protocol\n"
"Metric value\n")
+DEFUN (set_ipv6_nexthop_local,
+ set_ipv6_nexthop_local_cmd,
+ "set ipv6 next-hop local X:X::X:X",
+ SET_STR
+ IPV6_STR
+ "IPv6 next-hop address\n"
+ "IPv6 local address\n"
+ "IPv6 address of next hop\n")
+{
+ union sockunion su;
+ int ret;
+
+ ret = str2sockunion (argv[0], &su);
+ if (ret < 0)
+ {
+ vty_out (vty, "%% Malformed next-hop local address%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return ripng_route_set_add (vty, vty->index, "ipv6 next-hop local", argv[0]);
+}
+
+DEFUN (no_set_ipv6_nexthop_local,
+ no_set_ipv6_nexthop_local_cmd,
+ "no set ipv6 next-hop local",
+ NO_STR
+ SET_STR
+ IPV6_STR
+ "IPv6 next-hop address\n"
+ "IPv6 local address\n")
+{
+ if (argc == 0)
+ return ripng_route_set_delete (vty, vty->index, "ipv6 next-hop local", NULL);
+
+ return ripng_route_set_delete (vty, vty->index, "ipv6 next-hop local", argv[0]);
+}
+
+ALIAS (no_set_ipv6_nexthop_local,
+ no_set_ipv6_nexthop_local_val_cmd,
+ "no set ipv6 next-hop local X:X::X:X",
+ NO_STR
+ SET_STR
+ IPV6_STR
+ "IPv6 next-hop address\n"
+ "IPv6 local address\n"
+ "IPv6 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 ripng_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 ripng_route_set_delete (vty, vty->index, "tag", NULL);
+
+ return ripng_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
+ripng_route_map_reset ()
+{
+ /* XXX ??? */
+ ;
+}
+
void
ripng_route_map_init ()
{
route_map_init ();
route_map_init_vty ();
- /* route_map_install_match (&route_match_interface_cmd); */
+ route_map_install_match (&route_match_metric_cmd);
+ route_map_install_match (&route_match_interface_cmd);
+ route_map_install_match (&route_match_tag_cmd);
+
route_map_install_set (&route_set_metric_cmd);
+ route_map_install_set (&route_set_ipv6_nexthop_local_cmd);
+ route_map_install_set (&route_set_tag_cmd);
- /*
+ install_element (RMAP_NODE, &match_metric_cmd);
+ install_element (RMAP_NODE, &no_match_metric_cmd);
+ install_element (RMAP_NODE, &no_match_metric_val_cmd);
install_element (RMAP_NODE, &match_interface_cmd);
install_element (RMAP_NODE, &no_match_interface_cmd);
- */
+ install_element (RMAP_NODE, &no_match_interface_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);
+ install_element (RMAP_NODE, &no_set_metric_val_cmd);
+ install_element (RMAP_NODE, &set_ipv6_nexthop_local_cmd);
+ install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_cmd);
+ install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_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/ripngd/ripng_zebra.c b/ripngd/ripng_zebra.c
index 4d8a48d3..1af5e240 100644
--- a/ripngd/ripng_zebra.c
+++ b/ripngd/ripng_zebra.c
@@ -133,13 +133,19 @@ ripng_zebra_read_ipv6 (int command, struct zclient *zclient,
api.metric = 0;
if (command == ZEBRA_IPV6_ROUTE_ADD)
- ripng_redistribute_add (api.type, 0, &p, ifindex);
+ ripng_redistribute_add (api.type, RIPNG_ROUTE_REDISTRIBUTE, &p, ifindex, &nexthop);
else
- ripng_redistribute_delete (api.type, 0, &p, ifindex);
+ ripng_redistribute_delete (api.type, RIPNG_ROUTE_REDISTRIBUTE, &p, ifindex);
return 0;
}
+void
+ripng_zclient_reset ()
+{
+ zclient_reset (zclient);
+}
+
int
ripng_redistribute_unset (int type)
{
@@ -156,6 +162,12 @@ ripng_redistribute_unset (int type)
return CMD_SUCCESS;
}
+int
+ripng_redistribute_check (int type)
+{
+ return (zclient->redist[type]);
+}
+
void
ripng_redistribute_metric_set (int type, int metric)
{
@@ -163,11 +175,12 @@ ripng_redistribute_metric_set (int type, int metric)
ripng->route_map[type].metric = metric;
}
-void
+int
ripng_redistribute_metric_unset (int type)
{
ripng->route_map[type].metric_config = 0;
ripng->route_map[type].metric = 0;
+ return 0;
}
void
@@ -189,8 +202,42 @@ ripng_redistribute_routemap_unset (int type)
ripng->route_map[type].name = NULL;
ripng->route_map[type].map = NULL;
}
-
+/* Redistribution types */
+static struct {
+ int type;
+ int str_min_len;
+ char *str;
+} redist_type[] = {
+ {ZEBRA_ROUTE_KERNEL, 1, "kernel"},
+ {ZEBRA_ROUTE_CONNECT, 1, "connected"},
+ {ZEBRA_ROUTE_STATIC, 1, "static"},
+ {ZEBRA_ROUTE_OSPF6, 1, "ospf6"},
+ {ZEBRA_ROUTE_BGP, 1, "bgp"},
+ {0, 0, NULL}
+};
+
+void
+ripng_redistribute_clean ()
+{
+ int i;
+
+ for (i = 0; redist_type[i].str; i++)
+ {
+ if (zclient->redist[redist_type[i].type])
+ {
+ if (zclient->sock > 0)
+ zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE,
+ zclient->sock, redist_type[i].type);
+
+ zclient->redist[redist_type[i].type] = 0;
+
+ /* Remove the routes from RIPng table. */
+ ripng_redistribute_withdraw (redist_type[i].type);
+ }
+ }
+}
+
DEFUN (router_zebra,
router_zebra_cmd,
"router zebra",
@@ -236,513 +283,205 @@ DEFUN (no_ripng_redistribute_ripng,
return CMD_SUCCESS;
}
-DEFUN (ripng_redistribute_static,
- ripng_redistribute_static_cmd,
- "redistribute static",
- "Redistribute information from another routing protocol\n"
- "Static routes\n")
-{
- zclient_redistribute_set (zclient, ZEBRA_ROUTE_STATIC);
- return CMD_SUCCESS;
-}
-
-DEFUN (no_ripng_redistribute_static,
- no_ripng_redistribute_static_cmd,
- "no redistribute static",
- NO_STR
- "Redistribute information from another routing protocol\n"
- "Static routes\n")
-{
- ripng_redistribute_metric_unset (ZEBRA_ROUTE_STATIC);
- ripng_redistribute_routemap_unset (ZEBRA_ROUTE_STATIC);
- return ripng_redistribute_unset (ZEBRA_ROUTE_STATIC);
-}
-
-DEFUN (ripng_redistribute_kernel,
- ripng_redistribute_kernel_cmd,
- "redistribute kernel",
- "Redistribute information from another routing protocol\n"
- "Kernel routes\n")
-{
- zclient_redistribute_set (zclient, ZEBRA_ROUTE_KERNEL);
- return CMD_SUCCESS;
-}
-
-DEFUN (no_ripng_redistribute_kernel,
- no_ripng_redistribute_kernel_cmd,
- "no redistribute kernel",
- NO_STR
+DEFUN (ripng_redistribute_type,
+ ripng_redistribute_type_cmd,
+ "redistribute (kernel|connected|static|ospf6|bgp)",
"Redistribute information from another routing protocol\n"
- "Kernel routes\n")
+ "Kernel routes\n"
+ "Connected\n"
+ "Static routes\n"
+ "Open Shortest Path First (OSPFv3)\n"
+ "Border Gateway Protocol (BGP)\n")
{
- ripng_redistribute_metric_unset (ZEBRA_ROUTE_KERNEL);
- ripng_redistribute_routemap_unset (ZEBRA_ROUTE_KERNEL);
- return ripng_redistribute_unset (ZEBRA_ROUTE_KERNEL);
-}
+ int i;
-DEFUN (ripng_redistribute_connected,
- ripng_redistribute_connected_cmd,
- "redistribute connected",
- "Redistribute information from another routing protocol\n"
- "Connected\n")
-{
- zclient_redistribute_set (zclient, ZEBRA_ROUTE_CONNECT);
- return CMD_SUCCESS;
-}
+ for(i = 0; redist_type[i].str; i++)
+ {
+ if (strncmp (redist_type[i].str, argv[0],
+ redist_type[i].str_min_len) == 0)
+ {
+ zclient_redistribute_set (zclient, redist_type[i].type);
+ return CMD_SUCCESS;
+ }
+ }
-DEFUN (no_ripng_redistribute_connected,
- no_ripng_redistribute_connected_cmd,
- "no redistribute connected",
- NO_STR
- "Redistribute information from another routing protocol\n"
- "Connected\n")
-{
- ripng_redistribute_metric_unset (ZEBRA_ROUTE_CONNECT);
- ripng_redistribute_routemap_unset (ZEBRA_ROUTE_CONNECT);
- return ripng_redistribute_unset (ZEBRA_ROUTE_CONNECT);
-}
+ vty_out(vty, "Invalid type %s%s", argv[0],
+ VTY_NEWLINE);
-DEFUN (ripng_redistribute_bgp,
- ripng_redistribute_bgp_cmd,
- "redistribute bgp",
- "Redistribute information from another routing protocol\n"
- "Border Gateway Protocol (BGP)\n")
-{
- zclient_redistribute_set (zclient, ZEBRA_ROUTE_BGP);
- return CMD_SUCCESS;
+ return CMD_WARNING;
}
-DEFUN (no_ripng_redistribute_bgp,
- no_ripng_redistribute_bgp_cmd,
- "no redistribute bgp",
+DEFUN (no_ripng_redistribute_type,
+ no_ripng_redistribute_type_cmd,
+ "no redistribute (kernel|connected|static|ospf6|bgp)",
NO_STR
"Redistribute information from another routing protocol\n"
+ "Kernel routes\n"
+ "Connected\n"
+ "Static routes\n"
+ "Open Shortest Path First (OSPFv3)\n"
"Border Gateway Protocol (BGP)\n")
{
- ripng_redistribute_metric_unset (ZEBRA_ROUTE_BGP);
- ripng_redistribute_routemap_unset (ZEBRA_ROUTE_BGP);
- return ripng_redistribute_unset (ZEBRA_ROUTE_BGP);
-}
+ int i;
-DEFUN (ripng_redistribute_ospf6,
- ripng_redistribute_ospf6_cmd,
- "redistribute ospf6",
- "Redistribute information from another routing protocol\n"
- "IPv6 Open Shortest Path First (OSPFv3)\n")
-{
- zclient_redistribute_set (zclient, ZEBRA_ROUTE_OSPF6);
- return CMD_SUCCESS;
-}
+ for (i = 0; redist_type[i].str; i++)
+ {
+ if (strncmp(redist_type[i].str, argv[0],
+ redist_type[i].str_min_len) == 0)
+ {
+ ripng_redistribute_metric_unset (redist_type[i].type);
+ ripng_redistribute_routemap_unset (redist_type[i].type);
+ return ripng_redistribute_unset (redist_type[i].type);
+ }
+ }
-DEFUN (no_ripng_redistribute_ospf6,
- no_ripng_redistribute_ospf6_cmd,
- "no redistribute ospf6",
- NO_STR
- "Redistribute information from another routing protocol\n"
- "IPv6 Open Shortest Path First (OSPFv3)\n")
-{
- ripng_redistribute_metric_unset (ZEBRA_ROUTE_OSPF6);
- ripng_redistribute_routemap_unset (ZEBRA_ROUTE_OSPF6);
- return ripng_redistribute_unset (ZEBRA_ROUTE_OSPF6);
-}
+ vty_out(vty, "Invalid type %s%s", argv[0],
+ VTY_NEWLINE);
-DEFUN (ripng_redistribute_kernel_metric,
- ripng_redistribute_kernel_metric_cmd,
- "redistribute kernel metric <0-16>",
- "Redistribute information from another routing protocol\n"
- "Kernel routes\n"
- "Metric\n"
- "Metric value\n")
-{
- ripng_redistribute_metric_set (ZEBRA_ROUTE_KERNEL, atoi (argv[0]));
- zclient_redistribute_set (zclient, ZEBRA_ROUTE_KERNEL);
- return CMD_SUCCESS;
+ return CMD_WARNING;
}
-ALIAS (no_ripng_redistribute_kernel,
- no_ripng_redistribute_kernel_metric_cmd,
- "no redistribute kernel metric",
- NO_STR
- "Redistribute information from another routing protocol\n"
- "Kernel routes\n"
- "Metric\n")
-ALIAS (no_ripng_redistribute_kernel,
- no_ripng_redistribute_kernel_metric_val_cmd,
- "no redistribute kernel metric <0-16>",
- NO_STR
+DEFUN (ripng_redistribute_type_metric,
+ ripng_redistribute_type_metric_cmd,
+ "redistribute (kernel|connected|static|ospf6|bgp) metric <0-16>",
"Redistribute information from another routing protocol\n"
"Kernel routes\n"
- "Metric\n"
- "Metric value\n")
-
-DEFUN (ripng_redistribute_connected_metric,
- ripng_redistribute_connected_metric_cmd,
- "redistribute connected metric <0-16>",
- "Redistribute information from another routing protocol\n"
"Connected\n"
- "Metric\n"
- "Metric value\n")
-{
- ripng_redistribute_metric_set (ZEBRA_ROUTE_CONNECT, atoi (argv[0]));
- zclient_redistribute_set (zclient, ZEBRA_ROUTE_CONNECT);
- return CMD_SUCCESS;
-}
-
-ALIAS (no_ripng_redistribute_connected,
- no_ripng_redistribute_connected_metric_cmd,
- "no redistribute connected metric",
- NO_STR
- "Redistribute information from another routing protocol\n"
- "Connected\n"
- "Metric\n")
-
-ALIAS (no_ripng_redistribute_connected,
- no_ripng_redistribute_connected_metric_val_cmd,
- "no redistribute connected metric <0-16>",
- NO_STR
- "Redistribute information from another routing protocol\n"
- "Connected\n"
- "Metric\n"
- "Metric value\n")
-
-DEFUN (ripng_redistribute_static_metric,
- ripng_redistribute_static_metric_cmd,
- "redistribute static metric <0-16>",
- "Redistribute information from another routing protocol\n"
"Static routes\n"
+ "Open Shortest Path First (OSPFv3)\n"
+ "Border Gateway Protocol (BGP)\n"
"Metric\n"
"Metric value\n")
{
- ripng_redistribute_metric_set (ZEBRA_ROUTE_STATIC, atoi (argv[0]));
- zclient_redistribute_set (zclient, ZEBRA_ROUTE_STATIC);
- return CMD_SUCCESS;
-}
-
-ALIAS (no_ripng_redistribute_static,
- no_ripng_redistribute_static_metric_cmd,
- "no redistribute static metric",
- NO_STR
- "Redistribute information from another routing protocol\n"
- "Static routes\n"
- "Metric\n")
+ int i;
+ int metric;
-ALIAS (no_ripng_redistribute_static,
- no_ripng_redistribute_static_metric_val_cmd,
- "no redistribute static metric <0-16>",
- NO_STR
- "Redistribute information from another routing protocol\n"
- "Static routes\n"
- "Metric\n"
- "Metric value\n")
+ metric = atoi (argv[1]);
-DEFUN (ripng_redistribute_ospf6_metric,
- ripng_redistribute_ospf6_metric_cmd,
- "redistribute ospf6 metric <0-16>",
- "Redistribute information from another routing protocol\n"
- "IPv6 Open Shortest Path First (OSPFv3)\n"
- "Metric\n"
- "Metric value\n")
-{
- ripng_redistribute_metric_set (ZEBRA_ROUTE_OSPF6, atoi (argv[0]));
- zclient_redistribute_set (zclient, ZEBRA_ROUTE_OSPF6);
- return CMD_SUCCESS;
-}
+ for (i = 0; redist_type[i].str; i++) {
+ if (strncmp(redist_type[i].str, argv[0],
+ redist_type[i].str_min_len) == 0)
+ {
+ ripng_redistribute_metric_set (redist_type[i].type, metric);
+ zclient_redistribute_set (zclient, redist_type[i].type);
+ return CMD_SUCCESS;
+ }
+ }
-ALIAS (no_ripng_redistribute_ospf6,
- no_ripng_redistribute_ospf6_metric_cmd,
- "no redistribute ospf6 metric",
- NO_STR
- "Redistribute information from another routing protocol\n"
- "IPv6 Open Shortest Path First (OSPFv3)\n"
- "Metric\n")
+ vty_out(vty, "Invalid type %s%s", argv[0],
+ VTY_NEWLINE);
-ALIAS (no_ripng_redistribute_ospf6,
- no_ripng_redistribute_ospf6_metric_val_cmd,
- "no redistribute ospf6 metric <0-16>",
- NO_STR
- "Redistribute information from another routing protocol\n"
- "IPv6 Open Shortest Path First (OSPFv3)\n"
- "Metric\n"
- "Metric value\n")
-
-DEFUN (ripng_redistribute_bgp_metric,
- ripng_redistribute_bgp_metric_cmd,
- "redistribute bgp metric <0-16>",
- "Redistribute information from another routing protocol\n"
- "Border Gateway Protocol (BGP)\n"
- "Metric\n"
- "Metric value\n")
-{
- ripng_redistribute_metric_set (ZEBRA_ROUTE_BGP, atoi (argv[0]));
- zclient_redistribute_set (zclient, ZEBRA_ROUTE_BGP);
- return CMD_SUCCESS;
+ return CMD_WARNING;
}
-ALIAS (no_ripng_redistribute_bgp,
- no_ripng_redistribute_bgp_metric_cmd,
- "no redistribute bgp metric",
- NO_STR
- "Redistribute information from another routing protocol\n"
- "Border Gateway Protocol (BGP)\n"
- "Metric\n")
-
-ALIAS (no_ripng_redistribute_bgp,
- no_ripng_redistribute_bgp_metric_val_cmd,
- "no redistribute bgp metric <0-16>",
+ALIAS (no_ripng_redistribute_type,
+ no_ripng_redistribute_type_metric_cmd,
+ "no redistribute (kernel|connected|static|ospf6|bgp) metric <0-16>",
NO_STR
"Redistribute information from another routing protocol\n"
+ "Kernel routes\n"
+ "Connected\n"
+ "Static routes\n"
+ "Open Shortest Path First (OSPFv3)\n"
"Border Gateway Protocol (BGP)\n"
"Metric\n"
"Metric value\n")
-DEFUN (ripng_redistribute_kernel_routemap,
- ripng_redistribute_kernel_routemap_cmd,
- "redistribute kernel route-map WORD",
- "Redistribute information from another routing protocol\n"
- "Kernel routes\n"
- "Route map reference\n"
- "Pointer to route-map entries\n")
-{
- ripng_redistribute_routemap_set (ZEBRA_ROUTE_KERNEL, argv[0]);
- zclient_redistribute_set (zclient, ZEBRA_ROUTE_KERNEL);
- return CMD_SUCCESS;
-}
-
-ALIAS (no_ripng_redistribute_kernel,
- no_ripng_redistribute_kernel_routemap_cmd,
- "no redistribute kernel route-map WORD",
- NO_STR
+DEFUN (ripng_redistribute_type_routemap,
+ ripng_redistribute_type_routemap_cmd,
+ "redistribute (kernel|connected|static|ospf6|bgp) route-map WORD",
"Redistribute information from another routing protocol\n"
"Kernel routes\n"
- "Route map reference\n"
- "Pointer to route-map entries\n")
-
-DEFUN (ripng_redistribute_connected_routemap,
- ripng_redistribute_connected_routemap_cmd,
- "redistribute connected route-map WORD",
- "Redistribute information from another routing protocol\n"
"Connected\n"
- "Route map reference\n"
- "Pointer to route-map entries\n")
-{
- ripng_redistribute_routemap_set (ZEBRA_ROUTE_CONNECT, argv[0]);
- zclient_redistribute_set (zclient, ZEBRA_ROUTE_CONNECT);
- return CMD_SUCCESS;
-}
-
-ALIAS (no_ripng_redistribute_connected,
- no_ripng_redistribute_connected_routemap_cmd,
- "no redistribute connected route-map WORD",
- NO_STR
- "Redistribute information from another routing protocol\n"
- "Connected\n"
- "Route map reference\n"
- "Pointer to route-map entries\n")
-
-DEFUN (ripng_redistribute_static_routemap,
- ripng_redistribute_static_routemap_cmd,
- "redistribute static route-map WORD",
- "Redistribute information from another routing protocol\n"
- "Static routes\n"
- "Route map reference\n"
- "Pointer to route-map entries\n")
-{
- ripng_redistribute_routemap_set (ZEBRA_ROUTE_STATIC, argv[0]);
- zclient_redistribute_set (zclient, ZEBRA_ROUTE_STATIC);
- return CMD_SUCCESS;
-}
-
-ALIAS (no_ripng_redistribute_static,
- no_ripng_redistribute_static_routemap_cmd,
- "no redistribute static route-map WORD",
- NO_STR
- "Redistribute information from another routing protocol\n"
"Static routes\n"
- "Route map reference\n"
- "Pointer to route-map entries\n")
-
-DEFUN (ripng_redistribute_ospf6_routemap,
- ripng_redistribute_ospf6_routemap_cmd,
- "redistribute ospf6 route-map WORD",
- "Redistribute information from another routing protocol\n"
- "IPv6 Open Shortest Path First (OSPFv3)\n"
- "Route map reference\n"
- "Pointer to route-map entries\n")
-{
- ripng_redistribute_routemap_set (ZEBRA_ROUTE_OSPF6, argv[0]);
- zclient_redistribute_set (zclient, ZEBRA_ROUTE_OSPF6);
- return CMD_SUCCESS;
-}
-
-ALIAS (no_ripng_redistribute_ospf6,
- no_ripng_redistribute_ospf6_routemap_cmd,
- "no redistribute ospf6 route-map WORD",
- NO_STR
- "Redistribute information from another routing protocol\n"
- "IPv6 Open Shortest Path First (OSPFv3)\n"
- "Route map reference\n"
- "Pointer to route-map entries\n")
-
-DEFUN (ripng_redistribute_bgp_routemap,
- ripng_redistribute_bgp_routemap_cmd,
- "redistribute bgp route-map WORD",
- "Redistribute information from another routing protocol\n"
+ "Open Shortest Path First (OSPFv3)\n"
"Border Gateway Protocol (BGP)\n"
"Route map reference\n"
"Pointer to route-map entries\n")
{
- ripng_redistribute_routemap_set (ZEBRA_ROUTE_BGP, argv[0]);
- zclient_redistribute_set (zclient, ZEBRA_ROUTE_BGP);
- return CMD_SUCCESS;
-}
+ int i;
-ALIAS (no_ripng_redistribute_bgp,
- no_ripng_redistribute_bgp_routemap_cmd,
- "no redistribute bgp route-map WORD",
- NO_STR
- "Redistribute information from another routing protocol\n"
- "Border Gateway Protocol (BGP)\n"
- "Route map reference\n"
- "Pointer to route-map entries\n")
+ for (i = 0; redist_type[i].str; i++) {
+ if (strncmp(redist_type[i].str, argv[0],
+ redist_type[i].str_min_len) == 0)
+ {
+ ripng_redistribute_routemap_set (redist_type[i].type, argv[1]);
+ zclient_redistribute_set (zclient, redist_type[i].type);
+ return CMD_SUCCESS;
+ }
+ }
-DEFUN (ripng_redistribute_kernel_metric_routemap,
- ripng_redistribute_kernel_metric_routemap_cmd,
- "redistribute kernel metric <0-16> route-map WORD",
- "Redistribute information from another routing protocol\n"
- "Kernel routes\n"
- "Metric\n"
- "Metric value\n"
- "Route map reference\n"
- "Pointer to route-map entries\n")
-{
- ripng_redistribute_metric_set (ZEBRA_ROUTE_KERNEL, atoi (argv[0]));
- ripng_redistribute_routemap_set (ZEBRA_ROUTE_KERNEL, argv[1]);
- zclient_redistribute_set (zclient, ZEBRA_ROUTE_KERNEL);
- return CMD_SUCCESS;
+ vty_out(vty, "Invalid type %s%s", argv[0],
+ VTY_NEWLINE);
+
+ return CMD_WARNING;
}
-ALIAS (no_ripng_redistribute_kernel,
- no_ripng_redistribute_kernel_metric_routemap_cmd,
- "no redistribute kernel metric <0-16> route-map WORD",
+ALIAS (no_ripng_redistribute_type,
+ no_ripng_redistribute_type_routemap_cmd,
+ "no redistribute (kernel|connected|static|ospf6|bgp) route-map WORD",
NO_STR
"Redistribute information from another routing protocol\n"
"Kernel routes\n"
- "Metric\n"
- "Metric value\n"
- "Route map reference\n"
- "Pointer to route-map entries\n")
-
-DEFUN (ripng_redistribute_connected_metric_routemap,
- ripng_redistribute_connected_metric_routemap_cmd,
- "redistribute connected metric <0-16> route-map WORD",
- "Redistribute information from another routing protocol\n"
"Connected\n"
- "Metric\n"
- "Metric value\n"
+ "Static routes\n"
+ "Open Shortest Path First (OSPFv3)\n"
+ "Border Gateway Protocol (BGP)\n"
"Route map reference\n"
"Pointer to route-map entries\n")
-{
- ripng_redistribute_metric_set (ZEBRA_ROUTE_CONNECT, atoi (argv[0]));
- ripng_redistribute_routemap_set (ZEBRA_ROUTE_CONNECT, argv[1]);
- zclient_redistribute_set (zclient, ZEBRA_ROUTE_CONNECT);
- return CMD_SUCCESS;
-}
-ALIAS (no_ripng_redistribute_connected,
- no_ripng_redistribute_connected_metric_routemap_cmd,
- "no redistribute connected metric <0-16> route-map WORD",
- NO_STR
+DEFUN (ripng_redistribute_type_metric_routemap,
+ ripng_redistribute_type_metric_routemap_cmd,
+ "redistribute (kernel|connected|static|ospf6|bgp) metric <0-16> route-map WORD",
"Redistribute information from another routing protocol\n"
+ "Kernel routes\n"
"Connected\n"
- "Metric\n"
- "Metric value\n"
- "Route map reference\n"
- "Pointer to route-map entries\n")
-
-DEFUN (ripng_redistribute_static_metric_routemap,
- ripng_redistribute_static_metric_routemap_cmd,
- "redistribute static metric <0-16> route-map WORD",
- "Redistribute information from another routing protocol\n"
"Static routes\n"
+ "Open Shortest Path First (OSPFv3)\n"
+ "Border Gateway Protocol (BGP)\n"
"Metric\n"
"Metric value\n"
"Route map reference\n"
"Pointer to route-map entries\n")
{
- ripng_redistribute_metric_set (ZEBRA_ROUTE_STATIC, atoi (argv[0]));
- ripng_redistribute_routemap_set (ZEBRA_ROUTE_STATIC, argv[1]);
- zclient_redistribute_set (zclient, ZEBRA_ROUTE_STATIC);
- return CMD_SUCCESS;
-}
+ int i;
+ int metric;
-ALIAS (no_ripng_redistribute_static,
- no_ripng_redistribute_static_metric_routemap_cmd,
- "no redistribute static metric <0-16> route-map WORD",
- NO_STR
- "Redistribute information from another routing protocol\n"
- "Static routes\n"
- "Metric\n"
- "Metric value\n"
- "Route map reference\n"
- "Pointer to route-map entries\n")
+ metric = atoi (argv[1]);
-DEFUN (ripng_redistribute_ospf6_metric_routemap,
- ripng_redistribute_ospf6_metric_routemap_cmd,
- "redistribute ospf6 metric <0-16> route-map WORD",
- "Redistribute information from another routing protocol\n"
- "IPv6 Open Shortest Path First (OSPFv3)\n"
- "Metric\n"
- "Metric value\n"
- "Route map reference\n"
- "Pointer to route-map entries\n")
-{
- ripng_redistribute_metric_set (ZEBRA_ROUTE_OSPF6, atoi (argv[0]));
- ripng_redistribute_routemap_set (ZEBRA_ROUTE_OSPF6, argv[1]);
- zclient_redistribute_set (zclient, ZEBRA_ROUTE_OSPF6);
- return CMD_SUCCESS;
-}
+ for (i = 0; redist_type[i].str; i++) {
+ if (strncmp(redist_type[i].str, argv[0],
+ redist_type[i].str_min_len) == 0)
+ {
+ ripng_redistribute_metric_set (redist_type[i].type, metric);
+ ripng_redistribute_routemap_set (redist_type[i].type, argv[2]);
+ zclient_redistribute_set (zclient, redist_type[i].type);
+ return CMD_SUCCESS;
+ }
+ }
-ALIAS (no_ripng_redistribute_ospf6,
- no_ripng_redistribute_ospf6_metric_routemap_cmd,
- "no redistribute ospf6 metric <0-16> route-map WORD",
- NO_STR
- "Redistribute information from another routing protocol\n"
- "IPv6 Open Shortest Path First (OSPFv3)\n"
- "Metric\n"
- "Metric value\n"
- "Route map reference\n"
- "Pointer to route-map entries\n")
+ vty_out(vty, "Invalid type %s%s", argv[0],
+ VTY_NEWLINE);
-DEFUN (ripng_redistribute_bgp_metric_routemap,
- ripng_redistribute_bgp_metric_routemap_cmd,
- "redistribute bgp metric <0-16> route-map WORD",
- "Redistribute information from another routing protocol\n"
- "Border Gateway Protocol (BGP)\n"
- "Metric\n"
- "Metric value\n"
- "Route map reference\n"
- "Pointer to route-map entries\n")
-{
- ripng_redistribute_metric_set (ZEBRA_ROUTE_BGP, atoi (argv[0]));
- ripng_redistribute_routemap_set (ZEBRA_ROUTE_BGP, argv[1]);
- zclient_redistribute_set (zclient, ZEBRA_ROUTE_BGP);
- return CMD_SUCCESS;
+ return CMD_WARNING;
}
-ALIAS (no_ripng_redistribute_bgp,
- no_ripng_redistribute_bgp_metric_routemap_cmd,
- "no redistribute bgp metric <0-16> route-map WORD",
+ALIAS (no_ripng_redistribute_type,
+ no_ripng_redistribute_type_metric_routemap_cmd,
+ "no redistribute (kernel|connected|static|ospf6|bgp) metric <0-16> route-map WORD",
NO_STR
"Redistribute information from another routing protocol\n"
+ "Kernel routes\n"
+ "Connected\n"
+ "Static routes\n"
+ "Open Shortest Path First (OSPFv3)\n"
"Border Gateway Protocol (BGP)\n"
- "Metric\n"
- "Metric value\n"
"Route map reference\n"
"Pointer to route-map entries\n")
void
-ripng_redistribute_write (struct vty *vty)
+ripng_redistribute_write (struct vty *vty, int config_mode)
{
int i;
char *str[] = { "system", "kernel", "connected", "static", "rip",
@@ -751,24 +490,29 @@ ripng_redistribute_write (struct vty *vty)
for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
if (i != zclient->redist_default && zclient->redist[i])
{
- if (ripng->route_map[i].metric_config)
- {
- if (ripng->route_map[i].name)
- vty_out (vty, " redistribute %s metric %d route-map %s%s",
- str[i], ripng->route_map[i].metric,
- ripng->route_map[i].name, VTY_NEWLINE);
- else
- vty_out (vty, " redistribute %s metric %d%s",
- str[i], ripng->route_map[i].metric, VTY_NEWLINE);
- }
- else
- {
- if (ripng->route_map[i].name)
- vty_out (vty, " redistribute %s route-map %s%s",
- str[i], ripng->route_map[i].name, VTY_NEWLINE);
- else
- vty_out (vty, " redistribute %s%s", str[i], VTY_NEWLINE);
- }
+ if (config_mode)
+ {
+ if (ripng->route_map[i].metric_config)
+ {
+ if (ripng->route_map[i].name)
+ vty_out (vty, " redistribute %s metric %d route-map %s%s",
+ str[i], ripng->route_map[i].metric,
+ ripng->route_map[i].name, VTY_NEWLINE);
+ else
+ vty_out (vty, " redistribute %s metric %d%s",
+ str[i], ripng->route_map[i].metric, VTY_NEWLINE);
+ }
+ else
+ {
+ if (ripng->route_map[i].name)
+ vty_out (vty, " redistribute %s route-map %s%s",
+ str[i], ripng->route_map[i].name, VTY_NEWLINE);
+ else
+ vty_out (vty, " redistribute %s%s", str[i], VTY_NEWLINE);
+ }
+ }
+ else
+ vty_out (vty, " %s", str[i]);
}
}
@@ -823,55 +567,14 @@ zebra_init ()
install_default (ZEBRA_NODE);
install_element (ZEBRA_NODE, &ripng_redistribute_ripng_cmd);
install_element (ZEBRA_NODE, &no_ripng_redistribute_ripng_cmd);
- install_element (RIPNG_NODE, &ripng_redistribute_static_cmd);
- install_element (RIPNG_NODE, &no_ripng_redistribute_static_cmd);
- install_element (RIPNG_NODE, &ripng_redistribute_kernel_cmd);
- install_element (RIPNG_NODE, &no_ripng_redistribute_kernel_cmd);
- install_element (RIPNG_NODE, &ripng_redistribute_connected_cmd);
- install_element (RIPNG_NODE, &no_ripng_redistribute_connected_cmd);
- install_element (RIPNG_NODE, &ripng_redistribute_bgp_cmd);
- install_element (RIPNG_NODE, &no_ripng_redistribute_bgp_cmd);
- install_element (RIPNG_NODE, &ripng_redistribute_ospf6_cmd);
- install_element (RIPNG_NODE, &no_ripng_redistribute_ospf6_cmd);
- install_element (RIPNG_NODE, &ripng_redistribute_kernel_metric_cmd);
- install_element (RIPNG_NODE, &no_ripng_redistribute_kernel_metric_cmd);
- install_element (RIPNG_NODE, &no_ripng_redistribute_kernel_metric_val_cmd);
- install_element (RIPNG_NODE, &ripng_redistribute_connected_metric_cmd);
- install_element (RIPNG_NODE, &no_ripng_redistribute_connected_metric_cmd);
- install_element (RIPNG_NODE,
- &no_ripng_redistribute_connected_metric_val_cmd);
- install_element (RIPNG_NODE, &ripng_redistribute_static_metric_cmd);
- install_element (RIPNG_NODE, &no_ripng_redistribute_static_metric_cmd);
- install_element (RIPNG_NODE, &no_ripng_redistribute_static_metric_val_cmd);
- install_element (RIPNG_NODE, &ripng_redistribute_ospf6_metric_cmd);
- install_element (RIPNG_NODE, &no_ripng_redistribute_ospf6_metric_cmd);
- install_element (RIPNG_NODE, &no_ripng_redistribute_ospf6_metric_val_cmd);
- install_element (RIPNG_NODE, &ripng_redistribute_bgp_metric_cmd);
- install_element (RIPNG_NODE, &no_ripng_redistribute_bgp_metric_cmd);
- install_element (RIPNG_NODE, &no_ripng_redistribute_bgp_metric_val_cmd);
- install_element (RIPNG_NODE, &ripng_redistribute_kernel_routemap_cmd);
- install_element (RIPNG_NODE, &no_ripng_redistribute_kernel_routemap_cmd);
- install_element (RIPNG_NODE, &ripng_redistribute_connected_routemap_cmd);
- install_element (RIPNG_NODE, &no_ripng_redistribute_connected_routemap_cmd);
- install_element (RIPNG_NODE, &ripng_redistribute_static_routemap_cmd);
- install_element (RIPNG_NODE, &no_ripng_redistribute_static_routemap_cmd);
- install_element (RIPNG_NODE, &ripng_redistribute_ospf6_routemap_cmd);
- install_element (RIPNG_NODE, &no_ripng_redistribute_ospf6_routemap_cmd);
- install_element (RIPNG_NODE, &ripng_redistribute_bgp_routemap_cmd);
- install_element (RIPNG_NODE, &no_ripng_redistribute_bgp_routemap_cmd);
- install_element (RIPNG_NODE, &ripng_redistribute_kernel_metric_routemap_cmd);
- install_element (RIPNG_NODE,
- &no_ripng_redistribute_kernel_metric_routemap_cmd);
- install_element (RIPNG_NODE,
- &ripng_redistribute_connected_metric_routemap_cmd);
- install_element (RIPNG_NODE,
- &no_ripng_redistribute_connected_metric_routemap_cmd);
- install_element (RIPNG_NODE, &ripng_redistribute_static_metric_routemap_cmd);
- install_element (RIPNG_NODE,
- &no_ripng_redistribute_static_metric_routemap_cmd);
- install_element (RIPNG_NODE, &ripng_redistribute_ospf6_metric_routemap_cmd);
- install_element (RIPNG_NODE,
- &no_ripng_redistribute_ospf6_metric_routemap_cmd);
- install_element (RIPNG_NODE, &ripng_redistribute_bgp_metric_routemap_cmd);
- install_element (RIPNG_NODE, &no_ripng_redistribute_bgp_metric_routemap_cmd);
+
+ /* Install command elements to ripng node */
+ install_element (RIPNG_NODE, &ripng_redistribute_type_cmd);
+ install_element (RIPNG_NODE, &ripng_redistribute_type_routemap_cmd);
+ install_element (RIPNG_NODE, &ripng_redistribute_type_metric_cmd);
+ install_element (RIPNG_NODE, &ripng_redistribute_type_metric_routemap_cmd);
+ install_element (RIPNG_NODE, &no_ripng_redistribute_type_cmd);
+ install_element (RIPNG_NODE, &no_ripng_redistribute_type_routemap_cmd);
+ install_element (RIPNG_NODE, &no_ripng_redistribute_type_metric_cmd);
+ install_element (RIPNG_NODE, &no_ripng_redistribute_type_metric_routemap_cmd);
}
diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c
index e7cefaf0..a4d119dc 100644
--- a/ripngd/ripngd.c
+++ b/ripngd/ripngd.c
@@ -21,9 +21,6 @@
#include <zebra.h>
-/* For struct udphdr. */
-#include <netinet/udp.h>
-
#include "prefix.h"
#include "filter.h"
#include "log.h"
@@ -42,8 +39,7 @@
#include "ripngd/ripngd.h"
#include "ripngd/ripng_route.h"
#include "ripngd/ripng_debug.h"
-
-#define min(a, b) ((a) < (b) ? (a) : (b))
+#include "ripngd/ripng_nexthop.h"
/* RIPng structure which includes many parameters related to RIPng
protocol. If ripng couldn't active or ripng doesn't configured,
@@ -54,13 +50,11 @@ enum
{
ripng_all_route,
ripng_changed_route,
- ripng_split_horizon,
- ripng_no_split_horizon
};
/* Prototypes. */
void
-ripng_output_process (struct interface *, struct sockaddr_in6 *, int, int);
+ripng_output_process (struct interface *, struct sockaddr_in6 *, int);
int
ripng_triggered_update (struct thread *);
@@ -87,6 +81,12 @@ inet6_ntop (struct in6_addr *p)
return buf;
}
+int
+ripng_route_rte (struct ripng_info *rinfo)
+{
+ return (rinfo->type == ZEBRA_ROUTE_RIPNG && rinfo->sub_type == RIPNG_ROUTE_RTE);
+}
+
/* Allocate new ripng information. */
struct ripng_info *
ripng_info_new ()
@@ -175,12 +175,12 @@ ripng_send_packet (caddr_t buf, int bufsize, struct sockaddr_in6 *to,
struct in6_pktinfo *pkt;
struct sockaddr_in6 addr;
-#ifdef DEBUG
- if (to)
- zlog_info ("DEBUG RIPng: send to %s", inet6_ntop (&to->sin6_addr));
- zlog_info ("DEBUG RIPng: send if %s", ifp->name);
- zlog_info ("DEBUG RIPng: send packet size %d", bufsize);
-#endif /* DEBUG */
+ if (IS_RIPNG_DEBUG_SEND) {
+ if (to)
+ zlog_info ("send to %s", inet6_ntop (&to->sin6_addr));
+ zlog_info (" send interface %s", ifp->name);
+ zlog_info (" send packet size %d", bufsize);
+ }
memset (&addr, 0, sizeof (struct sockaddr_in6));
addr.sin6_family = AF_INET6;
@@ -222,8 +222,13 @@ ripng_send_packet (caddr_t buf, int bufsize, struct sockaddr_in6 *to,
ret = sendmsg (ripng->sock, &msg, 0);
- if (ret < 0)
- zlog_warn ("RIPng send fail on %s: %s", ifp->name, strerror (errno));
+ if (ret < 0) {
+ if (to)
+ zlog_err ("RIPng send fail on %s to %s: %s", ifp->name,
+ inet6_ntop (&to->sin6_addr), strerror (errno));
+ else
+ zlog_err ("RIPng send fail on %s: %s", ifp->name, strerror (errno));
+ }
return ret;
}
@@ -420,14 +425,6 @@ ripng_garbage_collect (struct thread *t)
/* Get route_node pointer. */
rp = rinfo->rp;
- /* Delete this route from the kernel. */
- ripng_zebra_ipv6_delete ((struct prefix_ipv6 *)&rp->p,
- &rinfo->nexthop, rinfo->ifindex);
- rinfo->flags &= ~RIPNG_RTF_FIB;
-
- /* Aggregate count decrement. */
- ripng_aggregate_decrement (rp, rinfo);
-
/* Unlock route_node. */
rp->info = NULL;
route_unlock_node (rp);
@@ -455,9 +452,16 @@ ripng_timeout (struct thread *t)
RIPNG_TIMER_ON (rinfo->t_garbage_collect, ripng_garbage_collect,
ripng->garbage_time);
+ /* Delete this route from the kernel. */
+ ripng_zebra_ipv6_delete ((struct prefix_ipv6 *)&rp->p, &rinfo->nexthop,
+ rinfo->ifindex);
/* - The metric for the route is set to 16 (infinity). This causes
the route to be removed from service. */
rinfo->metric = RIPNG_METRIC_INFINITY;
+ rinfo->flags &= ~RIPNG_RTF_FIB;
+
+ /* Aggregate count decrement. */
+ ripng_aggregate_decrement (rp, rinfo);
/* - The route change flag is to indicate that this entry has been
changed. */
@@ -479,12 +483,154 @@ ripng_timeout_update (struct ripng_info *rinfo)
}
}
+int
+ripng_incoming_filter (struct prefix_ipv6 *p, struct ripng_interface *ri)
+{
+ struct distribute *dist;
+ struct access_list *alist;
+ struct prefix_list *plist;
+
+ /* Input distribute-list filtering. */
+ if (ri->list[RIPNG_FILTER_IN])
+ {
+ if (access_list_apply (ri->list[RIPNG_FILTER_IN],
+ (struct prefix *) p) == FILTER_DENY)
+ {
+ if (IS_RIPNG_DEBUG_PACKET)
+ zlog_info ("%s/%d filtered by distribute in",
+ inet6_ntop (&p->prefix), p->prefixlen);
+ return -1;
+ }
+ }
+ if (ri->prefix[RIPNG_FILTER_IN])
+ {
+ if (prefix_list_apply (ri->prefix[RIPNG_FILTER_IN],
+ (struct prefix *) p) == PREFIX_DENY)
+ {
+ if (IS_RIPNG_DEBUG_PACKET)
+ zlog_info ("%s/%d filtered by prefix-list in",
+ inet6_ntop (&p->prefix), p->prefixlen);
+ return -1;
+ }
+ }
+
+ /* All interface filter check. */
+ dist = distribute_lookup (NULL);
+ if (dist)
+ {
+ if (dist->list[DISTRIBUTE_IN])
+ {
+ alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_IN]);
+
+ if (alist)
+ {
+ if (access_list_apply (alist,
+ (struct prefix *) p) == FILTER_DENY)
+ {
+ if (IS_RIPNG_DEBUG_PACKET)
+ zlog_info ("%s/%d filtered by distribute in",
+ inet6_ntop (&p->prefix), p->prefixlen);
+ return -1;
+ }
+ }
+ }
+ if (dist->prefix[DISTRIBUTE_IN])
+ {
+ plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_IN]);
+
+ if (plist)
+ {
+ if (prefix_list_apply (plist,
+ (struct prefix *) p) == PREFIX_DENY)
+ {
+ if (IS_RIPNG_DEBUG_PACKET)
+ zlog_info ("%s/%d filtered by prefix-list in",
+ inet6_ntop (&p->prefix), p->prefixlen);
+ return -1;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+int
+ripng_outgoing_filter (struct prefix_ipv6 *p, struct ripng_interface *ri)
+{
+ struct distribute *dist;
+ struct access_list *alist;
+ struct prefix_list *plist;
+
+ if (ri->list[RIPNG_FILTER_OUT])
+ {
+ if (access_list_apply (ri->list[RIPNG_FILTER_OUT],
+ (struct prefix *) p) == FILTER_DENY)
+ {
+ if (IS_RIPNG_DEBUG_PACKET)
+ zlog_info ("%s/%d is filtered by distribute out",
+ inet6_ntop (&p->prefix), p->prefixlen);
+ return -1;
+ }
+ }
+ if (ri->prefix[RIPNG_FILTER_OUT])
+ {
+ if (prefix_list_apply (ri->prefix[RIPNG_FILTER_OUT],
+ (struct prefix *) p) == PREFIX_DENY)
+ {
+ if (IS_RIPNG_DEBUG_PACKET)
+ zlog_info ("%s/%d is filtered by prefix-list out",
+ inet6_ntop (&p->prefix), p->prefixlen);
+ return -1;
+ }
+ }
+
+ /* All interface filter check. */
+ dist = distribute_lookup (NULL);
+ if (dist)
+ {
+ if (dist->list[DISTRIBUTE_OUT])
+ {
+ alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_OUT]);
+
+ if (alist)
+ {
+ if (access_list_apply (alist,
+ (struct prefix *) p) == FILTER_DENY)
+ {
+ if (IS_RIPNG_DEBUG_PACKET)
+ zlog_info ("%s/%d filtered by distribute out",
+ inet6_ntop (&p->prefix), p->prefixlen);
+ return -1;
+ }
+ }
+ }
+ if (dist->prefix[DISTRIBUTE_OUT])
+ {
+ plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_OUT]);
+
+ if (plist)
+ {
+ if (prefix_list_apply (plist,
+ (struct prefix *) p) == PREFIX_DENY)
+ {
+ if (IS_RIPNG_DEBUG_PACKET)
+ zlog_info ("%s/%d filtered by prefix-list out",
+ inet6_ntop (&p->prefix), p->prefixlen);
+ return -1;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
/* Process RIPng route according to RFC2080. */
void
ripng_route_process (struct rte *rte, struct sockaddr_in6 *from,
struct ripng_nexthop *ripng_nexthop,
struct interface *ifp)
{
+ int ret;
struct prefix_ipv6 p;
struct route_node *rp;
struct ripng_info *rinfo;
@@ -508,26 +654,9 @@ ripng_route_process (struct rte *rte, struct sockaddr_in6 *from,
/* Apply input filters. */
ri = ifp->info;
- if (ri->list[RIPNG_FILTER_IN])
- {
- if (access_list_apply (ri->list[RIPNG_FILTER_IN], &p) == FILTER_DENY)
- {
- if (IS_RIPNG_DEBUG_PACKET)
- zlog_info ("RIPng %s/%d is filtered by distribute in",
- inet6_ntop (&p.prefix), p.prefixlen);
- return;
- }
- }
- if (ri->prefix[RIPNG_FILTER_IN])
- {
- if (prefix_list_apply (ri->prefix[RIPNG_FILTER_IN], &p) == PREFIX_DENY)
- {
- if (IS_RIPNG_DEBUG_PACKET)
- zlog_info ("RIPng %s/%d is filtered by prefix-list in",
- inet6_ntop (&p.prefix), p.prefixlen);
- return;
- }
- }
+ ret = ripng_incoming_filter (&p, ri);
+ if (ret < 0)
+ return;
/* Modify entry. */
if (ri->routemap[RIPNG_FILTER_IN])
@@ -536,7 +665,17 @@ ripng_route_process (struct rte *rte, struct sockaddr_in6 *from,
struct ripng_info newinfo;
memset (&newinfo, 0, sizeof (struct ripng_info));
+ newinfo.type = ZEBRA_ROUTE_RIPNG;
+ newinfo.sub_type = RIPNG_ROUTE_RTE;
+ if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS)
+ newinfo.nexthop = ripng_nexthop->address;
+ else
+ newinfo.nexthop = from->sin6_addr;
+ newinfo.from = from->sin6_addr;
+ newinfo.ifindex = ifp->ifindex;
newinfo.metric = rte->metric;
+ newinfo.metric_out = rte->metric; /* XXX */
+ newinfo.tag = ntohs(rte->tag); /* XXX */
ret = route_map_apply (ri->routemap[RIPNG_FILTER_IN],
(struct prefix *)&p, RMAP_RIPNG, &newinfo);
@@ -549,9 +688,45 @@ ripng_route_process (struct rte *rte, struct sockaddr_in6 *from,
return;
}
- rte->metric = newinfo.metric;
+ /* Get back the object */
+ if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS) {
+ if (! IPV6_ADDR_SAME(&newinfo.nexthop, &ripng_nexthop->address) ) {
+ /* the nexthop get changed by the routemap */
+ if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop))
+ ripng_nexthop->address = newinfo.nexthop;
+ else
+ ripng_nexthop->address = in6addr_any;
+ }
+ } else {
+ if (! IPV6_ADDR_SAME(&newinfo.nexthop, &from->sin6_addr) ) {
+ /* the nexthop get changed by the routemap */
+ if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop)) {
+ ripng_nexthop->flag = RIPNG_NEXTHOP_ADDRESS;
+ ripng_nexthop->address = newinfo.nexthop;
+ }
+ }
+ }
+ 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
+ * (RFC2453 Sec. 3.9.2)
+ **/
+
+ /* Zebra ripngd can handle offset-list in. */
+ ret = ripng_offset_list_apply_in (&p, ifp, &rte->metric);
+
+ /* If offset-list does not modify the metric use interface's
+ * one. */
+ if (! ret)
+ rte->metric += ifp->metric;
+
+ if (rte->metric > RIPNG_METRIC_INFINITY)
+ rte->metric = RIPNG_METRIC_INFINITY;
+
/* Set nexthop pointer. */
if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS)
nexthop = &ripng_nexthop->address;
@@ -561,6 +736,23 @@ ripng_route_process (struct rte *rte, struct sockaddr_in6 *from,
/* Lookup RIPng routing table. */
rp = route_node_get (ripng->table, (struct prefix *) &p);
+ /* Sanity check */
+ rinfo = rp->info;
+ if (rinfo)
+ {
+ /* Redistributed route check. */
+ if (rinfo->type != ZEBRA_ROUTE_RIPNG
+ && rinfo->metric != RIPNG_METRIC_INFINITY)
+ return;
+
+ /* Local static route. */
+ if (rinfo->type == ZEBRA_ROUTE_RIPNG
+ && ((rinfo->sub_type == RIPNG_ROUTE_STATIC) ||
+ (rinfo->sub_type == RIPNG_ROUTE_DEFAULT))
+ && rinfo->metric != RIPNG_METRIC_INFINITY)
+ return;
+ }
+
if (rp->info == NULL)
{
/* Now, check to see whether there is already an explicit route
@@ -638,17 +830,45 @@ ripng_route_process (struct rte *rte, struct sockaddr_in6 *from,
oldmetric = rinfo->metric;
rinfo->metric = rte->metric;
rinfo->tag = ntohs (rte->tag);
+ IPV6_ADDR_COPY (&rinfo->from, &from->sin6_addr);
+ rinfo->ifindex = ifp->ifindex;
- if (! IN6_ARE_ADDR_EQUAL (&rinfo->nexthop, nexthop))
+ /* Should a new route to this network be established
+ while the garbage-collection timer is running, the
+ new route will replace the one that is about to be
+ deleted. In this case the garbage-collection timer
+ must be cleared. */
+
+ if (oldmetric == RIPNG_METRIC_INFINITY &&
+ rinfo->metric < RIPNG_METRIC_INFINITY)
+ {
+ rinfo->type = ZEBRA_ROUTE_RIPNG;
+ rinfo->sub_type = RIPNG_ROUTE_RTE;
+
+ RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
+
+ if (! IPV6_ADDR_SAME (&rinfo->nexthop, nexthop))
+ IPV6_ADDR_COPY (&rinfo->nexthop, nexthop);
+
+ ripng_zebra_ipv6_add (&p, nexthop, ifp->ifindex);
+ rinfo->flags |= RIPNG_RTF_FIB;
+
+ /* The aggregation counter needs to be updated because
+ the prefixes, which are into the gc, have been
+ removed from the aggregator (see ripng_timout). */
+ ripng_aggregate_increment (rp, rinfo);
+ }
+
+ /* Update nexthop and/or metric value. */
+ if (oldmetric != RIPNG_METRIC_INFINITY)
{
ripng_zebra_ipv6_delete (&p, &rinfo->nexthop, rinfo->ifindex);
ripng_zebra_ipv6_add (&p, nexthop, ifp->ifindex);
rinfo->flags |= RIPNG_RTF_FIB;
- IPV6_ADDR_COPY (&rinfo->nexthop, nexthop);
+ if (! IPV6_ADDR_SAME (&rinfo->nexthop, nexthop))
+ IPV6_ADDR_COPY (&rinfo->nexthop, nexthop);
}
- IPV6_ADDR_COPY (&rinfo->from, &from->sin6_addr);
- rinfo->ifindex = ifp->ifindex;
/* - Set the route change flag and signal the output process
to trigger an update. */
@@ -675,6 +895,12 @@ ripng_route_process (struct rte *rte, struct sockaddr_in6 *from,
/* - The metric for the route is set to 16
(infinity). This causes the route to be removed
from service.*/
+ ripng_zebra_ipv6_delete (&p, &rinfo->nexthop, rinfo->ifindex);
+ rinfo->flags &= ~RIPNG_RTF_FIB;
+
+ /* Aggregate count decrement. */
+ ripng_aggregate_decrement (rp, rinfo);
+
/* - The route change flag is to indicate that this
entry has been changed. */
/* - The output process is signalled to trigger a
@@ -686,13 +912,6 @@ ripng_route_process (struct rte *rte, struct sockaddr_in6 *from,
{
/* otherwise, re-initialize the timeout. */
ripng_timeout_update (rinfo);
-
- /* Should a new route to this network be established
- while the garbage-collection timer is running, the
- new route will replace the one that is about to be
- deleted. In this case the garbage-collection timer
- must be cleared. */
- RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
}
}
/* Unlock tempolary lock of the route. */
@@ -703,7 +922,7 @@ ripng_route_process (struct rte *rte, struct sockaddr_in6 *from,
/* Add redistributed route to RIPng table. */
void
ripng_redistribute_add (int type, int sub_type, struct prefix_ipv6 *p,
- unsigned int ifindex)
+ unsigned int ifindex, struct in6_addr *nexthop)
{
struct route_node *rp;
struct ripng_info *rinfo;
@@ -713,30 +932,89 @@ ripng_redistribute_add (int type, int sub_type, struct prefix_ipv6 *p,
return;
if (IN6_IS_ADDR_LOOPBACK (&p->prefix))
return;
+#if defined (MUSICA) || defined (LINUX)
+ /* XXX As long as the RIPng redistribution is applied to all the connected
+ * routes, one needs to filter the ::/96 prefixes.
+ * However it could be a wanted case, it will be removed soon.
+ */
+ if ((IN6_IS_ADDR_V4COMPAT(&p->prefix)) ||
+ (IN6_IS_ADDR_UNSPECIFIED (&p->prefix) && (p->prefixlen == 96)))
+ return;
+#endif /* MUSICA or LINUX */
rp = route_node_get (ripng->table, (struct prefix *) p);
rinfo = rp->info;
if (rinfo)
{
+ if (rinfo->type == ZEBRA_ROUTE_CONNECT
+ && rinfo->sub_type == RIPNG_ROUTE_INTERFACE
+ && rinfo->metric != RIPNG_METRIC_INFINITY) {
+ route_unlock_node (rp);
+ return;
+ }
+
+ /* Manually configured RIPng route check.
+ * They have the precedence on all the other entries.
+ **/
+ if (rinfo->type == ZEBRA_ROUTE_RIPNG
+ && ((rinfo->sub_type == RIPNG_ROUTE_STATIC) ||
+ (rinfo->sub_type == RIPNG_ROUTE_DEFAULT)) ) {
+ if (type != ZEBRA_ROUTE_RIPNG || ((sub_type != RIPNG_ROUTE_STATIC) &&
+ (sub_type != RIPNG_ROUTE_DEFAULT))) {
+ route_unlock_node (rp);
+ return;
+ }
+ }
+
RIPNG_TIMER_OFF (rinfo->t_timeout);
RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
+
+ /* Tells the other daemons about the deletion of
+ * this RIPng route
+ **/
+ if (ripng_route_rte (rinfo))
+ ripng_zebra_ipv6_delete ((struct prefix_ipv6 *)&rp->p, &rinfo->nexthop,
+ rinfo->metric);
+
+ rp->info = NULL;
+ ripng_info_free (rinfo);
+
route_unlock_node (rp);
+
}
- else
- {
- rinfo = ripng_info_new ();
- ripng_aggregate_increment (rp, rinfo);
- }
+
+ rinfo = ripng_info_new ();
rinfo->type = type;
rinfo->sub_type = sub_type;
rinfo->ifindex = ifindex;
rinfo->metric = 1;
- rinfo->flags |= RIPNG_RTF_FIB;
-
rinfo->rp = rp;
+
+ if (nexthop && IN6_IS_ADDR_LINKLOCAL(nexthop))
+ rinfo->nexthop = *nexthop;
+
+ rinfo->flags |= RIPNG_RTF_FIB;
rp->info = rinfo;
+
+ /* Aggregate check. */
+ ripng_aggregate_increment (rp, rinfo);
+
+ rinfo->flags |= RIPNG_RTF_CHANGED;
+
+ if (IS_RIPNG_DEBUG_EVENT) {
+ if (!nexthop)
+ zlog_info ("Redistribute new prefix %s/%d on the interface %s",
+ inet6_ntop(&p->prefix), p->prefixlen,
+ ifindex2ifname(ifindex));
+ else
+ zlog_info ("Redistribute new prefix %s/%d with nexthop %s on the interface %s",
+ inet6_ntop(&p->prefix), p->prefixlen, inet6_ntop(nexthop),
+ ifindex2ifname(ifindex));
+ }
+
+ ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
}
/* Delete redistributed route to RIPng table. */
@@ -751,6 +1029,15 @@ ripng_redistribute_delete (int type, int sub_type, struct prefix_ipv6 *p,
return;
if (IN6_IS_ADDR_LOOPBACK (&p->prefix))
return;
+#if defined (MUSICA) || defined (LINUX)
+ /* XXX As long as the RIPng redistribution is applied to all the connected
+ * routes, one needs to filter the ::/96 prefixes.
+ * However it could be a wanted case, it will be removed soon.
+ */
+ if ((IN6_IS_ADDR_V4COMPAT(&p->prefix)) ||
+ (IN6_IS_ADDR_UNSPECIFIED (&p->prefix) && (p->prefixlen == 96)))
+ return;
+#endif /* MUSICA or LINUX */
rp = route_node_lookup (ripng->table, (struct prefix *) p);
@@ -763,18 +1050,24 @@ ripng_redistribute_delete (int type, int sub_type, struct prefix_ipv6 *p,
&& rinfo->sub_type == sub_type
&& rinfo->ifindex == ifindex)
{
- rp->info = NULL;
-
+ /* Perform poisoned reverse. */
+ rinfo->metric = RIPNG_METRIC_INFINITY;
+ RIPNG_TIMER_ON (rinfo->t_garbage_collect,
+ ripng_garbage_collect, ripng->garbage_time);
RIPNG_TIMER_OFF (rinfo->t_timeout);
- RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
+
+ /* Aggregate count decrement. */
+ ripng_aggregate_decrement (rp, rinfo);
+
+ rinfo->flags |= RIPNG_RTF_CHANGED;
- ripng_info_free (rinfo);
+ if (IS_RIPNG_DEBUG_EVENT)
+ zlog_info ("Poisone %s/%d on the interface %s with an infinity metric [delete]",
+ inet6_ntop(&p->prefix), p->prefixlen,
+ ifindex2ifname(ifindex));
- route_unlock_node (rp);
+ ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
}
-
- /* For unlock route_node_lookup (). */
- route_unlock_node (rp);
}
}
@@ -785,19 +1078,35 @@ ripng_redistribute_withdraw (int type)
struct route_node *rp;
struct ripng_info *rinfo;
+ if (!ripng)
+ return;
+
for (rp = route_top (ripng->table); rp; rp = route_next (rp))
if ((rinfo = rp->info) != NULL)
{
- if (rinfo->type == type)
+ if ((rinfo->type == type)
+ && (rinfo->sub_type != RIPNG_ROUTE_INTERFACE))
{
- rp->info = NULL;
-
+ /* Perform poisoned reverse. */
+ rinfo->metric = RIPNG_METRIC_INFINITY;
+ RIPNG_TIMER_ON (rinfo->t_garbage_collect,
+ ripng_garbage_collect, ripng->garbage_time);
RIPNG_TIMER_OFF (rinfo->t_timeout);
- RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
- ripng_info_free (rinfo);
+ /* Aggregate count decrement. */
+ ripng_aggregate_decrement (rp, rinfo);
+
+ rinfo->flags |= RIPNG_RTF_CHANGED;
+
+ if (IS_RIPNG_DEBUG_EVENT) {
+ struct prefix_ipv6 *p = (struct prefix_ipv6 *) &rp->p;
- route_unlock_node (rp);
+ zlog_info ("Poisone %s/%d on the interface %s [withdraw]",
+ inet6_ntop(&p->prefix), p->prefixlen,
+ ifindex2ifname(rinfo->ifindex));
+ }
+
+ ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
}
}
}
@@ -818,6 +1127,7 @@ ripng_response_process (struct ripng_packet *packet, int size,
{
zlog_warn ("RIPng packet comes from non RIPng port %d from %s",
ntohs (from->sin6_port), inet6_ntop (&from->sin6_addr));
+ ripng_peer_bad_packet (from);
return;
}
@@ -828,6 +1138,7 @@ ripng_response_process (struct ripng_packet *packet, int size,
{
zlog_warn ("RIPng packet comes from non link local address %s",
inet6_ntop (&from->sin6_addr));
+ ripng_peer_bad_packet (from);
return;
}
@@ -840,6 +1151,7 @@ ripng_response_process (struct ripng_packet *packet, int size,
{
zlog_warn ("RIPng packet comes from my own link local address %s",
inet6_ntop (&from->sin6_addr));
+ ripng_peer_bad_packet (from);
return;
}
@@ -851,9 +1163,13 @@ ripng_response_process (struct ripng_packet *packet, int size,
{
zlog_warn ("RIPng packet comes with non 255 hop count %d from %s",
hoplimit, inet6_ntop (&from->sin6_addr));
+ ripng_peer_bad_packet (from);
return;
}
+ /* Update RIPng peer. */
+ ripng_peer_update (from, packet->version);
+
/* Reset nexthop. */
memset (&nexthop, 0, sizeof (struct ripng_nexthop));
nexthop.flag = RIPNG_NEXTHOP_UNSPEC;
@@ -881,18 +1197,21 @@ ripng_response_process (struct ripng_packet *packet, int size,
{
zlog_warn ("Destination prefix is a multicast address %s/%d [%d]",
inet6_ntop (&rte->addr), rte->prefixlen, rte->metric);
+ ripng_peer_bad_route (from);
continue;
}
if (IN6_IS_ADDR_LINKLOCAL (&rte->addr))
{
zlog_warn ("Destination prefix is a link-local address %s/%d [%d]",
inet6_ntop (&rte->addr), rte->prefixlen, rte->metric);
+ ripng_peer_bad_route (from);
continue;
}
if (IN6_IS_ADDR_LOOPBACK (&rte->addr))
{
zlog_warn ("Destination prefix is a loopback address %s/%d [%d]",
inet6_ntop (&rte->addr), rte->prefixlen, rte->metric);
+ ripng_peer_bad_route (from);
continue;
}
@@ -903,6 +1222,7 @@ ripng_response_process (struct ripng_packet *packet, int size,
zlog_warn ("Invalid prefix length %s/%d from %s%%%s",
inet6_ntop (&rte->addr), rte->prefixlen,
inet6_ntop (&from->sin6_addr), ifp->name);
+ ripng_peer_bad_route (from);
continue;
}
@@ -911,13 +1231,13 @@ ripng_response_process (struct ripng_packet *packet, int size,
{
zlog_warn ("Invalid metric %d from %s%%%s", rte->metric,
inet6_ntop (&from->sin6_addr), ifp->name);
+ ripng_peer_bad_route (from);
continue;
}
- /* Metric calculation. */
- rte->metric += ifp->metric;
- if (rte->metric > RIPNG_METRIC_INFINITY)
- rte->metric = RIPNG_METRIC_INFINITY;
+ /* Vincent: XXX Should we compute the direclty reachable nexthop
+ * for our RIPng network ?
+ **/
/* Routing table updates. */
ripng_route_process (rte, from, &nexthop, ifp);
@@ -936,6 +1256,10 @@ ripng_request_process (struct ripng_packet *packet,int size,
struct ripng_info *rinfo;
struct ripng_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)
@@ -945,6 +1269,9 @@ ripng_request_process (struct ripng_packet *packet,int size,
if (ri->passive)
return;
+ /* RIPng peer update. */
+ ripng_peer_update (from, packet->version);
+
lim = ((caddr_t) packet) + size;
rte = packet->rte;
@@ -965,7 +1292,7 @@ ripng_request_process (struct ripng_packet *packet,int size,
rte->metric == RIPNG_METRIC_INFINITY)
{
/* All route with split horizon */
- ripng_output_process (ifp, from, ripng_all_route, ripng_split_horizon);
+ ripng_output_process (ifp, from, ripng_all_route);
}
else
{
@@ -1044,6 +1371,7 @@ ripng_read (struct thread *thread)
{
zlog_warn ("RIPng invalid packet size %d from %s", len,
inet6_ntop (&from.sin6_addr));
+ ripng_peer_bad_packet (&from);
return 0;
}
@@ -1072,6 +1400,7 @@ ripng_read (struct thread *thread)
{
zlog_warn ("RIPng packet version %d doesn't fit to my version %d",
packet->version, ripng->version);
+ ripng_peer_bad_packet (&from);
return 0;
}
@@ -1086,6 +1415,7 @@ ripng_read (struct thread *thread)
break;
default:
zlog_warn ("Invalid RIPng command %d", packet->command);
+ ripng_peer_bad_packet (&from);
break;
}
return 0;
@@ -1148,7 +1478,7 @@ ripng_update (struct thread *t)
}
#endif /* RIPNG_ADVANCED */
- ripng_output_process (ifp, NULL, ripng_all_route, ripng_split_horizon);
+ ripng_output_process (ifp, NULL, ripng_all_route);
}
/* Triggered updates may be suppressed if a regular update is due by
@@ -1221,8 +1551,7 @@ ripng_triggered_update (struct thread *t)
if (ri->passive)
continue;
- ripng_output_process (ifp, NULL, ripng_changed_route,
- ripng_split_horizon);
+ ripng_output_process (ifp, NULL, ripng_changed_route);
}
/* Once all of the triggered updates have been generated, the route
@@ -1245,7 +1574,7 @@ ripng_triggered_update (struct thread *t)
the routing table entry in the stream. */
int
ripng_write_rte (int num, struct stream *s, struct prefix_ipv6 *p,
- u_int16_t tag, u_char metric)
+ struct in6_addr *nexthop, u_int16_t tag, u_char metric)
{
/* RIPng packet header. */
if (num == 0)
@@ -1256,9 +1585,15 @@ ripng_write_rte (int num, struct stream *s, struct prefix_ipv6 *p,
}
/* Write routing table entry. */
- stream_write (s, (caddr_t) &p->prefix, sizeof (struct in6_addr));
+ if (!nexthop)
+ stream_write (s, (caddr_t) &p->prefix, sizeof (struct in6_addr));
+ else
+ stream_write (s, (caddr_t) nexthop, sizeof (struct in6_addr));
stream_putw (s, tag);
- stream_putc (s, p->prefixlen);
+ if (p)
+ stream_putc (s, p->prefixlen);
+ else
+ stream_putc (s, 0);
stream_putc (s, metric);
return ++num;
@@ -1267,56 +1602,53 @@ ripng_write_rte (int num, struct stream *s, struct prefix_ipv6 *p,
/* Send RESPONSE message to specified destination. */
void
ripng_output_process (struct interface *ifp, struct sockaddr_in6 *to,
- int route_type, int split_horizon)
+ int route_type)
{
int ret;
- struct stream *s;
struct route_node *rp;
struct ripng_info *rinfo;
struct ripng_interface *ri;
struct ripng_aggregate *aggregate;
struct prefix_ipv6 *p;
- int num;
- int mtu;
- int rtemax;
- u_char metric;
- u_char metric_set;
-
- if (IS_RIPNG_DEBUG_EVENT)
- zlog_info ("RIPng update routes on interface %s", ifp->name);
-
- /* Output stream get from ripng structre. XXX this should be
- interface structure. */
- s = ripng->obuf;
-
- /* Reset stream and RTE counter. */
- stream_reset (s);
- num = 0;
-
- mtu = ifp->mtu;
- if (mtu < 0)
- mtu = IFMINMTU;
+ struct list * ripng_rte_list;
- rtemax = (min (mtu, RIPNG_MAX_PACKET_SIZE) -
- IPV6_HDRLEN -
- sizeof (struct udphdr) -
- sizeof (struct ripng_packet) +
- sizeof (struct rte)) / sizeof (struct rte);
+ if (IS_RIPNG_DEBUG_EVENT) {
+ if (to)
+ zlog_info ("RIPng update routes to neighbor %s",
+ inet6_ntop(&to->sin6_addr));
+ else
+ zlog_info ("RIPng update routes on interface %s", ifp->name);
+ }
-#ifdef DEBUG
- zlog_info ("DEBUG RIPng: ifmtu is %d", ifp->mtu);
- zlog_info ("DEBUG RIPng: rtemax is %d", rtemax);
-#endif /* DEBUG */
-
/* Get RIPng interface. */
ri = ifp->info;
-
+
+ ripng_rte_list = ripng_rte_new();
+
for (rp = route_top (ripng->table); rp; rp = route_next (rp))
{
if ((rinfo = rp->info) != NULL && rinfo->suppress == 0)
{
+ /* If no route-map are applied, the RTE will be these following
+ * informations.
+ */
p = (struct prefix_ipv6 *) &rp->p;
- metric = rinfo->metric;
+ rinfo->metric_out = rinfo->metric;
+ rinfo->tag_out = rinfo->tag;
+ memset(&rinfo->nexthop_out, 0, sizeof(rinfo->nexthop_out));
+ /* In order to avoid some local loops,
+ * if the RIPng 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.
+ */
+ if (rinfo->ifindex == ifp->ifindex)
+ rinfo->nexthop_out = rinfo->nexthop;
+
+ /* Apply output filters. */
+ ret = ripng_outgoing_filter (p, ri);
+ if (ret < 0)
+ continue;
/* Changed route only output. */
if (route_type == ripng_changed_route &&
@@ -1324,164 +1656,130 @@ ripng_output_process (struct interface *ifp, struct sockaddr_in6 *to,
continue;
/* Split horizon. */
- if (split_horizon == ripng_split_horizon &&
- rinfo->ifindex == ifp->ifindex)
- continue;
-
- /* Apply output filters.*/
- if (ri->list[RIPNG_FILTER_OUT])
- {
- if (access_list_apply (ri->list[RIPNG_FILTER_OUT],
- (struct prefix *) p) == FILTER_DENY)
- {
- if (IS_RIPNG_DEBUG_PACKET)
- zlog_info ("RIPng %s/%d is filtered by distribute out",
- inet6_ntop (&p->prefix), p->prefixlen);
- continue;
- }
- }
- if (ri->prefix[RIPNG_FILTER_OUT])
- {
- if (prefix_list_apply (ri->prefix[RIPNG_FILTER_OUT],
- (struct prefix *) p) == PREFIX_DENY)
- {
- if (IS_RIPNG_DEBUG_PACKET)
- zlog_info ("RIPng %s/%d is filtered by prefix-list out",
- inet6_ntop (&p->prefix), p->prefixlen);
- continue;
- }
- }
+ if (ri->split_horizon == RIPNG_SPLIT_HORIZON)
+ {
+ /* We perform split horizon for RIPng routes. */
+ if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
+ rinfo->ifindex == ifp->ifindex)
+ continue;
+ }
/* Preparation for route-map. */
- metric_set = 0;
+ rinfo->metric_set = 0;
+ /* nexthop_out,
+ * metric_out
+ * and tag_out are already initialized.
+ */
- /* Route-map */
+ /* Interface route-map */
if (ri->routemap[RIPNG_FILTER_OUT])
{
int ret;
- struct ripng_info newinfo;
-
- memset (&newinfo, 0, sizeof (struct ripng_info));
- newinfo.metric = metric;
ret = route_map_apply (ri->routemap[RIPNG_FILTER_OUT],
(struct prefix *) p, RMAP_RIPNG,
- &newinfo);
+ rinfo);
if (ret == RMAP_DENYMATCH)
{
if (IS_RIPNG_DEBUG_PACKET)
zlog_info ("RIPng %s/%d is filtered by route-map out",
inet6_ntop (&p->prefix), p->prefixlen);
- return;
+ continue;
}
- metric = newinfo.metric;
- metric_set = newinfo.metric_set;
}
- /* When the interface route-map does not set metric */
- if (! metric_set)
+ /* Redistribute route-map. */
+ if (ripng->route_map[rinfo->type].name)
{
- /* and the redistribute route-map is set. */
- if (ripng->route_map[rinfo->type].name)
+ int ret;
+
+ ret = route_map_apply (ripng->route_map[rinfo->type].map,
+ (struct prefix *) p, RMAP_RIPNG,
+ &rinfo);
+
+ if (ret == RMAP_DENYMATCH)
{
- int ret;
- struct ripng_info newinfo;
-
- memset (&newinfo, 0, sizeof (struct ripng_info));
- newinfo.metric = metric;
-
- ret = route_map_apply (ripng->route_map[rinfo->type].map,
- (struct prefix *) p, RMAP_RIPNG,
- &newinfo);
-
- if (ret == RMAP_DENYMATCH)
- {
- if (IS_RIPNG_DEBUG_PACKET)
- zlog_info ("RIPng %s/%d is filtered by route-map",
- inet6_ntop (&p->prefix), p->prefixlen);
- continue;
- }
-
- metric = newinfo.metric;
- metric_set = newinfo.metric_set;
+ if (IS_RIPNG_DEBUG_PACKET)
+ zlog_info ("RIPng %s/%d is filtered by route-map",
+ inet6_ntop (&p->prefix), p->prefixlen);
+ continue;
}
+ }
- /* When the redistribute route-map does not set metric. */
- if (! metric_set)
+ /* When the route-map does not set metric. */
+ if (! rinfo->metric_set)
+ {
+ /* If the redistribute metric is set. */
+ if (ripng->route_map[rinfo->type].metric_config
+ && rinfo->metric != RIPNG_METRIC_INFINITY)
+ {
+ rinfo->metric_out = ripng->route_map[rinfo->type].metric;
+ }
+ else
{
- /* If the redistribute metric is set. */
- if (ripng->route_map[rinfo->type].metric_config
+ /* If the route is not connected or localy generated
+ one, use default-metric value */
+ if (rinfo->type != ZEBRA_ROUTE_RIPNG
+ && rinfo->type != ZEBRA_ROUTE_CONNECT
&& rinfo->metric != RIPNG_METRIC_INFINITY)
- {
- metric = ripng->route_map[rinfo->type].metric;
- }
- else
- {
- /* If the route is not connected or localy generated
- one, use default-metric value */
- if (rinfo->type != ZEBRA_ROUTE_RIPNG
- && rinfo->type != ZEBRA_ROUTE_CONNECT
- && rinfo->metric != RIPNG_METRIC_INFINITY)
- metric = ripng->default_metric;
- }
+ rinfo->metric_out = ripng->default_metric;
}
}
- /* Write RTE to the stream. */
- num = ripng_write_rte (num, s, p, rinfo->tag, metric);
- if (num == rtemax)
- {
- ret = ripng_send_packet (STREAM_DATA (s), stream_get_endp (s),
- to, ifp);
-
- if (ret >= 0 && IS_RIPNG_DEBUG_SEND)
- ripng_packet_dump ((struct ripng_packet *)STREAM_DATA (s),
- stream_get_endp(s), "SEND");
- num = 0;
- stream_reset (s);
- }
+ /* Apply offset-list */
+ if (rinfo->metric_out != RIPNG_METRIC_INFINITY)
+ ripng_offset_list_apply_out (p, ifp, &rinfo->metric_out);
+
+ if (rinfo->metric_out > RIPNG_METRIC_INFINITY)
+ rinfo->metric_out = RIPNG_METRIC_INFINITY;
+
+ /* Perform split-horizon with poisoned reverse
+ * for RIPng routes.
+ **/
+ if (ri->split_horizon == RIPNG_SPLIT_HORIZON_POISONED_REVERSE) {
+ if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
+ rinfo->ifindex == ifp->ifindex)
+ rinfo->metric_out = RIPNG_METRIC_INFINITY;
+ }
+
+ /* Add RTE to the list */
+ ripng_rte_add(ripng_rte_list, p, rinfo, NULL);
}
+
+ /* Process the aggregated RTE entry */
if ((aggregate = rp->aggregate) != NULL &&
aggregate->count > 0 &&
aggregate->suppress == 0)
{
+ /* If no route-map are applied, the RTE will be these following
+ * informations.
+ */
p = (struct prefix_ipv6 *) &rp->p;
- metric = aggregate->metric;
+ aggregate->metric_set = 0;
+ aggregate->metric_out = aggregate->metric;
+ aggregate->tag_out = aggregate->tag;
+ memset(&aggregate->nexthop_out, 0, sizeof(aggregate->nexthop_out));
/* Apply output filters.*/
- if (ri->list[RIPNG_FILTER_OUT])
- {
- if (access_list_apply (ri->list[RIPNG_FILTER_OUT],
- (struct prefix *) p) == FILTER_DENY)
- {
- if (IS_RIPNG_DEBUG_PACKET)
- zlog_info ("RIPng %s/%d is filtered by distribute out",
- inet6_ntop (&p->prefix), p->prefixlen);
- continue;
- }
- }
- if (ri->prefix[RIPNG_FILTER_OUT])
- {
- if (prefix_list_apply (ri->prefix[RIPNG_FILTER_OUT],
- (struct prefix *) p) == PREFIX_DENY)
- {
- if (IS_RIPNG_DEBUG_PACKET)
- zlog_info ("RIPng %s/%d is filtered by prefix-list out",
- inet6_ntop (&p->prefix), p->prefixlen);
- continue;
- }
- }
+ ret = ripng_outgoing_filter (p, ri);
+ if (ret < 0)
+ continue;
- /* Route-map */
+ /* Interface route-map */
if (ri->routemap[RIPNG_FILTER_OUT])
{
int ret;
struct ripng_info newinfo;
+ /* let's cast the aggregate structure to ripng_info */
memset (&newinfo, 0, sizeof (struct ripng_info));
- newinfo.metric = metric;
+ /* the nexthop is :: */
+ newinfo.metric = aggregate->metric;
+ newinfo.metric_out = aggregate->metric_out;
+ newinfo.tag = aggregate->tag;
+ newinfo.tag_out = aggregate->tag_out;
ret = route_map_apply (ri->routemap[RIPNG_FILTER_OUT],
(struct prefix *) p, RMAP_RIPNG,
@@ -1492,45 +1790,40 @@ ripng_output_process (struct interface *ifp, struct sockaddr_in6 *to,
if (IS_RIPNG_DEBUG_PACKET)
zlog_info ("RIPng %s/%d is filtered by route-map out",
inet6_ntop (&p->prefix), p->prefixlen);
- return;
+ continue;
}
- metric = newinfo.metric;
+ aggregate->metric_out = newinfo.metric_out;
+ aggregate->tag_out = newinfo.tag_out;
+ if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop_out))
+ aggregate->nexthop_out = newinfo.nexthop_out;
}
+ /* There is no redistribute routemap for the aggregated RTE */
+
/* Changed route only output. */
+ /* XXX, vincent, in order to increase time convergence,
+ * it should be announced if a child has changed.
+ */
if (route_type == ripng_changed_route)
continue;
- /* Write RTE to the stream. */
- num = ripng_write_rte (num, s, p, aggregate->tag, metric);
- if (num == rtemax)
- {
- ret = ripng_send_packet (STREAM_DATA (s), stream_get_endp (s),
- to, ifp);
-
- if (ret >= 0 && IS_RIPNG_DEBUG_SEND)
- ripng_packet_dump ((struct ripng_packet *)STREAM_DATA (s),
- stream_get_endp(s), "SEND");
- num = 0;
- stream_reset (s);
- }
+ /* Apply offset-list */
+ if (aggregate->metric_out != RIPNG_METRIC_INFINITY)
+ ripng_offset_list_apply_out (p, ifp, &aggregate->metric_out);
+
+ if (aggregate->metric_out > RIPNG_METRIC_INFINITY)
+ aggregate->metric_out = RIPNG_METRIC_INFINITY;
+
+ /* Add RTE to the list */
+ ripng_rte_add(ripng_rte_list, p, NULL, aggregate);
}
}
-
- /* If unwritten RTE exist, flush it. */
- if (num != 0)
- {
- ret = ripng_send_packet (STREAM_DATA (s), stream_get_endp (s),
- to, ifp);
- if (ret >= 0 && IS_RIPNG_DEBUG_SEND)
- ripng_packet_dump ((struct ripng_packet *)STREAM_DATA (s),
- stream_get_endp (s), "SEND");
- num = 0;
- stream_reset (s);
- }
+ /* Flush the list */
+ ripng_rte_send(ripng_rte_list, ifp, to);
+ ripng_rte_free(ripng_rte_list);
}
/* Create new RIPng instance and set it to global variable. */
@@ -1541,7 +1834,7 @@ ripng_create ()
assert (ripng == NULL);
/* Allocaste RIPng instance. */
- ripng = XMALLOC (0, sizeof (struct ripng));
+ ripng = XMALLOC (MTYPE_RIPNG, sizeof (struct ripng));
memset (ripng, 0, sizeof (struct ripng));
/* Default version and timer values. */
@@ -1572,13 +1865,21 @@ ripng_create ()
return 0;
}
-/* Sned RIPng request to the interface. */
+/* Send RIPng request to the interface. */
int
ripng_request (struct interface *ifp)
{
struct rte *rte;
struct ripng_packet ripng_packet;
+ /* In default ripd doesn't send RIP_REQUEST to the loopback interface. */
+ if (if_is_loopback(ifp))
+ return 0;
+
+ /* If interface is down, don't send RIP packet. */
+ if (! if_is_up (ifp))
+ return 0;
+
if (IS_RIPNG_DEBUG_EVENT)
zlog_info ("RIPng send request to %s", ifp->name);
@@ -1592,22 +1893,6 @@ ripng_request (struct interface *ifp)
NULL, ifp);
}
-/* Clean up installed RIPng routes. */
-void
-ripng_terminate ()
-{
- struct route_node *rp;
- struct ripng_info *rinfo;
-
- for (rp = route_top (ripng->table); rp; rp = route_next (rp))
- if ((rinfo = rp->info) != NULL)
- {
- if (rinfo->type == ZEBRA_ROUTE_RIPNG &&
- rinfo->sub_type == RIPNG_ROUTE_RTE)
- ripng_zebra_ipv6_delete ((struct prefix_ipv6 *)&rp->p,
- &rinfo->nexthop, rinfo->ifindex);
- }
-}
int
ripng_update_jitter (int time)
@@ -1618,7 +1903,6 @@ ripng_update_jitter (int time)
void
ripng_event (enum ripng_event event, int sock)
{
- int ripng_request_all (struct thread *);
int jitter = 0;
switch (event)
@@ -1672,14 +1956,6 @@ struct
{ ZEBRA_ROUTE_BGP, "B", "bgp", 70},
};
-/* For messages. */
-struct message ripng_route_info[] =
-{
- { RIPNG_ROUTE_RTE, " "},
- { RIPNG_ROUTE_STATIC, "S"},
- { RIPNG_ROUTE_AGGREGATE, "a"}
-};
-
/* Print out routes update time. */
static void
ripng_vty_out_uptime (struct vty *vty, struct ripng_info *rinfo)
@@ -1709,6 +1985,40 @@ ripng_vty_out_uptime (struct vty *vty, struct ripng_info *rinfo)
}
}
+char *
+ripng_route_subtype_print (struct ripng_info *rinfo)
+{
+ static char str[3];
+ memset(str, 0, 3);
+
+ if (rinfo->suppress)
+ strcat(str, "S");
+
+ switch (rinfo->sub_type)
+ {
+ case RIPNG_ROUTE_RTE:
+ strcat(str, "n");
+ break;
+ case RIPNG_ROUTE_STATIC:
+ strcat(str, "s");
+ break;
+ case RIPNG_ROUTE_DEFAULT:
+ strcat(str, "d");
+ break;
+ case RIPNG_ROUTE_REDISTRIBUTE:
+ strcat(str, "r");
+ break;
+ case RIPNG_ROUTE_INTERFACE:
+ strcat(str, "i");
+ break;
+ default:
+ strcat(str, "?");
+ break;
+ }
+
+ return str;
+}
+
DEFUN (show_ipv6_ripng,
show_ipv6_ripng_cmd,
"show ipv6 ripng",
@@ -1722,10 +2032,16 @@ DEFUN (show_ipv6_ripng,
struct prefix_ipv6 *p;
int len;
+ if (! ripng)
+ return CMD_SUCCESS;
+
/* Header of display. */
- vty_out (vty, "%sCodes: R - RIPng%s%s"
- " Network "
- "Next Hop If Met Tag Time%s", VTY_NEWLINE,
+ vty_out (vty, "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP%s"
+ "Sub-codes:%s"
+ " (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s"
+ " (i) - interface, (a/S) - aggregated/Suppressed%s%s"
+ " Network Next Hop Via Metric Tag Time%s",
+ VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
for (rp = route_top (ripng->table); rp; rp = route_next (rp))
@@ -1735,20 +2051,18 @@ DEFUN (show_ipv6_ripng,
p = (struct prefix_ipv6 *) &rp->p;
#ifdef DEBUG
- len = vty_out (vty, "Ra %d/%d %s/%d ",
+ len = vty_out (vty, "R(a) %d/%d %s/%d ",
aggregate->count, aggregate->suppress,
inet6_ntop (&p->prefix), p->prefixlen);
#else
- len = vty_out (vty, "Ra %s/%d ",
+ len = vty_out (vty, "R(a) %s/%d ",
inet6_ntop (&p->prefix), p->prefixlen);
#endif /* DEBUG */
+ vty_out (vty, "%s", VTY_NEWLINE);
+ vty_out (vty, "%*s", 18, " ");
- len = 37 - len;
- if (len > 0)
- vty_out (vty, "%*s", len, " ");
-
- vty_out (vty, "%*s", 26, " ");
- vty_out (vty, "%4d %3d%s", aggregate->metric,
+ vty_out (vty, "%*s", 28, " ");
+ vty_out (vty, "self %2d %3d%s", aggregate->metric,
aggregate->tag,
VTY_NEWLINE);
}
@@ -1758,32 +2072,54 @@ DEFUN (show_ipv6_ripng,
p = (struct prefix_ipv6 *) &rp->p;
#ifdef DEBUG
- len = vty_out (vty, "%s%s 0/%d %s/%d ",
+ len = vty_out (vty, "%s(%s) 0/%d %s/%d ",
route_info[rinfo->type].str,
- rinfo->suppress ? "s" : " ",
+ ripng_route_subtype_print(rinfo),
rinfo->suppress,
inet6_ntop (&p->prefix), p->prefixlen);
#else
- len = vty_out (vty, "%s%s %s/%d ",
+ len = vty_out (vty, "%s(%s) %s/%d ",
route_info[rinfo->type].str,
- rinfo->suppress ? "s" : " ",
+ ripng_route_subtype_print(rinfo),
inet6_ntop (&p->prefix), p->prefixlen);
#endif /* DEBUG */
- len = 37 - len;
+ vty_out (vty, "%s", VTY_NEWLINE);
+ vty_out (vty, "%*s", 18, " ");
+ len = vty_out (vty, "%s", inet6_ntop (&rinfo->nexthop));
+
+ len = 28 - len;
if (len > 0)
- vty_out (vty, "%*s", len, " ");
+ len = vty_out (vty, "%*s", len, " ");
- len = vty_out (vty, "%s", inet6_ntop (&rinfo->nexthop));
+ /* from */
+ if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
+ (rinfo->sub_type == RIPNG_ROUTE_RTE))
+ {
+ len = vty_out (vty, "%s", ifindex2ifname(rinfo->ifindex));
+ } else if (rinfo->metric == RIPNG_METRIC_INFINITY)
+ {
+ len = vty_out (vty, "kill");
+ } else
+ len = vty_out (vty, "self");
- len = 26 - len;
+ len = 9 - len;
if (len > 0)
vty_out (vty, "%*s", len, " ");
- vty_out (vty, "%2d %2d %3d ",
- rinfo->ifindex, rinfo->metric, rinfo->tag);
+ vty_out (vty, " %2d %3d ",
+ rinfo->metric, rinfo->tag);
- if (rinfo->sub_type == RIPNG_ROUTE_RTE)
+ /* time */
+ if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
+ (rinfo->sub_type == RIPNG_ROUTE_RTE))
+ {
+ /* RTE from remote RIP routers */
ripng_vty_out_uptime (vty, rinfo);
+ } else if (rinfo->metric == RIPNG_METRIC_INFINITY)
+ {
+ /* poisonous reversed routes (gc) */
+ ripng_vty_out_uptime (vty, rinfo);
+ }
vty_out (vty, "%s", VTY_NEWLINE);
}
@@ -1792,6 +2128,88 @@ DEFUN (show_ipv6_ripng,
return CMD_SUCCESS;
}
+/* Return next event time. */
+static int
+ripng_next_thread_timer (struct thread *thread)
+{
+ struct timeval timer_now;
+
+ gettimeofday (&timer_now, NULL);
+
+ return thread->u.sands.tv_sec - timer_now.tv_sec;
+}
+
+DEFUN (show_ipv6_ripng_status,
+ show_ipv6_ripng_status_cmd,
+ "show ipv6 ripng status",
+ SHOW_STR
+ IP_STR
+ "Show RIPng routes\n"
+ "IPv6 routing protocol process parameters and statistics\n")
+{
+ listnode node;
+ int ripng_network_write (struct vty *, int);
+ void ripng_redistribute_write (struct vty *, int);
+
+ if (! ripng)
+ return CMD_SUCCESS;
+
+ vty_out (vty, "Routing Protocol is \"RIPng\"%s", VTY_NEWLINE);
+ vty_out (vty, " Sending updates every %ld seconds with +/-50%%,",
+ ripng->update_time);
+ vty_out (vty, " next due in %d seconds%s",
+ ripng_next_thread_timer (ripng->t_update),
+ VTY_NEWLINE);
+ vty_out (vty, " Timeout after %ld seconds,", ripng->timeout_time);
+ vty_out (vty, " garbage collect after %ld seconds%s", ripng->garbage_time,
+ VTY_NEWLINE);
+
+ /* Filtering status show. */
+ config_show_distribute (vty);
+
+ /* Default metric information. */
+ vty_out (vty, " Default redistribution metric is %d%s",
+ ripng->default_metric, VTY_NEWLINE);
+
+ /* Redistribute information. */
+ vty_out (vty, " Redistributing:");
+ ripng_redistribute_write (vty, 0);
+ vty_out (vty, "%s", VTY_NEWLINE);
+
+ vty_out (vty, " Default version control: send version %d,", ripng->version);
+ vty_out (vty, " receive version %d %s", ripng->version,
+ VTY_NEWLINE);
+
+ vty_out (vty, " Interface Send Recv%s", VTY_NEWLINE);
+
+ for (node = listhead (iflist); node; node = nextnode (node))
+ {
+ struct ripng_interface *ri;
+ struct interface *ifp;
+
+ ifp = getdata (node);
+ ri = ifp->info;
+
+ if (ri->enable_network || ri->enable_interface)
+ {
+
+ vty_out (vty, " %-17s%-3d %-3d%s", ifp->name,
+ ripng->version,
+ ripng->version,
+ VTY_NEWLINE);
+ }
+ }
+
+ vty_out (vty, " Routing for Networks:%s", VTY_NEWLINE);
+ ripng_network_write (vty, 0);
+
+ vty_out (vty, " Routing Information Sources:%s", VTY_NEWLINE);
+ vty_out (vty, " Gateway BadPackets BadRoutes Distance Last Update%s", VTY_NEWLINE);
+ ripng_peer_display (vty);
+
+ return CMD_SUCCESS;
+}
+
DEFUN (router_ripng,
router_ripng_cmd,
"router ripng",
@@ -1817,6 +2235,18 @@ DEFUN (router_ripng,
return CMD_SUCCESS;
}
+DEFUN (no_router_ripng,
+ no_router_ripng_cmd,
+ "no router ripng",
+ NO_STR
+ "Enable a routing process\n"
+ "Make RIPng instance command\n")
+{
+ if(ripng)
+ ripng_clean();
+ return CMD_SUCCESS;
+}
+
DEFUN (ripng_route,
ripng_route_cmd,
"route IPV6ADDR",
@@ -1844,7 +2274,7 @@ DEFUN (ripng_route,
}
rp->info = (void *)1;
- ripng_redistribute_add (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0);
+ ripng_redistribute_add (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0, NULL);
return CMD_SUCCESS;
}
@@ -2150,6 +2580,15 @@ DEFUN (no_ripng_timers,
return CMD_SUCCESS;
}
+ALIAS (no_ripng_timers,
+ no_ripng_timers_val_cmd,
+ "no timers basic <0-65535> <0-65535> <0-65535>",
+ NO_STR
+ "RIPng timers setup\n"
+ "Basic timer\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")
DEFUN (show_ipv6_protocols, show_ipv6_protocols_cmd,
"show ipv6 protocols",
@@ -2186,10 +2625,12 @@ DEFUN (ripng_default_information_originate,
{
struct prefix_ipv6 p;
- ripng->default_information = 1;
+ if (! ripng ->default_information) {
+ ripng->default_information = 1;
- str2prefix_ipv6 ("::/0", &p);
- ripng_redistribute_add (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0);
+ str2prefix_ipv6 ("::/0", &p);
+ ripng_redistribute_add (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_DEFAULT, &p, 0, NULL);
+ }
return CMD_SUCCESS;
}
@@ -2203,10 +2644,12 @@ DEFUN (no_ripng_default_information_originate,
{
struct prefix_ipv6 p;
- ripng->default_information = 0;
+ if (ripng->default_information) {
+ ripng->default_information = 0;
- str2prefix_ipv6 ("::/0", &p);
- ripng_redistribute_delete (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0);
+ str2prefix_ipv6 ("::/0", &p);
+ ripng_redistribute_delete (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_DEFAULT, &p, 0);
+ }
return CMD_SUCCESS;
}
@@ -2215,8 +2658,8 @@ DEFUN (no_ripng_default_information_originate,
int
ripng_config_write (struct vty *vty)
{
- int ripng_network_write (struct vty *);
- void ripng_redistribute_write (struct vty *);
+ int ripng_network_write (struct vty *, int);
+ void ripng_redistribute_write (struct vty *, int);
int write = 0;
struct route_node *rp;
@@ -2229,14 +2672,17 @@ ripng_config_write (struct vty *vty)
if (ripng->default_information)
vty_out (vty, " default-information originate%s", VTY_NEWLINE);
- ripng_network_write (vty);
+ ripng_network_write (vty, 1);
/* RIPng default metric configuration */
if (ripng->default_metric != RIPNG_DEFAULT_METRIC_DEFAULT)
vty_out (vty, " default-metric %d%s",
ripng->default_metric, VTY_NEWLINE);
- ripng_redistribute_write (vty);
+ ripng_redistribute_write (vty, 1);
+
+ /* RIP offset-list configuration. */
+ config_write_ripng_offset_list (vty);
/* RIPng aggregate routes. */
for (rp = route_top (ripng->aggregate); rp; rp = route_next (rp))
@@ -2355,6 +2801,7 @@ ripng_distribute_update (struct distribute *dist)
else
ri->prefix[RIPNG_FILTER_OUT] = NULL;
}
+
void
ripng_distribute_update_interface (struct interface *ifp)
{
@@ -2378,6 +2825,103 @@ ripng_distribute_update_all ()
ripng_distribute_update_interface (ifp);
}
}
+
+/* delete all the added ripng routes. */
+void
+ripng_clean()
+{
+ int i;
+ struct route_node *rp;
+ struct ripng_info *rinfo;
+
+ if (ripng) {
+ /* Clear RIPng routes */
+ for (rp = route_top (ripng->table); rp; rp = route_next (rp)) {
+ if ((rinfo = rp->info) != NULL) {
+ if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
+ (rinfo->sub_type == RIPNG_ROUTE_RTE))
+ ripng_zebra_ipv6_delete ((struct prefix_ipv6 *)&rp->p,
+ &rinfo->nexthop, rinfo->metric);
+
+ RIPNG_TIMER_OFF (rinfo->t_timeout);
+ RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
+
+ rp->info = NULL;
+ route_unlock_node (rp);
+
+ ripng_info_free(rinfo);
+ }
+ }
+
+ /* Cancel the RIPng timers */
+ RIPNG_TIMER_OFF (ripng->t_update);
+ RIPNG_TIMER_OFF (ripng->t_triggered_update);
+ RIPNG_TIMER_OFF (ripng->t_triggered_interval);
+
+ /* Cancel the read thread */
+ if (ripng->t_read) {
+ thread_cancel (ripng->t_read);
+ ripng->t_read = NULL;
+ }
+
+ /* Close the RIPng socket */
+ if (ripng->sock >= 0) {
+ close(ripng->sock);
+ ripng->sock = -1;
+ }
+
+ /* Static RIPng route configuration. */
+ for (rp = route_top (ripng->route); rp; rp = route_next (rp))
+ if (rp->info) {
+ rp->info = NULL;
+ route_unlock_node (rp);
+ }
+
+ /* RIPng aggregated prefixes */
+ for (rp = route_top (ripng->aggregate); rp; rp = route_next (rp))
+ if (rp->info) {
+ rp->info = NULL;
+ route_unlock_node (rp);
+ }
+
+ for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+ if (ripng->route_map[i].name)
+ free (ripng->route_map[i].name);
+
+ XFREE (MTYPE_ROUTE_TABLE, ripng->table);
+ XFREE (MTYPE_ROUTE_TABLE, ripng->route);
+ XFREE (MTYPE_ROUTE_TABLE, ripng->aggregate);
+
+ XFREE (MTYPE_RIPNG, ripng);
+ ripng = NULL;
+ } /* if (ripng) */
+
+ ripng_clean_network();
+ ripng_passive_interface_clean ();
+ ripng_offset_clean ();
+ ripng_interface_clean ();
+ ripng_redistribute_clean ();
+}
+
+/* Reset all values to the default settings. */
+void
+ripng_reset ()
+{
+ /* Call ripd related reset functions. */
+ ripng_debug_reset ();
+ ripng_route_map_reset ();
+
+ /* Call library reset functions. */
+ vty_reset ();
+ access_list_reset ();
+ prefix_list_reset ();
+
+ distribute_list_reset ();
+
+ ripng_interface_reset ();
+
+ ripng_zclient_reset ();
+}
void
ripng_if_rmap_update (struct if_rmap *if_rmap)
@@ -2468,10 +3012,13 @@ ripng_init ()
/* Install ripng commands. */
install_element (VIEW_NODE, &show_ipv6_ripng_cmd);
+ install_element (VIEW_NODE, &show_ipv6_ripng_status_cmd);
install_element (ENABLE_NODE, &show_ipv6_ripng_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_ripng_status_cmd);
install_element (CONFIG_NODE, &router_ripng_cmd);
+ install_element (CONFIG_NODE, &no_router_ripng_cmd);
install_default (RIPNG_NODE);
install_element (RIPNG_NODE, &ripng_route_cmd);
@@ -2485,6 +3032,7 @@ ripng_init ()
install_element (RIPNG_NODE, &ripng_timers_cmd);
install_element (RIPNG_NODE, &no_ripng_timers_cmd);
+ install_element (RIPNG_NODE, &no_ripng_timers_val_cmd);
#if 0
install_element (RIPNG_NODE, &ripng_update_timer_cmd);
install_element (RIPNG_NODE, &no_ripng_update_timer_cmd);
@@ -2517,6 +3065,8 @@ ripng_init ()
/* Route-map for interface. */
ripng_route_map_init ();
+ ripng_offset_init ();
+
route_map_add_hook (ripng_routemap_update);
route_map_delete_hook (ripng_routemap_update);
diff --git a/ripngd/ripngd.h b/ripngd/ripngd.h
index 816deb64..609e6925 100644
--- a/ripngd/ripngd.h
+++ b/ripngd/ripngd.h
@@ -44,13 +44,19 @@
#define RIPNG_TIMEOUT_TIMER_DEFAULT 180
#define RIPNG_GARBAGE_TIMER_DEFAULT 120
+/* RIPng peer timeout value. */
+#define RIPNG_PEER_TIMER_DEFAULT 180
+
/* Default config file name. */
#define RIPNG_DEFAULT_CONFIG "ripngd.conf"
/* RIPng route types. */
#define RIPNG_ROUTE_RTE 0
#define RIPNG_ROUTE_STATIC 1
-#define RIPNG_ROUTE_AGGREGATE 2
+#define RIPNG_ROUTE_DEFAULT 2
+#define RIPNG_ROUTE_REDISTRIBUTE 3
+#define RIPNG_ROUTE_INTERFACE 4
+#define RIPNG_ROUTE_AGGREGATE 5
/* Interface send/receive configuration. */
#define RIPNG_SEND_UNSPEC 0
@@ -58,12 +64,6 @@
#define RIPNG_RECEIVE_UNSPEC 0
#define RIPNG_RECEIVE_OFF 1
-/* Split horizon definitions. */
-#define RIPNG_SPLIT_HORIZON_UNSPEC 0
-#define RIPNG_SPLIT_HORIZON_NONE 1
-#define RIPNG_SPLIT_HORIZON 2
-#define RIPNG_SPLIT_HORIZON_POISONED 3
-
/* RIP default route's accept/announce methods. */
#define RIPNG_DEFAULT_ADVERTISE_UNSPEC 0
#define RIPNG_DEFAULT_ADVERTISE_NONE 1
@@ -139,10 +139,12 @@ struct ripng
/* Routing table entry. */
struct rte
{
- struct in6_addr addr;
- u_short tag;
- u_char prefixlen;
- u_char metric;
+ struct in6_addr addr; /* RIPng destination prefix */
+ u_short tag; /* RIPng tag */
+ u_char prefixlen; /* Length of the RIPng prefix */
+ u_char metric; /* Metric of the RIPng route */
+ /* The nexthop is stored by the structure
+ * ripng_nexthop within ripngd.c */
};
/* RIPNG send packet. */
@@ -189,11 +191,16 @@ struct ripng_info
struct thread *t_garbage_collect;
/* Route-map features - this variables can be changed. */
+ struct in6_addr nexthop_out;
u_char metric_set;
+ u_char metric_out;
+ u_short tag_out;
struct route_node *rp;
};
+#ifdef notyet
+#if 0
/* RIPng tag structure. */
struct ripng_tag
{
@@ -218,6 +225,14 @@ struct ripng_tag
/* Poison reverse. */
u_char poison_reverse;
};
+#endif /* 0 */
+#endif /* not yet */
+
+typedef enum {
+ RIPNG_NO_SPLIT_HORIZON = 0,
+ RIPNG_SPLIT_HORIZON,
+ RIPNG_SPLIT_HORIZON_POISONED_REVERSE
+} split_horizon_policy_t;
/* RIPng specific interface configuration. */
struct ripng_interface
@@ -229,6 +244,10 @@ struct ripng_interface
/* RIPng is running on this interface. */
int running;
+ /* Split horizon flag. */
+ split_horizon_policy_t split_horizon;
+ split_horizon_policy_t split_horizon_default;
+
/* For filter type slot. */
#define RIPNG_FILTER_IN 0
#define RIPNG_FILTER_OUT 1
@@ -243,8 +262,12 @@ struct ripng_interface
/* Route-map. */
struct route_map *routemap[RIPNG_FILTER_MAX];
+#ifdef notyet
+#if 0
/* RIPng tag configuration. */
struct ripng_tag *rtag;
+#endif /* 0 */
+#endif /* notyet */
/* Default information originate. */
u_char default_originate;
@@ -259,6 +282,29 @@ struct ripng_interface
int passive;
};
+/* RIPng peer information. */
+struct ripng_peer
+{
+ /* Peer address. */
+ struct in6_addr addr;
+
+ /* Peer RIPng tag value. */
+ int domain;
+
+ /* Last update time. */
+ time_t uptime;
+
+ /* Peer RIP version. */
+ u_char version;
+
+ /* Statistics. */
+ int recv_badpackets;
+ int recv_badroutes;
+
+ /* Timeout thread. */
+ struct thread *t_timeout;
+};
+
/* All RIPng events. */
enum ripng_event
{
@@ -295,15 +341,42 @@ extern struct thread_master *master;
/* Prototypes. */
void ripng_init ();
+void ripng_reset ();
+void ripng_clean ();
+void ripng_clean_network ();
+void ripng_interface_clean ();
+void ripng_interface_reset ();
+void ripng_passive_interface_clean ();
void ripng_if_init ();
+void ripng_route_map_init ();
+void ripng_route_map_reset ();
void ripng_terminate ();
-void ripng_zclient_start ();
+ /* zclient_init() is done by ripng_zebra.c:zebra_init() */
void zebra_init ();
+void ripng_zclient_start ();
+void ripng_zclient_reset ();
+void ripng_offset_init ();
+
+int config_write_ripng_offset_list (struct vty *);
+
+void ripng_peer_init ();
+void ripng_peer_update (struct sockaddr_in6 *, u_char);
+void ripng_peer_bad_route (struct sockaddr_in6 *);
+void ripng_peer_bad_packet (struct sockaddr_in6 *);
+void ripng_peer_display (struct vty *);
+struct ripng_peer *ripng_peer_lookup (struct in6_addr *);
+struct ripng_peer *ripng_peer_lookup_next (struct in6_addr *);
+
+int ripng_offset_list_apply_in (struct prefix_ipv6 *, struct interface *, u_char *);
+int ripng_offset_list_apply_out (struct prefix_ipv6 *, struct interface *, u_char *);
+void ripng_offset_clean ();
+
struct ripng_info * ripng_info_new ();
void ripng_info_free (struct ripng_info *rinfo);
void ripng_event (enum ripng_event, int);
int ripng_request (struct interface *ifp);
-void ripng_redistribute_add (int, int, struct prefix_ipv6 *, unsigned int);
+void ripng_redistribute_add (int, int, struct prefix_ipv6 *, unsigned int,
+ struct in6_addr *);
void ripng_redistribute_delete (int, int, struct prefix_ipv6 *, unsigned int);
void ripng_redistribute_withdraw (int type);
@@ -312,6 +385,17 @@ void ripng_if_rmap_update_interface (struct interface *);
void ripng_zebra_ipv6_add (struct prefix_ipv6 *p, struct in6_addr *nexthop, unsigned int ifindex);
void ripng_zebra_ipv6_delete (struct prefix_ipv6 *p, struct in6_addr *nexthop, unsigned int ifindex);
-void ripng_route_map_init ();
+
+void ripng_redistribute_clean ();
+
+const char *inet6_ntop (struct in6_addr *p);
+
+int ripng_write_rte (int num, struct stream *s, struct prefix_ipv6 *p,
+ struct in6_addr *nexthop, u_int16_t tag, u_char metric);
+int ripng_send_packet (caddr_t buf, int bufsize, struct sockaddr_in6 *to,
+ struct interface *ifp);
+
+void ripng_packet_dump (struct ripng_packet *packet, int size, char *sndrcv);
+
#endif /* _ZEBRA_RIPNG_RIPNGD_H */