ovs-vswitchd: Document "bridge/dump-flows" management command
[openvswitch] / datapath / datapath.c
index 14602152cb80b9f8ff57a4fc47f8b65fb86c6b39..aea8cc95c8bd8ac0f2a36f6143a319655ee29e51 100644 (file)
@@ -165,7 +165,8 @@ static void dp_ifinfo_notify(int event, struct net_bridge_port *port)
                kfree_skb(skb);
                goto errout;
        }
-       err = rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_KERNEL);
+       rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_KERNEL);
+       return;
 errout:
        if (err < 0)
                rtnl_set_sk_err(net, RTNLGRP_LINK, err);
@@ -783,7 +784,8 @@ static int validate_actions(const struct sw_flow_actions *actions)
                        break;
 
                case ODPAT_SET_VLAN_PCP:
-                       if (a->vlan_pcp.vlan_pcp & ~VLAN_PCP_MASK)
+                       if (a->vlan_pcp.vlan_pcp
+                           & ~(VLAN_PCP_MASK >> VLAN_PCP_SHIFT))
                                return -EINVAL;
                        break;
 
@@ -1127,6 +1129,7 @@ static int do_execute(struct datapath *dp, const struct odp_execute *executep)
        struct odp_flow_key key;
        struct sk_buff *skb;
        struct sw_flow_actions *actions;
+       struct ethhdr *eth;
        int err;
 
        err = -EFAULT;
@@ -1166,6 +1169,17 @@ static int do_execute(struct datapath *dp, const struct odp_execute *executep)
                           execute.length))
                goto error_free_skb;
 
+       skb_reset_mac_header(skb);
+       eth = eth_hdr(skb);
+
+    /* Normally, setting the skb 'protocol' field would be handled by a
+     * call to eth_type_trans(), but it assumes there's a sending
+     * device, which we may not have. */
+       if (ntohs(eth->h_proto) >= 1536)
+               skb->protocol = eth->h_proto;
+       else
+               skb->protocol = htons(ETH_P_802_2);
+
        flow_extract(skb, execute.in_port, &key);
        err = execute_actions(dp, skb, &key, actions->actions,
                              actions->n_actions, GFP_KERNEL);
@@ -1369,6 +1383,16 @@ get_port_group(struct datapath *dp, struct odp_port_group *upg)
        return 0;
 }
 
+static int get_listen_mask(const struct file *f)
+{
+       return (long)f->private_data;
+}
+
+static void set_listen_mask(struct file *f, int listen_mask)
+{
+       f->private_data = (void*)(long)listen_mask;
+}
+
 static long openvswitch_ioctl(struct file *f, unsigned int cmd,
                           unsigned long argp)
 {
@@ -1420,7 +1444,7 @@ static long openvswitch_ioctl(struct file *f, unsigned int cmd,
                break;
 
        case ODP_GET_LISTEN_MASK:
-               err = put_user((int)f->private_data, (int __user *)argp);
+               err = put_user(get_listen_mask(f), (int __user *)argp);
                break;
 
        case ODP_SET_LISTEN_MASK:
@@ -1431,7 +1455,7 @@ static long openvswitch_ioctl(struct file *f, unsigned int cmd,
                if (listeners & ~ODPL_ALL)
                        break;
                err = 0;
-               f->private_data = (void*)listeners;
+               set_listen_mask(f, listeners);
                break;
 
        case ODP_PORT_QUERY:
@@ -1498,7 +1522,7 @@ ssize_t openvswitch_read(struct file *f, char __user *buf, size_t nbytes,
                      loff_t *ppos)
 {
        /* XXX is there sufficient synchronization here? */
-       int listeners = (int) f->private_data;
+       int listeners = get_listen_mask(f);
        int dp_idx = iminor(f->f_dentry->d_inode);
        struct datapath *dp = get_dp(dp_idx);
        struct sk_buff *skb;
@@ -1538,7 +1562,7 @@ ssize_t openvswitch_read(struct file *f, char __user *buf, size_t nbytes,
                }
        }
 success:
-       copy_bytes = min(skb->len, nbytes);
+       copy_bytes = min_t(size_t, skb->len, nbytes);
        iov.iov_base = buf;
        iov.iov_len = copy_bytes;
        retval = skb_copy_datagram_iovec(skb, 0, &iov, iov.iov_len);
@@ -1560,7 +1584,7 @@ static unsigned int openvswitch_poll(struct file *file, poll_table *wait)
        if (dp) {
                mask = 0;
                poll_wait(file, &dp->waitqueue, wait);
-               if (dp_has_packet_of_interest(dp, (int)file->private_data))
+               if (dp_has_packet_of_interest(dp, get_listen_mask(file)))
                        mask |= POLLIN | POLLRDNORM;
        } else {
                mask = POLLIN | POLLRDNORM | POLLHUP;