Skip to content

Commit 2301401

Browse files
Florian Westphalummakynes
authored andcommitted
netfilter: conntrack: support a fixed size of 128 distinct labels
The conntrack label extension is currently variable-sized, e.g. if only 2 labels are used by iptables rules then the labels->bits[] array will only contain one element. We track size of each label storage area in the 'words' member. But in nftables and openvswitch we always have to ask for worst-case since we don't know what bit will be used at configuration time. As most arches are 64bit we need to allocate 24 bytes in this case: struct nf_conn_labels { u8 words; /* 0 1 */ /* XXX 7 bytes hole, try to pack */ long unsigned bits[2]; /* 8 24 */ Make bits a fixed size and drop the words member, it simplifies the code and only increases memory requirements on x86 when less than 64bit labels are required. We still only allocate the extension if its needed. Signed-off-by: Florian Westphal <[email protected]> Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent 6e1f760 commit 2301401

File tree

6 files changed

+18
-40
lines changed

6 files changed

+18
-40
lines changed

include/net/netfilter/nf_conntrack_labels.h

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@
1010
#define NF_CT_LABELS_MAX_SIZE ((XT_CONNLABEL_MAXBIT + 1) / BITS_PER_BYTE)
1111

1212
struct nf_conn_labels {
13-
u8 words;
14-
unsigned long bits[];
13+
unsigned long bits[NF_CT_LABELS_MAX_SIZE / sizeof(long)];
1514
};
1615

