@@ -28,12 +28,19 @@ struct ovs_ct_len_tbl {
2828 size_t minlen ;
2929};
3030
31+ /* Metadata mark for masked write to conntrack mark */
32+ struct md_mark {
33+ u32 value ;
34+ u32 mask ;
35+ };
36+
3137/* Conntrack action context for execution. */
3238struct ovs_conntrack_info {
3339 struct nf_conntrack_zone zone ;
3440 struct nf_conn * ct ;
3541 u32 flags ;
3642 u16 family ;
43+ struct md_mark mark ;
3744};
3845
3946static u16 key_to_nfproto (const struct sw_flow_key * key )
@@ -84,10 +91,12 @@ static u8 ovs_ct_get_state(enum ip_conntrack_info ctinfo)
8491}
8592
8693static void __ovs_ct_update_key (struct sw_flow_key * key , u8 state ,
87- const struct nf_conntrack_zone * zone )
94+ const struct nf_conntrack_zone * zone ,
95+ const struct nf_conn * ct )
8896{
8997 key -> ct .state = state ;
9098 key -> ct .zone = zone -> id ;
99+ key -> ct .mark = ct ? ct -> mark : 0 ;
91100}
92101
93102/* Update 'key' based on skb->nfct. If 'post_ct' is true, then OVS has
@@ -110,7 +119,7 @@ static void ovs_ct_update_key(const struct sk_buff *skb,
110119 } else if (post_ct ) {
111120 state = OVS_CS_F_TRACKED | OVS_CS_F_INVALID ;
112121 }
113- __ovs_ct_update_key (key , state , zone );
122+ __ovs_ct_update_key (key , state , zone , ct );
114123}
115124
116125void ovs_ct_fill_key (const struct sk_buff * skb , struct sw_flow_key * key )
@@ -127,6 +136,35 @@ int ovs_ct_put_key(const struct sw_flow_key *key, struct sk_buff *skb)
127136 nla_put_u16 (skb , OVS_KEY_ATTR_CT_ZONE , key -> ct .zone ))
128137 return - EMSGSIZE ;
129138
139+ if (IS_ENABLED (CONFIG_NF_CONNTRACK_MARK ) &&
140+ nla_put_u32 (skb , OVS_KEY_ATTR_CT_MARK , key -> ct .mark ))
141+ return - EMSGSIZE ;
142+
143+ return 0 ;
144+ }
145+
146+ static int ovs_ct_set_mark (struct sk_buff * skb , struct sw_flow_key * key ,
147+ u32 ct_mark , u32 mask )
148+ {
149+ enum ip_conntrack_info ctinfo ;
150+ struct nf_conn * ct ;
151+ u32 new_mark ;
152+
153+ if (!IS_ENABLED (CONFIG_NF_CONNTRACK_MARK ))
154+ return - ENOTSUPP ;
155+
156+ /* The connection could be invalid, in which case set_mark is no-op. */
157+ ct = nf_ct_get (skb , & ctinfo );
158+ if (!ct )
159+ return 0 ;
160+
161+ new_mark = ct_mark | (ct -> mark & ~(mask ));
162+ if (ct -> mark != new_mark ) {
163+ ct -> mark = new_mark ;
164+ nf_conntrack_event_cache (IPCT_MARK , ct );
165+ key -> ct .mark = new_mark ;
166+ }
167+
130168 return 0 ;
131169}
132170
@@ -247,7 +285,7 @@ static int ovs_ct_lookup(struct net *net, struct sw_flow_key *key,
247285 u8 state ;
248286
249287 state = OVS_CS_F_TRACKED | OVS_CS_F_NEW | OVS_CS_F_RELATED ;
250- __ovs_ct_update_key (key , state , & info -> zone );
288+ __ovs_ct_update_key (key , state , & info -> zone , exp -> master );
251289 } else {
252290 int err ;
253291
@@ -310,7 +348,13 @@ int ovs_ct_execute(struct net *net, struct sk_buff *skb,
310348 err = ovs_ct_commit (net , key , info , skb );
311349 else
312350 err = ovs_ct_lookup (net , key , info , skb );
351+ if (err )
352+ goto err ;
313353
354+ if (info -> mark .mask )
355+ err = ovs_ct_set_mark (skb , key , info -> mark .value ,
356+ info -> mark .mask );
357+ err :
314358 skb_push (skb , nh_ofs );
315359 return err ;
316360}
@@ -320,6 +364,8 @@ static const struct ovs_ct_len_tbl ovs_ct_attr_lens[OVS_CT_ATTR_MAX + 1] = {
320364 .maxlen = sizeof (u32 ) },
321365 [OVS_CT_ATTR_ZONE ] = { .minlen = sizeof (u16 ),
322366 .maxlen = sizeof (u16 ) },
367+ [OVS_CT_ATTR_MARK ] = { .minlen = sizeof (struct md_mark ),
368+ .maxlen = sizeof (struct md_mark ) },
323369};
324370
325371static int parse_ct (const struct nlattr * attr , struct ovs_conntrack_info * info ,
@@ -354,6 +400,14 @@ static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info,
354400 case OVS_CT_ATTR_ZONE :
355401 info -> zone .id = nla_get_u16 (a );
356402 break ;
403+ #endif
404+ #ifdef CONFIG_NF_CONNTRACK_MARK
405+ case OVS_CT_ATTR_MARK : {
406+ struct md_mark * mark = nla_data (a );
407+
408+ info -> mark = * mark ;
409+ break ;
410+ }
357411#endif
358412 default :
359413 OVS_NLERR (log , "Unknown conntrack attr (%d)" ,
@@ -377,6 +431,9 @@ bool ovs_ct_verify(enum ovs_key_attr attr)
377431 if (IS_ENABLED (CONFIG_NF_CONNTRACK_ZONES ) &&
378432 attr == OVS_KEY_ATTR_CT_ZONE )
379433 return true;
434+ if (IS_ENABLED (CONFIG_NF_CONNTRACK_MARK ) &&
435+ attr == OVS_KEY_ATTR_CT_MARK )
436+ return true;
380437
381438 return false;
382439}
@@ -439,6 +496,10 @@ int ovs_ct_action_to_attr(const struct ovs_conntrack_info *ct_info,
439496 if (IS_ENABLED (CONFIG_NF_CONNTRACK_ZONES ) &&
440497 nla_put_u16 (skb , OVS_CT_ATTR_ZONE , ct_info -> zone .id ))
441498 return - EMSGSIZE ;
499+ if (IS_ENABLED (CONFIG_NF_CONNTRACK_MARK ) &&
500+ nla_put (skb , OVS_CT_ATTR_MARK , sizeof (ct_info -> mark ),
501+ & ct_info -> mark ))
502+ return - EMSGSIZE ;
442503
443504 nla_nest_end (skb , start );
444505
0 commit comments