diff options
author | Donald Sharp <sharpd@cumulusnetworks.com> | 2017-08-08 13:54:32 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-08-08 13:54:32 +0200 |
commit | f66e92bc4856352dc4c1c81fa35b1dd570cd83e5 (patch) | |
tree | d95a4b505cc238c09ea4d2512f2ad6af92f5cb9c /ldpd | |
parent | Merge pull request #907 from opensourcerouting/vty-close-3.0 (diff) | |
parent | zebra: add support for static pseudowires (diff) | |
download | frr-f66e92bc4856352dc4c1c81fa35b1dd570cd83e5.tar.xz frr-f66e92bc4856352dc4c1c81fa35b1dd570cd83e5.zip |
Merge pull request #783 from opensourcerouting/pw-manager-2
Add Pseudowire management in Zebra
Diffstat (limited to 'ldpd')
-rw-r--r-- | ldpd/l2vpn.c | 65 | ||||
-rw-r--r-- | ldpd/lde.c | 60 | ||||
-rw-r--r-- | ldpd/lde.h | 1 | ||||
-rw-r--r-- | ldpd/lde_lib.c | 9 | ||||
-rw-r--r-- | ldpd/ldp.h | 3 | ||||
-rw-r--r-- | ldpd/ldp_zebra.c | 76 | ||||
-rw-r--r-- | ldpd/ldpd.c | 41 | ||||
-rw-r--r-- | ldpd/ldpd.h | 33 |
8 files changed, 211 insertions, 77 deletions
diff --git a/ldpd/l2vpn.c b/ldpd/l2vpn.c index 27948f5a1..afb9528d8 100644 --- a/ldpd/l2vpn.c +++ b/ldpd/l2vpn.c @@ -234,6 +234,7 @@ void l2vpn_pw_init(struct l2vpn_pw *pw) { struct fec fec; + struct zapi_pw zpw; l2vpn_pw_reset(pw); @@ -241,16 +242,23 @@ l2vpn_pw_init(struct l2vpn_pw *pw) lde_kernel_insert(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0, 0, 0, (void *)pw); lde_kernel_update(&fec); + + pw2zpw(pw, &zpw); + lde_imsg_compose_parent(IMSG_KPW_ADD, 0, &zpw, sizeof(zpw)); } void l2vpn_pw_exit(struct l2vpn_pw *pw) { struct fec fec; + struct zapi_pw zpw; l2vpn_pw_fec(pw, &fec); lde_kernel_remove(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0, 0); lde_kernel_update(&fec); + + pw2zpw(pw, &zpw); + lde_imsg_compose_parent(IMSG_KPW_DELETE, 0, &zpw, sizeof(zpw)); } static void @@ -268,7 +276,8 @@ l2vpn_pw_reset(struct l2vpn_pw *pw) { pw->remote_group = 0; pw->remote_mtu = 0; - pw->remote_status = 0; + pw->local_status = PW_FORWARDING; + pw->remote_status = PW_NOT_FORWARDING; if (pw->flags & F_PW_CWORD_CONF) pw->flags |= F_PW_CWORD; @@ -474,6 +483,56 @@ l2vpn_recv_pw_status_wcard(struct lde_nbr *ln, struct notify_msg *nm) } } +int +l2vpn_pw_status_update(struct zapi_pw_status *zpw) +{ + struct l2vpn *l2vpn; + struct l2vpn_pw *pw = NULL; + struct lde_nbr *ln; + struct fec fec; + uint32_t local_status; + + RB_FOREACH(l2vpn, l2vpn_head, &ldeconf->l2vpn_tree) { + pw = l2vpn_pw_find(l2vpn, zpw->ifname); + if (pw) + break; + } + if (!pw) { + log_warnx("%s: pseudowire %s not found", __func__, zpw->ifname); + return (1); + } + + if (zpw->status == PW_STATUS_UP) + local_status = PW_FORWARDING; + else + local_status = PW_NOT_FORWARDING; + + /* local status didn't change */ + if (pw->local_status == local_status) + return (0); + pw->local_status = local_status; + + /* notify remote peer about the status update */ + ln = lde_nbr_find_by_lsrid(pw->lsr_id); + if (ln == NULL) + return (0); + l2vpn_pw_fec(pw, &fec); + if (pw->flags & F_PW_STATUSTLV) + l2vpn_send_pw_status(ln, local_status, &fec); + else { + struct fec_node *fn; + fn = (struct fec_node *)fec_find(&ft, &fec); + if (fn) { + if (pw->local_status == PW_FORWARDING) + lde_send_labelmapping(ln, fn, 1); + else + lde_send_labelwithdraw(ln, fn, NULL, NULL); + } + } + + return (0); +} + void l2vpn_pw_ctl(pid_t pid) { @@ -490,7 +549,9 @@ l2vpn_pw_ctl(pid_t pid) sizeof(pwctl.ifname)); pwctl.pwid = pw->pwid; pwctl.lsr_id = pw->lsr_id; - pwctl.status = pw->flags & F_PW_STATUS_UP; + if (pw->local_status == PW_FORWARDING && + pw->remote_status == PW_FORWARDING) + pwctl.status = 1; lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_PW, 0, pid, &pwctl, sizeof(pwctl)); diff --git a/ldpd/lde.c b/ldpd/lde.c index 7540fc1cb..37d64eaf5 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -491,6 +491,15 @@ lde_dispatch_parent(struct thread *thread) } } break; + case IMSG_PW_UPDATE: + if (imsg.hdr.len != IMSG_HEADER_SIZE + + sizeof(struct zapi_pw_status)) + fatalx("PW_UPDATE imsg with wrong len"); + + if (l2vpn_pw_status_update(imsg.data) != 0) + log_warnx("%s: error updating PW status", + __func__); + break; case IMSG_NETWORK_ADD: case IMSG_NETWORK_UPDATE: if (imsg.hdr.len != IMSG_HEADER_SIZE + @@ -730,8 +739,8 @@ lde_update_label(struct fec_node *fn) void lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh) { - struct kroute kr; - struct kpw kpw; + struct kroute kr; + struct zapi_pw zpw; struct l2vpn_pw *pw; switch (fn->fec.type) { @@ -769,19 +778,10 @@ lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh) return; pw = (struct l2vpn_pw *) fn->data; - pw->flags |= F_PW_STATUS_UP; - - memset(&kpw, 0, sizeof(kpw)); - kpw.ifindex = pw->ifindex; - kpw.pw_type = fn->fec.u.pwid.type; - kpw.af = pw->af; - kpw.nexthop = pw->addr; - kpw.local_label = fn->local_label; - kpw.remote_label = fnh->remote_label; - kpw.flags = pw->flags; - - lde_imsg_compose_parent(IMSG_KPWLABEL_CHANGE, 0, &kpw, - sizeof(kpw)); + pw2zpw(pw, &zpw); + zpw.local_label = fn->local_label; + zpw.remote_label = fnh->remote_label; + lde_imsg_compose_parent(IMSG_KPW_SET, 0, &zpw, sizeof(zpw)); break; } } @@ -790,7 +790,7 @@ void lde_send_delete_klabel(struct fec_node *fn, struct fec_nh *fnh) { struct kroute kr; - struct kpw kpw; + struct zapi_pw zpw; struct l2vpn_pw *pw; switch (fn->fec.type) { @@ -824,21 +824,10 @@ lde_send_delete_klabel(struct fec_node *fn, struct fec_nh *fnh) break; case FEC_TYPE_PWID: pw = (struct l2vpn_pw *) fn->data; - if (!(pw->flags & F_PW_STATUS_UP)) - return; - pw->flags &= ~F_PW_STATUS_UP; - - memset(&kpw, 0, sizeof(kpw)); - kpw.ifindex = pw->ifindex; - kpw.pw_type = fn->fec.u.pwid.type; - kpw.af = pw->af; - kpw.nexthop = pw->addr; - kpw.local_label = fn->local_label; - kpw.remote_label = fnh->remote_label; - kpw.flags = pw->flags; - - lde_imsg_compose_parent(IMSG_KPWLABEL_DELETE, 0, &kpw, - sizeof(kpw)); + pw2zpw(pw, &zpw); + zpw.local_label = fn->local_label; + zpw.remote_label = fnh->remote_label; + lde_imsg_compose_parent(IMSG_KPW_UNSET, 0, &zpw, sizeof(zpw)); break; } } @@ -919,8 +908,12 @@ lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single) */ lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec); if (lw) { - if (!fec_find(&ln->sent_map_pending, &fn->fec)) + if (!fec_find(&ln->sent_map_pending, &fn->fec)) { + debug_evt("%s: FEC %s: scheduling to send label " + "mapping later (waiting for pending label release)", + __func__, log_fec(&fn->fec)); lde_map_pending_add(ln, fn); + } return; } @@ -966,8 +959,7 @@ lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single) map.flags |= F_MAP_PW_CWORD; if (pw->flags & F_PW_STATUSTLV) { map.flags |= F_MAP_PW_STATUS; - /* VPLS are always up */ - map.pw_status = PW_FORWARDING; + map.pw_status = pw->local_status; } break; } diff --git a/ldpd/lde.h b/ldpd/lde.h index 1cce48383..43f1d3648 100644 --- a/ldpd/lde.h +++ b/ldpd/lde.h @@ -238,6 +238,7 @@ void l2vpn_send_pw_status_wcard(struct lde_nbr *, uint32_t, void l2vpn_recv_pw_status(struct lde_nbr *, struct notify_msg *); void l2vpn_recv_pw_status_wcard(struct lde_nbr *, struct notify_msg *); +int l2vpn_pw_status_update(struct zapi_pw_status *); void l2vpn_pw_ctl(pid_t); void l2vpn_binding_ctl(pid_t); diff --git a/ldpd/lde_lib.c b/ldpd/lde_lib.c index 37a670bc8..c24a57b56 100644 --- a/ldpd/lde_lib.c +++ b/ldpd/lde_lib.c @@ -396,7 +396,7 @@ lde_kernel_update(struct fec *fec) lde_gc_start_timer(); } else { fn->local_label = lde_update_label(fn); - if (fn->local_label != NO_LABEL && RB_EMPTY(&fn->upstream)) + if (fn->local_label != NO_LABEL) /* FEC.1: perform lsr label distribution procedure */ RB_FOREACH(ln, nbr_tree, &lde_nbrs) lde_send_labelmapping(ln, fn, 1); @@ -531,6 +531,8 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln) pw->remote_mtu = map->fec.pwid.ifmtu; if (map->flags & F_MAP_PW_STATUS) pw->remote_status = map->pw_status; + else + pw->remote_status = PW_FORWARDING; fnh->remote_label = map->label; if (l2vpn_pw_ok(pw, fnh)) lde_send_change_klabel(fn, fnh); @@ -780,6 +782,7 @@ lde_check_withdraw(struct map *map, struct lde_nbr *ln) pw = (struct l2vpn_pw *) fn->data; if (pw == NULL) continue; + pw->remote_status = PW_NOT_FORWARDING; break; default: break; @@ -808,6 +811,7 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln) struct fec_node *fn; struct fec_nh *fnh; struct lde_map *me; + struct l2vpn_pw *pw; /* LWd.2: send label release */ lde_send_labelrelease(ln, NULL, map, map->label); @@ -831,6 +835,9 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln) case FEC_TYPE_PWID: if (f->u.pwid.lsr_id.s_addr != ln->id.s_addr) continue; + pw = (struct l2vpn_pw *) fn->data; + if (pw) + pw->remote_status = PW_NOT_FORWARDING; break; default: break; diff --git a/ldpd/ldp.h b/ldpd/ldp.h index c2b64d20c..cac3da7c5 100644 --- a/ldpd/ldp.h +++ b/ldpd/ldp.h @@ -285,9 +285,6 @@ struct address_list_tlv { #define MAP_TYPE_GENPWID 0x81 #define CONTROL_WORD_FLAG 0x8000 -#define PW_TYPE_ETHERNET_TAGGED 0x0004 -#define PW_TYPE_ETHERNET 0x0005 -#define PW_TYPE_WILDCARD 0x7FFF #define DEFAULT_PW_TYPE PW_TYPE_ETHERNET #define PW_TWCARD_RESERVED_BIT 0x8000 diff --git a/ldpd/ldp_zebra.c b/ldpd/ldp_zebra.c index 3320238a0..f7d715e81 100644 --- a/ldpd/ldp_zebra.c +++ b/ldpd/ldp_zebra.c @@ -54,6 +54,8 @@ static int ldp_interface_address_delete(int, struct zclient *, zebra_size_t, vrf_id_t); static int ldp_zebra_read_route(int, struct zclient *, zebra_size_t, vrf_id_t); +static int ldp_zebra_read_pw_status_update(int, struct zclient *, + zebra_size_t, vrf_id_t); static void ldp_zebra_connected(struct zclient *); static struct zclient *zclient; @@ -94,6 +96,25 @@ ifc2kaddr(struct interface *ifp, struct connected *ifc, struct kaddr *ka) } } +void +pw2zpw(struct l2vpn_pw *pw, struct zapi_pw *zpw) +{ + memset(zpw, 0, sizeof(*zpw)); + strlcpy(zpw->ifname, pw->ifname, sizeof(zpw->ifname)); + zpw->ifindex = pw->ifindex; + zpw->type = pw->l2vpn->pw_type; + zpw->af = pw->af; + zpw->nexthop.ipv6 = pw->addr.v6; + zpw->local_label = NO_LABEL; + zpw->remote_label = NO_LABEL; + if (pw->flags & F_PW_CWORD) + zpw->flags = F_PSEUDOWIRE_CWORD; + zpw->data.ldp.lsr_id = pw->lsr_id; + zpw->data.ldp.pwid = pw->pwid; + strlcpy(zpw->data.ldp.vpn_name, pw->l2vpn->name, + sizeof(zpw->data.ldp.vpn_name)); +} + static int zebra_send_mpls_labels(int cmd, struct kroute *kr) { @@ -154,17 +175,40 @@ kr_delete(struct kroute *kr) } int -kmpw_set(struct kpw *kpw) +kmpw_add(struct zapi_pw *zpw) { - /* TODO */ - return (0); + debug_zebra_out("pseudowire %s nexthop %s (add)", + zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop)); + + return (zebra_send_pw(zclient, ZEBRA_PW_ADD, zpw)); } int -kmpw_unset(struct kpw *kpw) +kmpw_del(struct zapi_pw *zpw) { - /* TODO */ - return (0); + debug_zebra_out("pseudowire %s nexthop %s (del)", + zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop)); + + return (zebra_send_pw(zclient, ZEBRA_PW_DELETE, zpw)); +} + +int +kmpw_set(struct zapi_pw *zpw) +{ + debug_zebra_out("pseudowire %s nexthop %s labels %u/%u (set)", + zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop), + zpw->local_label, zpw->remote_label); + + return (zebra_send_pw(zclient, ZEBRA_PW_SET, zpw)); +} + +int +kmpw_unset(struct zapi_pw *zpw) +{ + debug_zebra_out("pseudowire %s nexthop %s (unset)", + zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop)); + + return (zebra_send_pw(zclient, ZEBRA_PW_UNSET, zpw)); } void @@ -466,6 +510,25 @@ ldp_zebra_read_route(int command, struct zclient *zclient, zebra_size_t length, return (0); } +/* + * Receive PW status update from Zebra and send it to LDE process. + */ +static int +ldp_zebra_read_pw_status_update(int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) +{ + struct zapi_pw_status zpw; + + zebra_read_pw_status_update(command, zclient, length, vrf_id, &zpw); + + debug_zebra_in("pseudowire %s status %s", zpw.ifname, + (zpw.status == PW_STATUS_UP) ? "up" : "down"); + + main_imsg_compose_lde(IMSG_PW_UPDATE, 0, &zpw, sizeof(zpw)); + + return (0); +} + static void ldp_zebra_connected(struct zclient *zclient) { @@ -496,6 +559,7 @@ ldp_zebra_init(struct thread_master *master) zclient->redistribute_route_ipv4_del = ldp_zebra_read_route; zclient->redistribute_route_ipv6_add = ldp_zebra_read_route; zclient->redistribute_route_ipv6_del = ldp_zebra_read_route; + zclient->pw_status_update = ldp_zebra_read_pw_status_update; } void diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c index f9e44012e..303baf463 100644 --- a/ldpd/ldpd.c +++ b/ldpd/ldpd.c @@ -591,21 +591,36 @@ main_dispatch_lde(struct thread *thread) if (kr_delete(imsg.data)) log_warnx("%s: error deleting route", __func__); break; - case IMSG_KPWLABEL_CHANGE: + case IMSG_KPW_ADD: + case IMSG_KPW_DELETE: + case IMSG_KPW_SET: + case IMSG_KPW_UNSET: if (imsg.hdr.len - IMSG_HEADER_SIZE != - sizeof(struct kpw)) + sizeof(struct zapi_pw)) fatalx("invalid size of IMSG_KPWLABEL_CHANGE"); - if (kmpw_set(imsg.data)) - log_warnx("%s: error changing pseudowire", - __func__); - break; - case IMSG_KPWLABEL_DELETE: - if (imsg.hdr.len - IMSG_HEADER_SIZE != - sizeof(struct kpw)) - fatalx("invalid size of IMSG_KPWLABEL_DELETE"); - if (kmpw_unset(imsg.data)) - log_warnx("%s: error unsetting pseudowire", - __func__); + + switch (imsg.hdr.type) { + case IMSG_KPW_ADD: + if (kmpw_add(imsg.data)) + log_warnx("%s: error adding " + "pseudowire", __func__); + break; + case IMSG_KPW_DELETE: + if (kmpw_del(imsg.data)) + log_warnx("%s: error deleting " + "pseudowire", __func__); + break; + case IMSG_KPW_SET: + if (kmpw_set(imsg.data)) + log_warnx("%s: error setting " + "pseudowire", __func__); + break; + case IMSG_KPW_UNSET: + if (kmpw_unset(imsg.data)) + log_warnx("%s: error unsetting " + "pseudowire", __func__); + break; + } break; case IMSG_ACL_CHECK: if (imsg.hdr.len != IMSG_HEADER_SIZE + diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h index 97239ed08..fd7d5c572 100644 --- a/ldpd/ldpd.h +++ b/ldpd/ldpd.h @@ -29,6 +29,8 @@ #include "qobj.h" #include "prefix.h" #include "filter.h" +#include "pw.h" +#include "zclient.h" #include "ldp.h" @@ -43,7 +45,6 @@ #define LDPD_OPT_NOACTION 0x00000004 #define TCP_MD5_KEY_LEN 80 -#define L2VPN_NAME_LEN 32 #define RT_BUF_SIZE 16384 #define MAX_RTSOCK_BUF 128 * 1024 @@ -101,8 +102,10 @@ enum imsg_type { IMSG_CTL_LOG_VERBOSE, IMSG_KLABEL_CHANGE, IMSG_KLABEL_DELETE, - IMSG_KPWLABEL_CHANGE, - IMSG_KPWLABEL_DELETE, + IMSG_KPW_ADD, + IMSG_KPW_DELETE, + IMSG_KPW_SET, + IMSG_KPW_UNSET, IMSG_IFSTATUS, IMSG_NEWADDR, IMSG_DELADDR, @@ -148,7 +151,8 @@ enum imsg_type { IMSG_ACL_CHECK, IMSG_GET_LABEL_CHUNK, IMSG_RELEASE_LABEL_CHUNK, - IMSG_INIT + IMSG_INIT, + IMSG_PW_UPDATE }; struct ldpd_init { @@ -408,6 +412,7 @@ struct l2vpn_pw { unsigned int ifindex; uint32_t remote_group; uint16_t remote_mtu; + uint32_t local_status; uint32_t remote_status; uint8_t flags; QOBJ_FIELDS @@ -419,8 +424,7 @@ DECLARE_QOBJ_TYPE(l2vpn_pw) #define F_PW_STATUSTLV 0x02 /* status tlv negotiated */ #define F_PW_CWORD_CONF 0x04 /* control word configured */ #define F_PW_CWORD 0x08 /* control word negotiated */ -#define F_PW_STATUS_UP 0x10 /* pseudowire is operational */ -#define F_PW_STATIC_NBR_ADDR 0x20 /* static neighbor address configured */ +#define F_PW_STATIC_NBR_ADDR 0x10 /* static neighbor address configured */ struct l2vpn { RB_ENTRY(l2vpn) entry; @@ -544,16 +548,6 @@ struct kroute { uint16_t flags; }; -struct kpw { - unsigned short ifindex; - int pw_type; - int af; - union ldpd_addr nexthop; - uint32_t local_label; - uint32_t remote_label; - uint8_t flags; -}; - struct kaddr { char ifname[IF_NAMESIZE]; unsigned short ifindex; @@ -670,11 +664,14 @@ struct ldpd_conf *parse_config(char *); int cmdline_symset(char *); /* kroute.c */ +void pw2zpw(struct l2vpn_pw *, struct zapi_pw *); void kif_redistribute(const char *); int kr_change(struct kroute *); int kr_delete(struct kroute *); -int kmpw_set(struct kpw *); -int kmpw_unset(struct kpw *); +int kmpw_add(struct zapi_pw *); +int kmpw_del(struct zapi_pw *); +int kmpw_set(struct zapi_pw *); +int kmpw_unset(struct zapi_pw *); /* util.c */ uint8_t mask2prefixlen(in_addr_t); |