Merge pull request #783 from opensourcerouting/pw-manager-2

Add Pseudowire management in Zebra
This commit is contained in:
Donald Sharp 2017-08-08 07:54:32 -04:00 committed by GitHub
commit f66e92bc48
36 changed files with 1419 additions and 95 deletions

View File

@ -234,6 +234,7 @@ void
l2vpn_pw_init(struct l2vpn_pw *pw)
{
struct fec fec;
struct zapi_pw zpw;
l2vpn_pw_reset(pw);
@ -241,16 +242,23 @@ l2vpn_pw_init(struct l2vpn_pw *pw)
lde_kernel_insert(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0, 0,
0, (void *)pw);
lde_kernel_update(&fec);
pw2zpw(pw, &zpw);
lde_imsg_compose_parent(IMSG_KPW_ADD, 0, &zpw, sizeof(zpw));
}
void
l2vpn_pw_exit(struct l2vpn_pw *pw)
{
struct fec fec;
struct zapi_pw zpw;
l2vpn_pw_fec(pw, &fec);
lde_kernel_remove(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0, 0);
lde_kernel_update(&fec);
pw2zpw(pw, &zpw);
lde_imsg_compose_parent(IMSG_KPW_DELETE, 0, &zpw, sizeof(zpw));
}
static void
@ -268,7 +276,8 @@ l2vpn_pw_reset(struct l2vpn_pw *pw)
{
pw->remote_group = 0;
pw->remote_mtu = 0;
pw->remote_status = 0;
pw->local_status = PW_FORWARDING;
pw->remote_status = PW_NOT_FORWARDING;
if (pw->flags & F_PW_CWORD_CONF)
pw->flags |= F_PW_CWORD;
@ -474,6 +483,56 @@ l2vpn_recv_pw_status_wcard(struct lde_nbr *ln, struct notify_msg *nm)
}
}
int
l2vpn_pw_status_update(struct zapi_pw_status *zpw)
{
struct l2vpn *l2vpn;
struct l2vpn_pw *pw = NULL;
struct lde_nbr *ln;
struct fec fec;
uint32_t local_status;
RB_FOREACH(l2vpn, l2vpn_head, &ldeconf->l2vpn_tree) {
pw = l2vpn_pw_find(l2vpn, zpw->ifname);
if (pw)
break;
}
if (!pw) {
log_warnx("%s: pseudowire %s not found", __func__, zpw->ifname);
return (1);
}
if (zpw->status == PW_STATUS_UP)
local_status = PW_FORWARDING;
else
local_status = PW_NOT_FORWARDING;
/* local status didn't change */
if (pw->local_status == local_status)
return (0);
pw->local_status = local_status;
/* notify remote peer about the status update */
ln = lde_nbr_find_by_lsrid(pw->lsr_id);
if (ln == NULL)
return (0);
l2vpn_pw_fec(pw, &fec);
if (pw->flags & F_PW_STATUSTLV)
l2vpn_send_pw_status(ln, local_status, &fec);
else {
struct fec_node *fn;
fn = (struct fec_node *)fec_find(&ft, &fec);
if (fn) {
if (pw->local_status == PW_FORWARDING)
lde_send_labelmapping(ln, fn, 1);
else
lde_send_labelwithdraw(ln, fn, NULL, NULL);
}
}
return (0);
}
void
l2vpn_pw_ctl(pid_t pid)
{
@ -490,7 +549,9 @@ l2vpn_pw_ctl(pid_t pid)
sizeof(pwctl.ifname));
pwctl.pwid = pw->pwid;
pwctl.lsr_id = pw->lsr_id;
pwctl.status = pw->flags & F_PW_STATUS_UP;
if (pw->local_status == PW_FORWARDING &&
pw->remote_status == PW_FORWARDING)
pwctl.status = 1;
lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_PW, 0,
pid, &pwctl, sizeof(pwctl));

View File

@ -491,6 +491,15 @@ lde_dispatch_parent(struct thread *thread)
}
}
break;
case IMSG_PW_UPDATE:
if (imsg.hdr.len != IMSG_HEADER_SIZE +
sizeof(struct zapi_pw_status))
fatalx("PW_UPDATE imsg with wrong len");
if (l2vpn_pw_status_update(imsg.data) != 0)
log_warnx("%s: error updating PW status",
__func__);
break;
case IMSG_NETWORK_ADD:
case IMSG_NETWORK_UPDATE:
if (imsg.hdr.len != IMSG_HEADER_SIZE +
@ -731,7 +740,7 @@ void
lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh)
{
struct kroute kr;
struct kpw kpw;
struct zapi_pw zpw;
struct l2vpn_pw *pw;
switch (fn->fec.type) {
@ -769,19 +778,10 @@ lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh)
return;
pw = (struct l2vpn_pw *) fn->data;
pw->flags |= F_PW_STATUS_UP;
memset(&kpw, 0, sizeof(kpw));
kpw.ifindex = pw->ifindex;
kpw.pw_type = fn->fec.u.pwid.type;
kpw.af = pw->af;
kpw.nexthop = pw->addr;
kpw.local_label = fn->local_label;
kpw.remote_label = fnh->remote_label;
kpw.flags = pw->flags;
lde_imsg_compose_parent(IMSG_KPWLABEL_CHANGE, 0, &kpw,
sizeof(kpw));
pw2zpw(pw, &zpw);
zpw.local_label = fn->local_label;
zpw.remote_label = fnh->remote_label;
lde_imsg_compose_parent(IMSG_KPW_SET, 0, &zpw, sizeof(zpw));
break;
}
}
@ -790,7 +790,7 @@ void
lde_send_delete_klabel(struct fec_node *fn, struct fec_nh *fnh)
{
struct kroute kr;
struct kpw kpw;
struct zapi_pw zpw;
struct l2vpn_pw *pw;
switch (fn->fec.type) {
@ -824,21 +824,10 @@ lde_send_delete_klabel(struct fec_node *fn, struct fec_nh *fnh)
break;
case FEC_TYPE_PWID:
pw = (struct l2vpn_pw *) fn->data;
if (!(pw->flags & F_PW_STATUS_UP))
return;
pw->flags &= ~F_PW_STATUS_UP;
memset(&kpw, 0, sizeof(kpw));
kpw.ifindex = pw->ifindex;
kpw.pw_type = fn->fec.u.pwid.type;
kpw.af = pw->af;
kpw.nexthop = pw->addr;
kpw.local_label = fn->local_label;
kpw.remote_label = fnh->remote_label;
kpw.flags = pw->flags;
lde_imsg_compose_parent(IMSG_KPWLABEL_DELETE, 0, &kpw,
sizeof(kpw));
pw2zpw(pw, &zpw);
zpw.local_label = fn->local_label;
zpw.remote_label = fnh->remote_label;
lde_imsg_compose_parent(IMSG_KPW_UNSET, 0, &zpw, sizeof(zpw));
break;
}
}
@ -919,8 +908,12 @@ lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single)
*/
lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec);
if (lw) {
if (!fec_find(&ln->sent_map_pending, &fn->fec))
if (!fec_find(&ln->sent_map_pending, &fn->fec)) {
debug_evt("%s: FEC %s: scheduling to send label "
"mapping later (waiting for pending label release)",
__func__, log_fec(&fn->fec));
lde_map_pending_add(ln, fn);
}
return;
}
@ -966,8 +959,7 @@ lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single)
map.flags |= F_MAP_PW_CWORD;
if (pw->flags & F_PW_STATUSTLV) {
map.flags |= F_MAP_PW_STATUS;
/* VPLS are always up */
map.pw_status = PW_FORWARDING;
map.pw_status = pw->local_status;
}
break;
}

