mirror of
				https://gitea.osmocom.org/cellular-infrastructure/osmo-upf.git
				synced 2025-11-03 21:43:34 +00:00 
			
		
		
		
	tunmap: refactor nft ruleset: fix "martians" and "1024"
Take care of two problems: - limitation of <= 1024 base chains in nftables, so far meaning we can establish at most 1024 GTP tunnel mappings. - mangling of source IP in prerouting so far meaning that the system needs to be configured to permit 'martian' packets The new ruleset separates in pre- and post-routing, so that we set a new destination IP address in pre-routing, and set a new source IP address in post-routing. Hence no problem with martian packet rejection. The new ruleset uses verdict maps, which are more efficient, and do not hit a limit of 1024 as base chains do. Before, the nft rule used one chain id. In the new ruleset, each tunmap now needs two distinct chain ids. Refactor. Related: SYS#6327 SYS#6264 Change-Id: Iccb975a1c0f8a2087f7b7dc4942a6b41f5675a13
This commit is contained in:
		@@ -110,8 +110,9 @@ struct g_upf {
 | 
			
		||||
 | 
			
		||||
		struct nft_ctx *nft_ctx;
 | 
			
		||||
		char *table_name;
 | 
			
		||||
		int priority;
 | 
			
		||||
		uint32_t next_id_state;
 | 
			
		||||
		int priority_pre;
 | 
			
		||||
		int priority_post;
 | 
			
		||||
		uint32_t next_chain_id_state;
 | 
			
		||||
	} nft;
 | 
			
		||||
 | 
			
		||||
	struct llist_head netinst;
 | 
			
		||||
 
 | 
			
		||||
@@ -27,28 +27,32 @@
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/socket.h>
 | 
			
		||||
 | 
			
		||||
#define NFT_CHAIN_NAME_PREFIX_TUNMAP "tunmap"
 | 
			
		||||
 | 
			
		||||
struct upf_nft_tunmap_desc {
 | 
			
		||||
	struct {
 | 
			
		||||
		struct osmo_sockaddr gtp_local_addr;
 | 
			
		||||
		uint32_t local_teid;
 | 
			
		||||
		struct osmo_sockaddr gtp_remote_addr;
 | 
			
		||||
		uint32_t remote_teid;
 | 
			
		||||
		uint32_t chain_id;
 | 
			
		||||
	} access;
 | 
			
		||||
	struct {
 | 
			
		||||
		struct osmo_sockaddr gtp_local_addr;
 | 
			
		||||
		uint32_t local_teid;
 | 
			
		||||
		struct osmo_sockaddr gtp_remote_addr;
 | 
			
		||||
		uint32_t remote_teid;
 | 
			
		||||
		uint32_t chain_id;
 | 
			
		||||
	} core;
 | 
			
		||||
	/* id as in ruleset name 'tunmap<id>'. If zero, no id has been assigned yet. */
 | 
			
		||||
	uint32_t id;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int upf_nft_tunmap_to_str_buf(char *buf, size_t buflen, const struct upf_nft_tunmap_desc *tunmap);
 | 
			
		||||
char *upf_nft_tunmap_to_str_c(void *ctx, const struct upf_nft_tunmap_desc *tunmap);
 | 
			
		||||
 | 
			
		||||
int upf_nft_init();
 | 
			
		||||
int upf_nft_free();
 | 
			
		||||
 | 
			
		||||
char *upf_nft_tunmap_get_table_init_str(void *ctx);
 | 
			
		||||
char *upf_nft_tunmap_get_vmap_init_str(void *ctx);
 | 
			
		||||
char *upf_nft_tunmap_get_ruleset_str(void *ctx, struct upf_nft_tunmap_desc *tunmap);
 | 
			
		||||
char *upf_nft_tunmap_get_ruleset_del_str(void *ctx, struct upf_nft_tunmap_desc *tunmap);
 | 
			
		||||
int upf_nft_tunmap_create(struct upf_nft_tunmap_desc *tunmap);
 | 
			
		||||
int upf_nft_tunmap_delete(struct upf_nft_tunmap_desc *tunmap);
 | 
			
		||||
 
 | 
			
		||||
@@ -107,11 +107,11 @@ static int up_gtp_action_enable_disable(struct up_gtp_action *a, bool enable)
 | 
			
		||||
		else
 | 
			
		||||
			rc = upf_gtp_dev_tunend_del(gtp_dev, &a->tunend);
 | 
			
		||||
		if (rc) {
 | 
			
		||||
			LOG_UP_GTP_ACTION(a, LOGL_ERROR, "Failed to %s GTP tunnel: %d %s\n",
 | 
			
		||||
					  enable ? "enable" : "disable", rc, strerror(-rc));
 | 
			
		||||
			LOG_UP_GTP_ACTION(a, LOGL_ERROR, "Failed to %s GTP tunnel (rc=%d)\n",
 | 
			
		||||
					  enable ? "enable" : "disable", rc);
 | 
			
		||||
			return rc;
 | 
			
		||||
		}
 | 
			
