diff options
author | Philippe Guibert <philippe.guibert@6wind.com> | 2018-03-12 09:23:48 +0100 |
---|---|---|
committer | Philippe Guibert <philippe.guibert@6wind.com> | 2018-04-16 14:40:43 +0200 |
commit | 7abd6c4fa0331bc6a416c69080218457f9efc90f (patch) | |
tree | d6e0fdfceebd71c106b608fc66d9b24df40c3228 | |
parent | zebra: pbr rule structure is being added fwmark tag (diff) | |
download | frr-7abd6c4fa0331bc6a416c69080218457f9efc90f.tar.xz frr-7abd6c4fa0331bc6a416c69080218457f9efc90f.zip |
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>
-rw-r--r-- | lib/zclient.h | 15 | ||||
-rw-r--r-- | zebra/zebra_ns.c | 9 | ||||
-rw-r--r-- | zebra/zebra_ns.h | 2 | ||||
-rw-r--r-- | zebra/zebra_pbr.c | 104 | ||||
-rw-r--r-- | zebra/zebra_pbr.h | 41 | ||||
-rw-r--r-- | zebra/zserv.c | 56 | ||||
-rw-r--r-- | zebra/zserv.h | 4 |
7 files changed, 231 insertions, 0 deletions
diff --git a/lib/zclient.h b/lib/zclient.h index b8896f6b9..2cdcefd5e 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -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*/ diff --git a/zebra/zebra_ns.c b/zebra/zebra_ns.c index f2a459cbb..5c62e366a 100644 --- a/zebra/zebra_ns.c +++ b/zebra/zebra_ns.c @@ -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); diff --git a/zebra/zebra_ns.h b/zebra/zebra_ns.h index c37010105..fbf88ae6e 100644 --- a/zebra/zebra_ns.h +++ b/zebra/zebra_ns.h @@ -77,6 +77,8 @@ struct zebra_ns { struct hash *ipset_entry_hash; + struct hash *iptable_hash; + /* Back pointer */ struct ns *ns; }; diff --git a/zebra/zebra_pbr.c b/zebra/zebra_pbr.c index dd6e16bb7..42b3f37da 100644 --- a/zebra/zebra_pbr.c +++ b/zebra/zebra_pbr.c @@ -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. */ @@ -447,6 +531,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. */ int kernel_pbr_rule_del(struct zebra_pbr_rule *rule) diff --git a/zebra/zebra_pbr.h b/zebra/zebra_pbr.h index 9f25c6f43..6de33ee2e 100644 --- a/zebra/zebra_pbr.h +++ b/zebra/zebra_pbr.h @@ -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 */ diff --git a/zebra/zserv.c b/zebra/zserv.c index 4d9898ae2..b7bce1f56 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -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, diff --git a/zebra/zserv.h b/zebra/zserv.h index e66c1811c..f68e87956 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -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); |