From 6d681bd874dc7dee4300a5d3a5ced8bb1a679643 Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Fri, 16 Dec 2016 05:39:44 +0000 Subject: all: use ->text when parsing protocol argument and match on full protocol name in proto_redistnum() Signed-off-by: Quentin Young --- lib/log.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'lib/log.c') diff --git a/lib/log.c b/lib/log.c index f9877300b4..3ed41c75e8 100644 --- a/lib/log.c +++ b/lib/log.c @@ -1061,48 +1061,48 @@ proto_redistnum(int afi, const char *s) if (afi == AFI_IP) { - if (strncmp (s, "k", 1) == 0) + if (strmatch (s, "kernel")) return ZEBRA_ROUTE_KERNEL; - else if (strncmp (s, "c", 1) == 0) + else if (strmatch (s, "connected")) return ZEBRA_ROUTE_CONNECT; - else if (strncmp (s, "s", 1) == 0) + else if (strmatch (s, "static")) return ZEBRA_ROUTE_STATIC; - else if (strncmp (s, "r", 1) == 0) + else if (strmatch (s, "rip")) return ZEBRA_ROUTE_RIP; - else if (strncmp (s, "o", 1) == 0) + else if (strmatch (s, "ospf")) return ZEBRA_ROUTE_OSPF; - else if (strncmp (s, "i", 1) == 0) + else if (strmatch (s, "isis")) return ZEBRA_ROUTE_ISIS; - else if (strncmp (s, "bg", 2) == 0) + else if (strmatch (s, "bgp")) return ZEBRA_ROUTE_BGP; - else if (strncmp (s, "ta", 2) == 0) + else if (strmatch (s, "table")) return ZEBRA_ROUTE_TABLE; - else if (strncmp (s, "v", 1) == 0) + else if (strmatch (s, "vnc")) return ZEBRA_ROUTE_VNC; - else if (strncmp (s, "vd", 1) == 0) + else if (strmatch (s, "vd")) return ZEBRA_ROUTE_VNC_DIRECT; } if (afi == AFI_IP6) { - if (strncmp (s, "k", 1) == 0) + if (strmatch (s, "kernel")) return ZEBRA_ROUTE_KERNEL; - else if (strncmp (s, "c", 1) == 0) + else if (strmatch (s, "connected")) return ZEBRA_ROUTE_CONNECT; - else if (strncmp (s, "s", 1) == 0) + else if (strmatch (s, "static")) return ZEBRA_ROUTE_STATIC; - else if (strncmp (s, "r", 1) == 0) + else if (strmatch (s, "ripng")) return ZEBRA_ROUTE_RIPNG; - else if (strncmp (s, "o", 1) == 0) + else if (strmatch (s, "ospf6")) return ZEBRA_ROUTE_OSPF6; - else if (strncmp (s, "i", 1) == 0) + else if (strmatch (s, "isis")) return ZEBRA_ROUTE_ISIS; - else if (strncmp (s, "bg", 2) == 0) + else if (strmatch (s, "bgp")) return ZEBRA_ROUTE_BGP; - else if (strncmp (s, "ta", 2) == 0) + else if (strmatch (s, "table")) return ZEBRA_ROUTE_TABLE; - else if (strncmp (s, "v", 1) == 0) + else if (strmatch (s, "vnc")) return ZEBRA_ROUTE_VNC; - else if (strncmp (s, "vd", 1) == 0) + else if (strmatch (s, "vd")) return ZEBRA_ROUTE_VNC_DIRECT; } return -1; -- cgit v1.2.3 From ab0181eed3d118fc46e693c68e5bbc0248c7bfe5 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 20 Dec 2016 18:31:42 +0100 Subject: build: rename (2 of ?): route_types macros All of the autogenerated macros in lib/route_types.pl are now called FRR_* instead of QUAGGA_*. Signed-off-by: David Lamparter --- bgpd/bgp_vty.c | 80 +++++++++++++++++++++++++------------------------- isisd/isis_redist.c | 8 ++--- lib/log.c | 2 +- lib/route_types.pl | 34 ++++++++++----------- ospf6d/ospf6_asbr.c | 16 +++++----- ospfd/ospf_vty.c | 16 +++++----- ripd/rip_zebra.c | 32 ++++++++++---------- ripngd/ripng_zebra.c | 32 ++++++++++---------- zebra/zebra_routemap.c | 48 +++++++++++++++--------------- zebra/zebra_vty.c | 24 +++++++-------- 10 files changed, 146 insertions(+), 146 deletions(-) (limited to 'lib/log.c') diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 5dafac1e06..8ccc4e2a90 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -13813,9 +13813,9 @@ DEFUN (show_ip_bgp_instance_peer_group, DEFUN (bgp_redistribute_ipv4, bgp_redistribute_ipv4_cmd, - "redistribute " QUAGGA_IP_REDIST_STR_BGPD, + "redistribute " FRR_IP_REDIST_STR_BGPD, "Redistribute information from another routing protocol\n" - QUAGGA_IP_REDIST_HELP_STR_BGPD) + FRR_IP_REDIST_HELP_STR_BGPD) { int type; @@ -13831,9 +13831,9 @@ DEFUN (bgp_redistribute_ipv4, DEFUN (bgp_redistribute_ipv4_rmap, bgp_redistribute_ipv4_rmap_cmd, - "redistribute " QUAGGA_IP_REDIST_STR_BGPD " route-map WORD", + "redistribute " FRR_IP_REDIST_STR_BGPD " route-map WORD", "Redistribute information from another routing protocol\n" - QUAGGA_IP_REDIST_HELP_STR_BGPD + FRR_IP_REDIST_HELP_STR_BGPD "Route map reference\n" "Pointer to route-map entries\n") { @@ -13854,9 +13854,9 @@ DEFUN (bgp_redistribute_ipv4_rmap, DEFUN (bgp_redistribute_ipv4_metric, bgp_redistribute_ipv4_metric_cmd, - "redistribute " QUAGGA_IP_REDIST_STR_BGPD " metric <0-4294967295>", + "redistribute " FRR_IP_REDIST_STR_BGPD " metric <0-4294967295>", "Redistribute information from another routing protocol\n" - QUAGGA_IP_REDIST_HELP_STR_BGPD + FRR_IP_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" "Default metric\n") { @@ -13879,9 +13879,9 @@ DEFUN (bgp_redistribute_ipv4_metric, DEFUN (bgp_redistribute_ipv4_rmap_metric, bgp_redistribute_ipv4_rmap_metric_cmd, - "redistribute " QUAGGA_IP_REDIST_STR_BGPD " route-map WORD metric <0-4294967295>", + "redistribute " FRR_IP_REDIST_STR_BGPD " route-map WORD metric <0-4294967295>", "Redistribute information from another routing protocol\n" - QUAGGA_IP_REDIST_HELP_STR_BGPD + FRR_IP_REDIST_HELP_STR_BGPD "Route map reference\n" "Pointer to route-map entries\n" "Metric for redistributed routes\n" @@ -13907,9 +13907,9 @@ DEFUN (bgp_redistribute_ipv4_rmap_metric, DEFUN (bgp_redistribute_ipv4_metric_rmap, bgp_redistribute_ipv4_metric_rmap_cmd, - "redistribute " QUAGGA_IP_REDIST_STR_BGPD " metric <0-4294967295> route-map WORD", + "redistribute " FRR_IP_REDIST_STR_BGPD " metric <0-4294967295> route-map WORD", "Redistribute information from another routing protocol\n" - QUAGGA_IP_REDIST_HELP_STR_BGPD + FRR_IP_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" "Default metric\n" "Route map reference\n" @@ -14141,10 +14141,10 @@ ALIAS (no_bgp_redistribute_ipv4_ospf, DEFUN (no_bgp_redistribute_ipv4, no_bgp_redistribute_ipv4_cmd, - "no redistribute " QUAGGA_IP_REDIST_STR_BGPD, + "no redistribute " FRR_IP_REDIST_STR_BGPD, NO_STR "Redistribute information from another routing protocol\n" - QUAGGA_IP_REDIST_HELP_STR_BGPD) + FRR_IP_REDIST_HELP_STR_BGPD) { int type; @@ -14159,28 +14159,28 @@ DEFUN (no_bgp_redistribute_ipv4, ALIAS (no_bgp_redistribute_ipv4, no_bgp_redistribute_ipv4_rmap_cmd, - "no redistribute " QUAGGA_IP_REDIST_STR_BGPD " route-map WORD", + "no redistribute " FRR_IP_REDIST_STR_BGPD " route-map WORD", NO_STR "Redistribute information from another routing protocol\n" - QUAGGA_IP_REDIST_HELP_STR_BGPD + FRR_IP_REDIST_HELP_STR_BGPD "Route map reference\n" "Pointer to route-map entries\n") ALIAS (no_bgp_redistribute_ipv4, no_bgp_redistribute_ipv4_metric_cmd, - "no redistribute " QUAGGA_IP_REDIST_STR_BGPD " metric <0-4294967295>", + "no redistribute " FRR_IP_REDIST_STR_BGPD " metric <0-4294967295>", NO_STR "Redistribute information from another routing protocol\n" - QUAGGA_IP_REDIST_HELP_STR_BGPD + FRR_IP_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" "Default metric\n") ALIAS (no_bgp_redistribute_ipv4, no_bgp_redistribute_ipv4_rmap_metric_cmd, - "no redistribute " QUAGGA_IP_REDIST_STR_BGPD " route-map WORD metric <0-4294967295>", + "no redistribute " FRR_IP_REDIST_STR_BGPD " route-map WORD metric <0-4294967295>", NO_STR "Redistribute information from another routing protocol\n" - QUAGGA_IP_REDIST_HELP_STR_BGPD + FRR_IP_REDIST_HELP_STR_BGPD "Route map reference\n" "Pointer to route-map entries\n" "Metric for redistributed routes\n" @@ -14188,10 +14188,10 @@ ALIAS (no_bgp_redistribute_ipv4, ALIAS (no_bgp_redistribute_ipv4, no_bgp_redistribute_ipv4_metric_rmap_cmd, - "no redistribute " QUAGGA_IP_REDIST_STR_BGPD " metric <0-4294967295> route-map WORD", + "no redistribute " FRR_IP_REDIST_STR_BGPD " metric <0-4294967295> route-map WORD", NO_STR "Redistribute information from another routing protocol\n" - QUAGGA_IP_REDIST_HELP_STR_BGPD + FRR_IP_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" "Default metric\n" "Route map reference\n" @@ -14200,9 +14200,9 @@ ALIAS (no_bgp_redistribute_ipv4, #ifdef HAVE_IPV6 DEFUN (bgp_redistribute_ipv6, bgp_redistribute_ipv6_cmd, - "redistribute " QUAGGA_IP6_REDIST_STR_BGPD, + "redistribute " FRR_IP6_REDIST_STR_BGPD, "Redistribute information from another routing protocol\n" - QUAGGA_IP6_REDIST_HELP_STR_BGPD) + FRR_IP6_REDIST_HELP_STR_BGPD) { int type; @@ -14219,9 +14219,9 @@ DEFUN (bgp_redistribute_ipv6, DEFUN (bgp_redistribute_ipv6_rmap, bgp_redistribute_ipv6_rmap_cmd, - "redistribute " QUAGGA_IP6_REDIST_STR_BGPD " route-map WORD", + "redistribute " FRR_IP6_REDIST_STR_BGPD " route-map WORD", "Redistribute information from another routing protocol\n" - QUAGGA_IP6_REDIST_HELP_STR_BGPD + FRR_IP6_REDIST_HELP_STR_BGPD "Route map reference\n" "Pointer to route-map entries\n") { @@ -14242,9 +14242,9 @@ DEFUN (bgp_redistribute_ipv6_rmap, DEFUN (bgp_redistribute_ipv6_metric, bgp_redistribute_ipv6_metric_cmd, - "redistribute " QUAGGA_IP6_REDIST_STR_BGPD " metric <0-4294967295>", + "redistribute " FRR_IP6_REDIST_STR_BGPD " metric <0-4294967295>", "Redistribute information from another routing protocol\n" - QUAGGA_IP6_REDIST_HELP_STR_BGPD + FRR_IP6_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" "Default metric\n") { @@ -14267,9 +14267,9 @@ DEFUN (bgp_redistribute_ipv6_metric, DEFUN (bgp_redistribute_ipv6_rmap_metric, bgp_redistribute_ipv6_rmap_metric_cmd, - "redistribute " QUAGGA_IP6_REDIST_STR_BGPD " route-map WORD metric <0-4294967295>", + "redistribute " FRR_IP6_REDIST_STR_BGPD " route-map WORD metric <0-4294967295>", "Redistribute information from another routing protocol\n" - QUAGGA_IP6_REDIST_HELP_STR_BGPD + FRR_IP6_REDIST_HELP_STR_BGPD "Route map reference\n" "Pointer to route-map entries\n" "Metric for redistributed routes\n" @@ -14295,9 +14295,9 @@ DEFUN (bgp_redistribute_ipv6_rmap_metric, DEFUN (bgp_redistribute_ipv6_metric_rmap, bgp_redistribute_ipv6_metric_rmap_cmd, - "redistribute " QUAGGA_IP6_REDIST_STR_BGPD " metric <0-4294967295> route-map WORD", + "redistribute " FRR_IP6_REDIST_STR_BGPD " metric <0-4294967295> route-map WORD", "Redistribute information from another routing protocol\n" - QUAGGA_IP6_REDIST_HELP_STR_BGPD + FRR_IP6_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" "Default metric\n" "Route map reference\n" @@ -14323,10 +14323,10 @@ DEFUN (bgp_redistribute_ipv6_metric_rmap, DEFUN (no_bgp_redistribute_ipv6, no_bgp_redistribute_ipv6_cmd, - "no redistribute " QUAGGA_IP6_REDIST_STR_BGPD, + "no redistribute " FRR_IP6_REDIST_STR_BGPD, NO_STR "Redistribute information from another routing protocol\n" - QUAGGA_IP6_REDIST_HELP_STR_BGPD) + FRR_IP6_REDIST_HELP_STR_BGPD) { int type; @@ -14342,28 +14342,28 @@ DEFUN (no_bgp_redistribute_ipv6, ALIAS (no_bgp_redistribute_ipv6, no_bgp_redistribute_ipv6_rmap_cmd, - "no redistribute " QUAGGA_IP6_REDIST_STR_BGPD " route-map WORD", + "no redistribute " FRR_IP6_REDIST_STR_BGPD " route-map WORD", NO_STR "Redistribute information from another routing protocol\n" - QUAGGA_IP6_REDIST_HELP_STR_BGPD + FRR_IP6_REDIST_HELP_STR_BGPD "Route map reference\n" "Pointer to route-map entries\n") ALIAS (no_bgp_redistribute_ipv6, no_bgp_redistribute_ipv6_metric_cmd, - "no redistribute " QUAGGA_IP6_REDIST_STR_BGPD " metric <0-4294967295>", + "no redistribute " FRR_IP6_REDIST_STR_BGPD " metric <0-4294967295>", NO_STR "Redistribute information from another routing protocol\n" - QUAGGA_IP6_REDIST_HELP_STR_BGPD + FRR_IP6_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" "Default metric\n") ALIAS (no_bgp_redistribute_ipv6, no_bgp_redistribute_ipv6_rmap_metric_cmd, - "no redistribute " QUAGGA_IP6_REDIST_STR_BGPD " route-map WORD metric <0-4294967295>", + "no redistribute " FRR_IP6_REDIST_STR_BGPD " route-map WORD metric <0-4294967295>", NO_STR "Redistribute information from another routing protocol\n" - QUAGGA_IP6_REDIST_HELP_STR_BGPD + FRR_IP6_REDIST_HELP_STR_BGPD "Route map reference\n" "Pointer to route-map entries\n" "Metric for redistributed routes\n" @@ -14371,10 +14371,10 @@ ALIAS (no_bgp_redistribute_ipv6, ALIAS (no_bgp_redistribute_ipv6, no_bgp_redistribute_ipv6_metric_rmap_cmd, - "no redistribute " QUAGGA_IP6_REDIST_STR_BGPD " metric <0-4294967295> route-map WORD", + "no redistribute " FRR_IP6_REDIST_STR_BGPD " metric <0-4294967295> route-map WORD", NO_STR "Redistribute information from another routing protocol\n" - QUAGGA_IP6_REDIST_HELP_STR_BGPD + FRR_IP6_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" "Default metric\n" "Route map reference\n" diff --git a/isisd/isis_redist.c b/isisd/isis_redist.c index 21daaa7794..8282591a49 100644 --- a/isisd/isis_redist.c +++ b/isisd/isis_redist.c @@ -540,12 +540,12 @@ isis_redist_area_finish(struct isis_area *area) DEFUN (isis_redistribute, isis_redistribute_cmd, - "redistribute (ipv4|ipv6) " QUAGGA_REDIST_STR_ISISD + "redistribute (ipv4|ipv6) " FRR_REDIST_STR_ISISD " (level-1|level-2) {metric <0-16777215>|route-map WORD}", REDIST_STR "Redistribute IPv4 routes\n" "Redistribute IPv6 routes\n" - QUAGGA_REDIST_HELP_STR_ISISD + FRR_REDIST_HELP_STR_ISISD "Redistribute into level-1\n" "Redistribute into level-2\n" "Metric for redistributed routes\n" @@ -609,13 +609,13 @@ DEFUN (isis_redistribute, DEFUN (no_isis_redistribute, no_isis_redistribute_cmd, - "no redistribute (ipv4|ipv6) " QUAGGA_REDIST_STR_ISISD + "no redistribute (ipv4|ipv6) " FRR_REDIST_STR_ISISD " (level-1|level-2)", NO_STR REDIST_STR "Redistribute IPv4 routes\n" "Redistribute IPv6 routes\n" - QUAGGA_REDIST_HELP_STR_ISISD + FRR_REDIST_HELP_STR_ISISD "Redistribute into level-1\n" "Redistribute into level-2\n") { diff --git a/lib/log.c b/lib/log.c index f9877300b4..fb9d02a301 100644 --- a/lib/log.c +++ b/lib/log.c @@ -20,7 +20,7 @@ * 02111-1307, USA. */ -#define QUAGGA_DEFINE_DESC_TABLE +#define FRR_DEFINE_DESC_TABLE #include diff --git a/lib/route_types.pl b/lib/route_types.pl index d44cb12b23..ffe9bec04b 100755 --- a/lib/route_types.pl +++ b/lib/route_types.pl @@ -86,8 +86,8 @@ printf <{"ipv4"} && $daemons{$daemon}->{"ipv6"}) { my ($names, $help) = collect($daemon, 1, 1, 0); - printf "#define QUAGGA_REDIST_STR_%s \\\n %s\n", uc $daemon, $names; - printf "#define QUAGGA_REDIST_HELP_STR_%s \\\n%s\n", uc $daemon, $help; + printf "#define FRR_REDIST_STR_%s \\\n %s\n", uc $daemon, $names; + printf "#define FRR_REDIST_HELP_STR_%s \\\n%s\n", uc $daemon, $help; ($names, $help) = collect($daemon, 1, 0, 0); - printf "#define QUAGGA_IP_REDIST_STR_%s \\\n %s\n", uc $daemon, $names; - printf "#define QUAGGA_IP_REDIST_HELP_STR_%s \\\n%s\n", uc $daemon, $help; + printf "#define FRR_IP_REDIST_STR_%s \\\n %s\n", uc $daemon, $names; + printf "#define FRR_IP_REDIST_HELP_STR_%s \\\n%s\n", uc $daemon, $help; ($names, $help) = collect($daemon, 0, 1, 0); - printf "#define QUAGGA_IP6_REDIST_STR_%s \\\n %s\n", uc $daemon, $names; - printf "#define QUAGGA_IP6_REDIST_HELP_STR_%s \\\n%s\n", uc $daemon, $help; + printf "#define FRR_IP6_REDIST_STR_%s \\\n %s\n", uc $daemon, $names; + printf "#define FRR_IP6_REDIST_HELP_STR_%s \\\n%s\n", uc $daemon, $help; if ($daemon eq "zebra") { ($names, $help) = collect($daemon, 1, 0, 1); - printf "#define QUAGGA_IP_PROTOCOL_MAP_STR_%s \\\n %s\n", uc $daemon, $names; - printf "#define QUAGGA_IP_PROTOCOL_MAP_HELP_STR_%s \\\n%s\n", uc $daemon, $help; + printf "#define FRR_IP_PROTOCOL_MAP_STR_%s \\\n %s\n", uc $daemon, $names; + printf "#define FRR_IP_PROTOCOL_MAP_HELP_STR_%s \\\n%s\n", uc $daemon, $help; ($names, $help) = collect($daemon, 0, 1, 1); - printf "#define QUAGGA_IP6_PROTOCOL_MAP_STR_%s \\\n %s\n", uc $daemon, $names; - printf "#define QUAGGA_IP6_PROTOCOL_MAP_HELP_STR_%s \\\n%s\n", uc $daemon, $help; + printf "#define FRR_IP6_PROTOCOL_MAP_STR_%s \\\n %s\n", uc $daemon, $names; + printf "#define FRR_IP6_PROTOCOL_MAP_HELP_STR_%s \\\n%s\n", uc $daemon, $help; } } else { my ($names, $help) = collect($daemon, $daemons{$daemon}->{"ipv4"}, $daemons{$daemon}->{"ipv6"}, 0); - printf "#define QUAGGA_REDIST_STR_%s \\\n %s\n", uc $daemon, $names; - printf "#define QUAGGA_REDIST_HELP_STR_%s \\\n%s\n", uc $daemon, $help; + printf "#define FRR_REDIST_STR_%s \\\n %s\n", uc $daemon, $names; + printf "#define FRR_REDIST_HELP_STR_%s \\\n%s\n", uc $daemon, $help; } print "\n"; } print <|metric-type (1|2)|route-map WORD}", REDIST_STR - QUAGGA_REDIST_HELP_STR_OSPFD + FRR_REDIST_HELP_STR_OSPFD "Metric for redistributed routes\n" "OSPF default metric\n" "OSPF exterior metric type for redistributed routes\n" @@ -8117,11 +8117,11 @@ DEFUN (ospf_redistribute_source, DEFUN (no_ospf_redistribute_source, no_ospf_redistribute_source_cmd, - "no redistribute " QUAGGA_REDIST_STR_OSPFD + "no redistribute " FRR_REDIST_STR_OSPFD " {metric <0-16777214>|metric-type (1|2)|route-map WORD}", NO_STR REDIST_STR - QUAGGA_REDIST_HELP_STR_OSPFD + FRR_REDIST_HELP_STR_OSPFD "Metric for redistributed routes\n" "OSPF default metric\n" "OSPF exterior metric type for redistributed routes\n" @@ -8273,11 +8273,11 @@ DEFUN (no_ospf_redistribute_instance_source, DEFUN (ospf_distribute_list_out, ospf_distribute_list_out_cmd, - "distribute-list WORD out " QUAGGA_REDIST_STR_OSPFD, + "distribute-list WORD out " FRR_REDIST_STR_OSPFD, "Filter networks in routing updates\n" "Access-list name\n" OUT_STR - QUAGGA_REDIST_HELP_STR_OSPFD) + FRR_REDIST_HELP_STR_OSPFD) { struct ospf *ospf = vty->index; int source; @@ -8295,12 +8295,12 @@ DEFUN (ospf_distribute_list_out, DEFUN (no_ospf_distribute_list_out, no_ospf_distribute_list_out_cmd, - "no distribute-list WORD out " QUAGGA_REDIST_STR_OSPFD, + "no distribute-list WORD out " FRR_REDIST_STR_OSPFD, NO_STR "Filter networks in routing updates\n" "Access-list name\n" OUT_STR - QUAGGA_REDIST_HELP_STR_OSPFD) + FRR_REDIST_HELP_STR_OSPFD) { struct ospf *ospf = vty->index; int source; diff --git a/ripd/rip_zebra.c b/ripd/rip_zebra.c index 3f7c7a3e4d..44fc1cd8f9 100644 --- a/ripd/rip_zebra.c +++ b/ripd/rip_zebra.c @@ -371,9 +371,9 @@ DEFUN (no_rip_redistribute_rip, DEFUN (rip_redistribute_type, rip_redistribute_type_cmd, - "redistribute " QUAGGA_REDIST_STR_RIPD, + "redistribute " FRR_REDIST_STR_RIPD, REDIST_STR - QUAGGA_REDIST_HELP_STR_RIPD) + FRR_REDIST_HELP_STR_RIPD) { int i; @@ -396,10 +396,10 @@ DEFUN (rip_redistribute_type, DEFUN (no_rip_redistribute_type, no_rip_redistribute_type_cmd, - "no redistribute " QUAGGA_REDIST_STR_RIPD, + "no redistribute " FRR_REDIST_STR_RIPD, NO_STR REDIST_STR - QUAGGA_REDIST_HELP_STR_RIPD) + FRR_REDIST_HELP_STR_RIPD) { int i; @@ -423,9 +423,9 @@ DEFUN (no_rip_redistribute_type, DEFUN (rip_redistribute_type_routemap, rip_redistribute_type_routemap_cmd, - "redistribute " QUAGGA_REDIST_STR_RIPD " route-map WORD", + "redistribute " FRR_REDIST_STR_RIPD " route-map WORD", REDIST_STR - QUAGGA_REDIST_HELP_STR_RIPD + FRR_REDIST_HELP_STR_RIPD "Route map reference\n" "Pointer to route-map entries\n") { @@ -450,10 +450,10 @@ DEFUN (rip_redistribute_type_routemap, DEFUN (no_rip_redistribute_type_routemap, no_rip_redistribute_type_routemap_cmd, - "no redistribute " QUAGGA_REDIST_STR_RIPD " route-map WORD", + "no redistribute " FRR_REDIST_STR_RIPD " route-map WORD", NO_STR REDIST_STR - QUAGGA_REDIST_HELP_STR_RIPD + FRR_REDIST_HELP_STR_RIPD "Route map reference\n" "Pointer to route-map entries\n") { @@ -479,9 +479,9 @@ DEFUN (no_rip_redistribute_type_routemap, DEFUN (rip_redistribute_type_metric, rip_redistribute_type_metric_cmd, - "redistribute " QUAGGA_REDIST_STR_RIPD " metric <0-16>", + "redistribute " FRR_REDIST_STR_RIPD " metric <0-16>", REDIST_STR - QUAGGA_REDIST_HELP_STR_RIPD + FRR_REDIST_HELP_STR_RIPD "Metric\n" "Metric value\n") { @@ -509,10 +509,10 @@ DEFUN (rip_redistribute_type_metric, DEFUN (no_rip_redistribute_type_metric, no_rip_redistribute_type_metric_cmd, - "no redistribute " QUAGGA_REDIST_STR_RIPD " metric <0-16>", + "no redistribute " FRR_REDIST_STR_RIPD " metric <0-16>", NO_STR REDIST_STR - QUAGGA_REDIST_HELP_STR_RIPD + FRR_REDIST_HELP_STR_RIPD "Metric\n" "Metric value\n") { @@ -538,9 +538,9 @@ DEFUN (no_rip_redistribute_type_metric, DEFUN (rip_redistribute_type_metric_routemap, rip_redistribute_type_metric_routemap_cmd, - "redistribute " QUAGGA_REDIST_STR_RIPD " metric <0-16> route-map WORD", + "redistribute " FRR_REDIST_STR_RIPD " metric <0-16> route-map WORD", REDIST_STR - QUAGGA_REDIST_HELP_STR_RIPD + FRR_REDIST_HELP_STR_RIPD "Metric\n" "Metric value\n" "Route map reference\n" @@ -572,11 +572,11 @@ DEFUN (rip_redistribute_type_metric_routemap, DEFUN (no_rip_redistribute_type_metric_routemap, no_rip_redistribute_type_metric_routemap_cmd, - "no redistribute " QUAGGA_REDIST_STR_RIPD + "no redistribute " FRR_REDIST_STR_RIPD " metric <0-16> route-map WORD", NO_STR REDIST_STR - QUAGGA_REDIST_HELP_STR_RIPD + FRR_REDIST_HELP_STR_RIPD "Metric\n" "Metric value\n" "Route map reference\n" diff --git a/ripngd/ripng_zebra.c b/ripngd/ripng_zebra.c index d05b5dbad8..67337caf28 100644 --- a/ripngd/ripng_zebra.c +++ b/ripngd/ripng_zebra.c @@ -339,9 +339,9 @@ DEFUN (no_ripng_redistribute_ripng, DEFUN (ripng_redistribute_type, ripng_redistribute_type_cmd, - "redistribute " QUAGGA_REDIST_STR_RIPNGD, + "redistribute " FRR_REDIST_STR_RIPNGD, "Redistribute\n" - QUAGGA_REDIST_HELP_STR_RIPNGD) + FRR_REDIST_HELP_STR_RIPNGD) { int type; @@ -359,10 +359,10 @@ DEFUN (ripng_redistribute_type, DEFUN (no_ripng_redistribute_type, no_ripng_redistribute_type_cmd, - "no redistribute " QUAGGA_REDIST_STR_RIPNGD, + "no redistribute " FRR_REDIST_STR_RIPNGD, NO_STR "Redistribute\n" - QUAGGA_REDIST_HELP_STR_RIPNGD) + FRR_REDIST_HELP_STR_RIPNGD) { int type; @@ -382,9 +382,9 @@ DEFUN (no_ripng_redistribute_type, DEFUN (ripng_redistribute_type_metric, ripng_redistribute_type_metric_cmd, - "redistribute " QUAGGA_REDIST_STR_RIPNGD " metric <0-16>", + "redistribute " FRR_REDIST_STR_RIPNGD " metric <0-16>", "Redistribute\n" - QUAGGA_REDIST_HELP_STR_RIPNGD + FRR_REDIST_HELP_STR_RIPNGD "Metric\n" "Metric value\n") { @@ -408,18 +408,18 @@ DEFUN (ripng_redistribute_type_metric, ALIAS (no_ripng_redistribute_type, no_ripng_redistribute_type_metric_cmd, - "no redistribute " QUAGGA_REDIST_STR_RIPNGD " metric <0-16>", + "no redistribute " FRR_REDIST_STR_RIPNGD " metric <0-16>", NO_STR "Redistribute\n" - QUAGGA_REDIST_HELP_STR_RIPNGD + FRR_REDIST_HELP_STR_RIPNGD "Metric\n" "Metric value\n") DEFUN (ripng_redistribute_type_routemap, ripng_redistribute_type_routemap_cmd, - "redistribute " QUAGGA_REDIST_STR_RIPNGD " route-map WORD", + "redistribute " FRR_REDIST_STR_RIPNGD " route-map WORD", "Redistribute\n" - QUAGGA_REDIST_HELP_STR_RIPNGD + FRR_REDIST_HELP_STR_RIPNGD "Route map reference\n" "Pointer to route-map entries\n") { @@ -441,18 +441,18 @@ DEFUN (ripng_redistribute_type_routemap, ALIAS (no_ripng_redistribute_type, no_ripng_redistribute_type_routemap_cmd, - "no redistribute " QUAGGA_REDIST_STR_RIPNGD " route-map WORD", + "no redistribute " FRR_REDIST_STR_RIPNGD " route-map WORD", NO_STR "Redistribute\n" - QUAGGA_REDIST_HELP_STR_RIPNGD + FRR_REDIST_HELP_STR_RIPNGD "Route map reference\n" "Pointer to route-map entries\n") DEFUN (ripng_redistribute_type_metric_routemap, ripng_redistribute_type_metric_routemap_cmd, - "redistribute " QUAGGA_REDIST_STR_RIPNGD " metric <0-16> route-map WORD", + "redistribute " FRR_REDIST_STR_RIPNGD " metric <0-16> route-map WORD", "Redistribute\n" - QUAGGA_REDIST_HELP_STR_RIPNGD + FRR_REDIST_HELP_STR_RIPNGD "Metric\n" "Metric value\n" "Route map reference\n" @@ -478,10 +478,10 @@ DEFUN (ripng_redistribute_type_metric_routemap, ALIAS (no_ripng_redistribute_type, no_ripng_redistribute_type_metric_routemap_cmd, - "no redistribute " QUAGGA_REDIST_STR_RIPNGD " metric <0-16> route-map WORD", + "no redistribute " FRR_REDIST_STR_RIPNGD " metric <0-16> route-map WORD", NO_STR "Redistribute\n" - QUAGGA_REDIST_HELP_STR_RIPNGD + FRR_REDIST_HELP_STR_RIPNGD "Route map reference\n" "Pointer to route-map entries\n") diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index 3075a61c4a..041f67826b 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -730,10 +730,10 @@ ALIAS (no_zebra_route_map_timer, DEFUN (ip_protocol, ip_protocol_cmd, - "ip protocol " QUAGGA_IP_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP", + "ip protocol " FRR_IP_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP", IP_STR "Filter routing info exchanged between zebra and protocol\n" - QUAGGA_IP_PROTOCOL_MAP_HELP_STR_ZEBRA + FRR_IP_PROTOCOL_MAP_HELP_STR_ZEBRA "Route map name\n") { int i; @@ -767,11 +767,11 @@ DEFUN (ip_protocol, DEFUN (no_ip_protocol, no_ip_protocol_cmd, - "no ip protocol " QUAGGA_IP_PROTOCOL_MAP_STR_ZEBRA, + "no ip protocol " FRR_IP_PROTOCOL_MAP_STR_ZEBRA, NO_STR IP_STR "Stop filtering routing info between zebra and protocol\n" - QUAGGA_IP_PROTOCOL_MAP_HELP_STR_ZEBRA + FRR_IP_PROTOCOL_MAP_HELP_STR_ZEBRA "Protocol from which to stop filtering routes\n") { int i; @@ -805,11 +805,11 @@ DEFUN (no_ip_protocol, ALIAS (no_ip_protocol, no_ip_protocol_val_cmd, - "no ip protocol " QUAGGA_IP_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP", + "no ip protocol " FRR_IP_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP", NO_STR IP_STR "Stop filtering routing info between zebra and protocol\n" - QUAGGA_IP_PROTOCOL_MAP_HELP_STR_ZEBRA + FRR_IP_PROTOCOL_MAP_HELP_STR_ZEBRA "route map name") DEFUN (show_ip_protocol, @@ -843,10 +843,10 @@ DEFUN (show_ip_protocol, DEFUN (ipv6_protocol, ipv6_protocol_cmd, - "ipv6 protocol " QUAGGA_IP6_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP", + "ipv6 protocol " FRR_IP6_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP", IP6_STR "Filter IPv6 routing info exchanged between zebra and protocol\n" - QUAGGA_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA + FRR_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA "Route map name\n") { int i; @@ -880,11 +880,11 @@ DEFUN (ipv6_protocol, DEFUN (no_ipv6_protocol, no_ipv6_protocol_cmd, - "no ipv6 protocol " QUAGGA_IP6_PROTOCOL_MAP_STR_ZEBRA, + "no ipv6 protocol " FRR_IP6_PROTOCOL_MAP_STR_ZEBRA, NO_STR IP6_STR "Stop filtering IPv6 routing info between zebra and protocol\n" - QUAGGA_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA + FRR_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA "Protocol from which to stop filtering routes\n") { int i; @@ -919,11 +919,11 @@ DEFUN (no_ipv6_protocol, ALIAS (no_ipv6_protocol, no_ipv6_protocol_val_cmd, - "no ipv6 protocol " QUAGGA_IP6_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP", + "no ipv6 protocol " FRR_IP6_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP", NO_STR IP6_STR "Stop filtering IPv6 routing info between zebra and protocol\n" - QUAGGA_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA + FRR_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA "route map name") DEFUN (show_ipv6_protocol, @@ -957,10 +957,10 @@ DEFUN (show_ipv6_protocol, DEFUN (ip_protocol_nht_rmap, ip_protocol_nht_rmap_cmd, - "ip nht " QUAGGA_IP_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP", + "ip nht " FRR_IP_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP", IP_STR "Filter Next Hop tracking route resolution\n" - QUAGGA_IP_PROTOCOL_MAP_HELP_STR_ZEBRA + FRR_IP_PROTOCOL_MAP_HELP_STR_ZEBRA "Route map name\n") { int i; @@ -991,11 +991,11 @@ DEFUN (ip_protocol_nht_rmap, DEFUN (no_ip_protocol_nht_rmap, no_ip_protocol_nht_rmap_cmd, - "no ip nht " QUAGGA_IP_PROTOCOL_MAP_STR_ZEBRA, + "no ip nht " FRR_IP_PROTOCOL_MAP_STR_ZEBRA, NO_STR IP_STR "Filter Next Hop tracking route resolution\n" - QUAGGA_IP_PROTOCOL_MAP_HELP_STR_ZEBRA) + FRR_IP_PROTOCOL_MAP_HELP_STR_ZEBRA) { int i; @@ -1024,10 +1024,10 @@ DEFUN (no_ip_protocol_nht_rmap, ALIAS (no_ip_protocol_nht_rmap, no_ip_protocol_nht_rmap_val_cmd, - "no ip nht " QUAGGA_IP_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP", + "no ip nht " FRR_IP_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP", IP_STR "Filter Next Hop tracking route resolution\n" - QUAGGA_IP_PROTOCOL_MAP_HELP_STR_ZEBRA + FRR_IP_PROTOCOL_MAP_HELP_STR_ZEBRA "Route map name\n") DEFUN (show_ip_protocol_nht, @@ -1061,10 +1061,10 @@ DEFUN (show_ip_protocol_nht, DEFUN (ipv6_protocol_nht_rmap, ipv6_protocol_nht_rmap_cmd, - "ipv6 nht " QUAGGA_IP6_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP", + "ipv6 nht " FRR_IP6_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP", IP6_STR "Filter Next Hop tracking route resolution\n" - QUAGGA_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA + FRR_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA "Route map name\n") { int i; @@ -1089,11 +1089,11 @@ DEFUN (ipv6_protocol_nht_rmap, DEFUN (no_ipv6_protocol_nht_rmap, no_ipv6_protocol_nht_rmap_cmd, - "no ipv6 nht " QUAGGA_IP6_PROTOCOL_MAP_STR_ZEBRA, + "no ipv6 nht " FRR_IP6_PROTOCOL_MAP_STR_ZEBRA, NO_STR IP6_STR "Filter Next Hop tracking route resolution\n" - QUAGGA_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA) + FRR_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA) { int i; @@ -1127,11 +1127,11 @@ DEFUN (no_ipv6_protocol_nht_rmap, ALIAS (no_ipv6_protocol_nht_rmap, no_ipv6_protocol_nht_rmap_val_cmd, - "no ipv6 nht " QUAGGA_IP6_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP", + "no ipv6 nht " FRR_IP6_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP", NO_STR IP6_STR "Filter Next Hop tracking route resolution\n" - QUAGGA_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA + FRR_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA "Route map name\n") DEFUN (show_ipv6_protocol_nht, diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 84106e7ff9..98c20270c3 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -2858,11 +2858,11 @@ ALIAS (show_ip_route_supernets, DEFUN (show_ip_route_protocol, show_ip_route_protocol_cmd, - "show ip route " QUAGGA_IP_REDIST_STR_ZEBRA, + "show ip route " FRR_IP_REDIST_STR_ZEBRA, SHOW_STR IP_STR "IP routing table\n" - QUAGGA_IP_REDIST_HELP_STR_ZEBRA) + FRR_IP_REDIST_HELP_STR_ZEBRA) { int type; struct route_table *table; @@ -2906,12 +2906,12 @@ DEFUN (show_ip_route_protocol, ALIAS (show_ip_route_protocol, show_ip_route_vrf_protocol_cmd, - "show ip route " VRF_CMD_STR " " QUAGGA_IP_REDIST_STR_ZEBRA, + "show ip route " VRF_CMD_STR " " FRR_IP_REDIST_STR_ZEBRA, SHOW_STR IP_STR "IP routing table\n" VRF_CMD_HELP_STR - QUAGGA_IP_REDIST_HELP_STR_ZEBRA) + FRR_IP_REDIST_HELP_STR_ZEBRA) DEFUN (show_ip_route_ospf_instance, show_ip_route_ospf_instance_cmd, @@ -3487,12 +3487,12 @@ DEFUN (show_ip_route_vrf_all_supernets, DEFUN (show_ip_route_vrf_all_protocol, show_ip_route_vrf_all_protocol_cmd, - "show ip route " VRF_ALL_CMD_STR " " QUAGGA_IP_REDIST_STR_ZEBRA, + "show ip route " VRF_ALL_CMD_STR " " FRR_IP_REDIST_STR_ZEBRA, SHOW_STR IP_STR "IP routing table\n" VRF_ALL_CMD_HELP_STR - QUAGGA_IP_REDIST_HELP_STR_ZEBRA"\n") + FRR_IP_REDIST_HELP_STR_ZEBRA"\n") { int type; struct route_table *table; @@ -5124,11 +5124,11 @@ ALIAS (show_ipv6_route_prefix_longer, DEFUN (show_ipv6_route_protocol, show_ipv6_route_protocol_cmd, - "show ipv6 route " QUAGGA_IP6_REDIST_STR_ZEBRA, + "show ipv6 route " FRR_IP6_REDIST_STR_ZEBRA, SHOW_STR IP_STR "IP routing table\n" - QUAGGA_IP6_REDIST_HELP_STR_ZEBRA) + FRR_IP6_REDIST_HELP_STR_ZEBRA) { int type; struct route_table *table; @@ -5172,12 +5172,12 @@ DEFUN (show_ipv6_route_protocol, ALIAS (show_ipv6_route_protocol, show_ipv6_route_vrf_protocol_cmd, - "show ipv6 route " VRF_CMD_STR " " QUAGGA_IP6_REDIST_STR_ZEBRA, + "show ipv6 route " VRF_CMD_STR " " FRR_IP6_REDIST_STR_ZEBRA, SHOW_STR IP_STR "IP routing table\n" VRF_CMD_HELP_STR - QUAGGA_IP6_REDIST_HELP_STR_ZEBRA) + FRR_IP6_REDIST_HELP_STR_ZEBRA) DEFUN (show_ipv6_route_addr, show_ipv6_route_addr_cmd, @@ -5562,12 +5562,12 @@ DEFUN (show_ipv6_route_vrf_all_prefix_longer, DEFUN (show_ipv6_route_vrf_all_protocol, show_ipv6_route_vrf_all_protocol_cmd, - "show ipv6 route " VRF_ALL_CMD_STR " " QUAGGA_IP6_REDIST_STR_ZEBRA, + "show ipv6 route " VRF_ALL_CMD_STR " " FRR_IP6_REDIST_STR_ZEBRA, SHOW_STR IP_STR "IP routing table\n" VRF_ALL_CMD_HELP_STR - QUAGGA_IP6_REDIST_HELP_STR_ZEBRA) + FRR_IP6_REDIST_HELP_STR_ZEBRA) { int type; struct route_table *table; -- cgit v1.2.3 From 5ee62c66a95b9358275e8c883aed5c68b644dcca Mon Sep 17 00:00:00 2001 From: "G. Paul Ziemba" Date: Fri, 4 Nov 2016 09:47:36 -0700 Subject: BGP: deal with vnc related string ambiguities (issue #9) - "redist foo" parsing modified to check for foo==vnc and foo==vnc-direct instead of just leading 'v' character - string designating ZEBRA_ROUTE_VNC_DIRECT changed from "vpn" to "vnc-direct" - route_types.pl parser recognizes 7th field to restrict availability of a route type in the redist command to specific daemons - restrict "vnc-direct" to bgpd only (doesn't make sense elsewhere) - vnc documentation updated to match Signed-off-by: Lou Berger --- doc/vnc.texi | 4 ++-- lib/log.c | 12 ++++++------ lib/route_types.pl | 5 ++++- lib/route_types.txt | 8 ++++---- 4 files changed, 16 insertions(+), 13 deletions(-) (limited to 'lib/log.c') diff --git a/doc/vnc.texi b/doc/vnc.texi index 341cbfcce8..b0d2829cae 100644 --- a/doc/vnc.texi +++ b/doc/vnc.texi @@ -726,7 +726,7 @@ provided to other protocols, either via zebra or directly to BGP. It is important to note that when exporting routes to other protocols, the downstream protocol must also be configured to import the routes. For example, when VNC routes are exported to unicast BGP, the BGP -configuration must include a corresponding @code{redistribute vpn} +configuration must include a corresponding @code{redistribute vnc-direct} statement. @deffn {VNC} {export bgp|zebra mode none|group-nve|registering-nve|ce} @@ -1115,7 +1115,7 @@ The configuration for @code{VNC-GW 1} is shown below. router bgp 64512 bgp router-id 192.168.1.101 bgp cluster-id 1.2.3.4 - redistribute vpn + redistribute vnc-direct neighbor 192.168.1.102 remote-as 64512 no neighbor 192.168.1.102 activate neighbor 192.168.1.103 remote-as 64512 diff --git a/lib/log.c b/lib/log.c index f9877300b4..a0902b5d0d 100644 --- a/lib/log.c +++ b/lib/log.c @@ -1077,10 +1077,10 @@ proto_redistnum(int afi, const char *s) return ZEBRA_ROUTE_BGP; else if (strncmp (s, "ta", 2) == 0) return ZEBRA_ROUTE_TABLE; - else if (strncmp (s, "v", 1) == 0) - return ZEBRA_ROUTE_VNC; - else if (strncmp (s, "vd", 1) == 0) + else if (strcmp (s, "vnc-direct") == 0) return ZEBRA_ROUTE_VNC_DIRECT; + else if (strcmp (s, "vnc") == 0) + return ZEBRA_ROUTE_VNC; } if (afi == AFI_IP6) { @@ -1100,10 +1100,10 @@ proto_redistnum(int afi, const char *s) return ZEBRA_ROUTE_BGP; else if (strncmp (s, "ta", 2) == 0) return ZEBRA_ROUTE_TABLE; - else if (strncmp (s, "v", 1) == 0) - return ZEBRA_ROUTE_VNC; - else if (strncmp (s, "vd", 1) == 0) + else if (strcmp (s, "vnc-direct") == 0) return ZEBRA_ROUTE_VNC_DIRECT; + else if (strcmp (s, "vnc") == 0) + return ZEBRA_ROUTE_VNC; } return -1; } diff --git a/lib/route_types.pl b/lib/route_types.pl index d44cb12b23..7e99fdde09 100755 --- a/lib/route_types.pl +++ b/lib/route_types.pl @@ -56,7 +56,7 @@ while () { # else: 7-field line my @f = split(/,/, $_); - unless (@f == 7) { + unless (@f == 7 || @f == 8) { die "invalid input on route_types line $.\n"; } @@ -73,6 +73,7 @@ while () { "ipv4" => int($f[4]), "ipv6" => int($f[5]), "shorthelp" => $f[6], + "restrict2" => $f[7], }; push @protos, $proto; $daemons{$f[2]} = { @@ -137,6 +138,8 @@ sub collect { my (@names, @help) = ((), ()); for my $p (@protos) { next if ($protodetail{$p}->{"daemon"} eq $daemon && $daemon ne "zebra"); + next if ($protodetail{$p}->{"restrict2"} ne "" && + $protodetail{$p}->{"restrict2"} ne $daemon); next unless (($ipv4 && $protodetail{$p}->{"ipv4"}) || ($ipv6 && $protodetail{$p}->{"ipv6"})); push @names, $protodetail{$p}->{"cname"}; diff --git a/lib/route_types.txt b/lib/route_types.txt index 54572450b5..154f03f01c 100644 --- a/lib/route_types.txt +++ b/lib/route_types.txt @@ -64,9 +64,9 @@ ZEBRA_ROUTE_LDP, ldp, ldpd, 'L', 0, 0, "LDP" #vnc when sent to zebra ZEBRA_ROUTE_VNC, vnc, NULL, 'v', 1, 1, "VNC" # vnc when sent to bgp -ZEBRA_ROUTE_VNC_DIRECT, vpn, NULL, 'V', 1, 1, "VPN" -# vnc when sent to bgp (remote next hop?) -ZEBRA_ROUTE_VNC_DIRECT_RH, vpn-rh, NULL, 'V', 0, 0, "VPN" +ZEBRA_ROUTE_VNC_DIRECT, vnc-direct,NULL, 'V', 1, 1, "VNC-Direct", bgpd +# vnc when sent to bgp (resolve NVE mode) +ZEBRA_ROUTE_VNC_DIRECT_RH, vnc-rn, NULL, 'V', 0, 0, "VNC-RN" # bgp unicast -> vnc ZEBRA_ROUTE_BGP_DIRECT, bgp-direct, NULL, 'b', 0, 0, "BGP-Direct" # bgp unicast -> vnc @@ -90,4 +90,4 @@ ZEBRA_ROUTE_VNC, "Virtual Network Control (VNC)" ZEBRA_ROUTE_OLSR, "Optimised Link State Routing (OLSR)" ZEBRA_ROUTE_TABLE, "Non-main Kernel Routing Table" ZEBRA_ROUTE_LDP, "Label Distribution Protocol (LDP)" -ZEBRA_ROUTE_VNC_DIRECT, "VPN routes(VPN)" +ZEBRA_ROUTE_VNC_DIRECT, "VNC direct (not via zebra) routes" -- cgit v1.2.3 From 9473e340520626244678e59169547a27b1b257ad Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 3 Jan 2017 20:13:02 -0500 Subject: watchfrr: Rename watchquagga -> watchfrr Signed-off-by: Donald Sharp --- Makefile.am | 4 +- configure.ac | 22 +- cumulus/etc/quagga/daemons | 2 +- cumulus/etc/quagga/debian.conf | 4 +- debian/quagga.install | 2 +- debian/quagga.manpages | 2 +- debian/watchquagga.rc | 6 +- doc/Makefile.am | 6 +- doc/vtysh.texi | 8 +- doc/watchfrr.8.in | 231 +++++++ doc/watchquagga.8.in | 231 ------- lib/command.c | 2 +- lib/log.c | 2 +- lib/log.h | 2 +- lib/vty.c | 2 +- redhat/Makefile.am | 2 +- redhat/README.rpm_build.md | 12 +- redhat/quagga.spec.in | 72 +- redhat/quagga.sysconfig | 2 +- redhat/watchquagga.init | 14 +- solaris/prototype.daemons.in | 2 +- tools/quagga | 54 +- vtysh/Makefile.am | 2 +- vtysh/vtysh.c | 6 +- vtysh/vtysh.h | 4 +- watchfrr/.gitignore | 16 + watchfrr/Makefile.am | 13 + watchfrr/watchfrr.c | 1439 ++++++++++++++++++++++++++++++++++++++++ watchfrr/watchfrr.h | 29 + watchfrr/watchfrr_vty.c | 134 ++++ watchquagga/.gitignore | 16 - watchquagga/Makefile.am | 13 - watchquagga/watchquagga.c | 1439 ---------------------------------------- watchquagga/watchquagga.h | 29 - watchquagga/watchquagga_vty.c | 134 ---- 35 files changed, 1979 insertions(+), 1979 deletions(-) create mode 100644 doc/watchfrr.8.in delete mode 100644 doc/watchquagga.8.in create mode 100644 watchfrr/.gitignore create mode 100644 watchfrr/Makefile.am create mode 100644 watchfrr/watchfrr.c create mode 100644 watchfrr/watchfrr.h create mode 100644 watchfrr/watchfrr_vty.c delete mode 100644 watchquagga/.gitignore delete mode 100644 watchquagga/Makefile.am delete mode 100644 watchquagga/watchquagga.c delete mode 100644 watchquagga/watchquagga.h delete mode 100644 watchquagga/watchquagga_vty.c (limited to 'lib/log.c') diff --git a/Makefile.am b/Makefile.am index d8b9844ffc..d9b57a5eae 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,11 +2,11 @@ SUBDIRS = lib qpb fpm @ZEBRA@ @LIBRFP@ @RFPTEST@ \ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ @LDPD@ \ - @ISISD@ @PIMD@ @WATCHQUAGGA@ @VTYSH@ @OSPFCLIENT@ @DOC@ m4 @pkgsrcdir@ \ + @ISISD@ @PIMD@ @WATCHFRR@ @VTYSH@ @OSPFCLIENT@ @DOC@ m4 @pkgsrcdir@ \ redhat @SOLARIS@ tests tools cumulus DIST_SUBDIRS = lib qpb fpm zebra bgpd ripd ripngd ospfd ospf6d ldpd \ - isisd watchquagga vtysh ospfclient doc m4 pkgsrc redhat tests \ + isisd watchfrr vtysh ospfclient doc m4 pkgsrc redhat tests \ solaris pimd @LIBRFP@ @RFPTEST@ tools cumulus EXTRA_DIST = aclocal.m4 SERVICES REPORTING-BUGS \ diff --git a/configure.ac b/configure.ac index d0d5fbb19b..7b27cbd8db 100755 --- a/configure.ac +++ b/configure.ac @@ -213,8 +213,8 @@ AC_ARG_ENABLE(ospf6d, AS_HELP_STRING([--disable-ospf6d], [do not build ospf6d])) AC_ARG_ENABLE(ldpd, AS_HELP_STRING([--enable-ldpd], [build ldpd])) -AC_ARG_ENABLE(watchquagga, - AS_HELP_STRING([--disable-watchquagga], [do not build watchquagga])) +AC_ARG_ENABLE(watchfrr, + AS_HELP_STRING([--disable-watchfrr], [do not build watchfrr])) AC_ARG_ENABLE(isisd, AS_HELP_STRING([--disable-isisd], [do not build isisd])) AC_ARG_ENABLE(pimd, @@ -1170,12 +1170,12 @@ else fi AM_CONDITIONAL(LDPD, test "x$LDPD" = "xldpd") -if test "${enable_watchquagga}" = "no";then - WATCHQUAGGA="" +if test "${enable_watchfrr}" = "no";then + WATCHFRR="" else - WATCHQUAGGA="watchquagga" + WATCHFRR="watchfrr" fi -AM_CONDITIONAL(WATCHQUAGGA, test "x$WATCHQUAGGA" = "xwatchquagga") +AM_CONDITIONAL(WATCHFRR, test "x$WATCHFRR" = "xwatchfrr") OSPFCLIENT="" if test "${enable_ospfapi}" != "no";then @@ -1250,7 +1250,7 @@ AC_SUBST(RIPNGD) AC_SUBST(OSPFD) AC_SUBST(OSPF6D) AC_SUBST(LDPD) -AC_SUBST(WATCHQUAGGA) +AC_SUBST(WATCHFRR) AC_SUBST(ISISD) AC_SUBST(PIMD) AC_SUBST(SOLARIS) @@ -1548,7 +1548,7 @@ AC_DEFINE_UNQUOTED(PATH_LDPD_PID, "$frr_statedir/ldpd.pid",ldpd PID) AC_DEFINE_UNQUOTED(LDPD_SOCKET, "$frr_statedir/ldpd.sock",ldpd control socket) AC_DEFINE_UNQUOTED(PATH_ISISD_PID, "$frr_statedir/isisd.pid",isisd PID) AC_DEFINE_UNQUOTED(PATH_PIMD_PID, "$frr_statedir/pimd.pid",pimd PID) -AC_DEFINE_UNQUOTED(PATH_WATCHQUAGGA_PID, "$frr_statedir/watchquagga.pid",watchquagga PID) +AC_DEFINE_UNQUOTED(PATH_WATCHFRR_PID, "$frr_statedir/watchfrr.pid",watchfrr PID) AC_DEFINE_UNQUOTED(ZEBRA_SERV_PATH, "$frr_statedir/zserv.api",zebra api socket) AC_DEFINE_UNQUOTED(ZEBRA_VTYSH_PATH, "$frr_statedir/zebra.vty",zebra vty socket) AC_DEFINE_UNQUOTED(RIP_VTYSH_PATH, "$frr_statedir/ripd.vty",rip vty socket) @@ -1559,7 +1559,7 @@ AC_DEFINE_UNQUOTED(OSPF6_VTYSH_PATH, "$frr_statedir/ospf6d.vty",ospf6d vty socke AC_DEFINE_UNQUOTED(LDP_VTYSH_PATH, "$frr_statedir/ldpd.vty",ldpd vty socket) AC_DEFINE_UNQUOTED(ISIS_VTYSH_PATH, "$frr_statedir/isisd.vty",isisd vty socket) AC_DEFINE_UNQUOTED(PIM_VTYSH_PATH, "$frr_statedir/pimd.vty",pimd vty socket) -AC_DEFINE_UNQUOTED(WATCHQUAGGA_VTYSH_PATH, "$frr_statedir/watchquagga.vty",watchquagga vty socket) +AC_DEFINE_UNQUOTED(WATCHFRR_VTYSH_PATH, "$frr_statedir/watchfrr.vty",watchfrr vty socket) AC_DEFINE_UNQUOTED(DAEMON_VTY_DIR, "$frr_statedir",daemon vty directory) dnl autoconf does this, but it does it too late... @@ -1605,7 +1605,7 @@ AC_CACHE_VAL(ac_cv_htonl_works, AC_MSG_RESULT($ac_cv_htonl_works) AC_CONFIG_FILES([Makefile lib/Makefile qpb/Makefile zebra/Makefile ripd/Makefile - ripngd/Makefile bgpd/Makefile ospfd/Makefile watchquagga/Makefile + ripngd/Makefile bgpd/Makefile ospfd/Makefile watchfrr/Makefile ospf6d/Makefile ldpd/Makefile isisd/Makefile vtysh/Makefile doc/Makefile ospfclient/Makefile tests/Makefile m4/Makefile pimd/Makefile @@ -1629,7 +1629,7 @@ AC_CONFIG_FILES([Makefile lib/Makefile qpb/Makefile zebra/Makefile ripd/Makefile doc/ripngd.8 doc/pimd.8 doc/vtysh.1 - doc/watchquagga.8 + doc/watchfrr.8 doc/zebra.8 doc/quagga.1 pkgsrc/bgpd.sh pkgsrc/ospf6d.sh pkgsrc/ospfd.sh diff --git a/cumulus/etc/quagga/daemons b/cumulus/etc/quagga/daemons index dd0e23914b..c7b8496a4e 100644 --- a/cumulus/etc/quagga/daemons +++ b/cumulus/etc/quagga/daemons @@ -18,7 +18,7 @@ # When using "vtysh" such a config file is also needed. It should be owned by # group "quaggavty" and set to ug=rw,o= though. Check /etc/pam.d/quagga, too. # -# The watchquagga daemon is always started. Per default in monitoring-only but +# The watchfrr daemon is always started. Per default in monitoring-only but # that can be changed via /etc/quagga/debian.conf. # zebra=no diff --git a/cumulus/etc/quagga/debian.conf b/cumulus/etc/quagga/debian.conf index 88df9424e2..bd1fcecf9f 100644 --- a/cumulus/etc/quagga/debian.conf +++ b/cumulus/etc/quagga/debian.conf @@ -14,5 +14,5 @@ isisd_options=" --daemon -A 127.0.0.1" pimd_options=" --daemon -A 127.0.0.1" # The list of daemons to watch is automatically generated by the init script. -watchquagga_enable=yes -watchquagga_options=(-adz -r /usr/sbin/servicebBquaggabBrestartbB%s -s /usr/sbin/servicebBquaggabBstartbB%s -k /usr/sbin/servicebBquaggabBstopbB%s -b bB -t 30) +watchfrr_enable=yes +watchfrr_options=(-adz -r /usr/sbin/servicebBquaggabBrestartbB%s -s /usr/sbin/servicebBquaggabBstartbB%s -k /usr/sbin/servicebBquaggabBstopbB%s -b bB -t 30) diff --git a/debian/quagga.install b/debian/quagga.install index 6a70be9925..022bd94ec7 100644 --- a/debian/quagga.install +++ b/debian/quagga.install @@ -15,7 +15,7 @@ usr/share/man/man8/ripd.8 usr/share/man/man8/ripngd.8 usr/share/man/man8/zebra.8 usr/share/man/man8/isisd.8 -usr/share/man/man8/watchquagga.8 +usr/share/man/man8/watchfrr.8 usr/share/snmp/mibs/ cumulus/etc/* etc/ tools/*.service lib/systemd/system diff --git a/debian/quagga.manpages b/debian/quagga.manpages index 194b13af66..17a128b7e3 100644 --- a/debian/quagga.manpages +++ b/debian/quagga.manpages @@ -6,4 +6,4 @@ doc/ripngd.8 doc/vtysh.1 doc/zebra.8 doc/isisd.8 -doc/watchquagga.8 +doc/watchfrr.8 diff --git a/debian/watchquagga.rc b/debian/watchquagga.rc index e3b6340dce..81a00393d2 100644 --- a/debian/watchquagga.rc +++ b/debian/watchquagga.rc @@ -1,4 +1,4 @@ -check process watchquagga with pidfile /var/run/quagga/watchquagga.pid - start program = "/etc/init.d/quagga start watchquagga" with timeout 120 seconds - stop program = "/etc/init.d/quagga stop watchquagga" +check process watchfrr with pidfile /var/run/quagga/watchfrr.pid + start program = "/etc/init.d/quagga start watchfrr" with timeout 120 seconds + stop program = "/etc/init.d/quagga stop watchfrr" if 3 restarts within 10 cycles then timeout diff --git a/doc/Makefile.am b/doc/Makefile.am index ab2657bba4..a9c0cc221d 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -115,8 +115,8 @@ if VTYSH man_MANS += vtysh.1 endif -if WATCHQUAGGA -man_MANS += watchquagga.8 +if WATCHFRR +man_MANS += watchfrr.8 endif if ZEBRA @@ -135,7 +135,7 @@ EXTRA_DIST = BGP-TypeCode draft-zebra-00.ms draft-zebra-00.txt \ ripngd.8.in \ pimd.8.in \ vtysh.1.in \ - watchquagga.8.in \ + watchfrr.8.in \ zebra.8.in \ quagga.1.in \ \ diff --git a/doc/vtysh.texi b/doc/vtysh.texi index 69b7acd3b7..920b39d7f5 100644 --- a/doc/vtysh.texi +++ b/doc/vtysh.texi @@ -87,12 +87,12 @@ lost after doing a configuration save. @end quotation Since the @command{vtysh} command may be running as ordinary user on the -system, configuration writes will be tried through @command{watchquagga}, +system, configuration writes will be tried through @command{watchfrr}, using the @command{write integrated} command internally. Since -@command{watchquagga} is running as superuser, @command{vtysh} is able to +@command{watchfrr} is running as superuser, @command{vtysh} is able to ensure correct ownership and permissions on @file{Quagga.conf}. -If @command{watchquagga} is not running or the configuration write fails, +If @command{watchfrr} is not running or the configuration write fails, @command{vtysh} will attempt to directly write to the file. This is likely to fail if running as unprivileged user; alternatively it may leave the file with incorrect owner or permissions. @@ -147,7 +147,7 @@ installations. Unconditionally (regardless of @command{service integrated-vtysh-config} setting) write out integrated @file{Quagga.conf} file through -@command{watchquagga}. If @command{watchquagga} is not running, this command +@command{watchfrr}. If @command{watchfrr} is not running, this command is unavailable. @end deffn diff --git a/doc/watchfrr.8.in b/doc/watchfrr.8.in new file mode 100644 index 0000000000..813f87abd3 --- /dev/null +++ b/doc/watchfrr.8.in @@ -0,0 +1,231 @@ +.\" This file was originally generated by help2man 1.36. +.TH WATCHFRR 8 "July 2010" +.SH NAME +watchfrr \- a program to monitor the status of frr daemons +.SH SYNOPSIS +.B watchfrr +.RI [ option ...] +.IR daemon ... +.br +.B watchfrr +.BR \-h " | " \-v +.SH DESCRIPTION +.B watchfrr +is a watchdog program that monitors the status of supplied frr +.IR daemon s +and tries to restart them in case they become unresponsive or shut down. +.PP +To determine whether a daemon is running, it tries to connect to the +daemon's VTY UNIX stream socket, and send echo commands to ensure the +daemon responds. When the daemon crashes, EOF is received from the socket, +so that watchfrr can react immediately. +.PP +This program can run in one of the following 5 modes: +.TP +.B Mode 0: monitor +In this mode, the program serves as a monitor and reports status changes. +.IP +Example usage: watchfrr \-d zebra ospfd bgpd +.TP +.B Mode 1: global restart +In this mode, whenever a daemon hangs or crashes, the given command is used +to restart all watched daemons. +.IP +Example usage: watchfrr \-dz \e +.br +-R '/sbin/service zebra restart; /sbin/service ospfd restart' \e +.br +zebra ospfd +.TP +.B Mode 2: individual daemon restart +In this mode, whenever a single daemon hangs or crashes, the given command +is used to restart this daemon only. +.IP +Example usage: watchfrr \-dz \-r '/sbin/service %s restart' \e +.br +zebra ospfd bgpd +.TP +.B Mode 3: phased zebra restart +In this mode, whenever a single daemon hangs or crashes, the given command +is used to restart this daemon only. The only exception is the zebra +daemon; in this case, the following steps are taken: (1) all other daemons +are stopped, (2) zebra is restarted, and (3) other daemons are started +again. +.IP +Example usage: watchfrr \-adz \-r '/sbin/service %s restart' \e +.br +\-s '/sbin/service %s start' \e +.br +\-k '/sbin/service %s stop' zebra ospfd bgpd +.TP +.B Mode 4: phased global restart for any failure +In this mode, whenever a single daemon hangs or crashes, the following +steps are taken: (1) all other daemons are stopped, (2) zebra is restarted, +and (3) other daemons are started again. +.IP +Example usage: watchfrr \-Adz \-r '/sbin/service %s restart' \e +.br +\-s '/sbin/service %s start' \e +.br +\-k '/sbin/service %s stop' zebra ospfd bgpd +.PP +Important: It is believed that mode 2 (individual daemon restart) is not +safe, and mode 3 (phased zebra restart) may not be safe with certain +routing daemons. +.PP +In order to avoid restarting the daemons in quick succession, you can +supply the +.B \-m +and +.B \-M +options to set the minimum and maximum delay between the restart commands. +The minimum restart delay is recalculated each time a restart is attempted. +If the time since the last restart attempt exceeds twice the value of +.BR \-M , +the restart delay is set to the value of +.BR \-m , +otherwise the interval is doubled (but capped at the value of +.BR \-M ). +.SH OPTIONS +.TP +.BR \-d ", " \-\-daemon +Run in daemon mode. When supplied, error messages are sent to Syslog +instead of standard output (stdout). +.TP +.BI \-S " directory" "\fR, \fB\-\-statedir " directory +Set the VTY socket +.I directory +(the default value is "/var/run/frr"). +.TP +.BR \-e ", " \-\-no\-echo +Do not ping the daemons to test whether they respond. This option is +necessary if one or more daemons do not support the echo command. +.TP +.BI \-l " level" "\fR, \fB\-\-loglevel " level +Set the logging +.I level +(the default value is "6"). The value should range from 0 (LOG_EMERG) to 7 +(LOG_DEBUG), but higher number can be supplied if extra debugging messages +are required. +.TP +.BI \-m " number" "\fR, \fB\-\-min\-restart\-interval " number +Set the minimum +.I number +of seconds to wait between invocations of the daemon restart commands (the +default value is "60"). +.TP +.BI \-M " number" "\fR, \fB\-\-max\-restart\-interval " number +Set the maximum +.I number +of seconds to wait between invocations of the daemon restart commands (the +default value is "600"). +.TP +.BI \-i " number" "\fR, \fB\-\-interval " number +Set the status polling interval in seconds (the default value is "5"). +.TP +.BI \-t " number" "\fR, \fB\-\-timeout " number +Set the unresponsiveness timeout in seconds (the default value is "10"). +.TP +.BI \-T " number" "\fR, \fB\-\-restart\-timeout " number +Set the restart (kill) timeout in seconds (the default value is "20"). If +any background jobs are still running after this period has elapsed, they +will be killed. +.TP +.BI \-r " command" "\fR, \fB\-\-restart " command +Supply a Bourne shell +.I command +to restart a single daemon. The command string should contain the '%s' +placeholder to be substituted with the daemon name. +.IP +Note that +.B \-r +and +.B \-R +options are not compatible. +.TP +.BI \-s " command" "\fR, \fB\-\-start\-command " command +Supply a Bourne shell +.I command +to start a single daemon. The command string should contain the '%s' +placeholder to be substituted with the daemon name. +.TP +.BI \-k " command" "\fR, \fB\-\-kill\-command " command +Supply a Bourne shell +.I command +to stop a single daemon. The command string should contain the '%s' +placeholder to be substituted with the daemon name. +.TP +.BR \-R ", " \-\-restart\-all +When one or more daemons are shut down, try to restart them using the +Bourne shell command supplied on the command line. +.IP +Note that +.B \-r +and +.B \-R +options are not compatible. +.TP +.BR \-z ", " \-\-unresponsive\-restart +When a daemon is in an unresponsive state, treat it as being shut down for +the restart purposes. +.TP +.BR \-a ", " \-\-all\-restart +When zebra hangs or crashes, restart all daemons taking the following +steps: (1) stop all other daemons, (2) restart zebra, and (3) start other +daemons again. +.IP +Note that this option also requires +.BR \-r , +.BR \-s , +and +.B \-k +options to be specified. +.TP +.BR \-A ", " \-\-always\-all\-restart +When any daemon (i.e., not just zebra) hangs or crashes, restart all +daemons taking the following steps: (1) stop all other daemons, (2) restart +zebra, and (3) start other daemons again. +.IP +Note that this option also requires +.BR \-r , +.BR \-s , +and +.B \-k +options to be specified. +.TP +.BI \-p " filename" "\fR, \fB\-\-pid\-file " filename +Set the process identifier +.I filename +(the default value is "/var/run/frr/watchfrr.pid"). +.TP +.BI \-b " string" "\fR, \fB\-\-blank\-string " string +When the supplied +.I string +is found in any of the command line option arguments (i.e., +.BR \-r , +.BR \-s , +.BR \-k , +or +.BR \-R ), +replace it with a space. +.IP +This is an ugly hack to circumvent problems with passing the command line +arguments containing embedded spaces. +.TP +.BR \-v ", " \-\-version +Display the version information and exit. +.TP +.BR \-h ", " \-\-help +Display the usage information and exit. +.SH SEE ALSO +.BR zebra (8), +.BR bgpd (8), +.BR isisd (8), +.BR ospfd (8), +.BR ospf6d (8), +.BR ripd (8), +.BR ripngd (8) +.PP +See the project homepage at <@PACKAGE_URL@>. +.SH AUTHORS +Copyright 2004 Andrew J. Schorr diff --git a/doc/watchquagga.8.in b/doc/watchquagga.8.in deleted file mode 100644 index a7249b8376..0000000000 --- a/doc/watchquagga.8.in +++ /dev/null @@ -1,231 +0,0 @@ -.\" This file was originally generated by help2man 1.36. -.TH WATCHQUAGGA 8 "July 2010" -.SH NAME -watchquagga \- a program to monitor the status of quagga daemons -.SH SYNOPSIS -.B watchquagga -.RI [ option ...] -.IR daemon ... -.br -.B watchquagga -.BR \-h " | " \-v -.SH DESCRIPTION -.B watchquagga -is a watchdog program that monitors the status of supplied quagga -.IR daemon s -and tries to restart them in case they become unresponsive or shut down. -.PP -To determine whether a daemon is running, it tries to connect to the -daemon's VTY UNIX stream socket, and send echo commands to ensure the -daemon responds. When the daemon crashes, EOF is received from the socket, -so that watchquagga can react immediately. -.PP -This program can run in one of the following 5 modes: -.TP -.B Mode 0: monitor -In this mode, the program serves as a monitor and reports status changes. -.IP -Example usage: watchquagga \-d zebra ospfd bgpd -.TP -.B Mode 1: global restart -In this mode, whenever a daemon hangs or crashes, the given command is used -to restart all watched daemons. -.IP -Example usage: watchquagga \-dz \e -.br --R '/sbin/service zebra restart; /sbin/service ospfd restart' \e -.br -zebra ospfd -.TP -.B Mode 2: individual daemon restart -In this mode, whenever a single daemon hangs or crashes, the given command -is used to restart this daemon only. -.IP -Example usage: watchquagga \-dz \-r '/sbin/service %s restart' \e -.br -zebra ospfd bgpd -.TP -.B Mode 3: phased zebra restart -In this mode, whenever a single daemon hangs or crashes, the given command -is used to restart this daemon only. The only exception is the zebra -daemon; in this case, the following steps are taken: (1) all other daemons -are stopped, (2) zebra is restarted, and (3) other daemons are started -again. -.IP -Example usage: watchquagga \-adz \-r '/sbin/service %s restart' \e -.br -\-s '/sbin/service %s start' \e -.br -\-k '/sbin/service %s stop' zebra ospfd bgpd -.TP -.B Mode 4: phased global restart for any failure -In this mode, whenever a single daemon hangs or crashes, the following -steps are taken: (1) all other daemons are stopped, (2) zebra is restarted, -and (3) other daemons are started again. -.IP -Example usage: watchquagga \-Adz \-r '/sbin/service %s restart' \e -.br -\-s '/sbin/service %s start' \e -.br -\-k '/sbin/service %s stop' zebra ospfd bgpd -.PP -Important: It is believed that mode 2 (individual daemon restart) is not -safe, and mode 3 (phased zebra restart) may not be safe with certain -routing daemons. -.PP -In order to avoid restarting the daemons in quick succession, you can -supply the -.B \-m -and -.B \-M -options to set the minimum and maximum delay between the restart commands. -The minimum restart delay is recalculated each time a restart is attempted. -If the time since the last restart attempt exceeds twice the value of -.BR \-M , -the restart delay is set to the value of -.BR \-m , -otherwise the interval is doubled (but capped at the value of -.BR \-M ). -.SH OPTIONS -.TP -.BR \-d ", " \-\-daemon -Run in daemon mode. When supplied, error messages are sent to Syslog -instead of standard output (stdout). -.TP -.BI \-S " directory" "\fR, \fB\-\-statedir " directory -Set the VTY socket -.I directory -(the default value is "/var/run/quagga"). -.TP -.BR \-e ", " \-\-no\-echo -Do not ping the daemons to test whether they respond. This option is -necessary if one or more daemons do not support the echo command. -.TP -.BI \-l " level" "\fR, \fB\-\-loglevel " level -Set the logging -.I level -(the default value is "6"). The value should range from 0 (LOG_EMERG) to 7 -(LOG_DEBUG), but higher number can be supplied if extra debugging messages -are required. -.TP -.BI \-m " number" "\fR, \fB\-\-min\-restart\-interval " number -Set the minimum -.I number -of seconds to wait between invocations of the daemon restart commands (the -default value is "60"). -.TP -.BI \-M " number" "\fR, \fB\-\-max\-restart\-interval " number -Set the maximum -.I number -of seconds to wait between invocations of the daemon restart commands (the -default value is "600"). -.TP -.BI \-i " number" "\fR, \fB\-\-interval " number -Set the status polling interval in seconds (the default value is "5"). -.TP -.BI \-t " number" "\fR, \fB\-\-timeout " number -Set the unresponsiveness timeout in seconds (the default value is "10"). -.TP -.BI \-T " number" "\fR, \fB\-\-restart\-timeout " number -Set the restart (kill) timeout in seconds (the default value is "20"). If -any background jobs are still running after this period has elapsed, they -will be killed. -.TP -.BI \-r " command" "\fR, \fB\-\-restart " command -Supply a Bourne shell -.I command -to restart a single daemon. The command string should contain the '%s' -placeholder to be substituted with the daemon name. -.IP -Note that -.B \-r -and -.B \-R -options are not compatible. -.TP -.BI \-s " command" "\fR, \fB\-\-start\-command " command -Supply a Bourne shell -.I command -to start a single daemon. The command string should contain the '%s' -placeholder to be substituted with the daemon name. -.TP -.BI \-k " command" "\fR, \fB\-\-kill\-command " command -Supply a Bourne shell -.I command -to stop a single daemon. The command string should contain the '%s' -placeholder to be substituted with the daemon name. -.TP -.BR \-R ", " \-\-restart\-all -When one or more daemons are shut down, try to restart them using the -Bourne shell command supplied on the command line. -.IP -Note that -.B \-r -and -.B \-R -options are not compatible. -.TP -.BR \-z ", " \-\-unresponsive\-restart -When a daemon is in an unresponsive state, treat it as being shut down for -the restart purposes. -.TP -.BR \-a ", " \-\-all\-restart -When zebra hangs or crashes, restart all daemons taking the following -steps: (1) stop all other daemons, (2) restart zebra, and (3) start other -daemons again. -.IP -Note that this option also requires -.BR \-r , -.BR \-s , -and -.B \-k -options to be specified. -.TP -.BR \-A ", " \-\-always\-all\-restart -When any daemon (i.e., not just zebra) hangs or crashes, restart all -daemons taking the following steps: (1) stop all other daemons, (2) restart -zebra, and (3) start other daemons again. -.IP -Note that this option also requires -.BR \-r , -.BR \-s , -and -.B \-k -options to be specified. -.TP -.BI \-p " filename" "\fR, \fB\-\-pid\-file " filename -Set the process identifier -.I filename -(the default value is "/var/run/quagga/watchquagga.pid"). -.TP -.BI \-b " string" "\fR, \fB\-\-blank\-string " string -When the supplied -.I string -is found in any of the command line option arguments (i.e., -.BR \-r , -.BR \-s , -.BR \-k , -or -.BR \-R ), -replace it with a space. -.IP -This is an ugly hack to circumvent problems with passing the command line -arguments containing embedded spaces. -.TP -.BR \-v ", " \-\-version -Display the version information and exit. -.TP -.BR \-h ", " \-\-help -Display the usage information and exit. -.SH SEE ALSO -.BR zebra (8), -.BR bgpd (8), -.BR isisd (8), -.BR ospfd (8), -.BR ospf6d (8), -.BR ripd (8), -.BR ripngd (8) -.PP -See the project homepage at <@PACKAGE_URL@>. -.SH AUTHORS -Copyright 2004 Andrew J. Schorr diff --git a/lib/command.c b/lib/command.c index bc816dedea..1dcb232c32 100644 --- a/lib/command.c +++ b/lib/command.c @@ -4220,7 +4220,7 @@ install_default (enum node_type node) * * terminal = 0 -- vtysh / no logging, no config control * terminal = 1 -- normal daemon - * terminal = -1 -- watchquagga / no logging, but minimal config control */ + * terminal = -1 -- watchfrr / no logging, but minimal config control */ void cmd_init (int terminal) { diff --git a/lib/log.c b/lib/log.c index b3a124fd6f..6a3ce07799 100644 --- a/lib/log.c +++ b/lib/log.c @@ -59,7 +59,7 @@ const char *zlog_proto_names[] = "ISIS", "PIM", "RFP", - "WATCHQUAGGA", + "WATCHFRR", NULL, }; diff --git a/lib/log.h b/lib/log.h index feb1e1852d..cb6379cb2a 100644 --- a/lib/log.h +++ b/lib/log.h @@ -59,7 +59,7 @@ typedef enum ZLOG_ISIS, ZLOG_PIM, ZLOG_RFP, - ZLOG_WATCHQUAGGA, + ZLOG_WATCHFRR, } zlog_proto_t; /* If maxlvl is set to ZLOG_DISABLED, then no messages will be sent diff --git a/lib/vty.c b/lib/vty.c index b25a4eeffd..5919e5220a 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -2240,7 +2240,7 @@ vtysh_read (struct thread *thread) if (ret == CMD_SUSPEND) break; - /* warning: watchquagga hardcodes this result write */ + /* warning: watchfrr hardcodes this result write */ header[3] = ret; buffer_put(vty->obuf, header, 4); diff --git a/redhat/Makefile.am b/redhat/Makefile.am index 96870689dc..c70e71fef6 100644 --- a/redhat/Makefile.am +++ b/redhat/Makefile.am @@ -3,6 +3,6 @@ EXTRA_DIST = bgpd.init isisd.init \ ospf6d.init ospfd.init ldpd.init \ quagga.logrotate quagga.pam quagga.spec \ quagga.sysconfig ripd.init ripngd.init \ - watchquagga.init pimd.init zebra.init \ + watchfrr.init pimd.init zebra.init \ README.rpm_build.md diff --git a/redhat/README.rpm_build.md b/redhat/README.rpm_build.md index 05a0bdc591..c164d740b9 100644 --- a/redhat/README.rpm_build.md +++ b/redhat/README.rpm_build.md @@ -59,7 +59,7 @@ Building your own Quagga RPM %{!?quagga_user: %global quagga_user quagga } %{!?vty_group: %global vty_group quaggavt } %{!?with_fpm: %global with_fpm 0 } - %{!?with_watchquagga: %global with_watchquagga 1 } + %{!?with_watchfrr: %global with_watchfrr 1 } 6. Build the RPM @@ -84,11 +84,11 @@ Enabling daemons after installation of the package: chkconfig bgpd on ... etc -2. If you want to run `watchquagga`, then configure `/etc/sysconfig/quagga` - and uncomment the line with the daemons for `watchquagga` to monitor, - then enable watchquagga +2. If you want to run `watchfrr`, then configure `/etc/sysconfig/quagga` + and uncomment the line with the daemons for `watchfrr` to monitor, + then enable watchfrr - chkconfig watchquagga on + chkconfig watchfrr on 3. Check your firewall / IPtables to make sure the routing protocols are allowed. @@ -113,7 +113,7 @@ Configuration is stored in `/etc/quagga/*.conf` files. systemctl enable bgpd ... etc - Note: There is no watchquagga on systemd based systems. Systemd contains + Note: There is no watchfrr on systemd based systems. Systemd contains the functionality of monitoring and restarting daemons. 2. Check your firewall / IPtables to make sure the routing protocols are diff --git a/redhat/quagga.spec.in b/redhat/quagga.spec.in index 207889d923..752b70fca5 100644 --- a/redhat/quagga.spec.in +++ b/redhat/quagga.spec.in @@ -23,7 +23,7 @@ %{!?quagga_user: %global quagga_user quagga } %{!?vty_group: %global vty_group quaggavty } %{!?with_fpm: %global with_fpm 0 } -%{!?with_watchquagga: %global with_watchquagga 1 } +%{!?with_watchfrr: %global with_watchfrr 1 } %{!?with_bgp_vnc: %global with_bgp_vnc 0 } # path defines @@ -52,13 +52,13 @@ # Check for init.d (upstart) as used in CentOS 6 or systemd (ie CentOS 7) %{expand: %%global initsystem %(if [[ `/sbin/init --version 2> /dev/null` =~ upstart ]]; then echo upstart; elif [[ `systemctl` =~ -\.mount ]]; then echo systemd; fi)} # -# If init system is systemd, then always disable watchquagga +# If init system is systemd, then always disable watchfrr # %if "%{initsystem}" == "systemd" - # Note: For systems with systemd, watchquagga will NOT be built. Systemd + # Note: For systems with systemd, watchfrr will NOT be built. Systemd # takes over the role of restarting crashed processes. Value will # be overwritten with 0 below for systemd independent on the setting here - %global with_watchquagga 1 + %global with_watchfrr 1 %endif # if FPM is enabled, then enable tcp_zebra as well @@ -80,13 +80,13 @@ %define daemon_ldpd "" %endif -%if %{with_watchquagga} -%define daemon_watchquagga watchquagga +%if %{with_watchfrr} +%define daemon_watchfrr watchfrr %else -%define daemon_watchquagga "" +%define daemon_watchfrr "" %endif -%define all_daemons %{daemon_list} %{daemon_ldpd} %{daemon_watchquagga} +%define all_daemons %{daemon_list} %{daemon_ldpd} %{daemon_watchfrr} # allow build dir to be kept %{!?keep_build: %global keep_build 0 } @@ -232,10 +232,10 @@ developing OSPF-API and quagga applications. %else --disable-fpm \ %endif -%if %{with_watchquagga} - --enable-watchquagga \ +%if %{with_watchfrr} + --enable-watchfrr \ %else - --disable-watchquagga \ + --disable-watchfrr \ %endif %if %{with_bgp_vnc} --enable-bgp-vnc \ @@ -371,9 +371,9 @@ for daemon in %{all_daemons} ; do %endif fi done -%if %{with_watchquagga} - # No config for watchquagga - this is part of /etc/sysconfig/quagga - rm -f %{_sysconfdir}/watchquagga.* +%if %{with_watchfrr} + # No config for watchfrr - this is part of /etc/sysconfig/quagga + rm -f %{_sysconfdir}/watchfrr.* %endif if [ ! -e %{_sysconfdir}/vtysh.conf ]; then @@ -397,16 +397,16 @@ if [ "$1" -ge 1 ]; then # Rename restart flags for daemons handled specially. running_zebra="$restart_zebra" restart_zebra=no - %if %{with_watchquagga} - running_watchquagga="$restart_watchquagga" - restart_watchquagga=no + %if %{with_watchfrr} + running_watchfrr="$restart_watchfrr" + restart_watchfrr=no %endif %if "%{initsystem}" == "systemd" ## ## Systemd Version ## - # No watchquagga for systemd version + # No watchfrr for systemd version # # Stop all daemons other than zebra. for daemon in %all_daemons ; do @@ -427,12 +427,12 @@ if [ "$1" -ge 1 ]; then ## ## init.d Version ## - %if %{with_watchquagga} - # Stop watchquagga first. - [ "$running_watchquagga" = yes ] && \ - /etc/rc.d/init.d/watchquagga stop >/dev/null 2>&1 + %if %{with_watchfrr} + # Stop watchfrr first. + [ "$running_watchfrr" = yes ] && \ + /etc/rc.d/init.d/watchfrr stop >/dev/null 2>&1 %endif - # Stop all daemons other than zebra and watchquagga. + # Stop all daemons other than zebra and watchfrr. for daemon in %all_daemons ; do eval restart=\$restart_${daemon} [ "$restart" = yes ] && \ @@ -441,18 +441,18 @@ if [ "$1" -ge 1 ]; then # Restart zebra. [ "$running_zebra" = yes ] && \ /etc/rc.d/init.d/zebra restart >/dev/null 2>&1 - # Start all daemons other than zebra and watchquagga. + # Start all daemons other than zebra and watchfrr. for daemon in %all_daemons ; do eval restart=\$restart_${daemon} [ "$restart" = yes ] && \ /etc/rc.d/init.d/${daemon} start >/dev/null 2>&1 done - %if %{with_watchquagga} - # Start watchquagga last. - # Avoid postun scriptlet error if watchquagga is not running. - [ "$running_watchquagga" = yes ] && \ - /etc/rc.d/init.d/watchquagga start >/dev/null 2>&1 || : - %endif + %if %{with_watchfrr} + # Start watchfrr last. + # Avoid postun scriptlet error if watchfrr is not running. + [ "$running_watchfrr" = yes ] && \ + /etc/rc.d/init.d/watchfrr start >/dev/null 2>&1 || : + %endif %endif fi @@ -513,8 +513,8 @@ rm -rf %{buildroot} %{_sbindir}/quagga-reload.py %{_sbindir}/quagga-reload.pyc %{_sbindir}/quagga-reload.pyo -%if %{with_watchquagga} - %{_sbindir}/watchquagga +%if %{with_watchfrr} + %{_sbindir}/watchfrr %endif %{_sbindir}/ripngd %{_sbindir}/ospf6d @@ -533,8 +533,8 @@ rm -rf %{buildroot} %config %{_unitdir}/quagga.service %else %config /etc/rc.d/init.d/zebra - %if %{with_watchquagga} - %config /etc/rc.d/init.d/watchquagga + %if %{with_watchfrr} + %config /etc/rc.d/init.d/watchfrr %endif %config /etc/rc.d/init.d/ripd %config /etc/rc.d/init.d/ospfd @@ -586,7 +586,7 @@ rm -rf %{buildroot} - Add conditional logic to only build tex footnotes with supported texi2html - Added pimd to files section and fix double listing of /var/lib*/quagga - Numerous fixes to unify upstart/systemd startup into same spec file -- Only allow use of watchquagga for non-systemd systems. no need with systemd +- Only allow use of watchfrr for non-systemd systems. no need with systemd * Fri Sep 4 2015 Paul Jakma - buildreq updates @@ -607,7 +607,7 @@ rm -rf %{buildroot} - daemonv6_list should contain only IPv6 daemons * Wed Dec 22 2004 Andrew J. Schorr -- watchquagga added +- watchfrr added - on upgrade, all daemons should be condrestart'ed - on removal, all daemons should be stopped diff --git a/redhat/quagga.sysconfig b/redhat/quagga.sysconfig index 0cc6acfbae..97c28c807d 100644 --- a/redhat/quagga.sysconfig +++ b/redhat/quagga.sysconfig @@ -11,7 +11,7 @@ ZEBRA_OPTS="-A 127.0.0.1" PIMD_OPTS="-A 127.0.0.1" LDPD_OPTS="-A 127.0.0.1" -# Watchquagga configuration for LSB initscripts +# Watchfrr configuration for LSB initscripts # # (Not needed with systemd: the service files are configured to automatically # restart any daemon on failure. If zebra fails, all running daemons will be diff --git a/redhat/watchquagga.init b/redhat/watchquagga.init index dda3506621..51259edc05 100644 --- a/redhat/watchquagga.init +++ b/redhat/watchquagga.init @@ -2,9 +2,9 @@ # chkconfig: 2345 17 83 ### BEGIN INIT INFO -# Provides: watchquagga -# Short-Description: Quagga watchdog -# Description: Quagga watchdog for use with Zebra +# Provides: watchfrr +# Short-Description: Frr watchdog +# Description: Frr watchdog for use with Zebra ### END INIT INFO # source function library @@ -13,13 +13,13 @@ # Get network config . /etc/sysconfig/network -# quagga command line options +# frr command line options . /etc/sysconfig/quagga RETVAL=0 -PROG="watchquagga" -cmd=watchquagga -LOCK_FILE=/var/lock/subsys/watchquagga +PROG="watchfrr" +cmd=watchfrr +LOCK_FILE=/var/lock/subsys/watchfrr case "$1" in start) diff --git a/solaris/prototype.daemons.in b/solaris/prototype.daemons.in index ce65d5e350..8a906c9d0a 100644 --- a/solaris/prototype.daemons.in +++ b/solaris/prototype.daemons.in @@ -8,7 +8,7 @@ f none @sbindir@/ripd=$DESTDIR/@sbindir@/ripd 0755 root bin f none @sbindir@/ripngd=$DESTDIR/@sbindir@/ripngd 0755 root bin f none @sbindir@/ospfd=$DESTDIR/@sbindir@/ospfd 0755 root bin f none @sbindir@/ospf6d=$DESTDIR/@sbindir@/ospf6d 0755 root bin -f none @sbindir@/watchquagga=$DESTDIR/@sbindir@/watchquagga 0755 root bin +f none @sbindir@/watchfrr=$DESTDIR/@sbindir@/watchfrr 0755 root bin d none @sysconfdir@=$DESTDIR/@sysconfdir@ 0711 @enable_user@ @enable_group@ f none @sysconfdir@/zebra.conf.sample=$DESTDIR/@sysconfdir@/zebra.conf.sample 0644 root bin f none @sysconfdir@/bgpd.conf.sample=$DESTDIR/@sysconfdir@/bgpd.conf.sample 0644 root bin diff --git a/tools/quagga b/tools/quagga index e8595d7877..87f1ce5c5e 100755 --- a/tools/quagga +++ b/tools/quagga @@ -20,7 +20,7 @@ V_PATH=/var/run/quagga # Local Daemon selection may be done by using /etc/quagga/daemons. # See /usr/share/doc/quagga/README.Debian.gz for further information. -# Keep zebra first and do not list watchquagga! +# Keep zebra first and do not list watchfrr! DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd babeld pimd" MAX_INSTANCES=5 RELOAD_SCRIPT=/usr/lib/quagga/quagga-reload.py @@ -79,7 +79,7 @@ check_daemon() # vtysh_enable has no config file nor binary so skip check. # (Not sure why vtysh_enable is in this list but does not hurt) - if [ $1 != "watchquagga" -a $1 != "vtysh_enable" ]; then + if [ $1 != "watchfrr" -a $1 != "vtysh_enable" ]; then # check for daemon binary if [ ! -x "$D_PATH/$1" ]; then return 1; fi @@ -102,29 +102,29 @@ check_daemon() start() { ulimit -n $MAX_FDS - if [ "$1" = "watchquagga" ]; then + if [ "$1" = "watchfrr" ]; then - # We may need to restart watchquagga if new daemons are added and/or + # We may need to restart watchfrr if new daemons are added and/or # removed if started "$1" ; then - stop watchquagga + stop watchfrr else - # Echo only once. watchquagga is printed in the stop above + # Echo only once. watchfrr is printed in the stop above echo -n " $1" fi - if [ -e /var/run/quagga/watchquagga.started ] ; then - rm /var/run/quagga/watchquagga.started + if [ -e /var/run/quagga/watchfrr.started ] ; then + rm /var/run/quagga/watchfrr.started fi ${SSD} \ --start \ --pidfile=`pidfile $1` \ --exec "$D_PATH/$1" \ -- \ - "${watchquagga_options[@]}" + "${watchfrr_options[@]}" for i in `seq 1 10`; do - if [ -e /var/run/quagga/watchquagga.started ] ; then + if [ -e /var/run/quagga/watchfrr.started ] ; then break else sleep 1 @@ -203,7 +203,7 @@ stop() # Converts values from /etc/quagga/daemons to all-numeric values. convert_daemon_prios() { - for name in $DAEMONS zebra vtysh_enable watchquagga_enable; do + for name in $DAEMONS zebra vtysh_enable watchfrr_enable; do # First, assign the value set by the user to $value eval value=\${${name}:0:3} @@ -224,8 +224,8 @@ convert_daemon_prios() done } -# Starts watchquagga for all wanted daemons. -start_watchquagga() +# Starts watchfrr for all wanted daemons. +start_watchfrr() { local daemon_name local daemon_prio @@ -233,14 +233,14 @@ start_watchquagga() local daemon_inst # Start the monitor daemon only if desired. - if [ 0 -eq "$watchquagga_enable" ]; then + if [ 0 -eq "$watchfrr_enable" ]; then return fi # Check variable type - if ! declare -p watchquagga_options | grep -q '^declare \-a'; then + if ! declare -p watchfrr_options | grep -q '^declare \-a'; then echo - echo "ERROR: The variable watchquagga_options from /etc/quagga/debian.cnf must be a BASH array!" + echo "ERROR: The variable watchfrr_options from /etc/quagga/debian.cnf must be a BASH array!" echo "ERROR: Please convert config file and restart!" exit 1 fi @@ -256,13 +256,13 @@ start_watchquagga() eval "inst_disable=\${${daemon_name}_${inst}}" if [ -z ${inst_disable} ] || [ ${inst_disable} != 0 ]; then if check_daemon $daemon_name $inst; then - watchquagga_options+=("${daemon_name}-${inst}") + watchfrr_options+=("${daemon_name}-${inst}") fi fi done else if check_daemon $daemon_name; then - watchquagga_options+=($daemon_name) + watchfrr_options+=($daemon_name) fi fi found_one=1 @@ -272,16 +272,16 @@ start_watchquagga() # Start if at least one daemon is activated. if [ $found_one -eq 1 ]; then echo -n "Starting Quagga monitor daemon:" - start watchquagga + start watchfrr echo "." fi } -# Stopps watchquagga. -stop_watchquagga() +# Stopps watchfrr. +stop_watchfrr() { echo -n "Stopping Quagga monitor daemon:" - stop watchquagga + stop watchfrr echo "." } @@ -509,10 +509,10 @@ case "$1" in # Start all daemons cd $C_PATH/ - if [ "$2" != "watchquagga" ]; then + if [ "$2" != "watchfrr" ]; then start_prio 10 $dmn fi - start_watchquagga + start_watchfrr vtysh_b ;; @@ -525,8 +525,8 @@ case "$1" in stop|0) # Stop all daemons at level '0' or 'stop' - stop_watchquagga - if [ "$dmn" != "watchquagga" ]; then + stop_watchfrr + if [ "$dmn" != "watchfrr" ]; then [ -n "${dmn}" ] && eval "${dmn/-/_}=0" stop_prio 0 $dmn fi @@ -536,7 +536,7 @@ case "$1" in ip route flush proto zebra else [ -n "$dmn" ] && eval "${dmn/-/_}=0" - start_watchquagga + start_watchfrr fi ;; diff --git a/vtysh/Makefile.am b/vtysh/Makefile.am index 0ff2d738f0..090382b99b 100644 --- a/vtysh/Makefile.am +++ b/vtysh/Makefile.am @@ -86,7 +86,7 @@ vtysh_cmd_FILES = $(vtysh_scan) \ $(top_srcdir)/zebra/zebra_fpm.c \ $(top_srcdir)/zebra/zebra_ptm.c \ $(top_srcdir)/zebra/zebra_mpls_vty.c \ - $(top_srcdir)/watchquagga/watchquagga_vty.c \ + $(top_srcdir)/watchfrr/watchfrr_vty.c \ $(BGP_VNC_RFAPI_SRC) $(BGP_VNC_RFP_SRC) vtysh_cmd.c: $(vtysh_cmd_FILES) extract.pl diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index a4f108e447..6d6fe61306 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -73,7 +73,7 @@ struct vtysh_client vtysh_client[] = { .fd = -1, .name = "bgpd", .flag = VTYSH_BGPD, .path = BGP_VTYSH_PATH, .next = NULL}, { .fd = -1, .name = "isisd", .flag = VTYSH_ISISD, .path = ISIS_VTYSH_PATH, .next = NULL}, { .fd = -1, .name = "pimd", .flag = VTYSH_PIMD, .path = PIM_VTYSH_PATH, .next = NULL}, - { .fd = -1, .name = "watchquagga", .flag = VTYSH_WATCHQUAGGA, .path = WATCHQUAGGA_VTYSH_PATH, .next = NULL}, + { .fd = -1, .name = "watchfrr", .flag = VTYSH_WATCHFRR, .path = WATCHFRR_VTYSH_PATH, .next = NULL}, }; enum vtysh_write_integrated vtysh_write_integrated = WRITE_INTEGRATED_UNSPECIFIED; @@ -2592,7 +2592,7 @@ DEFUN (vtysh_write_memory, { ret = CMD_WARNING; for (i = 0; i < array_size(vtysh_client); i++) - if (vtysh_client[i].flag == VTYSH_WATCHQUAGGA) + if (vtysh_client[i].flag == VTYSH_WATCHFRR) break; if (i < array_size(vtysh_client) && vtysh_client[i].fd != -1) ret = vtysh_client_execute (&vtysh_client[i], "write integrated", stdout); @@ -2600,7 +2600,7 @@ DEFUN (vtysh_write_memory, if (ret != CMD_SUCCESS) { printf("\nWarning: attempting direct configuration write without " - "watchquagga.\nFile permissions and ownership may be " + "watchfrr.\nFile permissions and ownership may be " "incorrect, or write may fail.\n\n"); ret = vtysh_write_config_integrated(); } diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h index dade049ad7..46ed001919 100644 --- a/vtysh/vtysh.h +++ b/vtysh/vtysh.h @@ -34,11 +34,11 @@ DECLARE_MGROUP(MVTYSH) #define VTYSH_ISISD 0x40 #define VTYSH_PIMD 0x100 #define VTYSH_LDPD 0x200 -#define VTYSH_WATCHQUAGGA 0x400 +#define VTYSH_WATCHFRR 0x400 /* commands in REALLYALL are crucial to correct vtysh operation */ #define VTYSH_REALLYALL ~0U -/* watchquagga is not in ALL since library CLI functions should not be +/* watchfrr is not in ALL since library CLI functions should not be * run on it (logging & co. should stay in a fixed/frozen config, and * things like prefix lists are not even initialised) */ #define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD diff --git a/watchfrr/.gitignore b/watchfrr/.gitignore new file mode 100644 index 0000000000..d3b038feb5 --- /dev/null +++ b/watchfrr/.gitignore @@ -0,0 +1,16 @@ +Makefile +Makefile.in +*.o +watchfrr +tags +TAGS +.deps +.nfs* +*.lo +*.la +*.libs +.arch-inventory +.arch-ids +*~ +*.loT + diff --git a/watchfrr/Makefile.am b/watchfrr/Makefile.am new file mode 100644 index 0000000000..51851b0165 --- /dev/null +++ b/watchfrr/Makefile.am @@ -0,0 +1,13 @@ +## Process this file with Automake to create Makefile.in + +AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib +DEFS = @DEFS@ -DSTATEDIR=\"$(localstatedir)/\" + +AM_CFLAGS = $(WERROR) + +sbin_PROGRAMS = watchfrr + +noinst_HEADERS = watchfrr.h + +watchfrr_SOURCES = watchfrr.c watchfrr_vty.c +watchfrr_LDADD = ../lib/libzebra.la @LIBCAP@ diff --git a/watchfrr/watchfrr.c b/watchfrr/watchfrr.c new file mode 100644 index 0000000000..903e2bbe91 --- /dev/null +++ b/watchfrr/watchfrr.c @@ -0,0 +1,1439 @@ +/* + Monitor status of frr daemons and restart if necessary. + + Copyright (C) 2004 Andrew J. Schorr + + 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; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include "command.h" +#include "memory_vty.h" + +#include +#include +#include +#include +#include + +#include "watchfrr.h" + +#ifndef MIN +#define MIN(X,Y) (((X) <= (Y)) ? (X) : (Y)) +#endif + +/* Macros to help randomize timers. */ +#define JITTER(X) ((random() % ((X)+1))-((X)/2)) +#define FUZZY(X) ((X)+JITTER((X)/20)) + +#define DEFAULT_PERIOD 5 +#define DEFAULT_TIMEOUT 10 +#define DEFAULT_RESTART_TIMEOUT 20 +#define DEFAULT_LOGLEVEL LOG_INFO +#define DEFAULT_MIN_RESTART 60 +#define DEFAULT_MAX_RESTART 600 +#ifdef PATH_WATCHFRR_PID +#define DEFAULT_PIDFILE PATH_WATCHFRR_PID +#else +#define DEFAULT_PIDFILE STATEDIR "/watchfrr.pid" +#endif +#ifdef DAEMON_VTY_DIR +#define VTYDIR DAEMON_VTY_DIR +#else +#define VTYDIR STATEDIR +#endif + +#define PING_TOKEN "PING" + +/* Needs to be global, referenced somewhere inside libzebra. */ +struct thread_master *master; + +typedef enum +{ + MODE_MONITOR = 0, + MODE_GLOBAL_RESTART, + MODE_SEPARATE_RESTART, + MODE_PHASED_ZEBRA_RESTART, + MODE_PHASED_ALL_RESTART +} watch_mode_t; + +static const char *mode_str[] = +{ + "monitor", + "global restart", + "individual daemon restart", + "phased zebra restart", + "phased global restart for any failure", +}; + +typedef enum +{ + PHASE_NONE = 0, + PHASE_STOPS_PENDING, + PHASE_WAITING_DOWN, + PHASE_ZEBRA_RESTART_PENDING, + PHASE_WAITING_ZEBRA_UP +} restart_phase_t; + +static const char *phase_str[] = +{ + "None", + "Stop jobs running", + "Waiting for other daemons to come down", + "Zebra restart job running", + "Waiting for zebra to come up", + "Start jobs running", +}; + +#define PHASE_TIMEOUT (3*gs.restart_timeout) + +struct restart_info +{ + const char *name; + const char *what; + pid_t pid; + struct timeval time; + long interval; + struct thread *t_kill; + int kills; +}; + +static struct global_state +{ + watch_mode_t mode; + restart_phase_t phase; + struct thread *t_phase_hanging; + const char *vtydir; + long period; + long timeout; + long restart_timeout; + long min_restart_interval; + long max_restart_interval; + int do_ping; + struct daemon *daemons; + const char *restart_command; + const char *start_command; + const char *stop_command; + struct restart_info restart; + int unresponsive_restart; + int loglevel; + struct daemon *special; /* points to zebra when doing phased restart */ + int numdaemons; + int numpids; + int numdown; /* # of daemons that are not UP or UNRESPONSIVE */ +} gs = { + .mode = MODE_MONITOR, + .phase = PHASE_NONE, + .vtydir = VTYDIR, + .period = 1000*DEFAULT_PERIOD, + .timeout = DEFAULT_TIMEOUT, + .restart_timeout = DEFAULT_RESTART_TIMEOUT, + .loglevel = DEFAULT_LOGLEVEL, + .min_restart_interval = DEFAULT_MIN_RESTART, + .max_restart_interval = DEFAULT_MAX_RESTART, + .do_ping = 1, +}; + +typedef enum +{ + DAEMON_INIT, + DAEMON_DOWN, + DAEMON_CONNECTING, + DAEMON_UP, + DAEMON_UNRESPONSIVE +} daemon_state_t; + +#define IS_UP(DMN) \ + (((DMN)->state == DAEMON_UP) || ((DMN)->state == DAEMON_UNRESPONSIVE)) + +static const char *state_str[] = +{ + "Init", + "Down", + "Connecting", + "Up", + "Unresponsive", +}; + +struct daemon { + const char *name; + daemon_state_t state; + int fd; + struct timeval echo_sent; + u_int connect_tries; + struct thread *t_wakeup; + struct thread *t_read; + struct thread *t_write; + struct daemon *next; + struct restart_info restart; +}; + +static const struct option longopts[] = +{ + { "daemon", no_argument, NULL, 'd'}, + { "statedir", required_argument, NULL, 'S'}, + { "no-echo", no_argument, NULL, 'e'}, + { "loglevel", required_argument, NULL, 'l'}, + { "interval", required_argument, NULL, 'i'}, + { "timeout", required_argument, NULL, 't'}, + { "restart-timeout", required_argument, NULL, 'T'}, + { "restart", required_argument, NULL, 'r'}, + { "start-command", required_argument, NULL, 's'}, + { "kill-command", required_argument, NULL, 'k'}, + { "restart-all", required_argument, NULL, 'R'}, + { "all-restart", no_argument, NULL, 'a'}, + { "always-all-restart", no_argument, NULL, 'A'}, + { "unresponsive-restart", no_argument, NULL, 'z'}, + { "min-restart-interval", required_argument, NULL, 'm'}, + { "max-restart-interval", required_argument, NULL, 'M'}, + { "pid-file", required_argument, NULL, 'p'}, + { "blank-string", required_argument, NULL, 'b'}, + { "help", no_argument, NULL, 'h'}, + { "version", no_argument, NULL, 'v'}, + { NULL, 0, NULL, 0 } +}; + +static int try_connect(struct daemon *dmn); +static int wakeup_send_echo(struct thread *t_wakeup); +static void try_restart(struct daemon *dmn); +static void phase_check(void); + +static int +usage(const char *progname, int status) +{ + if (status != 0) + fprintf(stderr, "Try `%s --help' for more information.\n", progname); + else + { + printf("Usage : %s [OPTION...] ...\n\n\ +Watchdog program to monitor status of frr daemons and try to restart\n\ +them if they are down or unresponsive. It determines whether a daemon is\n\ +up based on whether it can connect to the daemon's vty unix stream socket.\n\ +It then repeatedly sends echo commands over that socket to determine whether\n\ +the daemon is responsive. If the daemon crashes, we will receive an EOF\n\ +on the socket connection and know immediately that the daemon is down.\n\n\ +The daemons to be monitored should be listed on the command line.\n\n\ +This program can run in one of 5 modes:\n\n\ +0. Mode: %s.\n\ + Just monitor and report on status changes. Example:\n\ + %s -d zebra ospfd bgpd\n\n\ +1. Mode: %s.\n\ + Whenever any daemon hangs or crashes, use the given command to restart\n\ + them all. Example:\n\ + %s -dz \\\n\ + -R '/sbin/service zebra restart; /sbin/service ospfd restart' \\\n\ + zebra ospfd\n\n\ +2. Mode: %s.\n\ + When any single daemon hangs or crashes, restart only the daemon that's\n\ + in trouble using the supplied restart command. Example:\n\ + %s -dz -r '/sbin/service %%s restart' zebra ospfd bgpd\n\n\ +3. Mode: %s.\n\ + The same as the previous mode, except that there is special treatment when\n\ + the zebra daemon is in trouble. In that case, a phased restart approach\n\ + is used: 1. stop all other daemons; 2. restart zebra; 3. start the other\n\ + daemons. Example:\n\ + %s -adz -r '/sbin/service %%s restart' \\\n\ + -s '/sbin/service %%s start' \\\n\ + -k '/sbin/service %%s stop' zebra ospfd bgpd\n\n\ +4. Mode: %s.\n\ + This is the same as the previous mode, except that the phased restart\n\ + procedure is used whenever any of the daemons hangs or crashes. Example:\n\ + %s -Adz -r '/sbin/service %%s restart' \\\n\ + -s '/sbin/service %%s start' \\\n\ + -k '/sbin/service %%s stop' zebra ospfd bgpd\n\n\ +As of this writing, it is believed that mode 2 [%s]\n\ +is not safe, and mode 3 [%s] may not be safe with some of the\n\ +routing daemons.\n\n\ +In order to avoid attempting to restart the daemons in a fast loop,\n\ +the -m and -M options allow you to control the minimum delay between\n\ +restart commands. The minimum restart delay is recalculated each time\n\ +a restart is attempted: if the time since the last restart attempt exceeds\n\ +twice the -M value, then the restart delay is set to the -m value.\n\ +Otherwise, the interval is doubled (but capped at the -M value).\n\n", + progname,mode_str[0],progname,mode_str[1],progname,mode_str[2], + progname,mode_str[3],progname,mode_str[4],progname,mode_str[2], + mode_str[3]); + + printf("Options:\n\ +-d, --daemon Run in daemon mode. In this mode, error messages are sent\n\ + to syslog instead of stdout.\n\ +-S, --statedir Set the vty socket directory (default is %s)\n\ +-e, --no-echo Do not ping the daemons to test responsiveness (this\n\ + option is necessary if the daemons do not support the\n\ + echo command)\n\ +-l, --loglevel Set the logging level (default is %d).\n\ + The value should range from %d (LOG_EMERG) to %d (LOG_DEBUG),\n\ + but it can be set higher than %d if extra-verbose debugging\n\ + messages are desired.\n\ +-m, --min-restart-interval\n\ + Set the minimum seconds to wait between invocations of daemon\n\ + restart commands (default is %d).\n\ +-M, --max-restart-interval\n\ + Set the maximum seconds to wait between invocations of daemon\n\ + restart commands (default is %d).\n\ +-i, --interval Set the status polling interval in seconds (default is %d)\n\ +-t, --timeout Set the unresponsiveness timeout in seconds (default is %d)\n\ +-T, --restart-timeout\n\ + Set the restart (kill) timeout in seconds (default is %d).\n\ + If any background jobs are still running after this much\n\ + time has elapsed, they will be killed.\n\ +-r, --restart Supply a Bourne shell command to use to restart a single\n\ + daemon. The command string should include '%%s' where the\n\ + name of the daemon should be substituted.\n\ + Note that -r and -R are incompatible.\n\ +-s, --start-command\n\ + Supply a Bourne shell to command to use to start a single\n\ + daemon. The command string should include '%%s' where the\n\ + name of the daemon should be substituted.\n\ +-k, --kill-command\n\ + Supply a Bourne shell to command to use to stop a single\n\ + daemon. The command string should include '%%s' where the\n\ + name of the daemon should be substituted.\n\ +-R, --restart-all\n\ + When one or more daemons is down, try to restart everything\n\ + using the Bourne shell command supplied as the argument.\n\ + Note that -r and -R are incompatible.\n\ +-z, --unresponsive-restart\n\ + When a daemon is unresponsive, treat it as being down for\n\ + restart purposes.\n\ +-a, --all-restart\n\ + When zebra hangs or crashes, restart all daemons using\n\ + this phased approach: 1. stop all other daemons; 2. restart\n\ + zebra; 3. start other daemons. Requires -r, -s, and -k.\n\ +-A, --always-all-restart\n\ + When any daemon (not just zebra) hangs or crashes, use the\n\ + same phased restart mechanism described above for -a.\n\ + Requires -r, -s, and -k.\n\ +-p, --pid-file Set process identifier file name\n\ + (default is %s).\n\ +-b, --blank-string\n\ + When the supplied argument string is found in any of the\n\ + various shell command arguments (-r, -s, -k, or -R), replace\n\ + it with a space. This is an ugly hack to circumvent problems\n\ + passing command-line arguments with embedded spaces.\n\ +-v, --version Print program version\n\ +-h, --help Display this help and exit\n", + VTYDIR,DEFAULT_LOGLEVEL,LOG_EMERG,LOG_DEBUG,LOG_DEBUG, + DEFAULT_MIN_RESTART,DEFAULT_MAX_RESTART, + DEFAULT_PERIOD,DEFAULT_TIMEOUT,DEFAULT_RESTART_TIMEOUT, + DEFAULT_PIDFILE); + } + + return status; +} + +static pid_t +run_background(char *shell_cmd) +{ + pid_t child; + + switch (child = fork()) + { + case -1: + zlog_err("fork failed, cannot run command [%s]: %s", + shell_cmd,safe_strerror(errno)); + return -1; + case 0: + /* Child process. */ + /* Use separate process group so child processes can be killed easily. */ + if (setpgid(0,0) < 0) + zlog_warn("warning: setpgid(0,0) failed: %s",safe_strerror(errno)); + { + char shell[] = "sh"; + char dashc[] = "-c"; + char * const argv[4] = { shell, dashc, shell_cmd, NULL}; + execv("/bin/sh", argv); + zlog_err("execv(/bin/sh -c '%s') failed: %s", + shell_cmd,safe_strerror(errno)); + _exit(127); + } + default: + /* Parent process: we will reap the child later. */ + zlog_err("Forked background command [pid %d]: %s",(int)child,shell_cmd); + return child; + } +} + +static struct timeval * +time_elapsed(struct timeval *result, const struct timeval *start_time) +{ + gettimeofday(result,NULL); + result->tv_sec -= start_time->tv_sec; + result->tv_usec -= start_time->tv_usec; + while (result->tv_usec < 0) + { + result->tv_usec += 1000000L; + result->tv_sec--; + } + return result; +} + +static int +restart_kill(struct thread *t_kill) +{ + struct restart_info *restart = THREAD_ARG(t_kill); + struct timeval delay; + + time_elapsed(&delay,&restart->time); + zlog_warn("Warning: %s %s child process %d still running after " + "%ld seconds, sending signal %d", + restart->what,restart->name,(int)restart->pid, (long)delay.tv_sec, + (restart->kills ? SIGKILL : SIGTERM)); + kill(-restart->pid,(restart->kills ? SIGKILL : SIGTERM)); + restart->kills++; + restart->t_kill = thread_add_timer(master,restart_kill,restart, + gs.restart_timeout); + return 0; +} + +static struct restart_info * +find_child(pid_t child) +{ + if (gs.mode == MODE_GLOBAL_RESTART) + { + if (gs.restart.pid == child) + return &gs.restart; + } + else + { + struct daemon *dmn; + for (dmn = gs.daemons; dmn; dmn = dmn->next) + { + if (dmn->restart.pid == child) + return &dmn->restart; + } + } + return NULL; +} + +static void +sigchild(void) +{ + pid_t child; + int status; + const char *name; + const char *what; + struct restart_info *restart; + + switch (child = waitpid(-1,&status,WNOHANG)) + { + case -1: + zlog_err("waitpid failed: %s",safe_strerror(errno)); + return; + case 0: + zlog_warn("SIGCHLD received, but waitpid did not reap a child"); + return; + } + + if (child == integrated_write_pid) + { + integrated_write_sigchld(status); + return; + } + + if ((restart = find_child(child)) != NULL) + { + name = restart->name; + what = restart->what; + restart->pid = 0; + gs.numpids--; + thread_cancel(restart->t_kill); + restart->t_kill = NULL; + /* Update restart time to reflect the time the command completed. */ + gettimeofday(&restart->time,NULL); + } + else + { + zlog_err("waitpid returned status for an unknown child process %d", + (int)child); + name = "(unknown)"; + what = "background"; + } + if (WIFSTOPPED(status)) + zlog_warn("warning: %s %s process %d is stopped", + what,name,(int)child); + else if (WIFSIGNALED(status)) + zlog_warn("%s %s process %d terminated due to signal %d", + what,name,(int)child,WTERMSIG(status)); + else if (WIFEXITED(status)) + { + if (WEXITSTATUS(status) != 0) + zlog_warn("%s %s process %d exited with non-zero status %d", + what,name,(int)child,WEXITSTATUS(status)); + else + zlog_debug("%s %s process %d exited normally",what,name,(int)child); + } + else + zlog_err("cannot interpret %s %s process %d wait status 0x%x", + what,name,(int)child,status); + phase_check(); +} + +static int +run_job(struct restart_info *restart, const char *cmdtype, const char *command, + int force, int update_interval) +{ + struct timeval delay; + + if (gs.loglevel > LOG_DEBUG+1) + zlog_debug("attempting to %s %s",cmdtype,restart->name); + + if (restart->pid) + { + if (gs.loglevel > LOG_DEBUG+1) + zlog_debug("cannot %s %s, previous pid %d still running", + cmdtype,restart->name,(int)restart->pid); + return -1; + } + + /* Note: time_elapsed test must come before the force test, since we need + to make sure that delay is initialized for use below in updating the + restart interval. */ + if ((time_elapsed(&delay,&restart->time)->tv_sec < restart->interval) && + !force) + { + if (gs.loglevel > LOG_DEBUG+1) + zlog_debug("postponing %s %s: " + "elapsed time %ld < retry interval %ld", + cmdtype,restart->name,(long)delay.tv_sec,restart->interval); + return -1; + } + + gettimeofday(&restart->time,NULL); + restart->kills = 0; + { + char cmd[strlen(command)+strlen(restart->name)+1]; + snprintf(cmd,sizeof(cmd),command,restart->name); + if ((restart->pid = run_background(cmd)) > 0) + { + restart->t_kill = thread_add_timer(master,restart_kill,restart, + gs.restart_timeout); + restart->what = cmdtype; + gs.numpids++; + } + else + restart->pid = 0; + } + + /* Calculate the new restart interval. */ + if (update_interval) + { + if (delay.tv_sec > 2*gs.max_restart_interval) + restart->interval = gs.min_restart_interval; + else if ((restart->interval *= 2) > gs.max_restart_interval) + restart->interval = gs.max_restart_interval; + if (gs.loglevel > LOG_DEBUG+1) + zlog_debug("restart %s interval is now %ld", + restart->name,restart->interval); + } + return restart->pid; +} + +#define SET_READ_HANDLER(DMN) \ + (DMN)->t_read = thread_add_read(master,handle_read,(DMN),(DMN)->fd) + +#define SET_WAKEUP_DOWN(DMN) \ + (DMN)->t_wakeup = thread_add_timer_msec(master,wakeup_down,(DMN), \ + FUZZY(gs.period)) + +#define SET_WAKEUP_UNRESPONSIVE(DMN) \ + (DMN)->t_wakeup = thread_add_timer_msec(master,wakeup_unresponsive,(DMN), \ + FUZZY(gs.period)) + +#define SET_WAKEUP_ECHO(DMN) \ + (DMN)->t_wakeup = thread_add_timer_msec(master,wakeup_send_echo,(DMN), \ + FUZZY(gs.period)) + +static int +wakeup_down(struct thread *t_wakeup) +{ + struct daemon *dmn = THREAD_ARG(t_wakeup); + + dmn->t_wakeup = NULL; + if (try_connect(dmn) < 0) + SET_WAKEUP_DOWN(dmn); + if ((dmn->connect_tries > 1) && (dmn->state != DAEMON_UP)) + try_restart(dmn); + return 0; +} + +static int +wakeup_init(struct thread *t_wakeup) +{ + struct daemon *dmn = THREAD_ARG(t_wakeup); + + dmn->t_wakeup = NULL; + if (try_connect(dmn) < 0) + { + SET_WAKEUP_DOWN(dmn); + zlog_err("%s state -> down : initial connection attempt failed", + dmn->name); + dmn->state = DAEMON_DOWN; + } + return 0; +} + +static void +daemon_down(struct daemon *dmn, const char *why) +{ + if (IS_UP(dmn) || (dmn->state == DAEMON_INIT)) + zlog_err("%s state -> down : %s",dmn->name,why); + else if (gs.loglevel > LOG_DEBUG) + zlog_debug("%s still down : %s",dmn->name,why); + if (IS_UP(dmn)) + gs.numdown++; + dmn->state = DAEMON_DOWN; + if (dmn->fd >= 0) + { + close(dmn->fd); + dmn->fd = -1; + } + THREAD_OFF(dmn->t_read); + THREAD_OFF(dmn->t_write); + THREAD_OFF(dmn->t_wakeup); + if (try_connect(dmn) < 0) + SET_WAKEUP_DOWN(dmn); + phase_check(); +} + +static int +handle_read(struct thread *t_read) +{ + struct daemon *dmn = THREAD_ARG(t_read); + static const char resp[sizeof(PING_TOKEN)+4] = PING_TOKEN "\n"; + char buf[sizeof(resp)+100]; + ssize_t rc; + struct timeval delay; + + dmn->t_read = NULL; + if ((rc = read(dmn->fd,buf,sizeof(buf))) < 0) + { + char why[100]; + + if (ERRNO_IO_RETRY(errno)) + { + /* Pretend it never happened. */ + SET_READ_HANDLER(dmn); + return 0; + } + snprintf(why,sizeof(why),"unexpected read error: %s", + safe_strerror(errno)); + daemon_down(dmn,why); + return 0; + } + if (rc == 0) + { + daemon_down(dmn,"read returned EOF"); + return 0; + } + if (!dmn->echo_sent.tv_sec) + { + char why[sizeof(buf)+100]; + snprintf(why,sizeof(why),"unexpected read returns %d bytes: %.*s", + (int)rc,(int)rc,buf); + daemon_down(dmn,why); + return 0; + } + + /* We are expecting an echo response: is there any chance that the + response would not be returned entirely in the first read? That + seems inconceivable... */ + if ((rc != sizeof(resp)) || memcmp(buf,resp,sizeof(resp))) + { + char why[100+sizeof(buf)]; + snprintf(why,sizeof(why),"read returned bad echo response of %d bytes " + "(expecting %u): %.*s", + (int)rc,(u_int)sizeof(resp),(int)rc,buf); + daemon_down(dmn,why); + return 0; + } + + time_elapsed(&delay,&dmn->echo_sent); + dmn->echo_sent.tv_sec = 0; + if (dmn->state == DAEMON_UNRESPONSIVE) + { + if (delay.tv_sec < gs.timeout) + { + dmn->state = DAEMON_UP; + zlog_warn("%s state -> up : echo response received after %ld.%06ld " + "seconds", dmn->name, + (long)delay.tv_sec, (long)delay.tv_usec); + } + else + zlog_warn("%s: slow echo response finally received after %ld.%06ld " + "seconds", dmn->name, + (long)delay.tv_sec, (long)delay.tv_usec); + } + else if (gs.loglevel > LOG_DEBUG+1) + zlog_debug("%s: echo response received after %ld.%06ld seconds", + dmn->name, (long)delay.tv_sec, (long)delay.tv_usec); + + SET_READ_HANDLER(dmn); + if (dmn->t_wakeup) + thread_cancel(dmn->t_wakeup); + SET_WAKEUP_ECHO(dmn); + + return 0; +} + +/* + * Wait till we notice that all daemons are ready before + * we send we are ready to systemd + */ +static void +daemon_send_ready (void) +{ + static int sent = 0; + if (!sent && gs.numdown == 0) + { +#if defined (HAVE_CUMULUS) + FILE *fp; + + fp = fopen(DAEMON_VTY_DIR "/watchfrr.started", "w"); + fclose(fp); +#endif + zlog_notice ("Watchfrr: Notifying Systemd we are up and running"); + systemd_send_started(master, 0); + sent = 1; + } +} + +static void +daemon_up(struct daemon *dmn, const char *why) +{ + dmn->state = DAEMON_UP; + gs.numdown--; + dmn->connect_tries = 0; + zlog_notice("%s state -> up : %s",dmn->name,why); + daemon_send_ready(); + if (gs.do_ping) + SET_WAKEUP_ECHO(dmn); + phase_check(); +} + +static int +check_connect(struct thread *t_write) +{ + struct daemon *dmn = THREAD_ARG(t_write); + int sockerr; + socklen_t reslen = sizeof(sockerr); + + dmn->t_write = NULL; + if (getsockopt(dmn->fd,SOL_SOCKET,SO_ERROR,(char *)&sockerr,&reslen) < 0) + { + zlog_warn("%s: check_connect: getsockopt failed: %s", + dmn->name,safe_strerror(errno)); + daemon_down(dmn,"getsockopt failed checking connection success"); + return 0; + } + if ((reslen == sizeof(sockerr)) && sockerr) + { + char why[100]; + snprintf(why,sizeof(why), + "getsockopt reports that connection attempt failed: %s", + safe_strerror(sockerr)); + daemon_down(dmn,why); + return 0; + } + + daemon_up(dmn,"delayed connect succeeded"); + return 0; +} + +static int +wakeup_connect_hanging(struct thread *t_wakeup) +{ + struct daemon *dmn = THREAD_ARG(t_wakeup); + char why[100]; + + dmn->t_wakeup = NULL; + snprintf(why,sizeof(why),"connection attempt timed out after %ld seconds", + gs.timeout); + daemon_down(dmn,why); + return 0; +} + +/* Making connection to protocol daemon. */ +static int +try_connect(struct daemon *dmn) +{ + int sock; + struct sockaddr_un addr; + socklen_t len; + + if (gs.loglevel > LOG_DEBUG+1) + zlog_debug("%s: attempting to connect",dmn->name); + dmn->connect_tries++; + + memset (&addr, 0, sizeof (struct sockaddr_un)); + addr.sun_family = AF_UNIX; + snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s.vty", + gs.vtydir,dmn->name); +#ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN + len = addr.sun_len = SUN_LEN(&addr); +#else + len = sizeof (addr.sun_family) + strlen (addr.sun_path); +#endif /* HAVE_STRUCT_SOCKADDR_UN_SUN_LEN */ + + /* Quick check to see if we might succeed before we go to the trouble + of creating a socket. */ + if (access(addr.sun_path, W_OK) < 0) + { + if (errno != ENOENT) + zlog_err("%s: access to socket %s denied: %s", + dmn->name,addr.sun_path,safe_strerror(errno)); + return -1; + } + + if ((sock = socket (AF_UNIX, SOCK_STREAM, 0)) < 0) + { + zlog_err("%s(%s): cannot make socket: %s", + __func__,addr.sun_path, safe_strerror(errno)); + return -1; + } + + if (set_nonblocking(sock) < 0 || set_cloexec(sock) < 0) + { + zlog_err("%s(%s): set_nonblocking/cloexec(%d) failed", + __func__, addr.sun_path, sock); + close(sock); + return -1; + } + + if (connect (sock, (struct sockaddr *) &addr, len) < 0) + { + if ((errno != EINPROGRESS) && (errno != EWOULDBLOCK)) + { + if (gs.loglevel > LOG_DEBUG) + zlog_debug("%s(%s): connect failed: %s", + __func__,addr.sun_path, safe_strerror(errno)); + close (sock); + return -1; + } + if (gs.loglevel > LOG_DEBUG) + zlog_debug("%s: connection in progress",dmn->name); + dmn->state = DAEMON_CONNECTING; + dmn->fd = sock; + dmn->t_write = thread_add_write(master,check_connect,dmn,dmn->fd); + dmn->t_wakeup = thread_add_timer(master,wakeup_connect_hanging,dmn, + gs.timeout); + SET_READ_HANDLER(dmn); + return 0; + } + + dmn->fd = sock; + SET_READ_HANDLER(dmn); + daemon_up(dmn,"connect succeeded"); + return 1; +} + +static int +phase_hanging(struct thread *t_hanging) +{ + gs.t_phase_hanging = NULL; + zlog_err("Phase [%s] hanging for %ld seconds, aborting phased restart", + phase_str[gs.phase],PHASE_TIMEOUT); + gs.phase = PHASE_NONE; + return 0; +} + +static void +set_phase(restart_phase_t new_phase) +{ + gs.phase = new_phase; + if (gs.t_phase_hanging) + thread_cancel(gs.t_phase_hanging); + gs.t_phase_hanging = thread_add_timer(master,phase_hanging,NULL, + PHASE_TIMEOUT); +} + +static void +phase_check(void) +{ + switch (gs.phase) + { + case PHASE_NONE: + break; + case PHASE_STOPS_PENDING: + if (gs.numpids) + break; + zlog_info("Phased restart: all routing daemon stop jobs have completed."); + set_phase(PHASE_WAITING_DOWN); + /*FALLTHRU*/ + case PHASE_WAITING_DOWN: + if (gs.numdown+IS_UP(gs.special) < gs.numdaemons) + break; + zlog_info("Phased restart: all routing daemons now down."); + run_job(&gs.special->restart,"restart",gs.restart_command,1,1); + set_phase(PHASE_ZEBRA_RESTART_PENDING); + /*FALLTHRU*/ + case PHASE_ZEBRA_RESTART_PENDING: + if (gs.special->restart.pid) + break; + zlog_info("Phased restart: %s restart job completed.",gs.special->name); + set_phase(PHASE_WAITING_ZEBRA_UP); + /*FALLTHRU*/ + case PHASE_WAITING_ZEBRA_UP: + if (!IS_UP(gs.special)) + break; + zlog_info("Phased restart: %s is now up.",gs.special->name); + { + struct daemon *dmn; + for (dmn = gs.daemons; dmn; dmn = dmn->next) + { + if (dmn != gs.special) + run_job(&dmn->restart,"start",gs.start_command,1,0); + } + } + gs.phase = PHASE_NONE; + THREAD_OFF(gs.t_phase_hanging); + zlog_notice("Phased global restart has completed."); + break; + } +} + +static void +try_restart(struct daemon *dmn) +{ + switch (gs.mode) + { + case MODE_MONITOR: + return; + case MODE_GLOBAL_RESTART: + run_job(&gs.restart,"restart",gs.restart_command,0,1); + break; + case MODE_SEPARATE_RESTART: + run_job(&dmn->restart,"restart",gs.restart_command,0,1); + break; + case MODE_PHASED_ZEBRA_RESTART: + if (dmn != gs.special) + { + if ((gs.special->state == DAEMON_UP) && (gs.phase == PHASE_NONE)) + run_job(&dmn->restart,"restart",gs.restart_command,0,1); + else + zlog_debug("%s: postponing restart attempt because master %s daemon " + "not up [%s], or phased restart in progress", + dmn->name,gs.special->name,state_str[gs.special->state]); + break; + } + /*FALLTHRU*/ + case MODE_PHASED_ALL_RESTART: + if ((gs.phase != PHASE_NONE) || gs.numpids) + { + if (gs.loglevel > LOG_DEBUG+1) + zlog_debug("postponing phased global restart: restart already in " + "progress [%s], or outstanding child processes [%d]", + phase_str[gs.phase],gs.numpids); + break; + } + /* Is it too soon for a restart? */ + { + struct timeval delay; + if (time_elapsed(&delay,&gs.special->restart.time)->tv_sec < + gs.special->restart.interval) + { + if (gs.loglevel > LOG_DEBUG+1) + zlog_debug("postponing phased global restart: " + "elapsed time %ld < retry interval %ld", + (long)delay.tv_sec,gs.special->restart.interval); + break; + } + } + run_job(&gs.restart,"restart",gs.restart_command,0,1); + break; + default: + zlog_err("error: unknown restart mode %d",gs.mode); + break; + } +} + +static int +wakeup_unresponsive(struct thread *t_wakeup) +{ + struct daemon *dmn = THREAD_ARG(t_wakeup); + + dmn->t_wakeup = NULL; + if (dmn->state != DAEMON_UNRESPONSIVE) + zlog_err("%s: no longer unresponsive (now %s), " + "wakeup should have been cancelled!", + dmn->name,state_str[dmn->state]); + else + { + SET_WAKEUP_UNRESPONSIVE(dmn); + try_restart(dmn); + } + return 0; +} + +static int +wakeup_no_answer(struct thread *t_wakeup) +{ + struct daemon *dmn = THREAD_ARG(t_wakeup); + + dmn->t_wakeup = NULL; + dmn->state = DAEMON_UNRESPONSIVE; + zlog_err("%s state -> unresponsive : no response yet to ping " + "sent %ld seconds ago",dmn->name,gs.timeout); + if (gs.unresponsive_restart) + { + SET_WAKEUP_UNRESPONSIVE(dmn); + try_restart(dmn); + } + return 0; +} + +static int +wakeup_send_echo(struct thread *t_wakeup) +{ + static const char echocmd[] = "echo " PING_TOKEN; + ssize_t rc; + struct daemon *dmn = THREAD_ARG(t_wakeup); + + dmn->t_wakeup = NULL; + if (((rc = write(dmn->fd,echocmd,sizeof(echocmd))) < 0) || + ((size_t)rc != sizeof(echocmd))) + { + char why[100+sizeof(echocmd)]; + snprintf(why,sizeof(why),"write '%s' returned %d instead of %u", + echocmd,(int)rc,(u_int)sizeof(echocmd)); + daemon_down(dmn,why); + } + else + { + gettimeofday(&dmn->echo_sent,NULL); + dmn->t_wakeup = thread_add_timer(master,wakeup_no_answer,dmn,gs.timeout); + } + return 0; +} + +static void +sigint(void) +{ + zlog_notice("Terminating on signal"); + systemd_send_stopping (); + exit(0); +} + +static int +valid_command(const char *cmd) +{ + char *p; + + return ((p = strchr(cmd,'%')) != NULL) && (*(p+1) == 's') && !strchr(p+1,'%'); +} + +/* This is an ugly hack to circumvent problems with passing command-line + arguments that contain spaces. The fix is to use a configuration file. */ +static char * +translate_blanks(const char *cmd, const char *blankstr) +{ + char *res; + char *p; + size_t bslen = strlen(blankstr); + + if (!(res = strdup(cmd))) + { + perror("strdup"); + exit(1); + } + while ((p = strstr(res,blankstr)) != NULL) + { + *p = ' '; + if (bslen != 1) + memmove(p+1,p+bslen,strlen(p+bslen)+1); + } + return res; +} + +struct zebra_privs_t watchfrr_privs = +{ +#ifdef VTY_GROUP + .vty_group = VTY_GROUP, +#endif +}; + +int +main(int argc, char **argv) +{ + const char *progname; + int opt; + int daemon_mode = 0; + const char *pidfile = DEFAULT_PIDFILE; + const char *special = "zebra"; + const char *blankstr = NULL; + static struct quagga_signal_t my_signals[] = + { + { + .signal = SIGINT, + .handler = sigint, + }, + { + .signal = SIGTERM, + .handler = sigint, + }, + { + .signal = SIGCHLD, + .handler = sigchild, + }, + }; + + if ((progname = strrchr (argv[0], '/')) != NULL) + progname++; + else + progname = argv[0]; + + gs.restart.name = "all"; + while ((opt = getopt_long(argc, argv, "aAb:dek:l:m:M:i:p:r:R:S:s:t:T:zvh", + longopts, 0)) != EOF) + { + switch (opt) + { + case 0: + break; + case 'a': + if ((gs.mode != MODE_MONITOR) && (gs.mode != MODE_SEPARATE_RESTART)) + { + fputs("Ambiguous operating mode selected.\n",stderr); + return usage(progname,1); + } + gs.mode = MODE_PHASED_ZEBRA_RESTART; + break; + case 'A': + if ((gs.mode != MODE_MONITOR) && (gs.mode != MODE_SEPARATE_RESTART)) + { + fputs("Ambiguous operating mode selected.\n",stderr); + return usage(progname,1); + } + gs.mode = MODE_PHASED_ALL_RESTART; + break; + case 'b': + blankstr = optarg; + break; + case 'd': + daemon_mode = 1; + break; + case 'e': + gs.do_ping = 0; + break; + case 'k': + if (!valid_command(optarg)) + { + fprintf(stderr,"Invalid kill command, must contain '%%s': %s\n", + optarg); + return usage(progname,1); + } + gs.stop_command = optarg; + break; + case 'l': + { + char garbage[3]; + if ((sscanf(optarg,"%d%1s",&gs.loglevel,garbage) != 1) || + (gs.loglevel < LOG_EMERG)) + { + fprintf(stderr,"Invalid loglevel argument: %s\n",optarg); + return usage(progname,1); + } + } + break; + case 'm': + { + char garbage[3]; + if ((sscanf(optarg,"%ld%1s", + &gs.min_restart_interval,garbage) != 1) || + (gs.min_restart_interval < 0)) + { + fprintf(stderr,"Invalid min_restart_interval argument: %s\n", + optarg); + return usage(progname,1); + } + } + break; + case 'M': + { + char garbage[3]; + if ((sscanf(optarg,"%ld%1s", + &gs.max_restart_interval,garbage) != 1) || + (gs.max_restart_interval < 0)) + { + fprintf(stderr,"Invalid max_restart_interval argument: %s\n", + optarg); + return usage(progname,1); + } + } + break; + case 'i': + { + char garbage[3]; + int period; + if ((sscanf(optarg,"%d%1s",&period,garbage) != 1) || + (gs.period < 1)) + { + fprintf(stderr,"Invalid interval argument: %s\n",optarg); + return usage(progname,1); + } + gs.period = 1000*period; + } + break; + case 'p': + pidfile = optarg; + break; + case 'r': + if ((gs.mode == MODE_GLOBAL_RESTART) || + (gs.mode == MODE_SEPARATE_RESTART)) + { + fputs("Ambiguous operating mode selected.\n",stderr); + return usage(progname,1); + } + if (!valid_command(optarg)) + { + fprintf(stderr, + "Invalid restart command, must contain '%%s': %s\n", + optarg); + return usage(progname,1); + } + gs.restart_command = optarg; + if (gs.mode == MODE_MONITOR) + gs.mode = MODE_SEPARATE_RESTART; + break; + case 'R': + if (gs.mode != MODE_MONITOR) + { + fputs("Ambiguous operating mode selected.\n",stderr); + return usage(progname,1); + } + if (strchr(optarg,'%')) + { + fprintf(stderr, + "Invalid restart-all arg, must not contain '%%s': %s\n", + optarg); + return usage(progname,1); + } + gs.restart_command = optarg; + gs.mode = MODE_GLOBAL_RESTART; + break; + case 's': + if (!valid_command(optarg)) + { + fprintf(stderr,"Invalid start command, must contain '%%s': %s\n", + optarg); + return usage(progname,1); + } + gs.start_command = optarg; + break; + case 'S': + gs.vtydir = optarg; + break; + case 't': + { + char garbage[3]; + if ((sscanf(optarg,"%ld%1s",&gs.timeout,garbage) != 1) || + (gs.timeout < 1)) + { + fprintf(stderr,"Invalid timeout argument: %s\n",optarg); + return usage(progname,1); + } + } + break; + case 'T': + { + char garbage[3]; + if ((sscanf(optarg,"%ld%1s",&gs.restart_timeout,garbage) != 1) || + (gs.restart_timeout < 1)) + { + fprintf(stderr,"Invalid restart timeout argument: %s\n",optarg); + return usage(progname,1); + } + } + break; + case 'z': + gs.unresponsive_restart = 1; + break; + case 'v': + printf ("%s version %s\n", progname, FRR_VERSION); + puts("Copyright 2004 Andrew J. Schorr"); + return 0; + case 'h': + return usage(progname,0); + default: + fputs("Invalid option.\n",stderr); + return usage(progname,1); + } + } + + if (gs.unresponsive_restart && (gs.mode == MODE_MONITOR)) + { + fputs("Option -z requires a -r or -R restart option.\n",stderr); + return usage(progname,1); + } + switch (gs.mode) + { + case MODE_MONITOR: + if (gs.restart_command || gs.start_command || gs.stop_command) + { + fprintf(stderr,"No kill/(re)start commands needed for %s mode.\n", + mode_str[gs.mode]); + return usage(progname,1); + } + break; + case MODE_GLOBAL_RESTART: + case MODE_SEPARATE_RESTART: + if (!gs.restart_command || gs.start_command || gs.stop_command) + { + fprintf(stderr,"No start/kill commands needed in [%s] mode.\n", + mode_str[gs.mode]); + return usage(progname,1); + } + break; + case MODE_PHASED_ZEBRA_RESTART: + case MODE_PHASED_ALL_RESTART: + if (!gs.restart_command || !gs.start_command || !gs.stop_command) + { + fprintf(stderr, + "Need start, kill, and restart commands in [%s] mode.\n", + mode_str[gs.mode]); + return usage(progname,1); + } + break; + } + + if (blankstr) + { + if (gs.restart_command) + gs.restart_command = translate_blanks(gs.restart_command,blankstr); + if (gs.start_command) + gs.start_command = translate_blanks(gs.start_command,blankstr); + if (gs.stop_command) + gs.stop_command = translate_blanks(gs.stop_command,blankstr); + } + + gs.restart.interval = gs.min_restart_interval; + + zprivs_init (&watchfrr_privs); + + master = thread_master_create(); + cmd_init(-1); + memory_init(); + vty_init(master); + watchfrr_vty_init(); + vty_serv_sock(NULL, 0, WATCHFRR_VTYSH_PATH); + + signal_init (master, array_size(my_signals), my_signals); + srandom(time(NULL)); + + { + int i; + struct daemon *tail = NULL; + + for (i = optind; i < argc; i++) + { + struct daemon *dmn; + + if (!(dmn = (struct daemon *)calloc(1,sizeof(*dmn)))) + { + fprintf(stderr,"calloc(1,%u) failed: %s\n", + (u_int)sizeof(*dmn), safe_strerror(errno)); + return 1; + } + dmn->name = dmn->restart.name = argv[i]; + dmn->state = DAEMON_INIT; + gs.numdaemons++; + gs.numdown++; + dmn->fd = -1; + dmn->t_wakeup = thread_add_timer_msec(master,wakeup_init,dmn, + 100+(random() % 900)); + dmn->restart.interval = gs.min_restart_interval; + if (tail) + tail->next = dmn; + else + gs.daemons = dmn; + tail = dmn; + + if (((gs.mode == MODE_PHASED_ZEBRA_RESTART) || + (gs.mode == MODE_PHASED_ALL_RESTART)) && + !strcmp(dmn->name,special)) + gs.special = dmn; + } + } + if (!gs.daemons) + { + fputs("Must specify one or more daemons to monitor.\n",stderr); + return usage(progname,1); + } + if (((gs.mode == MODE_PHASED_ZEBRA_RESTART) || + (gs.mode == MODE_PHASED_ALL_RESTART)) && !gs.special) + { + fprintf(stderr,"In mode [%s], but cannot find master daemon %s\n", + mode_str[gs.mode],special); + return usage(progname,1); + } + + zlog_default = openzlog(progname, ZLOG_WATCHFRR, 0, + LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); + zlog_set_level(NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED); + if (daemon_mode) + { + zlog_set_level(NULL, ZLOG_DEST_SYSLOG, MIN(gs.loglevel,LOG_DEBUG)); + if (daemon (0, 0) < 0) + { + fprintf(stderr, "Watchfrr daemon failed: %s", strerror(errno)); + exit (1); + } + } + else + zlog_set_level(NULL, ZLOG_DEST_STDOUT, MIN(gs.loglevel,LOG_DEBUG)); + + /* Make sure we're not already running. */ + pid_output (pidfile); + + /* Announce which daemons are being monitored. */ + { + struct daemon *dmn; + size_t len = 0; + + for (dmn = gs.daemons; dmn; dmn = dmn->next) + len += strlen(dmn->name)+1; + + { + char buf[len+1]; + char *p = buf; + + for (dmn = gs.daemons; dmn; dmn = dmn->next) + { + if (p != buf) + *p++ = ' '; + strcpy(p,dmn->name); + p += strlen(p); + } + zlog_notice("%s %s watching [%s], mode [%s]", + progname, FRR_VERSION, buf, mode_str[gs.mode]); + } + } + + { + struct thread thread; + + while (thread_fetch (master, &thread)) + thread_call (&thread); + } + + systemd_send_stopping (); + /* Not reached. */ + return 0; +} diff --git a/watchfrr/watchfrr.h b/watchfrr/watchfrr.h new file mode 100644 index 0000000000..4a479c72e6 --- /dev/null +++ b/watchfrr/watchfrr.h @@ -0,0 +1,29 @@ +/* + Common definitions for watchfrr API socket. + + 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 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; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef FRR_WATCHFRR_H +#define FRR_WATCHFRR_H + +extern void watchfrr_vty_init(void); + +extern pid_t integrated_write_pid; +extern void integrated_write_sigchld(int status); + +#endif /* FRR_WATCHFRR_H */ diff --git a/watchfrr/watchfrr_vty.c b/watchfrr/watchfrr_vty.c new file mode 100644 index 0000000000..4fffb020d7 --- /dev/null +++ b/watchfrr/watchfrr_vty.c @@ -0,0 +1,134 @@ +/* + watchfrr CLI functions. + + 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 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; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include + +#include "memory.h" +#include "log.h" +#include "vty.h" +#include "command.h" + +#include "watchfrr.h" + +pid_t integrated_write_pid; +static int integrated_result_fd; + +DEFUN (config_write_integrated, + config_write_integrated_cmd, + "write integrated", + "Write running configuration to memory, network, or terminal\n" + "Write integrated all-daemon Frr.conf file\n") +{ + pid_t child; + sigset_t oldmask, sigmask; + + if (integrated_write_pid != -1) { + vty_out(vty, "%% configuration write already in progress.%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + fflush(stdout); + fflush(stderr); + + /* need to temporarily block SIGCHLD because it could arrive between + * fork() call and setting the integrated_write_pid variable. This + * would mean the completion call gets lost and this hangs forever. + */ + sigemptyset(&oldmask); + sigemptyset(&sigmask); + sigaddset(&sigmask, SIGCHLD); + sigprocmask(SIG_BLOCK, &sigmask, &oldmask); + + child = fork(); + if (child == -1) { + vty_out(vty, "%% configuration write fork() failed: %s.%s", + safe_strerror(errno), VTY_NEWLINE); + sigprocmask(SIG_SETMASK, &oldmask, NULL); + return CMD_WARNING; + } + if (child != 0) { + /* note: the VTY won't write a command return value to vtysh; the + * session temporarily enters an intentional "hang" state. This is + * to make sure latency in vtysh doing the config write (several + * seconds is not rare to see) does not interfere with watchfrr's + * supervisor job. + * + * The fd is duplicated here so we don't need to hold a vty pointer + * (which could become invalid in the meantime). + */ + integrated_write_pid = child; + integrated_result_fd = dup(vty->wfd); + sigprocmask(SIG_SETMASK, &oldmask, NULL); + return CMD_SUSPEND; + } + + /* redirect stdout/stderr to vty session. Note vty->wfd is marked + * CLOEXEC, but dup2 will clear that flag. */ + dup2(vty->wfd, 1); + dup2(vty->wfd, 2); + + /* don't allow the user to pass parameters, we're root here! + * should probably harden vtysh at some point too... */ + execl(VTYSH_BIN_PATH, "vtysh", "-w", NULL); + + /* unbuffered write; we just messed with stdout... */ + char msg[512]; + snprintf(msg, sizeof(msg), "error executing %s: %s\n", + VTYSH_BIN_PATH, safe_strerror(errno)); + write(1, msg, strlen(msg)); + exit(1); +} + +void integrated_write_sigchld(int status) +{ + uint8_t reply[4] = { 0, 0, 0, CMD_WARNING }; + + if (WIFEXITED(status)) { + zlog_info("configuration write completed with exit code %d", + WEXITSTATUS(status)); + reply[3] = WEXITSTATUS(status); + } else if (WIFSIGNALED(status)) { + zlog_warn("configuration write terminated by signal %d", + WTERMSIG(status)); + } else { + zlog_warn("configuration write terminated"); + } + + if (reply[3] != CMD_SUCCESS) { + /* failure might be silent in vtysh without this */ + static const char msg[] = "% Configuration write failed.\n"; + write(integrated_result_fd, msg, strlen(msg)); + } + + /* don't care about failures here, if the connection is broken the + * return value will just be lost. */ + write(integrated_result_fd, reply, sizeof(reply)); + close(integrated_result_fd); + + integrated_write_pid = -1; +} + +void watchfrr_vty_init(void) +{ + integrated_write_pid = -1; + install_element(ENABLE_NODE, &config_write_integrated_cmd); +} diff --git a/watchquagga/.gitignore b/watchquagga/.gitignore deleted file mode 100644 index b6226d53d3..0000000000 --- a/watchquagga/.gitignore +++ /dev/null @@ -1,16 +0,0 @@ -Makefile -Makefile.in -*.o -watchquagga -tags -TAGS -.deps -.nfs* -*.lo -*.la -*.libs -.arch-inventory -.arch-ids -*~ -*.loT - diff --git a/watchquagga/Makefile.am b/watchquagga/Makefile.am deleted file mode 100644 index 43f743eba2..0000000000 --- a/watchquagga/Makefile.am +++ /dev/null @@ -1,13 +0,0 @@ -## Process this file with Automake to create Makefile.in - -AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib -DEFS = @DEFS@ -DSTATEDIR=\"$(localstatedir)/\" - -AM_CFLAGS = $(WERROR) - -sbin_PROGRAMS = watchquagga - -noinst_HEADERS = watchquagga.h - -watchquagga_SOURCES = watchquagga.c watchquagga_vty.c -watchquagga_LDADD = ../lib/libzebra.la @LIBCAP@ diff --git a/watchquagga/watchquagga.c b/watchquagga/watchquagga.c deleted file mode 100644 index a70070bef7..0000000000 --- a/watchquagga/watchquagga.c +++ /dev/null @@ -1,1439 +0,0 @@ -/* - Monitor status of quagga daemons and restart if necessary. - - Copyright (C) 2004 Andrew J. Schorr - - 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; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include "command.h" -#include "memory_vty.h" - -#include -#include -#include -#include -#include - -#include "watchquagga.h" - -#ifndef MIN -#define MIN(X,Y) (((X) <= (Y)) ? (X) : (Y)) -#endif - -/* Macros to help randomize timers. */ -#define JITTER(X) ((random() % ((X)+1))-((X)/2)) -#define FUZZY(X) ((X)+JITTER((X)/20)) - -#define DEFAULT_PERIOD 5 -#define DEFAULT_TIMEOUT 10 -#define DEFAULT_RESTART_TIMEOUT 20 -#define DEFAULT_LOGLEVEL LOG_INFO -#define DEFAULT_MIN_RESTART 60 -#define DEFAULT_MAX_RESTART 600 -#ifdef PATH_WATCHQUAGGA_PID -#define DEFAULT_PIDFILE PATH_WATCHQUAGGA_PID -#else -#define DEFAULT_PIDFILE STATEDIR "/watchquagga.pid" -#endif -#ifdef DAEMON_VTY_DIR -#define VTYDIR DAEMON_VTY_DIR -#else -#define VTYDIR STATEDIR -#endif - -#define PING_TOKEN "PING" - -/* Needs to be global, referenced somewhere inside libzebra. */ -struct thread_master *master; - -typedef enum -{ - MODE_MONITOR = 0, - MODE_GLOBAL_RESTART, - MODE_SEPARATE_RESTART, - MODE_PHASED_ZEBRA_RESTART, - MODE_PHASED_ALL_RESTART -} watch_mode_t; - -static const char *mode_str[] = -{ - "monitor", - "global restart", - "individual daemon restart", - "phased zebra restart", - "phased global restart for any failure", -}; - -typedef enum -{ - PHASE_NONE = 0, - PHASE_STOPS_PENDING, - PHASE_WAITING_DOWN, - PHASE_ZEBRA_RESTART_PENDING, - PHASE_WAITING_ZEBRA_UP -} restart_phase_t; - -static const char *phase_str[] = -{ - "None", - "Stop jobs running", - "Waiting for other daemons to come down", - "Zebra restart job running", - "Waiting for zebra to come up", - "Start jobs running", -}; - -#define PHASE_TIMEOUT (3*gs.restart_timeout) - -struct restart_info -{ - const char *name; - const char *what; - pid_t pid; - struct timeval time; - long interval; - struct thread *t_kill; - int kills; -}; - -static struct global_state -{ - watch_mode_t mode; - restart_phase_t phase; - struct thread *t_phase_hanging; - const char *vtydir; - long period; - long timeout; - long restart_timeout; - long min_restart_interval; - long max_restart_interval; - int do_ping; - struct daemon *daemons; - const char *restart_command; - const char *start_command; - const char *stop_command; - struct restart_info restart; - int unresponsive_restart; - int loglevel; - struct daemon *special; /* points to zebra when doing phased restart */ - int numdaemons; - int numpids; - int numdown; /* # of daemons that are not UP or UNRESPONSIVE */ -} gs = { - .mode = MODE_MONITOR, - .phase = PHASE_NONE, - .vtydir = VTYDIR, - .period = 1000*DEFAULT_PERIOD, - .timeout = DEFAULT_TIMEOUT, - .restart_timeout = DEFAULT_RESTART_TIMEOUT, - .loglevel = DEFAULT_LOGLEVEL, - .min_restart_interval = DEFAULT_MIN_RESTART, - .max_restart_interval = DEFAULT_MAX_RESTART, - .do_ping = 1, -}; - -typedef enum -{ - DAEMON_INIT, - DAEMON_DOWN, - DAEMON_CONNECTING, - DAEMON_UP, - DAEMON_UNRESPONSIVE -} daemon_state_t; - -#define IS_UP(DMN) \ - (((DMN)->state == DAEMON_UP) || ((DMN)->state == DAEMON_UNRESPONSIVE)) - -static const char *state_str[] = -{ - "Init", - "Down", - "Connecting", - "Up", - "Unresponsive", -}; - -struct daemon { - const char *name; - daemon_state_t state; - int fd; - struct timeval echo_sent; - u_int connect_tries; - struct thread *t_wakeup; - struct thread *t_read; - struct thread *t_write; - struct daemon *next; - struct restart_info restart; -}; - -static const struct option longopts[] = -{ - { "daemon", no_argument, NULL, 'd'}, - { "statedir", required_argument, NULL, 'S'}, - { "no-echo", no_argument, NULL, 'e'}, - { "loglevel", required_argument, NULL, 'l'}, - { "interval", required_argument, NULL, 'i'}, - { "timeout", required_argument, NULL, 't'}, - { "restart-timeout", required_argument, NULL, 'T'}, - { "restart", required_argument, NULL, 'r'}, - { "start-command", required_argument, NULL, 's'}, - { "kill-command", required_argument, NULL, 'k'}, - { "restart-all", required_argument, NULL, 'R'}, - { "all-restart", no_argument, NULL, 'a'}, - { "always-all-restart", no_argument, NULL, 'A'}, - { "unresponsive-restart", no_argument, NULL, 'z'}, - { "min-restart-interval", required_argument, NULL, 'm'}, - { "max-restart-interval", required_argument, NULL, 'M'}, - { "pid-file", required_argument, NULL, 'p'}, - { "blank-string", required_argument, NULL, 'b'}, - { "help", no_argument, NULL, 'h'}, - { "version", no_argument, NULL, 'v'}, - { NULL, 0, NULL, 0 } -}; - -static int try_connect(struct daemon *dmn); -static int wakeup_send_echo(struct thread *t_wakeup); -static void try_restart(struct daemon *dmn); -static void phase_check(void); - -static int -usage(const char *progname, int status) -{ - if (status != 0) - fprintf(stderr, "Try `%s --help' for more information.\n", progname); - else - { - printf("Usage : %s [OPTION...] ...\n\n\ -Watchdog program to monitor status of quagga daemons and try to restart\n\ -them if they are down or unresponsive. It determines whether a daemon is\n\ -up based on whether it can connect to the daemon's vty unix stream socket.\n\ -It then repeatedly sends echo commands over that socket to determine whether\n\ -the daemon is responsive. If the daemon crashes, we will receive an EOF\n\ -on the socket connection and know immediately that the daemon is down.\n\n\ -The daemons to be monitored should be listed on the command line.\n\n\ -This program can run in one of 5 modes:\n\n\ -0. Mode: %s.\n\ - Just monitor and report on status changes. Example:\n\ - %s -d zebra ospfd bgpd\n\n\ -1. Mode: %s.\n\ - Whenever any daemon hangs or crashes, use the given command to restart\n\ - them all. Example:\n\ - %s -dz \\\n\ - -R '/sbin/service zebra restart; /sbin/service ospfd restart' \\\n\ - zebra ospfd\n\n\ -2. Mode: %s.\n\ - When any single daemon hangs or crashes, restart only the daemon that's\n\ - in trouble using the supplied restart command. Example:\n\ - %s -dz -r '/sbin/service %%s restart' zebra ospfd bgpd\n\n\ -3. Mode: %s.\n\ - The same as the previous mode, except that there is special treatment when\n\ - the zebra daemon is in trouble. In that case, a phased restart approach\n\ - is used: 1. stop all other daemons; 2. restart zebra; 3. start the other\n\ - daemons. Example:\n\ - %s -adz -r '/sbin/service %%s restart' \\\n\ - -s '/sbin/service %%s start' \\\n\ - -k '/sbin/service %%s stop' zebra ospfd bgpd\n\n\ -4. Mode: %s.\n\ - This is the same as the previous mode, except that the phased restart\n\ - procedure is used whenever any of the daemons hangs or crashes. Example:\n\ - %s -Adz -r '/sbin/service %%s restart' \\\n\ - -s '/sbin/service %%s start' \\\n\ - -k '/sbin/service %%s stop' zebra ospfd bgpd\n\n\ -As of this writing, it is believed that mode 2 [%s]\n\ -is not safe, and mode 3 [%s] may not be safe with some of the\n\ -routing daemons.\n\n\ -In order to avoid attempting to restart the daemons in a fast loop,\n\ -the -m and -M options allow you to control the minimum delay between\n\ -restart commands. The minimum restart delay is recalculated each time\n\ -a restart is attempted: if the time since the last restart attempt exceeds\n\ -twice the -M value, then the restart delay is set to the -m value.\n\ -Otherwise, the interval is doubled (but capped at the -M value).\n\n", - progname,mode_str[0],progname,mode_str[1],progname,mode_str[2], - progname,mode_str[3],progname,mode_str[4],progname,mode_str[2], - mode_str[3]); - - printf("Options:\n\ --d, --daemon Run in daemon mode. In this mode, error messages are sent\n\ - to syslog instead of stdout.\n\ --S, --statedir Set the vty socket directory (default is %s)\n\ --e, --no-echo Do not ping the daemons to test responsiveness (this\n\ - option is necessary if the daemons do not support the\n\ - echo command)\n\ --l, --loglevel Set the logging level (default is %d).\n\ - The value should range from %d (LOG_EMERG) to %d (LOG_DEBUG),\n\ - but it can be set higher than %d if extra-verbose debugging\n\ - messages are desired.\n\ --m, --min-restart-interval\n\ - Set the minimum seconds to wait between invocations of daemon\n\ - restart commands (default is %d).\n\ --M, --max-restart-interval\n\ - Set the maximum seconds to wait between invocations of daemon\n\ - restart commands (default is %d).\n\ --i, --interval Set the status polling interval in seconds (default is %d)\n\ --t, --timeout Set the unresponsiveness timeout in seconds (default is %d)\n\ --T, --restart-timeout\n\ - Set the restart (kill) timeout in seconds (default is %d).\n\ - If any background jobs are still running after this much\n\ - time has elapsed, they will be killed.\n\ --r, --restart Supply a Bourne shell command to use to restart a single\n\ - daemon. The command string should include '%%s' where the\n\ - name of the daemon should be substituted.\n\ - Note that -r and -R are incompatible.\n\ --s, --start-command\n\ - Supply a Bourne shell to command to use to start a single\n\ - daemon. The command string should include '%%s' where the\n\ - name of the daemon should be substituted.\n\ --k, --kill-command\n\ - Supply a Bourne shell to command to use to stop a single\n\ - daemon. The command string should include '%%s' where the\n\ - name of the daemon should be substituted.\n\ --R, --restart-all\n\ - When one or more daemons is down, try to restart everything\n\ - using the Bourne shell command supplied as the argument.\n\ - Note that -r and -R are incompatible.\n\ --z, --unresponsive-restart\n\ - When a daemon is unresponsive, treat it as being down for\n\ - restart purposes.\n\ --a, --all-restart\n\ - When zebra hangs or crashes, restart all daemons using\n\ - this phased approach: 1. stop all other daemons; 2. restart\n\ - zebra; 3. start other daemons. Requires -r, -s, and -k.\n\ --A, --always-all-restart\n\ - When any daemon (not just zebra) hangs or crashes, use the\n\ - same phased restart mechanism described above for -a.\n\ - Requires -r, -s, and -k.\n\ --p, --pid-file Set process identifier file name\n\ - (default is %s).\n\ --b, --blank-string\n\ - When the supplied argument string is found in any of the\n\ - various shell command arguments (-r, -s, -k, or -R), replace\n\ - it with a space. This is an ugly hack to circumvent problems\n\ - passing command-line arguments with embedded spaces.\n\ --v, --version Print program version\n\ --h, --help Display this help and exit\n", - VTYDIR,DEFAULT_LOGLEVEL,LOG_EMERG,LOG_DEBUG,LOG_DEBUG, - DEFAULT_MIN_RESTART,DEFAULT_MAX_RESTART, - DEFAULT_PERIOD,DEFAULT_TIMEOUT,DEFAULT_RESTART_TIMEOUT, - DEFAULT_PIDFILE); - } - - return status; -} - -static pid_t -run_background(char *shell_cmd) -{ - pid_t child; - - switch (child = fork()) - { - case -1: - zlog_err("fork failed, cannot run command [%s]: %s", - shell_cmd,safe_strerror(errno)); - return -1; - case 0: - /* Child process. */ - /* Use separate process group so child processes can be killed easily. */ - if (setpgid(0,0) < 0) - zlog_warn("warning: setpgid(0,0) failed: %s",safe_strerror(errno)); - { - char shell[] = "sh"; - char dashc[] = "-c"; - char * const argv[4] = { shell, dashc, shell_cmd, NULL}; - execv("/bin/sh", argv); - zlog_err("execv(/bin/sh -c '%s') failed: %s", - shell_cmd,safe_strerror(errno)); - _exit(127); - } - default: - /* Parent process: we will reap the child later. */ - zlog_err("Forked background command [pid %d]: %s",(int)child,shell_cmd); - return child; - } -} - -static struct timeval * -time_elapsed(struct timeval *result, const struct timeval *start_time) -{ - gettimeofday(result,NULL); - result->tv_sec -= start_time->tv_sec; - result->tv_usec -= start_time->tv_usec; - while (result->tv_usec < 0) - { - result->tv_usec += 1000000L; - result->tv_sec--; - } - return result; -} - -static int -restart_kill(struct thread *t_kill) -{ - struct restart_info *restart = THREAD_ARG(t_kill); - struct timeval delay; - - time_elapsed(&delay,&restart->time); - zlog_warn("Warning: %s %s child process %d still running after " - "%ld seconds, sending signal %d", - restart->what,restart->name,(int)restart->pid, (long)delay.tv_sec, - (restart->kills ? SIGKILL : SIGTERM)); - kill(-restart->pid,(restart->kills ? SIGKILL : SIGTERM)); - restart->kills++; - restart->t_kill = thread_add_timer(master,restart_kill,restart, - gs.restart_timeout); - return 0; -} - -static struct restart_info * -find_child(pid_t child) -{ - if (gs.mode == MODE_GLOBAL_RESTART) - { - if (gs.restart.pid == child) - return &gs.restart; - } - else - { - struct daemon *dmn; - for (dmn = gs.daemons; dmn; dmn = dmn->next) - { - if (dmn->restart.pid == child) - return &dmn->restart; - } - } - return NULL; -} - -static void -sigchild(void) -{ - pid_t child; - int status; - const char *name; - const char *what; - struct restart_info *restart; - - switch (child = waitpid(-1,&status,WNOHANG)) - { - case -1: - zlog_err("waitpid failed: %s",safe_strerror(errno)); - return; - case 0: - zlog_warn("SIGCHLD received, but waitpid did not reap a child"); - return; - } - - if (child == integrated_write_pid) - { - integrated_write_sigchld(status); - return; - } - - if ((restart = find_child(child)) != NULL) - { - name = restart->name; - what = restart->what; - restart->pid = 0; - gs.numpids--; - thread_cancel(restart->t_kill); - restart->t_kill = NULL; - /* Update restart time to reflect the time the command completed. */ - gettimeofday(&restart->time,NULL); - } - else - { - zlog_err("waitpid returned status for an unknown child process %d", - (int)child); - name = "(unknown)"; - what = "background"; - } - if (WIFSTOPPED(status)) - zlog_warn("warning: %s %s process %d is stopped", - what,name,(int)child); - else if (WIFSIGNALED(status)) - zlog_warn("%s %s process %d terminated due to signal %d", - what,name,(int)child,WTERMSIG(status)); - else if (WIFEXITED(status)) - { - if (WEXITSTATUS(status) != 0) - zlog_warn("%s %s process %d exited with non-zero status %d", - what,name,(int)child,WEXITSTATUS(status)); - else - zlog_debug("%s %s process %d exited normally",what,name,(int)child); - } - else - zlog_err("cannot interpret %s %s process %d wait status 0x%x", - what,name,(int)child,status); - phase_check(); -} - -static int -run_job(struct restart_info *restart, const char *cmdtype, const char *command, - int force, int update_interval) -{ - struct timeval delay; - - if (gs.loglevel > LOG_DEBUG+1) - zlog_debug("attempting to %s %s",cmdtype,restart->name); - - if (restart->pid) - { - if (gs.loglevel > LOG_DEBUG+1) - zlog_debug("cannot %s %s, previous pid %d still running", - cmdtype,restart->name,(int)restart->pid); - return -1; - } - - /* Note: time_elapsed test must come before the force test, since we need - to make sure that delay is initialized for use below in updating the - restart interval. */ - if ((time_elapsed(&delay,&restart->time)->tv_sec < restart->interval) && - !force) - { - if (gs.loglevel > LOG_DEBUG+1) - zlog_debug("postponing %s %s: " - "elapsed time %ld < retry interval %ld", - cmdtype,restart->name,(long)delay.tv_sec,restart->interval); - return -1; - } - - gettimeofday(&restart->time,NULL); - restart->kills = 0; - { - char cmd[strlen(command)+strlen(restart->name)+1]; - snprintf(cmd,sizeof(cmd),command,restart->name); - if ((restart->pid = run_background(cmd)) > 0) - { - restart->t_kill = thread_add_timer(master,restart_kill,restart, - gs.restart_timeout); - restart->what = cmdtype; - gs.numpids++; - } - else - restart->pid = 0; - } - - /* Calculate the new restart interval. */ - if (update_interval) - { - if (delay.tv_sec > 2*gs.max_restart_interval) - restart->interval = gs.min_restart_interval; - else if ((restart->interval *= 2) > gs.max_restart_interval) - restart->interval = gs.max_restart_interval; - if (gs.loglevel > LOG_DEBUG+1) - zlog_debug("restart %s interval is now %ld", - restart->name,restart->interval); - } - return restart->pid; -} - -#define SET_READ_HANDLER(DMN) \ - (DMN)->t_read = thread_add_read(master,handle_read,(DMN),(DMN)->fd) - -#define SET_WAKEUP_DOWN(DMN) \ - (DMN)->t_wakeup = thread_add_timer_msec(master,wakeup_down,(DMN), \ - FUZZY(gs.period)) - -#define SET_WAKEUP_UNRESPONSIVE(DMN) \ - (DMN)->t_wakeup = thread_add_timer_msec(master,wakeup_unresponsive,(DMN), \ - FUZZY(gs.period)) - -#define SET_WAKEUP_ECHO(DMN) \ - (DMN)->t_wakeup = thread_add_timer_msec(master,wakeup_send_echo,(DMN), \ - FUZZY(gs.period)) - -static int -wakeup_down(struct thread *t_wakeup) -{ - struct daemon *dmn = THREAD_ARG(t_wakeup); - - dmn->t_wakeup = NULL; - if (try_connect(dmn) < 0) - SET_WAKEUP_DOWN(dmn); - if ((dmn->connect_tries > 1) && (dmn->state != DAEMON_UP)) - try_restart(dmn); - return 0; -} - -static int -wakeup_init(struct thread *t_wakeup) -{ - struct daemon *dmn = THREAD_ARG(t_wakeup); - - dmn->t_wakeup = NULL; - if (try_connect(dmn) < 0) - { - SET_WAKEUP_DOWN(dmn); - zlog_err("%s state -> down : initial connection attempt failed", - dmn->name); - dmn->state = DAEMON_DOWN; - } - return 0; -} - -static void -daemon_down(struct daemon *dmn, const char *why) -{ - if (IS_UP(dmn) || (dmn->state == DAEMON_INIT)) - zlog_err("%s state -> down : %s",dmn->name,why); - else if (gs.loglevel > LOG_DEBUG) - zlog_debug("%s still down : %s",dmn->name,why); - if (IS_UP(dmn)) - gs.numdown++; - dmn->state = DAEMON_DOWN; - if (dmn->fd >= 0) - { - close(dmn->fd); - dmn->fd = -1; - } - THREAD_OFF(dmn->t_read); - THREAD_OFF(dmn->t_write); - THREAD_OFF(dmn->t_wakeup); - if (try_connect(dmn) < 0) - SET_WAKEUP_DOWN(dmn); - phase_check(); -} - -static int -handle_read(struct thread *t_read) -{ - struct daemon *dmn = THREAD_ARG(t_read); - static const char resp[sizeof(PING_TOKEN)+4] = PING_TOKEN "\n"; - char buf[sizeof(resp)+100]; - ssize_t rc; - struct timeval delay; - - dmn->t_read = NULL; - if ((rc = read(dmn->fd,buf,sizeof(buf))) < 0) - { - char why[100]; - - if (ERRNO_IO_RETRY(errno)) - { - /* Pretend it never happened. */ - SET_READ_HANDLER(dmn); - return 0; - } - snprintf(why,sizeof(why),"unexpected read error: %s", - safe_strerror(errno)); - daemon_down(dmn,why); - return 0; - } - if (rc == 0) - { - daemon_down(dmn,"read returned EOF"); - return 0; - } - if (!dmn->echo_sent.tv_sec) - { - char why[sizeof(buf)+100]; - snprintf(why,sizeof(why),"unexpected read returns %d bytes: %.*s", - (int)rc,(int)rc,buf); - daemon_down(dmn,why); - return 0; - } - - /* We are expecting an echo response: is there any chance that the - response would not be returned entirely in the first read? That - seems inconceivable... */ - if ((rc != sizeof(resp)) || memcmp(buf,resp,sizeof(resp))) - { - char why[100+sizeof(buf)]; - snprintf(why,sizeof(why),"read returned bad echo response of %d bytes " - "(expecting %u): %.*s", - (int)rc,(u_int)sizeof(resp),(int)rc,buf); - daemon_down(dmn,why); - return 0; - } - - time_elapsed(&delay,&dmn->echo_sent); - dmn->echo_sent.tv_sec = 0; - if (dmn->state == DAEMON_UNRESPONSIVE) - { - if (delay.tv_sec < gs.timeout) - { - dmn->state = DAEMON_UP; - zlog_warn("%s state -> up : echo response received after %ld.%06ld " - "seconds", dmn->name, - (long)delay.tv_sec, (long)delay.tv_usec); - } - else - zlog_warn("%s: slow echo response finally received after %ld.%06ld " - "seconds", dmn->name, - (long)delay.tv_sec, (long)delay.tv_usec); - } - else if (gs.loglevel > LOG_DEBUG+1) - zlog_debug("%s: echo response received after %ld.%06ld seconds", - dmn->name, (long)delay.tv_sec, (long)delay.tv_usec); - - SET_READ_HANDLER(dmn); - if (dmn->t_wakeup) - thread_cancel(dmn->t_wakeup); - SET_WAKEUP_ECHO(dmn); - - return 0; -} - -/* - * Wait till we notice that all daemons are ready before - * we send we are ready to systemd - */ -static void -daemon_send_ready (void) -{ - static int sent = 0; - if (!sent && gs.numdown == 0) - { -#if defined (HAVE_CUMULUS) - FILE *fp; - - fp = fopen(DAEMON_VTY_DIR "/watchquagga.started", "w"); - fclose(fp); -#endif - zlog_notice ("Watchquagga: Notifying Systemd we are up and running"); - systemd_send_started(master, 0); - sent = 1; - } -} - -static void -daemon_up(struct daemon *dmn, const char *why) -{ - dmn->state = DAEMON_UP; - gs.numdown--; - dmn->connect_tries = 0; - zlog_notice("%s state -> up : %s",dmn->name,why); - daemon_send_ready(); - if (gs.do_ping) - SET_WAKEUP_ECHO(dmn); - phase_check(); -} - -static int -check_connect(struct thread *t_write) -{ - struct daemon *dmn = THREAD_ARG(t_write); - int sockerr; - socklen_t reslen = sizeof(sockerr); - - dmn->t_write = NULL; - if (getsockopt(dmn->fd,SOL_SOCKET,SO_ERROR,(char *)&sockerr,&reslen) < 0) - { - zlog_warn("%s: check_connect: getsockopt failed: %s", - dmn->name,safe_strerror(errno)); - daemon_down(dmn,"getsockopt failed checking connection success"); - return 0; - } - if ((reslen == sizeof(sockerr)) && sockerr) - { - char why[100]; - snprintf(why,sizeof(why), - "getsockopt reports that connection attempt failed: %s", - safe_strerror(sockerr)); - daemon_down(dmn,why); - return 0; - } - - daemon_up(dmn,"delayed connect succeeded"); - return 0; -} - -static int -wakeup_connect_hanging(struct thread *t_wakeup) -{ - struct daemon *dmn = THREAD_ARG(t_wakeup); - char why[100]; - - dmn->t_wakeup = NULL; - snprintf(why,sizeof(why),"connection attempt timed out after %ld seconds", - gs.timeout); - daemon_down(dmn,why); - return 0; -} - -/* Making connection to protocol daemon. */ -static int -try_connect(struct daemon *dmn) -{ - int sock; - struct sockaddr_un addr; - socklen_t len; - - if (gs.loglevel > LOG_DEBUG+1) - zlog_debug("%s: attempting to connect",dmn->name); - dmn->connect_tries++; - - memset (&addr, 0, sizeof (struct sockaddr_un)); - addr.sun_family = AF_UNIX; - snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s.vty", - gs.vtydir,dmn->name); -#ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN - len = addr.sun_len = SUN_LEN(&addr); -#else - len = sizeof (addr.sun_family) + strlen (addr.sun_path); -#endif /* HAVE_STRUCT_SOCKADDR_UN_SUN_LEN */ - - /* Quick check to see if we might succeed before we go to the trouble - of creating a socket. */ - if (access(addr.sun_path, W_OK) < 0) - { - if (errno != ENOENT) - zlog_err("%s: access to socket %s denied: %s", - dmn->name,addr.sun_path,safe_strerror(errno)); - return -1; - } - - if ((sock = socket (AF_UNIX, SOCK_STREAM, 0)) < 0) - { - zlog_err("%s(%s): cannot make socket: %s", - __func__,addr.sun_path, safe_strerror(errno)); - return -1; - } - - if (set_nonblocking(sock) < 0 || set_cloexec(sock) < 0) - { - zlog_err("%s(%s): set_nonblocking/cloexec(%d) failed", - __func__, addr.sun_path, sock); - close(sock); - return -1; - } - - if (connect (sock, (struct sockaddr *) &addr, len) < 0) - { - if ((errno != EINPROGRESS) && (errno != EWOULDBLOCK)) - { - if (gs.loglevel > LOG_DEBUG) - zlog_debug("%s(%s): connect failed: %s", - __func__,addr.sun_path, safe_strerror(errno)); - close (sock); - return -1; - } - if (gs.loglevel > LOG_DEBUG) - zlog_debug("%s: connection in progress",dmn->name); - dmn->state = DAEMON_CONNECTING; - dmn->fd = sock; - dmn->t_write = thread_add_write(master,check_connect,dmn,dmn->fd); - dmn->t_wakeup = thread_add_timer(master,wakeup_connect_hanging,dmn, - gs.timeout); - SET_READ_HANDLER(dmn); - return 0; - } - - dmn->fd = sock; - SET_READ_HANDLER(dmn); - daemon_up(dmn,"connect succeeded"); - return 1; -} - -static int -phase_hanging(struct thread *t_hanging) -{ - gs.t_phase_hanging = NULL; - zlog_err("Phase [%s] hanging for %ld seconds, aborting phased restart", - phase_str[gs.phase],PHASE_TIMEOUT); - gs.phase = PHASE_NONE; - return 0; -} - -static void -set_phase(restart_phase_t new_phase) -{ - gs.phase = new_phase; - if (gs.t_phase_hanging) - thread_cancel(gs.t_phase_hanging); - gs.t_phase_hanging = thread_add_timer(master,phase_hanging,NULL, - PHASE_TIMEOUT); -} - -static void -phase_check(void) -{ - switch (gs.phase) - { - case PHASE_NONE: - break; - case PHASE_STOPS_PENDING: - if (gs.numpids) - break; - zlog_info("Phased restart: all routing daemon stop jobs have completed."); - set_phase(PHASE_WAITING_DOWN); - /*FALLTHRU*/ - case PHASE_WAITING_DOWN: - if (gs.numdown+IS_UP(gs.special) < gs.numdaemons) - break; - zlog_info("Phased restart: all routing daemons now down."); - run_job(&gs.special->restart,"restart",gs.restart_command,1,1); - set_phase(PHASE_ZEBRA_RESTART_PENDING); - /*FALLTHRU*/ - case PHASE_ZEBRA_RESTART_PENDING: - if (gs.special->restart.pid) - break; - zlog_info("Phased restart: %s restart job completed.",gs.special->name); - set_phase(PHASE_WAITING_ZEBRA_UP); - /*FALLTHRU*/ - case PHASE_WAITING_ZEBRA_UP: - if (!IS_UP(gs.special)) - break; - zlog_info("Phased restart: %s is now up.",gs.special->name); - { - struct daemon *dmn; - for (dmn = gs.daemons; dmn; dmn = dmn->next) - { - if (dmn != gs.special) - run_job(&dmn->restart,"start",gs.start_command,1,0); - } - } - gs.phase = PHASE_NONE; - THREAD_OFF(gs.t_phase_hanging); - zlog_notice("Phased global restart has completed."); - break; - } -} - -static void -try_restart(struct daemon *dmn) -{ - switch (gs.mode) - { - case MODE_MONITOR: - return; - case MODE_GLOBAL_RESTART: - run_job(&gs.restart,"restart",gs.restart_command,0,1); - break; - case MODE_SEPARATE_RESTART: - run_job(&dmn->restart,"restart",gs.restart_command,0,1); - break; - case MODE_PHASED_ZEBRA_RESTART: - if (dmn != gs.special) - { - if ((gs.special->state == DAEMON_UP) && (gs.phase == PHASE_NONE)) - run_job(&dmn->restart,"restart",gs.restart_command,0,1); - else - zlog_debug("%s: postponing restart attempt because master %s daemon " - "not up [%s], or phased restart in progress", - dmn->name,gs.special->name,state_str[gs.special->state]); - break; - } - /*FALLTHRU*/ - case MODE_PHASED_ALL_RESTART: - if ((gs.phase != PHASE_NONE) || gs.numpids) - { - if (gs.loglevel > LOG_DEBUG+1) - zlog_debug("postponing phased global restart: restart already in " - "progress [%s], or outstanding child processes [%d]", - phase_str[gs.phase],gs.numpids); - break; - } - /* Is it too soon for a restart? */ - { - struct timeval delay; - if (time_elapsed(&delay,&gs.special->restart.time)->tv_sec < - gs.special->restart.interval) - { - if (gs.loglevel > LOG_DEBUG+1) - zlog_debug("postponing phased global restart: " - "elapsed time %ld < retry interval %ld", - (long)delay.tv_sec,gs.special->restart.interval); - break; - } - } - run_job(&gs.restart,"restart",gs.restart_command,0,1); - break; - default: - zlog_err("error: unknown restart mode %d",gs.mode); - break; - } -} - -static int -wakeup_unresponsive(struct thread *t_wakeup) -{ - struct daemon *dmn = THREAD_ARG(t_wakeup); - - dmn->t_wakeup = NULL; - if (dmn->state != DAEMON_UNRESPONSIVE) - zlog_err("%s: no longer unresponsive (now %s), " - "wakeup should have been cancelled!", - dmn->name,state_str[dmn->state]); - else - { - SET_WAKEUP_UNRESPONSIVE(dmn); - try_restart(dmn); - } - return 0; -} - -static int -wakeup_no_answer(struct thread *t_wakeup) -{ - struct daemon *dmn = THREAD_ARG(t_wakeup); - - dmn->t_wakeup = NULL; - dmn->state = DAEMON_UNRESPONSIVE; - zlog_err("%s state -> unresponsive : no response yet to ping " - "sent %ld seconds ago",dmn->name,gs.timeout); - if (gs.unresponsive_restart) - { - SET_WAKEUP_UNRESPONSIVE(dmn); - try_restart(dmn); - } - return 0; -} - -static int -wakeup_send_echo(struct thread *t_wakeup) -{ - static const char echocmd[] = "echo " PING_TOKEN; - ssize_t rc; - struct daemon *dmn = THREAD_ARG(t_wakeup); - - dmn->t_wakeup = NULL; - if (((rc = write(dmn->fd,echocmd,sizeof(echocmd))) < 0) || - ((size_t)rc != sizeof(echocmd))) - { - char why[100+sizeof(echocmd)]; - snprintf(why,sizeof(why),"write '%s' returned %d instead of %u", - echocmd,(int)rc,(u_int)sizeof(echocmd)); - daemon_down(dmn,why); - } - else - { - gettimeofday(&dmn->echo_sent,NULL); - dmn->t_wakeup = thread_add_timer(master,wakeup_no_answer,dmn,gs.timeout); - } - return 0; -} - -static void -sigint(void) -{ - zlog_notice("Terminating on signal"); - systemd_send_stopping (); - exit(0); -} - -static int -valid_command(const char *cmd) -{ - char *p; - - return ((p = strchr(cmd,'%')) != NULL) && (*(p+1) == 's') && !strchr(p+1,'%'); -} - -/* This is an ugly hack to circumvent problems with passing command-line - arguments that contain spaces. The fix is to use a configuration file. */ -static char * -translate_blanks(const char *cmd, const char *blankstr) -{ - char *res; - char *p; - size_t bslen = strlen(blankstr); - - if (!(res = strdup(cmd))) - { - perror("strdup"); - exit(1); - } - while ((p = strstr(res,blankstr)) != NULL) - { - *p = ' '; - if (bslen != 1) - memmove(p+1,p+bslen,strlen(p+bslen)+1); - } - return res; -} - -struct zebra_privs_t watchquagga_privs = -{ -#ifdef VTY_GROUP - .vty_group = VTY_GROUP, -#endif -}; - -int -main(int argc, char **argv) -{ - const char *progname; - int opt; - int daemon_mode = 0; - const char *pidfile = DEFAULT_PIDFILE; - const char *special = "zebra"; - const char *blankstr = NULL; - static struct quagga_signal_t my_signals[] = - { - { - .signal = SIGINT, - .handler = sigint, - }, - { - .signal = SIGTERM, - .handler = sigint, - }, - { - .signal = SIGCHLD, - .handler = sigchild, - }, - }; - - if ((progname = strrchr (argv[0], '/')) != NULL) - progname++; - else - progname = argv[0]; - - gs.restart.name = "all"; - while ((opt = getopt_long(argc, argv, "aAb:dek:l:m:M:i:p:r:R:S:s:t:T:zvh", - longopts, 0)) != EOF) - { - switch (opt) - { - case 0: - break; - case 'a': - if ((gs.mode != MODE_MONITOR) && (gs.mode != MODE_SEPARATE_RESTART)) - { - fputs("Ambiguous operating mode selected.\n",stderr); - return usage(progname,1); - } - gs.mode = MODE_PHASED_ZEBRA_RESTART; - break; - case 'A': - if ((gs.mode != MODE_MONITOR) && (gs.mode != MODE_SEPARATE_RESTART)) - { - fputs("Ambiguous operating mode selected.\n",stderr); - return usage(progname,1); - } - gs.mode = MODE_PHASED_ALL_RESTART; - break; - case 'b': - blankstr = optarg; - break; - case 'd': - daemon_mode = 1; - break; - case 'e': - gs.do_ping = 0; - break; - case 'k': - if (!valid_command(optarg)) - { - fprintf(stderr,"Invalid kill command, must contain '%%s': %s\n", - optarg); - return usage(progname,1); - } - gs.stop_command = optarg; - break; - case 'l': - { - char garbage[3]; - if ((sscanf(optarg,"%d%1s",&gs.loglevel,garbage) != 1) || - (gs.loglevel < LOG_EMERG)) - { - fprintf(stderr,"Invalid loglevel argument: %s\n",optarg); - return usage(progname,1); - } - } - break; - case 'm': - { - char garbage[3]; - if ((sscanf(optarg,"%ld%1s", - &gs.min_restart_interval,garbage) != 1) || - (gs.min_restart_interval < 0)) - { - fprintf(stderr,"Invalid min_restart_interval argument: %s\n", - optarg); - return usage(progname,1); - } - } - break; - case 'M': - { - char garbage[3]; - if ((sscanf(optarg,"%ld%1s", - &gs.max_restart_interval,garbage) != 1) || - (gs.max_restart_interval < 0)) - { - fprintf(stderr,"Invalid max_restart_interval argument: %s\n", - optarg); - return usage(progname,1); - } - } - break; - case 'i': - { - char garbage[3]; - int period; - if ((sscanf(optarg,"%d%1s",&period,garbage) != 1) || - (gs.period < 1)) - { - fprintf(stderr,"Invalid interval argument: %s\n",optarg); - return usage(progname,1); - } - gs.period = 1000*period; - } - break; - case 'p': - pidfile = optarg; - break; - case 'r': - if ((gs.mode == MODE_GLOBAL_RESTART) || - (gs.mode == MODE_SEPARATE_RESTART)) - { - fputs("Ambiguous operating mode selected.\n",stderr); - return usage(progname,1); - } - if (!valid_command(optarg)) - { - fprintf(stderr, - "Invalid restart command, must contain '%%s': %s\n", - optarg); - return usage(progname,1); - } - gs.restart_command = optarg; - if (gs.mode == MODE_MONITOR) - gs.mode = MODE_SEPARATE_RESTART; - break; - case 'R': - if (gs.mode != MODE_MONITOR) - { - fputs("Ambiguous operating mode selected.\n",stderr); - return usage(progname,1); - } - if (strchr(optarg,'%')) - { - fprintf(stderr, - "Invalid restart-all arg, must not contain '%%s': %s\n", - optarg); - return usage(progname,1); - } - gs.restart_command = optarg; - gs.mode = MODE_GLOBAL_RESTART; - break; - case 's': - if (!valid_command(optarg)) - { - fprintf(stderr,"Invalid start command, must contain '%%s': %s\n", - optarg); - return usage(progname,1); - } - gs.start_command = optarg; - break; - case 'S': - gs.vtydir = optarg; - break; - case 't': - { - char garbage[3]; - if ((sscanf(optarg,"%ld%1s",&gs.timeout,garbage) != 1) || - (gs.timeout < 1)) - { - fprintf(stderr,"Invalid timeout argument: %s\n",optarg); - return usage(progname,1); - } - } - break; - case 'T': - { - char garbage[3]; - if ((sscanf(optarg,"%ld%1s",&gs.restart_timeout,garbage) != 1) || - (gs.restart_timeout < 1)) - { - fprintf(stderr,"Invalid restart timeout argument: %s\n",optarg); - return usage(progname,1); - } - } - break; - case 'z': - gs.unresponsive_restart = 1; - break; - case 'v': - printf ("%s version %s\n", progname, FRR_VERSION); - puts("Copyright 2004 Andrew J. Schorr"); - return 0; - case 'h': - return usage(progname,0); - default: - fputs("Invalid option.\n",stderr); - return usage(progname,1); - } - } - - if (gs.unresponsive_restart && (gs.mode == MODE_MONITOR)) - { - fputs("Option -z requires a -r or -R restart option.\n",stderr); - return usage(progname,1); - } - switch (gs.mode) - { - case MODE_MONITOR: - if (gs.restart_command || gs.start_command || gs.stop_command) - { - fprintf(stderr,"No kill/(re)start commands needed for %s mode.\n", - mode_str[gs.mode]); - return usage(progname,1); - } - break; - case MODE_GLOBAL_RESTART: - case MODE_SEPARATE_RESTART: - if (!gs.restart_command || gs.start_command || gs.stop_command) - { - fprintf(stderr,"No start/kill commands needed in [%s] mode.\n", - mode_str[gs.mode]); - return usage(progname,1); - } - break; - case MODE_PHASED_ZEBRA_RESTART: - case MODE_PHASED_ALL_RESTART: - if (!gs.restart_command || !gs.start_command || !gs.stop_command) - { - fprintf(stderr, - "Need start, kill, and restart commands in [%s] mode.\n", - mode_str[gs.mode]); - return usage(progname,1); - } - break; - } - - if (blankstr) - { - if (gs.restart_command) - gs.restart_command = translate_blanks(gs.restart_command,blankstr); - if (gs.start_command) - gs.start_command = translate_blanks(gs.start_command,blankstr); - if (gs.stop_command) - gs.stop_command = translate_blanks(gs.stop_command,blankstr); - } - - gs.restart.interval = gs.min_restart_interval; - - zprivs_init (&watchquagga_privs); - - master = thread_master_create(); - cmd_init(-1); - memory_init(); - vty_init(master); - watchquagga_vty_init(); - vty_serv_sock(NULL, 0, WATCHQUAGGA_VTYSH_PATH); - - signal_init (master, array_size(my_signals), my_signals); - srandom(time(NULL)); - - { - int i; - struct daemon *tail = NULL; - - for (i = optind; i < argc; i++) - { - struct daemon *dmn; - - if (!(dmn = (struct daemon *)calloc(1,sizeof(*dmn)))) - { - fprintf(stderr,"calloc(1,%u) failed: %s\n", - (u_int)sizeof(*dmn), safe_strerror(errno)); - return 1; - } - dmn->name = dmn->restart.name = argv[i]; - dmn->state = DAEMON_INIT; - gs.numdaemons++; - gs.numdown++; - dmn->fd = -1; - dmn->t_wakeup = thread_add_timer_msec(master,wakeup_init,dmn, - 100+(random() % 900)); - dmn->restart.interval = gs.min_restart_interval; - if (tail) - tail->next = dmn; - else - gs.daemons = dmn; - tail = dmn; - - if (((gs.mode == MODE_PHASED_ZEBRA_RESTART) || - (gs.mode == MODE_PHASED_ALL_RESTART)) && - !strcmp(dmn->name,special)) - gs.special = dmn; - } - } - if (!gs.daemons) - { - fputs("Must specify one or more daemons to monitor.\n",stderr); - return usage(progname,1); - } - if (((gs.mode == MODE_PHASED_ZEBRA_RESTART) || - (gs.mode == MODE_PHASED_ALL_RESTART)) && !gs.special) - { - fprintf(stderr,"In mode [%s], but cannot find master daemon %s\n", - mode_str[gs.mode],special); - return usage(progname,1); - } - - zlog_default = openzlog(progname, ZLOG_WATCHQUAGGA, 0, - LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); - zlog_set_level(NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED); - if (daemon_mode) - { - zlog_set_level(NULL, ZLOG_DEST_SYSLOG, MIN(gs.loglevel,LOG_DEBUG)); - if (daemon (0, 0) < 0) - { - fprintf(stderr, "Watchquagga daemon failed: %s", strerror(errno)); - exit (1); - } - } - else - zlog_set_level(NULL, ZLOG_DEST_STDOUT, MIN(gs.loglevel,LOG_DEBUG)); - - /* Make sure we're not already running. */ - pid_output (pidfile); - - /* Announce which daemons are being monitored. */ - { - struct daemon *dmn; - size_t len = 0; - - for (dmn = gs.daemons; dmn; dmn = dmn->next) - len += strlen(dmn->name)+1; - - { - char buf[len+1]; - char *p = buf; - - for (dmn = gs.daemons; dmn; dmn = dmn->next) - { - if (p != buf) - *p++ = ' '; - strcpy(p,dmn->name); - p += strlen(p); - } - zlog_notice("%s %s watching [%s], mode [%s]", - progname, FRR_VERSION, buf, mode_str[gs.mode]); - } - } - - { - struct thread thread; - - while (thread_fetch (master, &thread)) - thread_call (&thread); - } - - systemd_send_stopping (); - /* Not reached. */ - return 0; -} diff --git a/watchquagga/watchquagga.h b/watchquagga/watchquagga.h deleted file mode 100644 index ecadf22c56..0000000000 --- a/watchquagga/watchquagga.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - Common definitions for watchquagga API socket. - - 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 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; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef QUAGGA_WATCHQUAGGA_H -#define QUAGGA_WATCHQUAGGA_H - -extern void watchquagga_vty_init(void); - -extern pid_t integrated_write_pid; -extern void integrated_write_sigchld(int status); - -#endif /* QUAGGA_WATCHQUAGGA_H */ diff --git a/watchquagga/watchquagga_vty.c b/watchquagga/watchquagga_vty.c deleted file mode 100644 index b96011b760..0000000000 --- a/watchquagga/watchquagga_vty.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - watchquagga CLI functions. - - 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 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; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include - -#include "memory.h" -#include "log.h" -#include "vty.h" -#include "command.h" - -#include "watchquagga.h" - -pid_t integrated_write_pid; -static int integrated_result_fd; - -DEFUN (config_write_integrated, - config_write_integrated_cmd, - "write integrated", - "Write running configuration to memory, network, or terminal\n" - "Write integrated all-daemon Quagga.conf file\n") -{ - pid_t child; - sigset_t oldmask, sigmask; - - if (integrated_write_pid != -1) { - vty_out(vty, "%% configuration write already in progress.%s", - VTY_NEWLINE); - return CMD_WARNING; - } - - fflush(stdout); - fflush(stderr); - - /* need to temporarily block SIGCHLD because it could arrive between - * fork() call and setting the integrated_write_pid variable. This - * would mean the completion call gets lost and this hangs forever. - */ - sigemptyset(&oldmask); - sigemptyset(&sigmask); - sigaddset(&sigmask, SIGCHLD); - sigprocmask(SIG_BLOCK, &sigmask, &oldmask); - - child = fork(); - if (child == -1) { - vty_out(vty, "%% configuration write fork() failed: %s.%s", - safe_strerror(errno), VTY_NEWLINE); - sigprocmask(SIG_SETMASK, &oldmask, NULL); - return CMD_WARNING; - } - if (child != 0) { - /* note: the VTY won't write a command return value to vtysh; the - * session temporarily enters an intentional "hang" state. This is - * to make sure latency in vtysh doing the config write (several - * seconds is not rare to see) does not interfere with watchquagga's - * supervisor job. - * - * The fd is duplicated here so we don't need to hold a vty pointer - * (which could become invalid in the meantime). - */ - integrated_write_pid = child; - integrated_result_fd = dup(vty->wfd); - sigprocmask(SIG_SETMASK, &oldmask, NULL); - return CMD_SUSPEND; - } - - /* redirect stdout/stderr to vty session. Note vty->wfd is marked - * CLOEXEC, but dup2 will clear that flag. */ - dup2(vty->wfd, 1); - dup2(vty->wfd, 2); - - /* don't allow the user to pass parameters, we're root here! - * should probably harden vtysh at some point too... */ - execl(VTYSH_BIN_PATH, "vtysh", "-w", NULL); - - /* unbuffered write; we just messed with stdout... */ - char msg[512]; - snprintf(msg, sizeof(msg), "error executing %s: %s\n", - VTYSH_BIN_PATH, safe_strerror(errno)); - write(1, msg, strlen(msg)); - exit(1); -} - -void integrated_write_sigchld(int status) -{ - uint8_t reply[4] = { 0, 0, 0, CMD_WARNING }; - - if (WIFEXITED(status)) { - zlog_info("configuration write completed with exit code %d", - WEXITSTATUS(status)); - reply[3] = WEXITSTATUS(status); - } else if (WIFSIGNALED(status)) { - zlog_warn("configuration write terminated by signal %d", - WTERMSIG(status)); - } else { - zlog_warn("configuration write terminated"); - } - - if (reply[3] != CMD_SUCCESS) { - /* failure might be silent in vtysh without this */ - static const char msg[] = "% Configuration write failed.\n"; - write(integrated_result_fd, msg, strlen(msg)); - } - - /* don't care about failures here, if the connection is broken the - * return value will just be lost. */ - write(integrated_result_fd, reply, sizeof(reply)); - close(integrated_result_fd); - - integrated_write_pid = -1; -} - -void watchquagga_vty_init(void) -{ - integrated_write_pid = -1; - install_element(ENABLE_NODE, &config_write_integrated_cmd); -} -- cgit v1.2.3