239b3ad0c1f99eab066419f8995cab408494a9ae
[cascardo/ovs.git] / ovn / controller / pinctrl.c
1
2 /* Copyright (c) 2015, 2016 Red Hat, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <config.h>
18 #include "dirs.h"
19 #include "pinctrl.h"
20 #include "ofp-msgs.h"
21 #include "ofp-print.h"
22 #include "ofp-util.h"
23 #include "rconn.h"
24 #include "openvswitch/vlog.h"
25 #include "socket-util.h"
26 #include "vswitch-idl.h"
27
28 VLOG_DEFINE_THIS_MODULE(pinctrl);
29
30 /* OpenFlow connection to the switch. */
31 static struct rconn *swconn;
32
33 /* Last seen sequence number for 'swconn'.  When this differs from
34  * rconn_get_connection_seqno(rconn), 'swconn' has reconnected. */
35 static unsigned int conn_seq_no;
36
37 void
38 pinctrl_init(void)
39 {
40     swconn = rconn_create(5, 0, DSCP_DEFAULT, 1 << OFP13_VERSION);
41     conn_seq_no = 0;
42 }
43
44 static ovs_be32
45 queue_msg(struct ofpbuf *msg)
46 {
47     const struct ofp_header *oh = msg->data;
48     ovs_be32 xid = oh->xid;
49
50     rconn_send(swconn, msg, NULL);
51     return xid;
52 }
53
54 static void
55 get_switch_config(struct rconn *swconn)
56 {
57     struct ofpbuf *request;
58
59     request = ofpraw_alloc(OFPRAW_OFPT_GET_CONFIG_REQUEST,
60                            rconn_get_version(swconn), 0);
61     queue_msg(request);
62 }
63
64 static void
65 set_switch_config(struct rconn *swconn, const struct ofp_switch_config *config)
66 {
67     struct ofpbuf *request;
68
69     request =
70         ofpraw_alloc(OFPRAW_OFPT_SET_CONFIG, rconn_get_version(swconn), 0);
71     ofpbuf_put(request, config, sizeof *config);
72
73     queue_msg(request);
74 }
75
76 static void
77 process_packet_in(struct controller_ctx *ctx OVS_UNUSED,
78                   const struct ofp_header *msg)
79 {
80     struct ofputil_packet_in pin;
81     uint32_t buffer_id;
82     size_t total_len;
83
84     if (ofputil_decode_packet_in(msg, &pin, &total_len, &buffer_id) != 0) {
85         return;
86     }
87     if (pin.reason != OFPR_ACTION) {
88         return;
89     }
90
91     /* XXX : process the received packet */
92 }
93
94 static void
95 pinctrl_recv(struct controller_ctx *ctx, const struct ofp_header *oh,
96              enum ofptype type)
97 {
98     if (type == OFPTYPE_ECHO_REQUEST) {
99         queue_msg(make_echo_reply(oh));
100     } else if (type == OFPTYPE_GET_CONFIG_REPLY) {
101         struct ofpbuf rq_buf;
102         struct ofp_switch_config *config_, config;
103
104         ofpbuf_use_const(&rq_buf, oh, ntohs(oh->length));
105         ofpraw_pull_assert(&rq_buf);
106         config_ = ofpbuf_pull(&rq_buf, sizeof *config_);
107         config = *config_;
108         config.miss_send_len = htons(UINT16_MAX);
109         set_switch_config(swconn, &config);
110     } else if (type == OFPTYPE_PACKET_IN) {
111         process_packet_in(ctx, oh);
112     } else if (type != OFPTYPE_ECHO_REPLY && type != OFPTYPE_BARRIER_REPLY) {
113         if (VLOG_IS_DBG_ENABLED()) {
114             static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(30, 300);
115
116             char *s = ofp_to_string(oh, ntohs(oh->length), 2);
117
118             VLOG_DBG_RL(&rl, "OpenFlow packet ignored: %s", s);
119             free(s);
120         }
121     }
122 }
123
124 void
125 pinctrl_run(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int)
126 {
127     if (br_int) {
128         char *target;
129
130         target = xasprintf("unix:%s/%s.mgmt", ovs_rundir(), br_int->name);
131         if (strcmp(target, rconn_get_target(swconn))) {
132             VLOG_INFO("%s: connecting to switch", target);
133             rconn_connect(swconn, target, target);
134         }
135         free(target);
136     } else {
137         rconn_disconnect(swconn);
138     }
139
140     rconn_run(swconn);
141
142     if (!rconn_is_connected(swconn)) {
143         return;
144     }
145
146     if (conn_seq_no != rconn_get_connection_seqno(swconn)) {
147         get_switch_config(swconn);
148         conn_seq_no = rconn_get_connection_seqno(swconn);
149     }
150
151     struct ofpbuf *msg = rconn_recv(swconn);
152
153     if (!msg) {
154         return;
155     }
156
157     const struct ofp_header *oh = msg->data;
158     enum ofptype type;
159
160     ofptype_decode(&type, oh);
161     pinctrl_recv(ctx, oh, type);
162     ofpbuf_delete(msg);
163 }
164
165 void
166 pinctrl_wait(void)
167 {
168     rconn_run_wait(swconn);
169     rconn_recv_wait(swconn);
170 }
171
172 void
173 pinctrl_destroy(void)
174 {
175     rconn_destroy(swconn);
176 }