summaryrefslogtreecommitdiffstats
path: root/ldpd/ldp_zebra.c
diff options
context:
space:
mode:
Diffstat (limited to 'ldpd/ldp_zebra.c')
-rw-r--r--ldpd/ldp_zebra.c466
1 files changed, 466 insertions, 0 deletions
diff --git a/ldpd/ldp_zebra.c b/ldpd/ldp_zebra.c
new file mode 100644
index 000000000..41ff47fba
--- /dev/null
+++ b/ldpd/ldp_zebra.c
@@ -0,0 +1,466 @@
+/*
+ * Copyright (C) 2016 by Open Source Routing.
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra 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, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "prefix.h"
+#include "stream.h"
+#include "memory.h"
+#include "zclient.h"
+#include "command.h"
+#include "network.h"
+#include "linklist.h"
+
+#include "ldpd.h"
+#include "ldpe.h"
+#include "lde.h"
+#include "log.h"
+#include "ldp_debug.h"
+
+static void ifp2kif(struct interface *, struct kif *);
+static void ifc2kaddr(struct interface *, struct connected *,
+ struct kaddr *);
+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,
+ vrf_id_t);
+static int ldp_interface_delete(int, struct zclient *, zebra_size_t,
+ vrf_id_t);
+static int ldp_interface_status_change(int command, struct zclient *,
+ zebra_size_t, vrf_id_t);
+static int ldp_interface_address_add(int, struct zclient *, zebra_size_t,
+ vrf_id_t);
+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 void ldp_zebra_connected(struct zclient *);
+
+static struct zclient *zclient;
+
+static void
+ifp2kif(struct interface *ifp, struct kif *kif)
+{
+ memset(kif, 0, sizeof(*kif));
+ strlcpy(kif->ifname, ifp->name, sizeof(kif->ifname));
+ kif->ifindex = ifp->ifindex;
+ kif->flags = ifp->flags;
+}
+
+static void
+ifc2kaddr(struct interface *ifp, struct connected *ifc, struct kaddr *ka)
+{
+ memset(ka, 0, sizeof(*ka));
+ ka->ifindex = ifp->ifindex;
+ ka->af = ifc->address->family;
+ ka->prefixlen = ifc->address->prefixlen;
+
+ switch (ka->af) {
+ case AF_INET:
+ ka->addr.v4 = ifc->address->u.prefix4;
+ if (ifc->destination)
+ ka->dstbrd.v4 = ifc->destination->u.prefix4;
+ break;
+ case AF_INET6:
+ ka->addr.v6 = ifc->address->u.prefix6;
+ if (ifc->destination)
+ ka->dstbrd.v6 = ifc->destination->u.prefix6;
+ break;
+ default:
+ break;
+ }
+}
+
+int
+kr_change(struct kroute *kr)
+{
+ /* TODO */
+ return (0);
+}
+
+int
+kr_delete(struct kroute *kr)
+{
+ /* TODO */
+ return (0);
+}
+
+int
+kmpw_set(struct kpw *kpw)
+{
+ /* TODO */
+ return (0);
+}
+
+int
+kmpw_unset(struct kpw *kpw)
+{
+ /* TODO */
+ return (0);
+}
+
+void
+kif_redistribute(const char *ifname)
+{
+ struct listnode *node, *cnode;
+ struct interface *ifp;
+ struct connected *ifc;
+ struct kif kif;
+ struct kaddr ka;
+
+ for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) {
+ if (ifname && strcmp(ifname, ifp->name) != 0)
+ continue;
+
+ ifp2kif(ifp, &kif);
+ main_imsg_compose_ldpe(IMSG_IFSTATUS, 0, &kif, sizeof(kif));
+
+ for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, ifc)) {
+ ifc2kaddr(ifp, ifc, &ka);
+ main_imsg_compose_ldpe(IMSG_NEWADDR, 0, &ka,
+ sizeof(ka));
+ }
+ }
+}
+
+static int
+ldp_router_id_update(int command, struct zclient *zclient, zebra_size_t length,
+ vrf_id_t vrf_id)
+{
+ struct prefix router_id;
+
+ zebra_router_id_update_read(zclient->ibuf, &router_id);
+
+ if (bad_addr_v4(router_id.u.prefix4))
+ return (0);
+
+ debug_zebra_in("router-id update %s", inet_ntoa(router_id.u.prefix4));
+
+ global.rtr_id.s_addr = router_id.u.prefix4.s_addr;
+ main_imsg_compose_ldpe(IMSG_RTRID_UPDATE, 0, &global.rtr_id,
+ sizeof(global.rtr_id));
+
+ return (0);
+}
+
+static int
+ldp_interface_add(int command, struct zclient *zclient, zebra_size_t length,
+ vrf_id_t vrf_id)
+{
+ struct interface *ifp;
+ struct kif kif;
+
+ ifp = zebra_interface_add_read(zclient->ibuf, vrf_id);
+ debug_zebra_in("interface add %s index %d mtu %d", ifp->name,
+ ifp->ifindex, ifp->mtu);
+
+ ifp2kif(ifp, &kif);
+ main_imsg_compose_ldpe(IMSG_IFSTATUS, 0, &kif, sizeof(kif));
+
+ return (0);
+}
+
+static int
+ldp_interface_delete(int command, struct zclient *zclient, zebra_size_t length,
+ vrf_id_t vrf_id)
+{
+ struct interface *ifp;
+
+ /* zebra_interface_state_read() updates interface structure in iflist */
+ ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
+ if (ifp == NULL)
+ return (0);
+
+ debug_zebra_in("interface delete %s index %d mtu %d", ifp->name,
+ ifp->ifindex, ifp->mtu);
+
+ /* To support pseudo interface do not free interface structure. */
+ /* if_delete(ifp); */
+ ifp->ifindex = IFINDEX_INTERNAL;
+
+ return (0);
+}
+
+static int
+ldp_interface_status_change(int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ struct interface *ifp;
+ struct listnode *node;
+ struct connected *ifc;
+ struct kif kif;
+ struct kaddr ka;
+ int link_new;
+
+ /*
+ * zebra_interface_state_read() updates interface structure in
+ * iflist.
+ */
+ ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
+ if (ifp == NULL)
+ return (0);
+
+ debug_zebra_in("interface %s state update", ifp->name);
+
+ ifp2kif(ifp, &kif);
+ main_imsg_compose_ldpe(IMSG_IFSTATUS, 0, &kif, sizeof(kif));
+
+ link_new = (ifp->flags & IFF_UP) && (ifp->flags & IFF_RUNNING);
+ if (link_new) {
+ for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
+ ifc2kaddr(ifp, ifc, &ka);
+ main_imsg_compose_ldpe(IMSG_NEWADDR, 0, &ka,
+ sizeof(ka));
+ }
+ } else {
+ for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
+ ifc2kaddr(ifp, ifc, &ka);
+ main_imsg_compose_ldpe(IMSG_DELADDR, 0, &ka,
+ sizeof(ka));
+ }
+ }
+
+ return (0);
+}
+
+static int
+ldp_interface_address_add(int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ struct connected *ifc;
+ struct interface *ifp;
+ struct kaddr ka;
+
+ ifc = zebra_interface_address_read(command, zclient->ibuf, vrf_id);
+ if (ifc == NULL)
+ return (0);
+
+ ifp = ifc->ifp;
+ ifc2kaddr(ifp, ifc, &ka);
+
+ /* Filter invalid addresses. */
+ if (bad_addr(ka.af, &ka.addr))
+ return (0);
+
+ debug_zebra_in("address add %s/%u", log_addr(ka.af, &ka.addr),
+ ka.prefixlen);
+
+ /* notify ldpe about new address */
+ main_imsg_compose_ldpe(IMSG_NEWADDR, 0, &ka, sizeof(ka));
+
+ return (0);
+}
+
+static int
+ldp_interface_address_delete(int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ struct connected *ifc;
+ struct interface *ifp;
+ struct kaddr ka;
+
+ ifc = zebra_interface_address_read(command, zclient->ibuf, vrf_id);
+ if (ifc == NULL)
+ return (0);
+
+ ifp = ifc->ifp;
+ ifc2kaddr(ifp, ifc, &ka);
+ connected_free(ifc);
+
+ /* Filter invalid addresses. */
+ if (bad_addr(ka.af, &ka.addr))
+ return (0);
+
+ debug_zebra_in("address delete %s/%u", log_addr(ka.af, &ka.addr),
+ ka.prefixlen);
+
+ /* notify ldpe about removed address */
+ main_imsg_compose_ldpe(IMSG_DELADDR, 0, &ka, sizeof(ka));
+
+ return (0);
+}
+
+static int
+ldp_zebra_read_route(int command, struct zclient *zclient, zebra_size_t length,
+ vrf_id_t vrf_id)
+{
+ struct stream *s;
+ u_char type;
+ u_char message_flags;
+ struct kroute kr;
+ int nhnum, nhlen;
+ size_t nhmark;
+
+ memset(&kr, 0, sizeof(kr));
+ s = zclient->ibuf;
+
+ type = stream_getc(s);
+ if (type == ZEBRA_ROUTE_CONNECT)
+ kr.flags |= F_CONNECTED;
+ stream_getc(s); /* flags, unused */
+ stream_getw(s); /* instance, unused */
+ message_flags = stream_getc(s);
+ if (!CHECK_FLAG(message_flags, ZAPI_MESSAGE_NEXTHOP))
+ return (0);
+
+ switch (command) {
+ case ZEBRA_IPV4_ROUTE_ADD:
+ case ZEBRA_REDISTRIBUTE_IPV4_ADD:
+ case ZEBRA_IPV4_ROUTE_DELETE:
+ case ZEBRA_REDISTRIBUTE_IPV4_DEL:
+ kr.af = AF_INET;
+ nhlen = sizeof(struct in_addr);
+ break;
+ case ZEBRA_IPV6_ROUTE_ADD:
+ case ZEBRA_REDISTRIBUTE_IPV6_ADD:
+ case ZEBRA_IPV6_ROUTE_DELETE:
+ case ZEBRA_REDISTRIBUTE_IPV6_DEL:
+ kr.af = AF_INET6;
+ nhlen = sizeof(struct in6_addr);
+ break;
+ default:
+ fatalx("ldp_zebra_read_route: unknown command");
+ }
+ kr.prefixlen = stream_getc(s);
+ stream_get(&kr.prefix, s, PSIZE(kr.prefixlen));
+
+ if (bad_addr(kr.af, &kr.prefix) ||
+ (kr.af == AF_INET6 && IN6_IS_SCOPE_EMBED(&kr.prefix.v6)))
+ return (0);
+
+ nhnum = stream_getc(s);
+ nhmark = stream_get_getp(s);
+ stream_set_getp(s, nhmark + nhnum * (nhlen + 5));
+
+ if (CHECK_FLAG(message_flags, ZAPI_MESSAGE_DISTANCE))
+ kr.priority = stream_getc(s);
+ if (CHECK_FLAG(message_flags, ZAPI_MESSAGE_METRIC))
+ stream_getl(s); /* metric, not used */
+
+ stream_set_getp(s, nhmark);
+
+ /* loop through all the nexthops */
+ for (; nhnum > 0; nhnum--) {
+ switch (kr.af) {
+ case AF_INET:
+ kr.nexthop.v4.s_addr = stream_get_ipv4(s);
+ break;
+ case AF_INET6:
+ stream_get(&kr.nexthop.v6, s, sizeof(kr.nexthop.v6));
+ break;
+ default:
+ break;
+ }
+ stream_getc(s); /* ifindex_num, unused. */
+ kr.ifindex = stream_getl(s);
+
+ switch (command) {
+ case ZEBRA_IPV4_ROUTE_ADD:
+ case ZEBRA_REDISTRIBUTE_IPV4_ADD:
+ case ZEBRA_IPV6_ROUTE_ADD:
+ case ZEBRA_REDISTRIBUTE_IPV6_ADD:
+ debug_zebra_in("route add %s/%d nexthop %s (%s)",
+ log_addr(kr.af, &kr.prefix), kr.prefixlen,
+ log_addr(kr.af, &kr.nexthop),
+ zebra_route_string(type));
+ main_imsg_compose_lde(IMSG_NETWORK_ADD, 0, &kr,
+ sizeof(kr));
+ break;
+ case ZEBRA_IPV4_ROUTE_DELETE:
+ case ZEBRA_REDISTRIBUTE_IPV4_DEL:
+ case ZEBRA_IPV6_ROUTE_DELETE:
+ case ZEBRA_REDISTRIBUTE_IPV6_DEL:
+ debug_zebra_in("route delete %s/%d nexthop %s (%s)",
+ log_addr(kr.af, &kr.prefix), kr.prefixlen,
+ log_addr(kr.af, &kr.nexthop),
+ zebra_route_string(type));
+ main_imsg_compose_lde(IMSG_NETWORK_DEL, 0, &kr,
+ sizeof(kr));
+ break;
+ default:
+ fatalx("ldp_zebra_read_route: unknown command");
+ }
+ }
+
+ return (0);
+}
+
+static void
+ldp_zebra_connected(struct zclient *zclient)
+{
+ int i;
+
+ zclient_send_reg_requests(zclient, VRF_DEFAULT);
+
+ for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
+ switch (i) {
+ case ZEBRA_ROUTE_KERNEL:
+ case ZEBRA_ROUTE_CONNECT:
+ case ZEBRA_ROUTE_STATIC:
+ case ZEBRA_ROUTE_ISIS:
+ zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient,
+ AFI_IP, i, 0, VRF_DEFAULT);
+ zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient,
+ AFI_IP6, i, 0, VRF_DEFAULT);
+ break;
+ case ZEBRA_ROUTE_RIP:
+ case ZEBRA_ROUTE_OSPF:
+ zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient,
+ AFI_IP, i, 0, VRF_DEFAULT);
+ break;
+ case ZEBRA_ROUTE_RIPNG:
+ case ZEBRA_ROUTE_OSPF6:
+ zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient,
+ AFI_IP6, i, 0, VRF_DEFAULT);
+ break;
+ case ZEBRA_ROUTE_BGP:
+ /* LDP should follow the IGP and ignore BGP routes */
+ default:
+ break;
+ }
+ }
+}
+
+void
+ldp_zebra_init(struct thread_master *master)
+{
+ /* Set default values. */
+ zclient = zclient_new(master);
+ zclient_init(zclient, ZEBRA_ROUTE_LDP, 0);
+
+ /* set callbacks */
+ zclient->zebra_connected = ldp_zebra_connected;
+ zclient->router_id_update = ldp_router_id_update;
+ zclient->interface_add = ldp_interface_add;
+ zclient->interface_delete = ldp_interface_delete;
+ zclient->interface_up = ldp_interface_status_change;
+ zclient->interface_down = ldp_interface_status_change;
+ zclient->interface_address_add = ldp_interface_address_add;
+ zclient->interface_address_delete = ldp_interface_address_delete;
+ zclient->ipv4_route_add = ldp_zebra_read_route;
+ zclient->ipv4_route_delete = ldp_zebra_read_route;
+ zclient->redistribute_route_ipv4_add = ldp_zebra_read_route;
+ zclient->redistribute_route_ipv4_del = ldp_zebra_read_route;
+ zclient->ipv6_route_add = ldp_zebra_read_route;
+ zclient->ipv6_route_delete = ldp_zebra_read_route;
+ zclient->redistribute_route_ipv6_add = ldp_zebra_read_route;
+ zclient->redistribute_route_ipv6_del = ldp_zebra_read_route;
+}