View File

@ -238,6 +238,7 @@ void l2vpn_send_pw_status_wcard(struct lde_nbr *, uint32_t,
void l2vpn_recv_pw_status(struct lde_nbr *, struct notify_msg *);
void l2vpn_recv_pw_status_wcard(struct lde_nbr *,
struct notify_msg *);
int l2vpn_pw_status_update(struct zapi_pw_status *);
void l2vpn_pw_ctl(pid_t);
void l2vpn_binding_ctl(pid_t);

View File

@ -396,7 +396,7 @@ lde_kernel_update(struct fec *fec)
lde_gc_start_timer();
} else {
fn->local_label = lde_update_label(fn);
if (fn->local_label != NO_LABEL && RB_EMPTY(&fn->upstream))
if (fn->local_label != NO_LABEL)
/* FEC.1: perform lsr label distribution procedure */
RB_FOREACH(ln, nbr_tree, &lde_nbrs)
lde_send_labelmapping(ln, fn, 1);
@ -531,6 +531,8 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln)
pw->remote_mtu = map->fec.pwid.ifmtu;
if (map->flags & F_MAP_PW_STATUS)
pw->remote_status = map->pw_status;
else
pw->remote_status = PW_FORWARDING;
fnh->remote_label = map->label;
if (l2vpn_pw_ok(pw, fnh))
lde_send_change_klabel(fn, fnh);
@ -780,6 +782,7 @@ lde_check_withdraw(struct map *map, struct lde_nbr *ln)
pw = (struct l2vpn_pw *) fn->data;
if (pw == NULL)
continue;
pw->remote_status = PW_NOT_FORWARDING;
break;
default:
break;
@ -808,6 +811,7 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln)
struct fec_node *fn;
struct fec_nh *fnh;
struct lde_map *me;
struct l2vpn_pw *pw;
/* LWd.2: send label release */
lde_send_labelrelease(ln, NULL, map, map->label);
@ -831,6 +835,9 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln)
case FEC_TYPE_PWID:
if (f->u.pwid.lsr_id.s_addr != ln->id.s_addr)
continue;
pw = (struct l2vpn_pw *) fn->data;
if (pw)
pw->remote_status = PW_NOT_FORWARDING;
break;
default:
break;

View File

@ -285,9 +285,6 @@ struct address_list_tlv {
#define MAP_TYPE_GENPWID 0x81
#define CONTROL_WORD_FLAG 0x8000
#define PW_TYPE_ETHERNET_TAGGED 0x0004
#define PW_TYPE_ETHERNET 0x0005
#define PW_TYPE_WILDCARD 0x7FFF
#define DEFAULT_PW_TYPE PW_TYPE_ETHERNET
#define PW_TWCARD_RESERVED_BIT 0x8000

View File

@ -54,6 +54,8 @@ static int ldp_interface_address_delete(int, struct zclient *,
zebra_size_t, vrf_id_t);
static int ldp_zebra_read_route(int, struct zclient *, zebra_size_t,
vrf_id_t);
static int ldp_zebra_read_pw_status_update(int, struct zclient *,
zebra_size_t, vrf_id_t);
static void ldp_zebra_connected(struct zclient *);
static struct zclient *zclient;
@ -94,6 +96,25 @@ ifc2kaddr(struct interface *ifp, struct connected *ifc, struct kaddr *ka)
}
}
void
pw2zpw(struct l2vpn_pw *pw, struct zapi_pw *zpw)
{
memset(zpw, 0, sizeof(*zpw));
strlcpy(zpw->ifname, pw->ifname, sizeof(zpw->ifname));
zpw->ifindex = pw->ifindex;
zpw->type = pw->l2vpn->pw_type;
zpw->af = pw->af;
zpw->nexthop.ipv6 = pw->addr.v6;
zpw->local_label = NO_LABEL;
zpw->remote_label = NO_LABEL;
if (pw->flags & F_PW_CWORD)
zpw->flags = F_PSEUDOWIRE_CWORD;
zpw->data.ldp.lsr_id = pw->lsr_id;
zpw->data.ldp.pwid = pw->pwid;
strlcpy(zpw->data.ldp.vpn_name, pw->l2vpn->name,
sizeof(zpw->data.ldp.vpn_name));
}
static int
zebra_send_mpls_labels(int cmd, struct kroute *kr)
{
@ -154,17 +175,40 @@ kr_delete(struct kroute *kr)
}
int
kmpw_set(struct kpw *kpw)
kmpw_add(struct zapi_pw *zpw)
{
/* TODO */
return (0);
debug_zebra_out("pseudowire %s nexthop %s (add)",
zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop));
return (zebra_send_pw(zclient, ZEBRA_PW_ADD, zpw));
}
int
kmpw_unset(struct kpw *kpw)
kmpw_del(struct zapi_pw *zpw)
{
/* TODO */
return (0);
debug_zebra_out("pseudowire %s nexthop %s (del)",
zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop));
return (zebra_send_pw(zclient, ZEBRA_PW_DELETE, zpw));
}
int
kmpw_set(struct zapi_pw *zpw)
{
debug_zebra_out("pseudowire %s nexthop %s labels %u/%u (set)",
zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop),
zpw->local_label, zpw->remote_label);
return (zebra_send_pw(zclient, ZEBRA_PW_SET, zpw));
}
int
kmpw_unset(struct zapi_pw *zpw)
{
debug_zebra_out("pseudowire %s nexthop %s (unset)",
zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop));
return (zebra_send_pw(zclient, ZEBRA_PW_UNSET, zpw));
}
void
@ -466,6 +510,25 @@ ldp_zebra_read_route(int command, struct zclient *zclient, zebra_size_t length,
return (0);
}
/*
* Receive PW status update from Zebra and send it to LDE process.
*/
static int
ldp_zebra_read_pw_status_update(int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id)
{
struct zapi_pw_status zpw;
zebra_read_pw_status_update(command, zclient, length, vrf_id, &zpw);
debug_zebra_in("pseudowire %s status %s", zpw.ifname,
(zpw.status == PW_STATUS_UP) ? "up" : "down");
main_imsg_compose_lde(IMSG_PW_UPDATE, 0, &zpw, sizeof(zpw));
return (0);
}
static void
ldp_zebra_connected(struct zclient *zclient)
{
@ -496,6 +559,7 @@ ldp_zebra_init(struct thread_master *master)
zclient->redistribute_route_ipv4_del = ldp_zebra_read_route;
zclient->redistribute_route_ipv6_add = ldp_zebra_read_route;
zclient->redistribute_route_ipv6_del = ldp_zebra_read_route;
zclient->pw_status_update = ldp_zebra_read_pw_status_update;
}
void

