summaryrefslogtreecommitdiff
path: root/bgpd/bgp_zebra.c
diff options
context:
space:
mode:
Diffstat (limited to 'bgpd/bgp_zebra.c')
-rw-r--r--bgpd/bgp_zebra.c475
1 files changed, 475 insertions, 0 deletions
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 581b4e6f5b..93a509c219 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -56,6 +56,7 @@
#include "bgpd/bgp_evpn.h"
#include "bgpd/bgp_mplsvpn.h"
#include "bgpd/bgp_labelpool.h"
+#include "bgpd/bgp_pbr.h"
/* All information about zebra. */
struct zclient *zclient = NULL;
@@ -997,6 +998,9 @@ static int bgp_table_map_apply(struct route_map *map, struct prefix *p,
static struct thread *bgp_tm_thread_connect;
static bool bgp_tm_status_connected;
+static bool bgp_tm_chunk_obtained;
+#define BGP_FLOWSPEC_TABLE_CHUNK 100000
+static uint32_t bgp_tm_min, bgp_tm_max, bgp_tm_chunk_size;
static int bgp_zebra_tm_connect(struct thread *t)
{
@@ -1017,12 +1021,27 @@ static int bgp_zebra_tm_connect(struct thread *t)
if (!bgp_tm_status_connected)
zlog_debug("Connecting to table manager. Success");
bgp_tm_status_connected = true;
+ if (!bgp_tm_chunk_obtained) {
+ if (bgp_zebra_get_table_range(bgp_tm_chunk_size,
+ &bgp_tm_min,
+ &bgp_tm_max) >= 0)
+ bgp_tm_chunk_obtained = true;
+ }
}
thread_add_timer(bm->master, bgp_zebra_tm_connect, zclient, delay,
&bgp_tm_thread_connect);
return 0;
}
+uint32_t bgp_zebra_tm_get_id(void)
+{
+ static int table_id;
+
+ if (!bgp_tm_chunk_obtained)
+ return ++table_id;
+ return bgp_tm_min++;
+}
+
void bgp_zebra_init_tm_connect(void)
{
int delay = 1;
@@ -1032,6 +1051,9 @@ void bgp_zebra_init_tm_connect(void)
if (bgp_tm_thread_connect != NULL)
return;
bgp_tm_status_connected = false;
+ bgp_tm_chunk_obtained = false;
+ bgp_tm_min = bgp_tm_max = 0;
+ bgp_tm_chunk_size = BGP_FLOWSPEC_TABLE_CHUNK;
thread_add_timer(bm->master, bgp_zebra_tm_connect, zclient, delay,
&bgp_tm_thread_connect);
}
@@ -1173,6 +1195,10 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
if (bgp_debug_zebra(p))
prefix2str(&api.prefix, buf_prefix, sizeof(buf_prefix));
+ if (safi == SAFI_FLOWSPEC)
+ return bgp_pbr_update_entry(bgp, &rn->p,
+ info, afi, safi, true);
+
/*
* vrf leaking support (will have only one nexthop)
*/
@@ -1459,6 +1485,7 @@ void bgp_zebra_withdraw(struct prefix *p, struct bgp_info *info,
struct bgp *bgp, safi_t safi)
{
struct zapi_route api;
+ struct peer *peer;
/* Don't try to install if we're not connected to Zebra or Zebra doesn't
* know of this instance.
@@ -1466,6 +1493,12 @@ void bgp_zebra_withdraw(struct prefix *p, struct bgp_info *info,
if (!bgp_install_info_to_zebra(bgp))
return;
+ if (safi == SAFI_FLOWSPEC) {
+ peer = info->peer;
+ return bgp_pbr_update_entry(peer->bgp, p,
+ info, AFI_IP, safi, false);
+ }
+
memset(&api, 0, sizeof(api));
memcpy(&api.rmac, &(info->attr->rmac), sizeof(struct ethaddr));
api.vrf_id = bgp->vrf_id;
@@ -1908,6 +1941,271 @@ int bgp_zebra_advertise_all_vni(struct bgp *bgp, int advertise)
return zclient_send_message(zclient);
}
+static int rule_notify_owner(int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ uint32_t seqno, priority, unique;
+ enum zapi_rule_notify_owner note;
+ struct bgp_pbr_action *bgp_pbra;
+ ifindex_t ifi;
+
+ if (!zapi_rule_notify_decode(zclient->ibuf, &seqno, &priority, &unique,
+ &ifi, &note))
+ return -1;
+
+ bgp_pbra = bgp_pbr_action_rule_lookup(vrf_id, unique);
+ if (!bgp_pbra) {
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("%s: Fail to look BGP rule (%u)",
+ __PRETTY_FUNCTION__, unique);
+ return 0;
+ }
+
+ switch (note) {
+ case ZAPI_RULE_FAIL_INSTALL:
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("%s: Received RULE_FAIL_INSTALL",
+ __PRETTY_FUNCTION__);
+ bgp_pbra->installed = false;
+ bgp_pbra->install_in_progress = false;
+ break;
+ case ZAPI_RULE_INSTALLED:
+ bgp_pbra->installed = true;
+ bgp_pbra->install_in_progress = false;
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("%s: Received RULE_INSTALLED",
+ __PRETTY_FUNCTION__);
+ break;
+ case ZAPI_RULE_REMOVED:
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("%s: Received RULE REMOVED",
+ __PRETTY_FUNCTION__);
+ break;
+ }
+
+ return 0;
+}
+
+static int ipset_notify_owner(int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ uint32_t unique;
+ enum zapi_ipset_notify_owner note;
+ struct bgp_pbr_match *bgp_pbim;
+
+ if (!zapi_ipset_notify_decode(zclient->ibuf,
+ &unique,
+ &note))
+ return -1;
+
+ bgp_pbim = bgp_pbr_match_ipset_lookup(vrf_id, unique);
+ if (!bgp_pbim) {
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("%s: Fail to look BGP match (%u)",
+ __PRETTY_FUNCTION__, unique);
+ return 0;
+ }
+
+ switch (note) {
+ case ZAPI_IPSET_FAIL_INSTALL:
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("%s: Received IPSET_FAIL_INSTALL",
+ __PRETTY_FUNCTION__);
+ bgp_pbim->installed = false;
+ bgp_pbim->install_in_progress = false;
+ break;
+ case ZAPI_IPSET_INSTALLED:
+ bgp_pbim->installed = true;
+ bgp_pbim->install_in_progress = false;
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("%s: Received IPSET_INSTALLED",
+ __PRETTY_FUNCTION__);
+ break;
+ case ZAPI_IPSET_REMOVED:
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("%s: Received IPSET REMOVED",
+ __PRETTY_FUNCTION__);
+ break;
+ }
+
+ return 0;
+}
+
+static int ipset_entry_notify_owner(int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ uint32_t unique;
+ char ipset_name[ZEBRA_IPSET_NAME_SIZE];
+ enum zapi_ipset_entry_notify_owner note;
+ struct bgp_pbr_match_entry *bgp_pbime;
+
+ if (!zapi_ipset_entry_notify_decode(
+ zclient->ibuf,
+ &unique,
+ ipset_name,
+ &note))
+ return -1;
+ bgp_pbime = bgp_pbr_match_ipset_entry_lookup(vrf_id,
+ ipset_name,
+ unique);
+ if (!bgp_pbime) {
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("%s: Fail to look BGP match entry (%u)",
+ __PRETTY_FUNCTION__, unique);
+ return 0;
+ }
+
+ switch (note) {
+ case ZAPI_IPSET_ENTRY_FAIL_INSTALL:
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("%s: Received IPSET_ENTRY_FAIL_INSTALL",
+ __PRETTY_FUNCTION__);
+ bgp_pbime->installed = false;
+ bgp_pbime->install_in_progress = false;
+ break;
+ case ZAPI_IPSET_ENTRY_INSTALLED:
+ bgp_pbime->installed = true;
+ bgp_pbime->install_in_progress = false;
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("%s: Received IPSET_ENTRY_INSTALLED",
+ __PRETTY_FUNCTION__);
+ break;
+ case ZAPI_IPSET_ENTRY_REMOVED:
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("%s: Received IPSET_ENTRY_REMOVED",
+ __PRETTY_FUNCTION__);
+ break;
+ }
+ return 0;
+}
+
+static int iptable_notify_owner(int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ uint32_t unique;
+ enum zapi_iptable_notify_owner note;
+ struct bgp_pbr_match *bgpm;
+
+ if (!zapi_iptable_notify_decode(
+ zclient->ibuf,
+ &unique,
+ &note))
+ return -1;
+ bgpm = bgp_pbr_match_iptable_lookup(vrf_id, unique);
+ if (!bgpm) {
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("%s: Fail to look BGP iptable (%u)",
+ __PRETTY_FUNCTION__, unique);
+ return 0;
+ }
+ switch (note) {
+ case ZAPI_IPTABLE_FAIL_INSTALL:
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("%s: Received IPTABLE_FAIL_INSTALL",
+ __PRETTY_FUNCTION__);
+ bgpm->installed_in_iptable = false;
+ bgpm->install_iptable_in_progress = false;
+ break;
+ case ZAPI_IPTABLE_INSTALLED:
+ bgpm->installed_in_iptable = true;
+ bgpm->install_iptable_in_progress = false;
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("%s: Received IPTABLE_INSTALLED",
+ __PRETTY_FUNCTION__);
+ bgpm->action->refcnt++;
+ break;
+ case ZAPI_IPTABLE_REMOVED:
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("%s: Received IPTABLE REMOVED",
+ __PRETTY_FUNCTION__);
+ break;
+ }
+ return 0;
+}
+
+static void bgp_encode_pbr_rule_action(struct stream *s,
+ struct bgp_pbr_action *pbra)
+{
+ struct prefix any;
+
+ stream_putl(s, 0); /* seqno unused */
+ stream_putl(s, 0); /* ruleno unused */
+
+ stream_putl(s, pbra->unique);
+
+ memset(&any, 0, sizeof(any));
+ any.family = AF_INET;
+ stream_putc(s, any.family);
+ stream_putc(s, any.prefixlen);
+ stream_put(s, &any.u.prefix, prefix_blen(&any));
+
+ stream_putw(s, 0); /* src port */
+
+ stream_putc(s, any.family);
+ stream_putc(s, any.prefixlen);
+ stream_put(s, &any.u.prefix, prefix_blen(&any));
+
+ stream_putw(s, 0); /* dst port */
+
+ stream_putl(s, pbra->fwmark); /* fwmark */
+
+ stream_putl(s, pbra->table_id);
+
+ stream_putl(s, 0); /* ifindex unused */
+}
+
+static void bgp_encode_pbr_ipset_match(struct stream *s,
+ struct bgp_pbr_match *pbim)
+{
+ stream_putl(s, pbim->unique);
+ stream_putl(s, pbim->type);
+
+ stream_put(s, pbim->ipset_name,
+ ZEBRA_IPSET_NAME_SIZE);
+
+
+}
+
+static void bgp_encode_pbr_ipset_entry_match(struct stream *s,
+ struct bgp_pbr_match_entry *pbime)
+{
+ stream_putl(s, pbime->unique);
+ /* check that back pointer is not null */
+ stream_put(s, pbime->backpointer->ipset_name,
+ ZEBRA_IPSET_NAME_SIZE);
+
+ stream_putc(s, pbime->src.family);
+ stream_putc(s, pbime->src.prefixlen);
+ stream_put(s, &pbime->src.u.prefix, prefix_blen(&pbime->src));
+
+ stream_putc(s, pbime->dst.family);
+ stream_putc(s, pbime->dst.prefixlen);
+ stream_put(s, &pbime->dst.u.prefix, prefix_blen(&pbime->dst));
+}
+
+static void bgp_encode_pbr_iptable_match(struct stream *s,
+ struct bgp_pbr_action *bpa,
+ struct bgp_pbr_match *pbm)
+{
+ stream_putl(s, pbm->unique2);
+
+ stream_putl(s, pbm->type);
+
+ stream_putl(s, pbm->flags);
+
+ /* TODO: correlate with what is contained
+ * into bgp_pbr_action.
+ * currently only forward supported
+ */
+ if (bpa->nh.type == NEXTHOP_TYPE_BLACKHOLE)
+ stream_putl(s, ZEBRA_IPTABLES_DROP);
+ else
+ stream_putl(s, ZEBRA_IPTABLES_FORWARD);
+ stream_putl(s, bpa->fwmark);
+ stream_put(s, pbm->ipset_name,
+ ZEBRA_IPSET_NAME_SIZE);
+}
+
/* BGP has established connection with Zebra. */
static void bgp_zebra_connected(struct zclient *zclient)
{
@@ -2167,6 +2465,10 @@ void bgp_zebra_init(struct thread_master *master)
zclient->local_ip_prefix_add = bgp_zebra_process_local_ip_prefix;
zclient->local_ip_prefix_del = bgp_zebra_process_local_ip_prefix;
zclient->label_chunk = bgp_zebra_process_label_chunk;
+ zclient->rule_notify_owner = rule_notify_owner;
+ zclient->ipset_notify_owner = ipset_notify_owner;
+ zclient->ipset_entry_notify_owner = ipset_entry_notify_owner;
+ zclient->iptable_notify_owner = iptable_notify_owner;
}
void bgp_zebra_destroy(void)
@@ -2182,3 +2484,176 @@ int bgp_zebra_num_connects(void)
{
return zclient_num_connects;
}
+
+void bgp_send_pbr_rule_action(struct bgp_pbr_action *pbra, bool install)
+{
+ struct stream *s;
+
+ if (pbra->install_in_progress)
+ return;
+ zlog_debug("%s: table %d fwmark %d %d", __PRETTY_FUNCTION__,
+ pbra->table_id, pbra->fwmark, install);
+ s = zclient->obuf;
+ stream_reset(s);
+
+ zclient_create_header(s,
+ install ? ZEBRA_RULE_ADD : ZEBRA_RULE_DELETE,
+ VRF_DEFAULT);
+ stream_putl(s, 1); /* send one pbr action */
+
+ bgp_encode_pbr_rule_action(s, pbra);
+
+ stream_putw_at(s, 0, stream_get_endp(s));
+ if (!zclient_send_message(zclient) && install)
+ pbra->install_in_progress = true;
+}
+
+void bgp_send_pbr_ipset_match(struct bgp_pbr_match *pbrim, bool install)
+{
+ struct stream *s;
+
+ if (pbrim->install_in_progress)
+ return;
+ zlog_debug("%s: name %s type %d %d", __PRETTY_FUNCTION__,
+ pbrim->ipset_name, pbrim->type, install);
+ s = zclient->obuf;
+ stream_reset(s);
+
+ zclient_create_header(s,
+ install ? ZEBRA_IPSET_CREATE :
+ ZEBRA_IPSET_DESTROY,
+ VRF_DEFAULT);
+
+ stream_putl(s, 1); /* send one pbr action */
+
+ bgp_encode_pbr_ipset_match(s, pbrim);
+
+ stream_putw_at(s, 0, stream_get_endp(s));
+ if (!zclient_send_message(zclient) && install)
+ pbrim->install_in_progress = true;
+}
+
+void bgp_send_pbr_ipset_entry_match(struct bgp_pbr_match_entry *pbrime,
+ bool install)
+{
+ struct stream *s;
+
+ if (pbrime->install_in_progress)
+ return;
+ zlog_debug("%s: name %s %d %d", __PRETTY_FUNCTION__,
+ pbrime->backpointer->ipset_name,
+ pbrime->unique, install);
+ s = zclient->obuf;
+ stream_reset(s);
+
+ zclient_create_header(s,
+ install ? ZEBRA_IPSET_ENTRY_ADD :
+ ZEBRA_IPSET_ENTRY_DELETE,
+ VRF_DEFAULT);
+
+ stream_putl(s, 1); /* send one pbr action */
+
+ bgp_encode_pbr_ipset_entry_match(s, pbrime);
+
+ stream_putw_at(s, 0, stream_get_endp(s));
+ if (!zclient_send_message(zclient) && install)
+ pbrime->install_in_progress = true;
+}
+
+void bgp_send_pbr_iptable(struct bgp_pbr_action *pba,
+ struct bgp_pbr_match *pbm,
+ bool install)
+{
+ struct stream *s;
+
+ if (pbm->install_iptable_in_progress)
+ return;
+ zlog_debug("%s: name %s type %d mark %d %d", __PRETTY_FUNCTION__,
+ pbm->ipset_name, pbm->type, pba->fwmark, install);
+ s = zclient->obuf;
+ stream_reset(s);
+
+ zclient_create_header(s,
+ install ? ZEBRA_IPTABLE_ADD :
+ ZEBRA_IPTABLE_DELETE,
+ VRF_DEFAULT);
+
+ bgp_encode_pbr_iptable_match(s, pba, pbm);
+
+ stream_putw_at(s, 0, stream_get_endp(s));
+ if (!zclient_send_message(zclient) && install) {
+ pbm->install_iptable_in_progress = true;
+ pba->refcnt++;
+ }
+}
+
+/* inject in table <table_id> a default route to:
+ * - if nexthop IP is present : to this nexthop
+ * - if vrf is different from local : to the matching VRF
+ */
+void bgp_zebra_announce_default(struct bgp *bgp, struct nexthop *nh,
+ afi_t afi, uint32_t table_id, bool announce)
+{
+ struct zapi_nexthop *api_nh;
+ struct zapi_route api;
+ struct prefix p;
+
+ if (!nh || nh->type != NEXTHOP_TYPE_IPV4
+ || nh->vrf_id == VRF_UNKNOWN)
+ return;
+ memset(&p, 0, sizeof(struct prefix));
+ /* default route */
+ if (afi != AFI_IP)
+ return;
+ p.family = AF_INET;
+ memset(&api, 0, sizeof(api));
+ api.vrf_id = bgp->vrf_id;
+ api.type = ZEBRA_ROUTE_BGP;
+ api.safi = SAFI_UNICAST;
+ api.prefix = p;
+ api.tableid = table_id;
+ api.nexthop_num = 1;
+ SET_FLAG(api.message, ZAPI_MESSAGE_TABLEID);
+ SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
+ api_nh = &api.nexthops[0];
+
+ /* redirect IP */
+ if (nh->gate.ipv4.s_addr) {
+ char buff[PREFIX_STRLEN];
+
+ api_nh->vrf_id = nh->vrf_id;
+ api_nh->gate.ipv4 = nh->gate.ipv4;
+ api_nh->type = NEXTHOP_TYPE_IPV4;
+
+ inet_ntop(AF_INET, &(nh->gate.ipv4), buff, INET_ADDRSTRLEN);
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_info("BGP: sending default route to %s table %d (redirect IP)",
+ buff, table_id);
+ zclient_route_send(announce ? ZEBRA_ROUTE_ADD
+ : ZEBRA_ROUTE_DELETE,
+ zclient, &api);
+ } else if (nh->vrf_id != bgp->vrf_id) {
+ struct vrf *vrf;
+ struct interface *ifp;
+
+ vrf = vrf_lookup_by_id(nh->vrf_id);
+ if (!vrf)
+ return;
+ /* create default route with interface <VRF>
+ * with nexthop-vrf <VRF>
+ */
+ ifp = if_lookup_by_name_all_vrf(vrf->name);
+ if (!ifp)
+ return;
+ api_nh->vrf_id = nh->vrf_id;
+ api_nh->type = NEXTHOP_TYPE_IFINDEX;
+ api_nh->ifindex = ifp->ifindex;
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_info("BGP: sending default route to %s table %d (redirect VRF)",
+ vrf->name, table_id);
+ zclient_route_send(announce ? ZEBRA_ROUTE_ADD
+ : ZEBRA_ROUTE_DELETE,
+ zclient, &api);
+ return;
+ }
+}