		||||
		LOG_UP_GTP_ACTION(a, LOGL_NOTICE, "%s GTP tunnel on dev %s\n", enable ? "Enabled" : "Disabled",
 | 
			
		||||
		LOG_UP_GTP_ACTION(a, LOGL_NOTICE, "%s tunend on dev %s\n", enable ? "Enabled" : "Disabled",
 | 
			
		||||
				  gtp_dev->name);
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
@@ -122,32 +122,18 @@ static int up_gtp_action_enable_disable(struct up_gtp_action *a, bool enable)
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (enable && a->tunmap.id != 0) {
 | 
			
		||||
			LOG_UP_GTP_ACTION(a, LOGL_ERROR,
 | 
			
		||||
					  "Cannot enable: nft GTP tunnel mapping rule has been enabled before"
 | 
			
		||||
					  " as nft rule id %u\n", a->tunmap.id);
 | 
			
		||||
			return -EALREADY;
 | 
			
		||||
		}
 | 
			
		||||
		if (!enable && a->tunmap.id == 0) {
 | 
			
		||||
			LOG_UP_GTP_ACTION(a, LOGL_ERROR,
 | 
			
		||||
					  "Cannot disable: nft GTP tunnel mapping rule has not been enabled"
 | 
			
		||||
					  " (no nft rule id)\n");
 | 
			
		||||
			return -ENOENT;
 | 
			
		||||
		}
 | 
			
		||||
		if (enable)
 | 
			
		||||
			rc = upf_nft_tunmap_create(&a->tunmap);
 | 
			
		||||
		else
 | 
			
		||||
			rc = upf_nft_tunmap_delete(&a->tunmap);
 | 
			
		||||
		if (rc) {
 | 
			
		||||
			LOG_UP_GTP_ACTION(a, LOGL_ERROR,
 | 
			
		||||
					  "Failed to %s nft GTP tunnel mapping %u:"
 | 
			
		||||
					  " %d %s\n", enable ? "enable" : "disable", a->tunmap.id, rc, strerror(-rc));
 | 
			
		||||
			LOG_UP_GTP_ACTION(a, LOGL_ERROR, "Failed to %s nft GTP tunnel mapping (rc=%d)\n",
 | 
			
		||||
					  enable ? "enable" : "disable", rc);
 | 
			
		||||
			return rc;
 | 
			
		||||
		}
 | 
			
		||||
		LOG_UP_GTP_ACTION(a, LOGL_NOTICE, "%s nft GTP tunnel mapping %u\n",
 | 
			
		||||
				  enable ? "Enabled" : "Disabled", a->tunmap.id);
 | 
			
		||||
		if (!enable)
 | 
			
		||||
			a->tunmap.id = 0;
 | 
			
		||||
		LOG_UP_GTP_ACTION(a, LOGL_NOTICE, "%s tunmap, nft chain IDs: access--%u-> <-%u--core\n",
 | 
			
		||||
				  enable ? "Enabled" : "Disabled",
 | 
			
		||||
				  a->tunmap.access.chain_id, a->tunmap.core.chain_id);
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
 
 | 
			
		||||
@@ -51,7 +51,8 @@ void g_upf_alloc(void *ctx)
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		.nft = {
 | 
			
		||||
			.priority = -300,
 | 
			
		||||
			.priority_pre = -300,
 | 
			
		||||
			.priority_post = 400,
 | 
			
		||||
		},
 | 
			
		||||
		.gtp = {
 | 
			
		||||
			/* TODO: recovery count state file; use lower byte of current time, poor person's random. */
 | 
			
		||||
 
 | 
			
		||||
@@ -35,6 +35,30 @@ static char *upf_nft_ruleset_table_create(void *ctx, const char *table_name)
 | 
			
		||||
	return talloc_asprintf(ctx, "add table inet %s\n", table_name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *upf_nft_ruleset_vmap_init(void *ctx, const char *table_name, int priority_pre, int priority_post)
 | 
			
		||||
{
 | 
			
		||||
	/* add chain inet osmo-upf pre { type filter hook prerouting priority -300; policy accept; }
 | 
			
		||||
	 * add chain inet osmo-upf post { type filter hook postrouting priority 400; policy accept; }
 | 
			
		||||
	 * add map inet osmo-upf tunmap-pre { typeof ip daddr . @ih,32,32 : verdict; }
 | 
			
		||||
	 * add map inet osmo-upf tunmap-post { typeof meta mark : verdict; }
 | 
			
		||||
	 * add rule inet osmo-upf pre udp dport 2152 ip daddr . @ih,32,32 vmap @tunmap-pre
 | 
			
		||||
	 * add rule inet osmo-upf post meta mark vmap @tunmap-post
 | 
			
		||||
	 */
 | 
			
		||||
	return talloc_asprintf(ctx,
 | 
			
		||||
		"add chain inet %s pre { type filter hook prerouting priority %d; policy accept; };\n"
 | 
			
		||||
		"add chain inet %s post { type filter hook postrouting priority %d; policy accept; };\n"
 | 
			
		||||
		"add map inet %s tunmap-pre { typeof ip daddr . @ih,32,32 : verdict; };\n"
 | 
			
		||||
		"add map inet %s tunmap-post { typeof meta mark : verdict; };\n"
 | 
			
		||||
		"add rule inet %s pre udp dport %u ip daddr . @ih,32,32 vmap @tunmap-pre;\n"
 | 
			
		||||
		"add rule inet %s post meta mark vmap @tunmap-post;\n",
 | 
			
		||||
		table_name, priority_pre,
 | 
			
		||||
		table_name, priority_post,
 | 
			
		||||
		table_name,
 | 
			
		||||
		table_name,
 | 
			
		||||
		table_name, PORT_GTP1_U,
 | 
			
		||||
		table_name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int upf_nft_run(const char *ruleset)
 | 
			
		||||
{
 | 
			
		||||
	int rc;
 | 
			
		||||
@@ -82,13 +106,19 @@ int upf_nft_init()
 | 
			
		||||
		return -EIO;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rc = upf_nft_run(upf_nft_ruleset_table_create(OTC_SELECT, g_upf->nft.table_name));
 | 
			
		||||
	rc = upf_nft_run(upf_nft_tunmap_get_table_init_str(OTC_SELECT));
 | 
			
		||||
	if (rc) {
 | 
			
		||||
		LOGP(DNFT, LOGL_ERROR, "Failed to create nft table %s\n",
 | 
			
		||||
		     osmo_quote_str_c(OTC_SELECT, g_upf->nft.table_name, -1));
 | 
			
		||||
		return rc;
 | 
			
		||||
	}
 | 
			
		||||
	LOGP(DNFT, LOGL_NOTICE, "Created nft table %s\n", osmo_quote_str_c(OTC_SELECT, g_upf->nft.table_name, -1));
 | 
			
		||||
 | 
			
		||||
	rc = upf_nft_run(upf_nft_tunmap_get_vmap_init_str(OTC_SELECT));
 | 
			
		||||
	if (rc) {
 | 
			
		||||
		LOGP(DNFT, LOGL_ERROR, "Failed to initialize nft verdict map in table %s\n", g_upf->nft.table_name);
 | 
			
		||||
		return rc;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -110,53 +140,112 @@ struct upf_nft_args_peer {
 | 
			
		||||
	const struct osmo_sockaddr *addr_local;
 | 
			
		||||
	/* The TEID that the peer sends to us in GTP packets. */
 | 
			
		||||
	uint32_t teid_local;
 | 
			
		||||
	/* The nft chain id that forwards packets received on addr_local,teid_local. Also used for the 'mark' id in
 | 
			
		||||
	 * the verdict map ruleset. */
 | 
			
		||||
	uint32_t chain_id;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct upf_nft_args {
 | 
			
		||||
	/* global table name */
 | 
			
		||||
	const char *table_name;
 | 
			
		||||
	/* chain name for this specific tunnel mapping */
 | 
			
		||||
	uint32_t chain_id;
 | 
			
		||||
	int priority;
 | 
			
		||||
 | 
			
		||||
	struct upf_nft_args_peer peer_a;
 | 
			
		||||
	struct upf_nft_args_peer peer_b;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int tunmap_single_direction(char *buf, size_t buflen,
 | 
			
		||||
static int tunmap_add_single_direction(char *buf, size_t buflen,
 | 
			
		||||
				       const struct upf_nft_args *args,
 | 
			
		||||
				   const struct upf_nft_args_peer *from_peer,
 | 
			
		||||
				   const struct upf_nft_args_peer *to_peer)
 | 
			
		||||
				       bool dir_a2b)
 | 
			
		||||
{
 | 
			
		||||
	struct osmo_strbuf sb = { .buf = buf, .len = buflen };
 | 
			
		||||
	const struct upf_nft_args_peer *from_peer;
 | 
			
		||||
	const struct upf_nft_args_peer *to_peer;
 | 
			
		||||
 | 
			
		||||
	OSMO_STRBUF_PRINTF(sb, "add rule inet %s " NFT_CHAIN_NAME_PREFIX_TUNMAP "%u", args->table_name, args->chain_id);
 | 
			
		||||
	if (dir_a2b) {
 | 
			
		||||
		from_peer = &args->peer_a;
 | 
			
		||||
		to_peer = &args->peer_b;
 | 
			
		||||
	} else {
 | 
			
		||||
		from_peer = &args->peer_b;
 | 
			
		||||
		to_peer = &args->peer_a;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Match only UDP packets */
 | 
			
		||||
	OSMO_STRBUF_PRINTF(sb, " meta l4proto udp");
 | 
			
		||||
	/* # add chain for verdict map in prerouting
 | 
			
		||||
	 * add chain inet osmo-upf tunmap-pre-123
 | 
			
		||||
	 * # mangle destination address at prerouting
 | 
			
		||||
	 * add rule inet osmo-upf tunmap-pre-123 ip daddr set 1.1.1.1 meta mark set 123 counter accept
 | 
			
		||||
	 *
 | 
			
		||||
	 * # add chain for verdict map in postrouting
 | 
			
		||||
	 * add chain inet osmo-upf tunmap-post-123
 | 
			
		||||
	 * # mangle source address and GTP TID at postrouting
 | 
			
		||||
	 * add rule inet osmo-upf tunmap-post-123 ip saddr set 2.2.2.1 @ih,32,32 set 0x00000102 counter accept
 | 
			
		||||
	 *
 | 
			
		||||
	 * # add elements to verdict map, jump to chain
 | 
			
		||||
	 * add element inet osmo-upf tunmap-pre { 2.2.2.3 . 0x00000203 : jump tunmap-pre-123 }
 | 
			
		||||
	 * add element inet osmo-upf tunmap-post { 123 : jump tunmap-post-123 }
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	/* Match on packets coming in at specific local IP */
 | 
			
		||||
	OSMO_STRBUF_PRINTF(sb, " ip daddr ");
 | 
			
		||||
	OSMO_STRBUF_APPEND(sb, osmo_sockaddr_to_str_buf2, from_peer->addr_local);
 | 
			
		||||
	OSMO_STRBUF_PRINTF(sb, "add chain inet %s tunmap-pre-%u;\n",
 | 
			
		||||
			   args->table_name, from_peer->chain_id);
 | 
			
		||||
 | 
			
		||||
	/* Match on the TEID in the header */
 | 
			
		||||
	OSMO_STRBUF_PRINTF(sb, " @ih,32,32 0x%08x", from_peer->teid_local);
 | 
			
		||||
 | 
			
		||||
	/* Change outgoing address to local IP on outgoing interface */
 | 
			
		||||
	OSMO_STRBUF_PRINTF(sb, " ip saddr set ");
 | 
			
		||||
	OSMO_STRBUF_APPEND(sb, osmo_sockaddr_to_str_buf2, to_peer->addr_local);
 | 
			
		||||
 | 
			
		||||
	/* Change destination address to to_peer */
 | 
			
		||||
	OSMO_STRBUF_PRINTF(sb, "add rule inet %s tunmap-pre-%u",
 | 
			
		||||
			   args->table_name, from_peer->chain_id);
 | 
			
		||||
	OSMO_STRBUF_PRINTF(sb, " ip daddr set ");
 | 
			
		||||
	OSMO_STRBUF_APPEND(sb, osmo_sockaddr_to_str_buf2, to_peer->addr_remote);
 | 
			
		||||
	OSMO_STRBUF_PRINTF(sb, " meta mark set %u counter accept;\n", from_peer->chain_id);
 | 
			
		||||
 | 
			
		||||
	/* Change the TEID in the header to the one to_peer expects */
 | 
			
		||||
	OSMO_STRBUF_PRINTF(sb, " @ih,32,32 set 0x%08x", to_peer->teid_remote);
 | 
			
		||||
	OSMO_STRBUF_PRINTF(sb, "add chain inet %s tunmap-post-%u;\n",
 | 
			
		||||
			   args->table_name, from_peer->chain_id);
 | 
			
		||||
 | 
			
		||||
	OSMO_STRBUF_PRINTF(sb, " counter");
 | 
			
		||||
	OSMO_STRBUF_PRINTF(sb, "add rule inet %s tunmap-post-%u",
 | 
			
		||||
			   args->table_name, from_peer->chain_id);
 | 
			
		||||
	OSMO_STRBUF_PRINTF(sb, " ip saddr set ");
 | 
			
		||||
	OSMO_STRBUF_APPEND(sb, osmo_sockaddr_to_str_buf2, to_peer->addr_local);
 | 
			
		||||
	OSMO_STRBUF_PRINTF(sb, " @ih,32,32 set 0x%x", to_peer->teid_remote);
 | 
			
		||||
	OSMO_STRBUF_PRINTF(sb, " counter accept;\n");
 | 
			
		||||
 | 
			
		||||
	OSMO_STRBUF_PRINTF(sb, " accept");
 | 
			
		||||
	OSMO_STRBUF_PRINTF(sb, ";\n");
 | 
			
		||||
	OSMO_STRBUF_PRINTF(sb, "add element inet %s tunmap-pre { ",
 | 
			
		||||
			   args->table_name);
 | 
			
		||||
	OSMO_STRBUF_APPEND(sb, osmo_sockaddr_to_str_buf2, from_peer->addr_local);
 | 
			
		||||
	OSMO_STRBUF_PRINTF(sb, " . 0x%x : jump tunmap-pre-%u };\n",
 | 
			
		||||
			   from_peer->teid_local, from_peer->chain_id);
 | 
			
		||||
 | 
			
		||||
	OSMO_STRBUF_PRINTF(sb, "add element inet %s tunmap-post { %u : jump tunmap-post-%u };\n",
 | 
			
		||||
			   args->table_name, from_peer->chain_id, from_peer->chain_id);
 | 
			
		||||
 | 
			
		||||
	return sb.chars_needed;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int tunmap_del_single_direction(char *buf, size_t buflen,
 | 
			
		||||
				       const struct upf_nft_args *args,
 | 
			
		||||
				       bool dir_a2b)
 | 
			
		||||
{
 | 
			
		||||
	struct osmo_strbuf sb = { .buf = buf, .len = buflen };
 | 
			
		||||
	const struct upf_nft_args_peer *from_peer;
 | 
			
		||||
 | 
			
		||||
	if (dir_a2b)
 | 
			
		||||
		from_peer = &args->peer_a;
 | 
			
		||||
	else
 | 
			
		||||
		from_peer = &args->peer_b;
 | 
			
		||||
 | 
			
		||||
	/* delete element inet osmo-upf tunmap-pre { 2.2.2.3 . 0x203 }
 | 
			
		||||
	 * delete element inet osmo-upf tunmap-post { 123 }
 | 
			
		||||
	 * delete chain inet osmo-upf tunmap-pre-123
 | 
			
		||||
	 * delete chain inet osmo-upf tunmap-post-123
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	OSMO_STRBUF_PRINTF(sb, "delete element inet %s tunmap-pre { ",
 | 
			
		||||
			   args->table_name);
 | 
			
		||||
	OSMO_STRBUF_APPEND(sb, osmo_sockaddr_to_str_buf2, from_peer->addr_local);
 | 
			
		||||
	OSMO_STRBUF_PRINTF(sb, " . 0x%x };\n", from_peer->teid_local);
 | 
			
		||||
 | 
			
		||||
	OSMO_STRBUF_PRINTF(sb, "delete element inet %s tunmap-post { %u };\n",
 | 
			
		||||
			   args->table_name, from_peer->chain_id);
 | 
			
		||||
 | 
			
		||||
	OSMO_STRBUF_PRINTF(sb, "delete chain inet %s tunmap-pre-%u;\n",
 | 
			
		||||
			   args->table_name, from_peer->chain_id);
 | 
			
		||||
 | 
			
		||||
	OSMO_STRBUF_PRINTF(sb, "delete chain inet %s tunmap-post-%u;\n",
 | 
			
		||||
			   args->table_name, from_peer->chain_id);
 | 
			
		||||
 | 
			
		||||
	return sb.chars_needed;
 | 
			
		||||
}
 | 
			
		||||
@@ -165,34 +254,56 @@ static int upf_nft_ruleset_tunmap_create_buf(char *buf, size_t buflen, const str
 | 
			
		||||
{
 | 
			
		||||
	struct osmo_strbuf sb = { .buf = buf, .len = buflen };
 | 
			
		||||
 | 
			
		||||
	/* Add a chain for this tunnel mapping */
 | 
			
		||||
	OSMO_STRBUF_PRINTF(sb, "add chain inet %s " NFT_CHAIN_NAME_PREFIX_TUNMAP "%u { type filter hook prerouting priority %d; }\n",
 | 
			
		||||
			   args->table_name, args->chain_id, args->priority);
 | 
			
		||||
 | 
			
		||||
	/* Forwarding from peer_a to peer_b */
 | 
			
		||||
	OSMO_STRBUF_APPEND(sb, tunmap_single_direction, args, &args->peer_a, &args->peer_b);
 | 
			
		||||
	OSMO_STRBUF_APPEND(sb, tunmap_add_single_direction, args, true);
 | 
			
		||||
	/* And from peer_b to peer_a */
 | 
			
		||||
	OSMO_STRBUF_APPEND(sb, tunmap_single_direction, args, &args->peer_b, &args->peer_a);
 | 
			
		||||
	OSMO_STRBUF_APPEND(sb, tunmap_add_single_direction, args, false);
 | 
			
		||||
 | 
			
		||||
	return sb.chars_needed;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *upf_nft_ruleset_tunmap_create_c(void *ctx, const struct upf_nft_args *args)
 | 
			
		||||
{
 | 
			
		||||
	OSMO_NAME_C_IMPL(ctx, 512, "ERROR", upf_nft_ruleset_tunmap_create_buf, args)
 | 
			
		||||
	OSMO_NAME_C_IMPL(ctx, 1024, "ERROR", upf_nft_ruleset_tunmap_create_buf, args)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int upf_nft_ruleset_tunmap_delete_buf(char *buf, size_t buflen, const struct upf_nft_args *args)
 | 
			
		||||
{
 | 
			
		||||
	struct osmo_strbuf sb = { .buf = buf, .len = buflen };
 | 
			
		||||
	OSMO_STRBUF_PRINTF(sb, "delete chain inet %s " NFT_CHAIN_NAME_PREFIX_TUNMAP "%u\n",
 | 
			
		||||
			   args->table_name, args->chain_id);
 | 
			
		||||
 | 
			
		||||
	/* Forwarding from peer_a to peer_b */
 | 
			
		||||
	OSMO_STRBUF_APPEND(sb, tunmap_del_single_direction, args, true);
 | 
			
		||||
	/* And from peer_b to peer_a */
 | 
			
		||||
	OSMO_STRBUF_APPEND(sb, tunmap_del_single_direction, args, false);
 | 
			
		||||
 | 
			
		||||
	return sb.chars_needed;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *upf_nft_ruleset_tunmap_delete_c(void *ctx, const struct upf_nft_args *args)
 | 
			
		||||
{
 | 
			
		||||
	OSMO_NAME_C_IMPL(ctx, 64, "ERROR", upf_nft_ruleset_tunmap_delete_buf, args)
 | 
			
		||||
	OSMO_NAME_C_IMPL(ctx, 512, "ERROR", upf_nft_ruleset_tunmap_delete_buf, args)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int upf_nft_tunmap_to_str_buf(char *buf, size_t buflen, const struct upf_nft_tunmap_desc *tunmap)
 | 
			
		||||
{
 | 
			
		||||
	struct osmo_strbuf sb = { .buf = buf, .len = buflen };
 | 
			
		||||
 | 
			
		||||
	/* ACCESS 1.1.1.2:0x102 <---> 2.2.2.1:0x201 UPF 2.2.2.3:0x203 <---> 3.3.3.2:0x302 CORE */
 | 
			
		||||
	OSMO_STRBUF_PRINTF(sb, "ACCESS ");
 | 
			
		||||
	OSMO_STRBUF_APPEND(sb, osmo_sockaddr_to_str_buf2, &tunmap->access.gtp_remote_addr);
 | 
			
		||||
	OSMO_STRBUF_PRINTF(sb, ":0x%x <---> ", tunmap->access.remote_teid);
 | 
			
		||||
	OSMO_STRBUF_APPEND(sb, osmo_sockaddr_to_str_buf2, &tunmap->access.gtp_local_addr);
 | 
			
		||||
	OSMO_STRBUF_PRINTF(sb, ":0x%x UPF ", tunmap->access.local_teid);
 | 
			
		||||
	OSMO_STRBUF_APPEND(sb, osmo_sockaddr_to_str_buf2, &tunmap->core.gtp_local_addr);
 | 
			
		||||
	OSMO_STRBUF_PRINTF(sb, ":0x%x <---> ", tunmap->core.local_teid);
 | 
			
		||||
	OSMO_STRBUF_APPEND(sb, osmo_sockaddr_to_str_buf2, &tunmap->core.gtp_remote_addr);
 | 
			
		||||
	OSMO_STRBUF_PRINTF(sb, ":0x%x CORE", tunmap->core.remote_teid);
 | 
			
		||||
	return sb.chars_needed;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
char *upf_nft_tunmap_to_str_c(void *ctx, const struct upf_nft_tunmap_desc *tunmap)
 | 
			
		||||
{
 | 
			
		||||
	OSMO_NAME_C_IMPL(ctx, 128, "ERROR", upf_nft_tunmap_to_str_buf, tunmap)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void upf_nft_args_from_tunmap_desc(struct upf_nft_args *args, const struct upf_nft_tunmap_desc *tunmap)
 | 
			
		||||
@@ -204,39 +315,62 @@ static void upf_nft_args_from_tunmap_desc(struct upf_nft_args *args, const struc
 | 
			
		||||
 | 
			
		||||
	*args = (struct upf_nft_args){
 | 
			
		||||
		.table_name = g_upf->nft.table_name,
 | 
			
		||||
		.chain_id = tunmap->id,
 | 
			
		||||
		.priority = g_upf->nft.priority,
 | 
			
		||||
		.peer_a = {
 | 
			
		||||
			.addr_remote = &tunmap->access.gtp_remote_addr,
 | 
			
		||||
			.teid_remote = tunmap->access.remote_teid,
 | 
			
		||||
			.addr_local = &tunmap->access.gtp_local_addr,
 | 
			
		||||
			.teid_local = tunmap->access.local_teid,
 | 
			
		||||
			.chain_id = tunmap->access.chain_id,
 | 
			
		||||
		},
 | 
			
		||||
		.peer_b = {
 | 
			
		||||
			.addr_remote = &tunmap->core.gtp_remote_addr,
 | 
			
		||||
			.teid_remote = tunmap->core.remote_teid,
 | 
			
		||||
			.addr_local = &tunmap->core.gtp_local_addr,
 | 
			
		||||
			.teid_local = tunmap->core.local_teid,
 | 
			
		||||
			.chain_id = tunmap->core.chain_id,
 | 
			
		||||
		},
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
char *upf_nft_tunmap_get_table_init_str(void *ctx)
 | 
			
		||||
{
 | 
			
		||||
	return upf_nft_ruleset_table_create(ctx, g_upf->nft.table_name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
char *upf_nft_tunmap_get_vmap_init_str(void *ctx)
 | 
			
		||||
{
 | 
			
		||||
	return upf_nft_ruleset_vmap_init(ctx, g_upf->nft.table_name, g_upf->nft.priority_pre,
 | 
			
		||||
					 g_upf->nft.priority_post);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint32_t chain_id_next(void)
 | 
			
		||||
{
 | 
			
		||||
	g_upf->nft.next_chain_id_state++;
 | 
			
		||||
	if (!g_upf->nft.next_chain_id_state)
 | 
			
		||||
		g_upf->nft.next_chain_id_state++;
 | 
			
		||||
	return g_upf->nft.next_chain_id_state;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
char *upf_nft_tunmap_get_ruleset_str(void *ctx, struct upf_nft_tunmap_desc *tunmap)
 | 
			
		||||
{
 | 
			
		||||
	struct upf_nft_args args;
 | 
			
		||||
 | 
			
		||||
	/* Give this tunnel mapping a new id, returned to the caller so that the tunnel mapping can be deleted later */
 | 
			
		||||
	if (!tunmap->id) {
 | 
			
		||||
		g_upf->nft.next_id_state++;
 | 
			
		||||
		if (!g_upf->nft.next_id_state)
 | 
			
		||||
			g_upf->nft.next_id_state++;
 | 
			
		||||
		tunmap->id = g_upf->nft.next_id_state;
 | 
			
		||||
	}
 | 
			
		||||
	if (!tunmap->access.chain_id)
 | 
			
		||||
		tunmap->access.chain_id = chain_id_next();
 | 
			
		||||
	if (!tunmap->core.chain_id)
 | 
			
		||||
		tunmap->core.chain_id = chain_id_next();
 | 
			
		||||
 | 
			
		||||
	upf_nft_args_from_tunmap_desc(&args, tunmap);
 | 
			
		||||
	return upf_nft_ruleset_tunmap_create_c(ctx, &args);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
char *upf_nft_tunmap_get_ruleset_del_str(void *ctx, struct upf_nft_tunmap_desc *tunmap)
 | 
			
		||||
{
 | 
			
		||||
	struct upf_nft_args args;
 | 
			
		||||
	upf_nft_args_from_tunmap_desc(&args, tunmap);
 | 
			
		||||
	return upf_nft_ruleset_tunmap_delete_c(ctx, &args);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int upf_nft_tunmap_create(struct upf_nft_tunmap_desc *tunmap)
 | 
			
		||||
{
 | 
			
		||||
	return upf_nft_run(upf_nft_tunmap_get_ruleset_str(OTC_SELECT, tunmap));
 | 
			
		||||
@@ -244,7 +378,5 @@ int upf_nft_tunmap_create(struct upf_nft_tunmap_desc *tunmap)
 | 
			
		||||
 | 
			
		||||
int upf_nft_tunmap_delete(struct upf_nft_tunmap_desc *tunmap)
 | 
			
		||||
{
 | 
			
		||||
	struct upf_nft_args args;
 | 
			
		||||
	upf_nft_args_from_tunmap_desc(&args, tunmap);
 | 
			
		||||
	return upf_nft_run(upf_nft_ruleset_tunmap_delete_c(OTC_SELECT, &args));
 | 
			
		||||
	return upf_nft_run(upf_nft_tunmap_get_ruleset_del_str(OTC_SELECT, tunmap));
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -300,12 +300,13 @@ DEFUN(show_nft_rule_tunmap_example, show_nft_rule_tunmap_example_cmd,
 | 
			
		||||
		.access = {
 | 
			
		||||
			.local_teid = 0x201,
 | 
			
		||||
			.remote_teid = 0x102,
 | 
			
		||||
			.chain_id = 123,
 | 
			
		||||
		},
 | 
			
		||||
		.core = {
 | 
			
		||||
			.local_teid = 0x203,
 | 
			
		||||
			.remote_teid = 0x302,
 | 
			
		||||
			.chain_id = 321,
 | 
			
		||||
		},
 | 
			
		||||
		.id = 123,
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	osmo_sockaddr_str_from_str2(&str, "1.1.1.1");
 | 
			
		||||
@@ -320,7 +321,14 @@ DEFUN(show_nft_rule_tunmap_example, show_nft_rule_tunmap_example_cmd,
 | 
			
		||||
	osmo_sockaddr_str_from_str2(&str, "3.3.3.3");
 | 
			
		||||
	osmo_sockaddr_str_to_sockaddr(&str, &d.core.gtp_remote_addr.u.sas);
 | 
			
		||||
 | 
			
		||||
	vty_out(vty, "%% init verdict map:%s", VTY_NEWLINE);
 | 
			
		||||
	vty_out(vty, "%s%s", upf_nft_tunmap_get_table_init_str(OTC_SELECT), VTY_NEWLINE);
 | 
			
		||||
	vty_out(vty, "%s%s", upf_nft_tunmap_get_vmap_init_str(OTC_SELECT), VTY_NEWLINE);
 | 
			
		||||
	vty_out(vty, "%% add tunmap:%s", VTY_NEWLINE);
 | 
			
		||||
	vty_out(vty, "%% %s%s", upf_nft_tunmap_to_str_c(OTC_SELECT, &d), VTY_NEWLINE);
 | 
			
		||||
	vty_out(vty, "%s%s", upf_nft_tunmap_get_ruleset_str(OTC_SELECT, &d), VTY_NEWLINE);
 | 
			
		||||
	vty_out(vty, "%% delete tunmap:%s", VTY_NEWLINE);
 | 
			
		||||
	vty_out(vty, "%s%s", upf_nft_tunmap_get_ruleset_del_str(OTC_SELECT, &d), VTY_NEWLINE);
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -3,9 +3,40 @@ OsmoUPF# configure terminal
 | 
			
		||||
OsmoUPF(config)# tunmap
 | 
			
		||||
 | 
			
		||||
OsmoUPF(config-tunmap)# show nft-rule tunmap example
 | 
			
		||||
add chain inet osmo-upf tunmap123 { type filter hook prerouting priority -300; }
 | 
			
		||||
add rule inet osmo-upf tunmap123 meta l4proto udp ip daddr 2.2.2.1 @ih,32,32 0x00000201 ip saddr set 2.2.2.3 ip daddr set 3.3.3.3 @ih,32,32 set 0x00000302 counter accept;
 | 
			
		||||
add rule inet osmo-upf tunmap123 meta l4proto udp ip daddr 2.2.2.3 @ih,32,32 0x00000203 ip saddr set 2.2.2.1 ip daddr set 1.1.1.1 @ih,32,32 set 0x00000102 counter accept;
 | 
			
		||||
% init verdict map:
 | 
			
		||||
add table inet osmo-upf
 | 
			
		||||
 | 
			
		||||
add chain inet osmo-upf pre { type filter hook prerouting priority -300; policy accept; };
 | 
			
		||||
add chain inet osmo-upf post { type filter hook postrouting priority 400; policy accept; };
 | 
			
		||||
add map inet osmo-upf tunmap-pre { typeof ip daddr . @ih,32,32 : verdict; };
 | 
			
		||||
add map inet osmo-upf tunmap-post { typeof meta mark : verdict; };
 | 
			
		||||
add rule inet osmo-upf pre udp dport 2152 ip daddr . @ih,32,32 vmap @tunmap-pre;
 | 
			
		||||
add rule inet osmo-upf post meta mark vmap @tunmap-post;
 | 
			
		||||
 | 
			
		||||
% add tunmap:
 | 
			
		||||
% ACCESS 1.1.1.1:0x102 <---> 2.2.2.1:0x201 UPF 2.2.2.3:0x203 <---> 3.3.3.3:0x302 CORE
 | 
			
		||||
add chain inet osmo-upf tunmap-pre-123;
 | 
			
		||||
add rule inet osmo-upf tunmap-pre-123 ip daddr set 3.3.3.3 meta mark set 123 counter accept;
 | 
			
		||||
add chain inet osmo-upf tunmap-post-123;
 | 
			
		||||
add rule inet osmo-upf tunmap-post-123 ip saddr set 2.2.2.3 @ih,32,32 set 0x302 counter accept;
 | 
			
		||||
add element inet osmo-upf tunmap-pre { 2.2.2.1 . 0x201 : jump tunmap-pre-123 };
 | 
			
		||||
add element inet osmo-upf tunmap-post { 123 : jump tunmap-post-123 };
 | 
			
		||||
add chain inet osmo-upf tunmap-pre-321;
 | 
			
		||||
add rule inet osmo-upf tunmap-pre-321 ip daddr set 1.1.1.1 meta mark set 321 counter accept;
 | 
			
		||||
add chain inet osmo-upf tunmap-post-321;
 | 
			
		||||
add rule inet osmo-upf tunmap-post-321 ip saddr set 2.2.2.1 @ih,32,32 set 0x102 counter accept;
 | 
			
		||||
add element inet osmo-upf tunmap-pre { 2.2.2.3 . 0x203 : jump tunmap-pre-321 };
 | 
			
		||||
add element inet osmo-upf tunmap-post { 321 : jump tunmap-post-321 };
 | 
			
		||||
 | 
			
		||||
% delete tunmap:
 | 
			
		||||
delete element inet osmo-upf tunmap-pre { 2.2.2.1 . 0x201 };
 | 
			
		||||
delete element inet osmo-upf tunmap-post { 123 };
 | 
			
		||||
delete chain inet osmo-upf tunmap-pre-123;
 | 
			
		||||
delete chain inet osmo-upf tunmap-post-123;
 | 
			
		||||
delete element inet osmo-upf tunmap-pre { 2.2.2.3 . 0x203 };
 | 
			
		||||
delete element inet osmo-upf tunmap-post { 321 };
 | 
			
		||||
delete chain inet osmo-upf tunmap-pre-321;
 | 
			
		||||
delete chain inet osmo-upf tunmap-post-321;
 | 
			
		||||
 | 
			
		||||
OsmoUPF(config-tunmap)# show nft-rule tunmap append
 | 
			
		||||
% deprecated config option: 'show nft-rule tunmap append'
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user