2018-02-04 13:33:33 +01:00
|
|
|
/* Zebra Policy Based Routing (PBR) main handling.
|
|
|
|
* Copyright (C) 2018 Cumulus Networks, Inc.
|
|
|
|
*
|
|
|
|
* This file is part of FRR.
|
|
|
|
*
|
|
|
|
* FRR 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.
|
|
|
|
*
|
|
|
|
* FRR 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 FRR; 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>
|
|
|
|
|
2018-02-16 03:34:04 +01:00
|
|
|
#include <jhash.h>
|
|
|
|
#include <hash.h>
|
2018-04-25 18:34:27 +02:00
|
|
|
#include <memory.h>
|
2018-05-04 13:57:31 +02:00
|
|
|
#include <hook.h>
|
2018-02-16 03:34:04 +01:00
|
|
|
|
2018-02-04 13:33:33 +01:00
|
|
|
#include "zebra/zebra_pbr.h"
|
|
|
|
#include "zebra/rt.h"
|
2018-04-22 22:01:20 +02:00
|
|
|
#include "zebra/zapi_msg.h"
|
2018-04-25 18:34:27 +02:00
|
|
|
#include "zebra/zebra_memory.h"
|
2018-05-29 09:51:41 +02:00
|
|
|
#include "zebra/zserv.h"
|
2018-04-25 18:34:27 +02:00
|
|
|
|
|
|
|
/* definitions */
|
|
|
|
DEFINE_MTYPE_STATIC(ZEBRA, PBR_IPTABLE_IFNAME, "PBR interface list")
|
2018-02-04 13:33:33 +01:00
|
|
|
|
|
|
|
/* definitions */
|
2018-04-23 15:17:19 +02:00
|
|
|
static const struct message ipset_type_msg[] = {
|
|
|
|
{IPSET_NET_PORT_NET, "net,port,net"},
|
|
|
|
{IPSET_NET_PORT, "net,port"},
|
|
|
|
{IPSET_NET_NET, "net,net"},
|
|
|
|
{IPSET_NET, "net"},
|
|
|
|
{0}
|
|
|
|
};
|
2018-02-04 13:33:33 +01:00
|
|
|
|
|
|
|
/* static function declarations */
|
2018-05-04 13:57:31 +02:00
|
|
|
DEFINE_HOOK(zebra_pbr_ipset_entry_wrap_script_get_stat, (struct zebra_ns *zns,
|
|
|
|
struct zebra_pbr_ipset_entry *ipset,
|
|
|
|
uint64_t *pkts, uint64_t *bytes),
|
|
|
|
(zns, ipset, pkts, bytes))
|
|
|
|
|
|
|
|
DEFINE_HOOK(zebra_pbr_iptable_wrap_script_get_stat, (struct zebra_ns *zns,
|
|
|
|
struct zebra_pbr_iptable *iptable,
|
|
|
|
uint64_t *pkts, uint64_t *bytes),
|
|
|
|
(zns, iptable, pkts, bytes))
|
|
|
|
|
|
|
|
DEFINE_HOOK(zebra_pbr_iptable_wrap_script_update, (struct zebra_ns *zns,
|
|
|
|
int cmd,
|
|
|
|
struct zebra_pbr_iptable *iptable),
|
|
|
|
(zns, cmd, iptable));
|
|
|
|
|
|
|
|
DEFINE_HOOK(zebra_pbr_ipset_entry_wrap_script_update, (struct zebra_ns *zns,
|
|
|
|
int cmd,
|
|
|
|
struct zebra_pbr_ipset_entry *ipset),
|
|
|
|
(zns, cmd, ipset));
|
|
|
|
|
|
|
|
DEFINE_HOOK(zebra_pbr_ipset_wrap_script_update, (struct zebra_ns *zns,
|
|
|
|
int cmd,
|
|
|
|
struct zebra_pbr_ipset *ipset),
|
|
|
|
(zns, cmd, ipset));
|
2018-02-04 13:33:33 +01:00
|
|
|
|
|
|
|
/* Private functions */
|
|
|
|
|
|
|
|
/* Public functions */
|
2018-02-16 03:34:04 +01:00
|
|
|
void zebra_pbr_rules_free(void *arg)
|
2018-02-16 02:11:12 +01:00
|
|
|
{
|
2018-02-16 03:34:04 +01:00
|
|
|
struct zebra_pbr_rule *rule;
|
|
|
|
|
|
|
|
rule = (struct zebra_pbr_rule *)arg;
|
|
|
|
|
2018-05-25 16:54:50 +02:00
|
|
|
(void)kernel_del_pbr_rule(rule);
|
2018-02-16 03:34:04 +01:00
|
|
|
XFREE(MTYPE_TMP, rule);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t zebra_pbr_rules_hash_key(void *arg)
|
|
|
|
{
|
|
|
|
struct zebra_pbr_rule *rule;
|
|
|
|
uint32_t key;
|
|
|
|
|
|
|
|
rule = (struct zebra_pbr_rule *)arg;
|
2018-03-21 11:59:02 +01:00
|
|
|
key = jhash_3words(rule->rule.seq, rule->rule.priority,
|
|
|
|
rule->rule.action.table,
|
|
|
|
prefix_hash_key(&rule->rule.filter.src_ip));
|
2018-02-23 19:45:36 +01:00
|
|
|
if (rule->ifp)
|
|
|
|
key = jhash_1word(rule->ifp->ifindex, key);
|
|
|
|
else
|
|
|
|
key = jhash_1word(0, key);
|
|
|
|
|
2018-03-21 11:59:02 +01:00
|
|
|
if (rule->rule.filter.fwmark)
|
|
|
|
key = jhash_1word(rule->rule.filter.fwmark, key);
|
2018-03-08 15:20:49 +01:00
|
|
|
else
|
|
|
|
key = jhash_1word(0, key);
|
2018-03-21 11:59:02 +01:00
|
|
|
return jhash_3words(rule->rule.filter.src_port,
|
|
|
|
rule->rule.filter.dst_port,
|
|
|
|
prefix_hash_key(&rule->rule.filter.dst_ip),
|
|
|
|
jhash_1word(rule->rule.unique, key));
|
2018-02-16 03:34:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2)
|
|
|
|
{
|
|
|
|
const struct zebra_pbr_rule *r1, *r2;
|
|
|
|
|
|
|
|
r1 = (const struct zebra_pbr_rule *)arg1;
|
|
|
|
r2 = (const struct zebra_pbr_rule *)arg2;
|
|
|
|
|
2018-03-21 11:59:02 +01:00
|
|
|
if (r1->rule.seq != r2->rule.seq)
|
2018-02-16 03:34:04 +01:00
|
|
|
return 0;
|
|
|
|
|
2018-03-21 11:59:02 +01:00
|
|
|
if (r1->rule.priority != r2->rule.priority)
|
2018-02-16 03:34:04 +01:00
|
|
|
return 0;
|
|
|
|
|
2018-03-21 11:59:02 +01:00
|
|
|
if (r1->rule.unique != r2->rule.unique)
|
2018-02-23 19:48:06 +01:00
|
|
|
return 0;
|
|
|
|
|
2018-03-21 11:59:02 +01:00
|
|
|
if (r1->rule.action.table != r2->rule.action.table)
|
2018-02-16 03:34:04 +01:00
|
|
|
return 0;
|
|
|
|
|
2018-03-21 11:59:02 +01:00
|
|
|
if (r1->rule.filter.src_port != r2->rule.filter.src_port)
|
2018-02-16 03:34:04 +01:00
|
|
|
return 0;
|
|
|
|
|
2018-03-21 11:59:02 +01:00
|
|
|
if (r1->rule.filter.dst_port != r2->rule.filter.dst_port)
|
2018-02-16 03:34:04 +01:00
|
|
|
return 0;
|
|
|
|
|
2018-03-21 11:59:02 +01:00
|
|
|
if (r1->rule.filter.fwmark != r2->rule.filter.fwmark)
|
2018-03-08 15:20:49 +01:00
|
|
|
return 0;
|
|
|
|
|
2018-03-21 11:59:02 +01:00
|
|
|
if (!prefix_same(&r1->rule.filter.src_ip, &r2->rule.filter.src_ip))
|
2018-02-16 03:34:04 +01:00
|
|
|
return 0;
|
|
|
|
|
2018-03-21 11:59:02 +01:00
|
|
|
if (!prefix_same(&r1->rule.filter.dst_ip, &r2->rule.filter.dst_ip))
|
2018-02-16 03:34:04 +01:00
|
|
|
return 0;
|
|
|
|
|
2018-02-23 19:45:36 +01:00
|
|
|
if (r1->ifp != r2->ifp)
|
|
|
|
return 0;
|
|
|
|
|
2018-02-16 03:34:04 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2018-03-24 14:58:04 +01:00
|
|
|
struct pbr_rule_unique_lookup {
|
2018-03-22 13:26:27 +01:00
|
|
|
struct zebra_pbr_rule *rule;
|
|
|
|
uint32_t unique;
|
2018-04-06 22:38:20 +02:00
|
|
|
struct interface *ifp;
|
2018-03-22 13:26:27 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
static int pbr_rule_lookup_unique_walker(struct hash_backet *b, void *data)
|
|
|
|
{
|
2018-03-24 14:58:04 +01:00
|
|
|
struct pbr_rule_unique_lookup *pul = data;
|
2018-03-22 13:26:27 +01:00
|
|
|
struct zebra_pbr_rule *rule = b->data;
|
|
|
|
|
2018-04-06 22:38:20 +02:00
|
|
|
if (pul->unique == rule->rule.unique && pul->ifp == rule->ifp) {
|
2018-03-22 13:26:27 +01:00
|
|
|
pul->rule = rule;
|
|
|
|
return HASHWALK_ABORT;
|
|
|
|
}
|
|
|
|
|
|
|
|
return HASHWALK_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct zebra_pbr_rule *pbr_rule_lookup_unique(struct zebra_ns *zns,
|
2018-04-06 22:38:20 +02:00
|
|
|
uint32_t unique,
|
|
|
|
struct interface *ifp)
|
2018-03-22 13:26:27 +01:00
|
|
|
{
|
2018-03-24 14:58:04 +01:00
|
|
|
struct pbr_rule_unique_lookup pul;
|
2018-03-22 13:26:27 +01:00
|
|
|
|
|
|
|
pul.unique = unique;
|
2018-04-06 22:38:20 +02:00
|
|
|
pul.ifp = ifp;
|
2018-03-22 13:26:27 +01:00
|
|
|
pul.rule = NULL;
|
|
|
|
hash_walk(zns->rules_hash, &pbr_rule_lookup_unique_walker, &pul);
|
|
|
|
|
|
|
|
return pul.rule;
|
|
|
|
}
|
|
|
|
|
2018-03-07 12:54:16 +01:00
|
|
|
void zebra_pbr_ipset_free(void *arg)
|
|
|
|
{
|
|
|
|
struct zebra_pbr_ipset *ipset;
|
2018-05-04 13:57:31 +02:00
|
|
|
struct zebra_ns *zns;
|
2018-03-07 12:54:16 +01:00
|
|
|
|
|
|
|
ipset = (struct zebra_pbr_ipset *)arg;
|
2018-05-04 13:57:31 +02:00
|
|
|
if (vrf_is_backend_netns())
|
|
|
|
zns = zebra_ns_lookup(ipset->vrf_id);
|
|
|
|
else
|
|
|
|
zns = zebra_ns_lookup(NS_DEFAULT);
|
|
|
|
hook_call(zebra_pbr_ipset_wrap_script_update,
|
|
|
|
zns, 0, ipset);
|
2018-03-07 12:54:16 +01:00
|
|
|
XFREE(MTYPE_TMP, ipset);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t zebra_pbr_ipset_hash_key(void *arg)
|
|
|
|
{
|
|
|
|
struct zebra_pbr_ipset *ipset = (struct zebra_pbr_ipset *)arg;
|
2018-03-07 15:46:00 +01:00
|
|
|
uint32_t *pnt = (uint32_t *)&ipset->ipset_name;
|
2018-03-07 12:54:16 +01:00
|
|
|
|
2018-03-07 15:46:00 +01:00
|
|
|
return jhash2(pnt, ZEBRA_IPSET_NAME_HASH_SIZE, 0x63ab42de);
|
2018-03-07 12:54:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int zebra_pbr_ipset_hash_equal(const void *arg1, const void *arg2)
|
|
|
|
{
|
|
|
|
const struct zebra_pbr_ipset *r1, *r2;
|
|
|
|
|
|
|
|
r1 = (const struct zebra_pbr_ipset *)arg1;
|
|
|
|
r2 = (const struct zebra_pbr_ipset *)arg2;
|
|
|
|
|
|
|
|
if (r1->type != r2->type)
|
|
|
|
return 0;
|
|
|
|
if (r1->unique != r2->unique)
|
|
|
|
return 0;
|
|
|
|
if (strncmp(r1->ipset_name, r2->ipset_name,
|
|
|
|
ZEBRA_IPSET_NAME_SIZE))
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void zebra_pbr_ipset_entry_free(void *arg)
|
|
|
|
{
|
|
|
|
struct zebra_pbr_ipset_entry *ipset;
|
2018-05-04 13:57:31 +02:00
|
|
|
struct zebra_ns *zns;
|
2018-03-07 12:54:16 +01:00
|
|
|
|
|
|
|
ipset = (struct zebra_pbr_ipset_entry *)arg;
|
2018-05-04 13:57:31 +02:00
|
|
|
if (ipset->backpointer && vrf_is_backend_netns()) {
|
|
|
|
struct zebra_pbr_ipset *ips = ipset->backpointer;
|
|
|
|
|
|
|
|
zns = zebra_ns_lookup((ns_id_t)ips->vrf_id);
|
|
|
|
} else
|
|
|
|
zns = zebra_ns_lookup(NS_DEFAULT);
|
|
|
|
hook_call(zebra_pbr_ipset_entry_wrap_script_update,
|
|
|
|
zns, 0, ipset);
|
2018-03-07 12:54:16 +01:00
|
|
|
|
|
|
|
XFREE(MTYPE_TMP, ipset);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t zebra_pbr_ipset_entry_hash_key(void *arg)
|
|
|
|
{
|
|
|
|
struct zebra_pbr_ipset_entry *ipset;
|
|
|
|
uint32_t key;
|
|
|
|
|
|
|
|
ipset = (struct zebra_pbr_ipset_entry *)arg;
|
|
|
|
key = prefix_hash_key(&ipset->src);
|
|
|
|
key = jhash_1word(ipset->unique, key);
|
|
|
|
key = jhash_1word(prefix_hash_key(&ipset->dst), key);
|
2018-03-30 13:01:39 +02:00
|
|
|
key = jhash(&ipset->dst_port_min, 2, key);
|
|
|
|
key = jhash(&ipset->dst_port_max, 2, key);
|
|
|
|
key = jhash(&ipset->src_port_min, 2, key);
|
|
|
|
key = jhash(&ipset->src_port_max, 2, key);
|
|
|
|
key = jhash(&ipset->proto, 1, key);
|
2018-03-07 12:54:16 +01:00
|
|
|
|
|
|
|
return key;
|
|
|
|
}
|
|
|
|
|
|
|
|
int zebra_pbr_ipset_entry_hash_equal(const void *arg1, const void *arg2)
|
|
|
|
{
|
|
|
|
const struct zebra_pbr_ipset_entry *r1, *r2;
|
|
|
|
|
|
|
|
r1 = (const struct zebra_pbr_ipset_entry *)arg1;
|
|
|
|
r2 = (const struct zebra_pbr_ipset_entry *)arg2;
|
|
|
|
|
|
|
|
if (r1->unique != r2->unique)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!prefix_same(&r1->src, &r2->src))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!prefix_same(&r1->dst, &r2->dst))
|
|
|
|
return 0;
|
|
|
|
|
2018-03-30 13:01:39 +02:00
|
|
|
if (r1->src_port_min != r2->src_port_min)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (r1->src_port_max != r2->src_port_max)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (r1->dst_port_min != r2->dst_port_min)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (r1->dst_port_max != r2->dst_port_max)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (r1->proto != r2->proto)
|
|
|
|
return 0;
|
2018-03-07 12:54:16 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2018-03-12 09:23:48 +01:00
|
|
|
void zebra_pbr_iptable_free(void *arg)
|
|
|
|
{
|
|
|
|
struct zebra_pbr_iptable *iptable;
|
2018-04-25 18:34:27 +02:00
|
|
|
struct listnode *node, *nnode;
|
|
|
|
char *name;
|
2018-05-04 13:57:31 +02:00
|
|
|
struct zebra_ns *zns;
|
2018-03-12 09:23:48 +01:00
|
|
|
|
|
|
|
iptable = (struct zebra_pbr_iptable *)arg;
|
2018-05-04 13:57:31 +02:00
|
|
|
if (vrf_is_backend_netns())
|
|
|
|
zns = zebra_ns_lookup((ns_id_t)iptable->vrf_id);
|
|
|
|
else
|
|
|
|
zns = zebra_ns_lookup(NS_DEFAULT);
|
|
|
|
hook_call(zebra_pbr_iptable_wrap_script_update,
|
|
|
|
zns, 0, iptable);
|
2018-03-12 09:23:48 +01:00
|
|
|
|
2018-04-25 18:34:27 +02:00
|
|
|
for (ALL_LIST_ELEMENTS(iptable->interface_name_list,
|
|
|
|
node, nnode, name)) {
|
|
|
|
XFREE(MTYPE_PBR_IPTABLE_IFNAME, name);
|
|
|
|
list_delete_node(iptable->interface_name_list,
|
|
|
|
node);
|
|
|
|
}
|
2018-03-12 09:23:48 +01:00
|
|
|
XFREE(MTYPE_TMP, iptable);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t zebra_pbr_iptable_hash_key(void *arg)
|
|
|
|
{
|
|
|
|
struct zebra_pbr_iptable *iptable = (struct zebra_pbr_iptable *)arg;
|
|
|
|
uint32_t *pnt = (uint32_t *)&(iptable->ipset_name);
|
|
|
|
uint32_t key;
|
|
|
|
|
|
|
|
key = jhash2(pnt, ZEBRA_IPSET_NAME_HASH_SIZE,
|
|
|
|
0x63ab42de);
|
|
|
|
key = jhash_1word(iptable->fwmark, key);
|
|
|
|
return jhash_3words(iptable->filter_bm, iptable->type,
|
|
|
|
iptable->unique, key);
|
|
|
|
}
|
|
|
|
|
|
|
|
int zebra_pbr_iptable_hash_equal(const void *arg1, const void *arg2)
|
|
|
|
{
|
|
|
|
const struct zebra_pbr_iptable *r1, *r2;
|
|
|
|
|
|
|
|
r1 = (const struct zebra_pbr_iptable *)arg1;
|
|
|
|
r2 = (const struct zebra_pbr_iptable *)arg2;
|
|
|
|
|
|
|
|
if (r1->type != r2->type)
|
|
|
|
return 0;
|
|
|
|
if (r1->unique != r2->unique)
|
|
|
|
return 0;
|
|
|
|
if (r1->filter_bm != r2->filter_bm)
|
|
|
|
return 0;
|
|
|
|
if (r1->fwmark != r2->fwmark)
|
|
|
|
return 0;
|
|
|
|
if (r1->action != r2->action)
|
|
|
|
return 0;
|
|
|
|
if (strncmp(r1->ipset_name, r2->ipset_name,
|
|
|
|
ZEBRA_IPSET_NAME_SIZE))
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2018-02-16 03:34:04 +01:00
|
|
|
static void *pbr_rule_alloc_intern(void *arg)
|
|
|
|
{
|
|
|
|
struct zebra_pbr_rule *zpr;
|
|
|
|
struct zebra_pbr_rule *new;
|
|
|
|
|
|
|
|
zpr = (struct zebra_pbr_rule *)arg;
|
|
|
|
|
|
|
|
new = XCALLOC(MTYPE_TMP, sizeof(*new));
|
|
|
|
|
|
|
|
memcpy(new, zpr, sizeof(*zpr));
|
|
|
|
|
|
|
|
return new;
|
|
|
|
}
|
|
|
|
|
2018-02-23 19:45:36 +01:00
|
|
|
void zebra_pbr_add_rule(struct zebra_ns *zns, struct zebra_pbr_rule *rule)
|
2018-02-16 03:34:04 +01:00
|
|
|
{
|
2018-03-22 13:26:27 +01:00
|
|
|
struct zebra_pbr_rule *unique =
|
2018-04-06 22:38:20 +02:00
|
|
|
pbr_rule_lookup_unique(zns, rule->rule.unique, rule->ifp);
|
2018-03-22 13:26:27 +01:00
|
|
|
|
2018-02-16 03:34:04 +01:00
|
|
|
(void)hash_get(zns->rules_hash, rule, pbr_rule_alloc_intern);
|
2018-05-25 16:54:50 +02:00
|
|
|
(void)kernel_add_pbr_rule(rule);
|
2018-03-22 13:26:27 +01:00
|
|
|
/*
|
|
|
|
* Rule Replace semantics, if we have an old, install the
|
|
|
|
* new rule, look above, and then delete the old
|
|
|
|
*/
|
|
|
|
if (unique)
|
|
|
|
zebra_pbr_del_rule(zns, unique);
|
2018-02-16 02:11:12 +01:00
|
|
|
}
|
|
|
|
|
2018-02-23 19:45:36 +01:00
|
|
|
void zebra_pbr_del_rule(struct zebra_ns *zns, struct zebra_pbr_rule *rule)
|
2018-02-16 02:11:12 +01:00
|
|
|
{
|
2018-02-16 03:34:04 +01:00
|
|
|
struct zebra_pbr_rule *lookup;
|
|
|
|
|
|
|
|
lookup = hash_lookup(zns->rules_hash, rule);
|
2018-05-25 16:54:50 +02:00
|
|
|
(void)kernel_del_pbr_rule(rule);
|
2018-02-16 03:34:04 +01:00
|
|
|
|
2018-03-22 22:00:19 +01:00
|
|
|
if (lookup) {
|
|
|
|
hash_release(zns->rules_hash, lookup);
|
2018-02-16 03:34:04 +01:00
|
|
|
XFREE(MTYPE_TMP, lookup);
|
2018-03-22 22:00:19 +01:00
|
|
|
} else
|
2018-02-16 03:34:04 +01:00
|
|
|
zlog_warn("%s: Rule being deleted we know nothing about",
|
|
|
|
__PRETTY_FUNCTION__);
|
2018-02-16 02:11:12 +01:00
|
|
|
}
|
|
|
|
|
2018-03-16 02:06:44 +01:00
|
|
|
static void zebra_pbr_cleanup_rules(struct hash_backet *b, void *data)
|
|
|
|
{
|
|
|
|
struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
|
|
|
|
struct zebra_pbr_rule *rule = b->data;
|
|
|
|
int *sock = data;
|
|
|
|
|
|
|
|
if (rule->sock == *sock) {
|
2018-05-25 16:54:50 +02:00
|
|
|
(void)kernel_del_pbr_rule(rule);
|
2018-03-16 02:06:44 +01:00
|
|
|
hash_release(zns->rules_hash, rule);
|
2018-03-22 22:00:19 +01:00
|
|
|
XFREE(MTYPE_TMP, rule);
|
2018-03-16 02:06:44 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-21 17:52:41 +01:00
|
|
|
static void zebra_pbr_cleanup_ipset(struct hash_backet *b, void *data)
|
|
|
|
{
|
|
|
|
struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
|
|
|
|
struct zebra_pbr_ipset *ipset = b->data;
|
|
|
|
int *sock = data;
|
|
|
|
|
2018-05-04 13:57:31 +02:00
|
|
|
if (ipset->sock == *sock) {
|
|
|
|
hook_call(zebra_pbr_ipset_wrap_script_update,
|
|
|
|
zns, 0, ipset);
|
2018-03-21 17:52:41 +01:00
|
|
|
hash_release(zns->ipset_hash, ipset);
|
2018-05-04 13:57:31 +02:00
|
|
|
}
|
2018-03-21 17:52:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void zebra_pbr_cleanup_ipset_entry(struct hash_backet *b, void *data)
|
|
|
|
{
|
|
|
|
struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
|
|
|
|
struct zebra_pbr_ipset_entry *ipset = b->data;
|
|
|
|
int *sock = data;
|
|
|
|
|
2018-05-04 13:57:31 +02:00
|
|
|
if (ipset->sock == *sock) {
|
|
|
|
hook_call(zebra_pbr_ipset_entry_wrap_script_update,
|
|
|
|
zns, 0, ipset);
|
2018-03-21 17:52:41 +01:00
|
|
|
hash_release(zns->ipset_entry_hash, ipset);
|
2018-05-04 13:57:31 +02:00
|
|
|
}
|
2018-03-21 17:52:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void zebra_pbr_cleanup_iptable(struct hash_backet *b, void *data)
|
|
|
|
{
|
|
|
|
struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
|
|
|
|
struct zebra_pbr_iptable *iptable = b->data;
|
|
|
|
int *sock = data;
|
|
|
|
|
2018-05-04 13:57:31 +02:00
|
|
|
if (iptable->sock == *sock) {
|
|
|
|
hook_call(zebra_pbr_iptable_wrap_script_update,
|
|
|
|
zns, 0, iptable);
|
2018-03-21 17:52:41 +01:00
|
|
|
hash_release(zns->iptable_hash, iptable);
|
2018-05-04 13:57:31 +02:00
|
|
|
}
|
2018-03-21 17:52:41 +01:00
|
|
|
}
|
|
|
|
|
2018-05-22 12:22:08 +02:00
|
|
|
static int zebra_pbr_client_close_cleanup(struct zserv *client)
|
2018-03-16 02:06:44 +01:00
|
|
|
{
|
2018-05-22 12:22:08 +02:00
|
|
|
int sock = client->sock;
|
2018-03-16 02:06:44 +01:00
|
|
|
struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
|
|
|
|
|
2018-05-22 12:22:08 +02:00
|
|
|
if (!sock)
|
|
|
|
return 0;
|
2018-03-16 02:06:44 +01:00
|
|
|
hash_iterate(zns->rules_hash, zebra_pbr_cleanup_rules, &sock);
|
2018-03-21 17:52:41 +01:00
|
|
|
hash_iterate(zns->iptable_hash,
|
|
|
|
zebra_pbr_cleanup_iptable, &sock);
|
|
|
|
hash_iterate(zns->ipset_entry_hash,
|
|
|
|
zebra_pbr_cleanup_ipset_entry, &sock);
|
|
|
|
hash_iterate(zns->ipset_hash,
|
|
|
|
zebra_pbr_cleanup_ipset, &sock);
|
2018-05-22 12:22:08 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void zebra_pbr_init(void)
|
|
|
|
{
|
2018-05-29 09:51:41 +02:00
|
|
|
hook_register(zserv_client_close, zebra_pbr_client_close_cleanup);
|
2018-03-16 02:06:44 +01:00
|
|
|
}
|
|
|
|
|
2018-03-07 12:54:16 +01:00
|
|
|
static void *pbr_ipset_alloc_intern(void *arg)
|
|
|
|
{
|
|
|
|
struct zebra_pbr_ipset *zpi;
|
|
|
|
struct zebra_pbr_ipset *new;
|
|
|
|
|
|
|
|
zpi = (struct zebra_pbr_ipset *)arg;
|
|
|
|
|
|
|
|
new = XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_ipset));
|
|
|
|
|
|
|
|
memcpy(new, zpi, sizeof(*zpi));
|
|
|
|
|
|
|
|
return new;
|
|
|
|
}
|
|
|
|
|
|
|
|
void zebra_pbr_create_ipset(struct zebra_ns *zns,
|
|
|
|
struct zebra_pbr_ipset *ipset)
|
|
|
|
{
|
2018-05-04 13:57:31 +02:00
|
|
|
int ret;
|
|
|
|
|
2018-03-07 12:54:16 +01:00
|
|
|
(void)hash_get(zns->ipset_hash, ipset, pbr_ipset_alloc_intern);
|
2018-05-04 13:57:31 +02:00
|
|
|
ret = hook_call(zebra_pbr_ipset_wrap_script_update,
|
|
|
|
zns, 1, ipset);
|
|
|
|
kernel_pbr_ipset_add_del_status(ipset,
|
2018-05-25 16:37:48 +02:00
|
|
|
ret ? DP_INSTALL_SUCCESS
|
|
|
|
: DP_INSTALL_FAILURE);
|
2018-03-07 12:54:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void zebra_pbr_destroy_ipset(struct zebra_ns *zns,
|
|
|
|
struct zebra_pbr_ipset *ipset)
|
|
|
|
{
|
|
|
|
struct zebra_pbr_ipset *lookup;
|
|
|
|
|
|
|
|
lookup = hash_lookup(zns->ipset_hash, ipset);
|
2018-05-04 13:57:31 +02:00
|
|
|
hook_call(zebra_pbr_ipset_wrap_script_update,
|
|
|
|
zns, 0, ipset);
|
2018-04-26 13:31:16 +02:00
|
|
|
if (lookup) {
|
|
|
|
hash_release(zns->ipset_hash, lookup);
|
2018-03-07 12:54:16 +01:00
|
|
|
XFREE(MTYPE_TMP, lookup);
|
2018-04-26 13:31:16 +02:00
|
|
|
} else
|
2018-03-07 15:46:00 +01:00
|
|
|
zlog_warn("%s: IPSet Entry being deleted we know nothing about",
|
2018-03-07 12:54:16 +01:00
|
|
|
__PRETTY_FUNCTION__);
|
|
|
|
}
|
|
|
|
|
2018-03-24 14:55:06 +01:00
|
|
|
struct pbr_ipset_name_lookup {
|
|
|
|
struct zebra_pbr_ipset *ipset;
|
|
|
|
char ipset_name[ZEBRA_IPSET_NAME_SIZE];
|
|
|
|
};
|
|
|
|
|
2018-06-21 15:01:01 +02:00
|
|
|
const char *zebra_pbr_ipset_type2str(uint32_t type)
|
2018-04-23 15:17:19 +02:00
|
|
|
{
|
|
|
|
return lookup_msg(ipset_type_msg, type,
|
|
|
|
"Unrecognized IPset Type");
|
|
|
|
}
|
|
|
|
|
2018-03-24 14:55:06 +01:00
|
|
|
static int zebra_pbr_ipset_pername_walkcb(struct hash_backet *backet, void *arg)
|
|
|
|
{
|
|
|
|
struct pbr_ipset_name_lookup *pinl =
|
|
|
|
(struct pbr_ipset_name_lookup *)arg;
|
|
|
|
struct zebra_pbr_ipset *zpi = (struct zebra_pbr_ipset *)backet->data;
|
|
|
|
|
|
|
|
if (!strncmp(pinl->ipset_name, zpi->ipset_name,
|
|
|
|
ZEBRA_IPSET_NAME_SIZE)) {
|
|
|
|
pinl->ipset = zpi;
|
|
|
|
return HASHWALK_ABORT;
|
|
|
|
}
|
|
|
|
return HASHWALK_CONTINUE;
|
|
|
|
}
|
|
|
|
|
2018-03-07 13:21:14 +01:00
|
|
|
struct zebra_pbr_ipset *zebra_pbr_lookup_ipset_pername(struct zebra_ns *zns,
|
|
|
|
char *ipsetname)
|
|
|
|
{
|
2018-03-24 14:55:06 +01:00
|
|
|
struct pbr_ipset_name_lookup pinl;
|
|
|
|
struct pbr_ipset_name_lookup *ptr = &pinl;
|
|
|
|
|
2018-03-07 13:21:14 +01:00
|
|
|
if (!ipsetname)
|
|
|
|
return NULL;
|
2018-03-24 14:55:06 +01:00
|
|
|
memset(ptr, 0, sizeof(struct pbr_ipset_name_lookup));
|
|
|
|
snprintf((char *)ptr->ipset_name, ZEBRA_IPSET_NAME_SIZE, "%s",
|
|
|
|
ipsetname);
|
|
|
|
hash_walk(zns->ipset_hash, zebra_pbr_ipset_pername_walkcb, ptr);
|
|
|
|
return ptr->ipset;
|
2018-03-07 13:21:14 +01:00
|
|
|
}
|
|
|
|
|
2018-03-07 12:54:16 +01:00
|
|
|
static void *pbr_ipset_entry_alloc_intern(void *arg)
|
|
|
|
{
|
|
|
|
struct zebra_pbr_ipset_entry *zpi;
|
|
|
|
struct zebra_pbr_ipset_entry *new;
|
|
|
|
|
|
|
|
zpi = (struct zebra_pbr_ipset_entry *)arg;
|
|
|
|
|
|
|
|
new = XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_ipset_entry));
|
|
|
|
|
|
|
|
memcpy(new, zpi, sizeof(*zpi));
|
|
|
|
|
|
|
|
return new;
|
|
|
|
}
|
|
|
|
|
|
|
|
void zebra_pbr_add_ipset_entry(struct zebra_ns *zns,
|
|
|
|
struct zebra_pbr_ipset_entry *ipset)
|
|
|
|
{
|
2018-05-04 13:57:31 +02:00
|
|
|
int ret;
|
|
|
|
|
2018-03-07 12:54:16 +01:00
|
|
|
(void)hash_get(zns->ipset_entry_hash, ipset,
|
|
|
|
pbr_ipset_entry_alloc_intern);
|
2018-05-04 13:57:31 +02:00
|
|
|
ret = hook_call(zebra_pbr_ipset_entry_wrap_script_update,
|
|
|
|
zns, 1, ipset);
|
|
|
|
kernel_pbr_ipset_entry_add_del_status(ipset,
|
2018-05-25 16:37:48 +02:00
|
|
|
ret ? DP_INSTALL_SUCCESS
|
|
|
|
: DP_INSTALL_FAILURE);
|
2018-03-07 12:54:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void zebra_pbr_del_ipset_entry(struct zebra_ns *zns,
|
|
|
|
struct zebra_pbr_ipset_entry *ipset)
|
|
|
|
{
|
|
|
|
struct zebra_pbr_ipset_entry *lookup;
|
|
|
|
|
2018-03-07 15:46:00 +01:00
|
|
|
lookup = hash_lookup(zns->ipset_entry_hash, ipset);
|
2018-05-04 13:57:31 +02:00
|
|
|
hook_call(zebra_pbr_ipset_entry_wrap_script_update,
|
|
|
|
zns, 0, ipset);
|
2018-04-26 13:31:16 +02:00
|
|
|
if (lookup) {
|
|
|
|
hash_release(zns->ipset_entry_hash, lookup);
|
2018-03-07 12:54:16 +01:00
|
|
|
XFREE(MTYPE_TMP, lookup);
|
2018-04-26 13:31:16 +02:00
|
|
|
} else
|
2018-03-07 12:54:16 +01:00
|
|
|
zlog_warn("%s: IPSet being deleted we know nothing about",
|
|
|
|
__PRETTY_FUNCTION__);
|
|
|
|
}
|
|
|
|
|
2018-03-12 09:23:48 +01:00
|
|
|
static void *pbr_iptable_alloc_intern(void *arg)
|
|
|
|
{
|
|
|
|
struct zebra_pbr_iptable *zpi;
|
|
|
|
struct zebra_pbr_iptable *new;
|
|
|
|
|
|
|
|
zpi = (struct zebra_pbr_iptable *)arg;
|
|
|
|
|
|
|
|
new = XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_iptable));
|
|
|
|
|
|
|
|
memcpy(new, zpi, sizeof(*zpi));
|
|
|
|
|
|
|
|
return new;
|
|
|
|
}
|
|
|
|
|
|
|
|
void zebra_pbr_add_iptable(struct zebra_ns *zns,
|
|
|
|
struct zebra_pbr_iptable *iptable)
|
|
|
|
{
|
2018-05-04 13:57:31 +02:00
|
|
|
int ret;
|
|
|
|
|
2018-03-12 09:23:48 +01:00
|
|
|
(void)hash_get(zns->iptable_hash, iptable,
|
|
|
|
pbr_iptable_alloc_intern);
|
2018-05-04 13:57:31 +02:00
|
|
|
ret = hook_call(zebra_pbr_iptable_wrap_script_update, zns, 1, iptable);
|
|
|
|
kernel_pbr_iptable_add_del_status(iptable,
|
2018-05-25 16:37:48 +02:00
|
|
|
ret ? DP_INSTALL_SUCCESS
|
|
|
|
: DP_INSTALL_FAILURE);
|
2018-03-12 09:23:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void zebra_pbr_del_iptable(struct zebra_ns *zns,
|
|
|
|
struct zebra_pbr_iptable *iptable)
|
|
|
|
{
|
2018-04-25 18:34:27 +02:00
|
|
|
struct zebra_pbr_iptable *lookup;
|
2018-03-12 09:23:48 +01:00
|
|
|
|
|
|
|
lookup = hash_lookup(zns->iptable_hash, iptable);
|
2018-05-04 13:57:31 +02:00
|
|
|
hook_call(zebra_pbr_iptable_wrap_script_update, zns, 0, iptable);
|
2018-04-25 18:34:27 +02:00
|
|
|
if (lookup) {
|
|
|
|
struct listnode *node, *nnode;
|
|
|
|
char *name;
|
|
|
|
|
|
|
|
hash_release(zns->iptable_hash, lookup);
|
|
|
|
for (ALL_LIST_ELEMENTS(iptable->interface_name_list,
|
|
|
|
node, nnode, name)) {
|
|
|
|
XFREE(MTYPE_PBR_IPTABLE_IFNAME, name);
|
|
|
|
list_delete_node(iptable->interface_name_list,
|
|
|
|
node);
|
|
|
|
}
|
2018-03-12 09:23:48 +01:00
|
|
|
XFREE(MTYPE_TMP, lookup);
|
2018-04-25 18:34:27 +02:00
|
|
|
} else
|
2018-03-12 09:23:48 +01:00
|
|
|
zlog_warn("%s: IPTable being deleted we know nothing about",
|
|
|
|
__PRETTY_FUNCTION__);
|
|
|
|
}
|
|
|
|
|
2018-02-04 13:33:33 +01:00
|
|
|
/*
|
|
|
|
* Handle success or failure of rule (un)install in the kernel.
|
|
|
|
*/
|
|
|
|
void kernel_pbr_rule_add_del_status(struct zebra_pbr_rule *rule,
|
2018-05-25 16:37:48 +02:00
|
|
|
enum dp_results res)
|
2018-02-04 13:33:33 +01:00
|
|
|
{
|
2018-02-23 19:48:06 +01:00
|
|
|
switch (res) {
|
2018-05-25 16:37:48 +02:00
|
|
|
case DP_INSTALL_SUCCESS:
|
2018-02-23 19:48:06 +01:00
|
|
|
zsend_rule_notify_owner(rule, ZAPI_RULE_INSTALLED);
|
|
|
|
break;
|
2018-05-25 16:37:48 +02:00
|
|
|
case DP_INSTALL_FAILURE:
|
2018-02-23 19:48:06 +01:00
|
|
|
zsend_rule_notify_owner(rule, ZAPI_RULE_FAIL_INSTALL);
|
|
|
|
break;
|
2018-05-25 16:37:48 +02:00
|
|
|
case DP_DELETE_SUCCESS:
|
2018-04-09 15:41:08 +02:00
|
|
|
zsend_rule_notify_owner(rule, ZAPI_RULE_REMOVED);
|
2018-02-23 19:48:06 +01:00
|
|
|
break;
|
2018-05-25 16:37:48 +02:00
|
|
|
case DP_DELETE_FAILURE:
|
2018-05-18 16:22:23 +02:00
|
|
|
zsend_rule_notify_owner(rule, ZAPI_RULE_FAIL_REMOVE);
|
2018-02-23 19:48:06 +01:00
|
|
|
break;
|
|
|
|
}
|
2018-02-04 13:33:33 +01:00
|
|
|
}
|
|
|
|
|
2018-03-07 15:46:00 +01:00
|
|
|
/*
|
|
|
|
* Handle success or failure of ipset (un)install in the kernel.
|
|
|
|
*/
|
|
|
|
void kernel_pbr_ipset_add_del_status(struct zebra_pbr_ipset *ipset,
|
2018-05-25 16:37:48 +02:00
|
|
|
enum dp_results res)
|
2018-03-07 15:46:00 +01:00
|
|
|
{
|
|
|
|
switch (res) {
|
2018-05-25 16:37:48 +02:00
|
|
|
case DP_INSTALL_SUCCESS:
|
2018-03-07 15:46:00 +01:00
|
|
|
zsend_ipset_notify_owner(ipset, ZAPI_IPSET_INSTALLED);
|
|
|
|
break;
|
2018-05-25 16:37:48 +02:00
|
|
|
case DP_INSTALL_FAILURE:
|
2018-03-07 15:46:00 +01:00
|
|
|
zsend_ipset_notify_owner(ipset, ZAPI_IPSET_FAIL_INSTALL);
|
|
|
|
break;
|
2018-05-25 16:37:48 +02:00
|
|
|
case DP_DELETE_SUCCESS:
|
2018-04-23 15:31:04 +02:00
|
|
|
zsend_ipset_notify_owner(ipset, ZAPI_IPSET_REMOVED);
|
|
|
|
break;
|
2018-05-25 16:37:48 +02:00
|
|
|
case DP_DELETE_FAILURE:
|
2018-05-18 16:22:23 +02:00
|
|
|
zsend_ipset_notify_owner(ipset, ZAPI_IPSET_FAIL_REMOVE);
|
2018-03-07 15:46:00 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Handle success or failure of ipset (un)install in the kernel.
|
|
|
|
*/
|
|
|
|
void kernel_pbr_ipset_entry_add_del_status(
|
|
|
|
struct zebra_pbr_ipset_entry *ipset,
|
2018-05-25 16:37:48 +02:00
|
|
|
enum dp_results res)
|
2018-03-07 15:46:00 +01:00
|
|
|
{
|
|
|
|
switch (res) {
|
2018-05-25 16:37:48 +02:00
|
|
|
case DP_INSTALL_SUCCESS:
|
2018-03-07 15:46:00 +01:00
|
|
|
zsend_ipset_entry_notify_owner(ipset,
|
|
|
|
ZAPI_IPSET_ENTRY_INSTALLED);
|
|
|
|
break;
|
2018-05-25 16:37:48 +02:00
|
|
|
case DP_INSTALL_FAILURE:
|
2018-03-07 15:46:00 +01:00
|
|
|
zsend_ipset_entry_notify_owner(ipset,
|
|
|
|
ZAPI_IPSET_ENTRY_FAIL_INSTALL);
|
|
|
|
break;
|
2018-05-25 16:37:48 +02:00
|
|
|
case DP_DELETE_SUCCESS:
|
2018-04-23 15:31:04 +02:00
|
|
|
zsend_ipset_entry_notify_owner(ipset,
|
|
|
|
ZAPI_IPSET_ENTRY_REMOVED);
|
|
|
|
break;
|
2018-05-25 16:37:48 +02:00
|
|
|
case DP_DELETE_FAILURE:
|
2018-04-23 15:31:04 +02:00
|
|
|
zsend_ipset_entry_notify_owner(ipset,
|
2018-05-18 16:22:23 +02:00
|
|
|
ZAPI_IPSET_ENTRY_FAIL_REMOVE);
|
2018-03-07 15:46:00 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-12 09:23:48 +01:00
|
|
|
/*
|
|
|
|
* Handle success or failure of ipset (un)install in the kernel.
|
|
|
|
*/
|
|
|
|
void kernel_pbr_iptable_add_del_status(struct zebra_pbr_iptable *iptable,
|
2018-05-25 16:37:48 +02:00
|
|
|
enum dp_results res)
|
2018-03-12 09:23:48 +01:00
|
|
|
{
|
|
|
|
switch (res) {
|
2018-05-25 16:37:48 +02:00
|
|
|
case DP_INSTALL_SUCCESS:
|
2018-03-12 09:23:48 +01:00
|
|
|
zsend_iptable_notify_owner(iptable, ZAPI_IPTABLE_INSTALLED);
|
|
|
|
break;
|
2018-05-25 16:37:48 +02:00
|
|
|
case DP_INSTALL_FAILURE:
|
2018-03-12 09:23:48 +01:00
|
|
|
zsend_iptable_notify_owner(iptable, ZAPI_IPTABLE_FAIL_INSTALL);
|
|
|
|
break;
|
2018-05-25 16:37:48 +02:00
|
|
|
case DP_DELETE_SUCCESS:
|
2018-04-23 15:31:04 +02:00
|
|
|
zsend_iptable_notify_owner(iptable,
|
|
|
|
ZAPI_IPTABLE_REMOVED);
|
|
|
|
break;
|
2018-05-25 16:37:48 +02:00
|
|
|
case DP_DELETE_FAILURE:
|
2018-04-23 15:31:04 +02:00
|
|
|
zsend_iptable_notify_owner(iptable,
|
2018-05-18 16:22:23 +02:00
|
|
|
ZAPI_IPTABLE_FAIL_REMOVE);
|
2018-03-12 09:23:48 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-04 13:33:33 +01:00
|
|
|
/*
|
|
|
|
* Handle rule delete notification from kernel.
|
|
|
|
*/
|
2018-02-23 19:45:36 +01:00
|
|
|
int kernel_pbr_rule_del(struct zebra_pbr_rule *rule)
|
2018-02-04 13:33:33 +01:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2018-04-23 15:17:19 +02:00
|
|
|
|
|
|
|
struct zebra_pbr_ipset_entry_unique_display {
|
|
|
|
struct zebra_pbr_ipset *zpi;
|
|
|
|
struct vty *vty;
|
2018-05-04 13:57:31 +02:00
|
|
|
struct zebra_ns *zns;
|
2018-04-23 15:17:19 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
struct zebra_pbr_env_display {
|
|
|
|
struct zebra_ns *zns;
|
|
|
|
struct vty *vty;
|
|
|
|
};
|
|
|
|
|
|
|
|
static const char *zebra_pbr_prefix2str(union prefixconstptr pu,
|
|
|
|
char *str, int size)
|
|
|
|
{
|
|
|
|
const struct prefix *p = pu.p;
|
|
|
|
char buf[PREFIX2STR_BUFFER];
|
|
|
|
|
|
|
|
if (p->family == AF_INET && p->prefixlen == IPV4_MAX_PREFIXLEN) {
|
|
|
|
snprintf(str, size, "%s", inet_ntop(p->family, &p->u.prefix,
|
|
|
|
buf, PREFIX2STR_BUFFER));
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
return prefix2str(pu, str, size);
|
|
|
|
}
|
|
|
|
|
2018-03-30 13:01:39 +02:00
|
|
|
static void zebra_pbr_display_port(struct vty *vty, uint32_t filter_bm,
|
|
|
|
uint16_t port_min, uint16_t port_max,
|
|
|
|
uint8_t proto)
|
|
|
|
{
|
|
|
|
if (!(filter_bm & PBR_FILTER_PROTO)) {
|
|
|
|
if (port_max)
|
|
|
|
vty_out(vty, ":udp/tcp:%d-%d",
|
|
|
|
port_min, port_max);
|
|
|
|
else
|
|
|
|
vty_out(vty, ":udp/tcp:%d",
|
|
|
|
port_min);
|
|
|
|
} else {
|
|
|
|
if (port_max)
|
|
|
|
vty_out(vty, ":proto %d:%d-%d",
|
|
|
|
proto, port_min, port_max);
|
|
|
|
else
|
|
|
|
vty_out(vty, ":proto %d:%d",
|
|
|
|
proto, port_min);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-23 15:17:19 +02:00
|
|
|
static int zebra_pbr_show_ipset_entry_walkcb(struct hash_backet *backet,
|
|
|
|
void *arg)
|
|
|
|
{
|
|
|
|
struct zebra_pbr_ipset_entry_unique_display *unique =
|
|
|
|
(struct zebra_pbr_ipset_entry_unique_display *)arg;
|
|
|
|
struct zebra_pbr_ipset *zpi = unique->zpi;
|
|
|
|
struct vty *vty = unique->vty;
|
|
|
|
struct zebra_pbr_ipset_entry *zpie =
|
|
|
|
(struct zebra_pbr_ipset_entry *)backet->data;
|
2018-05-04 13:57:31 +02:00
|
|
|
uint64_t pkts = 0, bytes = 0;
|
|
|
|
struct zebra_ns *zns = unique->zns;
|
|
|
|
int ret = 0;
|
2018-04-23 15:17:19 +02:00
|
|
|
|
|
|
|
if (zpie->backpointer != zpi)
|
|
|
|
return HASHWALK_CONTINUE;
|
|
|
|
|
2018-03-30 13:01:39 +02:00
|
|
|
if ((zpi->type == IPSET_NET_NET) ||
|
|
|
|
(zpi->type == IPSET_NET_PORT_NET)) {
|
2018-04-23 15:17:19 +02:00
|
|
|
char buf[PREFIX_STRLEN];
|
|
|
|
|
|
|
|
zebra_pbr_prefix2str(&(zpie->src), buf, sizeof(buf));
|
|
|
|
vty_out(vty, "\tfrom %s", buf);
|
2018-03-30 13:01:39 +02:00
|
|
|
if (zpie->filter_bm & PBR_FILTER_SRC_PORT)
|
|
|
|
zebra_pbr_display_port(vty, zpie->filter_bm,
|
|
|
|
zpie->src_port_min,
|
|
|
|
zpie->src_port_max,
|
|
|
|
zpie->proto);
|
2018-04-23 15:17:19 +02:00
|
|
|
vty_out(vty, " to ");
|
|
|
|
zebra_pbr_prefix2str(&(zpie->dst), buf, sizeof(buf));
|
|
|
|
vty_out(vty, "%s", buf);
|
2018-03-30 13:01:39 +02:00
|
|
|
if (zpie->filter_bm & PBR_FILTER_DST_PORT)
|
|
|
|
zebra_pbr_display_port(vty, zpie->filter_bm,
|
|
|
|
zpie->dst_port_min,
|
|
|
|
zpie->dst_port_max,
|
|
|
|
zpie->proto);
|
|
|
|
} else if ((zpi->type == IPSET_NET) ||
|
|
|
|
(zpi->type == IPSET_NET_PORT)) {
|
2018-04-23 15:17:19 +02:00
|
|
|
char buf[PREFIX_STRLEN];
|
|
|
|
|
|
|
|
if (zpie->filter_bm & PBR_FILTER_SRC_IP) {
|
|
|
|
zebra_pbr_prefix2str(&(zpie->src), buf, sizeof(buf));
|
|
|
|
vty_out(vty, "\tfrom %s", buf);
|
|
|
|
}
|
2018-03-30 13:01:39 +02:00
|
|
|
if (zpie->filter_bm & PBR_FILTER_SRC_PORT)
|
|
|
|
zebra_pbr_display_port(vty, zpie->filter_bm,
|
|
|
|
zpie->src_port_min,
|
|
|
|
zpie->src_port_max,
|
|
|
|
zpie->proto);
|
2018-04-23 15:17:19 +02:00
|
|
|
if (zpie->filter_bm & PBR_FILTER_DST_IP) {
|
|
|
|
zebra_pbr_prefix2str(&(zpie->dst), buf, sizeof(buf));
|
|
|
|
vty_out(vty, "\tto %s", buf);
|
|
|
|
}
|
2018-03-30 13:01:39 +02:00
|
|
|
if (zpie->filter_bm & PBR_FILTER_DST_PORT)
|
|
|
|
zebra_pbr_display_port(vty, zpie->filter_bm,
|
|
|
|
zpie->dst_port_min,
|
|
|
|
zpie->dst_port_max,
|
|
|
|
zpie->proto);
|
2018-04-23 15:17:19 +02:00
|
|
|
}
|
|
|
|
vty_out(vty, " (%u)\n", zpie->unique);
|
|
|
|
|
2018-05-04 13:57:31 +02:00
|
|
|
ret = hook_call(zebra_pbr_ipset_entry_wrap_script_get_stat,
|
|
|
|
zns, zpie, &pkts, &bytes);
|
|
|
|
if (ret && pkts > 0)
|
|
|
|
vty_out(vty, "\t pkts %" PRIu64 ", bytes %" PRIu64"\n",
|
|
|
|
pkts, bytes);
|
2018-04-23 15:17:19 +02:00
|
|
|
return HASHWALK_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int zebra_pbr_show_ipset_walkcb(struct hash_backet *backet, void *arg)
|
|
|
|
{
|
|
|
|
struct zebra_pbr_env_display *uniqueipset =
|
|
|
|
(struct zebra_pbr_env_display *)arg;
|
|
|
|
struct zebra_pbr_ipset *zpi = (struct zebra_pbr_ipset *)backet->data;
|
|
|
|
struct zebra_pbr_ipset_entry_unique_display unique;
|
|
|
|
struct vty *vty = uniqueipset->vty;
|
|
|
|
struct zebra_ns *zns = uniqueipset->zns;
|
|
|
|
|
|
|
|
vty_out(vty, "IPset %s type %s\n", zpi->ipset_name,
|
|
|
|
zebra_pbr_ipset_type2str(zpi->type));
|
|
|
|
unique.vty = vty;
|
|
|
|
unique.zpi = zpi;
|
2018-05-04 13:57:31 +02:00
|
|
|
unique.zns = zns;
|
2018-04-23 15:17:19 +02:00
|
|
|
hash_walk(zns->ipset_entry_hash, zebra_pbr_show_ipset_entry_walkcb,
|
|
|
|
&unique);
|
|
|
|
vty_out(vty, "\n");
|
|
|
|
return HASHWALK_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
*/
|
|
|
|
void zebra_pbr_show_ipset_list(struct vty *vty, char *ipsetname)
|
|
|
|
{
|
|
|
|
struct zebra_pbr_ipset *zpi;
|
|
|
|
struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
|
|
|
|
struct zebra_pbr_ipset_entry_unique_display unique;
|
|
|
|
struct zebra_pbr_env_display uniqueipset;
|
|
|
|
|
|
|
|
if (ipsetname) {
|
|
|
|
zpi = zebra_pbr_lookup_ipset_pername(zns, ipsetname);
|
|
|
|
if (!zpi) {
|
|
|
|
vty_out(vty, "No IPset %s found\n", ipsetname);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
vty_out(vty, "IPset %s type %s\n", ipsetname,
|
|
|
|
zebra_pbr_ipset_type2str(zpi->type));
|
|
|
|
|
|
|
|
unique.vty = vty;
|
|
|
|
unique.zpi = zpi;
|
2018-05-04 13:57:31 +02:00
|
|
|
unique.zns = zns;
|
2018-04-23 15:17:19 +02:00
|
|
|
hash_walk(zns->ipset_entry_hash,
|
|
|
|
zebra_pbr_show_ipset_entry_walkcb,
|
|
|
|
&unique);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
uniqueipset.zns = zns;
|
|
|
|
uniqueipset.vty = vty;
|
|
|
|
hash_walk(zns->ipset_hash, zebra_pbr_show_ipset_walkcb,
|
|
|
|
&uniqueipset);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct pbr_rule_fwmark_lookup {
|
|
|
|
struct zebra_pbr_rule *ptr;
|
|
|
|
uint32_t fwmark;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int zebra_pbr_rule_lookup_fwmark_walkcb(struct hash_backet *backet,
|
|
|
|
void *arg)
|
|
|
|
{
|
|
|
|
struct pbr_rule_fwmark_lookup *iprule =
|
|
|
|
(struct pbr_rule_fwmark_lookup *)arg;
|
|
|
|
struct zebra_pbr_rule *zpr = (struct zebra_pbr_rule *)backet->data;
|
|
|
|
|
|
|
|
if (iprule->fwmark == zpr->rule.filter.fwmark) {
|
|
|
|
iprule->ptr = zpr;
|
|
|
|
return HASHWALK_ABORT;
|
|
|
|
}
|
|
|
|
return HASHWALK_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int zebra_pbr_show_iptable_walkcb(struct hash_backet *backet, void *arg)
|
|
|
|
{
|
|
|
|
struct zebra_pbr_iptable *iptable =
|
|
|
|
(struct zebra_pbr_iptable *)backet->data;
|
|
|
|
struct zebra_pbr_env_display *env = (struct zebra_pbr_env_display *)arg;
|
|
|
|
struct vty *vty = env->vty;
|
|
|
|
struct zebra_ns *zns = env->zns;
|
2018-05-04 13:57:31 +02:00
|
|
|
int ret;
|
|
|
|
uint64_t pkts = 0, bytes = 0;
|
2018-04-23 15:17:19 +02:00
|
|
|
|
|
|
|
vty_out(vty, "IPtable %s action %s (%u)\n", iptable->ipset_name,
|
|
|
|
iptable->action == ZEBRA_IPTABLES_DROP ? "drop" : "redirect",
|
|
|
|
iptable->unique);
|
|
|
|
|
2018-05-04 13:57:31 +02:00
|
|
|
ret = hook_call(zebra_pbr_iptable_wrap_script_get_stat,
|
|
|
|
zns, iptable, &pkts, &bytes);
|
|
|
|
if (ret && pkts > 0)
|
|
|
|
vty_out(vty, "\t pkts %" PRIu64 ", bytes %" PRIu64"\n",
|
|
|
|
pkts, bytes);
|
2018-04-23 15:17:19 +02:00
|
|
|
if (iptable->action != ZEBRA_IPTABLES_DROP) {
|
|
|
|
struct pbr_rule_fwmark_lookup prfl;
|
|
|
|
|
|
|
|
prfl.fwmark = iptable->fwmark;
|
|
|
|
prfl.ptr = NULL;
|
|
|
|
hash_walk(zns->rules_hash,
|
|
|
|
&zebra_pbr_rule_lookup_fwmark_walkcb, &prfl);
|
|
|
|
if (prfl.ptr) {
|
|
|
|
struct zebra_pbr_rule *zpr = prfl.ptr;
|
|
|
|
|
|
|
|
vty_out(vty, "\t table %u, fwmark %u\n",
|
|
|
|
zpr->rule.action.table,
|
|
|
|
prfl.fwmark);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return HASHWALK_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void zebra_pbr_show_iptable(struct vty *vty)
|
|
|
|
{
|
|
|
|
struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
|
|
|
|
struct zebra_pbr_env_display env;
|
|
|
|
|
|
|
|
env.vty = vty;
|
|
|
|
env.zns = zns;
|
|
|
|
|
|
|
|
hash_walk(zns->iptable_hash, zebra_pbr_show_iptable_walkcb,
|
|
|
|
&env);
|
|
|
|
}
|
2018-04-25 18:34:27 +02:00
|
|
|
|
|
|
|
void zebra_pbr_iptable_update_interfacelist(struct stream *s,
|
|
|
|
struct zebra_pbr_iptable *zpi)
|
|
|
|
{
|
|
|
|
uint32_t i = 0, index;
|
|
|
|
struct interface *ifp;
|
|
|
|
char *name;
|
|
|
|
|
|
|
|
for (i = 0; i < zpi->nb_interface; i++) {
|
|
|
|
STREAM_GETL(s, index);
|
|
|
|
ifp = if_lookup_by_index(index, zpi->vrf_id);
|
|
|
|
if (!ifp)
|
|
|
|
continue;
|
|
|
|
name = XSTRDUP(MTYPE_PBR_IPTABLE_IFNAME, ifp->name);
|
|
|
|
listnode_add(zpi->interface_name_list, name);
|
|
|
|
}
|
|
|
|
stream_failure:
|
|
|
|
return;
|
|
|
|
}
|