summaryrefslogtreecommitdiffstats
path: root/vtysh
diff options
context:
space:
mode:
authorDonald Sharp <sharpd@cumulusnetworks.com>2015-05-20 03:03:42 +0200
committerDonald Sharp <sharpd@cumulusnetworks.com>2015-05-20 03:03:42 +0200
commit7c8ff89e9346227f0e721f7686d4c4d58f9c9135 (patch)
tree7a5f73baf68e31220396e2391cdd216cdf981d51 /vtysh
parentinitd: initd-mi.patch (diff)
downloadfrr-7c8ff89e9346227f0e721f7686d4c4d58f9c9135.tar.xz
frr-7c8ff89e9346227f0e721f7686d4c4d58f9c9135.zip
Multi-Instance OSPF Summary
——————————————------------- - etc/init.d/quagga is modified to support creating separate ospf daemon process for each instance. Each individual instance is monitored by watchquagga just like any protocol daemons.(requires initd-mi.patch). - Vtysh is modified to able to connect to multiple daemons of the same protocol (supported for OSPF only for now). - ospfd is modified to remember the Instance-ID that its invoked with. For the entire life of the process it caters to any command request that matches that instance-ID (unless its a non instance specific command). Routes/messages to zebra are tagged with instance-ID. - zebra route/redistribute mechanisms are modified to work with [protocol type + instance-id] - bgpd now has ability to have multiple instance specific redistribution for a protocol (OSPF only supported/tested for now). - zlog ability to display instance-id besides the protocol/daemon name. - Changes in other daemons are to because of the needed integration with some of the modified APIs/routines. (Didn’t prefer replicating too many separate instance specific APIs.) - config/show/debug commands are modified to take instance-id argument as appropriate. Guidelines to start using multi-instance ospf --------------------------------------------- The patch is backward compatible, i.e for any previous way of single ospf deamon(router ospf <cr>) will continue to work as is, including all the show commands etc. To enable multiple instances, do the following: 1. service quagga stop 2. Modify /etc/quagga/daemons to add instance-ids of each desired instance in the following format: ospfd=“yes" ospfd_instances="1,2,3" assuming you want to enable 3 instances with those instance ids. 3. Create corresponding ospfd config files as ospfd-1.conf, ospfd-2.conf and ospfd-3.conf. 4. service quagga start/restart 5. Verify that the deamons are started as expected. You should see ospfd started with -n <instance-id> option. ps –ef | grep quagga With that /var/run/quagga/ should have ospfd-<instance-id>.pid and ospfd-<instance-id>/vty to each instance. 6. vtysh to work with instances as you would with any other deamons. 7. Overall most quagga semantics are the same working with the instance deamon, like it is for any other daemon. NOTE: To safeguard against errors leading to too many processes getting invoked, a hard limit on number of instance-ids is in place, currently its 5. Allowed instance-id range is <1-65535> Once daemons are up, show running from vtysh should show the instance-id of each daemon as 'router ospf <instance-id>’ (without needing explicit configuration) Instance-id can not be changed via vtysh, other router ospf configuration is allowed as before. Signed-off-by: Vipin Kumar <vipin@cumulusnetworks.com> Reviewed-by: Daniel Walton <dwalton@cumulusnetworks.com> Reviewed-by: Dinesh G Dutt <ddutt@cumulusnetworks.com>
Diffstat (limited to 'vtysh')
-rwxr-xr-xvtysh/extract.pl.in2
-rw-r--r--vtysh/vtysh.c198
2 files changed, 184 insertions, 16 deletions
diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in
index 49788363e..2249b4092 100755
--- a/vtysh/extract.pl.in
+++ b/vtysh/extract.pl.in
@@ -35,7 +35,7 @@ $ignore{'"ip vrf NAME"'} = "ignore";
$ignore{'"router rip"'} = "ignore";
$ignore{'"router ripng"'} = "ignore";
$ignore{'"router ospf"'} = "ignore";
-$ignore{'"router ospf <0-65535>"'} = "ignore";
+$ignore{'"router ospf <1-65535>"'} = "ignore";
$ignore{'"router ospf6"'} = "ignore";
$ignore{'"router babel"'} = "ignore";
$ignore{'"router bgp " "<1-4294967295>"'} = "ignore";
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index f6d82972d..2534e8ae1 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -30,6 +30,10 @@
#include <readline/readline.h>
#include <readline/history.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <string.h>
+
#include "command.h"
#include "memory.h"
#include "vtysh/vtysh.h"
@@ -46,19 +50,22 @@ char *vtysh_pager_name = NULL;
struct vtysh_client
{
int fd;
- const char *name;
+ char *name;
int flag;
- const char *path;
-} vtysh_client[] =
-{
- { .fd = -1, .name = "zebra", .flag = VTYSH_ZEBRA, .path = ZEBRA_VTYSH_PATH},
- { .fd = -1, .name = "ripd", .flag = VTYSH_RIPD, .path = RIP_VTYSH_PATH},
- { .fd = -1, .name = "ripngd", .flag = VTYSH_RIPNGD, .path = RIPNG_VTYSH_PATH},
- { .fd = -1, .name = "ospfd", .flag = VTYSH_OSPFD, .path = OSPF_VTYSH_PATH},
- { .fd = -1, .name = "ospf6d", .flag = VTYSH_OSPF6D, .path = OSPF6_VTYSH_PATH},
- { .fd = -1, .name = "bgpd", .flag = VTYSH_BGPD, .path = BGP_VTYSH_PATH},
- { .fd = -1, .name = "isisd", .flag = VTYSH_ISISD, .path = ISIS_VTYSH_PATH},
- { .fd = -1, .name = "babeld", .flag = VTYSH_BABELD, .path = BABEL_VTYSH_PATH},
+ char *path;
+ struct vtysh_client *next;
+};
+
+struct vtysh_client vtysh_client[] =
+{
+ { .fd = -1, .name = "zebra", .flag = VTYSH_ZEBRA, .path = ZEBRA_VTYSH_PATH, .next = NULL},
+ { .fd = -1, .name = "ripd", .flag = VTYSH_RIPD, .path = RIP_VTYSH_PATH, .next = NULL},
+ { .fd = -1, .name = "ripngd", .flag = VTYSH_RIPNGD, .path = RIPNG_VTYSH_PATH, .next = NULL},
+ { .fd = -1, .name = "ospfd", .flag = VTYSH_OSPFD, .path = OSPF_VTYSH_PATH, .next = NULL},
+ { .fd = -1, .name = "ospf6d", .flag = VTYSH_OSPF6D, .path = OSPF6_VTYSH_PATH, .next = NULL},
+ { .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 = "babeld", .flag = VTYSH_BABELD, .path = BABEL_VTYSH_PATH, .next = NULL},
};
@@ -88,7 +95,7 @@ vclient_close (struct vtysh_client *vclient)
* under load - it SHOULD handle it. */
#define ERR_WHERE_STRING "vtysh(): vtysh_client_config(): "
static int
-vtysh_client_config (struct vtysh_client *vclient, char *line)
+vtysh_client_config_one (struct vtysh_client *vclient, char *line)
{
int ret;
char *buf;
@@ -186,7 +193,28 @@ vtysh_client_config (struct vtysh_client *vclient, char *line)
}
static int
-vtysh_client_execute (struct vtysh_client *vclient, const char *line, FILE *fp)
+vtysh_client_config (struct vtysh_client *head_client, char *line)
+{
+ struct vtysh_client *client;
+ int rc;
+
+ rc = vtysh_client_config_one(head_client, line);
+ if (rc != CMD_SUCCESS)
+ return rc;
+
+ client = head_client->next;
+ while (client)
+ {
+ rc = vtysh_client_config_one(client, line);
+ if (rc != CMD_SUCCESS)
+ return rc;
+ client = client->next;
+ }
+ return CMD_SUCCESS;
+}
+
+static int
+vtysh_client_execute_one (struct vtysh_client *vclient, const char *line, FILE *fp)
{
int ret;
char buf[1001];
@@ -250,6 +278,27 @@ vtysh_client_execute (struct vtysh_client *vclient, const char *line, FILE *fp)
}
}
+static int
+vtysh_client_execute (struct vtysh_client *head_client, const char *line, FILE *fp)
+{
+ struct vtysh_client *client;
+ int rc;
+
+ rc = vtysh_client_execute_one(head_client, line, fp);
+ if (rc != CMD_SUCCESS)
+ return rc;
+
+ client = head_client->next;
+ while (client)
+ {
+ rc = vtysh_client_execute_one(client, line, fp);
+ if (rc != CMD_SUCCESS)
+ return rc;
+ client = client->next;
+ }
+ return CMD_SUCCESS;
+}
+
void
vtysh_exit_ripd_only (void)
{
@@ -1005,6 +1054,14 @@ DEFUNSH (VTYSH_OSPFD,
return CMD_SUCCESS;
}
+ALIAS_SH (VTYSH_OSPFD,
+ router_ospf,
+ router_ospf_instance_cmd,
+ "router ospf <1-65535>",
+ "Enable a routing process\n"
+ "Start OSPF configuration\n"
+ "Instance ID\n")
+
DEFUNSH (VTYSH_OSPF6D,
router_ospf6,
router_ospf6_cmd,
@@ -2177,6 +2234,114 @@ vtysh_connect (struct vtysh_client *vclient)
return 0;
}
+/* Return true if str begins with prefix, else return false */
+static int
+begins_with(const char *str, const char *prefix)
+{
+ if (!str || !prefix)
+ return 0;
+ size_t lenstr = strlen(str);
+ size_t lenprefix = strlen(prefix);
+ if (lenprefix > lenstr)
+ return 0;
+ return strncmp(str, prefix, lenprefix) == 0;
+}
+
+/* Return true if str ends with suffix, else return false */
+static int
+ends_with(const char *str, const char *suffix)
+{
+ if (!str || !suffix)
+ return 0;
+ size_t lenstr = strlen(str);
+ size_t lensuffix = strlen(suffix);
+ if (lensuffix > lenstr)
+ return 0;
+ return strncmp(str + lenstr - lensuffix, suffix, lensuffix) == 0;
+}
+
+static void
+vtysh_client_sorted_insert (struct vtysh_client *head_client,
+ struct vtysh_client *client)
+{
+ struct vtysh_client *prev_node, *current_node;
+
+ prev_node = head_client;
+ current_node = head_client->next;
+ while (current_node)
+ {
+ if (strcmp(current_node->path, client->path) > 0)
+ break;
+
+ prev_node = current_node;
+ current_node = current_node->next;
+ }
+ client->next = current_node;
+ prev_node->next = client;
+}
+
+#define MAXIMUM_INSTANCES 10
+
+static void
+vtysh_update_all_insances(struct vtysh_client * head_client)
+{
+ struct vtysh_client *client;
+ char *path;
+ DIR *dir;
+ struct dirent *file;
+ int n = 0;
+
+ if (head_client->flag != VTYSH_OSPFD) return;
+
+ /* ls /var/run/quagga/ and look for all files ending in .vty */
+ dir = opendir("/var/run/quagga/");
+ if (dir)
+ {
+ while ((file = readdir(dir)) != NULL)
+ {
+ if (begins_with(file->d_name, "ospfd-") && ends_with(file->d_name, ".vty"))
+ {
+ if (n == MAXIMUM_INSTANCES)
+ {
+ fprintf(stderr,
+ "Parsing /var/run/quagga/, client limit(%d) reached!\n", n);
+ break;
+ }
+ client = (struct vtysh_client *) malloc(sizeof(struct vtysh_client));
+ client->fd = -1;
+ client->name = (char *) malloc(10);
+ strcpy(client->name, "ospfd");
+ client->flag = VTYSH_OSPFD;
+ client->path = (char *) malloc(100);
+ sprintf(client->path, "/var/run/quagga/%s", file->d_name);
+ client->next = NULL;
+ vtysh_client_sorted_insert(head_client, client);
+ n++;
+ }
+ }
+ closedir(dir);
+ }
+}
+
+int
+vtysh_connect_all_instances (struct vtysh_client *head_client)
+{
+ struct vtysh_client *client;
+ int rc = 0;
+
+ vtysh_update_all_insances(head_client);
+
+ client = head_client->next;
+ while (client)
+ {
+ if (vtysh_connect(client) == 0)
+ rc++;
+ client = client->next;
+ }
+
+ return rc;
+}
+
int
vtysh_connect_all(const char *daemon_name)
{
@@ -2194,7 +2359,9 @@ vtysh_connect_all(const char *daemon_name)
/* We need direct access to ripd in vtysh_exit_ripd_only. */
if (vtysh_client[i].flag == VTYSH_RIPD)
ripd_client = &vtysh_client[i];
- }
+
+ rc += vtysh_connect_all_instances(&vtysh_client[i]);
+ }
}
if (!matches)
fprintf(stderr, "Error: no daemons match name %s!\n", daemon_name);
@@ -2368,6 +2535,7 @@ vtysh_init_vty (void)
install_element (CONFIG_NODE, &router_ripng_cmd);
#endif
install_element (CONFIG_NODE, &router_ospf_cmd);
+ install_element (CONFIG_NODE, &router_ospf_instance_cmd);
#ifdef HAVE_IPV6
install_element (CONFIG_NODE, &router_ospf6_cmd);
#endif