]> git.proxmox.com Git - mirror_frr.git/blobdiff - zebra/zserv.c
Merge remote-tracking branch 'frr/master' into tcp-zebra
[mirror_frr.git] / zebra / zserv.c
index 97f7122774887df5bae9d29b18049a1740aa3752..a3a8c11c51c33a6adaa66499b81a642736a2edf4 100644 (file)
@@ -19,6 +19,7 @@
  */
 
 #include <zebra.h>
+#include <sys/un.h>
 
 #include "prefix.h"
 #include "command.h"
@@ -38,6 +39,7 @@
 #include "buffer.h"
 #include "nexthop.h"
 #include "vrf.h"
+#include "libfrr.h"
 
 #include "zebra/zserv.h"
 #include "zebra/zebra_ns.h"
@@ -1085,6 +1087,27 @@ int zsend_router_id_update(struct zserv *client, struct prefix *p,
        return zebra_server_send_message(client);
 }
 
+/*
+ * Function used by Zebra to send a PW status update to LDP daemon
+ */
+int zsend_pw_update(struct zserv *client, struct zebra_pw *pw)
+{
+       struct stream *s;
+
+       s = client->obuf;
+       stream_reset(s);
+
+       zserv_create_header(s, ZEBRA_PW_STATUS_UPDATE, pw->vrf_id);
+       stream_write(s, pw->ifname, IF_NAMESIZE);
+       stream_putl(s, pw->ifindex);
+       stream_putl(s, pw->status);
+
+       /* Put length at the first point of the stream. */
+       stream_putw_at(s, 0, stream_get_endp(s));
+
+       return zebra_server_send_message(client);
+}
+
 /* Register zebra server interface information.  Send current all
    interface and address information. */
 static int zread_interface_add(struct zserv *client, u_short length,
@@ -1877,14 +1900,12 @@ static void zread_mpls_labels(int command, struct zserv *client, u_short length,
        if (command == ZEBRA_MPLS_LABELS_ADD) {
                mpls_lsp_install(zvrf, type, in_label, out_label, gtype, &gate,
                                 ifindex);
-               if (out_label != MPLS_IMP_NULL_LABEL)
-                       mpls_ftn_update(1, zvrf, type, &prefix, gtype, &gate,
-                                       ifindex, distance, out_label);
+               mpls_ftn_update(1, zvrf, type, &prefix, gtype, &gate, ifindex,
+                               distance, out_label);
        } else if (command == ZEBRA_MPLS_LABELS_DELETE) {
                mpls_lsp_uninstall(zvrf, type, in_label, gtype, &gate, ifindex);
-               if (out_label != MPLS_IMP_NULL_LABEL)
-                       mpls_ftn_update(0, zvrf, type, &prefix, gtype, &gate,
-                                       ifindex, distance, out_label);
+               mpls_ftn_update(0, zvrf, type, &prefix, gtype, &gate, ifindex,
+                               distance, out_label);
        }
 }
 /* Send response to a label manager connect request to client */
@@ -2039,6 +2060,97 @@ static void zread_label_manager_request(int cmd, struct zserv *client,
        }
 }
 
