[ovs-dev] [PATCH 1/4] datapath: Kernel support for provider VLANs
Avinash
avinashandrew at gmail.com
Tue Jun 10 13:33:24 UTC 2014
Kernel recognizes and accepts ethertype of provider VLANs (ETH_P_8021AD)
along with normal VLAN (ETH_P_8021Q). Also in flow key formation,
only the outermost VLAN is considered. Remaining stacked VLANs are skipped.
Signed-off-by: Avinash <avinashandrew at gmail.com>
---
datapath/actions.c | 10 ++++++----
datapath/flow.c | 34 ++++++++++++++++++++++++++++++++--
datapath/flow_netlink.c | 17 +++++++++++++----
3 files changed, 51 insertions(+), 10 deletions(-)
diff --git a/datapath/actions.c b/datapath/actions.c
index 603c7cb..8dd11a0 100644
--- a/datapath/actions.c
+++ b/datapath/actions.c
@@ -84,8 +84,9 @@ static int pop_vlan(struct sk_buff *skb)
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);
@@ -93,8 +94,9 @@ static int pop_vlan(struct sk_buff *skb)
return err;
}
/* move next vlan tag to hw accel tag */
- if (likely(skb->protocol != htons(ETH_P_8021Q) ||
- skb->len < VLAN_ETH_HLEN))
+ if (likely((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);
diff --git a/datapath/flow.c b/datapath/flow.c
index c52081b..c64dfe4 100644
--- a/datapath/flow.c
+++ b/datapath/flow.c
@@ -290,7 +290,7 @@ 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;
@@ -309,6 +309,32 @@ static int parse_vlan(struct sk_buff *skb, struct
sw_flow_key *key)
return 0;
}
+static int parse_remaining_vlans(struct sk_buff *skb)
+{
+ struct qtag_prefix {
+ __be16 eth_type;
+ __be16 tci;
+ };
+
+ struct qtag_prefix *qp;
+ if (unlikely(skb->len < sizeof(struct qtag_prefix) + sizeof(__be16)))
+ return 0;
+
+ if (unlikely(!pskb_may_pull(skb, sizeof(struct qtag_prefix) +
+ sizeof(__be16))))
+ return -ENOMEM;
+
+ qp = (struct qtag_prefix *) skb->data;
+ while ((qp->eth_type == htons(ETH_P_8021Q) ||
+ qp->eth_type == htons(ETH_P_8021AD)))
+ {
+ __skb_pull(skb, sizeof(struct qtag_prefix));
+ qp = (struct qtag_prefix *) skb->data;
+ }
+
+ return 0;
+}
+
static __be16 parse_ethertype(struct sk_buff *skb)
{
struct llc_snap_hdr {
@@ -471,10 +497,14 @@ int ovs_flow_extract(struct sk_buff *skb, u16
in_port, struct sw_flow_key *key)
if (vlan_tx_tag_present(skb))
key->eth.tci = htons(vlan_get_tci(skb));
- else if (eth->h_proto == htons(ETH_P_8021Q))
+ else if (eth->h_proto == htons(ETH_P_8021Q) ||
+ eth->h_proto == htons(ETH_P_8021AD))
if (unlikely(parse_vlan(skb, key)))
return -ENOMEM;
+ if (unlikely(parse_remaining_vlans(skb)))
+ return -ENOMEM;
+
key->eth.type = parse_ethertype(skb);
if (unlikely(key->eth.type == htons(0)))
return -ENOMEM;
diff --git a/datapath/flow_netlink.c b/datapath/flow_netlink.c
index 803a94c..54b13fc 100644
--- a/datapath/flow_netlink.c
+++ b/datapath/flow_netlink.c
@@ -764,7 +764,8 @@ int ovs_nla_get_match(struct sw_flow_match *match,
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))) {
+ ((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;
if (!((key_attrs & (1ULL << OVS_KEY_ATTR_VLAN)) &&
@@ -937,9 +938,16 @@ int ovs_nla_put_flow(const struct sw_flow_key *swkey,
ether_addr_copy(eth_key->eth_src, output->eth.src);
ether_addr_copy(eth_key->eth_dst, output->eth.dst);
- if (swkey->eth.tci || swkey->eth.type == htons(ETH_P_8021Q)) {
+ if (swkey->eth.tci || swkey->eth.type == htons(ETH_P_8021Q)
+ || swkey->eth.type == htons(ETH_P_8021AD)) {
__be16 eth_type;
- eth_type = !is_mask ? htons(ETH_P_8021Q) : htons(0xffff);
+ if (is_mask)
+ eth_type = htons(0xffff);
+ else
+ eth_type = (swkey->eth.type == htons(ETH_P_8021AD))
+ ? htons(ETH_P_8021AD)
+ : htons(ETH_P_8021Q);
+
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;
@@ -1493,7 +1501,8 @@ 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;
--
1.9.0
More information about the dev
mailing list