View File

@ -591,21 +591,36 @@ main_dispatch_lde(struct thread *thread)
if (kr_delete(imsg.data))
log_warnx("%s: error deleting route", __func__);
break;
case IMSG_KPWLABEL_CHANGE:
case IMSG_KPW_ADD:
case IMSG_KPW_DELETE:
case IMSG_KPW_SET:
case IMSG_KPW_UNSET:
if (imsg.hdr.len - IMSG_HEADER_SIZE !=
sizeof(struct kpw))
sizeof(struct zapi_pw))
fatalx("invalid size of IMSG_KPWLABEL_CHANGE");
if (kmpw_set(imsg.data))
log_warnx("%s: error changing pseudowire",
__func__);
switch (imsg.hdr.type) {
case IMSG_KPW_ADD:
if (kmpw_add(imsg.data))
log_warnx("%s: error adding "
"pseudowire", __func__);
break;
case IMSG_KPWLABEL_DELETE:
if (imsg.hdr.len - IMSG_HEADER_SIZE !=
sizeof(struct kpw))
fatalx("invalid size of IMSG_KPWLABEL_DELETE");
case IMSG_KPW_DELETE:
if (kmpw_del(imsg.data))
log_warnx("%s: error deleting "
"pseudowire", __func__);
break;
case IMSG_KPW_SET:
if (kmpw_set(imsg.data))
log_warnx("%s: error setting "
"pseudowire", __func__);
break;
case IMSG_KPW_UNSET:
if (kmpw_unset(imsg.data))
log_warnx("%s: error unsetting pseudowire",
__func__);
log_warnx("%s: error unsetting "
"pseudowire", __func__);
break;
}
break;
case IMSG_ACL_CHECK:
if (imsg.hdr.len != IMSG_HEADER_SIZE +

View File

@ -29,6 +29,8 @@
#include "qobj.h"
#include "prefix.h"
#include "filter.h"
#include "pw.h"
#include "zclient.h"
#include "ldp.h"
@ -43,7 +45,6 @@
#define LDPD_OPT_NOACTION 0x00000004
#define TCP_MD5_KEY_LEN 80
#define L2VPN_NAME_LEN 32
#define RT_BUF_SIZE 16384
#define MAX_RTSOCK_BUF 128 * 1024
@ -101,8 +102,10 @@ enum imsg_type {
IMSG_CTL_LOG_VERBOSE,
IMSG_KLABEL_CHANGE,
IMSG_KLABEL_DELETE,
IMSG_KPWLABEL_CHANGE,
IMSG_KPWLABEL_DELETE,
IMSG_KPW_ADD,
IMSG_KPW_DELETE,
IMSG_KPW_SET,
IMSG_KPW_UNSET,
IMSG_IFSTATUS,
IMSG_NEWADDR,
IMSG_DELADDR,
@ -148,7 +151,8 @@ enum imsg_type {
IMSG_ACL_CHECK,
IMSG_GET_LABEL_CHUNK,
IMSG_RELEASE_LABEL_CHUNK,
IMSG_INIT
IMSG_INIT,
IMSG_PW_UPDATE
};
struct ldpd_init {
@ -408,6 +412,7 @@ struct l2vpn_pw {
unsigned int ifindex;
uint32_t remote_group;
uint16_t remote_mtu;
uint32_t local_status;
uint32_t remote_status;
uint8_t flags;
QOBJ_FIELDS
@ -419,8 +424,7 @@ DECLARE_QOBJ_TYPE(l2vpn_pw)
#define F_PW_STATUSTLV 0x02 /* status tlv negotiated */
#define F_PW_CWORD_CONF 0x04 /* control word configured */
#define F_PW_CWORD 0x08 /* control word negotiated */
#define F_PW_STATUS_UP 0x10 /* pseudowire is operational */
#define F_PW_STATIC_NBR_ADDR 0x20 /* static neighbor address configured */
#define F_PW_STATIC_NBR_ADDR 0x10 /* static neighbor address configured */
struct l2vpn {
RB_ENTRY(l2vpn) entry;
@ -544,16 +548,6 @@ struct kroute {
uint16_t flags;
};
struct kpw {
unsigned short ifindex;
int pw_type;
int af;
union ldpd_addr nexthop;
uint32_t local_label;
uint32_t remote_label;
uint8_t flags;
};
struct kaddr {
char ifname[IF_NAMESIZE];
unsigned short ifindex;
@ -670,11 +664,14 @@ struct ldpd_conf *parse_config(char *);
int cmdline_symset(char *);
/* kroute.c */
void pw2zpw(struct l2vpn_pw *, struct zapi_pw *);
void kif_redistribute(const char *);
int kr_change(struct kroute *);
int kr_delete(struct kroute *);
int kmpw_set(struct kpw *);
int kmpw_unset(struct kpw *);
int kmpw_add(struct zapi_pw *);
int kmpw_del(struct zapi_pw *);
int kmpw_set(struct zapi_pw *);
int kmpw_unset(struct zapi_pw *);
/* util.c */
uint8_t mask2prefixlen(in_addr_t);

View File

@ -73,6 +73,7 @@ pkginclude_HEADERS = \
module.h \
hook.h \
libfrr.h \
pw.h \
# end
noinst_HEADERS = \

View 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:

View 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 */
};

View File

@ -937,6 +937,11 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY (ZEBRA_LABEL_MANAGER_CONNECT),
DESC_ENTRY (ZEBRA_GET_LABEL_CHUNK),
DESC_ENTRY (ZEBRA_RELEASE_LABEL_CHUNK),
DESC_ENTRY (ZEBRA_PW_ADD),
DESC_ENTRY (ZEBRA_PW_DELETE),
DESC_ENTRY (ZEBRA_PW_SET),
DESC_ENTRY (ZEBRA_PW_UNSET),
DESC_ENTRY (ZEBRA_PW_STATUS_UPDATE),
};
#undef DESC_ENTRY

53
lib/pw.h Normal file
View File

@ -0,0 +1,53 @@
/* Pseudowire definitions
* Copyright (C) 2016 Volta Networks, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#ifndef _FRR_PW_H
#define _FRR_PW_H
/* L2VPN name length. */
#define L2VPN_NAME_LEN 32
/* Pseudowire type - LDP and BGP use the same values. */
#define PW_TYPE_ETHERNET_TAGGED 0x0004 /* RFC 4446 */
#define PW_TYPE_ETHERNET 0x0005 /* RFC 4446 */
#define PW_TYPE_WILDCARD 0x7FFF /* RFC 4863, RFC 6668 */
/* Pseudowire flags. */
#define F_PSEUDOWIRE_CWORD 0x01
/* Pseudowire status. */
#define PW_STATUS_DOWN 0
#define PW_STATUS_UP 1
/*
* Protocol-specific information about the pseudowire.
*/
union pw_protocol_fields
{
struct {
struct in_addr lsr_id;
uint32_t pwid;
char vpn_name[L2VPN_NAME_LEN];
} ldp;
struct {
/* TODO */
} bgp;
};
#endif /* _FRR_PW_H */

View File

@ -732,6 +732,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:
@ -1157,6 +1158,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:

View File

@ -1715,6 +1715,72 @@ lm_release_label_chunk (struct zclient *zclient, uint32_t start, uint32_t end)
return 0;
}
int
zebra_send_pw(struct zclient *zclient, int command, struct zapi_pw *pw)
{
struct stream *s;
/* Reset stream. */
s = zclient->obuf;
stream_reset(s);
zclient_create_header(s, command, VRF_DEFAULT);
stream_write(s, pw->ifname, IF_NAMESIZE);
stream_putl(s, pw->ifindex);
/* Put type */
stream_putl(s, pw->type);
/* Put nexthop */
stream_putl(s, pw->af);
switch (pw->af)
{
case AF_INET:
stream_put_in_addr(s, &pw->nexthop.ipv4);
break;
case AF_INET6:
stream_write(s, (u_char *)&pw->nexthop.ipv6, 16);
break;
default:
zlog_err ("%s: unknown af", __func__);
return -1;
}
/* Put labels */
stream_putl(s, pw->local_label);
stream_putl(s, pw->remote_label);
/* Put flags */
stream_putc(s, pw->flags);
/* Protocol specific fields */
stream_write(s, &pw->data, sizeof(union pw_protocol_fields));
/* Put length at the first point of the stream. */
stream_putw_at(s, 0, stream_get_endp(s));
return zclient_send_message(zclient);
}
/*
* Receive PW status update from Zebra and send it to LDE process.
*/
void
zebra_read_pw_status_update(int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id,
struct zapi_pw_status *pw)
{
struct stream *s;
memset(pw, 0, sizeof(struct zapi_pw_status));
s = zclient->ibuf;
/* Get data. */
stream_get(pw->ifname, s, IF_NAMESIZE);
pw->ifindex = stream_getl(s);
pw->status = stream_getl(s);
}
/* Zebra client message read function. */
static int
zclient_read (struct thread *thread)
@ -1899,6 +1965,10 @@ zclient_read (struct thread *thread)
if (zclient->interface_link_params)
(*zclient->interface_link_params) (command, zclient, length);
break;
case ZEBRA_PW_STATUS_UPDATE:
if (zclient->pw_status_update)
(*zclient->pw_status_update) (command, zclient, length, vrf_id);
break;
default:
break;
}

View File

@ -31,6 +31,12 @@
/* For vrf_bitmap_t. */
#include "vrf.h"
/* For union g_addr */
#include "nexthop.h"
/* For union pw_protocol_fields */
#include "pw.h"
/* For input/output buffer to zebra. */
#define ZEBRA_MAX_PACKET_SIZ 4096
@ -94,6 +100,11 @@ typedef enum {
ZEBRA_LABEL_MANAGER_CONNECT,
ZEBRA_GET_LABEL_CHUNK,
ZEBRA_RELEASE_LABEL_CHUNK,
ZEBRA_PW_ADD,
ZEBRA_PW_DELETE,
ZEBRA_PW_SET,
ZEBRA_PW_UNSET,
ZEBRA_PW_STATUS_UPDATE,
} zebra_message_types_t;
struct redist_proto
@ -164,6 +175,7 @@ struct zclient
int (*redistribute_route_ipv4_del) (int, struct zclient *, uint16_t, vrf_id_t);
int (*redistribute_route_ipv6_add) (int, struct zclient *, uint16_t, vrf_id_t);
int (*redistribute_route_ipv6_del) (int, struct zclient *, uint16_t, vrf_id_t);
int (*pw_status_update) (int, struct zclient *, uint16_t, vrf_id_t);
};
/* Zebra API message flag. */
@ -217,6 +229,27 @@ struct zapi_ipv4
vrf_id_t vrf_id;
};
struct zapi_pw
{
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 zapi_pw_status
{
char ifname[IF_NAMESIZE];
ifindex_t ifindex;
uint32_t status;
};
/* Prototypes of zebra client service functions. */
extern struct zclient *zclient_new (struct thread_master *);
extern void zclient_init (struct zclient *, int, u_short);
@ -278,6 +311,11 @@ extern int lm_label_manager_connect (struct zclient *zclient);
extern int lm_get_label_chunk (struct zclient *zclient, u_char keep,
uint32_t chunk_size, uint32_t *start, uint32_t *end);
extern int lm_release_label_chunk (struct zclient *zclient, uint32_t start, uint32_t end);
extern int zebra_send_pw(struct zclient *zclient, int command, struct zapi_pw *pw);
extern void zebra_read_pw_status_update(int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id,
struct zapi_pw_status *pw);
/* IPv6 prefix add and delete function prototype. */
struct zapi_ipv6

View 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)

