On Tuesday, December 30, 2014 10:12:59 AM you wrote:
> This is the linux kernel datapath portion of the 802.1AD patch.
> 
> 
> Signed-off-by: Thomas F Herbert <thomasfherb...@entpnt.com>
> 
> ---
>  datapath/actions.c                                | 32 ++++++---
>  datapath/flow.c                                   | 80 
> +++++++++++++++++++----
>  datapath/flow.h                                   |  1 +
>  datapath/flow_netlink.c                           | 62 ++++++++++++++++--
>  datapath/linux/compat/include/linux/openvswitch.h | 16 ++---
>  5 files changed, 153 insertions(+), 38 deletions(-)
> 
> diff --git a/datapath/actions.c b/datapath/actions.c
> index 5a1dbe2..baa82e6 100644
> --- a/datapath/actions.c
> +++ b/datapath/actions.c
> @@ -250,17 +250,18 @@ static int __pop_vlan_tci(struct sk_buff *skb, __be16 
> *current_tci)
>  
>       return 0;
>  }
> -
>  static int pop_vlan(struct sk_buff *skb, struct sw_flow_key *key)
>  {
>       __be16 tci;
>       int err;
> +     __be16 prot;
>  
>       if (likely(vlan_tx_tag_present(skb))) {
>               vlan_set_tci(skb, 0);
>       } else {
> -             if (unlikely(skb->protocol != htons(ETH_P_8021Q) ||
> -                          skb->len < VLAN_ETH_HLEN))
> +             if (unlikely(((skb->protocol != htons(ETH_P_8021Q)) &&
> +                     (skb->protocol != htons(ETH_P_8021AD))) ||
> +                             (skb->len < VLAN_ETH_HLEN)))
>                       return 0;
>  
>               err = __pop_vlan_tci(skb, &tci);
> @@ -269,9 +270,9 @@ static int pop_vlan(struct sk_buff *skb, struct 
> sw_flow_key *key)
>       }
>       /* move next vlan tag to hw accel tag */
>       if (likely(skb->protocol != htons(ETH_P_8021Q) ||
> -                skb->len < VLAN_ETH_HLEN)) {
> -             key->eth.tci = 0;
> -             return 0;
> +             skb->len < VLAN_ETH_HLEN)) {
> +                     key->eth.tci = 0;
> +                     return 0;
>       }

Please, don't mix up with code cleanups.



>       invalidate_flow_key(key);
> @@ -279,7 +280,13 @@ static int pop_vlan(struct sk_buff *skb, struct 
> sw_flow_key *key)
>       if (unlikely(err))
>               return err;
>  
> -     __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ntohs(tci));
> +     if (unlikely(skb->protocol == htons(ETH_P_8021AD)))
> +             prot = htons(ETH_P_8021AD);
> +        else
> +             prot = htons(ETH_P_8021Q);
> +
> +     __vlan_hwaccel_put_tag(skb, prot, ntohs(tci));
> +

Why not simply:
      __vlan_hwaccel_put_tag(skb, skb->protocol, ntohs(tci));


