15
15
#include <linux/openvswitch.h>
16
16
#include <net/ip.h>
17
17
#include <net/netfilter/nf_conntrack_core.h>
18
+ #include <net/netfilter/nf_conntrack_labels.h>
18
19
#include <net/netfilter/nf_conntrack_zones.h>
19
20
#include <net/netfilter/ipv6/nf_defrag_ipv6.h>
20
21
@@ -34,13 +35,20 @@ struct md_mark {
34
35
u32 mask ;
35
36
};
36
37
38
+ /* Metadata label for masked write to conntrack label. */
39
+ struct md_label {
40
+ struct ovs_key_ct_label value ;
41
+ struct ovs_key_ct_label mask ;
42
+ };
43
+
37
44
/* Conntrack action context for execution. */
38
45
struct ovs_conntrack_info {
39
46
struct nf_conntrack_zone zone ;
40
47
struct nf_conn * ct ;
41
48
u32 flags ;
42
49
u16 family ;
43
50
struct md_mark mark ;
51
+ struct md_label label ;
44
52
};
45
53
46
54
static u16 key_to_nfproto (const struct sw_flow_key * key )
@@ -90,13 +98,32 @@ static u8 ovs_ct_get_state(enum ip_conntrack_info ctinfo)
90
98
return ct_state ;
91
99
}
92
100
101
+ static void ovs_ct_get_label (const struct nf_conn * ct ,
102
+ struct ovs_key_ct_label * label )
103
+ {
104
+ struct nf_conn_labels * cl = ct ? nf_ct_labels_find (ct ) : NULL ;
105
+
106
+ if (cl ) {
107
+ size_t len = cl -> words * sizeof (long );
108
+
109
+ if (len > OVS_CT_LABEL_LEN )
110
+ len = OVS_CT_LABEL_LEN ;
111
+ else if (len < OVS_CT_LABEL_LEN )
112
+ memset (label , 0 , OVS_CT_LABEL_LEN );
113
+ memcpy (label , cl -> bits , len );
114
+ } else {
115
+ memset (label , 0 , OVS_CT_LABEL_LEN );
116
+ }
117
+ }
118
+
93
119
static void __ovs_ct_update_key (struct sw_flow_key * key , u8 state ,
94
120
const struct nf_conntrack_zone * zone ,
95
121
const struct nf_conn * ct )
96
122
{
97
123
key -> ct .state = state ;
98
124
key -> ct .zone = zone -> id ;
99
125
key -> ct .mark = ct ? ct -> mark : 0 ;
126
+ ovs_ct_get_label (ct , & key -> ct .label );
100
127
}
101
128
102
129
/* Update 'key' based on skb->nfct. If 'post_ct' is true, then OVS has
@@ -140,6 +167,11 @@ int ovs_ct_put_key(const struct sw_flow_key *key, struct sk_buff *skb)
140
167
nla_put_u32 (skb , OVS_KEY_ATTR_CT_MARK , key -> ct .mark ))
141
168
return - EMSGSIZE ;
142
169
170
+ if (IS_ENABLED (CONFIG_NF_CONNTRACK_LABEL ) &&
171
+ nla_put (skb , OVS_KEY_ATTR_CT_LABEL , sizeof (key -> ct .label ),
172
+ & key -> ct .label ))
173
+ return - EMSGSIZE ;
174
+
143
175
return 0 ;
144
176
}
145
177
@@ -168,6 +200,40 @@ static int ovs_ct_set_mark(struct sk_buff *skb, struct sw_flow_key *key,
168
200
return 0 ;
169
201
}
170
202
203
+ static int ovs_ct_set_label (struct sk_buff * skb , struct sw_flow_key * key ,
204
+ const struct ovs_key_ct_label * label ,
205
+ const struct ovs_key_ct_label * mask )
206
+ {
207
+ enum ip_conntrack_info ctinfo ;
208
+ struct nf_conn_labels * cl ;
209
+ struct nf_conn * ct ;
210
+ int err ;
211
+
212
+ if (!IS_ENABLED (CONFIG_NF_CONNTRACK_LABELS ))
213
+ return - ENOTSUPP ;
214
+
215
+ /* The connection could be invalid, in which case set_label is no-op.*/
216
+ ct = nf_ct_get (skb , & ctinfo );
217
+ if (!ct )
218
+ return 0 ;
219
+
220
+ cl = nf_ct_labels_find (ct );
221
+ if (!cl ) {
222
+ nf_ct_labels_ext_add (ct );
223
+ cl = nf_ct_labels_find (ct );
224
+ }
225
+ if (!cl || cl -> words * sizeof (long ) < OVS_CT_LABEL_LEN )
226
+ return - ENOSPC ;
227
+
228
+ err = nf_connlabels_replace (ct , (u32 * )label , (u32 * )mask ,
229
+ OVS_CT_LABEL_LEN / sizeof (u32 ));
230
+ if (err )
231
+ return err ;
232
+
233
+ ovs_ct_get_label (ct , & key -> ct .label );
234
+ return 0 ;
235
+ }
236
+
171
237
static int handle_fragments (struct net * net , struct sw_flow_key * key ,
172
238
u16 zone , struct sk_buff * skb )
173
239
{
@@ -327,6 +393,17 @@ static int ovs_ct_commit(struct net *net, struct sw_flow_key *key,
327
393
return 0 ;
328
394
}
329
395
396
+ static bool label_nonzero (const struct ovs_key_ct_label * label )
397
+ {
398
+ size_t i ;
399
+
400
+ for (i = 0 ; i < sizeof (* label ); i ++ )
401
+ if (label -> ct_label [i ])
402
+ return true;
403
+
404
+ return false;
405
+ }
406
+
330
407
int ovs_ct_execute (struct net * net , struct sk_buff * skb ,
331
408
struct sw_flow_key * key ,
332
409
const struct ovs_conntrack_info * info )
@@ -351,9 +428,15 @@ int ovs_ct_execute(struct net *net, struct sk_buff *skb,
351
428
if (err )
352
429
goto err ;
353
430
354
- if (info -> mark .mask )
431
+ if (info -> mark .mask ) {
355
432
err = ovs_ct_set_mark (skb , key , info -> mark .value ,
356
433
info -> mark .mask );
434
+ if (err )
435
+ goto err ;
436
+ }
437
+ if (label_nonzero (& info -> label .mask ))
438
+ err = ovs_ct_set_label (skb , key , & info -> label .value ,
439
+ & info -> label .mask );
357
440
err :
358
441
skb_push (skb , nh_ofs );
359
442
return err ;
@@ -366,6 +449,8 @@ static const struct ovs_ct_len_tbl ovs_ct_attr_lens[OVS_CT_ATTR_MAX + 1] = {
366
449
.maxlen = sizeof (u16 ) },
367
450
[OVS_CT_ATTR_MARK ] = { .minlen = sizeof (struct md_mark ),
368
451
.maxlen = sizeof (struct md_mark ) },
452
+ [OVS_CT_ATTR_LABEL ] = { .minlen = sizeof (struct md_label ),
453
+ .maxlen = sizeof (struct md_label ) },
369
454
};
370
455
371
456
static int parse_ct (const struct nlattr * attr , struct ovs_conntrack_info * info ,
@@ -408,6 +493,14 @@ static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info,
408
493
info -> mark = * mark ;
409
494
break ;
410
495
}
496
+ #endif
497
+ #ifdef CONFIG_NF_CONNTRACK_LABELS
498
+ case OVS_CT_ATTR_LABEL : {
499
+ struct md_label * label = nla_data (a );
500
+
501
+ info -> label = * label ;
502
+ break ;
503
+ }
411
504
#endif
412
505
default :
413
506
OVS_NLERR (log , "Unknown conntrack attr (%d)" ,
@@ -424,7 +517,7 @@ static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info,
424
517
return 0 ;
425
518
}
426
519
427
- bool ovs_ct_verify (enum ovs_key_attr attr )
520
+ bool ovs_ct_verify (struct net * net , enum ovs_key_attr attr )
428
521
{
429
522
if (attr == OVS_KEY_ATTR_CT_STATE )
430
523
return true;
@@ -434,6 +527,12 @@ bool ovs_ct_verify(enum ovs_key_attr attr)
434
527
if (IS_ENABLED (CONFIG_NF_CONNTRACK_MARK ) &&
435
528
attr == OVS_KEY_ATTR_CT_MARK )
436
529
return true;
530
+ if (IS_ENABLED (CONFIG_NF_CONNTRACK_LABELS ) &&
531
+ attr == OVS_KEY_ATTR_CT_LABEL ) {
532
+ struct ovs_net * ovs_net = net_generic (net , ovs_net_id );
533
+
534
+ return ovs_net -> xt_label ;
535
+ }
437
536
438
537
return false;
439
538
}
@@ -500,6 +599,10 @@ int ovs_ct_action_to_attr(const struct ovs_conntrack_info *ct_info,
500
599
nla_put (skb , OVS_CT_ATTR_MARK , sizeof (ct_info -> mark ),
501
600
& ct_info -> mark ))
502
601
return - EMSGSIZE ;
602
+ if (IS_ENABLED (CONFIG_NF_CONNTRACK_LABELS ) &&
603
+ nla_put (skb , OVS_CT_ATTR_LABEL , sizeof (ct_info -> label ),
604
+ & ct_info -> label ))
605
+ return - EMSGSIZE ;
503
606
504
607
nla_nest_end (skb , start );
505
608
@@ -513,3 +616,24 @@ void ovs_ct_free_action(const struct nlattr *a)
513
616
if (ct_info -> ct )
514
617
nf_ct_put (ct_info -> ct );
515
618
}
619
+
620
+ void ovs_ct_init (struct net * net )
621
+ {
622
+ unsigned int n_bits = sizeof (struct ovs_key_ct_label ) * BITS_PER_BYTE ;
623
+ struct ovs_net * ovs_net = net_generic (net , ovs_net_id );
624
+
625
+ if (nf_connlabels_get (net , n_bits )) {
626
+ ovs_net -> xt_label = false;
627
+ OVS_NLERR (true, "Failed to set connlabel length" );
628
+ } else {
629
+ ovs_net -> xt_label = true;
630
+ }
631
+ }
632
+
633
+ void ovs_ct_exit (struct net * net )
634
+ {
635
+ struct ovs_net * ovs_net = net_generic (net , ovs_net_id );
636
+
637
+ if (ovs_net -> xt_label )
638
+ nf_connlabels_put (net );
639
+ }
0 commit comments