View 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);

View 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)

View File

@ -33,14 +33,14 @@ zebra_SOURCES = \
zebra_ptm.c zebra_rnh.c zebra_ptm_redistribute.c \
zebra_ns.c zebra_vrf.c zebra_static.c zebra_mpls.c zebra_mpls_vty.c \
zebra_mroute.c \
label_manager.c \
label_manager.c zebra_pw.c \
# end
testzebra_SOURCES = test_main.c zebra_rib.c interface.c connected.c debug.c \
zebra_vty.c zebra_ptm.c zebra_routemap.c zebra_ns.c zebra_vrf.c \
kernel_null.c redistribute_null.c ioctl_null.c misc_null.c zebra_rnh_null.c \
zebra_ptm_null.c rtadv_null.c if_null.c zserv_null.c zebra_static.c \
zebra_memory.c zebra_mpls.c zebra_mpls_vty.c zebra_mpls_null.c
zebra_memory.c zebra_mpls.c zebra_mpls_vty.c zebra_mpls_null.c zebra_pw_null.c
noinst_HEADERS = \
zebra_memory.h \
@ -49,7 +49,8 @@ noinst_HEADERS = \
rt_netlink.h zebra_fpm_private.h zebra_rnh.h \
zebra_ptm_redistribute.h zebra_ptm.h zebra_routemap.h \
zebra_ns.h zebra_vrf.h ioctl_solaris.h zebra_static.h zebra_mpls.h \
kernel_netlink.h if_netlink.h zebra_mroute.h label_manager.h
kernel_netlink.h if_netlink.h zebra_mroute.h label_manager.h zebra_pw.h \
# end
zebra_LDADD = $(otherobj) ../lib/libfrr.la $(LIBCAP)

View File

