Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Pseudowire management in Zebra #710

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions ldpd/l2vpn.c
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,30 @@ l2vpn_recv_pw_status_wcard(struct lde_nbr *ln, struct notify_msg *nm)
}
}

int
l2vpn_pw_status_update(struct kpw *kpw)
{
struct l2vpn *l2vpn;
struct l2vpn_pw *pw;

RB_FOREACH(l2vpn, l2vpn_head, &ldeconf->l2vpn_tree) {
pw = l2vpn_pw_find(l2vpn, kpw->ifname);
if (pw)
break;
}
if (!pw) {
log_warnx("%s: pseudowire %s not found", __func__, kpw->ifname);
return (1);
}

if (kpw->flags & F_PW_STATUS_UP)
pw->flags |= F_PW_STATUS_UP;
else
pw->flags &= ~F_PW_STATUS_UP;

return (0);
}

void
l2vpn_pw_ctl(pid_t pid)
{
Expand Down
23 changes: 19 additions & 4 deletions ldpd/lde.c
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,7 @@ lde_dispatch_parent(struct thread *thread)
struct imsg imsg;
struct kif *kif;
struct kroute *kr;
struct kpw *kpw;
int fd = THREAD_FD(thread);
struct imsgev *iev = THREAD_ARG(thread);
struct imsgbuf *ibuf = &iev->ibuf;
Expand Down Expand Up @@ -491,6 +492,16 @@ lde_dispatch_parent(struct thread *thread)
}
}
break;
case IMSG_PW_UPDATE:
if (imsg.hdr.len != IMSG_HEADER_SIZE +
sizeof(struct kpw))
fatalx("PW_UPDATE imsg with wrong len");
kpw = imsg.data;

if (l2vpn_pw_status_update(kpw) != 0)
log_warnx("%s: error updating PW status",
__func__);
break;
case IMSG_NETWORK_ADD:
case IMSG_NETWORK_UPDATE:
if (imsg.hdr.len != IMSG_HEADER_SIZE +
Expand Down Expand Up @@ -769,16 +780,19 @@ lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh)
return;

pw = (struct l2vpn_pw *) fn->data;
pw->flags |= F_PW_STATUS_UP;

memset(&kpw, 0, sizeof(kpw));
strlcpy(kpw.ifname, pw->ifname, sizeof(kpw.ifname));
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;
kpw.lsr_id = pw->lsr_id;
kpw.pwid = pw->pwid;
strlcpy(kpw.vpn_name, pw->l2vpn->name, sizeof(kpw.vpn_name));

lde_imsg_compose_parent(IMSG_KPWLABEL_CHANGE, 0, &kpw,
sizeof(kpw));
Expand Down Expand Up @@ -824,18 +838,19 @@ lde_send_delete_klabel(struct fec_node *fn, struct fec_nh *fnh)
break;
case FEC_TYPE_PWID:
pw = (struct l2vpn_pw *) fn->data;
if (!(pw->flags & F_PW_STATUS_UP))
return;
pw->flags &= ~F_PW_STATUS_UP;

memset(&kpw, 0, sizeof(kpw));
strlcpy(kpw.ifname, pw->ifname, sizeof(kpw.ifname));
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;
kpw.lsr_id = pw->lsr_id;
kpw.pwid = pw->pwid;
strlcpy(kpw.vpn_name, pw->l2vpn->name, sizeof(kpw.vpn_name));

