2 * Copyright (c) 2010 Nicira Networks.
3 * Distributed under the terms of the GNU GPL version 2.
5 * Significant portions of this file may be copied from parts of the Linux
6 * kernel, by Linus Torvalds and others.
9 #include <linux/dcache.h>
10 #include <linux/kernel.h>
11 #include <linux/list.h>
15 #include "vport-generic.h"
17 struct device_config
{
20 unsigned char eth_addr
[ETH_ALEN
];
27 /* Protected by RTNL lock. */
28 char peer_name
[IFNAMSIZ
];
29 struct hlist_node hash_node
;
31 /* Protected by RCU. */
34 /* Protected by RCU. */
35 struct device_config
*devconf
;
38 /* Protected by RTNL lock. */
39 static struct hlist_head
*peer_table
;
40 #define PEER_HASH_BUCKETS 256
42 static inline struct patch_vport
*patch_vport_priv(const struct vport
*vport
)
44 return vport_priv(vport
);
48 static void free_config(struct rcu_head
*rcu
)
50 struct device_config
*c
= container_of(rcu
, struct device_config
, rcu
);
54 static void assign_config_rcu(struct vport
*vport
,
55 struct device_config
*new_config
)
57 struct patch_vport
*patch_vport
= patch_vport_priv(vport
);
58 struct device_config
*old_config
;
60 old_config
= rcu_dereference(patch_vport
->devconf
);
61 rcu_assign_pointer(patch_vport
->devconf
, new_config
);
62 call_rcu(&old_config
->rcu
, free_config
);
65 static struct hlist_head
*hash_bucket(const char *name
)
67 unsigned int hash
= full_name_hash(name
, strlen(name
));
68 return &peer_table
[hash
& (PEER_HASH_BUCKETS
- 1)];
71 static int patch_init(void)
73 peer_table
= kzalloc(PEER_HASH_BUCKETS
* sizeof(struct hlist_head
),
81 static void patch_exit(void)
86 static int set_config(struct vport
*vport
, const void *config
)
88 struct patch_vport
*patch_vport
= patch_vport_priv(vport
);
89 char peer_name
[IFNAMSIZ
];
91 strlcpy(peer_name
, config
, IFNAMSIZ
);
93 if (!strcmp(patch_vport
->name
, peer_name
))
96 strcpy(patch_vport
->peer_name
, peer_name
);
101 static struct vport
*patch_create(const struct vport_parms
*parms
)
104 struct patch_vport
*patch_vport
;
107 vport
= vport_alloc(sizeof(struct patch_vport
), &patch_vport_ops
, parms
);
109 err
= PTR_ERR(vport
);
113 patch_vport
= patch_vport_priv(vport
);
115 strcpy(patch_vport
->name
, parms
->name
);
117 err
= set_config(vport
, parms
->config
);
119 goto error_free_vport
;
121 patch_vport
->devconf
= kmalloc(sizeof(struct device_config
), GFP_KERNEL
);
122 if (!patch_vport
->devconf
) {
124 goto error_free_vport
;
127 vport_gen_rand_ether_addr(patch_vport
->devconf
->eth_addr
);
129 /* Make the default MTU fairly large so that it doesn't become the
130 * bottleneck on systems using jumbo frames. */
131 patch_vport
->devconf
->mtu
= 65535;
141 static int patch_modify(struct vport
*vport
, struct odp_port
*port
)
143 int err
= set_config(vport
, port
->config
);
145 struct patch_vport
*patch_vport
= patch_vport_priv(vport
);
147 hlist_del(&patch_vport
->hash_node
);
148 rcu_assign_pointer(patch_vport
->peer
, vport_locate(patch_vport
->peer_name
));
149 hlist_add_head(&patch_vport
->hash_node
, hash_bucket(patch_vport
->peer_name
));
154 static int patch_destroy(struct vport
*vport
)
156 struct patch_vport
*patch_vport
= patch_vport_priv(vport
);
158 kfree(patch_vport
->devconf
);
164 static void update_peers(const char *name
, struct vport
*vport
)
166 struct hlist_head
*bucket
= hash_bucket(name
);
167 struct patch_vport
*peer_vport
;
168 struct hlist_node
*node
;
170 hlist_for_each_entry(peer_vport
, node
, bucket
, hash_node
)
171 if (!strcmp(peer_vport
->peer_name
, name
))
172 rcu_assign_pointer(peer_vport
->peer
, vport
);
175 static int patch_attach(struct vport
*vport
)
177 struct patch_vport
*patch_vport
= patch_vport_priv(vport
);
179 hlist_add_head(&patch_vport
->hash_node
, hash_bucket(patch_vport
->peer_name
));
181 rcu_assign_pointer(patch_vport
->peer
, vport_locate(patch_vport
->peer_name
));
182 update_peers(patch_vport
->name
, vport
);
187 static int patch_detach(struct vport
*vport
)
189 struct patch_vport
*patch_vport
= patch_vport_priv(vport
);
191 update_peers(patch_vport
->name
, NULL
);
192 rcu_assign_pointer(patch_vport
->peer
, NULL
);
194 hlist_del(&patch_vport
->hash_node
);
199 static int patch_set_mtu(struct vport
*vport
, int mtu
)
201 struct patch_vport
*patch_vport
= patch_vport_priv(vport
);
202 struct device_config
*devconf
;
204 devconf
= kmemdup(patch_vport
->devconf
, sizeof(struct device_config
), GFP_KERNEL
);
209 assign_config_rcu(vport
, devconf
);
214 static int patch_set_addr(struct vport
*vport
, const unsigned char *addr
)
216 struct patch_vport
*patch_vport
= patch_vport_priv(vport
);
217 struct device_config
*devconf
;
219 devconf
= kmemdup(patch_vport
->devconf
, sizeof(struct device_config
), GFP_KERNEL
);
223 memcpy(devconf
->eth_addr
, addr
, ETH_ALEN
);
224 assign_config_rcu(vport
, devconf
);
230 static const char *patch_get_name(const struct vport
*vport
)
232 const struct patch_vport
*patch_vport
= patch_vport_priv(vport
);
233 return patch_vport
->name
;
236 static const unsigned char *patch_get_addr(const struct vport
*vport
)
238 const struct patch_vport
*patch_vport
= patch_vport_priv(vport
);
239 return rcu_dereference(patch_vport
->devconf
)->eth_addr
;
242 static int patch_get_mtu(const struct vport
*vport
)
244 const struct patch_vport
*patch_vport
= patch_vport_priv(vport
);
245 return rcu_dereference(patch_vport
->devconf
)->mtu
;
248 static int patch_send(struct vport
*vport
, struct sk_buff
*skb
)
250 struct patch_vport
*patch_vport
= patch_vport_priv(vport
);
251 struct vport
*peer
= rcu_dereference(patch_vport
->peer
);
252 int skb_len
= skb
->len
;
256 vport_record_error(vport
, VPORT_E_TX_DROPPED
);
261 vport_receive(peer
, skb
);
265 const struct vport_ops patch_vport_ops
= {
267 .flags
= VPORT_F_GEN_STATS
,
270 .create
= patch_create
,
271 .modify
= patch_modify
,
272 .destroy
= patch_destroy
,
273 .attach
= patch_attach
,
274 .detach
= patch_detach
,
275 .set_mtu
= patch_set_mtu
,
276 .set_addr
= patch_set_addr
,
277 .get_name
= patch_get_name
,
278 .get_addr
= patch_get_addr
,
279 .get_dev_flags
= vport_gen_get_dev_flags
,
280 .is_running
= vport_gen_is_running
,
281 .get_operstate
= vport_gen_get_operstate
,
282 .get_mtu
= patch_get_mtu
,