diff options
| -rw-r--r-- | lib/memory.c | 27 | ||||
| -rw-r--r-- | lib/memory.h | 9 | ||||
| -rw-r--r-- | ripngd/Makefile.am | 4 | ||||
| -rw-r--r-- | ripngd/ripng_debug.c | 3 | ||||
| -rw-r--r-- | ripngd/ripng_debug.h | 1 | ||||
| -rw-r--r-- | ripngd/ripng_interface.c | 548 | ||||
| -rw-r--r-- | ripngd/ripng_main.c | 30 | ||||
| -rw-r--r-- | ripngd/ripng_nexthop.c | 216 | ||||
| -rw-r--r-- | ripngd/ripng_nexthop.h | 62 | ||||
| -rw-r--r-- | ripngd/ripng_offset.c | 417 | ||||
| -rw-r--r-- | ripngd/ripng_peer.c | 220 | ||||
| -rw-r--r-- | ripngd/ripng_route.c | 1 | ||||
| -rw-r--r-- | ripngd/ripng_route.h | 6 | ||||
| -rw-r--r-- | ripngd/ripng_routemap.c | 619 | ||||
| -rw-r--r-- | ripngd/ripng_zebra.c | 711 | ||||
| -rw-r--r-- | ripngd/ripngd.c | 1200 | ||||
| -rw-r--r-- | ripngd/ripngd.h | 112 | 
17 files changed, 3147 insertions, 1039 deletions
diff --git a/lib/memory.c b/lib/memory.c index bf142dcf..93833113 100644 --- a/lib/memory.c +++ b/lib/memory.c @@ -255,6 +255,7 @@ struct memory_list memory_list_lib[] =    { MTYPE_ROUTE_MAP_INDEX,    "Route map index " },    { MTYPE_ROUTE_MAP_RULE,     "Route map rule  " },    { MTYPE_ROUTE_MAP_RULE_STR, "Route map rule str" }, +  { MTYPE_ROUTE_MAP_COMPILED, "Route map compiled" },    { MTYPE_DESC,               "Command desc    " },    { MTYPE_BUFFER,             "Buffer          " },    { MTYPE_BUFFER_DATA,        "Buffer data     " }, @@ -323,6 +324,17 @@ struct memory_list memory_list_rip[] =    { -1, NULL }  }; +struct memory_list memory_list_ripng[] = +{ +  { MTYPE_RIPNG,              "RIPng structure " }, +  { MTYPE_RIPNG_ROUTE,        "RIPng route info" }, +  { MTYPE_RIPNG_AGGREGATE,    "RIPng aggregate " }, +  { MTYPE_RIPNG_PEER,         "RIPng peer      " }, +  { MTYPE_RIPNG_OFFSET_LIST,  "RIPng offset lst" }, +  { MTYPE_RIPNG_RTE_DATA,     "RIPng rte data  " }, +  { -1, NULL } +}; +  struct memory_list memory_list_ospf[] =  {    { MTYPE_OSPF_TOP,           "OSPF top        " }, @@ -402,6 +414,8 @@ DEFUN (show_memory_all,    show_memory_vty (vty, memory_list_separator);    show_memory_vty (vty, memory_list_rip);    show_memory_vty (vty, memory_list_separator); +  show_memory_vty (vty, memory_list_ripng); +  show_memory_vty (vty, memory_list_separator);    show_memory_vty (vty, memory_list_ospf);    show_memory_vty (vty, memory_list_separator);    show_memory_vty (vty, memory_list_ospf6); @@ -439,6 +453,17 @@ DEFUN (show_memory_rip,    return CMD_SUCCESS;  } +DEFUN (show_memory_ripng, +       show_memory_ripng_cmd, +       "show memory ripng", +       SHOW_STR +       "Memory statistics\n" +       "RIPng memory\n") +{ +  show_memory_vty (vty, memory_list_ripng); +  return CMD_SUCCESS; +} +  DEFUN (show_memory_bgp,         show_memory_bgp_cmd,         "show memory bgp", @@ -479,6 +504,7 @@ memory_init ()    install_element (VIEW_NODE, &show_memory_all_cmd);    install_element (VIEW_NODE, &show_memory_lib_cmd);    install_element (VIEW_NODE, &show_memory_rip_cmd); +  install_element (VIEW_NODE, &show_memory_ripng_cmd);    install_element (VIEW_NODE, &show_memory_bgp_cmd);    install_element (VIEW_NODE, &show_memory_ospf_cmd);    install_element (VIEW_NODE, &show_memory_ospf6_cmd); @@ -487,6 +513,7 @@ memory_init ()    install_element (ENABLE_NODE, &show_memory_all_cmd);    install_element (ENABLE_NODE, &show_memory_lib_cmd);    install_element (ENABLE_NODE, &show_memory_rip_cmd); +  install_element (ENABLE_NODE, &show_memory_ripng_cmd);    install_element (ENABLE_NODE, &show_memory_bgp_cmd);    install_element (ENABLE_NODE, &show_memory_ospf_cmd);    install_element (ENABLE_NODE, &show_memory_ospf6_cmd); diff --git a/lib/memory.h b/lib/memory.h index 52e3bc11..a38cda3f 100644 --- a/lib/memory.h +++ b/lib/memory.h @@ -58,8 +58,6 @@ enum    MTYPE_HASH,    MTYPE_HASH_INDEX,    MTYPE_HASH_BACKET, -  MTYPE_RIPNG_ROUTE, -  MTYPE_RIPNG_AGGREGATE,    MTYPE_ROUTE_TABLE,    MTYPE_ROUTE_NODE,    MTYPE_ACCESS_LIST, @@ -179,6 +177,13 @@ enum    MTYPE_KEYCHAIN,    MTYPE_KEY, +  MTYPE_RIPNG, +  MTYPE_RIPNG_ROUTE, +  MTYPE_RIPNG_AGGREGATE, +  MTYPE_RIPNG_PEER, +  MTYPE_RIPNG_OFFSET_LIST, +  MTYPE_RIPNG_RTE_DATA, +    MTYPE_VTYSH_CONFIG,    MTYPE_VTYSH_CONFIG_LINE, 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 */  | 
