diff --git a/bgpd/bgp_advertise.c b/bgpd/bgp_advertise.c index de27513a42..da5ab94e97 100644 --- a/bgpd/bgp_advertise.c +++ b/bgpd/bgp_advertise.c @@ -26,6 +26,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "hash.h" #include "thread.h" #include "queue.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 4161d149fa..eca4441010 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -30,6 +30,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "stream.h" #include "jhash.h" #include "queue.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_aspath.h" diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index eefdd9e8ec..3cb52ef911 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -31,6 +31,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "jhash.h" #include "queue.h" #include "table.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_attr.h" @@ -1314,7 +1315,8 @@ bgp_attr_nexthop (struct bgp_attr_parser_args *args) gets ignored in any of these cases. */ nexthop_n = stream_get_ipv4 (peer->ibuf); nexthop_h = ntohl (nexthop_n); - if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h)) + if ((IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h)) + && !BGP_DEBUG (allow_martians, ALLOW_MARTIANS)) /* loopbacks may be used in testing */ { char buf[INET_ADDRSTRLEN]; inet_ntop (AF_INET, &nexthop_n, buf, INET_ADDRSTRLEN); @@ -1946,7 +1948,7 @@ bgp_attr_encap( } while (length >= 4) { - uint16_t subtype; + uint16_t subtype = 0; uint16_t sublength = 0; struct bgp_attr_encap_subtlv *tlv; diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 1117f6269d..0bf8c897de 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -99,6 +99,9 @@ struct attr_extra /* MP Nexthop length */ u_char mp_nexthop_len; + /* MP Nexthop preference */ + u_char mp_nexthop_prefer_global; + /* route tag */ u_short tag; @@ -128,7 +131,7 @@ struct attr struct in_addr nexthop; u_int32_t med; u_int32_t local_pref; - u_int32_t nh_ifindex; + ifindex_t nh_ifindex; /* Path origin attribute */ u_char origin; @@ -145,6 +148,7 @@ struct attr #define BATTR_RMAP_NEXTHOP_UNCHANGED (1 << 3) #define BATTR_RMAP_IPV6_GLOBAL_NHOP_CHANGED (1 << 4) #define BATTR_RMAP_IPV6_LL_NHOP_CHANGED (1 << 5) +#define BATTR_RMAP_IPV6_PREFER_GLOBAL_CHANGED (1 << 6) /* Router Reflector related structure. */ struct cluster_list @@ -274,6 +278,7 @@ bgp_rmap_nhop_changed(u_int32_t out_rmap_flags, u_int32_t in_rmap_flags) CHECK_FLAG(out_rmap_flags, BATTR_RMAP_NEXTHOP_UNCHANGED) || CHECK_FLAG(out_rmap_flags, BATTR_RMAP_IPV4_NHOP_CHANGED) || CHECK_FLAG(out_rmap_flags, BATTR_RMAP_IPV6_GLOBAL_NHOP_CHANGED) || + CHECK_FLAG(out_rmap_flags, BATTR_RMAP_IPV6_PREFER_GLOBAL_CHANGED) || CHECK_FLAG(out_rmap_flags, BATTR_RMAP_IPV6_LL_NHOP_CHANGED) || CHECK_FLAG(in_rmap_flags, BATTR_RMAP_NEXTHOP_UNCHANGED)) ? 1 : 0); } diff --git a/bgpd/bgp_bfd.c b/bgpd/bgp_bfd.c index b64fbee04d..ad221d922d 100644 --- a/bgpd/bgp_bfd.c +++ b/bgpd/bgp_bfd.c @@ -34,6 +34,8 @@ #include "vty.h" #include "bfd.h" #include "lib/json.h" +#include "filter.h" + #include "bgpd/bgpd.h" #include "bgp_fsm.h" #include "bgpd/bgp_bfd.h" @@ -71,7 +73,7 @@ bgp_bfd_peer_group2peer_copy(struct peer *conf, struct peer *peer) /* * bgp_bfd_is_peer_multihop - returns whether BFD peer is multi-hop or single hop. */ -static int +int bgp_bfd_is_peer_multihop(struct peer *peer) { struct bfd_info *bfd_info; @@ -711,7 +713,4 @@ bgp_bfd_init(void) install_element (BGP_NODE, &no_neighbor_bfd_cmd); install_element (BGP_NODE, &no_neighbor_bfd_val_cmd); install_element (BGP_NODE, &no_neighbor_bfd_type_cmd); - - /* Send the client registration */ - bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER); } diff --git a/bgpd/bgp_bfd.h b/bgpd/bgp_bfd.h index 4e554af696..e872637e3e 100644 --- a/bgpd/bgp_bfd.h +++ b/bgpd/bgp_bfd.h @@ -42,4 +42,7 @@ bgp_bfd_peer_config_write(struct vty *vty, struct peer *peer, char *addr); extern void bgp_bfd_show_info(struct vty *vty, struct peer *peer, u_char use_json, json_object *json_neigh); +extern int +bgp_bfd_is_peer_multihop(struct peer *peer); + #endif /* _QUAGGA_BGP_BFD_H */ diff --git a/bgpd/bgp_btoa.c b/bgpd/bgp_btoa.c index a6c16d8c2d..cd52c94b1f 100644 --- a/bgpd/bgp_btoa.c +++ b/bgpd/bgp_btoa.c @@ -27,6 +27,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "command.h" #include "memory.h" #include "privs.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_dump.h" @@ -143,7 +144,7 @@ main (int argc, char **argv) size_t len; int source_as; int dest_as; - int ifindex; + ifindex_t ifindex; int family; struct in_addr sip; struct in_addr dip; diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c index 4beae4391e..12c936b190 100644 --- a/bgpd/bgp_clist.c +++ b/bgpd/bgp_clist.c @@ -24,6 +24,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "prefix.h" #include "memory.h" #include "queue.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_community.h" diff --git a/bgpd/bgp_damp.c b/bgpd/bgp_damp.c index 2e2dc42ad1..f4a83d720b 100644 --- a/bgpd/bgp_damp.c +++ b/bgpd/bgp_damp.c @@ -27,6 +27,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "log.h" #include "thread.h" #include "queue.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_damp.h" diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index a3d420f691..dc0f539847 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -30,6 +30,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "sockunion.h" #include "memory.h" #include "queue.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_aspath.h" @@ -48,6 +49,7 @@ unsigned long conf_bgp_debug_keepalive; unsigned long conf_bgp_debug_update; unsigned long conf_bgp_debug_bestpath; unsigned long conf_bgp_debug_zebra; +unsigned long conf_bgp_debug_allow_martians; unsigned long conf_bgp_debug_nht; unsigned long conf_bgp_debug_update_groups; @@ -60,6 +62,7 @@ unsigned long term_bgp_debug_keepalive; unsigned long term_bgp_debug_update; unsigned long term_bgp_debug_bestpath; unsigned long term_bgp_debug_zebra; +unsigned long term_bgp_debug_allow_martians; unsigned long term_bgp_debug_nht; unsigned long term_bgp_debug_update_groups; @@ -1518,6 +1521,48 @@ DEFUN (no_debug_bgp_zebra_prefix, return CMD_SUCCESS; } +DEFUN (debug_bgp_allow_martians, + debug_bgp_allow_martians_cmd, + "debug bgp allow-martians", + DEBUG_STR + BGP_STR + "BGP allow martian next hops\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_ON (allow_martians, ALLOW_MARTIANS); + else + { + TERM_DEBUG_ON (allow_martians, ALLOW_MARTIANS); + vty_out (vty, "BGP allow_martian next hop debugging is on%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_allow_martians, + no_debug_bgp_allow_martians_cmd, + "no debug bgp allow-martians", + NO_STR + DEBUG_STR + BGP_STR + "BGP allow martian next hops\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_OFF (allow_martians, ALLOW_MARTIANS); + else + { + TERM_DEBUG_OFF (allow_martians, ALLOW_MARTIANS); + vty_out (vty, "BGP allow martian next hop debugging is off%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +ALIAS (no_debug_bgp_allow_martians, + undebug_bgp_allow_martians_cmd, + "undebug bgp allow-martians", + UNDEBUG_STR + BGP_STR + "BGP allow martian next hops\n") + /* debug bgp update-groups */ DEFUN (debug_bgp_update_groups, debug_bgp_update_groups_cmd, @@ -1580,6 +1625,7 @@ DEFUN (no_debug_bgp, TERM_DEBUG_OFF (as4, AS4_SEGMENT); TERM_DEBUG_OFF (neighbor_events, NEIGHBOR_EVENTS); TERM_DEBUG_OFF (zebra, ZEBRA); + TERM_DEBUG_OFF (allow_martians, ALLOW_MARTIANS); vty_out (vty, "All possible debugging has been turned off%s", VTY_NEWLINE); return CMD_SUCCESS; @@ -1634,6 +1680,8 @@ DEFUN (show_debugging_bgp, bgp_debug_list_print (vty, " BGP zebra debugging is on", bgp_debug_zebra_prefixes); + if (BGP_DEBUG (allow_martians, ALLOW_MARTIANS)) + vty_out (vty, " BGP allow martian next hop debugging is on%s", VTY_NEWLINE); vty_out (vty, "%s", VTY_NEWLINE); return CMD_SUCCESS; } @@ -1663,7 +1711,7 @@ bgp_config_write_debug (struct vty *vty) if (CONF_BGP_DEBUG (keepalive, KEEPALIVE)) { - write += bgp_debug_list_conf_print (vty, "debug bgp keepalive", + write += bgp_debug_list_conf_print (vty, "debug bgp keepalives", bgp_debug_keepalive_peers); } @@ -1717,6 +1765,12 @@ bgp_config_write_debug (struct vty *vty) } } + if (CONF_BGP_DEBUG (allow_martians, ALLOW_MARTIANS)) + { + vty_out (vty, "debug bgp allow-martians%s", VTY_NEWLINE); + write++; + } + return write; } @@ -1749,6 +1803,8 @@ bgp_debug_init (void) install_element (CONFIG_NODE, &debug_bgp_update_cmd); install_element (ENABLE_NODE, &debug_bgp_zebra_cmd); install_element (CONFIG_NODE, &debug_bgp_zebra_cmd); + install_element (ENABLE_NODE, &debug_bgp_allow_martians_cmd); + install_element (CONFIG_NODE, &debug_bgp_allow_martians_cmd); install_element (ENABLE_NODE, &debug_bgp_update_groups_cmd); install_element (CONFIG_NODE, &debug_bgp_update_groups_cmd); install_element (ENABLE_NODE, &debug_bgp_bestpath_prefix_cmd); @@ -1805,6 +1861,9 @@ bgp_debug_init (void) install_element (CONFIG_NODE, &no_debug_bgp_update_cmd); install_element (ENABLE_NODE, &no_debug_bgp_zebra_cmd); install_element (CONFIG_NODE, &no_debug_bgp_zebra_cmd); + install_element (ENABLE_NODE, &no_debug_bgp_allow_martians_cmd); + install_element (ENABLE_NODE, &undebug_bgp_allow_martians_cmd); + install_element (CONFIG_NODE, &no_debug_bgp_allow_martians_cmd); install_element (ENABLE_NODE, &no_debug_bgp_update_groups_cmd); install_element (CONFIG_NODE, &no_debug_bgp_update_groups_cmd); install_element (ENABLE_NODE, &no_debug_bgp_cmd); diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h index 8372c7e3f5..835d585735 100644 --- a/bgpd/bgp_debug.h +++ b/bgpd/bgp_debug.h @@ -66,6 +66,7 @@ extern unsigned long conf_bgp_debug_keepalive; extern unsigned long conf_bgp_debug_update; extern unsigned long conf_bgp_debug_bestpath; extern unsigned long conf_bgp_debug_zebra; +extern unsigned long conf_bgp_debug_allow_martians; extern unsigned long conf_bgp_debug_nht; extern unsigned long conf_bgp_debug_update_groups; @@ -76,6 +77,7 @@ extern unsigned long term_bgp_debug_keepalive; extern unsigned long term_bgp_debug_update; extern unsigned long term_bgp_debug_bestpath; extern unsigned long term_bgp_debug_zebra; +extern unsigned long term_bgp_debug_allow_martians; extern unsigned long term_bgp_debug_nht; extern unsigned long term_bgp_debug_update_groups; @@ -104,6 +106,7 @@ struct bgp_debug_filter #define BGP_DEBUG_UPDATE_OUT 0x02 #define BGP_DEBUG_UPDATE_PREFIX 0x04 #define BGP_DEBUG_ZEBRA 0x01 +#define BGP_DEBUG_ALLOW_MARTIANS 0x01 #define BGP_DEBUG_NHT 0x01 #define BGP_DEBUG_UPDATE_GROUPS 0x01 diff --git a/bgpd/bgp_dump.c b/bgpd/bgp_dump.c index ea292f5931..e219d5248e 100644 --- a/bgpd/bgp_dump.c +++ b/bgpd/bgp_dump.c @@ -29,9 +29,9 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "linklist.h" #include "queue.h" #include "memory.h" +#include "filter.h" #include "bgpd/bgp_table.h" - #include "bgpd/bgpd.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_attr.h" @@ -771,15 +771,41 @@ DEFUN (dump_bgp_all, DEFUN (no_dump_bgp_all, no_dump_bgp_all_cmd, - "no dump bgp (all|updates|routes-mrt) [PATH] [INTERVAL]", + "no dump bgp (all|all-et|updates|updates-et|routes-mrt) [PATH] [INTERVAL]", NO_STR "Stop dump packet\n" "Stop BGP packet dump\n" - "Stop dump process all/all-et\n" - "Stop dump process updates/updates-et\n" + "Stop dump process all\n" + "Stop dump process all-et\n" + "Stop dump process updates\n" + "Stop dump process updates-et\n" "Stop dump process route-mrt\n") { - return bgp_dump_unset (vty, &bgp_dump_all); + int bgp_dump_type = 0; + const struct bgp_dump_type_map *map = NULL; + struct bgp_dump *bgp_dump_struct = NULL; + + for (map = bgp_dump_type_map; map->str; map++) + if (strcmp(argv[0], map->str) == 0) + bgp_dump_type = map->type; + + switch (bgp_dump_type) + { + case BGP_DUMP_ALL: + case BGP_DUMP_ALL_ET: + bgp_dump_struct = &bgp_dump_all; + break; + case BGP_DUMP_UPDATES: + case BGP_DUMP_UPDATES_ET: + bgp_dump_struct = &bgp_dump_updates; + break; + case BGP_DUMP_ROUTES: + default: + bgp_dump_struct = &bgp_dump_routes; + break; + } + + return bgp_dump_unset (vty, bgp_dump_struct); } /* BGP node structure. */ diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index dc0137fd19..926e2650a2 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -25,6 +25,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "prefix.h" #include "command.h" #include "queue.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_ecommunity.h" @@ -769,7 +770,9 @@ ecommunity_match (const struct ecommunity *ecom1, /* Every community on com2 needs to be on com1 for this to match */ while (i < ecom1->size && j < ecom2->size) { - if (memcmp (ecom1->val + i, ecom2->val + j, ECOMMUNITY_SIZE) == 0) + if (memcmp (ecom1->val + i * ECOMMUNITY_SIZE, + ecom2->val + j * ECOMMUNITY_SIZE, + ECOMMUNITY_SIZE) == 0) j++; i++; } @@ -779,4 +782,3 @@ ecommunity_match (const struct ecommunity *ecom1, else return 0; } - diff --git a/bgpd/bgp_filter.c b/bgpd/bgp_filter.c index 693c639f75..33877e7258 100644 --- a/bgpd/bgp_filter.c +++ b/bgpd/bgp_filter.c @@ -25,6 +25,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "memory.h" #include "buffer.h" #include "queue.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_aspath.h" @@ -66,18 +67,12 @@ struct as_filter char *reg_str; }; -enum as_list_type -{ - ACCESS_TYPE_STRING, - ACCESS_TYPE_NUMBER -}; - /* AS path filter list. */ struct as_list { char *name; - enum as_list_type type; + enum access_type type; struct as_list *next; struct as_list *prev; diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 9da21fdffd..046767177b 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -32,6 +32,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "plist.h" #include "workqueue.h" #include "queue.h" +#include "filter.h" #include "lib/json.h" #include "bgpd/bgpd.h" @@ -1331,8 +1332,10 @@ bgp_start (struct peer *peer) if (bgp_debug_neighbor_events(peer)) zlog_debug ("%s [FSM] Waiting for NHT", peer->host); +#if !defined (HAVE_BGP_STANDALONE) BGP_EVENT_ADD(peer, TCP_connection_open_failed); return 0; +#endif } status = bgp_connect (peer); diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 1f2f7f86ce..5ef8154faf 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -68,6 +68,7 @@ static const struct option longopts[] = { "no_kernel", no_argument, NULL, 'n'}, { "user", required_argument, NULL, 'u'}, { "group", required_argument, NULL, 'g'}, + { "skip_runas", no_argument, NULL, 'S'}, { "version", no_argument, NULL, 'v'}, { "dryrun", no_argument, NULL, 'C'}, { "help", no_argument, NULL, 'h'}, @@ -163,6 +164,7 @@ redistribution between different routing protocols.\n\n\ -n, --no_kernel Do not install route to kernel.\n\ -u, --user User to run as\n\ -g, --group Group to run as\n\ +-S, --skip_runas Skip user and group run as\n\ -v, --version Print program version\n\ -C, --dryrun Check configuration for validity and exit\n\ -h, --help Display this help and exit\n\ @@ -200,9 +202,12 @@ sigint (void) zlog_notice ("Terminating on signal"); if (! retain_mode) - bgp_terminate (); + { + bgp_terminate (); + if (bgpd_privs.user) /* NULL if skip_runas flag set */ + zprivs_terminate (&bgpd_privs); + } - zprivs_terminate (&bgpd_privs); bgp_exit (0); exit (0); @@ -227,7 +232,6 @@ bgp_exit (int status) { struct bgp *bgp; struct listnode *node, *nnode; - extern struct zclient *zclient; /* it only makes sense for this to be called on a clean exit */ assert (status == 0); @@ -277,8 +281,8 @@ bgp_exit (int status) bgp_vrf_terminate (); cmd_terminate (); vty_terminate (); - if (zclient) - zclient_free (zclient); + + bgp_zebra_destroy(); if (bgp_nexthop_buf) stream_free (bgp_nexthop_buf); if (bgp_ifindices_buf) @@ -317,6 +321,7 @@ bgp_vrf_enable (vrf_id_t vrf_id, const char *name, void **info) { struct vrf *vrf; struct bgp *bgp; + vrf_id_t old_vrf_id; vrf = vrf_lookup (vrf_id); if (!vrf) // unexpected @@ -328,8 +333,13 @@ bgp_vrf_enable (vrf_id_t vrf_id, const char *name, void **info) bgp = bgp_lookup_by_name(name); if (bgp) { + old_vrf_id = bgp->vrf_id; /* We have instance configured, link to VRF and make it "up". */ bgp_vrf_link (bgp, vrf); + + /* Update any redistribute vrf bitmaps if the vrf_id changed */ + if (old_vrf_id != bgp->vrf_id) + bgp_update_redist_vrf_bitmaps(bgp, old_vrf_id); bgp_instance_up (bgp); } @@ -341,6 +351,7 @@ bgp_vrf_disable (vrf_id_t vrf_id, const char *name, void **info) { struct vrf *vrf; struct bgp *bgp; + vrf_id_t old_vrf_id; if (vrf_id == VRF_DEFAULT) return 0; @@ -355,8 +366,12 @@ bgp_vrf_disable (vrf_id_t vrf_id, const char *name, void **info) bgp = bgp_lookup_by_name(name); if (bgp) { + old_vrf_id = bgp->vrf_id; /* We have instance configured, unlink from VRF and make it "down". */ bgp_vrf_unlink (bgp, vrf); + /* Update any redistribute vrf bitmaps if the vrf_id changed */ + if (old_vrf_id != bgp->vrf_id) + bgp_update_redist_vrf_bitmaps(bgp, old_vrf_id); bgp_instance_down (bgp); } @@ -398,6 +413,7 @@ main (int argc, char **argv) char *progname; struct thread thread; int tmp_port; + int skip_runas = 0; /* Set umask before anything for security */ umask (0027); @@ -405,18 +421,13 @@ main (int argc, char **argv) /* Preserve name of myself. */ progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); - zlog_default = openzlog (progname, ZLOG_BGP, 0, - LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); - zprivs_init (&bgpd_privs); - zlog_set_file (NULL, LOG_DEFAULT_FILENAME, zlog_default->default_lvl); - /* BGP master init. */ bgp_master_init (); /* Command line argument treatment. */ while (1) { - opt = getopt_long (argc, argv, "df:i:z:hp:l:A:P:rnu:g:vC", longopts, 0); + opt = getopt_long (argc, argv, "df:i:z:hp:l:A:P:rnu:g:vCS", longopts, 0); if (opt == EOF) break; @@ -474,6 +485,9 @@ main (int argc, char **argv) case 'g': bgpd_privs.group = optarg; break; + case 'S': /* skip run as = override bgpd_privs */ + skip_runas = 1; + break; case 'v': print_version (progname); exit (0); @@ -490,6 +504,16 @@ main (int argc, char **argv) } } + zlog_default = openzlog (progname, ZLOG_BGP, 0, + LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); + + if (skip_runas) + memset (&bgpd_privs, 0, sizeof (bgpd_privs)); + zprivs_init (&bgpd_privs); + +#if defined(HAVE_CUMULUS) + zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl); +#endif /* Initializations. */ srandom (time (NULL)); diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index 8397177f8f..e7272cc0aa 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -29,6 +29,7 @@ #include "sockunion.h" #include "memory.h" #include "queue.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" @@ -467,6 +468,11 @@ bgp_info_mpath_update (struct bgp_node *rn, struct bgp_info *new_best, bgp_info_mpath_dequeue (old_best); } + if (debug) + zlog_debug("%s: starting mpath update, newbest %s num candidates %d old-mpath-count %d", + pfx_buf, new_best ? new_best->peer->host : "NONE", + listcount (mp_list), old_mpath_count); + /* * We perform an ordered walk through both lists in parallel. * The reason for the ordered walk is that if there are paths @@ -480,6 +486,8 @@ bgp_info_mpath_update (struct bgp_node *rn, struct bgp_info *new_best, */ while (mp_node || cur_mpath) { + struct bgp_info *tmp_info; + /* * We can bail out of this loop if all existing paths on the * multipath list have been visited (for cleanup purposes) and @@ -490,6 +498,12 @@ bgp_info_mpath_update (struct bgp_node *rn, struct bgp_info *new_best, mp_next_node = mp_node ? listnextnode (mp_node) : NULL; next_mpath = cur_mpath ? bgp_info_mpath_next (cur_mpath) : NULL; + tmp_info = mp_node ? listgetdata (mp_node) : NULL; + + if (debug) + zlog_debug("%s: comparing candidate %s with existing mpath %s", + pfx_buf, tmp_info ? tmp_info->peer->host : "NONE", + cur_mpath ? cur_mpath->peer->host : "NONE"); /* * If equal, the path was a multipath and is still a multipath. @@ -505,6 +519,12 @@ bgp_info_mpath_update (struct bgp_node *rn, struct bgp_info *new_best, bgp_info_mpath_enqueue (prev_mpath, cur_mpath); prev_mpath = cur_mpath; mpath_count++; + if (debug) + { + bgp_info_path_with_addpath_rx_str(cur_mpath, path_buf); + zlog_debug("%s: %s is still multipath, cur count %d", + pfx_buf, path_buf, mpath_count); + } } else { @@ -512,10 +532,11 @@ bgp_info_mpath_update (struct bgp_node *rn, struct bgp_info *new_best, if (debug) { bgp_info_path_with_addpath_rx_str(cur_mpath, path_buf); - zlog_debug ("%s remove mpath nexthop %s %s", pfx_buf, + zlog_debug ("%s: remove mpath %s nexthop %s, cur count %d", + pfx_buf, path_buf, inet_ntop (AF_INET, &cur_mpath->attr->nexthop, nh_buf[0], sizeof (nh_buf[0])), - path_buf); + mpath_count); } } mp_node = mp_next_node; @@ -538,10 +559,11 @@ bgp_info_mpath_update (struct bgp_node *rn, struct bgp_info *new_best, if (debug) { bgp_info_path_with_addpath_rx_str(cur_mpath, path_buf); - zlog_debug ("%s remove mpath nexthop %s %s", pfx_buf, + zlog_debug ("%s: remove mpath %s nexthop %s, cur count %d", + pfx_buf, path_buf, inet_ntop (AF_INET, &cur_mpath->attr->nexthop, nh_buf[0], sizeof (nh_buf[0])), - path_buf); + mpath_count); } cur_mpath = next_mpath; } @@ -574,10 +596,11 @@ bgp_info_mpath_update (struct bgp_node *rn, struct bgp_info *new_best, if (debug) { bgp_info_path_with_addpath_rx_str(new_mpath, path_buf); - zlog_debug ("%s add mpath nexthop %s %s", pfx_buf, + zlog_debug ("%s: add mpath %s nexthop %s, cur count %d", + pfx_buf, path_buf, inet_ntop (AF_INET, &new_mpath->attr->nexthop, nh_buf[0], sizeof (nh_buf[0])), - path_buf); + mpath_count); } } mp_node = mp_next_node; @@ -586,6 +609,10 @@ bgp_info_mpath_update (struct bgp_node *rn, struct bgp_info *new_best, if (new_best) { + if (debug) + zlog_debug("%s: New mpath count (incl newbest) %d mpath-change %s", + pfx_buf, mpath_count, mpath_changed ? "YES" : "NO"); + bgp_info_mpath_count_set (new_best, mpath_count-1); if (mpath_changed || (bgp_info_mpath_count (new_best) != old_mpath_count)) SET_FLAG (new_best->flags, BGP_INFO_MULTIPATH_CHG); diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 00f8221bcb..c22dbb05a9 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -26,6 +26,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "memory.h" #include "stream.h" #include "queue.h" +#include "filter.h" #include "lib/json.h" #include "bgpd/bgpd.h" @@ -481,7 +482,7 @@ show_adj_route_vpn (struct vty *vty, struct peer *peer, struct prefix_rd *prd, u { u_int16_t type; struct rd_as rd_as; - struct rd_ip rd_ip = { 0, { 0 }, 0}; + struct rd_ip rd_ip = {0}; u_char *pnt; pnt = rn->p.u.val; @@ -671,7 +672,7 @@ bgp_show_mpls_vpn (struct vty *vty, struct prefix_rd *prd, enum bgp_show_type ty { u_int16_t type; struct rd_as rd_as; - struct rd_ip rd_ip = { 0, { 0 }, 0}; + struct rd_ip rd_ip = {0}; u_char *pnt; pnt = rn->p.u.val; diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index 61972aabf1..a6e9b7de00 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -33,6 +33,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "network.h" #include "queue.h" #include "hash.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_open.h" @@ -62,7 +63,9 @@ bgp_md5_set_socket (int socket, union sockunion *su, const char *password) { int ret = -1; int en = ENOSYS; +#if HAVE_DECL_TCP_MD5SIG union sockunion su2; +#endif /* HAVE_TCP_MD5SIG */ assert (socket >= 0); @@ -228,6 +231,17 @@ bgp_set_socket_ttl (struct peer *peer, int bgp_sock) static int bgp_get_instance_for_inc_conn (int sock, struct bgp **bgp_inst) { +#ifndef SO_BINDTODEVICE + /* only Linux has SO_BINDTODEVICE, but we're in Linux-specific code here + * anyway since the assumption is that the interface name returned by + * getsockopt() is useful in identifying the VRF, particularly with Linux's + * VRF l3master device. The whole mechanism is specific to Linux, so... + * when other platforms add VRF support, this will need handling here as + * well. (or, some restructuring) */ + *bgp_inst = bgp_get_default (); + return !*bgp_inst; + +#else char name[VRF_NAMSIZ + 1]; socklen_t name_len = VRF_NAMSIZ; struct bgp *bgp; @@ -239,13 +253,18 @@ bgp_get_instance_for_inc_conn (int sock, struct bgp **bgp_inst) rc = getsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, name, &name_len); if (rc != 0) { +#if !defined (HAVE_BGP_STANDALONE) zlog_err ("[Error] BGP SO_BINDTODEVICE get failed (%s), sock %d", safe_strerror (errno), sock); return -1; +#endif } if (!strlen(name)) - return 0; /* default instance. */ + { + *bgp_inst = bgp_get_default (); + return 0; /* default instance. */ + } /* First try match to instance; if that fails, check for interfaces. */ bgp = bgp_lookup_by_name (name); @@ -275,6 +294,7 @@ bgp_get_instance_for_inc_conn (int sock, struct bgp **bgp_inst) /* We didn't match to either an instance or an interface. */ return -1; +#endif } /* Accept bgp connection. */ @@ -566,7 +586,7 @@ bgp_update_source (struct peer *peer) int bgp_connect (struct peer *peer) { - unsigned int ifindex = 0; + ifindex_t ifindex = 0; if (peer->conf_if && BGP_PEER_SU_UNSPEC(peer)) { @@ -656,7 +676,9 @@ bgp_getsockname (struct peer *peer) { zlog_err ("%s: nexthop_set failed, resetting connection - intf %p", peer->host, peer->nexthop.ifp); +#if !defined (HAVE_BGP_STANDALONE) return -1; +#endif } return 0; diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 80495065b0..1e5c4cf8b0 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -32,6 +32,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "jhash.h" #include "nexthop.h" #include "queue.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" @@ -236,6 +237,7 @@ bgp_connected_add (struct bgp *bgp, struct connected *ifc) for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { if (peer->conf_if && (strcmp (peer->conf_if, ifc->ifp->name) == 0) && + peer->status != Established && !CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY)) { if (peer_active(peer)) @@ -562,12 +564,13 @@ bgp_scan_init (struct bgp *bgp) bgp->connected_table[AFI_IP] = bgp_table_init (AFI_IP, SAFI_UNICAST); bgp->import_check_table[AFI_IP] = bgp_table_init (AFI_IP, SAFI_UNICAST); -#ifdef HAVE_IPV6 bgp->nexthop_cache_table[AFI_IP6] = bgp_table_init (AFI_IP6, SAFI_UNICAST); bgp->connected_table[AFI_IP6] = bgp_table_init (AFI_IP6, SAFI_UNICAST); bgp->import_check_table[AFI_IP6] = bgp_table_init (AFI_IP6, SAFI_UNICAST); -#endif /* HAVE_IPV6 */ + bgp->nexthop_cache_table[AFI_ETHER] = bgp_table_init (AFI_ETHER, SAFI_UNICAST); + bgp->connected_table[AFI_ETHER] = bgp_table_init (AFI_ETHER, SAFI_UNICAST); + bgp->import_check_table[AFI_ETHER] = bgp_table_init (AFI_ETHER, SAFI_UNICAST); } void diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 9d8d8f3b52..ef70d0e4f9 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -31,6 +31,7 @@ #include "memory.h" #include "nexthop.h" #include "vrf.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" @@ -370,8 +371,8 @@ bgp_parse_nexthop_update (int command, vrf_id_t vrf_id) { char buf[PREFIX2STR_BUFFER]; prefix2str(&p, buf, sizeof (buf)); - zlog_debug("parse nexthop update(%s): metric=%d, #nexthop=%d", buf, - metric, nexthop_num); + zlog_debug("%d: NH update for %s - metric %d (cur %d) #nhops %d (cur %d)", + vrf_id, buf, metric, bnc->metric, nexthop_num, bnc->nexthop_num); } if (metric != bnc->metric) @@ -396,30 +397,35 @@ bgp_parse_nexthop_update (int command, vrf_id_t vrf_id) nexthop->type = stream_getc (s); switch (nexthop->type) { - case ZEBRA_NEXTHOP_IPV4: + case NEXTHOP_TYPE_IPV4: nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s); break; - case ZEBRA_NEXTHOP_IFINDEX: + case NEXTHOP_TYPE_IFINDEX: nexthop->ifindex = stream_getl (s); break; - case ZEBRA_NEXTHOP_IPV4_IFINDEX: + case NEXTHOP_TYPE_IPV4_IFINDEX: nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s); nexthop->ifindex = stream_getl (s); break; -#ifdef HAVE_IPV6 - case ZEBRA_NEXTHOP_IPV6: + case NEXTHOP_TYPE_IPV6: stream_get (&nexthop->gate.ipv6, s, 16); break; - case ZEBRA_NEXTHOP_IPV6_IFINDEX: + case NEXTHOP_TYPE_IPV6_IFINDEX: stream_get (&nexthop->gate.ipv6, s, 16); nexthop->ifindex = stream_getl (s); break; -#endif default: /* do nothing */ break; } + if (BGP_DEBUG(nht, NHT)) + { + char buf[NEXTHOP_STRLEN]; + zlog_debug(" nhop via %s", + nexthop2str (nexthop, buf, sizeof (buf))); + } + if (nhlist_tail) { nhlist_tail->next = nexthop; @@ -642,6 +648,14 @@ evaluate_paths (struct bgp_nexthop_cache *bnc) int afi; struct peer *peer = (struct peer *)bnc->nht_info; + if (BGP_DEBUG(nht, NHT)) + { + char buf[PREFIX2STR_BUFFER]; + bnc_str(bnc, buf, PREFIX2STR_BUFFER); + zlog_debug("NH update for %s - flags 0x%x chgflags 0x%x - evaluate paths", + buf, bnc->flags, bnc->change_flags); + } + LIST_FOREACH(path, &(bnc->paths), nh_thread) { if (!(path->type == ZEBRA_ROUTE_BGP && @@ -681,8 +695,6 @@ evaluate_paths (struct bgp_nexthop_cache *bnc) if (CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_METRIC_CHANGED) || CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED)) SET_FLAG(path->flags, BGP_INFO_IGP_CHANGED); - else - UNSET_FLAG (path->flags, BGP_INFO_IGP_CHANGED); bgp_process(bgp, rn, afi, SAFI_UNICAST); } diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 947f5c09d4..6001092ce2 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -28,6 +28,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "command.h" #include "memory.h" #include "queue.h" +#include "filter.h" #include "lib/json.h" #include "bgpd/bgpd.h" @@ -195,6 +196,9 @@ bgp_afi_safi_valid_indices (afi_t afi, safi_t *safi) return 1; } break; + case AFI_ETHER: + default: + break; } zlog_debug ("unknown afi/safi (%u/%u)", afi, *safi); @@ -1473,7 +1477,7 @@ bgp_open_capability (struct stream *s, struct peer *peer) stream_putc(s, len); stream_put(s, names.nodename, len); -#ifdef _GNU_SOURCE +#ifdef HAVE_STRUCT_UTSNAME_DOMAINNAME if ((names.domainname[0] != '\0') && (strcmp(names.domainname, "(none)") != 0)) { @@ -1497,8 +1501,13 @@ bgp_open_capability (struct stream *s, struct peer *peer) stream_putc_at(s, capp, len); if (bgp_debug_neighbor_events(peer)) +#ifdef HAVE_STRUCT_UTSNAME_DOMAINNAME zlog_debug("%s Sending hostname cap with hn = %s, dn = %s", peer->host, names.nodename, names.domainname); +#else + zlog_debug("%s Sending hostname cap with hn = %s", peer->host, + names.nodename); +#endif } /* Sending base graceful-restart capability irrespective of the config */ diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 0236f6777a..2f9fdd5a75 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -32,6 +32,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "linklist.h" #include "plist.h" #include "queue.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" @@ -1162,10 +1163,12 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) { if (!peer->nexthop.v4.s_addr) { +#if !defined (HAVE_BGP_STANDALONE) zlog_err ("%s: No local IPv4 addr resetting connection, fd %d", peer->host, peer->fd); bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_SUBCODE_UNSPECIFIC); return -1; +#endif } } if (peer->afc_nego[AFI_IP6][SAFI_UNICAST] || @@ -1175,10 +1178,12 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) { if (IN6_IS_ADDR_UNSPECIFIED (&peer->nexthop.v6_global)) { +#if !defined (HAVE_BGP_STANDALONE) zlog_err ("%s: No local IPv6 addr resetting connection, fd %d", peer->host, peer->fd); bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_SUBCODE_UNSPECIFIC); return -1; +#endif } } peer->rtt = sockopt_tcp_rtt (peer->fd); diff --git a/bgpd/bgp_regex.c b/bgpd/bgp_regex.c index 15c23c9ff9..ea87633dc0 100644 --- a/bgpd/bgp_regex.c +++ b/bgpd/bgp_regex.c @@ -24,6 +24,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "command.h" #include "memory.h" #include "queue.h" +#include "filter.h" #include "bgpd.h" #include "bgp_aspath.h" diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index fff595d190..7295ff147f 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -376,7 +376,11 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, } if (debug) - bgp_info_path_with_addpath_rx_str (exist, exist_buf); + { + bgp_info_path_with_addpath_rx_str (exist, exist_buf); + zlog_debug("%s: Comparing %s flags 0x%x with %s flags 0x%x", + pfx_buf, new_buf, new->flags, exist_buf, exist->flags); + } newattr = new->attr; existattr = exist->attr; @@ -705,6 +709,15 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, * TODO: If unequal cost ibgp multipath is enabled we can * mark the paths as equal here instead of returning */ + if (debug) + { + if (ret == 1) + zlog_debug("%s: %s wins over %s after IGP metric comparison", + pfx_buf, new_buf, exist_buf); + else + zlog_debug("%s: %s loses to %s after IGP metric comparison", + pfx_buf, new_buf, exist_buf); + } return ret; } @@ -1638,14 +1651,19 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, /* Now that we know which path is the bestpath see if any of the other paths * qualify as multipaths */ + if (debug) + { + if (new_select) + bgp_info_path_with_addpath_rx_str (new_select, path_buf); + else + sprintf (path_buf, "NONE"); + zlog_debug("%s: After path selection, newbest is %s oldbest was %s", + pfx_buf, path_buf, + old_select ? old_select->peer->host : "NONE"); + } + if (do_mpath && new_select) { - if (debug) - { - bgp_info_path_with_addpath_rx_str (new_select, path_buf); - zlog_debug("%s: %s is the bestpath, now find multipaths", pfx_buf, path_buf); - } - for (ri = rn->info; (ri != NULL) && (nextri = ri->next, 1); ri = nextri) { @@ -1657,7 +1675,7 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, if (debug) zlog_debug("%s: %s is the bestpath, add to the multipath list", pfx_buf, path_buf); - bgp_mp_list_add (&mp_list, ri); + bgp_mp_list_add (&mp_list, ri); continue; } @@ -1749,6 +1767,57 @@ subgroup_process_announce_selected (struct update_subgroup *subgrp, return 0; } +/* + * Clear IGP changed flag and attribute changed flag for a route (all paths). + * This is called at the end of route processing. + */ +static void +bgp_zebra_clear_route_change_flags (struct bgp_node *rn) +{ + struct bgp_info *ri; + + for (ri = rn->info; ri; ri = ri->next) + { + if (BGP_INFO_HOLDDOWN (ri)) + continue; + UNSET_FLAG (ri->flags, BGP_INFO_IGP_CHANGED); + UNSET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED); + } +} + +/* + * Has the route changed from the RIB's perspective? This is invoked only + * if the route selection returns the same best route as earlier - to + * determine if we need to update zebra or not. + */ +static int +bgp_zebra_has_route_changed (struct bgp_node *rn, struct bgp_info *selected) +{ + struct bgp_info *mpinfo; + + /* If this is multipath, check all selected paths for any nexthop change or + * attribute change. Some attribute changes (e.g., community) aren't of + * relevance to the RIB, but we'll update zebra to ensure we handle the + * case of BGP nexthop change. This is the behavior when the best path has + * an attribute change anyway. + */ + if (CHECK_FLAG (selected->flags, BGP_INFO_IGP_CHANGED) || + CHECK_FLAG (selected->flags, BGP_INFO_MULTIPATH_CHG)) + return 1; + + /* If this is multipath, check all selected paths for any nexthop change */ + for (mpinfo = bgp_info_mpath_first (selected); mpinfo; + mpinfo = bgp_info_mpath_next (mpinfo)) + { + if (CHECK_FLAG (mpinfo->flags, BGP_INFO_IGP_CHANGED) + || CHECK_FLAG (mpinfo->flags, BGP_INFO_ATTR_CHANGED)) + return 1; + } + + /* Nothing has changed from the RIB's perspective. */ + return 0; +} + struct bgp_process_queue { struct bgp *bgp; @@ -1799,11 +1868,11 @@ bgp_process_main (struct work_queue *wq, void *data) !CHECK_FLAG(old_select->flags, BGP_INFO_ATTR_CHANGED) && !bgp->addpath_tx_used[afi][safi]) { - if (CHECK_FLAG (old_select->flags, BGP_INFO_IGP_CHANGED) || - CHECK_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG)) + if (bgp_zebra_has_route_changed (rn, old_select)) bgp_zebra_announce (p, old_select, bgp, afi, safi); UNSET_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG); + bgp_zebra_clear_route_change_flags (rn); UNSET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED); return WQ_SUCCESS; } @@ -1856,7 +1925,10 @@ bgp_process_main (struct work_queue *wq, void *data) bgp_zebra_withdraw (p, old_select, safi); } } - + + /* Clear any route change flags. */ + bgp_zebra_clear_route_change_flags (rn); + /* Reap old select bgp_info, if it has been removed */ if (old_select && CHECK_FLAG (old_select->flags, BGP_INFO_REMOVED)) bgp_info_reap (rn, old_select); @@ -5873,7 +5945,7 @@ route_vty_out (struct vty *vty, struct prefix *p, vty_out (vty, "%-16s", inet_ntoa (attr->nexthop)); } } -#ifdef HAVE_IPV6 + /* IPv6 Next Hop */ else if (p->family == AF_INET6 || BGP_ATTR_NEXTHOP_AFI_IP6(attr)) { @@ -5901,8 +5973,9 @@ route_vty_out (struct vty *vty, struct prefix *p, json_object_string_add(json_nexthop_ll, "afi", "ipv6"); json_object_string_add(json_nexthop_ll, "scope", "link-local"); - if (IPV6_ADDR_CMP (&attr->extra->mp_nexthop_global, - &attr->extra->mp_nexthop_local) != 0) + if ((IPV6_ADDR_CMP (&attr->extra->mp_nexthop_global, + &attr->extra->mp_nexthop_local) != 0) && + !attr->extra->mp_nexthop_prefer_global) json_object_boolean_true_add(json_nexthop_ll, "used"); else json_object_boolean_true_add(json_nexthop_global, "used"); @@ -5912,7 +5985,10 @@ route_vty_out (struct vty *vty, struct prefix *p, } else { - if ((attr->extra->mp_nexthop_len == 32) || (binfo->peer->conf_if)) + /* Display LL if LL/Global both in table unless prefer-global is set */ + if (((attr->extra->mp_nexthop_len == 32) && + !attr->extra->mp_nexthop_prefer_global) || + (binfo->peer->conf_if)) { if (binfo->peer->conf_if) { @@ -5954,7 +6030,6 @@ route_vty_out (struct vty *vty, struct prefix *p, } } } -#endif /* HAVE_IPV6 */ /* MED/Metric */ if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)) @@ -6635,7 +6710,6 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, if (json_paths) json_object_string_add(json_nexthop_global, "afi", "ipv4"); } -#ifdef HAVE_IPV6 else { assert (attr->extra); @@ -6654,8 +6728,6 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, buf, INET6_ADDRSTRLEN)); } } -#endif /* HAVE_IPV6 */ - /* Display the IGP cost or 'inaccessible' */ if (! CHECK_FLAG (binfo->flags, BGP_INFO_VALID)) @@ -6761,7 +6833,6 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, if (!json_paths) vty_out (vty, "%s", VTY_NEWLINE); -#ifdef HAVE_IPV6 /* display the link-local nexthop */ if (attr->extra && attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) { @@ -6775,13 +6846,19 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, json_object_string_add(json_nexthop_ll, "scope", "link-local"); json_object_boolean_true_add(json_nexthop_ll, "accessible"); - json_object_boolean_true_add(json_nexthop_ll, "used"); + + if (!attr->extra->mp_nexthop_prefer_global) + json_object_boolean_true_add(json_nexthop_ll, "used"); + else + json_object_boolean_true_add(json_nexthop_global, "used"); } else { - vty_out (vty, " (%s) (used)%s", - inet_ntop (AF_INET6, &attr->extra->mp_nexthop_local, + vty_out (vty, " (%s) %s%s", + inet_ntop (AF_INET6, &attr->extra->mp_nexthop_local, buf, INET6_ADDRSTRLEN), + attr->extra->mp_nexthop_prefer_global ? + "(prefer-global)" : "(used)", VTY_NEWLINE); } } @@ -6791,7 +6868,6 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, if (json_paths) json_object_boolean_true_add(json_nexthop_global, "used"); } -#endif /* HAVE_IPV6 */ /* Line 3 display Origin, Med, Locpref, Weight, Tag, valid, Int/Ext/Local, Atomic, best */ if (json_paths) @@ -7634,7 +7710,9 @@ route_vty_out_detail_header (struct vty *vty, struct bgp *bgp, { vty_out (vty, ", best #%d", best); if (safi == SAFI_UNICAST) - vty_out (vty, ", table Default-IP-Routing-Table"); + vty_out (vty, ", table %s", + (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) + ? "Default-IP-Routing-Table" : bgp->name); } else vty_out (vty, ", no best path"); @@ -9304,6 +9382,66 @@ DEFUN (show_ip_bgp_dampening_info, return bgp_show_dampening_parameters (vty, AFI_IP, SAFI_UNICAST); } + +DEFUN (show_ip_bgp_ipv4_dampening_parameters, + show_ip_bgp_ipv4_dampening_parameters_cmd, + "show ip bgp ipv4 (unicast|multicast) dampening parameters", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display detailed information about dampening\n" + "Display detail of configured dampening parameters\n") +{ + if (strncmp(argv[0], "m", 1) == 0) + return bgp_show_dampening_parameters (vty, AFI_IP, SAFI_MULTICAST); + + return bgp_show_dampening_parameters (vty, AFI_IP, SAFI_UNICAST); +} + + +DEFUN (show_ip_bgp_ipv4_dampening_flap_stats, + show_ip_bgp_ipv4_dampening_flap_stats_cmd, + "show ip bgp ipv4 (unicast|multicast) dampening flap-statistics", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display detailed information about dampening\n" + "Display flap statistics of routes\n") +{ + if (strncmp(argv[0], "m", 1) == 0) + return bgp_show (vty, NULL, AFI_IP, SAFI_MULTICAST, + bgp_show_type_flap_statistics, NULL, 0); + + return bgp_show (vty, NULL, AFI_IP, SAFI_MULTICAST, + bgp_show_type_flap_statistics, NULL, 0); +} + +DEFUN (show_ip_bgp_ipv4_dampening_dampd_paths, + show_ip_bgp_ipv4_dampening_dampd_paths_cmd, + "show ip bgp ipv4 (unicast|multicast) dampening dampened-paths", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display detailed information about dampening\n" + "Display paths suppressed due to dampening\n") +{ + if (strncmp(argv[0], "m", 1) == 0) + return bgp_show (vty, NULL, AFI_IP, SAFI_MULTICAST, + bgp_show_type_dampend_paths, NULL, 0); + + return bgp_show (vty, NULL, AFI_IP, SAFI_MULTICAST, + bgp_show_type_dampend_paths, NULL, 0); +} + static int bgp_show_route_map (struct vty *vty, const char *name, const char *rmap_str, afi_t afi, @@ -14438,7 +14576,10 @@ bgp_route_init (void) install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd); install_element (VIEW_NODE, &show_ip_bgp_dampening_params_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_dampening_parameters_cmd); install_element (VIEW_NODE, &show_ip_bgp_dampened_paths_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_dampening_dampd_paths_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_dampening_flap_stats_cmd); install_element (VIEW_NODE, &show_ip_bgp_damp_dampened_paths_cmd); install_element (VIEW_NODE, &show_ip_bgp_flap_statistics_cmd); install_element (VIEW_NODE, &show_ip_bgp_damp_flap_statistics_cmd); @@ -14591,6 +14732,9 @@ bgp_route_init (void) install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd); install_element (ENABLE_NODE, &show_ip_bgp_dampening_params_cmd); install_element (ENABLE_NODE, &show_ip_bgp_dampened_paths_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_dampening_parameters_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_dampening_dampd_paths_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_dampening_flap_stats_cmd); install_element (ENABLE_NODE, &show_ip_bgp_damp_dampened_paths_cmd); install_element (ENABLE_NODE, &show_ip_bgp_flap_statistics_cmd); install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_statistics_cmd); @@ -15000,6 +15144,13 @@ bgp_route_init (void) install_element (BGP_IPV4_NODE, &bgp_damp_unset_cmd); install_element (BGP_IPV4_NODE, &bgp_damp_unset2_cmd); install_element (BGP_IPV4_NODE, &bgp_damp_unset3_cmd); + + /* IPv4 Multicast Mode */ + install_element (BGP_IPV4M_NODE, &bgp_damp_set_cmd); + install_element (BGP_IPV4M_NODE, &bgp_damp_set2_cmd); + install_element (BGP_IPV4M_NODE, &bgp_damp_set3_cmd); + install_element (BGP_IPV4M_NODE, &bgp_damp_unset_cmd); + install_element (BGP_IPV4M_NODE, &bgp_damp_unset2_cmd); } void diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 3018d074fc..fea9ae6b18 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -103,6 +103,7 @@ o Cisco route-map o Local extensions set ipv6 next-hop global: Done + set ipv6 next-hop prefer-global: Done set ipv6 next-hop local : Done set as-path exclude : Done @@ -2192,6 +2193,67 @@ struct route_map_rule_cmd route_set_ipv6_nexthop_global_cmd = route_set_ipv6_nexthop_global_free }; +/* Set next-hop preference value. */ +static route_map_result_t +route_set_ipv6_nexthop_prefer_global (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct bgp_info *bgp_info; + struct peer *peer; + + if (type == RMAP_BGP) + { + /* Fetch routemap's rule information. */ + bgp_info = object; + peer = bgp_info->peer; + + if ((CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_IN) || + CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_IMPORT)) + && peer->su_remote + && sockunion_family (peer->su_remote) == AF_INET6) + { + /* Set next hop preference to global */ + bgp_info->attr->extra->mp_nexthop_prefer_global = TRUE; + SET_FLAG(bgp_info->attr->rmap_change_flags, + BATTR_RMAP_IPV6_PREFER_GLOBAL_CHANGED); + } + else + { + bgp_info->attr->extra->mp_nexthop_prefer_global = FALSE; + SET_FLAG(bgp_info->attr->rmap_change_flags, + BATTR_RMAP_IPV6_PREFER_GLOBAL_CHANGED); + } + } + return RMAP_OKAY; +} + +static void * +route_set_ipv6_nexthop_prefer_global_compile (const char *arg) +{ + int *rins = NULL; + + rins = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (int)); + *rins = 1; + + return rins; +} + +/* Free route map's compiled `ip next-hop' value. */ +static void +route_set_ipv6_nexthop_prefer_global_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip nexthop set preferred. */ +struct route_map_rule_cmd route_set_ipv6_nexthop_prefer_global_cmd = +{ + "ipv6 next-hop prefer-global", + route_set_ipv6_nexthop_prefer_global, + route_set_ipv6_nexthop_prefer_global_compile, + route_set_ipv6_nexthop_prefer_global_free +}; + /* `set ipv6 nexthop local IP_ADDRESS' */ /* Set nexthop to object. ojbect must be pointer to struct attr. */ @@ -2935,8 +2997,8 @@ DEFUN (match_peer, "match peer (A.B.C.D|X:X::X:X)", MATCH_STR "Match peer address\n" - "IPv6 address of peer\n" - "IP address of peer\n") + "IP address of peer\n" + "IPv6 address of peer\n") { return bgp_route_match_add (vty, vty->index, "peer", argv[0], RMAP_EVENT_MATCH_ADDED); @@ -2974,8 +3036,8 @@ ALIAS (no_match_peer, NO_STR MATCH_STR "Match peer address\n" - "IPv6 address of peer\n" - "IP address of peer\n") + "IP address of peer\n" + "IPv6 address of peer\n") ALIAS (no_match_peer, no_match_peer_local_cmd, @@ -4366,11 +4428,34 @@ DEFUN (no_set_ipv6_nexthop_peer, SET_STR IPV6_STR "IPv6 next-hop address\n" - ) + "Use peer address (for BGP only)\n") { return bgp_route_set_delete (vty, vty->index, "ipv6 next-hop peer-address", NULL); } +DEFUN (set_ipv6_nexthop_prefer_global, + set_ipv6_nexthop_prefer_global_cmd, + "set ipv6 next-hop prefer-global", + SET_STR + IPV6_STR + "IPv6 next-hop address\n" + "Prefer global over link-local if both exist\n") +{ + return bgp_route_set_add (vty, vty->index, "ipv6 next-hop prefer-global", NULL);; +} + +DEFUN (no_set_ipv6_nexthop_prefer_global, + no_set_ipv6_nexthop_prefer_global_cmd, + "no set ipv6 next-hop prefer-global", + NO_STR + SET_STR + IPV6_STR + "IPv6 next-hop address\n" + "Prefer global over link-local if both exist\n") +{ + return bgp_route_set_delete (vty, vty->index, "ipv6 next-hop prefer-global", NULL); +} + DEFUN (set_ipv6_nexthop_global, set_ipv6_nexthop_global_cmd, "set ipv6 next-hop global X:X::X:X", @@ -4704,6 +4789,7 @@ bgp_route_map_init (void) route_map_install_match (&route_match_ipv6_next_hop_cmd); route_map_install_match (&route_match_ipv6_address_prefix_list_cmd); route_map_install_set (&route_set_ipv6_nexthop_global_cmd); + route_map_install_set (&route_set_ipv6_nexthop_prefer_global_cmd); route_map_install_set (&route_set_ipv6_nexthop_local_cmd); route_map_install_set (&route_set_ipv6_nexthop_peer_cmd); @@ -4716,6 +4802,8 @@ bgp_route_map_init (void) install_element (RMAP_NODE, &set_ipv6_nexthop_global_cmd); install_element (RMAP_NODE, &no_set_ipv6_nexthop_global_cmd); install_element (RMAP_NODE, &no_set_ipv6_nexthop_global_val_cmd); + install_element (RMAP_NODE, &set_ipv6_nexthop_prefer_global_cmd); + install_element (RMAP_NODE, &no_set_ipv6_nexthop_prefer_global_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); diff --git a/bgpd/bgp_snmp.c b/bgpd/bgp_snmp.c index 84a527b96a..5e6218e8a3 100644 --- a/bgpd/bgp_snmp.c +++ b/bgpd/bgp_snmp.c @@ -30,6 +30,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "command.h" #include "thread.h" #include "smux.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" @@ -116,8 +117,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA SNMP_LOCAL_VARIABLES /* BGP-MIB instances. */ -oid bgp_oid [] = { BGP4MIB }; -oid bgp_trap_oid [] = { BGP4MIB, 0 }; +static oid bgp_oid [] = { BGP4MIB }; +static oid bgp_trap_oid [] = { BGP4MIB, 0 }; /* IP address 0.0.0.0. */ static struct in_addr bgp_empty_addr = { .s_addr = 0 }; @@ -137,7 +138,7 @@ static u_char *bgp4PathAttrTable (struct variable *, oid [], size_t *, int, size_t *, WriteMethod **); /* static u_char *bgpTraps (); */ -struct variable bgp_variables[] = +static struct variable bgp_variables[] = { /* BGP version. */ {BGPVERSION, OCTET_STRING, RONLY, bgpVersion, @@ -831,7 +832,7 @@ bgp4PathAttrTable (struct variable *v, oid name[], size_t *length, } /* BGP Traps. */ -struct trap_object bgpTrapList[] = +static struct trap_object bgpTrapList[] = { {3, {3, 1, BGPPEERLASTERROR}}, {3, {3, 1, BGPPEERSTATE}} diff --git a/bgpd/bgp_table.c b/bgpd/bgp_table.c index 1df24859f5..114c6ef013 100644 --- a/bgpd/bgp_table.c +++ b/bgpd/bgp_table.c @@ -25,6 +25,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "sockunion.h" #include "vty.h" #include "queue.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h index f4e5ec5b89..2f839c4af7 100644 --- a/bgpd/bgp_table.h +++ b/bgpd/bgp_table.h @@ -35,7 +35,7 @@ struct bgp_table struct peer *owner; struct route_table *route_table; - u_int64_t version; + uint64_t version; }; struct bgp_node @@ -56,7 +56,7 @@ struct bgp_node struct bgp_node *prn; - u_int64_t version; + uint64_t version; u_char flags; #define BGP_NODE_PROCESS_SCHEDULED (1 << 0) #define BGP_NODE_USER_CLEAR (1 << 1) @@ -112,44 +112,6 @@ bgp_node_table (struct bgp_node *node) return bgp_node_to_rnode (node)->table->info; } -/* - * bgp_node_info - * - * Returns the 'info' pointer corresponding to a bgp node. - */ -static inline void * -bgp_node_info (const struct bgp_node *node) -{ - return node->info; -} - -/* - * bgp_node_set_info - */ -static inline void -bgp_node_set_info (struct bgp_node *node, void *info) -{ - node->info = info; -} - -/* - * bgp_node_prefix - */ -static inline struct prefix * -bgp_node_prefix (struct bgp_node *node) -{ - return &node->p; -} - -/* - * bgp_node_prefixlen - */ -static inline u_char -bgp_node_prefixlen (struct bgp_node *node) -{ - return bgp_node_prefix (node)->prefixlen; -} - /* * bgp_node_parent_nolock * @@ -349,13 +311,13 @@ bgp_table_iter_started (bgp_table_iter_t * iter) /* This would benefit from a real atomic operation... * until then. */ -static inline u_int64_t +static inline uint64_t bgp_table_next_version (struct bgp_table *table) { return ++table->version; } -static inline u_int64_t +static inline uint64_t bgp_table_version (struct bgp_table *table) { return table->version; diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c index cd7710b501..29e6243a1a 100644 --- a/bgpd/bgp_updgrp.c +++ b/bgpd/bgp_updgrp.c @@ -668,7 +668,7 @@ updgrp_show_packet_queue_walkcb (struct update_group *updgrp, void *arg) */ void update_group_show_packet_queue (struct bgp *bgp, afi_t afi, safi_t safi, - struct vty *vty, u_int64_t id) + struct vty *vty, uint64_t id) { struct updwalk_context ctx; @@ -1587,7 +1587,7 @@ update_bgp_group_free (struct bgp *bgp) void update_group_show (struct bgp *bgp, afi_t afi, safi_t safi, struct vty *vty, - u_int64_t subgrp_id) + uint64_t subgrp_id) { struct updwalk_context ctx; memset (&ctx, 0, sizeof (ctx)); diff --git a/bgpd/bgp_updgrp.h b/bgpd/bgp_updgrp.h index aab2458b30..6ab384369c 100644 --- a/bgpd/bgp_updgrp.h +++ b/bgpd/bgp_updgrp.h @@ -133,7 +133,7 @@ struct update_group safi_t safi; int afid; - u_int64_t id; + uint64_t id; time_t uptime; u_int32_t join_events; @@ -231,8 +231,8 @@ struct update_subgroup */ struct { - u_int64_t update_group_id; - u_int64_t subgroup_id; + uint64_t update_group_id; + uint64_t subgroup_id; } split_from; u_int32_t join_events; @@ -248,7 +248,7 @@ struct update_subgroup u_int32_t split_events; u_int32_t merge_checks_triggered; - u_int64_t id; + uint64_t id; struct zlog *log; u_int16_t sflags; @@ -297,8 +297,8 @@ struct updwalk_context struct vty *vty; struct bgp_node *rn; struct bgp_info *ri; - u_int64_t updgrp_id; - u_int64_t subgrp_id; + uint64_t updgrp_id; + uint64_t subgrp_id; bgp_policy_type_e policy_type; const char *policy_name; int policy_event_start_flag; @@ -367,7 +367,7 @@ extern void update_bgp_group_init (struct bgp *); extern void udpate_bgp_group_free (struct bgp *); extern void -update_group_show (struct bgp *bgp, afi_t afi, safi_t safi, struct vty *vty, u_int64_t subgrp_id); +update_group_show (struct bgp *bgp, afi_t afi, safi_t safi, struct vty *vty, uint64_t subgrp_id); extern void update_group_show_stats (struct bgp *bgp, struct vty *vty); extern void update_group_adjust_peer (struct peer_af *paf); extern int update_group_adjust_soloness (struct peer *peer, int set); @@ -439,13 +439,13 @@ extern struct bgp_advertise *bgp_advertise_clean_subgroup (struct *adj); extern void update_group_show_adj_queue (struct bgp *bgp, afi_t afi, safi_t safi, struct vty *vty, - u_int64_t id); + uint64_t id); extern void update_group_show_advertised (struct bgp *bgp, afi_t afi, safi_t safi, struct vty *vty, - u_int64_t id); + uint64_t id); extern void update_group_show_packet_queue (struct bgp *bgp, afi_t afi, safi_t safi, struct vty *vty, - u_int64_t id); + uint64_t id); extern void subgroup_announce_route (struct update_subgroup *subgrp); extern void subgroup_announce_all (struct update_subgroup *subgrp); diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c index 4b684be1bb..c485e61e5c 100644 --- a/bgpd/bgp_updgrp_adv.c +++ b/bgpd/bgp_updgrp_adv.c @@ -36,6 +36,7 @@ #include "thread.h" #include "queue.h" #include "routemap.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" @@ -276,7 +277,7 @@ updgrp_show_adj_walkcb (struct update_group *updgrp, void *arg) static void updgrp_show_adj (struct bgp *bgp, afi_t afi, safi_t safi, - struct vty *vty, u_int64_t id, u_int8_t flags) + struct vty *vty, uint64_t id, u_int8_t flags) { struct updwalk_context ctx; memset (&ctx, 0, sizeof (ctx)); @@ -849,14 +850,14 @@ group_announce_route (struct bgp *bgp, afi_t afi, safi_t safi, void update_group_show_adj_queue (struct bgp *bgp, afi_t afi, safi_t safi, - struct vty *vty, u_int64_t id) + struct vty *vty, uint64_t id) { updgrp_show_adj (bgp, afi, safi, vty, id, UPDWALK_FLAGS_ADVQUEUE); } void update_group_show_advertised (struct bgp *bgp, afi_t afi, safi_t safi, - struct vty *vty, u_int64_t id) + struct vty *vty, uint64_t id) { updgrp_show_adj (bgp, afi, safi, vty, id, UPDWALK_FLAGS_ADVERTISED); } diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 5dff63e8c2..c83d751743 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -32,8 +32,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "memory.h" #include "hash.h" #include "queue.h" -#include "if.h" -#include "vrf.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_advertise.h" @@ -64,12 +63,20 @@ listen_range_exists (struct bgp *bgp, struct prefix *range, int exact); afi_t bgp_node_afi (struct vty *vty) { - if (vty->node == BGP_IPV6_NODE || - vty->node == BGP_IPV6M_NODE || - vty->node == BGP_VPNV6_NODE || - vty->node == BGP_ENCAPV6_NODE) - return AFI_IP6; - return AFI_IP; + afi_t afi; + switch (vty->node) + { + case BGP_IPV6_NODE: + case BGP_IPV6M_NODE: + case BGP_VPNV6_NODE: + case BGP_ENCAPV6_NODE: + afi = AFI_IP6; + break; + default: + afi = AFI_IP; + break; + } + return afi; } /* Utility function to get subsequent address family from current @@ -77,13 +84,26 @@ bgp_node_afi (struct vty *vty) safi_t bgp_node_safi (struct vty *vty) { - if (vty->node == BGP_VPNV4_NODE || vty->node == BGP_VPNV6_NODE) - return SAFI_MPLS_VPN; - if (vty->node == BGP_ENCAP_NODE || vty->node == BGP_ENCAPV6_NODE) - return SAFI_ENCAP; - if (vty->node == BGP_IPV4M_NODE || vty->node == BGP_IPV6M_NODE) - return SAFI_MULTICAST; - return SAFI_UNICAST; + safi_t safi; + switch (vty->node) + { + case BGP_ENCAP_NODE: + case BGP_ENCAPV6_NODE: + safi = SAFI_ENCAP; + break; + case BGP_VPNV4_NODE: + case BGP_VPNV6_NODE: + safi = SAFI_MPLS_VPN; + break; + case BGP_IPV4M_NODE: + case BGP_IPV6M_NODE: + safi = SAFI_MULTICAST; + break; + default: + safi = SAFI_UNICAST; + break; + } + return safi; } int @@ -304,6 +324,9 @@ bgp_vty_return (struct vty *vty, int ret) case BGP_ERR_INVALID_FOR_DYNAMIC_PEER: str = "Operation not allowed on a dynamic neighbor"; break; + case BGP_ERR_INVALID_FOR_DIRECT_PEER: + str = "Operation not allowed on a directly connected neighbor"; + break; } if (str) { @@ -533,26 +556,22 @@ bgp_clear_vty (struct vty *vty, const char *name, afi_t afi, safi_t safi, /* clear soft inbound */ static void -bgp_clear_star_soft_in (struct vty *vty) +bgp_clear_star_soft_in (struct vty *vty, const char *name) { - bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, + bgp_clear_vty (vty,name, AFI_IP, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_IN, NULL); -#ifdef HAVE_IPV6 - bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_all, + bgp_clear_vty (vty, name, AFI_IP6, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_IN, NULL); -#endif /* HAVE_IPV6 */ } /* clear soft outbound */ static void -bgp_clear_star_soft_out (struct vty *vty) +bgp_clear_star_soft_out (struct vty *vty, const char *name) { - bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, + bgp_clear_vty (vty, name, AFI_IP, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_OUT, NULL); -#ifdef HAVE_IPV6 - bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_all, + bgp_clear_vty (vty, name, AFI_IP6, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_OUT, NULL); -#endif /* HAVE_IPV6 */ } @@ -742,17 +761,39 @@ DEFUN (no_router_bgp, struct bgp *bgp; const char *name = NULL; - VTY_GET_INTEGER_RANGE ("AS", as, argv[0], 1, BGP_AS4_MAX); - if (argc == 3) - name = argv[2]; - - /* Lookup bgp structure. */ - bgp = bgp_lookup (as, name); - if (! bgp) + // "no router bgp" without an ASN + if (argc < 1) { - vty_out (vty, "%% Can't find BGP instance%s", VTY_NEWLINE); - return CMD_WARNING; + //Pending: Make VRF option available for ASN less config + bgp = bgp_get_default(); + + if (bgp == NULL) + { + vty_out (vty, "%% No BGP process is configured%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (listcount(bm->bgp) > 1) + { + vty_out (vty, "%% Multiple BGP processes are configured%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + else + { + VTY_GET_INTEGER_RANGE ("AS", as, argv[0], 1, BGP_AS4_MAX); + + if (argc == 3) + name = argv[2]; + + /* Lookup bgp structure. */ + bgp = bgp_lookup (as, name); + if (! bgp) + { + vty_out (vty, "%% Can't find BGP instance%s", VTY_NEWLINE); + return CMD_WARNING; + } } bgp_delete (bgp); @@ -770,6 +811,13 @@ ALIAS (no_router_bgp, "BGP view\nBGP VRF\n" "View/VRF name\n") +ALIAS (no_router_bgp, + no_router_bgp_noasn_cmd, + "no router bgp", + NO_STR + ROUTER_STR + BGP_STR) + /* BGP router-id. */ DEFUN (bgp_router_id, @@ -792,11 +840,7 @@ DEFUN (bgp_router_id, return CMD_WARNING; } - if (IPV4_ADDR_SAME (&bgp->router_id_static, &id)) - return CMD_SUCCESS; - - bgp->router_id_static = id; - bgp_router_id_set (bgp, &id); + bgp_router_id_static_set (bgp, id); return CMD_SUCCESS; } @@ -811,10 +855,6 @@ DEFUN (no_bgp_router_id, int ret; struct in_addr id; struct bgp *bgp; - struct interface *ifp; - struct listnode *node; - struct connected *ifc; - struct prefix *p; bgp = vty->index; @@ -822,32 +862,20 @@ DEFUN (no_bgp_router_id, { ret = inet_aton (argv[0], &id); if (! ret) - { - ifp = if_lookup_by_name_vrf(argv[0], bgp->vrf_id); - if (!ifp) { - vty_out (vty, "%% Malformed BGP router identifier%s", VTY_NEWLINE); - return CMD_WARNING; - } - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) - { - p = ifc->address; - if (p && (p->family == AF_INET)) - { - id = p->u.prefix4; - break; - } - } - } + { + vty_out (vty, "%% Malformed BGP router identifier%s", VTY_NEWLINE); + return CMD_WARNING; + } if (! IPV4_ADDR_SAME (&bgp->router_id_static, &id)) - { - vty_out (vty, "%% BGP router-id doesn't match%s", VTY_NEWLINE); - return CMD_WARNING; - } + { + vty_out (vty, "%% BGP router-id doesn't match%s", VTY_NEWLINE); + return CMD_WARNING; + } } - bgp->router_id_static.s_addr = 0; - bgp_router_id_set (bgp, &bgp->router_id_zebra); + id.s_addr = 0; + bgp_router_id_static_set (bgp, id); return CMD_SUCCESS; } @@ -860,56 +888,6 @@ ALIAS (no_bgp_router_id, "Override configured router identifier\n" "Manually configured router identifier\n") -DEFUN (bgp_router_id_interface, - bgp_router_id_interface_cmd, - "bgp router-id IFNAME", - BGP_STR - "Override configured router identifier\n" - "Interface name\n") -{ - struct bgp *bgp; - struct interface *ifp; - struct connected *ifc; - struct listnode *node; - struct prefix *p; - struct vrf *vrf; - - bgp = vty->index; - p = NULL; - - ifp = if_lookup_by_name_vrf(argv[0], bgp->vrf_id); - if (!ifp) - { - vrf = vrf_lookup(bgp->vrf_id); - vty_out (vty, "%% Couldnt find interface %s in VRF %s%s", argv[0], vrf? vrf->name:"", VTY_NEWLINE); - return CMD_WARNING; - } - - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) - { - p = ifc->address; - - if (p && (p->family == AF_INET)) - { - if (IPV4_ADDR_SAME (&bgp->router_id_static, &p->u.prefix4)) - return CMD_SUCCESS; - bgp->router_id_static = p->u.prefix4; - bgp_router_id_set (bgp, &p->u.prefix4); - return CMD_SUCCESS; - } - } - vty_out (vty, "%% Couldnt assign the router-id%s", VTY_NEWLINE); - return CMD_WARNING; -} - -ALIAS (no_bgp_router_id, - no_bgp_router_id_interface_cmd, - "no bgp router-id IFNAME", - NO_STR - BGP_STR - "Override configured router identifier\n" - "Interface name\n") - /* BGP Cluster ID. */ DEFUN (bgp_cluster_id, @@ -933,7 +911,7 @@ DEFUN (bgp_cluster_id, } bgp_cluster_id_set (bgp, &cluster); - bgp_clear_star_soft_out (vty); + bgp_clear_star_soft_out (vty, bgp->name); return CMD_SUCCESS; } @@ -969,7 +947,7 @@ DEFUN (no_bgp_cluster_id, } bgp_cluster_id_unset (bgp); - bgp_clear_star_soft_out (vty); + bgp_clear_star_soft_out (vty, bgp->name); return CMD_SUCCESS; } @@ -1666,7 +1644,7 @@ DEFUN (bgp_client_to_client_reflection, bgp = vty->index; bgp_flag_unset (bgp, BGP_FLAG_NO_CLIENT_TO_CLIENT); - bgp_clear_star_soft_out (vty); + bgp_clear_star_soft_out (vty, bgp->name); return CMD_SUCCESS; } @@ -1683,7 +1661,7 @@ DEFUN (no_bgp_client_to_client_reflection, bgp = vty->index; bgp_flag_set (bgp, BGP_FLAG_NO_CLIENT_TO_CLIENT); - bgp_clear_star_soft_out (vty); + bgp_clear_star_soft_out (vty, bgp->name); return CMD_SUCCESS; } @@ -1838,6 +1816,26 @@ DEFUN (bgp_graceful_restart_stalepath_time, return CMD_SUCCESS; } +DEFUN (bgp_graceful_restart_restart_time, + bgp_graceful_restart_restart_time_cmd, + "bgp graceful-restart restart-time <1-3600>", + "BGP specific commands\n" + "Graceful restart capability parameters\n" + "Set the time to wait to delete stale routes before a BGP open message is received\n" + "Delay value (seconds)\n") +{ + struct bgp *bgp; + u_int32_t restart; + + bgp = vty->index; + if (! bgp) + return CMD_WARNING; + + VTY_GET_INTEGER_RANGE ("restart-time", restart, argv[0], 1, 3600); + bgp->restart_time = restart; + return CMD_SUCCESS; +} + DEFUN (no_bgp_graceful_restart_stalepath_time, no_bgp_graceful_restart_stalepath_time_cmd, "no bgp graceful-restart stalepath-time", @@ -1856,6 +1854,24 @@ DEFUN (no_bgp_graceful_restart_stalepath_time, return CMD_SUCCESS; } +DEFUN (no_bgp_graceful_restart_restart_time, + no_bgp_graceful_restart_restart_time_cmd, + "no bgp graceful-restart restart-time", + NO_STR + "BGP specific commands\n" + "Graceful restart capability parameters\n" + "Set the time to wait to delete stale routes before a BGP open message is received\n") +{ + struct bgp *bgp; + + bgp = vty->index; + if (! bgp) + return CMD_WARNING; + + bgp->restart_time = BGP_DEFAULT_RESTART_TIME; + return CMD_SUCCESS; +} + ALIAS (no_bgp_graceful_restart_stalepath_time, no_bgp_graceful_restart_stalepath_time_val_cmd, "no bgp graceful-restart stalepath-time <1-3600>", @@ -1865,6 +1881,15 @@ ALIAS (no_bgp_graceful_restart_stalepath_time, "Set the max time to hold onto restarting peer's stale paths\n" "Delay value (seconds)\n") +ALIAS (no_bgp_graceful_restart_restart_time, + no_bgp_graceful_restart_restart_time_val_cmd, + "no bgp graceful-restart restart-time <1-3600>", + NO_STR + "BGP specific commands\n" + "Graceful restart capability parameters\n" + "Set the time to wait to delete stale routes before a BGP open message is received\n" + "Delay value (seconds)\n") + /* "bgp fast-external-failover" configuration. */ DEFUN (bgp_fast_external_failover, bgp_fast_external_failover_cmd, @@ -1904,7 +1929,7 @@ DEFUN (bgp_enforce_first_as, bgp = vty->index; bgp_flag_set (bgp, BGP_FLAG_ENFORCE_FIRST_AS); - bgp_clear_star_soft_in (vty); + bgp_clear_star_soft_in (vty, bgp->name); return CMD_SUCCESS; } @@ -1920,7 +1945,7 @@ DEFUN (no_bgp_enforce_first_as, bgp = vty->index; bgp_flag_unset (bgp, BGP_FLAG_ENFORCE_FIRST_AS); - bgp_clear_star_soft_in (vty); + bgp_clear_star_soft_in (vty, bgp->name); return CMD_SUCCESS; } @@ -2338,7 +2363,7 @@ DEFUN (bgp_default_local_preference, VTY_GET_INTEGER ("local preference", local_pref, argv[0]); bgp_default_local_preference_set (bgp, local_pref); - bgp_clear_star_soft_in (vty); + bgp_clear_star_soft_in (vty, bgp->name); return CMD_SUCCESS; } @@ -2355,7 +2380,7 @@ DEFUN (no_bgp_default_local_preference, bgp = vty->index; bgp_default_local_preference_unset (bgp); - bgp_clear_star_soft_in (vty); + bgp_clear_star_soft_in (vty, bgp->name); return CMD_SUCCESS; } @@ -2428,7 +2453,7 @@ DEFUN (bgp_rr_allow_outbound_policy, { bgp_flag_set(bgp, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY); update_group_announce_rrclients(bgp); - bgp_clear_star_soft_out (vty); + bgp_clear_star_soft_out (vty, bgp->name); } return CMD_SUCCESS; @@ -2450,7 +2475,7 @@ DEFUN (no_bgp_rr_allow_outbound_policy, { bgp_flag_unset(bgp, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY); update_group_announce_rrclients(bgp); - bgp_clear_star_soft_out (vty); + bgp_clear_star_soft_out (vty, bgp->name); } return CMD_SUCCESS; @@ -2697,7 +2722,7 @@ DEFUN (bgp_disable_connected_route_check, bgp = vty->index; bgp_flag_set (bgp, BGP_FLAG_DISABLE_NH_CONNECTED_CHK); - bgp_clear_star_soft_in (vty); + bgp_clear_star_soft_in (vty, bgp->name); return CMD_SUCCESS; } @@ -2713,7 +2738,7 @@ DEFUN (no_bgp_disable_connected_route_check, bgp = vty->index; bgp_flag_unset (bgp, BGP_FLAG_DISABLE_NH_CONNECTED_CHK); - bgp_clear_star_soft_in (vty); + bgp_clear_star_soft_in (vty, bgp->name); return CMD_SUCCESS; } @@ -2802,9 +2827,11 @@ DEFUN (neighbor_remote_as, static int peer_conf_interface_get (struct vty *vty, const char *conf_if, afi_t afi, - safi_t safi, int v6only, const char *peer_group_name) + safi_t safi, int v6only, const char *peer_group_name, + const char *as_str) { - as_t as; + as_t as = 0; + int as_type = AS_UNSPECIFIED; struct bgp *bgp; struct peer *peer; struct peer_group *group; @@ -2820,14 +2847,34 @@ peer_conf_interface_get (struct vty *vty, const char *conf_if, afi_t afi, return CMD_WARNING; } + if (as_str) + { + if (strncmp(as_str, "internal", strlen("internal")) == 0) + { + as_type = AS_INTERNAL; + } + else if (strncmp(as_str, "external", strlen("external")) == 0) + { + as_type = AS_EXTERNAL; + } + else + { + /* Get AS number. */ + VTY_GET_INTEGER_RANGE ("AS", as, as_str, 1, BGP_AS4_MAX); + as_type = AS_SPECIFIED; + } + } + peer = peer_lookup_by_conf_if (bgp, conf_if); if (!peer) { if (bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4) && afi == AFI_IP && safi == SAFI_UNICAST) - peer = peer_create (NULL, conf_if, bgp, bgp->as, 0, AS_UNSPECIFIED, 0, 0, NULL); + peer = peer_create (NULL, conf_if, bgp, bgp->as, as, as_type, 0, 0, + NULL); else - peer = peer_create (NULL, conf_if, bgp, bgp->as, 0, AS_UNSPECIFIED, afi, safi, NULL); + peer = peer_create (NULL, conf_if, bgp, bgp->as, as, as_type, afi, safi, + NULL); if (peer && v6only) SET_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY); @@ -2838,7 +2885,10 @@ peer_conf_interface_get (struct vty *vty, const char *conf_if, afi_t afi, * gets deleted later etc.) */ if (peer->ifp) - bgp_zebra_initiate_radv (bgp, peer); + { + bgp_zebra_initiate_radv (bgp, peer); + } + peer_flag_set (peer, PEER_FLAG_CAPABILITY_ENHE); } else if ((v6only && !CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY)) || (!v6only && CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY))) @@ -2885,9 +2935,11 @@ DEFUN (neighbor_interface_config, "Enable BGP on interface\n") { if (argc == 2) - return peer_conf_interface_get (vty, argv[0], AFI_IP, SAFI_UNICAST, 0, argv[1]); + return peer_conf_interface_get (vty, argv[0], AFI_IP, SAFI_UNICAST, 0, + argv[1], NULL); else - return peer_conf_interface_get (vty, argv[0], AFI_IP, SAFI_UNICAST, 0, NULL); + return peer_conf_interface_get (vty, argv[0], AFI_IP, SAFI_UNICAST, 0, + NULL, NULL); } ALIAS (neighbor_interface_config, @@ -2908,9 +2960,11 @@ DEFUN (neighbor_interface_config_v6only, "Enable BGP with v6 link-local only\n") { if (argc == 2) - return peer_conf_interface_get (vty, argv[0], AFI_IP, SAFI_UNICAST, 1, argv[1]); + return peer_conf_interface_get (vty, argv[0], AFI_IP, SAFI_UNICAST, 1, + argv[1], NULL); else - return peer_conf_interface_get (vty, argv[0], AFI_IP, SAFI_UNICAST, 1, NULL); + return peer_conf_interface_get (vty, argv[0], AFI_IP, SAFI_UNICAST, 1, + NULL, NULL); } ALIAS (neighbor_interface_config_v6only, @@ -2923,6 +2977,30 @@ ALIAS (neighbor_interface_config_v6only, "Member of the peer-group\n" "peer-group name\n") +DEFUN (neighbor_interface_config_remote_as, + neighbor_interface_config_remote_as_cmd, + "neighbor WORD interface remote-as (" CMD_AS_RANGE "|external|internal)", + NEIGHBOR_STR + "Interface name or neighbor tag\n" + "Enable BGP on interface\n" + AS_STR) +{ + return peer_conf_interface_get (vty, argv[0], AFI_IP, SAFI_UNICAST, 0, + NULL, argv[1]); +} + +DEFUN (neighbor_interface_v6only_config_remote_as, + neighbor_interface_v6only_config_remote_as_cmd, + "neighbor WORD interface v6only remote-as (" CMD_AS_RANGE "|external|internal)", + NEIGHBOR_STR + "Interface name or neighbor tag\n" + "Enable BGP on interface\n" + AS_STR) +{ + return peer_conf_interface_get (vty, argv[0], AFI_IP, SAFI_UNICAST, 1, + NULL, argv[1]); +} + DEFUN (neighbor_peer_group, neighbor_peer_group_cmd, "neighbor WORD peer-group", @@ -3073,6 +3151,24 @@ ALIAS (no_neighbor_interface_config, "Member of the peer-group\n" "peer-group name\n") +ALIAS (no_neighbor_interface_config, + no_neighbor_interface_config_remote_as_cmd, + "no neighbor WORD interface remote-as (" CMD_AS_RANGE "|internal|external)", + NO_STR + NEIGHBOR_STR + "Interface name\n" + "Configure BGP on interface\n" + AS_STR) + +ALIAS (no_neighbor_interface_config, + no_neighbor_interface_config_v6only_remote_as_cmd, + "no neighbor WORD interface v6only remote-as (" CMD_AS_RANGE "|internal|external)", + NO_STR + NEIGHBOR_STR + "Interface name\n" + "Configure BGP on interface\n" + "Enable BGP with v6 link-local only\n" + AS_STR) DEFUN (no_neighbor_peer_group, no_neighbor_peer_group_cmd, @@ -4434,6 +4530,9 @@ peer_ebgp_multihop_set_vty (struct vty *vty, const char *ip_str, if (! peer) return CMD_WARNING; + if (peer->conf_if) + return bgp_vty_return (vty, BGP_ERR_INVALID_FOR_DIRECT_PEER); + if (! ttl_str) ttl = MAXTTL; else @@ -12982,7 +13081,7 @@ DEFUN (show_ip_bgp_attr_info, static int bgp_show_update_groups(struct vty *vty, const char *name, int afi, int safi, - u_int64_t subgrp_id) + uint64_t subgrp_id) { struct bgp *bgp; @@ -13109,7 +13208,7 @@ DEFUN (show_ip_bgp_updgrps_s, "Detailed info about dynamic update groups\n" "Specific subgroup to display detailed info for\n") { - u_int64_t subgrp_id; + uint64_t subgrp_id; VTY_GET_ULL("subgroup-id", subgrp_id, argv[0]); return (bgp_show_update_groups(vty, NULL, AFI_IP, SAFI_UNICAST, subgrp_id)); @@ -13125,7 +13224,7 @@ DEFUN (show_ip_bgp_instance_updgrps_s, "Detailed info about dynamic update groups\n" "Specific subgroup to display detailed info for\n") { - u_int64_t subgrp_id; + uint64_t subgrp_id; VTY_GET_ULL("subgroup-id", subgrp_id, argv[2]); return (bgp_show_update_groups(vty, argv[1], AFI_IP, SAFI_UNICAST, subgrp_id)); @@ -13139,7 +13238,7 @@ DEFUN (show_bgp_ipv6_updgrps_s, "Detailed info about v6 dynamic update groups\n" "Specific subgroup to display detailed info for\n") { - u_int64_t subgrp_id; + uint64_t subgrp_id; VTY_GET_ULL("subgroup-id", subgrp_id, argv[0]); return(bgp_show_update_groups(vty, NULL, AFI_IP6, SAFI_UNICAST, subgrp_id)); @@ -13153,7 +13252,7 @@ DEFUN (show_bgp_instance_ipv6_updgrps_s, "Detailed info about v6 dynamic update groups\n" "Specific subgroup to display detailed info for\n") { - u_int64_t subgrp_id; + uint64_t subgrp_id; VTY_GET_ULL("subgroup-id", subgrp_id, argv[2]); return(bgp_show_update_groups(vty, argv[1], AFI_IP6, SAFI_UNICAST, subgrp_id)); @@ -13173,7 +13272,7 @@ DEFUN (show_bgp_updgrps_s, { afi_t afi; safi_t safi; - u_int64_t subgrp_id; + uint64_t subgrp_id; afi = (strcmp(argv[0], "ipv4") == 0) ? AFI_IP : AFI_IP6; safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; @@ -13220,7 +13319,7 @@ DEFUN (show_bgp_instance_updgrps_stats, static void show_bgp_updgrps_adj_info_aux (struct vty *vty, const char *name, afi_t afi, safi_t safi, - const char *what, u_int64_t subgrp_id) + const char *what, uint64_t subgrp_id) { struct bgp *bgp; @@ -13339,7 +13438,7 @@ DEFUN (show_ip_bgp_updgrps_adj_s, "Packet queue\n") { - u_int64_t subgrp_id; + uint64_t subgrp_id; VTY_GET_ULL("subgroup-id", subgrp_id, argv[0]); @@ -13361,7 +13460,7 @@ DEFUN (show_ip_bgp_instance_updgrps_adj_s, "Packet queue\n") { - u_int64_t subgrp_id; + uint64_t subgrp_id; VTY_GET_ULL("subgroup-id", subgrp_id, argv[2]); @@ -13387,7 +13486,7 @@ DEFUN (show_bgp_updgrps_afi_adj_s, { afi_t afi; safi_t safi; - u_int64_t subgrp_id; + uint64_t subgrp_id; afi = (strcmp(argv[0], "ipv4") == 0) ? AFI_IP : AFI_IP6; safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; @@ -13408,7 +13507,7 @@ DEFUN (show_bgp_updgrps_adj_s, "Announced routes\n" "Packet queue\n") { - u_int64_t subgrp_id; + uint64_t subgrp_id; VTY_GET_ULL("subgroup-id", subgrp_id, argv[0]); @@ -13428,7 +13527,7 @@ DEFUN (show_bgp_instance_updgrps_adj_s, "Announced routes\n" "Packet queue\n") { - u_int64_t subgrp_id; + uint64_t subgrp_id; VTY_GET_ULL("subgroup-id", subgrp_id, argv[2]); @@ -13569,7 +13668,7 @@ bgp_show_peer_group (struct vty *vty, struct bgp *bgp, } if (type == show_peer_group && ! find) - vty_out (vty, "%% No such peer-groupr%s", VTY_NEWLINE); + vty_out (vty, "%% No such peer-group%s", VTY_NEWLINE); return CMD_SUCCESS; } @@ -14376,13 +14475,12 @@ bgp_vty_init (void) /* "no router bgp" commands. */ install_element (CONFIG_NODE, &no_router_bgp_cmd); install_element (CONFIG_NODE, &no_router_bgp_instance_cmd); + install_element (CONFIG_NODE, &no_router_bgp_noasn_cmd); /* "bgp router-id" commands. */ install_element (BGP_NODE, &bgp_router_id_cmd); install_element (BGP_NODE, &no_bgp_router_id_cmd); install_element (BGP_NODE, &no_bgp_router_id_val_cmd); - install_element (BGP_NODE, &bgp_router_id_interface_cmd); - install_element (BGP_NODE, &no_bgp_router_id_interface_cmd); /* "bgp cluster-id" commands. */ install_element (BGP_NODE, &bgp_cluster_id_cmd); @@ -14481,6 +14579,9 @@ bgp_vty_init (void) install_element (BGP_NODE, &bgp_graceful_restart_stalepath_time_cmd); install_element (BGP_NODE, &no_bgp_graceful_restart_stalepath_time_cmd); install_element (BGP_NODE, &no_bgp_graceful_restart_stalepath_time_val_cmd); + install_element (BGP_NODE, &bgp_graceful_restart_restart_time_cmd); + install_element (BGP_NODE, &no_bgp_graceful_restart_restart_time_cmd); + install_element (BGP_NODE, &no_bgp_graceful_restart_restart_time_val_cmd); /* "bgp fast-external-failover" commands */ install_element (BGP_NODE, &bgp_fast_external_failover_cmd); @@ -14560,12 +14661,16 @@ bgp_vty_init (void) install_element (BGP_NODE, &neighbor_interface_config_v6only_cmd); install_element (BGP_NODE, &neighbor_interface_config_peergroup_cmd); install_element (BGP_NODE, &neighbor_interface_config_v6only_peergroup_cmd); + install_element (BGP_NODE, &neighbor_interface_config_remote_as_cmd); + install_element (BGP_NODE, &neighbor_interface_v6only_config_remote_as_cmd); install_element (BGP_NODE, &no_neighbor_cmd); install_element (BGP_NODE, &no_neighbor_remote_as_cmd); install_element (BGP_NODE, &no_neighbor_interface_config_cmd); install_element (BGP_NODE, &no_neighbor_interface_config_v6only_cmd); install_element (BGP_NODE, &no_neighbor_interface_config_peergroup_cmd); install_element (BGP_NODE, &no_neighbor_interface_config_v6only_peergroup_cmd); + install_element (BGP_NODE, &no_neighbor_interface_config_remote_as_cmd); + install_element (BGP_NODE, &no_neighbor_interface_config_v6only_remote_as_cmd); /* "neighbor peer-group" commands. */ install_element (BGP_NODE, &neighbor_peer_group_cmd); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index ceded236cd..c2df521e79 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -32,6 +32,8 @@ Boston, MA 02111-1307, USA. */ #include "queue.h" #include "memory.h" #include "lib/json.h" +#include "lib/bfd.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_route.h" @@ -109,8 +111,6 @@ bgp_router_id_update (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct prefix router_id; - struct listnode *node, *nnode; - struct bgp *bgp; zebra_router_id_update_read(zclient->ibuf,&router_id); @@ -121,32 +121,7 @@ bgp_router_id_update (int command, struct zclient *zclient, zebra_size_t length, zlog_debug("Rx Router Id update VRF %u Id %s", vrf_id, buf); } - if (vrf_id == VRF_DEFAULT) - { - /* Router-id change for default VRF has to also update all views. */ - for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp)) - { - if (bgp->inst_type == BGP_INSTANCE_TYPE_VRF) - continue; - - bgp->router_id_zebra = router_id.u.prefix4; - - if (!bgp->router_id_static.s_addr) - bgp_router_id_set (bgp, &router_id.u.prefix4); - } - } - else - { - bgp = bgp_lookup_by_vrf_id (vrf_id); - if (bgp) - { - bgp->router_id_zebra = router_id.u.prefix4; - - if (!bgp->router_id_static.s_addr) - bgp_router_id_set (bgp, &router_id.u.prefix4); - } - } - + bgp_router_id_zebra_bump (vrf_id, &router_id); return 0; } @@ -385,7 +360,16 @@ bgp_interface_down (int command, struct zclient *zclient, zebra_size_t length, for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { +#if defined(HAVE_CUMULUS) + /* Take down directly connected EBGP peers as well as 1-hop BFD + * tracked (directly connected) IBGP peers. + */ + if ((peer->ttl != 1) && (peer->gtsm_hops != 1) && + (!peer->bfd_info || bgp_bfd_is_peer_multihop(peer))) +#else + /* Take down directly connected EBGP peers */ if ((peer->ttl != 1) && (peer->gtsm_hops != 1)) +#endif continue; if (ifp == peer->nexthop.ifp) @@ -882,7 +866,7 @@ if_lookup_by_ipv4_exact (struct in_addr *addr, vrf_id_t vrf_id) #ifdef HAVE_IPV6 struct interface * -if_lookup_by_ipv6 (struct in6_addr *addr, unsigned int ifindex, vrf_id_t vrf_id) +if_lookup_by_ipv6 (struct in6_addr *addr, ifindex_t ifindex, vrf_id_t vrf_id) { struct listnode *ifnode; struct listnode *cnode; @@ -904,7 +888,7 @@ if_lookup_by_ipv6 (struct in6_addr *addr, unsigned int ifindex, vrf_id_t vrf_id) if (cp->family == AF_INET6) if (prefix_match (cp, (struct prefix *)&p)) { - if (IN6_IS_ADDR_LINKLOCAL(&cp->u.prefix6.s6_addr32[0])) + if (IN6_IS_ADDR_LINKLOCAL(&cp->u.prefix6)) { if (ifindex == ifp->ifindex) return ifp; @@ -918,7 +902,7 @@ if_lookup_by_ipv6 (struct in6_addr *addr, unsigned int ifindex, vrf_id_t vrf_id) } struct interface * -if_lookup_by_ipv6_exact (struct in6_addr *addr, unsigned int ifindex, vrf_id_t vrf_id) +if_lookup_by_ipv6_exact (struct in6_addr *addr, ifindex_t ifindex, vrf_id_t vrf_id) { struct listnode *ifnode; struct listnode *cnode; @@ -1163,12 +1147,18 @@ bgp_info_to_ipv6_nexthop (struct bgp_info *info) /* If both global and link-local address present. */ if (info->attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) { - /* Workaround for Cisco's nexthop bug. */ - if (IN6_IS_ADDR_UNSPECIFIED (&info->attr->extra->mp_nexthop_global) - && info->peer->su_remote->sa.sa_family == AF_INET6) - nexthop = &info->peer->su_remote->sin6.sin6_addr; + /* Check if route-map is set to prefer global over link-local */ + if (info->attr->extra->mp_nexthop_prefer_global) + nexthop = &info->attr->extra->mp_nexthop_global; else - nexthop = &info->attr->extra->mp_nexthop_local; + { + /* Workaround for Cisco's nexthop bug. */ + if (IN6_IS_ADDR_UNSPECIFIED (&info->attr->extra->mp_nexthop_global) + && info->peer->su_remote->sa.sa_family == AF_INET6) + nexthop = &info->peer->su_remote->sin6.sin6_addr; + else + nexthop = &info->attr->extra->mp_nexthop_local; + } } return nexthop; @@ -1401,7 +1391,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, if (p->family == AF_INET6 || (p->family == AF_INET && BGP_ATTR_NEXTHOP_AFI_IP6(info->attr))) { - unsigned int ifindex; + ifindex_t ifindex; struct in6_addr *nexthop; struct zapi_ipv6 api; int valid_nh_count = 0; @@ -1547,7 +1537,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, api.nexthop = (struct in6_addr **)STREAM_DATA (bgp_nexthop_buf); SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX); api.ifindex_num = valid_nh_count; - api.ifindex = (unsigned int *)STREAM_DATA (bgp_ifindices_buf); + api.ifindex = (ifindex_t *)STREAM_DATA (bgp_ifindices_buf); SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = metric; api.tag = 0; @@ -1891,16 +1881,30 @@ bgp_redistribute_metric_set (struct bgp *bgp, struct bgp_redist *red, afi_t afi, red->redist_metric_flag = 1; red->redist_metric = metric; - for (rn = bgp_table_top(bgp->rib[afi][SAFI_UNICAST]); rn; rn = bgp_route_next(rn)) { - for (ri = rn->info; ri; ri = ri->next) { - if (ri->sub_type == BGP_ROUTE_REDISTRIBUTE && ri->type == type && - ri->instance == red->instance) { - ri->attr->med = red->redist_metric; - bgp_info_set_flag(rn, ri, BGP_INFO_ATTR_CHANGED); - bgp_process(bgp, rn, afi, SAFI_UNICAST); - } + for (rn = bgp_table_top(bgp->rib[afi][SAFI_UNICAST]); rn; rn = bgp_route_next(rn)) + { + for (ri = rn->info; ri; ri = ri->next) + { + if (ri->sub_type == BGP_ROUTE_REDISTRIBUTE && + ri->type == type && + ri->instance == red->instance) + { + struct attr *old_attr; + struct attr new_attr; + struct attr_extra new_extra; + + new_attr.extra = &new_extra; + bgp_attr_dup (&new_attr, ri->attr); + new_attr.med = red->redist_metric; + old_attr = ri->attr; + ri->attr = bgp_attr_intern (&new_attr); + bgp_attr_unintern (&old_attr); + + bgp_info_set_flag(rn, ri, BGP_INFO_ATTR_CHANGED); + bgp_process(bgp, rn, afi, SAFI_UNICAST); + } + } } - } return 1; } @@ -1972,6 +1976,24 @@ bgp_redistribute_unset (struct bgp *bgp, afi_t afi, int type, u_short instance) return CMD_SUCCESS; } +/* Update redistribute vrf bitmap during triggers like + restart networking or delete/add VRFs */ +void +bgp_update_redist_vrf_bitmaps (struct bgp *bgp, vrf_id_t old_vrf_id) +{ + int i; + afi_t afi; + + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + if (vrf_bitmap_check (zclient->redist[afi][i], old_vrf_id)) + { + vrf_bitmap_unset (zclient->redist[afi][i], old_vrf_id); + vrf_bitmap_set (zclient->redist[afi][i], bgp->vrf_id); + } + return; +} + void bgp_zclient_reset (void) { @@ -2057,6 +2079,9 @@ bgp_zebra_connected (struct zclient *zclient) bgp_zebra_instance_register (bgp); + /* Send the client registration */ + bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER); + /* TODO - What if we have peers and networks configured, do we have to * kick-start them? */ diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index 1f845bd918..af921af82f 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -58,8 +58,8 @@ extern int bgp_redistribute_unreg (struct bgp *, afi_t, int, u_short); extern struct interface *if_lookup_by_ipv4 (struct in_addr *, vrf_id_t); extern struct interface *if_lookup_by_ipv4_exact (struct in_addr *, vrf_id_t); #ifdef HAVE_IPV6 -extern struct interface *if_lookup_by_ipv6 (struct in6_addr *, unsigned int, vrf_id_t); -extern struct interface *if_lookup_by_ipv6_exact (struct in6_addr *, unsigned int, vrf_id_t); +extern struct interface *if_lookup_by_ipv6 (struct in6_addr *, ifindex_t, vrf_id_t); +extern struct interface *if_lookup_by_ipv6_exact (struct in6_addr *, ifindex_t, vrf_id_t); #endif /* HAVE_IPV6 */ #endif /* _QUAGGA_BGP_ZEBRA_H */ diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 243e800a89..bfde53d3e4 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -209,8 +209,8 @@ bgp_config_check (struct bgp *bgp, int config) } /* Set BGP router identifier. */ -int -bgp_router_id_set (struct bgp *bgp, struct in_addr *id) +static int +bgp_router_id_set (struct bgp *bgp, const struct in_addr *id) { struct peer *peer; struct listnode *node, *nnode; @@ -235,6 +235,46 @@ bgp_router_id_set (struct bgp *bgp, struct in_addr *id) return 0; } +void +bgp_router_id_zebra_bump (vrf_id_t vrf_id, const struct prefix *router_id) +{ + struct listnode *node, *nnode; + struct bgp *bgp; + + if (vrf_id == VRF_DEFAULT) + { + /* Router-id change for default VRF has to also update all views. */ + for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp)) + { + if (bgp->inst_type == BGP_INSTANCE_TYPE_VRF) + continue; + + bgp->router_id_zebra = router_id->u.prefix4; + if (!bgp->router_id_static.s_addr) + bgp_router_id_set (bgp, &router_id->u.prefix4); + } + } + else + { + bgp = bgp_lookup_by_vrf_id (vrf_id); + if (bgp) + { + bgp->router_id_zebra = router_id->u.prefix4; + + if (!bgp->router_id_static.s_addr) + bgp_router_id_set (bgp, &router_id->u.prefix4); + } + } +} + +int +bgp_router_id_static_set (struct bgp *bgp, struct in_addr id) +{ + bgp->router_id_static = id; + bgp_router_id_set (bgp, id.s_addr ? &id : &bgp->router_id_zebra); + return 0; +} + /* BGP's cluster-id control. */ int bgp_cluster_id_set (struct bgp *bgp, struct in_addr *cluster_id) @@ -1255,7 +1295,7 @@ bgp_peer_conf_if_to_su_update_v4 (struct peer *peer, struct interface *ifp) { struct connected *ifc; struct prefix p; - u_int32_t s_addr; + u_int32_t addr; struct listnode *node; /* If our IPv4 address on the interface is /30 or /31, we can derive the @@ -1269,26 +1309,26 @@ bgp_peer_conf_if_to_su_update_v4 (struct peer *peer, struct interface *ifp) if (p.prefixlen == 30) { peer->su.sa.sa_family = AF_INET; - s_addr = ntohl(p.u.prefix4.s_addr); - if (s_addr % 4 == 1) - peer->su.sin.sin_addr.s_addr = htonl(s_addr+1); - else if (s_addr % 4 == 2) - peer->su.sin.sin_addr.s_addr = htonl(s_addr-1); + addr = ntohl(p.u.prefix4.s_addr); + if (addr % 4 == 1) + peer->su.sin.sin_addr.s_addr = htonl(addr+1); + else if (addr % 4 == 2) + peer->su.sin.sin_addr.s_addr = htonl(addr-1); #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - peer->su->sin.sin_len = sizeof(struct sockaddr_in); + peer->su.sin.sin_len = sizeof(struct sockaddr_in); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ return 1; } else if (p.prefixlen == 31) { peer->su.sa.sa_family = AF_INET; - s_addr = ntohl(p.u.prefix4.s_addr); - if (s_addr % 2 == 0) - peer->su.sin.sin_addr.s_addr = htonl(s_addr+1); + addr = ntohl(p.u.prefix4.s_addr); + if (addr % 2 == 0) + peer->su.sin.sin_addr.s_addr = htonl(addr+1); else - peer->su.sin.sin_addr.s_addr = htonl(s_addr-1); + peer->su.sin.sin_addr.s_addr = htonl(addr-1); #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - peer->su->sin.sin_len = sizeof(struct sockaddr_in); + peer->su.sin.sin_len = sizeof(struct sockaddr_in); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ return 1; } @@ -1827,6 +1867,15 @@ peer_deactivate (struct peer *peer, afi_t afi, safi_t safi) return ret; } +int +peer_afc_set (struct peer *peer, afi_t afi, safi_t safi, int enable) +{ + if (enable) + return peer_activate (peer, afi, safi); + else + return peer_deactivate (peer, afi, safi); +} + static void peer_nsf_stop (struct peer *peer) { @@ -2546,6 +2595,7 @@ peer_group_bind (struct bgp *bgp, union sockunion *su, struct peer *peer, int first_member = 0; afi_t afi; safi_t safi; + int cap_enhe_preset = 0; /* Lookup the peer. */ if (!peer) @@ -2580,8 +2630,18 @@ peer_group_bind (struct bgp *bgp, union sockunion *su, struct peer *peer, first_member = 1; } + if (CHECK_FLAG (peer->flags, PEER_FLAG_CAPABILITY_ENHE)) + cap_enhe_preset = 1; + peer_group2peer_config_copy(group, peer); + /* + * Capability extended-nexthop is enabled for an interface neighbor by + * default. So, fix that up here. + */ + if (peer->ifp && cap_enhe_preset) + peer_flag_set (peer, PEER_FLAG_CAPABILITY_ENHE); + for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { @@ -3167,6 +3227,8 @@ bgp_free (struct bgp *bgp) bgp_table_finish (&bgp->rib[afi][safi]); } + bgp_address_destroy (bgp); + /* If Default instance or VRF, unlink from the VRF structure. */ vrf = bgp_vrf_lookup_by_instance_type (bgp); if (vrf) @@ -4078,7 +4140,7 @@ peer_ebgp_multihop_unset (struct peer *peer) /* Neighbor description. */ int -peer_description_set (struct peer *peer, char *desc) +peer_description_set (struct peer *peer, const char *desc) { if (peer->desc) XFREE (MTYPE_PEER_DESC, peer->desc); @@ -4171,7 +4233,7 @@ peer_update_source_if_set (struct peer *peer, const char *ifname) } int -peer_update_source_addr_set (struct peer *peer, union sockunion *su) +peer_update_source_addr_set (struct peer *peer, const union sockunion *su) { struct peer_group *group; struct listnode *node, *nnode; @@ -6269,6 +6331,8 @@ bgp_config_write_peer_global (struct vty *vty, struct bgp *bgp, struct peer *g_peer = NULL; char buf[SU_ADDRSTRLEN]; char *addr; + int if_pg_printed = FALSE; + int if_ras_printed = FALSE; /* Skip dynamic neighbors. */ if (peer_dynamic_neighbor (peer)) @@ -6290,7 +6354,25 @@ bgp_config_write_peer_global (struct vty *vty, struct bgp *bgp, vty_out (vty, " neighbor %s interface", addr); if (peer_group_active (peer)) - vty_out (vty, " peer-group %s", peer->group->name); + { + vty_out (vty, " peer-group %s", peer->group->name); + if_pg_printed = TRUE; + } + else if (peer->as_type == AS_SPECIFIED) + { + vty_out (vty, " remote-as %u", peer->as); + if_ras_printed = TRUE; + } + else if (peer->as_type == AS_INTERNAL) + { + vty_out (vty, " remote-as internal"); + if_ras_printed = TRUE; + } + else if (peer->as_type == AS_EXTERNAL) + { + vty_out (vty, " remote-as external"); + if_ras_printed = TRUE; + } vty_out (vty, "%s", VTY_NEWLINE); } @@ -6301,7 +6383,7 @@ bgp_config_write_peer_global (struct vty *vty, struct bgp *bgp, { g_peer = peer->group->conf; - if (g_peer->as_type == AS_UNSPECIFIED) + if (g_peer->as_type == AS_UNSPECIFIED && !if_ras_printed) { if (peer->as_type == AS_SPECIFIED) { @@ -6320,7 +6402,7 @@ bgp_config_write_peer_global (struct vty *vty, struct bgp *bgp, /* For swpX peers we displayed the peer-group * via 'neighbor swpX interface peer-group WORD' */ - if (!peer->conf_if) + if (!if_pg_printed) vty_out (vty, " neighbor %s peer-group %s%s", addr, peer->group->name, VTY_NEWLINE); } @@ -6335,18 +6417,21 @@ bgp_config_write_peer_global (struct vty *vty, struct bgp *bgp, VTY_NEWLINE); } - if (peer->as_type == AS_SPECIFIED) + if (!if_ras_printed) { - vty_out (vty, " neighbor %s remote-as %u%s", addr, peer->as, - VTY_NEWLINE); - } - else if (peer->as_type == AS_INTERNAL) - { - vty_out (vty, " neighbor %s remote-as internal%s", addr, VTY_NEWLINE); - } - else if (peer->as_type == AS_EXTERNAL) - { - vty_out (vty, " neighbor %s remote-as external%s", addr, VTY_NEWLINE); + if (peer->as_type == AS_SPECIFIED) + { + vty_out (vty, " neighbor %s remote-as %u%s", addr, peer->as, + VTY_NEWLINE); + } + else if (peer->as_type == AS_INTERNAL) + { + vty_out (vty, " neighbor %s remote-as internal%s", addr, VTY_NEWLINE); + } + else if (peer->as_type == AS_EXTERNAL) + { + vty_out (vty, " neighbor %s remote-as external%s", addr, VTY_NEWLINE); + } } } @@ -6541,7 +6626,17 @@ bgp_config_write_peer_global (struct vty *vty, struct bgp *bgp, } /* capability extended-nexthop */ - if (CHECK_FLAG (peer->flags, PEER_FLAG_CAPABILITY_ENHE)) + if (peer->ifp && !CHECK_FLAG (peer->flags, PEER_FLAG_CAPABILITY_ENHE)) + { + if (! peer_group_active (peer) || + ! CHECK_FLAG (g_peer->flags, PEER_FLAG_CAPABILITY_ENHE)) + { + vty_out (vty, " no neighbor %s capability extended-nexthop%s", addr, + VTY_NEWLINE); + } + } + + if (!peer->ifp && CHECK_FLAG (peer->flags, PEER_FLAG_CAPABILITY_ENHE)) { if (! peer_group_active (peer) || ! CHECK_FLAG (g_peer->flags, PEER_FLAG_CAPABILITY_ENHE)) @@ -6630,10 +6725,32 @@ bgp_config_write_peer_af (struct vty *vty, struct bgp *bgp, { if (peer->afc[afi][safi]) { - afi_header_vty_out (vty, afi, safi, write, - " neighbor %s activate%s", - addr, VTY_NEWLINE); + if ((afi == AFI_IP) && (safi == SAFI_UNICAST)) + { + if (bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4)) + { + afi_header_vty_out(vty, afi, safi, write, + " neighbor %s activate%s", + addr, VTY_NEWLINE); + } + } + else + afi_header_vty_out (vty, afi, safi, write, + " neighbor %s activate%s", + addr, VTY_NEWLINE); } + else + { + if ((afi == AFI_IP) && (safi == SAFI_UNICAST)) + { + if (!bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4)) + { + afi_header_vty_out (vty, afi, safi, write, + " no neighbor %s activate%s", + addr, VTY_NEWLINE); + } + } + } } /* addpath TX knobs */ @@ -7116,6 +7233,9 @@ bgp_config_write (struct vty *vty) if (bgp->stalepath_time != BGP_DEFAULT_STALEPATH_TIME) vty_out (vty, " bgp graceful-restart stalepath-time %d%s", bgp->stalepath_time, VTY_NEWLINE); + if (bgp->restart_time != BGP_DEFAULT_RESTART_TIME) + vty_out (vty, " bgp graceful-restart restart-time %d%s", + bgp->restart_time, VTY_NEWLINE); if (bgp_flag_check (bgp, BGP_FLAG_GRACEFUL_RESTART)) vty_out (vty, " bgp graceful-restart%s", VTY_NEWLINE); @@ -7216,8 +7336,6 @@ bgp_config_write (struct vty *vty) /* ENCAPv6 configuration. */ write += bgp_config_write_family (vty, bgp, AFI_IP6, SAFI_ENCAP); - vty_out (vty, " exit%s", VTY_NEWLINE); - write++; } return write; diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 0c6aa6b21a..e8827ca91f 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -112,8 +112,8 @@ struct bgp_master #define BGP_OPT_CONFIG_CISCO (1 << 2) #define BGP_OPT_NO_LISTEN (1 << 3) - u_int64_t updgrp_idspace; - u_int64_t subgrp_idspace; + uint64_t updgrp_idspace; + uint64_t subgrp_idspace; /* timer to dampen route map changes */ struct thread *t_rmap_update; /* Handle route map updates */ @@ -518,7 +518,7 @@ struct peer /* BGP peer group. */ struct peer_group *group; - u_int64_t version[AFI_MAX][SAFI_MAX]; + uint64_t version[AFI_MAX][SAFI_MAX]; /* BGP peer_af structures, per configured AF on this peer */ struct peer_af *peer_af_array[BGP_AF_MAX]; @@ -583,7 +583,7 @@ struct peer time_t readtime; /* Last read time */ time_t resettime; /* Last reset time */ - unsigned int ifindex; /* ifindex of the BGP connection. */ + ifindex_t ifindex; /* ifindex of the BGP connection. */ char *conf_if; /* neighbor interface config name. */ struct interface *ifp; /* corresponding interface */ char *ifname; /* bind interface name. */ @@ -1120,6 +1120,7 @@ enum bgp_clear_type #define BGP_ERR_DYNAMIC_NEIGHBORS_RANGE_NOT_FOUND -31 #define BGP_ERR_INVALID_FOR_DYNAMIC_PEER -32 #define BGP_ERR_MAX -33 +#define BGP_ERR_INVALID_FOR_DIRECT_PEER -34 /* * Enumeration of different policy kinds a peer can be configured with. @@ -1207,7 +1208,8 @@ extern int bgp_flag_check (struct bgp *, int); extern void bgp_lock (struct bgp *); extern void bgp_unlock (struct bgp *); -extern int bgp_router_id_set (struct bgp *, struct in_addr *); +extern void bgp_router_id_zebra_bump (vrf_id_t, const struct prefix*); +extern int bgp_router_id_static_set (struct bgp *, struct in_addr); extern int bgp_cluster_id_set (struct bgp *, struct in_addr *); extern int bgp_cluster_id_unset (struct bgp *); @@ -1219,7 +1221,7 @@ extern int bgp_confederation_peers_check (struct bgp *, as_t); extern int bgp_confederation_peers_add (struct bgp *, as_t); extern int bgp_confederation_peers_remove (struct bgp *, as_t); -extern int bgp_timers_set (struct bgp *, u_int32_t, u_int32_t); +extern int bgp_timers_set (struct bgp *, u_int32_t keepalive, u_int32_t holdtime); extern int bgp_timers_unset (struct bgp *); extern int bgp_default_local_preference_set (struct bgp *, u_int32_t); @@ -1244,6 +1246,7 @@ extern int peer_group_listen_range_add(struct peer_group *, struct prefix *); extern int peer_activate (struct peer *, afi_t, safi_t); extern int peer_deactivate (struct peer *, afi_t, safi_t); +extern int peer_afc_set (struct peer *, afi_t, safi_t, int); extern int peer_group_bind (struct bgp *, union sockunion *, struct peer *, struct peer_group *, as_t *); @@ -1260,11 +1263,11 @@ extern int peer_ebgp_multihop_set (struct peer *, int); extern int peer_ebgp_multihop_unset (struct peer *); extern int is_ebgp_multihop_configured (struct peer *peer); -extern int peer_description_set (struct peer *, char *); +extern int peer_description_set (struct peer *, const char *); extern int peer_description_unset (struct peer *); extern int peer_update_source_if_set (struct peer *, const char *); -extern int peer_update_source_addr_set (struct peer *, union sockunion *); +extern int peer_update_source_addr_set (struct peer *, const union sockunion *); extern int peer_update_source_unset (struct peer *); extern int peer_default_originate_set (struct peer *, afi_t, safi_t, const char *); @@ -1276,7 +1279,7 @@ extern int peer_port_unset (struct peer *); extern int peer_weight_set (struct peer *, u_int16_t); extern int peer_weight_unset (struct peer *); -extern int peer_timers_set (struct peer *, u_int32_t, u_int32_t); +extern int peer_timers_set (struct peer *, u_int32_t keepalive, u_int32_t holdtime); extern int peer_timers_unset (struct peer *); extern int peer_timers_connect_set (struct peer *, u_int32_t); @@ -1501,4 +1504,5 @@ bgp_vrf_unlink (struct bgp *bgp, struct vrf *vrf) bgp->vrf_id = VRF_UNKNOWN; } +extern void bgp_update_redist_vrf_bitmaps (struct bgp*, vrf_id_t); #endif /* _QUAGGA_BGPD_H */ diff --git a/configure.ac b/configure.ac index cb4c8724f1..8a1131d347 100755 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ ## AC_PREREQ(2.60) -AC_INIT(Quagga, 0.99.24+cl3u2, [https://bugzilla.quagga.net]) +AC_INIT(Quagga, 0.99.24+cl3u3, [https://bugzilla.quagga.net]) CONFIG_ARGS="$*" AC_SUBST(CONFIG_ARGS) AC_CONFIG_SRCDIR(lib/zebra.h) @@ -21,6 +21,7 @@ AC_CANONICAL_HOST() AC_CANONICAL_TARGET() AM_INIT_AUTOMAKE(1.6) +m4_ifndef([AM_SILENT_RULES], [m4_define([AM_SILENT_RULES],[])]) AM_SILENT_RULES([yes]) AC_CONFIG_HEADERS(config.h) @@ -265,15 +266,11 @@ AC_ARG_WITH(libpam, AS_HELP_STRING([--with-libpam], [use libpam for PAM support in vtysh])) AC_ARG_ENABLE(tcp-zebra, AS_HELP_STRING([--enable-tcp-zebra], [enable TCP/IP socket connection between zebra and protocol daemon])) -AC_ARG_ENABLE(opaque-lsa, - AS_HELP_STRING([--disable-opaque-lsa],[do not build OSPF Opaque-LSA with OSPFAPI support (RFC2370)])) AC_ARG_ENABLE(ospfapi, AS_HELP_STRING([--disable-ospfapi], [do not build OSPFAPI to access the OSPF LSA Database])) AC_ARG_ENABLE(ospfclient, AS_HELP_STRING([--disable-ospfclient], [do not build OSPFAPI client for OSPFAPI, (this is the default if --disable-ospfapi is set)])) -AC_ARG_ENABLE(ospf-te, - AS_HELP_STRING([--disable-ospf-te],[disable Traffic Engineering Extension to OSPF])) AC_ARG_ENABLE(multipath, AS_HELP_STRING([--enable-multipath=ARG], [enable multipath function, ARG must be digit])) AC_ARG_ENABLE(user, @@ -320,13 +317,18 @@ AC_ARG_ENABLE(werror, AS_HELP_STRING([--enable-werror], [enable -Werror (recommended for developers only)])) AC_ARG_ENABLE(cumulus, AS_HELP_STRING([--enable-cumulus], [enable Cumulus Switch Special Extensions])) +AC_ARG_ENABLE(bgp-standalone, + AS_HELP_STRING([--enable-bgp-standalone], [Modify code to allow BGP to work without Zebra])) AC_ARG_ENABLE(rr-semantics, AS_HELP_STRING([--disable-rr-semantics], [disable the v6 Route Replace semantics])) AC_CHECK_HEADERS(json-c/json.h) AC_CHECK_LIB(json-c, json_object_get, LIBS="$LIBS -ljson-c") if test $ac_cv_lib_json_c_json_object_get = no; then - AC_MSG_ERROR([lib json is needed to compile]) + AC_CHECK_LIB(json, json_object_get, LIBS="$LIBS -ljson") + if test $ac_cv_lib_json_json_object_get = no; then + AC_MSG_ERROR([lib json is needed to compile]) + fi fi if test x"${enable_gcc_rdynamic}" != x"no" ; then @@ -368,6 +370,10 @@ if test "${enable_cumulus}" = "yes" ; then AC_DEFINE(HAVE_CUMULUS,,Compile Special Cumulus Code in) fi +if test "${enable_bgp_standalone}" = "yes" ; then + AC_DEFINE(HAVE_BGP_STANDALONE,,Allow BGP to work without Zebra) +fi + if test "${enable_shell_access}" = "yes"; then AC_DEFINE(HAVE_SHELL_ACCESS,,Allow user to use ssh/telnet/bash) fi @@ -380,15 +386,6 @@ if test "${enable_tcp_zebra}" = "yes"; then AC_DEFINE(HAVE_TCP_ZEBRA,,Use TCP for zebra communication) fi -if test "${enable_opaque_lsa}" != "no"; then - AC_DEFINE(HAVE_OPAQUE_LSA,,OSPF Opaque LSA) -fi - -if test "${enable_ospf_te}" != "no"; then - AC_DEFINE(HAVE_OPAQUE_LSA,,OSPF Opaque LSA) - AC_DEFINE(HAVE_OSPF_TE,,OSPF TE) -fi - if test "${enable_linux24_tcp_md5}" = "yes"; then AC_DEFINE(HAVE_TCP_MD5_LINUX24,,Old Linux 2.4 TCP MD5 Signature Patch) fi @@ -416,16 +413,22 @@ AC_SUBST(ISIS_TOPOLOGY_INCLUDES) AC_SUBST(ISIS_TOPOLOGY_DIR) AC_SUBST(ISIS_TOPOLOGY_LIB) -if test "${enable_user}" = "yes" || test x"${enable_user}" = x""; then - enable_user="quagga" -elif test "${enable_user}" = "no"; then - enable_user="root" +if test x"${enable_user}" = x"no"; then + enable_user="" +else + if test x"${enable_user}" = x"yes" || test x"${enable_user}" = x""; then + enable_user="quagga" + fi + AC_DEFINE_UNQUOTED(QUAGGA_USER, "${enable_user}", Quagga User) fi -if test "${enable_group}" = "yes" || test x"${enable_group}" = x""; then - enable_group="quagga" -elif test "${enable_group}" = "no"; then - enable_group="root" +if test x"${enable_group}" = x"no"; then + enable_group="" +else + if test x"${enable_group}" = x"yes" || test x"${enable_group}" = x""; then + enable_group="quagga" + fi + AC_DEFINE_UNQUOTED(QUAGGA_GROUP, "${enable_group}", Quagga Group) fi if test x"${enable_vty_group}" = x"yes" ; then @@ -438,8 +441,6 @@ fi AC_SUBST([enable_user]) AC_SUBST([enable_group]) AC_SUBST([enable_vty_group]) -AC_DEFINE_UNQUOTED(QUAGGA_USER, "${enable_user}", Quagga User) -AC_DEFINE_UNQUOTED(QUAGGA_GROUP, "${enable_group}", Quagga Group) enable_configfile_mask=${enable_configfile_mask:-0600} AC_DEFINE_UNQUOTED(CONFIGFILE_MASK, ${enable_configfile_mask}, Mask for config files) @@ -710,7 +711,7 @@ dnl [TODO] on Linux, and in [TODO] on Solaris. )] )] ) - AC_CHECK_LIB(readline, main, LIBREADLINE="$LIBREADLINE -lreadline",, + AC_CHECK_LIB(readline, main, LIBREADLINE="-lreadline $LIBREADLINE",, "$LIBREADLINE") if test $ac_cv_lib_readline_main = no; then AC_MSG_ERROR([vtysh needs libreadline but was not found and usable on your system.]) @@ -851,6 +852,14 @@ AC_CHECK_FUNCS([dup2 ftruncate getcwd gethostbyname getpagesize gettimeofday \ if_nametoindex if_indextoname getifaddrs \ uname fcntl getgrouplist]) +AC_CHECK_HEADER([asm-generic/unistd.h], + [AC_CHECK_DECL(__NR_setns, + AC_DEFINE(HAVE_NETNS,, Have netns),, + QUAGGA_INCLUDES [#include + ]) + AC_CHECK_FUNCS(setns, AC_DEFINE(HAVE_SETNS,, Have setns))] + ) + dnl ------------------------------------ dnl Determine routing get and set method dnl ------------------------------------ @@ -993,11 +1002,46 @@ dnl figure out how to specify an interface in multicast sockets API dnl --------------------------------------------------------------- AC_CHECK_MEMBERS([struct ip_mreqn.imr_ifindex], [], [], QUAGGA_INCLUDES) -AC_CHECK_HEADERS([linux/mroute.h], [], [], -[ -#if HAVE_NETINET_IN_H -#include -#endif]) +AC_CHECK_HEADERS([linux/mroute.h], [], [],[ + #ifdef HAVE_SYS_SOCKET_H + # include + #endif + #ifdef HAVE_NETINET_IN_H + # include + #endif + #define _LINUX_IN_H /* For Linux <= 2.6.25 */ + #include +]) + +m4_define([QUAGGA_INCLUDES], +QUAGGA_INCLUDES +[#if HAVE_LINUX_MROUTE_H +# include +#endif +])dnl + +AC_CHECK_HEADERS([netinet/ip_mroute.h], [], [],[ + #ifdef HAVE_SYS_SOCKET_H + # include + #endif + #ifdef HAVE_SYS_TYPES_H + # include + #endif + #ifdef HAVE_NETINET_IN_H + # include + #endif + #ifdef HAVE_NET_ROUTE_H + # include + #endif +]) + +m4_define([QUAGGA_INCLUDES], +QUAGGA_INCLUDES +[#if HAVE_NETINET_IP_MROUTE_H +# include +#endif +])dnl + AC_MSG_CHECKING([for BSD struct ip_mreq hack]) AC_TRY_COMPILE([#ifdef HAVE_SYS_PARAM_H #include @@ -1095,6 +1139,11 @@ AC_SUBST(IPFORWARD) AC_CHECK_FUNCS(getaddrinfo, [have_getaddrinfo=yes], [have_getaddrinfo=no]) +dnl ---------------------------------------------------------------------------- +dnl figure out if domainname is available in the utsname struct (GNU extension). +dnl ---------------------------------------------------------------------------- +AC_CHECK_MEMBERS([struct utsname.domainname], [], [], [#include ]) + dnl ---------- dnl IPv6 check dnl ---------- @@ -1202,16 +1251,14 @@ fi AM_CONDITIONAL(WATCHQUAGGA, test "x$WATCHQUAGGA" = "xwatchquagga") OSPFCLIENT="" -if test "${enable_opaque_lsa}" != "no"; then - if test "${enable_ospfapi}" != "no";then +if test "${enable_ospfapi}" != "no";then AC_DEFINE(SUPPORT_OSPF_API,,OSPFAPI) - if test "${enable_ospfclient}" != "no";then + if test "${enable_ospfclient}" != "no";then OSPFCLIENT="ospfclient" - fi fi - fi + AM_CONDITIONAL(OSPFCLIENT, test "x$OSPFCLIENT" = "xospfclient") case "${enable_ripngd}" in diff --git a/cumulus/etc/quagga/Quagga.conf b/cumulus/etc/quagga/Quagga.conf new file mode 100644 index 0000000000..e52f3f8aab --- /dev/null +++ b/cumulus/etc/quagga/Quagga.conf @@ -0,0 +1,2 @@ +log file /var/log/quagga/quagga.log +log timestamp precision 6 diff --git a/cumulus/etc/quagga/bgpd.conf b/cumulus/etc/quagga/bgpd.conf deleted file mode 100644 index 7c9c5ae286..0000000000 --- a/cumulus/etc/quagga/bgpd.conf +++ /dev/null @@ -1,3 +0,0 @@ -hostname bgpd -log timestamp precision 6 -log file /var/log/quagga/bgpd.log diff --git a/cumulus/etc/quagga/ospf6d.conf b/cumulus/etc/quagga/ospf6d.conf deleted file mode 100644 index 408ca1af1e..0000000000 --- a/cumulus/etc/quagga/ospf6d.conf +++ /dev/null @@ -1,3 +0,0 @@ -hostname ospfd -log timestamp precision 6 -log file /var/log/quagga/ospf6d.log diff --git a/cumulus/etc/quagga/ospfd.conf b/cumulus/etc/quagga/ospfd.conf deleted file mode 100644 index 8f2e53e030..0000000000 --- a/cumulus/etc/quagga/ospfd.conf +++ /dev/null @@ -1,3 +0,0 @@ -hostname ospfd -log timestamp precision 6 -log file /var/log/quagga/ospfd.log diff --git a/cumulus/etc/quagga/pimd.conf b/cumulus/etc/quagga/pimd.conf deleted file mode 100644 index 8aa1e7f5f0..0000000000 --- a/cumulus/etc/quagga/pimd.conf +++ /dev/null @@ -1,5 +0,0 @@ -hostname pimd -password cn321 -enable password cn321 -log timestamp precision 6 -log file /var/log/quagga/pimd.log diff --git a/cumulus/etc/quagga/zebra.conf b/cumulus/etc/quagga/zebra.conf deleted file mode 100644 index 67e4799413..0000000000 --- a/cumulus/etc/quagga/zebra.conf +++ /dev/null @@ -1,2 +0,0 @@ -hostname zebra -log file /var/log/quagga/zebra.log diff --git a/cumulus/start-stop-daemon.c b/cumulus/start-stop-daemon.c index ea63fbc217..4d447d9051 100644 --- a/cumulus/start-stop-daemon.c +++ b/cumulus/start-stop-daemon.c @@ -56,8 +56,9 @@ #include #include #include -#include +#ifdef linux #include +#endif static int testmode = 0; static int quietmode = 0; @@ -241,6 +242,7 @@ next_dirname(const char *s) return cur; } +#ifdef linux static void add_namespace(const char *path) { @@ -270,6 +272,7 @@ add_namespace(const char *path) namespace->nstype = nstype; LIST_INSERT_HEAD(&namespace_head, namespace, list); } +#endif #ifdef HAVE_LXC static void @@ -567,7 +570,9 @@ parse_options(int argc, char * const *argv) changeroot = optarg; break; case 'd': /* --namespace /.../||/name */ +#ifdef linux add_namespace(optarg); +#endif break; case 'N': /* --nice */ nicelevel = atoi(optarg); diff --git a/debian/changelog b/debian/changelog index b83daec10a..3114db3fd1 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,12 @@ -quagga (0.99.23.1-1+cl3u2) Release; urgency=medium +quagga (0.99.24+cl3u3) RELEASED; urgency=medium + + * New Enabled: Merge up-to 0.99.24 code from upstream + * New Enabled: Additional CLI simplification + * New Enabled: Various Bug Fixes + + -- dev-support Thu, 04 Aug 2016 08:43:36 -0700 + +quagga (0.99.23.1-1+cl3u2) RELEASED; urgency=medium * New Enabled: VRF - See Documentation for how to use * New Enabled: Improved interface statistics diff --git a/debian/quagga.install b/debian/quagga.install index 2651dd9e00..6a70be9925 100644 --- a/debian/quagga.install +++ b/debian/quagga.install @@ -1,6 +1,5 @@ etc/quagga/ usr/bin/vtysh -usr/bin/test_igmpv3_join usr/include/quagga/ usr/lib/ tools/quagga-reload.py usr/lib/quagga/ diff --git a/debian/rules b/debian/rules index e5e3ad8c11..25461b89d8 100755 --- a/debian/rules +++ b/debian/rules @@ -39,6 +39,8 @@ override_dh_auto_configure: --sysconfdir=/etc/quagga \ $(USE_SNMP) \ --enable-ospfapi=yes \ + --enable-vtysh=yes \ + --enable-isisd=yes \ --enable-multipath=256 \ --enable-user=quagga \ --enable-group=quagga \ @@ -51,6 +53,7 @@ override_dh_auto_configure: --enable-systemd=yes \ --enable-poll=yes \ --enable-cumulus=yes \ + --enable-pimd=no \ --enable-dependency-tracking; \ fi diff --git a/doc/.gitignore b/doc/.gitignore index 5071f98707..66c43c73e6 100644 --- a/doc/.gitignore +++ b/doc/.gitignore @@ -32,3 +32,4 @@ stamp-vti .arch-ids *~ *.loT +refix diff --git a/doc/bgpd.8 b/doc/bgpd.8 index 67143c2c59..7e90eaec5b 100644 --- a/doc/bgpd.8 +++ b/doc/bgpd.8 @@ -6,7 +6,7 @@ software .SH SYNOPSIS .B bgpd [ -.B \-dhrv +.B \-dhrSv ] [ .B \-f .I config-file @@ -74,6 +74,9 @@ Specify the user to run as. Default is \fIquagga\fR. \fB\-r\fR, \fB\-\-retain\fR When the program terminates, retain routes added by \fBbgpd\fR. .TP +\fB\-S\fR, \fB\-\-skip_runas\fR +Skip setting the process effective user and group. +.TP \fB\-v\fR, \fB\-\-version\fR Print the version and exit. .SH FILES diff --git a/doc/install.texi b/doc/install.texi index 7349e92cbe..811ad9ae89 100644 --- a/doc/install.texi +++ b/doc/install.texi @@ -83,8 +83,17 @@ OSPF-API is enabled if --enable-opaque-lsa is set. @item --disable-ospfclient Disable building of the example OSPF-API client. @item --disable-ospf-te -Disable support for OSPF Traffic Engineering Extension (internet-draft) this +Disable support for OSPF Traffic Engineering Extension (RFC3630) this requires support for Opaque LSAs. +@item --disable-ospf-ri +Disable support for OSPF Router Information (RFC4970 & RFC5088) this +requires support for Opaque LSAs and Traffic Engineering. +@item --enable-isisd +Build isisd. +@item --enable-isis-topology +Enable IS-IS topology generator. +@item --enable-isis-te +Enable Traffic Engineering Extension for ISIS (RFC5305) @item --enable-multipath=@var{ARG} Enable support for Equal Cost Multipath. @var{ARG} is the maximum number of ECMP paths to allow, set to 0 to allow unlimited number of paths. diff --git a/doc/isisd.texi b/doc/isisd.texi new file mode 100644 index 0000000000..bbc2896755 --- /dev/null +++ b/doc/isisd.texi @@ -0,0 +1,432 @@ +@cindex ISIS +@node ISIS +@chapter ISIS + +@acronym{ISIS,Intermediate System to Intermediate System} is a routing protocol +which is described in @cite{ISO10589, RFC1195, RFC5308}. ISIS is an +@acronym{IGP,Interior Gateway Protocol}. Compared with @acronym{RIP}, +@acronym{ISIS} can provide scalable network support and faster +convergence times like @acronym{OSPF}. ISIS is widely used in large networks such as +@acronym{ISP,Internet Service Provider} and carrier backbone networks. + +@menu +* Configuring isisd:: +* ISIS router:: +* ISIS Timer:: +* ISIS region:: +* ISIS interface:: +* Showing ISIS information:: +* ISIS Traffic Engineering:: +* Debugging ISIS:: +* ISIS Configuration Examples:: +@end menu + +@node Configuring isisd +@section Configuring isisd + +There are no @command{isisd} specific options. Common options can be +specified (@pxref{Common Invocation Options}) to @command{isisd}. +@command{isisd} needs to acquire interface information from +@command{zebra} in order to function. Therefore @command{zebra} must be +running before invoking @command{isisd}. Also, if @command{zebra} is +restarted then @command{isisd} must be too. + +Like other daemons, @command{isisd} configuration is done in @acronym{ISIS} +specific configuration file @file{isisd.conf}. + +@node ISIS router +@section ISIS router + +To start ISIS process you have to specify the ISIS router. As of this +writing, @command{isisd} does not support multiple ISIS processes. + +@deffn Command {router isis WORD} {} +@deffnx Command {no router isis WORD} {} +@anchor{router isis WORD}Enable or disable the ISIS process by specifying the ISIS domain with 'WORD'. +@command{isisd} does not yet support multiple ISIS processes but you must specify +the name of ISIS process. The ISIS process name 'WORD' is then used for interface +(see command @ref{ip router isis WORD}). +@end deffn + +@deffn {ISIS Command} {net XX.XXXX. ... .XXX.XX} {} +@deffnx {ISIS Command} {no net XX.XXXX. ... .XXX.XX} {} +Set/Unset network entity title (NET) provided in ISO format. +@end deffn + +@deffn {ISIS Command} {hostname dynamic} {} +@deffnx {ISIS Command} {no hostname dynamic} {} +Enable support for dynamic hostname. +@end deffn + +@deffn {ISIS Command} {area-password [clear | md5] } {} +@deffnx {ISIS Command} {domain-password [clear | md5] } {} +@deffnx {ISIS Command} {no area-password} {} +@deffnx {ISIS Command} {no domain-password} {} +Configure the authentication password for an area, respectively a domain, +as clear text or md5 one. +@end deffn + +@deffn {ISIS Command} {log-adjacency-changes} {} +@deffnx {ISIS Command} {no log-adjacency-changes} {} +Log changes in adjacency state. +@end deffn + +@deffn {ISIS Command} {metric-style [narrow | transition | wide]} {} +@deffnx {ISIS Command} {no metric-style} {} +@anchor{metric-style}Set old-style (ISO 10589) or new-style packet formats: + - narrow Use old style of TLVs with narrow metric + - transition Send and accept both styles of TLVs during transition + - wide Use new style of TLVs to carry wider metric +@end deffn + +@deffn {ISIS Command} {set-overload-bit} {} +@deffnx {ISIS Command} {no set-overload-bit} {} +Set overload bit to avoid any transit traffic. +@end deffn + +@node ISIS Timer +@section ISIS Timer + +@deffn {ISIS Command} {lsp-gen-interval <1-120>} {} +@deffnx {ISIS Command} {lsp-gen-interval [level-1 | level-2] <1-120>} {} +@deffnx {ISIS Command} {no lsp-gen-interval} {} +@deffnx {ISIS Command} {no lsp-gen-interval [level-1 | level-2]} {} +Set minimum interval in seconds between regenerating same LSP, +globally, for an area (level-1) or a domain (level-2). +@end deffn + +@deffn {ISIS Command} {lsp-refresh-interval <1-65235>} {} +@deffnx {ISIS Command} {lsp-refresh-interval [level-1 | level-2] <1-65235>} {} +@deffnx {ISIS Command} {no lsp-refresh-interval} {} +@deffnx {ISIS Command} {no lsp-refresh-interval [level-1 | level-2]} {} +Set LSP refresh interval in seconds, globally, for an area (level-1) or a domain (level-2). +@end deffn + +@deffn {ISIS Command} {lsp-refresh-interval <1-65235>} {} +@deffnx {ISIS Command} {lsp-refresh-interval [level-1 | level-2] <1-65235>} {} +@deffnx {ISIS Command} {no lsp-refresh-interval} {} +@deffnx {ISIS Command} {no lsp-refresh-interval [level-1 | level-2]} {} +Set LSP refresh interval in seconds, globally, for an area (level-1) or a domain (level-2). +@end deffn + +@deffn {ISIS Command} {max-lsp-lifetime <360-65535>} {} +@deffnx {ISIS Command} {max-lsp-lifetime [level-1 | level-2] <360-65535>} {} +@deffnx {ISIS Command} {no max-lsp-lifetime} {} +@deffnx {ISIS Command} {no max-lsp-lifetime [level-1 | level-2]} {} +Set LSP maximum LSP lifetime in seconds, globally, for an area (level-1) or a domain (level-2). +@end deffn + +@deffn {ISIS Command} {spf-interval <1-120>} {} +@deffnx {ISIS Command} {spf-interval [level-1 | level-2] <1-120>} {} +@deffnx {ISIS Command} {no spf-interval} {} +@deffnx {ISIS Command} {no spf-interval [level-1 | level-2]} {} +Set minimum interval between consecutive SPF calculations in seconds. +@end deffn + +@node ISIS region +@section ISIS region + +@deffn {ISIS Command} {is-type [level-1 | level-1-2 | level-2-only]} {} +@deffnx {ISIS Command} {no is-type} {} +Define the ISIS router behavior: + - level-1 Act as a station router only + - level-1-2 Act as both a station router and an area router + - level-2-only Act as an area router only +@end deffn + +@node ISIS interface +@section ISIS interface + +@deffn {Interface Command} {ip router isis WORD} {} +@deffnx {Interface Command} {no ip router isis WORD} {} +@anchor{ip router isis WORD}Activate ISIS adjacency on this interface. Note that the name +of ISIS instance must be the same as the one used to configure the ISIS process +(see command @ref{router isis WORD}). +@end deffn + +@deffn {Interface Command} {isis circuit-type [level-1 | level-1-2 | level-2]} {} +@deffnx {Interface Command} {no isis circuit-type} {} +Configure circuit type for interface: + - level-1 Level-1 only adjacencies are formed + - level-1-2 Level-1-2 adjacencies are formed + - level-2-only Level-2 only adjacencies are formed +@end deffn + +@deffn {Interface Command} {isis csnp-interval <1-600>} {} +@deffnx {Interface Command} {isis csnp-interval <1-600> [level-1 | level-2]} {} +@deffnx {Interface Command} {no isis csnp-interval} {} +@deffnx {Interface Command} {no isis csnp-interval [level-1 | level-2]} {} +Set CSNP interval in seconds globally, for an area (level-1) or a domain (level-2). +@end deffn + +@deffn {Interface Command} {isis hello padding} {} +Add padding to IS-IS hello packets. +@end deffn + +@deffn {Interface Command} {isis hello-interval <1-600>} {} +@deffnx {Interface Command} {isis hello-interval <1-600> [level-1 | level-2]} {} +@deffnx {Interface Command} {no isis hello-interval} {} +@deffnx {Interface Command} {no isis hello-interval [level-1 | level-2]} {} +Set Hello interval in seconds globally, for an area (level-1) or a domain (level-2). +@end deffn + +@deffn {Interface Command} {isis hello-multiplier <2-100>} {} +@deffnx {Interface Command} {isis hello-multiplier <2-100> [level-1 | level-2]} {} +@deffnx {Interface Command} {no isis hello-multiplier} {} +@deffnx {Interface Command} {no isis hello-multiplier [level-1 | level-2]} {} +Set multiplier for Hello holding time globally, for an area (level-1) or a domain (level-2). +@end deffn + +@deffn {Interface Command} {isis metric [<0-255> | <0-16777215>]} {} +@deffnx {Interface Command} {isis metric [<0-255> | <0-16777215>] [level-1 | level-2]} {} +@deffnx {Interface Command} {no isis metric} {} +@deffnx {Interface Command} {no isis metric [level-1 | level-2]} {} +Set default metric value globally, for an area (level-1) or a domain (level-2). +Max value depend if metric support narrow or wide value (see command @ref{metric-style}). +@end deffn + +@deffn {Interface Command} {isis network point-to-point} {} +@deffnx {Interface Command} {no isis network point-to-point} {} +Set network type to 'Point-to-Point' (broadcast by default). +@end deffn + +@deffn {Interface Command} {isis passive} {} +@deffnx {Interface Command} {no isis passive} {} +Configure the passive mode for this interface. +@end deffn + +@deffn {Interface Command} {isis password [clear | md5] } {} +@deffnx {Interface Command} {no isis password} {} +Configure the authentication password (clear or encoded text) for the interface. +@end deffn + +@deffn {Interface Command} {isis priority <0-127>} {} +@deffnx {Interface Command} {isis priority <0-127> [level-1 | level-2]} {} +@deffnx {Interface Command} {no isis priority} {} +@deffnx {Interface Command} {no isis priority [level-1 | level-2]} {} +Set priority for Designated Router election, globally, for the area (level-1) +or the domain (level-2). +@end deffn + +@deffn {Interface Command} {isis psnp-interval <1-120>} {} +@deffnx {Interface Command} {isis psnp-interval <1-120> [level-1 | level-2]} {} +@deffnx {Interface Command} {no isis psnp-interval} {} +@deffnx {Interface Command} {no isis psnp-interval [level-1 | level-2]} {} +Set PSNP interval in seconds globally, for an area (level-1) or a domain (level-2). +@end deffn + +@node Showing ISIS information +@section Showing ISIS information + +@deffn {Command} {show isis summary} {} +Show summary information about ISIS. +@end deffn + +@deffn {Command} {show isis hostname} {} +Show information about ISIS node. +@end deffn + +@deffn {Command} {show isis interface} {} +@deffnx {Command} {show isis interface detail} {} +@deffnx {Command} {show isis interface } {} +Show state and configuration of ISIS specified interface, or all +interfaces if no interface is given with or without details. +@end deffn + +@deffn {Command} {show isis neighbor} {} +@deffnx {Command} {show isis neighbor } {} +@deffnx {Command} {show isis neighbor detail} {} +Show state and information of ISIS specified neighbor, or all +neighbors if no system id is given with or without details. +@end deffn + +@deffn {Command} {show isis database} {} +@deffnx {Command} {show isis database [detail]} {} +@deffnx {Command} {show isis database [detail]} {} +@deffnx {Command} {show isis database detail } {} +Show the ISIS database globally, for a specific LSP id without or with details. +@end deffn + +@deffn {Command} {show isis topology} {} +@deffnx {Command} {show isis topology [level-1|level-2]} {} +Show topology IS-IS paths to Intermediate Systems, globally, +in area (level-1) or domain (level-2). +@end deffn + +@deffn {Command} {show ip route isis} {} +Show the ISIS routing table, as determined by the most recent SPF calculation. +@end deffn + +@node ISIS Traffic Engineering +@section Traffic Engineering + +@deffn {ISIS Command} {mpls-te on} {} +@deffnx {ISIS Command} {no mpls-te} {} +Enable Traffic Engineering LSP flooding. +@end deffn + +@deffn {ISIS Command} {mpls-te router-address } {} +@deffnx {ISIS Command} {no mpls-te router-address} {} +Configure stable IP address for MPLS-TE. +@end deffn + +@deffn {Command} {show isis mpls-te interface} {} +@deffnx {Command} {show isis mpls-te interface @var{interface}} {} +Show MPLS Traffic Engineering parameters for all or specified interface. +@end deffn + +@deffn {Command} {show isis mpls-te router} {} +Show Traffic Engineering router parameters. +@end deffn + +@node Debugging ISIS +@section Debugging ISIS + +@deffn {Command} {debug isis adj-packets} {} +@deffnx {Command} {no debug isis adj-packets} {} +IS-IS Adjacency related packets. +@end deffn + +@deffn {Command} {debug isis checksum-errors} {} +@deffnx {Command} {no debug isis checksum-errors} {} +IS-IS LSP checksum errors. +@end deffn + +@deffn {Command} {debug isis events} {} +@deffnx {Command} {no debug isis events} {} +IS-IS Events. +@end deffn + +@deffn {Command} {debug isis local-updates} {} +@deffnx {Command} {no debug isis local-updates} {} +IS-IS local update packets. +@end deffn + +@deffn {Command} {debug isis packet-dump} {} +@deffnx {Command} {no debug isis packet-dump} {} +IS-IS packet dump. +@end deffn + +@deffn {Command} {debug isis protocol-errors} {} +@deffnx {Command} {no debug isis protocol-errors} {} +IS-IS LSP protocol errors. +@end deffn + +@deffn {Command} {debug isis route-events} {} +@deffnx {Command} {no debug isis route-events} {} +IS-IS Route related events. +@end deffn + +@deffn {Command} {debug isis snp-packets} {} +@deffnx {Command} {no debug isis snp-packets} {} +IS-IS CSNP/PSNP packets. +@end deffn + +@deffn {Command} {debug isis spf-events} {} +@deffnx {Command} {debug isis spf-statistics} {} +@deffnx {Command} {debug isis spf-triggers} {} +@deffnx {Command} {no debug isis spf-events} {} +@deffnx {Command} {no debug isis spf-statistics} {} +@deffnx {Command} {no debug isis spf-triggers} {} +IS-IS Shortest Path First Events, Timing and Statistic Data +and triggering events. +@end deffn + +@deffn {Command} {debug isis update-packets} {} +@deffnx {Command} {no debug isis update-packets} {} +Update related packets. +@end deffn + +@deffn {Command} {show debugging isis} {} +Print which ISIS debug level is activate. +@end deffn + +@node ISIS Configuration Examples +@section ISIS Configuration Examples +A simple example, with MD5 authentication enabled: + +@example +@group +! +interface eth0 + ip router isis FOO + isis network point-to-point + isis circuit-type level-2-only +! +router isis FOO +net 47.0023.0000.0000.0000.0000.0000.0000.1900.0004.00 + metric-style wide + is-type level-2-only +@end group +@end example + + +A Traffic Engineering configuration, with Inter-ASv2 support. + + - First, the 'zebra.conf' part: + +@example +@group +hostname HOSTNAME +password PASSWORD +log file /var/log/zebra.log +! +interface eth0 + ip address 10.2.2.2/24 + mpls-te on + mpls-te link metric 10 + mpls-te link max-bw 1.25e+06 + mpls-te link max-rsv-bw 1.25e+06 + mpls-te link unrsv-bw 0 1.25e+06 + mpls-te link unrsv-bw 1 1.25e+06 + mpls-te link unrsv-bw 2 1.25e+06 + mpls-te link unrsv-bw 3 1.25e+06 + mpls-te link unrsv-bw 4 1.25e+06 + mpls-te link unrsv-bw 5 1.25e+06 + mpls-te link unrsv-bw 6 1.25e+06 + mpls-te link unrsv-bw 7 1.25e+06 + mpls-te link rsc-clsclr 0xab +! +interface eth1 + ip address 10.1.1.1/24 + mpls-te on + mpls-te link metric 10 + mpls-te link max-bw 1.25e+06 + mpls-te link max-rsv-bw 1.25e+06 + mpls-te link unrsv-bw 0 1.25e+06 + mpls-te link unrsv-bw 1 1.25e+06 + mpls-te link unrsv-bw 2 1.25e+06 + mpls-te link unrsv-bw 3 1.25e+06 + mpls-te link unrsv-bw 4 1.25e+06 + mpls-te link unrsv-bw 5 1.25e+06 + mpls-te link unrsv-bw 6 1.25e+06 + mpls-te link unrsv-bw 7 1.25e+06 + mpls-te link rsc-clsclr 0xab + mpls-te neighbor 10.1.1.2 as 65000 +@end group +@end example + + - Then the 'isisd.conf' itself: + +@example +@group +hostname HOSTNAME +password PASSWORD +log file /var/log/isisd.log +! +! +interface eth0 + ip router isis FOO +! +interface eth1 + ip router isis FOO +! +! +router isis FOO + isis net 47.0023.0000.0000.0000.0000.0000.0000.1900.0004.00 + mpls-te on + mpls-te router-address 10.1.1.1 +! +line vty +@end group +@end example diff --git a/doc/main.texi b/doc/main.texi index 4c11d2440d..29ed17c82b 100644 --- a/doc/main.texi +++ b/doc/main.texi @@ -42,6 +42,14 @@ When program terminates, retain routes added by zebra. @node Interface Commands @section Interface Commands +@menu +* Standard Commands:: +* Link Parameters Commands:: +@end menu + +@node Standard Commands +@subsection Standard Commands + @deffn Command {interface @var{ifname}} {} @end deffn @@ -74,18 +82,71 @@ Enable or disables multicast flag for the interface. @deffn {Interface Command} {bandwidth <1-10000000>} {} @deffnx {Interface Command} {no bandwidth <1-10000000>} {} -Set bandwidth value of the interface in kilobits/sec. This is for -calculating OSPF cost. This command does not affect the actual device +Set bandwidth value of the interface in kilobits/sec. This is for +calculating OSPF cost. This command does not affect the actual device configuration. @end deffn @deffn {Interface Command} {link-detect} {} @deffnx {Interface Command} {no link-detect} {} -Enable/disable link-detect on platforms which support this. Currently +Enable/disable link-detect on platforms which support this. Currently only Linux and Solaris, and only where network interface drivers support reporting link-state via the IFF_RUNNING flag. @end deffn +@node Link Parameters Commands +@subsection Link Parameters Commands + +@deffn {Interface Command} {link-params} {} +@deffnx {Interface Command} {no link-param} {} +Enter into the link parameters sub node. At least 'enable' must be set to activate the link parameters, +and consequently Traffic Engineering on this interface. MPLS-TE must be enable at the OSPF (@ref{OSPF Traffic Engineering}) +or ISIS (@ref{ISIS Traffic Engineering}) router level in complement to this. +Disable link parameters for this interface. +@end deffn + +Under link parameter statement, the following commands set the different TE values: + +@deffn link-params {enable} +Enable link parameters for this interface. +@end deffn + +@deffn link-params {metric <0-4294967295>} {} +@deffnx link-params {max-bw @var{bandwidth}} {} +@deffnx link-params {max-rsv-bw @var{bandwidth}} {} +@deffnx link-params {unrsv-bw <0-7> @var{bandwidth}} {} +@deffnx link-params {admin-grp @var{bandwidth}} {} +These commands specifies the Traffic Engineering parameters of the interface in conformity to RFC3630 (OSPF) +or RFC5305 (ISIS). +There are respectively the TE Metric (different from the OSPF or ISIS metric), Maximum Bandwidth (interface speed +by default), Maximum Reservable Bandwidth, Unreserved Bandwidth for each 0-7 priority and Admin Group (ISIS) or +Resource Class/Color (OSPF). + +Note that @var{bandwidth} are specified in IEEE floating point format and express in Bytes/second. +@end deffn + +@deffn link-param {delay <0-16777215> [min <0-16777215> | max <0-16777215>]} {} +@deffnx link-param {delay-variation <0-16777215>} {} +@deffnx link-param {packet-loss @var{percentage}} {} +@deffnx link-param {res-bw @var{bandwidth}} {} +@deffnx link-param {ava-bw @var{bandwidth}} {} +@deffnx link-param {use-bw @var{bandwidth}} {} +These command specifies additionnal Traffic Engineering parameters of the interface in conformity to +draft-ietf-ospf-te-metrics-extension-05.txt and draft-ietf-isis-te-metrics-extension-03.txt. There are +respectively the delay, jitter, loss, available bandwidth, reservable bandwidth and utilized bandwidth. + +Note that @var{bandwidth} are specified in IEEE floating point format and express in Bytes/second. +Delays and delay variation are express in micro-second (µs). Loss is specified in @var{percentage} ranging +from 0 to 50.331642% by step of 0.000003. +@end deffn + +@deffn link-param {neighbor as <0-65535>} {} +@deffnx link-param {no neighbor} {} +Specifies the remote ASBR IP address and Autonomous System (AS) number for InterASv2 link in OSPF (RFC5392). +Note that this option is not yet supported for ISIS (RFC5316). +@end deffn + + @node Static Route Commands @section Static Route Commands @@ -162,7 +223,7 @@ prevent traffic destined for a prefix to match less-specific routes (eg default) should the specified gateways not be reachable. Eg: @example -zebra> show ip route 10.0.0.0/8 +zebra> show ip route 10.0.0.0/8 Routing entry for 10.0.0.0/8 Known via "static", distance 1, metric 0 10.0.0.2 inactive @@ -182,7 +243,7 @@ These behave similarly to their ipv4 counterparts. @deffn Command {table @var{tableno}} {} Select the primary kernel routing table to be used. This only works for kernels supporting multiple routing tables (like GNU/Linux 2.2.x -and later). After setting @var{tableno} with this command, +and later). After setting @var{tableno} with this command, static routes defined after this are added to the specified table. @end deffn @@ -365,8 +426,8 @@ Display current routes which zebra holds in its database. @example @group -Router# show ip route -Codes: K - kernel route, C - connected, S - static, R - RIP, +Router# show ip route +Codes: K - kernel route, C - connected, S - static, R - RIP, B - BGP * - FIB route. K* 0.0.0.0/0 203.181.89.241 diff --git a/doc/mpls/ChangeLog.opaque.txt b/doc/mpls/ChangeLog.opaque.txt index 68ddf4c817..afcfaa3590 100644 --- a/doc/mpls/ChangeLog.opaque.txt +++ b/doc/mpls/ChangeLog.opaque.txt @@ -1,3 +1,16 @@ +----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- +Changes 2013.07.01 + +1. Feature enhancements + + 1.1 Update ospf_te.[c,h] in conformance to RFC3630 and clean the code. + Add new directive to enable MPLS-TE per interface instead of globally + + 1.2 Add support for RFC4970 "Router Information" and RFC5088 "PCE + Capabilities announcement". + + 1.3 Incorporate the mpls documentation into the main stream doc. + ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- Changes 2001.12.03 diff --git a/doc/mpls/ospfd.conf b/doc/mpls/ospfd.conf index 6be11f9120..2b15fa4d00 100644 --- a/doc/mpls/ospfd.conf +++ b/doc/mpls/ospfd.conf @@ -17,6 +17,7 @@ debug ospf packet all detail interface fxp0 ip ospf hello-interval 60 ip ospf dead-interval 240 + mpls-te on mpls-te link metric 999 mpls-te link max-bw 1.25e+06 mpls-te link max-rsv-bw 1.25e+06 diff --git a/doc/ospfd.texi b/doc/ospfd.texi index 45d1ad7cd2..96dffe0000 100644 --- a/doc/ospfd.texi +++ b/doc/ospfd.texi @@ -1,3 +1,4 @@ + @cindex OSPFv2 @node OSPFv2 @chapter OSPFv2 @@ -18,6 +19,9 @@ networks. * OSPF interface:: * Redistribute routes to OSPF:: * Showing OSPF information:: +* Opaque LSA:: +* OSPF Traffic Engineering:: +* Router Information:: * Debugging OSPF:: * OSPF Configuration Examples:: @end menu @@ -616,35 +620,137 @@ interfaces if no interface is given. Show the OSPF routing table, as determined by the most recent SPF calculation. @end deffn +@node Opaque LSA +@section Opaque LSA + +@deffn {OSPF Command} {ospf opaque-lsa} {} +@deffnx {OSPF Command} {capability opaque} {} +@deffnx {OSPF Command} {no ospf opaque-lsa} {} +@deffnx {OSPF Command} {no capability opaque} {} +@command{ospfd} support Opaque LSA (RFC2370) as fondment for MPLS Traffic Engineering LSA. Prior to used MPLS TE, opaque-lsa must be enable in the configuration file. Alternate command could be "mpls-te on" (@ref{OSPF Traffic Engineering}). +@end deffn + +@deffn {Command} {show ip ospf database (opaque-link|opaque-area|opaque-external)} {} +@deffnx {Command} {show ip ospf database (opaque-link|opaque-area|opaque-external) @var{link-state-id}} {} +@deffnx {Command} {show ip ospf database (opaque-link|opaque-area|opaque-external) @var{link-state-id} adv-router @var{adv-router}} {} +@deffnx {Command} {show ip ospf database (opaque-link|opaque-area|opaque-external) adv-router @var{adv-router}} {} +@deffnx {Command} {show ip ospf database (opaque-link|opaque-area|opaque-external) @var{link-state-id} self-originate} {} +@deffnx {Command} {show ip ospf database (opaque-link|opaque-area|opaque-external) self-originate} {} +Show Opaque LSA from the database. +@end deffn + +@node OSPF Traffic Engineering +@section Traffic Engineering + +@deffn {OSPF Command} {mpls-te on} {} +@deffnx {OSPF Command} {no mpls-te} {} +Enable Traffic Engineering LSA flooding. +@end deffn + +@deffn {OSPF Command} {mpls-te router-address } {} +@deffnx {OSPF Command} {no mpls-te} {} +Configure stable IP address for MPLS-TE. This IP address is then advertise in Opaque LSA Type-10 TLV=1 (TE) +option 1 (Router-Address). +@end deffn + +@deffn {OSPF Command} {mpls-te inter-as area |as} {} +@deffnx {OSPF Command} {no mpls-te inter-as} {} +Enable RFC5392 suuport - Inter-AS TE v2 - to flood Traffic Engineering parameters of Inter-AS link. +2 modes are supported: AREA and AS; LSA are flood in AREA with Opaque Type-10, +respectively in AS with Opaque Type-11. In all case, Opaque-LSA TLV=6. +@end deffn + +@deffn {Command} {show ip ospf mpls-te interface} {} +@deffnx {Command} {show ip ospf mpls-te interface @var{interface}} {} +Show MPLS Traffic Engineering parameters for all or specified interface. +@end deffn + +@deffn {Command} {show ip ospf mpls-te router} {} +Show Traffic Engineering router parameters. +@end deffn + +@node Router Information +@section Router Information + +@deffn {OSPF Command} {router-info [as | area ]} {} +@deffnx {OSPF Command} {no router-info} {} +Enable Router Information (RFC4970) LSA advertisement with AS scope (default) or Area scope flooding +when area is specified. +@end deffn + +@deffn {OSPF Command} {pce address } {} +@deffnx {OSPF Command} {no pce address} {} +@deffnx {OSPF Command} {pce domain as <0-65535>} {} +@deffnx {OSPF Command} {no pce domain as <0-65535>} {} +@deffnx {OSPF Command} {pce neighbor as <0-65535>} {} +@deffnx {OSPF Command} {no pce neighbor as <0-65535>} {} +@deffnx {OSPF Command} {pce flag BITPATTERN} {} +@deffnx {OSPF Command} {no pce flag} {} +@deffnx {OSPF Command} {pce scope BITPATTERN} {} +@deffnx {OSPF Command} {no pce scope} {} +The commands are conform to RFC 5088 and allow OSPF router announce Path Compuatation Elemenent (PCE) capabilities +through the Router Information (RI) LSA. Router Information must be enable prior to this. The command set/unset +respectively the PCE IP adress, Autonomous System (AS) numbers of controlled domains, neighbor ASs, flag and scope. +For flag and scope, please refer to RFC5088 for the BITPATTERN recognition. Multiple 'pce neighbor' command could +be specified in order to specify all PCE neighbours. +@end deffn + +@deffn {Command} {show ip ospf router-info} {} +Show Router Capabilities flag. +@end deffn +@deffn {Command} {show ip ospf router-info pce} {} +Show Router Capabilities PCE parameters. +@end deffn + @node Debugging OSPF @section Debugging OSPF @deffn {Command} {debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail]} {} @deffnx {Command} {no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail]} {} +Dump Packet for debugging @end deffn @deffn {Command} {debug ospf ism} {} @deffnx {Command} {debug ospf ism (status|events|timers)} {} @deffnx {Command} {no debug ospf ism} {} @deffnx {Command} {no debug ospf ism (status|events|timers)} {} +Show debug information of Interface State Machine @end deffn @deffn {Command} {debug ospf nsm} {} @deffnx {Command} {debug ospf nsm (status|events|timers)} {} @deffnx {Command} {no debug ospf nsm} {} @deffnx {Command} {no debug ospf nsm (status|events|timers)} {} +Show debug information of Network State Machine +@end deffn + +@deffn {Command} {debug ospf event} {} +@deffnx {Command} {no debug ospf event} {} +Show debug information of OSPF event +@end deffn + +@deffn {Command} {debug ospf nssa} {} +@deffnx {Command} {no debug ospf nssa} {} +Show debug information about Not So Stub Area @end deffn @deffn {Command} {debug ospf lsa} {} @deffnx {Command} {debug ospf lsa (generate|flooding|refresh)} {} @deffnx {Command} {no debug ospf lsa} {} @deffnx {Command} {no debug ospf lsa (generate|flooding|refresh)} {} +Show debug detail of Link State messages +@end deffn + +@deffn {Command} {debug ospf te} {} +@deffnx {Command} {no debug ospf te} {} +Show debug information about Traffic Engineering LSA @end deffn @deffn {Command} {debug ospf zebra} {} @deffnx {Command} {debug ospf zebra (interface|redistribute)} {} @deffnx {Command} {no debug ospf zebra} {} @deffnx {Command} {no debug ospf zebra (interface|redistribute)} {} +Show debug information of ZEBRA API @end deffn @deffn {Command} {show debugging ospf} {} @@ -702,3 +808,100 @@ router ospf ! @end group @end example + +A Traffic Engineering configuration, with Inter-ASv2 support. + + - First, the 'zebra.conf' part: + +@example +@group +hostname HOSTNAME +password PASSWORD +log file /var/log/zebra.log +! +interface eth0 + ip address 198.168.1.1/24 + mpls-te on + mpls-te link metric 10 + mpls-te link max-bw 1.25e+06 + mpls-te link max-rsv-bw 1.25e+06 + mpls-te link unrsv-bw 0 1.25e+06 + mpls-te link unrsv-bw 1 1.25e+06 + mpls-te link unrsv-bw 2 1.25e+06 + mpls-te link unrsv-bw 3 1.25e+06 + mpls-te link unrsv-bw 4 1.25e+06 + mpls-te link unrsv-bw 5 1.25e+06 + mpls-te link unrsv-bw 6 1.25e+06 + mpls-te link unrsv-bw 7 1.25e+06 + mpls-te link rsc-clsclr 0xab +! +interface eth1 + ip address 192.168.2.1/24 + mpls-te on + mpls-te link metric 10 + mpls-te link max-bw 1.25e+06 + mpls-te link max-rsv-bw 1.25e+06 + mpls-te link unrsv-bw 0 1.25e+06 + mpls-te link unrsv-bw 1 1.25e+06 + mpls-te link unrsv-bw 2 1.25e+06 + mpls-te link unrsv-bw 3 1.25e+06 + mpls-te link unrsv-bw 4 1.25e+06 + mpls-te link unrsv-bw 5 1.25e+06 + mpls-te link unrsv-bw 6 1.25e+06 + mpls-te link unrsv-bw 7 1.25e+06 + mpls-te link rsc-clsclr 0xab + mpls-te neighbor 192.168.2.2 as 65000 +@end group +@end example + + - Then the 'ospfd.conf' itself: + +@example +@group +hostname HOSTNAME +password PASSWORD +log file /var/log/ospfd.log +! +! +interface eth0 + ip ospf hello-interval 60 + ip ospf dead-interval 240 +! +interface eth1 + ip ospf hello-interval 60 + ip ospf dead-interval 240 +! +! +router ospf + ospf router-id 192.168.1.1 + network 192.168.0.0/16 area 1 + ospf opaque-lsa + mpls-te + mpls-te router-address 192.168.1.1 + mpls-te inter-as area 1 +! +line vty +@end group +@end example + +A router information example with PCE advsertisement: + +@example +@group +! +router ospf + ospf router-id 192.168.1.1 + network 192.168.0.0/16 area 1 + capability opaque + mpls-te + mpls-te router-address 192.168.1.1 + router-info area 0.0.0.1 + pce address 192.168.1.1 + pce flag 0x80 + pce domain as 65400 + pce neighbor as 65500 + pce neighbor as 65200 + pce scope 0x80 +! +@end group +@end example diff --git a/doc/quagga.texi b/doc/quagga.texi index 65089621a3..6831b30cdf 100644 --- a/doc/quagga.texi +++ b/doc/quagga.texi @@ -85,6 +85,7 @@ for @value{PACKAGE_STRING}. @uref{http://www.quagga.net,,Quagga} is a fork of * RIPng:: * OSPFv2:: * OSPFv3:: +* ISIS:: * BGP:: * Configuring Quagga as a Route Server:: * VTY shell:: @@ -109,6 +110,7 @@ for @value{PACKAGE_STRING}. @uref{http://www.quagga.net,,Quagga} is a fork of @include ripngd.texi @include ospfd.texi @include ospf6d.texi +@include isisd.texi @include bgpd.texi @include routeserver.texi @include vtysh.texi diff --git a/isisd/AUTHORS b/isisd/AUTHORS index 05fc0a5073..80b3a28e19 100644 --- a/isisd/AUTHORS +++ b/isisd/AUTHORS @@ -2,3 +2,4 @@ Sampo Saaristo Ofer Wald Hannes Gredler Subbaiah Venkata +Olivier Dugeon diff --git a/isisd/Makefile.am b/isisd/Makefile.am index 5f866638d9..bfe2e94779 100644 --- a/isisd/Makefile.am +++ b/isisd/Makefile.am @@ -16,7 +16,8 @@ libisis_a_SOURCES = \ isis_adjacency.c isis_lsp.c dict.c isis_circuit.c isis_pdu.c \ isis_tlv.c isisd.c isis_misc.c isis_zebra.c isis_dr.c \ isis_flags.c isis_dynhn.c iso_checksum.c isis_csm.c isis_events.c \ - isis_spf.c isis_redist.c isis_route.c isis_routemap.c + isis_spf.c isis_redist.c isis_route.c isis_routemap.c isis_te.c \ + isis_vty.c noinst_HEADERS = \ @@ -24,7 +25,7 @@ noinst_HEADERS = \ isis_lsp.h dict.h isis_circuit.h isis_misc.h isis_network.h \ isis_zebra.h isis_dr.h isis_flags.h isis_dynhn.h isis_common.h \ iso_checksum.h isis_csm.h isis_events.h isis_spf.h isis_redist.h \ - isis_route.h isis_routemap.h \ + isis_route.h isis_routemap.h isis_te.h \ include-netbsd/clnp.h include-netbsd/esis.h include-netbsd/iso.h isisd_SOURCES = \ diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 17ba40aa59..4f22a5e558 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -37,6 +37,7 @@ #include "linklist.h" #include "command.h" #include "thread.h" +#include "vty.h" #include "hash.h" #include "prefix.h" #include "stream.h" @@ -58,6 +59,7 @@ #include "isisd/isisd.h" #include "isisd/isis_csm.h" #include "isisd/isis_events.h" +#include "isisd/isis_te.h" /* * Prototypes. @@ -92,13 +94,12 @@ isis_circuit_new () circuit->csnp_interval[i] = DEFAULT_CSNP_INTERVAL; circuit->psnp_interval[i] = DEFAULT_PSNP_INTERVAL; circuit->priority[i] = DEFAULT_PRIORITY; - circuit->metrics[i].metric_default = DEFAULT_CIRCUIT_METRIC; - circuit->metrics[i].metric_expense = METRICS_UNSUPPORTED; - circuit->metrics[i].metric_error = METRICS_UNSUPPORTED; - circuit->metrics[i].metric_delay = METRICS_UNSUPPORTED; + circuit->metric[i] = DEFAULT_CIRCUIT_METRIC; circuit->te_metric[i] = DEFAULT_CIRCUIT_METRIC; } + circuit->mtc = mpls_te_circuit_new(); + return circuit; } @@ -196,30 +197,6 @@ circuit_scan_by_ifp (struct interface *ifp) return circuit_lookup_by_ifp (ifp, isis->init_circ_list); } -static struct isis_circuit * -isis_circuit_lookup (struct vty *vty) -{ - struct interface *ifp; - struct isis_circuit *circuit; - - ifp = (struct interface *) vty->index; - if (!ifp) - { - vty_out (vty, "Invalid interface %s", VTY_NEWLINE); - return NULL; - } - - circuit = circuit_scan_by_ifp (ifp); - if (!circuit) - { - vty_out (vty, "ISIS is not enabled on circuit %s%s", - ifp->name, VTY_NEWLINE); - return NULL; - } - - return circuit; -} - void isis_circuit_add_addr (struct isis_circuit *circuit, struct connected *connected) @@ -249,6 +226,10 @@ isis_circuit_add_addr (struct isis_circuit *circuit, ipv4->prefixlen = connected->address->prefixlen; ipv4->prefix = connected->address->u.prefix4; listnode_add (circuit->ip_addrs, ipv4); + + /* Update MPLS TE Local IP address parameter */ + set_circuitparams_local_ipaddr (circuit->mtc, ipv4->prefix); + if (circuit->area) lsp_regenerate_schedule (circuit->area, circuit->is_type, 0); @@ -545,6 +526,7 @@ isis_circuit_if_bind (struct isis_circuit *circuit, struct interface *ifp) assert (ifp->info == circuit); else ifp->info = circuit; + isis_link_params_update (circuit, ifp); } void @@ -646,15 +628,6 @@ isis_circuit_up (struct isis_circuit *circuit) /* * Get the Hardware Address */ -#ifdef HAVE_STRUCT_SOCKADDR_DL -#ifndef SUNOS_5 - if (circuit->interface->sdl.sdl_alen != ETHER_ADDR_LEN) - zlog_warn ("unsupported link layer"); - else - memcpy (circuit->u.bc.snpa, LLADDR (&circuit->interface->sdl), - ETH_ALEN); -#endif -#else if (circuit->interface->hw_addr_len != ETH_ALEN) { zlog_warn ("unsupported link layer"); @@ -668,7 +641,6 @@ isis_circuit_up (struct isis_circuit *circuit) circuit->interface->ifindex, ISO_MTU (circuit), snpa_print (circuit->u.bc.snpa)); #endif /* EXTREME_DEBUG */ -#endif /* HAVE_STRUCT_SOCKADDR_DL */ circuit->u.bc.adjdb[0] = list_new (); circuit->u.bc.adjdb[1] = list_new (); @@ -923,7 +895,7 @@ isis_circuit_print_vty (struct isis_circuit *circuit, struct vty *vty, vty_out (vty, " Metric: %d", circuit->te_metric[0]); else vty_out (vty, " Metric: %d", - circuit->metrics[0].metric_default); + circuit->metric[0]); if (!circuit->is_passive) { vty_out (vty, ", Active neighbors: %u%s", @@ -956,7 +928,7 @@ isis_circuit_print_vty (struct isis_circuit *circuit, struct vty *vty, vty_out (vty, " Metric: %d", circuit->te_metric[1]); else vty_out (vty, " Metric: %d", - circuit->metrics[1].metric_default); + circuit->metric[1]); if (!circuit->is_passive) { vty_out (vty, ", Active neighbors: %u%s", @@ -1250,1562 +1222,164 @@ isis_interface_config_write (struct vty *vty) return write; } -DEFUN (ip_router_isis, - ip_router_isis_cmd, - "ip router isis WORD", - "Interface Internet Protocol config commands\n" - "IP router interface commands\n" - "IS-IS Routing for IP\n" - "Routing process tag\n") +struct isis_circuit * +isis_circuit_create (struct isis_area *area, struct interface *ifp) { - struct isis_circuit *circuit; - struct interface *ifp; - struct isis_area *area; - int rv; - - ifp = (struct interface *) vty->index; - assert (ifp); - - /* Prevent more than one area per circuit */ - circuit = circuit_scan_by_ifp (ifp); - if (circuit) - { - if (circuit->ip_router == 1) - { - if (strcmp (circuit->area->area_tag, argv[0])) - { - vty_out (vty, "ISIS circuit is already defined on %s%s", - circuit->area->area_tag, VTY_NEWLINE); - return CMD_ERR_NOTHING_TODO; - } - return CMD_SUCCESS; - } - } - - if (isis_area_get (vty, argv[0]) != CMD_SUCCESS) - { - vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); - return CMD_ERR_NO_MATCH; - } - area = vty->index; - + struct isis_circuit *circuit = circuit_scan_by_ifp (ifp); + if (circuit && circuit->area) + return NULL; circuit = isis_csm_state_change (ISIS_ENABLE, circuit, area); if (circuit->state != C_STATE_CONF && circuit->state != C_STATE_UP) - { - vty_out(vty, "Couldn't bring up interface, please check log.%s", VTY_NEWLINE); - rv = CMD_WARNING; - } - else - { - isis_circuit_if_bind (circuit, ifp); - - circuit->ip_router = 1; - area->ip_circuits++; - circuit_update_nlpids (circuit); - rv = CMD_SUCCESS; - } - - vty->node = INTERFACE_NODE; - vty->index = ifp; - - if (circuit->ipv6_router) - lsp_regenerate_schedule(circuit->area, circuit->is_type, 0); - return rv; + return circuit; + isis_circuit_if_bind (circuit, ifp); + return circuit; } -DEFUN (no_ip_router_isis, - no_ip_router_isis_cmd, - "no ip router isis WORD", - NO_STR - "Interface Internet Protocol config commands\n" - "IP router interface commands\n" - "IS-IS Routing for IP\n" - "Routing process tag\n") +void +isis_circuit_af_set (struct isis_circuit *circuit, bool ip_router, bool ipv6_router) { - struct interface *ifp; - struct isis_area *area; - struct isis_circuit *circuit; + struct isis_area *area = circuit->area; + bool change = circuit->ip_router != ip_router || circuit->ipv6_router != ipv6_router; + bool was_enabled = !!circuit->area; - ifp = (struct interface *) vty->index; - if (!ifp) - { - vty_out (vty, "Invalid interface %s", VTY_NEWLINE); - return CMD_ERR_NO_MATCH; - } + area->ip_circuits += ip_router - circuit->ip_router; + area->ipv6_circuits += ipv6_router - circuit->ipv6_router; + circuit->ip_router = ip_router; + circuit->ipv6_router = ipv6_router; - area = isis_area_lookup (argv[0]); - if (!area) - { - vty_out (vty, "Can't find ISIS instance %s%s", - argv[0], VTY_NEWLINE); - return CMD_ERR_NO_MATCH; - } + if (!change) + return; - circuit = circuit_lookup_by_ifp (ifp, area->circuit_list); - if (!circuit) - { - vty_out (vty, "ISIS is not enabled on circuit %s%s", - ifp->name, VTY_NEWLINE); - return CMD_ERR_NO_MATCH; - } + circuit_update_nlpids (circuit); - circuit->ip_router = 0; - area->ip_circuits--; - if (circuit->ipv6_router == 0) + if (!ip_router && !ipv6_router) isis_csm_state_change (ISIS_DISABLE, circuit, area); + else if (!was_enabled) + isis_csm_state_change (ISIS_ENABLE, circuit, area); else - lsp_regenerate_schedule(area, circuit->is_type, 0); - - return CMD_SUCCESS; -} - -#ifdef HAVE_IPV6 -DEFUN (ipv6_router_isis, - ipv6_router_isis_cmd, - "ipv6 router isis WORD", - "IPv6 interface subcommands\n" - "IPv6 Router interface commands\n" - "IS-IS Routing for IPv6\n" - "Routing process tag\n") -{ - struct isis_circuit *circuit; - struct interface *ifp; - struct isis_area *area; - int rv; - - ifp = (struct interface *) vty->index; - assert (ifp); - - /* Prevent more than one area per circuit */ - circuit = circuit_scan_by_ifp (ifp); - if (circuit) - { - if (circuit->ipv6_router == 1) - { - if (strcmp (circuit->area->area_tag, argv[0])) - { - vty_out (vty, "ISIS circuit is already defined for IPv6 on %s%s", - circuit->area->area_tag, VTY_NEWLINE); - return CMD_ERR_NOTHING_TODO; - } - return CMD_SUCCESS; - } - } - - if (isis_area_get (vty, argv[0]) != CMD_SUCCESS) - { - vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); - return CMD_ERR_NO_MATCH; - } - area = vty->index; - - circuit = isis_csm_state_change (ISIS_ENABLE, circuit, area); - if (circuit->state != C_STATE_CONF && circuit->state != C_STATE_UP) - { - vty_out(vty, "Couldn't bring up interface, please check log.%s", VTY_NEWLINE); - rv = CMD_WARNING; - } - else - { - isis_circuit_if_bind (circuit, ifp); - - circuit->ipv6_router = 1; - area->ipv6_circuits++; - circuit_update_nlpids (circuit); - rv = CMD_SUCCESS; - } - - vty->node = INTERFACE_NODE; - vty->index = ifp; - - if (circuit->ip_router) lsp_regenerate_schedule(circuit->area, circuit->is_type, 0); - return rv; } -DEFUN (no_ipv6_router_isis, - no_ipv6_router_isis_cmd, - "no ipv6 router isis WORD", - NO_STR - "IPv6 interface subcommands\n" - "IPv6 Router interface commands\n" - "IS-IS Routing for IPv6\n" - "Routing process tag\n") +int +isis_circuit_passive_set (struct isis_circuit *circuit, bool passive) { - struct interface *ifp; - struct isis_area *area; - struct isis_circuit *circuit; + if (circuit->is_passive == passive) + return 0; - ifp = (struct interface *) vty->index; - if (!ifp) - { - vty_out (vty, "Invalid interface %s", VTY_NEWLINE); - return CMD_ERR_NO_MATCH; - } - - area = isis_area_lookup (argv[0]); - if (!area) - { - vty_out (vty, "Can't find ISIS instance %s%s", - argv[0], VTY_NEWLINE); - return CMD_ERR_NO_MATCH; - } - - circuit = circuit_lookup_by_ifp (ifp, area->circuit_list); - if (!circuit) - { - vty_out (vty, "ISIS is not enabled on circuit %s%s", - ifp->name, VTY_NEWLINE); - return CMD_ERR_NO_MATCH; - } - - circuit->ipv6_router = 0; - area->ipv6_circuits--; - if (circuit->ip_router == 0) - isis_csm_state_change (ISIS_DISABLE, circuit, area); - else - lsp_regenerate_schedule(area, circuit->is_type, 0); - - return CMD_SUCCESS; -} -#endif /* HAVE_IPV6 */ - -DEFUN (isis_passive, - isis_passive_cmd, - "isis passive", - "IS-IS commands\n" - "Configure the passive mode for interface\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - if (circuit->is_passive == 1) - return CMD_SUCCESS; + if (if_is_loopback (circuit->interface) && !passive) + return -1; if (circuit->state != C_STATE_UP) { - circuit->is_passive = 1; + circuit->is_passive = passive; } else { struct isis_area *area = circuit->area; isis_csm_state_change (ISIS_DISABLE, circuit, area); - circuit->is_passive = 1; + circuit->is_passive = passive; isis_csm_state_change (ISIS_ENABLE, circuit, area); } - return CMD_SUCCESS; + return 0; } -DEFUN (no_isis_passive, - no_isis_passive_cmd, - "no isis passive", - NO_STR - "IS-IS commands\n" - "Configure the passive mode for interface\n") +int +isis_circuit_metric_set (struct isis_circuit *circuit, int level, int metric) { - struct interface *ifp; - struct isis_circuit *circuit; + assert (level == IS_LEVEL_1 || level == IS_LEVEL_2); + if (metric > MAX_WIDE_LINK_METRIC) + return -1; + if (circuit->area && circuit->area->oldmetric + && metric > MAX_NARROW_LINK_METRIC) + return -1; - ifp = (struct interface *) vty->index; - if (!ifp) - { - vty_out (vty, "Invalid interface %s", VTY_NEWLINE); - return CMD_ERR_NO_MATCH; - } + circuit->te_metric[level - 1] = metric; + circuit->metric[level - 1] = metric; - /* FIXME: what is wrong with circuit = ifp->info ? */ - circuit = circuit_scan_by_ifp (ifp); - if (!circuit) - { - vty_out (vty, "ISIS is not enabled on circuit %s%s", - ifp->name, VTY_NEWLINE); - return CMD_ERR_NO_MATCH; - } - - if (if_is_loopback(ifp)) - { - vty_out (vty, "Can't set no passive for loopback interface%s", - VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - if (circuit->is_passive == 0) - return CMD_SUCCESS; - - if (circuit->state != C_STATE_UP) - { - circuit->is_passive = 0; - } - else - { - struct isis_area *area = circuit->area; - isis_csm_state_change (ISIS_DISABLE, circuit, area); - circuit->is_passive = 0; - isis_csm_state_change (ISIS_ENABLE, circuit, area); - } - - return CMD_SUCCESS; + if (circuit->area) + lsp_regenerate_schedule (circuit->area, level, 0); + return 0; } -DEFUN (isis_circuit_type, - isis_circuit_type_cmd, - "isis circuit-type (level-1|level-1-2|level-2-only)", - "IS-IS commands\n" - "Configure circuit type for interface\n" - "Level-1 only adjacencies are formed\n" - "Level-1-2 adjacencies are formed\n" - "Level-2 only adjacencies are formed\n") +int +isis_circuit_passwd_unset (struct isis_circuit *circuit) { - int circuit_type; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit_type = string2circuit_t (argv[0]); - if (!circuit_type) - { - vty_out (vty, "Unknown circuit-type %s", VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - if (circuit->state == C_STATE_UP && - circuit->area->is_type != IS_LEVEL_1_AND_2 && - circuit->area->is_type != circuit_type) - { - vty_out (vty, "Invalid circuit level for area %s.%s", - circuit->area->area_tag, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - isis_event_circuit_type_change (circuit, circuit_type); - - return CMD_SUCCESS; + memset(&circuit->passwd, 0, sizeof(circuit->passwd)); + return 0; } -DEFUN (no_isis_circuit_type, - no_isis_circuit_type_cmd, - "no isis circuit-type (level-1|level-1-2|level-2-only)", - NO_STR - "IS-IS commands\n" - "Configure circuit type for interface\n" - "Level-1 only adjacencies are formed\n" - "Level-1-2 adjacencies are formed\n" - "Level-2 only adjacencies are formed\n") -{ - int circuit_type; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - /* - * Set the circuits level to its default value - */ - if (circuit->state == C_STATE_UP) - circuit_type = circuit->area->is_type; - else - circuit_type = IS_LEVEL_1_AND_2; - isis_event_circuit_type_change (circuit, circuit_type); - - return CMD_SUCCESS; -} - -DEFUN (isis_passwd_md5, - isis_passwd_md5_cmd, - "isis password md5 WORD", - "IS-IS commands\n" - "Configure the authentication password for a circuit\n" - "Authentication type\n" - "Circuit password\n") +static int +isis_circuit_passwd_set (struct isis_circuit *circuit, u_char passwd_type, const char *passwd) { int len; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - len = strlen (argv[0]); + if (!passwd) + return -1; + + len = strlen(passwd); if (len > 254) - { - vty_out (vty, "Too long circuit password (>254)%s", VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } + return -1; + circuit->passwd.len = len; - circuit->passwd.type = ISIS_PASSWD_TYPE_HMAC_MD5; - strncpy ((char *)circuit->passwd.passwd, argv[0], 255); - - return CMD_SUCCESS; + strncpy((char *)circuit->passwd.passwd, passwd, 255); + circuit->passwd.type = passwd_type; + return 0; } -DEFUN (isis_passwd_clear, - isis_passwd_clear_cmd, - "isis password clear WORD", - "IS-IS commands\n" - "Configure the authentication password for a circuit\n" - "Authentication type\n" - "Circuit password\n") +int +isis_circuit_passwd_cleartext_set (struct isis_circuit *circuit, const char *passwd) { - int len; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - len = strlen (argv[0]); - if (len > 254) - { - vty_out (vty, "Too long circuit password (>254)%s", VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - circuit->passwd.len = len; - circuit->passwd.type = ISIS_PASSWD_TYPE_CLEARTXT; - strncpy ((char *)circuit->passwd.passwd, argv[0], 255); - - return CMD_SUCCESS; + return isis_circuit_passwd_set (circuit, ISIS_PASSWD_TYPE_CLEARTXT, passwd); } -DEFUN (no_isis_passwd, - no_isis_passwd_cmd, - "no isis password", - NO_STR - "IS-IS commands\n" - "Configure the authentication password for a circuit\n") +int +isis_circuit_passwd_hmac_md5_set (struct isis_circuit *circuit, const char *passwd) { - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - memset (&circuit->passwd, 0, sizeof (struct isis_passwd)); - - return CMD_SUCCESS; + return isis_circuit_passwd_set (circuit, ISIS_PASSWD_TYPE_HMAC_MD5, passwd); } - -DEFUN (isis_priority, - isis_priority_cmd, - "isis priority <0-127>", - "IS-IS commands\n" - "Set priority for Designated Router election\n" - "Priority value\n") -{ - int prio; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - prio = atoi (argv[0]); - if (prio < MIN_PRIORITY || prio > MAX_PRIORITY) - { - vty_out (vty, "Invalid priority %d - should be <0-127>%s", - prio, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - circuit->priority[0] = prio; - circuit->priority[1] = prio; - - return CMD_SUCCESS; -} - -DEFUN (no_isis_priority, - no_isis_priority_cmd, - "no isis priority", - NO_STR - "IS-IS commands\n" - "Set priority for Designated Router election\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit->priority[0] = DEFAULT_PRIORITY; - circuit->priority[1] = DEFAULT_PRIORITY; - - return CMD_SUCCESS; -} - -ALIAS (no_isis_priority, - no_isis_priority_arg_cmd, - "no isis priority <0-127>", - NO_STR - "IS-IS commands\n" - "Set priority for Designated Router election\n" - "Priority value\n") - -DEFUN (isis_priority_l1, - isis_priority_l1_cmd, - "isis priority <0-127> level-1", - "IS-IS commands\n" - "Set priority for Designated Router election\n" - "Priority value\n" - "Specify priority for level-1 routing\n") -{ - int prio; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - prio = atoi (argv[0]); - if (prio < MIN_PRIORITY || prio > MAX_PRIORITY) - { - vty_out (vty, "Invalid priority %d - should be <0-127>%s", - prio, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - circuit->priority[0] = prio; - - return CMD_SUCCESS; -} - -DEFUN (no_isis_priority_l1, - no_isis_priority_l1_cmd, - "no isis priority level-1", - NO_STR - "IS-IS commands\n" - "Set priority for Designated Router election\n" - "Specify priority for level-1 routing\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit->priority[0] = DEFAULT_PRIORITY; - - return CMD_SUCCESS; -} - -ALIAS (no_isis_priority_l1, - no_isis_priority_l1_arg_cmd, - "no isis priority <0-127> level-1", - NO_STR - "IS-IS commands\n" - "Set priority for Designated Router election\n" - "Priority value\n" - "Specify priority for level-1 routing\n") - -DEFUN (isis_priority_l2, - isis_priority_l2_cmd, - "isis priority <0-127> level-2", - "IS-IS commands\n" - "Set priority for Designated Router election\n" - "Priority value\n" - "Specify priority for level-2 routing\n") -{ - int prio; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - prio = atoi (argv[0]); - if (prio < MIN_PRIORITY || prio > MAX_PRIORITY) - { - vty_out (vty, "Invalid priority %d - should be <0-127>%s", - prio, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - circuit->priority[1] = prio; - - return CMD_SUCCESS; -} - -DEFUN (no_isis_priority_l2, - no_isis_priority_l2_cmd, - "no isis priority level-2", - NO_STR - "IS-IS commands\n" - "Set priority for Designated Router election\n" - "Specify priority for level-2 routing\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit->priority[1] = DEFAULT_PRIORITY; - - return CMD_SUCCESS; -} - -ALIAS (no_isis_priority_l2, - no_isis_priority_l2_arg_cmd, - "no isis priority <0-127> level-2", - NO_STR - "IS-IS commands\n" - "Set priority for Designated Router election\n" - "Priority value\n" - "Specify priority for level-2 routing\n") - -/* Metric command */ -DEFUN (isis_metric, - isis_metric_cmd, - "isis metric <0-16777215>", - "IS-IS commands\n" - "Set default metric for circuit\n" - "Default metric value\n") -{ - int met; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - met = atoi (argv[0]); - - /* RFC3787 section 5.1 */ - if (circuit->area && circuit->area->oldmetric == 1 && - met > MAX_NARROW_LINK_METRIC) - { - vty_out (vty, "Invalid metric %d - should be <0-63> " - "when narrow metric type enabled%s", - met, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - /* RFC4444 */ - if (circuit->area && circuit->area->newmetric == 1 && - met > MAX_WIDE_LINK_METRIC) - { - vty_out (vty, "Invalid metric %d - should be <0-16777215> " - "when wide metric type enabled%s", - met, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - circuit->te_metric[0] = met; - circuit->te_metric[1] = met; - - circuit->metrics[0].metric_default = met; - circuit->metrics[1].metric_default = met; - - if (circuit->area) - lsp_regenerate_schedule (circuit->area, circuit->is_type, 0); - - return CMD_SUCCESS; -} - -DEFUN (no_isis_metric, - no_isis_metric_cmd, - "no isis metric", - NO_STR - "IS-IS commands\n" - "Set default metric for circuit\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit->te_metric[0] = DEFAULT_CIRCUIT_METRIC; - circuit->te_metric[1] = DEFAULT_CIRCUIT_METRIC; - circuit->metrics[0].metric_default = DEFAULT_CIRCUIT_METRIC; - circuit->metrics[1].metric_default = DEFAULT_CIRCUIT_METRIC; - - if (circuit->area) - lsp_regenerate_schedule (circuit->area, circuit->is_type, 0); - - return CMD_SUCCESS; -} - -ALIAS (no_isis_metric, - no_isis_metric_arg_cmd, - "no isis metric <0-16777215>", - NO_STR - "IS-IS commands\n" - "Set default metric for circuit\n" - "Default metric value\n") - -DEFUN (isis_metric_l1, - isis_metric_l1_cmd, - "isis metric <0-16777215> level-1", - "IS-IS commands\n" - "Set default metric for circuit\n" - "Default metric value\n" - "Specify metric for level-1 routing\n") -{ - int met; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - met = atoi (argv[0]); - - /* RFC3787 section 5.1 */ - if (circuit->area && circuit->area->oldmetric == 1 && - met > MAX_NARROW_LINK_METRIC) - { - vty_out (vty, "Invalid metric %d - should be <0-63> " - "when narrow metric type enabled%s", - met, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - /* RFC4444 */ - if (circuit->area && circuit->area->newmetric == 1 && - met > MAX_WIDE_LINK_METRIC) - { - vty_out (vty, "Invalid metric %d - should be <0-16777215> " - "when wide metric type enabled%s", - met, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - circuit->te_metric[0] = met; - circuit->metrics[0].metric_default = met; - - if (circuit->area) - lsp_regenerate_schedule (circuit->area, IS_LEVEL_1, 0); - - return CMD_SUCCESS; -} - -DEFUN (no_isis_metric_l1, - no_isis_metric_l1_cmd, - "no isis metric level-1", - NO_STR - "IS-IS commands\n" - "Set default metric for circuit\n" - "Specify metric for level-1 routing\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit->te_metric[0] = DEFAULT_CIRCUIT_METRIC; - circuit->metrics[0].metric_default = DEFAULT_CIRCUIT_METRIC; - - if (circuit->area) - lsp_regenerate_schedule (circuit->area, IS_LEVEL_1, 0); - - return CMD_SUCCESS; -} - -ALIAS (no_isis_metric_l1, - no_isis_metric_l1_arg_cmd, - "no isis metric <0-16777215> level-1", - NO_STR - "IS-IS commands\n" - "Set default metric for circuit\n" - "Default metric value\n" - "Specify metric for level-1 routing\n") - -DEFUN (isis_metric_l2, - isis_metric_l2_cmd, - "isis metric <0-16777215> level-2", - "IS-IS commands\n" - "Set default metric for circuit\n" - "Default metric value\n" - "Specify metric for level-2 routing\n") -{ - int met; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - met = atoi (argv[0]); - - /* RFC3787 section 5.1 */ - if (circuit->area && circuit->area->oldmetric == 1 && - met > MAX_NARROW_LINK_METRIC) - { - vty_out (vty, "Invalid metric %d - should be <0-63> " - "when narrow metric type enabled%s", - met, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - /* RFC4444 */ - if (circuit->area && circuit->area->newmetric == 1 && - met > MAX_WIDE_LINK_METRIC) - { - vty_out (vty, "Invalid metric %d - should be <0-16777215> " - "when wide metric type enabled%s", - met, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - circuit->te_metric[1] = met; - circuit->metrics[1].metric_default = met; - - if (circuit->area) - lsp_regenerate_schedule (circuit->area, IS_LEVEL_2, 0); - - return CMD_SUCCESS; -} - -DEFUN (no_isis_metric_l2, - no_isis_metric_l2_cmd, - "no isis metric level-2", - NO_STR - "IS-IS commands\n" - "Set default metric for circuit\n" - "Specify metric for level-2 routing\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit->te_metric[1] = DEFAULT_CIRCUIT_METRIC; - circuit->metrics[1].metric_default = DEFAULT_CIRCUIT_METRIC; - - if (circuit->area) - lsp_regenerate_schedule (circuit->area, IS_LEVEL_2, 0); - - return CMD_SUCCESS; -} - -ALIAS (no_isis_metric_l2, - no_isis_metric_l2_arg_cmd, - "no isis metric <0-16777215> level-2", - NO_STR - "IS-IS commands\n" - "Set default metric for circuit\n" - "Default metric value\n" - "Specify metric for level-2 routing\n") -/* end of metrics */ - -DEFUN (isis_hello_interval, - isis_hello_interval_cmd, - "isis hello-interval <1-600>", - "IS-IS commands\n" - "Set Hello interval\n" - "Hello interval value\n" - "Holdtime 1 seconds, interval depends on multiplier\n") -{ - int interval; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - interval = atoi (argv[0]); - if (interval < MIN_HELLO_INTERVAL || interval > MAX_HELLO_INTERVAL) - { - vty_out (vty, "Invalid hello-interval %d - should be <1-600>%s", - interval, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - circuit->hello_interval[0] = (u_int16_t) interval; - circuit->hello_interval[1] = (u_int16_t) interval; - - return CMD_SUCCESS; -} - -DEFUN (no_isis_hello_interval, - no_isis_hello_interval_cmd, - "no isis hello-interval", - NO_STR - "IS-IS commands\n" - "Set Hello interval\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit->hello_interval[0] = DEFAULT_HELLO_INTERVAL; - circuit->hello_interval[1] = DEFAULT_HELLO_INTERVAL; - - return CMD_SUCCESS; -} - -ALIAS (no_isis_hello_interval, - no_isis_hello_interval_arg_cmd, - "no isis hello-interval <1-600>", - NO_STR - "IS-IS commands\n" - "Set Hello interval\n" - "Hello interval value\n" - "Holdtime 1 second, interval depends on multiplier\n") - -DEFUN (isis_hello_interval_l1, - isis_hello_interval_l1_cmd, - "isis hello-interval <1-600> level-1", - "IS-IS commands\n" - "Set Hello interval\n" - "Hello interval value\n" - "Holdtime 1 second, interval depends on multiplier\n" - "Specify hello-interval for level-1 IIHs\n") -{ - long interval; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - interval = atoi (argv[0]); - if (interval < MIN_HELLO_INTERVAL || interval > MAX_HELLO_INTERVAL) - { - vty_out (vty, "Invalid hello-interval %ld - should be <1-600>%s", - interval, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - circuit->hello_interval[0] = (u_int16_t) interval; - - return CMD_SUCCESS; -} - -DEFUN (no_isis_hello_interval_l1, - no_isis_hello_interval_l1_cmd, - "no isis hello-interval level-1", - NO_STR - "IS-IS commands\n" - "Set Hello interval\n" - "Specify hello-interval for level-1 IIHs\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit->hello_interval[0] = DEFAULT_HELLO_INTERVAL; - - return CMD_SUCCESS; -} - -ALIAS (no_isis_hello_interval_l1, - no_isis_hello_interval_l1_arg_cmd, - "no isis hello-interval <1-600> level-1", - NO_STR - "IS-IS commands\n" - "Set Hello interval\n" - "Hello interval value\n" - "Holdtime 1 second, interval depends on multiplier\n" - "Specify hello-interval for level-1 IIHs\n") - -DEFUN (isis_hello_interval_l2, - isis_hello_interval_l2_cmd, - "isis hello-interval <1-600> level-2", - "IS-IS commands\n" - "Set Hello interval\n" - "Hello interval value\n" - "Holdtime 1 second, interval depends on multiplier\n" - "Specify hello-interval for level-2 IIHs\n") -{ - long interval; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - interval = atoi (argv[0]); - if (interval < MIN_HELLO_INTERVAL || interval > MAX_HELLO_INTERVAL) - { - vty_out (vty, "Invalid hello-interval %ld - should be <1-600>%s", - interval, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - circuit->hello_interval[1] = (u_int16_t) interval; - - return CMD_SUCCESS; -} - -DEFUN (no_isis_hello_interval_l2, - no_isis_hello_interval_l2_cmd, - "no isis hello-interval level-2", - NO_STR - "IS-IS commands\n" - "Set Hello interval\n" - "Specify hello-interval for level-2 IIHs\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit->hello_interval[1] = DEFAULT_HELLO_INTERVAL; - - return CMD_SUCCESS; -} - -ALIAS (no_isis_hello_interval_l2, - no_isis_hello_interval_l2_arg_cmd, - "no isis hello-interval <1-600> level-2", - NO_STR - "IS-IS commands\n" - "Set Hello interval\n" - "Hello interval value\n" - "Holdtime 1 second, interval depends on multiplier\n" - "Specify hello-interval for level-2 IIHs\n") - -DEFUN (isis_hello_multiplier, - isis_hello_multiplier_cmd, - "isis hello-multiplier <2-100>", - "IS-IS commands\n" - "Set multiplier for Hello holding time\n" - "Hello multiplier value\n") -{ - int mult; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - mult = atoi (argv[0]); - if (mult < MIN_HELLO_MULTIPLIER || mult > MAX_HELLO_MULTIPLIER) - { - vty_out (vty, "Invalid hello-multiplier %d - should be <2-100>%s", - mult, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - circuit->hello_multiplier[0] = (u_int16_t) mult; - circuit->hello_multiplier[1] = (u_int16_t) mult; - - return CMD_SUCCESS; -} - -DEFUN (no_isis_hello_multiplier, - no_isis_hello_multiplier_cmd, - "no isis hello-multiplier", - NO_STR - "IS-IS commands\n" - "Set multiplier for Hello holding time\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit->hello_multiplier[0] = DEFAULT_HELLO_MULTIPLIER; - circuit->hello_multiplier[1] = DEFAULT_HELLO_MULTIPLIER; - - return CMD_SUCCESS; -} - -ALIAS (no_isis_hello_multiplier, - no_isis_hello_multiplier_arg_cmd, - "no isis hello-multiplier <2-100>", - NO_STR - "IS-IS commands\n" - "Set multiplier for Hello holding time\n" - "Hello multiplier value\n") - -DEFUN (isis_hello_multiplier_l1, - isis_hello_multiplier_l1_cmd, - "isis hello-multiplier <2-100> level-1", - "IS-IS commands\n" - "Set multiplier for Hello holding time\n" - "Hello multiplier value\n" - "Specify hello multiplier for level-1 IIHs\n") -{ - int mult; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - mult = atoi (argv[0]); - if (mult < MIN_HELLO_MULTIPLIER || mult > MAX_HELLO_MULTIPLIER) - { - vty_out (vty, "Invalid hello-multiplier %d - should be <2-100>%s", - mult, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - circuit->hello_multiplier[0] = (u_int16_t) mult; - - return CMD_SUCCESS; -} - -DEFUN (no_isis_hello_multiplier_l1, - no_isis_hello_multiplier_l1_cmd, - "no isis hello-multiplier level-1", - NO_STR - "IS-IS commands\n" - "Set multiplier for Hello holding time\n" - "Specify hello multiplier for level-1 IIHs\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit->hello_multiplier[0] = DEFAULT_HELLO_MULTIPLIER; - - return CMD_SUCCESS; -} - -ALIAS (no_isis_hello_multiplier_l1, - no_isis_hello_multiplier_l1_arg_cmd, - "no isis hello-multiplier <2-100> level-1", - NO_STR - "IS-IS commands\n" - "Set multiplier for Hello holding time\n" - "Hello multiplier value\n" - "Specify hello multiplier for level-1 IIHs\n") - -DEFUN (isis_hello_multiplier_l2, - isis_hello_multiplier_l2_cmd, - "isis hello-multiplier <2-100> level-2", - "IS-IS commands\n" - "Set multiplier for Hello holding time\n" - "Hello multiplier value\n" - "Specify hello multiplier for level-2 IIHs\n") -{ - int mult; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - mult = atoi (argv[0]); - if (mult < MIN_HELLO_MULTIPLIER || mult > MAX_HELLO_MULTIPLIER) - { - vty_out (vty, "Invalid hello-multiplier %d - should be <2-100>%s", - mult, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - circuit->hello_multiplier[1] = (u_int16_t) mult; - - return CMD_SUCCESS; -} - -DEFUN (no_isis_hello_multiplier_l2, - no_isis_hello_multiplier_l2_cmd, - "no isis hello-multiplier level-2", - NO_STR - "IS-IS commands\n" - "Set multiplier for Hello holding time\n" - "Specify hello multiplier for level-2 IIHs\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit->hello_multiplier[1] = DEFAULT_HELLO_MULTIPLIER; - - return CMD_SUCCESS; -} - -ALIAS (no_isis_hello_multiplier_l2, - no_isis_hello_multiplier_l2_arg_cmd, - "no isis hello-multiplier <2-100> level-2", - NO_STR - "IS-IS commands\n" - "Set multiplier for Hello holding time\n" - "Hello multiplier value\n" - "Specify hello multiplier for level-2 IIHs\n") - -DEFUN (isis_hello_padding, - isis_hello_padding_cmd, - "isis hello padding", - "IS-IS commands\n" - "Add padding to IS-IS hello packets\n" - "Pad hello packets\n" - "\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit->pad_hellos = 1; - - return CMD_SUCCESS; -} - -DEFUN (no_isis_hello_padding, - no_isis_hello_padding_cmd, - "no isis hello padding", - NO_STR - "IS-IS commands\n" - "Add padding to IS-IS hello packets\n" - "Pad hello packets\n" - "\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit->pad_hellos = 0; - - return CMD_SUCCESS; -} - -DEFUN (csnp_interval, - csnp_interval_cmd, - "isis csnp-interval <1-600>", - "IS-IS commands\n" - "Set CSNP interval in seconds\n" - "CSNP interval value\n") -{ - unsigned long interval; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - interval = atol (argv[0]); - if (interval < MIN_CSNP_INTERVAL || interval > MAX_CSNP_INTERVAL) - { - vty_out (vty, "Invalid csnp-interval %lu - should be <1-600>%s", - interval, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - circuit->csnp_interval[0] = (u_int16_t) interval; - circuit->csnp_interval[1] = (u_int16_t) interval; - - return CMD_SUCCESS; -} - -DEFUN (no_csnp_interval, - no_csnp_interval_cmd, - "no isis csnp-interval", - NO_STR - "IS-IS commands\n" - "Set CSNP interval in seconds\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit->csnp_interval[0] = DEFAULT_CSNP_INTERVAL; - circuit->csnp_interval[1] = DEFAULT_CSNP_INTERVAL; - - return CMD_SUCCESS; -} - -ALIAS (no_csnp_interval, - no_csnp_interval_arg_cmd, - "no isis csnp-interval <1-600>", - NO_STR - "IS-IS commands\n" - "Set CSNP interval in seconds\n" - "CSNP interval value\n") - -DEFUN (csnp_interval_l1, - csnp_interval_l1_cmd, - "isis csnp-interval <1-600> level-1", - "IS-IS commands\n" - "Set CSNP interval in seconds\n" - "CSNP interval value\n" - "Specify interval for level-1 CSNPs\n") -{ - unsigned long interval; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - interval = atol (argv[0]); - if (interval < MIN_CSNP_INTERVAL || interval > MAX_CSNP_INTERVAL) - { - vty_out (vty, "Invalid csnp-interval %lu - should be <1-600>%s", - interval, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - circuit->csnp_interval[0] = (u_int16_t) interval; - - return CMD_SUCCESS; -} - -DEFUN (no_csnp_interval_l1, - no_csnp_interval_l1_cmd, - "no isis csnp-interval level-1", - NO_STR - "IS-IS commands\n" - "Set CSNP interval in seconds\n" - "Specify interval for level-1 CSNPs\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit->csnp_interval[0] = DEFAULT_CSNP_INTERVAL; - - return CMD_SUCCESS; -} - -ALIAS (no_csnp_interval_l1, - no_csnp_interval_l1_arg_cmd, - "no isis csnp-interval <1-600> level-1", - NO_STR - "IS-IS commands\n" - "Set CSNP interval in seconds\n" - "CSNP interval value\n" - "Specify interval for level-1 CSNPs\n") - -DEFUN (csnp_interval_l2, - csnp_interval_l2_cmd, - "isis csnp-interval <1-600> level-2", - "IS-IS commands\n" - "Set CSNP interval in seconds\n" - "CSNP interval value\n" - "Specify interval for level-2 CSNPs\n") -{ - unsigned long interval; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - interval = atol (argv[0]); - if (interval < MIN_CSNP_INTERVAL || interval > MAX_CSNP_INTERVAL) - { - vty_out (vty, "Invalid csnp-interval %lu - should be <1-600>%s", - interval, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - circuit->csnp_interval[1] = (u_int16_t) interval; - - return CMD_SUCCESS; -} - -DEFUN (no_csnp_interval_l2, - no_csnp_interval_l2_cmd, - "no isis csnp-interval level-2", - NO_STR - "IS-IS commands\n" - "Set CSNP interval in seconds\n" - "Specify interval for level-2 CSNPs\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit->csnp_interval[1] = DEFAULT_CSNP_INTERVAL; - - return CMD_SUCCESS; -} - -ALIAS (no_csnp_interval_l2, - no_csnp_interval_l2_arg_cmd, - "no isis csnp-interval <1-600> level-2", - NO_STR - "IS-IS commands\n" - "Set CSNP interval in seconds\n" - "CSNP interval value\n" - "Specify interval for level-2 CSNPs\n") - -DEFUN (psnp_interval, - psnp_interval_cmd, - "isis psnp-interval <1-120>", - "IS-IS commands\n" - "Set PSNP interval in seconds\n" - "PSNP interval value\n") -{ - unsigned long interval; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - interval = atol (argv[0]); - if (interval < MIN_PSNP_INTERVAL || interval > MAX_PSNP_INTERVAL) - { - vty_out (vty, "Invalid psnp-interval %lu - should be <1-120>%s", - interval, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - circuit->psnp_interval[0] = (u_int16_t) interval; - circuit->psnp_interval[1] = (u_int16_t) interval; - - return CMD_SUCCESS; -} - -DEFUN (no_psnp_interval, - no_psnp_interval_cmd, - "no isis psnp-interval", - NO_STR - "IS-IS commands\n" - "Set PSNP interval in seconds\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit->psnp_interval[0] = DEFAULT_PSNP_INTERVAL; - circuit->psnp_interval[1] = DEFAULT_PSNP_INTERVAL; - - return CMD_SUCCESS; -} - -ALIAS (no_psnp_interval, - no_psnp_interval_arg_cmd, - "no isis psnp-interval <1-120>", - NO_STR - "IS-IS commands\n" - "Set PSNP interval in seconds\n" - "PSNP interval value\n") - -DEFUN (psnp_interval_l1, - psnp_interval_l1_cmd, - "isis psnp-interval <1-120> level-1", - "IS-IS commands\n" - "Set PSNP interval in seconds\n" - "PSNP interval value\n" - "Specify interval for level-1 PSNPs\n") -{ - unsigned long interval; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - interval = atol (argv[0]); - if (interval < MIN_PSNP_INTERVAL || interval > MAX_PSNP_INTERVAL) - { - vty_out (vty, "Invalid psnp-interval %lu - should be <1-120>%s", - interval, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - circuit->psnp_interval[0] = (u_int16_t) interval; - - return CMD_SUCCESS; -} - -DEFUN (no_psnp_interval_l1, - no_psnp_interval_l1_cmd, - "no isis psnp-interval level-1", - NO_STR - "IS-IS commands\n" - "Set PSNP interval in seconds\n" - "Specify interval for level-1 PSNPs\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit->psnp_interval[0] = DEFAULT_PSNP_INTERVAL; - - return CMD_SUCCESS; -} - -ALIAS (no_psnp_interval_l1, - no_psnp_interval_l1_arg_cmd, - "no isis psnp-interval <1-120> level-1", - NO_STR - "IS-IS commands\n" - "Set PSNP interval in seconds\n" - "PSNP interval value\n" - "Specify interval for level-1 PSNPs\n") - -DEFUN (psnp_interval_l2, - psnp_interval_l2_cmd, - "isis psnp-interval <1-120> level-2", - "IS-IS commands\n" - "Set PSNP interval in seconds\n" - "PSNP interval value\n" - "Specify interval for level-2 PSNPs\n") -{ - unsigned long interval; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - interval = atol (argv[0]); - if (interval < MIN_PSNP_INTERVAL || interval > MAX_PSNP_INTERVAL) - { - vty_out (vty, "Invalid psnp-interval %lu - should be <1-120>%s", - interval, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - circuit->psnp_interval[1] = (u_int16_t) interval; - - return CMD_SUCCESS; -} - -DEFUN (no_psnp_interval_l2, - no_psnp_interval_l2_cmd, - "no isis psnp-interval level-2", - NO_STR - "IS-IS commands\n" - "Set PSNP interval in seconds\n" - "Specify interval for level-2 PSNPs\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit->psnp_interval[1] = DEFAULT_PSNP_INTERVAL; - - return CMD_SUCCESS; -} - -ALIAS (no_psnp_interval_l2, - no_psnp_interval_l2_arg_cmd, - "no isis psnp-interval <1-120> level-2", - NO_STR - "IS-IS commands\n" - "Set PSNP interval in seconds\n" - "PSNP interval value\n" - "Specify interval for level-2 PSNPs\n") - struct cmd_node interface_node = { INTERFACE_NODE, "%s(config-if)# ", 1, }; -DEFUN (isis_network, - isis_network_cmd, - "isis network point-to-point", - "IS-IS commands\n" - "Set network type\n" - "point-to-point network type\n") +int +isis_circuit_circ_type_set(struct isis_circuit *circuit, int circ_type) { - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; + /* Changing the network type to/of loopback or unknown interfaces + * is not supported. */ + if (circ_type == CIRCUIT_T_UNKNOWN + || circ_type == CIRCUIT_T_LOOPBACK + || circuit->circ_type == CIRCUIT_T_LOOPBACK) + { + if (circuit->circ_type != circ_type) + return -1; + else + return 0; + } - /* RFC5309 section 4 */ - if (circuit->circ_type == CIRCUIT_T_P2P) - return CMD_SUCCESS; + if (circuit->circ_type == circ_type) + return 0; if (circuit->state != C_STATE_UP) { - circuit->circ_type = CIRCUIT_T_P2P; - circuit->circ_type_config = CIRCUIT_T_P2P; + circuit->circ_type = circ_type; + circuit->circ_type_config = circ_type; } else { struct isis_area *area = circuit->area; - if (!if_is_broadcast (circuit->interface)) - { - vty_out (vty, "isis network point-to-point " - "is valid only on broadcast interfaces%s", - VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } + if (circ_type == CIRCUIT_T_BROADCAST + && !if_is_broadcast(circuit->interface)) + return -1; - isis_csm_state_change (ISIS_DISABLE, circuit, area); - circuit->circ_type = CIRCUIT_T_P2P; - circuit->circ_type_config = CIRCUIT_T_P2P; - isis_csm_state_change (ISIS_ENABLE, circuit, area); + isis_csm_state_change(ISIS_DISABLE, circuit, area); + circuit->circ_type = circ_type; + circuit->circ_type_config = circ_type; + isis_csm_state_change(ISIS_ENABLE, circuit, area); } - - return CMD_SUCCESS; -} - -DEFUN (no_isis_network, - no_isis_network_cmd, - "no isis network point-to-point", - NO_STR - "IS-IS commands\n" - "Set network type for circuit\n" - "point-to-point network type\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - /* RFC5309 section 4 */ - if (circuit->circ_type == CIRCUIT_T_BROADCAST) - return CMD_SUCCESS; - - if (circuit->state != C_STATE_UP) - { - circuit->circ_type = CIRCUIT_T_BROADCAST; - circuit->circ_type_config = CIRCUIT_T_BROADCAST; - } - else - { - struct isis_area *area = circuit->area; - if (circuit->interface && - !if_is_broadcast (circuit->interface)) - { - vty_out (vty, "no isis network point-to-point " - "is valid only on broadcast interfaces%s", - VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - isis_csm_state_change (ISIS_DISABLE, circuit, area); - circuit->circ_type = CIRCUIT_T_BROADCAST; - circuit->circ_type_config = CIRCUIT_T_BROADCAST; - isis_csm_state_change (ISIS_ENABLE, circuit, area); - } - - return CMD_SUCCESS; + return 0; } int @@ -2845,87 +1419,5 @@ isis_circuit_init () install_element (INTERFACE_NODE, &interface_desc_cmd); install_element (INTERFACE_NODE, &no_interface_desc_cmd); - install_element (INTERFACE_NODE, &ip_router_isis_cmd); - install_element (INTERFACE_NODE, &no_ip_router_isis_cmd); - - install_element (INTERFACE_NODE, &isis_passive_cmd); - install_element (INTERFACE_NODE, &no_isis_passive_cmd); - - install_element (INTERFACE_NODE, &isis_circuit_type_cmd); - install_element (INTERFACE_NODE, &no_isis_circuit_type_cmd); - - install_element (INTERFACE_NODE, &isis_passwd_clear_cmd); - install_element (INTERFACE_NODE, &isis_passwd_md5_cmd); - install_element (INTERFACE_NODE, &no_isis_passwd_cmd); - - install_element (INTERFACE_NODE, &isis_priority_cmd); - install_element (INTERFACE_NODE, &no_isis_priority_cmd); - install_element (INTERFACE_NODE, &no_isis_priority_arg_cmd); - install_element (INTERFACE_NODE, &isis_priority_l1_cmd); - install_element (INTERFACE_NODE, &no_isis_priority_l1_cmd); - install_element (INTERFACE_NODE, &no_isis_priority_l1_arg_cmd); - install_element (INTERFACE_NODE, &isis_priority_l2_cmd); - install_element (INTERFACE_NODE, &no_isis_priority_l2_cmd); - install_element (INTERFACE_NODE, &no_isis_priority_l2_arg_cmd); - - install_element (INTERFACE_NODE, &isis_metric_cmd); - install_element (INTERFACE_NODE, &no_isis_metric_cmd); - install_element (INTERFACE_NODE, &no_isis_metric_arg_cmd); - install_element (INTERFACE_NODE, &isis_metric_l1_cmd); - install_element (INTERFACE_NODE, &no_isis_metric_l1_cmd); - install_element (INTERFACE_NODE, &no_isis_metric_l1_arg_cmd); - install_element (INTERFACE_NODE, &isis_metric_l2_cmd); - install_element (INTERFACE_NODE, &no_isis_metric_l2_cmd); - install_element (INTERFACE_NODE, &no_isis_metric_l2_arg_cmd); - - install_element (INTERFACE_NODE, &isis_hello_interval_cmd); - install_element (INTERFACE_NODE, &no_isis_hello_interval_cmd); - install_element (INTERFACE_NODE, &no_isis_hello_interval_arg_cmd); - install_element (INTERFACE_NODE, &isis_hello_interval_l1_cmd); - install_element (INTERFACE_NODE, &no_isis_hello_interval_l1_cmd); - install_element (INTERFACE_NODE, &no_isis_hello_interval_l1_arg_cmd); - install_element (INTERFACE_NODE, &isis_hello_interval_l2_cmd); - install_element (INTERFACE_NODE, &no_isis_hello_interval_l2_cmd); - install_element (INTERFACE_NODE, &no_isis_hello_interval_l2_arg_cmd); - - install_element (INTERFACE_NODE, &isis_hello_multiplier_cmd); - install_element (INTERFACE_NODE, &no_isis_hello_multiplier_cmd); - install_element (INTERFACE_NODE, &no_isis_hello_multiplier_arg_cmd); - install_element (INTERFACE_NODE, &isis_hello_multiplier_l1_cmd); - install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l1_cmd); - install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l1_arg_cmd); - install_element (INTERFACE_NODE, &isis_hello_multiplier_l2_cmd); - install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l2_cmd); - install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l2_arg_cmd); - - install_element (INTERFACE_NODE, &isis_hello_padding_cmd); - install_element (INTERFACE_NODE, &no_isis_hello_padding_cmd); - - install_element (INTERFACE_NODE, &csnp_interval_cmd); - install_element (INTERFACE_NODE, &no_csnp_interval_cmd); - install_element (INTERFACE_NODE, &no_csnp_interval_arg_cmd); - install_element (INTERFACE_NODE, &csnp_interval_l1_cmd); - install_element (INTERFACE_NODE, &no_csnp_interval_l1_cmd); - install_element (INTERFACE_NODE, &no_csnp_interval_l1_arg_cmd); - install_element (INTERFACE_NODE, &csnp_interval_l2_cmd); - install_element (INTERFACE_NODE, &no_csnp_interval_l2_cmd); - install_element (INTERFACE_NODE, &no_csnp_interval_l2_arg_cmd); - - install_element (INTERFACE_NODE, &psnp_interval_cmd); - install_element (INTERFACE_NODE, &no_psnp_interval_cmd); - install_element (INTERFACE_NODE, &no_psnp_interval_arg_cmd); - install_element (INTERFACE_NODE, &psnp_interval_l1_cmd); - install_element (INTERFACE_NODE, &no_psnp_interval_l1_cmd); - install_element (INTERFACE_NODE, &no_psnp_interval_l1_arg_cmd); - install_element (INTERFACE_NODE, &psnp_interval_l2_cmd); - install_element (INTERFACE_NODE, &no_psnp_interval_l2_cmd); - install_element (INTERFACE_NODE, &no_psnp_interval_l2_arg_cmd); - - install_element (INTERFACE_NODE, &isis_network_cmd); - install_element (INTERFACE_NODE, &no_isis_network_cmd); - -#ifdef HAVE_IPV6 - install_element (INTERFACE_NODE, &ipv6_router_isis_cmd); - install_element (INTERFACE_NODE, &no_ipv6_router_isis_cmd); -#endif + isis_vty_init (); } diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h index d883879731..9ada1e26a3 100644 --- a/isisd/isis_circuit.h +++ b/isisd/isis_circuit.h @@ -24,6 +24,10 @@ #define ISIS_CIRCUIT_H #include "vty.h" +#include "if.h" + +#include "isis_constants.h" +#include "isis_common.h" #define CIRCUIT_MAX 255 @@ -108,13 +112,14 @@ struct isis_circuit */ struct isis_passwd passwd; /* Circuit rx/tx password */ int is_type; /* circuit is type == level of circuit - * diffrenciated from circuit type (media) */ + * differentiated from circuit type (media) */ u_int32_t hello_interval[2]; /* l1HelloInterval in msecs */ u_int16_t hello_multiplier[2]; /* l1HelloMultiplier */ u_int16_t csnp_interval[2]; /* level-1 csnp-interval in seconds */ u_int16_t psnp_interval[2]; /* level-1 psnp-interval in seconds */ - struct metric metrics[2]; /* l1XxxMetric */ + u_int8_t metric[2]; u_int32_t te_metric[2]; + struct mpls_te_circuit *mtc; /* Support for MPLS-TE parameters - see isis_te.[c,h] */ int ip_router; /* Route IP ? */ int is_passive; /* Is Passive ? */ struct list *ip_addrs; /* our IP addresses */ @@ -167,4 +172,16 @@ void isis_circuit_print_vty (struct isis_circuit *circuit, struct vty *vty, size_t isis_circuit_pdu_size(struct isis_circuit *circuit); void isis_circuit_stream(struct isis_circuit *circuit, struct stream **stream); +struct isis_circuit *isis_circuit_create (struct isis_area *area, struct interface *ifp); +void isis_circuit_af_set (struct isis_circuit *circuit, bool ip_router, bool ipv6_router); +int isis_circuit_passive_set (struct isis_circuit *circuit, bool passive); +void isis_circuit_is_type_set (struct isis_circuit *circuit, int is_type); +int isis_circuit_circ_type_set (struct isis_circuit *circuit, int circ_type); + +int isis_circuit_metric_set (struct isis_circuit *circuit, int level, int metric); + +int isis_circuit_passwd_unset (struct isis_circuit *circuit); +int isis_circuit_passwd_cleartext_set (struct isis_circuit *circuit, const char *passwd); +int isis_circuit_passwd_hmac_md5_set (struct isis_circuit *circuit, const char *passwd); + #endif /* _ZEBRA_ISIS_CIRCUIT_H */ diff --git a/isisd/isis_events.c b/isisd/isis_events.c index 0dee9e6f52..460b1d25ba 100644 --- a/isisd/isis_events.c +++ b/isisd/isis_events.c @@ -77,119 +77,6 @@ isis_event_circuit_state_change (struct isis_circuit *circuit, return; } -static void -area_resign_level (struct isis_area *area, int level) -{ - if (area->lspdb[level - 1]) - { - lsp_db_destroy (area->lspdb[level - 1]); - area->lspdb[level - 1] = NULL; - } - if (area->spftree[level - 1]) - { - isis_spftree_del (area->spftree[level - 1]); - area->spftree[level - 1] = NULL; - } -#ifdef HAVE_IPV6 - if (area->spftree6[level - 1]) - { - isis_spftree_del (area->spftree6[level - 1]); - area->spftree6[level - 1] = NULL; - } -#endif - if (area->route_table[level - 1]) - { - route_table_finish (area->route_table[level - 1]); - area->route_table[level - 1] = NULL; - } -#ifdef HAVE_IPV6 - if (area->route_table6[level - 1]) - { - route_table_finish (area->route_table6[level - 1]); - area->route_table6[level - 1] = NULL; - } -#endif /* HAVE_IPV6 */ - - sched_debug("ISIS (%s): Resigned from L%d - canceling LSP regeneration timer.", - area->area_tag, level); - THREAD_TIMER_OFF (area->t_lsp_refresh[level - 1]); - area->lsp_regenerate_pending[level - 1] = 0; -} - -void -isis_event_system_type_change (struct isis_area *area, int newtype) -{ - struct listnode *node; - struct isis_circuit *circuit; - - if (isis->debugs & DEBUG_EVENTS) - zlog_debug ("ISIS-Evt (%s) system type change %s -> %s", area->area_tag, - circuit_t2string (area->is_type), circuit_t2string (newtype)); - - if (area->is_type == newtype) - return; /* No change */ - - switch (area->is_type) - { - case IS_LEVEL_1: - if (newtype == IS_LEVEL_2) - area_resign_level (area, IS_LEVEL_1); - - if (area->lspdb[1] == NULL) - area->lspdb[1] = lsp_db_init (); - if (area->route_table[1] == NULL) - area->route_table[1] = route_table_init (); -#ifdef HAVE_IPV6 - if (area->route_table6[1] == NULL) - area->route_table6[1] = route_table_init (); -#endif /* HAVE_IPV6 */ - break; - - case IS_LEVEL_1_AND_2: - if (newtype == IS_LEVEL_1) - area_resign_level (area, IS_LEVEL_2); - else - area_resign_level (area, IS_LEVEL_1); - break; - - case IS_LEVEL_2: - if (newtype == IS_LEVEL_1) - area_resign_level (area, IS_LEVEL_2); - - if (area->lspdb[0] == NULL) - area->lspdb[0] = lsp_db_init (); - if (area->route_table[0] == NULL) - area->route_table[0] = route_table_init (); -#ifdef HAVE_IPV6 - if (area->route_table6[0] == NULL) - area->route_table6[0] = route_table_init (); -#endif /* HAVE_IPV6 */ - break; - - default: - break; - } - - area->is_type = newtype; - - /* override circuit's is_type */ - if (area->is_type != IS_LEVEL_1_AND_2) - { - for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit)) - isis_event_circuit_type_change (circuit, newtype); - } - - spftree_area_init (area); - - if (newtype & IS_LEVEL_1) - lsp_generate (area, IS_LEVEL_1); - if (newtype & IS_LEVEL_2) - lsp_generate (area, IS_LEVEL_2); - lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); - - return; -} - static void circuit_commence_level (struct isis_circuit *circuit, int level) { @@ -258,7 +145,7 @@ circuit_resign_level (struct isis_circuit *circuit, int level) } void -isis_event_circuit_type_change (struct isis_circuit *circuit, int newtype) +isis_circuit_is_type_set (struct isis_circuit *circuit, int newtype) { if (circuit->state != C_STATE_UP) { diff --git a/isisd/isis_events.h b/isisd/isis_events.h index c252f3def9..e7cfa3509e 100644 --- a/isisd/isis_events.h +++ b/isisd/isis_events.h @@ -22,11 +22,6 @@ #ifndef _ZEBRA_ISIS_EVENTS_H #define _ZEBRA_ISIS_EVENTS_H -/* - * Events related to area - */ -void isis_event_system_type_change (struct isis_area *area, int newtype); - /* * Events related to circuit */ diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 7309248611..0177a9423a 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -52,6 +52,7 @@ #include "isisd/isis_csm.h" #include "isisd/isis_adjacency.h" #include "isisd/isis_spf.h" +#include "isisd/isis_te.h" #ifdef TOPOLOGY_GENERATE #include "spgrid.h" @@ -981,6 +982,8 @@ lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost) lspid_print (te_is_neigh->neigh_id, LSPid, dynhost, 0); vty_out (vty, " Metric : %-8d IS-Extended : %s%s", GET_TE_METRIC(te_is_neigh), LSPid, VTY_NEWLINE); + if (IS_MPLS_TE(isisMplsTE)) + mpls_te_print_detail(vty, te_is_neigh); } /* TE IPv4 tlv */ @@ -1091,6 +1094,64 @@ lsp_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to, return; } +/* Process IS_NEIGHBOURS TLV with TE subTLVs */ +void +lsp_te_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to, int frag_thold) +{ + int count, size = 0; + struct listnode *node, *nextnode; + struct te_is_neigh *elem; + + /* Start computing real size of TLVs */ + for (ALL_LIST_ELEMENTS (*from, node, nextnode, elem)) + size = size + elem->sub_tlvs_length + IS_NEIGHBOURS_LEN; + + /* can we fit all ? */ + if (!FRAG_NEEDED (lsp->pdu, frag_thold, size)) + { + tlv_add_te_is_neighs (*from, lsp->pdu); + if (listcount (*to) != 0) + { + for (ALL_LIST_ELEMENTS (*from, node, nextnode, elem)) + { + listnode_add (*to, elem); + list_delete_node (*from, node); + } + } + else + { + list_free (*to); + *to = *from; + *from = NULL; + } + } + else + { + /* fit all we can */ + /* Compute remaining place in LSP PDU */ + count = FRAG_THOLD (lsp->pdu, frag_thold) - 2 - + (STREAM_SIZE (lsp->pdu) - STREAM_REMAIN (lsp->pdu)); + /* Determine size of TE SubTLVs */ + elem = (struct te_is_neigh *)listgetdata ((struct listnode *)listhead (*from)); + count = count - elem->sub_tlvs_length - IS_NEIGHBOURS_LEN; + if (count > 0) + { + while (count > 0) + { + listnode_add (*to, listgetdata ((struct listnode *)listhead (*from))); + listnode_delete (*from, listgetdata ((struct listnode *)listhead (*from))); + + elem = (struct te_is_neigh *)listgetdata ((struct listnode *)listhead (*from)); + count = count - elem->sub_tlvs_length - IS_NEIGHBOURS_LEN; + } + + tlv_add_te_is_neighs (*to, lsp->pdu); + } + } + lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu)); + return; +} + static u_int16_t lsp_rem_lifetime (struct isis_area *area, int level) { @@ -1481,7 +1542,10 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) { ipreach = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct ipv4_reachability)); - ipreach->metrics = circuit->metrics[level - 1]; + ipreach->metrics.metric_default = circuit->metric[level - 1]; + ipreach->metrics.metric_expense = METRICS_UNSUPPORTED; + ipreach->metrics.metric_error = METRICS_UNSUPPORTED; + ipreach->metrics.metric_delay = METRICS_UNSUPPORTED; masklen2ip (ipv4->prefixlen, &ipreach->mask); ipreach->prefix.s_addr = ((ipreach->mask.s_addr) & (ipv4->prefix.s_addr)); @@ -1506,7 +1570,7 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) ((ipv4->prefixlen + 7)/8) - 1); if (area->oldmetric) - te_ipreach->te_metric = htonl (circuit->metrics[level - 1].metric_default); + te_ipreach->te_metric = htonl (circuit->metric[level - 1]); else te_ipreach->te_metric = htonl (circuit->te_metric[level - 1]); @@ -1541,7 +1605,7 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) if (area->oldmetric) ip6reach->metric = - htonl (circuit->metrics[level - 1].metric_default); + htonl (circuit->metric[level - 1]); else ip6reach->metric = htonl (circuit->te_metric[level - 1]); @@ -1580,7 +1644,10 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) else memcpy (is_neigh->neigh_id, circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1); - is_neigh->metrics = circuit->metrics[level - 1]; + is_neigh->metrics.metric_default = circuit->metric[level - 1]; + is_neigh->metrics.metric_expense = METRICS_UNSUPPORTED; + is_neigh->metrics.metric_error = METRICS_UNSUPPORTED; + is_neigh->metrics.metric_delay = METRICS_UNSUPPORTED; if (!memcmp (is_neigh->neigh_id, zero_id, ISIS_SYS_ID_LEN + 1)) { @@ -1612,7 +1679,7 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) memcpy (te_is_neigh->neigh_id, circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1); if (area->oldmetric) - metric = circuit->metrics[level - 1].metric_default; + metric = circuit->metric[level - 1]; else metric = circuit->te_metric[level - 1]; SET_TE_METRIC(te_is_neigh, metric); @@ -1625,6 +1692,14 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) } else { + /* Check if MPLS_TE is activate */ + if (IS_MPLS_TE(isisMplsTE) && HAS_LINK_PARAMS(circuit->interface)) + /* Add SubTLVs & Adjust real size of SubTLVs */ + te_is_neigh->sub_tlvs_length = add_te_subtlvs(te_is_neigh->sub_tlvs, circuit->mtc); + else + /* Or keep only TE metric with no SubTLVs if MPLS_TE is off */ + te_is_neigh->sub_tlvs_length = 0; + listnode_add (tlv_data.te_is_neighs, te_is_neigh); lsp_debug("ISIS (%s): Adding DIS %s.%02x as te-style neighbor", area->area_tag, sysid_print(te_is_neigh->neigh_id), @@ -1651,7 +1726,10 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) } is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh)); memcpy (is_neigh->neigh_id, nei->sysid, ISIS_SYS_ID_LEN); - is_neigh->metrics = circuit->metrics[level - 1]; + is_neigh->metrics.metric_default = circuit->metric[level - 1]; + is_neigh->metrics.metric_expense = METRICS_UNSUPPORTED; + is_neigh->metrics.metric_error = METRICS_UNSUPPORTED; + is_neigh->metrics.metric_delay = METRICS_UNSUPPORTED; listnode_add (tlv_data.is_neighs, is_neigh); lsp_debug("ISIS (%s): Adding old-style is reach for %s", area->area_tag, sysid_print(is_neigh->neigh_id)); @@ -1670,6 +1748,18 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) memcpy (te_is_neigh->neigh_id, nei->sysid, ISIS_SYS_ID_LEN); metric = circuit->te_metric[level - 1]; SET_TE_METRIC(te_is_neigh, metric); + /* Check if MPLS_TE is activate */ + if (IS_MPLS_TE(isisMplsTE) && HAS_LINK_PARAMS(circuit->interface)) + /* Update Local and Remote IP address for MPLS TE circuit parameters */ + /* NOTE sure that it is the pertinent place for that updates */ + /* Local IP address could be updated in isis_circuit.c - isis_circuit_add_addr() */ + /* But, where update remote IP address ? in isis_pdu.c - process_p2p_hello() ? */ + + /* Add SubTLVs & Adjust real size of SubTLVs */ + te_is_neigh->sub_tlvs_length = add_te_subtlvs(te_is_neigh->sub_tlvs, circuit->mtc); + else + /* Or keep only TE metric with no SubTLVs if MPLS_TE is off */ + te_is_neigh->sub_tlvs_length = 0; listnode_add (tlv_data.te_is_neighs, te_is_neigh); lsp_debug("ISIS (%s): Adding te-style is reach for %s", area->area_tag, sysid_print(te_is_neigh->neigh_id)); diff --git a/isisd/isis_lsp.h b/isisd/isis_lsp.h index a35bfa7622..7b2286b189 100644 --- a/isisd/isis_lsp.h +++ b/isisd/isis_lsp.h @@ -112,6 +112,8 @@ void lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost); int lsp_print_all (struct vty *vty, dict_t * lspdb, char detail, char dynhost); const char *lsp_bits2string (u_char *); +void lsp_te_tlv_fit (struct isis_lsp *lsp, struct list **from, + struct list **to, int frag_thold); /* sets SRMflags for all active circuits of an lsp */ void lsp_set_all_srmflags (struct isis_lsp *lsp); diff --git a/isisd/isis_main.c b/isisd/isis_main.c index f088bc1dec..81ca1e20c6 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -50,6 +50,8 @@ #include "isisd/isis_route.h" #include "isisd/isis_routemap.h" #include "isisd/isis_zebra.h" +#include "isisd/isis_tlv.h" +#include "isisd/isis_te.h" /* Default configuration file name */ #define ISISD_DEFAULT_CONFIG "isisd.conf" @@ -245,7 +247,9 @@ main (int argc, char **argv, char **envp) zlog_default = openzlog (progname, ZLOG_ISIS, 0, LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON); zprivs_init (&isisd_privs); - zlog_set_file (NULL, LOG_DEFAULT_FILENAME , zlog_default->default_lvl); +#if defined(HAVE_CUMULUS) + zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl); +#endif /* for reload */ _argc = argc; @@ -346,6 +350,7 @@ main (int argc, char **argv, char **envp) isis_spf_cmds_init (); isis_redist_init (); isis_route_map_init(); + isis_mpls_te_init(); /* create the global 'isis' instance */ isis_new (1); diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index 0401e44a9a..1dfb4623f6 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -53,6 +53,7 @@ #include "isisd/iso_checksum.h" #include "isisd/isis_csm.h" #include "isisd/isis_events.h" +#include "isisd/isis_te.h" #define ISIS_MINIMUM_FIXED_HDR_LEN 15 #define ISIS_MIN_PDU_LEN 13 /* partial seqnum pdu with id_len=2 */ @@ -630,6 +631,15 @@ process_p2p_hello (struct isis_circuit *circuit) if (found & TLVFLAG_IPV4_ADDR) tlvs_to_adj_ipv4_addrs (&tlvs, adj); + /* Update MPLS TE Remote IP address parameter if possible */ + if (IS_MPLS_TE(isisMplsTE) && circuit->mtc && IS_CIRCUIT_TE(circuit->mtc)) + if (adj->ipv4_addrs != NULL && listcount(adj->ipv4_addrs) != 0) + { + struct in_addr *ip_addr; + ip_addr = (struct in_addr *)listgetdata ((struct listnode *)listhead (adj->ipv4_addrs)); + set_circuitparams_rmt_ipaddr (circuit->mtc, *ip_addr); + } + #ifdef HAVE_IPV6 if (found & TLVFLAG_IPV6_ADDR) tlvs_to_adj_ipv6_addrs (&tlvs, adj); diff --git a/isisd/isis_redist.h b/isisd/isis_redist.h index 2184620054..cc9c2e6345 100644 --- a/isisd/isis_redist.h +++ b/isisd/isis_redist.h @@ -44,6 +44,7 @@ struct isis_redist struct isis_area; struct prefix; +struct vty; struct route_table *get_ext_reach(struct isis_area *area, int family, int level); diff --git a/isisd/isis_route.c b/isisd/isis_route.c index e72e0cac7a..67d45c8f10 100644 --- a/isisd/isis_route.c +++ b/isisd/isis_route.c @@ -50,7 +50,7 @@ #include "isis_zebra.h" static struct isis_nexthop * -isis_nexthop_create (struct in_addr *ip, unsigned int ifindex) +isis_nexthop_create (struct in_addr *ip, ifindex_t ifindex) { struct listnode *node; struct isis_nexthop *nexthop; @@ -91,7 +91,7 @@ isis_nexthop_delete (struct isis_nexthop *nexthop) static int nexthoplookup (struct list *nexthops, struct in_addr *ip, - unsigned int ifindex) + ifindex_t ifindex) { struct listnode *node; struct isis_nexthop *nh; @@ -130,7 +130,7 @@ nexthops_print (struct list *nhs) #ifdef HAVE_IPV6 static struct isis_nexthop6 * -isis_nexthop6_new (struct in6_addr *ip6, unsigned int ifindex) +isis_nexthop6_new (struct in6_addr *ip6, ifindex_t ifindex) { struct isis_nexthop6 *nexthop6; @@ -144,7 +144,7 @@ isis_nexthop6_new (struct in6_addr *ip6, unsigned int ifindex) } static struct isis_nexthop6 * -isis_nexthop6_create (struct in6_addr *ip6, unsigned int ifindex) +isis_nexthop6_create (struct in6_addr *ip6, ifindex_t ifindex) { struct listnode *node; struct isis_nexthop6 *nexthop6; @@ -181,7 +181,7 @@ isis_nexthop6_delete (struct isis_nexthop6 *nexthop6) static int nexthop6lookup (struct list *nexthops6, struct in6_addr *ip6, - unsigned int ifindex) + ifindex_t ifindex) { struct listnode *node; struct isis_nexthop6 *nh6; diff --git a/isisd/isis_route.h b/isisd/isis_route.h index 5adea2293b..0d2379cbe8 100644 --- a/isisd/isis_route.h +++ b/isisd/isis_route.h @@ -28,7 +28,7 @@ #ifdef HAVE_IPV6 struct isis_nexthop6 { - unsigned int ifindex; + ifindex_t ifindex; struct in6_addr ip6; struct in6_addr router_address6; unsigned int lock; @@ -37,7 +37,7 @@ struct isis_nexthop6 struct isis_nexthop { - unsigned int ifindex; + ifindex_t ifindex; struct in_addr ip; struct in_addr router_address; unsigned int lock; diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 32026f9b17..fd5af4a2b8 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -545,13 +545,13 @@ isis_spf_add2tent (struct isis_spftree *spftree, enum vertextype vtype, v = listgetdata (node); if (v->d_N > vertex->d_N) { - list_add_node_prev (spftree->tents, node, vertex); + listnode_add_before (spftree->tents, node, vertex); break; } else if (v->d_N == vertex->d_N && v->type > vertex->type) { /* Tie break, add according to type */ - list_add_node_prev (spftree->tents, node, vertex); + listnode_add_before (spftree->tents, node, vertex); break; } } diff --git a/isisd/isis_te.c b/isisd/isis_te.c new file mode 100644 index 0000000000..deaaa7104b --- /dev/null +++ b/isisd/isis_te.c @@ -0,0 +1,1369 @@ +/* + * IS-IS Rout(e)ing protocol - isis_te.c + * + * This is an implementation of RFC5305 + * + * Copyright (C) 2014 Orange Labs + * http://www.orange.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. + */ + +#include +#include + +#include "linklist.h" +#include "thread.h" +#include "vty.h" +#include "stream.h" +#include "memory.h" +#include "log.h" +#include "prefix.h" +#include "command.h" +#include "hash.h" +#include "if.h" +#include "vrf.h" +#include "checksum.h" +#include "md5.h" +#include "sockunion.h" +#include "network.h" + +#include "isisd/dict.h" +#include "isisd/isis_constants.h" +#include "isisd/isis_common.h" +#include "isisd/isis_flags.h" +#include "isisd/isis_circuit.h" +#include "isisd/isisd.h" +#include "isisd/isis_tlv.h" +#include "isisd/isis_lsp.h" +#include "isisd/isis_pdu.h" +#include "isisd/isis_dynhn.h" +#include "isisd/isis_misc.h" +#include "isisd/isis_csm.h" +#include "isisd/isis_adjacency.h" +#include "isisd/isis_spf.h" +#include "isisd/isis_te.h" + +/* Global varial for MPLS TE management */ +struct isis_mpls_te isisMplsTE; + +const char *mode2text[] = { "Disable", "Area", "AS", "Emulate" }; + +/*------------------------------------------------------------------------* + * Followings are control functions for MPLS-TE parameters management. + *------------------------------------------------------------------------*/ + +/* Search MPLS TE Circuit context from Interface */ +static struct mpls_te_circuit * +lookup_mpls_params_by_ifp (struct interface *ifp) +{ + struct isis_circuit *circuit; + + if ((circuit = circuit_scan_by_ifp (ifp)) == NULL) + return NULL; + + return circuit->mtc; +} + +/* Create new MPLS TE Circuit context */ +struct mpls_te_circuit * +mpls_te_circuit_new() +{ + struct mpls_te_circuit *mtc; + + zlog_debug ("ISIS MPLS-TE: Create new MPLS TE Circuit context"); + + mtc = XCALLOC(MTYPE_ISIS_MPLS_TE, sizeof (struct mpls_te_circuit)); + + if (mtc == NULL) + return NULL; + + mtc->status = disable; + mtc->type = STD_TE; + mtc->length = 0; + + return mtc; + +} + +/* Copy SUB TLVs parameters into a buffer - No space verification are performed */ +/* Caller must verify before that there is enough free space in the buffer */ +u_char +add_te_subtlvs(u_char *buf, struct mpls_te_circuit *mtc) +{ + u_char size, *tlvs = buf; + + zlog_debug ("ISIS MPLS-TE: Add TE Sub TLVs to buffer"); + + if (mtc == NULL) + { + zlog_debug("ISIS MPLS-TE: Abort! No MPLS TE Circuit available has been specified"); + return 0; + } + + /* Create buffer if not provided */ + if (buf == NULL) + { + zlog_debug("ISIS MPLS-TE: Abort! No Buffer has been specified"); + return 0; + } + + /* TE_SUBTLV_ADMIN_GRP */ + if (SUBTLV_TYPE(mtc->admin_grp) != 0) + { + size = SUBTLV_SIZE (&(mtc->admin_grp.header)); + memcpy(tlvs, &(mtc->admin_grp), size); + tlvs += size; + } + + /* TE_SUBTLV_LLRI */ + if (SUBTLV_TYPE(mtc->llri) != 0) + { + size = SUBTLV_SIZE (&(mtc->llri.header)); + memcpy(tlvs, &(mtc->llri), size); + tlvs += size; + } + + /* TE_SUBTLV_LCLIF_IPADDR */ + if (SUBTLV_TYPE(mtc->local_ipaddr) != 0) + { + size = SUBTLV_SIZE (&(mtc->local_ipaddr.header)); + memcpy(tlvs, &(mtc->local_ipaddr), size); + tlvs += size; + } + + /* TE_SUBTLV_RMTIF_IPADDR */ + if (SUBTLV_TYPE(mtc->rmt_ipaddr) != 0) + { + size = SUBTLV_SIZE (&(mtc->rmt_ipaddr.header)); + memcpy(tlvs, &(mtc->rmt_ipaddr), size); + tlvs += size; + } + + /* TE_SUBTLV_MAX_BW */ + if (SUBTLV_TYPE(mtc->max_bw) != 0) + { + size = SUBTLV_SIZE (&(mtc->max_bw.header)); + memcpy(tlvs, &(mtc->max_bw), size); + tlvs += size; + } + + /* TE_SUBTLV_MAX_RSV_BW */ + if (SUBTLV_TYPE(mtc->max_rsv_bw) != 0) + { + size = SUBTLV_SIZE (&(mtc->max_rsv_bw.header)); + memcpy(tlvs, &(mtc->max_rsv_bw), size); + tlvs += size; + } + + /* TE_SUBTLV_UNRSV_BW */ + if (SUBTLV_TYPE(mtc->unrsv_bw) != 0) + { + size = SUBTLV_SIZE (&(mtc->unrsv_bw.header)); + memcpy(tlvs, &(mtc->unrsv_bw), size); + tlvs += size; + } + + /* TE_SUBTLV_TE_METRIC */ + if (SUBTLV_TYPE(mtc->te_metric) != 0) + { + size = SUBTLV_SIZE (&(mtc->te_metric.header)); + memcpy(tlvs, &(mtc->te_metric), size); + tlvs += size; + } + + /* TE_SUBTLV_AV_DELAY */ + if (SUBTLV_TYPE(mtc->av_delay) != 0) + { + size = SUBTLV_SIZE (&(mtc->av_delay.header)); + memcpy(tlvs, &(mtc->av_delay), size); + tlvs += size; + } + + /* TE_SUBTLV_MM_DELAY */ + if (SUBTLV_TYPE(mtc->mm_delay) != 0) + { + size = SUBTLV_SIZE (&(mtc->mm_delay.header)); + memcpy(tlvs, &(mtc->mm_delay), size); + tlvs += size; + } + + /* TE_SUBTLV_DELAY_VAR */ + if (SUBTLV_TYPE(mtc->delay_var) != 0) + { + size = SUBTLV_SIZE (&(mtc->delay_var.header)); + memcpy(tlvs, &(mtc->delay_var), size); + tlvs += size; + } + + /* TE_SUBTLV_PKT_LOSS */ + if (SUBTLV_TYPE(mtc->pkt_loss) != 0) + { + size = SUBTLV_SIZE (&(mtc->pkt_loss.header)); + memcpy(tlvs, &(mtc->pkt_loss), size); + tlvs += size; + } + + /* TE_SUBTLV_RES_BW */ + if (SUBTLV_TYPE(mtc->res_bw) != 0) + { + size = SUBTLV_SIZE (&(mtc->res_bw.header)); + memcpy(tlvs, &(mtc->res_bw), size); + tlvs += size; + } + + /* TE_SUBTLV_AVA_BW */ + if (SUBTLV_TYPE(mtc->ava_bw) != 0) + { + size = SUBTLV_SIZE (&(mtc->ava_bw.header)); + memcpy(tlvs, &(mtc->ava_bw), size); + tlvs += size; + } + + /* TE_SUBTLV_USE_BW */ + if (SUBTLV_TYPE(mtc->use_bw) != 0) + { + size = SUBTLV_SIZE (&(mtc->use_bw.header)); + memcpy(tlvs, &(mtc->use_bw), size); + tlvs += size; + } + + /* Update SubTLVs length */ + mtc->length = subtlvs_len(mtc); + + zlog_debug("ISIS MPLS-TE: Add %d bytes length SubTLVs", mtc->length); + + return mtc->length; +} + +/* Compute total Sub-TLVs size */ +u_char +subtlvs_len (struct mpls_te_circuit *mtc) +{ + int length = 0; + + /* Sanity Check */ + if (mtc == NULL) + return 0; + + /* TE_SUBTLV_ADMIN_GRP */ + if (SUBTLV_TYPE(mtc->admin_grp) != 0) + length += SUBTLV_SIZE (&(mtc->admin_grp.header)); + + /* TE_SUBTLV_LLRI */ + if (SUBTLV_TYPE(mtc->llri) != 0) + length += SUBTLV_SIZE (&mtc->llri.header); + + /* TE_SUBTLV_LCLIF_IPADDR */ + if (SUBTLV_TYPE(mtc->local_ipaddr) != 0) + length += SUBTLV_SIZE (&mtc->local_ipaddr.header); + + /* TE_SUBTLV_RMTIF_IPADDR */ + if (SUBTLV_TYPE(mtc->rmt_ipaddr) != 0) + length += SUBTLV_SIZE (&mtc->rmt_ipaddr.header); + + /* TE_SUBTLV_MAX_BW */ + if (SUBTLV_TYPE(mtc->max_bw) != 0) + length += SUBTLV_SIZE (&mtc->max_bw.header); + + /* TE_SUBTLV_MAX_RSV_BW */ + if (SUBTLV_TYPE(mtc->max_rsv_bw) != 0) + length += SUBTLV_SIZE (&mtc->max_rsv_bw.header); + + /* TE_SUBTLV_UNRSV_BW */ + if (SUBTLV_TYPE(mtc->unrsv_bw) != 0) + length += SUBTLV_SIZE (&mtc->unrsv_bw.header); + + /* TE_SUBTLV_TE_METRIC */ + if (SUBTLV_TYPE(mtc->te_metric) != 0) + length += SUBTLV_SIZE (&mtc->te_metric.header); + + /* TE_SUBTLV_AV_DELAY */ + if (SUBTLV_TYPE(mtc->av_delay) != 0) + length += SUBTLV_SIZE (&mtc->av_delay.header); + + /* TE_SUBTLV_MM_DELAY */ + if (SUBTLV_TYPE(mtc->mm_delay) != 0) + length += SUBTLV_SIZE (&mtc->mm_delay.header); + + /* TE_SUBTLV_DELAY_VAR */ + if (SUBTLV_TYPE(mtc->delay_var) != 0) + length += SUBTLV_SIZE (&mtc->delay_var.header); + + /* TE_SUBTLV_PKT_LOSS */ + if (SUBTLV_TYPE(mtc->pkt_loss) != 0) + length += SUBTLV_SIZE (&mtc->pkt_loss.header); + + /* TE_SUBTLV_RES_BW */ + if (SUBTLV_TYPE(mtc->res_bw) != 0) + length += SUBTLV_SIZE (&mtc->res_bw.header); + + /* TE_SUBTLV_AVA_BW */ + if (SUBTLV_TYPE(mtc->ava_bw) != 0) + length += SUBTLV_SIZE (&mtc->ava_bw.header); + + /* TE_SUBTLV_USE_BW */ + if (SUBTLV_TYPE(mtc->use_bw) != 0) + length += SUBTLV_SIZE (&mtc->use_bw.header); + + /* Check that length is lower than the MAXIMUM SUBTLV size i.e. 256 */ + if (length > MAX_SUBTLV_SIZE) + { + mtc->length = 0; + return 0; + } + + mtc->length = (u_char)length; + + return mtc->length; +} + +/* Following are various functions to set MPLS TE parameters */ +static void +set_circuitparams_admin_grp (struct mpls_te_circuit *mtc, u_int32_t admingrp) +{ + SUBTLV_TYPE(mtc->admin_grp) = TE_SUBTLV_ADMIN_GRP; + SUBTLV_LEN(mtc->admin_grp) = SUBTLV_DEF_SIZE; + mtc->admin_grp.value = htonl(admingrp); + return; +} + +static void __attribute__ ((unused)) +set_circuitparams_llri (struct mpls_te_circuit *mtc, u_int32_t local, u_int32_t remote) +{ + SUBTLV_TYPE(mtc->llri) = TE_SUBTLV_LLRI; + SUBTLV_LEN(mtc->llri) = TE_SUBTLV_LLRI_SIZE; + mtc->llri.local = htonl(local); + mtc->llri.remote = htonl(remote); +} + +void +set_circuitparams_local_ipaddr (struct mpls_te_circuit *mtc, struct in_addr addr) +{ + + SUBTLV_TYPE(mtc->local_ipaddr) = TE_SUBTLV_LOCAL_IPADDR; + SUBTLV_LEN(mtc->local_ipaddr) = SUBTLV_DEF_SIZE; + mtc->local_ipaddr.value.s_addr = addr.s_addr; + return; +} + +void +set_circuitparams_rmt_ipaddr (struct mpls_te_circuit *mtc, struct in_addr addr) +{ + + SUBTLV_TYPE(mtc->rmt_ipaddr) = TE_SUBTLV_RMT_IPADDR; + SUBTLV_LEN(mtc->rmt_ipaddr) = SUBTLV_DEF_SIZE; + mtc->rmt_ipaddr.value.s_addr = addr.s_addr; + return; +} + +static void +set_circuitparams_max_bw (struct mpls_te_circuit *mtc, float fp) +{ + SUBTLV_TYPE(mtc->max_bw) = TE_SUBTLV_MAX_BW; + SUBTLV_LEN(mtc->max_bw) = SUBTLV_DEF_SIZE; + mtc->max_bw.value = htonf(fp); + return; +} + +static void +set_circuitparams_max_rsv_bw (struct mpls_te_circuit *mtc, float fp) +{ + SUBTLV_TYPE(mtc->max_rsv_bw) = TE_SUBTLV_MAX_RSV_BW; + SUBTLV_LEN(mtc->max_rsv_bw) = SUBTLV_DEF_SIZE; + mtc->max_rsv_bw.value = htonf(fp); + return; +} + +static void +set_circuitparams_unrsv_bw (struct mpls_te_circuit *mtc, int priority, float fp) +{ + /* Note that TLV-length field is the size of array. */ + SUBTLV_TYPE(mtc->unrsv_bw) = TE_SUBTLV_UNRSV_BW; + SUBTLV_LEN(mtc->unrsv_bw) = TE_SUBTLV_UNRSV_SIZE; + mtc->unrsv_bw.value[priority] = htonf(fp); + return; +} + +static void +set_circuitparams_te_metric (struct mpls_te_circuit *mtc, u_int32_t te_metric) +{ + SUBTLV_TYPE(mtc->te_metric) = TE_SUBTLV_TE_METRIC; + SUBTLV_LEN(mtc->te_metric) = TE_SUBTLV_TE_METRIC_SIZE; + mtc->te_metric.value[0] = (te_metric >> 16) & 0xFF; + mtc->te_metric.value[1] = (te_metric >> 8) & 0xFF; + mtc->te_metric.value[2] = te_metric & 0xFF; + return; +} + +static void +set_circuitparams_inter_as (struct mpls_te_circuit *mtc, struct in_addr addr, u_int32_t as) +{ + + /* Set the Remote ASBR IP address and then the associated AS number */ + SUBTLV_TYPE(mtc->rip) = TE_SUBTLV_RIP; + SUBTLV_LEN(mtc->rip) = SUBTLV_DEF_SIZE; + mtc->rip.value.s_addr = addr.s_addr; + + SUBTLV_TYPE(mtc->ras) = TE_SUBTLV_RAS; + SUBTLV_LEN(mtc->ras) = SUBTLV_DEF_SIZE; + mtc->ras.value = htonl(as); +} + +static void +unset_circuitparams_inter_as (struct mpls_te_circuit *mtc) +{ + + /* Reset the Remote ASBR IP address and then the associated AS number */ + SUBTLV_TYPE(mtc->rip) = 0; + SUBTLV_LEN(mtc->rip) = 0; + mtc->rip.value.s_addr = 0; + + SUBTLV_TYPE(mtc->ras) = 0; + SUBTLV_LEN(mtc->ras) = 0; + mtc->ras.value = 0; +} + +static void +set_circuitparams_av_delay (struct mpls_te_circuit *mtc, u_int32_t delay, u_char anormal) +{ + u_int32_t tmp; + /* Note that TLV-length field is the size of array. */ + SUBTLV_TYPE(mtc->av_delay) = TE_SUBTLV_AV_DELAY; + SUBTLV_LEN(mtc->av_delay) = SUBTLV_DEF_SIZE; + tmp = delay & TE_EXT_MASK; + if (anormal) + tmp |= TE_EXT_ANORMAL; + mtc->av_delay.value = htonl(tmp); + return; +} + +static void +set_circuitparams_mm_delay (struct mpls_te_circuit *mtc, u_int32_t low, u_int32_t high, u_char anormal) +{ + u_int32_t tmp; + /* Note that TLV-length field is the size of array. */ + SUBTLV_TYPE(mtc->mm_delay) = TE_SUBTLV_MM_DELAY; + SUBTLV_LEN(mtc->mm_delay) = TE_SUBTLV_MM_DELAY_SIZE; + tmp = low & TE_EXT_MASK; + if (anormal) + tmp |= TE_EXT_ANORMAL; + mtc->mm_delay.low = htonl(tmp); + mtc->mm_delay.high = htonl(high); + return; +} + +static void +set_circuitparams_delay_var (struct mpls_te_circuit *mtc, u_int32_t jitter) +{ + /* Note that TLV-length field is the size of array. */ + SUBTLV_TYPE(mtc->delay_var) = TE_SUBTLV_DELAY_VAR; + SUBTLV_LEN(mtc->delay_var) = SUBTLV_DEF_SIZE; + mtc->delay_var.value = htonl(jitter & TE_EXT_MASK); + return; +} + +static void +set_circuitparams_pkt_loss (struct mpls_te_circuit *mtc, u_int32_t loss, u_char anormal) +{ + u_int32_t tmp; + /* Note that TLV-length field is the size of array. */ + SUBTLV_TYPE(mtc->pkt_loss) = TE_SUBTLV_PKT_LOSS; + SUBTLV_LEN(mtc->pkt_loss) = SUBTLV_DEF_SIZE; + tmp = loss & TE_EXT_MASK; + if (anormal) + tmp |= TE_EXT_ANORMAL; + mtc->pkt_loss.value = htonl(tmp); + return; +} + +static void +set_circuitparams_res_bw (struct mpls_te_circuit *mtc, float fp) +{ + /* Note that TLV-length field is the size of array. */ + SUBTLV_TYPE(mtc->res_bw) = TE_SUBTLV_RES_BW; + SUBTLV_LEN(mtc->res_bw) = SUBTLV_DEF_SIZE; + mtc->res_bw.value = htonf(fp); + return; +} + +static void +set_circuitparams_ava_bw (struct mpls_te_circuit *mtc, float fp) +{ + /* Note that TLV-length field is the size of array. */ + SUBTLV_TYPE(mtc->ava_bw) = TE_SUBTLV_AVA_BW; + SUBTLV_LEN(mtc->ava_bw) = SUBTLV_DEF_SIZE; + mtc->ava_bw.value = htonf(fp); + return; +} + +static void +set_circuitparams_use_bw (struct mpls_te_circuit *mtc, float fp) +{ + /* Note that TLV-length field is the size of array. */ + SUBTLV_TYPE(mtc->use_bw) = TE_SUBTLV_USE_BW; + SUBTLV_LEN(mtc->use_bw) = SUBTLV_DEF_SIZE; + mtc->use_bw.value = htonf(fp); + return; +} + +/* Main initialization / update function of the MPLS TE Circuit context */ +/* Call when interface TE Link parameters are modified */ +void +isis_link_params_update (struct isis_circuit *circuit, struct interface *ifp) +{ + int i; + struct prefix_ipv4 *addr; + struct mpls_te_circuit *mtc; + + /* Sanity Check */ + if ((circuit == NULL) || (ifp == NULL)) + return; + + zlog_info ("MPLS-TE: Initialize circuit parameters for interface %s", ifp->name); + + /* Check if MPLS TE Circuit context has not been already created */ + if (circuit->mtc == NULL) + circuit->mtc = mpls_te_circuit_new(); + + mtc = circuit->mtc; + + /* Fulfil MTC TLV from ifp TE Link parameters */ + if (HAS_LINK_PARAMS(ifp)) + { + mtc->status = enable; + /* STD_TE metrics */ + if (IS_PARAM_SET(ifp->link_params, LP_ADM_GRP)) + set_circuitparams_admin_grp (mtc, ifp->link_params->admin_grp); + else + SUBTLV_TYPE(mtc->admin_grp) = 0; + + /* If not already set, register local IP addr from ip_addr list if it exists */ + if (SUBTLV_TYPE(mtc->local_ipaddr) == 0) + { + if (circuit->ip_addrs != NULL && listcount(circuit->ip_addrs) != 0) + { + addr = (struct prefix_ipv4 *)listgetdata ((struct listnode *)listhead (circuit->ip_addrs)); + set_circuitparams_local_ipaddr (mtc, addr->prefix); + } + } + + /* If not already set, try to determine Remote IP addr if circuit is P2P */ + if ((SUBTLV_TYPE(mtc->rmt_ipaddr) == 0) && (circuit->circ_type == CIRCUIT_T_P2P)) + { + struct isis_adjacency *adj = circuit->u.p2p.neighbor; + if (adj->ipv4_addrs != NULL && listcount(adj->ipv4_addrs) != 0) + { + struct in_addr *ip_addr; + ip_addr = (struct in_addr *)listgetdata ((struct listnode *)listhead (adj->ipv4_addrs)); + set_circuitparams_rmt_ipaddr (mtc, *ip_addr); + } + } + + if (IS_PARAM_SET(ifp->link_params, LP_MAX_BW)) + set_circuitparams_max_bw (mtc, ifp->link_params->max_bw); + else + SUBTLV_TYPE(mtc->max_bw) = 0; + + if (IS_PARAM_SET(ifp->link_params, LP_MAX_RSV_BW)) + set_circuitparams_max_rsv_bw (mtc, ifp->link_params->max_rsv_bw); + else + SUBTLV_TYPE(mtc->max_rsv_bw) = 0; + + if (IS_PARAM_SET(ifp->link_params, LP_UNRSV_BW)) + for (i = 0; i < MAX_CLASS_TYPE; i++) + set_circuitparams_unrsv_bw (mtc, i, ifp->link_params->unrsv_bw[i]); + else + SUBTLV_TYPE(mtc->unrsv_bw) = 0; + + if (IS_PARAM_SET(ifp->link_params, LP_TE)) + set_circuitparams_te_metric(mtc, ifp->link_params->te_metric); + else + SUBTLV_TYPE(mtc->te_metric) = 0; + + /* TE metric Extensions */ + if (IS_PARAM_SET(ifp->link_params, LP_DELAY)) + set_circuitparams_av_delay(mtc, ifp->link_params->av_delay, 0); + else + SUBTLV_TYPE(mtc->av_delay) = 0; + + if (IS_PARAM_SET(ifp->link_params, LP_MM_DELAY)) + set_circuitparams_mm_delay(mtc, ifp->link_params->min_delay, ifp->link_params->max_delay, 0); + else + SUBTLV_TYPE(mtc->mm_delay) = 0; + + if (IS_PARAM_SET(ifp->link_params, LP_DELAY_VAR)) + set_circuitparams_delay_var(mtc, ifp->link_params->delay_var); + else + SUBTLV_TYPE(mtc->delay_var) = 0; + + if (IS_PARAM_SET(ifp->link_params, LP_PKT_LOSS)) + set_circuitparams_pkt_loss(mtc, ifp->link_params->pkt_loss, 0); + else + SUBTLV_TYPE(mtc->pkt_loss) = 0; + + if (IS_PARAM_SET(ifp->link_params, LP_RES_BW)) + set_circuitparams_res_bw(mtc, ifp->link_params->res_bw); + else + SUBTLV_TYPE(mtc->res_bw) = 0; + + if (IS_PARAM_SET(ifp->link_params, LP_AVA_BW)) + set_circuitparams_ava_bw(mtc, ifp->link_params->ava_bw); + else + SUBTLV_TYPE(mtc->ava_bw) = 0; + + if (IS_PARAM_SET(ifp->link_params, LP_USE_BW)) + set_circuitparams_use_bw(mtc, ifp->link_params->use_bw); + else + SUBTLV_TYPE(mtc->use_bw) = 0; + + /* INTER_AS */ + if (IS_PARAM_SET(ifp->link_params, LP_RMT_AS)) + set_circuitparams_inter_as(mtc, ifp->link_params->rmt_ip, ifp->link_params->rmt_as); + else + /* reset inter-as TE params */ + unset_circuitparams_inter_as (mtc); + + /* Compute total length of SUB TLVs */ + mtc->length = subtlvs_len(mtc); + + } + else + mtc->status = disable; + + /* Finally Update LSP */ +#if 0 + if (IS_MPLS_TE(isisMplsTE) && circuit->area) + lsp_regenerate_schedule (circuit->area, circuit->is_type, 0); +#endif + return; +} + +void +isis_mpls_te_update (struct interface *ifp) +{ + struct isis_circuit *circuit; + + /* Sanity Check */ + if (ifp == NULL) + return; + + /* Get circuit context from interface */ + if ((circuit = circuit_scan_by_ifp(ifp)) == NULL) + return; + + /* Update TE TLVs ... */ + isis_link_params_update(circuit, ifp); + + /* ... and LSP */ + if (IS_MPLS_TE(isisMplsTE) && circuit->area) + lsp_regenerate_schedule (circuit->area, circuit->is_type, 0); + + return; +} + +/*------------------------------------------------------------------------* + * Followings are vty session control functions. + *------------------------------------------------------------------------*/ + +static u_char +show_vty_subtlv_admin_grp (struct vty *vty, struct te_subtlv_admin_grp *tlv) +{ + + if (vty != NULL) + vty_out (vty, " Administrative Group: 0x%x%s", + (u_int32_t) ntohl (tlv->value), VTY_NEWLINE); + else + zlog_debug (" Administrative Group: 0x%x", + (u_int32_t) ntohl (tlv->value)); + + return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); +} + +static u_char +show_vty_subtlv_llri (struct vty *vty, struct te_subtlv_llri *tlv) +{ + if (vty != NULL) + { + vty_out (vty, " Link Local ID: %d%s", (u_int32_t) ntohl (tlv->local), + VTY_NEWLINE); + vty_out (vty, " Link Remote ID: %d%s", (u_int32_t) ntohl (tlv->remote), + VTY_NEWLINE); + } + else + { + zlog_debug (" Link Local ID: %d", (u_int32_t) ntohl (tlv->local)); + zlog_debug (" Link Remote ID: %d", (u_int32_t) ntohl (tlv->remote)); + } + + return (SUBTLV_HDR_SIZE + TE_SUBTLV_LLRI_SIZE); +} + +static u_char +show_vty_subtlv_local_ipaddr (struct vty *vty, struct te_subtlv_local_ipaddr *tlv) +{ + if (vty != NULL) + vty_out (vty, " Local Interface IP Address(es): %s%s", inet_ntoa (tlv->value), VTY_NEWLINE); + else + zlog_debug (" Local Interface IP Address(es): %s", inet_ntoa (tlv->value)); + + return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); +} + +static u_char +show_vty_subtlv_rmt_ipaddr (struct vty *vty, struct te_subtlv_rmt_ipaddr *tlv) +{ + if (vty != NULL) + vty_out (vty, " Remote Interface IP Address(es): %s%s", inet_ntoa (tlv->value), VTY_NEWLINE); + else + zlog_debug (" Remote Interface IP Address(es): %s", inet_ntoa (tlv->value)); + + return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); +} + +static u_char +show_vty_subtlv_max_bw (struct vty *vty, struct te_subtlv_max_bw *tlv) +{ + float fval; + + fval = ntohf (tlv->value); + + if (vty != NULL) + vty_out (vty, " Maximum Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE); + else + zlog_debug (" Maximum Bandwidth: %g (Bytes/sec)", fval); + + return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); +} + +static u_char +show_vty_subtlv_max_rsv_bw (struct vty *vty, struct te_subtlv_max_rsv_bw *tlv) +{ + float fval; + + fval = ntohf (tlv->value); + + if (vty != NULL) + vty_out (vty, " Maximum Reservable Bandwidth: %g (Bytes/sec)%s", fval, + VTY_NEWLINE); + else + zlog_debug (" Maximum Reservable Bandwidth: %g (Bytes/sec)", fval); + + return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); +} + +static u_char +show_vty_subtlv_unrsv_bw (struct vty *vty, struct te_subtlv_unrsv_bw *tlv) +{ + float fval1, fval2; + int i; + + if (vty != NULL) + vty_out (vty, " Unreserved Bandwidth:%s",VTY_NEWLINE); + else + zlog_debug (" Unreserved Bandwidth:"); + + for (i = 0; i < MAX_CLASS_TYPE; i+=2) + { + fval1 = ntohf (tlv->value[i]); + fval2 = ntohf (tlv->value[i+1]); + if (vty != NULL) + vty_out (vty, " [%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)%s", i, fval1, i+1, fval2, VTY_NEWLINE); + else + zlog_debug (" [%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)", i, fval1, i+1, fval2); + } + + return (SUBTLV_HDR_SIZE + TE_SUBTLV_UNRSV_SIZE); +} + +static u_char +show_vty_subtlv_te_metric (struct vty *vty, struct te_subtlv_te_metric *tlv) +{ + u_int32_t te_metric; + + te_metric = tlv->value[2] | tlv->value[1] << 8 | tlv->value[0] << 16; + if (vty != NULL) + vty_out (vty, " Traffic Engineering Metric: %u%s", te_metric, VTY_NEWLINE); + else + zlog_debug (" Traffic Engineering Metric: %u", te_metric); + + return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); +} + +static u_char +show_vty_subtlv_ras (struct vty *vty, struct te_subtlv_ras *tlv) +{ + if (vty != NULL) + vty_out (vty, " Inter-AS TE Remote AS number: %u%s", ntohl (tlv->value), VTY_NEWLINE); + else + zlog_debug (" Inter-AS TE Remote AS number: %u", ntohl (tlv->value)); + + return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); +} + +static u_char +show_vty_subtlv_rip (struct vty *vty, struct te_subtlv_rip *tlv) +{ + if (vty != NULL) + vty_out (vty, " Inter-AS TE Remote ASBR IP address: %s%s", inet_ntoa (tlv->value), VTY_NEWLINE); + else + zlog_debug (" Inter-AS TE Remote ASBR IP address: %s", inet_ntoa (tlv->value)); + + return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); +} + +static u_char +show_vty_subtlv_av_delay (struct vty *vty, struct te_subtlv_av_delay *tlv) +{ + u_int32_t delay; + u_int32_t A; + + delay = (u_int32_t) ntohl (tlv->value) & TE_EXT_MASK; + A = (u_int32_t) ntohl (tlv->value) & TE_EXT_ANORMAL; + + if (vty != NULL) + vty_out (vty, " %s Average Link Delay: %d (micro-sec)%s", A ? "Anomalous" : "Normal", delay, VTY_NEWLINE); + else + zlog_debug (" %s Average Link Delay: %d (micro-sec)", A ? "Anomalous" : "Normal", delay); + + return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); +} + +static u_char +show_vty_subtlv_mm_delay (struct vty *vty, struct te_subtlv_mm_delay *tlv) +{ + u_int32_t low, high; + u_int32_t A; + + low = (u_int32_t) ntohl (tlv->low) & TE_EXT_MASK; + A = (u_int32_t) ntohl (tlv->low) & TE_EXT_ANORMAL; + high = (u_int32_t) ntohl (tlv->high) & TE_EXT_MASK; + + if (vty != NULL) + vty_out (vty, " %s Min/Max Link Delay: %d / %d (micro-sec)%s", A ? "Anomalous" : "Normal", low, high, VTY_NEWLINE); + else + zlog_debug (" %s Min/Max Link Delay: %d / %d (micro-sec)", A ? "Anomalous" : "Normal", low, high); + + return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); +} + +static u_char +show_vty_subtlv_delay_var (struct vty *vty, struct te_subtlv_delay_var *tlv) +{ + u_int32_t jitter; + + jitter = (u_int32_t) ntohl (tlv->value) & TE_EXT_MASK; + + if (vty != NULL) + vty_out (vty, " Delay Variation: %d (micro-sec)%s", jitter, VTY_NEWLINE); + else + zlog_debug (" Delay Variation: %d (micro-sec)", jitter); + + return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); +} + +static u_char +show_vty_subtlv_pkt_loss (struct vty *vty, struct te_subtlv_pkt_loss *tlv) +{ + u_int32_t loss; + u_int32_t A; + float fval; + + loss = (u_int32_t) ntohl (tlv->value) & TE_EXT_MASK; + fval = (float) (loss * LOSS_PRECISION); + A = (u_int32_t) ntohl (tlv->value) & TE_EXT_ANORMAL; + + if (vty != NULL) + vty_out (vty, " %s Link Packet Loss: %g (%%)%s", A ? "Anomalous" : "Normal", fval, VTY_NEWLINE); + else + zlog_debug (" %s Link Packet Loss: %g (%%)", A ? "Anomalous" : "Normal", fval); + + return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); +} + +static u_char +show_vty_subtlv_res_bw (struct vty *vty, struct te_subtlv_res_bw *tlv) +{ + float fval; + + fval = ntohf(tlv->value); + + if (vty != NULL) + vty_out (vty, " Unidirectional Residual Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE); + else + zlog_debug (" Unidirectional Residual Bandwidth: %g (Bytes/sec)", fval); + + return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); +} + +static u_char +show_vty_subtlv_ava_bw (struct vty *vty, struct te_subtlv_ava_bw *tlv) +{ + float fval; + + fval = ntohf (tlv->value); + + if (vty != NULL) + vty_out (vty, " Unidirectional Available Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE); + else + zlog_debug (" Unidirectional Available Bandwidth: %g (Bytes/sec)", fval); + + return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); +} + +static u_char +show_vty_subtlv_use_bw (struct vty *vty, struct te_subtlv_use_bw *tlv) +{ + float fval; + + fval = ntohf (tlv->value); + + if (vty != NULL) + vty_out (vty, " Unidirectional Utilized Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE); + else + zlog_debug (" Unidirectional Utilized Bandwidth: %g (Bytes/sec)", fval); + + return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); +} + +static u_char +show_vty_unknown_tlv (struct vty *vty, struct subtlv_header *tlvh) +{ + int i, rtn = 1; + u_char *v = (u_char *)tlvh; + + if (vty != NULL) + { + if (tlvh->length != 0) + { + vty_out (vty, " Unknown TLV: [type(%#.2x), length(%#.2x)]%s", + tlvh->type, tlvh->length, VTY_NEWLINE); + vty_out(vty, " Dump: [00]"); + rtn = 1; /* initialize end of line counter */ + for (i = 0; i < tlvh->length; i++) + { + vty_out (vty, " %#.2x", v[i]); + if (rtn == 8) + { + vty_out (vty, "%s [%.2x]", VTY_NEWLINE, i + 1); + rtn = 1; + } + else + rtn++; + } + vty_out (vty, "%s", VTY_NEWLINE); + } + else + vty_out (vty, " Unknown TLV: [type(%#.2x), length(%#.2x)]%s", + tlvh->type, tlvh->length, VTY_NEWLINE); + } + else + { + zlog_debug (" Unknown TLV: [type(%#.2x), length(%#.2x)]", + tlvh->type, tlvh->length); + } + + return SUBTLV_SIZE(tlvh); +} + +/* Main Show function */ +void +mpls_te_print_detail(struct vty *vty, struct te_is_neigh *te) +{ + struct subtlv_header *tlvh, *next; + u_int16_t sum = 0; + + zlog_debug ("ISIS MPLS-TE: Show database TE detail"); + + tlvh = (struct subtlv_header *)te->sub_tlvs; + + for (; sum < te->sub_tlvs_length; tlvh = (next ? next : SUBTLV_HDR_NEXT (tlvh))) + { + next = NULL; + + switch (tlvh->type) + { + case TE_SUBTLV_ADMIN_GRP: + sum += show_vty_subtlv_admin_grp (vty, (struct te_subtlv_admin_grp *)tlvh); + break; + case TE_SUBTLV_LLRI: + sum += show_vty_subtlv_llri (vty, (struct te_subtlv_llri *)tlvh); + break; + case TE_SUBTLV_LOCAL_IPADDR: + sum += show_vty_subtlv_local_ipaddr (vty, (struct te_subtlv_local_ipaddr *)tlvh); + break; + case TE_SUBTLV_RMT_IPADDR: + sum += show_vty_subtlv_rmt_ipaddr (vty, (struct te_subtlv_rmt_ipaddr *)tlvh); + break; + case TE_SUBTLV_MAX_BW: + sum += show_vty_subtlv_max_bw (vty, (struct te_subtlv_max_bw *)tlvh); + break; + case TE_SUBTLV_MAX_RSV_BW: + sum += show_vty_subtlv_max_rsv_bw (vty, (struct te_subtlv_max_rsv_bw *)tlvh); + break; + case TE_SUBTLV_UNRSV_BW: + sum += show_vty_subtlv_unrsv_bw (vty, (struct te_subtlv_unrsv_bw *)tlvh); + break; + case TE_SUBTLV_TE_METRIC: + sum += show_vty_subtlv_te_metric (vty, (struct te_subtlv_te_metric *)tlvh); + break; + case TE_SUBTLV_RAS: + sum += show_vty_subtlv_ras (vty, (struct te_subtlv_ras *)tlvh); + break; + case TE_SUBTLV_RIP: + sum += show_vty_subtlv_rip (vty, (struct te_subtlv_rip *)tlvh); + break; + case TE_SUBTLV_AV_DELAY: + sum += show_vty_subtlv_av_delay (vty, (struct te_subtlv_av_delay *)tlvh); + break; + case TE_SUBTLV_MM_DELAY: + sum += show_vty_subtlv_mm_delay (vty, (struct te_subtlv_mm_delay *)tlvh); + break; + case TE_SUBTLV_DELAY_VAR: + sum += show_vty_subtlv_delay_var (vty, (struct te_subtlv_delay_var *)tlvh); + break; + case TE_SUBTLV_PKT_LOSS: + sum += show_vty_subtlv_pkt_loss (vty, (struct te_subtlv_pkt_loss *)tlvh); + break; + case TE_SUBTLV_RES_BW: + sum += show_vty_subtlv_res_bw (vty, (struct te_subtlv_res_bw *)tlvh); + break; + case TE_SUBTLV_AVA_BW: + sum += show_vty_subtlv_ava_bw (vty, (struct te_subtlv_ava_bw *)tlvh); + break; + case TE_SUBTLV_USE_BW: + sum += show_vty_subtlv_use_bw (vty, (struct te_subtlv_use_bw *)tlvh); + break; + default: + sum += show_vty_unknown_tlv (vty, tlvh); + break; + } + } + return; +} + +/* Specific MPLS TE router parameters write function */ +void +isis_mpls_te_config_write_router (struct vty *vty) +{ + + zlog_debug ("ISIS MPLS-TE: Write ISIS router configuration"); + + if (IS_MPLS_TE(isisMplsTE)) + { + vty_out (vty, " mpls-te on%s", VTY_NEWLINE); + vty_out (vty, " mpls-te router-address %s%s", + inet_ntoa (isisMplsTE.router_id), VTY_NEWLINE); + } + + return; +} + + +/*------------------------------------------------------------------------* + * Followings are vty command functions. + *------------------------------------------------------------------------*/ + +DEFUN (isis_mpls_te_on, + isis_mpls_te_on_cmd, + "mpls-te on", + MPLS_TE_STR + "Enable MPLS-TE functionality\n") +{ + struct listnode *node; + struct isis_circuit *circuit; + + if (IS_MPLS_TE(isisMplsTE)) + return CMD_SUCCESS; + + if (IS_DEBUG_ISIS(DEBUG_TE)) + zlog_debug ("ISIS MPLS-TE: OFF -> ON"); + + isisMplsTE.status = enable; + + /* + * Following code is intended to handle two cases; + * + * 1) MPLS-TE was disabled at startup time, but now become enabled. + * In this case, we must enable MPLS-TE Circuit regarding interface MPLS_TE flag + * 2) MPLS-TE was once enabled then disabled, and now enabled again. + */ + for (ALL_LIST_ELEMENTS_RO (isisMplsTE.cir_list, node, circuit)) + { + if (circuit->mtc == NULL || IS_FLOOD_AS (circuit->mtc->type)) + continue; + + if ((circuit->mtc->status == disable) + && HAS_LINK_PARAMS(circuit->interface)) + circuit->mtc->status = enable; + else + continue; + + /* Reoriginate STD_TE & GMPLS circuits */ + if (circuit->area) + lsp_regenerate_schedule (circuit->area, circuit->is_type, 0); + } + + return CMD_SUCCESS; +} + +DEFUN (no_isis_mpls_te_on, + no_isis_mpls_te_on_cmd, + "no mpls-te", + NO_STR + "Disable the MPLS-TE functionality\n") +{ + struct listnode *node; + struct isis_circuit *circuit; + + if (isisMplsTE.status == disable) + return CMD_SUCCESS; + + if (IS_DEBUG_ISIS(DEBUG_TE)) + zlog_debug ("ISIS MPLS-TE: ON -> OFF"); + + isisMplsTE.status = disable; + + /* Flush LSP if circuit engage */ + for (ALL_LIST_ELEMENTS_RO (isisMplsTE.cir_list, node, circuit)) + { + if (circuit->mtc == NULL || (circuit->mtc->status == disable)) + continue; + + /* disable MPLS_TE Circuit */ + circuit->mtc->status = disable; + + /* Re-originate circuit without STD_TE & GMPLS parameters */ + if (circuit->area) + lsp_regenerate_schedule (circuit->area, circuit->is_type, 0); + } + + return CMD_SUCCESS; +} + +DEFUN (isis_mpls_te_router_addr, + isis_mpls_te_router_addr_cmd, + "mpls-te router-address A.B.C.D", + MPLS_TE_STR + "Stable IP address of the advertising router\n" + "MPLS-TE router address in IPv4 address format\n") +{ + struct in_addr value; + struct listnode *node; + struct isis_area *area; + + if (! inet_aton (argv[0], &value)) + { + vty_out (vty, "Please specify Router-Addr by A.B.C.D%s", VTY_NEWLINE); + return CMD_WARNING; + } + + isisMplsTE.router_id.s_addr = value.s_addr; + + if (isisMplsTE.status == disable) + return CMD_SUCCESS; + + /* Update main Router ID in isis global structure */ + isis->router_id = value.s_addr; + /* And re-schedule LSP update */ + for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area)) + if (listcount (area->area_addrs) > 0) + lsp_regenerate_schedule (area, area->is_type, 0); + + return CMD_SUCCESS; +} + +DEFUN (isis_mpls_te_inter_as, + isis_mpls_te_inter_as_cmd, + "mpls-te inter-as (level-1|level-1-2|level-2-only)", + MPLS_TE_STR + "Configure MPLS-TE Inter-AS support\n" + "AREA native mode self originate INTER-AS LSP with L1 only flooding scope)\n" + "AREA native mode self originate INTER-AS LSP with L1 and L2 flooding scope)\n" + "AS native mode self originate INTER-AS LSP with L2 only flooding scope\n") +{ + vty_out (vty, "Not yet supported%s", VTY_NEWLINE); + return CMD_SUCCESS; +} + +DEFUN (no_isis_mpls_te_inter_as, + no_isis_mpls_te_inter_as_cmd, + "no mpls-te inter-as", + NO_STR + "Disable the MPLS-TE functionality\n" + "Disable MPLS-TE Inter-AS support\n") +{ + + vty_out (vty, "Not yet supported%s", VTY_NEWLINE); + return CMD_SUCCESS; +} + +DEFUN (show_isis_mpls_te_router, + show_isis_mpls_te_router_cmd, + "show isis mpls-te router", + SHOW_STR + ISIS_STR + MPLS_TE_STR + "Router information\n") +{ + if (IS_MPLS_TE(isisMplsTE)) + { + vty_out (vty, "--- MPLS-TE router parameters ---%s", VTY_NEWLINE); + + if (vty != NULL) + { + if (ntohs (isisMplsTE.router_id.s_addr) != 0) + vty_out (vty, " Router-Address: %s%s", inet_ntoa (isisMplsTE.router_id), VTY_NEWLINE); + else + vty_out (vty, " N/A%s", VTY_NEWLINE); + } + } + else + vty_out (vty, " MPLS-TE is disable on this router%s", VTY_NEWLINE); + + return CMD_SUCCESS; +} + +static void +show_mpls_te_sub (struct vty *vty, struct interface *ifp) +{ + struct mpls_te_circuit *mtc; + + if ((IS_MPLS_TE(isisMplsTE)) + && ((mtc = lookup_mpls_params_by_ifp (ifp)) != NULL)) + { + /* Continue only if interface is not passive or support Inter-AS TEv2 */ + if (mtc->status != enable) + { + if (IS_INTER_AS(mtc->type)) + { + vty_out (vty, "-- Inter-AS TEv2 link parameters for %s --%s", + ifp->name, VTY_NEWLINE); + } + else + { + /* MPLS-TE is not activate on this interface */ + /* or this interface is passive and Inter-AS TEv2 is not activate */ + vty_out (vty, " %s: MPLS-TE is disabled on this interface%s", + ifp->name, VTY_NEWLINE); + return; + } + } + else + { + vty_out (vty, "-- MPLS-TE link parameters for %s --%s", + ifp->name, VTY_NEWLINE); + } + + show_vty_subtlv_admin_grp (vty, &mtc->admin_grp); + + if (SUBTLV_TYPE(mtc->local_ipaddr) != 0) + show_vty_subtlv_local_ipaddr (vty, &mtc->local_ipaddr); + if (SUBTLV_TYPE(mtc->rmt_ipaddr) != 0) + show_vty_subtlv_rmt_ipaddr (vty, &mtc->rmt_ipaddr); + + show_vty_subtlv_max_bw (vty, &mtc->max_bw); + show_vty_subtlv_max_rsv_bw (vty, &mtc->max_rsv_bw); + show_vty_subtlv_unrsv_bw (vty, &mtc->unrsv_bw); + show_vty_subtlv_te_metric (vty, &mtc->te_metric); + + if (IS_INTER_AS(mtc->type)) + { + if (SUBTLV_TYPE(mtc->ras) != 0) + show_vty_subtlv_ras (vty, &mtc->ras); + if (SUBTLV_TYPE(mtc->rip) != 0) + show_vty_subtlv_rip (vty, &mtc->rip); + } + + show_vty_subtlv_av_delay (vty, &mtc->av_delay); + show_vty_subtlv_mm_delay (vty, &mtc->mm_delay); + show_vty_subtlv_delay_var (vty, &mtc->delay_var); + show_vty_subtlv_pkt_loss (vty, &mtc->pkt_loss); + show_vty_subtlv_res_bw (vty, &mtc->res_bw); + show_vty_subtlv_ava_bw (vty, &mtc->ava_bw); + show_vty_subtlv_use_bw (vty, &mtc->use_bw); + vty_out (vty, "---------------%s%s", VTY_NEWLINE, VTY_NEWLINE); + } + else + { + vty_out (vty, " %s: MPLS-TE is disabled on this interface%s", + ifp->name, VTY_NEWLINE); + } + + return; +} + +DEFUN (show_isis_mpls_te_interface, + show_isis_mpls_te_interface_cmd, + "show isis mpls-te interface [INTERFACE]", + SHOW_STR + ISIS_STR + MPLS_TE_STR + "Interface information\n" + "Interface name\n") +{ + struct interface *ifp; + struct listnode *node; + + /* Show All Interfaces. */ + if (argc == 0) + { + for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp)) + show_mpls_te_sub (vty, ifp); + } + /* Interface name is specified. */ + else + { + if ((ifp = if_lookup_by_name (argv[0])) == NULL) + vty_out (vty, "No such interface name%s", VTY_NEWLINE); + else + show_mpls_te_sub (vty, ifp); + } + + return CMD_SUCCESS; +} + +/* Initialize MPLS_TE */ +void +isis_mpls_te_init (void) +{ + + zlog_debug("ISIS MPLS-TE: Initialize"); + + /* Initialize MPLS_TE structure */ + isisMplsTE.status = disable; + isisMplsTE.level = 0; + isisMplsTE.inter_as = off; + isisMplsTE.interas_areaid.s_addr = 0; + isisMplsTE.cir_list = list_new(); + isisMplsTE.router_id.s_addr = 0; + + /* Register new VTY commands */ + install_element (VIEW_NODE, &show_isis_mpls_te_router_cmd); + install_element (VIEW_NODE, &show_isis_mpls_te_interface_cmd); + install_element (ENABLE_NODE, &show_isis_mpls_te_router_cmd); + install_element (ENABLE_NODE, &show_isis_mpls_te_interface_cmd); + + install_element (ISIS_NODE, &isis_mpls_te_on_cmd); + install_element (ISIS_NODE, &no_isis_mpls_te_on_cmd); + install_element (ISIS_NODE, &isis_mpls_te_router_addr_cmd); + install_element (ISIS_NODE, &isis_mpls_te_inter_as_cmd); + install_element (ISIS_NODE, &no_isis_mpls_te_inter_as_cmd); + + return; +} diff --git a/isisd/isis_te.h b/isisd/isis_te.h new file mode 100644 index 0000000000..4cec1735ae --- /dev/null +++ b/isisd/isis_te.h @@ -0,0 +1,331 @@ +/* + * IS-IS Rout(e)ing protocol - isis_te.c + * + * This is an implementation of RFC5305, RFC 5307 and draft-ietf-isis-te-metric-extensions-11 + * + * Copyright (C) 2014 Orange Labs + * http://www.orange.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_ISIS_MPLS_TE_H +#define _ZEBRA_ISIS_MPLS_TE_H + +/* + * Traffic Engineering information are transport through LSP: + * - Extended IS Reachability TLV = 22 + * - Traffic Engineering Router ID TLV = 134 + * - Extended IP Reachability TLV = 135 + * - Inter-AS Reachability Information TLV = 141 + * + * and support following sub-TLV: + * + * Name Value Status + * _________________________________________________ + * Administartive group (color) 3 RFC5305 + * Link Local/Remote Identifiers 4 RFC5307 + * IPv4 interface address 6 RFC5305 + * IPv4 neighbor address 8 RFC5305 + * Maximum link bandwidth 9 RFC5305 + * Reservable link bandwidth 10 RFC5305 + * Unreserved bandwidth 11 RFC5305 + * TE Default metric 18 RFC5305 + * Link Protection Type 20 RFC5307 + * Interface Switching Capability 21 RFC5307 + * Remote AS number 24 RFC5316 + * IPv4 Remote ASBR identifier 25 RFC5316 + * + */ + +/* NOTE: RFC5316 is not yet supported in this version */ + +/* Following define the type of TE link regarding the various RFC */ +#define STD_TE 0x01 +#define GMPLS 0x02 +#define INTER_AS 0x04 +#define FLOOD_L1 0x10 +#define FLOOD_L2 0x20 +#define FLOOD_AS 0x40 +#define EMULATED 0x80 + +#define IS_STD_TE(x) (x & STD_TE) +#define IS_INTER_AS(x) (x & INTER_AS) +#define IS_EMULATED(x) (x & EMULATED) +#define IS_FLOOD_L1(x) (x & FLOOD_L1) +#define IS_FLOOD_L2(x) (x & FLOOD_L2) +#define IS_FLOOD_AS(x) (x & FLOOD_AS) +#define IS_INTER_AS_EMU(x) (x & INTER_AS & EMULATED) +#define IS_INTER_AS_AS(x) (x & INTER_AS & FLOOD_AS) + +/* + * Following section defines subTLV (tag, length, value) structures, + * used for Traffic Engineering. + */ +struct subtlv_header +{ + u_char type; /* sub_TLV_XXX type (see above) */ + u_char length; /* Value portion only, in byte */ +}; + +#define SUBTLV_HDR_SIZE 2 /* (sizeof (struct sub_tlv_header)) */ + +#define SUBTLV_SIZE(stlvh) (SUBTLV_HDR_SIZE + (stlvh)->length) + +#define SUBTLV_HDR_TOP(lsph) (struct subtlv_header *)((char *)(lsph) + ISIS_LSP_HEADER_SIZE) + +#define SUBTLV_HDR_NEXT(stlvh) (struct subtlv_header *)((char *)(stlvh) + SUBTLV_SIZE(stlvh)) + +#define SUBTLV_TYPE(stlvh) stlvh.header.type +#define SUBTLV_LEN(stlvh) stlvh.header.length +#define SUBTLV_VAL(stlvh) stlvh.value +#define SUBTLV_DATA(stlvh) stlvh + SUBTLV_HDR_SIZE + +#define SUBTLV_DEF_SIZE 4 + +/* Link Sub-TLV: Resource Class/Color - RFC 5305 */ +#define TE_SUBTLV_ADMIN_GRP 3 +struct te_subtlv_admin_grp +{ + struct subtlv_header header; /* Value length is 4 octets. */ + u_int32_t value; /* Admin. group membership. */ +} __attribute__((__packed__)); + +/* Link Local/Remote Identifiers - RFC 5307 */ +#define TE_SUBTLV_LLRI 4 +#define TE_SUBTLV_LLRI_SIZE 8 +struct te_subtlv_llri +{ + struct subtlv_header header; /* Value length is 8 octets. */ + u_int32_t local; /* Link Local Identifier */ + u_int32_t remote; /* Link Remote Identifier */ +} __attribute__((__packed__)); + +/* Link Sub-TLV: Local Interface IP Address - RFC 5305 */ +#define TE_SUBTLV_LOCAL_IPADDR 6 +struct te_subtlv_local_ipaddr +{ + struct subtlv_header header; /* Value length is 4 x N octets. */ + struct in_addr value; /* Local IP address(es). */ +} __attribute__((__packed__)); + +/* Link Sub-TLV: Neighbor Interface IP Address - RFC 5305 */ +#define TE_SUBTLV_RMT_IPADDR 8 +struct te_subtlv_rmt_ipaddr +{ + struct subtlv_header header; /* Value length is 4 x N octets. */ + struct in_addr value; /* Neighbor's IP address(es). */ +} __attribute__((__packed__)); + +/* Link Sub-TLV: Maximum Bandwidth - RFC 5305 */ +#define TE_SUBTLV_MAX_BW 9 +struct te_subtlv_max_bw +{ + struct subtlv_header header; /* Value length is 4 octets. */ + float value; /* bytes/sec */ +} __attribute__((__packed__)); + +/* Link Sub-TLV: Maximum Reservable Bandwidth - RFC 5305 */ +#define TE_SUBTLV_MAX_RSV_BW 10 +struct te_subtlv_max_rsv_bw +{ + struct subtlv_header header; /* Value length is 4 octets. */ + float value; /* bytes/sec */ +} __attribute__((__packed__)); + +/* Link Sub-TLV: Unreserved Bandwidth - RFC 5305 */ +#define TE_SUBTLV_UNRSV_BW 11 +#define TE_SUBTLV_UNRSV_SIZE 32 +struct te_subtlv_unrsv_bw +{ + struct subtlv_header header; /* Value length is 32 octets. */ + float value[8]; /* One for each priority level. */ +} __attribute__((__packed__)); + +/* Link Sub-TLV: Traffic Engineering Metric - RFC 5305 */ +#define TE_SUBTLV_TE_METRIC 18 +#define TE_SUBTLV_TE_METRIC_SIZE 3 +struct te_subtlv_te_metric +{ + struct subtlv_header header; /* Value length is 4 octets. */ + u_char value[3]; /* Link metric for TE purpose. */ +} __attribute__((__packed__)); + +/* Remote AS Number sub-TLV - RFC5316 */ +#define TE_SUBTLV_RAS 24 +struct te_subtlv_ras +{ + struct subtlv_header header; /* Value length is 4 octets. */ + u_int32_t value; /* Remote AS number */ +} __attribute__((__packed__)); + +/* IPv4 Remote ASBR ID Sub-TLV - RFC5316 */ +#define TE_SUBTLV_RIP 25 +struct te_subtlv_rip +{ + struct subtlv_header header; /* Value length is 4 octets. */ + struct in_addr value; /* Remote ASBR IP address */ +} __attribute__((__packed__)); + + +/* draft-ietf-isis-te-metric-extensions-11.txt */ +/* Link Sub-TLV: Average Link Delay */ +#define TE_SUBTLV_AV_DELAY 33 +struct te_subtlv_av_delay +{ + struct subtlv_header header; /* Value length is 4 bytes. */ + u_int32_t value; /* Average delay in micro-seconds only 24 bits => 0 ... 16777215 + with Anomalous Bit (A) as Upper most bit */ +} __attribute__((__packed__)); + +/* Link Sub-TLV: Low/High Link Delay */ +#define TE_SUBTLV_MM_DELAY 34 +#define TE_SUBTLV_MM_DELAY_SIZE 8 +struct te_subtlv_mm_delay +{ + struct subtlv_header header; /* Value length is 8 bytes. */ + u_int32_t low; /* low delay in micro-seconds only 24 bits => 0 ... 16777215 + with Anomalous Bit (A) as Upper most bit */ + u_int32_t high; /* high delay in micro-seconds only 24 bits => 0 ... 16777215 */ +} __attribute__((__packed__)); + +/* Link Sub-TLV: Link Delay Variation i.e. Jitter */ +#define TE_SUBTLV_DELAY_VAR 35 +struct te_subtlv_delay_var +{ + struct subtlv_header header; /* Value length is 4 bytes. */ + u_int32_t value; /* interval in micro-seconds only 24 bits => 0 ... 16777215 */ +} __attribute__((__packed__)); + +/* Link Sub-TLV: Routine Unidirectional Link Packet Loss */ +#define TE_SUBTLV_PKT_LOSS 36 +struct te_subtlv_pkt_loss +{ + struct subtlv_header header; /* Value length is 4 bytes. */ + u_int32_t value; /* in percentage of total traffic only 24 bits (2^24 - 2) + with Anomalous Bit (A) as Upper most bit */ +} __attribute__((__packed__)); + +/* Link Sub-TLV: Unidirectional Residual Bandwidth */ /* Optional */ +#define TE_SUBTLV_RES_BW 37 +struct te_subtlv_res_bw +{ + struct subtlv_header header; /* Value length is 4 bytes. */ + float value; /* bandwidth in IEEE floating point format with units in bytes per second */ +} __attribute__((__packed__)); + +/* Link Sub-TLV: Unidirectional Available Bandwidth */ /* Optional */ +#define TE_SUBTLV_AVA_BW 38 +struct te_subtlv_ava_bw +{ + struct subtlv_header header; /* Value length is 4 octets. */ + float value; /* bandwidth in IEEE floating point format with units in bytes per second */ +} __attribute__((__packed__)); + +/* Link Sub-TLV: Unidirectional Utilized Bandwidth */ /* Optional */ +#define TE_SUBTLV_USE_BW 39 +struct te_subtlv_use_bw +{ + struct subtlv_header header; /* Value length is 4 octets. */ + float value; /* bandwidth in IEEE floating point format with units in bytes per second */ +} __attribute__((__packed__)); + +#define TE_SUBTLV_MAX 40 /* Last SUBTLV + 1 */ + +/* Following declaration concerns the MPLS-TE and LINk-TE management */ +typedef enum _status_t { disable, enable, learn } status_t; + +/* Mode for Inter-AS LSP */ /* TODO: Check how if LSP is flooded in RFC5316 */ +typedef enum _interas_mode_t { off, region, as, emulate } interas_mode_t; + +#define IS_MPLS_TE(m) (m.status == enable) +#define IS_CIRCUIT_TE(c) (c->status == enable) + +/* Following structure are internal use only. */ +struct isis_mpls_te +{ + /* Status of MPLS-TE: enable or disable */ + status_t status; + + /* L1, L1-L2, L2-Only */ + u_int8_t level; + + /* RFC5316 */ + interas_mode_t inter_as; + struct in_addr interas_areaid; + + /* Circuit list on which TE are enable */ + struct list *cir_list; + + /* MPLS_TE router ID */ + struct in_addr router_id; +}; + +extern struct isis_mpls_te isisMplsTE; + +struct mpls_te_circuit +{ + + /* Status of MPLS-TE on this interface */ + status_t status; + + /* Type of MPLS-TE circuit: STD_TE(RFC5305), INTER_AS(RFC5316), INTER_AS_EMU(RFC5316 emulated) */ + u_int8_t type; + + /* Total size of sub_tlvs */ + u_char length; + + /* Store subTLV in network byte order. */ + /* RFC5305 */ + struct te_subtlv_admin_grp admin_grp; + /* RFC5307 */ + struct te_subtlv_llri llri; + /* RFC5305 */ + struct te_subtlv_local_ipaddr local_ipaddr; + struct te_subtlv_rmt_ipaddr rmt_ipaddr; + struct te_subtlv_max_bw max_bw; + struct te_subtlv_max_rsv_bw max_rsv_bw; + struct te_subtlv_unrsv_bw unrsv_bw; + struct te_subtlv_te_metric te_metric; + /* RFC5316 */ + struct te_subtlv_ras ras; + struct te_subtlv_rip rip; + /* draft-ietf-isis-te-metric-extension */ + struct te_subtlv_av_delay av_delay; + struct te_subtlv_mm_delay mm_delay; + struct te_subtlv_delay_var delay_var; + struct te_subtlv_pkt_loss pkt_loss; + struct te_subtlv_res_bw res_bw; + struct te_subtlv_ava_bw ava_bw; + struct te_subtlv_use_bw use_bw; +}; + +/* Prototypes. */ +void isis_mpls_te_init (void); +struct mpls_te_circuit *mpls_te_circuit_new(void); +void mpls_te_print_detail(struct vty *, struct te_is_neigh *); +void set_circuitparams_local_ipaddr (struct mpls_te_circuit *, struct in_addr); +void set_circuitparams_rmt_ipaddr (struct mpls_te_circuit *, struct in_addr); +u_char subtlvs_len (struct mpls_te_circuit *); +u_char add_te_subtlvs(u_char *, struct mpls_te_circuit *); +u_char build_te_subtlvs(u_char *, struct isis_circuit *); +void isis_link_params_update(struct isis_circuit *, struct interface *); +void isis_mpls_te_update(struct interface *); +void isis_mpls_te_config_write_router (struct vty *); + +#endif /* _ZEBRA_ISIS_MPLS_TE_H */ diff --git a/isisd/isis_tlv.c b/isisd/isis_tlv.c index b4017b5f45..1d29d78287 100644 --- a/isisd/isis_tlv.c +++ b/isisd/isis_tlv.c @@ -42,6 +42,7 @@ #include "isisd/isis_misc.h" #include "isisd/isis_pdu.h" #include "isisd/isis_lsp.h" +#include "isisd/isis_te.h" void free_tlv (void *val) @@ -229,9 +230,23 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected, while (length > value_len) { te_is_nei = (struct te_is_neigh *) pnt; - value_len += 11; - pnt += 11; - /* FIXME - subtlvs are handled here, for now we skip */ + value_len += IS_NEIGHBOURS_LEN; + pnt += IS_NEIGHBOURS_LEN; + /* FIXME - subtlvs are handled here, for now we skip */ + /* FIXME: All TE SubTLVs are not necessary present in LSP PDU. */ + /* So, it must be copied in a new te_is_neigh structure */ + /* rather than just initialize pointer to the original LSP PDU */ + /* to avoid consider the rest of lspdu as subTLVs or buffer overflow */ + if (IS_MPLS_TE(isisMplsTE)) + { + struct te_is_neigh *new = XCALLOC(MTYPE_ISIS_TLV, sizeof(struct te_is_neigh)); + memcpy(new->neigh_id, te_is_nei->neigh_id, ISIS_SYS_ID_LEN + 1); + memcpy(new->te_metric, te_is_nei->te_metric, 3); + new->sub_tlvs_length = te_is_nei->sub_tlvs_length; + memcpy(new->sub_tlvs, pnt, te_is_nei->sub_tlvs_length); + te_is_nei = new; + } + /* Skip SUB TLVs payload */ value_len += te_is_nei->sub_tlvs_length; pnt += te_is_nei->sub_tlvs_length; @@ -845,8 +860,8 @@ tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream) for (ALL_LIST_ELEMENTS_RO (te_is_neighs, node, te_is_neigh)) { - /* FIXME: This will be wrong if we are going to add TE sub TLVs. */ - if (pos - value + IS_NEIGHBOURS_LEN > 255) + /* FIXME: Check if Total SubTLVs size doesn't exceed 255 */ + if (pos - value + IS_NEIGHBOURS_LEN + te_is_neigh->sub_tlvs_length > 255) { retval = add_tlv (TE_IS_NEIGHBOURS, pos - value, value, stream); if (retval != ISIS_OK) @@ -858,9 +873,15 @@ tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream) pos += ISIS_SYS_ID_LEN + 1; memcpy (pos, te_is_neigh->te_metric, 3); pos += 3; - /* Sub TLVs length. */ - *pos = 0; + /* Set the total size of Sub TLVs */ + *pos = te_is_neigh->sub_tlvs_length; pos++; + /* Copy Sub TLVs if any */ + if (te_is_neigh->sub_tlvs_length > 0) + { + memcpy (pos, te_is_neigh->sub_tlvs, te_is_neigh->sub_tlvs_length); + pos += te_is_neigh->sub_tlvs_length; + } } return add_tlv (TE_IS_NEIGHBOURS, pos - value, value, stream); diff --git a/isisd/isis_tlv.h b/isisd/isis_tlv.h index 619003a0e3..5a39d564dc 100644 --- a/isisd/isis_tlv.h +++ b/isisd/isis_tlv.h @@ -39,7 +39,7 @@ * LSP Entries 9 n n y ISO10589 * Authentication 10 y y y ISO10589, RFC3567 * Checksum 12 y n y RFC3358 - * TE IS Reachability 22 n y n RFC5305 + * Extended IS Reachability 22 n y n RFC5305 * IS Alias 24 n y n RFC3786 * IP Int. Reachability 128 n y n RFC1195 * Protocols Supported 129 y y n RFC1195 @@ -50,6 +50,7 @@ * Extended IP Reachability 135 n y n RFC5305 * Dynamic Hostname 137 n y n RFC2763 * Shared Risk Link Group 138 n y y RFC5307 + * Inter-AS Reachability 141 n y n RFC5316 * Restart TLV 211 y n n RFC3847 * MT IS Reachability 222 n y n RFC5120 * MT Supported 229 y y n RFC5120 @@ -59,10 +60,10 @@ * MT IPv6 IP Reachability 237 n y n RFC5120 * P2P Adjacency State 240 y n n RFC3373 * IIH Sequence Number 241 y n n draft-shen-isis-iih-sequence - * Router Capability 242 - - - draft-ietf-isis-caps + * Router Capability 242 n y n RFC4971 * * - * IS Reachability sub-TLVs we (should) support. + * IS Reachability sub-TLVs we support (See isis_te.[c,h]) * ____________________________________________________________________________ * Name Value Status * ____________________________________________________________________________ @@ -76,6 +77,8 @@ * TE Default metric 18 RFC5305 * Link Protection Type 20 RFC5307 * Interface Switching Capability 21 RFC5307 + * Remote AS number 24 RFC5316 + * IPv4 Remote ASBR identifier 25 RFC5316 * * * IP Reachability sub-TLVs we (should) support. @@ -109,6 +112,7 @@ #define IPV6_ADDR 232 #define IPV6_REACHABILITY 236 #define WAY3_HELLO 240 +#define ROUTER_INFORMATION 242 #define AUTH_INFO_HDRLEN 3 @@ -121,6 +125,8 @@ #define IPV6_REACH_LEN 22 #define TE_IPV4_REACH_LEN 9 +#define MAX_SUBTLV_SIZE 256 + /* struct for neighbor */ struct is_neigh { @@ -128,12 +134,18 @@ struct is_neigh u_char neigh_id[ISIS_SYS_ID_LEN + 1]; }; -/* struct for te is neighbor */ +/* struct for te metric */ struct te_is_neigh { u_char neigh_id[ISIS_SYS_ID_LEN + 1]; u_char te_metric[3]; u_char sub_tlvs_length; + /* Theorical Maximum SubTLVs is 256 because the sub_tlvs_length is 8 bits */ + /* Practically, 118 bytes are necessary to store all supported TE parameters */ + /* FIXME: A pointer will use less memory, but need to be free */ + /* which is hard to fix, especially within free_tlvs() function */ + /* and malloc() / free() as a CPU cost compared to the memory usage */ + u_char sub_tlvs[MAX_SUBTLV_SIZE]; /* SUB TLVs storage */ }; /* Decode and encode three-octet metric into host byte order integer */ diff --git a/isisd/isis_vty.c b/isisd/isis_vty.c new file mode 100644 index 0000000000..4148eb55b9 --- /dev/null +++ b/isisd/isis_vty.c @@ -0,0 +1,2428 @@ +/* + * IS-IS Rout(e)ing protocol - isis_circuit.h + * + * Copyright (C) 2001,2002 Sampo Saaristo + * Tampere University of Technology + * Institute of Communications Engineering + * Copyright (C) 2016 David Lamparter, for NetDEF, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public Licenseas published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program 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 this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include + +#include "isis_circuit.h" +#include "isis_csm.h" +#include "isis_misc.h" +#include "isisd.h" + +static struct isis_circuit * +isis_circuit_lookup (struct vty *vty) +{ + struct interface *ifp; + struct isis_circuit *circuit; + + ifp = (struct interface *) vty->index; + if (!ifp) + { + vty_out (vty, "Invalid interface %s", VTY_NEWLINE); + return NULL; + } + + circuit = circuit_scan_by_ifp (ifp); + if (!circuit) + { + vty_out (vty, "ISIS is not enabled on circuit %s%s", + ifp->name, VTY_NEWLINE); + return NULL; + } + + return circuit; +} + +DEFUN (ip_router_isis, + ip_router_isis_cmd, + "(ip|ipv6) router isis WORD", + "Interface Internet Protocol config commands\n" + "IP router interface commands\n" + "IS-IS Routing for IP\n" + "Routing process tag\n") +{ + struct interface *ifp; + struct isis_circuit *circuit; + struct isis_area *area; + const char *af = argv[0]; + const char *area_tag = argv[1]; + + ifp = (struct interface *) vty->index; + assert (ifp); + + /* Prevent more than one area per circuit */ + circuit = circuit_scan_by_ifp (ifp); + if (circuit && circuit->area) + { + if (strcmp (circuit->area->area_tag, area_tag)) + { + vty_out (vty, "ISIS circuit is already defined on %s%s", + circuit->area->area_tag, VTY_NEWLINE); + return CMD_ERR_NOTHING_TODO; + } + } + + area = isis_area_lookup (area_tag); + if (!area) + area = isis_area_create (area_tag); + + if (!circuit || !circuit->area) { + circuit = isis_circuit_create (area, ifp); + + if (circuit->state != C_STATE_CONF && circuit->state != C_STATE_UP) + { + vty_out(vty, "Couldn't bring up interface, please check log.%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + bool ip = circuit->ip_router, ipv6 = circuit->ipv6_router; + if (af[2] != '\0') + ipv6 = true; + else + ip = true; + + isis_circuit_af_set (circuit, ip, ipv6); + return CMD_SUCCESS; +} + +DEFUN (no_ip_router_isis, + no_ip_router_isis_cmd, + "no (ip|ipv6) router isis WORD", + NO_STR + "Interface Internet Protocol config commands\n" + "IP router interface commands\n" + "IS-IS Routing for IP\n" + "Routing process tag\n") +{ + struct interface *ifp; + struct isis_area *area; + struct isis_circuit *circuit; + const char *af = argv[0]; + const char *area_tag = argv[1]; + + ifp = (struct interface *) vty->index; + if (!ifp) + { + vty_out (vty, "Invalid interface %s", VTY_NEWLINE); + return CMD_ERR_NO_MATCH; + } + + area = isis_area_lookup (area_tag); + if (!area) + { + vty_out (vty, "Can't find ISIS instance %s%s", + argv[0], VTY_NEWLINE); + return CMD_ERR_NO_MATCH; + } + + circuit = circuit_lookup_by_ifp (ifp, area->circuit_list); + if (!circuit) + { + vty_out (vty, "ISIS is not enabled on circuit %s%s", + ifp->name, VTY_NEWLINE); + return CMD_ERR_NO_MATCH; + } + + bool ip = circuit->ip_router, ipv6 = circuit->ipv6_router; + if (af[2] != '\0') + ipv6 = false; + else + ip = false; + + isis_circuit_af_set (circuit, ip, ipv6); + return CMD_SUCCESS; +} + +DEFUN (isis_passive, + isis_passive_cmd, + "isis passive", + "IS-IS commands\n" + "Configure the passive mode for interface\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + isis_circuit_passive_set (circuit, 1); + return CMD_SUCCESS; +} + +DEFUN (no_isis_passive, + no_isis_passive_cmd, + "no isis passive", + NO_STR + "IS-IS commands\n" + "Configure the passive mode for interface\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + if (if_is_loopback (circuit->interface)) + { + vty_out (vty, "Can't set no passive for loopback interface%s", + VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + isis_circuit_passive_set (circuit, 0); + return CMD_SUCCESS; +} + +DEFUN (isis_circuit_type, + isis_circuit_type_cmd, + "isis circuit-type (level-1|level-1-2|level-2-only)", + "IS-IS commands\n" + "Configure circuit type for interface\n" + "Level-1 only adjacencies are formed\n" + "Level-1-2 adjacencies are formed\n" + "Level-2 only adjacencies are formed\n") +{ + int is_type; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + is_type = string2circuit_t (argv[0]); + if (!is_type) + { + vty_out (vty, "Unknown circuit-type %s", VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + if (circuit->state == C_STATE_UP && + circuit->area->is_type != IS_LEVEL_1_AND_2 && + circuit->area->is_type != is_type) + { + vty_out (vty, "Invalid circuit level for area %s.%s", + circuit->area->area_tag, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + isis_circuit_is_type_set (circuit, is_type); + + return CMD_SUCCESS; +} + +DEFUN (no_isis_circuit_type, + no_isis_circuit_type_cmd, + "no isis circuit-type (level-1|level-1-2|level-2-only)", + NO_STR + "IS-IS commands\n" + "Configure circuit type for interface\n" + "Level-1 only adjacencies are formed\n" + "Level-1-2 adjacencies are formed\n" + "Level-2 only adjacencies are formed\n") +{ + int is_type; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + /* + * Set the circuits level to its default value + */ + if (circuit->state == C_STATE_UP) + is_type = circuit->area->is_type; + else + is_type = IS_LEVEL_1_AND_2; + isis_circuit_is_type_set (circuit, is_type); + + return CMD_SUCCESS; +} + +DEFUN (isis_network, + isis_network_cmd, + "isis network point-to-point", + "IS-IS commands\n" + "Set network type\n" + "point-to-point network type\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + if (isis_circuit_circ_type_set(circuit, CIRCUIT_T_P2P)) + { + vty_out (vty, "isis network point-to-point " + "is valid only on broadcast interfaces%s", + VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + return CMD_SUCCESS; +} + +DEFUN (no_isis_network, + no_isis_network_cmd, + "no isis network point-to-point", + NO_STR + "IS-IS commands\n" + "Set network type for circuit\n" + "point-to-point network type\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + if (isis_circuit_circ_type_set(circuit, CIRCUIT_T_BROADCAST)) + { + vty_out (vty, "isis network point-to-point " + "is valid only on broadcast interfaces%s", + VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + return CMD_SUCCESS; +} + +DEFUN (isis_passwd, + isis_passwd_cmd, + "isis password (md5|clear) WORD", + "IS-IS commands\n" + "Configure the authentication password for a circuit\n" + "HMAC-MD5 authentication\n" + "Cleartext password\n" + "Circuit password\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + int rv; + if (!circuit) + return CMD_ERR_NO_MATCH; + + if (argv[0][0] == 'm') + rv = isis_circuit_passwd_hmac_md5_set(circuit, argv[1]); + else + rv = isis_circuit_passwd_cleartext_set(circuit, argv[1]); + if (rv) + { + vty_out (vty, "Too long circuit password (>254)%s", VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + return CMD_SUCCESS; +} + +DEFUN (no_isis_passwd, + no_isis_passwd_cmd, + "no isis password", + NO_STR + "IS-IS commands\n" + "Configure the authentication password for a circuit\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + isis_circuit_passwd_unset(circuit); + + return CMD_SUCCESS; +} + +ALIAS (no_isis_passwd, + no_isis_passwd_arg_cmd, + "no isis password (md5|clear) WORD", + NO_STR + "IS-IS commands\n" + "Configure the authentication password for a circuit\n" + "HMAC-MD5 authentication\n" + "Cleartext password\n" + "Circuit password\n") + +DEFUN (isis_priority, + isis_priority_cmd, + "isis priority <0-127>", + "IS-IS commands\n" + "Set priority for Designated Router election\n" + "Priority value\n") +{ + int prio; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + prio = atoi (argv[0]); + if (prio < MIN_PRIORITY || prio > MAX_PRIORITY) + { + vty_out (vty, "Invalid priority %d - should be <0-127>%s", + prio, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + circuit->priority[0] = prio; + circuit->priority[1] = prio; + + return CMD_SUCCESS; +} + +DEFUN (no_isis_priority, + no_isis_priority_cmd, + "no isis priority", + NO_STR + "IS-IS commands\n" + "Set priority for Designated Router election\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + circuit->priority[0] = DEFAULT_PRIORITY; + circuit->priority[1] = DEFAULT_PRIORITY; + + return CMD_SUCCESS; +} + +ALIAS (no_isis_priority, + no_isis_priority_arg_cmd, + "no isis priority <0-127>", + NO_STR + "IS-IS commands\n" + "Set priority for Designated Router election\n" + "Priority value\n") + +DEFUN (isis_priority_l1, + isis_priority_l1_cmd, + "isis priority <0-127> level-1", + "IS-IS commands\n" + "Set priority for Designated Router election\n" + "Priority value\n" + "Specify priority for level-1 routing\n") +{ + int prio; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + prio = atoi (argv[0]); + if (prio < MIN_PRIORITY || prio > MAX_PRIORITY) + { + vty_out (vty, "Invalid priority %d - should be <0-127>%s", + prio, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + circuit->priority[0] = prio; + + return CMD_SUCCESS; +} + +DEFUN (no_isis_priority_l1, + no_isis_priority_l1_cmd, + "no isis priority level-1", + NO_STR + "IS-IS commands\n" + "Set priority for Designated Router election\n" + "Specify priority for level-1 routing\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + circuit->priority[0] = DEFAULT_PRIORITY; + + return CMD_SUCCESS; +} + +ALIAS (no_isis_priority_l1, + no_isis_priority_l1_arg_cmd, + "no isis priority <0-127> level-1", + NO_STR + "IS-IS commands\n" + "Set priority for Designated Router election\n" + "Priority value\n" + "Specify priority for level-1 routing\n") + +DEFUN (isis_priority_l2, + isis_priority_l2_cmd, + "isis priority <0-127> level-2", + "IS-IS commands\n" + "Set priority for Designated Router election\n" + "Priority value\n" + "Specify priority for level-2 routing\n") +{ + int prio; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + prio = atoi (argv[0]); + if (prio < MIN_PRIORITY || prio > MAX_PRIORITY) + { + vty_out (vty, "Invalid priority %d - should be <0-127>%s", + prio, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + circuit->priority[1] = prio; + + return CMD_SUCCESS; +} + +DEFUN (no_isis_priority_l2, + no_isis_priority_l2_cmd, + "no isis priority level-2", + NO_STR + "IS-IS commands\n" + "Set priority for Designated Router election\n" + "Specify priority for level-2 routing\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + circuit->priority[1] = DEFAULT_PRIORITY; + + return CMD_SUCCESS; +} + +ALIAS (no_isis_priority_l2, + no_isis_priority_l2_arg_cmd, + "no isis priority <0-127> level-2", + NO_STR + "IS-IS commands\n" + "Set priority for Designated Router election\n" + "Priority value\n" + "Specify priority for level-2 routing\n") + +/* Metric command */ +DEFUN (isis_metric, + isis_metric_cmd, + "isis metric <0-16777215>", + "IS-IS commands\n" + "Set default metric for circuit\n" + "Default metric value\n") +{ + int met; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + met = atoi (argv[0]); + + /* RFC3787 section 5.1 */ + if (circuit->area && circuit->area->oldmetric == 1 && + met > MAX_NARROW_LINK_METRIC) + { + vty_out (vty, "Invalid metric %d - should be <0-63> " + "when narrow metric type enabled%s", + met, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + /* RFC4444 */ + if (circuit->area && circuit->area->newmetric == 1 && + met > MAX_WIDE_LINK_METRIC) + { + vty_out (vty, "Invalid metric %d - should be <0-16777215> " + "when wide metric type enabled%s", + met, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + isis_circuit_metric_set (circuit, IS_LEVEL_1, met); + isis_circuit_metric_set (circuit, IS_LEVEL_2, met); + return CMD_SUCCESS; +} + +DEFUN (no_isis_metric, + no_isis_metric_cmd, + "no isis metric", + NO_STR + "IS-IS commands\n" + "Set default metric for circuit\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + isis_circuit_metric_set (circuit, IS_LEVEL_1, DEFAULT_CIRCUIT_METRIC); + isis_circuit_metric_set (circuit, IS_LEVEL_2, DEFAULT_CIRCUIT_METRIC); + return CMD_SUCCESS; +} + +ALIAS (no_isis_metric, + no_isis_metric_arg_cmd, + "no isis metric <0-16777215>", + NO_STR + "IS-IS commands\n" + "Set default metric for circuit\n" + "Default metric value\n") + +DEFUN (isis_metric_l1, + isis_metric_l1_cmd, + "isis metric <0-16777215> level-1", + "IS-IS commands\n" + "Set default metric for circuit\n" + "Default metric value\n" + "Specify metric for level-1 routing\n") +{ + int met; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + met = atoi (argv[0]); + + /* RFC3787 section 5.1 */ + if (circuit->area && circuit->area->oldmetric == 1 && + met > MAX_NARROW_LINK_METRIC) + { + vty_out (vty, "Invalid metric %d - should be <0-63> " + "when narrow metric type enabled%s", + met, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + /* RFC4444 */ + if (circuit->area && circuit->area->newmetric == 1 && + met > MAX_WIDE_LINK_METRIC) + { + vty_out (vty, "Invalid metric %d - should be <0-16777215> " + "when wide metric type enabled%s", + met, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + isis_circuit_metric_set (circuit, IS_LEVEL_1, met); + return CMD_SUCCESS; +} + +DEFUN (no_isis_metric_l1, + no_isis_metric_l1_cmd, + "no isis metric level-1", + NO_STR + "IS-IS commands\n" + "Set default metric for circuit\n" + "Specify metric for level-1 routing\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + isis_circuit_metric_set (circuit, IS_LEVEL_1, DEFAULT_CIRCUIT_METRIC); + return CMD_SUCCESS; +} + +ALIAS (no_isis_metric_l1, + no_isis_metric_l1_arg_cmd, + "no isis metric <0-16777215> level-1", + NO_STR + "IS-IS commands\n" + "Set default metric for circuit\n" + "Default metric value\n" + "Specify metric for level-1 routing\n") + +DEFUN (isis_metric_l2, + isis_metric_l2_cmd, + "isis metric <0-16777215> level-2", + "IS-IS commands\n" + "Set default metric for circuit\n" + "Default metric value\n" + "Specify metric for level-2 routing\n") +{ + int met; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + met = atoi (argv[0]); + + /* RFC3787 section 5.1 */ + if (circuit->area && circuit->area->oldmetric == 1 && + met > MAX_NARROW_LINK_METRIC) + { + vty_out (vty, "Invalid metric %d - should be <0-63> " + "when narrow metric type enabled%s", + met, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + /* RFC4444 */ + if (circuit->area && circuit->area->newmetric == 1 && + met > MAX_WIDE_LINK_METRIC) + { + vty_out (vty, "Invalid metric %d - should be <0-16777215> " + "when wide metric type enabled%s", + met, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + isis_circuit_metric_set (circuit, IS_LEVEL_2, met); + return CMD_SUCCESS; +} + +DEFUN (no_isis_metric_l2, + no_isis_metric_l2_cmd, + "no isis metric level-2", + NO_STR + "IS-IS commands\n" + "Set default metric for circuit\n" + "Specify metric for level-2 routing\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + isis_circuit_metric_set (circuit, IS_LEVEL_2, DEFAULT_CIRCUIT_METRIC); + return CMD_SUCCESS; +} + +ALIAS (no_isis_metric_l2, + no_isis_metric_l2_arg_cmd, + "no isis metric <0-16777215> level-2", + NO_STR + "IS-IS commands\n" + "Set default metric for circuit\n" + "Default metric value\n" + "Specify metric for level-2 routing\n") +/* end of metrics */ + +DEFUN (isis_hello_interval, + isis_hello_interval_cmd, + "isis hello-interval <1-600>", + "IS-IS commands\n" + "Set Hello interval\n" + "Hello interval value\n" + "Holdtime 1 seconds, interval depends on multiplier\n") +{ + int interval; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + interval = atoi (argv[0]); + if (interval < MIN_HELLO_INTERVAL || interval > MAX_HELLO_INTERVAL) + { + vty_out (vty, "Invalid hello-interval %d - should be <1-600>%s", + interval, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + circuit->hello_interval[0] = (u_int16_t) interval; + circuit->hello_interval[1] = (u_int16_t) interval; + + return CMD_SUCCESS; +} + +DEFUN (no_isis_hello_interval, + no_isis_hello_interval_cmd, + "no isis hello-interval", + NO_STR + "IS-IS commands\n" + "Set Hello interval\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + circuit->hello_interval[0] = DEFAULT_HELLO_INTERVAL; + circuit->hello_interval[1] = DEFAULT_HELLO_INTERVAL; + + return CMD_SUCCESS; +} + +ALIAS (no_isis_hello_interval, + no_isis_hello_interval_arg_cmd, + "no isis hello-interval <1-600>", + NO_STR + "IS-IS commands\n" + "Set Hello interval\n" + "Hello interval value\n" + "Holdtime 1 second, interval depends on multiplier\n") + +DEFUN (isis_hello_interval_l1, + isis_hello_interval_l1_cmd, + "isis hello-interval <1-600> level-1", + "IS-IS commands\n" + "Set Hello interval\n" + "Hello interval value\n" + "Holdtime 1 second, interval depends on multiplier\n" + "Specify hello-interval for level-1 IIHs\n") +{ + long interval; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + interval = atoi (argv[0]); + if (interval < MIN_HELLO_INTERVAL || interval > MAX_HELLO_INTERVAL) + { + vty_out (vty, "Invalid hello-interval %ld - should be <1-600>%s", + interval, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + circuit->hello_interval[0] = (u_int16_t) interval; + + return CMD_SUCCESS; +} + +DEFUN (no_isis_hello_interval_l1, + no_isis_hello_interval_l1_cmd, + "no isis hello-interval level-1", + NO_STR + "IS-IS commands\n" + "Set Hello interval\n" + "Specify hello-interval for level-1 IIHs\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + circuit->hello_interval[0] = DEFAULT_HELLO_INTERVAL; + + return CMD_SUCCESS; +} + +ALIAS (no_isis_hello_interval_l1, + no_isis_hello_interval_l1_arg_cmd, + "no isis hello-interval <1-600> level-1", + NO_STR + "IS-IS commands\n" + "Set Hello interval\n" + "Hello interval value\n" + "Holdtime 1 second, interval depends on multiplier\n" + "Specify hello-interval for level-1 IIHs\n") + +DEFUN (isis_hello_interval_l2, + isis_hello_interval_l2_cmd, + "isis hello-interval <1-600> level-2", + "IS-IS commands\n" + "Set Hello interval\n" + "Hello interval value\n" + "Holdtime 1 second, interval depends on multiplier\n" + "Specify hello-interval for level-2 IIHs\n") +{ + long interval; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + interval = atoi (argv[0]); + if (interval < MIN_HELLO_INTERVAL || interval > MAX_HELLO_INTERVAL) + { + vty_out (vty, "Invalid hello-interval %ld - should be <1-600>%s", + interval, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + circuit->hello_interval[1] = (u_int16_t) interval; + + return CMD_SUCCESS; +} + +DEFUN (no_isis_hello_interval_l2, + no_isis_hello_interval_l2_cmd, + "no isis hello-interval level-2", + NO_STR + "IS-IS commands\n" + "Set Hello interval\n" + "Specify hello-interval for level-2 IIHs\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + circuit->hello_interval[1] = DEFAULT_HELLO_INTERVAL; + + return CMD_SUCCESS; +} + +ALIAS (no_isis_hello_interval_l2, + no_isis_hello_interval_l2_arg_cmd, + "no isis hello-interval <1-600> level-2", + NO_STR + "IS-IS commands\n" + "Set Hello interval\n" + "Hello interval value\n" + "Holdtime 1 second, interval depends on multiplier\n" + "Specify hello-interval for level-2 IIHs\n") + +DEFUN (isis_hello_multiplier, + isis_hello_multiplier_cmd, + "isis hello-multiplier <2-100>", + "IS-IS commands\n" + "Set multiplier for Hello holding time\n" + "Hello multiplier value\n") +{ + int mult; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + mult = atoi (argv[0]); + if (mult < MIN_HELLO_MULTIPLIER || mult > MAX_HELLO_MULTIPLIER) + { + vty_out (vty, "Invalid hello-multiplier %d - should be <2-100>%s", + mult, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + circuit->hello_multiplier[0] = (u_int16_t) mult; + circuit->hello_multiplier[1] = (u_int16_t) mult; + + return CMD_SUCCESS; +} + +DEFUN (no_isis_hello_multiplier, + no_isis_hello_multiplier_cmd, + "no isis hello-multiplier", + NO_STR + "IS-IS commands\n" + "Set multiplier for Hello holding time\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + circuit->hello_multiplier[0] = DEFAULT_HELLO_MULTIPLIER; + circuit->hello_multiplier[1] = DEFAULT_HELLO_MULTIPLIER; + + return CMD_SUCCESS; +} + +ALIAS (no_isis_hello_multiplier, + no_isis_hello_multiplier_arg_cmd, + "no isis hello-multiplier <2-100>", + NO_STR + "IS-IS commands\n" + "Set multiplier for Hello holding time\n" + "Hello multiplier value\n") + +DEFUN (isis_hello_multiplier_l1, + isis_hello_multiplier_l1_cmd, + "isis hello-multiplier <2-100> level-1", + "IS-IS commands\n" + "Set multiplier for Hello holding time\n" + "Hello multiplier value\n" + "Specify hello multiplier for level-1 IIHs\n") +{ + int mult; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + mult = atoi (argv[0]); + if (mult < MIN_HELLO_MULTIPLIER || mult > MAX_HELLO_MULTIPLIER) + { + vty_out (vty, "Invalid hello-multiplier %d - should be <2-100>%s", + mult, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + circuit->hello_multiplier[0] = (u_int16_t) mult; + + return CMD_SUCCESS; +} + +DEFUN (no_isis_hello_multiplier_l1, + no_isis_hello_multiplier_l1_cmd, + "no isis hello-multiplier level-1", + NO_STR + "IS-IS commands\n" + "Set multiplier for Hello holding time\n" + "Specify hello multiplier for level-1 IIHs\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + circuit->hello_multiplier[0] = DEFAULT_HELLO_MULTIPLIER; + + return CMD_SUCCESS; +} + +ALIAS (no_isis_hello_multiplier_l1, + no_isis_hello_multiplier_l1_arg_cmd, + "no isis hello-multiplier <2-100> level-1", + NO_STR + "IS-IS commands\n" + "Set multiplier for Hello holding time\n" + "Hello multiplier value\n" + "Specify hello multiplier for level-1 IIHs\n") + +DEFUN (isis_hello_multiplier_l2, + isis_hello_multiplier_l2_cmd, + "isis hello-multiplier <2-100> level-2", + "IS-IS commands\n" + "Set multiplier for Hello holding time\n" + "Hello multiplier value\n" + "Specify hello multiplier for level-2 IIHs\n") +{ + int mult; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + mult = atoi (argv[0]); + if (mult < MIN_HELLO_MULTIPLIER || mult > MAX_HELLO_MULTIPLIER) + { + vty_out (vty, "Invalid hello-multiplier %d - should be <2-100>%s", + mult, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + circuit->hello_multiplier[1] = (u_int16_t) mult; + + return CMD_SUCCESS; +} + +DEFUN (no_isis_hello_multiplier_l2, + no_isis_hello_multiplier_l2_cmd, + "no isis hello-multiplier level-2", + NO_STR + "IS-IS commands\n" + "Set multiplier for Hello holding time\n" + "Specify hello multiplier for level-2 IIHs\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + circuit->hello_multiplier[1] = DEFAULT_HELLO_MULTIPLIER; + + return CMD_SUCCESS; +} + +ALIAS (no_isis_hello_multiplier_l2, + no_isis_hello_multiplier_l2_arg_cmd, + "no isis hello-multiplier <2-100> level-2", + NO_STR + "IS-IS commands\n" + "Set multiplier for Hello holding time\n" + "Hello multiplier value\n" + "Specify hello multiplier for level-2 IIHs\n") + +DEFUN (isis_hello_padding, + isis_hello_padding_cmd, + "isis hello padding", + "IS-IS commands\n" + "Add padding to IS-IS hello packets\n" + "Pad hello packets\n" + "\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + circuit->pad_hellos = 1; + + return CMD_SUCCESS; +} + +DEFUN (no_isis_hello_padding, + no_isis_hello_padding_cmd, + "no isis hello padding", + NO_STR + "IS-IS commands\n" + "Add padding to IS-IS hello packets\n" + "Pad hello packets\n" + "\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + circuit->pad_hellos = 0; + + return CMD_SUCCESS; +} + +DEFUN (csnp_interval, + csnp_interval_cmd, + "isis csnp-interval <1-600>", + "IS-IS commands\n" + "Set CSNP interval in seconds\n" + "CSNP interval value\n") +{ + unsigned long interval; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + interval = atol (argv[0]); + if (interval < MIN_CSNP_INTERVAL || interval > MAX_CSNP_INTERVAL) + { + vty_out (vty, "Invalid csnp-interval %lu - should be <1-600>%s", + interval, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + circuit->csnp_interval[0] = (u_int16_t) interval; + circuit->csnp_interval[1] = (u_int16_t) interval; + + return CMD_SUCCESS; +} + +DEFUN (no_csnp_interval, + no_csnp_interval_cmd, + "no isis csnp-interval", + NO_STR + "IS-IS commands\n" + "Set CSNP interval in seconds\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + circuit->csnp_interval[0] = DEFAULT_CSNP_INTERVAL; + circuit->csnp_interval[1] = DEFAULT_CSNP_INTERVAL; + + return CMD_SUCCESS; +} + +ALIAS (no_csnp_interval, + no_csnp_interval_arg_cmd, + "no isis csnp-interval <1-600>", + NO_STR + "IS-IS commands\n" + "Set CSNP interval in seconds\n" + "CSNP interval value\n") + +DEFUN (csnp_interval_l1, + csnp_interval_l1_cmd, + "isis csnp-interval <1-600> level-1", + "IS-IS commands\n" + "Set CSNP interval in seconds\n" + "CSNP interval value\n" + "Specify interval for level-1 CSNPs\n") +{ + unsigned long interval; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + interval = atol (argv[0]); + if (interval < MIN_CSNP_INTERVAL || interval > MAX_CSNP_INTERVAL) + { + vty_out (vty, "Invalid csnp-interval %lu - should be <1-600>%s", + interval, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + circuit->csnp_interval[0] = (u_int16_t) interval; + + return CMD_SUCCESS; +} + +DEFUN (no_csnp_interval_l1, + no_csnp_interval_l1_cmd, + "no isis csnp-interval level-1", + NO_STR + "IS-IS commands\n" + "Set CSNP interval in seconds\n" + "Specify interval for level-1 CSNPs\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + circuit->csnp_interval[0] = DEFAULT_CSNP_INTERVAL; + + return CMD_SUCCESS; +} + +ALIAS (no_csnp_interval_l1, + no_csnp_interval_l1_arg_cmd, + "no isis csnp-interval <1-600> level-1", + NO_STR + "IS-IS commands\n" + "Set CSNP interval in seconds\n" + "CSNP interval value\n" + "Specify interval for level-1 CSNPs\n") + +DEFUN (csnp_interval_l2, + csnp_interval_l2_cmd, + "isis csnp-interval <1-600> level-2", + "IS-IS commands\n" + "Set CSNP interval in seconds\n" + "CSNP interval value\n" + "Specify interval for level-2 CSNPs\n") +{ + unsigned long interval; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + interval = atol (argv[0]); + if (interval < MIN_CSNP_INTERVAL || interval > MAX_CSNP_INTERVAL) + { + vty_out (vty, "Invalid csnp-interval %lu - should be <1-600>%s", + interval, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + circuit->csnp_interval[1] = (u_int16_t) interval; + + return CMD_SUCCESS; +} + +DEFUN (no_csnp_interval_l2, + no_csnp_interval_l2_cmd, + "no isis csnp-interval level-2", + NO_STR + "IS-IS commands\n" + "Set CSNP interval in seconds\n" + "Specify interval for level-2 CSNPs\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + circuit->csnp_interval[1] = DEFAULT_CSNP_INTERVAL; + + return CMD_SUCCESS; +} + +ALIAS (no_csnp_interval_l2, + no_csnp_interval_l2_arg_cmd, + "no isis csnp-interval <1-600> level-2", + NO_STR + "IS-IS commands\n" + "Set CSNP interval in seconds\n" + "CSNP interval value\n" + "Specify interval for level-2 CSNPs\n") + +DEFUN (psnp_interval, + psnp_interval_cmd, + "isis psnp-interval <1-120>", + "IS-IS commands\n" + "Set PSNP interval in seconds\n" + "PSNP interval value\n") +{ + unsigned long interval; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + interval = atol (argv[0]); + if (interval < MIN_PSNP_INTERVAL || interval > MAX_PSNP_INTERVAL) + { + vty_out (vty, "Invalid psnp-interval %lu - should be <1-120>%s", + interval, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + circuit->psnp_interval[0] = (u_int16_t) interval; + circuit->psnp_interval[1] = (u_int16_t) interval; + + return CMD_SUCCESS; +} + +DEFUN (no_psnp_interval, + no_psnp_interval_cmd, + "no isis psnp-interval", + NO_STR + "IS-IS commands\n" + "Set PSNP interval in seconds\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + circuit->psnp_interval[0] = DEFAULT_PSNP_INTERVAL; + circuit->psnp_interval[1] = DEFAULT_PSNP_INTERVAL; + + return CMD_SUCCESS; +} + +ALIAS (no_psnp_interval, + no_psnp_interval_arg_cmd, + "no isis psnp-interval <1-120>", + NO_STR + "IS-IS commands\n" + "Set PSNP interval in seconds\n" + "PSNP interval value\n") + +DEFUN (psnp_interval_l1, + psnp_interval_l1_cmd, + "isis psnp-interval <1-120> level-1", + "IS-IS commands\n" + "Set PSNP interval in seconds\n" + "PSNP interval value\n" + "Specify interval for level-1 PSNPs\n") +{ + unsigned long interval; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + interval = atol (argv[0]); + if (interval < MIN_PSNP_INTERVAL || interval > MAX_PSNP_INTERVAL) + { + vty_out (vty, "Invalid psnp-interval %lu - should be <1-120>%s", + interval, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + circuit->psnp_interval[0] = (u_int16_t) interval; + + return CMD_SUCCESS; +} + +DEFUN (no_psnp_interval_l1, + no_psnp_interval_l1_cmd, + "no isis psnp-interval level-1", + NO_STR + "IS-IS commands\n" + "Set PSNP interval in seconds\n" + "Specify interval for level-1 PSNPs\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + circuit->psnp_interval[0] = DEFAULT_PSNP_INTERVAL; + + return CMD_SUCCESS; +} + +ALIAS (no_psnp_interval_l1, + no_psnp_interval_l1_arg_cmd, + "no isis psnp-interval <1-120> level-1", + NO_STR + "IS-IS commands\n" + "Set PSNP interval in seconds\n" + "PSNP interval value\n" + "Specify interval for level-1 PSNPs\n") + +DEFUN (psnp_interval_l2, + psnp_interval_l2_cmd, + "isis psnp-interval <1-120> level-2", + "IS-IS commands\n" + "Set PSNP interval in seconds\n" + "PSNP interval value\n" + "Specify interval for level-2 PSNPs\n") +{ + unsigned long interval; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + interval = atol (argv[0]); + if (interval < MIN_PSNP_INTERVAL || interval > MAX_PSNP_INTERVAL) + { + vty_out (vty, "Invalid psnp-interval %lu - should be <1-120>%s", + interval, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + circuit->psnp_interval[1] = (u_int16_t) interval; + + return CMD_SUCCESS; +} + +DEFUN (no_psnp_interval_l2, + no_psnp_interval_l2_cmd, + "no isis psnp-interval level-2", + NO_STR + "IS-IS commands\n" + "Set PSNP interval in seconds\n" + "Specify interval for level-2 PSNPs\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + circuit->psnp_interval[1] = DEFAULT_PSNP_INTERVAL; + + return CMD_SUCCESS; +} + +ALIAS (no_psnp_interval_l2, + no_psnp_interval_l2_arg_cmd, + "no isis psnp-interval <1-120> level-2", + NO_STR + "IS-IS commands\n" + "Set PSNP interval in seconds\n" + "PSNP interval value\n" + "Specify interval for level-2 PSNPs\n") + +static int +validate_metric_style_narrow (struct vty *vty, struct isis_area *area) +{ + struct isis_circuit *circuit; + struct listnode *node; + + if (! vty) + return CMD_ERR_AMBIGUOUS; + + if (! area) + { + vty_out (vty, "ISIS area is invalid%s", VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit)) + { + if ((area->is_type & IS_LEVEL_1) && + (circuit->is_type & IS_LEVEL_1) && + (circuit->te_metric[0] > MAX_NARROW_LINK_METRIC)) + { + vty_out (vty, "ISIS circuit %s metric is invalid%s", + circuit->interface->name, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + if ((area->is_type & IS_LEVEL_2) && + (circuit->is_type & IS_LEVEL_2) && + (circuit->te_metric[1] > MAX_NARROW_LINK_METRIC)) + { + vty_out (vty, "ISIS circuit %s metric is invalid%s", + circuit->interface->name, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + } + + return CMD_SUCCESS; +} + +DEFUN (metric_style, + metric_style_cmd, + "metric-style (narrow|transition|wide)", + "Use old-style (ISO 10589) or new-style packet formats\n" + "Use old style of TLVs with narrow metric\n" + "Send and accept both styles of TLVs during transition\n" + "Use new style of TLVs to carry wider metric\n") +{ + struct isis_area *area = vty->index; + int ret; + + assert(area); + + if (strncmp (argv[0], "w", 1) == 0) + { + isis_area_metricstyle_set(area, false, true); + return CMD_SUCCESS; + } + + ret = validate_metric_style_narrow (vty, area); + if (ret != CMD_SUCCESS) + return ret; + + if (strncmp (argv[0], "t", 1) == 0) + isis_area_metricstyle_set(area, true, true); + else if (strncmp (argv[0], "n", 1) == 0) + isis_area_metricstyle_set(area, true, false); + return CMD_SUCCESS; + + return CMD_SUCCESS; +} + +DEFUN (no_metric_style, + no_metric_style_cmd, + "no metric-style", + NO_STR + "Use old-style (ISO 10589) or new-style packet formats\n") +{ + struct isis_area *area = vty->index; + int ret; + + assert (area); + ret = validate_metric_style_narrow (vty, area); + if (ret != CMD_SUCCESS) + return ret; + + isis_area_metricstyle_set(area, true, false); + return CMD_SUCCESS; +} + +DEFUN (set_overload_bit, + set_overload_bit_cmd, + "set-overload-bit", + "Set overload bit to avoid any transit traffic\n" + "Set overload bit\n") +{ + struct isis_area *area = vty->index; + assert (area); + + isis_area_overload_bit_set(area, true); + return CMD_SUCCESS; +} + +DEFUN (no_set_overload_bit, + no_set_overload_bit_cmd, + "no set-overload-bit", + "Reset overload bit to accept transit traffic\n" + "Reset overload bit\n") +{ + struct isis_area *area = vty->index; + assert (area); + + isis_area_overload_bit_set(area, false); + return CMD_SUCCESS; +} + +DEFUN (set_attached_bit, + set_attached_bit_cmd, + "set-attached-bit", + "Set attached bit to identify as L1/L2 router for inter-area traffic\n" + "Set attached bit\n") +{ + struct isis_area *area = vty->index; + assert (area); + + isis_area_attached_bit_set(area, true); + return CMD_SUCCESS; +} + +DEFUN (no_set_attached_bit, + no_set_attached_bit_cmd, + "no set-attached-bit", + "Reset attached bit\n") +{ + struct isis_area *area = vty->index; + assert (area); + + isis_area_attached_bit_set(area, false); + return CMD_SUCCESS; +} + +DEFUN (dynamic_hostname, + dynamic_hostname_cmd, + "hostname dynamic", + "Dynamic hostname for IS-IS\n" + "Dynamic hostname\n") +{ + struct isis_area *area = vty->index; + assert(area); + + isis_area_dynhostname_set(area, true); + return CMD_SUCCESS; +} + +DEFUN (no_dynamic_hostname, + no_dynamic_hostname_cmd, + "no hostname dynamic", + NO_STR + "Dynamic hostname for IS-IS\n" + "Dynamic hostname\n") +{ + struct isis_area *area = vty->index; + assert(area); + + isis_area_dynhostname_set(area, false); + return CMD_SUCCESS; +} + +static int area_lsp_mtu_set(struct vty *vty, unsigned int lsp_mtu) +{ + struct isis_area *area = vty->index; + struct listnode *node; + struct isis_circuit *circuit; + + if (!area) + { + vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); + return CMD_ERR_NO_MATCH; + } + + for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) + { + if(circuit->state != C_STATE_INIT && circuit->state != C_STATE_UP) + continue; + if(lsp_mtu > isis_circuit_pdu_size(circuit)) + { + vty_out(vty, "ISIS area contains circuit %s, which has a maximum PDU size of %zu.%s", + circuit->interface->name, isis_circuit_pdu_size(circuit), + VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + } + + isis_area_lsp_mtu_set(area, lsp_mtu); + return CMD_SUCCESS; +} + +DEFUN (area_lsp_mtu, + area_lsp_mtu_cmd, + "lsp-mtu <128-4352>", + "Configure the maximum size of generated LSPs\n" + "Maximum size of generated LSPs\n") +{ + unsigned int lsp_mtu; + + VTY_GET_INTEGER_RANGE("lsp-mtu", lsp_mtu, argv[0], 128, 4352); + + return area_lsp_mtu_set(vty, lsp_mtu); +} + +DEFUN(no_area_lsp_mtu, + no_area_lsp_mtu_cmd, + "no lsp-mtu", + NO_STR + "Configure the maximum size of generated LSPs\n") +{ + return area_lsp_mtu_set(vty, DEFAULT_LSP_MTU); +} + +ALIAS(no_area_lsp_mtu, + no_area_lsp_mtu_arg_cmd, + "no lsp-mtu <128-4352>", + NO_STR + "Configure the maximum size of generated LSPs\n" + "Maximum size of generated LSPs\n"); + +DEFUN (is_type, + is_type_cmd, + "is-type (level-1|level-1-2|level-2-only)", + "IS Level for this routing process (OSI only)\n" + "Act as a station router only\n" + "Act as both a station router and an area router\n" + "Act as an area router only\n") +{ + struct isis_area *area; + int type; + + area = vty->index; + + if (!area) + { + vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); + return CMD_ERR_NO_MATCH; + } + + type = string2circuit_t (argv[0]); + if (!type) + { + vty_out (vty, "Unknown IS level %s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + isis_area_is_type_set(area, type); + + return CMD_SUCCESS; +} + +DEFUN (no_is_type, + no_is_type_cmd, + "no is-type (level-1|level-1-2|level-2-only)", + NO_STR + "IS Level for this routing process (OSI only)\n" + "Act as a station router only\n" + "Act as both a station router and an area router\n" + "Act as an area router only\n") +{ + struct isis_area *area; + int type; + + area = vty->index; + assert (area); + + /* + * Put the is-type back to defaults: + * - level-1-2 on first area + * - level-1 for the rest + */ + if (listgetdata (listhead (isis->area_list)) == area) + type = IS_LEVEL_1_AND_2; + else + type = IS_LEVEL_1; + + isis_area_is_type_set(area, type); + + return CMD_SUCCESS; +} + +static int +set_lsp_gen_interval (struct vty *vty, struct isis_area *area, + uint16_t interval, int level) +{ + int lvl; + + for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl) + { + if (!(lvl & level)) + continue; + + if (interval >= area->lsp_refresh[lvl-1]) + { + vty_out (vty, "LSP gen interval %us must be less than " + "the LSP refresh interval %us%s", + interval, area->lsp_refresh[lvl-1], VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + } + + for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl) + { + if (!(lvl & level)) + continue; + area->lsp_gen_interval[lvl-1] = interval; + } + + return CMD_SUCCESS; +} + +DEFUN (lsp_gen_interval, + lsp_gen_interval_cmd, + "lsp-gen-interval <1-120>", + "Minimum interval between regenerating same LSP\n" + "Minimum interval in seconds\n") +{ + struct isis_area *area; + uint16_t interval; + int level; + + area = vty->index; + interval = atoi (argv[0]); + level = IS_LEVEL_1 | IS_LEVEL_2; + return set_lsp_gen_interval (vty, area, interval, level); +} + +DEFUN (no_lsp_gen_interval, + no_lsp_gen_interval_cmd, + "no lsp-gen-interval", + NO_STR + "Minimum interval between regenerating same LSP\n") +{ + struct isis_area *area; + uint16_t interval; + int level; + + area = vty->index; + interval = DEFAULT_MIN_LSP_GEN_INTERVAL; + level = IS_LEVEL_1 | IS_LEVEL_2; + return set_lsp_gen_interval (vty, area, interval, level); +} + +ALIAS (no_lsp_gen_interval, + no_lsp_gen_interval_arg_cmd, + "no lsp-gen-interval <1-120>", + NO_STR + "Minimum interval between regenerating same LSP\n" + "Minimum interval in seconds\n") + +DEFUN (lsp_gen_interval_l1, + lsp_gen_interval_l1_cmd, + "lsp-gen-interval level-1 <1-120>", + "Minimum interval between regenerating same LSP\n" + "Set interval for level 1 only\n" + "Minimum interval in seconds\n") +{ + struct isis_area *area; + uint16_t interval; + int level; + + area = vty->index; + interval = atoi (argv[0]); + level = IS_LEVEL_1; + return set_lsp_gen_interval (vty, area, interval, level); +} + +DEFUN (no_lsp_gen_interval_l1, + no_lsp_gen_interval_l1_cmd, + "no lsp-gen-interval level-1", + NO_STR + "Minimum interval between regenerating same LSP\n" + "Set interval for level 1 only\n") +{ + struct isis_area *area; + uint16_t interval; + int level; + + area = vty->index; + interval = DEFAULT_MIN_LSP_GEN_INTERVAL; + level = IS_LEVEL_1; + return set_lsp_gen_interval (vty, area, interval, level); +} + +ALIAS (no_lsp_gen_interval_l1, + no_lsp_gen_interval_l1_arg_cmd, + "no lsp-gen-interval level-1 <1-120>", + NO_STR + "Minimum interval between regenerating same LSP\n" + "Set interval for level 1 only\n" + "Minimum interval in seconds\n") + +DEFUN (lsp_gen_interval_l2, + lsp_gen_interval_l2_cmd, + "lsp-gen-interval level-2 <1-120>", + "Minimum interval between regenerating same LSP\n" + "Set interval for level 2 only\n" + "Minimum interval in seconds\n") +{ + struct isis_area *area; + uint16_t interval; + int level; + + area = vty->index; + interval = atoi (argv[0]); + level = IS_LEVEL_2; + return set_lsp_gen_interval (vty, area, interval, level); +} + +DEFUN (no_lsp_gen_interval_l2, + no_lsp_gen_interval_l2_cmd, + "no lsp-gen-interval level-2", + NO_STR + "Minimum interval between regenerating same LSP\n" + "Set interval for level 2 only\n") +{ + struct isis_area *area; + uint16_t interval; + int level; + + area = vty->index; + interval = DEFAULT_MIN_LSP_GEN_INTERVAL; + level = IS_LEVEL_2; + return set_lsp_gen_interval (vty, area, interval, level); +} + +ALIAS (no_lsp_gen_interval_l2, + no_lsp_gen_interval_l2_arg_cmd, + "no lsp-gen-interval level-2 <1-120>", + NO_STR + "Minimum interval between regenerating same LSP\n" + "Set interval for level 2 only\n" + "Minimum interval in seconds\n") + +DEFUN (spf_interval, + spf_interval_cmd, + "spf-interval <1-120>", + "Minimum interval between SPF calculations\n" + "Minimum interval between consecutive SPFs in seconds\n") +{ + struct isis_area *area; + u_int16_t interval; + + area = vty->index; + interval = atoi (argv[0]); + area->min_spf_interval[0] = interval; + area->min_spf_interval[1] = interval; + + return CMD_SUCCESS; +} + +DEFUN (no_spf_interval, + no_spf_interval_cmd, + "no spf-interval", + NO_STR + "Minimum interval between SPF calculations\n") +{ + struct isis_area *area; + + area = vty->index; + + area->min_spf_interval[0] = MINIMUM_SPF_INTERVAL; + area->min_spf_interval[1] = MINIMUM_SPF_INTERVAL; + + return CMD_SUCCESS; +} + +ALIAS (no_spf_interval, + no_spf_interval_arg_cmd, + "no spf-interval <1-120>", + NO_STR + "Minimum interval between SPF calculations\n" + "Minimum interval between consecutive SPFs in seconds\n") + +DEFUN (spf_interval_l1, + spf_interval_l1_cmd, + "spf-interval level-1 <1-120>", + "Minimum interval between SPF calculations\n" + "Set interval for level 1 only\n" + "Minimum interval between consecutive SPFs in seconds\n") +{ + struct isis_area *area; + u_int16_t interval; + + area = vty->index; + interval = atoi (argv[0]); + area->min_spf_interval[0] = interval; + + return CMD_SUCCESS; +} + +DEFUN (no_spf_interval_l1, + no_spf_interval_l1_cmd, + "no spf-interval level-1", + NO_STR + "Minimum interval between SPF calculations\n" + "Set interval for level 1 only\n") +{ + struct isis_area *area; + + area = vty->index; + + area->min_spf_interval[0] = MINIMUM_SPF_INTERVAL; + + return CMD_SUCCESS; +} + +ALIAS (no_spf_interval, + no_spf_interval_l1_arg_cmd, + "no spf-interval level-1 <1-120>", + NO_STR + "Minimum interval between SPF calculations\n" + "Set interval for level 1 only\n" + "Minimum interval between consecutive SPFs in seconds\n") + +DEFUN (spf_interval_l2, + spf_interval_l2_cmd, + "spf-interval level-2 <1-120>", + "Minimum interval between SPF calculations\n" + "Set interval for level 2 only\n" + "Minimum interval between consecutive SPFs in seconds\n") +{ + struct isis_area *area; + u_int16_t interval; + + area = vty->index; + interval = atoi (argv[0]); + area->min_spf_interval[1] = interval; + + return CMD_SUCCESS; +} + +DEFUN (no_spf_interval_l2, + no_spf_interval_l2_cmd, + "no spf-interval level-2", + NO_STR + "Minimum interval between SPF calculations\n" + "Set interval for level 2 only\n") +{ + struct isis_area *area; + + area = vty->index; + + area->min_spf_interval[1] = MINIMUM_SPF_INTERVAL; + + return CMD_SUCCESS; +} + +ALIAS (no_spf_interval, + no_spf_interval_l2_arg_cmd, + "no spf-interval level-2 <1-120>", + NO_STR + "Minimum interval between SPF calculations\n" + "Set interval for level 2 only\n" + "Minimum interval between consecutive SPFs in seconds\n") + +static int +area_max_lsp_lifetime_set(struct vty *vty, int level, + uint16_t interval) +{ + struct isis_area *area = vty->index; + int lvl; + uint16_t refresh_interval = interval - 300; + int set_refresh_interval[ISIS_LEVELS] = {0, 0}; + + if (!area) + { + vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); + return CMD_ERR_NO_MATCH; + } + + for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++) + { + if (!(lvl & level)) + continue; + + if (refresh_interval < area->lsp_refresh[lvl-1]) + { + vty_out (vty, "Level %d Max LSP lifetime %us must be 300s greater than " + "the configured LSP refresh interval %us%s", + lvl, interval, area->lsp_refresh[lvl-1], VTY_NEWLINE); + vty_out (vty, "Automatically reducing level %d LSP refresh interval " + "to %us%s", lvl, refresh_interval, VTY_NEWLINE); + set_refresh_interval[lvl-1] = 1; + + if (refresh_interval <= area->lsp_gen_interval[lvl-1]) + { + vty_out (vty, "LSP refresh interval %us must be greater than " + "the configured LSP gen interval %us%s", + refresh_interval, area->lsp_gen_interval[lvl-1], + VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + } + } + + for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++) + { + if (!(lvl & level)) + continue; + isis_area_max_lsp_lifetime_set(area, lvl, interval); + if (set_refresh_interval[lvl-1]) + isis_area_lsp_refresh_set(area, lvl, refresh_interval); + } + + return CMD_SUCCESS; +} + +DEFUN (max_lsp_lifetime, + max_lsp_lifetime_cmd, + "max-lsp-lifetime <350-65535>", + "Maximum LSP lifetime\n" + "LSP lifetime in seconds\n") +{ + return area_max_lsp_lifetime_set(vty, IS_LEVEL_1_AND_2, atoi(argv[0])); +} + +DEFUN (no_max_lsp_lifetime, + no_max_lsp_lifetime_cmd, + "no max-lsp-lifetime", + NO_STR + "LSP lifetime in seconds\n") +{ + return area_max_lsp_lifetime_set(vty, IS_LEVEL_1_AND_2, + DEFAULT_LSP_LIFETIME); +} + +ALIAS (no_max_lsp_lifetime, + no_max_lsp_lifetime_arg_cmd, + "no max-lsp-lifetime <350-65535>", + NO_STR + "Maximum LSP lifetime\n" + "LSP lifetime in seconds\n") + +DEFUN (max_lsp_lifetime_l1, + max_lsp_lifetime_l1_cmd, + "max-lsp-lifetime level-1 <350-65535>", + "Maximum LSP lifetime for Level 1 only\n" + "LSP lifetime for Level 1 only in seconds\n") +{ + return area_max_lsp_lifetime_set(vty, IS_LEVEL_1, atoi(argv[0])); +} + +DEFUN (no_max_lsp_lifetime_l1, + no_max_lsp_lifetime_l1_cmd, + "no max-lsp-lifetime level-1", + NO_STR + "LSP lifetime for Level 1 only in seconds\n") +{ + return area_max_lsp_lifetime_set(vty, IS_LEVEL_1, DEFAULT_LSP_LIFETIME); +} + +ALIAS (no_max_lsp_lifetime_l1, + no_max_lsp_lifetime_l1_arg_cmd, + "no max-lsp-lifetime level-1 <350-65535>", + NO_STR + "Maximum LSP lifetime for Level 1 only\n" + "LSP lifetime for Level 1 only in seconds\n") + +DEFUN (max_lsp_lifetime_l2, + max_lsp_lifetime_l2_cmd, + "max-lsp-lifetime level-2 <350-65535>", + "Maximum LSP lifetime for Level 2 only\n" + "LSP lifetime for Level 2 only in seconds\n") +{ + return area_max_lsp_lifetime_set(vty, IS_LEVEL_2, atoi(argv[0])); +} + +DEFUN (no_max_lsp_lifetime_l2, + no_max_lsp_lifetime_l2_cmd, + "no max-lsp-lifetime level-2", + NO_STR + "LSP lifetime for Level 2 only in seconds\n") +{ + return area_max_lsp_lifetime_set(vty, IS_LEVEL_2, DEFAULT_LSP_LIFETIME); +} + +ALIAS (no_max_lsp_lifetime_l2, + no_max_lsp_lifetime_l2_arg_cmd, + "no max-lsp-lifetime level-2 <350-65535>", + NO_STR + "Maximum LSP lifetime for Level 2 only\n" + "LSP lifetime for Level 2 only in seconds\n") + +static int +area_lsp_refresh_interval_set(struct vty *vty, int level, uint16_t interval) +{ + struct isis_area *area = vty->index; + int lvl; + + if (!area) + { + vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); + return CMD_ERR_NO_MATCH; + } + + for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl) + { + if (!(lvl & level)) + continue; + if (interval <= area->lsp_gen_interval[lvl-1]) + { + vty_out (vty, "LSP refresh interval %us must be greater than " + "the configured LSP gen interval %us%s", + interval, area->lsp_gen_interval[lvl-1], + VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + if (interval > (area->max_lsp_lifetime[lvl-1] - 300)) + { + vty_out (vty, "LSP refresh interval %us must be less than " + "the configured LSP lifetime %us less 300%s", + interval, area->max_lsp_lifetime[lvl-1], + VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + } + + for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl) + { + if (!(lvl & level)) + continue; + isis_area_lsp_refresh_set(area, lvl, interval); + } + + return CMD_SUCCESS; +} + +DEFUN (lsp_refresh_interval, + lsp_refresh_interval_cmd, + "lsp-refresh-interval <1-65235>", + "LSP refresh interval\n" + "LSP refresh interval in seconds\n") +{ + return area_lsp_refresh_interval_set(vty, IS_LEVEL_1_AND_2, atoi(argv[0])); +} + +DEFUN (no_lsp_refresh_interval, + no_lsp_refresh_interval_cmd, + "no lsp-refresh-interval", + NO_STR + "LSP refresh interval in seconds\n") +{ + return area_lsp_refresh_interval_set(vty, IS_LEVEL_1_AND_2, + DEFAULT_MAX_LSP_GEN_INTERVAL); +} + +ALIAS (no_lsp_refresh_interval, + no_lsp_refresh_interval_arg_cmd, + "no lsp-refresh-interval <1-65235>", + NO_STR + "LSP refresh interval\n" + "LSP refresh interval in seconds\n") + +DEFUN (lsp_refresh_interval_l1, + lsp_refresh_interval_l1_cmd, + "lsp-refresh-interval level-1 <1-65235>", + "LSP refresh interval for Level 1 only\n" + "LSP refresh interval for Level 1 only in seconds\n") +{ + return area_lsp_refresh_interval_set(vty, IS_LEVEL_1, atoi(argv[0])); +} + +DEFUN (no_lsp_refresh_interval_l1, + no_lsp_refresh_interval_l1_cmd, + "no lsp-refresh-interval level-1", + NO_STR + "LSP refresh interval for Level 1 only in seconds\n") +{ + return area_lsp_refresh_interval_set(vty, IS_LEVEL_1, + DEFAULT_MAX_LSP_GEN_INTERVAL); +} + +ALIAS (no_lsp_refresh_interval_l1, + no_lsp_refresh_interval_l1_arg_cmd, + "no lsp-refresh-interval level-1 <1-65235>", + NO_STR + "LSP refresh interval for Level 1 only\n" + "LSP refresh interval for Level 1 only in seconds\n") + +DEFUN (lsp_refresh_interval_l2, + lsp_refresh_interval_l2_cmd, + "lsp-refresh-interval level-2 <1-65235>", + "LSP refresh interval for Level 2 only\n" + "LSP refresh interval for Level 2 only in seconds\n") +{ + return area_lsp_refresh_interval_set(vty, IS_LEVEL_2, atoi(argv[0])); +} + +DEFUN (no_lsp_refresh_interval_l2, + no_lsp_refresh_interval_l2_cmd, + "no lsp-refresh-interval level-2", + NO_STR + "LSP refresh interval for Level 2 only in seconds\n") +{ + return area_lsp_refresh_interval_set(vty, IS_LEVEL_2, + DEFAULT_MAX_LSP_GEN_INTERVAL); +} + +ALIAS (no_lsp_refresh_interval_l2, + no_lsp_refresh_interval_l2_arg_cmd, + "no lsp-refresh-interval level-2 <1-65235>", + NO_STR + "LSP refresh interval for Level 2 only\n" + "LSP refresh interval for Level 2 only in seconds\n") + +static int +area_passwd_set(struct vty *vty, int level, + int (*type_set)(struct isis_area *area, int level, + const char *passwd, u_char snp_auth), + const char *passwd, u_char snp_auth) +{ + struct isis_area *area = vty->index; + + if (!area) + { + vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); + return CMD_ERR_NO_MATCH; + } + + if (passwd && strlen(passwd) > 254) + { + vty_out (vty, "Too long area password (>254)%s", VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + type_set(area, level, passwd, snp_auth); + return CMD_SUCCESS; +} + +DEFUN (area_passwd_md5, + area_passwd_md5_cmd, + "(area-password|domain-password) md5 WORD", + "Configure the authentication password for an area\n" + "Set the authentication password for a routing domain\n" + "Authentication type\n" + "Level-wide password\n") +{ + u_char snp_auth = 0; + int level = (argv[0][0] == 'd') ? IS_LEVEL_2 : IS_LEVEL_1; + + if (argc > 2) + { + snp_auth = SNP_AUTH_SEND; + if (strncmp(argv[2], "v", 1) == 0) + snp_auth |= SNP_AUTH_RECV; + } + + return area_passwd_set(vty, level, isis_area_passwd_hmac_md5_set, + argv[1], snp_auth); +} + +ALIAS (area_passwd_md5, + area_passwd_md5_snpauth_cmd, + "(area-password|domain-password) md5 WORD authenticate snp (send-only|validate)", + "Configure the authentication password for an area\n" + "Set the authentication password for a routing domain\n" + "Authentication type\n" + "Level-wide password\n" + "Authentication\n" + "SNP PDUs\n" + "Send but do not check PDUs on receiving\n" + "Send and check PDUs on receiving\n") + +DEFUN (area_passwd_clear, + area_passwd_clear_cmd, + "(area-password|domain-password) clear WORD", + "Configure the authentication password for an area\n" + "Set the authentication password for a routing domain\n" + "Authentication type\n" + "Area password\n") +{ + u_char snp_auth = 0; + int level = (argv[0][0] == 'd') ? IS_LEVEL_2 : IS_LEVEL_1; + + if (argc > 2) + { + snp_auth = SNP_AUTH_SEND; + if (strncmp(argv[2], "v", 1) == 0) + snp_auth |= SNP_AUTH_RECV; + } + + return area_passwd_set(vty, level, isis_area_passwd_cleartext_set, + argv[1], snp_auth); +} + +ALIAS (area_passwd_clear, + area_passwd_clear_snpauth_cmd, + "(area-password|domain-password) clear WORD authenticate snp (send-only|validate)", + "Configure the authentication password for an area\n" + "Set the authentication password for a routing domain\n" + "Authentication type\n" + "Area password\n" + "Authentication\n" + "SNP PDUs\n" + "Send but do not check PDUs on receiving\n" + "Send and check PDUs on receiving\n") + +DEFUN (no_area_passwd, + no_area_passwd_cmd, + "no (area-password|domain-password)", + NO_STR + "Configure the authentication password for an area\n" + "Set the authentication password for a routing domain\n") +{ + int level = (argv[0][0] == 'd') ? IS_LEVEL_2 : IS_LEVEL_1; + struct isis_area *area = vty->index; + + if (!area) + { + vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); + return CMD_ERR_NO_MATCH; + } + + return isis_area_passwd_unset (area, level); +} + +void +isis_vty_init (void) +{ + install_element (INTERFACE_NODE, &ip_router_isis_cmd); + install_element (INTERFACE_NODE, &no_ip_router_isis_cmd); + + install_element (INTERFACE_NODE, &isis_passive_cmd); + install_element (INTERFACE_NODE, &no_isis_passive_cmd); + + install_element (INTERFACE_NODE, &isis_circuit_type_cmd); + install_element (INTERFACE_NODE, &no_isis_circuit_type_cmd); + + install_element (INTERFACE_NODE, &isis_network_cmd); + install_element (INTERFACE_NODE, &no_isis_network_cmd); + + install_element (INTERFACE_NODE, &isis_passwd_cmd); + install_element (INTERFACE_NODE, &no_isis_passwd_cmd); + install_element (INTERFACE_NODE, &no_isis_passwd_arg_cmd); + + install_element (INTERFACE_NODE, &isis_priority_cmd); + install_element (INTERFACE_NODE, &no_isis_priority_cmd); + install_element (INTERFACE_NODE, &no_isis_priority_arg_cmd); + install_element (INTERFACE_NODE, &isis_priority_l1_cmd); + install_element (INTERFACE_NODE, &no_isis_priority_l1_cmd); + install_element (INTERFACE_NODE, &no_isis_priority_l1_arg_cmd); + install_element (INTERFACE_NODE, &isis_priority_l2_cmd); + install_element (INTERFACE_NODE, &no_isis_priority_l2_cmd); + install_element (INTERFACE_NODE, &no_isis_priority_l2_arg_cmd); + + install_element (INTERFACE_NODE, &isis_metric_cmd); + install_element (INTERFACE_NODE, &no_isis_metric_cmd); + install_element (INTERFACE_NODE, &no_isis_metric_arg_cmd); + install_element (INTERFACE_NODE, &isis_metric_l1_cmd); + install_element (INTERFACE_NODE, &no_isis_metric_l1_cmd); + install_element (INTERFACE_NODE, &no_isis_metric_l1_arg_cmd); + install_element (INTERFACE_NODE, &isis_metric_l2_cmd); + install_element (INTERFACE_NODE, &no_isis_metric_l2_cmd); + install_element (INTERFACE_NODE, &no_isis_metric_l2_arg_cmd); + + install_element (INTERFACE_NODE, &isis_hello_interval_cmd); + install_element (INTERFACE_NODE, &no_isis_hello_interval_cmd); + install_element (INTERFACE_NODE, &no_isis_hello_interval_arg_cmd); + install_element (INTERFACE_NODE, &isis_hello_interval_l1_cmd); + install_element (INTERFACE_NODE, &no_isis_hello_interval_l1_cmd); + install_element (INTERFACE_NODE, &no_isis_hello_interval_l1_arg_cmd); + install_element (INTERFACE_NODE, &isis_hello_interval_l2_cmd); + install_element (INTERFACE_NODE, &no_isis_hello_interval_l2_cmd); + install_element (INTERFACE_NODE, &no_isis_hello_interval_l2_arg_cmd); + + install_element (INTERFACE_NODE, &isis_hello_multiplier_cmd); + install_element (INTERFACE_NODE, &no_isis_hello_multiplier_cmd); + install_element (INTERFACE_NODE, &no_isis_hello_multiplier_arg_cmd); + install_element (INTERFACE_NODE, &isis_hello_multiplier_l1_cmd); + install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l1_cmd); + install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l1_arg_cmd); + install_element (INTERFACE_NODE, &isis_hello_multiplier_l2_cmd); + install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l2_cmd); + install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l2_arg_cmd); + + install_element (INTERFACE_NODE, &isis_hello_padding_cmd); + install_element (INTERFACE_NODE, &no_isis_hello_padding_cmd); + + install_element (INTERFACE_NODE, &csnp_interval_cmd); + install_element (INTERFACE_NODE, &no_csnp_interval_cmd); + install_element (INTERFACE_NODE, &no_csnp_interval_arg_cmd); + install_element (INTERFACE_NODE, &csnp_interval_l1_cmd); + install_element (INTERFACE_NODE, &no_csnp_interval_l1_cmd); + install_element (INTERFACE_NODE, &no_csnp_interval_l1_arg_cmd); + install_element (INTERFACE_NODE, &csnp_interval_l2_cmd); + install_element (INTERFACE_NODE, &no_csnp_interval_l2_cmd); + install_element (INTERFACE_NODE, &no_csnp_interval_l2_arg_cmd); + + install_element (INTERFACE_NODE, &psnp_interval_cmd); + install_element (INTERFACE_NODE, &no_psnp_interval_cmd); + install_element (INTERFACE_NODE, &no_psnp_interval_arg_cmd); + install_element (INTERFACE_NODE, &psnp_interval_l1_cmd); + install_element (INTERFACE_NODE, &no_psnp_interval_l1_cmd); + install_element (INTERFACE_NODE, &no_psnp_interval_l1_arg_cmd); + install_element (INTERFACE_NODE, &psnp_interval_l2_cmd); + install_element (INTERFACE_NODE, &no_psnp_interval_l2_cmd); + install_element (INTERFACE_NODE, &no_psnp_interval_l2_arg_cmd); + + install_element (ISIS_NODE, &metric_style_cmd); + install_element (ISIS_NODE, &no_metric_style_cmd); + + install_element (ISIS_NODE, &set_overload_bit_cmd); + install_element (ISIS_NODE, &no_set_overload_bit_cmd); + + install_element (ISIS_NODE, &set_attached_bit_cmd); + install_element (ISIS_NODE, &no_set_attached_bit_cmd); + + install_element (ISIS_NODE, &dynamic_hostname_cmd); + install_element (ISIS_NODE, &no_dynamic_hostname_cmd); + + install_element (ISIS_NODE, &area_lsp_mtu_cmd); + install_element (ISIS_NODE, &no_area_lsp_mtu_cmd); + install_element (ISIS_NODE, &no_area_lsp_mtu_arg_cmd); + + install_element (ISIS_NODE, &is_type_cmd); + install_element (ISIS_NODE, &no_is_type_cmd); + + install_element (ISIS_NODE, &lsp_gen_interval_cmd); + install_element (ISIS_NODE, &no_lsp_gen_interval_cmd); + install_element (ISIS_NODE, &no_lsp_gen_interval_arg_cmd); + install_element (ISIS_NODE, &lsp_gen_interval_l1_cmd); + install_element (ISIS_NODE, &no_lsp_gen_interval_l1_cmd); + install_element (ISIS_NODE, &no_lsp_gen_interval_l1_arg_cmd); + install_element (ISIS_NODE, &lsp_gen_interval_l2_cmd); + install_element (ISIS_NODE, &no_lsp_gen_interval_l2_cmd); + install_element (ISIS_NODE, &no_lsp_gen_interval_l2_arg_cmd); + + install_element (ISIS_NODE, &spf_interval_cmd); + install_element (ISIS_NODE, &no_spf_interval_cmd); + install_element (ISIS_NODE, &no_spf_interval_arg_cmd); + install_element (ISIS_NODE, &spf_interval_l1_cmd); + install_element (ISIS_NODE, &no_spf_interval_l1_cmd); + install_element (ISIS_NODE, &no_spf_interval_l1_arg_cmd); + install_element (ISIS_NODE, &spf_interval_l2_cmd); + install_element (ISIS_NODE, &no_spf_interval_l2_cmd); + install_element (ISIS_NODE, &no_spf_interval_l2_arg_cmd); + + install_element (ISIS_NODE, &max_lsp_lifetime_cmd); + install_element (ISIS_NODE, &no_max_lsp_lifetime_cmd); + install_element (ISIS_NODE, &no_max_lsp_lifetime_arg_cmd); + install_element (ISIS_NODE, &max_lsp_lifetime_l1_cmd); + install_element (ISIS_NODE, &no_max_lsp_lifetime_l1_cmd); + install_element (ISIS_NODE, &no_max_lsp_lifetime_l1_arg_cmd); + install_element (ISIS_NODE, &max_lsp_lifetime_l2_cmd); + install_element (ISIS_NODE, &no_max_lsp_lifetime_l2_cmd); + install_element (ISIS_NODE, &no_max_lsp_lifetime_l2_arg_cmd); + + install_element (ISIS_NODE, &lsp_refresh_interval_cmd); + install_element (ISIS_NODE, &no_lsp_refresh_interval_cmd); + install_element (ISIS_NODE, &no_lsp_refresh_interval_arg_cmd); + install_element (ISIS_NODE, &lsp_refresh_interval_l1_cmd); + install_element (ISIS_NODE, &no_lsp_refresh_interval_l1_cmd); + install_element (ISIS_NODE, &no_lsp_refresh_interval_l1_arg_cmd); + install_element (ISIS_NODE, &lsp_refresh_interval_l2_cmd); + install_element (ISIS_NODE, &no_lsp_refresh_interval_l2_cmd); + install_element (ISIS_NODE, &no_lsp_refresh_interval_l2_arg_cmd); + + install_element (ISIS_NODE, &area_passwd_md5_cmd); + install_element (ISIS_NODE, &area_passwd_md5_snpauth_cmd); + install_element (ISIS_NODE, &area_passwd_clear_cmd); + install_element (ISIS_NODE, &area_passwd_clear_snpauth_cmd); + install_element (ISIS_NODE, &no_area_passwd_cmd); +} diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index 125a2f63d3..569ff70d8d 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -49,6 +49,7 @@ #include "isisd/isis_lsp.h" #include "isisd/isis_route.h" #include "isisd/isis_zebra.h" +#include "isisd/isis_te.h" struct zclient *zclient = NULL; @@ -61,6 +62,13 @@ isis_router_id_update_zebra (int command, struct zclient *zclient, struct listnode *node; struct prefix router_id; + /* + * If ISIS TE is enable, TE Router ID is set through specific command. + * See mpls_te_router_addr() command in isis_te.c + */ + if (IS_MPLS_TE(isisMplsTE)) + return 0; + zebra_router_id_update_read (zclient->ibuf, &router_id); if (isis->router_id == router_id.u.prefix4.s_addr) return 0; @@ -228,6 +236,23 @@ isis_zebra_if_address_del (int command, struct zclient *client, return 0; } +static int +isis_zebra_link_params (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct interface *ifp; + + ifp = zebra_interface_link_params_read (zclient->ibuf); + + if (ifp == NULL) + return 0; + + /* Update TE TLV */ + isis_mpls_te_update(ifp); + + return 0; +} + static void isis_zebra_route_add_ipv4 (struct prefix *prefix, struct isis_route_info *route_info) @@ -278,12 +303,12 @@ isis_zebra_route_add_ipv4 (struct prefix *prefix, /* FIXME: can it be ? */ if (nexthop->ip.s_addr != INADDR_ANY) { - stream_putc (stream, ZEBRA_NEXTHOP_IPV4); + stream_putc (stream, NEXTHOP_TYPE_IPV4); stream_put_in_addr (stream, &nexthop->ip); } else { - stream_putc (stream, ZEBRA_NEXTHOP_IFINDEX); + stream_putc (stream, NEXTHOP_TYPE_IFINDEX); stream_putl (stream, nexthop->ifindex); } } @@ -333,7 +358,7 @@ isis_zebra_route_add_ipv6 (struct prefix *prefix, { struct zapi_ipv6 api; struct in6_addr **nexthop_list; - unsigned int *ifindex_list; + ifindex_t *ifindex_list; struct isis_nexthop6 *nexthop6; int i, size; struct listnode *node; @@ -370,7 +395,7 @@ isis_zebra_route_add_ipv6 (struct prefix *prefix, /* allocate memory for ifindex_list */ size = sizeof (unsigned int) * listcount (route_info->nexthops6); - ifindex_list = (unsigned int *) XMALLOC (MTYPE_ISIS_TMP, size); + ifindex_list = (ifindex_t *) XMALLOC (MTYPE_ISIS_TMP, size); if (!ifindex_list) { zlog_err ("isis_zebra_add_route_ipv6: out of memory!"); @@ -420,7 +445,7 @@ isis_zebra_route_del_ipv6 (struct prefix *prefix, { struct zapi_ipv6 api; struct in6_addr **nexthop_list; - unsigned int *ifindex_list; + ifindex_t *ifindex_list; struct isis_nexthop6 *nexthop6; int i, size; struct listnode *node; @@ -451,7 +476,7 @@ isis_zebra_route_del_ipv6 (struct prefix *prefix, /* allocate memory for ifindex_list */ size = sizeof (unsigned int) * listcount (route_info->nexthops6); - ifindex_list = (unsigned int *) XMALLOC (MTYPE_ISIS_TMP, size); + ifindex_list = (ifindex_t *) XMALLOC (MTYPE_ISIS_TMP, size); if (!ifindex_list) { zlog_err ("isis_zebra_route_del_ipv6: out of memory!"); @@ -680,6 +705,7 @@ isis_zebra_init (struct thread_master *master) zclient->interface_down = isis_zebra_if_state_down; zclient->interface_address_add = isis_zebra_if_address_add; zclient->interface_address_delete = isis_zebra_if_address_del; + zclient->interface_link_params = isis_zebra_link_params; zclient->ipv4_route_add = isis_zebra_read_ipv4; zclient->ipv4_route_delete = isis_zebra_read_ipv4; zclient->redistribute_route_ipv4_add = isis_zebra_read_ipv4; diff --git a/isisd/isisd.c b/isisd/isisd.c index 228d2bcb31..5a90115127 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -54,6 +54,7 @@ #include "isisd/isis_route.h" #include "isisd/isis_zebra.h" #include "isisd/isis_events.h" +#include "isisd/isis_te.h" #ifdef TOPOLOGY_GENERATE #include "spgrid.h" @@ -98,6 +99,7 @@ isis_new (unsigned long process_id) * uncomment the next line for full debugs */ /* isis->debugs = 0xFFFF; */ + isisMplsTE.status = disable; /* Only support TE metric */ } struct isis_area * @@ -781,14 +783,16 @@ print_debug (struct vty *vty, int flags, int onoff) } DEFUN (show_debugging, - show_debugging_cmd, + show_debugging_isis_cmd, "show debugging isis", SHOW_STR "State of each debugging option\n" ISIS_STR) { - vty_out (vty, "IS-IS:%s", VTY_NEWLINE); - print_debug (vty, isis->debugs, 1); + if (isis->debugs) { + vty_out (vty, "IS-IS:%s", VTY_NEWLINE); + print_debug (vty, isis->debugs, 1); + } return CMD_SUCCESS; } @@ -1612,1221 +1616,252 @@ DEFUN (no_net, return area_clear_net_title (vty, argv[0]); } -static -int area_set_lsp_mtu(struct vty *vty, struct isis_area *area, unsigned int lsp_mtu) +void isis_area_lsp_mtu_set(struct isis_area *area, unsigned int lsp_mtu) { - struct isis_circuit *circuit; - struct listnode *node; - - for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) - { - if(circuit->state != C_STATE_INIT && circuit->state != C_STATE_UP) - continue; - if(lsp_mtu > isis_circuit_pdu_size(circuit)) - { - vty_out(vty, "ISIS area contains circuit %s, which has a maximum PDU size of %zu.%s", - circuit->interface->name, isis_circuit_pdu_size(circuit), - VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - } - area->lsp_mtu = lsp_mtu; lsp_regenerate_schedule(area, IS_LEVEL_1_AND_2, 1); - - return CMD_SUCCESS; -} - -DEFUN (area_lsp_mtu, - area_lsp_mtu_cmd, - "lsp-mtu <128-4352>", - "Configure the maximum size of generated LSPs\n" - "Maximum size of generated LSPs\n") -{ - struct isis_area *area; - - area = vty->index; - if (!area) - { - vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); - return CMD_ERR_NO_MATCH; - } - - unsigned int lsp_mtu; - - VTY_GET_INTEGER_RANGE("lsp-mtu", lsp_mtu, argv[0], 128, 4352); - - return area_set_lsp_mtu(vty, area, lsp_mtu); -} - -DEFUN(no_area_lsp_mtu, - no_area_lsp_mtu_cmd, - "no lsp-mtu", - NO_STR - "Configure the maximum size of generated LSPs\n") -{ - struct isis_area *area; - - area = vty->index; - if (!area) - { - vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); - return CMD_ERR_NO_MATCH; - } - - return area_set_lsp_mtu(vty, area, DEFAULT_LSP_MTU); -} - -ALIAS(no_area_lsp_mtu, - no_area_lsp_mtu_arg_cmd, - "no lsp-mtu <128-4352>", - NO_STR - "Configure the maximum size of generated LSPs\n" - "Maximum size of generated LSPs\n"); - -DEFUN (area_passwd_md5, - area_passwd_md5_cmd, - "area-password md5 WORD", - "Configure the authentication password for an area\n" - "Authentication type\n" - "Area password\n") -{ - struct isis_area *area; - int len; - - area = vty->index; - - if (!area) - { - vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); - return CMD_ERR_NO_MATCH; - } - - len = strlen (argv[0]); - if (len > 254) - { - vty_out (vty, "Too long area password (>254)%s", VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - area->area_passwd.len = (u_char) len; - area->area_passwd.type = ISIS_PASSWD_TYPE_HMAC_MD5; - strncpy ((char *)area->area_passwd.passwd, argv[0], 255); - - if (argc > 1) - { - SET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_SEND); - if (strncmp(argv[1], "v", 1) == 0) - SET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV); - else - UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV); - } - else - { - UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_SEND); - UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV); - } - lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); - - return CMD_SUCCESS; -} - -ALIAS (area_passwd_md5, - area_passwd_md5_snpauth_cmd, - "area-password md5 WORD authenticate snp (send-only|validate)", - "Configure the authentication password for an area\n" - "Authentication type\n" - "Area password\n" - "Authentication\n" - "SNP PDUs\n" - "Send but do not check PDUs on receiving\n" - "Send and check PDUs on receiving\n") - -DEFUN (area_passwd_clear, - area_passwd_clear_cmd, - "area-password clear WORD", - "Configure the authentication password for an area\n" - "Authentication type\n" - "Area password\n") -{ - struct isis_area *area; - int len; - - area = vty->index; - - if (!area) - { - vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); - return CMD_ERR_NO_MATCH; - } - - len = strlen (argv[0]); - if (len > 254) - { - vty_out (vty, "Too long area password (>254)%s", VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - area->area_passwd.len = (u_char) len; - area->area_passwd.type = ISIS_PASSWD_TYPE_CLEARTXT; - strncpy ((char *)area->area_passwd.passwd, argv[0], 255); - - if (argc > 1) - { - SET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_SEND); - if (strncmp(argv[1], "v", 1) == 0) - SET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV); - else - UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV); - } - else - { - UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_SEND); - UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV); - } - lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); - - return CMD_SUCCESS; -} - -ALIAS (area_passwd_clear, - area_passwd_clear_snpauth_cmd, - "area-password clear WORD authenticate snp (send-only|validate)", - "Configure the authentication password for an area\n" - "Authentication type\n" - "Area password\n" - "Authentication\n" - "SNP PDUs\n" - "Send but do not check PDUs on receiving\n" - "Send and check PDUs on receiving\n") - -DEFUN (no_area_passwd, - no_area_passwd_cmd, - "no area-password", - NO_STR - "Configure the authentication password for an area\n") -{ - struct isis_area *area; - - area = vty->index; - - if (!area) - { - vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); - return CMD_ERR_NO_MATCH; - } - - memset (&area->area_passwd, 0, sizeof (struct isis_passwd)); - lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); - - return CMD_SUCCESS; -} - -DEFUN (domain_passwd_md5, - domain_passwd_md5_cmd, - "domain-password md5 WORD", - "Set the authentication password for a routing domain\n" - "Authentication type\n" - "Routing domain password\n") -{ - struct isis_area *area; - int len; - - area = vty->index; - - if (!area) - { - vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); - return CMD_ERR_NO_MATCH; - } - - len = strlen (argv[0]); - if (len > 254) - { - vty_out (vty, "Too long area password (>254)%s", VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - area->domain_passwd.len = (u_char) len; - area->domain_passwd.type = ISIS_PASSWD_TYPE_HMAC_MD5; - strncpy ((char *)area->domain_passwd.passwd, argv[0], 255); - - if (argc > 1) - { - SET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_SEND); - if (strncmp(argv[1], "v", 1) == 0) - SET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV); - else - UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV); - } - else - { - UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_SEND); - UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV); - } - lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); - - return CMD_SUCCESS; -} - -ALIAS (domain_passwd_md5, - domain_passwd_md5_snpauth_cmd, - "domain-password md5 WORD authenticate snp (send-only|validate)", - "Set the authentication password for a routing domain\n" - "Authentication type\n" - "Routing domain password\n" - "Authentication\n" - "SNP PDUs\n" - "Send but do not check PDUs on receiving\n" - "Send and check PDUs on receiving\n") - -DEFUN (domain_passwd_clear, - domain_passwd_clear_cmd, - "domain-password clear WORD", - "Set the authentication password for a routing domain\n" - "Authentication type\n" - "Routing domain password\n") -{ - struct isis_area *area; - int len; - - area = vty->index; - - if (!area) - { - vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); - return CMD_ERR_NO_MATCH; - } - - len = strlen (argv[0]); - if (len > 254) - { - vty_out (vty, "Too long area password (>254)%s", VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - area->domain_passwd.len = (u_char) len; - area->domain_passwd.type = ISIS_PASSWD_TYPE_CLEARTXT; - strncpy ((char *)area->domain_passwd.passwd, argv[0], 255); - - if (argc > 1) - { - SET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_SEND); - if (strncmp(argv[1], "v", 1) == 0) - SET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV); - else - UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV); - } - else - { - UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_SEND); - UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV); - } - lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); - - return CMD_SUCCESS; -} - -ALIAS (domain_passwd_clear, - domain_passwd_clear_snpauth_cmd, - "domain-password clear WORD authenticate snp (send-only|validate)", - "Set the authentication password for a routing domain\n" - "Authentication type\n" - "Routing domain password\n" - "Authentication\n" - "SNP PDUs\n" - "Send but do not check PDUs on receiving\n" - "Send and check PDUs on receiving\n") - -DEFUN (no_domain_passwd, - no_domain_passwd_cmd, - "no domain-password", - NO_STR - "Set the authentication password for a routing domain\n") -{ - struct isis_area *area; - - area = vty->index; - - if (!area) - { - vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); - return CMD_ERR_NO_MATCH; - } - - memset (&area->domain_passwd, 0, sizeof (struct isis_passwd)); - lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); - - return CMD_SUCCESS; -} - -DEFUN (is_type, - is_type_cmd, - "is-type (level-1|level-1-2|level-2-only)", - "IS Level for this routing process (OSI only)\n" - "Act as a station router only\n" - "Act as both a station router and an area router\n" - "Act as an area router only\n") -{ - struct isis_area *area; - int type; - - area = vty->index; - - if (!area) - { - vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); - return CMD_ERR_NO_MATCH; - } - - type = string2circuit_t (argv[0]); - if (!type) - { - vty_out (vty, "Unknown IS level %s", VTY_NEWLINE); - return CMD_SUCCESS; - } - - isis_event_system_type_change (area, type); - - return CMD_SUCCESS; -} - -DEFUN (no_is_type, - no_is_type_cmd, - "no is-type (level-1|level-1-2|level-2-only)", - NO_STR - "IS Level for this routing process (OSI only)\n" - "Act as a station router only\n" - "Act as both a station router and an area router\n" - "Act as an area router only\n") -{ - struct isis_area *area; - int type; - - area = vty->index; - assert (area); - - /* - * Put the is-type back to defaults: - * - level-1-2 on first area - * - level-1 for the rest - */ - if (listgetdata (listhead (isis->area_list)) == area) - type = IS_LEVEL_1_AND_2; - else - type = IS_LEVEL_1; - - isis_event_system_type_change (area, type); - - return CMD_SUCCESS; } static int -set_lsp_gen_interval (struct vty *vty, struct isis_area *area, - uint16_t interval, int level) +isis_area_passwd_set(struct isis_area *area, int level, u_char passwd_type, + const char *passwd, u_char snp_auth) { - int lvl; + struct isis_passwd *dest; + struct isis_passwd modified; + int len; - for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl) + assert((level == IS_LEVEL_1) || (level == IS_LEVEL_2)); + dest = (level == IS_LEVEL_1) ? &area->area_passwd : &area->domain_passwd; + memset(&modified, 0, sizeof(modified)); + + if (passwd_type != ISIS_PASSWD_TYPE_UNUSED) { - if (!(lvl & level)) - continue; + if (!passwd) + return -1; - if (interval >= area->lsp_refresh[lvl-1]) - { - vty_out (vty, "LSP gen interval %us must be less than " - "the LSP refresh interval %us%s", - interval, area->lsp_refresh[lvl-1], VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } + len = strlen(passwd); + if (len > 254) + return -1; + + modified.len = len; + strncpy((char*)modified.passwd, passwd, 255); + modified.type = passwd_type; + modified.snp_auth = snp_auth; } - for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl) + if (memcmp(&modified, dest, sizeof(modified))) { - if (!(lvl & level)) - continue; - area->lsp_gen_interval[lvl-1] = interval; + memcpy(dest, &modified, sizeof(modified)); + lsp_regenerate_schedule(area, IS_LEVEL_1|IS_LEVEL_2, 1); } - return CMD_SUCCESS; + return 0; } -DEFUN (lsp_gen_interval, - lsp_gen_interval_cmd, - "lsp-gen-interval <1-120>", - "Minimum interval between regenerating same LSP\n" - "Minimum interval in seconds\n") +int +isis_area_passwd_unset (struct isis_area *area, int level) { - struct isis_area *area; - uint16_t interval; - int level; - - area = vty->index; - interval = atoi (argv[0]); - level = IS_LEVEL_1 | IS_LEVEL_2; - return set_lsp_gen_interval (vty, area, interval, level); + return isis_area_passwd_set (area, level, ISIS_PASSWD_TYPE_UNUSED, NULL, 0); } -DEFUN (no_lsp_gen_interval, - no_lsp_gen_interval_cmd, - "no lsp-gen-interval", - NO_STR - "Minimum interval between regenerating same LSP\n") +int +isis_area_passwd_cleartext_set (struct isis_area *area, int level, + const char *passwd, u_char snp_auth) { - struct isis_area *area; - uint16_t interval; - int level; - - area = vty->index; - interval = DEFAULT_MIN_LSP_GEN_INTERVAL; - level = IS_LEVEL_1 | IS_LEVEL_2; - return set_lsp_gen_interval (vty, area, interval, level); + return isis_area_passwd_set (area, level, ISIS_PASSWD_TYPE_CLEARTXT, + passwd, snp_auth); } -ALIAS (no_lsp_gen_interval, - no_lsp_gen_interval_arg_cmd, - "no lsp-gen-interval <1-120>", - NO_STR - "Minimum interval between regenerating same LSP\n" - "Minimum interval in seconds\n") - -DEFUN (lsp_gen_interval_l1, - lsp_gen_interval_l1_cmd, - "lsp-gen-interval level-1 <1-120>", - "Minimum interval between regenerating same LSP\n" - "Set interval for level 1 only\n" - "Minimum interval in seconds\n") +int +isis_area_passwd_hmac_md5_set (struct isis_area *area, int level, + const char *passwd, u_char snp_auth) { - struct isis_area *area; - uint16_t interval; - int level; - - area = vty->index; - interval = atoi (argv[0]); - level = IS_LEVEL_1; - return set_lsp_gen_interval (vty, area, interval, level); + return isis_area_passwd_set (area, level, ISIS_PASSWD_TYPE_HMAC_MD5, + passwd, snp_auth); } -DEFUN (no_lsp_gen_interval_l1, - no_lsp_gen_interval_l1_cmd, - "no lsp-gen-interval level-1", - NO_STR - "Minimum interval between regenerating same LSP\n" - "Set interval for level 1 only\n") +static void +area_resign_level (struct isis_area *area, int level) { - struct isis_area *area; - uint16_t interval; - int level; + if (area->lspdb[level - 1]) + { + lsp_db_destroy (area->lspdb[level - 1]); + area->lspdb[level - 1] = NULL; + } + if (area->spftree[level - 1]) + { + isis_spftree_del (area->spftree[level - 1]); + area->spftree[level - 1] = NULL; + } +#ifdef HAVE_IPV6 + if (area->spftree6[level - 1]) + { + isis_spftree_del (area->spftree6[level - 1]); + area->spftree6[level - 1] = NULL; + } +#endif + if (area->route_table[level - 1]) + { + route_table_finish (area->route_table[level - 1]); + area->route_table[level - 1] = NULL; + } +#ifdef HAVE_IPV6 + if (area->route_table6[level - 1]) + { + route_table_finish (area->route_table6[level - 1]); + area->route_table6[level - 1] = NULL; + } +#endif /* HAVE_IPV6 */ - area = vty->index; - interval = DEFAULT_MIN_LSP_GEN_INTERVAL; - level = IS_LEVEL_1; - return set_lsp_gen_interval (vty, area, interval, level); + sched_debug("ISIS (%s): Resigned from L%d - canceling LSP regeneration timer.", + area->area_tag, level); + THREAD_TIMER_OFF (area->t_lsp_refresh[level - 1]); + area->lsp_regenerate_pending[level - 1] = 0; } -ALIAS (no_lsp_gen_interval_l1, - no_lsp_gen_interval_l1_arg_cmd, - "no lsp-gen-interval level-1 <1-120>", - NO_STR - "Minimum interval between regenerating same LSP\n" - "Set interval for level 1 only\n" - "Minimum interval in seconds\n") - -DEFUN (lsp_gen_interval_l2, - lsp_gen_interval_l2_cmd, - "lsp-gen-interval level-2 <1-120>", - "Minimum interval between regenerating same LSP\n" - "Set interval for level 2 only\n" - "Minimum interval in seconds\n") +void +isis_area_is_type_set(struct isis_area *area, int is_type) { - struct isis_area *area; - uint16_t interval; - int level; - - area = vty->index; - interval = atoi (argv[0]); - level = IS_LEVEL_2; - return set_lsp_gen_interval (vty, area, interval, level); -} - -DEFUN (no_lsp_gen_interval_l2, - no_lsp_gen_interval_l2_cmd, - "no lsp-gen-interval level-2", - NO_STR - "Minimum interval between regenerating same LSP\n" - "Set interval for level 2 only\n") -{ - struct isis_area *area; - uint16_t interval; - int level; - - area = vty->index; - interval = DEFAULT_MIN_LSP_GEN_INTERVAL; - level = IS_LEVEL_2; - return set_lsp_gen_interval (vty, area, interval, level); -} - -ALIAS (no_lsp_gen_interval_l2, - no_lsp_gen_interval_l2_arg_cmd, - "no lsp-gen-interval level-2 <1-120>", - NO_STR - "Minimum interval between regenerating same LSP\n" - "Set interval for level 2 only\n" - "Minimum interval in seconds\n") - -static int -validate_metric_style_narrow (struct vty *vty, struct isis_area *area) -{ - struct isis_circuit *circuit; struct listnode *node; - - if (! vty) - return CMD_ERR_AMBIGUOUS; + struct isis_circuit *circuit; - if (! area) - { - vty_out (vty, "ISIS area is invalid%s", VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } + if (isis->debugs & DEBUG_EVENTS) + zlog_debug ("ISIS-Evt (%s) system type change %s -> %s", area->area_tag, + circuit_t2string (area->is_type), circuit_t2string (is_type)); - for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit)) - { - if ((area->is_type & IS_LEVEL_1) && - (circuit->is_type & IS_LEVEL_1) && - (circuit->te_metric[0] > MAX_NARROW_LINK_METRIC)) - { - vty_out (vty, "ISIS circuit %s metric is invalid%s", - circuit->interface->name, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - if ((area->is_type & IS_LEVEL_2) && - (circuit->is_type & IS_LEVEL_2) && - (circuit->te_metric[1] > MAX_NARROW_LINK_METRIC)) - { - vty_out (vty, "ISIS circuit %s metric is invalid%s", - circuit->interface->name, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - } + if (area->is_type == is_type) + return; /* No change */ - return CMD_SUCCESS; -} + switch (area->is_type) + { + case IS_LEVEL_1: + if (is_type == IS_LEVEL_2) + area_resign_level (area, IS_LEVEL_1); -DEFUN (metric_style, - metric_style_cmd, - "metric-style (narrow|transition|wide)", - "Use old-style (ISO 10589) or new-style packet formats\n" - "Use old style of TLVs with narrow metric\n" - "Send and accept both styles of TLVs during transition\n" - "Use new style of TLVs to carry wider metric\n") -{ - struct isis_area *area; - int ret; + if (area->lspdb[1] == NULL) + area->lspdb[1] = lsp_db_init (); + if (area->route_table[1] == NULL) + area->route_table[1] = route_table_init (); +#ifdef HAVE_IPV6 + if (area->route_table6[1] == NULL) + area->route_table6[1] = route_table_init (); +#endif /* HAVE_IPV6 */ + break; - area = vty->index; - assert (area); + case IS_LEVEL_1_AND_2: + if (is_type == IS_LEVEL_1) + area_resign_level (area, IS_LEVEL_2); + else + area_resign_level (area, IS_LEVEL_1); + break; - if (strncmp (argv[0], "w", 1) == 0) - { - area->newmetric = 1; - area->oldmetric = 0; - } - else - { - ret = validate_metric_style_narrow (vty, area); - if (ret != CMD_SUCCESS) - return ret; + case IS_LEVEL_2: + if (is_type == IS_LEVEL_1) + area_resign_level (area, IS_LEVEL_2); - if (strncmp (argv[0], "t", 1) == 0) - { - area->newmetric = 1; - area->oldmetric = 1; - } - else if (strncmp (argv[0], "n", 1) == 0) - { - area->newmetric = 0; - area->oldmetric = 1; - } - } + if (area->lspdb[0] == NULL) + area->lspdb[0] = lsp_db_init (); + if (area->route_table[0] == NULL) + area->route_table[0] = route_table_init (); +#ifdef HAVE_IPV6 + if (area->route_table6[0] == NULL) + area->route_table6[0] = route_table_init (); +#endif /* HAVE_IPV6 */ + break; - return CMD_SUCCESS; -} + default: + break; + } -DEFUN (no_metric_style, - no_metric_style_cmd, - "no metric-style", - NO_STR - "Use old-style (ISO 10589) or new-style packet formats\n") -{ - struct isis_area *area; - int ret; + area->is_type = is_type; - area = vty->index; - assert (area); + /* override circuit's is_type */ + if (area->is_type != IS_LEVEL_1_AND_2) + { + for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit)) + isis_circuit_is_type_set (circuit, is_type); + } - ret = validate_metric_style_narrow (vty, area); - if (ret != CMD_SUCCESS) - return ret; + spftree_area_init (area); - /* Default is narrow metric. */ - area->newmetric = 0; - area->oldmetric = 1; - - return CMD_SUCCESS; -} - -DEFUN (set_overload_bit, - set_overload_bit_cmd, - "set-overload-bit", - "Set overload bit to avoid any transit traffic\n" - "Set overload bit\n") -{ - struct isis_area *area; - - area = vty->index; - assert (area); - - area->overload_bit = LSPBIT_OL; + if (is_type & IS_LEVEL_1) + lsp_generate (area, IS_LEVEL_1); + if (is_type & IS_LEVEL_2) + lsp_generate (area, IS_LEVEL_2); lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); - return CMD_SUCCESS; + return; } -DEFUN (no_set_overload_bit, - no_set_overload_bit_cmd, - "no set-overload-bit", - "Reset overload bit to accept transit traffic\n" - "Reset overload bit\n") +void isis_area_metricstyle_set(struct isis_area *area, bool old_metric, + bool new_metric) { - struct isis_area *area; - - area = vty->index; - assert (area); - - area->overload_bit = 0; - lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); - - return CMD_SUCCESS; -} - -DEFUN (set_attached_bit, - set_attached_bit_cmd, - "set-attached-bit", - "Set attached bit to identify as L1/L2 router for inter-area traffic\n" - "Set attached bit\n") -{ - struct isis_area *area; - - area = vty->index; - assert (area); - - area->attached_bit = LSPBIT_ATT; - lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); - - return CMD_SUCCESS; -} - -DEFUN (no_set_attached_bit, - no_set_attached_bit_cmd, - "no set-attached-bit", - "Reset attached bit\n") -{ - struct isis_area *area; - - area = vty->index; - assert (area); - - area->attached_bit = 0; - lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); - - return CMD_SUCCESS; -} - -DEFUN (dynamic_hostname, - dynamic_hostname_cmd, - "hostname dynamic", - "Dynamic hostname for IS-IS\n" - "Dynamic hostname\n") -{ - struct isis_area *area; - - area = vty->index; - assert (area); - - if (!area->dynhostname) - { - area->dynhostname = 1; - lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 0); - } - - return CMD_SUCCESS; -} - -DEFUN (no_dynamic_hostname, - no_dynamic_hostname_cmd, - "no hostname dynamic", - NO_STR - "Dynamic hostname for IS-IS\n" - "Dynamic hostname\n") -{ - struct isis_area *area; - - area = vty->index; - assert (area); - - if (area->dynhostname) + if (area->oldmetric != old_metric + || area->newmetric != new_metric) { - area->dynhostname = 0; - lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 0); + area->oldmetric = old_metric; + area->newmetric = new_metric; + lsp_regenerate_schedule(area, IS_LEVEL_1 | IS_LEVEL_2, 1); } - - return CMD_SUCCESS; } -DEFUN (spf_interval, - spf_interval_cmd, - "spf-interval <1-120>", - "Minimum interval between SPF calculations\n" - "Minimum interval between consecutive SPFs in seconds\n") +void isis_area_overload_bit_set(struct isis_area *area, bool overload_bit) { - struct isis_area *area; - u_int16_t interval; + char new_overload_bit = overload_bit ? LSPBIT_OL : 0; - area = vty->index; - interval = atoi (argv[0]); - area->min_spf_interval[0] = interval; - area->min_spf_interval[1] = interval; - - return CMD_SUCCESS; -} - -DEFUN (no_spf_interval, - no_spf_interval_cmd, - "no spf-interval", - NO_STR - "Minimum interval between SPF calculations\n") -{ - struct isis_area *area; - - area = vty->index; - - area->min_spf_interval[0] = MINIMUM_SPF_INTERVAL; - area->min_spf_interval[1] = MINIMUM_SPF_INTERVAL; - - return CMD_SUCCESS; -} - -ALIAS (no_spf_interval, - no_spf_interval_arg_cmd, - "no spf-interval <1-120>", - NO_STR - "Minimum interval between SPF calculations\n" - "Minimum interval between consecutive SPFs in seconds\n") - -DEFUN (spf_interval_l1, - spf_interval_l1_cmd, - "spf-interval level-1 <1-120>", - "Minimum interval between SPF calculations\n" - "Set interval for level 1 only\n" - "Minimum interval between consecutive SPFs in seconds\n") -{ - struct isis_area *area; - u_int16_t interval; - - area = vty->index; - interval = atoi (argv[0]); - area->min_spf_interval[0] = interval; - - return CMD_SUCCESS; -} - -DEFUN (no_spf_interval_l1, - no_spf_interval_l1_cmd, - "no spf-interval level-1", - NO_STR - "Minimum interval between SPF calculations\n" - "Set interval for level 1 only\n") -{ - struct isis_area *area; - - area = vty->index; - - area->min_spf_interval[0] = MINIMUM_SPF_INTERVAL; - - return CMD_SUCCESS; -} - -ALIAS (no_spf_interval, - no_spf_interval_l1_arg_cmd, - "no spf-interval level-1 <1-120>", - NO_STR - "Minimum interval between SPF calculations\n" - "Set interval for level 1 only\n" - "Minimum interval between consecutive SPFs in seconds\n") - -DEFUN (spf_interval_l2, - spf_interval_l2_cmd, - "spf-interval level-2 <1-120>", - "Minimum interval between SPF calculations\n" - "Set interval for level 2 only\n" - "Minimum interval between consecutive SPFs in seconds\n") -{ - struct isis_area *area; - u_int16_t interval; - - area = vty->index; - interval = atoi (argv[0]); - area->min_spf_interval[1] = interval; - - return CMD_SUCCESS; -} - -DEFUN (no_spf_interval_l2, - no_spf_interval_l2_cmd, - "no spf-interval level-2", - NO_STR - "Minimum interval between SPF calculations\n" - "Set interval for level 2 only\n") -{ - struct isis_area *area; - - area = vty->index; - - area->min_spf_interval[1] = MINIMUM_SPF_INTERVAL; - - return CMD_SUCCESS; -} - -ALIAS (no_spf_interval, - no_spf_interval_l2_arg_cmd, - "no spf-interval level-2 <1-120>", - NO_STR - "Minimum interval between SPF calculations\n" - "Set interval for level 2 only\n" - "Minimum interval between consecutive SPFs in seconds\n") - -static int -set_lsp_max_lifetime (struct vty *vty, struct isis_area *area, - uint16_t interval, int level) -{ - int lvl; - int set_refresh_interval[ISIS_LEVELS] = {0, 0}; - uint16_t refresh_interval; - - refresh_interval = interval - 300; - - for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++) + if (new_overload_bit != area->overload_bit) { - if (!(lvl & level)) - continue; - if (refresh_interval < area->lsp_refresh[lvl-1]) - { - vty_out (vty, "Level %d Max LSP lifetime %us must be 300s greater than " - "the configured LSP refresh interval %us%s", - lvl, interval, area->lsp_refresh[lvl-1], VTY_NEWLINE); - vty_out (vty, "Automatically reducing level %d LSP refresh interval " - "to %us%s", lvl, refresh_interval, VTY_NEWLINE); - set_refresh_interval[lvl-1] = 1; - - if (refresh_interval <= area->lsp_gen_interval[lvl-1]) - { - vty_out (vty, "LSP refresh interval %us must be greater than " - "the configured LSP gen interval %us%s", - refresh_interval, area->lsp_gen_interval[lvl-1], - VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - } + area->overload_bit = new_overload_bit; + lsp_regenerate_schedule(area, IS_LEVEL_1 | IS_LEVEL_2, 1); } +} - for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++) +void isis_area_attached_bit_set(struct isis_area *area, bool attached_bit) +{ + char new_attached_bit = attached_bit ? LSPBIT_ATT : 0; + + if (new_attached_bit != area->attached_bit) { - if (!(lvl & level)) - continue; - area->max_lsp_lifetime[lvl-1] = interval; - /* Automatically reducing lsp_refresh_interval to interval - 300 */ - if (set_refresh_interval[lvl-1]) - area->lsp_refresh[lvl-1] = refresh_interval; + area->attached_bit = new_attached_bit; + lsp_regenerate_schedule(area, IS_LEVEL_1 | IS_LEVEL_2, 1); } - - lsp_regenerate_schedule (area, level, 1); - - return CMD_SUCCESS; } -DEFUN (max_lsp_lifetime, - max_lsp_lifetime_cmd, - "max-lsp-lifetime <350-65535>", - "Maximum LSP lifetime\n" - "LSP lifetime in seconds\n") +void isis_area_dynhostname_set(struct isis_area *area, bool dynhostname) { - struct isis_area *area; - uint16_t interval; - int level; - - area = vty->index; - interval = atoi (argv[0]); - level = IS_LEVEL_1 | IS_LEVEL_2; - return set_lsp_max_lifetime (vty, area, interval, level); -} - -DEFUN (no_max_lsp_lifetime, - no_max_lsp_lifetime_cmd, - "no max-lsp-lifetime", - NO_STR - "LSP lifetime in seconds\n") -{ - struct isis_area *area; - uint16_t interval; - int level; - - area = vty->index; - interval = DEFAULT_LSP_LIFETIME; - level = IS_LEVEL_1 | IS_LEVEL_2; - return set_lsp_max_lifetime (vty, area, interval, level); -} - -ALIAS (no_max_lsp_lifetime, - no_max_lsp_lifetime_arg_cmd, - "no max-lsp-lifetime <350-65535>", - NO_STR - "Maximum LSP lifetime\n" - "LSP lifetime in seconds\n") - -DEFUN (max_lsp_lifetime_l1, - max_lsp_lifetime_l1_cmd, - "max-lsp-lifetime level-1 <350-65535>", - "Maximum LSP lifetime for Level 1 only\n" - "LSP lifetime for Level 1 only in seconds\n") -{ - struct isis_area *area; - uint16_t interval; - int level; - - area = vty->index; - interval = atoi (argv[0]); - level = IS_LEVEL_1; - return set_lsp_max_lifetime (vty, area, interval, level); -} - -DEFUN (no_max_lsp_lifetime_l1, - no_max_lsp_lifetime_l1_cmd, - "no max-lsp-lifetime level-1", - NO_STR - "LSP lifetime for Level 1 only in seconds\n") -{ - struct isis_area *area; - uint16_t interval; - int level; - - area = vty->index; - interval = DEFAULT_LSP_LIFETIME; - level = IS_LEVEL_1; - return set_lsp_max_lifetime (vty, area, interval, level); -} - -ALIAS (no_max_lsp_lifetime_l1, - no_max_lsp_lifetime_l1_arg_cmd, - "no max-lsp-lifetime level-1 <350-65535>", - NO_STR - "Maximum LSP lifetime for Level 1 only\n" - "LSP lifetime for Level 1 only in seconds\n") - -DEFUN (max_lsp_lifetime_l2, - max_lsp_lifetime_l2_cmd, - "max-lsp-lifetime level-2 <350-65535>", - "Maximum LSP lifetime for Level 2 only\n" - "LSP lifetime for Level 2 only in seconds\n") -{ - struct isis_area *area; - uint16_t interval; - int level; - - area = vty->index; - interval = atoi (argv[0]); - level = IS_LEVEL_2; - return set_lsp_max_lifetime (vty, area, interval, level); -} - -DEFUN (no_max_lsp_lifetime_l2, - no_max_lsp_lifetime_l2_cmd, - "no max-lsp-lifetime level-2", - NO_STR - "LSP lifetime for Level 2 only in seconds\n") -{ - struct isis_area *area; - uint16_t interval; - int level; - - area = vty->index; - interval = DEFAULT_LSP_LIFETIME; - level = IS_LEVEL_2; - return set_lsp_max_lifetime (vty, area, interval, level); -} - -ALIAS (no_max_lsp_lifetime_l2, - no_max_lsp_lifetime_l2_arg_cmd, - "no max-lsp-lifetime level-2 <350-65535>", - NO_STR - "Maximum LSP lifetime for Level 2 only\n" - "LSP lifetime for Level 2 only in seconds\n") - -static int -set_lsp_refresh_interval (struct vty *vty, struct isis_area *area, - uint16_t interval, int level) -{ - int lvl; - - for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl) + if (area->dynhostname != dynhostname) { - if (!(lvl & level)) - continue; - if (interval <= area->lsp_gen_interval[lvl-1]) - { - vty_out (vty, "LSP refresh interval %us must be greater than " - "the configured LSP gen interval %us%s", - interval, area->lsp_gen_interval[lvl-1], - VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - if (interval > (area->max_lsp_lifetime[lvl-1] - 300)) - { - vty_out (vty, "LSP refresh interval %us must be less than " - "the configured LSP lifetime %us less 300%s", - interval, area->max_lsp_lifetime[lvl-1], - VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } + area->dynhostname = dynhostname; + lsp_regenerate_schedule(area, IS_LEVEL_1 | IS_LEVEL_2, 0); } - - for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl) - { - if (!(lvl & level)) - continue; - area->lsp_refresh[lvl-1] = interval; - } - lsp_regenerate_schedule (area, level, 1); - - return CMD_SUCCESS; } -DEFUN (lsp_refresh_interval, - lsp_refresh_interval_cmd, - "lsp-refresh-interval <1-65235>", - "LSP refresh interval\n" - "LSP refresh interval in seconds\n") +void +isis_area_max_lsp_lifetime_set(struct isis_area *area, int level, + uint16_t max_lsp_lifetime) { - struct isis_area *area; - uint16_t interval; - int level; + assert((level == IS_LEVEL_1) || (level == IS_LEVEL_2)); - area = vty->index; - interval = atoi (argv[0]); - level = IS_LEVEL_1 | IS_LEVEL_2; - return set_lsp_refresh_interval (vty, area, interval, level); + if (area->max_lsp_lifetime[level-1] == max_lsp_lifetime) + return; + + area->max_lsp_lifetime[level-1] = max_lsp_lifetime; + lsp_regenerate_schedule(area, level, 1); } -DEFUN (no_lsp_refresh_interval, - no_lsp_refresh_interval_cmd, - "no lsp-refresh-interval", - NO_STR - "LSP refresh interval in seconds\n") +void +isis_area_lsp_refresh_set(struct isis_area *area, int level, + uint16_t lsp_refresh) { - struct isis_area *area; - uint16_t interval; - int level; + assert((level == IS_LEVEL_1) || (level == IS_LEVEL_2)); - area = vty->index; - interval = DEFAULT_MAX_LSP_GEN_INTERVAL; - level = IS_LEVEL_1 | IS_LEVEL_2; - return set_lsp_refresh_interval (vty, area, interval, level); + if (area->lsp_refresh[level-1] == lsp_refresh) + return; + + area->lsp_refresh[level-1] = lsp_refresh; + lsp_regenerate_schedule(area, level, 1); } -ALIAS (no_lsp_refresh_interval, - no_lsp_refresh_interval_arg_cmd, - "no lsp-refresh-interval <1-65235>", - NO_STR - "LSP refresh interval\n" - "LSP refresh interval in seconds\n") - -DEFUN (lsp_refresh_interval_l1, - lsp_refresh_interval_l1_cmd, - "lsp-refresh-interval level-1 <1-65235>", - "LSP refresh interval for Level 1 only\n" - "LSP refresh interval for Level 1 only in seconds\n") -{ - struct isis_area *area; - uint16_t interval; - int level; - - area = vty->index; - interval = atoi (argv[0]); - level = IS_LEVEL_1; - return set_lsp_refresh_interval (vty, area, interval, level); -} - -DEFUN (no_lsp_refresh_interval_l1, - no_lsp_refresh_interval_l1_cmd, - "no lsp-refresh-interval level-1", - NO_STR - "LSP refresh interval for Level 1 only in seconds\n") -{ - struct isis_area *area; - uint16_t interval; - int level; - - area = vty->index; - interval = DEFAULT_MAX_LSP_GEN_INTERVAL; - level = IS_LEVEL_1; - return set_lsp_refresh_interval (vty, area, interval, level); -} - -ALIAS (no_lsp_refresh_interval_l1, - no_lsp_refresh_interval_l1_arg_cmd, - "no lsp-refresh-interval level-1 <1-65235>", - NO_STR - "LSP refresh interval for Level 1 only\n" - "LSP refresh interval for Level 1 only in seconds\n") - -DEFUN (lsp_refresh_interval_l2, - lsp_refresh_interval_l2_cmd, - "lsp-refresh-interval level-2 <1-65235>", - "LSP refresh interval for Level 2 only\n" - "LSP refresh interval for Level 2 only in seconds\n") -{ - struct isis_area *area; - uint16_t interval; - int level; - - area = vty->index; - interval = atoi (argv[0]); - level = IS_LEVEL_2; - return set_lsp_refresh_interval (vty, area, interval, level); -} - -DEFUN (no_lsp_refresh_interval_l2, - no_lsp_refresh_interval_l2_cmd, - "no lsp-refresh-interval level-2", - NO_STR - "LSP refresh interval for Level 2 only in seconds\n") -{ - struct isis_area *area; - uint16_t interval; - int level; - - area = vty->index; - interval = DEFAULT_MAX_LSP_GEN_INTERVAL; - level = IS_LEVEL_2; - return set_lsp_refresh_interval (vty, area, interval, level); -} - -ALIAS (no_lsp_refresh_interval_l2, - no_lsp_refresh_interval_l2_arg_cmd, - "no lsp-refresh-interval level-2 <1-65235>", - NO_STR - "LSP refresh interval for Level 2 only\n" - "LSP refresh interval for Level 2 only in seconds\n") - DEFUN (log_adj_changes, log_adj_changes_cmd, "log-adjacency-changes", @@ -3251,6 +2286,7 @@ isis_config_write (struct vty *vty) #endif /* TOPOLOGY_GENERATE */ } + isis_mpls_te_config_write_router(vty); } return write; @@ -3305,7 +2341,7 @@ isis_init () install_element (ENABLE_NODE, &show_database_arg_detail_cmd); install_element (ENABLE_NODE, &show_database_detail_cmd); install_element (ENABLE_NODE, &show_database_detail_arg_cmd); - install_element (ENABLE_NODE, &show_debugging_cmd); + install_element (ENABLE_NODE, &show_debugging_isis_cmd); install_node (&debug_node, config_write_debug); @@ -3375,77 +2411,6 @@ isis_init () install_element (ISIS_NODE, &net_cmd); install_element (ISIS_NODE, &no_net_cmd); - install_element (ISIS_NODE, &is_type_cmd); - install_element (ISIS_NODE, &no_is_type_cmd); - - install_element (ISIS_NODE, &area_lsp_mtu_cmd); - install_element (ISIS_NODE, &no_area_lsp_mtu_cmd); - install_element (ISIS_NODE, &no_area_lsp_mtu_arg_cmd); - - install_element (ISIS_NODE, &area_passwd_md5_cmd); - install_element (ISIS_NODE, &area_passwd_md5_snpauth_cmd); - install_element (ISIS_NODE, &area_passwd_clear_cmd); - install_element (ISIS_NODE, &area_passwd_clear_snpauth_cmd); - install_element (ISIS_NODE, &no_area_passwd_cmd); - - install_element (ISIS_NODE, &domain_passwd_md5_cmd); - install_element (ISIS_NODE, &domain_passwd_md5_snpauth_cmd); - install_element (ISIS_NODE, &domain_passwd_clear_cmd); - install_element (ISIS_NODE, &domain_passwd_clear_snpauth_cmd); - install_element (ISIS_NODE, &no_domain_passwd_cmd); - - install_element (ISIS_NODE, &lsp_gen_interval_cmd); - install_element (ISIS_NODE, &no_lsp_gen_interval_cmd); - install_element (ISIS_NODE, &no_lsp_gen_interval_arg_cmd); - install_element (ISIS_NODE, &lsp_gen_interval_l1_cmd); - install_element (ISIS_NODE, &no_lsp_gen_interval_l1_cmd); - install_element (ISIS_NODE, &no_lsp_gen_interval_l1_arg_cmd); - install_element (ISIS_NODE, &lsp_gen_interval_l2_cmd); - install_element (ISIS_NODE, &no_lsp_gen_interval_l2_cmd); - install_element (ISIS_NODE, &no_lsp_gen_interval_l2_arg_cmd); - - install_element (ISIS_NODE, &spf_interval_cmd); - install_element (ISIS_NODE, &no_spf_interval_cmd); - install_element (ISIS_NODE, &no_spf_interval_arg_cmd); - install_element (ISIS_NODE, &spf_interval_l1_cmd); - install_element (ISIS_NODE, &no_spf_interval_l1_cmd); - install_element (ISIS_NODE, &no_spf_interval_l1_arg_cmd); - install_element (ISIS_NODE, &spf_interval_l2_cmd); - install_element (ISIS_NODE, &no_spf_interval_l2_cmd); - install_element (ISIS_NODE, &no_spf_interval_l2_arg_cmd); - - install_element (ISIS_NODE, &max_lsp_lifetime_cmd); - install_element (ISIS_NODE, &no_max_lsp_lifetime_cmd); - install_element (ISIS_NODE, &no_max_lsp_lifetime_arg_cmd); - install_element (ISIS_NODE, &max_lsp_lifetime_l1_cmd); - install_element (ISIS_NODE, &no_max_lsp_lifetime_l1_cmd); - install_element (ISIS_NODE, &no_max_lsp_lifetime_l1_arg_cmd); - install_element (ISIS_NODE, &max_lsp_lifetime_l2_cmd); - install_element (ISIS_NODE, &no_max_lsp_lifetime_l2_cmd); - install_element (ISIS_NODE, &no_max_lsp_lifetime_l2_arg_cmd); - - install_element (ISIS_NODE, &lsp_refresh_interval_cmd); - install_element (ISIS_NODE, &no_lsp_refresh_interval_cmd); - install_element (ISIS_NODE, &no_lsp_refresh_interval_arg_cmd); - install_element (ISIS_NODE, &lsp_refresh_interval_l1_cmd); - install_element (ISIS_NODE, &no_lsp_refresh_interval_l1_cmd); - install_element (ISIS_NODE, &no_lsp_refresh_interval_l1_arg_cmd); - install_element (ISIS_NODE, &lsp_refresh_interval_l2_cmd); - install_element (ISIS_NODE, &no_lsp_refresh_interval_l2_cmd); - install_element (ISIS_NODE, &no_lsp_refresh_interval_l2_arg_cmd); - - install_element (ISIS_NODE, &set_overload_bit_cmd); - install_element (ISIS_NODE, &no_set_overload_bit_cmd); - - install_element (ISIS_NODE, &set_attached_bit_cmd); - install_element (ISIS_NODE, &no_set_attached_bit_cmd); - - install_element (ISIS_NODE, &dynamic_hostname_cmd); - install_element (ISIS_NODE, &no_dynamic_hostname_cmd); - - install_element (ISIS_NODE, &metric_style_cmd); - install_element (ISIS_NODE, &no_metric_style_cmd); - install_element (ISIS_NODE, &log_adj_changes_cmd); install_element (ISIS_NODE, &no_log_adj_changes_cmd); diff --git a/isisd/isisd.h b/isisd/isisd.h index 6fe1eb8144..9a4f360a2b 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -27,7 +27,11 @@ #define ISISD_VERSION "0.0.7" +#include "isisd/isis_constants.h" +#include "isisd/isis_common.h" #include "isisd/isis_redist.h" +#include "isis_flags.h" +#include "dict.h" /* uncomment if you are a developer in bug hunt */ /* #define EXTREME_DEBUG */ @@ -139,6 +143,25 @@ struct isis_area *isis_area_lookup (const char *); int isis_area_get (struct vty *vty, const char *area_tag); void print_debug(struct vty *, int, int); +void isis_area_overload_bit_set(struct isis_area *area, bool overload_bit); +void isis_area_attached_bit_set(struct isis_area *area, bool attached_bit); +void isis_area_dynhostname_set(struct isis_area *area, bool dynhostname); +void isis_area_metricstyle_set(struct isis_area *area, bool old_metric, + bool new_metric); +void isis_area_lsp_mtu_set(struct isis_area *area, unsigned int lsp_mtu); +void isis_area_is_type_set(struct isis_area *area, int is_type); +void isis_area_max_lsp_lifetime_set(struct isis_area *area, int level, + uint16_t max_lsp_lifetime); +void isis_area_lsp_refresh_set(struct isis_area *area, int level, + uint16_t lsp_refresh); +/* IS_LEVEL_1 sets area_passwd, IS_LEVEL_2 domain_passwd */ +int isis_area_passwd_unset (struct isis_area *area, int level); +int isis_area_passwd_cleartext_set (struct isis_area *area, int level, + const char *passwd, u_char snp_auth); +int isis_area_passwd_hmac_md5_set (struct isis_area *area, int level, + const char *passwd, u_char snp_auth); +void isis_vty_init (void); + /* Master of threads. */ extern struct thread_master *master; @@ -174,4 +197,8 @@ extern struct thread_master *master; } \ while (0) +#define DEBUG_TE (1<<13) + +#define IS_DEBUG_ISIS(x) (isis->debugs & x) + #endif /* ISISD_H */ diff --git a/lib/.gitignore b/lib/.gitignore index ca49c1b6a3..8174bda7d8 100644 --- a/lib/.gitignore +++ b/lib/.gitignore @@ -19,3 +19,4 @@ route_types.h command_lex.c command_parse.c command_parse.h +refix diff --git a/lib/Makefile.am b/lib/Makefile.am index b7bb434776..3dfd09e2e6 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -17,7 +17,7 @@ libzebra_la_SOURCES = \ filter.c routemap.c distribute.c stream.c str.c log.c plist.c \ zclient.c sockopt.c smux.c agentx.c snmp.c md5.c if_rmap.c keychain.c privs.c \ sigevent.c pqueue.c jhash.c memtypes.c workqueue.c nexthop.c json.c \ - ptm_lib.c csv.c bfd.c vrf.c systemd.c + ptm_lib.c csv.c bfd.c vrf.c systemd.c ns.c BUILT_SOURCES = memtypes.h route_types.h gitversion.h command_parse.h @@ -35,7 +35,7 @@ pkginclude_HEADERS = \ plist.h zclient.h sockopt.h smux.h md5.h if_rmap.h keychain.h \ privs.h sigevent.h pqueue.h jhash.h zassert.h memtypes.h \ workqueue.h route_types.h libospf.h nexthop.h json.h \ - ptm_lib.h csv.h bfd.h vrf.h systemd.h bitfield.h + ptm_lib.h csv.h bfd.h vrf.h ns.h systemd.h bitfield.h noinst_HEADERS = \ plist_int.h diff --git a/lib/agentx.c b/lib/agentx.c index bb95903adf..5996b34a0f 100644 --- a/lib/agentx.c +++ b/lib/agentx.c @@ -24,11 +24,110 @@ #if defined HAVE_SNMP && defined SNMP_AGENTX #include #include +#include +#include #include "command.h" #include "smux.h" +#include "memory.h" +#include "linklist.h" -int agentx_enabled = 0; +static int agentx_enabled = 0; + +static struct thread_master *agentx_tm; +static struct thread *timeout_thr = NULL; +static struct list *events = NULL; + +static void agentx_events_update(void); + +static int +agentx_timeout(struct thread *t) +{ + timeout_thr = NULL; + + snmp_timeout (); + run_alarms (); + netsnmp_check_outstanding_agent_requests (); + agentx_events_update (); + return 0; +} + +static int +agentx_read(struct thread *t) +{ + fd_set fds; + struct listnode *ln = THREAD_ARG (t); + list_delete_node (events, ln); + + FD_ZERO (&fds); + FD_SET (THREAD_FD (t), &fds); + snmp_read (&fds); + + netsnmp_check_outstanding_agent_requests (); + agentx_events_update (); + return 0; +} + +static void +agentx_events_update(void) +{ + int maxfd = 0; + int block = 1; + struct timeval timeout = { .tv_sec = 0, .tv_usec = 0 }; + fd_set fds; + struct listnode *ln; + struct thread *thr; + int fd, thr_fd; + + THREAD_OFF (timeout_thr); + + FD_ZERO (&fds); + snmp_select_info (&maxfd, &fds, &timeout, &block); + + if (!block) + timeout_thr = thread_add_timer_tv (agentx_tm, agentx_timeout, NULL, &timeout); + + ln = listhead (events); + thr = ln ? listgetdata (ln) : NULL; + thr_fd = thr ? THREAD_FD (thr) : -1; + + /* "two-pointer" / two-list simultaneous iteration + * ln/thr/thr_fd point to the next existing event listener to hit while + * fd counts to catch up */ + for (fd = 0; fd < maxfd; fd++) + { + /* caught up */ + if (thr_fd == fd) + { + struct listnode *nextln = listnextnode (ln); + if (!FD_ISSET (fd, &fds)) + { + thread_cancel (thr); + list_delete_node (events, ln); + } + ln = nextln; + thr = ln ? listgetdata (ln) : NULL; + thr_fd = thr ? THREAD_FD (thr) : -1; + } + /* need listener, but haven't hit one where it would be */ + else if (FD_ISSET (fd, &fds)) + { + struct listnode *newln; + thr = thread_add_read (agentx_tm, agentx_read, NULL, fd); + newln = listnode_add_before (events, ln, thr); + thr->arg = newln; + } + } + + /* leftover event listeners at this point have fd > maxfd, delete them */ + while (ln) + { + struct listnode *nextln = listnextnode (ln); + thread_cancel (listgetdata (ln)); + list_delete_node (events, ln); + ln = nextln; + } +} /* AgentX node. */ static struct cmd_node agentx_node = @@ -77,6 +176,8 @@ DEFUN (agentx_enable, if (!agentx_enabled) { init_snmp("quagga"); + events = list_new(); + agentx_events_update (); agentx_enabled = 1; return CMD_SUCCESS; } @@ -99,6 +200,8 @@ DEFUN (no_agentx, void smux_init (struct thread_master *tm) { + agentx_tm = tm; + netsnmp_enable_subagent (); snmp_disable_log (); snmp_enable_calllog (); @@ -207,6 +310,7 @@ smux_trap (struct variable *vp, size_t vp_len, send_v2trap (notification_vars); snmp_free_varbind (notification_vars); + agentx_events_update (); return 1; } diff --git a/lib/bfd.c b/lib/bfd.c index 2116fa5c1f..67a84c95f9 100644 --- a/lib/bfd.c +++ b/lib/bfd.c @@ -504,8 +504,8 @@ bfd_client_sendmsg (struct zclient *zclient, int command) if (ret < 0) { if (bfd_debug) - zlog_debug ("bfd_client_sendmsg %d: zclient_send_message() failed", - getpid()); + zlog_debug ("bfd_client_sendmsg %ld: zclient_send_message() failed", + (long) getpid()); return; } diff --git a/lib/command.c b/lib/command.c index f7800aa724..b4ef30a300 100644 --- a/lib/command.c +++ b/lib/command.c @@ -666,8 +666,12 @@ node_parent ( enum node_type node ) case KEYCHAIN_KEY_NODE: ret = KEYCHAIN_NODE; break; + case LINK_PARAMS_NODE: + ret = INTERFACE_NODE; + break; default: ret = CONFIG_NODE; + break; } return ret; @@ -961,6 +965,7 @@ DEFUN (config_exit, vty_config_unlock (vty); break; case INTERFACE_NODE: + case NS_NODE: case VRF_NODE: case ZEBRA_NODE: case BGP_NODE: @@ -989,6 +994,9 @@ DEFUN (config_exit, case KEYCHAIN_KEY_NODE: vty->node = KEYCHAIN_NODE; break; + case LINK_PARAMS_NODE: + vty->node = INTERFACE_NODE; + break; default: break; } @@ -1016,6 +1024,7 @@ DEFUN (config_end, break; case CONFIG_NODE: case INTERFACE_NODE: + case NS_NODE: case VRF_NODE: case ZEBRA_NODE: case RIP_NODE: @@ -1038,6 +1047,7 @@ DEFUN (config_end, case MASC_NODE: case PIM_NODE: case VTY_NODE: + case LINK_PARAMS_NODE: vty_config_unlock (vty); vty->node = ENABLE_NODE; break; @@ -1757,6 +1767,10 @@ set_log_file(struct vty *vty, const char *fname, int loglevel) host.logfile = XSTRDUP (MTYPE_HOST, fname); +#if defined(HAVE_CUMULUS) + if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED) + zlog_default->maxlvl[ZLOG_DEST_SYSLOG] = ZLOG_DISABLED; +#endif return CMD_SUCCESS; } @@ -1955,11 +1969,25 @@ DEFUN (no_config_log_timestamp_precision, int cmd_banner_motd_file (const char *file) { - if (host.motdfile) - XFREE (MTYPE_HOST, host.motdfile); - host.motdfile = XSTRDUP (MTYPE_HOST, file); + int success = CMD_SUCCESS; + char p[PATH_MAX]; + char *rpath; + char *in; - return CMD_SUCCESS; + rpath = realpath (file, p); + if (!rpath) + return CMD_ERR_NO_FILE; + in = strstr (rpath, SYSCONFDIR); + if (in == rpath) + { + if (host.motdfile) + XFREE (MTYPE_HOST, host.motdfile); + host.motdfile = XSTRDUP (MTYPE_HOST, file); + } + else + success = CMD_WARNING; + + return success; } DEFUN (banner_motd_file, @@ -1970,7 +1998,15 @@ DEFUN (banner_motd_file, "Banner from a file\n" "Filename\n") { - return cmd_banner_motd_file (argv[3]->arg); + int cmd = cmd_banner_motd_file (argv[3]->arg); + + if (cmd == CMD_ERR_NO_FILE) + vty_out (vty, "%s does not exist", argv[3]->arg); + else if (cmd == CMD_WARNING) + vty_out (vty, "%s must be in %s", + argv[0], SYSCONFDIR); + + return cmd; } DEFUN (banner_motd_default, @@ -2098,7 +2134,6 @@ cmd_init (int terminal) install_element (RESTRICTED_NODE, &config_enable_cmd); install_element (RESTRICTED_NODE, &config_terminal_length_cmd); install_element (RESTRICTED_NODE, &config_terminal_no_length_cmd); - install_element (RESTRICTED_NODE, &show_commandtree_cmd); install_element (RESTRICTED_NODE, &echo_cmd); } @@ -2167,7 +2202,6 @@ cmd_init (int terminal) vrf_install_commands (); } - install_element (CONFIG_NODE, &show_commandtree_cmd); srandom(time(NULL)); } diff --git a/lib/command.h b/lib/command.h index 786539034b..5e1b48c68f 100644 --- a/lib/command.h +++ b/lib/command.h @@ -75,6 +75,7 @@ enum node_type AAA_NODE, /* AAA node. */ KEYCHAIN_NODE, /* Key-chain node. */ KEYCHAIN_KEY_NODE, /* Key-chain key node. */ + NS_NODE, /* Logical-Router node. */ VRF_NODE, /* VRF mode node. */ INTERFACE_NODE, /* Interface mode node. */ ZEBRA_NODE, /* zebra connection node. */ @@ -109,6 +110,7 @@ enum node_type FORWARDING_NODE, /* IP forwarding node. */ PROTOCOL_NODE, /* protocol filtering node */ VTY_NODE, /* Vty node. */ + LINK_PARAMS_NODE, /* Link-parameters node */ }; /* Node which has some commands and prompt string and configuration @@ -356,6 +358,10 @@ struct cmd_element #define AREA_TAG_STR "[area tag]\n" #define COMMUNITY_AANN_STR "Community number where AA and NN are (0-65535)\n" #define COMMUNITY_VAL_STR "Community number in AA:NN format (where AA and NN are (0-65535)) or local-AS|no-advertise|no-export|internet or additive\n" +#define MPLS_TE_STR "MPLS-TE specific commands\n" +#define LINK_PARAMS_STR "Configure interface link parameters\n" +#define OSPF_RI_STR "OSPF Router Information specific commands\n" +#define PCE_STR "PCE Router Information specific commands\n" #define CONF_BACKUP_EXT ".sav" diff --git a/lib/filter.h b/lib/filter.h index 37535cb13b..e6ccd33b3a 100644 --- a/lib/filter.h +++ b/lib/filter.h @@ -25,6 +25,11 @@ #include "if.h" +/* Filter direction. */ +#define FILTER_IN 0 +#define FILTER_OUT 1 +#define FILTER_MAX 2 + /* Filter type is made by `permit', `deny' and `dynamic'. */ enum filter_type { diff --git a/lib/if.c b/lib/if.c index 8f1461326f..e44882a43e 100644 --- a/lib/if.c +++ b/lib/if.c @@ -205,6 +205,8 @@ if_delete (struct interface *ifp) list_free (ifp->connected); list_free (ifp->nbr_connected); + if_link_params_free (ifp); + XFREE (MTYPE_IF, ifp); } @@ -226,41 +228,41 @@ if_add_hook (int type, int (*func)(struct interface *ifp)) /* Interface existance check by index. */ struct interface * -if_lookup_by_index_vrf (unsigned int index, vrf_id_t vrf_id) +if_lookup_by_index_vrf (ifindex_t ifindex, vrf_id_t vrf_id) { struct listnode *node; struct interface *ifp; for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp)) { - if (ifp->ifindex == index) + if (ifp->ifindex == ifindex) return ifp; } return NULL; } struct interface * -if_lookup_by_index (unsigned int index) +if_lookup_by_index (ifindex_t ifindex) { - return if_lookup_by_index_vrf (index, VRF_DEFAULT); + return if_lookup_by_index_vrf (ifindex, VRF_DEFAULT); } const char * -ifindex2ifname_vrf (unsigned int index, vrf_id_t vrf_id) +ifindex2ifname_vrf (ifindex_t ifindex, vrf_id_t vrf_id) { struct interface *ifp; - return ((ifp = if_lookup_by_index_vrf (index, vrf_id)) != NULL) ? + return ((ifp = if_lookup_by_index_vrf (ifindex, vrf_id)) != NULL) ? ifp->name : "unknown"; } const char * -ifindex2ifname (unsigned int index) +ifindex2ifname (ifindex_t ifindex) { - return ifindex2ifname_vrf (index, VRF_DEFAULT); + return ifindex2ifname_vrf (ifindex, VRF_DEFAULT); } -unsigned int +ifindex_t ifname2ifindex_vrf (const char *name, vrf_id_t vrf_id) { struct interface *ifp; @@ -269,7 +271,7 @@ ifname2ifindex_vrf (const char *name, vrf_id_t vrf_id) : IFINDEX_INTERNAL; } -unsigned int +ifindex_t ifname2ifindex (const char *name) { return ifname2ifindex_vrf (name, VRF_DEFAULT); @@ -1167,7 +1169,7 @@ connected_add_by_prefix (struct interface *ifp, struct prefix *p, } #ifndef HAVE_IF_NAMETOINDEX -unsigned int +ifindex_t if_nametoindex (const char *name) { struct interface *ifp; @@ -1179,7 +1181,7 @@ if_nametoindex (const char *name) #ifndef HAVE_IF_INDEXTONAME char * -if_indextoname (unsigned int ifindex, char *name) +if_indextoname (ifindex_t ifindex, char *name) { struct interface *ifp; @@ -1244,7 +1246,7 @@ ifaddr_ipv4_delete (struct in_addr *ifaddr, struct interface *ifp) /* Lookup interface by interface's IP address or interface index. */ static struct interface * -ifaddr_ipv4_lookup (struct in_addr *addr, unsigned int ifindex) +ifaddr_ipv4_lookup (struct in_addr *addr, ifindex_t ifindex) { struct prefix_ipv4 p; struct route_node *rn; @@ -1304,3 +1306,105 @@ if_terminate (struct list **intf_list) list_delete (*intf_list); *intf_list = NULL; } + +const char * +if_link_type_str (enum zebra_link_type llt) +{ + switch (llt) + { +#define llts(T,S) case (T): return (S) + llts(ZEBRA_LLT_UNKNOWN, "Unknown"); + llts(ZEBRA_LLT_ETHER, "Ethernet"); + llts(ZEBRA_LLT_EETHER, "Experimental Ethernet"); + llts(ZEBRA_LLT_AX25, "AX.25 Level 2"); + llts(ZEBRA_LLT_PRONET, "PROnet token ring"); + llts(ZEBRA_LLT_IEEE802, "IEEE 802.2 Ethernet/TR/TB"); + llts(ZEBRA_LLT_ARCNET, "ARCnet"); + llts(ZEBRA_LLT_APPLETLK, "AppleTalk"); + llts(ZEBRA_LLT_DLCI, "Frame Relay DLCI"); + llts(ZEBRA_LLT_ATM, "ATM"); + llts(ZEBRA_LLT_METRICOM, "Metricom STRIP"); + llts(ZEBRA_LLT_IEEE1394, "IEEE 1394 IPv4"); + llts(ZEBRA_LLT_EUI64, "EUI-64"); + llts(ZEBRA_LLT_INFINIBAND, "InfiniBand"); + llts(ZEBRA_LLT_SLIP, "SLIP"); + llts(ZEBRA_LLT_CSLIP, "Compressed SLIP"); + llts(ZEBRA_LLT_SLIP6, "SLIPv6"); + llts(ZEBRA_LLT_CSLIP6, "Compressed SLIPv6"); + llts(ZEBRA_LLT_ROSE, "ROSE packet radio"); + llts(ZEBRA_LLT_X25, "CCITT X.25"); + llts(ZEBRA_LLT_PPP, "PPP"); + llts(ZEBRA_LLT_CHDLC, "Cisco HDLC"); + llts(ZEBRA_LLT_RAWHDLC, "Raw HDLC"); + llts(ZEBRA_LLT_LAPB, "LAPB"); + llts(ZEBRA_LLT_IPIP, "IPIP Tunnel"); + llts(ZEBRA_LLT_IPIP6, "IPIP6 Tunnel"); + llts(ZEBRA_LLT_FRAD, "FRAD"); + llts(ZEBRA_LLT_SKIP, "SKIP vif"); + llts(ZEBRA_LLT_LOOPBACK, "Loopback"); + llts(ZEBRA_LLT_LOCALTLK, "Localtalk"); + llts(ZEBRA_LLT_FDDI, "FDDI"); + llts(ZEBRA_LLT_SIT, "IPv6-in-IPv4 SIT"); + llts(ZEBRA_LLT_IPDDP, "IP-in-DDP tunnel"); + llts(ZEBRA_LLT_IPGRE, "GRE over IP"); + llts(ZEBRA_LLT_PIMREG, "PIMSM registration"); + llts(ZEBRA_LLT_HIPPI, "HiPPI"); + llts(ZEBRA_LLT_IRDA, "IrDA"); + llts(ZEBRA_LLT_FCPP, "Fibre-Channel PtP"); + llts(ZEBRA_LLT_FCAL, "Fibre-Channel Arbitrated Loop"); + llts(ZEBRA_LLT_FCPL, "Fibre-Channel Public Loop"); + llts(ZEBRA_LLT_FCFABRIC, "Fibre-Channel Fabric"); + llts(ZEBRA_LLT_IEEE802_TR, "IEEE 802.2 Token Ring"); + llts(ZEBRA_LLT_IEEE80211, "IEEE 802.11"); + llts(ZEBRA_LLT_IEEE80211_RADIOTAP, "IEEE 802.11 Radiotap"); + llts(ZEBRA_LLT_IEEE802154, "IEEE 802.15.4"); + llts(ZEBRA_LLT_IEEE802154_PHY, "IEEE 802.15.4 Phy"); + default: + zlog_warn ("Unknown value %d", llt); + return "Unknown type!"; +#undef llts + } + return NULL; +} + +struct if_link_params * +if_link_params_get (struct interface *ifp) +{ + int i; + + if (ifp->link_params != NULL) + return ifp->link_params; + + struct if_link_params *iflp = XCALLOC(MTYPE_IF_LINK_PARAMS, + sizeof (struct if_link_params)); + if (iflp == NULL) return NULL; + + /* Set TE metric == standard metric */ + iflp->te_metric = ifp->metric; + + /* Compute default bandwidth based on interface */ + int bw = (float)((ifp->bandwidth ? ifp->bandwidth : DEFAULT_BANDWIDTH) + * TE_KILO_BIT / TE_BYTE); + + /* Set Max, Reservable and Unreserved Bandwidth */ + iflp->max_bw = bw; + iflp->max_rsv_bw = bw; + for (i = 0; i < MAX_CLASS_TYPE; i++) + iflp->unrsv_bw[i] = bw; + + /* Update Link parameters status */ + iflp->lp_status = LP_TE | LP_MAX_BW | LP_MAX_RSV_BW | LP_UNRSV_BW; + + /* Finally attach newly created Link Parameters */ + ifp->link_params = iflp; + + return iflp; +} + +void +if_link_params_free (struct interface *ifp) +{ + if (ifp->link_params == NULL) return; + XFREE(MTYPE_IF_LINK_PARAMS, ifp->link_params); + ifp->link_params = NULL; +} diff --git a/lib/if.h b/lib/if.h index 4ec85bc841..17f8565595 100644 --- a/lib/if.h +++ b/lib/if.h @@ -21,8 +21,69 @@ Boston, MA 02111-1307, USA. */ #ifndef _ZEBRA_IF_H #define _ZEBRA_IF_H +#include "zebra.h" #include "linklist.h" +/* Interface link-layer type, if known. Derived from: + * + * net/if_arp.h on various platforms - Linux especially. + * http://www.iana.org/assignments/arp-parameters/arp-parameters.xhtml + * + * Some of the more obviously defunct technologies left out. + */ +enum zebra_link_type { + ZEBRA_LLT_UNKNOWN = 0, + ZEBRA_LLT_ETHER, + ZEBRA_LLT_EETHER, + ZEBRA_LLT_AX25, + ZEBRA_LLT_PRONET, + ZEBRA_LLT_IEEE802, + ZEBRA_LLT_ARCNET, + ZEBRA_LLT_APPLETLK, + ZEBRA_LLT_DLCI, + ZEBRA_LLT_ATM, + ZEBRA_LLT_METRICOM, + ZEBRA_LLT_IEEE1394, + ZEBRA_LLT_EUI64, + ZEBRA_LLT_INFINIBAND, + ZEBRA_LLT_SLIP, + ZEBRA_LLT_CSLIP, + ZEBRA_LLT_SLIP6, + ZEBRA_LLT_CSLIP6, + ZEBRA_LLT_RSRVD, + ZEBRA_LLT_ADAPT, + ZEBRA_LLT_ROSE, + ZEBRA_LLT_X25, + ZEBRA_LLT_PPP, + ZEBRA_LLT_CHDLC, + ZEBRA_LLT_LAPB, + ZEBRA_LLT_RAWHDLC, + ZEBRA_LLT_IPIP, + ZEBRA_LLT_IPIP6, + ZEBRA_LLT_FRAD, + ZEBRA_LLT_SKIP, + ZEBRA_LLT_LOOPBACK, + ZEBRA_LLT_LOCALTLK, + ZEBRA_LLT_FDDI, + ZEBRA_LLT_SIT, + ZEBRA_LLT_IPDDP, + ZEBRA_LLT_IPGRE, + ZEBRA_LLT_IP6GRE, + ZEBRA_LLT_PIMREG, + ZEBRA_LLT_HIPPI, + ZEBRA_LLT_ECONET, + ZEBRA_LLT_IRDA, + ZEBRA_LLT_FCPP, + ZEBRA_LLT_FCAL, + ZEBRA_LLT_FCPL, + ZEBRA_LLT_FCFABRIC, + ZEBRA_LLT_IEEE802_TR, + ZEBRA_LLT_IEEE80211, + ZEBRA_LLT_IEEE80211_RADIOTAP, + ZEBRA_LLT_IEEE802154, + ZEBRA_LLT_IEEE802154_PHY, +}; + /* Interface name length. @@ -36,6 +97,8 @@ Boston, MA 02111-1307, USA. */ #define INTERFACE_NAMSIZ 20 #define INTERFACE_HWADDR_MAX 20 +typedef signed int ifindex_t; + #ifdef HAVE_PROC_NET_DEV struct if_stats { @@ -68,6 +131,63 @@ struct if_stats }; #endif /* HAVE_PROC_NET_DEV */ +/* Here are "non-official" architectural constants. */ +#define TE_EXT_MASK 0x0FFFFFFF +#define TE_EXT_ANORMAL 0x80000000 +#define LOSS_PRECISION 0.000003 +#define TE_KILO_BIT 1000 +#define TE_BYTE 8 +#define DEFAULT_BANDWIDTH 10000 +#define MAX_CLASS_TYPE 8 +#define MAX_PKT_LOSS 50.331642 + +/* Link Parameters Status: 0: unset, 1: set, */ +#define LP_UNSET 0x0000 +#define LP_TE 0x0001 +#define LP_MAX_BW 0x0002 +#define LP_MAX_RSV_BW 0x0004 +#define LP_UNRSV_BW 0x0008 +#define LP_ADM_GRP 0x0010 +#define LP_RMT_AS 0x0020 +#define LP_DELAY 0x0040 +#define LP_MM_DELAY 0x0080 +#define LP_DELAY_VAR 0x0100 +#define LP_PKT_LOSS 0x0200 +#define LP_RES_BW 0x0400 +#define LP_AVA_BW 0x0800 +#define LP_USE_BW 0x1000 + +#define IS_PARAM_UNSET(lp, st) !(lp->lp_status & st) +#define IS_PARAM_SET(lp, st) (lp->lp_status & st) +#define IS_LINK_PARAMS_SET(lp) (lp->lp_status != LP_UNSET) + +#define SET_PARAM(lp, st) (lp->lp_status) |= (st) +#define UNSET_PARAM(lp, st) (lp->lp_status) &= ~(st) +#define RESET_LINK_PARAM(lp) (lp->lp_status = LP_UNSET) + +/* Link Parameters for Traffic Engineering */ +struct if_link_params { + u_int32_t lp_status; /* Status of Link Parameters: */ + u_int32_t te_metric; /* Traffic Engineering metric */ + float max_bw; /* Maximum Bandwidth */ + float max_rsv_bw; /* Maximum Reservable Bandwidth */ + float unrsv_bw[MAX_CLASS_TYPE]; /* Unreserved Bandwidth per Class Type (8) */ + u_int32_t admin_grp; /* Administrative group */ + u_int32_t rmt_as; /* Remote AS number */ + struct in_addr rmt_ip; /* Remote IP address */ + u_int32_t av_delay; /* Link Average Delay */ + u_int32_t min_delay; /* Link Min Delay */ + u_int32_t max_delay; /* Link Max Delay */ + u_int32_t delay_var; /* Link Delay Variation */ + float pkt_loss; /* Link Packet Loss */ + float res_bw; /* Residual Bandwidth */ + float ava_bw; /* Available Bandwidth */ + float use_bw; /* Utilized Bandwidth */ +}; + +#define INTERFACE_LINK_PARAMS_SIZE sizeof(struct if_link_params) +#define HAS_LINK_PARAMS(ifp) ((ifp)->link_params != NULL) + /* Interface structure */ struct interface { @@ -82,9 +202,9 @@ struct interface /* Interface index (should be IFINDEX_INTERNAL for non-kernel or deleted interfaces). */ - unsigned int ifindex; + ifindex_t ifindex; #define IFINDEX_INTERNAL 0 -#define IFINDEX_DELETED UINT_MAX +#define IFINDEX_DELETED INT_MAX /* Zebra internal interface status */ u_char status; @@ -103,24 +223,17 @@ struct interface unsigned int mtu; /* IPv4 MTU */ unsigned int mtu6; /* IPv6 MTU - probably, but not neccessarily same as mtu */ - /* Hardware address. */ -#ifdef HAVE_STRUCT_SOCKADDR_DL - union { - /* note that sdl_storage is never accessed, it only exists to make space. - * all actual uses refer to sdl - but use sizeof(sdl_storage)! this fits - * best with C aliasing rules. */ - struct sockaddr_dl sdl; - struct sockaddr_storage sdl_storage; - }; -#else - unsigned short hw_type; + /* Link-layer information and hardware address */ + enum zebra_link_type ll_type; u_char hw_addr[INTERFACE_HWADDR_MAX]; int hw_addr_len; -#endif /* HAVE_STRUCT_SOCKADDR_DL */ /* interface bandwidth, kbits */ unsigned int bandwidth; + /* Link parameters for Traffic Engineering */ + struct if_link_params *link_params; + /* description of the interface. */ char *desc; @@ -264,7 +377,7 @@ struct nbr_connected /* Prototypes. */ extern int if_cmp_name_func (char *, char *); extern struct interface *if_create (const char *name, int namelen); -extern struct interface *if_lookup_by_index (unsigned int); +extern struct interface *if_lookup_by_index (ifindex_t); extern struct interface *if_lookup_exact_address (void *matchaddr, int family); extern struct interface *if_lookup_address (void *matchaddr, int family); extern struct interface *if_lookup_prefix (struct prefix *prefix); @@ -273,8 +386,7 @@ extern void if_update_vrf (struct interface *, const char *name, int namelen, vrf_id_t vrf_id); extern struct interface *if_create_vrf (const char *name, int namelen, vrf_id_t vrf_id); -extern struct interface *if_lookup_by_index_vrf (unsigned int, - vrf_id_t vrf_id); +extern struct interface *if_lookup_by_index_vrf (ifindex_t, vrf_id_t vrf_id); extern struct interface *if_lookup_exact_address_vrf (void *matchaddr, int family, vrf_id_t vrf_id); extern struct interface *if_lookup_address_vrf (void *matchaddr, int family, @@ -328,18 +440,19 @@ extern void if_init (struct list **); extern void if_terminate (struct list **); extern void if_dump_all (void); extern const char *if_flag_dump(unsigned long); +extern const char *if_link_type_str (enum zebra_link_type); /* Please use ifindex2ifname instead of if_indextoname where possible; ifindex2ifname uses internal interface info, whereas if_indextoname must make a system call. */ -extern const char *ifindex2ifname (unsigned int); -extern const char *ifindex2ifname_vrf (unsigned int, vrf_id_t vrf_id); +extern const char *ifindex2ifname (ifindex_t); +extern const char *ifindex2ifname_vrf (ifindex_t, vrf_id_t vrf_id); /* Please use ifname2ifindex instead of if_nametoindex where possible; ifname2ifindex uses internal interface info, whereas if_nametoindex must make a system call. */ -extern unsigned int ifname2ifindex(const char *ifname); -extern unsigned int ifname2ifindex_vrf(const char *ifname, vrf_id_t vrf_id); +extern ifindex_t ifname2ifindex(const char *ifname); +extern ifindex_t ifname2ifindex_vrf(const char *ifname, vrf_id_t vrf_id); /* Connected address functions. */ extern struct connected *connected_new (void); @@ -359,12 +472,16 @@ extern void nbr_connected_free (struct nbr_connected *); struct nbr_connected *nbr_connected_check (struct interface *, struct prefix *); #ifndef HAVE_IF_NAMETOINDEX -extern unsigned int if_nametoindex (const char *); +extern ifindex_t if_nametoindex (const char *); #endif #ifndef HAVE_IF_INDEXTONAME -extern char *if_indextoname (unsigned int, char *); +extern char *if_indextoname (ifindex_t, char *); #endif +/* link parameters */ +struct if_link_params *if_link_params_get (struct interface *); +void if_link_params_free (struct interface *); + /* Exported variables. */ extern struct cmd_element interface_desc_cmd; extern struct cmd_element no_interface_desc_cmd; diff --git a/lib/linklist.c b/lib/linklist.c index 4b16f07dd1..d27a2da848 100644 --- a/lib/linklist.c +++ b/lib/linklist.c @@ -122,7 +122,7 @@ listnode_add_sort (struct list *list, void *val) list->count++; } -void +struct listnode * listnode_add_after (struct list *list, struct listnode *pp, void *val) { struct listnode *nn; @@ -157,6 +157,45 @@ listnode_add_after (struct list *list, struct listnode *pp, void *val) pp->next = nn; } list->count++; + return nn; +} + +struct listnode * +listnode_add_before (struct list *list, struct listnode *pp, void *val) +{ + struct listnode *nn; + + assert (val != NULL); + + nn = listnode_new (); + nn->data = val; + + if (pp == NULL) + { + if (list->tail) + list->tail->next = nn; + else + list->head = nn; + + nn->prev = list->tail; + nn->next = pp; + + list->tail = nn; + } + else + { + if (pp->prev) + pp->prev->next = nn; + else + list->head = nn; + + nn->prev = pp->prev; + nn->next = pp; + + pp->prev = nn; + } + list->count++; + return nn; } /* Move given listnode to tail of the list */ @@ -266,52 +305,6 @@ list_delete_node (struct list *list, struct listnode *node) listnode_free (node); } -/* ospf_spf.c */ -void -list_add_node_prev (struct list *list, struct listnode *current, void *val) -{ - struct listnode *node; - - assert (val != NULL); - - node = listnode_new (); - node->next = current; - node->data = val; - - if (current->prev == NULL) - list->head = node; - else - current->prev->next = node; - - node->prev = current->prev; - current->prev = node; - - list->count++; -} - -/* ospf_spf.c */ -void -list_add_node_next (struct list *list, struct listnode *current, void *val) -{ - struct listnode *node; - - assert (val != NULL); - - node = listnode_new (); - node->prev = current; - node->data = val; - - if (current->next == NULL) - list->tail = node; - else - current->next->prev = node; - - node->next = current->next; - current->next = node; - - list->count++; -} - /* ospf_spf.c */ void list_add_list (struct list *l, struct list *m) diff --git a/lib/linklist.h b/lib/linklist.h index 6209c8b9d6..e99e50f4fa 100644 --- a/lib/linklist.h +++ b/lib/linklist.h @@ -67,7 +67,8 @@ extern void list_free (struct list *); extern void listnode_add (struct list *, void *); extern void listnode_add_sort (struct list *, void *); -extern void listnode_add_after (struct list *, struct listnode *, void *); +extern struct listnode *listnode_add_after (struct list *, struct listnode *, void *); +extern struct listnode *listnode_add_before (struct list *, struct listnode *, void *); extern void listnode_move_to_tail (struct list *, struct listnode *); extern void listnode_delete (struct list *, void *); extern struct listnode *listnode_lookup (struct list *, void *); @@ -80,8 +81,6 @@ extern void list_delete_all_node (struct list *); extern void list_delete_node (struct list *, struct listnode *); /* For ospf_spf.c */ -extern void list_add_node_prev (struct list *, struct listnode *, void *); -extern void list_add_node_next (struct list *, struct listnode *, void *); extern void list_add_list (struct list *, struct list *); /* List iteration macro. diff --git a/lib/log.c b/lib/log.c index 453a611dcd..ea50ae18cc 100644 --- a/lib/log.c +++ b/lib/log.c @@ -179,6 +179,7 @@ static void vzlog (struct zlog *zl, int priority, const char *format, va_list args) { char proto_str[32]; + int original_errno = errno; struct timestamp_control tsctl; tsctl.already_rendered = 0; @@ -197,6 +198,7 @@ vzlog (struct zlog *zl, int priority, const char *format, va_list args) fflush (stderr); /* In this case we return at here. */ + errno = original_errno; return; } tsctl.precision = zl->timestamp_precision; @@ -249,6 +251,8 @@ vzlog (struct zlog *zl, int priority, const char *format, va_list args) if (priority <= zl->maxlvl[ZLOG_DEST_MONITOR]) vty_log ((zl->record_priority ? zlog_priority[priority] : NULL), proto_str, format, &tsctl, args); + + errno = original_errno; } static char * diff --git a/lib/memory.c b/lib/memory.c index 290b999bb8..8d1a03743e 100644 --- a/lib/memory.c +++ b/lib/memory.c @@ -80,9 +80,11 @@ zmalloc (int type, size_t size) /* * Allocate memory as in zmalloc, and also clear the memory. + * Add an extra 'z' prefix to function name to avoid collision when linking + * statically with zlib that exports the 'zcalloc' symbol. */ void * -zcalloc (int type, size_t size) +zzcalloc (int type, size_t size) { void *memory; @@ -97,9 +99,9 @@ zcalloc (int type, size_t size) } /* - * Given a pointer returned by zmalloc or zcalloc, free it and + * Given a pointer returned by zmalloc or zzcalloc, free it and * return a pointer to a new size, basically acting like realloc(). - * Requires: ptr was returned by zmalloc, zcalloc, or zrealloc with the + * Requires: ptr was returned by zmalloc, zzcalloc, or zrealloc with the * same type. * Effects: Returns a pointer to the new memory, or aborts. */ @@ -109,7 +111,7 @@ zrealloc (int type, void *ptr, size_t size) void *memory; if (ptr == NULL) /* is really alloc */ - return zcalloc(type, size); + return zzcalloc(type, size); memory = realloc (ptr, size); if (memory == NULL) @@ -122,7 +124,7 @@ zrealloc (int type, void *ptr, size_t size) /* * Free memory allocated by z*alloc or zstrdup. - * Requires: ptr was returned by zmalloc, zcalloc, or zrealloc with the + * Requires: ptr was returned by zmalloc, zzcalloc, or zrealloc with the * same type. * Effects: The memory is freed and may no longer be referenced. */ @@ -196,7 +198,7 @@ mtype_zcalloc (const char *file, int line, int type, size_t size) mstat[type].c_calloc++; mstat[type].t_calloc++; - memory = zcalloc (type, size); + memory = zzcalloc (type, size); mtype_log ("xcalloc", memory, file, line, type); return memory; diff --git a/lib/memory.h b/lib/memory.h index 23962235db..501352993d 100644 --- a/lib/memory.h +++ b/lib/memory.h @@ -56,7 +56,7 @@ extern struct mlist mlists[]; mtype_zstrdup (__FILE__, __LINE__, (mtype), (str)) #else #define XMALLOC(mtype, size) zmalloc ((mtype), (size)) -#define XCALLOC(mtype, size) zcalloc ((mtype), (size)) +#define XCALLOC(mtype, size) zzcalloc ((mtype), (size)) #define XREALLOC(mtype, ptr, size) zrealloc ((mtype), (ptr), (size)) #define XFREE(mtype, ptr) do { \ zfree ((mtype), (ptr)); \ @@ -67,7 +67,7 @@ extern struct mlist mlists[]; /* Prototypes of memory function. */ extern void *zmalloc (int type, size_t size); -extern void *zcalloc (int type, size_t size); +extern void *zzcalloc (int type, size_t size); extern void *zrealloc (int type, void *ptr, size_t size); extern void zfree (int type, void *ptr); extern char *zstrdup (int type, const char *str); diff --git a/lib/memtypes.c b/lib/memtypes.c index d0faecb640..510312f336 100644 --- a/lib/memtypes.c +++ b/lib/memtypes.c @@ -77,6 +77,10 @@ struct memory_list memory_list_lib[] = { MTYPE_VRF, "VRF" }, { MTYPE_VRF_NAME, "VRF name" }, { MTYPE_VRF_BITMAP, "VRF bit-map" }, + { MTYPE_NS, "Logical-Router" }, + { MTYPE_NS_NAME, "Logical-Router Name" }, + { MTYPE_NS_BITMAP, "Logical-Router bit-map" }, + { MTYPE_IF_LINK_PARAMS, "Informational Link Parameters" }, { -1, NULL }, }; @@ -228,6 +232,8 @@ struct memory_list memory_list_ospf[] = { MTYPE_OSPF_IF_INFO, "OSPF if info" }, { MTYPE_OSPF_IF_PARAMS, "OSPF if params" }, { MTYPE_OSPF_MESSAGE, "OSPF message" }, + { MTYPE_OSPF_MPLS_TE, "OSPF MPLS parameters" }, + { MTYPE_OSPF_PCE_PARAMS, "OSPF PCE parameters" }, { -1, NULL }, }; @@ -269,6 +275,7 @@ struct memory_list memory_list_isis[] = { MTYPE_ISIS_NEXTHOP6, "ISIS nexthop6" }, { MTYPE_ISIS_DICT, "ISIS dictionary" }, { MTYPE_ISIS_DICT_NODE, "ISIS dictionary node" }, + { MTYPE_ISIS_MPLS_TE, "ISIS MPLS_TE parameters" }, { -1, NULL }, }; diff --git a/lib/network.c b/lib/network.c index 3373983b3c..5379ecb5a6 100644 --- a/lib/network.c +++ b/lib/network.c @@ -93,3 +93,21 @@ set_nonblocking(int fd) } return 0; } + +float +htonf (float host) +{ + u_int32_t lu1, lu2; + float convert; + + memcpy (&lu1, &host, sizeof (u_int32_t)); + lu2 = htonl (lu1); + memcpy (&convert, &lu2, sizeof (u_int32_t)); + return convert; +} + +float +ntohf (float net) +{ + return htonf (net); +} diff --git a/lib/network.h b/lib/network.h index 4d9c2284bf..0fcb575d1c 100644 --- a/lib/network.h +++ b/lib/network.h @@ -37,4 +37,7 @@ extern int set_nonblocking(int fd); #define ERRNO_IO_RETRY(EN) \ (((EN) == EAGAIN) || ((EN) == EWOULDBLOCK) || ((EN) == EINTR)) +extern float htonf (float); +extern float ntohf (float); + #endif /* _ZEBRA_NETWORK_H */ diff --git a/lib/nexthop.c b/lib/nexthop.c index 5853884218..14486ea157 100644 --- a/lib/nexthop.c +++ b/lib/nexthop.c @@ -153,3 +153,36 @@ nexthops_free (struct nexthop *nexthop) nexthop_free (nh); } } + +const char * +nexthop2str (struct nexthop *nexthop, char *str, int size) +{ + switch (nexthop->type) + { + case NEXTHOP_TYPE_IFINDEX: + snprintf (str, size, "if %u", nexthop->ifindex); + break; + case NEXTHOP_TYPE_IPV4: + snprintf (str, size, "%s", inet_ntoa (nexthop->gate.ipv4)); + break; + case NEXTHOP_TYPE_IPV4_IFINDEX: + snprintf (str, size, "%s if %u", + inet_ntoa (nexthop->gate.ipv4), nexthop->ifindex); + break; + case NEXTHOP_TYPE_IPV6: + snprintf (str, size, "%s", inet6_ntoa (nexthop->gate.ipv6)); + break; + case NEXTHOP_TYPE_IPV6_IFINDEX: + snprintf (str, size, "%s if %u", + inet6_ntoa (nexthop->gate.ipv6), nexthop->ifindex); + break; + case NEXTHOP_TYPE_BLACKHOLE: + snprintf (str, size, "blackhole"); + break; + default: + snprintf (str, size, "unknown"); + break; + } + + return str; +} diff --git a/lib/nexthop.h b/lib/nexthop.h index eb9b27ea9e..39e8b5425f 100644 --- a/lib/nexthop.h +++ b/lib/nexthop.h @@ -26,6 +26,9 @@ #include "prefix.h" +/* Maximum next hop string length - gateway + ifindex */ +#define NEXTHOP_STRLEN (INET6_ADDRSTRLEN + 30) + union g_addr { struct in_addr ipv4; struct in6_addr ipv6; @@ -48,7 +51,7 @@ struct nexthop struct nexthop *prev; /* Interface index. */ - unsigned int ifindex; + ifindex_t ifindex; enum nexthop_types_t type; @@ -97,4 +100,5 @@ void nexthops_free (struct nexthop *nexthop); extern const char *nexthop_type_to_str (enum nexthop_types_t nh_type); extern int nexthop_same_no_recurse (struct nexthop *next1, struct nexthop *next2); +extern const char * nexthop2str (struct nexthop *nexthop, char *str, int size); #endif /*_LIB_NEXTHOP_H */ diff --git a/lib/ns.c b/lib/ns.c new file mode 100644 index 0000000000..4765a18ef2 --- /dev/null +++ b/lib/ns.c @@ -0,0 +1,734 @@ +/* + * NS functions. + * Copyright (C) 2014 6WIND S.A. + * + * 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. + */ + +#include + +#ifdef HAVE_NETNS +#undef _GNU_SOURCE +#define _GNU_SOURCE + +#include +#endif + +#include "if.h" +#include "ns.h" +#include "prefix.h" +#include "table.h" +#include "log.h" +#include "memory.h" + +#include "command.h" +#include "vty.h" + + +#ifndef CLONE_NEWNET +#define CLONE_NEWNET 0x40000000 /* New network namespace (lo, device, names sockets, etc) */ +#endif + +#ifndef HAVE_SETNS +static inline int setns(int fd, int nstype) +{ +#ifdef __NR_setns + return syscall(__NR_setns, fd, nstype); +#else + errno = ENOSYS; + return -1; +#endif +} +#endif /* HAVE_SETNS */ + +#ifdef HAVE_NETNS + +#define NS_DEFAULT_NAME "/proc/self/ns/net" +static int have_netns_enabled = -1; + +#else /* !HAVE_NETNS */ + +#define NS_DEFAULT_NAME "Default-logical-router" + +#endif /* HAVE_NETNS */ + +static int have_netns(void) +{ +#ifdef HAVE_NETNS + if (have_netns_enabled < 0) + { + int fd = open (NS_DEFAULT_NAME, O_RDONLY); + + if (fd < 0) + have_netns_enabled = 0; + else + { + have_netns_enabled = 1; + close(fd); + } + } + return have_netns_enabled; +#else + return 0; +#endif +} + +struct ns +{ + /* Identifier, same as the vector index */ + ns_id_t ns_id; + /* Name */ + char *name; + /* File descriptor */ + int fd; + + /* Master list of interfaces belonging to this NS */ + struct list *iflist; + + /* User data */ + void *info; +}; + +/* Holding NS hooks */ +struct ns_master +{ + int (*ns_new_hook) (ns_id_t, void **); + int (*ns_delete_hook) (ns_id_t, void **); + int (*ns_enable_hook) (ns_id_t, void **); + int (*ns_disable_hook) (ns_id_t, void **); +} ns_master = {0,}; + +/* NS table */ +struct route_table *ns_table = NULL; + +static int ns_is_enabled (struct ns *ns); +static int ns_enable (struct ns *ns); +static void ns_disable (struct ns *ns); + + +/* Build the table key */ +static void +ns_build_key (ns_id_t ns_id, struct prefix *p) +{ + p->family = AF_INET; + p->prefixlen = IPV4_MAX_BITLEN; + p->u.prefix4.s_addr = ns_id; +} + +/* Get a NS. If not found, create one. */ +static struct ns * +ns_get (ns_id_t ns_id) +{ + struct prefix p; + struct route_node *rn; + struct ns *ns; + + ns_build_key (ns_id, &p); + rn = route_node_get (ns_table, &p); + if (rn->info) + { + ns = (struct ns *)rn->info; + route_unlock_node (rn); /* get */ + return ns; + } + + ns = XCALLOC (MTYPE_NS, sizeof (struct ns)); + ns->ns_id = ns_id; + ns->fd = -1; + rn->info = ns; + + /* + * Initialize interfaces. + * + * I'm not sure if this belongs here or in + * the vrf code. + */ + // if_init (&ns->iflist); + + zlog_info ("NS %u is created.", ns_id); + + if (ns_master.ns_new_hook) + (*ns_master.ns_new_hook) (ns_id, &ns->info); + + return ns; +} + +/* Delete a NS. This is called in ns_terminate(). */ +static void +ns_delete (struct ns *ns) +{ + zlog_info ("NS %u is to be deleted.", ns->ns_id); + + ns_disable (ns); + + if (ns_master.ns_delete_hook) + (*ns_master.ns_delete_hook) (ns->ns_id, &ns->info); + + /* + * I'm not entirely sure if the vrf->iflist + * needs to be moved into here or not. + */ + //if_terminate (&ns->iflist); + + if (ns->name) + XFREE (MTYPE_NS_NAME, ns->name); + + XFREE (MTYPE_NS, ns); +} + +/* Look up a NS by identifier. */ +static struct ns * +ns_lookup (ns_id_t ns_id) +{ + struct prefix p; + struct route_node *rn; + struct ns *ns = NULL; + + ns_build_key (ns_id, &p); + rn = route_node_lookup (ns_table, &p); + if (rn) + { + ns = (struct ns *)rn->info; + route_unlock_node (rn); /* lookup */ + } + return ns; +} + +/* + * Check whether the NS is enabled - that is, whether the NS + * is ready to allocate resources. Currently there's only one + * type of resource: socket. + */ +static int +ns_is_enabled (struct ns *ns) +{ + if (have_netns()) + return ns && ns->fd >= 0; + else + return ns && ns->fd == -2 && ns->ns_id == NS_DEFAULT; +} + +/* + * Enable a NS - that is, let the NS be ready to use. + * The NS_ENABLE_HOOK callback will be called to inform + * that they can allocate resources in this NS. + * + * RETURN: 1 - enabled successfully; otherwise, 0. + */ +static int +ns_enable (struct ns *ns) +{ + + if (!ns_is_enabled (ns)) + { + if (have_netns()) { + ns->fd = open (ns->name, O_RDONLY); + } else { + ns->fd = -2; /* Remember that ns_enable_hook has been called */ + errno = -ENOTSUP; + } + + if (!ns_is_enabled (ns)) + { + zlog_err ("Can not enable NS %u: %s!", + ns->ns_id, safe_strerror (errno)); + return 0; + } + + if (have_netns()) + zlog_info ("NS %u is associated with NETNS %s.", + ns->ns_id, ns->name); + + zlog_info ("NS %u is enabled.", ns->ns_id); + if (ns_master.ns_enable_hook) + (*ns_master.ns_enable_hook) (ns->ns_id, &ns->info); + } + + return 1; +} + +/* + * Disable a NS - that is, let the NS be unusable. + * The NS_DELETE_HOOK callback will be called to inform + * that they must release the resources in the NS. + */ +static void +ns_disable (struct ns *ns) +{ + if (ns_is_enabled (ns)) + { + zlog_info ("NS %u is to be disabled.", ns->ns_id); + + if (ns_master.ns_disable_hook) + (*ns_master.ns_disable_hook) (ns->ns_id, &ns->info); + + if (have_netns()) + close (ns->fd); + + ns->fd = -1; + } +} + + +/* Add a NS hook. Please add hooks before calling ns_init(). */ +void +ns_add_hook (int type, int (*func)(ns_id_t, void **)) +{ + switch (type) { + case NS_NEW_HOOK: + ns_master.ns_new_hook = func; + break; + case NS_DELETE_HOOK: + ns_master.ns_delete_hook = func; + break; + case NS_ENABLE_HOOK: + ns_master.ns_enable_hook = func; + break; + case NS_DISABLE_HOOK: + ns_master.ns_disable_hook = func; + break; + default: + break; + } +} + +/* Return the iterator of the first NS. */ +ns_iter_t +ns_first (void) +{ + struct route_node *rn; + + for (rn = route_top (ns_table); rn; rn = route_next (rn)) + if (rn->info) + { + route_unlock_node (rn); /* top/next */ + return (ns_iter_t)rn; + } + return NS_ITER_INVALID; +} + +/* Return the next NS iterator to the given iterator. */ +ns_iter_t +ns_next (ns_iter_t iter) +{ + struct route_node *rn = NULL; + + /* Lock it first because route_next() will unlock it. */ + if (iter != NS_ITER_INVALID) + rn = route_next (route_lock_node ((struct route_node *)iter)); + + for (; rn; rn = route_next (rn)) + if (rn->info) + { + route_unlock_node (rn); /* next */ + return (ns_iter_t)rn; + } + return NS_ITER_INVALID; +} + +/* Return the NS iterator of the given NS ID. If it does not exist, + * the iterator of the next existing NS is returned. */ +ns_iter_t +ns_iterator (ns_id_t ns_id) +{ + struct prefix p; + struct route_node *rn; + + ns_build_key (ns_id, &p); + rn = route_node_get (ns_table, &p); + if (rn->info) + { + /* OK, the NS exists. */ + route_unlock_node (rn); /* get */ + return (ns_iter_t)rn; + } + + /* Find the next NS. */ + for (rn = route_next (rn); rn; rn = route_next (rn)) + if (rn->info) + { + route_unlock_node (rn); /* next */ + return (ns_iter_t)rn; + } + + return NS_ITER_INVALID; +} + +/* Obtain the NS ID from the given NS iterator. */ +ns_id_t +ns_iter2id (ns_iter_t iter) +{ + struct route_node *rn = (struct route_node *) iter; + return (rn && rn->info) ? ((struct ns *)rn->info)->ns_id : NS_DEFAULT; +} + +/* Obtain the data pointer from the given NS iterator. */ +void * +ns_iter2info (ns_iter_t iter) +{ + struct route_node *rn = (struct route_node *) iter; + return (rn && rn->info) ? ((struct ns *)rn->info)->info : NULL; +} + +/* Obtain the interface list from the given NS iterator. */ +struct list * +ns_iter2iflist (ns_iter_t iter) +{ + struct route_node *rn = (struct route_node *) iter; + return (rn && rn->info) ? ((struct ns *)rn->info)->iflist : NULL; +} + +/* Get the data pointer of the specified NS. If not found, create one. */ +void * +ns_info_get (ns_id_t ns_id) +{ + struct ns *ns = ns_get (ns_id); + return ns->info; +} + +/* Look up the data pointer of the specified NS. */ +void * +ns_info_lookup (ns_id_t ns_id) +{ + struct ns *ns = ns_lookup (ns_id); + return ns ? ns->info : NULL; +} + +/* Look up the interface list in a NS. */ +struct list * +ns_iflist (ns_id_t ns_id) +{ + struct ns * ns = ns_lookup (ns_id); + return ns ? ns->iflist : NULL; +} + +/* Get the interface list of the specified NS. Create one if not find. */ +struct list * +ns_iflist_get (ns_id_t ns_id) +{ + struct ns * ns = ns_get (ns_id); + return ns->iflist; +} + +/* + * NS bit-map + */ + +#define NS_BITMAP_NUM_OF_GROUPS 8 +#define NS_BITMAP_NUM_OF_BITS_IN_GROUP \ + (UINT16_MAX / NS_BITMAP_NUM_OF_GROUPS) +#define NS_BITMAP_NUM_OF_BYTES_IN_GROUP \ + (NS_BITMAP_NUM_OF_BITS_IN_GROUP / CHAR_BIT + 1) /* +1 for ensure */ + +#define NS_BITMAP_GROUP(_id) \ + ((_id) / NS_BITMAP_NUM_OF_BITS_IN_GROUP) +#define NS_BITMAP_BIT_OFFSET(_id) \ + ((_id) % NS_BITMAP_NUM_OF_BITS_IN_GROUP) + +#define NS_BITMAP_INDEX_IN_GROUP(_bit_offset) \ + ((_bit_offset) / CHAR_BIT) +#define NS_BITMAP_FLAG(_bit_offset) \ + (((u_char)1) << ((_bit_offset) % CHAR_BIT)) + +struct ns_bitmap +{ + u_char *groups[NS_BITMAP_NUM_OF_GROUPS]; +}; + +ns_bitmap_t +ns_bitmap_init (void) +{ + return (ns_bitmap_t) XCALLOC (MTYPE_NS_BITMAP, sizeof (struct ns_bitmap)); +} + +void +ns_bitmap_free (ns_bitmap_t bmap) +{ + struct ns_bitmap *bm = (struct ns_bitmap *) bmap; + int i; + + if (bmap == NS_BITMAP_NULL) + return; + + for (i = 0; i < NS_BITMAP_NUM_OF_GROUPS; i++) + if (bm->groups[i]) + XFREE (MTYPE_NS_BITMAP, bm->groups[i]); + + XFREE (MTYPE_NS_BITMAP, bm); +} + +void +ns_bitmap_set (ns_bitmap_t bmap, ns_id_t ns_id) +{ + struct ns_bitmap *bm = (struct ns_bitmap *) bmap; + u_char group = NS_BITMAP_GROUP (ns_id); + u_char offset = NS_BITMAP_BIT_OFFSET (ns_id); + + if (bmap == NS_BITMAP_NULL) + return; + + if (bm->groups[group] == NULL) + bm->groups[group] = XCALLOC (MTYPE_NS_BITMAP, + NS_BITMAP_NUM_OF_BYTES_IN_GROUP); + + SET_FLAG (bm->groups[group][NS_BITMAP_INDEX_IN_GROUP (offset)], + NS_BITMAP_FLAG (offset)); +} + +void +ns_bitmap_unset (ns_bitmap_t bmap, ns_id_t ns_id) +{ + struct ns_bitmap *bm = (struct ns_bitmap *) bmap; + u_char group = NS_BITMAP_GROUP (ns_id); + u_char offset = NS_BITMAP_BIT_OFFSET (ns_id); + + if (bmap == NS_BITMAP_NULL || bm->groups[group] == NULL) + return; + + UNSET_FLAG (bm->groups[group][NS_BITMAP_INDEX_IN_GROUP (offset)], + NS_BITMAP_FLAG (offset)); +} + +int +ns_bitmap_check (ns_bitmap_t bmap, ns_id_t ns_id) +{ + struct ns_bitmap *bm = (struct ns_bitmap *) bmap; + u_char group = NS_BITMAP_GROUP (ns_id); + u_char offset = NS_BITMAP_BIT_OFFSET (ns_id); + + if (bmap == NS_BITMAP_NULL || bm->groups[group] == NULL) + return 0; + + return CHECK_FLAG (bm->groups[group][NS_BITMAP_INDEX_IN_GROUP (offset)], + NS_BITMAP_FLAG (offset)) ? 1 : 0; +} + +/* + * NS realization with NETNS + */ + +static char * +ns_netns_pathname (struct vty *vty, const char *name) +{ + static char pathname[PATH_MAX]; + char *result; + + if (name[0] == '/') /* absolute pathname */ + result = realpath (name, pathname); + else /* relevant pathname */ + { + char tmp_name[PATH_MAX]; + snprintf (tmp_name, PATH_MAX, "%s/%s", NS_RUN_DIR, name); + result = realpath (tmp_name, pathname); + } + + if (! result) + { + vty_out (vty, "Invalid pathname: %s%s", safe_strerror (errno), + VTY_NEWLINE); + return NULL; + } + return pathname; +} + +DEFUN (ns_netns, + ns_netns_cmd, + "logical-router <1-65535> ns NAME", + "Enable a logical-router\n" + "Specify the logical-router indentifier\n" + "The Name Space\n" + "The file name in " NS_RUN_DIR ", or a full pathname\n") +{ + ns_id_t ns_id = NS_DEFAULT; + struct ns *ns = NULL; + char *pathname = ns_netns_pathname (vty, argv[1]); + + if (!pathname) + return CMD_WARNING; + + VTY_GET_INTEGER ("NS ID", ns_id, argv[0]); + ns = ns_get (ns_id); + + if (ns->name && strcmp (ns->name, pathname) != 0) + { + vty_out (vty, "NS %u is already configured with NETNS %s%s", + ns->ns_id, ns->name, VTY_NEWLINE); + return CMD_WARNING; + } + + if (!ns->name) + ns->name = XSTRDUP (MTYPE_NS_NAME, pathname); + + if (!ns_enable (ns)) + { + vty_out (vty, "Can not associate NS %u with NETNS %s%s", + ns->ns_id, ns->name, VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +DEFUN (no_ns_netns, + no_ns_netns_cmd, + "no logical-router <1-65535> ns NAME", + NO_STR + "Enable a Logical-Router\n" + "Specify the Logical-Router identifier\n" + "The Name Space\n" + "The file name in " NS_RUN_DIR ", or a full pathname\n") +{ + ns_id_t ns_id = NS_DEFAULT; + struct ns *ns = NULL; + char *pathname = ns_netns_pathname (vty, argv[1]); + + if (!pathname) + return CMD_WARNING; + + VTY_GET_INTEGER ("NS ID", ns_id, argv[0]); + ns = ns_lookup (ns_id); + + if (!ns) + { + vty_out (vty, "NS %u is not found%s", ns_id, VTY_NEWLINE); + return CMD_SUCCESS; + } + + if (ns->name && strcmp (ns->name, pathname) != 0) + { + vty_out (vty, "Incorrect NETNS file name%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ns_disable (ns); + + if (ns->name) + { + XFREE (MTYPE_NS_NAME, ns->name); + ns->name = NULL; + } + + return CMD_SUCCESS; +} + +/* NS node. */ +static struct cmd_node ns_node = +{ + NS_NODE, + "", /* NS node has no interface. */ + 1 +}; + +/* NS configuration write function. */ +static int +ns_config_write (struct vty *vty) +{ + struct route_node *rn; + struct ns *ns; + int write = 0; + + for (rn = route_top (ns_table); rn; rn = route_next (rn)) + if ((ns = rn->info) != NULL && + ns->ns_id != NS_DEFAULT && ns->name) + { + vty_out (vty, "logical-router %u netns %s%s", ns->ns_id, ns->name, VTY_NEWLINE); + write++; + } + + return write; +} + +/* Initialize NS module. */ +void +ns_init (void) +{ + struct ns *default_ns; + + /* Allocate NS table. */ + ns_table = route_table_init (); + + /* The default NS always exists. */ + default_ns = ns_get (NS_DEFAULT); + if (!default_ns) + { + zlog_err ("ns_init: failed to create the default NS!"); + exit (1); + } + + /* Set the default NS name. */ + default_ns->name = XSTRDUP (MTYPE_NS_NAME, NS_DEFAULT_NAME); + + /* Enable the default NS. */ + if (!ns_enable (default_ns)) + { + zlog_err ("ns_init: failed to enable the default NS!"); + exit (1); + } + + if (have_netns()) + { + /* Install NS commands. */ + install_node (&ns_node, ns_config_write); + install_element (CONFIG_NODE, &ns_netns_cmd); + install_element (CONFIG_NODE, &no_ns_netns_cmd); + } +} + +/* Terminate NS module. */ +void +ns_terminate (void) +{ + struct route_node *rn; + struct ns *ns; + + for (rn = route_top (ns_table); rn; rn = route_next (rn)) + if ((ns = rn->info) != NULL) + ns_delete (ns); + + route_table_finish (ns_table); + ns_table = NULL; +} + +/* Create a socket for the NS. */ +int +ns_socket (int domain, int type, int protocol, ns_id_t ns_id) +{ + struct ns *ns = ns_lookup (ns_id); + int ret = -1; + + if (!ns_is_enabled (ns)) + { + errno = ENOSYS; + return -1; + } + + if (have_netns()) + { + ret = (ns_id != NS_DEFAULT) ? setns (ns->fd, CLONE_NEWNET) : 0; + if (ret >= 0) + { + ret = socket (domain, type, protocol); + if (ns_id != NS_DEFAULT) + setns (ns_lookup (NS_DEFAULT)->fd, CLONE_NEWNET); + } + } + else + ret = socket (domain, type, protocol); + + return ret; +} diff --git a/lib/ns.h b/lib/ns.h new file mode 100644 index 0000000000..3fac739861 --- /dev/null +++ b/lib/ns.h @@ -0,0 +1,142 @@ +/* + * NS related header. + * Copyright (C) 2014 6WIND S.A. + * + * 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_NS_H +#define _ZEBRA_NS_H + +#include "linklist.h" + +typedef u_int16_t ns_id_t; + +/* The default NS ID */ +#define NS_DEFAULT 0 + +/* + * The command strings + */ +#define NS_RUN_DIR "/var/run/netns" +#define NS_CMD_STR "logical-router <0-65535>" +#define NS_CMD_HELP_STR "Specify the Logical-Router\nThe Logical-Router ID\n" + +#define NS_ALL_CMD_STR "logical-router all" +#define NS_ALL_CMD_HELP_STR "Specify the logical-router\nAll logical-router's\n" + +/* + * NS hooks + */ + +#define NS_NEW_HOOK 0 /* a new logical-router is just created */ +#define NS_DELETE_HOOK 1 /* a logical-router is to be deleted */ +#define NS_ENABLE_HOOK 2 /* a logical-router is ready to use */ +#define NS_DISABLE_HOOK 3 /* a logical-router is to be unusable */ + +/* + * Add a specific hook ns module. + * @param1: hook type + * @param2: the callback function + * - param 1: the NS ID + * - param 2: the address of the user data pointer (the user data + * can be stored in or freed from there) + */ +extern void ns_add_hook (int, int (*)(ns_id_t, void **)); + +/* + * NS iteration + */ + +typedef void * ns_iter_t; +#define NS_ITER_INVALID NULL /* invalid value of the iterator */ + +/* + * NS iteration utilities. Example for the usage: + * + * ns_iter_t iter = ns_first(); + * for (; iter != NS_ITER_INVALID; iter = ns_next (iter)) + * + * or + * + * ns_iter_t iter = ns_iterator (); + * for (; iter != NS_ITER_INVALID; iter = ns_next (iter)) + */ + +/* Return the iterator of the first NS. */ +extern ns_iter_t ns_first (void); +/* Return the next NS iterator to the given iterator. */ +extern ns_iter_t ns_next (ns_iter_t); +/* Return the NS iterator of the given NS ID. If it does not exist, + * the iterator of the next existing NS is returned. */ +extern ns_iter_t ns_iterator (ns_id_t); + +/* + * NS iterator to properties + */ +extern ns_id_t ns_iter2id (ns_iter_t); +extern void *ns_iter2info (ns_iter_t); +extern struct list *ns_iter2iflist (ns_iter_t); + +/* + * Utilities to obtain the user data + */ + +/* Get the data pointer of the specified NS. If not found, create one. */ +extern void *ns_info_get (ns_id_t); +/* Look up the data pointer of the specified NS. */ +extern void *ns_info_lookup (ns_id_t); + +/* + * Utilities to obtain the interface list + */ + +/* Look up the interface list of the specified NS. */ +extern struct list *ns_iflist (ns_id_t); +/* Get the interface list of the specified NS. Create one if not find. */ +extern struct list *ns_iflist_get (ns_id_t); + +/* + * NS bit-map: maintaining flags, one bit per NS ID + */ + +typedef void * ns_bitmap_t; +#define NS_BITMAP_NULL NULL + +extern ns_bitmap_t ns_bitmap_init (void); +extern void ns_bitmap_free (ns_bitmap_t); +extern void ns_bitmap_set (ns_bitmap_t, ns_id_t); +extern void ns_bitmap_unset (ns_bitmap_t, ns_id_t); +extern int ns_bitmap_check (ns_bitmap_t, ns_id_t); + +/* + * NS initializer/destructor + */ +/* Please add hooks before calling ns_init(). */ +extern void ns_init (void); +extern void ns_terminate (void); + +/* + * NS utilities + */ + +/* Create a socket serving for the given NS */ +extern int ns_socket (int, int, int, ns_id_t); + +#endif /*_ZEBRA_NS_H*/ + diff --git a/lib/plist.c b/lib/plist.c index a1289801c4..7bb80fa2a4 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -958,6 +958,11 @@ vty_prefix_list_install (struct vty *vty, afi_t afi, const char *name, return CMD_WARNING; } break; + case AFI_ETHER: + default: + vty_out (vty, "%% Unrecognized AFI (%d)%s", afi, VTY_NEWLINE); + return CMD_WARNING; + break; } /* ge and le check. */ diff --git a/lib/prefix.c b/lib/prefix.c index 256cd3a49a..d2bb028315 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -194,8 +194,9 @@ str2family(const char *string) return AF_INET; else if (!strcmp("ipv6", string)) return AF_INET6; - else - return -1; + else if (!strcmp("ethernet", string)) + return AF_ETHERNET; + return -1; } /* Address Famiy Identifier to Address Family converter. */ @@ -208,6 +209,8 @@ afi2family (afi_t afi) else if (afi == AFI_IP6) return AF_INET6; #endif /* HAVE_IPV6 */ + else if (afi == AFI_ETHER) + return AF_ETHERNET; return 0; } @@ -220,9 +223,27 @@ family2afi (int family) else if (family == AF_INET6) return AFI_IP6; #endif /* HAVE_IPV6 */ + else if (family == AF_ETHERNET) + return AFI_ETHER; return 0; } +const char * +afi2str(afi_t afi) +{ + switch (afi) { + case AFI_IP: + return "IPv4"; + case AFI_IP6: + return "IPv6"; + case AFI_ETHER: + return "ethernet"; + default: + break; + } + return NULL; +} + const char * safi2str(safi_t safi) { @@ -286,6 +307,10 @@ prefix_copy (struct prefix *dest, const struct prefix *src) dest->u.lp.id = src->u.lp.id; dest->u.lp.adv_router = src->u.lp.adv_router; } + else if (src->family == AF_ETHERNET) + { + dest->u.prefix_eth = src->u.prefix_eth; + } else { zlog (NULL, LOG_ERR, "prefix_copy(): Unknown address family %d", @@ -321,6 +346,10 @@ prefix_same (const struct prefix *p1, const struct prefix *p2) if (IPV6_ADDR_SAME (&p1->u.prefix6.s6_addr, &p2->u.prefix6.s6_addr)) return 1; #endif /* HAVE_IPV6 */ + if (p1->family == AF_ETHERNET) { + if (!memcmp(p1->u.prefix_eth.octet, p2->u.prefix_eth.octet, ETHER_ADDR_LEN)) + return 1; + } } return 0; } @@ -412,6 +441,8 @@ prefix_family_str (const struct prefix *p) if (p->family == AF_INET6) return "inet6"; #endif /* HAVE_IPV6 */ + if (p->family == AF_ETHERNET) + return "ether"; return "unspec"; } @@ -482,6 +513,60 @@ str2prefix_ipv4 (const char *str, struct prefix_ipv4 *p) return ret; } +/* When string format is invalid return 0. */ +int +str2prefix_eth (const char *str, struct prefix_eth *p) +{ + int ret = 0; + int plen = 48; + char *pnt; + char *cp = NULL; + const char *str_addr = str; + unsigned int a[6]; + int i; + + /* Find slash inside string. */ + pnt = strchr (str, '/'); + + if (pnt) + { + /* Get prefix length. */ + plen = (u_char) atoi (++pnt); + if (plen > 48) + { + ret = 0; + goto done; + } + + cp = XMALLOC (MTYPE_TMP, (pnt - str) + 1); + strncpy (cp, str, pnt - str); + *(cp + (pnt - str)) = '\0'; + + str_addr = cp; + } + + /* Convert string to prefix. */ + if (sscanf(str_addr, "%2x:%2x:%2x:%2x:%2x:%2x", + a+0, a+1, a+2, a+3, a+4, a+5) != 6) + { + ret = 0; + goto done; + } + for (i = 0; i < 6; ++i) + { + p->eth_addr.octet[i] = a[i] & 0xff; + } + p->prefixlen = plen; + p->family = AF_ETHERNET; + ret = 1; + +done: + if (cp) + XFREE (MTYPE_TMP, cp); + + return ret; +} + /* Convert masklen into IP address's netmask (network byte order). */ void masklen2ip (const int masklen, struct in_addr *netmask) @@ -572,7 +657,7 @@ str2prefix_ipv6 (const char *str, struct prefix_ipv6 *p) { int plen; - cp = XMALLOC (0, (pnt - str) + 1); + cp = XMALLOC (MTYPE_TMP, (pnt - str) + 1); strncpy (cp, str, pnt - str); *(cp + (pnt - str)) = '\0'; ret = inet_pton (AF_INET6, cp, &p->prefix); @@ -768,6 +853,8 @@ prefix_blen (const struct prefix *p) return IPV6_MAX_BYTELEN; break; #endif /* HAVE_IPV6 */ + case AF_ETHERNET: + return ETHER_ADDR_LEN; } return 0; } @@ -790,6 +877,11 @@ str2prefix (const char *str, struct prefix *p) return ret; #endif /* HAVE_IPV6 */ + /* Next we try to convert string to struct prefix_eth. */ + ret = str2prefix_eth (str, (struct prefix_eth *) p); + if (ret) + return ret; + return 0; } @@ -799,6 +891,24 @@ prefix2str (union prefix46constptr pu, char *str, int size) const struct prefix *p = pu.p; char buf[PREFIX2STR_BUFFER]; + if (p->family == AF_ETHERNET) { + int i; + char *s = str; + + assert(size > (3*ETHER_ADDR_LEN) + 1 /* slash */ + 3 /* plen */ ); + for (i = 0; i < ETHER_ADDR_LEN; ++i) { + sprintf(s, "%02x", p->u.prefix_eth.octet[i]); + if (i < (ETHER_ADDR_LEN - 1)) { + *(s+2) = ':'; + s += 3; + } else { + s += 2; + } + } + sprintf(s, "/%d", p->prefixlen); + return 0; + } + snprintf (str, size, "%s/%d", inet_ntop (p->family, &p->u.prefix, buf, PREFIX2STR_BUFFER), p->prefixlen); diff --git a/lib/prefix.h b/lib/prefix.h index 39c2b62019..85488ccea7 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -23,8 +23,30 @@ #ifndef _ZEBRA_PREFIX_H #define _ZEBRA_PREFIX_H +#ifdef SUNOS_5 +# include +#else +# ifdef GNU_LINUX +# include +# else +# include +# endif +#endif #include "sockunion.h" +#ifndef ETHER_ADDR_LEN +#define ETHER_ADDR_LEN ETHERADDRL +#endif + +/* + * there isn't a portable ethernet address type. We define our + * own to simplify internal handling + */ +struct ethaddr { + u_char octet[ETHER_ADDR_LEN]; +} __packed; + + /* * A struct prefix contains an address family, a prefix length, and an * address. This can represent either a 'network prefix' as defined @@ -34,6 +56,15 @@ * interface. */ +/* different OSes use different names */ +#if defined(AF_PACKET) +#define AF_ETHERNET AF_PACKET +#else +#if defined(AF_LINK) +#define AF_ETHERNET AF_LINK +#endif +#endif + /* IPv4 and IPv6 unified prefix structure. */ struct prefix { @@ -51,6 +82,7 @@ struct prefix struct in_addr id; struct in_addr adv_router; } lp; + struct ethaddr prefix_eth; /* AF_ETHERNET */ u_char val[8]; uintptr_t ptr; } u __attribute__ ((aligned (8))); @@ -90,6 +122,14 @@ struct prefix_rd u_char val[8] __attribute__ ((aligned (8))); }; +/* Prefix for ethernet. */ +struct prefix_eth +{ + u_char family; + u_char prefixlen; + struct ethaddr eth_addr __attribute__ ((aligned (8))); /* AF_ETHERNET */ +}; + /* Prefix for a generic pointer */ struct prefix_ptr { @@ -174,6 +214,7 @@ extern int str2family(const char *); extern int afi2family (afi_t); extern afi_t family2afi (int); extern const char *safi2str(safi_t safi); +extern const char *afi2str(afi_t afi); /* Check bit of the prefix. */ extern unsigned int prefix_bit (const u_char *prefix, const u_char prefixlen); @@ -205,6 +246,8 @@ extern struct prefix *sockunion2prefix (const union sockunion *dest, extern struct prefix *sockunion2hostprefix (const union sockunion *, struct prefix *p); extern void prefix2sockunion (const struct prefix *, union sockunion *); +extern int str2prefix_eth (const char *, struct prefix_eth *); + extern struct prefix_ipv4 *prefix_ipv4_new (void); extern void prefix_ipv4_free (struct prefix_ipv4 *); extern int str2prefix_ipv4 (const char *, struct prefix_ipv4 *); diff --git a/lib/privs.c b/lib/privs.c index e6d76b600b..3fb96aed12 100644 --- a/lib/privs.c +++ b/lib/privs.c @@ -307,11 +307,18 @@ zprivs_caps_init (struct zebra_privs_t *zprivs) current_caps = cap_get_proc(); if (current_caps) + { current_caps_text = cap_to_text(current_caps, NULL); + cap_free(current_caps); + } wanted_caps_text = cap_to_text(zprivs_state.caps, NULL); fprintf(stderr, "Wanted caps: %s\n", wanted_caps_text ? wanted_caps_text : "???"); fprintf(stderr, "Have caps: %s\n", current_caps_text ? current_caps_text : "???"); + if (current_caps_text) + cap_free(current_caps_text); + if (wanted_caps_text) + cap_free(wanted_caps_text); exit (1); } diff --git a/lib/routemap.c b/lib/routemap.c index d8d1872d65..9267056df6 100644 --- a/lib/routemap.c +++ b/lib/routemap.c @@ -1591,7 +1591,7 @@ DEFUN (rmap_onmatch_goto, } if (argc == 1 && argv[0]) - VTY_GET_INTEGER_RANGE("route-map index", d, argv[0], 1, 65536); + VTY_GET_INTEGER_RANGE("route-map index", d, argv[0], 1, 65535); else d = index->pref + 1; @@ -1669,7 +1669,7 @@ DEFUN (rmap_show_name, ALIAS (rmap_onmatch_goto, rmap_continue_index_cmd, - "continue <1-65536>", + "continue <1-65535>", "Exit policy on matches\n" "Goto Clause number\n") diff --git a/lib/sigevent.c b/lib/sigevent.c index c80a729012..a120028d81 100644 --- a/lib/sigevent.c +++ b/lib/sigevent.c @@ -237,6 +237,8 @@ core_handler(int signo , siginfo, program_counter(context) #endif ); + /* dump memory stats on core */ + log_memstats_stderr ("core_handler"); abort(); } diff --git a/lib/sockopt.c b/lib/sockopt.c index 257271bc0b..31b2edbacf 100644 --- a/lib/sockopt.c +++ b/lib/sockopt.c @@ -219,8 +219,9 @@ setsockopt_ipv6_tclass(int sock, int tclass) int setsockopt_ipv4_multicast(int sock, int optname, + struct in_addr if_addr, unsigned int mcast_addr, - unsigned int ifindex) + ifindex_t ifindex) { #ifdef HAVE_RFC3678 struct group_req gr; @@ -279,18 +280,20 @@ setsockopt_ipv4_multicast(int sock, #elif defined(HAVE_BSD_STRUCT_IP_MREQ_HACK) /* #if OS_TYPE */ /* standard BSD API */ - struct in_addr m; struct ip_mreq mreq; int ret; assert(optname == IP_ADD_MEMBERSHIP || optname == IP_DROP_MEMBERSHIP); - m.s_addr = htonl(ifindex); memset (&mreq, 0, sizeof(mreq)); mreq.imr_multiaddr.s_addr = mcast_addr; - mreq.imr_interface = m; - +#if !defined __OpenBSD__ + mreq.imr_interface.s_addr = htonl (ifindex); +#else + mreq.imr_interface.s_addr = if_addr.s_addr; +#endif + ret = setsockopt (sock, IPPROTO_IP, optname, (void *)&mreq, sizeof(mreq)); if ((ret < 0) && (optname == IP_ADD_MEMBERSHIP) && (errno == EADDRINUSE)) { @@ -318,8 +321,8 @@ setsockopt_ipv4_multicast(int sock, * Set IP_MULTICAST_IF socket option in an OS-dependent manner. */ int -setsockopt_ipv4_multicast_if(int sock, - unsigned int ifindex) +setsockopt_ipv4_multicast_if(int sock, struct in_addr if_addr, + ifindex_t ifindex) { #ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX @@ -336,7 +339,11 @@ setsockopt_ipv4_multicast_if(int sock, #elif defined(HAVE_BSD_STRUCT_IP_MREQ_HACK) struct in_addr m; - m.s_addr = htonl(ifindex); +#if !defined __OpenBSD__ + m.s_addr = htonl (ifindex); +#else + m.s_addr = if_addr.s_addr; +#endif return setsockopt (sock, IPPROTO_IP, IP_MULTICAST_IF, (void *)&m, sizeof(m)); #else @@ -345,7 +352,7 @@ setsockopt_ipv4_multicast_if(int sock, } static int -setsockopt_ipv4_ifindex (int sock, int val) +setsockopt_ipv4_ifindex (int sock, ifindex_t val) { int ret; @@ -381,7 +388,7 @@ setsockopt_ipv4_tos(int sock, int tos) int -setsockopt_ifindex (int af, int sock, int val) +setsockopt_ifindex (int af, int sock, ifindex_t val) { int ret = -1; @@ -408,11 +415,11 @@ setsockopt_ifindex (int af, int sock, int val) * Returns the interface index (small integer >= 1) if it can be * determined, or else 0. */ -static int +static ifindex_t getsockopt_ipv4_ifindex (struct msghdr *msgh) { /* XXX: initialize to zero? (Always overwritten, so just cosmetic.) */ - int ifindex = -1; + ifindex_t ifindex = -1; #if defined(IP_PKTINFO) /* Linux pktinfo based ifindex retrieval */ @@ -432,7 +439,7 @@ getsockopt_ipv4_ifindex (struct msghdr *msgh) struct sockaddr_dl *sdl; #else /* SUNOS_5 uses an integer with the index. */ - int *ifindex_p; + ifindex_t *ifindex_p; #endif /* SUNOS_5 */ #ifndef SUNOS_5 @@ -473,7 +480,7 @@ getsockopt_ipv4_ifindex (struct msghdr *msgh) } /* return ifindex, 0 if none found */ -int +ifindex_t getsockopt_ifindex (int af, struct msghdr *msgh) { switch (af) diff --git a/lib/sockopt.h b/lib/sockopt.h index cb14efc7ba..d67b510b66 100644 --- a/lib/sockopt.h +++ b/lib/sockopt.h @@ -83,16 +83,17 @@ extern int setsockopt_ipv6_tclass (int, int); (((af) == AF_INET) : SOPT_SIZE_CMSG_IFINDEX_IPV4() \ ? SOPT_SIZE_CMSG_PKTINFO_IPV6()) -extern int setsockopt_ipv4_multicast_if(int sock, - unsigned int ifindex); +extern int setsockopt_ipv4_multicast_if(int sock, struct in_addr if_addr, + ifindex_t ifindex); extern int setsockopt_ipv4_multicast(int sock, int optname, + struct in_addr if_addr, unsigned int mcast_addr, - unsigned int ifindex); + ifindex_t ifindex); extern int setsockopt_ipv4_tos(int sock, int tos); /* Ask for, and get, ifindex, by whatever method is supported. */ -extern int setsockopt_ifindex (int, int, int); -extern int getsockopt_ifindex (int, struct msghdr *); +extern int setsockopt_ifindex (int, int, ifindex_t); +extern ifindex_t getsockopt_ifindex (int, struct msghdr *); /* swab the fields in iph between the host order and system order expected * for IP_HDRINCL. diff --git a/lib/sockunion.c b/lib/sockunion.c index b5a2eb954a..9184e500fc 100644 --- a/lib/sockunion.c +++ b/lib/sockunion.c @@ -291,7 +291,7 @@ sockunion_sizeof (const union sockunion *su) 1 : connect is in progress */ enum connect_result sockunion_connect (int fd, const union sockunion *peersu, unsigned short port, - unsigned int ifindex) + ifindex_t ifindex) { int ret; int val; diff --git a/lib/sockunion.h b/lib/sockunion.h index a33051ae57..105b11a24c 100644 --- a/lib/sockunion.h +++ b/lib/sockunion.h @@ -24,6 +24,7 @@ #define _ZEBRA_SOCKUNION_H #include "privs.h" +#include "if.h" union sockunion { @@ -95,7 +96,7 @@ extern int sockunion_socket (const union sockunion *su); extern const char *inet_sutop (const union sockunion *su, char *str); extern enum connect_result sockunion_connect (int fd, const union sockunion *su, unsigned short port, - unsigned int); + ifindex_t); extern union sockunion *sockunion_getsockname (int); extern union sockunion *sockunion_getpeername (int); extern union sockunion *sockunion_dup (const union sockunion *); diff --git a/lib/str.c b/lib/str.c index d8f039a094..16f759c074 100644 --- a/lib/str.c +++ b/lib/str.c @@ -54,26 +54,34 @@ snprintf(char *str, size_t size, const char *format, ...) #endif #ifndef HAVE_STRLCPY -/** - * Like strncpy but does not 0 fill the buffer and always null - * terminates. - * - * @param bufsize is the size of the destination buffer. - * - * @return index of the terminating byte. - **/ +/* + * Copy string src to buffer dst of size dsize. At most dsize-1 + * chars will be copied. Always NUL terminates (unless dsize == 0). + * Returns strlen(src); if retval >= dsize, truncation occurred. + */ size_t -strlcpy(char *d, const char *s, size_t bufsize) +strlcpy(char *dst, const char *src, size_t dsize) { - size_t len = strlen(s); - size_t ret = len; - if (bufsize > 0) { - if (len >= bufsize) - len = bufsize-1; - memcpy(d, s, len); - d[len] = 0; + const char *osrc = src; + size_t nleft = dsize; + + /* Copy as many bytes as will fit. */ + if (nleft != 0) { + while (--nleft != 0) { + if ((*dst++ = *src++) == '\0') + break; + } } - return ret; + + /* Not enough room in dst, add NUL and traverse rest of src. */ + if (nleft == 0) { + if (dsize != 0) + *dst = '\0'; /* NUL-terminate dst */ + while (*src++) + ; + } + + return(src - osrc - 1); /* count does not include NUL */ } #endif diff --git a/lib/stream.c b/lib/stream.c index 4c237563a5..809e749fb9 100644 --- a/lib/stream.c +++ b/lib/stream.c @@ -373,6 +373,47 @@ stream_getw_from (struct stream *s, size_t from) return w; } +/* Get next 3-byte from the stream. */ +u_int32_t +stream_get3_from (struct stream *s, size_t from) +{ + u_int32_t l; + + STREAM_VERIFY_SANE(s); + + if (!GETP_VALID (s, from + 3)) + { + STREAM_BOUND_WARN (s, "get 3byte"); + return 0; + } + + l = s->data[from++] << 16; + l |= s->data[from++] << 8; + l |= s->data[from]; + + return l; +} + +u_int32_t +stream_get3 (struct stream *s) +{ + u_int32_t l; + + STREAM_VERIFY_SANE(s); + + if (STREAM_READABLE (s) < 3) + { + STREAM_BOUND_WARN (s, "get 3byte"); + return 0; + } + + l = s->data[s->getp++] << 16; + l |= s->data[s->getp++] << 8; + l |= s->data[s->getp++]; + + return l; +} + /* Get next long word from the stream. */ u_int32_t stream_getl_from (struct stream *s, size_t from) @@ -502,6 +543,28 @@ stream_get_ipv4 (struct stream *s) return l; } +float +stream_getf (struct stream *s) +{ + union { + float r; + uint32_t d; + } u; + u.d = stream_getl (s); + return u.r; +} + +double +stream_getd (struct stream *s) +{ + union { + double r; + uint64_t d; + } u; + u.d = stream_getq (s); + return u.r; +} + /* Copy to source to stream. * * XXX: This uses CHECK_SIZE and hence has funny semantics -> Size will wrap @@ -566,6 +629,25 @@ stream_putw (struct stream *s, u_int16_t w) return 2; } +/* Put long word to the stream. */ +int +stream_put3 (struct stream *s, u_int32_t l) +{ + STREAM_VERIFY_SANE (s); + + if (STREAM_WRITEABLE (s) < 3) + { + STREAM_BOUND_WARN (s, "put"); + return 0; + } + + s->data[s->endp++] = (u_char)(l >> 16); + s->data[s->endp++] = (u_char)(l >> 8); + s->data[s->endp++] = (u_char)l; + + return 3; +} + /* Put long word to the stream. */ int stream_putl (struct stream *s, u_int32_t l) @@ -610,6 +692,28 @@ stream_putq (struct stream *s, uint64_t q) return 8; } +int +stream_putf (struct stream *s, float f) +{ + union { + float i; + uint32_t o; + } u; + u.i = f; + return stream_putl (s, u.o); +} + +int +stream_putd (struct stream *s, double d) +{ + union { + double i; + uint64_t o; + } u; + u.i = d; + return stream_putq (s, u.o); +} + int stream_putc_at (struct stream *s, size_t putp, u_char c) { @@ -643,6 +747,23 @@ stream_putw_at (struct stream *s, size_t putp, u_int16_t w) return 2; } +int +stream_put3_at (struct stream *s, size_t putp, u_int32_t l) +{ + STREAM_VERIFY_SANE(s); + + if (!PUT_AT_VALID (s, putp + 3)) + { + STREAM_BOUND_WARN (s, "put"); + return 0; + } + s->data[putp] = (u_char)(l >> 16); + s->data[putp + 1] = (u_char)(l >> 8); + s->data[putp + 2] = (u_char)l; + + return 3; +} + int stream_putl_at (struct stream *s, size_t putp, u_int32_t l) { diff --git a/lib/stream.h b/lib/stream.h index 738034438c..1e2bc89b32 100644 --- a/lib/stream.h +++ b/lib/stream.h @@ -167,6 +167,8 @@ extern int stream_putc (struct stream *, u_char); extern int stream_putc_at (struct stream *, size_t, u_char); extern int stream_putw (struct stream *, u_int16_t); extern int stream_putw_at (struct stream *, size_t, u_int16_t); +extern int stream_put3 (struct stream *, u_int32_t); +extern int stream_put3_at (struct stream *, size_t, u_int32_t); extern int stream_putl (struct stream *, u_int32_t); extern int stream_putl_at (struct stream *, size_t, u_int32_t); extern int stream_putq (struct stream *, uint64_t); @@ -186,12 +188,20 @@ extern u_char stream_getc (struct stream *); extern u_char stream_getc_from (struct stream *, size_t); extern u_int16_t stream_getw (struct stream *); extern u_int16_t stream_getw_from (struct stream *, size_t); +extern u_int32_t stream_get3 (struct stream *); +extern u_int32_t stream_get3_from (struct stream *, size_t); extern u_int32_t stream_getl (struct stream *); extern u_int32_t stream_getl_from (struct stream *, size_t); extern uint64_t stream_getq (struct stream *); extern uint64_t stream_getq_from (struct stream *, size_t); extern u_int32_t stream_get_ipv4 (struct stream *); +/* IEEE-754 floats */ +extern float stream_getf (struct stream *); +extern double stream_getd (struct stream *); +extern int stream_putf (struct stream *, float); +extern int stream_putd (struct stream *, double); + #undef stream_read #undef stream_write diff --git a/lib/thread.c b/lib/thread.c index 8d75509b1d..a128786c3d 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -32,15 +32,6 @@ #include "command.h" #include "sigevent.h" -#if defined HAVE_SNMP && defined SNMP_AGENTX -#include -#include -#include -#include - -extern int agentx_enabled; -#endif - #if defined(__APPLE__) #include #include @@ -48,12 +39,8 @@ extern int agentx_enabled; /* Recent absolute time of day */ struct timeval recent_time; -static struct timeval last_recent_time; /* Relative time, since startup */ static struct timeval relative_time; -static struct timeval relative_time_base; -/* init flag */ -static unsigned short timers_inited; static struct hash *cpu_record = NULL; @@ -106,27 +93,6 @@ timeval_elapsed (struct timeval a, struct timeval b) + (a.tv_usec - b.tv_usec)); } -#if !defined(HAVE_CLOCK_MONOTONIC) && !defined(__APPLE__) -static void -quagga_gettimeofday_relative_adjust (void) -{ - struct timeval diff; - if (timeval_cmp (recent_time, last_recent_time) < 0) - { - relative_time.tv_sec++; - relative_time.tv_usec = 0; - } - else - { - diff = timeval_subtract (recent_time, last_recent_time); - relative_time.tv_sec += diff.tv_sec; - relative_time.tv_usec += diff.tv_usec; - relative_time = timeval_adjust (relative_time); - } - last_recent_time = recent_time; -} -#endif /* !HAVE_CLOCK_MONOTONIC && !__APPLE__ */ - /* gettimeofday wrapper, to keep recent_time updated */ static int quagga_gettimeofday (struct timeval *tv) @@ -137,12 +103,6 @@ quagga_gettimeofday (struct timeval *tv) if (!(ret = gettimeofday (&recent_time, NULL))) { - /* init... */ - if (!timers_inited) - { - relative_time_base = last_recent_time = recent_time; - timers_inited = 1; - } /* avoid copy if user passed recent_time pointer.. */ if (tv != &recent_time) *tv = recent_time; @@ -182,8 +142,7 @@ quagga_get_relative (struct timeval *tv) return 0; } #else /* !HAVE_CLOCK_MONOTONIC && !__APPLE__ */ - if (!(ret = quagga_gettimeofday (&recent_time))) - quagga_gettimeofday_relative_adjust(); +#error no monotonic clock on this system #endif /* HAVE_CLOCK_MONOTONIC */ if (tv) @@ -192,18 +151,6 @@ quagga_get_relative (struct timeval *tv) return ret; } -/* Get absolute time stamp, but in terms of the internal timer - * Could be wrong, but at least won't go back. - */ -static void -quagga_real_stabilised (struct timeval *tv) -{ - *tv = relative_time_base; - tv->tv_sec += relative_time.tv_sec; - tv->tv_usec += relative_time.tv_usec; - *tv = timeval_adjust (*tv); -} - /* Exported Quagga timestamp function. * Modelled on POSIX clock_gettime. */ @@ -212,29 +159,19 @@ quagga_gettime (enum quagga_clkid clkid, struct timeval *tv) { switch (clkid) { - case QUAGGA_CLK_REALTIME: - return quagga_gettimeofday (tv); case QUAGGA_CLK_MONOTONIC: return quagga_get_relative (tv); - case QUAGGA_CLK_REALTIME_STABILISED: - quagga_real_stabilised (tv); - return 0; default: errno = EINVAL; return -1; } } -/* time_t value in terms of stabilised absolute time. - * replacement for POSIX time() - */ time_t -quagga_time (time_t *t) +quagga_monotime (void) { struct timeval tv; - quagga_real_stabilised (&tv); - if (t) - *t = tv.tv_sec; + quagga_get_relative(&tv); return tv.tv_sec; } @@ -983,6 +920,17 @@ funcname_thread_add_timer_msec (struct thread_master *m, arg, &trel, debugargpass); } +/* Add timer event thread with "millisecond" resolution */ +struct thread * +funcname_thread_add_timer_tv (struct thread_master *m, + int (*func) (struct thread *), + void *arg, struct timeval *tv, + debugargdef) +{ + return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER, + arg, tv, debugargpass); +} + /* Add a background thread, with an optional millisec delay */ struct thread * funcname_thread_add_background (struct thread_master *m, @@ -1343,12 +1291,7 @@ thread_fetch (struct thread_master *m, struct thread *fetch) while (1) { int num = 0; -#if defined HAVE_SNMP && defined SNMP_AGENTX - struct timeval snmp_timer_wait; - int snmpblock = 0; - int fdsetsize; -#endif - + /* Signals pre-empt everything */ quagga_sigevent_process (); @@ -1384,35 +1327,7 @@ thread_fetch (struct thread_master *m, struct thread *fetch) (!timer_wait || (timeval_cmp (*timer_wait, *timer_wait_bg) > 0))) timer_wait = timer_wait_bg; } - -#if defined HAVE_SNMP && defined SNMP_AGENTX - /* When SNMP is enabled, we may have to select() on additional - FD. snmp_select_info() will add them to `readfd'. The trick - with this function is its last argument. We need to set it to - 0 if timer_wait is not NULL and we need to use the provided - new timer only if it is still set to 0. */ - if (agentx_enabled) - { - fdsetsize = FD_SETSIZE; - snmpblock = 1; - if (timer_wait) - { - snmpblock = 0; - memcpy(&snmp_timer_wait, timer_wait, sizeof(struct timeval)); - } -#if defined(HAVE_POLL) - /* clear fdset since there are no other fds in fd_set, - then add injected fds from snmp_select_info into pollset */ - FD_ZERO(&readfd); -#endif - snmp_select_info(&fdsetsize, &readfd, &snmp_timer_wait, &snmpblock); -#if defined(HAVE_POLL) - add_snmp_pollfds(m, &readfd, fdsetsize); -#endif - if (snmpblock == 0) - timer_wait = &snmp_timer_wait; - } -#endif + num = fd_select (m, FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait); /* Signals should get quick treatment */ @@ -1424,30 +1339,6 @@ thread_fetch (struct thread_master *m, struct thread *fetch) return NULL; } -#if defined HAVE_SNMP && defined SNMP_AGENTX -#if defined(HAVE_POLL) - /* re-enter pollfds in fd_set for handling in snmp_read */ - FD_ZERO(&readfd); - nfds_t i; - for (i = m->handler.pfdcount; i < m->handler.pfdcountsnmp; ++i) - { - if (m->handler.pfds[i].revents == POLLIN) - FD_SET(m->handler.pfds[i].fd, &readfd); - } -#endif - if (agentx_enabled) - { - if (num > 0) - snmp_read(&readfd); - else if (num == 0) - { - snmp_timeout(); - run_alarms(); - } - netsnmp_check_outstanding_agent_requests(); - } -#endif - /* Check foreground timers. Historically, they have had higher priority than I/O threads, so let's push them onto the ready list in front of the I/O threads. */ diff --git a/lib/thread.h b/lib/thread.h index 8b42ffe58a..c692142839 100644 --- a/lib/thread.h +++ b/lib/thread.h @@ -130,9 +130,7 @@ struct cpu_thread_history /* Clocks supported by Quagga */ enum quagga_clkid { - QUAGGA_CLK_REALTIME = 0, /* ala gettimeofday() */ - QUAGGA_CLK_MONOTONIC, /* monotonic, against an indeterminate base */ - QUAGGA_CLK_REALTIME_STABILISED, /* like realtime, but non-decrementing */ + QUAGGA_CLK_MONOTONIC = 1, /* monotonic, against an indeterminate base */ }; /* Struct timeval's tv_usec one second value. */ @@ -199,6 +197,7 @@ enum quagga_clkid { #define thread_add_write(m,f,a,v) funcname_thread_add_read_write(THREAD_WRITE,m,f,a,v,#f,__FILE__,__LINE__) #define thread_add_timer(m,f,a,v) funcname_thread_add_timer(m,f,a,v,#f,__FILE__,__LINE__) #define thread_add_timer_msec(m,f,a,v) funcname_thread_add_timer_msec(m,f,a,v,#f,__FILE__,__LINE__) +#define thread_add_timer_tv(m,f,a,v) funcname_thread_add_timer_tv(m,f,a,v,#f,__FILE__,__LINE__) #define thread_add_event(m,f,a,v) funcname_thread_add_event(m,f,a,v,#f,__FILE__,__LINE__) #define thread_execute(m,f,a,v) funcname_thread_execute(m,f,a,v,#f,__FILE__,__LINE__) @@ -219,6 +218,10 @@ extern struct thread *funcname_thread_add_timer (struct thread_master *, extern struct thread *funcname_thread_add_timer_msec (struct thread_master *, int (*)(struct thread *), void *, long, debugargdef); +extern struct thread *funcname_thread_add_timer_tv (struct thread_master *, + int (*)(struct thread *), + void *, struct timeval *, + debugargdef); extern struct thread *funcname_thread_add_event (struct thread_master *, int (*)(struct thread *), void *, int, debugargdef); @@ -253,7 +256,7 @@ extern struct cmd_element clear_thread_cpu_cmd; * all systems, and fully monotonic on /some/ systems. */ extern int quagga_gettime (enum quagga_clkid, struct timeval *); -extern time_t quagga_time (time_t *); +extern time_t quagga_monotime (void); /* Returns elapsed real (wall clock) time. */ extern unsigned long thread_consumed_time(RUSAGE_T *after, RUSAGE_T *before, diff --git a/lib/vty.h b/lib/vty.h index 81251e07bb..599882a382 100644 --- a/lib/vty.h +++ b/lib/vty.h @@ -220,7 +220,7 @@ do { \ #define VTY_GET_INTEGER_RANGE(NAME,V,STR,MIN,MAX) \ do { \ - unsigned long tmpl; \ + unsigned long long tmpl; \ VTY_GET_INTEGER_RANGE_HEART(NAME,tmpl,STR,MIN,MAX); \ (V) = tmpl; \ } while (0) diff --git a/lib/zclient.c b/lib/zclient.c index ef9516c912..753954fd84 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -32,6 +32,7 @@ #include "zclient.h" #include "memory.h" #include "table.h" +#include "nexthop.h" /* Zebra client events. */ enum event {ZCLIENT_SCHEDULE, ZCLIENT_READ, ZCLIENT_CONNECT}; @@ -709,6 +710,8 @@ zclient_connect (struct thread *t) * * If ZAPI_MESSAGE_TAG is set, the tag value is written as a 2 byte value * + * If ZAPI_MESSAGE_MTU is set, the mtu value is written as a 4 byte value + * * XXX: No attention paid to alignment. */ int @@ -744,7 +747,7 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p, if (CHECK_FLAG (api->flags, ZEBRA_FLAG_BLACKHOLE)) { stream_putc (s, 1); - stream_putc (s, ZEBRA_NEXTHOP_BLACKHOLE); + stream_putc (s, NEXTHOP_TYPE_BLACKHOLE); /* XXX assert(api->nexthop_num == 0); */ /* XXX assert(api->ifindex_num == 0); */ } @@ -753,12 +756,12 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p, for (i = 0; i < api->nexthop_num; i++) { - stream_putc (s, ZEBRA_NEXTHOP_IPV4); + stream_putc (s, NEXTHOP_TYPE_IPV4); stream_put_in_addr (s, api->nexthop[i]); } for (i = 0; i < api->ifindex_num; i++) { - stream_putc (s, ZEBRA_NEXTHOP_IFINDEX); + stream_putc (s, NEXTHOP_TYPE_IFINDEX); stream_putl (s, api->ifindex[i]); } } @@ -769,6 +772,8 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p, stream_putl (s, api->metric); if (CHECK_FLAG (api->message, ZAPI_MESSAGE_TAG)) stream_putw (s, api->tag); + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_MTU)) + stream_putl (s, api->mtu); /* Put length at the first point of the stream. */ stream_putw_at (s, 0, stream_get_endp (s)); @@ -809,7 +814,7 @@ zapi_ipv4_route_ipv6_nexthop (u_char cmd, struct zclient *zclient, if (CHECK_FLAG (api->flags, ZEBRA_FLAG_BLACKHOLE)) { stream_putc (s, 1); - stream_putc (s, ZEBRA_NEXTHOP_BLACKHOLE); + stream_putc (s, NEXTHOP_TYPE_BLACKHOLE); /* XXX assert(api->nexthop_num == 0); */ /* XXX assert(api->ifindex_num == 0); */ } @@ -818,12 +823,12 @@ zapi_ipv4_route_ipv6_nexthop (u_char cmd, struct zclient *zclient, for (i = 0; i < api->nexthop_num; i++) { - stream_putc (s, ZEBRA_NEXTHOP_IPV6); + stream_putc (s, NEXTHOP_TYPE_IPV6); stream_write (s, (u_char *)api->nexthop[i], 16); } for (i = 0; i < api->ifindex_num; i++) { - stream_putc (s, ZEBRA_NEXTHOP_IFINDEX); + stream_putc (s, NEXTHOP_TYPE_IFINDEX); stream_putl (s, api->ifindex[i]); } } @@ -834,6 +839,8 @@ zapi_ipv4_route_ipv6_nexthop (u_char cmd, struct zclient *zclient, stream_putl (s, api->metric); if (CHECK_FLAG (api->message, ZAPI_MESSAGE_TAG)) stream_putw (s, api->tag); + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_MTU)) + stream_putl (s, api->mtu); /* Put length at the first point of the stream. */ stream_putw_at (s, 0, stream_get_endp (s)); @@ -873,7 +880,7 @@ zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p, if (CHECK_FLAG (api->flags, ZEBRA_FLAG_BLACKHOLE)) { stream_putc (s, 1); - stream_putc (s, ZEBRA_NEXTHOP_BLACKHOLE); + stream_putc (s, NEXTHOP_TYPE_BLACKHOLE); /* XXX assert(api->nexthop_num == 0); */ /* XXX assert(api->ifindex_num == 0); */ } @@ -882,12 +889,12 @@ zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p, for (i = 0; i < api->nexthop_num; i++) { - stream_putc (s, ZEBRA_NEXTHOP_IPV6); + stream_putc (s, NEXTHOP_TYPE_IPV6); stream_write (s, (u_char *)api->nexthop[i], 16); } for (i = 0; i < api->ifindex_num; i++) { - stream_putc (s, ZEBRA_NEXTHOP_IFINDEX); + stream_putc (s, NEXTHOP_TYPE_IFINDEX); stream_putl (s, api->ifindex[i]); } } @@ -898,6 +905,8 @@ zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p, stream_putl (s, api->metric); if (CHECK_FLAG (api->message, ZAPI_MESSAGE_TAG)) stream_putw (s, api->tag); + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_MTU)) + stream_putl (s, api->mtu); /* Put length at the first point of the stream. */ stream_putw_at (s, 0, stream_get_endp (s)); @@ -951,8 +960,6 @@ zebra_router_id_update_read (struct stream *s, struct prefix *rid) * ZEBRA_INTERFACE_DELETE from zebra to the client is: * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+ - * | type | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | ifname | * | | @@ -960,20 +967,32 @@ zebra_router_id_update_read (struct stream *s, struct prefix *rid) * | | * | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | ifindex | + * | ifindex | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | if_flags | + * | status | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | if_flags | * | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | metric | + * | metric | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | ifmtu | + * | ifmtu | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | ifmtu6 | + * | ifmtu6 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | bandwidth | + * | bandwidth | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | sockaddr_dl | + * | Link Layer Type | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Harware Address Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Hardware Address if HW lenght different from 0 | + * | ... max INTERFACE_HWADDR_MAX | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Link_params? | Whether a link-params follows: 1 or 0. + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Link_params 0 or 1 INTERFACE_LINK_PARAMS_SIZE sized | + * | .... (struct if_link_params). | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ @@ -1062,7 +1081,138 @@ zebra_interface_state_read (struct stream *s, vrf_id_t vrf_id) return ifp; } -/* +static void +link_params_set_value(struct stream *s, struct if_link_params *iflp) +{ + + if (iflp == NULL) + return; + + iflp->lp_status = stream_getl (s); + iflp->te_metric = stream_getl (s); + iflp->max_bw = stream_getf (s); + iflp->max_rsv_bw = stream_getf (s); + uint32_t bwclassnum = stream_getl (s); + { + unsigned int i; + for (i = 0; i < bwclassnum && i < MAX_CLASS_TYPE; i++) + iflp->unrsv_bw[i] = stream_getf (s); + if (i < bwclassnum) + zlog_err ("%s: received %d > %d (MAX_CLASS_TYPE) bw entries" + " - outdated library?", + __func__, bwclassnum, MAX_CLASS_TYPE); + } + iflp->admin_grp = stream_getl (s); + iflp->rmt_as = stream_getl (s); + iflp->rmt_ip.s_addr = stream_get_ipv4 (s); + + iflp->av_delay = stream_getl (s); + iflp->min_delay = stream_getl (s); + iflp->max_delay = stream_getl (s); + iflp->delay_var = stream_getl (s); + + iflp->pkt_loss = stream_getf (s); + iflp->res_bw = stream_getf (s); + iflp->ava_bw = stream_getf (s); + iflp->use_bw = stream_getf (s); +} + +struct interface * +zebra_interface_link_params_read (struct stream *s) +{ + struct if_link_params *iflp; + uint32_t ifindex = stream_getl (s); + + struct interface *ifp = if_lookup_by_index (ifindex); + + if (ifp == NULL || s == NULL) + { + zlog_err ("%s: unknown ifindex %u, shouldn't happen", + __func__, ifindex); + return NULL; + } + + if ((iflp = if_link_params_get (ifp)) == NULL) + return NULL; + + link_params_set_value(s, iflp); + + return ifp; +} + +void +zebra_interface_if_set_value (struct stream *s, struct interface *ifp) +{ + u_char link_params_status = 0; + + /* Read interface's index. */ + ifp->ifindex = stream_getl (s); + ifp->status = stream_getc (s); + + /* Read interface's value. */ + ifp->flags = stream_getq (s); + ifp->ptm_enable = stream_getc (s); + ifp->ptm_status = stream_getc (s); + ifp->metric = stream_getl (s); + ifp->mtu = stream_getl (s); + ifp->mtu6 = stream_getl (s); + ifp->bandwidth = stream_getl (s); + ifp->ll_type = stream_getl (s); + ifp->hw_addr_len = stream_getl (s); + if (ifp->hw_addr_len) + stream_get (ifp->hw_addr, s, MIN(ifp->hw_addr_len, INTERFACE_HWADDR_MAX)); + + /* Read Traffic Engineering status */ + link_params_status = stream_getc (s); + /* Then, Traffic Engineering parameters if any */ + if (link_params_status) + { + struct if_link_params *iflp = if_link_params_get (ifp); + link_params_set_value(s, iflp); + } +} + +size_t +zebra_interface_link_params_write (struct stream *s, struct interface *ifp) +{ + size_t w; + struct if_link_params *iflp; + int i; + + if (s == NULL || ifp == NULL || ifp->link_params == NULL) + return 0; + + iflp = ifp->link_params; + w = 0; + + w += stream_putl (s, iflp->lp_status); + + w += stream_putl (s, iflp->te_metric); + w += stream_putf (s, iflp->max_bw); + w += stream_putf (s, iflp->max_rsv_bw); + + w += stream_putl (s, MAX_CLASS_TYPE); + for (i = 0; i < MAX_CLASS_TYPE; i++) + w += stream_putf (s, iflp->unrsv_bw[i]); + + w += stream_putl (s, iflp->admin_grp); + w += stream_putl (s, iflp->rmt_as); + w += stream_put_in_addr (s, &iflp->rmt_ip); + + w += stream_putl (s, iflp->av_delay); + w += stream_putl (s, iflp->min_delay); + w += stream_putl (s, iflp->max_delay); + w += stream_putl (s, iflp->delay_var); + + w += stream_putf (s, iflp->pkt_loss); + w += stream_putf (s, iflp->res_bw); + w += stream_putf (s, iflp->ava_bw); + w += stream_putf (s, iflp->use_bw); + + return w; +} + +/* * format of message for address additon is: * 0 * 0 1 2 3 4 5 6 7 @@ -1091,33 +1241,8 @@ zebra_interface_state_read (struct stream *s, vrf_id_t vrf_id) * : : * | | * +-+-+-+-+-+-+-+-+ - * */ -void -zebra_interface_if_set_value (struct stream *s, struct interface *ifp) -{ - /* Read interface's index. */ - ifp->ifindex = stream_getl (s); - ifp->status = stream_getc (s); - - /* Read interface's value. */ - ifp->flags = stream_getq (s); - ifp->ptm_enable = stream_getc (s); - ifp->ptm_status = stream_getc (s); - ifp->metric = stream_getl (s); - ifp->mtu = stream_getl (s); - ifp->mtu6 = stream_getl (s); - ifp->bandwidth = stream_getl (s); -#ifdef HAVE_STRUCT_SOCKADDR_DL - stream_get (&ifp->sdl, s, sizeof (ifp->sdl_storage)); -#else - ifp->hw_addr_len = stream_getl (s); - if (ifp->hw_addr_len) - stream_get (ifp->hw_addr, s, MIN(ifp->hw_addr_len, INTERFACE_HWADDR_MAX)); -#endif /* HAVE_STRUCT_SOCKADDR_DL */ -} - static int memconstant(const void *s, int c, size_t n) { @@ -1133,7 +1258,7 @@ memconstant(const void *s, int c, size_t n) struct connected * zebra_interface_address_read (int type, struct stream *s, vrf_id_t vrf_id) { - unsigned int ifindex; + ifindex_t ifindex; struct interface *ifp; struct connected *ifc; struct prefix p, d; @@ -1503,6 +1628,9 @@ zclient_read (struct thread *thread) case ZEBRA_REDISTRIBUTE_IPV6_DEL: if (zclient->redistribute_route_ipv6_del) (*zclient->redistribute_route_ipv6_del) (command, zclient, length, vrf_id); + case ZEBRA_INTERFACE_LINK_PARAMS: + if (zclient->interface_link_params) + (*zclient->interface_link_params) (command, zclient, length); break; default: break; diff --git a/lib/zclient.h b/lib/zclient.h index f30190c1b4..b95d18ec1a 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -93,6 +93,7 @@ struct zclient int (*interface_down) (int, struct zclient *, uint16_t, vrf_id_t); int (*interface_address_add) (int, struct zclient *, uint16_t, vrf_id_t); int (*interface_address_delete) (int, struct zclient *, uint16_t, vrf_id_t); + int (*interface_link_params) (int, struct zclient *, uint16_t); int (*interface_bfd_dest_update) (int, struct zclient *, uint16_t, vrf_id_t); int (*interface_nbr_address_add) (int, struct zclient *, uint16_t, vrf_id_t); int (*interface_nbr_address_delete) (int, struct zclient *, uint16_t, vrf_id_t); @@ -116,6 +117,7 @@ struct zclient #define ZAPI_MESSAGE_DISTANCE 0x04 #define ZAPI_MESSAGE_METRIC 0x08 #define ZAPI_MESSAGE_TAG 0x10 +#define ZAPI_MESSAGE_MTU 0x20 /* Zserv protocol message header */ struct zserv_header @@ -146,7 +148,7 @@ struct zapi_ipv4 struct in_addr **nexthop; u_char ifindex_num; - unsigned int *ifindex; + ifindex_t *ifindex; u_char distance; @@ -154,6 +156,8 @@ struct zapi_ipv4 u_short tag; + u_int32_t mtu; + vrf_id_t vrf_id; }; @@ -211,6 +215,9 @@ extern void zebra_router_id_update_read (struct stream *s, struct prefix *rid); extern int zapi_ipv4_route (u_char, struct zclient *, struct prefix_ipv4 *, struct zapi_ipv4 *); +extern struct interface *zebra_interface_link_params_read (struct stream *); +extern size_t zebra_interface_link_params_write (struct stream *, + struct interface *); #ifdef HAVE_IPV6 /* IPv6 prefix add and delete function prototype. */ @@ -229,7 +236,7 @@ struct zapi_ipv6 struct in6_addr **nexthop; u_char ifindex_num; - unsigned int *ifindex; + ifindex_t *ifindex; u_char distance; @@ -237,6 +244,8 @@ struct zapi_ipv6 u_short tag; + u_int32_t mtu; + vrf_id_t vrf_id; }; diff --git a/lib/zebra.h b/lib/zebra.h index 59c154ba46..fdfd471825 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -445,7 +445,8 @@ struct in_pktinfo #define ZEBRA_INTERFACE_ENABLE_RADV 47 #define ZEBRA_INTERFACE_DISABLE_RADV 48 #define ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB 49 -#define ZEBRA_MESSAGE_MAX 50 +#define ZEBRA_INTERFACE_LINK_PARAMS 50 +#define ZEBRA_MESSAGE_MAX 51 /* Marker value used in new Zserv, in the byte location corresponding * the command value in the old zserv header. To allow old and new @@ -489,20 +490,10 @@ extern const char *zserv_command_string (unsigned int command); #define ZEBRA_FLAG_BLACKHOLE 0x04 #define ZEBRA_FLAG_IBGP 0x08 #define ZEBRA_FLAG_SELECTED 0x10 -#define ZEBRA_FLAG_CHANGED 0x20 #define ZEBRA_FLAG_STATIC 0x40 #define ZEBRA_FLAG_REJECT 0x80 #define ZEBRA_FLAG_SCOPE_LINK 0x100 -/* Zebra nexthop flags. */ -#define ZEBRA_NEXTHOP_IFINDEX 1 -#define ZEBRA_NEXTHOP_IPV4 2 -#define ZEBRA_NEXTHOP_IPV4_IFINDEX 3 -#define ZEBRA_NEXTHOP_IPV6 4 -#define ZEBRA_NEXTHOP_IPV6_IFINDEX 5 -#define ZEBRA_NEXTHOP_BLACKHOLE 6 -#define ZEBRA_NEXTHOP_IPV4_ONLINK 7 - #ifndef INADDR_LOOPBACK #define INADDR_LOOPBACK 0x7f000001 /* Internet address 127.0.0.1. */ #endif @@ -511,7 +502,8 @@ extern const char *zserv_command_string (unsigned int command); typedef enum { AFI_IP = 1, AFI_IP6 = 2, -#define AFI_MAX 3 + AFI_ETHER = 3, /* RFC 1700 has "6" for 802.* */ + AFI_MAX = 4 } afi_t; /* Subsequent Address Family Identifier. */ @@ -522,11 +514,6 @@ typedef enum { #define SAFI_ENCAP 7 /* per IANA */ #define SAFI_MAX 8 -/* Filter direction. */ -#define FILTER_IN 0 -#define FILTER_OUT 1 -#define FILTER_MAX 2 - /* Default Administrative Distance of each protocol. */ #define ZEBRA_KERNEL_DISTANCE_DEFAULT 0 #define ZEBRA_CONNECT_DISTANCE_DEFAULT 0 diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 1207419e58..208d3b8c4c 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -426,7 +426,7 @@ ospf6_asbr_send_externals_to_area (struct ospf6_area *oa) } void -ospf6_asbr_redistribute_add (int type, int ifindex, struct prefix *prefix, +ospf6_asbr_redistribute_add (int type, ifindex_t ifindex, struct prefix *prefix, u_int nexthop_num, struct in6_addr *nexthop) { int ret; @@ -575,7 +575,8 @@ ospf6_asbr_redistribute_add (int type, int ifindex, struct prefix *prefix, } void -ospf6_asbr_redistribute_remove (int type, int ifindex, struct prefix *prefix) +ospf6_asbr_redistribute_remove (int type, ifindex_t ifindex, + struct prefix *prefix) { struct ospf6_route *match; struct ospf6_external_info *info = NULL; diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h index 90befdc0dd..645e8fd9cf 100644 --- a/ospf6d/ospf6_asbr.h +++ b/ospf6d/ospf6_asbr.h @@ -49,7 +49,7 @@ struct ospf6_external_info struct in6_addr forwarding; /* u_int32_t tag; */ - unsigned int ifindex; + ifindex_t ifindex; }; /* AS-External-LSA */ @@ -79,11 +79,11 @@ extern void ospf6_asbr_lsentry_add (struct ospf6_route *asbr_entry); extern void ospf6_asbr_lsentry_remove (struct ospf6_route *asbr_entry); extern int ospf6_asbr_is_asbr (struct ospf6 *o); -extern void ospf6_asbr_redistribute_add (int type, int ifindex, +extern void ospf6_asbr_redistribute_add (int type, ifindex_t ifindex, struct prefix *prefix, u_int nexthop_num, struct in6_addr *nexthop); -extern void ospf6_asbr_redistribute_remove (int type, int ifindex, +extern void ospf6_asbr_redistribute_remove (int type, ifindex_t ifindex, struct prefix *prefix); extern int ospf6_redistribute_config_write (struct vty *vty); diff --git a/ospf6d/ospf6_bfd.c b/ospf6d/ospf6_bfd.c index 503c7e0cd7..f9bb6f0031 100644 --- a/ospf6d/ospf6_bfd.c +++ b/ospf6d/ospf6_bfd.c @@ -420,7 +420,4 @@ ospf6_bfd_init(void) install_element (INTERFACE_NODE, &ipv6_ospf6_bfd_cmd); install_element (INTERFACE_NODE, &ipv6_ospf6_bfd_param_cmd); install_element (INTERFACE_NODE, &no_ipv6_ospf6_bfd_cmd); - - /* Send the client registration */ - bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER); } diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index 720a3e0e69..f24ec46da7 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -61,7 +61,7 @@ const char *ospf6_interface_state_str[] = }; struct ospf6_interface * -ospf6_interface_lookup_by_ifindex (int ifindex) +ospf6_interface_lookup_by_ifindex (ifindex_t ifindex) { struct ospf6_interface *oi; struct interface *ifp; diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h index 5e6b455682..3e09bfb930 100644 --- a/ospf6d/ospf6_interface.h +++ b/ospf6d/ospf6_interface.h @@ -152,7 +152,7 @@ extern const char *ospf6_interface_state_str[]; /* Function Prototypes */ -extern struct ospf6_interface *ospf6_interface_lookup_by_ifindex (int); +extern struct ospf6_interface *ospf6_interface_lookup_by_ifindex (ifindex_t); extern struct ospf6_interface *ospf6_interface_create (struct interface *); extern void ospf6_interface_delete (struct ospf6_interface *); diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c index 3f008d3d9f..35e5a91544 100644 --- a/ospf6d/ospf6_lsa.c +++ b/ospf6d/ospf6_lsa.c @@ -818,7 +818,7 @@ ospf6_lsa_handler_name (struct ospf6_lsa_handler *h) DEFUN (debug_ospf6_lsa_type, debug_ospf6_lsa_hex_cmd, - "debug ospf6 lsa (router|network|inter-prefix|inter-router|as-ext|grp-mbr|type7|link|intra-prefix|unknown)", + "debug ospf6 lsa (router|network|inter-prefix|inter-router|as-external|link|intra-prefix|unknown)", DEBUG_STR OSPF6_STR "Debug Link State Advertisements (LSAs)\n" @@ -862,7 +862,7 @@ DEFUN (debug_ospf6_lsa_type, ALIAS (debug_ospf6_lsa_type, debug_ospf6_lsa_hex_detail_cmd, - "debug ospf6 lsa (router|network|inter-prefix|inter-router|as-ext|grp-mbr|type7|link|intra-prefix|unknown) (originate|examine|flooding)", + "debug ospf6 lsa (router|network|inter-prefix|inter-router|as-external|link|intra-prefix|unknown) (originate|examine|flooding)", DEBUG_STR OSPF6_STR "Debug Link State Advertisements (LSAs)\n" @@ -871,7 +871,7 @@ ALIAS (debug_ospf6_lsa_type, DEFUN (no_debug_ospf6_lsa_type, no_debug_ospf6_lsa_hex_cmd, - "no debug ospf6 lsa (router|network|inter-prefix|inter-router|as-ext|grp-mbr|type7|link|intra-prefix|unknown)", + "no debug ospf6 lsa (router|network|inter-prefix|inter-router|as-external|link|intra-prefix|unknown)", NO_STR DEBUG_STR OSPF6_STR @@ -915,7 +915,7 @@ DEFUN (no_debug_ospf6_lsa_type, ALIAS (no_debug_ospf6_lsa_type, no_debug_ospf6_lsa_hex_detail_cmd, - "no debug ospf6 lsa (router|network|inter-prefix|inter-router|as-ext|grp-mbr|type7|link|intra-prefix) (originate|examine|flooding)", + "no debug ospf6 lsa (router|network|inter-prefix|inter-router|as-external|link|intra-prefix) (originate|examine|flooding)", NO_STR DEBUG_STR OSPF6_STR diff --git a/ospf6d/ospf6_main.c b/ospf6d/ospf6_main.c index c989a5a10a..a368b05304 100644 --- a/ospf6d/ospf6_main.c +++ b/ospf6d/ospf6_main.c @@ -321,7 +321,9 @@ main (int argc, char *argv[], char *envp[]) LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); zprivs_init (&ospf6d_privs); - zlog_set_file (NULL, LOG_DEFAULT_FILENAME, zlog_default->default_lvl); +#if defined(HAVE_CUMULUS) + zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl); +#endif /* initialize zebra libraries */ signal_init (master, array_size(ospf6_signals), ospf6_signals); diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index fe57f2f423..b0e94288b4 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -290,7 +290,7 @@ ospf6_hello_recv (struct in6_addr *src, struct in6_addr *dst, memcpy (&on->linklocal_addr, src, sizeof (struct in6_addr)); /* Neighbor ifindex check */ - if (on->ifindex != ntohl (hello->interface_id)) + if (on->ifindex != (ifindex_t)ntohl (hello->interface_id)) { on->ifindex = ntohl (hello->interface_id); neighbor_ifindex_change++; @@ -1525,7 +1525,7 @@ ospf6_receive (struct thread *thread) unsigned int len; char srcname[64], dstname[64]; struct in6_addr src, dst; - unsigned int ifindex; + ifindex_t ifindex; struct iovec iovector[2]; struct ospf6_interface *oi; struct ospf6_header *oh; diff --git a/ospf6d/ospf6_message.h b/ospf6d/ospf6_message.h index b085a9673b..4a9e0c7a66 100644 --- a/ospf6d/ospf6_message.h +++ b/ospf6d/ospf6_message.h @@ -64,7 +64,7 @@ struct ospf6_header #define OSPF6_HELLO_MIN_SIZE 20U struct ospf6_hello { - u_int32_t interface_id; + ifindex_t interface_id; u_char priority; u_char options[3]; u_int16_t hello_interval; diff --git a/ospf6d/ospf6_neighbor.h b/ospf6d/ospf6_neighbor.h index fad7fd578a..f9e197e99b 100644 --- a/ospf6d/ospf6_neighbor.h +++ b/ospf6d/ospf6_neighbor.h @@ -53,7 +53,7 @@ struct ospf6_neighbor u_int32_t router_id; /* Neighbor Interface ID */ - u_int32_t ifindex; + ifindex_t ifindex; /* Router Priority of this neighbor */ u_char priority; diff --git a/ospf6d/ospf6_network.c b/ospf6d/ospf6_network.c index 7b1cf91932..2227d03477 100644 --- a/ospf6d/ospf6_network.c +++ b/ospf6d/ospf6_network.c @@ -113,7 +113,7 @@ ospf6_serv_sock (void) /* ospf6 set socket option */ int -ospf6_sso (u_int ifindex, struct in6_addr *group, int option) +ospf6_sso (ifindex_t ifindex, struct in6_addr *group, int option) { struct ipv6_mreq mreq6; int ret; @@ -193,19 +193,23 @@ iov_totallen (struct iovec *iov) int ospf6_sendmsg (struct in6_addr *src, struct in6_addr *dst, - unsigned int *ifindex, struct iovec *message) + ifindex_t *ifindex, struct iovec *message) { int retval; struct msghdr smsghdr; struct cmsghdr *scmsgp; - u_char cmsgbuf[CMSG_SPACE(sizeof (struct in6_pktinfo))]; + union + { + struct cmsghdr hdr; + u_char buf[CMSG_SPACE (sizeof (struct in6_pktinfo))]; + } cmsgbuf; struct in6_pktinfo *pktinfo; struct sockaddr_in6 dst_sin6; assert (dst); assert (*ifindex); - scmsgp = (struct cmsghdr *)cmsgbuf; + scmsgp = (struct cmsghdr *)&cmsgbuf; pktinfo = (struct in6_pktinfo *)(CMSG_DATA(scmsgp)); memset (&dst_sin6, 0, sizeof (struct sockaddr_in6)); @@ -222,7 +226,7 @@ ospf6_sendmsg (struct in6_addr *src, struct in6_addr *dst, dst_sin6.sin6_len = sizeof (struct sockaddr_in6); #endif /*SIN6_LEN*/ memcpy (&dst_sin6.sin6_addr, dst, sizeof (struct in6_addr)); -#ifdef HAVE_SIN6_SCOPE_ID +#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID dst_sin6.sin6_scope_id = *ifindex; #endif @@ -238,8 +242,8 @@ ospf6_sendmsg (struct in6_addr *src, struct in6_addr *dst, smsghdr.msg_iovlen = iov_count (message); smsghdr.msg_name = (caddr_t) &dst_sin6; smsghdr.msg_namelen = sizeof (struct sockaddr_in6); - smsghdr.msg_control = (caddr_t) cmsgbuf; - smsghdr.msg_controllen = scmsgp->cmsg_len; + smsghdr.msg_control = (caddr_t) &cmsgbuf.buf; + smsghdr.msg_controllen = sizeof(cmsgbuf.buf); retval = sendmsg (ospf6_sock, &smsghdr, 0); if (retval != iov_totallen (message)) @@ -251,7 +255,7 @@ ospf6_sendmsg (struct in6_addr *src, struct in6_addr *dst, int ospf6_recvmsg (struct in6_addr *src, struct in6_addr *dst, - unsigned int *ifindex, struct iovec *message) + ifindex_t *ifindex, struct iovec *message) { int retval; struct msghdr rmsghdr; diff --git a/ospf6d/ospf6_network.h b/ospf6d/ospf6_network.h index 2aeafe5041..4fa2839519 100644 --- a/ospf6d/ospf6_network.h +++ b/ospf6d/ospf6_network.h @@ -29,12 +29,12 @@ extern struct in6_addr allspfrouters6; extern struct in6_addr alldrouters6; extern int ospf6_serv_sock (void); -extern int ospf6_sso (u_int ifindex, struct in6_addr *group, int option); +extern int ospf6_sso (ifindex_t ifindex, struct in6_addr *group, int option); extern int ospf6_sendmsg (struct in6_addr *, struct in6_addr *, - unsigned int *, struct iovec *); + ifindex_t *, struct iovec *); extern int ospf6_recvmsg (struct in6_addr *, struct in6_addr *, - unsigned int *, struct iovec *); + ifindex_t *, struct iovec *); #endif /* OSPF6_NETWORK_H */ diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c index 0a98c8f082..5172eee48d 100644 --- a/ospf6d/ospf6_route.c +++ b/ospf6d/ospf6_route.c @@ -331,7 +331,7 @@ ospf6_add_nexthop (struct list *nh_list, int ifindex, void ospf6_route_zebra_copy_nexthops (struct ospf6_route *route, - unsigned int *ifindexes, + ifindex_t *ifindexes, struct in6_addr **nexthop_addr, int entries) { diff --git a/ospf6d/ospf6_route.h b/ospf6d/ospf6_route.h index e783b72d8e..610b0970b0 100644 --- a/ospf6d/ospf6_route.h +++ b/ospf6d/ospf6_route.h @@ -41,7 +41,7 @@ extern unsigned char conf_debug_ospf6_route; struct ospf6_nexthop { /* Interface index */ - unsigned int ifindex; + ifindex_t ifindex; /* IP address, if any */ struct in6_addr address; @@ -278,7 +278,7 @@ extern int ospf6_num_nexthops (struct list *nh_list); extern int ospf6_route_cmp_nexthops (struct ospf6_route *a, struct ospf6_route *b); extern void ospf6_route_zebra_copy_nexthops (struct ospf6_route *route, - unsigned int *ifindices, + ifindex_t *ifindices, struct in6_addr **addr, int entries); extern int ospf6_route_get_first_nh_index (struct ospf6_route *route); diff --git a/ospf6d/ospf6_snmp.c b/ospf6d/ospf6_snmp.c index 307d420ece..382cf62f72 100644 --- a/ospf6d/ospf6_snmp.c +++ b/ospf6d/ospf6_snmp.c @@ -29,6 +29,8 @@ #include "log.h" #include "vty.h" #include "linklist.h" +#include "vector.h" +#include "vrf.h" #include "smux.h" #include "ospf6_proto.h" @@ -205,8 +207,8 @@ SNMP_LOCAL_VARIABLES /* OSPFv3-MIB instances. */ -oid ospfv3_oid [] = { OSPFv3MIB }; -oid ospfv3_trap_oid [] = { OSPFv3MIB, 0 }; +static oid ospfv3_oid [] = { OSPFv3MIB }; +static oid ospfv3_trap_oid [] = { OSPFv3MIB, 0 }; /* Hook functions. */ static u_char *ospfv3GeneralGroup (struct variable *, oid *, size_t *, @@ -220,7 +222,7 @@ static u_char *ospfv3NbrEntry (struct variable *, oid *, size_t *, static u_char *ospfv3IfEntry (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); -struct variable ospfv3_variables[] = +static struct variable ospfv3_variables[] = { /* OSPF general variables */ {OSPFv3ROUTERID, UNSIGNED, RWRITE, ospfv3GeneralGroup, @@ -623,7 +625,7 @@ ospfv3WwLsdbEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { struct ospf6_lsa *lsa = NULL; - u_int32_t ifindex, area_id, id, instid, adv_router; + ifindex_t ifindex, area_id, id, instid, adv_router; u_int16_t type; int len; oid *offset; @@ -749,7 +751,7 @@ ospfv3WwLsdbEntry (struct variable *v, oid *name, size_t *length, ifslist = list_new (); if (!ifslist) return NULL; ifslist->cmp = (int (*)(void *, void *))if_icmp_func; - for (ALL_LIST_ELEMENTS_RO (iflist, node, iif)) + for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, iif)) listnode_add_sort (ifslist, iif); for (ALL_LIST_ELEMENTS_RO (ifslist, node, iif)) @@ -835,7 +837,8 @@ static u_char * ospfv3IfEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { - unsigned int ifindex, instid; + ifindex_t ifindex = 0; + unsigned int instid = 0; struct ospf6_interface *oi = NULL; struct ospf6_lsa *lsa = NULL; struct interface *iif; @@ -849,8 +852,6 @@ ospfv3IfEntry (struct variable *v, oid *name, size_t *length, == MATCH_FAILED) return NULL; - ifindex = instid = 0; - /* Check OSPFv3 instance. */ if (ospf6 == NULL) return NULL; @@ -887,7 +888,7 @@ ospfv3IfEntry (struct variable *v, oid *name, size_t *length, ifslist = list_new (); if (!ifslist) return NULL; ifslist->cmp = (int (*)(void *, void *))if_icmp_func; - for (ALL_LIST_ELEMENTS_RO (iflist, i, iif)) + for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), i, iif)) listnode_add_sort (ifslist, iif); for (ALL_LIST_ELEMENTS_RO (ifslist, i, iif)) @@ -988,7 +989,8 @@ static u_char * ospfv3NbrEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { - unsigned int ifindex, instid, rtrid; + ifindex_t ifindex = 0; + unsigned int instid, rtrid; struct ospf6_interface *oi = NULL; struct ospf6_neighbor *on = NULL; struct interface *iif; @@ -1001,7 +1003,7 @@ ospfv3NbrEntry (struct variable *v, oid *name, size_t *length, == MATCH_FAILED) return NULL; - ifindex = instid = rtrid = 0; + instid = rtrid = 0; /* Check OSPFv3 instance. */ if (ospf6 == NULL) @@ -1047,7 +1049,7 @@ ospfv3NbrEntry (struct variable *v, oid *name, size_t *length, ifslist = list_new (); if (!ifslist) return NULL; ifslist->cmp = (int (*)(void *, void *))if_icmp_func; - for (ALL_LIST_ELEMENTS_RO (iflist, i, iif)) + for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), i, iif)) listnode_add_sort (ifslist, iif); for (ALL_LIST_ELEMENTS_RO (ifslist, i, iif)) diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c index ab1213ebb6..957988b53d 100644 --- a/ospf6d/ospf6_spf.c +++ b/ospf6d/ospf6_spf.c @@ -266,7 +266,7 @@ ospf6_nexthop_calc (struct ospf6_vertex *w, struct ospf6_vertex *v, caddr_t lsdesc) { int i; - unsigned int ifindex; + ifindex_t ifindex; struct ospf6_interface *oi; u_int16_t type; u_int32_t adv_router; diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index 93ec1f2ce0..77ea01e53d 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -28,6 +28,7 @@ #include "stream.h" #include "zclient.h" #include "memory.h" +#include "lib/bfd.h" #include "ospf6_proto.h" #include "ospf6_top.h" @@ -376,7 +377,7 @@ ospf6_zebra_route_update (int type, struct ospf6_route *request) char buf[PREFIX2STR_BUFFER]; int nhcount; struct in6_addr **nexthops; - unsigned int *ifindexes; + ifindex_t *ifindexes; int ret = 0; struct prefix_ipv6 *dest; @@ -442,7 +443,7 @@ ospf6_zebra_route_update (int type, struct ospf6_route *request) /* allocate memory for ifindex_list */ ifindexes = XCALLOC (MTYPE_OSPF6_OTHER, - nhcount * sizeof (unsigned int)); + nhcount * sizeof (ifindex_t)); if (ifindexes == NULL) { zlog_warn ("Can't send route to zebra: malloc failed"); @@ -656,6 +657,9 @@ DEFUN (no_redistribute_ospf6, static void ospf6_zebra_connected (struct zclient *zclient) { + /* Send the client registration */ + bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER); + zclient_send_reg_requests (zclient, VRF_DEFAULT); } diff --git a/ospfclient/.gitignore b/ospfclient/.gitignore index 191322b6a1..a6000f8021 100644 --- a/ospfclient/.gitignore +++ b/ospfclient/.gitignore @@ -13,4 +13,4 @@ TAGS .arch-ids *~ *.loT - +refix diff --git a/ospfclient/ospf_apiclient.h b/ospfclient/ospf_apiclient.h index 0e74787ae0..809861995e 100644 --- a/ospfclient/ospf_apiclient.h +++ b/ospfclient/ospf_apiclient.h @@ -23,7 +23,7 @@ #ifndef _OSPF_APICLIENT_H #define _OSPF_APICLIENT_H -#define MTYPE_OSPF_APICLIENT 0 +#define MTYPE_OSPF_APICLIENT MTYPE_TMP /* Structure for the OSPF API client */ struct ospf_apiclient diff --git a/ospfd/Makefile.am b/ospfd/Makefile.am index 9eb166a3d6..55f9bf2d8e 100644 --- a/ospfd/Makefile.am +++ b/ospfd/Makefile.am @@ -16,7 +16,7 @@ libospf_la_SOURCES = \ ospf_nsm.c ospf_dump.c ospf_network.c ospf_packet.c ospf_lsa.c \ ospf_spf.c ospf_route.c ospf_ase.c ospf_abr.c ospf_ia.c ospf_flood.c \ ospf_lsdb.c ospf_asbr.c ospf_routemap.c ospf_snmp.c \ - ospf_opaque.c ospf_te.c ospf_vty.c ospf_api.c ospf_apiserver.c \ + ospf_opaque.c ospf_te.c ospf_ri.c ospf_vty.c ospf_api.c ospf_apiserver.c \ ospf_bfd.c ospfdheaderdir = $(pkgincludedir)/ospfd @@ -28,12 +28,12 @@ ospfdheader_HEADERS = \ noinst_HEADERS = \ ospf_interface.h ospf_neighbor.h ospf_network.h ospf_packet.h \ ospf_zebra.h ospf_spf.h ospf_route.h ospf_ase.h ospf_abr.h ospf_ia.h \ - ospf_flood.h ospf_snmp.h ospf_te.h ospf_vty.h ospf_apiserver.h \ + ospf_flood.h ospf_snmp.h ospf_te.h ospf_ri.h ospf_vty.h ospf_apiserver.h \ ospf_bfd.h ospfd_SOURCES = ospf_main.c -ospfd_LDADD = libospf.la ../lib/libzebra.la @LIBCAP@ +ospfd_LDADD = libospf.la ../lib/libzebra.la @LIBCAP@ @LIBM@ EXTRA_DIST = OSPF-MIB.txt OSPF-TRAP-MIB.txt ChangeLog.opaque.txt diff --git a/ospfd/ospf_api.c b/ospfd/ospf_api.c index 45525f4a2c..9f90f671ce 100644 --- a/ospfd/ospf_api.c +++ b/ospfd/ospf_api.c @@ -23,9 +23,6 @@ #include #ifdef SUPPORT_OSPF_API -#ifndef HAVE_OPAQUE_LSA -#error "Core Opaque-LSA module must be configured." -#endif /* HAVE_OPAQUE_LSA */ #include "linklist.h" #include "prefix.h" diff --git a/ospfd/ospf_apiserver.c b/ospfd/ospf_apiserver.c index 92f68f75f8..aac8ef4b8b 100644 --- a/ospfd/ospf_apiserver.c +++ b/ospfd/ospf_apiserver.c @@ -23,9 +23,6 @@ #include #ifdef SUPPORT_OSPF_API -#ifndef HAVE_OPAQUE_LSA -#error "Core Opaque-LSA module must be configured." -#endif /* HAVE_OPAQUE_LSA */ #include "linklist.h" #include "prefix.h" diff --git a/ospfd/ospf_asbr.c b/ospfd/ospf_asbr.c index ddb26dd543..21f99af128 100644 --- a/ospfd/ospf_asbr.c +++ b/ospfd/ospf_asbr.c @@ -136,7 +136,7 @@ ospf_route_map_set_compare (struct route_map_set_values *values1, /* Add an External info for AS-external-LSA. */ struct external_info * ospf_external_info_add (u_char type, u_short instance, struct prefix_ipv4 p, - unsigned int ifindex, struct in_addr nexthop, + ifindex_t ifindex, struct in_addr nexthop, u_short tag) { struct external_info *new; diff --git a/ospfd/ospf_asbr.h b/ospfd/ospf_asbr.h index ade671013a..25a53aad4f 100644 --- a/ospfd/ospf_asbr.h +++ b/ospfd/ospf_asbr.h @@ -41,7 +41,7 @@ struct external_info struct prefix_ipv4 p; /* Interface index. */ - unsigned int ifindex; + ifindex_t ifindex; /* Nexthop address. */ struct in_addr nexthop; @@ -63,7 +63,7 @@ extern int ospf_route_map_set_compare (struct route_map_set_values *, struct route_map_set_values *); extern struct external_info *ospf_external_info_add (u_char, u_short, struct prefix_ipv4, - unsigned int, + ifindex_t, struct in_addr, u_short); extern void ospf_external_info_delete (u_char, u_short, struct prefix_ipv4); diff --git a/ospfd/ospf_bfd.c b/ospfd/ospf_bfd.c index ec486c4688..c87bcb0afb 100644 --- a/ospfd/ospf_bfd.c +++ b/ospfd/ospf_bfd.c @@ -452,7 +452,4 @@ ospf_bfd_init(void) install_element (INTERFACE_NODE, &ip_ospf_bfd_param_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_bfd_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_bfd_param_cmd); - - /* Send the client registration */ - bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER); } diff --git a/ospfd/ospf_dump.c b/ospfd/ospf_dump.c index 861f9d3516..a53c726853 100644 --- a/ospfd/ospf_dump.c +++ b/ospfd/ospf_dump.c @@ -133,6 +133,7 @@ unsigned long conf_debug_ospf_nsm = 0; unsigned long conf_debug_ospf_lsa = 0; unsigned long conf_debug_ospf_zebra = 0; unsigned long conf_debug_ospf_nssa = 0; +unsigned long conf_debug_ospf_te = 0; /* Enable debug option variables -- valid only session. */ unsigned long term_debug_ospf_packet[5] = {0, 0, 0, 0, 0}; @@ -142,7 +143,7 @@ unsigned long term_debug_ospf_nsm = 0; unsigned long term_debug_ospf_lsa = 0; unsigned long term_debug_ospf_zebra = 0; unsigned long term_debug_ospf_nssa = 0; - +unsigned long term_debug_ospf_te = 0; const char * @@ -328,13 +329,14 @@ ospf_options_dump (u_char options) { static char buf[OSPF_OPTION_STR_MAXLEN]; - snprintf (buf, OSPF_OPTION_STR_MAXLEN, "*|%s|%s|%s|%s|%s|%s|*", + snprintf (buf, OSPF_OPTION_STR_MAXLEN, "*|%s|%s|%s|%s|%s|%s|%s", (options & OSPF_OPTION_O) ? "O" : "-", (options & OSPF_OPTION_DC) ? "DC" : "-", (options & OSPF_OPTION_EA) ? "EA" : "-", (options & OSPF_OPTION_NP) ? "N/P" : "-", (options & OSPF_OPTION_MC) ? "MC" : "-", - (options & OSPF_OPTION_E) ? "E" : "-"); + (options & OSPF_OPTION_E) ? "E" : "-", + (options & OSPF_OPTION_MT) ? "M/T" : "-"); return buf; } @@ -619,13 +621,11 @@ ospf_packet_ls_upd_dump (struct stream *s, u_int16_t length) case OSPF_AS_NSSA_LSA: ospf_as_external_lsa_dump (s, length); break; -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: ospf_opaque_lsa_dump (s, length); break; -#endif /* HAVE_OPAQUE_LSA */ default: break; } @@ -1922,6 +1922,33 @@ DEFUN (no_debug_ospf_instance_nssa, return CMD_SUCCESS; } +DEFUN (debug_ospf_te, + debug_ospf_te_cmd, + "debug ospf te", + DEBUG_STR + OSPF_STR + "OSPF-TE information\n") +{ + if (vty->node == CONFIG_NODE) + CONF_DEBUG_ON (te, TE); + TERM_DEBUG_ON (te, TE); + return CMD_SUCCESS; +} + +DEFUN (no_debug_ospf_te, + no_debug_ospf_te_cmd, + "no debug ospf te", + NO_STR + DEBUG_STR + OSPF_STR + "OSPF-TE information\n") +{ + if (vty->node == CONFIG_NODE) + CONF_DEBUG_OFF (te, TE); + TERM_DEBUG_OFF (te, TE); + return CMD_SUCCESS; +} + DEFUN (no_debug_ospf, no_debug_ospf_cmd, "no debug ospf", @@ -2133,6 +2160,7 @@ config_write_debug (struct vty *vty) struct ospf *ospf; char str[16]; + memset (str, 0, 16); if ((ospf = ospf_lookup()) == NULL) return CMD_SUCCESS; @@ -2271,6 +2299,7 @@ debug_init () install_element (ENABLE_NODE, &debug_ospf_zebra_cmd); install_element (ENABLE_NODE, &debug_ospf_event_cmd); install_element (ENABLE_NODE, &debug_ospf_nssa_cmd); + install_element (ENABLE_NODE, &debug_ospf_te_cmd); install_element (ENABLE_NODE, &no_debug_ospf_packet_send_recv_detail_cmd); install_element (ENABLE_NODE, &no_debug_ospf_packet_send_recv_cmd); install_element (ENABLE_NODE, &no_debug_ospf_packet_all_cmd); @@ -2284,6 +2313,7 @@ debug_init () install_element (ENABLE_NODE, &no_debug_ospf_zebra_cmd); install_element (ENABLE_NODE, &no_debug_ospf_event_cmd); install_element (ENABLE_NODE, &no_debug_ospf_nssa_cmd); + install_element (ENABLE_NODE, &no_debug_ospf_te_cmd); install_element (ENABLE_NODE, &show_debugging_ospf_instance_cmd); install_element (ENABLE_NODE, &debug_ospf_instance_packet_send_recv_detail_cmd); @@ -2327,6 +2357,7 @@ debug_init () install_element (CONFIG_NODE, &debug_ospf_zebra_cmd); install_element (CONFIG_NODE, &debug_ospf_event_cmd); install_element (CONFIG_NODE, &debug_ospf_nssa_cmd); + install_element (CONFIG_NODE, &debug_ospf_te_cmd); install_element (CONFIG_NODE, &no_debug_ospf_packet_send_recv_detail_cmd); install_element (CONFIG_NODE, &no_debug_ospf_packet_send_recv_cmd); install_element (CONFIG_NODE, &no_debug_ospf_packet_all_cmd); @@ -2340,6 +2371,7 @@ debug_init () install_element (CONFIG_NODE, &no_debug_ospf_zebra_cmd); install_element (CONFIG_NODE, &no_debug_ospf_event_cmd); install_element (CONFIG_NODE, &no_debug_ospf_nssa_cmd); + install_element (CONFIG_NODE, &no_debug_ospf_te_cmd); install_element (CONFIG_NODE, &debug_ospf_instance_packet_send_recv_detail_cmd); install_element (CONFIG_NODE, &debug_ospf_instance_packet_send_recv_cmd); diff --git a/ospfd/ospf_dump.h b/ospfd/ospf_dump.h index a2d5e8ba19..f843df03ae 100644 --- a/ospfd/ospf_dump.h +++ b/ospfd/ospf_dump.h @@ -57,6 +57,7 @@ #define OSPF_DEBUG_EVENT 0x01 #define OSPF_DEBUG_NSSA 0x02 +#define OSPF_DEBUG_TE 0x04 /* Macro for setting debug option. */ #define CONF_DEBUG_PACKET_ON(a, b) conf_debug_ospf_packet[a] |= (b) @@ -98,6 +99,8 @@ #define IS_DEBUG_OSPF_NSSA IS_DEBUG_OSPF(nssa,NSSA) +#define IS_DEBUG_OSPF_TE IS_DEBUG_OSPF(te,TE) + #define IS_CONF_DEBUG_OSPF_PACKET(a, b) \ (conf_debug_ospf_packet[a] & OSPF_DEBUG_ ## b) #define IS_CONF_DEBUG_OSPF(a, b) \ @@ -119,6 +122,7 @@ extern unsigned long term_debug_ospf_nsm; extern unsigned long term_debug_ospf_lsa; extern unsigned long term_debug_ospf_zebra; extern unsigned long term_debug_ospf_nssa; +extern unsigned long term_debug_ospf_te; /* Message Strings. */ extern char *ospf_lsa_type_str[]; diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c index e9f443111a..7f83ddeaae 100644 --- a/ospfd/ospf_flood.c +++ b/ospfd/ospf_flood.c @@ -156,9 +156,7 @@ ospf_process_self_originated_lsa (struct ospf *ospf, ospf_router_lsa_update_area (area); return; case OSPF_NETWORK_LSA: -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: -#endif /* HAVE_OPAQUE_LSA */ /* We must find the interface the LSA could belong to. If the interface is no more a broadcast type or we are no more the DR, we flush the LSA otherwise -- create the new instance and @@ -178,13 +176,11 @@ ospf_process_self_originated_lsa (struct ospf *ospf, return; } -#ifdef HAVE_OPAQUE_LSA if (new->data->type == OSPF_OPAQUE_LINK_LSA) { ospf_opaque_lsa_refresh (new); return; } -#endif /* HAVE_OPAQUE_LSA */ if (oi->network_lsa_self) oi->network_lsa_self->data->ls_seqnum = new->data->ls_seqnum; @@ -211,14 +207,12 @@ ospf_process_self_originated_lsa (struct ospf *ospf, else ospf_lsa_flush_as (ospf, new); break; -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AREA_LSA: ospf_opaque_lsa_refresh (new); break; case OSPF_OPAQUE_AS_LSA: ospf_opaque_lsa_refresh (new); /* Reconsideration may needed. *//* XXX */ break; -#endif /* HAVE_OPAQUE_LSA */ default: break; } @@ -299,25 +293,17 @@ ospf_flood (struct ospf *ospf, struct ospf_neighbor *nbr, interface. */ lsa_ack_flag = ospf_flood_through (ospf, nbr, new); -#ifdef HAVE_OPAQUE_LSA /* Remove the current database copy from all neighbors' Link state retransmission lists. AS_EXTERNAL and AS_EXTERNAL_OPAQUE does ^^^^^^^^^^^^^^^^^^^^^^^ not have area ID. All other (even NSSA's) do have area ID. */ -#else /* HAVE_OPAQUE_LSA */ - /* Remove the current database copy from all neighbors' Link state - retransmission lists. Only AS_EXTERNAL does not have area ID. - All other (even NSSA's) do have area ID. */ -#endif /* HAVE_OPAQUE_LSA */ if (current) { switch (current->data->type) { case OSPF_AS_EXTERNAL_LSA: -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: -#endif /* HAVE_OPAQUE_LSA */ ospf_ls_retransmit_delete_nbr_as (ospf, current); break; default: @@ -439,7 +425,6 @@ ospf_flood_through_interface (struct ospf_interface *oi, } } -#ifdef HAVE_OPAQUE_LSA if (IS_OPAQUE_LSA (lsa->data->type)) { if (! CHECK_FLAG (onbr->options, OSPF_OPTION_O)) @@ -449,7 +434,6 @@ ospf_flood_through_interface (struct ospf_interface *oi, continue; } } -#endif /* HAVE_OPAQUE_LSA */ /* If the new LSA was received from this neighbor, examine the next neighbor. */ @@ -584,7 +568,6 @@ ospf_flood_through_area (struct ospf_area *area, oi->type == OSPF_IFTYPE_VIRTUALLINK) continue; -#ifdef HAVE_OPAQUE_LSA if ((lsa->data->type == OSPF_OPAQUE_LINK_LSA) && (lsa->oi != oi)) { /* @@ -596,7 +579,6 @@ ospf_flood_through_area (struct ospf_area *area, (void *)lsa->oi, (void *)oi); continue; } -#endif /* HAVE_OPAQUE_LSA */ if (ospf_flood_through_interface (oi, inbr, lsa)) lsa_ack_flag = 1; @@ -706,16 +688,12 @@ ospf_flood_through (struct ospf *ospf, case OSPF_NETWORK_LSA: case OSPF_SUMMARY_LSA: case OSPF_ASBR_SUMMARY_LSA: -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: /* ospf_flood_through_interface ? */ case OSPF_OPAQUE_AREA_LSA: -#endif /* HAVE_OPAQUE_LSA */ lsa_ack_flag = ospf_flood_through_area (inbr->oi->area, inbr, lsa); break; case OSPF_AS_EXTERNAL_LSA: /* Type-5 */ -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: -#endif /* HAVE_OPAQUE_LSA */ lsa_ack_flag = ospf_flood_through_as (ospf, inbr, lsa); break; /* Type-7 Only received within NSSA, then flooded */ @@ -745,9 +723,7 @@ ospf_flood_through (struct ospf *ospf, switch (lsa->data->type) { case OSPF_AS_EXTERNAL_LSA: /* Type-5 */ -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: -#endif /* HAVE_OPAQUE_LSA */ lsa_ack_flag = ospf_flood_through_as (ospf, inbr, lsa); break; /* Type-7 Only received within NSSA, then flooded */ @@ -1024,16 +1000,12 @@ ospf_lsa_flush (struct ospf *ospf, struct ospf_lsa *lsa) case OSPF_SUMMARY_LSA: case OSPF_ASBR_SUMMARY_LSA: case OSPF_AS_NSSA_LSA: -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: -#endif /* HAVE_OPAQUE_LSA */ ospf_lsa_flush_area (lsa, lsa->area); break; case OSPF_AS_EXTERNAL_LSA: -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: -#endif /* HAVE_OPAQUE_LSA */ ospf_lsa_flush_as (ospf, lsa); break; default: diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index a062004ac4..2c8124b93d 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -243,9 +243,7 @@ ospf_if_new (struct ospf *ospf, struct interface *ifp, struct prefix *p) oi->crypt_seqnum = time (NULL); -#ifdef HAVE_OPAQUE_LSA ospf_opaque_type9_lsa_init (oi); -#endif /* HAVE_OPAQUE_LSA */ oi->ospf = ospf; @@ -297,7 +295,7 @@ ospf_if_cleanup (struct ospf_interface *oi) ospf_ls_upd_queue_empty (oi); /* Reset pseudo neighbor. */ - ospf_nbr_self_reset (oi); + ospf_nbr_self_reset (oi, oi->ospf->router_id); } void @@ -307,9 +305,7 @@ ospf_if_free (struct ospf_interface *oi) assert (oi->state == ISM_Down); -#ifdef HAVE_OPAQUE_LSA ospf_opaque_type9_lsa_term (oi); -#endif /* HAVE_OPAQUE_LSA */ /* Free Pseudo Neighbour */ ospf_nbr_delete (oi->nbr_self); @@ -696,9 +692,7 @@ ospf_if_new_hook (struct interface *ifp) SET_IF_PARAM (IF_DEF_PARAMS (ifp), auth_type); IF_DEF_PARAMS (ifp)->auth_type = OSPF_AUTH_NOTSET; -#ifdef HAVE_OPAQUE_LSA rc = ospf_opaque_new_if (ifp); -#endif /* HAVE_OPAQUE_LSA */ return rc; } @@ -707,9 +701,7 @@ ospf_if_delete_hook (struct interface *ifp) { int rc = 0; struct route_node *rn; -#ifdef HAVE_OPAQUE_LSA rc = ospf_opaque_del_if (ifp); -#endif /* HAVE_OPAQUE_LSA */ route_table_finish (IF_OIFS (ifp)); @@ -926,7 +918,7 @@ ospf_vl_new (struct ospf *ospf, struct ospf_vl_data *vl_data) zlog_debug ("ospf_vl_new(): set associated area to the backbone"); /* Add pseudo neighbor. */ - ospf_nbr_self_reset (voi); + ospf_nbr_self_reset (voi, voi->ospf->router_id); ospf_area_add_if (voi->area, voi); diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h index 68dbf186d2..7a74288bff 100644 --- a/ospfd/ospf_interface.h +++ b/ospfd/ospf_interface.h @@ -188,9 +188,7 @@ struct ospf_interface /* self-originated LSAs. */ struct ospf_lsa *network_lsa_self; /* network-LSA. */ -#ifdef HAVE_OPAQUE_LSA struct list *opaque_lsa_self; /* Type-9 Opaque-LSAs */ -#endif /* HAVE_OPAQUE_LSA */ struct route_table *ls_upd_queue; @@ -211,9 +209,7 @@ struct ospf_interface struct thread *t_ls_ack; /* timer */ struct thread *t_ls_ack_direct; /* event */ struct thread *t_ls_upd_event; /* event */ -#ifdef HAVE_OPAQUE_LSA struct thread *t_opaque_lsa_self; /* Type-9 Opaque-LSAs */ -#endif /* HAVE_OPAQUE_LSA */ int on_write_q; diff --git a/ospfd/ospf_ism.c b/ospfd/ospf_ism.c index 9649df8dc0..ae6d0cdbc5 100644 --- a/ospfd/ospf_ism.c +++ b/ospfd/ospf_ism.c @@ -593,9 +593,7 @@ ism_change_state (struct ospf_interface *oi, int state) oi->network_lsa_self = NULL; } -#ifdef HAVE_OPAQUE_LSA ospf_opaque_ism_change (oi, old_state); -#endif /* HAVE_OPAQUE_LSA */ /* Check area border status. */ ospf_check_abr_status (oi->ospf); diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index ec0eab5f0a..b96ed452c1 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -2251,7 +2251,7 @@ ospf_nssa_lsa_flush (struct ospf *ospf, struct prefix_ipv4 *p) void ospf_external_lsa_flush (struct ospf *ospf, u_char type, struct prefix_ipv4 *p, - unsigned int ifindex /*, struct in_addr nexthop */) + ifindex_t ifindex /*, struct in_addr nexthop */) { struct ospf_lsa *lsa; @@ -2642,11 +2642,9 @@ ospf_discard_from_db (struct ospf *ospf, ospf_ase_unregister_external_lsa (old, ospf); ospf_ls_retransmit_delete_nbr_as (ospf, old); break; -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: ospf_ls_retransmit_delete_nbr_as (ospf, old); break; -#endif /* HAVE_OPAQUE_LSA */ case OSPF_AS_NSSA_LSA: ospf_ls_retransmit_delete_nbr_area (old->area, old); ospf_ase_unregister_external_lsa (old, ospf); @@ -2680,9 +2678,7 @@ ospf_lsa_install (struct ospf *ospf, struct ospf_interface *oi, lsdb = ospf->lsdb; break; case OSPF_AS_EXTERNAL_LSA: -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: -#endif /* HAVE_OPAQUE_LSA */ lsdb = ospf->lsdb; break; default: @@ -2794,7 +2790,6 @@ ospf_lsa_install (struct ospf *ospf, struct ospf_interface *oi, case OSPF_AS_EXTERNAL_LSA: new = ospf_external_lsa_install (ospf, lsa, rt_recalc); break; -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: if (IS_LSA_SELF (lsa)) lsa->oi = oi; /* Specify outgoing ospf-interface for this LSA. */ @@ -2807,7 +2802,6 @@ ospf_lsa_install (struct ospf *ospf, struct ospf_interface *oi, case OSPF_OPAQUE_AS_LSA: new = ospf_opaque_lsa_install (lsa, rt_recalc); break; -#endif /* HAVE_OPAQUE_LSA */ case OSPF_AS_NSSA_LSA: new = ospf_external_lsa_install (ospf, lsa, rt_recalc); default: /* type-6,8,9....nothing special */ @@ -2825,9 +2819,7 @@ ospf_lsa_install (struct ospf *ospf, struct ospf_interface *oi, switch (lsa->data->type) { case OSPF_AS_EXTERNAL_LSA: -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: -#endif /* HAVE_OPAQUE_LSA */ case OSPF_AS_NSSA_LSA: zlog_debug ("LSA[%s]: Install %s", dump_lsa_key (new), @@ -3061,7 +3053,6 @@ ospf_lsa_maxage_walker_remover (struct ospf *ospf, struct ospf_lsa *lsa) switch (lsa->data->type) { -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: @@ -3074,7 +3065,6 @@ ospf_lsa_maxage_walker_remover (struct ospf *ospf, struct ospf_lsa *lsa) * topology, and thus, routing recalculation is not needed here. */ break; -#endif /* HAVE_OPAQUE_LSA */ case OSPF_AS_EXTERNAL_LSA: case OSPF_AS_NSSA_LSA: ospf_ase_incremental_update (ospf, lsa); @@ -3115,12 +3105,10 @@ ospf_lsa_maxage_walker (struct thread *thread) ospf_lsa_maxage_walker_remover (ospf, lsa); LSDB_LOOP (ASBR_SUMMARY_LSDB (area), rn, lsa) ospf_lsa_maxage_walker_remover (ospf, lsa); -#ifdef HAVE_OPAQUE_LSA LSDB_LOOP (OPAQUE_AREA_LSDB (area), rn, lsa) ospf_lsa_maxage_walker_remover (ospf, lsa); LSDB_LOOP (OPAQUE_LINK_LSDB (area), rn, lsa) ospf_lsa_maxage_walker_remover (ospf, lsa); -#endif /* HAVE_OPAQUE_LSA */ LSDB_LOOP (NSSA_LSDB (area), rn, lsa) ospf_lsa_maxage_walker_remover (ospf, lsa); } @@ -3130,10 +3118,8 @@ ospf_lsa_maxage_walker (struct thread *thread) { LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa) ospf_lsa_maxage_walker_remover (ospf, lsa); -#ifdef HAVE_OPAQUE_LSA LSDB_LOOP (OPAQUE_AS_LSDB (ospf), rn, lsa) ospf_lsa_maxage_walker_remover (ospf, lsa); -#endif /* HAVE_OPAQUE_LSA */ } OSPF_TIMER_ON (ospf->t_maxage_walker, ospf_lsa_maxage_walker, @@ -3186,15 +3172,11 @@ ospf_lsa_lookup (struct ospf_area *area, u_int32_t type, case OSPF_SUMMARY_LSA: case OSPF_ASBR_SUMMARY_LSA: case OSPF_AS_NSSA_LSA: -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: -#endif /* HAVE_OPAQUE_LSA */ return ospf_lsdb_lookup_by_id (area->lsdb, type, id, adv_router); case OSPF_AS_EXTERNAL_LSA: -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: -#endif /* HAVE_OPAQUE_LSA */ return ospf_lsdb_lookup_by_id (ospf->lsdb, type, id, adv_router); default: break; @@ -3230,13 +3212,11 @@ ospf_lsa_lookup_by_id (struct ospf_area *area, u_int32_t type, return ospf_lsdb_lookup_by_id (area->lsdb, type, id, id); case OSPF_AS_EXTERNAL_LSA: case OSPF_AS_NSSA_LSA: -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: /* Currently not used. */ break; -#endif /* HAVE_OPAQUE_LSA */ default: break; } @@ -3249,14 +3229,12 @@ ospf_lsa_lookup_by_header (struct ospf_area *area, struct lsa_header *lsah) { struct ospf_lsa *match; -#ifdef HAVE_OPAQUE_LSA /* * Strictly speaking, the LSA-ID field for Opaque-LSAs (type-9/10/11) * is redefined to have two subfields; opaque-type and opaque-id. * However, it is harmless to treat the two sub fields together, as if * they two were forming a unique LSA-ID. */ -#endif /* HAVE_OPAQUE_LSA */ match = ospf_lsa_lookup (area, lsah->type, lsah->id, lsah->adv_router); @@ -3407,14 +3385,12 @@ ospf_lsa_flush_schedule (struct ospf *ospf, struct ospf_lsa *lsa) switch (lsa->data->type) { -#ifdef HAVE_OPAQUE_LSA /* Opaque wants to be notified of flushes */ case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: ospf_opaque_lsa_refresh (lsa); break; -#endif /* HAVE_OPAQUE_LSA */ default: ospf_refresher_unregister_lsa (ospf, lsa); ospf_lsa_flush (ospf, lsa); @@ -3474,22 +3450,18 @@ ospf_flush_self_originated_lsas_now (struct ospf *ospf) ospf_lsa_flush_schedule (ospf, lsa); LSDB_LOOP (ASBR_SUMMARY_LSDB (area), rn, lsa) ospf_lsa_flush_schedule (ospf, lsa); -#ifdef HAVE_OPAQUE_LSA LSDB_LOOP (OPAQUE_LINK_LSDB (area), rn, lsa) ospf_lsa_flush_schedule (ospf, lsa); LSDB_LOOP (OPAQUE_AREA_LSDB (area), rn, lsa) ospf_lsa_flush_schedule (ospf, lsa); -#endif /* HAVE_OPAQUE_LSA */ } if (need_to_flush_ase) { LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa) ospf_lsa_flush_schedule (ospf, lsa); -#ifdef HAVE_OPAQUE_LSA LSDB_LOOP (OPAQUE_AS_LSDB (ospf), rn, lsa) ospf_lsa_flush_schedule (ospf, lsa); -#endif /* HAVE_OPAQUE_LSA */ } /* @@ -3698,13 +3670,11 @@ ospf_lsa_refresh (struct ospf *ospf, struct ospf_lsa *lsa) else ospf_lsa_flush_as (ospf, lsa); break; -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: new = ospf_opaque_lsa_refresh (lsa); break; -#endif /* HAVE_OPAQUE_LSA */ default: break; } @@ -3731,7 +3701,7 @@ ospf_refresher_register_lsa (struct ospf *ospf, struct ospf_lsa *lsa) */ delay = (random() % (max_delay - min_delay)) + min_delay; - current_index = ospf->lsa_refresh_queue.index + (quagga_time (NULL) + current_index = ospf->lsa_refresh_queue.index + (quagga_monotime () - ospf->lsa_refresher_started)/OSPF_LSA_REFRESHER_GRANULARITY; index = (current_index + delay/OSPF_LSA_REFRESHER_GRANULARITY) @@ -3795,7 +3765,7 @@ ospf_lsa_refresh_walker (struct thread *t) modulus. */ ospf->lsa_refresh_queue.index = ((unsigned long)(ospf->lsa_refresh_queue.index + - (quagga_time (NULL) - ospf->lsa_refresher_started) + (quagga_monotime () - ospf->lsa_refresher_started) / OSPF_LSA_REFRESHER_GRANULARITY)) % OSPF_LSA_REFRESHER_SLOTS; @@ -3836,7 +3806,7 @@ ospf_lsa_refresh_walker (struct thread *t) ospf->t_lsa_refresher = thread_add_timer (master, ospf_lsa_refresh_walker, ospf, ospf->lsa_refresh_interval); - ospf->lsa_refresher_started = quagga_time (NULL); + ospf->lsa_refresher_started = quagga_monotime (); for (ALL_LIST_ELEMENTS (lsa_to_refresh, node, nnode, lsa)) { diff --git a/ospfd/ospf_lsa.h b/ospfd/ospf_lsa.h index f2c08b1b93..28ecc9d4d6 100644 --- a/ospfd/ospf_lsa.h +++ b/ospfd/ospf_lsa.h @@ -27,11 +27,7 @@ /* OSPF LSA Range definition. */ #define OSPF_MIN_LSA 1 /* begin range here */ -#if defined (HAVE_OPAQUE_LSA) #define OSPF_MAX_LSA 12 -#else -#define OSPF_MAX_LSA 8 -#endif /* OSPF LSA Type definition. */ #define OSPF_UNKNOWN_LSA 0 @@ -211,9 +207,7 @@ struct as_external_lsa } e[1]; }; -#ifdef HAVE_OPAQUE_LSA #include "ospfd/ospf_opaque.h" -#endif /* HAVE_OPAQUE_LSA */ /* Macros. */ #define GET_METRIC(x) get_metric(x) @@ -283,7 +277,7 @@ extern struct ospf_lsa *ospf_lsa_install (struct ospf *, extern void ospf_nssa_lsa_flush (struct ospf *ospf, struct prefix_ipv4 *p); extern void ospf_external_lsa_flush (struct ospf *, u_char, struct prefix_ipv4 *, - unsigned int /* , struct in_addr nexthop */); + ifindex_t /* , struct in_addr nexthop */); extern struct in_addr ospf_get_ip_from_ifp (struct ospf_interface *); diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c index 495ee2fd02..55ec2a306c 100644 --- a/ospfd/ospf_main.c +++ b/ospfd/ospf_main.c @@ -288,7 +288,9 @@ main (int argc, char **argv) zlog_default = openzlog (progname, ZLOG_OSPF, instance, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); zprivs_init (&ospfd_privs); - zlog_set_file (NULL, LOG_DEFAULT_FILENAME, zlog_default->default_lvl); +#if defined(HAVE_CUMULUS) + zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl); +#endif /* OSPF master init. */ ospf_master_init (); @@ -323,9 +325,7 @@ main (int argc, char **argv) #ifdef HAVE_SNMP ospf_snmp_init (); #endif /* HAVE_SNMP */ -#ifdef HAVE_OPAQUE_LSA ospf_opaque_init (); -#endif /* HAVE_OPAQUE_LSA */ /* Need to initialize the default ospf structure, so the interface mode commands can be duly processed if they are received before 'router ospf', diff --git a/ospfd/ospf_neighbor.c b/ospfd/ospf_neighbor.c index 16753b85df..a573936c18 100644 --- a/ospfd/ospf_neighbor.c +++ b/ospfd/ospf_neighbor.c @@ -238,18 +238,18 @@ ospf_nbr_bidirectional (struct in_addr *router_id, /* reset nbr_self */ void -ospf_nbr_self_reset (struct ospf_interface *oi) +ospf_nbr_self_reset (struct ospf_interface *oi, struct in_addr router_id) { if (oi->nbr_self) ospf_nbr_delete (oi->nbr_self); oi->nbr_self = ospf_nbr_new (oi); - ospf_nbr_add_self (oi); + ospf_nbr_add_self (oi, router_id); } /* Add self to nbr list. */ void -ospf_nbr_add_self (struct ospf_interface *oi) +ospf_nbr_add_self (struct ospf_interface *oi, struct in_addr router_id) { struct prefix p; struct route_node *rn; @@ -260,7 +260,7 @@ ospf_nbr_add_self (struct ospf_interface *oi) /* Initial state */ oi->nbr_self->address = *oi->address; oi->nbr_self->priority = OSPF_IF_PARAM (oi, priority); - oi->nbr_self->router_id = oi->ospf->router_id; + oi->nbr_self->router_id = router_id; oi->nbr_self->src = oi->address->u.prefix4; oi->nbr_self->state = NSM_TwoWay; @@ -310,7 +310,6 @@ ospf_nbr_count (struct ospf_interface *oi, int state) return count; } -#ifdef HAVE_OPAQUE_LSA int ospf_nbr_count_opaque_capable (struct ospf_interface *oi) { @@ -327,7 +326,6 @@ ospf_nbr_count_opaque_capable (struct ospf_interface *oi) return count; } -#endif /* HAVE_OPAQUE_LSA */ /* lookup nbr by address - use this only if you know you must * otherwise use the ospf_nbr_lookup() wrapper, which deals diff --git a/ospfd/ospf_neighbor.h b/ospfd/ospf_neighbor.h index 81e212b573..d62de44b5e 100644 --- a/ospfd/ospf_neighbor.h +++ b/ospfd/ospf_neighbor.h @@ -102,12 +102,10 @@ extern struct ospf_neighbor *ospf_nbr_new (struct ospf_interface *); extern void ospf_nbr_free (struct ospf_neighbor *); extern void ospf_nbr_delete (struct ospf_neighbor *); extern int ospf_nbr_bidirectional (struct in_addr *, struct in_addr *, int); -extern void ospf_nbr_self_reset (struct ospf_interface *); -extern void ospf_nbr_add_self (struct ospf_interface *); +extern void ospf_nbr_self_reset (struct ospf_interface *, struct in_addr); +extern void ospf_nbr_add_self (struct ospf_interface *, struct in_addr); extern int ospf_nbr_count (struct ospf_interface *, int); -#ifdef HAVE_OPAQUE_LSA extern int ospf_nbr_count_opaque_capable (struct ospf_interface *); -#endif /* HAVE_OPAQUE_LSA */ extern struct ospf_neighbor *ospf_nbr_get (struct ospf_interface *, struct ospf_header *, struct ip *, struct prefix *); diff --git a/ospfd/ospf_network.c b/ospfd/ospf_network.c index 2f167a50a5..6caa38d68b 100644 --- a/ospfd/ospf_network.c +++ b/ospfd/ospf_network.c @@ -48,12 +48,12 @@ extern struct zebra_privs_t ospfd_privs; /* Join to the OSPF ALL SPF ROUTERS multicast group. */ int ospf_if_add_allspfrouters (struct ospf *top, struct prefix *p, - unsigned int ifindex) + ifindex_t ifindex) { int ret; ret = setsockopt_ipv4_multicast (top->fd, IP_ADD_MEMBERSHIP, - htonl (OSPF_ALLSPFROUTERS), + p->u.prefix4, htonl (OSPF_ALLSPFROUTERS), ifindex); if (ret < 0) zlog_warn ("can't setsockopt IP_ADD_MEMBERSHIP (fd %d, addr %s, " @@ -69,12 +69,12 @@ ospf_if_add_allspfrouters (struct ospf *top, struct prefix *p, int ospf_if_drop_allspfrouters (struct ospf *top, struct prefix *p, - unsigned int ifindex) + ifindex_t ifindex) { int ret; ret = setsockopt_ipv4_multicast (top->fd, IP_DROP_MEMBERSHIP, - htonl (OSPF_ALLSPFROUTERS), + p->u.prefix4, htonl (OSPF_ALLSPFROUTERS), ifindex); if (ret < 0) zlog_warn ("can't setsockopt IP_DROP_MEMBERSHIP (fd %d, addr %s, " @@ -89,13 +89,12 @@ ospf_if_drop_allspfrouters (struct ospf *top, struct prefix *p, /* Join to the OSPF ALL Designated ROUTERS multicast group. */ int -ospf_if_add_alldrouters (struct ospf *top, struct prefix *p, unsigned int - ifindex) +ospf_if_add_alldrouters (struct ospf *top, struct prefix *p, ifindex_t ifindex) { int ret; ret = setsockopt_ipv4_multicast (top->fd, IP_ADD_MEMBERSHIP, - htonl (OSPF_ALLDROUTERS), + p->u.prefix4, htonl (OSPF_ALLDROUTERS), ifindex); if (ret < 0) zlog_warn ("can't setsockopt IP_ADD_MEMBERSHIP (fd %d, addr %s, " @@ -110,13 +109,12 @@ ospf_if_add_alldrouters (struct ospf *top, struct prefix *p, unsigned int } int -ospf_if_drop_alldrouters (struct ospf *top, struct prefix *p, unsigned int - ifindex) +ospf_if_drop_alldrouters (struct ospf *top, struct prefix *p, ifindex_t ifindex) { int ret; ret = setsockopt_ipv4_multicast (top->fd, IP_DROP_MEMBERSHIP, - htonl (OSPF_ALLDROUTERS), + p->u.prefix4, htonl (OSPF_ALLDROUTERS), ifindex); if (ret < 0) zlog_warn ("can't setsockopt IP_DROP_MEMBERSHIP (fd %d, addr %s, " @@ -130,7 +128,7 @@ ospf_if_drop_alldrouters (struct ospf *top, struct prefix *p, unsigned int } int -ospf_if_ipmulticast (struct ospf *top, struct prefix *p, unsigned int ifindex) +ospf_if_ipmulticast (struct ospf *top, struct prefix *p, ifindex_t ifindex) { u_char val; int ret, len; @@ -151,7 +149,7 @@ ospf_if_ipmulticast (struct ospf *top, struct prefix *p, unsigned int ifindex) zlog_warn ("can't setsockopt IP_MULTICAST_TTL(1) for fd %d: %s", top->fd, safe_strerror (errno)); - ret = setsockopt_ipv4_multicast_if (top->fd, ifindex); + ret = setsockopt_ipv4_multicast_if (top->fd, p->u.prefix4, ifindex); if (ret < 0) zlog_warn("can't setsockopt IP_MULTICAST_IF(fd %d, addr %s, " "ifindex %u): %s", diff --git a/ospfd/ospf_network.h b/ospfd/ospf_network.h index e0a5c69d5c..8257adb4af 100644 --- a/ospfd/ospf_network.h +++ b/ospfd/ospf_network.h @@ -25,14 +25,14 @@ /* Prototypes. */ extern int ospf_if_add_allspfrouters (struct ospf *, struct prefix *, - unsigned int); + ifindex_t); extern int ospf_if_drop_allspfrouters (struct ospf *, struct prefix *, - unsigned int); + ifindex_t); extern int ospf_if_add_alldrouters (struct ospf *, struct prefix *, - unsigned int); + ifindex_t); extern int ospf_if_drop_alldrouters (struct ospf *, struct prefix *, - unsigned int); -extern int ospf_if_ipmulticast (struct ospf *, struct prefix *, unsigned int); + ifindex_t); +extern int ospf_if_ipmulticast (struct ospf *, struct prefix *, ifindex_t); extern int ospf_sock_init (void); extern void ospf_adjust_sndbuflen (struct ospf *, unsigned int); diff --git a/ospfd/ospf_nsm.c b/ospfd/ospf_nsm.c index 23d1e3fc6c..c6b55b0746 100644 --- a/ospfd/ospf_nsm.c +++ b/ospfd/ospf_nsm.c @@ -222,7 +222,6 @@ ospf_db_summary_isempty (struct ospf_neighbor *nbr) static int ospf_db_summary_add (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) { -#ifdef HAVE_OPAQUE_LSA switch (lsa->data->type) { case OSPF_OPAQUE_LINK_LSA: @@ -240,7 +239,6 @@ ospf_db_summary_add (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) default: break; } -#endif /* HAVE_OPAQUE_LSA */ /* Stay away from any Local Translated Type-7 LSAs */ if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT)) @@ -299,7 +297,6 @@ nsm_negotiation_done (struct ospf_neighbor *nbr) LSDB_LOOP (ASBR_SUMMARY_LSDB (area), rn, lsa) ospf_db_summary_add (nbr, lsa); -#ifdef HAVE_OPAQUE_LSA /* Process only if the neighbor is opaque capable. */ if (CHECK_FLAG (nbr->options, OSPF_OPTION_O)) { @@ -308,7 +305,6 @@ nsm_negotiation_done (struct ospf_neighbor *nbr) LSDB_LOOP (OPAQUE_AREA_LSDB (area), rn, lsa) ospf_db_summary_add (nbr, lsa); } -#endif /* HAVE_OPAQUE_LSA */ if (CHECK_FLAG (nbr->options, OSPF_OPTION_NP)) { @@ -321,13 +317,11 @@ nsm_negotiation_done (struct ospf_neighbor *nbr) LSDB_LOOP (EXTERNAL_LSDB (nbr->oi->ospf), rn, lsa) ospf_db_summary_add (nbr, lsa); -#ifdef HAVE_OPAQUE_LSA if (CHECK_FLAG (nbr->options, OSPF_OPTION_O) && (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK && area->external_routing == OSPF_AREA_DEFAULT)) LSDB_LOOP (OPAQUE_AS_LSDB (nbr->oi->ospf), rn, lsa) ospf_db_summary_add (nbr, lsa); -#endif /* HAVE_OPAQUE_LSA */ return 0; } @@ -383,10 +377,8 @@ nsm_clear_adj (struct ospf_neighbor *nbr) if (!ospf_ls_retransmit_isempty (nbr)) ospf_ls_retransmit_clear (nbr); -#ifdef HAVE_OPAQUE_LSA if (CHECK_FLAG (nbr->options, OSPF_OPTION_O)) UNSET_FLAG (nbr->options, OSPF_OPTION_O); -#endif /* HAVE_OPAQUE_LSA */ } static int @@ -768,9 +760,7 @@ nsm_change_state (struct ospf_neighbor *nbr, int state) } } -#ifdef HAVE_OPAQUE_LSA ospf_opaque_nsm_change (nbr, old_state); -#endif /* HAVE_OPAQUE_LSA */ /* State changes from > ExStart to <= ExStart should clear any Exchange * or Full/LSA Update related lists and state. @@ -783,7 +773,7 @@ nsm_change_state (struct ospf_neighbor *nbr, int state) if (state == NSM_ExStart) { if (nbr->dd_seqnum == 0) - nbr->dd_seqnum = quagga_time (NULL); + nbr->dd_seqnum = (uint32_t)random (); else nbr->dd_seqnum++; diff --git a/ospfd/ospf_opaque.c b/ospfd/ospf_opaque.c index 4c05c77252..9b395b3e8e 100644 --- a/ospfd/ospf_opaque.c +++ b/ospfd/ospf_opaque.c @@ -22,12 +22,11 @@ */ /***** MTYPE definitions are not reflected to "memory.h" yet. *****/ -#define MTYPE_OSPF_OPAQUE_FUNCTAB 0 -#define MTYPE_OPAQUE_INFO_PER_TYPE 0 -#define MTYPE_OPAQUE_INFO_PER_ID 0 +#define MTYPE_OSPF_OPAQUE_FUNCTAB MTYPE_TMP +#define MTYPE_OPAQUE_INFO_PER_TYPE MTYPE_TMP +#define MTYPE_OPAQUE_INFO_PER_ID MTYPE_TMP #include -#ifdef HAVE_OPAQUE_LSA #include "linklist.h" #include "prefix.h" @@ -62,9 +61,8 @@ * Followings are initialize/terminate functions for Opaque-LSAs handling. *------------------------------------------------------------------------*/ -#ifdef HAVE_OSPF_TE #include "ospfd/ospf_te.h" -#endif /* HAVE_OSPF_TE */ +#include "ospfd/ospf_ri.h" #ifdef SUPPORT_OSPF_API int ospf_apiserver_init (void); @@ -87,10 +85,11 @@ ospf_opaque_init (void) ospf_opaque_register_vty (); ospf_opaque_funclist_init (); -#ifdef HAVE_OSPF_TE if (ospf_mpls_te_init () != 0) exit (1); -#endif /* HAVE_OSPF_TE */ + + if (ospf_router_info_init () != 0) + exit (1); #ifdef SUPPORT_OSPF_API if ((ospf_apiserver_enable) && (ospf_apiserver_init () != 0)) @@ -103,9 +102,9 @@ ospf_opaque_init (void) void ospf_opaque_term (void) { -#ifdef HAVE_OSPF_TE ospf_mpls_te_term (); -#endif /* HAVE_OSPF_TE */ + + ospf_router_info_term (); #ifdef SUPPORT_OSPF_API ospf_apiserver_term (); @@ -220,6 +219,12 @@ ospf_opaque_type_name (u_char opaque_type) case OPAQUE_TYPE_GRACE_LSA: name = "Grace-LSA"; break; + case OPAQUE_TYPE_INTER_AS_LSA: + name = "Inter-AS TE-v2 LSA"; + break; + case OPAQUE_TYPE_ROUTER_INFORMATION_LSA: + name = "Router Information LSA"; + break; default: if (OPAQUE_TYPE_RANGE_UNASSIGNED (opaque_type)) name = "Unassigned"; @@ -1986,6 +1991,7 @@ ospf_opaque_lsa_refresh_schedule (struct ospf_lsa *lsa0) struct opaque_info_per_type *oipt; struct opaque_info_per_id *oipi; struct ospf_lsa *lsa; + struct ospf *top; int delay; if ((oipt = lookup_opaque_info_by_type (lsa0)) == NULL @@ -2017,7 +2023,10 @@ ospf_opaque_lsa_refresh_schedule (struct ospf_lsa *lsa0) ospf_ls_retransmit_delete_nbr_area (lsa->area, lsa); break; case OSPF_OPAQUE_AS_LSA: - ospf_ls_retransmit_delete_nbr_as (lsa0->area->ospf, lsa); + top = ospf_lookup (); + if ((lsa0->area != NULL) && (lsa0->area->ospf != NULL)) + top = lsa0->area->ospf; + ospf_ls_retransmit_delete_nbr_as (top, lsa); break; default: zlog_warn ("ospf_opaque_lsa_refresh_schedule: Unexpected LSA-type(%u)", lsa->data->type); @@ -2062,6 +2071,9 @@ ospf_opaque_lsa_flush_schedule (struct ospf_lsa *lsa0) struct opaque_info_per_type *oipt; struct opaque_info_per_id *oipi; struct ospf_lsa *lsa; + struct ospf *top; + + top = ospf_lookup (); if ((oipt = lookup_opaque_info_by_type (lsa0)) == NULL || (oipi = lookup_opaque_info_by_id (oipt, lsa0)) == NULL) @@ -2085,7 +2097,9 @@ ospf_opaque_lsa_flush_schedule (struct ospf_lsa *lsa0) ospf_ls_retransmit_delete_nbr_area (lsa->area, lsa); break; case OSPF_OPAQUE_AS_LSA: - ospf_ls_retransmit_delete_nbr_as (lsa0->area->ospf, lsa); + if ((lsa0->area != NULL) && (lsa0->area->ospf != NULL)) + top = lsa0->area->ospf; + ospf_ls_retransmit_delete_nbr_as (top, lsa); break; default: zlog_warn ("ospf_opaque_lsa_flush_schedule: Unexpected LSA-type(%u)", lsa->data->type); @@ -2109,7 +2123,7 @@ ospf_opaque_lsa_flush_schedule (struct ospf_lsa *lsa0) zlog_debug ("Schedule Type-%u Opaque-LSA to FLUSH: [opaque-type=%u, opaque-id=%x]", lsa->data->type, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)), GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr))); /* This lsa will be flushed and removed eventually. */ - ospf_lsa_flush (lsa0->area->ospf, lsa); + ospf_lsa_flush (top, lsa); out: return; @@ -2151,28 +2165,6 @@ ospf_opaque_self_originated_lsa_received (struct ospf_neighbor *nbr, * Followings are util functions; probably be used by Opaque-LSAs only... *------------------------------------------------------------------------*/ -void -htonf (float *src, float *dst) -{ - u_int32_t lu1, lu2; - - memcpy (&lu1, src, sizeof (u_int32_t)); - lu2 = htonl (lu1); - memcpy (dst, &lu2, sizeof (u_int32_t)); - return; -} - -void -ntohf (float *src, float *dst) -{ - u_int32_t lu1, lu2; - - memcpy (&lu1, src, sizeof (u_int32_t)); - lu2 = ntohl (lu1); - memcpy (dst, &lu2, sizeof (u_int32_t)); - return; -} - struct ospf * oi_to_top (struct ospf_interface *oi) { @@ -2185,4 +2177,3 @@ oi_to_top (struct ospf_interface *oi) return top; } -#endif /* HAVE_OPAQUE_LSA */ diff --git a/ospfd/ospf_opaque.h b/ospfd/ospf_opaque.h index b9490a0ff2..2ac9b41efc 100644 --- a/ospfd/ospf_opaque.h +++ b/ospfd/ospf_opaque.h @@ -60,6 +60,10 @@ #define OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA 1 #define OPAQUE_TYPE_SYCAMORE_OPTICAL_TOPOLOGY_DESC 2 #define OPAQUE_TYPE_GRACE_LSA 3 +#define OPAQUE_TYPE_L1VPN_LSA 5 +#define OPAQUE_TYPE_ROUTER_INFORMATION_LSA 4 +#define OPAQUE_TYPE_INTER_AS_LSA 6 +#define OPAQUE_TYPE_MAX 6 /* Followings types are proposed in internet-draft documents. */ #define OPAQUE_TYPE_8021_QOSPF 129 @@ -70,7 +74,7 @@ #define OPAQUE_TYPE_WILDCARD 0 #define OPAQUE_TYPE_RANGE_UNASSIGNED(type) \ - ( 4 <= (type) && (type) <= 127) + ( OPAQUE_TYPE_MAX <= (type) && (type) <= 127) #define OPAQUE_TYPE_RANGE_RESERVED(type) \ (127 < (type) && (type) <= 255) @@ -137,8 +141,6 @@ extern void ospf_opaque_lsa_flush_schedule (struct ospf_lsa *lsa); extern void ospf_opaque_self_originated_lsa_received (struct ospf_neighbor *nbr, struct ospf_lsa *lsa); -extern void htonf (float *src, float *dst); -extern void ntohf (float *src, float *dst); extern struct ospf *oi_to_top (struct ospf_interface *oi); #endif /* _ZEBRA_OSPF_OPAQUE_H */ diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index 3f80bf214b..399a558a0d 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -913,7 +913,7 @@ ospf_hello (struct ip *iph, struct ospf_header *ospfh, /* Compare options. */ #define REJECT_IF_TBIT_ON 1 /* XXX */ #ifdef REJECT_IF_TBIT_ON - if (CHECK_FLAG (hello->options, OSPF_OPTION_T)) + if (CHECK_FLAG (hello->options, OSPF_OPTION_MT)) { /* * This router does not support non-zero TOS. @@ -925,7 +925,6 @@ ospf_hello (struct ip *iph, struct ospf_header *ospfh, } #endif /* REJECT_IF_TBIT_ON */ -#ifdef HAVE_OPAQUE_LSA if (CHECK_FLAG (oi->ospf->config, OSPF_OPAQUE_CAPABLE) && CHECK_FLAG (hello->options, OSPF_OPTION_O)) { @@ -941,7 +940,6 @@ ospf_hello (struct ip *iph, struct ospf_header *ospfh, UNSET_FLAG (hello->options, OSPF_OPTION_O); /* Ignore O-bit. */ #endif /* STRICT_OBIT_USAGE_CHECK */ } -#endif /* HAVE_OPAQUE_LSA */ /* new for NSSA is to ensure that NP is on and E is off */ @@ -1093,7 +1091,6 @@ ospf_db_desc_proc (struct stream *s, struct ospf_interface *oi, return; } -#ifdef HAVE_OPAQUE_LSA if (IS_OPAQUE_LSA (lsah->type) && ! CHECK_FLAG (nbr->options, OSPF_OPTION_O)) { @@ -1101,14 +1098,11 @@ ospf_db_desc_proc (struct stream *s, struct ospf_interface *oi, OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch); return; } -#endif /* HAVE_OPAQUE_LSA */ switch (lsah->type) { case OSPF_AS_EXTERNAL_LSA: -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: -#endif /* HAVE_OPAQUE_LSA */ /* Check for stub area. Reject if AS-External from stub but allow if from NSSA. */ if (oi->area->external_routing == OSPF_AREA_STUB) @@ -1271,7 +1265,7 @@ ospf_db_desc (struct ip *iph, struct ospf_header *ospfh, } #ifdef REJECT_IF_TBIT_ON - if (CHECK_FLAG (dd->options, OSPF_OPTION_T)) + if (CHECK_FLAG (dd->options, OSPF_OPTION_MT)) { /* * In Hello protocol, optional capability must have checked @@ -1282,7 +1276,6 @@ ospf_db_desc (struct ip *iph, struct ospf_header *ospfh, } #endif /* REJECT_IF_TBIT_ON */ -#ifdef HAVE_OPAQUE_LSA if (CHECK_FLAG (dd->options, OSPF_OPTION_O) && !CHECK_FLAG (oi->ospf->config, OSPF_OPAQUE_CAPABLE)) { @@ -1292,7 +1285,6 @@ ospf_db_desc (struct ip *iph, struct ospf_header *ospfh, */ UNSET_FLAG (dd->options, OSPF_OPTION_O); } -#endif /* HAVE_OPAQUE_LSA */ /* Add event to thread. */ OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_PacketReceived); @@ -1357,7 +1349,6 @@ ospf_db_desc (struct ip *iph, struct ospf_header *ospfh, /* This is where the real Options are saved */ nbr->options = dd->options; -#ifdef HAVE_OPAQUE_LSA if (CHECK_FLAG (oi->ospf->config, OSPF_OPAQUE_CAPABLE)) { if (IS_DEBUG_OSPF_EVENT) @@ -1375,7 +1366,6 @@ ospf_db_desc (struct ip *iph, struct ospf_header *ospfh, /* This situation is undesirable, but not a real error. */ } } -#endif /* HAVE_OPAQUE_LSA */ OSPF_NSM_EVENT_EXECUTE (nbr, NSM_NegotiationDone); @@ -1653,7 +1643,6 @@ ospf_ls_upd_list_lsa (struct ospf_neighbor *nbr, struct stream *s, if (ntohs (lsah->ls_age) > OSPF_LSA_MAXAGE) lsah->ls_age = htons (OSPF_LSA_MAXAGE); -#ifdef HAVE_OPAQUE_LSA if (CHECK_FLAG (nbr->options, OSPF_OPTION_O)) { #ifdef STRICT_OBIT_USAGE_CHECK @@ -1685,7 +1674,6 @@ ospf_ls_upd_list_lsa (struct ospf_neighbor *nbr, struct stream *s, zlog_warn ("LSA[Type%d:%s]: Opaque capability mismatch?", lsah->type, inet_ntoa (lsah->id)); continue; } -#endif /* HAVE_OPAQUE_LSA */ /* Create OSPF LSA instance. */ lsa = ospf_lsa_new (); @@ -1695,16 +1683,12 @@ ospf_ls_upd_list_lsa (struct ospf_neighbor *nbr, struct stream *s, switch (lsah->type) { case OSPF_AS_EXTERNAL_LSA: -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: -#endif /* HAVE_OPAQUE_LSA */ lsa->area = NULL; break; -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: lsa->oi = oi; /* Remember incoming interface for flooding control. */ /* Fallthrough */ -#endif /* HAVE_OPAQUE_LSA */ default: lsa->area = oi->area; break; @@ -1892,7 +1876,6 @@ ospf_ls_upd (struct ospf *ospf, struct ip *iph, struct ospf_header *ospfh, DISCARD_LSA (lsa, 3); } -#ifdef HAVE_OPAQUE_LSA if (IS_OPAQUE_LSA (lsa->data->type) && IPV4_ADDR_SAME (&lsa->data->adv_router, &oi->ospf->router_id)) { @@ -1940,7 +1923,6 @@ ospf_ls_upd (struct ospf *ospf, struct ip *iph, struct ospf_header *ospfh, continue; } } -#endif /* HAVE_OPAQUE_LSA */ /* It might be happen that received LSA is self-originated network LSA, but * router ID is changed. So, we should check if LSA is a network-LSA whose @@ -2161,7 +2143,7 @@ ospf_recv_packet (int fd, struct interface **ifp, struct stream *ibuf) int ret; struct ip *iph; u_int16_t ip_len; - unsigned int ifindex = 0; + ifindex_t ifindex = 0; struct iovec iov; /* Header and data both require alignment. */ char buff [CMSG_SPACE(SOPT_SIZE_CMSG_IFINDEX_IPV4())]; @@ -2517,7 +2499,6 @@ ospf_lsa_examin (struct lsa_header * lsah, const u_int16_t lsalen, const u_char case OSPF_SUMMARY_LSA: case OSPF_ASBR_SUMMARY_LSA: /* RFC2328 A.4.4, LSA header + 4 bytes followed by N>=1 4-bytes TOS blocks */ -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: @@ -2525,7 +2506,6 @@ ospf_lsa_examin (struct lsa_header * lsah, const u_int16_t lsalen, const u_char * data) padded to 32-bit alignment." This is considered equivalent * to 4-byte alignment of all other LSA types, see OSPF-ALIGNMENT.txt * file for the detailed analysis of this passage. */ -#endif ret = lsalen % 4 ? MSG_NG : MSG_OK; break; default: @@ -3157,10 +3137,8 @@ ospf_make_db_desc (struct ospf_interface *oi, struct ospf_neighbor *nbr, /* Set Options. */ options = OPTIONS (oi); -#ifdef HAVE_OPAQUE_LSA if (CHECK_FLAG (oi->ospf->config, OSPF_OPAQUE_CAPABLE)) SET_FLAG (options, OSPF_OPTION_O); -#endif /* HAVE_OPAQUE_LSA */ stream_putc (s, options); /* DD flags */ @@ -3185,7 +3163,6 @@ ospf_make_db_desc (struct ospf_interface *oi, struct ospf_neighbor *nbr, for (rn = route_top (table); rn; rn = route_next (rn)) if ((lsa = rn->info) != NULL) { -#ifdef HAVE_OPAQUE_LSA if (IS_OPAQUE_LSA (lsa->data->type) && (! CHECK_FLAG (options, OSPF_OPTION_O))) { @@ -3194,7 +3171,6 @@ ospf_make_db_desc (struct ospf_interface *oi, struct ospf_neighbor *nbr, ospf_lsdb_delete (lsdb, lsa); continue; } -#endif /* HAVE_OPAQUE_LSA */ if (!CHECK_FLAG (lsa->flags, OSPF_LSA_DISCARD)) { diff --git a/ospfd/ospf_ri.c b/ospfd/ospf_ri.c new file mode 100644 index 0000000000..8fefd2bdb8 --- /dev/null +++ b/ospfd/ospf_ri.c @@ -0,0 +1,1639 @@ +/* + * This is an implementation of RFC4970 Router Information + * with support of RFC5088 PCE Capabilites announcement + * + * Module name: Router Information + * Version: 0.99.22 + * Created: 2012-02-01 by Olivier Dugeon + * Copyright (C) 2012 Orange Labs http://www.orange.com/ + * + * This file is part of GNU Quagga. + * + * 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 Quagga 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 Quagga; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include +#include + +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "table.h" +#include "memory.h" +#include "command.h" +#include "vty.h" +#include "stream.h" +#include "log.h" +#include "thread.h" +#include "hash.h" +#include "sockunion.h" /* for inet_aton() */ + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_ism.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_flood.h" +#include "ospfd/ospf_packet.h" +#include "ospfd/ospf_spf.h" +#include "ospfd/ospf_dump.h" +#include "ospfd/ospf_route.h" +#include "ospfd/ospf_ase.h" +#include "ospfd/ospf_zebra.h" +#include "ospfd/ospf_ri.h" +#include "ospfd/ospf_te.h" + +struct ospf_pce_info +{ + + /* Store Router Information PCE TLV and SubTLV in network byte order. */ + struct ri_tlv_pce pce_header; + struct ri_pce_subtlv_address pce_address; + struct ri_pce_subtlv_path_scope pce_scope; + struct list *pce_domain; + struct list *pce_neighbor; + struct ri_pce_subtlv_cap_flag pce_cap_flag; +}; + +/* Following structure are internal use only. */ +struct ospf_router_info +{ + status_t status; + + u_int8_t registered; + u_int8_t scope; + + /* Flags to manage this router information. */ +#define RIFLG_LOOKUP_DONE 0x1 +#define RIFLG_LSA_ENGAGED 0x2 +#define RIFLG_LSA_FORCED_REFRESH 0x4 + u_int32_t flags; + + /* area pointer if flooding is Type 10 Null if flooding is AS scope */ + struct ospf_area *area; + struct in_addr area_id; + + /* Store Router Information Capabilities LSA */ + struct ri_tlv_router_cap router_cap; + + /* Store PCE capability LSA */ + struct ospf_pce_info pce_info; +}; + +/* + * Global variable to manage Opaque-LSA/Router Information on this node. + * Note that all parameter values are stored in network byte order. + */ +static struct ospf_router_info OspfRI; + +/*------------------------------------------------------------------------------* + * Followings are initialize/terminate functions for Router Information handling. + *------------------------------------------------------------------------------*/ + +static void ospf_router_info_ism_change (struct ospf_interface *oi, + int old_status); +static void ospf_router_info_nsm_change (struct ospf_neighbor *nbr, + int old_status); +static void ospf_router_info_config_write_router (struct vty *vty); +static void ospf_router_info_show_info (struct vty *vty, + struct ospf_lsa *lsa); +static int ospf_router_info_lsa_originate (void *arg); +static struct ospf_lsa *ospf_router_info_lsa_refresh (struct ospf_lsa *lsa); +static void ospf_router_info_lsa_schedule (opcode_t opcode); +static void ospf_router_info_register_vty (void); +static void del_pce_info (void *val); + +int +ospf_router_info_init (void) +{ + + memset (&OspfRI, 0, sizeof (struct ospf_router_info)); + OspfRI.status = disabled; + OspfRI.registered = 0; + OspfRI.scope = OSPF_OPAQUE_AS_LSA; + OspfRI.flags = 0; + + /* Initialize pce domain and neighbor list */ + OspfRI.pce_info.pce_domain = list_new (); + OspfRI.pce_info.pce_domain->del = del_pce_info; + OspfRI.pce_info.pce_neighbor = list_new (); + OspfRI.pce_info.pce_neighbor->del = del_pce_info; + + ospf_router_info_register_vty (); + + return 0; +} + +static int +ospf_router_info_register (u_int8_t scope) +{ + int rc = 0; + + if (OspfRI.registered) + return 0; + + zlog_info ("Register Router Information with scope %s(%d)", + scope == OSPF_OPAQUE_AREA_LSA ? "Area" : "AS", scope); + rc = ospf_register_opaque_functab (scope, + OPAQUE_TYPE_ROUTER_INFORMATION_LSA, + NULL, /* new interface */ + NULL, /* del interface */ + ospf_router_info_ism_change, + ospf_router_info_nsm_change, + ospf_router_info_config_write_router, + NULL, /* Config. write interface */ + NULL, /* Config. write debug */ + ospf_router_info_show_info, + ospf_router_info_lsa_originate, + ospf_router_info_lsa_refresh, + NULL, /* new_lsa_hook */ + NULL); /* del_lsa_hook */ + + if (rc != 0) + { + zlog_warn ("ospf_router_info_init: Failed to register functions"); + return rc; + } + + OspfRI.registered = 1; + OspfRI.scope = scope; + return 0; +} + +static int +ospf_router_info_unregister () +{ + + if ((OspfRI.scope != OSPF_OPAQUE_AS_LSA) + && (OspfRI.scope != OSPF_OPAQUE_AREA_LSA)) + { + zlog_warn ("Unable to unregister Router Info functions: Wrong scope!"); + return -1; + } + + ospf_delete_opaque_functab (OspfRI.scope, + OPAQUE_TYPE_ROUTER_INFORMATION_LSA); + + OspfRI.registered = 0; + return 0; + +} + +void +ospf_router_info_term (void) +{ + + list_delete (OspfRI.pce_info.pce_domain); + list_delete (OspfRI.pce_info.pce_neighbor); + + OspfRI.pce_info.pce_domain = NULL; + OspfRI.pce_info.pce_neighbor = NULL; + OspfRI.status = disabled; + + ospf_router_info_unregister (); + + return; +} + +static void +del_pce_info (void *val) +{ + XFREE (MTYPE_OSPF_PCE_PARAMS, val); + return; +} + +/*------------------------------------------------------------------------* + * Followings are control functions for ROUTER INFORMATION parameters management. + *------------------------------------------------------------------------*/ + +static void +set_router_info_capabilities (struct ri_tlv_router_cap *ric, u_int32_t cap) +{ + ric->header.type = htons (RI_TLV_CAPABILITIES); + ric->header.length = htons (RI_TLV_LENGTH); + ric->value = htonl (cap); + return; +} + +static int +set_pce_header (struct ospf_pce_info *pce) +{ + u_int16_t length = 0; + struct listnode *node; + struct ri_pce_subtlv_domain *domain; + struct ri_pce_subtlv_neighbor *neighbor; + + /* PCE Address */ + if (ntohs (pce->pce_address.header.type) != 0) + length += RI_TLV_SIZE (&pce->pce_address.header); + + /* PCE Path Scope */ + if (ntohs (pce->pce_scope.header.type) != 0) + length += RI_TLV_SIZE (&pce->pce_scope.header); + + /* PCE Domain */ + for (ALL_LIST_ELEMENTS_RO (pce->pce_domain, node, domain)) + { + if (ntohs (domain->header.type) != 0) + length += RI_TLV_SIZE (&domain->header); + } + + /* PCE Neighbor */ + for (ALL_LIST_ELEMENTS_RO (pce->pce_neighbor, node, neighbor)) + { + if (ntohs (neighbor->header.type) != 0) + length += RI_TLV_SIZE (&neighbor->header); + } + + /* PCE Capabilities */ + if (ntohs (pce->pce_cap_flag.header.type) != 0) + length += RI_TLV_SIZE (&pce->pce_cap_flag.header); + + if (length != 0) + { + pce->pce_header.header.type = htons (RI_TLV_PCE); + pce->pce_header.header.length = htons (length); + } + else + { + pce->pce_header.header.type = 0; + pce->pce_header.header.length = 0; + } + + return length; +} + +static void +set_pce_address (struct in_addr ipv4, struct ospf_pce_info *pce) +{ + + /* Enable PCE Info */ + pce->pce_header.header.type = htons (RI_TLV_PCE); + /* Set PCE Address */ + pce->pce_address.header.type = htons (RI_PCE_SUBTLV_ADDRESS); + pce->pce_address.header.length = htons (PCE_ADDRESS_LENGTH_IPV4); + pce->pce_address.address.type = htons (PCE_ADDRESS_TYPE_IPV4); + pce->pce_address.address.value = ipv4; + + return; +} + +static void +set_pce_path_scope (u_int32_t scope, struct ospf_pce_info *pce) +{ + + /* Enable PCE Info */ + pce->pce_header.header.type = htons (RI_TLV_PCE); + /* Set PCE Scope */ + pce->pce_scope.header.type = htons (RI_PCE_SUBTLV_PATH_SCOPE); + pce->pce_scope.header.length = htons (RI_TLV_LENGTH); + pce->pce_scope.value = htonl (scope); + + return; +} + +static void +set_pce_domain (u_int16_t type, u_int32_t domain, struct ospf_pce_info *pce) +{ + + struct ri_pce_subtlv_domain *new; + + /* Enable PCE Info */ + pce->pce_header.header.type = htons (RI_TLV_PCE); + + /* Create new domain info */ + new = + XCALLOC (MTYPE_OSPF_PCE_PARAMS, + sizeof (struct ri_pce_subtlv_domain)); + + new->header.type = htons (RI_PCE_SUBTLV_DOMAIN); + new->header.length = htons (PCE_ADDRESS_LENGTH_IPV4); + new->type = htons (type); + new->value = htonl (domain); + + /* Add new domain to the list */ + listnode_add (pce->pce_domain, new); + + return; +} + +static void +unset_pce_domain (u_int16_t type, u_int32_t domain, struct ospf_pce_info *pce) +{ + struct listnode *node; + struct ri_pce_subtlv_domain *old = NULL; + int found = 0; + + /* Search the corresponding node */ + for (ALL_LIST_ELEMENTS_RO (pce->pce_domain, node, old)) + { + if ((old->type == htons (type)) && (old->value == htonl (domain))) + { + found = 1; + break; + } + } + + /* if found remove it */ + if (found) + { + listnode_delete (pce->pce_domain, old); + + /* Avoid misjudgement in the next lookup. */ + if (listcount (pce->pce_domain) == 0) + pce->pce_domain->head = pce->pce_domain->tail = NULL; + + /* Finally free the old domain */ + XFREE (MTYPE_OSPF_PCE_PARAMS, old); + } +} + +static void +set_pce_neighbor (u_int16_t type, u_int32_t domain, struct ospf_pce_info *pce) +{ + + struct ri_pce_subtlv_neighbor *new; + + /* Enable PCE Info */ + pce->pce_header.header.type = htons (RI_TLV_PCE); + + /* Create new neighbor info */ + new = + XCALLOC (MTYPE_OSPF_PCE_PARAMS, + sizeof (struct ri_pce_subtlv_neighbor)); + + new->header.type = htons (RI_PCE_SUBTLV_NEIGHBOR); + new->header.length = htons (PCE_ADDRESS_LENGTH_IPV4); + new->type = htons (type); + new->value = htonl (domain); + + /* Add new domain to the list */ + listnode_add (pce->pce_neighbor, new); + + return; +} + +static void +unset_pce_neighbor (u_int16_t type, u_int32_t domain, + struct ospf_pce_info *pce) +{ + struct listnode *node; + struct ri_pce_subtlv_neighbor *old = NULL; + int found = 0; + + /* Search the corresponding node */ + for (ALL_LIST_ELEMENTS_RO (pce->pce_neighbor, node, old)) + { + if ((old->type == htons (type)) && (old->value == htonl (domain))) + { + found = 1; + break; + } + } + + /* if found remove it */ + if (found) + { + listnode_delete (pce->pce_neighbor, old); + + /* Avoid misjudgement in the next lookup. */ + if (listcount (pce->pce_neighbor) == 0) + pce->pce_neighbor->head = pce->pce_neighbor->tail = NULL; + + /* Finally free the old domain */ + XFREE (MTYPE_OSPF_PCE_PARAMS, old); + } +} + +static void +set_pce_cap_flag (u_int32_t cap, struct ospf_pce_info *pce) +{ + + /* Enable PCE Info */ + pce->pce_header.header.type = htons (RI_TLV_PCE); + /* Set PCE Capabilities flag */ + pce->pce_cap_flag.header.type = htons (RI_PCE_SUBTLV_CAP_FLAG); + pce->pce_cap_flag.header.length = htons (RI_TLV_LENGTH); + pce->pce_cap_flag.value = htonl (cap); + + return; +} + + +static void +unset_param (struct ri_tlv_header *tlv) +{ + + tlv->type = 0; + /* Fill the Value to 0 */ + memset ((tlv + RI_TLV_HDR_SIZE), 0, RI_TLV_BODY_SIZE (tlv)); + tlv->length = 0; + + return; +} + +static void +initialize_params (struct ospf_router_info *ori) +{ + u_int32_t cap; + struct ospf *top; + + /* + * Initialize default Router Information Capabilities. + */ + cap = 0; + cap = cap | RI_TE_SUPPORT; + + set_router_info_capabilities (&ori->router_cap, cap); + + /* If Area address is not null and exist, retrieve corresponding structure */ + top = ospf_lookup (); + zlog_info ("RI-> Initialize Router Info for %s scope within area %s", + OspfRI.scope == OSPF_OPAQUE_AREA_LSA ? "Area" : "AS", + inet_ntoa (OspfRI.area_id)); + + /* Try to get the Area context at this step. Do it latter if not available */ + if ((OspfRI.scope == OSPF_OPAQUE_AREA_LSA) && (OspfRI.area == NULL)) + OspfRI.area = ospf_area_lookup_by_area_id (top, OspfRI.area_id); + + /* + * Initialize default PCE Information values + */ + /* PCE address == OSPF Router ID */ + set_pce_address (top->router_id, &ori->pce_info); + + /* PCE scope */ + cap = 7; /* Set L, R and Rd bits to one = intra & inter-area path computation */ + set_pce_path_scope (cap, &ori->pce_info); + + /* PCE Capabilities */ + cap = + PCE_CAP_BIDIRECTIONAL | PCE_CAP_DIVERSE_PATH | PCE_CAP_OBJECTIVES | + PCE_CAP_ADDITIVE | PCE_CAP_MULTIPLE_REQ; + set_pce_cap_flag (cap, &ori->pce_info); + + /* Finally compute PCE header */ + set_pce_header (&ori->pce_info); + + return; +} + +static int +is_mandated_params_set (struct ospf_router_info ori) +{ + int rc = 0; + + if (ntohs (ori.router_cap.header.type) == 0) + goto out; + + if ((ntohs (ori.pce_info.pce_header.header.type) == RI_TLV_PCE) + && (ntohs (ori.pce_info.pce_address.header.type) == 0) + && (ntohs (ori.pce_info.pce_cap_flag.header.type) == 0)) + goto out; + + rc = 1; + +out: + return rc; +} + +/*------------------------------------------------------------------------* + * Followings are callback functions against generic Opaque-LSAs handling. + *------------------------------------------------------------------------*/ +static void +ospf_router_info_ism_change (struct ospf_interface *oi, int old_state) +{ + /* So far, nothing to do here. */ + return; + +} + +static void +ospf_router_info_nsm_change (struct ospf_neighbor *nbr, int old_state) +{ + + /* So far, nothing to do here. */ + return; +} + +/*------------------------------------------------------------------------* + * Followings are OSPF protocol processing functions for ROUTER INFORMATION + *------------------------------------------------------------------------*/ + +static void +build_tlv_header (struct stream *s, struct ri_tlv_header *tlvh) +{ + + stream_put (s, tlvh, sizeof (struct ri_tlv_header)); + return; +} + +static void +build_tlv (struct stream *s, struct ri_tlv_header *tlvh) +{ + + if (ntohs (tlvh->type) != 0) + { + build_tlv_header (s, tlvh); + stream_put (s, tlvh + 1, RI_TLV_BODY_SIZE (tlvh)); + } + return; +} + +static void +ospf_router_info_lsa_body_set (struct stream *s) +{ + + struct listnode *node; + struct ri_pce_subtlv_domain *domain; + struct ri_pce_subtlv_neighbor *neighbor; + + /* Build Router Information TLV */ + build_tlv (s, &OspfRI.router_cap.header); + + /* Add RI PCE TLV if it is set */ + /* Compute PCE Info header first */ + if ((set_pce_header (&OspfRI.pce_info)) != 0) + { + + /* Build PCE TLV */ + build_tlv_header (s, &OspfRI.pce_info.pce_header.header); + + /* Build PCE address sub-tlv */ + build_tlv (s, &OspfRI.pce_info.pce_address.header); + + /* Build PCE path scope sub-tlv */ + build_tlv (s, &OspfRI.pce_info.pce_scope.header); + + /* Build PCE domain sub-tlv */ + for (ALL_LIST_ELEMENTS_RO (OspfRI.pce_info.pce_domain, node, domain)) + build_tlv (s, &domain->header); + + /* Build PCE neighbor sub-tlv */ + for (ALL_LIST_ELEMENTS_RO + (OspfRI.pce_info.pce_neighbor, node, neighbor)) + build_tlv (s, &neighbor->header); + + /* Build PCE cap flag sub-tlv */ + build_tlv (s, &OspfRI.pce_info.pce_cap_flag.header); + } + + return; +} + +/* Create new opaque-LSA. */ +static struct ospf_lsa * +ospf_router_info_lsa_new () +{ + struct ospf *top; + struct stream *s; + struct lsa_header *lsah; + struct ospf_lsa *new = NULL; + u_char options, lsa_type; + struct in_addr lsa_id; + u_int32_t tmp; + u_int16_t length; + + /* Create a stream for LSA. */ + if ((s = stream_new (OSPF_MAX_LSA_SIZE)) == NULL) + { + zlog_warn ("ospf_router_info_lsa_new: stream_new() ?"); + goto out; + } + lsah = (struct lsa_header *) STREAM_DATA (s); + + options = OSPF_OPTION_E; /* Enable AS external as we flood RI with Opaque Type 11 */ + options |= OSPF_OPTION_O; /* Don't forget this :-) */ + + lsa_type = OspfRI.scope; + /* LSA ID == 0 for Router Information see RFC 4970 */ + tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_ROUTER_INFORMATION_LSA, 0); + lsa_id.s_addr = htonl (tmp); + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_debug + ("LSA[Type%d:%s]: Create an Opaque-LSA/ROUTER INFORMATION instance", + lsa_type, inet_ntoa (lsa_id)); + + top = ospf_lookup (); + + /* Set opaque-LSA header fields. */ + lsa_header_set (s, options, lsa_type, lsa_id, top->router_id); + + /* Set opaque-LSA body fields. */ + ospf_router_info_lsa_body_set (s); + + /* Set length. */ + length = stream_get_endp (s); + lsah->length = htons (length); + + /* Now, create an OSPF LSA instance. */ + if ((new = ospf_lsa_new ()) == NULL) + { + zlog_warn ("ospf_router_info_lsa_new: ospf_lsa_new() ?"); + stream_free (s); + goto out; + } + if ((new->data = ospf_lsa_data_new (length)) == NULL) + { + zlog_warn ("ospf_router_info_lsa_new: ospf_lsa_data_new() ?"); + ospf_lsa_unlock (&new); + new = NULL; + stream_free (s); + goto out; + } + + new->area = OspfRI.area; /* Area must be null if the Opaque type is AS scope, fulfill otherwise */ + + SET_FLAG (new->flags, OSPF_LSA_SELF); + memcpy (new->data, lsah, length); + stream_free (s); + +out:return new; +} + +static int +ospf_router_info_lsa_originate1 (void *arg) +{ + struct ospf_lsa *new; + struct ospf *top; + struct ospf_area *area; + int rc = -1; + + /* First check if the area is known if flooding scope is Area */ + if (OspfRI.scope == OSPF_OPAQUE_AREA_LSA) + { + area = (struct ospf_area *) arg; + if (area->area_id.s_addr != OspfRI.area_id.s_addr) + { + zlog_debug + ("RI -> This is not the Router Information Area. Stop processing"); + goto out; + } + OspfRI.area = area; + } + + /* Create new Opaque-LSA/ROUTER INFORMATION instance. */ + if ((new = ospf_router_info_lsa_new ()) == NULL) + { + zlog_warn + ("ospf_router_info_lsa_originate1: ospf_router_info_lsa_new() ?"); + goto out; + } + + /* Get ospf info */ + top = ospf_lookup (); + + /* Install this LSA into LSDB. */ + if (ospf_lsa_install (top, NULL /*oi */ , new) == NULL) + { + zlog_warn ("ospf_router_info_lsa_originate1: ospf_lsa_install() ?"); + ospf_lsa_unlock (&new); + goto out; + } + + /* Now this Router Info parameter entry has associated LSA. */ + SET_FLAG (OspfRI.flags, RIFLG_LSA_ENGAGED); + + /* Update new LSA origination count. */ + top->lsa_originate_count++; + + /* Flood new LSA through AS. */ + if (OspfRI.scope == OSPF_OPAQUE_AS_LSA) + ospf_flood_through_as (top, NULL /*nbr */ , new); + else + ospf_flood_through_area (OspfRI.area, NULL /*nbr */ , new); + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + { + zlog_debug ("LSA[Type%d:%s]: Originate Opaque-LSA/ROUTER INFORMATION", + new->data->type, inet_ntoa (new->data->id)); + ospf_lsa_header_dump (new->data); + } + + rc = 0; +out:return rc; +} + +static int +ospf_router_info_lsa_originate (void *arg) +{ + + int rc = -1; + + if (OspfRI.status == disabled) + { + zlog_info + ("ospf_router_info_lsa_originate: ROUTER INFORMATION is disabled now."); + rc = 0; /* This is not an error case. */ + goto out; + } + + /* Check if Router Information LSA is already engaged */ + if (OspfRI.flags & RIFLG_LSA_ENGAGED) + { + if (OspfRI.flags & RIFLG_LSA_FORCED_REFRESH) + { + OspfRI.flags &= ~RIFLG_LSA_FORCED_REFRESH; + ospf_router_info_lsa_schedule (REFRESH_THIS_LSA); + } + } + else + { + if (!is_mandated_params_set (OspfRI)) + zlog_warn + ("ospf_router_info_lsa_originate: lacks mandated ROUTER INFORMATION parameters"); + + /* Ok, let's try to originate an LSA */ + if (ospf_router_info_lsa_originate1 (arg) != 0) + goto out; + } + + rc = 0; +out:return rc; +} + +static struct ospf_lsa * +ospf_router_info_lsa_refresh (struct ospf_lsa *lsa) +{ + struct ospf_lsa *new = NULL; + struct ospf *top; + + if (OspfRI.status == disabled) + { + /* + * This LSA must have flushed before due to ROUTER INFORMATION status change. + * It seems a slip among routers in the routing domain. + */ + zlog_info + ("ospf_router_info_lsa_refresh: ROUTER INFORMATION is disabled now."); + lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); /* Flush it anyway. */ + } + + /* Verify that the Router Information ID is supported */ + if (GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr)) != 0) + { + zlog_warn + ("ospf_router_info_lsa_refresh: Unsupported Router Information ID"); + goto out; + } + + /* If the lsa's age reached to MaxAge, start flushing procedure. */ + if (IS_LSA_MAXAGE (lsa)) + { + OspfRI.flags &= ~RIFLG_LSA_ENGAGED; + ospf_opaque_lsa_flush_schedule (lsa); + goto out; + } + + /* Create new Opaque-LSA/ROUTER INFORMATION instance. */ + if ((new = ospf_router_info_lsa_new ()) == NULL) + { + zlog_warn + ("ospf_router_info_lsa_refresh: ospf_router_info_lsa_new() ?"); + goto out; + } + new->data->ls_seqnum = lsa_seqnum_increment (lsa); + + /* Install this LSA into LSDB. */ + /* Given "lsa" will be freed in the next function. */ + top = ospf_lookup (); + if (ospf_lsa_install (top, NULL /*oi */ , new) == NULL) + { + zlog_warn ("ospf_router_info_lsa_refresh: ospf_lsa_install() ?"); + ospf_lsa_unlock (&new); + goto out; + } + + /* Flood updated LSA through AS or AREA depending of OspfRI.scope. */ + if (OspfRI.scope == OSPF_OPAQUE_AS_LSA) + ospf_flood_through_as (top, NULL /*nbr */ , new); + else + ospf_flood_through_area (OspfRI.area, NULL /*nbr */ , new); + + /* Debug logging. */ + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + { + zlog_debug ("LSA[Type%d:%s]: Refresh Opaque-LSA/ROUTER INFORMATION", + new->data->type, inet_ntoa (new->data->id)); + ospf_lsa_header_dump (new->data); + } + +out:return new; +} + +static void +ospf_router_info_lsa_schedule (opcode_t opcode) +{ + struct ospf_lsa lsa; + struct lsa_header lsah; + struct ospf *top; + u_int32_t tmp; + + memset (&lsa, 0, sizeof (lsa)); + memset (&lsah, 0, sizeof (lsah)); + + zlog_debug ("RI-> LSA schedule %s%s%s", + opcode == REORIGINATE_THIS_LSA ? "Re-Originate" : "", + opcode == REFRESH_THIS_LSA ? "Refresh" : "", + opcode == FLUSH_THIS_LSA ? "Flush" : ""); + + top = ospf_lookup (); + if ((OspfRI.scope == OSPF_OPAQUE_AREA_LSA) && (OspfRI.area == NULL)) + { + zlog_warn + ("ospf_router_info_lsa_schedule(): Router Info is Area scope flooding but area is not set"); + OspfRI.area = ospf_area_lookup_by_area_id (top, OspfRI.area_id); + } + lsa.area = OspfRI.area; + lsa.data = &lsah; + lsah.type = OspfRI.scope; + + /* LSA ID is set to 0 for the Router Information. See RFC 4970 */ + tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_ROUTER_INFORMATION_LSA, 0); + lsah.id.s_addr = htonl (tmp); + + switch (opcode) + { + case REORIGINATE_THIS_LSA: + if (OspfRI.scope == OSPF_OPAQUE_AREA_LSA) + ospf_opaque_lsa_reoriginate_schedule ((void *) OspfRI.area, + OSPF_OPAQUE_AREA_LSA, + OPAQUE_TYPE_ROUTER_INFORMATION_LSA); + else + ospf_opaque_lsa_reoriginate_schedule ((void *) top, + OSPF_OPAQUE_AS_LSA, + OPAQUE_TYPE_ROUTER_INFORMATION_LSA); + break; + case REFRESH_THIS_LSA: + ospf_opaque_lsa_refresh_schedule (&lsa); + break; + case FLUSH_THIS_LSA: + OspfRI.flags &= ~RIFLG_LSA_ENGAGED; + ospf_opaque_lsa_flush_schedule (&lsa); + break; + default: + zlog_warn ("ospf_router_info_lsa_schedule: Unknown opcode (%u)", + opcode); + break; + } + + return; +} + +/*------------------------------------------------------------------------* + * Followings are vty session control functions. + *------------------------------------------------------------------------*/ + +static u_int16_t +show_vty_router_cap (struct vty *vty, struct ri_tlv_header *tlvh) +{ + struct ri_tlv_router_cap *top = (struct ri_tlv_router_cap *) tlvh; + + if (vty != NULL) + vty_out (vty, " Router Capabilities: 0x%x%s", ntohl (top->value), + VTY_NEWLINE); + else + zlog_debug (" Router Capabilities: 0x%x", ntohl (top->value)); + + return RI_TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_pce_subtlv_address (struct vty *vty, struct ri_tlv_header *tlvh) +{ + struct ri_pce_subtlv_address *top = (struct ri_pce_subtlv_address *) tlvh; + + if (ntohs (top->address.type) == PCE_ADDRESS_TYPE_IPV4) + { + if (vty != NULL) + vty_out (vty, " PCE Address: %s%s", inet_ntoa (top->address.value), + VTY_NEWLINE); + else + zlog_debug (" PCE Address: %s", inet_ntoa (top->address.value)); + } + else + { + /* TODO: Add support to IPv6 with inet_ntop() */ + if (vty != NULL) + vty_out (vty, " PCE Address: 0x%x%s", + ntohl (top->address.value.s_addr), VTY_NEWLINE); + else + zlog_debug (" PCE Address: 0x%x", + ntohl (top->address.value.s_addr)); + } + + return RI_TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_pce_subtlv_path_scope (struct vty *vty, struct ri_tlv_header *tlvh) +{ + struct ri_pce_subtlv_path_scope *top = + (struct ri_pce_subtlv_path_scope *) tlvh; + + if (vty != NULL) + vty_out (vty, " PCE Path Scope: 0x%x%s", ntohl (top->value), + VTY_NEWLINE); + else + zlog_debug (" PCE Path Scope: 0x%x", ntohl (top->value)); + + return RI_TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_pce_subtlv_domain (struct vty *vty, struct ri_tlv_header *tlvh) +{ + struct ri_pce_subtlv_domain *top = (struct ri_pce_subtlv_domain *) tlvh; + struct in_addr tmp; + + if (ntohs (top->type) == PCE_DOMAIN_TYPE_AREA) + { + tmp.s_addr = top->value; + if (vty != NULL) + vty_out (vty, " PCE domain Area: %s%s", inet_ntoa (tmp), + VTY_NEWLINE); + else + zlog_debug (" PCE domain Area: %s", inet_ntoa (tmp)); + } + else + { + if (vty != NULL) + vty_out (vty, " PCE domain AS: %d%s", ntohl (top->value), + VTY_NEWLINE); + else + zlog_debug (" PCE domain AS: %d", ntohl (top->value)); + } + return RI_TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_pce_subtlv_neighbor (struct vty *vty, struct ri_tlv_header *tlvh) +{ + + struct ri_pce_subtlv_neighbor *top = (struct ri_pce_subtlv_neighbor *) tlvh; + struct in_addr tmp; + + if (ntohs (top->type) == PCE_DOMAIN_TYPE_AREA) + { + tmp.s_addr = top->value; + if (vty != NULL) + vty_out (vty, " PCE neighbor Area: %s%s", inet_ntoa (tmp), + VTY_NEWLINE); + else + zlog_debug (" PCE neighbor Area: %s", inet_ntoa (tmp)); + } + else + { + if (vty != NULL) + vty_out (vty, " PCE neighbor AS: %d%s", ntohl (top->value), + VTY_NEWLINE); + else + zlog_debug (" PCE neighbor AS: %d", ntohl (top->value)); + } + return RI_TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_pce_subtlv_cap_flag (struct vty *vty, struct ri_tlv_header *tlvh) +{ + struct ri_pce_subtlv_cap_flag *top = (struct ri_pce_subtlv_cap_flag *) tlvh; + + if (vty != NULL) + vty_out (vty, " PCE Capabilities Flag: 0x%x%s", ntohl (top->value), + VTY_NEWLINE); + else + zlog_debug (" PCE Capabilities Flag: 0x%x", ntohl (top->value)); + + return RI_TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_unknown_tlv (struct vty *vty, struct ri_tlv_header *tlvh) +{ + if (vty != NULL) + vty_out (vty, " Unknown TLV: [type(0x%x), length(0x%x)]%s", + ntohs (tlvh->type), ntohs (tlvh->length), VTY_NEWLINE); + else + zlog_debug (" Unknown TLV: [type(0x%x), length(0x%x)]", + ntohs (tlvh->type), ntohs (tlvh->length)); + + return RI_TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_pce_info (struct vty *vty, struct ri_tlv_header *ri, uint32_t total) +{ + struct ri_tlv_header *tlvh; + u_int16_t sum = 0; + + for (tlvh = ri; sum < total; tlvh = RI_TLV_HDR_NEXT (tlvh)) + { + switch (ntohs (tlvh->type)) + { + case RI_PCE_SUBTLV_ADDRESS: + sum += show_vty_pce_subtlv_address (vty, tlvh); + break; + case RI_PCE_SUBTLV_PATH_SCOPE: + sum += show_vty_pce_subtlv_path_scope (vty, tlvh); + break; + case RI_PCE_SUBTLV_DOMAIN: + sum += show_vty_pce_subtlv_domain (vty, tlvh); + break; + case RI_PCE_SUBTLV_NEIGHBOR: + sum += show_vty_pce_subtlv_neighbor (vty, tlvh); + break; + case RI_PCE_SUBTLV_CAP_FLAG: + sum += show_vty_pce_subtlv_cap_flag (vty, tlvh); + break; + default: + sum += show_vty_unknown_tlv (vty, tlvh); + break; + } + } + return sum; +} + +static void +ospf_router_info_show_info (struct vty *vty, struct ospf_lsa *lsa) +{ + struct lsa_header *lsah = (struct lsa_header *) lsa->data; + struct ri_tlv_header *tlvh; + u_int16_t length = 0, sum = 0; + + /* Initialize TLV browsing */ + length = ntohs (lsah->length) - OSPF_LSA_HEADER_SIZE; + + for (tlvh = RI_TLV_HDR_TOP (lsah); sum < length; + tlvh = RI_TLV_HDR_NEXT (tlvh)) + { + switch (ntohs (tlvh->type)) + { + case RI_TLV_CAPABILITIES: + sum += show_vty_router_cap (vty, tlvh); + break; + case RI_TLV_PCE: + tlvh++; + sum += RI_TLV_HDR_SIZE; + sum += show_vty_pce_info (vty, tlvh, length - sum); + break; + default: + sum += show_vty_unknown_tlv (vty, tlvh); + break; + } + } + + return; +} + +static void +ospf_router_info_config_write_router (struct vty *vty) +{ + struct ospf_pce_info *pce = &OspfRI.pce_info; + struct listnode *node; + struct ri_pce_subtlv_domain *domain; + struct ri_pce_subtlv_neighbor *neighbor; + struct in_addr tmp; + + if (OspfRI.status == enabled) + { + if (OspfRI.scope == OSPF_OPAQUE_AS_LSA) + vty_out (vty, " router-info as%s", VTY_NEWLINE); + else + vty_out (vty, " router-info area %s%s", inet_ntoa (OspfRI.area_id), + VTY_NEWLINE); + + if (pce->pce_address.header.type != 0) + vty_out (vty, " pce address %s%s", + inet_ntoa (pce->pce_address.address.value), VTY_NEWLINE); + + if (pce->pce_cap_flag.header.type != 0) + vty_out (vty, " pce flag 0x%x%s", ntohl (pce->pce_cap_flag.value), + VTY_NEWLINE); + + for (ALL_LIST_ELEMENTS_RO (pce->pce_domain, node, domain)) + { + if (domain->header.type != 0) + { + if (domain->type == PCE_DOMAIN_TYPE_AREA) + { + tmp.s_addr = domain->value; + vty_out (vty, " pce domain area %s%s", inet_ntoa (tmp), + VTY_NEWLINE); + } + else + { + vty_out (vty, " pce domain as %d%s", ntohl (domain->value), + VTY_NEWLINE); + } + } + } + + for (ALL_LIST_ELEMENTS_RO (pce->pce_neighbor, node, neighbor)) + { + if (neighbor->header.type != 0) + { + if (neighbor->type == PCE_DOMAIN_TYPE_AREA) + { + tmp.s_addr = neighbor->value; + vty_out (vty, " pce neighbor area %s%s", inet_ntoa (tmp), + VTY_NEWLINE); + } + else + { + vty_out (vty, " pce neighbor as %d%s", + ntohl (neighbor->value), VTY_NEWLINE); + } + } + } + + if (pce->pce_scope.header.type != 0) + vty_out (vty, " pce scope 0x%x%s", + ntohl (OspfRI.pce_info.pce_scope.value), VTY_NEWLINE); + } + return; +} + +/*------------------------------------------------------------------------* + * Followings are vty command functions. + *------------------------------------------------------------------------*/ + +DEFUN (router_info, + router_info_area_cmd, + "router-info area A.B.C.D", + OSPF_RI_STR + "Enable the Router Information functionality with Area flooding scope\n" + "OSPF area ID in IP format") +{ + + u_int8_t scope; + + if (OspfRI.status == enabled) + return CMD_SUCCESS; + + /* Check and get Area value if present */ + if (argc == 1) + { + if (!inet_aton (argv[0], &OspfRI.area_id)) + { + vty_out (vty, "Please specify Router Info Area by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + scope = OSPF_OPAQUE_AREA_LSA; + } + else + { + OspfRI.area_id.s_addr = 0; + scope = OSPF_OPAQUE_AS_LSA; + } + + /* First start to register Router Information callbacks */ + if ((ospf_router_info_register (scope)) != 0) + { + zlog_warn ("Enable to register Router Information callbacks. Abort!"); + return CMD_WARNING; + } + + OspfRI.status = enabled; + + if (IS_DEBUG_OSPF_EVENT) + zlog_debug ("RI-> Router Information (%s flooding): OFF -> ON", + OspfRI.scope == OSPF_OPAQUE_AREA_LSA ? "Area" : "AS"); + + /* + * Following code is intended to handle two cases; + * + * 1) Router Information was disabled at startup time, but now become enabled. + * 2) Router Information was once enabled then disabled, and now enabled again. + */ + + initialize_params (&OspfRI); + + /* Refresh RI LSA if already engaged */ + if (OspfRI.flags & RIFLG_LSA_ENGAGED) + { + zlog_debug ("RI-> Initial origination following configuration"); + ospf_router_info_lsa_schedule (REORIGINATE_THIS_LSA); + } + return CMD_SUCCESS; + +} + +ALIAS (router_info, + router_info_as_cmd, + "router-info as", + OSPF_RI_STR + "Enable the Router Information functionality with AS flooding scope\n") + +DEFUN (no_router_info, + no_router_info_cmd, + "no router-info", + NO_STR + "Disable the Router Information functionality\n") +{ + + if (OspfRI.status == disabled) + return CMD_SUCCESS; + + if (IS_DEBUG_OSPF_EVENT) + zlog_debug ("RI-> Router Information: ON -> OFF"); + + if (OspfRI.flags & RIFLG_LSA_ENGAGED) + ospf_router_info_lsa_schedule (FLUSH_THIS_LSA); + + /* Unregister the callbacks */ + ospf_router_info_unregister (); + + OspfRI.status = disabled; + + return CMD_SUCCESS; +} + +DEFUN (pce_address, + pce_address_cmd, + "pce address A.B.C.D", + PCE_STR + "Stable IP address of the PCE\n" + "PCE address in IPv4 address format\n") +{ + struct in_addr value; + struct ospf_pce_info *pi = &OspfRI.pce_info; + + if (!inet_aton (argv[0], &value)) + { + vty_out (vty, "Please specify PCE Address by A.B.C.D%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (ntohs (pi->pce_address.header.type) == 0 + || ntohl (pi->pce_address.address.value.s_addr) != ntohl (value.s_addr)) + { + + set_pce_address (value, pi); + + /* Refresh RI LSA if already engaged */ + if ((OspfRI.status == enabled) && (OspfRI.flags & RIFLG_LSA_ENGAGED)) + ospf_router_info_lsa_schedule (REFRESH_THIS_LSA); + } + + return CMD_SUCCESS; +} + +DEFUN (no_pce_address, + no_pce_address_cmd, + "no pce address", + NO_STR + PCE_STR + "Disable PCE address\n") +{ + + unset_param (&OspfRI.pce_info.pce_address.header); + + /* Refresh RI LSA if already engaged */ + if ((OspfRI.status == enabled) && (OspfRI.flags & RIFLG_LSA_ENGAGED)) + ospf_router_info_lsa_schedule (REFRESH_THIS_LSA); + + return CMD_SUCCESS; +} + +DEFUN (pce_path_scope, + pce_path_scope_cmd, + "pce scope BITPATTERN", + PCE_STR + "Path scope visibilities of the PCE for path computation\n" + "32-bit Hexadecimal value\n") +{ + uint32_t scope; + struct ospf_pce_info *pi = &OspfRI.pce_info; + + if (sscanf (argv[0], "0x%x", &scope) != 1) + { + vty_out (vty, "pce_path_scope: fscanf: %s%s", safe_strerror (errno), + VTY_NEWLINE); + return CMD_WARNING; + } + + if (ntohl (pi->pce_scope.header.type) == 0 || scope != pi->pce_scope.value) + { + set_pce_path_scope (scope, pi); + + /* Refresh RI LSA if already engaged */ + if ((OspfRI.status == enabled) && (OspfRI.flags & RIFLG_LSA_ENGAGED)) + ospf_router_info_lsa_schedule (REFRESH_THIS_LSA); + } + + return CMD_SUCCESS; +} + +DEFUN (no_pce_path_scope, + no_pce_path_scope_cmd, + "no pce scope", + NO_STR + PCE_STR + "Disable PCE path scope\n") +{ + + unset_param (&OspfRI.pce_info.pce_address.header); + + /* Refresh RI LSA if already engaged */ + if ((OspfRI.status == enabled) && (OspfRI.flags & RIFLG_LSA_ENGAGED)) + ospf_router_info_lsa_schedule (REFRESH_THIS_LSA); + + return CMD_SUCCESS; +} + +DEFUN (pce_domain, + pce_domain_cmd, + "pce domain as <0-65535>", + PCE_STR + "Configure PCE domain AS number\n" + "AS number where the PCE as visibilities for path computation\n" + "AS number in decimal <0-65535>\n") +{ + + uint32_t as; + struct ospf_pce_info *pce = &OspfRI.pce_info; + struct listnode *node; + struct ri_pce_subtlv_domain *domain; + + if (sscanf (argv[0], "%d", &as) != 1) + { + vty_out (vty, "pce_domain: fscanf: %s%s", safe_strerror (errno), + VTY_NEWLINE); + return CMD_WARNING; + } + + /* Check if the domain is not already in the domain list */ + for (ALL_LIST_ELEMENTS_RO (pce->pce_domain, node, domain)) + { + if (ntohl (domain->header.type) == 0 && as == domain->value) + goto out; + } + + /* Create new domain if not found */ + set_pce_domain (PCE_DOMAIN_TYPE_AS, as, pce); + + /* Refresh RI LSA if already engaged */ + if ((OspfRI.status == enabled) && (OspfRI.flags & RIFLG_LSA_ENGAGED)) + ospf_router_info_lsa_schedule (REFRESH_THIS_LSA); + +out:return CMD_SUCCESS; +} + +DEFUN (no_pce_domain, + no_pce_domain_cmd, + "no pce domain as <0-65535>", + NO_STR + PCE_STR + "Disable PCE domain AS number\n" + "AS number where the PCE as visibilities for path computation\n" + "AS number in decimal <0-65535>\n") +{ + + uint32_t as; + struct ospf_pce_info *pce = &OspfRI.pce_info; + + if (sscanf (argv[0], "%d", &as) != 1) + { + vty_out (vty, "no_pce_domain: fscanf: %s%s", safe_strerror (errno), + VTY_NEWLINE); + return CMD_WARNING; + } + + /* Unset corresponding PCE domain */ + unset_pce_domain (PCE_DOMAIN_TYPE_AS, as, pce); + + /* Refresh RI LSA if already engaged */ + if ((OspfRI.status == enabled) && (OspfRI.flags & RIFLG_LSA_ENGAGED)) + ospf_router_info_lsa_schedule (REFRESH_THIS_LSA); + + return CMD_SUCCESS; +} + +DEFUN (pce_neigbhor, + pce_neighbor_cmd, + "pce neighbor as <0-65535>", + PCE_STR + "Configure PCE neighbor domain AS number\n" + "AS number of PCE neighbors\n" + "AS number in decimal <0-65535>\n") +{ + + uint32_t as; + struct ospf_pce_info *pce = &OspfRI.pce_info; + struct listnode *node; + struct ri_pce_subtlv_neighbor *neighbor; + + if (sscanf (argv[0], "%d", &as) != 1) + { + vty_out (vty, "pce_neighbor: fscanf: %s%s", safe_strerror (errno), + VTY_NEWLINE); + return CMD_WARNING; + } + + /* Check if the domain is not already in the domain list */ + for (ALL_LIST_ELEMENTS_RO (pce->pce_neighbor, node, neighbor)) + { + if (ntohl (neighbor->header.type) == 0 && as == neighbor->value) + goto out; + } + + /* Create new domain if not found */ + set_pce_neighbor (PCE_DOMAIN_TYPE_AS, as, pce); + + /* Refresh RI LSA if already engaged */ + if ((OspfRI.status == enabled) && (OspfRI.flags & RIFLG_LSA_ENGAGED)) + ospf_router_info_lsa_schedule (REFRESH_THIS_LSA); + +out:return CMD_SUCCESS; +} + +DEFUN (no_pce_neighbor, + no_pce_neighbor_cmd, + "no pce neighbor as <0-65535>", + NO_STR + PCE_STR + "Disable PCE neighbor AS number\n" + "AS number of PCE neighbor\n" + "AS number in decimal <0-65535>\n") +{ + + uint32_t as; + struct ospf_pce_info *pce = &OspfRI.pce_info; + + if (sscanf (argv[0], "%d", &as) != 1) + { + vty_out (vty, "no_pce_neighbor: fscanf: %s%s", safe_strerror (errno), + VTY_NEWLINE); + return CMD_WARNING; + } + + /* Unset corresponding PCE domain */ + unset_pce_neighbor (PCE_DOMAIN_TYPE_AS, as, pce); + + /* Refresh RI LSA if already engaged */ + if ((OspfRI.status == enabled) && (OspfRI.flags & RIFLG_LSA_ENGAGED)) + ospf_router_info_lsa_schedule (REFRESH_THIS_LSA); + + return CMD_SUCCESS; +} + +DEFUN (pce_cap_flag, + pce_cap_flag_cmd, + "pce flag BITPATTERN", + PCE_STR + "Capabilities of the PCE for path computation\n" + "32-bit Hexadecimal value\n") +{ + + uint32_t cap; + struct ospf_pce_info *pce = &OspfRI.pce_info; + + if (sscanf (argv[0], "0x%x", &cap) != 1) + { + vty_out (vty, "pce_cap_flag: fscanf: %s%s", safe_strerror (errno), + VTY_NEWLINE); + return CMD_WARNING; + } + + if (ntohl (pce->pce_cap_flag.header.type) == 0 + || cap != pce->pce_cap_flag.value) + { + set_pce_cap_flag (cap, pce); + + /* Refresh RI LSA if already engaged */ + if ((OspfRI.status == enabled) && (OspfRI.flags & RIFLG_LSA_ENGAGED)) + ospf_router_info_lsa_schedule (REFRESH_THIS_LSA); + } + + return CMD_SUCCESS; +} + +DEFUN (no_pce_cap_flag, + no_pce_cap_flag_cmd, + "no pce flag", + NO_STR + PCE_STR + "Disable PCE capabilities\n") +{ + + unset_param (&OspfRI.pce_info.pce_cap_flag.header); + + /* Refresh RI LSA if already engaged */ + if ((OspfRI.status == enabled) && (OspfRI.flags & RIFLG_LSA_ENGAGED)) + ospf_router_info_lsa_schedule (REFRESH_THIS_LSA); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_ospf_router_info, + show_ip_ospf_router_info_cmd, + "show ip ospf router-info", + SHOW_STR + IP_STR + OSPF_STR + "Router Information\n") +{ + + if (OspfRI.status == enabled) + { + vty_out (vty, "--- Router Information parameters ---%s", VTY_NEWLINE); + show_vty_router_cap (vty, &OspfRI.router_cap.header); + } + else + { + if (vty != NULL) + vty_out (vty, " Router Information is disabled on this router%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +DEFUN (show_ip_opsf_router_info_pce, + show_ip_ospf_router_info_pce_cmd, + "show ip ospf router-info pce", + SHOW_STR + IP_STR + OSPF_STR + "Router Information\n" + "PCE information\n") +{ + + struct ospf_pce_info *pce = &OspfRI.pce_info; + struct listnode *node; + struct ri_pce_subtlv_domain *domain; + struct ri_pce_subtlv_neighbor *neighbor; + + if (OspfRI.status == enabled) + { + vty_out (vty, "--- PCE parameters ---%s", VTY_NEWLINE); + + if (pce->pce_address.header.type != 0) + show_vty_pce_subtlv_address (vty, &pce->pce_address.header); + + if (pce->pce_scope.header.type != 0) + show_vty_pce_subtlv_path_scope (vty, &pce->pce_scope.header); + + for (ALL_LIST_ELEMENTS_RO (pce->pce_domain, node, domain)) + { + if (domain->header.type != 0) + show_vty_pce_subtlv_domain (vty, &domain->header); + } + + for (ALL_LIST_ELEMENTS_RO (pce->pce_neighbor, node, neighbor)) + { + if (neighbor->header.type != 0) + show_vty_pce_subtlv_neighbor (vty, &neighbor->header); + } + + if (pce->pce_cap_flag.header.type != 0) + show_vty_pce_subtlv_cap_flag (vty, &pce->pce_cap_flag.header); + + } + else + { + vty_out (vty, " Router Information is disabled on this router%s", + VTY_NEWLINE); + } + + return CMD_SUCCESS; +} + +/* Install new CLI commands */ +static void +ospf_router_info_register_vty (void) +{ + install_element (VIEW_NODE, &show_ip_ospf_router_info_cmd); + install_element (VIEW_NODE, &show_ip_ospf_router_info_pce_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_router_info_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_router_info_pce_cmd); + + install_element (OSPF_NODE, &router_info_area_cmd); + install_element (OSPF_NODE, &router_info_as_cmd); + install_element (OSPF_NODE, &no_router_info_cmd); + install_element (OSPF_NODE, &pce_address_cmd); + install_element (OSPF_NODE, &pce_path_scope_cmd); + install_element (OSPF_NODE, &pce_domain_cmd); + install_element (OSPF_NODE, &no_pce_domain_cmd); + install_element (OSPF_NODE, &pce_neighbor_cmd); + install_element (OSPF_NODE, &no_pce_neighbor_cmd); + install_element (OSPF_NODE, &pce_cap_flag_cmd); + + return; +} diff --git a/ospfd/ospf_ri.h b/ospfd/ospf_ri.h new file mode 100644 index 0000000000..3f898ac598 --- /dev/null +++ b/ospfd/ospf_ri.h @@ -0,0 +1,191 @@ +/* + * This is an implementation of RFC4970 Router Information + * with support of RFC5088 PCE Capabilites announcement + * + * Module name: Router Information + * Version: 0.99.22 + * Created: 2012-02-01 by Olivier Dugeon + * Copyright (C) 2012 Orange Labs http://www.orange.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_OSPF_ROUTER_INFO_H +#define _ZEBRA_OSPF_ROUTER_INFO_H + +/* + * Opaque LSA's link state ID for Router Information is + * structured as follows. + * + * 24 16 8 0 + * +--------+--------+--------+--------+ + * | 1 | MBZ |........|........| + * +--------+--------+--------+--------+ + * |<-Type->||<-- Instance --->| + * + * + * Type: IANA has assigned '4' for Router Information. + * MBZ: Reserved, must be set to zero. + * Instance: User may select an arbitrary 16-bit value. + * + */ + +/* + * 24 16 8 0 + * +--------+--------+--------+--------+ --- + * | LS age |Options | 9,10,11| A + * +--------+--------+--------+--------+ | + * | 4 | 0 | Instance | | + * +--------+--------+--------+--------+ | + * | Advertising router | | Standard (Opaque) LSA header; + * +--------+--------+--------+--------+ | Type 9,10 or 11 are used. + * | LS sequence number | | + * +--------+--------+--------+--------+ | + * | LS checksum | Length | V + * +--------+--------+--------+--------+ --- + * | Type | Length | A + * +--------+--------+--------+--------+ | TLV part for Router Information; Values might be + * | Values ... | V structured as a set of sub-TLVs. + * +--------+--------+--------+--------+ --- + */ + +/* + * Following section defines TLV (tag, length, value) structures, + * used for Router Information. + */ +struct ri_tlv_header +{ + u_int16_t type; /* RI_TLV_XXX (see below) */ + u_int16_t length; /* Value portion only, in byte */ +}; + +#define RI_TLV_HDR_SIZE (sizeof (struct ri_tlv_header)) +#define RI_TLV_BODY_SIZE(tlvh) (ROUNDUP (ntohs ((tlvh)->length), sizeof (u_int32_t))) +#define RI_TLV_SIZE(tlvh) (RI_TLV_HDR_SIZE + RI_TLV_BODY_SIZE(tlvh)) +#define RI_TLV_HDR_TOP(lsah) (struct ri_tlv_header *)((char *)(lsah) + OSPF_LSA_HEADER_SIZE) +#define RI_TLV_HDR_NEXT(tlvh) (struct ri_tlv_header *)((char *)(tlvh) + RI_TLV_SIZE(tlvh)) + +/* + * Following section defines TLV body parts. + */ + +/* Up to now, 8 code point have been assigned to Router Information */ +/* Only type 1 Router Capabilities and 6 PCE are supported with this code */ +#define RI_IANA_MAX_TYPE 8 + +/* RFC4970: Router Information Capabilities TLV */ /* Mandatory */ +#define RI_TLV_CAPABILITIES 1 + +struct ri_tlv_router_cap +{ + struct ri_tlv_header header; /* Value length is 4 bytes. */ + u_int32_t value; +}; + +#define RI_GRACE_RESTART 0x01 +#define RI_GRACE_HELPER 0x02 +#define RI_STUB_SUPPORT 0x04 +#define RI_TE_SUPPORT 0x08 +#define RI_P2P_OVER_LAN 0x10 +#define RI_TE_EXPERIMENTAL 0x20 + +#define RI_TLV_LENGTH 4 + +/* RFC5088: PCE Capabilities TLV */ /* Optional */ +/* RI PCE TLV */ +#define RI_TLV_PCE 6 + +struct ri_tlv_pce +{ + struct ri_tlv_header header; +/* A set of PCE-sub-TLVs will follow. */ +}; + +/* PCE Address Sub-TLV */ /* Mandatory */ +#define RI_PCE_SUBTLV_ADDRESS 1 +struct ri_pce_subtlv_address +{ + struct ri_tlv_header header; /* Type = 1; Length is 8 (IPv4) or 20 (IPv6) bytes. */ +#define PCE_ADDRESS_LENGTH_IPV4 8 +#define PCE_ADDRESS_LENGTH_IPV6 20 + struct + { + u_int16_t type; /* Address type: 1 = IPv4, 2 = IPv6 */ +#define PCE_ADDRESS_TYPE_IPV4 1 +#define PCE_ADDRESS_TYPE_IPV6 2 + u_int16_t reserved; + struct in_addr value; /* PCE address */ + } address; +}; + +/* PCE Path-Scope Sub-TLV */ /* Mandatory */ +#define RI_PCE_SUBTLV_PATH_SCOPE 2 +struct ri_pce_subtlv_path_scope +{ + struct ri_tlv_header header; /* Type = 2; Length = 4 bytes. */ + u_int32_t value; /* L, R, Rd, S, Sd, Y, PrefL, PrefR, PrefS and PrefY bits see RFC5088 page 9 */ +}; + +/* PCE Domain Sub-TLV */ /* Optional */ +#define RI_PCE_SUBTLV_DOMAIN 3 + +#define PCE_DOMAIN_TYPE_AREA 1 +#define PCE_DOMAIN_TYPE_AS 2 + +struct ri_pce_subtlv_domain +{ + struct ri_tlv_header header; /* Type = 3; Length = 8 bytes. */ + u_int16_t type; /* Domain type: 1 = OSPF Area ID, 2 = AS Number */ + u_int16_t reserved; + u_int32_t value; +}; + +/* PCE Neighbor Sub-TLV */ /* Mandatory if R or S bit is set */ +#define RI_PCE_SUBTLV_NEIGHBOR 4 +struct ri_pce_subtlv_neighbor +{ + struct ri_tlv_header header; /* Type = 4; Length = 8 bytes. */ + u_int16_t type; /* Domain type: 1 = OSPF Area ID, 2 = AS Number */ + u_int16_t reserved; + u_int32_t value; +}; + +/* PCE Capabilities Flags Sub-TLV */ /* Optional */ +#define RI_PCE_SUBTLV_CAP_FLAG 5 + +#define PCE_CAP_GMPLS_LINK 0x0001 +#define PCE_CAP_BIDIRECTIONAL 0x0002 +#define PCE_CAP_DIVERSE_PATH 0x0004 +#define PCE_CAP_LOAD_BALANCE 0x0008 +#define PCE_CAP_SYNCHRONIZED 0x0010 +#define PCE_CAP_OBJECTIVES 0x0020 +#define PCE_CAP_ADDITIVE 0x0040 +#define PCE_CAP_PRIORIZATION 0x0080 +#define PCE_CAP_MULTIPLE_REQ 0x0100 + +struct ri_pce_subtlv_cap_flag +{ + struct ri_tlv_header header; /* Type = 5; Length = n x 4 bytes. */ + u_int32_t value; +}; + +/* Prototypes. */ +extern int ospf_router_info_init (void); +extern void ospf_router_info_term (void); + +#endif /* _ZEBRA_OSPF_ROUTER_INFO_H */ diff --git a/ospfd/ospf_route.c b/ospfd/ospf_route.c index 7efba7a8c0..175850c318 100644 --- a/ospfd/ospf_route.c +++ b/ospfd/ospf_route.c @@ -47,8 +47,6 @@ ospf_route_new () new = XCALLOC (MTYPE_OSPF_ROUTE, sizeof (struct ospf_route)); - new->ctime = quagga_time (NULL); - new->mtime = new->ctime; new->paths = list_new (); new->paths->del = (void (*) (void *))ospf_path_free; diff --git a/ospfd/ospf_route.h b/ospfd/ospf_route.h index 4de3a3da16..6b6d9f1fab 100644 --- a/ospfd/ospf_route.h +++ b/ospfd/ospf_route.h @@ -39,7 +39,7 @@ struct ospf_path { struct in_addr nexthop; struct in_addr adv_router; - unsigned int ifindex; + ifindex_t ifindex; unsigned char unnumbered; }; @@ -90,12 +90,6 @@ struct route_external struct ospf_route { - /* Create time. */ - time_t ctime; - - /* Modified time. */ - time_t mtime; - /* Destination Type. */ u_char type; diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c index 1636153378..676756d6d9 100644 --- a/ospfd/ospf_snmp.c +++ b/ospfd/ospf_snmp.c @@ -209,8 +209,8 @@ SNMP_LOCAL_VARIABLES /* OSPF-MIB instances. */ -oid ospf_oid [] = { OSPF2MIB }; -oid ospf_trap_oid [] = { OSPF2MIB, 16, 2 }; /* Not reverse mappable! */ +static oid ospf_oid [] = { OSPF2MIB }; +static oid ospf_trap_oid [] = { OSPF2MIB, 16, 2 }; /* Not reverse mappable! */ /* IP address 0.0.0.0. */ static struct in_addr ospf_empty_addr = { .s_addr = 0 }; @@ -243,7 +243,7 @@ static u_char *ospfExtLsdbEntry (struct variable *, oid *, size_t *, int, static u_char *ospfAreaAggregateEntry (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); -struct variable ospf_variables[] = +static struct variable ospf_variables[] = { /* OSPF general variables */ {OSPFROUTERID, IPADDRESS, RWRITE, ospfGeneralGroup, @@ -1408,25 +1408,25 @@ ospfHostEntry (struct variable *v, oid *name, size_t *length, int exact, return NULL; } -struct list *ospf_snmp_iflist; +static struct list *ospf_snmp_iflist; struct ospf_snmp_if { struct in_addr addr; - unsigned int ifindex; + ifindex_t ifindex; struct interface *ifp; }; static struct ospf_snmp_if * ospf_snmp_if_new (void) { - return XCALLOC (0, sizeof (struct ospf_snmp_if)); + return XCALLOC (MTYPE_TMP, sizeof (struct ospf_snmp_if)); } static void ospf_snmp_if_free (struct ospf_snmp_if *osif) { - XFREE (0, osif); + XFREE (MTYPE_TMP, osif); } void @@ -1455,7 +1455,7 @@ ospf_snmp_if_update (struct interface *ifp) struct prefix *p; struct ospf_snmp_if *osif; struct in_addr *addr; - unsigned int ifindex; + ifindex_t ifindex; ospf_snmp_if_delete (ifp); @@ -1530,7 +1530,7 @@ ospf_snmp_is_if_have_addr (struct interface *ifp) } static struct ospf_interface * -ospf_snmp_if_lookup (struct in_addr *ifaddr, unsigned int *ifindex) +ospf_snmp_if_lookup (struct in_addr *ifaddr, ifindex_t *ifindex) { struct listnode *node; struct ospf_snmp_if *osif; @@ -1554,8 +1554,8 @@ ospf_snmp_if_lookup (struct in_addr *ifaddr, unsigned int *ifindex) } static struct ospf_interface * -ospf_snmp_if_lookup_next (struct in_addr *ifaddr, unsigned int *ifindex, - int ifaddr_next, int ifindex_next) +ospf_snmp_if_lookup_next (struct in_addr *ifaddr, ifindex_t *ifindex, + int ifaddr_next, ifindex_t ifindex_next) { struct ospf_snmp_if *osif; struct listnode *nn; @@ -1638,11 +1638,11 @@ ospf_snmp_iftype (struct interface *ifp) static struct ospf_interface * ospfIfLookup (struct variable *v, oid *name, size_t *length, - struct in_addr *ifaddr, unsigned int *ifindex, int exact) + struct in_addr *ifaddr, ifindex_t *ifindex, int exact) { unsigned int len; int ifaddr_next = 0; - int ifindex_next = 0; + ifindex_t ifindex_next = 0; struct ospf_interface *oi; oid *offset; @@ -1694,7 +1694,7 @@ static u_char * ospfIfEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { - unsigned int ifindex; + ifindex_t ifindex; struct in_addr ifaddr; struct ospf_interface *oi; struct ospf *ospf; @@ -1802,11 +1802,11 @@ ospfIfEntry (struct variable *v, oid *name, size_t *length, int exact, static struct ospf_interface * ospfIfMetricLookup (struct variable *v, oid *name, size_t *length, - struct in_addr *ifaddr, unsigned int *ifindex, int exact) + struct in_addr *ifaddr, ifindex_t *ifindex, int exact) { unsigned int len; int ifaddr_next = 0; - int ifindex_next = 0; + ifindex_t ifindex_next = 0; struct ospf_interface *oi; oid *offset; int metric; @@ -1866,7 +1866,7 @@ ospfIfMetricEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { /* Currently we support metric 1 only. */ - unsigned int ifindex; + ifindex_t ifindex; struct in_addr ifaddr; struct ospf_interface *oi; struct ospf *ospf; @@ -1912,7 +1912,7 @@ ospfIfMetricEntry (struct variable *v, oid *name, size_t *length, int exact, return NULL; } -struct route_table *ospf_snmp_vl_table; +static struct route_table *ospf_snmp_vl_table; void ospf_snmp_vl_add (struct ospf_vl_data *vl_data) @@ -2133,7 +2133,7 @@ ospfVirtIfEntry (struct variable *v, oid *name, size_t *length, int exact, static struct ospf_neighbor * ospf_snmp_nbr_lookup (struct ospf *ospf, struct in_addr *nbr_addr, - unsigned int *ifindex) + ifindex_t *ifindex) { struct listnode *node, *nnode; struct ospf_interface *oi; @@ -2161,7 +2161,7 @@ ospf_snmp_nbr_lookup (struct ospf *ospf, struct in_addr *nbr_addr, } static struct ospf_neighbor * -ospf_snmp_nbr_lookup_next (struct in_addr *nbr_addr, unsigned int *ifindex, +ospf_snmp_nbr_lookup_next (struct in_addr *nbr_addr, ifindex_t *ifindex, int first) { struct listnode *nn; @@ -2208,7 +2208,7 @@ ospf_snmp_nbr_lookup_next (struct in_addr *nbr_addr, unsigned int *ifindex, static struct ospf_neighbor * ospfNbrLookup (struct variable *v, oid *name, size_t *length, - struct in_addr *nbr_addr, unsigned int *ifindex, int exact) + struct in_addr *nbr_addr, ifindex_t *ifindex, int exact) { unsigned int len; int first; @@ -2303,7 +2303,7 @@ ospfNbrEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { struct in_addr nbr_addr; - unsigned int ifindex; + ifindex_t ifindex; struct ospf_neighbor *nbr; struct ospf_interface *oi; @@ -2618,7 +2618,7 @@ ospfAreaAggregateEntry (struct variable *v, oid *name, size_t *length, #define NBRSTATECHANGE 2 #define VIRTNBRSTATECHANGE 3 -struct trap_object ospfNbrTrapList[] = +static struct trap_object ospfNbrTrapList[] = { {-2, {1, OSPFROUTERID}}, {3, {10, 1, OSPFNBRIPADDR}}, @@ -2627,7 +2627,7 @@ struct trap_object ospfNbrTrapList[] = }; -struct trap_object ospfVirtNbrTrapList[] = +static struct trap_object ospfVirtNbrTrapList[] = { {-2, {1, 1}}, {3, {11, 1, OSPFVIRTNBRAREA}}, @@ -2635,7 +2635,7 @@ struct trap_object ospfVirtNbrTrapList[] = {3, {11, 1, OSPFVIRTNBRSTATE}} }; -struct trap_object ospfIfTrapList[] = +static struct trap_object ospfIfTrapList[] = { {-2, {1, OSPFROUTERID}}, {3, {7, 1, OSPFIFIPADDRESS}}, @@ -2643,7 +2643,7 @@ struct trap_object ospfIfTrapList[] = {3, {7, 1, OSPFIFSTATE}} }; -struct trap_object ospfVirtIfTrapList[] = +static struct trap_object ospfVirtIfTrapList[] = { {-2, {1, OSPFROUTERID}}, {3, {9, 1, OSPFVIRTIFAREAID}}, diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c index db06623ddf..b55105ac8f 100644 --- a/ospfd/ospf_te.c +++ b/ospfd/ospf_te.c @@ -1,8 +1,11 @@ /* - * This is an implementation of draft-katz-yeung-ospf-traffic-06.txt + * This is an implementation of RFC3630 * Copyright (C) 2001 KDD R&D Laboratories, Inc. * http://www.kddlabs.co.jp/ * + * Copyright (C) 2012 Orange Labs + * http://www.orange.com + * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it @@ -21,15 +24,11 @@ * 02111-1307, USA. */ -/***** MTYPE definition is not reflected to "memory.h" yet. *****/ -#define MTYPE_OSPF_MPLS_TE_LINKPARAMS 0 +/* Add support of RFC7471 */ +/* Add support of RFC5392, RFC6827 */ #include - -#ifdef HAVE_OSPF_TE -#ifndef HAVE_OPAQUE_LSA -#error "Wrong configure option" -#endif /* HAVE_OPAQUE_LSA */ +#include #include "linklist.h" #include "prefix.h" @@ -44,6 +43,7 @@ #include "thread.h" #include "hash.h" #include "sockunion.h" /* for inet_aton() */ +#include "network.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" @@ -61,81 +61,35 @@ #include "ospfd/ospf_ase.h" #include "ospfd/ospf_zebra.h" #include "ospfd/ospf_te.h" - -/* Following structure are internal use only. */ -struct ospf_mpls_te -{ - enum { disabled, enabled } status; - - /* List elements are zebra-interfaces (ifp), not ospf-interfaces (oi). */ - struct list *iflist; - - /* Store Router-TLV in network byte order. */ - struct te_tlv_router_addr router_addr; -}; - -struct mpls_te_link -{ - /* - * According to MPLS-TE (draft) specification, 24-bit Opaque-ID field - * is subdivided into 8-bit "unused" field and 16-bit "instance" field. - * In this implementation, each Link-TLV has its own instance. - */ - u_int32_t instance; - - /* Reference pointer to a Zebra-interface. */ - struct interface *ifp; - - /* Area info in which this MPLS-TE link belongs to. */ - struct ospf_area *area; - - /* Flags to manage this link parameters. */ - u_int32_t flags; -#define LPFLG_LOOKUP_DONE 0x1 -#define LPFLG_LSA_ENGAGED 0x2 -#define LPFLG_LSA_FORCED_REFRESH 0x4 - - /* Store Link-TLV in network byte order. */ - struct te_tlv_link link_header; - struct te_link_subtlv_link_type link_type; - struct te_link_subtlv_link_id link_id; - struct te_link_subtlv_lclif_ipaddr *lclif_ipaddr; - struct te_link_subtlv_rmtif_ipaddr *rmtif_ipaddr; - struct te_link_subtlv_te_metric te_metric; - struct te_link_subtlv_max_bw max_bw; - struct te_link_subtlv_max_rsv_bw max_rsv_bw; - struct te_link_subtlv_unrsv_bw unrsv_bw; - struct te_link_subtlv_rsc_clsclr rsc_clsclr; -}; +#include "ospfd/ospf_vty.h" /* * Global variable to manage Opaque-LSA/MPLS-TE on this node. * Note that all parameter values are stored in network byte order. */ -static struct ospf_mpls_te OspfMplsTE; +struct ospf_mpls_te OspfMplsTE; -enum oifstate { +const char *mode2text[] = { "Disable", "AS", "Area", "Emulate" }; + +enum oifstate +{ OI_ANY, OI_DOWN, OI_UP }; -enum sched_opcode { - REORIGINATE_PER_AREA, REFRESH_THIS_LSA, FLUSH_THIS_LSA -}; - /*------------------------------------------------------------------------* * Followings are initialize/terminate functions for MPLS-TE handling. *------------------------------------------------------------------------*/ static int ospf_mpls_te_new_if (struct interface *ifp); static int ospf_mpls_te_del_if (struct interface *ifp); -static void ospf_mpls_te_ism_change (struct ospf_interface *oi, int old_status); +static void ospf_mpls_te_ism_change (struct ospf_interface *oi, + int old_status); static void ospf_mpls_te_nsm_change (struct ospf_neighbor *nbr, int old_status); static void ospf_mpls_te_config_write_router (struct vty *vty); -static void ospf_mpls_te_config_write_if (struct vty *vty, struct interface *ifp); static void ospf_mpls_te_show_info (struct vty *vty, struct ospf_lsa *lsa); -static int ospf_mpls_te_lsa_originate (void *arg); +static int ospf_mpls_te_lsa_originate_area (void *arg); +static int ospf_mpls_te_lsa_originate_as (void *arg); static struct ospf_lsa *ospf_mpls_te_lsa_refresh (struct ospf_lsa *lsa); -static void ospf_mpls_te_lsa_schedule (struct mpls_te_link *lp, enum sched_opcode); static void del_mpls_te_link (void *val); static void ospf_mpls_te_register_vty (void); @@ -153,21 +107,22 @@ ospf_mpls_te_init (void) ospf_mpls_te_ism_change, ospf_mpls_te_nsm_change, ospf_mpls_te_config_write_router, - ospf_mpls_te_config_write_if, + NULL,/*ospf_mpls_te_config_write_if */ NULL,/* ospf_mpls_te_config_write_debug */ ospf_mpls_te_show_info, - ospf_mpls_te_lsa_originate, + ospf_mpls_te_lsa_originate_area, ospf_mpls_te_lsa_refresh, NULL,/* ospf_mpls_te_new_lsa_hook */ NULL /* ospf_mpls_te_del_lsa_hook */); if (rc != 0) { - zlog_warn ("ospf_mpls_te_init: Failed to register functions"); + zlog_warn ("ospf_mpls_te_init: Failed to register Traffic Engineering functions"); goto out; } memset (&OspfMplsTE, 0, sizeof (struct ospf_mpls_te)); OspfMplsTE.status = disabled; + OspfMplsTE.inter_as = Disable; OspfMplsTE.iflist = list_new (); OspfMplsTE.iflist->del = del_mpls_te_link; @@ -177,16 +132,75 @@ out: return rc; } +/* Additional register for RFC5392 support */ +static int +ospf_mpls_te_register (enum inter_as_mode mode) +{ + int rc; + u_int8_t scope; + + if (OspfMplsTE.inter_as != Disable) + return 0; + + if (mode == AS) + scope = OSPF_OPAQUE_AS_LSA; + else + scope = OSPF_OPAQUE_AREA_LSA; + + rc = ospf_register_opaque_functab (scope, + OPAQUE_TYPE_INTER_AS_LSA, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + ospf_mpls_te_show_info, + ospf_mpls_te_lsa_originate_as, + ospf_mpls_te_lsa_refresh, NULL, NULL); + + if (rc != 0) + { + zlog_warn ("ospf_router_info_init: Failed to register Inter-AS functions"); + return rc; + } + + return 0; +} + +static int +ospf_mpls_te_unregister () +{ + u_int8_t scope; + + if (OspfMplsTE.inter_as == Disable) + return 0; + + if (OspfMplsTE.inter_as == AS) + scope = OSPF_OPAQUE_AS_LSA; + else + scope = OSPF_OPAQUE_AREA_LSA; + + ospf_delete_opaque_functab (scope, OPAQUE_TYPE_INTER_AS_LSA); + + return 0; + +} + void ospf_mpls_te_term (void) { list_delete (OspfMplsTE.iflist); - OspfMplsTE.iflist = NULL; - OspfMplsTE.status = disabled; ospf_delete_opaque_functab (OSPF_OPAQUE_AREA_LSA, OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA); + OspfMplsTE.status = disabled; + + ospf_mpls_te_unregister (); + OspfMplsTE.inter_as = Disable; + return; } @@ -197,11 +211,11 @@ ospf_mpls_te_term (void) static void del_mpls_te_link (void *val) { - XFREE (MTYPE_OSPF_MPLS_TE_LINKPARAMS, val); + XFREE (MTYPE_OSPF_MPLS_TE, val); return; } -static u_int32_t +u_int32_t get_mpls_te_instance_value (void) { static u_int32_t seqno = 0; @@ -279,9 +293,9 @@ lookup_linkparams_by_instance (struct ospf_lsa *lsa) } static void -ospf_mpls_te_foreach_area ( - void (*func)(struct mpls_te_link *lp, enum sched_opcode), - enum sched_opcode sched_opcode) +ospf_mpls_te_foreach_area (void (*func) + (struct mpls_te_link * lp, opcode_t sched_opcode), + opcode_t sched_opcode) { struct listnode *node, *nnode; struct listnode *node2; @@ -290,10 +304,12 @@ ospf_mpls_te_foreach_area ( for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp)) { + /* Skip Inter-AS TEv2 Links */ + if (IS_INTER_AS (lp->type)) + continue; if ((area = lp->area) == NULL) continue; - if (lp->flags & LPFLG_LOOKUP_DONE) - continue; + if CHECK_FLAG (lp->flags, LPFLG_LOOKUP_DONE) continue; if (func != NULL) (* func)(lp, sched_opcode); @@ -302,12 +318,12 @@ ospf_mpls_te_foreach_area ( if ((lp = listgetdata (node2)) != NULL) if (lp->area != NULL) if (IPV4_ADDR_SAME (&lp->area->area_id, &area->area_id)) - lp->flags |= LPFLG_LOOKUP_DONE; + SET_FLAG (lp->flags, LPFLG_LOOKUP_DONE); } for (ALL_LIST_ELEMENTS_RO (OspfMplsTE.iflist, node, lp)) if (lp->area != NULL) - lp->flags &= ~LPFLG_LOOKUP_DONE; + UNSET_FLAG (lp->flags, LPFLG_LOOKUP_DONE); return; } @@ -316,7 +332,7 @@ static void set_mpls_te_router_addr (struct in_addr ipv4) { OspfMplsTE.router_addr.header.type = htons (TE_TLV_ROUTER_ADDR); - OspfMplsTE.router_addr.header.length = htons (sizeof (ipv4)); + OspfMplsTE.router_addr.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); OspfMplsTE.router_addr.value = ipv4; return; } @@ -324,7 +340,6 @@ set_mpls_te_router_addr (struct in_addr ipv4) static void set_linkparams_link_header (struct mpls_te_link *lp) { - struct te_tlv_header *tlvh; u_int16_t length = 0; /* TE_LINK_SUBTLV_LINK_TYPE */ @@ -336,14 +351,12 @@ set_linkparams_link_header (struct mpls_te_link *lp) length += TLV_SIZE (&lp->link_id.header); /* TE_LINK_SUBTLV_LCLIF_IPADDR */ - if ((tlvh = (struct te_tlv_header *) lp->lclif_ipaddr) != NULL - && ntohs (tlvh->type) != 0) - length += TLV_SIZE (tlvh); + if (lp->lclif_ipaddr.header.type != 0) + length += TLV_SIZE (&lp->lclif_ipaddr.header); /* TE_LINK_SUBTLV_RMTIF_IPADDR */ - if ((tlvh = (struct te_tlv_header *) lp->rmtif_ipaddr) != NULL - && ntohs (tlvh->type) != 0) - length += TLV_SIZE (tlvh); + if (lp->rmtif_ipaddr.header.type != 0) + length += TLV_SIZE (&lp->rmtif_ipaddr.header); /* TE_LINK_SUBTLV_TE_METRIC */ if (ntohs (lp->te_metric.header.type) != 0) @@ -365,6 +378,50 @@ set_linkparams_link_header (struct mpls_te_link *lp) if (ntohs (lp->rsc_clsclr.header.type) != 0) length += TLV_SIZE (&lp->rsc_clsclr.header); + /* TE_LINK_SUBTLV_LLRI */ + if (ntohs (lp->llri.header.type) != 0) + length += TLV_SIZE (&lp->llri.header); + + /* TE_LINK_SUBTLV_RIP */ + if (ntohs (lp->rip.header.type) != 0) + length += TLV_SIZE (&lp->rip.header); + + /* TE_LINK_SUBTLV_RAS */ + if (ntohs (lp->ras.header.type) != 0) + length += TLV_SIZE (&lp->ras.header); + + /* TE_LINK_SUBTLV_LRRID */ + if (ntohs (lp->lrrid.header.type) != 0) + length += TLV_SIZE (&lp->lrrid.header); + + /* TE_LINK_SUBTLV_AV_DELAY */ + if (ntohs (lp->av_delay.header.type) != 0) + length += TLV_SIZE (&lp->av_delay.header); + + /* TE_LINK_SUBTLV_MM_DELAY */ + if (ntohs (lp->mm_delay.header.type) != 0) + length += TLV_SIZE (&lp->mm_delay.header); + + /* TE_LINK_SUBTLV_DELAY_VAR */ + if (ntohs (lp->delay_var.header.type) != 0) + length += TLV_SIZE (&lp->delay_var.header); + + /* TE_LINK_SUBTLV_PKT_LOSS */ + if (ntohs (lp->pkt_loss.header.type) != 0) + length += TLV_SIZE (&lp->pkt_loss.header); + + /* TE_LINK_SUBTLV_RES_BW */ + if (ntohs (lp->res_bw.header.type) != 0) + length += TLV_SIZE (&lp->res_bw.header); + + /* TE_LINK_SUBTLV_AVA_BW */ + if (ntohs (lp->ava_bw.header.type) != 0) + length += TLV_SIZE (&lp->ava_bw.header); + + /* TE_LINK_SUBTLV_USE_BW */ + if (ntohs (lp->use_bw.header.type) != 0) + length += TLV_SIZE (&lp->use_bw.header); + lp->link_header.header.type = htons (TE_TLV_LINK); lp->link_header.header.length = htons (length); @@ -375,7 +432,7 @@ static void set_linkparams_link_type (struct ospf_interface *oi, struct mpls_te_link *lp) { lp->link_type.header.type = htons (TE_LINK_SUBTLV_LINK_TYPE); - lp->link_type.header.length = htons (sizeof (lp->link_type.link_type.value)); + lp->link_type.header.length = htons (TE_LINK_SUBTLV_TYPE_SIZE); switch (oi->type) { @@ -401,7 +458,7 @@ set_linkparams_link_id (struct ospf_interface *oi, struct mpls_te_link *lp) int done = 0; lp->link_id.header.type = htons (TE_LINK_SUBTLV_LINK_ID); - lp->link_id.header.length = htons (sizeof (lp->link_id.value)); + lp->link_id.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); /* * The Link ID is identical to the contents of the Link ID field @@ -411,8 +468,7 @@ set_linkparams_link_id (struct ospf_interface *oi, struct mpls_te_link *lp) { case OSPF_IFTYPE_POINTOPOINT: /* Take the router ID of the neighbor. */ - if ((nbr = ospf_nbr_lookup_ptop (oi)) - && nbr->state == NSM_Full) + if ((nbr = ospf_nbr_lookup_ptop (oi)) && nbr->state == NSM_Full) { lp->link_id.value = nbr->router_id; done = 1; @@ -447,40 +503,60 @@ set_linkparams_link_id (struct ospf_interface *oi, struct mpls_te_link *lp) return; } +static void +set_linkparams_lclif_ipaddr (struct mpls_te_link *lp, struct in_addr lclif) +{ + + lp->lclif_ipaddr.header.type = htons (TE_LINK_SUBTLV_LCLIF_IPADDR); + lp->lclif_ipaddr.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); + lp->lclif_ipaddr.value[0] = lclif; + return; +} + +static void +set_linkparams_rmtif_ipaddr (struct mpls_te_link *lp, struct in_addr rmtif) +{ + + lp->rmtif_ipaddr.header.type = htons (TE_LINK_SUBTLV_RMTIF_IPADDR); + lp->rmtif_ipaddr.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); + lp->rmtif_ipaddr.value[0] = rmtif; + return; +} + static void set_linkparams_te_metric (struct mpls_te_link *lp, u_int32_t te_metric) { lp->te_metric.header.type = htons (TE_LINK_SUBTLV_TE_METRIC); - lp->te_metric.header.length = htons (sizeof (lp->te_metric.value)); + lp->te_metric.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); lp->te_metric.value = htonl (te_metric); return; } static void -set_linkparams_max_bw (struct mpls_te_link *lp, float *fp) +set_linkparams_max_bw (struct mpls_te_link *lp, float fp) { lp->max_bw.header.type = htons (TE_LINK_SUBTLV_MAX_BW); - lp->max_bw.header.length = htons (sizeof (lp->max_bw.value)); - htonf (fp, &lp->max_bw.value); + lp->max_bw.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); + lp->max_bw.value = htonf (fp); return; } static void -set_linkparams_max_rsv_bw (struct mpls_te_link *lp, float *fp) +set_linkparams_max_rsv_bw (struct mpls_te_link *lp, float fp) { lp->max_rsv_bw.header.type = htons (TE_LINK_SUBTLV_MAX_RSV_BW); - lp->max_rsv_bw.header.length = htons (sizeof (lp->max_rsv_bw.value)); - htonf (fp, &lp->max_rsv_bw.value); + lp->max_rsv_bw.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); + lp->max_rsv_bw.value = htonf (fp); return; } static void -set_linkparams_unrsv_bw (struct mpls_te_link *lp, int priority, float *fp) +set_linkparams_unrsv_bw (struct mpls_te_link *lp, int priority, float fp) { /* Note that TLV-length field is the size of array. */ lp->unrsv_bw.header.type = htons (TE_LINK_SUBTLV_UNRSV_BW); - lp->unrsv_bw.header.length = htons (sizeof (lp->unrsv_bw.value)); - htonf (fp, &lp->unrsv_bw.value [priority]); + lp->unrsv_bw.header.length = htons (TE_LINK_SUBTLV_UNRSV_SIZE); + lp->unrsv_bw.value [priority] = htonf (fp); return; } @@ -488,21 +564,283 @@ static void set_linkparams_rsc_clsclr (struct mpls_te_link *lp, u_int32_t classcolor) { lp->rsc_clsclr.header.type = htons (TE_LINK_SUBTLV_RSC_CLSCLR); - lp->rsc_clsclr.header.length = htons (sizeof (lp->rsc_clsclr.value)); + lp->rsc_clsclr.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); lp->rsc_clsclr.value = htonl (classcolor); return; } +static void +set_linkparams_inter_as (struct mpls_te_link *lp, struct in_addr addr, + u_int32_t as) +{ + + /* Set the Remote ASBR IP address and then the associated AS number */ + lp->rip.header.type = htons (TE_LINK_SUBTLV_RIP); + lp->rip.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); + lp->rip.value = addr; + + lp->ras.header.type = htons (TE_LINK_SUBTLV_RAS); + lp->ras.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); + lp->ras.value = htonl (as); +} + +static void +unset_linkparams_inter_as (struct mpls_te_link *lp) +{ + + /* Reset the Remote ASBR IP address and then the associated AS number */ + lp->rip.header.type = htons (0); + lp->rip.header.length = htons (0); + lp->rip.value.s_addr = htonl (0); + + lp->ras.header.type = htons (0); + lp->ras.header.length = htons (0); + lp->ras.value = htonl (0); +} + +void +set_linkparams_llri (struct mpls_te_link *lp, u_int32_t local, + u_int32_t remote) +{ + + lp->llri.header.type = htons (TE_LINK_SUBTLV_LLRI); + lp->llri.header.length = htons (TE_LINK_SUBTLV_LLRI_SIZE); + lp->llri.local = htonl (local); + lp->llri.remote = htonl (remote); +} + +void +set_linkparams_lrrid (struct mpls_te_link *lp, struct in_addr local, + struct in_addr remote) +{ + + lp->lrrid.header.type = htons (TE_LINK_SUBTLV_LRRID); + lp->lrrid.header.length = htons (TE_LINK_SUBTLV_LRRID_SIZE); + lp->lrrid.local.s_addr = local.s_addr; + lp->lrrid.remote.s_addr = remote.s_addr; +} + +static void +set_linkparams_av_delay (struct mpls_te_link *lp, u_int32_t delay, u_char anormal) +{ + u_int32_t tmp; + /* Note that TLV-length field is the size of array. */ + lp->av_delay.header.type = htons (TE_LINK_SUBTLV_AV_DELAY); + lp->av_delay.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); + tmp = delay & TE_EXT_MASK; + if (anormal) + tmp |= TE_EXT_ANORMAL; + lp->av_delay.value = htonl (tmp); + return; +} + +static void +set_linkparams_mm_delay (struct mpls_te_link *lp, u_int32_t low, u_int32_t high, u_char anormal) +{ + u_int32_t tmp; + /* Note that TLV-length field is the size of array. */ + lp->mm_delay.header.type = htons (TE_LINK_SUBTLV_MM_DELAY); + lp->mm_delay.header.length = htons (TE_LINK_SUBTLV_MM_DELAY_SIZE); + tmp = low & TE_EXT_MASK; + if (anormal) + tmp |= TE_EXT_ANORMAL; + lp->mm_delay.low = htonl (tmp); + lp->mm_delay.high = htonl (high); + return; +} + +static void +set_linkparams_delay_var (struct mpls_te_link *lp, u_int32_t jitter) +{ + /* Note that TLV-length field is the size of array. */ + lp->delay_var.header.type = htons (TE_LINK_SUBTLV_DELAY_VAR); + lp->delay_var.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); + lp->delay_var.value = htonl (jitter & TE_EXT_MASK); + return; +} + +static void +set_linkparams_pkt_loss (struct mpls_te_link *lp, u_int32_t loss, u_char anormal) +{ + u_int32_t tmp; + /* Note that TLV-length field is the size of array. */ + lp->pkt_loss.header.type = htons (TE_LINK_SUBTLV_PKT_LOSS); + lp->pkt_loss.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); + tmp = loss & TE_EXT_MASK; + if (anormal) + tmp |= TE_EXT_ANORMAL; + lp->pkt_loss.value = htonl (tmp); + return; +} + +static void +set_linkparams_res_bw (struct mpls_te_link *lp, float fp) +{ + /* Note that TLV-length field is the size of array. */ + lp->res_bw.header.type = htons (TE_LINK_SUBTLV_RES_BW); + lp->res_bw.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); + lp->res_bw.value = htonf (fp); + return; +} + +static void +set_linkparams_ava_bw (struct mpls_te_link *lp, float fp) +{ + /* Note that TLV-length field is the size of array. */ + lp->ava_bw.header.type = htons (TE_LINK_SUBTLV_AVA_BW); + lp->ava_bw.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); + lp->ava_bw.value = htonf (fp); + return; +} + +static void +set_linkparams_use_bw (struct mpls_te_link *lp, float fp) +{ + /* Note that TLV-length field is the size of array. */ + lp->use_bw.header.type = htons (TE_LINK_SUBTLV_USE_BW); + lp->use_bw.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); + lp->use_bw.value = htonf (fp); + return; +} + +/* Update TE parameters from Interface */ +static void +update_linkparams(struct mpls_te_link *lp) +{ + int i; + struct interface *ifp; + + /* Get the Interface structure */ + if ((ifp = lp->ifp) == NULL) + { + zlog_warn("OSPF MPLS-TE: Abort update TE parameters: no interface associated to Link Parameters"); + return; + } + if (!HAS_LINK_PARAMS(ifp)) + { + zlog_warn("OSPF MPLS-TE: Abort update TE parameters: no Link Parameters for interface"); + return; + } + + /* RFC3630 metrics */ + if (IS_PARAM_SET(ifp->link_params, LP_ADM_GRP)) + set_linkparams_rsc_clsclr (lp, ifp->link_params->admin_grp); + else + TLV_TYPE(lp->rsc_clsclr) = 0; + + if (IS_PARAM_SET(ifp->link_params, LP_MAX_BW)) + set_linkparams_max_bw (lp, ifp->link_params->max_bw); + else + TLV_TYPE(lp->max_bw) = 0; + + if (IS_PARAM_SET(ifp->link_params, LP_MAX_RSV_BW)) + set_linkparams_max_rsv_bw (lp, ifp->link_params->max_rsv_bw); + else + TLV_TYPE(lp->max_rsv_bw) = 0; + + if (IS_PARAM_SET(ifp->link_params, LP_UNRSV_BW)) + for (i = 0; i < MAX_CLASS_TYPE; i++) + set_linkparams_unrsv_bw (lp, i, ifp->link_params->unrsv_bw[i]); + else + TLV_TYPE(lp->unrsv_bw) = 0; + + if (IS_PARAM_SET(ifp->link_params, LP_TE)) + set_linkparams_te_metric(lp, ifp->link_params->te_metric); + else + TLV_TYPE(lp->te_metric) = 0; + + /* TE metric Extensions */ + if (IS_PARAM_SET(ifp->link_params, LP_DELAY)) + set_linkparams_av_delay(lp, ifp->link_params->av_delay, 0); + else + TLV_TYPE(lp->av_delay) = 0; + + if (IS_PARAM_SET(ifp->link_params, LP_MM_DELAY)) + set_linkparams_mm_delay(lp, ifp->link_params->min_delay, ifp->link_params->max_delay, 0); + else + TLV_TYPE(lp->mm_delay) = 0; + + if (IS_PARAM_SET(ifp->link_params, LP_DELAY_VAR)) + set_linkparams_delay_var(lp, ifp->link_params->delay_var); + else + TLV_TYPE(lp->delay_var) = 0; + + if (IS_PARAM_SET(ifp->link_params, LP_PKT_LOSS)) + set_linkparams_pkt_loss(lp, ifp->link_params->pkt_loss, 0); + else + TLV_TYPE(lp->pkt_loss) = 0; + + if (IS_PARAM_SET(ifp->link_params, LP_RES_BW)) + set_linkparams_res_bw(lp, ifp->link_params->res_bw); + else + TLV_TYPE(lp->res_bw) = 0; + + if (IS_PARAM_SET(ifp->link_params, LP_AVA_BW)) + set_linkparams_ava_bw(lp, ifp->link_params->ava_bw); + else + TLV_TYPE(lp->ava_bw) = 0; + + if (IS_PARAM_SET(ifp->link_params, LP_USE_BW)) + set_linkparams_use_bw(lp, ifp->link_params->use_bw); + else + TLV_TYPE(lp->use_bw) = 0; + + /* RFC5392 */ + if (IS_PARAM_SET(ifp->link_params, LP_RMT_AS)) + { + /* Flush LSA if it engaged and was previously a STD_TE one */ + if (IS_STD_TE(lp->type) && CHECK_FLAG (lp->flags, LPFLG_LSA_ENGAGED)) + { + if (IS_DEBUG_OSPF_TE) + zlog_debug("OSPF MPLS-TE Update IF: Switch from Standard LSA to INTER-AS for %s[%d/%d]", + ifp->name, lp->flags, lp->type); + + ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA); + /* Then, switch it to INTER-AS */ + if (OspfMplsTE.inter_as == AS) + lp->flags = INTER_AS | FLOOD_AS; + else + { + lp->flags = INTER_AS | FLOOD_AREA; + lp->area = ospf_area_lookup_by_area_id (ospf_lookup(), OspfMplsTE.interas_areaid); + } + } + set_linkparams_inter_as(lp, ifp->link_params->rmt_ip, ifp->link_params->rmt_as); + } + else + { + if (IS_DEBUG_OSPF_TE) + zlog_debug("OSPF MPLS-TE Update IF: Switch from INTER-AS LSA to Standard for %s[%d/%d]", + ifp->name, lp->flags, lp->type); + + /* reset inter-as TE params */ + /* Flush LSA if it engaged and was previously an INTER_AS one */ + if (IS_INTER_AS(lp->type) && CHECK_FLAG (lp->flags, LPFLG_LSA_ENGAGED)) + { + ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA); + /* Then, switch it to Standard TE */ + lp->flags = STD_TE | FLOOD_AREA; + } + unset_linkparams_inter_as (lp); + } +} + static void initialize_linkparams (struct mpls_te_link *lp) { struct interface *ifp = lp->ifp; struct ospf_interface *oi; - float fval; - int i; + + if (IS_DEBUG_OSPF_TE) + zlog_debug("MPLS-TE(initialize_linkparams) Initialize Link Parameters for interface %s", + ifp->name); if ((oi = lookup_oi_by_ifp (ifp, NULL, OI_ANY)) == NULL) - return; + { + zlog_warn("MPLS-TE(initialize_linkparams) Could not find corresponding OSPF Interface for %s", + ifp->name); + return; + } /* * Try to set initial values those can be derived from @@ -510,18 +848,19 @@ initialize_linkparams (struct mpls_te_link *lp) */ set_linkparams_link_type (oi, lp); - /* - * Linux and *BSD kernel holds bandwidth parameter as an "int" type. - * We may have to reconsider, if "ifp->bandwidth" type changes to float. - */ - fval = (float)((ifp->bandwidth ? ifp->bandwidth - : OSPF_DEFAULT_BANDWIDTH) * 1000 / 8); + /* Set local IP addr */ + set_linkparams_lclif_ipaddr (lp, oi->address->u.prefix4); - set_linkparams_max_bw (lp, &fval); - set_linkparams_max_rsv_bw (lp, &fval); + /* Set Remote IP addr if Point to Point Interface */ + if (oi->type == LINK_TYPE_SUBTLV_VALUE_PTP) + { + struct prefix *pref = CONNECTED_PREFIX(oi->connected); + if (pref != NULL) + set_linkparams_rmtif_ipaddr(lp, pref->u.prefix4); + } - for (i = 0; i < 8; i++) - set_linkparams_unrsv_bw (lp, i, &fval); + /* Keep Area information in combination with link parameters. */ + lp->area = oi->area; return; } @@ -532,13 +871,22 @@ is_mandated_params_set (struct mpls_te_link *lp) int rc = 0; if (ntohs (OspfMplsTE.router_addr.header.type) == 0) + { + zlog_warn ("MPLS-TE(is_mandated_params_set) Missing Router Address"); goto out; + } if (ntohs (lp->link_type.header.type) == 0) + { + zlog_warn ("MPLS-TE(is_mandated_params_set) Missing Link Type"); goto out; + } - if (ntohs (lp->link_id.header.type) == 0) + if (!IS_INTER_AS (lp->type) && (ntohs (lp->link_id.header.type) == 0)) + { + zlog_warn ("MPLS-TE(is_mandated_params_set) Missing Link ID"); goto out; + } rc = 1; out: @@ -555,6 +903,10 @@ ospf_mpls_te_new_if (struct interface *ifp) struct mpls_te_link *new; int rc = -1; + if (IS_DEBUG_OSPF_TE) + zlog_debug ("MPLS-TE(ospf_mpls_te_new_if) Add new %s interface %s to MPLS-TE list", + ifp->link_params ? "Active" : "Inactive", ifp->name); + if (lookup_linkparams_by_ifp (ifp) != NULL) { zlog_warn ("ospf_mpls_te_new_if: ifp(%p) already in use?", (void *)ifp); @@ -562,23 +914,33 @@ ospf_mpls_te_new_if (struct interface *ifp) goto out; } - new = XCALLOC (MTYPE_OSPF_MPLS_TE_LINKPARAMS, - sizeof (struct mpls_te_link)); + new = XCALLOC (MTYPE_OSPF_MPLS_TE, sizeof (struct mpls_te_link)); if (new == NULL) { zlog_warn ("ospf_mpls_te_new_if: XMALLOC: %s", safe_strerror (errno)); goto out; } - new->area = NULL; - new->flags = 0; new->instance = get_mpls_te_instance_value (); new->ifp = ifp; + /* By default TE-Link is RFC3630 compatible flooding in Area and not active */ + /* This default behavior will be adapted with call to ospf_mpls_te_update_if() */ + new->type = STD_TE | FLOOD_AREA; + new->flags = LPFLG_LSA_INACTIVE; - initialize_linkparams (new); + /* Initialize Link Parameters from Interface */ + initialize_linkparams(new); + /* Set TE Parameters from Interface */ + update_linkparams(new); + + /* Add Link Parameters structure to the list */ listnode_add (OspfMplsTE.iflist, new); + if (IS_DEBUG_OSPF_TE) + zlog_debug("OSPF MPLS-TE New IF: Add new LP context for %s[%d/%d]", + ifp->name, new->flags, new->type); + /* Schedule Opaque-LSA refresh. *//* XXX */ rc = 0; @@ -603,7 +965,7 @@ ospf_mpls_te_del_if (struct interface *ifp) if (listcount (iflist) == 0) iflist->head = iflist->tail = NULL; - XFREE (MTYPE_OSPF_MPLS_TE_LINKPARAMS, lp); + XFREE (MTYPE_OSPF_MPLS_TE, lp); } /* Schedule Opaque-LSA refresh. *//* XXX */ @@ -613,6 +975,56 @@ ospf_mpls_te_del_if (struct interface *ifp) return rc; } +/* Main initialization / update function of the MPLS TE Link context */ + +/* Call when interface TE Link parameters are modified */ +void +ospf_mpls_te_update_if (struct interface *ifp) +{ + struct mpls_te_link *lp; + + if (IS_DEBUG_OSPF_TE) + zlog_debug ("OSPF MPLS-TE: Update LSA parameters for interface %s [%s]", + ifp->name, HAS_LINK_PARAMS(ifp) ? "ON" : "OFF"); + + /* Get Link context from interface */ + if ((lp = lookup_linkparams_by_ifp(ifp)) == NULL) + { + zlog_warn ("OSPF MPLS-TE Update: Did not find Link Parameters context for interface %s", ifp->name); + return; + } + + /* Fulfill MPLS-TE Link TLV from Interface TE Link parameters */ + if (HAS_LINK_PARAMS(ifp)) + { + SET_FLAG (lp->flags, LPFLG_LSA_ACTIVE); + + /* Update TE parameters */ + update_linkparams(lp); + + /* Finally Re-Originate or Refresh Opaque LSA if MPLS_TE is enabled */ + if (OspfMplsTE.status == enabled) + if (lp->area != NULL) + { + if CHECK_FLAG (lp->flags, LPFLG_LSA_ENGAGED) + ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); + else + ospf_mpls_te_lsa_schedule (lp, REORIGINATE_THIS_LSA); + } + } + else + { + /* If MPLS TE is disable on this interface, flush LSA if it is already engaged */ + if CHECK_FLAG (lp->flags, LPFLG_LSA_ENGAGED) + ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA); + else + /* Reset Activity flag */ + lp->flags = LPFLG_LSA_INACTIVE; + } + + return; +} + static void ospf_mpls_te_ism_change (struct ospf_interface *oi, int old_state) { @@ -625,10 +1037,10 @@ ospf_mpls_te_ism_change (struct ospf_interface *oi, int old_state) zlog_warn ("ospf_mpls_te_ism_change: Cannot get linkparams from OI(%s)?", IF_NAME (oi)); goto out; } + if (oi->area == NULL || oi->area->ospf == NULL) { - zlog_warn ("ospf_mpls_te_ism_change: Cannot refer to OSPF from OI(%s)?", -IF_NAME (oi)); + zlog_warn ("ospf_mpls_te_ism_change: Cannot refer to OSPF from OI(%s)?", IF_NAME (oi)); goto out; } #ifdef notyet @@ -637,13 +1049,17 @@ IF_NAME (oi)); || (lp->area != NULL && oi->area == NULL)) { /* How should we consider this case? */ - zlog_warn ("MPLS-TE: Area for OI(%s) has changed to [%s], flush previous LSAs", IF_NAME (oi), oi->area ? inet_ntoa (oi->area->area_id) : "N/A"); + zlog_warn ("MPLS-TE: Area for OI(%s) has changed to [%s], flush previous LSAs", + IF_NAME (oi), oi->area ? inet_ntoa (oi->area->area_id) : "N/A"); ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA); } #endif - /* Keep Area information in conbination with linkparams. */ + /* Keep Area information in combination with linkparams. */ lp->area = oi->area; + /* Keep interface MPLS-TE status */ + lp->flags = HAS_LINK_PARAMS(oi->ifp); + switch (oi->state) { case ISM_PointToPoint: @@ -653,37 +1069,53 @@ IF_NAME (oi)); old_type = lp->link_type; old_id = lp->link_id; + /* Set Link type, Link ID, Local and Remote IP addr */ set_linkparams_link_type (oi, lp); set_linkparams_link_id (oi, lp); + set_linkparams_lclif_ipaddr (lp, oi->address->u.prefix4); + if (oi->type == LINK_TYPE_SUBTLV_VALUE_PTP) + { + struct prefix *pref = CONNECTED_PREFIX(oi->connected); + if (pref != NULL) + set_linkparams_rmtif_ipaddr(lp, pref->u.prefix4); + } + + /* Update TE parameters */ + update_linkparams(lp); + + /* Try to Schedule LSA */ if ((ntohs (old_type.header.type) != ntohs (lp->link_type.header.type) || old_type.link_type.value != lp->link_type.link_type.value) || (ntohs (old_id.header.type) != ntohs (lp->link_id.header.type) - || ntohl (old_id.value.s_addr) != ntohl (lp->link_id.value.s_addr))) + || ntohl (old_id.value.s_addr) != + ntohl (lp->link_id.value.s_addr))) { - if (lp->flags & LPFLG_LSA_ENGAGED) + if CHECK_FLAG (lp->flags, LPFLG_LSA_ENGAGED) ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); else - ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); + ospf_mpls_te_lsa_schedule (lp, REORIGINATE_THIS_LSA); + } break; default: lp->link_type.header.type = htons (0); lp->link_id.header.type = htons (0); - if (lp->flags & LPFLG_LSA_ENGAGED) + if CHECK_FLAG (lp->flags, LPFLG_LSA_ENGAGED) ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA); break; } out: return; + } static void ospf_mpls_te_nsm_change (struct ospf_neighbor *nbr, int old_state) { - /* So far, nothing to do here. */ + /* Nothing to do here */ return; } @@ -711,106 +1143,10 @@ build_router_tlv (struct stream *s) } static void -build_link_subtlv_link_type (struct stream *s, struct mpls_te_link *lp) -{ - struct te_tlv_header *tlvh = &lp->link_type.header; - if (ntohs (tlvh->type) != 0) +build_link_subtlv (struct stream *s, struct te_tlv_header *tlvh) { - build_tlv_header (s, tlvh); - stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); - } - return; -} -static void -build_link_subtlv_link_id (struct stream *s, struct mpls_te_link *lp) -{ - struct te_tlv_header *tlvh = &lp->link_id.header; - if (ntohs (tlvh->type) != 0) - { - build_tlv_header (s, tlvh); - stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); - } - return; -} - -static void -build_link_subtlv_lclif_ipaddr (struct stream *s, struct mpls_te_link *lp) -{ - struct te_tlv_header *tlvh = (struct te_tlv_header *) lp->lclif_ipaddr; - if (tlvh != NULL && ntohs (tlvh->type) != 0) - { - build_tlv_header (s, tlvh); - stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); - } - return; -} - -static void -build_link_subtlv_rmtif_ipaddr (struct stream *s, struct mpls_te_link *lp) -{ - struct te_tlv_header *tlvh = (struct te_tlv_header *) lp->rmtif_ipaddr; - if (tlvh != NULL && ntohs (tlvh->type) != 0) - { - build_tlv_header (s, tlvh); - stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); - } - return; -} - -static void -build_link_subtlv_te_metric (struct stream *s, struct mpls_te_link *lp) -{ - struct te_tlv_header *tlvh = &lp->te_metric.header; - if (ntohs (tlvh->type) != 0) - { - build_tlv_header (s, tlvh); - stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); - } - return; -} - -static void -build_link_subtlv_max_bw (struct stream *s, struct mpls_te_link *lp) -{ - struct te_tlv_header *tlvh = &lp->max_bw.header; - if (ntohs (tlvh->type) != 0) - { - build_tlv_header (s, tlvh); - stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); - } - return; -} - -static void -build_link_subtlv_max_rsv_bw (struct stream *s, struct mpls_te_link *lp) -{ - struct te_tlv_header *tlvh = &lp->max_rsv_bw.header; - if (ntohs (tlvh->type) != 0) - { - build_tlv_header (s, tlvh); - stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); - } - return; -} - -static void -build_link_subtlv_unrsv_bw (struct stream *s, struct mpls_te_link *lp) -{ - struct te_tlv_header *tlvh = &lp->unrsv_bw.header; - if (ntohs (tlvh->type) != 0) - { - build_tlv_header (s, tlvh); - stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); - } - return; -} - -static void -build_link_subtlv_rsc_clsclr (struct stream *s, struct mpls_te_link *lp) -{ - struct te_tlv_header *tlvh = &lp->rsc_clsclr.header; - if (ntohs (tlvh->type) != 0) + if ((tlvh != NULL) && (ntohs (tlvh->type) != 0)) { build_tlv_header (s, tlvh); stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); @@ -824,15 +1160,27 @@ build_link_tlv (struct stream *s, struct mpls_te_link *lp) set_linkparams_link_header (lp); build_tlv_header (s, &lp->link_header.header); - build_link_subtlv_link_type (s, lp); - build_link_subtlv_link_id (s, lp); - build_link_subtlv_lclif_ipaddr (s, lp); - build_link_subtlv_rmtif_ipaddr (s, lp); - build_link_subtlv_te_metric (s, lp); - build_link_subtlv_max_bw (s, lp); - build_link_subtlv_max_rsv_bw (s, lp); - build_link_subtlv_unrsv_bw (s, lp); - build_link_subtlv_rsc_clsclr (s, lp); + build_link_subtlv (s, &lp->link_type.header); + build_link_subtlv (s, &lp->link_id.header); + build_link_subtlv (s, &lp->lclif_ipaddr.header); + build_link_subtlv (s, &lp->rmtif_ipaddr.header); + build_link_subtlv (s, &lp->te_metric.header); + build_link_subtlv (s, &lp->max_bw.header); + build_link_subtlv (s, &lp->max_rsv_bw.header); + build_link_subtlv (s, &lp->unrsv_bw.header); + build_link_subtlv (s, &lp->rsc_clsclr.header); + build_link_subtlv (s, &lp->lrrid.header); + build_link_subtlv (s, &lp->llri.header); + build_link_subtlv (s, &lp->rip.header); + build_link_subtlv (s, &lp->ras.header); + build_link_subtlv (s, &lp->av_delay.header); + build_link_subtlv (s, &lp->mm_delay.header); + build_link_subtlv (s, &lp->delay_var.header); + build_link_subtlv (s, &lp->pkt_loss.header); + build_link_subtlv (s, &lp->res_bw.header); + build_link_subtlv (s, &lp->ava_bw.header); + build_link_subtlv (s, &lp->res_bw.header); + return; } @@ -861,7 +1209,7 @@ ospf_mpls_te_lsa_new (struct ospf_area *area, struct mpls_te_link *lp) struct stream *s; struct lsa_header *lsah; struct ospf_lsa *new = NULL; - u_char options, lsa_type; + u_char options, lsa_type = 0; struct in_addr lsa_id; u_int32_t tmp; u_int16_t length; @@ -874,19 +1222,42 @@ ospf_mpls_te_lsa_new (struct ospf_area *area, struct mpls_te_link *lp) } lsah = (struct lsa_header *) STREAM_DATA (s); - options = LSA_OPTIONS_GET (area); - options |= LSA_OPTIONS_NSSA_GET (area); - options |= OSPF_OPTION_O; /* Don't forget this :-) */ + options = OSPF_OPTION_O; /* Don't forget this :-) */ - lsa_type = OSPF_OPAQUE_AREA_LSA; - tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, lp->instance); - lsa_id.s_addr = htonl (tmp); + /* Set opaque-LSA header fields depending of the type of RFC */ + if (IS_INTER_AS (lp->type)) + { + if IS_FLOOD_AS (lp->type) + { + options |= OSPF_OPTION_E; /* Enable AS external as we flood Inter-AS with Opaque Type 11 */ + lsa_type = OSPF_OPAQUE_AS_LSA; + } + else + { + options |= LSA_OPTIONS_GET (area); /* Get area default option */ + options |= LSA_OPTIONS_NSSA_GET (area); + lsa_type = OSPF_OPAQUE_AREA_LSA; + } + tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_INTER_AS_LSA, lp->instance); + lsa_id.s_addr = htonl (tmp); + + struct ospf *top = ospf_lookup (); + + lsa_header_set (s, options, lsa_type, lsa_id, top->router_id); + } + else + { + options |= LSA_OPTIONS_GET (area); /* Get area default option */ + options |= LSA_OPTIONS_NSSA_GET (area); + lsa_type = OSPF_OPAQUE_AREA_LSA; + tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, lp->instance); + lsa_id.s_addr = htonl (tmp); + lsa_header_set (s, options, lsa_type, lsa_id, area->ospf->router_id); + } if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) - zlog_debug ("LSA[Type%d:%s]: Create an Opaque-LSA/MPLS-TE instance", lsa_type, inet_ntoa (lsa_id)); - - /* Set opaque-LSA header fields. */ - lsa_header_set (s, options, lsa_type, lsa_id, area->ospf->router_id); + zlog_debug ("LSA[Type%d:%s]: Create an Opaque-LSA/MPLS-TE instance", + lsa_type, inet_ntoa (lsa_id)); /* Set opaque-LSA body fields. */ ospf_mpls_te_lsa_body_set (s, lp); @@ -941,9 +1312,8 @@ ospf_mpls_te_lsa_originate1 (struct ospf_area *area, struct mpls_te_link *lp) goto out; } - /* Now this linkparameter entry has associated LSA. */ - lp->flags |= LPFLG_LSA_ENGAGED; - + /* Now this link-parameter entry has associated LSA. */ + SET_FLAG (lp->flags, LPFLG_LSA_ENGAGED); /* Update new LSA origination count. */ area->ospf->lsa_originate_count++; @@ -954,7 +1324,8 @@ ospf_mpls_te_lsa_originate1 (struct ospf_area *area, struct mpls_te_link *lp) { char area_id[INET_ADDRSTRLEN]; strcpy (area_id, inet_ntoa (area->area_id)); - zlog_debug ("LSA[Type%d:%s]: Originate Opaque-LSA/MPLS-TE: Area(%s), Link(%s)", new->data->type, inet_ntoa (new->data->id), area_id, lp->ifp->name); + zlog_debug ("LSA[Type%d:%s]: Originate Opaque-LSA/MPLS-TE: Area(%s), Link(%s)", + new->data->type, inet_ntoa (new->data->id), area_id, lp->ifp->name); ospf_lsa_header_dump (new->data); } @@ -964,7 +1335,7 @@ out: } static int -ospf_mpls_te_lsa_originate (void *arg) +ospf_mpls_te_lsa_originate_area (void *arg) { struct ospf_area *area = (struct ospf_area *) arg; struct listnode *node, *nnode; @@ -973,34 +1344,44 @@ ospf_mpls_te_lsa_originate (void *arg) if (OspfMplsTE.status == disabled) { - zlog_info ("ospf_mpls_te_lsa_originate: MPLS-TE is disabled now."); + zlog_info ("ospf_mpls_te_lsa_originate_area: MPLS-TE is disabled now."); rc = 0; /* This is not an error case. */ goto out; } for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp)) { + /* Process only enabled LSA with area scope flooding */ + if (!CHECK_FLAG (lp->flags, LPFLG_LSA_ACTIVE) || IS_FLOOD_AS (lp->type)) + continue; + if (lp->area == NULL) continue; + if (! IPV4_ADDR_SAME (&lp->area->area_id, &area->area_id)) continue; - if (lp->flags & LPFLG_LSA_ENGAGED) + if CHECK_FLAG (lp->flags, LPFLG_LSA_ENGAGED) { - if (lp->flags & LPFLG_LSA_FORCED_REFRESH) + if CHECK_FLAG (lp->flags, LPFLG_LSA_FORCED_REFRESH) { - lp->flags &= ~LPFLG_LSA_FORCED_REFRESH; + UNSET_FLAG (lp->flags, LPFLG_LSA_FORCED_REFRESH); + zlog_warn ("OSPF MPLS-TE (ospf_mpls_te_lsa_originate_area): Refresh instead of Originate"); ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); } continue; } if (! is_mandated_params_set (lp)) { - zlog_warn ("ospf_mpls_te_lsa_originate: Link(%s) lacks some mandated MPLS-TE parameters.", lp->ifp ? lp->ifp->name : "?"); + zlog_warn ("ospf_mpls_te_lsa_originate_area: Link(%s) lacks some mandated MPLS-TE parameters.", + lp->ifp ? lp->ifp->name : "?"); continue; } /* Ok, let's try to originate an LSA for this area and Link. */ + if (IS_DEBUG_OSPF_TE) + zlog_debug ("MPLS-TE(ospf_mpls_te_lsa_originate_area) Let's finally reoriginate the LSA %d through the Area %s for Link %s", + lp->instance, inet_ntoa (area->area_id), lp->ifp ? lp->ifp->name : "?"); if (ospf_mpls_te_lsa_originate1 (area, lp) != 0) goto out; } @@ -1010,11 +1391,112 @@ out: return rc; } +static int +ospf_mpls_te_lsa_originate2 (struct ospf *top, struct mpls_te_link *lp) +{ + struct ospf_lsa *new; + int rc = -1; + + /* Create new Opaque-LSA/Inter-AS instance. */ + if ((new = ospf_mpls_te_lsa_new (NULL, lp)) == NULL) + { + zlog_warn ("ospf_mpls_te_lsa_originate2: ospf_router_info_lsa_new() ?"); + goto out; + } + + /* Install this LSA into LSDB. */ + if (ospf_lsa_install (top, NULL /*oi */ , new) == NULL) + { + zlog_warn ("ospf_mpls_te_lsa_originate2: ospf_lsa_install() ?"); + ospf_lsa_unlock (&new); + goto out; + } + + /* Now this Router Info parameter entry has associated LSA. */ + SET_FLAG (lp->flags, LPFLG_LSA_ENGAGED); + /* Update new LSA origination count. */ + top->lsa_originate_count++; + + /* Flood new LSA through AS. */ + ospf_flood_through_as (top, NULL /*nbr */ , new); + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + { + zlog_debug ("LSA[Type%d:%s]: Originate Opaque-LSA/MPLS-TE Inter-AS", + new->data->type, inet_ntoa (new->data->id)); + ospf_lsa_header_dump (new->data); + } + + rc = 0; +out:return rc; +} + +static int +ospf_mpls_te_lsa_originate_as (void *arg) +{ + struct ospf *top; + struct ospf_area *area; + struct listnode *node, *nnode; + struct mpls_te_link *lp; + int rc = -1; + + if ((OspfMplsTE.status == disabled) || (OspfMplsTE.inter_as == Disable)) + { + zlog_info + ("ospf_mpls_te_lsa_originate_as: MPLS-TE Inter-AS is disabled for now."); + rc = 0; /* This is not an error case. */ + goto out; + } + + for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp)) + { + /* Process only enabled INTER_AS Links or Pseudo-Links */ + if (!CHECK_FLAG (lp->flags, LPFLG_LSA_ACTIVE) || !IS_INTER_AS (lp->type)) + continue; + + if CHECK_FLAG (lp->flags, LPFLG_LSA_ENGAGED) + { + if CHECK_FLAG (lp->flags, LPFLG_LSA_FORCED_REFRESH) + { + UNSET_FLAG (lp->flags, LPFLG_LSA_FORCED_REFRESH); + ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); + } + continue; + } + if (!is_mandated_params_set (lp)) + { + zlog_warn ("ospf_mpls_te_lsa_originate_as: Link(%s) lacks some mandated MPLS-TE parameters.", + lp->ifp ? lp->ifp->name : "?"); + continue; + } + + /* Ok, let's try to originate an LSA for this AS and Link. */ + if (IS_DEBUG_OSPF_TE) + zlog_debug ("MPLS-TE(ospf_mpls_te_lsa_originate_as) Let's finally re-originate the Inter-AS LSA %d through the %s for Link %s", + lp->instance, IS_FLOOD_AS (lp->type) ? "AS" : "Area", lp->ifp ? lp->ifp->name : "Unknown"); + + if (IS_FLOOD_AS (lp->type)) + { + top = (struct ospf *) arg; + rc = ospf_mpls_te_lsa_originate2 (top, lp); + } + else + { + area = (struct ospf_area *) arg; + rc = ospf_mpls_te_lsa_originate1 (area, lp); + } + } + + rc = 0; +out:return rc; +} + static struct ospf_lsa * ospf_mpls_te_lsa_refresh (struct ospf_lsa *lsa) { struct mpls_te_link *lp; struct ospf_area *area = lsa->area; + struct ospf *top; struct ospf_lsa *new = NULL; if (OspfMplsTE.status == disabled) @@ -1034,11 +1516,18 @@ ospf_mpls_te_lsa_refresh (struct ospf_lsa *lsa) lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); /* Flush it anyway. */ } + /* Check if lp was not disable in the interval */ + if (!CHECK_FLAG (lp->flags, LPFLG_LSA_ACTIVE)) + { + zlog_warn ("ospf_mpls_te_lsa_refresh: lp was disabled: Flush it!"); + lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); /* Flush it anyway. */ + } + /* If the lsa's age reached to MaxAge, start flushing procedure. */ if (IS_LSA_MAXAGE (lsa)) { if (lp) - lp->flags &= ~LPFLG_LSA_ENGAGED; + UNSET_FLAG (lp->flags, LPFLG_LSA_ENGAGED); ospf_opaque_lsa_flush_schedule (lsa); goto out; } @@ -1053,15 +1542,24 @@ ospf_mpls_te_lsa_refresh (struct ospf_lsa *lsa) /* Install this LSA into LSDB. */ /* Given "lsa" will be freed in the next function. */ - if (ospf_lsa_install (area->ospf, NULL/*oi*/, new) == NULL) + /* As area could be NULL i.e. when using OPAQUE_LSA_AS, we prefer to use ospf_lookup() to get ospf instance */ + if (area) + top = area->ospf; + else + top = ospf_lookup (); + + if (ospf_lsa_install (top, NULL /*oi */ , new) == NULL) { zlog_warn ("ospf_mpls_te_lsa_refresh: ospf_lsa_install() ?"); ospf_lsa_unlock (&new); goto out; } - /* Flood updated LSA through area. */ - ospf_flood_through_area (area, NULL/*nbr*/, new); + /* Flood updated LSA through AS or Area depending of the RFC of the link */ + if (IS_FLOOD_AS (lp->type)) + ospf_flood_through_as (top, NULL, new); + else + ospf_flood_through_area (area, NULL/*nbr*/, new); /* Debug logging. */ if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) @@ -1075,34 +1573,80 @@ out: return new; } -static void -ospf_mpls_te_lsa_schedule (struct mpls_te_link *lp, - enum sched_opcode opcode) +void +ospf_mpls_te_lsa_schedule (struct mpls_te_link *lp, opcode_t opcode) { struct ospf_lsa lsa; struct lsa_header lsah; + struct ospf *top; u_int32_t tmp; memset (&lsa, 0, sizeof (lsa)); memset (&lsah, 0, sizeof (lsah)); + top = ospf_lookup (); + + /* Check if the pseudo link is ready to flood */ + if (!(CHECK_FLAG (lp->flags, LPFLG_LSA_ACTIVE)) + || !(IS_FLOOD_AREA (lp->type) || IS_FLOOD_AS (lp->type))) { + return; + } lsa.area = lp->area; lsa.data = &lsah; - lsah.type = OSPF_OPAQUE_AREA_LSA; - tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, lp->instance); - lsah.id.s_addr = htonl (tmp); + if (IS_FLOOD_AS (lp->type)) + { + lsah.type = OSPF_OPAQUE_AS_LSA; + tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_INTER_AS_LSA, lp->instance); + lsah.id.s_addr = htonl (tmp); + } + else + { + lsah.type = OSPF_OPAQUE_AREA_LSA; + if (IS_INTER_AS (lp->type)) + { + /* Set the area context if not know */ + if (lp->area == NULL) + lp->area = ospf_area_lookup_by_area_id (top, OspfMplsTE.interas_areaid); + /* Unable to set the area context. Abort! */ + if (lp->area == NULL) + { + zlog_warn ("MPLS-TE(ospf_mpls_te_lsa_schedule) Area context is null. Abort !"); + return; + } + tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_INTER_AS_LSA, lp->instance); + } + else + tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, lp->instance); + lsah.id.s_addr = htonl (tmp); + } switch (opcode) { - case REORIGINATE_PER_AREA: - ospf_opaque_lsa_reoriginate_schedule ((void *) lp->area, - OSPF_OPAQUE_AREA_LSA, OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA); + case REORIGINATE_THIS_LSA: + if (IS_FLOOD_AS (lp->type)) + { + ospf_opaque_lsa_reoriginate_schedule ((void *) top, OSPF_OPAQUE_AS_LSA, + OPAQUE_TYPE_INTER_AS_LSA); + break; + } + + if (IS_FLOOD_AREA (lp->type)) + { + if (IS_INTER_AS (lp->type)) + ospf_opaque_lsa_reoriginate_schedule ((void *) lp->area, OSPF_OPAQUE_AREA_LSA, + OPAQUE_TYPE_INTER_AS_LSA); + else + ospf_opaque_lsa_reoriginate_schedule ((void *) lp->area, OSPF_OPAQUE_AREA_LSA, + OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA); + break; + } break; case REFRESH_THIS_LSA: ospf_opaque_lsa_refresh_schedule (&lsa); break; case FLUSH_THIS_LSA: - lp->flags &= ~LPFLG_LSA_ENGAGED; + /* Reset Activity flag */ + lp->flags = LPFLG_LSA_INACTIVE; ospf_opaque_lsa_flush_schedule (&lsa); break; default: @@ -1113,6 +1657,7 @@ ospf_mpls_te_lsa_schedule (struct mpls_te_link *lp, return; } + /*------------------------------------------------------------------------* * Followings are vty session control functions. *------------------------------------------------------------------------*/ @@ -1123,7 +1668,8 @@ show_vty_router_addr (struct vty *vty, struct te_tlv_header *tlvh) struct te_tlv_router_addr *top = (struct te_tlv_router_addr *) tlvh; if (vty != NULL) - vty_out (vty, " Router-Address: %s%s", inet_ntoa (top->value), VTY_NEWLINE); + vty_out (vty, " Router-Address: %s%s", inet_ntoa (top->value), + VTY_NEWLINE); else zlog_debug (" Router-Address: %s", inet_ntoa (top->value)); @@ -1136,7 +1682,8 @@ show_vty_link_header (struct vty *vty, struct te_tlv_header *tlvh) struct te_tlv_link *top = (struct te_tlv_link *) tlvh; if (vty != NULL) - vty_out (vty, " Link: %u octets of data%s", ntohs (top->header.length), VTY_NEWLINE); + vty_out (vty, " Link: %u octets of data%s", ntohs (top->header.length), + VTY_NEWLINE); else zlog_debug (" Link: %u octets of data", ntohs (top->header.length)); @@ -1163,7 +1710,8 @@ show_vty_link_subtlv_link_type (struct vty *vty, struct te_tlv_header *tlvh) } if (vty != NULL) - vty_out (vty, " Link-Type: %s (%u)%s", cp, top->link_type.value, VTY_NEWLINE); + vty_out (vty, " Link-Type: %s (%u)%s", cp, top->link_type.value, + VTY_NEWLINE); else zlog_debug (" Link-Type: %s (%u)", cp, top->link_type.value); @@ -1185,7 +1733,8 @@ show_vty_link_subtlv_link_id (struct vty *vty, struct te_tlv_header *tlvh) } static u_int16_t -show_vty_link_subtlv_lclif_ipaddr (struct vty *vty, struct te_tlv_header *tlvh) +show_vty_link_subtlv_lclif_ipaddr (struct vty *vty, + struct te_tlv_header *tlvh) { struct te_link_subtlv_lclif_ipaddr *top; int i, n; @@ -1201,7 +1750,8 @@ show_vty_link_subtlv_lclif_ipaddr (struct vty *vty, struct te_tlv_header *tlvh) for (i = 0; i < n; i++) { if (vty != NULL) - vty_out (vty, " #%d: %s%s", i, inet_ntoa (top->value[i]), VTY_NEWLINE); + vty_out (vty, " #%d: %s%s", i, inet_ntoa (top->value[i]), + VTY_NEWLINE); else zlog_debug (" #%d: %s", i, inet_ntoa (top->value[i])); } @@ -1209,7 +1759,8 @@ show_vty_link_subtlv_lclif_ipaddr (struct vty *vty, struct te_tlv_header *tlvh) } static u_int16_t -show_vty_link_subtlv_rmtif_ipaddr (struct vty *vty, struct te_tlv_header *tlvh) +show_vty_link_subtlv_rmtif_ipaddr (struct vty *vty, + struct te_tlv_header *tlvh) { struct te_link_subtlv_rmtif_ipaddr *top; int i, n; @@ -1224,7 +1775,8 @@ show_vty_link_subtlv_rmtif_ipaddr (struct vty *vty, struct te_tlv_header *tlvh) for (i = 0; i < n; i++) { if (vty != NULL) - vty_out (vty, " #%d: %s%s", i, inet_ntoa (top->value[i]), VTY_NEWLINE); + vty_out (vty, " #%d: %s%s", i, inet_ntoa (top->value[i]), + VTY_NEWLINE); else zlog_debug (" #%d: %s", i, inet_ntoa (top->value[i])); } @@ -1238,9 +1790,11 @@ show_vty_link_subtlv_te_metric (struct vty *vty, struct te_tlv_header *tlvh) top = (struct te_link_subtlv_te_metric *) tlvh; if (vty != NULL) - vty_out (vty, " Traffic Engineering Metric: %u%s", (u_int32_t) ntohl (top->value), VTY_NEWLINE); + vty_out (vty, " Traffic Engineering Metric: %u%s", + (u_int32_t) ntohl (top->value), VTY_NEWLINE); else - zlog_debug (" Traffic Engineering Metric: %u", (u_int32_t) ntohl (top->value)); + zlog_debug (" Traffic Engineering Metric: %u", + (u_int32_t) ntohl (top->value)); return TLV_SIZE (tlvh); } @@ -1252,7 +1806,7 @@ show_vty_link_subtlv_max_bw (struct vty *vty, struct te_tlv_header *tlvh) float fval; top = (struct te_link_subtlv_max_bw *) tlvh; - ntohf (&top->value, &fval); + fval = ntohf (top->value); if (vty != NULL) vty_out (vty, " Maximum Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE); @@ -1269,10 +1823,11 @@ show_vty_link_subtlv_max_rsv_bw (struct vty *vty, struct te_tlv_header *tlvh) float fval; top = (struct te_link_subtlv_max_rsv_bw *) tlvh; - ntohf (&top->value, &fval); + fval = ntohf (top->value); if (vty != NULL) - vty_out (vty, " Maximum Reservable Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE); + vty_out (vty, " Maximum Reservable Bandwidth: %g (Bytes/sec)%s", fval, + VTY_NEWLINE); else zlog_debug (" Maximum Reservable Bandwidth: %g (Bytes/sec)", fval); @@ -1283,17 +1838,25 @@ static u_int16_t show_vty_link_subtlv_unrsv_bw (struct vty *vty, struct te_tlv_header *tlvh) { struct te_link_subtlv_unrsv_bw *top; - float fval; + float fval1, fval2; int i; top = (struct te_link_subtlv_unrsv_bw *) tlvh; - for (i = 0; i < 8; i++) + if (vty != NULL) + vty_out (vty, " Unreserved Bandwidth per Class Type in Byte/s:%s", VTY_NEWLINE); + else + zlog_debug (" Unreserved Bandwidth per Class Type in Byte/s:"); + for (i = 0; i < MAX_CLASS_TYPE; i+=2) { - ntohf (&top->value[i], &fval); + fval1 = ntohf (top->value[i]); + fval2 = ntohf (top->value[i+1]); + if (vty != NULL) - vty_out (vty, " Unreserved Bandwidth (pri %d): %g (Bytes/sec)%s", i, fval, VTY_NEWLINE); + vty_out(vty, " [%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)%s", + i, fval1, i+1, fval2, VTY_NEWLINE); else - zlog_debug (" Unreserved Bandwidth (pri %d): %g (Bytes/sec)", i, fval); + zlog_debug (" [%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)", + i, fval1, i+1, fval2); } return TLV_SIZE (tlvh); @@ -1306,9 +1869,230 @@ show_vty_link_subtlv_rsc_clsclr (struct vty *vty, struct te_tlv_header *tlvh) top = (struct te_link_subtlv_rsc_clsclr *) tlvh; if (vty != NULL) - vty_out (vty, " Resource class/color: 0x%x%s", (u_int32_t) ntohl (top->value), VTY_NEWLINE); + vty_out (vty, " Resource class/color: 0x%x%s", + (u_int32_t) ntohl (top->value), VTY_NEWLINE); else - zlog_debug (" Resource Class/Color: 0x%x", (u_int32_t) ntohl (top->value)); + zlog_debug (" Resource Class/Color: 0x%x", + (u_int32_t) ntohl (top->value)); + + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_link_subtlv_lrrid (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_link_subtlv_lrrid *top; + + top = (struct te_link_subtlv_lrrid *) tlvh; + + if (vty != NULL) + { + vty_out (vty, " Local TE Router ID: %s%s", inet_ntoa (top->local), + VTY_NEWLINE); + vty_out (vty, " Remote TE Router ID: %s%s", inet_ntoa (top->remote), + VTY_NEWLINE); + } + else + { + zlog_debug (" Local TE Router ID: %s", inet_ntoa (top->local)); + zlog_debug (" Remote TE Router ID: %s", inet_ntoa (top->remote)); + } + + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_link_subtlv_llri (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_link_subtlv_llri *top; + + top = (struct te_link_subtlv_llri *) tlvh; + + if (vty != NULL) + { + vty_out (vty, " Link Local ID: %d%s", (u_int32_t) ntohl (top->local), + VTY_NEWLINE); + vty_out (vty, " Link Remote ID: %d%s", (u_int32_t) ntohl (top->remote), + VTY_NEWLINE); + } + else + { + zlog_debug (" Link Local ID: %d", (u_int32_t) ntohl (top->local)); + zlog_debug (" Link Remote ID: %d", (u_int32_t) ntohl (top->remote)); + } + + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_link_subtlv_rip (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_link_subtlv_rip *top; + + top = (struct te_link_subtlv_rip *) tlvh; + + if (vty != NULL) + vty_out (vty, " Inter-AS TE Remote ASBR IP address: %s%s", + inet_ntoa (top->value), VTY_NEWLINE); + else + zlog_debug (" Inter-AS TE Remote ASBR IP address: %s", + inet_ntoa (top->value)); + + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_link_subtlv_ras (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_link_subtlv_ras *top; + + top = (struct te_link_subtlv_ras *) tlvh; + + if (vty != NULL) + vty_out (vty, " Inter-AS TE Remote AS number: %u%s", ntohl (top->value), + VTY_NEWLINE); + else + zlog_debug (" Inter-AS TE Remote AS number: %u", ntohl (top->value)); + + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_link_subtlv_av_delay (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_link_subtlv_av_delay *top; + u_int32_t delay; + u_int32_t anomalous; + + top = (struct te_link_subtlv_av_delay *) tlvh; + delay = (u_int32_t) ntohl (top->value) & TE_EXT_MASK; + anomalous = (u_int32_t) ntohl (top->value) & TE_EXT_ANORMAL; + + if (vty != NULL) + vty_out (vty, " %s Average Link Delay: %d (micro-sec)%s", + anomalous ? "Anomalous" : "Normal", delay, VTY_NEWLINE); + else + zlog_debug (" %s Average Link Delay: %d (micro-sec)", + anomalous ? "Anomalous" : "Normal", delay); + + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_link_subtlv_mm_delay (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_link_subtlv_mm_delay *top; + u_int32_t low, high; + u_int32_t anomalous; + + top = (struct te_link_subtlv_mm_delay *) tlvh; + low = (u_int32_t) ntohl (top->low) & TE_EXT_MASK; + anomalous = (u_int32_t) ntohl (top->low) & TE_EXT_ANORMAL; + high = (u_int32_t) ntohl (top->high); + + if (vty != NULL) + vty_out (vty, " %s Min/Max Link Delay: %d/%d (micro-sec)%s", + anomalous ? "Anomalous" : "Normal", low, high, VTY_NEWLINE); + else + zlog_debug (" %s Min/Max Link Delay: %d/%d (micro-sec)", + anomalous ? "Anomalous" : "Normal", low, high); + + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_link_subtlv_delay_var (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_link_subtlv_delay_var *top; + u_int32_t jitter; + + top = (struct te_link_subtlv_delay_var *) tlvh; + jitter = (u_int32_t) ntohl (top->value) & TE_EXT_MASK; + + if (vty != NULL) + vty_out (vty, " Delay Variation: %d (micro-sec)%s", jitter, VTY_NEWLINE); + else + zlog_debug (" Delay Variation: %d (micro-sec)", jitter); + + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_link_subtlv_pkt_loss (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_link_subtlv_pkt_loss *top; + u_int32_t loss; + u_int32_t anomalous; + float fval; + + top = (struct te_link_subtlv_pkt_loss *) tlvh; + loss = (u_int32_t) ntohl (top->value) & TE_EXT_MASK; + fval = (float) (loss * LOSS_PRECISION); + anomalous = (u_int32_t) ntohl (top->value) & TE_EXT_ANORMAL; + + if (vty != NULL) + vty_out (vty, " %s Link Loss: %g (%%)%s", anomalous ? "Anomalous" : "Normal", + fval, VTY_NEWLINE); + else + zlog_debug (" %s Link Loss: %g (%%)", anomalous ? "Anomalous" : "Normal", + fval); + + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_link_subtlv_res_bw (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_link_subtlv_res_bw *top; + float fval; + + top = (struct te_link_subtlv_res_bw *) tlvh; + fval = ntohf (top->value); + + if (vty != NULL) + vty_out (vty, " Unidirectional Residual Bandwidth: %g (Bytes/sec)%s", + fval, VTY_NEWLINE); + else + zlog_debug (" Unidirectional Residual Bandwidth: %g (Bytes/sec)", + fval); + + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_link_subtlv_ava_bw (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_link_subtlv_ava_bw *top; + float fval; + + top = (struct te_link_subtlv_ava_bw *) tlvh; + fval = ntohf (top->value); + + if (vty != NULL) + vty_out (vty, " Unidirectional Available Bandwidth: %g (Bytes/sec)%s", + fval, VTY_NEWLINE); + else + zlog_debug (" Unidirectional Available Bandwidth: %g (Bytes/sec)", + fval); + + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_link_subtlv_use_bw (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_link_subtlv_use_bw *top; + float fval; + + top = (struct te_link_subtlv_use_bw *) tlvh; + fval = ntohf (top->value); + + if (vty != NULL) + vty_out (vty, " Unidirectional Utilized Bandwidth: %g (Bytes/sec)%s", + fval, VTY_NEWLINE); + else + zlog_debug (" Unidirectional Utilized Bandwidth: %g (Bytes/sec)", + fval); return TLV_SIZE (tlvh); } @@ -1317,9 +2101,11 @@ static u_int16_t show_vty_unknown_tlv (struct vty *vty, struct te_tlv_header *tlvh) { if (vty != NULL) - vty_out (vty, " Unknown TLV: [type(0x%x), length(0x%x)]%s", ntohs (tlvh->type), ntohs (tlvh->length), VTY_NEWLINE); + vty_out (vty, " Unknown TLV: [type(0x%x), length(0x%x)]%s", + ntohs (tlvh->type), ntohs (tlvh->length), VTY_NEWLINE); else - zlog_debug (" Unknown TLV: [type(0x%x), length(0x%x)]", ntohs (tlvh->type), ntohs (tlvh->length)); + zlog_debug (" Unknown TLV: [type(0x%x), length(0x%x)]", + ntohs (tlvh->type), ntohs (tlvh->length)); return TLV_SIZE (tlvh); } @@ -1363,6 +2149,39 @@ ospf_mpls_te_show_link_subtlv (struct vty *vty, struct te_tlv_header *tlvh0, case TE_LINK_SUBTLV_RSC_CLSCLR: sum += show_vty_link_subtlv_rsc_clsclr (vty, tlvh); break; + case TE_LINK_SUBTLV_LRRID: + sum += show_vty_link_subtlv_lrrid (vty, tlvh); + break; + case TE_LINK_SUBTLV_LLRI: + sum += show_vty_link_subtlv_llri (vty, tlvh); + break; + case TE_LINK_SUBTLV_RIP: + sum += show_vty_link_subtlv_rip (vty, tlvh); + break; + case TE_LINK_SUBTLV_RAS: + sum += show_vty_link_subtlv_ras (vty, tlvh); + break; + case TE_LINK_SUBTLV_AV_DELAY: + sum += show_vty_link_subtlv_av_delay (vty, tlvh); + break; + case TE_LINK_SUBTLV_MM_DELAY: + sum += show_vty_link_subtlv_mm_delay (vty, tlvh); + break; + case TE_LINK_SUBTLV_DELAY_VAR: + sum += show_vty_link_subtlv_delay_var (vty, tlvh); + break; + case TE_LINK_SUBTLV_PKT_LOSS: + sum += show_vty_link_subtlv_pkt_loss (vty, tlvh); + break; + case TE_LINK_SUBTLV_RES_BW: + sum += show_vty_link_subtlv_res_bw (vty, tlvh); + break; + case TE_LINK_SUBTLV_AVA_BW: + sum += show_vty_link_subtlv_ava_bw (vty, tlvh); + break; + case TE_LINK_SUBTLV_USE_BW: + sum += show_vty_link_subtlv_use_bw (vty, tlvh); + break; default: sum += show_vty_unknown_tlv (vty, tlvh); break; @@ -1416,49 +2235,20 @@ ospf_mpls_te_show_info (struct vty *vty, struct ospf_lsa *lsa) static void ospf_mpls_te_config_write_router (struct vty *vty) { + if (OspfMplsTE.status == enabled) { - vty_out (vty, " mpls-te%s", VTY_NEWLINE); + vty_out (vty, " mpls-te on%s", VTY_NEWLINE); vty_out (vty, " mpls-te router-address %s%s", inet_ntoa (OspfMplsTE.router_addr.value), VTY_NEWLINE); } - return; -} -static void -ospf_mpls_te_config_write_if (struct vty *vty, struct interface *ifp) -{ - struct mpls_te_link *lp; + if (OspfMplsTE.inter_as == AS) + vty_out (vty, " mpls-te inter-as as%s", VTY_NEWLINE); + if (OspfMplsTE.inter_as == Area) + vty_out (vty, " mpls-te inter-as area %s %s", + inet_ntoa (OspfMplsTE.interas_areaid), VTY_NEWLINE); - if ((OspfMplsTE.status == enabled) - && (! if_is_loopback (ifp) && if_is_up (ifp) && ospf_oi_count (ifp) > 0) - && ((lp = lookup_linkparams_by_ifp (ifp)) != NULL)) - { - float fval; - int i; - - vty_out (vty, " mpls-te link metric %u%s", - (u_int32_t) ntohl (lp->te_metric.value), VTY_NEWLINE); - - ntohf (&lp->max_bw.value, &fval); - if (fval >= MPLS_TE_MINIMUM_BANDWIDTH) - vty_out (vty, " mpls-te link max-bw %g%s", fval, VTY_NEWLINE); - - ntohf (&lp->max_rsv_bw.value, &fval); - if (fval >= MPLS_TE_MINIMUM_BANDWIDTH) - vty_out (vty, " mpls-te link max-rsv-bw %g%s", fval, VTY_NEWLINE); - - for (i = 0; i < 8; i++) - { - ntohf (&lp->unrsv_bw.value[i], &fval); - if (fval >= MPLS_TE_MINIMUM_BANDWIDTH) - vty_out (vty, " mpls-te link unrsv-bw %d %g%s", - i, fval, VTY_NEWLINE); - } - - vty_out (vty, " mpls-te link rsc-clsclr 0x%x%s", - (u_int32_t) ntohl (lp->rsc_clsclr.value), VTY_NEWLINE); - } return; } @@ -1466,13 +2256,13 @@ ospf_mpls_te_config_write_if (struct vty *vty, struct interface *ifp) * Followings are vty command functions. *------------------------------------------------------------------------*/ -DEFUN (mpls_te, - mpls_te_cmd, - "mpls-te", - "Configure MPLS-TE parameters\n" +DEFUN (ospf_mpls_te_on, + ospf_mpls_te_on_cmd, + "mpls-te on", + MPLS_TE_STR "Enable the MPLS-TE functionality\n") { - struct listnode *node, *nnode; + struct listnode *node; struct mpls_te_link *lp; struct ospf *ospf = vty->index; @@ -1487,31 +2277,28 @@ DEFUN (mpls_te, OspfMplsTE.status = enabled; - /* - * Following code is intended to handle two cases; - * - * 1) MPLS-TE was disabled at startup time, but now become enabled. - * 2) MPLS-TE was once enabled then disabled, and now enabled again. - */ - for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp)) - initialize_linkparams (lp); + /* Reoriginate RFC3630 & RFC6827 Links */ + ospf_mpls_te_foreach_area (ospf_mpls_te_lsa_schedule, REORIGINATE_THIS_LSA); - ospf_mpls_te_foreach_area (ospf_mpls_te_lsa_schedule, REORIGINATE_PER_AREA); + /* Reoriginate LSA if INTER-AS is always on */ + if (OspfMplsTE.inter_as != Disable) + { + for (ALL_LIST_ELEMENTS_RO (OspfMplsTE.iflist, node, lp)) + { + if (IS_INTER_AS (lp->type)) + { + ospf_mpls_te_lsa_schedule (lp, REORIGINATE_THIS_LSA); + } + } + } return CMD_SUCCESS; } -ALIAS (mpls_te, - mpls_te_on_cmd, - "mpls-te on", - "Configure MPLS-TE parameters\n" - "Enable the MPLS-TE functionality\n") - -DEFUN (no_mpls_te, - no_mpls_te_cmd, +DEFUN (no_ospf_mpls_te, + no_ospf_mpls_te_cmd, "no mpls-te", NO_STR - "Configure MPLS-TE parameters\n" "Disable the MPLS-TE functionality\n") { struct listnode *node, *nnode; @@ -1530,24 +2317,23 @@ DEFUN (no_mpls_te, OspfMplsTE.status = disabled; for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp)) - if (lp->area != NULL) - if (lp->flags & LPFLG_LSA_ENGAGED) + if CHECK_FLAG (lp->flags, LPFLG_LSA_ENGAGED) ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA); return CMD_SUCCESS; } -ALIAS (no_mpls_te, - no_mpls_te_val_cmd, +ALIAS (no_ospf_mpls_te, + no_ospf_mpls_te_val_cmd, "no mpls-te on", NO_STR - "Configure MPLS-TE parameters\n" + MPLS_TE_STR "Disable the MPLS-TE functionality\n") -DEFUN (mpls_te_router_addr, - mpls_te_router_addr_cmd, +DEFUN (ospf_mpls_te_router_addr, + ospf_mpls_te_router_addr_cmd, "mpls-te router-address A.B.C.D", - "MPLS-TE specific commands\n" + MPLS_TE_STR "Stable IP address of the advertising router\n" "MPLS-TE router address in IPv4 address format\n") { @@ -1578,10 +2364,10 @@ DEFUN (mpls_te_router_addr, for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp)) { - if (lp->area == NULL) + if ((lp->area == NULL) || IS_FLOOD_AS (lp->type)) continue; - if ((lp->flags & LPFLG_LSA_ENGAGED) == 0) + if (!CHECK_FLAG (lp->flags, LPFLG_LSA_ENGAGED)) { need_to_reoriginate = 1; break; @@ -1590,247 +2376,152 @@ DEFUN (mpls_te_router_addr, for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp)) { - if (lp->area == NULL) + if ((lp->area == NULL) || IS_FLOOD_AS (lp->type)) continue; if (need_to_reoriginate) - lp->flags |= LPFLG_LSA_FORCED_REFRESH; + SET_FLAG (lp->flags, LPFLG_LSA_FORCED_REFRESH); else ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); } if (need_to_reoriginate) - ospf_mpls_te_foreach_area ( - ospf_mpls_te_lsa_schedule, REORIGINATE_PER_AREA); + ospf_mpls_te_foreach_area (ospf_mpls_te_lsa_schedule, REORIGINATE_THIS_LSA); } out: return CMD_SUCCESS; } -DEFUN (mpls_te_link_metric, - mpls_te_link_metric_cmd, - "mpls-te link metric <0-4294967295>", - "MPLS-TE specific commands\n" - "Configure MPLS-TE link parameters\n" - "Link metric for MPLS-TE purpose\n" - "Metric\n") +static int +set_inter_as_mode (struct vty *vty, const char *mode_name, + const char *area_id) { - struct interface *ifp = (struct interface *) vty->index; + enum inter_as_mode mode; + struct listnode *node; struct mpls_te_link *lp; - u_int32_t value; + int format; - if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL) + if (OspfMplsTE.status == enabled) { - vty_out (vty, "mpls_te_link_metric: Something wrong!%s", VTY_NEWLINE); - return CMD_WARNING; - } - value = strtoul (argv[0], NULL, 10); + /* Read and Check inter_as mode */ + if (strcmp (mode_name, "as") == 0) + mode = AS; + else if (strcmp (mode_name, "area") == 0) + { + mode = Area; + VTY_GET_OSPF_AREA_ID (OspfMplsTE.interas_areaid, format, area_id); + } + else + { + vty_out (vty, "Unknown mode. Please choose between as or area%s", + VTY_NEWLINE); + return CMD_WARNING; + } - if (ntohs (lp->te_metric.header.type) == 0 - || ntohl (lp->te_metric.value) != value) - { - set_linkparams_te_metric (lp, value); + if (IS_DEBUG_OSPF_EVENT) + zlog_debug ("MPLS-TE: Inter-AS enable with %s flooding support", + mode2text[mode]); - if (OspfMplsTE.status == enabled) - if (lp->area != NULL) - { - if (lp->flags & LPFLG_LSA_ENGAGED) - ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); - else - ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); - } + /* Register new callbacks regarding the flooding scope (AS or Area) */ + if (ospf_mpls_te_register (mode) < 0) + { + vty_out (vty, "Internal error: Unable to register Inter-AS functions%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + /* Enable mode and re-originate LSA if needed */ + if ((OspfMplsTE.inter_as == Disable) && (mode != OspfMplsTE.inter_as)) + { + OspfMplsTE.inter_as = mode; + /* Re-originate all InterAS-TEv2 LSA */ + for (ALL_LIST_ELEMENTS_RO (OspfMplsTE.iflist, node, lp)) + { + if (IS_INTER_AS (lp->type)) + { + if (mode == AS) + lp->type |= FLOOD_AS; + else + lp->type |= FLOOD_AREA; + ospf_mpls_te_lsa_schedule (lp, REORIGINATE_THIS_LSA); + } + } + } + else + { + vty_out (vty, "Please change Inter-AS support to disable first before going to mode %s%s", + mode2text[mode], VTY_NEWLINE); + return CMD_WARNING; + } } return CMD_SUCCESS; } -DEFUN (mpls_te_link_maxbw, - mpls_te_link_maxbw_cmd, - "mpls-te link max-bw BANDWIDTH", - "MPLS-TE specific commands\n" - "Configure MPLS-TE link parameters\n" - "Maximum bandwidth that can be used\n" - "Bytes/second (IEEE floating point format)\n") + +DEFUN (ospf_mpls_te_inter_as_as, + ospf_mpls_te_inter_as_cmd, + "mpls-te inter-as as", + MPLS_TE_STR + "Configure MPLS-TE Inter-AS support\n" + "AS native mode self originate INTER_AS LSA with Type 11 (as flooding scope)\n") { - struct interface *ifp = (struct interface *) vty->index; + return set_inter_as_mode (vty, "as", ""); +} + +DEFUN (ospf_mpls_te_inter_as_area, + ospf_mpls_te_inter_as_area_cmd, + "mpls-te inter-as area (A.B.C.D|<0-4294967295>)", + MPLS_TE_STR + "Configure MPLS-TE Inter-AS support\n" + "AREA native mode self originate INTER_AS LSA with Type 10 (area flooding scope)\n" + "OSPF area ID in IP format\n" + "OSPF area ID as decimal value\n") +{ + return set_inter_as_mode (vty, "area", argv[0]); +} + +DEFUN (no_ospf_mpls_te_inter_as, + no_ospf_mpls_te_inter_as_cmd, + "no mpls-te inter-as", + NO_STR + MPLS_TE_STR + "Disable MPLS-TE Inter-AS support\n") +{ + + struct listnode *node, *nnode; struct mpls_te_link *lp; - float f1, f2; - if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL) + if (IS_DEBUG_OSPF_EVENT) + zlog_debug ("MPLS-TE: Inter-AS support OFF"); + + if ((OspfMplsTE.status == enabled) && (OspfMplsTE.inter_as != Disable)) { - vty_out (vty, "mpls_te_link_maxbw: Something wrong!%s", VTY_NEWLINE); - return CMD_WARNING; + OspfMplsTE.inter_as = Disable; + /* Flush all Inter-AS LSA */ + for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp)) + if (IS_INTER_AS (lp->type) && CHECK_FLAG (lp->flags, LPFLG_LSA_ENGAGED)) + ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA); } - ntohf (&lp->max_bw.value, &f1); - if (sscanf (argv[0], "%g", &f2) != 1) - { - vty_out (vty, "mpls_te_link_maxbw: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE); - return CMD_WARNING; - } + /* Deregister the Callbacks for Inter-AS suport */ + ospf_mpls_te_unregister (); - if (ntohs (lp->max_bw.header.type) == 0 - || f1 != f2) - { - set_linkparams_max_bw (lp, &f2); - - if (OspfMplsTE.status == enabled) - if (lp->area != NULL) - { - if (lp->flags & LPFLG_LSA_ENGAGED) - ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); - else - ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); - } - } return CMD_SUCCESS; } -DEFUN (mpls_te_link_max_rsv_bw, - mpls_te_link_max_rsv_bw_cmd, - "mpls-te link max-rsv-bw BANDWIDTH", - "MPLS-TE specific commands\n" - "Configure MPLS-TE link parameters\n" - "Maximum bandwidth that may be reserved\n" - "Bytes/second (IEEE floating point format)\n") -{ - struct interface *ifp = (struct interface *) vty->index; - struct mpls_te_link *lp; - float f1, f2; - - if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL) - { - vty_out (vty, "mpls_te_link_max_rsv_bw: Something wrong!%s", VTY_NEWLINE); - return CMD_WARNING; - } - - ntohf (&lp->max_rsv_bw.value, &f1); - if (sscanf (argv[0], "%g", &f2) != 1) - { - vty_out (vty, "mpls_te_link_max_rsv_bw: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE); - return CMD_WARNING; - } - - if (ntohs (lp->max_rsv_bw.header.type) == 0 - || f1 != f2) - { - set_linkparams_max_rsv_bw (lp, &f2); - - if (OspfMplsTE.status == enabled) - if (lp->area != NULL) - { - if (lp->flags & LPFLG_LSA_ENGAGED) - ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); - else - ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); - } - } - return CMD_SUCCESS; -} - -DEFUN (mpls_te_link_unrsv_bw, - mpls_te_link_unrsv_bw_cmd, - "mpls-te link unrsv-bw <0-7> BANDWIDTH", - "MPLS-TE specific commands\n" - "Configure MPLS-TE link parameters\n" - "Unreserved bandwidth at each priority level\n" - "Priority\n" - "Bytes/second (IEEE floating point format)\n") -{ - struct interface *ifp = (struct interface *) vty->index; - struct mpls_te_link *lp; - int priority; - float f1, f2; - - if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL) - { - vty_out (vty, "mpls_te_link_unrsv_bw: Something wrong!%s", VTY_NEWLINE); - return CMD_WARNING; - } - - /* We don't have to consider about range check here. */ - if (sscanf (argv[0], "%d", &priority) != 1) - { - vty_out (vty, "mpls_te_link_unrsv_bw: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE); - return CMD_WARNING; - } - - ntohf (&lp->unrsv_bw.value [priority], &f1); - if (sscanf (argv[1], "%g", &f2) != 1) - { - vty_out (vty, "mpls_te_link_unrsv_bw: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE); - return CMD_WARNING; - } - - if (ntohs (lp->unrsv_bw.header.type) == 0 - || f1 != f2) - { - set_linkparams_unrsv_bw (lp, priority, &f2); - - if (OspfMplsTE.status == enabled) - if (lp->area != NULL) - { - if (lp->flags & LPFLG_LSA_ENGAGED) - ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); - else - ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); - } - } - return CMD_SUCCESS; -} - -DEFUN (mpls_te_link_rsc_clsclr, - mpls_te_link_rsc_clsclr_cmd, - "mpls-te link rsc-clsclr BITPATTERN", - "MPLS-TE specific commands\n" - "Configure MPLS-TE link parameters\n" - "Administrative group membership\n" - "32-bit Hexadecimal value (ex. 0xa1)\n") -{ - struct interface *ifp = (struct interface *) vty->index; - struct mpls_te_link *lp; - unsigned long value; - - if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL) - { - vty_out (vty, "mpls_te_link_rsc_clsclr: Something wrong!%s", VTY_NEWLINE); - return CMD_WARNING; - } - - if (sscanf (argv[0], "0x%lx", &value) != 1) - { - vty_out (vty, "mpls_te_link_rsc_clsclr: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE); - return CMD_WARNING; - } - - if (ntohs (lp->rsc_clsclr.header.type) == 0 - || ntohl (lp->rsc_clsclr.value) != value) - { - set_linkparams_rsc_clsclr (lp, value); - - if (OspfMplsTE.status == enabled) - if (lp->area != NULL) - { - if (lp->flags & LPFLG_LSA_ENGAGED) - ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); - else - ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); - } - } - return CMD_SUCCESS; -} - -DEFUN (show_mpls_te_router, - show_mpls_te_router_cmd, - "show mpls-te router", +DEFUN (show_ip_ospf_mpls_te_router, + show_ip_ospf_mpls_te_router_cmd, + "show ip ospf mpls-te router", SHOW_STR + IP_STR + OSPF_STR "MPLS-TE information\n" - "Router information\n") + "MPLS-TE Router parameters\n") { if (OspfMplsTE.status == enabled) { - vty_out (vty, "--- MPLS-TE router parameters ---%s", - VTY_NEWLINE); + vty_out (vty, "--- MPLS-TE router parameters ---%s", VTY_NEWLINE); if (ntohs (OspfMplsTE.router_addr.header.type) != 0) show_vty_router_addr (vty, &OspfMplsTE.router_addr.header); @@ -1844,29 +2535,73 @@ static void show_mpls_te_link_sub (struct vty *vty, struct interface *ifp) { struct mpls_te_link *lp; - struct te_tlv_header *tlvh; if ((OspfMplsTE.status == enabled) - && (! if_is_loopback (ifp) && if_is_up (ifp) && ospf_oi_count (ifp) > 0) - && ((lp = lookup_linkparams_by_ifp (ifp)) != NULL)) + && HAS_LINK_PARAMS(ifp) + && !if_is_loopback (ifp) + && if_is_up (ifp) + && ((lp = lookup_linkparams_by_ifp (ifp)) != NULL)) { + /* Continue only if interface is not passive or support Inter-AS TEv2 */ + if (!(ospf_oi_count (ifp) > 0)) + { + if (IS_INTER_AS (lp->type)) + { + vty_out (vty, "-- Inter-AS TEv2 link parameters for %s --%s", + ifp->name, VTY_NEWLINE); + } + else + { + /* MPLS-TE is not activate on this interface */ + /* or this interface is passive and Inter-AS TEv2 is not activate */ + vty_out (vty, " %s: MPLS-TE is disabled on this interface%s", + ifp->name, VTY_NEWLINE); + return; + } + } + else + { vty_out (vty, "-- MPLS-TE link parameters for %s --%s", ifp->name, VTY_NEWLINE); + } - show_vty_link_subtlv_link_type (vty, &lp->link_type.header); - show_vty_link_subtlv_link_id (vty, &lp->link_id.header); - - if ((tlvh = (struct te_tlv_header *) lp->lclif_ipaddr) != NULL) - show_vty_link_subtlv_lclif_ipaddr (vty, tlvh); - if ((tlvh = (struct te_tlv_header *) lp->rmtif_ipaddr) != NULL) - show_vty_link_subtlv_rmtif_ipaddr (vty, tlvh); - - show_vty_link_subtlv_te_metric (vty, &lp->te_metric.header); - - show_vty_link_subtlv_max_bw (vty, &lp->max_bw.header); - show_vty_link_subtlv_max_rsv_bw (vty, &lp->max_rsv_bw.header); - show_vty_link_subtlv_unrsv_bw (vty, &lp->unrsv_bw.header); - show_vty_link_subtlv_rsc_clsclr (vty, &lp->rsc_clsclr.header); + if (TLV_TYPE(lp->link_type) != 0) + show_vty_link_subtlv_link_type (vty, &lp->link_type.header); + if (TLV_TYPE(lp->link_id) != 0) + show_vty_link_subtlv_link_id (vty, &lp->link_id.header); + if (TLV_TYPE(lp->lclif_ipaddr) != 0) + show_vty_link_subtlv_lclif_ipaddr (vty, &lp->lclif_ipaddr.header); + if (TLV_TYPE(lp->rmtif_ipaddr) != 0) + show_vty_link_subtlv_rmtif_ipaddr (vty, &lp->rmtif_ipaddr.header); + if (TLV_TYPE(lp->rip) != 0) + show_vty_link_subtlv_rip (vty, &lp->rip.header); + if (TLV_TYPE(lp->ras) != 0) + show_vty_link_subtlv_ras (vty, &lp->ras.header); + if (TLV_TYPE(lp->te_metric) != 0) + show_vty_link_subtlv_te_metric (vty, &lp->te_metric.header); + if (TLV_TYPE(lp->max_bw) != 0) + show_vty_link_subtlv_max_bw (vty, &lp->max_bw.header); + if (TLV_TYPE(lp->max_rsv_bw) != 0) + show_vty_link_subtlv_max_rsv_bw (vty, &lp->max_rsv_bw.header); + if (TLV_TYPE(lp->unrsv_bw) != 0) + show_vty_link_subtlv_unrsv_bw (vty, &lp->unrsv_bw.header); + if (TLV_TYPE(lp->rsc_clsclr) != 0) + show_vty_link_subtlv_rsc_clsclr (vty, &lp->rsc_clsclr.header); + if (TLV_TYPE(lp->av_delay) != 0) + show_vty_link_subtlv_av_delay (vty, &lp->av_delay.header); + if (TLV_TYPE(lp->mm_delay) != 0) + show_vty_link_subtlv_mm_delay (vty, &lp->mm_delay.header); + if (TLV_TYPE(lp->delay_var) != 0) + show_vty_link_subtlv_delay_var (vty, &lp->delay_var.header); + if (TLV_TYPE(lp->pkt_loss) != 0) + show_vty_link_subtlv_pkt_loss (vty, &lp->pkt_loss.header); + if (TLV_TYPE(lp->res_bw) != 0) + show_vty_link_subtlv_res_bw (vty, &lp->res_bw.header); + if (TLV_TYPE(lp->ava_bw) != 0) + show_vty_link_subtlv_ava_bw (vty, &lp->ava_bw.header); + if (TLV_TYPE(lp->use_bw) != 0) + show_vty_link_subtlv_use_bw (vty, &lp->use_bw.header); + vty_out (vty, "---------------%s%s", VTY_NEWLINE, VTY_NEWLINE); } else { @@ -1877,10 +2612,12 @@ show_mpls_te_link_sub (struct vty *vty, struct interface *ifp) return; } -DEFUN (show_mpls_te_link, - show_mpls_te_link_cmd, - "show mpls-te interface [INTERFACE]", +DEFUN (show_ip_ospf_mpls_te_link, + show_ip_ospf_mpls_te_link_cmd, + "show ip ospf mpls-te interface [INTERFACE]", SHOW_STR + IP_STR + OSPF_STR "MPLS-TE information\n" "Interface information\n" "Interface name\n") @@ -1909,24 +2646,18 @@ DEFUN (show_mpls_te_link, static void ospf_mpls_te_register_vty (void) { - install_element (VIEW_NODE, &show_mpls_te_router_cmd); - install_element (VIEW_NODE, &show_mpls_te_link_cmd); - install_element (ENABLE_NODE, &show_mpls_te_router_cmd); - install_element (ENABLE_NODE, &show_mpls_te_link_cmd); + install_element (VIEW_NODE, &show_ip_ospf_mpls_te_router_cmd); + install_element (VIEW_NODE, &show_ip_ospf_mpls_te_link_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_mpls_te_router_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_mpls_te_link_cmd); - install_element (OSPF_NODE, &mpls_te_cmd); - install_element (OSPF_NODE, &no_mpls_te_cmd); - install_element (OSPF_NODE, &no_mpls_te_val_cmd); - install_element (OSPF_NODE, &mpls_te_on_cmd); - install_element (OSPF_NODE, &mpls_te_router_addr_cmd); - - install_element (INTERFACE_NODE, &mpls_te_link_metric_cmd); - install_element (INTERFACE_NODE, &mpls_te_link_maxbw_cmd); - install_element (INTERFACE_NODE, &mpls_te_link_max_rsv_bw_cmd); - install_element (INTERFACE_NODE, &mpls_te_link_unrsv_bw_cmd); - install_element (INTERFACE_NODE, &mpls_te_link_rsc_clsclr_cmd); + install_element (OSPF_NODE, &ospf_mpls_te_on_cmd); + install_element (OSPF_NODE, &no_ospf_mpls_te_cmd); + install_element (OSPF_NODE, &no_ospf_mpls_te_val_cmd); + install_element (OSPF_NODE, &ospf_mpls_te_router_addr_cmd); + install_element (OSPF_NODE, &ospf_mpls_te_inter_as_cmd); + install_element (OSPF_NODE, &ospf_mpls_te_inter_as_area_cmd); + install_element (OSPF_NODE, &no_ospf_mpls_te_inter_as_cmd); return; } - -#endif /* HAVE_OSPF_TE */ diff --git a/ospfd/ospf_te.h b/ospfd/ospf_te.h index 863d8ba8f2..8bb77c40c5 100644 --- a/ospfd/ospf_te.h +++ b/ospfd/ospf_te.h @@ -1,8 +1,11 @@ /* - * This is an implementation of draft-katz-yeung-ospf-traffic-06.txt + * This is an implementation of RFC3630, RFC5392 & RFC6827 * Copyright (C) 2001 KDD R&D Laboratories, Inc. * http://www.kddlabs.co.jp/ * + * Copyright (C) 2012 Orange Labs + * http://www.orange.com + * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it @@ -21,6 +24,10 @@ * 02111-1307, USA. */ +/* Add support of RFC7471 */ +/* Add support of RFC5392 */ +/* Add support of RFC6827 (partial) */ + #ifndef _ZEBRA_OSPF_MPLS_TE_H #define _ZEBRA_OSPF_MPLS_TE_H @@ -42,6 +49,7 @@ */ #define MAX_LEGAL_TE_INSTANCE_NUM (0xffff) +#define LEGAL_TE_INSTANCE_RANGE(i) (0 <= (i) && (i) <= 0xffff) /* * 24 16 8 0 @@ -62,6 +70,31 @@ * +--------+--------+--------+--------+ --- */ +/* Following define the type of TE link regarding the various RFC */ +#define STD_TE 0x01 +#define GMPLS 0x02 +#define INTER_AS 0x04 +#define PSEUDO_TE 0x08 +#define FLOOD_AREA 0x10 +#define FLOOD_AS 0x20 +#define EMULATED 0x80 + +#define IS_STD_TE(x) (x & STD_TE) +#define IS_PSEUDO_TE(x) (x & PSEUDO_TE) +#define IS_INTER_AS(x) (x & INTER_AS) +#define IS_EMULATED(x) (x & EMULATED) +#define IS_FLOOD_AREA(x) (x & FLOOD_AREA) +#define IS_FLOOD_AS(x) (x & FLOOD_AS) +#define IS_INTER_AS_EMU(x) (x & INTER_AS & EMULATED) +#define IS_INTER_AS_AS(x) (x & INTER_AS & FLOOD_AS) + +/* Flags to manage TE Link LSA */ +#define LPFLG_LSA_INACTIVE 0x0 +#define LPFLG_LSA_ACTIVE 0x1 +#define LPFLG_LSA_ENGAGED 0x2 +#define LPFLG_LOOKUP_DONE 0x4 +#define LPFLG_LSA_FORCED_REFRESH 0x8 + /* * Following section defines TLV (tag, length, value) structures, * used for Traffic Engineering. @@ -87,10 +120,18 @@ struct te_tlv_header #define TLV_HDR_NEXT(tlvh) \ (struct te_tlv_header *)((char *)(tlvh) + TLV_SIZE(tlvh)) +#define TLV_HDR_SUBTLV(tlvh) \ + (struct te_tlv_header *)((char *)(tlvh) + TLV_HDR_SIZE) + +#define TLV_TYPE(tlvh) tlvh.header.type +#define TLV_LEN(tlvh) tlvh.header.length +#define TLV_HDR(tlvh) tlvh.header + + /* * Following section defines TLV body parts. */ -/* Router Address TLV *//* Mandatory */ +/* Router Address TLV */ /* Mandatory */ #define TE_TLV_ROUTER_ADDR 1 struct te_tlv_router_addr { @@ -106,12 +147,16 @@ struct te_tlv_link /* A set of link-sub-TLVs will follow. */ }; -/* Link Type Sub-TLV *//* Mandatory */ -#define TE_LINK_SUBTLV_LINK_TYPE 1 +#define TE_LINK_SUBTLV_DEF_SIZE 4 + +/* Link Type Sub-TLV */ /* Mandatory */ +#define TE_LINK_SUBTLV_LINK_TYPE 1 +#define TE_LINK_SUBTLV_TYPE_SIZE 1 struct te_link_subtlv_link_type { struct te_tlv_header header; /* Value length is 1 octet. */ - struct { + struct + { #define LINK_TYPE_SUBTLV_VALUE_PTP 1 #define LINK_TYPE_SUBTLV_VALUE_MA 2 u_char value; @@ -119,75 +164,303 @@ struct te_link_subtlv_link_type } link_type; }; -/* Link Sub-TLV: Link ID *//* Mandatory */ -#define TE_LINK_SUBTLV_LINK_ID 2 +/* Link Sub-TLV: Link ID */ /* Mandatory */ +#define TE_LINK_SUBTLV_LINK_ID 2 struct te_link_subtlv_link_id { struct te_tlv_header header; /* Value length is 4 octets. */ struct in_addr value; /* Same as router-lsa's link-id. */ }; -/* Link Sub-TLV: Local Interface IP Address *//* Optional */ -#define TE_LINK_SUBTLV_LCLIF_IPADDR 3 +/* Link Sub-TLV: Local Interface IP Address */ /* Optional */ +#define TE_LINK_SUBTLV_LCLIF_IPADDR 3 struct te_link_subtlv_lclif_ipaddr { struct te_tlv_header header; /* Value length is 4 x N octets. */ struct in_addr value[1]; /* Local IP address(es). */ }; -/* Link Sub-TLV: Remote Interface IP Address *//* Optional */ -#define TE_LINK_SUBTLV_RMTIF_IPADDR 4 +/* Link Sub-TLV: Remote Interface IP Address */ /* Optional */ +#define TE_LINK_SUBTLV_RMTIF_IPADDR 4 struct te_link_subtlv_rmtif_ipaddr { struct te_tlv_header header; /* Value length is 4 x N octets. */ struct in_addr value[1]; /* Neighbor's IP address(es). */ }; -/* Link Sub-TLV: Traffic Engineering Metric *//* Optional */ -#define TE_LINK_SUBTLV_TE_METRIC 5 +/* Link Sub-TLV: Traffic Engineering Metric */ /* Optional */ +#define TE_LINK_SUBTLV_TE_METRIC 5 struct te_link_subtlv_te_metric { struct te_tlv_header header; /* Value length is 4 octets. */ u_int32_t value; /* Link metric for TE purpose. */ }; -/* Link Sub-TLV: Maximum Bandwidth *//* Optional */ -#define TE_LINK_SUBTLV_MAX_BW 6 +/* Link Sub-TLV: Maximum Bandwidth */ /* Optional */ +#define TE_LINK_SUBTLV_MAX_BW 6 struct te_link_subtlv_max_bw { struct te_tlv_header header; /* Value length is 4 octets. */ float value; /* bytes/sec */ }; -/* Link Sub-TLV: Maximum Reservable Bandwidth *//* Optional */ -#define TE_LINK_SUBTLV_MAX_RSV_BW 7 +/* Link Sub-TLV: Maximum Reservable Bandwidth */ /* Optional */ +#define TE_LINK_SUBTLV_MAX_RSV_BW 7 struct te_link_subtlv_max_rsv_bw { struct te_tlv_header header; /* Value length is 4 octets. */ float value; /* bytes/sec */ }; -/* Link Sub-TLV: Unreserved Bandwidth *//* Optional */ -#define TE_LINK_SUBTLV_UNRSV_BW 8 +/* Link Sub-TLV: Unreserved Bandwidth */ /* Optional */ +#define TE_LINK_SUBTLV_UNRSV_BW 8 +#define TE_LINK_SUBTLV_UNRSV_SIZE 32 struct te_link_subtlv_unrsv_bw { struct te_tlv_header header; /* Value length is 32 octets. */ - float value[8]; /* One for each priority level. */ + float value[MAX_CLASS_TYPE]; /* One for each priority level. */ }; -/* Link Sub-TLV: Resource Class/Color *//* Optional */ -#define TE_LINK_SUBTLV_RSC_CLSCLR 9 +/* Link Sub-TLV: Resource Class/Color */ /* Optional */ +#define TE_LINK_SUBTLV_RSC_CLSCLR 9 struct te_link_subtlv_rsc_clsclr { struct te_tlv_header header; /* Value length is 4 octets. */ u_int32_t value; /* Admin. group membership. */ }; -/* Here are "non-official" architechtual constants. */ +/* For RFC6827 */ +/* Local and Remote TE Router ID */ +#define TE_LINK_SUBTLV_LRRID 10 +#define TE_LINK_SUBTLV_LRRID_SIZE 8 +struct te_link_subtlv_lrrid +{ + struct te_tlv_header header; /* Value length is 8 octets. */ + struct in_addr local; /* Local TE Router Identifier */ + struct in_addr remote; /* Remote TE Router Identifier */ +}; + +/* RFC4203: Link Local/Remote Identifiers */ +#define TE_LINK_SUBTLV_LLRI 11 +#define TE_LINK_SUBTLV_LLRI_SIZE 8 +struct te_link_subtlv_llri +{ + struct te_tlv_header header; /* Value length is 8 octets. */ + u_int32_t local; /* Link Local Identifier */ + u_int32_t remote; /* Link Remote Identifier */ +}; + +/* Inter-RA Export Upward sub-TLV (12) and Inter-RA Export Downward sub-TLV (13) (RFC6827bis) are not yet supported */ +/* SUBTLV 14-16 (RFC4203) are not yet supported */ +/* Bandwidth Constraints sub-TLV (17) (RFC4124) is not yet supported */ +/* SUBLV 18-20 are for OSPFv6 TE (RFC5329). see ospf6d */ + +/* For RFC 5392 */ +/* Remote AS Number sub-TLV */ +#define TE_LINK_SUBTLV_RAS 21 +struct te_link_subtlv_ras +{ + struct te_tlv_header header; /* Value length is 4 octets. */ + u_int32_t value; /* Remote AS number */ +}; + +/* IPv4 Remote ASBR ID Sub-TLV */ +#define TE_LINK_SUBTLV_RIP 22 +struct te_link_subtlv_rip +{ + struct te_tlv_header header; /* Value length is 4 octets. */ + struct in_addr value; /* Remote ASBR IP address */ +}; + +/* SUBTLV 24 is IPv6 Remote ASBR ID (RFC5392). see ospf6d */ + +/* SUBTLV 23 (RFC5330) and 25 (RFC6001) are not yet supported */ + +/* SUBTLV 26 (RFC7308) is not yet supported */ + +/* RFC7471 */ +/* Link Sub-TLV: Average Link Delay */ /* Optional */ +#define TE_LINK_SUBTLV_AV_DELAY 27 +struct te_link_subtlv_av_delay +{ + struct te_tlv_header header; /* Value length is 4 bytes. */ + u_int32_t value; /* delay in micro-seconds only 24 bits => 0 ... 16777215 + with Anomalous Bit as Upper most bit */ +}; + +/* Link Sub-TLV: Low/High Link Delay */ +#define TE_LINK_SUBTLV_MM_DELAY 28 +#define TE_LINK_SUBTLV_MM_DELAY_SIZE 8 +struct te_link_subtlv_mm_delay +{ + struct te_tlv_header header; /* Value length is 8 bytes. */ + u_int32_t low; /* low delay in micro-seconds only 24 bits => 0 ... 16777215 + with Anomalous Bit (A) as Upper most bit */ + u_int32_t high; /* high delay in micro-seconds only 24 bits => 0 ... 16777215 */ +}; + +/* Link Sub-TLV: Link Delay Variation i.e. Jitter */ +#define TE_LINK_SUBTLV_DELAY_VAR 29 +struct te_link_subtlv_delay_var +{ + struct te_tlv_header header; /* Value length is 4 bytes. */ + u_int32_t value; /* interval in micro-seconds only 24 bits => 0 ... 16777215 */ +}; + +/* Link Sub-TLV: Routine Unidirectional Link Packet Loss */ +#define TE_LINK_SUBTLV_PKT_LOSS 30 +struct te_link_subtlv_pkt_loss +{ + struct te_tlv_header header; /* Value length is 4 bytes. */ + u_int32_t value; /* in percentage of total traffic only 24 bits (2^24 - 2) + with Anomalous Bit as Upper most bit */ +}; + +/* Link Sub-TLV: Unidirectional Residual Bandwidth */ /* Optional */ +#define TE_LINK_SUBTLV_RES_BW 31 +struct te_link_subtlv_res_bw +{ + struct te_tlv_header header; /* Value length is 4 bytes. */ + float value; /* bandwidth in IEEE floating point format with units in bytes per second */ +}; + +/* Link Sub-TLV: Unidirectional Available Bandwidth */ /* Optional */ +#define TE_LINK_SUBTLV_AVA_BW 32 +struct te_link_subtlv_ava_bw +{ + struct te_tlv_header header; /* Value length is 4 octets. */ + float value; /* bandwidth in IEEE floating point format with units in bytes per second */ +}; + +/* Link Sub-TLV: Unidirectional Utilized Bandwidth */ /* Optional */ +#define TE_LINK_SUBTLV_USE_BW 33 +struct te_link_subtlv_use_bw +{ + struct te_tlv_header header; /* Value length is 4 octets. */ + float value; /* bandwidth in IEEE floating point format with units in bytes per second */ +}; + +#define TE_LINK_SUBTLV_MAX 34 /* Last SUBTLV + 1 */ + +/* Here are "non-official" architectural constants. */ #define MPLS_TE_MINIMUM_BANDWIDTH 1.0 /* Reasonable? *//* XXX */ +/* Following declaration concerns the MPLS-TE and LINk-TE management */ +typedef enum _opcode_t +{ REORIGINATE_THIS_LSA, REFRESH_THIS_LSA, FLUSH_THIS_LSA } opcode_t; + +typedef enum _status_t +{ disabled, enabled } status_t; + +/* Mode for Inter-AS Opaque-LSA */ +enum inter_as_mode { Disable, AS, Area }; + +struct te_link_subtlv +{ + struct te_tlv_header header; + union + { + u_int32_t link_type; + struct in_addr link_id; + struct in_addr lclif; + struct in_addr rmtif; + u_int32_t te_metric; + float max_bw; + float max_rsv_bw; + float unrsv[8]; + u_int32_t rsc_clsclr; + u_int32_t llri[2]; + u_int32_t ras; + struct in_addr rip; + struct in_addr lrrid[2]; + u_int32_t av_delay; + u_int32_t mm_delay; + u_int32_t delay_var; + u_int32_t pkt_loss; + float res_bw; + float ava_bw; + float use_bw; + } value; +}; + +/* Following structure are internal use only. */ +struct ospf_mpls_te +{ + /* Status of MPLS-TE: enable or disbale */ + status_t status; + + /* RFC5392 */ + enum inter_as_mode inter_as; + struct in_addr interas_areaid; + + /* List elements are zebra-interfaces (ifp), not ospf-interfaces (oi). */ + struct list *iflist; + + /* Store Router-TLV in network byte order. */ + struct te_tlv_router_addr router_addr; +}; + +struct mpls_te_link +{ + /* + * According to MPLS-TE (draft) specification, 24-bit Opaque-ID field + * is subdivided into 8-bit "unused" field and 16-bit "instance" field. + * In this implementation, each Link-TLV has its own instance. + */ + u_int32_t instance; + + /* Reference pointer to a Zebra-interface. */ + struct interface *ifp; + + /* Area info in which this MPLS-TE link belongs to. */ + struct ospf_area *area; + + /* Flags to manage this link parameters. */ + u_int32_t flags; + + /* Type of MPLS-TE link: RFC3630, RFC5392, RFC5392 emulated, RFC6827 */ + u_int8_t type; + + /* Store Link-TLV in network byte order. */ + /* RFC3630 & RFC6827 / RFC 6827 */ + struct te_tlv_link link_header; + struct te_link_subtlv_link_type link_type; + struct te_link_subtlv_link_id link_id; + struct te_link_subtlv_lclif_ipaddr lclif_ipaddr; + struct te_link_subtlv_rmtif_ipaddr rmtif_ipaddr; + struct te_link_subtlv_te_metric te_metric; + struct te_link_subtlv_max_bw max_bw; + struct te_link_subtlv_max_rsv_bw max_rsv_bw; + struct te_link_subtlv_unrsv_bw unrsv_bw; + struct te_link_subtlv_rsc_clsclr rsc_clsclr; + /* RFC4203 */ + struct te_link_subtlv_llri llri; + /* RFC5392 */ + struct te_link_subtlv_ras ras; + struct te_link_subtlv_rip rip; + /* RFC6827 */ + struct te_link_subtlv_lrrid lrrid; + /* RFC7471 */ + struct te_link_subtlv_av_delay av_delay; + struct te_link_subtlv_mm_delay mm_delay; + struct te_link_subtlv_delay_var delay_var; + struct te_link_subtlv_pkt_loss pkt_loss; + struct te_link_subtlv_res_bw res_bw; + struct te_link_subtlv_ava_bw ava_bw; + struct te_link_subtlv_use_bw use_bw; + + struct in_addr adv_router; + struct in_addr id; +}; + /* Prototypes. */ extern int ospf_mpls_te_init (void); extern void ospf_mpls_te_term (void); +extern struct ospf_mpls_te *get_ospf_mpls_te (void); +extern void ospf_mpls_te_update_if (struct interface *); +extern void ospf_mpls_te_lsa_schedule (struct mpls_te_link *, opcode_t); +extern u_int32_t get_mpls_te_instance_value (void); +extern void set_linkparams_llri (struct mpls_te_link *, u_int32_t, u_int32_t); +extern void set_linkparams_lrrid (struct mpls_te_link *, struct in_addr, struct in_addr); #endif /* _ZEBRA_OSPF_MPLS_TE_H */ diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index beda0caa11..1b26c67866 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -64,7 +64,7 @@ static const char *ospf_network_type_str[] = }; /* Utility functions. */ -static int +int ospf_str2area_id (const char *str, struct in_addr *area_id, int *format) { char *endptr = NULL; @@ -271,43 +271,10 @@ DEFUN (no_ospf_router_id, struct ospf *ospf = vty->index; struct listnode *node; struct ospf_area *area; - struct in_addr id; - struct interface *ifp; - struct connected *ifc; - struct prefix *p; - int ret; if (!ospf) return CMD_SUCCESS; - if (argc == 1) - { - ret = inet_aton (argv[0], &id); - if (! ret) - { - ifp = if_lookup_by_name(argv[0]); - if (!ifp) { - vty_out (vty, "%% Malformed OSPF router identifier%s", VTY_NEWLINE); - return CMD_WARNING; - } - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) - { - p = ifc->address; - if (p && (p->family == AF_INET)) - { - id = p->u.prefix4; - break; - } - } - } - - if (! IPV4_ADDR_SAME (&ospf->router_id_static, &id)) - { - vty_out (vty, "%% OSPF router-id doesn't match%s", VTY_NEWLINE); - return CMD_WARNING; - } - } - ospf->router_id_static.s_addr = 0; for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) @@ -331,63 +298,6 @@ ALIAS (no_ospf_router_id, "router-id for the OSPF process\n" "OSPF router-id in IP address format\n") -DEFUN (ospf_router_id_interface, - ospf_router_id_interface_cmd, - "ospf router-id IFNAME", - "OSPF specific commands\n" - "router-id for the OSPF process\n" - "Interface name\n") -{ - struct ospf *ospf = vty->index; - struct listnode *node; - struct ospf_area *area; - struct interface *ifp; - struct connected *ifc; - struct prefix *p; - - if (!ospf) - return CMD_SUCCESS; - - p = NULL; - ifp = if_lookup_by_name(argv[0]); - if (!ifp) - { - vty_out (vty, "%% Couldnt find interface %s%s", argv[0], VTY_NEWLINE); - return CMD_WARNING; - } - - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) - { - p = ifc->address; - - if (p && (p->family == AF_INET)) - { - if (IPV4_ADDR_SAME (&ospf->router_id_static, &p->u.prefix4)) - return CMD_SUCCESS; - ospf->router_id_static = p->u.prefix4; - for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) - if (area->full_nbrs) - { - vty_out (vty, "For this router-id change to take effect," - " save config and restart ospfd%s", VTY_NEWLINE); - return CMD_SUCCESS; - } - ospf_router_id_update (ospf); - return CMD_SUCCESS; - } - } - vty_out (vty, "%% Couldnt assign the router-id%s", VTY_NEWLINE); - return CMD_WARNING; -} - -ALIAS (no_ospf_router_id, - no_ospf_router_id_interface_cmd, - "no ospf router-id IFNAME", - NO_STR - "OSPF specific commands\n" - "router-id for the OSPF process\n" - "Interface name\n") - static void ospf_passive_interface_default (struct ospf *ospf, u_char newval) { @@ -3355,7 +3265,6 @@ show_ip_ospf_area (struct vty *vty, struct ospf_area *area, json_object *json_ar ospf_lsdb_checksum (area->lsdb, OSPF_AS_NSSA_LSA), VTY_NEWLINE); } -#ifdef HAVE_OPAQUE_LSA if (use_json) { json_object_int_add(json_area, "lsaOpaqueLinkNumber", ospf_lsdb_count (area->lsdb, OSPF_OPAQUE_LINK_LSA)); @@ -3372,7 +3281,6 @@ show_ip_ospf_area (struct vty *vty, struct ospf_area *area, json_object *json_ar ospf_lsdb_count (area->lsdb, OSPF_OPAQUE_AREA_LSA), ospf_lsdb_checksum (area->lsdb, OSPF_OPAQUE_AREA_LSA), VTY_NEWLINE); } -#endif /* HAVE_OPAQUE_LSA */ if (use_json) json_object_object_add(json_areas, inet_ntoa (area->area_id), json_area); @@ -3456,7 +3364,6 @@ show_ip_ospf_common (struct vty *vty, struct ospf *ospf, u_char use_json) "enabled" : "disabled", VTY_NEWLINE); } -#ifdef HAVE_OPAQUE_LSA if (use_json) { if (CHECK_FLAG (ospf->config, OSPF_OPAQUE_CAPABLE)) @@ -3470,7 +3377,6 @@ show_ip_ospf_common (struct vty *vty, struct ospf *ospf, u_char use_json) CHECK_FLAG (ospf->config, OSPF_OPAQUE_CAPABLE) ? "enabled" : "disabled", VTY_NEWLINE); } -#endif /* HAVE_OPAQUE_LSA */ /* Show stub-router configuration */ if (ospf->stub_router_startup_time != OSPF_STUB_ROUTER_UNCONFIGURED @@ -3624,7 +3530,6 @@ show_ip_ospf_common (struct vty *vty, struct ospf *ospf, u_char use_json) ospf_lsdb_checksum (ospf->lsdb, OSPF_AS_EXTERNAL_LSA), VTY_NEWLINE); } -#ifdef HAVE_OPAQUE_LSA if (use_json) { json_object_int_add(json, "lsaAsopaqueCounter", @@ -3638,7 +3543,6 @@ show_ip_ospf_common (struct vty *vty, struct ospf *ospf, u_char use_json) ospf_lsdb_count (ospf->lsdb, OSPF_OPAQUE_AS_LSA), ospf_lsdb_checksum (ospf->lsdb, OSPF_OPAQUE_AS_LSA), VTY_NEWLINE); } -#endif /* HAVE_OPAQUE_LSA */ /* Show number of areas attached. */ if (use_json) @@ -3967,7 +3871,13 @@ show_ip_ospf_interface_sub (struct vty *vty, struct ospf *ospf, struct interface { struct timeval result; unsigned long time_store = 0; - result = tv_sub (oi->t_hello->u.sands, recent_relative_time()); + if (oi->t_hello) + result = tv_sub (oi->t_hello->u.sands, recent_relative_time()); + else + { + result.tv_sec = 0; + result.tv_usec = 0; + } time_store = (1000 * result.tv_sec) + (result.tv_usec / 1000); json_object_int_add(json_interface_sub, "timerHelloInMsecs", time_store); } @@ -4029,20 +3939,29 @@ show_ip_ospf_interface_common (struct vty *vty, struct ospf *ospf, int argc, if (ospf_oi_count(ifp)) { show_ip_ospf_interface_sub (vty, ospf, ifp, json_interface_sub, use_json); + if (use_json) + json_object_object_add (json, ifp->name, json_interface_sub); } } } else if (argv[iface_argv] && strcmp(argv[iface_argv], "json") == 0) { + if (!use_json) + { + json = json_object_new_object(); + json_interface_sub = json_object_new_object (); + use_json = 1; + } /* Show All Interfaces. */ for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp)) { if (ospf_oi_count(ifp)) { show_ip_ospf_interface_sub (vty, ospf, ifp, json_interface_sub, use_json); - json_object_object_add(json, ifp->name, json_interface_sub); - } - } + if (use_json) + json_object_object_add(json, ifp->name, json_interface_sub); + } + } } else { @@ -5185,11 +5104,9 @@ show_lsa_summary (struct vty *vty, struct ospf_lsa *lsa, int self) break; case OSPF_NETWORK_LSA: case OSPF_ASBR_SUMMARY_LSA: -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: -#endif /* HAVE_OPAQUE_LSA */ default: break; } @@ -5209,12 +5126,10 @@ static const char *show_database_desc[] = "AS External Link States", "Group Membership LSA", "NSSA-external Link States", -#ifdef HAVE_OPAQUE_LSA "Type-8 LSA", "Link-Local Opaque-LSA", "Area-Local Opaque-LSA", "AS-external Opaque-LSA", -#endif /* HAVE_OPAQUE_LSA */ }; static const char *show_database_header[] = @@ -5227,12 +5142,10 @@ static const char *show_database_header[] = "Link ID ADV Router Age Seq# CkSum Route", " --- header for Group Member ----", "Link ID ADV Router Age Seq# CkSum Route", -#ifdef HAVE_OPAQUE_LSA " --- type-8 ---", "Opaque-Type/Id ADV Router Age Seq# CkSum", "Opaque-Type/Id ADV Router Age Seq# CkSum", "Opaque-Type/Id ADV Router Age Seq# CkSum", -#endif /* HAVE_OPAQUE_LSA */ }; static void @@ -5504,7 +5417,6 @@ show_func_dummy (struct vty *vty, struct ospf_lsa *lsa) return 0; } -#ifdef HAVE_OPAQUE_LSA static int show_opaque_lsa_detail (struct vty *vty, struct ospf_lsa *lsa) { @@ -5517,7 +5429,6 @@ show_opaque_lsa_detail (struct vty *vty, struct ospf_lsa *lsa) } return 0; } -#endif /* HAVE_OPAQUE_LSA */ int (*show_function[])(struct vty *, struct ospf_lsa *) = { @@ -5529,12 +5440,10 @@ int (*show_function[])(struct vty *, struct ospf_lsa *) = show_as_external_lsa_detail, show_func_dummy, show_as_nssa_lsa_detail, /* almost same as external */ -#ifdef HAVE_OPAQUE_LSA NULL, /* type-8 */ show_opaque_lsa_detail, show_opaque_lsa_detail, show_opaque_lsa_detail, -#endif /* HAVE_OPAQUE_LSA */ }; static void @@ -5593,9 +5502,7 @@ show_lsa_detail (struct vty *vty, struct ospf *ospf, int type, switch (type) { case OSPF_AS_EXTERNAL_LSA: -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: -#endif /* HAVE_OPAQUE_LSA */ vty_out (vty, " %s %s%s", show_database_desc[type], VTY_NEWLINE, VTY_NEWLINE); @@ -5642,9 +5549,7 @@ show_lsa_detail_adv_router (struct vty *vty, struct ospf *ospf, int type, switch (type) { case OSPF_AS_EXTERNAL_LSA: -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: -#endif /* HAVE_OPAQUE_LSA */ vty_out (vty, " %s %s%s", show_database_desc[type], VTY_NEWLINE, VTY_NEWLINE); @@ -5680,9 +5585,7 @@ show_ip_ospf_database_summary (struct vty *vty, struct ospf *ospf, int self) switch (type) { case OSPF_AS_EXTERNAL_LSA: -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: -#endif /* HAVE_OPAQUE_LSA */ continue; default: break; @@ -5709,9 +5612,7 @@ show_ip_ospf_database_summary (struct vty *vty, struct ospf *ospf, int self) switch (type) { case OSPF_AS_EXTERNAL_LSA: -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: -#endif /* HAVE_OPAQUE_LSA */ break; default: continue; @@ -5763,17 +5664,10 @@ show_ip_ospf_database_maxage (struct vty *vty, struct ospf *ospf) #define OSPF_LSA_TYPE_NSSA_DESC "NSSA external link state\n" #define OSPF_LSA_TYPE_NSSA_CMD_STR "|nssa-external" -#ifdef HAVE_OPAQUE_LSA #define OSPF_LSA_TYPE_OPAQUE_LINK_DESC "Link local Opaque-LSA\n" #define OSPF_LSA_TYPE_OPAQUE_AREA_DESC "Link area Opaque-LSA\n" #define OSPF_LSA_TYPE_OPAQUE_AS_DESC "Link AS Opaque-LSA\n" #define OSPF_LSA_TYPE_OPAQUE_CMD_STR "|opaque-link|opaque-area|opaque-as" -#else /* HAVE_OPAQUE_LSA */ -#define OSPF_LSA_TYPE_OPAQUE_LINK_DESC "" -#define OSPF_LSA_TYPE_OPAQUE_AREA_DESC "" -#define OSPF_LSA_TYPE_OPAQUE_AS_DESC "" -#define OSPF_LSA_TYPE_OPAQUE_CMD_STR "" -#endif /* HAVE_OPAQUE_LSA */ #define OSPF_LSA_TYPES_CMD_STR \ "asbr-summary|external|network|router|summary" \ @@ -5835,14 +5729,12 @@ show_ip_ospf_database_common (struct vty *vty, struct ospf *ospf, show_ip_ospf_database_maxage (vty, ospf); return CMD_SUCCESS; } -#ifdef HAVE_OPAQUE_LSA else if (strncmp (argv[arg_base + 0], "opaque-l", 8) == 0) type = OSPF_OPAQUE_LINK_LSA; else if (strncmp (argv[arg_base + 0], "opaque-ar", 9) == 0) type = OSPF_OPAQUE_AREA_LSA; else if (strncmp (argv[arg_base + 0], "opaque-as", 9) == 0) type = OSPF_OPAQUE_AS_LSA; -#endif /* HAVE_OPAQUE_LSA */ else return CMD_WARNING; @@ -6037,14 +5929,12 @@ show_ip_ospf_database_type_adv_router_common (struct vty *vty, struct ospf *ospf type = OSPF_ASBR_SUMMARY_LSA; else if (strncmp (argv[arg_base + 0], "e", 1) == 0) type = OSPF_AS_EXTERNAL_LSA; -#ifdef HAVE_OPAQUE_LSA else if (strncmp (argv[arg_base + 0], "opaque-l", 8) == 0) type = OSPF_OPAQUE_LINK_LSA; else if (strncmp (argv[arg_base + 0], "opaque-ar", 9) == 0) type = OSPF_OPAQUE_AREA_LSA; else if (strncmp (argv[arg_base + 0], "opaque-as", 9) == 0) type = OSPF_OPAQUE_AS_LSA; -#endif /* HAVE_OPAQUE_LSA */ else return CMD_WARNING; @@ -9579,9 +9469,7 @@ config_write_interface (struct vty *vty) } } while (rn); -#ifdef HAVE_OPAQUE_LSA ospf_opaque_config_write_if (vty, ifp); -#endif /* HAVE_OPAQUE_LSA */ } return write; @@ -10077,9 +9965,7 @@ ospf_config_write (struct vty *vty) /* Distance configuration. */ config_write_ospf_distance (vty, ospf); -#ifdef HAVE_OPAQUE_LSA ospf_opaque_config_write_router (vty, ospf); -#endif /* HAVE_OPAQUE_LSA */ } return write; @@ -10421,10 +10307,8 @@ ospf_vty_init (void) /* "ospf router-id" commands. */ install_element (OSPF_NODE, &ospf_router_id_cmd); install_element (OSPF_NODE, &ospf_router_id_old_cmd); - install_element (OSPF_NODE, &ospf_router_id_interface_cmd); install_element (OSPF_NODE, &no_ospf_router_id_cmd); install_element (OSPF_NODE, &no_ospf_router_id_val_cmd); - install_element (OSPF_NODE, &no_ospf_router_id_interface_cmd); /* "passive-interface" commands. */ install_element (OSPF_NODE, &ospf_passive_interface_addr_cmd); diff --git a/ospfd/ospf_vty.h b/ospfd/ospf_vty.h index 28bb419af8..429ac318f7 100644 --- a/ospfd/ospf_vty.h +++ b/ospfd/ospf_vty.h @@ -54,5 +54,6 @@ extern void ospf_vty_init (void); extern void ospf_vty_show_init (void); extern void ospf_vty_clear_init (void); +extern int ospf_str2area_id (const char *, struct in_addr *, int *); #endif /* _QUAGGA_OSPF_VTY_H */ diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index c7bf38eb68..c0b94a3360 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -34,6 +34,8 @@ #include "filter.h" #include "plist.h" #include "log.h" +#include "lib/bfd.h" +#include "nexthop.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" @@ -51,6 +53,7 @@ #ifdef HAVE_SNMP #include "ospfd/ospf_snmp.h" #endif /* HAVE_SNMP */ +#include "ospfd/ospf_te.h" /* Zebra structure to hold current status. */ struct zclient *zclient = NULL; @@ -329,6 +332,24 @@ ospf_interface_address_delete (int command, struct zclient *zclient, return 0; } +static int +ospf_interface_link_params (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct interface *ifp; + + ifp = zebra_interface_link_params_read (zclient->ibuf); + + if (ifp == NULL) + return 0; + + /* Update TE TLV */ + ospf_mpls_te_update_if (ifp); + + return 0; +} + + void ospf_zebra_add (struct prefix_ipv4 *p, struct ospf_route *or) { @@ -392,18 +413,18 @@ ospf_zebra_add (struct prefix_ipv4 *p, struct ospf_route *or) (path->nexthop.s_addr != INADDR_ANY && path->ifindex != 0)) { - stream_putc (s, ZEBRA_NEXTHOP_IPV4_IFINDEX); + stream_putc (s, NEXTHOP_TYPE_IPV4_IFINDEX); stream_put_in_addr (s, &path->nexthop); stream_putl (s, path->ifindex); } else if (path->nexthop.s_addr != INADDR_ANY) { - stream_putc (s, ZEBRA_NEXTHOP_IPV4); + stream_putc (s, NEXTHOP_TYPE_IPV4); stream_put_in_addr (s, &path->nexthop); } else { - stream_putc (s, ZEBRA_NEXTHOP_IFINDEX); + stream_putc (s, NEXTHOP_TYPE_IFINDEX); if (path->ifindex) stream_putl (s, path->ifindex); else @@ -413,18 +434,18 @@ ospf_zebra_add (struct prefix_ipv4 *p, struct ospf_route *or) if (path->nexthop.s_addr != INADDR_ANY && path->ifindex != 0) { - stream_putc (s, ZEBRA_NEXTHOP_IPV4_IFINDEX); + stream_putc (s, NEXTHOP_TYPE_IPV4_IFINDEX); stream_put_in_addr (s, &path->nexthop); stream_putl (s, path->ifindex); } else if (path->nexthop.s_addr != INADDR_ANY) { - stream_putc (s, ZEBRA_NEXTHOP_IPV4); + stream_putc (s, NEXTHOP_TYPE_IPV4); stream_put_in_addr (s, &path->nexthop); } else { - stream_putc (s, ZEBRA_NEXTHOP_IFINDEX); + stream_putc (s, NEXTHOP_TYPE_IFINDEX); if (path->ifindex) stream_putl (s, path->ifindex); else @@ -513,18 +534,18 @@ ospf_zebra_delete (struct prefix_ipv4 *p, struct ospf_route *or) if (path->nexthop.s_addr != INADDR_ANY && path->ifindex != 0) { - stream_putc (s, ZEBRA_NEXTHOP_IPV4_IFINDEX); + stream_putc (s, NEXTHOP_TYPE_IPV4_IFINDEX); stream_put_in_addr (s, &path->nexthop); stream_putl (s, path->ifindex); } else if (path->nexthop.s_addr != INADDR_ANY) { - stream_putc (s, ZEBRA_NEXTHOP_IPV4); + stream_putc (s, NEXTHOP_TYPE_IPV4); stream_put_in_addr (s, &path->nexthop); } else { - stream_putc (s, ZEBRA_NEXTHOP_IFINDEX); + stream_putc (s, NEXTHOP_TYPE_IFINDEX); stream_putl (s, path->ifindex); } @@ -1558,6 +1579,9 @@ ospf_distance_apply (struct prefix_ipv4 *p, struct ospf_route *or) static void ospf_zebra_connected (struct zclient *zclient) { + /* Send the client registration */ + bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER); + zclient_send_reg_requests (zclient, VRF_DEFAULT); } @@ -1575,6 +1599,8 @@ ospf_zebra_init (struct thread_master *master, u_short instance) zclient->interface_down = ospf_interface_state_down; zclient->interface_address_add = ospf_interface_address_add; zclient->interface_address_delete = ospf_interface_address_delete; + zclient->interface_link_params = ospf_interface_link_params; + zclient->ipv4_route_add = ospf_zebra_read_ipv4; zclient->ipv4_route_delete = ospf_zebra_read_ipv4; zclient->redistribute_route_ipv4_add = ospf_zebra_read_ipv4; diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index ea66042f2e..7156c1edac 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -124,7 +124,7 @@ ospf_router_id_update (struct ospf *ospf) * oi->nbr_self->router_id = router_id for * !(virtual | ptop) links */ - ospf_nbr_self_reset (oi); + ospf_nbr_self_reset (oi, router_id); } /* If AS-external-LSA is queued, then flush those LSAs. */ @@ -272,7 +272,7 @@ ospf_new (u_short instance) new->lsa_refresh_interval = OSPF_LSA_REFRESH_INTERVAL_DEFAULT; new->t_lsa_refresher = thread_add_timer (master, ospf_lsa_refresh_walker, new, new->lsa_refresh_interval); - new->lsa_refresher_started = quagga_time (NULL); + new->lsa_refresher_started = quagga_monotime (); if ((new->fd = ospf_sock_init()) < 0) { @@ -305,7 +305,7 @@ ospf_lookup () if (listcount (om->ospf) == 0) return NULL; - return listgetdata (listhead (om->ospf)); + return listgetdata ((struct listnode *)listhead (om->ospf)); } struct ospf * @@ -351,9 +351,7 @@ ospf_get () if (ospf->router_id_static.s_addr == 0) ospf_router_id_update (ospf); -#ifdef HAVE_OPAQUE_LSA ospf_opaque_type11_lsa_init (ospf); -#endif /* HAVE_OPAQUE_LSA */ } return ospf; @@ -373,9 +371,7 @@ ospf_get_instance (u_short instance) if (ospf->router_id_static.s_addr == 0) ospf_router_id_update (ospf); -#ifdef HAVE_OPAQUE_LSA ospf_opaque_type11_lsa_init (ospf); -#endif /* HAVE_OPAQUE_LSA */ } return ospf; @@ -513,9 +509,7 @@ ospf_finish_final (struct ospf *ospf) int i; u_short instance = 0; -#ifdef HAVE_OPAQUE_LSA ospf_opaque_type11_lsa_term (ospf); -#endif /* HAVE_OPAQUE_LSA */ /* be nice if this worked, but it doesn't */ /*ospf_flush_self_originated_lsas_now (ospf);*/ @@ -611,17 +605,13 @@ ospf_finish_final (struct ospf *ospf) OSPF_TIMER_OFF (ospf->t_lsa_refresher); OSPF_TIMER_OFF (ospf->t_read); OSPF_TIMER_OFF (ospf->t_write); -#ifdef HAVE_OPAQUE_LSA OSPF_TIMER_OFF (ospf->t_opaque_lsa_self); -#endif close (ospf->fd); stream_free(ospf->ibuf); -#ifdef HAVE_OPAQUE_LSA LSDB_LOOP (OPAQUE_AS_LSDB (ospf), rn, lsa) ospf_discard_from_db (ospf, ospf->lsdb, lsa); -#endif /* HAVE_OPAQUE_LSA */ LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa) ospf_discard_from_db (ospf, ospf->lsdb, lsa); @@ -733,9 +723,7 @@ ospf_area_new (struct ospf *ospf, struct in_addr area_id) /* Self-originated LSAs initialize. */ new->router_lsa_self = NULL; -#ifdef HAVE_OPAQUE_LSA ospf_opaque_type10_lsa_init (new); -#endif /* HAVE_OPAQUE_LSA */ new->oiflist = list_new (); new->ranges = route_table_init (); @@ -764,12 +752,10 @@ ospf_area_free (struct ospf_area *area) LSDB_LOOP (NSSA_LSDB (area), rn, lsa) ospf_discard_from_db (area->ospf, area->lsdb, lsa); -#ifdef HAVE_OPAQUE_LSA LSDB_LOOP (OPAQUE_AREA_LSDB (area), rn, lsa) ospf_discard_from_db (area->ospf, area->lsdb, lsa); LSDB_LOOP (OPAQUE_LINK_LSDB (area), rn, lsa) ospf_discard_from_db (area->ospf, area->lsdb, lsa); -#endif /* HAVE_OPAQUE_LSA */ ospf_lsdb_delete_all (area->lsdb); ospf_lsdb_free (area->lsdb); @@ -787,9 +773,7 @@ ospf_area_free (struct ospf_area *area) /* Cancel timer. */ OSPF_TIMER_OFF (area->t_stub_router); -#ifdef HAVE_OPAQUE_LSA OSPF_TIMER_OFF (area->t_opaque_lsa_self); -#endif /* HAVE_OPAQUE_LSA */ if (OSPF_IS_AREA_BACKBONE (area)) area->ospf->backbone = NULL; @@ -888,7 +872,7 @@ add_ospf_interface (struct interface *ifp, struct ospf_area *area, oi->type = IF_DEF_PARAMS (ifp)->type; /* Add pseudo neighbor. */ - ospf_nbr_self_reset (oi); + ospf_nbr_self_reset (oi, oi->ospf->router_id); ospf_area_add_if (oi->area, oi); @@ -1160,7 +1144,7 @@ ospf_network_run_interface (struct prefix *p, struct ospf_area *area, oi->output_cost = ospf_if_get_output_cost (oi); /* Add pseudo neighbor. */ - ospf_nbr_add_self (oi); + ospf_nbr_add_self (oi, oi->ospf->router_id); /* Relate ospf interface to ospf instance. */ oi->ospf = area->ospf; @@ -1598,7 +1582,7 @@ ospf_timers_refresh_set (struct ospf *ospf, int interval) return 1; time_left = ospf->lsa_refresh_interval - - (quagga_time (NULL) - ospf->lsa_refresher_started); + (quagga_monotime () - ospf->lsa_refresher_started); if (time_left > interval) { @@ -1617,7 +1601,7 @@ ospf_timers_refresh_unset (struct ospf *ospf) int time_left; time_left = ospf->lsa_refresh_interval - - (quagga_time (NULL) - ospf->lsa_refresher_started); + (quagga_monotime () - ospf->lsa_refresher_started); if (time_left > OSPF_LSA_REFRESH_INTERVAL_DEFAULT) { @@ -1939,5 +1923,4 @@ ospf_master_init () om = &ospf_master; om->ospf = list_new (); om->master = thread_master_create (); - om->start_time = quagga_time (NULL); } diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h index 95809306d6..af238c53ae 100644 --- a/ospfd/ospfd.h +++ b/ospfd/ospfd.h @@ -59,13 +59,14 @@ #define OSPF_AUTH_CMD_NOTSEEN -2 /* OSPF options. */ -#define OSPF_OPTION_T 0x01 /* TOS. */ +#define OSPF_OPTION_MT 0x01 /* M/T */ #define OSPF_OPTION_E 0x02 #define OSPF_OPTION_MC 0x04 #define OSPF_OPTION_NP 0x08 #define OSPF_OPTION_EA 0x10 #define OSPF_OPTION_DC 0x20 #define OSPF_OPTION_O 0x40 +#define OSPF_OPTION_DN 0x80 /* OSPF Database Description flags. */ #define OSPF_DD_FLAG_MS 0x01 @@ -98,9 +99,6 @@ struct ospf_master struct list *external[ZEBRA_ROUTE_MAX + 1]; #define EXTERNAL_INFO(E) (E->external_info) - /* OSPF start time. */ - time_t start_time; - /* Various OSPF global configuration. */ u_char options; #define OSPF_MASTER_SHUTDOWN (1 << 0) /* deferred-shutdown */ @@ -165,11 +163,9 @@ struct ospf #define OSPF_LOG_ADJACENCY_CHANGES (1 << 3) #define OSPF_LOG_ADJACENCY_DETAIL (1 << 4) -#ifdef HAVE_OPAQUE_LSA /* Opaque-LSA administrative flags. */ u_char opaque; #define OPAQUE_OPERATION_READY_BIT (1 << 0) -#endif /* HAVE_OPAQUE_LSA */ /* RFC3137 stub router. Configured time to stay stub / max-metric */ unsigned int stub_router_startup_time; /* seconds */ @@ -212,9 +208,7 @@ struct ospf int external_origin; /* AS-external-LSA origin flag. */ int ase_calc; /* ASE calculation flag. */ -#ifdef HAVE_OPAQUE_LSA struct list *opaque_lsa_self; /* Type-11 Opaque-LSAs */ -#endif /* HAVE_OPAQUE_LSA */ /* Routing tables. */ struct route_table *old_table; /* Old routing table. */ @@ -243,9 +237,7 @@ struct ospf struct thread *t_spf_calc; /* SPF calculation timer. */ struct thread *t_ase_calc; /* ASE calculation timer. */ struct thread *t_external_lsa; /* AS-external-LSA origin timer. */ -#ifdef HAVE_OPAQUE_LSA struct thread *t_opaque_lsa_self; /* Type-11 Opaque-LSAs origin event. */ -#endif /* HAVE_OPAQUE_LSA */ unsigned int maxage_delay; /* Delay on Maxage remover timer, sec */ struct thread *t_maxage; /* MaxAge LSA remover timer. */ @@ -368,9 +360,7 @@ struct ospf_area /* Self-originated LSAs. */ struct ospf_lsa *router_lsa_self; -#ifdef HAVE_OPAQUE_LSA struct list *opaque_lsa_self; /* Type-10 Opaque-LSAs */ -#endif /* HAVE_OPAQUE_LSA */ /* Area announce list. */ struct @@ -412,9 +402,7 @@ struct ospf_area /* Threads. */ struct thread *t_stub_router; /* Stub-router timer */ -#ifdef HAVE_OPAQUE_LSA struct thread *t_opaque_lsa_self; /* Type-10 Opaque-LSAs origin. */ -#endif /* HAVE_OPAQUE_LSA */ /* Statistics field. */ u_int32_t spf_calculation; /* SPF Calculation Count. */ diff --git a/pimd/Makefile.am b/pimd/Makefile.am index 115d73678d..d578c97363 100644 --- a/pimd/Makefile.am +++ b/pimd/Makefile.am @@ -43,7 +43,7 @@ AM_CFLAGS = $(WERROR) noinst_LIBRARIES = libpim.a sbin_PROGRAMS = pimd -bin_PROGRAMS = test_igmpv3_join +noinst_PROGRAMS = test_igmpv3_join libpim_a_SOURCES = \ pimd.c pim_version.c pim_cmd.c pim_signals.c pim_iface.c \ @@ -52,7 +52,7 @@ libpim_a_SOURCES = \ pim_oil.c pim_zlookup.c pim_pim.c pim_tlv.c pim_neighbor.c \ pim_hello.c pim_ifchannel.c pim_join.c pim_assert.c \ pim_msg.c pim_upstream.c pim_rpf.c pim_macro.c \ - pim_igmp_join.c pim_ssmpingd.c pim_int.c pim_rp.c \ + pim_ssmpingd.c pim_int.c pim_rp.c \ pim_static.c pim_br.c pim_register.c pim_routemap.c noinst_HEADERS = \ @@ -69,7 +69,7 @@ pimd_SOURCES = \ pim_main.c $(libpim_a_SOURCES) test_igmpv3_join_SOURCES = \ - test_igmpv3_join.c pim_igmp_join.c + test_igmpv3_join.c pimd_LDADD = ../lib/libzebra.la @LIBCAP@ test_igmpv3_join_LDADD = ../lib/libzebra.la diff --git a/pimd/pim_assert.c b/pimd/pim_assert.c index 9f9c9e66f0..d3df6a1102 100644 --- a/pimd/pim_assert.c +++ b/pimd/pim_assert.c @@ -258,9 +258,7 @@ int pim_assert_recv(struct interface *ifp, /* Parse assert group addr */ - offset = pim_parse_addr_group(ifp->name, src_addr, - &msg_group_addr, - curr, curr_size); + offset = pim_parse_addr_group (&msg_group_addr, curr, curr_size); if (offset < 1) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); @@ -275,9 +273,7 @@ int pim_assert_recv(struct interface *ifp, /* Parse assert source addr */ - offset = pim_parse_addr_ucast(ifp->name, src_addr, - &msg_source_addr, - curr, curr_size); + offset = pim_parse_addr_ucast (&msg_source_addr, curr, curr_size); if (offset < 1) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 68446572eb..6cfed0f2c6 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -22,14 +22,13 @@ #include -#include - #include "command.h" #include "if.h" #include "prefix.h" #include "zclient.h" #include "pimd.h" +#include "pim_mroute.h" #include "pim_cmd.h" #include "pim_iface.h" #include "pim_vty.h" @@ -1599,7 +1598,7 @@ static void mroute_add_all() struct channel_oil *c_oil; for (ALL_LIST_ELEMENTS_RO(qpim_channel_oil_list, node, c_oil)) { - if (pim_mroute_add(&c_oil->oil)) { + if (pim_mroute_add(c_oil)) { /* just log warning */ char source_str[100]; char group_str[100]; @@ -1618,7 +1617,7 @@ static void mroute_del_all() struct channel_oil *c_oil; for (ALL_LIST_ELEMENTS_RO(qpim_channel_oil_list, node, c_oil)) { - if (pim_mroute_del(&c_oil->oil)) { + if (pim_mroute_del(c_oil)) { /* just log warning */ char source_str[100]; char group_str[100]; @@ -1637,12 +1636,12 @@ static void static_mroute_add_all() struct static_route *s_route; for (ALL_LIST_ELEMENTS_RO(qpim_static_route_list, node, s_route)) { - if (pim_mroute_add(&s_route->mc)) { + if (pim_mroute_add(&s_route->c_oil)) { /* just log warning */ char source_str[100]; char group_str[100]; - pim_inet4_dump("", s_route->mc.mfcc_origin, source_str, sizeof(source_str)); - pim_inet4_dump("", s_route->mc.mfcc_mcastgrp, group_str, sizeof(group_str)); + pim_inet4_dump("", s_route->c_oil.oil.mfcc_origin, source_str, sizeof(source_str)); + pim_inet4_dump("", s_route->c_oil.oil.mfcc_mcastgrp, group_str, sizeof(group_str)); zlog_warn("%s %s: (S,G)=(%s,%s) failure writing MFC", __FILE__, __PRETTY_FUNCTION__, source_str, group_str); @@ -1656,12 +1655,12 @@ static void static_mroute_del_all() struct static_route *s_route; for (ALL_LIST_ELEMENTS_RO(qpim_static_route_list, node, s_route)) { - if (pim_mroute_del(&s_route->mc)) { + if (pim_mroute_del(&s_route->c_oil)) { /* just log warning */ char source_str[100]; char group_str[100]; - pim_inet4_dump("", s_route->mc.mfcc_origin, source_str, sizeof(source_str)); - pim_inet4_dump("", s_route->mc.mfcc_mcastgrp, group_str, sizeof(group_str)); + pim_inet4_dump("", s_route->c_oil.oil.mfcc_origin, source_str, sizeof(source_str)); + pim_inet4_dump("", s_route->c_oil.oil.mfcc_mcastgrp, group_str, sizeof(group_str)); zlog_warn("%s %s: (S,G)=(%s,%s) failure clearing MFC", __FILE__, __PRETTY_FUNCTION__, source_str, group_str); @@ -2088,10 +2087,10 @@ static void show_multicast_interfaces(struct vty *vty) inet_ntoa(ifaddr), ifp->ifindex, pim_ifp->mroute_vif_index, - vreq.icount, - vreq.ocount, - vreq.ibytes, - vreq.obytes, + (unsigned long) vreq.icount, + (unsigned long) vreq.ocount, + (unsigned long) vreq.ibytes, + (unsigned long) vreq.obytes, VTY_NEWLINE); } } @@ -2189,6 +2188,9 @@ static void show_mroute(struct vty *vty) char source_str[100]; int oif_vif_index; + if (!c_oil->installed) + continue; + pim_inet4_dump("", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("", c_oil->oil.mfcc_origin, source_str, sizeof(source_str)); @@ -2239,6 +2241,9 @@ static void show_mroute(struct vty *vty) char source_str[100]; int oif_vif_index; + if (!s_route->c_oil.installed) + continue; + pim_inet4_dump("", s_route->group, group_str, sizeof(group_str)); pim_inet4_dump("", s_route->source, source_str, sizeof(source_str)); @@ -2256,7 +2261,7 @@ static void show_mroute(struct vty *vty) ifp_in = pim_if_find_by_vif_index(s_route->iif); ifp_out = pim_if_find_by_vif_index(oif_vif_index); - pim_time_uptime(oif_uptime, sizeof(oif_uptime), now - s_route->creation[oif_vif_index]); + pim_time_uptime(oif_uptime, sizeof(oif_uptime), now - s_route->c_oil.oif_creation[oif_vif_index]); proto[0] = '\0'; strcat(proto, "S"); @@ -2302,34 +2307,21 @@ static void show_mroute_count(struct vty *vty) for (ALL_LIST_ELEMENTS_RO(qpim_channel_oil_list, node, c_oil)) { char group_str[100]; char source_str[100]; - struct sioc_sg_req sgreq; - memset(&sgreq, 0, sizeof(sgreq)); - sgreq.src = c_oil->oil.mfcc_origin; - sgreq.grp = c_oil->oil.mfcc_mcastgrp; + if (!c_oil->installed) + continue; + + pim_mroute_update_counters (c_oil); pim_inet4_dump("", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("", c_oil->oil.mfcc_origin, source_str, sizeof(source_str)); - if (ioctl(qpim_mroute_socket_fd, SIOCGETSGCNT, &sgreq)) { - int e = errno; - vty_out(vty, - "ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=(%s,%s): errno=%d: %s%s", - (unsigned long)SIOCGETSGCNT, - source_str, - group_str, - e, - safe_strerror(e), - VTY_NEWLINE); - continue; - } - vty_out(vty, "%-15s %-15s %7ld %10ld %7ld %s", source_str, group_str, - sgreq.pktcnt, - sgreq.bytecnt, - sgreq.wrong_if, + c_oil->cc.pktcnt, + c_oil->cc.bytecnt, + c_oil->cc.wrong_if, VTY_NEWLINE); } @@ -2337,37 +2329,21 @@ static void show_mroute_count(struct vty *vty) for (ALL_LIST_ELEMENTS_RO(qpim_static_route_list, node, s_route)) { char group_str[100]; char source_str[100]; - struct sioc_sg_req sgreq; - memset(&sgreq, 0, sizeof(sgreq)); - sgreq.src = s_route->mc.mfcc_origin; - sgreq.grp = s_route->mc.mfcc_mcastgrp; - - pim_inet4_dump("", s_route->mc.mfcc_mcastgrp, group_str, sizeof(group_str)); - pim_inet4_dump("", s_route->mc.mfcc_origin, source_str, sizeof(source_str)); - - if (ioctl(qpim_mroute_socket_fd, SIOCGETSGCNT, &sgreq)) { - int e = errno; - vty_out(vty, - "ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=(%s,%s): errno=%d: %s%s", - /* note that typeof ioctl defs can vary across platforms, from - * int, to unsigned int, to long unsigned int - */ - (unsigned long)SIOCGETSGCNT, - source_str, - group_str, - e, - safe_strerror(e), - VTY_NEWLINE); + if (!s_route->c_oil.installed) continue; - } + + pim_mroute_update_counters (&s_route->c_oil); + + pim_inet4_dump("", s_route->c_oil.oil.mfcc_mcastgrp, group_str, sizeof(group_str)); + pim_inet4_dump("", s_route->c_oil.oil.mfcc_origin, source_str, sizeof(source_str)); vty_out(vty, "%-15s %-15s %7ld %10ld %7ld %s", source_str, group_str, - sgreq.pktcnt, - sgreq.bytecnt, - sgreq.wrong_if, + s_route->c_oil.cc.pktcnt, + s_route->c_oil.cc.bytecnt, + s_route->c_oil.cc.wrong_if, VTY_NEWLINE); } } @@ -2486,9 +2462,9 @@ DEFUN (ip_pim_rp, ip_pim_rp_cmd, "ip pim rp A.B.C.D", IP_STR - "pim multicast routing" - "Rendevous Point" - "ip address of RP") + "pim multicast routing\n" + "Rendevous Point\n" + "ip address of RP\n") { int result; @@ -2511,9 +2487,9 @@ DEFUN (no_ip_pim_rp, "no ip pim rp {A.B.C.D}", NO_STR IP_STR - "pim multicast routing" - "Rendevous Point" - "ip address of RP") + "pim multicast routing\n" + "Rendevous Point\n" + "ip address of RP\n") { qpim_rp.rpf_addr.s_addr = INADDR_NONE; diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index 1dfbd9990a..a8a1d08805 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -632,7 +632,7 @@ int pim_if_add_vif(struct interface *ifp) { struct pim_interface *pim_ifp = ifp->info; struct in_addr ifaddr; - unsigned char flags; + unsigned char flags = 0; zassert(pim_ifp); @@ -668,8 +668,13 @@ int pim_if_add_vif(struct interface *ifp) return -3; } - flags = (ifp->ifindex == PIM_OIF_PIM_REGISTER_VIF) ? - VIFF_REGISTER : VIFF_USE_IFINDEX; + if (ifp->ifindex == PIM_OIF_PIM_REGISTER_VIF) + flags = VIFF_REGISTER; +#ifdef VIFF_USE_IFINDEX + else + flags = VIFF_USE_IFINDEX; +#endif + if (pim_mroute_add_vif(ifp, ifaddr, flags)) { /* pim_mroute_add_vif reported error */ return -5; @@ -767,7 +772,7 @@ void pim_if_del_vif_all() } } -struct interface *pim_if_find_by_vif_index(int vif_index) +struct interface *pim_if_find_by_vif_index(ifindex_t vif_index) { struct listnode *ifnode; struct interface *ifp; @@ -779,6 +784,7 @@ struct interface *pim_if_find_by_vif_index(int vif_index) if (ifp->info) { struct pim_interface *pim_ifp; pim_ifp = ifp->info; + if (vif_index == pim_ifp->mroute_vif_index) return ifp; } @@ -790,7 +796,7 @@ struct interface *pim_if_find_by_vif_index(int vif_index) /* pim_if_add_vif() uses ifindex as vif_index */ -int pim_if_find_vifindex_by_ifindex(int ifindex) +int pim_if_find_vifindex_by_ifindex(ifindex_t ifindex) { struct pim_interface *pim_ifp; struct interface *ifp; @@ -949,7 +955,7 @@ static struct igmp_join *igmp_join_find(struct list *join_list, } static int igmp_join_sock(const char *ifname, - int ifindex, + ifindex_t ifindex, struct in_addr group_addr, struct in_addr source_addr) { diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h index 15489f81fa..790afabea1 100644 --- a/pimd/pim_iface.h +++ b/pimd/pim_iface.h @@ -63,7 +63,7 @@ enum pim_interface_type { struct pim_interface { enum pim_interface_type itype; uint32_t options; /* bit vector */ - int mroute_vif_index; + ifindex_t mroute_vif_index; struct in_addr primary_address; /* remember addr to detect change */ int igmp_default_robustness_variable; /* IGMPv3 QRV */ @@ -133,8 +133,8 @@ int pim_if_del_vif(struct interface *ifp); void pim_if_add_vif_all(void); void pim_if_del_vif_all(void); -struct interface *pim_if_find_by_vif_index(int vif_index); -int pim_if_find_vifindex_by_ifindex(int ifindex); +struct interface *pim_if_find_by_vif_index(ifindex_t vif_index); +int pim_if_find_vifindex_by_ifindex(ifindex_t ifindex); int pim_if_lan_delay_enabled(struct interface *ifp); uint16_t pim_if_effective_propagation_delay_msec(struct interface *ifp); diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c index 6df835e252..3b63b10e0d 100644 --- a/pimd/pim_igmp.c +++ b/pimd/pim_igmp.c @@ -46,10 +46,7 @@ static void group_timer_off(struct igmp_group *group); -static struct igmp_group *find_group_by_addr(struct igmp_sock *igmp, - struct in_addr group_addr); - -static int igmp_sock_open(struct in_addr ifaddr, int ifindex, uint32_t pim_options) +static int igmp_sock_open(struct in_addr ifaddr, ifindex_t ifindex, uint32_t pim_options) { int fd; int join = 0; @@ -974,7 +971,7 @@ static int pim_igmp_read(struct thread *t) socklen_t tolen = sizeof(to); uint8_t buf[PIM_IGMP_BUFSIZE_READ]; int len; - int ifindex = -1; + ifindex_t ifindex = -1; int result = -1; /* defaults to bad */ zassert(t); @@ -1012,7 +1009,7 @@ static int pim_igmp_read(struct thread *t) #ifdef PIM_CHECK_RECV_IFINDEX_SANITY /* ifindex sanity check */ - if (ifindex != (int) igmp->interface->ifindex) { + if (ifindex != igmp->interface->ifindex) { char from_str[100]; char to_str[100]; struct interface *ifp; @@ -1024,7 +1021,7 @@ static int pim_igmp_read(struct thread *t) ifp = if_lookup_by_index(ifindex); if (ifp) { - zassert(ifindex == (int) ifp->ifindex); + zassert(ifindex == ifp->ifindex); } #ifdef PIM_REPORT_RECV_IFINDEX_MISMATCH @@ -1358,8 +1355,9 @@ void igmp_group_timer_on(struct igmp_group *group, group, interval_msec); } -static struct igmp_group *find_group_by_addr(struct igmp_sock *igmp, - struct in_addr group_addr) +struct igmp_group * +find_group_by_addr (struct igmp_sock *igmp, + struct in_addr group_addr) { struct igmp_group *group; struct listnode *node; diff --git a/pimd/pim_igmp.h b/pimd/pim_igmp.h index ab396159e3..c6685c2837 100644 --- a/pimd/pim_igmp.h +++ b/pimd/pim_igmp.h @@ -162,6 +162,8 @@ struct igmp_group { int64_t last_igmp_v2_report_dsec; }; +struct igmp_group *find_group_by_addr (struct igmp_sock *igmp, + struct in_addr group_addr); struct igmp_group *igmp_add_group_by_addr(struct igmp_sock *igmp, struct in_addr group_addr); diff --git a/pimd/pim_igmp_join.c b/pimd/pim_igmp_join.c deleted file mode 100644 index 62e32c6014..0000000000 --- a/pimd/pim_igmp_join.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - PIM for Quagga - Copyright (C) 2008 Everton da Silva Marques - - This program 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 of the License, or - (at your option) any later version. - - This program 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 this program; see the file COPYING; if not, write to the - Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, - MA 02110-1301 USA - - $QuaggaId: $Format:%an, %ai, %h$ $ -*/ - -#include - -#include -#include -#include - -#include "pim_igmp_join.h" - -#ifndef SOL_IP -#define SOL_IP IPPROTO_IP -#endif - -#ifndef MCAST_JOIN_SOURCE_GROUP -#define MCAST_JOIN_SOURCE_GROUP 46 -struct group_source_req -{ - uint32_t gsr_interface; - struct sockaddr_storage gsr_group; - struct sockaddr_storage gsr_source; -}; -#endif - -int pim_igmp_join_source(int fd, int ifindex, - struct in_addr group_addr, - struct in_addr source_addr) -{ - struct group_source_req req; - struct sockaddr_in group; - struct sockaddr_in source; - - memset(&group, 0, sizeof(group)); - group.sin_family = AF_INET; - group.sin_addr = group_addr; - group.sin_port = htons(0); - memcpy(&req.gsr_group, &group, sizeof(struct sockaddr_in)); - - memset(&source, 0, sizeof(source)); - source.sin_family = AF_INET; - source.sin_addr = source_addr; - source.sin_port = htons(0); - memcpy(&req.gsr_source, &source, sizeof(struct sockaddr_in)); - - req.gsr_interface = ifindex; - - return setsockopt(fd, SOL_IP, MCAST_JOIN_SOURCE_GROUP, - &req, sizeof(req)); - - return 0; -} diff --git a/pimd/pim_igmp_join.h b/pimd/pim_igmp_join.h index 1127af1202..1700276de8 100644 --- a/pimd/pim_igmp_join.h +++ b/pimd/pim_igmp_join.h @@ -23,10 +23,48 @@ #ifndef PIM_IGMP_JOIN_H #define PIM_IGMP_JOIN_H -#include +/* required headers #include'd by caller */ -int pim_igmp_join_source(int fd, int ifindex, - struct in_addr group_addr, - struct in_addr source_addr); +#ifndef SOL_IP +#define SOL_IP IPPROTO_IP +#endif + +#ifndef MCAST_JOIN_SOURCE_GROUP +#define MCAST_JOIN_SOURCE_GROUP 46 +struct group_source_req +{ + uint32_t gsr_interface; + struct sockaddr_storage gsr_group; + struct sockaddr_storage gsr_source; +}; +#endif + +static int pim_igmp_join_source(int fd, ifindex_t ifindex, + struct in_addr group_addr, + struct in_addr source_addr) +{ + struct group_source_req req; + struct sockaddr_in group; + struct sockaddr_in source; + + memset(&group, 0, sizeof(group)); + group.sin_family = AF_INET; + group.sin_addr = group_addr; + group.sin_port = htons(0); + memcpy(&req.gsr_group, &group, sizeof(struct sockaddr_in)); + + memset(&source, 0, sizeof(source)); + source.sin_family = AF_INET; + source.sin_addr = source_addr; + source.sin_port = htons(0); + memcpy(&req.gsr_source, &source, sizeof(struct sockaddr_in)); + + req.gsr_interface = ifindex; + + return setsockopt(fd, SOL_IP, MCAST_JOIN_SOURCE_GROUP, + &req, sizeof(req)); + + return 0; +} #endif /* PIM_IGMP_JOIN_H */ diff --git a/pimd/pim_igmpv3.c b/pimd/pim_igmpv3.c index 0a6b6b3795..7300e6c6b4 100644 --- a/pimd/pim_igmpv3.c +++ b/pimd/pim_igmpv3.c @@ -834,11 +834,26 @@ void igmpv3_report_toin(struct igmp_sock *igmp, struct in_addr from, on_trace(__PRETTY_FUNCTION__, ifp, from, group_addr, num_sources, sources); - /* non-existant group is created as INCLUDE {empty} */ - group = igmp_add_group_by_addr(igmp, group_addr); - if (!group) { - return; - } + /* + * If the requested filter mode is INCLUDE *and* the requested source + * list is empty, then the entry corresponding to the requested + * interface and multicast address is deleted if present. If no such + * entry is present, the request is ignored. + */ + if (num_sources) + { + /* non-existant group is created as INCLUDE {empty} */ + group = igmp_add_group_by_addr(igmp, group_addr); + if (!group) { + return; + } + } + else + { + group = find_group_by_addr (igmp, group_addr); + if (!group) + return; + } if (group->group_filtermode_isexcl) { /* EXCLUDE mode */ diff --git a/pimd/pim_join.c b/pimd/pim_join.c index f3b5e78ada..3852b423f0 100644 --- a/pimd/pim_join.c +++ b/pimd/pim_join.c @@ -127,14 +127,8 @@ int pim_joinprune_recv(struct interface *ifp, /* Parse ucast addr */ - addr_offset = pim_parse_addr_ucast(ifp->name, src_addr, - &msg_upstream_addr, - buf, pastend - buf); -#if 0 - zlog_warn("%s: pim_parse_addr_ucast addr_offset=%d", - __PRETTY_FUNCTION__, - addr_offset); -#endif + addr_offset = pim_parse_addr_ucast (&msg_upstream_addr, + buf, pastend - buf); if (addr_offset < 1) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); @@ -197,14 +191,8 @@ int pim_joinprune_recv(struct interface *ifp, uint16_t msg_num_pruned_sources; int source; - addr_offset = pim_parse_addr_group(ifp->name, src_addr, - &msg_group_addr, - buf, pastend - buf); -#if 0 - zlog_warn("%s: pim_parse_addr_group addr_offset=%d", - __PRETTY_FUNCTION__, - addr_offset); -#endif + addr_offset = pim_parse_addr_group (&msg_group_addr, + buf, pastend - buf); if (addr_offset < 1) { return -5; } @@ -243,15 +231,9 @@ int pim_joinprune_recv(struct interface *ifp, /* Scan joined sources */ for (source = 0; source < msg_num_joined_sources; ++source) { - addr_offset = pim_parse_addr_source(ifp->name, src_addr, - &msg_source_addr, - &msg_source_flags, - buf, pastend - buf); -#if 0 - zlog_warn("%s: pim_parse_addr_source addr_offset=%d", - __PRETTY_FUNCTION__, - addr_offset); -#endif + addr_offset = pim_parse_addr_source (&msg_source_addr, + &msg_source_flags, + buf, pastend - buf); if (addr_offset < 1) { return -7; } @@ -267,10 +249,9 @@ int pim_joinprune_recv(struct interface *ifp, /* Scan pruned sources */ for (source = 0; source < msg_num_pruned_sources; ++source) { - addr_offset = pim_parse_addr_source(ifp->name, src_addr, - &msg_source_addr, - &msg_source_flags, - buf, pastend - buf); + addr_offset = pim_parse_addr_source (&msg_source_addr, + &msg_source_flags, + buf, pastend - buf); if (addr_offset < 1) { return -8; } diff --git a/pimd/pim_main.c b/pimd/pim_main.c index b28b3d6242..b65b925fad 100644 --- a/pimd/pim_main.c +++ b/pimd/pim_main.c @@ -138,7 +138,9 @@ int main(int argc, char** argv, char** envp) { zlog_default = openzlog(progname, ZLOG_PIM, 0, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); zprivs_init (&pimd_privs); - zlog_set_file (NULL, LOG_DEFAULT_FILENAME, zlog_default->default_lvl); +#if defined(HAVE_CUMULUS) + zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl); +#endif /* this while just reads the options */ while (1) { diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index 8048d4b3c7..56f49d62f5 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -143,6 +143,8 @@ pim_mroute_msg_nocache (int fd, struct interface *ifp, const struct igmpmsg *msg return 0; } + pim_upstream_keep_alive_timer_start (up, PIM_KEEPALIVE_PERIOD); + up->channel_oil = pim_channel_oil_add(msg->im_dst, msg->im_src, pim_ifp->mroute_vif_index); @@ -154,6 +156,7 @@ pim_mroute_msg_nocache (int fd, struct interface *ifp, const struct igmpmsg *msg } return 0; } + up->channel_oil->cc.pktcnt++; pim_channel_add_oif(up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_SOURCE); @@ -312,7 +315,6 @@ int pim_mroute_msg(int fd, const char *buf, int buf_size) pim_inet4_dump("", ip_hdr->ip_dst, grp_str, sizeof(grp_str)); zlog_debug("%s: not a kernel upcall proto=%d src: %s dst: %s msg_size=%d", __PRETTY_FUNCTION__, ip_hdr->ip_p, src_str, grp_str, buf_size); - //zlog_hexdump(buf, buf_size); } return 0; } @@ -344,7 +346,6 @@ int pim_mroute_msg(int fd, const char *buf, int buf_size) return pim_mroute_msg_nocache(fd, ifp, msg, src_str, grp_str); break; case IGMPMSG_WHOLEPKT: - zlog_hexdump(buf, buf_size); return pim_mroute_msg_wholepkt(fd, ifp, (const char *)msg, src_str, grp_str); break; default: @@ -500,7 +501,16 @@ int pim_mroute_add_vif(struct interface *ifp, struct in_addr ifaddr, unsigned ch memset(&vc, 0, sizeof(vc)); vc.vifc_vifi = pim_ifp->mroute_vif_index; +#ifdef VIFF_USE_IFINDEX vc.vifc_lcl_ifindex = ifp->ifindex; +#else + if (ifaddr.s_addr == INADDR_ANY) { + zlog_warn("%s: unnumbered interfaces are not supported on this platform", + __PRETTY_FUNCTION__); + return -1; + } + memcpy(&vc.vifc_lcl_addr, &ifaddr, sizeof(vc.vifc_lcl_addr)); +#endif vc.vifc_flags = flags; vc.vifc_threshold = PIM_MROUTE_MIN_TTL; vc.vifc_rate_limit = 0; @@ -557,7 +567,7 @@ int pim_mroute_del_vif(int vif_index) return 0; } -int pim_mroute_add(struct mfcctl *mc) +int pim_mroute_add(struct channel_oil *c_oil) { int err; int orig = 0; @@ -575,17 +585,17 @@ int pim_mroute_add(struct mfcctl *mc) * vif to be part of the outgoing list * in the case of a (*,G). */ - if (mc->mfcc_origin.s_addr == INADDR_ANY) + if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY) { - orig = mc->mfcc_ttls[mc->mfcc_parent]; - mc->mfcc_ttls[mc->mfcc_parent] = 1; + orig = c_oil->oil.mfcc_ttls[c_oil->oil.mfcc_parent]; + c_oil->oil.mfcc_ttls[c_oil->oil.mfcc_parent] = 1; } err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_ADD_MFC, - mc, sizeof(*mc)); + &c_oil->oil, sizeof(c_oil->oil)); - if (mc->mfcc_origin.s_addr == INADDR_ANY) - mc->mfcc_ttls[mc->mfcc_parent] = orig; + if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY) + c_oil->oil.mfcc_ttls[c_oil->oil.mfcc_parent] = orig; if (err) { int e = errno; @@ -597,10 +607,11 @@ int pim_mroute_add(struct mfcctl *mc) return -2; } + c_oil->installed = 1; return 0; } -int pim_mroute_del(struct mfcctl *mc) +int pim_mroute_del (struct channel_oil *c_oil) { int err; @@ -613,7 +624,7 @@ int pim_mroute_del(struct mfcctl *mc) return -1; } - err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_DEL_MFC, mc, sizeof(*mc)); + err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_DEL_MFC, &c_oil->oil, sizeof(c_oil->oil)); if (err) { int e = errno; zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_MFC): errno=%d: %s", @@ -624,5 +635,44 @@ int pim_mroute_del(struct mfcctl *mc) return -2; } + c_oil->installed = 0; + return 0; } + +void +pim_mroute_update_counters (struct channel_oil *c_oil) +{ + struct sioc_sg_req sgreq; + + memset (&sgreq, 0, sizeof(sgreq)); + sgreq.src = c_oil->oil.mfcc_origin; + sgreq.grp = c_oil->oil.mfcc_mcastgrp; + + c_oil->cc.oldpktcnt = c_oil->cc.pktcnt; + c_oil->cc.oldbytecnt = c_oil->cc.bytecnt; + c_oil->cc.oldwrong_if = c_oil->cc.wrong_if; + + if (ioctl (qpim_mroute_socket_fd, SIOCGETSGCNT, &sgreq)) + { + char group_str[100]; + char source_str[100]; + + pim_inet4_dump("", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); + pim_inet4_dump("", c_oil->oil.mfcc_origin, source_str, sizeof(source_str)); + + zlog_warn ("ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=(%s,%s): errno=%d: %s", + (unsigned long)SIOCGETSGCNT, + source_str, + group_str, + errno, + safe_strerror(errno)); + return; + } + + c_oil->cc.pktcnt = sgreq.pktcnt; + c_oil->cc.bytecnt = sgreq.bytecnt; + c_oil->cc.wrong_if = sgreq.wrong_if; + + return; +} diff --git a/pimd/pim_mroute.h b/pimd/pim_mroute.h index c1ce012e2d..176fb81cbc 100644 --- a/pimd/pim_mroute.h +++ b/pimd/pim_mroute.h @@ -169,9 +169,10 @@ int pim_mroute_socket_disable(void); int pim_mroute_add_vif(struct interface *ifp, struct in_addr ifaddr, unsigned char flags); int pim_mroute_del_vif(int vif_index); -int pim_mroute_add(struct mfcctl *mc); -int pim_mroute_del(struct mfcctl *mc); +int pim_mroute_add(struct channel_oil *c_oil); +int pim_mroute_del(struct channel_oil *c_oil); int pim_mroute_msg(int fd, const char *buf, int buf_size); +void pim_mroute_update_counters (struct channel_oil *c_oil); #endif /* PIM_MROUTE_H */ diff --git a/pimd/pim_oil.c b/pimd/pim_oil.c index 8755818c0f..96f9ef2b62 100644 --- a/pimd/pim_oil.c +++ b/pimd/pim_oil.c @@ -79,6 +79,7 @@ static struct channel_oil *channel_oil_new(struct in_addr group_addr, c_oil->oil.mfcc_origin = source_addr; c_oil->oil.mfcc_parent = input_vif_index; c_oil->oil_ref_count = 1; + c_oil->installed = 0; zassert(c_oil->oil_size == 0); @@ -253,7 +254,7 @@ int pim_channel_add_oif(struct channel_oil *channel_oil, channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = PIM_MROUTE_MIN_TTL; - if (pim_mroute_add(&channel_oil->oil)) { + if (pim_mroute_add(channel_oil)) { if (PIM_DEBUG_MROUTE) { char group_str[100]; diff --git a/pimd/pim_oil.h b/pimd/pim_oil.h index f0a14a9baa..c63c026c0f 100644 --- a/pimd/pim_oil.h +++ b/pimd/pim_oil.h @@ -50,6 +50,17 @@ #define PIM_OIF_PIM_REGISTER_VIF (MAXVIFS - 1) #define PIM_MAX_USABLE_VIFS (MAXVIFS - 2) + +struct channel_counts +{ + unsigned long pktcnt; + unsigned long oldpktcnt; + unsigned long bytecnt; + unsigned long oldbytecnt; + unsigned long wrong_if; + unsigned long oldwrong_if; +}; + /* qpim_channel_oil_list holds a list of struct channel_oil. @@ -59,10 +70,12 @@ struct channel_oil { struct mfcctl oil; + int installed; int oil_size; int oil_ref_count; time_t oif_creation[MAXVIFS]; uint32_t oif_flags[MAXVIFS]; + struct channel_counts cc; }; void pim_channel_oil_free(struct channel_oil *c_oil); diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index eedbc116d8..0dfd39cd16 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -278,7 +278,7 @@ static int pim_sock_read(struct thread *t) socklen_t tolen = sizeof(to); uint8_t buf[PIM_PIM_BUFSIZE_READ]; int len; - int ifindex = -1; + ifindex_t ifindex = -1; int result = -1; /* defaults to bad */ zassert(t); @@ -386,7 +386,7 @@ static void pim_sock_read_on(struct interface *ifp) pim_ifp->pim_sock_fd); } -static int pim_sock_open(struct in_addr ifaddr, int ifindex) +static int pim_sock_open(struct in_addr ifaddr, ifindex_t ifindex) { int fd; diff --git a/pimd/pim_register.h b/pimd/pim_register.h index 7f3cdea3a2..039c0006e0 100644 --- a/pimd/pim_register.h +++ b/pimd/pim_register.h @@ -29,6 +29,7 @@ #define PIM_REGISTER_NR_BIT 0x40000000 #define PIM_MSG_REGISTER_LEN (8) +#define PIM_MSG_REGISTER_STOP_LEN (4) void pim_register_send_test_packet_start (struct in_addr source, struct in_addr group, diff --git a/pimd/pim_routemap.c b/pimd/pim_routemap.c index ced7c87484..adfd4fd2c3 100644 --- a/pimd/pim_routemap.c +++ b/pimd/pim_routemap.c @@ -26,9 +26,56 @@ #include "pimd.h" + +static void +pim_route_map_mark_update (const char *rmap_name) +{ + // placeholder + return; +} + +static void +pim_route_map_add (const char *rmap_name) +{ + if (route_map_mark_updated(rmap_name, 0) == 0) + pim_route_map_mark_update(rmap_name); + + route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED); +} + +static void +pim_route_map_delete (const char *rmap_name) +{ + if (route_map_mark_updated(rmap_name, 1) == 0) + pim_route_map_mark_update(rmap_name); + + route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_DELETED); +} + +static void +pim_route_map_event (route_map_event_t event, const char *rmap_name) +{ + if (route_map_mark_updated(rmap_name, 0) == 0) + pim_route_map_mark_update(rmap_name); + + route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED); +} + void pim_route_map_init (void) { route_map_init (); route_map_init_vty (); + route_map_add_hook (pim_route_map_add); + route_map_delete_hook (pim_route_map_delete); + route_map_event_hook (pim_route_map_event); +} + +void +pim_route_map_terminate (void) +{ + route_map_add_hook (NULL); + route_map_delete_hook (NULL); + route_map_event_hook (NULL); + route_map_finish(); } diff --git a/pimd/pim_sock.c b/pimd/pim_sock.c index a2e166f796..a024e3ae01 100644 --- a/pimd/pim_sock.c +++ b/pimd/pim_sock.c @@ -79,6 +79,7 @@ int pim_socket_mcast(int protocol, struct in_addr ifaddr, int ifindex, int loop) return PIM_SOCK_ERR_SOCKET; } +#ifdef SO_BINDTODEVICE if (protocol == IPPROTO_PIM) { int ret; @@ -104,7 +105,10 @@ int pim_socket_mcast(int protocol, struct in_addr ifaddr, int ifindex, int loop) return PIM_SOCK_ERR_BIND; } } - +#else + /* XXX: use IP_PKTINFO / IP_RECVIF to emulate behaviour? Or change to + * only use 1 socket for all interfaces? */ +#endif /* Needed to obtain destination address from recvmsg() */ { @@ -209,7 +213,7 @@ int pim_socket_mcast(int protocol, struct in_addr ifaddr, int ifindex, int loop) } int pim_socket_join(int fd, struct in_addr group, - struct in_addr ifaddr, int ifindex) + struct in_addr ifaddr, ifindex_t ifindex) { int ret; @@ -257,7 +261,7 @@ int pim_socket_join(int fd, struct in_addr group, return ret; } -int pim_socket_join_source(int fd, int ifindex, +int pim_socket_join_source(int fd, ifindex_t ifindex, struct in_addr group_addr, struct in_addr source_addr, const char *ifname) @@ -281,7 +285,7 @@ int pim_socket_join_source(int fd, int ifindex, int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len, struct sockaddr_in *from, socklen_t *fromlen, struct sockaddr_in *to, socklen_t *tolen, - int *ifindex) + ifindex_t *ifindex) { struct msghdr msgh; struct cmsghdr *cmsg; diff --git a/pimd/pim_sock.h b/pimd/pim_sock.h index 9a9b64a4a3..f0a1600818 100644 --- a/pimd/pim_sock.h +++ b/pimd/pim_sock.h @@ -41,15 +41,15 @@ int pim_socket_raw(int protocol); int pim_socket_mcast(int protocol, struct in_addr ifaddr, int ifindex, int loop); int pim_socket_join(int fd, struct in_addr group, - struct in_addr ifaddr, int ifindex); -int pim_socket_join_source(int fd, int ifindex, + struct in_addr ifaddr, ifindex_t ifindex); +int pim_socket_join_source(int fd, ifindex_t ifindex, struct in_addr group_addr, struct in_addr source_addr, const char *ifname); int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len, struct sockaddr_in *from, socklen_t *fromlen, struct sockaddr_in *to, socklen_t *tolen, - int *ifindex); + ifindex_t *ifindex); int pim_socket_mcastloop_get(int fd); diff --git a/pimd/pim_ssmpingd.c b/pimd/pim_ssmpingd.c index d564bf57bc..fe88eba271 100644 --- a/pimd/pim_ssmpingd.c +++ b/pimd/pim_ssmpingd.c @@ -250,7 +250,7 @@ static int ssmpingd_read_msg(struct ssmpingd_sock *ss) struct sockaddr_in to; socklen_t fromlen = sizeof(from); socklen_t tolen = sizeof(to); - int ifindex = -1; + ifindex_t ifindex = -1; uint8_t buf[1000]; int len; diff --git a/pimd/pim_static.c b/pimd/pim_static.c index 47a34daf48..c1154dc088 100644 --- a/pimd/pim_static.c +++ b/pimd/pim_static.c @@ -24,16 +24,17 @@ #include "vty.h" #include "if.h" - -#include "pim_static.h" -#include "pim_time.h" -#include "pim_str.h" -#include "pimd.h" -#include "pim_iface.h" #include "log.h" #include "memory.h" #include "linklist.h" +#include "pimd.h" +#include "pim_oil.h" +#include "pim_static.h" +#include "pim_time.h" +#include "pim_str.h" +#include "pim_iface.h" + void pim_static_route_free(struct static_route *s_route) { XFREE(MTYPE_PIM_STATIC_ROUTE, s_route); @@ -66,12 +67,12 @@ static struct static_route *static_route_new(unsigned int iif, s_route->source = source; s_route->iif = iif; s_route->oif_ttls[oif] = 1; - s_route->oif_count = 1; - s_route->mc.mfcc_origin = source; - s_route->mc.mfcc_mcastgrp = group; - s_route->mc.mfcc_parent = iif; - s_route->mc.mfcc_ttls[oif] = 1; - s_route->creation[oif] = pim_time_monotonic_sec(); + s_route->c_oil.oil_ref_count = 1; + s_route->c_oil.oil.mfcc_origin = source; + s_route->c_oil.oil.mfcc_mcastgrp = group; + s_route->c_oil.oil.mfcc_parent = iif; + s_route->c_oil.oil.mfcc_ttls[oif] = 1; + s_route->c_oil.oif_creation[oif] = pim_time_monotonic_sec(); return s_route; } @@ -84,8 +85,8 @@ int pim_static_add(struct interface *iif, struct interface *oif, struct in_addr struct static_route *original_s_route = 0; struct pim_interface *pim_iif = iif ? iif->info : 0; struct pim_interface *pim_oif = oif ? oif->info : 0; - unsigned int iif_index = pim_iif ? pim_iif->mroute_vif_index : 0; - unsigned int oif_index = pim_oif ? pim_oif->mroute_vif_index : 0; + ifindex_t iif_index = pim_iif ? pim_iif->mroute_vif_index : 0; + ifindex_t oif_index = pim_oif ? pim_oif->mroute_vif_index : 0; if (!iif_index || !oif_index) { zlog_warn("%s %s: Unable to add static route: Invalid interface index(iif=%d,oif=%d)", @@ -138,30 +139,30 @@ int pim_static_add(struct interface *iif, struct interface *oif, struct in_addr /* Route exists and has the same input interface, but adding a new output interface */ if (s_route->iif == iif_index) { s_route->oif_ttls[oif_index] = 1; - s_route->mc.mfcc_ttls[oif_index] = 1; - s_route->creation[oif_index] = pim_time_monotonic_sec(); - ++s_route->oif_count; + s_route->c_oil.oil.mfcc_ttls[oif_index] = 1; + s_route->c_oil.oif_creation[oif_index] = pim_time_monotonic_sec(); + ++s_route->c_oil.oil_ref_count; } else { /* input interface changed */ s_route->iif = iif_index; - s_route->mc.mfcc_parent = iif_index; + s_route->c_oil.oil.mfcc_parent = iif_index; #ifdef PIM_ENFORCE_LOOPFREE_MFC /* check to make sure the new input was not an old output */ if (s_route->oif_ttls[iif_index]) { s_route->oif_ttls[iif_index] = 0; - s_route->creation[iif_index] = 0; - s_route->mc.mfcc_ttls[iif_index] = 0; - --s_route->oif_count; + s_route->c_oil.oif_creation[iif_index] = 0; + s_route->c_oil.oil.mfcc_ttls[iif_index] = 0; + --s_route->c_oil.oil_ref_count; } #endif /* now add the new output, if it is new */ if (!s_route->oif_ttls[oif_index]) { s_route->oif_ttls[oif_index] = 1; - s_route->creation[oif_index] = pim_time_monotonic_sec(); - s_route->mc.mfcc_ttls[oif_index] = 1; - ++s_route->oif_count; + s_route->c_oil.oif_creation[oif_index] = pim_time_monotonic_sec(); + s_route->c_oil.oil.mfcc_ttls[oif_index] = 1; + ++s_route->c_oil.oil_ref_count; } } @@ -175,7 +176,7 @@ int pim_static_add(struct interface *iif, struct interface *oif, struct in_addr listnode_add(qpim_static_route_list, s_route); } - if (pim_mroute_add(&(s_route->mc))) + if (pim_mroute_add(&s_route->c_oil)) { char gifaddr_str[100]; char sifaddr_str[100]; @@ -228,8 +229,8 @@ int pim_static_del(struct interface *iif, struct interface *oif, struct in_addr struct static_route *s_route = 0; struct pim_interface *pim_iif = iif ? iif->info : 0; struct pim_interface *pim_oif = oif ? oif->info : 0; - unsigned int iif_index = pim_iif ? pim_iif->mroute_vif_index : 0; - unsigned int oif_index = pim_oif ? pim_oif->mroute_vif_index : 0; + ifindex_t iif_index = pim_iif ? pim_iif->mroute_vif_index : 0; + ifindex_t oif_index = pim_oif ? pim_oif->mroute_vif_index : 0; if (!iif_index || !oif_index) { zlog_warn("%s %s: Unable to remove static route: Invalid interface index(iif=%d,oif=%d)", @@ -245,11 +246,12 @@ int pim_static_del(struct interface *iif, struct interface *oif, struct in_addr s_route->source.s_addr == source.s_addr && s_route->oif_ttls[oif_index]) { s_route->oif_ttls[oif_index] = 0; - s_route->mc.mfcc_ttls[oif_index] = 0; - --s_route->oif_count; + s_route->c_oil.oil.mfcc_ttls[oif_index] = 0; + --s_route->c_oil.oil_ref_count; /* If there are no more outputs then delete the whole route, otherwise set the route with the new outputs */ - if (s_route->oif_count <= 0 ? pim_mroute_del(&s_route->mc) : pim_mroute_add(&s_route->mc)) { + if (s_route->c_oil.oil_ref_count <= 0 ? + pim_mroute_del(&s_route->c_oil) : pim_mroute_add(&s_route->c_oil)) { char gifaddr_str[100]; char sifaddr_str[100]; pim_inet4_dump("", group, gifaddr_str, sizeof(gifaddr_str)); @@ -262,15 +264,15 @@ int pim_static_del(struct interface *iif, struct interface *oif, struct in_addr sifaddr_str); s_route->oif_ttls[oif_index] = 1; - s_route->mc.mfcc_ttls[oif_index] = 1; - ++s_route->oif_count; + s_route->c_oil.oil.mfcc_ttls[oif_index] = 1; + ++s_route->c_oil.oil_ref_count; return -1; } - s_route->creation[oif_index] = 0; + s_route->c_oil.oif_creation[oif_index] = 0; - if (s_route->oif_count <= 0) { + if (s_route->c_oil.oil_ref_count <= 0) { listnode_delete(qpim_static_route_list, s_route); pim_static_route_free(s_route); } diff --git a/pimd/pim_static.h b/pimd/pim_static.h index b3be09e913..07d31d59b7 100644 --- a/pimd/pim_static.h +++ b/pimd/pim_static.h @@ -32,11 +32,9 @@ struct static_route { struct in_addr group; struct in_addr source; - unsigned int iif; + struct channel_oil c_oil; + ifindex_t iif; unsigned char oif_ttls[MAXVIFS]; - int oif_count; - struct mfcctl mc; - time_t creation[MAXVIFS]; }; void pim_static_route_free(struct static_route *s_route); diff --git a/pimd/pim_tlv.c b/pimd/pim_tlv.c index 0c768be122..38f6de9fea 100644 --- a/pimd/pim_tlv.c +++ b/pimd/pim_tlv.c @@ -97,6 +97,25 @@ uint8_t *pim_tlv_append_uint32(uint8_t *buf, #define ucast_ipv4_encoding_len (2 + sizeof(struct in_addr)) +static int +pim_encode_unicast_address (uint8_t *buf, struct prefix *p) +{ + switch (p->family) + { + case AF_INET: + *(uint8_t *)buf = PIM_MSG_ADDRESS_FAMILY_IPV4; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */ + ++buf; + *(uint8_t *)buf = 0; /* ucast IPv4 native encoding type (RFC 4601: 4.9.1) */ + ++buf; + memcpy (buf, &p->u.prefix4, sizeof (struct in_addr)); + return ucast_ipv4_encoding_len; + break; + default: + return 0; + break; + } +} + uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, const uint8_t *buf_pastend, struct list *ifconnected) @@ -121,22 +140,14 @@ uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, for (; node; node = listnextnode(node)) { struct connected *ifc = listgetdata(node); struct prefix *p = ifc->address; - - if (p->family != AF_INET) - continue; + int l_encode; if ((curr + ucast_ipv4_encoding_len) > buf_pastend) return 0; - /* Write encoded unicast IPv4 address */ - *(uint8_t *) curr = PIM_MSG_ADDRESS_FAMILY_IPV4; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */ - ++curr; - *(uint8_t *) curr = 0; /* ucast IPv4 native encoding type (RFC 4601: 4.9.1) */ - ++curr; - memcpy(curr, &p->u.prefix4, sizeof(struct in_addr)); - curr += sizeof(struct in_addr); - - option_len += ucast_ipv4_encoding_len; + l_encode = pim_encode_unicast_address (curr, p); + curr += l_encode; + option_len += l_encode; } if (PIM_DEBUG_PIM_TRACE_DETAIL) { @@ -340,10 +351,10 @@ int pim_tlv_parse_generation_id(const char *ifname, struct in_addr src_addr, return 0; } -int pim_parse_addr_ucast(const char *ifname, struct in_addr src_addr, - struct prefix *p, - const uint8_t *buf, - int buf_size) +int +pim_parse_addr_ucast (struct prefix *p, + const uint8_t *buf, + int buf_size) { const int ucast_encoding_min_len = 3; /* 1 family + 1 type + 1 addr */ const uint8_t *addr; @@ -352,12 +363,9 @@ int pim_parse_addr_ucast(const char *ifname, struct in_addr src_addr, int type; if (buf_size < ucast_encoding_min_len) { - char src_str[100]; - pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); - zlog_warn("%s: unicast address encoding overflow: left=%d needed=%d from %s on %s", + zlog_warn("%s: unicast address encoding overflow: left=%d needed=%d", __PRETTY_FUNCTION__, - buf_size, ucast_encoding_min_len, - src_str, ifname); + buf_size, ucast_encoding_min_len); return -1; } @@ -367,24 +375,19 @@ int pim_parse_addr_ucast(const char *ifname, struct in_addr src_addr, family = *addr++; type = *addr++; + if (type) { + zlog_warn("%s: unknown unicast address encoding type=%d", + __PRETTY_FUNCTION__, + type); + return -2; + } + switch (family) { case PIM_MSG_ADDRESS_FAMILY_IPV4: - if (type) { - char src_str[100]; - pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); - zlog_warn("%s: unknown unicast address encoding type=%d from %s on %s", - __PRETTY_FUNCTION__, - type, src_str, ifname); - return -2; - } - if ((addr + sizeof(struct in_addr)) > pastend) { - char src_str[100]; - pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); - zlog_warn("%s: IPv4 unicast address overflow: left=%zd needed=%zu from %s on %s", + zlog_warn("%s: IPv4 unicast address overflow: left=%zd needed=%zu", __PRETTY_FUNCTION__, - pastend - addr, sizeof(struct in_addr), - src_str, ifname); + pastend - addr, sizeof(struct in_addr)); return -3; } @@ -396,11 +399,9 @@ int pim_parse_addr_ucast(const char *ifname, struct in_addr src_addr, break; default: { - char src_str[100]; - pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); - zlog_warn("%s: unknown unicast address encoding family=%d from %s on %s", + zlog_warn("%s: unknown unicast address encoding family=%d from", __PRETTY_FUNCTION__, - family, src_str, ifname); + family); return -4; } } @@ -408,10 +409,10 @@ int pim_parse_addr_ucast(const char *ifname, struct in_addr src_addr, return addr - buf; } -int pim_parse_addr_group(const char *ifname, struct in_addr src_addr, - struct prefix *p, - const uint8_t *buf, - int buf_size) +int +pim_parse_addr_group (struct prefix *p, + const uint8_t *buf, + int buf_size) { const int grp_encoding_min_len = 4; /* 1 family + 1 type + 1 reserved + 1 addr */ const uint8_t *addr; @@ -421,12 +422,9 @@ int pim_parse_addr_group(const char *ifname, struct in_addr src_addr, int mask_len; if (buf_size < grp_encoding_min_len) { - char src_str[100]; - pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); - zlog_warn("%s: group address encoding overflow: left=%d needed=%d from %s on %s", + zlog_warn("%s: group address encoding overflow: left=%d needed=%d", __PRETTY_FUNCTION__, - buf_size, grp_encoding_min_len, - src_str, ifname); + buf_size, grp_encoding_min_len); return -1; } @@ -442,21 +440,15 @@ int pim_parse_addr_group(const char *ifname, struct in_addr src_addr, switch (family) { case PIM_MSG_ADDRESS_FAMILY_IPV4: if (type) { - char src_str[100]; - pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); - zlog_warn("%s: unknown group address encoding type=%d from %s on %s", - __PRETTY_FUNCTION__, - type, src_str, ifname); + zlog_warn("%s: unknown group address encoding type=%d from", + __PRETTY_FUNCTION__, type); return -2; } if ((addr + sizeof(struct in_addr)) > pastend) { - char src_str[100]; - pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); - zlog_warn("%s: IPv4 group address overflow: left=%zd needed=%zu from %s on %s", + zlog_warn("%s: IPv4 group address overflow: left=%zd needed=%zu from", __PRETTY_FUNCTION__, - pastend - addr, sizeof(struct in_addr), - src_str, ifname); + pastend - addr, sizeof(struct in_addr)); return -3; } @@ -469,11 +461,8 @@ int pim_parse_addr_group(const char *ifname, struct in_addr src_addr, break; default: { - char src_str[100]; - pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); - zlog_warn("%s: unknown group address encoding family=%d from %s on %s", - __PRETTY_FUNCTION__, - family, src_str, ifname); + zlog_warn("%s: unknown group address encoding family=%d from", + __PRETTY_FUNCTION__, family); return -4; } } @@ -481,12 +470,11 @@ int pim_parse_addr_group(const char *ifname, struct in_addr src_addr, return addr - buf; } -int pim_parse_addr_source(const char *ifname, - struct in_addr src_addr, - struct prefix *p, - uint8_t *flags, - const uint8_t *buf, - int buf_size) +int +pim_parse_addr_source(struct prefix *p, + uint8_t *flags, + const uint8_t *buf, + int buf_size) { const int src_encoding_min_len = 4; /* 1 family + 1 type + 1 reserved + 1 addr */ const uint8_t *addr; @@ -496,12 +484,9 @@ int pim_parse_addr_source(const char *ifname, int mask_len; if (buf_size < src_encoding_min_len) { - char src_str[100]; - pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); - zlog_warn("%s: source address encoding overflow: left=%d needed=%d from %s on %s", + zlog_warn("%s: source address encoding overflow: left=%d needed=%d", __PRETTY_FUNCTION__, - buf_size, src_encoding_min_len, - src_str, ifname); + buf_size, src_encoding_min_len); return -1; } @@ -513,25 +498,20 @@ int pim_parse_addr_source(const char *ifname, *flags = *addr++; mask_len = *addr++; + if (type) { + zlog_warn("%s: unknown source address encoding type=%d: %02x%02x%02x%02x%02x%02x%02x%02x", + __PRETTY_FUNCTION__, + type, + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); + return -2; + } + switch (family) { case PIM_MSG_ADDRESS_FAMILY_IPV4: - if (type) { - char src_str[100]; - pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); - zlog_warn("%s: unknown source address encoding type=%d from %s on %s: %02x%02x%02x%02x%02x%02x%02x%02x", - __PRETTY_FUNCTION__, - type, src_str, ifname, - buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); - return -2; - } - if ((addr + sizeof(struct in_addr)) > pastend) { - char src_str[100]; - pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); - zlog_warn("%s: IPv4 source address overflow: left=%zd needed=%zu from %s on %s", + zlog_warn("%s: IPv4 source address overflow: left=%zd needed=%zu", __PRETTY_FUNCTION__, - pastend - addr, sizeof(struct in_addr), - src_str, ifname); + pastend - addr, sizeof(struct in_addr)); return -3; } @@ -550,10 +530,8 @@ int pim_parse_addr_source(const char *ifname, received with any other mask length. */ if (p->prefixlen != 32) { - char src_str[100]; - pim_inet4_dump("", p->u.prefix4, src_str, sizeof(src_str)); - zlog_warn("%s: IPv4 bad source address mask: %s/%d", - __PRETTY_FUNCTION__, src_str, p->prefixlen); + zlog_warn("%s: IPv4 bad source address mask: %d", + __PRETTY_FUNCTION__, p->prefixlen); return -4; } @@ -562,11 +540,9 @@ int pim_parse_addr_source(const char *ifname, break; default: { - char src_str[100]; - pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); - zlog_warn("%s: unknown source address encoding family=%d from %s on %s: %02x%02x%02x%02x%02x%02x%02x%02x", + zlog_warn("%s: unknown source address encoding family=%d: %02x%02x%02x%02x%02x%02x%02x%02x", __PRETTY_FUNCTION__, - family, src_str, ifname, + family, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); return -5; } @@ -606,8 +582,7 @@ int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr, /* Parse ucast addr */ - addr_offset = pim_parse_addr_ucast(ifname, src_addr, &tmp, - addr, pastend - addr); + addr_offset = pim_parse_addr_ucast(&tmp, addr, pastend - addr); if (addr_offset < 1) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); diff --git a/pimd/pim_tlv.h b/pimd/pim_tlv.h index b802cf8977..59d49954e7 100644 --- a/pimd/pim_tlv.h +++ b/pimd/pim_tlv.h @@ -115,17 +115,13 @@ int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr, uint16_t option_len, const uint8_t *tlv_curr); -int pim_parse_addr_ucast(const char *ifname, struct in_addr src_addr, - struct prefix *p, - const uint8_t *buf, - int buf_size); -int pim_parse_addr_group(const char *ifname, struct in_addr src_addr, - struct prefix *p, - const uint8_t *buf, - int buf_size); -int pim_parse_addr_source(const char *ifname, - struct in_addr src_addr, - struct prefix *p, +int pim_parse_addr_ucast (struct prefix *p, + const uint8_t *buf, + int buf_size); +int pim_parse_addr_group (struct prefix *p, + const uint8_t *buf, + int buf_size); +int pim_parse_addr_source(struct prefix *p, uint8_t *flags, const uint8_t *buf, int buf_size); diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index cb2619abb7..8267885756 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -59,7 +59,7 @@ static void upstream_channel_oil_detach(struct pim_upstream *up) { if (up->channel_oil) { pim_channel_oil_del(up->channel_oil); - up->channel_oil = 0; + up->channel_oil = NULL; } } @@ -715,12 +715,29 @@ pim_upstream_keep_alive_timer (struct thread *t) up = THREAD_ARG(t); - pim_br_clear_pmbr (up->source_addr, up->group_addr); - /* - * We need to do more here :) - * But this is the start. - */ + if (I_am_RP (up->group_addr)) + { + pim_br_clear_pmbr (up->source_addr, up->group_addr); + /* + * We need to do more here :) + * But this is the start. + */ + } + else + { + pim_mroute_update_counters (up->channel_oil); + if (up->channel_oil->cc.oldpktcnt >= up->channel_oil->cc.pktcnt) + { + pim_mroute_del (up->channel_oil); + pim_upstream_delete (up); + } + else + { + up->t_ka_timer = NULL; + pim_upstream_keep_alive_timer_start (up, PIM_KEEPALIVE_PERIOD); + } + } return 1; } diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index beb0622a3f..f1c8930856 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -33,6 +33,7 @@ #include "pim_str.h" #include "pim_ssmpingd.h" #include "pim_pim.h" +#include "pim_oil.h" #include "pim_static.h" int pim_debug_config_write(struct vty *vty) diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index b19b3941b1..d357e5cc83 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -387,18 +387,27 @@ static void scan_upstream_rpf_cache() void pim_scan_individual_oil (struct channel_oil *c_oil) { + struct in_addr vif_source; + int input_iface_vif_index; int old_vif_index; - int input_iface_vif_index = fib_lookup_if_vif_index(c_oil->oil.mfcc_origin); + if (!pim_rp_set_upstream_addr (&vif_source, c_oil->oil.mfcc_origin)) + return; + + input_iface_vif_index = fib_lookup_if_vif_index (vif_source); if (input_iface_vif_index < 1) { - char source_str[100]; - char group_str[100]; - pim_inet4_dump("", c_oil->oil.mfcc_origin, source_str, sizeof(source_str)); - pim_inet4_dump("", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); - zlog_warn("%s %s: could not find input interface for (S,G)=(%s,%s)", - __FILE__, __PRETTY_FUNCTION__, - source_str, group_str); + if (PIM_DEBUG_ZEBRA) + { + char source_str[100]; + char group_str[100]; + pim_inet4_dump("", c_oil->oil.mfcc_origin, source_str, sizeof(source_str)); + pim_inet4_dump("", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); + zlog_debug("%s %s: could not find input interface(%d) for (S,G)=(%s,%s)", + __FILE__, __PRETTY_FUNCTION__, c_oil->oil.mfcc_parent, + source_str, group_str); + } + pim_mroute_del (c_oil); return; } @@ -448,7 +457,7 @@ pim_scan_individual_oil (struct channel_oil *c_oil) zlog_debug ("FF"); /* update kernel multicast forwarding cache (MFC) */ - if (pim_mroute_add(&c_oil->oil)) + if (pim_mroute_add(c_oil)) { /* just log warning */ struct interface *old_iif = pim_if_find_by_vif_index(old_vif_index); @@ -524,7 +533,7 @@ static int redist_read_ipv4_route(int command, struct zclient *zclient, { struct stream *s; struct zapi_ipv4 api; - unsigned long ifindex; + ifindex_t ifindex; struct in_addr nexthop; struct prefix_ipv4 p; int min_len = 4; @@ -611,7 +620,7 @@ static int redist_read_ipv4_route(int command, struct zclient *zclient, if (PIM_DEBUG_ZEBRA) { char buf[2][INET_ADDRSTRLEN]; zlog_debug("%s: add %s %s/%d " - "nexthop %s ifindex %ld metric%s %u distance%s %u", + "nexthop %s ifindex %d metric%s %u distance%s %u", __PRETTY_FUNCTION__, zebra_route_string(api.type), inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])), @@ -629,7 +638,7 @@ static int redist_read_ipv4_route(int command, struct zclient *zclient, if (PIM_DEBUG_ZEBRA) { char buf[2][INET_ADDRSTRLEN]; zlog_debug("%s: delete %s %s/%d " - "nexthop %s ifindex %ld metric%s %u distance%s %u", + "nexthop %s ifindex %d metric%s %u distance%s %u", __PRETTY_FUNCTION__, zebra_route_string(api.type), inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])), @@ -754,7 +763,7 @@ static int fib_lookup_if_vif_index(struct in_addr addr) struct pim_zlookup_nexthop nexthop_tab[PIM_NEXTHOP_IFINDEX_TAB_SIZE]; int num_ifindex; int vif_index; - int first_ifindex; + ifindex_t first_ifindex; num_ifindex = zclient_lookup_nexthop(qpim_zclient_lookup, nexthop_tab, PIM_NEXTHOP_IFINDEX_TAB_SIZE, addr, @@ -900,7 +909,7 @@ static int del_oif(struct channel_oil *channel_oil, channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = 0; - if (pim_mroute_add(&channel_oil->oil)) { + if (pim_mroute_add(channel_oil)) { char group_str[100]; char source_str[100]; pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); @@ -917,7 +926,7 @@ static int del_oif(struct channel_oil *channel_oil, --channel_oil->oil_size; if (channel_oil->oil_size < 1) { - if (pim_mroute_del(&channel_oil->oil)) { + if (pim_mroute_del(channel_oil)) { /* just log a warning in case of failure */ char group_str[100]; char source_str[100]; diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c index 1f8cdfa07e..86d7edbd01 100644 --- a/pimd/pim_zlookup.c +++ b/pimd/pim_zlookup.c @@ -229,8 +229,8 @@ static int zclient_read_nexthop(struct zclient *zlookup, --length; switch (nexthop_type) { - case ZEBRA_NEXTHOP_IFINDEX: - case ZEBRA_NEXTHOP_IPV4_IFINDEX: + case NEXTHOP_TYPE_IFINDEX: + case NEXTHOP_TYPE_IPV4_IFINDEX: if (num_ifindex >= tab_size) { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); @@ -239,7 +239,7 @@ static int zclient_read_nexthop(struct zclient *zlookup, (num_ifindex + 1), tab_size, addr_str); return num_ifindex; } - if (nexthop_type == ZEBRA_NEXTHOP_IPV4_IFINDEX) { + if (nexthop_type == NEXTHOP_TYPE_IPV4_IFINDEX) { if (length < 4) { zlog_err("%s: socket %d short input expecting nexthop IPv4-addr: len=%d", __func__, zlookup->sock, length); @@ -256,7 +256,7 @@ static int zclient_read_nexthop(struct zclient *zlookup, nexthop_tab[num_ifindex].route_metric = metric; ++num_ifindex; break; - case ZEBRA_NEXTHOP_IPV4: + case NEXTHOP_TYPE_IPV4: if (num_ifindex >= tab_size) { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); diff --git a/pimd/pim_zlookup.h b/pimd/pim_zlookup.h index 1f184942ca..f2be6d4fa0 100644 --- a/pimd/pim_zlookup.h +++ b/pimd/pim_zlookup.h @@ -31,7 +31,7 @@ struct pim_zlookup_nexthop { struct in_addr nexthop_addr; - int ifindex; + ifindex_t ifindex; uint32_t route_metric; uint8_t protocol_distance; }; diff --git a/pimd/pimd.c b/pimd/pimd.c index 5b6824da58..91d8d56afc 100644 --- a/pimd/pimd.c +++ b/pimd/pimd.c @@ -87,6 +87,8 @@ static void pim_free() if (qpim_static_route_list) list_free(qpim_static_route_list); + + pim_route_map_terminate(); } void pim_init() diff --git a/pimd/pimd.h b/pimd/pimd.h index c5fec76675..6d48d83621 100644 --- a/pimd/pimd.h +++ b/pimd/pimd.h @@ -25,7 +25,6 @@ #include -#include "pim_mroute.h" #include "pim_assert.h" #define PIMD_PROGNAME "pimd" @@ -178,5 +177,6 @@ void pim_init(void); void pim_terminate(void); extern void pim_route_map_init (void); +extern void pim_route_map_terminate(void); #endif /* PIMD_H */ diff --git a/pimd/test_igmpv3_join.c b/pimd/test_igmpv3_join.c index 6f1e34de88..5c4574024b 100644 --- a/pimd/test_igmpv3_join.c +++ b/pimd/test_igmpv3_join.c @@ -20,6 +20,8 @@ $QuaggaId: $Format:%an, %ai, %h$ $ */ +#include + #include #include #include @@ -30,16 +32,15 @@ #include #include -#include "thread.h" +#include "if.h" #include "pim_igmp_join.h" -struct thread_master *master; const char *prog_name = 0; static int iface_solve_index(const char *ifname) { struct if_nameindex *ini; - int ifindex = -1; + ifindex_t ifindex = -1; int i; if (!ifname) @@ -79,7 +80,7 @@ int main(int argc, const char *argv[]) const char *ifname; const char *group; const char *source; - int ifindex; + ifindex_t ifindex; int result; int fd; diff --git a/redhat/quagga.spec.in b/redhat/quagga.spec.in index c1d5f00167..9ff65e9a22 100644 --- a/redhat/quagga.spec.in +++ b/redhat/quagga.spec.in @@ -71,7 +71,6 @@ %define daemon_list zebra ripd ospfd bgpd isisd pimd ripngd ospfd6d - %if %{with_watchquagga} %define daemon_watchquagga watchquagga %else @@ -220,6 +219,7 @@ developing OSPF-API and quagga applications. --disable-watchquagga \ %endif --enable-gcc-rdynamic \ + --enable-isisd=yes \ --enable-systemd=yes \ --enable-poll=yes diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c index 6748e197da..09b35d00b9 100644 --- a/ripd/rip_interface.c +++ b/ripd/rip_interface.c @@ -74,12 +74,13 @@ static int ipv4_multicast_join (int sock, struct in_addr group, struct in_addr ifa, - unsigned int ifindex) + ifindex_t ifindex) { int ret; ret = setsockopt_ipv4_multicast (sock, IP_ADD_MEMBERSHIP, + ifa, group.s_addr, ifindex); @@ -95,12 +96,13 @@ static int ipv4_multicast_leave (int sock, struct in_addr group, struct in_addr ifa, - unsigned int ifindex) + ifindex_t ifindex) { int ret; ret = setsockopt_ipv4_multicast (sock, IP_DROP_MEMBERSHIP, + ifa, group.s_addr, ifindex); @@ -136,9 +138,13 @@ rip_interface_new (void) void rip_interface_multicast_set (int sock, struct connected *connected) { + struct in_addr addr; + assert (connected != NULL); - - if (setsockopt_ipv4_multicast_if (sock, connected->ifp->ifindex) < 0) + + addr = CONNECTED_ID(connected)->u.prefix4; + + if (setsockopt_ipv4_multicast_if (sock, addr, connected->ifp->ifindex) < 0) { zlog_warn ("Can't setsockopt IP_MULTICAST_IF on fd %d to " "ifindex %d for interface %s", diff --git a/ripd/rip_main.c b/ripd/rip_main.c index f920e809e2..aa1c4ff4df 100644 --- a/ripd/rip_main.c +++ b/ripd/rip_main.c @@ -205,7 +205,9 @@ main (int argc, char **argv) zlog_default = openzlog (progname, ZLOG_RIP, 0, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); zprivs_init (&ripd_privs); - zlog_set_file (NULL, LOG_DEFAULT_FILENAME, zlog_default->default_lvl); +#if defined(HAVE_CUMULUS) + zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl); +#endif /* Command line option parse. */ while (1) diff --git a/ripd/rip_snmp.c b/ripd/rip_snmp.c index 4b7d1b4c50..c28b9379cc 100644 --- a/ripd/rip_snmp.c +++ b/ripd/rip_snmp.c @@ -81,10 +81,10 @@ SNMP_LOCAL_VARIABLES /* RIP-MIB instances. */ -oid rip_oid [] = { RIPV2MIB }; +static oid rip_oid [] = { RIPV2MIB }; /* Interface cache table sorted by interface's address. */ -struct route_table *rip_ifaddr_table; +static struct route_table *rip_ifaddr_table; /* Hook functions. */ static u_char *rip2Globals (struct variable *, oid [], size_t *, @@ -96,7 +96,7 @@ static u_char *rip2IfConfAddress (struct variable *, oid [], size_t *, static u_char *rip2PeerTable (struct variable *, oid [], size_t *, int, size_t *, WriteMethod **); -struct variable rip_variables[] = +static struct variable rip_variables[] = { /* RIP Global Counters. */ {RIP2GLOBALROUTECHANGES, COUNTER, RONLY, rip2Globals, diff --git a/ripd/ripd.c b/ripd/ripd.c index 42f1015453..3a8cd80e7a 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -1579,7 +1579,7 @@ rip_send_packet (u_char * buf, int size, struct sockaddr_in *to, /* Add redistributed route to RIP table. */ void rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p, - unsigned int ifindex, struct in_addr *nexthop, + ifindex_t ifindex, struct in_addr *nexthop, unsigned int metric, unsigned char distance) { int ret; @@ -1653,7 +1653,7 @@ rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p, /* Delete redistributed route from RIP table. */ void rip_redistribute_delete (int type, int sub_type, struct prefix_ipv4 *p, - unsigned int ifindex) + ifindex_t ifindex) { int ret; struct route_node *rp; @@ -1795,7 +1795,7 @@ setsockopt_pktinfo (int sock) /* Read RIP packet by recvmsg function. */ int rip_recvmsg (int sock, u_char *buf, int size, struct sockaddr_in *from, - int *ifindex) + ifindex_t *ifindex) { int ret; struct msghdr msg; @@ -1836,7 +1836,7 @@ rip_read_new (struct thread *t) int sock; char buf[RIP_PACKET_MAXSIZ]; struct sockaddr_in from; - unsigned int ifindex; + ifindex_t ifindex; /* Fetch socket then register myself. */ sock = THREAD_FD (t); diff --git a/ripd/ripd.h b/ripd/ripd.h index fe9e521d88..d01d0b6bbe 100644 --- a/ripd/ripd.h +++ b/ripd/ripd.h @@ -198,7 +198,7 @@ struct rip_info struct in_addr from; /* Which interface does this route come from. */ - unsigned int ifindex; + ifindex_t ifindex; /* Metric of this route. */ u_int32_t metric; @@ -224,7 +224,7 @@ struct rip_info u_char metric_set; u_int32_t metric_out; u_short tag_out; - unsigned int ifindex_out; + ifindex_t ifindex_out; struct route_node *rp; @@ -400,9 +400,9 @@ extern int rip_request_send (struct sockaddr_in *, struct interface *, u_char, extern int rip_neighbor_lookup (struct sockaddr_in *); extern int rip_redistribute_check (int); -extern void rip_redistribute_add (int, int, struct prefix_ipv4 *, unsigned int, +extern void rip_redistribute_add (int, int, struct prefix_ipv4 *, ifindex_t, struct in_addr *, unsigned int, unsigned char); -extern void rip_redistribute_delete (int, int, struct prefix_ipv4 *, unsigned int); +extern void rip_redistribute_delete (int, int, struct prefix_ipv4 *, ifindex_t); extern void rip_redistribute_withdraw (int); extern void rip_zebra_ipv4_add (struct route_node *); extern void rip_zebra_ipv4_delete (struct route_node *); diff --git a/ripngd/ripng_main.c b/ripngd/ripng_main.c index a1c71c8562..f401a43156 100644 --- a/ripngd/ripng_main.c +++ b/ripngd/ripng_main.c @@ -204,7 +204,9 @@ main (int argc, char **argv) zlog_default = openzlog(progname, ZLOG_RIPNG, 0, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); zprivs_init (&ripngd_privs); - zlog_set_file (NULL, LOG_DEFAULT_FILENAME, zlog_default->default_lvl); +#if defined(HAVE_CUMULUS) + zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl); +#endif while (1) { diff --git a/ripngd/ripng_zebra.c b/ripngd/ripng_zebra.c index ecfe2d5154..d8667cb68c 100644 --- a/ripngd/ripng_zebra.c +++ b/ripngd/ripng_zebra.c @@ -42,7 +42,7 @@ static void ripng_zebra_ipv6_send (struct route_node *rp, u_char cmd) { static struct in6_addr **nexthops = NULL; - static unsigned int *ifindexes = NULL; + static ifindex_t *ifindexes = NULL; static unsigned int nexthops_len = 0; struct list *list = (struct list *)rp->info; diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c index b786c6f938..2858bb6462 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -229,7 +229,7 @@ ripng_send_packet (caddr_t buf, int bufsize, struct sockaddr_in6 *to, /* Receive UDP RIPng packet from socket. */ static int ripng_recv_packet (int sock, u_char *buf, int bufsize, - struct sockaddr_in6 *from, unsigned int *ifindex, + struct sockaddr_in6 *from, ifindex_t *ifindex, int *hoplimit) { int ret; @@ -973,7 +973,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, struct in6_addr *nexthop) + ifindex_t ifindex, struct in6_addr *nexthop) { struct route_node *rp; struct ripng_info *rinfo = NULL, newinfo; @@ -1043,7 +1043,7 @@ ripng_redistribute_add (int type, int sub_type, struct prefix_ipv6 *p, /* Delete redistributed route to RIPng table. */ void ripng_redistribute_delete (int type, int sub_type, struct prefix_ipv6 *p, - unsigned int ifindex) + ifindex_t ifindex) { struct route_node *rp; struct ripng_info *rinfo; @@ -1361,7 +1361,7 @@ ripng_read (struct thread *thread) int sock; struct sockaddr_in6 from; struct ripng_packet *packet; - unsigned int ifindex = 0; + ifindex_t ifindex = 0; struct interface *ifp; int hoplimit = -1; diff --git a/ripngd/ripngd.h b/ripngd/ripngd.h index 1496de08bf..b87b927f48 100644 --- a/ripngd/ripngd.h +++ b/ripngd/ripngd.h @@ -176,7 +176,7 @@ struct ripng_info struct in6_addr from; /* Which interface does this route come from. */ - unsigned int ifindex; + ifindex_t ifindex; /* Metric of this route. */ u_char metric; @@ -381,9 +381,9 @@ extern void ripng_info_free (struct ripng_info *rinfo); extern void ripng_event (enum ripng_event, int); extern int ripng_request (struct interface *ifp); extern void ripng_redistribute_add (int, int, struct prefix_ipv6 *, - unsigned int, struct in6_addr *); + ifindex_t, struct in6_addr *); extern void ripng_redistribute_delete (int, int, struct prefix_ipv6 *, - unsigned int); + ifindex_t); extern void ripng_redistribute_withdraw (int type); extern void ripng_distribute_update_interface (struct interface *); diff --git a/tests/aspath_test.c b/tests/aspath_test.c index fde12c41c4..9d595807fe 100644 --- a/tests/aspath_test.c +++ b/tests/aspath_test.c @@ -25,6 +25,7 @@ #include "stream.h" #include "privs.h" #include "queue.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_aspath.h" diff --git a/tests/bgp_capability_test.c b/tests/bgp_capability_test.c index ecabc2f19f..73f46b59a0 100644 --- a/tests/bgp_capability_test.c +++ b/tests/bgp_capability_test.c @@ -26,6 +26,7 @@ #include "privs.h" #include "memory.h" #include "queue.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_open.h" diff --git a/tests/bgp_mp_attr_test.c b/tests/bgp_mp_attr_test.c index ba619916d4..928d69752a 100644 --- a/tests/bgp_mp_attr_test.c +++ b/tests/bgp_mp_attr_test.c @@ -26,6 +26,7 @@ #include "privs.h" #include "memory.h" #include "queue.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_attr.h" diff --git a/tests/bgp_mpath_test.c b/tests/bgp_mpath_test.c index bafbef75fb..66a718cbe2 100644 --- a/tests/bgp_mpath_test.c +++ b/tests/bgp_mpath_test.c @@ -30,6 +30,7 @@ #include "memory.h" #include "zclient.h" #include "queue.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" diff --git a/tests/ecommunity_test.c b/tests/ecommunity_test.c index 1d4f6a1860..9166af6142 100644 --- a/tests/ecommunity_test.c +++ b/tests/ecommunity_test.c @@ -25,6 +25,7 @@ #include "privs.h" #include "memory.h" #include "queue.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_ecommunity.h" diff --git a/tests/testcli.refout b/tests/testcli.refout index 1515ea2c65..7da5494827 100644 --- a/tests/testcli.refout +++ b/tests/testcli.refout @@ -272,6 +272,7 @@ Current configuration: ! hostname test ! +! line vty ! end @@ -283,6 +284,7 @@ Current configuration: ! hostname foohost ! +! line vty ! end diff --git a/tools/quagga-reload.py b/tools/quagga-reload.py index 9c0cbb48d6..900ed55c43 100755 --- a/tools/quagga-reload.py +++ b/tools/quagga-reload.py @@ -23,6 +23,9 @@ from ipaddr import IPv6Address from pprint import pformat +log = logging.getLogger(__name__) + + class Context(object): """ @@ -80,12 +83,12 @@ class Config(object): The internal representation has been marked appropriately by passing it through vtysh with the -m parameter """ - logger.info('Loading Config object from file %s', filename) + log.info('Loading Config object from file %s', filename) try: file_output = subprocess.check_output(['/usr/bin/vtysh', '-m', '-f', filename]) except subprocess.CalledProcessError as e: - logger.error('vtysh marking of config file %s failed with error %s:', filename, str(e)) + log.error('vtysh marking of config file %s failed with error %s:', filename, str(e)) print "vtysh marking of file %s failed with error: %s" % (filename, str(e)) sys.exit(1) @@ -105,14 +108,14 @@ class Config(object): The internal representation has been marked appropriately by passing it through vtysh with the -m parameter """ - logger.info('Loading Config object from vtysh show running') + log.info('Loading Config object from vtysh show running') try: config_text = subprocess.check_output( "/usr/bin/vtysh -c 'show run' | /usr/bin/tail -n +4 | /usr/bin/vtysh -m -f -", shell=True) except subprocess.CalledProcessError as e: - logger.error('vtysh marking of running config failed with error %s:', str(e)) + log.error('vtysh marking of running config failed with error %s:', str(e)) print "vtysh marking of running config failed with error %s:" % (str(e)) sys.exit(1) @@ -259,13 +262,13 @@ end ctx_keys = [line, ] current_context_lines = [] - logger.debug('LINE %-50s: entering new context, %-50s', line, ctx_keys) + log.debug('LINE %-50s: entering new context, %-50s', line, ctx_keys) self.save_contexts(ctx_keys, current_context_lines) new_ctx = True elif line == "end": self.save_contexts(ctx_keys, current_context_lines) - logger.debug('LINE %-50s: exiting old context, %-50s', line, ctx_keys) + log.debug('LINE %-50s: exiting old context, %-50s', line, ctx_keys) # Start a new context new_ctx = True @@ -281,7 +284,7 @@ end # Start a new context ctx_keys = copy.deepcopy(main_ctx_key) current_context_lines = [] - logger.debug('LINE %-50s: popping from subcontext to ctx%-50s', line, ctx_keys) + log.debug('LINE %-50s: popping from subcontext to ctx%-50s', line, ctx_keys) elif new_ctx is True: if not main_ctx_key: @@ -292,7 +295,7 @@ end current_context_lines = [] new_ctx = False - logger.debug('LINE %-50s: entering new context, %-50s', line, ctx_keys) + log.debug('LINE %-50s: entering new context, %-50s', line, ctx_keys) elif "address-family " in line: main_ctx_key = [] @@ -301,7 +304,7 @@ end self.save_contexts(ctx_keys, current_context_lines) current_context_lines = [] main_ctx_key = copy.deepcopy(ctx_keys) - logger.debug('LINE %-50s: entering sub-context, append to ctx_keys', line) + log.debug('LINE %-50s: entering sub-context, append to ctx_keys', line) if line == "address-family ipv6": ctx_keys.append("address-family ipv6 unicast") @@ -313,7 +316,7 @@ end else: # Continuing in an existing context, add non-commented lines to it current_context_lines.append(line) - logger.debug('LINE %-50s: append to current_context_lines, %-50s', line, ctx_keys) + log.debug('LINE %-50s: append to current_context_lines, %-50s', line, ctx_keys) # Save the context of the last one self.save_contexts(ctx_keys, current_context_lines) @@ -448,7 +451,7 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): for (ctx_keys, line) in lines_to_del: deleted = False - if ctx_keys[0].startswith('router bgp') and line.startswith('neighbor '): + if ctx_keys[0].startswith('router bgp') and line and line.startswith('neighbor '): """ BGP changed how it displays swpX peers that are part of peer-group. Older versions of quagga would display these on separate lines: @@ -507,6 +510,56 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): lines_to_add_to_del.append((ctx_keys, swpx_interface)) lines_to_add_to_del.append((tmp_ctx_keys, swpx_peergroup)) + """ + In 3.0.1 we changed how we display neighbor interface command. Older + versions of quagga would display the following: + neighbor swp1 interface + neighbor swp1 remote-as external + neighbor swp1 capability extended-nexthop + + but today we display via a single line + neighbor swp1 interface remote-as external + + and capability extended-nexthop is no longer needed because we + automatically enable it when the neighbor is of type interface. + + This change confuses quagga-reload.py so check to see if we are deleting + neighbor swp1 interface remote-as (external|internal|ASNUM) + + and adding + neighbor swp1 interface + neighbor swp1 remote-as (external|internal|ASNUM) + neighbor swp1 capability extended-nexthop + + If so then chop the del line and the corresponding add lines + """ + re_swpx_int_remoteas = re.search('neighbor (\S+) interface remote-as (\S+)', line) + re_swpx_int_v6only_remoteas = re.search('neighbor (\S+) interface v6only remote-as (\S+)', line) + + if re_swpx_int_remoteas or re_swpx_int_v6only_remoteas: + swpx_interface = None + swpx_remoteas = None + + if re_swpx_int_remoteas: + swpx = re_swpx_int_remoteas.group(1) + remoteas = re_swpx_int_remoteas.group(2) + swpx_interface = "neighbor %s interface" % swpx + elif re_swpx_int_v6only_remoteas: + swpx = re_swpx_int_v6only_remoteas.group(1) + remoteas = re_swpx_int_v6only_remoteas.group(2) + swpx_interface = "neighbor %s interface v6only" % swpx + + swpx_remoteas = "neighbor %s remote-as %s" % (swpx, remoteas) + found_add_swpx_interface = line_exist(lines_to_add, ctx_keys, swpx_interface) + found_add_swpx_remoteas = line_exist(lines_to_add, ctx_keys, swpx_remoteas) + tmp_ctx_keys = tuple(list(ctx_keys)) + + if found_add_swpx_interface and found_add_swpx_remoteas: + deleted = True + lines_to_del_to_del.append((ctx_keys, line)) + lines_to_add_to_del.append((ctx_keys, swpx_interface)) + lines_to_add_to_del.append((tmp_ctx_keys, swpx_remoteas)) + if not deleted: found_add_line = line_exist(lines_to_add, ctx_keys, line) @@ -558,7 +611,7 @@ def compare_context_objects(newconf, running): # Compare the two Config objects to find the lines that we need to add/del lines_to_add = [] lines_to_del = [] - restart_bgpd = False + delete_bgpd = False # Find contexts that are in newconf but not in running # Find contexts that are in running but not in newconf @@ -566,17 +619,21 @@ def compare_context_objects(newconf, running): if running_ctx_keys not in newconf.contexts: - # Check if bgp's local ASN has changed. If yes, just restart it # We check that the len is 1 here so that we only look at ('router bgp 10') # and not ('router bgp 10', 'address-family ipv4 unicast'). The - # latter could cause a false restart_bgpd positive if ipv4 unicast is in + # latter could cause a false delete_bgpd positive if ipv4 unicast is in # running but not in newconf. if "router bgp" in running_ctx_keys[0] and len(running_ctx_keys) == 1: - restart_bgpd = True + delete_bgpd = True + lines_to_del.append((running_ctx_keys, None)) + + # If this is an address-family under 'router bgp' and we are already deleting the + # entire 'router bgp' context then ignore this sub-context + elif "router bgp" in running_ctx_keys[0] and len(running_ctx_keys) > 1 and delete_bgpd: continue # Non-global context - if running_ctx_keys and not any("address-family" in key for key in running_ctx_keys): + elif running_ctx_keys and not any("address-family" in key for key in running_ctx_keys): lines_to_del.append((running_ctx_keys, None)) # Global context @@ -602,11 +659,6 @@ def compare_context_objects(newconf, running): for (newconf_ctx_keys, newconf_ctx) in newconf.contexts.iteritems(): if newconf_ctx_keys not in running.contexts: - - # If its "router bgp" and we're restarting bgp, skip doing - # anything specific for bgp - if "router bgp" in newconf_ctx_keys[0] and restart_bgpd: - continue lines_to_add.append((newconf_ctx_keys, None)) for line in newconf_ctx.lines: @@ -614,7 +666,7 @@ def compare_context_objects(newconf, running): (lines_to_add, lines_to_del) = ignore_delete_re_add_lines(lines_to_add, lines_to_del) - return (lines_to_add, lines_to_del, restart_bgpd) + return (lines_to_add, lines_to_del) if __name__ == '__main__': # Command line options @@ -624,15 +676,21 @@ if __name__ == '__main__': group.add_argument('--reload', action='store_true', help='Apply the deltas', default=False) group.add_argument('--test', action='store_true', help='Show the deltas', default=False) parser.add_argument('--debug', action='store_true', help='Enable debugs', default=False) + parser.add_argument('--stdout', action='store_true', help='Log to STDOUT', default=False) parser.add_argument('filename', help='Location of new quagga config file') args = parser.parse_args() # Logging # For --test log to stdout # For --reload log to /var/log/quagga/quagga-reload.log - if args.test: + if args.test or args.stdout: logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)5s: %(message)s') + + # Color the errors and warnings in red + logging.addLevelName(logging.ERROR, "\033[91m %s\033[0m" % logging.getLevelName(logging.ERROR)) + logging.addLevelName(logging.WARNING, "\033[91m%s\033[0m" % logging.getLevelName(logging.WARNING)) + elif args.reload: if not os.path.isdir('/var/log/quagga/'): os.makedirs('/var/log/quagga/') @@ -644,7 +702,7 @@ if __name__ == '__main__': # argparse should prevent this from happening but just to be safe... else: raise Exception('Must specify --reload or --test') - logger = logging.getLogger(__name__) + log = logging.getLogger(__name__) # Verify the new config file is valid if not os.path.isfile(args.filename): @@ -657,15 +715,15 @@ if __name__ == '__main__': # Verify that 'service integrated-vtysh-config' is configured vtysh_filename = '/etc/quagga/vtysh.conf' - service_integrated_vtysh_config = False + service_integrated_vtysh_config = True if os.path.isfile(vtysh_filename): with open(vtysh_filename, 'r') as fh: for line in fh.readlines(): line = line.strip() - if line == 'service integrated-vtysh-config': - service_integrated_vtysh_config = True + if line == 'no service integrated-vtysh-config': + service_integrated_vtysh_config = False break if not service_integrated_vtysh_config: @@ -673,9 +731,9 @@ if __name__ == '__main__': sys.exit(1) if args.debug: - logger.setLevel(logging.DEBUG) + log.setLevel(logging.DEBUG) - logger.info('Called via "%s"', str(args)) + log.info('Called via "%s"', str(args)) # Create a Config object from the config generated by newconf newconf = Config() @@ -691,7 +749,7 @@ if __name__ == '__main__': else: running.load_from_show_running() - (lines_to_add, lines_to_del, restart_bgp) = compare_context_objects(newconf, running) + (lines_to_add, lines_to_del) = compare_context_objects(newconf, running) lines_to_configure = [] if lines_to_del: @@ -720,12 +778,9 @@ if __name__ == '__main__': lines_to_configure.append(cmd) print cmd - if restart_bgp: - print "BGP local AS changed, bgpd would restart" - elif args.reload: - logger.debug('New Quagga Config\n%s', newconf.get_lines()) + log.debug('New Quagga Config\n%s', newconf.get_lines()) # This looks a little odd but we have to do this twice...here is why # If the user had this running bgp config: @@ -752,9 +807,9 @@ if __name__ == '__main__': for x in range(2): running = Config() running.load_from_show_running() - logger.debug('Running Quagga Config (Pass #%d)\n%s', x, running.get_lines()) + log.debug('Running Quagga Config (Pass #%d)\n%s', x, running.get_lines()) - (lines_to_add, lines_to_del, restart_bgp) = compare_context_objects(newconf, running) + (lines_to_add, lines_to_del) = compare_context_objects(newconf, running) if lines_to_del: for (ctx_keys, line) in lines_to_del: @@ -792,17 +847,17 @@ if __name__ == '__main__': # 'no ip ospf authentication message-digest 1.1.1.1' in # our example above # - Split that last entry by whitespace and drop the last word - logger.warning('Failed to execute %s', ' '.join(cmd)) + log.warning('Failed to execute %s', ' '.join(cmd)) last_arg = cmd[-1].split(' ') if len(last_arg) <= 2: - logger.error('"%s" we failed to remove this command', original_cmd) + log.error('"%s" we failed to remove this command', original_cmd) break new_last_arg = last_arg[0:-1] cmd[-1] = ' '.join(new_last_arg) else: - logger.info('Executed "%s"', ' '.join(cmd)) + log.info('Executed "%s"', ' '.join(cmd)) break if lines_to_add: @@ -822,7 +877,7 @@ if __name__ == '__main__': string.digits) for _ in range(6)) filename = "/var/run/quagga/reload-%s.txt" % random_string - logger.info("%s content\n%s" % (filename, pformat(lines_to_configure))) + log.info("%s content\n%s" % (filename, pformat(lines_to_configure))) with open(filename, 'w') as fh: for line in lines_to_configure: @@ -830,6 +885,5 @@ if __name__ == '__main__': subprocess.call(['/usr/bin/vtysh', '-f', filename]) os.unlink(filename) - if restart_bgp: - subprocess.call(['sudo', 'systemctl', 'reset-failed', 'quagga']) - subprocess.call(['sudo', 'systemctl', '--no-block', 'restart', 'quagga']) + # Make these changes persistent + subprocess.call(['/usr/bin/vtysh', '-c', 'write']) diff --git a/vtysh/Makefile.am b/vtysh/Makefile.am index 2180a78629..ed49acca47 100644 --- a/vtysh/Makefile.am +++ b/vtysh/Makefile.am @@ -20,15 +20,43 @@ dist_examples_DATA = vtysh.conf.sample EXTRA_DIST = extract.pl -vtysh_cmd_FILES = $(top_srcdir)/bgpd/*.c $(top_srcdir)/isisd/*.c \ - $(top_srcdir)/ospfd/*.c $(top_srcdir)/ospf6d/*.c \ - $(top_srcdir)/ripd/*.c $(top_srcdir)/ripngd/*.c \ - $(top_srcdir)/pimd/pim_cmd.c \ +vtysh_scan = + +if PIMD +vtysh_scan += $(top_srcdir)/pimd/pim_cmd.c +endif + +if BGPD +vtysh_scan += $(top_srcdir)/bgpd/*.c +endif + +if ISISD +vtysh_scan += $(top_srcdir)/isisd/*.c +endif + +if OSPFD +vtysh_scan += $(top_srcdir)/ospfd/*.c +endif + +if OSPF6D +vtysh_scan += $(top_srcdir)/ospf6d/*.c +endif + +if RIPD +vtysh_scan += $(top_srcdir)/ripd/*.c +endif + +if RIPNGD +vtysh_scan += $(top_srcdir)/ripngd/*.c +endif + +vtysh_cmd_FILES = $(vtysh_scan) \ $(top_srcdir)/lib/keychain.c $(top_srcdir)/lib/routemap.c \ $(top_srcdir)/lib/filter.c $(top_srcdir)/lib/plist.c \ $(top_srcdir)/lib/distribute.c $(top_srcdir)/lib/if_rmap.c \ - $(top_srcdir)/lib/vty.c $(top_srcdir)/zebra/debug.c \ $(top_srcdir)/lib/vrf.c \ + $(top_srcdir)/lib/vty.c $(top_srcdir)/zebra/debug.c \ + $(top_srcdir)/lib/ns.c \ $(top_srcdir)/zebra/interface.c \ $(top_srcdir)/zebra/irdp_interface.c \ $(top_srcdir)/zebra/rtadv.c $(top_srcdir)/zebra/zebra_vty.c \ diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in index e8992a036a..7563daa506 100755 --- a/vtysh/extract.pl.in +++ b/vtysh/extract.pl.in @@ -36,6 +36,7 @@ EOF $ignore{'"interface IFNAME"'} = "ignore"; $ignore{'"interface IFNAME " "vrf <0-65535>"'} = "ignore"; $ignore{'"interface IFNAME " "vrf NAME"'} = "ignore"; +$ignore{'"link-params"'} = "ignore"; $ignore{'"vrf NAME"'} = "ignore"; $ignore{'"ip vrf NAME"'} = "ignore"; $ignore{'"router rip"'} = "ignore"; @@ -58,6 +59,8 @@ $ignore{'"address-family ipv4 vrf NAME"'} = "ignore"; $ignore{'"address-family encap"'} = "ignore"; $ignore{'"address-family encapv4"'} = "ignore"; $ignore{'"address-family encapv6"'} = "ignore"; +$ignore{'"address-family vpnv6"'} = "ignore"; +$ignore{'"address-family vpnv6 unicast"'} = "ignore"; $ignore{'"exit-address-family"'} = "ignore"; $ignore{'"key chain WORD"'} = "ignore"; $ignore{'"key <0-2147483647>"'} = "ignore"; @@ -118,7 +121,7 @@ foreach (@ARGV) { $protocol = "VTYSH_RIPD"; } elsif ($file =~ /lib\/routemap\.c$/) { - $protocol = "VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA"; + $protocol = "VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_PIMD"; } elsif ($file =~ /lib\/vrf\.c$/) { $protocol = "VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA"; @@ -126,11 +129,14 @@ foreach (@ARGV) { elsif ($file =~ /lib\/filter\.c$/) { $protocol = "VTYSH_ALL"; } + elsif ($file =~ /lib\/ns\.c$/) { + $protocol = "VTYSH_ZEBRA"; + } elsif ($file =~ /lib\/plist\.c$/) { if ($defun_array[1] =~ m/ipv6/) { $protocol = "VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA"; } else { - $protocol = "VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD|VTYSH_ZEBRA"; + $protocol = "VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_PIMD"; } } elsif ($file =~ /lib\/distribute\.c$/) { diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 9d4061cfcf..18ca0dca29 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -37,9 +37,11 @@ #include "linklist.h" #include "command.h" #include "memory.h" +#include "filter.h" #include "vtysh/vtysh.h" #include "log.h" #include "bgpd/bgp_vty.h" +#include "ns.h" #include "vrf.h" #include "lib/grammar_sandbox.h" @@ -73,7 +75,7 @@ struct vtysh_client vtysh_client[] = }; /* Using integrated config from Quagga.conf. Default is no. */ -int vtysh_writeconfig_integrated = 0; +int vtysh_writeconfig_integrated = 1; extern char config_default[]; @@ -506,6 +508,28 @@ vtysh_execute (const char *line) return vtysh_execute_func (line, 1); } +static char * +trim (char *s) +{ + size_t size; + char *end; + + size = strlen(s); + + if (!size) + return s; + + end = s + size - 1; + while (end >= s && isspace(*end)) + end--; + *(end + 1) = '\0'; + + while (*s && isspace(*s)) + s++; + + return s; +} + int vtysh_mark_file (const char *filename) { @@ -517,6 +541,8 @@ vtysh_mark_file (const char *filename) struct cmd_element *cmd; int saved_ret, prev_node; int lineno = 0; + char *vty_buf_copy = NULL; + char *vty_buf_trimmed = NULL; if (strncmp("-", filename, 1) == 0) confp = stdin; @@ -537,13 +563,16 @@ vtysh_mark_file (const char *filename) vtysh_execute_no_pager ("enable"); vtysh_execute_no_pager ("configure terminal"); + vty_buf_copy = XCALLOC (MTYPE_VTY, VTY_BUFSIZ); while (fgets (vty->buf, VTY_BUFSIZ, confp)) { lineno++; tried = 0; + strcpy(vty_buf_copy, vty->buf); + vty_buf_trimmed = trim(vty_buf_copy); - if (vty->buf[0] == '!' || vty->buf[1] == '#') + if (vty_buf_trimmed[0] == '!' || vty_buf_trimmed[0] == '#') { fprintf(stdout, "%s", vty->buf); continue; @@ -558,6 +587,12 @@ vtysh_mark_file (const char *filename) continue; } + /* Ignore the "end" lines, we will generate these where appropriate */ + if (strlen(vty_buf_trimmed) == 3 && strncmp("end", vty_buf_trimmed, 3) == 0) + { + continue; + } + prev_node = vty->node; saved_ret = ret = cmd_execute_command_strict (vline, vty, &cmd); @@ -608,21 +643,25 @@ vtysh_mark_file (const char *filename) fprintf (stderr,"line %d: Warning...: %s\n", lineno, vty->buf); fclose(confp); vty_close(vty); + XFREE(MTYPE_VTY, vty_buf_copy); return CMD_WARNING; case CMD_ERR_AMBIGUOUS: fprintf (stderr,"line %d: %% Ambiguous command: %s\n", lineno, vty->buf); fclose(confp); vty_close(vty); + XFREE(MTYPE_VTY, vty_buf_copy); return CMD_ERR_AMBIGUOUS; case CMD_ERR_NO_MATCH: fprintf (stderr,"line %d: %% Unknown command: %s\n", lineno, vty->buf); fclose(confp); vty_close(vty); + XFREE(MTYPE_VTY, vty_buf_copy); return CMD_ERR_NO_MATCH; case CMD_ERR_INCOMPLETE: fprintf (stderr,"line %d: %% Command incomplete: %s\n", lineno, vty->buf); fclose(confp); vty_close(vty); + XFREE(MTYPE_VTY, vty_buf_copy); return CMD_ERR_INCOMPLETE; case CMD_SUCCESS: fprintf(stdout, "%s", vty->buf); @@ -654,6 +693,7 @@ vtysh_mark_file (const char *filename) /* This is the end */ fprintf(stdout, "end\n"); vty_close(vty); + XFREE(MTYPE_VTY, vty_buf_copy); if (confp != stdin) fclose(confp); @@ -847,7 +887,10 @@ command_generator (const char *text, int state) if (rl_end && isspace ((int) rl_line_buffer[rl_end - 1])) vector_set (vline, NULL); + if (matched) + XFREE (MTYPE_TMP, matched); matched = cmd_complete_command (vline, vty, &complete_status); + cmd_free_strvec (vline); } if (matched && matched[index]) @@ -899,6 +942,12 @@ static struct cmd_node interface_node = "%s(config-if)# ", }; +static struct cmd_node ns_node = +{ + NS_NODE, + "%s(config-logical-router)# ", +}; + static struct cmd_node vrf_node = { VRF_NODE, @@ -995,6 +1044,12 @@ static struct cmd_node keychain_key_node = "%s(config-keychain-key)# " }; +struct cmd_node link_params_node = +{ + LINK_PARAMS_NODE, + "%s(config-link-params)# ", +}; + /* Defined in lib/vty.c */ extern struct cmd_node vty_node; @@ -1348,6 +1403,7 @@ vtysh_exit (struct vty *vty) vty->node = ENABLE_NODE; break; case INTERFACE_NODE: + case NS_NODE: case VRF_NODE: case ZEBRA_NODE: case BGP_NODE: @@ -1377,6 +1433,9 @@ vtysh_exit (struct vty *vty) case KEYCHAIN_KEY_NODE: vty->node = KEYCHAIN_NODE; break; + case LINK_PARAMS_NODE: + vty->node = INTERFACE_NODE; + break; default: break; } @@ -1576,6 +1635,19 @@ DEFSH (VTYSH_ZEBRA, "Interface's name\n" VRF_CMD_HELP_STR) +DEFUNSH (VTYSH_NS, + vtysh_ns, + vtysh_ns_cmd, + "logical-router <1-65535 ns NAME", + "Enable a logical-router\n" + "Specify the logical-router indentifier\n" + "The Name Space\n" + "The file name in " NS_RUN_DIR ", or a full pathname\n") +{ + vty->node = NS_NODE; + return CMD_SUCCESS; +} + DEFUNSH (VTYSH_VRF, vtysh_vrf, vtysh_vrf_cmd, @@ -1594,6 +1666,20 @@ DEFSH (VTYSH_ZEBRA, "Delete a pseudo vrf's configuration\n" "VRF's name\n") +DEFUNSH (VTYSH_NS, + vtysh_exit_ns, + vtysh_exit_ns_cmd, + "exit", + "Exit current mode and down to previous mode\n") +{ + return vtysh_exit (vty); +} + +ALIAS (vtysh_exit_ns, + vtysh_quit_ns_cmd, + "quit", + "Exit current mode and down to previous mode\n") + DEFUNSH (VTYSH_VRF, vtysh_exit_vrf, vtysh_exit_vrf_cmd, @@ -1709,6 +1795,17 @@ DEFUN (vtysh_show_work_queues_daemon, return ret; } +DEFUNSH (VTYSH_ZEBRA, + vtysh_link_params, + vtysh_link_params_cmd, + "link-params", + LINK_PARAMS_STR + ) +{ + vty->node = LINK_PARAMS_NODE; + return CMD_SUCCESS; +} + /* Memory */ DEFUN (vtysh_show_memory, vtysh_show_memory_cmd, @@ -2099,7 +2196,8 @@ DEFUN (vtysh_write_terminal, vty_out (vty, "!%s", VTY_NEWLINE); for (i = 0; i < array_size(vtysh_client); i++) - vtysh_client_config (&vtysh_client[i], line); + if ((argc < 1 ) || (begins_with(vtysh_client[i].name, argv[0]))) + vtysh_client_config (&vtysh_client[i], line); /* Integrate vtysh specific configuration. */ vtysh_config_write (); @@ -2319,7 +2417,7 @@ ALIAS (vtysh_write_terminal, SHOW_STR "Current operating configuration\n") -ALIAS (vtysh_write_terminal_daemon, +ALIAS (vtysh_write_terminal, vtysh_show_running_config_daemon_cmd, "show running-config (zebra|ripd|ripngd|ospfd|ospf6d|bgpd|isisd|pimd)", SHOW_STR @@ -2805,6 +2903,8 @@ vtysh_init_vty (void) install_node (&bgp_node, NULL); install_node (&rip_node, NULL); install_node (&interface_node, NULL); + install_node (&link_params_node, NULL); + install_node (&ns_node, NULL); install_node (&vrf_node, NULL); install_node (&rmap_node, NULL); install_node (&zebra_node, NULL); @@ -2834,6 +2934,8 @@ vtysh_init_vty (void) vtysh_install_default (BGP_NODE); vtysh_install_default (RIP_NODE); vtysh_install_default (INTERFACE_NODE); + vtysh_install_default (LINK_PARAMS_NODE); + vtysh_install_default (NS_NODE); vtysh_install_default (VRF_NODE); vtysh_install_default (RMAP_NODE); vtysh_install_default (ZEBRA_NODE); @@ -2927,8 +3029,14 @@ vtysh_init_vty (void) install_element (INTERFACE_NODE, &no_interface_desc_cmd); install_element (INTERFACE_NODE, &vtysh_end_all_cmd); install_element (INTERFACE_NODE, &vtysh_exit_interface_cmd); + install_element (LINK_PARAMS_NODE, &vtysh_end_all_cmd); + install_element (LINK_PARAMS_NODE, &vtysh_exit_interface_cmd); install_element (INTERFACE_NODE, &vtysh_quit_interface_cmd); + install_element (NS_NODE, &vtysh_end_all_cmd); + install_element (NS_NODE, &vtysh_exit_ns_cmd); + install_element (NS_NODE, &vtysh_quit_ns_cmd); + install_element (VRF_NODE, &vtysh_end_all_cmd); install_element (VRF_NODE, &vtysh_exit_vrf_cmd); install_element (VRF_NODE, &vtysh_quit_vrf_cmd); @@ -2977,6 +3085,7 @@ vtysh_init_vty (void) install_element (CONFIG_NODE, &vtysh_no_interface_cmd); install_element (CONFIG_NODE, &vtysh_interface_vrf_cmd); install_element (CONFIG_NODE, &vtysh_no_interface_vrf_cmd); + install_element (INTERFACE_NODE, &vtysh_link_params_cmd); install_element (ENABLE_NODE, &vtysh_show_running_config_cmd); install_element (ENABLE_NODE, &vtysh_show_running_config_daemon_cmd); install_element (ENABLE_NODE, &vtysh_copy_runningconfig_startupconfig_cmd); diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h index e974cf331c..75822b1363 100644 --- a/vtysh/vtysh.h +++ b/vtysh/vtysh.h @@ -34,6 +34,7 @@ #define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD #define VTYSH_RMAP VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_PIMD #define VTYSH_INTERFACE VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_PIMD +#define VTYSH_NS VTYSH_ZEBRA #define VTYSH_VRF VTYSH_ZEBRA /* vtysh local configuration file. */ diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index fcad333b9f..118b7ba035 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -171,6 +171,7 @@ vtysh_config_parse_line (const char *line) { if (config->index == RMAP_NODE || config->index == INTERFACE_NODE || + config->index == NS_NODE || config->index == VRF_NODE || config->index == VTY_NODE) config_add_line_uniq (config->line, line); @@ -183,6 +184,8 @@ vtysh_config_parse_line (const char *line) default: if (strncmp (line, "interface", strlen ("interface")) == 0) config = config_get (INTERFACE_NODE, line); + else if (strncmp (line, "logical-router", strlen ("ns")) == 0) + config = config_get (NS_NODE, line); else if (strncmp (line, "vrf", strlen ("vrf")) == 0) config = config_get (VRF_NODE, line); else if (strncmp (line, "router-id", strlen ("router-id")) == 0) @@ -318,7 +321,14 @@ vtysh_config_dump (FILE *fp) if ((master = vector_slot (configvec, i)) != NULL) { for (ALL_LIST_ELEMENTS (master, node, nnode, config)) - { + { + /* Don't print empty sections for interface/vrf. Route maps on the + * other hand could have a legitimate empty section at the end. + */ + if ((config->index == INTERFACE_NODE || (config->index == VRF_NODE)) + && list_isempty (config->line)) + continue; + fprintf (fp, "%s\n", config->name); fflush (fp); @@ -412,8 +422,8 @@ vtysh_config_write () sprintf (line, "hostname %s", host.name); vtysh_config_parse_line(line); } - if (vtysh_writeconfig_integrated) - vtysh_config_parse_line ("service integrated-vtysh-config"); + if (!vtysh_writeconfig_integrated) + vtysh_config_parse_line ("no service integrated-vtysh-config"); user_config_write (); } diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c index cd21c94efd..3c46194d31 100644 --- a/vtysh/vtysh_main.c +++ b/vtysh/vtysh_main.c @@ -317,7 +317,7 @@ main (int argc, char **argv, char **env) case 'c': { struct cmd_rec *cr; - cr = XMALLOC(0, sizeof(*cr)); + cr = XMALLOC(MTYPE_TMP, sizeof(*cr)); cr->line = optarg; cr->next = NULL; if (tail) @@ -415,7 +415,10 @@ main (int argc, char **argv, char **env) if (vtysh_connect_all (daemon_name) <= 0) { fprintf(stderr, "Exiting: failed to connect to any daemons.\n"); - exit(1); + if (no_error) + exit(0); + else + exit(1); } if (inputfile) @@ -501,7 +504,7 @@ main (int argc, char **argv, char **env) struct cmd_rec *cr; cr = cmd; cmd = cmd->next; - XFREE(0, cr); + XFREE(MTYPE_TMP, cr); } } diff --git a/vtysh/vtysh_user.c b/vtysh/vtysh_user.c index 0d72c378a3..1886ba3a67 100644 --- a/vtysh/vtysh_user.c +++ b/vtysh/vtysh_user.c @@ -116,7 +116,7 @@ struct list *userlist; static struct vtysh_user * user_new (void) { - return XCALLOC (0, sizeof (struct vtysh_user)); + return XCALLOC (MTYPE_TMP, sizeof (struct vtysh_user)); } static struct vtysh_user * @@ -195,7 +195,11 @@ vtysh_auth (void) struct vtysh_user *user; struct passwd *passwd; - passwd = getpwuid (geteuid ()); + if ((passwd = getpwuid (geteuid ())) == NULL) + { + fprintf (stderr, "could not lookup user ID %d\n", (int) geteuid()); + exit (1); + } user = user_lookup (passwd->pw_name); if (user && user->nopassword) diff --git a/watchquagga/watchquagga.c b/watchquagga/watchquagga.c index 2a237efb6a..e882653e38 100644 --- a/watchquagga/watchquagga.c +++ b/watchquagga/watchquagga.c @@ -1337,8 +1337,6 @@ main(int argc, char **argv) zlog_default = openzlog(progname, ZLOG_NONE, 0, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); - zlog_set_file (NULL, LOG_DEFAULT_FILENAME, zlog_default->default_lvl); - zlog_set_level(NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED); if (daemon_mode) { diff --git a/zebra/Makefile.am b/zebra/Makefile.am index 4492f9e6d4..0218af81b7 100644 --- a/zebra/Makefile.am +++ b/zebra/Makefile.am @@ -31,19 +31,19 @@ zebra_SOURCES = \ redistribute.c debug.c rtadv.c zebra_snmp.c zebra_vty.c \ irdp_main.c irdp_interface.c irdp_packet.c router-id.c zebra_fpm.c \ $(othersrc) zebra_ptm.c zebra_rnh.c zebra_ptm_redistribute.c \ - zebra_ns.c zebra_vrf.c + zebra_ns.c zebra_vrf.c zebra_static.c testzebra_SOURCES = test_main.c zebra_rib.c interface.c connected.c debug.c \ zebra_vty.c zebra_ptm.c zebra_routemap.c zebra_ns.c zebra_vrf.c \ kernel_null.c redistribute_null.c ioctl_null.c misc_null.c zebra_rnh_null.c \ - zebra_ptm_null.c rtadv_null.c if_null.c zserv_null.c + zebra_ptm_null.c rtadv_null.c if_null.c zserv_null.c zebra_static.c noinst_HEADERS = \ connected.h ioctl.h rib.h rt.h zserv.h redistribute.h debug.h rtadv.h \ interface.h ipforward.h irdp.h router-id.h kernel_socket.h \ rt_netlink.h zebra_fpm.h zebra_fpm_private.h zebra_rnh.h \ zebra_ptm_redistribute.h zebra_ptm.h zebra_routemap.h \ - zebra_ns.h zebra_vrf.h ioctl_solaris.h + zebra_ns.h zebra_vrf.h ioctl_solaris.h zebra_static.h zebra_LDADD = $(otherobj) ../lib/libzebra.la $(LIBCAP) diff --git a/zebra/connected.c b/zebra/connected.c index 42b5a8ab9c..6e82e6ec78 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -185,26 +185,28 @@ connected_update(struct interface *ifp, struct connected *ifc) void connected_up_ipv4 (struct interface *ifp, struct connected *ifc) { - struct prefix_ipv4 p; + struct prefix p; if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) return; - PREFIX_COPY_IPV4(&p, CONNECTED_PREFIX(ifc)); + PREFIX_COPY_IPV4((struct prefix_ipv4 *)&p, CONNECTED_PREFIX(ifc)); /* Apply mask to the network. */ - apply_mask_ipv4 (&p); + apply_mask (&p); /* In case of connected address is 0.0.0.0/0 we treat it tunnel address. */ - if (prefix_ipv4_any (&p)) + if (prefix_ipv4_any ((struct prefix_ipv4 *)&p)) return; - rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, 0, &p, NULL, NULL, ifp->ifindex, - ifp->vrf_id, RT_TABLE_MAIN, ifp->metric, 0, SAFI_UNICAST); + rib_add (AFI_IP, SAFI_UNICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, + 0, 0, &p, NULL, NULL, ifp->ifindex, + RT_TABLE_MAIN, ifp->metric, 0, 0); - rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, 0, &p, NULL, NULL, ifp->ifindex, - ifp->vrf_id, RT_TABLE_MAIN, ifp->metric, 0, SAFI_MULTICAST); + rib_add (AFI_IP, SAFI_MULTICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, + 0, 0, &p, NULL, NULL, ifp->ifindex, + RT_TABLE_MAIN, ifp->metric, 0, 0); if (IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug ("%u: IF %s IPv4 address add/up, scheduling RIB processing", @@ -303,7 +305,7 @@ connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr, void connected_down_ipv4 (struct interface *ifp, struct connected *ifc) { - struct prefix_ipv4 p; + struct prefix p; if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) return; @@ -311,19 +313,19 @@ connected_down_ipv4 (struct interface *ifp, struct connected *ifc) PREFIX_COPY_IPV4(&p, CONNECTED_PREFIX(ifc)); /* Apply mask to the network. */ - apply_mask_ipv4 (&p); + apply_mask (&p); /* In case of connected address is 0.0.0.0/0 we treat it tunnel address. */ - if (prefix_ipv4_any (&p)) + if (prefix_ipv4_any ((struct prefix_ipv4 *)&p)) return; /* Same logic as for connected_up_ipv4(): push the changes into the head. */ - rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, 0, &p, NULL, ifp->ifindex, ifp->vrf_id, 0, - SAFI_UNICAST); + rib_delete (AFI_IP, SAFI_UNICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, + 0, 0, &p, NULL, ifp->ifindex, 0); - rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, 0, &p, NULL, ifp->ifindex, ifp->vrf_id, 0, - SAFI_MULTICAST); + rib_delete (AFI_IP, SAFI_MULTICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, + 0, 0, &p, NULL, ifp->ifindex, 0); if (IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug ("%u: IF %s IPv4 address down, scheduling RIB processing", @@ -358,28 +360,28 @@ connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr, rib_update (ifp->vrf_id, RIB_UPDATE_IF_CHANGE); } -#ifdef HAVE_IPV6 void connected_up_ipv6 (struct interface *ifp, struct connected *ifc) { - struct prefix_ipv6 p; + struct prefix p; if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) return; - PREFIX_COPY_IPV6(&p, CONNECTED_PREFIX(ifc)); + PREFIX_COPY_IPV6((struct prefix_ipv6 *)&p, CONNECTED_PREFIX(ifc)); /* Apply mask to the network. */ - apply_mask_ipv6 (&p); + apply_mask (&p); #ifndef LINUX - /* XXX: It is already done by rib_bogus_ipv6 within rib_add_ipv6 */ - if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix)) + /* XXX: It is already done by rib_bogus_ipv6 within rib_add */ + if (IN6_IS_ADDR_UNSPECIFIED (&p.u.prefix6)) return; #endif - rib_add_ipv6 (ZEBRA_ROUTE_CONNECT, 0, 0, &p, NULL, ifp->ifindex, ifp->vrf_id, - RT_TABLE_MAIN, ifp->metric, 0, SAFI_UNICAST); + rib_add (AFI_IP6, SAFI_UNICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, + 0, 0, &p, NULL, NULL, ifp->ifindex, + RT_TABLE_MAIN, ifp->metric, 0, 0); if (IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug ("%u: IF %s IPv6 address down, scheduling RIB processing", @@ -456,20 +458,20 @@ connected_add_ipv6 (struct interface *ifp, int flags, struct in6_addr *addr, void connected_down_ipv6 (struct interface *ifp, struct connected *ifc) { - struct prefix_ipv6 p; + struct prefix p; if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) return; PREFIX_COPY_IPV6(&p, CONNECTED_PREFIX(ifc)); - apply_mask_ipv6 (&p); + apply_mask (&p); - if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix)) + if (IN6_IS_ADDR_UNSPECIFIED (&p.u.prefix6)) return; - rib_delete_ipv6 (ZEBRA_ROUTE_CONNECT, 0, 0, &p, NULL, ifp->ifindex, - ifp->vrf_id, 0, SAFI_UNICAST); + rib_delete (AFI_IP6, SAFI_UNICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, + 0, 0, &p, NULL, ifp->ifindex, 0); if (IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug ("%u: IF %s IPv6 address down, scheduling RIB processing", @@ -502,7 +504,6 @@ connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address, rib_update (ifp->vrf_id, RIB_UPDATE_IF_CHANGE); } -#endif /* HAVE_IPV6 */ int connected_is_unnumbered (struct interface *ifp) diff --git a/zebra/if_ioctl.c b/zebra/if_ioctl.c index 88fea3427f..0a9807b8b9 100644 --- a/zebra/if_ioctl.c +++ b/zebra/if_ioctl.c @@ -427,7 +427,7 @@ interface_info_ioctl () struct listnode *node, *nnode; struct interface *ifp; - for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp)) + for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), node, nnode, ifp)) { if_get_index (ifp); #ifdef SIOCGIFHWADDR diff --git a/zebra/interface.c b/zebra/interface.c index 87a426fdc4..2b1e6f4ac6 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -39,6 +39,7 @@ #include "zebra_vrf.h" #include "zebra/interface.h" #include "zebra/rib.h" +#include "zebra/rt.h" #include "zebra/zserv.h" #include "zebra/redistribute.h" #include "zebra/debug.h" @@ -280,7 +281,7 @@ if_subnet_delete (struct interface *ifp, struct connected *ifc) /* If deleted address is primary, mark subsequent one as such and distribute. */ if (! CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY)) { - ifc = listgetdata (listhead (addr_list)); + ifc = listgetdata ((struct listnode *)listhead (addr_list)); zebra_interface_address_delete_update (ifp, ifc); UNSET_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY); /* XXX: Linux kernel removes all the secondary addresses when the primary @@ -744,8 +745,7 @@ if_nbr_ipv6ll_to_ipv4ll_neigh_update (struct interface *ifp, inet_pton (AF_INET, buf, &ipv4_ll); ipv6_ll_address_to_mac(address, (u_char *)mac); - netlink_neigh_update (add ? RTM_NEWNEIGH : RTM_DELNEIGH, - ifp->ifindex, ipv4_ll.s_addr, mac, 6); + kernel_neigh_update (add, ifp->ifindex, ipv4_ll.s_addr, mac, 6); } static void @@ -991,9 +991,6 @@ nd_dump_vty (struct vty *vty, struct interface *ifp) static void if_dump_vty (struct vty *vty, struct interface *ifp) { -#ifdef HAVE_STRUCT_SOCKADDR_DL - struct sockaddr_dl *sdl; -#endif /* HAVE_STRUCT_SOCKADDR_DL */ struct connected *connected; struct nbr_connected *nbr_connected; struct listnode *node; @@ -1055,19 +1052,7 @@ if_dump_vty (struct vty *vty, struct interface *ifp) if_flag_dump (ifp->flags), VTY_NEWLINE); /* Hardware address. */ -#ifdef HAVE_STRUCT_SOCKADDR_DL - sdl = &ifp->sdl; - if (sdl != NULL && sdl->sdl_alen != 0) - { - int i; - u_char *ptr; - - vty_out (vty, " HWaddr: "); - for (i = 0, ptr = (u_char *)LLADDR (sdl); i < sdl->sdl_alen; i++, ptr++) - vty_out (vty, "%s%02x", i == 0 ? "" : ":", *ptr); - vty_out (vty, "%s", VTY_NEWLINE); - } -#else + vty_out (vty, " Type: %s%s", if_link_type_str (ifp->ll_type), VTY_NEWLINE); if (ifp->hw_addr_len != 0) { int i; @@ -1077,7 +1062,6 @@ if_dump_vty (struct vty *vty, struct interface *ifp) vty_out (vty, "%s%02x", i == 0 ? "" : ":", ifp->hw_addr[i]); vty_out (vty, "%s", VTY_NEWLINE); } -#endif /* HAVE_STRUCT_SOCKADDR_DL */ /* Bandwidth in Mbps */ if (ifp->bandwidth != 0) @@ -1090,7 +1074,7 @@ if_dump_vty (struct vty *vty, struct interface *ifp) { if (! rn->info) continue; - + for (ALL_LIST_ELEMENTS_RO ((struct list *)rn->info, node, connected)) connected_dump_vty (vty, connected); } @@ -1102,6 +1086,53 @@ if_dump_vty (struct vty *vty, struct interface *ifp) connected_dump_vty (vty, connected); } + if (HAS_LINK_PARAMS(ifp)) + { + int i; + struct if_link_params *iflp = ifp->link_params; + vty_out(vty, " Traffic Engineering Link Parameters:%s", VTY_NEWLINE); + if (IS_PARAM_SET(iflp, LP_TE)) + vty_out(vty, " TE metric %u%s",iflp->te_metric, VTY_NEWLINE); + if (IS_PARAM_SET(iflp, LP_MAX_BW)) + vty_out(vty, " Maximum Bandwidth %g (Byte/s)%s", iflp->max_bw, VTY_NEWLINE); + if (IS_PARAM_SET(iflp, LP_MAX_RSV_BW)) + vty_out(vty, " Maximum Reservable Bandwidth %g (Byte/s)%s", iflp->max_rsv_bw, VTY_NEWLINE); + if (IS_PARAM_SET(iflp, LP_UNRSV_BW)) { + vty_out(vty, " Unreserved Bandwidth per Class Type in Byte/s:%s", VTY_NEWLINE); + for (i = 0; i < MAX_CLASS_TYPE; i+=2) + vty_out(vty, " [%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)%s", + i, iflp->unrsv_bw[i], i+1, iflp->unrsv_bw[i+1], VTY_NEWLINE); + } + + if (IS_PARAM_SET(iflp, LP_ADM_GRP)) + vty_out(vty, " Administrative Group:%u%s", iflp->admin_grp, VTY_NEWLINE); + if (IS_PARAM_SET(iflp, LP_DELAY)) + { + vty_out(vty, " Link Delay Average: %u (micro-sec.)", iflp->av_delay); + if (IS_PARAM_SET(iflp, LP_MM_DELAY)) + { + vty_out(vty, " Min: %u (micro-sec.)", iflp->min_delay); + vty_out(vty, " Max: %u (micro-sec.)", iflp->max_delay); + } + vty_out(vty, "%s", VTY_NEWLINE); + } + if (IS_PARAM_SET(iflp, LP_DELAY_VAR)) + vty_out(vty, " Link Delay Variation %u (micro-sec.)%s", iflp->delay_var, VTY_NEWLINE); + if (IS_PARAM_SET(iflp, LP_PKT_LOSS)) + vty_out(vty, " Link Packet Loss %g (in %%)%s", iflp->pkt_loss, VTY_NEWLINE); + if (IS_PARAM_SET(iflp, LP_AVA_BW)) + vty_out(vty, " Available Bandwidth %g (Byte/s)%s", iflp->ava_bw, VTY_NEWLINE); + if (IS_PARAM_SET(iflp, LP_RES_BW)) + vty_out(vty, " Residual Bandwidth %g (Byte/s)%s", iflp->res_bw, VTY_NEWLINE); + if (IS_PARAM_SET(iflp, LP_USE_BW)) + vty_out(vty, " Utilized Bandwidth %g (Byte/s)%s", iflp->use_bw, VTY_NEWLINE); + if (IS_PARAM_SET(iflp, LP_RMT_AS)) + vty_out(vty, " Neighbor ASBR IP: %s AS: %u %s", inet_ntoa(iflp->rmt_ip), iflp->rmt_as, VTY_NEWLINE); + } + + #ifdef RTADV + nd_dump_vty (vty, ifp); + #endif /* RTADV */ #if defined (HAVE_RTADV) nd_dump_vty (vty, ifp); #endif /* HAVE_RTADV */ @@ -1201,13 +1232,13 @@ DEFUN_NOSH (zebra_interface, "Interface's name\n") { int ret; - struct interface * ifp; + struct interface *ifp; /* Call lib interface() */ if ((ret = interface_cmd.func (self, vty, argc, argv)) != CMD_SUCCESS) return ret; - ifp = vty->index; + ifp = vty->index; if (ifp->ifindex == IFINDEX_INTERNAL) /* Is this really necessary? Shouldn't status be initialized to 0 @@ -1706,6 +1737,692 @@ ALIAS (no_bandwidth_if, "Set bandwidth informational parameter\n" "Bandwidth in megabits\n") +struct cmd_node link_params_node = +{ + LINK_PARAMS_NODE, + "%s(config-link-params)# ", + 1, +}; + +static void +link_param_cmd_set_uint32 (struct interface *ifp, uint32_t *field, + uint32_t type, uint32_t value) +{ + /* Update field as needed */ + if (IS_PARAM_UNSET(ifp->link_params, type) || *field != value) + { + *field = value; + SET_PARAM(ifp->link_params, type); + + /* force protocols to update LINK STATE due to parameters change */ + if (if_is_operative (ifp)) + zebra_interface_parameters_update (ifp); + } +} +static void +link_param_cmd_set_float (struct interface *ifp, float *field, + uint32_t type, float value) +{ + + /* Update field as needed */ + if (IS_PARAM_UNSET(ifp->link_params, type) || *field != value) + { + *field = value; + SET_PARAM(ifp->link_params, type); + + /* force protocols to update LINK STATE due to parameters change */ + if (if_is_operative (ifp)) + zebra_interface_parameters_update (ifp); + } +} + +static void +link_param_cmd_unset (struct interface *ifp, uint32_t type) +{ + + /* Unset field */ + UNSET_PARAM(ifp->link_params, type); + + /* force protocols to update LINK STATE due to parameters change */ + if (if_is_operative (ifp)) + zebra_interface_parameters_update (ifp); +} + +DEFUN (link_params, + link_params_cmd, + "link-params", + LINK_PARAMS_STR) +{ + vty->node = LINK_PARAMS_NODE; + + return CMD_SUCCESS; +} + +/* Specific Traffic Engineering parameters commands */ +DEFUN (link_params_enable, + link_params_enable_cmd, + "enable", + "Activate link parameters on this interface\n") +{ + struct interface *ifp = (struct interface *) vty->index; + + /* This command could be issue at startup, when activate MPLS TE */ + /* on a new interface or after a ON / OFF / ON toggle */ + /* In all case, TE parameters are reset to their default factory */ + if (IS_ZEBRA_DEBUG_EVENT) + zlog_debug ("Link-params: enable TE link parameters on interface %s", ifp->name); + + if (!if_link_params_get (ifp)) + { + if (IS_ZEBRA_DEBUG_EVENT) + zlog_debug ("Link-params: failed to init TE link parameters %s", ifp->name); + + return CMD_WARNING; + } + + /* force protocols to update LINK STATE due to parameters change */ + if (if_is_operative (ifp)) + zebra_interface_parameters_update (ifp); + + return CMD_SUCCESS; +} + +DEFUN (no_link_params_enable, + no_link_params_enable_cmd, + "no enable", + NO_STR + "Disable link parameters on this interface\n") +{ + struct interface *ifp = (struct interface *) vty->index; + + zlog_debug ("MPLS-TE: disable TE link parameters on interface %s", ifp->name); + + if_link_params_free (ifp); + + /* force protocols to update LINK STATE due to parameters change */ + if (if_is_operative (ifp)) + zebra_interface_parameters_update (ifp); + + return CMD_SUCCESS; +} + +/* STANDARD TE metrics */ +DEFUN (link_params_metric, + link_params_metric_cmd, + "metric <0-4294967295>", + "Link metric for MPLS-TE purpose\n" + "Metric value in decimal\n") +{ + struct interface *ifp = (struct interface *) vty->index; + struct if_link_params *iflp = if_link_params_get (ifp); + u_int32_t metric; + + VTY_GET_ULONG("metric", metric, argv[0]); + + /* Update TE metric if needed */ + link_param_cmd_set_uint32 (ifp, &iflp->te_metric, LP_TE, metric); + + return CMD_SUCCESS; +} + +DEFUN (no_link_params_metric, + no_link_params_metric_cmd, + "no metric", + NO_STR + "Disbale Link Metric on this interface\n") +{ + struct interface *ifp = (struct interface *) vty->index; + + /* Unset TE Metric */ + link_param_cmd_unset(ifp, LP_TE); + + return CMD_SUCCESS; +} + +DEFUN (link_params_maxbw, + link_params_maxbw_cmd, + "max-bw BANDWIDTH", + "Maximum bandwidth that can be used\n" + "Bytes/second (IEEE floating point format)\n") +{ + struct interface *ifp = (struct interface *) vty->index; + struct if_link_params *iflp = if_link_params_get (ifp); + + float bw; + + if (sscanf (argv[0], "%g", &bw) != 1) + { + vty_out (vty, "link_params_maxbw: fscanf: %s%s", safe_strerror (errno), + VTY_NEWLINE); + return CMD_WARNING; + } + + /* Check that Maximum bandwidth is not lower than other bandwidth parameters */ + if ((bw <= iflp->max_rsv_bw) + || (bw <= iflp->unrsv_bw[0]) + || (bw <= iflp->unrsv_bw[1]) + || (bw <= iflp->unrsv_bw[2]) + || (bw <= iflp->unrsv_bw[3]) + || (bw <= iflp->unrsv_bw[4]) + || (bw <= iflp->unrsv_bw[5]) + || (bw <= iflp->unrsv_bw[6]) + || (bw <= iflp->unrsv_bw[7]) + || (bw <= iflp->ava_bw) + || (bw <= iflp->res_bw) + || (bw <= iflp->use_bw)) + { + vty_out (vty, + "Maximum Bandwidth could not be lower than others bandwidth%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + /* Update Maximum Bandwidth if needed */ + link_param_cmd_set_float (ifp, &iflp->max_bw, LP_MAX_BW, bw); + + return CMD_SUCCESS; +} + +DEFUN (link_params_max_rsv_bw, + link_params_max_rsv_bw_cmd, + "max-rsv-bw BANDWIDTH", + "Maximum bandwidth that may be reserved\n" + "Bytes/second (IEEE floating point format)\n") +{ + struct interface *ifp = (struct interface *) vty->index; + struct if_link_params *iflp = if_link_params_get (ifp); + float bw; + + if (sscanf (argv[0], "%g", &bw) != 1) + { + vty_out (vty, "link_params_max_rsv_bw: fscanf: %s%s", safe_strerror (errno), + VTY_NEWLINE); + return CMD_WARNING; + } + + /* Check that bandwidth is not greater than maximum bandwidth parameter */ + if (bw > iflp->max_bw) + { + vty_out (vty, + "Maximum Reservable Bandwidth could not be greater than Maximum Bandwidth (%g)%s", + iflp->max_bw, VTY_NEWLINE); + return CMD_WARNING; + } + + /* Update Maximum Reservable Bandwidth if needed */ + link_param_cmd_set_float (ifp, &iflp->max_rsv_bw, LP_MAX_RSV_BW, bw); + + return CMD_SUCCESS; +} + +DEFUN (link_params_unrsv_bw, + link_params_unrsv_bw_cmd, + "unrsv-bw <0-7> BANDWIDTH", + "Unreserved bandwidth at each priority level\n" + "Priority\n" + "Bytes/second (IEEE floating point format)\n") +{ + struct interface *ifp = (struct interface *) vty->index; + struct if_link_params *iflp = if_link_params_get (ifp); + int priority; + float bw; + + /* We don't have to consider about range check here. */ + if (sscanf (argv[0], "%d", &priority) != 1) + { + vty_out (vty, "link_params_unrsv_bw: fscanf: %s%s", safe_strerror (errno), + VTY_NEWLINE); + return CMD_WARNING; + } + + if (sscanf (argv[1], "%g", &bw) != 1) + { + vty_out (vty, "link_params_unrsv_bw: fscanf: %s%s", safe_strerror (errno), + VTY_NEWLINE); + return CMD_WARNING; + } + + /* Check that bandwidth is not greater than maximum bandwidth parameter */ + if (bw > iflp->max_bw) + { + vty_out (vty, + "UnReserved Bandwidth could not be greater than Maximum Bandwidth (%g)%s", + iflp->max_bw, VTY_NEWLINE); + return CMD_WARNING; + } + + /* Update Unreserved Bandwidth if needed */ + link_param_cmd_set_float (ifp, &iflp->unrsv_bw[priority], LP_UNRSV_BW, bw); + + return CMD_SUCCESS; +} + +DEFUN (link_params_admin_grp, + link_params_admin_grp_cmd, + "admin-grp BITPATTERN", + "Administrative group membership\n" + "32-bit Hexadecimal value (e.g. 0xa1)\n") +{ + struct interface *ifp = (struct interface *) vty->index; + struct if_link_params *iflp = if_link_params_get (ifp); + unsigned long value; + + if (sscanf (argv[0], "0x%lx", &value) != 1) + { + vty_out (vty, "link_params_admin_grp: fscanf: %s%s", + safe_strerror (errno), VTY_NEWLINE); + return CMD_WARNING; + } + + /* Update Administrative Group if needed */ + link_param_cmd_set_uint32 (ifp, &iflp->admin_grp, LP_ADM_GRP, value); + + return CMD_SUCCESS; +} + +DEFUN (no_link_params_admin_grp, + no_link_params_admin_grp_cmd, + "no admin-grp", + NO_STR + "Disbale Administrative group membership on this interface\n") +{ + struct interface *ifp = (struct interface *) vty->index; + + /* Unset Admin Group */ + link_param_cmd_unset(ifp, LP_ADM_GRP); + + return CMD_SUCCESS; +} + +/* RFC5392 & RFC5316: INTER-AS */ +DEFUN (link_params_inter_as, + link_params_inter_as_cmd, + "neighbor A.B.C.D as <1-4294967295>", + "Configure remote ASBR information (Neighbor IP address and AS number)\n" + "Remote IP address in dot decimal A.B.C.D\n" + "Remote AS number\n" + "AS number in the range <1-4294967295>\n") +{ + + struct interface *ifp = (struct interface *) vty->index; + struct if_link_params *iflp = if_link_params_get (ifp); + struct in_addr addr; + u_int32_t as; + + if (!inet_aton (argv[0], &addr)) + { + vty_out (vty, "Please specify Router-Addr by A.B.C.D%s", VTY_NEWLINE); + return CMD_WARNING; + } + + VTY_GET_ULONG("AS number", as, argv[1]); + + /* Update Remote IP and Remote AS fields if needed */ + if (IS_PARAM_UNSET(iflp, LP_RMT_AS) + || iflp->rmt_as != as + || iflp->rmt_ip.s_addr != addr.s_addr) + { + + iflp->rmt_as = as; + iflp->rmt_ip.s_addr = addr.s_addr; + SET_PARAM(iflp, LP_RMT_AS); + + /* force protocols to update LINK STATE due to parameters change */ + if (if_is_operative (ifp)) + zebra_interface_parameters_update (ifp); + } + return CMD_SUCCESS; +} + +DEFUN (no_link_params_inter_as, + no_link_params_inter_as_cmd, + "no neighbor", + NO_STR + "Remove Neighbor IP address and AS number for Inter-AS TE\n") +{ + + struct interface *ifp = (struct interface *) vty->index; + struct if_link_params *iflp = if_link_params_get (ifp); + + /* Reset Remote IP and AS neighbor */ + iflp->rmt_as = 0; + iflp->rmt_ip.s_addr = 0; + UNSET_PARAM(iflp, LP_RMT_AS); + + /* force protocols to update LINK STATE due to parameters change */ + if (if_is_operative (ifp)) + zebra_interface_parameters_update (ifp); + + return CMD_SUCCESS; +} + +/* RFC7471: OSPF Traffic Engineering (TE) Metric extensions & draft-ietf-isis-metric-extensions-07.txt */ +DEFUN (link_params_delay, + link_params_delay_cmd, + "delay <0-16777215>", + "Unidirectional Average Link Delay\n" + "Average delay in micro-second as decimal (0...16777215)\n") +{ + + struct interface *ifp = (struct interface *) vty->index; + struct if_link_params *iflp = if_link_params_get (ifp); + u_int32_t delay = 0, low = 0, high = 0; + u_int8_t update = 0; + + /* Get and Check new delay values */ + VTY_GET_ULONG("delay", delay, argv[0]); + switch (argc) + { + case 1: + /* Check new delay value against old Min and Max delays if set */ + if (IS_PARAM_SET(iflp, LP_MM_DELAY) + && (delay <= iflp->min_delay || delay >= iflp->max_delay)) + { + vty_out (vty, "Average delay should be comprise between Min (%d) and Max (%d) delay%s", + iflp->min_delay, iflp->max_delay, VTY_NEWLINE); + return CMD_WARNING; + } + /* Update delay if value is not set or change */ + if (IS_PARAM_UNSET(iflp, LP_DELAY)|| iflp->av_delay != delay) + { + iflp->av_delay = delay; + SET_PARAM(iflp, LP_DELAY); + update = 1; + } + /* Unset Min and Max delays if already set */ + if (IS_PARAM_SET(iflp, LP_MM_DELAY)) + { + iflp->min_delay = 0; + iflp->max_delay = 0; + UNSET_PARAM(iflp, LP_MM_DELAY); + update = 1; + } + break; + case 2: + vty_out (vty, "You should specify both Minimum and Maximum delay with Average delay%s", + VTY_NEWLINE); + return CMD_WARNING; + break; + case 3: + VTY_GET_ULONG("minimum delay", low, argv[1]); + VTY_GET_ULONG("maximum delay", high, argv[2]); + /* Check new delays value coherency */ + if (delay <= low || delay >= high) + { + vty_out (vty, "Average delay should be comprise between Min (%d) and Max (%d) delay%s", + low, high, VTY_NEWLINE); + return CMD_WARNING; + } + /* Update Delays if needed */ + if (IS_PARAM_UNSET(iflp, LP_DELAY) + || IS_PARAM_UNSET(iflp, LP_MM_DELAY) + || iflp->av_delay != delay + || iflp->min_delay != low + || iflp->max_delay != high) + { + iflp->av_delay = delay; + SET_PARAM(iflp, LP_DELAY); + iflp->min_delay = low; + iflp->max_delay = high; + SET_PARAM(iflp, LP_MM_DELAY); + update = 1; + } + break; + default: + return CMD_WARNING; + break; + } + + /* force protocols to update LINK STATE due to parameters change */ + if (update == 1 && if_is_operative (ifp)) + zebra_interface_parameters_update (ifp); + + return CMD_SUCCESS; +} + +ALIAS (link_params_delay, + link_params_delay_mm_cmd, + "delay <0-16777215> min <0-16777215> max <0-16777215>", + "Unidirectional Average Link Delay (optionally Minimum and Maximum delays)\n" + "Average delay in micro-second as decimal (0...16777215)\n" + "Minimum delay\n" + "Minimum delay in micro-second as decimal (0...16777215)\n" + "Maximum delay\n" + "Maximum delay in micro-second as decimal (0...16777215)\n") + +DEFUN (no_link_params_delay, + no_link_params_delay_cmd, + "no delay", + NO_STR + "Disbale Unidirectional Average, Min & Max Link Delay on this interface\n") +{ + struct interface *ifp = (struct interface *) vty->index; + struct if_link_params *iflp = if_link_params_get (ifp); + + /* Unset Delays */ + iflp->av_delay = 0; + UNSET_PARAM(iflp, LP_DELAY); + iflp->min_delay = 0; + iflp->max_delay = 0; + UNSET_PARAM(iflp, LP_MM_DELAY); + + /* force protocols to update LINK STATE due to parameters change */ + if (if_is_operative (ifp)) + zebra_interface_parameters_update (ifp); + + return CMD_SUCCESS; +} + +DEFUN (link_params_delay_var, + link_params_delay_var_cmd, + "delay-variation <0-16777215>", + "Unidirectional Link Delay Variation\n" + "delay variation in micro-second as decimal (0...16777215)\n") +{ + struct interface *ifp = (struct interface *) vty->index; + struct if_link_params *iflp = if_link_params_get (ifp); + u_int32_t value; + + VTY_GET_ULONG("delay variation", value, argv[0]); + + /* Update Delay Variation if needed */ + link_param_cmd_set_uint32 (ifp, &iflp->delay_var, LP_DELAY_VAR, value); + + return CMD_SUCCESS; +} + +DEFUN (no_link_params_delay_var, + no_link_params_delay_var_cmd, + "no delay-variation", + NO_STR + "Disbale Unidirectional Delay Variation on this interface\n") +{ + struct interface *ifp = (struct interface *) vty->index; + + /* Unset Delay Variation */ + link_param_cmd_unset(ifp, LP_DELAY_VAR); + + return CMD_SUCCESS; +} + +DEFUN (link_params_pkt_loss, + link_params_pkt_loss_cmd, + "packet-loss PERCENTAGE", + "Unidirectional Link Packet Loss\n" + "percentage of total traffic by 0.000003% step and less than 50.331642%\n") +{ + struct interface *ifp = (struct interface *) vty->index; + struct if_link_params *iflp = if_link_params_get (ifp); + float fval; + + if (sscanf (argv[0], "%g", &fval) != 1) + { + vty_out (vty, "link_params_pkt_loss: fscanf: %s%s", safe_strerror (errno), + VTY_NEWLINE); + return CMD_WARNING; + } + + if (fval > MAX_PKT_LOSS) + fval = MAX_PKT_LOSS; + + /* Update Packet Loss if needed */ + link_param_cmd_set_float (ifp, &iflp->pkt_loss, LP_PKT_LOSS, fval); + + return CMD_SUCCESS; +} + +DEFUN (no_link_params_pkt_loss, + no_link_params_pkt_loss_cmd, + "no packet-loss", + NO_STR + "Disbale Unidirectional Link Packet Loss on this interface\n") +{ + struct interface *ifp = (struct interface *) vty->index; + + /* Unset Packet Loss */ + link_param_cmd_unset(ifp, LP_PKT_LOSS); + + return CMD_SUCCESS; +} + +DEFUN (link_params_res_bw, + link_params_res_bw_cmd, + "res-bw BANDWIDTH", + "Unidirectional Residual Bandwidth\n" + "Bytes/second (IEEE floating point format)\n") +{ + struct interface *ifp = (struct interface *) vty->index; + struct if_link_params *iflp = if_link_params_get (ifp); + float bw; + + if (sscanf (argv[0], "%g", &bw) != 1) + { + vty_out (vty, "link_params_res_bw: fscanf: %s%s", safe_strerror (errno), + VTY_NEWLINE); + return CMD_WARNING; + } + + /* Check that bandwidth is not greater than maximum bandwidth parameter */ + if (bw > iflp->max_bw) + { + vty_out (vty, + "Residual Bandwidth could not be greater than Maximum Bandwidth (%g)%s", + iflp->max_bw, VTY_NEWLINE); + return CMD_WARNING; + } + + /* Update Residual Bandwidth if needed */ + link_param_cmd_set_float (ifp, &iflp->res_bw, LP_RES_BW, bw); + + return CMD_SUCCESS; +} + +DEFUN (no_link_params_res_bw, + no_link_params_res_bw_cmd, + "no res-bw", + NO_STR + "Disbale Unidirectional Residual Bandwidth on this interface\n") +{ + struct interface *ifp = (struct interface *) vty->index; + + /* Unset Residual Bandwidth */ + link_param_cmd_unset(ifp, LP_RES_BW); + + return CMD_SUCCESS; +} + +DEFUN (link_params_ava_bw, + link_params_ava_bw_cmd, + "ava-bw BANDWIDTH", + "Unidirectional Available Bandwidth\n" + "Bytes/second (IEEE floating point format)\n") +{ + struct interface *ifp = (struct interface *) vty->index; + struct if_link_params *iflp = if_link_params_get (ifp); + float bw; + + if (sscanf (argv[0], "%g", &bw) != 1) + { + vty_out (vty, "link_params_ava_bw: fscanf: %s%s", safe_strerror (errno), + VTY_NEWLINE); + return CMD_WARNING; + } + + /* Check that bandwidth is not greater than maximum bandwidth parameter */ + if (bw > iflp->max_bw) + { + vty_out (vty, + "Available Bandwidth could not be greater than Maximum Bandwidth (%g)%s", + iflp->max_bw, VTY_NEWLINE); + return CMD_WARNING; + } + + /* Update Residual Bandwidth if needed */ + link_param_cmd_set_float (ifp, &iflp->ava_bw, LP_AVA_BW, bw); + + return CMD_SUCCESS; +} + +DEFUN (no_link_params_ava_bw, + no_link_params_ava_bw_cmd, + "no ava-bw", + NO_STR + "Disbale Unidirectional Available Bandwidth on this interface\n") +{ + struct interface *ifp = (struct interface *) vty->index; + + /* Unset Available Bandwidth */ + link_param_cmd_unset(ifp, LP_AVA_BW); + + return CMD_SUCCESS; +} + +DEFUN (link_params_use_bw, + link_params_use_bw_cmd, + "use-bw BANDWIDTH", + "Unidirectional Utilised Bandwidth\n" + "Bytes/second (IEEE floating point format)\n") +{ + struct interface *ifp = (struct interface *) vty->index; + struct if_link_params *iflp = if_link_params_get (ifp); + float bw; + + if (sscanf (argv[0], "%g", &bw) != 1) + { + vty_out (vty, "link_params_use_bw: fscanf: %s%s", safe_strerror (errno), + VTY_NEWLINE); + return CMD_WARNING; + } + + /* Check that bandwidth is not greater than maximum bandwidth parameter */ + if (bw > iflp->max_bw) + { + vty_out (vty, + "Utilised Bandwidth could not be greater than Maximum Bandwidth (%g)%s", + iflp->max_bw, VTY_NEWLINE); + return CMD_WARNING; + } + + /* Update Utilized Bandwidth if needed */ + link_param_cmd_set_float (ifp, &iflp->use_bw, LP_USE_BW, bw); + + return CMD_SUCCESS; +} + +DEFUN (no_link_params_use_bw, + no_link_params_use_bw_cmd, + "no use-bw", + NO_STR + "Disbale Unidirectional Utilised Bandwidth on this interface\n") +{ + struct interface *ifp = (struct interface *) vty->index; + + /* Unset Utilised Bandwidth */ + link_param_cmd_unset(ifp, LP_USE_BW); + + return CMD_SUCCESS; +} + static int ip_address_install (struct vty *vty, struct interface *ifp, const char *addr_str, const char *peer_str, @@ -2070,6 +2787,58 @@ DEFUN (no_ipv6_address, } #endif /* HAVE_IPV6 */ +static int +link_params_config_write (struct vty *vty, struct interface *ifp) +{ + int i; + + if ((ifp == NULL) || !HAS_LINK_PARAMS(ifp)) + return -1; + + struct if_link_params *iflp = ifp->link_params; + + vty_out (vty, " link-params%s", VTY_NEWLINE); + vty_out(vty, " enable%s", VTY_NEWLINE); + if (IS_PARAM_SET(iflp, LP_TE)) + vty_out(vty, " metric %u%s",iflp->te_metric, VTY_NEWLINE); + if (IS_PARAM_SET(iflp, LP_MAX_BW)) + vty_out(vty, " max-bw %g%s", iflp->max_bw, VTY_NEWLINE); + if (IS_PARAM_SET(iflp, LP_MAX_RSV_BW)) + vty_out(vty, " max-rsv-bw %g%s", iflp->max_rsv_bw, VTY_NEWLINE); + if (IS_PARAM_SET(iflp, LP_UNRSV_BW)) + { + for (i = 0; i < 8; i++) + vty_out(vty, " unrsv-bw %d %g%s", + i, iflp->unrsv_bw[i], VTY_NEWLINE); + } + if (IS_PARAM_SET(iflp, LP_ADM_GRP)) + vty_out(vty, " admin-grp %u%s", iflp->admin_grp, VTY_NEWLINE); + if (IS_PARAM_SET(iflp, LP_DELAY)) + { + vty_out(vty, " delay %u", iflp->av_delay); + if (IS_PARAM_SET(iflp, LP_MM_DELAY)) + { + vty_out(vty, " min %u", iflp->min_delay); + vty_out(vty, " max %u", iflp->max_delay); + } + vty_out(vty, "%s", VTY_NEWLINE); + } + if (IS_PARAM_SET(iflp, LP_DELAY_VAR)) + vty_out(vty, " delay-variation %u%s", iflp->delay_var, VTY_NEWLINE); + if (IS_PARAM_SET(iflp, LP_PKT_LOSS)) + vty_out(vty, " packet-loss %g%s", iflp->pkt_loss, VTY_NEWLINE); + if (IS_PARAM_SET(iflp, LP_AVA_BW)) + vty_out(vty, " ava-bw %g%s", iflp->ava_bw, VTY_NEWLINE); + if (IS_PARAM_SET(iflp, LP_RES_BW)) + vty_out(vty, " res-bw %g%s", iflp->res_bw, VTY_NEWLINE); + if (IS_PARAM_SET(iflp, LP_USE_BW)) + vty_out(vty, " use-bw %g%s", iflp->use_bw, VTY_NEWLINE); + if (IS_PARAM_SET(iflp, LP_RMT_AS)) + vty_out(vty, " neighbor %s as %u%s", inet_ntoa(iflp->rmt_ip), + iflp->rmt_as, VTY_NEWLINE); + return 0; +} + static int if_config_write (struct vty *vty) { @@ -2114,10 +2883,8 @@ if_config_write (struct vty *vty) if (ifp->bandwidth != 0) vty_out(vty, " bandwidth %u%s", ifp->bandwidth, VTY_NEWLINE); - if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION)) - vty_out(vty, " link-detect%s", VTY_NEWLINE); - else - vty_out(vty, " no link-detect%s", VTY_NEWLINE); + if (!CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION)) + vty_out(vty, " no link-detect%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (ifp->connected, addrnode, ifc)) { @@ -2152,6 +2919,8 @@ if_config_write (struct vty *vty) irdp_config_write (vty, ifp); #endif /* IRDP */ + link_params_config_write (vty, ifp); + vty_out (vty, "!%s", VTY_NEWLINE); } return 0; @@ -2184,6 +2953,7 @@ zebra_if_init (void) /* Install configuration write function. */ install_node (&interface_node, if_config_write); + install_node (&link_params_node, NULL); install_node (&vrf_node, vrf_config_write); install_element (VIEW_NODE, &show_interface_cmd); @@ -2227,9 +2997,26 @@ zebra_if_init (void) install_element (INTERFACE_NODE, &ip_address_label_cmd); install_element (INTERFACE_NODE, &no_ip_address_label_cmd); #endif /* HAVE_NETLINK */ - + install_element(INTERFACE_NODE, &link_params_cmd); + install_default(LINK_PARAMS_NODE); + install_element(LINK_PARAMS_NODE, &link_params_enable_cmd); + install_element(LINK_PARAMS_NODE, &no_link_params_enable_cmd); + install_element(LINK_PARAMS_NODE, &link_params_metric_cmd); + install_element(LINK_PARAMS_NODE, &link_params_maxbw_cmd); + install_element(LINK_PARAMS_NODE, &link_params_max_rsv_bw_cmd); + install_element(LINK_PARAMS_NODE, &link_params_unrsv_bw_cmd); + install_element(LINK_PARAMS_NODE, &link_params_admin_grp_cmd); + install_element(LINK_PARAMS_NODE, &link_params_inter_as_cmd); + install_element(LINK_PARAMS_NODE, &no_link_params_inter_as_cmd); + install_element(LINK_PARAMS_NODE, &link_params_delay_cmd); + install_element(LINK_PARAMS_NODE, &link_params_delay_mm_cmd); + install_element(LINK_PARAMS_NODE, &link_params_delay_var_cmd); + install_element(LINK_PARAMS_NODE, &link_params_pkt_loss_cmd); + install_element(LINK_PARAMS_NODE, &link_params_ava_bw_cmd); + install_element(LINK_PARAMS_NODE, &link_params_res_bw_cmd); + install_element(LINK_PARAMS_NODE, &link_params_use_bw_cmd); + install_element (CONFIG_NODE, &zebra_vrf_cmd); install_element (CONFIG_NODE, &no_vrf_cmd); install_default (VRF_NODE); - } diff --git a/zebra/interface.h b/zebra/interface.h index 2857198373..6039e2d379 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -211,6 +211,16 @@ struct zebra_if struct irdp_interface irdp; #endif +#ifdef HAVE_STRUCT_SOCKADDR_DL + union { + /* note that sdl_storage is never accessed, it only exists to make space. + * all actual uses refer to sdl - but use sizeof(sdl_storage)! this fits + * best with C aliasing rules. */ + struct sockaddr_dl sdl; + struct sockaddr_storage sdl_storage; + }; +#endif + #ifdef SUNOS_5 /* the real IFF_UP state of the primary interface. * need this to differentiate between all interfaces being diff --git a/zebra/kernel_null.c b/zebra/kernel_null.c index 5efc1e2a55..17b3c7bc8d 100644 --- a/zebra/kernel_null.c +++ b/zebra/kernel_null.c @@ -39,9 +39,6 @@ int kernel_add_ipv6 (struct prefix *a, struct rib *b) { return 0; } int kernel_update_ipv6 (struct prefix *a, struct rib *b) { return 0; } int kernel_delete_ipv6 (struct prefix *a, struct rib *b) { return 0; } -int kernel_add_route (struct prefix_ipv4 *a, struct in_addr *b, int c, int d) -{ return 0; } - int kernel_address_add_ipv4 (struct interface *a, struct connected *b) { zlog_debug ("%s", __func__); @@ -60,7 +57,7 @@ int kernel_address_delete_ipv4 (struct interface *a, struct connected *b) return 0; } -int netlink_neigh_update (int cmd, int ifindex, __u32 addr, char *lla, int llalen) +int kernel_neigh_update (int a, int b, uint32_t c, char *d, int e) { return 0; } diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index b47ee787e8..733e627265 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -20,6 +20,7 @@ */ #include +#include #include "if.h" #include "prefix.h" @@ -240,7 +241,9 @@ static const struct message rtm_flag_str[] = #ifdef RTF_CLONING {RTF_CLONING, "CLONING"}, #endif /* RTF_CLONING */ +#ifdef RTF_XRESOLVE {RTF_XRESOLVE, "XRESOLVE"}, +#endif /* RTF_XRESOLVE */ #ifdef RTF_LLINFO {RTF_LLINFO, "LLINFO"}, #endif /* RTF_LLINFO */ @@ -377,6 +380,29 @@ bsd_linkdetect_translate (struct if_msghdr *ifm) } #endif /* HAVE_BSD_IFI_LINK_STATE */ +static enum zebra_link_type +sdl_to_zebra_link_type (unsigned int sdlt) +{ + switch (sdlt) + { + case IFT_ETHER: return ZEBRA_LLT_ETHER; + case IFT_X25: return ZEBRA_LLT_X25; + case IFT_FDDI: return ZEBRA_LLT_FDDI; + case IFT_PPP: return ZEBRA_LLT_PPP; + case IFT_LOOP: return ZEBRA_LLT_LOOPBACK; + case IFT_SLIP: return ZEBRA_LLT_SLIP; + case IFT_ARCNET: return ZEBRA_LLT_ARCNET; + case IFT_ATM: return ZEBRA_LLT_ATM; + case IFT_LOCALTALK: return ZEBRA_LLT_LOCALTLK; + case IFT_HIPPI: return ZEBRA_LLT_HIPPI; +#ifdef IFT_IEEE1394 + case IFT_IEEE1394: return ZEBRA_LLT_IEEE1394; +#endif + + default: return ZEBRA_LLT_UNKNOWN; + } +} + /* * Handle struct if_msghdr obtained from reading routing socket or * sysctl (from interface_list). There may or may not be sockaddrs @@ -533,14 +559,23 @@ ifm_read (struct if_msghdr *ifm) * is fine here. * a nonzero ifnlen from RTA_NAME_GET() means sdl is valid */ + ifp->ll_type = ZEBRA_LLT_UNKNOWN; + ifp->hw_addr_len = 0; if (ifnlen) - { + { #ifdef HAVE_STRUCT_SOCKADDR_DL_SDL_LEN - memcpy (&ifp->sdl, sdl, sdl->sdl_len); + memcpy (&((struct zebra_if *)ifp->info)->sdl, sdl, sdl->sdl_len); #else - memcpy (&ifp->sdl, sdl, sizeof (struct sockaddr_dl)); + memcpy (&((struct zebra_if *)ifp->info)->sdl, sdl, sizeof (struct sockaddr_dl)); #endif /* HAVE_STRUCT_SOCKADDR_DL_SDL_LEN */ - } + + ifp->ll_type = sdl_to_zebra_link_type (sdl->sdl_type); + if (sdl->sdl_alen <= sizeof(ifp->hw_addr)) + { + memcpy (ifp->hw_addr, LLADDR(sdl), sdl->sdl_alen); + ifp->hw_addr_len = sdl->sdl_alen; + } + } if_add_update (ifp); } @@ -882,10 +917,10 @@ rtm_read (struct rt_msghdr *rtm) if (dest.sa.sa_family == AF_INET) { - struct prefix_ipv4 p; + struct prefix p; p.family = AF_INET; - p.prefix = dest.sin.sin_addr; + p.u.prefix4 = dest.sin.sin_addr; if (flags & RTF_HOST) p.prefixlen = IPV4_MAX_PREFIXLEN; else @@ -925,7 +960,7 @@ rtm_read (struct rt_msghdr *rtm) case ZEBRA_RIB_FOUND_EXACT: /* RIB RR == FIB RR */ zlog_debug ("%s: %s %s: done Ok", __func__, lookup (rtm_type_str, rtm->rtm_type), buf); - rib_lookup_and_dump (&p); + rib_lookup_and_dump (&p, VRF_DEFAULT); return; break; } @@ -938,18 +973,18 @@ rtm_read (struct rt_msghdr *rtm) case ZEBRA_RIB_FOUND_EXACT: zlog_debug ("%s: %s %s: desync: RR is still in RIB, while already not in FIB", __func__, lookup (rtm_type_str, rtm->rtm_type), buf); - rib_lookup_and_dump (&p); + rib_lookup_and_dump (&p, VRF_DEFAULT); break; case ZEBRA_RIB_FOUND_CONNECTED: case ZEBRA_RIB_FOUND_NOGATE: zlog_debug ("%s: %s %s: desync: RR is still in RIB, plus gate differs", __func__, lookup (rtm_type_str, rtm->rtm_type), buf); - rib_lookup_and_dump (&p); + rib_lookup_and_dump (&p, VRF_DEFAULT); break; case ZEBRA_RIB_NOTFOUND: /* RIB RR == FIB RR */ zlog_debug ("%s: %s %s: done Ok", __func__, lookup (rtm_type_str, rtm->rtm_type), buf); - rib_lookup_and_dump (&p); + rib_lookup_and_dump (&p, VRF_DEFAULT); return; break; } @@ -965,19 +1000,19 @@ rtm_read (struct rt_msghdr *rtm) * to specify the route really */ if (rtm->rtm_type == RTM_CHANGE) - rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, - NULL, 0, VRF_DEFAULT, SAFI_UNICAST); + rib_delete (AFI_IP, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, + 0, zebra_flags, &p, NULL, 0, 0); + union g_addr ggate = { .ipv4 = gate.sin.sin_addr }; if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD || rtm->rtm_type == RTM_CHANGE) - rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, zebra_flags, - &p, &gate.sin.sin_addr, NULL, 0, VRF_DEFAULT, 0, 0, 0, SAFI_UNICAST); + rib_add (AFI_IP, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0, zebra_flags, + &p, &ggate, NULL, 0, 0, 0, 0, 0); else - rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0 zebra_flags, - &p, &gate.sin.sin_addr, 0, VRF_DEFAULT, SAFI_UNICAST); + rib_delete (AFI_IP, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, + 0, zebra_flags, &p, &ggate, 0, 0); } -#ifdef HAVE_IPV6 if (dest.sa.sa_family == AF_INET6) { /* One day we might have a debug section here like one in the @@ -985,11 +1020,11 @@ rtm_read (struct rt_msghdr *rtm) */ if (rtm->rtm_type != RTM_GET && rtm->rtm_pid == pid) return; - struct prefix_ipv6 p; - unsigned int ifindex = 0; + struct prefix p; + ifindex_t ifindex = 0; p.family = AF_INET6; - p.prefix = dest.sin6.sin6_addr; + p.u.prefix6 = dest.sin6.sin6_addr; if (flags & RTF_HOST) p.prefixlen = IPV6_MAX_PREFIXLEN; else @@ -1007,19 +1042,20 @@ rtm_read (struct rt_msghdr *rtm) * to specify the route really */ if (rtm->rtm_type == RTM_CHANGE) - rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, - NULL, 0, VRF_DEFAULT, SAFI_UNICAST); - + rib_delete (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, + 0, zebra_flags, &p, NULL, 0, 0); + + union g_addr ggate = { .ipv6 = gate.sin6.sin6_addr }; if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD || rtm->rtm_type == RTM_CHANGE) - rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, zebra_flags, - &p, &gate.sin6.sin6_addr, ifindex, VRF_DEFAULT, 0, 0, SAFI_UNICAST); + rib_add (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, + 0, zebra_flags, &p, &ggate, NULL, ifindex, + 0, 0, 0, 0); else - rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, zebra_flags, - &p, &gate.sin6.sin6_addr, ifindex, VRF_DEFAULT, SAFI_UNICAST); + rib_delete (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, + 0, zebra_flags, &p, &ggate, ifindex, 0); } -#endif /* HAVE_IPV6 */ } /* Interface function for the kernel routing table updates. Support @@ -1097,7 +1133,7 @@ rtm_write (int message, __func__, dest_buf, mask_buf, index); return -1; } - gate = (union sockunion *) & ifp->sdl; + gate = (union sockunion *) &((struct zebra_if *)ifp->info)->sdl; } if (mask) diff --git a/zebra/main.c b/zebra/main.c index ab907f83e8..d8892f582a 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -150,7 +150,7 @@ usage (char *progname, int status) "-r, --retain When program terminates, retain added route "\ "by zebra.\n"\ "-u, --user User to run as\n"\ - "-g, --group Group to run as\n", progname); + "-g, --group Group to run as\n", progname); #ifdef HAVE_NETLINK printf ("-s, --nl-bufsize Set netlink receive buffer size\n"); #endif /* HAVE_NETLINK */ @@ -245,7 +245,9 @@ main (int argc, char **argv) zlog_default = openzlog (progname, ZLOG_ZEBRA, 0, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); zprivs_init (&zserv_privs); - zlog_set_file (NULL, LOG_DEFAULT_FILENAME, zlog_default->default_lvl); +#if defined(HAVE_CUMULUS) + zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl); +#endif while (1) { diff --git a/zebra/redistribute.c b/zebra/redistribute.c index 1867362778..fb9fa0216a 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -144,17 +144,23 @@ zebra_redistribute (struct zserv *client, int type, u_short instance, vrf_id_t v if (table) for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, newrib) - if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED) - && newrib->type == type - && newrib->instance == instance - && newrib->distance != DISTANCE_INFINITY - && zebra_check_addr (&rn->p)) - { - client->redist_v4_add_cnt++; - zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV4_ADD, client, &rn->p, newrib); - } - -#ifdef HAVE_IPV6 + { + if (IS_ZEBRA_DEBUG_EVENT) + zlog_debug("%s: checking: selected=%d, type=%d, distance=%d, zebra_check_addr=%d", + __func__, CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED), + newrib->type, newrib->distance, zebra_check_addr (&rn->p)); + + if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED) + && newrib->type == type + && newrib->instance == instance + && newrib->distance != DISTANCE_INFINITY + && zebra_check_addr (&rn->p)) + { + client->redist_v4_add_cnt++; + zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV4_ADD, client, &rn->p, newrib); + } + } + table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id); if (table) for (rn = route_top (table); rn; rn = route_next (rn)) @@ -168,7 +174,6 @@ zebra_redistribute (struct zserv *client, int type, u_short instance, vrf_id_t v client->redist_v6_add_cnt++; zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV6_ADD, client, &rn->p, newrib); } -#endif /* HAVE_IPV6 */ } /* Either advertise a route for redistribution to registered clients or */ @@ -380,9 +385,11 @@ zebra_interface_up_update (struct interface *ifp) if (ifp->ptm_status || !ifp->ptm_enable) { for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) - { - zsend_interface_update (ZEBRA_INTERFACE_UP, client, ifp); - } + if (client->ifinfo) + { + zsend_interface_update (ZEBRA_INTERFACE_UP, client, ifp); + zsend_interface_link_params (client, ifp); + } } } @@ -413,10 +420,12 @@ zebra_interface_add_update (struct interface *ifp) zlog_debug ("MESSAGE: ZEBRA_INTERFACE_ADD %s[%d]", ifp->name, ifp->vrf_id); for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) - { - client->ifadd_cnt++; - zsend_interface_add (client, ifp); - } + if (client->ifinfo) + { + client->ifadd_cnt++; + zsend_interface_add (client, ifp); + zsend_interface_link_params (client, ifp); + } } void @@ -545,9 +554,9 @@ int zebra_add_import_table_entry (struct route_node *rn, struct rib *rib, const char *rmap_name) { struct rib *newrib; - struct prefix_ipv4 p4; + struct prefix p; struct nexthop *nhop; - struct in_addr *gate; + union g_addr *gate; route_map_result_t ret = RMAP_MATCH; if (rmap_name) @@ -558,9 +567,9 @@ zebra_add_import_table_entry (struct route_node *rn, struct rib *rib, const char { if (rn->p.family == AF_INET) { - p4.family = AF_INET; - p4.prefixlen = rn->p.prefixlen; - p4.prefix = rn->p.u.prefix4; + p.family = AF_INET; + p.prefixlen = rn->p.prefixlen; + p.u.prefix4 = rn->p.u.prefix4; if (rib->nexthop_num == 1) { @@ -568,14 +577,13 @@ zebra_add_import_table_entry (struct route_node *rn, struct rib *rib, const char if (nhop->type == NEXTHOP_TYPE_IFINDEX) gate = NULL; else - gate = &nhop->gate.ipv4; + gate = (union g_addr *)&nhop->gate.ipv4; - rib_add_ipv4(ZEBRA_ROUTE_TABLE, rib->table, 0, &p4, - gate, &nhop->src.ipv4, - nhop->ifindex, rib->vrf_id, zebrad.rtm_table_default, - rib->metric, - zebra_import_table_distance[AFI_IP][rib->table], - SAFI_UNICAST); + rib_add (AFI_IP, SAFI_UNICAST, rib->vrf_id, ZEBRA_ROUTE_TABLE, + rib->table, 0, &p, gate, (union g_addr *)&nhop->src.ipv4, + nhop->ifindex, zebrad.rtm_table_default, + rib->metric, rib->mtu, + zebra_import_table_distance[AFI_IP][rib->table]); } else if (rib->nexthop_num > 1) { @@ -584,6 +592,7 @@ zebra_add_import_table_entry (struct route_node *rn, struct rib *rib, const char newrib->distance = zebra_import_table_distance[AFI_IP][rib->table]; newrib->flags = rib->flags; newrib->metric = rib->metric; + newrib->mtu = rib->mtu; newrib->table = zebrad.rtm_table_default; newrib->nexthop_num = 0; newrib->uptime = time(NULL); @@ -593,7 +602,7 @@ zebra_add_import_table_entry (struct route_node *rn, struct rib *rib, const char for (nhop = rib->nexthop; nhop; nhop = nhop->next) rib_copy_nexthops(newrib, nhop); - rib_add_ipv4_multipath(&p4, newrib, SAFI_UNICAST); + rib_add_multipath(AFI_IP, SAFI_UNICAST, &p, newrib); } } } @@ -608,16 +617,17 @@ zebra_add_import_table_entry (struct route_node *rn, struct rib *rib, const char int zebra_del_import_table_entry (struct route_node *rn, struct rib *rib) { - struct prefix_ipv4 p4; + struct prefix p; if (rn->p.family == AF_INET) { - p4.family = AF_INET; - p4.prefixlen = rn->p.prefixlen; - p4.prefix = rn->p.u.prefix4; + p.family = AF_INET; + p.prefixlen = rn->p.prefixlen; + p.u.prefix4 = rn->p.u.prefix4; - rib_delete_ipv4(ZEBRA_ROUTE_TABLE, rib->table, rib->flags, &p4, NULL, - 0, rib->vrf_id, zebrad.rtm_table_default, SAFI_UNICAST); + rib_delete (AFI_IP, SAFI_UNICAST, rib->vrf_id, ZEBRA_ROUTE_TABLE, + rib->table, rib->flags, &p, NULL, + 0, zebrad.rtm_table_default); } /* DD: Add IPv6 code */ @@ -791,3 +801,18 @@ zebra_import_table_rm_update () return; } + +/* Interface parameters update */ +void +zebra_interface_parameters_update (struct interface *ifp) +{ + struct listnode *node, *nnode; + struct zserv *client; + + if (IS_ZEBRA_DEBUG_EVENT) + zlog_debug ("MESSAGE: ZEBRA_INTERFACE_LINK_PARAMS %s", ifp->name); + + for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) + if (client->ifinfo) + zsend_interface_link_params (client, ifp); +} diff --git a/zebra/redistribute.h b/zebra/redistribute.h index 5e3cf1bfd3..e3bce7af46 100644 --- a/zebra/redistribute.h +++ b/zebra/redistribute.h @@ -49,6 +49,7 @@ extern void zebra_interface_address_add_update (struct interface *, struct connected *); extern void zebra_interface_address_delete_update (struct interface *, struct connected *c); +extern void zebra_interface_parameters_update (struct interface *); extern void zebra_interface_vrf_update_del (struct interface *, vrf_id_t new_vrf_id); extern void zebra_interface_vrf_update_add (struct interface *, vrf_id_t old_vrf_id); diff --git a/zebra/redistribute_null.c b/zebra/redistribute_null.c index c21ee44702..85d3bd2f1b 100644 --- a/zebra/redistribute_null.c +++ b/zebra/redistribute_null.c @@ -60,6 +60,10 @@ void zebra_interface_address_delete_update (struct interface *a, struct connected *b) { return; } +/* Interface parameters update */ +void zebra_interface_parameters_update (struct interface *ifp) +{ return; }; + void zebra_interface_vrf_update_del (struct interface *a, vrf_id_t new_vrf_id) { return; } diff --git a/zebra/rib.h b/zebra/rib.h index 5e0bce4461..500d96cbe4 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -64,6 +64,10 @@ struct rib /* Metric */ u_int32_t metric; + /* MTU */ + u_int32_t mtu; + u_int32_t nexthop_mtu; + /* Distance. */ u_char distance; @@ -81,6 +85,7 @@ struct rib #define RIB_ENTRY_REMOVED 0x1 /* to simplify NHT logic when NHs change, instead of doing a NH by NH cmp */ #define RIB_ENTRY_NEXTHOPS_CHANGED 0x2 +#define RIB_ENTRY_CHANGED 0x4 /* Nexthop information. */ u_char nexthop_num; @@ -170,52 +175,6 @@ typedef struct rib_dest_t_ #define RNODE_FOREACH_RIB_SAFE(rn, rib, next) \ RIB_DEST_FOREACH_ROUTE_SAFE (rib_dest_from_rnode (rn), rib, next) -/* Static route information. */ -struct static_route -{ - /* For linked list. */ - struct static_route *prev; - struct static_route *next; - - /* VRF identifier. */ - vrf_id_t vrf_id; - - /* Administrative distance. */ - u_char distance; - - /* Tag */ - u_short tag; - - /* Flag for this static route's type. */ - u_char type; -#define STATIC_IFINDEX 1 -#define STATIC_IPV4_GATEWAY 2 -#define STATIC_IPV4_BLACKHOLE 3 -#define STATIC_IPV6_GATEWAY 4 -#define STATIC_IPV6_GATEWAY_IFINDEX 5 - - /* - * Nexthop value. - * - * Under IPv4 addr and ifindex are - * used independentyly. - * STATIC_IPV4_GATEWAY uses addr - * STATIC_IFINDEX uses ifindex - */ - union g_addr addr; - unsigned int ifindex; - - char ifname[INTERFACE_NAMSIZ + 1]; - - /* bit flags */ - u_char flags; -/* - see ZEBRA_FLAG_REJECT - ZEBRA_FLAG_BLACKHOLE - */ -}; - - /* The following for loop allows to iterate over the nexthop * structure of routes. * @@ -321,14 +280,14 @@ typedef enum RIB_UPDATE_OTHER } rib_update_event_t; -extern struct nexthop *rib_nexthop_ifindex_add (struct rib *, unsigned int); +extern struct nexthop *rib_nexthop_ifindex_add (struct rib *, ifindex_t); extern struct nexthop *rib_nexthop_blackhole_add (struct rib *); extern struct nexthop *rib_nexthop_ipv4_add (struct rib *, struct in_addr *, struct in_addr *); extern struct nexthop *rib_nexthop_ipv4_ifindex_add (struct rib *, struct in_addr *, struct in_addr *, - unsigned int); + ifindex_t); extern void rib_nexthop_add (struct rib *rib, struct nexthop *nexthop); extern void rib_copy_nexthops (struct rib *rib, struct nexthop *nh); @@ -361,31 +320,40 @@ extern int rib_lookup_ipv4_route (struct prefix_ipv4 *, union sockunion *, #define ZEBRA_RIB_FOUND_CONNECTED 2 #define ZEBRA_RIB_NOTFOUND 3 +extern void rib_nexthop_delete (struct rib *rib, struct nexthop *nexthop); extern struct nexthop *rib_nexthop_ipv6_add (struct rib *, struct in6_addr *); extern struct nexthop *rib_nexthop_ipv6_ifindex_add (struct rib *rib, struct in6_addr *ipv6, - unsigned int ifindex); + ifindex_t ifindex); extern int is_zebra_valid_kernel_table(u_int32_t table_id); extern int is_zebra_main_routing_table(u_int32_t table_id); extern int zebra_check_addr (struct prefix *p); +extern void rib_addnode (struct route_node *rn, struct rib *rib, int process); +extern void rib_delnode (struct route_node *rn, struct rib *rib); +extern int rib_install_kernel (struct route_node *rn, struct rib *rib, int update); +extern int rib_uninstall_kernel (struct route_node *rn, struct rib *rib); + /* NOTE: - * All rib_add_ipv[46]* functions will not just add prefix into RIB, but + * All rib_add function will not just add prefix into RIB, but * also implicitly withdraw equal prefix of same type. */ -extern int rib_add_ipv4 (int type, u_short instance, int flags, struct prefix_ipv4 *p, - struct in_addr *gate, struct in_addr *src, - unsigned int ifindex, vrf_id_t vrf_id, u_int32_t table_id, - u_int32_t, u_char, safi_t); +extern int rib_add (afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, + u_short instance, int flags, struct prefix *p, + union g_addr *gate, union g_addr *src, + ifindex_t ifindex, u_int32_t table_id, + u_int32_t, u_int32_t, u_char); -extern int rib_add_ipv4_multipath (struct prefix_ipv4 *, struct rib *, safi_t); +extern int rib_add_multipath (afi_t afi, safi_t safi, struct prefix *, + struct rib *); -extern int rib_delete_ipv4 (int type, u_short instance, int flags, struct prefix_ipv4 *p, - struct in_addr *gate, unsigned int ifindex, - vrf_id_t, u_int32_t, safi_t safi); +extern int rib_delete (afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, + u_short instance, int flags, struct prefix *p, + union g_addr *gate, ifindex_t ifindex, + u_int32_t table_id); -extern struct rib *rib_match_ipv4 (struct in_addr, safi_t safi, vrf_id_t, - struct route_node **rn_out); +extern struct rib *rib_match (afi_t afi, safi_t safi, vrf_id_t, union g_addr *, + struct route_node **rn_out); extern struct rib *rib_match_ipv4_multicast (struct in_addr addr, struct route_node **rn_out); @@ -400,50 +368,8 @@ extern void rib_init (void); extern unsigned long rib_score_proto (u_char proto, u_short instance); extern void rib_queue_add (struct route_node *rn); -extern void -static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_route *si); -extern void -static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p, struct static_route *si); - -extern int -static_add_ipv4 (safi_t safi, struct prefix *p, struct in_addr *gate, unsigned int ifindex, - const char *ifname, u_char flags, u_short tag, - u_char distance, struct zebra_vrf *zvrf); - -extern int -static_delete_ipv4 (safi_t safi, struct prefix *p, struct in_addr *gate, unsigned int ifindex, - u_short tag, u_char distance, struct zebra_vrf *zvrf); - -extern int -rib_add_ipv6 (int type, u_short instance, int flags, struct prefix_ipv6 *p, - struct in6_addr *gate, unsigned int ifindex, vrf_id_t vrf_id, - u_int32_t table_id, u_int32_t metric, u_char distance, safi_t safi); - -extern int -rib_delete_ipv6 (int type, u_short instance, int flags, struct prefix_ipv6 *p, - struct in6_addr *gate, unsigned int ifindex, vrf_id_t vrf_id, - u_int32_t table_id, safi_t safi); - -extern struct rib *rib_lookup_ipv6 (struct in6_addr *, vrf_id_t); - -extern struct rib *rib_match_ipv6 (struct in6_addr *, vrf_id_t); - extern struct route_table *rib_table_ipv6; -extern int -static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, - unsigned int ifindex, const char *ifname, u_char flags, - u_short tag, u_char distance, struct zebra_vrf *zvrf); - -extern int -rib_add_ipv6_multipath (struct prefix *, struct rib *, safi_t, - unsigned long); - -extern int -static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, - unsigned int ifindex, u_short tag, u_char distance, - struct zebra_vrf *zvrf); - extern int rib_gc_dest (struct route_node *rn); extern struct route_table *rib_tables_iter_next (rib_tables_iter_t *iter); diff --git a/zebra/rt.h b/zebra/rt.h index 331df45c47..46e71fa46e 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -30,15 +30,13 @@ extern int kernel_add_ipv4 (struct prefix *, struct rib *); extern int kernel_update_ipv4 (struct prefix *, struct rib *); extern int kernel_delete_ipv4 (struct prefix *, struct rib *); -extern int kernel_add_route (struct prefix_ipv4 *, struct in_addr *, int, int); + extern int kernel_address_add_ipv4 (struct interface *, struct connected *); extern int kernel_address_delete_ipv4 (struct interface *, struct connected *); +extern int kernel_neigh_update (int, int, uint32_t, char *, int); -#ifdef HAVE_IPV6 extern int kernel_add_ipv6 (struct prefix *, struct rib *); extern int kernel_update_ipv6 (struct prefix *, struct rib *); extern int kernel_delete_ipv6 (struct prefix *, struct rib *); -#endif /* HAVE_IPV6 */ - #endif /* _ZEBRA_RT_H */ diff --git a/zebra/rt_ioctl.c b/zebra/rt_ioctl.c index 383c5f71ac..597392c38a 100644 --- a/zebra/rt_ioctl.c +++ b/zebra/rt_ioctl.c @@ -46,121 +46,11 @@ kernel_read (int sock) return; } -#if 0 -/* Initialization prototype of struct sockaddr_in. */ -static struct sockaddr_in sin_proto = -{ -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - sizeof (struct sockaddr_in), -#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ - AF_INET, 0, {0}, {0} -}; -#endif /* 0 */ - /* Solaris has ortentry. */ #ifdef HAVE_OLD_RTENTRY #define rtentry ortentry #endif /* HAVE_OLD_RTENTRY */ -/* Interface to ioctl route message. */ -int -kernel_add_route (struct prefix_ipv4 *dest, struct in_addr *gate, - int index, int flags) -{ - int ret; - int sock; - struct rtentry rtentry; - struct sockaddr_in sin_dest, sin_mask, sin_gate; - - memset (&rtentry, 0, sizeof (struct rtentry)); - - /* Make destination. */ - memset (&sin_dest, 0, sizeof (struct sockaddr_in)); - sin_dest.sin_family = AF_INET; -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - sin_dest.sin_len = sizeof (struct sockaddr_in); -#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ - sin_dest.sin_addr = dest->prefix; - - /* Make gateway. */ - if (gate) - { - memset (&sin_gate, 0, sizeof (struct sockaddr_in)); - sin_gate.sin_family = AF_INET; -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - sin_gate.sin_len = sizeof (struct sockaddr_in); -#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ - sin_gate.sin_addr = *gate; - } - - memset (&sin_mask, 0, sizeof (struct sockaddr_in)); - sin_mask.sin_family = AF_INET; -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - sin_gate.sin_len = sizeof (struct sockaddr_in); -#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ - masklen2ip (dest->prefixlen, &sin_mask.sin_addr); - - /* Set destination address, mask and gateway.*/ - memcpy (&rtentry.rt_dst, &sin_dest, sizeof (struct sockaddr_in)); - if (gate) - memcpy (&rtentry.rt_gateway, &sin_gate, sizeof (struct sockaddr_in)); -#ifndef SUNOS_5 - memcpy (&rtentry.rt_genmask, &sin_mask, sizeof (struct sockaddr_in)); -#endif /* SUNOS_5 */ - - /* Routing entry flag set. */ - if (dest->prefixlen == 32) - rtentry.rt_flags |= RTF_HOST; - - if (gate && gate->s_addr != INADDR_ANY) - rtentry.rt_flags |= RTF_GATEWAY; - - rtentry.rt_flags |= RTF_UP; - - /* Additional flags */ - rtentry.rt_flags |= flags; - - - /* For tagging route. */ - /* rtentry.rt_flags |= RTF_DYNAMIC; */ - - /* Open socket for ioctl. */ - sock = socket (AF_INET, SOCK_DGRAM, 0); - if (sock < 0) - { - zlog_warn ("can't make socket\n"); - return -1; - } - - /* Send message by ioctl(). */ - ret = ioctl (sock, SIOCADDRT, &rtentry); - if (ret < 0) - { - switch (errno) - { - case EEXIST: - close (sock); - return ZEBRA_ERR_RTEXIST; - break; - case ENETUNREACH: - close (sock); - return ZEBRA_ERR_RTUNREACH; - break; - case EPERM: - close (sock); - return ZEBRA_ERR_EPERM; - break; - } - - close (sock); - zlog_warn ("write : %s (%d)", safe_strerror (errno), errno); - return 1; - } - close (sock); - - return ret; -} - /* Interface to ioctl route message. */ static int kernel_ioctl_ipv4 (u_long cmd, struct prefix *p, struct rib *rib, int family) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 481ff781e3..fb9aef4aaf 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -20,6 +20,7 @@ */ #include +#include /* Hack for GNU libc version 2. */ #ifndef MSG_TRUNC @@ -74,7 +75,7 @@ extern u_int32_t nl_rcvbufsize; /* Note: on netlink systems, there should be a 1-to-1 mapping between interface names and ifindex values. */ static void -set_ifindex(struct interface *ifp, unsigned int ifi_index) +set_ifindex(struct interface *ifp, ifindex_t ifi_index) { struct interface *oifp; struct zebra_ns *zns = zebra_ns_lookup (NS_DEFAULT); @@ -523,6 +524,68 @@ netlink_interface_update_hw_addr (struct rtattr **tb, struct interface *ifp) } } +static enum zebra_link_type +netlink_to_zebra_link_type (unsigned int hwt) +{ + switch (hwt) + { + case ARPHRD_ETHER: return ZEBRA_LLT_ETHER; + case ARPHRD_EETHER: return ZEBRA_LLT_EETHER; + case ARPHRD_AX25: return ZEBRA_LLT_AX25; + case ARPHRD_PRONET: return ZEBRA_LLT_PRONET; + case ARPHRD_IEEE802: return ZEBRA_LLT_IEEE802; + case ARPHRD_ARCNET: return ZEBRA_LLT_ARCNET; + case ARPHRD_APPLETLK: return ZEBRA_LLT_APPLETLK; + case ARPHRD_DLCI: return ZEBRA_LLT_DLCI; + case ARPHRD_ATM: return ZEBRA_LLT_ATM; + case ARPHRD_METRICOM: return ZEBRA_LLT_METRICOM; + case ARPHRD_IEEE1394: return ZEBRA_LLT_IEEE1394; + case ARPHRD_EUI64: return ZEBRA_LLT_EUI64; + case ARPHRD_INFINIBAND: return ZEBRA_LLT_INFINIBAND; + case ARPHRD_SLIP: return ZEBRA_LLT_SLIP; + case ARPHRD_CSLIP: return ZEBRA_LLT_CSLIP; + case ARPHRD_SLIP6: return ZEBRA_LLT_SLIP6; + case ARPHRD_CSLIP6: return ZEBRA_LLT_CSLIP6; + case ARPHRD_RSRVD: return ZEBRA_LLT_RSRVD; + case ARPHRD_ADAPT: return ZEBRA_LLT_ADAPT; + case ARPHRD_ROSE: return ZEBRA_LLT_ROSE; + case ARPHRD_X25: return ZEBRA_LLT_X25; + case ARPHRD_PPP: return ZEBRA_LLT_PPP; + case ARPHRD_CISCO: return ZEBRA_LLT_CHDLC; + case ARPHRD_LAPB: return ZEBRA_LLT_LAPB; + case ARPHRD_RAWHDLC: return ZEBRA_LLT_RAWHDLC; + case ARPHRD_TUNNEL: return ZEBRA_LLT_IPIP; + case ARPHRD_TUNNEL6: return ZEBRA_LLT_IPIP6; + case ARPHRD_FRAD: return ZEBRA_LLT_FRAD; + case ARPHRD_SKIP: return ZEBRA_LLT_SKIP; + case ARPHRD_LOOPBACK: return ZEBRA_LLT_LOOPBACK; + case ARPHRD_LOCALTLK: return ZEBRA_LLT_LOCALTLK; + case ARPHRD_FDDI: return ZEBRA_LLT_FDDI; + case ARPHRD_SIT: return ZEBRA_LLT_SIT; + case ARPHRD_IPDDP: return ZEBRA_LLT_IPDDP; + case ARPHRD_IPGRE: return ZEBRA_LLT_IPGRE; + case ARPHRD_PIMREG: return ZEBRA_LLT_PIMREG; + case ARPHRD_HIPPI: return ZEBRA_LLT_HIPPI; + case ARPHRD_ECONET: return ZEBRA_LLT_ECONET; + case ARPHRD_IRDA: return ZEBRA_LLT_IRDA; + case ARPHRD_FCPP: return ZEBRA_LLT_FCPP; + case ARPHRD_FCAL: return ZEBRA_LLT_FCAL; + case ARPHRD_FCPL: return ZEBRA_LLT_FCPL; + case ARPHRD_FCFABRIC: return ZEBRA_LLT_FCFABRIC; + case ARPHRD_IEEE802_TR: return ZEBRA_LLT_IEEE802_TR; + case ARPHRD_IEEE80211: return ZEBRA_LLT_IEEE80211; + case ARPHRD_IEEE802154: return ZEBRA_LLT_IEEE802154; +#ifdef ARPHRD_IP6GRE + case ARPHRD_IP6GRE: return ZEBRA_LLT_IP6GRE; +#endif +#ifdef ARPHRD_IEEE802154_PHY + case ARPHRD_IEEE802154_PHY: return ZEBRA_LLT_IEEE802154_PHY; +#endif + + default: return ZEBRA_LLT_UNKNOWN; + } +} + #define parse_rtattr_nested(tb, max, rta) \ netlink_parse_rtattr((tb), (max), RTA_DATA(rta), RTA_PAYLOAD(rta)) @@ -698,7 +761,7 @@ netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h, ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN; /* Hardware type and address. */ - ifp->hw_type = ifi->ifi_type; + ifp->ll_type = netlink_to_zebra_link_type (ifi->ifi_type); netlink_interface_update_hw_addr (tb, ifp); if_add_update (ifp); @@ -860,12 +923,14 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h, struct rtmsg *rtm; struct rtattr *tb[RTA_MAX + 1]; u_char flags = 0; + struct prefix p; char anyaddr[16] = { 0 }; int index; int table; int metric; + u_int32_t mtu = 0; void *dest; void *gate; @@ -937,16 +1002,28 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h, if (tb[RTA_PRIORITY]) metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]); + if (tb[RTA_METRICS]) + { + struct rtattr *mxrta[RTAX_MAX+1]; + + memset (mxrta, 0, sizeof mxrta); + netlink_parse_rtattr (mxrta, RTAX_MAX, RTA_DATA(tb[RTA_METRICS]), + RTA_PAYLOAD(tb[RTA_METRICS])); + + if (mxrta[RTAX_MTU]) + mtu = *(u_int32_t *) RTA_DATA(mxrta[RTAX_MTU]); + } + if (rtm->rtm_family == AF_INET) { - struct prefix_ipv4 p; p.family = AF_INET; - memcpy (&p.prefix, dest, 4); + memcpy (&p.u.prefix4, dest, 4); p.prefixlen = rtm->rtm_dst_len; if (!tb[RTA_MULTIPATH]) - rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, flags, &p, gate, src, index, - vrf_id, table, metric, 0, SAFI_UNICAST); + rib_add (AFI_IP, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL, + 0, flags, &p, gate, src, index, + table, metric, mtu, 0); else { /* This is a multipath route */ @@ -962,6 +1039,7 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h, rib->distance = 0; rib->flags = flags; rib->metric = metric; + rib->mtu = mtu; rib->vrf_id = vrf_id; rib->table = table; rib->nexthop_num = 0; @@ -1002,21 +1080,19 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h, if (rib->nexthop_num == 0) XFREE (MTYPE_RIB, rib); else - rib_add_ipv4_multipath (&p, rib, SAFI_UNICAST); + rib_add_multipath (AFI_IP, SAFI_UNICAST, &p, rib); } } -#ifdef HAVE_IPV6 if (rtm->rtm_family == AF_INET6) { - struct prefix_ipv6 p; p.family = AF_INET6; - memcpy (&p.prefix, dest, 16); + memcpy (&p.u.prefix6, dest, 16); p.prefixlen = rtm->rtm_dst_len; - rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, flags, &p, gate, index, vrf_id, - table, metric, 0, SAFI_UNICAST); + rib_add (AFI_IP6, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL, + 0, flags, &p, gate, src, index, + table, metric, mtu, 0); } -#endif /* HAVE_IPV6 */ return 0; } @@ -1045,12 +1121,14 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h, struct rtmsg *rtm; struct rtattr *tb[RTA_MAX + 1]; u_char zebra_flags = 0; - + struct prefix p; + char anyaddr[16] = { 0 }; int index; int table; int metric; + u_int32_t mtu = 0; void *dest; void *gate; @@ -1142,14 +1220,28 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h, if (tb[RTA_PREFSRC]) src = RTA_DATA (tb[RTA_PREFSRC]); - if (h->nlmsg_type == RTM_NEWROUTE && tb[RTA_PRIORITY]) - metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]); + if (h->nlmsg_type == RTM_NEWROUTE) + { + if (tb[RTA_PRIORITY]) + metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]); + + if (tb[RTA_METRICS]) + { + struct rtattr *mxrta[RTAX_MAX+1]; + + memset (mxrta, 0, sizeof mxrta); + netlink_parse_rtattr (mxrta, RTAX_MAX, RTA_DATA(tb[RTA_METRICS]), + RTA_PAYLOAD(tb[RTA_METRICS])); + + if (mxrta[RTAX_MTU]) + mtu = *(u_int32_t *) RTA_DATA(mxrta[RTAX_MTU]); + } + } if (rtm->rtm_family == AF_INET) { - struct prefix_ipv4 p; p.family = AF_INET; - memcpy (&p.prefix, dest, 4); + memcpy (&p.u.prefix4, dest, 4); p.prefixlen = rtm->rtm_dst_len; if (IS_ZEBRA_DEBUG_KERNEL) @@ -1163,8 +1255,9 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h, if (h->nlmsg_type == RTM_NEWROUTE) { if (!tb[RTA_MULTIPATH]) - rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, 0, &p, gate, src, index, vrf_id, - table, metric, 0, SAFI_UNICAST); + rib_add (AFI_IP, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL, + 0, 0, &p, gate, src, index, + table, metric, mtu, 0); else { /* This is a multipath route */ @@ -1180,6 +1273,7 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h, rib->distance = 0; rib->flags = 0; rib->metric = metric; + rib->mtu = mtu; rib->vrf_id = vrf_id; rib->table = table; rib->nexthop_num = 0; @@ -1221,21 +1315,20 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h, if (rib->nexthop_num == 0) XFREE (MTYPE_RIB, rib); else - rib_add_ipv4_multipath (&p, rib, SAFI_UNICAST); + rib_add_multipath (AFI_IP, SAFI_UNICAST, &p, rib); } } else - rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, gate, index, - vrf_id, table, SAFI_UNICAST); + rib_delete (AFI_IP, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL, 0, zebra_flags, + &p, gate, index, table); } -#ifdef HAVE_IPV6 if (rtm->rtm_family == AF_INET6) { - struct prefix_ipv6 p; + struct prefix p; p.family = AF_INET6; - memcpy (&p.prefix, dest, 16); + memcpy (&p.u.prefix6, dest, 16); p.prefixlen = rtm->rtm_dst_len; if (IS_ZEBRA_DEBUG_KERNEL) @@ -1247,13 +1340,13 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h, } if (h->nlmsg_type == RTM_NEWROUTE) - rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, 0, &p, gate, index, vrf_id, - table, metric, 0, SAFI_UNICAST); + rib_add (AFI_IP6, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL, + 0, 0, &p, gate, src, index, + table, metric, mtu, 0); else - rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, gate, index, - vrf_id, table, SAFI_UNICAST); + rib_delete (AFI_IP6, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL, + 0, zebra_flags, &p, gate, index, table); } -#endif /* HAVE_IPV6 */ return 0; } @@ -1973,8 +2066,8 @@ _netlink_route_debug( } } -int -netlink_neigh_update (int cmd, int ifindex, __u32 addr, char *lla, int llalen) +static int +netlink_neigh_update (int cmd, int ifindex, uint32_t addr, char *lla, int llalen) { struct { struct nlmsghdr n; @@ -1998,7 +2091,7 @@ netlink_neigh_update (int cmd, int ifindex, __u32 addr, char *lla, int llalen) addattr_l(&req.n, sizeof(req), NDA_DST, &addr, 4); addattr_l(&req.n, sizeof(req), NDA_LLADDR, lla, llalen); - return netlink_talk (&req.n, &zns->netlink_cmd, NS_DEFAULT); + return netlink_talk (&req.n, &zns->netlink_cmd, zns); } /* Routing table change via netlink interface. */ @@ -2079,6 +2172,20 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, addattr32(&req.n, sizeof req, RTA_TABLE, rib->table); } + if (rib->mtu || rib->nexthop_mtu) + { + char buf[NL_PKT_BUF_SIZE]; + struct rtattr *rta = (void *) buf; + u_int32_t mtu = rib->mtu; + if (!mtu || (rib->nexthop_mtu && rib->nexthop_mtu < mtu)) + mtu = rib->nexthop_mtu; + rta->rta_type = RTA_METRICS; + rta->rta_len = RTA_LENGTH(0); + rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTAX_MTU, &mtu, sizeof mtu); + addattr_l (&req.n, NL_PKT_BUF_SIZE, RTA_METRICS, RTA_DATA (rta), + RTA_PAYLOAD (rta)); + } + if (discard) { if (cmd == RTM_NEWROUTE) @@ -2392,6 +2499,12 @@ kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc) return netlink_address (RTM_DELADDR, AF_INET, ifp, ifc); } +int +kernel_neigh_update (int add, int ifindex, uint32_t addr, char *lla, int llalen) +{ + return netlink_neigh_update(add ? RTM_NEWNEIGH : RTM_DELNEIGH, ifindex, addr, + lla, llalen); +} extern struct thread_master *master; diff --git a/zebra/rt_netlink.h b/zebra/rt_netlink.h index 1d9280a295..80d035e839 100644 --- a/zebra/rt_netlink.h +++ b/zebra/rt_netlink.h @@ -41,9 +41,6 @@ nl_msg_type_to_str (uint16_t msg_type); extern const char * nl_rtproto_to_str (u_char rtproto); -int -netlink_neigh_update (int cmd, int ifindex, __u32 addr, char *lla, int llalen); - extern int interface_lookup_netlink (struct zebra_ns *zns); extern int netlink_route_read (struct zebra_ns *zns); diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index abeb87a427..24671829f0 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -76,7 +76,7 @@ kernel_rtm_ipv4 (int cmd, struct prefix *p, struct rib *rib, int family) struct nexthop *nexthop, *tnexthop; int recursing; int nexthop_num = 0; - unsigned int ifindex = 0; + ifindex_t ifindex = 0; int gate = 0; int error; char prefix_buf[PREFIX_STRLEN]; @@ -287,7 +287,7 @@ kernel_rtm_ipv6_multipath (int cmd, struct prefix *p, struct rib *rib, struct nexthop *nexthop, *tnexthop; int recursing; int nexthop_num = 0; - unsigned int ifindex = 0; + ifindex_t ifindex = 0; int gate = 0; int error; @@ -428,3 +428,10 @@ kernel_delete_ipv6 (struct prefix *p, struct rib *rib) return route; } #endif /* HAVE_IPV6 */ + +int +kernel_neigh_update (int add, int ifindex, uint32_t addr, char *lla, int llalen) +{ + /* TODO */ + return 0; +} diff --git a/zebra/rtadv.c b/zebra/rtadv.c index 750502aa23..8384b327ff 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -69,23 +69,26 @@ static void rtadv_event (struct zebra_ns *, enum rtadv_event, int); static int if_join_all_router (int, struct interface *); static int if_leave_all_router (int, struct interface *); -static int rtadv_increment_received(unsigned int *ifindex) { +static int +rtadv_increment_received(struct zebra_ns *zns, ifindex_t *ifindex) +{ int ret = -1; struct interface *iface; struct zebra_if *zif; - iface = if_lookup_by_index_vrf(*ifindex, VRF_DEFAULT); - if (iface && iface->info) { - zif = iface->info; - zif->ra_rcvd++; - ret = 0; - } + iface = if_lookup_by_index_per_ns (zns, *ifindex); + if (iface && iface->info) + { + zif = iface->info; + zif->ra_rcvd++; + ret = 0; + } return ret; } static int -rtadv_recv_packet (int sock, u_char *buf, int buflen, - struct sockaddr_in6 *from, unsigned int *ifindex, +rtadv_recv_packet (struct zebra_ns *zns, int sock, u_char *buf, int buflen, + struct sockaddr_in6 *from, ifindex_t *ifindex, int *hoplimit) { int ret; @@ -134,10 +137,7 @@ rtadv_recv_packet (int sock, u_char *buf, int buflen, } } - if(rtadv_increment_received(ifindex) < 0) - zlog_err("%s: could not increment RA received counter on ifindex %d", - __func__, *ifindex); - + rtadv_increment_received(zns, ifindex); return ret; } @@ -152,9 +152,6 @@ rtadv_send_packet (int sock, struct interface *ifp) struct cmsghdr *cmsgptr; struct in6_pktinfo *pkt; struct sockaddr_in6 addr; -#ifdef HAVE_STRUCT_SOCKADDR_DL - struct sockaddr_dl *sdl; -#endif /* HAVE_STRUCT_SOCKADDR_DL */ static void *adata = NULL; unsigned char buf[RTADV_MSG_SIZE]; struct nd_router_advert *rtadv; @@ -315,24 +312,6 @@ rtadv_send_packet (int sock, struct interface *ifp) } /* Hardware address. */ -#ifdef HAVE_STRUCT_SOCKADDR_DL - sdl = &ifp->sdl; - if (sdl != NULL && sdl->sdl_alen != 0) - { - buf[len++] = ND_OPT_SOURCE_LINKADDR; - - /* Option length should be rounded up to next octet if - the link address does not end on an octet boundary. */ - buf[len++] = (sdl->sdl_alen + 9) >> 3; - - memcpy (buf + len, LLADDR (sdl), sdl->sdl_alen); - len += sdl->sdl_alen; - - /* Pad option to end on an octet boundary. */ - memset (buf + len, 0, -(sdl->sdl_alen + 2) & 0x7); - len += -(sdl->sdl_alen + 2) & 0x7; - } -#else if (ifp->hw_addr_len != 0) { buf[len++] = ND_OPT_SOURCE_LINKADDR; @@ -348,7 +327,6 @@ rtadv_send_packet (int sock, struct interface *ifp) memset (buf + len, 0, -(ifp->hw_addr_len + 2) & 0x7); len += -(ifp->hw_addr_len + 2) & 0x7; } -#endif /* HAVE_STRUCT_SOCKADDR_DL */ /* MTU */ if (zif->rtadv.AdvLinkMTU) @@ -534,7 +512,7 @@ rtadv_process_advert (u_char *msg, unsigned int len, struct interface *ifp, static void -rtadv_process_packet (u_char *buf, unsigned int len, unsigned int ifindex, int hoplimit, +rtadv_process_packet (u_char *buf, unsigned int len, ifindex_t ifindex, int hoplimit, struct sockaddr_in6 *from, struct zebra_ns *zns) { struct icmp6_hdr *icmph; @@ -609,7 +587,7 @@ rtadv_read (struct thread *thread) int len; u_char buf[RTADV_MSG_SIZE]; struct sockaddr_in6 from; - unsigned int ifindex = 0; + ifindex_t ifindex = 0; int hoplimit = -1; struct zebra_ns *zns = THREAD_ARG (thread); @@ -619,7 +597,7 @@ rtadv_read (struct thread *thread) /* Register myself. */ rtadv_event (zns, RTADV_READ, sock); - len = rtadv_recv_packet (sock, buf, BUFSIZ, &from, &ifindex, &hoplimit); + len = rtadv_recv_packet (zns, sock, buf, sizeof (buf), &from, &ifindex, &hoplimit); if (len < 0) { diff --git a/zebra/rtread_getmsg.c b/zebra/rtread_getmsg.c index 6d2edde640..0facc1a19f 100644 --- a/zebra/rtread_getmsg.c +++ b/zebra/rtread_getmsg.c @@ -70,28 +70,30 @@ static void handle_route_entry (mib2_ipRouteEntry_t *routeEntry) { - struct prefix_ipv4 prefix; - struct in_addr tmpaddr, gateway; - u_char zebra_flags = 0; + struct prefix prefix; + struct in_addr tmpaddr, gateway; + union g_addr *ggateway; + u_char zebra_flags = 0; - if (routeEntry->ipRouteInfo.re_ire_type & IRE_CACHETABLE) - return; + if (routeEntry->ipRouteInfo.re_ire_type & IRE_CACHETABLE) + return; - if (routeEntry->ipRouteInfo.re_ire_type & IRE_HOST_REDIRECT) - zebra_flags |= ZEBRA_FLAG_SELFROUTE; + if (routeEntry->ipRouteInfo.re_ire_type & IRE_HOST_REDIRECT) + zebra_flags |= ZEBRA_FLAG_SELFROUTE; - prefix.family = AF_INET; + prefix.family = AF_INET; - tmpaddr.s_addr = routeEntry->ipRouteDest; - prefix.prefix = tmpaddr; + tmpaddr.s_addr = routeEntry->ipRouteDest; + prefix.u.prefix4 = tmpaddr; - tmpaddr.s_addr = routeEntry->ipRouteMask; - prefix.prefixlen = ip_masklen (tmpaddr); + tmpaddr.s_addr = routeEntry->ipRouteMask; + prefix.prefixlen = ip_masklen (tmpaddr); - gateway.s_addr = routeEntry->ipRouteNextHop; + gateway.s_addr = routeEntry->ipRouteNextHop; + ggateway = (union g_addr *)&gateway; - rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &prefix, - &gateway, NULL, 0, VRF_DEFAULT, 0, 0, 0, SAFI_UNICAST); + rib_add (AFI_IP, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0, + zebra_flags, &prefix, ggateway, NULL, 0, 0, 0, 0, 0); } void diff --git a/zebra/test_main.c b/zebra/test_main.c index 902c675aef..95c56bb046 100644 --- a/zebra/test_main.c +++ b/zebra/test_main.c @@ -112,7 +112,7 @@ usage (char *progname, int status) exit (status); } -static unsigned int test_ifindex = 0; +static ifindex_t test_ifindex = 0; /* testrib commands */ DEFUN (test_interface_state, diff --git a/zebra/zebra_ns.c b/zebra/zebra_ns.c index 6b04aa741a..084a5d181f 100644 --- a/zebra/zebra_ns.c +++ b/zebra/zebra_ns.c @@ -21,6 +21,7 @@ */ #include "zebra.h" +#include "lib/ns.h" #include "lib/vrf.h" #include "lib/prefix.h" #include "lib/memory.h" @@ -86,6 +87,8 @@ zebra_ns_init (void) { dzns = XCALLOC (MTYPE_ZEBRA_NS, sizeof (struct zebra_ns)); + ns_init (); + zebra_vrf_init (); zebra_ns_enable (0, (void **)&dzns); diff --git a/zebra/zebra_ns.h b/zebra/zebra_ns.h index 07fcfcdac1..8a821c465a 100644 --- a/zebra/zebra_ns.h +++ b/zebra/zebra_ns.h @@ -23,6 +23,8 @@ #if !defined(__ZEBRA_NS_H__) #define __ZEBRA_NS_H__ +#include + #ifdef HAVE_NETLINK /* Socket interface to kernel */ struct nlsock @@ -34,9 +36,6 @@ struct nlsock }; #endif -/* NetNS ID type. */ -typedef u_int16_t ns_id_t; - struct zebra_ns { /* net-ns name. */ diff --git a/zebra/zebra_ptm.c b/zebra/zebra_ptm.c index bf6afb0216..133b0fc2e9 100644 --- a/zebra/zebra_ptm.c +++ b/zebra/zebra_ptm.c @@ -31,6 +31,7 @@ #include "command.h" #include "stream.h" #include "ptm_lib.h" +#include "network.h" #include "buffer.h" #include "zebra/zebra_ptm_redistribute.h" #include "bfd.h" @@ -131,11 +132,13 @@ zebra_ptm_init (void) void zebra_ptm_finish(void) { - if (ptm_cb.ptm_sock != -1) - close(ptm_cb.ptm_sock); + int proto; - if (ptm_cb.wb) - buffer_free(ptm_cb.wb); + for (proto = 0; proto < ZEBRA_ROUTE_MAX; proto++) + if (CHECK_FLAG(ptm_cb.client_flags[proto], ZEBRA_PTM_BFD_CLIENT_FLAG_REG)) + zebra_ptm_bfd_client_deregister(proto); + + buffer_flush_all(ptm_cb.wb, ptm_cb.ptm_sock); if (ptm_cb.out_data) free(ptm_cb.out_data); @@ -150,6 +153,12 @@ zebra_ptm_finish(void) thread_cancel (ptm_cb.t_write); if (ptm_cb.t_timer) thread_cancel (ptm_cb.t_timer); + + if (ptm_cb.wb) + buffer_free(ptm_cb.wb); + + if (ptm_cb.ptm_sock != -1) + close(ptm_cb.ptm_sock); } static int @@ -375,9 +384,11 @@ zebra_ptm_socket_init (void) ptm_cb.ptm_sock = -1; - sock = socket (PF_UNIX, (SOCK_STREAM | SOCK_NONBLOCK), 0); + sock = socket (PF_UNIX, SOCK_STREAM, 0); if (sock < 0) return -1; + if (set_nonblocking(sock) < 0) + return -1; /* Make server socket. */ memset (&addr, 0, sizeof (struct sockaddr_un)); @@ -999,24 +1010,26 @@ zebra_ptm_bfd_client_register (struct zserv *client, int sock, u_short length) zlog_debug ("%s: Sent message (%d) %s", __func__, data_len, ptm_cb.out_data); zebra_ptm_send_message(ptm_cb.out_data, data_len); + + SET_FLAG(ptm_cb.client_flags[client->proto], ZEBRA_PTM_BFD_CLIENT_FLAG_REG); return 0; } /* BFD client deregister */ void -zebra_ptm_bfd_client_deregister (struct zserv *client) +zebra_ptm_bfd_client_deregister (int proto) { void *out_ctxt; char tmp_buf[64]; int data_len = ZEBRA_PTM_SEND_MAX_SOCKBUF; - if (client->proto != ZEBRA_ROUTE_OSPF && client->proto != ZEBRA_ROUTE_BGP - && client->proto != ZEBRA_ROUTE_OSPF6) + if (proto != ZEBRA_ROUTE_OSPF && proto != ZEBRA_ROUTE_BGP + && proto != ZEBRA_ROUTE_OSPF6) return; if (IS_ZEBRA_DEBUG_EVENT) - zlog_debug("bfd_client_deregister msg for client %s", - zebra_route_string(client->proto)); + zlog_err("bfd_client_deregister msg for client %s", + zebra_route_string(proto)); if (ptm_cb.ptm_sock == -1) { @@ -1030,7 +1043,7 @@ zebra_ptm_bfd_client_deregister (struct zserv *client) sprintf(tmp_buf, "%s", ZEBRA_PTM_BFD_CLIENT_DEREG_CMD); ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_CMD_STR, tmp_buf); - sprintf(tmp_buf, "%s", zebra_route_string(client->proto)); + sprintf(tmp_buf, "%s", zebra_route_string(proto)); ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_CLIENT_FIELD, tmp_buf); @@ -1039,7 +1052,9 @@ zebra_ptm_bfd_client_deregister (struct zserv *client) if (IS_ZEBRA_DEBUG_SEND) zlog_debug ("%s: Sent message (%d) %s", __func__, data_len, ptm_cb.out_data); + zebra_ptm_send_message(ptm_cb.out_data, data_len); + UNSET_FLAG(ptm_cb.client_flags[proto], ZEBRA_PTM_BFD_CLIENT_FLAG_REG); } int diff --git a/zebra/zebra_ptm.h b/zebra/zebra_ptm.h index 27c0e42f99..71c85d9094 100644 --- a/zebra/zebra_ptm.h +++ b/zebra/zebra_ptm.h @@ -27,6 +27,8 @@ extern const char ZEBRA_PTM_SOCK_NAME[]; #define ZEBRA_PTM_MAX_SOCKBUF 3200 /* 25B *128 ports */ #define ZEBRA_PTM_SEND_MAX_SOCKBUF 512 +#define ZEBRA_PTM_BFD_CLIENT_FLAG_REG (1 << 1) /* client registered with BFD */ + /* Zebra ptm context block */ struct zebra_ptm_cb { @@ -44,6 +46,7 @@ struct zebra_ptm_cb int ptm_enable; int pid; + u_int8_t client_flags[ZEBRA_ROUTE_MAX]; }; #define ZEBRA_PTM_STATUS_DOWN 0 @@ -72,5 +75,5 @@ int zebra_ptm_bfd_client_register (struct zserv *client, int sock, void zebra_ptm_if_init(struct zebra_if *zebra_ifp); void zebra_ptm_if_set_ptm_state(struct interface *ifp, struct zebra_if *zebra_ifp); void zebra_ptm_if_write (struct vty *vty, struct zebra_if *zebra_ifp); -void zebra_ptm_bfd_client_deregister (struct zserv *client); +void zebra_ptm_bfd_client_deregister (int proto); #endif diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index d70f528f5a..3812101431 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -21,12 +21,12 @@ #include +#include "if.h" #include "prefix.h" #include "table.h" #include "memory.h" #include "str.h" #include "command.h" -#include "if.h" #include "log.h" #include "sockunion.h" #include "linklist.h" @@ -119,13 +119,17 @@ _rnode_zlog(const char *_func, vrf_id_t vrf_id, struct route_node *rn, int prior int is_zebra_valid_kernel_table(u_int32_t table_id) { - if ((table_id > ZEBRA_KERNEL_TABLE_MAX) || - (table_id == RT_TABLE_UNSPEC) || + if ((table_id > ZEBRA_KERNEL_TABLE_MAX)) + return 0; + +#ifdef linux + if ((table_id == RT_TABLE_UNSPEC) || (table_id == RT_TABLE_LOCAL) || (table_id == RT_TABLE_COMPAT)) return 0; - else - return 1; +#endif + + return 1; } int @@ -191,7 +195,7 @@ rib_copy_nexthops (struct rib *rib, struct nexthop *nh) } /* Delete specified nexthop from the list. */ -static void +void rib_nexthop_delete (struct rib *rib, struct nexthop *nexthop) { if (nexthop->next) @@ -206,7 +210,7 @@ rib_nexthop_delete (struct rib *rib, struct nexthop *nexthop) struct nexthop * -rib_nexthop_ifindex_add (struct rib *rib, unsigned int ifindex) +rib_nexthop_ifindex_add (struct rib *rib, ifindex_t ifindex) { struct nexthop *nexthop; @@ -237,7 +241,7 @@ rib_nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv4, struct in_addr *src struct nexthop * rib_nexthop_ipv4_ifindex_add (struct rib *rib, struct in_addr *ipv4, - struct in_addr *src, unsigned int ifindex) + struct in_addr *src, ifindex_t ifindex) { struct nexthop *nexthop; struct interface *ifp; @@ -277,7 +281,7 @@ rib_nexthop_ipv6_add (struct rib *rib, struct in6_addr *ipv6) struct nexthop * rib_nexthop_ipv6_ifindex_add (struct rib *rib, struct in6_addr *ipv6, - unsigned int ifindex) + ifindex_t ifindex) { struct nexthop *nexthop; @@ -348,6 +352,7 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, zebra_deregister_rnh_static_nexthops(rib->vrf_id, nexthop->resolved, top); nexthops_free(nexthop->resolved); nexthop->resolved = NULL; + rib->nexthop_mtu = 0; } /* Skip nexthops that have been filtered out due to route-map */ @@ -405,6 +410,10 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, { if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) continue; + + /* if the next hop is imported from another table, skip it */ + if (match->type == ZEBRA_ROUTE_TABLE) + continue; if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) break; } @@ -537,6 +546,8 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, } resolved = 1; } + if (resolved && set) + rib->nexthop_mtu = match->mtu; return resolved; } else @@ -736,10 +747,10 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set, } struct rib * -rib_match_ipv4 (struct in_addr addr, safi_t safi, vrf_id_t vrf_id, - struct route_node **rn_out) +rib_match (afi_t afi, safi_t safi, vrf_id_t vrf_id, + union g_addr *addr, struct route_node **rn_out) { - struct prefix_ipv4 p; + struct prefix p; struct route_table *table; struct route_node *rn; struct rib *match; @@ -747,14 +758,18 @@ rib_match_ipv4 (struct in_addr addr, safi_t safi, vrf_id_t vrf_id, int recursing; /* Lookup table. */ - table = zebra_vrf_table (AFI_IP, safi, vrf_id); + table = zebra_vrf_table (afi, safi, vrf_id); if (! table) return 0; - memset (&p, 0, sizeof (struct prefix_ipv4)); - p.family = AF_INET; + memset (&p, 0, sizeof (struct prefix)); + p.family = afi; + p.u.prefix = *(u_char *)addr; p.prefixlen = IPV4_MAX_PREFIXLEN; - p.prefix = addr; + if (afi == AFI_IP) + p.prefixlen = IPV4_MAX_PREFIXLEN; + else + p.prefixlen = IPV6_MAX_PREFIXLEN; rn = route_node_match (table, (struct prefix *) &p); @@ -809,23 +824,23 @@ rib_match_ipv4_multicast (struct in_addr addr, struct route_node **rn_out) { struct rib *rib = NULL, *mrib = NULL, *urib = NULL; struct route_node *m_rn = NULL, *u_rn = NULL; - int skip_bgp = 0; /* bool */ + union g_addr gaddr = { .ipv4 = addr }; switch (ipv4_multicast_mode) { case MCAST_MRIB_ONLY: - return rib_match_ipv4 (addr, SAFI_MULTICAST, skip_bgp, rn_out); + return rib_match (AFI_IP, SAFI_MULTICAST, VRF_DEFAULT, &gaddr, rn_out); case MCAST_URIB_ONLY: - return rib_match_ipv4 (addr, SAFI_UNICAST, skip_bgp, rn_out); + return rib_match (AFI_IP, SAFI_UNICAST, VRF_DEFAULT, &gaddr, rn_out); case MCAST_NO_CONFIG: case MCAST_MIX_MRIB_FIRST: - rib = mrib = rib_match_ipv4 (addr, SAFI_MULTICAST, skip_bgp, &m_rn); + rib = mrib = rib_match (AFI_IP, SAFI_MULTICAST, VRF_DEFAULT, &gaddr, &m_rn); if (!mrib) - rib = urib = rib_match_ipv4 (addr, SAFI_UNICAST, skip_bgp, &u_rn); + rib = urib = rib_match (AFI_IP, SAFI_UNICAST, VRF_DEFAULT, &gaddr, &u_rn); break; case MCAST_MIX_DISTANCE: - mrib = rib_match_ipv4 (addr, SAFI_MULTICAST, skip_bgp, &m_rn); - urib = rib_match_ipv4 (addr, SAFI_UNICAST, skip_bgp, &u_rn); + mrib = rib_match (AFI_IP, SAFI_MULTICAST, VRF_DEFAULT, &gaddr, &m_rn); + urib = rib_match (AFI_IP, SAFI_UNICAST, VRF_DEFAULT, &gaddr, &u_rn); if (mrib && urib) rib = urib->distance < mrib->distance ? urib : mrib; else if (mrib) @@ -834,8 +849,8 @@ rib_match_ipv4_multicast (struct in_addr addr, struct route_node **rn_out) rib = urib; break; case MCAST_MIX_PFXLEN: - mrib = rib_match_ipv4 (addr, SAFI_MULTICAST, skip_bgp, &m_rn); - urib = rib_match_ipv4 (addr, SAFI_UNICAST, skip_bgp, &u_rn); + mrib = rib_match (AFI_IP, SAFI_MULTICAST, VRF_DEFAULT, &gaddr, &m_rn); + urib = rib_match (AFI_IP, SAFI_UNICAST, VRF_DEFAULT, &gaddr, &u_rn); if (mrib && urib) rib = u_rn->p.prefixlen > m_rn->p.prefixlen ? urib : mrib; else if (mrib) @@ -998,68 +1013,6 @@ rib_lookup_ipv4_route (struct prefix_ipv4 *p, union sockunion * qgate, return ZEBRA_RIB_NOTFOUND; } -struct rib * -rib_match_ipv6 (struct in6_addr *addr, vrf_id_t vrf_id) -{ - struct prefix_ipv6 p; - struct route_table *table; - struct route_node *rn; - struct rib *match; - struct nexthop *newhop, *tnewhop; - int recursing; - - /* Lookup table. */ - table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id); - if (! table) - return 0; - - memset (&p, 0, sizeof (struct prefix_ipv6)); - p.family = AF_INET6; - p.prefixlen = IPV6_MAX_PREFIXLEN; - IPV6_ADDR_COPY (&p.prefix, addr); - - rn = route_node_match (table, (struct prefix *) &p); - - while (rn) - { - route_unlock_node (rn); - - /* Pick up selected route. */ - RNODE_FOREACH_RIB (rn, match) - { - if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) - continue; - if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) - break; - } - - /* If there is no selected route or matched route is EGP, go up - tree. */ - if (! match) - { - do { - rn = rn->parent; - } while (rn && rn->info == NULL); - if (rn) - route_lock_node (rn); - } - else - { - if (match->type == ZEBRA_ROUTE_CONNECT) - /* Directly point connected route. */ - return match; - else - { - for (ALL_NEXTHOPS_RO(match->nexthop, newhop, tnewhop, recursing)) - if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)) - return match; - return NULL; - } - } - } - return NULL; -} - #define RIB_SYSTEM_ROUTE(R) \ ((R)->type == ZEBRA_ROUTE_KERNEL || (R)->type == ZEBRA_ROUTE_CONNECT) @@ -1180,7 +1133,7 @@ nexthop_active_check (struct route_node *rn, struct rib *rib, /* Iterate over all nexthops of the given RIB entry and refresh their * ACTIVE flag. rib->nexthop_active_num is updated accordingly. If any * nexthop is found to toggle the ACTIVE flag, the whole rib structure - * is flagged with ZEBRA_FLAG_CHANGED. The 4th 'set' argument is + * is flagged with RIB_ENTRY_CHANGED. The 4th 'set' argument is * transparently passed to nexthop_active_check(). * * Return value is the new number of active nexthops. @@ -1191,12 +1144,12 @@ nexthop_active_update (struct route_node *rn, struct rib *rib, int set) { struct nexthop *nexthop; union g_addr prev_src; - unsigned int prev_active, prev_index, new_active, old_num_nh; - + unsigned int prev_active, new_active, old_num_nh; + ifindex_t prev_index; old_num_nh = rib->nexthop_active_num; rib->nexthop_active_num = 0; - UNSET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED); + UNSET_FLAG (rib->status, RIB_ENTRY_CHANGED); for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) { @@ -1216,15 +1169,15 @@ nexthop_active_update (struct route_node *rn, struct rib *rib, int set) nexthop->type < NEXTHOP_TYPE_BLACKHOLE) && !(IPV6_ADDR_SAME (&prev_src.ipv6, &nexthop->rmap_src.ipv6)))) { - SET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED); + SET_FLAG (rib->status, RIB_ENTRY_CHANGED); SET_FLAG (rib->status, RIB_ENTRY_NEXTHOPS_CHANGED); } } if (old_num_nh != rib->nexthop_active_num) - SET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED); + SET_FLAG (rib->status, RIB_ENTRY_CHANGED); - if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_CHANGED)) + if (CHECK_FLAG (rib->status, RIB_ENTRY_CHANGED)) { SET_FLAG (rib->status, RIB_ENTRY_NEXTHOPS_CHANGED); } @@ -1237,7 +1190,7 @@ nexthop_active_update (struct route_node *rn, struct rib *rib, int set) /* Update flag indicates whether this is a "replace" or not. Currently, this * is only used for IPv4. */ -static int +int rib_install_kernel (struct route_node *rn, struct rib *rib, int update) { int ret = 0; @@ -1292,7 +1245,7 @@ rib_install_kernel (struct route_node *rn, struct rib *rib, int update) } /* Uninstall the route from kernel. */ -static int +int rib_uninstall_kernel (struct route_node *rn, struct rib *rib) { int ret = 0; @@ -1421,7 +1374,7 @@ rib_process_add_route (struct zebra_vrf *zvrf, struct route_node *rn, /* Update real nexthop. This may actually determine if nexthop is active or not. */ if (!nexthop_active_update (rn, select, 1)) { - UNSET_FLAG(select->flags, ZEBRA_FLAG_CHANGED); + UNSET_FLAG(select->status, RIB_ENTRY_CHANGED); return; } @@ -1447,7 +1400,7 @@ rib_process_add_route (struct zebra_vrf *zvrf, struct route_node *rn, /* Update for redistribution. */ if (installed) redistribute_update (&rn->p, select, NULL); - UNSET_FLAG(select->flags, ZEBRA_FLAG_CHANGED); + UNSET_FLAG(select->status, RIB_ENTRY_CHANGED); } static void @@ -1474,7 +1427,7 @@ rib_process_del_route (struct zebra_vrf *zvrf, struct route_node *rn, /* Update nexthop for route, reset changed flag. */ nexthop_active_update (rn, fib, 1); - UNSET_FLAG(fib->flags, ZEBRA_FLAG_CHANGED); + UNSET_FLAG(fib->status, RIB_ENTRY_CHANGED); } static void @@ -1495,7 +1448,7 @@ rib_process_update_route (struct zebra_vrf *zvrf, struct route_node *rn, * something has changed. */ if (select != fib || - CHECK_FLAG (select->flags, ZEBRA_FLAG_CHANGED)) + CHECK_FLAG (select->status, RIB_ENTRY_CHANGED)) { zfpm_trigger_update (rn, "updating existing route"); @@ -1544,7 +1497,6 @@ rib_process_update_route (struct zebra_vrf *zvrf, struct route_node *rn, for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next) UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); } - } /* Update for redistribution. */ @@ -1615,11 +1567,53 @@ rib_process_update_route (struct zebra_vrf *zvrf, struct route_node *rn, /* Set real nexthop. */ nexthop_active_update (rn, fib, 1); - UNSET_FLAG(fib->flags, ZEBRA_FLAG_CHANGED); + UNSET_FLAG(fib->status, RIB_ENTRY_CHANGED); } /* Clear changed flag. */ - UNSET_FLAG(select->flags, ZEBRA_FLAG_CHANGED); + UNSET_FLAG(select->status, RIB_ENTRY_CHANGED); +} + +/* Check if 'alternate' RIB entry is better than 'current'. */ +static struct rib * +rib_choose_best (struct rib *current, struct rib *alternate) +{ + if (current == NULL) + return alternate; + + /* filter route selection in following order: + * - connected beats other types + * - lower distance beats higher + * - lower metric beats higher for equal distance + * - last, hence oldest, route wins tie break. + */ + + /* Connected routes. Pick the last connected + * route of the set of lowest metric connected routes. + */ + if (alternate->type == ZEBRA_ROUTE_CONNECT) + { + if (current->type != ZEBRA_ROUTE_CONNECT + || alternate->metric <= current->metric) + return alternate; + + return current; + } + + if (current->type == ZEBRA_ROUTE_CONNECT) + return current; + + /* higher distance loses */ + if (alternate->distance < current->distance) + return alternate; + if (current->distance < alternate->distance) + return current; + + /* metric tie-breaks equal distance */ + if (alternate->metric <= current->metric) + return alternate; + + return current; } /* Core function for processing routing information base. */ @@ -1631,6 +1625,7 @@ rib_process (struct route_node *rn) struct rib *fib = NULL; struct rib *select = NULL; struct rib *del = NULL; + struct rib *best = NULL; char buf[INET6_ADDRSTRLEN]; rib_dest_t *dest; struct zebra_vrf *zvrf = NULL; @@ -1699,7 +1694,7 @@ rib_process (struct route_node *rn) * the nexthop_active_update() code. Thus, we might miss changes to * recursive NHs. */ - if (!CHECK_FLAG(rib->flags, ZEBRA_FLAG_CHANGED) && + if (!CHECK_FLAG(rib->status, RIB_ENTRY_CHANGED) && ! nexthop_active_update (rn, rib, 0)) { if (rib->type == ZEBRA_ROUTE_TABLE) @@ -1727,66 +1722,16 @@ rib_process (struct route_node *rn) /* Infinite distance. */ if (rib->distance == DISTANCE_INFINITY) { - UNSET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED); + UNSET_FLAG (rib->status, RIB_ENTRY_CHANGED); continue; } - /* Newly selected rib, the common case. */ - if (!select) - { - select = rib; - continue; - } - - /* filter route selection in following order: - * - connected beats other types - * - lower distance beats higher - * - lower metric beats higher for equal distance - * - last, hence oldest, route wins tie break. - */ - - /* Connected routes. Pick the last connected - * route of the set of lowest metric connected routes. - */ - if (rib->type == ZEBRA_ROUTE_CONNECT) - { - if (select->type != ZEBRA_ROUTE_CONNECT - || rib->metric <= select->metric) - { - UNSET_FLAG (select->flags, ZEBRA_FLAG_CHANGED); - select = rib; - } - else - UNSET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED); - continue; - } - else if (select->type == ZEBRA_ROUTE_CONNECT) - { - UNSET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED); - continue; - } - - /* higher distance loses */ - if (rib->distance > select->distance) - { - UNSET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED); - continue; - } - - /* lower wins */ - if (rib->distance < select->distance) - { - UNSET_FLAG (select->flags, ZEBRA_FLAG_CHANGED); - select = rib; - continue; - } - - /* metric tie-breaks equal distance */ - if (rib->metric <= select->metric) - { - UNSET_FLAG (select->flags, ZEBRA_FLAG_CHANGED); - select = rib; - } + best = rib_choose_best(select, rib); + if (select && best != select) + UNSET_FLAG (select->status, RIB_ENTRY_CHANGED); + if (best != rib) + UNSET_FLAG (rib->status, RIB_ENTRY_CHANGED); + select = best; } /* RNODE_FOREACH_RIB_SAFE */ /* After the cycle is finished, the following pointers will be set: @@ -1815,7 +1760,7 @@ rib_process (struct route_node *rn) if (IS_ZEBRA_DEBUG_RIB) rnode_debug (rn, vrf_id, "Updating existing route, select %p, fib %p", (void *)select, (void *)fib); - if (CHECK_FLAG (select->flags, ZEBRA_FLAG_CHANGED)) + if (CHECK_FLAG (select->status, RIB_ENTRY_CHANGED)) { if (info->safi == SAFI_UNICAST) zfpm_trigger_update (rn, "updating existing route"); @@ -1857,7 +1802,7 @@ rib_process (struct route_node *rn) rib_uninstall_kernel (rn, select); UNSET_FLAG (select->flags, ZEBRA_FLAG_SELECTED); } - UNSET_FLAG (select->flags, ZEBRA_FLAG_CHANGED); + UNSET_FLAG (select->status, RIB_ENTRY_CHANGED); } else if (! RIB_SYSTEM_ROUTE (select)) { @@ -1910,7 +1855,7 @@ rib_process (struct route_node *rn) /* Set real nexthop. */ nexthop_active_update (rn, fib, 1); - UNSET_FLAG(fib->flags, ZEBRA_FLAG_CHANGED); + UNSET_FLAG(fib->status, RIB_ENTRY_CHANGED); } /* Regardless of some RIB entry being SELECTED or not before, now we can @@ -1980,7 +1925,7 @@ rib_process (struct route_node *rn) redistribute_delete(&rn->p, fib); } } - UNSET_FLAG(select->flags, ZEBRA_FLAG_CHANGED); + UNSET_FLAG(select->status, RIB_ENTRY_CHANGED); } #endif @@ -2313,7 +2258,7 @@ rib_link (struct route_node *rn, struct rib *rib, int process) rib_queue_add (rn); } -static void +void rib_addnode (struct route_node *rn, struct rib *rib, int process) { /* RIB node has been un-removed before route-node is processed. @@ -2368,7 +2313,7 @@ rib_unlink (struct route_node *rn, struct rib *rib) } -static void +void rib_delnode (struct route_node *rn, struct rib *rib) { afi_t afi; @@ -2402,123 +2347,6 @@ rib_delnode (struct route_node *rn, struct rib *rib) } } -int -rib_add_ipv4 (int type, u_short instance, int flags, struct prefix_ipv4 *p, - struct in_addr *gate, struct in_addr *src, - unsigned int ifindex, vrf_id_t vrf_id, u_int32_t table_id, - u_int32_t metric, u_char distance, safi_t safi) -{ - struct rib *rib; - struct rib *same = NULL; - struct route_table *table; - struct route_node *rn; - struct nexthop *nexthop; - - /* Lookup table. */ - table = zebra_vrf_table_with_table_id (AFI_IP, safi, vrf_id, table_id); - if (! table) - return 0; - - /* Make it sure prefixlen is applied to the prefix. */ - apply_mask_ipv4 (p); - - /* Set default distance by route type. */ - if (distance == 0) - { - if ((unsigned)type >= array_size(route_info)) - distance = 150; - else - distance = route_info[type].distance; - - /* iBGP distance is 200. */ - if (type == ZEBRA_ROUTE_BGP && CHECK_FLAG (flags, ZEBRA_FLAG_IBGP)) - distance = 200; - } - - /* Lookup route node.*/ - rn = route_node_get (table, (struct prefix *) p); - - /* If same type of route are installed, treat it as a implicit - withdraw. */ - RNODE_FOREACH_RIB (rn, rib) - { - if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) - continue; - - if (rib->type != type) - continue; - if (rib->instance != instance) - continue; - - if (rib->type != ZEBRA_ROUTE_CONNECT) - { - same = rib; - break; - } - /* Duplicate connected route comes in. */ - else if ((nexthop = rib->nexthop) && - nexthop->type == NEXTHOP_TYPE_IFINDEX && - nexthop->ifindex == ifindex && - !CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) - { - rib->refcnt++; - return 0 ; - } - } - - /* Allocate new rib structure. */ - rib = XCALLOC (MTYPE_RIB, sizeof (struct rib)); - rib->type = type; - rib->instance = instance; - rib->distance = distance; - rib->flags = flags; - rib->metric = metric; - rib->table = table_id; - rib->vrf_id = vrf_id; - rib->nexthop_num = 0; - rib->uptime = time (NULL); - - /* Nexthop settings. */ - if (gate) - { - if (ifindex) - rib_nexthop_ipv4_ifindex_add (rib, gate, src, ifindex); - else - rib_nexthop_ipv4_add (rib, gate, src); - } - else - rib_nexthop_ifindex_add (rib, ifindex); - - /* If this route is kernel route, set FIB flag to the route. */ - if (type == ZEBRA_ROUTE_KERNEL || type == ZEBRA_ROUTE_CONNECT) - for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) - SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); - - /* Link new rib to node.*/ - if (IS_ZEBRA_DEBUG_RIB) - { - char buf[INET6_ADDRSTRLEN]; - if (IS_ZEBRA_DEBUG_RIB) - { - inet_ntop (p->family, &p->prefix, buf, INET6_ADDRSTRLEN); - zlog_debug ("%u:%s/%d: Inserting route rn %p, rib %p (type %d) " - "existing %p", - vrf_id, buf, p->prefixlen, (void *)rn, (void *)rib, rib->type, (void *)same); - } - - if (IS_ZEBRA_DEBUG_RIB_DETAILED) - rib_dump ((struct prefix *)p, rib); - } - rib_addnode (rn, rib, 1); - - /* Free implicit route.*/ - if (same) - rib_delnode (rn, same); - - route_unlock_node (rn); - return 0; -} - /* This function dumps the contents of a given RIB entry into * standard debug log. Calling function name and IP prefix in * question are passed as 1st and 2nd arguments. @@ -2546,9 +2374,10 @@ void _rib_dump (const char * func, ); zlog_debug ( - "%s: metric == %u, distance == %u, flags == %u, status == %u", + "%s: metric == %u, mtu == %u, distance == %u, flags == %u, status == %u", func, rib->metric, + rib->mtu, rib->distance, rib->flags, rib->status @@ -2681,21 +2510,31 @@ void rib_lookup_and_pushup (struct prefix_ipv4 * p, vrf_id_t vrf_id) } int -rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib, safi_t safi) +rib_add_multipath (afi_t afi, safi_t safi, struct prefix *p, + struct rib *rib) { struct route_table *table; struct route_node *rn; struct rib *same; struct nexthop *nexthop; int ret = 0; - + int family; + + if (!rib) + return 0; + + if (p->family == AF_INET) + family = AFI_IP; + else + family = AFI_IP6; + /* Lookup table. */ - table = zebra_vrf_table_with_table_id (AFI_IP, safi, rib->vrf_id, rib->table); + table = zebra_vrf_table_with_table_id (family, safi, rib->vrf_id, rib->table); if (! table) return 0; /* Make it sure prefixlen is applied to the prefix. */ - apply_mask_ipv4 (p); + apply_mask (p); /* Set default distance by route type. */ if (rib->distance == 0) @@ -2709,7 +2548,7 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib, safi_t safi) } /* Lookup route node.*/ - rn = route_node_get (table, (struct prefix *) p); + rn = route_node_get (table, p); /* If same type of route are installed, treat it as a implicit withdraw. */ @@ -2735,7 +2574,7 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib, safi_t safi) char buf[INET6_ADDRSTRLEN]; if (IS_ZEBRA_DEBUG_RIB) { - inet_ntop (p->family, &p->prefix, buf, INET6_ADDRSTRLEN); + inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN); zlog_debug ("%u:%s/%d: Inserting route rn %p, rib %p (type %d) " "existing %p", rib->vrf_id, buf, p->prefixlen, (void *)rn, @@ -2759,11 +2598,10 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib, safi_t safi) return ret; } -/* XXX factor with rib_delete_ipv6 */ int -rib_delete_ipv4 (int type, u_short instance, int flags, struct prefix_ipv4 *p, - struct in_addr *gate, unsigned int ifindex, vrf_id_t vrf_id, - u_int32_t table_id, safi_t safi) +rib_delete (afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, u_short instance, + int flags, struct prefix *p, union g_addr *gate, ifindex_t ifindex, + u_int32_t table_id) { struct route_table *table; struct route_node *rn; @@ -2776,15 +2614,15 @@ rib_delete_ipv4 (int type, u_short instance, int flags, struct prefix_ipv4 *p, char buf2[INET6_ADDRSTRLEN]; /* Lookup table. */ - table = zebra_vrf_table_with_table_id (AFI_IP, safi, vrf_id, table_id); + table = zebra_vrf_table_with_table_id (afi, safi, vrf_id, table_id); if (! table) return 0; /* Apply mask. */ - apply_mask_ipv4 (p); + apply_mask (p); /* Lookup route node. */ - rn = route_node_lookup (table, (struct prefix *) p); + rn = route_node_lookup (table, p); if (! rn) { if (IS_ZEBRA_DEBUG_RIB) @@ -2830,7 +2668,8 @@ rib_delete_ipv4 (int type, u_short instance, int flags, struct prefix_ipv4 *p, break; } for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) - if (IPV4_ADDR_SAME (&nexthop->gate.ipv4, gate)) + if (IPV4_ADDR_SAME (&nexthop->gate.ipv4, gate) || + IPV6_ADDR_SAME (&nexthop->gate.ipv6, gate)) { same = rib; break; @@ -2848,10 +2687,10 @@ rib_delete_ipv4 (int type, u_short instance, int flags, struct prefix_ipv4 *p, { if (IS_ZEBRA_DEBUG_RIB) { - zlog_debug ("%u:%s/%d: rn %p, rib %p (type %d) was deleted " + zlog_debug ("%u:%s: rn %p, rib %p (type %d) was deleted " "from kernel, adding", - vrf_id, inet_ntop (p->family, &p->prefix, buf1, INET6_ADDRSTRLEN), - p->prefixlen, rn, fib, fib->type); + vrf_id, prefix2str(p, buf1, INET6_ADDRSTRLEN), + rn, fib, fib->type); } if (allow_delete) { @@ -2876,7 +2715,7 @@ rib_delete_ipv4 (int type, u_short instance, int flags, struct prefix_ipv4 *p, zlog_debug ("%u:%s: via %s ifindex %d type %d " "doesn't exist in rib", vrf_id, prefix2str (p, buf1, sizeof(buf1)), - inet_ntop (AF_INET, gate, buf2, INET_ADDRSTRLEN), + inet_ntop (family2afi(afi), gate, buf2, INET_ADDRSTRLEN), ifindex, type); else @@ -2897,444 +2736,14 @@ rib_delete_ipv4 (int type, u_short instance, int flags, struct prefix_ipv4 *p, return 0; } -/* Install static route into rib. */ -void -static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_route *si) -{ - struct rib *rib; - struct route_node *rn; - struct route_table *table; - struct prefix nh_p; - /* Lookup table. */ - table = zebra_vrf_table (afi, safi, si->vrf_id); - if (! table) - return; - - /* Lookup existing route */ - rn = route_node_get (table, p); - RNODE_FOREACH_RIB (rn, rib) - { - if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) - continue; - - if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance) - break; - } - - if (rib) - { - /* if tag value changed , update old value in RIB */ - if (rib->tag != si->tag) - rib->tag = si->tag; - - /* Same distance static route is there. Update it with new - nexthop. */ - route_unlock_node (rn); - switch (si->type) - { - case STATIC_IPV4_GATEWAY: - rib_nexthop_ipv4_add (rib, &si->addr.ipv4, NULL); - nh_p.family = AF_INET; - nh_p.prefixlen = IPV4_MAX_BITLEN; - nh_p.u.prefix4 = si->addr.ipv4; - zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn); - break; - case STATIC_IFINDEX: - rib_nexthop_ifindex_add (rib, si->ifindex); - break; - case STATIC_IPV4_BLACKHOLE: - rib_nexthop_blackhole_add (rib); - break; - case STATIC_IPV6_GATEWAY: - rib_nexthop_ipv6_add (rib, &si->addr.ipv6); - nh_p.family = AF_INET6; - nh_p.prefixlen = IPV6_MAX_BITLEN; - nh_p.u.prefix6 = si->addr.ipv6; - zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn); - break; - case STATIC_IPV6_GATEWAY_IFINDEX: - rib_nexthop_ipv6_ifindex_add (rib, &si->addr.ipv6, si->ifindex); - break; - } - - if (IS_ZEBRA_DEBUG_RIB) - { - char buf[INET6_ADDRSTRLEN]; - if (IS_ZEBRA_DEBUG_RIB) - { - inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN); - zlog_debug ("%u:%s/%d: Modifying route rn %p, rib %p (type %d)", - si->vrf_id, buf, p->prefixlen, rn, rib, rib->type); - } - } - /* Schedule route for processing or invoke NHT, as appropriate. */ - if (si->type == STATIC_IPV4_GATEWAY || - si->type == STATIC_IPV6_GATEWAY) - zebra_evaluate_rnh(si->vrf_id, nh_p.family, 1, RNH_NEXTHOP_TYPE, &nh_p); - else - rib_queue_add (rn); - } - else - { - /* This is new static route. */ - rib = XCALLOC (MTYPE_RIB, sizeof (struct rib)); - - rib->type = ZEBRA_ROUTE_STATIC; - rib->instance = 0; - rib->distance = si->distance; - rib->metric = 0; - rib->vrf_id = si->vrf_id; - rib->table = si->vrf_id ? (zebra_vrf_lookup(si->vrf_id))->table_id : zebrad.rtm_table_default; - rib->nexthop_num = 0; - rib->tag = si->tag; - - switch (si->type) - { - case STATIC_IPV4_GATEWAY: - rib_nexthop_ipv4_add (rib, &si->addr.ipv4, NULL); - nh_p.family = AF_INET; - nh_p.prefixlen = IPV4_MAX_BITLEN; - nh_p.u.prefix4 = si->addr.ipv4; - zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn); - break; - case STATIC_IFINDEX: - rib_nexthop_ifindex_add (rib, si->ifindex); - break; - case STATIC_IPV4_BLACKHOLE: - rib_nexthop_blackhole_add (rib); - break; - case STATIC_IPV6_GATEWAY: - rib_nexthop_ipv6_add (rib, &si->addr.ipv6); - nh_p.family = AF_INET6; - nh_p.prefixlen = IPV6_MAX_BITLEN; - nh_p.u.prefix6 = si->addr.ipv6; - zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn); - break; - case STATIC_IPV6_GATEWAY_IFINDEX: - rib_nexthop_ipv6_ifindex_add (rib, &si->addr.ipv6, si->ifindex); - break; - } - - /* Save the flags of this static routes (reject, blackhole) */ - rib->flags = si->flags; - - if (IS_ZEBRA_DEBUG_RIB) - { - char buf[INET6_ADDRSTRLEN]; - if (IS_ZEBRA_DEBUG_RIB) - { - inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN); - zlog_debug ("%u:%s/%d: Inserting route rn %p, rib %p (type %d)", - si->vrf_id, buf, p->prefixlen, rn, rib, rib->type); - } - } - /* Link this rib to the tree. Schedule for processing or invoke NHT, - * as appropriate. - */ - if (si->type == STATIC_IPV4_GATEWAY || - si->type == STATIC_IPV6_GATEWAY) - { - rib_addnode (rn, rib, 0); - zebra_evaluate_rnh(si->vrf_id, nh_p.family, 1, RNH_NEXTHOP_TYPE, &nh_p); - } - else - rib_addnode (rn, rib, 1); - } -} - -static int -static_nexthop_same (struct nexthop *nexthop, struct static_route *si) -{ - if (nexthop->type == NEXTHOP_TYPE_IPV4 - && si->type == STATIC_IPV4_GATEWAY - && IPV4_ADDR_SAME (&nexthop->gate.ipv4, &si->addr.ipv4)) - return 1; - if (nexthop->type == NEXTHOP_TYPE_IFINDEX - && si->type == STATIC_IFINDEX - && nexthop->ifindex == si->ifindex) - return 1; - if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE - && si->type == STATIC_IPV4_BLACKHOLE) - return 1; - if (nexthop->type == NEXTHOP_TYPE_IPV6 - && si->type == STATIC_IPV6_GATEWAY - && IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->addr.ipv6)) - return 1; - if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX - && si->type == STATIC_IPV6_GATEWAY_IFINDEX - && IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->addr.ipv6) - && nexthop->ifindex == si->ifindex) - return 1; - return 0; -} - -/* Uninstall static route from RIB. */ -void -static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p, struct static_route *si) -{ - struct route_node *rn; - struct rib *rib; - struct nexthop *nexthop; - struct route_table *table; - struct prefix nh_p; - - /* Lookup table. */ - table = zebra_vrf_table (afi, safi, si->vrf_id); - if (! table) - return; - - /* Lookup existing route with type and distance. */ - rn = route_node_lookup (table, p); - if (! rn) - return; - - RNODE_FOREACH_RIB (rn, rib) - { - if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) - continue; - - if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance && - rib->tag == si->tag) - break; - } - - if (! rib) - { - route_unlock_node (rn); - return; - } - - /* Lookup nexthop. */ - for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) - if (static_nexthop_same (nexthop, si)) - break; - - /* Can't find nexthop. */ - if (! nexthop) - { - route_unlock_node (rn); - return; - } - - /* Check nexthop. */ - if (rib->nexthop_num == 1) - rib_delnode (rn, rib); - else - { - /* Mark this nexthop as inactive and reinstall the route. Then, delete - * the nexthop. There is no need to re-evaluate the route for this - * scenario. - */ - if (IS_ZEBRA_DEBUG_RIB) - { - char buf[INET6_ADDRSTRLEN]; - if (IS_ZEBRA_DEBUG_RIB) - { - inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN); - zlog_debug ("%u:%s/%d: Modifying route rn %p, rib %p (type %d)", - si->vrf_id, buf, p->prefixlen, rn, rib, rib->type); - } - } - UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); - if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) - { - /* If there are other active nexthops, do an update. */ - if (rib->nexthop_active_num > 1) - { - rib_install_kernel (rn, rib, 1); - redistribute_update (&rn->p, rib, NULL); - } - else - { - redistribute_delete (&rn->p, rib); - rib_uninstall_kernel (rn, rib); - } - } - - if (afi == AFI_IP) - { - /* Delete the nexthop and dereg from NHT */ - nh_p.family = AF_INET; - nh_p.prefixlen = IPV4_MAX_BITLEN; - nh_p.u.prefix4 = nexthop->gate.ipv4; - } - else - { - nh_p.family = AF_INET6; - nh_p.prefixlen = IPV6_MAX_BITLEN; - nh_p.u.prefix6 = nexthop->gate.ipv6; - } - rib_nexthop_delete (rib, nexthop); - zebra_deregister_rnh_static_nh(si->vrf_id, &nh_p, rn); - nexthop_free (nexthop); - } - /* Unlock node. */ - route_unlock_node (rn); -} int -static_add_ipv4 (safi_t safi, struct prefix *p, struct in_addr *gate, unsigned int ifindex, - const char *ifname, u_char flags, u_short tag, - u_char distance, struct zebra_vrf *zvrf) -{ - u_char type = 0; - struct route_node *rn; - struct static_route *si; - struct static_route *pp; - struct static_route *cp; - struct static_route *update = NULL; - struct route_table *stable = zvrf->stable[AFI_IP][safi]; - - if (! stable) - return -1; - - /* Lookup static route prefix. */ - rn = route_node_get (stable, p); - - /* Make flags. */ - if (gate) - type = STATIC_IPV4_GATEWAY; - else if (ifindex) - type = STATIC_IFINDEX; - else - type = STATIC_IPV4_BLACKHOLE; - - /* Do nothing if there is a same static route. */ - for (si = rn->info; si; si = si->next) - { - if (type == si->type - && (! gate || IPV4_ADDR_SAME (gate, &si->addr.ipv4)) - && (! ifindex || ifindex == si->ifindex)) - { - if ((distance == si->distance) && (tag == si->tag)) - { - route_unlock_node (rn); - return 0; - } - else - update = si; - } - } - - /* Distance or tag changed. */ - if (update) - static_delete_ipv4 (safi, p, gate, ifindex, update->tag, update->distance, zvrf); - - /* Make new static route structure. */ - si = XCALLOC (MTYPE_STATIC_ROUTE, sizeof (struct static_route)); - - si->type = type; - si->distance = distance; - si->flags = flags; - si->tag = tag; - si->vrf_id = zvrf->vrf_id; - si->ifindex = ifindex; - if (si->ifindex) - strcpy(si->ifname, ifname); - - if (gate) - si->addr.ipv4 = *gate; - - /* Add new static route information to the tree with sort by - distance value and gateway address. */ - for (pp = NULL, cp = rn->info; cp; pp = cp, cp = cp->next) - { - if (si->distance < cp->distance) - break; - if (si->distance > cp->distance) - continue; - if (si->type == STATIC_IPV4_GATEWAY && cp->type == STATIC_IPV4_GATEWAY) - { - if (ntohl (si->addr.ipv4.s_addr) < ntohl (cp->addr.ipv4.s_addr)) - break; - if (ntohl (si->addr.ipv4.s_addr) > ntohl (cp->addr.ipv4.s_addr)) - continue; - } - } - - /* Make linked list. */ - if (pp) - pp->next = si; - else - rn->info = si; - if (cp) - cp->prev = si; - si->prev = pp; - si->next = cp; - - /* Install into rib. */ - static_install_route (AFI_IP, safi, p, si); - - return 1; -} - -int -static_delete_ipv4 (safi_t safi, struct prefix *p, struct in_addr *gate, unsigned int ifindex, - u_short tag, u_char distance, struct zebra_vrf *zvrf) -{ - u_char type = 0; - struct route_node *rn; - struct static_route *si; - struct route_table *stable; - - /* Lookup table. */ - stable = zebra_vrf_static_table (AFI_IP, safi, zvrf); - if (! stable) - return -1; - - /* Lookup static route prefix. */ - rn = route_node_lookup (stable, p); - if (! rn) - return 0; - - /* Make flags. */ - if (gate) - type = STATIC_IPV4_GATEWAY; - else if (ifindex) - type = STATIC_IFINDEX; - else - type = STATIC_IPV4_BLACKHOLE; - - /* Find same static route is the tree */ - for (si = rn->info; si; si = si->next) - if (type == si->type - && (! gate || IPV4_ADDR_SAME (gate, &si->addr.ipv4)) - && (! ifindex || ifindex == si->ifindex) - && (! tag || (tag == si->tag))) - break; - - /* Can't find static route. */ - if (! si) - { - route_unlock_node (rn); - return 0; - } - - /* Install into rib. */ - static_uninstall_route (AFI_IP, safi, p, si); - - /* Unlink static route from linked list. */ - if (si->prev) - si->prev->next = si->next; - else - rn->info = si->next; - if (si->next) - si->next->prev = si->prev; - route_unlock_node (rn); - - /* Free static route configuration. */ - XFREE (MTYPE_STATIC_ROUTE, si); - - route_unlock_node (rn); - - return 1; -} - -int -rib_add_ipv6 (int type, u_short instance, int flags, struct prefix_ipv6 *p, - struct in6_addr *gate, unsigned int ifindex, vrf_id_t vrf_id, - u_int32_t table_id, u_int32_t metric, u_char distance, safi_t safi) +rib_add (afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, + u_short instance, int flags, struct prefix *p, + union g_addr *gate, union g_addr *src, ifindex_t ifindex, + u_int32_t table_id, u_int32_t metric, u_int32_t mtu, + u_char distance) { struct rib *rib; struct rib *same = NULL; @@ -3343,22 +2752,28 @@ rib_add_ipv6 (int type, u_short instance, int flags, struct prefix_ipv6 *p, struct nexthop *nexthop; /* Lookup table. */ - table = zebra_vrf_table_with_table_id (AFI_IP6, safi, vrf_id, table_id); + table = zebra_vrf_table_with_table_id (afi, safi, vrf_id, table_id); if (! table) return 0; /* Make sure mask is applied. */ - apply_mask_ipv6 (p); + apply_mask (p); /* Set default distance by route type. */ - if (!distance) - distance = route_info[type].distance; - - if (type == ZEBRA_ROUTE_BGP && CHECK_FLAG (flags, ZEBRA_FLAG_IBGP)) - distance = 200; + if (distance == 0) + { + if ((unsigned)type >= array_size(route_info)) + distance = 150; + else + distance = route_info[type].distance; + + /* iBGP distance is 200. */ + if (type == ZEBRA_ROUTE_BGP && CHECK_FLAG (flags, ZEBRA_FLAG_IBGP)) + distance = 200; + } /* Lookup route node.*/ - rn = route_node_get (table, (struct prefix *) p); + rn = route_node_get (table, p); /* If same type of route are installed, treat it as a implicit withdraw. */ @@ -3376,12 +2791,14 @@ rib_add_ipv6 (int type, u_short instance, int flags, struct prefix_ipv6 *p, same = rib; break; } + /* Duplicate connected route comes in. */ else if ((nexthop = rib->nexthop) && nexthop->type == NEXTHOP_TYPE_IFINDEX && - nexthop->ifindex == ifindex) + nexthop->ifindex == ifindex && + !CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) { rib->refcnt++; - return 0; + return 0 ; } } @@ -3393,6 +2810,7 @@ rib_add_ipv6 (int type, u_short instance, int flags, struct prefix_ipv6 *p, rib->distance = distance; rib->flags = flags; rib->metric = metric; + rib->mtu = mtu; rib->table = table_id; rib->vrf_id = vrf_id; rib->nexthop_num = 0; @@ -3401,10 +2819,20 @@ rib_add_ipv6 (int type, u_short instance, int flags, struct prefix_ipv6 *p, /* Nexthop settings. */ if (gate) { - if (ifindex) - rib_nexthop_ipv6_ifindex_add (rib, gate, ifindex); + if (afi == AFI_IP6) + { + if (ifindex) + rib_nexthop_ipv6_ifindex_add (rib, &gate->ipv6, ifindex); + else + rib_nexthop_ipv6_add (rib, &gate->ipv6); + } else - rib_nexthop_ipv6_add (rib, gate); + { + if (ifindex) + rib_nexthop_ipv4_ifindex_add (rib, &gate->ipv4, &src->ipv4, ifindex); + else + rib_nexthop_ipv4_add (rib, &gate->ipv4, &src->ipv4); + } } else rib_nexthop_ifindex_add (rib, ifindex); @@ -3420,7 +2848,7 @@ rib_add_ipv6 (int type, u_short instance, int flags, struct prefix_ipv6 *p, char buf[INET6_ADDRSTRLEN]; if (IS_ZEBRA_DEBUG_RIB) { - inet_ntop (p->family, &p->prefix, buf, INET6_ADDRSTRLEN); + inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN); zlog_debug ("%u:%s/%d: Inserting route rn %p, rib %p (type %d) " "existing %p", vrf_id, buf, p->prefixlen, (void *)rn, @@ -3428,7 +2856,7 @@ rib_add_ipv6 (int type, u_short instance, int flags, struct prefix_ipv6 *p, } if (IS_ZEBRA_DEBUG_RIB_DETAILED) - rib_dump ((struct prefix *)p, rib); + rib_dump (p, rib); } rib_addnode (rn, rib, 1); @@ -3440,406 +2868,6 @@ rib_add_ipv6 (int type, u_short instance, int flags, struct prefix_ipv6 *p, return 0; } -int -rib_add_ipv6_multipath (struct prefix *p, struct rib *rib, safi_t safi, - unsigned long ifindex) -{ - struct route_table *table; - struct route_node *rn; - struct rib *same = NULL; - struct nexthop *nexthop; - int ret = 0; - int family; - - if (!rib) - return 0; - - if (p->family == AF_INET) - family = AFI_IP; - else - family = AFI_IP6; - - /* Lookup table. */ - table = zebra_vrf_table_with_table_id (family, safi, rib->vrf_id, rib->table); - if (! table) - return 0; - - if (p->family == AF_INET) - { - /* Make it sure prefixlen is applied to the prefix. */ - apply_mask_ipv4 ((struct prefix_ipv4 *)p); - } - else - { - /* Make sure mask is applied. */ - apply_mask_ipv6 ((struct prefix_ipv6 *)p); - } - - /* Set default distance by route type. */ - if (rib->distance == 0) - { - rib->distance = route_info[rib->type].distance; - - /* iBGP distance is 200. */ - if (rib->type == ZEBRA_ROUTE_BGP - && CHECK_FLAG (rib->flags, ZEBRA_FLAG_IBGP)) - rib->distance = 200; - } - - /* Lookup route node.*/ - rn = route_node_get (table, (struct prefix *) p); - - /* If same type of route are installed, treat it as a implicit - withdraw. */ - RNODE_FOREACH_RIB (rn, same) { - if (CHECK_FLAG (same->status, RIB_ENTRY_REMOVED)) { - continue; - } - if (same->type != rib->type) { - continue; - } - - if (same->instance != rib->instance) { - continue; - } - - if (same->table != rib->table) { - continue; - } - if (same->type != ZEBRA_ROUTE_CONNECT) { - break; - } - else if ((nexthop = same->nexthop) && - nexthop->type == NEXTHOP_TYPE_IFINDEX && - nexthop->ifindex == ifindex) { - same->refcnt++; - return 0; - } - } - - /* If this route is kernel route, set FIB flag to the route. */ - if (rib->type == ZEBRA_ROUTE_KERNEL || rib->type == ZEBRA_ROUTE_CONNECT) { - for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) { - SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); - } - } - - /* Link new rib to node.*/ - if (IS_ZEBRA_DEBUG_RIB) - { - char buf[INET6_ADDRSTRLEN]; - if (IS_ZEBRA_DEBUG_RIB) - { - inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN); - zlog_debug ("%u:%s/%d: Inserting route rn %p, rib %p (type %d) " - "existing %p", - rib->vrf_id, buf, p->prefixlen, rn, rib, rib->type, same); - } - - if (IS_ZEBRA_DEBUG_RIB_DETAILED) - rib_dump ((struct prefix *)p, rib); - } - rib_addnode (rn, rib, 1); - ret = 1; - - /* Free implicit route.*/ - if (same) - { - rib_delnode (rn, same); - ret = -1; - } - - route_unlock_node (rn); - return ret; -} - -/* XXX factor with rib_delete_ipv6 */ - -int -rib_delete_ipv6 (int type, u_short instance, int flags, struct prefix_ipv6 *p, - struct in6_addr *gate, unsigned int ifindex, vrf_id_t vrf_id, - u_int32_t table_id, safi_t safi) -{ - struct route_table *table; - struct route_node *rn; - struct rib *rib; - struct rib *fib = NULL; - struct rib *same = NULL; - struct nexthop *nexthop, *tnexthop; - int recursing; - char buf1[PREFIX_STRLEN]; - char buf2[INET6_ADDRSTRLEN]; - - /* Apply mask. */ - apply_mask_ipv6 (p); - - /* Lookup table. */ - table = zebra_vrf_table_with_table_id (AFI_IP6, safi, vrf_id, table_id); - if (! table) - return 0; - - /* Lookup route node. */ - rn = route_node_lookup (table, (struct prefix *) p); - if (! rn) - { - if (IS_ZEBRA_DEBUG_RIB) - zlog_debug ("%u:%s: doesn't exist in rib", - vrf_id, prefix2str (p, buf1, sizeof(buf1))); - return ZEBRA_ERR_RTNOEXIST; - } - - /* Lookup same type route. */ - RNODE_FOREACH_RIB (rn, rib) - { - if (CHECK_FLAG(rib->status, RIB_ENTRY_REMOVED)) - continue; - - if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) - fib = rib; - - if (rib->type != type) - continue; - if (rib->instance != instance) - continue; - if (rib->type == ZEBRA_ROUTE_CONNECT && (nexthop = rib->nexthop) && - nexthop->type == NEXTHOP_TYPE_IFINDEX) - { - if (nexthop->ifindex != ifindex) - continue; - if (rib->refcnt) - { - rib->refcnt--; - route_unlock_node (rn); - route_unlock_node (rn); - return 0; - } - same = rib; - break; - } - /* Make sure that the route found has the same gateway. */ - else - { - if (gate == NULL) - { - same = rib; - break; - } - for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) - if (IPV6_ADDR_SAME (&nexthop->gate.ipv6, gate)) - { - same = rib; - break; - } - if (same) - break; - } - } - - /* If same type of route can't be found and this message is from - kernel. */ - if (! same) - { - if (fib && type == ZEBRA_ROUTE_KERNEL && - CHECK_FLAG(flags, ZEBRA_FLAG_SELFROUTE)) - { - if (IS_ZEBRA_DEBUG_RIB) - zlog_debug ("%u:%s/%d: rn %p, rib %p (type %d) was deleted " - "from kernel, adding", - vrf_id, inet_ntop (p->family, &p->prefix, buf1, INET6_ADDRSTRLEN), - p->prefixlen, rn, fib, fib->type); - if (allow_delete) - { - /* Unset flags. */ - for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next) - UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); - - UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED); - } - else - { - /* This means someone else, other than Zebra, has deleted a Zebra - * route from the kernel. We will add it back */ - rib_install_kernel(rn, fib, 0); - } - } - else - { - if (IS_ZEBRA_DEBUG_KERNEL) - { - if (gate) - zlog_debug ("%s: vrf %u via %s ifindex %d type %d " - "doesn't exist in rib", - prefix2str (p, buf1, sizeof(buf1)), vrf_id, - inet_ntop (AF_INET6, gate, buf2, INET6_ADDRSTRLEN), - ifindex, - type); - else - zlog_debug ("%s: vrf %u ifindex %d type %d doesn't exist in rib", - prefix2str (p, buf1, sizeof(buf1)), vrf_id, - ifindex, - type); - } - route_unlock_node (rn); - return ZEBRA_ERR_RTNOEXIST; - } - } - - if (same) - rib_delnode (rn, same); - - route_unlock_node (rn); - return 0; -} - -/* Add static route into static route configuration. */ -int -static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, - unsigned int ifindex, const char *ifname, u_char flags, - u_short tag, u_char distance, struct zebra_vrf *zvrf) -{ - struct route_node *rn; - struct static_route *si; - struct static_route *pp; - struct static_route *cp; - struct static_route *update = NULL; - struct route_table *stable = zvrf->stable[AFI_IP6][SAFI_UNICAST]; - - if (! stable) - return -1; - - if (!gate && - (type == STATIC_IPV6_GATEWAY || type == STATIC_IPV6_GATEWAY_IFINDEX)) - return -1; - - if (!ifindex && - (type == STATIC_IPV6_GATEWAY_IFINDEX || type == STATIC_IFINDEX)) - return -1; - - /* Lookup static route prefix. */ - rn = route_node_get (stable, p); - - /* Do nothing if there is a same static route. */ - for (si = rn->info; si; si = si->next) - { - if (type == si->type - && (! gate || IPV6_ADDR_SAME (gate, &si->addr.ipv6)) - && (! ifindex || ifindex == si->ifindex)) - { - if ((distance == si->distance) && (tag == si->tag)) - { - route_unlock_node (rn); - return 0; - } - else - update = si; - } - } - - /* Distance or tag changed. */ - if (update) - static_delete_ipv6 (p, type, gate, ifindex, update->tag, update->distance, zvrf); - - /* Make new static route structure. */ - si = XCALLOC (MTYPE_STATIC_ROUTE, sizeof (struct static_route)); - - si->type = type; - si->distance = distance; - si->flags = flags; - si->tag = tag; - si->vrf_id = zvrf->vrf_id; - si->ifindex = ifindex; - if (si->ifindex) - strcpy (si->ifname, ifname); - - switch (type) - { - case STATIC_IPV6_GATEWAY: - si->addr.ipv6 = *gate; - break; - case STATIC_IPV6_GATEWAY_IFINDEX: - si->addr.ipv6 = *gate; - break; - } - - /* Add new static route information to the tree with sort by - distance value and gateway address. */ - for (pp = NULL, cp = rn->info; cp; pp = cp, cp = cp->next) - { - if (si->distance < cp->distance) - break; - if (si->distance > cp->distance) - continue; - } - - /* Make linked list. */ - if (pp) - pp->next = si; - else - rn->info = si; - if (cp) - cp->prev = si; - si->prev = pp; - si->next = cp; - - /* Install into rib. */ - static_install_route (AFI_IP6, SAFI_UNICAST, p, si); - - return 1; -} - -/* Delete static route from static route configuration. */ -int -static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, - unsigned int ifindex, u_short tag, u_char distance, - struct zebra_vrf *zvrf) -{ - struct route_node *rn; - struct static_route *si; - struct route_table *stable; - - /* Lookup table. */ - stable = zebra_vrf_static_table (AFI_IP6, SAFI_UNICAST, zvrf); - if (! stable) - return -1; - - /* Lookup static route prefix. */ - rn = route_node_lookup (stable, p); - if (! rn) - return 0; - - /* Find same static route is the tree */ - for (si = rn->info; si; si = si->next) - if (distance == si->distance - && type == si->type - && (! gate || IPV6_ADDR_SAME (gate, &si->addr.ipv6)) - && (! ifindex || ifindex == si->ifindex) - && (! tag || (tag == si->tag))) - break; - - /* Can't find static route. */ - if (! si) - { - route_unlock_node (rn); - return 0; - } - - /* Install into rib. */ - static_uninstall_route (AFI_IP6, SAFI_UNICAST, p, si); - - /* Unlink static route from linked list. */ - if (si->prev) - si->prev->next = si->next; - else - rn->info = si->next; - if (si->next) - si->next->prev = si->prev; - - /* Free static route configuration. */ - XFREE (MTYPE_STATIC_ROUTE, si); - - return 1; -} - /* Schedule routes of a particular table (address-family) based on event. */ static void rib_update_table (struct route_table *table, rib_update_event_t event) diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 8b76ea65c9..ef2357b99c 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -353,18 +353,17 @@ zebra_rnh_resolve_entry (vrf_id_t vrfid, int family, rnh_type_t type, if (!rn) return NULL; - /* Do not resolve over default route unless allowed && - * match route to be exact if so specified + /* When resolving nexthops, do not resolve via the default route unless + * 'ip nht resolve-via-default' is configured. */ if ((type == RNH_NEXTHOP_TYPE) && (is_default_prefix (&rn->p) && !nh_resolve_via_default(rn->p.family))) rib = NULL; - else if ((type == RNH_IMPORT_CHECK_TYPE) && - ((is_default_prefix(&rn->p)) || - ((CHECK_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH)) && - !prefix_same(&nrn->p, &rn->p)))) - rib = NULL; + else if ((type == RNH_IMPORT_CHECK_TYPE) && + CHECK_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH) && + !prefix_same(&nrn->p, &rn->p)) + rib = NULL; else { /* Identify appropriate route entry. */ @@ -593,7 +592,7 @@ zebra_rnh_process_static_routes (vrf_id_t vrfid, int family, vrfid, bufn, bufs); } - SET_FLAG(srib->flags, ZEBRA_FLAG_CHANGED); + SET_FLAG(srib->status, RIB_ENTRY_CHANGED); SET_FLAG(srib->status, RIB_ENTRY_NEXTHOPS_CHANGED); rib_queue_add(static_rn); } @@ -887,21 +886,21 @@ send_client (struct rnh *rnh, struct zserv *client, rnh_type_t type, vrf_id_t vr stream_putc (s, nexthop->type); switch (nexthop->type) { - case ZEBRA_NEXTHOP_IPV4: + case NEXTHOP_TYPE_IPV4: stream_put_in_addr (s, &nexthop->gate.ipv4); break; - case ZEBRA_NEXTHOP_IFINDEX: + case NEXTHOP_TYPE_IFINDEX: stream_putl (s, nexthop->ifindex); break; - case ZEBRA_NEXTHOP_IPV4_IFINDEX: + case NEXTHOP_TYPE_IPV4_IFINDEX: stream_put_in_addr (s, &nexthop->gate.ipv4); stream_putl (s, nexthop->ifindex); break; #ifdef HAVE_IPV6 - case ZEBRA_NEXTHOP_IPV6: + case NEXTHOP_TYPE_IPV6: stream_put (s, &nexthop->gate.ipv6, 16); break; - case ZEBRA_NEXTHOP_IPV6_IFINDEX: + case NEXTHOP_TYPE_IPV6_IFINDEX: stream_put (s, &nexthop->gate.ipv6, 16); stream_putl (s, nexthop->ifindex); break; @@ -921,7 +920,7 @@ send_client (struct rnh *rnh, struct zserv *client, rnh_type_t type, vrf_id_t vr } stream_putw_at (s, 0, stream_get_endp (s)); - client->nh_last_upd_time = quagga_time(NULL); + client->nh_last_upd_time = quagga_monotime(); client->last_write_cmd = cmd; return zebra_server_send_message(client); } diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index db3e5eaba1..1417824d07 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -252,7 +252,7 @@ route_match_interface (void *rule, struct prefix *prefix, { struct nh_rmap_obj *nh_data; char *ifname = rule; - unsigned int ifindex; + ifindex_t ifindex; if (type == RMAP_ZEBRA) { diff --git a/zebra/zebra_snmp.c b/zebra/zebra_snmp.c index 11fc0ef40d..3186ebf693 100644 --- a/zebra/zebra_snmp.c +++ b/zebra/zebra_snmp.c @@ -39,6 +39,7 @@ #include "zebra/rib.h" #include "zebra/zserv.h" +#include "zebra/zebra_vrf.h" #define IPFWMIB 1,3,6,1,2,1,4,24 @@ -84,7 +85,7 @@ #define IPADDRESS ASN_IPADDRESS #define OBJECTIDENTIFIER ASN_OBJECT_ID -oid ipfw_oid [] = { IPFWMIB }; +static oid ipfw_oid [] = { IPFWMIB }; /* Hook functions. */ static u_char * ipFwNumber (struct variable *, oid [], size_t *, @@ -96,7 +97,7 @@ static u_char * ipCidrNumber (struct variable *, oid [], size_t *, static u_char * ipCidrTable (struct variable *, oid [], size_t *, int, size_t *, WriteMethod **); -struct variable zebra_variables[] = +static struct variable zebra_variables[] = { {0, GAUGE32, RONLY, ipFwNumber, 1, {1}}, {IPFORWARDDEST, IPADDRESS, RONLY, ipFwTable, 3, {2, 1, 1}}, diff --git a/zebra/zebra_static.c b/zebra/zebra_static.c new file mode 100644 index 0000000000..7d47510635 --- /dev/null +++ b/zebra/zebra_static.c @@ -0,0 +1,480 @@ +/* + * Static Routing Information code + * Copyright (C) 2016 Cumulus Networks + * Donald Sharp + * + * This file is part of Quagga. + * + * Quagga 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. + * + * Quagga 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 Quagga; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ +#include + +#include +#include + +#include "zebra/debug.h" +#include "zebra/rib.h" +#include "zebra/zserv.h" +#include "zebra/zebra_vrf.h" +#include "zebra/zebra_static.h" +#include "zebra/zebra_rnh.h" +#include "zebra/redistribute.h" + +/* Install static route into rib. */ +void +static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_route *si) +{ + struct rib *rib; + struct route_node *rn; + struct route_table *table; + struct prefix nh_p; + + /* Lookup table. */ + table = zebra_vrf_table (afi, safi, si->vrf_id); + if (! table) + return; + + /* Lookup existing route */ + rn = route_node_get (table, p); + RNODE_FOREACH_RIB (rn, rib) + { + if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) + continue; + + if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance) + break; + } + + if (rib) + { + /* if tag value changed , update old value in RIB */ + if (rib->tag != si->tag) + rib->tag = si->tag; + + /* Same distance static route is there. Update it with new + nexthop. */ + route_unlock_node (rn); + switch (si->type) + { + case STATIC_IPV4_GATEWAY: + rib_nexthop_ipv4_add (rib, &si->addr.ipv4, NULL); + nh_p.family = AF_INET; + nh_p.prefixlen = IPV4_MAX_BITLEN; + nh_p.u.prefix4 = si->addr.ipv4; + zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn); + break; + case STATIC_IFINDEX: + rib_nexthop_ifindex_add (rib, si->ifindex); + break; + case STATIC_IPV4_BLACKHOLE: + rib_nexthop_blackhole_add (rib); + break; + case STATIC_IPV6_GATEWAY: + rib_nexthop_ipv6_add (rib, &si->addr.ipv6); + nh_p.family = AF_INET6; + nh_p.prefixlen = IPV6_MAX_BITLEN; + nh_p.u.prefix6 = si->addr.ipv6; + zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn); + break; + case STATIC_IPV6_GATEWAY_IFINDEX: + rib_nexthop_ipv6_ifindex_add (rib, &si->addr.ipv6, si->ifindex); + break; + } + + if (IS_ZEBRA_DEBUG_RIB) + { + char buf[INET6_ADDRSTRLEN]; + if (IS_ZEBRA_DEBUG_RIB) + { + inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN); + zlog_debug ("%u:%s/%d: Modifying route rn %p, rib %p (type %d)", + si->vrf_id, buf, p->prefixlen, rn, rib, rib->type); + } + } + /* Schedule route for processing or invoke NHT, as appropriate. */ + if (si->type == STATIC_IPV4_GATEWAY || + si->type == STATIC_IPV6_GATEWAY) + zebra_evaluate_rnh(si->vrf_id, nh_p.family, 1, RNH_NEXTHOP_TYPE, &nh_p); + else + rib_queue_add (rn); + } + else + { + /* This is new static route. */ + rib = XCALLOC (MTYPE_RIB, sizeof (struct rib)); + + rib->type = ZEBRA_ROUTE_STATIC; + rib->instance = 0; + rib->distance = si->distance; + rib->metric = 0; + rib->mtu = 0; + rib->vrf_id = si->vrf_id; + rib->table = si->vrf_id ? (zebra_vrf_lookup(si->vrf_id))->table_id : zebrad.rtm_table_default; + rib->nexthop_num = 0; + rib->tag = si->tag; + + switch (si->type) + { + case STATIC_IPV4_GATEWAY: + rib_nexthop_ipv4_add (rib, &si->addr.ipv4, NULL); + nh_p.family = AF_INET; + nh_p.prefixlen = IPV4_MAX_BITLEN; + nh_p.u.prefix4 = si->addr.ipv4; + zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn); + break; + case STATIC_IFINDEX: + rib_nexthop_ifindex_add (rib, si->ifindex); + break; + case STATIC_IPV4_BLACKHOLE: + rib_nexthop_blackhole_add (rib); + break; + case STATIC_IPV6_GATEWAY: + rib_nexthop_ipv6_add (rib, &si->addr.ipv6); + nh_p.family = AF_INET6; + nh_p.prefixlen = IPV6_MAX_BITLEN; + nh_p.u.prefix6 = si->addr.ipv6; + zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn); + break; + case STATIC_IPV6_GATEWAY_IFINDEX: + rib_nexthop_ipv6_ifindex_add (rib, &si->addr.ipv6, si->ifindex); + break; + } + + /* Save the flags of this static routes (reject, blackhole) */ + rib->flags = si->flags; + + if (IS_ZEBRA_DEBUG_RIB) + { + char buf[INET6_ADDRSTRLEN]; + if (IS_ZEBRA_DEBUG_RIB) + { + inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN); + zlog_debug ("%u:%s/%d: Inserting route rn %p, rib %p (type %d)", + si->vrf_id, buf, p->prefixlen, rn, rib, rib->type); + } + } + /* Link this rib to the tree. Schedule for processing or invoke NHT, + * as appropriate. + */ + if (si->type == STATIC_IPV4_GATEWAY || + si->type == STATIC_IPV6_GATEWAY) + { + rib_addnode (rn, rib, 0); + zebra_evaluate_rnh(si->vrf_id, nh_p.family, 1, RNH_NEXTHOP_TYPE, &nh_p); + } + else + rib_addnode (rn, rib, 1); + } +} +static int +static_nexthop_same (struct nexthop *nexthop, struct static_route *si) +{ + if (nexthop->type == NEXTHOP_TYPE_IPV4 + && si->type == STATIC_IPV4_GATEWAY + && IPV4_ADDR_SAME (&nexthop->gate.ipv4, &si->addr.ipv4)) + return 1; + if (nexthop->type == NEXTHOP_TYPE_IFINDEX + && si->type == STATIC_IFINDEX + && nexthop->ifindex == si->ifindex) + return 1; + if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE + && si->type == STATIC_IPV4_BLACKHOLE) + return 1; + if (nexthop->type == NEXTHOP_TYPE_IPV6 + && si->type == STATIC_IPV6_GATEWAY + && IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->addr.ipv6)) + return 1; + if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX + && si->type == STATIC_IPV6_GATEWAY_IFINDEX + && IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->addr.ipv6) + && nexthop->ifindex == si->ifindex) + return 1; + return 0; +} + +/* Uninstall static route from RIB. */ +void +static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p, struct static_route *si) +{ + struct route_node *rn; + struct rib *rib; + struct nexthop *nexthop; + struct route_table *table; + struct prefix nh_p; + + /* Lookup table. */ + table = zebra_vrf_table (afi, safi, si->vrf_id); + if (! table) + return; + + /* Lookup existing route with type and distance. */ + rn = route_node_lookup (table, p); + if (! rn) + return; + + RNODE_FOREACH_RIB (rn, rib) + { + if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) + continue; + + if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance && + rib->tag == si->tag) + break; + } + + if (! rib) + { + route_unlock_node (rn); + return; + } + + /* Lookup nexthop. */ + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + if (static_nexthop_same (nexthop, si)) + break; + + /* Can't find nexthop. */ + if (! nexthop) + { + route_unlock_node (rn); + return; + } + + /* Check nexthop. */ + if (rib->nexthop_num == 1) + rib_delnode (rn, rib); + else + { + /* Mark this nexthop as inactive and reinstall the route. Then, delete + * the nexthop. There is no need to re-evaluate the route for this + * scenario. + */ + if (IS_ZEBRA_DEBUG_RIB) + { + char buf[INET6_ADDRSTRLEN]; + if (IS_ZEBRA_DEBUG_RIB) + { + inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN); + zlog_debug ("%u:%s/%d: Modifying route rn %p, rib %p (type %d)", + si->vrf_id, buf, p->prefixlen, rn, rib, rib->type); + } + } + UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) + { + /* If there are other active nexthops, do an update. */ + if (rib->nexthop_active_num > 1) + { + rib_install_kernel (rn, rib, 1); + redistribute_update (&rn->p, rib, NULL); + } + else + { + redistribute_delete (&rn->p, rib); + rib_uninstall_kernel (rn, rib); + } + } + + if (afi == AFI_IP) + { + /* Delete the nexthop and dereg from NHT */ + nh_p.family = AF_INET; + nh_p.prefixlen = IPV4_MAX_BITLEN; + nh_p.u.prefix4 = nexthop->gate.ipv4; + } + else + { + nh_p.family = AF_INET6; + nh_p.prefixlen = IPV6_MAX_BITLEN; + nh_p.u.prefix6 = nexthop->gate.ipv6; + } + rib_nexthop_delete (rib, nexthop); + zebra_deregister_rnh_static_nh(si->vrf_id, &nh_p, rn); + nexthop_free (nexthop); + } + /* Unlock node. */ + route_unlock_node (rn); +} + +int +static_add_route (afi_t afi, safi_t safi, u_char type, struct prefix *p, + union g_addr *gate, ifindex_t ifindex, + const char *ifname, u_char flags, u_short tag, + u_char distance, struct zebra_vrf *zvrf) +{ + struct route_node *rn; + struct static_route *si; + struct static_route *pp; + struct static_route *cp; + struct static_route *update = NULL; + struct route_table *stable = zvrf->stable[afi][safi]; + + if (! stable) + return -1; + + if (!gate && + (type == STATIC_IPV4_GATEWAY || + type == STATIC_IPV6_GATEWAY || + type == STATIC_IPV6_GATEWAY_IFINDEX)) + return -1; + + if (!ifindex && + (type == STATIC_IFINDEX || + type == STATIC_IPV6_GATEWAY_IFINDEX)) + return -1; + + /* Lookup static route prefix. */ + rn = route_node_get (stable, p); + + /* Do nothing if there is a same static route. */ + for (si = rn->info; si; si = si->next) + { + if (type == si->type + && (! gate || + ((afi == AFI_IP && IPV4_ADDR_SAME (gate, &si->addr.ipv4)) || + (afi == AFI_IP6 && IPV6_ADDR_SAME (gate, &si->addr.ipv6)))) + && (! ifindex || ifindex == si->ifindex)) + { + if ((distance == si->distance) && (tag == si->tag)) + { + route_unlock_node (rn); + return 0; + } + else + update = si; + } + } + + /* Distance or tag changed. */ + if (update) + static_delete_route (afi, safi, type, p, gate, + ifindex, update->tag, update->distance, zvrf); + + /* Make new static route structure. */ + si = XCALLOC (MTYPE_STATIC_ROUTE, sizeof (struct static_route)); + + si->type = type; + si->distance = distance; + si->flags = flags; + si->tag = tag; + si->vrf_id = zvrf->vrf_id; + si->ifindex = ifindex; + if (si->ifindex) + strcpy(si->ifname, ifname); + + switch (type) + { + case STATIC_IPV4_GATEWAY: + si->addr.ipv4 = gate->ipv4; + break; + case STATIC_IPV6_GATEWAY: + si->addr.ipv6 = gate->ipv6; + break; + case STATIC_IPV6_GATEWAY_IFINDEX: + si->addr.ipv6 = gate->ipv6; + break; + case STATIC_IFINDEX: + break; + } + + /* Add new static route information to the tree with sort by + distance value and gateway address. */ + for (pp = NULL, cp = rn->info; cp; pp = cp, cp = cp->next) + { + if (si->distance < cp->distance) + break; + if (si->distance > cp->distance) + continue; + if (si->type == STATIC_IPV4_GATEWAY && cp->type == STATIC_IPV4_GATEWAY) + { + if (ntohl (si->addr.ipv4.s_addr) < ntohl (cp->addr.ipv4.s_addr)) + break; + if (ntohl (si->addr.ipv4.s_addr) > ntohl (cp->addr.ipv4.s_addr)) + continue; + } + } + + /* Make linked list. */ + if (pp) + pp->next = si; + else + rn->info = si; + if (cp) + cp->prev = si; + si->prev = pp; + si->next = cp; + + /* Install into rib. */ + static_install_route (afi, safi, p, si); + + return 1; +} + +int +static_delete_route (afi_t afi, safi_t safi, u_char type, struct prefix *p, + union g_addr *gate, ifindex_t ifindex, + u_short tag, u_char distance, struct zebra_vrf *zvrf) +{ + struct route_node *rn; + struct static_route *si; + struct route_table *stable; + + /* Lookup table. */ + stable = zebra_vrf_static_table (afi, safi, zvrf); + if (! stable) + return -1; + + /* Lookup static route prefix. */ + rn = route_node_lookup (stable, p); + if (! rn) + return 0; + + /* Find same static route is the tree */ + for (si = rn->info; si; si = si->next) + if (type == si->type + && (! gate || ( + (afi == AFI_IP && IPV4_ADDR_SAME (gate, &si->addr.ipv4)) || + (afi == AFI_IP6 && IPV6_ADDR_SAME (gate, &si->addr.ipv6)))) + && (! ifindex || ifindex == si->ifindex) + && (! tag || (tag == si->tag))) + break; + + /* Can't find static route. */ + if (! si) + { + route_unlock_node (rn); + return 0; + } + + /* Install into rib. */ + static_uninstall_route (AFI_IP, safi, p, si); + + /* Unlink static route from linked list. */ + if (si->prev) + si->prev->next = si->next; + else + rn->info = si->next; + if (si->next) + si->next->prev = si->prev; + route_unlock_node (rn); + + /* Free static route configuration. */ + XFREE (MTYPE_STATIC_ROUTE, si); + + route_unlock_node (rn); + + return 1; +} diff --git a/zebra/zebra_static.h b/zebra/zebra_static.h new file mode 100644 index 0000000000..0f00609b55 --- /dev/null +++ b/zebra/zebra_static.h @@ -0,0 +1,89 @@ +/* + * Static Routing Information header + * Copyright (C) 2016 Cumulus Networks + * Donald Sharp + * + * This file is part of Quagga. + * + * Quagga 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. + * + * Quagga 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 Quagga; 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_STATIC_H__ +#define __ZEBRA_STATIC_H__ + +/* Static route information. */ +struct static_route +{ + /* For linked list. */ + struct static_route *prev; + struct static_route *next; + + /* VRF identifier. */ + vrf_id_t vrf_id; + + /* Administrative distance. */ + u_char distance; + + /* Tag */ + u_short tag; + + /* Flag for this static route's type. */ + u_char type; +#define STATIC_IFINDEX 1 +#define STATIC_IPV4_GATEWAY 2 +#define STATIC_IPV4_BLACKHOLE 3 +#define STATIC_IPV6_GATEWAY 4 +#define STATIC_IPV6_GATEWAY_IFINDEX 5 + + /* + * Nexthop value. + * + * Under IPv4 addr and ifindex are + * used independentyly. + * STATIC_IPV4_GATEWAY uses addr + * STATIC_IFINDEX uses ifindex + */ + union g_addr addr; + ifindex_t ifindex; + + char ifname[INTERFACE_NAMSIZ + 1]; + + /* bit flags */ + u_char flags; +/* + see ZEBRA_FLAG_REJECT + ZEBRA_FLAG_BLACKHOLE + */ +}; + +extern void +static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_route *si); +extern void +static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p, struct static_route *si); + +extern int +static_add_route (afi_t, safi_t safi, u_char type, struct prefix *p, + union g_addr *gate, ifindex_t ifindex, + const char *ifname, u_char flags, u_short tag, + u_char distance, struct zebra_vrf *zvrf); + +extern int +static_delete_route (afi_t, safi_t safi, u_char type, struct prefix *p, + union g_addr *gate, ifindex_t ifindex, + u_short tag, u_char distance, + struct zebra_vrf *zvrf); + + +#endif diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index 46dc29d102..d9bd919bfe 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -29,6 +29,7 @@ #include "zebra/rib.h" #include "zebra/zebra_vrf.h" #include "zebra/router-id.h" +#include "zebra/zebra_static.h" extern struct zebra_t zebrad; struct list *zvrf_list; diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index e9090cbed2..72d0ced658 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -29,19 +29,25 @@ #include "rib.h" #include "nexthop.h" #include "vrf.h" +#include "lib/json.h" #include "zebra/zserv.h" #include "zebra/zebra_vrf.h" #include "zebra/zebra_rnh.h" #include "zebra/redistribute.h" #include "zebra/zebra_routemap.h" +#include "zebra/zebra_static.h" extern int allow_delete; -static int do_show_ip_route(struct vty *vty, const char *vrf_name, safi_t safi); +static int do_show_ip_route(struct vty *vty, const char *vrf_name, + safi_t safi, u_char use_json); static void vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, int mcast); +#define ONE_DAY_SECOND 60*60*24 +#define ONE_WEEK_SECOND 60*60*24*7 + /* General function for static route. */ static int zebra_static_ipv4 (struct vty *vty, safi_t safi, int add_cmd, @@ -60,6 +66,7 @@ zebra_static_ipv4 (struct vty *vty, safi_t safi, int add_cmd, struct zebra_vrf *zvrf = NULL; unsigned int ifindex = 0; const char *ifname = NULL; + u_char type = STATIC_IPV4_BLACKHOLE; ret = str2prefix (dest_str, &p); if (ret <= 0) @@ -111,9 +118,9 @@ zebra_static_ipv4 (struct vty *vty, safi_t safi, int add_cmd, return CMD_WARNING; } if (add_cmd) - static_add_ipv4 (safi, &p, NULL, ifindex, ifname, ZEBRA_FLAG_BLACKHOLE, tag, distance, zvrf); + static_add_route (AFI_IP, safi, type, &p, NULL, ifindex, ifname, ZEBRA_FLAG_BLACKHOLE, tag, distance, zvrf); else - static_delete_ipv4 (safi, &p, NULL, ifindex, tag, distance, zvrf); + static_delete_route (AFI_IP, safi, type, &p, NULL, ifindex, tag, distance, zvrf); return CMD_SUCCESS; } @@ -137,9 +144,9 @@ zebra_static_ipv4 (struct vty *vty, safi_t safi, int add_cmd, if (gate_str == NULL) { if (add_cmd) - static_add_ipv4 (safi, &p, NULL, ifindex, ifname, flag, tag, distance, zvrf); + static_add_route (AFI_IP, safi, type, &p, NULL, ifindex, ifname, flag, tag, distance, zvrf); else - static_delete_ipv4 (safi, &p, NULL, ifindex, tag, distance, zvrf); + static_delete_route (AFI_IP, safi, type, &p, NULL, ifindex, tag, distance, zvrf); return CMD_SUCCESS; } @@ -158,12 +165,15 @@ zebra_static_ipv4 (struct vty *vty, safi_t safi, int add_cmd, else ifindex = ifp->ifindex; ifname = gate_str; + type = STATIC_IFINDEX; } + else + type = STATIC_IPV4_GATEWAY; if (add_cmd) - static_add_ipv4 (safi, &p, ifindex ? NULL : &gate, ifindex, ifname, flag, tag, distance, zvrf); + static_add_route (AFI_IP, safi, type, &p, ifindex ? NULL : (union g_addr *)&gate, ifindex, ifname, flag, tag, distance, zvrf); else - static_delete_ipv4 (safi, &p, ifindex ? NULL : &gate, ifindex, tag, distance, zvrf); + static_delete_route (AFI_IP, safi, type, &p, ifindex ? NULL : (union g_addr *)&gate, ifindex, tag, distance, zvrf); return CMD_SUCCESS; } @@ -278,7 +288,7 @@ DEFUN (show_ip_rpf, IP_STR "Display RPF information for multicast source\n") { - return do_show_ip_route(vty, VRF_DEFAULT_NAME, SAFI_MULTICAST); + return do_show_ip_route(vty, VRF_DEFAULT_NAME, SAFI_MULTICAST, 0); } DEFUN (show_ip_rpf_addr, @@ -1929,6 +1939,8 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, int mcast) vty_out (vty, ", distance %u, metric %u", rib->distance, rib->metric); if (rib->tag) vty_out (vty, ", tag %d", rib->tag); + if (rib->mtu) + vty_out (vty, ", mtu %u", rib->mtu); if (rib->vrf_id != VRF_DEFAULT) { zvrf = vrf_info_lookup(rib->vrf_id); @@ -1944,8 +1956,6 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, int mcast) vty_out (vty, ", reject"); vty_out (vty, "%s", VTY_NEWLINE); -#define ONE_DAY_SECOND 60*60*24 -#define ONE_WEEK_SECOND 60*60*24*7 if (rib->type == ZEBRA_ROUTE_RIP || rib->type == ZEBRA_ROUTE_OSPF || rib->type == ZEBRA_ROUTE_ISIS @@ -2048,12 +2058,151 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, int mcast) } static void -vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib) +vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib, + json_object *json) { struct nexthop *nexthop, *tnexthop; int recursing; int len = 0; char buf[BUFSIZ]; + json_object *json_nexthops = NULL; + json_object *json_nexthop = NULL; + json_object *json_route = NULL; + + if (json) + { + json_route = json_object_new_object(); + json_nexthops = json_object_new_array(); + + json_object_string_add(json_route, "prefix", prefix2str (&rn->p, buf, sizeof buf)); + json_object_string_add(json_route, "protocol", zebra_route_string(rib->type)); + + if (rib->instance) + json_object_int_add(json_route, "instance", rib->instance); + + if (rib->vrf_id) + json_object_int_add(json_route, "vrfId", rib->vrf_id); + + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + json_object_boolean_true_add(json_route, "selected"); + + if (rib->type != ZEBRA_ROUTE_CONNECT && rib->type != ZEBRA_ROUTE_KERNEL) + { + json_object_int_add(json_route, "distance", rib->distance); + json_object_int_add(json_route, "metric", rib->metric); + } + + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE)) + json_object_boolean_true_add(json_route, "blackhole"); + + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_REJECT)) + json_object_boolean_true_add(json_route, "reject"); + + if (rib->type == ZEBRA_ROUTE_RIP + || rib->type == ZEBRA_ROUTE_OSPF + || rib->type == ZEBRA_ROUTE_ISIS + || rib->type == ZEBRA_ROUTE_TABLE + || rib->type == ZEBRA_ROUTE_BGP) + { + time_t uptime; + struct tm *tm; + + uptime = time (NULL); + uptime -= rib->uptime; + tm = gmtime (&uptime); + + if (uptime < ONE_DAY_SECOND) + sprintf(buf, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); + else if (uptime < ONE_WEEK_SECOND) + sprintf(buf, "%dd%02dh%02dm", tm->tm_yday, tm->tm_hour, tm->tm_min); + else + sprintf(buf, "%02dw%dd%02dh", tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour); + + json_object_string_add(json_route, "uptime", buf); + } + + for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) + { + json_nexthop = json_object_new_object(); + + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) + json_object_boolean_true_add(json_nexthop, "fib"); + + switch (nexthop->type) + { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + json_object_string_add(json_nexthop, "ip", inet_ntoa (nexthop->gate.ipv4)); + json_object_string_add(json_nexthop, "afi", "ipv4"); + + if (nexthop->ifindex) + { + json_object_int_add(json_nexthop, "interfaceIndex", nexthop->ifindex); + json_object_string_add(json_nexthop, "interfaceName", ifindex2ifname_vrf (nexthop->ifindex, rib->vrf_id)); + } + break; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + json_object_string_add(json_nexthop, "ip", inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ)); + json_object_string_add(json_nexthop, "afi", "ipv6"); + + if (nexthop->ifindex) + { + json_object_int_add(json_nexthop, "interfaceIndex", nexthop->ifindex); + json_object_string_add(json_nexthop, "interfaceName", ifindex2ifname_vrf (nexthop->ifindex, rib->vrf_id)); + } + break; + + case NEXTHOP_TYPE_IFINDEX: + json_object_boolean_true_add(json_nexthop, "directlyConnected"); + json_object_int_add(json_nexthop, "interfaceIndex", nexthop->ifindex); + json_object_string_add(json_nexthop, "interfaceName", ifindex2ifname_vrf (nexthop->ifindex, rib->vrf_id)); + break; + case NEXTHOP_TYPE_BLACKHOLE: + json_object_boolean_true_add(json_nexthop, "blackhole"); + break; + default: + break; + } + + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + json_object_boolean_true_add(json_nexthop, "active"); + + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ONLINK)) + json_object_boolean_true_add(json_nexthop, "onLink"); + + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) + json_object_boolean_true_add(json_nexthop, "recursive"); + + switch (nexthop->type) + { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + if (nexthop->src.ipv4.s_addr) + { + if (inet_ntop(AF_INET, &nexthop->src.ipv4, buf, sizeof buf)) + json_object_string_add(json_nexthop, "source", buf); + } + break; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + if (!IPV6_ADDR_SAME(&nexthop->src.ipv6, &in6addr_any)) + { + if (inet_ntop(AF_INET6, &nexthop->src.ipv6, buf, sizeof buf)) + json_object_string_add(json_nexthop, "source", buf); + } + break; + default: + break; + } + + json_object_array_add(json_nexthops, json_nexthop); + } + + json_object_object_add(json_route, "nexthops", json_nexthops); + json_object_array_add(json, json_route); + return; + } /* Nexthop information. */ for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) @@ -2160,9 +2309,6 @@ vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib) uptime -= rib->uptime; tm = gmtime (&uptime); -#define ONE_DAY_SECOND 60*60*24 -#define ONE_WEEK_SECOND 60*60*24*7 - if (uptime < ONE_DAY_SECOND) vty_out (vty, ", %02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); @@ -2180,62 +2326,112 @@ vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib) DEFUN (show_ip_route, show_ip_route_cmd, - "show ip route", + "show ip route {json}", SHOW_STR IP_STR "IP routing table\n") { - return do_show_ip_route (vty, VRF_DEFAULT_NAME, SAFI_UNICAST); + return do_show_ip_route (vty, VRF_DEFAULT_NAME, SAFI_UNICAST, use_json(argc, argv)); } static int -do_show_ip_route(struct vty *vty, const char *vrf_name, safi_t safi) +do_show_ip_route (struct vty *vty, const char *vrf_name, safi_t safi, + u_char use_json) { struct route_table *table; struct route_node *rn; struct rib *rib; int first = 1; struct zebra_vrf *zvrf = NULL; + char buf[BUFSIZ]; + json_object *json = NULL; + json_object *json_prefix = NULL; if (!(zvrf = zebra_vrf_list_lookup_by_name (vrf_name))) { - vty_out (vty, "vrf %s not defined%s", vrf_name, VTY_NEWLINE); + if (use_json) + vty_out (vty, "{}%s", VTY_NEWLINE); + else + vty_out (vty, "vrf %s not defined%s", vrf_name, VTY_NEWLINE); return CMD_SUCCESS; } if (zvrf->vrf_id == VRF_UNKNOWN) { - vty_out (vty, "vrf %s inactive%s", vrf_name, VTY_NEWLINE); + if (use_json) + vty_out (vty, "{}%s", VTY_NEWLINE); + else + vty_out (vty, "vrf %s inactive%s", vrf_name, VTY_NEWLINE); return CMD_SUCCESS; } table = zebra_vrf_table (AFI_IP, safi, zvrf->vrf_id); if (! table) - return CMD_SUCCESS; + { + if (use_json) + vty_out (vty, "{}%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + if (use_json) + { + json = json_object_new_object(); + + /* Show all IPv4 routes. */ + for (rn = route_top (table); rn; rn = route_next (rn)) + { + RNODE_FOREACH_RIB (rn, rib) + { + if (!json_prefix) + json_prefix = json_object_new_array(); + vty_show_ip_route (vty, rn, rib, json_prefix); + } + + if (json_prefix) + { + prefix2str (&rn->p, buf, sizeof buf); + json_object_object_add(json, buf, json_prefix); + json_prefix = NULL; + } + } + + vty_out (vty, "%s%s", json_object_to_json_string(json), VTY_NEWLINE); + json_object_free(json); + } + else + { + /* Show all IPv4 routes. */ + for (rn = route_top (table); rn; rn = route_next (rn)) + { + RNODE_FOREACH_RIB (rn, rib) + { + if (first) + { + vty_out (vty, SHOW_ROUTE_V4_HEADER); + first = 0; + } + vty_show_ip_route (vty, rn, rib, NULL); + } + } + } - /* Show all IPv4 routes. */ - for (rn = route_top (table); rn; rn = route_next (rn)) - RNODE_FOREACH_RIB (rn, rib) - { - if (first) - { - vty_out (vty, SHOW_ROUTE_V4_HEADER); - first = 0; - } - vty_show_ip_route (vty, rn, rib); - } return CMD_SUCCESS; } DEFUN (show_ip_route_vrf, show_ip_route_vrf_cmd, - "show ip route " VRF_CMD_STR, + "show ip route " VRF_CMD_STR " {json}", SHOW_STR IP_STR "IP routing table\n" VRF_CMD_HELP_STR) { - return do_show_ip_route (vty, argv[0], SAFI_UNICAST); + u_char uj = use_json(argc, argv); + + if (argc == 1 && uj) + return do_show_ip_route (vty, NULL, SAFI_UNICAST, uj); + else + return do_show_ip_route (vty, argv[0], SAFI_UNICAST, uj); } DEFUN (show_ip_nht, @@ -2430,7 +2626,7 @@ DEFUN (show_ip_route_tag, vty_out (vty, SHOW_ROUTE_V4_HEADER); first = 0; } - vty_show_ip_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib, NULL); } return CMD_SUCCESS; } @@ -2490,7 +2686,7 @@ DEFUN (show_ip_route_prefix_longer, vty_out (vty, SHOW_ROUTE_V4_HEADER); first = 0; } - vty_show_ip_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib, NULL); } return CMD_SUCCESS; } @@ -2542,7 +2738,7 @@ DEFUN (show_ip_route_supernets, vty_out (vty, SHOW_ROUTE_V4_HEADER); first = 0; } - vty_show_ip_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib, NULL); } } return CMD_SUCCESS; @@ -2600,7 +2796,7 @@ DEFUN (show_ip_route_protocol, vty_out (vty, SHOW_ROUTE_V4_HEADER); first = 0; } - vty_show_ip_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib, NULL); } return CMD_SUCCESS; } @@ -2645,7 +2841,7 @@ DEFUN (show_ip_route_ospf_instance, vty_out (vty, SHOW_ROUTE_V4_HEADER); first = 0; } - vty_show_ip_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib, NULL); } return CMD_SUCCESS; } @@ -3014,7 +3210,7 @@ DEFUN (show_ip_route_vrf_all, vty_out (vty, "%sVRF %s:%s", VTY_NEWLINE, zvrf->name, VTY_NEWLINE); vrf_header = 0; } - vty_show_ip_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib, NULL); } vrf_header = 1; } @@ -3068,7 +3264,7 @@ DEFUN (show_ip_route_vrf_all_tag, vty_out (vty, "%sVRF %s:%s", VTY_NEWLINE, zvrf->name, VTY_NEWLINE); vrf_header = 0; } - vty_show_ip_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib, NULL); } vrf_header = 1; } @@ -3124,7 +3320,7 @@ DEFUN (show_ip_route_vrf_all_prefix_longer, vty_out (vty, "%sVRF %s:%s", VTY_NEWLINE, zvrf->name, VTY_NEWLINE); vrf_header = 0; } - vty_show_ip_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib, NULL); } vrf_header = 1; } @@ -3177,7 +3373,7 @@ DEFUN (show_ip_route_vrf_all_supernets, vty_out (vty, "%sVRF %s:%s", VTY_NEWLINE, zvrf->name, VTY_NEWLINE); vrf_header = 0; } - vty_show_ip_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib, NULL); } } vrf_header = 1; @@ -3233,7 +3429,7 @@ DEFUN (show_ip_route_vrf_all_protocol, vty_out (vty, "%sVRF %s:%s", VTY_NEWLINE, zvrf->name, VTY_NEWLINE); vrf_header = 0; } - vty_show_ip_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib, NULL); } vrf_header = 1; } @@ -3541,9 +3737,9 @@ static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str, } if (add_cmd) - static_add_ipv6 (&p, type, gate, ifindex, ifname, flag, tag, distance, zvrf); + static_add_route (AFI_IP6, SAFI_UNICAST, type, &p, (union g_addr *)gate, ifindex, ifname, flag, tag, distance, zvrf); else - static_delete_ipv6 (&p, type, gate, ifindex, tag, distance, zvrf); + static_delete_route (AFI_IP6, SAFI_UNICAST, type, &p, (union g_addr *)gate, ifindex, tag, distance, zvrf); return CMD_SUCCESS; } @@ -4544,7 +4740,7 @@ DEFUN (no_ipv6_route_ifname_flags_pref_tag_vrf, DEFUN (show_ipv6_route, show_ipv6_route_cmd, - "show ipv6 route", + "show ipv6 route {json}", SHOW_STR IP_STR "IPv6 routing table\n") @@ -4555,18 +4751,28 @@ DEFUN (show_ipv6_route, int first = 1; vrf_id_t vrf_id = VRF_DEFAULT; struct zebra_vrf *zvrf = NULL; + char buf[BUFSIZ]; + json_object *json = NULL; + json_object *json_prefix = NULL; + u_char uj = use_json(argc, argv); - if (argc > 0) + if (argc > 0 && argv[0] && strcmp(argv[0], "json") != 0) { if (!(zvrf = zebra_vrf_list_lookup_by_name (argv[0]))) { - vty_out (vty, "vrf %s not defined%s", argv[0], VTY_NEWLINE); + if (uj) + vty_out (vty, "{}%s", VTY_NEWLINE); + else + vty_out (vty, "vrf %s not defined%s", argv[0], VTY_NEWLINE); return CMD_SUCCESS; } if (zvrf->vrf_id == VRF_UNKNOWN) { - vty_out (vty, "vrf %s inactive%s", argv[0], VTY_NEWLINE); + if (uj) + vty_out (vty, "{}%s", VTY_NEWLINE); + else + vty_out (vty, "vrf %s inactive%s", argv[0], VTY_NEWLINE); return CMD_SUCCESS; } else @@ -4575,25 +4781,60 @@ DEFUN (show_ipv6_route, table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id); if (! table) - return CMD_SUCCESS; + { + if (uj) + vty_out (vty, "{}%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + if (uj) + { + json = json_object_new_object(); + + /* Show all IPv6 route. */ + for (rn = route_top (table); rn; rn = route_next (rn)) + { + RNODE_FOREACH_RIB (rn, rib) + { + if (!json_prefix) + json_prefix = json_object_new_array(); + vty_show_ip_route (vty, rn, rib, json_prefix); + } + + if (json_prefix) + { + prefix2str (&rn->p, buf, sizeof buf); + json_object_object_add(json, buf, json_prefix); + json_prefix = NULL; + } + } + + vty_out (vty, "%s%s", json_object_to_json_string(json), VTY_NEWLINE); + json_object_free(json); + } + else + { + /* Show all IPv6 route. */ + for (rn = route_top (table); rn; rn = route_next (rn)) + { + RNODE_FOREACH_RIB (rn, rib) + { + if (first) + { + vty_out (vty, SHOW_ROUTE_V6_HEADER); + first = 0; + } + vty_show_ip_route (vty, rn, rib, NULL); + } + } + } - /* Show all IPv6 route. */ - for (rn = route_top (table); rn; rn = route_next (rn)) - RNODE_FOREACH_RIB (rn, rib) - { - if (first) - { - vty_out (vty, SHOW_ROUTE_V6_HEADER); - first = 0; - } - vty_show_ip_route (vty, rn, rib); - } return CMD_SUCCESS; } ALIAS (show_ipv6_route, show_ipv6_route_vrf_cmd, - "show ipv6 route " VRF_CMD_STR, + "show ipv6 route " VRF_CMD_STR " {json}", SHOW_STR IP_STR "IPv6 routing table\n" @@ -4639,7 +4880,7 @@ DEFUN (show_ipv6_route_tag, vty_out (vty, SHOW_ROUTE_V6_HEADER); first = 0; } - vty_show_ip_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib, NULL); } return CMD_SUCCESS; } @@ -4699,7 +4940,7 @@ DEFUN (show_ipv6_route_prefix_longer, vty_out (vty, SHOW_ROUTE_V6_HEADER); first = 0; } - vty_show_ip_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib, NULL); } return CMD_SUCCESS; } @@ -4757,7 +4998,7 @@ DEFUN (show_ipv6_route_protocol, vty_out (vty, SHOW_ROUTE_V6_HEADER); first = 0; } - vty_show_ip_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib, NULL); } return CMD_SUCCESS; } @@ -4983,7 +5224,7 @@ DEFUN (show_ipv6_mroute, vty_out (vty, SHOW_ROUTE_V6_HEADER); first = 0; } - vty_show_ip_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib, NULL); } return CMD_SUCCESS; } @@ -5033,7 +5274,7 @@ DEFUN (show_ipv6_route_vrf_all, vty_out (vty, "%sVRF %s:%s", VTY_NEWLINE, zvrf->name, VTY_NEWLINE); vrf_header = 0; } - vty_show_ip_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib, NULL); } vrf_header = 1; } @@ -5087,7 +5328,7 @@ DEFUN (show_ipv6_route_vrf_all_tag, vty_out (vty, "%sVRF %s:%s", VTY_NEWLINE, zvrf->name, VTY_NEWLINE); vrf_header = 0; } - vty_show_ip_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib, NULL); } vrf_header = 1; } @@ -5144,7 +5385,7 @@ DEFUN (show_ipv6_route_vrf_all_prefix_longer, vty_out (vty, "%sVRF %s:%s", VTY_NEWLINE, zvrf->name, VTY_NEWLINE); vrf_header = 0; } - vty_show_ip_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib, NULL); } vrf_header = 1; } @@ -5199,7 +5440,7 @@ DEFUN (show_ipv6_route_vrf_all_protocol, vty_out (vty, "%sVRF %s:%s", VTY_NEWLINE, zvrf->name, VTY_NEWLINE); vrf_header = 0; } - vty_show_ip_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib, NULL); } vrf_header = 1; } @@ -5343,7 +5584,7 @@ DEFUN (show_ipv6_mroute_vrf_all, vty_out (vty, SHOW_ROUTE_V6_HEADER); first = 0; } - vty_show_ip_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib, NULL); } } return CMD_SUCCESS; diff --git a/zebra/zserv.c b/zebra/zserv.c index daecaf5e10..020a252371 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -97,7 +97,7 @@ zserv_flush_data(struct thread *thread) break; } - client->last_write_time = quagga_time(NULL); + client->last_write_time = quagga_monotime(); return 0; } @@ -131,7 +131,7 @@ zebra_server_send_message(struct zserv *client) break; } - client->last_write_time = quagga_time(NULL); + client->last_write_time = quagga_monotime(); return 0; } @@ -160,13 +160,19 @@ zserv_encode_interface (struct stream *s, struct interface *ifp) stream_putl (s, ifp->mtu); stream_putl (s, ifp->mtu6); stream_putl (s, ifp->bandwidth); -#ifdef HAVE_STRUCT_SOCKADDR_DL - stream_put (s, &ifp->sdl, sizeof (ifp->sdl_storage)); -#else + stream_putl (s, ifp->ll_type); stream_putl (s, ifp->hw_addr_len); if (ifp->hw_addr_len) stream_put (s, ifp->hw_addr, ifp->hw_addr_len); -#endif /* HAVE_STRUCT_SOCKADDR_DL */ + + /* Then, Traffic Engineering parameters if any */ + if (HAS_LINK_PARAMS(ifp) && IS_LINK_PARAMS_SET(ifp->link_params)) + { + stream_putc (s, 1); + zebra_interface_link_params_write (s, ifp); + } + else + stream_putc (s, 0); /* Write packet size. */ stream_putw_at (s, 0, stream_get_endp (s)); @@ -255,6 +261,35 @@ zsend_vrf_delete (struct zserv *client, struct zebra_vrf *zvrf) return zebra_server_send_message (client); } +int +zsend_interface_link_params (struct zserv *client, struct interface *ifp) +{ + struct stream *s; + + /* Check this client need interface information. */ + if (! client->ifinfo) + return 0; + + if (!ifp->link_params) + return 0; + s = client->obuf; + stream_reset (s); + + zserv_create_header (s, ZEBRA_INTERFACE_LINK_PARAMS, ifp->vrf_id); + + /* Add Interface Index */ + stream_putl (s, ifp->ifindex); + + /* Then TE Link Parameters */ + if (zebra_interface_link_params_write (s, ifp) == 0) + return 0; + + /* Write packet size. */ + stream_putw_at (s, 0, stream_get_endp (s)); + + return zebra_server_send_message (client); +} + /* Interface address is added/deleted. Send ZEBRA_INTERFACE_ADDRESS_ADD or * ZEBRA_INTERFACE_ADDRESS_DELETE to the client. * @@ -695,6 +730,8 @@ zsend_redistribute_route (int cmd, struct zserv *client, struct prefix *p, SET_FLAG(zapi_flags, ZAPI_MESSAGE_TAG); stream_putw(s, rib->tag); } + SET_FLAG (zapi_flags, ZAPI_MESSAGE_MTU); + stream_putl (s, rib->mtu); } /* write real message flags value */ @@ -710,10 +747,9 @@ zsend_redistribute_route (int cmd, struct zserv *client, struct prefix *p, return zebra_server_send_message(client); } -#ifdef HAVE_IPV6 static int -zsend_ipv6_nexthop_lookup (struct zserv *client, struct in6_addr *addr, - vrf_id_t vrf_id) +zsend_nexthop_lookup (struct zserv *client, afi_t afi, safi_t safi, + vrf_id_t vrf_id, union g_addr *addr) { struct stream *s; struct rib *rib; @@ -722,18 +758,28 @@ zsend_ipv6_nexthop_lookup (struct zserv *client, struct in6_addr *addr, struct nexthop *nexthop; /* Lookup nexthop. */ - rib = rib_match_ipv6 (addr, vrf_id); + rib = rib_match (afi, safi, vrf_id, addr, NULL); /* Get output stream. */ s = client->obuf; stream_reset (s); /* Fill in result. */ - zserv_create_header (s, ZEBRA_IPV6_NEXTHOP_LOOKUP, vrf_id); - stream_put (s, addr, 16); + if (afi == AFI_IP) + { + zserv_create_header (s, ZEBRA_IPV4_NEXTHOP_LOOKUP, vrf_id); + stream_put_in_addr (s, &addr->ipv4); + } + else + { + zserv_create_header (s, ZEBRA_IPV6_NEXTHOP_LOOKUP, vrf_id); + stream_put (s, &addr->ipv6, 16); + } if (rib) { + if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) + zlog_debug("%s: Matching rib entry found.", __func__); stream_putl (s, rib->metric); num = 0; nump = stream_get_endp(s); @@ -747,82 +793,21 @@ zsend_ipv6_nexthop_lookup (struct zserv *client, struct in6_addr *addr, stream_putc (s, nexthop->type); switch (nexthop->type) { - case ZEBRA_NEXTHOP_IPV6: - stream_put (s, &nexthop->gate.ipv6, 16); - break; - case ZEBRA_NEXTHOP_IPV6_IFINDEX: - stream_put (s, &nexthop->gate.ipv6, 16); - stream_putl (s, nexthop->ifindex); - break; - case ZEBRA_NEXTHOP_IFINDEX: - stream_putl (s, nexthop->ifindex); - break; - default: - /* do nothing */ - break; - } - num++; - } - stream_putc_at (s, nump, num); - } - else - { - stream_putl (s, 0); - stream_putc (s, 0); - } - - stream_putw_at (s, 0, stream_get_endp (s)); - - return zebra_server_send_message(client); -} -#endif /* HAVE_IPV6 */ - -static int -zsend_ipv4_nexthop_lookup (struct zserv *client, struct in_addr addr, - vrf_id_t vrf_id) -{ - struct stream *s; - struct rib *rib; - unsigned long nump; - u_char num; - struct nexthop *nexthop; - - /* Lookup nexthop. */ - rib = rib_match_ipv4 (addr, SAFI_UNICAST, vrf_id, NULL); - - /* Get output stream. */ - s = client->obuf; - stream_reset (s); - - /* Fill in result. */ - zserv_create_header (s, ZEBRA_IPV4_NEXTHOP_LOOKUP, vrf_id); - stream_put_in_addr (s, &addr); - - if (rib) - { - if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) - zlog_debug("%s: Matching rib entry found.", __func__); - stream_putl (s, rib->metric); - num = 0; - nump = stream_get_endp(s); - stream_putc (s, 0); - /* Only non-recursive routes are elegible to resolve the nexthop we - * are looking up. Therefore, we will just iterate over the top - * chain of nexthops. */ - for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) - if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) - { - stream_putc (s, nexthop->type); - switch (nexthop->type) - { - case ZEBRA_NEXTHOP_IPV4: + case NEXTHOP_TYPE_IPV4: stream_put_in_addr (s, &nexthop->gate.ipv4); break; - case ZEBRA_NEXTHOP_IPV4_IFINDEX: + case NEXTHOP_TYPE_IPV4_IFINDEX: stream_put_in_addr (s, &nexthop->gate.ipv4); stream_putl (s, nexthop->ifindex); break; - case ZEBRA_NEXTHOP_IFINDEX: + case NEXTHOP_TYPE_IPV6: + stream_put (s, &nexthop->gate.ipv6, 16); + break; + case NEXTHOP_TYPE_IPV6_IFINDEX: + stream_put (s, &nexthop->gate.ipv6, 16); + stream_putl (s, nexthop->ifindex); + break; + case NEXTHOP_TYPE_IFINDEX: stream_putl (s, nexthop->ifindex); break; default: @@ -842,7 +827,7 @@ zsend_ipv4_nexthop_lookup (struct zserv *client, struct in_addr addr, } stream_putw_at (s, 0, stream_get_endp (s)); - + return zebra_server_send_message(client); } @@ -864,7 +849,7 @@ zserv_rnh_register (struct zserv *client, int sock, u_short length, s = client->ibuf; - client->nh_reg_time = quagga_time(NULL); + client->nh_reg_time = quagga_monotime(); while (l < length) { @@ -952,7 +937,7 @@ zserv_rnh_unregister (struct zserv *client, int sock, u_short length, rnh = zebra_lookup_rnh(&p, zvrf->vrf_id, type); if (rnh) { - client->nh_dereg_time = quagga_time(NULL); + client->nh_dereg_time = quagga_monotime(); zebra_remove_rnh_client(rnh, client, type); } } @@ -996,14 +981,14 @@ zsend_ipv4_nexthop_lookup_mrib (struct zserv *client, struct in_addr addr, struc stream_putc (s, nexthop->type); switch (nexthop->type) { - case ZEBRA_NEXTHOP_IPV4: + case NEXTHOP_TYPE_IPV4: stream_put_in_addr (s, &nexthop->gate.ipv4); break; - case ZEBRA_NEXTHOP_IPV4_IFINDEX: + case NEXTHOP_TYPE_IPV4_IFINDEX: stream_put_in_addr (s, &nexthop->gate.ipv4); stream_putl (s, nexthop->ifindex); break; - case ZEBRA_NEXTHOP_IFINDEX: + case NEXTHOP_TYPE_IFINDEX: stream_putl (s, nexthop->ifindex); break; default: @@ -1061,14 +1046,14 @@ zsend_ipv4_import_lookup (struct zserv *client, struct prefix_ipv4 *p, stream_putc (s, nexthop->type); switch (nexthop->type) { - case ZEBRA_NEXTHOP_IPV4: + case NEXTHOP_TYPE_IPV4: stream_put_in_addr (s, &nexthop->gate.ipv4); break; - case ZEBRA_NEXTHOP_IPV4_IFINDEX: + case NEXTHOP_TYPE_IPV4_IFINDEX: stream_put_in_addr (s, &nexthop->gate.ipv4); stream_putl (s, nexthop->ifindex); break; - case ZEBRA_NEXTHOP_IFINDEX: + case NEXTHOP_TYPE_IFINDEX: stream_putl (s, nexthop->ifindex); break; default: @@ -1182,13 +1167,13 @@ zread_ipv4_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf) { int i; struct rib *rib; - struct prefix_ipv4 p; + struct prefix p; u_char message; struct in_addr nexthop; u_char nexthop_num; u_char nexthop_type; struct stream *s; - unsigned int ifindex; + ifindex_t ifindex; safi_t safi; int ret; @@ -1210,7 +1195,7 @@ zread_ipv4_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf) memset (&p, 0, sizeof (struct prefix_ipv4)); p.family = AF_INET; p.prefixlen = stream_getc (s); - stream_get (&p.prefix, s, PSIZE (p.prefixlen)); + stream_get (&p.u.prefix4, s, PSIZE (p.prefixlen)); /* VRF ID */ rib->vrf_id = zvrf->vrf_id; @@ -1227,23 +1212,23 @@ zread_ipv4_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf) switch (nexthop_type) { - case ZEBRA_NEXTHOP_IFINDEX: + case NEXTHOP_TYPE_IFINDEX: ifindex = stream_getl (s); rib_nexthop_ifindex_add (rib, ifindex); break; - case ZEBRA_NEXTHOP_IPV4: + case NEXTHOP_TYPE_IPV4: nexthop.s_addr = stream_get_ipv4 (s); rib_nexthop_ipv4_add (rib, &nexthop, NULL); break; - case ZEBRA_NEXTHOP_IPV4_IFINDEX: + case NEXTHOP_TYPE_IPV4_IFINDEX: nexthop.s_addr = stream_get_ipv4 (s); ifindex = stream_getl (s); rib_nexthop_ipv4_ifindex_add (rib, &nexthop, NULL, ifindex); break; - case ZEBRA_NEXTHOP_IPV6: + case NEXTHOP_TYPE_IPV6: stream_forward_getp (s, IPV6_MAX_BYTELEN); break; - case ZEBRA_NEXTHOP_BLACKHOLE: + case NEXTHOP_TYPE_BLACKHOLE: rib_nexthop_blackhole_add (rib); break; } @@ -1264,10 +1249,15 @@ zread_ipv4_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf) else rib->tag = 0; + if (CHECK_FLAG (message, ZAPI_MESSAGE_MTU)) + rib->mtu = stream_getl (s); + else + rib->mtu = 0; + /* Table */ rib->table = zvrf->table_id; - ret = rib_add_ipv4_multipath (&p, rib, safi); + ret = rib_add_multipath (AFI_IP, safi, &p, rib); /* Stats */ if (ret > 0) @@ -1284,9 +1274,10 @@ zread_ipv4_delete (struct zserv *client, u_short length, struct zebra_vrf *zvrf) int i; struct stream *s; struct zapi_ipv4 api; - struct in_addr nexthop, *nexthop_p; + struct in_addr nexthop; + union g_addr *nexthop_p; unsigned long ifindex; - struct prefix_ipv4 p; + struct prefix p; u_char nexthop_num; u_char nexthop_type; u_int32_t table_id; @@ -1307,7 +1298,7 @@ zread_ipv4_delete (struct zserv *client, u_short length, struct zebra_vrf *zvrf) memset (&p, 0, sizeof (struct prefix_ipv4)); p.family = AF_INET; p.prefixlen = stream_getc (s); - stream_get (&p.prefix, s, PSIZE (p.prefixlen)); + stream_get (&p.u.prefix4, s, PSIZE (p.prefixlen)); /* Nexthop, ifindex, distance, metric. */ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) @@ -1320,19 +1311,19 @@ zread_ipv4_delete (struct zserv *client, u_short length, struct zebra_vrf *zvrf) switch (nexthop_type) { - case ZEBRA_NEXTHOP_IFINDEX: + case NEXTHOP_TYPE_IFINDEX: ifindex = stream_getl (s); break; - case ZEBRA_NEXTHOP_IPV4: + case NEXTHOP_TYPE_IPV4: nexthop.s_addr = stream_get_ipv4 (s); - nexthop_p = &nexthop; + nexthop_p = (union g_addr *)&nexthop; break; - case ZEBRA_NEXTHOP_IPV4_IFINDEX: + case NEXTHOP_TYPE_IPV4_IFINDEX: nexthop.s_addr = stream_get_ipv4 (s); - nexthop_p = &nexthop; + nexthop_p = (union g_addr *)&nexthop; ifindex = stream_getl (s); break; - case ZEBRA_NEXTHOP_IPV6: + case NEXTHOP_TYPE_IPV6: stream_forward_getp (s, IPV6_MAX_BYTELEN); break; } @@ -1359,8 +1350,8 @@ zread_ipv4_delete (struct zserv *client, u_short length, struct zebra_vrf *zvrf) table_id = zvrf->table_id; - rib_delete_ipv4 (api.type, api.instance, api.flags, &p, nexthop_p, ifindex, - zvrf->vrf_id, table_id, api.safi); + rib_delete (AFI_IP, api.safi, zvrf->vrf_id, api.type, api.instance, + api.flags, &p, nexthop_p, ifindex, table_id); client->v4_route_del_cnt++; return 0; } @@ -1377,7 +1368,8 @@ zread_ipv4_nexthop_lookup (struct zserv *client, u_short length, if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) zlog_debug("%s: looking up %s", __func__, inet_ntop (AF_INET, &addr, buf, BUFSIZ)); - return zsend_ipv4_nexthop_lookup (client, addr, zvrf->vrf_id); + return zsend_nexthop_lookup (client, AFI_IP, SAFI_UNICAST, + zvrf->vrf_id, (union g_addr *)&addr); } /* MRIB Nexthop lookup for IPv4. */ @@ -1417,8 +1409,7 @@ zread_ipv4_route_ipv6_nexthop_add (struct zserv *client, u_short length, struct u_char message; u_char nexthop_num; u_char nexthop_type; - unsigned long ifindex; - struct prefix_ipv4 p; + struct prefix p; safi_t safi; static struct in6_addr nexthops[MULTIPATH_NUM]; static unsigned int ifindices[MULTIPATH_NUM]; @@ -1427,7 +1418,6 @@ zread_ipv4_route_ipv6_nexthop_add (struct zserv *client, u_short length, struct /* Get input stream. */ s = client->ibuf; - ifindex = 0; memset (&nexthop, 0, sizeof (struct in6_addr)); /* Allocate new rib. */ @@ -1445,7 +1435,7 @@ zread_ipv4_route_ipv6_nexthop_add (struct zserv *client, u_short length, struct memset (&p, 0, sizeof (struct prefix_ipv4)); p.family = AF_INET; p.prefixlen = stream_getc (s); - stream_get (&p.prefix, s, PSIZE (p.prefixlen)); + stream_get (&p.u.prefix4, s, PSIZE (p.prefixlen)); /* VRF ID */ rib->vrf_id = zvrf->vrf_id; @@ -1468,18 +1458,18 @@ zread_ipv4_route_ipv6_nexthop_add (struct zserv *client, u_short length, struct switch (nexthop_type) { - case ZEBRA_NEXTHOP_IPV6: + case NEXTHOP_TYPE_IPV6: stream_get (&nexthop, s, 16); if (nh_count < MULTIPATH_NUM) { nexthops[nh_count++] = nexthop; } break; - case ZEBRA_NEXTHOP_IFINDEX: + case NEXTHOP_TYPE_IFINDEX: if (if_count < MULTIPATH_NUM) { ifindices[if_count++] = stream_getl (s); } break; - case ZEBRA_NEXTHOP_BLACKHOLE: + case NEXTHOP_TYPE_BLACKHOLE: rib_nexthop_blackhole_add (rib); break; } @@ -1518,10 +1508,15 @@ zread_ipv4_route_ipv6_nexthop_add (struct zserv *client, u_short length, struct else rib->tag = 0; + if (CHECK_FLAG (message, ZAPI_MESSAGE_MTU)) + rib->mtu = stream_getl (s); + else + rib->mtu = 0; + /* Table */ rib->table = zvrf->table_id; - ret = rib_add_ipv6_multipath ((struct prefix *)&p, rib, safi, ifindex); + ret = rib_add_multipath (AFI_IP6, safi, &p, rib); /* Stats */ if (ret > 0) client->v4_route_add_cnt++; @@ -1541,8 +1536,7 @@ zread_ipv6_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf) u_char message; u_char nexthop_num; u_char nexthop_type; - unsigned long ifindex; - struct prefix_ipv6 p; + struct prefix p; safi_t safi; static struct in6_addr nexthops[MULTIPATH_NUM]; static unsigned int ifindices[MULTIPATH_NUM]; @@ -1551,7 +1545,6 @@ zread_ipv6_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf) /* Get input stream. */ s = client->ibuf; - ifindex = 0; memset (&nexthop, 0, sizeof (struct in6_addr)); /* Allocate new rib. */ @@ -1569,7 +1562,7 @@ zread_ipv6_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf) memset (&p, 0, sizeof (struct prefix_ipv6)); p.family = AF_INET6; p.prefixlen = stream_getc (s); - stream_get (&p.prefix, s, PSIZE (p.prefixlen)); + stream_get (&p.u.prefix6, s, PSIZE (p.prefixlen)); /* We need to give nh-addr, nh-ifindex with the same next-hop object * to the rib to ensure that IPv6 multipathing works; need to coalesce @@ -1589,18 +1582,18 @@ zread_ipv6_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf) switch (nexthop_type) { - case ZEBRA_NEXTHOP_IPV6: + case NEXTHOP_TYPE_IPV6: stream_get (&nexthop, s, 16); if (nh_count < MULTIPATH_NUM) { nexthops[nh_count++] = nexthop; } break; - case ZEBRA_NEXTHOP_IFINDEX: + case NEXTHOP_TYPE_IFINDEX: if (if_count < MULTIPATH_NUM) { ifindices[if_count++] = stream_getl (s); } break; - case ZEBRA_NEXTHOP_BLACKHOLE: + case NEXTHOP_TYPE_BLACKHOLE: rib_nexthop_blackhole_add (rib); break; } @@ -1636,11 +1629,16 @@ zread_ipv6_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf) else rib->tag = 0; + if (CHECK_FLAG (message, ZAPI_MESSAGE_MTU)) + rib->mtu = stream_getl (s); + else + rib->mtu = 0; + /* VRF ID */ rib->vrf_id = zvrf->vrf_id; rib->table = zvrf->table_id; - ret = rib_add_ipv6_multipath ((struct prefix *)&p, rib, safi, ifindex); + ret = rib_add_multipath (AFI_IP, safi, &p, rib); /* Stats */ if (ret > 0) client->v6_route_add_cnt++; @@ -1658,8 +1656,9 @@ zread_ipv6_delete (struct zserv *client, u_short length, struct zebra_vrf *zvrf) struct stream *s; struct zapi_ipv6 api; struct in6_addr nexthop; + union g_addr *pnexthop; unsigned long ifindex; - struct prefix_ipv6 p; + struct prefix p; s = client->ibuf; ifindex = 0; @@ -1676,7 +1675,7 @@ zread_ipv6_delete (struct zserv *client, u_short length, struct zebra_vrf *zvrf) memset (&p, 0, sizeof (struct prefix_ipv6)); p.family = AF_INET6; p.prefixlen = stream_getc (s); - stream_get (&p.prefix, s, PSIZE (p.prefixlen)); + stream_get (&p.u.prefix6, s, PSIZE (p.prefixlen)); /* Nexthop, ifindex, distance, metric. */ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) @@ -1690,10 +1689,11 @@ zread_ipv6_delete (struct zserv *client, u_short length, struct zebra_vrf *zvrf) switch (nexthop_type) { - case ZEBRA_NEXTHOP_IPV6: + case NEXTHOP_TYPE_IPV6: stream_get (&nexthop, s, 16); + pnexthop = (union g_addr *)&nexthop; break; - case ZEBRA_NEXTHOP_IFINDEX: + case NEXTHOP_TYPE_IFINDEX: ifindex = stream_getl (s); break; } @@ -1719,11 +1719,11 @@ zread_ipv6_delete (struct zserv *client, u_short length, struct zebra_vrf *zvrf) api.tag = 0; if (IN6_IS_ADDR_UNSPECIFIED (&nexthop)) - rib_delete_ipv6 (api.type, api.instance, api.flags, &p, NULL, ifindex, - zvrf->vrf_id, client->rtm_table, api.safi); + rib_delete (AFI_IP6, api.safi, zvrf->vrf_id, api.type, api.instance, + api.flags, &p, NULL, ifindex, client->rtm_table); else - rib_delete_ipv6 (api.type, api.instance, api.flags, &p, &nexthop, ifindex, - zvrf->vrf_id, client->rtm_table, api.safi); + rib_delete (AFI_IP6, api.safi, zvrf->vrf_id, api.type, api.instance, + api.flags, &p, pnexthop, ifindex, client->rtm_table); client->v6_route_del_cnt++; return 0; @@ -1741,7 +1741,8 @@ zread_ipv6_nexthop_lookup (struct zserv *client, u_short length, zlog_debug("%s: looking up %s", __func__, inet_ntop (AF_INET6, &addr, buf, BUFSIZ)); - return zsend_ipv6_nexthop_lookup (client, &addr, zvrf->vrf_id); + return zsend_nexthop_lookup (client, AFI_IP6, SAFI_UNICAST, + zvrf->vrf_id, (union g_addr *)&addr); } /* Register zebra server router-id information. Send current router-id */ @@ -1832,7 +1833,7 @@ static void zebra_client_close (struct zserv *client) { /* Send client de-registration to BFD */ - zebra_ptm_bfd_client_deregister(client); + zebra_ptm_bfd_client_deregister(client->proto); /* Cleanup any registered nexthops - across all VRFs. */ zebra_client_close_cleanup_rnh (client); @@ -1867,7 +1868,7 @@ zebra_client_close (struct zserv *client) /* Free client structure. */ listnode_delete (zebrad.client_list, client); - XFREE (0, client); + XFREE (MTYPE_TMP, client); } /* Make new client. */ @@ -1878,7 +1879,7 @@ zebra_client_create (int sock) int i; afi_t afi; - client = XCALLOC (0, sizeof (struct zserv)); + client = XCALLOC (MTYPE_TMP, sizeof (struct zserv)); /* Make client input/output buffer. */ client->sock = sock; @@ -1889,7 +1890,7 @@ zebra_client_create (int sock) /* Set table number. */ client->rtm_table = zebrad.rtm_table_default; - client->connect_time = quagga_time(NULL); + client->connect_time = quagga_monotime(); /* Initialize flags */ for (afi = AFI_IP; afi < AFI_MAX; afi++) for (i = 0; i < ZEBRA_ROUTE_MAX; i++) @@ -2015,7 +2016,7 @@ zebra_client_read (struct thread *thread) zlog_debug ("zebra message received [%s] %d in VRF %u", zserv_command_string (command), length, vrf_id); - client->last_read_time = quagga_time(NULL); + client->last_read_time = quagga_monotime(); client->last_read_cmd = command; zvrf = zebra_vrf_lookup (vrf_id); @@ -2325,7 +2326,7 @@ zserv_time_buf(time_t *time1, char *buf, int buflen) return (buf); } - now = quagga_time(NULL); + now = quagga_monotime(); now -= *time1; tm = gmtime(&now); diff --git a/zebra/zserv.h b/zebra/zserv.h index 737795ad54..3667f5b2b6 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -165,6 +165,8 @@ extern int zsend_router_id_update (struct zserv *, struct prefix *, extern int zsend_interface_vrf_update (struct zserv *, struct interface *, vrf_id_t); +extern int zsend_interface_link_params (struct zserv *, struct interface *); + extern pid_t pid; extern void zserv_create_header(struct stream *s, uint16_t cmd, vrf_id_t vrf_id);