X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=datapath%2Fflow.c;h=e90b36a93b5a37f2171d540216a1f277b6f7cd52;hb=254f2dc8e3eb18debf4a8f238b9c87cf4d4dbd3f;hp=09bdcd1e2ef7b9f6de90a6ae49fa8e8f2179bc1b;hpb=36956a7d33c9ee204fcb184484a5aaacbd9ecef8;p=openvswitch diff --git a/datapath/flow.c b/datapath/flow.c index 09bdcd1e..e90b36a9 100644 --- a/datapath/flow.c +++ b/datapath/flow.c @@ -103,13 +103,11 @@ void flow_used(struct sw_flow *flow, struct sk_buff *skb) spin_unlock_bh(&flow->lock); } -struct sw_flow_actions *flow_actions_alloc(u32 actions_len) +struct sw_flow_actions *flow_actions_alloc(const struct nlattr *actions) { + int actions_len = nla_len(actions); struct sw_flow_actions *sfa; - if (actions_len % NLA_ALIGNTO) - return ERR_PTR(-EINVAL); - /* At least DP_MAX_PORTS actions are required to be able to flood a * packet to every port. Factor of 2 allows for setting VLAN tags, * etc. */ @@ -121,6 +119,7 @@ struct sw_flow_actions *flow_actions_alloc(u32 actions_len) return ERR_PTR(-ENOMEM); sfa->actions_len = actions_len; + memcpy(sfa->actions, nla_data(actions), actions_len); return sfa; } @@ -399,15 +398,15 @@ int flow_cmp(const struct tbl_node *node, void *key2_) /** * flow_from_nlattrs - parses Netlink attributes into a flow key. * @swkey: receives the extracted flow key. - * @key: start of %ODP_KEY_ATTR_* Netlink attribute sequence. - * @key_len: number of bytes in @key. + * @key: Netlink attribute holding nested %ODP_KEY_ATTR_* Netlink attribute + * sequence. * * This state machine accepts the following forms, with [] for optional * elements and | for alternatives: * * [tun_id] in_port ethernet [8021q] [ethertype [IP [TCP|UDP|ICMP] | ARP] */ -static int flow_from_nlattrs(struct sw_flow_key *swkey, const struct nlattr *key, u32 key_len) +int flow_from_nlattrs(struct sw_flow_key *swkey, const struct nlattr *attr) { const struct nlattr *nla; u16 prev_type; @@ -417,7 +416,7 @@ static int flow_from_nlattrs(struct sw_flow_key *swkey, const struct nlattr *key swkey->dl_type = htons(ETH_P_802_2); prev_type = ODP_KEY_ATTR_UNSPEC; - nla_for_each_attr(nla, key, key_len, rem) { + nla_for_each_nested(nla, attr, rem) { static const u32 key_lens[ODP_KEY_ATTR_MAX + 1] = { [ODP_KEY_ATTR_TUN_ID] = 8, [ODP_KEY_ATTR_IN_PORT] = 4, @@ -572,39 +571,43 @@ static int flow_from_nlattrs(struct sw_flow_key *swkey, const struct nlattr *key return -EINVAL; } -static u32 flow_to_nlattrs(const struct sw_flow_key *swkey, struct sk_buff *skb) +int flow_to_nlattrs(const struct sw_flow_key *swkey, struct sk_buff *skb) { struct odp_key_ethernet *eth_key; - - if (skb_tailroom(skb) < FLOW_BUFSIZE) - return -EMSGSIZE; + struct nlattr *nla; if (swkey->tun_id != cpu_to_be64(0)) - nla_put_be64(skb, ODP_KEY_ATTR_TUN_ID, swkey->tun_id); + NLA_PUT_BE64(skb, ODP_KEY_ATTR_TUN_ID, swkey->tun_id); - nla_put_u32(skb, ODP_KEY_ATTR_IN_PORT, swkey->in_port); + NLA_PUT_U32(skb, ODP_KEY_ATTR_IN_PORT, swkey->in_port); - eth_key = nla_data(__nla_reserve(skb, ODP_KEY_ATTR_ETHERNET, sizeof(*eth_key))); + nla = nla_reserve(skb, ODP_KEY_ATTR_ETHERNET, sizeof(*eth_key)); + if (!nla) + goto nla_put_failure; + eth_key = nla_data(nla); memcpy(eth_key->eth_src, swkey->dl_src, ETH_ALEN); memcpy(eth_key->eth_dst, swkey->dl_dst, ETH_ALEN); if (swkey->dl_tci != htons(0)) { - struct odp_key_8021q *q_key; + struct odp_key_8021q q_key; - q_key = nla_data(__nla_reserve(skb, ODP_KEY_ATTR_8021Q, sizeof(*q_key))); - q_key->q_tpid = htons(ETH_P_8021Q); - q_key->q_tci = swkey->dl_tci & ~htons(VLAN_TAG_PRESENT); + q_key.q_tpid = htons(ETH_P_8021Q); + q_key.q_tci = swkey->dl_tci & ~htons(VLAN_TAG_PRESENT); + NLA_PUT(skb, ODP_KEY_ATTR_8021Q, sizeof(q_key), &q_key); } if (swkey->dl_type == htons(ETH_P_802_2)) - goto exit; + return 0; - nla_put_be16(skb, ODP_KEY_ATTR_ETHERTYPE, swkey->dl_type); + NLA_PUT_BE16(skb, ODP_KEY_ATTR_ETHERTYPE, swkey->dl_type); if (swkey->dl_type == htons(ETH_P_IP)) { struct odp_key_ipv4 *ipv4_key; - ipv4_key = nla_data(__nla_reserve(skb, ODP_KEY_ATTR_IPV4, sizeof(*ipv4_key))); + nla = nla_reserve(skb, ODP_KEY_ATTR_IPV4, sizeof(*ipv4_key)); + if (!nla) + goto nla_put_failure; + ipv4_key = nla_data(nla); ipv4_key->ipv4_src = swkey->nw_src; ipv4_key->ipv4_dst = swkey->nw_dst; ipv4_key->ipv4_proto = swkey->nw_proto; @@ -613,63 +616,47 @@ static u32 flow_to_nlattrs(const struct sw_flow_key *swkey, struct sk_buff *skb) if (swkey->nw_proto == IPPROTO_TCP) { struct odp_key_tcp *tcp_key; - tcp_key = nla_data(__nla_reserve(skb, ODP_KEY_ATTR_TCP, sizeof(*tcp_key))); + nla = nla_reserve(skb, ODP_KEY_ATTR_TCP, sizeof(*tcp_key)); + if (!nla) + goto nla_put_failure; + tcp_key = nla_data(nla); tcp_key->tcp_src = swkey->tp_src; tcp_key->tcp_dst = swkey->tp_dst; } else if (swkey->nw_proto == IPPROTO_UDP) { struct odp_key_udp *udp_key; - udp_key = nla_data(__nla_reserve(skb, ODP_KEY_ATTR_UDP, sizeof(*udp_key))); + nla = nla_reserve(skb, ODP_KEY_ATTR_UDP, sizeof(*udp_key)); + if (!nla) + goto nla_put_failure; + udp_key = nla_data(nla); udp_key->udp_src = swkey->tp_src; udp_key->udp_dst = swkey->tp_dst; } else if (swkey->nw_proto == IPPROTO_ICMP) { struct odp_key_icmp *icmp_key; - icmp_key = nla_data(__nla_reserve(skb, ODP_KEY_ATTR_ICMP, sizeof(*icmp_key))); + nla = nla_reserve(skb, ODP_KEY_ATTR_ICMP, sizeof(*icmp_key)); + if (!nla) + goto nla_put_failure; + icmp_key = nla_data(nla); icmp_key->icmp_type = ntohs(swkey->tp_src); icmp_key->icmp_code = ntohs(swkey->tp_dst); } } else if (swkey->dl_type == htons(ETH_P_ARP)) { struct odp_key_arp *arp_key; - arp_key = nla_data(__nla_reserve(skb, ODP_KEY_ATTR_ARP, sizeof(*arp_key))); + nla = nla_reserve(skb, ODP_KEY_ATTR_ARP, sizeof(*arp_key)); + if (!nla) + goto nla_put_failure; + arp_key = nla_data(nla); arp_key->arp_sip = swkey->nw_src; arp_key->arp_tip = swkey->nw_dst; arp_key->arp_op = htons(swkey->nw_proto); } -exit: - return skb->len; -} - -int flow_copy_from_user(struct sw_flow_key *swkey, const struct nlattr __user *ukey, u32 ukey_len) -{ - char key[FLOW_BUFSIZE] __aligned(NLA_ALIGNTO); - - if (ukey_len > FLOW_BUFSIZE || ukey_len % NLA_ALIGNTO) - return -EINVAL; - - if (copy_from_user(key, ukey, ukey_len)) - return -EFAULT; - - return flow_from_nlattrs(swkey, (const struct nlattr *)key, ukey_len); -} - -int flow_copy_to_user(struct nlattr __user *ukey, const struct sw_flow_key *swkey, u32 ukey_len) -{ - struct sk_buff *skb; - int retval; - - skb = alloc_skb(FLOW_BUFSIZE, GFP_KERNEL); - if (!skb) - return -ENOMEM; - - retval = flow_to_nlattrs(swkey, skb); - if (copy_to_user(ukey, skb->data, min(skb->len, ukey_len))) - retval = -EFAULT; - kfree_skb(skb); + return 0; - return retval; +nla_put_failure: + return -EMSGSIZE; } /* Initializes the flow module.