816c813bfd505340ae93afb83cc0011e3d849724
[openvswitch] / switch / table-linear.c
1 /* Copyright (C) 2008 Board of Trustees, Leland Stanford Jr. University.
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining a copy
4  * of this software and associated documentation files (the "Software"), to
5  * deal in the Software without restriction, including without limitation the
6  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7  * sell copies of the Software, and to permit persons to whom the Software is
8  * furnished to do so, subject to the following conditions:
9  *
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19  * IN THE SOFTWARE.
20  */
21
22 #include "table.h"
23 #include <stdlib.h>
24 #include "flow.h"
25 #include "list.h"
26 #include "switch-flow.h"
27 #include "datapath.h"
28
29 struct sw_table_linear {
30     struct sw_table swt;
31
32     unsigned int max_flows;
33     unsigned int n_flows;
34     struct list flows;
35 };
36
37 static struct sw_flow *table_linear_lookup(struct sw_table *swt,
38                                            const struct sw_flow_key *key)
39 {
40     struct sw_table_linear *tl = (struct sw_table_linear *) swt;
41     struct sw_flow *flow;
42     LIST_FOR_EACH (flow, struct sw_flow, node, &tl->flows) {
43         if (flow_matches(&flow->key, key))
44             return flow;
45     }
46     return NULL;
47 }
48
49 static int table_linear_insert(struct sw_table *swt, struct sw_flow *flow)
50 {
51     struct sw_table_linear *tl = (struct sw_table_linear *) swt;
52     struct sw_flow *f;
53
54     /* Replace flows that match exactly. */
55     LIST_FOR_EACH (f, struct sw_flow, node, &tl->flows) {
56         if (f->key.wildcards == flow->key.wildcards
57             && flow_matches(&f->key, &flow->key)) {
58             list_replace(&flow->node, &f->node);
59             flow_free(f);
60             return 1;
61         }
62     }
63
64     /* Table overflow? */
65     if (tl->n_flows >= tl->max_flows) {
66         return 0;
67     }
68     tl->n_flows++;
69
70     /* FIXME: need to order rules from most to least specific. */
71     list_push_back(&tl->flows, &flow->node);
72     return 1;
73 }
74
75 static void
76 do_delete(struct sw_flow *flow) 
77 {
78     list_remove(&flow->node);
79     flow_free(flow);
80 }
81
82 static int table_linear_delete(struct sw_table *swt,
83                                const struct sw_flow_key *key, int strict)
84 {
85     struct sw_table_linear *tl = (struct sw_table_linear *) swt;
86     struct sw_flow *flow, *n;
87     unsigned int count = 0;
88
89     LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &tl->flows) {
90         if (flow_del_matches(&flow->key, key, strict)) {
91             do_delete(flow);
92             count++;
93         }
94     }
95     tl->n_flows -= count;
96     return count;
97 }
98
99 static int table_linear_timeout(struct datapath *dp, struct sw_table *swt)
100 {
101     struct sw_table_linear *tl = (struct sw_table_linear *) swt;
102     struct sw_flow *flow, *n;
103     int count = 0;
104
105     LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &tl->flows) {
106         if (flow_timeout(flow)) {
107             dp_send_flow_expired(dp, flow);
108             do_delete(flow);
109             count++;
110         }
111     }
112     tl->n_flows -= count;
113     return count;
114 }
115
116 static void table_linear_destroy(struct sw_table *swt)
117 {
118     struct sw_table_linear *tl = (struct sw_table_linear *) swt;
119
120     while (!list_is_empty(&tl->flows)) {
121         struct sw_flow *flow = CONTAINER_OF(list_front(&tl->flows),
122                                             struct sw_flow, node);
123         list_remove(&flow->node);
124         flow_free(flow);
125     }
126     free(tl);
127 }
128
129 /* Linear table's private data is just a pointer to the table */
130
131 static int table_linear_iterator(struct sw_table *swt,
132                                  struct swt_iterator *swt_iter) 
133 {
134     struct sw_table_linear *tl = (struct sw_table_linear *) swt;
135
136     swt_iter->private = tl;
137
138     if (!tl->n_flows)
139         swt_iter->flow = NULL;
140     else
141         swt_iter->flow = CONTAINER_OF(list_front(&tl->flows), struct sw_flow, node);
142
143     return 1;
144 }
145
146 static void table_linear_next(struct swt_iterator *swt_iter)
147 {
148     struct sw_table_linear *tl;
149     struct list *next;
150
151     if (swt_iter->flow == NULL)
152         return;
153
154     tl = (struct sw_table_linear *) swt_iter->private;
155
156     next = swt_iter->flow->node.next;
157     if (next == &tl->flows)
158         swt_iter->flow = NULL;
159     else
160         swt_iter->flow = CONTAINER_OF(next, struct sw_flow, node);
161 }
162
163 static void table_linear_iterator_destroy(struct swt_iterator *swt_iter)
164 {}
165
166 static void table_linear_stats(struct sw_table *swt,
167                                struct sw_table_stats *stats)
168 {
169     struct sw_table_linear *tl = (struct sw_table_linear *) swt;
170     stats->name = "linear";
171     stats->n_flows = tl->n_flows;
172     stats->max_flows = tl->max_flows;
173 }
174
175
176 struct sw_table *table_linear_create(unsigned int max_flows)
177 {
178     struct sw_table_linear *tl;
179     struct sw_table *swt;
180
181     tl = calloc(1, sizeof *tl);
182     if (tl == NULL)
183         return NULL;
184
185     swt = &tl->swt;
186     swt->lookup = table_linear_lookup;
187     swt->insert = table_linear_insert;
188     swt->delete = table_linear_delete;
189     swt->timeout = table_linear_timeout;
190     swt->destroy = table_linear_destroy;
191     swt->stats = table_linear_stats;
192
193     swt->iterator = table_linear_iterator;
194     swt->iterator_next = table_linear_next;
195     swt->iterator_destroy = table_linear_iterator_destroy;
196
197     tl->max_flows = max_flows;
198     tl->n_flows = 0;
199     list_init(&tl->flows);
200
201     return swt;
202 }