From c16a0a62bcc77fba61d95ed45496b3d46cfe0734 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Mon, 12 Mar 2018 09:38:53 +0100 Subject: [PATCH] bgpd: handle configuration of iptables with zebra The API for filling in an IPTABLE_ADD and IPTABLE_DELETE message. Also, the API is handling the notification callback, so as to know if zebra managed to add or delete the relevant iptable entry. Signed-off-by: Philippe Guibert --- bgpd/bgp_zebra.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++ bgpd/bgp_zebra.h | 3 ++ lib/zclient.c | 36 +++++++++++++++++++ lib/zclient.h | 7 ++++ 4 files changed, 138 insertions(+) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index eb9cc6c3f..f47668603 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -2047,6 +2047,49 @@ static int ipset_entry_notify_owner(int command, struct zclient *zclient, 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, + ¬e)) + 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__); + 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) { @@ -2107,6 +2150,29 @@ static void bgp_encode_pbr_ipset_entry_match(struct stream *s, 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) { @@ -2369,6 +2435,7 @@ void bgp_zebra_init(struct thread_master *master) 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) @@ -2459,3 +2526,28 @@ void bgp_send_pbr_ipset_entry_match(struct bgp_pbr_match_entry *pbrime, 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; +} diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index 94a20a3fd..003db6531 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -79,5 +79,8 @@ extern void bgp_send_pbr_ipset_match(struct bgp_pbr_match *pbrim, bool install); extern void bgp_send_pbr_ipset_entry_match(struct bgp_pbr_match_entry *pbrime, bool install); +extern void bgp_send_pbr_iptable(struct bgp_pbr_action *pba, + struct bgp_pbr_match *pbm, + bool install); #endif /* _QUAGGA_BGP_ZEBRA_H */ diff --git a/lib/zclient.c b/lib/zclient.c index dc27cbef7..cb39099fc 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -1374,6 +1374,26 @@ stream_failure: return false; } +bool zapi_iptable_notify_decode(struct stream *s, + uint32_t *unique, + enum zapi_iptable_notify_owner *note) +{ + uint32_t uni; + + STREAM_GET(note, s, sizeof(*note)); + + STREAM_GETL(s, uni); + + if (zclient_debug) + zlog_debug("%s: %u", __PRETTY_FUNCTION__, uni); + *unique = uni; + + return true; + +stream_failure: + return false; +} + struct nexthop *nexthop_from_zapi_nexthop(struct zapi_nexthop *znh) { struct nexthop *n = nexthop_new(); @@ -2765,6 +2785,22 @@ static int zclient_read(struct thread *thread) (*zclient->label_chunk)(command, zclient, length, vrf_id); break; + case ZEBRA_IPSET_NOTIFY_OWNER: + if (zclient->ipset_notify_owner) + (*zclient->ipset_notify_owner)(command, zclient, length, + vrf_id); + break; + case ZEBRA_IPSET_ENTRY_NOTIFY_OWNER: + if (zclient->ipset_entry_notify_owner) + (*zclient->ipset_entry_notify_owner)(command, + zclient, length, + vrf_id); + break; + case ZEBRA_IPTABLE_NOTIFY_OWNER: + if (zclient->iptable_notify_owner) + (*zclient->iptable_notify_owner)(command, + zclient, length, + vrf_id); default: break; } diff --git a/lib/zclient.h b/lib/zclient.h index 71f5b3838..8d26b7fe5 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -258,6 +258,10 @@ struct zclient { struct zclient *zclient, uint16_t length, vrf_id_t vrf_id); + int (*iptable_notify_owner)(int command, + struct zclient *zclient, + uint16_t length, + vrf_id_t vrf_id); }; /* Zebra API message flag. */ @@ -680,6 +684,9 @@ bool zapi_ipset_entry_notify_decode(struct stream *s, uint32_t *unique, char *ipset_name, enum zapi_ipset_entry_notify_owner *note); +bool zapi_iptable_notify_decode(struct stream *s, + uint32_t *unique, + enum zapi_iptable_notify_owner *note); extern struct nexthop *nexthop_from_zapi_nexthop(struct zapi_nexthop *znh); extern bool zapi_nexthop_update_decode(struct stream *s, -- 2.39.5