lde_imsg_compose_parent(IMSG_KPWLABEL_DELETE, 0, &kpw,
sizeof(kpw));
Expand Down
1 change: 1 addition & 0 deletions ldpd/lde.h
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ void l2vpn_send_pw_status_wcard(struct lde_nbr *, uint32_t,
void l2vpn_recv_pw_status(struct lde_nbr *, struct notify_msg *);
void l2vpn_recv_pw_status_wcard(struct lde_nbr *,
struct notify_msg *);
int l2vpn_pw_status_update(struct kpw *);
void l2vpn_pw_ctl(pid_t);
void l2vpn_binding_ctl(pid_t);

Expand Down
110 changes: 106 additions & 4 deletions ldpd/ldp_zebra.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ static void ifp2kif(struct interface *, struct kif *);
static void ifc2kaddr(struct interface *, struct connected *,
struct kaddr *);
static int zebra_send_mpls_labels(int, struct kroute *);
static int zebra_send_kpw(int, struct kpw *);
static int ldp_router_id_update(int, struct zclient *, zebra_size_t,
vrf_id_t);
static int ldp_interface_add(int, struct zclient *, zebra_size_t,
Expand All @@ -54,6 +55,8 @@ static int ldp_interface_address_delete(int, struct zclient *,
zebra_size_t, vrf_id_t);
static int ldp_zebra_read_route(int, struct zclient *, zebra_size_t,
vrf_id_t);
static int ldp_zebra_read_pw_status_update(int, struct zclient *,
zebra_size_t, vrf_id_t);
static void ldp_zebra_connected(struct zclient *);

static struct zclient *zclient;
Expand Down Expand Up @@ -153,18 +156,84 @@ kr_delete(struct kroute *kr)
return (zebra_send_mpls_labels(ZEBRA_MPLS_LABELS_DELETE, kr));
}

static int
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this function Belong in zclient.c to allow other, future, routing protocols to take advantage of it? Should it be under zapi_route as well? Instead of a specialized function?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. I'll submit another commit in a while.

zebra_send_kpw(int cmd, struct kpw *kpw)
{
struct stream *s;
int type;
uint8_t flags = 0;
union pw_protocol_fields data;

debug_zebra_out("pseudowire %s ifindex %u nexthop %s labels %s/%s (%s)",
kpw->ifname, kpw->ifindex, log_addr(kpw->af, &kpw->nexthop),
log_label(kpw->local_label), log_label(kpw->remote_label),
(cmd == ZEBRA_PW_ADD) ? "add" : "delete");

/* Reset stream. */
s = zclient->obuf;
stream_reset(s);

zclient_create_header(s, cmd, VRF_DEFAULT);
stream_write(s, kpw->ifname, IF_NAMESIZE);
stream_putl(s, kpw->ifindex);

/* Put type */
switch (kpw->pw_type) {
case PW_TYPE_ETHERNET:
type = PSEUDOWIRE_TYPE_ETH;
break;
case PW_TYPE_ETHERNET_TAGGED:
type = PSEUDOWIRE_TYPE_ETH_TAGGED;
break;
default:
fatalx("zebra_send_kpw: unknown pseudowire type");
}
stream_putl(s, type);

/* Put nexthop */
stream_putl(s, kpw->af);
switch (kpw->af) {
case AF_INET:
stream_put_in_addr(s, &kpw->nexthop.v4);
break;
case AF_INET6:
stream_write(s, (u_char *)&kpw->nexthop.v6, 16);
break;
default:
fatalx("zebra_send_kpw: unknown af");
}

/* Put labels */
stream_putl(s, kpw->local_label);
stream_putl(s, kpw->remote_label);

/* Put flags */
if (kpw->flags & F_PW_CWORD)
flags |= F_PSEUDOWIRE_CWORD;
stream_putc(s, flags);

/* Protocol specific fields */
data.ldp.lsr_id = kpw->lsr_id;
data.ldp.pwid = kpw->pwid;
strlcpy(data.ldp.vpn_name, kpw->vpn_name, sizeof(data.ldp.vpn_name));
stream_write(s, &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));
}

int
kmpw_set(struct kpw *kpw)
{
/* TODO */
return (0);
return (zebra_send_kpw (ZEBRA_PW_ADD, kpw));
}

int
kmpw_unset(struct kpw *kpw)
{
/* TODO */
return (0);
return (zebra_send_kpw (ZEBRA_PW_DELETE, kpw));
}

void
Expand Down Expand Up @@ -466,6 +535,38 @@ ldp_zebra_read_route(int command, struct zclient *zclient, zebra_size_t length,
return (0);
}

/*
* Receive PW status update from Zebra and send it to LDE process.
*/
static int
ldp_zebra_read_pw_status_update(int command, struct zclient *zclient,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, should this function of decoding the data be in zclient.c?

zebra_size_t length, vrf_id_t vrf_id)
{
struct stream *s;
uint8_t status;
struct kpw kpw;

memset(&kpw, 0, sizeof(struct kpw));
s = zclient->ibuf;

/* Get data. */
stream_get(kpw.ifname, s, IF_NAMESIZE);
kpw.ifindex = stream_getl(s);

status = stream_getc(s);
if (status == PSEUDOWIRE_STATUS_UP)
kpw.flags |= F_PW_STATUS_UP;
else
kpw.flags &= ~F_PW_STATUS_UP;

debug_zebra_in("pseudowire %s ifindex %u status %s", kpw.ifname,
kpw.ifindex, (kpw.flags & F_PW_STATUS_UP) ? "up" : "down");

main_imsg_compose_lde(IMSG_PW_UPDATE, 0, &kpw, sizeof(kpw));

return (0);
}

static void
ldp_zebra_connected(struct zclient *zclient)
{
Expand Down Expand Up @@ -496,6 +597,7 @@ ldp_zebra_init(struct thread_master *master)
zclient->redistribute_route_ipv4_del = ldp_zebra_read_route;
zclient->redistribute_route_ipv6_add = ldp_zebra_read_route;
zclient->redistribute_route_ipv6_del = ldp_zebra_read_route;
zclient->pw_status_update = ldp_zebra_read_pw_status_update;
}

void
Expand Down
9 changes: 7 additions & 2 deletions ldpd/ldpd.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "qobj.h"
#include "prefix.h"
#include "filter.h"
#include "mpls.h"

