diff options
| -rw-r--r-- | include/uapi/linux/openvswitch.h | 5 | ||||
| -rw-r--r-- | net/openvswitch/actions.c | 1 | ||||
| -rw-r--r-- | net/openvswitch/conntrack.c | 67 | ||||
| -rw-r--r-- | net/openvswitch/conntrack.h | 1 | ||||
| -rw-r--r-- | net/openvswitch/flow.h | 1 | ||||
| -rw-r--r-- | net/openvswitch/flow_netlink.c | 12 |
6 files changed, 83 insertions, 4 deletions
diff --git a/include/uapi/linux/openvswitch.h b/include/uapi/linux/openvswitch.h index 55f599792673..7a185b554343 100644 --- a/include/uapi/linux/openvswitch.h +++ b/include/uapi/linux/openvswitch.h | |||
| @@ -325,6 +325,7 @@ enum ovs_key_attr { | |||
| 325 | * the accepted length of the array. */ | 325 | * the accepted length of the array. */ |
| 326 | OVS_KEY_ATTR_CT_STATE, /* u8 bitmask of OVS_CS_F_* */ | 326 | OVS_KEY_ATTR_CT_STATE, /* u8 bitmask of OVS_CS_F_* */ |
| 327 | OVS_KEY_ATTR_CT_ZONE, /* u16 connection tracking zone. */ | 327 | OVS_KEY_ATTR_CT_ZONE, /* u16 connection tracking zone. */ |
| 328 | OVS_KEY_ATTR_CT_MARK, /* u32 connection tracking mark */ | ||
| 328 | 329 | ||
| 329 | #ifdef __KERNEL__ | 330 | #ifdef __KERNEL__ |
| 330 | OVS_KEY_ATTR_TUNNEL_INFO, /* struct ip_tunnel_info */ | 331 | OVS_KEY_ATTR_TUNNEL_INFO, /* struct ip_tunnel_info */ |
| @@ -613,11 +614,15 @@ struct ovs_action_hash { | |||
| 613 | * enum ovs_ct_attr - Attributes for %OVS_ACTION_ATTR_CT action. | 614 | * enum ovs_ct_attr - Attributes for %OVS_ACTION_ATTR_CT action. |
| 614 | * @OVS_CT_ATTR_FLAGS: u32 connection tracking flags. | 615 | * @OVS_CT_ATTR_FLAGS: u32 connection tracking flags. |
| 615 | * @OVS_CT_ATTR_ZONE: u16 connection tracking zone. | 616 | * @OVS_CT_ATTR_ZONE: u16 connection tracking zone. |
| 617 | * @OVS_CT_ATTR_MARK: u32 value followed by u32 mask. For each bit set in the | ||
| 618 | * mask, the corresponding bit in the value is copied to the connection | ||
| 619 | * tracking mark field in the connection. | ||
| 616 | */ | 620 | */ |
| 617 | enum ovs_ct_attr { | 621 | enum ovs_ct_attr { |
| 618 | OVS_CT_ATTR_UNSPEC, | 622 | OVS_CT_ATTR_UNSPEC, |
| 619 | OVS_CT_ATTR_FLAGS, /* u8 bitmask of OVS_CT_F_*. */ | 623 | OVS_CT_ATTR_FLAGS, /* u8 bitmask of OVS_CT_F_*. */ |
| 620 | OVS_CT_ATTR_ZONE, /* u16 zone id. */ | 624 | OVS_CT_ATTR_ZONE, /* u16 zone id. */ |
| 625 | OVS_CT_ATTR_MARK, /* mark to associate with this connection. */ | ||
| 621 | __OVS_CT_ATTR_MAX | 626 | __OVS_CT_ATTR_MAX |
| 622 | }; | 627 | }; |
| 623 | 628 | ||
diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index 72ca2c491b0a..9741d2c703df 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c | |||
| @@ -968,6 +968,7 @@ static int execute_masked_set_action(struct sk_buff *skb, | |||
| 968 | 968 | ||
| 969 | case OVS_KEY_ATTR_CT_STATE: | 969 | case OVS_KEY_ATTR_CT_STATE: |
| 970 | case OVS_KEY_ATTR_CT_ZONE: | 970 | case OVS_KEY_ATTR_CT_ZONE: |
| 971 | case OVS_KEY_ATTR_CT_MARK: | ||
| 971 | err = -EINVAL; | 972 | err = -EINVAL; |
| 972 | break; | 973 | break; |
| 973 | } | 974 | } |
diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c index 1189fd50f1cf..e53dafccf21f 100644 --- a/net/openvswitch/conntrack.c +++ b/net/openvswitch/conntrack.c | |||
| @@ -28,12 +28,19 @@ struct ovs_ct_len_tbl { | |||
| 28 | size_t minlen; | 28 | size_t minlen; |
| 29 | }; | 29 | }; |
| 30 | 30 | ||
| 31 | /* Metadata mark for masked write to conntrack mark */ | ||
| 32 | struct md_mark { | ||
| 33 | u32 value; | ||
| 34 | u32 mask; | ||
| 35 | }; | ||
| 36 | |||
| 31 | /* Conntrack action context for execution. */ | 37 | /* Conntrack action context for execution. */ |
| 32 | struct ovs_conntrack_info { | 38 | struct ovs_conntrack_info { |
| 33 | struct nf_conntrack_zone zone; | 39 | struct nf_conntrack_zone zone; |
| 34 | struct nf_conn *ct; | 40 | struct nf_conn *ct; |
| 35 | u32 flags; | 41 | u32 flags; |
| 36 | u16 family; | 42 | u16 family; |
| 43 | struct md_mark mark; | ||
| 37 | }; | 44 | }; |
| 38 | 45 | ||
| 39 | static u16 key_to_nfproto(const struct sw_flow_key *key) | 46 | static 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) | |||
| 84 | } | 91 | } |
| 85 | 92 | ||
| 86 | static void __ovs_ct_update_key(struct sw_flow_key *key, u8 state, | 93 | static 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) | ||
| 88 | { | 96 | { |
| 89 | key->ct.state = state; | 97 | key->ct.state = state; |
| 90 | key->ct.zone = zone->id; | 98 | key->ct.zone = zone->id; |
| 99 | key->ct.mark = ct ? ct->mark : 0; | ||
| 91 | } | 100 | } |
| 92 | 101 | ||
| 93 | /* Update 'key' based on skb->nfct. If 'post_ct' is true, then OVS has | 102 | /* 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, | |||
| 110 | } else if (post_ct) { | 119 | } else if (post_ct) { |
| 111 | state = OVS_CS_F_TRACKED | OVS_CS_F_INVALID; | 120 | state = OVS_CS_F_TRACKED | OVS_CS_F_INVALID; |
| 112 | } | 121 | } |
| 113 | __ovs_ct_update_key(key, state, zone); | 122 | __ovs_ct_update_key(key, state, zone, ct); |
| 114 | } | 123 | } |
| 115 | 124 | ||
| 116 | void ovs_ct_fill_key(const struct sk_buff *skb, struct sw_flow_key *key) | 125 | void 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) | |||
| 127 | nla_put_u16(skb, OVS_KEY_ATTR_CT_ZONE, key->ct.zone)) | 136 | nla_put_u16(skb, OVS_KEY_ATTR_CT_ZONE, key->ct.zone)) |
| 128 | return -EMSGSIZE; | 137 | return -EMSGSIZE; |
| 129 | 138 | ||
| 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 | |||
| 130 | return 0; | 168 | return 0; |
| 131 | } | 169 | } |
| 132 | 170 | ||
| @@ -247,7 +285,7 @@ static int ovs_ct_lookup(struct net *net, struct sw_flow_key *key, | |||
| 247 | u8 state; | 285 | u8 state; |
| 248 | 286 | ||
| 249 | state = OVS_CS_F_TRACKED | OVS_CS_F_NEW | OVS_CS_F_RELATED; | 287 | 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); |
| 251 | } else { | 289 | } else { |
| 252 | int err; | 290 | int err; |
| 253 | 291 | ||
| @@ -310,7 +348,13 @@ int ovs_ct_execute(struct net *net, struct sk_buff *skb, | |||
| 310 | err = ovs_ct_commit(net, key, info, skb); | 348 | err = ovs_ct_commit(net, key, info, skb); |
| 311 | else | 349 | else |
| 312 | err = ovs_ct_lookup(net, key, info, skb); | 350 | err = ovs_ct_lookup(net, key, info, skb); |
| 351 | if (err) | ||
| 352 | goto err; | ||
| 313 | 353 | ||
| 354 | if (info->mark.mask) | ||
| 355 | err = ovs_ct_set_mark(skb, key, info->mark.value, | ||
| 356 | info->mark.mask); | ||
| 357 | err: | ||
| 314 | skb_push(skb, nh_ofs); | 358 | skb_push(skb, nh_ofs); |
| 315 | return err; | 359 | return err; |
| 316 | } | 360 | } |
| @@ -320,6 +364,8 @@ static const struct ovs_ct_len_tbl ovs_ct_attr_lens[OVS_CT_ATTR_MAX + 1] = { | |||
| 320 | .maxlen = sizeof(u32) }, | 364 | .maxlen = sizeof(u32) }, |
| 321 | [OVS_CT_ATTR_ZONE] = { .minlen = sizeof(u16), | 365 | [OVS_CT_ATTR_ZONE] = { .minlen = sizeof(u16), |
| 322 | .maxlen = sizeof(u16) }, | 366 | .maxlen = sizeof(u16) }, |
| 367 | [OVS_CT_ATTR_MARK] = { .minlen = sizeof(struct md_mark), | ||
| 368 | .maxlen = sizeof(struct md_mark) }, | ||
| 323 | }; | 369 | }; |
| 324 | 370 | ||
| 325 | static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info, | 371 | static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info, |
| @@ -355,6 +401,14 @@ static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info, | |||
| 355 | info->zone.id = nla_get_u16(a); | 401 | info->zone.id = nla_get_u16(a); |
| 356 | break; | 402 | break; |
| 357 | #endif | 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 | } | ||
| 411 | #endif | ||
| 358 | default: | 412 | default: |
| 359 | OVS_NLERR(log, "Unknown conntrack attr (%d)", | 413 | OVS_NLERR(log, "Unknown conntrack attr (%d)", |
| 360 | type); | 414 | type); |
| @@ -377,6 +431,9 @@ bool ovs_ct_verify(enum ovs_key_attr attr) | |||
| 377 | if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) && | 431 | if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) && |
| 378 | attr == OVS_KEY_ATTR_CT_ZONE) | 432 | attr == OVS_KEY_ATTR_CT_ZONE) |
| 379 | return true; | 433 | return true; |
| 434 | if (IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) && | ||
| 435 | attr == OVS_KEY_ATTR_CT_MARK) | ||
| 436 | return true; | ||
| 380 | 437 | ||
| 381 | return false; | 438 | return false; |
| 382 | } | 439 | } |
| @@ -439,6 +496,10 @@ int ovs_ct_action_to_attr(const struct ovs_conntrack_info *ct_info, | |||
| 439 | if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) && | 496 | if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) && |
| 440 | nla_put_u16(skb, OVS_CT_ATTR_ZONE, ct_info->zone.id)) | 497 | nla_put_u16(skb, OVS_CT_ATTR_ZONE, ct_info->zone.id)) |
| 441 | return -EMSGSIZE; | 498 | 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; | ||
| 442 | 503 | ||
| 443 | nla_nest_end(skb, start); | 504 | nla_nest_end(skb, start); |
| 444 | 505 | ||
diff --git a/net/openvswitch/conntrack.h b/net/openvswitch/conntrack.h index e812ee64a718..87b289c58978 100644 --- a/net/openvswitch/conntrack.h +++ b/net/openvswitch/conntrack.h | |||
| @@ -65,6 +65,7 @@ static inline void ovs_ct_fill_key(const struct sk_buff *skb, | |||
| 65 | { | 65 | { |
| 66 | key->ct.state = 0; | 66 | key->ct.state = 0; |
| 67 | key->ct.zone = 0; | 67 | key->ct.zone = 0; |
| 68 | key->ct.mark = 0; | ||
| 68 | } | 69 | } |
| 69 | 70 | ||
| 70 | static inline int ovs_ct_put_key(const struct sw_flow_key *key, | 71 | static inline int ovs_ct_put_key(const struct sw_flow_key *key, |
diff --git a/net/openvswitch/flow.h b/net/openvswitch/flow.h index 312c7d755b9b..e05e69711ce1 100644 --- a/net/openvswitch/flow.h +++ b/net/openvswitch/flow.h | |||
| @@ -114,6 +114,7 @@ struct sw_flow_key { | |||
| 114 | struct { | 114 | struct { |
| 115 | /* Connection tracking fields. */ | 115 | /* Connection tracking fields. */ |
| 116 | u16 zone; | 116 | u16 zone; |
| 117 | u32 mark; | ||
| 117 | u8 state; | 118 | u8 state; |
| 118 | } ct; | 119 | } ct; |
| 119 | 120 | ||
diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c index 4e795b289eb7..b17a4ec348f9 100644 --- a/net/openvswitch/flow_netlink.c +++ b/net/openvswitch/flow_netlink.c | |||
| @@ -281,7 +281,7 @@ size_t ovs_key_attr_size(void) | |||
| 281 | /* Whenever adding new OVS_KEY_ FIELDS, we should consider | 281 | /* Whenever adding new OVS_KEY_ FIELDS, we should consider |
| 282 | * updating this function. | 282 | * updating this function. |
| 283 | */ | 283 | */ |
| 284 | BUILD_BUG_ON(OVS_KEY_ATTR_TUNNEL_INFO != 24); | 284 | BUILD_BUG_ON(OVS_KEY_ATTR_TUNNEL_INFO != 25); |
| 285 | 285 | ||
| 286 | return nla_total_size(4) /* OVS_KEY_ATTR_PRIORITY */ | 286 | return nla_total_size(4) /* OVS_KEY_ATTR_PRIORITY */ |
| 287 | + nla_total_size(0) /* OVS_KEY_ATTR_TUNNEL */ | 287 | + nla_total_size(0) /* OVS_KEY_ATTR_TUNNEL */ |
| @@ -292,6 +292,7 @@ size_t ovs_key_attr_size(void) | |||
| 292 | + nla_total_size(4) /* OVS_KEY_ATTR_RECIRC_ID */ | 292 | + nla_total_size(4) /* OVS_KEY_ATTR_RECIRC_ID */ |
| 293 | + nla_total_size(1) /* OVS_KEY_ATTR_CT_STATE */ | 293 | + nla_total_size(1) /* OVS_KEY_ATTR_CT_STATE */ |
| 294 | + nla_total_size(2) /* OVS_KEY_ATTR_CT_ZONE */ | 294 | + nla_total_size(2) /* OVS_KEY_ATTR_CT_ZONE */ |
| 295 | + nla_total_size(4) /* OVS_KEY_ATTR_CT_MARK */ | ||
| 295 | + nla_total_size(12) /* OVS_KEY_ATTR_ETHERNET */ | 296 | + nla_total_size(12) /* OVS_KEY_ATTR_ETHERNET */ |
| 296 | + nla_total_size(2) /* OVS_KEY_ATTR_ETHERTYPE */ | 297 | + nla_total_size(2) /* OVS_KEY_ATTR_ETHERTYPE */ |
| 297 | + nla_total_size(4) /* OVS_KEY_ATTR_VLAN */ | 298 | + nla_total_size(4) /* OVS_KEY_ATTR_VLAN */ |
| @@ -343,6 +344,7 @@ static const struct ovs_len_tbl ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = { | |||
| 343 | [OVS_KEY_ATTR_MPLS] = { .len = sizeof(struct ovs_key_mpls) }, | 344 | [OVS_KEY_ATTR_MPLS] = { .len = sizeof(struct ovs_key_mpls) }, |
| 344 | [OVS_KEY_ATTR_CT_STATE] = { .len = sizeof(u8) }, | 345 | [OVS_KEY_ATTR_CT_STATE] = { .len = sizeof(u8) }, |
| 345 | [OVS_KEY_ATTR_CT_ZONE] = { .len = sizeof(u16) }, | 346 | [OVS_KEY_ATTR_CT_ZONE] = { .len = sizeof(u16) }, |
| 347 | [OVS_KEY_ATTR_CT_MARK] = { .len = sizeof(u32) }, | ||
| 346 | }; | 348 | }; |
| 347 | 349 | ||
| 348 | static bool is_all_zero(const u8 *fp, size_t size) | 350 | static bool is_all_zero(const u8 *fp, size_t size) |
| @@ -787,6 +789,13 @@ static int metadata_from_nlattrs(struct sw_flow_match *match, u64 *attrs, | |||
| 787 | SW_FLOW_KEY_PUT(match, ct.zone, ct_zone, is_mask); | 789 | SW_FLOW_KEY_PUT(match, ct.zone, ct_zone, is_mask); |
| 788 | *attrs &= ~(1ULL << OVS_KEY_ATTR_CT_ZONE); | 790 | *attrs &= ~(1ULL << OVS_KEY_ATTR_CT_ZONE); |
| 789 | } | 791 | } |
| 792 | if (*attrs & (1 << OVS_KEY_ATTR_CT_MARK) && | ||
| 793 | ovs_ct_verify(OVS_KEY_ATTR_CT_MARK)) { | ||
| 794 | u32 mark = nla_get_u32(a[OVS_KEY_ATTR_CT_MARK]); | ||
| 795 | |||
| 796 | SW_FLOW_KEY_PUT(match, ct.mark, mark, is_mask); | ||
| 797 | *attrs &= ~(1ULL << OVS_KEY_ATTR_CT_MARK); | ||
| 798 | } | ||
| 790 | return 0; | 799 | return 0; |
| 791 | } | 800 | } |
| 792 | 801 | ||
| @@ -1919,6 +1928,7 @@ static int validate_set(const struct nlattr *a, | |||
| 1919 | 1928 | ||
| 1920 | case OVS_KEY_ATTR_PRIORITY: | 1929 | case OVS_KEY_ATTR_PRIORITY: |
| 1921 | case OVS_KEY_ATTR_SKB_MARK: | 1930 | case OVS_KEY_ATTR_SKB_MARK: |
| 1931 | case OVS_KEY_ATTR_CT_MARK: | ||
| 1922 | case OVS_KEY_ATTR_ETHERNET: | 1932 | case OVS_KEY_ATTR_ETHERNET: |
| 1923 | break; | 1933 | break; |
| 1924 | 1934 | ||
