netdev: Pass class structure, instead of type, to "create" function.
[sliver-openvswitch.git] / lib / netdev-patch.c
1 /*
2  * Copyright (c) 2010 Nicira Networks.
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 apatched 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 <errno.h>
19 #include <fcntl.h>
20 #include <net/if.h>
21 #include <sys/ioctl.h>
22
23 #include "netdev-provider.h"
24 #include "netdev-vport.h"
25 #include "openflow/openflow.h"
26 #include "openvswitch/datapath-protocol.h"
27 #include "packets.h"
28 #include "socket-util.h"
29 #include "vlog.h"
30
31 VLOG_DEFINE_THIS_MODULE(netdev_patch)
32
33 struct netdev_dev_patch {
34     struct netdev_dev netdev_dev;
35 };
36
37 struct netdev_patch {
38     struct netdev netdev;
39 };
40
41 static struct netdev_dev_patch *
42 netdev_dev_patch_cast(const struct netdev_dev *netdev_dev)
43 {
44     netdev_dev_assert_class(netdev_dev, &netdev_patch_class);
45     return CONTAINER_OF(netdev_dev, struct netdev_dev_patch, netdev_dev);
46 }
47
48 static struct netdev_patch *
49 netdev_patch_cast(const struct netdev *netdev)
50 {
51     netdev_assert_class(netdev, &netdev_patch_class);
52     return CONTAINER_OF(netdev, struct netdev_patch, netdev);
53 }
54
55 static int
56 parse_config(const char *name, const struct shash *args,
57              const char **peerp)
58 {
59     const char *peer;
60
61     peer = shash_find_data(args, "peer");
62     if (!peer) {
63         VLOG_WARN("%s: patch type requires valid 'peer' argument", name);
64         return EINVAL;
65     }
66
67     if (shash_count(args) > 1) {
68         VLOG_WARN("%s: patch type takes only a 'peer' argument", name);
69         return EINVAL;
70     }
71
72     if (strlen(peer) >= IFNAMSIZ) {
73         VLOG_WARN("%s: patch 'peer' arg too long", name);
74         return EINVAL;
75     }
76
77     if (!strcmp(name, peer)) {
78         VLOG_WARN("%s: patch peer must not be self", name);
79         return EINVAL;
80     }
81
82     *peerp = peer;
83
84     return 0;
85 }
86
87 static int
88 netdev_patch_create(const struct netdev_class *class OVS_UNUSED,
89                     const char *name, const struct shash *args,
90                     struct netdev_dev **netdev_devp)
91 {
92     int err;
93     struct odp_vport_add ova;
94     const char *peer;
95     struct netdev_dev_patch *netdev_dev;
96
97     err = parse_config(name, args, &peer);
98     if (err) {
99         return err;
100     }
101
102     ovs_strlcpy(ova.port_type, "patch", sizeof ova.port_type);
103     ovs_strlcpy(ova.devname, name, sizeof ova.devname);
104     ova.config = (char *)peer;
105
106     err = netdev_vport_do_ioctl(ODP_VPORT_ADD, &ova);
107     if (err == EBUSY) {
108         VLOG_WARN("%s: destroying existing device", name);
109
110         err = netdev_vport_do_ioctl(ODP_VPORT_DEL, ova.devname);
111         if (err) {
112             return err;
113         }
114
115         err = netdev_vport_do_ioctl(ODP_VPORT_ADD, &ova);
116     }
117
118     if (err) {
119         return err;
120     }
121
122     netdev_dev = xmalloc(sizeof *netdev_dev);
123     netdev_dev_init(&netdev_dev->netdev_dev, name, &netdev_patch_class);
124
125     *netdev_devp = &netdev_dev->netdev_dev;
126     return 0;
127 }
128
129 static int
130 netdev_patch_reconfigure(struct netdev_dev *netdev_dev_, const struct shash *args)
131 {
132     const char *name = netdev_dev_get_name(netdev_dev_);
133     struct odp_vport_mod ovm;
134     const char *peer;
135     int err;
136
137     err = parse_config(name, args, &peer);
138     if (err) {
139         return err;
140     }
141
142     ovs_strlcpy(ovm.devname, name, sizeof ovm.devname);
143     ovm.config = (char *)peer;
144
145     return netdev_vport_do_ioctl(ODP_VPORT_MOD, &ovm);
146 }
147
148 static void
149 netdev_patch_destroy(struct netdev_dev *netdev_dev_)
150 {
151     struct netdev_dev_patch *netdev_dev = netdev_dev_patch_cast(netdev_dev_);
152
153     netdev_vport_do_ioctl(ODP_VPORT_DEL, (char *)netdev_dev_get_name(netdev_dev_));
154     free(netdev_dev);
155 }
156
157 static int
158 netdev_patch_open(struct netdev_dev *netdev_dev_, int ethertype OVS_UNUSED,
159                 struct netdev **netdevp)
160 {
161     struct netdev_patch *netdev;
162
163     netdev = xmalloc(sizeof *netdev);
164     netdev_init(&netdev->netdev, netdev_dev_);
165
166     *netdevp = &netdev->netdev;
167     return 0;
168 }
169
170 static void
171 netdev_patch_close(struct netdev *netdev_)
172 {
173     struct netdev_patch *netdev = netdev_patch_cast(netdev_);
174     free(netdev);
175 }
176
177 const struct netdev_class netdev_patch_class = {
178     "patch",
179
180     NULL,                       /* init */
181     NULL,                       /* run */
182     NULL,                       /* wait */
183
184     netdev_patch_create,
185     netdev_patch_destroy,
186     netdev_patch_reconfigure,
187
188     netdev_patch_open,
189     netdev_patch_close,
190
191     NULL,                       /* enumerate */
192
193     NULL,                       /* recv */
194     NULL,                       /* recv_wait */
195     NULL,                       /* drain */
196
197     NULL,                       /* send */
198     NULL,                       /* send_wait */
199
200     netdev_vport_set_etheraddr,
201     netdev_vport_get_etheraddr,
202     netdev_vport_get_mtu,
203     NULL,                       /* get_ifindex */
204     netdev_vport_get_carrier,
205     netdev_vport_get_stats,
206     netdev_vport_set_stats,
207
208     NULL,                       /* get_features */
209     NULL,                       /* set_advertisements */
210     NULL,                       /* get_vlan_vid */
211
212     NULL,                       /* set_policing */
213     NULL,                       /* get_qos_types */
214     NULL,                       /* get_qos_capabilities */
215     NULL,                       /* get_qos */
216     NULL,                       /* set_qos */
217     NULL,                       /* get_queue */
218     NULL,                       /* set_queue */
219     NULL,                       /* delete_queue */
220     NULL,                       /* get_queue_stats */
221     NULL,                       /* dump_queues */
222     NULL,                       /* dump_queue_stats */
223
224     NULL,                       /* get_in4 */
225     NULL,                       /* set_in4 */
226     NULL,                       /* get_in6 */
227     NULL,                       /* add_router */
228     NULL,                       /* get_next_hop */
229     NULL,                       /* arp_lookup */
230
231     netdev_vport_update_flags,
232
233     netdev_vport_poll_add,
234     netdev_vport_poll_remove,
235 };