+static int zread_pseudowire(int command, struct zserv *client, u_short length,
+                           vrf_id_t vrf_id)
+{
+       struct stream *s;
+       struct zebra_vrf *zvrf;
+       char ifname[IF_NAMESIZE];
+       ifindex_t ifindex;
+       int type;
+       int af;
+       union g_addr nexthop;
+       uint32_t local_label;
+       uint32_t remote_label;
+       uint8_t flags;
+       union pw_protocol_fields data;
+       uint8_t protocol;
+       struct zebra_pw *pw;
+
+       zvrf = vrf_info_lookup(vrf_id);
+       if (!zvrf)
+               return -1;
+
+       /* Get input stream.  */
+       s = client->ibuf;
+
+       /* Get data. */
+       stream_get(ifname, s, IF_NAMESIZE);
+       ifindex = stream_getl(s);
+       type = stream_getl(s);
+       af = stream_getl(s);
+       switch (af) {
+       case AF_INET:
+               nexthop.ipv4.s_addr = stream_get_ipv4(s);
+               break;
+       case AF_INET6:
+               stream_get(&nexthop.ipv6, s, 16);
+               break;
+       default:
+               return -1;
+       }
+       local_label = stream_getl(s);
+       remote_label = stream_getl(s);
+       flags = stream_getc(s);
+       stream_get(&data, s, sizeof(data));
+       protocol = client->proto;
+
+       pw = zebra_pw_find(zvrf, ifname);
+       switch (command) {
+       case ZEBRA_PW_ADD:
+               if (pw) {
+                       zlog_warn("%s: pseudowire %s already exists [%s]",
+                                 __func__, ifname,
+                                 zserv_command_string(command));
+                       return -1;
+               }
+
+               zebra_pw_add(zvrf, ifname, protocol, client);
+               break;
+       case ZEBRA_PW_DELETE:
+               if (!pw) {
+                       zlog_warn("%s: pseudowire %s not found [%s]", __func__,
+                                 ifname, zserv_command_string(command));
+                       return -1;
+               }
+
+               zebra_pw_del(zvrf, pw);
+               break;
+       case ZEBRA_PW_SET:
+       case ZEBRA_PW_UNSET:
+               if (!pw) {
+                       zlog_warn("%s: pseudowire %s not found [%s]", __func__,
+                                 ifname, zserv_command_string(command));
+                       return -1;
+               }
+
+               switch (command) {
+               case ZEBRA_PW_SET:
+                       pw->enabled = 1;
+                       break;
+               case ZEBRA_PW_UNSET:
+                       pw->enabled = 0;
+                       break;
+               }
+
+               zebra_pw_change(pw, ifindex, type, af, &nexthop, local_label,
+                               remote_label, flags, &data);
+               break;
+       }
+
+       return 0;
+}
+
 /* Cleanup registered nexthops (across VRFs) upon client disconnect. */
 static void zebra_client_close_cleanup_rnh(struct zserv *client)
 {
@@ -2083,6 +2195,9 @@ static void zebra_client_close(struct zserv *client)
        zebra_mpls_cleanup_fecs_for_client(vrf_info_lookup(VRF_DEFAULT),
                                           client);
 
+       /* Remove pseudowires associated with this client */
+       zebra_pw_client_close(client);
+
        /* Close file descriptor. */
        if (client->sock) {
                unsigned long nroutes;
@@ -2436,6 +2551,12 @@ static int zebra_client_read(struct thread *thread)
        case ZEBRA_INTERFACE_SET_MASTER:
                zread_interface_set_master(client, sock, length);
                break;
+       case ZEBRA_PW_ADD:
+       case ZEBRA_PW_DELETE:
+       case ZEBRA_PW_SET:
+       case ZEBRA_PW_UNSET:
+               zread_pseudowire(command, client, length, vrf_id);
+               break;
        default:
                zlog_info("Zebra received unknown command %d", command);
                break;
@@ -2486,116 +2607,59 @@ static int zebra_accept(struct thread *thread)
        return 0;
 }
 
-#ifdef HAVE_TCP_ZEBRA
-/* Make zebra's server socket. */
-static void zebra_serv()
-{
-       int ret;
-       int accept_sock;
-       struct sockaddr_in addr;
-
-       accept_sock = socket(AF_INET, SOCK_STREAM, 0);
-
-       if (accept_sock < 0) {
-               zlog_warn("Can't create zserv stream socket: %s",
-                         safe_strerror(errno));
-               zlog_warn(
-                       "zebra can't provice full functionality due to above error");
-               return;
-       }
-
-       memset(&addr, 0, sizeof(struct sockaddr_in));
-       addr.sin_family = AF_INET;
-       addr.sin_port = htons(ZEBRA_PORT);
-#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
-       addr.sin_len = sizeof(struct sockaddr_in);
-#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
-       addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-
-       sockopt_reuseaddr(accept_sock);
-       sockopt_reuseport(accept_sock);
-
-       if (zserv_privs.change(ZPRIVS_RAISE))
-               zlog_err("Can't raise privileges");
-
-       ret = bind(accept_sock, (struct sockaddr *)&addr,
-                  sizeof(struct sockaddr_in));
-       if (ret < 0) {
-               zlog_warn("Can't bind to stream socket: %s",
-                         safe_strerror(errno));
-               zlog_warn(
-                       "zebra can't provice full functionality due to above error");
-               close(accept_sock); /* Avoid sd leak. */
-               return;
-       }
-
-       if (zserv_privs.change(ZPRIVS_LOWER))
-               zlog_err("Can't lower privileges");
-
-       ret = listen(accept_sock, 1);
-       if (ret < 0) {
-               zlog_warn("Can't listen to stream socket: %s",
-                         safe_strerror(errno));
-               zlog_warn(
-                       "zebra can't provice full functionality due to above error");
-               close(accept_sock); /* Avoid sd leak. */
-               return;
-       }
-
-       zebra_event(ZEBRA_SERV, accept_sock, NULL);
-}
-#else /* HAVE_TCP_ZEBRA */
-
-/* For sockaddr_un. */
-#include <sys/un.h>
-
-/* zebra server UNIX domain socket. */
-static void zebra_serv_un(const char *path)
+/* Make zebra server socket, wiping any existing one (see bug #403). */
+void zebra_zserv_socket_init(char *path)
 {
        int ret;
-       int sock, len;
-       struct sockaddr_un serv;
+       int sock;
        mode_t old_mask;
+       struct sockaddr_storage sa;
+       socklen_t sa_len;
 
-       /* First of all, unlink existing socket */
-       unlink(path);
+       if (!frr_zclient_addr(&sa, &sa_len, path))
+               /* should be caught in zebra main() */
+               return;
 
        /* Set umask */
        old_mask = umask(0077);
 
        /* Make UNIX domain socket. */
-       sock = socket(AF_UNIX, SOCK_STREAM, 0);
+       sock = socket(sa.ss_family, SOCK_STREAM, 0);
        if (sock < 0) {
-               zlog_warn("Can't create zserv unix socket: %s",
+               zlog_warn("Can't create zserv socket: %s",
                          safe_strerror(errno));
                zlog_warn(
                        "zebra can't provide full functionality due to above error");
                return;
        }
 
-       /* Make server socket. */
-       memset(&serv, 0, sizeof(struct sockaddr_un));
-       serv.sun_family = AF_UNIX;
-       strncpy(serv.sun_path, path, strlen(path));
-#ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
-       len = serv.sun_len = SUN_LEN(&serv);
-#else
-       len = sizeof(serv.sun_family) + strlen(serv.sun_path);
-#endif /* HAVE_STRUCT_SOCKADDR_UN_SUN_LEN */
-
-       ret = bind(sock, (struct sockaddr *)&serv, len);
+       if (sa.ss_family != AF_UNIX) {
+               sockopt_reuseaddr(sock);
+               sockopt_reuseport(sock);
+       } else {
+               struct sockaddr_un *suna = (struct sockaddr_un *)&sa;
+               if (suna->sun_path[0])
+                       unlink(suna->sun_path);
+       }
+
+       if (zserv_privs.change(ZPRIVS_RAISE))
+               zlog_err("Can't raise privileges");
+
+       ret = bind(sock, (struct sockaddr *)&sa, sa_len);
        if (ret < 0) {
-               zlog_warn("Can't bind to unix socket %s: %s", path,
+               zlog_warn("Can't bind zserv socket on %s: %s", path,
                          safe_strerror(errno));
                zlog_warn(
                        "zebra can't provide full functionality due to above error");
                close(sock);
                return;
        }
+       if (zserv_privs.change(ZPRIVS_LOWER))
+               zlog_err("Can't lower privileges");
 
        ret = listen(sock, 5);
        if (ret < 0) {
-               zlog_warn("Can't listen to unix socket %s: %s", path,
+               zlog_warn("Can't listen to zserv socket %s: %s", path,
                          safe_strerror(errno));
                zlog_warn(
                        "zebra can't provide full functionality due to above error");
@@ -2607,7 +2671,6 @@ static void zebra_serv_un(const char *path)
 
        zebra_event(ZEBRA_SERV, sock, NULL);
 }
-#endif /* HAVE_TCP_ZEBRA */
 
 
 static void zebra_event(enum event event, int sock, struct zserv *client)
@@ -2647,10 +2710,6 @@ static char *zserv_time_buf(time_t *time1, char *buf, int buflen)
        now -= *time1;
        tm = gmtime(&now);
 
-/* Making formatted timer strings. */
-#define ONE_DAY_SECOND 60*60*24
-#define ONE_WEEK_SECOND 60*60*24*7
-
        if (now < ONE_DAY_SECOND)
                snprintf(buf, buflen, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min,
                         tm->tm_sec);
@@ -3050,13 +3109,3 @@ void zebra_init(void)
        /* Route-map */
        zebra_route_map_init();
 }
-
-/* Make zebra server socket, wiping any existing one (see bug #403). */
-void zebra_zserv_socket_init(char *path)
-{
-#ifdef HAVE_TCP_ZEBRA
-       zebra_serv();
-#else
-       zebra_serv_un(path ? path : ZEBRA_SERV_PATH);
-#endif /* HAVE_TCP_ZEBRA */
-}