back to topotato report
topotato coverage report
Current view: top level - zebra - zebra_pw.c (source / functions) Hit Total Coverage
Test: aggregated run ( view descriptions ) Lines: 29 427 6.8 %
Date: 2023-02-24 19:38:44 Functions: 6 33 18.2 %

          Line data    Source code
       1             : /* Zebra PW code
       2             :  * Copyright (C) 2016 Volta Networks, Inc.
       3             :  *
       4             :  * This program is free software; you can redistribute it and/or modify
       5             :  * it under the terms of the GNU General Public License as published by
       6             :  * the Free Software Foundation; either version 2 of the License, or
       7             :  * (at your option) any later version.
       8             :  *
       9             :  * This program is distributed in the hope that it will be useful, but
      10             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12             :  * General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU General Public License
      15             :  * along with this program; see the file COPYING; if not, write to the
      16             :  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
      17             :  * MA 02110-1301 USA
      18             :  */
      19             : 
      20             : #include <zebra.h>
      21             : 
      22             : #include "log.h"
      23             : #include "memory.h"
      24             : #include "thread.h"
      25             : #include "command.h"
      26             : #include "vrf.h"
      27             : #include "lib/json.h"
      28             : #include "printfrr.h"
      29             : 
      30             : #include "zebra/debug.h"
      31             : #include "zebra/rib.h"
      32             : #include "zebra/zebra_router.h"
      33             : #include "zebra/zapi_msg.h"
      34             : #include "zebra/zebra_rnh.h"
      35             : #include "zebra/zebra_vrf.h"
      36             : #include "zebra/zebra_pw.h"
      37             : 
      38         279 : DEFINE_MTYPE_STATIC(LIB, PW, "Pseudowire");
      39             : 
      40             : DEFINE_QOBJ_TYPE(zebra_pw);
      41             : 
      42           0 : DEFINE_HOOK(pw_install, (struct zebra_pw * pw), (pw));
      43           0 : DEFINE_HOOK(pw_uninstall, (struct zebra_pw * pw), (pw));
      44             : 
      45             : #define MPLS_NO_LABEL MPLS_INVALID_LABEL
      46             : 
      47             : static int zebra_pw_enabled(struct zebra_pw *);
      48             : static void zebra_pw_install(struct zebra_pw *);
      49             : static void zebra_pw_uninstall(struct zebra_pw *);
      50             : static void zebra_pw_install_retry(struct thread *thread);
      51             : static int zebra_pw_check_reachability(const struct zebra_pw *);
      52             : static void zebra_pw_update_status(struct zebra_pw *, int);
      53             : 
      54           0 : static inline int zebra_pw_compare(const struct zebra_pw *a,
      55             :                                    const struct zebra_pw *b)
      56             : {
      57           0 :         return (strcmp(a->ifname, b->ifname));
      58             : }
      59             : 
      60           0 : RB_GENERATE(zebra_pw_head, zebra_pw, pw_entry, zebra_pw_compare)
      61           0 : RB_GENERATE(zebra_static_pw_head, zebra_pw, static_pw_entry, zebra_pw_compare)
      62             : 
      63           0 : struct zebra_pw *zebra_pw_add(struct zebra_vrf *zvrf, const char *ifname,
      64             :                               uint8_t protocol, struct zserv *client)
      65             : {
      66           0 :         struct zebra_pw *pw;
      67             : 
      68           0 :         if (IS_ZEBRA_DEBUG_PW)
      69           0 :                 zlog_debug("%u: adding pseudowire %s protocol %s",
      70             :                            zvrf_id(zvrf), ifname, zebra_route_string(protocol));
      71             : 
      72           0 :         pw = XCALLOC(MTYPE_PW, sizeof(*pw));
      73           0 :         strlcpy(pw->ifname, ifname, sizeof(pw->ifname));
      74           0 :         pw->protocol = protocol;
      75           0 :         pw->vrf_id = zvrf_id(zvrf);
      76           0 :         pw->client = client;
      77           0 :         pw->status = PW_NOT_FORWARDING;
      78           0 :         pw->local_label = MPLS_NO_LABEL;
      79           0 :         pw->remote_label = MPLS_NO_LABEL;
      80           0 :         pw->flags = F_PSEUDOWIRE_CWORD;
      81             : 
      82           0 :         RB_INSERT(zebra_pw_head, &zvrf->pseudowires, pw);
      83           0 :         if (pw->protocol == ZEBRA_ROUTE_STATIC) {
      84           0 :                 RB_INSERT(zebra_static_pw_head, &zvrf->static_pseudowires, pw);
      85           0 :                 QOBJ_REG(pw, zebra_pw);
      86             :         }
      87             : 
      88           0 :         return pw;
      89             : }
      90             : 
      91           0 : void zebra_pw_del(struct zebra_vrf *zvrf, struct zebra_pw *pw)
      92             : {
      93           0 :         if (IS_ZEBRA_DEBUG_PW)
      94           0 :                 zlog_debug("%u: deleting pseudowire %s protocol %s", pw->vrf_id,
      95             :                            pw->ifname, zebra_route_string(pw->protocol));
      96             : 
      97             :         /* remove nexthop tracking */
      98           0 :         zebra_deregister_rnh_pseudowire(pw->vrf_id, pw);
      99             : 
     100             :         /* uninstall */
     101           0 :         if (pw->status == PW_FORWARDING) {
     102           0 :                 hook_call(pw_uninstall, pw);
     103           0 :                 dplane_pw_uninstall(pw);
     104             :         }
     105             : 
     106           0 :         THREAD_OFF(pw->install_retry_timer);
     107             : 
     108             :         /* unlink and release memory */
     109           0 :         RB_REMOVE(zebra_pw_head, &zvrf->pseudowires, pw);
     110           0 :         if (pw->protocol == ZEBRA_ROUTE_STATIC)
     111           0 :                 RB_REMOVE(zebra_static_pw_head, &zvrf->static_pseudowires, pw);
     112             : 
     113           0 :         XFREE(MTYPE_PW, pw);
     114           0 : }
     115             : 
     116           0 : void zebra_pw_change(struct zebra_pw *pw, ifindex_t ifindex, int type, int af,
     117             :                      union g_addr *nexthop, uint32_t local_label,
     118             :                      uint32_t remote_label, uint8_t flags,
     119             :                      union pw_protocol_fields *data)
     120             : {
     121           0 :         pw->ifindex = ifindex;
     122           0 :         pw->type = type;
     123           0 :         pw->af = af;
     124           0 :         pw->nexthop = *nexthop;
     125           0 :         pw->local_label = local_label;
     126           0 :         pw->remote_label = remote_label;
     127           0 :         pw->flags = flags;
     128           0 :         pw->data = *data;
     129             : 
     130           0 :         if (zebra_pw_enabled(pw)) {
     131           0 :                 bool nht_exists;
     132           0 :                 zebra_register_rnh_pseudowire(pw->vrf_id, pw, &nht_exists);
     133           0 :                 if (nht_exists)
     134           0 :                         zebra_pw_update(pw);
     135             :         } else {
     136           0 :                 if (pw->protocol == ZEBRA_ROUTE_STATIC)
     137           0 :                         zebra_deregister_rnh_pseudowire(pw->vrf_id, pw);
     138           0 :                 zebra_pw_uninstall(pw);
     139             :         }
     140           0 : }
     141             : 
     142           0 : struct zebra_pw *zebra_pw_find(struct zebra_vrf *zvrf, const char *ifname)
     143             : {
     144           0 :         struct zebra_pw pw;
     145           0 :         strlcpy(pw.ifname, ifname, sizeof(pw.ifname));
     146           0 :         return (RB_FIND(zebra_pw_head, &zvrf->pseudowires, &pw));
     147             : }
     148             : 
     149           0 : static int zebra_pw_enabled(struct zebra_pw *pw)
     150             : {
     151           0 :         if (pw->protocol == ZEBRA_ROUTE_STATIC) {
     152           0 :                 if (pw->local_label == MPLS_NO_LABEL
     153           0 :                     || pw->remote_label == MPLS_NO_LABEL || pw->af == AF_UNSPEC)
     154             :                         return 0;
     155           0 :                 return 1;
     156             :         } else
     157           0 :                 return pw->enabled;
     158             : }
     159             : 
     160           0 : void zebra_pw_update(struct zebra_pw *pw)
     161             : {
     162           0 :         if (zebra_pw_check_reachability(pw) < 0) {
     163           0 :                 zebra_pw_uninstall(pw);
     164           0 :                 zebra_pw_install_failure(pw, PW_NOT_FORWARDING);
     165             :                 /* wait for NHT and try again later */
     166             :         } else {
     167             :                 /*
     168             :                  * Install or reinstall the pseudowire (e.g. to update
     169             :                  * parameters like the nexthop or the use of the control word).
     170             :                  */
     171           0 :                 zebra_pw_install(pw);
     172             :         }
     173           0 : }
     174             : 
     175           0 : static void zebra_pw_install(struct zebra_pw *pw)
     176             : {
     177           0 :         if (IS_ZEBRA_DEBUG_PW)
     178           0 :                 zlog_debug("%u: installing pseudowire %s protocol %s",
     179             :                            pw->vrf_id, pw->ifname,
     180             :                            zebra_route_string(pw->protocol));
     181             : 
     182           0 :         hook_call(pw_install, pw);
     183           0 :         if (dplane_pw_install(pw) == ZEBRA_DPLANE_REQUEST_FAILURE) {
     184           0 :                 zebra_pw_install_failure(pw, PW_NOT_FORWARDING);
     185           0 :                 return;
     186             :         }
     187             : 
     188           0 :         if (pw->status != PW_FORWARDING)
     189           0 :                 zebra_pw_update_status(pw, PW_FORWARDING);
     190             : }
     191             : 
     192           0 : static void zebra_pw_uninstall(struct zebra_pw *pw)
     193             : {
     194           0 :         if (pw->status != PW_FORWARDING)
     195             :                 return;
     196             : 
     197           0 :         if (IS_ZEBRA_DEBUG_PW)
     198           0 :                 zlog_debug("%u: uninstalling pseudowire %s protocol %s",
     199             :                            pw->vrf_id, pw->ifname,
     200             :                            zebra_route_string(pw->protocol));
     201             : 
     202             :         /* ignore any possible error */
     203           0 :         hook_call(pw_uninstall, pw);
     204           0 :         dplane_pw_uninstall(pw);
     205             : 
     206           0 :         if (zebra_pw_enabled(pw))
     207           0 :                 zebra_pw_update_status(pw, PW_NOT_FORWARDING);
     208             : }
     209             : 
     210             : /*
     211             :  * Installation of the pseudowire in the kernel or hardware has failed. This
     212             :  * function will notify the pseudowire client about the failure and schedule
     213             :  * to retry the installation later. This function can be called by an external
     214             :  * agent that performs the pseudowire installation in an asynchronous way.
     215             :  */
     216           0 : void zebra_pw_install_failure(struct zebra_pw *pw, int pwstatus)
     217             : {
     218           0 :         if (IS_ZEBRA_DEBUG_PW)
     219           0 :                 zlog_debug(
     220             :                         "%u: failed installing pseudowire %s, scheduling retry in %u seconds",
     221             :                         pw->vrf_id, pw->ifname, PW_INSTALL_RETRY_INTERVAL);
     222             : 
     223             :         /* schedule to retry later */
     224           0 :         THREAD_OFF(pw->install_retry_timer);
     225           0 :         thread_add_timer(zrouter.master, zebra_pw_install_retry, pw,
     226             :                          PW_INSTALL_RETRY_INTERVAL, &pw->install_retry_timer);
     227             : 
     228           0 :         zebra_pw_update_status(pw, pwstatus);
     229           0 : }
     230             : 
     231           0 : static void zebra_pw_install_retry(struct thread *thread)
     232             : {
     233           0 :         struct zebra_pw *pw = THREAD_ARG(thread);
     234             : 
     235           0 :         zebra_pw_install(pw);
     236           0 : }
     237             : 
     238           0 : static void zebra_pw_update_status(struct zebra_pw *pw, int status)
     239             : {
     240           0 :         pw->status = status;
     241           0 :         if (pw->client)
     242           0 :                 zsend_pw_update(pw->client, pw);
     243             : }
     244             : 
     245           0 : static int zebra_pw_check_reachability_strict(const struct zebra_pw *pw,
     246             :                                               struct route_entry *re)
     247             : {
     248           0 :         const struct nexthop *nexthop;
     249           0 :         const struct nexthop_group *nhg;
     250           0 :         bool found_p = false;
     251           0 :         bool fail_p = false;
     252             : 
     253             :         /* TODO: consider GRE/L2TPv3 tunnels in addition to MPLS LSPs */
     254             : 
     255             :         /* All active nexthops must be labelled; look at
     256             :          * primary and backup fib lists, in case there's been
     257             :          * a backup nexthop activation.
     258             :          */
     259           0 :         nhg = rib_get_fib_nhg(re);
     260           0 :         if (nhg && nhg->nexthop) {
     261           0 :                 for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
     262           0 :                         if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
     263           0 :                                 continue;
     264             : 
     265           0 :                         if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
     266           0 :                                 if (nexthop->nh_label != NULL)
     267             :                                         found_p = true;
     268             :                                 else {
     269             :                                         fail_p = true;
     270             :                                         break;
     271             :                                 }
     272             :                         }
     273             :                 }
     274             :         }
     275             : 
     276           0 :         if (fail_p)
     277           0 :                 goto done;
     278             : 
     279           0 :         nhg = rib_get_fib_backup_nhg(re);
     280           0 :         if (nhg && nhg->nexthop) {
     281           0 :                 for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
     282           0 :                         if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
     283           0 :                                 continue;
     284             : 
     285           0 :                         if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
     286           0 :                                 if (nexthop->nh_label != NULL)
     287             :                                         found_p = true;
     288             :                                 else {
     289             :                                         fail_p = true;
     290             :                                         break;
     291             :                                 }
     292             :                         }
     293             :                 }
     294             :         }
     295             : 
     296           0 : done:
     297             : 
     298           0 :         if (fail_p || !found_p) {
     299           0 :                 if (IS_ZEBRA_DEBUG_PW)
     300           0 :                         zlog_debug("%s: unlabeled route for %s",
     301             :                                    __func__, pw->ifname);
     302           0 :                 return -1;
     303             :         }
     304             : 
     305             :         return 0;
     306             : }
     307             : 
     308           0 : static int zebra_pw_check_reachability(const struct zebra_pw *pw)
     309             : {
     310           0 :         struct route_entry *re;
     311           0 :         const struct nexthop *nexthop;
     312           0 :         const struct nexthop_group *nhg;
     313           0 :         bool found_p = false;
     314             : 
     315             :         /* TODO: consider GRE/L2TPv3 tunnels in addition to MPLS LSPs */
     316             : 
     317             :         /* Find route to the remote end of the pseudowire */
     318           0 :         re = rib_match(family2afi(pw->af), SAFI_UNICAST, pw->vrf_id,
     319             :                        &pw->nexthop, NULL);
     320           0 :         if (!re) {
     321           0 :                 if (IS_ZEBRA_DEBUG_PW)
     322           0 :                         zlog_debug("%s: no route found for %s", __func__,
     323             :                                    pw->ifname);
     324           0 :                 return -1;
     325             :         }
     326             : 
     327             :         /* Stricter checking for some OSes (OBSD, e.g.) */
     328           0 :         if (mpls_pw_reach_strict)
     329           0 :                 return zebra_pw_check_reachability_strict(pw, re);
     330             : 
     331             :         /* There must be at least one installed labelled nexthop;
     332             :          * look at primary and backup fib lists, in case there's been
     333             :          * a backup nexthop activation.
     334             :          */
     335           0 :         nhg = rib_get_fib_nhg(re);
     336           0 :         if (nhg && nhg->nexthop) {
     337           0 :                 for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
     338           0 :                         if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
     339           0 :                                 continue;
     340             : 
     341           0 :                         if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE) &&
     342           0 :                             nexthop->nh_label != NULL) {
     343             :                                 found_p = true;
     344             :                                 break;
     345             :                         }
     346             :                 }
     347             :         }
     348             : 
     349           0 :         if (found_p)
     350             :                 return 0;
     351             : 
     352           0 :         nhg = rib_get_fib_backup_nhg(re);
     353           0 :         if (nhg && nhg->nexthop) {
     354           0 :                 for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
     355           0 :                         if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
     356           0 :                                 continue;
     357             : 
     358           0 :                         if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE) &&
     359           0 :                             nexthop->nh_label != NULL) {
     360             :                                 found_p = true;
     361             :                                 break;
     362             :                         }
     363             :                 }
     364             :         }
     365             : 
     366           0 :         if (!found_p) {
     367           0 :                 if (IS_ZEBRA_DEBUG_PW)
     368           0 :                         zlog_debug("%s: unlabeled route for %s",
     369             :                                    __func__, pw->ifname);
     370           0 :                 return -1;
     371             :         }
     372             : 
     373             :         return 0;
     374             : }
     375             : 
     376         199 : static int zebra_pw_client_close(struct zserv *client)
     377             : {
     378         199 :         struct vrf *vrf;
     379         199 :         struct zebra_vrf *zvrf;
     380         199 :         struct zebra_pw *pw, *tmp;
     381             : 
     382         597 :         RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
     383         199 :                 zvrf = vrf->info;
     384         398 :                 RB_FOREACH_SAFE (pw, zebra_pw_head, &zvrf->pseudowires, tmp) {
     385           0 :                         if (pw->client != client)
     386           0 :                                 continue;
     387           0 :                         zebra_pw_del(zvrf, pw);
     388             :                 }
     389             :         }
     390             : 
     391         199 :         return 0;
     392             : }
     393             : 
     394          93 : void zebra_pw_init(struct zebra_vrf *zvrf)
     395             : {
     396          93 :         RB_INIT(zebra_pw_head, &zvrf->pseudowires);
     397          93 :         RB_INIT(zebra_static_pw_head, &zvrf->static_pseudowires);
     398             : 
     399          93 :         hook_register(zserv_client_close, zebra_pw_client_close);
     400          93 : }
     401             : 
     402          93 : void zebra_pw_exit(struct zebra_vrf *zvrf)
     403             : {
     404          93 :         struct zebra_pw *pw;
     405             : 
     406          93 :         while (!RB_EMPTY(zebra_pw_head, &zvrf->pseudowires)) {
     407           0 :                 pw = RB_ROOT(zebra_pw_head, &zvrf->pseudowires);
     408             : 
     409           0 :                 zebra_pw_del(zvrf, pw);
     410             :         }
     411          93 : }
     412             : 
     413           0 : DEFUN_NOSH (pseudowire_if,
     414             :             pseudowire_if_cmd,
     415             :             "pseudowire IFNAME",
     416             :             "Static pseudowire configuration\n"
     417             :             "Pseudowire name\n")
     418             : {
     419           0 :         struct zebra_vrf *zvrf;
     420           0 :         struct zebra_pw *pw;
     421           0 :         const char *ifname;
     422           0 :         int idx = 0;
     423             : 
     424           0 :         zvrf = vrf_info_lookup(VRF_DEFAULT);
     425           0 :         if (!zvrf)
     426             :                 return CMD_WARNING;
     427             : 
     428           0 :         argv_find(argv, argc, "IFNAME", &idx);
     429           0 :         ifname = argv[idx]->arg;
     430             : 
     431           0 :         pw = zebra_pw_find(zvrf, ifname);
     432           0 :         if (pw && pw->protocol != ZEBRA_ROUTE_STATIC) {
     433           0 :                 vty_out(vty, "%% Pseudowire is not static\n");
     434           0 :                 return CMD_WARNING;
     435             :         }
     436             : 
     437           0 :         if (!pw)
     438           0 :                 pw = zebra_pw_add(zvrf, ifname, ZEBRA_ROUTE_STATIC, NULL);
     439           0 :         VTY_PUSH_CONTEXT(PW_NODE, pw);
     440             : 
     441           0 :         return CMD_SUCCESS;
     442             : }
     443             : 
     444           0 : DEFUN (no_pseudowire_if,
     445             :        no_pseudowire_if_cmd,
     446             :        "no pseudowire IFNAME",
     447             :        NO_STR
     448             :        "Static pseudowire configuration\n"
     449             :        "Pseudowire name\n")
     450             : {
     451           0 :         struct zebra_vrf *zvrf;
     452           0 :         struct zebra_pw *pw;
     453           0 :         const char *ifname;
     454           0 :         int idx = 0;
     455             : 
     456           0 :         zvrf = vrf_info_lookup(VRF_DEFAULT);
     457           0 :         if (!zvrf)
     458             :                 return CMD_WARNING;
     459             : 
     460           0 :         argv_find(argv, argc, "IFNAME", &idx);
     461           0 :         ifname = argv[idx]->arg;
     462             : 
     463           0 :         pw = zebra_pw_find(zvrf, ifname);
     464           0 :         if (pw) {
     465           0 :                 if (pw->protocol != ZEBRA_ROUTE_STATIC) {
     466           0 :                         vty_out(vty, "%% Pseudowire is not static\n");
     467           0 :                         return CMD_WARNING;
     468             :                 }
     469           0 :                 zebra_pw_del(zvrf, pw);
     470             :         }
     471             : 
     472             :         return CMD_SUCCESS;
     473             : }
     474             : 
     475           0 : DEFUN (pseudowire_labels,
     476             :        pseudowire_labels_cmd,
     477             :        "[no] mpls label local (16-1048575) remote (16-1048575)",
     478             :        NO_STR
     479             :        "MPLS L2VPN PW command\n"
     480             :        "MPLS L2VPN static labels\n"
     481             :        "Local pseudowire label\n"
     482             :        "Local pseudowire label\n"
     483             :        "Remote pseudowire label\n"
     484             :        "Remote pseudowire label\n")
     485             : {
     486           0 :         VTY_DECLVAR_CONTEXT(zebra_pw, pw);
     487           0 :         int idx = 0;
     488           0 :         mpls_label_t local_label, remote_label;
     489             : 
     490           0 :         if (argv_find(argv, argc, "no", &idx)) {
     491             :                 local_label = MPLS_NO_LABEL;
     492             :                 remote_label = MPLS_NO_LABEL;
     493             :         } else {
     494           0 :                 argv_find(argv, argc, "local", &idx);
     495           0 :                 local_label = atoi(argv[idx + 1]->arg);
     496           0 :                 argv_find(argv, argc, "remote", &idx);
     497           0 :                 remote_label = atoi(argv[idx + 1]->arg);
     498             :         }
     499             : 
     500           0 :         zebra_pw_change(pw, pw->ifindex, pw->type, pw->af, &pw->nexthop,
     501           0 :                         local_label, remote_label, pw->flags, &pw->data);
     502             : 
     503           0 :         return CMD_SUCCESS;
     504             : }
     505             : 
     506           0 : DEFUN (pseudowire_neighbor,
     507             :        pseudowire_neighbor_cmd,
     508             :        "[no] neighbor <A.B.C.D|X:X::X:X>",
     509             :        NO_STR
     510             :        "Specify the IPv4 or IPv6 address of the remote endpoint\n"
     511             :        "IPv4 address\n"
     512             :        "IPv6 address\n")
     513             : {
     514           0 :         VTY_DECLVAR_CONTEXT(zebra_pw, pw);
     515           0 :         int idx = 0;
     516           0 :         const char *address;
     517           0 :         int af;
     518           0 :         union g_addr nexthop;
     519             : 
     520           0 :         af = AF_UNSPEC;
     521           0 :         memset(&nexthop, 0, sizeof(nexthop));
     522             : 
     523           0 :         if (!argv_find(argv, argc, "no", &idx)) {
     524           0 :                 argv_find(argv, argc, "neighbor", &idx);
     525           0 :                 address = argv[idx + 1]->arg;
     526             : 
     527           0 :                 if (inet_pton(AF_INET, address, &nexthop.ipv4) == 1)
     528             :                         af = AF_INET;
     529           0 :                 else if (inet_pton(AF_INET6, address, &nexthop.ipv6) == 1)
     530             :                         af = AF_INET6;
     531             :                 else {
     532           0 :                         vty_out(vty, "%% Malformed address\n");
     533           0 :                         return CMD_WARNING;
     534             :                 }
     535             :         }
     536             : 
     537           0 :         zebra_pw_change(pw, pw->ifindex, pw->type, af, &nexthop,
     538           0 :                         pw->local_label, pw->remote_label, pw->flags,
     539             :                         &pw->data);
     540             : 
     541           0 :         return CMD_SUCCESS;
     542             : }
     543             : 
     544           0 : DEFUN (pseudowire_control_word,
     545             :        pseudowire_control_word_cmd,
     546             :        "[no] control-word <exclude|include>",
     547             :        NO_STR
     548             :        "Control-word options\n"
     549             :        "Exclude control-word in pseudowire packets\n"
     550             :        "Include control-word in pseudowire packets\n")
     551             : {
     552           0 :         VTY_DECLVAR_CONTEXT(zebra_pw, pw);
     553           0 :         int idx = 0;
     554           0 :         uint8_t flags = 0;
     555             : 
     556           0 :         if (argv_find(argv, argc, "no", &idx))
     557             :                 flags = F_PSEUDOWIRE_CWORD;
     558             :         else {
     559           0 :                 argv_find(argv, argc, "control-word", &idx);
     560           0 :                 if (argv[idx + 1]->text[0] == 'i')
     561           0 :                         flags = F_PSEUDOWIRE_CWORD;
     562             :         }
     563             : 
     564           0 :         zebra_pw_change(pw, pw->ifindex, pw->type, pw->af, &pw->nexthop,
     565             :                         pw->local_label, pw->remote_label, flags, &pw->data);
     566             : 
     567           0 :         return CMD_SUCCESS;
     568             : }
     569             : 
     570           0 : DEFUN (show_pseudowires,
     571             :        show_pseudowires_cmd,
     572             :        "show mpls pseudowires",
     573             :        SHOW_STR
     574             :        MPLS_STR
     575             :        "Pseudowires\n")
     576             : {
     577           0 :         struct zebra_vrf *zvrf;
     578           0 :         struct zebra_pw *pw;
     579             : 
     580           0 :         zvrf = vrf_info_lookup(VRF_DEFAULT);
     581           0 :         if (!zvrf)
     582             :                 return 0;
     583             : 
     584           0 :         vty_out(vty, "%-16s %-24s %-12s %-8s %-10s\n", "Interface", "Neighbor",
     585             :                 "Labels", "Protocol", "Status");
     586             : 
     587           0 :         RB_FOREACH (pw, zebra_pw_head, &zvrf->pseudowires) {
     588           0 :                 char buf_nbr[INET6_ADDRSTRLEN];
     589           0 :                 char buf_labels[64];
     590             : 
     591           0 :                 inet_ntop(pw->af, &pw->nexthop, buf_nbr, sizeof(buf_nbr));
     592             : 
     593           0 :                 if (pw->local_label != MPLS_NO_LABEL
     594           0 :                     && pw->remote_label != MPLS_NO_LABEL)
     595           0 :                         snprintf(buf_labels, sizeof(buf_labels), "%u/%u",
     596             :                                  pw->local_label, pw->remote_label);
     597             :                 else
     598           0 :                         snprintf(buf_labels, sizeof(buf_labels), "-");
     599             : 
     600           0 :                 vty_out(vty, "%-16s %-24s %-12s %-8s %-10s\n", pw->ifname,
     601           0 :                         (pw->af != AF_UNSPEC) ? buf_nbr : "-", buf_labels,
     602           0 :                         zebra_route_string(pw->protocol),
     603           0 :                         (zebra_pw_enabled(pw) && pw->status == PW_FORWARDING)
     604             :                                 ? "UP"
     605             :                                 : "DOWN");
     606             :         }
     607             : 
     608             :         return CMD_SUCCESS;
     609             : }
     610             : 
     611           0 : static void vty_show_mpls_pseudowire_detail(struct vty *vty)
     612             : {
     613           0 :         struct zebra_vrf *zvrf;
     614           0 :         struct zebra_pw *pw;
     615           0 :         struct route_entry *re;
     616           0 :         struct nexthop *nexthop;
     617           0 :         struct nexthop_group *nhg;
     618             : 
     619           0 :         zvrf = vrf_info_lookup(VRF_DEFAULT);
     620           0 :         if (!zvrf)
     621             :                 return;
     622             : 
     623           0 :         RB_FOREACH (pw, zebra_pw_head, &zvrf->pseudowires) {
     624           0 :                 char buf_nbr[INET6_ADDRSTRLEN];
     625           0 :                 char buf_nh[100];
     626             : 
     627           0 :                 vty_out(vty, "Interface: %s\n", pw->ifname);
     628           0 :                 inet_ntop(pw->af, &pw->nexthop, buf_nbr, sizeof(buf_nbr));
     629           0 :                 vty_out(vty, "  Neighbor: %s\n",
     630           0 :                         (pw->af != AF_UNSPEC) ? buf_nbr : "-");
     631           0 :                 if (pw->local_label != MPLS_NO_LABEL)
     632           0 :                         vty_out(vty, "  Local Label: %u\n", pw->local_label);
     633             :                 else
     634           0 :                         vty_out(vty, "  Local Label: %s\n", "-");
     635           0 :                 if (pw->remote_label != MPLS_NO_LABEL)
     636           0 :                         vty_out(vty, "  Remote Label: %u\n", pw->remote_label);
     637             :                 else
     638           0 :                         vty_out(vty, "  Remote Label: %s\n", "-");
     639           0 :                 vty_out(vty, "  Protocol: %s\n",
     640           0 :                         zebra_route_string(pw->protocol));
     641           0 :                 if (pw->protocol == ZEBRA_ROUTE_LDP)
     642           0 :                         vty_out(vty, "  VC-ID: %u\n", pw->data.ldp.pwid);
     643           0 :                 vty_out(vty, "  Status: %s \n",
     644           0 :                         (zebra_pw_enabled(pw) && pw->status == PW_FORWARDING)
     645             :                         ? "Up"
     646             :                         : "Down");
     647           0 :                 re = rib_match(family2afi(pw->af), SAFI_UNICAST, pw->vrf_id,
     648             :                                &pw->nexthop, NULL);
     649           0 :                 if (re == NULL)
     650           0 :                         continue;
     651             : 
     652           0 :                 nhg = rib_get_fib_nhg(re);
     653           0 :                 for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
     654           0 :                         snprintfrr(buf_nh, sizeof(buf_nh), "%pNHv",
     655             :                                    nexthop);
     656           0 :                         vty_out(vty, "  Next Hop: %s\n", buf_nh);
     657           0 :                         if (nexthop->nh_label)
     658           0 :                                 vty_out(vty, "  Next Hop label: %u\n",
     659             :                                         nexthop->nh_label->label[0]);
     660             :                         else
     661           0 :                                 vty_out(vty, "  Next Hop label: %s\n",
     662             :                                         "-");
     663             :                 }
     664             : 
     665             :                 /* Include any installed backups */
     666           0 :                 nhg = rib_get_fib_backup_nhg(re);
     667           0 :                 if (nhg == NULL)
     668             :                         continue;
     669             : 
     670           0 :                 for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
     671           0 :                         snprintfrr(buf_nh, sizeof(buf_nh), "%pNHv",
     672             :                                    nexthop);
     673           0 :                         vty_out(vty, "  Next Hop: %s\n", buf_nh);
     674           0 :                         if (nexthop->nh_label)
     675           0 :                                 vty_out(vty, "  Next Hop label: %u\n",
     676             :                                         nexthop->nh_label->label[0]);
     677             :                         else
     678           0 :                                 vty_out(vty, "  Next Hop label: %s\n",
     679             :                                         "-");
     680             :                 }
     681             :         }
     682             : }
     683             : 
     684           0 : static void vty_show_mpls_pseudowire(struct zebra_pw *pw, json_object *json_pws)
     685             : {
     686           0 :         struct route_entry *re;
     687           0 :         struct nexthop *nexthop;
     688           0 :         struct nexthop_group *nhg;
     689           0 :         char buf_nbr[INET6_ADDRSTRLEN];
     690           0 :         char buf_nh[100];
     691           0 :         json_object *json_pw = NULL;
     692           0 :         json_object *json_nexthop = NULL;
     693           0 :         json_object *json_nexthops = NULL;
     694             : 
     695           0 :         json_nexthops = json_object_new_array();
     696           0 :         json_pw = json_object_new_object();
     697             : 
     698           0 :         json_object_string_add(json_pw, "interface", pw->ifname);
     699           0 :         if (pw->af == AF_UNSPEC)
     700           0 :                 json_object_string_add(json_pw, "neighbor", "-");
     701             :         else {
     702           0 :                 inet_ntop(pw->af, &pw->nexthop, buf_nbr, sizeof(buf_nbr));
     703           0 :                 json_object_string_add(json_pw, "neighbor", buf_nbr);
     704             :         }
     705           0 :         if (pw->local_label != MPLS_NO_LABEL)
     706           0 :                 json_object_int_add(json_pw, "localLabel", pw->local_label);
     707             :         else
     708           0 :                 json_object_string_add(json_pw, "localLabel", "-");
     709           0 :         if (pw->remote_label != MPLS_NO_LABEL)
     710           0 :                 json_object_int_add(json_pw, "remoteLabel", pw->remote_label);
     711             :         else
     712           0 :                 json_object_string_add(json_pw, "remoteLabel", "-");
     713           0 :         json_object_string_add(json_pw, "protocol",
     714           0 :                                zebra_route_string(pw->protocol));
     715           0 :         if (pw->protocol == ZEBRA_ROUTE_LDP)
     716           0 :                 json_object_int_add(json_pw, "vcId", pw->data.ldp.pwid);
     717           0 :         json_object_string_add(
     718             :                 json_pw, "Status",
     719           0 :                 (zebra_pw_enabled(pw) && pw->status == PW_FORWARDING) ? "Up"
     720             :                                                                       : "Down");
     721           0 :         re = rib_match(family2afi(pw->af), SAFI_UNICAST, pw->vrf_id,
     722           0 :                        &pw->nexthop, NULL);
     723           0 :         if (re == NULL)
     724           0 :                 goto done;
     725             : 
     726           0 :         nhg = rib_get_fib_nhg(re);
     727           0 :         for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
     728           0 :                 json_nexthop = json_object_new_object();
     729           0 :                 snprintfrr(buf_nh, sizeof(buf_nh), "%pNHv", nexthop);
     730           0 :                 json_object_string_add(json_nexthop, "nexthop", buf_nh);
     731           0 :                 if (nexthop->nh_label)
     732           0 :                         json_object_int_add(
     733             :                                 json_nexthop, "nhLabel",
     734           0 :                                 nexthop->nh_label->label[0]);
     735             :                 else
     736           0 :                         json_object_string_add(json_nexthop, "nhLabel",
     737             :                                                "-");
     738             : 
     739           0 :                 json_object_array_add(json_nexthops, json_nexthop);
     740             :         }
     741             : 
     742             :         /* Include installed backup nexthops also */
     743           0 :         nhg = rib_get_fib_backup_nhg(re);
     744           0 :         if (nhg == NULL)
     745             :                 goto done;
     746             : 
     747           0 :         for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
     748           0 :                 json_nexthop = json_object_new_object();
     749           0 :                 snprintfrr(buf_nh, sizeof(buf_nh), "%pNHv", nexthop);
     750           0 :                 json_object_string_add(json_nexthop, "nexthop", buf_nh);
     751           0 :                 if (nexthop->nh_label)
     752           0 :                         json_object_int_add(
     753             :                                 json_nexthop, "nhLabel",
     754           0 :                                 nexthop->nh_label->label[0]);
     755             :                 else
     756           0 :                         json_object_string_add(json_nexthop, "nhLabel",
     757             :                                                "-");
     758             : 
     759           0 :                 json_object_array_add(json_nexthops, json_nexthop);
     760             :         }
     761             : 
     762           0 : done:
     763             : 
     764           0 :         json_object_object_add(json_pw, "nexthops", json_nexthops);
     765           0 :         json_object_array_add(json_pws, json_pw);
     766           0 : }
     767             : 
     768           0 : static void vty_show_mpls_pseudowire_detail_json(struct vty *vty)
     769             : {
     770           0 :         json_object *json = NULL;
     771           0 :         json_object *json_pws = NULL;
     772           0 :         struct zebra_vrf *zvrf;
     773           0 :         struct zebra_pw *pw;
     774             : 
     775           0 :         zvrf = vrf_info_lookup(VRF_DEFAULT);
     776           0 :         if (!zvrf)
     777             :                 return;
     778             : 
     779           0 :         json = json_object_new_object();
     780           0 :         json_pws = json_object_new_array();
     781           0 :         RB_FOREACH (pw, zebra_pw_head, &zvrf->pseudowires) {
     782           0 :                 vty_show_mpls_pseudowire(pw, json_pws);
     783             :         }
     784           0 :         json_object_object_add(json, "pw", json_pws);
     785           0 :         vty_json(vty, json);
     786             : }
     787             : 
     788           0 : DEFUN(show_pseudowires_detail, show_pseudowires_detail_cmd,
     789             :       "show mpls pseudowires detail [json]$json",
     790             :       SHOW_STR MPLS_STR
     791             :       "Pseudowires\n"
     792             :       "Detailed output\n" JSON_STR)
     793             : {
     794           0 :         bool uj = use_json(argc, argv);
     795             : 
     796           0 :         if (uj)
     797           0 :                 vty_show_mpls_pseudowire_detail_json(vty);
     798             :         else
     799           0 :                 vty_show_mpls_pseudowire_detail(vty);
     800             : 
     801           0 :         return CMD_SUCCESS;
     802             : }
     803             : 
     804             : /* Pseudowire configuration write function. */
     805           0 : static int zebra_pw_config(struct vty *vty)
     806             : {
     807           0 :         int write = 0;
     808           0 :         struct zebra_vrf *zvrf;
     809           0 :         struct zebra_pw *pw;
     810             : 
     811           0 :         zvrf = vrf_info_lookup(VRF_DEFAULT);
     812           0 :         if (!zvrf)
     813             :                 return 0;
     814             : 
     815           0 :         RB_FOREACH (pw, zebra_static_pw_head, &zvrf->static_pseudowires) {
     816           0 :                 vty_out(vty, "pseudowire %s\n", pw->ifname);
     817           0 :                 if (pw->local_label != MPLS_NO_LABEL
     818           0 :                     && pw->remote_label != MPLS_NO_LABEL)
     819           0 :                         vty_out(vty, " mpls label local %u remote %u\n",
     820             :                                 pw->local_label, pw->remote_label);
     821             :                 else
     822           0 :                         vty_out(vty,
     823             :                                 " ! Incomplete config, specify the static MPLS labels\n");
     824             : 
     825           0 :                 if (pw->af != AF_UNSPEC) {
     826           0 :                         char buf[INET6_ADDRSTRLEN];
     827           0 :                         inet_ntop(pw->af, &pw->nexthop, buf, sizeof(buf));
     828           0 :                         vty_out(vty, " neighbor %s\n", buf);
     829             :                 } else
     830           0 :                         vty_out(vty,
     831             :                                 " ! Incomplete config, specify a neighbor address\n");
     832             : 
     833           0 :                 if (!(pw->flags & F_PSEUDOWIRE_CWORD))
     834           0 :                         vty_out(vty, " control-word exclude\n");
     835             : 
     836           0 :                 vty_out(vty, "exit\n");
     837           0 :                 vty_out(vty, "!\n");
     838           0 :                 write = 1;
     839             :         }
     840             : 
     841             :         return write;
     842             : }
     843             : 
     844             : static int zebra_pw_config(struct vty *vty);
     845             : static struct cmd_node pw_node = {
     846             :         .name = "pw",
     847             :         .node = PW_NODE,
     848             :         .parent_node = CONFIG_NODE,
     849             :         .prompt = "%s(config-pw)# ",
     850             :         .config_write = zebra_pw_config,
     851             : };
     852             : 
     853          93 : void zebra_pw_vty_init(void)
     854             : {
     855          93 :         install_node(&pw_node);
     856          93 :         install_default(PW_NODE);
     857             : 
     858          93 :         install_element(CONFIG_NODE, &pseudowire_if_cmd);
     859          93 :         install_element(CONFIG_NODE, &no_pseudowire_if_cmd);
     860          93 :         install_element(PW_NODE, &pseudowire_labels_cmd);
     861          93 :         install_element(PW_NODE, &pseudowire_neighbor_cmd);
     862          93 :         install_element(PW_NODE, &pseudowire_control_word_cmd);
     863             : 
     864          93 :         install_element(VIEW_NODE, &show_pseudowires_cmd);
     865          93 :         install_element(VIEW_NODE, &show_pseudowires_detail_cmd);
     866          93 : }

Generated by: LCOV version v1.16-topotato