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

pimd: eBGP integration for SA loop detection #17699

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
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
17 changes: 16 additions & 1 deletion doc/user/pim.rst
Original file line number Diff line number Diff line change
Expand Up @@ -546,10 +546,25 @@ Commands available for MSDP
Create or update a mesh group to set the source address used to connect to
peers.

.. clicmd:: msdp peer A.B.C.D source A.B.C.D
.. clicmd:: msdp peer A.B.C.D source A.B.C.D [as AS_NUMBER]

Create a regular MSDP session with peer using the specified source address.

Optionally the Autonomous Number (AS) can be provided for eBGP assisted
loop detection (see RFC 4611 Section 2.1. Peering between PIM Border
Routers).

.. note::

The BGP configuration must be enabled in order for this feature to work:

::

bgp send-extra-data zebra

This knob causes BGP to send the AS Path information to ``zebra`` so
MSDP can use that information.

.. clicmd:: msdp peer A.B.C.D sa-filter ACL_NAME <in|out>

Configure incoming or outgoing SA filtering rule.
Expand Down
3 changes: 2 additions & 1 deletion lib/log.c
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,8 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY(ZEBRA_TC_FILTER_ADD),
DESC_ENTRY(ZEBRA_TC_FILTER_DELETE),
DESC_ENTRY(ZEBRA_OPAQUE_NOTIFY),
DESC_ENTRY(ZEBRA_SRV6_SID_NOTIFY)
DESC_ENTRY(ZEBRA_SRV6_SID_NOTIFY),
DESC_ENTRY(ZEBRA_ROUTE_LOOKUP),
};
#undef DESC_ENTRY

Expand Down
161 changes: 161 additions & 0 deletions lib/zclient.c
Original file line number Diff line number Diff line change
Expand Up @@ -5131,3 +5131,164 @@ void zclient_register_neigh(struct zclient *zclient, vrf_id_t vrf_id, afi_t afi,
stream_putw_at(s, 0, stream_get_endp(s));
zclient_send_message(zclient);
}

static struct zroute_nh_info *zapi_route_nh_decode(struct stream *s)
{
struct zroute_nh_info *rni = XCALLOC(MTYPE_TMP, sizeof(*rni));

STREAM_GETL(s, rni->rni_vrf_id);
STREAM_GETC(s, rni->rni_type);

switch (rni->rni_type) {
case NEXTHOP_TYPE_IPV4:
case NEXTHOP_TYPE_IPV4_IFINDEX:
STREAM_GET(&rni->rni_addr, s, sizeof(struct in_addr));
STREAM_GETL(s, rni->rni_ifindex);
break;
case NEXTHOP_TYPE_IPV6:
STREAM_GET(&rni->rni_addr, s, sizeof(struct in6_addr));
break;
case NEXTHOP_TYPE_IPV6_IFINDEX:
STREAM_GET(&rni->rni_addr, s, sizeof(struct in6_addr));
STREAM_GETL(s, rni->rni_ifindex);
break;
case NEXTHOP_TYPE_IFINDEX:
STREAM_GETL(s, rni->rni_ifindex);
break;
}

return rni;

stream_failure:
zlog_warn("%s: failed to parse next hop", __func__);
XFREE(MTYPE_TMP, rni);
return NULL;
}