@ -32,6 +32,7 @@ unsigned long zebra_debug_rib;
unsigned long zebra_debug_fpm;
unsigned long zebra_debug_nht;
unsigned long zebra_debug_mpls;
unsigned long zebra_debug_pw;
DEFUN (show_debugging_zebra,
show_debugging_zebra_cmd,
@ -85,6 +86,8 @@ DEFUN (show_debugging_zebra,
vty_out (vty, " Zebra next-hop tracking debugging is on%s", VTY_NEWLINE);
if (IS_ZEBRA_DEBUG_MPLS)
vty_out (vty, " Zebra MPLS debugging is on%s", VTY_NEWLINE);
if (IS_ZEBRA_DEBUG_PW)
vty_out (vty, " Zebra pseudowire debugging is on%s", VTY_NEWLINE);
return CMD_SUCCESS;
}
@ -122,6 +125,21 @@ DEFUN (debug_zebra_mpls,
return CMD_WARNING;
}
DEFUN (debug_zebra_pw,
debug_zebra_pw_cmd,
"[no] debug zebra pseudowires",
"Negate a command or set its defaults\n"
DEBUG_STR
"Zebra configuration\n"
"Debug option set for zebra pseudowires\n")
{
if (strmatch (argv[0]->text, "no"))
UNSET_FLAG (zebra_debug_pw, ZEBRA_DEBUG_PW);
else
SET_FLAG (zebra_debug_pw, ZEBRA_DEBUG_PW);
return CMD_WARNING;
}
DEFUN (debug_zebra_packet,
debug_zebra_packet_cmd,
"debug zebra packet [<recv|send>] [detail]",
@ -410,6 +428,11 @@ config_write_debug (struct vty *vty)
vty_out (vty, "debug zebra mpls%s", VTY_NEWLINE);
write++;
}
if (IS_ZEBRA_DEBUG_PW)
{
vty_out (vty, "debug zebra pseudowires%s", VTY_NEWLINE);
write++;
}
return write;
}
@ -422,6 +445,7 @@ zebra_debug_init (void)
zebra_debug_rib = 0;
zebra_debug_fpm = 0;
zebra_debug_mpls = 0;
zebra_debug_pw = 0;
install_node (&debug_node, config_write_debug);
@ -430,6 +454,7 @@ zebra_debug_init (void)
install_element (ENABLE_NODE, &debug_zebra_events_cmd);
install_element (ENABLE_NODE, &debug_zebra_nht_cmd);
install_element (ENABLE_NODE, &debug_zebra_mpls_cmd);
install_element (ENABLE_NODE, &debug_zebra_pw_cmd);
install_element (ENABLE_NODE, &debug_zebra_packet_cmd);
install_element (ENABLE_NODE, &debug_zebra_kernel_cmd);
install_element (ENABLE_NODE, &debug_zebra_kernel_msgdump_cmd);
@ -449,6 +474,7 @@ zebra_debug_init (void)
install_element (CONFIG_NODE, &debug_zebra_events_cmd);
install_element (CONFIG_NODE, &debug_zebra_nht_cmd);
install_element (CONFIG_NODE, &debug_zebra_mpls_cmd);
install_element (CONFIG_NODE, &debug_zebra_pw_cmd);
install_element (CONFIG_NODE, &debug_zebra_packet_cmd);
install_element (CONFIG_NODE, &debug_zebra_kernel_cmd);
install_element (CONFIG_NODE, &debug_zebra_kernel_msgdump_cmd);

View File

@ -43,6 +43,8 @@
#define ZEBRA_DEBUG_MPLS 0x01
#define ZEBRA_DEBUG_PW 0x01
/* Debug related macro. */
#define IS_ZEBRA_DEBUG_EVENT (zebra_debug_event & ZEBRA_DEBUG_EVENT)
@ -64,6 +66,7 @@
#define IS_ZEBRA_DEBUG_FPM (zebra_debug_fpm & ZEBRA_DEBUG_FPM)
#define IS_ZEBRA_DEBUG_NHT (zebra_debug_nht & ZEBRA_DEBUG_NHT)
#define IS_ZEBRA_DEBUG_MPLS (zebra_debug_mpls & ZEBRA_DEBUG_MPLS)
#define IS_ZEBRA_DEBUG_PW (zebra_debug_pw & ZEBRA_DEBUG_PW)
extern unsigned long zebra_debug_event;
extern unsigned long zebra_debug_packet;
@ -72,6 +75,7 @@ extern unsigned long zebra_debug_rib;
extern unsigned long zebra_debug_fpm;
extern unsigned long zebra_debug_nht;
extern unsigned long zebra_debug_mpls;
extern unsigned long zebra_debug_pw;
extern void zebra_debug_init (void);

View 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); */

View File

@ -91,6 +91,7 @@ struct rib
#define RIB_ENTRY_NEXTHOPS_CHANGED 0x2
#define RIB_ENTRY_CHANGED 0x4
#define RIB_ENTRY_SELECTED_FIB 0x8
#define RIB_ENTRY_LABELS_CHANGED 0x10
/* Nexthop information. */
u_char nexthop_num;

View File

