mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-07-12 19:41:15 +00:00
Merge branch 'stable/3.0'
... with a lot of fixups. Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
This commit is contained in:
commit
9cdce038c5
65
ldpd/l2vpn.c
65
ldpd/l2vpn.c
@ -235,6 +235,7 @@ void
|
|||||||
l2vpn_pw_init(struct l2vpn_pw *pw)
|
l2vpn_pw_init(struct l2vpn_pw *pw)
|
||||||
{
|
{
|
||||||
struct fec fec;
|
struct fec fec;
|
||||||
|
struct zapi_pw zpw;
|
||||||
|
|
||||||
l2vpn_pw_reset(pw);
|
l2vpn_pw_reset(pw);
|
||||||
|
|
||||||
@ -242,16 +243,23 @@ l2vpn_pw_init(struct l2vpn_pw *pw)
|
|||||||
lde_kernel_insert(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0, 0,
|
lde_kernel_insert(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0, 0,
|
||||||
0, (void *)pw);
|
0, (void *)pw);
|
||||||
lde_kernel_update(&fec);
|
lde_kernel_update(&fec);
|
||||||
|
|
||||||
|
pw2zpw(pw, &zpw);
|
||||||
|
lde_imsg_compose_parent(IMSG_KPW_ADD, 0, &zpw, sizeof(zpw));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
l2vpn_pw_exit(struct l2vpn_pw *pw)
|
l2vpn_pw_exit(struct l2vpn_pw *pw)
|
||||||
{
|
{
|
||||||
struct fec fec;
|
struct fec fec;
|
||||||
|
struct zapi_pw zpw;
|
||||||
|
|
||||||
l2vpn_pw_fec(pw, &fec);
|
l2vpn_pw_fec(pw, &fec);
|
||||||
lde_kernel_remove(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0, 0);
|
lde_kernel_remove(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0, 0);
|
||||||
lde_kernel_update(&fec);
|
lde_kernel_update(&fec);
|
||||||
|
|
||||||
|
pw2zpw(pw, &zpw);
|
||||||
|
lde_imsg_compose_parent(IMSG_KPW_DELETE, 0, &zpw, sizeof(zpw));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -269,7 +277,8 @@ l2vpn_pw_reset(struct l2vpn_pw *pw)
|
|||||||
{
|
{
|
||||||
pw->remote_group = 0;
|
pw->remote_group = 0;
|
||||||
pw->remote_mtu = 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)
|
if (pw->flags & F_PW_CWORD_CONF)
|
||||||
pw->flags |= F_PW_CWORD;
|
pw->flags |= F_PW_CWORD;
|
||||||
@ -475,6 +484,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
|
void
|
||||||
l2vpn_pw_ctl(pid_t pid)
|
l2vpn_pw_ctl(pid_t pid)
|
||||||
{
|
{
|
||||||
@ -491,7 +550,9 @@ l2vpn_pw_ctl(pid_t pid)
|
|||||||
sizeof(pwctl.ifname));
|
sizeof(pwctl.ifname));
|
||||||
pwctl.pwid = pw->pwid;
|
pwctl.pwid = pw->pwid;
|
||||||
pwctl.lsr_id = pw->lsr_id;
|
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,
|
lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_PW, 0,
|
||||||
pid, &pwctl, sizeof(pwctl));
|
pid, &pwctl, sizeof(pwctl));
|
||||||
|
60
ldpd/lde.c
60
ldpd/lde.c
@ -472,6 +472,15 @@ lde_dispatch_parent(struct thread *thread)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
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_ADD:
|
||||||
case IMSG_NETWORK_UPDATE:
|
case IMSG_NETWORK_UPDATE:
|
||||||
if (imsg.hdr.len != IMSG_HEADER_SIZE +
|
if (imsg.hdr.len != IMSG_HEADER_SIZE +
|
||||||
@ -712,8 +721,8 @@ lde_update_label(struct fec_node *fn)
|
|||||||
void
|
void
|
||||||
lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh)
|
lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh)
|
||||||
{
|
{
|
||||||
struct kroute kr;
|
struct kroute kr;
|
||||||
struct kpw kpw;
|
struct zapi_pw zpw;
|
||||||
struct l2vpn_pw *pw;
|
struct l2vpn_pw *pw;
|
||||||
|
|
||||||
switch (fn->fec.type) {
|
switch (fn->fec.type) {
|
||||||
@ -751,19 +760,10 @@ lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
pw = (struct l2vpn_pw *) fn->data;
|
pw = (struct l2vpn_pw *) fn->data;
|
||||||
pw->flags |= F_PW_STATUS_UP;
|
pw2zpw(pw, &zpw);
|
||||||
|
zpw.local_label = fn->local_label;
|
||||||
memset(&kpw, 0, sizeof(kpw));
|
zpw.remote_label = fnh->remote_label;
|
||||||
kpw.ifindex = pw->ifindex;
|
lde_imsg_compose_parent(IMSG_KPW_SET, 0, &zpw, sizeof(zpw));
|
||||||
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));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -772,7 +772,7 @@ void
|
|||||||
lde_send_delete_klabel(struct fec_node *fn, struct fec_nh *fnh)
|
lde_send_delete_klabel(struct fec_node *fn, struct fec_nh *fnh)
|
||||||
{
|
{
|
||||||
struct kroute kr;
|
struct kroute kr;
|
||||||
struct kpw kpw;
|
struct zapi_pw zpw;
|
||||||
struct l2vpn_pw *pw;
|
struct l2vpn_pw *pw;
|
||||||
|
|
||||||
switch (fn->fec.type) {
|
switch (fn->fec.type) {
|
||||||
@ -806,21 +806,10 @@ lde_send_delete_klabel(struct fec_node *fn, struct fec_nh *fnh)
|
|||||||
break;
|
break;
|
||||||
case FEC_TYPE_PWID:
|
case FEC_TYPE_PWID:
|
||||||
pw = (struct l2vpn_pw *) fn->data;
|
pw = (struct l2vpn_pw *) fn->data;
|
||||||
if (!(pw->flags & F_PW_STATUS_UP))
|
pw2zpw(pw, &zpw);
|
||||||
return;
|
zpw.local_label = fn->local_label;
|
||||||
pw->flags &= ~F_PW_STATUS_UP;
|
zpw.remote_label = fnh->remote_label;
|
||||||
|
lde_imsg_compose_parent(IMSG_KPW_UNSET, 0, &zpw, sizeof(zpw));
|
||||||
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));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -901,8 +890,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);
|
lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec);
|
||||||
if (lw) {
|
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);
|
lde_map_pending_add(ln, fn);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -948,8 +941,7 @@ lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single)
|
|||||||
map.flags |= F_MAP_PW_CWORD;
|
map.flags |= F_MAP_PW_CWORD;
|
||||||
if (pw->flags & F_PW_STATUSTLV) {
|
if (pw->flags & F_PW_STATUSTLV) {
|
||||||
map.flags |= F_MAP_PW_STATUS;
|
map.flags |= F_MAP_PW_STATUS;
|
||||||
/* VPLS are always up */
|
map.pw_status = pw->local_status;
|
||||||
map.pw_status = PW_FORWARDING;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -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(struct lde_nbr *, struct notify_msg *);
|
||||||
void l2vpn_recv_pw_status_wcard(struct lde_nbr *,
|
void l2vpn_recv_pw_status_wcard(struct lde_nbr *,
|
||||||
struct notify_msg *);
|
struct notify_msg *);
|
||||||
|
int l2vpn_pw_status_update(struct zapi_pw_status *);
|
||||||
void l2vpn_pw_ctl(pid_t);
|
void l2vpn_pw_ctl(pid_t);
|
||||||
void l2vpn_binding_ctl(pid_t);
|
void l2vpn_binding_ctl(pid_t);
|
||||||
|
|
||||||
|
@ -396,8 +396,7 @@ lde_kernel_update(struct fec *fec)
|
|||||||
lde_gc_start_timer();
|
lde_gc_start_timer();
|
||||||
} else {
|
} else {
|
||||||
fn->local_label = lde_update_label(fn);
|
fn->local_label = lde_update_label(fn);
|
||||||
if (fn->local_label != NO_LABEL &&
|
if (fn->local_label != NO_LABEL)
|
||||||
RB_EMPTY(lde_map_head, &fn->upstream))
|
|
||||||
/* FEC.1: perform lsr label distribution procedure */
|
/* FEC.1: perform lsr label distribution procedure */
|
||||||
RB_FOREACH(ln, nbr_tree, &lde_nbrs)
|
RB_FOREACH(ln, nbr_tree, &lde_nbrs)
|
||||||
lde_send_labelmapping(ln, fn, 1);
|
lde_send_labelmapping(ln, fn, 1);
|
||||||
@ -531,6 +530,8 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln)
|
|||||||
pw->remote_mtu = map->fec.pwid.ifmtu;
|
pw->remote_mtu = map->fec.pwid.ifmtu;
|
||||||
if (map->flags & F_MAP_PW_STATUS)
|
if (map->flags & F_MAP_PW_STATUS)
|
||||||
pw->remote_status = map->pw_status;
|
pw->remote_status = map->pw_status;
|
||||||
|
else
|
||||||
|
pw->remote_status = PW_FORWARDING;
|
||||||
fnh->remote_label = map->label;
|
fnh->remote_label = map->label;
|
||||||
if (l2vpn_pw_ok(pw, fnh))
|
if (l2vpn_pw_ok(pw, fnh))
|
||||||
lde_send_change_klabel(fn, fnh);
|
lde_send_change_klabel(fn, fnh);
|
||||||
@ -774,6 +775,7 @@ lde_check_withdraw(struct map *map, struct lde_nbr *ln)
|
|||||||
pw = (struct l2vpn_pw *) fn->data;
|
pw = (struct l2vpn_pw *) fn->data;
|
||||||
if (pw == NULL)
|
if (pw == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
pw->remote_status = PW_NOT_FORWARDING;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -802,6 +804,7 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln)
|
|||||||
struct fec_node *fn;
|
struct fec_node *fn;
|
||||||
struct fec_nh *fnh;
|
struct fec_nh *fnh;
|
||||||
struct lde_map *me;
|
struct lde_map *me;
|
||||||
|
struct l2vpn_pw *pw;
|
||||||
|
|
||||||
/* LWd.2: send label release */
|
/* LWd.2: send label release */
|
||||||
lde_send_labelrelease(ln, NULL, map, map->label);
|
lde_send_labelrelease(ln, NULL, map, map->label);
|
||||||
@ -825,6 +828,9 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln)
|
|||||||
case FEC_TYPE_PWID:
|
case FEC_TYPE_PWID:
|
||||||
if (f->u.pwid.lsr_id.s_addr != ln->id.s_addr)
|
if (f->u.pwid.lsr_id.s_addr != ln->id.s_addr)
|
||||||
continue;
|
continue;
|
||||||
|
pw = (struct l2vpn_pw *) fn->data;
|
||||||
|
if (pw)
|
||||||
|
pw->remote_status = PW_NOT_FORWARDING;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -285,9 +285,6 @@ struct address_list_tlv {
|
|||||||
#define MAP_TYPE_GENPWID 0x81
|
#define MAP_TYPE_GENPWID 0x81
|
||||||
|
|
||||||
#define CONTROL_WORD_FLAG 0x8000
|
#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 DEFAULT_PW_TYPE PW_TYPE_ETHERNET
|
||||||
|
|
||||||
#define PW_TWCARD_RESERVED_BIT 0x8000
|
#define PW_TWCARD_RESERVED_BIT 0x8000
|
||||||
|
@ -52,6 +52,8 @@ static int ldp_interface_address_delete(int, struct zclient *,
|
|||||||
zebra_size_t, vrf_id_t);
|
zebra_size_t, vrf_id_t);
|
||||||
static int ldp_zebra_read_route(int, struct zclient *, zebra_size_t,
|
static int ldp_zebra_read_route(int, struct zclient *, zebra_size_t,
|
||||||
vrf_id_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 void ldp_zebra_connected(struct zclient *);
|
||||||
|
|
||||||
static struct zclient *zclient;
|
static struct zclient *zclient;
|
||||||
@ -92,6 +94,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
|
static int
|
||||||
zebra_send_mpls_labels(int cmd, struct kroute *kr)
|
zebra_send_mpls_labels(int cmd, struct kroute *kr)
|
||||||
{
|
{
|
||||||
@ -152,17 +173,40 @@ kr_delete(struct kroute *kr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
kmpw_set(struct kpw *kpw)
|
kmpw_add(struct zapi_pw *zpw)
|
||||||
{
|
{
|
||||||
/* TODO */
|
debug_zebra_out("pseudowire %s nexthop %s (add)",
|
||||||
return (0);
|
zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop));
|
||||||
|
|
||||||
|
return (zebra_send_pw(zclient, ZEBRA_PW_ADD, zpw));
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
kmpw_unset(struct kpw *kpw)
|
kmpw_del(struct zapi_pw *zpw)
|
||||||
{
|
{
|
||||||
/* TODO */
|
debug_zebra_out("pseudowire %s nexthop %s (del)",
|
||||||
return (0);
|
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
|
void
|
||||||
@ -464,6 +508,25 @@ ldp_zebra_read_route(int command, struct zclient *zclient, zebra_size_t length,
|
|||||||
return (0);
|
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
|
static void
|
||||||
ldp_zebra_connected(struct zclient *zclient)
|
ldp_zebra_connected(struct zclient *zclient)
|
||||||
{
|
{
|
||||||
@ -494,6 +557,7 @@ ldp_zebra_init(struct thread_master *master)
|
|||||||
zclient->redistribute_route_ipv4_del = ldp_zebra_read_route;
|
zclient->redistribute_route_ipv4_del = ldp_zebra_read_route;
|
||||||
zclient->redistribute_route_ipv6_add = ldp_zebra_read_route;
|
zclient->redistribute_route_ipv6_add = ldp_zebra_read_route;
|
||||||
zclient->redistribute_route_ipv6_del = ldp_zebra_read_route;
|
zclient->redistribute_route_ipv6_del = ldp_zebra_read_route;
|
||||||
|
zclient->pw_status_update = ldp_zebra_read_pw_status_update;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
41
ldpd/ldpd.c
41
ldpd/ldpd.c
@ -578,21 +578,36 @@ main_dispatch_lde(struct thread *thread)
|
|||||||
if (kr_delete(imsg.data))
|
if (kr_delete(imsg.data))
|
||||||
log_warnx("%s: error deleting route", __func__);
|
log_warnx("%s: error deleting route", __func__);
|
||||||
break;
|
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 !=
|
if (imsg.hdr.len - IMSG_HEADER_SIZE !=
|
||||||
sizeof(struct kpw))
|
sizeof(struct zapi_pw))
|
||||||
fatalx("invalid size of IMSG_KPWLABEL_CHANGE");
|
fatalx("invalid size of IMSG_KPWLABEL_CHANGE");
|
||||||
if (kmpw_set(imsg.data))
|
|
||||||
log_warnx("%s: error changing pseudowire",
|
switch (imsg.hdr.type) {
|
||||||
__func__);
|
case IMSG_KPW_ADD:
|
||||||
break;
|
if (kmpw_add(imsg.data))
|
||||||
case IMSG_KPWLABEL_DELETE:
|
log_warnx("%s: error adding "
|
||||||
if (imsg.hdr.len - IMSG_HEADER_SIZE !=
|
"pseudowire", __func__);
|
||||||
sizeof(struct kpw))
|
break;
|
||||||
fatalx("invalid size of IMSG_KPWLABEL_DELETE");
|
case IMSG_KPW_DELETE:
|
||||||
if (kmpw_unset(imsg.data))
|
if (kmpw_del(imsg.data))
|
||||||
log_warnx("%s: error unsetting pseudowire",
|
log_warnx("%s: error deleting "
|
||||||
__func__);
|
"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__);
|
||||||
|
break;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case IMSG_ACL_CHECK:
|
case IMSG_ACL_CHECK:
|
||||||
if (imsg.hdr.len != IMSG_HEADER_SIZE +
|
if (imsg.hdr.len != IMSG_HEADER_SIZE +
|
||||||
|
33
ldpd/ldpd.h
33
ldpd/ldpd.h
@ -30,6 +30,8 @@
|
|||||||
#include "prefix.h"
|
#include "prefix.h"
|
||||||
#include "filter.h"
|
#include "filter.h"
|
||||||
#include "vty.h"
|
#include "vty.h"
|
||||||
|
#include "pw.h"
|
||||||
|
#include "zclient.h"
|
||||||
|
|
||||||
#include "ldp.h"
|
#include "ldp.h"
|
||||||
|
|
||||||
@ -44,7 +46,6 @@
|
|||||||
#define LDPD_OPT_NOACTION 0x00000004
|
#define LDPD_OPT_NOACTION 0x00000004
|
||||||
|
|
||||||
#define TCP_MD5_KEY_LEN 80
|
#define TCP_MD5_KEY_LEN 80
|
||||||
#define L2VPN_NAME_LEN 32
|
|
||||||
|
|
||||||
#define RT_BUF_SIZE 16384
|
#define RT_BUF_SIZE 16384
|
||||||
#define MAX_RTSOCK_BUF 128 * 1024
|
#define MAX_RTSOCK_BUF 128 * 1024
|
||||||
@ -102,8 +103,10 @@ enum imsg_type {
|
|||||||
IMSG_CTL_LOG_VERBOSE,
|
IMSG_CTL_LOG_VERBOSE,
|
||||||
IMSG_KLABEL_CHANGE,
|
IMSG_KLABEL_CHANGE,
|
||||||
IMSG_KLABEL_DELETE,
|
IMSG_KLABEL_DELETE,
|
||||||
IMSG_KPWLABEL_CHANGE,
|
IMSG_KPW_ADD,
|
||||||
IMSG_KPWLABEL_DELETE,
|
IMSG_KPW_DELETE,
|
||||||
|
IMSG_KPW_SET,
|
||||||
|
IMSG_KPW_UNSET,
|
||||||
IMSG_IFSTATUS,
|
IMSG_IFSTATUS,
|
||||||
IMSG_NEWADDR,
|
IMSG_NEWADDR,
|
||||||
IMSG_DELADDR,
|
IMSG_DELADDR,
|
||||||
@ -147,7 +150,8 @@ enum imsg_type {
|
|||||||
IMSG_DEBUG_UPDATE,
|
IMSG_DEBUG_UPDATE,
|
||||||
IMSG_LOG,
|
IMSG_LOG,
|
||||||
IMSG_ACL_CHECK,
|
IMSG_ACL_CHECK,
|
||||||
IMSG_INIT
|
IMSG_INIT,
|
||||||
|
IMSG_PW_UPDATE
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ldpd_init {
|
struct ldpd_init {
|
||||||
@ -407,6 +411,7 @@ struct l2vpn_pw {
|
|||||||
unsigned int ifindex;
|
unsigned int ifindex;
|
||||||
uint32_t remote_group;
|
uint32_t remote_group;
|
||||||
uint16_t remote_mtu;
|
uint16_t remote_mtu;
|
||||||
|
uint32_t local_status;
|
||||||
uint32_t remote_status;
|
uint32_t remote_status;
|
||||||
uint8_t flags;
|
uint8_t flags;
|
||||||
QOBJ_FIELDS
|
QOBJ_FIELDS
|
||||||
@ -418,8 +423,7 @@ DECLARE_QOBJ_TYPE(l2vpn_pw)
|
|||||||
#define F_PW_STATUSTLV 0x02 /* status tlv negotiated */
|
#define F_PW_STATUSTLV 0x02 /* status tlv negotiated */
|
||||||
#define F_PW_CWORD_CONF 0x04 /* control word configured */
|
#define F_PW_CWORD_CONF 0x04 /* control word configured */
|
||||||
#define F_PW_CWORD 0x08 /* control word negotiated */
|
#define F_PW_CWORD 0x08 /* control word negotiated */
|
||||||
#define F_PW_STATUS_UP 0x10 /* pseudowire is operational */
|
#define F_PW_STATIC_NBR_ADDR 0x10 /* static neighbor address configured */
|
||||||
#define F_PW_STATIC_NBR_ADDR 0x20 /* static neighbor address configured */
|
|
||||||
|
|
||||||
struct l2vpn {
|
struct l2vpn {
|
||||||
RB_ENTRY(l2vpn) entry;
|
RB_ENTRY(l2vpn) entry;
|
||||||
@ -542,16 +546,6 @@ struct kroute {
|
|||||||
uint16_t flags;
|
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 {
|
struct kaddr {
|
||||||
char ifname[IF_NAMESIZE];
|
char ifname[IF_NAMESIZE];
|
||||||
unsigned short ifindex;
|
unsigned short ifindex;
|
||||||
@ -668,11 +662,14 @@ struct ldpd_conf *parse_config(char *);
|
|||||||
int cmdline_symset(char *);
|
int cmdline_symset(char *);
|
||||||
|
|
||||||
/* kroute.c */
|
/* kroute.c */
|
||||||
|
void pw2zpw(struct l2vpn_pw *, struct zapi_pw *);
|
||||||
void kif_redistribute(const char *);
|
void kif_redistribute(const char *);
|
||||||
int kr_change(struct kroute *);
|
int kr_change(struct kroute *);
|
||||||
int kr_delete(struct kroute *);
|
int kr_delete(struct kroute *);
|
||||||
int kmpw_set(struct kpw *);
|
int kmpw_add(struct zapi_pw *);
|
||||||
int kmpw_unset(struct kpw *);
|
int kmpw_del(struct zapi_pw *);
|
||||||
|
int kmpw_set(struct zapi_pw *);
|
||||||
|
int kmpw_unset(struct zapi_pw *);
|
||||||
|
|
||||||
/* util.c */
|
/* util.c */
|
||||||
uint8_t mask2prefixlen(in_addr_t);
|
uint8_t mask2prefixlen(in_addr_t);
|
||||||
|
@ -289,6 +289,8 @@ nbr_new(struct in_addr id, int af, int ds_tlv, union ldpd_addr *addr,
|
|||||||
void
|
void
|
||||||
nbr_del(struct nbr *nbr)
|
nbr_del(struct nbr *nbr)
|
||||||
{
|
{
|
||||||
|
struct adj *adj;
|
||||||
|
|
||||||
log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));
|
log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));
|
||||||
|
|
||||||
nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION);
|
nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION);
|
||||||
@ -314,6 +316,11 @@ nbr_del(struct nbr *nbr)
|
|||||||
mapping_list_clr(&nbr->release_list);
|
mapping_list_clr(&nbr->release_list);
|
||||||
mapping_list_clr(&nbr->abortreq_list);
|
mapping_list_clr(&nbr->abortreq_list);
|
||||||
|
|
||||||
|
while ((adj = RB_ROOT(nbr_adj_head, &nbr->adj_tree)) != NULL) {
|
||||||
|
adj->nbr = NULL;
|
||||||
|
RB_REMOVE(nbr_adj_head, &nbr->adj_tree, adj);
|
||||||
|
}
|
||||||
|
|
||||||
if (nbr->peerid)
|
if (nbr->peerid)
|
||||||
RB_REMOVE(nbr_pid_head, &nbrs_by_pid, nbr);
|
RB_REMOVE(nbr_pid_head, &nbrs_by_pid, nbr);
|
||||||
RB_REMOVE(nbr_id_head, &nbrs_by_id, nbr);
|
RB_REMOVE(nbr_id_head, &nbrs_by_id, nbr);
|
||||||
|
@ -110,6 +110,7 @@ const char *node_names[] = {
|
|||||||
"forwarding", // FORWARDING_NODE,
|
"forwarding", // FORWARDING_NODE,
|
||||||
"protocol", // PROTOCOL_NODE,
|
"protocol", // PROTOCOL_NODE,
|
||||||
"mpls", // MPLS_NODE,
|
"mpls", // MPLS_NODE,
|
||||||
|
"pw", // PW_NODE,
|
||||||
"vty", // VTY_NODE,
|
"vty", // VTY_NODE,
|
||||||
"link-params", // LINK_PARAMS_NODE,
|
"link-params", // LINK_PARAMS_NODE,
|
||||||
"bgp evpn vni", // BGP_EVPN_VNI_NODE,
|
"bgp evpn vni", // BGP_EVPN_VNI_NODE,
|
||||||
@ -1253,6 +1254,7 @@ void cmd_exit(struct vty *vty)
|
|||||||
vty_config_unlock(vty);
|
vty_config_unlock(vty);
|
||||||
break;
|
break;
|
||||||
case INTERFACE_NODE:
|
case INTERFACE_NODE:
|
||||||
|
case PW_NODE:
|
||||||
case NS_NODE:
|
case NS_NODE:
|
||||||
case VRF_NODE:
|
case VRF_NODE:
|
||||||
case ZEBRA_NODE:
|
case ZEBRA_NODE:
|
||||||
@ -1338,6 +1340,7 @@ DEFUN (config_end,
|
|||||||
break;
|
break;
|
||||||
case CONFIG_NODE:
|
case CONFIG_NODE:
|
||||||
case INTERFACE_NODE:
|
case INTERFACE_NODE:
|
||||||
|
case PW_NODE:
|
||||||
case NS_NODE:
|
case NS_NODE:
|
||||||
case VRF_NODE:
|
case VRF_NODE:
|
||||||
case ZEBRA_NODE:
|
case ZEBRA_NODE:
|
||||||
|
@ -132,6 +132,7 @@ enum node_type {
|
|||||||
FORWARDING_NODE, /* IP forwarding node. */
|
FORWARDING_NODE, /* IP forwarding node. */
|
||||||
PROTOCOL_NODE, /* protocol filtering node */
|
PROTOCOL_NODE, /* protocol filtering node */
|
||||||
MPLS_NODE, /* MPLS config node */
|
MPLS_NODE, /* MPLS config node */
|
||||||
|
PW_NODE, /* Pseudowire config node */
|
||||||
VTY_NODE, /* Vty node. */
|
VTY_NODE, /* Vty node. */
|
||||||
LINK_PARAMS_NODE, /* Link-parameters node */
|
LINK_PARAMS_NODE, /* Link-parameters node */
|
||||||
BGP_EVPN_VNI_NODE, /* BGP EVPN VNI */
|
BGP_EVPN_VNI_NODE, /* BGP EVPN VNI */
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
|
|
||||||
/* Architectual Constants */
|
/* Architectual Constants */
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
#define OSPF_LS_REFRESH_TIME 60
|
#define OSPF_LS_REFRESH_TIME 120
|
||||||
#else
|
#else
|
||||||
#define OSPF_LS_REFRESH_TIME 1800
|
#define OSPF_LS_REFRESH_TIME 1800
|
||||||
#endif
|
#endif
|
||||||
|
@ -916,6 +916,11 @@ static const struct zebra_desc_table command_types[] = {
|
|||||||
DESC_ENTRY(ZEBRA_MACIP_DEL),
|
DESC_ENTRY(ZEBRA_MACIP_DEL),
|
||||||
DESC_ENTRY(ZEBRA_REMOTE_MACIP_ADD),
|
DESC_ENTRY(ZEBRA_REMOTE_MACIP_ADD),
|
||||||
DESC_ENTRY(ZEBRA_REMOTE_MACIP_DEL),
|
DESC_ENTRY(ZEBRA_REMOTE_MACIP_DEL),
|
||||||
|
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
|
#undef DESC_ENTRY
|
||||||
|
|
||||||
|
52
lib/pw.h
Normal file
52
lib/pw.h
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
/* 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 */
|
@ -123,6 +123,7 @@ pkginclude_HEADERS += \
|
|||||||
lib/prefix.h \
|
lib/prefix.h \
|
||||||
lib/privs.h \
|
lib/privs.h \
|
||||||
lib/ptm_lib.h \
|
lib/ptm_lib.h \
|
||||||
|
lib/pw.h \
|
||||||
lib/qobj.h \
|
lib/qobj.h \
|
||||||
lib/route_types.h \
|
lib/route_types.h \
|
||||||
lib/routemap.h \
|
lib/routemap.h \
|
||||||
|
@ -684,6 +684,7 @@ static void vty_end_config(struct vty *vty)
|
|||||||
break;
|
break;
|
||||||
case CONFIG_NODE:
|
case CONFIG_NODE:
|
||||||
case INTERFACE_NODE:
|
case INTERFACE_NODE:
|
||||||
|
case PW_NODE:
|
||||||
case ZEBRA_NODE:
|
case ZEBRA_NODE:
|
||||||
case RIP_NODE:
|
case RIP_NODE:
|
||||||
case RIPNG_NODE:
|
case RIPNG_NODE:
|
||||||
@ -1094,6 +1095,7 @@ static void vty_stop_input(struct vty *vty)
|
|||||||
break;
|
break;
|
||||||
case CONFIG_NODE:
|
case CONFIG_NODE:
|
||||||
case INTERFACE_NODE:
|
case INTERFACE_NODE:
|
||||||
|
case PW_NODE:
|
||||||
case ZEBRA_NODE:
|
case ZEBRA_NODE:
|
||||||
case RIP_NODE:
|
case RIP_NODE:
|
||||||
case RIPNG_NODE:
|
case RIPNG_NODE:
|
||||||
|
@ -1834,6 +1834,69 @@ int lm_release_label_chunk(struct zclient *zclient, uint32_t start,
|
|||||||
return 0;
|
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. */
|
/* Zebra client message read function. */
|
||||||
static int zclient_read(struct thread *thread)
|
static int zclient_read(struct thread *thread)
|
||||||
{
|
{
|
||||||
@ -2061,6 +2124,11 @@ static int zclient_read(struct thread *thread)
|
|||||||
(*zclient->local_macip_del)(command, zclient, length,
|
(*zclient->local_macip_del)(command, zclient, length,
|
||||||
vrf_id);
|
vrf_id);
|
||||||
break;
|
break;
|
||||||
|
case ZEBRA_PW_STATUS_UPDATE:
|
||||||
|
if (zclient->pw_status_update)
|
||||||
|
(*zclient->pw_status_update)(command, zclient, length,
|
||||||
|
vrf_id);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,12 @@
|
|||||||
/* For vrf_bitmap_t. */
|
/* For vrf_bitmap_t. */
|
||||||
#include "vrf.h"
|
#include "vrf.h"
|
||||||
|
|
||||||
|
/* For union g_addr */
|
||||||
|
#include "nexthop.h"
|
||||||
|
|
||||||
|
/* For union pw_protocol_fields */
|
||||||
|
#include "pw.h"
|
||||||
|
|
||||||
/* For input/output buffer to zebra. */
|
/* For input/output buffer to zebra. */
|
||||||
#define ZEBRA_MAX_PACKET_SIZ 4096
|
#define ZEBRA_MAX_PACKET_SIZ 4096
|
||||||
|
|
||||||
@ -106,6 +112,11 @@ typedef enum {
|
|||||||
ZEBRA_MACIP_DEL,
|
ZEBRA_MACIP_DEL,
|
||||||
ZEBRA_REMOTE_MACIP_ADD,
|
ZEBRA_REMOTE_MACIP_ADD,
|
||||||
ZEBRA_REMOTE_MACIP_DEL,
|
ZEBRA_REMOTE_MACIP_DEL,
|
||||||
|
ZEBRA_PW_ADD,
|
||||||
|
ZEBRA_PW_DELETE,
|
||||||
|
ZEBRA_PW_SET,
|
||||||
|
ZEBRA_PW_UNSET,
|
||||||
|
ZEBRA_PW_STATUS_UPDATE,
|
||||||
} zebra_message_types_t;
|
} zebra_message_types_t;
|
||||||
|
|
||||||
struct redist_proto {
|
struct redist_proto {
|
||||||
@ -187,6 +198,7 @@ struct zclient {
|
|||||||
int (*local_vni_del)(int, struct zclient *, uint16_t, vrf_id_t);
|
int (*local_vni_del)(int, struct zclient *, uint16_t, vrf_id_t);
|
||||||
int (*local_macip_add)(int, struct zclient *, uint16_t, vrf_id_t);
|
int (*local_macip_add)(int, struct zclient *, uint16_t, vrf_id_t);
|
||||||
int (*local_macip_del)(int, struct zclient *, uint16_t, vrf_id_t);
|
int (*local_macip_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. */
|
/* Zebra API message flag. */
|
||||||
@ -266,6 +278,25 @@ struct zapi_ipv4 {
|
|||||||
vrf_id_t vrf_id;
|
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. */
|
/* Prototypes of zebra client service functions. */
|
||||||
extern struct zclient *zclient_new(struct thread_master *);
|
extern struct zclient *zclient_new(struct thread_master *);
|
||||||
extern void zclient_init(struct zclient *, int, u_short);
|
extern void zclient_init(struct zclient *, int, u_short);
|
||||||
@ -338,6 +369,12 @@ extern int lm_get_label_chunk(struct zclient *zclient, u_char keep,
|
|||||||
uint32_t *end);
|
uint32_t *end);
|
||||||
extern int lm_release_label_chunk(struct zclient *zclient, uint32_t start,
|
extern int lm_release_label_chunk(struct zclient *zclient, uint32_t start,
|
||||||
uint32_t end);
|
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. */
|
/* IPv6 prefix add and delete function prototype. */
|
||||||
|
|
||||||
struct zapi_ipv6 {
|
struct zapi_ipv6 {
|
||||||
|
@ -83,8 +83,7 @@ static void _lsdb_count_assert(struct ospf6_lsdb *lsdb)
|
|||||||
zlog_debug("PANIC !! lsdb[%p]->count = %d, real = %d", lsdb,
|
zlog_debug("PANIC !! lsdb[%p]->count = %d, real = %d", lsdb,
|
||||||
lsdb->count, num);
|
lsdb->count, num);
|
||||||
for (ALL_LSDB(lsdb, debug))
|
for (ALL_LSDB(lsdb, debug))
|
||||||
zlog_debug("%p %p %s lsdb[%p]", debug->prev, debug->next,
|
zlog_debug("%s lsdb[%p]", debug->name, debug->lsdb);
|
||||||
debug->name, debug->lsdb);
|
|
||||||
zlog_debug("DUMP END");
|
zlog_debug("DUMP END");
|
||||||
|
|
||||||
assert(num == lsdb->count);
|
assert(num == lsdb->count);
|
||||||
|
@ -147,6 +147,7 @@ vtysh_cmd_FILES = $(vtysh_scan) \
|
|||||||
$(top_srcdir)/zebra/zebra_fpm.c \
|
$(top_srcdir)/zebra/zebra_fpm.c \
|
||||||
$(top_srcdir)/zebra/zebra_ptm.c \
|
$(top_srcdir)/zebra/zebra_ptm.c \
|
||||||
$(top_srcdir)/zebra/zebra_mpls_vty.c \
|
$(top_srcdir)/zebra/zebra_mpls_vty.c \
|
||||||
|
$(top_srcdir)/zebra/zebra_pw.c \
|
||||||
$(top_srcdir)/watchfrr/watchfrr_vty.c \
|
$(top_srcdir)/watchfrr/watchfrr_vty.c \
|
||||||
$(BGP_VNC_RFAPI_SRC) $(BGP_VNC_RFP_SRC)
|
$(BGP_VNC_RFAPI_SRC) $(BGP_VNC_RFP_SRC)
|
||||||
|
|
||||||
|
@ -923,6 +923,10 @@ static struct cmd_node interface_node = {
|
|||||||
INTERFACE_NODE, "%s(config-if)# ",
|
INTERFACE_NODE, "%s(config-if)# ",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct cmd_node pw_node = {
|
||||||
|
PW_NODE, "%s(config-pw)# ",
|
||||||
|
};
|
||||||
|
|
||||||
static struct cmd_node ns_node = {
|
static struct cmd_node ns_node = {
|
||||||
NS_NODE, "%s(config-logical-router)# ",
|
NS_NODE, "%s(config-logical-router)# ",
|
||||||
};
|
};
|
||||||
@ -1418,6 +1422,7 @@ static int vtysh_exit(struct vty *vty)
|
|||||||
vty->node = ENABLE_NODE;
|
vty->node = ENABLE_NODE;
|
||||||
break;
|
break;
|
||||||
case INTERFACE_NODE:
|
case INTERFACE_NODE:
|
||||||
|
case PW_NODE:
|
||||||
case NS_NODE:
|
case NS_NODE:
|
||||||
case VRF_NODE:
|
case VRF_NODE:
|
||||||
case ZEBRA_NODE:
|
case ZEBRA_NODE:
|
||||||
@ -1671,6 +1676,15 @@ DEFUNSH(VTYSH_INTERFACE, vtysh_interface, vtysh_interface_cmd,
|
|||||||
return CMD_SUCCESS;
|
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. */
|
/* TODO Implement "no interface command in isisd. */
|
||||||
DEFSH(VTYSH_ZEBRA | VTYSH_RIPD | VTYSH_RIPNGD | VTYSH_OSPFD | VTYSH_OSPF6D
|
DEFSH(VTYSH_ZEBRA | VTYSH_RIPD | VTYSH_RIPNGD | VTYSH_OSPFD | VTYSH_OSPF6D
|
||||||
| VTYSH_EIGRPD,
|
| VTYSH_EIGRPD,
|
||||||
@ -2921,6 +2935,7 @@ void vtysh_init_vty(void)
|
|||||||
install_node(&bgp_node, NULL);
|
install_node(&bgp_node, NULL);
|
||||||
install_node(&rip_node, NULL);
|
install_node(&rip_node, NULL);
|
||||||
install_node(&interface_node, NULL);
|
install_node(&interface_node, NULL);
|
||||||
|
install_node(&pw_node, NULL);
|
||||||
install_node(&link_params_node, NULL);
|
install_node(&link_params_node, NULL);
|
||||||
install_node(&ns_node, NULL);
|
install_node(&ns_node, NULL);
|
||||||
install_node(&vrf_node, NULL);
|
install_node(&vrf_node, NULL);
|
||||||
@ -3093,6 +3108,10 @@ void vtysh_init_vty(void)
|
|||||||
install_element(LINK_PARAMS_NODE, &vtysh_exit_interface_cmd);
|
install_element(LINK_PARAMS_NODE, &vtysh_exit_interface_cmd);
|
||||||
install_element(INTERFACE_NODE, &vtysh_quit_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(NS_NODE, &vtysh_end_all_cmd);
|
||||||
|
|
||||||
install_element(CONFIG_NODE, &vtysh_ns_cmd);
|
install_element(CONFIG_NODE, &vtysh_ns_cmd);
|
||||||
@ -3168,6 +3187,7 @@ void vtysh_init_vty(void)
|
|||||||
install_element(CONFIG_NODE, &vtysh_interface_cmd);
|
install_element(CONFIG_NODE, &vtysh_interface_cmd);
|
||||||
install_element(CONFIG_NODE, &vtysh_no_interface_cmd);
|
install_element(CONFIG_NODE, &vtysh_no_interface_cmd);
|
||||||
install_element(CONFIG_NODE, &vtysh_no_interface_vrf_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(INTERFACE_NODE, &vtysh_link_params_cmd);
|
||||||
install_element(ENABLE_NODE, &vtysh_show_running_config_cmd);
|
install_element(ENABLE_NODE, &vtysh_show_running_config_cmd);
|
||||||
install_element(ENABLE_NODE, &vtysh_copy_running_config_cmd);
|
install_element(ENABLE_NODE, &vtysh_copy_running_config_cmd);
|
||||||
|
@ -181,6 +181,8 @@ void vtysh_config_parse_line(void *arg, const char *line)
|
|||||||
default:
|
default:
|
||||||
if (strncmp(line, "interface", strlen("interface")) == 0)
|
if (strncmp(line, "interface", strlen("interface")) == 0)
|
||||||
config = config_get(INTERFACE_NODE, line);
|
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)
|
else if (strncmp(line, "logical-router", strlen("ns")) == 0)
|
||||||
config = config_get(NS_NODE, line);
|
config = config_get(NS_NODE, line);
|
||||||
else if (strncmp(line, "vrf", strlen("vrf")) == 0)
|
else if (strncmp(line, "vrf", strlen("vrf")) == 0)
|
||||||
|
@ -32,6 +32,7 @@ unsigned long zebra_debug_fpm;
|
|||||||
unsigned long zebra_debug_nht;
|
unsigned long zebra_debug_nht;
|
||||||
unsigned long zebra_debug_mpls;
|
unsigned long zebra_debug_mpls;
|
||||||
unsigned long zebra_debug_vxlan;
|
unsigned long zebra_debug_vxlan;
|
||||||
|
unsigned long zebra_debug_pw;
|
||||||
|
|
||||||
DEFUN (show_debugging_zebra,
|
DEFUN (show_debugging_zebra,
|
||||||
show_debugging_zebra_cmd,
|
show_debugging_zebra_cmd,
|
||||||
@ -82,6 +83,8 @@ DEFUN (show_debugging_zebra,
|
|||||||
vty_out(vty, " Zebra next-hop tracking debugging is on\n");
|
vty_out(vty, " Zebra next-hop tracking debugging is on\n");
|
||||||
if (IS_ZEBRA_DEBUG_MPLS)
|
if (IS_ZEBRA_DEBUG_MPLS)
|
||||||
vty_out(vty, " Zebra MPLS debugging is on\n");
|
vty_out(vty, " Zebra MPLS debugging is on\n");
|
||||||
|
if (IS_ZEBRA_DEBUG_PW)
|
||||||
|
vty_out(vty, " Zebra pseudowire debugging is on\n");
|
||||||
|
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -130,6 +133,21 @@ DEFUN (debug_zebra_vxlan,
|
|||||||
return CMD_WARNING;
|
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,
|
DEFUN (debug_zebra_packet,
|
||||||
debug_zebra_packet_cmd,
|
debug_zebra_packet_cmd,
|
||||||
"debug zebra packet [<recv|send>] [detail]",
|
"debug zebra packet [<recv|send>] [detail]",
|
||||||
@ -419,6 +437,10 @@ static int config_write_debug(struct vty *vty)
|
|||||||
vty_out(vty, "debug zebra vxlan\n");
|
vty_out(vty, "debug zebra vxlan\n");
|
||||||
write++;
|
write++;
|
||||||
}
|
}
|
||||||
|
if (IS_ZEBRA_DEBUG_PW) {
|
||||||
|
vty_out(vty, "debug zebra pseudowires\n");
|
||||||
|
write++;
|
||||||
|
}
|
||||||
return write;
|
return write;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -431,6 +453,7 @@ void zebra_debug_init(void)
|
|||||||
zebra_debug_fpm = 0;
|
zebra_debug_fpm = 0;
|
||||||
zebra_debug_mpls = 0;
|
zebra_debug_mpls = 0;
|
||||||
zebra_debug_vxlan = 0;
|
zebra_debug_vxlan = 0;
|
||||||
|
zebra_debug_pw = 0;
|
||||||
|
|
||||||
install_node(&debug_node, config_write_debug);
|
install_node(&debug_node, config_write_debug);
|
||||||
|
|
||||||
@ -440,6 +463,7 @@ void zebra_debug_init(void)
|
|||||||
install_element(ENABLE_NODE, &debug_zebra_nht_cmd);
|
install_element(ENABLE_NODE, &debug_zebra_nht_cmd);
|
||||||
install_element(ENABLE_NODE, &debug_zebra_mpls_cmd);
|
install_element(ENABLE_NODE, &debug_zebra_mpls_cmd);
|
||||||
install_element(ENABLE_NODE, &debug_zebra_vxlan_cmd);
|
install_element(ENABLE_NODE, &debug_zebra_vxlan_cmd);
|
||||||
|
install_element(ENABLE_NODE, &debug_zebra_pw_cmd);
|
||||||
install_element(ENABLE_NODE, &debug_zebra_packet_cmd);
|
install_element(ENABLE_NODE, &debug_zebra_packet_cmd);
|
||||||
install_element(ENABLE_NODE, &debug_zebra_kernel_cmd);
|
install_element(ENABLE_NODE, &debug_zebra_kernel_cmd);
|
||||||
install_element(ENABLE_NODE, &debug_zebra_kernel_msgdump_cmd);
|
install_element(ENABLE_NODE, &debug_zebra_kernel_msgdump_cmd);
|
||||||
@ -459,6 +483,7 @@ void zebra_debug_init(void)
|
|||||||
install_element(CONFIG_NODE, &debug_zebra_nht_cmd);
|
install_element(CONFIG_NODE, &debug_zebra_nht_cmd);
|
||||||
install_element(CONFIG_NODE, &debug_zebra_mpls_cmd);
|
install_element(CONFIG_NODE, &debug_zebra_mpls_cmd);
|
||||||
install_element(CONFIG_NODE, &debug_zebra_vxlan_cmd);
|
install_element(CONFIG_NODE, &debug_zebra_vxlan_cmd);
|
||||||
|
install_element(CONFIG_NODE, &debug_zebra_pw_cmd);
|
||||||
install_element(CONFIG_NODE, &debug_zebra_packet_cmd);
|
install_element(CONFIG_NODE, &debug_zebra_packet_cmd);
|
||||||
install_element(CONFIG_NODE, &debug_zebra_kernel_cmd);
|
install_element(CONFIG_NODE, &debug_zebra_kernel_cmd);
|
||||||
install_element(CONFIG_NODE, &debug_zebra_kernel_msgdump_cmd);
|
install_element(CONFIG_NODE, &debug_zebra_kernel_msgdump_cmd);
|
||||||
|
@ -44,6 +44,8 @@
|
|||||||
|
|
||||||
#define ZEBRA_DEBUG_VXLAN 0x01
|
#define ZEBRA_DEBUG_VXLAN 0x01
|
||||||
|
|
||||||
|
#define ZEBRA_DEBUG_PW 0x01
|
||||||
|
|
||||||
/* Debug related macro. */
|
/* Debug related macro. */
|
||||||
#define IS_ZEBRA_DEBUG_EVENT (zebra_debug_event & ZEBRA_DEBUG_EVENT)
|
#define IS_ZEBRA_DEBUG_EVENT (zebra_debug_event & ZEBRA_DEBUG_EVENT)
|
||||||
|
|
||||||
@ -66,6 +68,7 @@
|
|||||||
#define IS_ZEBRA_DEBUG_NHT (zebra_debug_nht & ZEBRA_DEBUG_NHT)
|
#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_MPLS (zebra_debug_mpls & ZEBRA_DEBUG_MPLS)
|
||||||
#define IS_ZEBRA_DEBUG_VXLAN (zebra_debug_vxlan & ZEBRA_DEBUG_VXLAN)
|
#define IS_ZEBRA_DEBUG_VXLAN (zebra_debug_vxlan & ZEBRA_DEBUG_VXLAN)
|
||||||
|
#define IS_ZEBRA_DEBUG_PW (zebra_debug_pw & ZEBRA_DEBUG_PW)
|
||||||
|
|
||||||
extern unsigned long zebra_debug_event;
|
extern unsigned long zebra_debug_event;
|
||||||
extern unsigned long zebra_debug_packet;
|
extern unsigned long zebra_debug_packet;
|
||||||
@ -75,6 +78,7 @@ extern unsigned long zebra_debug_fpm;
|
|||||||
extern unsigned long zebra_debug_nht;
|
extern unsigned long zebra_debug_nht;
|
||||||
extern unsigned long zebra_debug_mpls;
|
extern unsigned long zebra_debug_mpls;
|
||||||
extern unsigned long zebra_debug_vxlan;
|
extern unsigned long zebra_debug_vxlan;
|
||||||
|
extern unsigned long zebra_debug_pw;
|
||||||
|
|
||||||
extern void zebra_debug_init(void);
|
extern void zebra_debug_init(void);
|
||||||
|
|
||||||
|
@ -627,6 +627,7 @@ int ifm_read(struct if_msghdr *ifm)
|
|||||||
#ifdef HAVE_NET_RT_IFLIST
|
#ifdef HAVE_NET_RT_IFLIST
|
||||||
ifp->stats = ifm->ifm_data;
|
ifp->stats = ifm->ifm_data;
|
||||||
#endif /* HAVE_NET_RT_IFLIST */
|
#endif /* HAVE_NET_RT_IFLIST */
|
||||||
|
ifp->speed = ifm->ifm_data.ifi_baudrate / 1000000;
|
||||||
|
|
||||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
if (IS_ZEBRA_DEBUG_KERNEL)
|
||||||
zlog_debug("%s: interface %s index %d", __func__, ifp->name,
|
zlog_debug("%s: interface %s index %d", __func__, ifp->name,
|
||||||
|
@ -299,6 +299,7 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
zebra_mpls_init();
|
zebra_mpls_init();
|
||||||
zebra_mpls_vty_init();
|
zebra_mpls_vty_init();
|
||||||
|
zebra_pw_vty_init();
|
||||||
|
|
||||||
/* For debug purpose. */
|
/* For debug purpose. */
|
||||||
/* SET_FLAG (zebra_debug_event, ZEBRA_DEBUG_EVENT); */
|
/* SET_FLAG (zebra_debug_event, ZEBRA_DEBUG_EVENT); */
|
||||||
|
@ -89,6 +89,7 @@ struct route_entry {
|
|||||||
#define ROUTE_ENTRY_NEXTHOPS_CHANGED 0x2
|
#define ROUTE_ENTRY_NEXTHOPS_CHANGED 0x2
|
||||||
#define ROUTE_ENTRY_CHANGED 0x4
|
#define ROUTE_ENTRY_CHANGED 0x4
|
||||||
#define ROUTE_ENTRY_SELECTED_FIB 0x8
|
#define ROUTE_ENTRY_SELECTED_FIB 0x8
|
||||||
|
#define ROUTE_ENTRY_LABELS_CHANGED 0x10
|
||||||
|
|
||||||
/* Nexthop information. */
|
/* Nexthop information. */
|
||||||
u_char nexthop_num;
|
u_char nexthop_num;
|
||||||
|
@ -56,6 +56,7 @@ zebra_zebra_SOURCES = \
|
|||||||
zebra/zebra_ns.c \
|
zebra/zebra_ns.c \
|
||||||
zebra/zebra_ptm.c \
|
zebra/zebra_ptm.c \
|
||||||
zebra/zebra_ptm_redistribute.c \
|
zebra/zebra_ptm_redistribute.c \
|
||||||
|
zebra/zebra_pw.c \
|
||||||
zebra/zebra_rib.c \
|
zebra/zebra_rib.c \
|
||||||
zebra/zebra_rnh.c \
|
zebra/zebra_rnh.c \
|
||||||
zebra/zebra_routemap.c \
|
zebra/zebra_routemap.c \
|
||||||
@ -95,6 +96,7 @@ noinst_HEADERS += \
|
|||||||
zebra/zebra_ns.h \
|
zebra/zebra_ns.h \
|
||||||
zebra/zebra_ptm.h \
|
zebra/zebra_ptm.h \
|
||||||
zebra/zebra_ptm_redistribute.h \
|
zebra/zebra_ptm_redistribute.h \
|
||||||
|
zebra/zebra_pw.h \
|
||||||
zebra/zebra_rnh.h \
|
zebra/zebra_rnh.h \
|
||||||
zebra/zebra_routemap.h \
|
zebra/zebra_routemap.h \
|
||||||
zebra/zebra_static.h \
|
zebra/zebra_static.h \
|
||||||
|
@ -2222,7 +2222,7 @@ found:
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
|
SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
|
||||||
SET_FLAG(re->status, ROUTE_ENTRY_NEXTHOPS_CHANGED);
|
SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED);
|
||||||
rib_queue_add(rn);
|
rib_queue_add(rn);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -2405,7 +2405,7 @@ void mpls_ldp_ftn_uninstall_all(struct zebra_vrf *zvrf, int afi)
|
|||||||
nexthop_del_labels(nexthop);
|
nexthop_del_labels(nexthop);
|
||||||
SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
|
SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
|
||||||
SET_FLAG(re->status,
|
SET_FLAG(re->status,
|
||||||
ROUTE_ENTRY_NEXTHOPS_CHANGED);
|
ROUTE_ENTRY_LABELS_CHANGED);
|
||||||
update = 1;
|
update = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@ extern struct zebra_privs_t zserv_privs;
|
|||||||
struct {
|
struct {
|
||||||
u_int32_t rtseq;
|
u_int32_t rtseq;
|
||||||
int fd;
|
int fd;
|
||||||
|
int ioctl_fd;
|
||||||
} kr_state;
|
} kr_state;
|
||||||
|
|
||||||
static int kernel_send_rtmsg_v4(int action, mpls_label_t in_label,
|
static int kernel_send_rtmsg_v4(int action, mpls_label_t in_label,
|
||||||
@ -330,6 +331,85 @@ int kernel_del_lsp(zebra_lsp_t *lsp)
|
|||||||
return ret;
|
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
|
#define MAX_RTSOCK_BUF 128 * 1024
|
||||||
int mpls_kernel_init(void)
|
int mpls_kernel_init(void)
|
||||||
{
|
{
|
||||||
@ -341,6 +421,12 @@ int mpls_kernel_init(void)
|
|||||||
return -1;
|
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 */
|
/* grow receive buffer, don't wanna miss messages */
|
||||||
optlen = sizeof(default_rcvbuf);
|
optlen = sizeof(default_rcvbuf);
|
||||||
if (getsockopt(kr_state.fd, SOL_SOCKET, SO_RCVBUF, &default_rcvbuf,
|
if (getsockopt(kr_state.fd, SOL_SOCKET, SO_RCVBUF, &default_rcvbuf,
|
||||||
@ -359,6 +445,10 @@ int mpls_kernel_init(void)
|
|||||||
|
|
||||||
kr_state.rtseq = 1;
|
kr_state.rtseq = 1;
|
||||||
|
|
||||||
|
/* register hook to install/uninstall pseudowires */
|
||||||
|
hook_register(pw_install, kmpw_install);
|
||||||
|
hook_register(pw_uninstall, kmpw_uninstall);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
533
zebra/zebra_pw.c
Normal file
533
zebra/zebra_pw.c
Normal file
@ -0,0 +1,533 @@
|
|||||||
|
/* 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))
|
||||||
|
|
||||||
|
#define MPLS_NO_LABEL MPLS_INVALID_LABEL
|
||||||
|
|
||||||
|
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);
|
||||||
|
thread_add_timer(zebrad.master, zebra_pw_install_retry, pw,
|
||||||
|
PW_INSTALL_RETRY_INTERVAL, &pw->install_retry_timer);
|
||||||
|
|
||||||
|
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 route_entry *re;
|
||||||
|
struct nexthop *nexthop;
|
||||||
|
|
||||||
|
/* TODO: consider GRE/L2TPv3 tunnels in addition to MPLS LSPs */
|
||||||
|
|
||||||
|
/* find route to the remote end of the pseudowire */
|
||||||
|
re = rib_match(family2afi(pw->af), SAFI_UNICAST, pw->vrf_id,
|
||||||
|
&pw->nexthop, NULL);
|
||||||
|
if (!re) {
|
||||||
|
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(re->nexthop, nexthop)) {
|
||||||
|
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(zebra_pw_head, &zvrf->pseudowires);
|
||||||
|
RB_INIT(zebra_static_pw_head, &zvrf->static_pseudowires);
|
||||||
|
}
|
||||||
|
|
||||||
|
void zebra_pw_exit(struct zebra_vrf *zvrf)
|
||||||
|
{
|
||||||
|
struct zebra_pw *pw;
|
||||||
|
|
||||||
|
while ((pw = RB_ROOT(zebra_pw_head, &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\n");
|
||||||
|
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\n");
|
||||||
|
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\n", "Interface", "Neighbor",
|
||||||
|
"Labels", "Protocol", "Status");
|
||||||
|
|
||||||
|
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\n", 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");
|
||||||
|
}
|
||||||
|
|
||||||
|
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\n", pw->ifname);
|
||||||
|
if (pw->local_label != MPLS_NO_LABEL
|
||||||
|
&& pw->remote_label != MPLS_NO_LABEL)
|
||||||
|
vty_out(vty, " mpls label local %u remote %u\n",
|
||||||
|
pw->local_label, pw->remote_label);
|
||||||
|
else
|
||||||
|
vty_out(vty,
|
||||||
|
" ! Incomplete config, specify the static "
|
||||||
|
"MPLS labels\n");
|
||||||
|
|
||||||
|
if (pw->af != AF_UNSPEC) {
|
||||||
|
char buf[INET6_ADDRSTRLEN];
|
||||||
|
inet_ntop(pw->af, &pw->nexthop, buf, sizeof(buf));
|
||||||
|
vty_out(vty, " neighbor %s\n", buf);
|
||||||
|
} else
|
||||||
|
vty_out(vty,
|
||||||
|
" ! Incomplete config, specify a neighbor "
|
||||||
|
"address\n");
|
||||||
|
|
||||||
|
if (!(pw->flags & F_PSEUDOWIRE_CWORD))
|
||||||
|
vty_out(vty, " control-word exclude\n");
|
||||||
|
|
||||||
|
vty_out(vty, "!\n");
|
||||||
|
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
75
zebra/zebra_pw.h
Normal 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_ */
|
@ -126,6 +126,7 @@ struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type)
|
|||||||
rnh->client_list = list_new();
|
rnh->client_list = list_new();
|
||||||
rnh->vrf_id = vrfid;
|
rnh->vrf_id = vrfid;
|
||||||
rnh->zebra_static_route_list = list_new();
|
rnh->zebra_static_route_list = list_new();
|
||||||
|
rnh->zebra_pseudowire_list = list_new();
|
||||||
route_lock_node(rn);
|
route_lock_node(rn);
|
||||||
rn->info = rnh;
|
rn->info = rnh;
|
||||||
rnh->node = rn;
|
rnh->node = rn;
|
||||||
@ -161,6 +162,7 @@ void zebra_free_rnh(struct rnh *rnh)
|
|||||||
rnh->flags |= ZEBRA_NHT_DELETED;
|
rnh->flags |= ZEBRA_NHT_DELETED;
|
||||||
list_free(rnh->client_list);
|
list_free(rnh->client_list);
|
||||||
list_free(rnh->zebra_static_route_list);
|
list_free(rnh->zebra_static_route_list);
|
||||||
|
list_free(rnh->zebra_pseudowire_list);
|
||||||
free_state(rnh->vrf_id, rnh->state, rnh->node);
|
free_state(rnh->vrf_id, rnh->state, rnh->node);
|
||||||
XFREE(MTYPE_RNH, rnh);
|
XFREE(MTYPE_RNH, rnh);
|
||||||
}
|
}
|
||||||
@ -210,7 +212,8 @@ void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client,
|
|||||||
}
|
}
|
||||||
listnode_delete(rnh->client_list, client);
|
listnode_delete(rnh->client_list, client);
|
||||||
if (list_isempty(rnh->client_list)
|
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);
|
zebra_delete_rnh(rnh, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,7 +240,8 @@ void zebra_deregister_rnh_static_nh(vrf_id_t vrf_id, struct prefix *nh,
|
|||||||
listnode_delete(rnh->zebra_static_route_list, static_rn);
|
listnode_delete(rnh->zebra_static_route_list, static_rn);
|
||||||
|
|
||||||
if (list_isempty(rnh->client_list)
|
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);
|
zebra_delete_rnh(rnh, RNH_NEXTHOP_TYPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,6 +288,58 @@ void zebra_deregister_rnh_static_nexthops(vrf_id_t vrf_id,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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)
|
/* Apply the NHT route-map for a client to the route (and nexthops)
|
||||||
* resolving a NH.
|
* resolving a NH.
|
||||||
*/
|
*/
|
||||||
@ -595,6 +651,15 @@ static void 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,
|
* See if a tracked nexthop entry has undergone any change, and if so,
|
||||||
* take appropriate action; this involves notifying any clients and/or
|
* take appropriate action; this involves notifying any clients and/or
|
||||||
@ -636,6 +701,9 @@ static void zebra_rnh_eval_nexthop_entry(vrf_id_t vrfid, int family, int force,
|
|||||||
/* Process static routes attached to this nexthop */
|
/* Process static routes attached to this nexthop */
|
||||||
zebra_rnh_process_static_routes(vrfid, family, nrn, rnh, prn,
|
zebra_rnh_process_static_routes(vrfid, family, nrn, rnh, prn,
|
||||||
rnh->state);
|
rnh->state);
|
||||||
|
|
||||||
|
/* Process pseudowires attached to this nexthop */
|
||||||
|
zebra_rnh_process_pseudowires(vrfid, rnh);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -694,8 +762,10 @@ static void zebra_rnh_clear_nhc_flag(vrf_id_t vrfid, int family,
|
|||||||
|
|
||||||
re = zebra_rnh_resolve_entry(vrfid, family, type, nrn, rnh, &prn);
|
re = zebra_rnh_resolve_entry(vrfid, family, type, nrn, rnh, &prn);
|
||||||
|
|
||||||
if (re)
|
if (re) {
|
||||||
UNSET_FLAG(re->status, ROUTE_ENTRY_NEXTHOPS_CHANGED);
|
UNSET_FLAG(re->status, ROUTE_ENTRY_NEXTHOPS_CHANGED);
|
||||||
|
UNSET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Evaluate all tracked entries (nexthops or routes for import into BGP)
|
/* Evaluate all tracked entries (nexthops or routes for import into BGP)
|
||||||
@ -840,7 +910,8 @@ static int compare_state(struct route_entry *r1, struct route_entry *r2)
|
|||||||
if (r1->nexthop_num != r2->nexthop_num)
|
if (r1->nexthop_num != r2->nexthop_num)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (CHECK_FLAG(r1->status, ROUTE_ENTRY_NEXTHOPS_CHANGED))
|
if (CHECK_FLAG(r1->status, ROUTE_ENTRY_NEXTHOPS_CHANGED)
|
||||||
|
|| CHECK_FLAG(r1->status, ROUTE_ENTRY_LABELS_CHANGED))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -1003,5 +1074,7 @@ static void print_rnh(struct route_node *rn, struct vty *vty)
|
|||||||
if (!list_isempty(rnh->zebra_static_route_list))
|
if (!list_isempty(rnh->zebra_static_route_list))
|
||||||
vty_out(vty, " zebra%s",
|
vty_out(vty, " zebra%s",
|
||||||
rnh->filtered[ZEBRA_ROUTE_STATIC] ? "(filtered)" : "");
|
rnh->filtered[ZEBRA_ROUTE_STATIC] ? "(filtered)" : "");
|
||||||
|
if (!list_isempty(rnh->zebra_pseudowire_list))
|
||||||
|
vty_out(vty, " zebra[pseudowires]");
|
||||||
vty_out(vty, "\n");
|
vty_out(vty, "\n");
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,8 @@ struct rnh {
|
|||||||
struct list *
|
struct list *
|
||||||
zebra_static_route_list; /* static routes dependent on this NH
|
zebra_static_route_list; /* static routes dependent on this NH
|
||||||
*/
|
*/
|
||||||
|
struct list
|
||||||
|
*zebra_pseudowire_list; /* pseudowires dependent on this NH */
|
||||||
struct route_node *node;
|
struct route_node *node;
|
||||||
int filtered[ZEBRA_ROUTE_MAX]; /* if this has been filtered for client
|
int filtered[ZEBRA_ROUTE_MAX]; /* if this has been filtered for client
|
||||||
*/
|
*/
|
||||||
@ -67,6 +69,8 @@ extern void zebra_deregister_rnh_static_nexthops(vrf_id_t,
|
|||||||
struct route_node *rn);
|
struct route_node *rn);
|
||||||
extern void zebra_deregister_rnh_static_nh(vrf_id_t, struct prefix *,
|
extern void zebra_deregister_rnh_static_nh(vrf_id_t, struct prefix *,
|
||||||
struct route_node *);
|
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,
|
extern void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client,
|
||||||
rnh_type_t type);
|
rnh_type_t type);
|
||||||
extern void zebra_evaluate_rnh(vrf_id_t vrfid, int family, int force,
|
extern void zebra_evaluate_rnh(vrf_id_t vrfid, int family, int force,
|
||||||
|
@ -203,6 +203,7 @@ static int zebra_vrf_delete(struct vrf *vrf)
|
|||||||
zebra_vxlan_close_tables(zvrf);
|
zebra_vxlan_close_tables(zvrf);
|
||||||
|
|
||||||
zebra_mpls_close_tables(zvrf);
|
zebra_mpls_close_tables(zvrf);
|
||||||
|
zebra_pw_exit(zvrf);
|
||||||
|
|
||||||
for (ALL_LIST_ELEMENTS_RO(vrf->iflist, node, ifp))
|
for (ALL_LIST_ELEMENTS_RO(vrf->iflist, node, ifp))
|
||||||
if_nbr_ipv6ll_to_ipv4ll_neigh_del_all(ifp);
|
if_nbr_ipv6ll_to_ipv4ll_neigh_del_all(ifp);
|
||||||
@ -372,6 +373,7 @@ struct zebra_vrf *zebra_vrf_alloc(void)
|
|||||||
|
|
||||||
zebra_vxlan_init_tables(zvrf);
|
zebra_vxlan_init_tables(zvrf);
|
||||||
zebra_mpls_init_tables(zvrf);
|
zebra_mpls_init_tables(zvrf);
|
||||||
|
zebra_pw_init(zvrf);
|
||||||
|
|
||||||
return zvrf;
|
return zvrf;
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#define __ZEBRA_RIB_H__
|
#define __ZEBRA_RIB_H__
|
||||||
|
|
||||||
#include <zebra/zebra_ns.h>
|
#include <zebra/zebra_ns.h>
|
||||||
|
#include <zebra/zebra_pw.h>
|
||||||
|
|
||||||
/* MPLS (Segment Routing) global block */
|
/* MPLS (Segment Routing) global block */
|
||||||
typedef struct mpls_srgb_t_ {
|
typedef struct mpls_srgb_t_ {
|
||||||
@ -89,6 +90,10 @@ struct zebra_vrf {
|
|||||||
/* MPLS Segment Routing Global block */
|
/* MPLS Segment Routing Global block */
|
||||||
mpls_srgb_t mpls_srgb;
|
mpls_srgb_t mpls_srgb;
|
||||||
|
|
||||||
|
/* Pseudowires. */
|
||||||
|
struct zebra_pw_head pseudowires;
|
||||||
|
struct zebra_static_pw_head static_pseudowires;
|
||||||
|
|
||||||
/* MPLS processing flags */
|
/* MPLS processing flags */
|
||||||
u_int16_t mpls_flags;
|
u_int16_t mpls_flags;
|
||||||
#define MPLS_FLAG_SCHEDULE_LSPS (1 << 0)
|
#define MPLS_FLAG_SCHEDULE_LSPS (1 << 0)
|
||||||
|
131
zebra/zserv.c
131
zebra/zserv.c
@ -1085,6 +1085,27 @@ int zsend_router_id_update(struct zserv *client, struct prefix *p,
|
|||||||
return zebra_server_send_message(client);
|
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
|
/* Register zebra server interface information. Send current all
|
||||||
interface and address information. */
|
interface and address information. */
|
||||||
static int zread_interface_add(struct zserv *client, u_short length,
|
static int zread_interface_add(struct zserv *client, u_short length,
|
||||||
@ -1877,14 +1898,12 @@ static void zread_mpls_labels(int command, struct zserv *client, u_short length,
|
|||||||
if (command == ZEBRA_MPLS_LABELS_ADD) {
|
if (command == ZEBRA_MPLS_LABELS_ADD) {
|
||||||
mpls_lsp_install(zvrf, type, in_label, out_label, gtype, &gate,
|
mpls_lsp_install(zvrf, type, in_label, out_label, gtype, &gate,
|
||||||
ifindex);
|
ifindex);
|
||||||
if (out_label != MPLS_IMP_NULL_LABEL)
|
mpls_ftn_update(1, zvrf, type, &prefix, gtype, &gate, ifindex,
|
||||||
mpls_ftn_update(1, zvrf, type, &prefix, gtype, &gate,
|
distance, out_label);
|
||||||
ifindex, distance, out_label);
|
|
||||||
} else if (command == ZEBRA_MPLS_LABELS_DELETE) {
|
} else if (command == ZEBRA_MPLS_LABELS_DELETE) {
|
||||||
mpls_lsp_uninstall(zvrf, type, in_label, gtype, &gate, ifindex);
|
mpls_lsp_uninstall(zvrf, type, in_label, gtype, &gate, ifindex);
|
||||||
if (out_label != MPLS_IMP_NULL_LABEL)
|
mpls_ftn_update(0, zvrf, type, &prefix, gtype, &gate, ifindex,
|
||||||
mpls_ftn_update(0, zvrf, type, &prefix, gtype, &gate,
|
distance, out_label);
|
||||||
ifindex, distance, out_label);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Send response to a label manager connect request to client */
|
/* Send response to a label manager connect request to client */
|
||||||
@ -2039,6 +2058,97 @@ static void zread_label_manager_request(int cmd, struct zserv *client,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int zread_pseudowire(int command, struct zserv *client, u_short length,
|
||||||
|
vrf_id_t vrf_id)
|
||||||
|
{
|
||||||
|
struct stream *s;
|
||||||
|
struct zebra_vrf *zvrf;
|
||||||
|
char ifname[IF_NAMESIZE];
|
||||||
|
ifindex_t ifindex;
|
||||||
|
int type;
|
||||||
|
int af;
|
||||||
|
union g_addr nexthop;
|
||||||
|
uint32_t local_label;
|
||||||
|
uint32_t remote_label;
|
||||||
|
uint8_t flags;
|
||||||
|
union pw_protocol_fields data;
|
||||||
|
uint8_t protocol;
|
||||||
|
struct zebra_pw *pw;
|
||||||
|
|
||||||
|
zvrf = vrf_info_lookup(vrf_id);
|
||||||
|
if (!zvrf)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Get input stream. */
|
||||||
|
s = client->ibuf;
|
||||||
|
|
||||||
|
/* Get data. */
|
||||||
|
stream_get(ifname, s, IF_NAMESIZE);
|
||||||
|
ifindex = stream_getl(s);
|
||||||
|
type = stream_getl(s);
|
||||||
|
af = stream_getl(s);
|
||||||
|
switch (af) {
|
||||||
|
case AF_INET:
|
||||||
|
nexthop.ipv4.s_addr = stream_get_ipv4(s);
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
stream_get(&nexthop.ipv6, s, 16);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
local_label = stream_getl(s);
|
||||||
|
remote_label = stream_getl(s);
|
||||||
|
flags = stream_getc(s);
|
||||||
|
stream_get(&data, s, sizeof(data));
|
||||||
|
protocol = client->proto;
|
||||||
|
|
||||||
|
pw = zebra_pw_find(zvrf, ifname);
|
||||||
|
switch (command) {
|
||||||
|
case ZEBRA_PW_ADD:
|
||||||
|
if (pw) {
|
||||||
|
zlog_warn("%s: pseudowire %s already exists [%s]",
|
||||||
|
__func__, ifname,
|
||||||
|
zserv_command_string(command));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
zebra_pw_add(zvrf, ifname, protocol, client);
|
||||||
|
break;
|
||||||
|
case ZEBRA_PW_DELETE:
|
||||||
|
if (!pw) {
|
||||||
|
zlog_warn("%s: pseudowire %s not found [%s]", __func__,
|
||||||
|
ifname, zserv_command_string(command));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
zebra_pw_del(zvrf, pw);
|
||||||
|
break;
|
||||||
|
case ZEBRA_PW_SET:
|
||||||
|
case ZEBRA_PW_UNSET:
|
||||||
|
if (!pw) {
|
||||||
|
zlog_warn("%s: pseudowire %s not found [%s]", __func__,
|
||||||
|
ifname, zserv_command_string(command));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (command) {
|
||||||
|
case ZEBRA_PW_SET:
|
||||||
|
pw->enabled = 1;
|
||||||
|
break;
|
||||||
|
case ZEBRA_PW_UNSET:
|
||||||
|
pw->enabled = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
zebra_pw_change(pw, ifindex, type, af, &nexthop, local_label,
|
||||||
|
remote_label, flags, &data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Cleanup registered nexthops (across VRFs) upon client disconnect. */
|
/* Cleanup registered nexthops (across VRFs) upon client disconnect. */
|
||||||
static void zebra_client_close_cleanup_rnh(struct zserv *client)
|
static void zebra_client_close_cleanup_rnh(struct zserv *client)
|
||||||
{
|
{
|
||||||
@ -2083,6 +2193,9 @@ static void zebra_client_close(struct zserv *client)
|
|||||||
zebra_mpls_cleanup_fecs_for_client(vrf_info_lookup(VRF_DEFAULT),
|
zebra_mpls_cleanup_fecs_for_client(vrf_info_lookup(VRF_DEFAULT),
|
||||||
client);
|
client);
|
||||||
|
|
||||||
|
/* Remove pseudowires associated with this client */
|
||||||
|
zebra_pw_client_close(client);
|
||||||
|
|
||||||
/* Close file descriptor. */
|
/* Close file descriptor. */
|
||||||
if (client->sock) {
|
if (client->sock) {
|
||||||
unsigned long nroutes;
|
unsigned long nroutes;
|
||||||
@ -2436,6 +2549,12 @@ static int zebra_client_read(struct thread *thread)
|
|||||||
case ZEBRA_INTERFACE_SET_MASTER:
|
case ZEBRA_INTERFACE_SET_MASTER:
|
||||||
zread_interface_set_master(client, sock, length);
|
zread_interface_set_master(client, sock, length);
|
||||||
break;
|
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:
|
default:
|
||||||
zlog_info("Zebra received unknown command %d", command);
|
zlog_info("Zebra received unknown command %d", command);
|
||||||
break;
|
break;
|
||||||
|
@ -30,6 +30,8 @@
|
|||||||
#include "zclient.h"
|
#include "zclient.h"
|
||||||
|
|
||||||
#include "zebra/zebra_ns.h"
|
#include "zebra/zebra_ns.h"
|
||||||
|
#include "zebra/zebra_pw.h"
|
||||||
|
|
||||||
/* Default port information. */
|
/* Default port information. */
|
||||||
#define ZEBRA_VTY_PORT 2601
|
#define ZEBRA_VTY_PORT 2601
|
||||||
|
|
||||||
@ -175,6 +177,7 @@ extern int zsend_interface_vrf_update(struct zserv *, struct interface *,
|
|||||||
vrf_id_t);
|
vrf_id_t);
|
||||||
|
|
||||||
extern int zsend_interface_link_params(struct zserv *, struct interface *);
|
extern int zsend_interface_link_params(struct zserv *, struct interface *);
|
||||||
|
extern int zsend_pw_update(struct zserv *, struct zebra_pw *);
|
||||||
|
|
||||||
extern pid_t pid;
|
extern pid_t pid;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user