]> git.puffer.fish Git - matthieu/frr.git/commitdiff
zebra: add support for static pseudowires
authorRenato Westphal <renato@opensourcerouting.org>
Tue, 1 Aug 2017 23:16:28 +0000 (20:16 -0300)
committerRenato Westphal <renato@opensourcerouting.org>
Wed, 2 Aug 2017 00:12:13 +0000 (21:12 -0300)
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
lib/command.c
lib/command.h
lib/vty.c
vtysh/Makefile.am
vtysh/vtysh.c
vtysh/vtysh_config.c
zebra/main.c
zebra/zebra_pw.c
zebra/zebra_pw.h
zebra/zebra_rnh.c
zebra/zebra_vrf.h

index 4912461adb2395108ab94cda88a1210c6fa40fde..c2ee79035af014cedf11e57831ba025bca3cab43 100644 (file)
@@ -1392,6 +1392,7 @@ cmd_exit (struct vty *vty)
       vty_config_unlock (vty);
       break;
     case INTERFACE_NODE:
+    case PW_NODE:
     case NS_NODE:
     case VRF_NODE:
     case ZEBRA_NODE:
@@ -1471,6 +1472,7 @@ DEFUN (config_end,
       break;
     case CONFIG_NODE:
     case INTERFACE_NODE:
+    case PW_NODE:
     case NS_NODE:
     case VRF_NODE:
     case ZEBRA_NODE:
index 223f028144ac218936342cd355ec838e146c444d..313d73f7c88f873ae339725900d9451b7e95c8ef 100644 (file)
@@ -130,6 +130,7 @@ enum node_type
   FORWARDING_NODE,              /* IP forwarding node. */
   PROTOCOL_NODE,                /* protocol filtering node */
   MPLS_NODE,                    /* MPLS config node */
+  PW_NODE,                      /* Pseudowire config node */
   VTY_NODE,                     /* Vty node. */
   LINK_PARAMS_NODE,             /* Link-parameters node */
 };
index e7e0f17e6787fb28ad5ac63615dc9f6e825ca2a4..9b4badb096c84d3b3cd3ca170431e09c216c30bc 100644 (file)
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -731,6 +731,7 @@ vty_end_config (struct vty *vty)
       break;
     case CONFIG_NODE:
     case INTERFACE_NODE:
+    case PW_NODE:
     case ZEBRA_NODE:
     case RIP_NODE:
     case RIPNG_NODE:
@@ -1156,6 +1157,7 @@ vty_stop_input (struct vty *vty)
       break;
     case CONFIG_NODE:
     case INTERFACE_NODE:
+    case PW_NODE:
     case ZEBRA_NODE:
     case RIP_NODE:
     case RIPNG_NODE:
index 9a5008f9d742fe9da341afbde3ac96f4cfc304a6..2e928657f45bd4c4dd2aaca417d095d5859ec121 100644 (file)
@@ -127,6 +127,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)/zebra/zebra_pw.c \
                  $(top_srcdir)/watchfrr/watchfrr_vty.c \
                  $(BGP_VNC_RFAPI_SRC) $(BGP_VNC_RFP_SRC)
 
index 17b95707d646b2753345a1cb4ac520f1d0d0e8e2..84907fb63dcaa2d46b0847904f4189fe511e6ecb 100644 (file)
@@ -890,6 +890,12 @@ static struct cmd_node interface_node =
   "%s(config-if)# ",
 };
 