@ -1346,7 +1346,7 @@ mpls_ftn_update (int add, struct zebra_vrf *zvrf, enum lsp_types_t type,
return 0;
SET_FLAG (rib->status, RIB_ENTRY_CHANGED);
SET_FLAG (rib->status, RIB_ENTRY_NEXTHOPS_CHANGED);
SET_FLAG (rib->status, RIB_ENTRY_LABELS_CHANGED);
rib_queue_add (rn);
return 0;
@ -1542,7 +1542,7 @@ mpls_ldp_ftn_uninstall_all (struct zebra_vrf *zvrf, int afi)
{
nexthop_del_labels (nexthop);
SET_FLAG (rib->status, RIB_ENTRY_CHANGED);
SET_FLAG (rib->status, RIB_ENTRY_NEXTHOPS_CHANGED);
SET_FLAG (rib->status, RIB_ENTRY_LABELS_CHANGED);
update = 1;
}

View File

@ -35,6 +35,7 @@ extern struct zebra_privs_t zserv_privs;
struct {
u_int32_t rtseq;
int fd;
int ioctl_fd;
} kr_state;
static int
@ -337,6 +338,90 @@ kernel_del_lsp (zebra_lsp_t *lsp)
return ret;
}
static int
kmpw_install (struct zebra_pw *pw)
{
struct ifreq ifr;
struct ifmpwreq imr;
struct sockaddr_storage ss;
struct sockaddr_in *sa_in = (struct sockaddr_in *) &ss;
struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *) &ss;
memset (&imr, 0, sizeof (imr));
switch (pw->type)
{
case PW_TYPE_ETHERNET:
imr.imr_type = IMR_TYPE_ETHERNET;
break;
case PW_TYPE_ETHERNET_TAGGED:
imr.imr_type = IMR_TYPE_ETHERNET_TAGGED;
break;
default:
zlog_err ("%s: unhandled pseudowire type (%#X)", __func__,
pw->type);
return -1;
}
if (pw->flags & F_PSEUDOWIRE_CWORD)
imr.imr_flags |= IMR_FLAG_CONTROLWORD;
/* pseudowire nexthop */
memset (&ss, 0, sizeof (ss));
switch (pw->af) {
case AF_INET:
sa_in->sin_family = AF_INET;
sa_in->sin_len = sizeof (struct sockaddr_in);
sa_in->sin_addr = pw->nexthop.ipv4;
break;
case AF_INET6:
sa_in6->sin6_family = AF_INET6;
sa_in6->sin6_len = sizeof (struct sockaddr_in6);
sa_in6->sin6_addr = pw->nexthop.ipv6;
break;
default:
zlog_err ("%s: unhandled pseudowire address-family (%u)", __func__,
pw->af);
return -1;
}
memcpy (&imr.imr_nexthop, (struct sockaddr *) &ss,
sizeof (imr.imr_nexthop));
/* pseudowire local/remote labels */
imr.imr_lshim.shim_label = pw->local_label;
imr.imr_rshim.shim_label = pw->remote_label;
/* ioctl */
memset (&ifr, 0, sizeof (ifr));
strlcpy (ifr.ifr_name, pw->ifname, sizeof (ifr.ifr_name));
ifr.ifr_data = (caddr_t) &imr;
if (ioctl (kr_state.ioctl_fd, SIOCSETMPWCFG, &ifr) == -1)
{
zlog_err ("ioctl SIOCSETMPWCFG: %s", safe_strerror (errno));
return -1;
}
return 0;
}
static int
kmpw_uninstall (struct zebra_pw *pw)
{
struct ifreq ifr;
struct ifmpwreq imr;
memset(&ifr, 0, sizeof (ifr));
memset(&imr, 0, sizeof (imr));
strlcpy (ifr.ifr_name, pw->ifname, sizeof (ifr.ifr_name));
ifr.ifr_data = (caddr_t) &imr;
if (ioctl (kr_state.ioctl_fd, SIOCSETMPWCFG, &ifr) == -1)
{
zlog_err ("ioctl SIOCSETMPWCFG: %s", safe_strerror (errno));
return -1;
}
return 0;
}
#define MAX_RTSOCK_BUF 128 * 1024
int
mpls_kernel_init (void)
@ -344,11 +429,18 @@ mpls_kernel_init (void)
int rcvbuf, default_rcvbuf;
socklen_t optlen;
if ((kr_state.fd = socket(AF_ROUTE, SOCK_RAW, 0)) == -1) {
if ((kr_state.fd = socket(AF_ROUTE, SOCK_RAW, 0)) == -1)
{
zlog_warn("%s: socket", __func__);
return -1;
}
if ((kr_state.ioctl_fd = socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0)) == -1)
{
zlog_warn("%s: ioctl socket", __func__);
return -1;
}
/* grow receive buffer, don't wanna miss messages */
optlen = sizeof (default_rcvbuf);
if (getsockopt(kr_state.fd, SOL_SOCKET, SO_RCVBUF,
@ -364,5 +456,9 @@ mpls_kernel_init (void)
kr_state.rtseq = 1;
/* register hook to install/uninstall pseudowires */
hook_register (pw_install, kmpw_install);
hook_register (pw_uninstall, kmpw_uninstall);
return 0;
}

532
zebra/zebra_pw.c Normal file
View File

@ -0,0 +1,532 @@
/* Zebra PW code
* Copyright (C) 2016 Volta Networks, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include <zebra.h>
#include "log.h"
#include "memory.h"
#include "thread.h"
#include "command.h"
#include "vrf.h"
#include "zebra/debug.h"
#include "zebra/rib.h"
#include "zebra/zserv.h"
#include "zebra/zebra_rnh.h"
#include "zebra/zebra_vrf.h"
#include "zebra/zebra_pw.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 *);
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)
{
return (strcmp(a->ifname, b->ifname));
}
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)
{
struct zebra_pw *pw;
if (IS_ZEBRA_DEBUG_PW)
zlog_debug("%u: adding pseudowire %s protocol %s",
zvrf_id(zvrf), ifname, zebra_route_string(protocol));
pw = XCALLOC(MTYPE_PW, sizeof(*pw));
strlcpy(pw->ifname, ifname, sizeof(pw->ifname));
pw->protocol = protocol;
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;
}
void zebra_pw_del(struct zebra_vrf *zvrf, struct zebra_pw *pw)
{
if (IS_ZEBRA_DEBUG_PW)
zlog_debug("%u: deleting pseudowire %s protocol %s", pw->vrf_id,
pw->ifname, zebra_route_string(pw->protocol));
/* remove nexthop tracking */
zebra_deregister_rnh_pseudowire(pw->vrf_id, pw);
/* uninstall */
if (pw->status == PW_STATUS_UP)
hook_call(pw_uninstall, pw);
else if (pw->install_retry_timer)
THREAD_TIMER_OFF(pw->install_retry_timer);
/* 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);
}
void zebra_pw_change(struct zebra_pw *pw, 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)
{
zebra_deregister_rnh_pseudowire(pw->vrf_id, pw);
pw->ifindex = ifindex;
pw->type = type;
pw->af = af;
pw->nexthop = *nexthop;
pw->local_label = local_label;
pw->remote_label = remote_label;
pw->flags = flags;
pw->data = *data;
if (zebra_pw_enabled(pw))
zebra_register_rnh_pseudowire(pw->vrf_id, pw);
else
zebra_pw_uninstall(pw);
}
struct zebra_pw *zebra_pw_find(struct zebra_vrf *zvrf, const char *ifname)
{
struct zebra_pw pw;
strlcpy(pw.ifname, ifname, sizeof(pw.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) {
zebra_pw_uninstall(pw);
/* wait for NHT and try again later */
} else {
/*
* Install or reinstall the pseudowire (e.g. to update
* parameters like the nexthop or the use of the control word).
*/
zebra_pw_install(pw);
}
}
static void zebra_pw_install(struct zebra_pw *pw)
{
if (IS_ZEBRA_DEBUG_PW)
zlog_debug("%u: installing pseudowire %s protocol %s",
pw->vrf_id, pw->ifname,
zebra_route_string(pw->protocol));
if (hook_call(pw_install, pw)) {
zebra_pw_install_failure(pw);
return;
}
if (pw->status == PW_STATUS_DOWN)
zebra_pw_update_status(pw, PW_STATUS_UP);
}
static void zebra_pw_uninstall(struct zebra_pw *pw)
{
if (pw->status == PW_STATUS_DOWN)
return;
if (IS_ZEBRA_DEBUG_PW)
zlog_debug("%u: uninstalling pseudowire %s protocol %s",
pw->vrf_id, pw->ifname,
zebra_route_string(pw->protocol));
/* ignore any possible error */
hook_call(pw_uninstall, pw);
if (zebra_pw_enabled(pw))
zebra_pw_update_status(pw, PW_STATUS_DOWN);
}
/*
* Installation of the pseudowire in the kernel or hardware has failed. This
* function will notify the pseudowire client about the failure and schedule
* to retry the installation later. This function can be called by an external
* agent that performs the pseudowire installation in an asynchronous way.
*/
void zebra_pw_install_failure(struct zebra_pw *pw)
{
if (IS_ZEBRA_DEBUG_PW)
zlog_debug("%u: failed installing pseudowire %s, "
"scheduling retry in %u seconds", pw->vrf_id,
pw->ifname, PW_INSTALL_RETRY_INTERVAL);
/* schedule to retry later */
THREAD_TIMER_OFF(pw->install_retry_timer);
pw->install_retry_timer =
thread_add_timer(zebrad.master, zebra_pw_install_retry,
pw, PW_INSTALL_RETRY_INTERVAL);
zebra_pw_update_status(pw, PW_STATUS_DOWN);
}
static int zebra_pw_install_retry(struct thread *thread)
{
struct zebra_pw *pw = THREAD_ARG(thread);
pw->install_retry_timer = NULL;
zebra_pw_install(pw);
return 0;
}
static void zebra_pw_update_status(struct zebra_pw *pw, int status)
{
pw->status = status;
if (pw->client)
zsend_pw_update(pw->client, pw);
}
static int zebra_pw_check_reachability(struct zebra_pw *pw)
{
struct rib *rib;
struct nexthop *nexthop, *tnexthop;
int recursing;
/* TODO: consider GRE/L2TPv3 tunnels in addition to MPLS LSPs */
/* find route to the remote end of the pseudowire */
rib = rib_match(family2afi(pw->af), SAFI_UNICAST, pw->vrf_id,
&pw->nexthop, NULL);
if (!rib) {
if (IS_ZEBRA_DEBUG_PW)
zlog_warn("%s: no route found for %s", __func__,
pw->ifname);
return -1;
}
/*
* Need to ensure that there's a label binding for all nexthops.
* Otherwise, ECMP for this route could render the pseudowire unusable.
*/
for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) {
if (!nexthop->nh_label) {
if (IS_ZEBRA_DEBUG_PW)
zlog_warn("%s: unlabeled route for %s",
__func__, pw->ifname);
return -1;
}
}
return 0;
}
void
zebra_pw_client_close(struct zserv *client)
{
struct vrf *vrf;
struct zebra_vrf *zvrf;
struct zebra_pw *pw, *tmp;
RB_FOREACH(vrf, vrf_id_head, &vrfs_by_id) {
zvrf = vrf->info;
RB_FOREACH_SAFE(pw, zebra_pw_head, &zvrf->pseudowires, tmp) {
if (pw->client != client)
continue;
zebra_pw_del(zvrf, pw);
}
}
}
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)
{
struct zebra_pw *pw;
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);
}

