mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-04 02:06:12 +00:00
zebra: add IPTABLE_ADD and IPTABLE_DEL commands in zapi
Those messages permit a remote daemon to configure an iptable entry. A structure is defined that maps to an iptable entry. More specifically, this structure proposes to associate fwmark, and a table ID. Adding to the configuration, the initialisation of iptables hash list is done into zebra netnamespace. Also a hook for notifying the sender that the iptables has been correctly set is done. Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
This commit is contained in:
parent
1907e4b80b
commit
7abd6c4fa0
@ -52,6 +52,12 @@
|
||||
*/
|
||||
#define ZEBRA_IPSET_NAME_SIZE 32
|
||||
|
||||
/* IPTable action is defined by two values: either
|
||||
* forward or drop
|
||||
*/
|
||||
#define ZEBRA_IPTABLES_FORWARD 0
|
||||
#define ZEBRA_IPTABLES_DROP 1
|
||||
|
||||
extern struct sockaddr_storage zclient_addr;
|
||||
extern socklen_t zclient_addr_len;
|
||||
|
||||
@ -146,6 +152,9 @@ typedef enum {
|
||||
ZEBRA_IPSET_ENTRY_DELETE,
|
||||
ZEBRA_IPSET_NOTIFY_OWNER,
|
||||
ZEBRA_IPSET_ENTRY_NOTIFY_OWNER,
|
||||
ZEBRA_IPTABLE_ADD,
|
||||
ZEBRA_IPTABLE_DELETE,
|
||||
ZEBRA_IPTABLE_NOTIFY_OWNER,
|
||||
} zebra_message_types_t;
|
||||
|
||||
struct redist_proto {
|
||||
@ -409,6 +418,12 @@ enum zapi_ipset_entry_notify_owner {
|
||||
ZAPI_IPSET_ENTRY_REMOVED,
|
||||
};
|
||||
|
||||
enum zapi_iptable_notify_owner {
|
||||
ZAPI_IPTABLE_FAIL_INSTALL,
|
||||
ZAPI_IPTABLE_INSTALLED,
|
||||
ZAPI_IPTABLE_REMOVED,
|
||||
};
|
||||
|
||||
/* Zebra MAC types */
|
||||
#define ZEBRA_MACIP_TYPE_STICKY 0x01 /* Sticky MAC*/
|
||||
#define ZEBRA_MACIP_TYPE_GW 0x02 /* gateway (SVI) mac*/
|
||||
|
@ -148,6 +148,12 @@ int zebra_ns_enable(ns_id_t ns_id, void **info)
|
||||
hash_create_size(8, zebra_pbr_ipset_entry_hash_key,
|
||||
zebra_pbr_ipset_entry_hash_equal,
|
||||
"IPset Hash Entry");
|
||||
|
||||
zns->iptable_hash =
|
||||
hash_create_size(8, zebra_pbr_iptable_hash_key,
|
||||
zebra_pbr_iptable_hash_equal,
|
||||
"IPtable Hash Entry");
|
||||
|
||||
#if defined(HAVE_RTADV)
|
||||
rtadv_init(zns);
|
||||
#endif
|
||||
@ -261,6 +267,9 @@ int zebra_ns_disable(ns_id_t ns_id, void **info)
|
||||
hash_clean(zns->ipset_entry_hash,
|
||||
zebra_pbr_ipset_entry_free),
|
||||
hash_free(zns->ipset_entry_hash);
|
||||
hash_clean(zns->iptable_hash,
|
||||
zebra_pbr_iptable_free);
|
||||
hash_free(zns->iptable_hash);
|
||||
|
||||
while (!RB_EMPTY(zebra_ns_table_head, &zns->ns_tables)) {
|
||||
znst = RB_ROOT(zebra_ns_table_head, &zns->ns_tables);
|
||||
|
@ -77,6 +77,8 @@ struct zebra_ns {
|
||||
|
||||
struct hash *ipset_entry_hash;
|
||||
|
||||
struct hash *iptable_hash;
|
||||
|
||||
/* Back pointer */
|
||||
struct ns *ns;
|
||||
};
|
||||
|
@ -211,6 +211,51 @@ int zebra_pbr_ipset_entry_hash_equal(const void *arg1, const void *arg2)
|
||||
return 1;
|
||||
}
|
||||
|
||||
void zebra_pbr_iptable_free(void *arg)
|
||||
{
|
||||
struct zebra_pbr_iptable *iptable;
|
||||
|
||||
iptable = (struct zebra_pbr_iptable *)arg;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static void *pbr_rule_alloc_intern(void *arg)
|
||||
{
|
||||
struct zebra_pbr_rule *zpr;
|
||||
@ -383,6 +428,45 @@ void zebra_pbr_del_ipset_entry(struct zebra_ns *zns,
|
||||
__PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
(void)hash_get(zns->iptable_hash, iptable,
|
||||
pbr_iptable_alloc_intern);
|
||||
/* TODO call netlink layer */
|
||||
}
|
||||
|
||||
void zebra_pbr_del_iptable(struct zebra_ns *zns,
|
||||
struct zebra_pbr_iptable *iptable)
|
||||
{
|
||||
struct zebra_pbr_ipset_entry *lookup;
|
||||
|
||||
lookup = hash_lookup(zns->iptable_hash, iptable);
|
||||
/* TODO:
|
||||
* - call netlink layer
|
||||
* - detach from iptable list
|
||||
*/
|
||||
if (lookup)
|
||||
XFREE(MTYPE_TMP, lookup);
|
||||
else
|
||||
zlog_warn("%s: IPTable being deleted we know nothing about",
|
||||
__PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle success or failure of rule (un)install in the kernel.
|
||||
*/
|
||||
@ -446,6 +530,26 @@ void kernel_pbr_ipset_entry_add_del_status(
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle success or failure of ipset (un)install in the kernel.
|
||||
*/
|
||||
void kernel_pbr_iptable_add_del_status(struct zebra_pbr_iptable *iptable,
|
||||
enum southbound_results res)
|
||||
{
|
||||
switch (res) {
|
||||
case SOUTHBOUND_INSTALL_SUCCESS:
|
||||
zsend_iptable_notify_owner(iptable, ZAPI_IPTABLE_INSTALLED);
|
||||
break;
|
||||
case SOUTHBOUND_INSTALL_FAILURE:
|
||||
zsend_iptable_notify_owner(iptable, ZAPI_IPTABLE_FAIL_INSTALL);
|
||||
break;
|
||||
case SOUTHBOUND_DELETE_SUCCESS:
|
||||
case SOUTHBOUND_DELETE_FAILURE:
|
||||
/* TODO : handling of delete event */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle rule delete notification from kernel.
|
||||
*/
|
||||
|
@ -148,6 +148,35 @@ struct zebra_pbr_ipset_entry {
|
||||
struct zebra_pbr_ipset *backpointer;
|
||||
};
|
||||
|
||||
/*
|
||||
* An IPTables Action
|
||||
*
|
||||
* This is a filter mapped on ipset entries
|
||||
*/
|
||||
struct zebra_pbr_iptable {
|
||||
/*
|
||||
* Originating zclient sock fd, so we can know who to send
|
||||
* back to.
|
||||
*/
|
||||
int sock;
|
||||
|
||||
uint32_t unique;
|
||||
|
||||
/* include ipset type
|
||||
*/
|
||||
uint32_t type;
|
||||
|
||||
/* include which IP is to be filtered
|
||||
*/
|
||||
uint32_t filter_bm;
|
||||
|
||||
uint32_t fwmark;
|
||||
|
||||
uint32_t action;
|
||||
|
||||
char ipset_name[ZEBRA_IPSET_NAME_SIZE];
|
||||
};
|
||||
|
||||
void zebra_pbr_add_rule(struct zebra_ns *zns, struct zebra_pbr_rule *rule);
|
||||
void zebra_pbr_del_rule(struct zebra_ns *zns, struct zebra_pbr_rule *rule);
|
||||
void zebra_pbr_create_ipset(struct zebra_ns *zns,
|
||||
@ -161,6 +190,11 @@ void zebra_pbr_add_ipset_entry(struct zebra_ns *zns,
|
||||
void zebra_pbr_del_ipset_entry(struct zebra_ns *zns,
|
||||
struct zebra_pbr_ipset_entry *ipset);
|
||||
|
||||
void zebra_pbr_add_iptable(struct zebra_ns *zns,
|
||||
struct zebra_pbr_iptable *iptable);
|
||||
void zebra_pbr_del_iptable(struct zebra_ns *zns,
|
||||
struct zebra_pbr_iptable *iptable);
|
||||
|
||||
/*
|
||||
* Install specified rule for a specific interface.
|
||||
* It is possible that the user-defined sequence number and the one in the
|
||||
@ -196,6 +230,9 @@ extern void kernel_pbr_ipset_entry_add_del_status(
|
||||
struct zebra_pbr_ipset_entry *ipset,
|
||||
enum southbound_results res);
|
||||
|
||||
extern void kernel_pbr_iptable_add_del_status(struct zebra_pbr_iptable *iptable,
|
||||
enum southbound_results res);
|
||||
|
||||
/*
|
||||
* Handle rule delete notification from kernel.
|
||||
*/
|
||||
@ -220,4 +257,8 @@ extern void zebra_pbr_ipset_entry_free(void *arg);
|
||||
extern uint32_t zebra_pbr_ipset_entry_hash_key(void *arg);
|
||||
extern int zebra_pbr_ipset_entry_hash_equal(const void *arg1, const void *arg2);
|
||||
|
||||
extern void zebra_pbr_iptable_free(void *arg);
|
||||
extern uint32_t zebra_pbr_iptable_hash_key(void *arg);
|
||||
extern int zebra_pbr_iptable_hash_equal(const void *arg1, const void *arg2);
|
||||
|
||||
#endif /* _ZEBRA_PBR_H */
|
||||
|
@ -817,6 +817,35 @@ void zsend_ipset_entry_notify_owner(
|
||||
zebra_server_send_message(client, s);
|
||||
}
|
||||
|
||||
void zsend_iptable_notify_owner(struct zebra_pbr_iptable *iptable,
|
||||
enum zapi_iptable_notify_owner note)
|
||||
{
|
||||
struct listnode *node;
|
||||
struct zserv *client;
|
||||
struct stream *s;
|
||||
|
||||
if (IS_ZEBRA_DEBUG_PACKET)
|
||||
zlog_debug("%s: Notifying %u", __PRETTY_FUNCTION__,
|
||||
iptable->unique);
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) {
|
||||
if (iptable->sock == client->sock)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!client)
|
||||
return;
|
||||
|
||||
s = stream_new(ZEBRA_MAX_PACKET_SIZ);
|
||||
|
||||
zclient_create_header(s, ZEBRA_IPTABLE_NOTIFY_OWNER, VRF_DEFAULT);
|
||||
stream_put(s, ¬e, sizeof(note));
|
||||
stream_putl(s, iptable->unique);
|
||||
stream_putw_at(s, 0, stream_get_endp(s));
|
||||
|
||||
zebra_server_send_message(client, s);
|
||||
}
|
||||
|
||||
/* Router-id is updated. Send ZEBRA_ROUTER_ID_ADD to client. */
|
||||
int zsend_router_id_update(struct zserv *client, struct prefix *p,
|
||||
vrf_id_t vrf_id)
|
||||
@ -2854,6 +2883,31 @@ stream_failure:
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void zread_iptable(ZAPI_HANDLER_ARGS)
|
||||
{
|
||||
struct zebra_pbr_iptable zpi;
|
||||
struct stream *s;
|
||||
|
||||
s = msg;
|
||||
|
||||
memset(&zpi, 0, sizeof(zpi));
|
||||
|
||||
zpi.sock = client->sock;
|
||||
STREAM_GETL(s, zpi.unique);
|
||||
STREAM_GETL(s, zpi.type);
|
||||
STREAM_GETL(s, zpi.filter_bm);
|
||||
STREAM_GETL(s, zpi.action);
|
||||
STREAM_GETL(s, zpi.fwmark);
|
||||
STREAM_GET(&zpi.ipset_name, s,
|
||||
ZEBRA_IPSET_NAME_SIZE);
|
||||
|
||||
if (hdr->command == ZEBRA_IPTABLE_ADD)
|
||||
zebra_pbr_add_iptable(zvrf->zns, &zpi);
|
||||
else
|
||||
zebra_pbr_del_iptable(zvrf->zns, &zpi);
|
||||
stream_failure:
|
||||
return;
|
||||
}
|
||||
|
||||
void (*zserv_handlers[])(ZAPI_HANDLER_ARGS) = {
|
||||
[ZEBRA_ROUTER_ID_ADD] = zread_router_id_add,
|
||||
@ -2919,6 +2973,8 @@ void (*zserv_handlers[])(ZAPI_HANDLER_ARGS) = {
|
||||
[ZEBRA_IPSET_DESTROY] = zread_ipset,
|
||||
[ZEBRA_IPSET_ENTRY_ADD] = zread_ipset_entry,
|
||||
[ZEBRA_IPSET_ENTRY_DELETE] = zread_ipset_entry,
|
||||
[ZEBRA_IPTABLE_ADD] = zread_iptable,
|
||||
[ZEBRA_IPTABLE_DELETE] = zread_iptable,
|
||||
};
|
||||
|
||||
static inline void zserv_handle_commands(struct zserv *client,
|
||||
|
@ -190,6 +190,7 @@ extern int zsend_route_notify_owner(struct route_entry *re, struct prefix *p,
|
||||
struct zebra_pbr_rule;
|
||||
struct zebra_pbr_ipset;
|
||||
struct zebra_pbr_ipset_entry;
|
||||
struct zebra_pbr_iptable;
|
||||
extern void zsend_rule_notify_owner(struct zebra_pbr_rule *rule,
|
||||
enum zapi_rule_notify_owner note);
|
||||
extern void zsend_ipset_notify_owner(
|
||||
@ -198,6 +199,9 @@ extern void zsend_ipset_notify_owner(
|
||||
extern void zsend_ipset_entry_notify_owner(
|
||||
struct zebra_pbr_ipset_entry *ipset,
|
||||
enum zapi_ipset_entry_notify_owner note);
|
||||
extern void zsend_iptable_notify_owner(
|
||||
struct zebra_pbr_iptable *iptable,
|
||||
enum zapi_iptable_notify_owner note);
|
||||
|
||||
extern void zserv_nexthop_num_warn(const char *, const struct prefix *,
|
||||
const unsigned int);
|
||||
|
Loading…
Reference in New Issue
Block a user