+static struct cmd_node pw_node =
+{
+  PW_NODE,
+  "%s(config-pw)# ",
+};
+
 static struct cmd_node ns_node =
 {
   NS_NODE,
@@ -1489,6 +1495,7 @@ vtysh_exit (struct vty *vty)
       vty->node = ENABLE_NODE;
       break;
     case INTERFACE_NODE:
+    case PW_NODE:
     case NS_NODE:
     case VRF_NODE:
     case ZEBRA_NODE:
@@ -1776,6 +1783,17 @@ DEFUNSH (VTYSH_INTERFACE,
   return CMD_SUCCESS;
 }
 
+DEFUNSH (VTYSH_ZEBRA,
+        vtysh_pseudowire,
+        vtysh_pseudowire_cmd,
+        "pseudowire IFNAME",
+        "Static pseudowire configuration\n"
+        "Pseudowire name\n")
+{
+  vty->node = PW_NODE;
+  return CMD_SUCCESS;
+}
+
 /* TODO Implement "no interface command in isisd. */
 DEFSH (VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D,
        vtysh_no_interface_cmd,
@@ -3094,6 +3112,7 @@ vtysh_init_vty (void)
   install_node (&bgp_node, NULL);
   install_node (&rip_node, NULL);
   install_node (&interface_node, NULL);
+  install_node (&pw_node, NULL);
   install_node (&link_params_node, NULL);
   install_node (&ns_node, NULL);
   install_node (&vrf_node, NULL);
@@ -3130,6 +3149,7 @@ vtysh_init_vty (void)
   vtysh_install_default (BGP_NODE);
   vtysh_install_default (RIP_NODE);
   vtysh_install_default (INTERFACE_NODE);
+  vtysh_install_default (PW_NODE);
   vtysh_install_default (LINK_PARAMS_NODE);
   vtysh_install_default (NS_NODE);
   vtysh_install_default (VRF_NODE);
@@ -3273,6 +3293,10 @@ vtysh_init_vty (void)
   install_element (LINK_PARAMS_NODE, &vtysh_exit_interface_cmd);
   install_element (INTERFACE_NODE, &vtysh_quit_interface_cmd);
 
+  install_element (PW_NODE, &vtysh_end_all_cmd);
+  install_element (PW_NODE, &vtysh_exit_interface_cmd);
+  install_element (PW_NODE, &vtysh_quit_interface_cmd);
+
   install_element (NS_NODE, &vtysh_end_all_cmd);
 
   install_element (CONFIG_NODE, &vtysh_ns_cmd);
@@ -3335,6 +3359,7 @@ vtysh_init_vty (void)
   install_element (CONFIG_NODE, &vtysh_interface_cmd);
   install_element (CONFIG_NODE, &vtysh_no_interface_cmd);
   install_element (CONFIG_NODE, &vtysh_no_interface_vrf_cmd);
+  install_element (CONFIG_NODE, &vtysh_pseudowire_cmd);
   install_element (INTERFACE_NODE, &vtysh_link_params_cmd);
   install_element (ENABLE_NODE, &vtysh_show_running_config_cmd);
   install_element (ENABLE_NODE, &vtysh_copy_running_config_cmd);
index 94c4042dd4b8e79914b219aca88a694575516145..4e4c24112399ad4d11e8eeb5a8773a3093566e75 100644 (file)
@@ -196,6 +196,8 @@ vtysh_config_parse_line (const char *line)
     default:
       if (strncmp (line, "interface", strlen ("interface")) == 0)
        config = config_get (INTERFACE_NODE, line);
+      else if (strncmp (line, "pseudowire", strlen ("pseudowire")) == 0)
+       config = config_get (PW_NODE, line);
       else if (strncmp (line, "logical-router", strlen ("ns")) == 0)
        config = config_get (NS_NODE, line);
       else if (strncmp (line, "vrf", strlen ("vrf")) == 0)
index 459e6148d8459b2a2b645462d68e7e467044928b..84d71c33b94753c04f246103a10bd27d14e3a0c4 100644 (file)
@@ -314,6 +314,7 @@ main (int argc, char **argv)
 
   zebra_mpls_init ();
   zebra_mpls_vty_init ();
+  zebra_pw_vty_init ();
 
   /* For debug purpose. */
   /* SET_FLAG (zebra_debug_event, ZEBRA_DEBUG_EVENT); */
index bb8682b52aa9dbf31d142670a8ac01294a061a5a..2164ddf6eefd49bcfb8892346dd80149a1779453 100644 (file)
@@ -22,6 +22,7 @@
 #include "log.h"
 #include "memory.h"
 #include "thread.h"
+#include "command.h"
 #include "vrf.h"
 
 #include "zebra/debug.h"
 
 DEFINE_MTYPE_STATIC(LIB, PW, "Pseudowire")
 
+DEFINE_QOBJ_TYPE(zebra_pw)
+
 DEFINE_HOOK(pw_install, (struct zebra_pw *pw), (pw))
 DEFINE_HOOK(pw_uninstall, (struct zebra_pw *pw), (pw))
 
 extern struct zebra_t zebrad;
 
+static int zebra_pw_enabled(struct zebra_pw *);
 static void zebra_pw_install(struct zebra_pw *);
 static void zebra_pw_uninstall(struct zebra_pw *);
 static int zebra_pw_install_retry(struct thread *);
@@ -45,12 +49,13 @@ static int zebra_pw_check_reachability(struct zebra_pw *);
 static void zebra_pw_update_status(struct zebra_pw *, int);
 
 static inline int zebra_pw_compare(const struct zebra_pw *a,
-                                    const struct zebra_pw *b)
+                                  const struct zebra_pw *b)
 {
        return (strcmp(a->ifname, b->ifname));
 }
 
-RB_GENERATE(zebra_pw_head, zebra_pw, entry, zebra_pw_compare)
+RB_GENERATE(zebra_pw_head, zebra_pw, pw_entry, zebra_pw_compare)
+RB_GENERATE(zebra_static_pw_head, zebra_pw, static_pw_entry, zebra_pw_compare)
 
 struct zebra_pw *zebra_pw_add(struct zebra_vrf *zvrf, const char *ifname,
                              uint8_t protocol, struct zserv *client)
@@ -67,8 +72,15 @@ struct zebra_pw *zebra_pw_add(struct zebra_vrf *zvrf, const char *ifname,
        pw->vrf_id = zvrf_id(zvrf);
        pw->client = client;
        pw->status = PW_STATUS_UP;
+       pw->local_label = MPLS_NO_LABEL;
+       pw->remote_label = MPLS_NO_LABEL;
+       pw->flags = F_PSEUDOWIRE_CWORD;
 
        RB_INSERT(zebra_pw_head, &zvrf->pseudowires, pw);
+       if (pw->protocol == ZEBRA_ROUTE_STATIC) {
+               RB_INSERT(zebra_static_pw_head, &zvrf->static_pseudowires, pw);
+               QOBJ_REG(pw, zebra_pw);
+       }
 
        return pw;
 }
@@ -90,6 +102,8 @@ void zebra_pw_del(struct zebra_vrf *zvrf, struct zebra_pw *pw)
 
        /* unlink and release memory */
        RB_REMOVE(zebra_pw_head, &zvrf->pseudowires, pw);
+       if (pw->protocol == ZEBRA_ROUTE_STATIC)
+               RB_REMOVE(zebra_static_pw_head, &zvrf->static_pseudowires, pw);
        XFREE(MTYPE_PW, pw);
 }
 