75
zebra/zebra_pw.h Normal file
View File

@ -0,0 +1,75 @@
/* Zebra PW code
* Copyright (C) 2016 Volta Networks, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#ifndef ZEBRA_PW_H_
#define ZEBRA_PW_H_
#include <net/if.h>
#include <netinet/in.h>
#include "hook.h"
#include "qobj.h"
#define PW_INSTALL_RETRY_INTERVAL 30
struct zebra_pw {
RB_ENTRY(zebra_pw) pw_entry, static_pw_entry;
vrf_id_t vrf_id;
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;
int enabled;
int status;
uint8_t protocol;
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, 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))
struct zebra_pw *zebra_pw_add(struct zebra_vrf *, const char *,
uint8_t, struct zserv *);
void zebra_pw_del(struct zebra_vrf *, struct zebra_pw *);
void zebra_pw_change(struct zebra_pw *, ifindex_t, int, int, union g_addr *,
uint32_t, uint32_t, uint8_t, union pw_protocol_fields *);
struct zebra_pw *zebra_pw_find(struct zebra_vrf *, const char *);
void zebra_pw_update(struct zebra_pw *);
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_ */

29
zebra/zebra_pw_null.c Normal file
View File

@ -0,0 +1,29 @@
/* Zebra PW code
* Copyright (C) 2016 Volta Networks, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include <zebra.h>
#include "vrf.h"
#include "zebra/rib.h"
#include "zebra/zserv.h"
#include "zebra/zebra_vrf.h"
void zebra_pw_init(struct zebra_vrf *zvrf) {}
void zebra_pw_exit(struct zebra_vrf *zvrf) {}

View File

@ -131,6 +131,7 @@ zebra_add_rnh (struct prefix *p, vrf_id_t vrfid, rnh_type_t type)
rnh->client_list = list_new();
rnh->vrf_id = vrfid;
rnh->zebra_static_route_list = list_new();
rnh->zebra_pseudowire_list = list_new();
route_lock_node (rn);
rn->info = rnh;
rnh->node = rn;
@ -168,6 +169,7 @@ zebra_free_rnh (struct rnh *rnh)
rnh->flags |= ZEBRA_NHT_DELETED;
list_free (rnh->client_list);
list_free (rnh->zebra_static_route_list);
list_free (rnh->zebra_pseudowire_list);
free_state (rnh->vrf_id, rnh->state, rnh->node);
XFREE (MTYPE_RNH, rnh);
}
@ -222,7 +224,8 @@ zebra_remove_rnh_client (struct rnh *rnh, struct zserv *client, rnh_type_t type)
}
listnode_delete(rnh->client_list, client);
if (list_isempty(rnh->client_list) &&
list_isempty(rnh->zebra_static_route_list))
list_isempty(rnh->zebra_static_route_list) &&
list_isempty(rnh->zebra_pseudowire_list))
zebra_delete_rnh(rnh, type);
}
@ -252,7 +255,8 @@ zebra_deregister_rnh_static_nh(vrf_id_t vrf_id, struct prefix *nh,
listnode_delete(rnh->zebra_static_route_list, static_rn);
if (list_isempty(rnh->client_list) &&
list_isempty(rnh->zebra_static_route_list))
list_isempty(rnh->zebra_static_route_list) &&
list_isempty(rnh->zebra_pseudowire_list))
zebra_delete_rnh(rnh, RNH_NEXTHOP_TYPE);
}
@ -301,6 +305,62 @@ zebra_deregister_rnh_static_nexthops (vrf_id_t vrf_id, struct nexthop *nexthop,
}
}
/* XXX move this utility function elsewhere? */
static void
addr2hostprefix (int af, const union g_addr *addr, struct prefix *prefix)
{
switch (af)
{
case AF_INET:
prefix->family = AF_INET;
prefix->prefixlen = IPV4_MAX_BITLEN;
prefix->u.prefix4 = addr->ipv4;
break;
case AF_INET6:
prefix->family = AF_INET6;
prefix->prefixlen = IPV6_MAX_BITLEN;
prefix->u.prefix6 = addr->ipv6;
break;
default:
zlog_warn ("%s: unknown address family %d", __func__, af);
break;
}
}
void
zebra_register_rnh_pseudowire (vrf_id_t vrf_id, struct zebra_pw *pw)
{
struct prefix nh;
struct rnh *rnh;
addr2hostprefix (pw->af, &pw->nexthop, &nh);
rnh = zebra_add_rnh (&nh, vrf_id, RNH_NEXTHOP_TYPE);
if (rnh && !listnode_lookup (rnh->zebra_pseudowire_list, pw))
{
listnode_add (rnh->zebra_pseudowire_list, pw);
pw->rnh = rnh;
zebra_evaluate_rnh (vrf_id, pw->af, 1, RNH_NEXTHOP_TYPE, &nh);
}
}
void
zebra_deregister_rnh_pseudowire (vrf_id_t vrf_id, struct zebra_pw *pw)
{
struct rnh *rnh;
rnh = pw->rnh;
if (!rnh)
return;
listnode_delete (rnh->zebra_pseudowire_list, pw);
pw->rnh = NULL;
if (list_isempty (rnh->client_list) &&
list_isempty (rnh->zebra_static_route_list) &&
list_isempty (rnh->zebra_pseudowire_list))
zebra_delete_rnh (rnh, RNH_NEXTHOP_TYPE);
}
/* Apply the NHT route-map for a client to the route (and nexthops)
* resolving a NH.
*/
@ -611,6 +671,16 @@ zebra_rnh_process_static_routes (vrf_id_t vrfid, int family,
}
}
static void
zebra_rnh_process_pseudowires (vrf_id_t vrfid, struct rnh *rnh)
{
struct zebra_pw *pw;
struct listnode *node;
for (ALL_LIST_ELEMENTS_RO (rnh->zebra_pseudowire_list, node, pw))
zebra_pw_update (pw);
}
/*
* See if a tracked nexthop entry has undergone any change, and if so,
* take appropriate action; this involves notifying any clients and/or
@ -655,6 +725,9 @@ zebra_rnh_eval_nexthop_entry (vrf_id_t vrfid, int family, int force,
/* Process static routes attached to this nexthop */
zebra_rnh_process_static_routes (vrfid, family, nrn, rnh,
prn, rnh->state);
/* Process pseudowires attached to this nexthop */
zebra_rnh_process_pseudowires (vrfid, rnh);
}
}
@ -717,7 +790,10 @@ zebra_rnh_clear_nhc_flag (vrf_id_t vrfid, int family, rnh_type_t type,
rib = zebra_rnh_resolve_entry (vrfid, family, type, nrn, rnh, &prn);
if (rib)
{
UNSET_FLAG (rib->status, RIB_ENTRY_NEXTHOPS_CHANGED);
UNSET_FLAG (rib->status, RIB_ENTRY_LABELS_CHANGED);
}
}
/* Evaluate all tracked entries (nexthops or routes for import into BGP)
@ -868,7 +944,8 @@ compare_state (struct rib *r1, struct rib *r2)
if (r1->nexthop_num != r2->nexthop_num)
return 1;
if (CHECK_FLAG(r1->status, RIB_ENTRY_NEXTHOPS_CHANGED))
if (CHECK_FLAG(r1->status, RIB_ENTRY_NEXTHOPS_CHANGED) ||
CHECK_FLAG(r1->status, RIB_ENTRY_LABELS_CHANGED))
return 1;
return 0;
@ -1030,6 +1107,8 @@ print_rnh (struct route_node *rn, struct vty *vty)
vty_out(vty, " %s(fd %d)%s", zebra_route_string(client->proto),
client->sock, rnh->filtered[client->proto] ? "(filtered)" : "");
if (!list_isempty(rnh->zebra_static_route_list))
vty_out(vty, " zebra%s", rnh->filtered[ZEBRA_ROUTE_STATIC] ? "(filtered)" : "");
vty_out(vty, " zebra[static routes]%s", rnh->filtered[ZEBRA_ROUTE_STATIC] ? "(filtered)" : "");
if (!list_isempty(rnh->zebra_pseudowire_list))
vty_out(vty, " zebra[pseudowires]");
vty_out(vty, "%s", VTY_NEWLINE);
}

View File

@ -42,6 +42,7 @@ struct rnh
struct prefix resolved_route;
struct list *client_list;
struct list *zebra_static_route_list; /* static routes dependent on this NH */
struct list *zebra_pseudowire_list; /* pseudowires dependent on this NH */
struct route_node *node;
int filtered[ZEBRA_ROUTE_MAX]; /* if this has been filtered for client */
};
@ -67,6 +68,8 @@ extern void zebra_register_rnh_static_nh(vrf_id_t, struct prefix *, struct route
extern void zebra_deregister_rnh_static_nexthops (vrf_id_t, struct nexthop *nexthop,
struct route_node *rn);
extern void zebra_deregister_rnh_static_nh(vrf_id_t, struct prefix *, struct route_node *);
extern void zebra_register_rnh_pseudowire (vrf_id_t, struct zebra_pw *);
extern void zebra_deregister_rnh_pseudowire (vrf_id_t, struct zebra_pw *);
extern void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client,
rnh_type_t type);
extern void zebra_evaluate_rnh(vrf_id_t vrfid, int family, int force, rnh_type_t type,

View File

@ -246,6 +246,7 @@ zebra_vrf_delete (struct vrf *vrf)
}
zebra_mpls_close_tables (zvrf);
zebra_pw_exit (zvrf);
for (ALL_LIST_ELEMENTS_RO (vrf->iflist, node, ifp))
if_nbr_ipv6ll_to_ipv4ll_neigh_del_all (ifp);
@ -423,6 +424,7 @@ zebra_vrf_alloc (void)
}
zebra_mpls_init_tables (zvrf);
zebra_pw_init (zvrf);
return zvrf;
}

