History

openvswitch: Add recirc and hash action.

Recirc action allows a packet to reenter openvswitch processing. currently openvswitch lookup flow for packet received and execute set of actions on that packet, with help of recirc action we can process/modify the packet and recirculate it back in openvswitch for another pass. OVS hash action calculates 5-tupple hash and set hash in flow-key hash. This can be used along with recirculation for distributing packets among different ports for bond devices. For example: OVS bonding can use following actions: Match on: bond flow; Action: hash, recirc(id) Match on: recirc-id == id and hash lower bits == a; Action: output port_bond_a

Andy Zhou committed 12 years ago

Commit 971427f1 parent 32ae87f7 files · +288 −12Browse files

Unified · Split

7 files
  1. include/uapi/linux/openvswitch.h +26 −0
  2. net/openvswitch/actions.c +197 −6
  3. net/openvswitch/datapath.c +9 −2
  4. net/openvswitch/datapath.h +6 −1
  5. net/openvswitch/flow.c +6 −1
  6. net/openvswitch/flow.h +3 −0
  7. net/openvswitch/flow_netlink.c +41 −2
include/uapi/linux/openvswitch.h+26−0
@@ -289,6 +289,9 @@ enum ovs_key_attr { · 288 unmodified lines
289289 OVS_KEY_ATTR_TUNNEL, /* Nested set of ovs_tunnel attributes */
290290 OVS_KEY_ATTR_SCTP, /* struct ovs_key_sctp */
291291 OVS_KEY_ATTR_TCP_FLAGS, /* be16 TCP flags. */
292+ OVS_KEY_ATTR_DP_HASH, /* u32 hash value. Value 0 indicates the hash
293+ is not computed by the datapath. */
294+ OVS_KEY_ATTR_RECIRC_ID, /* u32 recirc id */
292295
293296 #ifdef __KERNEL__
294297 OVS_KEY_ATTR_IPV4_TUNNEL, /* struct ovs_key_ipv4_tunnel */
@@ -493,6 +496,27 @@ struct ovs_action_push_vlan { · 198 unmodified lines
493496 __be16 vlan_tci; /* 802.1Q TCI (VLAN ID and priority). */
494497 };
495498
499+/* Data path hash algorithm for computing Datapath hash.
500+ *
501+ * The algorithm type only specifies the fields in a flow
502+ * will be used as part of the hash. Each datapath is free
503+ * to use its own hash algorithm. The hash value will be
504+ * opaque to the user space daemon.
505+ */
506+enum ovs_hash_alg {
507+ OVS_HASH_ALG_L4,
508+};
509+
510+/*
511+ * struct ovs_action_hash - %OVS_ACTION_ATTR_HASH action argument.
512+ * @hash_alg: Algorithm used to compute hash prior to recirculation.
513+ * @hash_basis: basis used for computing hash.
514+ */
515+struct ovs_action_hash {
516+ uint32_t hash_alg; /* One of ovs_hash_alg. */
517+ uint32_t hash_basis;
518+};
519+
496520 /**
497521 * enum ovs_action_attr - Action types.
498522 *
@@ -521,6 +545,8 @@ enum ovs_action_attr { · 22 unmodified lines
521545 OVS_ACTION_ATTR_PUSH_VLAN, /* struct ovs_action_push_vlan. */
522546 OVS_ACTION_ATTR_POP_VLAN, /* No argument. */
523547 OVS_ACTION_ATTR_SAMPLE, /* Nested OVS_SAMPLE_ATTR_*. */
548+ OVS_ACTION_ATTR_RECIRC, /* u32 recirc_id. */
549+ OVS_ACTION_ATTR_HASH, /* struct ovs_action_hash. */
524550 __OVS_ACTION_ATTR_MAX
525551 };
526552
net/openvswitch/actions.c+197−6
@@ -1,5 +1,5 @@
11 /*
2− * Copyright (c) 2007-2013 Nicira, Inc.
2+ * Copyright (c) 2007-2014 Nicira, Inc.
33 *
44 * This program is free software; you can redistribute it and/or
55 * modify it under the terms of version 2 of the GNU General Public
@@ -35,12 +35,78 @@ · 29 unmodified lines
3535 #include <net/sctp/checksum.h>
3636
3737 #include "datapath.h"
38+#include "flow.h"
3839 #include "vport.h"
3940
4041 static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
4142 struct sw_flow_key *key,
4243 const struct nlattr *attr, int len);
4344
45+struct deferred_action {
46+ struct sk_buff *skb;
47+ const struct nlattr *actions;
48+
49+ /* Store pkt_key clone when creating deferred action. */
50+ struct sw_flow_key pkt_key;
51+};
52+
53+#define DEFERRED_ACTION_FIFO_SIZE 10
54+struct action_fifo {
55+ int head;
56+ int tail;
57+ /* Deferred action fifo queue storage. */
58+ struct deferred_action fifo[DEFERRED_ACTION_FIFO_SIZE];
59+};
60+
61+static struct action_fifo __percpu *action_fifos;
62+static DEFINE_PER_CPU(int, exec_actions_level);
63+
64+static void action_fifo_init(struct action_fifo *fifo)
65+{
66+ fifo->head = 0;
67+ fifo->tail = 0;
68+}
69+
70+static bool action_fifo_is_empty(struct action_fifo *fifo)
71+{
72+ return (fifo->head == fifo->tail);
73+}
74+
75+static struct deferred_action *action_fifo_get(struct action_fifo *fifo)
76+{
77+ if (action_fifo_is_empty(fifo))
78+ return NULL;
79+
80+ return &fifo->fifo[fifo->tail++];
81+}
82+
83+static struct deferred_action *action_fifo_put(struct action_fifo *fifo)
84+{
85+ if (fifo->head >= DEFERRED_ACTION_FIFO_SIZE - 1)
86+ return NULL;
87+
88+ return &fifo->fifo[fifo->head++];
89+}
90+
91+/* Return true if fifo is not full */
92+static struct deferred_action *add_deferred_actions(struct sk_buff *skb,
93+ struct sw_flow_key *key,
94+ const struct nlattr *attr)
95+{
96+ struct action_fifo *fifo;
97+ struct deferred_action *da;
98+
99+ fifo = this_cpu_ptr(action_fifos);
100+ da = action_fifo_put(fifo);
101+ if (da) {
102+ da->skb = skb;
103+ da->actions = attr;
104+ da->pkt_key = *key;
105+ }
106+
107+ return da;
108+}
109+
44110 static int make_writable(struct sk_buff *skb, int write_len)
45111 {
46112 if (!pskb_may_pull(skb, write_len))
@@ -485,8 +551,29 @@ static int sample(struct datapath *dp, struct sk_buff *skb, · 438 unmodified lines
485551 /* Skip the sample action when out of memory. */
486552 return 0;
487553
488− /* do_execute_actions() will consume the cloned skb. */
489− return do_execute_actions(dp, skb, key, a, rem);
554+ if (!add_deferred_actions(skb, key, a)) {
555+ if (net_ratelimit())
556+ pr_warn("%s: deferred actions limit reached, dropping sample action\n",
557+ ovs_dp_name(dp));
558+
559+ kfree_skb(skb);
560+ }
561+ return 0;
562+}
563+
564+static void execute_hash(struct sk_buff *skb, struct sw_flow_key *key,
565+ const struct nlattr *attr)
566+{
567+ struct ovs_action_hash *hash_act = nla_data(attr);
568+ u32 hash = 0;
569+
570+ /* OVS_HASH_ALG_L4 is the only possible hash algorithm. */
571+ hash = skb_get_hash(skb);
572+ hash = jhash_1word(hash, hash_act->hash_basis);
573+ if (!hash)
574+ hash = 0x1;
575+
576+ key->ovs_flow_hash = hash;
490577 }
491578
492579 static int execute_set_action(struct sk_buff *skb,
@@ -535,6 +622,44 @@ static int execute_set_action(struct sk_buff *skb, · 42 unmodified lines
535622 return err;
536623 }
537624
625+static int execute_recirc(struct datapath *dp, struct sk_buff *skb,
626+ struct sw_flow_key *key,
627+ const struct nlattr *a, int rem)
628+{
629+ struct deferred_action *da;
630+ int err;
631+
632+ err = ovs_flow_key_update(skb, key);
633+ if (err)
634+ return err;
635+
636+ if (!last_action(a, rem)) {
637+ /* Recirc action is the not the last action
638+ * of the action list, need to clone the skb.
639+ */
640+ skb = skb_clone(skb, GFP_ATOMIC);
641+
642+ /* Skip the recirc action when out of memory, but
643+ * continue on with the rest of the action list.
644+ */
645+ if (!skb)
646+ return 0;
647+ }
648+
649+ da = add_deferred_actions(skb, key, NULL);
650+ if (da) {
651+ da->pkt_key.recirc_id = nla_get_u32(a);
652+ } else {
653+ kfree_skb(skb);
654+
655+ if (net_ratelimit())
656+ pr_warn("%s: deferred action limit reached, drop recirc action\n",
657+ ovs_dp_name(dp));
658+ }
659+
660+ return 0;
661+}
662+
538663 /* Execute a list of actions against 'skb'. */
539664 static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
540665 struct sw_flow_key *key,
@@ -566,6 +691,10 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, · 25 unmodified lines
566691 output_userspace(dp, skb, key, a);
567692 break;
568693
694+ case OVS_ACTION_ATTR_HASH:
695+ execute_hash(skb, key, a);
696+ break;
697+
569698 case OVS_ACTION_ATTR_PUSH_VLAN:
570699 err = push_vlan(skb, nla_data(a));
571700 if (unlikely(err)) /* skb already freed. */
@@ -576,6 +705,17 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, · 4 unmodified lines
576705 err = pop_vlan(skb);
577706 break;
578707
708+ case OVS_ACTION_ATTR_RECIRC:
709+ err = execute_recirc(dp, skb, key, a, rem);
710+ if (last_action(a, rem)) {
711+ /* If this is the last action, the skb has
712+ * been consumed or freed.
713+ * Return immediately.
714+ */
715+ return err;
716+ }
717+ break;
718+
579719 case OVS_ACTION_ATTR_SET:
580720 err = execute_set_action(skb, nla_data(a));
581721 break;
@@ -601,12 +741,63 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, · 19 unmodified lines
601741 return 0;
602742 }
603743
744+static void process_deferred_actions(struct datapath *dp)
745+{
746+ struct action_fifo *fifo = this_cpu_ptr(action_fifos);
747+
748+ /* Do not touch the FIFO in case there is no deferred actions. */
749+ if (action_fifo_is_empty(fifo))
750+ return;
751+
752+ /* Finishing executing all deferred actions. */
753+ do {
754+ struct deferred_action *da = action_fifo_get(fifo);
755+ struct sk_buff *skb = da->skb;
756+ struct sw_flow_key *key = &da->pkt_key;
757+ const struct nlattr *actions = da->actions;
758+
759+ if (actions)
760+ do_execute_actions(dp, skb, key, actions,
761+ nla_len(actions));
762+ else
763+ ovs_dp_process_packet(skb, key);
764+ } while (!action_fifo_is_empty(fifo));
765+
766+ /* Reset FIFO for the next packet. */
767+ action_fifo_init(fifo);
768+}
769+
604770 /* Execute a list of actions against 'skb'. */
605771 int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb,
606772 struct sw_flow_key *key)
607773 {
608− struct sw_flow_actions *acts = rcu_dereference(OVS_CB(skb)->flow->sf_acts);
774+ int level = this_cpu_read(exec_actions_level);
775+ struct sw_flow_actions *acts;
776+ int err;
777+
778+ acts = rcu_dereference(OVS_CB(skb)->flow->sf_acts);
779+
780+ this_cpu_inc(exec_actions_level);
781+ err = do_execute_actions(dp, skb, key,
782+ acts->actions, acts->actions_len);
783+
784+ if (!level)
785+ process_deferred_actions(dp);
786+
787+ this_cpu_dec(exec_actions_level);
788+ return err;
789+}
790+
791+int action_fifos_init(void)
792+{
793+ action_fifos = alloc_percpu(struct action_fifo);
794+ if (!action_fifos)
795+ return -ENOMEM;
609796
610− return do_execute_actions(dp, skb, key,
611− acts->actions, acts->actions_len);
797+ return 0;
798+}
799+
800+void action_fifos_exit(void)
801+{
802+ free_percpu(action_fifos);
612803 }
net/openvswitch/datapath.c+9−2
@@ -156,7 +156,7 @@ static struct datapath *get_dp(struct net *net, int dp_ifindex) · 155 unmodified lines
156156 }
157157
158158 /* Must be called with rcu_read_lock or ovs_mutex. */
159−static const char *ovs_dp_name(const struct datapath *dp)
159+const char *ovs_dp_name(const struct datapath *dp)
160160 {
161161 struct vport *vport = ovs_vport_ovsl_rcu(dp, OVSP_LOCAL);
162162 return vport->ops->get_name(vport);
@@ -2065,10 +2065,14 @@ static int __init dp_init(void) · 1902 unmodified lines
20652065
20662066 pr_info("Open vSwitch switching datapath\n");
20672067
2068− err = ovs_internal_dev_rtnl_link_register();
2068+ err = action_fifos_init();
20692069 if (err)
20702070 goto error;
20712071
2072+ err = ovs_internal_dev_rtnl_link_register();
2073+ if (err)
2074+ goto error_action_fifos_exit;
2075+
20722076 err = ovs_flow_init();
20732077 if (err)
20742078 goto error_unreg_rtnl_link;
@@ -2101,6 +2105,8 @@ error_flow_exit: · 26 unmodified lines
21012105 ovs_flow_exit();
21022106 error_unreg_rtnl_link:
21032107 ovs_internal_dev_rtnl_link_unregister();
2108+error_action_fifos_exit:
2109+ action_fifos_exit();
21042110 error:
21052111 return err;
21062112 }
@@ -2114,6 +2120,7 @@ static void dp_cleanup(void) · 7 unmodified lines
21142120 ovs_vport_exit();
21152121 ovs_flow_exit();
21162122 ovs_internal_dev_rtnl_link_unregister();
2123+ action_fifos_exit();
21172124 }
21182125
21192126 module_init(dp_init);
net/openvswitch/datapath.h+6−1
@@ -1,5 +1,5 @@
11 /*
2− * Copyright (c) 2007-2012 Nicira, Inc.
2+ * Copyright (c) 2007-2014 Nicira, Inc.
33 *
44 * This program is free software; you can redistribute it and/or
55 * modify it under the terms of version 2 of the GNU General Public
@@ -189,13 +189,18 @@ void ovs_dp_detach_port(struct vport *); · 183 unmodified lines
189189 int ovs_dp_upcall(struct datapath *, struct sk_buff *,
190190 const struct dp_upcall_info *);
191191
192+const char *ovs_dp_name(const struct datapath *dp);
192193 struct sk_buff *ovs_vport_cmd_build_info(struct vport *, u32 pid, u32 seq,
193194 u8 cmd);
194195
195196 int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb,
196197 struct sw_flow_key *);
198+
197199 void ovs_dp_notify_wq(struct work_struct *work);
198200
201+int action_fifos_init(void);
202+void action_fifos_exit(void);
203+
199204 #define OVS_NLERR(fmt, ...) \
200205 do { \
201206 if (net_ratelimit()) \
net/openvswitch/flow.c+6−1
@@ -1,5 +1,5 @@
11 /*
2− * Copyright (c) 2007-2013 Nicira, Inc.
2+ * Copyright (c) 2007-2014 Nicira, Inc.
33 *
44 * This program is free software; you can redistribute it and/or
55 * modify it under the terms of version 2 of the GNU General Public
@@ -606,6 +606,11 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key) · 600 unmodified lines
606606 return 0;
607607 }
608608
609+int ovs_flow_key_update(struct sk_buff *skb, struct sw_flow_key *key)
610+{
611+ return key_extract(skb, key);
612+}
613+
609614 int ovs_flow_key_extract(struct ovs_key_ipv4_tunnel *tun_key,
610615 struct sk_buff *skb, struct sw_flow_key *key)
611616 {
net/openvswitch/flow.h+3−0
@@ -72,6 +72,8 @@ struct sw_flow_key { · 71 unmodified lines
7272 u32 skb_mark; /* SKB mark. */
7373 u16 in_port; /* Input switch port (or DP_MAX_PORTS). */
7474 } __packed phy; /* Safe when right after 'tun_key'. */
75+ u32 ovs_flow_hash; /* Datapath computed hash value. */
76+ u32 recirc_id; /* Recirculation ID. */
7577 struct {
7678 u8 src[ETH_ALEN]; /* Ethernet source address. */
7779 u8 dst[ETH_ALEN]; /* Ethernet destination address. */
@@ -187,6 +189,7 @@ void ovs_flow_stats_get(const struct sw_flow *, struct ovs_flow_stats *, · 109 unmodified lines
187189 void ovs_flow_stats_clear(struct sw_flow *);
188190 u64 ovs_flow_used_time(unsigned long flow_jiffies);
189191
192+int ovs_flow_key_update(struct sk_buff *skb, struct sw_flow_key *key);
190193 int ovs_flow_key_extract(struct ovs_key_ipv4_tunnel *tun_key,
191194 struct sk_buff *skb, struct sw_flow_key *key);
192195 /* Extract key from packet coming from userspace. */
net/openvswitch/flow_netlink.c+41−2
@@ -1,5 +1,5 @@
11 /*
2− * Copyright (c) 2007-2013 Nicira, Inc.
2+ * Copyright (c) 2007-2014 Nicira, Inc.
33 *
44 * This program is free software; you can redistribute it and/or
55 * modify it under the terms of version 2 of the GNU General Public
@@ -251,6 +251,8 @@ static const int ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = { · 245 unmodified lines
251251 [OVS_KEY_ATTR_ICMPV6] = sizeof(struct ovs_key_icmpv6),
252252 [OVS_KEY_ATTR_ARP] = sizeof(struct ovs_key_arp),
253253 [OVS_KEY_ATTR_ND] = sizeof(struct ovs_key_nd),
254+ [OVS_KEY_ATTR_RECIRC_ID] = sizeof(u32),
255+ [OVS_KEY_ATTR_DP_HASH] = sizeof(u32),
254256 [OVS_KEY_ATTR_TUNNEL] = -1,
255257 };
256258
@@ -454,6 +456,20 @@ static int ipv4_tun_to_nlattr(struct sk_buff *skb, · 197 unmodified lines
454456 static int metadata_from_nlattrs(struct sw_flow_match *match, u64 *attrs,
455457 const struct nlattr **a, bool is_mask)
456458 {
459+ if (*attrs & (1 << OVS_KEY_ATTR_DP_HASH)) {
460+ u32 hash_val = nla_get_u32(a[OVS_KEY_ATTR_DP_HASH]);
461+
462+ SW_FLOW_KEY_PUT(match, ovs_flow_hash, hash_val, is_mask);
463+ *attrs &= ~(1 << OVS_KEY_ATTR_DP_HASH);
464+ }
465+
466+ if (*attrs & (1 << OVS_KEY_ATTR_RECIRC_ID)) {
467+ u32 recirc_id = nla_get_u32(a[OVS_KEY_ATTR_RECIRC_ID]);
468+
469+ SW_FLOW_KEY_PUT(match, recirc_id, recirc_id, is_mask);
470+ *attrs &= ~(1 << OVS_KEY_ATTR_RECIRC_ID);
471+ }
472+
457473 if (*attrs & (1 << OVS_KEY_ATTR_PRIORITY)) {
458474 SW_FLOW_KEY_PUT(match, phy.priority,
459475 nla_get_u32(a[OVS_KEY_ATTR_PRIORITY]), is_mask);
@@ -873,6 +889,12 @@ int ovs_nla_put_flow(const struct sw_flow_key *swkey, · 413 unmodified lines
873889 struct nlattr *nla, *encap;
874890 bool is_mask = (swkey != output);
875891
892+ if (nla_put_u32(skb, OVS_KEY_ATTR_RECIRC_ID, output->recirc_id))
893+ goto nla_put_failure;
894+
895+ if (nla_put_u32(skb, OVS_KEY_ATTR_DP_HASH, output->ovs_flow_hash))
896+ goto nla_put_failure;
897+
876898 if (nla_put_u32(skb, OVS_KEY_ATTR_PRIORITY, output->phy.priority))
877899 goto nla_put_failure;
878900
@@ -1401,11 +1423,13 @@ int ovs_nla_copy_actions(const struct nlattr *attr, · 522 unmodified lines
14011423 /* Expected argument lengths, (u32)-1 for variable length. */
14021424 static const u32 action_lens[OVS_ACTION_ATTR_MAX + 1] = {
14031425 [OVS_ACTION_ATTR_OUTPUT] = sizeof(u32),
1426+ [OVS_ACTION_ATTR_RECIRC] = sizeof(u32),
14041427 [OVS_ACTION_ATTR_USERSPACE] = (u32)-1,
14051428 [OVS_ACTION_ATTR_PUSH_VLAN] = sizeof(struct ovs_action_push_vlan),
14061429 [OVS_ACTION_ATTR_POP_VLAN] = 0,
14071430 [OVS_ACTION_ATTR_SET] = (u32)-1,
1408− [OVS_ACTION_ATTR_SAMPLE] = (u32)-1
1431+ [OVS_ACTION_ATTR_SAMPLE] = (u32)-1,
1432+ [OVS_ACTION_ATTR_HASH] = sizeof(struct ovs_action_hash)
14091433 };
14101434 const struct ovs_action_push_vlan *vlan;
14111435 int type = nla_type(a);
@@ -1432,6 +1456,18 @@ int ovs_nla_copy_actions(const struct nlattr *attr, · 20 unmodified lines
14321456 return -EINVAL;
14331457 break;
14341458
1459+ case OVS_ACTION_ATTR_HASH: {
1460+ const struct ovs_action_hash *act_hash = nla_data(a);
1461+
1462+ switch (act_hash->hash_alg) {
1463+ case OVS_HASH_ALG_L4:
1464+ break;
1465+ default:
1466+ return -EINVAL;
1467+ }
1468+
1469+ break;
1470+ }
14351471
14361472 case OVS_ACTION_ATTR_POP_VLAN:
14371473 break;
@@ -1444,6 +1480,9 @@ int ovs_nla_copy_actions(const struct nlattr *attr, · 6 unmodified lines
14441480 return -EINVAL;
14451481 break;
14461482
1483+ case OVS_ACTION_ATTR_RECIRC:
1484+ break;
1485+
14471486 case OVS_ACTION_ATTR_SET:
14481487 err = validate_set(a, key, sfa, &skip_copy);
14491488 if (err)