@@ -109,7 +123,7 @@ void zebra_pw_change(struct zebra_pw *pw, ifindex_t ifindex, int type, int af,
        pw->flags = flags;
        pw->data = *data;
 
-       if (pw->enabled)
+       if (zebra_pw_enabled(pw))
                zebra_register_rnh_pseudowire(pw->vrf_id, pw);
        else
                zebra_pw_uninstall(pw);
@@ -122,6 +136,18 @@ struct zebra_pw *zebra_pw_find(struct zebra_vrf *zvrf, const char *ifname)
        return (RB_FIND(zebra_pw_head, &zvrf->pseudowires, &pw));
 }
 
+static int zebra_pw_enabled(struct zebra_pw *pw)
+{
+       if (pw->protocol == ZEBRA_ROUTE_STATIC) {
+               if (pw->local_label == MPLS_NO_LABEL
+                   || pw->remote_label == MPLS_NO_LABEL
+                   || pw->af == AF_UNSPEC)
+                       return 0;
+               return 1;
+       } else
+               return pw->enabled;
+}
+
 void zebra_pw_update(struct zebra_pw *pw)
 {
        if (zebra_pw_check_reachability(pw) < 0) {
@@ -165,7 +191,7 @@ static void zebra_pw_uninstall(struct zebra_pw *pw)
        /* ignore any possible error */
        hook_call(pw_uninstall, pw);
 
-       if (pw->enabled)
+       if (zebra_pw_enabled(pw))
                zebra_pw_update_status(pw, PW_STATUS_DOWN);
 }
 
@@ -234,7 +260,7 @@ static int zebra_pw_check_reachability(struct zebra_pw *pw)
                if (!nexthop->nh_label) {
                        if (IS_ZEBRA_DEBUG_PW)
                                zlog_warn("%s: unlabeled route for %s",
-                                   __func__, pw->ifname);
+                                         __func__, pw->ifname);
                        return -1;
                }
        }