struct zroute_info *zapi_route_lookup(struct zclient *zc, vrf_id_t vrf_id, int family,
const void *addr)
{
struct zroute_info *ri;
struct zroute_nh_info *rni;
struct stream *s;
int err;
size_t addr_size;
uint32_t idx;
uint16_t length;
uint16_t command;
uint8_t marker;
uint8_t version;
struct ipaddr ip;
union {
struct in_addr ia;
struct in6_addr i6a;
} const *address = addr;

/* Initial checks and logging. */
switch (family) {
case AF_INET:
/* `0.0.0.0` is unroutable. */
if (address->ia.s_addr == INADDR_NONE)
return NULL;

addr_size = sizeof(struct in_addr);
break;

default:
zlog_warn("%s: unsupported address family %d", __func__, family);
return NULL;
}

/* Get output stream and reset it. */
s = zc->obuf;
stream_reset(s);

/* Create and send lookup request. */
zclient_create_header(s, ZEBRA_ROUTE_LOOKUP, vrf_id);
stream_putl(s, family);
stream_put(s, addr, addr_size);
stream_putw_at(s, 0, stream_get_endp(s));
err = writen(zc->sock, s->data, stream_get_endp(s));
if (err < 0) {
flog_err(EC_LIB_SOCKET, "%s: writen() failure: %d writing to zclient lookup socket",
__func__, errno);
return NULL;
}
if (err == 0) {
flog_err_sys(EC_LIB_SOCKET, "%s: connection closed on zclient lookup socket",
__func__);
return NULL;
}

/* Read and handle unwanted messages. */
s = zc->ibuf;
do {
stream_reset(s);
err = zclient_read_header(s, zc->sock, &length, &marker, &version, &vrf_id,
&command);
if (err != 0) {
flog_err(EC_LIB_ZAPI_MISSMATCH, "%s: zclient_read_header() failed",
__func__);
return NULL;
}
} while (command != ZEBRA_ROUTE_LOOKUP);

/* Read the response. */
STREAM_GETC(s, err);

/* No route found case. */
if (err == 0)
return NULL;

ri = XCALLOC(MTYPE_TMP, sizeof(*ri));
stream_get_ipaddr(s, &ip);
ri->ri_p.family = ip.ipa_type;
switch (ri->ri_p.family) {
case AF_INET:
ri->ri_p.u.prefix4 = ip.ip._v4_addr;
break;
case AF_INET6:
ri->ri_p.u.prefix6 = ip.ip._v6_addr;
break;
default:
XFREE(MTYPE_TMP, ri);
zlog_warn("%s: invalid IP type %d", __func__, ri->ri_p.family);
return NULL;
}
STREAM_GETW(s, ri->ri_p.prefixlen);
STREAM_GETL(s, ri->ri_distance);
STREAM_GETL(s, ri->ri_metric);
STREAM_GETL(s, ri->ri_type);
STREAM_GETL(s, ri->ri_nexthop_num);

for (idx = 0; idx < ri->ri_nexthop_num; idx++) {
rni = zapi_route_nh_decode(s);
SLIST_INSERT_HEAD(&ri->ri_nhlist, rni, rni_entry);
}

STREAM_GETL(s, ri->ri_opaque_size);
STREAM_GET(ri->ri_opaque, s, ri->ri_opaque_size);

return ri;

stream_failure:
zlog_warn("%s: invalid message format", __func__);
return NULL;
}

void zroute_info_free(struct zroute_info **ri)
{
struct zroute_nh_info *rni;

/* Handle `NULL` pointers */
if (*ri == NULL)
return;

/* Free all allocated next hop information. */
while ((rni = SLIST_FIRST(&(*ri)->ri_nhlist)) != NULL) {
SLIST_REMOVE(&(*ri)->ri_nhlist, rni, zroute_nh_info, rni_entry);
XFREE(MTYPE_TMP, rni);
}

XFREE(MTYPE_TMP, (*ri));
}
70 changes: 70 additions & 0 deletions lib/zclient.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ struct zclient;
#include "srte.h"
#include "srv6.h"

#include "openbsd-queue.h"

#ifdef __cplusplus
extern "C" {
#endif
Expand Down Expand Up @@ -238,6 +240,7 @@ typedef enum {
ZEBRA_TC_FILTER_DELETE,
ZEBRA_OPAQUE_NOTIFY,
ZEBRA_SRV6_SID_NOTIFY,
ZEBRA_ROUTE_LOOKUP,
} zebra_message_types_t;
/* Zebra message types. Please update the corresponding
* command_types array with any changes!
Expand Down Expand Up @@ -1375,6 +1378,73 @@ extern int zapi_client_close_notify_decode(struct stream *s,

extern int zclient_send_zebra_gre_request(struct zclient *client,
struct interface *ifp);

/*
* Route lookup zebra API.
*/

/**
* Zebra route next hop information.
*/
struct zroute_nh_info {
/** Next hop pointer to next. */
SLIST_ENTRY(zroute_nh_info) rni_entry;

/** Next hop VRF. */
vrf_id_t rni_vrf_id;
/** Next hop type (see `enum nexthop_types_t`). */
uint8_t rni_type;
/** Next hop address. */
union {
struct in_addr v4;
struct in6_addr v6;
} rni_addr;
/** Next hop interface index. */
ifindex_t rni_ifindex;
};

/**
* Zebra route information.
*/
struct zroute_info {
/** Route prefix. */
struct prefix ri_p;
/** Route distance */
int ri_distance;
/** Route metric */
int ri_metric;
/** Route type. */
int ri_type;
/** Amount of next hops. */
uint32_t ri_nexthop_num;

/** List of next hops. */
SLIST_HEAD(, zroute_nh_info) ri_nhlist;

/** Opaque data size. */
uint32_t ri_opaque_size;
/** Protocol specific opaque information. */
uint8_t ri_opaque[ZAPI_MESSAGE_OPAQUE_LENGTH];
};

/**
* Request zebra to lookup a route for us matching those specifications.
*
* \param zc Zebra client context pointer.
* \param vrf_id the VRF identification.
* \param family Address type (e.g. `AF_INET`).
* \param addr Address (usually `struct in_addr *`).
* \returns a pointer to the result allocated in the heap. Memory should
* be returned using `zroute_info_free()`.
*/
struct zroute_info *zapi_route_lookup(struct zclient *zc, vrf_id_t vrf_id, int family,
const void *addr);

/**
* Unallocates all memory allocated by `zapi_route_lookup`.
*/
void zroute_info_free(struct zroute_info **ri);

#ifdef __cplusplus
}
#endif
Expand Down
Loading
Loading