View File

@ -24,6 +24,7 @@
#define __ZEBRA_RIB_H__
#include <zebra/zebra_ns.h>
#include <zebra/zebra_pw.h>
/* Routing table instance. */
struct zebra_vrf
@ -79,6 +80,10 @@ struct zebra_vrf
/* MPLS label forwarding table */
struct hash *lsp_table;
/* Pseudowires. */
struct zebra_pw_head pseudowires;
struct zebra_static_pw_head static_pseudowires;
/* MPLS processing flags */
u_int16_t mpls_flags;
#define MPLS_FLAG_SCHEDULE_LSPS (1 << 0)

View File

@ -932,6 +932,13 @@ vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib,
break;
}
if (nexthop->nh_label && nexthop->nh_label->num_labels)
{
json_object_string_add(json_nexthop, "labels",
mpls_label2str (nexthop->nh_label->num_labels,
nexthop->nh_label->label, buf, BUFSIZ));
}
json_object_array_add(json_nexthops, json_nexthop);
}

View File

@ -1013,6 +1013,28 @@ 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
@ -1762,14 +1784,12 @@ zread_mpls_labels (int command, struct zserv *client, u_short length,
{
mpls_lsp_install (zvrf, type, in_label, out_label, gtype, &gate,
NULL, ifindex);
if (out_label != MPLS_IMP_NULL_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, NULL, ifindex);
if (out_label != MPLS_IMP_NULL_LABEL)
mpls_ftn_update (0, zvrf, type, &prefix, gtype, &gate, ifindex,
distance, out_label);
}
@ -1933,6 +1953,103 @@ zread_label_manager_request (int cmd, struct zserv *client, vrf_id_t vrf_id)
}
}
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)
@ -1972,6 +2089,9 @@ zebra_client_close (struct zserv *client)
/* Release Label Manager chunks */
release_daemon_chunks (client->proto, client->instance);
/* Remove pseudowires associated with this client */
zebra_pw_client_close (client);
/* Close file descriptor. */
if (client->sock)
{
@ -2269,6 +2389,12 @@ zebra_client_read (struct thread *thread)
case ZEBRA_RELEASE_LABEL_CHUNK:
zread_label_manager_request (command, client, vrf_id);
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;

View File

@ -31,6 +31,8 @@
#include "zclient.h"
#include "zebra/zebra_ns.h"
#include "zebra/zebra_pw.h"
/* Default port information. */
#define ZEBRA_VTY_PORT 2601
@ -170,6 +172,7 @@ extern int zsend_interface_vrf_update (struct zserv *, struct interface *,
vrf_id_t);
extern int zsend_interface_link_params (struct zserv *, struct interface *);
extern int zsend_pw_update (struct zserv *, struct zebra_pw *);
extern pid_t pid;