>       return 0;
>  }
>  
> @@ -297,15 +304,20 @@ static int push_vlan(struct sk_buff *skb, struct 
> sw_flow_key *key,
>               /* Update mac_len for subsequent MPLS actions */
>               skb->mac_len += VLAN_HLEN;
>  
> -             if (skb->ip_summed == CHECKSUM_COMPLETE)
> -                     skb->csum = csum_add(skb->csum, csum_partial(skb->data
> +             skb->csum = csum_add(skb->csum, csum_partial(skb->data
>                                       + (2 * ETH_ALEN), VLAN_HLEN, 0));

Could you elaborate on the above change?  I don't see why
the checksum is needed in all cases.


>               invalidate_flow_key(key);
>       } else {
>               key->eth.tci = vlan->vlan_tci;
>       }
> -     __vlan_hwaccel_put_tag(skb, vlan->vlan_tpid, ntohs(vlan->vlan_tci) & 
> ~VLAN_TAG_PRESENT);
> +
> +        if (likely(vlan->vlan_tpid == htons(ETH_P_8021Q))) {
> +             __vlan_hwaccel_put_tag(skb, vlan->vlan_tpid, 
> ntohs(vlan->vlan_tci) & ~VLAN_TAG_PRESENT);
> +        } else {
> +             __vlan_put_tag(skb, vlan->vlan_tpid, ntohs(vlan->vlan_tci) & 
> ~VLAN_TAG_PRESENT);
> +             skb->vlan_tci &= ~VLAN_TAG_PRESENT;
> +     }
>       return 0;

break long lines?

>  
> diff --git a/datapath/flow.c b/datapath/flow.c
> index 69b13b3..d549fae 100644
> --- a/datapath/flow.c
> +++ b/datapath/flow.c
> @@ -296,21 +296,75 @@ static bool icmp6hdr_ok(struct sk_buff *skb)
>  static int parse_vlan(struct sk_buff *skb, struct sw_flow_key *key)
>  {
>       struct qtag_prefix {
> -             __be16 eth_type; /* ETH_P_8021Q */
> +             __be16 eth_type; /* ETH_P_8021Q  or ETH_P_8021AD */
>               __be16 tci;
>       };
> -     struct qtag_prefix *qp;
> +     struct qtag_prefix *qp = (struct qtag_prefix *) skb->data;
>  
> -     if (unlikely(skb->len < sizeof(struct qtag_prefix) + sizeof(__be16)))
> -             return 0;
> +     struct qinqtag_prefix {
> +             __be16 eth_type; /* ETH_P_8021Q  or ETH_P_8021AD */
> +             __be16 tci;
> +             __be16 encapsulated_proto; /* ETH_P_8021Q */
> +             __be16 ctci;
> +     };
>  
> -     if (unlikely(!pskb_may_pull(skb, sizeof(struct qtag_prefix) +
> -                                      sizeof(__be16))))
> -             return -ENOMEM;
> +     if (likely(skb->vlan_tci | htons(VLAN_TAG_PRESENT))) {
> +
> +             key->eth.tci = skb->vlan_tci | htons(VLAN_TAG_PRESENT);
> +
> +             if(unlikely(skb->vlan_proto == htons(ETH_P_8021AD))) {
                 ^ missing space


> +                     struct qtag_prefix *qp = (struct qtag_prefix *) 
> skb->data;
 
again?

> +
> +                     if (unlikely(skb->len < sizeof(struct qtag_prefix) +
> +                                     sizeof(__be16)))
> +                             return 0;

This check is included in the pskb_may_pull() below.

> +
> +                     if (unlikely(!pskb_may_pull(skb, sizeof(struct 
> qtag_prefix) +
> +                                     sizeof(__be16)))) {
> +                             return -ENOMEM;
> +                     }
> +

I'd suggest to use offsetof(struct  qtag_prefix, ctci), but I am not really
sure if it's portable. Or simply define the ctci_offset above as 
sizeof(struct qtag_prefix) + sizeof(__be16) for better readability.

> +                     if (likely(qp->eth_type == htons(ETH_P_8021Q))) {
> +                             key->eth.ctci = qp->tci | 
> htons(VLAN_TAG_PRESENT);
> +                             __skb_pull(skb, sizeof(struct qtag_prefix));
> +                     }
> +             }
> +                return 0;
> +     }
> +
> +
> +        if (qp->eth_type == htons(ETH_P_8021AD)) {
> +             struct qinqtag_prefix *qinqp = (struct qinqtag_prefix *) 
> skb->data;
>  
> -     qp = (struct qtag_prefix *) skb->data;
> -     key->eth.tci = qp->tci | htons(VLAN_TAG_PRESENT);
> -     __skb_pull(skb, sizeof(struct qtag_prefix));
> +             if (unlikely(skb->len < sizeof(struct qinqtag_prefix) +
> +                                     sizeof(__be16)))
> +                     return 0;
> +
> +             if (unlikely(!pskb_may_pull(skb, sizeof(struct qinqtag_prefix) +
> +                             sizeof(__be16)))) {
> +                     return -ENOMEM;
> +             }

Same above

> +             key->eth.tci = qinqp->tci | htons(VLAN_TAG_PRESENT);
> +             key->eth.ctci = qinqp->ctci | htons(VLAN_TAG_PRESENT);
> +
> +             __skb_pull(skb, sizeof(struct qinqtag_prefix));
> +
> +                return 0;
> +
> +     }
> +        if (qp->eth_type == htons(ETH_P_8021Q)) {
> +
> +             if (unlikely(skb->len < sizeof(struct qtag_prefix) +
> +                                     sizeof(__be16)))
> +                     return -ENOMEM;
> +
> +             if (unlikely(!pskb_may_pull(skb, sizeof(struct qtag_prefix) +
> +                             sizeof(__be16))))
> +                     return 0;
> +             key->eth.tci = qp->tci | htons(VLAN_TAG_PRESENT);
> +
> +             __skb_pull(skb, sizeof(struct qtag_prefix));
> +     }
>  
>       return 0;
>  }
> @@ -472,9 +526,9 @@ static int key_extract(struct sk_buff *skb, struct 
> sw_flow_key *key)
>        */
>  
>       key->eth.tci = 0;
> -     if (vlan_tx_tag_present(skb))
> -             key->eth.tci = htons(vlan_get_tci(skb));
> -     else if (eth->h_proto == htons(ETH_P_8021Q))
> +     if ((vlan_tx_tag_present(skb)) ||
> +             (eth->h_proto == htons(ETH_P_8021Q)) ||
> +             (eth->h_proto == htons(ETH_P_8021AD)))
>               if (unlikely(parse_vlan(skb, key)))
>                       return -ENOMEM;
>  
> diff --git a/datapath/flow.h b/datapath/flow.h
> index 2bbf789..0bf0477 100644
> --- a/datapath/flow.h
> +++ b/datapath/flow.h
> @@ -134,6 +134,7 @@ struct sw_flow_key {
>               u8     src[ETH_ALEN];   /* Ethernet source address. */
>               u8     dst[ETH_ALEN];   /* Ethernet destination address. */
>               __be16 tci;             /* 0 if no VLAN, VLAN_TAG_PRESENT set 
> otherwise. */
> +             __be16 ctci;            /* 0 if no VLAN, VLAN_TAG_PRESENT set 
> otherwise. */
>               __be16 type;            /* Ethernet frame type. */
>       } eth;
>       union {
> diff --git a/datapath/flow_netlink.c b/datapath/flow_netlink.c
> index c611e71..2e307ba 100644
> --- a/datapath/flow_netlink.c
> +++ b/datapath/flow_netlink.c
> @@ -274,7 +274,7 @@ size_t ovs_key_attr_size(void)
>  
>       return    nla_total_size(4)   /* OVS_KEY_ATTR_PRIORITY */
>               + nla_total_size(0)   /* OVS_KEY_ATTR_TUNNEL */
> -               + ovs_tun_key_attr_size()
> +             + ovs_tun_key_attr_size()

please, no code cleanups

>               + nla_total_size(4)   /* OVS_KEY_ATTR_IN_PORT */
>               + nla_total_size(4)   /* OVS_KEY_ATTR_SKB_MARK */
>               + nla_total_size(4)   /* OVS_KEY_ATTR_DP_HASH */
> @@ -681,6 +681,28 @@ static int metadata_from_nlattrs(struct sw_flow_match 
> *match,  u64 *attrs,
>       }
>       return 0;
>  }
> +static int ovs_nested_vlan_from_nlattrs(struct sw_flow_match *match,
> +                                     u64 attrs, const struct nlattr **a,
> +                                     bool is_mask, bool log)
> +{
> +     if (attrs & (1ULL << OVS_KEY_ATTR_VLAN)) { /* This should be nested 
> inner or "customer" tci" */

line is too long, perhaps put the comment above the if() ?

> +             __be16 ctci;
> +
> +             ctci = nla_get_be16(a[OVS_KEY_ATTR_VLAN]);
> +             if (!(ctci & htons(VLAN_TAG_PRESENT))) {
> +                     if (is_mask)
> +                             OVS_NLERR(log, "VLAN TCI mask does not have 
> exact match for VLAN_TAG_PRESENT bit.");
> +                     else
> +                             OVS_NLERR(log, "VLAN TCI does not have 
> VLAN_TAG_PRESENT bit set.");
> +
> +                     return -EINVAL;
> +             }
> +
> +             SW_FLOW_KEY_PUT(match, eth.ctci, ctci, is_mask);
> +             attrs &= ~(1ULL << OVS_KEY_ATTR_VLAN);
> +     }
> +     return 0;
> +}
>  
>  static int ovs_key_from_nlattrs(struct sw_flow_match *match, u64 attrs,
>                               const struct nlattr **a, bool is_mask,
> @@ -720,6 +742,7 @@ static int ovs_key_from_nlattrs(struct sw_flow_match 
> *match, u64 attrs,
>               attrs &= ~(1ULL << OVS_KEY_ATTR_VLAN);
>       }
>  
> +

extra line...

>       if (attrs & (1ULL << OVS_KEY_ATTR_ETHERTYPE)) {
>               __be16 eth_type;
>  
> @@ -969,8 +992,9 @@ int ovs_nla_get_match(struct sw_flow_match *match,
>               return err;
>  
>       if ((key_attrs & (1ULL << OVS_KEY_ATTR_ETHERNET)) &&
> -         (key_attrs & (1ULL << OVS_KEY_ATTR_ETHERTYPE)) &&
> -         (nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE]) == htons(ETH_P_8021Q))) {
> +             (key_attrs & (1ULL << OVS_KEY_ATTR_ETHERTYPE)) &&
> +                     ((nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE]) == 
> htons(ETH_P_8021Q)) ||
> +                     (nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE]) == 
> htons(ETH_P_8021AD)))) {
>               __be16 tci;

The indentation here is odd.

>               if (!((key_attrs & (1ULL << OVS_KEY_ATTR_VLAN)) &&
> @@ -986,9 +1010,23 @@ int ovs_nla_get_match(struct sw_flow_match *match,
>               encap_valid = true;
>  
>               if (tci & htons(VLAN_TAG_PRESENT)) {
> -                     err = parse_flow_nlattrs(encap, a, &key_attrs, log);
> -                     if (err)
> -                             return err;
> +                     u64 v_attrs = 0;
> +
> +                     if (unlikely((nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE]) 
> == htons(ETH_P_8021AD)))) {
> +
> +                             err = parse_flow_nlattrs(encap, a, &v_attrs, 
> log);

break long lines?

> +                             if (err)
> +                                     return err;
> +                             if (v_attrs) {
> +                                     err = 
> ovs_nested_vlan_from_nlattrs(match, v_attrs, a, false, log);
> +                                     if (err)
> +                                             return err;
> +                             }
> +                     } else {
> +                             err = parse_flow_nlattrs(encap, a, &key_attrs, 
> log);
> +                             if (err)
> +                                     return err;
> +                     }
>               } else if (!tci) {
>                       /* Corner case for truncated 802.1Q header. */
>                       if (nla_len(encap)) {
> @@ -1191,6 +1229,15 @@ int ovs_nla_put_flow(const struct sw_flow_key *swkey,
>               encap = nla_nest_start(skb, OVS_KEY_ATTR_ENCAP);
>               if (!swkey->eth.tci)
>                       goto unencap;
> +     } else if (swkey->eth.tci || swkey->eth.type == htons(ETH_P_8021AD)) {
> +             __be16 eth_type;
> +             eth_type = !is_mask ? htons(ETH_P_8021AD) : htons(0xffff);
> +             if (nla_put_be16(skb, OVS_KEY_ATTR_ETHERTYPE, eth_type) ||
> +                 nla_put_be16(skb, OVS_KEY_ATTR_VLAN, output->eth.tci))
> +                     goto nla_put_failure;
> +             encap = nla_nest_start(skb, OVS_KEY_ATTR_ENCAP);
> +             if (!swkey->eth.tci)
> +                     goto unencap;
>       } else
>               encap = NULL;
>  
> @@ -1828,7 +1875,8 @@ static int __ovs_nla_copy_actions(const struct nlattr 
> *attr,
>  
>               case OVS_ACTION_ATTR_PUSH_VLAN:
>                       vlan = nla_data(a);
> -                     if (vlan->vlan_tpid != htons(ETH_P_8021Q))
> +                     if ((vlan->vlan_tpid != htons(ETH_P_8021Q)) &&
> +                             (vlan->vlan_tpid != htons(ETH_P_8021AD)))
>                               return -EINVAL;
>                       if (!(vlan->vlan_tci & htons(VLAN_TAG_PRESENT)))
>                               return -EINVAL;
> diff --git a/datapath/linux/compat/include/linux/openvswitch.h 
> b/datapath/linux/compat/include/linux/openvswitch.h
> index 67715f8..6b5538a 100644
> --- a/datapath/linux/compat/include/linux/openvswitch.h
> +++ b/datapath/linux/compat/include/linux/openvswitch.h
> @@ -570,14 +570,14 @@ struct ovs_action_push_mpls {
>   * @vlan_tci: Tag control identifier (TCI) to push.  The CFI bit must be set
>   * (but it will not be set in the 802.1Q header that is pushed).
>   *
> - * The @vlan_tpid value is typically %ETH_P_8021Q.  The only acceptable TPID
> - * values are those that the kernel module also parses as 802.1Q headers, to
> - * prevent %OVS_ACTION_ATTR_PUSH_VLAN followed by %OVS_ACTION_ATTR_POP_VLAN
> - * from having surprising results.
> + * The @vlan_tpid value is typically %ETH_P_8021Q or %ETH_P_8021AD.
> + * The only acceptable TPID values are those that the kernel module also 
> parses
> + * as 802.1Q headers, to prevent %OVS_ACTION_ATTR_PUSH_VLAN followed by
> + * %OVS_ACTION_ATTR_POP_VLAN from having surprising results.
>   */
>  struct ovs_action_push_vlan {
> -     __be16 vlan_tpid;       /* 802.1Q TPID. */
> -     __be16 vlan_tci;        /* 802.1Q TCI (VLAN ID and priority). */
> +     __be16 vlan_tpid;       /* 802.1Q or 802.1ad TPID. */
> +     __be16 vlan_tci;        /* 802.1Q or 802.1ad TCI (VLAN ID and 
> priority). */
>  };
>  
>  /* Data path hash algorithm for computing Datapath hash.
> @@ -629,9 +629,9 @@ struct ovs_action_push_tnl {
>   * @OVS_ACTION_ATTR_OUTPUT: Output packet to port.
>   * @OVS_ACTION_ATTR_USERSPACE: Send packet to userspace according to nested
>   * %OVS_USERSPACE_ATTR_* attributes.
> - * @OVS_ACTION_ATTR_PUSH_VLAN: Push a new outermost 802.1Q header onto the
> + * @OVS_ACTION_ATTR_PUSH_VLAN: Push a new outermost 802.1Q or 802.1ad header 
> onto the
>   * packet.
> - * @OVS_ACTION_ATTR_POP_VLAN: Pop the outermost 802.1Q header off the packet.
> + * @OVS_ACTION_ATTR_POP_VLAN: Pop the outermost 802.1Q or 802.1ad header off 
> the packet.

Break long lines.

>   * @OVS_ACTION_ATTR_SAMPLE: Probabilitically executes actions, as specified 
> in
>   * the nested %OVS_SAMPLE_ATTR_* attributes.
>   * @OVS_ACTION_ATTR_SET: Replaces the contents of an existing header.  The
> 

Thanks
fbl
_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to