]>
Commit | Line | Data |
---|---|---|
064af421 | 1 | /* |
db5ce514 | 2 | * Copyright (c) 2009, 2010, 2011 Nicira Networks. |
43253595 | 3 | * Copyright (c) 2010 Jean Tourrilhes - HP-Labs. |
064af421 | 4 | * |
a14bc59f BP |
5 | * Licensed under the Apache License, Version 2.0 (the "License"); |
6 | * you may not use this file except in compliance with the License. | |
7 | * You may obtain a copy of the License at: | |
064af421 | 8 | * |
a14bc59f BP |
9 | * http://www.apache.org/licenses/LICENSE-2.0 |
10 | * | |
11 | * Unless required by applicable law or agreed to in writing, software | |
12 | * distributed under the License is distributed on an "AS IS" BASIS, | |
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | * See the License for the specific language governing permissions and | |
15 | * limitations under the License. | |
064af421 BP |
16 | */ |
17 | ||
18 | #include <config.h> | |
19 | #include "ofproto.h" | |
20 | #include <errno.h> | |
21 | #include <inttypes.h> | |
9d82ec47 | 22 | #include <sys/socket.h> |
064af421 BP |
23 | #include <net/if.h> |
24 | #include <netinet/in.h> | |
25 | #include <stdbool.h> | |
26 | #include <stdlib.h> | |
10a24935 | 27 | #include "byte-order.h" |
e7934396 | 28 | #include "cfm.h" |
064af421 | 29 | #include "classifier.h" |
19a87e36 | 30 | #include "connmgr.h" |
064af421 | 31 | #include "coverage.h" |
064af421 | 32 | #include "dpif.h" |
4f2cad2c | 33 | #include "dynamic-string.h" |
064af421 | 34 | #include "fail-open.h" |
ca0f572c BP |
35 | #include "hash.h" |
36 | #include "hmap.h" | |
064af421 BP |
37 | #include "in-band.h" |
38 | #include "mac-learning.h" | |
53ddd40a | 39 | #include "multipath.h" |
064af421 BP |
40 | #include "netdev.h" |
41 | #include "netflow.h" | |
cdee00fd | 42 | #include "netlink.h" |
09246b99 | 43 | #include "nx-match.h" |
064af421 BP |
44 | #include "odp-util.h" |
45 | #include "ofp-print.h" | |
fa37b408 | 46 | #include "ofp-util.h" |
72b06300 | 47 | #include "ofproto-sflow.h" |
064af421 BP |
48 | #include "ofpbuf.h" |
49 | #include "openflow/nicira-ext.h" | |
50 | #include "openflow/openflow.h" | |
064af421 BP |
51 | #include "openvswitch/datapath-protocol.h" |
52 | #include "packets.h" | |
53 | #include "pinsched.h" | |
54 | #include "pktbuf.h" | |
55 | #include "poll-loop.h" | |
064af421 BP |
56 | #include "rconn.h" |
57 | #include "shash.h" | |
b3c01ed3 | 58 | #include "sset.h" |
fe55ad15 | 59 | #include "stream-ssl.h" |
064af421 BP |
60 | #include "svec.h" |
61 | #include "tag.h" | |
79e745c9 | 62 | #include "timer.h" |
064af421 | 63 | #include "timeval.h" |
c4617b3c | 64 | #include "unaligned.h" |
4f2cad2c | 65 | #include "unixctl.h" |
064af421 | 66 | #include "vconn.h" |
5136ce49 | 67 | #include "vlog.h" |
064af421 | 68 | |
d98e6007 | 69 | VLOG_DEFINE_THIS_MODULE(ofproto); |
064af421 | 70 | |
cc01d0bb BP |
71 | COVERAGE_DEFINE(facet_changed_rule); |
72 | COVERAGE_DEFINE(facet_revalidate); | |
d76f09ea | 73 | COVERAGE_DEFINE(odp_overflow); |
d76f09ea BP |
74 | COVERAGE_DEFINE(ofproto_agg_request); |
75 | COVERAGE_DEFINE(ofproto_costly_flags); | |
76 | COVERAGE_DEFINE(ofproto_ctlr_action); | |
cc01d0bb | 77 | COVERAGE_DEFINE(ofproto_del_rule); |
d76f09ea BP |
78 | COVERAGE_DEFINE(ofproto_error); |
79 | COVERAGE_DEFINE(ofproto_expiration); | |
80 | COVERAGE_DEFINE(ofproto_expired); | |
81 | COVERAGE_DEFINE(ofproto_flows_req); | |
82 | COVERAGE_DEFINE(ofproto_flush); | |
83 | COVERAGE_DEFINE(ofproto_invalidated); | |
d76f09ea | 84 | COVERAGE_DEFINE(ofproto_no_packet_in); |
d76f09ea BP |
85 | COVERAGE_DEFINE(ofproto_ofp2odp); |
86 | COVERAGE_DEFINE(ofproto_packet_in); | |
87 | COVERAGE_DEFINE(ofproto_packet_out); | |
88 | COVERAGE_DEFINE(ofproto_queue_req); | |
89 | COVERAGE_DEFINE(ofproto_recv_openflow); | |
90 | COVERAGE_DEFINE(ofproto_reinit_ports); | |
d76f09ea BP |
91 | COVERAGE_DEFINE(ofproto_unexpected_rule); |
92 | COVERAGE_DEFINE(ofproto_uninstallable); | |
93 | COVERAGE_DEFINE(ofproto_update_port); | |
94 | ||
878ae780 EJ |
95 | /* Maximum depth of flow table recursion (due to NXAST_RESUBMIT actions) in a |
96 | * flow translation. */ | |
97 | #define MAX_RESUBMIT_RECURSION 16 | |
98 | ||
f29152ca BP |
99 | struct rule; |
100 | ||
064af421 | 101 | struct ofport { |
ca0f572c | 102 | struct hmap_node hmap_node; /* In struct ofproto's "ports" hmap. */ |
064af421 BP |
103 | struct netdev *netdev; |
104 | struct ofp_phy_port opp; /* In host byte order. */ | |
ca0f572c | 105 | uint16_t odp_port; |
e7934396 | 106 | struct cfm *cfm; /* Connectivity Fault Management, if any. */ |
064af421 BP |
107 | }; |
108 | ||
109 | static void ofport_free(struct ofport *); | |
e7934396 BP |
110 | static void ofport_run(struct ofproto *, struct ofport *); |
111 | static void ofport_wait(struct ofport *); | |
064af421 | 112 | |
f29152ca BP |
113 | struct action_xlate_ctx { |
114 | /* action_xlate_ctx_init() initializes these members. */ | |
115 | ||
116 | /* The ofproto. */ | |
117 | struct ofproto *ofproto; | |
118 | ||
119 | /* Flow to which the OpenFlow actions apply. xlate_actions() will modify | |
120 | * this flow when actions change header fields. */ | |
121 | struct flow flow; | |
122 | ||
123 | /* The packet corresponding to 'flow', or a null pointer if we are | |
124 | * revalidating without a packet to refer to. */ | |
125 | const struct ofpbuf *packet; | |
126 | ||
7aa697dd BP |
127 | /* If nonnull, called just before executing a resubmit action. |
128 | * | |
129 | * This is normally null so the client has to set it manually after | |
130 | * calling action_xlate_ctx_init(). */ | |
878ae780 | 131 | void (*resubmit_hook)(struct action_xlate_ctx *, struct rule *); |
7aa697dd | 132 | |
ebe482fd EJ |
133 | /* If true, the speciality of 'flow' should be checked before executing |
134 | * its actions. If special_cb returns false on 'flow' rendered | |
135 | * uninstallable and no actions will be executed. */ | |
136 | bool check_special; | |
137 | ||
f29152ca BP |
138 | /* xlate_actions() initializes and uses these members. The client might want |
139 | * to look at them after it returns. */ | |
140 | ||
cdee00fd | 141 | struct ofpbuf *odp_actions; /* Datapath actions. */ |
f29152ca BP |
142 | tag_type tags; /* Tags associated with OFPP_NORMAL actions. */ |
143 | bool may_set_up_flow; /* True ordinarily; false if the actions must | |
144 | * be reassessed for every packet. */ | |
145 | uint16_t nf_output_iface; /* Output interface index for NetFlow. */ | |
146 | ||
147 | /* xlate_actions() initializes and uses these members, but the client has no | |
148 | * reason to look at them. */ | |
149 | ||
150 | int recurse; /* Recursion level, via xlate_table_action. */ | |
cdee00fd | 151 | int last_pop_priority; /* Offset in 'odp_actions' just past most |
7aec165d | 152 | * recent ODP_ACTION_ATTR_SET_PRIORITY. */ |
f29152ca BP |
153 | }; |
154 | ||
155 | static void action_xlate_ctx_init(struct action_xlate_ctx *, | |
156 | struct ofproto *, const struct flow *, | |
157 | const struct ofpbuf *); | |
cdee00fd BP |
158 | static struct ofpbuf *xlate_actions(struct action_xlate_ctx *, |
159 | const union ofp_action *in, size_t n_in); | |
064af421 | 160 | |
bcf84111 | 161 | /* An OpenFlow flow. */ |
064af421 | 162 | struct rule { |
0c43ad9a | 163 | long long int used; /* Time last used; time created if not used. */ |
064af421 | 164 | long long int created; /* Creation time. */ |
064af421 | 165 | |
bcf84111 | 166 | /* These statistics: |
064af421 | 167 | * |
bcf84111 BP |
168 | * - Do include packets and bytes from facets that have been deleted or |
169 | * whose own statistics have been folded into the rule. | |
79eee1eb | 170 | * |
bcf84111 BP |
171 | * - Do include packets and bytes sent "by hand" that were accounted to |
172 | * the rule without any facet being involved (this is a rare corner | |
173 | * case in rule_execute()). | |
064af421 | 174 | * |
bcf84111 BP |
175 | * - Do not include packet or bytes that can be obtained from any facet's |
176 | * packet_count or byte_count member or that can be obtained from the | |
177 | * datapath by, e.g., dpif_flow_get() for any facet. | |
178 | */ | |
179 | uint64_t packet_count; /* Number of packets received. */ | |
180 | uint64_t byte_count; /* Number of bytes received. */ | |
181 | ||
182 | ovs_be64 flow_cookie; /* Controller-issued identifier. */ | |
183 | ||
184 | struct cls_rule cr; /* In owning ofproto's classifier. */ | |
185 | uint16_t idle_timeout; /* In seconds from time of last use. */ | |
186 | uint16_t hard_timeout; /* In seconds from time of creation. */ | |
187 | bool send_flow_removed; /* Send a flow removed message? */ | |
188 | int n_actions; /* Number of elements in actions[]. */ | |
189 | union ofp_action *actions; /* OpenFlow actions. */ | |
190 | struct list facets; /* List of "struct facet"s. */ | |
064af421 BP |
191 | }; |
192 | ||
bcf84111 BP |
193 | static struct rule *rule_from_cls_rule(const struct cls_rule *); |
194 | static bool rule_is_hidden(const struct rule *); | |
064af421 | 195 | |
bcf84111 | 196 | static struct rule *rule_create(const struct cls_rule *, |
0193b2af | 197 | const union ofp_action *, size_t n_actions, |
ca069229 | 198 | uint16_t idle_timeout, uint16_t hard_timeout, |
8054fc48 | 199 | ovs_be64 flow_cookie, bool send_flow_removed); |
064af421 | 200 | static void rule_destroy(struct ofproto *, struct rule *); |
bcf84111 BP |
201 | static void rule_free(struct rule *); |
202 | ||
203 | static struct rule *rule_lookup(struct ofproto *, const struct flow *); | |
afe75089 | 204 | static void rule_insert(struct ofproto *, struct rule *); |
064af421 | 205 | static void rule_remove(struct ofproto *, struct rule *); |
bcf84111 BP |
206 | |
207 | static void rule_send_removed(struct ofproto *, struct rule *, uint8_t reason); | |
3394b5b6 EJ |
208 | static void rule_get_stats(const struct rule *, uint64_t *packets, |
209 | uint64_t *bytes); | |
bcf84111 BP |
210 | |
211 | /* An exact-match instantiation of an OpenFlow flow. */ | |
212 | struct facet { | |
213 | long long int used; /* Time last used; time created if not used. */ | |
214 | ||
215 | /* These statistics: | |
216 | * | |
217 | * - Do include packets and bytes sent "by hand", e.g. with | |
218 | * dpif_execute(). | |
219 | * | |
220 | * - Do include packets and bytes that were obtained from the datapath | |
221 | * when a flow was deleted (e.g. dpif_flow_del()) or when its | |
ba25b8f4 BP |
222 | * statistics were reset (e.g. dpif_flow_put() with |
223 | * DPIF_FP_ZERO_STATS). | |
bcf84111 BP |
224 | * |
225 | * - Do not include any packets or bytes that can currently be obtained | |
226 | * from the datapath by, e.g., dpif_flow_get(). | |
227 | */ | |
228 | uint64_t packet_count; /* Number of packets received. */ | |
229 | uint64_t byte_count; /* Number of bytes received. */ | |
230 | ||
3394b5b6 EJ |
231 | uint64_t dp_packet_count; /* Last known packet count in the datapath. */ |
232 | uint64_t dp_byte_count; /* Last known byte count in the datapath. */ | |
233 | ||
878ae780 EJ |
234 | uint64_t rs_packet_count; /* Packets pushed to resubmit children. */ |
235 | uint64_t rs_byte_count; /* Bytes pushed to resubmit children. */ | |
236 | long long int rs_used; /* Used time pushed to resubmit children. */ | |
237 | ||
bcf84111 BP |
238 | /* Number of bytes passed to account_cb. This may include bytes that can |
239 | * currently obtained from the datapath (thus, it can be greater than | |
240 | * byte_count). */ | |
241 | uint64_t accounted_bytes; | |
242 | ||
243 | struct hmap_node hmap_node; /* In owning ofproto's 'facets' hmap. */ | |
244 | struct list list_node; /* In owning rule's 'facets' list. */ | |
245 | struct rule *rule; /* Owning rule. */ | |
246 | struct flow flow; /* Exact-match flow. */ | |
247 | bool installed; /* Installed in datapath? */ | |
248 | bool may_install; /* True ordinarily; false if actions must | |
249 | * be reassessed for every packet. */ | |
cf22f8cb | 250 | size_t actions_len; /* Number of bytes in actions[]. */ |
cdee00fd | 251 | struct nlattr *actions; /* Datapath actions. */ |
bcf84111 BP |
252 | tag_type tags; /* Tags (set only by hooks). */ |
253 | struct netflow_flow nf_flow; /* Per-flow NetFlow tracking data. */ | |
254 | }; | |
255 | ||
256 | static struct facet *facet_create(struct ofproto *, struct rule *, | |
257 | const struct flow *, | |
258 | const struct ofpbuf *packet); | |
259 | static void facet_remove(struct ofproto *, struct facet *); | |
260 | static void facet_free(struct facet *); | |
261 | ||
262 | static struct facet *facet_lookup_valid(struct ofproto *, const struct flow *); | |
263 | static bool facet_revalidate(struct ofproto *, struct facet *); | |
264 | ||
265 | static void facet_install(struct ofproto *, struct facet *, bool zero_stats); | |
266 | static void facet_uninstall(struct ofproto *, struct facet *); | |
d530fcd2 | 267 | static void facet_flush_stats(struct ofproto *, struct facet *); |
bcf84111 | 268 | |
7f7ae89d BP |
269 | static void facet_make_actions(struct ofproto *, struct facet *, |
270 | const struct ofpbuf *packet); | |
bcf84111 | 271 | static void facet_update_stats(struct ofproto *, struct facet *, |
c97fb132 | 272 | const struct dpif_flow_stats *); |
878ae780 | 273 | static void facet_push_stats(struct ofproto *, struct facet *); |
064af421 | 274 | |
856081f6 BP |
275 | static void send_packet_in(struct ofproto *, struct dpif_upcall *, |
276 | const struct flow *, bool clone); | |
76ce9432 | 277 | |
064af421 BP |
278 | struct ofproto { |
279 | /* Settings. */ | |
280 | uint64_t datapath_id; /* Datapath ID. */ | |
281 | uint64_t fallback_dpid; /* Datapath ID if no better choice found. */ | |
5a719c38 JP |
282 | char *mfr_desc; /* Manufacturer. */ |
283 | char *hw_desc; /* Hardware. */ | |
284 | char *sw_desc; /* Software version. */ | |
285 | char *serial_desc; /* Serial number. */ | |
8abc4ed7 | 286 | char *dp_desc; /* Datapath description. */ |
064af421 BP |
287 | |
288 | /* Datapath. */ | |
c228a364 | 289 | struct dpif *dpif; |
e9e28be3 | 290 | struct netdev_monitor *netdev_monitor; |
ca0f572c | 291 | struct hmap ports; /* Contains "struct ofport"s. */ |
064af421 BP |
292 | struct shash port_by_name; |
293 | uint32_t max_ports; | |
294 | ||
295 | /* Configuration. */ | |
064af421 | 296 | struct netflow *netflow; |
72b06300 | 297 | struct ofproto_sflow *sflow; |
064af421 BP |
298 | |
299 | /* Flow table. */ | |
300 | struct classifier cls; | |
79e745c9 | 301 | struct timer next_expiration; |
bcf84111 BP |
302 | |
303 | /* Facets. */ | |
304 | struct hmap facets; | |
305 | bool need_revalidate; | |
064af421 BP |
306 | struct tag_set revalidate_set; |
307 | ||
308 | /* OpenFlow connections. */ | |
19a87e36 | 309 | struct connmgr *connmgr; |
064af421 BP |
310 | |
311 | /* Hooks for ovs-vswitchd. */ | |
312 | const struct ofhooks *ofhooks; | |
313 | void *aux; | |
314 | ||
315 | /* Used by default ofhooks. */ | |
316 | struct mac_learning *ml; | |
317 | }; | |
318 | ||
7aa697dd BP |
319 | /* Map from dpif name to struct ofproto, for use by unixctl commands. */ |
320 | static struct shash all_ofprotos = SHASH_INITIALIZER(&all_ofprotos); | |
321 | ||
064af421 BP |
322 | static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); |
323 | ||
324 | static const struct ofhooks default_ofhooks; | |
325 | ||
fa60c019 | 326 | static uint64_t pick_datapath_id(const struct ofproto *); |
064af421 | 327 | static uint64_t pick_fallback_dpid(void); |
76ce9432 | 328 | |
0de7a4b4 | 329 | static int ofproto_expire(struct ofproto *); |
878ae780 EJ |
330 | static void flow_push_stats(struct ofproto *, const struct rule *, |
331 | struct flow *, uint64_t packets, uint64_t bytes, | |
332 | long long int used); | |
4a4cdb3b | 333 | |
856081f6 | 334 | static void handle_upcall(struct ofproto *, struct dpif_upcall *); |
064af421 | 335 | |
3269c562 | 336 | static void handle_openflow(struct ofconn *, struct ofpbuf *); |
064af421 | 337 | |
ca0f572c | 338 | static struct ofport *get_port(const struct ofproto *, uint16_t odp_port); |
064af421 BP |
339 | static void update_port(struct ofproto *, const char *devname); |
340 | static int init_ports(struct ofproto *); | |
341 | static void reinit_ports(struct ofproto *); | |
342 | ||
7aa697dd BP |
343 | static void ofproto_unixctl_init(void); |
344 | ||
064af421 | 345 | int |
1a6f1e2a JG |
346 | ofproto_create(const char *datapath, const char *datapath_type, |
347 | const struct ofhooks *ofhooks, void *aux, | |
064af421 BP |
348 | struct ofproto **ofprotop) |
349 | { | |
19a87e36 | 350 | char local_name[IF_NAMESIZE]; |
064af421 | 351 | struct ofproto *p; |
c228a364 | 352 | struct dpif *dpif; |
064af421 BP |
353 | int error; |
354 | ||
355 | *ofprotop = NULL; | |
356 | ||
7aa697dd BP |
357 | ofproto_unixctl_init(); |
358 | ||
064af421 | 359 | /* Connect to datapath and start listening for messages. */ |
1a6f1e2a | 360 | error = dpif_open(datapath, datapath_type, &dpif); |
064af421 BP |
361 | if (error) { |
362 | VLOG_ERR("failed to open datapath %s: %s", datapath, strerror(error)); | |
363 | return error; | |
364 | } | |
82272ede BP |
365 | error = dpif_recv_set_mask(dpif, |
366 | ((1u << DPIF_UC_MISS) | | |
367 | (1u << DPIF_UC_ACTION) | | |
368 | (1u << DPIF_UC_SAMPLE))); | |
064af421 BP |
369 | if (error) { |
370 | VLOG_ERR("failed to listen on datapath %s: %s", | |
371 | datapath, strerror(error)); | |
c228a364 | 372 | dpif_close(dpif); |
064af421 BP |
373 | return error; |
374 | } | |
c228a364 | 375 | dpif_flow_flush(dpif); |
8f24562a | 376 | dpif_recv_purge(dpif); |
064af421 | 377 | |
19a87e36 BP |
378 | error = dpif_port_get_name(dpif, ODPP_LOCAL, |
379 | local_name, sizeof local_name); | |
380 | if (error) { | |
381 | VLOG_ERR("%s: cannot get name of datapath local port (%s)", | |
382 | datapath, strerror(error)); | |
383 | return error; | |
384 | } | |
385 | ||
064af421 | 386 | /* Initialize settings. */ |
ec6fde61 | 387 | p = xzalloc(sizeof *p); |
064af421 | 388 | p->fallback_dpid = pick_fallback_dpid(); |
fa60c019 | 389 | p->datapath_id = p->fallback_dpid; |
5a719c38 JP |
390 | p->mfr_desc = xstrdup(DEFAULT_MFR_DESC); |
391 | p->hw_desc = xstrdup(DEFAULT_HW_DESC); | |
392 | p->sw_desc = xstrdup(DEFAULT_SW_DESC); | |
393 | p->serial_desc = xstrdup(DEFAULT_SERIAL_DESC); | |
23ff2821 | 394 | p->dp_desc = xstrdup(DEFAULT_DP_DESC); |
064af421 BP |
395 | |
396 | /* Initialize datapath. */ | |
397 | p->dpif = dpif; | |
8b61709d | 398 | p->netdev_monitor = netdev_monitor_create(); |
ca0f572c | 399 | hmap_init(&p->ports); |
064af421 | 400 | shash_init(&p->port_by_name); |
996c1b3d | 401 | p->max_ports = dpif_get_max_ports(dpif); |
064af421 BP |
402 | |
403 | /* Initialize submodules. */ | |
064af421 | 404 | p->netflow = NULL; |
72b06300 | 405 | p->sflow = NULL; |
064af421 BP |
406 | |
407 | /* Initialize flow table. */ | |
408 | classifier_init(&p->cls); | |
79e745c9 | 409 | timer_set_duration(&p->next_expiration, 1000); |
bcf84111 BP |
410 | |
411 | /* Initialize facet table. */ | |
412 | hmap_init(&p->facets); | |
413 | p->need_revalidate = false; | |
064af421 BP |
414 | tag_set_init(&p->revalidate_set); |
415 | ||
064af421 BP |
416 | /* Initialize hooks. */ |
417 | if (ofhooks) { | |
418 | p->ofhooks = ofhooks; | |
419 | p->aux = aux; | |
420 | p->ml = NULL; | |
421 | } else { | |
422 | p->ofhooks = &default_ofhooks; | |
423 | p->aux = p; | |
424 | p->ml = mac_learning_create(); | |
425 | } | |
426 | ||
fa60c019 BP |
427 | /* Pick final datapath ID. */ |
428 | p->datapath_id = pick_datapath_id(p); | |
b123cc3c | 429 | VLOG_INFO("using datapath ID %016"PRIx64, p->datapath_id); |
fa60c019 | 430 | |
7aa697dd BP |
431 | shash_add_once(&all_ofprotos, dpif_name(p->dpif), p); |
432 | ||
19a87e36 BP |
433 | /* Initialize OpenFlow connections. */ |
434 | p->connmgr = connmgr_create(p, datapath, local_name); | |
435 | ||
064af421 BP |
436 | *ofprotop = p; |
437 | return 0; | |
438 | } | |
439 | ||
440 | void | |
441 | ofproto_set_datapath_id(struct ofproto *p, uint64_t datapath_id) | |
442 | { | |
443 | uint64_t old_dpid = p->datapath_id; | |
fa60c019 | 444 | p->datapath_id = datapath_id ? datapath_id : pick_datapath_id(p); |
064af421 | 445 | if (p->datapath_id != old_dpid) { |
b123cc3c | 446 | VLOG_INFO("datapath ID changed to %016"PRIx64, p->datapath_id); |
76ce9432 BP |
447 | |
448 | /* Force all active connections to reconnect, since there is no way to | |
449 | * notify a controller that the datapath ID has changed. */ | |
fa05809b | 450 | ofproto_reconnect_controllers(p); |
064af421 BP |
451 | } |
452 | } | |
453 | ||
76ce9432 BP |
454 | void |
455 | ofproto_set_controllers(struct ofproto *p, | |
456 | const struct ofproto_controller *controllers, | |
457 | size_t n_controllers) | |
458 | { | |
19a87e36 | 459 | connmgr_set_controllers(p->connmgr, controllers, n_controllers); |
064af421 BP |
460 | } |
461 | ||
31681a5d JP |
462 | void |
463 | ofproto_set_fail_mode(struct ofproto *p, enum ofproto_fail_mode fail_mode) | |
464 | { | |
19a87e36 | 465 | connmgr_set_fail_mode(p->connmgr, fail_mode); |
31681a5d JP |
466 | } |
467 | ||
fa05809b BP |
468 | /* Drops the connections between 'ofproto' and all of its controllers, forcing |
469 | * them to reconnect. */ | |
470 | void | |
471 | ofproto_reconnect_controllers(struct ofproto *ofproto) | |
472 | { | |
19a87e36 | 473 | connmgr_reconnect(ofproto->connmgr); |
917e50e1 BP |
474 | } |
475 | ||
476 | /* Sets the 'n' TCP port addresses in 'extras' as ones to which 'ofproto''s | |
477 | * in-band control should guarantee access, in the same way that in-band | |
478 | * control guarantees access to OpenFlow controllers. */ | |
479 | void | |
480 | ofproto_set_extra_in_band_remotes(struct ofproto *ofproto, | |
481 | const struct sockaddr_in *extras, size_t n) | |
482 | { | |
19a87e36 | 483 | connmgr_set_extra_in_band_remotes(ofproto->connmgr, extras, n); |
917e50e1 BP |
484 | } |
485 | ||
b1da6250 BP |
486 | /* Sets the OpenFlow queue used by flows set up by in-band control on |
487 | * 'ofproto' to 'queue_id'. If 'queue_id' is negative, then in-band control | |
488 | * flows will use the default queue. */ | |
489 | void | |
490 | ofproto_set_in_band_queue(struct ofproto *ofproto, int queue_id) | |
491 | { | |
19a87e36 | 492 | connmgr_set_in_band_queue(ofproto->connmgr, queue_id); |
b1da6250 BP |
493 | } |
494 | ||
064af421 BP |
495 | void |
496 | ofproto_set_desc(struct ofproto *p, | |
5a719c38 JP |
497 | const char *mfr_desc, const char *hw_desc, |
498 | const char *sw_desc, const char *serial_desc, | |
8abc4ed7 | 499 | const char *dp_desc) |
064af421 | 500 | { |
5a719c38 JP |
501 | struct ofp_desc_stats *ods; |
502 | ||
503 | if (mfr_desc) { | |
504 | if (strlen(mfr_desc) >= sizeof ods->mfr_desc) { | |
505 | VLOG_WARN("truncating mfr_desc, must be less than %zu characters", | |
506 | sizeof ods->mfr_desc); | |
507 | } | |
508 | free(p->mfr_desc); | |
509 | p->mfr_desc = xstrdup(mfr_desc); | |
064af421 | 510 | } |
5a719c38 JP |
511 | if (hw_desc) { |
512 | if (strlen(hw_desc) >= sizeof ods->hw_desc) { | |
513 | VLOG_WARN("truncating hw_desc, must be less than %zu characters", | |
514 | sizeof ods->hw_desc); | |
515 | } | |
516 | free(p->hw_desc); | |
517 | p->hw_desc = xstrdup(hw_desc); | |
064af421 | 518 | } |
5a719c38 JP |
519 | if (sw_desc) { |
520 | if (strlen(sw_desc) >= sizeof ods->sw_desc) { | |
521 | VLOG_WARN("truncating sw_desc, must be less than %zu characters", | |
522 | sizeof ods->sw_desc); | |
523 | } | |
524 | free(p->sw_desc); | |
525 | p->sw_desc = xstrdup(sw_desc); | |
526 | } | |
527 | if (serial_desc) { | |
528 | if (strlen(serial_desc) >= sizeof ods->serial_num) { | |
529 | VLOG_WARN("truncating serial_desc, must be less than %zu " | |
530 | "characters", | |
531 | sizeof ods->serial_num); | |
532 | } | |
533 | free(p->serial_desc); | |
534 | p->serial_desc = xstrdup(serial_desc); | |
064af421 | 535 | } |
8abc4ed7 | 536 | if (dp_desc) { |
5a719c38 JP |
537 | if (strlen(dp_desc) >= sizeof ods->dp_desc) { |
538 | VLOG_WARN("truncating dp_desc, must be less than %zu characters", | |
539 | sizeof ods->dp_desc); | |
540 | } | |
8abc4ed7 JP |
541 | free(p->dp_desc); |
542 | p->dp_desc = xstrdup(dp_desc); | |
543 | } | |
064af421 BP |
544 | } |
545 | ||
064af421 BP |
546 | int |
547 | ofproto_set_snoops(struct ofproto *ofproto, const struct svec *snoops) | |
548 | { | |
19a87e36 | 549 | return connmgr_set_snoops(ofproto->connmgr, snoops); |
064af421 BP |
550 | } |
551 | ||
552 | int | |
0193b2af JG |
553 | ofproto_set_netflow(struct ofproto *ofproto, |
554 | const struct netflow_options *nf_options) | |
064af421 | 555 | { |
76343538 | 556 | if (nf_options && nf_options->collectors.n) { |
064af421 BP |
557 | if (!ofproto->netflow) { |
558 | ofproto->netflow = netflow_create(); | |
559 | } | |
0193b2af | 560 | return netflow_set_options(ofproto->netflow, nf_options); |
064af421 BP |
561 | } else { |
562 | netflow_destroy(ofproto->netflow); | |
563 | ofproto->netflow = NULL; | |
564 | return 0; | |
565 | } | |
566 | } | |
567 | ||
72b06300 BP |
568 | void |
569 | ofproto_set_sflow(struct ofproto *ofproto, | |
570 | const struct ofproto_sflow_options *oso) | |
571 | { | |
572 | struct ofproto_sflow *os = ofproto->sflow; | |
573 | if (oso) { | |
574 | if (!os) { | |
575 | struct ofport *ofport; | |
72b06300 BP |
576 | |
577 | os = ofproto->sflow = ofproto_sflow_create(ofproto->dpif); | |
4e8e4213 | 578 | HMAP_FOR_EACH (ofport, hmap_node, &ofproto->ports) { |
ca0f572c | 579 | ofproto_sflow_add_port(os, ofport->odp_port, |
72b06300 BP |
580 | netdev_get_name(ofport->netdev)); |
581 | } | |
582 | } | |
583 | ofproto_sflow_set_options(os, oso); | |
584 | } else { | |
585 | ofproto_sflow_destroy(os); | |
586 | ofproto->sflow = NULL; | |
587 | } | |
588 | } | |
e7934396 BP |
589 | \f |
590 | /* Connectivity Fault Management configuration. */ | |
591 | ||
592 | /* Clears the CFM configuration from 'port_no' on 'ofproto'. */ | |
593 | void | |
594 | ofproto_iface_clear_cfm(struct ofproto *ofproto, uint32_t port_no) | |
595 | { | |
596 | struct ofport *ofport = get_port(ofproto, port_no); | |
597 | if (ofport && ofport->cfm){ | |
598 | cfm_destroy(ofport->cfm); | |
599 | ofport->cfm = NULL; | |
600 | } | |
601 | } | |
72b06300 | 602 | |
e7934396 BP |
603 | /* Configures connectivity fault management on 'port_no' in 'ofproto'. Takes |
604 | * basic configuration from the configuration members in 'cfm', and the set of | |
605 | * remote maintenance points from the 'n_remote_mps' elements in 'remote_mps'. | |
606 | * Ignores the statistics members of 'cfm'. | |
607 | * | |
608 | * This function has no effect if 'ofproto' does not have a port 'port_no'. */ | |
609 | void | |
610 | ofproto_iface_set_cfm(struct ofproto *ofproto, uint32_t port_no, | |
611 | const struct cfm *cfm, | |
612 | const uint16_t *remote_mps, size_t n_remote_mps) | |
613 | { | |
614 | struct ofport *ofport; | |
615 | ||
616 | ofport = get_port(ofproto, port_no); | |
617 | if (!ofport) { | |
618 | VLOG_WARN("%s: cannot configure CFM on nonexistent port %"PRIu32, | |
619 | dpif_name(ofproto->dpif), port_no); | |
620 | return; | |
621 | } | |
622 | ||
623 | if (!ofport->cfm) { | |
624 | ofport->cfm = cfm_create(); | |
625 | } | |
626 | ||
627 | ofport->cfm->mpid = cfm->mpid; | |
628 | ofport->cfm->interval = cfm->interval; | |
e7934396 BP |
629 | memcpy(ofport->cfm->maid, cfm->maid, CCM_MAID_LEN); |
630 | ||
631 | cfm_update_remote_mps(ofport->cfm, remote_mps, n_remote_mps); | |
632 | ||
633 | if (!cfm_configure(ofport->cfm)) { | |
634 | VLOG_WARN("%s: CFM configuration on port %"PRIu32" (%s) failed", | |
635 | dpif_name(ofproto->dpif), port_no, | |
636 | netdev_get_name(ofport->netdev)); | |
637 | cfm_destroy(ofport->cfm); | |
638 | ofport->cfm = NULL; | |
639 | } | |
640 | } | |
641 | ||
642 | /* Returns the connectivity fault management object associated with 'port_no' | |
643 | * within 'ofproto', or a null pointer if 'ofproto' does not have a port | |
644 | * 'port_no' or if that port does not have CFM configured. The caller must not | |
645 | * modify or destroy the returned object. */ | |
646 | const struct cfm * | |
647 | ofproto_iface_get_cfm(struct ofproto *ofproto, uint32_t port_no) | |
648 | { | |
649 | struct ofport *ofport = get_port(ofproto, port_no); | |
650 | return ofport ? ofport->cfm : NULL; | |
651 | } | |
652 | \f | |
064af421 BP |
653 | uint64_t |
654 | ofproto_get_datapath_id(const struct ofproto *ofproto) | |
655 | { | |
656 | return ofproto->datapath_id; | |
657 | } | |
658 | ||
76ce9432 | 659 | bool |
7d674866 | 660 | ofproto_has_primary_controller(const struct ofproto *ofproto) |
064af421 | 661 | { |
19a87e36 | 662 | return connmgr_has_controllers(ofproto->connmgr); |
064af421 BP |
663 | } |
664 | ||
abdfe474 JP |
665 | enum ofproto_fail_mode |
666 | ofproto_get_fail_mode(const struct ofproto *p) | |
667 | { | |
19a87e36 | 668 | return connmgr_get_fail_mode(p->connmgr); |
abdfe474 JP |
669 | } |
670 | ||
064af421 BP |
671 | void |
672 | ofproto_get_snoops(const struct ofproto *ofproto, struct svec *snoops) | |
673 | { | |
19a87e36 | 674 | connmgr_get_snoops(ofproto->connmgr, snoops); |
064af421 BP |
675 | } |
676 | ||
677 | void | |
678 | ofproto_destroy(struct ofproto *p) | |
679 | { | |
ca0f572c | 680 | struct ofport *ofport, *next_ofport; |
064af421 BP |
681 | |
682 | if (!p) { | |
683 | return; | |
684 | } | |
685 | ||
7aa697dd BP |
686 | shash_find_and_delete(&all_ofprotos, dpif_name(p->dpif)); |
687 | ||
064af421 | 688 | ofproto_flush_flows(p); |
f41240e6 | 689 | connmgr_destroy(p->connmgr); |
064af421 | 690 | classifier_destroy(&p->cls); |
bcf84111 | 691 | hmap_destroy(&p->facets); |
064af421 | 692 | |
c228a364 | 693 | dpif_close(p->dpif); |
e9e28be3 | 694 | netdev_monitor_destroy(p->netdev_monitor); |
4e8e4213 | 695 | HMAP_FOR_EACH_SAFE (ofport, next_ofport, hmap_node, &p->ports) { |
ca0f572c | 696 | hmap_remove(&p->ports, &ofport->hmap_node); |
064af421 BP |
697 | ofport_free(ofport); |
698 | } | |
699 | shash_destroy(&p->port_by_name); | |
700 | ||
064af421 | 701 | netflow_destroy(p->netflow); |
72b06300 | 702 | ofproto_sflow_destroy(p->sflow); |
064af421 | 703 | |
064af421 BP |
704 | mac_learning_destroy(p->ml); |
705 | ||
5a719c38 JP |
706 | free(p->mfr_desc); |
707 | free(p->hw_desc); | |
708 | free(p->sw_desc); | |
709 | free(p->serial_desc); | |
cb871ae0 JP |
710 | free(p->dp_desc); |
711 | ||
ca0f572c | 712 | hmap_destroy(&p->ports); |
3b917492 | 713 | |
064af421 BP |
714 | free(p); |
715 | } | |
716 | ||
717 | int | |
718 | ofproto_run(struct ofproto *p) | |
719 | { | |
720 | int error = ofproto_run1(p); | |
721 | if (!error) { | |
722 | error = ofproto_run2(p, false); | |
723 | } | |
724 | return error; | |
725 | } | |
726 | ||
e9e28be3 BP |
727 | static void |
728 | process_port_change(struct ofproto *ofproto, int error, char *devname) | |
729 | { | |
730 | if (error == ENOBUFS) { | |
731 | reinit_ports(ofproto); | |
732 | } else if (!error) { | |
733 | update_port(ofproto, devname); | |
734 | free(devname); | |
735 | } | |
736 | } | |
737 | ||
064af421 BP |
738 | int |
739 | ofproto_run1(struct ofproto *p) | |
740 | { | |
e7934396 | 741 | struct ofport *ofport; |
064af421 BP |
742 | char *devname; |
743 | int error; | |
744 | int i; | |
745 | ||
149f577a JG |
746 | if (shash_is_empty(&p->port_by_name)) { |
747 | init_ports(p); | |
748 | } | |
749 | ||
064af421 | 750 | for (i = 0; i < 50; i++) { |
856081f6 | 751 | struct dpif_upcall packet; |
064af421 | 752 | |
856081f6 | 753 | error = dpif_recv(p->dpif, &packet); |
064af421 BP |
754 | if (error) { |
755 | if (error == ENODEV) { | |
756 | /* Someone destroyed the datapath behind our back. The caller | |
757 | * better destroy us and give up, because we're just going to | |
758 | * spin from here on out. */ | |
39a559f2 BP |
759 | static struct vlog_rate_limit rl2 = VLOG_RATE_LIMIT_INIT(1, 5); |
760 | VLOG_ERR_RL(&rl2, "%s: datapath was destroyed externally", | |
c228a364 | 761 | dpif_name(p->dpif)); |
064af421 BP |
762 | return ENODEV; |
763 | } | |
764 | break; | |
765 | } | |
766 | ||
856081f6 | 767 | handle_upcall(p, &packet); |
064af421 BP |
768 | } |
769 | ||
e9e28be3 BP |
770 | while ((error = dpif_port_poll(p->dpif, &devname)) != EAGAIN) { |
771 | process_port_change(p, error, devname); | |
772 | } | |
773 | while ((error = netdev_monitor_poll(p->netdev_monitor, | |
774 | &devname)) != EAGAIN) { | |
775 | process_port_change(p, error, devname); | |
064af421 BP |
776 | } |
777 | ||
e7934396 BP |
778 | HMAP_FOR_EACH (ofport, hmap_node, &p->ports) { |
779 | ofport_run(p, ofport); | |
780 | } | |
781 | ||
19a87e36 | 782 | connmgr_run(p->connmgr, handle_openflow); |
064af421 | 783 | |
79e745c9 | 784 | if (timer_expired(&p->next_expiration)) { |
0de7a4b4 | 785 | int delay = ofproto_expire(p); |
79e745c9 | 786 | timer_set_duration(&p->next_expiration, delay); |
064af421 | 787 | COVERAGE_INC(ofproto_expiration); |
064af421 BP |
788 | } |
789 | ||
790 | if (p->netflow) { | |
791 | netflow_run(p->netflow); | |
792 | } | |
72b06300 BP |
793 | if (p->sflow) { |
794 | ofproto_sflow_run(p->sflow); | |
795 | } | |
064af421 BP |
796 | |
797 | return 0; | |
798 | } | |
799 | ||
064af421 BP |
800 | int |
801 | ofproto_run2(struct ofproto *p, bool revalidate_all) | |
802 | { | |
bcf84111 BP |
803 | /* Figure out what we need to revalidate now, if anything. */ |
804 | struct tag_set revalidate_set = p->revalidate_set; | |
805 | if (p->need_revalidate) { | |
806 | revalidate_all = true; | |
807 | } | |
808 | ||
809 | /* Clear the revalidation flags. */ | |
810 | tag_set_init(&p->revalidate_set); | |
811 | p->need_revalidate = false; | |
812 | ||
813 | /* Now revalidate if there's anything to do. */ | |
814 | if (revalidate_all || !tag_set_is_empty(&revalidate_set)) { | |
815 | struct facet *facet, *next; | |
816 | ||
817 | HMAP_FOR_EACH_SAFE (facet, next, hmap_node, &p->facets) { | |
818 | if (revalidate_all | |
819 | || tag_set_intersects(&revalidate_set, facet->tags)) { | |
820 | facet_revalidate(p, facet); | |
821 | } | |
822 | } | |
064af421 BP |
823 | } |
824 | ||
825 | return 0; | |
826 | } | |
827 | ||
828 | void | |
829 | ofproto_wait(struct ofproto *p) | |
830 | { | |
e7934396 | 831 | struct ofport *ofport; |
064af421 | 832 | |
e7934396 BP |
833 | HMAP_FOR_EACH (ofport, hmap_node, &p->ports) { |
834 | ofport_wait(ofport); | |
835 | } | |
19a87e36 BP |
836 | dpif_recv_wait(p->dpif); |
837 | dpif_port_poll_wait(p->dpif); | |
838 | netdev_monitor_poll_wait(p->netdev_monitor); | |
72b06300 BP |
839 | if (p->sflow) { |
840 | ofproto_sflow_wait(p->sflow); | |
841 | } | |
064af421 BP |
842 | if (!tag_set_is_empty(&p->revalidate_set)) { |
843 | poll_immediate_wake(); | |
844 | } | |
845 | if (p->need_revalidate) { | |
846 | /* Shouldn't happen, but if it does just go around again. */ | |
847 | VLOG_DBG_RL(&rl, "need revalidate in ofproto_wait_cb()"); | |
848 | poll_immediate_wake(); | |
79e745c9 EJ |
849 | } else { |
850 | timer_wait(&p->next_expiration); | |
064af421 | 851 | } |
19a87e36 | 852 | connmgr_wait(p->connmgr); |
064af421 BP |
853 | } |
854 | ||
855 | void | |
856 | ofproto_revalidate(struct ofproto *ofproto, tag_type tag) | |
857 | { | |
858 | tag_set_add(&ofproto->revalidate_set, tag); | |
859 | } | |
860 | ||
861 | struct tag_set * | |
862 | ofproto_get_revalidate_set(struct ofproto *ofproto) | |
863 | { | |
864 | return &ofproto->revalidate_set; | |
865 | } | |
866 | ||
867 | bool | |
868 | ofproto_is_alive(const struct ofproto *p) | |
869 | { | |
19a87e36 | 870 | return connmgr_has_controllers(p->connmgr); |
064af421 BP |
871 | } |
872 | ||
bffc0589 | 873 | void |
2cdcb898 | 874 | ofproto_get_ofproto_controller_info(const struct ofproto *ofproto, |
bffc0589 AE |
875 | struct shash *info) |
876 | { | |
19a87e36 | 877 | connmgr_get_controller_info(ofproto->connmgr, info); |
bffc0589 AE |
878 | } |
879 | ||
880 | void | |
881 | ofproto_free_ofproto_controller_info(struct shash *info) | |
882 | { | |
883 | struct shash_node *node; | |
884 | ||
885 | SHASH_FOR_EACH (node, info) { | |
886 | struct ofproto_controller_info *cinfo = node->data; | |
887 | while (cinfo->pairs.n) { | |
888 | free((char *) cinfo->pairs.values[--cinfo->pairs.n]); | |
889 | } | |
890 | free(cinfo); | |
891 | } | |
892 | shash_destroy(info); | |
893 | } | |
894 | ||
3a6ccc8c BP |
895 | /* Deletes port number 'odp_port' from the datapath for 'ofproto'. |
896 | * | |
897 | * This is almost the same as calling dpif_port_del() directly on the | |
898 | * datapath, but it also makes 'ofproto' close its open netdev for the port | |
899 | * (if any). This makes it possible to create a new netdev of a different | |
900 | * type under the same name, which otherwise the netdev library would refuse | |
901 | * to do because of the conflict. (The netdev would eventually get closed on | |
902 | * the next trip through ofproto_run(), but this interface is more direct.) | |
903 | * | |
3a6ccc8c BP |
904 | * Returns 0 if successful, otherwise a positive errno. */ |
905 | int | |
906 | ofproto_port_del(struct ofproto *ofproto, uint16_t odp_port) | |
907 | { | |
908 | struct ofport *ofport = get_port(ofproto, odp_port); | |
0b61210e | 909 | const char *name = ofport ? ofport->opp.name : "<unknown>"; |
3a6ccc8c BP |
910 | int error; |
911 | ||
912 | error = dpif_port_del(ofproto->dpif, odp_port); | |
913 | if (error) { | |
914 | VLOG_ERR("%s: failed to remove port %"PRIu16" (%s) interface (%s)", | |
915 | dpif_name(ofproto->dpif), odp_port, name, strerror(error)); | |
916 | } else if (ofport) { | |
917 | /* 'name' is ofport->opp.name and update_port() is going to destroy | |
918 | * 'ofport'. Just in case update_port() refers to 'name' after it | |
919 | * destroys 'ofport', make a copy of it around the update_port() | |
920 | * call. */ | |
921 | char *devname = xstrdup(name); | |
922 | update_port(ofproto, devname); | |
923 | free(devname); | |
924 | } | |
925 | return error; | |
926 | } | |
927 | ||
a4e2e1f2 EJ |
928 | /* Checks if 'ofproto' thinks 'odp_port' should be included in floods. Returns |
929 | * true if 'odp_port' exists and should be included, false otherwise. */ | |
930 | bool | |
931 | ofproto_port_is_floodable(struct ofproto *ofproto, uint16_t odp_port) | |
932 | { | |
933 | struct ofport *ofport = get_port(ofproto, odp_port); | |
934 | return ofport && !(ofport->opp.config & OFPPC_NO_FLOOD); | |
935 | } | |
936 | ||
3cf10406 BP |
937 | /* Sends 'packet' out of port 'port_no' within 'p'. If 'vlan_tci' is zero the |
938 | * packet will not have any 802.1Q hader; if it is nonzero, then the packet | |
939 | * will be sent with the VLAN TCI specified by 'vlan_tci & ~VLAN_CFI'. | |
940 | * | |
941 | * Returns 0 if successful, otherwise a positive errno value. */ | |
064af421 | 942 | int |
3cf10406 BP |
943 | ofproto_send_packet(struct ofproto *ofproto, |
944 | uint32_t port_no, uint16_t vlan_tci, | |
064af421 BP |
945 | const struct ofpbuf *packet) |
946 | { | |
3cf10406 BP |
947 | struct ofpbuf odp_actions; |
948 | int error; | |
cdee00fd | 949 | |
3cf10406 BP |
950 | ofpbuf_init(&odp_actions, 32); |
951 | if (vlan_tci != 0) { | |
952 | nl_msg_put_u32(&odp_actions, ODP_ACTION_ATTR_SET_DL_TCI, | |
953 | ntohs(vlan_tci & ~VLAN_CFI)); | |
954 | } | |
955 | nl_msg_put_u32(&odp_actions, ODP_ACTION_ATTR_OUTPUT, port_no); | |
956 | error = dpif_execute(ofproto->dpif, odp_actions.data, odp_actions.size, | |
957 | packet); | |
958 | ofpbuf_uninit(&odp_actions); | |
cdee00fd | 959 | |
3cf10406 BP |
960 | if (error) { |
961 | VLOG_WARN_RL(&rl, "%s: failed to send packet on port %"PRIu32" (%s)", | |
962 | dpif_name(ofproto->dpif), port_no, strerror(error)); | |
963 | } | |
964 | return error; | |
064af421 BP |
965 | } |
966 | ||
fa8b054f BP |
967 | /* Adds a flow to the OpenFlow flow table in 'p' that matches 'cls_rule' and |
968 | * performs the 'n_actions' actions in 'actions'. The new flow will not | |
969 | * timeout. | |
970 | * | |
971 | * If cls_rule->priority is in the range of priorities supported by OpenFlow | |
972 | * (0...65535, inclusive) then the flow will be visible to OpenFlow | |
973 | * controllers; otherwise, it will be hidden. | |
974 | * | |
975 | * The caller retains ownership of 'cls_rule' and 'actions'. */ | |
064af421 | 976 | void |
cf3fad8a | 977 | ofproto_add_flow(struct ofproto *p, const struct cls_rule *cls_rule, |
fa8b054f | 978 | const union ofp_action *actions, size_t n_actions) |
064af421 BP |
979 | { |
980 | struct rule *rule; | |
bcf84111 | 981 | rule = rule_create(cls_rule, actions, n_actions, 0, 0, 0, false); |
afe75089 | 982 | rule_insert(p, rule); |
064af421 BP |
983 | } |
984 | ||
985 | void | |
cf3fad8a | 986 | ofproto_delete_flow(struct ofproto *ofproto, const struct cls_rule *target) |
064af421 BP |
987 | { |
988 | struct rule *rule; | |
989 | ||
990 | rule = rule_from_cls_rule(classifier_find_rule_exactly(&ofproto->cls, | |
cf3fad8a | 991 | target)); |
064af421 BP |
992 | if (rule) { |
993 | rule_remove(ofproto, rule); | |
994 | } | |
995 | } | |
996 | ||
064af421 BP |
997 | void |
998 | ofproto_flush_flows(struct ofproto *ofproto) | |
999 | { | |
bcf84111 | 1000 | struct facet *facet, *next_facet; |
5ecc9d81 BP |
1001 | struct rule *rule, *next_rule; |
1002 | struct cls_cursor cursor; | |
bcf84111 | 1003 | |
064af421 | 1004 | COVERAGE_INC(ofproto_flush); |
bcf84111 BP |
1005 | |
1006 | HMAP_FOR_EACH_SAFE (facet, next_facet, hmap_node, &ofproto->facets) { | |
1007 | /* Mark the facet as not installed so that facet_remove() doesn't | |
1008 | * bother trying to uninstall it. There is no point in uninstalling it | |
1009 | * individually since we are about to blow away all the facets with | |
1010 | * dpif_flow_flush(). */ | |
1011 | facet->installed = false; | |
a2c6a63c EJ |
1012 | facet->dp_packet_count = 0; |
1013 | facet->dp_byte_count = 0; | |
bcf84111 BP |
1014 | facet_remove(ofproto, facet); |
1015 | } | |
5ecc9d81 BP |
1016 | |
1017 | cls_cursor_init(&cursor, &ofproto->cls, NULL); | |
1018 | CLS_CURSOR_FOR_EACH_SAFE (rule, next_rule, cr, &cursor) { | |
1019 | rule_remove(ofproto, rule); | |
1020 | } | |
1021 | ||
c228a364 | 1022 | dpif_flow_flush(ofproto->dpif); |
19a87e36 | 1023 | connmgr_flushed(ofproto->connmgr); |
064af421 BP |
1024 | } |
1025 | \f | |
1026 | static void | |
1027 | reinit_ports(struct ofproto *p) | |
1028 | { | |
b0ec0f27 | 1029 | struct dpif_port_dump dump; |
b3c01ed3 | 1030 | struct sset devnames; |
064af421 | 1031 | struct ofport *ofport; |
4c738a8d | 1032 | struct dpif_port dpif_port; |
b3c01ed3 | 1033 | const char *devname; |
064af421 | 1034 | |
898bf89d JP |
1035 | COVERAGE_INC(ofproto_reinit_ports); |
1036 | ||
b3c01ed3 | 1037 | sset_init(&devnames); |
4e8e4213 | 1038 | HMAP_FOR_EACH (ofport, hmap_node, &p->ports) { |
b3c01ed3 | 1039 | sset_add(&devnames, ofport->opp.name); |
064af421 | 1040 | } |
4c738a8d | 1041 | DPIF_PORT_FOR_EACH (&dpif_port, &dump, p->dpif) { |
b3c01ed3 | 1042 | sset_add(&devnames, dpif_port.name); |
064af421 | 1043 | } |
064af421 | 1044 | |
b3c01ed3 BP |
1045 | SSET_FOR_EACH (devname, &devnames) { |
1046 | update_port(p, devname); | |
064af421 | 1047 | } |
b3c01ed3 | 1048 | sset_destroy(&devnames); |
064af421 BP |
1049 | } |
1050 | ||
064af421 | 1051 | static struct ofport * |
4c738a8d | 1052 | make_ofport(const struct dpif_port *dpif_port) |
064af421 | 1053 | { |
149f577a | 1054 | struct netdev_options netdev_options; |
064af421 BP |
1055 | enum netdev_flags flags; |
1056 | struct ofport *ofport; | |
1057 | struct netdev *netdev; | |
064af421 BP |
1058 | int error; |
1059 | ||
149f577a | 1060 | memset(&netdev_options, 0, sizeof netdev_options); |
4c738a8d BP |
1061 | netdev_options.name = dpif_port->name; |
1062 | netdev_options.type = dpif_port->type; | |
149f577a | 1063 | netdev_options.ethertype = NETDEV_ETH_TYPE_NONE; |
149f577a JG |
1064 | |
1065 | error = netdev_open(&netdev_options, &netdev); | |
064af421 BP |
1066 | if (error) { |
1067 | VLOG_WARN_RL(&rl, "ignoring port %s (%"PRIu16") because netdev %s " | |
1068 | "cannot be opened (%s)", | |
4c738a8d BP |
1069 | dpif_port->name, dpif_port->port_no, |
1070 | dpif_port->name, strerror(error)); | |
064af421 BP |
1071 | return NULL; |
1072 | } | |
1073 | ||
0a6f5542 | 1074 | ofport = xzalloc(sizeof *ofport); |
064af421 | 1075 | ofport->netdev = netdev; |
4c738a8d BP |
1076 | ofport->odp_port = dpif_port->port_no; |
1077 | ofport->opp.port_no = odp_port_to_ofp_port(dpif_port->port_no); | |
80992a35 | 1078 | netdev_get_etheraddr(netdev, ofport->opp.hw_addr); |
4c738a8d | 1079 | ovs_strlcpy(ofport->opp.name, dpif_port->name, sizeof ofport->opp.name); |
064af421 BP |
1080 | |
1081 | netdev_get_flags(netdev, &flags); | |
1082 | ofport->opp.config = flags & NETDEV_UP ? 0 : OFPPC_PORT_DOWN; | |
1083 | ||
85da620e | 1084 | ofport->opp.state = netdev_get_carrier(netdev) ? 0 : OFPPS_LINK_DOWN; |
064af421 BP |
1085 | |
1086 | netdev_get_features(netdev, | |
1087 | &ofport->opp.curr, &ofport->opp.advertised, | |
1088 | &ofport->opp.supported, &ofport->opp.peer); | |
1089 | return ofport; | |
1090 | } | |
1091 | ||
1092 | static bool | |
4c738a8d | 1093 | ofport_conflicts(const struct ofproto *p, const struct dpif_port *dpif_port) |
064af421 | 1094 | { |
4c738a8d | 1095 | if (get_port(p, dpif_port->port_no)) { |
064af421 | 1096 | VLOG_WARN_RL(&rl, "ignoring duplicate port %"PRIu16" in datapath", |
4c738a8d | 1097 | dpif_port->port_no); |
064af421 | 1098 | return true; |
4c738a8d | 1099 | } else if (shash_find(&p->port_by_name, dpif_port->name)) { |
064af421 | 1100 | VLOG_WARN_RL(&rl, "ignoring duplicate device %s in datapath", |
4c738a8d | 1101 | dpif_port->name); |
064af421 BP |
1102 | return true; |
1103 | } else { | |
1104 | return false; | |
1105 | } | |
1106 | } | |
1107 | ||
1108 | static int | |
1109 | ofport_equal(const struct ofport *a_, const struct ofport *b_) | |
1110 | { | |
1111 | const struct ofp_phy_port *a = &a_->opp; | |
1112 | const struct ofp_phy_port *b = &b_->opp; | |
1113 | ||
1114 | BUILD_ASSERT_DECL(sizeof *a == 48); /* Detect ofp_phy_port changes. */ | |
1115 | return (a->port_no == b->port_no | |
1116 | && !memcmp(a->hw_addr, b->hw_addr, sizeof a->hw_addr) | |
0b61210e | 1117 | && !strcmp(a->name, b->name) |
064af421 BP |
1118 | && a->state == b->state |
1119 | && a->config == b->config | |
1120 | && a->curr == b->curr | |
1121 | && a->advertised == b->advertised | |
1122 | && a->supported == b->supported | |
1123 | && a->peer == b->peer); | |
1124 | } | |
1125 | ||
064af421 BP |
1126 | static void |
1127 | ofport_install(struct ofproto *p, struct ofport *ofport) | |
1128 | { | |
0b61210e | 1129 | const char *netdev_name = ofport->opp.name; |
72b06300 | 1130 | |
e9e28be3 | 1131 | netdev_monitor_add(p->netdev_monitor, ofport->netdev); |
ca0f572c | 1132 | hmap_insert(&p->ports, &ofport->hmap_node, hash_int(ofport->odp_port, 0)); |
72b06300 BP |
1133 | shash_add(&p->port_by_name, netdev_name, ofport); |
1134 | if (p->sflow) { | |
ca0f572c | 1135 | ofproto_sflow_add_port(p->sflow, ofport->odp_port, netdev_name); |
72b06300 | 1136 | } |
064af421 BP |
1137 | } |
1138 | ||
1139 | static void | |
1140 | ofport_remove(struct ofproto *p, struct ofport *ofport) | |
1141 | { | |
e9e28be3 | 1142 | netdev_monitor_remove(p->netdev_monitor, ofport->netdev); |
ca0f572c | 1143 | hmap_remove(&p->ports, &ofport->hmap_node); |
064af421 | 1144 | shash_delete(&p->port_by_name, |
0b61210e | 1145 | shash_find(&p->port_by_name, ofport->opp.name)); |
72b06300 | 1146 | if (p->sflow) { |
ca0f572c | 1147 | ofproto_sflow_del_port(p->sflow, ofport->odp_port); |
72b06300 | 1148 | } |
064af421 BP |
1149 | } |
1150 | ||
e7934396 BP |
1151 | static void |
1152 | ofport_run(struct ofproto *ofproto, struct ofport *ofport) | |
1153 | { | |
1154 | if (ofport->cfm) { | |
a58727fb EJ |
1155 | cfm_run(ofport->cfm); |
1156 | ||
1157 | if (cfm_should_send_ccm(ofport->cfm)) { | |
1158 | struct ofpbuf packet; | |
1159 | struct ccm *ccm; | |
1160 | ||
1161 | ofpbuf_init(&packet, 0); | |
1162 | ccm = compose_packet(&packet, eth_addr_ccm, ofport->opp.hw_addr, | |
1163 | ETH_TYPE_CFM, sizeof *ccm); | |
1164 | cfm_compose_ccm(ofport->cfm, ccm); | |
1165 | ofproto_send_packet(ofproto, ofport->odp_port, 0, &packet); | |
1166 | ofpbuf_uninit(&packet); | |
e7934396 BP |
1167 | } |
1168 | } | |
1169 | } | |
1170 | ||
1171 | static void | |
1172 | ofport_wait(struct ofport *ofport) | |
1173 | { | |
1174 | if (ofport->cfm) { | |
1175 | cfm_wait(ofport->cfm); | |
1176 | } | |
1177 | } | |
1178 | ||
064af421 BP |
1179 | static void |
1180 | ofport_free(struct ofport *ofport) | |
1181 | { | |
1182 | if (ofport) { | |
e7934396 | 1183 | cfm_destroy(ofport->cfm); |
064af421 BP |
1184 | netdev_close(ofport->netdev); |
1185 | free(ofport); | |
1186 | } | |
1187 | } | |
1188 | ||
ca0f572c BP |
1189 | static struct ofport * |
1190 | get_port(const struct ofproto *ofproto, uint16_t odp_port) | |
1191 | { | |
1192 | struct ofport *port; | |
1193 | ||
4e8e4213 | 1194 | HMAP_FOR_EACH_IN_BUCKET (port, hmap_node, |
ca0f572c BP |
1195 | hash_int(odp_port, 0), &ofproto->ports) { |
1196 | if (port->odp_port == odp_port) { | |
1197 | return port; | |
1198 | } | |
1199 | } | |
1200 | return NULL; | |
1201 | } | |
1202 | ||
064af421 BP |
1203 | static void |
1204 | update_port(struct ofproto *p, const char *devname) | |
1205 | { | |
4c738a8d | 1206 | struct dpif_port dpif_port; |
c874dc6d BP |
1207 | struct ofport *old_ofport; |
1208 | struct ofport *new_ofport; | |
064af421 BP |
1209 | int error; |
1210 | ||
1211 | COVERAGE_INC(ofproto_update_port); | |
c874dc6d BP |
1212 | |
1213 | /* Query the datapath for port information. */ | |
4c738a8d | 1214 | error = dpif_port_query_by_name(p->dpif, devname, &dpif_port); |
064af421 | 1215 | |
c874dc6d BP |
1216 | /* Find the old ofport. */ |
1217 | old_ofport = shash_find_data(&p->port_by_name, devname); | |
1218 | if (!error) { | |
1219 | if (!old_ofport) { | |
1220 | /* There's no port named 'devname' but there might be a port with | |
1221 | * the same port number. This could happen if a port is deleted | |
1222 | * and then a new one added in its place very quickly, or if a port | |
1223 | * is renamed. In the former case we want to send an OFPPR_DELETE | |
1224 | * and an OFPPR_ADD, and in the latter case we want to send a | |
1225 | * single OFPPR_MODIFY. We can distinguish the cases by comparing | |
1226 | * the old port's ifindex against the new port, or perhaps less | |
1227 | * reliably but more portably by comparing the old port's MAC | |
1228 | * against the new port's MAC. However, this code isn't that smart | |
1229 | * and always sends an OFPPR_MODIFY (XXX). */ | |
4c738a8d | 1230 | old_ofport = get_port(p, dpif_port.port_no); |
064af421 | 1231 | } |
c874dc6d | 1232 | } else if (error != ENOENT && error != ENODEV) { |
064af421 BP |
1233 | VLOG_WARN_RL(&rl, "dpif_port_query_by_name returned unexpected error " |
1234 | "%s", strerror(error)); | |
4c738a8d | 1235 | goto exit; |
064af421 | 1236 | } |
c874dc6d BP |
1237 | |
1238 | /* Create a new ofport. */ | |
4c738a8d | 1239 | new_ofport = !error ? make_ofport(&dpif_port) : NULL; |
c874dc6d BP |
1240 | |
1241 | /* Eliminate a few pathological cases. */ | |
1242 | if (!old_ofport && !new_ofport) { | |
4c738a8d | 1243 | goto exit; |
c874dc6d BP |
1244 | } else if (old_ofport && new_ofport) { |
1245 | /* Most of the 'config' bits are OpenFlow soft state, but | |
bc4a55cd BP |
1246 | * OFPPC_PORT_DOWN is maintained by the kernel. So transfer the |
1247 | * OpenFlow bits from old_ofport. (make_ofport() only sets | |
1248 | * OFPPC_PORT_DOWN and leaves the other bits 0.) */ | |
c874dc6d BP |
1249 | new_ofport->opp.config |= old_ofport->opp.config & ~OFPPC_PORT_DOWN; |
1250 | ||
1251 | if (ofport_equal(old_ofport, new_ofport)) { | |
1252 | /* False alarm--no change. */ | |
1253 | ofport_free(new_ofport); | |
4c738a8d | 1254 | goto exit; |
c874dc6d BP |
1255 | } |
1256 | } | |
1257 | ||
1258 | /* Now deal with the normal cases. */ | |
1259 | if (old_ofport) { | |
1260 | ofport_remove(p, old_ofport); | |
1261 | } | |
1262 | if (new_ofport) { | |
1263 | ofport_install(p, new_ofport); | |
1264 | } | |
127c9484 BP |
1265 | connmgr_send_port_status(p->connmgr, |
1266 | new_ofport ? &new_ofport->opp : &old_ofport->opp, | |
1267 | (!old_ofport ? OFPPR_ADD | |
1268 | : !new_ofport ? OFPPR_DELETE | |
1269 | : OFPPR_MODIFY)); | |
c874dc6d | 1270 | ofport_free(old_ofport); |
4c738a8d BP |
1271 | |
1272 | exit: | |
1273 | dpif_port_destroy(&dpif_port); | |
064af421 BP |
1274 | } |
1275 | ||
1276 | static int | |
1277 | init_ports(struct ofproto *p) | |
1278 | { | |
b0ec0f27 | 1279 | struct dpif_port_dump dump; |
4c738a8d | 1280 | struct dpif_port dpif_port; |
064af421 | 1281 | |
4c738a8d BP |
1282 | DPIF_PORT_FOR_EACH (&dpif_port, &dump, p->dpif) { |
1283 | if (!ofport_conflicts(p, &dpif_port)) { | |
1284 | struct ofport *ofport = make_ofport(&dpif_port); | |
064af421 BP |
1285 | if (ofport) { |
1286 | ofport_install(p, ofport); | |
1287 | } | |
1288 | } | |
1289 | } | |
b0ec0f27 | 1290 | |
064af421 BP |
1291 | return 0; |
1292 | } | |
1293 | \f | |
bcf84111 BP |
1294 | /* Returns true if 'rule' should be hidden from the controller. |
1295 | * | |
1296 | * Rules with priority higher than UINT16_MAX are set up by ofproto itself | |
1297 | * (e.g. by in-band control) and are intentionally hidden from the | |
1298 | * controller. */ | |
1299 | static bool | |
1300 | rule_is_hidden(const struct rule *rule) | |
1301 | { | |
1302 | return rule->cr.priority > UINT16_MAX; | |
1303 | } | |
1304 | ||
1305 | /* Creates and returns a new rule initialized as specified. | |
1306 | * | |
1307 | * The caller is responsible for inserting the rule into the classifier (with | |
1308 | * rule_insert()). */ | |
064af421 | 1309 | static struct rule * |
bcf84111 | 1310 | rule_create(const struct cls_rule *cls_rule, |
064af421 | 1311 | const union ofp_action *actions, size_t n_actions, |
ca069229 | 1312 | uint16_t idle_timeout, uint16_t hard_timeout, |
8054fc48 | 1313 | ovs_be64 flow_cookie, bool send_flow_removed) |
064af421 | 1314 | { |
ec6fde61 | 1315 | struct rule *rule = xzalloc(sizeof *rule); |
bcf84111 | 1316 | rule->cr = *cls_rule; |
064af421 BP |
1317 | rule->idle_timeout = idle_timeout; |
1318 | rule->hard_timeout = hard_timeout; | |
39997502 | 1319 | rule->flow_cookie = flow_cookie; |
064af421 | 1320 | rule->used = rule->created = time_msec(); |
ca069229 | 1321 | rule->send_flow_removed = send_flow_removed; |
bcf84111 | 1322 | list_init(&rule->facets); |
3dffcf07 BP |
1323 | if (n_actions > 0) { |
1324 | rule->n_actions = n_actions; | |
1325 | rule->actions = xmemdup(actions, n_actions * sizeof *actions); | |
1326 | } | |
0193b2af | 1327 | |
064af421 BP |
1328 | return rule; |
1329 | } | |
1330 | ||
1331 | static struct rule * | |
1332 | rule_from_cls_rule(const struct cls_rule *cls_rule) | |
1333 | { | |
1334 | return cls_rule ? CONTAINER_OF(cls_rule, struct rule, cr) : NULL; | |
1335 | } | |
1336 | ||
1337 | static void | |
1338 | rule_free(struct rule *rule) | |
1339 | { | |
1340 | free(rule->actions); | |
064af421 BP |
1341 | free(rule); |
1342 | } | |
1343 | ||
bcf84111 BP |
1344 | /* Destroys 'rule' and iterates through all of its facets and revalidates them, |
1345 | * destroying any that no longer has a rule (which is probably all of them). | |
064af421 | 1346 | * |
bcf84111 | 1347 | * The caller must have already removed 'rule' from the classifier. */ |
064af421 BP |
1348 | static void |
1349 | rule_destroy(struct ofproto *ofproto, struct rule *rule) | |
1350 | { | |
bcf84111 BP |
1351 | struct facet *facet, *next_facet; |
1352 | LIST_FOR_EACH_SAFE (facet, next_facet, list_node, &rule->facets) { | |
1353 | facet_revalidate(ofproto, facet); | |
064af421 BP |
1354 | } |
1355 | rule_free(rule); | |
1356 | } | |
1357 | ||
bcf84111 BP |
1358 | /* Returns true if 'rule' has an OpenFlow OFPAT_OUTPUT or OFPAT_ENQUEUE action |
1359 | * that outputs to 'out_port' (output to OFPP_FLOOD and OFPP_ALL doesn't | |
1360 | * count). */ | |
064af421 | 1361 | static bool |
8054fc48 | 1362 | rule_has_out_port(const struct rule *rule, ovs_be16 out_port) |
064af421 BP |
1363 | { |
1364 | const union ofp_action *oa; | |
1365 | struct actions_iterator i; | |
1366 | ||
1367 | if (out_port == htons(OFPP_NONE)) { | |
1368 | return true; | |
1369 | } | |
1370 | for (oa = actions_first(&i, rule->actions, rule->n_actions); oa; | |
1371 | oa = actions_next(&i)) { | |
c1c9c9c4 | 1372 | if (action_outputs_to_port(oa, out_port)) { |
064af421 BP |
1373 | return true; |
1374 | } | |
1375 | } | |
1376 | return false; | |
1377 | } | |
1378 | ||
750638bb BP |
1379 | /* Executes, within 'ofproto', the 'n_actions' actions in 'actions' on |
1380 | * 'packet', which arrived on 'in_port'. | |
1381 | * | |
1382 | * Takes ownership of 'packet'. */ | |
9dbb9d5e | 1383 | static bool |
856081f6 | 1384 | execute_odp_actions(struct ofproto *ofproto, const struct flow *flow, |
cf22f8cb | 1385 | const struct nlattr *odp_actions, size_t actions_len, |
750638bb | 1386 | struct ofpbuf *packet) |
9dbb9d5e | 1387 | { |
b9298d3f | 1388 | if (actions_len == NLA_ALIGN(NLA_HDRLEN + sizeof(uint64_t)) |
7aec165d | 1389 | && odp_actions->nla_type == ODP_ACTION_ATTR_CONTROLLER) { |
9dbb9d5e BP |
1390 | /* As an optimization, avoid a round-trip from userspace to kernel to |
1391 | * userspace. This also avoids possibly filling up kernel packet | |
1392 | * buffers along the way. */ | |
856081f6 | 1393 | struct dpif_upcall upcall; |
9dbb9d5e | 1394 | |
82272ede | 1395 | upcall.type = DPIF_UC_ACTION; |
856081f6 BP |
1396 | upcall.packet = packet; |
1397 | upcall.key = NULL; | |
1398 | upcall.key_len = 0; | |
1399 | upcall.userdata = nl_attr_get_u64(odp_actions); | |
1400 | upcall.sample_pool = 0; | |
1401 | upcall.actions = NULL; | |
1402 | upcall.actions_len = 0; | |
9dbb9d5e | 1403 | |
856081f6 | 1404 | send_packet_in(ofproto, &upcall, flow, false); |
9dbb9d5e | 1405 | |
750638bb BP |
1406 | return true; |
1407 | } else { | |
1408 | int error; | |
9dbb9d5e | 1409 | |
cdee00fd | 1410 | error = dpif_execute(ofproto->dpif, odp_actions, actions_len, packet); |
750638bb BP |
1411 | ofpbuf_delete(packet); |
1412 | return !error; | |
1413 | } | |
9dbb9d5e BP |
1414 | } |
1415 | ||
bcf84111 BP |
1416 | /* Executes the actions indicated by 'facet' on 'packet' and credits 'facet''s |
1417 | * statistics appropriately. 'packet' must have at least sizeof(struct | |
1418 | * ofp_packet_in) bytes of headroom. | |
064af421 | 1419 | * |
bcf84111 BP |
1420 | * For correct results, 'packet' must actually be in 'facet''s flow; that is, |
1421 | * applying flow_extract() to 'packet' would yield the same flow as | |
1422 | * 'facet->flow'. | |
064af421 | 1423 | * |
bcf84111 BP |
1424 | * 'facet' must have accurately composed ODP actions; that is, it must not be |
1425 | * in need of revalidation. | |
750638bb BP |
1426 | * |
1427 | * Takes ownership of 'packet'. */ | |
064af421 | 1428 | static void |
bcf84111 BP |
1429 | facet_execute(struct ofproto *ofproto, struct facet *facet, |
1430 | struct ofpbuf *packet) | |
064af421 | 1431 | { |
c97fb132 | 1432 | struct dpif_flow_stats stats; |
bcf84111 BP |
1433 | |
1434 | assert(ofpbuf_headroom(packet) >= sizeof(struct ofp_packet_in)); | |
1435 | ||
1436 | flow_extract_stats(&facet->flow, packet, &stats); | |
9fe215f0 | 1437 | stats.used = time_msec(); |
856081f6 | 1438 | if (execute_odp_actions(ofproto, &facet->flow, |
cdee00fd | 1439 | facet->actions, facet->actions_len, packet)) { |
878ae780 | 1440 | facet_update_stats(ofproto, facet, &stats); |
bcf84111 BP |
1441 | } |
1442 | } | |
1443 | ||
1444 | /* Executes the actions indicated by 'rule' on 'packet' and credits 'rule''s | |
1445 | * statistics (or the statistics for one of its facets) appropriately. | |
1446 | * 'packet' must have at least sizeof(struct ofp_packet_in) bytes of headroom. | |
1447 | * | |
1448 | * 'packet' doesn't necessarily have to match 'rule'. 'rule' will be credited | |
1449 | * with statistics for 'packet' either way. | |
1450 | * | |
1451 | * Takes ownership of 'packet'. */ | |
1452 | static void | |
1453 | rule_execute(struct ofproto *ofproto, struct rule *rule, uint16_t in_port, | |
1454 | struct ofpbuf *packet) | |
1455 | { | |
f29152ca | 1456 | struct action_xlate_ctx ctx; |
cdee00fd | 1457 | struct ofpbuf *odp_actions; |
bcf84111 | 1458 | struct facet *facet; |
bcf84111 BP |
1459 | struct flow flow; |
1460 | size_t size; | |
064af421 | 1461 | |
750638bb BP |
1462 | assert(ofpbuf_headroom(packet) >= sizeof(struct ofp_packet_in)); |
1463 | ||
bcf84111 BP |
1464 | flow_extract(packet, 0, in_port, &flow); |
1465 | ||
1466 | /* First look for a related facet. If we find one, account it to that. */ | |
1467 | facet = facet_lookup_valid(ofproto, &flow); | |
1468 | if (facet && facet->rule == rule) { | |
1469 | facet_execute(ofproto, facet, packet); | |
1470 | return; | |
064af421 BP |
1471 | } |
1472 | ||
bcf84111 BP |
1473 | /* Otherwise, if 'rule' is in fact the correct rule for 'packet', then |
1474 | * create a new facet for it and use that. */ | |
1475 | if (rule_lookup(ofproto, &flow) == rule) { | |
1476 | facet = facet_create(ofproto, rule, &flow, packet); | |
1477 | facet_execute(ofproto, facet, packet); | |
1478 | facet_install(ofproto, facet, true); | |
1479 | return; | |
1480 | } | |
1481 | ||
1482 | /* We can't account anything to a facet. If we were to try, then that | |
1483 | * facet would have a non-matching rule, busting our invariants. */ | |
f29152ca | 1484 | action_xlate_ctx_init(&ctx, ofproto, &flow, packet); |
cdee00fd | 1485 | odp_actions = xlate_actions(&ctx, rule->actions, rule->n_actions); |
bcf84111 | 1486 | size = packet->size; |
856081f6 | 1487 | if (execute_odp_actions(ofproto, &flow, odp_actions->data, |
cdee00fd | 1488 | odp_actions->size, packet)) { |
064af421 | 1489 | rule->used = time_msec(); |
bcf84111 BP |
1490 | rule->packet_count++; |
1491 | rule->byte_count += size; | |
878ae780 | 1492 | flow_push_stats(ofproto, rule, &flow, 1, size, rule->used); |
064af421 | 1493 | } |
cdee00fd | 1494 | ofpbuf_delete(odp_actions); |
064af421 BP |
1495 | } |
1496 | ||
afe75089 | 1497 | /* Inserts 'rule' into 'p''s flow table. */ |
064af421 | 1498 | static void |
afe75089 | 1499 | rule_insert(struct ofproto *p, struct rule *rule) |
064af421 BP |
1500 | { |
1501 | struct rule *displaced_rule; | |
1502 | ||
064af421 | 1503 | displaced_rule = rule_from_cls_rule(classifier_insert(&p->cls, &rule->cr)); |
bcf84111 BP |
1504 | if (displaced_rule) { |
1505 | rule_destroy(p, displaced_rule); | |
064af421 | 1506 | } |
bcf84111 | 1507 | p->need_revalidate = true; |
064af421 BP |
1508 | } |
1509 | ||
bcf84111 BP |
1510 | /* Creates and returns a new facet within 'ofproto' owned by 'rule', given a |
1511 | * 'flow' and an example 'packet' within that flow. | |
1512 | * | |
1513 | * The caller must already have determined that no facet with an identical | |
1514 | * 'flow' exists in 'ofproto' and that 'flow' is the best match for 'rule' in | |
1515 | * 'ofproto''s classifier table. */ | |
1516 | static struct facet * | |
1517 | facet_create(struct ofproto *ofproto, struct rule *rule, | |
1518 | const struct flow *flow, const struct ofpbuf *packet) | |
064af421 | 1519 | { |
bcf84111 | 1520 | struct facet *facet; |
fbb2ea0b | 1521 | |
bcf84111 BP |
1522 | facet = xzalloc(sizeof *facet); |
1523 | facet->used = time_msec(); | |
1524 | hmap_insert(&ofproto->facets, &facet->hmap_node, flow_hash(flow, 0)); | |
1525 | list_push_back(&rule->facets, &facet->list_node); | |
1526 | facet->rule = rule; | |
1527 | facet->flow = *flow; | |
1528 | netflow_flow_init(&facet->nf_flow); | |
1529 | netflow_flow_update_time(ofproto->netflow, &facet->nf_flow, facet->used); | |
1530 | ||
1531 | facet_make_actions(ofproto, facet, packet); | |
064af421 | 1532 | |
bcf84111 BP |
1533 | return facet; |
1534 | } | |
1535 | ||
1536 | static void | |
1537 | facet_free(struct facet *facet) | |
1538 | { | |
1539 | free(facet->actions); | |
1540 | free(facet); | |
064af421 BP |
1541 | } |
1542 | ||
431d4707 | 1543 | /* Remove 'rule' from 'ofproto' and free up the associated memory: |
431d4707 BP |
1544 | * |
1545 | * - Removes 'rule' from the classifier. | |
1546 | * | |
bcf84111 BP |
1547 | * - If 'rule' has facets, revalidates them (and possibly uninstalls and |
1548 | * destroys them), via rule_destroy(). | |
431d4707 | 1549 | */ |
064af421 BP |
1550 | static void |
1551 | rule_remove(struct ofproto *ofproto, struct rule *rule) | |
1552 | { | |
bcf84111 BP |
1553 | COVERAGE_INC(ofproto_del_rule); |
1554 | ofproto->need_revalidate = true; | |
064af421 BP |
1555 | classifier_remove(&ofproto->cls, &rule->cr); |
1556 | rule_destroy(ofproto, rule); | |
1557 | } | |
1558 | ||
bcf84111 BP |
1559 | /* Remove 'facet' from 'ofproto' and free up the associated memory: |
1560 | * | |
1561 | * - If 'facet' was installed in the datapath, uninstalls it and updates its | |
1562 | * rule's statistics, via facet_uninstall(). | |
1563 | * | |
1564 | * - Removes 'facet' from its rule and from ofproto->facets. | |
1565 | */ | |
1566 | static void | |
1567 | facet_remove(struct ofproto *ofproto, struct facet *facet) | |
1568 | { | |
1569 | facet_uninstall(ofproto, facet); | |
d530fcd2 | 1570 | facet_flush_stats(ofproto, facet); |
bcf84111 BP |
1571 | hmap_remove(&ofproto->facets, &facet->hmap_node); |
1572 | list_remove(&facet->list_node); | |
1573 | facet_free(facet); | |
1574 | } | |
1575 | ||
7f7ae89d BP |
1576 | /* Composes the ODP actions for 'facet' based on its rule's actions. */ |
1577 | static void | |
bcf84111 BP |
1578 | facet_make_actions(struct ofproto *p, struct facet *facet, |
1579 | const struct ofpbuf *packet) | |
064af421 | 1580 | { |
bcf84111 | 1581 | const struct rule *rule = facet->rule; |
cdee00fd | 1582 | struct ofpbuf *odp_actions; |
f29152ca | 1583 | struct action_xlate_ctx ctx; |
064af421 | 1584 | |
f29152ca | 1585 | action_xlate_ctx_init(&ctx, p, &facet->flow, packet); |
cdee00fd | 1586 | odp_actions = xlate_actions(&ctx, rule->actions, rule->n_actions); |
19739aee JP |
1587 | facet->tags = ctx.tags; |
1588 | facet->may_install = ctx.may_set_up_flow; | |
1589 | facet->nf_flow.output_iface = ctx.nf_output_iface; | |
064af421 | 1590 | |
cdee00fd BP |
1591 | if (facet->actions_len != odp_actions->size |
1592 | || memcmp(facet->actions, odp_actions->data, odp_actions->size)) { | |
7f7ae89d | 1593 | free(facet->actions); |
cdee00fd BP |
1594 | facet->actions_len = odp_actions->size; |
1595 | facet->actions = xmemdup(odp_actions->data, odp_actions->size); | |
064af421 | 1596 | } |
cdee00fd BP |
1597 | |
1598 | ofpbuf_delete(odp_actions); | |
064af421 BP |
1599 | } |
1600 | ||
1601 | static int | |
ba25b8f4 | 1602 | facet_put__(struct ofproto *ofproto, struct facet *facet, |
c62b0064 BP |
1603 | const struct nlattr *actions, size_t actions_len, |
1604 | struct dpif_flow_stats *stats) | |
064af421 | 1605 | { |
19cf4069 | 1606 | struct odputil_keybuf keybuf; |
c62b0064 | 1607 | enum dpif_flow_put_flags flags; |
36956a7d BP |
1608 | struct ofpbuf key; |
1609 | ||
c62b0064 BP |
1610 | flags = DPIF_FP_CREATE | DPIF_FP_MODIFY; |
1611 | if (stats) { | |
1612 | flags |= DPIF_FP_ZERO_STATS; | |
3394b5b6 EJ |
1613 | facet->dp_packet_count = 0; |
1614 | facet->dp_byte_count = 0; | |
c62b0064 BP |
1615 | } |
1616 | ||
19cf4069 | 1617 | ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); |
36956a7d | 1618 | odp_flow_key_from_flow(&key, &facet->flow); |
36956a7d | 1619 | |
feebdea2 | 1620 | return dpif_flow_put(ofproto->dpif, flags, key.data, key.size, |
c62b0064 | 1621 | actions, actions_len, stats); |
064af421 BP |
1622 | } |
1623 | ||
bcf84111 BP |
1624 | /* If 'facet' is installable, inserts or re-inserts it into 'p''s datapath. If |
1625 | * 'zero_stats' is true, clears any existing statistics from the datapath for | |
1626 | * 'facet'. */ | |
064af421 | 1627 | static void |
bcf84111 | 1628 | facet_install(struct ofproto *p, struct facet *facet, bool zero_stats) |
064af421 | 1629 | { |
c62b0064 BP |
1630 | struct dpif_flow_stats stats; |
1631 | ||
1632 | if (facet->may_install | |
1633 | && !facet_put__(p, facet, facet->actions, facet->actions_len, | |
1634 | zero_stats ? &stats : NULL)) { | |
1635 | facet->installed = true; | |
064af421 BP |
1636 | } |
1637 | } | |
1638 | ||
bcf84111 BP |
1639 | /* Ensures that the bytes in 'facet', plus 'extra_bytes', have been passed up |
1640 | * to the accounting hook function in the ofhooks structure. */ | |
064af421 | 1641 | static void |
bcf84111 BP |
1642 | facet_account(struct ofproto *ofproto, |
1643 | struct facet *facet, uint64_t extra_bytes) | |
064af421 | 1644 | { |
bcf84111 | 1645 | uint64_t total_bytes = facet->byte_count + extra_bytes; |
064af421 BP |
1646 | |
1647 | if (ofproto->ofhooks->account_flow_cb | |
bcf84111 | 1648 | && total_bytes > facet->accounted_bytes) |
064af421 BP |
1649 | { |
1650 | ofproto->ofhooks->account_flow_cb( | |
cdee00fd | 1651 | &facet->flow, facet->tags, facet->actions, facet->actions_len, |
bcf84111 BP |
1652 | total_bytes - facet->accounted_bytes, ofproto->aux); |
1653 | facet->accounted_bytes = total_bytes; | |
064af421 BP |
1654 | } |
1655 | } | |
1656 | ||
d530fcd2 | 1657 | /* If 'rule' is installed in the datapath, uninstalls it. */ |
064af421 | 1658 | static void |
bcf84111 | 1659 | facet_uninstall(struct ofproto *p, struct facet *facet) |
064af421 | 1660 | { |
bcf84111 | 1661 | if (facet->installed) { |
19cf4069 | 1662 | struct odputil_keybuf keybuf; |
c97fb132 | 1663 | struct dpif_flow_stats stats; |
36956a7d | 1664 | struct ofpbuf key; |
064af421 | 1665 | |
19cf4069 | 1666 | ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); |
36956a7d | 1667 | odp_flow_key_from_flow(&key, &facet->flow); |
36956a7d | 1668 | |
feebdea2 BP |
1669 | if (!dpif_flow_del(p->dpif, key.data, key.size, &stats)) { |
1670 | facet_update_stats(p, facet, &stats); | |
064af421 | 1671 | } |
bcf84111 | 1672 | facet->installed = false; |
3394b5b6 EJ |
1673 | facet->dp_packet_count = 0; |
1674 | facet->dp_byte_count = 0; | |
a2c6a63c EJ |
1675 | } else { |
1676 | assert(facet->dp_packet_count == 0); | |
1677 | assert(facet->dp_byte_count == 0); | |
064af421 BP |
1678 | } |
1679 | } | |
1680 | ||
bcf84111 BP |
1681 | /* Returns true if the only action for 'facet' is to send to the controller. |
1682 | * (We don't report NetFlow expiration messages for such facets because they | |
1683 | * are just part of the control logic for the network, not real traffic). */ | |
0193b2af | 1684 | static bool |
bcf84111 | 1685 | facet_is_controller_flow(struct facet *facet) |
0193b2af | 1686 | { |
bcf84111 BP |
1687 | return (facet |
1688 | && facet->rule->n_actions == 1 | |
1689 | && action_outputs_to_port(&facet->rule->actions[0], | |
c1c9c9c4 | 1690 | htons(OFPP_CONTROLLER))); |
0193b2af JG |
1691 | } |
1692 | ||
bcf84111 | 1693 | /* Folds all of 'facet''s statistics into its rule. Also updates the |
3394b5b6 EJ |
1694 | * accounting ofhook and emits a NetFlow expiration if appropriate. All of |
1695 | * 'facet''s statistics in the datapath should have been zeroed and folded into | |
1696 | * its packet and byte counts before this function is called. */ | |
064af421 | 1697 | static void |
d530fcd2 | 1698 | facet_flush_stats(struct ofproto *ofproto, struct facet *facet) |
064af421 | 1699 | { |
3394b5b6 EJ |
1700 | assert(!facet->dp_byte_count); |
1701 | assert(!facet->dp_packet_count); | |
1702 | ||
878ae780 | 1703 | facet_push_stats(ofproto, facet); |
bcf84111 | 1704 | facet_account(ofproto, facet, 0); |
064af421 | 1705 | |
bcf84111 | 1706 | if (ofproto->netflow && !facet_is_controller_flow(facet)) { |
064af421 | 1707 | struct ofexpired expired; |
bcf84111 BP |
1708 | expired.flow = facet->flow; |
1709 | expired.packet_count = facet->packet_count; | |
1710 | expired.byte_count = facet->byte_count; | |
1711 | expired.used = facet->used; | |
1712 | netflow_expire(ofproto->netflow, &facet->nf_flow, &expired); | |
1713 | } | |
1714 | ||
1715 | facet->rule->packet_count += facet->packet_count; | |
1716 | facet->rule->byte_count += facet->byte_count; | |
1717 | ||
1718 | /* Reset counters to prevent double counting if 'facet' ever gets | |
1719 | * reinstalled. */ | |
1720 | facet->packet_count = 0; | |
1721 | facet->byte_count = 0; | |
878ae780 EJ |
1722 | facet->rs_packet_count = 0; |
1723 | facet->rs_byte_count = 0; | |
bcf84111 BP |
1724 | facet->accounted_bytes = 0; |
1725 | ||
1726 | netflow_flow_clear(&facet->nf_flow); | |
1727 | } | |
1728 | ||
1729 | /* Searches 'ofproto''s table of facets for one exactly equal to 'flow'. | |
1730 | * Returns it if found, otherwise a null pointer. | |
1731 | * | |
1732 | * The returned facet might need revalidation; use facet_lookup_valid() | |
1733 | * instead if that is important. */ | |
1734 | static struct facet * | |
1735 | facet_find(struct ofproto *ofproto, const struct flow *flow) | |
1736 | { | |
1737 | struct facet *facet; | |
1738 | ||
1739 | HMAP_FOR_EACH_WITH_HASH (facet, hmap_node, flow_hash(flow, 0), | |
1740 | &ofproto->facets) { | |
1741 | if (flow_equal(flow, &facet->flow)) { | |
1742 | return facet; | |
1743 | } | |
1744 | } | |
1745 | ||
1746 | return NULL; | |
1747 | } | |
1748 | ||
1749 | /* Searches 'ofproto''s table of facets for one exactly equal to 'flow'. | |
1750 | * Returns it if found, otherwise a null pointer. | |
1751 | * | |
1752 | * The returned facet is guaranteed to be valid. */ | |
1753 | static struct facet * | |
1754 | facet_lookup_valid(struct ofproto *ofproto, const struct flow *flow) | |
1755 | { | |
1756 | struct facet *facet = facet_find(ofproto, flow); | |
1757 | ||
1758 | /* The facet we found might not be valid, since we could be in need of | |
1759 | * revalidation. If it is not valid, don't return it. */ | |
1760 | if (facet | |
1761 | && ofproto->need_revalidate | |
1762 | && !facet_revalidate(ofproto, facet)) { | |
1763 | COVERAGE_INC(ofproto_invalidated); | |
1764 | return NULL; | |
064af421 | 1765 | } |
064af421 | 1766 | |
bcf84111 BP |
1767 | return facet; |
1768 | } | |
0193b2af | 1769 | |
bcf84111 BP |
1770 | /* Re-searches 'ofproto''s classifier for a rule matching 'facet': |
1771 | * | |
1772 | * - If the rule found is different from 'facet''s current rule, moves | |
1773 | * 'facet' to the new rule and recompiles its actions. | |
1774 | * | |
1775 | * - If the rule found is the same as 'facet''s current rule, leaves 'facet' | |
1776 | * where it is and recompiles its actions anyway. | |
1777 | * | |
1778 | * - If there is none, destroys 'facet'. | |
1779 | * | |
d530fcd2 | 1780 | * Returns true if 'facet' still exists, false if it has been destroyed. */ |
bcf84111 BP |
1781 | static bool |
1782 | facet_revalidate(struct ofproto *ofproto, struct facet *facet) | |
1783 | { | |
f29152ca | 1784 | struct action_xlate_ctx ctx; |
cdee00fd | 1785 | struct ofpbuf *odp_actions; |
d530fcd2 | 1786 | struct rule *new_rule; |
d530fcd2 | 1787 | bool actions_changed; |
bcf84111 BP |
1788 | |
1789 | COVERAGE_INC(facet_revalidate); | |
d530fcd2 BP |
1790 | |
1791 | /* Determine the new rule. */ | |
1792 | new_rule = rule_lookup(ofproto, &facet->flow); | |
1793 | if (!new_rule) { | |
1794 | /* No new rule, so delete the facet. */ | |
bcf84111 BP |
1795 | facet_remove(ofproto, facet); |
1796 | return false; | |
1797 | } | |
1798 | ||
d530fcd2 BP |
1799 | /* Calculate new ODP actions. |
1800 | * | |
cdee00fd BP |
1801 | * We do not modify any 'facet' state yet, because we might need to, e.g., |
1802 | * emit a NetFlow expiration and, if so, we need to have the old state | |
1803 | * around to properly compose it. */ | |
f29152ca | 1804 | action_xlate_ctx_init(&ctx, ofproto, &facet->flow, NULL); |
cdee00fd BP |
1805 | odp_actions = xlate_actions(&ctx, new_rule->actions, new_rule->n_actions); |
1806 | actions_changed = (facet->actions_len != odp_actions->size | |
1807 | || memcmp(facet->actions, odp_actions->data, | |
1808 | facet->actions_len)); | |
d530fcd2 BP |
1809 | |
1810 | /* If the ODP actions changed or the installability changed, then we need | |
1811 | * to talk to the datapath. */ | |
e4add896 BP |
1812 | if (actions_changed || ctx.may_set_up_flow != facet->installed) { |
1813 | if (ctx.may_set_up_flow) { | |
c97fb132 | 1814 | struct dpif_flow_stats stats; |
d530fcd2 | 1815 | |
c62b0064 BP |
1816 | facet_put__(ofproto, facet, |
1817 | odp_actions->data, odp_actions->size, &stats); | |
feebdea2 | 1818 | facet_update_stats(ofproto, facet, &stats); |
d530fcd2 BP |
1819 | } else { |
1820 | facet_uninstall(ofproto, facet); | |
1821 | } | |
1822 | ||
1823 | /* The datapath flow is gone or has zeroed stats, so push stats out of | |
1824 | * 'facet' into 'rule'. */ | |
1825 | facet_flush_stats(ofproto, facet); | |
1826 | } | |
1827 | ||
1828 | /* Update 'facet' now that we've taken care of all the old state. */ | |
f29152ca BP |
1829 | facet->tags = ctx.tags; |
1830 | facet->nf_flow.output_iface = ctx.nf_output_iface; | |
1831 | facet->may_install = ctx.may_set_up_flow; | |
d530fcd2 BP |
1832 | if (actions_changed) { |
1833 | free(facet->actions); | |
cdee00fd BP |
1834 | facet->actions_len = odp_actions->size; |
1835 | facet->actions = xmemdup(odp_actions->data, odp_actions->size); | |
d530fcd2 BP |
1836 | } |
1837 | if (facet->rule != new_rule) { | |
bcf84111 BP |
1838 | COVERAGE_INC(facet_changed_rule); |
1839 | list_remove(&facet->list_node); | |
d530fcd2 BP |
1840 | list_push_back(&new_rule->facets, &facet->list_node); |
1841 | facet->rule = new_rule; | |
1842 | facet->used = new_rule->created; | |
5e1b3214 | 1843 | facet->rs_used = facet->used; |
0c0afbec | 1844 | } |
bcf84111 | 1845 | |
cdfcd496 BP |
1846 | ofpbuf_delete(odp_actions); |
1847 | ||
bcf84111 | 1848 | return true; |
064af421 BP |
1849 | } |
1850 | \f | |
064af421 BP |
1851 | static void |
1852 | send_error_oh(const struct ofconn *ofconn, const struct ofp_header *oh, | |
1853 | int error) | |
1854 | { | |
dc4762ed | 1855 | struct ofpbuf *buf = ofputil_encode_error_msg(error, oh); |
26c112c2 BP |
1856 | if (buf) { |
1857 | COVERAGE_INC(ofproto_error); | |
b0421aa2 | 1858 | ofconn_send_reply(ofconn, buf); |
26c112c2 | 1859 | } |
064af421 BP |
1860 | } |
1861 | ||
064af421 | 1862 | static int |
d1e2cf21 | 1863 | handle_echo_request(struct ofconn *ofconn, const struct ofp_header *oh) |
064af421 | 1864 | { |
b0421aa2 | 1865 | ofconn_send_reply(ofconn, make_echo_reply(oh)); |
064af421 BP |
1866 | return 0; |
1867 | } | |
1868 | ||
1869 | static int | |
d1e2cf21 | 1870 | handle_features_request(struct ofconn *ofconn, const struct ofp_header *oh) |
064af421 | 1871 | { |
64ff1d96 | 1872 | struct ofproto *ofproto = ofconn_get_ofproto(ofconn); |
064af421 BP |
1873 | struct ofp_switch_features *osf; |
1874 | struct ofpbuf *buf; | |
064af421 BP |
1875 | struct ofport *port; |
1876 | ||
1877 | osf = make_openflow_xid(sizeof *osf, OFPT_FEATURES_REPLY, oh->xid, &buf); | |
64ff1d96 | 1878 | osf->datapath_id = htonll(ofproto->datapath_id); |
064af421 BP |
1879 | osf->n_buffers = htonl(pktbuf_capacity()); |
1880 | osf->n_tables = 2; | |
1881 | osf->capabilities = htonl(OFPC_FLOW_STATS | OFPC_TABLE_STATS | | |
0254ae23 | 1882 | OFPC_PORT_STATS | OFPC_ARP_MATCH_IP); |
064af421 BP |
1883 | osf->actions = htonl((1u << OFPAT_OUTPUT) | |
1884 | (1u << OFPAT_SET_VLAN_VID) | | |
1885 | (1u << OFPAT_SET_VLAN_PCP) | | |
1886 | (1u << OFPAT_STRIP_VLAN) | | |
1887 | (1u << OFPAT_SET_DL_SRC) | | |
1888 | (1u << OFPAT_SET_DL_DST) | | |
1889 | (1u << OFPAT_SET_NW_SRC) | | |
1890 | (1u << OFPAT_SET_NW_DST) | | |
959a2ecd | 1891 | (1u << OFPAT_SET_NW_TOS) | |
064af421 | 1892 | (1u << OFPAT_SET_TP_SRC) | |
c1c9c9c4 BP |
1893 | (1u << OFPAT_SET_TP_DST) | |
1894 | (1u << OFPAT_ENQUEUE)); | |
064af421 | 1895 | |
64ff1d96 | 1896 | HMAP_FOR_EACH (port, hmap_node, &ofproto->ports) { |
064af421 BP |
1897 | hton_ofp_phy_port(ofpbuf_put(buf, &port->opp, sizeof port->opp)); |
1898 | } | |
1899 | ||
b0421aa2 | 1900 | ofconn_send_reply(ofconn, buf); |
064af421 BP |
1901 | return 0; |
1902 | } | |
1903 | ||
1904 | static int | |
d1e2cf21 | 1905 | handle_get_config_request(struct ofconn *ofconn, const struct ofp_header *oh) |
064af421 | 1906 | { |
64ff1d96 | 1907 | struct ofproto *ofproto = ofconn_get_ofproto(ofconn); |
064af421 BP |
1908 | struct ofpbuf *buf; |
1909 | struct ofp_switch_config *osc; | |
1910 | uint16_t flags; | |
1911 | bool drop_frags; | |
1912 | ||
1913 | /* Figure out flags. */ | |
64ff1d96 | 1914 | dpif_get_drop_frags(ofproto->dpif, &drop_frags); |
064af421 | 1915 | flags = drop_frags ? OFPC_FRAG_DROP : OFPC_FRAG_NORMAL; |
064af421 BP |
1916 | |
1917 | /* Send reply. */ | |
1918 | osc = make_openflow_xid(sizeof *osc, OFPT_GET_CONFIG_REPLY, oh->xid, &buf); | |
1919 | osc->flags = htons(flags); | |
810605a2 | 1920 | osc->miss_send_len = htons(ofconn_get_miss_send_len(ofconn)); |
b0421aa2 | 1921 | ofconn_send_reply(ofconn, buf); |
064af421 BP |
1922 | |
1923 | return 0; | |
1924 | } | |
1925 | ||
1926 | static int | |
d1e2cf21 | 1927 | handle_set_config(struct ofconn *ofconn, const struct ofp_switch_config *osc) |
064af421 | 1928 | { |
64ff1d96 | 1929 | struct ofproto *ofproto = ofconn_get_ofproto(ofconn); |
d1e2cf21 | 1930 | uint16_t flags = ntohs(osc->flags); |
064af421 | 1931 | |
1ce0a5fa BP |
1932 | if (ofconn_get_type(ofconn) == OFCONN_PRIMARY |
1933 | && ofconn_get_role(ofconn) != NX_ROLE_SLAVE) { | |
064af421 BP |
1934 | switch (flags & OFPC_FRAG_MASK) { |
1935 | case OFPC_FRAG_NORMAL: | |
64ff1d96 | 1936 | dpif_set_drop_frags(ofproto->dpif, false); |
064af421 BP |
1937 | break; |
1938 | case OFPC_FRAG_DROP: | |
64ff1d96 | 1939 | dpif_set_drop_frags(ofproto->dpif, true); |
064af421 BP |
1940 | break; |
1941 | default: | |
1942 | VLOG_WARN_RL(&rl, "requested bad fragment mode (flags=%"PRIx16")", | |
1943 | osc->flags); | |
1944 | break; | |
1945 | } | |
1946 | } | |
1947 | ||
810605a2 | 1948 | ofconn_set_miss_send_len(ofconn, ntohs(osc->miss_send_len)); |
064af421 BP |
1949 | |
1950 | return 0; | |
1951 | } | |
1952 | ||
064af421 BP |
1953 | static void do_xlate_actions(const union ofp_action *in, size_t n_in, |
1954 | struct action_xlate_ctx *ctx); | |
1955 | ||
1956 | static void | |
1957 | add_output_action(struct action_xlate_ctx *ctx, uint16_t port) | |
1958 | { | |
ca0f572c | 1959 | const struct ofport *ofport = get_port(ctx->ofproto, port); |
6cfaf517 BP |
1960 | |
1961 | if (ofport) { | |
1962 | if (ofport->opp.config & OFPPC_NO_FWD) { | |
1963 | /* Forwarding disabled on port. */ | |
1964 | return; | |
1965 | } | |
1966 | } else { | |
1967 | /* | |
1968 | * We don't have an ofport record for this port, but it doesn't hurt to | |
1969 | * allow forwarding to it anyhow. Maybe such a port will appear later | |
1970 | * and we're pre-populating the flow table. | |
1971 | */ | |
064af421 | 1972 | } |
6cfaf517 | 1973 | |
7aec165d | 1974 | nl_msg_put_u32(ctx->odp_actions, ODP_ACTION_ATTR_OUTPUT, port); |
6a07af36 | 1975 | ctx->nf_output_iface = port; |
064af421 BP |
1976 | } |
1977 | ||
1978 | static struct rule * | |
bcf84111 | 1979 | rule_lookup(struct ofproto *ofproto, const struct flow *flow) |
064af421 | 1980 | { |
3c4486a5 | 1981 | return rule_from_cls_rule(classifier_lookup(&ofproto->cls, flow)); |
064af421 BP |
1982 | } |
1983 | ||
1984 | static void | |
1985 | xlate_table_action(struct action_xlate_ctx *ctx, uint16_t in_port) | |
1986 | { | |
5f8bfd69 | 1987 | if (ctx->recurse < MAX_RESUBMIT_RECURSION) { |
2c5d1389 | 1988 | uint16_t old_in_port; |
064af421 | 1989 | struct rule *rule; |
064af421 | 1990 | |
2c5d1389 BP |
1991 | /* Look up a flow with 'in_port' as the input port. Then restore the |
1992 | * original input port (otherwise OFPP_NORMAL and OFPP_IN_PORT will | |
1993 | * have surprising behavior). */ | |
1994 | old_in_port = ctx->flow.in_port; | |
e18fe8a2 | 1995 | ctx->flow.in_port = in_port; |
bcf84111 | 1996 | rule = rule_lookup(ctx->ofproto, &ctx->flow); |
2c5d1389 BP |
1997 | ctx->flow.in_port = old_in_port; |
1998 | ||
7aa697dd BP |
1999 | if (ctx->resubmit_hook) { |
2000 | ctx->resubmit_hook(ctx, rule); | |
2001 | } | |
2002 | ||
064af421 | 2003 | if (rule) { |
064af421 BP |
2004 | ctx->recurse++; |
2005 | do_xlate_actions(rule->actions, rule->n_actions, ctx); | |
2006 | ctx->recurse--; | |
2007 | } | |
5f8bfd69 | 2008 | } else { |
db5ce514 | 2009 | static struct vlog_rate_limit recurse_rl = VLOG_RATE_LIMIT_INIT(1, 1); |
5f8bfd69 BP |
2010 | |
2011 | VLOG_ERR_RL(&recurse_rl, "NXAST_RESUBMIT recursed over %d times", | |
2012 | MAX_RESUBMIT_RECURSION); | |
064af421 BP |
2013 | } |
2014 | } | |
2015 | ||
f1588b1f BP |
2016 | static void |
2017 | flood_packets(struct ofproto *ofproto, uint16_t odp_in_port, uint32_t mask, | |
cdee00fd | 2018 | uint16_t *nf_output_iface, struct ofpbuf *odp_actions) |
f1588b1f BP |
2019 | { |
2020 | struct ofport *ofport; | |
2021 | ||
2022 | HMAP_FOR_EACH (ofport, hmap_node, &ofproto->ports) { | |
2023 | uint16_t odp_port = ofport->odp_port; | |
2024 | if (odp_port != odp_in_port && !(ofport->opp.config & mask)) { | |
7aec165d | 2025 | nl_msg_put_u32(odp_actions, ODP_ACTION_ATTR_OUTPUT, odp_port); |
f1588b1f BP |
2026 | } |
2027 | } | |
2028 | *nf_output_iface = NF_OUT_FLOOD; | |
2029 | } | |
2030 | ||
064af421 | 2031 | static void |
aae51f53 BP |
2032 | xlate_output_action__(struct action_xlate_ctx *ctx, |
2033 | uint16_t port, uint16_t max_len) | |
064af421 BP |
2034 | { |
2035 | uint16_t odp_port; | |
6a07af36 JG |
2036 | uint16_t prev_nf_output_iface = ctx->nf_output_iface; |
2037 | ||
2038 | ctx->nf_output_iface = NF_OUT_DROP; | |
064af421 | 2039 | |
aae51f53 | 2040 | switch (port) { |
064af421 | 2041 | case OFPP_IN_PORT: |
e18fe8a2 | 2042 | add_output_action(ctx, ctx->flow.in_port); |
064af421 BP |
2043 | break; |
2044 | case OFPP_TABLE: | |
e18fe8a2 | 2045 | xlate_table_action(ctx, ctx->flow.in_port); |
064af421 BP |
2046 | break; |
2047 | case OFPP_NORMAL: | |
e18fe8a2 | 2048 | if (!ctx->ofproto->ofhooks->normal_cb(&ctx->flow, ctx->packet, |
cdee00fd | 2049 | ctx->odp_actions, &ctx->tags, |
6a07af36 | 2050 | &ctx->nf_output_iface, |
064af421 BP |
2051 | ctx->ofproto->aux)) { |
2052 | COVERAGE_INC(ofproto_uninstallable); | |
d6fbec6d | 2053 | ctx->may_set_up_flow = false; |
064af421 BP |
2054 | } |
2055 | break; | |
2056 | case OFPP_FLOOD: | |
f1588b1f | 2057 | flood_packets(ctx->ofproto, ctx->flow.in_port, OFPPC_NO_FLOOD, |
cdee00fd | 2058 | &ctx->nf_output_iface, ctx->odp_actions); |
9628cd42 | 2059 | break; |
064af421 | 2060 | case OFPP_ALL: |
f1588b1f | 2061 | flood_packets(ctx->ofproto, ctx->flow.in_port, 0, |
cdee00fd | 2062 | &ctx->nf_output_iface, ctx->odp_actions); |
064af421 BP |
2063 | break; |
2064 | case OFPP_CONTROLLER: | |
7aec165d | 2065 | nl_msg_put_u64(ctx->odp_actions, ODP_ACTION_ATTR_CONTROLLER, max_len); |
064af421 BP |
2066 | break; |
2067 | case OFPP_LOCAL: | |
2068 | add_output_action(ctx, ODPP_LOCAL); | |
2069 | break; | |
2070 | default: | |
aae51f53 | 2071 | odp_port = ofp_port_to_odp_port(port); |
e18fe8a2 | 2072 | if (odp_port != ctx->flow.in_port) { |
064af421 BP |
2073 | add_output_action(ctx, odp_port); |
2074 | } | |
2075 | break; | |
2076 | } | |
6a07af36 JG |
2077 | |
2078 | if (prev_nf_output_iface == NF_OUT_FLOOD) { | |
2079 | ctx->nf_output_iface = NF_OUT_FLOOD; | |
2080 | } else if (ctx->nf_output_iface == NF_OUT_DROP) { | |
2081 | ctx->nf_output_iface = prev_nf_output_iface; | |
2082 | } else if (prev_nf_output_iface != NF_OUT_DROP && | |
2083 | ctx->nf_output_iface != NF_OUT_FLOOD) { | |
2084 | ctx->nf_output_iface = NF_OUT_MULTI; | |
2085 | } | |
064af421 BP |
2086 | } |
2087 | ||
aae51f53 BP |
2088 | static void |
2089 | xlate_output_action(struct action_xlate_ctx *ctx, | |
2090 | const struct ofp_action_output *oao) | |
2091 | { | |
2092 | xlate_output_action__(ctx, ntohs(oao->port), ntohs(oao->max_len)); | |
2093 | } | |
2094 | ||
c1c9c9c4 BP |
2095 | /* If the final ODP action in 'ctx' is "pop priority", drop it, as an |
2096 | * optimization, because we're going to add another action that sets the | |
2097 | * priority immediately after, or because there are no actions following the | |
2098 | * pop. */ | |
2099 | static void | |
2100 | remove_pop_action(struct action_xlate_ctx *ctx) | |
2101 | { | |
cdee00fd BP |
2102 | if (ctx->odp_actions->size == ctx->last_pop_priority) { |
2103 | ctx->odp_actions->size -= NLA_ALIGN(NLA_HDRLEN); | |
2104 | ctx->last_pop_priority = -1; | |
2105 | } | |
2106 | } | |
2107 | ||
2108 | static void | |
2109 | add_pop_action(struct action_xlate_ctx *ctx) | |
2110 | { | |
2111 | if (ctx->odp_actions->size != ctx->last_pop_priority) { | |
7aec165d | 2112 | nl_msg_put_flag(ctx->odp_actions, ODP_ACTION_ATTR_POP_PRIORITY); |
cdee00fd | 2113 | ctx->last_pop_priority = ctx->odp_actions->size; |
c1c9c9c4 BP |
2114 | } |
2115 | } | |
2116 | ||
2117 | static void | |
2118 | xlate_enqueue_action(struct action_xlate_ctx *ctx, | |
2119 | const struct ofp_action_enqueue *oae) | |
2120 | { | |
2121 | uint16_t ofp_port, odp_port; | |
aae51f53 BP |
2122 | uint32_t priority; |
2123 | int error; | |
2124 | ||
2125 | error = dpif_queue_to_priority(ctx->ofproto->dpif, ntohl(oae->queue_id), | |
2126 | &priority); | |
2127 | if (error) { | |
2128 | /* Fall back to ordinary output action. */ | |
2129 | xlate_output_action__(ctx, ntohs(oae->port), 0); | |
2130 | return; | |
2131 | } | |
c1c9c9c4 BP |
2132 | |
2133 | /* Figure out ODP output port. */ | |
2134 | ofp_port = ntohs(oae->port); | |
2135 | if (ofp_port != OFPP_IN_PORT) { | |
2136 | odp_port = ofp_port_to_odp_port(ofp_port); | |
2137 | } else { | |
2138 | odp_port = ctx->flow.in_port; | |
2139 | } | |
2140 | ||
2141 | /* Add ODP actions. */ | |
2142 | remove_pop_action(ctx); | |
7aec165d | 2143 | nl_msg_put_u32(ctx->odp_actions, ODP_ACTION_ATTR_SET_PRIORITY, priority); |
c1c9c9c4 | 2144 | add_output_action(ctx, odp_port); |
cdee00fd | 2145 | add_pop_action(ctx); |
c1c9c9c4 BP |
2146 | |
2147 | /* Update NetFlow output port. */ | |
2148 | if (ctx->nf_output_iface == NF_OUT_DROP) { | |
2149 | ctx->nf_output_iface = odp_port; | |
2150 | } else if (ctx->nf_output_iface != NF_OUT_FLOOD) { | |
2151 | ctx->nf_output_iface = NF_OUT_MULTI; | |
2152 | } | |
2153 | } | |
2154 | ||
eedc0097 JP |
2155 | static void |
2156 | xlate_set_queue_action(struct action_xlate_ctx *ctx, | |
2157 | const struct nx_action_set_queue *nasq) | |
2158 | { | |
2159 | uint32_t priority; | |
2160 | int error; | |
2161 | ||
2162 | error = dpif_queue_to_priority(ctx->ofproto->dpif, ntohl(nasq->queue_id), | |
2163 | &priority); | |
2164 | if (error) { | |
2165 | /* Couldn't translate queue to a priority, so ignore. A warning | |
2166 | * has already been logged. */ | |
2167 | return; | |
2168 | } | |
2169 | ||
2170 | remove_pop_action(ctx); | |
7aec165d | 2171 | nl_msg_put_u32(ctx->odp_actions, ODP_ACTION_ATTR_SET_PRIORITY, priority); |
eedc0097 JP |
2172 | } |
2173 | ||
350a665f BP |
2174 | static void |
2175 | xlate_set_dl_tci(struct action_xlate_ctx *ctx) | |
2176 | { | |
66642cb4 BP |
2177 | ovs_be16 tci = ctx->flow.vlan_tci; |
2178 | if (!(tci & htons(VLAN_CFI))) { | |
7aec165d | 2179 | nl_msg_put_flag(ctx->odp_actions, ODP_ACTION_ATTR_STRIP_VLAN); |
350a665f | 2180 | } else { |
7aec165d | 2181 | nl_msg_put_be16(ctx->odp_actions, ODP_ACTION_ATTR_SET_DL_TCI, |
cdee00fd | 2182 | tci & ~htons(VLAN_CFI)); |
350a665f BP |
2183 | } |
2184 | } | |
2185 | ||
7b064a79 BP |
2186 | struct xlate_reg_state { |
2187 | ovs_be16 vlan_tci; | |
2188 | ovs_be64 tun_id; | |
2189 | }; | |
2190 | ||
b6c9e612 | 2191 | static void |
7b064a79 BP |
2192 | save_reg_state(const struct action_xlate_ctx *ctx, |
2193 | struct xlate_reg_state *state) | |
b6c9e612 | 2194 | { |
7b064a79 BP |
2195 | state->vlan_tci = ctx->flow.vlan_tci; |
2196 | state->tun_id = ctx->flow.tun_id; | |
2197 | } | |
b6c9e612 | 2198 | |
7b064a79 BP |
2199 | static void |
2200 | update_reg_state(struct action_xlate_ctx *ctx, | |
2201 | const struct xlate_reg_state *state) | |
2202 | { | |
2203 | if (ctx->flow.vlan_tci != state->vlan_tci) { | |
b6c9e612 BP |
2204 | xlate_set_dl_tci(ctx); |
2205 | } | |
7b064a79 | 2206 | if (ctx->flow.tun_id != state->tun_id) { |
7aec165d BP |
2207 | nl_msg_put_be64(ctx->odp_actions, |
2208 | ODP_ACTION_ATTR_SET_TUNNEL, ctx->flow.tun_id); | |
926947e6 | 2209 | } |
b6c9e612 BP |
2210 | } |
2211 | ||
064af421 BP |
2212 | static void |
2213 | xlate_nicira_action(struct action_xlate_ctx *ctx, | |
2214 | const struct nx_action_header *nah) | |
2215 | { | |
2216 | const struct nx_action_resubmit *nar; | |
659586ef | 2217 | const struct nx_action_set_tunnel *nast; |
eedc0097 | 2218 | const struct nx_action_set_queue *nasq; |
53ddd40a | 2219 | const struct nx_action_multipath *nam; |
e41a9130 | 2220 | enum nx_action_subtype subtype = ntohs(nah->subtype); |
7b064a79 | 2221 | struct xlate_reg_state state; |
b9298d3f | 2222 | ovs_be64 tun_id; |
064af421 BP |
2223 | |
2224 | assert(nah->vendor == htonl(NX_VENDOR_ID)); | |
2225 | switch (subtype) { | |
2226 | case NXAST_RESUBMIT: | |
2227 | nar = (const struct nx_action_resubmit *) nah; | |
2228 | xlate_table_action(ctx, ofp_port_to_odp_port(ntohs(nar->in_port))); | |
2229 | break; | |
2230 | ||
659586ef JG |
2231 | case NXAST_SET_TUNNEL: |
2232 | nast = (const struct nx_action_set_tunnel *) nah; | |
b9298d3f | 2233 | tun_id = htonll(ntohl(nast->tun_id)); |
7aec165d | 2234 | nl_msg_put_be64(ctx->odp_actions, ODP_ACTION_ATTR_SET_TUNNEL, tun_id); |
b9298d3f | 2235 | ctx->flow.tun_id = tun_id; |
659586ef JG |
2236 | break; |
2237 | ||
401eeb92 BP |
2238 | case NXAST_DROP_SPOOFED_ARP: |
2239 | if (ctx->flow.dl_type == htons(ETH_TYPE_ARP)) { | |
7aec165d BP |
2240 | nl_msg_put_flag(ctx->odp_actions, |
2241 | ODP_ACTION_ATTR_DROP_SPOOFED_ARP); | |
401eeb92 BP |
2242 | } |
2243 | break; | |
2244 | ||
eedc0097 JP |
2245 | case NXAST_SET_QUEUE: |
2246 | nasq = (const struct nx_action_set_queue *) nah; | |
2247 | xlate_set_queue_action(ctx, nasq); | |
2248 | break; | |
2249 | ||
2250 | case NXAST_POP_QUEUE: | |
cdee00fd | 2251 | add_pop_action(ctx); |
eedc0097 JP |
2252 | break; |
2253 | ||
b6c9e612 | 2254 | case NXAST_REG_MOVE: |
7b064a79 BP |
2255 | save_reg_state(ctx, &state); |
2256 | nxm_execute_reg_move((const struct nx_action_reg_move *) nah, | |
2257 | &ctx->flow); | |
2258 | update_reg_state(ctx, &state); | |
b6c9e612 BP |
2259 | break; |
2260 | ||
2261 | case NXAST_REG_LOAD: | |
7b064a79 | 2262 | save_reg_state(ctx, &state); |
b6c9e612 BP |
2263 | nxm_execute_reg_load((const struct nx_action_reg_load *) nah, |
2264 | &ctx->flow); | |
7b064a79 BP |
2265 | update_reg_state(ctx, &state); |
2266 | break; | |
96fc46e8 BP |
2267 | |
2268 | case NXAST_NOTE: | |
2269 | /* Nothing to do. */ | |
b6c9e612 BP |
2270 | break; |
2271 | ||
b9298d3f BP |
2272 | case NXAST_SET_TUNNEL64: |
2273 | tun_id = ((const struct nx_action_set_tunnel64 *) nah)->tun_id; | |
7aec165d | 2274 | nl_msg_put_be64(ctx->odp_actions, ODP_ACTION_ATTR_SET_TUNNEL, tun_id); |
b9298d3f BP |
2275 | ctx->flow.tun_id = tun_id; |
2276 | break; | |
2277 | ||
53ddd40a BP |
2278 | case NXAST_MULTIPATH: |
2279 | nam = (const struct nx_action_multipath *) nah; | |
2280 | multipath_execute(nam, &ctx->flow); | |
2281 | break; | |
2282 | ||
999f0d45 | 2283 | /* If you add a new action here that modifies flow data, don't forget to |
c1c9c9c4 | 2284 | * update the flow key in ctx->flow at the same time. */ |
999f0d45 | 2285 | |
e41a9130 | 2286 | case NXAST_SNAT__OBSOLETE: |
064af421 | 2287 | default: |
e41a9130 | 2288 | VLOG_DBG_RL(&rl, "unknown Nicira action type %d", (int) subtype); |
064af421 BP |
2289 | break; |
2290 | } | |
2291 | } | |
2292 | ||
2293 | static void | |
2294 | do_xlate_actions(const union ofp_action *in, size_t n_in, | |
2295 | struct action_xlate_ctx *ctx) | |
2296 | { | |
2297 | struct actions_iterator iter; | |
2298 | const union ofp_action *ia; | |
2299 | const struct ofport *port; | |
2300 | ||
ca0f572c | 2301 | port = get_port(ctx->ofproto, ctx->flow.in_port); |
064af421 | 2302 | if (port && port->opp.config & (OFPPC_NO_RECV | OFPPC_NO_RECV_STP) && |
ba186119 | 2303 | port->opp.config & (eth_addr_equals(ctx->flow.dl_dst, eth_addr_stp) |
064af421 BP |
2304 | ? OFPPC_NO_RECV_STP : OFPPC_NO_RECV)) { |
2305 | /* Drop this flow. */ | |
2306 | return; | |
2307 | } | |
2308 | ||
2309 | for (ia = actions_first(&iter, in, n_in); ia; ia = actions_next(&iter)) { | |
e41a9130 | 2310 | enum ofp_action_type type = ntohs(ia->type); |
cdee00fd | 2311 | const struct ofp_action_dl_addr *oada; |
064af421 BP |
2312 | |
2313 | switch (type) { | |
2314 | case OFPAT_OUTPUT: | |
2315 | xlate_output_action(ctx, &ia->output); | |
2316 | break; | |
2317 | ||
2318 | case OFPAT_SET_VLAN_VID: | |
66642cb4 BP |
2319 | ctx->flow.vlan_tci &= ~htons(VLAN_VID_MASK); |
2320 | ctx->flow.vlan_tci |= ia->vlan_vid.vlan_vid | htons(VLAN_CFI); | |
350a665f | 2321 | xlate_set_dl_tci(ctx); |
064af421 BP |
2322 | break; |
2323 | ||
2324 | case OFPAT_SET_VLAN_PCP: | |
66642cb4 BP |
2325 | ctx->flow.vlan_tci &= ~htons(VLAN_PCP_MASK); |
2326 | ctx->flow.vlan_tci |= htons( | |
2327 | (ia->vlan_pcp.vlan_pcp << VLAN_PCP_SHIFT) | VLAN_CFI); | |
350a665f | 2328 | xlate_set_dl_tci(ctx); |
064af421 BP |
2329 | break; |
2330 | ||
2331 | case OFPAT_STRIP_VLAN: | |
66642cb4 | 2332 | ctx->flow.vlan_tci = htons(0); |
350a665f | 2333 | xlate_set_dl_tci(ctx); |
064af421 BP |
2334 | break; |
2335 | ||
2336 | case OFPAT_SET_DL_SRC: | |
cdee00fd | 2337 | oada = ((struct ofp_action_dl_addr *) ia); |
7aec165d | 2338 | nl_msg_put_unspec(ctx->odp_actions, ODP_ACTION_ATTR_SET_DL_SRC, |
cdee00fd BP |
2339 | oada->dl_addr, ETH_ADDR_LEN); |
2340 | memcpy(ctx->flow.dl_src, oada->dl_addr, ETH_ADDR_LEN); | |
064af421 BP |
2341 | break; |
2342 | ||
2343 | case OFPAT_SET_DL_DST: | |
cdee00fd | 2344 | oada = ((struct ofp_action_dl_addr *) ia); |
7aec165d | 2345 | nl_msg_put_unspec(ctx->odp_actions, ODP_ACTION_ATTR_SET_DL_DST, |
cdee00fd BP |
2346 | oada->dl_addr, ETH_ADDR_LEN); |
2347 | memcpy(ctx->flow.dl_dst, oada->dl_addr, ETH_ADDR_LEN); | |
064af421 BP |
2348 | break; |
2349 | ||
2350 | case OFPAT_SET_NW_SRC: | |
7aec165d | 2351 | nl_msg_put_be32(ctx->odp_actions, ODP_ACTION_ATTR_SET_NW_SRC, |
cdee00fd BP |
2352 | ia->nw_addr.nw_addr); |
2353 | ctx->flow.nw_src = ia->nw_addr.nw_addr; | |
064af421 BP |
2354 | break; |
2355 | ||
2d70a31a | 2356 | case OFPAT_SET_NW_DST: |
7aec165d | 2357 | nl_msg_put_be32(ctx->odp_actions, ODP_ACTION_ATTR_SET_NW_DST, |
cdee00fd BP |
2358 | ia->nw_addr.nw_addr); |
2359 | ctx->flow.nw_dst = ia->nw_addr.nw_addr; | |
2d38e234 | 2360 | break; |
959a2ecd JP |
2361 | |
2362 | case OFPAT_SET_NW_TOS: | |
7aec165d | 2363 | nl_msg_put_u8(ctx->odp_actions, ODP_ACTION_ATTR_SET_NW_TOS, |
cdee00fd BP |
2364 | ia->nw_tos.nw_tos); |
2365 | ctx->flow.nw_tos = ia->nw_tos.nw_tos; | |
2d70a31a JP |
2366 | break; |
2367 | ||
064af421 | 2368 | case OFPAT_SET_TP_SRC: |
7aec165d | 2369 | nl_msg_put_be16(ctx->odp_actions, ODP_ACTION_ATTR_SET_TP_SRC, |
cdee00fd BP |
2370 | ia->tp_port.tp_port); |
2371 | ctx->flow.tp_src = ia->tp_port.tp_port; | |
064af421 BP |
2372 | break; |
2373 | ||
2d70a31a | 2374 | case OFPAT_SET_TP_DST: |
7aec165d | 2375 | nl_msg_put_be16(ctx->odp_actions, ODP_ACTION_ATTR_SET_TP_DST, |
cdee00fd BP |
2376 | ia->tp_port.tp_port); |
2377 | ctx->flow.tp_dst = ia->tp_port.tp_port; | |
2d70a31a JP |
2378 | break; |
2379 | ||
064af421 BP |
2380 | case OFPAT_VENDOR: |
2381 | xlate_nicira_action(ctx, (const struct nx_action_header *) ia); | |
2382 | break; | |
2383 | ||
c1c9c9c4 BP |
2384 | case OFPAT_ENQUEUE: |
2385 | xlate_enqueue_action(ctx, (const struct ofp_action_enqueue *) ia); | |
2386 | break; | |
2387 | ||
064af421 | 2388 | default: |
e41a9130 | 2389 | VLOG_DBG_RL(&rl, "unknown action type %d", (int) type); |
064af421 BP |
2390 | break; |
2391 | } | |
2392 | } | |
2393 | } | |
2394 | ||
f29152ca BP |
2395 | static void |
2396 | action_xlate_ctx_init(struct action_xlate_ctx *ctx, | |
2397 | struct ofproto *ofproto, const struct flow *flow, | |
2398 | const struct ofpbuf *packet) | |
064af421 | 2399 | { |
f29152ca BP |
2400 | ctx->ofproto = ofproto; |
2401 | ctx->flow = *flow; | |
2402 | ctx->packet = packet; | |
7aa697dd | 2403 | ctx->resubmit_hook = NULL; |
ebe482fd | 2404 | ctx->check_special = true; |
f29152ca | 2405 | } |
1eb0942d | 2406 | |
e7934396 BP |
2407 | static void |
2408 | ofproto_process_cfm(struct ofproto *ofproto, const struct flow *flow, | |
2409 | const struct ofpbuf *packet) | |
2410 | { | |
2411 | struct ofport *ofport; | |
2412 | ||
2413 | ofport = get_port(ofproto, flow->in_port); | |
2414 | if (ofport && ofport->cfm) { | |
2415 | cfm_process_heartbeat(ofport->cfm, packet); | |
2416 | } | |
2417 | } | |
2418 | ||
cdee00fd | 2419 | static struct ofpbuf * |
f29152ca BP |
2420 | xlate_actions(struct action_xlate_ctx *ctx, |
2421 | const union ofp_action *in, size_t n_in) | |
2422 | { | |
064af421 | 2423 | COVERAGE_INC(ofproto_ofp2odp); |
cdee00fd BP |
2424 | |
2425 | ctx->odp_actions = ofpbuf_new(512); | |
f29152ca BP |
2426 | ctx->tags = 0; |
2427 | ctx->may_set_up_flow = true; | |
2428 | ctx->nf_output_iface = NF_OUT_DROP; | |
2429 | ctx->recurse = 0; | |
cdee00fd | 2430 | ctx->last_pop_priority = -1; |
ebe482fd | 2431 | |
e7934396 BP |
2432 | if (ctx->check_special && cfm_should_process_flow(&ctx->flow)) { |
2433 | if (ctx->packet) { | |
2434 | ofproto_process_cfm(ctx->ofproto, &ctx->flow, ctx->packet); | |
2435 | } | |
ebe482fd | 2436 | ctx->may_set_up_flow = false; |
e7934396 BP |
2437 | } else if (ctx->check_special |
2438 | && ctx->ofproto->ofhooks->special_cb | |
2439 | && !ctx->ofproto->ofhooks->special_cb(&ctx->flow, ctx->packet, | |
2440 | ctx->ofproto->aux)) { | |
2441 | ctx->may_set_up_flow = false; | |
2442 | } else { | |
2443 | do_xlate_actions(in, n_in, ctx); | |
ebe482fd EJ |
2444 | } |
2445 | ||
f29152ca | 2446 | remove_pop_action(ctx); |
0ad9b732 | 2447 | |
d6fbec6d | 2448 | /* Check with in-band control to see if we're allowed to set up this |
0ad9b732 | 2449 | * flow. */ |
19a87e36 BP |
2450 | if (!connmgr_may_set_up_flow(ctx->ofproto->connmgr, &ctx->flow, |
2451 | ctx->odp_actions->data, | |
2452 | ctx->odp_actions->size)) { | |
f29152ca | 2453 | ctx->may_set_up_flow = false; |
0ad9b732 JP |
2454 | } |
2455 | ||
cdee00fd | 2456 | return ctx->odp_actions; |
064af421 BP |
2457 | } |
2458 | ||
9deba63b BP |
2459 | /* Checks whether 'ofconn' is a slave controller. If so, returns an OpenFlow |
2460 | * error message code (composed with ofp_mkerr()) for the caller to propagate | |
2461 | * upward. Otherwise, returns 0. | |
2462 | * | |
2228b50d | 2463 | * The log message mentions 'msg_type'. */ |
9deba63b | 2464 | static int |
2228b50d | 2465 | reject_slave_controller(struct ofconn *ofconn, const const char *msg_type) |
9deba63b | 2466 | { |
1ce0a5fa BP |
2467 | if (ofconn_get_type(ofconn) == OFCONN_PRIMARY |
2468 | && ofconn_get_role(ofconn) == NX_ROLE_SLAVE) { | |
9deba63b | 2469 | static struct vlog_rate_limit perm_rl = VLOG_RATE_LIMIT_INIT(1, 5); |
9deba63b | 2470 | VLOG_WARN_RL(&perm_rl, "rejecting %s message from slave controller", |
2228b50d | 2471 | msg_type); |
9deba63b BP |
2472 | |
2473 | return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_EPERM); | |
2474 | } else { | |
2475 | return 0; | |
2476 | } | |
2477 | } | |
2478 | ||
064af421 | 2479 | static int |
d1e2cf21 | 2480 | handle_packet_out(struct ofconn *ofconn, const struct ofp_header *oh) |
064af421 | 2481 | { |
64ff1d96 | 2482 | struct ofproto *p = ofconn_get_ofproto(ofconn); |
064af421 BP |
2483 | struct ofp_packet_out *opo; |
2484 | struct ofpbuf payload, *buffer; | |
ac51afaf | 2485 | union ofp_action *ofp_actions; |
f29152ca | 2486 | struct action_xlate_ctx ctx; |
cdee00fd | 2487 | struct ofpbuf *odp_actions; |
ac51afaf | 2488 | struct ofpbuf request; |
ae412e7d | 2489 | struct flow flow; |
ac51afaf | 2490 | size_t n_ofp_actions; |
064af421 | 2491 | uint16_t in_port; |
064af421 BP |
2492 | int error; |
2493 | ||
ac51afaf BP |
2494 | COVERAGE_INC(ofproto_packet_out); |
2495 | ||
2228b50d | 2496 | error = reject_slave_controller(ofconn, "OFPT_PACKET_OUT"); |
9deba63b BP |
2497 | if (error) { |
2498 | return error; | |
2499 | } | |
2500 | ||
ac51afaf | 2501 | /* Get ofp_packet_out. */ |
0bc9407d | 2502 | ofpbuf_use_const(&request, oh, ntohs(oh->length)); |
bbc32a88 | 2503 | opo = ofpbuf_pull(&request, offsetof(struct ofp_packet_out, actions)); |
ac51afaf BP |
2504 | |
2505 | /* Get actions. */ | |
2506 | error = ofputil_pull_actions(&request, ntohs(opo->actions_len), | |
2507 | &ofp_actions, &n_ofp_actions); | |
064af421 BP |
2508 | if (error) { |
2509 | return error; | |
2510 | } | |
064af421 | 2511 | |
ac51afaf | 2512 | /* Get payload. */ |
064af421 | 2513 | if (opo->buffer_id != htonl(UINT32_MAX)) { |
10d0a1d2 BP |
2514 | error = ofconn_pktbuf_retrieve(ofconn, ntohl(opo->buffer_id), |
2515 | &buffer, &in_port); | |
7778bd15 | 2516 | if (error || !buffer) { |
064af421 BP |
2517 | return error; |
2518 | } | |
2519 | payload = *buffer; | |
2520 | } else { | |
ac51afaf | 2521 | payload = request; |
064af421 BP |
2522 | buffer = NULL; |
2523 | } | |
2524 | ||
ac51afaf BP |
2525 | /* Extract flow, check actions. */ |
2526 | flow_extract(&payload, 0, ofp_port_to_odp_port(ntohs(opo->in_port)), | |
2527 | &flow); | |
f1defbf9 | 2528 | error = validate_actions(ofp_actions, n_ofp_actions, &flow, p->max_ports); |
ac51afaf BP |
2529 | if (error) { |
2530 | goto exit; | |
2531 | } | |
2532 | ||
2533 | /* Send. */ | |
f29152ca | 2534 | action_xlate_ctx_init(&ctx, p, &flow, &payload); |
cdee00fd BP |
2535 | odp_actions = xlate_actions(&ctx, ofp_actions, n_ofp_actions); |
2536 | dpif_execute(p->dpif, odp_actions->data, odp_actions->size, &payload); | |
2537 | ofpbuf_delete(odp_actions); | |
064af421 | 2538 | |
ac51afaf BP |
2539 | exit: |
2540 | ofpbuf_delete(buffer); | |
2541 | return 0; | |
064af421 BP |
2542 | } |
2543 | ||
2544 | static void | |
2545 | update_port_config(struct ofproto *p, struct ofport *port, | |
2546 | uint32_t config, uint32_t mask) | |
2547 | { | |
2548 | mask &= config ^ port->opp.config; | |
2549 | if (mask & OFPPC_PORT_DOWN) { | |
2550 | if (config & OFPPC_PORT_DOWN) { | |
2551 | netdev_turn_flags_off(port->netdev, NETDEV_UP, true); | |
2552 | } else { | |
2553 | netdev_turn_flags_on(port->netdev, NETDEV_UP, true); | |
2554 | } | |
2555 | } | |
f1588b1f BP |
2556 | #define REVALIDATE_BITS (OFPPC_NO_RECV | OFPPC_NO_RECV_STP | \ |
2557 | OFPPC_NO_FWD | OFPPC_NO_FLOOD) | |
064af421 BP |
2558 | if (mask & REVALIDATE_BITS) { |
2559 | COVERAGE_INC(ofproto_costly_flags); | |
2560 | port->opp.config ^= mask & REVALIDATE_BITS; | |
2561 | p->need_revalidate = true; | |
2562 | } | |
2563 | #undef REVALIDATE_BITS | |
064af421 BP |
2564 | if (mask & OFPPC_NO_PACKET_IN) { |
2565 | port->opp.config ^= OFPPC_NO_PACKET_IN; | |
2566 | } | |
2567 | } | |
2568 | ||
2569 | static int | |
d1e2cf21 | 2570 | handle_port_mod(struct ofconn *ofconn, const struct ofp_header *oh) |
064af421 | 2571 | { |
64ff1d96 | 2572 | struct ofproto *p = ofconn_get_ofproto(ofconn); |
d1e2cf21 | 2573 | const struct ofp_port_mod *opm = (const struct ofp_port_mod *) oh; |
064af421 BP |
2574 | struct ofport *port; |
2575 | int error; | |
2576 | ||
2228b50d | 2577 | error = reject_slave_controller(ofconn, "OFPT_PORT_MOD"); |
9deba63b BP |
2578 | if (error) { |
2579 | return error; | |
2580 | } | |
064af421 | 2581 | |
ca0f572c | 2582 | port = get_port(p, ofp_port_to_odp_port(ntohs(opm->port_no))); |
064af421 BP |
2583 | if (!port) { |
2584 | return ofp_mkerr(OFPET_PORT_MOD_FAILED, OFPPMFC_BAD_PORT); | |
2585 | } else if (memcmp(port->opp.hw_addr, opm->hw_addr, OFP_ETH_ALEN)) { | |
2586 | return ofp_mkerr(OFPET_PORT_MOD_FAILED, OFPPMFC_BAD_HW_ADDR); | |
2587 | } else { | |
2588 | update_port_config(p, port, ntohl(opm->config), ntohl(opm->mask)); | |
2589 | if (opm->advertise) { | |
2590 | netdev_set_advertisements(port->netdev, ntohl(opm->advertise)); | |
2591 | } | |
2592 | } | |
2593 | return 0; | |
2594 | } | |
2595 | ||
2596 | static struct ofpbuf * | |
06a5e131 | 2597 | make_ofp_stats_reply(ovs_be32 xid, ovs_be16 type, size_t body_len) |
064af421 BP |
2598 | { |
2599 | struct ofp_stats_reply *osr; | |
2600 | struct ofpbuf *msg; | |
2601 | ||
2602 | msg = ofpbuf_new(MIN(sizeof *osr + body_len, UINT16_MAX)); | |
2603 | osr = put_openflow_xid(sizeof *osr, OFPT_STATS_REPLY, xid, msg); | |
2604 | osr->type = type; | |
2605 | osr->flags = htons(0); | |
2606 | return msg; | |
2607 | } | |
2608 | ||
2609 | static struct ofpbuf * | |
d1e2cf21 | 2610 | start_ofp_stats_reply(const struct ofp_header *request, size_t body_len) |
064af421 | 2611 | { |
d1e2cf21 BP |
2612 | const struct ofp_stats_request *osr |
2613 | = (const struct ofp_stats_request *) request; | |
2614 | return make_ofp_stats_reply(osr->header.xid, osr->type, body_len); | |
064af421 BP |
2615 | } |
2616 | ||
2617 | static void * | |
06a5e131 BP |
2618 | append_ofp_stats_reply(size_t nbytes, struct ofconn *ofconn, |
2619 | struct ofpbuf **msgp) | |
064af421 BP |
2620 | { |
2621 | struct ofpbuf *msg = *msgp; | |
2622 | assert(nbytes <= UINT16_MAX - sizeof(struct ofp_stats_reply)); | |
2623 | if (nbytes + msg->size > UINT16_MAX) { | |
2624 | struct ofp_stats_reply *reply = msg->data; | |
2625 | reply->flags = htons(OFPSF_REPLY_MORE); | |
06a5e131 | 2626 | *msgp = make_ofp_stats_reply(reply->header.xid, reply->type, nbytes); |
b0421aa2 | 2627 | ofconn_send_reply(ofconn, msg); |
064af421 BP |
2628 | } |
2629 | return ofpbuf_put_uninit(*msgp, nbytes); | |
2630 | } | |
2631 | ||
09246b99 BP |
2632 | static struct ofpbuf * |
2633 | make_nxstats_reply(ovs_be32 xid, ovs_be32 subtype, size_t body_len) | |
2634 | { | |
2635 | struct nicira_stats_msg *nsm; | |
2636 | struct ofpbuf *msg; | |
2637 | ||
2638 | msg = ofpbuf_new(MIN(sizeof *nsm + body_len, UINT16_MAX)); | |
2639 | nsm = put_openflow_xid(sizeof *nsm, OFPT_STATS_REPLY, xid, msg); | |
2640 | nsm->type = htons(OFPST_VENDOR); | |
2641 | nsm->flags = htons(0); | |
2642 | nsm->vendor = htonl(NX_VENDOR_ID); | |
d5f2379b | 2643 | nsm->subtype = subtype; |
09246b99 BP |
2644 | return msg; |
2645 | } | |
2646 | ||
2647 | static struct ofpbuf * | |
2648 | start_nxstats_reply(const struct nicira_stats_msg *request, size_t body_len) | |
2649 | { | |
2650 | return make_nxstats_reply(request->header.xid, request->subtype, body_len); | |
2651 | } | |
2652 | ||
2653 | static void | |
2654 | append_nxstats_reply(size_t nbytes, struct ofconn *ofconn, | |
2655 | struct ofpbuf **msgp) | |
2656 | { | |
2657 | struct ofpbuf *msg = *msgp; | |
2658 | assert(nbytes <= UINT16_MAX - sizeof(struct nicira_stats_msg)); | |
2659 | if (nbytes + msg->size > UINT16_MAX) { | |
2660 | struct nicira_stats_msg *reply = msg->data; | |
2661 | reply->flags = htons(OFPSF_REPLY_MORE); | |
2662 | *msgp = make_nxstats_reply(reply->header.xid, reply->subtype, nbytes); | |
b0421aa2 | 2663 | ofconn_send_reply(ofconn, msg); |
09246b99 BP |
2664 | } |
2665 | ofpbuf_prealloc_tailroom(*msgp, nbytes); | |
2666 | } | |
2667 | ||
064af421 | 2668 | static int |
3269c562 | 2669 | handle_desc_stats_request(struct ofconn *ofconn, |
d1e2cf21 | 2670 | const struct ofp_header *request) |
064af421 | 2671 | { |
64ff1d96 | 2672 | struct ofproto *p = ofconn_get_ofproto(ofconn); |
064af421 BP |
2673 | struct ofp_desc_stats *ods; |
2674 | struct ofpbuf *msg; | |
2675 | ||
06a5e131 BP |
2676 | msg = start_ofp_stats_reply(request, sizeof *ods); |
2677 | ods = append_ofp_stats_reply(sizeof *ods, ofconn, &msg); | |
5a719c38 JP |
2678 | memset(ods, 0, sizeof *ods); |
2679 | ovs_strlcpy(ods->mfr_desc, p->mfr_desc, sizeof ods->mfr_desc); | |
2680 | ovs_strlcpy(ods->hw_desc, p->hw_desc, sizeof ods->hw_desc); | |
2681 | ovs_strlcpy(ods->sw_desc, p->sw_desc, sizeof ods->sw_desc); | |
2682 | ovs_strlcpy(ods->serial_num, p->serial_desc, sizeof ods->serial_num); | |
2683 | ovs_strlcpy(ods->dp_desc, p->dp_desc, sizeof ods->dp_desc); | |
b0421aa2 | 2684 | ofconn_send_reply(ofconn, msg); |
064af421 BP |
2685 | |
2686 | return 0; | |
2687 | } | |
2688 | ||
064af421 | 2689 | static int |
3269c562 | 2690 | handle_table_stats_request(struct ofconn *ofconn, |
d1e2cf21 | 2691 | const struct ofp_header *request) |
064af421 | 2692 | { |
64ff1d96 | 2693 | struct ofproto *p = ofconn_get_ofproto(ofconn); |
064af421 BP |
2694 | struct ofp_table_stats *ots; |
2695 | struct ofpbuf *msg; | |
064af421 | 2696 | |
06a5e131 | 2697 | msg = start_ofp_stats_reply(request, sizeof *ots * 2); |
064af421 | 2698 | |
064af421 | 2699 | /* Classifier table. */ |
06a5e131 | 2700 | ots = append_ofp_stats_reply(sizeof *ots, ofconn, &msg); |
064af421 | 2701 | memset(ots, 0, sizeof *ots); |
064af421 | 2702 | strcpy(ots->name, "classifier"); |
f1dd9191 | 2703 | ots->wildcards = (ofconn_get_flow_format(ofconn) == NXFF_OPENFLOW10 |
f9bfea14 | 2704 | ? htonl(OFPFW_ALL) : htonl(OVSFW_ALL)); |
ad828225 | 2705 | ots->max_entries = htonl(1024 * 1024); /* An arbitrary big number. */ |
bcf84111 | 2706 | ots->active_count = htonl(classifier_count(&p->cls)); |
c4617b3c BP |
2707 | put_32aligned_be64(&ots->lookup_count, htonll(0)); /* XXX */ |
2708 | put_32aligned_be64(&ots->matched_count, htonll(0)); /* XXX */ | |
064af421 | 2709 | |
b0421aa2 | 2710 | ofconn_send_reply(ofconn, msg); |
064af421 BP |
2711 | return 0; |
2712 | } | |
2713 | ||
abaad8cf | 2714 | static void |
ca0f572c | 2715 | append_port_stat(struct ofport *port, struct ofconn *ofconn, |
a4948b95 | 2716 | struct ofpbuf **msgp) |
abaad8cf JP |
2717 | { |
2718 | struct netdev_stats stats; | |
2719 | struct ofp_port_stats *ops; | |
2720 | ||
d295e8e9 JP |
2721 | /* Intentionally ignore return value, since errors will set |
2722 | * 'stats' to all-1s, which is correct for OpenFlow, and | |
abaad8cf JP |
2723 | * netdev_get_stats() will log errors. */ |
2724 | netdev_get_stats(port->netdev, &stats); | |
2725 | ||
06a5e131 | 2726 | ops = append_ofp_stats_reply(sizeof *ops, ofconn, msgp); |
ca0f572c | 2727 | ops->port_no = htons(port->opp.port_no); |
abaad8cf | 2728 | memset(ops->pad, 0, sizeof ops->pad); |
c4617b3c BP |
2729 | put_32aligned_be64(&ops->rx_packets, htonll(stats.rx_packets)); |
2730 | put_32aligned_be64(&ops->tx_packets, htonll(stats.tx_packets)); | |
2731 | put_32aligned_be64(&ops->rx_bytes, htonll(stats.rx_bytes)); | |
2732 | put_32aligned_be64(&ops->tx_bytes, htonll(stats.tx_bytes)); | |
2733 | put_32aligned_be64(&ops->rx_dropped, htonll(stats.rx_dropped)); | |
2734 | put_32aligned_be64(&ops->tx_dropped, htonll(stats.tx_dropped)); | |
2735 | put_32aligned_be64(&ops->rx_errors, htonll(stats.rx_errors)); | |
2736 | put_32aligned_be64(&ops->tx_errors, htonll(stats.tx_errors)); | |
2737 | put_32aligned_be64(&ops->rx_frame_err, htonll(stats.rx_frame_errors)); | |
2738 | put_32aligned_be64(&ops->rx_over_err, htonll(stats.rx_over_errors)); | |
2739 | put_32aligned_be64(&ops->rx_crc_err, htonll(stats.rx_crc_errors)); | |
2740 | put_32aligned_be64(&ops->collisions, htonll(stats.collisions)); | |
abaad8cf JP |
2741 | } |
2742 | ||
064af421 | 2743 | static int |
d1e2cf21 | 2744 | handle_port_stats_request(struct ofconn *ofconn, const struct ofp_header *oh) |
064af421 | 2745 | { |
64ff1d96 | 2746 | struct ofproto *p = ofconn_get_ofproto(ofconn); |
d1e2cf21 | 2747 | const struct ofp_port_stats_request *psr = ofputil_stats_body(oh); |
064af421 BP |
2748 | struct ofp_port_stats *ops; |
2749 | struct ofpbuf *msg; | |
2750 | struct ofport *port; | |
064af421 | 2751 | |
d1e2cf21 | 2752 | msg = start_ofp_stats_reply(oh, sizeof *ops * 16); |
abaad8cf | 2753 | if (psr->port_no != htons(OFPP_NONE)) { |
ca0f572c | 2754 | port = get_port(p, ofp_port_to_odp_port(ntohs(psr->port_no))); |
abaad8cf | 2755 | if (port) { |
ca0f572c | 2756 | append_port_stat(port, ofconn, &msg); |
abaad8cf JP |
2757 | } |
2758 | } else { | |
4e8e4213 | 2759 | HMAP_FOR_EACH (port, hmap_node, &p->ports) { |
ca0f572c | 2760 | append_port_stat(port, ofconn, &msg); |
abaad8cf | 2761 | } |
064af421 BP |
2762 | } |
2763 | ||
b0421aa2 | 2764 | ofconn_send_reply(ofconn, msg); |
064af421 BP |
2765 | return 0; |
2766 | } | |
2767 | ||
c6ebb8fb | 2768 | static void |
588cd7b5 | 2769 | calc_flow_duration__(long long int start, uint32_t *sec, uint32_t *nsec) |
c6ebb8fb BP |
2770 | { |
2771 | long long int msecs = time_msec() - start; | |
588cd7b5 BP |
2772 | *sec = msecs / 1000; |
2773 | *nsec = (msecs % 1000) * (1000 * 1000); | |
2774 | } | |
2775 | ||
2776 | static void | |
2777 | calc_flow_duration(long long int start, ovs_be32 *sec_be, ovs_be32 *nsec_be) | |
2778 | { | |
2779 | uint32_t sec, nsec; | |
2780 | ||
2781 | calc_flow_duration__(start, &sec, &nsec); | |
2782 | *sec_be = htonl(sec); | |
2783 | *nsec_be = htonl(nsec); | |
c6ebb8fb BP |
2784 | } |
2785 | ||
064af421 | 2786 | static void |
5ecc9d81 BP |
2787 | put_ofp_flow_stats(struct ofconn *ofconn, struct rule *rule, |
2788 | ovs_be16 out_port, struct ofpbuf **replyp) | |
064af421 | 2789 | { |
064af421 BP |
2790 | struct ofp_flow_stats *ofs; |
2791 | uint64_t packet_count, byte_count; | |
c4617b3c | 2792 | ovs_be64 cookie; |
064af421 BP |
2793 | size_t act_len, len; |
2794 | ||
5ecc9d81 | 2795 | if (rule_is_hidden(rule) || !rule_has_out_port(rule, out_port)) { |
064af421 BP |
2796 | return; |
2797 | } | |
2798 | ||
2799 | act_len = sizeof *rule->actions * rule->n_actions; | |
2800 | len = offsetof(struct ofp_flow_stats, actions) + act_len; | |
2801 | ||
3394b5b6 | 2802 | rule_get_stats(rule, &packet_count, &byte_count); |
064af421 | 2803 | |
5ecc9d81 | 2804 | ofs = append_ofp_stats_reply(len, ofconn, replyp); |
064af421 | 2805 | ofs->length = htons(len); |
ad828225 | 2806 | ofs->table_id = 0; |
064af421 | 2807 | ofs->pad = 0; |
f1dd9191 BP |
2808 | ofputil_cls_rule_to_match(&rule->cr, ofconn_get_flow_format(ofconn), |
2809 | &ofs->match, rule->flow_cookie, &cookie); | |
c4617b3c | 2810 | put_32aligned_be64(&ofs->cookie, cookie); |
c6ebb8fb | 2811 | calc_flow_duration(rule->created, &ofs->duration_sec, &ofs->duration_nsec); |
064af421 BP |
2812 | ofs->priority = htons(rule->cr.priority); |
2813 | ofs->idle_timeout = htons(rule->idle_timeout); | |
2814 | ofs->hard_timeout = htons(rule->hard_timeout); | |
39997502 | 2815 | memset(ofs->pad2, 0, sizeof ofs->pad2); |
c4617b3c BP |
2816 | put_32aligned_be64(&ofs->packet_count, htonll(packet_count)); |
2817 | put_32aligned_be64(&ofs->byte_count, htonll(byte_count)); | |
3dffcf07 BP |
2818 | if (rule->n_actions > 0) { |
2819 | memcpy(ofs->actions, rule->actions, act_len); | |
2820 | } | |
064af421 BP |
2821 | } |
2822 | ||
3c4486a5 BP |
2823 | static bool |
2824 | is_valid_table(uint8_t table_id) | |
064af421 | 2825 | { |
a02e5331 BP |
2826 | if (table_id == 0 || table_id == 0xff) { |
2827 | return true; | |
2828 | } else { | |
2829 | /* It would probably be better to reply with an error but there doesn't | |
2830 | * seem to be any appropriate value, so that might just be | |
2831 | * confusing. */ | |
2832 | VLOG_WARN_RL(&rl, "controller asked for invalid table %"PRIu8, | |
2833 | table_id); | |
2834 | return false; | |
2835 | } | |
064af421 BP |
2836 | } |
2837 | ||
2838 | static int | |
d1e2cf21 | 2839 | handle_flow_stats_request(struct ofconn *ofconn, const struct ofp_header *oh) |
064af421 | 2840 | { |
d1e2cf21 | 2841 | const struct ofp_flow_stats_request *fsr = ofputil_stats_body(oh); |
64ff1d96 | 2842 | struct ofproto *ofproto = ofconn_get_ofproto(ofconn); |
5ecc9d81 | 2843 | struct ofpbuf *reply; |
064af421 | 2844 | |
064af421 | 2845 | COVERAGE_INC(ofproto_flows_req); |
d1e2cf21 | 2846 | reply = start_ofp_stats_reply(oh, 1024); |
3c4486a5 | 2847 | if (is_valid_table(fsr->table_id)) { |
5ecc9d81 | 2848 | struct cls_cursor cursor; |
3c4486a5 | 2849 | struct cls_rule target; |
5ecc9d81 | 2850 | struct rule *rule; |
3c4486a5 | 2851 | |
d8ae4d67 BP |
2852 | ofputil_cls_rule_from_match(&fsr->match, 0, NXFF_OPENFLOW10, 0, |
2853 | &target); | |
64ff1d96 | 2854 | cls_cursor_init(&cursor, &ofproto->cls, &target); |
5ecc9d81 BP |
2855 | CLS_CURSOR_FOR_EACH (rule, cr, &cursor) { |
2856 | put_ofp_flow_stats(ofconn, rule, fsr->out_port, &reply); | |
2857 | } | |
3c4486a5 | 2858 | } |
b0421aa2 | 2859 | ofconn_send_reply(ofconn, reply); |
3c4486a5 | 2860 | |
064af421 BP |
2861 | return 0; |
2862 | } | |
2863 | ||
09246b99 | 2864 | static void |
5ecc9d81 BP |
2865 | put_nx_flow_stats(struct ofconn *ofconn, struct rule *rule, |
2866 | ovs_be16 out_port, struct ofpbuf **replyp) | |
09246b99 | 2867 | { |
09246b99 BP |
2868 | struct nx_flow_stats *nfs; |
2869 | uint64_t packet_count, byte_count; | |
2870 | size_t act_len, start_len; | |
5ecc9d81 | 2871 | struct ofpbuf *reply; |
09246b99 | 2872 | |
5ecc9d81 | 2873 | if (rule_is_hidden(rule) || !rule_has_out_port(rule, out_port)) { |
09246b99 BP |
2874 | return; |
2875 | } | |
2876 | ||
3394b5b6 | 2877 | rule_get_stats(rule, &packet_count, &byte_count); |
09246b99 BP |
2878 | |
2879 | act_len = sizeof *rule->actions * rule->n_actions; | |
2880 | ||
5ecc9d81 | 2881 | append_nxstats_reply(sizeof *nfs + NXM_MAX_LEN + act_len, ofconn, replyp); |
1dfee98d | 2882 | start_len = (*replyp)->size; |
5ecc9d81 BP |
2883 | reply = *replyp; |
2884 | ||
2885 | nfs = ofpbuf_put_uninit(reply, sizeof *nfs); | |
09246b99 BP |
2886 | nfs->table_id = 0; |
2887 | nfs->pad = 0; | |
2888 | calc_flow_duration(rule->created, &nfs->duration_sec, &nfs->duration_nsec); | |
2889 | nfs->cookie = rule->flow_cookie; | |
2890 | nfs->priority = htons(rule->cr.priority); | |
2891 | nfs->idle_timeout = htons(rule->idle_timeout); | |
2892 | nfs->hard_timeout = htons(rule->hard_timeout); | |
5ecc9d81 | 2893 | nfs->match_len = htons(nx_put_match(reply, &rule->cr)); |
09246b99 BP |
2894 | memset(nfs->pad2, 0, sizeof nfs->pad2); |
2895 | nfs->packet_count = htonll(packet_count); | |
2896 | nfs->byte_count = htonll(byte_count); | |
2897 | if (rule->n_actions > 0) { | |
5ecc9d81 | 2898 | ofpbuf_put(reply, rule->actions, act_len); |
09246b99 | 2899 | } |
5ecc9d81 | 2900 | nfs->length = htons(reply->size - start_len); |
09246b99 BP |
2901 | } |
2902 | ||
2903 | static int | |
d1e2cf21 | 2904 | handle_nxst_flow(struct ofconn *ofconn, const struct ofp_header *oh) |
09246b99 | 2905 | { |
64ff1d96 | 2906 | struct ofproto *ofproto = ofconn_get_ofproto(ofconn); |
09246b99 | 2907 | struct nx_flow_stats_request *nfsr; |
09246b99 | 2908 | struct cls_rule target; |
5ecc9d81 | 2909 | struct ofpbuf *reply; |
d1e2cf21 | 2910 | struct ofpbuf b; |
09246b99 BP |
2911 | int error; |
2912 | ||
0bc9407d | 2913 | ofpbuf_use_const(&b, oh, ntohs(oh->length)); |
d1e2cf21 | 2914 | |
09246b99 | 2915 | /* Dissect the message. */ |
bbc32a88 | 2916 | nfsr = ofpbuf_pull(&b, sizeof *nfsr); |
d1e2cf21 | 2917 | error = nx_pull_match(&b, ntohs(nfsr->match_len), 0, &target); |
09246b99 BP |
2918 | if (error) { |
2919 | return error; | |
2920 | } | |
d1e2cf21 BP |
2921 | if (b.size) { |
2922 | return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); | |
2923 | } | |
09246b99 BP |
2924 | |
2925 | COVERAGE_INC(ofproto_flows_req); | |
5ecc9d81 | 2926 | reply = start_nxstats_reply(&nfsr->nsm, 1024); |
3c4486a5 | 2927 | if (is_valid_table(nfsr->table_id)) { |
5ecc9d81 BP |
2928 | struct cls_cursor cursor; |
2929 | struct rule *rule; | |
2930 | ||
64ff1d96 | 2931 | cls_cursor_init(&cursor, &ofproto->cls, &target); |
5ecc9d81 BP |
2932 | CLS_CURSOR_FOR_EACH (rule, cr, &cursor) { |
2933 | put_nx_flow_stats(ofconn, rule, nfsr->out_port, &reply); | |
2934 | } | |
3c4486a5 | 2935 | } |
b0421aa2 | 2936 | ofconn_send_reply(ofconn, reply); |
5ecc9d81 | 2937 | |
09246b99 BP |
2938 | return 0; |
2939 | } | |
2940 | ||
4f2cad2c | 2941 | static void |
3394b5b6 | 2942 | flow_stats_ds(struct rule *rule, struct ds *results) |
4f2cad2c | 2943 | { |
4f2cad2c JP |
2944 | uint64_t packet_count, byte_count; |
2945 | size_t act_len = sizeof *rule->actions * rule->n_actions; | |
2946 | ||
3394b5b6 | 2947 | rule_get_stats(rule, &packet_count, &byte_count); |
4f2cad2c JP |
2948 | |
2949 | ds_put_format(results, "duration=%llds, ", | |
2950 | (time_msec() - rule->created) / 1000); | |
3693a563 | 2951 | ds_put_format(results, "idle=%.3fs, ", (time_msec() - rule->used) / 1000.0); |
52ae00b3 | 2952 | ds_put_format(results, "priority=%u, ", rule->cr.priority); |
4f2cad2c JP |
2953 | ds_put_format(results, "n_packets=%"PRIu64", ", packet_count); |
2954 | ds_put_format(results, "n_bytes=%"PRIu64", ", byte_count); | |
cb833cf6 | 2955 | cls_rule_format(&rule->cr, results); |
a5df0e72 | 2956 | ds_put_char(results, ','); |
3dffcf07 BP |
2957 | if (act_len > 0) { |
2958 | ofp_print_actions(results, &rule->actions->header, act_len); | |
3c8552c1 JP |
2959 | } else { |
2960 | ds_put_cstr(results, "drop"); | |
3dffcf07 | 2961 | } |
4f2cad2c JP |
2962 | ds_put_cstr(results, "\n"); |
2963 | } | |
2964 | ||
d295e8e9 | 2965 | /* Adds a pretty-printed description of all flows to 'results', including |
ee8b231c | 2966 | * hidden flows (e.g., set up by in-band control). */ |
4f2cad2c JP |
2967 | void |
2968 | ofproto_get_all_flows(struct ofproto *p, struct ds *results) | |
2969 | { | |
5ecc9d81 BP |
2970 | struct cls_cursor cursor; |
2971 | struct rule *rule; | |
064af421 | 2972 | |
5ecc9d81 BP |
2973 | cls_cursor_init(&cursor, &p->cls, NULL); |
2974 | CLS_CURSOR_FOR_EACH (rule, cr, &cursor) { | |
3394b5b6 | 2975 | flow_stats_ds(rule, results); |
064af421 | 2976 | } |
064af421 BP |
2977 | } |
2978 | ||
27d34fce BP |
2979 | static void |
2980 | query_aggregate_stats(struct ofproto *ofproto, struct cls_rule *target, | |
734bbeb4 | 2981 | ovs_be16 out_port, uint8_t table_id, |
27d34fce BP |
2982 | struct ofp_aggregate_stats_reply *oasr) |
2983 | { | |
5ecc9d81 BP |
2984 | uint64_t total_packets = 0; |
2985 | uint64_t total_bytes = 0; | |
2986 | int n_flows = 0; | |
27d34fce BP |
2987 | |
2988 | COVERAGE_INC(ofproto_agg_request); | |
5ecc9d81 | 2989 | |
3c4486a5 | 2990 | if (is_valid_table(table_id)) { |
5ecc9d81 BP |
2991 | struct cls_cursor cursor; |
2992 | struct rule *rule; | |
3c4486a5 | 2993 | |
5ecc9d81 BP |
2994 | cls_cursor_init(&cursor, &ofproto->cls, target); |
2995 | CLS_CURSOR_FOR_EACH (rule, cr, &cursor) { | |
2996 | if (!rule_is_hidden(rule) && rule_has_out_port(rule, out_port)) { | |
2997 | uint64_t packet_count; | |
2998 | uint64_t byte_count; | |
2999 | ||
3394b5b6 | 3000 | rule_get_stats(rule, &packet_count, &byte_count); |
5ecc9d81 BP |
3001 | |
3002 | total_packets += packet_count; | |
3003 | total_bytes += byte_count; | |
3004 | n_flows++; | |
3005 | } | |
3006 | } | |
3c4486a5 | 3007 | } |
27d34fce | 3008 | |
5ecc9d81 | 3009 | oasr->flow_count = htonl(n_flows); |
c4617b3c BP |
3010 | put_32aligned_be64(&oasr->packet_count, htonll(total_packets)); |
3011 | put_32aligned_be64(&oasr->byte_count, htonll(total_bytes)); | |
27d34fce BP |
3012 | memset(oasr->pad, 0, sizeof oasr->pad); |
3013 | } | |
3014 | ||
064af421 | 3015 | static int |
3269c562 | 3016 | handle_aggregate_stats_request(struct ofconn *ofconn, |
d1e2cf21 | 3017 | const struct ofp_header *oh) |
064af421 | 3018 | { |
d1e2cf21 | 3019 | const struct ofp_aggregate_stats_request *request = ofputil_stats_body(oh); |
64ff1d96 | 3020 | struct ofproto *ofproto = ofconn_get_ofproto(ofconn); |
064af421 | 3021 | struct ofp_aggregate_stats_reply *reply; |
064af421 BP |
3022 | struct cls_rule target; |
3023 | struct ofpbuf *msg; | |
3024 | ||
d8ae4d67 BP |
3025 | ofputil_cls_rule_from_match(&request->match, 0, NXFF_OPENFLOW10, 0, |
3026 | &target); | |
064af421 | 3027 | |
d1e2cf21 | 3028 | msg = start_ofp_stats_reply(oh, sizeof *reply); |
06a5e131 | 3029 | reply = append_ofp_stats_reply(sizeof *reply, ofconn, &msg); |
64ff1d96 | 3030 | query_aggregate_stats(ofproto, &target, request->out_port, |
27d34fce | 3031 | request->table_id, reply); |
b0421aa2 | 3032 | ofconn_send_reply(ofconn, msg); |
064af421 BP |
3033 | return 0; |
3034 | } | |
3035 | ||
09246b99 | 3036 | static int |
d1e2cf21 | 3037 | handle_nxst_aggregate(struct ofconn *ofconn, const struct ofp_header *oh) |
09246b99 | 3038 | { |
64ff1d96 | 3039 | struct ofproto *ofproto = ofconn_get_ofproto(ofconn); |
09246b99 BP |
3040 | struct nx_aggregate_stats_request *request; |
3041 | struct ofp_aggregate_stats_reply *reply; | |
3042 | struct cls_rule target; | |
d1e2cf21 | 3043 | struct ofpbuf b; |
09246b99 BP |
3044 | struct ofpbuf *buf; |
3045 | int error; | |
3046 | ||
0bc9407d | 3047 | ofpbuf_use_const(&b, oh, ntohs(oh->length)); |
d1e2cf21 | 3048 | |
09246b99 | 3049 | /* Dissect the message. */ |
bbc32a88 | 3050 | request = ofpbuf_pull(&b, sizeof *request); |
d1e2cf21 | 3051 | error = nx_pull_match(&b, ntohs(request->match_len), 0, &target); |
09246b99 BP |
3052 | if (error) { |
3053 | return error; | |
3054 | } | |
d1e2cf21 BP |
3055 | if (b.size) { |
3056 | return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); | |
3057 | } | |
09246b99 BP |
3058 | |
3059 | /* Reply. */ | |
3060 | COVERAGE_INC(ofproto_flows_req); | |
3061 | buf = start_nxstats_reply(&request->nsm, sizeof *reply); | |
3062 | reply = ofpbuf_put_uninit(buf, sizeof *reply); | |
64ff1d96 | 3063 | query_aggregate_stats(ofproto, &target, request->out_port, |
09246b99 | 3064 | request->table_id, reply); |
b0421aa2 | 3065 | ofconn_send_reply(ofconn, buf); |
09246b99 BP |
3066 | |
3067 | return 0; | |
3068 | } | |
3069 | ||
c1c9c9c4 BP |
3070 | struct queue_stats_cbdata { |
3071 | struct ofconn *ofconn; | |
ca0f572c | 3072 | struct ofport *ofport; |
c1c9c9c4 | 3073 | struct ofpbuf *msg; |
c1c9c9c4 BP |
3074 | }; |
3075 | ||
3076 | static void | |
db9220c3 | 3077 | put_queue_stats(struct queue_stats_cbdata *cbdata, uint32_t queue_id, |
c1c9c9c4 BP |
3078 | const struct netdev_queue_stats *stats) |
3079 | { | |
3080 | struct ofp_queue_stats *reply; | |
3081 | ||
06a5e131 | 3082 | reply = append_ofp_stats_reply(sizeof *reply, cbdata->ofconn, &cbdata->msg); |
ca0f572c | 3083 | reply->port_no = htons(cbdata->ofport->opp.port_no); |
c1c9c9c4 BP |
3084 | memset(reply->pad, 0, sizeof reply->pad); |
3085 | reply->queue_id = htonl(queue_id); | |
c4617b3c BP |
3086 | put_32aligned_be64(&reply->tx_bytes, htonll(stats->tx_bytes)); |
3087 | put_32aligned_be64(&reply->tx_packets, htonll(stats->tx_packets)); | |
3088 | put_32aligned_be64(&reply->tx_errors, htonll(stats->tx_errors)); | |
c1c9c9c4 BP |
3089 | } |
3090 | ||
3091 | static void | |
db9220c3 | 3092 | handle_queue_stats_dump_cb(uint32_t queue_id, |
c1c9c9c4 BP |
3093 | struct netdev_queue_stats *stats, |
3094 | void *cbdata_) | |
3095 | { | |
3096 | struct queue_stats_cbdata *cbdata = cbdata_; | |
3097 | ||
3098 | put_queue_stats(cbdata, queue_id, stats); | |
3099 | } | |
3100 | ||
3101 | static void | |
ca0f572c | 3102 | handle_queue_stats_for_port(struct ofport *port, uint32_t queue_id, |
c1c9c9c4 BP |
3103 | struct queue_stats_cbdata *cbdata) |
3104 | { | |
ca0f572c | 3105 | cbdata->ofport = port; |
c1c9c9c4 BP |
3106 | if (queue_id == OFPQ_ALL) { |
3107 | netdev_dump_queue_stats(port->netdev, | |
3108 | handle_queue_stats_dump_cb, cbdata); | |
3109 | } else { | |
3110 | struct netdev_queue_stats stats; | |
3111 | ||
1ac788f6 BP |
3112 | if (!netdev_get_queue_stats(port->netdev, queue_id, &stats)) { |
3113 | put_queue_stats(cbdata, queue_id, &stats); | |
3114 | } | |
c1c9c9c4 BP |
3115 | } |
3116 | } | |
3117 | ||
3118 | static int | |
d1e2cf21 | 3119 | handle_queue_stats_request(struct ofconn *ofconn, const struct ofp_header *oh) |
c1c9c9c4 | 3120 | { |
64ff1d96 | 3121 | struct ofproto *ofproto = ofconn_get_ofproto(ofconn); |
d1e2cf21 | 3122 | const struct ofp_queue_stats_request *qsr; |
c1c9c9c4 BP |
3123 | struct queue_stats_cbdata cbdata; |
3124 | struct ofport *port; | |
3125 | unsigned int port_no; | |
3126 | uint32_t queue_id; | |
3127 | ||
d1e2cf21 BP |
3128 | qsr = ofputil_stats_body(oh); |
3129 | if (!qsr) { | |
c1c9c9c4 BP |
3130 | return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); |
3131 | } | |
c1c9c9c4 BP |
3132 | |
3133 | COVERAGE_INC(ofproto_queue_req); | |
3134 | ||
3135 | cbdata.ofconn = ofconn; | |
d1e2cf21 | 3136 | cbdata.msg = start_ofp_stats_reply(oh, 128); |
c1c9c9c4 BP |
3137 | |
3138 | port_no = ntohs(qsr->port_no); | |
3139 | queue_id = ntohl(qsr->queue_id); | |
3140 | if (port_no == OFPP_ALL) { | |
4e8e4213 | 3141 | HMAP_FOR_EACH (port, hmap_node, &ofproto->ports) { |
ca0f572c | 3142 | handle_queue_stats_for_port(port, queue_id, &cbdata); |
c1c9c9c4 BP |
3143 | } |
3144 | } else if (port_no < ofproto->max_ports) { | |
ca0f572c | 3145 | port = get_port(ofproto, ofp_port_to_odp_port(port_no)); |
c1c9c9c4 | 3146 | if (port) { |
ca0f572c | 3147 | handle_queue_stats_for_port(port, queue_id, &cbdata); |
c1c9c9c4 BP |
3148 | } |
3149 | } else { | |
3150 | ofpbuf_delete(cbdata.msg); | |
3151 | return ofp_mkerr(OFPET_QUEUE_OP_FAILED, OFPQOFC_BAD_PORT); | |
3152 | } | |
b0421aa2 | 3153 | ofconn_send_reply(ofconn, cbdata.msg); |
c1c9c9c4 BP |
3154 | |
3155 | return 0; | |
3156 | } | |
3157 | ||
878ae780 EJ |
3158 | /* Updates 'facet''s used time. Caller is responsible for calling |
3159 | * facet_push_stats() to update the flows which 'facet' resubmits into. */ | |
064af421 | 3160 | static void |
bcf84111 | 3161 | facet_update_time(struct ofproto *ofproto, struct facet *facet, |
3394b5b6 | 3162 | long long int used) |
064af421 | 3163 | { |
bcf84111 BP |
3164 | if (used > facet->used) { |
3165 | facet->used = used; | |
3166 | if (used > facet->rule->used) { | |
3167 | facet->rule->used = used; | |
4836f9f2 | 3168 | } |
bcf84111 | 3169 | netflow_flow_update_time(ofproto->netflow, &facet->nf_flow, used); |
064af421 BP |
3170 | } |
3171 | } | |
3172 | ||
bcf84111 BP |
3173 | /* Folds the statistics from 'stats' into the counters in 'facet'. |
3174 | * | |
3175 | * Because of the meaning of a facet's counters, it only makes sense to do this | |
3176 | * if 'stats' are not tracked in the datapath, that is, if 'stats' represents a | |
3177 | * packet that was sent by hand or if it represents statistics that have been | |
3178 | * cleared out of the datapath. */ | |
064af421 | 3179 | static void |
bcf84111 | 3180 | facet_update_stats(struct ofproto *ofproto, struct facet *facet, |
c97fb132 | 3181 | const struct dpif_flow_stats *stats) |
064af421 | 3182 | { |
0b13821f | 3183 | if (stats->n_packets || stats->used > facet->used) { |
3394b5b6 | 3184 | facet_update_time(ofproto, facet, stats->used); |
bcf84111 BP |
3185 | facet->packet_count += stats->n_packets; |
3186 | facet->byte_count += stats->n_bytes; | |
878ae780 | 3187 | facet_push_stats(ofproto, facet); |
bcf84111 | 3188 | netflow_flow_update_flags(&facet->nf_flow, stats->tcp_flags); |
064af421 BP |
3189 | } |
3190 | } | |
3191 | ||
878ae780 EJ |
3192 | static void |
3193 | facet_push_stats(struct ofproto *ofproto, struct facet *facet) | |
3194 | { | |
3195 | uint64_t rs_packets, rs_bytes; | |
3196 | ||
3197 | assert(facet->packet_count >= facet->rs_packet_count); | |
3198 | assert(facet->byte_count >= facet->rs_byte_count); | |
3199 | assert(facet->used >= facet->rs_used); | |
3200 | ||
3201 | rs_packets = facet->packet_count - facet->rs_packet_count; | |
3202 | rs_bytes = facet->byte_count - facet->rs_byte_count; | |
3203 | ||
3204 | if (rs_packets || rs_bytes || facet->used > facet->rs_used) { | |
3205 | facet->rs_packet_count = facet->packet_count; | |
3206 | facet->rs_byte_count = facet->byte_count; | |
3207 | facet->rs_used = facet->used; | |
3208 | ||
3209 | flow_push_stats(ofproto, facet->rule, &facet->flow, | |
3210 | rs_packets, rs_bytes, facet->used); | |
3211 | } | |
3212 | } | |
3213 | ||
3214 | struct ofproto_push { | |
3215 | struct action_xlate_ctx ctx; | |
3216 | uint64_t packets; | |
3217 | uint64_t bytes; | |
3218 | long long int used; | |
3219 | }; | |
3220 | ||
3221 | static void | |
3222 | push_resubmit(struct action_xlate_ctx *ctx, struct rule *rule) | |
3223 | { | |
3224 | struct ofproto_push *push = CONTAINER_OF(ctx, struct ofproto_push, ctx); | |
3225 | ||
3226 | if (rule) { | |
3227 | rule->packet_count += push->packets; | |
3228 | rule->byte_count += push->bytes; | |
3229 | rule->used = MAX(push->used, rule->used); | |
3230 | } | |
3231 | } | |
3232 | ||
3233 | /* Pushes flow statistics to the rules which 'flow' resubmits into given | |
3234 | * 'rule''s actions. */ | |
3235 | static void | |
3236 | flow_push_stats(struct ofproto *ofproto, const struct rule *rule, | |
3237 | struct flow *flow, uint64_t packets, uint64_t bytes, | |
3238 | long long int used) | |
3239 | { | |
3240 | struct ofproto_push push; | |
3241 | ||
3242 | push.packets = packets; | |
3243 | push.bytes = bytes; | |
3244 | push.used = used; | |
3245 | ||
3246 | action_xlate_ctx_init(&push.ctx, ofproto, flow, NULL); | |
3247 | push.ctx.resubmit_hook = push_resubmit; | |
3248 | ofpbuf_delete(xlate_actions(&push.ctx, rule->actions, rule->n_actions)); | |
3249 | } | |
3250 | ||
79eee1eb BP |
3251 | /* Implements OFPFC_ADD and the cases for OFPFC_MODIFY and OFPFC_MODIFY_STRICT |
3252 | * in which no matching flow already exists in the flow table. | |
3253 | * | |
3254 | * Adds the flow specified by 'ofm', which is followed by 'n_actions' | |
64ff1d96 | 3255 | * ofp_actions, to the ofproto's flow table. Returns 0 on success or an |
3269c562 | 3256 | * OpenFlow error code as encoded by ofp_mkerr() on failure. |
79eee1eb BP |
3257 | * |
3258 | * 'ofconn' is used to retrieve the packet buffer specified in ofm->buffer_id, | |
3259 | * if any. */ | |
064af421 | 3260 | static int |
3052b0c5 | 3261 | add_flow(struct ofconn *ofconn, struct flow_mod *fm) |
064af421 | 3262 | { |
64ff1d96 | 3263 | struct ofproto *p = ofconn_get_ofproto(ofconn); |
064af421 BP |
3264 | struct ofpbuf *packet; |
3265 | struct rule *rule; | |
3266 | uint16_t in_port; | |
3267 | int error; | |
3268 | ||
3052b0c5 BP |
3269 | if (fm->flags & OFPFF_CHECK_OVERLAP |
3270 | && classifier_rule_overlaps(&p->cls, &fm->cr)) { | |
3271 | return ofp_mkerr(OFPET_FLOW_MOD_FAILED, OFPFMFC_OVERLAP); | |
49bdc010 JP |
3272 | } |
3273 | ||
064af421 | 3274 | error = 0; |
3052b0c5 | 3275 | if (fm->buffer_id != UINT32_MAX) { |
10d0a1d2 BP |
3276 | error = ofconn_pktbuf_retrieve(ofconn, fm->buffer_id, |
3277 | &packet, &in_port); | |
212fe71c BP |
3278 | } else { |
3279 | packet = NULL; | |
165cd8a3 | 3280 | in_port = UINT16_MAX; |
064af421 BP |
3281 | } |
3282 | ||
bcf84111 BP |
3283 | rule = rule_create(&fm->cr, fm->actions, fm->n_actions, |
3284 | fm->idle_timeout, fm->hard_timeout, fm->cookie, | |
3285 | fm->flags & OFPFF_SEND_FLOW_REM); | |
afe75089 BP |
3286 | rule_insert(p, rule); |
3287 | if (packet) { | |
3288 | rule_execute(p, rule, in_port, packet); | |
3289 | } | |
064af421 BP |
3290 | return error; |
3291 | } | |
3292 | ||
79eee1eb | 3293 | static struct rule * |
3052b0c5 | 3294 | find_flow_strict(struct ofproto *p, const struct flow_mod *fm) |
064af421 | 3295 | { |
3052b0c5 | 3296 | return rule_from_cls_rule(classifier_find_rule_exactly(&p->cls, &fm->cr)); |
79eee1eb | 3297 | } |
064af421 | 3298 | |
79eee1eb | 3299 | static int |
3269c562 | 3300 | send_buffered_packet(struct ofconn *ofconn, |
3052b0c5 | 3301 | struct rule *rule, uint32_t buffer_id) |
79eee1eb | 3302 | { |
64ff1d96 | 3303 | struct ofproto *ofproto = ofconn_get_ofproto(ofconn); |
79eee1eb BP |
3304 | struct ofpbuf *packet; |
3305 | uint16_t in_port; | |
79eee1eb | 3306 | int error; |
064af421 | 3307 | |
3052b0c5 | 3308 | if (buffer_id == UINT32_MAX) { |
79eee1eb | 3309 | return 0; |
064af421 | 3310 | } |
79eee1eb | 3311 | |
10d0a1d2 | 3312 | error = ofconn_pktbuf_retrieve(ofconn, buffer_id, &packet, &in_port); |
79eee1eb BP |
3313 | if (error) { |
3314 | return error; | |
3315 | } | |
3316 | ||
64ff1d96 | 3317 | rule_execute(ofproto, rule, in_port, packet); |
79eee1eb | 3318 | |
064af421 BP |
3319 | return 0; |
3320 | } | |
79eee1eb BP |
3321 | \f |
3322 | /* OFPFC_MODIFY and OFPFC_MODIFY_STRICT. */ | |
064af421 BP |
3323 | |
3324 | struct modify_flows_cbdata { | |
3325 | struct ofproto *ofproto; | |
3052b0c5 | 3326 | const struct flow_mod *fm; |
79eee1eb | 3327 | struct rule *match; |
064af421 BP |
3328 | }; |
3329 | ||
3052b0c5 BP |
3330 | static int modify_flow(struct ofproto *, const struct flow_mod *, |
3331 | struct rule *); | |
79eee1eb BP |
3332 | |
3333 | /* Implements OFPFC_MODIFY. Returns 0 on success or an OpenFlow error code as | |
3334 | * encoded by ofp_mkerr() on failure. | |
3335 | * | |
3336 | * 'ofconn' is used to retrieve the packet buffer specified in ofm->buffer_id, | |
3337 | * if any. */ | |
3338 | static int | |
3052b0c5 | 3339 | modify_flows_loose(struct ofconn *ofconn, struct flow_mod *fm) |
79eee1eb | 3340 | { |
64ff1d96 | 3341 | struct ofproto *p = ofconn_get_ofproto(ofconn); |
5ecc9d81 BP |
3342 | struct rule *match = NULL; |
3343 | struct cls_cursor cursor; | |
3344 | struct rule *rule; | |
79eee1eb | 3345 | |
5ecc9d81 BP |
3346 | cls_cursor_init(&cursor, &p->cls, &fm->cr); |
3347 | CLS_CURSOR_FOR_EACH (rule, cr, &cursor) { | |
3348 | if (!rule_is_hidden(rule)) { | |
3349 | match = rule; | |
3350 | modify_flow(p, fm, rule); | |
3351 | } | |
3352 | } | |
79eee1eb | 3353 | |
5ecc9d81 | 3354 | if (match) { |
d6302b0f BP |
3355 | /* This credits the packet to whichever flow happened to match last. |
3356 | * That's weird. Maybe we should do a lookup for the flow that | |
3357 | * actually matches the packet? Who knows. */ | |
5ecc9d81 | 3358 | send_buffered_packet(ofconn, match, fm->buffer_id); |
79eee1eb BP |
3359 | return 0; |
3360 | } else { | |
3052b0c5 | 3361 | return add_flow(ofconn, fm); |
79eee1eb BP |
3362 | } |
3363 | } | |
3364 | ||
3365 | /* Implements OFPFC_MODIFY_STRICT. Returns 0 on success or an OpenFlow error | |
3366 | * code as encoded by ofp_mkerr() on failure. | |
3367 | * | |
3368 | * 'ofconn' is used to retrieve the packet buffer specified in ofm->buffer_id, | |
3369 | * if any. */ | |
3370 | static int | |
3052b0c5 | 3371 | modify_flow_strict(struct ofconn *ofconn, struct flow_mod *fm) |
79eee1eb | 3372 | { |
64ff1d96 | 3373 | struct ofproto *p = ofconn_get_ofproto(ofconn); |
3052b0c5 | 3374 | struct rule *rule = find_flow_strict(p, fm); |
79eee1eb | 3375 | if (rule && !rule_is_hidden(rule)) { |
3052b0c5 BP |
3376 | modify_flow(p, fm, rule); |
3377 | return send_buffered_packet(ofconn, rule, fm->buffer_id); | |
79eee1eb | 3378 | } else { |
3052b0c5 | 3379 | return add_flow(ofconn, fm); |
79eee1eb BP |
3380 | } |
3381 | } | |
3382 | ||
79eee1eb BP |
3383 | /* Implements core of OFPFC_MODIFY and OFPFC_MODIFY_STRICT where 'rule' has |
3384 | * been identified as a flow in 'p''s flow table to be modified, by changing | |
3385 | * the rule's actions to match those in 'ofm' (which is followed by 'n_actions' | |
3386 | * ofp_action[] structures). */ | |
064af421 | 3387 | static int |
3052b0c5 | 3388 | modify_flow(struct ofproto *p, const struct flow_mod *fm, struct rule *rule) |
064af421 | 3389 | { |
3052b0c5 | 3390 | size_t actions_len = fm->n_actions * sizeof *rule->actions; |
79eee1eb | 3391 | |
3052b0c5 | 3392 | rule->flow_cookie = fm->cookie; |
79eee1eb BP |
3393 | |
3394 | /* If the actions are the same, do nothing. */ | |
3052b0c5 BP |
3395 | if (fm->n_actions == rule->n_actions |
3396 | && (!fm->n_actions | |
3397 | || !memcmp(fm->actions, rule->actions, actions_len))) { | |
79eee1eb BP |
3398 | return 0; |
3399 | } | |
3400 | ||
3401 | /* Replace actions. */ | |
3402 | free(rule->actions); | |
3052b0c5 BP |
3403 | rule->actions = fm->n_actions ? xmemdup(fm->actions, actions_len) : NULL; |
3404 | rule->n_actions = fm->n_actions; | |
79eee1eb | 3405 | |
bcf84111 | 3406 | p->need_revalidate = true; |
79eee1eb BP |
3407 | |
3408 | return 0; | |
3409 | } | |
3410 | \f | |
3411 | /* OFPFC_DELETE implementation. */ | |
3412 | ||
8054fc48 | 3413 | static void delete_flow(struct ofproto *, struct rule *, ovs_be16 out_port); |
79eee1eb BP |
3414 | |
3415 | /* Implements OFPFC_DELETE. */ | |
3416 | static void | |
3052b0c5 | 3417 | delete_flows_loose(struct ofproto *p, const struct flow_mod *fm) |
79eee1eb | 3418 | { |
5ecc9d81 BP |
3419 | struct rule *rule, *next_rule; |
3420 | struct cls_cursor cursor; | |
064af421 | 3421 | |
5ecc9d81 BP |
3422 | cls_cursor_init(&cursor, &p->cls, &fm->cr); |
3423 | CLS_CURSOR_FOR_EACH_SAFE (rule, next_rule, cr, &cursor) { | |
3424 | delete_flow(p, rule, htons(fm->out_port)); | |
3425 | } | |
064af421 BP |
3426 | } |
3427 | ||
79eee1eb BP |
3428 | /* Implements OFPFC_DELETE_STRICT. */ |
3429 | static void | |
3052b0c5 | 3430 | delete_flow_strict(struct ofproto *p, struct flow_mod *fm) |
79eee1eb | 3431 | { |
3052b0c5 | 3432 | struct rule *rule = find_flow_strict(p, fm); |
79eee1eb | 3433 | if (rule) { |
3052b0c5 | 3434 | delete_flow(p, rule, htons(fm->out_port)); |
79eee1eb BP |
3435 | } |
3436 | } | |
3437 | ||
79eee1eb BP |
3438 | /* Implements core of OFPFC_DELETE and OFPFC_DELETE_STRICT where 'rule' has |
3439 | * been identified as a flow to delete from 'p''s flow table, by deleting the | |
3440 | * flow and sending out a OFPT_FLOW_REMOVED message to any interested | |
3441 | * controller. | |
3442 | * | |
3443 | * Will not delete 'rule' if it is hidden. Will delete 'rule' only if | |
3444 | * 'out_port' is htons(OFPP_NONE) or if 'rule' actually outputs to the | |
3445 | * specified 'out_port'. */ | |
3446 | static void | |
8054fc48 | 3447 | delete_flow(struct ofproto *p, struct rule *rule, ovs_be16 out_port) |
79eee1eb BP |
3448 | { |
3449 | if (rule_is_hidden(rule)) { | |
3450 | return; | |
3451 | } | |
3452 | ||
3453 | if (out_port != htons(OFPP_NONE) && !rule_has_out_port(rule, out_port)) { | |
3454 | return; | |
3455 | } | |
3456 | ||
bcf84111 | 3457 | rule_send_removed(p, rule, OFPRR_DELETE); |
79eee1eb BP |
3458 | rule_remove(p, rule); |
3459 | } | |
3460 | \f | |
064af421 | 3461 | static int |
2e4f5fcf | 3462 | handle_flow_mod(struct ofconn *ofconn, const struct ofp_header *oh) |
064af421 | 3463 | { |
64ff1d96 | 3464 | struct ofproto *p = ofconn_get_ofproto(ofconn); |
2e4f5fcf | 3465 | struct flow_mod fm; |
064af421 BP |
3466 | int error; |
3467 | ||
3052b0c5 | 3468 | error = reject_slave_controller(ofconn, "flow_mod"); |
9deba63b BP |
3469 | if (error) { |
3470 | return error; | |
3471 | } | |
3052b0c5 | 3472 | |
f1dd9191 | 3473 | error = ofputil_decode_flow_mod(&fm, oh, ofconn_get_flow_format(ofconn)); |
064af421 BP |
3474 | if (error) { |
3475 | return error; | |
3476 | } | |
3477 | ||
2e4f5fcf BP |
3478 | /* We do not support the emergency flow cache. It will hopefully get |
3479 | * dropped from OpenFlow in the near future. */ | |
3480 | if (fm.flags & OFPFF_EMERG) { | |
49bdc010 JP |
3481 | /* There isn't a good fit for an error code, so just state that the |
3482 | * flow table is full. */ | |
3483 | return ofp_mkerr(OFPET_FLOW_MOD_FAILED, OFPFMFC_ALL_TABLES_FULL); | |
3484 | } | |
3485 | ||
2e4f5fcf BP |
3486 | error = validate_actions(fm.actions, fm.n_actions, |
3487 | &fm.cr.flow, p->max_ports); | |
3488 | if (error) { | |
3489 | return error; | |
3490 | } | |
3491 | ||
3492 | switch (fm.command) { | |
3052b0c5 | 3493 | case OFPFC_ADD: |
2e4f5fcf | 3494 | return add_flow(ofconn, &fm); |
3052b0c5 BP |
3495 | |
3496 | case OFPFC_MODIFY: | |
2e4f5fcf | 3497 | return modify_flows_loose(ofconn, &fm); |
3052b0c5 BP |
3498 | |
3499 | case OFPFC_MODIFY_STRICT: | |
2e4f5fcf | 3500 | return modify_flow_strict(ofconn, &fm); |
3052b0c5 BP |
3501 | |
3502 | case OFPFC_DELETE: | |
2e4f5fcf | 3503 | delete_flows_loose(p, &fm); |
3052b0c5 BP |
3504 | return 0; |
3505 | ||
3506 | case OFPFC_DELETE_STRICT: | |
2e4f5fcf | 3507 | delete_flow_strict(p, &fm); |
3052b0c5 BP |
3508 | return 0; |
3509 | ||
3510 | default: | |
3511 | return ofp_mkerr(OFPET_FLOW_MOD_FAILED, OFPFMFC_BAD_COMMAND); | |
3512 | } | |
3513 | } | |
3514 | ||
659586ef | 3515 | static int |
d1e2cf21 | 3516 | handle_tun_id_from_cookie(struct ofconn *ofconn, const struct ofp_header *oh) |
659586ef | 3517 | { |
d1e2cf21 BP |
3518 | const struct nxt_tun_id_cookie *msg |
3519 | = (const struct nxt_tun_id_cookie *) oh; | |
f1dd9191 BP |
3520 | enum nx_flow_format flow_format; |
3521 | ||
3522 | flow_format = msg->set ? NXFF_TUN_ID_FROM_COOKIE : NXFF_OPENFLOW10; | |
3523 | ofconn_set_flow_format(ofconn, flow_format); | |
659586ef | 3524 | |
659586ef JG |
3525 | return 0; |
3526 | } | |
3527 | ||
9deba63b | 3528 | static int |
d1e2cf21 | 3529 | handle_role_request(struct ofconn *ofconn, const struct ofp_header *oh) |
9deba63b | 3530 | { |
d1e2cf21 | 3531 | struct nx_role_request *nrr = (struct nx_role_request *) oh; |
9deba63b BP |
3532 | struct nx_role_request *reply; |
3533 | struct ofpbuf *buf; | |
3534 | uint32_t role; | |
3535 | ||
1ce0a5fa | 3536 | if (ofconn_get_type(ofconn) != OFCONN_PRIMARY) { |
19a87e36 | 3537 | VLOG_WARN_RL(&rl, "ignoring role request on service connection"); |
9deba63b BP |
3538 | return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_EPERM); |
3539 | } | |
3540 | ||
3541 | role = ntohl(nrr->role); | |
3542 | if (role != NX_ROLE_OTHER && role != NX_ROLE_MASTER | |
3543 | && role != NX_ROLE_SLAVE) { | |
3544 | VLOG_WARN_RL(&rl, "received request for unknown role %"PRIu32, role); | |
3545 | ||
3546 | /* There's no good error code for this. */ | |
3547 | return ofp_mkerr(OFPET_BAD_REQUEST, -1); | |
3548 | } | |
3549 | ||
1ce0a5fa | 3550 | ofconn_set_role(ofconn, role); |
9deba63b | 3551 | |
d1e2cf21 | 3552 | reply = make_nxmsg_xid(sizeof *reply, NXT_ROLE_REPLY, oh->xid, &buf); |
9deba63b | 3553 | reply->role = htonl(role); |
b0421aa2 | 3554 | ofconn_send_reply(ofconn, buf); |
9deba63b BP |
3555 | |
3556 | return 0; | |
3557 | } | |
3558 | ||
09246b99 | 3559 | static int |
d1e2cf21 | 3560 | handle_nxt_set_flow_format(struct ofconn *ofconn, const struct ofp_header *oh) |
09246b99 | 3561 | { |
d1e2cf21 BP |
3562 | const struct nxt_set_flow_format *msg |
3563 | = (const struct nxt_set_flow_format *) oh; | |
09246b99 | 3564 | uint32_t format; |
09246b99 BP |
3565 | |
3566 | format = ntohl(msg->format); | |
3567 | if (format == NXFF_OPENFLOW10 | |
3568 | || format == NXFF_TUN_ID_FROM_COOKIE | |
3569 | || format == NXFF_NXM) { | |
f1dd9191 | 3570 | ofconn_set_flow_format(ofconn, format); |
09246b99 BP |
3571 | return 0; |
3572 | } else { | |
3573 | return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_EPERM); | |
3574 | } | |
3575 | } | |
3576 | ||
064af421 | 3577 | static int |
d1e2cf21 | 3578 | handle_barrier_request(struct ofconn *ofconn, const struct ofp_header *oh) |
246e61ea JP |
3579 | { |
3580 | struct ofp_header *ob; | |
3581 | struct ofpbuf *buf; | |
3582 | ||
3583 | /* Currently, everything executes synchronously, so we can just | |
3584 | * immediately send the barrier reply. */ | |
3585 | ob = make_openflow_xid(sizeof *ob, OFPT_BARRIER_REPLY, oh->xid, &buf); | |
b0421aa2 | 3586 | ofconn_send_reply(ofconn, buf); |
246e61ea JP |
3587 | return 0; |
3588 | } | |
3589 | ||
d1e2cf21 BP |
3590 | static int |
3591 | handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg) | |
064af421 | 3592 | { |
d1e2cf21 BP |
3593 | const struct ofp_header *oh = msg->data; |
3594 | const struct ofputil_msg_type *type; | |
064af421 BP |
3595 | int error; |
3596 | ||
d1e2cf21 BP |
3597 | error = ofputil_decode_msg_type(oh, &type); |
3598 | if (error) { | |
3599 | return error; | |
3600 | } | |
064af421 | 3601 | |
d1e2cf21 BP |
3602 | switch (ofputil_msg_type_code(type)) { |
3603 | /* OpenFlow requests. */ | |
3604 | case OFPUTIL_OFPT_ECHO_REQUEST: | |
3605 | return handle_echo_request(ofconn, oh); | |
064af421 | 3606 | |
d1e2cf21 BP |
3607 | case OFPUTIL_OFPT_FEATURES_REQUEST: |
3608 | return handle_features_request(ofconn, oh); | |
064af421 | 3609 | |
d1e2cf21 BP |
3610 | case OFPUTIL_OFPT_GET_CONFIG_REQUEST: |
3611 | return handle_get_config_request(ofconn, oh); | |
064af421 | 3612 | |
d1e2cf21 BP |
3613 | case OFPUTIL_OFPT_SET_CONFIG: |
3614 | return handle_set_config(ofconn, msg->data); | |
064af421 | 3615 | |
d1e2cf21 BP |
3616 | case OFPUTIL_OFPT_PACKET_OUT: |
3617 | return handle_packet_out(ofconn, oh); | |
064af421 | 3618 | |
d1e2cf21 BP |
3619 | case OFPUTIL_OFPT_PORT_MOD: |
3620 | return handle_port_mod(ofconn, oh); | |
064af421 | 3621 | |
d1e2cf21 | 3622 | case OFPUTIL_OFPT_FLOW_MOD: |
2e4f5fcf | 3623 | return handle_flow_mod(ofconn, oh); |
064af421 | 3624 | |
d1e2cf21 BP |
3625 | case OFPUTIL_OFPT_BARRIER_REQUEST: |
3626 | return handle_barrier_request(ofconn, oh); | |
064af421 | 3627 | |
d1e2cf21 BP |
3628 | /* OpenFlow replies. */ |
3629 | case OFPUTIL_OFPT_ECHO_REPLY: | |
3630 | return 0; | |
246e61ea | 3631 | |
d1e2cf21 | 3632 | /* Nicira extension requests. */ |
d1e2cf21 BP |
3633 | case OFPUTIL_NXT_TUN_ID_FROM_COOKIE: |
3634 | return handle_tun_id_from_cookie(ofconn, oh); | |
3635 | ||
3636 | case OFPUTIL_NXT_ROLE_REQUEST: | |
3637 | return handle_role_request(ofconn, oh); | |
3638 | ||
3639 | case OFPUTIL_NXT_SET_FLOW_FORMAT: | |
3640 | return handle_nxt_set_flow_format(ofconn, oh); | |
3641 | ||
3642 | case OFPUTIL_NXT_FLOW_MOD: | |
2e4f5fcf | 3643 | return handle_flow_mod(ofconn, oh); |
d1e2cf21 BP |
3644 | |
3645 | /* OpenFlow statistics requests. */ | |
3646 | case OFPUTIL_OFPST_DESC_REQUEST: | |
3647 | return handle_desc_stats_request(ofconn, oh); | |
3648 | ||
3649 | case OFPUTIL_OFPST_FLOW_REQUEST: | |
3650 | return handle_flow_stats_request(ofconn, oh); | |
3651 | ||
3652 | case OFPUTIL_OFPST_AGGREGATE_REQUEST: | |
3653 | return handle_aggregate_stats_request(ofconn, oh); | |
3654 | ||
3655 | case OFPUTIL_OFPST_TABLE_REQUEST: | |
3656 | return handle_table_stats_request(ofconn, oh); | |
3657 | ||
3658 | case OFPUTIL_OFPST_PORT_REQUEST: | |
3659 | return handle_port_stats_request(ofconn, oh); | |
3660 | ||
3661 | case OFPUTIL_OFPST_QUEUE_REQUEST: | |
3662 | return handle_queue_stats_request(ofconn, oh); | |
3663 | ||
3664 | /* Nicira extension statistics requests. */ | |
3665 | case OFPUTIL_NXST_FLOW_REQUEST: | |
3666 | return handle_nxst_flow(ofconn, oh); | |
3667 | ||
3668 | case OFPUTIL_NXST_AGGREGATE_REQUEST: | |
3669 | return handle_nxst_aggregate(ofconn, oh); | |
3670 | ||
3671 | case OFPUTIL_INVALID: | |
3672 | case OFPUTIL_OFPT_HELLO: | |
3673 | case OFPUTIL_OFPT_ERROR: | |
3674 | case OFPUTIL_OFPT_FEATURES_REPLY: | |
3675 | case OFPUTIL_OFPT_GET_CONFIG_REPLY: | |
3676 | case OFPUTIL_OFPT_PACKET_IN: | |
3677 | case OFPUTIL_OFPT_FLOW_REMOVED: | |
3678 | case OFPUTIL_OFPT_PORT_STATUS: | |
3679 | case OFPUTIL_OFPT_BARRIER_REPLY: | |
3680 | case OFPUTIL_OFPT_QUEUE_GET_CONFIG_REQUEST: | |
3681 | case OFPUTIL_OFPT_QUEUE_GET_CONFIG_REPLY: | |
3682 | case OFPUTIL_OFPST_DESC_REPLY: | |
3683 | case OFPUTIL_OFPST_FLOW_REPLY: | |
3684 | case OFPUTIL_OFPST_QUEUE_REPLY: | |
3685 | case OFPUTIL_OFPST_PORT_REPLY: | |
3686 | case OFPUTIL_OFPST_TABLE_REPLY: | |
3687 | case OFPUTIL_OFPST_AGGREGATE_REPLY: | |
d1e2cf21 BP |
3688 | case OFPUTIL_NXT_ROLE_REPLY: |
3689 | case OFPUTIL_NXT_FLOW_REMOVED: | |
3690 | case OFPUTIL_NXST_FLOW_REPLY: | |
3691 | case OFPUTIL_NXST_AGGREGATE_REPLY: | |
064af421 BP |
3692 | default: |
3693 | if (VLOG_IS_WARN_ENABLED()) { | |
3694 | char *s = ofp_to_string(oh, ntohs(oh->length), 2); | |
3695 | VLOG_DBG_RL(&rl, "OpenFlow message ignored: %s", s); | |
3696 | free(s); | |
3697 | } | |
d1e2cf21 BP |
3698 | if (oh->type == OFPT_STATS_REQUEST || oh->type == OFPT_STATS_REPLY) { |
3699 | return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_STAT); | |
3700 | } else { | |
3701 | return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_TYPE); | |
3702 | } | |
064af421 | 3703 | } |
d1e2cf21 | 3704 | } |
064af421 | 3705 | |
d1e2cf21 BP |
3706 | static void |
3707 | handle_openflow(struct ofconn *ofconn, struct ofpbuf *ofp_msg) | |
3708 | { | |
3709 | int error = handle_openflow__(ofconn, ofp_msg); | |
064af421 BP |
3710 | if (error) { |
3711 | send_error_oh(ofconn, ofp_msg->data, error); | |
3712 | } | |
d1e2cf21 | 3713 | COVERAGE_INC(ofproto_recv_openflow); |
064af421 BP |
3714 | } |
3715 | \f | |
3716 | static void | |
856081f6 | 3717 | handle_miss_upcall(struct ofproto *p, struct dpif_upcall *upcall) |
064af421 | 3718 | { |
bcf84111 | 3719 | struct facet *facet; |
ae412e7d | 3720 | struct flow flow; |
064af421 | 3721 | |
856081f6 BP |
3722 | /* Obtain in_port and tun_id, at least. */ |
3723 | odp_flow_key_to_flow(upcall->key, upcall->key_len, &flow); | |
064af421 | 3724 | |
856081f6 BP |
3725 | /* Set header pointers in 'flow'. */ |
3726 | flow_extract(upcall->packet, flow.tun_id, flow.in_port, &flow); | |
4617e2c1 | 3727 | |
e7934396 BP |
3728 | if (cfm_should_process_flow(&flow)) { |
3729 | ofproto_process_cfm(p, &flow, upcall->packet); | |
3730 | ofpbuf_delete(upcall->packet); | |
3731 | return; | |
3732 | } else if (p->ofhooks->special_cb | |
3733 | && !p->ofhooks->special_cb(&flow, upcall->packet, p->aux)) { | |
ebe482fd EJ |
3734 | ofpbuf_delete(upcall->packet); |
3735 | return; | |
3736 | } | |
3737 | ||
0ad9b732 JP |
3738 | /* Check with in-band control to see if this packet should be sent |
3739 | * to the local port regardless of the flow table. */ | |
19a87e36 | 3740 | if (connmgr_msg_in_hook(p->connmgr, &flow, upcall->packet)) { |
3cf10406 | 3741 | ofproto_send_packet(p, ODPP_LOCAL, 0, upcall->packet); |
0ad9b732 JP |
3742 | } |
3743 | ||
bcf84111 BP |
3744 | facet = facet_lookup_valid(p, &flow); |
3745 | if (!facet) { | |
3746 | struct rule *rule = rule_lookup(p, &flow); | |
3747 | if (!rule) { | |
3748 | /* Don't send a packet-in if OFPPC_NO_PACKET_IN asserted. */ | |
856081f6 | 3749 | struct ofport *port = get_port(p, flow.in_port); |
bcf84111 BP |
3750 | if (port) { |
3751 | if (port->opp.config & OFPPC_NO_PACKET_IN) { | |
3752 | COVERAGE_INC(ofproto_no_packet_in); | |
3753 | /* XXX install 'drop' flow entry */ | |
856081f6 | 3754 | ofpbuf_delete(upcall->packet); |
bcf84111 BP |
3755 | return; |
3756 | } | |
3757 | } else { | |
3758 | VLOG_WARN_RL(&rl, "packet-in on unknown port %"PRIu16, | |
856081f6 | 3759 | flow.in_port); |
064af421 | 3760 | } |
064af421 | 3761 | |
bcf84111 | 3762 | COVERAGE_INC(ofproto_packet_in); |
856081f6 | 3763 | send_packet_in(p, upcall, &flow, false); |
bcf84111 | 3764 | return; |
064af421 | 3765 | } |
bcf84111 | 3766 | |
856081f6 | 3767 | facet = facet_create(p, rule, &flow, upcall->packet); |
bcf84111 BP |
3768 | } else if (!facet->may_install) { |
3769 | /* The facet is not installable, that is, we need to process every | |
3770 | * packet, so process the current packet's actions into 'facet'. */ | |
856081f6 | 3771 | facet_make_actions(p, facet, upcall->packet); |
064af421 BP |
3772 | } |
3773 | ||
bcf84111 | 3774 | if (facet->rule->cr.priority == FAIL_OPEN_PRIORITY) { |
7778bd15 BP |
3775 | /* |
3776 | * Extra-special case for fail-open mode. | |
3777 | * | |
3778 | * We are in fail-open mode and the packet matched the fail-open rule, | |
3779 | * but we are connected to a controller too. We should send the packet | |
3780 | * up to the controller in the hope that it will try to set up a flow | |
3781 | * and thereby allow us to exit fail-open. | |
3782 | * | |
3783 | * See the top-level comment in fail-open.c for more information. | |
3784 | */ | |
856081f6 | 3785 | send_packet_in(p, upcall, &flow, true); |
7778bd15 | 3786 | } |
750638bb | 3787 | |
856081f6 | 3788 | facet_execute(p, facet, upcall->packet); |
bcf84111 | 3789 | facet_install(p, facet, false); |
064af421 | 3790 | } |
72b06300 BP |
3791 | |
3792 | static void | |
856081f6 | 3793 | handle_upcall(struct ofproto *p, struct dpif_upcall *upcall) |
72b06300 | 3794 | { |
856081f6 | 3795 | struct flow flow; |
72b06300 | 3796 | |
856081f6 | 3797 | switch (upcall->type) { |
82272ede | 3798 | case DPIF_UC_ACTION: |
72b06300 | 3799 | COVERAGE_INC(ofproto_ctlr_action); |
856081f6 BP |
3800 | odp_flow_key_to_flow(upcall->key, upcall->key_len, &flow); |
3801 | send_packet_in(p, upcall, &flow, false); | |
72b06300 BP |
3802 | break; |
3803 | ||
82272ede | 3804 | case DPIF_UC_SAMPLE: |
72b06300 | 3805 | if (p->sflow) { |
856081f6 BP |
3806 | odp_flow_key_to_flow(upcall->key, upcall->key_len, &flow); |
3807 | ofproto_sflow_received(p->sflow, upcall, &flow); | |
72b06300 | 3808 | } |
856081f6 | 3809 | ofpbuf_delete(upcall->packet); |
72b06300 BP |
3810 | break; |
3811 | ||
82272ede | 3812 | case DPIF_UC_MISS: |
856081f6 | 3813 | handle_miss_upcall(p, upcall); |
72b06300 BP |
3814 | break; |
3815 | ||
982b8810 | 3816 | case DPIF_N_UC_TYPES: |
72b06300 | 3817 | default: |
856081f6 | 3818 | VLOG_WARN_RL(&rl, "upcall has unexpected type %"PRIu32, upcall->type); |
72b06300 BP |
3819 | break; |
3820 | } | |
3821 | } | |
064af421 | 3822 | \f |
4a4cdb3b BP |
3823 | /* Flow expiration. */ |
3824 | ||
0de7a4b4 | 3825 | static int ofproto_dp_max_idle(const struct ofproto *); |
3394b5b6 | 3826 | static void ofproto_update_stats(struct ofproto *); |
5ecc9d81 | 3827 | static void rule_expire(struct ofproto *, struct rule *); |
bcf84111 | 3828 | static void ofproto_expire_facets(struct ofproto *, int dp_max_idle); |
4a4cdb3b BP |
3829 | |
3830 | /* This function is called periodically by ofproto_run(). Its job is to | |
3831 | * collect updates for the flows that have been installed into the datapath, | |
3832 | * most importantly when they last were used, and then use that information to | |
0de7a4b4 BP |
3833 | * expire flows that have not been used recently. |
3834 | * | |
3835 | * Returns the number of milliseconds after which it should be called again. */ | |
3836 | static int | |
4a4cdb3b BP |
3837 | ofproto_expire(struct ofproto *ofproto) |
3838 | { | |
5ecc9d81 BP |
3839 | struct rule *rule, *next_rule; |
3840 | struct cls_cursor cursor; | |
3841 | int dp_max_idle; | |
4a4cdb3b | 3842 | |
3394b5b6 EJ |
3843 | /* Update stats for each flow in the datapath. */ |
3844 | ofproto_update_stats(ofproto); | |
4a4cdb3b | 3845 | |
bcf84111 | 3846 | /* Expire facets that have been idle too long. */ |
5ecc9d81 BP |
3847 | dp_max_idle = ofproto_dp_max_idle(ofproto); |
3848 | ofproto_expire_facets(ofproto, dp_max_idle); | |
bcf84111 BP |
3849 | |
3850 | /* Expire OpenFlow flows whose idle_timeout or hard_timeout has passed. */ | |
5ecc9d81 BP |
3851 | cls_cursor_init(&cursor, &ofproto->cls, NULL); |
3852 | CLS_CURSOR_FOR_EACH_SAFE (rule, next_rule, cr, &cursor) { | |
3853 | rule_expire(ofproto, rule); | |
3854 | } | |
4a4cdb3b BP |
3855 | |
3856 | /* Let the hook know that we're at a stable point: all outstanding data | |
3857 | * in existing flows has been accounted to the account_cb. Thus, the | |
3858 | * hook can now reasonably do operations that depend on having accurate | |
3859 | * flow volume accounting (currently, that's just bond rebalancing). */ | |
3860 | if (ofproto->ofhooks->account_checkpoint_cb) { | |
3861 | ofproto->ofhooks->account_checkpoint_cb(ofproto->aux); | |
3862 | } | |
0de7a4b4 | 3863 | |
5ecc9d81 | 3864 | return MIN(dp_max_idle, 1000); |
4a4cdb3b BP |
3865 | } |
3866 | ||
3394b5b6 | 3867 | /* Update 'packet_count', 'byte_count', and 'used' members of installed facets. |
878ae780 EJ |
3868 | * |
3869 | * This function also pushes statistics updates to rules which each facet | |
3870 | * resubmits into. Generally these statistics will be accurate. However, if a | |
3871 | * facet changes the rule it resubmits into at some time in between | |
3872 | * ofproto_update_stats() runs, it is possible that statistics accrued to the | |
3873 | * old rule will be incorrectly attributed to the new rule. This could be | |
3874 | * avoided by calling ofproto_update_stats() whenever rules are created or | |
3875 | * deleted. However, the performance impact of making so many calls to the | |
3876 | * datapath do not justify the benefit of having perfectly accurate statistics. | |
3394b5b6 | 3877 | */ |
4a4cdb3b | 3878 | static void |
3394b5b6 | 3879 | ofproto_update_stats(struct ofproto *p) |
4a4cdb3b | 3880 | { |
c97fb132 | 3881 | const struct dpif_flow_stats *stats; |
704a1e09 | 3882 | struct dpif_flow_dump dump; |
feebdea2 BP |
3883 | const struct nlattr *key; |
3884 | size_t key_len; | |
4a4cdb3b | 3885 | |
704a1e09 | 3886 | dpif_flow_dump_start(&dump, p->dpif); |
feebdea2 | 3887 | while (dpif_flow_dump_next(&dump, &key, &key_len, NULL, NULL, &stats)) { |
bcf84111 | 3888 | struct facet *facet; |
ae412e7d | 3889 | struct flow flow; |
14608a15 | 3890 | |
feebdea2 | 3891 | if (odp_flow_key_to_flow(key, key_len, &flow)) { |
36956a7d BP |
3892 | struct ds s; |
3893 | ||
3894 | ds_init(&s); | |
feebdea2 | 3895 | odp_flow_key_format(key, key_len, &s); |
36956a7d BP |
3896 | VLOG_WARN_RL(&rl, "failed to convert ODP flow key to flow: %s", |
3897 | ds_cstr(&s)); | |
3898 | ds_destroy(&s); | |
3899 | ||
3900 | continue; | |
3901 | } | |
bcf84111 | 3902 | facet = facet_find(p, &flow); |
4a4cdb3b | 3903 | |
bcf84111 | 3904 | if (facet && facet->installed) { |
3394b5b6 EJ |
3905 | |
3906 | if (stats->n_packets >= facet->dp_packet_count) { | |
3907 | facet->packet_count += stats->n_packets - facet->dp_packet_count; | |
3908 | } else { | |
3909 | VLOG_WARN_RL(&rl, "unexpected packet count from the datapath"); | |
3910 | } | |
3911 | ||
3912 | if (stats->n_bytes >= facet->dp_byte_count) { | |
3913 | facet->byte_count += stats->n_bytes - facet->dp_byte_count; | |
3914 | } else { | |
3915 | VLOG_WARN_RL(&rl, "unexpected byte count from datapath"); | |
3916 | } | |
3917 | ||
3918 | facet->dp_packet_count = stats->n_packets; | |
3919 | facet->dp_byte_count = stats->n_bytes; | |
3920 | ||
3921 | facet_update_time(p, facet, stats->used); | |
feebdea2 | 3922 | facet_account(p, facet, stats->n_bytes); |
878ae780 | 3923 | facet_push_stats(p, facet); |
4a4cdb3b BP |
3924 | } else { |
3925 | /* There's a flow in the datapath that we know nothing about. | |
3926 | * Delete it. */ | |
3927 | COVERAGE_INC(ofproto_unexpected_rule); | |
feebdea2 | 3928 | dpif_flow_del(p->dpif, key, key_len, NULL); |
4a4cdb3b | 3929 | } |
4a4cdb3b | 3930 | } |
704a1e09 | 3931 | dpif_flow_dump_done(&dump); |
4a4cdb3b BP |
3932 | } |
3933 | ||
0de7a4b4 | 3934 | /* Calculates and returns the number of milliseconds of idle time after which |
bcf84111 | 3935 | * facets should expire from the datapath and we should fold their statistics |
0de7a4b4 BP |
3936 | * into their parent rules in userspace. */ |
3937 | static int | |
3938 | ofproto_dp_max_idle(const struct ofproto *ofproto) | |
3939 | { | |
3940 | /* | |
3941 | * Idle time histogram. | |
3942 | * | |
bcf84111 | 3943 | * Most of the time a switch has a relatively small number of facets. When |
0de7a4b4 BP |
3944 | * this is the case we might as well keep statistics for all of them in |
3945 | * userspace and to cache them in the kernel datapath for performance as | |
3946 | * well. | |
3947 | * | |
bcf84111 | 3948 | * As the number of facets increases, the memory required to maintain |
0de7a4b4 | 3949 | * statistics about them in userspace and in the kernel becomes |
bcf84111 | 3950 | * significant. However, with a large number of facets it is likely that |
0de7a4b4 BP |
3951 | * only a few of them are "heavy hitters" that consume a large amount of |
3952 | * bandwidth. At this point, only heavy hitters are worth caching in the | |
bcf84111 | 3953 | * kernel and maintaining in userspaces; other facets we can discard. |
0de7a4b4 BP |
3954 | * |
3955 | * The technique used to compute the idle time is to build a histogram with | |
bcf84111 BP |
3956 | * N_BUCKETS buckets whose width is BUCKET_WIDTH msecs each. Each facet |
3957 | * that is installed in the kernel gets dropped in the appropriate bucket. | |
0de7a4b4 | 3958 | * After the histogram has been built, we compute the cutoff so that only |
bcf84111 BP |
3959 | * the most-recently-used 1% of facets (but at least 1000 flows) are kept |
3960 | * cached. At least the most-recently-used bucket of facets is kept, so | |
3961 | * actually an arbitrary number of facets can be kept in any given | |
0de7a4b4 BP |
3962 | * expiration run (though the next run will delete most of those unless |
3963 | * they receive additional data). | |
3964 | * | |
bcf84111 | 3965 | * This requires a second pass through the facets, in addition to the pass |
3394b5b6 | 3966 | * made by ofproto_update_stats(), because the former function never looks |
bcf84111 | 3967 | * at uninstallable facets. |
0de7a4b4 BP |
3968 | */ |
3969 | enum { BUCKET_WIDTH = ROUND_UP(100, TIME_UPDATE_INTERVAL) }; | |
3970 | enum { N_BUCKETS = 5000 / BUCKET_WIDTH }; | |
3971 | int buckets[N_BUCKETS] = { 0 }; | |
bcf84111 | 3972 | struct facet *facet; |
0de7a4b4 | 3973 | int total, bucket; |
0de7a4b4 BP |
3974 | long long int now; |
3975 | int i; | |
3976 | ||
bcf84111 | 3977 | total = hmap_count(&ofproto->facets); |
0de7a4b4 BP |
3978 | if (total <= 1000) { |
3979 | return N_BUCKETS * BUCKET_WIDTH; | |
3980 | } | |
3981 | ||
3982 | /* Build histogram. */ | |
3983 | now = time_msec(); | |
bcf84111 BP |
3984 | HMAP_FOR_EACH (facet, hmap_node, &ofproto->facets) { |
3985 | long long int idle = now - facet->used; | |
0de7a4b4 BP |
3986 | int bucket = (idle <= 0 ? 0 |
3987 | : idle >= BUCKET_WIDTH * N_BUCKETS ? N_BUCKETS - 1 | |
3988 | : (unsigned int) idle / BUCKET_WIDTH); | |
3989 | buckets[bucket]++; | |
3990 | } | |
3991 | ||
3992 | /* Find the first bucket whose flows should be expired. */ | |
3993 | for (bucket = 0; bucket < N_BUCKETS; bucket++) { | |
3994 | if (buckets[bucket]) { | |
3995 | int subtotal = 0; | |
3996 | do { | |
3997 | subtotal += buckets[bucket++]; | |
3998 | } while (bucket < N_BUCKETS && subtotal < MAX(1000, total / 100)); | |
3999 | break; | |
4000 | } | |
4001 | } | |
4002 | ||
4003 | if (VLOG_IS_DBG_ENABLED()) { | |
4004 | struct ds s; | |
4005 | ||
4006 | ds_init(&s); | |
4007 | ds_put_cstr(&s, "keep"); | |
4008 | for (i = 0; i < N_BUCKETS; i++) { | |
4009 | if (i == bucket) { | |
4010 | ds_put_cstr(&s, ", drop"); | |
4011 | } | |
4012 | if (buckets[i]) { | |
4013 | ds_put_format(&s, " %d:%d", i * BUCKET_WIDTH, buckets[i]); | |
4014 | } | |
4015 | } | |
4016 | VLOG_INFO("%s: %s (msec:count)", | |
4017 | dpif_name(ofproto->dpif), ds_cstr(&s)); | |
4018 | ds_destroy(&s); | |
4019 | } | |
4020 | ||
4021 | return bucket * BUCKET_WIDTH; | |
4022 | } | |
4023 | ||
4a4cdb3b | 4024 | static void |
bcf84111 | 4025 | facet_active_timeout(struct ofproto *ofproto, struct facet *facet) |
4a4cdb3b | 4026 | { |
bcf84111 BP |
4027 | if (ofproto->netflow && !facet_is_controller_flow(facet) && |
4028 | netflow_active_timeout_expired(ofproto->netflow, &facet->nf_flow)) { | |
4a4cdb3b | 4029 | struct ofexpired expired; |
feebdea2 | 4030 | |
bcf84111 | 4031 | if (facet->installed) { |
c97fb132 | 4032 | struct dpif_flow_stats stats; |
c33087b8 BP |
4033 | |
4034 | facet_put__(ofproto, facet, facet->actions, facet->actions_len, | |
4035 | &stats); | |
4036 | facet_update_stats(ofproto, facet, &stats); | |
4a4cdb3b BP |
4037 | } |
4038 | ||
c33087b8 BP |
4039 | expired.flow = facet->flow; |
4040 | expired.packet_count = facet->packet_count; | |
4041 | expired.byte_count = facet->byte_count; | |
4042 | expired.used = facet->used; | |
bcf84111 BP |
4043 | netflow_expire(ofproto->netflow, &facet->nf_flow, &expired); |
4044 | } | |
4045 | } | |
4a4cdb3b | 4046 | |
bcf84111 BP |
4047 | static void |
4048 | ofproto_expire_facets(struct ofproto *ofproto, int dp_max_idle) | |
4049 | { | |
4050 | long long int cutoff = time_msec() - dp_max_idle; | |
4051 | struct facet *facet, *next_facet; | |
4052 | ||
4053 | HMAP_FOR_EACH_SAFE (facet, next_facet, hmap_node, &ofproto->facets) { | |
4054 | facet_active_timeout(ofproto, facet); | |
4055 | if (facet->used < cutoff) { | |
4056 | facet_remove(ofproto, facet); | |
4057 | } | |
4a4cdb3b BP |
4058 | } |
4059 | } | |
4060 | ||
5ecc9d81 BP |
4061 | /* If 'rule' is an OpenFlow rule, that has expired according to OpenFlow rules, |
4062 | * then delete it entirely. */ | |
4a4cdb3b | 4063 | static void |
5ecc9d81 | 4064 | rule_expire(struct ofproto *ofproto, struct rule *rule) |
4a4cdb3b | 4065 | { |
bcf84111 BP |
4066 | struct facet *facet, *next_facet; |
4067 | long long int now; | |
4068 | uint8_t reason; | |
4a4cdb3b | 4069 | |
bcf84111 | 4070 | /* Has 'rule' expired? */ |
4a4cdb3b | 4071 | now = time_msec(); |
bcf84111 BP |
4072 | if (rule->hard_timeout |
4073 | && now > rule->created + rule->hard_timeout * 1000) { | |
4074 | reason = OFPRR_HARD_TIMEOUT; | |
4075 | } else if (rule->idle_timeout && list_is_empty(&rule->facets) | |
4076 | && now >rule->used + rule->idle_timeout * 1000) { | |
4077 | reason = OFPRR_IDLE_TIMEOUT; | |
4a4cdb3b | 4078 | } else { |
bcf84111 | 4079 | return; |
4a4cdb3b | 4080 | } |
064af421 | 4081 | |
bcf84111 | 4082 | COVERAGE_INC(ofproto_expired); |
064af421 | 4083 | |
bcf84111 BP |
4084 | /* Update stats. (This is a no-op if the rule expired due to an idle |
4085 | * timeout, because that only happens when the rule has no facets left.) */ | |
4086 | LIST_FOR_EACH_SAFE (facet, next_facet, list_node, &rule->facets) { | |
5ecc9d81 | 4087 | facet_remove(ofproto, facet); |
064af421 BP |
4088 | } |
4089 | ||
bcf84111 BP |
4090 | /* Get rid of the rule. */ |
4091 | if (!rule_is_hidden(rule)) { | |
5ecc9d81 | 4092 | rule_send_removed(ofproto, rule, reason); |
bcf84111 | 4093 | } |
5ecc9d81 | 4094 | rule_remove(ofproto, rule); |
064af421 | 4095 | } |
bcf84111 | 4096 | \f |
ca069229 | 4097 | static void |
bcf84111 | 4098 | rule_send_removed(struct ofproto *p, struct rule *rule, uint8_t reason) |
064af421 | 4099 | { |
588cd7b5 | 4100 | struct ofputil_flow_removed fr; |
064af421 | 4101 | |
3b587616 BP |
4102 | if (!rule->send_flow_removed) { |
4103 | return; | |
4104 | } | |
4105 | ||
588cd7b5 BP |
4106 | fr.rule = rule->cr; |
4107 | fr.cookie = rule->flow_cookie; | |
4108 | fr.reason = reason; | |
4109 | calc_flow_duration__(rule->created, &fr.duration_sec, &fr.duration_nsec); | |
4110 | fr.idle_timeout = rule->idle_timeout; | |
4111 | fr.packet_count = rule->packet_count; | |
4112 | fr.byte_count = rule->byte_count; | |
7a0efeb5 | 4113 | |
19a87e36 | 4114 | connmgr_send_flow_removed(p->connmgr, &fr); |
064af421 BP |
4115 | } |
4116 | ||
3394b5b6 EJ |
4117 | /* Obtains statistics for 'rule' and stores them in '*packets' and '*bytes'. |
4118 | * The returned statistics include statistics for all of 'rule''s facets. */ | |
4119 | static void | |
4120 | rule_get_stats(const struct rule *rule, uint64_t *packets, uint64_t *bytes) | |
4121 | { | |
4122 | uint64_t p, b; | |
4123 | struct facet *facet; | |
4124 | ||
4125 | /* Start from historical data for 'rule' itself that are no longer tracked | |
4126 | * in facets. This counts, for example, facets that have expired. */ | |
4127 | p = rule->packet_count; | |
4128 | b = rule->byte_count; | |
4129 | ||
4130 | /* Add any statistics that are tracked by facets. This includes | |
4131 | * statistical data recently updated by ofproto_update_stats() as well as | |
4132 | * stats for packets that were executed "by hand" via dpif_execute(). */ | |
4133 | LIST_FOR_EACH (facet, list_node, &rule->facets) { | |
4134 | p += facet->packet_count; | |
4135 | b += facet->byte_count; | |
4136 | } | |
4137 | ||
4138 | *packets = p; | |
4139 | *bytes = b; | |
4140 | } | |
4141 | ||
82272ede | 4142 | /* Given 'upcall', of type DPIF_UC_ACTION or DPIF_UC_MISS, sends an |
856081f6 BP |
4143 | * OFPT_PACKET_IN message to each OpenFlow controller as necessary according to |
4144 | * their individual configurations. | |
43253595 | 4145 | * |
2c00fecf BP |
4146 | * If 'clone' is true, the caller retains ownership of 'upcall->packet'. |
4147 | * Otherwise, ownership is transferred to this function. */ | |
43253595 | 4148 | static void |
856081f6 BP |
4149 | send_packet_in(struct ofproto *ofproto, struct dpif_upcall *upcall, |
4150 | const struct flow *flow, bool clone) | |
43253595 | 4151 | { |
19a87e36 | 4152 | struct ofputil_packet_in pin; |
76ce9432 | 4153 | |
19a87e36 BP |
4154 | pin.packet = upcall->packet; |
4155 | pin.in_port = odp_port_to_ofp_port(flow->in_port); | |
4156 | pin.reason = upcall->type == DPIF_UC_MISS ? OFPR_NO_MATCH : OFPR_ACTION; | |
4157 | pin.buffer_id = 0; /* not yet known */ | |
4158 | pin.send_len = upcall->userdata; | |
4159 | connmgr_send_packet_in(ofproto->connmgr, upcall, flow, | |
4160 | clone ? NULL : upcall->packet); | |
064af421 BP |
4161 | } |
4162 | ||
4163 | static uint64_t | |
fa60c019 | 4164 | pick_datapath_id(const struct ofproto *ofproto) |
064af421 | 4165 | { |
fa60c019 | 4166 | const struct ofport *port; |
064af421 | 4167 | |
ca0f572c | 4168 | port = get_port(ofproto, ODPP_LOCAL); |
fa60c019 BP |
4169 | if (port) { |
4170 | uint8_t ea[ETH_ADDR_LEN]; | |
4171 | int error; | |
4172 | ||
4173 | error = netdev_get_etheraddr(port->netdev, ea); | |
064af421 BP |
4174 | if (!error) { |
4175 | return eth_addr_to_uint64(ea); | |
4176 | } | |
4177 | VLOG_WARN("could not get MAC address for %s (%s)", | |
fa60c019 | 4178 | netdev_get_name(port->netdev), strerror(error)); |
064af421 | 4179 | } |
fa60c019 | 4180 | return ofproto->fallback_dpid; |
064af421 BP |
4181 | } |
4182 | ||
4183 | static uint64_t | |
4184 | pick_fallback_dpid(void) | |
4185 | { | |
4186 | uint8_t ea[ETH_ADDR_LEN]; | |
70150daf | 4187 | eth_addr_nicira_random(ea); |
064af421 BP |
4188 | return eth_addr_to_uint64(ea); |
4189 | } | |
4190 | \f | |
7aa697dd BP |
4191 | static void |
4192 | ofproto_unixctl_list(struct unixctl_conn *conn, const char *arg OVS_UNUSED, | |
4193 | void *aux OVS_UNUSED) | |
4194 | { | |
4195 | const struct shash_node *node; | |
4196 | struct ds results; | |
4197 | ||
4198 | ds_init(&results); | |
4199 | SHASH_FOR_EACH (node, &all_ofprotos) { | |
4200 | ds_put_format(&results, "%s\n", node->name); | |
4201 | } | |
4202 | unixctl_command_reply(conn, 200, ds_cstr(&results)); | |
4203 | ds_destroy(&results); | |
4204 | } | |
4205 | ||
4206 | struct ofproto_trace { | |
4207 | struct action_xlate_ctx ctx; | |
4208 | struct flow flow; | |
4209 | struct ds *result; | |
4210 | }; | |
4211 | ||
4212 | static void | |
4213 | trace_format_rule(struct ds *result, int level, const struct rule *rule) | |
4214 | { | |
4215 | ds_put_char_multiple(result, '\t', level); | |
4216 | if (!rule) { | |
4217 | ds_put_cstr(result, "No match\n"); | |
4218 | return; | |
4219 | } | |
4220 | ||
4221 | ds_put_format(result, "Rule: cookie=%#"PRIx64" ", | |
4222 | ntohll(rule->flow_cookie)); | |
4223 | cls_rule_format(&rule->cr, result); | |
4224 | ds_put_char(result, '\n'); | |
4225 | ||
4226 | ds_put_char_multiple(result, '\t', level); | |
4227 | ds_put_cstr(result, "OpenFlow "); | |
4228 | ofp_print_actions(result, (const struct ofp_action_header *) rule->actions, | |
4229 | rule->n_actions * sizeof *rule->actions); | |
4230 | ds_put_char(result, '\n'); | |
4231 | } | |
4232 | ||
4233 | static void | |
4234 | trace_format_flow(struct ds *result, int level, const char *title, | |
4235 | struct ofproto_trace *trace) | |
4236 | { | |
4237 | ds_put_char_multiple(result, '\t', level); | |
4238 | ds_put_format(result, "%s: ", title); | |
4239 | if (flow_equal(&trace->ctx.flow, &trace->flow)) { | |
4240 | ds_put_cstr(result, "unchanged"); | |
4241 | } else { | |
4242 | flow_format(result, &trace->ctx.flow); | |
4243 | trace->flow = trace->ctx.flow; | |
4244 | } | |
4245 | ds_put_char(result, '\n'); | |
4246 | } | |
4247 | ||
4248 | static void | |
878ae780 | 4249 | trace_resubmit(struct action_xlate_ctx *ctx, struct rule *rule) |
7aa697dd BP |
4250 | { |
4251 | struct ofproto_trace *trace = CONTAINER_OF(ctx, struct ofproto_trace, ctx); | |
4252 | struct ds *result = trace->result; | |
4253 | ||
4254 | ds_put_char(result, '\n'); | |
4255 | trace_format_flow(result, ctx->recurse + 1, "Resubmitted flow", trace); | |
4256 | trace_format_rule(result, ctx->recurse + 1, rule); | |
4257 | } | |
4258 | ||
4259 | static void | |
4260 | ofproto_unixctl_trace(struct unixctl_conn *conn, const char *args_, | |
4261 | void *aux OVS_UNUSED) | |
4262 | { | |
4263 | char *dpname, *in_port_s, *tun_id_s, *packet_s; | |
4264 | char *args = xstrdup(args_); | |
4265 | char *save_ptr = NULL; | |
4266 | struct ofproto *ofproto; | |
4267 | struct ofpbuf packet; | |
4268 | struct rule *rule; | |
4269 | struct ds result; | |
4270 | struct flow flow; | |
4271 | uint16_t in_port; | |
11e6a15b | 4272 | ovs_be64 tun_id; |
7aa697dd BP |
4273 | char *s; |
4274 | ||
4275 | ofpbuf_init(&packet, strlen(args) / 2); | |
4276 | ds_init(&result); | |
4277 | ||
4278 | dpname = strtok_r(args, " ", &save_ptr); | |
4279 | tun_id_s = strtok_r(NULL, " ", &save_ptr); | |
4280 | in_port_s = strtok_r(NULL, " ", &save_ptr); | |
4281 | packet_s = strtok_r(NULL, "", &save_ptr); /* Get entire rest of line. */ | |
4282 | if (!dpname || !in_port_s || !packet_s) { | |
4283 | unixctl_command_reply(conn, 501, "Bad command syntax"); | |
4284 | goto exit; | |
4285 | } | |
4286 | ||
4287 | ofproto = shash_find_data(&all_ofprotos, dpname); | |
4288 | if (!ofproto) { | |
4289 | unixctl_command_reply(conn, 501, "Unknown ofproto (use ofproto/list " | |
4290 | "for help)"); | |
4291 | goto exit; | |
4292 | } | |
4293 | ||
8fec720d | 4294 | tun_id = htonll(strtoull(tun_id_s, NULL, 0)); |
7aa697dd BP |
4295 | in_port = ofp_port_to_odp_port(atoi(in_port_s)); |
4296 | ||
4297 | packet_s = ofpbuf_put_hex(&packet, packet_s, NULL); | |
4298 | packet_s += strspn(packet_s, " "); | |
4299 | if (*packet_s != '\0') { | |
4300 | unixctl_command_reply(conn, 501, "Trailing garbage in command"); | |
4301 | goto exit; | |
4302 | } | |
4303 | if (packet.size < ETH_HEADER_LEN) { | |
4304 | unixctl_command_reply(conn, 501, "Packet data too short for Ethernet"); | |
4305 | goto exit; | |
4306 | } | |
4307 | ||
4308 | ds_put_cstr(&result, "Packet: "); | |
4309 | s = ofp_packet_to_string(packet.data, packet.size, packet.size); | |
4310 | ds_put_cstr(&result, s); | |
4311 | free(s); | |
4312 | ||
4313 | flow_extract(&packet, tun_id, in_port, &flow); | |
4314 | ds_put_cstr(&result, "Flow: "); | |
4315 | flow_format(&result, &flow); | |
4316 | ds_put_char(&result, '\n'); | |
4317 | ||
4318 | rule = rule_lookup(ofproto, &flow); | |
4319 | trace_format_rule(&result, 0, rule); | |
4320 | if (rule) { | |
4321 | struct ofproto_trace trace; | |
cdee00fd | 4322 | struct ofpbuf *odp_actions; |
7aa697dd BP |
4323 | |
4324 | trace.result = &result; | |
4325 | trace.flow = flow; | |
4326 | action_xlate_ctx_init(&trace.ctx, ofproto, &flow, &packet); | |
4327 | trace.ctx.resubmit_hook = trace_resubmit; | |
cdee00fd BP |
4328 | odp_actions = xlate_actions(&trace.ctx, |
4329 | rule->actions, rule->n_actions); | |
7aa697dd BP |
4330 | |
4331 | ds_put_char(&result, '\n'); | |
4332 | trace_format_flow(&result, 0, "Final flow", &trace); | |
4333 | ds_put_cstr(&result, "Datapath actions: "); | |
cdee00fd BP |
4334 | format_odp_actions(&result, odp_actions->data, odp_actions->size); |
4335 | ofpbuf_delete(odp_actions); | |
7aa697dd BP |
4336 | } |
4337 | ||
4338 | unixctl_command_reply(conn, 200, ds_cstr(&result)); | |
4339 | ||
4340 | exit: | |
4341 | ds_destroy(&result); | |
4342 | ofpbuf_uninit(&packet); | |
4343 | free(args); | |
4344 | } | |
4345 | ||
4346 | static void | |
4347 | ofproto_unixctl_init(void) | |
4348 | { | |
4349 | static bool registered; | |
4350 | if (registered) { | |
4351 | return; | |
4352 | } | |
4353 | registered = true; | |
4354 | ||
4355 | unixctl_command_register("ofproto/list", ofproto_unixctl_list, NULL); | |
4356 | unixctl_command_register("ofproto/trace", ofproto_unixctl_trace, NULL); | |
4357 | } | |
4358 | \f | |
064af421 | 4359 | static bool |
ae412e7d | 4360 | default_normal_ofhook_cb(const struct flow *flow, const struct ofpbuf *packet, |
cdee00fd | 4361 | struct ofpbuf *odp_actions, tag_type *tags, |
6a07af36 | 4362 | uint16_t *nf_output_iface, void *ofproto_) |
064af421 BP |
4363 | { |
4364 | struct ofproto *ofproto = ofproto_; | |
db8077c3 | 4365 | struct mac_entry *dst_mac; |
064af421 BP |
4366 | |
4367 | /* Drop frames for reserved multicast addresses. */ | |
4368 | if (eth_addr_is_reserved(flow->dl_dst)) { | |
4369 | return true; | |
4370 | } | |
4371 | ||
4372 | /* Learn source MAC (but don't try to learn from revalidation). */ | |
db8077c3 BP |
4373 | if (packet != NULL |
4374 | && mac_learning_may_learn(ofproto->ml, flow->dl_src, 0)) { | |
4375 | struct mac_entry *src_mac; | |
4376 | ||
4377 | src_mac = mac_learning_insert(ofproto->ml, flow->dl_src, 0); | |
1bfe9681 | 4378 | if (mac_entry_is_new(src_mac) || src_mac->port.i != flow->in_port) { |
064af421 BP |
4379 | /* The log messages here could actually be useful in debugging, |
4380 | * so keep the rate limit relatively high. */ | |
4381 | static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(30, 300); | |
4382 | VLOG_DBG_RL(&rl, "learned that "ETH_ADDR_FMT" is on port %"PRIu16, | |
4383 | ETH_ADDR_ARGS(flow->dl_src), flow->in_port); | |
db8077c3 BP |
4384 | |
4385 | ofproto_revalidate(ofproto, | |
4386 | mac_learning_changed(ofproto->ml, src_mac)); | |
1bfe9681 | 4387 | src_mac->port.i = flow->in_port; |
064af421 BP |
4388 | } |
4389 | } | |
4390 | ||
4391 | /* Determine output port. */ | |
db8077c3 BP |
4392 | dst_mac = mac_learning_lookup(ofproto->ml, flow->dl_dst, 0, tags); |
4393 | if (!dst_mac) { | |
f1588b1f | 4394 | flood_packets(ofproto, flow->in_port, OFPPC_NO_FLOOD, |
cdee00fd | 4395 | nf_output_iface, odp_actions); |
064af421 | 4396 | } else { |
1bfe9681 | 4397 | int out_port = dst_mac->port.i; |
db8077c3 BP |
4398 | if (out_port != flow->in_port) { |
4399 | nl_msg_put_u32(odp_actions, ODP_ACTION_ATTR_OUTPUT, out_port); | |
4400 | *nf_output_iface = out_port; | |
4401 | } else { | |
4402 | /* Drop. */ | |
4403 | } | |
064af421 BP |
4404 | } |
4405 | ||
4406 | return true; | |
4407 | } | |
4408 | ||
4409 | static const struct ofhooks default_ofhooks = { | |
064af421 BP |
4410 | default_normal_ofhook_cb, |
4411 | NULL, | |
ebe482fd | 4412 | NULL, |
064af421 BP |
4413 | NULL |
4414 | }; |