21a03636bfcd3f03057ff3fc3a4496c5bb86543f
[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
30 #define THIS_MODULE VLM_netdev_patch
31 #include "vlog.h"
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_patchnew_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_patchnew_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 char *name, const char *type OVS_UNUSED,
89                   const struct shash *args, struct netdev_dev **netdev_devp)
90 {
91     int err;
92     struct odp_vport_add ova;
93     const char *peer;
94     struct netdev_dev_patch *netdev_dev;
95
96     err = parse_config(name, args, &peer);
97     if (err) {
98         return err;
99     }
100
101     ovs_strlcpy(ova.port_type, "patch", sizeof ova.port_type);
102     ovs_strlcpy(ova.devname, name, sizeof ova.devname);
103     ova.config = (char *)peer;
104
105     err = netdev_vport_do_ioctl(ODP_VPORT_ADD, &ova);
106     if (err == EEXIST) {
107         VLOG_WARN("%s: destroying existing device", name);
108
109         err = netdev_vport_do_ioctl(ODP_VPORT_DEL, ova.devname);
110         if (err) {
111             return err;
112         }
113
114         err = netdev_vport_do_ioctl(ODP_VPORT_ADD, &ova);
115     }
116
117     if (err) {
118         return err;
119     }
120
121     netdev_dev = xmalloc(sizeof *netdev_dev);
122     netdev_dev_init(&netdev_dev->netdev_dev, name, &netdev_patchnew_class);
123
124     *netdev_devp = &netdev_dev->netdev_dev;
125     return 0;
126 }
127
128 static int
129 netdev_patch_reconfigure(struct netdev_dev *netdev_dev_, const struct shash *args)
130 {
131     const char *name = netdev_dev_get_name(netdev_dev_);
132     struct odp_vport_mod ovm;
133     const char *peer;
134     int err;
135
136     err = parse_config(name, args, &peer);
137     if (err) {
138         return err;
139     }
140
141     ovs_strlcpy(ovm.devname, name, sizeof ovm.devname);
142     ovm.config = (char *)peer;
143
144     return netdev_vport_do_ioctl(ODP_VPORT_MOD, &ovm);
145 }
146
147 static void
148 netdev_patch_destroy(struct netdev_dev *netdev_dev_)
149 {
150     struct netdev_dev_patch *netdev_dev = netdev_dev_patch_cast(netdev_dev_);
151
152     netdev_vport_do_ioctl(ODP_VPORT_DEL, (char *)netdev_dev_get_name(netdev_dev_));
153     free(netdev_dev);
154 }
155
156 static int
157 netdev_patch_open(struct netdev_dev *netdev_dev_, int ethertype OVS_UNUSED,
158                 struct netdev **netdevp)
159 {
160     struct netdev_patch *netdev;
161
162     netdev = xmalloc(sizeof *netdev);
163     netdev_init(&netdev->netdev, netdev_dev_);
164
165     *netdevp = &netdev->netdev;
166     return 0;
167 }
168
169 static void
170 netdev_patch_close(struct netdev *netdev_)
171 {
172     struct netdev_patch *netdev = netdev_patch_cast(netdev_);
173     free(netdev);
174 }
175
176 const struct netdev_class netdev_patchnew_class = {
177     "patchnew",
178
179     NULL,                       /* init */
180     NULL,                       /* run */
181     NULL,                       /* wait */
182
183     netdev_patch_create,
184     netdev_patch_destroy,
185     netdev_patch_reconfigure,
186
187     netdev_patch_open,
188     netdev_patch_close,
189
190     NULL,                       /* enumerate */
191
192     NULL,                       /* recv */
193     NULL,                       /* recv_wait */
194     NULL,                       /* drain */
195
196     NULL,                       /* send */
197     NULL,                       /* send_wait */
198
199     netdev_vport_set_etheraddr,
200     netdev_vport_get_etheraddr,
201     netdev_vport_get_mtu,
202     NULL,                       /* get_ifindex */
203     netdev_vport_get_carrier,
204     netdev_vport_get_stats,
205     NULL,                       /* set_stats */
206
207     NULL,                       /* get_features */
208     NULL,                       /* set_advertisements */
209     NULL,                       /* get_vlan_vid */
210     NULL,                       /* set_policing */
211
212     NULL,                       /* get_in4 */
213     NULL,                       /* set_in4 */
214     NULL,                       /* get_in6 */
215     NULL,                       /* add_router */
216     NULL,                       /* get_next_hop */
217     NULL,                       /* arp_lookup */
218
219     netdev_vport_update_flags,
220
221     netdev_vport_poll_add,
222     netdev_vport_poll_remove,
223 };