diff options
Diffstat (limited to 'pbrd/pbr_zebra.c')
| -rw-r--r-- | pbrd/pbr_zebra.c | 194 |
1 files changed, 115 insertions, 79 deletions
diff --git a/pbrd/pbr_zebra.c b/pbrd/pbr_zebra.c index 097c9f2964..876f9e19e0 100644 --- a/pbrd/pbr_zebra.c +++ b/pbrd/pbr_zebra.c @@ -3,6 +3,9 @@ * Zebra connect code. * Copyright (C) 2018 Cumulus Networks, Inc. * Donald Sharp + * Portions: + * Copyright (c) 2021 The MITRE Corporation. + * Copyright (c) 2023 LabN Consulting, L.L.C. */ #include <zebra.h> @@ -20,6 +23,7 @@ #include "log.h" #include "nexthop.h" #include "nexthop_group.h" +#include "pbr.h" #include "pbr_nht.h" #include "pbr_map.h" @@ -125,29 +129,6 @@ int pbr_ifp_down(struct interface *ifp) return 0; } -static int interface_vrf_update(ZAPI_CALLBACK_ARGS) -{ - struct interface *ifp; - vrf_id_t new_vrf_id; - - ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id, - &new_vrf_id); - - if (!ifp) { - DEBUGD(&pbr_dbg_zebra, "%s: VRF change interface not found", - __func__); - - return 0; - } - - DEBUGD(&pbr_dbg_zebra, "%s: %s VRF change %u -> %u", __func__, - ifp->name, vrf_id, new_vrf_id); - - if_update_to_new_vrf(ifp, new_vrf_id); - - return 0; -} - static int route_notify_owner(ZAPI_CALLBACK_ARGS) { struct prefix p; @@ -331,6 +312,11 @@ void route_add(struct pbr_nexthop_group_cache *pnhgc, struct nexthop_group nhg, "%s: Asked to install unsupported route type: L2VPN", __func__); break; + case AFI_LINKSTATE: + DEBUGD(&pbr_dbg_zebra, + "%s: Asked to install unsupported route type: Link-State", + __func__); + break; case AFI_UNSPEC: DEBUGD(&pbr_dbg_zebra, "%s: Asked to install unspecified route type", __func__); @@ -376,6 +362,11 @@ void route_delete(struct pbr_nexthop_group_cache *pnhgc, afi_t afi) "%s: Asked to delete unsupported route type: L2VPN", __func__); break; + case AFI_LINKSTATE: + DEBUGD(&pbr_dbg_zebra, + "%s: Asked to delete unsupported route type: Link-State", + __func__); + break; case AFI_UNSPEC: DEBUGD(&pbr_dbg_zebra, "%s: Asked to delete unspecified route type", __func__); @@ -422,7 +413,6 @@ extern struct zebra_privs_t pbr_privs; static zclient_handler *const pbr_handlers[] = { [ZEBRA_INTERFACE_ADDRESS_ADD] = interface_address_add, [ZEBRA_INTERFACE_ADDRESS_DELETE] = interface_address_delete, - [ZEBRA_INTERFACE_VRF_UPDATE] = interface_vrf_update, [ZEBRA_ROUTE_NOTIFY_OWNER] = route_notify_owner, [ZEBRA_RULE_NOTIFY_OWNER] = rule_notify_owner, [ZEBRA_NEXTHOP_UPDATE] = pbr_zebra_nexthop_update, @@ -479,27 +469,9 @@ void pbr_send_rnh(struct nexthop *nhop, bool reg) } } -static void pbr_encode_pbr_map_sequence_prefix(struct stream *s, - struct prefix *p, - unsigned char family) -{ - struct prefix any; - - if (!p) { - memset(&any, 0, sizeof(any)); - any.family = family; - p = &any; - } - - stream_putc(s, p->family); - stream_putc(s, p->prefixlen); - stream_put(s, &p->u.prefix, prefix_blen(p)); -} -static void -pbr_encode_pbr_map_sequence_vrf(struct stream *s, - const struct pbr_map_sequence *pbrms, - const struct interface *ifp) +static uint32_t pbr_map_sequence_vrf(const struct pbr_map_sequence *pbrms, + const struct interface *ifp) { struct pbr_vrf *pbr_vrf; @@ -510,46 +482,116 @@ pbr_encode_pbr_map_sequence_vrf(struct stream *s, if (!pbr_vrf) { DEBUGD(&pbr_dbg_zebra, "%s: VRF not found", __func__); - return; + return 0; } - stream_putl(s, pbr_vrf->vrf->data.l.table_id); + return pbr_vrf->vrf->data.l.table_id; + } -static void pbr_encode_pbr_map_sequence(struct stream *s, +/* + * 230716 gpz note: it would be worthwhile for pbrd to represent + * its rules internally using the lib/pbr.h structures to help + * move toward a more common structure across pbrd, bgpd, and zebra. + */ +static bool pbr_encode_pbr_map_sequence(struct stream *s, struct pbr_map_sequence *pbrms, struct interface *ifp) { - unsigned char family; + struct pbr_rule r; + uint8_t family; + + /* + * Opportunistic address family field is set when any of the IP + * address match/set fields is set, or when a NH/NHG is resolved. + * The value is needed by zebra for the underlying netlink + * messaging, particularly in delete operations, because it + * selects the rule database (IPv4 vs. IPv6). + * + * Historically the value has been encoded into any unused + * "match src/dst address" fields and picked off in zebra. + */ family = AF_INET; if (pbrms->family) family = pbrms->family; - stream_putl(s, pbrms->seqno); - stream_putl(s, pbrms->ruleno); - stream_putl(s, pbrms->unique); - stream_putc(s, pbrms->ip_proto); /* The ip_proto */ - pbr_encode_pbr_map_sequence_prefix(s, pbrms->src, family); - stream_putw(s, pbrms->src_prt); - pbr_encode_pbr_map_sequence_prefix(s, pbrms->dst, family); - stream_putw(s, pbrms->dst_prt); - stream_putc(s, pbrms->dsfield); - stream_putl(s, pbrms->mark); + if (pbrms->src) + assert(family == pbrms->src->family); + if (pbrms->dst) + assert(family == pbrms->dst->family); + + /* + * Convert struct pbr_map_sequence to canonical form + */ + memset(&r, 0, sizeof(r)); + r.seq = pbrms->seqno; + r.priority = pbrms->ruleno; + r.unique = pbrms->unique; + + r.family = pbrms->family; + + /* filter */ + r.filter.filter_bm = pbrms->filter_bm; + if (pbrms->src) + r.filter.src_ip = *pbrms->src; + else + r.filter.src_ip.family = family; + if (pbrms->dst) + r.filter.dst_ip = *pbrms->dst; + else + r.filter.dst_ip.family = family; + r.filter.src_port = pbrms->src_prt; + r.filter.dst_port = pbrms->dst_prt; + r.filter.pcp = pbrms->match_pcp; + r.filter.vlan_id = pbrms->match_vlan_id; + r.filter.vlan_flags = pbrms->match_vlan_flags; + r.filter.dsfield = pbrms->dsfield; + r.filter.fwmark = pbrms->mark; + r.filter.ip_proto = pbrms->ip_proto; + + r.filter.filter_bm = pbrms->filter_bm; - stream_putl(s, pbrms->action_queue_id); + /* actions */ - stream_putw(s, pbrms->action_vlan_id); - stream_putw(s, pbrms->action_vlan_flags); - stream_putw(s, pbrms->action_pcp); + r.action.flags = pbrms->action_bm; + SET_FLAG(r.action.flags, PBR_ACTION_TABLE); /* always valid */ + + /* + * if the user does not use the command "set vrf name unchanged" + * then pbr_encode_pbr_map_sequence_vrf will not be called + */ if (pbrms->vrf_unchanged || pbrms->vrf_lookup) - pbr_encode_pbr_map_sequence_vrf(s, pbrms, ifp); + r.action.table = pbr_map_sequence_vrf(pbrms, ifp); else if (pbrms->nhgrp_name) - stream_putl(s, pbr_nht_get_table(pbrms->nhgrp_name)); + r.action.table = pbr_nht_get_table(pbrms->nhgrp_name); else if (pbrms->nhg) - stream_putl(s, pbr_nht_get_table(pbrms->internal_nhg_name)); - stream_put(s, ifp->name, INTERFACE_NAMSIZ); + r.action.table = pbr_nht_get_table(pbrms->internal_nhg_name); + else { + /* Not valid for install without table */ + return false; + } + + r.action.queue_id = pbrms->action_queue_id; + + r.action.src_ip = pbrms->action_src; + r.action.dst_ip = pbrms->action_dst; + + r.action.src_port = pbrms->action_src_port; + r.action.dst_port = pbrms->action_dst_port; + + r.action.dscp = pbrms->action_dscp; + r.action.ecn = pbrms->action_ecn; + + r.action.pcp = pbrms->action_pcp; + r.action.vlan_id = pbrms->action_vlan_id; + + strlcpy(r.ifname, ifp->name, sizeof(r.ifname)); + + zapi_pbr_rule_encode(s, &r); + + return true; } bool pbr_send_pbr_map(struct pbr_map_sequence *pbrms, @@ -561,9 +603,6 @@ bool pbr_send_pbr_map(struct pbr_map_sequence *pbrms, is_installed &= pbrms->installed; - DEBUGD(&pbr_dbg_zebra, "%s: for %s %d(%" PRIu64 ")", __func__, - pbrm->name, install, is_installed); - /* * If we are installed and asked to do so again and the config * has not changed, just return. @@ -584,20 +623,17 @@ bool pbr_send_pbr_map(struct pbr_map_sequence *pbrms, install ? ZEBRA_RULE_ADD : ZEBRA_RULE_DELETE, VRF_DEFAULT); - /* - * We are sending one item at a time at the moment - */ - stream_putl(s, 1); - DEBUGD(&pbr_dbg_zebra, "%s: %s %s seq %u %d %s %u", __func__, install ? "Installing" : "Deleting", pbrm->name, pbrms->seqno, install, pmi->ifp->name, pmi->delete); - pbr_encode_pbr_map_sequence(s, pbrms, pmi->ifp); - - stream_putw_at(s, 0, stream_get_endp(s)); - - zclient_send_message(zclient); + if (pbr_encode_pbr_map_sequence(s, pbrms, pmi->ifp)) { + stream_putw_at(s, 0, stream_get_endp(s)); + zclient_send_message(zclient); + } else { + DEBUGD(&pbr_dbg_zebra, "%s: %s seq %u encode failed, skipped", + __func__, pbrm->name, pbrms->seqno); + } return true; } |