1716
static inline struct nf_conn_labels *nf_ct_labels_find(const struct nf_conn *ct)
@@ -26,20 +25,13 @@ static inline struct nf_conn_labels *nf_ct_labels_find(const struct nf_conn *ct)
2625
static inline struct nf_conn_labels *nf_ct_labels_ext_add(struct nf_conn *ct)
2726
{
2827
#ifdef CONFIG_NF_CONNTRACK_LABELS
29-
struct nf_conn_labels *cl_ext;
3028
struct net *net = nf_ct_net(ct);
31-
u8 words;
3229

33-
words = ACCESS_ONCE(net->ct.label_words);
34-
if (words == 0)
30+
if (net->ct.labels_used == 0)
3531
return NULL;
3632

37-
cl_ext = nf_ct_ext_add_length(ct, NF_CT_EXT_LABELS,
38-
words * sizeof(long), GFP_ATOMIC);
39-
if (cl_ext != NULL)
40-
cl_ext->words = words;
41-
42-
return cl_ext;
33+
return nf_ct_ext_add_length(ct, NF_CT_EXT_LABELS,
34+
sizeof(struct nf_conn_labels), GFP_ATOMIC);
4335
#else
4436
return NULL;
4537
#endif

net/netfilter/nf_conntrack_labels.c

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ int nf_connlabel_set(struct nf_conn *ct, u16 bit)
2020
{
2121
struct nf_conn_labels *labels = nf_ct_labels_find(ct);
2222

23-
if (!labels || BIT_WORD(bit) >= labels->words)
23+
if (!labels)
2424
return -ENOSPC;
2525

2626
if (test_bit(bit, labels->bits))
@@ -60,7 +60,7 @@ int nf_connlabels_replace(struct nf_conn *ct,
6060
if (!labels)
6161
return -ENOSPC;
6262

63-
size = labels->words * sizeof(long);
63+
size = sizeof(labels->bits);
6464
if (size < (words32 * sizeof(u32)))
6565
words32 = size / sizeof(u32);
6666

@@ -80,16 +80,11 @@ EXPORT_SYMBOL_GPL(nf_connlabels_replace);
8080

8181
int nf_connlabels_get(struct net *net, unsigned int bits)
8282
{
83-
size_t words;
84-
85-
words = BIT_WORD(bits) + 1;
86-
if (words > NF_CT_LABELS_MAX_SIZE / sizeof(long))
83+
if (BIT_WORD(bits) >= NF_CT_LABELS_MAX_SIZE / sizeof(long))
8784
return -ERANGE;
8885

8986
spin_lock(&nf_connlabels_lock);
9087
net->ct.labels_used++;
91-
if (words > net->ct.label_words)
92-
net->ct.label_words = words;
9388
spin_unlock(&nf_connlabels_lock);
9489

9590
return 0;
@@ -100,8 +95,6 @@ void nf_connlabels_put(struct net *net)
10095
{
10196
spin_lock(&nf_connlabels_lock);
10297
net->ct.labels_used--;
103-
if (net->ct.labels_used == 0)
104-
net->ct.label_words = 0;
10598
spin_unlock(&nf_connlabels_lock);
10699
}
107100
EXPORT_SYMBOL_GPL(nf_connlabels_put);

net/netfilter/nf_conntrack_netlink.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -346,25 +346,25 @@ static inline int ctnetlink_label_size(const struct nf_conn *ct)
346346

347347
if (!labels)
348348
return 0;
349-
return nla_total_size(labels->words * sizeof(long));
349+
return nla_total_size(sizeof(labels->bits));
350350
}
351351

352352
static int
353353
ctnetlink_dump_labels(struct sk_buff *skb, const struct nf_conn *ct)
354354
{
355355
struct nf_conn_labels *labels = nf_ct_labels_find(ct);
356-
unsigned int len, i;
356+
unsigned int i;
357357

358358
if (!labels)
359359
return 0;
360360

361-
len = labels->words * sizeof(long);
362361
i = 0;
363362
do {
364363
if (labels->bits[i] != 0)
365-
return nla_put(skb, CTA_LABELS, len, labels->bits);
364+
return nla_put(skb, CTA_LABELS, sizeof(labels->bits),
365+
labels->bits);
366366
i++;
367-
} while (i < labels->words);
367+
} while (i < ARRAY_SIZE(labels->bits));
368368

369369
return 0;
370370
}

net/netfilter/nft_ct.c

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -113,18 +113,11 @@ static void nft_ct_get_eval(const struct nft_expr *expr,
113113
#ifdef CONFIG_NF_CONNTRACK_LABELS
114114
case NFT_CT_LABELS: {
115115
struct nf_conn_labels *labels = nf_ct_labels_find(ct);
116-
unsigned int size;
117116

118-
if (!labels) {
117+
if (labels)
118+
memcpy(dest, labels->bits, NF_CT_LABELS_MAX_SIZE);
119+
else
119120
memset(dest, 0, NF_CT_LABELS_MAX_SIZE);
120-
return;
121-
}
122-
123-
size = labels->words * sizeof(long);
124-
memcpy(dest, labels->bits, size);
125-
if (size < NF_CT_LABELS_MAX_SIZE)
126-
memset(((char *) dest) + size, 0,
127-
NF_CT_LABELS_MAX_SIZE - size);
128121
return;
129122
}
130123
#endif

net/netfilter/xt_connlabel.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ static bool connlabel_match(const struct nf_conn *ct, u16 bit)
2525
if (!labels)
2626
return false;
2727

28-
return BIT_WORD(bit) < labels->words && test_bit(bit, labels->bits);
28+
return test_bit(bit, labels->bits);
2929
}
3030

3131
static bool

net/openvswitch/conntrack.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ static void ovs_ct_get_labels(const struct nf_conn *ct,
135135
struct nf_conn_labels *cl = ct ? nf_ct_labels_find(ct) : NULL;
136136

137137
if (cl) {
138-
size_t len = cl->words * sizeof(long);
138+
size_t len = sizeof(cl->bits);
139139

140140
if (len > OVS_CT_LABELS_LEN)
141141
len = OVS_CT_LABELS_LEN;
@@ -274,7 +274,7 @@ static int ovs_ct_set_labels(struct sk_buff *skb, struct sw_flow_key *key,
274274
nf_ct_labels_ext_add(ct);
275275
cl = nf_ct_labels_find(ct);
276276
}
277-
if (!cl || cl->words * sizeof(long) < OVS_CT_LABELS_LEN)
277+
if (!cl || sizeof(cl->bits) < OVS_CT_LABELS_LEN)
278278
return -ENOSPC;
279279

280280
err = nf_connlabels_replace(ct, (u32 *)labels, (u32 *)mask,

0 commit comments

Comments
 (0)