@@ -262,6 +288,7 @@ zebra_pw_client_close(struct zserv *client)
 void zebra_pw_init(struct zebra_vrf *zvrf)
 {
        RB_INIT(&zvrf->pseudowires);
+       RB_INIT(&zvrf->static_pseudowires);
 }
 
 void zebra_pw_exit(struct zebra_vrf *zvrf)
@@ -271,3 +298,235 @@ void zebra_pw_exit(struct zebra_vrf *zvrf)
        while ((pw = RB_ROOT(&zvrf->pseudowires)) != NULL)
                zebra_pw_del(zvrf, pw);
 }
+
+DEFUN_NOSH (pseudowire_if,
+           pseudowire_if_cmd,
+           "[no] pseudowire IFNAME",
+           NO_STR
+           "Static pseudowire configuration\n"
+           "Pseudowire name\n")
+{
+       struct zebra_vrf *zvrf;
+       struct zebra_pw *pw;
+       int idx = 0;
+       const char *ifname;
+
+       zvrf = vrf_info_lookup(VRF_DEFAULT);
+       if (!zvrf)
+               return CMD_WARNING;
+
+       argv_find(argv, argc, "IFNAME", &idx);
+       ifname = argv[idx]->arg;
+       pw = zebra_pw_find(zvrf, ifname);
+       if (pw && pw->protocol != ZEBRA_ROUTE_STATIC) {
+               vty_out(vty, "%% Pseudowire is not static%s", VTY_NEWLINE);
+               return CMD_WARNING;
+       }
+
+       if (argv_find(argv, argc, "no", &idx)) {
+               if (!pw)
+                       return CMD_SUCCESS;
+               zebra_pw_del(zvrf, pw);
+       }
+
+       if (!pw)
+               pw = zebra_pw_add(zvrf, ifname, ZEBRA_ROUTE_STATIC, NULL);
+       VTY_PUSH_CONTEXT(PW_NODE, pw);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (pseudowire_labels,
+       pseudowire_labels_cmd,
+       "[no] mpls label local (16-1048575) remote (16-1048575)",
+       NO_STR
+       "MPLS L2VPN PW command\n"
+       "MPLS L2VPN static labels\n"
+       "Local pseudowire label\n"
+       "Local pseudowire label\n"
+       "Remote pseudowire label\n"
+       "Remote pseudowire label\n")
+{
+       VTY_DECLVAR_CONTEXT(zebra_pw, pw);
+       int idx = 0;
+       mpls_label_t local_label, remote_label;
+
+       if (argv_find(argv, argc, "no", &idx)) {
+               local_label = MPLS_NO_LABEL;
+               remote_label = MPLS_NO_LABEL;
+       } else {
+               argv_find(argv, argc, "local", &idx);
+               local_label = atoi(argv[idx + 1]->arg);
+               argv_find(argv, argc, "remote", &idx);
+               remote_label = atoi(argv[idx + 1]->arg);
+       }
+
+       zebra_pw_change(pw, pw->ifindex, pw->type, pw->af, &pw->nexthop,
+                       local_label, remote_label, pw->flags, &pw->data);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (pseudowire_neighbor,
+       pseudowire_neighbor_cmd,
+       "[no] neighbor <A.B.C.D|X:X::X:X>",
+       NO_STR
+       "Specify the IPv4 or IPv6 address of the remote endpoint\n"
+       "IPv4 address\n"
+       "IPv6 address\n")
+{
+       VTY_DECLVAR_CONTEXT(zebra_pw, pw);
+       int idx = 0;
+       const char *address;
+       int af;
+       union g_addr nexthop;
+
+       af = AF_UNSPEC;
+       memset(&nexthop, 0, sizeof(nexthop));
+
+       if (!argv_find(argv, argc, "no", &idx)) {
+               argv_find(argv, argc, "neighbor", &idx);
+               address = argv[idx + 1]->arg;
+
+               if (inet_pton(AF_INET, address, &nexthop.ipv4) == 1)
+                       af = AF_INET;
+               else if (inet_pton(AF_INET6, address, &nexthop.ipv6) == 1)
+                       af = AF_INET6;
+               else {
+                       vty_out(vty, "%% Malformed address%s", VTY_NEWLINE);
+                       return CMD_WARNING;
+               }
+       }
+
+       zebra_pw_change(pw, pw->ifindex, pw->type, af, &nexthop,
+                       pw->local_label, pw->remote_label, pw->flags,
+                       &pw->data);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (pseudowire_control_word,
+       pseudowire_control_word_cmd,
+       "[no] control-word <exclude|include>",
+       NO_STR
+       "Control-word options\n"
+       "Exclude control-word in pseudowire packets\n"
+       "Include control-word in pseudowire packets\n")
+{
+       VTY_DECLVAR_CONTEXT(zebra_pw, pw);
+       int idx = 0;
+       uint8_t flags = 0;
+
+       if (argv_find(argv, argc, "no", &idx))
+               flags = F_PSEUDOWIRE_CWORD;
+       else {
+               argv_find(argv, argc, "control-word", &idx);
+               if (argv[idx + 1]->text[0] == 'i')
+                       flags = F_PSEUDOWIRE_CWORD;
+       }
+
+       zebra_pw_change(pw, pw->ifindex, pw->type, pw->af, &pw->nexthop,
+                       pw->local_label, pw->remote_label, flags, &pw->data);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (show_pseudowires,
+       show_pseudowires_cmd,
+       "show pseudowires",
+       SHOW_STR
+       "Pseudowires")
+{
+       struct zebra_vrf *zvrf;
+       struct zebra_pw *pw;
+
+       zvrf = vrf_info_lookup(VRF_DEFAULT);
+       if (!zvrf)
+               return 0;
+
+       vty_out(vty, "%-16s %-24s %-12s %-8s %-10s%s",
+               "Interface", "Neighbor", "Labels", "Protocol", "Status",
+               VTY_NEWLINE);
+
+       RB_FOREACH(pw, zebra_pw_head, &zvrf->pseudowires) {
+               char buf_nbr[INET6_ADDRSTRLEN];
+               char buf_labels[64];
+
+               inet_ntop(pw->af, &pw->nexthop, buf_nbr, sizeof(buf_nbr));
+
+               if (pw->local_label != MPLS_NO_LABEL
+                   && pw->remote_label != MPLS_NO_LABEL)
+                       snprintf(buf_labels, sizeof(buf_labels), "%u/%u",
+                                pw->local_label, pw->remote_label);
+               else
+                       snprintf(buf_labels, sizeof(buf_labels), "-");
+
+               vty_out(vty, "%-16s %-24s %-12s %-8s %-10s%s",
+                       pw->ifname, (pw->af != AF_UNSPEC) ? buf_nbr : "-",
+                       buf_labels, zebra_route_string(pw->protocol),
+                       (zebra_pw_enabled(pw) && pw->status == PW_STATUS_UP) ?
+                       "UP" : "DOWN", VTY_NEWLINE);
+       }
+
+       return CMD_SUCCESS;
+}
+
+/* Pseudowire configuration write function. */
+static int zebra_pw_config(struct vty *vty)
+{
+       int write = 0;
+       struct zebra_vrf *zvrf;
+       struct zebra_pw *pw;
+
+       zvrf = vrf_info_lookup(VRF_DEFAULT);
+       if (!zvrf)
+               return 0;
+
+       RB_FOREACH(pw, zebra_static_pw_head, &zvrf->static_pseudowires) {
+               vty_out(vty, "pseudowire %s%s", pw->ifname, VTY_NEWLINE);
+               if (pw->local_label != MPLS_NO_LABEL
+                   && pw->remote_label != MPLS_NO_LABEL)
+                       vty_out(vty, " mpls label local %u remote %u%s",
+                               pw->local_label, pw->remote_label,
+                               VTY_NEWLINE);
+               else
+                       vty_out(vty, " ! Incomplete config, specify the static "
+                               "MPLS labels%s", VTY_NEWLINE);
+
+               if (pw->af != AF_UNSPEC) {
+                       char buf[INET6_ADDRSTRLEN];
+                       inet_ntop(pw->af, &pw->nexthop, buf, sizeof(buf));
+                       vty_out(vty, " neighbor %s%s", buf, VTY_NEWLINE);
+               } else
+                       vty_out(vty, " ! Incomplete config, specify a neighbor "
+                               "address%s", VTY_NEWLINE);
+
+               if (!(pw->flags & F_PSEUDOWIRE_CWORD))
+                       vty_out(vty, " control-word exclude%s", VTY_NEWLINE);
+
+               vty_out(vty, "!%s", VTY_NEWLINE);
+               write = 1;
+       }
+
+       return write;
+}
+
+static struct cmd_node pw_node =
+{
+       PW_NODE,
+       "%s(config-pw)# ",
+       1,
+};
+
+void zebra_pw_vty_init(void)
+{
+       install_node(&pw_node, zebra_pw_config);
+       install_default(PW_NODE);
+
+       install_element(CONFIG_NODE, &pseudowire_if_cmd);
+       install_element(PW_NODE, &pseudowire_labels_cmd);
+       install_element(PW_NODE, &pseudowire_neighbor_cmd);
+       install_element(PW_NODE, &pseudowire_control_word_cmd);
+
+       install_element(VIEW_NODE, &show_pseudowires_cmd);
+}
index 9cb6ab416fcb3ab8db5810d7b37071c8c1cf8b2c..b588bac0a2b45b62457d318762935b1800fd1b6c 100644 (file)
 #include <netinet/in.h>
 
 #include "hook.h"
+#include "qobj.h"
 
 #define PW_INSTALL_RETRY_INTERVAL      30
 
 struct zebra_pw {
-       RB_ENTRY(zebra_pw) entry;
+       RB_ENTRY(zebra_pw) pw_entry, static_pw_entry;
        vrf_id_t vrf_id;
        char ifname[IF_NAMESIZE];
        ifindex_t ifindex;
@@ -45,10 +46,15 @@ struct zebra_pw {
        struct zserv *client;
        struct rnh *rnh;
        struct thread *install_retry_timer;
+       QOBJ_FIELDS
 };
+DECLARE_QOBJ_TYPE(zebra_pw)
 
 RB_HEAD(zebra_pw_head, zebra_pw);
-RB_PROTOTYPE(zebra_pw_head, zebra_pw, entry, zebra_pw_compare);
+RB_PROTOTYPE(zebra_pw_head, zebra_pw, pw_entry, zebra_pw_compare);
+
+RB_HEAD(zebra_static_pw_head, zebra_pw);
+RB_PROTOTYPE(zebra_static_pw_head, zebra_pw, static_pw_entry, zebra_pw_compare);
 
 DECLARE_HOOK(pw_install, (struct zebra_pw * pw), (pw))
 DECLARE_HOOK(pw_uninstall, (struct zebra_pw * pw), (pw))
@@ -64,5 +70,6 @@ void zebra_pw_install_failure(struct zebra_pw *);
 void zebra_pw_client_close(struct zserv *);
 void zebra_pw_init(struct zebra_vrf *);
 void zebra_pw_exit(struct zebra_vrf *);
+void zebra_pw_vty_init(void);
 
-#endif                         /* ZEBRA_PW_H_ */
+#endif /* ZEBRA_PW_H_ */
index ff3b94a25b017e2b6a4bc08cf8ab5850e3a95a0f..d5ebbbc466e4db60e33eadafa4ca8bd1356eded3 100644 (file)
@@ -348,7 +348,7 @@ zebra_deregister_rnh_pseudowire (vrf_id_t vrf_id, struct zebra_pw *pw)
 {
   struct rnh *rnh;
 
-  rnh =pw->rnh;
+  rnh = pw->rnh;
   if (!rnh)
     return;
 
index eab87e67d6d0b2cbbe09a95cbe1ea9ddb6a7d00e..56c98931f20a58c52184f4053282a0490bb1dae8 100644 (file)
@@ -82,6 +82,7 @@ struct zebra_vrf
 
   /* Pseudowires. */
   struct zebra_pw_head pseudowires;
+  struct zebra_static_pw_head static_pseudowires;
 
   /* MPLS processing flags */
   u_int16_t mpls_flags;