lkml.org 
[lkml]   [2015]   [Jul]   [30]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH net-next 6/9] openvswitch: Allow matching on conntrack mark
    Date
    From: Justin Pettit <jpettit@nicira.com>

    Allow matching and setting the conntrack mark field. As with conntrack
    state and zone, these are populated by executing the ct() action. Unlike
    these, the ct_mark is also a writable field. The set_field() action may
    be used to modify the mark, which will take effect on the most recent
    conntrack entry.

    E.g.: actions:ct(zone=0),ct(zone=1),set_field(1->ct_mark)

    This will perform conntrack lookup in zone 0, then lookup in zone 1,
    then modify the mark for the entry in zone 1. The mark for the entry in
    zone 0 is unchanged. The conntrack entry itself must be committed using
    the "commit" flag in the conntrack action flags for this change to persist.

    Signed-off-by: Justin Pettit <jpettit@nicira.com>
    Signed-off-by: Joe Stringer <joestringer@nicira.com>
    ---
    include/uapi/linux/openvswitch.h | 1 +
    net/openvswitch/actions.c | 6 ++++++
    net/openvswitch/conntrack.c | 40 ++++++++++++++++++++++++++++++++++++++++
    net/openvswitch/conntrack.h | 14 ++++++++++++++
    net/openvswitch/flow.c | 1 +
    net/openvswitch/flow.h | 1 +
    net/openvswitch/flow_netlink.c | 15 ++++++++++++++-
    7 files changed, 77 insertions(+), 1 deletion(-)

    diff --git a/include/uapi/linux/openvswitch.h b/include/uapi/linux/openvswitch.h
    index 1dae30a..207788c 100644
    --- a/include/uapi/linux/openvswitch.h
    +++ b/include/uapi/linux/openvswitch.h
    @@ -325,6 +325,7 @@ enum ovs_key_attr {
    * the accepted length of the array. */
    OVS_KEY_ATTR_CT_STATE, /* u8 bitmask of OVS_CS_F_* */
    OVS_KEY_ATTR_CT_ZONE, /* u16 connection tracking zone. */
    + OVS_KEY_ATTR_CT_MARK, /* u32 connection tracking mark */

    #ifdef __KERNEL__
    OVS_KEY_ATTR_TUNNEL_INFO, /* struct ip_tunnel_info */
    diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
    index 4a62ed4..77b01f5 100644
    --- a/net/openvswitch/actions.c
    +++ b/net/openvswitch/actions.c
    @@ -944,6 +944,12 @@ static int execute_masked_set_action(struct sk_buff *skb,
    err = set_mpls(skb, flow_key, nla_data(a), get_mask(a,
    __be32 *));
    break;
    +
    + case OVS_KEY_ATTR_CT_MARK:
    + err = ovs_ct_set_mark(skb, flow_key, nla_get_u32(a),
    + *get_mask(a, u32 *));
    + break;
    +
    }

    return err;
    diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c
    index 284b89e..6dc68dc 100644
    --- a/net/openvswitch/conntrack.c
    +++ b/net/openvswitch/conntrack.c
    @@ -114,6 +114,15 @@ u16 ovs_ct_get_zone(const struct sk_buff *skb)
    return ct ? nf_ct_zone(ct) : NF_CT_DEFAULT_ZONE;
    }

    +u32 ovs_ct_get_mark(const struct sk_buff *skb)
    +{
    + enum ip_conntrack_info ctinfo;
    + struct nf_conn *ct;
    +
    + ct = nf_ct_get(skb, &ctinfo);
    + return ct ? ct->mark : 0;
    +}
    +
    static bool __ovs_ct_state_valid(u8 state)
    {
    return (state && !(state & OVS_CS_F_INVALID));
    @@ -207,6 +216,7 @@ static void __ovs_ct_update_key(struct sk_buff *skb, struct sw_flow_key *key,
    {
    key->ct.state = state;
    key->ct.zone = zone;
    + key->ct.mark = ovs_ct_get_mark(skb);
    }

    static void ovs_ct_update_key(struct sk_buff *skb, struct sw_flow_key *key,
    @@ -340,6 +350,32 @@ int ovs_ct_execute(struct sk_buff *skb, struct sw_flow_key *key,
    return err;
    }

    +int ovs_ct_set_mark(struct sk_buff *skb, struct sw_flow_key *key,
    + u32 ct_mark, u32 mask)
    +{
    +#ifdef CONFIG_NF_CONNTRACK_MARK
    + enum ip_conntrack_info ctinfo;
    + struct nf_conn *ct;
    + u32 new_mark;
    +
    + /* This must happen directly after lookup/commit. */
    + ct = nf_ct_get(skb, &ctinfo);
    + if (!ct)
    + return -EINVAL;
    +
    + new_mark = ct_mark | (ct->mark & ~(mask));
    + if (ct->mark != new_mark) {
    + ct->mark = new_mark;
    + nf_conntrack_event_cache(IPCT_MARK, ct);
    + key->ct.mark = ct_mark;
    + }
    +
    + return 0;
    +#else
    + return -ENOTSUPP;
    +#endif
    +}
    +
    static const struct ovs_ct_len_tbl ovs_ct_attr_lens[OVS_CT_ATTR_MAX + 1] = {
    [OVS_CT_ATTR_FLAGS] = { .minlen = sizeof(u32),
    .maxlen = sizeof(u32) },
    @@ -403,6 +439,10 @@ bool ovs_ct_verify(enum ovs_key_attr attr)
    if (attr & OVS_KEY_ATTR_CT_ZONE)
    return true;
    #endif
    +#ifdef CONFIG_NF_CONNTRACK_MARK
    + if (attr & OVS_KEY_ATTR_CT_MARK)
    + return true;
    +#endif

    return false;
    }
    diff --git a/net/openvswitch/conntrack.h b/net/openvswitch/conntrack.h
    index 7a01751..03a1ec5 100644
    --- a/net/openvswitch/conntrack.h
    +++ b/net/openvswitch/conntrack.h
    @@ -31,6 +31,9 @@ int ovs_ct_action_to_attr(const struct ovs_conntrack_info *, struct sk_buff *);
    int ovs_ct_execute(struct sk_buff *, struct sw_flow_key *,
    const struct ovs_conntrack_info *);

    +int ovs_ct_set_mark(struct sk_buff *, struct sw_flow_key *, u32 ct_mark,
    + u32 mask);
    +u32 ovs_ct_get_mark(const struct sk_buff *skb);
    u8 ovs_ct_get_state(const struct sk_buff *skb);
    u16 ovs_ct_get_zone(const struct sk_buff *skb);
    bool ovs_ct_state_valid(const struct sw_flow_key *key);
    @@ -72,11 +75,22 @@ static inline u16 ovs_ct_get_zone(const struct sk_buff *skb)
    return 0;
    }

    +static inline u32 ovs_ct_get_mark(const struct sk_buff *skb)
    +{
    + return 0;
    +}
    +
    static inline bool ovs_ct_state_valid(const struct sw_flow_key *key)
    {
    return false;
    }

    +static inline int ovs_ct_set_mark(struct sk_buff *skb, struct sw_flow_key *key,
    + u32 ct_mark, u32 mask)
    +{
    + return -ENOTSUPP;
    +}
    +
    static inline void ovs_ct_free_action(const struct nlattr *a) { }
    #endif
    #endif /* ovs_conntrack.h */
    diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c
    index 131b807..05ce284 100644
    --- a/net/openvswitch/flow.c
    +++ b/net/openvswitch/flow.c
    @@ -710,6 +710,7 @@ int ovs_flow_key_extract(const struct ip_tunnel_info *tun_info,
    key->phy.skb_mark = skb->mark;
    key->ct.state = ovs_ct_get_state(skb);
    key->ct.zone = ovs_ct_get_zone(skb);
    + key->ct.mark = ovs_ct_get_mark(skb);
    key->ovs_flow_hash = 0;
    key->recirc_id = 0;

    diff --git a/net/openvswitch/flow.h b/net/openvswitch/flow.h
    index 312c7d7..e05e697 100644
    --- a/net/openvswitch/flow.h
    +++ b/net/openvswitch/flow.h
    @@ -114,6 +114,7 @@ struct sw_flow_key {
    struct {
    /* Connection tracking fields. */
    u16 zone;
    + u32 mark;
    u8 state;
    } ct;

    diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c
    index 4eeaa5a..90e80a6 100644
    --- a/net/openvswitch/flow_netlink.c
    +++ b/net/openvswitch/flow_netlink.c
    @@ -282,7 +282,7 @@ size_t ovs_key_attr_size(void)
    /* Whenever adding new OVS_KEY_ FIELDS, we should consider
    * updating this function.
    */
    - BUILD_BUG_ON(OVS_KEY_ATTR_TUNNEL_INFO != 24);
    + BUILD_BUG_ON(OVS_KEY_ATTR_TUNNEL_INFO != 25);

    return nla_total_size(4) /* OVS_KEY_ATTR_PRIORITY */
    + nla_total_size(0) /* OVS_KEY_ATTR_TUNNEL */
    @@ -293,6 +293,7 @@ size_t ovs_key_attr_size(void)
    + nla_total_size(4) /* OVS_KEY_ATTR_RECIRC_ID */
    + nla_total_size(1) /* OVS_KEY_ATTR_CT_STATE */
    + nla_total_size(2) /* OVS_KEY_ATTR_CT_ZONE */
    + + nla_total_size(4) /* OVS_KEY_ATTR_CT_MARK */
    + nla_total_size(12) /* OVS_KEY_ATTR_ETHERNET */
    + nla_total_size(2) /* OVS_KEY_ATTR_ETHERTYPE */
    + nla_total_size(4) /* OVS_KEY_ATTR_VLAN */
    @@ -344,6 +345,7 @@ static const struct ovs_len_tbl ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = {
    [OVS_KEY_ATTR_MPLS] = { .len = sizeof(struct ovs_key_mpls) },
    [OVS_KEY_ATTR_CT_STATE] = { .len = sizeof(u8) },
    [OVS_KEY_ATTR_CT_ZONE] = { .len = sizeof(u16) },
    + [OVS_KEY_ATTR_CT_MARK] = { .len = sizeof(u32) },
    };

    static bool is_all_zero(const u8 *fp, size_t size)
    @@ -788,6 +790,13 @@ static int metadata_from_nlattrs(struct sw_flow_match *match, u64 *attrs,
    SW_FLOW_KEY_PUT(match, ct.zone, ct_zone, is_mask);
    *attrs &= ~(1ULL << OVS_KEY_ATTR_CT_ZONE);
    }
    + if (*attrs & (1 << OVS_KEY_ATTR_CT_MARK) &&
    + ovs_ct_verify(OVS_KEY_ATTR_CT_MARK)) {
    + uint32_t mark = nla_get_u32(a[OVS_KEY_ATTR_CT_MARK]);
    +
    + SW_FLOW_KEY_PUT(match, ct.mark, mark, is_mask);
    + *attrs &= ~(1ULL << OVS_KEY_ATTR_CT_MARK);
    + }
    return 0;
    }

    @@ -1341,6 +1350,9 @@ static int __ovs_nla_put_key(const struct sw_flow_key *swkey,
    if (nla_put_u16(skb, OVS_KEY_ATTR_CT_ZONE, output->ct.zone))
    goto nla_put_failure;

    + if (nla_put_u32(skb, OVS_KEY_ATTR_CT_MARK, output->ct.mark))
    + goto nla_put_failure;
    +
    nla = nla_reserve(skb, OVS_KEY_ATTR_ETHERNET, sizeof(*eth_key));
    if (!nla)
    goto nla_put_failure;
    @@ -1923,6 +1935,7 @@ static int validate_set(const struct nlattr *a,

    case OVS_KEY_ATTR_PRIORITY:
    case OVS_KEY_ATTR_SKB_MARK:
    + case OVS_KEY_ATTR_CT_MARK:
    case OVS_KEY_ATTR_ETHERNET:
    break;

    --
    2.1.4


    \
     
     \ /
      Last update: 2015-07-30 20:21    [W:4.400 / U:0.592 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site