#include "ldp.h"

Expand All @@ -43,7 +44,6 @@
#define LDPD_OPT_NOACTION 0x00000004

#define TCP_MD5_KEY_LEN 80
#define L2VPN_NAME_LEN 32

#define RT_BUF_SIZE 16384
#define MAX_RTSOCK_BUF 128 * 1024
Expand Down Expand Up @@ -148,7 +148,8 @@ enum imsg_type {
IMSG_ACL_CHECK,
IMSG_GET_LABEL_CHUNK,
IMSG_RELEASE_LABEL_CHUNK,
IMSG_INIT
IMSG_INIT,
IMSG_PW_UPDATE
};

struct ldpd_init {
Expand Down Expand Up @@ -545,13 +546,17 @@ struct kroute {
};

struct kpw {
char ifname[IF_NAMESIZE];
unsigned short ifindex;
int pw_type;
int af;
union ldpd_addr nexthop;
uint32_t local_label;
uint32_t remote_label;
uint8_t flags;
struct in_addr lsr_id;
uint32_t pwid;
char vpn_name[L2VPN_NAME_LEN];
};

struct kaddr {
Expand Down
3 changes: 3 additions & 0 deletions lib/log.c
Original file line number Diff line number Diff line change
Expand Up @@ -967,6 +967,9 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY (ZEBRA_LABEL_MANAGER_CONNECT),
DESC_ENTRY (ZEBRA_GET_LABEL_CHUNK),
DESC_ENTRY (ZEBRA_RELEASE_LABEL_CHUNK),
DESC_ENTRY (ZEBRA_PW_ADD),
DESC_ENTRY (ZEBRA_PW_DELETE),
DESC_ENTRY (ZEBRA_PW_STATUS_UPDATE),
};
#undef DESC_ENTRY

Expand Down
16 changes: 16 additions & 0 deletions lib/mpls.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,22 @@ enum lsp_types_t
ZEBRA_LSP_LDP = 2 /* LDP LSP. */
};

/* pseudowire types */
enum pw_types_t
{
PSEUDOWIRE_TYPE_ETH,
PSEUDOWIRE_TYPE_ETH_TAGGED
};

/* pseudowire flags */
#define F_PSEUDOWIRE_CWORD 0x01

/* pseudowire status */
#define PSEUDOWIRE_STATUS_DOWN 0
#define PSEUDOWIRE_STATUS_UP 1

#define L2VPN_NAME_LEN 32

/* Functions for basic label operations. */

/* Encode a label stack entry from fields; convert to network byte-order as
Expand Down
4 changes: 4 additions & 0 deletions lib/zclient.c
Original file line number Diff line number Diff line change
Expand Up @@ -1899,6 +1899,10 @@ zclient_read (struct thread *thread)
if (zclient->interface_link_params)
(*zclient->interface_link_params) (command, zclient, length);
break;
case ZEBRA_PW_STATUS_UPDATE:
if (zclient->pw_status_update)
(*zclient->pw_status_update) (command, zclient, length, vrf_id);
break;
default:
break;
}
Expand Down
16 changes: 16 additions & 0 deletions lib/zclient.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
/* For vrf_bitmap_t. */
#include "vrf.h"

/* For L2VPN_NAME_LEN */
#include "mpls.h"

/* For input/output buffer to zebra. */
#define ZEBRA_MAX_PACKET_SIZ 4096

Expand Down Expand Up @@ -94,6 +97,9 @@ typedef enum {
ZEBRA_LABEL_MANAGER_CONNECT,
ZEBRA_GET_LABEL_CHUNK,
ZEBRA_RELEASE_LABEL_CHUNK,
ZEBRA_PW_ADD,
ZEBRA_PW_DELETE,
ZEBRA_PW_STATUS_UPDATE,
} zebra_message_types_t;

struct redist_proto
Expand Down Expand Up @@ -164,6 +170,7 @@ struct zclient
int (*redistribute_route_ipv4_del) (int, struct zclient *, uint16_t, vrf_id_t);
int (*redistribute_route_ipv6_add) (int, struct zclient *, uint16_t, vrf_id_t);
int (*redistribute_route_ipv6_del) (int, struct zclient *, uint16_t, vrf_id_t);
int (*pw_status_update) (int, struct zclient *, uint16_t, vrf_id_t);
};

/* Zebra API message flag. */
Expand Down Expand Up @@ -217,6 +224,15 @@ struct zapi_ipv4
vrf_id_t vrf_id;
};

union pw_protocol_fields {
struct {
struct in_addr lsr_id;
uint32_t pwid;
char vpn_name[L2VPN_NAME_LEN];
} ldp;
/* TODO: BGP */
};

/* Prototypes of zebra client service functions. */
extern struct zclient *zclient_new (struct thread_master *);
extern void zclient_init (struct zclient *, int, u_short);
Expand Down
Loading